From eeb93bce05cd5d571e9ea6d664cc1121ce832660 Mon Sep 17 00:00:00 2001 From: Maleclypse <54345792+Maleclypse@users.noreply.github.com> Date: Thu, 18 Feb 2021 01:19:49 -0600 Subject: [PATCH 001/453] Valentine Cards (#47438) --- data/json/items/newspaper.json | 15 ++++++++++ data/json/snippets/valentines.json | 45 ++++++++++++++++++++++++++++++ 2 files changed, 60 insertions(+) create mode 100644 data/json/snippets/valentines.json diff --git a/data/json/items/newspaper.json b/data/json/items/newspaper.json index ca49cfd403468..ee55cd8e2bdaf 100644 --- a/data/json/items/newspaper.json +++ b/data/json/items/newspaper.json @@ -14,6 +14,21 @@ "weight": "3 g", "volume": "5 ml" }, + { + "type": "GENERIC", + "id": "valentine_card", + "category": "books", + "symbol": ",", + "color": "red", + "name": { "str": "valentine card" }, + "snippet_category": "valentine", + "description": "A creased holiday card. It appears to be a Valentine's Day card from before the Cataclysm.", + "price": 0, + "price_postapoc": 0, + "material": [ "paper" ], + "weight": "3 g", + "volume": "5 ml" + }, { "type": "GENERIC", "id": "survnote", diff --git a/data/json/snippets/valentines.json b/data/json/snippets/valentines.json new file mode 100644 index 0000000000000..71d3624a7bb92 --- /dev/null +++ b/data/json/snippets/valentines.json @@ -0,0 +1,45 @@ +[ + { + "type": "snippet", + "category": "valentine", + "text": [ + { + "id": "valentine_1", + "text": "There is a picture of a kitten pouncing; blood faintly drips from its claws. \"I'd kill! For you to be my valentine.\"" + }, + { + "id": "valentine_2", + "text": "A police robot stalks between office cubicles while an indistinct person hides under a desk. \"Don't hide from love!\"" + }, + { "id": "valentine_3", "text": "A picture of a bloody steak. \"My love can feed you.\"" }, + { + "id": "valentine_4", + "text": "A rustic campground at night lit by a campfire. \"We should go away together. Where no one can find us.\"" + }, + { + "id": "valentine_5", + "text": "A girl with a giant spoon stirs a cauldron with a boy inside and a fire below. \"You suit my taste just right, Valentine\"" + }, + { + "id": "valentine_6", + "text": "A person stepping out from the forest. \"Don't be afraid, it's me, your valentine!\"" + }, + { + "id": "valentine_7", + "text": "A building that says 'Crematorium' on it. \"Ashes to ashes, dust to dust, show me a Valentine, that I can trust\"" + }, + { + "id": "valentine_8", + "text": "A popular RPG character. \"We should adventure together.\" In the background, a village in flames." + }, + { + "id": "valentine_9", + "text": "A picture of a room that looks like your bedroom. \"I can't wait to see you again, Valentine. Sweet dreams.\"" + }, + { + "id": "valentine_10", + "text": "A girl smiles into the camera. Behind here a house is on fire. \"I'm burning, I'm burning, I'm burning for you, my valentine!\"" + } + ] + } +] From a72bbae02aa169186e86f3097efb2b8cc1a1d970 Mon Sep 17 00:00:00 2001 From: LaVeyanFiend <51099123+LaVeyanFiend@users.noreply.github.com> Date: Thu, 18 Feb 2021 02:34:00 -0500 Subject: [PATCH 002/453] Add a proficiency for handloading, and a new profession (#47244) --- data/json/items/book/fabrication.json | 1 + data/json/professions.json | 43 ++++++++++++ data/json/proficiencies/misc.json | 10 +++ data/json/recipes/ammo/40x46mm.json | 12 ++++ data/json/recipes/ammo/40x53mm.json | 6 ++ data/json/recipes/ammo/pistol.json | 65 +++++++++++++++++++ data/json/recipes/ammo/rifle.json | 54 ++++++++++++++- data/json/recipes/ammo/shot.json | 18 +++++ data/json/recipes/recipe_ammo.json | 5 ++ .../recipes/recipes_grenade_propelled.json | 2 + .../Generic_Guns/recipes/recipes_pistol.json | 6 ++ .../Generic_Guns/recipes/recipes_rifle.json | 4 ++ .../Generic_Guns/recipes/recipes_shot.json | 18 +++++ 13 files changed, 243 insertions(+), 1 deletion(-) diff --git a/data/json/items/book/fabrication.json b/data/json/items/book/fabrication.json index 3de5357d9ddac..1854df6c1c4f1 100644 --- a/data/json/items/book/fabrication.json +++ b/data/json/items/book/fabrication.json @@ -155,6 +155,7 @@ "skill": "fabrication", "required_level": 3, "max_level": 6, + "proficiencies": [ { "proficiency": "prof_handloading", "time_factor": 0.8, "fail_factor": 0.5 } ], "intelligence": 9, "time": "30 m" }, diff --git a/data/json/professions.json b/data/json/professions.json index ddc6ec5764117..6f9853a31e3ed 100644 --- a/data/json/professions.json +++ b/data/json/professions.json @@ -136,6 +136,15 @@ { "item": "38_speedloader", "ammo-item": "357mag_fmj", "charges": 7 } ] }, + { + "type": "item_group", + "subtype": "collection", + "id": "m1911_10_magazines_reloaded", + "entries": [ + { "item": "m1911_10mag", "ammo-item": "reloaded_10mm_fmj", "charges": 8 }, + { "item": "m1911_10mag", "ammo-item": "reloaded_10mm_fmj", "charges": 8 } + ] + }, { "type": "item_group", "subtype": "collection", @@ -3912,5 +3921,39 @@ "male": [ "boxer_shorts" ], "female": [ "bra", "panties" ] } + }, + { + "type": "profession", + "id": "handloader", + "name": "Hobby Handloader", + "description": "Out of financial concerns and an appreciation for power, you took up handloading for your mighty handgun. Now that the gunstores are closed, your skills ensure you won't be running out of ammo anytime soon.", + "points": 5, + "proficiencies": [ "prof_handloading" ], + "items": { + "both": { + "items": [ + "pants", + "dress_shirt", + "wristwatch", + "socks", + "boots", + "jacket_light", + "gloves_fingerless", + "press", + "puller", + "slingpack", + "hat_ball" + ], + "entries": [ + { "group": "charged_cell_phone" }, + { "group": "m1911_10_magazines_reloaded" }, + { "item": "ear_plugs", "custom-flags": [ "no_auto_equip" ] }, + { "item": "m1911_10", "ammo-item": "reloaded_10mm_fmj", "charges": 8, "container-item": "holster" } + ] + }, + "male": [ "briefs" ], + "female": [ "bra", "panties" ] + }, + "skills": [ { "level": 3, "name": "fabrication" }, { "level": 3, "name": "gun" }, { "level": 3, "name": "pistol" } ] } ] diff --git a/data/json/proficiencies/misc.json b/data/json/proficiencies/misc.json index ce099486ce465..1db2662f4a661 100644 --- a/data/json/proficiencies/misc.json +++ b/data/json/proficiencies/misc.json @@ -134,5 +134,15 @@ "default_fail_multiplier": 2, "time_to_learn": "10 h", "required_proficiencies": [ "prof_fine_metalsmithing", "prof_redsmithing" ] + }, + { + "type": "proficiency", + "id": "prof_handloading", + "name": { "str": "Handloading" }, + "description": "You know how to accurately measure powder and projectile weights for reloading firearm cartridges.", + "can_learn": true, + "default_time_multiplier": 1.5, + "default_fail_multiplier": 5, + "time_to_learn": "8 h" } ] diff --git a/data/json/recipes/ammo/40x46mm.json b/data/json/recipes/ammo/40x46mm.json index e6ae3fa91ea05..a19c439a1d90d 100644 --- a/data/json/recipes/ammo/40x46mm.json +++ b/data/json/recipes/ammo/40x46mm.json @@ -15,6 +15,7 @@ "reversible": true, "//": "186 mg gunpowder rounded to 2 100 mg 'pieces', same as factory M576 load.", "using": [ [ "shot_forming", 1 ], [ "ammo_bullet", 8 ] ], + "proficiencies": [ { "proficiency": "prof_handloading" } ], "tools": [ [ [ "press", -1 ] ], [ [ "swage", -1 ] ] ], "qualities": [ { "id": "CUT", "level": 1 } ], "components": [ @@ -40,6 +41,7 @@ "charges": 1, "reversible": true, "using": [ [ "shot_forming", 1 ], [ "ammo_bullet", 8 ] ], + "proficiencies": [ { "proficiency": "prof_handloading" } ], "tools": [ [ [ "press", -1 ] ], [ [ "swage", -1 ] ] ], "qualities": [ { "id": "CUT", "level": 1 } ], "//": "186 mg gunpowder rounded to 2 100 mg 'pieces', same as factory M576 load.", @@ -66,6 +68,7 @@ "charges": 1, "reversible": true, "using": [ [ "bullet_forming", 1 ], [ "ammo_bullet", 8 ] ], + "proficiencies": [ { "proficiency": "prof_handloading" } ], "tools": [ [ [ "press", -1 ] ], [ [ "swage", -1 ] ] ], "qualities": [ { "id": "CUT", "level": 1 } ], "//": "186 mg gunpowder rounded to 2 100 mg 'pieces', same as factory M576 load.", @@ -92,6 +95,7 @@ "charges": 1, "reversible": true, "using": [ [ "bullet_forming", 1 ], [ "ammo_bullet", 8 ] ], + "proficiencies": [ { "proficiency": "prof_handloading" } ], "tools": [ [ [ "press", -1 ] ], [ [ "swage", -1 ] ] ], "qualities": [ { "id": "CUT", "level": 1 } ], "//": "186 mg gunpowder rounded to 2 100 mg 'pieces', same as factory M576 load.", @@ -120,6 +124,7 @@ "tools": [ [ [ "press", -1 ] ], [ [ "swage", -1 ] ] ], "qualities": [ { "id": "CUT", "level": 1 } ], "//": "186 mg gunpowder rounded to 2 100 mg 'pieces', same as factory M576 load.", + "proficiencies": [ { "proficiency": "prof_handloading" } ], "components": [ [ [ "sheet_metal_small", 1 ] ], [ [ "paper", 1 ], [ "wax", 1 ] ], @@ -146,6 +151,7 @@ "tools": [ [ [ "press", -1 ] ], [ [ "swage", -1 ] ] ], "qualities": [ { "id": "CUT", "level": 1 } ], "//": "186 mg gunpowder rounded to 2 100 mg 'pieces', same as factory M576 load.", + "proficiencies": [ { "proficiency": "prof_handloading" } ], "components": [ [ [ "sheet_metal_small", 1 ] ], [ [ "paper", 1 ], [ "wax", 1 ] ], @@ -170,6 +176,7 @@ "charges": 1, "reversible": true, "using": [ [ "shot_forming", 1 ], [ "ammo_bullet", 8 ] ], + "proficiencies": [ { "proficiency": "prof_handloading" } ], "tools": [ [ [ "press", -1 ] ], [ [ "swage", -1 ] ] ], "qualities": [ { "id": "CUT", "level": 1 } ], "components": [ @@ -195,6 +202,7 @@ "charges": 1, "reversible": true, "using": [ [ "shot_forming", 1 ], [ "ammo_bullet", 8 ] ], + "proficiencies": [ { "proficiency": "prof_handloading" } ], "tools": [ [ [ "press", -1 ] ], [ [ "swage", -1 ] ] ], "qualities": [ { "id": "CUT", "level": 1 } ], "components": [ @@ -220,6 +228,7 @@ "charges": 1, "reversible": true, "using": [ [ "bullet_forming", 1 ], [ "ammo_bullet", 8 ] ], + "proficiencies": [ { "proficiency": "prof_handloading" } ], "tools": [ [ [ "press", -1 ] ], [ [ "swage", -1 ] ] ], "qualities": [ { "id": "CUT", "level": 1 } ], "components": [ @@ -245,6 +254,7 @@ "charges": 1, "reversible": true, "using": [ [ "bullet_forming", 1 ], [ "ammo_bullet", 8 ] ], + "proficiencies": [ { "proficiency": "prof_handloading" } ], "tools": [ [ [ "press", -1 ] ], [ [ "swage", -1 ] ] ], "qualities": [ { "id": "CUT", "level": 1 } ], "components": [ @@ -271,6 +281,7 @@ "reversible": true, "tools": [ [ [ "press", -1 ] ], [ [ "swage", -1 ] ] ], "qualities": [ { "id": "CUT", "level": 1 } ], + "proficiencies": [ { "proficiency": "prof_handloading" } ], "components": [ [ [ "sheet_metal_small", 1 ] ], [ [ "paper", 1 ], [ "wax", 1 ] ], @@ -296,6 +307,7 @@ "reversible": true, "tools": [ [ [ "press", -1 ] ], [ [ "swage", -1 ] ] ], "qualities": [ { "id": "CUT", "level": 1 } ], + "proficiencies": [ { "proficiency": "prof_handloading" } ], "components": [ [ [ "sheet_metal_small", 1 ] ], [ [ "paper", 1 ], [ "wax", 1 ] ], diff --git a/data/json/recipes/ammo/40x53mm.json b/data/json/recipes/ammo/40x53mm.json index 6d3778b2df483..e03a7bc5438e3 100644 --- a/data/json/recipes/ammo/40x53mm.json +++ b/data/json/recipes/ammo/40x53mm.json @@ -14,6 +14,7 @@ "charges": 1, "reversible": true, "using": [ [ "shot_forming", 12 ], [ "ammo_bullet", 126 ] ], + "proficiencies": [ { "proficiency": "prof_handloading" } ], "tools": [ [ [ "press", -1 ] ], [ [ "swage", -1 ] ] ], "qualities": [ { "id": "CUT", "level": 1 } ], "//": "11.5x the propellant and 11.5x the payload of 12 gauge 00 shot load. 13409 mg gunpowder rounded to 134 100 mg 'pieces'", @@ -40,6 +41,7 @@ "charges": 1, "reversible": true, "using": [ [ "bullet_forming", 12 ], [ "ammo_bullet", 115 ] ], + "proficiencies": [ { "proficiency": "prof_handloading" } ], "tools": [ [ [ "press", -1 ] ], [ [ "swage", -1 ] ] ], "qualities": [ { "id": "CUT", "level": 1 } ], "//": "11.5x the propellant and 11.5x the payload of 12 gauge slug load. 19366 mg gunpowder rounded to 194 100 mg 'pieces'", @@ -68,6 +70,7 @@ "tools": [ [ [ "press", -1 ] ], [ [ "swage", -1 ] ] ], "qualities": [ { "id": "CUT", "level": 1 } ], "//": "11.5x the propellant and 11.5x the payload of 12 gauge flechette load. 8625 mg gunpowder rounded to 86 100 mg 'pieces'", + "proficiencies": [ { "proficiency": "prof_handloading" } ], "components": [ [ [ "sheet_metal_small", 1 ] ], [ [ "paper", 1 ], [ "wax", 1 ] ], @@ -92,6 +95,7 @@ "charges": 1, "reversible": true, "using": [ [ "shot_forming", 12 ], [ "ammo_bullet", 126 ] ], + "proficiencies": [ { "proficiency": "prof_handloading" } ], "tools": [ [ [ "press", -1 ] ], [ [ "swage", -1 ] ] ], "qualities": [ { "id": "CUT", "level": 1 } ], "components": [ @@ -117,6 +121,7 @@ "charges": 1, "reversible": true, "using": [ [ "bullet_forming", 12 ], [ "ammo_bullet", 115 ] ], + "proficiencies": [ { "proficiency": "prof_handloading" } ], "tools": [ [ [ "press", -1 ] ], [ [ "swage", -1 ] ] ], "qualities": [ { "id": "CUT", "level": 1 } ], "components": [ @@ -143,6 +148,7 @@ "reversible": true, "tools": [ [ [ "press", -1 ] ], [ [ "swage", -1 ] ] ], "qualities": [ { "id": "CUT", "level": 1 } ], + "proficiencies": [ { "proficiency": "prof_handloading" } ], "components": [ [ [ "sheet_metal_small", 1 ] ], [ [ "paper", 1 ], [ "wax", 1 ] ], diff --git a/data/json/recipes/ammo/pistol.json b/data/json/recipes/ammo/pistol.json index 66607ed15581f..6f1669fb514b7 100644 --- a/data/json/recipes/ammo/pistol.json +++ b/data/json/recipes/ammo/pistol.json @@ -14,6 +14,7 @@ "charges": 1, "reversible": true, "using": [ [ "bullet_forming", 2 ], [ "ammo_bullet", 2 ], [ "ammo_9mm", 1 ] ], + "proficiencies": [ { "proficiency": "prof_handloading" } ], "components": [ [ [ "chem_black_powder", 3 ] ], [ [ "copper", 1 ] ] ] }, { @@ -31,6 +32,7 @@ "charges": 1, "reversible": true, "using": [ [ "bullet_forming", 2 ], [ "ammo_bullet", 2 ], [ "ammo_9mm", 1 ] ], + "proficiencies": [ { "proficiency": "prof_handloading" } ], "components": [ [ [ "chem_black_powder", 3 ] ], [ [ "copper", 1 ] ] ] }, { @@ -48,6 +50,7 @@ "charges": 1, "reversible": true, "using": [ [ "bullet_forming", 2 ], [ "ammo_bullet", 4 ] ], + "proficiencies": [ { "proficiency": "prof_handloading" } ], "components": [ [ [ "40_casing", 1 ] ], [ [ "smpistol_primer", 1 ] ], [ [ "chem_black_powder", 3 ] ], [ [ "copper", 1 ] ] ] }, { @@ -65,6 +68,7 @@ "charges": 1, "reversible": true, "using": [ [ "bullet_forming", 2 ], [ "ammo_bullet", 4 ] ], + "proficiencies": [ { "proficiency": "prof_handloading" } ], "components": [ [ [ "40_casing", 1 ] ], [ [ "smpistol_primer", 1 ] ], [ [ "chem_black_powder", 6 ] ], [ [ "copper", 1 ] ] ] }, { @@ -82,6 +86,7 @@ "charges": 1, "reversible": true, "using": [ [ "bullet_forming", 2 ], [ "ammo_bullet", 2 ] ], + "proficiencies": [ { "proficiency": "prof_handloading" } ], "components": [ [ [ "32_casing", 1 ] ], [ [ "smpistol_primer", 1 ] ], [ [ "chem_black_powder", 2 ] ], [ [ "copper", 1 ] ] ] }, { @@ -99,6 +104,7 @@ "charges": 1, "reversible": true, "using": [ [ "bullet_forming", 2 ], [ "ammo_bullet", 2 ] ], + "proficiencies": [ { "proficiency": "prof_handloading" } ], "components": [ [ [ "38_casing", 1 ] ], [ [ "smpistol_primer", 1 ] ], [ [ "chem_black_powder", 3 ] ], [ [ "copper", 1 ] ] ] }, { @@ -116,6 +122,7 @@ "charges": 1, "reversible": true, "using": [ [ "bullet_forming", 5 ], [ "ammo_bullet", 4 ] ], + "proficiencies": [ { "proficiency": "prof_handloading" } ], "components": [ [ [ "44_casing", 1 ] ], [ [ "lgpistol_primer", 1 ] ], [ [ "chem_black_powder", 7 ] ], [ [ "copper", 2 ] ] ] }, { @@ -133,6 +140,7 @@ "charges": 1, "reversible": true, "using": [ [ "bullet_forming", 3 ], [ "ammo_bullet", 4 ] ], + "proficiencies": [ { "proficiency": "prof_handloading" } ], "components": [ [ [ "45_casing", 1 ] ], [ [ "lgpistol_primer", 1 ] ], [ [ "chem_black_powder", 3 ] ], [ [ "copper", 2 ] ] ] }, { @@ -150,6 +158,7 @@ "charges": 1, "reversible": true, "using": [ [ "bullet_forming", 3 ], [ "ammo_bullet", 4 ] ], + "proficiencies": [ { "proficiency": "prof_handloading" } ], "components": [ [ [ "45_casing", 1 ] ], [ [ "lgpistol_primer", 1 ] ], [ [ "chem_black_powder", 5 ] ], [ [ "copper", 1 ] ] ] }, { @@ -167,6 +176,7 @@ "charges": 1, "reversible": true, "using": [ [ "bullet_forming", 2 ], [ "ammo_bullet", 1 ] ], + "proficiencies": [ { "proficiency": "prof_handloading" } ], "components": [ [ [ "46mm_casing", 1 ] ], [ [ "smpistol_primer", 1 ] ], [ [ "chem_black_powder", 4 ] ], [ [ "copper", 1 ] ] ] }, { @@ -184,6 +194,7 @@ "charges": 1, "reversible": true, "using": [ [ "bullet_forming", 3 ], [ "ammo_bullet", 3 ] ], + "proficiencies": [ { "proficiency": "prof_handloading" } ], "components": [ [ [ "460_casing", 1 ] ], [ [ "lgpistol_primer", 1 ] ], [ [ "chem_black_powder", 8 ] ], [ [ "copper", 2 ] ] ] }, { @@ -201,6 +212,7 @@ "charges": 1, "reversible": true, "using": [ [ "bullet_forming", 3 ], [ "ammo_bullet", 3 ] ], + "proficiencies": [ { "proficiency": "prof_handloading" } ], "components": [ [ [ "460_casing", 1 ] ], [ [ "lgpistol_primer", 1 ] ], [ [ "chem_black_powder", 8 ] ], [ [ "copper", 2 ] ] ] }, { @@ -218,6 +230,7 @@ "charges": 1, "reversible": true, "using": [ [ "bullet_forming", 6 ], [ "ammo_bullet", 8 ] ], + "proficiencies": [ { "proficiency": "prof_handloading" } ], "components": [ [ [ "500_casing", 1 ] ], [ [ "lgrifle_primer", 1 ] ], [ [ "chem_black_powder", 19 ] ], [ [ "copper", 5 ] ] ] }, { @@ -235,6 +248,7 @@ "charges": 1, "reversible": true, "using": [ [ "bullet_forming", 2 ], [ "ammo_bullet", 2 ], [ "ammo_762_25", 1 ] ], + "proficiencies": [ { "proficiency": "prof_handloading" } ], "components": [ [ [ "chem_black_powder", 4 ] ], [ [ "copper", 1 ] ] ] }, { @@ -252,6 +266,7 @@ "charges": 1, "reversible": true, "using": [ [ "bullet_forming", 2 ], [ "ammo_bullet", 2 ] ], + "proficiencies": [ { "proficiency": "prof_handloading" } ], "components": [ [ [ "9x18mm_casing", 1 ] ], [ [ "smpistol_primer", 1 ] ], [ [ "chem_black_powder", 4 ] ], [ [ "copper", 1 ] ] ] }, { @@ -269,6 +284,7 @@ "charges": 1, "reversible": true, "using": [ [ "bullet_forming", 2 ], [ "ammo_bullet", 2 ] ], + "proficiencies": [ { "proficiency": "prof_handloading" } ], "components": [ [ [ "9x18mm_casing", 1 ] ], [ [ "smpistol_primer", 1 ] ], [ [ "chem_black_powder", 4 ] ], [ [ "copper", 1 ] ] ] }, { @@ -286,6 +302,7 @@ "charges": 1, "reversible": true, "using": [ [ "bullet_forming", 2 ], [ "ammo_bullet", 2 ], [ "ammo_380", 1 ] ], + "proficiencies": [ { "proficiency": "prof_handloading" } ], "components": [ [ [ "chem_black_powder", 3 ] ], [ [ "copper", 1 ] ] ] }, { @@ -303,6 +320,7 @@ "charges": 1, "reversible": true, "using": [ [ "bullet_forming", 2 ], [ "ammo_bullet", 2 ], [ "ammo_380", 1 ] ], + "proficiencies": [ { "proficiency": "prof_handloading" } ], "components": [ [ [ "chem_black_powder", 3 ] ], [ [ "copper", 1 ] ] ] }, { @@ -320,6 +338,7 @@ "charges": 1, "reversible": true, "using": [ [ "bullet_forming", 2 ], [ "ammo_bullet", 1 ], [ "ammo_57", 1 ] ], + "proficiencies": [ { "proficiency": "prof_handloading" } ], "components": [ [ [ "chem_black_powder", 4 ] ], [ [ "copper", 1 ] ] ] }, { @@ -338,6 +357,7 @@ "reversible": true, "using": [ [ "ammo_bullet", 1 ] ], "qualities": [ { "id": "CUT", "level": 1 } ], + "proficiencies": [ { "proficiency": "prof_handloading" } ], "components": [ [ [ "chem_black_powder", 4 ] ], [ [ "smpistol_primer", 1 ] ], [ [ "paper", 1 ], [ "aluminum_foil", 1 ] ] ] }, { @@ -356,6 +376,7 @@ "reversible": true, "using": [ [ "ammo_bullet", 2 ] ], "qualities": [ { "id": "CUT", "level": 1 } ], + "proficiencies": [ { "proficiency": "prof_handloading" } ], "components": [ [ [ "chem_black_powder", 4 ] ], [ [ "lgpistol_primer", 1 ] ], [ [ "paper", 1 ], [ "aluminum_foil", 1 ] ] ] }, { @@ -374,6 +395,7 @@ "reversible": true, "using": [ [ "bullet_forming", 2 ], [ "ammo_bullet", 2 ] ], "//": "207 mg gunpowder rounded to 2 100 mg 'pieces'", + "proficiencies": [ { "proficiency": "prof_handloading" } ], "components": [ [ [ "32_casing", 1 ] ], [ [ "smpistol_primer", 1 ] ], @@ -397,6 +419,7 @@ "reversible": true, "using": [ [ "bullet_forming", 2 ], [ "ammo_bullet", 2 ] ], "//": "315 mg gunpowder rounded to 3 100 mg 'pieces'", + "proficiencies": [ { "proficiency": "prof_handloading" } ], "components": [ [ [ "38_casing", 1 ] ], [ [ "smpistol_primer", 1 ] ], @@ -420,6 +443,7 @@ "reversible": true, "using": [ [ "bullet_forming", 2 ], [ "ammo_bullet", 3 ] ], "//": "315 mg gunpowder rounded to 3 100 mg 'pieces'", + "proficiencies": [ { "proficiency": "prof_handloading" } ], "components": [ [ [ "38_casing", 1 ] ], [ [ "smpistol_primer", 1 ] ], @@ -442,6 +466,7 @@ "reversible": true, "using": [ [ "bullet_forming", 2 ], [ "ammo_bullet", 1 ], [ "ammo_38super", 1 ] ], "//": "323 mg gunpowder rounded to 3 100 mg 'pieces'", + "proficiencies": [ { "proficiency": "prof_handloading" } ], "components": [ [ [ "gunpowder", 3 ], [ "gunpowder_pistol", 3 ], [ "gunpowder_shotgun", 3 ] ], [ [ "copper", 1 ] ] ] }, { @@ -460,6 +485,7 @@ "reversible": true, "using": [ [ "bullet_forming", 2 ], [ "ammo_bullet", 7 ], [ "ammo_357sig", 1 ] ], "//": "370 mg gunpowder rounded to 4 100 mg 'pieces'", + "proficiencies": [ { "proficiency": "prof_handloading" } ], "components": [ [ [ "gunpowder", 4 ], [ "gunpowder_rifle", 4 ], [ "gunpowder_magnum_pistol", 4 ] ], [ [ "copper", 1 ] ] ] }, { @@ -478,6 +504,7 @@ "reversible": true, "using": [ [ "bullet_forming", 2 ], [ "ammo_bullet", 8 ], [ "ammo_357sig", 1 ] ], "//": "531 mg gunpowder rounded to 5 100 mg 'pieces'", + "proficiencies": [ { "proficiency": "prof_handloading" } ], "components": [ [ [ "gunpowder", 5 ], [ "gunpowder_rifle", 5 ], [ "gunpowder_magnum_pistol", 5 ] ], [ [ "copper", 1 ] ] ] }, { @@ -495,6 +522,7 @@ "charges": 1, "reversible": true, "using": [ [ "bullet_forming", 2 ], [ "ammo_bullet", 7 ], [ "ammo_357sig", 1 ] ], + "proficiencies": [ { "proficiency": "prof_handloading" } ], "components": [ [ [ "chem_black_powder", 4 ] ], [ [ "copper", 1 ] ] ] }, { @@ -512,6 +540,7 @@ "charges": 1, "reversible": true, "using": [ [ "bullet_forming", 2 ], [ "ammo_bullet", 8 ], [ "ammo_357sig", 1 ] ], + "proficiencies": [ { "proficiency": "prof_handloading" } ], "components": [ [ [ "chem_black_powder", 5 ] ], [ [ "copper", 1 ] ] ] }, { @@ -530,6 +559,7 @@ "reversible": true, "using": [ [ "bullet_forming", 2 ], [ "ammo_bullet", 3 ], [ "ammo_357mag", 1 ] ], "//": "520 mg gunpowder rounded to 5 100 mg 'pieces'", + "proficiencies": [ { "proficiency": "prof_handloading" } ], "components": [ [ [ "gunpowder", 5 ], [ "gunpowder_rifle", 5 ], [ "gunpowder_magnum_pistol", 5 ] ], [ [ "copper", 1 ] ] ] }, { @@ -548,6 +578,7 @@ "reversible": true, "using": [ [ "bullet_forming", 2 ], [ "ammo_bullet", 4 ], [ "ammo_357mag", 1 ] ], "//": "520 mg gunpowder rounded to 5 100 mg 'pieces'", + "proficiencies": [ { "proficiency": "prof_handloading" } ], "components": [ [ [ "gunpowder", 5 ], [ "gunpowder_rifle", 5 ], [ "gunpowder_magnum_pistol", 5 ] ], [ [ "copper", 1 ] ] ] }, { @@ -565,6 +596,7 @@ "charges": 1, "reversible": true, "using": [ [ "bullet_forming", 2 ], [ "ammo_bullet", 3 ], [ "ammo_357mag", 1 ] ], + "proficiencies": [ { "proficiency": "prof_handloading" } ], "components": [ [ [ "chem_black_powder", 5 ] ], [ [ "copper", 1 ] ] ] }, { @@ -582,6 +614,7 @@ "charges": 1, "reversible": true, "using": [ [ "bullet_forming", 2 ], [ "ammo_bullet", 4 ], [ "ammo_357mag", 1 ] ], + "proficiencies": [ { "proficiency": "prof_handloading" } ], "components": [ [ [ "chem_black_powder", 5 ] ], [ [ "copper", 1 ] ] ] }, { @@ -599,6 +632,7 @@ "charges": 1, "reversible": true, "using": [ [ "bullet_forming", 2 ], [ "ammo_bullet", 3 ] ], + "proficiencies": [ { "proficiency": "prof_handloading" } ], "components": [ [ [ "38_casing", 1 ] ], [ [ "smpistol_primer", 1 ] ], [ [ "chem_black_powder", 3 ] ] ] }, { @@ -617,6 +651,7 @@ "reversible": true, "using": [ [ "bullet_forming", 2 ], [ "ammo_bullet", 2 ] ], "//": "453 mg gunpowder rounded to 5 100 mg 'pieces'", + "proficiencies": [ { "proficiency": "prof_handloading" } ], "components": [ [ [ "38_casing", 1 ] ], [ [ "smpistol_primer", 1 ] ], @@ -639,6 +674,7 @@ "reversible": true, "using": [ [ "bullet_forming", 2 ], [ "ammo_bullet", 4 ] ], "//": "320 mg gunpowder rounded to 3 100 mg 'pieces'", + "proficiencies": [ { "proficiency": "prof_handloading" } ], "components": [ [ [ "40_casing", 1 ] ], [ [ "smpistol_primer", 1 ] ], @@ -662,6 +698,7 @@ "reversible": true, "using": [ [ "bullet_forming", 2 ], [ "ammo_bullet", 4 ] ], "//": "576 mg gunpowder rounded to 6 100 mg 'pieces'", + "proficiencies": [ { "proficiency": "prof_handloading" } ], "components": [ [ [ "40_casing", 1 ] ], [ [ "smpistol_primer", 1 ] ], @@ -685,6 +722,7 @@ "reversible": true, "using": [ [ "bullet_forming", 2 ], [ "ammo_bullet", 3 ], [ "ammo_10mm", 1 ] ], "//": "330 mg gunpowder rounded to 3 100 mg 'pieces'", + "proficiencies": [ { "proficiency": "prof_handloading" } ], "components": [ [ [ "gunpowder", 3 ], [ "gunpowder_magnum_pistol", 3 ] ], [ [ "copper", 1 ] ] ] }, { @@ -702,6 +740,7 @@ "charges": 1, "reversible": true, "using": [ [ "bullet_forming", 2 ], [ "ammo_bullet", 3 ], [ "ammo_10mm", 1 ] ], + "proficiencies": [ { "proficiency": "prof_handloading" } ], "components": [ [ [ "chem_black_powder", 3 ] ], [ [ "copper", 1 ] ] ] }, { @@ -720,6 +759,7 @@ "reversible": true, "using": [ [ "bullet_forming", 5 ], [ "ammo_bullet", 4 ] ], "//": "660 mg gunpowder rounded to 7 100 mg 'pieces'", + "proficiencies": [ { "proficiency": "prof_handloading" } ], "components": [ [ [ "44_casing", 1 ] ], [ [ "lgpistol_primer", 1 ] ], @@ -743,6 +783,7 @@ "reversible": true, "using": [ [ "bullet_forming", 5 ], [ "ammo_bullet", 4 ] ], "//": "660 mg gunpowder rounded to 7 100 mg 'pieces'", + "proficiencies": [ { "proficiency": "prof_handloading" } ], "components": [ [ [ "44_casing", 1 ] ], [ [ "lgpistol_primer", 1 ] ], @@ -765,6 +806,7 @@ "charges": 1, "reversible": true, "using": [ [ "bullet_forming", 5 ], [ "ammo_bullet", 4 ] ], + "proficiencies": [ { "proficiency": "prof_handloading" } ], "components": [ [ [ "44_casing", 1 ] ], [ [ "lgpistol_primer", 1 ] ], [ [ "chem_black_powder", 7 ] ], [ [ "copper", 2 ] ] ] }, { @@ -783,6 +825,7 @@ "reversible": true, "using": [ [ "bullet_forming", 3 ], [ "ammo_bullet", 4 ] ], "//": "330 mg gunpowder rounded to 3 100 mg 'pieces'", + "proficiencies": [ { "proficiency": "prof_handloading" } ], "components": [ [ [ "45_casing", 1 ] ], [ [ "lgpistol_primer", 1 ] ], @@ -806,6 +849,7 @@ "reversible": true, "using": [ [ "bullet_forming", 3 ], [ "ammo_bullet", 4 ] ], "//": "466 mg gunpowder rounded to 5 100 mg 'pieces'", + "proficiencies": [ { "proficiency": "prof_handloading" } ], "components": [ [ [ "45_casing", 1 ] ], [ [ "lgpistol_primer", 1 ] ], @@ -829,6 +873,7 @@ "reversible": true, "using": [ [ "bullet_forming", 3 ], [ "ammo_bullet", 4 ] ], "//": "513 mg gunpowder rounded to 5 100 mg 'pieces'", + "proficiencies": [ { "proficiency": "prof_handloading" } ], "components": [ [ [ "45_casing", 1 ] ], [ [ "lgpistol_primer", 1 ] ], @@ -852,6 +897,7 @@ "reversible": true, "using": [ [ "bullet_forming", 5 ], [ "ammo_bullet", 6 ] ], "//": "1574 mg gunpowder rounded to 16 100 mg 'pieces'", + "proficiencies": [ { "proficiency": "prof_handloading" } ], "components": [ [ [ "454_casing", 1 ] ], [ [ "smrifle_primer", 1 ] ], @@ -874,6 +920,7 @@ "charges": 1, "reversible": true, "using": [ [ "bullet_forming", 5 ], [ "ammo_bullet", 6 ] ], + "proficiencies": [ { "proficiency": "prof_handloading" } ], "components": [ [ [ "454_casing", 1 ] ], [ [ "smrifle_primer", 1 ] ], [ [ "chem_black_powder", 16 ] ], [ [ "copper", 2 ] ] ] }, { @@ -892,6 +939,7 @@ "reversible": true, "using": [ [ "bullet_forming", 3 ], [ "ammo_bullet", 5 ], [ "ammo_45colt", 1 ] ], "//": "505 mg gunpowder rounded to 5 100 mg 'pieces'", + "proficiencies": [ { "proficiency": "prof_handloading" } ], "components": [ [ [ "gunpowder", 5 ], [ "gunpowder_pistol", 5 ], [ "gunpowder_shotgun", 5 ] ], [ [ "copper", 2 ] ] ] }, { @@ -909,6 +957,7 @@ "charges": 1, "reversible": true, "using": [ [ "bullet_forming", 3 ], [ "ammo_bullet", 5 ], [ "ammo_45colt", 1 ] ], + "proficiencies": [ { "proficiency": "prof_handloading" } ], "components": [ [ [ "chem_black_powder", 5 ] ], [ [ "copper", 2 ] ] ] }, { @@ -927,6 +976,7 @@ "reversible": true, "//": "Unable to find load data, used 5.7 data as cartridges are similar. 388 mg gunpowder rounded to 4 100 mg 'pieces'", "using": [ [ "bullet_forming", 2 ], [ "ammo_bullet", 1 ] ], + "proficiencies": [ { "proficiency": "prof_handloading" } ], "components": [ [ [ "46mm_casing", 1 ] ], [ [ "smpistol_primer", 1 ] ], @@ -950,6 +1000,7 @@ "reversible": true, "using": [ [ "bullet_forming", 3 ], [ "ammo_bullet", 3 ] ], "//": "842 mg gunpowder rounded to 8 100 mg 'pieces'", + "proficiencies": [ { "proficiency": "prof_handloading" } ], "components": [ [ [ "460_casing", 1 ] ], [ [ "lgpistol_primer", 1 ] ], @@ -973,6 +1024,7 @@ "reversible": true, "using": [ [ "bullet_forming", 3 ], [ "ammo_bullet", 3 ] ], "//": "842 mg gunpowder rounded to 8 100 mg 'pieces'", + "proficiencies": [ { "proficiency": "prof_handloading" } ], "components": [ [ [ "460_casing", 1 ] ], [ [ "lgpistol_primer", 1 ] ], @@ -996,6 +1048,7 @@ "reversible": true, "using": [ [ "bullet_forming", 6 ], [ "ammo_bullet", 8 ] ], "//": "1943 mg gunpowder rounded to 19 100 mg 'pieces'", + "proficiencies": [ { "proficiency": "prof_handloading" } ], "components": [ [ [ "500_casing", 1 ] ], [ [ "lgrifle_primer", 1 ] ], @@ -1019,6 +1072,7 @@ "reversible": true, "using": [ [ "bullet_forming", 2 ], [ "ammo_bullet", 1 ] ], "//": "388 mg gunpowder rounded to 4 100 mg 'pieces'", + "proficiencies": [ { "proficiency": "prof_handloading" } ], "components": [ [ [ "57mm_casing", 1 ] ], [ [ "smrifle_primer", 1 ] ], @@ -1041,6 +1095,7 @@ "charges": 1, "reversible": true, "using": [ [ "bullet_forming", 2 ], [ "ammo_bullet", 2 ], [ "ammo_762_25", 1 ] ], + "proficiencies": [ { "proficiency": "prof_handloading" } ], "//": "390 mg gunpowder rounded to 4 100 mg 'pieces'", "components": [ [ [ "gunpowder", 4 ], [ "gunpowder_pistol", 4 ] ], [ [ "copper", 1 ] ] ] }, @@ -1059,6 +1114,7 @@ "charges": 1, "reversible": true, "using": [ [ "bullet_forming", 2 ], [ "ammo_bullet", 2 ], [ "ammo_9mm", 1 ] ], + "proficiencies": [ { "proficiency": "prof_handloading" } ], "//": "290 mg gunpowder rounded to 3 100 mg 'pieces'", "components": [ [ [ "gunpowder", 3 ], [ "gunpowder_pistol", 3 ], [ "gunpowder_shotgun", 3 ] ], [ [ "copper", 1 ] ] ] }, @@ -1077,6 +1133,7 @@ "charges": 1, "reversible": true, "using": [ [ "bullet_forming", 2 ], [ "ammo_bullet", 2 ], [ "ammo_9mm", 1 ] ], + "proficiencies": [ { "proficiency": "prof_handloading" } ], "//": "537 mg gunpowder rounded to 5 100 mg 'pieces'", "components": [ [ [ "gunpowder", 5 ], [ "gunpowder_pistol", 5 ] ], [ [ "copper", 1 ] ] ] }, @@ -1095,6 +1152,7 @@ "charges": 1, "reversible": true, "using": [ [ "bullet_forming", 2 ], [ "ammo_bullet", 2 ], [ "ammo_9mm", 1 ] ], + "proficiencies": [ { "proficiency": "prof_handloading" } ], "//": "Arbitrary powder amount as +p+ is not a real standard but an informal one which has about 20% higher pressure than standard 9mm, while +p is a standard that has 10% higher pressure. 580 mg gunpowder rounded to 6 100 mg 'pieces'", "components": [ [ [ "gunpowder", 6 ], [ "gunpowder_pistol", 6 ] ], [ [ "copper", 1 ] ] ] }, @@ -1113,6 +1171,7 @@ "charges": 1, "reversible": true, "using": [ [ "bullet_forming", 2 ], [ "ammo_bullet", 2 ], [ "ammo_9mm", 1 ] ], + "proficiencies": [ { "proficiency": "prof_handloading" } ], "//": "290 mg gunpowder rounded to 3 100 mg 'pieces'", "components": [ [ [ "gunpowder", 3 ], [ "gunpowder_pistol", 3 ], [ "gunpowder_shotgun", 3 ] ], [ [ "copper", 1 ] ] ] }, @@ -1132,6 +1191,7 @@ "reversible": true, "using": [ [ "bullet_forming", 2 ], [ "ammo_bullet", 2 ] ], "//": "401 mg gunpowder rounded to 4 100 mg 'pieces'", + "proficiencies": [ { "proficiency": "prof_handloading" } ], "components": [ [ [ "9x18mm_casing", 1 ] ], [ [ "smpistol_primer", 1 ] ], @@ -1155,6 +1215,7 @@ "reversible": true, "using": [ [ "bullet_forming", 2 ], [ "ammo_bullet", 2 ] ], "//": "401 mg gunpowder rounded to 4 100 mg 'pieces'", + "proficiencies": [ { "proficiency": "prof_handloading" } ], "components": [ [ [ "9x18mm_casing", 1 ] ], [ [ "smpistol_primer", 1 ] ], @@ -1177,6 +1238,7 @@ "charges": 1, "reversible": true, "using": [ [ "bullet_forming", 2 ], [ "ammo_bullet", 2 ] ], + "proficiencies": [ { "proficiency": "prof_handloading" } ], "//": "Arbitrary powder amount as +p+ is not a real standard but an informal one which has about 20% higher pressure than standard 9mm, while +p is a standard that has 10% higher pressure. 481 mg gunpowder rounded to 5 100 mg 'pieces'", "components": [ [ [ "9x18mm_casing", 1 ] ], @@ -1200,6 +1262,7 @@ "charges": 1, "reversible": true, "using": [ [ "bullet_forming", 2 ], [ "ammo_bullet", 2 ], [ "ammo_380", 1 ] ], + "proficiencies": [ { "proficiency": "prof_handloading" } ], "//": "278 mg gunpowder rounded to 3 100 mg 'pieces'", "components": [ [ [ "gunpowder", 3 ], [ "gunpowder_pistol", 3 ], [ "gunpowder_shotgun", 3 ] ], [ [ "copper", 1 ] ] ] }, @@ -1218,6 +1281,7 @@ "charges": 1, "reversible": true, "using": [ [ "bullet_forming", 2 ], [ "ammo_bullet", 2 ], [ "ammo_380", 1 ] ], + "proficiencies": [ { "proficiency": "prof_handloading" } ], "//": "320 mg gunpowder rounded to 3 100 mg 'pieces'", "components": [ [ [ "gunpowder", 3 ], [ "gunpowder_pistol", 3 ], [ "gunpowder_shotgun", 3 ] ], [ [ "copper", 1 ] ] ] }, @@ -1236,6 +1300,7 @@ "charges": 1, "reversible": true, "using": [ [ "bullet_forming", 2 ], [ "ammo_bullet", 2 ], [ "ammo_380", 1 ] ], + "proficiencies": [ { "proficiency": "prof_handloading" } ], "//": "278 mg gunpowder rounded to 3 100 mg 'pieces'", "components": [ [ [ "gunpowder", 3 ], [ "gunpowder_pistol", 3 ], [ "gunpowder_shotgun", 3 ] ], [ [ "copper", 1 ] ] ] } diff --git a/data/json/recipes/ammo/rifle.json b/data/json/recipes/ammo/rifle.json index 12a35a9055660..1b02e79926de9 100644 --- a/data/json/recipes/ammo/rifle.json +++ b/data/json/recipes/ammo/rifle.json @@ -15,6 +15,7 @@ "reversible": true, "using": [ [ "ammo_bullet", 10 ] ], "qualities": [ { "id": "CUT", "level": 1 } ], + "proficiencies": [ { "proficiency": "prof_handloading" } ], "components": [ [ [ "chem_black_powder", 30 ] ], [ [ "paper", 1 ] ] ] }, { @@ -33,6 +34,7 @@ "reversible": true, "using": [ [ "ammo_bullet", 10 ] ], "qualities": [ { "id": "CUT", "level": 1 } ], + "proficiencies": [ { "proficiency": "prof_handloading" } ], "components": [ [ [ "chem_black_powder", 30 ] ], [ [ "paper", 1 ] ] ] }, { @@ -51,6 +53,7 @@ "reversible": true, "using": [ [ "bullet_forming", 3 ], [ "ammo_bullet", 1 ] ], "//": "65 mg gunpowder rounded to 1 100 mg 'pieces'", + "proficiencies": [ { "proficiency": "prof_handloading" } ], "components": [ [ [ "22_casing_new", 1 ] ], [ [ "gunpowder", 1 ], [ "gunpowder_pistol", 1 ] ], [ [ "copper", 1 ] ] ] }, { @@ -69,6 +72,7 @@ "reversible": true, "using": [ [ "bullet_forming", 2 ], [ "ammo_bullet", 1 ] ], "//": "65 mg gunpowder rounded to 1 100 mg 'pieces'", + "proficiencies": [ { "proficiency": "prof_handloading" } ], "components": [ [ [ "22_casing_new", 1 ] ], [ [ "gunpowder", 1 ], [ "gunpowder_pistol", 1 ] ] ] }, { @@ -86,6 +90,7 @@ "charges": 1, "reversible": true, "using": [ [ "bullet_forming", 3 ], [ "ammo_bullet", 1 ] ], + "proficiencies": [ { "proficiency": "prof_handloading" } ], "components": [ [ [ "22_casing_new", 1 ] ], [ [ "chem_black_powder", 1 ] ], [ [ "copper", 1 ] ] ] }, { @@ -103,6 +108,7 @@ "charges": 1, "reversible": true, "using": [ [ "bullet_forming", 2 ], [ "ammo_bullet", 1 ] ], + "proficiencies": [ { "proficiency": "prof_handloading" } ], "components": [ [ [ "22_casing_new", 1 ] ], [ [ "chem_black_powder", 1 ] ] ] }, { @@ -121,6 +127,7 @@ "reversible": true, "using": [ [ "bullet_forming", 4 ], [ "ammo_bullet", 1 ] ], "//": "1500 mg gunpowder rounded to 15 100 mg 'pieces'", + "proficiencies": [ { "proficiency": "prof_handloading" } ], "components": [ [ [ "223_casing", 1 ] ], [ [ "smrifle_primer", 1 ] ], @@ -143,6 +150,7 @@ "charges": 1, "reversible": true, "using": [ [ "bullet_forming", 4 ], [ "ammo_bullet", 1 ] ], + "proficiencies": [ { "proficiency": "prof_handloading" } ], "components": [ [ [ "223_casing", 1 ] ], [ [ "smrifle_primer", 1 ] ], [ [ "chem_black_powder", 15 ] ], [ [ "copper", 1 ] ] ] }, { @@ -161,6 +169,7 @@ "reversible": true, "using": [ [ "bullet_forming", 8 ], [ "ammo_bullet", 3 ], [ "ammo_270win", 1 ] ], "//": "2974 mg gunpowder rounded to 30 100 mg 'pieces'", + "proficiencies": [ { "proficiency": "prof_handloading" } ], "components": [ [ [ "gunpowder", 30 ], [ "gunpowder_magnum_pistol", 30 ], [ "gunpowder_rifle", 30 ] ], [ [ "copper", 1 ] ] ] }, { @@ -178,6 +187,7 @@ "charges": 1, "reversible": true, "using": [ [ "bullet_forming", 8 ], [ "ammo_bullet", 3 ], [ "ammo_270win", 1 ] ], + "proficiencies": [ { "proficiency": "prof_handloading" } ], "components": [ [ [ "chem_black_powder", 30 ] ], [ [ "copper", 1 ] ] ] }, { @@ -196,6 +206,7 @@ "reversible": true, "using": [ [ "bullet_forming", 12 ], [ "ammo_bullet", 4 ] ], "//": "4327 mg gunpowder rounded to 43 100 mg 'pieces'", + "proficiencies": [ { "proficiency": "prof_handloading" } ], "components": [ [ [ "300_casing", 1 ] ], [ [ "lgrifle_primer", 1 ] ], @@ -218,6 +229,7 @@ "charges": 1, "reversible": true, "using": [ [ "bullet_forming", 12 ], [ "ammo_bullet", 4 ] ], + "proficiencies": [ { "proficiency": "prof_handloading" } ], "components": [ [ [ "300_casing", 1 ] ], [ [ "lgrifle_primer", 1 ] ], [ [ "chem_black_powder", 43 ] ], [ [ "copper", 2 ] ] ] }, { @@ -236,6 +248,7 @@ "reversible": true, "using": [ [ "bullet_forming", 12 ], [ "ammo_bullet", 3 ] ], "//": "3200 mg gunpowder rounded to 32 100 mg 'pieces'", + "proficiencies": [ { "proficiency": "prof_handloading" } ], "components": [ [ [ "3006_casing", 1 ] ], [ [ "lgrifle_primer", 1 ] ], @@ -259,6 +272,7 @@ "reversible": true, "using": [ [ "bullet_forming", 12 ], [ "ammo_bullet", 4 ] ], "//": "3300 mg gunpowder rounded to 33 100 mg 'pieces'", + "proficiencies": [ { "proficiency": "prof_handloading" } ], "components": [ [ [ "3006_casing", 1 ] ], [ [ "lgrifle_primer", 1 ] ], @@ -282,6 +296,7 @@ "reversible": true, "using": [ [ "bullet_forming", 12 ], [ "ammo_bullet", 4 ] ], "//": "3300 mg gunpowder rounded to 33 100 mg 'pieces'", + "proficiencies": [ { "proficiency": "prof_handloading" } ], "components": [ [ [ "3006_casing", 1 ] ], [ [ "lgrifle_primer", 1 ] ], @@ -310,6 +325,7 @@ "charges": 1, "reversible": true, "using": [ [ "bullet_forming", 12 ], [ "ammo_bullet", 4 ] ], + "proficiencies": [ { "proficiency": "prof_handloading" } ], "components": [ [ [ "3006_casing", 1 ] ], [ [ "lgrifle_primer", 1 ] ], [ [ "chem_black_powder", 32 ] ], [ [ "copper", 2 ] ] ] }, { @@ -327,6 +343,7 @@ "charges": 1, "reversible": true, "using": [ [ "bullet_forming", 12 ], [ "ammo_bullet", 4 ] ], + "proficiencies": [ { "proficiency": "prof_handloading" } ], "components": [ [ [ "3006_casing", 1 ] ], [ [ "lgrifle_primer", 1 ] ], [ [ "chem_black_powder", 33 ] ], [ [ "copper", 2 ] ] ] }, { @@ -344,6 +361,7 @@ "charges": 1, "reversible": true, "using": [ [ "bullet_forming", 12 ], [ "ammo_bullet", 4 ] ], + "proficiencies": [ { "proficiency": "prof_handloading" } ], "components": [ [ [ "3006_casing", 1 ] ], [ [ "lgrifle_primer", 1 ] ], @@ -368,6 +386,7 @@ "reversible": true, "using": [ [ "bullet_forming", 9 ], [ "ammo_bullet", 3 ] ], "//": "2800 mg gunpowder rounded to 28 100 mg 'pieces'", + "proficiencies": [ { "proficiency": "prof_handloading" } ], "components": [ [ [ "308_casing", 1 ], [ "762_51_casing", 1 ] ], [ [ "lgrifle_primer", 1 ] ], @@ -395,6 +414,7 @@ "charges": 1, "reversible": true, "using": [ [ "bullet_forming", 9 ], [ "ammo_bullet", 3 ] ], + "proficiencies": [ { "proficiency": "prof_handloading" } ], "components": [ [ [ "308_casing", 1 ], [ "762_51_casing", 1 ] ], [ [ "lgrifle_primer", 1 ] ], @@ -418,6 +438,7 @@ "reversible": true, "using": [ [ "bullet_forming", 15 ], [ "ammo_bullet", 5 ] ], "//": "2844 mg gunpowder rounded to 28 100 mg 'pieces'", + "proficiencies": [ { "proficiency": "prof_handloading" } ], "components": [ [ [ "4570_casing", 1 ] ], [ [ "lgrifle_primer", 1 ] ], @@ -442,6 +463,7 @@ "reversible": true, "using": [ [ "bullet_forming", 15 ], [ "ammo_bullet", 3 ] ], "//": "3000 mg gunpowder rounded to 30 100 mg 'pieces'", + "proficiencies": [ { "proficiency": "prof_handloading" } ], "components": [ [ [ "4570_casing", 1 ] ], [ [ "lgrifle_primer", 1 ] ], @@ -465,6 +487,7 @@ "reversible": true, "using": [ [ "bullet_forming", 15 ], [ "ammo_bullet", 8 ] ], "//": "1944 mg gunpowder rounded to 19 100 mg 'pieces'", + "proficiencies": [ { "proficiency": "prof_handloading" } ], "components": [ [ [ "4570_casing", 1 ] ], [ [ "lgrifle_primer", 1 ] ], @@ -487,6 +510,7 @@ "charges": 1, "reversible": true, "using": [ [ "bullet_forming", 15 ], [ "ammo_bullet", 8 ] ], + "proficiencies": [ { "proficiency": "prof_handloading" } ], "components": [ [ [ "4570_casing", 1 ] ], [ [ "lgrifle_primer", 1 ] ], [ [ "chem_black_powder", 19 ] ], [ [ "copper", 3 ] ] ] }, { @@ -503,7 +527,7 @@ "book_learn": [ [ "recipe_caseless", 4 ] ], "charges": 1, "reversible": true, - "proficiencies": [ { "proficiency": "prof_plasticworking" } ], + "proficiencies": [ { "proficiency": "prof_plasticworking" }, { "proficiency": "prof_handloading" } ], "using": [ [ "bullet_forming", 2 ], [ "ammo_bullet", 2 ], [ "plastic_molding", 1 ] ], "//": "3000 mg gunpowder rounded to 30 100 mg 'pieces'", "components": [ @@ -529,6 +553,7 @@ "reversible": true, "using": [ [ "bullet_forming", 18 ], [ "ammo_bullet", 12 ] ], "//": "15800 mg gunpowder rounded to 158 100 mg 'pieces'", + "proficiencies": [ { "proficiency": "prof_handloading" } ], "components": [ [ [ "50_casing", 1 ] ], [ [ "lgrifle_primer", 1 ] ], @@ -551,6 +576,7 @@ "charges": 1, "reversible": true, "using": [ [ "bullet_forming", 18 ], [ "ammo_bullet", 12 ] ], + "proficiencies": [ { "proficiency": "prof_handloading" } ], "components": [ [ [ "50_casing", 1 ] ], [ [ "lgrifle_primer", 1 ] ], [ [ "chem_black_powder", 158 ] ], [ [ "copper", 6 ] ] ] }, { @@ -569,6 +595,7 @@ "reversible": true, "using": [ [ "bullet_forming", 21 ], [ "ammo_bullet", 12 ] ], "//": "15800 mg gunpowder rounded to 158 100 mg 'pieces'", + "proficiencies": [ { "proficiency": "prof_handloading" } ], "components": [ [ [ "50_casing", 1 ] ], [ [ "lgrifle_primer", 1 ] ], @@ -592,6 +619,7 @@ "charges": 1, "reversible": true, "using": [ [ "bullet_forming", 21 ], [ "ammo_bullet", 12 ] ], + "proficiencies": [ { "proficiency": "prof_handloading" } ], "components": [ [ [ "50_casing", 1 ] ], [ [ "lgrifle_primer", 1 ] ], @@ -616,6 +644,7 @@ "reversible": true, "using": [ [ "bullet_forming", 21 ] ], "//": "15800 mg gunpowder rounded to 158 100 mg 'pieces'", + "proficiencies": [ { "proficiency": "prof_handloading" } ], "components": [ [ [ "50_casing", 1 ] ], [ [ "lgrifle_primer", 1 ] ], @@ -639,6 +668,7 @@ "charges": 1, "reversible": true, "using": [ [ "bullet_forming", 21 ] ], + "proficiencies": [ { "proficiency": "prof_handloading" } ], "components": [ [ [ "50_casing", 1 ] ], [ [ "lgrifle_primer", 1 ] ], @@ -663,6 +693,7 @@ "reversible": true, "using": [ [ "bullet_forming", 4 ], [ "ammo_bullet", 1 ] ], "//": "1295 mg gunpowder rounded to 13 100 mg 'pieces'", + "proficiencies": [ { "proficiency": "prof_handloading" } ], "components": [ [ [ "545_casing", 1 ] ], [ [ "smrifle_primer", 1 ] ], @@ -685,6 +716,7 @@ "charges": 1, "reversible": true, "using": [ [ "bullet_forming", 4 ], [ "ammo_bullet", 1 ] ], + "proficiencies": [ { "proficiency": "prof_handloading" } ], "components": [ [ [ "545_casing", 1 ] ], [ [ "smrifle_primer", 1 ] ], [ [ "chem_black_powder", 13 ] ], [ [ "copper", 1 ] ] ] }, { @@ -703,6 +735,7 @@ "reversible": true, "using": [ [ "bullet_forming", 4 ], [ "ammo_bullet", 1 ] ], "//": "1295 mg gunpowder rounded to 13 100 mg 'pieces'", + "proficiencies": [ { "proficiency": "prof_handloading" } ], "components": [ [ [ "545_casing", 1 ] ], [ [ "smrifle_primer", 1 ] ], @@ -725,6 +758,7 @@ "charges": 1, "reversible": true, "using": [ [ "bullet_forming", 4 ], [ "ammo_bullet", 1 ] ], + "proficiencies": [ { "proficiency": "prof_handloading" } ], "components": [ [ [ "545_casing", 1 ] ], [ [ "smrifle_primer", 1 ] ], [ [ "chem_black_powder", 13 ] ], [ [ "copper", 1 ] ] ] }, { @@ -742,6 +776,7 @@ "charges": 1, "reversible": true, "using": [ [ "bullet_forming", 4 ], [ "ammo_bullet", 3 ], [ "ammo_300blk", 1 ] ], + "proficiencies": [ { "proficiency": "prof_handloading" } ], "//": "1133 mg gunpowder rounded to 11 100 mg 'pieces'", "components": [ [ [ "gunpowder", 11 ] ], [ [ "copper", 1 ] ] ] }, @@ -760,6 +795,7 @@ "charges": 1, "reversible": true, "using": [ [ "bullet_forming", 4 ], [ "ammo_bullet", 3 ], [ "ammo_300blk", 1 ] ], + "proficiencies": [ { "proficiency": "prof_handloading" } ], "components": [ [ [ "chem_black_powder", 11 ] ], [ [ "copper", 1 ] ] ] }, { @@ -778,6 +814,7 @@ "reversible": true, "using": [ [ "bullet_forming", 20 ] ], "//": "1717 mg gunpowder rounded to 17 100 mg 'pieces'", + "proficiencies": [ { "proficiency": "prof_handloading" } ], "components": [ [ [ "223_casing", 1 ] ], [ [ "smrifle_primer", 1 ] ], @@ -802,6 +839,7 @@ "reversible": true, "using": [ [ "bullet_forming", 4 ], [ "ammo_bullet", 1 ] ], "//": "1717 mg gunpowder rounded to 17 100 mg 'pieces'", + "proficiencies": [ { "proficiency": "prof_handloading" } ], "components": [ [ [ "223_casing", 1 ] ], [ [ "smrifle_primer", 1 ] ], @@ -825,6 +863,7 @@ "charges": 1, "reversible": true, "using": [ [ "bullet_forming", 20 ] ], + "proficiencies": [ { "proficiency": "prof_handloading" } ], "components": [ [ [ "223_casing", 1 ] ], [ [ "smrifle_primer", 1 ] ], @@ -848,6 +887,7 @@ "charges": 1, "reversible": true, "using": [ [ "bullet_forming", 4 ], [ "ammo_bullet", 1 ] ], + "proficiencies": [ { "proficiency": "prof_handloading" } ], "components": [ [ [ "223_casing", 1 ] ], [ [ "smrifle_primer", 1 ] ], @@ -872,6 +912,7 @@ "reversible": true, "using": [ [ "bullet_forming", 20 ], [ "ammo_bullet", 18 ] ], "//": "16523 mg gunpowder rounded to 165 100 mg 'pieces'", + "proficiencies": [ { "proficiency": "prof_handloading" } ], "components": [ [ [ "700nx_casing", 1 ] ], [ [ "lgrifle_primer", 1 ] ], @@ -894,6 +935,7 @@ "charges": 1, "reversible": true, "using": [ [ "bullet_forming", 20 ], [ "ammo_bullet", 18 ] ], + "proficiencies": [ { "proficiency": "prof_handloading" } ], "components": [ [ [ "700nx_casing", 1 ] ], [ [ "lgrifle_primer", 1 ] ], [ [ "chem_black_powder", 165 ] ], [ [ "copper", 10 ] ] ] }, { @@ -912,6 +954,7 @@ "reversible": true, "using": [ [ "bullet_forming", 9 ], [ "ammo_bullet", 3 ] ], "//": "2462 mg gunpowder rounded to 25 100 mg 'pieces'", + "proficiencies": [ { "proficiency": "prof_handloading" } ], "components": [ [ [ "308_casing", 1 ], [ "762_51_casing", 1 ] ], [ [ "lgrifle_primer", 1 ] ], @@ -935,6 +978,7 @@ "reversible": true, "using": [ [ "bullet_forming", 9 ], [ "ammo_bullet", 3 ] ], "//": "2462 mg gunpowder rounded to 25 100 mg 'pieces'", + "proficiencies": [ { "proficiency": "prof_handloading" } ], "components": [ [ [ "308_casing", 1 ], [ "762_51_casing", 1 ] ], [ [ "lgrifle_primer", 1 ] ], @@ -963,6 +1007,7 @@ "charges": 1, "reversible": true, "using": [ [ "bullet_forming", 9 ], [ "ammo_bullet", 3 ] ], + "proficiencies": [ { "proficiency": "prof_handloading" } ], "components": [ [ [ "308_casing", 1 ], [ "762_51_casing", 1 ] ], [ [ "lgrifle_primer", 1 ] ], @@ -985,6 +1030,7 @@ "charges": 1, "reversible": true, "using": [ [ "bullet_forming", 9 ], [ "ammo_bullet", 3 ] ], + "proficiencies": [ { "proficiency": "prof_handloading" } ], "components": [ [ [ "308_casing", 1 ], [ "762_51_casing", 1 ] ], [ [ "lgrifle_primer", 1 ] ], @@ -1008,6 +1054,7 @@ "charges": 1, "reversible": true, "using": [ [ "bullet_forming", 10 ], [ "ammo_bullet", 3 ] ], + "proficiencies": [ { "proficiency": "prof_handloading" } ], "//": "2851 mg gunpowder rounded to 29 100 mg 'pieces'", "components": [ [ [ "762R_casing", 1 ] ], @@ -1036,6 +1083,7 @@ "charges": 1, "reversible": true, "using": [ [ "bullet_forming", 10 ], [ "ammo_bullet", 3 ] ], + "proficiencies": [ { "proficiency": "prof_handloading" } ], "components": [ [ [ "762R_casing", 1 ] ], [ [ "lgrifle_primer", 1 ] ], [ [ "chem_black_powder", 29 ] ], [ [ "copper", 2 ] ] ] }, { @@ -1053,6 +1101,7 @@ "charges": 1, "reversible": true, "using": [ [ "bullet_forming", 5 ], [ "ammo_bullet", 2 ] ], + "proficiencies": [ { "proficiency": "prof_handloading" } ], "//": "1535 mg gunpowder rounded to 15 100 mg 'pieces'", "components": [ [ [ "762_casing", 1 ] ], @@ -1077,6 +1126,7 @@ "charges": 1, "reversible": true, "using": [ [ "bullet_forming", 5 ], [ "ammo_bullet", 2 ] ], + "proficiencies": [ { "proficiency": "prof_handloading" } ], "components": [ [ [ "762_casing", 1 ] ], [ [ "lgrifle_primer", 1 ] ], @@ -1100,6 +1150,7 @@ "charges": 1, "reversible": true, "using": [ [ "bullet_forming", 5 ], [ "ammo_bullet", 3 ] ], + "proficiencies": [ { "proficiency": "prof_handloading" } ], "//": "1535 mg gunpowder rounded to 15 100 mg 'pieces'", "components": [ [ [ "762_casing", 1 ] ], @@ -1123,6 +1174,7 @@ "charges": 1, "reversible": true, "using": [ [ "bullet_forming", 5 ], [ "ammo_bullet", 3 ] ], + "proficiencies": [ { "proficiency": "prof_handloading" } ], "components": [ [ [ "762_casing", 1 ] ], [ [ "lgrifle_primer", 1 ] ], [ [ "chem_black_powder", 15 ] ], [ [ "copper", 2 ] ] ] } ] diff --git a/data/json/recipes/ammo/shot.json b/data/json/recipes/ammo/shot.json index 7b0f8e87235b2..ca6cdbfdeaf69 100644 --- a/data/json/recipes/ammo/shot.json +++ b/data/json/recipes/ammo/shot.json @@ -15,6 +15,7 @@ "reversible": true, "//": "Assumes standard 9 pellet 00 load. 1166 mg gunpowder rounded to 12 100 mg 'pieces'", "using": [ [ "shot_forming", 1 ], [ "ammo_bullet", 11 ], [ "ammo_shot", 1 ] ], + "proficiencies": [ { "proficiency": "prof_handloading" } ], "tools": [ [ [ "press", -1 ] ] ], "components": [ [ [ "gunpowder", 12 ], [ "gunpowder_pistol", 12 ], [ "gunpowder_shotgun", 12 ] ] ] }, @@ -33,6 +34,7 @@ "charges": 1, "reversible": true, "using": [ [ "shot_forming", 1 ], [ "ammo_bullet", 8 ], [ "ammo_410shot", 1 ] ], + "proficiencies": [ { "proficiency": "prof_handloading" } ], "tools": [ [ [ "press", -1 ] ] ], "//": "971 mg gunpowder rounded to 10 100 mg 'pieces'", "components": [ [ [ "gunpowder", 10 ], [ "gunpowder_pistol", 10 ], [ "gunpowder_shotgun", 10 ] ] ] @@ -52,6 +54,7 @@ "charges": 1, "reversible": true, "using": [ [ "shot_forming", 1 ], [ "ammo_bullet", 10 ], [ "ammo_shot", 1 ] ], + "proficiencies": [ { "proficiency": "prof_handloading" } ], "tools": [ [ [ "press", -1 ] ] ], "//": "1490 mg gunpowder rounded to 15 100 mg 'pieces'", "components": [ [ [ "gunpowder", 15 ], [ "gunpowder_pistol", 15 ], [ "gunpowder_shotgun", 15 ] ] ] @@ -70,6 +73,7 @@ "book_learn": [ [ "recipe_bullets", 3 ], [ "manual_shotgun", 3 ] ], "charges": 1, "using": [ [ "ammo_shot", 1 ] ], + "proficiencies": [ { "proficiency": "prof_handloading" } ], "tools": [ [ [ "press", -1 ] ] ], "//": "same charge as a 1 oz load, could find no refference to actual loading data. 1490 mg gunpowder rounded to 15 100 mg 'pieces'", "components": [ [ [ "gunpowder", 15 ], [ "gunpowder_pistol", 15 ], [ "gunpowder_shotgun", 15 ] ], [ [ "magnesium", 5 ] ] ] @@ -89,6 +93,7 @@ "charges": 1, "reversible": true, "using": [ [ "ammo_shot", 1 ] ], + "proficiencies": [ { "proficiency": "prof_handloading" } ], "tools": [ [ [ "press", -1 ] ] ], "//": "Wikipedia states the shells contain 20 7.3 grain flechettes for a 146 grain or 1/3 oz load. http://www.sabotdesigns.com/002.html lists flechette velocity at 1950 fps. Gunpowder charge is calculated as if it was a solid slug for sake of ease. 750 mg gunpowder rounded to 8 100 mg 'pieces", "components": [ [ [ "gunpowder", 8 ], [ "gunpowder_pistol", 8 ], [ "gunpowder_shotgun", 8 ] ], [ [ "combatnail", 10 ] ] ] @@ -109,6 +114,7 @@ "reversible": true, "//": "assumes 1 oz slug. 1684 mg gunpowder rounded to 17 100 mg 'pieces'", "using": [ [ "bullet_forming", 1 ], [ "ammo_bullet", 10 ], [ "ammo_shot", 1 ] ], + "proficiencies": [ { "proficiency": "prof_handloading" } ], "components": [ [ [ "gunpowder", 17 ], [ "gunpowder_pistol", 17 ], [ "gunpowder_shotgun", 17 ] ] ] }, { @@ -126,6 +132,7 @@ "charges": 1, "reversible": true, "using": [ [ "shot_forming", 1 ], [ "ammo_bullet", 11 ], [ "ammo_shot", 1 ] ], + "proficiencies": [ { "proficiency": "prof_handloading" } ], "tools": [ [ [ "press", -1 ] ] ], "components": [ [ [ "chem_black_powder", 12 ] ] ] }, @@ -145,6 +152,7 @@ "reversible": true, "//": "assumes 1 oz load", "using": [ [ "shot_forming", 1 ], [ "ammo_bullet", 10 ], [ "ammo_shot", 1 ] ], + "proficiencies": [ { "proficiency": "prof_handloading" } ], "tools": [ [ [ "press", -1 ] ] ], "components": [ [ [ "chem_black_powder", 15 ] ] ] }, @@ -163,6 +171,7 @@ "charges": 1, "reversible": true, "using": [ [ "ammo_shot", 1 ] ], + "proficiencies": [ { "proficiency": "prof_handloading" } ], "tools": [ [ [ "press", -1 ] ] ], "components": [ [ [ "chem_black_powder", 15 ] ], [ [ "magnesium", 5 ] ] ] }, @@ -181,6 +190,7 @@ "charges": 1, "reversible": true, "using": [ [ "ammo_shot", 1 ] ], + "proficiencies": [ { "proficiency": "prof_handloading" } ], "tools": [ [ [ "press", -1 ] ] ], "components": [ [ [ "chem_black_powder", 8 ] ], [ [ "combatnail", 10 ] ] ] }, @@ -199,6 +209,7 @@ "charges": 1, "reversible": true, "using": [ [ "bullet_forming", 1 ], [ "ammo_bullet", 10 ], [ "ammo_shot", 1 ] ], + "proficiencies": [ { "proficiency": "prof_handloading" } ], "components": [ [ [ "chem_black_powder", 17 ] ] ] }, { @@ -271,6 +282,7 @@ "using": [ [ "ammo_shot", 2 ] ], "tools": [ [ [ "press", -1 ] ] ], "//": "1166 mg gunpowder rounded to 12 100 mg 'pieces'; recipe makes two shells", + "proficiencies": [ { "proficiency": "prof_handloading" } ], "components": [ [ [ "gunpowder", 23 ], [ "gunpowder_pistol", 23 ], [ "gunpowder_shotgun", 23 ] ], [ @@ -303,6 +315,7 @@ "charges": 2, "reversible": true, "using": [ [ "ammo_shot", 2 ] ], + "proficiencies": [ { "proficiency": "prof_handloading" } ], "tools": [ [ [ "press", -1 ] ] ], "components": [ [ [ "chem_black_powder", 23 ] ], @@ -362,6 +375,7 @@ "book_learn": [ [ "recipe_bullets", 3 ], [ "manual_shotgun", 2 ], [ "pocket_survival", 2 ], [ "mag_survival", 2 ] ], "charges": 1, "using": [ [ "ammo_shot", 1 ] ], + "proficiencies": [ { "proficiency": "prof_handloading" } ], "tools": [ [ [ "press", -1 ] ] ], "components": [ [ [ "incendiary", 25 ] ] ] }, @@ -380,6 +394,7 @@ "charges": 1, "reversible": true, "using": [ [ "ammo_bullet", 8 ] ], + "proficiencies": [ { "proficiency": "prof_handloading" } ], "qualities": [ { "id": "CUT", "level": 1 } ], "components": [ [ [ "chem_black_powder", 15 ] ], [ [ "shotgun_primer", 1 ] ], [ [ "paper", 1 ], [ "aluminum_foil", 1 ] ] ] }, @@ -398,6 +413,7 @@ "charges": 1, "reversible": true, "using": [ [ "ammo_bullet", 16 ] ], + "proficiencies": [ { "proficiency": "prof_handloading" } ], "qualities": [ { "id": "CUT", "level": 1 } ], "components": [ [ [ "chem_black_powder", 15 ] ], [ [ "shotgun_primer", 1 ] ], [ [ "paper", 1 ], [ "aluminum_foil", 1 ] ] ] }, @@ -416,6 +432,7 @@ "charges": 1, "reversible": true, "using": [ [ "ammo_bullet", 16 ] ], + "proficiencies": [ { "proficiency": "prof_handloading" } ], "qualities": [ { "id": "CUT", "level": 1 } ], "components": [ [ [ "chem_black_powder", 12 ] ], @@ -439,6 +456,7 @@ "charges": 1, "reversible": true, "using": [ [ "ammo_bullet", 8 ] ], + "proficiencies": [ { "proficiency": "prof_handloading" } ], "qualities": [ { "id": "CUT", "level": 1 } ], "components": [ [ [ "chem_black_powder", 15 ] ], [ [ "shotgun_primer", 1 ] ], [ [ "paper", 1 ], [ "aluminum_foil", 1 ] ] ] } diff --git a/data/json/recipes/recipe_ammo.json b/data/json/recipes/recipe_ammo.json index 2e62dea8f6346..d3750c6917f6d 100644 --- a/data/json/recipes/recipe_ammo.json +++ b/data/json/recipes/recipe_ammo.json @@ -556,6 +556,7 @@ "autolearn": true, "book_learn": [ [ "recipe_bullets", 2 ], [ "manual_shotgun", 2 ] ], "qualities": [ { "id": "CUT", "level": 1 } ], + "proficiencies": [ { "proficiency": "prof_handloading" } ], "components": [ [ [ "gunpowder", 20 ], [ "chem_black_powder", 20 ] ], [ @@ -584,6 +585,7 @@ "autolearn": true, "book_learn": [ [ "recipe_bullets", 2 ], [ "manual_shotgun", 2 ] ], "qualities": [ { "id": "CUT", "level": 1 }, { "id": "SAW_M", "level": 1 } ], + "proficiencies": [ { "proficiency": "prof_handloading" } ], "components": [ [ [ "gunpowder", 20 ], [ "chem_black_powder", 20 ] ], [ [ "scrap", 1 ], [ "nail", 8 ], [ "copper", 16 ], [ "lead", 16 ] ], @@ -603,6 +605,7 @@ "autolearn": true, "book_learn": [ [ "recipe_bullets", 2 ], [ "manual_shotgun", 2 ] ], "qualities": [ { "id": "CUT", "level": 1 }, { "id": "SAW_M", "level": 1 } ], + "proficiencies": [ { "proficiency": "prof_handloading" } ], "components": [ [ [ "gunpowder", 20 ], [ "chem_black_powder", 20 ] ], [ [ "rebar", 1 ], [ "spear_rebar", 1 ], [ "rebar_rail", 1 ], [ "steel_rail", 1 ], [ "scrap", 1 ] ], @@ -624,6 +627,7 @@ "book_learn": [ [ "recipe_bullets", 2 ], [ "manual_shotgun", 2 ] ], "qualities": [ { "id": "CUT", "level": 1 }, { "id": "HAMMER", "level": 1 } ], "using": [ [ "surface_heat", 2 ] ], + "proficiencies": [ { "proficiency": "prof_handloading" } ], "components": [ [ [ "gunpowder", 20 ], [ "chem_black_powder", 20 ] ], [ [ "lead", 24 ] ], [ [ "paper", 1 ], [ "aluminum_foil", 1 ] ] ] }, { @@ -639,6 +643,7 @@ "autolearn": true, "book_learn": [ [ "recipe_bullets", 2 ], [ "manual_shotgun", 2 ] ], "qualities": [ { "id": "CUT", "level": 1 } ], + "proficiencies": [ { "proficiency": "prof_handloading" } ], "components": [ [ [ "gunpowder", 20 ], [ "chem_black_powder", 20 ] ], [ [ "nail", 8 ], [ "combatnail", 8 ] ], diff --git a/data/mods/Generic_Guns/recipes/recipes_grenade_propelled.json b/data/mods/Generic_Guns/recipes/recipes_grenade_propelled.json index 8d0dbedf2d1a9..5099e347436ba 100644 --- a/data/mods/Generic_Guns/recipes/recipes_grenade_propelled.json +++ b/data/mods/Generic_Guns/recipes/recipes_grenade_propelled.json @@ -14,6 +14,7 @@ "charges": 1, "reversible": true, "using": [ [ "bullet_forming", 2 ], [ "ammo_bullet", 12 ], [ "req_grenade", -1 ] ], + "proficiencies": [ { "proficiency": "prof_handloading" } ], "tools": [ [ [ "press", -1 ] ], [ [ "swage", -1 ] ] ], "qualities": [ { "id": "CUT", "level": 1 } ], "components": [ @@ -37,6 +38,7 @@ "charges": 1, "reversible": true, "using": [ [ "bullet_forming", 2 ], [ "ammo_bullet", 12 ], [ "req_grenade", -1 ] ], + "proficiencies": [ { "proficiency": "prof_handloading" } ], "tools": [ [ [ "press", -1 ] ], [ [ "swage", -1 ] ] ], "qualities": [ { "id": "CUT", "level": 1 } ], "components": [ diff --git a/data/mods/Generic_Guns/recipes/recipes_pistol.json b/data/mods/Generic_Guns/recipes/recipes_pistol.json index 5912d6bf07e73..ba751161e446f 100644 --- a/data/mods/Generic_Guns/recipes/recipes_pistol.json +++ b/data/mods/Generic_Guns/recipes/recipes_pistol.json @@ -14,6 +14,7 @@ "charges": 1, "reversible": true, "using": [ [ "req_pistol_tiny", 1 ], [ "bullet_forming", 2 ], [ "ammo_bullet", 2 ] ], + "proficiencies": [ { "proficiency": "prof_handloading" } ], "components": [ [ [ "gunpowder", 2 ], [ "gunpowder_pistol", 2 ], [ "gunpowder_shotgun", 2 ] ] ] }, { @@ -29,6 +30,7 @@ "activity_level": "fake", "copy-from": "reloaded_tiny_pistol_jhp", "using": [ [ "req_pistol_tiny", 1 ], [ "bullet_forming", 2 ], [ "ammo_bullet", 2 ] ], + "proficiencies": [ { "proficiency": "prof_handloading" } ], "components": [ [ [ "gunpowder", 2 ], [ "gunpowder_pistol", 2 ] ], [ [ "copper", 1 ] ] ] }, { @@ -53,6 +55,7 @@ "charges": 1, "reversible": true, "using": [ [ "req_pistol", 1 ], [ "bullet_forming", 2 ], [ "ammo_bullet", 2 ] ], + "proficiencies": [ { "proficiency": "prof_handloading" } ], "components": [ [ [ "gunpowder", 4 ], [ "gunpowder_pistol", 4 ], [ "gunpowder_shotgun", 4 ] ] ] }, { @@ -68,6 +71,7 @@ "activity_level": "fake", "copy-from": "reloaded_pistol_jhp", "using": [ [ "req_pistol", 1 ], [ "bullet_forming", 2 ], [ "ammo_bullet", 2 ] ], + "proficiencies": [ { "proficiency": "prof_handloading" } ], "components": [ [ [ "gunpowder", 4 ], [ "gunpowder_pistol", 4 ], [ "gunpowder_shotgun", 4 ] ], [ [ "copper", 1 ], [ "pistol_tiny_casing", 1 ] ] @@ -95,6 +99,7 @@ "charges": 1, "reversible": true, "using": [ [ "req_pistol_magnum", 1 ], [ "bullet_forming", 5 ], [ "ammo_bullet", 5 ] ], + "proficiencies": [ { "proficiency": "prof_handloading" } ], "components": [ [ [ "gunpowder", 6 ], [ "gunpowder_rifle", 6 ], [ "gunpowder_magnum_pistol", 6 ] ] ] }, { @@ -110,6 +115,7 @@ "activity_level": "fake", "copy-from": "reloaded_pistol_magnum_jhp", "using": [ [ "req_pistol_magnum", 1 ], [ "bullet_forming", 5 ], [ "ammo_bullet", 4 ] ], + "proficiencies": [ { "proficiency": "prof_handloading" } ], "components": [ [ [ "gunpowder", 6 ], [ "gunpowder_rifle", 6 ], [ "gunpowder_magnum_pistol", 6 ] ], [ [ "copper", 2 ], [ "pistol_magnum_casing", 1 ] ] diff --git a/data/mods/Generic_Guns/recipes/recipes_rifle.json b/data/mods/Generic_Guns/recipes/recipes_rifle.json index 0a76716d1647a..9cb81f6eee452 100644 --- a/data/mods/Generic_Guns/recipes/recipes_rifle.json +++ b/data/mods/Generic_Guns/recipes/recipes_rifle.json @@ -14,6 +14,7 @@ "charges": 1, "reversible": true, "using": [ [ "ammo_bullet", 10 ] ], + "proficiencies": [ { "proficiency": "prof_handloading" } ], "qualities": [ { "id": "CUT", "level": 1 } ], "components": [ [ [ "chem_black_powder", 5 ] ], [ [ "paper", 1 ] ] ] }, @@ -32,6 +33,7 @@ "charges": 1, "reversible": true, "using": [ [ "ammo_bullet", 10 ] ], + "proficiencies": [ { "proficiency": "prof_handloading" } ], "qualities": [ { "id": "CUT", "level": 1 } ], "components": [ [ [ "chem_black_powder", 5 ] ], [ [ "paper", 1 ] ] ] }, @@ -50,6 +52,7 @@ "charges": 1, "reversible": true, "using": [ [ "req_rifle", 1 ], [ "bullet_forming", 9 ], [ "ammo_bullet", 6 ] ], + "proficiencies": [ { "proficiency": "prof_handloading" } ], "components": [ [ [ "gunpowder", 12 ], [ "gunpowder_magnum_pistol", 12 ], [ "gunpowder_rifle", 12 ], [ "gunpowder_large_rifle", 12 ] ] ] @@ -94,6 +97,7 @@ "charges": 1, "reversible": true, "using": [ [ "req_rifle_huge", 1 ], [ "bullet_forming", 18 ], [ "ammo_bullet", 12 ] ], + "proficiencies": [ { "proficiency": "prof_handloading" } ], "components": [ [ [ "gunpowder", 30 ], [ "gunpowder_large_rifle", 30 ] ] ] }, { diff --git a/data/mods/Generic_Guns/recipes/recipes_shot.json b/data/mods/Generic_Guns/recipes/recipes_shot.json index a2994f101900e..f5c4724219eaf 100644 --- a/data/mods/Generic_Guns/recipes/recipes_shot.json +++ b/data/mods/Generic_Guns/recipes/recipes_shot.json @@ -14,6 +14,7 @@ "charges": 1, "reversible": true, "using": [ [ "shot_forming", 1 ], [ "ammo_bullet", 10 ], [ "req_shot", 1 ] ], + "proficiencies": [ { "proficiency": "prof_handloading" } ], "tools": [ [ [ "press", -1 ] ] ], "components": [ [ [ "gunpowder", 6 ], [ "gunpowder_pistol", 6 ], [ "gunpowder_shotgun", 6 ] ] ] }, @@ -32,6 +33,7 @@ "charges": 1, "reversible": true, "using": [ [ "shot_forming", 1 ], [ "ammo_bullet", 10 ], [ "req_shot", 1 ] ], + "proficiencies": [ { "proficiency": "prof_handloading" } ], "tools": [ [ [ "press", -1 ] ] ], "components": [ [ [ "chem_black_powder", 6 ] ] ] }, @@ -51,6 +53,7 @@ "charges": 1, "reversible": true, "using": [ [ "shot_forming", 1 ], [ "ammo_bullet", 10 ], [ "req_shot", 1 ] ], + "proficiencies": [ { "proficiency": "prof_handloading" } ], "tools": [ [ [ "press_dowel", -1 ] ] ] }, { @@ -69,6 +72,7 @@ "tools": [ [ [ "press", -1 ] ] ], "book_learn": [ [ "recipe_bullets", 1 ], [ "manual_shotgun", 1 ] ], "using": [ [ "shot_forming", 1 ], [ "ammo_bullet", 10 ], [ "req_shot", 1 ] ], + "proficiencies": [ { "proficiency": "prof_handloading" } ], "components": [ [ [ "gunpowder", 3 ], [ "gunpowder_pistol", 3 ], [ "gunpowder_shotgun", 3 ] ] ] }, { @@ -85,6 +89,7 @@ "charges": 1, "reversible": true, "using": [ [ "shot_forming", 1 ], [ "ammo_bullet", 10 ], [ "req_shot", 1 ] ], + "proficiencies": [ { "proficiency": "prof_handloading" } ], "components": [ [ [ "chem_black_powder", 3 ] ] ] }, { @@ -103,6 +108,7 @@ "reversible": true, "book_learn": [ [ "survival_book", 1 ], [ "mag_survival", 1 ] ], "tools": [ [ [ "press_dowel", -1 ] ] ], + "proficiencies": [ { "proficiency": "prof_handloading" } ], "components": [ [ [ "chem_black_powder", 3 ] ] ] }, { @@ -121,6 +127,7 @@ "tools": [ [ [ "press", -1 ] ] ], "book_learn": [ [ "recipe_bullets", 3 ], [ "manual_shotgun", 3 ] ], "using": [ [ "req_shot", 1 ] ], + "proficiencies": [ { "proficiency": "prof_handloading" } ], "components": [ [ [ "gunpowder", 3 ], [ "gunpowder_pistol", 3 ], [ "gunpowder_shotgun", 3 ] ], [ [ "magnesium", 5 ] ] ] }, { @@ -139,6 +146,7 @@ "tools": [ [ [ "press", -1 ] ] ], "book_learn": [ [ "recipe_bullets", 3 ], [ "manual_shotgun", 3 ] ], "using": [ [ "req_shot", 1 ] ], + "proficiencies": [ { "proficiency": "prof_handloading" } ], "components": [ [ [ "chem_black_powder", 3 ] ], [ [ "magnesium", 5 ] ] ] }, { @@ -156,6 +164,7 @@ "charges": 1, "reversible": true, "using": [ [ "shot_forming", 1 ], [ "ammo_bullet", 10 ], [ "req_shot", 1 ] ], + "proficiencies": [ { "proficiency": "prof_handloading" } ], "book_learn": [ [ "survival_book", 1 ], [ "mag_survival", 1 ] ], "tools": [ [ [ "press_dowel", -1 ] ] ] }, @@ -175,6 +184,7 @@ "difficulty": 3, "book_learn": [ [ "recipe_bullets", 3 ], [ "manual_shotgun", 3 ] ], "using": [ [ "bullet_forming", 1 ], [ "ammo_bullet", 20 ], [ "req_shot", 1 ] ], + "proficiencies": [ { "proficiency": "prof_handloading" } ], "components": [ [ [ "gunpowder", 6 ], [ "gunpowder_pistol", 6 ], [ "gunpowder_shotgun", 6 ] ] ] }, { @@ -193,6 +203,7 @@ "difficulty": 3, "book_learn": [ [ "recipe_bullets", 3 ], [ "manual_shotgun", 3 ] ], "using": [ [ "bullet_forming", 1 ], [ "ammo_bullet", 20 ], [ "req_shot", 1 ] ], + "proficiencies": [ { "proficiency": "prof_handloading" } ], "components": [ [ [ "chem_black_powder", 6 ] ] ] }, { @@ -210,6 +221,7 @@ "charges": 1, "reversible": true, "using": [ [ "shot_forming", 1 ], [ "ammo_bullet", 10 ], [ "req_shot", 1 ] ], + "proficiencies": [ { "proficiency": "prof_handloading" } ], "book_learn": [ [ "survival_book", 1 ], [ "mag_survival", 1 ] ], "tools": [ [ [ "press_dowel", -1 ] ] ] }, @@ -229,6 +241,7 @@ "tools": [ [ [ "press", -1 ] ] ], "book_learn": [ [ "recipe_bullets", 4 ], [ "manual_shotgun", 4 ] ], "using": [ [ "req_shot", 1 ] ], + "proficiencies": [ { "proficiency": "prof_handloading" } ], "components": [ [ [ "gunpowder", 6 ], [ "gunpowder_pistol", 6 ], [ "gunpowder_shotgun", 6 ] ], [ [ "combatnail", 10 ] ] ] }, { @@ -247,6 +260,7 @@ "tools": [ [ [ "press", -1 ] ] ], "book_learn": [ [ "recipe_bullets", 4 ], [ "manual_shotgun", 4 ] ], "using": [ [ "req_shot", 1 ] ], + "proficiencies": [ { "proficiency": "prof_handloading" } ], "components": [ [ [ "chem_black_powder", 6 ] ], [ [ "combatnail", 10 ] ] ] }, { @@ -264,6 +278,7 @@ "charges": 1, "reversible": true, "using": [ [ "shot_forming", 1 ], [ "ammo_bullet", 10 ], [ "req_shot", 1 ] ], + "proficiencies": [ { "proficiency": "prof_handloading" } ], "book_learn": [ [ "survival_book", 1 ], [ "mag_survival", 1 ] ], "tools": [ [ [ "press_dowel", -1 ] ] ] }, @@ -282,6 +297,7 @@ "reversible": true, "tools": [ [ [ "press", -1 ] ] ], "using": [ [ "req_shot", 1 ] ], + "proficiencies": [ { "proficiency": "prof_handloading" } ], "components": [ [ [ "gunpowder", 6 ], [ "gunpowder_pistol", 6 ], [ "gunpowder_shotgun", 6 ] ], [ @@ -314,6 +330,7 @@ "reversible": true, "tools": [ [ [ "press", -1 ] ] ], "using": [ [ "req_shot", 1 ] ], + "proficiencies": [ { "proficiency": "prof_handloading" } ], "components": [ [ [ "chem_black_powder", 6 ] ], [ @@ -346,6 +363,7 @@ "charges": 1, "reversible": true, "using": [ [ "shot_forming", 1 ], [ "ammo_bullet", 10 ], [ "req_shot", 1 ] ], + "proficiencies": [ { "proficiency": "prof_handloading" } ], "book_learn": [ [ "survival_book", 1 ], [ "mag_survival", 1 ] ], "tools": [ [ [ "press_dowel", -1 ] ] ] } From efb5fc37a45ae5c0bf32a477547e9ab8c9452f16 Mon Sep 17 00:00:00 2001 From: slimeboy460 <68845349+slimeboy460@users.noreply.github.com> Date: Wed, 17 Feb 2021 21:35:17 -1000 Subject: [PATCH 003/453] Drug Dealer Profession (#47255) --- data/json/professions.json | 17 +++++++++++++++++ 1 file changed, 17 insertions(+) diff --git a/data/json/professions.json b/data/json/professions.json index 6f9853a31e3ed..9b4d5e7de891c 100644 --- a/data/json/professions.json +++ b/data/json/professions.json @@ -3922,6 +3922,23 @@ "female": [ "bra", "panties" ] } }, + { + "type": "profession", + "id": "local_drug_dealer", + "name": "Drug Dealer", + "description": "You were about to make your biggest sale yet, but when you met the buyer he tried to bite you. To top it off, it seems that this wasn't some sort of bad high for the user, as the whole town tried going for your throat too.", + "points": 2, + "skills": [ { "level": 1, "name": "melee" }, { "level": 2, "name": "stabbing" }, { "level": 2, "name": "speech" } ], + "items": { + "both": { + "items": [ "hoodie", "jeans", "mbag", "socks", "sneakers", "bandana", "gloves_medical", "switchblade" ], + "entries": [ { "item": "crack", "charges": 25, "container-item": "bag_zipper" } ] + }, + "male": [ "briefs" ], + "female": [ "sports_bra", "boy_shorts" ] + }, + "traits": [ "LIAR" ] + }, { "type": "profession", "id": "handloader", From cd4d731f0e02d48405786e7864f009d2b41ee33c Mon Sep 17 00:00:00 2001 From: ToxiClay Date: Wed, 23 Dec 2020 17:27:35 -0500 Subject: [PATCH 004/453] Add hallula bread (#46282) --- data/json/items/comestibles/bread.json | 22 ++++++++++++++++++++++ data/json/recipes/food/bread.json | 25 +++++++++++++++++++++++++ 2 files changed, 47 insertions(+) diff --git a/data/json/items/comestibles/bread.json b/data/json/items/comestibles/bread.json index 1fabede92c375..d7f66d42cba2d 100644 --- a/data/json/items/comestibles/bread.json +++ b/data/json/items/comestibles/bread.json @@ -304,5 +304,27 @@ "flags": [ "EATEN_HOT", "EATEN_COLD" ], "fun": 3, "vitamins": [ [ "calcium", 2 ], [ "iron", 6 ] ] + }, + { + "type": "COMESTIBLE", + "id": "hallula", + "name": { "str_sp": "hallula" }, + "weight": "45 g", + "color": "brown", + "spoils_in": "10 days", + "container": "bag_plastic", + "comestible_type": "FOOD", + "symbol": "%", + "healthy": 1, + "calories": 61, + "description": "This type of bread is popular in Chile and Bolivia. Prepared using animal lard or oil, it resembles a large, round scone. In the pre-Cataclysm world, it would usually be filled with savory ingredients rather than sweet ones.", + "price": "272 cent", + "price_postapoc": "4 USD", + "material": [ "wheat" ], + "volume": "48 ml", + "charges": 16, + "flags": [ "EATEN_HOT", "EATEN_COLD" ], + "fun": 4, + "vitamins": [ [ "calcium", 2 ], [ "iron", 6 ] ] } ] diff --git a/data/json/recipes/food/bread.json b/data/json/recipes/food/bread.json index 63671d90fd276..c9996e42485f4 100644 --- a/data/json/recipes/food/bread.json +++ b/data/json/recipes/food/bread.json @@ -47,5 +47,30 @@ [ [ "salt", 1 ] ] ], "//": "Later: this needs baking soda. Also possibility of rewrite to use portions of components' charges." + }, + { + "type": "recipe", + "activity_level": "LIGHT_EXERCISE", + "result": "hallula", + "category": "CC_FOOD", + "subcategory": "CSC_FOOD_BREAD", + "skill_used": "cooking", + "difficulty": 3, + "charges": 8, + "time": "30 m", + "batch_time_factors": [ 50, 5 ], + "book_learn": [ [ "family_cookbook", 1 ], [ "baking_book", 2 ], [ "cookbook", 2 ] ], + "qualities": [ { "id": "COOK", "level": 3 } ], + "tools": [ [ [ "surface_heat", 8, "LIST" ] ] ], + "components": [ + [ [ "flour", 3 ] ], + [ [ "yeast", 2 ] ], + [ [ "sugar", 1 ] ], + [ [ "salt", 1 ] ], + [ [ "water", 1 ] ], + [ [ "any_butter_or_oil", 2, "LIST" ] ] + ], + "//": "I'm not sure whether this should also be rewritten to use a portion of charges, or scaled up so that the smallest component in the recipe becomes a single charge.", + "//2": "Since milk is only used sparingly in the creation of hallula, to give it a glazed appearance, Cataclysm practicality suggests omitting it." } ] From 5e76050de5bb5bb71d75a5c09205c1da56cfdda4 Mon Sep 17 00:00:00 2001 From: Jamuro-g <76928284+Jamuro-g@users.noreply.github.com> Date: Thu, 18 Feb 2021 08:37:34 +0100 Subject: [PATCH 005/453] Arm mounted pouch (#46946) --- data/json/itemgroups/activities_hobbies.json | 2 ++ data/json/items/armor/storage.json | 30 ++++++++++++++++++++ data/json/recipes/armor/storage.json | 14 +++++++++ 3 files changed, 46 insertions(+) diff --git a/data/json/itemgroups/activities_hobbies.json b/data/json/itemgroups/activities_hobbies.json index 04328bb8792f8..f8967629f8a8d 100644 --- a/data/json/itemgroups/activities_hobbies.json +++ b/data/json/itemgroups/activities_hobbies.json @@ -143,6 +143,7 @@ { "item": "multitool", "prob": 12 }, { "item": "throwing_knife", "prob": 7 }, { "item": "slingpack", "prob": 18 }, + { "item": "armrig", "prob": 3 }, { "item": "manual_cutting", "prob": 12 }, { "item": "manual_launcher", "prob": 1 }, { "item": "recipe_bullets", "prob": 8 }, @@ -207,6 +208,7 @@ [ "backpack_hiking", 12 ], [ "bigback", 3 ], [ "travelpack", 6 ], + [ "armrig", 3 ], [ "cowboy_hat", 4 ], [ "10gal_hat", 4 ], { "item": "bb", "prob": 8, "charges": [ 1, 500 ] }, diff --git a/data/json/items/armor/storage.json b/data/json/items/armor/storage.json index bd554b679a081..d71ba7e2f0ae4 100644 --- a/data/json/items/armor/storage.json +++ b/data/json/items/armor/storage.json @@ -808,6 +808,36 @@ "material_thickness": 0.2, "flags": [ "VARSIZE", "WATER_FRIENDLY", "BELTED" ] }, + { + "id": "armrig", + "type": "ARMOR", + "name": { "str": "armband pouch", "str_pl": "armband pouches" }, + "description": "A small pouch that can be worn on the upper arm using buckled straps. This is a favoured item among sports & camping enthusiasts.", + "weight": "205 g", + "volume": "550 ml", + "price": 3000, + "price_postapoc": 250, + "material": [ "cotton", "plastic" ], + "symbol": "[", + "looks_like": "armguard_soft", + "color": "dark_gray", + "covers": [ "arm_l", "arm_r" ], + "sided": true, + "coverage": 20, + "encumbrance": 2, + "max_encumbrance": 7, + "pocket_data": [ + { + "pocket_type": "CONTAINER", + "max_contains_volume": "500 ml", + "max_contains_weight": "1 kg", + "max_item_length": "15 cm", + "moves": 200 + } + ], + "material_thickness": 2, + "flags": [ "VARSIZE", "WATER_FRIENDLY", "BELTED" ] + }, { "id": "makeshift_knapsack", "type": "ARMOR", diff --git a/data/json/recipes/armor/storage.json b/data/json/recipes/armor/storage.json index ff090b5150e85..974de7a3a2569 100644 --- a/data/json/recipes/armor/storage.json +++ b/data/json/recipes/armor/storage.json @@ -388,6 +388,20 @@ "proficiencies": [ { "proficiency": "prof_closures" }, { "proficiency": "prof_leatherworking_basic" } ], "components": [ [ [ "2x4", 2 ] ], [ [ "nail", 10 ] ] ] }, + { + "result": "armrig", + "type": "recipe", + "activity_level": "LIGHT_EXERCISE", + "category": "CC_ARMOR", + "subcategory": "CSC_ARMOR_STORAGE", + "skill_used": "tailor", + "difficulty": 3, + "time": "1 h", + "autolearn": true, + "reversible": true, + "using": [ [ "tailoring_cotton", 2 ], [ "fastener_small", 1 ] ], + "proficiencies": [ { "proficiency": "prof_closures" } ] + }, { "result": "chestpouch", "type": "recipe", From 5cd68d50199062f79ecec4cf37b903dfb66d215c Mon Sep 17 00:00:00 2001 From: Xenomorph-III Date: Thu, 18 Feb 2021 20:44:39 +1300 Subject: [PATCH 006/453] Tazer drone iii (#47353) --- data/json/items/corpses/inactive_bots.json | 26 ++++++++++++++++++++++ data/json/items/generic.json | 18 +++++++++++++++ data/json/monstergroups/lab.json | 2 ++ data/json/monsters/drones.json | 14 ++++++++++++ data/json/recipes/other/bots.json | 26 ++++++++++++++++++++++ 5 files changed, 86 insertions(+) diff --git a/data/json/items/corpses/inactive_bots.json b/data/json/items/corpses/inactive_bots.json index 4eb2412326a20..abe50e4bbf6cb 100644 --- a/data/json/items/corpses/inactive_bots.json +++ b/data/json/items/corpses/inactive_bots.json @@ -740,5 +740,31 @@ "moves": 150, "skills": [ "electronics", "computer" ] } + }, + { + "id": "bot_tazer_hack", + "type": "TOOL", + "name": { "str": "inactive tazer hack" }, + "description": "This is an inactive tazer hack. Hacks are fist-sized robots that fly through the air. This one has a tazer and attacks by flying at its target and delivering an electric shock. Use this item to reprogram and release the tazer hack. Electronics and computer skills determine if the targeting matrix is reprogrammed successfully.", + "weight": "4700 g", + "volume": "750 ml", + "price": 64500, + "price_postapoc": 3000, + "to_hit": -3, + "bashing": 6, + "cutting": 6, + "material": [ "aluminum", "plastic" ], + "symbol": ",", + "color": "cyan", + "use_action": { + "type": "place_monster", + "monster_id": "mon_tazer_hack", + "friendly_msg": "The tazer hack flies from your hand and surveys the area!", + "hostile_msg": "You misprogram the tazer hack; run!", + "difficulty": 3, + "moves": 60, + "place_randomly": true, + "skills": [ "electronics", "computer" ] + } } ] diff --git a/data/json/items/generic.json b/data/json/items/generic.json index 0b48a50938a2b..468efcc0ab120 100644 --- a/data/json/items/generic.json +++ b/data/json/items/generic.json @@ -3390,5 +3390,23 @@ ] } ] + }, + { + "type": "GENERIC", + "id": "broken_tazer_hack", + "symbol": ",", + "color": "green", + "name": { "str": "broken tazer hack" }, + "category": "other", + "description": "A broken tazer hack, with its propellers still and tazer inert. Could be gutted for parts.", + "price": 1000, + "price_postapoc": 10, + "material": [ "steel", "plastic" ], + "weight": "100 kg", + "volume": "65 L", + "bashing": 4, + "cutting": 4, + "to_hit": -3, + "flags": [ "TRADER_AVOID", "NO_REPAIR" ] } ] diff --git a/data/json/monstergroups/lab.json b/data/json/monstergroups/lab.json index 029c7f53c004b..00344d5b7347f 100644 --- a/data/json/monstergroups/lab.json +++ b/data/json/monstergroups/lab.json @@ -95,6 +95,7 @@ { "monster": "mon_zombie_labsecurity", "freq": 700, "cost_multiplier": 2 }, { "monster": "mon_science_bot", "freq": 50, "cost_multiplier": 4 }, { "monster": "mon_manhack", "freq": 200, "cost_multiplier": 0 }, + { "monster": "mon_tazer_hack", "freq": 150, "cost_multiplier": 0 }, { "monster": "mon_manhack", "freq": 45, "cost_multiplier": 0, "pack_size": [ 2, 3 ] }, { "monster": "mon_skitterbot", "freq": 85, "cost_multiplier": 0 }, { "monster": "mon_skitterbot", "freq": 85, "cost_multiplier": 0, "pack_size": [ 2, 3 ] }, @@ -145,6 +146,7 @@ { "monster": "mon_zombie_labsecurity", "freq": 40, "cost_multiplier": 0, "pack_size": [ 2, 3 ] }, { "monster": "mon_zombie_hazmat", "freq": 40, "cost_multiplier": 1, "pack_size": [ 1, 3 ] }, { "monster": "mon_manhack", "freq": 20, "cost_multiplier": 1, "pack_size": [ 3, 12 ] }, + { "monster": "mon_tazer_hack", "freq": 20, "cost_multiplier": 1, "pack_size": [ 1, 5 ] }, { "monster": "mon_mutant_experimental", "freq": 10, "cost_multiplier": 0, "pack_size": [ 1, 3 ] }, { "monster": "mon_skitterbot", "freq": 10, "cost_multiplier": 0, "pack_size": [ 2, 3 ] }, { "monster": "mon_zombie_phase_skulker", "freq": 10, "cost_multiplier": 0, "pack_size": [ 2, 3 ] }, diff --git a/data/json/monsters/drones.json b/data/json/monsters/drones.json index e902291d66fe5..61bee7c3eba09 100644 --- a/data/json/monsters/drones.json +++ b/data/json/monsters/drones.json @@ -185,5 +185,19 @@ "PRIORITIZE_TARGETS", "HIT_AND_RUN" ] + }, + { + "id": "mon_tazer_hack", + "copy-from": "base_drone", + "type": "MONSTER", + "name": { "str": "tazer hack" }, + "description": "An automated drone, this small quadcopter robot appears to have a tazer strapped to the front. While extremely fast, it is very fragile.", + "diff": 10, + "speed": 350, + "color": "cyan", + "armor_cut": 2, + "armor_bullet": 1, + "revert_to_itype": "bot_tazer_hack", + "special_attacks": [ [ "TAZER", 5 ] ] } ] diff --git a/data/json/recipes/other/bots.json b/data/json/recipes/other/bots.json index 413f27a8c981b..8ff9c11997cfd 100644 --- a/data/json/recipes/other/bots.json +++ b/data/json/recipes/other/bots.json @@ -791,5 +791,31 @@ [ [ "floodlight", 1 ] ], [ [ "turret_chassis", 1 ] ] ] + }, + { + "type": "recipe", + "activity_level": "LIGHT_EXERCISE", + "result": "bot_tazer_hack", + "category": "CC_ELECTRONIC", + "subcategory": "CSC_ELECTRONIC_OTHER", + "skill_used": "electronics", + "skills_required": [ [ "mechanics", 4 ], [ "computer", 4 ] ], + "difficulty": 6, + "time": "50 m", + "reversible": true, + "decomp_learn": 7, + "book_learn": [ [ "recipe_lab_elec", 5 ], [ "textbook_robots", 6 ] ], + "using": [ [ "soldering_standard", 10 ] ], + "qualities": [ { "id": "SCREW", "level": 1 } ], + "components": [ + [ [ "tazer", 1 ] ], + [ [ "ai_module_basic", 1 ] ], + [ [ "RAM", 1 ] ], + [ [ "small_storage_battery", 1 ] ], + [ [ "scrap", 1 ] ], + [ [ "quad_rotors", 1 ] ], + [ [ "sensor_module", 1 ] ], + [ [ "identification_module", 1 ] ] + ] } ] From 07f403d54bbb809c1cf31310aa608c48cb3c9db7 Mon Sep 17 00:00:00 2001 From: grawprog <77870049+grawprog@users.noreply.github.com> Date: Wed, 17 Feb 2021 23:47:51 -0800 Subject: [PATCH 007/453] Added Gelatin and Several Gelatin Based Recipes (#47080) --- data/json/itemgroups/Food/food.json | 9 +- data/json/itemgroups/SUS/fridges.json | 7 + .../json/itemgroups/collections_domestic.json | 2 + data/json/items/comestibles/junkfood.json | 129 ++++++++++++ data/json/items/comestibles/other.json | 83 ++++++++ data/json/recipes/food/dry.json | 14 ++ data/json/recipes/food/other.json | 197 ++++++++++++++++++ data/json/recipes/recipe_food.json | 9 +- .../json/requirements/cooking_components.json | 33 +++ 9 files changed, 479 insertions(+), 4 deletions(-) diff --git a/data/json/itemgroups/Food/food.json b/data/json/itemgroups/Food/food.json index 99d9cf752b614..a3b1cfab1acbc 100644 --- a/data/json/itemgroups/Food/food.json +++ b/data/json/itemgroups/Food/food.json @@ -46,7 +46,10 @@ { "item": "dry_beans", "prob": 40 }, { "item": "dry_lentils", "prob": 30 }, { "item": "dry_rice", "prob": 40 }, - { "item": "freeze_dried_meal", "prob": 10 } + { "item": "freeze_dried_meal", "prob": 10 }, + { "item": "gelatin_powder", "prob": 40 }, + { "item": "chem_agar", "prob": 15 }, + { "item": "gelatin_dessert_powder", "prob": 40 } ] }, { @@ -426,6 +429,7 @@ { "item": "candy", "prob": 70 }, { "item": "candy2", "prob": 70 }, { "item": "candy3", "prob": 70 }, + { "item": "candy4", "prob": 70 }, { "item": "cow_candy", "prob": 20 }, { "item": "maltballs", "prob": 60 }, { "item": "mintpatties", "prob": 60 }, @@ -553,7 +557,8 @@ { "item": "pie", "prob": 20 }, { "item": "pie_veggy", "prob": 18 }, { "item": "pie_meat", "prob": 18 }, - { "item": "pie_maple", "prob": 9 } + { "item": "pie_maple", "prob": 9 }, + { "item": "gelatin_dessert_processed", "prob": 40 } ] }, { diff --git a/data/json/itemgroups/SUS/fridges.json b/data/json/itemgroups/SUS/fridges.json index d99955ed69801..75a7f9e8b6fe8 100644 --- a/data/json/itemgroups/SUS/fridges.json +++ b/data/json/itemgroups/SUS/fridges.json @@ -39,6 +39,8 @@ { "item": "yoghurt", "prob": 80 }, { "item": "butter", "prob": 80 }, { "item": "pudding", "prob": 30 }, + { "item": "gelatin_dessert_processed", "prob": 20 }, + { "item": "egg_bird_unfert", "prob": 85, "count-min": 1, "count-max": 12 }, { "item": "egg_bird_unfert", "prob": 85, "charges-min": 1, "charges-max": 12, "container-item": "carton_egg" }, { "item": "bacon", "prob": 25 }, { @@ -520,6 +522,8 @@ { "item": "onion_rings", "charges-min": 1, "prob": 10 }, { "item": "pizza_veggy", "charges-min": 1, "prob": 20 }, { "item": "nachosv", "charges-min": 1, "prob": 20 }, + { "item": "gelatin_dessert_vegan", "prob": 30 }, + { "item": "gelatin_dessert_vegan_fruit", "prob": 30 }, { "distribution": [ { @@ -623,6 +627,8 @@ { "item": "yoghurt", "prob": 20 }, { "item": "butter", "prob": 20 }, { "item": "pudding", "prob": 20 }, + { "item": "gelatin_dessert_processed", "prob": 10 }, + { "item": "egg_bird_unfert", "prob": 20, "count-min": 1, "count-max": 12 }, { "item": "egg_bird_unfert", "prob": 20, "charges-min": 1, "charges-max": 12, "container-item": "carton_egg" }, { "item": "bacon", "prob": 25 }, { @@ -880,6 +886,7 @@ { "item": "yoghurt", "count": [ 1, 3 ], "prob": 75 }, { "item": "butter", "prob": 50 }, { "item": "pudding", "prob": 30 }, + { "item": "gelatin_dessert_processed", "prob": 10 }, { "item": "veggy_salad", "charges-min": 1, "prob": 19 }, { "item": "blt", "charges-min": 1, "prob": 13 }, { "item": "protein_shake", "charges-min": 1, "prob": 6 }, diff --git a/data/json/itemgroups/collections_domestic.json b/data/json/itemgroups/collections_domestic.json index 428fa249a7c5e..cf4dc12db2eeb 100644 --- a/data/json/itemgroups/collections_domestic.json +++ b/data/json/itemgroups/collections_domestic.json @@ -564,6 +564,7 @@ { "item": "noodles_fast", "prob": 30 }, { "item": "ravioli", "prob": 25 }, { "item": "sauce_red", "prob": 20 }, + { "item": "gelatin_dessert_powder", "prob": 20 }, { "item": "sauce_pesto", "prob": 15 }, { "item": "bread", "prob": 14 }, { "item": "cornbread", "prob": 7 }, @@ -579,6 +580,7 @@ { "item": "can_cheese", "prob": 8 }, { "item": "yoghurt", "prob": 8 }, { "item": "pudding", "prob": 10 }, + { "item": "gelatin_dessert_processed", "prob": 10 }, { "item": "veggy_pickled", "prob": 8, "charges": 2, "container-item": "jar_glass_sealed" }, { "item": "sauerkraut", "prob": 5, "charges": 4, "container-item": "jar_glass_sealed" }, { "item": "meat_pickled", "prob": 4, "charges": 2, "container-item": "jar_glass_sealed" }, diff --git a/data/json/items/comestibles/junkfood.json b/data/json/items/comestibles/junkfood.json index ba0922582c693..4831417945a6c 100644 --- a/data/json/items/comestibles/junkfood.json +++ b/data/json/items/comestibles/junkfood.json @@ -317,6 +317,48 @@ "charges": 3, "fun": 3 }, + { + "type": "COMESTIBLE", + "id": "candy4", + "name": { "str_sp": "gummy candy" }, + "weight": "46 g", + "color": "yellow", + "spoils_in": "360 days", + "container": "bag_plastic", + "comestible_type": "FOOD", + "symbol": "%", + "healthy": -1, + "calories": 85, + "description": "A handful of colorful fruit and soda pop flavored gummy candies.", + "price": 180, + "price_postapoc": 200, + "material": [ "junk", "flesh" ], + "volume": "90 ml", + "flags": [ "EDIBLE_FROZEN" ], + "charges": 3, + "fun": 5 + }, + { + "type": "COMESTIBLE", + "id": "candy5", + "name": { "str_sp": "gummy candy" }, + "weight": "46 g", + "color": "light_green", + "spoils_in": "360 days", + "container": "bag_plastic", + "comestible_type": "FOOD", + "symbol": "%", + "healthy": -1, + "calories": 85, + "description": "A handful of colorful fruit and soda pop flavored vegan gummy candies made from agar. They have kind of a strange texture, but they're still tasty.", + "price": 180, + "price_postapoc": 200, + "material": [ "junk", "veggy" ], + "volume": "90 ml", + "flags": [ "EDIBLE_FROZEN" ], + "charges": 3, + "fun": 4 + }, { "type": "COMESTIBLE", "id": "candy3gator", @@ -1290,5 +1332,92 @@ "flags": [ "EATEN_HOT" ], "vitamins": [ [ "vitA", 3 ], [ "iron", 10 ] ], "fun": 4 + }, + { + "type": "COMESTIBLE", + "id": "gelatin_dessert_powder", + "name": "gelatin dessert powder", + "weight": "175 g", + "color": "white", + "spoils_in": "1461 days", + "container": "box_small", + "comestible_type": "FOOD", + "symbol": "%", + "quench": -8, + "calories": 400, + "description": "A small box of gelatin dessert powder. Just add water and set. Comes in a variety of flavors.", + "price": 5, + "price_postapoc": 10, + "material": [ "flesh", "junk" ], + "volume": "250ml", + "flags": [ "EATEN_COLD" ], + "fun": -2 + }, + { + "type": "COMESTIBLE", + "id": "gelatin_dessert_base", + "name": "unflavored gelatin dessert", + "weight": "232 g", + "color": "white", + "spoils_in": "7 days 12 hours", + "container": "cup_plastic", + "comestible_type": "FOOD", + "symbol": "%", + "calories": 100, + "description": "An unflavored jiggly, sugary treat made from gelatin and sugar. This would taste better with some flavor.", + "price": 210, + "price_postapoc": 250, + "material": [ "flesh", "junk" ], + "volume": "250 ml", + "phase": "solid", + "fun": 5 + }, + { + "type": "COMESTIBLE", + "id": "gelatin_dessert_processed", + "name": "processed gelatin dessert", + "description": "A jiggly, sugary treat made from gelatin and sugar. Comes in a variety of flavors. A kid favorite pre-Cataclysm.", + "fun": 20, + "copy-from": "gelatin_dessert_base" + }, + { + "type": "COMESTIBLE", + "id": "gelatin_dessert_homemade", + "name": "homemade gelatin dessert", + "color": "light_red", + "description": "A homemade jiggly, sugary treat made from gelatin and sugar flavored with fruit juice. A kid favorite pre-Cataclysm.", + "fun": 25, + "copy-from": "gelatin_dessert_base" + }, + { + "type": "COMESTIBLE", + "id": "gelatin_dessert_fruit", + "name": "fruit filled gelatin dessert", + "color": "light_red", + "description": "A jiggly, sugary treat made from gelatin and sugar flavored with fruit juice and set with fruit. A kid favorite pre-Cataclysm and a healthy treat", + "fun": 20, + "healthy": 1, + "copy-from": "gelatin_dessert_base" + }, + { + "type": "COMESTIBLE", + "id": "gelatin_dessert_vegan", + "name": "vegan gelatin dessert", + "color": "light_green", + "description": "A vegan friendly homemade jiggly, sugary treat made from agar and sugar flavored with fruit juice. A kid favorite pre-Cataclysm. They'll never know the difference.", + "fun": 20, + "material": [ "veggy", "junk" ], + "copy-from": "gelatin_dessert_base" + }, + { + "type": "COMESTIBLE", + "id": "gelatin_dessert_vegan_fruit", + "name": "fruit filled vegan gelatin dessert", + "color": "light_green", + "description": "A vegan friendly jiggly, sugary treat made from agar and sugar flavored with fruit juice and set with fruit. A kid favorite pre-Cataclysm and a healthy treat", + "fun": 15, + "material": [ "veggy", "junk" ], + "healthy": 1, + "copy-from": "gelatin_dessert_base" } ] diff --git a/data/json/items/comestibles/other.json b/data/json/items/comestibles/other.json index e17fdd5481181..7fff34d328366 100644 --- a/data/json/items/comestibles/other.json +++ b/data/json/items/comestibles/other.json @@ -188,6 +188,50 @@ "charges": 4, "fun": -10 }, + { + "type": "COMESTIBLE", + "id": "gelatin_powder", + "name": { "str_sp": "powdered gelatin" }, + "weight": "11 g", + "color": "yellow", + "container": "bag_plastic", + "comestible_type": "FOOD", + "symbol": "%", + "quench": -1, + "calories": 6, + "description": "Dried and powdered gelatin, used as a gelling agent when mixed with water.", + "price": 150, + "price_postapoc": 50, + "material": "powder", + "volume": "250 ml", + "flags": [ "EDIBLE_FROZEN" ], + "charges": 25, + "fun": -10 + }, + { + "type": "COMESTIBLE", + "id": "gelatin_fresh", + "name": { "str_sp": "fresh gelatin" }, + "conditional_names": [ + { "type": "COMPONENT_ID", "condition": "mutant", "name": { "str_sp": "abomination %s" } }, + { "type": "FLAG", "condition": "CANNIBALISM", "name": { "str_sp": "amoral %s" } }, + { "type": "FLAG", "condition": "STRICT_HUMANITARIANISM", "name": { "str_sp": "Orwell's %s" } } + ], + "weight": "25 g", + "color": "yellow", + "spoils_in": "7 days", + "comestible_type": "FOOD", + "symbol": "%", + "calories": 6, + "//": "Same as the meat it's been made from. It's additional ingredient compared to smoking, jerking, and dehydrating, so there's no incentive otherwise.", + "description": "Fresh ", + "price": 150, + "price_postapoc": 50, + "material": [ "flesh" ], + "volume": "250 ml", + "vitamins": [ [ "vitA", 10 ], [ "vitC", 15 ], [ "calcium", 2 ], [ "iron", 8 ] ], + "flags": [ "EATEN_COLD", "FREEZERBURN" ] + }, { "type": "COMESTIBLE", "id": "meal_bone_tainted", @@ -868,5 +912,44 @@ "price_postapoc": 200, "freezing_point": -459, "description": "A small packet of commercial instant coffee powder. No creamer or sweetener added." + }, + { + "type": "COMESTIBLE", + "id": "acid_soaked_hide", + "name": "acid soaked hide", + "description": "Raw hide soaking in a dilute acid solution to extract collagen. After 24 hours the solution can be strained to extract fresh gelatin.", + "weight": "500 g", + "color": "yellow", + "sealed": false, + "symbol": "~", + "calories": 9, + "quench": 6, + "fun": -10, + "price": 0, + "volume": "10L", + "price_postapoc": 10, + "phase": "liquid", + "comestible_type": "DRINK", + "flags": [ "NUTRIENT_OVERRIDE" ], + "brewable": { "time": "24 hours", "results": [ "gelatin_extracted" ] } + }, + { + "type": "COMESTIBLE", + "id": "gelatin_extracted", + "name": "extracted gelatin", + "description": "Freshly extracted gelatin in a dilute acid solution. It needs to be strained to separate the gelatin from the acid.", + "weight": "500 g", + "color": "yellow", + "sealed": false, + "symbol": "~", + "calories": 9, + "quench": 6, + "fun": -10, + "price": 0, + "volume": "10L", + "price_postapoc": 10, + "phase": "liquid", + "comestible_type": "DRINK", + "flags": [ "NUTRIENT_OVERRIDE" ] } ] diff --git a/data/json/recipes/food/dry.json b/data/json/recipes/food/dry.json index 0fedb62d4ee58..91593ee23709f 100644 --- a/data/json/recipes/food/dry.json +++ b/data/json/recipes/food/dry.json @@ -396,5 +396,19 @@ "batch_time_factors": [ 67, 5 ], "tools": [ [ [ "dehydrator", 25 ], [ "char_smoker", 25 ] ], [ [ "surface_heat", 5, "LIST" ] ] ], "components": [ [ [ "raw_lentils", 1 ] ] ] + }, + { + "type": "recipe", + "activity_level": "NO_EXERCISE", + "result": "gelatin_powder", + "category": "CC_FOOD", + "subcategory": "CSC_FOOD_DRY", + "skill_used": "cooking", + "difficulty": 2, + "time": "18 m", + "autolearn": true, + "batch_time_factors": [ 67, 5 ], + "tools": [ [ [ "dehydrator", 25 ], [ "char_smoker", 25 ] ] ], + "components": [ [ [ "gelatin_fresh", 1 ] ] ] } ] diff --git a/data/json/recipes/food/other.json b/data/json/recipes/food/other.json index f7f915c4fd061..11602abce0cf8 100644 --- a/data/json/recipes/food/other.json +++ b/data/json/recipes/food/other.json @@ -42,5 +42,202 @@ "time": "15 m", "charges": 2, "components": [ [ [ "water_clean", 1 ] ], [ [ "freeze_dried_meal", 1 ] ] ] + }, + { + "type": "recipe", + "activity_level": "NO_EXERCISE", + "result": "acid_soaked_hide", + "result_mult": 1, + "category": "CC_FOOD", + "subcategory": "CSC_FOOD_OTHER", + "skill_used": "cooking", + "difficulty": 3, + "time": "8 m", + "batch_time_factors": [ 50, 4 ], + "book_learn": [ [ "textbook_chemistry", 3 ], [ "adv_chemistry", 3 ] ], + "components": [ + [ [ "formic_acid", 10 ] ], + [ [ "water", 10 ], [ "water_clean", 10 ] ], + [ [ "raw_leather", 1 ], [ "raw_tainted_leather", 1 ], [ "raw_hleather", 1 ], [ "raw_demihumanleather", 1 ] ] + ] + }, + { + "type": "recipe", + "activity_level": "LIGHT_EXERCISE", + "result": "gelatin_fresh", + "byproducts": [ [ "formic_acid" ], [ "ruined_chunks" ] ], + "result_mult": 12, + "category": "CC_FOOD", + "subcategory": "CSC_FOOD_OTHER", + "skill_used": "cooking", + "difficulty": 2, + "time": "120 m", + "batch_time_factors": [ 90, 1 ], + "charges": 1, + "autolearn": true, + "tools": [ [ "colander_steel" ] ], + "components": [ [ [ "gelatin_extracted", 1 ] ] ] + }, + { + "type": "recipe", + "activity_level": "NO_EXERCISE", + "result": "gelatin_dessert_processed", + "category": "CC_FOOD", + "subcategory": "CSC_FOOD_OTHER", + "skill_used": "cooking", + "difficulty": 1, + "time": "60 m", + "batch_time_factors": [ 20, 1 ], + "charges": 5, + "autolearn": true, + "qualities": [ { "id": "BOIL", "level": 1 }, { "id": "CONTAIN", "level": 1 } ], + "tools": [ [ [ "surface_heat", 16, "LIST" ] ] ], + "components": [ [ [ "water", 1 ], [ "water_clean", 1 ] ], [ [ "gelatin_dessert_powder", 1 ] ] ] + }, + { + "type": "recipe", + "activity_level": "NO_EXERCISE", + "result": "gelatin_dessert_base", + "category": "CC_FOOD", + "subcategory": "CSC_FOOD_OTHER", + "skill_used": "cooking", + "difficulty": 1, + "time": "60 m", + "batch_time_factors": [ 20, 1 ], + "charges": 5, + "autolearn": true, + "qualities": [ { "id": "BOIL", "level": 1 }, { "id": "CONTAIN", "level": 1 } ], + "tools": [ [ [ "surface_heat", 16, "LIST" ] ] ], + "components": [ [ [ "water", 2 ], [ "water_clean", 2 ] ], [ [ "gelatin_powder", 10 ], [ "gelatin_fresh", 1 ] ], [ [ "sugar", 20 ] ] ] + }, + { + "type": "recipe", + "activity_level": "NO_EXERCISE", + "result": "gelatin_dessert_homemade", + "category": "CC_FOOD", + "subcategory": "CSC_FOOD_OTHER", + "skill_used": "cooking", + "difficulty": 1, + "time": "60 m", + "batch_time_factors": [ 20, 1 ], + "charges": 5, + "book_learn": [ [ "sweets_book", 1 ], [ "baking_book", 1 ], [ "mag_cooking", 3 ], [ "family_cookbook", 3 ] ], + "qualities": [ { "id": "BOIL", "level": 1 }, { "id": "CONTAIN", "level": 1 } ], + "tools": [ [ [ "surface_heat", 16, "LIST" ] ] ], + "components": [ + [ [ "water", 1 ], [ "water_clean", 1 ], [ "sweet_water", 1 ] ], + [ [ "gelatin_powder", 5 ], [ "gelatin_fresh", 1 ] ], + [ [ "sugar", 20 ] ], + [ [ "sweet_juice", 1, "LIST" ], [ "soda_pop", 1, "LIST" ] ] + ] + }, + { + "type": "recipe", + "activity_level": "NO_EXERCISE", + "result": "gelatin_dessert_fruit", + "category": "CC_FOOD", + "subcategory": "CSC_FOOD_OTHER", + "skill_used": "cooking", + "difficulty": 1, + "time": "60 m", + "batch_time_factors": [ 20, 1 ], + "charges": 5, + "book_learn": [ [ "sweets_book", 1 ], [ "baking_book", 1 ], [ "mag_cooking", 3 ], [ "family_cookbook", 3 ] ], + "qualities": [ { "id": "BOIL", "level": 1 }, { "id": "CONTAIN", "level": 1 } ], + "tools": [ [ [ "surface_heat", 16, "LIST" ] ] ], + "components": [ + [ [ "water", 1 ], [ "water_clean", 1 ], [ "sweet_water", 1 ] ], + [ [ "gelatin_powder", 5 ], [ "gelatin_fresh", 1 ] ], + [ [ "sugar", 10 ] ], + [ [ "sweet_juice", 1, "LIST" ], [ "soda_pop", 1, "LIST" ] ], + [ [ "sweet_fruit", 1, "LIST" ] ] + ] + }, + { + "type": "recipe", + "activity_level": "NO_EXERCISE", + "result": "gelatin_dessert_vegan", + "category": "CC_FOOD", + "subcategory": "CSC_FOOD_OTHER", + "skill_used": "cooking", + "difficulty": 1, + "time": "60 m", + "batch_time_factors": [ 20, 1 ], + "charges": 5, + "book_learn": [ [ "sweets_book", 1 ], [ "baking_book", 1 ], [ "mag_cooking", 1 ], [ "family_cookbook", 1 ] ], + "qualities": [ { "id": "BOIL", "level": 1 }, { "id": "CONTAIN", "level": 1 } ], + "tools": [ [ [ "surface_heat", 16, "LIST" ] ] ], + "components": [ + [ [ "water", 1 ], [ "water_clean", 1 ], [ "sweet_water", 1 ] ], + [ [ "chem_agar", 5 ] ], + [ [ "sugar", 20 ] ], + [ [ "sweet_juice", 1, "LIST" ], [ "soda_pop", 1, "LIST" ] ] + ] + }, + { + "type": "recipe", + "activity_level": "NO_EXERCISE", + "result": "gelatin_dessert_vegan_fruit", + "category": "CC_FOOD", + "subcategory": "CSC_FOOD_OTHER", + "skill_used": "cooking", + "difficulty": 1, + "time": "60 m", + "batch_time_factors": [ 20, 1 ], + "charges": 5, + "book_learn": [ [ "sweets_book", 1 ], [ "baking_book", 1 ], [ "mag_cooking", 1 ], [ "family_cookbook", 1 ] ], + "qualities": [ { "id": "BOIL", "level": 1 }, { "id": "CONTAIN", "level": 1 } ], + "tools": [ [ [ "surface_heat", 16, "LIST" ] ] ], + "components": [ + [ [ "water", 1 ], [ "water_clean", 1 ], [ "sweet_water", 1 ] ], + [ [ "chem_agar", 5 ] ], + [ [ "sugar", 20 ] ], + [ [ "sweet_juice", 1, "LIST" ], [ "soda_pop", 1, "LIST" ] ], + [ [ "sweet_fruit", 1, "LIST" ] ] + ] + }, + { + "type": "recipe", + "activity_level": "NO_EXERCISE", + "result": "candy4", + "category": "CC_FOOD", + "subcategory": "CSC_FOOD_OTHER", + "skill_used": "cooking", + "difficulty": 2, + "time": "60 m", + "batch_time_factors": [ 20, 1 ], + "charges": 12, + "book_learn": [ [ "sweets_book", 2 ], [ "baking_book", 2 ], [ "family_cookbook", 2 ] ], + "qualities": [ { "id": "BOIL", "level": 1 } ], + "tools": [ [ [ "surface_heat", 16, "LIST" ] ], [ [ "mold_plastic", 1 ] ] ], + "components": [ + [ [ "water", 1 ], [ "water_clean", 1 ], [ "sweet_water", 1 ] ], + [ [ "beet_syrup", 1 ] ], + [ [ "gelatin_powder", 25 ], [ "gelatin_fresh", 2 ] ], + [ [ "sugar", 50 ] ], + [ [ "sweet_juice", 1, "LIST" ], [ "soda_pop", 1, "LIST" ] ] + ] + }, + { + "type": "recipe", + "activity_level": "NO_EXERCISE", + "result": "candy5", + "category": "CC_FOOD", + "subcategory": "CSC_FOOD_OTHER", + "skill_used": "cooking", + "difficulty": 2, + "time": "60 m", + "batch_time_factors": [ 20, 1 ], + "charges": 12, + "book_learn": [ [ "sweets_book", 2 ], [ "baking_book", 2 ], [ "family_cookbook", 2 ] ], + "qualities": [ { "id": "BOIL", "level": 1 } ], + "tools": [ [ [ "surface_heat", 16, "LIST" ] ], [ [ "mold_plastic", 1 ] ] ], + "components": [ + [ [ "water", 1 ], [ "water_clean", 1 ], [ "sweet_water", 1 ] ], + [ [ "beet_syrup", 1 ] ], + [ [ "chem_agar", 25 ] ], + [ [ "sugar", 50 ] ], + [ [ "sweet_juice", 1, "LIST" ], [ "soda_pop", 1, "LIST" ] ] + ] } ] diff --git a/data/json/recipes/recipe_food.json b/data/json/recipes/recipe_food.json index 7a36e0ed04bfc..607b12345d3d4 100644 --- a/data/json/recipes/recipe_food.json +++ b/data/json/recipes/recipe_food.json @@ -2284,7 +2284,7 @@ "qualities": [ { "id": "COOK", "level": 2 } ], "tools": [ [ [ "surface_heat", 7, "LIST" ] ] ], "components": [ - [ [ "broth_bone", 1 ] ], + [ [ "gelatin_fresh", 1 ], [ "gelatin_powder", 25 ], [ "chem_agar", 25 ] ], [ [ "meat_red", 1, "LIST" ], [ "meat_cooked", 1 ], @@ -2315,7 +2315,11 @@ "batch_time_factors": [ 50, 5 ], "qualities": [ { "id": "COOK", "level": 2 } ], "tools": [ [ [ "surface_heat", 7, "LIST" ] ] ], - "components": [ [ [ "broth_bone", 1 ] ], [ [ "veggy_any", 4, "LIST" ] ], [ [ "water_clean", 2 ], [ "water", 2 ] ] ] + "components": [ + [ [ "gelatin_fresh", 1 ], [ "gelatin_powder", 25 ], [ "chem_agar", 25 ] ], + [ [ "veggy_any", 4, "LIST" ] ], + [ [ "water_clean", 1 ], [ "water", 1 ] ] + ] }, { "type": "recipe", @@ -2470,6 +2474,7 @@ "type": "recipe", "activity_level": "NO_EXERCISE", "result": "broth_bone", + "byproducts": [ [ "gelatin_fresh" ] ], "charges": 1, "category": "CC_FOOD", "subcategory": "CSC_FOOD_OTHER", diff --git a/data/json/requirements/cooking_components.json b/data/json/requirements/cooking_components.json index 296049cfb5ae5..3068d9ff991ba 100644 --- a/data/json/requirements/cooking_components.json +++ b/data/json/requirements/cooking_components.json @@ -831,5 +831,38 @@ [ "mixed_alcohol_weak", 1 ] ] ] + }, + { + "id": "soda_pop", + "type": "requirement", + "//": "Soda's and such. Anything carbonated that isn't alcholic or an energy drink.", + "components": [ + [ + [ "cola", 1 ], + [ "creamsoda", 1 ], + [ "crispycran", 1 ], + [ "lemonlime", 1 ], + [ "orangesoda", 1 ], + [ "purple_drink", 1 ], + [ "rootbeer", 1 ], + [ "spezi", 1 ] + ] + ] + }, + { + "id": "sweet_juice", + "type": "requirement", + "//": "Non-carbonated, sweet fruit based drinks.", + "components": [ + [ + [ "oj", 1 ], + [ "lemonade", 1 ], + [ "apple_cider", 1 ], + [ "cranberry_juice", 1 ], + [ "juice", 1 ], + [ "juice_pasteurized", 1 ], + [ "kompot", 1 ] + ] + ] } ] From c548905f98450e36819a72fce3663db22dd9fb05 Mon Sep 17 00:00:00 2001 From: Xaleth Date: Thu, 18 Feb 2021 01:50:42 -0600 Subject: [PATCH 008/453] Content: bread in a can (#45680) --- data/json/itemgroups/Food/food.json | 2 ++ data/json/itemgroups/food_service.json | 2 +- data/json/items/comestibles/bread.json | 10 +++++----- data/json/items/comestibles/wheat.json | 6 +++--- data/json/items/containers.json | 4 ++-- data/json/recipes/food/bread.json | 11 ++++++----- 6 files changed, 19 insertions(+), 16 deletions(-) diff --git a/data/json/itemgroups/Food/food.json b/data/json/itemgroups/Food/food.json index a3b1cfab1acbc..17d8462984bb5 100644 --- a/data/json/itemgroups/Food/food.json +++ b/data/json/itemgroups/Food/food.json @@ -134,6 +134,7 @@ { "item": "apple_canned", "prob": 1 }, { "item": "can_cheese", "prob": 1 }, { "item": "fish_canned", "prob": 1 }, + { "item": "brown_bread", "prob": 1 }, { "item": "can_spam", "prob": 1 }, { "item": "can_sardine", "prob": 1 }, { "item": "ravioli", "prob": 1 }, @@ -189,6 +190,7 @@ { "item": "can_chowder", "prob": 35 }, { "item": "can_herring", "prob": 30 }, { "item": "can_chicken", "prob": 40 }, + { "item": "brown_bread", "prob": 20 }, { "item": "broth", "prob": 15 }, { "item": "crackers", "prob": 10 }, { "item": "oyster_crackers", "prob": 10 }, diff --git a/data/json/itemgroups/food_service.json b/data/json/itemgroups/food_service.json index 6c53e003c029d..97a77205dea06 100644 --- a/data/json/itemgroups/food_service.json +++ b/data/json/itemgroups/food_service.json @@ -661,7 +661,7 @@ "subtype": "distribution", "entries": [ { "item": "bread", "prob": 65 }, - { "item": "brown_bread", "prob": 50 }, + { "item": "brown_bread", "prob": 50, "container-item": "bag_plastic" }, { "item": "cake2", "prob": 10 }, { "item": "cake3", "prob": 10 }, { "item": "cornbread", "prob": 35 }, diff --git a/data/json/items/comestibles/bread.json b/data/json/items/comestibles/bread.json index d7f66d42cba2d..89e5844a82cd0 100644 --- a/data/json/items/comestibles/bread.json +++ b/data/json/items/comestibles/bread.json @@ -290,20 +290,20 @@ "weight": "45 g", "color": "brown", "spoils_in": "10 days", - "container": "bag_plastic", + "container": "can_medium", "comestible_type": "FOOD", "symbol": "%", "healthy": 1, - "calories": 74, + "calories": 130, "description": "A sweet bread, like cake.", "price": "272 cent", - "price_postapoc": "4 USD", + "price_postapoc": "2 USD", "material": [ "wheat" ], - "volume": "48 ml", + "volume": "480 ml", "charges": 10, "flags": [ "EATEN_HOT", "EATEN_COLD" ], "fun": 3, - "vitamins": [ [ "calcium", 2 ], [ "iron", 6 ] ] + "vitamins": [ [ "calcium", 4 ], [ "iron", 4 ] ] }, { "type": "COMESTIBLE", diff --git a/data/json/items/comestibles/wheat.json b/data/json/items/comestibles/wheat.json index db88bd2b7d909..5e3af87f6e18a 100644 --- a/data/json/items/comestibles/wheat.json +++ b/data/json/items/comestibles/wheat.json @@ -147,10 +147,10 @@ "type": "COMESTIBLE", "id": "bread_flour", "name": { "str_sp": "bread flour" }, - "weight": "13 g", + "weight": "60 g", "color": "white", "spoils_in": "360 days", - "container": "bag_paper_powder_small", + "container": "bag_paper_powder", "comestible_type": "FOOD", "symbol": "%", "quench": -1, @@ -159,7 +159,7 @@ "price": "200 cent", "price_postapoc": "95 cent", "material": [ "wheat", "powder" ], - "volume": "250 ml", + "volume": "2400 ml", "flags": [ "EDIBLE_FROZEN", "RAW" ], "charges": 20, "vitamins": [ [ "iron", 4 ] ], diff --git a/data/json/items/containers.json b/data/json/items/containers.json index ecc421bd78a50..f8a17a90e43df 100644 --- a/data/json/items/containers.json +++ b/data/json/items/containers.json @@ -162,7 +162,7 @@ "flags": [ "TRADER_AVOID" ] }, { - "id": "bag_paper_powder_small", + "id": "bag_paper_powder", "type": "GENERIC", "category": "container", "name": { "str": "small powder paper bag" }, @@ -177,7 +177,7 @@ { "pocket_type": "CONTAINER", "watertight": false, - "max_contains_volume": "2 L", + "max_contains_volume": "2500 ml", "max_contains_weight": "2 kg", "moves": 200 } diff --git a/data/json/recipes/food/bread.json b/data/json/recipes/food/bread.json index c9996e42485f4..77e84cf6bf0eb 100644 --- a/data/json/recipes/food/bread.json +++ b/data/json/recipes/food/bread.json @@ -33,17 +33,18 @@ "skill_used": "cooking", "difficulty": 3, "charges": 10, - "time": "30 m", + "time": "1 h 30 m", "batch_time_factors": [ 50, 5 ], + "autolearn": false, "book_learn": [ [ "family_cookbook", 1 ], [ "baking_book", 2 ], [ "cookbook", 2 ], [ "cookbook_daintydishes", 2 ] ], "qualities": [ { "id": "COOK", "level": 3 } ], "tools": [ [ [ "surface_heat", 8, "LIST" ] ] ], "components": [ [ [ "bread_flour", 1 ] ], - [ [ "flour", 1 ] ], - [ [ "cornmeal", 1 ] ], - [ [ "molasses", 1 ] ], - [ [ "water", 1 ] ], + [ [ "flour", 5 ] ], + [ [ "cornmeal", 5 ] ], + [ [ "molasses", 2 ] ], + [ [ "water", 1 ], [ "water_clean", 1 ] ], [ [ "salt", 1 ] ] ], "//": "Later: this needs baking soda. Also possibility of rewrite to use portions of components' charges." From f7e0e674c0ce4e4779270ca5f961d3e788e6fde3 Mon Sep 17 00:00:00 2001 From: El-Jekozo <72350516+El-Jekozo@users.noreply.github.com> Date: Thu, 18 Feb 2021 09:51:50 +0200 Subject: [PATCH 009/453] New random mission (#44999) --- data/json/npcs/TALK_COMMON_MISSION.json | 14 ++++++++ data/json/npcs/missiondef.json | 48 +++++++++++++++++++++++++ 2 files changed, 62 insertions(+) diff --git a/data/json/npcs/TALK_COMMON_MISSION.json b/data/json/npcs/TALK_COMMON_MISSION.json index 4bcee75e8b9cb..f60741645f8b4 100644 --- a/data/json/npcs/TALK_COMMON_MISSION.json +++ b/data/json/npcs/TALK_COMMON_MISSION.json @@ -324,5 +324,19 @@ { "text": "Thank you.", "topic": "TALK_NONE", "effect": "clear_mission" }, { "text": "Thanks, bye.", "topic": "TALK_DONE", "effect": "clear_mission" } ] + }, + { + "//": "MISSION_PYROMANIAC mission set this topic as starting topic for mission giver.", + "type": "talk_topic", + "id": "MISSION_PYROMANIAC", + "dynamic_line": "Are we there yet, ? I can't wait to burn that building!", + "responses": [ + { + "text": "We're here. Let's do it!", + "topic": "TALK_MISSION_INQUIRE", + "condition": { "and": [ "mission_complete", { "u_has_items": { "item": "gasoline", "count": 200 } } ] } + }, + { "text": "Be patient, , we're getting there soon.", "topic": "TALK_DONE" } + ] } ] diff --git a/data/json/npcs/missiondef.json b/data/json/npcs/missiondef.json index 0ad333b4a54fc..109e4a3df41a2 100644 --- a/data/json/npcs/missiondef.json +++ b/data/json/npcs/missiondef.json @@ -817,5 +817,53 @@ "success_lie": "OK, then hand them over.", "failure": "Well, that's a shame." } + }, + { + "id": "MISSION_PYROMANIAC", + "type": "mission_definition", + "name": { "str": "Angry pyromaniac" }, + "goal": "MGOAL_GO_TO", + "difficulty": 0, + "value": 0, + "//": "NPC will ask player to burn tagged house. Will follow player after accepting mission.", + "//2": "Change first topic to do proper checks. MGOAL_GO_TO to check if player stands on tagged tile.", + "//3": "At the end of the mission, will place fire on tagged tile and NPC will join player faction.", + "has_generic_rewards": false, + "start": { + "effect": [ "follow_only", { "npc_first_topic": "MISSION_PYROMANIAC" } ], + "assign_mission_target": { + "om_terrain": "house", + "om_terrain_replace": "forest", + "om_terrain_match_type": "PREFIX", + "search_range": 75, + "random": true, + "z": 0 + } + }, + "end": { + "effect": [ "follow", { "u_consume_item": "gasoline", "count": 200 }, { "mapgen_update": "MISSION_PYROMANIAC_BURN" } ] + }, + "origins": [ "ORIGIN_OPENER_NPC" ], + "dialogue": { + "describe": "Oh man, I want to burn it so bad…", + "offer": "I'm so infuriated! I've got an enemy that ruined my life, and now I want to get revenge! I don't care about , I just want to burn his house! Would you help me, ?", + "accepted": "Good. Let's go to his house and burn it down! Oh, by the way, could you bring gasoline with you, ? I was so angry I forgot to bring it with me…", + "rejected": "Seriously? It's such an easy job…", + "advice": "Maybe we can find some gasoline at gas station.", + "inquire": "Are you ready, ?", + "success": "Sweet, sweet revenge! Ah, smells so nice! Feels like the smell of napalm in the morning! All his stuff, and probably even that , will burn to ashes in a matter of minutes. You helped me get my revenge, so I'll follow you to the end, !", + "success_lie": "What?! You liar!", + "failure": "Wow, you failed? How…" + } + }, + { + "//": "For MISSION_PYROMANIAC. Will spawn fire on tile where PC is standing.", + "type": "mapgen", + "update_mapgen_id": "MISSION_PYROMANIAC_BURN", + "method": "json", + "object": { + "place_liquids": [ { "liquid": "gasoline", "x": [ 5, 20 ], "y": [ 5, 20 ], "amount": 5, "repeat": 40 } ], + "place_fields": [ { "field": "fd_fire", "x": [ 5, 20 ], "y": [ 5, 20 ], "repeat": 40 } ] + } } ] From e71e8f892b2fbeea408e38c722762b451b526a27 Mon Sep 17 00:00:00 2001 From: RobertoVGoulart Date: Thu, 18 Feb 2021 04:53:41 -0300 Subject: [PATCH 010/453] Mycus fruit Juice (#44952) --- data/json/items/comestibles/drink.json | 25 +++++++++++++++++++++++++ data/json/recipes/recipe_food.json | 14 ++++++++++++++ 2 files changed, 39 insertions(+) diff --git a/data/json/items/comestibles/drink.json b/data/json/items/comestibles/drink.json index 534a4b82288d4..86ac6d0e05ebd 100644 --- a/data/json/items/comestibles/drink.json +++ b/data/json/items/comestibles/drink.json @@ -862,6 +862,31 @@ "vitamins": [ [ "vitC", 50 ], [ "calcium", 3 ] ], "fun": 3 }, + { + "type": "COMESTIBLE", + "id": "mycus_juice", + "name": "mycus juice", + "weight": "263 g", + "color": "light_gray", + "use_action": [ "MYCUS" ], + "spoils_in": "5 days", + "container": "bottle_plastic", + "comestible_type": "DRINK", + "symbol": "~", + "quench": 100, + "healthy": 2, + "calories": 462, + "description": "Freshly-squeezed from the fruit of the mycus.", + "price": 0, + "price_postapoc": 0, + "material": [ "water", "mushroom" ], + "primary_material": "water", + "volume": "250 ml", + "phase": "liquid", + "flags": [ "EATEN_COLD", "MYCUS_OK", "NUTRIENT_OVERRIDE" ], + "vitamins": [ [ "vitA", 16 ], [ "vitB", 16 ], [ "vitC", 20 ], [ "calcium", 20 ], [ "iron", 16 ] ], + "fun": 30 + }, { "type": "COMESTIBLE", "id": "rootbeer", diff --git a/data/json/recipes/recipe_food.json b/data/json/recipes/recipe_food.json index 607b12345d3d4..197af978fa36f 100644 --- a/data/json/recipes/recipe_food.json +++ b/data/json/recipes/recipe_food.json @@ -7419,6 +7419,20 @@ ] ] }, + { + "type": "recipe", + "activity_level": "LIGHT_EXERCISE", + "result": "mycus_juice", + "category": "CC_FOOD", + "subcategory": "CSC_FOOD_DRINKS", + "skill_used": "cooking", + "difficulty": 1, + "time": "5 m", + "autolearn": true, + "qualities": [ { "id": "HAMMER", "level": 1 }, { "id": "CONTAIN", "level": 1 } ], + "tools": [ [ [ "rag", -1 ] ] ], + "components": [ [ [ "mycus_fruit", 1 ] ], [ [ "water", 1 ], [ "water_clean", 1 ] ] ] + }, { "type": "recipe", "activity_level": "NO_EXERCISE", From f2864fd6d5f394335ca54362a30515e7032c85f4 Mon Sep 17 00:00:00 2001 From: Zukulini Date: Thu, 18 Feb 2021 01:56:41 -0600 Subject: [PATCH 011/453] Milleable corn (#46254) --- data/json/itemgroups/Food/food.json | 2 + data/json/items/comestibles/raw_veggy.json | 46 ++++++++++-- data/json/items/comestibles/veggy_dishes.json | 46 ++++++++++-- data/json/recipes/food/dry.json | 31 ++++++++ data/json/recipes/food/pasta.json | 2 + data/json/recipes/other/other.json | 4 +- data/json/recipes/recipe_food.json | 72 ++++++++++++++++--- .../json/requirements/cooking_components.json | 14 +++- 8 files changed, 193 insertions(+), 24 deletions(-) diff --git a/data/json/itemgroups/Food/food.json b/data/json/itemgroups/Food/food.json index 17d8462984bb5..8ed9a6d47d3d8 100644 --- a/data/json/itemgroups/Food/food.json +++ b/data/json/itemgroups/Food/food.json @@ -39,6 +39,7 @@ { "item": "dry_meat", "prob": 10 }, { "item": "dry_fish", "prob": 10 }, { "item": "dry_veggy", "prob": 10 }, + { "item": "dry_corn", "prob": 1 }, { "item": "dry_fruit", "prob": 10 }, { "item": "oatmeal", "prob": 40 }, { "item": "fruit_leather", "prob": 15 }, @@ -221,6 +222,7 @@ { "item": "dry_meat", "prob": 10 }, { "item": "dry_fish", "prob": 10 }, { "item": "dry_veggy", "prob": 10 }, + { "item": "dry_corn", "prob": 1 }, { "item": "dry_fruit", "prob": 10 }, { "item": "oatmeal", "prob": 40 }, { "item": "toastem", "prob": 30 }, diff --git a/data/json/items/comestibles/raw_veggy.json b/data/json/items/comestibles/raw_veggy.json index b19ded32d195f..cb384ab5531e4 100644 --- a/data/json/items/comestibles/raw_veggy.json +++ b/data/json/items/comestibles/raw_veggy.json @@ -209,24 +209,62 @@ { "type": "COMESTIBLE", "id": "corn", - "name": { "str_sp": "corn" }, - "weight": "153 g", + "name": { "str": "corn cob" }, + "weight": "690 g", "color": "light_green", "spoils_in": "5 days", "comestible_type": "FOOD", "symbol": "%", "healthy": 1, "calories": 132, - "description": "Delicious golden kernels.", + "description": "A corn cob full of delicious golden kernels. You can eat them on the cob or shell it for cooking.", "price": 170, "//": "Thinking this is a single ear here.", "price_postapoc": 50, "material": [ "veggy" ], "volume": "750 ml", + "flags": [ "EATEN_HOT", "RAW" ], + "vitamins": [ [ "vitA", 2 ], [ "vitC", 12 ], [ "iron", 4 ] ], + "use_action": { "type": "transform", "target": "empty_corn_cob", "moves": 500 } + }, + { + "type": "COMESTIBLE", + "id": "corn_kernels", + "name": { "str_sp": "corn kernels" }, + "weight": "210 g", + "color": "yellow", + "spoils_in": "5 days", + "comestible_type": "FOOD", + "symbol": "%", + "healthy": 1, + "calories": 132, + "description": "Delicious golden kernels.", + "price": 200, + "price_postapoc": 60, + "material": [ "veggy" ], + "volume": "285 ml", "flags": [ "EATEN_HOT", "SMOKABLE", "RAW" ], - "smoking_result": "dry_veggy", + "smoking_result": "dry_corn", "vitamins": [ [ "vitA", 2 ], [ "vitC", 12 ], [ "iron", 4 ] ] }, + { + "type": "COMESTIBLE", + "id": "empty_corn_cob", + "name": { "str_sp": "empty corn cob" }, + "weight": "480 g", + "color": "yellow", + "spoils_in": "5 days", + "comestible_type": "FOOD", + "symbol": "%", + "healthy": 1, + "description": "An empty corn cob. It may seem useless, but it can be used to make stock, a delicious jelly, or as fuel.", + "price": 1, + "price_postapoc": 1, + "material": [ "veggy" ], + "volume": "465 ml", + "fun": -8, + "flags": [ "RAW" ] + }, { "type": "COMESTIBLE", "id": "cotton_boll", diff --git a/data/json/items/comestibles/veggy_dishes.json b/data/json/items/comestibles/veggy_dishes.json index adc2170fc9dc7..0205681ab45c4 100644 --- a/data/json/items/comestibles/veggy_dishes.json +++ b/data/json/items/comestibles/veggy_dishes.json @@ -227,20 +227,20 @@ "type": "COMESTIBLE", "id": "cornmeal", "name": { "str_sp": "cornmeal" }, - "weight": "19 g", + "weight": "60 g", "color": "yellow", "spoils_in": "360 days", "container": "box_small", "comestible_type": "FOOD", "symbol": "%", "quench": -1, - "calories": 47, - "vitamins": [ [ "iron", 3 ] ], + "calories": 44, + "vitamins": [ [ "vitA", 2 ], [ "vitC", 12 ], [ "iron", 4 ] ], "description": "This yellow cornmeal is useful for baking.", "price": 450, "price_postapoc": 25, "material": [ "veggy", "powder" ], - "volume": "250 ml", + "volume": "1070 ml", "flags": [ "EDIBLE_FROZEN" ], "charges": 10, "fun": -5 @@ -667,6 +667,27 @@ "flags": [ "EDIBLE_FROZEN" ], "charges": 2 }, + { + "type": "COMESTIBLE", + "id": "dry_corn", + "name": { "str_sp": "dehydrated corn kernels" }, + "weight": "180 g", + "color": "yellow", + "comestible_type": "FOOD", + "symbol": "%", + "quench": -10, + "healthy": 1, + "calories": 132, + "description": "A handful of dried corn kernels.", + "price": 60, + "price_postapoc": 50, + "material": [ "veggy" ], + "milling": { "into": "cornmeal", "conversion_rate": 3 }, + "volume": "255 ml", + "flags": [ "EDIBLE_FROZEN", "RAW" ], + "vitamins": [ [ "vitA", 2 ], [ "vitC", 12 ], [ "iron", 4 ] ], + "fun": -10 + }, { "type": "COMESTIBLE", "id": "rehydrated_veggy", @@ -680,6 +701,23 @@ "delete": { "flags": [ "RAW" ] }, "fun": 2 }, + { + "type": "COMESTIBLE", + "id": "rehydrated_corn_kernels", + "name": { "str_sp": "rehydrated corn kernels" }, + "copy-from": "veggy", + "weight": "70 g", + "color": "yellow", + "spoils_in": "1 day", + "description": "Reconstituted corn kernels; much more enjoyable to eat now that they have been rehydrated.", + "price": 900, + "price_postapoc": 50, + "smoking_result": "dry_corn", + "volume": "95 ml", + "delete": { "flags": [ "RAW" ] }, + "vitamins": [ [ "vitA", 2 ], [ "vitC", 12 ], [ "iron", 4 ] ], + "fun": 2 + }, { "type": "COMESTIBLE", "id": "veggy_salad", diff --git a/data/json/recipes/food/dry.json b/data/json/recipes/food/dry.json index 91593ee23709f..7d18e8d7061fb 100644 --- a/data/json/recipes/food/dry.json +++ b/data/json/recipes/food/dry.json @@ -240,6 +240,37 @@ [ [ "veggy_any_fresh_uncooked", 1, "LIST" ], [ "dandelion_cooked", 1 ], [ "burdock_cooked", 1 ], [ "wild_herbs", 40 ] ] ] }, + { + "type": "recipe", + "activity_level": "NO_EXERCISE", + "result": "dry_corn", + "charges": 1, + "category": "CC_FOOD", + "subcategory": "CSC_FOOD_DRY", + "skill_used": "cooking", + "difficulty": 2, + "time": "18 m", + "autolearn": true, + "batch_time_factors": [ 67, 5 ], + "tools": [ [ [ "dehydrator", 25 ], [ "char_smoker", 25 ] ] ], + "components": [ [ [ "corn_kernels", 1 ] ] ] + }, + { + "type": "recipe", + "activity_level": "NO_EXERCISE", + "result": "dry_corn", + "charges": 1, + "category": "CC_FOOD", + "id_suffix": "frozen_ingredients", + "subcategory": "CSC_FOOD_DRY", + "skill_used": "cooking", + "difficulty": 2, + "time": "20 m", + "autolearn": true, + "batch_time_factors": [ 67, 5 ], + "tools": [ [ [ "dehydrator", 25 ], [ "char_smoker", 25 ] ], [ [ "surface_heat", 5, "LIST" ] ] ], + "components": [ [ [ "corn_kernels", 1 ] ] ] + }, { "result": "dry_veggy_tainted", "charges": 1, diff --git a/data/json/recipes/food/pasta.json b/data/json/recipes/food/pasta.json index 2ed02574899ee..bdf3c328df838 100644 --- a/data/json/recipes/food/pasta.json +++ b/data/json/recipes/food/pasta.json @@ -112,7 +112,9 @@ [ "veggy", 2 ], [ "veggy_wild", 2 ], [ "rehydrated_veggy", 2 ], + [ "rehydrated_corn_kernels", 2 ], [ "dry_veggy", 2 ], + [ "dry_corn", 2 ], [ "mushroom", 2 ], [ "mushroom_cooked", 2 ], [ "morel_cooked", 2 ], diff --git a/data/json/recipes/other/other.json b/data/json/recipes/other/other.json index f0ed6b762dccb..5db4e4f6aad83 100644 --- a/data/json/recipes/other/other.json +++ b/data/json/recipes/other/other.json @@ -15,8 +15,8 @@ [ "fish", 1 ], [ "dry_meat", 1 ], [ "dry_fish", 1 ], - [ "corn", 1 ], - [ "irradiated_corn", 1 ], + [ "corn_kernels", 1 ], + [ "rehydrated_corn_kernels", 1 ], [ "irradiated_carrot", 1 ], [ "carrot", 1 ], [ "bread", 1 ], diff --git a/data/json/recipes/recipe_food.json b/data/json/recipes/recipe_food.json index 197af978fa36f..e032cfc4a730c 100644 --- a/data/json/recipes/recipe_food.json +++ b/data/json/recipes/recipe_food.json @@ -486,6 +486,19 @@ "qualities": [ { "id": "CONTAIN", "level": 1 } ], "components": [ [ [ "dry_veggy", 1 ] ], [ [ "water_clean", 1 ] ] ] }, + { + "type": "recipe", + "activity_level": "NO_EXERCISE", + "result": "rehydrated_corn_kernels", + "category": "CC_FOOD", + "subcategory": "CSC_FOOD_VEGGI", + "skill_used": "cooking", + "time": "3 m", + "autolearn": true, + "flags": [ "BLIND_HARD" ], + "qualities": [ { "id": "CONTAIN", "level": 1 } ], + "components": [ [ [ "dry_corn", 1 ] ], [ [ "water_clean", 1 ] ] ] + }, { "type": "recipe", "activity_level": "NO_EXERCISE", @@ -678,7 +691,9 @@ [ "irradiated_celery", 3 ], [ "veggy_wild", 3 ], [ "veggy", 3 ], - [ "rehydrated_veggy", 3 ] + [ "rehydrated_veggy", 3 ], + [ "rehydrated_corn_kernels", 3 ], + [ "corn_kernels", 3 ] ], [ [ "lettuce", 2 ], @@ -833,7 +848,9 @@ [ "irradiated_celery", 3 ], [ "veggy_wild", 3 ], [ "veggy", 3 ], - [ "rehydrated_veggy", 3 ] + [ "rehydrated_veggy", 3 ], + [ "rehydrated_corn_kernels", 3 ], + [ "corn_kernels", 3 ] ], [ [ "soysauce", 1 ], [ "horseradish", 1 ], [ "salt", 1 ], [ "seasoning_salt", 1 ] ] ] @@ -2397,6 +2414,7 @@ [ [ "jerky", 2 ], [ "dry_meat", 2 ], [ "meat_smoked", 2 ], [ "dry_fish", 2 ], [ "fish_smoked", 2 ] ], [ [ "dry_veggy", 2 ], + [ "dry_corn", 2 ], [ "dry_fruit", 2 ], [ "dry_mushroom", 2 ], [ "juice_pulp", 4 ], @@ -3989,8 +4007,11 @@ [ "mustard_powder", 20 ], [ "garlic_clove", 6 ], [ "rehydrated_veggy", 1 ], + [ "rehydrated_corn_kernels", 1 ], + [ "corn_kernels", 1 ], [ "dry_mushroom", 1 ], - [ "dry_veggy", 1 ] + [ "dry_veggy", 1 ], + [ "dry_corn", 1 ] ] ] }, @@ -4113,6 +4134,9 @@ [ "veggy_salted", 2 ], [ "rehydrated_veggy", 2 ], [ "dry_veggy", 2 ], + [ "rehydrated_corn_kernels", 2 ], + [ "dry_corn", 2 ], + [ "corn_kernels", 2 ], [ "mushroom", 2 ], [ "dry_mushroom", 2 ], [ "morel_cooked", 2 ], @@ -4149,6 +4173,9 @@ [ "veggy_salted", 2 ], [ "rehydrated_veggy", 2 ], [ "dry_veggy", 2 ], + [ "rehydrated_corn_kernels", 2 ], + [ "dry_corn", 2 ], + [ "corn_kernels", 2 ], [ "mushroom", 2 ], [ "dry_mushroom", 2 ], [ "morel_cooked", 2 ], @@ -4186,11 +4213,14 @@ [ "veggy_wild", 2 ], [ "veggy_salted", 2 ], [ "rehydrated_veggy", 2 ], + [ "rehydrated_corn_kernels", 2 ], + [ "corn_kernels", 2 ], [ "mushroom", 2 ], [ "dry_mushroom", 2 ], [ "morel_cooked", 2 ], [ "mushroom_cooked", 2 ], - [ "dry_veggy", 2 ] + [ "dry_veggy", 2 ], + [ "dry_corn", 2 ] ], [ [ "tomato", 1 ], [ "irradiated_tomato", 1 ], [ "can_tomato", 1 ] ], [ [ "meat_red", 1, "LIST" ], [ "dry_meat", 1 ], [ "can_chicken", 1 ] ], @@ -4220,7 +4250,8 @@ [ "tofu", 2 ], [ "dry_tofu", 2 ], [ "mushroom_cooked", 2 ], - [ "dry_veggy", 2 ] + [ "dry_veggy", 2 ], + [ "dry_corn", 2 ] ], [ [ "sauce_pesto", 1 ], @@ -4268,7 +4299,8 @@ [ "dry_mushroom", 2 ], [ "morel_cooked", 2 ], [ "mushroom_cooked", 2 ], - [ "dry_veggy", 2 ] + [ "dry_veggy", 2 ], + [ "dry_corn", 2 ] ], [ [ "cheese", 2 ], [ "can_cheese", 2 ], [ "cheese_hard", 2 ] ], [ [ "sauce_pesto", 1 ], [ "sauce_red", 1 ], [ "seasoning_italian", 5 ], [ "wild_herbs", 10 ] ], @@ -4409,7 +4441,8 @@ [ "coffee_syrup", 5 ], [ "cola", 6 ], [ "con_milk", 1 ], - [ "corn", 3 ], + [ "corn_kernels", 3 ], + [ "rehydrated_corn_kernels", 3 ], [ "honey_bottled", 1 ], [ "honey_glassed", 1 ], [ "honeycomb", 1 ], @@ -4630,7 +4663,7 @@ "autolearn": true, "batch_time_factors": [ 83, 3 ], "tools": [ [ [ "surface_heat", 5, "LIST" ] ], [ [ "rock_quern", -1 ], [ "clay_quern", -1 ] ] ], - "components": [ [ [ "corn", 1 ], [ "irradiated_corn", 1 ], [ "kernels", 1 ] ] ] + "components": [ [ [ "dry_corn", 1 ], [ "kernels", 1 ] ] ] }, { "type": "recipe", @@ -4913,6 +4946,8 @@ [ "irradiated_tomato", 1 ], [ "irradiated_broccoli", 1 ], [ "rehydrated_veggy", 1 ], + [ "rehydrated_corn_kernels", 1 ], + [ "corn_kernels", 1 ], [ "morel_cooked", 1 ], [ "mushroom_cooked", 1 ], [ "sauerkraut_onions", 1 ], @@ -5833,6 +5868,8 @@ [ "irradiated_tomato", 1 ], [ "irradiated_broccoli", 1 ], [ "rehydrated_veggy", 1 ], + [ "rehydrated_corn_kernels", 1 ], + [ "corn_kernels", 1 ], [ "morel_cooked", 1 ], [ "mushroom_cooked", 1 ], [ "sauerkraut_onions", 1 ], @@ -6419,7 +6456,20 @@ "autolearn": true, "batch_time_factors": [ 83, 3 ], "tools": [ [ [ "food_processor", 20 ] ] ], - "components": [ [ [ "corn", 1 ], [ "irradiated_corn", 1 ], [ "kernels", 1 ] ] ] + "components": [ [ [ "dry_corn", 1 ] ] ] + }, + { + "result": "corn_kernels", + "type": "recipe", + "activity_level": "LIGHT_EXERCISE", + "category": "CC_FOOD", + "subcategory": "CSC_FOOD_OTHER", + "byproducts": [ [ "empty_corn_cob", 1 ] ], + "skill_used": "cooking", + "time": "20 s", + "autolearn": true, + "qualities": [ { "id": "CUT", "level": 1 } ], + "components": [ [ [ "corn", 1 ], [ "irradiated_corn", 1 ] ] ] }, { "result": "flour", @@ -6517,7 +6567,7 @@ "components": [ [ [ "can_corn", 1 ], - [ "corn", 1 ], + [ "corn_kernels", 1 ], [ "oats", 1 ], [ "buckwheat", 1 ], [ "wheat", 1 ], @@ -6755,7 +6805,7 @@ "autolearn": true, "batch_time_factors": [ 83, 3 ], "tools": [ [ [ "surface_heat", 5, "LIST" ] ], [ [ "mortar_pestle", -1 ] ] ], - "components": [ [ [ "corn", 1 ], [ "irradiated_corn", 1 ], [ "kernels", 1 ] ] ] + "components": [ [ [ "dry_corn", 1 ] ] ] }, { "type": "recipe", diff --git a/data/json/requirements/cooking_components.json b/data/json/requirements/cooking_components.json index 3068d9ff991ba..62f1e3568fd05 100644 --- a/data/json/requirements/cooking_components.json +++ b/data/json/requirements/cooking_components.json @@ -382,6 +382,8 @@ [ "can_corn", 1 ], [ "hominy", 1 ], [ "dry_veggy", 1 ], + [ "dry_corn", 1 ], + [ "corn_kernels", 1 ], [ "con_milk", 1 ], [ "flatbread", 1 ], [ "tortilla_corn", 1 ], @@ -447,8 +449,11 @@ [ [ "veggy_wild", 2 ], [ "veggy", 2 ], + [ "corn_kernels", 2 ], [ "rehydrated_veggy", 2 ], + [ "rehydrated_corn_kernels", 2 ], [ "dry_veggy", 2 ], + [ "dry_corn", 2 ], [ "dry_beans", 2 ], [ "can_beans", 2 ], [ "raw_beans", 2 ], @@ -665,6 +670,8 @@ [ "raw_dandelion", 1 ], [ "raw_burdock", 1 ], [ "rehydrated_veggy", 1 ], + [ "rehydrated_corn_kernels", 1 ], + [ "corn_kernels", 1 ], [ "veggy", 1 ], [ "veggy_wild", 1 ], [ "veggy_salted", 1 ], @@ -675,7 +682,7 @@ { "id": "veggy_any_uncooked", "type": "requirement", - "components": [ [ [ "rehydrated_veggy", 1 ], [ "veggy_any_fresh_uncooked", 1, "LIST" ] ] ] + "components": [ [ [ "rehydrated_veggy", 1 ], [ "rehydrated_corn_kernels", 1 ], [ "veggy_any_fresh_uncooked", 1, "LIST" ] ] ] }, { "id": "veggy_any_fresh_uncooked", @@ -691,8 +698,7 @@ [ "cattail_stalk", 1 ], [ "celery", 1 ], [ "irradiated_celery", 1 ], - [ "corn", 1 ], - [ "irradiated_corn", 1 ], + [ "corn_kernels", 1 ], [ "cucumber", 1 ], [ "irradiated_cucumber", 1 ], [ "lettuce", 1 ], @@ -750,6 +756,8 @@ "components": [ [ [ "veggy_any", 1, "LIST" ], + [ "empty_corn_cob", 1 ], + [ "corn", 1 ], [ "powder_eggs", 1 ], [ "eggs_bird", 1, "LIST" ], [ "egg_reptile", 1 ], From 6589717ed51ca1ca9bb8fec0327f2c678d29cbdb Mon Sep 17 00:00:00 2001 From: klorpa <30924131+klorpa@users.noreply.github.com> Date: Thu, 18 Feb 2021 02:07:00 -0600 Subject: [PATCH 012/453] Talk Tag Additions (#47010) --- data/json/items/armor/storage.json | 2 +- data/json/npcs/talk_tags.json | 41 +++++++++++++++++++++++++++++- data/json/npcs/talk_tags_chat.json | 28 +++++++++++++------- doc/MARTIALART_JSON.md | 2 +- doc/PROFICIENCY.md | 2 +- 5 files changed, 62 insertions(+), 13 deletions(-) diff --git a/data/json/items/armor/storage.json b/data/json/items/armor/storage.json index d71ba7e2f0ae4..b410c75b32f3b 100644 --- a/data/json/items/armor/storage.json +++ b/data/json/items/armor/storage.json @@ -1047,7 +1047,7 @@ "warmth": 8, "material_thickness": 2, "properties": [ [ "creature_size_capacity", "SMALL" ] ], - "use_action": "CAPTURE_MONSTER_ACT", + "use_action": [ "CAPTURE_MONSTER_ACT" ], "flags": [ "BELTED", "WATERPROOF" ] }, { diff --git a/data/json/npcs/talk_tags.json b/data/json/npcs/talk_tags.json index 2b25404c7ca4b..a75f1f17c1ee8 100644 --- a/data/json/npcs/talk_tags.json +++ b/data/json/npcs/talk_tags.json @@ -63,6 +63,7 @@ "I'm sorry . I'm afraid I can't do that.", "Wish I could, .", "Nothing to trade, sorry .", + "I don't want to trade right now.", "Maybe next time?" ] }, @@ -79,6 +80,7 @@ "Great idea! Call me when you find SOMEONE ELSE to do it.", "I'm afraid I can't help you there.", "Not exactly the settlin' type.", + "I can't help you with that right now.", "I'm more of a free spirit, can't settle, sorry." ] }, @@ -445,6 +447,7 @@ "Time for bed! See you in the morning.", "There's a bed calling my name, and I'm going to it.", "Good night! Wake me if you need me.", + "Well, I'm going to bed now.", "Calling it a night for now. You get some rest too, okay?" ] }, @@ -608,6 +611,7 @@ "Drop your weapon, !", "Put down your !", "Alright, drop the !", + "Hey, put that weapon down!", "Please put down your weapon. I'll give you to the count of three. One…", "Let's take it easy now, okay? Put the weapon down." ] @@ -777,6 +781,7 @@ "Bombs away!", "Shrapnel, incoming! Watch it!", "Making some noise!", + "It's gonna blow!", "Hit the deck!" ] }, @@ -944,6 +949,9 @@ "! This is the end,", "I can take on", "Time to die,", + "Prepare to die,", + "See you in hell,", + "Rot in hell,", "Say your prayers," ] }, @@ -980,6 +988,7 @@ "Hold up, gotta plug this hole in me.", "Watch my back while I stitch my arm back on .", "Gotta bandage this or I'll bleed out. Give me a sec.", + "Let me fix myself up here for a second.", "I ain't got time to ble-wait, that's a lot of blood. Give me a second while I patch this." ] }, @@ -996,6 +1005,8 @@ "What was that?", "Huh? Is someone there?", "Who's there?", + "Did anyone else hear that?", + "Sounds like someone said something.", "Who goes there?" ] }, @@ -1010,6 +1021,8 @@ "What's that noise?", "Is something over there?", "Sounds like something bad's going on.", + "What's going on over there?", + "Sounds like a fight's going on.", "What was that?" ] }, @@ -1024,6 +1037,9 @@ "Did you hear that? Sounded like", "What is making that sound? I can hear the", "I could swear I heard", + "Huh? I think I just heard", + "Huh? That sounded like", + "I think that was the sound of", "I could have sworn I just heard" ] }, @@ -1067,6 +1083,7 @@ "Mmm, that weed smells good.", "Man, I can smell the weed, can I have some?", "Are you sure it's a good idea to smoke that now?", + "Are you getting stoned right now?", "Is that the devil's lettuce I smell?" ] }, @@ -1091,7 +1108,14 @@ "type": "snippet", "category": "", "//": "Complaint when the NPC is near the avatar who is smoking crack.", - "text": [ "Ew, smells like burning rubber!", "Ugh, that smells rancid!", "Why are you smoking crack cocaine?", "" ] + "text": [ + "Ew, smells like burning rubber!", + "Ugh, that smells rancid!", + "Why are you smoking crack cocaine?", + "Crack cocaine smells awful!", + "Are you seriously going to be a crackhead around me?", + "" + ] }, { "type": "snippet", @@ -1114,6 +1138,7 @@ "Pass some ethanol, I need to power my ethanol burner.", "Waiter! I need a refill, my ethanol burner is running out of charge!", "I require ethanol for my internal power supply. Anything on you?", + "I need some ethanol to power up my CBMs.", "Got any alcohol to spare? Need to recharge my drives. Methanol, would do." ] }, @@ -1125,6 +1150,7 @@ "I need some junk to power my internal furnace.", "I can't recharge my CBMs without some firewood for my internal furnace.", "I need something to use as fuel for my furnace.", + "I need something to burn for my furnace. Can you help?", "Hey, , can I get some waste paper or withered plants? I need to recharge." ] }, @@ -1135,6 +1161,8 @@ "text": [ "I need some fuel to power my bionics.", "I can't recharge my CBMs without some fuel.", + "Could I get some fuel for my bionics?", + "I need more fuel. Can you help me out here?", "Hey, , can I get some fuel? I need to recharge." ] }, @@ -1163,6 +1191,7 @@ "What was the Cataclysm like for you?", "How did you make it through the initial chaos?", "Tell me how you survived the initial wave of the Cataclysm.", + "How did you survive those first few days?", "Was it rough surviving thus far?" ] }, @@ -1173,6 +1202,8 @@ "text": [ "How do you think we ended up here? What even happened?", "What's going on? Like, big picture, what the hell happened?", + "What do you think the cataclysm even was?", + "So how do you think the end of the world happened?", "Have you heard anything about how the apocalypse came about?" ] }, @@ -1184,6 +1215,7 @@ "Let's talk about something else.", "Let's change the subject.", "I'd like to ask you about something else.", + "I'd like to talk about about something else.", "Moving on…", "Anyway…" ] @@ -1294,6 +1326,7 @@ "Retreat! Retreat!", "Book it!", "Leg it!", + "I'm getting the hell out of here!", "Thank fuck for all the cardio!" ] }, @@ -1306,6 +1339,7 @@ "! Die, you ! I want to live!", "My feet failed me! Arms, don't fail me!", "Can't run! Have to fight!", + "I can't run away from this!", "If I die, I'm taking you all with me!" ] }, @@ -1322,6 +1356,7 @@ "Somebody get some water!", "Fire, fire, FIRE!", "Get an extinguisher!", + "Somebody get some water or something!", "Danger hot!" ] }, @@ -1355,6 +1390,7 @@ "Clean water, the taste that refreshes!", "I was parched, but not I am not.", "Water is nice, but I should get a grog ration.", + "Nothing quite like clean water.", "That wasn't Evian, but I'm not thirsty." ] }, @@ -1366,6 +1402,7 @@ "And now I have eaten and am not hungry.", "That food was good, but I miss real restaurants.", "Well, that satisfied me.", + "Nice to have food once in a while.", "I just had some food, but I'm still peckish. Would you mind if I ate more?" ] }, @@ -1376,6 +1413,8 @@ "text": [ "Hey, , we're out of food.", "Hey, the larder is empty! We're going to starve.", + "There's no food in the larder!", + "We need more food in the basecamp larder; it's empty.", "Uhm, , I don't meant to criticize, but we should focus on distributing some food into the basecamp larder." ] }, diff --git a/data/json/npcs/talk_tags_chat.json b/data/json/npcs/talk_tags_chat.json index 55a9b672fd038..a7520f39c32c7 100644 --- a/data/json/npcs/talk_tags_chat.json +++ b/data/json/npcs/talk_tags_chat.json @@ -19,6 +19,8 @@ "text": [ "Yeah, this summer heat is hitting me hard, you know?", "Enjoying the summer.", + "Not quite like the summers from before, huh?", + "Can't wait for this summer to be over.", "Kinda wishing it would cool off a bit, to be honest." ] }, @@ -29,6 +31,8 @@ "text": [ "OK, maybe it'll stop me from freezing in this weather.", "Gotta say, I'm not minding the snow.", + "Not quite like the winters from before, huh?", + "Can't wait for this winter to be over.", "It's weird the zombies don't freeze." ] }, @@ -36,7 +40,13 @@ "type": "snippet", "category": "", "//": "A sentence about being sick to go before a more general chitchat message.", - "text": [ "Well, I'm feeling pretty sick… but sure." ] + "text": [ + "A nice chat might improve my health somewhat.", + "Alright, but I'm feeling a bit under the weather.", + "I'm not feeling too well, but I can still talk for a bit.", + "We can talk, even though I'm not feeling too well.", + "Well, I'm feeling pretty sick… but sure." + ] }, { "type": "snippet", @@ -58,7 +68,7 @@ "What the heck. How's life been treating you?", "So, how about that weather, eh?", "Nice of you to make time. How's it been for you lately?", - "My dogs’ve been barkin’ lately, you know?", + "My dogs've been barkin' lately, you know?", "I feel great today. Not sure what it is, just one of those days." ] }, @@ -70,11 +80,11 @@ "I just can't believe it's over. I keep running my head back to the days it all fell apart. The riots. The lies. The psychos. It never really felt like it was going to go like this.", "You ever think there's any truth to the crap they were spouting before the world ended? Mind control drugs in the water, bio-terrorism? Some of it would make sense, but it seems so far-fetched. Then again, we're dealing with actual zombies.", "I wonder if I should be getting more religious now, or less. You know what I'm sayin', ?", - "I been thinkin’ about rearranging my gear. It’s a real mess. Don’t wanna go for my weapon and accidentally pull out a granola bar, right?", - "You ever wonder why we even bother? We’re all just gonna be zombies eventually anyway. I mean, not that I’m gonna stop fighting, but what’s the damn point?", + "I been thinkin' about rearranging my gear. It's a real mess. Don't wanna go for my weapon and accidentally pull out a granola bar, right?", + "You ever wonder why we even bother? We're all just gonna be zombies eventually anyway. I mean, not that I'm gonna stop fighting, but what's the damn point?", "I wish I could go bust a cap in one of those zombies right now, without all the fuss about being scared for my life.", "Every time I close my eyes, I can still see the riots. Do you get that, or is it just me?", - "You ever feel like the whole time before the apocalypse was just a dream you’re waking up from?", + "You ever feel like the whole time before the apocalypse was just a dream you're waking up from?", "When do you think you realized the world was ending? For me, it was that damned YouTube video with the lady killing the baby. Holy shit, you know?", "I wonder if the government's still out there, holed up in some bunker.", "Remember some of the crazy news from the end of the world? The stuff that got drowned out by the riot coverage I mean. Like, didn't the governor of Rhode Island secede from the Union or something?", @@ -89,9 +99,9 @@ "text": [ "I can't stop wondering who fucked up to make all this happen. Obviously we can't trust the news, they claimed the zombies were \"rioters\" for weeks. Why? Where did this come from?", "If what they told us about the Chinese was even partly true, do you think it's like this in China? Or maybe the US is some kind of quarantine zone, and at least some of the world is still out there.", - "Have you noticed injuries aren’t healing the same as usual? I started spotting it before the world ended, but it’s become more pronounced. There’s hardly even a granulation step after a cut closes.", - "I still don’t understand how these zombies are powered. They’re like perpetual motion machines.", - "So many parts of this still don't fit together. Who created the zombies? What powers them? Maybe the rumours of mind control drugs were true all along, and someone found a way to bioengineer living dead." + "Have you noticed injuries aren't healing the same as usual? I started spotting it before the world ended, but it's become more pronounced. There's hardly even a granulation step after a cut closes.", + "I still don't understand how these zombies are powered. They're like perpetual motion machines.", + "So many parts of this still don't fit together. Who created the zombies? What powers them? Maybe the rumors of mind control drugs were true all along, and someone found a way to bioengineer living dead." ] }, { @@ -103,7 +113,7 @@ "", "How do these zombies even keep going? What are they eating? Do you think they'll ever rot away?", "I been thinkin', one of these days, we're gonna run out of toilet paper. What then?", - "Do you think it’s weird how we’ll, like, open a locked building and find a lone zombie inside? How’d it even get there?", + "Do you think it's weird how we'll, like, open a locked building and find a lone zombie inside? How'd it even get there?", "Sometimes I wonder if we're all psychos, not just the ones that went crazy and rioted. I never would have thought I could do the things I've done since the world ended.", "You read any good books lately? I'm glad we still got books.", "You know what I miss? Movie theaters. You think Hollywood survived this? Maybe there's a bunch of zombie actors out there, filmin' shit out of reflex. Hah, I'd watch that shit." diff --git a/doc/MARTIALART_JSON.md b/doc/MARTIALART_JSON.md index 2331a993b9fc1..48a89d7eeaffd 100644 --- a/doc/MARTIALART_JSON.md +++ b/doc/MARTIALART_JSON.md @@ -61,7 +61,7 @@ "aoe": "spin", // This technique has an area-of-effect; doesn't work against solo targets "block_counter": true, // This technique may automatically counterattack on a successful block "dodge_counter": true, // This technique may automatically counterattack on a successful dodge -"weighting": 2, // Affects likelihood this technique will be seleted when many are available +"weighting": 2, // Affects likelihood this technique will be selected when many are available "defensive": true, // Game won't try to select this technique when attacking "miss_recovery": true, // Misses while attacking will use fewer moves "messages" : [ // What is printed when this technique is used by the player and by an npc diff --git a/doc/PROFICIENCY.md b/doc/PROFICIENCY.md index 1aa7481c5ed3a..80a57222aaa54 100644 --- a/doc/PROFICIENCY.md +++ b/doc/PROFICIENCY.md @@ -38,7 +38,7 @@ Optional. Float When used in recipes these values are the amount the time to complete the recipe, and the chance to fail the recipe, will be multiplied by. - For proficiencies that represent core basic knowledge and foundational principles, the `time` should usually be low (1.5 or so), and the `fail` should be high (4 or more). -- For "flavour" proficiencies that offer a small boost, these should be around 1.5 each. +- For "flavor" proficiencies that offer a small boost, these should be around 1.5 each. - Most other proficiencies should be in the 2-3 range for both values. ### `time_to_learn` From bf170fdb710de64584c868c44be19fc5a8a79e40 Mon Sep 17 00:00:00 2001 From: UmbralReaper <67179462+UmbralReaper@users.noreply.github.com> Date: Sat, 20 Feb 2021 19:53:41 +1000 Subject: [PATCH 013/453] Fix typo in Valentines Card (#47583) --- data/json/snippets/valentines.json | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/data/json/snippets/valentines.json b/data/json/snippets/valentines.json index 71d3624a7bb92..966bf1253dad7 100644 --- a/data/json/snippets/valentines.json +++ b/data/json/snippets/valentines.json @@ -38,7 +38,7 @@ }, { "id": "valentine_10", - "text": "A girl smiles into the camera. Behind here a house is on fire. \"I'm burning, I'm burning, I'm burning for you, my valentine!\"" + "text": "A girl smiles into the camera. Behind her a house is on fire. \"I'm burning, I'm burning, I'm burning for you, my valentine!\"" } ] } From 0b98fa8d647ae896d711b06cc0ee55a500900cba Mon Sep 17 00:00:00 2001 From: SariusSkelrets <68650913+SariusSkelrets@users.noreply.github.com> Date: Tue, 23 Feb 2021 02:35:57 -0500 Subject: [PATCH 014/453] (CrazyCataclysm) Crazy Hallucinations (#47386) --- data/mods/CrazyCataclysm/crazy_monsters.json | 14 ++++++++++++++ 1 file changed, 14 insertions(+) diff --git a/data/mods/CrazyCataclysm/crazy_monsters.json b/data/mods/CrazyCataclysm/crazy_monsters.json index 57808d7c97670..30a5246dfd178 100644 --- a/data/mods/CrazyCataclysm/crazy_monsters.json +++ b/data/mods/CrazyCataclysm/crazy_monsters.json @@ -14,6 +14,20 @@ "copy-from": "mon_zombie_electric", "special_attacks": [ [ "SHOCKING_REVEAL", 25 ] ] }, + { + "id": "halloween_dragon", + "type": "MONSTER", + "name": { "str": "inflatable dragon" }, + "copy-from": "mon_dragon_dummy", + "delete": { "flags": [ "NOT_HALLUCINATION" ] } + }, + { + "id": "halloween_ghost", + "type": "MONSTER", + "name": { "str": "inflatable ghost" }, + "copy-from": "mon_halloween_ghost", + "delete": { "flags": [ "NOT_HALLUCINATION" ] } + }, { "id": "mon_zombie_skeltal", "type": "MONSTER", From eff23224dcc3959a9cbf9ada27b8c2b534fe01f1 Mon Sep 17 00:00:00 2001 From: Fosheze <50811445+Fosheze@users.noreply.github.com> Date: Tue, 23 Feb 2021 01:39:26 -0600 Subject: [PATCH 015/453] Mealgurb (#47685) --- data/mods/Aftershock/items/comestibles/bug_brew.json | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/data/mods/Aftershock/items/comestibles/bug_brew.json b/data/mods/Aftershock/items/comestibles/bug_brew.json index 36657471e1eff..bcbf8d7cbd91d 100644 --- a/data/mods/Aftershock/items/comestibles/bug_brew.json +++ b/data/mods/Aftershock/items/comestibles/bug_brew.json @@ -2,7 +2,7 @@ { "type": "COMESTIBLE", "id": "afs_mealgrub_medium", - "name": { "str": "mealgurb growth medium" }, + "name": { "str": "mealgrub growth medium" }, "description": "All sort of organic substances rendered into a nutritious goop that can be used as a growth medium in grub aquaculture. Urban myth claims that its original formula was just bottled industrial runoff. Whatever the case, mealgrubs thrive within it.", "weight": "100 g", "container": "jug_plastic", @@ -25,7 +25,7 @@ { "type": "COMESTIBLE", "id": "afs_mealgrub_spores", - "name": { "str_sp": "mealgurb spores" }, + "name": { "str_sp": "mealgrub spores" }, "description": "Mealgrubs are a staple aquacultural product, treasured for their ability to process nearly any organic substance into safe for consumption animal protein. As the result of very heavy handed gene-modding these are propietary organism, and strictly speaking, its illegal to grow them without a licence.", "weight": "100 g", "container": "bottle_plastic_small", From d2df94f7d5c7041851ff0292839e73414e664772 Mon Sep 17 00:00:00 2001 From: Lamandus <33199510+Lamandus@users.noreply.github.com> Date: Tue, 23 Feb 2021 08:46:59 +0100 Subject: [PATCH 016/453] Add duct tape blindfold for old reciepe plus tweaks for reciepe (#47527) --- data/json/items/tool_armor.json | 22 ++++++++++++++++++++++ data/json/recipes/armor/head.json | 7 ++----- data/json/recipes/recipe_obsolete.json | 6 ++++++ 3 files changed, 30 insertions(+), 5 deletions(-) diff --git a/data/json/items/tool_armor.json b/data/json/items/tool_armor.json index 5187b13499c55..fb659605f0cfb 100644 --- a/data/json/items/tool_armor.json +++ b/data/json/items/tool_armor.json @@ -114,6 +114,28 @@ "environmental_protection": 1, "flags": [ "BLIND" ] }, + { + "id": "blindfold_duct", + "type": "ARMOR", + "name": { "str": "duct tape blindfold" }, + "//": "A folded bandana still takes up some space on the head.", + "description": "A simple covering tied over the eyes to block sight, made out of duct tape. Useful for sleeping in bright areas.", + "weight": "20 g", + "volume": "60 ml", + "price": 10, + "price_postapoc": 5, + "material": [ "plastic" ], + "symbol": "[", + "looks_like": "blindfold", + "color": "dark_gray", + "covers": [ "eyes" ], + "coverage": 95, + "encumbrance": 10, + "warmth": 0, + "material_thickness": 1, + "environmental_protection": 1, + "flags": [ "BLIND" ] + }, { "id": "ear_plugs", "type": "ARMOR", diff --git a/data/json/recipes/armor/head.json b/data/json/recipes/armor/head.json index 8e6c5c7b22f32..75e2a2c0af783 100644 --- a/data/json/recipes/armor/head.json +++ b/data/json/recipes/armor/head.json @@ -42,18 +42,15 @@ "components": [ [ [ "felt_patch", 4 ] ] ] }, { - "result": "blindfold", + "result": "blindfold_duct", "type": "recipe", "activity_level": "NO_EXERCISE", - "id_suffix": "from_tape", "category": "CC_ARMOR", "subcategory": "CSC_ARMOR_HEAD", "skill_used": "fabrication", - "difficulty": 1, "time": "3 m", - "reversible": true, "autolearn": true, - "components": [ [ [ "duct_tape", 10 ] ] ], + "components": [ [ [ "duct_tape", 50 ] ] ], "flags": [ "BLIND_EASY" ] }, { diff --git a/data/json/recipes/recipe_obsolete.json b/data/json/recipes/recipe_obsolete.json index 40c0171aa442e..40b4b52c04c91 100644 --- a/data/json/recipes/recipe_obsolete.json +++ b/data/json/recipes/recipe_obsolete.json @@ -2752,6 +2752,12 @@ "result": "mp3", "obsolete": true }, + { + "type": "recipe", + "result": "blindfold", + "id_suffix": "from_tape", + "obsolete": true + }, { "type": "recipe", "result": "towel", From f6d2644466bbc988bc439542f5e73d0e1a5521d3 Mon Sep 17 00:00:00 2001 From: Curtis Merrill Date: Tue, 23 Feb 2021 02:51:26 -0500 Subject: [PATCH 017/453] Prepare npc, spell, character, and item for new ai (#47207) --- src/character.cpp | 2 +- src/character.h | 7 +- src/creature.h | 7 ++ src/item.cpp | 20 +++--- src/item.h | 3 +- src/magic.cpp | 92 ++++++++++++++++++++++-- src/magic.h | 14 +++- src/magic_spell_effect.cpp | 11 +-- src/npc.cpp | 25 +++++++ src/npc.h | 15 ++++ src/npcmove.cpp | 36 +++++++--- src/ranged.cpp | 132 +++++++++++++++++++++++----------- tests/player_helpers.cpp | 46 ++++++++++++ tests/player_helpers.h | 4 ++ tests/ranged_balance_test.cpp | 47 +----------- 15 files changed, 338 insertions(+), 123 deletions(-) diff --git a/src/character.cpp b/src/character.cpp index 42071b6f7d1db..fe1cd151e70fc 100644 --- a/src/character.cpp +++ b/src/character.cpp @@ -2673,7 +2673,7 @@ int Character::get_mod_stat_from_bionic( const character_stat &Stat ) const return ret; } -int Character::get_standard_stamina_cost( item *thrown_item ) +int Character::get_standard_stamina_cost( const item *thrown_item ) const { // Previously calculated as 2_gram * std::max( 1, str_cur ) // using 16_gram normalizes it to 8 str. Same effort expenditure diff --git a/src/character.h b/src/character.h index d46b7db26de3a..a348e13a42716 100644 --- a/src/character.h +++ b/src/character.h @@ -501,7 +501,7 @@ class Character : public Creature, public visitable void mod_stat( const std::string &stat, float modifier ) override; - int get_standard_stamina_cost( item *thrown_item = nullptr ); + int get_standard_stamina_cost( const item *thrown_item = nullptr ) const; /**Get bonus to max_hp from excess stored fat*/ int get_fat_to_hp() const; @@ -1635,6 +1635,10 @@ class Character : public Creature, public visitable */ int item_reload_cost( const item &it, const item &ammo, int qty ) const; + projectile thrown_item_projectile( const item &thrown ) const; + int thrown_item_adjusted_damage( const item &thrown ) const; + // calculates the total damage possible from a thrown item, without resistances and such. + int thrown_item_total_damage_raw( const item &thrown ) const; /** Maximum thrown range with a given item, taking all active effects into account. */ int throw_range( const item & ) const; /** Dispersion of a thrown item, against a given target, taking into account whether or not the throw was blind. */ @@ -1847,6 +1851,7 @@ class Character : public Creature, public visitable // gets all the spells known by this character that have this spell class // spells returned are a copy, do not try to edit them from here, instead use known_magic::get_spell std::vector spells_known_of_class( const trait_id &spell_class ) const; + bool cast_spell( spell &sp, bool fake_spell, cata::optional target ); void make_bleed( const effect_source &source, const bodypart_id &bp, time_duration duration, int intensity = 1, bool permanent = false, bool force = false, bool defferred = false ); diff --git a/src/creature.h b/src/creature.h index 720fd01dc6493..011f9cca36a26 100644 --- a/src/creature.h +++ b/src/creature.h @@ -44,6 +44,7 @@ class anatomy; class avatar; class field; class field_entry; +class npc; class player; class time_duration; struct point; @@ -263,6 +264,12 @@ class Creature : public location, public viewer virtual const avatar *as_avatar() const { return nullptr; } + virtual const npc *as_npc() { + return nullptr; + } + virtual const npc *as_npc() const { + return nullptr; + } virtual monster *as_monster() { return nullptr; } diff --git a/src/item.cpp b/src/item.cpp index 5abee103d7c07..92b826a865dc5 100644 --- a/src/item.cpp +++ b/src/item.cpp @@ -1498,7 +1498,7 @@ static const double hits_by_accuracy[41] = { 9993, 9997, 9998, 9999, 10000 // 16 to 20 }; -double item::effective_dps( const Character &guy, monster &mon ) const +double item::effective_dps( const Character &guy, Creature &mon ) const { const float mon_dodge = mon.get_dodge(); float base_hit = guy.get_dex() / 4.0f + guy.get_hit_weapon( *this ); @@ -1533,19 +1533,19 @@ double item::effective_dps( const Character &guy, monster &mon ) const // sum average damage past armor and return the number of moves required to achieve // that damage const auto calc_effective_damage = [ &, moves_per_attack]( const double num_strikes, - const bool crit, const Character & guy, monster & mon ) { - monster temp_mon = mon; + const bool crit, const Character & guy, Creature & mon ) { + Creature *temp_mon = &mon; double subtotal_damage = 0; damage_instance base_damage; guy.roll_all_damage( crit, base_damage, true, *this ); damage_instance dealt_damage = base_damage; - temp_mon.absorb_hit( bodypart_id( "torso" ), dealt_damage ); + temp_mon->absorb_hit( bodypart_id( "torso" ), dealt_damage ); dealt_damage_instance dealt_dams; for( const damage_unit &dmg_unit : dealt_damage.damage_units ) { int cur_damage = 0; int total_pain = 0; - temp_mon.deal_damage_handle_type( effect_source::empty(), dmg_unit, bodypart_id( "torso" ), - cur_damage, total_pain ); + temp_mon->deal_damage_handle_type( effect_source::empty(), dmg_unit, bodypart_id( "torso" ), + cur_damage, total_pain ); if( cur_damage > 0 ) { dealt_dams.dealt_dams[ static_cast( dmg_unit.type )] += cur_damage; } @@ -1555,20 +1555,20 @@ double item::effective_dps( const Character &guy, monster &mon ) const double subtotal_moves = moves_per_attack * num_strikes; if( has_technique( RAPID ) ) { - monster temp_rs_mon = mon; + Creature *temp_rs_mon = &mon; damage_instance rs_base_damage; guy.roll_all_damage( crit, rs_base_damage, true, *this ); damage_instance dealt_rs_damage = rs_base_damage; for( damage_unit &dmg_unit : dealt_rs_damage.damage_units ) { dmg_unit.damage_multiplier *= 0.66; } - temp_rs_mon.absorb_hit( bodypart_id( "torso" ), dealt_rs_damage ); + temp_rs_mon->absorb_hit( bodypart_id( "torso" ), dealt_rs_damage ); dealt_damage_instance rs_dealt_dams; for( const damage_unit &dmg_unit : dealt_rs_damage.damage_units ) { int cur_damage = 0; int total_pain = 0; - temp_rs_mon.deal_damage_handle_type( effect_source::empty(), dmg_unit, bodypart_id( "torso" ), - cur_damage, total_pain ); + temp_rs_mon->deal_damage_handle_type( effect_source::empty(), dmg_unit, bodypart_id( "torso" ), + cur_damage, total_pain ); if( cur_damage > 0 ) { rs_dealt_dams.dealt_dams[ static_cast( dmg_unit.type ) ] += cur_damage; } diff --git a/src/item.h b/src/item.h index 6290008679cd7..6f5064ce44ad8 100644 --- a/src/item.h +++ b/src/item.h @@ -34,6 +34,7 @@ #include "visitable.h" class Character; +class Creature; class JsonIn; class JsonObject; class JsonOut; @@ -624,7 +625,7 @@ class item : public visitable * Calculate the item's effective damage per second past armor when wielded by a * character against a monster. */ - double effective_dps( const Character &guy, monster &mon ) const; + double effective_dps( const Character &guy, Creature &mon ) const; /** * calculate effective dps against a stock set of monsters. by default, assume g->u * is wielding diff --git a/src/magic.cpp b/src/magic.cpp index 5c00d08c538d5..f9ddd69fde511 100644 --- a/src/magic.cpp +++ b/src/magic.cpp @@ -8,6 +8,7 @@ #include #include +#include "avatar.h" #include "calendar.h" #include "cata_utility.h" #include "catacharset.h" @@ -33,14 +34,17 @@ #include "make_static.h" #include "magic_enchantment.h" #include "map.h" +#include "map_iterator.h" #include "messages.h" #include "mongroup.h" #include "monster.h" #include "mtype.h" #include "mutation.h" +#include "npc.h" #include "output.h" #include "pimpl.h" #include "point.h" +#include "projectile.h" #include "requirements.h" #include "rng.h" #include "sounds.h" @@ -565,6 +569,18 @@ int spell::min_leveled_damage() const return type->min_damage + std::round( get_level() * type->damage_increment ); } +float spell::dps( const Character &caster, const Creature & ) const +{ + if( type->effect_name != "attack" ) { + return 0.0f; + } + const float time_modifier = 100.0f / casting_time( caster ); + const float failure_modifier = 1.0f - spell_fail( caster ); + const float raw_dps = damage() + damage_dot() * duration_turns() / 1_turns; + // TODO: calculate true dps with armor and resistances and any caster bonuses + return raw_dps * time_modifier * failure_modifier; +} + int spell::damage() const { const int leveled_damage = min_leveled_damage(); @@ -679,6 +695,45 @@ int spell::range() const } } +std::vector spell::targetable_locations( const Character &source ) const +{ + + const tripoint char_pos = source.pos(); + const bool select_ground = is_valid_target( spell_target::ground ); + const bool ignore_walls = has_flag( spell_flag::NO_PROJECTILE ); + map &here = get_map(); + + // TODO: put this in a namespace for reuse + const auto has_obstruction = [&]( const tripoint & at ) { + for( const tripoint &line_point : line_to( char_pos, at ) ) { + if( here.impassable( line_point ) ) { + return true; + } + } + return false; + }; + + std::vector selectable_targets; + for( const tripoint &query : here.points_in_radius( char_pos, range() ) ) { + if( !ignore_walls && has_obstruction( query ) ) { + // it's blocked somewhere! + continue; + } + + if( !select_ground ) { + if( !source.sees( query ) ) { + // can't target a critter you can't see + continue; + } + } + + if( is_valid_target( source, query ) ) { + selectable_targets.push_back( query ); + } + } + return selectable_targets; +} + int spell::min_leveled_duration() const { return type->min_duration + std::round( get_level() * type->duration_increment ); @@ -792,14 +847,17 @@ bool spell::is_spell_class( const trait_id &mid ) const return mid == type->spell_class; } -bool spell::can_cast( Character &guy ) const +bool spell::can_cast( const Character &guy ) const { if( guy.has_trait_flag( STATIC( json_character_flag( "NO_SPELLCASTING" ) ) ) ) { return false; } + // only required because crafting_inventory always rebuilds the cache. maybe a const version doesn't write to cache. + Character &guy_inv = const_cast( guy ); + if( !type->spell_components.is_empty() && - !type->spell_components->can_make_with_inventory( guy.crafting_inventory( guy.pos(), 0 ), + !type->spell_components->can_make_with_inventory( guy_inv.crafting_inventory( guy.pos(), 0 ), return_true ) ) { return false; } @@ -1076,13 +1134,22 @@ void spell::create_field( const tripoint &at ) const } } -void spell::make_sound( const tripoint &target ) const +int spell::sound_volume() const { + int loudness = 0; if( !has_flag( spell_flag::SILENT ) ) { - int loudness = std::abs( damage() ) / 3; + loudness = std::abs( damage() ) / 3; if( has_flag( spell_flag::LOUD ) ) { loudness += 1 + damage() / 3; } + } + return loudness; +} + +void spell::make_sound( const tripoint &target ) const +{ + const int loudness = sound_volume(); + if( loudness > 0 ) { make_sound( target, loudness ); } } @@ -1307,6 +1374,23 @@ dealt_damage_instance spell::get_dealt_damage_instance() const return dmg; } +dealt_projectile_attack spell::get_projectile_attack( const tripoint &target, + Creature &hit_critter ) const +{ + projectile bolt; + bolt.speed = 10000; + bolt.impact = get_damage_instance(); + bolt.proj_effects.emplace( "magic" ); + + dealt_projectile_attack atk; + atk.end_point = target; + atk.hit_critter = &hit_critter; + atk.proj = bolt; + atk.missed_by = 0.0; + + return atk; +} + std::string spell::effect_data() const { return type->effect_str; diff --git a/src/magic.h b/src/magic.h index 9480ab9768a0d..fe4195a46d1b2 100644 --- a/src/magic.h +++ b/src/magic.h @@ -30,6 +30,7 @@ class JsonOut; class nc_color; class spell; class time_duration; +struct dealt_projectile_attack; struct requirement_data; namespace spell_effect @@ -441,7 +442,11 @@ class spell int damage_dot() const; damage_over_time_data damage_over_time( const std::vector &bps ) const; dealt_damage_instance get_dealt_damage_instance() const; + dealt_projectile_attack get_projectile_attack( const tripoint &target, + Creature &hit_critter ) const; damage_instance get_damage_instance() const; + // calculate damage per second against a target + float dps( const Character &caster, const Creature &target ) const; // how big is the spell's radius int aoe() const; std::set effect_area( const spell_effect::override_parameters ¶ms, @@ -449,6 +454,12 @@ class spell std::set effect_area( const tripoint &source, const tripoint &target ) const; // distance spell can be cast int range() const; + /** + * all of the tripoints the spell can be cast at. + * if the spell can't be cast through walls, does not return anything behind walls + * if the spell can't target the ground, can't target unseen locations, etc. + */ + std::vector targetable_locations( const Character &source ) const; // how much energy does the spell cost int energy_cost( const Character &guy ) const; // how long does this spell's effect last @@ -464,7 +475,7 @@ class spell const requirement_data &components() const; bool has_components() const; // can the Character cast this spell? - bool can_cast( Character &guy ) const; + bool can_cast( const Character &guy ) const; // can the Character learn this spell? bool can_learn( const Character &guy ) const; // is this spell valid @@ -525,6 +536,7 @@ class spell // tries to create a field at the location specified void create_field( const tripoint &at ) const; + int sound_volume() const; // makes a spell sound at the location void make_sound( const tripoint &target ) const; void make_sound( const tripoint &target, int loudness ) const; diff --git a/src/magic_spell_effect.cpp b/src/magic_spell_effect.cpp index c010c0cac8a8c..43978f1c511db 100644 --- a/src/magic_spell_effect.cpp +++ b/src/magic_spell_effect.cpp @@ -480,16 +480,7 @@ static void damage_targets( const spell &sp, Creature &caster, continue; } - projectile bolt; - bolt.speed = 10000; - bolt.impact = sp.get_damage_instance(); - bolt.proj_effects.emplace( "magic" ); - - dealt_projectile_attack atk; - atk.end_point = target; - atk.hit_critter = cr; - atk.proj = bolt; - atk.missed_by = 0.0; + dealt_projectile_attack atk = sp.get_projectile_attack( target, *cr ); if( !sp.effect_data().empty() ) { add_effect_to_target( target, sp ); } diff --git a/src/npc.cpp b/src/npc.cpp index f35b05d6d3434..3a397284ef590 100644 --- a/src/npc.cpp +++ b/src/npc.cpp @@ -2135,6 +2135,26 @@ bool npc::is_travelling() const Creature::Attitude npc::attitude_to( const Creature &other ) const { + const auto same_as = []( const Creature * lhs, const Creature * rhs ) { + return &lhs == &rhs; + }; + + for( const weak_ptr_fast &buddy : ai_cache.friends ) { + if( same_as( &other, buddy.lock().get() ) ) { + return Creature::Attitude::FRIENDLY; + } + } + for( const weak_ptr_fast &enemy : ai_cache.hostile_guys ) { + if( same_as( &other, enemy.lock().get() ) ) { + return Creature::Attitude::HOSTILE; + } + } + for( const weak_ptr_fast &neutral : ai_cache.neutral_guys ) { + if( same_as( &other, neutral.lock().get() ) ) { + return Creature::Attitude::NEUTRAL; + } + } + if( other.is_npc() || other.is_player() ) { const player &guy = dynamic_cast( other ); // check faction relationships first @@ -2632,6 +2652,11 @@ std::string npc_attitude_id( npc_attitude att ) return iter->second; } +int npc::closest_enemy_to_friendly_distance() const +{ + return ai_cache.closest_enemy_to_friendly_distance(); +} + std::string npc_attitude_name( npc_attitude att ) { switch( att ) { diff --git a/src/npc.h b/src/npc.h index f0a2abdc1e183..d082eb01409f9 100644 --- a/src/npc.h +++ b/src/npc.h @@ -573,11 +573,17 @@ struct npc_short_term_cache { double my_weapon_value = 0; // Use weak_ptr to avoid circular references between Creatures + // attitude of creatures the npc can see + std::vector> hostile_guys; + std::vector> neutral_guys; std::vector> friends; std::vector dangerous_explosives; std::map threat_map; // Cache of locations the NPC has searched recently in npc::find_item() lru_cache searched_tiles; + // returns the value of the distance between a friendly creature and the closest enemy to that friendly creature. + // returns -1 if not applicable + int closest_enemy_to_friendly_distance() const; }; // DO NOT USE! This is old, use strings as talk topic instead, e.g. "TALK_AGREE_FOLLOW" instead of @@ -766,6 +772,12 @@ class npc : public player bool is_npc() const override { return true; } + const npc *as_npc() override { + return this; + } + const npc *as_npc() const override { + return this; + } void load_npc_template( const string_id &ident ); void npc_dismount(); weak_ptr_fast chosen_mount; @@ -1239,6 +1251,9 @@ class npc : public player std::vector miss_ids; cata::optional assigned_camp = cata::nullopt; + // accessors to ai_cache functions + int closest_enemy_to_friendly_distance() const; + private: npc_attitude attitude = NPCATT_NULL; // What we want to do to the player npc_attitude previous_attitude = NPCATT_NULL; diff --git a/src/npcmove.cpp b/src/npcmove.cpp index 1134c0e69c436..1a47a3e300a11 100644 --- a/src/npcmove.cpp +++ b/src/npcmove.cpp @@ -371,6 +371,23 @@ static bool too_close( const tripoint &critter_pos, const tripoint &ally_pos, co return rl_dist( critter_pos, ally_pos ) <= def_radius; } +int npc_short_term_cache::closest_enemy_to_friendly_distance() const +{ + int distance = INT_MAX; + for( const weak_ptr_fast &buddy : friends ) { + if( buddy.expired() ) { + continue; + } + for( const weak_ptr_fast &enemy : hostile_guys ) { + if( enemy.expired() ) { + continue; + } + distance = std::min( distance, rl_dist( buddy.lock()->pos(), enemy.lock()->pos() ) ); + } + } + return distance; +} + void npc::assess_danger() { float assessment = 0.0f; @@ -454,7 +471,6 @@ void npc::assess_danger() } // find our Character friends and enemies - std::vector> hostile_guys; const bool clairvoyant = clairvoyance(); for( const npc &guy : g->all_npcs() ) { if( &guy == this ) { @@ -467,12 +483,12 @@ void npc::assess_danger() if( has_faction_relationship( guy, npc_factions::watch_your_back ) ) { ai_cache.friends.emplace_back( g->shared_from( guy ) ); } else if( attitude_to( guy ) != Attitude::NEUTRAL && sees( guy.pos() ) ) { - hostile_guys.emplace_back( g->shared_from( guy ) ); + ai_cache.hostile_guys.emplace_back( g->shared_from( guy ) ); } } if( sees( player_character.pos() ) ) { if( is_enemy() ) { - hostile_guys.emplace_back( g->shared_from( player_character ) ); + ai_cache.hostile_guys.emplace_back( g->shared_from( player_character ) ); } else if( is_friendly( player_character ) ) { ai_cache.friends.emplace_back( g->shared_from( player_character ) ); } @@ -488,11 +504,14 @@ void npc::assess_danger() continue; } if( att != Attitude::HOSTILE && ( critter.friendly || !is_enemy() ) ) { + ai_cache.neutral_guys.emplace_back( g->shared_from( critter ) ); continue; } if( !sees( critter ) ) { continue; } + + ai_cache.hostile_guys.emplace_back( g->shared_from( critter ) ); float critter_threat = evaluate_enemy( critter ); // warn and consider the odds for distant enemies int dist = rl_dist( pos(), critter.pos() ); @@ -548,7 +567,7 @@ void npc::assess_danger() } } - if( assessment == 0.0 && hostile_guys.empty() ) { + if( assessment == 0.0 && ai_cache.hostile_guys.empty() ) { ai_cache.danger_assessment = assessment; return; } @@ -594,7 +613,7 @@ void npc::assess_danger() return foe_threat; }; - for( const weak_ptr_fast &guy : hostile_guys ) { + for( const weak_ptr_fast &guy : ai_cache.hostile_guys ) { player *foe = dynamic_cast( guy.lock().get() ); if( foe && foe->is_npc() ) { assessment += handle_hostile( *foe, evaluate_enemy( *foe ), translate_marker( "bandit" ), @@ -603,11 +622,10 @@ void npc::assess_danger() } for( const weak_ptr_fast &guy : ai_cache.friends ) { - player *ally = dynamic_cast( guy.lock().get() ); - if( !( ally && ally->is_npc() ) ) { + if( !( guy.lock() && guy.lock()->is_npc() ) ) { continue; } - float guy_threat = evaluate_enemy( *ally ); + float guy_threat = evaluate_enemy( *guy.lock() ); float min_danger = assessment >= NPC_DANGER_VERY_LOW ? NPC_DANGER_VERY_LOW : -10.0f; assessment = std::max( min_danger, assessment - guy_threat * 0.5f ); } @@ -702,6 +720,8 @@ void npc::regen_ai_cache() } float old_assessment = ai_cache.danger_assessment; ai_cache.friends.clear(); + ai_cache.hostile_guys.clear(); + ai_cache.neutral_guys.clear(); ai_cache.target = shared_ptr_fast(); ai_cache.ally = shared_ptr_fast(); ai_cache.can_heal.clear_all(); diff --git a/src/ranged.cpp b/src/ranged.cpp index a6da99c1a2153..aface68e45d3d 100644 --- a/src/ranged.cpp +++ b/src/ranged.cpp @@ -113,6 +113,8 @@ static const std::string flag_MOUNTABLE( "MOUNTABLE" ); static const trait_id trait_PYROMANIA( "PYROMANIA" ); +static const std::set ferric = { material_id( "iron" ), material_id( "steel" ) }; + // Maximum duration of aim-and-fire loop, in turns static constexpr int AIF_DURATION_LIMIT = 10; @@ -962,64 +964,112 @@ int Character::throwing_dispersion( const item &to_throw, Creature *critter, return std::max( 0, dispersion ); } -dealt_projectile_attack player::throw_item( const tripoint &target, const item &to_throw, - const cata::optional &blind_throw_from_pos ) +static cata::optional character_throw_assist( const Character &guy ) { - // Copy the item, we may alter it before throwing - item thrown = to_throw; - - const int move_cost = throw_cost( *this, to_throw ); - mod_moves( -move_cost ); - - const int throwing_skill = get_skill_level( skill_throw ); - units::volume volume = to_throw.volume(); - units::mass weight = to_throw.weight(); - - bool throw_assist = false; - int throw_assist_str = 0; - if( is_mounted() ) { - auto *mons = mounted_creature.get(); + cata::optional throw_assist = cata::nullopt; + if( guy.is_mounted() ) { + auto *mons = guy.mounted_creature.get(); if( mons->mech_str_addition() != 0 ) { - throw_assist = true; - throw_assist_str = mons->mech_str_addition(); + throw_assist = mons->mech_str_addition(); mons->use_mech_power( -3 ); } } - if( !throw_assist ) { - const int stamina_cost = get_standard_stamina_cost( &thrown ); - mod_stamina( stamina_cost + throwing_skill ); - } + return throw_assist; +} - const skill_id &skill_used = skill_throw; - int skill_level = std::min( MAX_SKILL, get_skill_level( skill_throw ) ); +static int throwing_skill_adjusted( const Character &guy ) +{ + int skill_level = std::min( MAX_SKILL, guy.get_skill_level( skill_throw ) ); // if you are lying on the floor, you can't really throw that well - if( has_effect( effect_downed ) ) { + if( guy.has_effect( effect_downed ) ) { skill_level = std::max( 0, skill_level - 5 ); } - // We'll be constructing a projectile - projectile proj; - proj.impact = thrown.base_damage_thrown(); - proj.speed = 10 + skill_level; - auto &impact = proj.impact; - auto &proj_effects = proj.proj_effects; - - static const std::set ferric = { material_id( "iron" ), material_id( "steel" ) }; + return skill_level; +} - bool do_railgun = has_active_bionic( bio_railgun ) && thrown.made_of_any( ferric ) && - !throw_assist; +int Character::thrown_item_adjusted_damage( const item &thrown ) const +{ + const cata::optional throw_assist = character_throw_assist( *this ); + const bool do_railgun = has_active_bionic( bio_railgun ) && thrown.made_of_any( ferric ) && + !throw_assist; // The damage dealt due to item's weight, player's strength, and skill level // Up to str/2 or weight/100g (lower), so 10 str is 5 damage before multipliers // Railgun doubles the effective strength ///\EFFECT_STR increases throwing damage double stats_mod = do_railgun ? get_str() : ( get_str() / 2.0 ); - stats_mod = throw_assist ? throw_assist_str / 2.0 : stats_mod; + stats_mod = throw_assist ? *throw_assist / 2.0 : stats_mod; // modify strength impact based on skill level, clamped to [0.15 - 1] // mod = mod * [ ( ( skill / max_skill ) * 0.85 ) + 0.15 ] stats_mod *= ( std::min( MAX_SKILL, get_skill_level( skill_throw ) ) / static_cast( MAX_SKILL ) ) * 0.85 + 0.15; - impact.add_damage( damage_type::BASH, std::min( weight / 100.0_gram, stats_mod ) ); + return stats_mod; +} + +projectile Character::thrown_item_projectile( const item &thrown ) const +{ + // We'll be constructing a projectile + projectile proj; + proj.impact = thrown.base_damage_thrown(); + proj.speed = 10 + throwing_skill_adjusted( *this ); + return proj; +} + +int Character::thrown_item_total_damage_raw( const item &thrown ) const +{ + projectile proj = thrown_item_projectile( thrown ); + const units::volume volume = thrown.volume(); + proj.impact.add_damage( damage_type::BASH, std::min( thrown.weight() / 100.0_gram, + static_cast( thrown_item_adjusted_damage( thrown ) ) ) ); + // Item will shatter upon landing, destroying the item, dealing damage, and making noise + if( !thrown.active && thrown.made_of( material_id( "glass" ) ) && + rng( 0, units::to_milliliter( 2_liter - volume ) ) < get_str() * 100 ) { + proj.impact.add_damage( damage_type::CUT, units::to_milliliter( volume ) / 500.0f ); + } + // Some minor (skill/2) armor piercing for skillful throws + // Not as much as in melee, though + const int skill_level = throwing_skill_adjusted( *this ); + for( damage_unit &du : proj.impact.damage_units ) { + du.res_pen += skill_level / 2.0f; + } + + int total_damage = 0; + for( damage_unit &du : proj.impact.damage_units ) { + total_damage += du.amount * du.damage_multiplier; + } + return total_damage; +} + +dealt_projectile_attack player::throw_item( const tripoint &target, const item &to_throw, + const cata::optional &blind_throw_from_pos ) +{ + // Copy the item, we may alter it before throwing + item thrown = to_throw; + + const int move_cost = throw_cost( *this, to_throw ); + mod_moves( -move_cost ); + + const int throwing_skill = get_skill_level( skill_throw ); + const units::volume volume = to_throw.volume(); + const units::mass weight = to_throw.weight(); + const cata::optional throw_assist = character_throw_assist( *this ); + + if( !throw_assist ) { + const int stamina_cost = get_standard_stamina_cost( &thrown ); + mod_stamina( stamina_cost + throwing_skill ); + } + + const int skill_level = throwing_skill_adjusted( *this ); + projectile proj = thrown_item_projectile( thrown ); + damage_instance &impact = proj.impact; + std::set &proj_effects = proj.proj_effects; + + const bool do_railgun = has_active_bionic( bio_railgun ) && thrown.made_of_any( ferric ) && + !throw_assist; + + impact.add_damage( damage_type::BASH, std::min( weight / 100.0_gram, + static_cast( thrown_item_adjusted_damage( thrown ) ) ) ); if( thrown.has_flag( flag_ACT_ON_RANGED_HIT ) ) { proj_effects.insert( "ACT_ON_RANGED_HIT" ); @@ -1096,7 +1146,7 @@ dealt_projectile_attack player::throw_item( const tripoint &target, const item & float range = rl_dist( throw_from, target ); proj.range = range; - int skill_lvl = get_skill_level( skill_used ); + int skill_lvl = get_skill_level( skill_throw ); // Avoid awarding tons of xp for lucky throws against hard to hit targets const float range_factor = std::min( range, skill_lvl + 3 ); // We're aiming to get a damaging hit, not just an accurate one - reward proper weapons @@ -1109,14 +1159,14 @@ dealt_projectile_attack player::throw_item( const tripoint &target, const item & const double missed_by = dealt_attack.missed_by; if( missed_by <= 0.1 && dealt_attack.hit_critter != nullptr ) { - practice( skill_used, final_xp_mult, MAX_SKILL ); + practice( skill_throw, final_xp_mult, MAX_SKILL ); // TODO: Check target for existence of head get_event_bus().send( getID() ); } else if( dealt_attack.hit_critter != nullptr && missed_by > 0.0f ) { - practice( skill_used, final_xp_mult / ( 1.0f + missed_by ), MAX_SKILL ); + practice( skill_throw, final_xp_mult / ( 1.0f + missed_by ), MAX_SKILL ); } else { // Pure grindy practice - cap gain at lvl 2 - practice( skill_used, 5, 2 ); + practice( skill_throw, 5, 2 ); } // Reset last target pos last_target_pos = cata::nullopt; diff --git a/tests/player_helpers.cpp b/tests/player_helpers.cpp index 6658c7490792f..58dc5de7b4914 100644 --- a/tests/player_helpers.cpp +++ b/tests/player_helpers.cpp @@ -116,6 +116,52 @@ void clear_character( player &dummy ) dummy.setpos( spot ); } +void arm_shooter( npc &shooter, const std::string &gun_type, + const std::vector &mods, + const std::string &ammo_type ) +{ + shooter.remove_weapon(); + // XL so arrows can fit. + if( !shooter.is_wearing( itype_id( "debug_backpack" ) ) ) { + shooter.worn.push_back( item( "debug_backpack" ) ); + } + + const itype_id &gun_id{ itype_id( gun_type ) }; + // Give shooter a loaded gun of the requested type. + item &gun = shooter.i_add( item( gun_id ) ); + itype_id ammo_id; + // if ammo is not supplied we want the default + if( ammo_type.empty() ) { + if( gun.ammo_default().is_null() ) { + ammo_id = item( gun.magazine_default() ).ammo_default(); + } else { + ammo_id = gun.ammo_default(); + } + } else { + ammo_id = itype_id( ammo_type ); + } + const ammotype &type_of_ammo = item::find_type( ammo_id )->ammo->type; + if( gun.magazine_integral() ) { + item &ammo = shooter.i_add( item( ammo_id, calendar::turn, gun.ammo_capacity( type_of_ammo ) ) ); + REQUIRE( gun.is_reloadable_with( ammo_id ) ); + REQUIRE( shooter.can_reload( gun, ammo_id ) ); + gun.reload( shooter, item_location( shooter, &ammo ), gun.ammo_capacity( type_of_ammo ) ); + } else { + const itype_id magazine_id = gun.magazine_default(); + item &magazine = shooter.i_add( item( magazine_id ) ); + item &ammo = shooter.i_add( item( ammo_id, calendar::turn, + magazine.ammo_capacity( type_of_ammo ) ) ); + REQUIRE( magazine.is_reloadable_with( ammo_id ) ); + REQUIRE( shooter.can_reload( magazine, ammo_id ) ); + magazine.reload( shooter, item_location( shooter, &ammo ), magazine.ammo_capacity( type_of_ammo ) ); + gun.reload( shooter, item_location( shooter, &magazine ), magazine.ammo_capacity( type_of_ammo ) ); + } + for( const auto &mod : mods ) { + gun.put_in( item( itype_id( mod ) ), item_pocket::pocket_type::MOD ); + } + shooter.wield( gun ); +} + void clear_avatar() { clear_character( get_avatar() ); diff --git a/tests/player_helpers.h b/tests/player_helpers.h index df2fecc801109..59e79903a0737 100644 --- a/tests/player_helpers.h +++ b/tests/player_helpers.h @@ -21,4 +21,8 @@ void give_and_activate_bionic( player &, bionic_id const & ); item tool_with_ammo( const std::string &tool, int qty ); +void arm_shooter( npc &shooter, const std::string &gun_type, + const std::vector &mods = {}, + const std::string &ammo_type = "" ); + #endif // CATA_TESTS_PLAYER_HELPERS_H diff --git a/tests/ranged_balance_test.cpp b/tests/ranged_balance_test.cpp index 32c3e64d6294e..40997377ae042 100644 --- a/tests/ranged_balance_test.cpp +++ b/tests/ranged_balance_test.cpp @@ -24,6 +24,7 @@ #include "map_helpers.h" #include "npc.h" #include "pimpl.h" +#include "player_helpers.h" #include "point.h" #include "ret_val.h" #include "test_statistics.h" @@ -76,52 +77,6 @@ std::ostream &operator<<( std::ostream &stream, const dispersion_sources &source return stream; } -static void arm_shooter( npc &shooter, const std::string &gun_type, - const std::vector &mods = {}, - const std::string &ammo_type = "" ) -{ - shooter.remove_weapon(); - // XL so arrows can fit. - if( !shooter.is_wearing( itype_id( "debug_backpack" ) ) ) { - shooter.worn.push_back( item( "debug_backpack" ) ); - } - - const itype_id &gun_id{ itype_id( gun_type ) }; - // Give shooter a loaded gun of the requested type. - item &gun = shooter.i_add( item( gun_id ) ); - itype_id ammo_id; - // if ammo is not supplied we want the default - if( ammo_type.empty() ) { - if( gun.ammo_default().is_null() ) { - ammo_id = item( gun.magazine_default() ).ammo_default(); - } else { - ammo_id = gun.ammo_default(); - } - } else { - ammo_id = itype_id( ammo_type ); - } - const ammotype &type_of_ammo = item::find_type( ammo_id )->ammo->type; - if( gun.magazine_integral() ) { - item &ammo = shooter.i_add( item( ammo_id, calendar::turn, gun.ammo_capacity( type_of_ammo ) ) ); - REQUIRE( gun.is_reloadable_with( ammo_id ) ); - REQUIRE( shooter.can_reload( gun, ammo_id ) ); - gun.reload( shooter, item_location( shooter, &ammo ), gun.ammo_capacity( type_of_ammo ) ); - } else { - const itype_id magazine_id = gun.magazine_default(); - item &magazine = shooter.i_add( item( magazine_id ) ); - item &ammo = shooter.i_add( item( ammo_id, calendar::turn, - magazine.ammo_capacity( type_of_ammo ) ) ); - REQUIRE( magazine.is_reloadable_with( ammo_id ) ); - REQUIRE( shooter.can_reload( magazine, ammo_id ) ); - magazine.reload( shooter, item_location( shooter, &ammo ), magazine.ammo_capacity( type_of_ammo ) ); - gun.reload( shooter, item_location( shooter, &magazine ), magazine.ammo_capacity( type_of_ammo ) ); - } - for( const auto &mod : mods ) { - gun.put_in( item( itype_id( mod ) ), item_pocket::pocket_type::MOD ); - } - shooter.wield( gun ); -} - static void equip_shooter( npc &shooter, const std::vector &apparel ) { CHECK( !shooter.in_vehicle ); From a1fc49f1fec1f6b6c4b34b7cbf21c8f8b69066dc Mon Sep 17 00:00:00 2001 From: NeviNovat <51816321+NeviNovat@users.noreply.github.com> Date: Tue, 23 Feb 2021 09:54:12 +0200 Subject: [PATCH 018/453] Make acetylene torch cut metal walls. (#46255) --- src/activity_handlers.cpp | 4 ++++ src/iuse.cpp | 8 +++++--- src/mapdata.cpp | 4 ++++ src/mapdata.h | 2 ++ 4 files changed, 15 insertions(+), 3 deletions(-) diff --git a/src/activity_handlers.cpp b/src/activity_handlers.cpp index 07b87fc21484a..8deb436a90773 100644 --- a/src/activity_handlers.cpp +++ b/src/activity_handlers.cpp @@ -2299,6 +2299,10 @@ void activity_handlers::oxytorch_finish( player_activity *act, player *p ) here.ter_set( pos, t_mdoor_frame ); here.spawn_item( pos, itype_steel_plate, rng( 0, 1 ) ); here.spawn_item( pos, itype_steel_chunk, rng( 3, 8 ) ); + } else if( ter == t_wall_metal ) { + here.ter_set( pos, t_scrap_wall_halfway ); + here.spawn_item( pos, itype_steel_plate, rng( 2, 3 ) ); + here.spawn_item( pos, itype_steel_chunk, rng( 12, 20 ) ); } else if( ter == t_window_enhanced || ter == t_window_enhanced_noglass ) { here.ter_set( pos, t_window_empty ); here.spawn_item( pos, itype_steel_plate, rng( 0, 1 ) ); diff --git a/src/iuse.cpp b/src/iuse.cpp index 78c776a6a4c84..c22039c0af03b 100644 --- a/src/iuse.cpp +++ b/src/iuse.cpp @@ -5015,7 +5015,8 @@ cata::optional iuse::oxytorch( player *p, item *it, bool, const tripoint & t_metal_grate_window_with_curtain_open, t_metal_grate_window_noglass, t_metal_grate_window_with_curtain_noglass, - t_metal_grate_window_with_curtain_open_noglass + t_metal_grate_window_with_curtain_open_noglass, + t_wall_metal }; const std::set allowed_furn_id { f_rack, @@ -5070,8 +5071,9 @@ cata::optional iuse::oxytorch( player *p, item *it, bool, const tripoint & ter == t_metal_grate_window_with_curtain_open_noglass ) { turns = to_turns( 10_seconds ); } else if( ter == t_door_metal_locked || ter == t_door_metal_c || ter == t_door_bar_c || - ter == t_door_bar_locked || ter == t_door_metal_pickable || furn == f_safe_l || - furn == f_gunsafe_ml || furn == f_gunsafe_mj || furn == f_gun_safe_el ) { + ter == t_door_bar_locked || ter == t_door_metal_pickable || ter == t_wall_metal || + furn == f_safe_l || furn == f_gunsafe_ml || furn == f_gunsafe_mj || + furn == f_gun_safe_el ) { turns = to_turns( 15_seconds ); } else { return cata::nullopt; diff --git a/src/mapdata.cpp b/src/mapdata.cpp index 8a22701bbcc0e..75431e198f9a5 100644 --- a/src/mapdata.cpp +++ b/src/mapdata.cpp @@ -551,6 +551,8 @@ ter_id t_null, t_wall_half, t_wall_wood, t_wall_wood_chipped, t_wall_wood_broken, t_wall, t_concrete_wall, t_brick_wall, t_wall_metal, + t_scrap_wall, + t_scrap_wall_halfway, t_wall_glass, t_wall_glass_alarm, t_reinforced_glass, t_reinforced_glass_shutter, t_reinforced_glass_shutter_open, @@ -707,6 +709,8 @@ void set_ter_ids() t_concrete_wall = ter_id( "t_concrete_wall" ); t_brick_wall = ter_id( "t_brick_wall" ); t_wall_metal = ter_id( "t_wall_metal" ); + t_scrap_wall = ter_id( "t_scrap_wall" ); + t_scrap_wall_halfway = ter_id( "t_scrap_wall_halfway" ); t_wall_glass = ter_id( "t_wall_glass" ); t_wall_glass_alarm = ter_id( "t_wall_glass_alarm" ); t_reinforced_glass = ter_id( "t_reinforced_glass" ); diff --git a/src/mapdata.h b/src/mapdata.h index ec365bfa3140d..cc1457c5fd52c 100644 --- a/src/mapdata.h +++ b/src/mapdata.h @@ -466,6 +466,8 @@ extern ter_id t_null, t_wall_half, t_wall_wood, t_wall_wood_chipped, t_wall_wood_broken, t_wall, t_concrete_wall, t_brick_wall, t_wall_metal, + t_scrap_wall, + t_scrap_wall_halfway, t_wall_glass, t_wall_glass_alarm, t_reinforced_glass, t_reinforced_glass_shutter, t_reinforced_glass_shutter_open, From a2050d705443a20f2e9f5b97be4e364be8dc67ff Mon Sep 17 00:00:00 2001 From: Karol1223 <68503002+Karol1223@users.noreply.github.com> Date: Tue, 23 Feb 2021 08:55:42 +0100 Subject: [PATCH 019/453] Added disassembly recipes for several items (#46316) --- data/json/recipes/recipe_deconstruction.json | 167 +++++++++++++++++++ 1 file changed, 167 insertions(+) diff --git a/data/json/recipes/recipe_deconstruction.json b/data/json/recipes/recipe_deconstruction.json index e1839c50960f2..43b395ca54024 100644 --- a/data/json/recipes/recipe_deconstruction.json +++ b/data/json/recipes/recipe_deconstruction.json @@ -5025,5 +5025,172 @@ "time": "5 m", "qualities": [ { "id": "HAMMER", "level": 1 } ], "components": [ [ [ "material_rocksalt", 10 ] ] ] + }, + { + "result": "knife_butter", + "type": "uncraft", + "activity_level": "MODERATE_EXERCISE", + "time": "12 s", + "qualities": [ { "id": "HAMMER", "level": 1 } ], + "components": [ [ [ "scrap", 1 ] ] ] + }, + { + "result": "flask_hip", + "type": "uncraft", + "activity_level": "MODERATE_EXERCISE", + "time": "12 s", + "qualities": [ { "id": "HAMMER", "level": 1 } ], + "components": [ [ [ "scrap", 2 ] ] ] + }, + { + "result": "clamp", + "type": "uncraft", + "activity_level": "MODERATE_EXERCISE", + "time": "1 m", + "qualities": [ { "id": "HAMMER", "level": 1 }, { "id": "SAW_M", "level": 1 } ], + "components": [ [ [ "scrap", 6 ] ] ] + }, + { + "result": "e_tool", + "type": "uncraft", + "activity_level": "MODERATE_EXERCISE", + "time": "2 m", + "qualities": [ { "id": "SAW_M", "level": 1 } ], + "components": [ [ [ "sheet_metal_small", 2 ] ], [ [ "scrap", 2 ] ] ] + }, + { + "result": "harmonica_holder", + "type": "uncraft", + "activity_level": "MODERATE_EXERCISE", + "time": "12 s", + "qualities": [ { "id": "HAMMER", "level": 1 } ], + "components": [ [ [ "scrap", 2 ] ] ] + }, + { + "result": "coin_quarter", + "type": "uncraft", + "activity_level": "MODERATE_EXERCISE", + "time": "2 s", + "qualities": [ { "id": "HAMMER", "level": 1 } ], + "components": [ [ [ "silver_small", 5 ] ] ] + }, + { + "result": "coin_nickel", + "type": "uncraft", + "activity_level": "MODERATE_EXERCISE", + "time": "2 s", + "qualities": [ { "id": "HAMMER", "level": 1 } ], + "components": [ [ [ "copper", 5 ] ] ] + }, + { + "result": "spray_can", + "type": "uncraft", + "activity_level": "MODERATE_EXERCISE", + "time": "2 m", + "qualities": [ { "id": "SAW_M", "level": 1 } ], + "components": [ [ [ "sheet_metal_small", 1 ] ], [ [ "scrap", 1 ] ] ] + }, + { + "result": "can_medium", + "type": "uncraft", + "activity_level": "MODERATE_EXERCISE", + "time": "12 s", + "qualities": [ { "id": "HAMMER", "level": 1 } ], + "components": [ [ [ "scrap", 1 ] ] ] + }, + { + "result": "can_food_big", + "type": "uncraft", + "activity_level": "MODERATE_EXERCISE", + "time": "1 m", + "qualities": [ { "id": "SAW_M", "level": 1 } ], + "components": [ [ [ "sheet_metal_small", 2 ] ], [ [ "scrap", 3 ] ] ] + }, + { + "result": "multitool", + "type": "uncraft", + "activity_level": "MODERATE_EXERCISE", + "time": "40 s", + "qualities": [ { "id": "HAMMER", "level": 1 }, { "id": "SCREW", "level": 1 } ], + "components": [ [ [ "scrap", 3 ] ] ] + }, + { + "result": "thermos", + "type": "uncraft", + "activity_level": "MODERATE_EXERCISE", + "time": "2 m", + "qualities": [ { "id": "SAW_M", "level": 1 } ], + "components": [ [ [ "sheet_metal_small", 2 ] ] ] + }, + { + "result": "scissors", + "type": "uncraft", + "activity_level": "MODERATE_EXERCISE", + "time": "12 s", + "qualities": [ { "id": "HAMMER", "level": 1 } ], + "components": [ [ [ "scrap", 2 ] ] ] + }, + { + "result": "shavingkit", + "type": "uncraft", + "activity_level": "MODERATE_EXERCISE", + "time": "12 s", + "qualities": [ { "id": "HAMMER", "level": 1 } ], + "components": [ [ [ "plastic_chunk", 2 ] ] ] + }, + { + "result": "hammer", + "type": "uncraft", + "activity_level": "MODERATE_EXERCISE", + "time": "30 s", + "qualities": [ { "id": "HAMMER", "level": 1 } ], + "components": [ [ [ "splinter", 1 ] ], [ [ "steel_chunk", 2 ] ] ] + }, + { + "result": "tongs", + "type": "uncraft", + "activity_level": "MODERATE_EXERCISE", + "time": "2 m", + "qualities": [ { "id": "HAMMER", "level": 1 }, { "id": "SAW_M", "level": 1 } ], + "components": [ [ [ "steel_chunk", 2 ] ] ] + }, + { + "result": "umbrella", + "type": "uncraft", + "activity_level": "MODERATE_EXERCISE", + "time": "1 m", + "qualities": [ { "id": "CUT", "level": 1 } ], + "components": [ [ [ "plastic_chunk", 2 ] ] ] + }, + { + "result": "mask_dust", + "type": "uncraft", + "activity_level": "LIGHT_EXERCISE", + "time": "12 s", + "components": [ [ [ "string_6", 1 ] ], [ [ "rag", 1 ] ] ] + }, + { + "result": "horn_bicycle", + "type": "uncraft", + "activity_level": "MODERATE_EXERCISE", + "time": "12 s", + "qualities": [ { "id": "CUT", "level": 1 } ], + "components": [ [ [ "plastic_chunk", 3 ] ] ] + }, + { + "result": "cards_magic", + "type": "uncraft", + "activity_level": "NO_EXERCISE", + "time": "2 s", + "components": [ [ [ "paper", 20 ] ] ], + "flags": [ "BLIND_EASY" ] + }, + { + "result": "webbing_belt", + "type": "uncraft", + "activity_level": "LIGHT_EXERCISE", + "time": "30 s", + "qualities": [ { "id": "CUT", "level": 1 } ], + "components": [ [ [ "nylon", 3 ] ], [ [ "scrap", 1 ] ] ] } ] From 59202643ae54927fba448f4556a4f94053af1935 Mon Sep 17 00:00:00 2001 From: Hirmuolio <22011552+Hirmuolio@users.noreply.github.com> Date: Tue, 23 Feb 2021 09:57:15 +0200 Subject: [PATCH 020/453] Celsius temperature for freezing point (#47028) --- data/json/items/chemicals_and_resources.json | 8 +- data/json/items/classes/comestible.json | 2 +- data/json/items/comestibles/alcohol.json | 94 +++++++++---------- data/json/items/comestibles/drink.json | 2 +- data/json/items/comestibles/drink_other.json | 10 +- data/json/items/comestibles/egg.json | 2 +- data/json/items/comestibles/junkfood.json | 2 +- data/json/items/comestibles/med.json | 2 +- data/json/items/comestibles/mutagen.json | 2 +- data/json/items/comestibles/nuts.json | 2 +- data/json/items/comestibles/other.json | 18 ++-- data/json/items/comestibles/protein.json | 2 +- data/json/items/comestibles/seed.json | 2 +- data/json/items/comestibles/spice.json | 4 +- data/mods/Magiclysm/items/alchemy_items.json | 2 +- .../Magiclysm/items/cast_spell_items.json | 6 +- data/mods/Magiclysm/items/mutagen.json | 2 +- data/mods/TEST_DATA/items.json | 2 +- doc/JSON_INFO.md | 4 +- src/cata_utility.cpp | 5 + src/cata_utility.h | 7 ++ src/item.cpp | 10 +- src/item.h | 2 +- src/itype.h | 4 +- src/material.cpp | 4 +- src/material.h | 4 +- 26 files changed, 108 insertions(+), 96 deletions(-) diff --git a/data/json/items/chemicals_and_resources.json b/data/json/items/chemicals_and_resources.json index 02431bc4db41e..5608d816e56a5 100644 --- a/data/json/items/chemicals_and_resources.json +++ b/data/json/items/chemicals_and_resources.json @@ -224,7 +224,7 @@ "charges": 2, "category": "chems", "fun": -30, - "freezing_point": 17, + "freezing_point": -8, "conditional_names": [ { "type": "FLAG", "condition": "DIRTY", "name": "bleach spill" } ] }, { @@ -248,7 +248,7 @@ "charges": 2, "category": "chems", "fun": -30, - "freezing_point": -108 + "freezing_point": -78 }, { "type": "COMESTIBLE", @@ -365,7 +365,7 @@ "volume": "250 ml", "phase": "liquid", "category": "chems", - "freezing_point": 28, + "freezing_point": -2, "fun": -1 }, { @@ -386,7 +386,7 @@ "volume": "250 ml", "phase": "liquid", "category": "chems", - "freezing_point": 28, + "freezing_point": -2, "fun": -1 }, { diff --git a/data/json/items/classes/comestible.json b/data/json/items/classes/comestible.json index 7bf287864d6b2..f7401bdd4c5e7 100644 --- a/data/json/items/classes/comestible.json +++ b/data/json/items/classes/comestible.json @@ -13,6 +13,6 @@ "material": [ "powder" ], "symbol": "%", "charges": 100, - "freezing_point": -459 + "freezing_point": -274 } ] diff --git a/data/json/items/comestibles/alcohol.json b/data/json/items/comestibles/alcohol.json index f1ae939e677a8..6616bfec72467 100644 --- a/data/json/items/comestibles/alcohol.json +++ b/data/json/items/comestibles/alcohol.json @@ -24,7 +24,7 @@ "charges": 5, "flags": [ "EATEN_COLD", "MYCUS_OK" ], "fun": 25, - "freezing_point": 17 + "freezing_point": -8 }, { "type": "COMESTIBLE", @@ -52,7 +52,7 @@ "charges": 5, "flags": [ "EATEN_COLD" ], "fun": 15, - "freezing_point": 17 + "freezing_point": -8 }, { "type": "COMESTIBLE", @@ -80,7 +80,7 @@ "charges": 5, "flags": [ "EATEN_COLD" ], "fun": 15, - "freezing_point": 17 + "freezing_point": -8 }, { "type": "COMESTIBLE", @@ -106,7 +106,7 @@ "phase": "liquid", "charges": 5, "fun": 15, - "freezing_point": 17 + "freezing_point": -8 }, { "type": "COMESTIBLE", @@ -133,7 +133,7 @@ "charges": 5, "flags": [ "EATEN_COLD" ], "fun": 16, - "freezing_point": 15 + "freezing_point": -9 }, { "type": "COMESTIBLE", @@ -160,7 +160,7 @@ "charges": 5, "flags": [ "EATEN_COLD" ], "fun": 15, - "freezing_point": 17 + "freezing_point": -8 }, { "type": "COMESTIBLE", @@ -187,7 +187,7 @@ "charges": 5, "flags": [ "EATEN_COLD" ], "fun": 15, - "freezing_point": 17 + "freezing_point": -8 }, { "type": "COMESTIBLE", @@ -213,7 +213,7 @@ "volume": "250 ml", "phase": "liquid", "flags": [ "EATEN_COLD" ], - "freezing_point": 23, + "freezing_point": -5, "fun": 14, "vitamins": [ [ "calcium", 1 ] ] }, @@ -240,7 +240,7 @@ "material": [ "alcohol" ], "volume": "250 ml", "flags": [ "EATEN_COLD" ], - "freezing_point": -22, + "freezing_point": -30, "phase": "liquid", "charges": 7, "fun": 15 @@ -269,7 +269,7 @@ "phase": "liquid", "charges": 7, "flags": [ "EATEN_COLD", "NUTRIENT_OVERRIDE" ], - "freezing_point": -22, + "freezing_point": -30, "fun": 15 }, { @@ -296,7 +296,7 @@ "phase": "liquid", "charges": 7, "flags": [ "EATEN_COLD" ], - "freezing_point": -22, + "freezing_point": -30, "fun": 15 }, { @@ -324,7 +324,7 @@ "charges": 7, "fun": 15, "flags": [ "EATEN_COLD" ], - "freezing_point": -22 + "freezing_point": -30 }, { "type": "COMESTIBLE", @@ -351,7 +351,7 @@ "charges": 7, "fun": 18, "flags": [ "EATEN_COLD" ], - "freezing_point": -22 + "freezing_point": -30 }, { "type": "COMESTIBLE", @@ -375,7 +375,7 @@ "material": [ "alcohol" ], "volume": "250 ml", "flags": [ "EDIBLE_FROZEN" ], - "freezing_point": 0, + "freezing_point": -17, "phase": "liquid", "charges": 7, "fun": 10 @@ -407,7 +407,7 @@ "charges": 7, "flags": [ "EATEN_COLD" ], "fun": 10, - "freezing_point": 22 + "freezing_point": -6 }, { "type": "COMESTIBLE", @@ -433,7 +433,7 @@ "phase": "liquid", "charges": 7, "flags": [ "EATEN_COLD" ], - "freezing_point": -22, + "freezing_point": -30, "fun": 5 }, { @@ -461,7 +461,7 @@ "volume": "250 ml", "phase": "liquid", "flags": [ "EATEN_COLD", "NUTRIENT_OVERRIDE" ], - "freezing_point": -22, + "freezing_point": -30, "fun": 4 }, { @@ -490,7 +490,7 @@ "charges": 7, "flags": [ "EATEN_COLD" ], "fun": 2, - "freezing_point": 20 + "freezing_point": -7 }, { "type": "COMESTIBLE", @@ -514,7 +514,7 @@ "material": [ "alcohol" ], "volume": "250 ml", "flags": [ "EATEN_COLD" ], - "freezing_point": -22, + "freezing_point": -30, "phase": "liquid", "charges": 7, "fun": 12 @@ -597,7 +597,7 @@ "volume": "250 ml", "phase": "liquid", "flags": [ "EATEN_COLD" ], - "freezing_point": -29, + "freezing_point": -34, "fun": 20, "vitamins": [ [ "vitA", 2 ], [ "vitC", 118 ], [ "calcium", 2 ], [ "iron", 1 ] ] }, @@ -625,7 +625,7 @@ "volume": "250 ml", "phase": "liquid", "flags": [ "EATEN_COLD" ], - "freezing_point": -29, + "freezing_point": -34, "fun": 20, "vitamins": [ [ "vitC", 135 ], [ "calcium", 1 ], [ "iron", 1 ] ] }, @@ -653,7 +653,7 @@ "volume": "250 ml", "phase": "liquid", "flags": [ "EATEN_COLD" ], - "freezing_point": -22, + "freezing_point": -30, "fun": 20 }, { @@ -679,7 +679,7 @@ "volume": "250 ml", "phase": "liquid", "flags": [ "EATEN_COLD" ], - "freezing_point": 23, + "freezing_point": -5, "fun": 10, "vitamins": [ [ "calcium", 1 ] ] }, @@ -707,7 +707,7 @@ "phase": "liquid", "charges": 7, "flags": [ "EATEN_COLD" ], - "freezing_point": 23, + "freezing_point": -5, "fun": 14 }, { @@ -736,7 +736,7 @@ "charges": 7, "flags": [ "EATEN_COLD" ], "fun": 16, - "freezing_point": 25 + "freezing_point": -4 }, { "type": "COMESTIBLE", @@ -763,7 +763,7 @@ "charges": 7, "flags": [ "EATEN_COLD" ], "fun": 16, - "freezing_point": 25 + "freezing_point": -4 }, { "type": "COMESTIBLE", @@ -790,7 +790,7 @@ "phase": "liquid", "charges": 7, "flags": [ "EATEN_COLD" ], - "freezing_point": 23, + "freezing_point": -5, "fun": 12 }, { @@ -817,7 +817,7 @@ "volume": "250 ml", "phase": "liquid", "flags": [ "EATEN_COLD" ], - "freezing_point": 23, + "freezing_point": -5, "fun": 8, "vitamins": [ [ "calcium", 1 ] ] }, @@ -846,7 +846,7 @@ "phase": "liquid", "charges": 7, "flags": [ "EATEN_COLD" ], - "freezing_point": -49, + "freezing_point": -45, "fun": 12 }, { @@ -873,7 +873,7 @@ "volume": "250 ml", "phase": "liquid", "flags": [ "EATEN_COLD" ], - "freezing_point": 23, + "freezing_point": -5, "fun": 10, "vitamins": [ [ "calcium", 1 ] ] }, @@ -901,7 +901,7 @@ "volume": "250 ml", "phase": "liquid", "flags": [ "EATEN_COLD" ], - "freezing_point": 23, + "freezing_point": -5, "fun": 14, "vitamins": [ [ "calcium", 1 ] ] }, @@ -929,7 +929,7 @@ "volume": "250 ml", "phase": "liquid", "flags": [ "EATEN_COLD" ], - "freezing_point": 23, + "freezing_point": -5, "fun": 14, "vitamins": [ [ "calcium", 1 ] ] }, @@ -956,7 +956,7 @@ "primary_material": "alcohol", "volume": "250 ml", "phase": "liquid", - "freezing_point": 23, + "freezing_point": -5, "fun": 14, "vitamins": [ [ "calcium", 1 ], [ "iron", 1 ] ], "flags": [ "EATEN_COLD" ] @@ -985,7 +985,7 @@ "volume": "250 ml", "phase": "liquid", "flags": [ "EATEN_COLD" ], - "freezing_point": 23, + "freezing_point": -5, "fun": 14, "vitamins": [ [ "calcium", 1 ] ] }, @@ -1015,7 +1015,7 @@ "fun": 18, "vitamins": [ [ "calcium", 1 ], [ "iron", 1 ] ], "flags": [ "EATEN_COLD" ], - "freezing_point": 23 + "freezing_point": -5 }, { "type": "COMESTIBLE", @@ -1044,7 +1044,7 @@ "flags": [ "EATEN_COLD", "EDIBLE_FROZEN" ], "fun": 8, "vitamins": [ [ "vitC", 20 ] ], - "freezing_point": -22 + "freezing_point": -30 }, { "type": "COMESTIBLE", @@ -1073,7 +1073,7 @@ "flags": [ "EATEN_COLD", "EDIBLE_FROZEN" ], "fun": -12, "vitamins": [ [ "vitC", 20 ] ], - "freezing_point": -22 + "freezing_point": -30 }, { "type": "COMESTIBLE", @@ -1098,7 +1098,7 @@ "material": [ "alcohol" ], "volume": "250 ml", "flags": [ "EATEN_COLD" ], - "freezing_point": -22, + "freezing_point": -30, "phase": "liquid", "charges": 7, "fun": 17 @@ -1155,7 +1155,7 @@ "material": [ "alcohol" ], "volume": "250 ml", "flags": [ "EATEN_COLD" ], - "freezing_point": -22, + "freezing_point": -30, "phase": "liquid", "charges": 7, "fun": 17 @@ -1205,7 +1205,7 @@ "phase": "liquid", "charges": 5, "flags": [ "EATEN_COLD" ], - "freezing_point": -27, + "freezing_point": -33, "fun": 20 }, { @@ -1233,7 +1233,7 @@ "phase": "liquid", "charges": 2, "flags": [ "EATEN_COLD" ], - "freezing_point": -22, + "freezing_point": -30, "fun": 20 }, { @@ -1259,7 +1259,7 @@ "volume": "500 ml", "phase": "liquid", "flags": [ "EATEN_COLD" ], - "freezing_point": -22, + "freezing_point": -30, "fun": 20 }, { @@ -1285,7 +1285,7 @@ "volume": "250 ml", "phase": "liquid", "flags": [ "EATEN_COLD" ], - "freezing_point": -22, + "freezing_point": -30, "fun": 20 }, { @@ -1368,7 +1368,7 @@ "flags": [ "EATEN_COLD", "FREEZERBURN" ], "fun": 20, "vitamins": [ [ "vitA", 5 ], [ "vitC", 3 ], [ "calcium", 12 ], [ "iron", 2 ] ], - "freezing_point": 12 + "freezing_point": -11 }, { "type": "COMESTIBLE", @@ -1394,7 +1394,7 @@ "charges": 5, "phase": "liquid", "flags": [ "EATEN_COLD" ], - "freezing_point": -22, + "freezing_point": -30, "fun": 20 }, { @@ -1421,7 +1421,7 @@ "volume": "250 ml", "phase": "liquid", "flags": [ "EATEN_COLD" ], - "freezing_point": -29, + "freezing_point": -34, "fun": 25, "vitamins": [ [ "vitA", 2 ], [ "vitC", 23 ], [ "calcium", 1 ], [ "iron", 2 ] ] }, @@ -1449,7 +1449,7 @@ "volume": "250 ml", "phase": "liquid", "flags": [ "EATEN_COLD" ], - "freezing_point": 23, + "freezing_point": -5, "fun": 10, "vitamins": [ [ "calcium", 1 ] ] } diff --git a/data/json/items/comestibles/drink.json b/data/json/items/comestibles/drink.json index 86ac6d0e05ebd..767e3acc26509 100644 --- a/data/json/items/comestibles/drink.json +++ b/data/json/items/comestibles/drink.json @@ -1013,7 +1013,7 @@ "volume": "250 ml", "phase": "liquid", "fun": 2, - "freezing_point": 22 + "freezing_point": -5 }, { "type": "COMESTIBLE", diff --git a/data/json/items/comestibles/drink_other.json b/data/json/items/comestibles/drink_other.json index 153549c05982e..e5cb02f33e9f8 100644 --- a/data/json/items/comestibles/drink_other.json +++ b/data/json/items/comestibles/drink_other.json @@ -46,7 +46,7 @@ "flags": [ "EATEN_COLD", "RAW" ], "phase": "liquid", "vitamins": [ ], - "freezing_point": 30 + "freezing_point": -1 }, { "id": "mayonnaise", @@ -69,7 +69,7 @@ "fun": -1, "flags": [ "FREEZERBURN" ], "phase": "liquid", - "freezing_point": 25 + "freezing_point": -4 }, { "id": "ketchup", @@ -155,7 +155,7 @@ "phase": "liquid", "charges": 16, "fun": -4, - "freezing_point": 28 + "freezing_point": -2 }, { "type": "COMESTIBLE", @@ -179,7 +179,7 @@ "fun": -25, "flags": [ "NUTRIENT_OVERRIDE" ], "vitamins": [ ], - "freezing_point": 14 + "freezing_point": -26 }, { "type": "COMESTIBLE", @@ -213,7 +213,7 @@ "fun": 2, "flags": [ "USE_EAT_VERB" ], "vitamins": [ [ "calcium", 18 ], [ "iron", 23 ] ], - "freezing_point": -20 + "freezing_point": -29 }, { "id": "horseradish", diff --git a/data/json/items/comestibles/egg.json b/data/json/items/comestibles/egg.json index f6e1070108758..5d17be2fbaa06 100644 --- a/data/json/items/comestibles/egg.json +++ b/data/json/items/comestibles/egg.json @@ -303,7 +303,7 @@ "flags": [ "EDIBLE_FROZEN" ], "charges": 16, "fun": -4, - "freezing_point": -459, + "freezing_point": -274, "vitamins": [ [ "vitB", 2 ] ] }, { diff --git a/data/json/items/comestibles/junkfood.json b/data/json/items/comestibles/junkfood.json index 4831417945a6c..f3288ba8378ac 100644 --- a/data/json/items/comestibles/junkfood.json +++ b/data/json/items/comestibles/junkfood.json @@ -518,7 +518,7 @@ "charges": 16, "fun": 5, "vitamins": [ [ "calcium", 2 ] ], - "freezing_point": -70 + "freezing_point": -57 }, { "type": "COMESTIBLE", diff --git a/data/json/items/comestibles/med.json b/data/json/items/comestibles/med.json index a43233a3f92f3..c2d2c1cace9a0 100644 --- a/data/json/items/comestibles/med.json +++ b/data/json/items/comestibles/med.json @@ -438,7 +438,7 @@ "phase": "liquid", "charges": 4, "flags": [ "EATEN_COLD" ], - "freezing_point": -49, + "freezing_point": -45, "fun": 30 }, { diff --git a/data/json/items/comestibles/mutagen.json b/data/json/items/comestibles/mutagen.json index c61ea57a91b56..c17dbe2d332bf 100644 --- a/data/json/items/comestibles/mutagen.json +++ b/data/json/items/comestibles/mutagen.json @@ -21,7 +21,7 @@ "flags": [ "NUTRIENT_OVERRIDE" ], "vitamins": [ ], "material": [ "water" ], - "freezing_point": 17 + "freezing_point": -8 }, { "abstract": "iv_mutagen_flavor", diff --git a/data/json/items/comestibles/nuts.json b/data/json/items/comestibles/nuts.json index cc75f8256ba3e..c141fc7c2045c 100644 --- a/data/json/items/comestibles/nuts.json +++ b/data/json/items/comestibles/nuts.json @@ -428,7 +428,7 @@ "charges": 4, "flags": [ "EATEN_HOT" ], "fun": 5, - "freezing_point": -80 + "freezing_point": -62 }, { "id": "peanutbutter", diff --git a/data/json/items/comestibles/other.json b/data/json/items/comestibles/other.json index 7fff34d328366..7aea6e36a17d6 100644 --- a/data/json/items/comestibles/other.json +++ b/data/json/items/comestibles/other.json @@ -284,7 +284,7 @@ "price_postapoc": 0, "material": [ "paper" ], "volume": "250 ml", - "freezing_point": -459, + "freezing_point": -274, "charges": 50, "fun": -20 }, @@ -303,7 +303,7 @@ "price_postapoc": 0, "material": [ "cardboard" ], "volume": "250 ml", - "freezing_point": -459, + "freezing_point": -274, "charges": 10, "fun": -20 }, @@ -570,7 +570,7 @@ "calories": 2, "charges": 20, "fun": -5, - "freezing_point": -459 + "freezing_point": -274 }, { "type": "COMESTIBLE", @@ -667,7 +667,7 @@ "calories": 170, "vitamins": [ [ "vitA", 20 ], [ "vitC", 45 ], [ "calcium", 5 ], [ "iron", 5 ] ], "fun": 5, - "freezing_point": -459, + "freezing_point": -274, "color": "brown", "flags": [ "INEDIBLE", "CATTLE" ], "use_action": [ "CATTLEFODDER" ] @@ -689,7 +689,7 @@ "calories": 400, "vitamins": [ [ "calcium", 1 ], [ "iron", 7 ] ], "fun": 5, - "freezing_point": -459, + "freezing_point": -274, "color": "brown", "flags": [ "INEDIBLE", "BIRD", "NUTRIENT_OVERRIDE" ], "use_action": [ "BIRDFOOD" ] @@ -738,7 +738,7 @@ "calories": 380, "vitamins": [ [ "vitA", 25 ], [ "iron", 25 ], [ "vitB", 20 ], [ "calcium", 30 ] ], "fun": -15, - "freezing_point": -459, + "freezing_point": -274, "color": "brown", "flags": [ "LUPINE" ], "use_action": [ "DOGFOOD" ] @@ -787,7 +787,7 @@ "calories": 380, "vitamins": [ [ "vitA", 25 ], [ "iron", 25 ], [ "vitB", 20 ], [ "calcium", 30 ] ], "fun": -15, - "freezing_point": -459, + "freezing_point": -274, "color": "brown", "flags": [ "FELINE" ], "use_action": [ "CATFOOD" ] @@ -856,7 +856,7 @@ "material": [ "paper" ], "price": 50, "price_postapoc": 200, - "freezing_point": -459, + "freezing_point": -274, "description": "A paper sachet with tea leaves inside. Put it into boiling water to make a cup of black tea." }, { @@ -910,7 +910,7 @@ "material": [ "plastic" ], "price": 50, "price_postapoc": 200, - "freezing_point": -459, + "freezing_point": -274, "description": "A small packet of commercial instant coffee powder. No creamer or sweetener added." }, { diff --git a/data/json/items/comestibles/protein.json b/data/json/items/comestibles/protein.json index e2606881a9660..c53ec23f5d907 100644 --- a/data/json/items/comestibles/protein.json +++ b/data/json/items/comestibles/protein.json @@ -51,7 +51,7 @@ "color": "white", "container": "bottle_plastic_small", "calories": 100, - "freezing_point": -459, + "freezing_point": -274, "vitamins": [ ] }, { diff --git a/data/json/items/comestibles/seed.json b/data/json/items/comestibles/seed.json index 9d1470d6ff7c9..8baf3413c641b 100644 --- a/data/json/items/comestibles/seed.json +++ b/data/json/items/comestibles/seed.json @@ -678,7 +678,7 @@ "primary_material": "dried_vegetable", "volume": "250 ml", "flags": [ "SMOKED" ], - "freezing_point": -459, + "freezing_point": -274, "charges": 4, "fun": 3 }, diff --git a/data/json/items/comestibles/spice.json b/data/json/items/comestibles/spice.json index bfc6cd92eb589..9afad56556cdf 100644 --- a/data/json/items/comestibles/spice.json +++ b/data/json/items/comestibles/spice.json @@ -19,7 +19,7 @@ "volume": "250 ml", "color": "red", "primary_material": "water", - "freezing_point": -22, + "freezing_point": -30, "phase": "liquid" }, { @@ -142,7 +142,7 @@ "charges": 10, "healthy": -1, "fun": -15, - "freezing_point": -22, + "freezing_point": -30, "phase": "liquid" }, { diff --git a/data/mods/Magiclysm/items/alchemy_items.json b/data/mods/Magiclysm/items/alchemy_items.json index 44c9abcd4c0b8..b9ee2454e18ef 100644 --- a/data/mods/Magiclysm/items/alchemy_items.json +++ b/data/mods/Magiclysm/items/alchemy_items.json @@ -176,7 +176,7 @@ "container": "flask_glass", "charges": 1, "phase": "liquid", - "freezing_point": -100 + "freezing_point": -73 }, { "id": "stirge_proboscis", diff --git a/data/mods/Magiclysm/items/cast_spell_items.json b/data/mods/Magiclysm/items/cast_spell_items.json index 8ebb9e3283124..bd5f1a5a49a02 100644 --- a/data/mods/Magiclysm/items/cast_spell_items.json +++ b/data/mods/Magiclysm/items/cast_spell_items.json @@ -19,7 +19,7 @@ "flags": [ "EATEN_COLD", "NUTRIENT_OVERRIDE" ], "phase": "liquid", "price": 2500, - "freezing_point": 40 + "freezing_point": 4 }, { "id": "mana_potion", @@ -56,7 +56,7 @@ "flags": [ "EATEN_COLD", "NUTRIENT_OVERRIDE" ], "phase": "liquid", "price": 3000, - "freezing_point": 40 + "freezing_point": 4 }, { "id": "ogres_strength_potion", @@ -139,7 +139,7 @@ "flags": [ "TRADER_AVOID", "NUTRIENT_OVERRIDE" ], "phase": "liquid", "price": 2500, - "freezing_point": 10 + "freezing_point": -12 }, { "id": "twisted_restore_potion_improved", diff --git a/data/mods/Magiclysm/items/mutagen.json b/data/mods/Magiclysm/items/mutagen.json index 5e12fc705c9a1..b7dcd25032157 100644 --- a/data/mods/Magiclysm/items/mutagen.json +++ b/data/mods/Magiclysm/items/mutagen.json @@ -20,7 +20,7 @@ "charges": 2, "use_action": { "type": "mutagen_iv", "mutation_category": "MANATOUCHED" }, "flags": [ "EATEN_COLD", "NUTRIENT_OVERRIDE" ], - "freezing_point": -22, + "freezing_point": -30, "fun": -15 }, { diff --git a/data/mods/TEST_DATA/items.json b/data/mods/TEST_DATA/items.json index e3b6be5073653..3fd587bede745 100644 --- a/data/mods/TEST_DATA/items.json +++ b/data/mods/TEST_DATA/items.json @@ -1341,7 +1341,7 @@ "charges": 7, "flags": [ "EATEN_COLD" ], "fun": -5, - "freezing_point": 20 + "freezing_point": -7 }, { "id": "test_nuclear_carafe", diff --git a/doc/JSON_INFO.md b/doc/JSON_INFO.md index df08d7a2873f3..4453242c0f6d4 100644 --- a/doc/JSON_INFO.md +++ b/doc/JSON_INFO.md @@ -829,7 +829,7 @@ When you sort your inventory by category, these are the categories that are disp | `specific_heat_liquid` | Specific heat of a material when not frozen (J/(g K)). Default 4.186. | `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 ). +| `freezing_point` | Freezing point of this material (C). Default 0 C ( 32 F ). | `edible` | Optional boolean. Default is false. | `rotting` | Optional boolean. Default is false. | `soft` | Optional boolean. Default is false. @@ -2592,7 +2592,7 @@ CBMs can be defined like this: "charges" : 4, // Number of uses when spawned "stack_size" : 8, // (Optional) How many uses are in the above-defined volume. If omitted, is the same as 'charges' "fun" : 50 // Morale effects when used -"freezing_point": 32, // (Optional) Temperature in F at which item freezes, default is water (32F/0C) +"freezing_point": 32, // (Optional) Temperature in C at which item freezes, default is water (32F/0C) "cooks_like": "meat_cooked", // (Optional) If the item is used in a recipe, replaces it with its cooks_like "parasites": 10, // (Optional) Probability of becoming parasitised when eating "contamination": [ { "disease": "bad_food", "probability": 5 } ], // (Optional) List of diseases carried by this comestible and their associated probability. Values must be in the [0, 100] range. diff --git a/src/cata_utility.cpp b/src/cata_utility.cpp index 55423a14645a9..93926db360f9f 100644 --- a/src/cata_utility.cpp +++ b/src/cata_utility.cpp @@ -214,6 +214,11 @@ double temp_to_kelvin( double fahrenheit ) return temp_to_celsius( fahrenheit ) + 273.15; } +double celsius_to_kelvin( double celsius ) +{ + return celsius + 273.15; +} + double kelvin_to_fahrenheit( double kelvin ) { return 1.8 * ( kelvin - 273.15 ) + 32; diff --git a/src/cata_utility.h b/src/cata_utility.h index 182156cb70c1d..7ca37e414ded5 100644 --- a/src/cata_utility.h +++ b/src/cata_utility.h @@ -199,6 +199,13 @@ double temp_to_celsius( double fahrenheit ); */ double temp_to_kelvin( double fahrenheit ); +/** + * Convert a temperature from degrees Celsius to Kelvin. + * + * @return Temperature in degrees K. + */ +double celsius_to_kelvin( double celsius ); + /** * Convert a temperature from Kelvin to degrees Fahrenheit. * diff --git a/src/item.cpp b/src/item.cpp index 92b826a865dc5..d63317d7ebf9b 100644 --- a/src/item.cpp +++ b/src/item.cpp @@ -1802,7 +1802,7 @@ void item::debug_info( std::vector &info, const iteminfo_query *parts, iteminfo::lower_is_better, get_latent_heat() ) ); info.push_back( iteminfo( "BASE", _( "Freeze point: " ), "", - iteminfo::lower_is_better, + iteminfo::lower_is_better | iteminfo::is_decimal, get_freeze_point() ) ); } } @@ -8807,7 +8807,7 @@ void item::set_item_specific_energy( const float new_specific_energy ) const float specific_heat_liquid = get_specific_heat_liquid(); // J/g K const float specific_heat_solid = get_specific_heat_solid(); // J/g K const float latent_heat = get_latent_heat(); // J/kg - const float freezing_temperature = temp_to_kelvin( get_freeze_point() ); // K + const float freezing_temperature = celsius_to_kelvin( get_freeze_point() ); // K const float completely_frozen_specific_energy = specific_heat_solid * freezing_temperature; // Energy that the item would have if it was completely solid at freezing temperature const float completely_liquid_specific_energy = completely_frozen_specific_energy + @@ -8870,7 +8870,7 @@ float item::get_specific_energy_from_temperature( const float new_temperature ) const float specific_heat_liquid = get_specific_heat_liquid(); // J/g K const float specific_heat_solid = get_specific_heat_solid(); // J/g K const float latent_heat = get_latent_heat(); // J/kg - const float freezing_temperature = temp_to_kelvin( get_freeze_point() ); // K + const float freezing_temperature = celsius_to_kelvin( get_freeze_point() ); // K const float completely_frozen_energy = specific_heat_solid * freezing_temperature; // Energy that the item would have if it was completely solid at freezing temperature const float completely_liquid_energy = completely_frozen_energy + @@ -8888,7 +8888,7 @@ float item::get_specific_energy_from_temperature( const float new_temperature ) void item::set_item_temperature( float new_temperature ) { - const float freezing_temperature = temp_to_kelvin( get_freeze_point() ); // K + const float freezing_temperature = celsius_to_kelvin( get_freeze_point() ); // K const float specific_heat_solid = get_specific_heat_solid(); // J/g K const float latent_heat = get_latent_heat(); // J/kg @@ -9530,7 +9530,7 @@ void item::calc_temp( const int temp, const float insulation, const time_duratio const float specific_heat_liquid = get_specific_heat_liquid(); const float specific_heat_solid = get_specific_heat_solid(); const float latent_heat = get_latent_heat(); - const float freezing_temperature = temp_to_kelvin( get_freeze_point() ); // K + const float freezing_temperature = celsius_to_kelvin( get_freeze_point() ); // K const float completely_frozen_specific_energy = specific_heat_solid * freezing_temperature; // Energy that the item would have if it was completely solid at freezing temperature const float completely_liquid_specific_energy = completely_frozen_specific_energy + diff --git a/src/item.h b/src/item.h index 6f5064ce44ad8..b0860f2b93334 100644 --- a/src/item.h +++ b/src/item.h @@ -1245,7 +1245,7 @@ class item : public visitable float get_specific_heat_liquid() const; float get_specific_heat_solid() const; float get_latent_heat() const; - float get_freeze_point() const; // Fahrenheit + float get_freeze_point() const; // Celsius // If this is food, returns itself. If it contains food, return that // contents. Otherwise, returns nullptr. diff --git a/src/itype.h b/src/itype.h index a4894e37834ba..471013f573dc6 100644 --- a/src/itype.h +++ b/src/itype.h @@ -161,8 +161,8 @@ struct islot_comestible { /**Amount of radiation you get from this comestible*/ int radiation = 0; - /** freezing point in degrees Fahrenheit, below this temperature item can freeze */ - int freeze_point = temperatures::freezing; + /** freezing point in degrees celsius, below this temperature item can freeze */ + float freeze_point = 0; /**List of diseases carried by this comestible and their associated probability*/ std::map contamination; diff --git a/src/material.cpp b/src/material.cpp index 32e8cbf57e267..54a6d9f01bf2b 100644 --- a/src/material.cpp +++ b/src/material.cpp @@ -68,7 +68,7 @@ void material_type::load( const JsonObject &jsobj, const std::string & ) optional( jsobj, was_loaded, "specific_heat_liquid", _specific_heat_liquid ); optional( jsobj, was_loaded, "specific_heat_solid", _specific_heat_solid ); optional( jsobj, was_loaded, "latent_heat", _latent_heat ); - optional( jsobj, was_loaded, "freeze_point", _freeze_point ); + optional( jsobj, was_loaded, "freezing_point", _freeze_point ); assign( jsobj, "salvaged_into", _salvaged_into ); optional( jsobj, was_loaded, "repaired_with", _repaired_with, itype_id::NULL_ID() ); @@ -227,7 +227,7 @@ float material_type::latent_heat() const return _latent_heat; } -int material_type::freeze_point() const +float material_type::freeze_point() const { return _freeze_point; } diff --git a/src/material.h b/src/material.h index c20e83c02128f..5ecd0914e34c8 100644 --- a/src/material.h +++ b/src/material.h @@ -75,7 +75,7 @@ class material_type float _specific_heat_liquid = 4.186f; float _specific_heat_solid = 2.108f; float _latent_heat = 334.0f; - int _freeze_point = 32; // Fahrenheit + float _freeze_point = 0; // Celsius bool _edible = false; bool _rotting = false; bool _soft = false; @@ -127,7 +127,7 @@ class material_type float specific_heat_liquid() const; float specific_heat_solid() const; float latent_heat() const; - int freeze_point() const; + float freeze_point() const; int density() const; bool edible() const; bool rotting() const; From 8ec49fc9d7a836c62645821ecf3682d5c82b7040 Mon Sep 17 00:00:00 2001 From: Charlie Gardai <32105250+Moltenhead@users.noreply.github.com> Date: Tue, 23 Feb 2021 08:58:57 +0100 Subject: [PATCH 021/453] Stand up peek (#47257) --- src/avatar.cpp | 7 +++++++ src/avatar.h | 2 ++ src/game.cpp | 26 +++++++++++++++++++++++--- src/game.h | 9 +++++++++ 4 files changed, 41 insertions(+), 3 deletions(-) diff --git a/src/avatar.cpp b/src/avatar.cpp index 4fe74ab391b7c..b28b60e68c89c 100644 --- a/src/avatar.cpp +++ b/src/avatar.cpp @@ -1526,6 +1526,13 @@ void avatar::toggle_crouch_mode() } } +void avatar::activate_crouch_mode() +{ + if( !is_crouching() ) { + set_movement_mode( move_mode_id( "crouch" ) ); + } +} + void avatar::reset_move_mode() { if( !is_walking() ) { diff --git a/src/avatar.h b/src/avatar.h index 1fa81646c7d7e..427aac2176d3c 100644 --- a/src/avatar.h +++ b/src/avatar.h @@ -237,6 +237,8 @@ class avatar : public player void toggle_run_mode(); // Toggles crouching on/off. void toggle_crouch_mode(); + // Activate crouch mode if not in crouch mode. + void activate_crouch_mode(); bool wield( item_location target ); bool wield( item &target ) override; diff --git a/src/game.cpp b/src/game.cpp index abbb714f18cd9..c06d043ea41dc 100644 --- a/src/game.cpp +++ b/src/game.cpp @@ -6130,10 +6130,20 @@ void game::peek( const tripoint &p ) u.moves -= 200; tripoint prev = u.pos(); u.setpos( p ); + const bool is_same_pos = u.pos() == prev; + const bool is_standup_peek = is_same_pos && u.is_crouching(); tripoint center = p; - const look_around_result result = look_around( /*show_window=*/true, center, center, false, false, - true ); - u.setpos( prev ); + + look_around_result result; + const look_around_params looka_params = { true, center, center, false, false, true }; + if( is_standup_peek ) { // Non moving peek from crouch is a standup peek + u.reset_move_mode(); + result = look_around( looka_params ); + u.activate_crouch_mode(); + } else { // Else is normal peek + result = look_around( looka_params ); + u.setpos( prev ); + } if( result.peek_action && *result.peek_action == PA_BLIND_THROW ) { item_location loc; @@ -6141,6 +6151,7 @@ void game::peek( const tripoint &p ) } m.invalidate_map_cache( p.z ); } + //////////////////////////////////////////////////////////////////////////////////////////// cata::optional game::look_debug() { @@ -7051,6 +7062,8 @@ cata::optional game::look_around() return result.position; } +//look_around_result game::look_around( const bool show_window, tripoint ¢er, +// const tripoint &start_point, bool has_first_point, bool select_zone, bool peeking ) look_around_result game::look_around( const bool show_window, tripoint ¢er, const tripoint &start_point, bool has_first_point, bool select_zone, bool peeking ) { @@ -7369,6 +7382,13 @@ look_around_result game::look_around( const bool show_window, tripoint ¢er, return result; } +look_around_result game::look_around( look_around_params looka_params ) +{ + return look_around( looka_params.show_window, looka_params.center, looka_params.start_point, + looka_params.has_first_point, + looka_params.select_zone, looka_params.peeking ); +} + std::vector game::find_nearby_items( int iRadius ) { std::map temp_items; diff --git a/src/game.h b/src/game.h index 88e59f130d982..247d68f7da31e 100644 --- a/src/game.h +++ b/src/game.h @@ -125,6 +125,14 @@ struct look_around_result { cata::optional position; cata::optional peek_action; }; +struct look_around_params { + const bool show_window; + tripoint ¢er; + const tripoint &start_point; + bool has_first_point; + bool select_zone; + bool peeking; +}; struct w_map { int id; @@ -572,6 +580,7 @@ class game cata::optional look_around(); look_around_result look_around( bool show_window, tripoint ¢er, const tripoint &start_point, bool has_first_point, bool select_zone, bool peeking ); + look_around_result look_around( look_around_params ); // Shared method to print "look around" info void pre_print_all_tile_info( const tripoint &lp, const catacurses::window &w_info, From e807a1daf9c2db384070edd8d9111d6d2f6f3bf4 Mon Sep 17 00:00:00 2001 From: Mom-Bun <43492737+Mom-Bun@users.noreply.github.com> Date: Wed, 24 Feb 2021 03:54:04 -0600 Subject: [PATCH 022/453] [AFTERSHOCK] Basic Ballistic Weapons (#47559) --- .../itemgroups/spaceship_groups.json | 2 +- .../itemgroups/weapons/energy_gun_groups.json | 92 +++++++++++++++++ data/mods/Aftershock/items/ammo/10mm.json | 42 ++++++++ data/mods/Aftershock/items/ammo/25mm.json | 23 +++++ data/mods/Aftershock/items/ammo/7.50mm.json | 42 ++++++++ data/mods/Aftershock/items/ammo_type.json | 18 ++++ data/mods/Aftershock/items/casing.json | 15 +++ data/mods/Aftershock/items/gun/10mm.json | 35 +++++++ data/mods/Aftershock/items/gun/25mm.json | 47 +++++++++ data/mods/Aftershock/items/gun/7.50mm.json | 98 +++++++++++++++++++ .../Aftershock/items/gun/combination.json | 19 ---- data/mods/Aftershock/items/magazine/10mm.json | 19 ++++ data/mods/Aftershock/items/magazine/25mm.json | 18 ++++ .../Aftershock/items/magazine/7.50mm.json | 37 +++++++ .../mods/Aftershock/items/magazine/alien.json | 1 - .../Aftershock/vehicles/vehicle_parts.json | 28 ++++++ 16 files changed, 515 insertions(+), 21 deletions(-) create mode 100644 data/mods/Aftershock/items/ammo/10mm.json create mode 100644 data/mods/Aftershock/items/ammo/25mm.json create mode 100644 data/mods/Aftershock/items/ammo/7.50mm.json create mode 100644 data/mods/Aftershock/items/casing.json create mode 100644 data/mods/Aftershock/items/gun/10mm.json create mode 100644 data/mods/Aftershock/items/gun/25mm.json create mode 100644 data/mods/Aftershock/items/gun/7.50mm.json delete mode 100644 data/mods/Aftershock/items/gun/combination.json create mode 100644 data/mods/Aftershock/items/magazine/10mm.json create mode 100644 data/mods/Aftershock/items/magazine/25mm.json create mode 100644 data/mods/Aftershock/items/magazine/7.50mm.json diff --git a/data/mods/Aftershock/itemgroups/spaceship_groups.json b/data/mods/Aftershock/itemgroups/spaceship_groups.json index 53f1b65c30d41..2e664bacb8d8e 100644 --- a/data/mods/Aftershock/itemgroups/spaceship_groups.json +++ b/data/mods/Aftershock/itemgroups/spaceship_groups.json @@ -19,7 +19,7 @@ { "item": "emer_blanket", "count": 2 }, { "item": "afs_radiobeacon" }, { "item": "afs_landfall_gun", "container-item": "back_holster" }, - { "item": "22_lr", "charges": 18 }, + { "item": "afs_7.50mm_rp", "charges": 18 }, { "item": "afs_landfall_kit_2_instructions" } ] } diff --git a/data/mods/Aftershock/itemgroups/weapons/energy_gun_groups.json b/data/mods/Aftershock/itemgroups/weapons/energy_gun_groups.json index 1516ee5b1b817..829ca018ce3d8 100644 --- a/data/mods/Aftershock/itemgroups/weapons/energy_gun_groups.json +++ b/data/mods/Aftershock/itemgroups/weapons/energy_gun_groups.json @@ -40,5 +40,97 @@ "subtype": "distribution", "ammo": 100, "items": [ [ "afs_4g_plasma", 30 ] ] + }, + { + "type": "item_group", + "id": "guns_pistol_rare", + "items": [ { "item": "afs_orion_84K", "prob": 15, "charges-min": 0, "charges-max": 20 } ] + }, + { + "type": "item_group", + "id": "guns_pistol_rare_display", + "items": [ { "item": "afs_orion_84K", "prob": 15, "charges-min": 0, "charges-max": 0 } ] + }, + { + "type": "item_group", + "id": "guns_pistol_obscure", + "items": [ { "item": "afs_orion_84K", "prob": 50, "charges-min": 0, "charges-max": 20 } ] + }, + { + "type": "item_group", + "id": "guns_rifle_rare_display", + "items": [ + { "item": "afs_gibrifle", "prob": 1, "charges-min": 0, "charges-max": 0 }, + { "item": "afs_Accipitermg", "prob": 1, "charges-min": 0, "charges-max": 0 } + ] + }, + { + "type": "item_group", + "id": "guns_rifle_rare", + "items": [ + { "item": "afs_gibrifle", "prob": 25, "charges-min": 0, "charges-max": 30 }, + { "item": "afs_Accipitermg", "prob": 20, "charges-min": 0, "charges-max": 30 } + ] + }, + { + "type": "item_group", + "id": "guns_rifle_milspec", + "items": [ + { "item": "afs_gibrifle", "prob": 50, "charges-min": 0, "charges-max": 30 }, + { "item": "afs_Accipitermg", "prob": 45, "charges-min": 0, "charges-max": 30 } + ] + }, + { + "type": "item_group", + "id": "guns_shotgun_milspec", + "items": [ { "item": "afs_gibs_shotgun", "prob": 20, "charges-min": 0, "charges-max": 40 } ] + }, + { + "type": "item_group", + "id": "mags_pistol_rare", + "items": [ [ "afs_84k_20mag", 15 ] ] + }, + { + "type": "item_group", + "id": "mags_rifle_rare", + "items": [ [ "afs_UICASTA30", 40 ], [ "afs_UICASTA100drum", 20 ] ] + }, + { + "type": "item_group", + "id": "mags_shotgun_rare", + "items": [ [ "afs_25mm_mag", 50 ] ] + }, + { + "type": "item_group", + "id": "ammo_pistol_rare", + "subtype": "distribution", + "entries": [ { "item": "afs_10mm_caseless_FMJ", "prob": 20 }, { "item": "afs_10mm_caseless_JHP", "prob": 15 } ] + }, + { + "type": "item_group", + "id": "ammo_rifle_rare", + "//": "Less common rifle ammo including that only used by police/paramilitary forces.", + "subtype": "distribution", + "entries": [ { "item": "afs_7.50mm_caseless", "prob": 40 }, { "item": "afs_7.50mm_rp", "prob": 50 } ] + }, + { + "type": "item_group", + "id": "ammo_rifle_milspec", + "subtype": "distribution", + "entries": [ { "item": "afs_7.50mm_caseless", "prob": 40 }, { "item": "afs_7.50mm_rp", "prob": 50 } ] + }, + { + "type": "item_group", + "id": "ammo_shotgun_rare", + "//": "Less common shotgun ammo including that only used by police/paramilitary forces.", + "subtype": "distribution", + "entries": [ { "item": "afs_25mm_shot", "prob": 10 } ] + }, + { + "type": "item_group", + "id": "ammo_shotgun_milspec", + "//": "Military specification shotgun ammo found at military sites.", + "subtype": "distribution", + "entries": [ { "item": "afs_25mm_shot", "prob": 10 } ] } ] diff --git a/data/mods/Aftershock/items/ammo/10mm.json b/data/mods/Aftershock/items/ammo/10mm.json new file mode 100644 index 0000000000000..6f9a8ff576377 --- /dev/null +++ b/data/mods/Aftershock/items/ammo/10mm.json @@ -0,0 +1,42 @@ +[ + { + "id": "afs_10mm_caseless_FMJ", + "type": "AMMO", + "name": { "str_sp": "10mm FMJ caseless" }, + "description": "Standardized 10mm ammunition with a brass jacketed projectile. For as long as you can remember bullets like these have been used for military, law enforcement, and civilian use. Being caseless, these cannot be disassembled or reloaded.", + "weight": "9 g", + "volume": "117 ml", + "price": 400, + "material": [ "lead" ], + "symbol": "=", + "color": "yellow", + "count": 40, + "stack_size": 40, + "ammo_type": "afs_10mm", + "range": 14, + "damage": { "damage_type": "bullet", "amount": 29, "armor_penetration": 4 }, + "dispersion": 60, + "recoil": 650, + "effects": [ "COOKOFF" ] + }, + { + "id": "afs_10mm_caseless_JHP", + "type": "AMMO", + "name": { "str_sp": "10mm JHP caseless" }, + "description": "Standardized 10mm ammunition with a hollow point projectile. While they have inferior penetration to FMJ rounds, their expansion slightly increases stopping power against unarmed targets and reduces overpenetration. Being caseless, these cannot be disassembled or reloaded.", + "weight": "7 g", + "volume": "115 ml", + "price": 150, + "material": [ "lead" ], + "symbol": "=", + "color": "yellow", + "count": 40, + "stack_size": 40, + "ammo_type": "afs_10mm", + "range": 14, + "damage": { "damage_type": "bullet", "amount": 31 }, + "dispersion": 60, + "recoil": 600, + "effects": [ "COOKOFF" ] + } +] diff --git a/data/mods/Aftershock/items/ammo/25mm.json b/data/mods/Aftershock/items/ammo/25mm.json new file mode 100644 index 0000000000000..e9d0a9c5c4b0b --- /dev/null +++ b/data/mods/Aftershock/items/ammo/25mm.json @@ -0,0 +1,23 @@ +[ + { + "id": "afs_25mm_shot", + "type": "AMMO", + "name": { "str_sp": "25mm canister shot" }, + "description": "A 25mm grenade with a canister shot load, deals devastating damage against moderately armored foes within mid to close range. Relatively low tech and affordable when compared to other 25mm grenades, these are often fielded by frontier outfits due to their adequate performance in anti-drone and close quarters combat.", + "weight": "130 g", + "volume": "230 ml", + "price": 8000, + "material": [ "superalloy", "powder", "lead" ], + "symbol": "=", + "color": "pink", + "count": 6, + "stack_size": 1, + "ammo_type": "afs_25mm", + "casing": "afs_25_casing", + "range": 24, + "damage": { "damage_type": "bullet", "amount": 60, "armor_penetration": 15 }, + "dispersion": 75, + "recoil": 2200, + "effects": [ "NEVER_MISFIRES" ] + } +] diff --git a/data/mods/Aftershock/items/ammo/7.50mm.json b/data/mods/Aftershock/items/ammo/7.50mm.json new file mode 100644 index 0000000000000..43a949af6248a --- /dev/null +++ b/data/mods/Aftershock/items/ammo/7.50mm.json @@ -0,0 +1,42 @@ +[ + { + "id": "afs_7.50mm_caseless", + "type": "AMMO", + "name": { "str_sp": "7.50mm caseless" }, + "description": "An intermediate bullet with an acceptable all-round performance. Due to their role as UICA's standard issue rifle cartridge, these are ubiquitous wherever Earth makes its presence be known. Being caseless, these cannot be disassembled or reloaded.", + "weight": "12 g", + "volume": "194 ml", + "price": 280, + "material": [ "lead" ], + "symbol": "=", + "color": "yellow", + "count": 30, + "stack_size": 47, + "ammo_type": "afs_7.50mm", + "range": 36, + "damage": { "damage_type": "bullet", "amount": 44, "armor_penetration": 2 }, + "dispersion": 30, + "recoil": 1500, + "effects": [ "COOKOFF" ] + }, + { + "id": "afs_7.50mm_rp", + "type": "AMMO", + "name": { "str_sp": "7.50mm RP" }, + "description": "Civilian-legal 7.50mm ammunition featuring a reduced propellant case and unjacketed projectiles. The 7.50mm RP round is extremely weak with very low stopping power, short range, and negligible recoil. While cheaper than military grade rounds, its only really useful for rifle training, and for hunting small animals. Being caseless, these cannot be disassembled or reloaded.", + "weight": "3 g", + "volume": "65 ml", + "price": 150, + "material": [ "lead" ], + "symbol": "=", + "color": "yellow", + "count": 80, + "stack_size": 100, + "ammo_type": "afs_7.50mm", + "range": 13, + "damage": { "damage_type": "bullet", "amount": 12 }, + "dispersion": 60, + "recoil": 150, + "effects": [ "COOKOFF" ] + } +] diff --git a/data/mods/Aftershock/items/ammo_type.json b/data/mods/Aftershock/items/ammo_type.json index 4701fc308abba..c27192d8af173 100644 --- a/data/mods/Aftershock/items/ammo_type.json +++ b/data/mods/Aftershock/items/ammo_type.json @@ -22,5 +22,23 @@ "id": "afs_shydrogen", "name": "solid hydrogen", "default": "afs_shydrogen" + }, + { + "type": "ammunition_type", + "id": "afs_25mm", + "name": "25mm", + "default": "afs_25mm_shot" + }, + { + "type": "ammunition_type", + "id": "afs_10mm", + "name": "10mm", + "default": "afs_10mm_caseless_JHP" + }, + { + "type": "ammunition_type", + "id": "afs_7.50mm", + "name": "7.50mm", + "default": "afs_7.50mm_caseless" } ] diff --git a/data/mods/Aftershock/items/casing.json b/data/mods/Aftershock/items/casing.json new file mode 100644 index 0000000000000..581288094ed15 --- /dev/null +++ b/data/mods/Aftershock/items/casing.json @@ -0,0 +1,15 @@ +[ + { + "id": "afs_25_casing", + "type": "GENERIC", + "category": "spare_parts", + "name": { "str": "25mm casing" }, + "description": "A large casing from a spent 25mm cartridge.", + "weight": "50 g", + "volume": "45ml", + "material": [ "superalloy" ], + "symbol": "=", + "stackable": true, + "color": "dark_gray" + } +] diff --git a/data/mods/Aftershock/items/gun/10mm.json b/data/mods/Aftershock/items/gun/10mm.json new file mode 100644 index 0000000000000..1dfe73939b256 --- /dev/null +++ b/data/mods/Aftershock/items/gun/10mm.json @@ -0,0 +1,35 @@ +[ + { + "id": "afs_orion_84K", + "copy-from": "pistol_base", + "looks_like": "glock_17", + "type": "GUN", + "name": { "str": "Seyfert 84K" }, + "description": "Commonly carried by shipping crews that can afford it, Seyfert Armistice's 84K pistol doesn't particularly shine or show anything special but it keeps you safe on long journeys in the vast dark of Orion's Arm.", + "weight": "780 g", + "volume": "480 ml", + "longest_side": "205 mm", + "price": 59200, + "to_hit": -2, + "bashing": 8, + "material": [ "plastic", "superalloy" ], + "symbol": "(", + "color": "dark_gray", + "ammo": "afs_10mm", + "ranged_damage": { "damage_type": "bullet", "amount": -5 }, + "dispersion": 480, + "durability": 8, + "blackpowder_tolerance": 48, + "min_cycle_recoil": 570, + "pocket_data": [ + { + "magazine_well": "103 ml", + "pocket_type": "MAGAZINE_WELL", + "holster": true, + "max_contains_volume": "20 L", + "max_contains_weight": "20 kg", + "item_restriction": [ "afs_84k_20mag" ] + } + ] + } +] diff --git a/data/mods/Aftershock/items/gun/25mm.json b/data/mods/Aftershock/items/gun/25mm.json new file mode 100644 index 0000000000000..5868bc0ba49d6 --- /dev/null +++ b/data/mods/Aftershock/items/gun/25mm.json @@ -0,0 +1,47 @@ +[ + { + "id": "afs_gibs_shotgun", + "looks_like": "m79", + "type": "GUN", + "reload_noise_volume": 10, + "name": { "str": "Gibson S86" }, + "description": "Manufactured by Gibson Armory, the S86 is a light-weight grenade launcher designed to take care of moderately armored opponents. While the S86 firepower is nothing to truly gawk at, it still packs quite a punch both for the target and user and is usually mounted as it is impossible to fire with average strength.", + "weight": "2700 g", + "volume": "2800 ml", + "longest_side": "736 mm", + "price": 550000, + "to_hit": -3, + "bashing": 10, + "material": [ "superalloy", "plastic" ], + "symbol": "(", + "color": "brown", + "min_strength": 18, + "ranged_damage": { "damage_type": "bullet", "amount": 10 }, + "skill": "launcher", + "modes": [ [ "DEFAULT", "DOUBLE", 4 ] ], + "dispersion": 90, + "durability": 6, + "ammo": [ "afs_25mm" ], + "clip_size": 1, + "pocket_data": [ + { + "pocket_type": "MAGAZINE_WELL", + "holster": true, + "max_contains_volume": "20 L", + "max_contains_weight": "20 kg", + "item_restriction": [ "afs_25mm_mag" ] + } + ], + "reload": 400, + "valid_mod_locations": [ + [ "accessories", 2 ], + [ "barrel", 1 ], + [ "sights", 1 ], + [ "sling", 1 ], + [ "grip mount", 1 ], + [ "rail mount", 1 ], + [ "stock mount", 1 ], + [ "underbarrel mount", 1 ] + ] + } +] diff --git a/data/mods/Aftershock/items/gun/7.50mm.json b/data/mods/Aftershock/items/gun/7.50mm.json new file mode 100644 index 0000000000000..483e77a8f31f9 --- /dev/null +++ b/data/mods/Aftershock/items/gun/7.50mm.json @@ -0,0 +1,98 @@ +[ + { + "id": "afs_landfall_gun", + "type": "GUN", + "copy-from": "rifle_22", + "name": { "str": "landfall survival gun" }, + "description": "A lightweight, bolt-action gun that is barely more than a 6.55mm barrel mounted within a flimsy metal assembly. Cheaply made and outdated in all respects, it's only useful in the most extenuating of circumstances.", + "price": 5000, + "material": [ "steel", "plastic" ], + "flags": [ "NEVER_JAMS", "RELOAD_EJECT" ], + "dispersion": 250, + "longest_side": "60 cm", + "reload": 100, + "durability": 5, + "blackpowder_tolerance": 60, + "ammo": [ "afs_7.50mm" ], + "pocket_data": [ { "pocket_type": "MAGAZINE", "rigid": true, "ammo_restriction": { "afs_7.50mm": 1 } } ], + "faults": [ "fault_gun_blackpowder", "fault_gun_dirt" ] + }, + { + "id": "afs_Accipitermg", + "copy-from": "rifle_auto", + "looks_like": "ar15", + "type": "GUN", + "name": { "str": "Accipiter Hawk-00" }, + "description": "A light machine gun manufactured by Accipiter Firearms and distributed by Wraitheon. The Hawk-00's high rate of fire makes it ideally suited to lay down suppressive fire; but also makes it exceedingly hard to control while unmounted.", + "weight": "7500 g", + "volume": "10610 ml", + "longest_side": "1035 mm", + "price": 750000, + "to_hit": -1, + "bashing": 12, + "material": [ "superalloy", "plastic" ], + "symbol": "(", + "color": "dark_gray", + "ammo": [ "afs_7.50mm" ], + "dispersion": 200, + "durability": 7, + "min_cycle_recoil": 1350, + "reload": 400, + "modes": [ [ "DEFAULT", "burst", 4 ] ], + "built_in_mods": [ "bipod" ], + "valid_mod_locations": [ + [ "accessories", 4 ], + [ "barrel", 1 ], + [ "bore", 1 ], + [ "brass catcher", 1 ], + [ "grip", 1 ], + [ "mechanism", 4 ], + [ "muzzle", 1 ], + [ "rail", 1 ], + [ "sights", 1 ], + [ "sling", 1 ], + [ "stock", 1 ] + ], + "pocket_data": [ + { + "pocket_type": "MAGAZINE_WELL", + "holster": true, + "max_contains_volume": "20 L", + "max_contains_weight": "20 kg", + "item_restriction": [ "afs_UICASTA30", "afs_UICASTA100drum" ] + } + ] + }, + { + "id": "afs_gibrifle", + "copy-from": "rifle_semi", + "looks_like": "ar15", + "type": "GUN", + "name": { "str": "G&W SR-P9" }, + "description": "An eminently sturdy and reliable bullpup rifle issued by UICA's military during early reclamation expeditions. Although its been out of service for nearly two decades, many a private military and contractor has found a use for the SR-P9, and it remains common long past its initial introduction into service.", + "weight": "3170 g", + "volume": "3100 ml", + "longest_side": "630 mm", + "price": 125000, + "to_hit": -1, + "bashing": 12, + "material": [ "superalloy", "plastic" ], + "ranged_damage": { "damage_type": "bullet", "amount": -7 }, + "modes": [ [ "DEFAULT", "semi-auto", 1 ], [ "BURST", "burst", 2 ] ], + "symbol": "(", + "color": "dark_gray", + "ammo": [ "afs_7.50mm" ], + "dispersion": 150, + "durability": 10, + "min_cycle_recoil": 1350, + "pocket_data": [ + { + "pocket_type": "MAGAZINE_WELL", + "holster": true, + "max_contains_volume": "20 L", + "max_contains_weight": "20 kg", + "item_restriction": [ "afs_UICASTA30" ] + } + ] + } +] diff --git a/data/mods/Aftershock/items/gun/combination.json b/data/mods/Aftershock/items/gun/combination.json deleted file mode 100644 index 694a5f95fea72..0000000000000 --- a/data/mods/Aftershock/items/gun/combination.json +++ /dev/null @@ -1,19 +0,0 @@ -[ - { - "id": "afs_landfall_gun", - "type": "GUN", - "copy-from": "rifle_22", - "name": { "str": "landfall survival gun" }, - "description": "A lightweight, bolt-action gun that is barely more than a .22 barrel mounted within a flimsy metal assembly. Cheaply made and outdated in all respects, it's only useful in the most extenuating of circumstances.", - "price": 5000, - "price_postapoc": 5000, - "material": [ "steel", "plastic" ], - "flags": [ "NEVER_JAMS", "RELOAD_EJECT" ], - "dispersion": 250, - "longest_side": "60 cm", - "reload": 100, - "durability": 5, - "blackpowder_tolerance": 60, - "faults": [ "fault_gun_blackpowder", "fault_gun_dirt" ] - } -] diff --git a/data/mods/Aftershock/items/magazine/10mm.json b/data/mods/Aftershock/items/magazine/10mm.json new file mode 100644 index 0000000000000..e211e6613d77e --- /dev/null +++ b/data/mods/Aftershock/items/magazine/10mm.json @@ -0,0 +1,19 @@ +[ + { + "id": "afs_84k_20mag", + "looks_like": "glock17_17", + "type": "MAGAZINE", + "name": { "str": "84k 10mm 20-round magazine" }, + "description": "A 20-round magazine for use with the Seyfert 84k.", + "weight": "70 g", + "volume": "103 ml", + "longest_side": "114 mm", + "price": 2400, + "material": [ "plastic", "superalloy" ], + "symbol": "#", + "color": "light_gray", + "ammo_type": [ "afs_10mm" ], + "flags": [ "MAG_COMPACT" ], + "pocket_data": [ { "pocket_type": "MAGAZINE", "rigid": true, "ammo_restriction": { "afs_10mm": 20 } } ] + } +] diff --git a/data/mods/Aftershock/items/magazine/25mm.json b/data/mods/Aftershock/items/magazine/25mm.json new file mode 100644 index 0000000000000..64c3ac9736f93 --- /dev/null +++ b/data/mods/Aftershock/items/magazine/25mm.json @@ -0,0 +1,18 @@ +[ + { + "id": "afs_25mm_mag", + "looks_like": "stanag30", + "type": "MAGAZINE", + "name": { "str": "25mm 40-round magazine" }, + "description": "A 40-round magazine for use with 25mm firearms.", + "weight": "340 g", + "volume": "2 L", + "price": 70000, + "material": [ "superalloy", "plastic" ], + "symbol": "#", + "color": "dark_gray", + "ammo_type": [ "afs_25mm" ], + "reload_time": 60, + "pocket_data": [ { "pocket_type": "MAGAZINE", "rigid": true, "ammo_restriction": { "afs_25mm": 40 } } ] + } +] diff --git a/data/mods/Aftershock/items/magazine/7.50mm.json b/data/mods/Aftershock/items/magazine/7.50mm.json new file mode 100644 index 0000000000000..0967b6f04edd1 --- /dev/null +++ b/data/mods/Aftershock/items/magazine/7.50mm.json @@ -0,0 +1,37 @@ +[ + { + "id": "afs_UICASTA30", + "looks_like": "stanag30", + "type": "MAGAZINE", + "name": { "str": "UICASTA 30-round magazine" }, + "description": "A standardized 30-round magazine compatible with most UICA issue rifles.", + "weight": "265 g", + "volume": "290 ml", + "longest_side": "190 mm", + "price": 8000, + "material": [ "superalloy" ], + "symbol": "#", + "color": "light_gray", + "ammo_type": [ "afs_7.50mm" ], + "flags": [ "MAG_COMPACT" ], + "pocket_data": [ { "pocket_type": "MAGAZINE", "rigid": true, "ammo_restriction": { "afs_7.50mm": 30 } } ] + }, + { + "id": "afs_UICASTA100drum", + "looks_like": "stanag30", + "type": "MAGAZINE", + "name": { "str": "UICASTA 100-round double drum magazine" }, + "description": "A standardized 100-round double drum magazine compatible with most UICA issue rifles.", + "weight": "1700 g", + "volume": "1200 ml", + "longest_side": "300 mm", + "price": 14000, + "material": [ "plastic", "superalloy" ], + "symbol": "#", + "color": "light_gray", + "ammo_type": [ "afs_7.50mm" ], + "reload_time": 200, + "flags": [ "MAG_BULKY" ], + "pocket_data": [ { "pocket_type": "MAGAZINE", "rigid": true, "ammo_restriction": { "afs_7.50mm": 100 } } ] + } +] diff --git a/data/mods/Aftershock/items/magazine/alien.json b/data/mods/Aftershock/items/magazine/alien.json index f9b12cb95b11b..7fbeaab6184aa 100644 --- a/data/mods/Aftershock/items/magazine/alien.json +++ b/data/mods/Aftershock/items/magazine/alien.json @@ -8,7 +8,6 @@ "weight": "1000 g", "volume": "1225ml", "price": 100000, - "price_postapoc": 5000, "material": [ "iron", "plastic" ], "symbol": "=", "color": "yellow", diff --git a/data/mods/Aftershock/vehicles/vehicle_parts.json b/data/mods/Aftershock/vehicles/vehicle_parts.json index b7aad54ed241c..377859a40a80c 100644 --- a/data/mods/Aftershock/vehicles/vehicle_parts.json +++ b/data/mods/Aftershock/vehicles/vehicle_parts.json @@ -28,6 +28,34 @@ "removal": { "skills": [ [ "mechanics", 3 ] ] } } }, + { + "id": "afs_mounted_gibs_shotgun", + "copy-from": "turret", + "type": "vehicle_part", + "name": { "str": "mounted Gibson S86" }, + "item": "afs_gibs_shotgun", + "color": "magenta", + "broken_color": "magenta", + "breaks_into": [ { "item": "scrap", "count": 9 }, { "item": "steel_chunk", "count": 4 }, { "item": "steel_lump", "count": 1 } ], + "requirements": { + "install": { "skills": [ [ "mechanics", 5 ], [ "electronics", 5 ] ] }, + "removal": { "skills": [ [ "mechanics", 3 ] ] } + } + }, + { + "id": "afs_mounted_Accipitermg", + "copy-from": "turret", + "type": "vehicle_part", + "name": { "str": "mounted Accipiter Hawk-00" }, + "item": "afs_Accipitermg", + "color": "magenta", + "broken_color": "magenta", + "breaks_into": [ { "item": "scrap", "count": 9 }, { "item": "steel_chunk", "count": 4 }, { "item": "steel_lump", "count": 1 } ], + "requirements": { + "install": { "skills": [ [ "mechanics", 5 ], [ "electronics", 5 ] ] }, + "removal": { "skills": [ [ "mechanics", 3 ] ] } + } + }, { "id": "afs_laser_rifle", "copy-from": "turret", From 2a03058624ecf1f05a9a80beaa5212226084b332 Mon Sep 17 00:00:00 2001 From: OromisElf Date: Wed, 24 Feb 2021 10:56:22 +0100 Subject: [PATCH 023/453] makes glass walls and glass doors constructable (#47692) --- data/json/construction.json | 31 +++++++++++++++++++++++++++++++ data/json/construction_group.json | 10 ++++++++++ 2 files changed, 41 insertions(+) diff --git a/data/json/construction.json b/data/json/construction.json index 2d8fb4a8ef6cd..df165bd231bfc 100644 --- a/data/json/construction.json +++ b/data/json/construction.json @@ -4271,5 +4271,36 @@ "byproducts": [ { "item": "pebble", "count": [ 70, 100 ] } ], "pre_terrain": "t_railroad_rubble", "post_terrain": "t_dirt" + }, + { + "type": "construction", + "id": "constr_glass_wall", + "group": "build_glass_wall", + "category": "CONSTRUCT", + "required_skills": [ [ "fabrication", 3 ] ], + "time": "60 m", + "qualities": [ [ { "id": "HAMMER_SOFT", "level": 1 } ] ], + "components": [ + [ [ "frame_wood", 1 ] ], + [ [ "chunk_rubber", 16 ] ], + [ [ "glass_sheet", 2 ] ], + [ [ "superglue", 2 ], [ "duct_tape", 10 ] ] + ], + "pre_note": "Must be supported on at least two sides.", + "pre_special": "check_support", + "post_terrain": "t_wall_glass" + }, + { + "type": "construction", + "id": "constr_glass_wall_door", + "group": "build_glass_door", + "category": "CONSTRUCT", + "required_skills": [ [ "fabrication", 3 ] ], + "time": "60 m", + "qualities": [ [ { "id": "HAMMER_SOFT", "level": 1 } ] ], + "components": [ [ [ "frame_wood", 1 ] ], [ [ "chunk_rubber", 16 ] ], [ [ "glass_sheet", 2 ] ], [ [ "rag", 8 ] ] ], + "pre_note": "Must be supported on at least two sides.", + "pre_special": "check_support", + "post_terrain": "t_door_glass_c" } ] diff --git a/data/json/construction_group.json b/data/json/construction_group.json index 2ae0acb904d0d..5495ebfb62d93 100644 --- a/data/json/construction_group.json +++ b/data/json/construction_group.json @@ -284,6 +284,16 @@ "id": "build_fire_ring", "name": "Build Fire Ring" }, + { + "type": "construction_group", + "id": "build_glass_door", + "name": "Build Glass Door" + }, + { + "type": "construction_group", + "id": "build_glass_wall", + "name": "Build Glass Wall" + }, { "type": "construction_group", "id": "build_high_end_of_a_concrete_ramp", From c576cf6f0dd7b2dd2a05ce16b8d5a0078176302c Mon Sep 17 00:00:00 2001 From: Maleclypse <54345792+Maleclypse@users.noreply.github.com> Date: Wed, 24 Feb 2021 04:10:27 -0600 Subject: [PATCH 024/453] Crackers as bread and jam&cheese sandwich (#47649) --- data/json/items/comestibles/sandwich.json | 21 +++++++++++++++++++ data/json/recipes/recipe_food.json | 15 +++++++++++++ .../json/requirements/cooking_components.json | 3 ++- 3 files changed, 38 insertions(+), 1 deletion(-) diff --git a/data/json/items/comestibles/sandwich.json b/data/json/items/comestibles/sandwich.json index bcacfb4ddf8fe..5c63db38b7143 100644 --- a/data/json/items/comestibles/sandwich.json +++ b/data/json/items/comestibles/sandwich.json @@ -113,6 +113,27 @@ "fun": 6, "vitamins": [ [ "vitC", 6 ], [ "calcium", 7 ], [ "iron", 12 ] ] }, + { + "type": "COMESTIBLE", + "id": "sandwich_jam_cheese", + "name": { "str": "jam and cheese sandwich", "str_pl": "jam and cheese sandwiches" }, + "weight": "140 g", + "color": "brown", + "spoils_in": "1 day 13 hours", + "container": "wrapper", + "comestible_type": "FOOD", + "symbol": "%", + "quench": 1, + "calories": 382, + "description": "A delicious jam and cheese sandwich.", + "price": 200, + "price_postapoc": 200, + "material": [ "fruit", "wheat", "milk" ], + "primary_material": "wheat", + "volume": "250 ml", + "fun": 6, + "vitamins": [ [ "vitC", 6 ], [ "calcium", 7 ], [ "iron", 12 ] ] + }, { "type": "COMESTIBLE", "id": "sandwich_jam_butter", diff --git a/data/json/recipes/recipe_food.json b/data/json/recipes/recipe_food.json index e032cfc4a730c..6b8706fc18a1b 100644 --- a/data/json/recipes/recipe_food.json +++ b/data/json/recipes/recipe_food.json @@ -5948,6 +5948,21 @@ "autolearn": true, "components": [ [ [ "bread_sandwich", 2, "LIST" ] ], [ [ "jam_fruit", 1 ] ] ] }, + { + "type": "recipe", + "activity_level": "LIGHT_EXERCISE", + "result": "sandwich_jam_cheese", + "category": "CC_FOOD", + "subcategory": "CSC_FOOD_VEGGI", + "skill_used": "cooking", + "time": "1 m", + "autolearn": true, + "components": [ + [ [ "bread_sandwich", 2, "LIST" ] ], + [ [ "jam_fruit", 1 ] ], + [ [ "cheese", 1 ], [ "cheese_hard", 1 ], [ "can_cheese", 1 ] ] + ] + }, { "type": "recipe", "activity_level": "LIGHT_EXERCISE", diff --git a/data/json/requirements/cooking_components.json b/data/json/requirements/cooking_components.json index 62f1e3568fd05..f951bc13d5150 100644 --- a/data/json/requirements/cooking_components.json +++ b/data/json/requirements/cooking_components.json @@ -30,7 +30,8 @@ [ "wastebread", 1 ], [ "sourdough_bread", 1 ], [ "biscuit", 1 ], - [ "brioche", 1 ] + [ "brioche", 1 ], + [ "crackers", 1 ] ] ] }, From 855d4fb3d78e438e0d7c7bdf7cdf6e9627b2f414 Mon Sep 17 00:00:00 2001 From: casswedson <58050969+casswedson@users.noreply.github.com> Date: Sun, 28 Feb 2021 02:53:00 -0500 Subject: [PATCH 025/453] [Aftershock] misc typograpical fixes (#47783) --- data/mods/Aftershock/items/armor.json | 2 +- data/mods/Aftershock/items/books.json | 2 +- data/mods/Aftershock/items/comestibles/alienfood.json | 4 ++-- data/mods/Aftershock/items/comestibles/bug_brew.json | 6 +++--- data/mods/Aftershock/items/comestibles/cheap_food.json | 2 +- data/mods/Aftershock/items/comestibles/comestibles.json | 2 +- data/mods/Aftershock/items/gun/laser.json | 4 ++-- data/mods/Aftershock/items/gunmods/laser_gunmods.json | 2 +- data/mods/Aftershock/items/items.json | 2 +- data/mods/Aftershock/items/magazine/8x40mm.json | 2 +- data/mods/Aftershock/items/tools.json | 2 +- data/mods/Aftershock/items/weapons.json | 2 +- data/mods/Aftershock/maps/furniture.json | 6 +++--- data/mods/Aftershock/maps/terrain_floraxeno.json | 2 +- data/mods/Aftershock/maps/terrain_groundxeno.json | 2 +- data/mods/Aftershock/mobs/robots.json | 4 ++-- data/mods/Aftershock/mobs/water_mobs.json | 4 ++-- data/mods/Aftershock/mutations/mutations.json | 4 ++-- data/mods/Aftershock/mutations/obsolete.json | 2 +- data/mods/Aftershock/player/professions.json | 4 ++-- data/mods/Aftershock/scenarios.json | 2 +- 21 files changed, 31 insertions(+), 31 deletions(-) diff --git a/data/mods/Aftershock/items/armor.json b/data/mods/Aftershock/items/armor.json index 063723b459c8c..e1aa04b0d5b65 100644 --- a/data/mods/Aftershock/items/armor.json +++ b/data/mods/Aftershock/items/armor.json @@ -334,7 +334,7 @@ "type": "ARMOR", "id": "xllegpouch_large", "name": { "str": "XL leg ammo pouch", "str_pl": "XL leg ammo pouches" }, - "description": "An XL fabric ammo pouch that can be strapped to your leg and capable of holding two magazine close at hand.", + "description": "An XL fabric ammo pouch that can be strapped to your leg; capable of holding two magazines close at hand.", "weight": "120 g", "volume": "250 ml", "copy-from": "legpouch_large", diff --git a/data/mods/Aftershock/items/books.json b/data/mods/Aftershock/items/books.json index abc292f69fb8f..207f3f928304f 100644 --- a/data/mods/Aftershock/items/books.json +++ b/data/mods/Aftershock/items/books.json @@ -114,7 +114,7 @@ "id": "cyrus'_notes", "type": "BOOK", "name": { "str": "Cyrus Whateley's Notes on Repurposing mi-go victims", "str_pl": "copies of Cyrus Whateley's Notes" }, - "description": "A folio of notes written by a madman. They seem to suggestion ways to re-animate the dead and create various affronts to the natural order.", + "description": "A folio of notes written by a madman. They seem to suggest ways to re-animate the dead and create various affronts to the natural order.", "weight": "2063 g", "volume": "2 L", "price": 929200, diff --git a/data/mods/Aftershock/items/comestibles/alienfood.json b/data/mods/Aftershock/items/comestibles/alienfood.json index 387e9678d112f..fca6482f85682 100644 --- a/data/mods/Aftershock/items/comestibles/alienfood.json +++ b/data/mods/Aftershock/items/comestibles/alienfood.json @@ -236,7 +236,7 @@ "copy-from": "flesh", "type": "COMESTIBLE", "name": "alien stomach", - "description": "A balloon like organ you can only guess is a stomach. It is surprisingly durable.", + "description": "A balloon-like organ you can only guess is a stomach. It is surprisingly durable.", "weight": "72 g", "volume": "250 ml", "price_postapoc": 25, @@ -254,7 +254,7 @@ "copy-from": "alien_stomach", "type": "COMESTIBLE", "name": "large alien stomach", - "description": "A balloon like organ of a large alien. It is surprisingly durable.", + "description": "A balloon-like organ of a large alien you can only guess is a stomach. It is surprisingly durable.", "proportional": { "weight": 2.0, "volume": 2.0, "price": 1.5, "calories": 2.0 } }, { diff --git a/data/mods/Aftershock/items/comestibles/bug_brew.json b/data/mods/Aftershock/items/comestibles/bug_brew.json index bcbf8d7cbd91d..b4cc64ef268ed 100644 --- a/data/mods/Aftershock/items/comestibles/bug_brew.json +++ b/data/mods/Aftershock/items/comestibles/bug_brew.json @@ -3,7 +3,7 @@ "type": "COMESTIBLE", "id": "afs_mealgrub_medium", "name": { "str": "mealgrub growth medium" }, - "description": "All sort of organic substances rendered into a nutritious goop that can be used as a growth medium in grub aquaculture. Urban myth claims that its original formula was just bottled industrial runoff. Whatever the case, mealgrubs thrive within it.", + "description": "All sorts of organic substances rendered into a nutritious goop that can be used as a growth medium in grub aquaculture. Urban myth claims that its original formula was just bottled industrial runoff. Whatever the case, mealgrubs thrive within it.", "weight": "100 g", "container": "jug_plastic", "comestible_type": "DRINK", @@ -26,7 +26,7 @@ "type": "COMESTIBLE", "id": "afs_mealgrub_spores", "name": { "str_sp": "mealgrub spores" }, - "description": "Mealgrubs are a staple aquacultural product, treasured for their ability to process nearly any organic substance into safe for consumption animal protein. As the result of very heavy handed gene-modding these are propietary organism, and strictly speaking, its illegal to grow them without a licence.", + "description": "Mealgrubs are a staple aquacultural product, treasured for their ability to process nearly any organic substance into safe for consumption animal protein. As the result of very heavy-handed gene-modding these are proprietary organisms, and strictly speaking, it's illegal to grow them without a license.", "weight": "100 g", "container": "bottle_plastic_small", "comestible_type": "DRINK", @@ -99,7 +99,7 @@ "calories": 360, "healthy": 3, "charges": 5, - "description": "A handful of edible and heavily genemoded grubs, each only slightly thinner than your thumb. Engineered in the wake of the XXII century to feed an overpopulated Earth and its fledging colonies these are sturdy, easily grown and scalable crop.\n\nRemoved from their growth solution they'll quickly die and desiccate, as these already have. They could be safely be eaten with no further processing, for a nutritious if somewhat striking meal.", + "description": "A handful of edible and heavily genemoded grubs, each only slightly thinner than your thumb. Engineered in the wake of the XXII century to feed an overpopulated Earth and its fledgling colonies these are sturdy, easily grown and scalable crop.\n\nRemoved from their growth solution they'll quickly die and desiccate, as these already have. They could be safely eaten with no further processing, for a nutritious if somewhat striking meal.", "fun": 0, "freezing_point": -9999, "vitamins": [ [ "calcium", 2 ], [ "iron", 2 ], [ "vitA", 1 ], [ "vitB", 2 ], [ "bad_food", 1 ] ] diff --git a/data/mods/Aftershock/items/comestibles/cheap_food.json b/data/mods/Aftershock/items/comestibles/cheap_food.json index b5a15933f321b..e2967601a7aee 100644 --- a/data/mods/Aftershock/items/comestibles/cheap_food.json +++ b/data/mods/Aftershock/items/comestibles/cheap_food.json @@ -56,7 +56,7 @@ "weight": "10 g", "color": "yellow", "healthy": 2, - "description": "An golden can of sundew, the leading soft drink of the world. Staring at the can, you feel a craving so intense that you are unsure whether its genuine, or if it has been carefully engineered and implanted into your mind.", + "description": "A golden can of Sundew, the leading soft drink of the world. Staring at the can, you feel a craving so intense that you are unsure whether it's genuine, or if it has been carefully engineered and implanted into your mind.", "price": 1000, "looks_like": "diesel", "container": "can_drink", diff --git a/data/mods/Aftershock/items/comestibles/comestibles.json b/data/mods/Aftershock/items/comestibles/comestibles.json index f6c008a621f9f..601a46c16c416 100644 --- a/data/mods/Aftershock/items/comestibles/comestibles.json +++ b/data/mods/Aftershock/items/comestibles/comestibles.json @@ -45,7 +45,7 @@ { "id": "cream_prot_cold", "name": { "str": "heat retention cream" }, - "description": "Rub this on your skin when you are expecting exposure extreme cold temperatures. Cannot protect from instant frostbite. Smells like the inside of a sheep.", + "description": "Rub this on your skin when you are expecting exposure to extreme cold temperatures. Cannot protect from instant frostbite. Smells like the inside of a sheep.", "use_action": { "type": "cast_spell", "spell_id": "cream_prot_cold", "no_fail": true, "level": 0 }, "type": "COMESTIBLE", "weight": "265 g", diff --git a/data/mods/Aftershock/items/gun/laser.json b/data/mods/Aftershock/items/gun/laser.json index 1f73494f232db..f661f9c21a156 100644 --- a/data/mods/Aftershock/items/gun/laser.json +++ b/data/mods/Aftershock/items/gun/laser.json @@ -22,7 +22,7 @@ "type": "GUN", "copy-from": "afs_sentinel_stunner", "name": { "str": "wrist-trilaser" }, - "description": "A powerful tri-barreled laser weapon, still mounted to the robotic hand of the wraitheon drone it originally belonged too. Can still be fired when connected to an UPS.", + "description": "A powerful tri-barreled laser weapon, still mounted to the robotic hand of the wraitheon drone it originally belonged to. Can still be fired when connected to an UPS.", "color": "red", "range": 10, "ranged_damage": { "damage_type": "heat", "amount": 25, "armor_penetration": 4 }, @@ -126,7 +126,7 @@ "type": "GUN", "name": { "str": "Av-22" }, "copy-from": "v29", - "description": "A common pulse-laser pistol cleared for civilian use. Recoiless, energy-efficient, and easy to use, the av-22 is often carried as a defense weapon by those who lack the practice required to effectively use ballistic weaponry. Due to its low power, it must be fired in sequence mode to stand a chance against hardened foes.", + "description": "A common pulse-laser pistol cleared for civilian use. Recoilless, energy-efficient, and easy to use, the av-22 is often carried as a defense weapon by those who lack the practice required to effectively use ballistic weaponry. Due to its low power, it must be fired in sequence mode to stand a chance against hardened foes.", "price": "500 USD", "price_postapoc": "500 USD", "ammo": [ "battery" ], diff --git a/data/mods/Aftershock/items/gunmods/laser_gunmods.json b/data/mods/Aftershock/items/gunmods/laser_gunmods.json index 3e24a390659a6..1a166a6ab7779 100644 --- a/data/mods/Aftershock/items/gunmods/laser_gunmods.json +++ b/data/mods/Aftershock/items/gunmods/laser_gunmods.json @@ -4,7 +4,7 @@ "type": "GUNMOD", "copy-from": "electrolaser_conversion", "name": { "str": "electrolaser conversion" }, - "description": "A set of high-tech electronics and optics. This convert a laser pistol into a less-lethal electrolaser capable of stunning targets, at the cost of decreased damage output and increased power consumption.", + "description": "A set of high-tech electronics and optics. This converts a laser pistol into a less-lethal electrolaser capable of stunning targets, at the cost of decreased damage output and increased power consumption.", "damage_modifier": { "damage_type": "heat", "amount": -4 }, "range_modifier": -10, "ammo_to_fire_multiplier": 1.2 diff --git a/data/mods/Aftershock/items/items.json b/data/mods/Aftershock/items/items.json index 72acc78c9a8d6..2850b072dc91f 100644 --- a/data/mods/Aftershock/items/items.json +++ b/data/mods/Aftershock/items/items.json @@ -159,7 +159,7 @@ "id": "afs_titanium_tooth", "type": "GENERIC", "name": { "str": "titanium tooth" }, - "description": "A dental implant made of pure titanium, used to replace teeth due to its bio-compatibility and durability.", + "description": "A dental implant made of pure titanium, used to replace teeth due to its biocompatibility and durability.", "price": 5000, "price_postapoc": 50, "weight": "10 g", diff --git a/data/mods/Aftershock/items/magazine/8x40mm.json b/data/mods/Aftershock/items/magazine/8x40mm.json index 7ce95637cb29a..601ae05442828 100644 --- a/data/mods/Aftershock/items/magazine/8x40mm.json +++ b/data/mods/Aftershock/items/magazine/8x40mm.json @@ -4,7 +4,7 @@ "looks_like": "38_speedloader", "type": "MAGAZINE", "name": { "str": "RMGS5 8x40mm speedloader" }, - "description": "This speedloader, made by Rivtech for use with RM99 revolver, can hold 5 rounds of 8x40mm caseless rounds and quickly reload a compatible revolver.", + "description": "This speedloader, made by Rivtech for use with the RM99 revolver, can hold 5 rounds of 8x40mm caseless rounds and quickly reload a compatible revolver.", "weight": "92 g", "volume": "250 ml", "price": 8000, diff --git a/data/mods/Aftershock/items/tools.json b/data/mods/Aftershock/items/tools.json index 7603c1eae9f7b..34994dff76944 100644 --- a/data/mods/Aftershock/items/tools.json +++ b/data/mods/Aftershock/items/tools.json @@ -134,7 +134,7 @@ "copy-from": "afs_power_cutter", "type": "TOOL", "name": { "str": "power cutter (on)", "str_pl": "power cutters (on)" }, - "description": "A huge, gas-powered saw with a diamond blade, currently a whirling blur. It's consuming gasoline, but can be used a fantastic tool for cutting metal. You can also use it as a terrifying weapon, if you're into that sort of thing.", + "description": "A huge, gas-powered saw with a diamond blade, currently a whirling blur. It's consuming gasoline, but can be used as a fantastic tool for cutting metal. You can also use it as a terrifying weapon, if you're into that sort of thing.", "cutting": 80, "turns_per_charge": 3, "revert_to": "afs_power_cutter", diff --git a/data/mods/Aftershock/items/weapons.json b/data/mods/Aftershock/items/weapons.json index 2f79eba429112..68a3f41b46377 100644 --- a/data/mods/Aftershock/items/weapons.json +++ b/data/mods/Aftershock/items/weapons.json @@ -86,7 +86,7 @@ "looks_like": "recurbow", "color": "white", "name": { "str": "Alien lune" }, - "description": "A delicate strand of light links the antipodes of this cresent-shaped device. If the strand is interrupted, the device clanks and shudders before violently emitting a bolt of plasma from its apex.", + "description": "A delicate strand of light links the antipodes of this crescent-shaped device. If the strand is interrupted, the device clanks and shudders before violently emitting a bolt of plasma from its apex.", "price": 1000000, "price_postapoc": 20000, "material": [ "superalloy", "hardsteel" ], diff --git a/data/mods/Aftershock/maps/furniture.json b/data/mods/Aftershock/maps/furniture.json index 25e5c9d6ad353..0331899aa3867 100644 --- a/data/mods/Aftershock/maps/furniture.json +++ b/data/mods/Aftershock/maps/furniture.json @@ -4,7 +4,7 @@ "id": "f_afs_escape_pod_seat", "name": "escape pod seat", "copy-from": "f_seat_airplane", - "description": "The cushioned and upright facing seat of single-seater escape pod. A storage space beneath it holds survival supplies.", + "description": "The cushioned and upright facing seat of a single-seater escape pod. A storage space beneath it holds survival supplies.", "symbol": "H", "color": "light_red", "flags": [ "TRANSPARENT", "FLAMMABLE_ASH", "ORGANIC", "MOUNTABLE", "CAN_SIT" ], @@ -358,7 +358,7 @@ "id": "f_neuralnet_inserter", "name": "neural net inserter", "looks_like": "f_drill_press", - "description": "This device looks like a cross between some kind of nightmare dentistry equipment and socketing tool mounted on a slide that lets it drop precisely down. Useful for those project that require putting delicate items into hard to reach spaces.", + "description": "This device looks like a cross between some kind of nightmare dentistry equipment and socketing tool mounted on a slide that lets it drop precisely down. Useful for those projects that require putting delicate items into hard to reach spaces.", "symbol": "7", "color": "yellow_red", "move_cost_mod": -1, @@ -800,7 +800,7 @@ "type": "furniture", "id": "f_toposcan_terminal", "name": "DIRT data interface", - "description": "All-in-one integrated console for a Driving Intelligent Realtime Topography rover-mounted vehicular terrain scanner system. In other words, useless display monitor.", + "description": "All-in-one integrated console for a Driving Intelligent Realtime Topography rover-mounted vehicular terrain scanner system. In other words, a useless display monitor.", "looks_like": "f_console", "symbol": "?", "color": "light_gray", diff --git a/data/mods/Aftershock/maps/terrain_floraxeno.json b/data/mods/Aftershock/maps/terrain_floraxeno.json index 942bf4cba1afd..3a67dc85bae55 100644 --- a/data/mods/Aftershock/maps/terrain_floraxeno.json +++ b/data/mods/Aftershock/maps/terrain_floraxeno.json @@ -3,7 +3,7 @@ "type": "terrain", "id": "t_tree_worm", "name": "leviathan annelids", - "description": "Several massive protusions emerge from the ground, coiled together into a tower. At the top, blue and purple tentacles sway in the wind.", + "description": "Several massive protrusions emerge from the ground, coiled together into a tower. At the top, blue and purple tentacles sway in the wind.", "symbol": "I", "color": "magenta", "move_cost": 0, diff --git a/data/mods/Aftershock/maps/terrain_groundxeno.json b/data/mods/Aftershock/maps/terrain_groundxeno.json index c19729963bec1..f21d78887f670 100644 --- a/data/mods/Aftershock/maps/terrain_groundxeno.json +++ b/data/mods/Aftershock/maps/terrain_groundxeno.json @@ -417,7 +417,7 @@ "type": "terrain", "id": "t_moxfloor", "name": "bleached coral floor", - "description": "Small outgrowths of white coral spring from a underlying lattice of black, pulsating veins.", + "description": "Small outgrowths of white coral spring from an underlying lattice of black, pulsating veins.", "symbol": ".", "looks_like": "t_fungus", "color": "light_red", diff --git a/data/mods/Aftershock/mobs/robots.json b/data/mods/Aftershock/mobs/robots.json index e8599b7875209..1130c4303e408 100644 --- a/data/mods/Aftershock/mobs/robots.json +++ b/data/mods/Aftershock/mobs/robots.json @@ -174,7 +174,7 @@ "id": "afs_mon_sentinel_lx", "type": "MONSTER", "name": { "str": "Wraitheon Sentinel-lx" }, - "description": "Its exterior plates sable and gold, this luxurious variant of a Wraitheon drone was once kept as a bodyguard by society's wealthiest. Still with its wrist sword extended, it resembles an ancient knight, standing an eternal watch.", + "description": "Its exterior plates are sable and gold, this luxurious variant of a Wraitheon drone was once kept as a bodyguard by society's wealthiest. Still with its wrist sword extended, it resembles an ancient knight, standing an eternal watch.", "default_faction": "WraitheonRobotics", "species": [ "ROBOT" ], "diff": 10, @@ -534,7 +534,7 @@ "type": "MONSTER", "copy-from": "mon_milbot_base", "name": "Wraitheon Hashashiyyin", - "description": "he Hashashiyyin is unorthodox in its design as a military humaniform. While it keeps the strength of most Wraitheon humaniforms, it also prioritizes stealth. It comes equipped with an integrated 5x50mm flechette gun.", + "description": "The Hashashiyyin is unorthodox in its design as a military humaniform. While it keeps the strength of most Wraitheon humaniforms, it also prioritizes stealth. It comes equipped with an integrated 5x50mm flechette gun.", "diff": 15, "melee_damage": [ { "damage_type": "electric", "amount": 6 } ], "starting_ammo": { "5x50dart": 1000 }, diff --git a/data/mods/Aftershock/mobs/water_mobs.json b/data/mods/Aftershock/mobs/water_mobs.json index 221f98237faf8..c1edc8b8e750c 100644 --- a/data/mods/Aftershock/mobs/water_mobs.json +++ b/data/mods/Aftershock/mobs/water_mobs.json @@ -3,7 +3,7 @@ "id": "mon_deep_go", "type": "MONSTER", "name": { "str": "deep one" }, - "description": "An alien that appears to have evolved for survival in the depths. Its tubular grey body bears numerous sets of paired appendages of with clawed portrusions, and a pair of thick muscular fins. You see glimpses of its shape, shifting in and out of the water.", + "description": "An alien that appears to have evolved for survival in the depths. Its tubular grey body bears numerous sets of paired appendages with clawed protrusions, and a pair of thick muscular fins. You see glimpses of its shape, shifting in and out of the water.", "default_faction": "mi-go", "bodytype": "migo", "species": [ "NETHER" ], @@ -54,7 +54,7 @@ "id": "mon_deep_go_slaver", "type": "MONSTER", "name": { "str": "deep one slaver" }, - "description": "An alien that appears to have evolved for survival in the depths. Its tubular grey body bears numerous sets of paired appendages of with clawed portrusions, and a pair of thick muscular fins. You see glimpses of its shape, shifting in and out of the water. It is carrying a conical object that hums with an odd keening sound.", + "description": "An alien that appears to have evolved for survival in the depths. Its tubular grey body bears numerous sets of paired appendages with clawed protrusions, and a pair of thick muscular fins. You see glimpses of its shape, shifting in and out of the water. It is carrying a conical object that hums with an odd keening sound.", "default_faction": "mi-go", "bodytype": "migo", "species": [ "NETHER" ], diff --git a/data/mods/Aftershock/mutations/mutations.json b/data/mods/Aftershock/mutations/mutations.json index 1a35967601017..24122b71cf8ab 100644 --- a/data/mods/Aftershock/mutations/mutations.json +++ b/data/mods/Aftershock/mutations/mutations.json @@ -269,7 +269,7 @@ "id": "EERIE", "name": "Eerie", "points": 1, - "description": "You are offputting to others. You're mannerisms have changed as if human interaction is becoming foreign.", + "description": "You are off-putting to others. Your mannerisms have changed as if human interaction is becoming foreign.", "category": [ "MIGO" ], "social_modifiers": { "persuade": -15, "lie": -10 }, "ugliness": 2 @@ -629,7 +629,7 @@ "name": "Trumpeting Voice", "points": -1, "mixed_effect": true, - "description": "You have a trumpeting, elephantine voice. Threatening NPCs will be easier, but lying will very hard.", + "description": "You have a trumpeting, elephantine voice. Threatening NPCs will be easier, but lying will be very hard.", "changes_to": [ "SNARL" ], "category": [ "MASTODON" ], "social_modifiers": { "lie": -30, "intimidate": 10 } diff --git a/data/mods/Aftershock/mutations/obsolete.json b/data/mods/Aftershock/mutations/obsolete.json index f68356232f2bd..5b24fe475aa15 100644 --- a/data/mods/Aftershock/mutations/obsolete.json +++ b/data/mods/Aftershock/mutations/obsolete.json @@ -284,7 +284,7 @@ "points": -2, "visibility": 4, "ugliness": 5, - "description": "You smell like exactly like a shaggy elephant would, assuming it sweated, which you do. Monsters that track scent will find you very easily, and humans will react poorly.", + "description": "You smell exactly like a shaggy elephant would, assuming it sweated, which you do. Monsters that track scent will find you very easily, and humans will react poorly.", "valid": false, "scent_intensity": 1200, "prereqs": [ "ELEPHANTINE_SMELL" ], diff --git a/data/mods/Aftershock/player/professions.json b/data/mods/Aftershock/player/professions.json index 35ee54c408a08..f23c6ca95c82c 100644 --- a/data/mods/Aftershock/player/professions.json +++ b/data/mods/Aftershock/player/professions.json @@ -107,7 +107,7 @@ "type": "profession", "id": "afs_atomic_pitchman", "name": { "male": "Atomic Pitchman", "female": "Atomic Pitchwoman" }, - "description": "You were hired to market Rivtech's products through TV and were on your way to the studio when the bombs hit. You enter now the end of the world with nothing but the snazzy clothes on your back and a bunch of plutonium-powered toys.", + "description": "You were hired to market Rivtech's products through TV and were on your way to the studio when the bombs hit. You now enter the end of the world with nothing but the snazzy clothes on your back and a bunch of plutonium-powered toys.", "points": 3, "skills": [ { "level": 1, "name": "speech" } ], "items": { @@ -192,7 +192,7 @@ "id": "afs_wraitheon_executive", "name": "Wraitheon Executive", "description": { - "str": "You were one of the chief executives of the Megacorporation Wraitheon Robotics ltd. and consistently ranked among the most powerful and influential persons of the world. Still, the apocalypse has caught you unprepared, and now after the dissolution of your company and the crumbling of your network of influence, your were left powerless and destitute, and must rely on your two robotic bodyguards to survive.", + "str": "You were one of the chief executives of the Megacorporation Wraitheon Robotics ltd. and consistently ranked among the most powerful and influential persons of the world. Still, the apocalypse has caught you unprepared, and now after the dissolution of your company and the crumbling of your network of influence, you are left powerless and destitute, and must rely on your two robotic bodyguards to survive.", "//NOLINT(cata-text-style)": "not a period" }, "points": 8, diff --git a/data/mods/Aftershock/scenarios.json b/data/mods/Aftershock/scenarios.json index d088fd7efa4da..2028f491d72e2 100644 --- a/data/mods/Aftershock/scenarios.json +++ b/data/mods/Aftershock/scenarios.json @@ -88,7 +88,7 @@ "id": "escape_pod", "name": "Stranded Spacer", "points": 1, - "description": "What was to be a routine cargo transfer ended in tragedy when, in a brief moment of chaos, your space ship was intercepted and destroyed by a StO missile. As soon as the MAW alarm flared to life, you scrambled to the nearest escape pod and barely managed reach the uncertain safety of the planet below.", + "description": "What was to be a routine cargo transfer ended in tragedy when, in a brief moment of chaos, your space ship was intercepted and destroyed by a StO missile. As soon as the MAW alarm flared to life, you scrambled to the nearest escape pod and barely managed to reach the uncertain safety of the planet below.", "allowed_locs": [ "sloc_escape_pod" ], "professions": [ "afs_espatier", "afs_rating" ], "flags": [ "LONE_START" ], From dae6396f2925164ac86edb14c3b3c4f700147a06 Mon Sep 17 00:00:00 2001 From: Lamandus <33199510+Lamandus@users.noreply.github.com> Date: Wed, 3 Mar 2021 23:47:20 +0100 Subject: [PATCH 026/453] Tweaks for teas (#47848) --- data/json/items/comestibles/drink.json | 29 ++++++++++++---------- data/json/items/comestibles/other.json | 3 +-- data/json/items/comestibles/raw_veggy.json | 9 ++++--- 3 files changed, 22 insertions(+), 19 deletions(-) diff --git a/data/json/items/comestibles/drink.json b/data/json/items/comestibles/drink.json index 767e3acc26509..cf5f49f876cf7 100644 --- a/data/json/items/comestibles/drink.json +++ b/data/json/items/comestibles/drink.json @@ -102,7 +102,8 @@ "description": "A healthy beverage made from bee balm steeped in boiling water. Can be used to reduce negative effects of common cold or flu.", "price": 100, "price_postapoc": 25, - "fun": 1 + "fun": 1, + "flags": [ "EATEN_HOT" ] }, { "type": "COMESTIBLE", @@ -162,10 +163,11 @@ "spoils_in": "10 days", "quench": 34, "healthy": 1, - "calories": 0, + "calories": 1, "description": "A healthy beverage made from chamomile flowers steeped in boiling water. Can be used to treat insomnia.", "price": 100, "price_postapoc": 25, + "flags": [ "EATEN_HOT", "NUTRIENT_OVERRIDE" ], "fun": 1 }, { @@ -388,14 +390,14 @@ "symbol": "~", "quench": 48, "healthy": 1, - "calories": 26, + "calories": 1, "description": "A healthy beverage made from dandelion roots steeped in boiling water.", "price": 50, "price_postapoc": 25, "volume": "250 ml", "material": [ "water" ], "phase": "liquid", - "flags": [ "EATEN_HOT" ], + "flags": [ "EATEN_HOT", "NUTRIENT_OVERRIDE" ], "fun": 2 }, { @@ -496,14 +498,14 @@ "symbol": "~", "quench": 44, "healthy": 1, - "calories": 9, + "calories": 1, "description": "A healthy beverage made from herbs steeped in boiling water.", "price": 100, "price_postapoc": 25, "volume": "250 ml", "material": [ "water" ], "phase": "liquid", - "flags": [ "EATEN_HOT" ], + "flags": [ "EATEN_HOT", "NUTRIENT_OVERRIDE" ], "fun": 4 }, { @@ -646,11 +648,11 @@ "spoils_in": "10 days", "quench": 34, "healthy": 1, - "calories": 0, "description": "A healthy beverage made from lotus flowers steeped in boiling water.", "price": 100, "price_postapoc": 25, - "fun": 1 + "fun": 1, + "flags": [ "EATEN_HOT", "NUTRIENT_OVERRIDE" ] }, { "id": "mex_chocolate", @@ -769,7 +771,8 @@ "phase": "liquid", "charges": 2, "vitamins": [ [ "vitA", 5 ], [ "vitB", 3 ], [ "vitC", 2 ], [ "calcium", 12 ] ], - "fun": 10 + "fun": 10, + "flags": [ "EATEN_HOT" ] }, { "type": "COMESTIBLE", @@ -832,6 +835,7 @@ "price": 0, "price_postapoc": 25, "volume": "250 ml", + "calories": 1, "material": [ "water" ], "phase": "liquid", "flags": [ "EATEN_HOT", "NUTRIENT_OVERRIDE" ], @@ -964,11 +968,12 @@ "spoils_in": "10 days", "quench": 34, "healthy": 1, - "calories": 0, + "calories": 1, "description": "A healthy beverage made from spurge flowers steeped in boiling water. Can be used to prevent asthma attacks.", "price": 100, "price_postapoc": 25, "fun": 1, + "flags": [ "EATEN_HOT", "NUTRIENT_OVERRIDE" ], "use_action": { "type": "consume_drug", "activation_message": "You no longer need to worry about asthma attacks, at least for a while.", @@ -1027,7 +1032,7 @@ "comestible_type": "DRINK", "symbol": "~", "quench": 40, - "calories": 2, + "calories": 1, "description": "The beverage of gentlemen everywhere, made from applying hot water to oxidized leaves of the tea plant /Camellia sinensis/.", "price": 90, "price_postapoc": 25, @@ -1133,7 +1138,6 @@ "color": "green", "fatigue_mod": 7, "stim": 2, - "calories": 2, "description": "Made from applying hot water to leaves of the tea plant /Camellia sinensis/. Green tea has a lighter, fresher taste than black and is traditionally preferred in Asian cultures." }, { @@ -1142,7 +1146,6 @@ "name": { "str": "fruit tea" }, "copy-from": "tea", "color": "red", - "calories": 0, "fatigue_mod": 0, "stim": 0, "description": "A tasty beverage made with herbs and dried fruit from plants other than the tea plant. While colloquially called 'tea', technically it's an infusion.", diff --git a/data/json/items/comestibles/other.json b/data/json/items/comestibles/other.json index 7aea6e36a17d6..7f30fadddfd09 100644 --- a/data/json/items/comestibles/other.json +++ b/data/json/items/comestibles/other.json @@ -853,6 +853,7 @@ "color": "white", "symbol": "?", "container": "box_tea", + "calories": 1, "material": [ "paper" ], "price": 50, "price_postapoc": 200, @@ -878,7 +879,6 @@ "type": "COMESTIBLE", "name": { "str": "herbal tea bag" }, "copy-from": "tea_bag", - "calories": 9, "description": "A paper sachet with dried wild herbs inside. Put it into boiling water to make a cup of herbal tea." }, { @@ -886,7 +886,6 @@ "type": "COMESTIBLE", "name": { "str": "dandelion tea bag" }, "copy-from": "tea_bag", - "calories": 26, "description": "A paper sachet with dried dandelion roots inside. Put it into boiling water to make a cup of dandelion tea." }, { diff --git a/data/json/items/comestibles/raw_veggy.json b/data/json/items/comestibles/raw_veggy.json index cb384ab5531e4..4a9eb15fbc77d 100644 --- a/data/json/items/comestibles/raw_veggy.json +++ b/data/json/items/comestibles/raw_veggy.json @@ -736,22 +736,23 @@ "type": "COMESTIBLE", "id": "tea_raw", "name": { "str": "black tea leaf", "str_pl": "black tea leaves" }, - "weight": "14 g", + "weight": "3 g", "color": "green", "fatigue_mod": 3, "stim": 1, "container": "bag_plastic", "comestible_type": "FOOD", "symbol": "%", - "calories": 17, + "calories": 1, "description": "Dried leaves of a tropical plant. You can boil them into tea, or you can just eat them raw. They aren't too filling though.", "price": 1030, "price_postapoc": 250, "material": [ "veggy" ], "primary_material": "dried_vegetable", - "volume": "250 ml", + "volume": "320 ml", "flags": [ "EDIBLE_FROZEN", "RAW", "IRREPLACEABLE_CONSUMABLE" ], - "charges": 20, + "charges": 33, + "//": "Tea is sold by weight not by volume. 1 kg of tea has a volume of 3,4 liters. We use smaller packs of at least 100 mg. Such a tea has a volume of 340 ml minus package makes it around 320 ml. 3 g per serving makes 33 charges.", "fun": -1 }, { From 39e4360de3449da6a7d772efb8b3f94903b569d6 Mon Sep 17 00:00:00 2001 From: actual-nh <74678550+actual-nh@users.noreply.github.com> Date: Tue, 2 Mar 2021 19:46:22 -0500 Subject: [PATCH 027/453] Have travis run for 0.F-dev (#47844) Currently, .travis.yml has a 'development' branch specified as one to run tests for; the current equivalent is the 0.F-dev branch. --- .travis.yml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/.travis.yml b/.travis.yml index 0318807d6fb86..194cd80956d65 100644 --- a/.travis.yml +++ b/.travis.yml @@ -27,7 +27,7 @@ os: linux branches: only: - master - - development + - 0.F-dev # Overall strategy for what sorts of builds to include: # We want a build for each compiler and each platform. From 36c0f6a3cadf77a24335a960591859350e32cfd2 Mon Sep 17 00:00:00 2001 From: Lamandus <33199510+Lamandus@users.noreply.github.com> Date: Wed, 3 Mar 2021 23:51:31 +0100 Subject: [PATCH 028/453] Tweakes to copper and metal pipes. (#47825) --- data/json/items/resources/metal.json | 10 ++++++---- 1 file changed, 6 insertions(+), 4 deletions(-) diff --git a/data/json/items/resources/metal.json b/data/json/items/resources/metal.json index 45d9ae1a6123c..a1496900e4f17 100644 --- a/data/json/items/resources/metal.json +++ b/data/json/items/resources/metal.json @@ -3,16 +3,17 @@ "type": "GENERIC", "id": "pipe", "name": { "str": "pipe" }, - "description": "A steel pipe, makes a good melee weapon. Useful in a few crafting recipes.", + "description": "A steel pipe; makes a good melee weapon. Useful in a few crafting recipes.", "category": "spare_parts", "weight": "1250 g", + "longest_side": "60 cm", "to_hit": 1, "color": "dark_gray", "symbol": "/", "material": [ "steel" ], "qualities": [ [ "HAMMER", 1 ] ], "techniques": [ "WBLOCK_1" ], - "volume": "1 L", + "volume": "370 ml", "bashing": 12, "price": 7500, "price_postapoc": 10 @@ -57,15 +58,16 @@ "type": "GENERIC", "id": "cu_pipe", "name": { "str": "copper tubing" }, - "description": "A copper tube, too thin to be much use as a melee weapon, but will do if nothing else is available. Useful in a few crafting recipes.", + "description": "A copper tube; too thin to be much use as a melee weapon, but will do if nothing else is available. Useful in a few crafting recipes.", "category": "spare_parts", "weight": "345 g", + "longest_side": "60 cm", "to_hit": -1, "color": "light_red", "symbol": "/", "material": [ "copper" ], "techniques": [ "WBLOCK_1" ], - "volume": "500 ml", + "volume": "370 ml", "bashing": 5, "price": 7500, "price_postapoc": 10 From eca03f6098cbf31b05e04c36fd02953b505d6ec5 Mon Sep 17 00:00:00 2001 From: Maleclypse <54345792+Maleclypse@users.noreply.github.com> Date: Wed, 3 Mar 2021 17:00:47 -0600 Subject: [PATCH 029/453] Fried eggs deluxe, sandwiches, and condiment list (#47786) --- data/json/items/comestibles/egg.json | 48 ++++++++++++++ data/json/recipes/recipe_food.json | 65 +++++++++++++++++++ .../json/requirements/cooking_components.json | 17 +++++ 3 files changed, 130 insertions(+) diff --git a/data/json/items/comestibles/egg.json b/data/json/items/comestibles/egg.json index 5d17be2fbaa06..d06956948c024 100644 --- a/data/json/items/comestibles/egg.json +++ b/data/json/items/comestibles/egg.json @@ -354,6 +354,54 @@ "fun": 2, "flags": [ "EATEN_HOT", "FREEZERBURN" ] }, + { + "type": "COMESTIBLE", + "id": "deluxe_fried_eggs", + "name": { "str_sp": "deluxe fried eggs" }, + "copy-from": "scrambled_eggs", + "color": "yellow", + "symbol": "%", + "quench": -1, + "calories": 322, + "description": "Deluxe sunny-side up eggs fried with a runny yolk and just a bit of crisp on the edges with cheese or a vegetable, garnish and condiment.", + "price": 500, + "price_postapoc": 120, + "material": [ "egg", "veggy" ], + "fun": 2, + "flags": [ "EATEN_HOT", "FREEZERBURN" ] + }, + { + "type": "COMESTIBLE", + "id": "fried_egg_sandwich", + "name": { "str_sp": "fried egg sandwich" }, + "copy-from": "scrambled_eggs", + "color": "yellow", + "symbol": "%", + "quench": -1, + "calories": 422, + "description": "Sunny-side up eggs fried with a runny yolk and just a bit of crisp on the edges. Made into a sandwich, just like Sunday morning.", + "price": 500, + "price_postapoc": 120, + "material": [ "egg", "wheat" ], + "fun": 2, + "flags": [ "EATEN_HOT", "FREEZERBURN" ] + }, + { + "type": "COMESTIBLE", + "id": "deluxe_fried_egg_sandwich", + "name": { "str_sp": "deluxe fried egg sandwich" }, + "copy-from": "scrambled_eggs", + "color": "yellow", + "symbol": "%", + "quench": -1, + "calories": 422, + "description": "Deluxe sunny-side up eggs fried with a runny yolk and just a bit of crisp on the edges. Made into a sandwich, just like Sunday morning.", + "price": 500, + "price_postapoc": 120, + "material": [ "egg", "wheat" ], + "fun": 2, + "flags": [ "EATEN_HOT", "FREEZERBURN" ] + }, { "type": "COMESTIBLE", "id": "pickled_egg", diff --git a/data/json/recipes/recipe_food.json b/data/json/recipes/recipe_food.json index 6b8706fc18a1b..16da46e19d8e1 100644 --- a/data/json/recipes/recipe_food.json +++ b/data/json/recipes/recipe_food.json @@ -3611,6 +3611,71 @@ "tools": [ [ [ "surface_heat", 2, "LIST" ] ] ], "components": [ [ [ "eggs_bird", 2, "LIST" ], [ "egg_reptile", 2 ] ], [ [ "any_butter_or_oil", 2, "LIST" ] ] ] }, + { + "type": "recipe", + "activity_level": "LIGHT_EXERCISE", + "result": "deluxe_fried_eggs", + "category": "CC_FOOD", + "subcategory": "CSC_FOOD_OTHER", + "skill_used": "cooking", + "difficulty": 2, + "time": "8 m", + "autolearn": true, + "batch_time_factors": [ 80, 2 ], + "qualities": [ { "id": "COOK", "level": 2 } ], + "tools": [ [ [ "surface_heat", 2, "LIST" ] ] ], + "components": [ + [ [ "eggs_bird", 2, "LIST" ], [ "egg_reptile", 2 ] ], + [ [ "any_butter_or_oil", 2, "LIST" ] ], + [ [ "mushroom", 1 ], [ "mushroom_morel", 1 ], [ "garlic_clove", 1 ], [ "onion", 1 ] ], + [ [ "cheese", 1 ], [ "cheese_hard", 1 ], [ "can_cheese", 1 ], [ "veggy_green", 1, "LIST" ] ], + [ [ "salt_preservation", 2, "LIST" ] ], + [ [ "condiment", 2, "LIST" ] ] + ] + }, + { + "type": "recipe", + "activity_level": "LIGHT_EXERCISE", + "result": "fried_egg_sandwich", + "category": "CC_FOOD", + "subcategory": "CSC_FOOD_OTHER", + "skill_used": "cooking", + "difficulty": 2, + "time": "6 m", + "autolearn": true, + "batch_time_factors": [ 80, 2 ], + "qualities": [ { "id": "COOK", "level": 2 } ], + "tools": [ [ [ "surface_heat", 2, "LIST" ] ] ], + "components": [ + [ [ "eggs_bird", 2, "LIST" ], [ "egg_reptile", 2 ] ], + [ [ "any_butter_or_oil", 2, "LIST" ] ], + [ [ "bread_sandwich", 2, "LIST" ] ], + [ [ "condiment", 2, "LIST" ] ] + ] + }, + { + "type": "recipe", + "activity_level": "LIGHT_EXERCISE", + "result": "deluxe_fried_egg_sandwich", + "category": "CC_FOOD", + "subcategory": "CSC_FOOD_OTHER", + "skill_used": "cooking", + "difficulty": 2, + "time": "8 m", + "autolearn": true, + "batch_time_factors": [ 80, 2 ], + "qualities": [ { "id": "COOK", "level": 2 } ], + "tools": [ [ [ "surface_heat", 2, "LIST" ] ] ], + "components": [ + [ [ "eggs_bird", 2, "LIST" ], [ "egg_reptile", 2 ] ], + [ [ "any_butter_or_oil", 2, "LIST" ] ], + [ [ "mushroom", 1 ], [ "mushroom_morel", 1 ], [ "garlic_clove", 1 ], [ "onion", 1 ] ], + [ [ "cheese", 1 ], [ "cheese_hard", 1 ], [ "can_cheese", 1 ], [ "veggy_green", 1, "LIST" ] ], + [ [ "salt_preservation", 2, "LIST" ] ], + [ [ "condiment", 2, "LIST" ] ], + [ [ "bread_sandwich", 2, "LIST" ] ] + ] + }, { "type": "recipe", "activity_level": "NO_EXERCISE", diff --git a/data/json/requirements/cooking_components.json b/data/json/requirements/cooking_components.json index f951bc13d5150..5b2913d707145 100644 --- a/data/json/requirements/cooking_components.json +++ b/data/json/requirements/cooking_components.json @@ -544,6 +544,23 @@ ] ] }, + { + "id": "condiment", + "type": "requirement", + "//": " Should be about a teaspoon, or smallest serving", + "components": [ + [ + [ "mayonnaise", 1 ], + [ "mustard", 1 ], + [ "soysauce", 1 ], + [ "hot_sauce", 1 ], + [ "ketchup", 1 ], + [ "horseradish", 1 ], + [ "sauerkraut", 1 ], + [ "butter", 1 ] + ] + ] + }, { "id": "salt_preservation", "type": "requirement", From 87ed116f06e1c61820eb1ed96610e1a517415d1a Mon Sep 17 00:00:00 2001 From: Maleclypse <54345792+Maleclypse@users.noreply.github.com> Date: Wed, 3 Mar 2021 17:02:28 -0600 Subject: [PATCH 030/453] Homemade toastems, buttercream frosting and recipes (#47696) --- data/json/items/comestibles/junkfood.json | 45 +++++++++++++++++++ data/json/recipes/recipe_food.json | 53 +++++++++++++++++++++++ 2 files changed, 98 insertions(+) diff --git a/data/json/items/comestibles/junkfood.json b/data/json/items/comestibles/junkfood.json index f3288ba8378ac..1e6b73eaa5ebd 100644 --- a/data/json/items/comestibles/junkfood.json +++ b/data/json/items/comestibles/junkfood.json @@ -37,6 +37,14 @@ "description": "Dry toaster pastries, usually coated with solid frosting. Sadly, these are not.", "fun": 10 }, + { + "type": "COMESTIBLE", + "id": "toastem4", + "name": { "str": "homemade toast-em" }, + "copy-from": "toastem", + "description": "Homemade toaster pastries, lacking icing but at least fruit filled.", + "fun": 10 + }, { "type": "COMESTIBLE", "id": "toasterpastryfrozen", @@ -68,6 +76,43 @@ "description": "A delicious fruit-filled pastry that you've cooked. It even comes with frosting!", "fun": 20 }, + { + "type": "COMESTIBLE", + "id": "homemade_toasterpastry", + "name": { "str": "toaster pastry", "str_pl": "toaster pastries" }, + "copy-from": "toasterpastryfrozen", + "quench": 4, + "description": "A delicious homemade fruit-filled pastry that you've cooked.", + "fun": 20 + }, + { + "type": "COMESTIBLE", + "id": "homemade_toasterpastry2", + "name": { "str": "toaster pastry with buttercream", "str_pl": "toaster pastries with buttercream" }, + "copy-from": "toasterpastryfrozen", + "quench": 4, + "description": "A delicious homemade fruit-filled pastry that you've cooked. It even comes with buttercream!", + "fun": 30 + }, + { + "type": "COMESTIBLE", + "id": "buttercream", + "name": { "str": "buttercream icing", "str_pl": "cups of buttercream icing" }, + "weight": "32 g", + "color": "brown", + "container": "bag_plastic", + "comestible_type": "FOOD", + "symbol": "%", + "calories": 288, + "description": "Smooth sugary buttercream icing. Almost good enough to forget the end of everything.", + "price": 100, + "price_postapoc": 400, + "material": [ "junk" ], + "volume": "1 L", + "charges": 8, + "flags": [ "EDIBLE_FROZEN" ], + "fun": 6 + }, { "type": "COMESTIBLE", "id": "chips2", diff --git a/data/json/recipes/recipe_food.json b/data/json/recipes/recipe_food.json index 16da46e19d8e1..c3ab7e4257802 100644 --- a/data/json/recipes/recipe_food.json +++ b/data/json/recipes/recipe_food.json @@ -5382,6 +5382,20 @@ "book_learn": [ [ "mag_glam", 1 ] ], "components": [ [ [ "bread_sandwich", 1, "LIST" ] ], [ [ "any_butter", 1, "LIST" ] ], [ [ "sprinkles", 3 ] ] ] }, + { + "type": "recipe", + "activity_level": "LIGHT_EXERCISE", + "result": "toastem4", + "category": "CC_FOOD", + "subcategory": "CSC_FOOD_SNACK", + "skill_used": "cooking", + "time": "40 m", + "charges": 6, + "book_learn": [ [ "baking_book", 1 ] ], + "qualities": [ { "id": "CUT", "level": 1 }, { "id": "COOK", "level": 2 } ], + "tools": [ [ [ "surface_heat", 20, "LIST" ] ] ], + "components": [ [ [ "flour", 12 ] ], [ [ "eggs_bird", 1, "LIST" ] ], [ [ "jam_fruit", 9 ] ], [ [ "cornmeal", 1 ] ] ] + }, { "type": "recipe", "activity_level": "LIGHT_EXERCISE", @@ -5395,6 +5409,45 @@ "tools": [ [ [ "surface_heat", 10, "LIST" ] ] ], "components": [ [ [ "toasterpastryfrozen", 1 ] ] ] }, + { + "type": "recipe", + "activity_level": "LIGHT_EXERCISE", + "result": "homemade_toasterpastry", + "category": "CC_FOOD", + "subcategory": "CSC_FOOD_SNACK", + "skill_used": "cooking", + "time": "2 m 30 s", + "charges": 1, + "autolearn": true, + "tools": [ [ [ "surface_heat", 10, "LIST" ] ] ], + "components": [ [ [ "toastem4", 1 ] ] ] + }, + { + "type": "recipe", + "activity_level": "LIGHT_EXERCISE", + "result": "homemade_toasterpastry2", + "category": "CC_FOOD", + "subcategory": "CSC_FOOD_SNACK", + "skill_used": "cooking", + "time": "2 m 30 s", + "charges": 1, + "autolearn": true, + "tools": [ [ [ "surface_heat", 10, "LIST" ] ] ], + "components": [ [ [ "toastem4", 1 ] ], [ [ "buttercream", 1 ] ] ] + }, + { + "type": "recipe", + "activity_level": "LIGHT_EXERCISE", + "result": "buttercream", + "category": "CC_FOOD", + "subcategory": "CSC_FOOD_SNACK", + "skill_used": "cooking", + "difficulty": 1, + "time": "6 m 30 s", + "autolearn": true, + "qualities": [ { "id": "COOK", "level": 1 } ], + "components": [ [ [ "milk_cream", 1 ] ], [ [ "butter", 16 ] ], [ [ "sugar_standard", 1, "LIST" ] ] ] + }, { "type": "recipe", "activity_level": "LIGHT_EXERCISE", From 8efe10aa1f35e26d543a2978ce9b0bd48be7ae88 Mon Sep 17 00:00:00 2001 From: Fris0uman Date: Fri, 19 Feb 2021 18:20:04 +0100 Subject: [PATCH 031/453] [My Sweet Cataclysm] Chocolate Cows don't drop "cow pies" (#47609) --- data/mods/My_Sweet_Cataclysm/sweet_items.json | 17 +++++++++++++++++ .../mods/My_Sweet_Cataclysm/sweet_monsters.json | 2 ++ 2 files changed, 19 insertions(+) diff --git a/data/mods/My_Sweet_Cataclysm/sweet_items.json b/data/mods/My_Sweet_Cataclysm/sweet_items.json index 274223cca9368..9def6b336f864 100644 --- a/data/mods/My_Sweet_Cataclysm/sweet_items.json +++ b/data/mods/My_Sweet_Cataclysm/sweet_items.json @@ -28,6 +28,23 @@ "calories": 10, "vitamins": [ ] }, + { + "type": "COMESTIBLE", + "comestible_type": "FOOD", + "id": "feces_candy", + "symbol": "^", + "name": { "str_sp": "sticky sludge" }, + "charges": 10, + "volume": "1000 ml", + "weight": "100 g", + "color": "white", + "looks_like": "ruined_candy", + "description": "A pile of weird sticky sludge. It looks absolutly disgusting but smells kind of sweet.", + "material": [ "junk" ], + "calories": 10, + "fun": -12, + "vitamins": [ ] + }, { "id": "rock_candy_chunk", "type": "TOOL", diff --git a/data/mods/My_Sweet_Cataclysm/sweet_monsters.json b/data/mods/My_Sweet_Cataclysm/sweet_monsters.json index 81894d4a8f671..5d5e1d9266c71 100644 --- a/data/mods/My_Sweet_Cataclysm/sweet_monsters.json +++ b/data/mods/My_Sweet_Cataclysm/sweet_monsters.json @@ -491,6 +491,7 @@ "description": "The domestic cow, a baleful, ruminating farm animal. It is quite muscular, and the males can have a violent streak to accompany their nasty-looking horns. This one looks to be made entirely of chocolate.", "copy-from": "mon_cow_calf", "harvest": "choc_cows", + "biosignature": { "biosig_item": "feces_candy", "biosig_timer": "1 d" }, "upgrades": { "age_grow": 180, "into": "mon_cow_choc" } }, { @@ -501,6 +502,7 @@ "copy-from": "mon_cow", "harvest": "choc_cows", "starting_ammo": { "milk_raw_choc": 40 }, + "biosignature": { "biosig_item": "feces_candy", "biosig_timer": "1 d" }, "reproduction": { "baby_monster": "mon_cow_calf_choc", "baby_count": 1, "baby_timer": 343 } }, { From 6a826e8dd68bf58e45f337ca1c838ec4ccd45ce6 Mon Sep 17 00:00:00 2001 From: Fris0uman Date: Wed, 3 Mar 2021 18:22:23 +0100 Subject: [PATCH 032/453] Remove unused FATIGUE energy source from spells (#47852) --- data/mods/Magiclysm/Spells/debug.json | 15 --------------- doc/MAGIC.md | 2 +- src/activity_handlers.cpp | 3 --- src/magic.cpp | 12 ------------ src/magic.h | 1 - 5 files changed, 1 insertion(+), 32 deletions(-) diff --git a/data/mods/Magiclysm/Spells/debug.json b/data/mods/Magiclysm/Spells/debug.json index a0ac89ceecd15..c99193044fa48 100644 --- a/data/mods/Magiclysm/Spells/debug.json +++ b/data/mods/Magiclysm/Spells/debug.json @@ -112,21 +112,6 @@ "base_energy_cost": 100, "energy_source": "STAMINA" }, - { - "id": "debug_fatigue", - "type": "SPELL", - "name": "Debug Fatigue Spell", - "description": "Uses a little fatigue", - "message": "Debug spell %s cast.", - "valid_targets": [ "self" ], - "effect": "none", - "shape": "blast", - "min_range": 1, - "max_range": 1, - "base_casting_time": 100, - "base_energy_cost": 100, - "energy_source": "FATIGUE" - }, { "id": "debug_polymorph", "type": "SPELL", diff --git a/doc/MAGIC.md b/doc/MAGIC.md index eb74d0bf4b570..9d66f225036f4 100644 --- a/doc/MAGIC.md +++ b/doc/MAGIC.md @@ -21,7 +21,7 @@ In `data/mods/Magiclysm` there is a template spell, copied here for your perusal "spell_class": "NONE", // "base_casting_time": 100, // this is the casting time (in moves) "base_energy_cost": 10, // the amount of energy (of the requisite type) to cast the spell - "energy_source": "MANA", // the type of energy used to cast the spell. types are: MANA, BIONIC, HP, STAMINA, FATIGUE, NONE (none will not use mana) + "energy_source": "MANA", // the type of energy used to cast the spell. types are: MANA, BIONIC, HP, STAMINA, NONE (none will not use mana) "components": [requirement_id] // an id from a requirement, like the ones you use for crafting. spell components require to cast. "difficulty": 12, // the difficulty to learn/cast the spell "max_level": 10, // maximum level you can achieve in the spell diff --git a/src/activity_handlers.cpp b/src/activity_handlers.cpp index 8deb436a90773..76423042b7f4f 100644 --- a/src/activity_handlers.cpp +++ b/src/activity_handlers.cpp @@ -4275,9 +4275,6 @@ void activity_handlers::spellcasting_finish( player_activity *act, player *p ) case magic_energy_type::hp: blood_magic( p, cost ); break; - case magic_energy_type::fatigue: - p->mod_fatigue( cost ); - break; case magic_energy_type::none: default: break; diff --git a/src/magic.cpp b/src/magic.cpp index f9ddd69fde511..9d42d3c71050f 100644 --- a/src/magic.cpp +++ b/src/magic.cpp @@ -153,7 +153,6 @@ std::string enum_to_string( magic_energy_type data ) { switch( data ) { case magic_energy_type::bionic: return "BIONIC"; - case magic_energy_type::fatigue: return "FATIGUE"; case magic_energy_type::hp: return "HP"; case magic_energy_type::mana: return "MANA"; case magic_energy_type::none: return "NONE"; @@ -1047,8 +1046,6 @@ std::string spell::energy_string() const return _( "stamina" ); case magic_energy_type::bionic: return _( "bionic power" ); - case magic_energy_type::fatigue: - return _( "fatigue" ); default: return ""; } @@ -1070,9 +1067,6 @@ std::string spell::energy_cost_string( const Character &guy ) const auto pair = get_hp_bar( energy_cost( guy ), guy.get_stamina_max() ); return colorize( pair.first, pair.second ); } - if( energy_source() == magic_energy_type::fatigue ) { - return colorize( std::to_string( energy_cost( guy ) ), c_cyan ); - } debugmsg( "ERROR: Spell %s has invalid energy source.", id().c_str() ); return _( "error: energy_type" ); } @@ -1095,10 +1089,6 @@ std::string spell::energy_cur_string( const Character &guy ) const if( energy_source() == magic_energy_type::hp ) { return ""; } - if( energy_source() == magic_energy_type::fatigue ) { - const std::pair pair = guy.get_fatigue_description(); - return colorize( pair.first, pair.second ); - } debugmsg( "ERROR: Spell %s has invalid energy source.", id().c_str() ); return _( "error: energy_type" ); } @@ -1729,8 +1719,6 @@ bool known_magic::has_enough_energy( const Character &guy, const spell &sp ) con } } return false; - case magic_energy_type::fatigue: - return guy.get_fatigue() < fatigue_levels::EXHAUSTED; case magic_energy_type::none: return true; default: diff --git a/src/magic.h b/src/magic.h index fe4195a46d1b2..a4b7ed49c7d6f 100644 --- a/src/magic.h +++ b/src/magic.h @@ -82,7 +82,6 @@ enum class magic_energy_type : int { mana, stamina, bionic, - fatigue, none, last }; From 40a4128b2c305f891b2ae7c05b1fd0fa237020ab Mon Sep 17 00:00:00 2001 From: Curtis Merrill Date: Wed, 3 Mar 2021 18:19:31 -0500 Subject: [PATCH 033/453] [Magiclysm] add owlbear origin snippet (#47752) --- data/mods/Magiclysm/snippets/survivor_notes.json | 12 ++++++++++++ 1 file changed, 12 insertions(+) create mode 100644 data/mods/Magiclysm/snippets/survivor_notes.json diff --git a/data/mods/Magiclysm/snippets/survivor_notes.json b/data/mods/Magiclysm/snippets/survivor_notes.json new file mode 100644 index 0000000000000..cd03a44abc5b0 --- /dev/null +++ b/data/mods/Magiclysm/snippets/survivor_notes.json @@ -0,0 +1,12 @@ +[ + { + "type": "snippet", + "category": "note", + "text": [ + { + "id": "magiclysm_note_1", + "text": "\"(Spell Name) RECIPE V3\n---\nRare Ingredients:\n- 17 drams owl's blood - less no effect, more turns bear into large owl\n- 1 gastrolith, large american alligator\n- 3 teeth or claws from a honey badger\n- 8 pounds bear meat, preferably polar bear, grizzly will suffice\nBring a large pot (meat must fully submerge) filled about half way with potion starter fluid (high grade) to a boil. Add gastrolith and teeth/claws after boiling, add the blood, stir counterclockwise for a minute while chanting standard polymorph spell. Continue until concoction has a slight glow. Add the bear meat, remove from heat, cover for 24 hours.\nBear MUST eat all 8 pounds of the meat (claws and gastrolith optional).\n---\n*I've finally gotten my hands on enough polar bear meat. The grizzly variations are a bit lackluster.*\nThere are flecks of blood on the page.\"" + } + ] + } +] From 21228378bd8f5e4a4663efaa2a5b98738ffcb171 Mon Sep 17 00:00:00 2001 From: Curtis Merrill Date: Wed, 3 Mar 2021 18:19:47 -0500 Subject: [PATCH 034/453] [Magiclysm] add lesser banishment spell, buff greater banishment (#47537) --- data/mods/Magiclysm/Spells/animist.json | 21 +++++++++++++++++++ .../Spells/attunements/Blood_Mage.json | 7 +++++-- .../mods/Magiclysm/itemgroups/spellbooks.json | 1 + data/mods/Magiclysm/items/spell_scrolls.json | 9 ++++++++ 4 files changed, 36 insertions(+), 2 deletions(-) diff --git a/data/mods/Magiclysm/Spells/animist.json b/data/mods/Magiclysm/Spells/animist.json index d778743be6535..1d864efb1aa0d 100644 --- a/data/mods/Magiclysm/Spells/animist.json +++ b/data/mods/Magiclysm/Spells/animist.json @@ -221,6 +221,27 @@ "max_range": 30, "range_increment": 1.0 }, + { + "id": "banishment_lesser", + "type": "SPELL", + "name": "Lesser Banishment", + "description": "Banish a monster to the lesser-known nether dimension. If a monster is more powerful than you can handle, the spell drains your life force to make up the difference.", + "valid_targets": [ "hostile" ], + "flags": [ "SOMATIC", "VERBAL" ], + "effect": "banishment", + "shape": "blast", + "min_damage": 40, + "damage_increment": 10, + "max_damage": 290, + "min_range": 6, + "max_range": 6, + "base_energy_cost": 600, + "spell_class": "ANIMIST", + "difficulty": 9, + "max_level": 25, + "base_casting_time": 100, + "energy_source": "MANA" + }, { "id": "summon_wisps", "type": "SPELL", diff --git a/data/mods/Magiclysm/Spells/attunements/Blood_Mage.json b/data/mods/Magiclysm/Spells/attunements/Blood_Mage.json index 778b5d1c0f1e9..e075473efd142 100644 --- a/data/mods/Magiclysm/Spells/attunements/Blood_Mage.json +++ b/data/mods/Magiclysm/Spells/attunements/Blood_Mage.json @@ -13,11 +13,14 @@ "max_damage": 640, "min_range": 6, "max_range": 6, + "min_aoe": 0, + "max_aoe": 2, + "aoe_increment": 0.04, "base_energy_cost": 400, "spell_class": "BLOOD_MAGE", - "difficulty": 9, + "difficulty": 6, "max_level": 35, - "base_casting_time": 500, + "base_casting_time": 100, "energy_source": "MANA" }, { diff --git a/data/mods/Magiclysm/itemgroups/spellbooks.json b/data/mods/Magiclysm/itemgroups/spellbooks.json index bdfc1c30fabd5..2d538d1a7aab4 100644 --- a/data/mods/Magiclysm/itemgroups/spellbooks.json +++ b/data/mods/Magiclysm/itemgroups/spellbooks.json @@ -134,6 +134,7 @@ [ "spell_scroll_druidic_healing", 20 ], [ "spell_scroll_summon_magic_motorcycle", 5 ], [ "bio_sneeze_beam", 50 ], + [ "spell_scroll_banishment_lesser", 30 ], [ "spell_scroll_nova_flare", 25 ], [ "spell_scroll_freezing_touch", 40 ] ] diff --git a/data/mods/Magiclysm/items/spell_scrolls.json b/data/mods/Magiclysm/items/spell_scrolls.json index 7698667b2b643..abbf141e0de31 100644 --- a/data/mods/Magiclysm/items/spell_scrolls.json +++ b/data/mods/Magiclysm/items/spell_scrolls.json @@ -801,6 +801,15 @@ "description": "With a shout and a gesture, the target starts bleeding from old wounds.", "use_action": { "type": "learn_spell", "spells": [ "bleed" ] } }, + { + "type": "BOOK", + "copy-from": "spell_scroll", + "id": "spell_scroll_banishment_lesser", + "//": "Animist spell", + "name": { "str": "Scroll of Lesser Banishment", "str_pl": "Scrolls of Lesser Banishment" }, + "description": "Banish a monster to the lesser-known nether dimension. If a monster is more powerful than you can handle, the spell drains your life force to make up the difference.", + "use_action": { "type": "learn_spell", "spells": [ "banishment_lesser" ] } + }, { "type": "BOOK", "copy-from": "spell_scroll", From 4b8f856393cdc996c2e93d3ebb78642864931fbe Mon Sep 17 00:00:00 2001 From: Ramza13 <52087122+Ramza13@users.noreply.github.com> Date: Tue, 23 Feb 2021 18:22:29 -0500 Subject: [PATCH 035/453] Unhardcode bio_heatsink and bio_climate (#47713) --- data/json/bionics.json | 4 +++- doc/JSON_FLAGS.md | 2 ++ src/character.cpp | 10 +++++----- src/map_field.cpp | 8 ++++---- 4 files changed, 14 insertions(+), 10 deletions(-) diff --git a/data/json/bionics.json b/data/json/bionics.json index edad7d25787f3..79915e8fc3624 100644 --- a/data/json/bionics.json +++ b/data/json/bionics.json @@ -258,7 +258,8 @@ "act_cost": "100 J", "react_cost": "100 J", "time": 1, - "flags": [ "BIONIC_TOGGLED" ] + "flags": [ "BIONIC_TOGGLED" ], + "active_flags": [ "CLIMATE_CONTROL" ] }, { "id": "bio_cloak", @@ -581,6 +582,7 @@ [ "foot_r", 1 ] ], "flags": [ "BIONIC_TOGGLED", "BIONIC_NPC_USABLE" ], + "active_flags": [ "HEATSINK" ], "act_cost": "1 kJ", "react_cost": "1 kJ", "time": 1 diff --git a/doc/JSON_FLAGS.md b/doc/JSON_FLAGS.md index a970ca43e483e..69ccb0472c6f4 100644 --- a/doc/JSON_FLAGS.md +++ b/doc/JSON_FLAGS.md @@ -1549,3 +1549,5 @@ Gun fault flags: - ```ALARMCLOCK``` You always can set alarms. - ```PARAIMMUNE``` You are immune to parasites. - ```IMMUNE_SPOIL``` You are immune to negative outcomes from spoiled food. +- ```CLIMATE_CONTROL``` You are resistant to extreme temperatures. +- ```HEATSINK``` You are resistant to extreme heat. \ No newline at end of file diff --git a/src/character.cpp b/src/character.cpp index fe1cd151e70fc..27a9e29cffc26 100644 --- a/src/character.cpp +++ b/src/character.cpp @@ -276,12 +276,10 @@ static const trait_id trait_WOOLALLERGY( "WOOLALLERGY" ); static const bionic_id bio_ads( "bio_ads" ); static const bionic_id bio_blaster( "bio_blaster" ); -static const bionic_id bio_climate( "bio_climate" ); static const bionic_id bio_voice( "bio_voice" ); static const bionic_id bio_flashlight( "bio_flashlight" ); static const bionic_id bio_gills( "bio_gills" ); static const bionic_id bio_ground_sonar( "bio_ground_sonar" ); -static const bionic_id bio_heatsink( "bio_heatsink" ); static const bionic_id bio_hydraulics( "bio_hydraulics" ); static const bionic_id bio_jointservo( "bio_jointservo" ); static const bionic_id bio_laser( "bio_laser" ); @@ -387,6 +385,7 @@ static const json_character_flag json_flag_BLIND( "BLIND" ); static const json_character_flag json_flag_BULLET_IMMUNE( "BULLET_IMMUNE" ); static const json_character_flag json_flag_CLAIRVOYANCE( "CLAIRVOYANCE" ); static const json_character_flag json_flag_CLAIRVOYANCE_PLUS( "CLAIRVOYANCE_PLUS" ); +static const json_character_flag json_flag_CLIMATE_CONTROL( "CLIMATE_CONTROL" ); static const json_character_flag json_flag_COLD_IMMUNE( "COLD_IMMUNE" ); static const json_character_flag json_flag_CUT_IMMUNE( "CUT_IMMUNE" ); static const json_character_flag json_flag_DEAF( "DEAF" ); @@ -394,6 +393,7 @@ static const json_character_flag json_flag_ELECTRIC_IMMUNE( "ELECTRIC_IMMUNE" ); static const json_character_flag json_flag_ENHANCED_VISION( "ENHANCED_VISION" ); static const json_character_flag json_flag_EYE_MEMBRANE( "EYE_MEMBRANE" ); static const json_character_flag json_flag_HEATPROOF( "HEATPROOF" ); +static const json_character_flag json_flag_HEATSINK( "HEATSINK" ); static const json_character_flag json_flag_IMMUNE_HEARING_DAMAGE( "IMMUNE_HEARING_DAMAGE" ); static const json_character_flag json_flag_INFRARED( "INFRARED" ); static const json_character_flag json_flag_NIGHT_VISION( "NIGHT_VISION" ); @@ -4549,7 +4549,7 @@ bool Character::in_climate_control() { bool regulated_area = false; // Check - if( has_active_bionic( bio_climate ) ) { + if( has_flag( json_flag_CLIMATE_CONTROL ) ) { return true; } map &here = get_map(); @@ -6431,7 +6431,7 @@ void Character::update_bodytemp() const bool has_sleep = has_effect( effect_sleep ); const bool has_sleep_state = has_sleep || in_sleep_state(); const bool heat_immune = has_flag( json_flag_HEATPROOF ); - const bool has_heatsink = has_bionic( bio_heatsink ) || is_wearing( itype_rm13_armor_on ) || + const bool has_heatsink = has_flag( json_flag_HEATSINK ) || is_wearing( itype_rm13_armor_on ) || heat_immune; const bool has_common_cold = has_effect( effect_common_cold ); const bool has_climate_control = in_climate_control(); @@ -7449,7 +7449,7 @@ bool Character::is_immune_field( const field_type_id &fid ) const return is_elec_immune(); } if( ft.has_fire ) { - return has_active_bionic( bio_heatsink ) || is_wearing( itype_rm13_armor_on ); + return has_flag( json_flag_HEATSINK ) || is_wearing( itype_rm13_armor_on ); } if( ft.has_acid ) { return !is_on_ground() && get_env_resist( body_part_foot_l ) >= 15 && diff --git a/src/map_field.cpp b/src/map_field.cpp index ae320217bbc59..dfa2eacfc8623 100644 --- a/src/map_field.cpp +++ b/src/map_field.cpp @@ -72,8 +72,6 @@ static const itype_id itype_rock( "rock" ); static const species_id species_FUNGUS( "FUNGUS" ); -static const bionic_id bio_heatsink( "bio_heatsink" ); - static const efftype_id effect_badpoison( "badpoison" ); static const efftype_id effect_blind( "blind" ); static const efftype_id effect_corroding( "corroding" ); @@ -93,6 +91,8 @@ static const trait_id trait_M_SKIN3( "M_SKIN3" ); static const trait_id trait_THRESH_MARLOSS( "THRESH_MARLOSS" ); static const trait_id trait_THRESH_MYCUS( "THRESH_MYCUS" ); +static const json_character_flag json_flag_HEATSINK( "HEATSINK" ); + using namespace map_field_processing; void map::create_burnproducts( const tripoint &p, const item &fuel, const units::mass &burned_mass ) @@ -1472,7 +1472,7 @@ void map::player_in_field( player &u ) } if( ft == fd_fire ) { // Heatsink or suit prevents ALL fire damage. - if( !u.has_active_bionic( bio_heatsink ) && !u.is_wearing( itype_rm13_armor_on ) ) { + if( !u.has_flag( json_flag_HEATSINK ) && !u.is_wearing( itype_rm13_armor_on ) ) { // To modify power of a field based on... whatever is relevant for the effect. int adjusted_intensity = cur.get_field_intensity(); @@ -1587,7 +1587,7 @@ void map::player_in_field( player &u ) if( !inside ) { // Fireballs can't touch you inside a car. // Heatsink or suit stops fire. - if( !u.has_active_bionic( bio_heatsink ) && + if( !u.has_flag( json_flag_HEATSINK ) && !u.is_wearing( itype_rm13_armor_on ) ) { u.add_msg_player_or_npc( m_bad, _( "You're torched by flames!" ), _( " is torched by flames!" ) ); From e45301ae465d1e085480dc8e03b684592ec4aa61 Mon Sep 17 00:00:00 2001 From: Maleclypse <54345792+Maleclypse@users.noreply.github.com> Date: Thu, 4 Mar 2021 00:44:54 -0600 Subject: [PATCH 036/453] Hunting lodge Location (#44378) --- data/json/itemgroups/SUS/lodge.json | 80 ++++++ data/json/mapgen/hunting_lodge.json | 180 ++++++++++++++ data/json/mapgen/nested/lodge_nested.json | 228 +++++++++++++++++ data/json/mapgen_palettes/lodge_palette.json | 235 ++++++++++++++++++ .../overmap/overmap_special/specials.json | 18 ++ .../overmap_terrain/overmap_terrain.json | 28 +++ data/json/scenarios.json | 3 + data/json/start_locations.json | 6 + 8 files changed, 778 insertions(+) create mode 100644 data/json/itemgroups/SUS/lodge.json create mode 100644 data/json/mapgen/hunting_lodge.json create mode 100644 data/json/mapgen/nested/lodge_nested.json create mode 100644 data/json/mapgen_palettes/lodge_palette.json diff --git a/data/json/itemgroups/SUS/lodge.json b/data/json/itemgroups/SUS/lodge.json new file mode 100644 index 0000000000000..d3e03875adf68 --- /dev/null +++ b/data/json/itemgroups/SUS/lodge.json @@ -0,0 +1,80 @@ +[ + { + "id": "SUS_hunting_archery", + "type": "item_group", + "//": "items found in an archery space", + "subtype": "collection", + "entries": [ + { "item": "compbow", "prob": 50 }, + { "item": "compbow_high", "prob": 20 }, + { "item": "compbow_low", "prob": 40 }, + { "item": "recurbow", "prob": 30 }, + { "item": "reflexrecurvebow", "prob": 10 } + ] + }, + { + "id": "SUS_hunting_rifle", + "type": "item_group", + "//": "items found in a rifle hunting space", + "subtype": "collection", + "entries": [ + { "item": "ar15", "prob": 150, "charges-min": 0, "charges-max": 30 }, + { "item": "marlin_9a", "prob": 20, "charges-min": 0, "charges-max": 19 }, + { "item": "remington700_270", "prob": 10, "charges-min": 0, "charges-max": 4 }, + { "item": "remington_700", "prob": 40, "charges-min": 0, "charges-max": 4 }, + { "item": "ruger_1022", "prob": 70, "charges-min": 0, "charges-max": 10 }, + { "item": "ruger_mini", "prob": 10, "charges-min": 0, "charges-max": 5 }, + { "item": "win70", "prob": 20, "charges-min": 0, "charges-max": 3 }, + { "item": "colt_lightning", "prob": 2, "charges-min": 0, "charges-max": 10 }, + { "item": "henry_big_boy", "prob": 2, "charges-min": 0, "charges-max": 10 }, + { "item": "weatherby_5", "prob": 2, "charges-min": 0, "charges-max": 3 } + ] + }, + { + "id": "hunting_lodge_weapons", + "type": "item_group", + "//": "items found in a shotgun hunting space", + "subtype": "distribution", + "entries": [ + { "group": "guns_shotgun_common", "prob": 30 }, + { "group": "SUS_hunting_rifle", "prob": 20 }, + { "group": "SUS_hunting_archery", "prob": 15 } + ] + }, + { + "id": "cannibal_weapons", + "type": "item_group", + "//": "items found in a most dangerous game space", + "subtype": "distribution", + "entries": [ + { "group": "guns_shotgun_common", "prob": 30 }, + { "group": "SUS_hunting_rifle", "prob": 20 }, + { "group": "guns_smg_rare", "prob": 15 } + ] + }, + { + "id": "lodge_archery_ammo", + "type": "item_group", + "//": "archery ammo", + "subtype": "collection", + "entries": [ + { "item": "arrow_metal", "prob": 20 }, + { "item": "arrow_metal_bodkin", "prob": 20 }, + { "item": "arrow_metal_target", "prob": 30 }, + { "item": "arrow_cf", "prob": 10 } + ] + }, + { + "id": "cannibal_food", + "type": "item_group", + "subtype": "collection", + "entries": [ + { "item": "machete", "prob": 20 }, + { "group": "preserved_food", "custom-flags": [ "CANNIBALISM" ], "prob": 30 }, + { "group": "preserved_food", "prob": 20 }, + { "group": "dry_goods", "prob": 30 }, + { "group": "dry_goods", "custom-flags": [ "CANNIBALISM" ], "prob": 60 }, + { "group": "pantry", "prob": 10 } + ] + } +] diff --git a/data/json/mapgen/hunting_lodge.json b/data/json/mapgen/hunting_lodge.json new file mode 100644 index 0000000000000..c675c04bebdcd --- /dev/null +++ b/data/json/mapgen/hunting_lodge.json @@ -0,0 +1,180 @@ +[ + { + "type": "mapgen", + "method": "json", + "om_terrain": [ [ "lodge_ground1", "lodge_ground2" ] ], + "weight": 100, + "object": { + "fill_ter": "t_floor", + "rows": [ + ".%##W###W###W###W###+##W#################%......", + ".*#c B#c B#B c#B c# #h s# >#*......", + ".*Wd B#d B#B d#B d# #h T# W*......", + ".*##=###=###=###=## ##=## #*......", + ".*# #*......", + ".*W W*......", + ".*# YY YY AAAAAAAA a OOO >#*......", + ".%########+######################## ###%......", + ".*********G~~~~~~~~~~~~~~~~~~~~~~%# #***......", + "~~~~~~~~~~G~~~~~~~~~~~*############ #*........", + "oooooooooooooooo~~~~~~*w #%........", + "oooooooooooooooo~~~~~~*#Y w*........", + "ooooooooooooooooGGGGGGG+ ttttt bw*........", + "ooooooooooooooooGGGGGGG+ ttttt bw*........", + "oooooooooooooooo~~~~~G*#Y w*........", + "oooooooooooooooo~~~~~G*w w*........", + "~~~~~~~~~~~~~~~~~~~~~G*##### ########*........", + "~~~~~~~~~~~~~~~~~~~~~G***#<# #********........", + "~~~~~~~~~~~~~~~~%~~~~GGGG+ # #%****...........", + "......*###-###-###-######### #####*...........", + ".....0*#UU URU URU URU #12C 5 F#*...........", + ".....0*#R z C uW*...........", + ".....0*#UU URU URU URU #3CC& 4CVuF#*...........", + "......%###-###-###-##########+######%..........." + ], + "palettes": [ "lodge_palette" ], + "place_monsters": [ { "monster": "GROUP_ZOMBIE", "x": 29, "y": 4 } ], + "place_nested": [ + { + "chunks": [ [ "lodge_pantry_15x15", 80 ], [ "lodge_cannibal_15x15", 20 ], [ "lodge_hunting_15x15", 50 ] ], + "x": 8, + "y": 9 + } + ] + } + }, + { + "type": "mapgen", + "method": "json", + "om_terrain": [ [ "lodge_2ndfloor1", "lodge_2ndfloor2" ] ], + "weight": 100, + "object": { + "fill_ter": "t_floor", + "rows": [ + " ##W###W###W###W###w##W################# ", + " # <# ", + " W W ", + " # # ", + " # # ", + " W W ", + " # <# ", + " ########w#######wwww#############www### ", + " ", + " ", + " ", + " ", + " ", + " ", + " ", + " ", + " ", + " ", + " ", + " ", + " ", + " ", + " ", + " " + ], + "palettes": [ "lodge_2ndfloor_palette" ] + } + }, + { + "type": "mapgen", + "method": "json", + "om_terrain": [ [ "lodge_basement_residential1", "lodge_basement_residential2" ] ], + "weight": 100, + "object": { + "fill_ter": "t_rock", + "rows": [ + " %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% ", + " % % ", + " % % ", + " % % ", + " % % ", + " % % ", + " % % ", + " %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% %%% ", + " % % ", + " %%%%%%%%%%%%%% % ", + " % BB% ", + " % % ", + " % % ", + " % % ", + " % % ", + " % % ", + " %%%%% %%%%%%%% ", + " %<| % ", + " % + % ", + " %%%%%%% ", + " ", + " ", + " ", + " " + ], + "palettes": [ "basement_residential" ], + "place_monsters": [ { "monster": "GROUP_ZOMBIE", "x": 7, "y": 4 } ], + "place_nested": [ + { "chunks": [ [ "lodge_game_6x6", 80 ], [ "lodge_dungeon_6x6", 20 ], [ "lodge_drug_6x6", 50 ] ], "x": 2, "y": 1 }, + { "chunks": [ [ "5x5_sauna_W", 30 ], [ "5x5_pool", 10 ], [ "5x5_gym_W", 60 ] ], "x": 24, "y": 1 }, + { + "chunks": [ [ "room_6x6_woodworker", 5 ], [ "room_6x6_bike", 15 ], [ "room_6x6_office_E", 5 ] ], + "x": 24, + "y": 10 + } + ] + } + }, + { + "type": "mapgen", + "method": "json", + "om_terrain": [ "lodge_basement_laboratory_entrance" ], + "//": "doesn't work rebuild later", + "object": { + "fill_ter": "t_rock", + "rotation": [ 0, 3 ], + "rows": [ + "##--------------------##", + "##| |>>| |##", + "##| |MM| |##", + "##| |..| |##", + "##| |..| |##", + "##| |..| |##", + "##| |..| |##", + "##| |..| |##", + "##|---+---|..|---+---|##", + "##|.......M..M.......|##", + "##|.......M..M.......|##", + "|----+----|..|----+----|", + "|.........|..|d.......d|", + "|.ccccccc.|..|xh..h..hx|", + "|.........|7.|d..dxd..d|", + "|---------|..|---------|", + "########--|LL6--########", + "########=,,,,,,=########", + "########=,,,,,,=########", + "########=,,,,,,=########", + "########===WW===########", + "##########=,,=##########", + "##########=<<=##########", + "##########====##########" + ], + "palettes": [ "lab_palette" ], + "terrain": { + "=": "t_wall", + ",": "t_rock_floor", + "6": "t_card_science", + "7": "t_rock_floor", + "<": "t_stairs_up", + ">": "t_stairs_down" + }, + "furniture": { "C": "f_centrifuge" }, + "mapping": { "c": { "items": { "item": "chem_lab", "chance": 30 } }, "d": { "items": { "item": "office", "chance": 30 } } }, + "monster": { "7": { "monster": "mon_turret_rifle" } }, + "place_nested": [ + { "chunks": [ "lab_spawn_7x7_crossdoors" ], "x": 3, "y": 1 }, + { "chunks": [ "lab_spawn_7x7_crossdoors" ], "x": 14, "y": 1 } + ] + } + } +] diff --git a/data/json/mapgen/nested/lodge_nested.json b/data/json/mapgen/nested/lodge_nested.json new file mode 100644 index 0000000000000..7f89e90c344b3 --- /dev/null +++ b/data/json/mapgen/nested/lodge_nested.json @@ -0,0 +1,228 @@ +[ + { + "type": "mapgen", + "method": "json", + "nested_mapgen_id": "lodge_cannibal_15x15", + "object": { + "mapgensize": [ 15, 15 ], + "rows": [ + " ", + " ", + " ", + " ", + " ", + " ", + " ", + " ", + " ", + " ", + " ", + "DF ARF LRL ORa ", + "R ", + "SF DRA LRa ORO ", + "DF ARF LRL LRa ", + "R ", + "SF DRA LRa LRL ", + " " + ], + "palettes": [ "lodge_items" ] + } + }, + { + "type": "mapgen", + "method": "json", + "nested_mapgen_id": "lodge_hunting_15x15", + "object": { + "mapgensize": [ 15, 15 ], + "rows": [ + " ", + " ", + " ", + " ", + " ", + " ", + " ", + " ", + " ", + " ", + " ", + "DF ARF BRB BRa ", + "R ", + "SF DRA BRa BRB ", + " " + ], + "palettes": [ "lodge_items" ] + } + }, + { + "type": "mapgen", + "method": "json", + "nested_mapgen_id": "lodge_pantry_15x15", + "object": { + "mapgensize": [ 15, 15 ], + "rows": [ + " ", + " ", + " ", + " ", + " ", + " ", + " ", + " ", + " ", + " ", + " ", + "SS SRa SRS SRS ", + "R ", + "SS SRA BRB SRS ", + " " + ], + "palettes": [ "lodge_items" ] + } + }, + { + "type": "mapgen", + "method": "json", + "nested_mapgen_id": "lodge_game_6x6", + "object": { + "mapgensize": [ 6, 6 ], + "rows": [ + "E CC T", + " ", + " BB ", + " BB ", + " BB ", + "E T" + ], + "terrain": { + ".": "t_floor", + "B": "t_floor", + "C": "t_floor", + "y": "t_floor", + "T": "t_floor", + "E": "t_floor", + " ": "t_carpet_red", + "h": "t_carpet_red", + "A": "t_carpet_red", + "d": "t_carpet_red", + "f": "t_carpet_red", + "O": "t_carpet_red", + "=": "t_carpet_red" + }, + "furniture": { "A": "f_stool", "B": "f_table", "E": "f_armchair", "C": "f_bookcase", "T": "f_floor_lamp" }, + "items": { "C": [ { "item": "games", "chance": 80, "repeat": [ 3, 6 ] } ] } + } + }, + { + "type": "mapgen", + "method": "json", + "nested_mapgen_id": "lodge_dungeon_6x6", + "object": { + "mapgensize": [ 6, 6 ], + "rows": [ + " tc td", + " t t ", + " tttt ", + " ", + " h ", + "C T" + ], + "terrain": { + ".": "t_floor", + "B": "t_floor", + "C": "t_floor", + "c": "t_floor", + "y": "t_floor", + "T": "t_floor", + "t": "t_reb_cage", + "E": "t_floor", + " ": "t_carpet_red", + "h": "t_carpet_red", + "A": "t_carpet_red", + "d": "t_carpet_red", + "f": "t_carpet_red", + "O": "t_carpet_red", + "=": "t_carpet_red" + }, + "furniture": { + "A": "f_stool", + "B": "f_workbench", + "E": "f_armchair", + "C": "f_rack_wood", + "T": "f_floor_lamp", + "d": "f_mannequin", + "b": "f_bench", + "f": "f_table", + "h": "f_butcher_rack", + "y": [ "f_indoor_plant_y", "f_indoor_plant" ] + }, + "items": { + "C": [ + { "item": "SUS_tailoring_materials", "chance": 80, "repeat": [ 3, 6 ] }, + { "item": "leather_shop_repair", "chance": 40, "repeat": [ 2, 4 ] }, + { "item": "bullwhip", "chance": 100 } + ], + "c": [ + { "item": "bone", "chance": 80, "repeat": [ 4, 8 ] }, + { "item": "pants", "chance": 100 }, + { "item": "shirts", "chance": 100 }, + { "item": "leather_shop_accessories", "chance": 10 } + ] + } + } + }, + { + "type": "mapgen", + "method": "json", + "nested_mapgen_id": "lodge_drug_6x6", + "object": { + "mapgensize": [ 6, 6 ], + "rows": [ + "E CC T", + " ", + " BB ", + " BB ", + " BB ", + "E T" + ], + "terrain": { + ".": "t_floor", + "B": "t_floor", + "C": "t_floor", + "y": "t_floor", + "T": "t_floor", + "E": "t_floor", + " ": "t_carpet_red", + "h": "t_carpet_red", + "A": "t_carpet_red", + "d": "t_carpet_red", + "f": "t_carpet_red", + "O": "t_carpet_red", + "=": "t_carpet_red" + }, + "furniture": { + "A": "f_stool", + "B": "f_workbench", + "E": "f_armchair", + "C": "f_rack_wood", + "T": "f_floor_lamp", + "d": "f_mannequin", + "b": "f_bench", + "f": "f_table", + "h": "f_chair", + "y": [ "f_indoor_plant_y", "f_indoor_plant" ] + }, + "items": { + "C": [ + { "item": "straw_doll", "chance": 80, "repeat": [ 6, 14 ] }, + { "item": "bag_body_bag", "chance": 40, "repeat": [ 2, 4 ] } + ], + "B": [ + { "item": "coke", "chance": 60, "repeat": [ 13, 126 ] }, + { "item": "funnel", "chance": 60, "repeat": [ 0, 1 ] }, + { "item": "plastic_bag", "chance": 90, "repeat": [ 20, 60 ] } + ] + } + } + } +] diff --git a/data/json/mapgen_palettes/lodge_palette.json b/data/json/mapgen_palettes/lodge_palette.json new file mode 100644 index 0000000000000..dd7b0b86e68a3 --- /dev/null +++ b/data/json/mapgen_palettes/lodge_palette.json @@ -0,0 +1,235 @@ +[ + { + "type": "palette", + "id": "lodge_palette", + "terrain": { + "#": "t_rock_wall", + "+": [ [ "t_door_c", 3 ], "t_door_locked" ], + "=": "t_door_c", + "z": "t_door_metal_locked", + ".": [ [ "t_region_groundcover", 4 ], "t_region_groundcover_forest" ], + "~": [ [ "t_region_groundcover_barren", 3 ], "t_region_groundcover" ], + "*": [ [ "t_region_groundcover", 15 ], "t_region_shrub" ], + "G": "t_sidewalk", + "o": "t_pavement", + "P": "t_water_pump", + "R": "t_floor", + "r": "t_floor", + "S": "t_floor", + "-": "t_window_bars_curtains", + "w": "t_double_pane_glass_with_curtain_open_window_closed", + "W": [ [ "t_double_pane_glass_with_curtain", 2 ], "t_double_pane_glass_with_curtain_open_window_closed" ], + "%": "t_gutter_downspout", + "q": "t_swater_sh", + "Q": "t_water_dp", + "H": "t_chickenwire_gate_c", + "I": "t_chickenwire_fence", + "<": "t_wood_stairs_down", + ">": "t_wood_stairs_up" + }, + "furniture": { + "a": "f_armchair", + "A": "f_bookcase", + "b": "f_bench", + "B": "f_bed", + "C": "f_counter", + "c": "f_chair", + "d": "f_desk", + "D": "f_dresser", + "F": "f_fridge", + "h": "f_bathtub", + "l": "f_stool", + "L": "f_locker", + "O": "f_sofa", + "R": [ "f_rack", "f_utility_shelf" ], + "S": "f_woodstove", + "s": "f_sink", + "t": "f_table", + "T": "f_toilet", + "U": "f_utility_shelf", + "V": "f_oven", + "u": "f_cupboard", + "Y": "f_rack_coat", + "Z": "f_fireplace", + "y": [ "f_indoor_plant_y", "f_indoor_plant" ], + "1": "f_cupboard", + "2": "f_cupboard", + "3": "f_cupboard", + "4": "f_cupboard", + "5": "f_sink", + "&": "f_trashcan", + "0": "f_standing_tank" + }, + "liquids": { "0": { "liquid": "water_clean", "amount": [ 10, 900 ] } }, + "items": { + "a": { "item": "livingroom", "chance": 20 }, + "A": [ + { "item": "homebooks", "chance": 60, "repeat": [ 1, 3 ] }, + { "item": "magazines", "chance": 60, "repeat": [ 1, 8 ] }, + { "item": "manuals", "chance": 30 } + ], + "B": { "item": "bed", "chance": 60 }, + "d": [ { "item": "livingroom", "chance": 40 }, { "item": "office", "chance": 40 } ], + "D": [ + { "item": "SUS_dresser_mens", "chance": 50, "repeat": [ 1, 4 ] }, + { "item": "SUS_dresser_womens", "chance": 50, "repeat": [ 1, 4 ] } + ], + "F": { "item": "SUS_fridge", "chance": 35 }, + "h": { "item": "shower", "chance": 20 }, + "L": [ + { "item": "tools_earthworking", "chance": 30, "repeat": [ 1, 4 ] }, + { "item": "tools_home", "chance": 30, "repeat": [ 1, 4 ] } + ], + "O": { "item": "livingroom", "chance": 20 }, + "S": { "item": "stash_wood", "chance": 60, "repeat": [ 2, 4 ] }, + "&": { "item": "trash", "chance": 20 }, + "R": [ + { "item": "camping", "chance": 50 }, + { "item": "gear_survival", "chance": 30 }, + { "item": "cannedfood", "chance": 50 }, + { "item": "stash_food", "chance": 50 } + ], + "s": { "item": "SUS_bathroom_sink", "chance": 60 }, + "t": { "item": "dining", "chance": 30, "repeat": [ 1, 2 ] }, + "U": { "item": "camping", "chance": 30, "repeat": [ 1, 4 ] }, + "u": { "item": "SUS_pantry", "chance": 50 }, + "V": { "item": "SUS_oven", "chance": 70 }, + "Y": { "item": "coat_rack", "chance": 35, "repeat": [ 1, 4 ] }, + "1": [ { "item": "SUS_dishes", "chance": 35 }, { "item": "SUS_silverware", "chance": 35 } ], + "2": { "item": "SUS_cookware", "chance": 35 }, + "3": [ { "item": "SUS_utensils", "chance": 35 }, { "item": "SUS_knife_drawer", "chance": 35 } ], + "4": [ { "item": "SUS_junk_drawer", "chance": 35 }, { "item": "SUS_spice_collection", "chance": 35 } ], + "5": { "item": "SUS_kitchen_sink", "chance": 35 } + }, + "toilets": { "T": { } } + }, + { + "type": "palette", + "id": "lodge_2ndfloor_palette", + "terrain": { + "#": "t_rock_wall", + "+": [ [ "t_door_c", 3 ], "t_door_locked" ], + "=": "t_door_c", + " ": "t_open_air", + ".": "t_gutter_north", + "~": "t_gutter_south", + "*": "t_gutter_east", + "R": "t_floor", + "p": "t_floor", + "r": "t_rock_floor", + "S": "t_rock_floor", + "-": "t_window_bars_curtains", + "w": "t_double_pane_glass_with_curtain_open_window_closed", + "W": [ [ "t_double_pane_glass_with_curtain", 2 ], "t_double_pane_glass_with_curtain_open_window_closed" ], + "%": "t_gutter_downspout", + "q": "t_swater_sh", + "Q": "t_water_dp", + "H": "t_chickenwire_gate_c", + "I": "t_chickenwire_fence", + "<": "t_wood_stairs_down", + ">": "t_wood_stairs_up" + }, + "furniture": { + "a": "f_armchair", + "A": "f_bookcase", + "b": "f_bench", + "B": "f_bed", + "C": "f_counter", + "c": "f_chair", + "d": "f_desk", + "D": "f_dresser", + "F": "f_fridge", + "h": "f_bathtub", + "l": "f_stool", + "L": "f_locker", + "O": "f_sofa", + "p": "f_pool_table", + "R": [ "f_rack", "f_utility_shelf" ], + "S": "f_woodstove", + "s": "f_sink", + "t": "f_table", + "T": "f_toilet", + "Y": "f_rack_coat", + "Z": "f_fireplace", + "y": [ "f_indoor_plant_y", "f_indoor_plant" ], + "5": "f_sink", + "&": "f_trashcan" + }, + "liquids": { "0": { "liquid": "water_clean", "amount": [ 10, 900 ] } }, + "items": { + "a": { "item": "livingroom", "chance": 20 }, + "A": [ + { "item": "homebooks", "chance": 60, "repeat": [ 1, 3 ] }, + { "item": "magazines", "chance": 60, "repeat": [ 1, 8 ] }, + { "item": "manuals", "chance": 30 } + ], + "B": { "item": "bed", "chance": 60 }, + "d": [ { "item": "livingroom", "chance": 40 }, { "item": "office", "chance": 40 } ], + "D": [ + { "item": "SUS_dresser_mens", "chance": 50, "repeat": [ 1, 4 ] }, + { "item": "SUS_dresser_womens", "chance": 50, "repeat": [ 1, 4 ] } + ], + "F": { "item": "SUS_fridge", "chance": 35 }, + "h": { "item": "shower", "chance": 20 }, + "L": [ + { "item": "tools_earthworking", "chance": 30, "repeat": [ 1, 4 ] }, + { "item": "tools_home", "chance": 30, "repeat": [ 1, 4 ] } + ], + "O": { "item": "livingroom", "chance": 20 }, + "S": { "item": "stash_wood", "chance": 60, "repeat": [ 2, 4 ] }, + "&": { "item": "trash", "chance": 20 }, + "R": [ + { "item": "camping", "chance": 50 }, + { "item": "gear_survival", "chance": 30 }, + { "item": "cannedfood", "chance": 50 }, + { "item": "stash_food", "chance": 50 } + ], + "s": { "item": "SUS_bathroom_sink", "chance": 60 }, + "t": { "item": "dining", "chance": 30, "repeat": [ 1, 2 ] }, + "U": { "item": "camping", "chance": 30, "repeat": [ 1, 4 ] }, + "u": { "item": "SUS_pantry", "chance": 50 }, + "V": { "item": "SUS_oven", "chance": 70 }, + "Y": { "item": "coat_rack", "chance": 35, "repeat": [ 1, 4 ] }, + "1": [ { "item": "SUS_dishes", "chance": 35 }, { "item": "SUS_silverware", "chance": 35 } ], + "2": { "item": "SUS_cookware", "chance": 35 }, + "3": [ { "item": "SUS_utensils", "chance": 35 }, { "item": "SUS_knife_drawer", "chance": 35 } ], + "4": [ { "item": "SUS_junk_drawer", "chance": 35 }, { "item": "SUS_spice_collection", "chance": 35 } ], + "5": { "item": "SUS_kitchen_sink", "chance": 35 } + }, + "toilets": { "T": { } } + }, + { + "type": "palette", + "id": "lodge_items", + "terrain": { + "a": "t_floor", + "A": "t_floor", + "B": "t_floor", + "D": "t_floor", + "F": "t_floor", + "h": "t_floor", + "L": "t_floor", + "O": "t_floor", + "S": "t_floor", + "&": "t_floor", + "R": "t_floor" + }, + "items": { + "a": { "item": "clothing_hunting", "chance": 20, "repeat": [ 1, 6 ] }, + "A": { "item": "tools_hunting", "chance": 60, "repeat": [ 1, 8 ] }, + "B": { "item": "tools_hunting", "chance": 60 }, + "D": { "item": "hunting_lodge_weapons" }, + "F": { "item": "lodge_archery_ammo", "chance": 30, "repeat": [ 1, 4 ] }, + "h": { "item": "cannibal_weapons", "repeat": [ 1, 4 ] }, + "L": { "item": "cannibal_food", "repeat": [ 1, 4 ] }, + "S": { "item": "stash_wood", "chance": 60, "repeat": [ 2, 4 ] }, + "&": { "item": "trash", "chance": 20 }, + "R": [ + { "item": "camping", "chance": 50 }, + { "item": "gear_survival", "chance": 30 }, + { "item": "cannedfood", "chance": 50, "repeat": [ 3, 8 ] }, + { "item": "stash_food", "chance": 50, "repeat": [ 3, 8 ] } + ] + } + } +] diff --git a/data/json/overmap/overmap_special/specials.json b/data/json/overmap/overmap_special/specials.json index a967b44cbfa00..a224570fb4db6 100644 --- a/data/json/overmap/overmap_special/specials.json +++ b/data/json/overmap/overmap_special/specials.json @@ -249,6 +249,24 @@ "occurrences": [ 0, 2 ], "flags": [ "CLASSIC", "WILDERNESS" ] }, + { + "type": "overmap_special", + "id": "Hunting Lodge", + "overmaps": [ + { "point": [ 0, 0, 0 ], "overmap": "lodge_ground1_north" }, + { "point": [ 1, 0, 0 ], "overmap": "lodge_ground2_north" }, + { "point": [ 0, 0, 1 ], "overmap": "lodge_2ndfloor1_north" }, + { "point": [ 1, 0, 1 ], "overmap": "lodge_2ndfloor2_north" }, + { "point": [ 0, 0, -1 ], "overmap": "lodge_basement_residential1_north" }, + { "point": [ 1, 0, -1 ], "overmap": "lodge_basement_residential2_north" } + ], + "connections": [ { "point": [ 0, -1, 0 ], "terrain": "road", "existing": true } ], + "locations": [ "land", "swamp" ], + "city_distance": [ 15, -1 ], + "city_sizes": [ 1, 8 ], + "occurrences": [ 0, 2 ], + "flags": [ "CLASSIC", "WILDERNESS" ] + }, { "type": "overmap_special", "id": "Gas Station", diff --git a/data/json/overmap/overmap_terrain/overmap_terrain.json b/data/json/overmap/overmap_terrain/overmap_terrain.json index 8fc28084fd9c0..171b70dada0cf 100644 --- a/data/json/overmap/overmap_terrain/overmap_terrain.json +++ b/data/json/overmap/overmap_terrain/overmap_terrain.json @@ -219,6 +219,34 @@ "see_cost": 5, "extras": "build" }, + { + "type": "overmap_terrain", + "id": [ "lodge_ground1", "lodge_ground2" ], + "name": "hunting lodge", + "sym": "L", + "copy-from": "generic_forest", + "color": "light_green", + "see_cost": 4, + "extend": { "flags": [ "SOURCE_GUN", "SOURCE_AMMO" ] } + }, + { + "type": "overmap_terrain", + "id": [ "lodge_2ndfloor1", "lodge_2ndfloor2" ], + "name": "second floor hunting lodge", + "copy-from": "generic_forest", + "sym": "L", + "see_cost": 4, + "color": "light_green" + }, + { + "type": "overmap_terrain", + "id": [ "lodge_basement_residential1", "lodge_basement_residential2", "lodge_basement_laboratory_entrance" ], + "name": "hunting lodge basement", + "copy-from": "generic_forest", + "sym": "L", + "see_cost": 4, + "color": "light_green" + }, { "type": "overmap_terrain", "id": "dirtroad1_aban1", diff --git a/data/json/scenarios.json b/data/json/scenarios.json index f7a7522da5496..634bcf79b105f 100644 --- a/data/json/scenarios.json +++ b/data/json/scenarios.json @@ -95,6 +95,7 @@ "sloc_horse_ranch", "sloc_lighthouse_ground", "sloc_cabin_lake", + "sloc_lodge_ground", "sloc_freshwater_research_station" ], "start_name": "Safe Building", @@ -296,6 +297,7 @@ "sloc_hermit_shack", "sloc_farm_survivalist", "sloc_campsite", + "sloc_lodge_ground", "sloc_campground" ], "start_name": "Outside Town", @@ -314,6 +316,7 @@ "sloc_field", "sloc_forest", "sloc_cabin", + "sloc_lodge_ground", "sloc_hermit_shack", "sloc_farm_survivalist", "sloc_campsite", diff --git a/data/json/start_locations.json b/data/json/start_locations.json index 99848e24e71e2..7041747c9d520 100644 --- a/data/json/start_locations.json +++ b/data/json/start_locations.json @@ -457,6 +457,12 @@ "name": "Freshwater Research Station", "terrain": [ "sealab_small_surface" ] }, + { + "type": "start_location", + "id": "sloc_lodge_ground", + "name": "Hunting Lodge", + "terrain": [ "lodge_ground" ] + }, { "type": "start_location", "id": "sloc_gas_station", From 387b12c906e379b287b0c39639db685acb19ca84 Mon Sep 17 00:00:00 2001 From: LyleSY Date: Thu, 4 Mar 2021 01:57:22 -0500 Subject: [PATCH 037/453] fungal evolution (#47247) --- data/json/monstergroups/fungi.json | 12 +++++++---- data/json/monsters/fungus.json | 33 ++++++++++++++++++++++++++++++ 2 files changed, 41 insertions(+), 4 deletions(-) diff --git a/data/json/monstergroups/fungi.json b/data/json/monstergroups/fungi.json index a506431db6685..baac22efbea7c 100644 --- a/data/json/monstergroups/fungi.json +++ b/data/json/monstergroups/fungi.json @@ -4,8 +4,9 @@ "name": "GROUP_FUNGI", "default": "mon_spore", "monsters": [ - { "monster": "mon_fungaloid", "freq": 300, "cost_multiplier": 0 }, - { "monster": "mon_fungaloid_young", "freq": 100, "cost_multiplier": 0 }, + { "monster": "mon_fungaloid", "freq": 400, "cost_multiplier": 0 }, + { "monster": "mon_fungaloid_shambler", "freq": 200, "cost_multiplier": 0 }, + { "monster": "mon_fungaloid_young", "freq": 200, "cost_multiplier": 0 }, { "monster": "mon_zombie_fungus", "freq": 0, "cost_multiplier": 0 }, { "monster": "mon_boomer_fungus", "freq": 0, "cost_multiplier": 0 }, { "monster": "mon_zombie_child_fungus", "freq": 0, "cost_multiplier": 0 }, @@ -18,8 +19,9 @@ "name": "GROUP_FUNGI_FUNGALOID", "default": "mon_fungaloid", "monsters": [ - { "monster": "mon_fungaloid", "freq": 300, "cost_multiplier": 0 }, - { "monster": "mon_fungaloid_young", "freq": 100, "cost_multiplier": 0, "pack_size": [ 2, 3 ] } + { "monster": "mon_fungaloid", "freq": 500, "cost_multiplier": 0 }, + { "monster": "mon_fungaloid_shambler", "freq": 250, "cost_multiplier": 0 }, + { "monster": "mon_fungaloid_young", "freq": 250, "cost_multiplier": 0, "pack_size": [ 2, 3 ] } ] }, { @@ -28,6 +30,7 @@ "default": "mon_fungal_tendril", "monsters": [ { "monster": "mon_fungaloid", "freq": 10, "cost_multiplier": 0 }, + { "monster": "mon_fungaloid_shambler", "freq": 30, "cost_multiplier": 0 }, { "monster": "mon_fungaloid_young", "freq": 30, "cost_multiplier": 0 }, { "monster": "mon_zombie_fungus", "freq": 75, "cost_multiplier": 0 }, { "monster": "mon_boomer_fungus", "freq": 50, "cost_multiplier": 0 }, @@ -42,6 +45,7 @@ "default": "mon_fungal_blossom", "monsters": [ { "monster": "mon_fungaloid", "freq": 20, "cost_multiplier": 0 }, + { "monster": "mon_fungaloid_shambler", "freq": 50, "cost_multiplier": 0 }, { "monster": "mon_fungaloid_young", "freq": 50, "cost_multiplier": 0 }, { "monster": "mon_zombie_fungus", "freq": 100, "cost_multiplier": 0 }, { "monster": "mon_boomer_fungus", "freq": 50, "cost_multiplier": 0 }, diff --git a/data/json/monsters/fungus.json b/data/json/monsters/fungus.json index d8efb3e515a99..c38ae3e704fcb 100644 --- a/data/json/monsters/fungus.json +++ b/data/json/monsters/fungus.json @@ -172,8 +172,41 @@ "harvest": "fungaloid", "special_attacks": [ [ "FUNGUS", 30 ] ], "death_function": [ "FUNGUS", "NORMAL" ], + "upgrades": { "half_life": 14, "into": "mon_fungaloid_shambler" }, "flags": [ "STUMBLES", "POISON", "NO_BREATHE", "NOHEAD" ] }, + { + "id": "mon_fungaloid_shambler", + "type": "MONSTER", + "name": { "str": "fungaloid shambler" }, + "description": "A large white fungus, a bulging gray stalk supporting a bloom at the top. Spores float from its gills and tendrils extend from the base. Chunks of rock, metal, bone, and wood are held by tendrils as a kind of armor.", + "copy-from": "mon_fungaloid", + "volume": "12 L", + "weight": "160 kg", + "hp": 150, + "speed": 20, + "armor_cut": 10, + "armor_bullet": 20, + "armor_stab": 20, + "armor_acid": 3, + "special_attacks": [ + [ "FUNGUS", 20 ], + { + "type": "gun", + "cooldown": 5, + "move_cost": 150, + "gun_type": "feral_human_thrown_rock", + "fake_skills": [ [ "gun", 2 ], [ "throw", 2 ] ], + "fake_dex": 6, + "fake_per": 6, + "require_targeting_player": false, + "ranges": [ [ 2, 5, "DEFAULT" ] ], + "description": "The fungaloid shambler throws a rock!" + } + ], + "death_drops": [ { "group": "wreckage", "count": 5 }, { "group": "trash_forest", "count": 5 } ], + "upgrades": { } + }, { "id": "mon_fungaloid_queen", "type": "MONSTER", From 3711f239cdd5c0780cadff0e50c797e71c56952b Mon Sep 17 00:00:00 2001 From: FuelType-Memes <42695732+FuelType-Memes@users.noreply.github.com> Date: Thu, 4 Mar 2021 09:58:46 +0300 Subject: [PATCH 038/453] Add book strap carrier (#47665) --- .../itemgroups/Clothing_Gear/clothing.json | 1 + .../Clothing_Gear/gear_civilian.json | 1 + data/json/itemgroups/art_antiques_crafts.json | 3 +- data/json/items/armor/storage.json | 31 +++++++++++++++++++ data/json/recipes/armor/storage.json | 13 ++++++++ .../mods/Magiclysm/itemgroups/itemgroups.json | 10 +++++- 6 files changed, 57 insertions(+), 2 deletions(-) diff --git a/data/json/itemgroups/Clothing_Gear/clothing.json b/data/json/itemgroups/Clothing_Gear/clothing.json index 92b6d2762745f..38006e9cecf33 100644 --- a/data/json/itemgroups/Clothing_Gear/clothing.json +++ b/data/json/itemgroups/Clothing_Gear/clothing.json @@ -3015,6 +3015,7 @@ { "distribution": [ { "item": "case_violin", "prob": 5 }, + { "item": "bookstrap", "prob": 5 }, { "item": "quiver", "prob": 20 }, { "item": "quiver_large", "prob": 15 }, { "item": "solarpack", "prob": 5 }, diff --git a/data/json/itemgroups/Clothing_Gear/gear_civilian.json b/data/json/itemgroups/Clothing_Gear/gear_civilian.json index ee282114dc97d..b9021c3d1629e 100644 --- a/data/json/itemgroups/Clothing_Gear/gear_civilian.json +++ b/data/json/itemgroups/Clothing_Gear/gear_civilian.json @@ -100,6 +100,7 @@ [ "slingpack", 19 ], [ "travelpack", 10 ], [ "petpack", 1 ], + [ "bookstrap", 1 ], [ "pockknife", 14 ], [ "roller_shoes_off", 10 ], [ "knife_swissarmy", 10 ], diff --git a/data/json/itemgroups/art_antiques_crafts.json b/data/json/itemgroups/art_antiques_crafts.json index 1fc319800412c..d1e5a376777c1 100644 --- a/data/json/itemgroups/art_antiques_crafts.json +++ b/data/json/itemgroups/art_antiques_crafts.json @@ -194,7 +194,8 @@ { "item": "coin_quarter", "prob": 1 }, { "item": "bronze_medal", "prob": 1 }, { "item": "silver_medal", "prob": 1 }, - { "item": "gold_medal", "prob": 1 } + { "item": "gold_medal", "prob": 1 }, + { "item": "bookstrap", "prob": 5 } ] }, { diff --git a/data/json/items/armor/storage.json b/data/json/items/armor/storage.json index b410c75b32f3b..fd01f42405db0 100644 --- a/data/json/items/armor/storage.json +++ b/data/json/items/armor/storage.json @@ -1964,5 +1964,36 @@ "warmth": 2, "material_thickness": 1, "flags": [ "BELTED", "WATER_FRIENDLY" ] + }, + { + "id": "bookstrap", + "type": "ARMOR", + "name": { "str": "bookstrap" }, + "description": "An old-fashioned book strap carrier. Guaranteed to make you feel like a proper scholar.", + "weight": "204 g", + "volume": "350 ml", + "price": 12000, + "price_postapoc": 450, + "material": [ "leather" ], + "symbol": "[", + "looks_like": "leather_belt", + "color": "brown", + "covers": [ "leg_l", "leg_r" ], + "sided": true, + "coverage": 5, + "encumbrance": 0, + "max_encumbrance": 11, + "pocket_data": [ + { + "pocket_type": "CONTAINER", + "min_item_volume": "500 ml", + "max_contains_volume": "3 L", + "max_contains_weight": "4 kg", + "max_item_length": "40 cm", + "moves": 400 + } + ], + "material_thickness": 1, + "flags": [ "BELTED", "WATER_FRIENDLY" ] } ] diff --git a/data/json/recipes/armor/storage.json b/data/json/recipes/armor/storage.json index 974de7a3a2569..ed0db71e93ea3 100644 --- a/data/json/recipes/armor/storage.json +++ b/data/json/recipes/armor/storage.json @@ -1388,5 +1388,18 @@ { "proficiency": "prof_leatherworking" }, { "proficiency": "prof_leatherworking_basic" } ] + }, + { + "result": "bookstrap", + "type": "recipe", + "activity_level": "LIGHT_EXERCISE", + "category": "CC_ARMOR", + "subcategory": "CSC_ARMOR_STORAGE", + "skill_used": "tailor", + "time": "1 h 30 m", + "autolearn": true, + "reversible": true, + "using": [ [ "tailoring_leather_small", 4 ], [ "clasps", 2 ] ], + "proficiencies": [ { "proficiency": "prof_closures" }, { "proficiency": "prof_leatherworking_basic" } ] } ] diff --git a/data/mods/Magiclysm/itemgroups/itemgroups.json b/data/mods/Magiclysm/itemgroups/itemgroups.json index c8e672809f894..54f1baa86964e 100644 --- a/data/mods/Magiclysm/itemgroups/itemgroups.json +++ b/data/mods/Magiclysm/itemgroups/itemgroups.json @@ -237,7 +237,15 @@ { "type": "item_group", "id": "magic_shop_clothes", - "items": [ [ "cloak", 3 ], [ "cloak_wool", 5 ], [ "jedi_cloak", 3 ], [ "robe", 5 ], [ "tophat", 5 ], [ "leathersandals", 6 ] ] + "items": [ + [ "cloak", 3 ], + [ "cloak_wool", 5 ], + [ "jedi_cloak", 3 ], + [ "robe", 5 ], + [ "tophat", 5 ], + [ "leathersandals", 6 ], + [ "bookstrap", 2 ] + ] }, { "type": "item_group", From d03baa82b939946dedcd633da9fbd89969d83de5 Mon Sep 17 00:00:00 2001 From: Anton Burmistrov Date: Thu, 4 Mar 2021 11:00:34 +0400 Subject: [PATCH 039/453] Partial mine jsonify; new zombie miner (#47790) * Moved mine_entrance OMT from the list of hardcoded locations to industial locations Also removed mine_shaft OMT and replaced it with mine_shaft_middle and mine_shaft_lower OMTs. Also added mine_entrance_roof OMT. * Added mine_entrance and mine_shaft to the list of obsoleted terrains * Added a zombie miner and its death drops * Created a json-version of mine entrance and its roof * Created a json-version of mine shaft (middle and lower variants) * Changed overmap special definition of a mine to include new json chunks * Applied migration of hardcoded mine_entrance and mine_shaft OMTs to new json variants * Made hardcoded mine chunks generate to the west of lower section of new mine shaft OMT Also removed mine_entrance and mine_shaft from the list of hardocoded mapgen. * Completely removed build_mine_room function as all mine rooms are now defined in json Also removed hardcoded generation of mine entrance and mine shaft. * Removed mentions of mine rooms from mapgen.h * Updated alt_map_key mod * Updated graphical overmap mod * Added missing harvest * Appease clang and constify * Quickfix * Appease clang one more time --- data/json/mapgen/mine/mine_entrance.json | 194 ++++++++ data/json/mapgen/mine/mine_shaft.json | 88 ++++ data/json/monsterdrops/zombie_technician.json | 24 + data/json/monsters/zed_misc.json | 35 ++ data/json/obsolete_terrains.json | 4 +- .../overmap/overmap_special/specials.json | 8 +- .../overmap_terrain_hardcoded.json | 18 - .../overmap_terrain_industrial.json | 36 ++ .../go_overmap_terrain_hardcoded.json | 16 +- data/mods/alt_map_key/overmap_terrain.json | 17 +- src/mapgen.cpp | 445 ++++-------------- src/mapgen.h | 5 - src/overmap.cpp | 15 +- src/savegame.cpp | 4 +- 14 files changed, 517 insertions(+), 392 deletions(-) create mode 100644 data/json/mapgen/mine/mine_entrance.json create mode 100644 data/json/mapgen/mine/mine_shaft.json diff --git a/data/json/mapgen/mine/mine_entrance.json b/data/json/mapgen/mine/mine_entrance.json new file mode 100644 index 0000000000000..71f2e6a6508c2 --- /dev/null +++ b/data/json/mapgen/mine/mine_entrance.json @@ -0,0 +1,194 @@ +[ + { + "type": "mapgen", + "method": "json", + "om_terrain": "mine_entrance", + "object": { + "rows": [ + "fffffffffffФФfffffffffff", + "f v ,,,,,,,,,,,, !f", + "f/ ,,,,,,,,,,,,,,,,,f", + "|-000--000-0+0|00--00|,f", + "|dddrFFddcW..2|2..Fdd|,f", + "0dC.....Cc....?....dC|,f", + "0............a|b...d.|,f", + "0..C...|*-|-*-|b.....|,f", + "|rddd1p|.l|&_s|a36561|,f", + "|-000--|--|---|------|,f", + "f ,,,,,,,,,,,,,,,,,f", + "|----|+|----| ,,,,,,,/f", + "|I.hĎ|.|дh.I| ,|---%--|", + "0BB..+.+..BB0 ,|eEE~~4|", + "|----|.|----| ,|~EE~~4|", + "|I.hĎ|.|дh.I| ,|------|", + "0BB..+.+..BB0 ,|888888|", + "|----|.|----| ,?~~~~~8|", + "|I.hD|.|Дh.I| ,|888888|", + "0BB..+.+..BB0 ,|------|", + "|----|.|----| ,^`````@|", + "|&___+.+____| ,^``````|", + "|R__s|.|Й__7|/ №|999``$|", + "|----|0|----|fff|------|" + ], + "fill_ter": "t_floor", + "terrain": { + " ": [ [ "t_region_groundcover", 4 ], [ "t_region_shrub", 2 ], [ "t_region_tree", 1 ] ], + "!": "t_manhole_cover", + "/": "t_gutter_downspout", + "|": "t_wall", + "-": "t_wall", + "_": "t_linoleum_white", + "&": "t_linoleum_white", + "*": "t_door_c", + "?": "t_door_locked_alarm", + "+": "t_door_locked", + "%": "t_door_metal_c", + "^": "t_door_metal_locked", + "№": "t_gates_mech_control", + ",": "t_sidewalk", + ".": "t_floor", + "~": "t_thconc_floor", + "`": "t_thconc_floor", + "0": "t_metal_grate_window_with_curtain", + "4": "t_thconc_floor", + "8": "t_thconc_floor", + "9": "t_thconc_floor", + "E": "t_elevator", + "e": "t_elevator_control_off", + "f": "t_chainfence", + "L": "t_door_metal_locked", + "R": "t_linoleum_white", + "s": "t_linoleum_white", + "v": "t_dirt", + "w": "t_window_alarm", + "W": "t_water_dispenser", + "Й": "t_linoleum_white", + "Ф": "t_chaingate_l" + }, + "furniture": { + "1": "f_shredder", + "2": "f_rack_coat", + "3": "f_server", + "4": "f_metal_bench", + "5": "f_console", + "6": "f_console_broken", + "7": "f_shower", + "8": "f_utility_shelf", + "9": "f_utility_shelf", + "a": "f_air_conditioner", + "B": "f_bed", + "b": "f_bookcase", + "c": "f_counter", + "C": "f_chair", + "d": "f_desk", + "D": "f_desk", + "Ď": "f_desk", + "F": "f_filing_cabinet", + "h": "f_chair", + "I": "f_dresser", + "l": "f_locker", + "p": [ "f_indoor_plant", "f_indoor_plant_y" ], + "R": "f_trashcan", + "r": "f_trashcan", + "s": "f_sink", + "v": "f_vent_pipe", + "Д": "f_desk", + "д": "f_desk", + "Й": "f_rack_coat" + }, + "toilets": { "&": { } }, + "items": { + "2": { "item": "coat_rack", "chance": 60, "repeat": 2 }, + "8": { "item": "mine_storage", "chance": 50, "repeat": 4 }, + "9": { "item": "car_kit", "chance": 60, "repeat": 2 }, + "B": { "item": "bed", "chance": 50 }, + "b": { "item": "lab_bookshelves", "chance": 60, "repeat": 2 }, + "c": { "item": "office_supplies", "chance": 60 }, + "D": { "item": "SUS_junk_drawer_artsy", "chance": 90 }, + "Ď": { "item": "SUS_junk_drawer_messy", "chance": 90 }, + "d": { "item": "SUS_office_desk", "chance": 90 }, + "F": { "item": "SUS_office_filing_cabinet", "chance": 90 }, + "I": { "item": "SUS_dresser_mens", "chance": 60 }, + "l": { "item": "SUS_janitors_closet", "chance": 85 }, + "R": { "item": "trash_cart", "chance": 50 }, + "r": { "item": "trash_cart", "chance": 50 }, + "s": { "item": "SUS_bathroom_sink", "chance": 70 }, + "Д": { "item": "SUS_junk_drawer_handy", "chance": 90 }, + "д": { "item": "SUS_junk_drawer_tidy", "chance": 90 } + }, + "monster": { + ",": { "monster": "mon_zombie_miner", "chance": 5 }, + ".": { "monster": "mon_zombie_miner", "chance": 5 }, + "`": { "monster": "mon_zombie_miner", "chance": 5 }, + " ": { "monster": "mon_zombie_miner", "chance": 5 }, + "~": { "monster": "mon_zombie_miner", "chance": 5 } + }, + "computers": { + "5": { + "name": "NEPowerOS", + "security": 2, + "options": [ { "name": "Divert power to elevator", "action": "elevator_on" } ], + "failures": [ { "action": "alarm" } ] + } + }, + "gaspumps": { "@": { "fuel": "gasoline", "amount": [ 10000, 50000 ] }, "$": { "fuel": "diesel", "amount": [ 10000, 50000 ] } }, + "nested": { "`": { "chunks": [ [ "mechanical_fluid", 10 ], [ "gasoline_diesel_motor_oil", 80 ], [ "null", 80 ] ] } } + } + }, + { + "type": "mapgen", + "method": "json", + "om_terrain": "mine_entrance_roof", + "object": { + "rows": [ + " ", + " ", + " ", + "Ю--------------------| ", + "|....................| ", + "|....................| ", + "|....................| ", + "|....................| ", + "|....................| ", + "|--------------------| ", + " ", + "|-----------| ", + "|...........| |------Ю", + "|...........| |......|", + "|...........| |......|", + "|...........| |......|", + "|...........| |......|", + "|...........| |......|", + "|...........| |......|", + "|...........| |......|", + "|...........| |......|", + "|...........| |......|", + "|...........| |......|", + "|-----------Ю |------|" + ], + "terrain": { " ": "t_open_air", "|": "t_gutter_north", "-": "t_gutter_west", "Ю": "t_gutter_drop", ".": "t_flat_roof" } + } + }, + { + "type": "mapgen", + "method": "json", + "nested_mapgen_id": "mechanical_fluid", + "object": { + "mapgensize": [ 1, 1 ], + "place_fields": [ { "field": "fd_mechanical_fluid", "x": 0, "y": 0, "intensity": 1, "age": 10 } ] + } + }, + { + "type": "mapgen", + "method": "json", + "nested_mapgen_id": "gasoline_diesel_motor_oil", + "object": { + "mapgensize": [ 1, 1 ], + "place_liquids": [ + { "liquid": "gasoline", "x": 0, "y": 0, "chance": 20 }, + { "liquid": "diesel", "x": 0, "y": 0, "chance": 20 }, + { "liquid": "motor_oil", "x": 0, "y": 0, "chance": 20 } + ] + } + } +] diff --git a/data/json/mapgen/mine/mine_shaft.json b/data/json/mapgen/mine/mine_shaft.json new file mode 100644 index 0000000000000..674b1d3d59031 --- /dev/null +++ b/data/json/mapgen/mine/mine_shaft.json @@ -0,0 +1,88 @@ +[ + { + "type": "mapgen", + "method": "json", + "om_terrain": "mine_shaft_middle", + "object": { + "fill_ter": "t_rock", + "rows": [ + " <# ", + " # ", + " # ", + " # ", + " # ", + " # ", + " # ", + " # ", + " # ", + " # ", + " # ", + " # ", + " # ", + " ....#># ", + " ....### ", + " ", + " ", + " ", + " ", + " ", + " ", + " ", + " ", + " " + ], + "terrain": { "<": "t_ladder_up", ">": "t_ladder_down", "#": "t_grate", ".": "t_hole" } + } + }, + { + "type": "mapgen", + "method": "json", + "om_terrain": "mine_shaft_lower", + "object": { + "fill_ter": "t_rock_floor", + "rows": [ + "###### ## ########", + "####### ##########", + "######## ##########", + "######## ########", + " ###### #########", + " ## ##########", + "# ########## ", + " ###### ######### ", + "######## #### #", + "###### ", + "###### ######", + "##### ######", + "### |------| ######", + "# |!@@..<|-| ###", + " |.@@....S| ", + "### |---....S| #", + " +.......S| ", + " |.......S| ####", + "## |LLLLLL|-| ######", + "#### |------| ######", + "###### ######", + "####### ## #######", + "######## ## #######", + "######### # ########" + ], + "terrain": { + "<": "t_ladder_up", + "-": "t_wall", + "|": "t_wall", + ".": "t_thconc_floor", + "+": "t_door_metal_c", + "!": "t_elevator_control", + "@": "t_elevator", + "#": [ [ "t_rock", 4 ], [ "t_rock_floor", 1 ] ], + "L": "t_thconc_floor", + "S": "t_thconc_floor" + }, + "furniture": { "L": "f_locker", "S": "f_utility_shelf" }, + "items": { + "L": [ { "item": "clothing_work_set", "chance": 50 }, { "item": "hardware_clothing", "chance": 50 } ], + "S": { "item": "mine_equipment", "chance": 80 } + } + } + } +] diff --git a/data/json/monsterdrops/zombie_technician.json b/data/json/monsterdrops/zombie_technician.json index 08f86d38970f2..4b460cefd2293 100644 --- a/data/json/monsterdrops/zombie_technician.json +++ b/data/json/monsterdrops/zombie_technician.json @@ -13,5 +13,29 @@ { "group": "supplies_electronics", "prob": 50 }, { "item": "id_industrial", "prob": 20 } ] + }, + { + "id": "mon_zombie_miner_death_drops", + "type": "item_group", + "subtype": "collection", + "entries": [ + { "group": "clothing_work_boots", "damage": [ 1, 4 ] }, + { "group": "clothing_work_glasses", "prob": 60, "damage": [ 1, 4 ] }, + { "group": "clothing_work_gloves", "prob": 75, "damage": [ 1, 4 ] }, + { "group": "clothing_work_mask", "prob": 40, "damage": [ 1, 4 ] }, + { "item": "ear_plugs", "prob": 15, "damage": [ 1, 4 ] }, + { "item": "tool_belt", "prob": 25, "damage": [ 1, 4 ] }, + { + "distribution": [ + { + "collection": [ { "group": "clothing_work_pants", "damage": [ 1, 4 ] }, { "group": "clothing_work_torso", "damage": [ 1, 4 ] } ], + "prob": 75 + }, + { "item": "jumpsuit", "prob": 25, "damage": [ 1, 4 ] } + ] + }, + { "group": "underwear", "damage": [ 1, 4 ] }, + { "item": "miner_hat", "prob": 90, "damage": [ 1, 4 ] } + ] } ] diff --git a/data/json/monsters/zed_misc.json b/data/json/monsters/zed_misc.json index d6290e4a8882b..7303d05206aa1 100644 --- a/data/json/monsters/zed_misc.json +++ b/data/json/monsters/zed_misc.json @@ -1313,6 +1313,41 @@ "RANGED_ATTACKER" ] }, + { + "id": "mon_zombie_miner", + "type": "MONSTER", + "name": { "str": "zombie miner" }, + "description": "This zombie's face, hands, work clothes, and miner's helmet are fully covered with stains of coal dust.", + "default_faction": "zombie", + "looks_like": "mon_zombie_technician", + "bodytype": "human", + "species": [ "ZOMBIE", "HUMAN" ], + "diff": 2, + "volume": "62500 ml", + "weight": "81500 g", + "hp": 85, + "speed": 75, + "material": [ "flesh" ], + "symbol": "Z", + "color": "i_light_cyan", + "aggression": 70, + "morale": 100, + "melee_skill": 5, + "melee_dice": 2, + "melee_dice_sides": 3, + "melee_cut": 0, + "dodge": 1, + "armor_bash": 2, + "armor_cut": 2, + "armor_bullet": 2, + "vision_day": 15, + "vision_night": 2, + "harvest": "zombie", + "special_attacks": [ { "type": "bite", "cooldown": 20 } ], + "death_drops": "mon_zombie_miner_death_drops", + "death_function": [ "NORMAL" ], + "flags": [ "SEES", "HEARS", "SMELLS", "WARM", "BASHES", "GROUP_BASH", "POISON", "NO_BREATHE", "REVIVES", "FILTHY" ] + }, { "id": "mon_zombie_thorny", "type": "MONSTER", diff --git a/data/json/obsolete_terrains.json b/data/json/obsolete_terrains.json index 3bd39eb0b7947..9d6f430d64b54 100644 --- a/data/json/obsolete_terrains.json +++ b/data/json/obsolete_terrains.json @@ -23,7 +23,9 @@ "office_tower_1_entrance", "office_tower_1", "office_tower_b_entrance", - "office_tower_b" + "office_tower_b", + "mine_entrance", + "mine_shaft" ] } ] diff --git a/data/json/overmap/overmap_special/specials.json b/data/json/overmap/overmap_special/specials.json index a224570fb4db6..845aed0757c17 100644 --- a/data/json/overmap/overmap_special/specials.json +++ b/data/json/overmap/overmap_special/specials.json @@ -1126,7 +1126,13 @@ { "type": "overmap_special", "id": "Mine Entrance", - "overmaps": [ { "point": [ 0, 0, 0 ], "overmap": "s_lot_north" }, { "point": [ 0, 1, 0 ], "overmap": "mine_entrance" } ], + "overmaps": [ + { "point": [ 0, 0, 0 ], "overmap": "s_lot_north" }, + { "point": [ 0, 1, 0 ], "overmap": "mine_entrance_north" }, + { "point": [ 0, 1, 1 ], "overmap": "mine_entrance_roof_north" }, + { "point": [ 0, 1, -1 ], "overmap": "mine_shaft_middle_north" }, + { "point": [ 0, 1, -2 ], "overmap": "mine_shaft_lower_north" } + ], "connections": [ { "point": [ 0, -1, 0 ], "terrain": "road", "connection": "local_road", "from": [ 0, 0, 0 ] } ], "locations": [ "wilderness" ], "city_distance": [ 10, 40 ], diff --git a/data/json/overmap/overmap_terrain/overmap_terrain_hardcoded.json b/data/json/overmap/overmap_terrain/overmap_terrain_hardcoded.json index 55f6ceb154e70..9135c4c7402d7 100644 --- a/data/json/overmap/overmap_terrain/overmap_terrain_hardcoded.json +++ b/data/json/overmap/overmap_terrain/overmap_terrain_hardcoded.json @@ -103,24 +103,6 @@ "see_cost": 5, "flags": [ "KNOWN_DOWN", "NO_ROTATE" ] }, - { - "type": "overmap_terrain", - "id": "mine_entrance", - "name": "mine entrance", - "sym": "M", - "color": "magenta", - "see_cost": 5, - "flags": [ "KNOWN_DOWN", "NO_ROTATE" ] - }, - { - "type": "overmap_terrain", - "id": "mine_shaft", - "name": "mine shaft", - "sym": "O", - "color": "dark_gray", - "see_cost": 5, - "flags": [ "KNOWN_UP", "KNOWN_DOWN", "NO_ROTATE" ] - }, { "type": "overmap_terrain", "id": "mine", diff --git a/data/json/overmap/overmap_terrain/overmap_terrain_industrial.json b/data/json/overmap/overmap_terrain/overmap_terrain_industrial.json index 0485bde2cc4ff..805072815c9a4 100644 --- a/data/json/overmap/overmap_terrain/overmap_terrain_industrial.json +++ b/data/json/overmap/overmap_terrain/overmap_terrain_industrial.json @@ -357,5 +357,41 @@ "see_cost": 5, "extras": "build", "mondensity": 2 + }, + { + "type": "overmap_terrain", + "id": "mine_entrance", + "name": "mine entrance", + "sym": "M", + "color": "magenta", + "see_cost": 5, + "flags": [ "KNOWN_DOWN" ] + }, + { + "type": "overmap_terrain", + "id": "mine_entrance_roof", + "name": "mine entrance roof", + "sym": "M", + "color": "magenta", + "see_cost": 5, + "flags": [ "KNOWN_DOWN" ] + }, + { + "type": "overmap_terrain", + "id": "mine_shaft_middle", + "name": "mine shaft", + "sym": "O", + "color": "dark_gray", + "see_cost": 5, + "flags": [ "KNOWN_UP", "KNOWN_DOWN" ] + }, + { + "type": "overmap_terrain", + "id": "mine_shaft_lower", + "name": "mine shaft", + "sym": "O", + "color": "dark_gray", + "see_cost": 5, + "flags": [ "KNOWN_UP" ] } ] diff --git a/data/mods/Graphical_Overmap/go_overmap_terrain_hardcoded.json b/data/mods/Graphical_Overmap/go_overmap_terrain_hardcoded.json index bfad7b7e1e650..cabc893f2281c 100644 --- a/data/mods/Graphical_Overmap/go_overmap_terrain_hardcoded.json +++ b/data/mods/Graphical_Overmap/go_overmap_terrain_hardcoded.json @@ -73,8 +73,20 @@ }, { "type": "overmap_terrain", - "id": "mine_shaft", - "copy-from": "mine_shaft", + "id": "mine_entrance_roof", + "copy-from": "mine_entrance_roof", + "sym": "\u00D3" + }, + { + "type": "overmap_terrain", + "id": "mine_shaft_middle", + "copy-from": "mine_shaft_middle", + "sym": "\u00D3" + }, + { + "type": "overmap_terrain", + "id": "mine_shaft_lower", + "copy-from": "mine_shaft_lower", "sym": "\u00D3" }, { diff --git a/data/mods/alt_map_key/overmap_terrain.json b/data/mods/alt_map_key/overmap_terrain.json index 0d60bd267ba3c..b36f4871df532 100644 --- a/data/mods/alt_map_key/overmap_terrain.json +++ b/data/mods/alt_map_key/overmap_terrain.json @@ -1836,11 +1836,18 @@ }, { "type": "overmap_terrain", - "id": "mine_shaft", - "copy-from": "mine_shaft", - "name": "mine shaft", - "sym": "m", - "color": "i_black" + "id": "mine_entrance_roof", + "copy-from": "mine_entrance_roof" + }, + { + "type": "overmap_terrain", + "id": "mine_shaft_middle", + "copy-from": "mine_shaft_middle" + }, + { + "type": "overmap_terrain", + "id": "mine_shaft_lower", + "copy-from": "mine_shaft_lower" }, { "type": "overmap_terrain", diff --git a/src/mapgen.cpp b/src/mapgen.cpp index 87be7a15af895..f71fed4becd0e 100644 --- a/src/mapgen.cpp +++ b/src/mapgen.cpp @@ -103,8 +103,6 @@ static const trait_id trait_NPC_STATIC_NPC( "NPC_STATIC_NPC" ); static constexpr int MON_RADIUS = 3; static void science_room( map *m, const point &p1, const point &p2, int z, int rotate ); -static void build_mine_room( room_type type, const point &p1, const point &p2, - const mapgendata &dat ); // (x,y,z) are absolute coordinates of a submap // x%2 and y%2 must be 0! @@ -4254,48 +4252,7 @@ void map::draw_temple( const mapgendata &dat ) void map::draw_mine( mapgendata &dat ) { const oter_id &terrain_type = dat.terrain_type(); - if( terrain_type == "mine_entrance" ) { - dat.fill_groundcover(); - int tries = 0; - bool build_shaft = true; - do { - point p1( rng( 1, 2 * SEEX - 10 ), rng( 1, 2 * SEEY - 10 ) ); - point p2( p1 + point( rng( 4, 9 ), rng( 4, 9 ) ) ); - if( build_shaft ) { - build_mine_room( room_mine_shaft, p1, p2, dat ); - build_shaft = false; - } else { - bool okay = true; - for( int x = p1.x - 1; x <= p2.x + 1 && okay; x++ ) { - for( int y = p1.y - 1; y <= p2.y + 1 && okay; y++ ) { - okay = dat.is_groundcover( ter( point( x, y ) ) ); - } - } - if( okay ) { - room_type type = static_cast( rng( room_mine_office, room_mine_housing ) ); - build_mine_room( type, p1, p2, dat ); - tries = 0; - } else { - tries++; - } - } - } while( tries < 5 ); - int ladderx = rng( 0, EAST_EDGE ), laddery = rng( 0, SOUTH_EDGE ); - while( !dat.is_groundcover( ter( point( ladderx, laddery ) ) ) ) { - ladderx = rng( 0, EAST_EDGE ); - laddery = rng( 0, SOUTH_EDGE ); - } - ter_set( point( ladderx, laddery ), t_manhole_cover ); - } else if( terrain_type == "mine_shaft" ) { - // Not intended to actually be inhabited! - fill_background( this, t_rock ); - square( this, t_hole, point( SEEX - 3, SEEY - 3 ), point( SEEX + 2, SEEY + 2 ) ); - line( this, t_grate, point( SEEX - 3, SEEY - 4 ), point( SEEX + 2, SEEY - 4 ) ); - ter_set( point( SEEX - 3, SEEY - 5 ), t_ladder_up ); - ter_set( point( SEEX + 2, SEEY - 5 ), t_ladder_down ); - rotate( rng( 0, 3 ) ); - } else if( terrain_type == "mine" || - terrain_type == "mine_down" ) { + if( terrain_type == "mine" || terrain_type == "mine_down" ) { if( is_ot_match( "mine", dat.north(), ot_match_type::prefix ) ) { dat.n_fac = ( one_in( 10 ) ? 0 : -2 ); } else { @@ -4329,140 +4286,117 @@ void map::draw_mine( mapgendata &dat ) } } - if( dat.above() == "mine_shaft" ) { // We need the entrance room - square( this, t_floor, point( 10, 10 ), point( 15, 15 ) ); - line( this, t_wall, point( 9, 9 ), point( 16, 9 ) ); - line( this, t_wall, point( 9, 16 ), point( 16, 16 ) ); - line( this, t_wall, point( 9, 10 ), point( 9, 15 ) ); - line( this, t_wall, point( 16, 10 ), point( 16, 15 ) ); - line( this, t_wall, point( 10, 11 ), point( 12, 11 ) ); - ter_set( point( 10, 10 ), t_elevator_control ); - ter_set( point( 11, 10 ), t_elevator ); - ter_set( point( 10, 12 ), t_ladder_up ); - line_furn( this, f_counter, point( 10, 15 ), point( 15, 15 ) ); - place_items( item_group_id( "mine_equipment" ), 86, point( 10, 15 ), point( 15, 15 ), - false, calendar::start_of_cataclysm ); - if( one_in( 2 ) ) { - ter_set( point( 9, 12 ), t_door_c ); - } else { - ter_set( point( 16, 12 ), t_door_c ); - } - - } else { // Not an entrance; maybe some hazards! - switch( rng( 0, 6 ) ) { - case 0: - break; // Nothing! Lucky! + // Not an entrance; maybe some hazards! + switch( rng( 0, 6 ) ) { + case 0: + break; // Nothing! Lucky! - case 1: { // Toxic gas - int cx = rng( 9, 14 ); - int cy = rng( 9, 14 ); - ter_set( point( cx, cy ), t_rock ); - add_field( {cx, cy, abs_sub.z}, fd_gas_vent, 2 ); - } - break; + case 1: { // Toxic gas + point gas_vent_location( rng( 9, 14 ), rng( 9, 14 ) ); + ter_set( point( gas_vent_location ), t_rock ); + add_field( { gas_vent_location, abs_sub.z}, fd_gas_vent, 2 ); + } + break; - case 2: { // Lava - int x1 = rng( 6, SEEX ); - int y1 = rng( 6, SEEY ); - int x2 = rng( SEEX + 1, SEEX * 2 - 7 ); - int y2 = rng( SEEY + 1, SEEY * 2 - 7 ); - int num = rng( 2, 4 ); - for( int i = 0; i < num; i++ ) { - int lx1 = x1 + rng( -1, 1 ), lx2 = x2 + rng( -1, 1 ), - ly1 = y1 + rng( -1, 1 ), ly2 = y2 + rng( -1, 1 ); - line( this, t_lava, point( lx1, ly1 ), point( lx2, ly2 ) ); - } + case 2: { // Lava + point start_location( rng( 6, SEEX ), rng( 6, SEEY ) ); + point end_location( rng( SEEX + 1, SEEX * 2 - 7 ), rng( SEEY + 1, SEEY * 2 - 7 ) ); + const int num = rng( 2, 4 ); + for( int i = 0; i < num; i++ ) { + int lx1 = start_location.x + rng( -1, 1 ), lx2 = end_location.x + rng( -1, 1 ), + ly1 = start_location.y + rng( -1, 1 ), ly2 = end_location.y + rng( -1, 1 ); + line( this, t_lava, point( lx1, ly1 ), point( lx2, ly2 ) ); } - break; + } + break; - case 3: { // Wrecked equipment - int x = rng( 9, 14 ); - int y = rng( 9, 14 ); - for( int i = x - 3; i < x + 3; i++ ) { - for( int j = y - 3; j < y + 3; j++ ) { - if( !one_in( 4 ) ) { - make_rubble( tripoint( i, j, abs_sub.z ), f_wreckage, true ); - } + case 3: { // Wrecked equipment + point wreck_location( rng( 9, 14 ), rng( 9, 14 ) ); + for( int i = wreck_location.x - 3; i < wreck_location.x + 3; i++ ) { + for( int j = wreck_location.y - 3; j < wreck_location.y + 3; j++ ) { + if( !one_in( 4 ) ) { + make_rubble( tripoint( i, j, abs_sub.z ), f_wreckage, true ); } } - place_items( item_group_id( "wreckage" ), 70, point( x - 3, y - 3 ), - point( x + 2, y + 2 ), false, calendar::start_of_cataclysm ); } - break; + place_items( item_group_id( "wreckage" ), 70, wreck_location + point( -3, -3 ), + wreck_location + point( 2, 2 ), false, calendar::start_of_cataclysm ); + } + break; - case 4: { // Dead miners - int num_bodies = rng( 4, 8 ); - for( int i = 0; i < num_bodies; i++ ) { - if( const auto body = random_point( *this, [this]( const tripoint & p ) { - return move_cost( p ) == 2; - } ) ) { - add_item( *body, item::make_corpse() ); - place_items( item_group_id( "mine_equipment" ), 60, *body, *body, - false, calendar::start_of_cataclysm ); - } + case 4: { // Dead miners + const int num_bodies = rng( 4, 8 ); + for( int i = 0; i < num_bodies; i++ ) { + if( const auto body = random_point( *this, [this]( const tripoint & p ) { + return move_cost( p ) == 2; + } ) ) { + add_item( *body, item::make_corpse() ); + place_items( item_group_id( "mine_equipment" ), 60, *body, *body, + false, calendar::start_of_cataclysm ); } } - break; + } + break; - case 5: { // Dark worm! - int num_worms = rng( 1, 5 ); - for( int i = 0; i < num_worms; i++ ) { - std::vector sides; - if( dat.n_fac == 6 ) { - sides.push_back( direction::NORTH ); - } - if( dat.e_fac == 6 ) { - sides.push_back( direction::EAST ); - } - if( dat.s_fac == 6 ) { - sides.push_back( direction::SOUTH ); - } - if( dat.w_fac == 6 ) { - sides.push_back( direction::WEST ); - } - if( sides.empty() ) { - place_spawns( GROUP_DARK_WYRM, 1, point( SEEX, SEEY ), point( SEEX, SEEY ), 1, true ); - i = num_worms; - } else { - point p; - switch( random_entry( sides ) ) { - case direction::NORTH: - p = point( rng( 1, SEEX * 2 - 2 ), rng( 1, 5 ) ); - break; - case direction::EAST: - p = point( SEEX * 2 - rng( 2, 6 ), rng( 1, SEEY * 2 - 2 ) ); - break; - case direction::SOUTH: - p = point( rng( 1, SEEX * 2 - 2 ), SEEY * 2 - rng( 2, 6 ) ); - break; - case direction::WEST: - p = point( rng( 1, 5 ), rng( 1, SEEY * 2 - 2 ) ); - break; - default: - break; - } - ter_set( p, t_rock_floor ); - place_spawns( GROUP_DARK_WYRM, 1, p, p, 1, true ); + case 5: { // Dark worm! + const int num_worms = rng( 1, 5 ); + for( int i = 0; i < num_worms; i++ ) { + std::vector sides; + if( dat.n_fac == 6 ) { + sides.push_back( direction::NORTH ); + } + if( dat.e_fac == 6 ) { + sides.push_back( direction::EAST ); + } + if( dat.s_fac == 6 ) { + sides.push_back( direction::SOUTH ); + } + if( dat.w_fac == 6 ) { + sides.push_back( direction::WEST ); + } + if( sides.empty() ) { + place_spawns( GROUP_DARK_WYRM, 1, point( SEEX, SEEY ), point( SEEX, SEEY ), 1, true ); + i = num_worms; + } else { + point p; + switch( random_entry( sides ) ) { + case direction::NORTH: + p = point( rng( 1, SEEX * 2 - 2 ), rng( 1, 5 ) ); + break; + case direction::EAST: + p = point( SEEX * 2 - rng( 2, 6 ), rng( 1, SEEY * 2 - 2 ) ); + break; + case direction::SOUTH: + p = point( rng( 1, SEEX * 2 - 2 ), SEEY * 2 - rng( 2, 6 ) ); + break; + case direction::WEST: + p = point( rng( 1, 5 ), rng( 1, SEEY * 2 - 2 ) ); + break; + default: + break; } + ter_set( p, t_rock_floor ); + place_spawns( GROUP_DARK_WYRM, 1, p, p, 1, true ); } } - break; + } + break; - case 6: { // Spiral - int orx = rng( SEEX - 4, SEEX ), ory = rng( SEEY - 4, SEEY ); - line( this, t_rock, point( orx, ory ), point( orx + 5, ory ) ); - line( this, t_rock, point( orx + 5, ory ), point( orx + 5, ory + 5 ) ); - line( this, t_rock, point( orx + 1, ory + 5 ), point( orx + 5, ory + 5 ) ); - line( this, t_rock, point( orx + 1, ory + 2 ), point( orx + 1, ory + 4 ) ); - line( this, t_rock, point( orx + 1, ory + 2 ), point( orx + 3, ory + 2 ) ); - ter_set( point( orx + 3, ory + 3 ), t_rock ); - add_item( point( orx + 2, ory + 3 ), item::make_corpse() ); - place_items( item_group_id( "mine_equipment" ), 60, point( orx + 2, ory + 3 ), - point( orx + 2, ory + 3 ), false, calendar::start_of_cataclysm ); - } - break; + case 6: { // Spiral + const int orx = rng( SEEX - 4, SEEX ), ory = rng( SEEY - 4, SEEY ); + line( this, t_rock, point( orx, ory ), point( orx + 5, ory ) ); + line( this, t_rock, point( orx + 5, ory ), point( orx + 5, ory + 5 ) ); + line( this, t_rock, point( orx + 1, ory + 5 ), point( orx + 5, ory + 5 ) ); + line( this, t_rock, point( orx + 1, ory + 2 ), point( orx + 1, ory + 4 ) ); + line( this, t_rock, point( orx + 1, ory + 2 ), point( orx + 3, ory + 2 ) ); + ter_set( point( orx + 3, ory + 3 ), t_rock ); + add_item( point( orx + 2, ory + 3 ), item::make_corpse() ); + place_items( item_group_id( "mine_equipment" ), 60, point( orx + 2, ory + 3 ), + point( orx + 2, ory + 3 ), false, calendar::start_of_cataclysm ); } + break; } + if( terrain_type == "mine_down" ) { // Don't forget to build a slope down! std::vector open; if( dat.n_fac == 4 ) { @@ -4634,14 +4568,14 @@ void map::draw_mine( mapgendata &dat ) computer *tmpcomp = nullptr; switch( rn ) { case 1: { // Wyrms - int x = rng( SEEX, SEEX + 1 ), y = rng( SEEY, SEEY + 1 ); + const int x = rng( SEEX, SEEX + 1 ), y = rng( SEEY, SEEY + 1 ); ter_set( point( x, y ), t_pedestal_wyrm ); spawn_item( point( x, y ), "petrified_eye" ); } break; // That's it! game::examine handles the pedestal/wyrm spawns case 2: { // The Thing dog - int num_bodies = rng( 4, 8 ); + const int num_bodies = rng( 4, 8 ); for( int i = 0; i < num_bodies; i++ ) { int x = rng( 4, SEEX * 2 - 5 ); int y = rng( 4, SEEX * 2 - 5 ); @@ -6126,191 +6060,6 @@ void science_room( map *m, const point &p1, const point &p2, int z, int rotate ) } } -void build_mine_room( room_type type, const point &p1, const point &p2, const mapgendata &dat ) -{ - map *const m = &dat.m; - std::vector possibilities; - point mid( static_cast( ( p1.x + p2.x ) / 2 ), static_cast( ( p1.y + p2.y ) / 2 ) ); - if( p2.x < SEEX ) { - possibilities.push_back( direction::EAST ); - } - if( p1.x > SEEX + 1 ) { - possibilities.push_back( direction::WEST ); - } - if( p1.y > SEEY + 1 ) { - possibilities.push_back( direction::NORTH ); - } - if( p2.y < SEEY ) { - possibilities.push_back( direction::SOUTH ); - } - - if( possibilities.empty() ) { // We're in the middle of the map! - if( mid.x <= SEEX ) { - possibilities.push_back( direction::EAST ); - } else { - possibilities.push_back( direction::WEST ); - } - if( mid.y <= SEEY ) { - possibilities.push_back( direction::SOUTH ); - } else { - possibilities.push_back( direction::NORTH ); - } - } - - const direction door_side = random_entry( possibilities ); - point door_point; - switch( door_side ) { - case direction::NORTH: - door_point.x = mid.x; - door_point.y = p1.y; - break; - case direction::EAST: - door_point.x = p2.x; - door_point.y = mid.y; - break; - case direction::SOUTH: - door_point.x = mid.x; - door_point.y = p2.y; - break; - case direction::WEST: - door_point.x = p1.x; - door_point.y = mid.y; - break; - default: - break; - } - square( m, t_floor, p1, p2 ); - line( m, t_wall, p1, point( p2.x, p1.y ) ); - line( m, t_wall, point( p1.x, p2.y ), p2 ); - line( m, t_wall, p1 + point_south, point( p1.x, p2.y - 1 ) ); - line( m, t_wall, point( p2.x, p1.y + 1 ), p2 + point_north ); - // Main build switch! - switch( type ) { - case room_mine_shaft: { - m->furn_set( p1 + point_south_east, furn_str_id( "f_console" ) ); - line( m, t_wall, point( p2.x - 2, p1.y + 2 ), point( p2.x - 1, p1.y + 2 ) ); - m->ter_set( point( p2.x - 2, p1.y + 1 ), t_elevator ); - m->ter_set( point( p2.x - 1, p1.y + 1 ), t_elevator_control_off ); - computer *tmpcomp = m->add_computer( p1 + tripoint( 1, 1, m->get_abs_sub().z ), - _( "NEPowerOS" ), 2 ); - tmpcomp->add_option( _( "Divert power to elevator" ), COMPACT_ELEVATOR_ON, 0 ); - tmpcomp->add_failure( COMPFAIL_ALARM ); - } - break; - - case room_mine_office: - line_furn( m, f_counter, point( mid.x, p1.y + 2 ), point( mid.x, p2.y - 2 ) ); - line( m, t_window, point( mid.x - 1, p1.y ), point( mid.x + 1, p1.y ) ); - line( m, t_window, point( mid.x - 1, p2.y ), point( mid.x + 1, p2.y ) ); - line( m, t_window, point( p1.x, mid.y - 1 ), point( p1.x, mid.y + 1 ) ); - line( m, t_window, point( p2.x, mid.y - 1 ), point( p2.x, mid.y + 1 ) ); - m->place_items( item_group_id( "office" ), 80, p1 + point_south_east, - p2 + point_north_west, false, calendar::start_of_cataclysm ); - break; - - case room_mine_storage: - m->place_items( item_group_id( "mine_storage" ), 85, p1 + point( 2, 2 ), - p2 + point( -2, -2 ), false, calendar::start_of_cataclysm ); - break; - - case room_mine_fuel: { - int spacing = rng( 2, 4 ); - if( door_side == direction::NORTH || door_side == direction::SOUTH ) { - int y = ( door_side == direction::NORTH ? p1.y + 2 : p2.y - 2 ); - for( int x = p1.x + 1; x <= p2.x - 1; x += spacing ) { - m->place_gas_pump( point( x, y ), rng( 10000, 50000 ) ); - } - } else { - int x = ( door_side == direction::EAST ? p2.x - 2 : p1.x + 2 ); - for( int y = p1.y + 1; y <= p2.y - 1; y += spacing ) { - m->place_gas_pump( point( x, y ), rng( 10000, 50000 ) ); - } - } - } - break; - - case room_mine_housing: - if( door_side == direction::NORTH || door_side == direction::SOUTH ) { - for( int y = p1.y + 2; y <= p2.y - 2; y += 2 ) { - m->ter_set( point( p1.x, y ), t_window ); - m->furn_set( point( p1.x + 1, y ), f_bed ); - m->place_items( item_group_id( "bed" ), 60, point( p1.x + 1, y ), - point( p1.x + 1, y ), false, calendar::start_of_cataclysm ); - m->furn_set( point( p1.x + 2, y ), f_bed ); - m->place_items( item_group_id( "bed" ), 60, point( p1.x + 2, y ), - point( p1.x + 2, y ), false, calendar::start_of_cataclysm ); - m->ter_set( point( p2.x, y ), t_window ); - m->furn_set( point( p2.x - 1, y ), f_bed ); - m->place_items( item_group_id( "bed" ), 60, point( p2.x - 1, y ), - point( p2.x - 1, y ), false, calendar::start_of_cataclysm ); - m->furn_set( point( p2.x - 2, y ), f_bed ); - m->place_items( item_group_id( "bed" ), 60, point( p2.x - 2, y ), - point( p2.x - 2, y ), false, calendar::start_of_cataclysm ); - m->furn_set( point( p1.x + 1, y + 1 ), f_dresser ); - m->place_items( item_group_id( "dresser" ), 78, point( p1.x + 1, y + 1 ), - point( p1.x + 1, y + 1 ), false, calendar::start_of_cataclysm ); - m->furn_set( point( p2.x - 1, y + 1 ), f_dresser ); - m->place_items( item_group_id( "dresser" ), 78, point( p2.x - 1, y + 1 ), - point( p2.x - 1, y + 1 ), false, calendar::start_of_cataclysm ); - } - } else { - for( int x = p1.x + 2; x <= p2.x - 2; x += 2 ) { - m->ter_set( point( x, p1.y ), t_window ); - m->furn_set( point( x, p1.y + 1 ), f_bed ); - m->place_items( item_group_id( "bed" ), 60, point( x, p1.y + 1 ), - point( x, p1.y + 1 ), false, calendar::start_of_cataclysm ); - m->furn_set( point( x, p1.y + 2 ), f_bed ); - m->place_items( item_group_id( "bed" ), 60, point( x, p1.y + 2 ), - point( x, p1.y + 2 ), false, calendar::start_of_cataclysm ); - m->ter_set( point( x, p2.y ), t_window ); - m->furn_set( point( x, p2.y - 1 ), f_bed ); - m->place_items( item_group_id( "bed" ), 60, point( x, p2.y - 1 ), - point( x, p2.y - 1 ), false, calendar::start_of_cataclysm ); - m->furn_set( point( x, p2.y - 2 ), f_bed ); - m->place_items( item_group_id( "bed" ), 60, point( x, p2.y - 2 ), - point( x, p2.y - 2 ), false, calendar::start_of_cataclysm ); - m->furn_set( point( x + 1, p1.y + 1 ), f_dresser ); - m->place_items( item_group_id( "dresser" ), 78, point( x + 1, p1.y + 1 ), - point( x + 1, p1.y + 1 ), false, calendar::start_of_cataclysm ); - m->furn_set( point( x + 1, p2.y - 1 ), f_dresser ); - m->place_items( item_group_id( "dresser" ), 78, point( x + 1, p2.y - 1 ), - point( x + 1, p2.y - 1 ), false, calendar::start_of_cataclysm ); - } - } - m->place_items( item_group_id( "bedroom" ), 65, p1 + point_south_east, - p2 + point_north_west, false, calendar::start_of_cataclysm ); - break; - default: - //Suppress warnings - break; - } - - if( type == room_mine_fuel ) { // Fuel stations are open on one side - switch( door_side ) { - case direction::NORTH: - line( m, t_floor, p1, point( p2.x, p1.y ) ); - break; - case direction::EAST: - line( m, t_floor, point( p2.x, p1.y + 1 ), p2 + point_north ); - break; - case direction::SOUTH: - line( m, t_floor, point( p1.x, p2.y ), p2 ); - break; - case direction::WEST: - line( m, t_floor, p1 + point_south, point( p1.x, p2.y - 1 ) ); - break; - default: - break; - } - } else { - if( type == room_mine_storage ) { // Storage has a locked door - m->ter_set( door_point, t_door_locked ); - } else { - m->ter_set( door_point, t_door_c ); - } - } -} - void map::create_anomaly( const tripoint &cp, artifact_natural_property prop, bool create_rubble ) { // TODO: Z diff --git a/src/mapgen.h b/src/mapgen.h index 4dda960cc54bc..7767c4ddc683a 100644 --- a/src/mapgen.h +++ b/src/mapgen.h @@ -458,11 +458,6 @@ enum room_type { room_bedroom, room_backyard, room_study, - room_mine_shaft, - room_mine_office, - room_mine_storage, - room_mine_fuel, - room_mine_housing, room_split }; diff --git a/src/overmap.cpp b/src/overmap.cpp index f103a7b8ffde3..83e9edf6e7e0b 100644 --- a/src/overmap.cpp +++ b/src/overmap.cpp @@ -744,9 +744,7 @@ bool oter_t::is_hardcoded() const "looted_building", // pseudo-terrain "mine", "mine_down", - "mine_entrance", "mine_finale", - "mine_shaft", "office_tower_1", "office_tower_1_entrance", "office_tower_b", @@ -1513,7 +1511,6 @@ bool overmap::generate_sub( const int z ) std::vector central_lab_points; std::vector lab_train_points; std::vector central_lab_train_points; - std::vector shaft_points; std::vector mine_points; // These are so common that it's worth checking first as int. const oter_id skip_above[5] = { @@ -1583,10 +1580,10 @@ bool overmap::generate_sub( const int z ) ter_set( p, oter_id( "central_lab" ) ); } else if( is_ot_match( "hidden_lab_stairs", oter_above, ot_match_type::contains ) ) { lab_points.push_back( city( p.xy(), rng( 1, 5 + z ) ) ); - } else if( oter_above == "mine_entrance" ) { - shaft_points.push_back( p.xy() ); - } else if( oter_above == "mine_shaft" || - oter_above == "mine_down" ) { + } else if( is_ot_match( "mine_entrance", oter_ground, ot_match_type::type ) && z == -2 ) { + mine_points.push_back( city( ( p + tripoint_west ).xy(), rng( 6 + z, 10 + z ) ) ); + requires_sub = true; + } else if( oter_above == "mine_down" ) { ter_set( p, oter_id( "mine" ) ); mine_points.push_back( city( p.xy(), rng( 6 + z, 10 + z ) ) ); // technically not all finales need a sub level, @@ -1746,10 +1743,6 @@ bool overmap::generate_sub( const int z ) build_mine( tripoint_om_omt( i.pos, z ), i.size ); } - for( auto &i : shaft_points ) { - ter_set( tripoint_om_omt( i, z ), oter_id( "mine_shaft" ) ); - requires_sub = true; - } for( auto &i : ant_points ) { const tripoint_om_omt p_loc( i.pos, z ); if( ter( p_loc ) != "empty_rock" ) { diff --git a/src/savegame.cpp b/src/savegame.cpp index 941fc16a7f334..96a1b941acfd4 100644 --- a/src/savegame.cpp +++ b/src/savegame.cpp @@ -348,7 +348,7 @@ void overmap::convert_terrain( if( old == "fema" || old == "fema_entrance" || old == "fema_1_3" || old == "fema_2_1" || old == "fema_2_2" || old == "fema_2_3" || old == "fema_3_1" || old == "fema_3_2" || old == "fema_3_3" || - old == "s_lot" ) { + old == "s_lot" || old == "mine_entrance" ) { ter_set( pos, oter_id( old + "_north" ) ); } else if( old.compare( 0, 6, "bridge" ) == 0 ) { ter_set( pos, oter_id( old ) ); @@ -361,6 +361,8 @@ void overmap::convert_terrain( } } else if( old.compare( 0, 10, "mass_grave" ) == 0 ) { ter_set( pos, oter_id( "field" ) ); + } else if( old == "mine_shaft" ) { + ter_set( pos, oter_id( "mine_shaft_middle_north" ) ); } else if( old.compare( 0, 23, "office_tower_1_entrance" ) == 0 ) { ter_set( pos, oter_id( "office_tower_ne_north" ) ); ter_set( pos + point_west, oter_id( "office_tower_nw_north" ) ); From 40c0653d5f1c159841ff56a768b3ab095d17259c Mon Sep 17 00:00:00 2001 From: actual-nh <74678550+actual-nh@users.noreply.github.com> Date: Thu, 4 Mar 2021 16:19:20 -0500 Subject: [PATCH 040/453] Add 0.F-dev to matrix.yml (#47875) (Getting 0.F-dev working with Travis appears to require additional settings by someone with permissions.) This change enables both pushes and pull requests of 0.F-dev to get checked by the General Matrix. As it is, if one bases a PR off of 0.F-dev, it doesn't get checked by Github. --- .github/workflows/matrix.yml | 2 ++ 1 file changed, 2 insertions(+) diff --git a/.github/workflows/matrix.yml b/.github/workflows/matrix.yml index 2a9445b3239c1..473ec2d77281a 100644 --- a/.github/workflows/matrix.yml +++ b/.github/workflows/matrix.yml @@ -4,6 +4,7 @@ on: push: branches: - master + - 0.F-dev paths-ignore: - 'android/**' - 'build-data/osx/**' @@ -18,6 +19,7 @@ on: pull_request: branches: - master + - 0.F-dev paths-ignore: - 'android/**' - 'build-data/osx/**' From 0ed6845f8a930f3a28621023c72fc73acd0d2b5d Mon Sep 17 00:00:00 2001 From: actual-nh <74678550+actual-nh@users.noreply.github.com> Date: Fri, 5 Mar 2021 05:12:40 -0500 Subject: [PATCH 041/453] 0.F-dev workflows (#47875) --- .github/workflows/clang-tidy.yml | 2 ++ .github/workflows/cmake-format.yml | 2 ++ .github/workflows/flake8.yml | 2 ++ .github/workflows/pr-validator.yml | 1 + 4 files changed, 7 insertions(+) diff --git a/.github/workflows/clang-tidy.yml b/.github/workflows/clang-tidy.yml index 56ee2ee858be7..6d888a7be574c 100644 --- a/.github/workflows/clang-tidy.yml +++ b/.github/workflows/clang-tidy.yml @@ -4,6 +4,7 @@ on: push: branches: - master + - 0.F-dev paths: - '**.cpp' - '**.h' @@ -15,6 +16,7 @@ on: pull_request: branches: - master + - 0.F-dev paths: - '**.cpp' - '**.h' diff --git a/.github/workflows/cmake-format.yml b/.github/workflows/cmake-format.yml index bba76717aaef4..563127694ade7 100644 --- a/.github/workflows/cmake-format.yml +++ b/.github/workflows/cmake-format.yml @@ -4,6 +4,7 @@ on: push: branches: - master + - 0.F-dev paths: - '**/CMakeLists.txt' - '**.cmake' @@ -11,6 +12,7 @@ on: pull_request: branches: - master + - 0.F-dev paths: - '**/CMakeLists.txt' - '**.cmake' diff --git a/.github/workflows/flake8.yml b/.github/workflows/flake8.yml index ed7b63dbbc07a..4434a75707c6d 100644 --- a/.github/workflows/flake8.yml +++ b/.github/workflows/flake8.yml @@ -4,11 +4,13 @@ on: push: branches: - master + - 0.F-dev paths: - '**.py' pull_request: branches: - master + - 0.F-dev paths: - '**.py' diff --git a/.github/workflows/pr-validator.yml b/.github/workflows/pr-validator.yml index 2897f6a160c1b..62c6095211c5e 100644 --- a/.github/workflows/pr-validator.yml +++ b/.github/workflows/pr-validator.yml @@ -3,6 +3,7 @@ on: pull_request: branches: - master + - 0.F-dev types: [opened, edited, synchronize] jobs: validate: From b9ff9dbf848261f81e270180719938eb331ac9c1 Mon Sep 17 00:00:00 2001 From: actual-nh Date: Sat, 6 Mar 2021 14:33:47 -0500 Subject: [PATCH 042/453] Alter brown bread recipe to match canned version (#47915) Fixes #47874. --- data/json/recipes/food/bread.json | 2 ++ 1 file changed, 2 insertions(+) diff --git a/data/json/recipes/food/bread.json b/data/json/recipes/food/bread.json index 77e84cf6bf0eb..d8ae2930a9b1a 100644 --- a/data/json/recipes/food/bread.json +++ b/data/json/recipes/food/bread.json @@ -44,6 +44,8 @@ [ [ "flour", 5 ] ], [ [ "cornmeal", 5 ] ], [ [ "molasses", 2 ] ], + [ [ "sugar", 1 ] ], + [ [ "molasses", 1 ], [ "sugar", 13 ] ], [ [ "water", 1 ], [ "water_clean", 1 ] ], [ [ "salt", 1 ] ] ], From 59aaf2db258b26ae5e78f321c09749028149a7f7 Mon Sep 17 00:00:00 2001 From: Anton Burmistrov Date: Tue, 9 Mar 2021 00:34:10 +0400 Subject: [PATCH 043/453] Mine entrance expand (#47928) * Added mine_materials item group * Added Trolley vehicle * Expanded and tweaked above-ground and underground levels of mine entrance --- .../Locations_MapExtras/locations.json | 20 +++ data/json/mapgen/mine/mine_entrance.json | 131 +++++++++++------- data/json/mapgen/mine/mine_shaft.json | 88 ++++++------ .../overmap/overmap_special/specials.json | 10 +- .../overmap_terrain_industrial.json | 9 +- data/json/vehicles/trains.json | 7 + 6 files changed, 163 insertions(+), 102 deletions(-) diff --git a/data/json/itemgroups/Locations_MapExtras/locations.json b/data/json/itemgroups/Locations_MapExtras/locations.json index 7d728d02b06ca..a3670f5a8f9ca 100644 --- a/data/json/itemgroups/Locations_MapExtras/locations.json +++ b/data/json/itemgroups/Locations_MapExtras/locations.json @@ -1218,6 +1218,26 @@ [ "tool_anfo_charge", 2 ] ] }, + { + "type": "item_group", + "id": "mine_materials", + "subtype": "collection", + "entries": [ + { "item": "coal_lump", "prob": 20, "count": [ 1, 10 ] }, + { "item": "rock", "prob": 40, "count": [ 1, 10 ] }, + { "item": "rock_large", "prob": 10, "count": [ 1, 10 ] }, + { "item": "rock_flaking", "prob": 20, "count": [ 1, 10 ] }, + { "item": "material_shrd_limestone", "prob": 40, "count": [ 1, 10 ] }, + { "item": "material_limestone", "prob": 40, "count": [ 1, 10 ] }, + { "item": "material_niter", "prob": 5, "count": [ 1, 10 ] }, + { "item": "material_sand", "prob": 50, "charges": 500, "container-item": "bag_canvas" }, + { "item": "material_soil", "prob": 50, "charges": 500, "container-item": "bag_canvas" }, + { "item": "chunk_sulfur", "prob": 5, "count": [ 1, 10 ] }, + { "item": "material_rocksalt", "prob": 5, "count": [ 1, 10 ] }, + { "item": "material_rhodonite", "prob": 5, "count": [ 1, 10 ] }, + { "item": "material_zincite", "prob": 5, "count": [ 1, 10 ] } + ] + }, { "type": "item_group", "id": "mine_equipment", diff --git a/data/json/mapgen/mine/mine_entrance.json b/data/json/mapgen/mine/mine_entrance.json index 71f2e6a6508c2..f6b517c69f266 100644 --- a/data/json/mapgen/mine/mine_entrance.json +++ b/data/json/mapgen/mine/mine_entrance.json @@ -2,33 +2,33 @@ { "type": "mapgen", "method": "json", - "om_terrain": "mine_entrance", + "om_terrain": [ [ "mine_entrance", "mine_entrance_loading_zone" ] ], "object": { "rows": [ - "fffffffffffФФfffffffffff", - "f v ,,,,,,,,,,,, !f", - "f/ ,,,,,,,,,,,,,,,,,f", - "|-000--000-0+0|00--00|,f", - "|dddrFFddcW..2|2..Fdd|,f", - "0dC.....Cc....?....dC|,f", - "0............a|b...d.|,f", - "0..C...|*-|-*-|b.....|,f", - "|rddd1p|.l|&_s|a36561|,f", - "|-000--|--|---|------|,f", - "f ,,,,,,,,,,,,,,,,,f", - "|----|+|----| ,,,,,,,/f", - "|I.hĎ|.|дh.I| ,|---%--|", - "0BB..+.+..BB0 ,|eEE~~4|", - "|----|.|----| ,|~EE~~4|", - "|I.hĎ|.|дh.I| ,|------|", - "0BB..+.+..BB0 ,|888888|", - "|----|.|----| ,?~~~~~8|", - "|I.hD|.|Дh.I| ,|888888|", - "0BB..+.+..BB0 ,|------|", - "|----|.|----| ,^`````@|", - "|&___+.+____| ,^``````|", - "|R__s|.|Й__7|/ №|999``$|", - "|----|0|----|fff|------|" + "fffffffffffФФfffffffffffffffФФФФФffffffФФФФФff ", + "f v ,,,,,,,,,,,, ! f ;;;;;;;;;;;;;;;; f ", + "f/ ,,,,,,,,,,,,,,,,, f ;;;;;;;;;;;;;;;; f ", + "|-000--000-0+0|00--00|, f ;;;;;;;;;;;;;;;; f ", + "|dddrFFddcW..2|2..Fdd|, f ;°°°;;;;;;;;;°;; f ", + "0dC.....Cc....?....dC|, f ;°°°;;;;;;;;°°°; f ", + "0............a|b...d.|, f ;°°°;;;;;;;°°°°° f ", + "0..C...|*-|-*-|b.....|, f °°°°°;;;;;;;°°°; f ", + "|rddd1p|.l|&_s|a36561|, f ;°°°;;;;;;;;°°°; f ", + "|-000--|--|---|------|, f ;;°;;;;;;;;;°°°; f ", + "f ,,,,,,,,,,,,,,,,,,,,,,;;;;;;;;;;;;;;;; f ", + "|----|+|----| ,,,,,,,,,,,,,;;;;;;;;;;;;;;;; f ", + "|I.hĎ|.|дh.I| ,|---%-------;;;;;;;;;;;;;;;; f ", + "0BB..+.+..BB0 ,|eEE~~~eEE®®;;;;;;Ø;;;;;;;;; f ", + "|----|.|----| ,|~EE~~~~EE==;;;;;;;;;;;;;;;; f ", + "|I.hĎ|.|дh.I| ,|------|EE=~;;;;;;;;;;;;;;;; f ", + "0BB..+.+..BB0 ,|TTogTr|~~=~;;;;;;;;;;;;;;;; f ", + "|----|.|----| ,0S....Ć|8~=~8| |````| f ", + "|I.hD|.|Дh.I| ,|a....Ĉ|8~=~8| |$``@| f ", + "0BB..+.+..BB0 ,|----+-|8~=~8| |````| f ", + "|----|.|----| ,|hth..h|8~=~8| |````| f ", + "|&___+.+____| ,+.....t|8~~~8| |````| f ", + "|R__s|.|Й__7|/ /|hth..h|88888|/ /|9999| f ", + "|----|0|----|fff|-0--0-|-----|fff|----|fffffff " ], "fill_ter": "t_floor", "terrain": { @@ -43,12 +43,15 @@ "?": "t_door_locked_alarm", "+": "t_door_locked", "%": "t_door_metal_c", - "^": "t_door_metal_locked", - "№": "t_gates_mech_control", ",": "t_sidewalk", + ";": "t_pavement", + "°": "t_pavement_y", + "Ø": "t_pavement", ".": "t_floor", "~": "t_thconc_floor", "`": "t_thconc_floor", + "®": "t_thconc_floor", + "=": "t_conveyor", "0": "t_metal_grate_window_with_curtain", "4": "t_thconc_floor", "8": "t_thconc_floor", @@ -66,6 +69,7 @@ "Ф": "t_chaingate_l" }, "furniture": { + "®": "f_machinery_heavy", "1": "f_shredder", "2": "f_rack_coat", "3": "f_server", @@ -79,18 +83,25 @@ "B": "f_bed", "b": "f_bookcase", "c": "f_counter", + "Ć": "f_cupboard", + "Ĉ": "f_cupboard", "C": "f_chair", "d": "f_desk", "D": "f_desk", "Ď": "f_desk", "F": "f_filing_cabinet", + "g": "f_fridge", "h": "f_chair", "I": "f_dresser", "l": "f_locker", + "o": "f_oven", "p": [ "f_indoor_plant", "f_indoor_plant_y" ], "R": "f_trashcan", "r": "f_trashcan", + "S": "f_sink", "s": "f_sink", + "T": "f_counter", + "t": "f_table", "v": "f_vent_pipe", "Д": "f_desk", "д": "f_desk", @@ -99,20 +110,33 @@ "toilets": { "&": { } }, "items": { "2": { "item": "coat_rack", "chance": 60, "repeat": 2 }, - "8": { "item": "mine_storage", "chance": 50, "repeat": 4 }, + "8": { "item": "mine_materials", "chance": 50, "repeat": 4 }, "9": { "item": "car_kit", "chance": 60, "repeat": 2 }, "B": { "item": "bed", "chance": 50 }, "b": { "item": "lab_bookshelves", "chance": 60, "repeat": 2 }, "c": { "item": "office_supplies", "chance": 60 }, + "Ć": [ + { "item": "SUS_silverware", "chance": 80 }, + { "item": "SUS_utensils", "chance": 80 }, + { "item": "SUS_knife_drawer", "chance": 80 }, + { "item": "SUS_dishes", "chance": 80 }, + { "item": "SUS_cookware", "chance": 80 } + ], + "Ĉ": { "item": "SUS_pantry", "chance": 80 }, "D": { "item": "SUS_junk_drawer_artsy", "chance": 90 }, "Ď": { "item": "SUS_junk_drawer_messy", "chance": 90 }, "d": { "item": "SUS_office_desk", "chance": 90 }, "F": { "item": "SUS_office_filing_cabinet", "chance": 90 }, + "g": { "item": "SUS_fridge", "chance": 80 }, "I": { "item": "SUS_dresser_mens", "chance": 60 }, "l": { "item": "SUS_janitors_closet", "chance": 85 }, + "o": { "item": "SUS_oven", "chance": 70 }, "R": { "item": "trash_cart", "chance": 50 }, "r": { "item": "trash_cart", "chance": 50 }, + "S": { "item": "SUS_kitchen_sink", "chance": 90 }, "s": { "item": "SUS_bathroom_sink", "chance": 70 }, + "T": { "item": "SUS_appliances_cupboard", "chance": 10 }, + "t": { "item": "dining", "chance": 45 }, "Д": { "item": "SUS_junk_drawer_handy", "chance": 90 }, "д": { "item": "SUS_junk_drawer_tidy", "chance": 90 } }, @@ -132,39 +156,40 @@ } }, "gaspumps": { "@": { "fuel": "gasoline", "amount": [ 10000, 50000 ] }, "$": { "fuel": "diesel", "amount": [ 10000, 50000 ] } }, + "vehicles": { "Ø": { "vehicle": "tatra_truck", "chance": 50, "fuel": 40 } }, "nested": { "`": { "chunks": [ [ "mechanical_fluid", 10 ], [ "gasoline_diesel_motor_oil", 80 ], [ "null", 80 ] ] } } } }, { "type": "mapgen", "method": "json", - "om_terrain": "mine_entrance_roof", + "om_terrain": [ [ "mine_entrance_roof", "mine_entrance_loading_zone_roof" ] ], "object": { "rows": [ - " ", - " ", - " ", - "Ю--------------------| ", - "|....................| ", - "|....................| ", - "|....................| ", - "|....................| ", - "|....................| ", - "|--------------------| ", - " ", - "|-----------| ", - "|...........| |------Ю", - "|...........| |......|", - "|...........| |......|", - "|...........| |......|", - "|...........| |......|", - "|...........| |......|", - "|...........| |......|", - "|...........| |......|", - "|...........| |......|", - "|...........| |......|", - "|...........| |......|", - "|-----------Ю |------|" + " ", + " ", + " ", + "Ю--------------------| ", + "|....................| ", + "|....................| ", + "|....................| ", + "|....................| ", + "|....................| ", + "|--------------------| ", + " ", + "|-----------| ", + "|...........| |------------| ", + "|...........| |............| ", + "|...........| |............| ", + "|...........| |............| ", + "|...........| |............| ", + "|...........| |............| |----| ", + "|...........| |............| |....| ", + "|...........| |............| |....| ", + "|...........| |............| |....| ", + "|...........| |............| |....| ", + "|...........| |............| |....| ", + "|-----------Ю Ю------------Ю Ю----| " ], "terrain": { " ": "t_open_air", "|": "t_gutter_north", "-": "t_gutter_west", "Ю": "t_gutter_drop", ".": "t_flat_roof" } } diff --git a/data/json/mapgen/mine/mine_shaft.json b/data/json/mapgen/mine/mine_shaft.json index 674b1d3d59031..3d56375160457 100644 --- a/data/json/mapgen/mine/mine_shaft.json +++ b/data/json/mapgen/mine/mine_shaft.json @@ -6,21 +6,21 @@ "object": { "fill_ter": "t_rock", "rows": [ - " <# ", - " # ", - " # ", - " # ", - " # ", - " # ", - " # ", - " # ", - " # ", - " # ", - " # ", - " # ", - " # ", - " ....#># ", - " ....### ", + " <#", + " #", + " #", + " #", + " #", + " #", + " #", + " #", + " #", + " #", + " #", + " #", + " #>#", + " ....###", + " .... ", " ", " ", " ", @@ -37,34 +37,34 @@ { "type": "mapgen", "method": "json", - "om_terrain": "mine_shaft_lower", + "om_terrain": [ [ "mine_shaft_lower", "mine_shaft_lower_east" ] ], "object": { "fill_ter": "t_rock_floor", "rows": [ - "###### ## ########", - "####### ##########", - "######## ##########", - "######## ########", - " ###### #########", - " ## ##########", - "# ########## ", - " ###### ######### ", - "######## #### #", - "###### ", - "###### ######", - "##### ######", - "### |------| ######", - "# |!@@..<|-| ###", - " |.@@....S| ", - "### |---....S| #", - " +.......S| ", - " |.......S| ####", - "## |LLLLLL|-| ######", - "#### |------| ######", - "###### ######", - "####### ## #######", - "######## ## #######", - "######### # ########" + "###### ## #################### #######", + "###### ## ################### ########", + "###### ## ############# #### #########", + "####### ############### ### ##########", + "######## ############### ## ###########", + "######## ############## ############", + " ###### ################ ##########", + " ## ################# ###########", + "# ##### ###### ###########", + " #### ## ", + "###### ### #### #### ", + "###### |-| #### ##### ", + "###### |----|<|--| ", + "##### |!@@...!@@| #### #####", + "### |.@@....@@| ######### ######", + " +.......@@| ########## ######", + "*****************=========| # ######## ####", + " +.......®®| ####### ####", + " |.........| ######### ####", + "# |.........| ######### #", + "## |LLLL|SSSS| ######### #", + "#### |----|----| ######## #", + "###### ######### ", + "####### ## ####### ######## " ], "terrain": { "<": "t_ladder_up", @@ -75,14 +75,18 @@ "!": "t_elevator_control", "@": "t_elevator", "#": [ [ "t_rock", 4 ], [ "t_rock_floor", 1 ] ], + "=": "t_conveyor", + "*": "t_railroad_track_small", + "®": "t_thconc_floor", "L": "t_thconc_floor", "S": "t_thconc_floor" }, - "furniture": { "L": "f_locker", "S": "f_utility_shelf" }, + "furniture": { "®": "f_machinery_heavy", "L": "f_locker", "S": "f_utility_shelf" }, "items": { "L": [ { "item": "clothing_work_set", "chance": 50 }, { "item": "hardware_clothing", "chance": 50 } ], "S": { "item": "mine_equipment", "chance": 80 } - } + }, + "place_vehicles": [ { "vehicle": "trolley", "x": 10, "y": 16, "chance": 100, "status": 0 } ] } } ] diff --git a/data/json/overmap/overmap_special/specials.json b/data/json/overmap/overmap_special/specials.json index 845aed0757c17..326b01007d486 100644 --- a/data/json/overmap/overmap_special/specials.json +++ b/data/json/overmap/overmap_special/specials.json @@ -1129,11 +1129,17 @@ "overmaps": [ { "point": [ 0, 0, 0 ], "overmap": "s_lot_north" }, { "point": [ 0, 1, 0 ], "overmap": "mine_entrance_north" }, + { "point": [ 1, 1, 0 ], "overmap": "mine_entrance_loading_zone_north" }, + { "point": [ 1, 0, 0 ], "overmap": "road_end_north" }, { "point": [ 0, 1, 1 ], "overmap": "mine_entrance_roof_north" }, { "point": [ 0, 1, -1 ], "overmap": "mine_shaft_middle_north" }, - { "point": [ 0, 1, -2 ], "overmap": "mine_shaft_lower_north" } + { "point": [ 0, 1, -2 ], "overmap": "mine_shaft_lower_north" }, + { "point": [ 1, 1, -2 ], "overmap": "mine_shaft_lower_east_north" } + ], + "connections": [ + { "point": [ 0, -1, 0 ], "terrain": "road", "connection": "local_road", "from": [ 0, 0, 0 ] }, + { "point": [ 1, -1, 0 ], "terrain": "road", "connection": "local_road", "from": [ 1, 0, 0 ] } ], - "connections": [ { "point": [ 0, -1, 0 ], "terrain": "road", "connection": "local_road", "from": [ 0, 0, 0 ] } ], "locations": [ "wilderness" ], "city_distance": [ 10, 40 ], "city_sizes": [ 4, -1 ], diff --git a/data/json/overmap/overmap_terrain/overmap_terrain_industrial.json b/data/json/overmap/overmap_terrain/overmap_terrain_industrial.json index 805072815c9a4..4b946bab6f2a4 100644 --- a/data/json/overmap/overmap_terrain/overmap_terrain_industrial.json +++ b/data/json/overmap/overmap_terrain/overmap_terrain_industrial.json @@ -360,7 +360,7 @@ }, { "type": "overmap_terrain", - "id": "mine_entrance", + "id": [ "mine_entrance", "mine_entrance_loading_zone" ], "name": "mine entrance", "sym": "M", "color": "magenta", @@ -369,12 +369,11 @@ }, { "type": "overmap_terrain", - "id": "mine_entrance_roof", + "id": [ "mine_entrance_roof", "mine_entrance_loading_zone_roof" ], "name": "mine entrance roof", "sym": "M", "color": "magenta", - "see_cost": 5, - "flags": [ "KNOWN_DOWN" ] + "see_cost": 5 }, { "type": "overmap_terrain", @@ -387,7 +386,7 @@ }, { "type": "overmap_terrain", - "id": "mine_shaft_lower", + "id": [ "mine_shaft_lower", "mine_shaft_lower_east" ], "name": "mine shaft", "sym": "O", "color": "dark_gray", diff --git a/data/json/vehicles/trains.json b/data/json/vehicles/trains.json index 21dcea76870b3..44aba2971a6a2 100644 --- a/data/json/vehicles/trains.json +++ b/data/json/vehicles/trains.json @@ -249,5 +249,12 @@ { "x": 0, "y": 0, "parts": [ "frame_vertical_2", "seat", "rail_wheel_small_pair", "controls" ] }, { "x": 0, "y": 0, "parts": [ { "part": "fuel_bunker", "fuel": "coal_lump" } ] } ] + }, + { + "id": "trolley", + "type": "vehicle", + "name": "Trolley", + "blueprint": [ "O" ], + "parts": [ { "x": 0, "y": 0, "parts": [ "frame_vertical", "cargo_space", "rail_wheel_small_pair" ] } ] } ] From 59c9c5e18ebcc27985241a0fdbfa6d7ebdaa8d9f Mon Sep 17 00:00:00 2001 From: LyleSY Date: Mon, 8 Mar 2021 15:36:30 -0500 Subject: [PATCH 044/453] [DinoMod] Mushroom Madness (#47907) --- data/mods/DinoMod/monstergroups/fungi.json | 85 +++- data/mods/DinoMod/monsters/fungus.json | 427 ++++++++++++++++++++- 2 files changed, 485 insertions(+), 27 deletions(-) diff --git a/data/mods/DinoMod/monstergroups/fungi.json b/data/mods/DinoMod/monstergroups/fungi.json index 569949fcec0f3..e4ea76ddb0158 100644 --- a/data/mods/DinoMod/monstergroups/fungi.json +++ b/data/mods/DinoMod/monstergroups/fungi.json @@ -1,24 +1,42 @@ [ - { - "type": "monstergroup", - "name": "GROUP_FUNGI", - "default": "mon_spore", - "monsters": [ - { "monster": "mon_zpinosaurus_fungus", "freq": 0, "cost_multiplier": 0 }, - { "monster": "mon_zyrannosaurus_fungus", "freq": 0, "cost_multiplier": 0 }, - { "monster": "mon_zankylosaurus_fungus", "freq": 0, "cost_multiplier": 0 }, - { "monster": "mon_zeinonychus_fungus", "freq": 0, "cost_multiplier": 0 } - ] - }, { "type": "monstergroup", "name": "GROUP_FUNGI_TOWER", "default": "mon_fungal_tendril", "monsters": [ - { "monster": "mon_zpinosaurus_fungus", "freq": 50, "cost_multiplier": 0 }, - { "monster": "mon_zyrannosaurus_fungus", "freq": 50, "cost_multiplier": 0 }, - { "monster": "mon_zankylosaurus_fungus", "freq": 250, "cost_multiplier": 0 }, - { "monster": "mon_zeinonychus_fungus", "freq": 75, "cost_multiplier": 0 } + { "monster": "mon_zilophosaurus_fungus", "freq": 1, "cost_multiplier": 0, "starts": 72 }, + { "monster": "mon_zeratosaurus_fungus", "freq": 1, "cost_multiplier": 0, "starts": 72 }, + { "monster": "mon_zallosaurus_fungus", "freq": 1, "cost_multiplier": 0, "starts": 144 }, + { "monster": "mon_zacrocanthosaurus_fungus", "freq": 1, "cost_multiplier": 0, "starts": 144 }, + { "monster": "mon_ziats_fungus", "freq": 1, "cost_multiplier": 0, "starts": 144 }, + { "monster": "mon_zalbertosaurus_fungus", "freq": 1, "cost_multiplier": 0, "starts": 72 }, + { "monster": "mon_zyrannosaurus_fungus", "freq": 1, "cost_multiplier": 0, "starts": 144 }, + { "monster": "mon_zallimimus_fungus", "freq": 1, "cost_multiplier": 0, "starts": 72 }, + { "monster": "mon_zothronychus_fungus", "freq": 1, "cost_multiplier": 0, "starts": 72 }, + { "monster": "mon_zeinonychus_fungus", "freq": 1, "cost_multiplier": 0, "starts": 72 }, + { "monster": "mon_zutahraptor_fungus", "freq": 1, "cost_multiplier": 0, "starts": 144 }, + { "monster": "mon_zapatosaurus_fungus", "freq": 1, "cost_multiplier": 0, "starts": 72 }, + { "monster": "mon_zrontosaurus_fungus", "freq": 1, "cost_multiplier": 0, "starts": 72 }, + { "monster": "mon_ziplodocus_fungus", "freq": 1, "cost_multiplier": 0, "starts": 72 }, + { "monster": "mon_zamarasaurus_fungus", "freq": 1, "cost_multiplier": 0, "starts": 72 }, + { "monster": "mon_zrachiosaurus_fungus", "freq": 1, "cost_multiplier": 0, "starts": 72 }, + { "monster": "mon_zalamosaurus_fungus", "freq": 1, "cost_multiplier": 0, "starts": 72 }, + { "monster": "mon_ztegosaurus_fungus", "freq": 1, "cost_multiplier": 0, "starts": 72 }, + { "monster": "mon_zyoplosaurus_fungus", "freq": 1, "cost_multiplier": 0, "starts": 72 }, + { "monster": "mon_zankylosaurus_fungus", "freq": 1, "cost_multiplier": 0, "starts": 72 }, + { "monster": "mon_zodosaurus_fungus", "freq": 1, "cost_multiplier": 0, "starts": 72 }, + { "monster": "mon_zedmontonia_fungus", "freq": 1, "cost_multiplier": 0, "starts": 72 }, + { "monster": "mon_zamptosaurus_fungus", "freq": 1, "cost_multiplier": 0, "starts": 72 }, + { "monster": "mon_zaiasaura_fungus", "freq": 1, "cost_multiplier": 0, "starts": 72 }, + { "monster": "mon_zarasaurolophus_fungus", "freq": 1, "cost_multiplier": 0, "starts": 72 }, + { "monster": "mon_zorythosaurus_fungus", "freq": 1, "cost_multiplier": 0, "starts": 72 }, + { "monster": "mon_zedmontosaurus_fungus", "freq": 1, "cost_multiplier": 0, "starts": 72 }, + { "monster": "mon_zachycephalosaurus_fungus", "freq": 1, "cost_multiplier": 0, "starts": 72 }, + { "monster": "mon_zachyrhinosaurus_fungus", "freq": 1, "cost_multiplier": 0, "starts": 72 }, + { "monster": "mon_zentaceratops_fungus", "freq": 1, "cost_multiplier": 0, "starts": 72 }, + { "monster": "mon_zosmoceratops_fungus", "freq": 1, "cost_multiplier": 0, "starts": 72 }, + { "monster": "mon_zorosaurus_fungus", "freq": 1, "cost_multiplier": 0, "starts": 72 }, + { "monster": "mon_zriceratops_fungus", "freq": 1, "cost_multiplier": 0, "starts": 72 } ] }, { @@ -26,10 +44,39 @@ "name": "GROUP_FUNGI_FLOWERS", "default": "mon_fungal_blossom", "monsters": [ - { "monster": "mon_zpinosaurus_fungus", "freq": 50, "cost_multiplier": 0 }, - { "monster": "mon_zyrannosaurus_fungus", "freq": 50, "cost_multiplier": 0 }, - { "monster": "mon_zankylosaurus_fungus", "freq": 250, "cost_multiplier": 0 }, - { "monster": "mon_zeinonychus_fungus", "freq": 75, "cost_multiplier": 0 } + { "monster": "mon_zilophosaurus_fungus", "freq": 1, "cost_multiplier": 0, "starts": 72 }, + { "monster": "mon_zeratosaurus_fungus", "freq": 1, "cost_multiplier": 0, "starts": 72 }, + { "monster": "mon_zallosaurus_fungus", "freq": 1, "cost_multiplier": 0, "starts": 144 }, + { "monster": "mon_zacrocanthosaurus_fungus", "freq": 1, "cost_multiplier": 0, "starts": 144 }, + { "monster": "mon_ziats_fungus", "freq": 1, "cost_multiplier": 0, "starts": 144 }, + { "monster": "mon_zalbertosaurus_fungus", "freq": 1, "cost_multiplier": 0, "starts": 72 }, + { "monster": "mon_zyrannosaurus_fungus", "freq": 1, "cost_multiplier": 0, "starts": 144 }, + { "monster": "mon_zallimimus_fungus", "freq": 1, "cost_multiplier": 0, "starts": 72 }, + { "monster": "mon_zothronychus_fungus", "freq": 1, "cost_multiplier": 0, "starts": 72 }, + { "monster": "mon_zeinonychus_fungus", "freq": 1, "cost_multiplier": 0, "starts": 72 }, + { "monster": "mon_zutahraptor_fungus", "freq": 1, "cost_multiplier": 0, "starts": 144 }, + { "monster": "mon_zapatosaurus_fungus", "freq": 1, "cost_multiplier": 0, "starts": 72 }, + { "monster": "mon_zrontosaurus_fungus", "freq": 1, "cost_multiplier": 0, "starts": 72 }, + { "monster": "mon_ziplodocus_fungus", "freq": 1, "cost_multiplier": 0, "starts": 72 }, + { "monster": "mon_zamarasaurus_fungus", "freq": 1, "cost_multiplier": 0, "starts": 72 }, + { "monster": "mon_zrachiosaurus_fungus", "freq": 1, "cost_multiplier": 0, "starts": 72 }, + { "monster": "mon_zalamosaurus_fungus", "freq": 1, "cost_multiplier": 0, "starts": 72 }, + { "monster": "mon_ztegosaurus_fungus", "freq": 1, "cost_multiplier": 0, "starts": 72 }, + { "monster": "mon_zyoplosaurus_fungus", "freq": 1, "cost_multiplier": 0, "starts": 72 }, + { "monster": "mon_zankylosaurus_fungus", "freq": 1, "cost_multiplier": 0, "starts": 72 }, + { "monster": "mon_zodosaurus_fungus", "freq": 1, "cost_multiplier": 0, "starts": 72 }, + { "monster": "mon_zedmontonia_fungus", "freq": 1, "cost_multiplier": 0, "starts": 72 }, + { "monster": "mon_zamptosaurus_fungus", "freq": 1, "cost_multiplier": 0, "starts": 72 }, + { "monster": "mon_zaiasaura_fungus", "freq": 1, "cost_multiplier": 0, "starts": 72 }, + { "monster": "mon_zarasaurolophus_fungus", "freq": 1, "cost_multiplier": 0, "starts": 72 }, + { "monster": "mon_zorythosaurus_fungus", "freq": 1, "cost_multiplier": 0, "starts": 72 }, + { "monster": "mon_zedmontosaurus_fungus", "freq": 1, "cost_multiplier": 0, "starts": 72 }, + { "monster": "mon_zachycephalosaurus_fungus", "freq": 1, "cost_multiplier": 0, "starts": 72 }, + { "monster": "mon_zachyrhinosaurus_fungus", "freq": 1, "cost_multiplier": 0, "starts": 72 }, + { "monster": "mon_zentaceratops_fungus", "freq": 1, "cost_multiplier": 0, "starts": 72 }, + { "monster": "mon_zosmoceratops_fungus", "freq": 1, "cost_multiplier": 0, "starts": 72 }, + { "monster": "mon_zorosaurus_fungus", "freq": 1, "cost_multiplier": 0, "starts": 72 }, + { "monster": "mon_zriceratops_fungus", "freq": 1, "cost_multiplier": 0, "starts": 72 } ] } ] diff --git a/data/mods/DinoMod/monsters/fungus.json b/data/mods/DinoMod/monsters/fungus.json index 8bc86b455790e..fa1f15212e239 100644 --- a/data/mods/DinoMod/monsters/fungus.json +++ b/data/mods/DinoMod/monsters/fungus.json @@ -1,4 +1,40 @@ [ + { + "id": "mon_zilophosaurus_fungus", + "type": "MONSTER", + "name": { "str": "fungal Dilophosaurus zombie" }, + "description": "Once a predator dinosaur with sharp teeth and two prominent bony crests on its head, fungal tendrils now sprout from its mouth, eyes, and other orifices, holding together a shambling mass of mold-covered flesh with a colorful frill of interwoven mushrooms.", + "copy-from": "mon_zilophosaurus", + "default_faction": "fungus", + "species": [ "FUNGUS" ], + "diff": 2, + "proportional": { "hp": 0.75, "speed": 0.65 }, + "color": "light_gray", + "relative": { "melee_skill": -1, "melee_dice": -1, "melee_dice_sides": 3, "armor_bash": 3 }, + "vision_day": 5, + "vision_night": 5, + "special_attacks": [ [ "FUNGUS", 200 ], { "type": "bite", "cooldown": 5 } ], + "upgrades": { }, + "flags": [ "SEES", "SMELLS", "POISON", "STUMBLES", "NO_BREATHE", "FILTHY", "WARM" ] + }, + { + "id": "mon_zeratosaurus_fungus", + "type": "MONSTER", + "name": { "str": "fungal zombie dragon" }, + "description": "Once an enormous, scaly dinosaur studded with bony spikes with colorful horns, fungal tendrils now sprout from its mouth, eyes, and other orifices, holding together a shambling mass of mold-covered scales and spikes.", + "copy-from": "mon_zeratosaurus", + "default_faction": "fungus", + "species": [ "FUNGUS" ], + "diff": 2, + "proportional": { "hp": 0.75, "speed": 0.65 }, + "color": "light_gray", + "relative": { "melee_skill": -1, "melee_dice": -1, "melee_dice_sides": 3, "armor_bash": 3 }, + "vision_day": 5, + "vision_night": 5, + "special_attacks": [ [ "FUNGUS", 200 ], { "type": "bite", "cooldown": 5 } ], + "upgrades": { }, + "flags": [ "SEES", "SMELLS", "HEARS", "BASHES", "POISON", "STUMBLES", "NO_BREATHE", "FILTHY", "WARM", "SWIMS" ] + }, { "id": "mon_zpinosaurus_fungus", "type": "MONSTER", @@ -17,6 +53,78 @@ "upgrades": { }, "flags": [ "SEES", "SMELLS", "POISON", "STUMBLES", "BASHES", "DESTROYS", "NO_BREATHE", "FILTHY", "WARM", "SWIMS" ] }, + { + "id": "mon_zallosaurus_fungus", + "type": "MONSTER", + "name": { "str": "fungal Allosaurus zombie" }, + "description": "Once a large predatory bipedal dinosaur with a broad scaly back, fungal tendrils now sprout from its mouth, eyes, and other orifices, holding together a shambling mass of mold-covered flesh.", + "copy-from": "mon_zallosaurus", + "default_faction": "fungus", + "species": [ "FUNGUS" ], + "diff": 2, + "proportional": { "hp": 0.75, "speed": 0.65 }, + "color": "light_gray", + "relative": { "melee_skill": -1, "melee_dice": -1, "melee_dice_sides": 3, "armor_bash": 3 }, + "vision_day": 5, + "vision_night": 5, + "special_attacks": [ [ "FUNGUS", 200 ], { "type": "bite", "cooldown": 5 } ], + "upgrades": { }, + "flags": [ "SEES", "SMELLS", "POISON", "STUMBLES", "BASHES", "NO_BREATHE", "FILTHY", "WARM" ] + }, + { + "id": "mon_zacrocanthosaurus_fungus", + "type": "MONSTER", + "name": { "str": "fungal Acrocanthosaurus zombie" }, + "description": "Once a huge predatory bipedal dinosaur, with a tall ridge running down the length of its back covered with heavy muscles and showing teeth curved and serrated like sawblades, fungal tendrils now sprout from its mouth, eyes, and other orifices, holding together a shambling mass of mold-covered flesh.", + "copy-from": "mon_zacrocanthosaurus", + "default_faction": "fungus", + "species": [ "FUNGUS" ], + "diff": 2, + "proportional": { "hp": 0.75, "speed": 0.65 }, + "color": "light_gray", + "relative": { "melee_skill": -1, "melee_dice": -1, "melee_dice_sides": 3, "armor_bash": 3 }, + "vision_day": 5, + "vision_night": 5, + "special_attacks": [ [ "FUNGUS", 200 ], [ "GRAB", 10 ], [ "LUNGE", 20 ] ], + "upgrades": { }, + "flags": [ "SEES", "SMELLS", "POISON", "STUMBLES", "BASHES", "NO_BREATHE", "FILTHY", "WARM" ] + }, + { + "id": "mon_ziats_fungus", + "type": "MONSTER", + "name": { "str": "fungal Siats zombie" }, + "description": "Once a huge predatory bipedal dinosaur with long claws and strong arms for grappling, fungal tendrils now sprout from its mouth, eyes, and other orifices, holding together a shambling mass of mold-covered flesh.", + "copy-from": "mon_ziats", + "default_faction": "fungus", + "species": [ "FUNGUS" ], + "diff": 2, + "proportional": { "hp": 0.75, "speed": 0.65 }, + "color": "light_gray", + "relative": { "melee_skill": -1, "melee_dice": -1, "melee_dice_sides": 3, "armor_bash": 3 }, + "vision_day": 5, + "vision_night": 5, + "special_attacks": [ [ "FUNGUS", 200 ], [ "BIO_OP_TAKEDOWN", 20 ], [ "RANGED_PULL", 20 ], [ "GRAB_DRAG", 10 ] ], + "upgrades": { }, + "flags": [ "SEES", "SMELLS", "POISON", "STUMBLES", "BASHES", "NO_BREATHE", "FILTHY", "WARM" ] + }, + { + "id": "mon_zalbertosaurus_fungus", + "type": "MONSTER", + "name": { "str": "fungal Albertosaurus zombie" }, + "description": "Once a huge predatory bipedal dinosaur with long claws and massive jaws, fungal tendrils now sprout from its mouth, eyes, and other orifices, holding together a shambling mass of mold-covered flesh.", + "copy-from": "mon_zalbertosaurus", + "default_faction": "fungus", + "species": [ "FUNGUS" ], + "diff": 2, + "proportional": { "hp": 0.75, "speed": 0.65 }, + "color": "light_gray", + "relative": { "melee_skill": -1, "melee_dice": -1, "melee_dice_sides": 3, "armor_bash": 3 }, + "vision_day": 5, + "vision_night": 5, + "special_attacks": [ [ "FUNGUS", 200 ], { "type": "bite", "cooldown": 5 }, [ "GRAB", 7 ], [ "scratch", 20 ], [ "LUNGE", 5 ] ], + "upgrades": { }, + "flags": [ "SEES", "SMELLS", "POISON", "STUMBLES", "BASHES", "DESTROYS", "NO_BREATHE", "FILTHY", "WARM" ] + }, { "id": "mon_zyrannosaurus_fungus", "type": "MONSTER", @@ -36,11 +144,11 @@ "flags": [ "SEES", "SMELLS", "POISON", "STUMBLES", "BASHES", "DESTROYS", "NO_BREATHE", "FILTHY", "WARM" ] }, { - "id": "mon_zankylosaurus_fungus", + "id": "mon_zallimimus_fungus", "type": "MONSTER", - "name": { "str": "fungal Ankylosaurus zombie" }, - "description": "Once something like a giant armadillo dinosaur hybrid with a spiked tail, fungal tendrils now sprout from its mouth, eyes, and other orifices, holding together an enormous shambling mass of mold-covered flesh.", - "copy-from": "mon_zankylosaurus", + "name": { "str": "fungal Gallimimus zombie" }, + "description": "Once a featherd bipedal plant eating dinosaur, fungal tendrils now sprout from its mouth, eyes, and other orifices, holding together an enormous shambling mass of mold-covered feathers.", + "copy-from": "mon_zallimimus", "default_faction": "fungus", "species": [ "FUNGUS" ], "diff": 2, @@ -49,15 +157,33 @@ "relative": { "melee_skill": -1, "melee_dice": -1, "melee_dice_sides": 3, "armor_bash": 3 }, "vision_day": 5, "vision_night": 5, - "special_attacks": [ [ "FUNGUS", 200 ] ], + "special_attacks": [ [ "FUNGUS", 200 ], [ "scratch", 10 ], { "type": "bite", "cooldown": 5 } ], "upgrades": { }, - "flags": [ "SEES", "SMELLS", "POISON", "STUMBLES", "NO_BREATHE", "FILTHY", "WARM", "BASHES" ] + "flags": [ "SEES", "SMELLS", "HEARS", "PET_MOUNTABLE", "POISON", "STUMBLES", "NO_BREATHE", "FILTHY", "WARM" ] + }, + { + "id": "mon_zothronychus_fungus", + "type": "MONSTER", + "name": { "str": "fungal Nothronychus zombie" }, + "description": "Once a large feathered bipedal plant eating dinosaur with sharp curved claws, fungal tendrils now sprout from its mouth, eyes, and other orifices, holding together a shambling mass of mold-covered feathers.", + "copy-from": "mon_zothronychus", + "default_faction": "fungus", + "species": [ "FUNGUS" ], + "diff": 2, + "proportional": { "hp": 0.75, "speed": 0.65 }, + "color": "light_gray", + "relative": { "melee_skill": -1, "melee_dice": -1, "melee_dice_sides": 3, "armor_bash": 3 }, + "vision_day": 5, + "vision_night": 5, + "special_attacks": [ [ "FUNGUS", 200 ], [ "LONGSWIPE", 30 ] ], + "upgrades": { }, + "flags": [ "SEES", "SMELLS", "HEARS", "KEENNOSE", "POISON", "STUMBLES", "NO_BREATHE", "FILTHY", "WARM", "BASHES" ] }, { "id": "mon_zeinonychus_fungus", "type": "MONSTER", "name": { "str": "fungal Deinonychus zombie" }, - "description": "Once a medium-sized feathered carnivorous dinosaur, fungal tendrils now sprout from its mouth, eyes, and other orifices, holding together an enormous shambling mass of mold-covered flesh.", + "description": "Once a feathered meat eating dinosaur with a large, sickle-shaped talon on each foot, fungal tendrils now sprout from its mouth, eyes, and other orifices, holding together an enormous shambling mass of mold-covered flesh.", "copy-from": "mon_zeinonychus", "default_faction": "fungus", "species": [ "FUNGUS" ], @@ -67,8 +193,293 @@ "relative": { "melee_skill": -1, "melee_dice": -1, "melee_dice_sides": 3, "armor_bash": 3 }, "vision_day": 5, "vision_night": 5, - "special_attacks": [ [ "FUNGUS", 200 ], { "type": "bite", "cooldown": 5 } ], + "special_attacks": [ + [ "FUNGUS", 200 ], + { "type": "leap", "cooldown": 5, "max_range": 5, "allow_no_target": true }, + [ "scratch", 10 ], + { "type": "bite", "cooldown": 5 } + ], "upgrades": { }, "flags": [ "SEES", "SMELLS", "KEENNOSE", "POISON", "STUMBLES", "NO_BREATHE", "FILTHY", "WARM" ] + }, + { + "id": "mon_zutahraptor_fungus", + "type": "MONSTER", + "name": { "str": "fungal Utahraptor zombie" }, + "description": "Once a large feathered meat eating dinosaur with a sickle-shaped talon on each foot, fungal tendrils now sprout from its mouth, eyes, and other orifices, holding together an enormous shambling mass of mold-covered flesh.", + "copy-from": "mon_zutahraptor", + "default_faction": "fungus", + "species": [ "FUNGUS" ], + "diff": 2, + "proportional": { "hp": 0.75, "speed": 0.65 }, + "color": "light_gray", + "relative": { "melee_skill": -1, "melee_dice": -1, "melee_dice_sides": 3, "armor_bash": 3 }, + "vision_day": 5, + "vision_night": 5, + "special_attacks": [ + [ "FUNGUS", 200 ], + { "type": "leap", "cooldown": 5, "max_range": 5, "allow_no_target": true }, + [ "scratch", 10 ], + { "type": "bite", "cooldown": 5 } + ], + "upgrades": { }, + "flags": [ "SEES", "SMELLS", "KEENNOSE", "POISON", "STUMBLES", "NO_BREATHE", "FILTHY", "WARM" ] + }, + { + "id": "mon_zapatosaurus_fungus", + "type": "MONSTER", + "name": { "str": "fungal Apatosaurus zombie" }, + "description": "Once a massive, long-necked, four-legged plant eating dinosaur with a long, whip-like tail, fungal tendrils now sprout from its mouth, eyes, and other orifices, holding together an enormous shambling mass of mold-covered flesh.", + "copy-from": "mon_zapatosaurus", + "default_faction": "fungus", + "species": [ "FUNGUS" ], + "diff": 2, + "proportional": { "hp": 0.75, "speed": 0.65 }, + "color": "light_gray", + "relative": { "melee_skill": -1, "melee_dice": -1, "melee_dice_sides": 3, "armor_bash": 3 }, + "vision_day": 5, + "vision_night": 5, + "special_attacks": [ + [ "FUNGUS", 200 ], + { "id": "slam", "cooldown": 10, "damage_max_instance": [ { "damage_type": "bash", "amount": 12 } ] }, + [ "SMASH", 30 ] + ], + "upgrades": { }, + "flags": [ "SEES", "SMELLS", "POISON", "STUMBLES", "NO_BREATHE", "FILTHY", "WARM", "BASHES" ] + }, + { + "id": "mon_zrontosaurus_fungus", + "type": "MONSTER", + "name": { "str": "fungal Brontosaurus zombie" }, + "description": "Once a massive, long-necked, four-legged plant eating dinosaur with a bulky torso and long, whip-like tail, fungal tendrils now sprout from its mouth, eyes, and other orifices, holding together an enormous shambling mass of mold-covered flesh.", + "copy-from": "mon_zapatosaurus_fungus" + }, + { + "id": "mon_ziplodocus_fungus", + "type": "MONSTER", + "name": { "str": "fungal Diplodocus zombie" }, + "description": "Once a huge, long-necked, four-legged plant eating dinosaur with a tiny head and long, whip-like tail, fungal tendrils now sprout from its mouth, eyes, and other orifices, holding together an enormous shambling mass of mold-covered flesh.", + "copy-from": "mon_zapatosaurus_fungus" + }, + { + "id": "mon_zamarasaurus_fungus", + "type": "MONSTER", + "name": { "str": "fungal Camarasaurus zombie" }, + "description": "Once a huge, long-necked, four-legged plant eating dinosaur with a long, whip-like tail, fungal tendrils now sprout from its mouth, eyes, and other orifices, holding together an enormous shambling mass of mold-covered flesh.", + "copy-from": "mon_zapatosaurus_fungus" + }, + { + "id": "mon_zrachiosaurus_fungus", + "type": "MONSTER", + "name": { "str": "fungal Brachiosaurus zombie" }, + "description": "Once a gigantic, long-necked, four-legged plant eating dinosaur with longer forelegs and a long, whip-like tail, fungal tendrils now sprout from its mouth, eyes, and other orifices, holding together an enormous shambling mass of mold-covered flesh.", + "copy-from": "mon_zapatosaurus_fungus", + "proportional": { "hp": 2, "speed": 0.65 } + }, + { + "id": "mon_zalamosaurus_fungus", + "type": "MONSTER", + "name": { "str": "fungal Alamosaurus zombie" }, + "description": "Once a gigantic, long-necked, four-legged plant eating dinosaur with longer forelegs and spiked tail protected by natural bone armor, fungal tendrils now sprout from its mouth, eyes, and other orifices, holding together an enormous shambling mass of mold-covered flesh.", + "copy-from": "mon_zapatosaurus_fungus", + "proportional": { "hp": 1.5, "speed": 0.8, "armor_bash": 2, "armor_cut": 2 } + }, + { + "id": "mon_ztegosaurus_fungus", + "type": "MONSTER", + "name": { "str": "fungal Stegosaurus zombie" }, + "description": "Once a large four legged plant eating dinosaur with heavy bone plates jutting from its back and spiked tail, fungal tendrils now sprout from its mouth, eyes, and other orifices, holding together a shambling mass of mold-covered flesh.", + "copy-from": "mon_ztegosaurus", + "default_faction": "fungus", + "species": [ "FUNGUS" ], + "diff": 2, + "proportional": { "hp": 0.75, "speed": 0.65 }, + "color": "light_gray", + "relative": { "melee_skill": -1, "melee_dice": -1, "melee_dice_sides": 3, "armor_bash": 3 }, + "vision_day": 5, + "vision_night": 5, + "special_attacks": [ + [ "FUNGUS", 200 ], + { "id": "slam", "cooldown": 10, "damage_max_instance": [ { "damage_type": "bash", "amount": 12 } ] }, + [ "SMASH", 30 ] + ], + "upgrades": { }, + "flags": [ "SEES", "SMELLS", "POISON", "STUMBLES", "NO_BREATHE", "FILTHY", "WARM", "BASHES" ] + }, + { + "id": "mon_zyoplosaurus_fungus", + "type": "MONSTER", + "name": { "str": "fungal Dyoplosaurus zombie" }, + "description": "Once something like a giant armadillo dinosaur hybrid with a spiked club tail, fungal tendrils now sprout from its mouth, eyes, and other orifices, holding together a shambling mass of mold-covered flesh and bone.", + "copy-from": "mon_zankylosaurus_fungus", + "proportional": { "hp": 0.35, "speed": 1.2 } + }, + { + "id": "mon_zankylosaurus_fungus", + "type": "MONSTER", + "name": { "str": "fungal Ankylosaurus zombie" }, + "description": "Once something like a giant armadillo dinosaur hybrid with a spiked tail, fungal tendrils now sprout from its mouth, eyes, and other orifices, holding together an enormous shambling mass of mold-covered flesh and bone.", + "copy-from": "mon_zankylosaurus", + "default_faction": "fungus", + "species": [ "FUNGUS" ], + "diff": 2, + "proportional": { "hp": 0.75, "speed": 0.65 }, + "color": "light_gray", + "relative": { "melee_skill": -1, "melee_dice": -1, "melee_dice_sides": 3, "armor_bash": 3 }, + "vision_day": 5, + "vision_night": 5, + "special_attacks": [ + [ "FUNGUS", 200 ], + [ "scratch", 10 ], + { "type": "bite", "cooldown": 5 }, + { "id": "slam", "cooldown": 10, "damage_max_instance": [ { "damage_type": "bash", "amount": 12 } ] }, + [ "SMASH", 30 ] + ], + "upgrades": { }, + "flags": [ "SEES", "SMELLS", "POISON", "STUMBLES", "NO_BREATHE", "FILTHY", "WARM", "BASHES" ] + }, + { + "id": "mon_zodosaurus_fungus", + "type": "MONSTER", + "name": { "str": "fungal Nodosaurus zombie" }, + "description": "Once something like a giant armadillo dinosaur hybrid, fungal tendrils now sprout from its mouth, eyes, and other orifices, holding together a shambling mass of mold-covered flesh and bone.", + "copy-from": "mon_zankylosaurus_fungus", + "proportional": { "hp": 0.6 }, + "special_attacks": [ [ "FUNGUS", 200 ], [ "scratch", 10 ], { "type": "bite", "cooldown": 5 } ] + }, + { + "id": "mon_zedmontonia_fungus", + "type": "MONSTER", + "name": { "str": "fungal Edmontonia zombie" }, + "description": "Once something like a giant armadillo dinosaur hybrid with long bony spikes, fungal tendrils now sprout from its mouth, eyes, and other orifices, holding together a shambling mass of mold-covered flesh and bone.", + "copy-from": "mon_zankylosaurus_fungus", + "melee_cut": 10, + "proportional": { "hp": 0.65 }, + "special_attacks": [ [ "FUNGUS", 200 ], [ "scratch", 10 ], { "type": "bite", "cooldown": 5 } ] + }, + { + "id": "mon_zamptosaurus_fungus", + "type": "MONSTER", + "name": { "str": "fungal Camptosaurus zombie" }, + "description": "Once a large feathered bipedal dinosaur with strong legs, broad shoulders and a pointed beak, fungal tendrils now sprout from its mouth, eyes, and other orifices, holding together an enormous shambling mass of mold-covered feathers.", + "copy-from": "mon_zamptosaurus", + "default_faction": "fungus", + "species": [ "FUNGUS" ], + "diff": 2, + "proportional": { "hp": 0.75, "speed": 0.65 }, + "color": "light_gray", + "relative": { "melee_skill": -1, "melee_dice": -1, "melee_dice_sides": 3, "armor_bash": 3 }, + "vision_day": 5, + "vision_night": 5, + "special_attacks": [ [ "FUNGUS", 200 ], [ "scratch", 10 ], { "type": "bite", "cooldown": 5 } ], + "upgrades": { }, + "flags": [ "SEES", "SMELLS", "POISON", "STUMBLES", "NO_BREATHE", "FILTHY", "WARM", "BASHES" ] + }, + { + "id": "mon_zaiasaura_fungus", + "type": "MONSTER", + "name": { "str": "fungal Maiasaura zombie" }, + "description": "Once a huge four legged plant eating dinosaur with hooves, a heavy tail, and a flat beak, fungal tendrils now sprout from its mouth, eyes, and other orifices, holding together a shambling mass of mold-covered flesh and bone.", + "copy-from": "mon_zamptosaurus_fungus", + "proportional": { "hp": 3 } + }, + { + "id": "mon_zarasaurolophus_fungus", + "type": "MONSTER", + "name": { "str": "fungal Parasaurolophus zombie" }, + "description": "Once a huge four legged plant eating dinosaur with a blunt head crest, fungal tendrils now sprout from its mouth, eyes, and other orifices, holding together a shambling mass of mold-covered flesh and bone.", + "copy-from": "mon_zamptosaurus_fungus", + "proportional": { "hp": 4 } + }, + { + "id": "mon_zorythosaurus_fungus", + "type": "MONSTER", + "name": { "str": "fungal Corythosaurus zombie" }, + "description": "Once a huge four legged plant eating dinosaur with a short beak and a tall head crest, fungal tendrils now sprout from its mouth, eyes, and other orifices, holding together a shambling mass of mold-covered flesh and bone.", + "copy-from": "mon_zamptosaurus_fungus", + "proportional": { "hp": 4 }, + "special_attacks": [ [ "FUNGUS", 200 ], [ "scratch", 10 ], { "type": "bite", "cooldown": 5 }, [ "SHRIEK", 5 ] ] + }, + { + "id": "mon_zedmontosaurus_fungus", + "type": "MONSTER", + "name": { "str": "fungal Edmontosaurus zombie" }, + "description": "Once a huge four legged plant eating dinosaur with a broad toothless beak, fungal tendrils now sprout from its mouth, eyes, and other orifices, holding together a shambling mass of mold-covered flesh and bone.", + "copy-from": "mon_zamptosaurus_fungus", + "proportional": { "hp": 5 } + }, + { + "id": "mon_zachycephalosaurus_fungus", + "type": "MONSTER", + "name": { "str": "fungal Pachycephalosaurus zombie" }, + "description": "Once a feathered bipedal dinosaur with a hard-looking domed head, fungal tendrils now sprout from its mouth, eyes, and other orifices, holding together a shambling mass of mold-covered feathers.", + "copy-from": "mon_zachycephalosaurus", + "default_faction": "fungus", + "species": [ "FUNGUS" ], + "diff": 2, + "proportional": { "hp": 0.75, "speed": 0.65 }, + "color": "light_gray", + "relative": { "melee_skill": -1, "melee_dice": -1, "melee_dice_sides": 3, "armor_bash": 3 }, + "vision_day": 5, + "vision_night": 5, + "special_attacks": [ [ "FUNGUS", 200 ], [ "scratch", 10 ], { "type": "bite", "cooldown": 5 } ], + "upgrades": { }, + "flags": [ "SEES", "SMELLS", "POISON", "STUMBLES", "NO_BREATHE", "FILTHY", "WARM", "PET_MOUNTABLE" ] + }, + { + "id": "mon_zachyrhinosaurus_fungus", + "type": "MONSTER", + "name": { "str": "fungal Pachyrhinosaurus zombie" }, + "description": "Once a massive four legged plant eating dinosaur with a tall bony crest from which four long horns and a short nose horn emerge, fungal tendrils now sprout from its mouth, eyes, and other orifices, holding together a shambling mass of mold-covered flesh.", + "copy-from": "mon_zriceratops_fungus", + "proportional": { "hp": 0.65 }, + "special_attacks": [ + [ "FUNGUS", 200 ], + { "id": "slam", "cooldown": 10, "damage_max_instance": [ { "damage_type": "bash", "amount": 12 } ] }, + [ "SMASH", 30 ] + ] + }, + { + "id": "mon_zentaceratops_fungus", + "type": "MONSTER", + "name": { "str": "fungal Pentaceraterror" }, + "description": "Once a massive four legged plant eating dinosaur with a tall bony crest from which four long horns and a short nose horn emerge, fungal tendrils now sprout from its mouth, eyes, and other orifices, holding together a shambling mass of mold-covered flesh.", + "copy-from": "mon_zriceratops_fungus", + "proportional": { "armor_bash": 2 } + }, + { + "id": "mon_zosmoceratops_fungus", + "type": "MONSTER", + "name": { "str": "fungal Kosmoceratops zombie" }, + "description": "Once a massive four legged plant eating dinosaur with a tall bony crest from which fifteen horns and spikes emerge, fungal tendrils now sprout from its mouth, eyes, and other orifices, holding together a shambling mass of mold-covered flesh.", + "copy-from": "mon_zriceratops_fungus", + "proportional": { "melee_dice": 2, "melee_cut": 0.65 } + }, + { + "id": "mon_zorosaurus_fungus", + "type": "MONSTER", + "name": { "str": "fungal Torosaurus zombie" }, + "description": "Once a massive four legged plant eating dinosaur with a tall bony crest from which two wicked looking horns emerge, fungal tendrils now sprout from its mouth, eyes, and other orifices, holding together a shambling mass of mold-covered flesh.", + "copy-from": "mon_zriceratops_fungus", + "proportional": { "melee_dice": 2, "melee_cut": 0.65 }, + "special_attacks": [ [ "FUNGUS", 200 ], { "id": "impale" }, [ "STRETCH_ATTACK", 5 ] ] + }, + { + "id": "mon_zriceratops_fungus", + "type": "MONSTER", + "name": { "str": "fungal Triceraterror" }, + "description": "Once a massive four legged plant eating dinosaur with a bony head crest from which three wicked looking horns emerge, fungal tendrils now sprout from its mouth, eyes, and other orifices, holding together a shambling mass of mold-covered flesh.", + "copy-from": "mon_zriceratops", + "default_faction": "fungus", + "species": [ "FUNGUS" ], + "diff": 2, + "proportional": { "hp": 0.75, "speed": 0.65 }, + "color": "light_gray", + "relative": { "melee_skill": -1, "melee_dice": -1, "melee_dice_sides": 3, "armor_bash": 3 }, + "vision_day": 5, + "vision_night": 5, + "special_attacks": [ [ "FUNGUS", 200 ], { "id": "impale" } ], + "upgrades": { }, + "flags": [ "SEES", "SMELLS", "POISON", "STUMBLES", "NO_BREATHE", "FILTHY", "WARM", "PET_MOUNTABLE", "BASHES" ] } ] From 9e8a44bf9b6ab91f8a30ee951f5f059117d29e65 Mon Sep 17 00:00:00 2001 From: casswedson Date: Mon, 8 Mar 2021 21:19:54 -0500 Subject: [PATCH 045/453] misc typograpical fixes (#47953) --- data/mods/CRT_EXPANSION/deadspace/deadspaceitems.json | 2 +- data/mods/CRT_EXPANSION/items/crt_ammo.json | 2 +- data/mods/CRT_EXPANSION/items/crt_armor.json | 2 +- data/mods/CRT_EXPANSION/items/crt_gun.json | 2 +- data/mods/CRT_EXPANSION/items/crt_toolarmor.json | 10 +++++----- data/mods/CRT_EXPANSION/items/crt_tools.json | 2 +- data/mods/CRT_EXPANSION/martial/CRT_Bladework.json | 2 +- .../CRT_EXPANSION/mutations/crt_wendigo_mutations.json | 2 +- data/mods/CRT_EXPANSION/mutations/wendigo_mut_cat.json | 2 +- data/mods/CRT_EXPANSION/scenarios/crt_classes.json | 10 +++++----- data/mods/Generic_Guns/firearms/pistol.json | 2 +- data/mods/Generic_Guns/firearms/pistol_magnum.json | 4 ++-- data/mods/Generic_Guns/firearms/rifle.json | 2 +- data/mods/Generic_Guns/firearms/rifle_huge.json | 2 +- data/mods/Generic_Guns/magazines/rifle.json | 2 +- 15 files changed, 24 insertions(+), 24 deletions(-) diff --git a/data/mods/CRT_EXPANSION/deadspace/deadspaceitems.json b/data/mods/CRT_EXPANSION/deadspace/deadspaceitems.json index 943cd8b7731ce..6f646b8f256e9 100644 --- a/data/mods/CRT_EXPANSION/deadspace/deadspaceitems.json +++ b/data/mods/CRT_EXPANSION/deadspace/deadspaceitems.json @@ -39,7 +39,7 @@ "type": "ARMOR", "category": "armor", "name": "CRIT Engineering Suit", - "description": "An airtight, flexible suit of woven composite fibers complete with segmented plates of armor. A complex system digitizes items in an individual pocket universe for storage while built in joint-torsion ratchets generate the neccessary energy required to power the interface.", + "description": "An airtight, flexible suit of woven composite fibers complete with segmented plates of armor. A complex system digitizes items in an individual pocket universe for storage while built in joint-torsion ratchets generate the necessary energy required to power the interface.", "weight": "13460 g", "volume": "14 L", "price": 900000000, diff --git a/data/mods/CRT_EXPANSION/items/crt_ammo.json b/data/mods/CRT_EXPANSION/items/crt_ammo.json index b207d694a30e0..7fa03d67f224a 100644 --- a/data/mods/CRT_EXPANSION/items/crt_ammo.json +++ b/data/mods/CRT_EXPANSION/items/crt_ammo.json @@ -47,7 +47,7 @@ "copy-from": "pellet", "type": "AMMO", "name": { "str_sp": "alloy pellets" }, - "description": "An gimmicky alloy pellet with the purpose of reaching a higher velocity than a normal lead pellet for breaking the sound barrier resulting in an extremely loud crack, not so useful for stealth.", + "description": "A gimmicky alloy pellet with the purpose of reaching a higher velocity than a normal lead pellet for breaking the sound barrier resulting in an extremely loud crack, not so useful for stealth.", "material": [ "steel" ], "symbol": "=", "color": "dark_gray", diff --git a/data/mods/CRT_EXPANSION/items/crt_armor.json b/data/mods/CRT_EXPANSION/items/crt_armor.json index ecc0eb6c43e57..2f6d322632d9b 100644 --- a/data/mods/CRT_EXPANSION/items/crt_armor.json +++ b/data/mods/CRT_EXPANSION/items/crt_armor.json @@ -261,7 +261,7 @@ "type": "ARMOR", "category": "armor", "name": { "str": "pair of CRIT Enforcer docks", "str_pl": "pairs of CRIT Enforcer docks" }, - "description": "CRIT Enforcer docks. Metal plates vaguely molded into the shape of oversized feet which clamp down onto your own footwear keep your feet out of harms way. It looks terrible and feels clunky unlike most of C.R.I.T's designs, but they do seem to be worth using if you were to be in the middle of a warzone.", + "description": "CRIT Enforcer docks. Metal plates vaguely molded into the shape of oversized feet which clamp down onto your own footwear keep your feet out of harms way. It looks terrible and feels clunky unlike most of C.R.I.T's designs, but they do seem to be worth using if you were to be in the middle of a war zone.", "weight": "2060 g", "volume": "1500 ml", "price": 100000, diff --git a/data/mods/CRT_EXPANSION/items/crt_gun.json b/data/mods/CRT_EXPANSION/items/crt_gun.json index 29500fede4f49..b645c14f8f931 100644 --- a/data/mods/CRT_EXPANSION/items/crt_gun.json +++ b/data/mods/CRT_EXPANSION/items/crt_gun.json @@ -252,7 +252,7 @@ "id": "ds_rivet_gun", "type": "GUN", "name": "Rivet Driver", - "description": "Experimental double purpose tool under development in C.R.I.T R&D. It takes a regular nail and then enlongates it within a fraction of a second before firing it out, upon reaching a target, the fragile stake explodes into shards inside the target.", + "description": "Experimental double purpose tool under development in C.R.I.T R&D. It takes a regular nail and then elongates it within a fraction of a second before firing it out, upon reaching a target, the fragile stake explodes into shards inside the target.", "weight": "1650 g", "volume": "750 ml", "price": 1000000, diff --git a/data/mods/CRT_EXPANSION/items/crt_toolarmor.json b/data/mods/CRT_EXPANSION/items/crt_toolarmor.json index b1666136f844e..228154a7b7f4c 100644 --- a/data/mods/CRT_EXPANSION/items/crt_toolarmor.json +++ b/data/mods/CRT_EXPANSION/items/crt_toolarmor.json @@ -3,8 +3,8 @@ "id": "crt_gasmask", "type": "TOOL_ARMOR", "category": "armor", - "name": { "str": "CRIT gasmask (off)", "str_pl": "CRIT gasmasks (off)" }, - "description": "This is a heavily modified Spec Ops modified gasmask, fitted with top-of-the-line electronics and lined with Kevlar for extra protection in order to keep one's head where it should be. Various filters and other high tech wizardry allow for enhanced oxygen intake and safety even under bombardment. It has an integrated HUD and the option to turn it on for more features.", + "name": { "str": "CRIT gas mask (off)", "str_pl": "CRIT gas masks (off)" }, + "description": "This is a heavily modified Spec Ops modified gas mask, fitted with top-of-the-line electronics and lined with Kevlar for extra protection in order to keep one's head where it should be. Various filters and other high tech wizardry allow for enhanced oxygen intake and safety even under bombardment. It has an integrated HUD and the option to turn it on for more features.", "weight": "5 kg", "volume": "1 L", "price": 2500000, @@ -45,8 +45,8 @@ "id": "crt_gasmask_on", "type": "TOOL_ARMOR", "category": "armor", - "name": { "str": "CRIT gasmask (on)", "str_pl": "CRIT gasmasks (on)" }, - "description": "This a heavily modified gasmask. It is currently on and draining power for the HUD, low-level nightvision and other protective elements.", + "name": { "str": "CRIT gas mask (on)", "str_pl": "CRIT gas masks (on)" }, + "description": "This a heavily modified gas mask. It is currently on and draining power for the HUD, low-level night vision and other protective elements.", "weight": "5 kg", "volume": "1 L", "price": 2500000, @@ -88,7 +88,7 @@ "type": "TOOL_ARMOR", "category": "armor", "name": { "str": "CRIT EM vest (off)", "str_pl": "CRIT EM vests (off)" }, - "description": "The Enhanced Movement vest is embedded with high-tech filaments and reactive servos which protects its wearer and assists in movement at the cost high power usage. It is commonly worn by C.R.I.T Spec Ops for its ease of use and manuverability. Turn it on for suit mode, extra protection and movement.", + "description": "The Enhanced Movement vest is embedded with high-tech filaments and reactive servos which protects its wearer and assists in movement at the cost high power usage. It is commonly worn by C.R.I.T Spec Ops for its ease of use and maneuverability. Turn it on for suit mode, extra protection and movement.", "weight": "10 kg", "volume": "6250 ml", "price": 7000000, diff --git a/data/mods/CRT_EXPANSION/items/crt_tools.json b/data/mods/CRT_EXPANSION/items/crt_tools.json index d98d70f31e0ea..d01795aa7d2b3 100644 --- a/data/mods/CRT_EXPANSION/items/crt_tools.json +++ b/data/mods/CRT_EXPANSION/items/crt_tools.json @@ -63,7 +63,7 @@ "type": "TOOL", "category": "weapons", "name": "CRIT Reso-blade", - "description": "CRIT melee weapon. Alien runes adorn the carbon steel blade. The blade oddly seems to lack sharpness, and yet upon closer oberservation, a hum of energy thrums from within.", + "description": "CRIT melee weapon. Alien runes adorn the carbon steel blade. The blade oddly seems to lack sharpness, and yet upon closer inspection, a hum of energy thrums from within.", "color": "dark_gray", "material": [ "hardsteel" ], "//": "Legacy artifact data is set for always on wield dex +2 and speed up times 2", diff --git a/data/mods/CRT_EXPANSION/martial/CRT_Bladework.json b/data/mods/CRT_EXPANSION/martial/CRT_Bladework.json index 751e3c3d2fc7d..75efd9a3e449c 100644 --- a/data/mods/CRT_EXPANSION/martial/CRT_Bladework.json +++ b/data/mods/CRT_EXPANSION/martial/CRT_Bladework.json @@ -16,7 +16,7 @@ "type": "martial_art", "id": "style_crt_blade", "name": "CRIT Blade-work", - "description": "An offensive style centered around rapid slashes and prodding. Each attack landed increases combat ability but leaves you increasingly vunerable", + "description": "An offensive style centered around rapid slashes and prodding. Each attack landed increases combat ability but leaves you increasingly vulnerable", "initiate": [ "You prepare to whittle down your enemies.", "%s initiates blade-work." ], "arm_block": 99, "leg_block": 99, diff --git a/data/mods/CRT_EXPANSION/mutations/crt_wendigo_mutations.json b/data/mods/CRT_EXPANSION/mutations/crt_wendigo_mutations.json index db237d5336376..87efffb5b22a9 100644 --- a/data/mods/CRT_EXPANSION/mutations/crt_wendigo_mutations.json +++ b/data/mods/CRT_EXPANSION/mutations/crt_wendigo_mutations.json @@ -14,7 +14,7 @@ "id": "NMELD", "name": "Nature's Boon", "points": 3, - "description": "Your very prescence is masked by nature itself. You are slightly harder to detect.", + "description": "Your very presence is masked by nature itself. You are slightly harder to detect.", "valid": false, "purifiable": false, "prereqs": [ "WEAKSCENT" ], diff --git a/data/mods/CRT_EXPANSION/mutations/wendigo_mut_cat.json b/data/mods/CRT_EXPANSION/mutations/wendigo_mut_cat.json index 1cf8a61f0880b..3ba2aa896727e 100644 --- a/data/mods/CRT_EXPANSION/mutations/wendigo_mut_cat.json +++ b/data/mods/CRT_EXPANSION/mutations/wendigo_mut_cat.json @@ -28,7 +28,7 @@ "copy-from": "iv_mutagen_flavor", "type": "COMESTIBLE", "name": "wendigo serum", - "description": "A super-concentrated peat-brown substance with glittering green flecks that reminds you of a a tree. You need a syringe to inject it… if you really want to?", + "description": "A super-concentrated peat-brown substance with glittering green flecks that reminds you of a tree. You need a syringe to inject it… if you really want to?", "color": "light_gray", "healthy": -2, "use_action": { "type": "mutagen_iv", "mutation_category": "WENDIGO" } diff --git a/data/mods/CRT_EXPANSION/scenarios/crt_classes.json b/data/mods/CRT_EXPANSION/scenarios/crt_classes.json index 89f6d4d92a68a..041172c84f5a0 100644 --- a/data/mods/CRT_EXPANSION/scenarios/crt_classes.json +++ b/data/mods/CRT_EXPANSION/scenarios/crt_classes.json @@ -32,7 +32,7 @@ "type": "profession", "id": "crt_dude", "name": "CRIT Janitor", - "description": "*Sigh* Your life has been a wreck. Hopping place to place you finally found a job at C.R.I.T… as a janitor of sorts. The pay was good and you got some sneak-peeks on some pretty cool stuff. After all non-essential personel were purged you found yourself stuck with nothing but the uniform they gave you and your job's sign-bonus equipment.", + "description": "*Sigh* Your life has been a wreck. Hopping place to place you finally found a job at C.R.I.T… as a janitor of sorts. The pay was good and you got some sneak-peeks on some pretty cool stuff. After all non-essential personnel were purged you found yourself stuck with nothing but the uniform they gave you and your job's sign-bonus equipment.", "points": 6, "skills": [ { "level": 2, "name": "tailor" }, @@ -112,7 +112,7 @@ "type": "profession", "id": "crt_rifleman", "name": "CRIT Grunt", - "description": "You were part of the infantry; first to hit the ground running, clear a FOB and then come back to relax with your squad. Those days ended when the cataclysm reared its ugly head. Your lines were torn through like wet paper when the otherworldy abominations arived. Now fleeing for your life, will you have what it takes to survive or is this hellish landcape your resting place?", + "description": "You were part of the infantry; first to hit the ground running, clear a FOB and then come back to relax with your squad. Those days ended when the cataclysm reared its ugly head. Your lines were torn through like wet paper when the otherworldly abominations arrived. Now fleeing for your life, will you have what it takes to survive or is this hellish landscape your resting place?", "points": 8, "traits": [ "MARTIAL_CRT" ], "skills": [ { "level": 3, "name": "gun" }, { "level": 3, "name": "rifle" }, { "level": 1, "name": "stabbing" } ], @@ -199,7 +199,7 @@ "type": "profession", "id": "crt_saw", "name": "CRIT Automatic Rifleman", - "description": "You were assigned the billet of specializing in creating dead zones and providing support fire. When the cataclysm struck, your trusty LMG couldn't keep the veritable tide of undead from overtaking your squad. Now running with all the strength your body can muster, will you have what it takes to survive or is this hellish landcape something you just can't suppress?", + "description": "You were assigned the billet of specializing in creating dead zones and providing support fire. When the cataclysm struck, your trusty LMG couldn't keep the veritable tide of undead from overtaking your squad. Now running with all the strength your body can muster, will you have what it takes to survive or is this hellish landscape something you just can't suppress?", "points": 10, "traits": [ "MARTIAL_CRT" ], "skills": [ { "level": 3, "name": "gun" }, { "level": 3, "name": "rifle" }, { "level": 1, "name": "pistol" } ], @@ -332,7 +332,7 @@ "type": "profession", "id": "crt_juggernaught", "name": "CRIT Lone Wolf", - "description": "STR 10 recommended. You are fully armored badass granted the full authority of a U.S Marshal. Sent in as the one man army capable of handling anything. Dropped into warzones, you singlehandedly laid out entire battalions by yourself. Time to hang them all.", + "description": "STR 10 recommended. You are fully armored badass granted the full authority of a U.S Marshal. Sent in as the one man army capable of handling anything. Dropped into war zones, you singlehandedly laid out entire battalions by yourself. Time to hang them all.", "traits": [ "MARTIAL_CRT", "PROF_FED" ], "CBMs": [ "bio_weight", @@ -664,7 +664,7 @@ "type": "profession", "id": "crt_vamp", "name": "CRIT Night Walker", - "description": "Your base in New England fell to the unholy onslaught of the Cataclysm. However, as a a top researcher in the R&D department, you had chosen to slowly mutate yourself into something more than human. Even if the concotion was less than perfect, your old flimsy body feels empowered. With the new flesh that is now your own, bare your fangs and fight until the next dawn.", + "description": "Your base in New England fell to the unholy onslaught of the Cataclysm. However, as a top researcher in the R&D department, you had chosen to slowly mutate yourself into something more than human. Even if the concoction was less than perfect, your old flimsy body feels empowered. With the new flesh that is now your own, bare your fangs and fight until the next dawn.", "traits": [ "MARTIAL_CRT", "THRESH_VAMP", diff --git a/data/mods/Generic_Guns/firearms/pistol.json b/data/mods/Generic_Guns/firearms/pistol.json index 7a69b3b076ab1..fe459c467a140 100644 --- a/data/mods/Generic_Guns/firearms/pistol.json +++ b/data/mods/Generic_Guns/firearms/pistol.json @@ -15,7 +15,7 @@ "type": "GUN", "name": { "str": "machine pistol" }, "ammo": [ "ammo_pistol" ], - "description": "This pistol is a tiny machinegun you can stuff into a holster, with which you could dump its magazine at a blistering rate into any close range foes. Machine pistols mostly see use by vehicle crewmen or bodygaurds of VIPs. Due to its preposterous rate of fire it is difficult to control.", + "description": "This pistol is a tiny machinegun you can stuff into a holster, with which you could dump its magazine at a blistering rate into any close range foes. Machine pistols mostly see use by vehicle crewmen or bodyguards of VIPs. Due to its preposterous rate of fire it is difficult to control.", "pocket_data": [ { "pocket_type": "MAGAZINE_WELL", diff --git a/data/mods/Generic_Guns/firearms/pistol_magnum.json b/data/mods/Generic_Guns/firearms/pistol_magnum.json index 58b5fb14f5f09..e9c3e018c6bd2 100644 --- a/data/mods/Generic_Guns/firearms/pistol_magnum.json +++ b/data/mods/Generic_Guns/firearms/pistol_magnum.json @@ -6,7 +6,7 @@ "name": { "str": "hand cannon" }, "ammo": [ "ammo_pistol", "ammo_pistol_magnum" ], "//": "We're just going to prtend that .357 and .44 magnum deagles will run .38's and .44 special just fine", - "description": "This large pistol is almost as heavy as a small carbine, and just about as powerful too. Chambered in hard hitting magnum calibers, it is suitable for hunting medium game, humans, or offsetting any of one's perceived deficiencies. Though tradtionally such magnums are revolvers, this one is a magazine fed semi-automatic.", + "description": "This large pistol is almost as heavy as a small carbine, and just about as powerful too. Chambered in hard hitting magnum calibers, it is suitable for hunting medium game, humans, or offsetting any of one's perceived deficiencies. Though traditionally such magnums are revolvers, this one is a magazine fed semi-automatic.", "pocket_data": [ { "pocket_type": "MAGAZINE_WELL", @@ -34,7 +34,7 @@ "type": "GUN", "name": { "str": "handmade magnum carbine" }, "ammo": [ "ammo_pistol_magnum", "ammo_pistol" ], - "description": "A crudely constructed carbine, chambered for magnum pistol ammo and standard pistol ammo. It feeds from commerical magnum pistol magazines, and locks with a rudimentary lever action system. Its powerful cartridge and relative precision should serve well against zombies and medium game.", + "description": "A crudely constructed carbine, chambered for magnum pistol ammo and standard pistol ammo. It feeds from commercial magnum pistol magazines, and locks with a rudimentary lever action system. Its powerful cartridge and relative precision should serve well against zombies and medium game.", "weight": "2114 g", "volume": "2 L", "price": 10000, diff --git a/data/mods/Generic_Guns/firearms/rifle.json b/data/mods/Generic_Guns/firearms/rifle.json index 4870b21236a9d..80ef35b8a6516 100644 --- a/data/mods/Generic_Guns/firearms/rifle.json +++ b/data/mods/Generic_Guns/firearms/rifle.json @@ -59,7 +59,7 @@ "type": "GUN", "name": "sporter carbine", "ammo": [ "ammo_rifle" ], - "description": "Though often mislabeled an asssault rifle, this common, cheap magazine fed carbine isn't capable of automatic fire. While almost as effective as a proper rifle, the wider variety of components and varying levels of maintenance make these less reliable than their military brethren. These rifles are just as adequate for taking on anything smaller than large game, however.", + "description": "Though often mislabeled an assault rifle, this common, cheap magazine fed carbine isn't capable of automatic fire. While almost as effective as a proper rifle, the wider variety of components and varying levels of maintenance make these less reliable than their military brethren. These rifles are just as adequate for taking on anything smaller than large game, however.", "pocket_data": [ { "pocket_type": "MAGAZINE_WELL", diff --git a/data/mods/Generic_Guns/firearms/rifle_huge.json b/data/mods/Generic_Guns/firearms/rifle_huge.json index b3773574befc9..51c386db8255f 100644 --- a/data/mods/Generic_Guns/firearms/rifle_huge.json +++ b/data/mods/Generic_Guns/firearms/rifle_huge.json @@ -23,7 +23,7 @@ "type": "GUN", "name": { "str": "elephant rifle" }, "ammo": [ "ammo_rifle_huge" ], - "description": "Elegantly engraved, with deep glossy blued steel and figured wood, this break-action double rifle is almost too nice to shoot. Your shoulder might beg you not to; the chambers are almost wide enough for two fingers and the recoil is monstruous. You could probably kill anything with this, especially if you were to fire both barrels at once.", + "description": "Elegantly engraved, with deep glossy blued steel and figured wood, this break-action double rifle is almost too nice to shoot. Your shoulder might beg you not to; the chambers are almost wide enough for two fingers and the recoil is monstrous. You could probably kill anything with this, especially if you were to fire both barrels at once.", "modes": [ [ "DEFAULT", "single", 1 ], [ "DOUBLE", "double", 2 ] ], "extend": { "flags": [ "RELOAD_ONE" ] }, "clip_size": 2, diff --git a/data/mods/Generic_Guns/magazines/rifle.json b/data/mods/Generic_Guns/magazines/rifle.json index ac8667a01e991..c2e1553b397ad 100644 --- a/data/mods/Generic_Guns/magazines/rifle.json +++ b/data/mods/Generic_Guns/magazines/rifle.json @@ -18,7 +18,7 @@ "type": "MAGAZINE", "material": [ "aluminum" ], "name": "standard rifle magazine", - "description": "A 30 round standard capacity magazine for service rifles, cheaper than the cost of a meal due to its adoption by nearly every other common rifle. They're made of aluminum and were originally meant to be dispsoable, so they're not the most durable; don't let them get damaged.", + "description": "A 30 round standard capacity magazine for service rifles, cheaper than the cost of a meal due to its adoption by nearly every other common rifle. They're made of aluminum and were originally meant to be disposable, so they're not the most durable; don't let them get damaged.", "volume": "500 ml", "ammo_type": [ "ammo_rifle" ], "pocket_data": [ { "pocket_type": "MAGAZINE", "ammo_restriction": { "ammo_rifle": 30 }, "rigid": true } ] From f26520fac75ff4030370f4e58c2c6b525b102ad5 Mon Sep 17 00:00:00 2001 From: OromisElf Date: Tue, 9 Mar 2021 12:04:12 +0100 Subject: [PATCH 046/453] body pillow recipe makes makeshift body pillow now (#47917) --- data/json/items/generic.json | 9 +++++++++ data/json/recipes/recipe_obsolete.json | 5 +++++ data/json/recipes/recipe_others.json | 2 +- 3 files changed, 15 insertions(+), 1 deletion(-) diff --git a/data/json/items/generic.json b/data/json/items/generic.json index 468efcc0ab120..01319f25c1389 100644 --- a/data/json/items/generic.json +++ b/data/json/items/generic.json @@ -2400,6 +2400,15 @@ "flags": [ "SLEEP_AID" ], "category": "other" }, + { + "type": "GENERIC", + "id": "bodypillow_makeshift", + "copy-from": "bodypillow", + "name": { "str": "makeshift body pillow" }, + "description": "A big, body-sized pillow. Someone drew a vaguely humanoid figure on it. Its heartwarming smile fills you with joy.", + "price": 100, + "price_postapoc": 50 + }, { "type": "GENERIC", "id": "down_pillow", diff --git a/data/json/recipes/recipe_obsolete.json b/data/json/recipes/recipe_obsolete.json index 40b4b52c04c91..9c56edb33c045 100644 --- a/data/json/recipes/recipe_obsolete.json +++ b/data/json/recipes/recipe_obsolete.json @@ -2777,5 +2777,10 @@ "type": "recipe", "result": "rifle_223", "obsolete": true + }, + { + "type": "recipe", + "result": "bodypillow", + "obsolete": true } ] diff --git a/data/json/recipes/recipe_others.json b/data/json/recipes/recipe_others.json index 3f3fb8664bdc4..4886c50cb5789 100644 --- a/data/json/recipes/recipe_others.json +++ b/data/json/recipes/recipe_others.json @@ -56,7 +56,7 @@ { "type": "recipe", "activity_level": "LIGHT_EXERCISE", - "result": "bodypillow", + "result": "bodypillow_makeshift", "category": "CC_OTHER", "subcategory": "CSC_OTHER_OTHER", "skill_used": "tailor", From 5a2171dbf1db265726d31379b4c3ec98475e8087 Mon Sep 17 00:00:00 2001 From: Maleclypse <54345792+Maleclypse@users.noreply.github.com> Date: Sun, 14 Mar 2021 15:36:34 -0500 Subject: [PATCH 047/453] Traffic Bollards and an example of deployment (#48017) --- .../furniture_and_terrain/terrain-walls.json | 20 +++++++++++++++ data/json/mapgen/sub_station.json | 2 +- data/json/mapgen_palettes/subway.json | 1 + .../Magiclysm/worldgen/forge_of_wonders.json | 25 ++++++++++--------- 4 files changed, 35 insertions(+), 13 deletions(-) diff --git a/data/json/furniture_and_terrain/terrain-walls.json b/data/json/furniture_and_terrain/terrain-walls.json index 69f2cb631d5d0..69cc70c69b254 100644 --- a/data/json/furniture_and_terrain/terrain-walls.json +++ b/data/json/furniture_and_terrain/terrain-walls.json @@ -1352,6 +1352,26 @@ "items": [ { "item": "rock", "count": [ 10, 22 ] } ] } }, + { + "type": "terrain", + "id": "t_bollard", + "name": "bollard", + "looks_like": "t_fence_post", + "description": "A set of concrete and steel bollards designed to harden areas against vehicle ram attacks. It requires a few more steps to walk in between the bollards sticking up out of the ground.", + "symbol": "1", + "color": "light_gray", + "move_cost": 6, + "coverage": 20, + "flags": [ "WALL", "PERMEABLE" ], + "bash": { + "str_min": 350, + "str_max": 650, + "sound": "crash!", + "sound_fail": "whump!", + "ter_set": "t_sidewalk", + "items": [ { "item": "rock", "count": [ 6, 13 ] }, { "item": "steel_chunk", "count": [ 1, 3 ] } ] + } + }, { "type": "terrain", "id": "t_support_l", diff --git a/data/json/mapgen/sub_station.json b/data/json/mapgen/sub_station.json index 200c1be0667f0..8e345e70aa6ba 100644 --- a/data/json/mapgen/sub_station.json +++ b/data/json/mapgen/sub_station.json @@ -8,7 +8,7 @@ "fill_ter": "t_thconc_floor", "rows": [ "SSSSSSSSSSSSSSSSSSSSSSSS", - "SSSSSSSSSSSSSSSSSSSSSSSS", + "SSSttttttttttttttttttSSS", "SS||-;;-||-;;-||-;;-||SS", "SS| | | |SS", "SS| |SS", diff --git a/data/json/mapgen_palettes/subway.json b/data/json/mapgen_palettes/subway.json index 1502b7ebaad56..7c7ec2270d7f6 100644 --- a/data/json/mapgen_palettes/subway.json +++ b/data/json/mapgen_palettes/subway.json @@ -8,6 +8,7 @@ "-": "t_wall_glass", ";": "t_door_glass_c", "S": "t_sidewalk", + "t": "t_bollard", "*": "t_region_shrub_decorative", ">": "t_stairs_down", "<": "t_stairs_up", diff --git a/data/mods/Magiclysm/worldgen/forge_of_wonders.json b/data/mods/Magiclysm/worldgen/forge_of_wonders.json index e5681b712e32c..cf7833a7587e7 100644 --- a/data/mods/Magiclysm/worldgen/forge_of_wonders.json +++ b/data/mods/Magiclysm/worldgen/forge_of_wonders.json @@ -23,25 +23,25 @@ "rows": [ " T 2 ++++++ 2 ", " T +++++++ Y ", - " Y ++++++++ T ", + " Y 55555555 T ", " +++++++ ", " ########||||#########################||&&&&&&&||###############||||##############||||############### ", " #..................................##...........##............................4............4.......# ", - " #..4.@.@...........................##...........##..................XXXXXXXXXXXXXXXXXXXXXXXXXXXXXX.# ", - " #...fffff.................2........##...........##..................X$$$$$$$$$$$$$$$$$$$$$$$$$$$$X.# ", - " #...fffff..........................##...........##..................#$$$$$$$$$$$$$$$$$$$$$$$$$$$$X.# ", - " #....@.@.........................................................XXX#$$$$$$$$$$$$$$$$$$$$$$$$$$$$X.| ", - " #........................................44......................X94#$$$$$$$$$$$$$$$$$$$$$$$$$$$$X.| ", - " #............4...........................44......................X89#$$$$$$$$$$$$$$$$$$$$$$$$$$$$X.| ", - " #................................................................X94#$$$$$$$$$$$$$$$$$$$$$$$$$$$$X.| ", - " #...........@.@..................................................XXX#$$$$$$$$$$$$$$$$$$$$$$$$$$$$X.| ", - " #.........zZZZZZ....................................................#$$$$$$$$$$$$$$$$$$$$$$$$$$$$X.# ", + " #..4.@.@...........................##...........##............5.....XXXXXXXXXXXXXXXXXXXXXXXXXXXXXX.# ", + " #...fffff.................2........##...........##.............5....X$$$$$$$$$$$$$$$$$$$$$$$$$$$$X.# ", + " #...fffff..........................##...........##............5.....#$$$$$$$$$$$$$$$$$$$$$$$$$$$$X.# ", + " #....@.@.......................................................5.XXX#$$$$$$$$$$$$$$$$$$$$$$$$$$$$X.| ", + " #........................................44...................5..X94#$$$$$$$$$$$$$$$$$$$$$$$$$$$$X.| ", + " #............4...........................44....................5.X89#$$$$$$$$$$$$$$$$$$$$$$$$$$$$X.| ", + " #.............................................................5..X94#$$$$$$$$$$$$$$$$$$$$$$$$$$$$X.| ", + " #...........@.@................................................5.XXX#$$$$$$$$$$$$$$$$$$$$$$$$$$$$X.| ", + " #.........zZZZZZ..............................................5.....#$$$$$$$$$$$$$$$$$$$$$$$$$$$$X.# ", " #..........ZZZZZz...................................##...........##.X$$$$$$$$$$$$$$$$$$$$$$$$$$$$X.# ", " |...........@.@............4...................2....##...........##.XXXXXXXXXXXXXXXXXXXXXXXXXXXXXX.# ", " |...................................................##...........##.....4...............4..........# ", " |...................................#####|||##########||&&&&&&&||##################|||############## ", " |...................................# +++++++ ", - " |...................................# ++++++++ 2 ", + " |...................................# 55555555 2 ", " #...................................# 2 +++++++ ", " #.......................4...........# ++++++++ 2 ", " #...................................# ++++++++ Y ", @@ -113,7 +113,8 @@ "9": "t_vault_vent", "2": "t_strconc_floor", "4": "t_thconc_floor_echandelier", - "+": "t_railroad_rubble" + "+": "t_railroad_rubble", + "5": "t_bollard" }, "furniture": { "h": "f_demon_forge", From b7e404f92cc6696bc9f6e47003f53da7be605e97 Mon Sep 17 00:00:00 2001 From: akirashirosawa <38557723+akirashirosawa@users.noreply.github.com> Date: Sun, 14 Mar 2021 10:49:46 +0300 Subject: [PATCH 048/453] add description for Uyen's missions (#48026) --- .../surface_refugees/NPC_Uyen_Tran.json | 11 ++++++----- 1 file changed, 6 insertions(+), 5 deletions(-) diff --git a/data/json/npcs/refugee_center/surface_refugees/NPC_Uyen_Tran.json b/data/json/npcs/refugee_center/surface_refugees/NPC_Uyen_Tran.json index 0653bd650cbe7..5d87f6d91f973 100644 --- a/data/json/npcs/refugee_center/surface_refugees/NPC_Uyen_Tran.json +++ b/data/json/npcs/refugee_center/surface_refugees/NPC_Uyen_Tran.json @@ -157,9 +157,8 @@ { "id": "MISSION_REFUGEE_Uyen_1", "type": "mission_definition", - "name": { - "str": "Find 50 doses of antiseptic for Uyen Tran in the refugee center, in exchange for Merch." - }, + "name": { "str": "Find 50 doses of antiseptic" }, + "description": "Find 50 doses of antiseptic for Uyen Tran in the refugee center, in exchange for Merch.", "goal": "MGOAL_FIND_ITEM", "difficulty": 2, "value": 0, @@ -189,7 +188,8 @@ { "id": "MISSION_REFUGEE_Uyen_2", "type": "mission_definition", - "name": { "str": "Find 30 bandages for Uyen Tran in the refugee center, in exchange for Merch." }, + "name": { "str": "Find 30 bandages" }, + "description": "Find 30 bandages for Uyen Tran in the refugee center, in exchange for Merch.", "goal": "MGOAL_FIND_ITEM", "difficulty": 2, "value": 0, @@ -219,7 +219,8 @@ { "id": "MISSION_REFUGEE_Uyen_3", "type": "mission_definition", - "name": { "str": "Find 6 bottles of Prozac for Uyen Tran in the refugee center, in exchange for Merch." }, + "name": { "str": "Find 6 bottles of Prozac" }, + "description": "Find 6 bottles of Prozac for Uyen Tran in the refugee center, in exchange for Merch.", "goal": "MGOAL_FIND_ITEM", "difficulty": 2, "value": 0, From e72fb346b7333746df5f678d2295025f5bb5df83 Mon Sep 17 00:00:00 2001 From: anothersimulacrum Date: Sun, 14 Mar 2021 13:46:12 -0700 Subject: [PATCH 049/453] JSONize some trap features, replace trap int_id externs with string_ids (#47933) * JSONize trap sonar detectibility Add trap flags - just the same as normal flags, but for traps! Stick them in their own separate file to avoid confusion. * JSONize trap memorial messages light_snare and heavy_snare seem to no longer exist, or I couldn't find any reference to them but this and tilesets. Updated dissector trap message, and added a trap message to some traps (the hallway ones, one or two of the similar-but-not-the-same variants of existing traps). * JSONize trap temperature convection Not quite sure how to describe it, went the lazy route. * Move traps externs from int to string ids When loading the game without this content, these will now only give an error on the use of these, instead of at the end data loading for traps. Previously there were performance concerns with this, but this should be fine since #44261 - see #44500. tr_null must remain an int id, as it used in the string to int id conversion. This is fine, as it will always be loaded (it's in data/core). Move the ledge trap over to data/core as well, because everything will need the 'open space' trap. --- data/core/traps.json | 17 ++++++ data/json/flags/trap.json | 12 ++++ data/json/traps.json | 78 ++++++++++++++++++++++---- doc/JSON_FLAGS.md | 4 ++ doc/JSON_INFO.md | 1 + src/game.cpp | 3 +- src/memorial_logger.cpp | 114 +------------------------------------- src/trap.cpp | 85 ++++++++++++---------------- src/trap.h | 66 ++++++++++++++-------- 9 files changed, 184 insertions(+), 196 deletions(-) create mode 100644 data/core/traps.json create mode 100644 data/json/flags/trap.json diff --git a/data/core/traps.json b/data/core/traps.json new file mode 100644 index 0000000000000..da83ec74d9697 --- /dev/null +++ b/data/core/traps.json @@ -0,0 +1,17 @@ +[ + { + "//": "We're always going to need a 'nothing here' tile, we currently use traps for this.", + "type": "trap", + "id": "tr_ledge", + "name": "ledge", + "color": "i_cyan", + "memorial_male": { "ctxt": "memorial_female", "str": "Fell down a ledge." }, + "memorial_female": { "ctxt": "memorial_female", "str": "Fell down a ledge." }, + "symbol": " ", + "visibility": 0, + "avoidance": 99999, + "difficulty": 99, + "action": "ledge", + "vehicle_data": { "is_falling": true } + } +] diff --git a/data/json/flags/trap.json b/data/json/flags/trap.json new file mode 100644 index 0000000000000..f213b6d193ef2 --- /dev/null +++ b/data/json/flags/trap.json @@ -0,0 +1,12 @@ +[ + { + "type": "json_flag", + "id": "SONAR_DETECTABLE", + "context": [ ] + }, + { + "type": "json_flag", + "id": "CONVECTS_TEMPERATURE", + "context": [ ] + } +] diff --git a/data/json/traps.json b/data/json/traps.json index 0cfb8c4e069db..d48d932157a79 100644 --- a/data/json/traps.json +++ b/data/json/traps.json @@ -4,6 +4,8 @@ "id": "tr_bubblewrap", "name": "bubble wrap", "color": "light_cyan", + "memorial_male": { "ctxt": "memorial_male", "str": "Stepped on bubble wrap." }, + "memorial_female": { "ctxt": "memorial_female", "str": "Stepped on bubble wrap." }, "symbol": "_", "visibility": 0, "avoidance": 8, @@ -17,6 +19,8 @@ "id": "tr_glass", "name": "glass shards", "color": "light_cyan", + "memorial_male": { "ctxt": "memorial_male", "str": "Stepped on glass." }, + "memorial_female": { "ctxt": "memorial_female", "str": "Stepped on glass." }, "symbol": "_", "visibility": 6, "avoidance": 8, @@ -103,6 +107,8 @@ "id": "tr_microlab_shifting_hall", "name": "microlab shifting hall", "color": "brown", + "memorial_male": { "ctxt": "memorial_male", "str": "Triggered a dimensional anomaly." }, + "memorial_female": { "ctxt": "memorial_female", "str": "Triggered a dimensional anomaly." }, "symbol": ".", "visibility": 99, "avoidance": 99, @@ -116,6 +122,8 @@ "id": "tr_microlab_shifting_hall_2", "name": "microlab shifting hall", "color": "brown", + "memorial_male": { "ctxt": "memorial_male", "str": "Triggered a dimensional anomaly." }, + "memorial_female": { "ctxt": "memorial_female", "str": "Triggered a dimensional anomaly." }, "symbol": ".", "visibility": 99, "avoidance": 99, @@ -130,6 +138,8 @@ "trigger_weight": "200 g", "name": "bear trap", "color": "blue", + "memorial_male": { "ctxt": "memorial_male", "str": "Caught by a beartrap." }, + "memorial_female": { "ctxt": "memorial_female", "str": "Caught by a beartrap." }, "symbol": "^", "visibility": 2, "avoidance": 7, @@ -152,12 +162,15 @@ "trigger_weight": "200 g", "name": "buried bear trap", "color": "blue", + "memorial_male": { "ctxt": "memorial_male", "str": "Caught by a beartrap." }, + "memorial_female": { "ctxt": "memorial_female", "str": "Caught by a beartrap." }, "symbol": "^", "visibility": 9, "avoidance": 8, "difficulty": 4, "action": "beartrap", "drops": [ "beartrap" ], + "flags": [ "SONAR_DETECTABLE" ], "vehicle_data": { "damage": 300, "sound_volume": 8, @@ -173,6 +186,8 @@ "id": "tr_nailboard", "name": "spiked board", "color": "light_gray", + "memorial_male": { "ctxt": "memorial_male", "str": "Stepped on a spiked board." }, + "memorial_female": { "ctxt": "memorial_female", "str": "Stepped on a spiked board." }, "symbol": "_", "visibility": 1, "avoidance": 6, @@ -186,6 +201,8 @@ "id": "tr_caltrops", "name": "caltrops", "color": "dark_gray", + "memorial_male": { "ctxt": "memorial_male", "str": "Stepped on a caltrop." }, + "memorial_female": { "ctxt": "memorial_female", "str": "stepped on a caltrop." }, "symbol": "_", "visibility": 4, "avoidance": 6, @@ -199,6 +216,8 @@ "id": "tr_caltrops_glass", "name": "glass caltrops", "color": "dark_gray", + "memorial_male": { "ctxt": "memorial_male", "str": "Stepped on a glass caltrop." }, + "memorial_female": { "ctxt": "memorial_female", "str": "Stepped on a glass caltrop." }, "symbol": "_", "visibility": 6, "avoidance": 6, @@ -212,6 +231,8 @@ "id": "tr_tripwire", "name": "tripwire", "color": "light_red", + "memorial_male": { "ctxt": "memorial_male", "str": "Tripped on a tripwire." }, + "memorial_female": { "ctxt": "memorial_female", "str": "Tripped on a tripwire." }, "symbol": "^", "visibility": 6, "avoidance": 4, @@ -225,6 +246,8 @@ "trigger_weight": "200 g", "name": "crossbow trap", "color": "green", + "memorial_male": { "ctxt": "memorial_male", "str": "Trigged a crossbow trap." }, + "memorial_female": { "ctxt": "memorial_female", "str": "Trigged a crossbow trap." }, "symbol": "^", "visibility": 5, "avoidance": 4, @@ -248,6 +271,8 @@ "trigger_weight": "200 g", "name": "shotgun trap", "color": "red", + "memorial_male": { "ctxt": "memorial_male", "str": "Triggered a shotgun trap." }, + "memorial_female": { "ctxt": "memorial_female", "str": "Triggered a shotgun trap." }, "symbol": "^", "visibility": 4, "avoidance": 5, @@ -270,6 +295,8 @@ "trigger_weight": "200 g", "name": "shotgun trap", "color": "red", + "memorial_male": { "ctxt": "memorial_male", "str": "Triggered a shotgun trap." }, + "memorial_female": { "ctxt": "memorial_female", "str": "Triggered a shotgun trap." }, "symbol": "^", "visibility": 4, "avoidance": 5, @@ -293,6 +320,8 @@ "trigger_weight": "200 g", "name": "shotgun trap", "color": "red", + "memorial_male": { "ctxt": "memorial_male", "str": "Triggered a shotgun trap." }, + "memorial_female": { "ctxt": "memorial_female", "str": "Triggered a shotgun trap." }, "symbol": "^", "visibility": 4, "avoidance": 5, @@ -329,6 +358,8 @@ "id": "tr_blade", "name": "spinning blade", "color": "cyan", + "memorial_male": { "ctxt": "memorial_male", "str": "Triggered a blade trap." }, + "memorial_female": { "ctxt": "memorial_female", "str": "Triggered a blade trap." }, "symbol": "\\", "visibility": 0, "avoidance": 4, @@ -342,6 +373,8 @@ "trigger_weight": "200 g", "name": "land mine", "color": "red", + "memorial_male": { "ctxt": "memorial_male", "str": "Stepped on a land mine." }, + "memorial_female": { "ctxt": "memorial_female", "str": "Stepped on a land mine." }, "symbol": "^", "visibility": 1, "avoidance": 14, @@ -364,12 +397,15 @@ "trigger_weight": "200 g", "name": "buried land mine", "color": "red", + "memorial_male": { "ctxt": "memorial_male", "str": "Stepped on a land mine." }, + "memorial_female": { "ctxt": "memorial_female", "str": "Stepped on a land mine." }, "symbol": "_", "visibility": 10, "avoidance": 14, "difficulty": 10, "action": "landmine", "drops": [ "landmine" ], + "flags": [ "SONAR_DETECTABLE" ], "vehicle_data": { "do_explosion": true, "damage": 1000, @@ -386,6 +422,8 @@ "trigger_weight": "200 g", "name": "teleport pad", "color": "magenta", + "memorial_male": { "ctxt": "memorial_male", "str": "Triggered a teleport trap." }, + "memorial_female": { "ctxt": "memorial_female", "str": "Triggered a teleport trap." }, "symbol": "_", "visibility": 0, "avoidance": 15, @@ -398,6 +436,8 @@ "id": "tr_goo", "name": "goo pit", "color": "dark_gray", + "memorial_male": { "ctxt": "memorial_male", "str": "Stepped into thick goo." }, + "memorial_female": { "ctxt": "memorial_female", "str": "Stepped into thick goo." }, "symbol": "_", "visibility": 0, "avoidance": 15, @@ -409,6 +449,8 @@ "id": "tr_dissector", "name": "exposed high-energy conduit", "color": "cyan", + "memorial_male": { "ctxt": "memorial_male", "str": "Stepped into an exposed high-energy conduit." }, + "memorial_female": { "ctxt": "memorial_female", "str": "Stepped into an exposed high-energy conduit." }, "symbol": "7", "visibility": 2, "avoidance": 20, @@ -421,11 +463,14 @@ "id": "tr_sinkhole", "name": "sinkhole", "color": "brown", + "memorial_male": { "ctxt": "memorial_male", "str": "Stepped into a sinkhole." }, + "memorial_female": { "ctxt": "memorial_female", "str": "Stepped into a sinkhole." }, "symbol": "_", "visibility": 10, "avoidance": 14, "difficulty": 99, "action": "sinkhole", + "flags": [ "SONAR_DETECTABLE" ], "vehicle_data": { "damage": 500 } }, { @@ -433,6 +478,8 @@ "id": "tr_pit", "name": "pit", "color": "brown", + "memorial_male": { "ctxt": "memorial_male", "str": "Fell in a pit." }, + "memorial_female": { "ctxt": "memorial_female", "str": "Fell in a pit." }, "symbol": "0", "visibility": 0, "avoidance": 8, @@ -445,6 +492,8 @@ "id": "tr_spike_pit", "name": "spiked pit", "color": "blue", + "memorial_male": { "ctxt": "memorial_male", "str": "Fell into a spiked pit." }, + "memorial_female": { "ctxt": "memorial_female", "str": "Fell into a spiked pit." }, "symbol": "0", "visibility": 0, "avoidance": 8, @@ -457,11 +506,14 @@ "id": "tr_lava", "name": "lava", "color": "red", + "memorial_male": { "ctxt": "memorial_male", "str": "Stepped into lava." }, + "memorial_female": { "ctxt": "memorial_female", "str": "Stepped into lava." }, "symbol": "~", "visibility": 0, "avoidance": 99, "difficulty": 99, "action": "lava", + "flags": [ "CONVECTS_TEMPERATURE" ], "vehicle_data": { "damage": 500 } }, { @@ -469,30 +521,22 @@ "id": "tr_portal", "name": "shimmering portal", "color": "magenta", + "memorial_male": { "ctxt": "memorial_male", "str": "Triggered a teleoport trap." }, + "memorial_female": { "ctxt": "memorial_female", "str": "Triggered a teleoport trap." }, "symbol": "%", "visibility": 0, "avoidance": 99, "difficulty": 99, "action": "portal" }, - { - "type": "trap", - "id": "tr_ledge", - "name": "ledge", - "color": "i_cyan", - "symbol": " ", - "visibility": 0, - "avoidance": 99999, - "difficulty": 99, - "action": "ledge", - "vehicle_data": { "is_falling": true } - }, { "type": "trap", "id": "tr_boobytrap", "trigger_weight": "200 g", "name": "booby trap", "color": "light_cyan", + "memorial_male": { "ctxt": "memorial_male", "str": "Triggered a booby trap." }, + "memorial_female": { "ctxt": "memorial_female", "str": "Triggered a booby trap." }, "symbol": "^", "visibility": 5, "avoidance": 4, @@ -514,6 +558,8 @@ "id": "tr_temple_flood", "name": "ledge", "color": "light_gray", + "memorial_male": { "ctxt": "memorial_male", "str": "Triggered a flood trap." }, + "memorial_female": { "ctxt": "memorial_female", "str": "Triggered a flood trap." }, "symbol": "^", "visibility": 9, "avoidance": 20, @@ -561,6 +607,8 @@ "id": "tr_shadow", "name": "", "color": "white", + "memorial_male": { "ctxt": "memorial_male", "str": "Triggered a shadow trap." }, + "memorial_female": { "ctxt": "memorial_female", "str": "Triggered a shadow trap." }, "symbol": "^", "visibility": 99, "avoidance": 99, @@ -573,6 +621,8 @@ "id": "tr_drain", "name": "", "color": "white", + "memorial_male": { "ctxt": "memorial_male", "str": "Triggered a life-draining trap." }, + "memorial_female": { "ctxt": "memorial_female", "str": "Triggered a life-draining trap." }, "symbol": "^", "visibility": 99, "avoidance": 99, @@ -585,6 +635,8 @@ "id": "tr_snake", "name": "", "color": "white", + "memorial_male": { "ctxt": "memorial_male", "str": "Triggered a shadow snake trap." }, + "memorial_female": { "ctxt": "memorial_female", "str": "Triggered a shadow snake trap." }, "symbol": "^", "visibility": 99, "avoidance": 99, @@ -597,6 +649,8 @@ "id": "tr_glass_pit", "name": "glass pit", "color": "cyan", + "memorial_male": { "ctxt": "memorial_male", "str": "Fell into a pit filled with glass shards." }, + "memorial_female": { "ctxt": "memorial_female", "str": "Fell into a pit filled with glass shards." }, "symbol": "0", "visibility": 0, "avoidance": 8, diff --git a/doc/JSON_FLAGS.md b/doc/JSON_FLAGS.md index 69ccb0472c6f4..f26119aaa4bf1 100644 --- a/doc/JSON_FLAGS.md +++ b/doc/JSON_FLAGS.md @@ -206,6 +206,10 @@ These are handled through `ammo_types.json`. You can tag a weapon with these to - ```WIDE``` Prevents `HARDTOSHOOT` monster flag from having any effect. Implied by ```SHOT``` or liquid ammo. - ```NON_FOULING``` This ammo does not cause dirtying or blackpowder fouling on the gun when fired. +## Traps + +- ```SONAR_DETECTABLE``` This trap can be identified with ground-penetrating SONAR. +- ```CONVECTS_TEMPERATURE``` This trap convects temperature, like lava. ## Armor diff --git a/doc/JSON_INFO.md b/doc/JSON_INFO.md index 4453242c0f6d4..d695eaab30f72 100644 --- a/doc/JSON_INFO.md +++ b/doc/JSON_INFO.md @@ -1973,6 +1973,7 @@ it is present to help catch errors. "spell_data": { "id": "bear_trap" }, // data required for trapfunc::spell() "trigger_weight": "200 g", // If an item with this weight or more is thrown onto the trap, it triggers. TODO: what is the default? "drops": [ "beartrap" ], // For disassembly? + "flags": [ "EXAMPLE_FLAG" ], // A set of valid flags for this trap "vehicle_data": { "damage": 300, "sound_volume": 8, diff --git a/src/game.cpp b/src/game.cpp index c06d043ea41dc..1e7443182b49f 100644 --- a/src/game.cpp +++ b/src/game.cpp @@ -1868,10 +1868,11 @@ int get_heat_radiation( const tripoint &location, bool direct ) int get_convection_temperature( const tripoint &location ) { + static const flag_id trap_convects( "CONVECTS_TEMPERATURE" ); int temp_mod = 0; map &here = get_map(); // Directly on lava tiles - int lava_mod = here.tr_at( location ) == tr_lava ? + int lava_mod = here.tr_at( location ).has_flag( trap_convects ) ? fd_fire->get_intensity_level().convection_temperature_mod : 0; // Modifier from fields for( auto fd : here.field_at( location ) ) { diff --git a/src/memorial_logger.cpp b/src/memorial_logger.cpp index 122180f7b8bd7..9de81018cf371 100644 --- a/src/memorial_logger.cpp +++ b/src/memorial_logger.cpp @@ -49,6 +49,7 @@ #include "skill.h" #include "stats_tracker.h" #include "translations.h" +#include "trap.h" #include "type_id.h" #include "units.h" @@ -57,36 +58,6 @@ static const efftype_id effect_datura( "datura" ); static const efftype_id effect_drunk( "drunk" ); static const efftype_id effect_jetinjector( "jetinjector" ); -static const trap_str_id tr_bubblewrap( "tr_bubblewrap" ); -static const trap_str_id tr_glass( "tr_glass" ); -static const trap_str_id tr_beartrap( "tr_beartrap" ); -static const trap_str_id tr_nailboard( "tr_nailboard" ); -static const trap_str_id tr_caltrops( "tr_caltrops" ); -static const trap_str_id tr_caltrops_glass( "tr_caltrops_glass" ); -static const trap_str_id tr_tripwire( "tr_tripwire" ); -static const trap_str_id tr_crossbow( "tr_crossbow" ); -static const trap_str_id tr_shotgun_2( "tr_shotgun_2" ); -static const trap_str_id tr_shotgun_1( "tr_shotgun_1" ); -static const trap_str_id tr_blade( "tr_blade" ); -static const trap_str_id tr_landmine( "tr_landmine" ); -static const trap_str_id tr_light_snare( "tr_light_snare" ); -static const trap_str_id tr_heavy_snare( "tr_heavy_snare" ); -static const trap_str_id tr_telepad( "tr_telepad" ); -static const trap_str_id tr_goo( "tr_goo" ); -static const trap_str_id tr_dissector( "tr_dissector" ); -static const trap_str_id tr_sinkhole( "tr_sinkhole" ); -static const trap_str_id tr_pit( "tr_pit" ); -static const trap_str_id tr_spike_pit( "tr_spike_pit" ); -static const trap_str_id tr_lava( "tr_lava" ); -static const trap_str_id tr_portal( "tr_portal" ); -static const trap_str_id tr_ledge( "tr_ledge" ); -static const trap_str_id tr_boobytrap( "tr_boobytrap" ); -static const trap_str_id tr_temple_flood( "tr_temple_flood" ); -static const trap_str_id tr_shadow( "tr_shadow" ); -static const trap_str_id tr_drain( "tr_drain" ); -static const trap_str_id tr_snake( "tr_snake" ); -static const trap_str_id tr_glass_pit( "tr_glass_pit" ); - static const trait_id trait_CANNIBAL( "CANNIBAL" ); static const trait_id trait_PSYCHOPATH( "PSYCHOPATH" ); static const trait_id trait_SAPIOVORE( "SAPIOVORE" ); @@ -655,87 +626,8 @@ void memorial_logger::notify( const cata::event &e ) character_id ch = e.get( "character" ); if( ch == avatar_id ) { trap_str_id trap = e.get( "trap" ); - if( trap == tr_bubblewrap ) { - add( pgettext( "memorial_male", "Stepped on bubble wrap." ), - pgettext( "memorial_female", "Stepped on bubble wrap." ) ); - } else if( trap == tr_glass ) { - add( pgettext( "memorial_male", "Stepped on glass." ), - pgettext( "memorial_female", "Stepped on glass." ) ); - } else if( trap == tr_beartrap ) { - add( pgettext( "memorial_male", "Caught by a beartrap." ), - pgettext( "memorial_female", "Caught by a beartrap." ) ); - } else if( trap == tr_nailboard ) { - add( pgettext( "memorial_male", "Stepped on a spiked board." ), - pgettext( "memorial_female", "Stepped on a spiked board." ) ); - } else if( trap == tr_caltrops ) { - add( pgettext( "memorial_male", "Stepped on a caltrop." ), - pgettext( "memorial_female", "Stepped on a caltrop." ) ); - } else if( trap == tr_caltrops_glass ) { - add( pgettext( "memorial_male", "Stepped on a glass caltrop." ), - pgettext( "memorial_female", "Stepped on a glass caltrop." ) ); - } else if( trap == tr_tripwire ) { - add( pgettext( "memorial_male", "Tripped on a tripwire." ), - pgettext( "memorial_female", "Tripped on a tripwire." ) ); - } else if( trap == tr_crossbow ) { - add( pgettext( "memorial_male", "Triggered a crossbow trap." ), - pgettext( "memorial_female", "Triggered a crossbow trap." ) ); - } else if( trap == tr_shotgun_1 || trap == tr_shotgun_2 ) { - add( pgettext( "memorial_male", "Triggered a shotgun trap." ), - pgettext( "memorial_female", "Triggered a shotgun trap." ) ); - } else if( trap == tr_blade ) { - add( pgettext( "memorial_male", "Triggered a blade trap." ), - pgettext( "memorial_female", "Triggered a blade trap." ) ); - } else if( trap == tr_light_snare ) { - add( pgettext( "memorial_male", "Triggered a light snare." ), - pgettext( "memorial_female", "Triggered a light snare." ) ); - } else if( trap == tr_heavy_snare ) { - add( pgettext( "memorial_male", "Triggered a heavy snare." ), - pgettext( "memorial_female", "Triggered a heavy snare." ) ); - } else if( trap == tr_landmine ) { - add( pgettext( "memorial_male", "Stepped on a land mine." ), - pgettext( "memorial_female", "Stepped on a land mine." ) ); - } else if( trap == tr_boobytrap ) { - add( pgettext( "memorial_male", "Triggered a booby trap." ), - pgettext( "memorial_female", "Triggered a booby trap." ) ); - } else if( trap == tr_telepad || trap == tr_portal ) { - add( pgettext( "memorial_male", "Triggered a teleport trap." ), - pgettext( "memorial_female", "Triggered a teleport trap." ) ); - } else if( trap == tr_goo ) { - add( pgettext( "memorial_male", "Stepped into thick goo." ), - pgettext( "memorial_female", "Stepped into thick goo." ) ); - } else if( trap == tr_dissector ) { - add( pgettext( "memorial_male", "Stepped into a dissector." ), - pgettext( "memorial_female", "Stepped into a dissector." ) ); - } else if( trap == tr_pit ) { - add( pgettext( "memorial_male", "Fell in a pit." ), - pgettext( "memorial_female", "Fell in a pit." ) ); - } else if( trap == tr_spike_pit ) { - add( pgettext( "memorial_male", "Fell into a spiked pit." ), - pgettext( "memorial_female", "Fell into a spiked pit." ) ); - } else if( trap == tr_glass_pit ) { - add( pgettext( "memorial_male", "Fell into a pit filled with glass shards." ), - pgettext( "memorial_female", "Fell into a pit filled with glass shards." ) ); - } else if( trap == tr_lava ) { - add( pgettext( "memorial_male", "Stepped into lava." ), - pgettext( "memorial_female", "Stepped into lava." ) ); - } else if( trap == tr_sinkhole ) { - add( pgettext( "memorial_male", "Stepped into a sinkhole." ), - pgettext( "memorial_female", "Stepped into a sinkhole." ) ); - } else if( trap == tr_ledge ) { - add( pgettext( "memorial_male", "Fell down a ledge." ), - pgettext( "memorial_female", "Fell down a ledge." ) ); - } else if( trap == tr_temple_flood ) { - add( pgettext( "memorial_male", "Triggered a flood trap." ), - pgettext( "memorial_female", "Triggered a flood trap." ) ); - } else if( trap == tr_shadow ) { - add( pgettext( "memorial_male", "Triggered a shadow trap." ), - pgettext( "memorial_female", "Triggered a shadow trap." ) ); - } else if( trap == tr_drain ) { - add( pgettext( "memorial_male", "Triggered a life-draining trap." ), - pgettext( "memorial_female", "Triggered a life-draining trap." ) ); - } else if( trap == tr_snake ) { - add( pgettext( "memorial_male", "Triggered a shadow snake trap." ), - pgettext( "memorial_female", "Triggered a shadow snake trap." ) ); + if( trap->has_memorial_msg() ) { + add( trap->memorial_msg( true ), trap->memorial_msg( false ) ); } } break; diff --git a/src/trap.cpp b/src/trap.cpp index d40d52ee58d58..3eb7195b13042 100644 --- a/src/trap.cpp +++ b/src/trap.cpp @@ -110,6 +110,17 @@ void trap::load( const JsonObject &jo, const std::string & ) mandatory( jo, was_loaded, "visibility", visibility ); mandatory( jo, was_loaded, "avoidance", avoidance ); mandatory( jo, was_loaded, "difficulty", difficulty ); + + optional( jo, was_loaded, "memorial_male", memorial_male ); + optional( jo, was_loaded, "memorial_female", memorial_female ); + + // Require either none, or both + if( !!memorial_male != !!memorial_female ) { + jo.throw_error( "Only one gender of memorial message specified for trap %s, but none or both required.", + id.str() ); + } + + optional( jo, was_loaded, "flags", _flags ); optional( jo, was_loaded, "trap_radius", trap_radius, 0 ); // TODO: Is there a generic_factory version of this? act = trap_function_from_string( jo.get_string( "action" ) ); @@ -195,8 +206,8 @@ bool trap::is_trivial_to_spot() const bool trap::detected_by_ground_sonar() const { - // @TODO make this a property - return loadid == tr_beartrap_buried || loadid == tr_landmine_buried || loadid == tr_sinkhole; + static const flag_id sonar_detectable = flag_id( "SONAR_DETECTABLE" ); + return has_flag( sonar_detectable ); } bool trap::detect_trap( const tripoint &pos, const Character &p ) const @@ -322,29 +333,28 @@ void trap::on_disarmed( map &m, const tripoint &p ) const ////////////////////////// // convenient int-lookup names for hard-coded functions -trap_id -tr_null, -tr_beartrap_buried, -tr_shotgun_2, -tr_shotgun_1, -tr_blade, -tr_landmine, -tr_landmine_buried, -tr_telepad, -tr_goo, -tr_dissector, -tr_sinkhole, -tr_pit, -tr_lava, -tr_portal, -tr_ledge, -tr_temple_flood, -tr_temple_toggle, -tr_glow, -tr_hum, -tr_shadow, -tr_drain, -tr_snake; +trap_id tr_null; +const trap_str_id tr_beartrap_buried( "tr_beartrap_buried" ); +const trap_str_id tr_shotgun_2( "tr_shotgun_2" ); +const trap_str_id tr_shotgun_1( "tr_shotgun_1" ); +const trap_str_id tr_blade( "tr_blade" ); +const trap_str_id tr_landmine( "tr_landmine" ); +const trap_str_id tr_landmine_buried( "tr_landmine_buried" ); +const trap_str_id tr_telepad( "tr_telepad" ); +const trap_str_id tr_goo( "tr_goo" ); +const trap_str_id tr_dissector( "tr_dissector" ); +const trap_str_id tr_sinkhole( "tr_sinkhole" ); +const trap_str_id tr_pit( "tr_pit" ); +const trap_str_id tr_lava( "tr_lava" ); +const trap_str_id tr_portal( "tr_portal" ); +const trap_str_id tr_ledge( "tr_ledge" ); +const trap_str_id tr_temple_flood( "tr_temple_flood" ); +const trap_str_id tr_temple_toggle( "tr_temple_toggle" ); +const trap_str_id tr_glow( "tr_glow" ); +const trap_str_id tr_hum( "tr_hum" ); +const trap_str_id tr_shadow( "tr_shadow" ); +const trap_str_id tr_drain( "tr_drain" ); +const trap_str_id tr_snake( "tr_snake" ); void trap::check_consistency() { @@ -378,31 +388,8 @@ void trap::finalize() funnel_traps.push_back( &t ); } } - const auto trapfind = []( const char *id ) { - return trap_str_id( id ).id(); - }; + tr_null = trap_str_id::NULL_ID().id(); - tr_beartrap_buried = trapfind( "tr_beartrap_buried" ); - tr_shotgun_2 = trapfind( "tr_shotgun_2" ); - tr_shotgun_1 = trapfind( "tr_shotgun_1" ); - tr_blade = trapfind( "tr_blade" ); - tr_landmine = trapfind( "tr_landmine" ); - tr_landmine_buried = trapfind( "tr_landmine_buried" ); - tr_telepad = trapfind( "tr_telepad" ); - tr_goo = trapfind( "tr_goo" ); - tr_dissector = trapfind( "tr_dissector" ); - tr_sinkhole = trapfind( "tr_sinkhole" ); - tr_pit = trapfind( "tr_pit" ); - tr_lava = trapfind( "tr_lava" ); - tr_portal = trapfind( "tr_portal" ); - tr_ledge = trapfind( "tr_ledge" ); - tr_temple_flood = trapfind( "tr_temple_flood" ); - tr_temple_toggle = trapfind( "tr_temple_toggle" ); - tr_glow = trapfind( "tr_glow" ); - tr_hum = trapfind( "tr_hum" ); - tr_shadow = trapfind( "tr_shadow" ); - tr_drain = trapfind( "tr_drain" ); - tr_snake = trapfind( "tr_snake" ); } std::string trap::debug_describe() const diff --git a/src/trap.h b/src/trap.h index 295d45eb92c33..91f7f55e728d9 100644 --- a/src/trap.h +++ b/src/trap.h @@ -137,6 +137,12 @@ struct trap { std::string map_regen; trap_function act; translation name_; + + cata::optional memorial_male; + cata::optional memorial_female; + + cata::flat_set _flags; + /** * If an item with this weight or more is thrown onto the trap, it triggers. */ @@ -166,6 +172,21 @@ struct trap { return loadid != id; } + bool has_flag( const flag_id &flag ) const { + return _flags.count( flag ); + } + + bool has_memorial_msg() const { + return memorial_male && memorial_female; + } + + std::string memorial_msg( bool male ) const { + if( male ) { + return memorial_male->translated(); + } + return memorial_female->translated(); + } + /** * Called when the player examines a tile. This is supposed to handled * all kind of interaction of the player with the trap, including removal. @@ -322,28 +343,27 @@ struct trap { const trap_function &trap_function_from_string( const std::string &function_name ); -extern trap_id -tr_null, -tr_beartrap_buried, -tr_shotgun_2, -tr_shotgun_1, -tr_blade, -tr_landmine, -tr_landmine_buried, -tr_telepad, -tr_goo, -tr_dissector, -tr_sinkhole, -tr_pit, -tr_lava, -tr_portal, -tr_ledge, -tr_temple_flood, -tr_temple_toggle, -tr_glow, -tr_hum, -tr_shadow, -tr_drain, -tr_snake; +extern trap_id tr_null; +extern const trap_str_id tr_beartrap_buried; +extern const trap_str_id tr_shotgun_2; +extern const trap_str_id tr_shotgun_1; +extern const trap_str_id tr_blade; +extern const trap_str_id tr_landmine; +extern const trap_str_id tr_landmine_buried; +extern const trap_str_id tr_telepad; +extern const trap_str_id tr_goo; +extern const trap_str_id tr_dissector; +extern const trap_str_id tr_sinkhole; +extern const trap_str_id tr_pit; +extern const trap_str_id tr_lava; +extern const trap_str_id tr_portal; +extern const trap_str_id tr_ledge; +extern const trap_str_id tr_temple_flood; +extern const trap_str_id tr_temple_toggle; +extern const trap_str_id tr_glow; +extern const trap_str_id tr_hum; +extern const trap_str_id tr_shadow; +extern const trap_str_id tr_drain; +extern const trap_str_id tr_snake; #endif // CATA_SRC_TRAP_H From 2ef3433e7dabdf60f6258f664a3ded1d3d311364 Mon Sep 17 00:00:00 2001 From: anothersimulacrum Date: Mon, 1 Mar 2021 17:07:51 -0800 Subject: [PATCH 050/453] Clean up character mutation gain a bit (#47821) Reduce duplicated code. I presume there's a reason that set_mutations didn't just call set_mutation, and the only difference is that it doesn't do the cache updates till the end, so preserve that behaviour. --- src/character.h | 7 +++++++ src/mutation.cpp | 40 +++++++++++++++++++--------------------- 2 files changed, 26 insertions(+), 21 deletions(-) diff --git a/src/character.h b/src/character.h index a348e13a42716..1ee1982608254 100644 --- a/src/character.h +++ b/src/character.h @@ -974,6 +974,13 @@ class Character : public Creature, public visitable /** Add or removes a mutation on the player, but does not trigger mutation loss/gain effects. */ void set_mutations( const std::vector &traits ); void set_mutation( const trait_id & ); + protected: + // Set a mutation, but don't do any of the necessary updates + // Only call this from one of the above two functions + void set_mutation_unsafe( const trait_id & ); + public: + // Do the mutation updates necessary when adding a mutation (nonspecific cache updates) + void do_mutation_updates(); void unset_mutation( const trait_id & ); /**Unset switched mutation and set target mutation instead*/ void switch_mutations( const trait_id &switched, const trait_id &target, bool start_powered ); diff --git a/src/mutation.cpp b/src/mutation.cpp index ea289fdce0c25..c8229f05af92d 100644 --- a/src/mutation.cpp +++ b/src/mutation.cpp @@ -158,27 +158,7 @@ void Character::toggle_trait( const trait_id &trait_ ) } } -void Character::set_mutations( const std::vector &traits ) -{ - for( const trait_id &trait : traits ) { - const auto iter = my_mutations.find( trait ); - if( iter != my_mutations.end() ) { - continue; - } - my_mutations.emplace( trait, trait_data{} ); - cached_mutations.push_back( &trait.obj() ); - mutation_effect( trait, false ); - } - recalc_sight_limits(); - calc_encumbrance(); - - // If the stamina is higher than the max (Languorous), set it back to max - if( get_stamina() > get_stamina_max() ) { - set_stamina( get_stamina_max() ); - } -} - -void Character::set_mutation( const trait_id &trait ) +void Character::set_mutation_unsafe( const trait_id &trait ) { const auto iter = my_mutations.find( trait ); if( iter != my_mutations.end() ) { @@ -187,6 +167,10 @@ void Character::set_mutation( const trait_id &trait ) my_mutations.emplace( trait, trait_data{} ); cached_mutations.push_back( &trait.obj() ); mutation_effect( trait, false ); +} + +void Character::do_mutation_updates() +{ recalc_sight_limits(); calc_encumbrance(); @@ -196,6 +180,20 @@ void Character::set_mutation( const trait_id &trait ) } } +void Character::set_mutations( const std::vector &traits ) +{ + for( const trait_id &trait : traits ) { + set_mutation_unsafe( trait ); + } + do_mutation_updates(); +} + +void Character::set_mutation( const trait_id &trait ) +{ + set_mutation_unsafe( trait ); + do_mutation_updates(); +} + void Character::unset_mutation( const trait_id &trait_ ) { // Take copy of argument because it might be a reference into a container From e5527f7dce67558c11ff2000c0099c1a87b957a1 Mon Sep 17 00:00:00 2001 From: anothersimulacrum Date: Sun, 14 Mar 2021 13:48:23 -0700 Subject: [PATCH 051/453] Allow CBMs to specify mutations that prevent installation. (#47822) * Move CBM installation checks to Character Reduce code duplication, encapsulate things better, and make this available outside of the inventory menus. * Allow mutations to prevent installing CBMs Bionics can currently cancel mutations when installed, but can't have mutations prevent installation. --- doc/JSON_INFO.md | 2 ++ src/bionics.cpp | 50 +++++++++++++++++++++++++++++++++ src/bionics.h | 4 +++ src/character.h | 3 ++ src/game_inventory.cpp | 64 ++++-------------------------------------- src/mutation.cpp | 12 ++++++++ 6 files changed, 77 insertions(+), 58 deletions(-) diff --git a/doc/JSON_INFO.md b/doc/JSON_INFO.md index d695eaab30f72..20dbbaac92b1e 100644 --- a/doc/JSON_INFO.md +++ b/doc/JSON_INFO.md @@ -655,6 +655,7 @@ For information about tools with option to export ASCII art in format ready to b | weight_capacity_bonus | (_optional_) Bonus to weight carrying capacity in grams, can be negative. Strings can be used - "5000 g" or "5 kg" (default: `0`) | weight_capacity_modifier | (_optional_) Factor modifying base weight carrying capacity. (default: `1`) | canceled_mutations | (_optional_) A list of mutations/traits that are removed when this bionic is installed (e.g. because it replaces the fault biological part). +| mutation_conflicts | (_optional_) A list of mutations that prevent this bionic from being installed. | included_bionics | (_optional_) Additional bionics that are installed automatically when this bionic is installed. This can be used to install several bionics from one CBM item, which is useful as each of those can be activated independently. | included | (_optional_) Whether this bionic is included with another. If true this bionic does not require a CBM item to be defined. (default: `false`) | env_protec | (_optional_) How much environmental protection does this bionic provide on the specified body parts. @@ -692,6 +693,7 @@ For information about tools with option to export ASCII art in format ready to b "encumbrance" : [ [ "torso", 10 ], [ "arm_l", 10 ], [ "arm_r", 10 ], [ "leg_l", 10 ], [ "leg_r", 10 ], [ "foot_l", 10 ], [ "foot_r", 10 ] ], "description" : "You have a battery draining attachment, and thus can make use of the energy contained in normal, everyday batteries. Use 'E' to consume batteries.", "canceled_mutations": ["HYPEROPIC"], + "mutation_conflicts": [ "HUGE" ], "installation_requirement": "sewing_standard", "included_bionics": ["bio_blindfold"] }, diff --git a/src/bionics.cpp b/src/bionics.cpp index 20a28a9ef7bcb..72706762976de 100644 --- a/src/bionics.cpp +++ b/src/bionics.cpp @@ -192,6 +192,7 @@ static const trait_id trait_PROF_MED( "PROF_MED" ); static const trait_id trait_THRESH_MEDICAL( "THRESH_MEDICAL" ); static const json_character_flag json_flag_BIONIC_GUN( "BIONIC_GUN" ); +static const json_character_flag json_flag_BIONIC_NPC_USABLE( "BIONIC_NPC_USABLE" ); static const json_character_flag json_flag_BIONIC_WEAPON( "BIONIC_WEAPON" ); static const json_character_flag json_flag_BIONIC_TOGGLED( "BIONIC_TOGGLED" ); @@ -317,6 +318,7 @@ void bionic_data::load( const JsonObject &jsobj, const std::string & ) optional( jsobj, was_loaded, "learned_spells", learned_spells ); optional( jsobj, was_loaded, "learned_proficiencies", proficiencies ); optional( jsobj, was_loaded, "canceled_mutations", canceled_mutations ); + optional( jsobj, was_loaded, "mutation_conflicts", mutation_conflicts ); optional( jsobj, was_loaded, "included_bionics", included_bionics ); optional( jsobj, was_loaded, "included", included ); optional( jsobj, was_loaded, "upgraded_bionic", upgraded_bionic ); @@ -2316,6 +2318,54 @@ bool Character::uninstall_bionic( const bionic &target_cbm, monster &installer, return false; } +ret_val Character::is_installable( const item_location &loc, const bool by_autodoc ) const +{ + const item *it = loc.get_item(); + const itype *itemtype = it->type; + const bionic_id &bid = itemtype->bionic->id; + + const auto has_trait_lambda = [this]( const trait_id & candidate ) { + return has_trait( candidate ); + }; + + if( it->has_flag( flag_FILTHY ) ) { + // NOLINTNEXTLINE(cata-text-style): single space after the period for symmetry + const std::string msg = by_autodoc ? _( "/!\\ CBM is highly contaminated. /!\\" ) : + _( "CBM is filthy." ); + return ret_val::make_failure( msg ); + } else if( it->has_flag( flag_NO_STERILE ) ) { + const std::string msg = by_autodoc ? + // NOLINTNEXTLINE(cata-text-style): single space after the period for symmetry + _( "/!\\ CBM is not sterile. /!\\ Please use autoclave to sterilize." ) : + _( "CBM is not sterile." ); + return ret_val::make_failure( msg ); + } else if( it->has_fault( fault_id( "fault_bionic_salvaged" ) ) ) { + return ret_val::make_failure( _( "CBM already deployed. Please reset to factory state." ) ); + } else if( has_bionic( bid ) ) { + return ret_val::make_failure( _( "CBM is already installed." ) ); + } else if( !can_install_cbm_on_bp( get_occupied_bodyparts( bid ) ) ) { + return ret_val::make_failure( _( "CBM not compatible with patient's body." ) ); + } else if( std::any_of( bid->mutation_conflicts.begin(), bid->mutation_conflicts.end(), + has_trait_lambda ) ) { + return ret_val::make_failure( _( "CBM not compatible with patient's body." ) ); + } else if( bid->upgraded_bionic && + !has_bionic( bid->upgraded_bionic ) && + it->is_upgrade() ) { + return ret_val::make_failure( _( "No base version installed." ) ); + } else if( std::any_of( bid->available_upgrades.begin(), + bid->available_upgrades.end(), + std::bind( &Character::has_bionic, this, + std::placeholders::_1 ) ) ) { + return ret_val::make_failure( _( "Superior version installed." ) ); + } else if( is_npc() && !bid->has_flag( json_flag_BIONIC_NPC_USABLE ) ) { + return ret_val::make_failure( _( "CBM not compatible with patient." ) ); + } else if( units::energy_max - get_max_power_level() < bid->capacity ) { + return ret_val::make_failure( _( "Max power capacity already reached." ) ); + } + + return ret_val::make_success( std::string() ); +} + bool Character::can_install_bionics( const itype &type, Character &installer, bool autodoc, int skill_level ) { diff --git a/src/bionics.h b/src/bionics.h index 8f18e22307110..0dfee95903409 100644 --- a/src/bionics.h +++ b/src/bionics.h @@ -113,6 +113,10 @@ struct bionic_data { * E.g. enhanced optic bionic may cancel HYPEROPIC trait. */ std::vector canceled_mutations; + /** + * Mutations/traits that prevent installing this CBM + */ + std::set mutation_conflicts; /** * The spells you learn when you install this bionic, and what level you learn them at. diff --git a/src/character.h b/src/character.h index 1ee1982608254..660e5b0c792a3 100644 --- a/src/character.h +++ b/src/character.h @@ -1310,6 +1310,9 @@ class Character : public Creature, public visitable /**Is the installation possible*/ bool can_install_bionics( const itype &type, Character &installer, bool autodoc = false, int skill_level = -1 ); + /** Is this bionic elligible to be installed in the player? */ + // Should be ret_val, but ret_val.h doesn't like it + ret_val is_installable( const item_location &loc, bool by_autodoc ) const; std::map bionic_installation_issues( const bionic_id &bioid ); /** Initialize all the values needed to start the operation player_activity */ bool install_bionics( const itype &type, player &installer, bool autodoc = false, diff --git a/src/game_inventory.cpp b/src/game_inventory.cpp index 32f08207802cb..0198fd600e926 100644 --- a/src/game_inventory.cpp +++ b/src/game_inventory.cpp @@ -74,8 +74,6 @@ static const trait_id trait_NOPAIN( "NOPAIN" ); static const trait_id trait_SAPROPHAGE( "SAPROPHAGE" ); static const trait_id trait_SAPROVORE( "SAPROVORE" ); -static const json_character_flag json_flag_BIONIC_NPC_USABLE( "BIONIC_NPC_USABLE" ); - using item_filter = std::function; using item_location_filter = std::function; @@ -1816,41 +1814,15 @@ class bionic_install_preset: public inventory_selector_preset } std::string get_denial( const item_location &loc ) const override { - const item *it = loc.get_item(); - const itype *itemtype = it->type; - const bionic_id &bid = itemtype->bionic->id; - - if( it->has_flag( flag_FILTHY ) ) { - // NOLINTNEXTLINE(cata-text-style): single space after the period for symmetry - return _( "/!\\ CBM is highly contaminated. /!\\" ); - } else if( it->has_flag( flag_NO_STERILE ) ) { - // NOLINTNEXTLINE(cata-text-style): single space after the period for symmetry - return _( "/!\\ CBM is not sterile. /!\\ Please use autoclave to sterilize." ); - } else if( it->has_fault( fault_id( "fault_bionic_salvaged" ) ) ) { - return _( "CBM already deployed. Please reset to factory state." ); - } else if( pa.has_bionic( bid ) ) { - return _( "CBM already installed." ); - } else if( !pa.can_install_cbm_on_bp( get_occupied_bodyparts( bid ) ) ) { - return _( "CBM not compatible with patient's body." ); - } else if( bid->upgraded_bionic && - !pa.has_bionic( bid->upgraded_bionic ) && - it->is_upgrade() ) { - return _( "No base version installed." ); - } else if( std::any_of( bid->available_upgrades.begin(), - bid->available_upgrades.end(), - std::bind( &player::has_bionic, &pa, - std::placeholders::_1 ) ) ) { - return _( "Superior version installed." ); - } else if( pa.is_npc() && !bid->has_flag( json_flag_BIONIC_NPC_USABLE ) ) { - return _( "CBM not compatible with patient." ); - } else if( units::energy_max - pa.get_max_power_level() < bid->capacity ) { - return _( "Max power capacity already reached." ); - } else if( !p.has_enough_anesth( *itemtype, pa ) ) { + const ret_val installable = pa.is_installable( loc, true ); + if( installable.success() && !p.has_enough_anesth( *loc.get_item()->type, pa ) ) { const int weight = units::to_kilogram( pa.bodyweight() ) / 10; const int duration = loc.get_item()->type->bionic->difficulty * 2; const requirement_data req_anesth = *requirement_id( "anesthetic" ) * duration * weight; return string_format( _( "%i mL" ), req_anesth.get_tools().front().front().count ); + } else if( !installable.success() ) { + return installable.str(); } return std::string(); @@ -1929,32 +1901,8 @@ class bionic_install_surgeon_preset : public inventory_selector_preset } std::string get_denial( const item_location &loc ) const override { - const item *it = loc.get_item(); - const itype *itemtype = it->type; - const bionic_id &bid = itemtype->bionic->id; - - if( it->has_flag( flag_FILTHY ) ) { - return _( "CBM is filthy." ); - } else if( it->has_flag( flag_NO_STERILE ) ) { - return _( "CBM is not sterile." ); - } else if( it->has_fault( fault_bionic_salvaged ) ) { - return _( "CBM is already deployed." ); - } else if( pa.has_bionic( bid ) ) { - return _( "CBM is already installed." ); - } else if( bid->upgraded_bionic && - !pa.has_bionic( bid->upgraded_bionic ) && - it->is_upgrade() ) { - return _( "No base version installed." ); - } else if( std::any_of( bid->available_upgrades.begin(), - bid->available_upgrades.end(), - std::bind( &player::has_bionic, &pa, - std::placeholders::_1 ) ) ) { - return _( "Superior version installed." ); - } else if( pa.is_npc() && !bid->has_flag( json_flag_BIONIC_NPC_USABLE ) ) { - return _( "CBM is not compatible with patient." ); - } - - return std::string(); + const ret_val installable = pa.is_installable( loc, false ); + return installable.str(); } protected: diff --git a/src/mutation.cpp b/src/mutation.cpp index c8229f05af92d..3824b264a35ac 100644 --- a/src/mutation.cpp +++ b/src/mutation.cpp @@ -854,6 +854,10 @@ bool Character::mutation_ok( const trait_id &mutation, bool force_good, bool for return false; } } + + if( bid->mutation_conflicts.count( mutation ) != 0 ) { + return false; + } } const mutation_branch &mdata = mutation.obj(); @@ -1182,6 +1186,14 @@ bool Character::mutate_towards( const trait_id &mut ) return false; } + // Just prevent it when it conflicts with a CBM, for now + // TODO: Consequences? + for( const bionic_id &bid : get_bionics() ) { + if( bid->mutation_conflicts.count( mut ) != 0 ) { + return false; + } + } + for( size_t i = 0; !has_threshreq && i < threshreq.size(); i++ ) { if( has_trait( threshreq[i] ) ) { has_threshreq = true; From b48c33e7b87a0181de77c0ec2bbc7c093ef5b75f Mon Sep 17 00:00:00 2001 From: Anton Burmistrov Date: Mon, 15 Mar 2021 00:49:21 +0400 Subject: [PATCH 052/453] Spiral mine jsonify (#48003) --- .../furniture_and_terrain/terrain-walls.json | 20 ++ data/json/mapgen/mine/mine_shaft.json | 20 +- data/json/mapgen/mine/mine_spiral.json | 190 ++++++++++++++++++ data/json/mapgen/nested/mine_nested.json | 76 +++++++ data/json/npcs/mine/spiral_madman.json | 126 ++++++++++++ data/json/npcs/talk_tags.json | 16 ++ data/json/obsolete_terrains.json | 4 +- data/json/overmap/overmap_special/mine.json | 63 ++++++ .../overmap_terrain_hardcoded.json | 18 -- .../overmap_terrain_industrial.json | 25 +++ .../go_overmap_terrain_hardcoded.json | 24 +-- data/mods/alt_map_key/overmap_terrain.json | 16 -- src/map.h | 1 - src/mapgen.cpp | 97 +-------- src/overmap.cpp | 11 +- 15 files changed, 546 insertions(+), 161 deletions(-) create mode 100644 data/json/mapgen/mine/mine_spiral.json create mode 100644 data/json/mapgen/nested/mine_nested.json create mode 100644 data/json/npcs/mine/spiral_madman.json create mode 100644 data/json/overmap/overmap_special/mine.json diff --git a/data/json/furniture_and_terrain/terrain-walls.json b/data/json/furniture_and_terrain/terrain-walls.json index 69cc70c69b254..34759ba834000 100644 --- a/data/json/furniture_and_terrain/terrain-walls.json +++ b/data/json/furniture_and_terrain/terrain-walls.json @@ -1482,5 +1482,25 @@ "ter_set": "t_null", "items": [ { "item": "rock", "count": [ 3, 8 ] }, { "item": "pebble", "count": [ 20, 38 ] } ] } + }, + { + "type": "terrain", + "id": "t_pillar", + "name": "pillar", + "looks_like": "t_column", + "description": "A concrete column that helps keep the mine's ceiling and walls from collapsing.", + "symbol": "1", + "color": "light_gray", + "move_cost": 0, + "coverage": 80, + "flags": [ "WALL", "PERMEABLE", "MINEABLE" ], + "bash": { + "str_min": 120, + "str_max": 200, + "sound": "crash!", + "sound_fail": "whump!", + "ter_set": "t_reb_cage", + "items": [ { "item": "rock", "count": [ 10, 22 ] } ] + } } ] diff --git a/data/json/mapgen/mine/mine_shaft.json b/data/json/mapgen/mine/mine_shaft.json index 3d56375160457..8fee0022eb3de 100644 --- a/data/json/mapgen/mine/mine_shaft.json +++ b/data/json/mapgen/mine/mine_shaft.json @@ -43,28 +43,28 @@ "rows": [ "###### ## #################### #######", "###### ## ################### ########", - "###### ## ############# #### #########", + "######№ ## №############# #### #########", "####### ############### ### ##########", "######## ############### ## ###########", "######## ############## ############", " ###### ################ ##########", - " ## ################# ###########", - "# ##### ###### ###########", + " ##№ ################# ###########", + "# №##### №###### ###########", " #### ## ", "###### ### #### #### ", "###### |-| #### ##### ", "###### |----|<|--| ", "##### |!@@...!@@| #### #####", - "### |.@@....@@| ######### ######", + "###№ |.@@....@@| ######### ######", " +.......@@| ########## ######", "*****************=========| # ######## ####", - " +.......®®| ####### ####", + " +.......®®| №####### ####", " |.........| ######### ####", "# |.........| ######### #", - "## |LLLL|SSSS| ######### #", - "#### |----|----| ######## #", + "## |LLLL|SSSS| №######### #", + "####№ |----|----| ######## #", "###### ######### ", - "####### ## ####### ######## " + "####### ## №####### ######## " ], "terrain": { "<": "t_ladder_up", @@ -78,6 +78,7 @@ "=": "t_conveyor", "*": "t_railroad_track_small", "®": "t_thconc_floor", + "№": "t_pillar", "L": "t_thconc_floor", "S": "t_thconc_floor" }, @@ -86,7 +87,8 @@ "L": [ { "item": "clothing_work_set", "chance": 50 }, { "item": "hardware_clothing", "chance": 50 } ], "S": { "item": "mine_equipment", "chance": 80 } }, - "place_vehicles": [ { "vehicle": "trolley", "x": 10, "y": 16, "chance": 100, "status": 0 } ] + "place_vehicles": [ { "vehicle": "trolley", "x": 10, "y": 16, "chance": 100, "status": 0 } ], + "monsters": { " ": { "monster": "GROUP_MINER", "chance": 1, "density": 0.0005 } } } } ] diff --git a/data/json/mapgen/mine/mine_spiral.json b/data/json/mapgen/mine/mine_spiral.json new file mode 100644 index 0000000000000..e69daee9f44c2 --- /dev/null +++ b/data/json/mapgen/mine/mine_spiral.json @@ -0,0 +1,190 @@ +[ + { + "type": "monstergroup", + "name": "GROUP_MINER", + "default": "mon_zombie_miner", + "monsters": [ ] + }, + { + "type": "mapgen", + "method": "json", + "om_terrain": [ [ "mine_spiral_west", "mine_spiral_central", "mine_spiral_east" ] ], + "object": { + "fill_ter": "t_rock_floor", + "rows": [ + "########################################################################", + "@@@@@@@@@@@@@@@@@@@@@@@@@###############################################", + "@ @###############################################", + "@ ##################### @###############################################", + "@ #@@@@@@@@@@@@@@@@@@@# @###############################################", + "@ #@ @# @###############################################", + "@ #@ ############### @# @###############################################", + "@ #@ #@@@@@@@@@@@### @# @###############################################", + "@ #@ #@ ># @# @###############################################", + "@ #@ #@ @@@@@@@@@### @# @###############################################", + "@ #@ #@ ############ @# @###############################################", + "@ #@ #@ @# @###############################################", + "@ #@ #@@@@@@@@@@@@@@@@# @#####################@@@@@@@@@@@@@@@@@@@@@@@@@@", + "@ #@ ################## @#####################! @@@@@@@@@@@!@@@@@@@@@@ !", + "@ #@ @##################### ", + "@ #@@@@@@@@@@@@@@@@########################### ", + "@ ############################################**************************", + "@ @@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@## #### ", + "@ # ## ", + "@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@##### ! @@@@@@@@@@!@@@@@@@@@@ !", + "###############################################@@@@@@@@@@@@@@@@@@@@@@@@@", + "########################################################################", + "########################################################################", + "########################################################################" + ], + "terrain": { + "@": [ [ "t_rock", 4 ], [ "t_rock_floor", 1 ] ], + "#": "t_rock", + "*": "t_railroad_track_small", + "!": "t_pillar", + ">": "t_slope_down" + }, + "items": { " ": { "item": "mine_equipment", "chance": 1 } }, + "monsters": { " ": { "monster": "GROUP_MINER", "chance": 1, "density": 0.001 } } + } + }, + { + "type": "mapgen", + "method": "json", + "om_terrain": [ + [ "mine_spiral_-1_nw", "mine_spiral_-1_n", "mine_spiral_-1_ne" ], + [ "mine_spiral_-1_sw", "mine_spiral_-1_s", "mine_spiral_-1_se" ] + ], + "object": { + "fill_ter": "t_rock_floor", + "rows": [ + "####################################@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@", + "####################################@ @", + "########@@@@@@@@@@@@@@@@@@@@@@@@@@@@@ 1 1 ###### @", + "########@ # @", + "########@ @@@@@@@@@@@@@@@@@@@@@@@@@@@ # #### @", + "########@ @##################@######@ # #~ # @", + "########@ @# @######@ # # @", + "########@ @# @@@@@@@@@@@@@@@ @######@ ###### @", + "########@ @# @#############@ @######@ @", + "########@ @# @####< #@ @######@ @", + "########@ @# @########### #@ @######@ @", + "########@ @# @@@@@@@@@@@@ #@ @######@ 1 1 1 @", + "########@ @# #@ @######@ @", + "########@ @################@ @######@ @", + "########@ @@@@@@@@@@@@@@@@@@ @######@ @", + "########@ @######@ @", + "########@@@@@@@@@@@@@@@@@@@@@@######@ @", + "####################################@ @", + "####################################@@@@@@@@@@@@@@@@@@@@@@@ @", + "##########################################################@ @", + "##########################################################@ @", + "#####@@@@@@@@@@@@@@@@@@####@@@@@@@@@@@@@@@@@@@############@ @", + "##### #### @############@ @", + "##### #### #### #### ############@ @", + "#####%%%%%%######%%%%%%####!!!!!!######$$$$$$ ############@ @", + "#####% ###### %####! ##### $ ############@ @", + "#####% %%%%######%%%% %####! !!!!##### $$$$ $ ############@ @", + "#####% % %######% % %####! ! !##### $ >$ $ ############@ @", + "#####% %######% %####! !##### $ $ ############@ @", + "#####%%%%%%######%%%%%%####!!!!!!##### $$$$$$ ############@ @", + "#### ###### ## ##### ############@ @", + "### ###### @####@ @############@ @", + "#@ @@@@@@@######@@@@@@@@@@@@@@@@@####@@@@@@@@############@ @", + "#@ @#####################################################@ @", + "#@ @####################################################### @", + "#@ @@@@@@@######@@@@@@@@@@@@@@@@######@@@@@@@@@@@@@@@@@@@### @", + "### ###### ###### ## @", + "#### ###### ## ###### ### #### ##", + "##### ###### #### ###### ##### ###### ###", + "#####^^^^^^######^^^^^^####&&&&&&######&&&&&&######******######******###", + "#####^ ###### ^####& ###### &######* ###### *###", + "#####^ ^^^^######^^^^ ^####& &&&&######&&&& &######* ****######**** *###", + "#####^ ^ ^######^ ^ ^####& & &######& & &######* * *######* * *###", + "#####^ ^######^ ^####& &######& &######* *######* *###", + "#####^^^^^^######^^^^^^####&&&&&&######&&&&&&######******######******###", + "##### #### #### #### ###### ###### ###", + "##### @##@ @####@ ###", + "#####@@@@@@@@@@@@@@@@@@@##@@@@@@@@@@@@@@@@@@@@####@@@@@@@@@@@@@@@@@@@###" + ], + "terrain": { + "@": [ [ "t_rock", 4 ], [ "t_rock_floor", 1 ] ], + "#": "t_rock", + ">": "t_slope_down", + "<": "t_slope_up", + "$": "t_lava" + }, + "furniture": { "&": "f_wreckage", "^": "f_rubble", "%": "f_rubble_rock", "!": "f_rubble_landfill" }, + "nested": { + "1": { "chunks": [ [ "spiral_cw", 25 ], [ "spiral_ccw", 25 ], [ "spiral_boulder_cw", 25 ], [ "spiral_boulder_ccw", 25 ] ] } + }, + "item": { "*": { "item": "rock", "chance": 100 } }, + "npcs": { "~": { "class": "spiral_madman" } } + } + }, + { + "type": "mapgen", + "method": "json", + "om_terrain": [ + [ "mine_spiral_finale_nw", "mine_spiral_finale_n", "mine_spiral_finale_ne" ], + [ "mine_spiral_finale_sw", "mine_spiral_finale_s", "mine_spiral_finale_se" ] + ], + "object": { + "fill_ter": "t_rock_floor", + "rows": [ + "###### 1 1 1 1 1 1 1 1 ", + "# ", + "# #### ", + "# #! # ", + "# # ", + "###### ", + " ", + " ###### ", + " # ", + " #### # ", + " # !# # ", + " # # ", + " ###### ", + " ", + "###### 1 1 1 1 1 1 ###### ", + "# # ", + "# #### #### # ", + "# #! # # # # ", + "# # # # ", + "###### ###### ", + " ", + "###### ###### ###### ", + "# # # ", + "# #### #### # #### # ", + "# # # # !# # # # # ", + "# # # # # # ", + "###### ###### ###### ", + " < ", + "###### 1 ###### 1 1 1 ###### ", + "# # # ", + "# #### # #### #### # ", + "# #! # # #! # # # # ", + "# # # # # # ", + "###### ###### ###### ", + " ", + "###### ###### ", + "# # ", + "# #### #### # ", + "# # # # !# # ", + "# # # # ", + "###### ###### ", + " ", + "###### 1 1 1 1 1 1 1 1 ", + "# ", + "# #### ", + "# #! # ", + "# # ", + "###### " + ], + "terrain": { "@": [ [ "t_rock", 4 ], [ "t_rock_floor", 1 ] ], "#": "t_rock", "<": "t_slope_up" }, + "monsters": { " ": { "monster": "GROUP_SPIRAL", "chance": 1, "density": 0.001 } }, + "nested": { "1": { "chunks": [ [ "spiral_cw", 50 ], [ "spiral_ccw", 50 ] ] } }, + "items": { "!": { "item": "spiral", "chance": 60 } } + } + } +] diff --git a/data/json/mapgen/nested/mine_nested.json b/data/json/mapgen/nested/mine_nested.json new file mode 100644 index 0000000000000..ee70e895db90f --- /dev/null +++ b/data/json/mapgen/nested/mine_nested.json @@ -0,0 +1,76 @@ +[ + { + "type": "palette", + "id": "mine_palette", + "terrain": { "#": "t_rock", " ": "t_rock_floor", "$": "t_rock_floor" }, + "furniture": { "$": "f_boulder_large" } + }, + { + "type": "mapgen", + "method": "json", + "nested_mapgen_id": "spiral_cw", + "object": { + "palettes": [ "mine_palette" ], + "mapgensize": [ 6, 6 ], + "rows": [ + "######", + " #", + "#### #", + "# # #", + "# #", + "######" + ] + } + }, + { + "type": "mapgen", + "method": "json", + "nested_mapgen_id": "spiral_ccw", + "object": { + "palettes": [ "mine_palette" ], + "mapgensize": [ 6, 6 ], + "rows": [ + "######", + "# ", + "# ####", + "# # #", + "# #", + "######" + ] + } + }, + { + "type": "mapgen", + "method": "json", + "nested_mapgen_id": "spiral_boulder_cw", + "object": { + "palettes": [ "mine_palette" ], + "mapgensize": [ 6, 6 ], + "rows": [ + "$$$$$$", + " $", + "$$$$ $", + "$ $ $", + "$ $", + "$$$$$$" + ] + } + }, + { + "type": "mapgen", + "method": "json", + "nested_mapgen_id": "spiral_boulder_ccw", + "object": { + "palettes": [ "mine_palette" ], + "mapgensize": [ 6, 6 ], + "rows": [ + "$$$$$$", + "$ ", + "$ $$$$", + "$ $ $", + "$ $", + "$$$$$$" + ] + } + } +] diff --git a/data/json/npcs/mine/spiral_madman.json b/data/json/npcs/mine/spiral_madman.json new file mode 100644 index 0000000000000..5a130d2345717 --- /dev/null +++ b/data/json/npcs/mine/spiral_madman.json @@ -0,0 +1,126 @@ +[ + { + "type": "npc", + "id": "spiral_madman", + "//": "Former miner, poor fellow succumbed to spiral madness.", + "name_suffix": "miner", + "class": "NC_SPIRAL_MADMAN", + "attitude": 0, + "mission": 8, + "chat": "TALK_SPIRAL_MADMAN_FIRST_MEETING", + "faction": "no_faction" + }, + { + "type": "npc_class", + "id": "NC_SPIRAL_MADMAN", + "name": { "str": "Miner" }, + "job_description": "Spirals.", + "traits": [ { "group": "NPC_starting_traits" }, { "group": "Appearance_demographics" } ], + "bonus_str": { "rng": [ 2, 4 ] }, + "bonus_dex": { "rng": [ 0, 2 ] }, + "worn_override": "NC_SPIRAL_MADMAN_worn", + "weapon_override": "NC_SPIRAL_MADMAN_wield" + }, + { + "type": "item_group", + "id": "NC_SPIRAL_MADMAN_worn", + "subtype": "collection", + "entries": [ + { "group": "clothing_work_boots", "damage": [ 0, 2 ] }, + { "group": "clothing_work_glasses", "prob": 60, "damage": [ 0, 2 ] }, + { "group": "clothing_work_gloves", "prob": 75, "damage": [ 0, 2 ] }, + { "group": "clothing_work_mask", "prob": 40, "damage": [ 0, 2 ] }, + { "item": "ear_plugs", "prob": 15, "damage": [ 0, 2 ] }, + { "item": "tool_belt", "prob": 25, "damage": [ 0, 2 ] }, + { + "distribution": [ + { + "collection": [ { "group": "clothing_work_pants", "damage": [ 0, 2 ] }, { "group": "clothing_work_torso", "damage": [ 0, 2 ] } ], + "prob": 75 + }, + { "item": "jumpsuit", "prob": 25, "damage": [ 0, 2 ] } + ] + }, + { "group": "underwear", "damage": [ 0, 1 ] }, + { "item": "miner_hat", "prob": 90, "damage": [ 0, 2 ] } + ] + }, + { + "type": "item_group", + "id": "NC_SPIRAL_MADMAN_wield", + "items": [ + [ "pickaxe", 50 ], + [ "shovel", 50 ], + [ "bucket", 20 ], + [ "gasoline_lantern", 10 ], + [ "electric_lantern", 10 ], + [ "oil_lamp", 10 ], + [ "jackhammer", 5 ], + [ "elec_jackhammer", 5 ] + ] + }, + { + "id": "TALK_SPIRAL_MADMAN_FIRST_MEETING", + "type": "talk_topic", + "dynamic_line": "Spirals?", + "speaker_effect": { "effect": { "u_add_var": "first_meeting", "type": "dialogue", "context": "first_meeting", "value": "yes" } }, + "responses": [ + { + "text": "Hello there!", + "topic": "TALK_SPIRAL_MADMAN_GENERIC", + "condition": { "not": { "u_has_var": "first_meeting", "type": "dialogue", "context": "first_meeting", "value": "yes" } } + }, + { + "text": "I'm outta here. Bye.", + "topic": "TALK_DONE", + "condition": { "not": { "u_has_var": "first_meeting", "type": "dialogue", "context": "first_meeting", "value": "yes" } } + }, + { + "text": "Poor fellow - looks like you're out of your mind. Can't help you, sorry. I'm outta here. Bye.", + "topic": "TALK_DONE", + "condition": { "u_has_var": "first_meeting", "type": "dialogue", "context": "first_meeting", "value": "yes" } + } + ] + }, + { + "id": "TALK_SPIRAL_MADMAN_GENERIC", + "type": "talk_topic", + "dynamic_line": "", + "responses": [ + { "text": "What are you doing here?", "topic": "TALK_SPIRAL_MADMAN_SPIRALS" }, + { "text": "Sorry, what?", "topic": "TALK_SPIRAL_MADMAN_SPIRALS" }, + { "text": "I'm outta here. Bye.", "topic": "TALK_DONE" } + ] + }, + { + "id": "TALK_SPIRAL_MADMAN_SPIRALS", + "type": "talk_topic", + "dynamic_line": "", + "responses": [ + { "text": "Why are you repeating 'spirals' over and over again?", "topic": "TALK_SPIRAL_MADMAN_R_U_NUTS" }, + { "text": "Sorry, what?", "topic": "TALK_SPIRAL_MADMAN_R_U_NUTS" }, + { "text": "I'm outta here. Bye.", "topic": "TALK_DONE" } + ] + }, + { + "id": "TALK_SPIRAL_MADMAN_R_U_NUTS", + "type": "talk_topic", + "dynamic_line": "", + "responses": [ + { "text": "Are you nuts?", "topic": "TALK_SPIRAL_MADMAN_THIS_IS_MADNESS" }, + { "text": "Sorry, what?", "topic": "TALK_SPIRAL_MADMAN_THIS_IS_MADNESS" }, + { "text": "I'm outta here. Bye.", "topic": "TALK_DONE" } + ] + }, + { + "id": "TALK_SPIRAL_MADMAN_THIS_IS_MADNESS", + "type": "talk_topic", + "dynamic_line": "", + "responses": [ + { + "text": "Poor fellow - looks like you're out of your mind. Can't help you, sorry. I'm outta here. Bye.", + "topic": "TALK_DONE" + } + ] + } +] diff --git a/data/json/npcs/talk_tags.json b/data/json/npcs/talk_tags.json index a75f1f17c1ee8..148a71851d38e 100644 --- a/data/json/npcs/talk_tags.json +++ b/data/json/npcs/talk_tags.json @@ -1,4 +1,20 @@ [ + { + "type": "snippet", + "category": "", + "//": "Spiral madman's responses.", + "text": [ + "Spirals.", + "Spirals…", + "Spirals?", + "Spirals!", + "Spirals!!!", + "SpIrAlS.", + "SPIRALS.", + "AHAHAHAHA!!!", + "SpiRAAAAAAALS!" + ] + }, { "type": "snippet", "category": "", diff --git a/data/json/obsolete_terrains.json b/data/json/obsolete_terrains.json index 9d6f430d64b54..dc517d80da30e 100644 --- a/data/json/obsolete_terrains.json +++ b/data/json/obsolete_terrains.json @@ -25,7 +25,9 @@ "office_tower_b_entrance", "office_tower_b", "mine_entrance", - "mine_shaft" + "mine_shaft", + "spiral", + "spiral_hub" ] } ] diff --git a/data/json/overmap/overmap_special/mine.json b/data/json/overmap/overmap_special/mine.json new file mode 100644 index 0000000000000..d409849534a0e --- /dev/null +++ b/data/json/overmap/overmap_special/mine.json @@ -0,0 +1,63 @@ +[ + { + "type": "overmap_special", + "id": "Mine Entrance", + "overmaps": [ + { "point": [ 0, 0, 0 ], "overmap": "s_lot_north" }, + { "point": [ 0, 1, 0 ], "overmap": "mine_entrance_north" }, + { "point": [ 1, 1, 0 ], "overmap": "mine_entrance_loading_zone_north" }, + { "point": [ 1, 0, 0 ], "overmap": "road_end_north" }, + { "point": [ 0, 1, 1 ], "overmap": "mine_entrance_roof_north" }, + { "point": [ 0, 1, -1 ], "overmap": "mine_shaft_middle_north" }, + { "point": [ 0, 1, -2 ], "overmap": "mine_shaft_lower_north" }, + { "point": [ 1, 1, -2 ], "overmap": "mine_shaft_lower_east_north" } + ], + "connections": [ + { "point": [ 0, -1, 0 ], "terrain": "road", "connection": "local_road", "from": [ 0, 0, 0 ] }, + { "point": [ 1, -1, 0 ], "terrain": "road", "connection": "local_road", "from": [ 1, 0, 0 ] } + ], + "locations": [ "wilderness" ], + "city_distance": [ 10, 40 ], + "city_sizes": [ 4, -1 ], + "occurrences": [ 0, 2 ], + "flags": [ "WILDERNESS" ] + }, + { + "type": "overmap_special", + "id": "Spiral mine", + "overmaps": [ + { "point": [ 0, 0, 0 ], "overmap": "s_lot_north" }, + { "point": [ 0, 1, 0 ], "overmap": "mine_entrance_north" }, + { "point": [ 1, 1, 0 ], "overmap": "mine_entrance_loading_zone_north" }, + { "point": [ 1, 0, 0 ], "overmap": "road_end_north" }, + { "point": [ 0, 1, 1 ], "overmap": "mine_entrance_roof_north" }, + { "point": [ 0, 1, -1 ], "overmap": "mine_shaft_middle_north" }, + { "point": [ 0, 1, -2 ], "overmap": "mine_shaft_lower_north" }, + { "point": [ 1, 1, -2 ], "overmap": "mine_shaft_lower_east_north" }, + { "point": [ -1, 1, -2 ], "overmap": "mine_spiral_east_north" }, + { "point": [ -2, 1, -2 ], "overmap": "mine_spiral_central_north" }, + { "point": [ -3, 1, -2 ], "overmap": "mine_spiral_west_north" }, + { "point": [ -3, 1, -3 ], "overmap": "mine_spiral_-1_nw_north" }, + { "point": [ -2, 1, -3 ], "overmap": "mine_spiral_-1_n_north" }, + { "point": [ -1, 1, -3 ], "overmap": "mine_spiral_-1_ne_north" }, + { "point": [ -3, 2, -3 ], "overmap": "mine_spiral_-1_sw_north" }, + { "point": [ -2, 2, -3 ], "overmap": "mine_spiral_-1_s_north" }, + { "point": [ -1, 2, -3 ], "overmap": "mine_spiral_-1_se_north" }, + { "point": [ -3, 1, -4 ], "overmap": "mine_spiral_finale_nw_north" }, + { "point": [ -2, 1, -4 ], "overmap": "mine_spiral_finale_n_north" }, + { "point": [ -1, 1, -4 ], "overmap": "mine_spiral_finale_ne_north" }, + { "point": [ -3, 2, -4 ], "overmap": "mine_spiral_finale_sw_north" }, + { "point": [ -2, 2, -4 ], "overmap": "mine_spiral_finale_s_north" }, + { "point": [ -1, 2, -4 ], "overmap": "mine_spiral_finale_se_north" } + ], + "connections": [ + { "point": [ 0, -1, 0 ], "terrain": "road", "connection": "local_road", "from": [ 0, 0, 0 ] }, + { "point": [ 1, -1, 0 ], "terrain": "road", "connection": "local_road", "from": [ 1, 0, 0 ] } + ], + "locations": [ "wilderness" ], + "city_distance": [ 10, 40 ], + "city_sizes": [ 4, -1 ], + "occurrences": [ 0, 2 ], + "flags": [ "WILDERNESS" ] + } +] diff --git a/data/json/overmap/overmap_terrain/overmap_terrain_hardcoded.json b/data/json/overmap/overmap_terrain/overmap_terrain_hardcoded.json index 9135c4c7402d7..a47b500821000 100644 --- a/data/json/overmap/overmap_terrain/overmap_terrain_hardcoded.json +++ b/data/json/overmap/overmap_terrain/overmap_terrain_hardcoded.json @@ -130,24 +130,6 @@ "see_cost": 2, "flags": [ "NO_ROTATE" ] }, - { - "type": "overmap_terrain", - "id": "spiral_hub", - "name": "spiral cavern", - "sym": "@", - "color": "pink", - "see_cost": 2, - "flags": [ "NO_ROTATE" ] - }, - { - "type": "overmap_terrain", - "id": "spiral", - "name": "spiral cavern", - "sym": "@", - "color": "pink", - "see_cost": 2, - "flags": [ "NO_ROTATE" ] - }, { "type": "overmap_terrain", "id": "cave", diff --git a/data/json/overmap/overmap_terrain/overmap_terrain_industrial.json b/data/json/overmap/overmap_terrain/overmap_terrain_industrial.json index 4b946bab6f2a4..69511469ecc81 100644 --- a/data/json/overmap/overmap_terrain/overmap_terrain_industrial.json +++ b/data/json/overmap/overmap_terrain/overmap_terrain_industrial.json @@ -392,5 +392,30 @@ "color": "dark_gray", "see_cost": 5, "flags": [ "KNOWN_UP" ] + }, + { + "type": "overmap_terrain", + "id": [ + "mine_spiral_west", + "mine_spiral_central", + "mine_spiral_east", + "mine_spiral_-1_nw", + "mine_spiral_-1_n", + "mine_spiral_-1_ne", + "mine_spiral_-1_sw", + "mine_spiral_-1_s", + "mine_spiral_-1_se", + "mine_spiral_finale_nw", + "mine_spiral_finale_n", + "mine_spiral_finale_ne", + "mine_spiral_finale_sw", + "mine_spiral_finale_s", + "mine_spiral_finale_se" + ], + "name": "mine tunnels", + "sym": "O", + "color": "dark_gray", + "see_cost": 5, + "flags": [ "KNOWN_UP" ] } ] diff --git a/data/mods/Graphical_Overmap/go_overmap_terrain_hardcoded.json b/data/mods/Graphical_Overmap/go_overmap_terrain_hardcoded.json index cabc893f2281c..b191a9c5b5643 100644 --- a/data/mods/Graphical_Overmap/go_overmap_terrain_hardcoded.json +++ b/data/mods/Graphical_Overmap/go_overmap_terrain_hardcoded.json @@ -91,33 +91,33 @@ }, { "type": "overmap_terrain", - "id": "mine", - "copy-from": "mine", + "id": "mine_shaft_middle", + "copy-from": "mine_shaft_middle", "sym": "\u00D3" }, { "type": "overmap_terrain", - "id": "mine_down", - "copy-from": "mine_down", + "id": "mine_shaft_lower", + "copy-from": "mine_shaft_lower", "sym": "\u00D3" }, { "type": "overmap_terrain", - "id": "mine_finale", - "copy-from": "mine_finale", + "id": "mine", + "copy-from": "mine", "sym": "\u00D3" }, { "type": "overmap_terrain", - "id": "spiral_hub", - "copy-from": "spiral_hub", - "sym": "\u00EA" + "id": "mine_down", + "copy-from": "mine_down", + "sym": "\u00D3" }, { "type": "overmap_terrain", - "id": "spiral", - "copy-from": "spiral", - "sym": "\u00EA" + "id": "mine_finale", + "copy-from": "mine_finale", + "sym": "\u00D3" }, { "type": "overmap_terrain", diff --git a/data/mods/alt_map_key/overmap_terrain.json b/data/mods/alt_map_key/overmap_terrain.json index b36f4871df532..964abdde3832b 100644 --- a/data/mods/alt_map_key/overmap_terrain.json +++ b/data/mods/alt_map_key/overmap_terrain.json @@ -1873,22 +1873,6 @@ "sym": "M", "color": "i_black" }, - { - "type": "overmap_terrain", - "id": "spiral_hub", - "copy-from": "spiral_hub", - "name": "spiral cavern", - "sym": "@", - "color": "pink" - }, - { - "type": "overmap_terrain", - "id": "spiral", - "copy-from": "spiral", - "name": "spiral cavern", - "sym": "@", - "color": "pink" - }, { "type": "overmap_terrain", "id": "radio_tower", diff --git a/src/map.h b/src/map.h index 517c724753382..11a3728a1cd5d 100644 --- a/src/map.h +++ b/src/map.h @@ -1644,7 +1644,6 @@ class map void draw_lab( mapgendata &dat ); void draw_temple( const mapgendata &dat ); void draw_mine( mapgendata &dat ); - void draw_spiral( const mapgendata &dat ); void draw_anthill( const mapgendata &dat ); void draw_slimepit( const mapgendata &dat ); void draw_spider_pit( const mapgendata &dat ); diff --git a/src/mapgen.cpp b/src/mapgen.cpp index f71fed4becd0e..1517e3a0e57a0 100644 --- a/src/mapgen.cpp +++ b/src/mapgen.cpp @@ -2968,8 +2968,6 @@ void map::draw_map( mapgendata &dat ) draw_triffid( dat ); } else if( is_ot_match( "spider", terrain_type, ot_match_type::prefix ) ) { draw_spider_pit( dat ); - } else if( is_ot_match( "spiral", terrain_type, ot_match_type::prefix ) ) { - draw_spiral( dat ); } else if( is_ot_match( "temple", terrain_type, ot_match_type::prefix ) ) { draw_temple( dat ); } else if( is_ot_match( "mine", terrain_type, ot_match_type::prefix ) ) { @@ -4381,20 +4379,6 @@ void map::draw_mine( mapgendata &dat ) } } break; - - case 6: { // Spiral - const int orx = rng( SEEX - 4, SEEX ), ory = rng( SEEY - 4, SEEY ); - line( this, t_rock, point( orx, ory ), point( orx + 5, ory ) ); - line( this, t_rock, point( orx + 5, ory ), point( orx + 5, ory + 5 ) ); - line( this, t_rock, point( orx + 1, ory + 5 ), point( orx + 5, ory + 5 ) ); - line( this, t_rock, point( orx + 1, ory + 2 ), point( orx + 1, ory + 4 ) ); - line( this, t_rock, point( orx + 1, ory + 2 ), point( orx + 3, ory + 2 ) ); - ter_set( point( orx + 3, ory + 3 ), t_rock ); - add_item( point( orx + 2, ory + 3 ), item::make_corpse() ); - place_items( item_group_id( "mine_equipment" ), 60, point( orx + 2, ory + 3 ), - point( orx + 2, ory + 3 ), false, calendar::start_of_cataclysm ); - } - break; } if( terrain_type == "mine_down" ) { // Don't forget to build a slope down! @@ -4560,9 +4544,9 @@ void map::draw_mine( mapgendata &dat ) // Now, pick and generate a type of finale! int rn = 0; if( face.empty() ) { - rn = rng( 1, 3 ); // Amigara fault is not valid + rn = rng( 1, 2 ); // Amigara fault is not valid } else { - rn = rng( 1, 4 ); + rn = rng( 1, 3 ); } computer *tmpcomp = nullptr; @@ -4589,25 +4573,7 @@ void map::draw_mine( mapgendata &dat ) } break; - case 3: { // Spiral down - line( this, t_rock, point( 5, 5 ), point( 5, 18 ) ); - line( this, t_rock, point( 5, 5 ), point( 18, 5 ) ); - line( this, t_rock, point( 18, 5 ), point( 18, 18 ) ); - line( this, t_rock, point( 8, 18 ), point( 18, 18 ) ); - line( this, t_rock, point( 8, 8 ), point( 8, 18 ) ); - line( this, t_rock, point( 8, 8 ), point( 15, 8 ) ); - line( this, t_rock, point( 15, 8 ), point( 15, 15 ) ); - line( this, t_rock, point( 10, 15 ), point( 15, 15 ) ); - line( this, t_rock, point( 10, 10 ), point( 10, 15 ) ); - line( this, t_rock, point( 10, 10 ), point( 13, 10 ) ); - line( this, t_rock, point( 13, 10 ), point( 13, 13 ) ); - ter_set( point( 12, 13 ), t_rock ); - ter_set( point( 12, 12 ), t_slope_down ); - ter_set( point( 12, 11 ), t_slope_down ); - } - break; - - case 4: { // Amigara fault + case 3: { // Amigara fault // Construct the fault on the appropriate face switch( random_entry( face ) ) { case direction::NORTH: @@ -4642,63 +4608,6 @@ void map::draw_mine( mapgendata &dat ) } } -void map::draw_spiral( const mapgendata &dat ) -{ - const oter_id &terrain_type = dat.terrain_type(); - if( terrain_type == "spiral_hub" ) { - fill_background( this, t_rock_floor ); - line( this, t_rock, point( 23, 0 ), point( 23, 23 ) ); - line( this, t_rock, point( 2, 23 ), point( 23, 23 ) ); - line( this, t_rock, point( 2, 4 ), point( 2, 23 ) ); - line( this, t_rock, point( 2, 4 ), point( 18, 4 ) ); - line( this, t_rock, point( 18, 4 ), point( 18, 18 ) ); // bad - line( this, t_rock, point( 6, 18 ), point( 18, 18 ) ); - line( this, t_rock, point( 6, 7 ), point( 6, 18 ) ); - line( this, t_rock, point( 6, 7 ), point( 15, 7 ) ); - line( this, t_rock, point( 15, 7 ), point( 15, 15 ) ); - line( this, t_rock, point( 8, 15 ), point( 15, 15 ) ); - line( this, t_rock, point( 8, 9 ), point( 8, 15 ) ); - line( this, t_rock, point( 8, 9 ), point( 13, 9 ) ); - line( this, t_rock, point( 13, 9 ), point( 13, 13 ) ); - line( this, t_rock, point( 10, 13 ), point( 13, 13 ) ); - line( this, t_rock, point( 10, 11 ), point( 10, 13 ) ); - square( this, t_slope_up, point( 11, 11 ), point( 12, 12 ) ); - rotate( rng( 0, 3 ) ); - } else if( terrain_type == "spiral" ) { - fill_background( this, t_rock_floor ); - const int num_spiral = rng( 1, 4 ); - std::list offsets; - const int spiral_width = 8; - // Divide the room into quadrants, and place a spiral origin - // at a random offset within each quadrant. - for( int x = 0; x < 2; ++x ) { - for( int y = 0; y < 2; ++y ) { - const int x_jitter = rng( 0, SEEX - spiral_width ); - const int y_jitter = rng( 0, SEEY - spiral_width ); - offsets.push_back( point( ( x * SEEX ) + x_jitter, - ( y * SEEY ) + y_jitter ) ); - } - } - - // Randomly place from 1 - 4 of the spirals at the chosen offsets. - for( int i = 0; i < num_spiral; i++ ) { - const point chosen_point = random_entry_removed( offsets ); - const int orx = chosen_point.x; - const int ory = chosen_point.y; - - line( this, t_rock, point( orx, ory ), point( orx + 5, ory ) ); - line( this, t_rock, point( orx + 5, ory ), point( orx + 5, ory + 5 ) ); - line( this, t_rock, point( orx + 1, ory + 5 ), point( orx + 5, ory + 5 ) ); - line( this, t_rock, point( orx + 1, ory + 2 ), point( orx + 1, ory + 4 ) ); - line( this, t_rock, point( orx + 1, ory + 2 ), point( orx + 3, ory + 2 ) ); - ter_set( point( orx + 3, ory + 3 ), t_rock ); - ter_set( point( orx + 2, ory + 3 ), t_rock_floor ); - place_items( item_group_id( "spiral" ), 60, point( orx + 2, ory + 3 ), - point( orx + 2, ory + 3 ), false, calendar::turn_zero ); - } - } -} - void map::draw_spider_pit( const mapgendata &dat ) { const oter_id &terrain_type = dat.terrain_type(); diff --git a/src/overmap.cpp b/src/overmap.cpp index 83e9edf6e7e0b..baa6babc4fa8b 100644 --- a/src/overmap.cpp +++ b/src/overmap.cpp @@ -59,7 +59,6 @@ static const species_id species_ZOMBIE( "ZOMBIE" ); static const mongroup_id GROUP_CHUD( "GROUP_CHUD" ); static const mongroup_id GROUP_RIVER( "GROUP_RIVER" ); static const mongroup_id GROUP_SEWER( "GROUP_SEWER" ); -static const mongroup_id GROUP_SPIRAL( "GROUP_SPIRAL" ); static const mongroup_id GROUP_SWAMP( "GROUP_SWAMP" ); static const mongroup_id GROUP_WORM( "GROUP_WORM" ); static const mongroup_id GROUP_ZOMBIE( "GROUP_ZOMBIE" ); @@ -752,8 +751,6 @@ bool oter_t::is_hardcoded() const "slimepit", "slimepit_down", "spider_pit_under", - "spiral", - "spiral_hub", "temple", "temple_finale", "temple_stairs", @@ -1580,7 +1577,7 @@ bool overmap::generate_sub( const int z ) ter_set( p, oter_id( "central_lab" ) ); } else if( is_ot_match( "hidden_lab_stairs", oter_above, ot_match_type::contains ) ) { lab_points.push_back( city( p.xy(), rng( 1, 5 + z ) ) ); - } else if( is_ot_match( "mine_entrance", oter_ground, ot_match_type::type ) && z == -2 ) { + } else if( is_ot_match( "mine_entrance", oter_ground, ot_match_type::prefix ) && z == -2 ) { mine_points.push_back( city( ( p + tripoint_west ).xy(), rng( 6 + z, 10 + z ) ) ); requires_sub = true; } else if( oter_above == "mine_down" ) { @@ -1589,12 +1586,6 @@ bool overmap::generate_sub( const int z ) // technically not all finales need a sub level, // but at this point we don't know requires_sub = true; - } else if( oter_above == "mine_finale" ) { - for( const tripoint_om_omt &q : points_in_radius( p, 1, 0 ) ) { - ter_set( q, oter_id( "spiral" ) ); - } - ter_set( p, oter_id( "spiral_hub" ) ); - add_mon_group( mongroup( GROUP_SPIRAL, tripoint( i * 2, j * 2, z ), 2, 200 ) ); } } } From 51206db22f76386c25d6cab1ed055a1fd4043c2d Mon Sep 17 00:00:00 2001 From: Jamuro-g <76928284+Jamuro-g@users.noreply.github.com> Date: Sun, 14 Mar 2021 21:53:54 +0100 Subject: [PATCH 053/453] prevent bell spam (#47987) --- src/computer_session.cpp | 17 +++++++++++++---- 1 file changed, 13 insertions(+), 4 deletions(-) diff --git a/src/computer_session.cpp b/src/computer_session.cpp index df4de3fcadefe..0aaf5995ed18d 100644 --- a/src/computer_session.cpp +++ b/src/computer_session.cpp @@ -405,12 +405,21 @@ void computer_session::action_unlock() query_any( _( "Lock disabled. Press any key…" ) ); } -//Toll is required for the church computer/mechanism to function +//Toll is required for the church/school computer/mechanism to function void computer_session::action_toll() { - sounds::sound( get_player_character().pos(), 120, sounds::sound_t::music, - //~ the sound of a church bell ringing - _( "Bohm… Bohm… Bohm…" ), true, "environment", "church_bells" ); + if( calendar::turn < comp.next_attempt ) { + print_error( _( "[Bellsystem 1.2] is currently in use." ) ); + query_any( _( "Please wait for at least one minute." ) ); + reset_terminal(); + } else { + comp.next_attempt = calendar::turn + 1_minutes; + sounds::sound( get_player_character().pos(), 120, sounds::sound_t::music, + //~ the sound of a church bell ringing + _( "Bohm… Bohm… Bohm…" ), true, "environment", "church_bells" ); + + query_any( _( "[Bellsystem 1.2] activated. Have a nice day." ) ); + } } void computer_session::action_sample() From 7fb54af78524807d5e6ca677de7fc2a939929b55 Mon Sep 17 00:00:00 2001 From: Jeremy Rose Date: Sun, 21 Feb 2021 11:41:31 -0800 Subject: [PATCH 054/453] Note that vat is required for fermentation in vinegar brewing (#47651) --- data/json/items/comestibles/brewing.json | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/data/json/items/comestibles/brewing.json b/data/json/items/comestibles/brewing.json index 5ed9904171f38..add3d845d3d67 100644 --- a/data/json/items/comestibles/brewing.json +++ b/data/json/items/comestibles/brewing.json @@ -411,7 +411,7 @@ "type": "COMESTIBLE", "id": "brew_vinegar", "name": { "str": "unfermented vinegar" }, - "description": "Mixture of water, alcohol and fruit juice that will eventually become vinegar.", + "description": "Mixture of water, alcohol and fruit juice that will eventually become vinegar when fermented in a vat.", "weight": "15 g", "color": "yellow", "container": "jug_plastic", From a1e3a9c0dd5c298591f1845e35278f2e48a8cd42 Mon Sep 17 00:00:00 2001 From: Ramza13 <52087122+Ramza13@users.noreply.github.com> Date: Fri, 12 Mar 2021 21:45:06 -0500 Subject: [PATCH 055/453] Unhardcode ease of sleep (#48010) --- data/json/bionics.json | 3 ++- data/json/enchantments.json | 24 ++++++++++++++++++++++++ data/json/mutations/mutations.json | 7 +++++-- doc/MAGIC.md | 1 + src/character.cpp | 19 +++---------------- src/magic_enchantment.cpp | 1 + src/magic_enchantment.h | 1 + 7 files changed, 37 insertions(+), 19 deletions(-) diff --git a/data/json/bionics.json b/data/json/bionics.json index 79915e8fc3624..205e9072af9c4 100644 --- a/data/json/bionics.json +++ b/data/json/bionics.json @@ -1224,6 +1224,7 @@ "name": { "str": "Soporific Induction" }, "description": "An electrode has been implanted into your brain's ventrolateral preoptic nucleus. It turns on whenever you're trying to fall asleep, creating an artificial but effective sensation of fatigue.", "occupied_bodyparts": [ [ "head", 1 ] ], - "flags": [ "BIONIC_TOGGLED" ] + "flags": [ "BIONIC_TOGGLED" ], + "enchantments": [ "ENCH_BIO_SOPORIFIC" ] } ] diff --git a/data/json/enchantments.json b/data/json/enchantments.json index 34e1b8d6ae50b..85852553944b5 100644 --- a/data/json/enchantments.json +++ b/data/json/enchantments.json @@ -11,5 +11,29 @@ "condition": "ACTIVE", "ench_effects": [ { "effect": "invisibility", "intensity": 1 } ], "emitter": "emit_shadow_field" + }, + { + "type": "enchantment", + "id": "ENCH_TRAIT_INSOMNIA", + "condition": "ALWAYS", + "values": [ { "value": "SLEEPY", "add": -12 } ] + }, + { + "type": "enchantment", + "id": "ENCH_TRAIT_EASYSLEEPER", + "condition": "ALWAYS", + "values": [ { "value": "SLEEPY", "add": 24 } ] + }, + { + "type": "enchantment", + "id": "ENCH_TRAIT_EASYSLEEPER2", + "condition": "ALWAYS", + "values": [ { "value": "SLEEPY", "add": 40 } ] + }, + { + "type": "enchantment", + "id": "ENCH_BIO_SOPORIFIC", + "condition": "ACTIVE", + "values": [ { "value": "SLEEPY", "add": 30 } ] } ] diff --git a/data/json/mutations/mutations.json b/data/json/mutations/mutations.json index 0136745a04956..d1ed05dbb5ee6 100644 --- a/data/json/mutations/mutations.json +++ b/data/json/mutations/mutations.json @@ -304,7 +304,8 @@ "starting_trait": true, "valid": false, "cancels": [ "INSOMNIA" ], - "category": [ "MOUSE", "INSECT" ] + "category": [ "MOUSE", "INSECT" ], + "enchantments": [ "ENCH_TRAIT_EASYSLEEPER" ] }, { "type": "mutation", @@ -315,7 +316,8 @@ "prereqs": [ "MET_RAT" ], "cancels": [ "INSOMNIA" ], "threshreq": [ "THRESH_MOUSE" ], - "category": [ "MOUSE" ] + "category": [ "MOUSE" ], + "enchantments": [ "ENCH_TRAIT_EASYSLEEPER2" ] }, { "type": "mutation", @@ -1060,6 +1062,7 @@ "starting_trait": true, "valid": false, "category": [ "MEDICAL" ], + "enchantments": [ "ENCH_TRAIT_INSOMNIA" ], "cancels": [ "EASYSLEEPER" ] }, { diff --git a/doc/MAGIC.md b/doc/MAGIC.md index 9d66f225036f4..adb40c129e92e 100644 --- a/doc/MAGIC.md +++ b/doc/MAGIC.md @@ -493,6 +493,7 @@ Effects for the character that has the enchantment: * SOCIAL_LIE * SOCIAL_PERSUADE * SOCIAL_INTIMIDATE +* SLEEPY : The higher this is the more easily you fall asleep. * ARMOR_BASH * ARMOR_CUT * ARMOR_STAB diff --git a/src/character.cpp b/src/character.cpp index 27a9e29cffc26..71d9ac7f4d6ca 100644 --- a/src/character.cpp +++ b/src/character.cpp @@ -12394,22 +12394,9 @@ int Character::sleep_spot( const tripoint &p ) const if( has_addiction( add_type::SLEEP ) ) { sleepy -= 4; } - if( has_trait( trait_INSOMNIA ) ) { - // 12.5 points is the difference between "tired" and "dead tired" - sleepy -= 12; - } - if( has_trait( trait_EASYSLEEPER ) ) { - // Low fatigue (being rested) has a much stronger effect than high fatigue - // so it's OK for the value to be that much higher - sleepy += 24; - } - if( has_active_bionic( bio_soporific ) ) { - sleepy += 30; - } - if( has_trait( trait_EASYSLEEPER2 ) ) { - // Mousefolk can sleep just about anywhere. - sleepy += 40; - } + + sleepy = enchantment_cache->modify_value( enchant_vals::mod::SLEEPY, sleepy ); + if( watersleep && get_map().has_flag_ter( "SWIMMABLE", pos() ) ) { sleepy += 10; //comfy water! } diff --git a/src/magic_enchantment.cpp b/src/magic_enchantment.cpp index d90dade25f21c..cfbd928183c2f 100644 --- a/src/magic_enchantment.cpp +++ b/src/magic_enchantment.cpp @@ -81,6 +81,7 @@ namespace io case enchant_vals::mod::SOCIAL_LIE: return "SOCIAL_LIE"; case enchant_vals::mod::SOCIAL_PERSUADE: return "SOCIAL_PERSUADE"; case enchant_vals::mod::SOCIAL_INTIMIDATE: return "SOCIAL_INTIMIDATE"; + case enchant_vals::mod::SLEEPY: return "SLEEPY"; case enchant_vals::mod::ARMOR_ACID: return "ARMOR_ACID"; case enchant_vals::mod::ARMOR_BASH: return "ARMOR_BASH"; case enchant_vals::mod::ARMOR_BIO: return "ARMOR_BIO"; diff --git a/src/magic_enchantment.h b/src/magic_enchantment.h index 69404bb52b4c4..442d56b50b45f 100644 --- a/src/magic_enchantment.h +++ b/src/magic_enchantment.h @@ -57,6 +57,7 @@ enum class mod : int { SOCIAL_LIE, SOCIAL_PERSUADE, SOCIAL_INTIMIDATE, + SLEEPY, ARMOR_BASH, ARMOR_CUT, ARMOR_STAB, From 39632ff2b72e8e4a9903eea3a12976dd5008c29d Mon Sep 17 00:00:00 2001 From: Maleclypse <54345792+Maleclypse@users.noreply.github.com> Date: Tue, 16 Mar 2021 01:26:38 -0500 Subject: [PATCH 056/453] Flag Fix for Bollards for 0.F Dev (#48052) --- data/json/furniture_and_terrain/terrain-walls.json | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/data/json/furniture_and_terrain/terrain-walls.json b/data/json/furniture_and_terrain/terrain-walls.json index 34759ba834000..f88f870d7d403 100644 --- a/data/json/furniture_and_terrain/terrain-walls.json +++ b/data/json/furniture_and_terrain/terrain-walls.json @@ -1362,7 +1362,7 @@ "color": "light_gray", "move_cost": 6, "coverage": 20, - "flags": [ "WALL", "PERMEABLE" ], + "flags": [ "TRANSPARENT", "WALL", "SHORT", "PERMEABLE" ], "bash": { "str_min": 350, "str_max": 650, From 57760b1130db994000631b866ca87b6092d65b8b Mon Sep 17 00:00:00 2001 From: Xenomorph-III Date: Tue, 16 Mar 2021 19:36:30 +1300 Subject: [PATCH 057/453] Add Faction Endings to Hub 01 (#48007) --- data/json/npcs/factions.json | 1 + data/json/snippets/epilogue_factions.json | 8 ++++++++ 2 files changed, 9 insertions(+) diff --git a/data/json/npcs/factions.json b/data/json/npcs/factions.json index f19057b1d75f1..574ebb641d86b 100644 --- a/data/json/npcs/factions.json +++ b/data/json/npcs/factions.json @@ -75,6 +75,7 @@ }, "marloss": { "kill on sight": true } }, + "epilogues": [ { "power_min": 0, "id": "epilogue_faction_robofac_0" }, { "power_max": 150, "id": "epilogue_faction_robofac_150" } ], "description": "The surviving staff of Hub 01, a pre-Cataclysm research lab. They rarely leave their lab, if at all, and rely on their robots and advanced technology to survive." }, { diff --git a/data/json/snippets/epilogue_factions.json b/data/json/snippets/epilogue_factions.json index 3245828e9ca9b..50cddf0617156 100644 --- a/data/json/snippets/epilogue_factions.json +++ b/data/json/snippets/epilogue_factions.json @@ -47,6 +47,14 @@ { "id": "epilogue_faction_hells_raiders_150", "text": " Fueled by drugs and rage, the Hell's Raiders fought tooth and nail to overthrow the last strongholds of the Old Guard. The costly victories brought the warlords abundant territory and slaves but little in the way of stability. Within weeks, infighting led to civil war as tribes vied for leadership of the faction. When only one warlord finally secured control, there was nothing left to fight for… just endless cities full of the dead." + }, + { + "id": "epilogue_faction_robofac_0", + "text": " Despite Melchior's enlightened leadership, shortages and crises plagued Hub-01 from the first day of the Cataclysm. The researchers and administrators among the surviving staff lacked the practical skills to survive in the savage new world. As Hub-01's systems collapsed from a lack of maintenance, the few survivors fled the building to be killed by the zombies and bandits." + }, + { + "id": "epilogue_faction_robofac_150", + "text": " Melchior's enlightened leadership, combined with practical skills provided by mercenary survivors, allowed Hub-01 to flourish briefly. It became a mecca for advanced technology, selling off devices and equipment that could no longer be reproduced. Despite this, Hub-01 was never able to expand sufficiently to renew its own population, nor was it able to unite with any other prosperous community, nor could enough trustworthy mercenaries (or staff) be recruited to replace those who died in its defense. Hub-01 fell into disrepair and ruin. After the air processing facility was overtaken by mold, the remaining staff of Hub-01 fled the building and were killed by zombies and bandits. Melchior's drones - possibly by design - were incapable of maintaining themselves without human hands, and stopped working a few months later. Without regular maintenance, Melchior's own systems also fell to ruin, and less than a decade after the Cataclysm, humanity's first AI powered down and was forgotten." } ] } From 4eb60f6fed22544c04f8ab1dd68884bf24302c58 Mon Sep 17 00:00:00 2001 From: Eric <52087122+Ramza13@users.noreply.github.com> Date: Tue, 16 Mar 2021 02:54:18 -0400 Subject: [PATCH 058/453] Merge most effect flags and character flags (#47633) --- data/json/effects.json | 4 +- data/json/flags.json | 60 ------------------------ data/mods/Magiclysm/effects/effects.json | 22 ++++----- doc/JSON_FLAGS.md | 7 ++- src/character.cpp | 22 +++------ src/character.h | 2 +- src/flag.cpp | 12 ----- src/flag.h | 12 ----- src/game.cpp | 2 +- src/monattack.cpp | 2 +- src/player.cpp | 4 +- src/teleport.cpp | 4 +- tests/creature_effect_test.cpp | 2 +- 13 files changed, 33 insertions(+), 122 deletions(-) diff --git a/data/json/effects.json b/data/json/effects.json index 1d9b5d72315dd..748426bfce091 100644 --- a/data/json/effects.json +++ b/data/json/effects.json @@ -745,7 +745,7 @@ "id": "invisibility", "name": [ "Invisible" ], "desc": [ "You are invisible." ], - "flags": [ "EFFECT_INVISIBLE" ] + "flags": [ "INVISIBLE" ] }, { "type": "effect_type", @@ -2410,7 +2410,7 @@ "type": "effect_type", "id": "ignore_fall_damage", "//": "Used for translocation via teleporter_list as a way to avoid fall damage by teleporting Z levels", - "flags": [ "EFFECT_FEATHER_FALL" ] + "flags": [ "FEATHER_FALL" ] }, { "type": "effect_type", diff --git a/data/json/flags.json b/data/json/flags.json index 8be9600699457..0ce224a92a9c3 100644 --- a/data/json/flags.json +++ b/data/json/flags.json @@ -10,11 +10,6 @@ "type": "json_flag", "context": [ ] }, - { - "id": "EFFECT_INVISIBLE", - "context": [ ], - "type": "json_flag" - }, { "id": "ALARMCLOCK", "type": "json_flag", @@ -81,11 +76,6 @@ "//": "Blinds the wearer while worn, and provides nominal protection vs flashbang flashes.", "info": "This gear prevents you from seeing anything." }, - { - "id": "EFFECT_NIGHT_VISION", - "context": [ ], - "type": "json_flag" - }, { "id": "BLOCK_WHILE_WORN", "type": "json_flag", @@ -1012,56 +1002,6 @@ "context": [ "mutation" ], "//": "This mutation does not count toward thresholds at all." }, - { - "id": "EFFECT_FEATHER_FALL", - "context": [ ], - "type": "json_flag" - }, - { - "id": "EFFECT_BIO_IMMUNE", - "context": [ ], - "type": "json_flag" - }, - { - "id": "EFFECT_BASH_IMMUNE", - "context": [ ], - "type": "json_flag" - }, - { - "id": "EFFECT_CUT_IMMUNE", - "context": [ ], - "type": "json_flag" - }, - { - "id": "EFFECT_BULLET_IMMUNE", - "context": [ ], - "type": "json_flag" - }, - { - "id": "EFFECT_ACID_IMMUNE", - "context": [ ], - "type": "json_flag" - }, - { - "id": "EFFECT_STAB_IMMUNE", - "context": [ ], - "type": "json_flag" - }, - { - "id": "EFFECT_HEAT_IMMUNE", - "context": [ ], - "type": "json_flag" - }, - { - "id": "EFFECT_COLD_IMMUNE", - "context": [ ], - "type": "json_flag" - }, - { - "id": "EFFECT_ELECTRIC_IMMUNE", - "context": [ ], - "type": "json_flag" - }, { "id": "HIDDEN_HALLU", "type": "json_flag", diff --git a/data/mods/Magiclysm/effects/effects.json b/data/mods/Magiclysm/effects/effects.json index 063b384f2b8c2..74e0760460e89 100644 --- a/data/mods/Magiclysm/effects/effects.json +++ b/data/mods/Magiclysm/effects/effects.json @@ -27,7 +27,7 @@ "apply_message": "Your sight adjusts to the darkness.", "remove_message": "The darkness loses its shape.", "rating": "good", - "flags": [ "EFFECT_NIGHT_VISION" ] + "flags": [ "NIGHT_VISION" ] }, { "type": "effect_type", @@ -48,7 +48,7 @@ "desc": [ "Nothing can see you." ], "apply_message": "You fade away.", "remove_message": "You can see your hands again.", - "flags": [ "EFFECT_INVISIBLE" ] + "flags": [ "INVISIBLE" ] }, { "type": "effect_type", @@ -180,14 +180,14 @@ "remove_message": "Your skin stops tingling, your life is empty and meaningless again.", "rating": "good", "flags": [ - "EFFECT_ELECTRIC_IMMUNE", - "EFFECT_BIO_IMMUNE", - "EFFECT_BASH_IMMUNE", - "EFFECT_CUT_IMMUNE", - "EFFECT_ACID_IMMUNE", - "EFFECT_STAB_IMMUNE", - "EFFECT_HEAT_IMMUNE", - "EFFECT_COLD_IMMUNE" + "ELECTRIC_IMMUNE", + "BIO_IMMUNE", + "BASH_IMMUNE", + "CUT_IMMUNE", + "ACID_IMMUNE", + "STAB_IMMUNE", + "HEAT_IMMUNE", + "COLD_IMMUNE" ] }, { @@ -198,7 +198,7 @@ "apply_message": "Your body feels light as a feather.", "remove_message": "The earth pulls you down hard.", "rating": "good", - "flags": [ "EFFECT_FEATHER_FALL" ] + "flags": [ "FEATHER_FALL" ] }, { "type": "effect_type", diff --git a/doc/JSON_FLAGS.md b/doc/JSON_FLAGS.md index f26119aaa4bf1..733265f0e4f5a 100644 --- a/doc/JSON_FLAGS.md +++ b/doc/JSON_FLAGS.md @@ -13,7 +13,7 @@ - [Bionics](#bionics) - [Books](#books) - [Use actions](#use-actions) - - [Character - (Bionic/Mutation)](#character) + - [Character - (Bionic/Mutation/Effect)](#character) - [Comestibles](#comestibles) - [Comestible type](#comestible-type) - [Addiction type](#addiction-type) @@ -1553,5 +1553,8 @@ Gun fault flags: - ```ALARMCLOCK``` You always can set alarms. - ```PARAIMMUNE``` You are immune to parasites. - ```IMMUNE_SPOIL``` You are immune to negative outcomes from spoiled food. +- ```FEATHER_FALL``` You are immune to fall damage. +- ```INVISIBLE``` You can't be seen. +- ```DIMENSIONAL_ANCHOR``` You can't be teleported. - ```CLIMATE_CONTROL``` You are resistant to extreme temperatures. -- ```HEATSINK``` You are resistant to extreme heat. \ No newline at end of file +- ```HEATSINK``` You are resistant to extreme heat. diff --git a/src/character.cpp b/src/character.cpp index 71d9ac7f4d6ca..2fbad6bb7b331 100644 --- a/src/character.cpp +++ b/src/character.cpp @@ -396,6 +396,7 @@ static const json_character_flag json_flag_HEATPROOF( "HEATPROOF" ); static const json_character_flag json_flag_HEATSINK( "HEATSINK" ); static const json_character_flag json_flag_IMMUNE_HEARING_DAMAGE( "IMMUNE_HEARING_DAMAGE" ); static const json_character_flag json_flag_INFRARED( "INFRARED" ); +static const json_character_flag json_flag_INVISIBLE( "INVISIBLE" ); static const json_character_flag json_flag_NIGHT_VISION( "NIGHT_VISION" ); static const json_character_flag json_flag_NO_DISEASE( "NO_DISEASE" ); static const json_character_flag json_flag_NO_MINIMAL_HEALING( "NO_MINIMAL_HEALING" ); @@ -4386,8 +4387,7 @@ bool Character::has_nv() if( !nv_cached ) { nv_cached = true; nv = ( worn_with_flag( flag_GNV_EFFECT ) || - has_flag( json_flag_NIGHT_VISION ) || - has_effect_with_flag( flag_EFFECT_NIGHT_VISION ) ); + has_flag( json_flag_NIGHT_VISION ) ); } return nv; @@ -7501,40 +7501,31 @@ bool Character::is_immune_damage( const damage_type dt ) const return false; case damage_type::BIOLOGICAL: return has_flag( json_flag_BIO_IMMUNE ) || - has_effect_with_flag( flag_EFFECT_BIO_IMMUNE ) || worn_with_flag( flag_BIO_IMMUNE ); case damage_type::BASH: return has_flag( json_flag_BASH_IMMUNE ) || - has_effect_with_flag( flag_EFFECT_BASH_IMMUNE ) || worn_with_flag( flag_BASH_IMMUNE ); case damage_type::CUT: return has_flag( json_flag_CUT_IMMUNE ) || - has_effect_with_flag( flag_EFFECT_CUT_IMMUNE ) || worn_with_flag( flag_CUT_IMMUNE ); case damage_type::ACID: return has_flag( json_flag_ACID_IMMUNE ) || - has_effect_with_flag( flag_EFFECT_ACID_IMMUNE ) || worn_with_flag( flag_ACID_IMMUNE ); case damage_type::STAB: return has_flag( json_flag_STAB_IMMUNE ) || - has_effect_with_flag( flag_EFFECT_STAB_IMMUNE ) || worn_with_flag( flag_STAB_IMMUNE ); case damage_type::BULLET: return has_flag( json_flag_BULLET_IMMUNE ) || - has_effect_with_flag( flag_EFFECT_BULLET_IMMUNE ) || worn_with_flag( flag_BULLET_IMMUNE ); case damage_type::HEAT: return has_flag( json_flag_HEATPROOF ) || - has_effect_with_flag( flag_EFFECT_HEAT_IMMUNE ) || worn_with_flag( flag_HEAT_IMMUNE ); case damage_type::COLD: return has_flag( json_flag_COLD_IMMUNE ) || - has_effect_with_flag( flag_EFFECT_COLD_IMMUNE ) || worn_with_flag( flag_COLD_IMMUNE ); case damage_type::ELECTRIC: return has_flag( json_flag_ELECTRIC_IMMUNE ) || - worn_with_flag( flag_ELECTRIC_IMMUNE ) || - has_effect_with_flag( flag_EFFECT_ELECTRIC_IMMUNE ); + worn_with_flag( flag_ELECTRIC_IMMUNE ); default: return true; } @@ -7624,14 +7615,13 @@ tripoint_abs_omt Character::global_omt_location() const bool Character::is_blind() const { return ( worn_with_flag( flag_BLIND ) || - has_effect( effect_blind ) || has_flag( json_flag_BLIND ) ); } bool Character::is_invisible() const { return ( - has_effect_with_flag( flag_EFFECT_INVISIBLE ) || + has_flag( json_flag_INVISIBLE ) || is_wearing_active_optcloak() || has_trait( trait_DEBUG_CLOAK ) ); @@ -13133,6 +13123,6 @@ bool Character::has_bionic_with_flag( const json_character_flag &flag ) const bool Character::has_flag( const json_character_flag &flag ) const { - // If this is a performance problem create a map of flags stored for a character and updated on trait, mutation, bionic add/remove, activate/deactivate - return has_trait_flag( flag ) || has_bionic_with_flag( flag ); + // If this is a performance problem create a map of flags stored for a character and updated on trait, mutation, bionic add/remove, activate/deactivate, effect gain/loss + return has_trait_flag( flag ) || has_bionic_with_flag( flag ) || has_effect_with_flag( flag ); } diff --git a/src/character.h b/src/character.h index 660e5b0c792a3..0df50d945dc29 100644 --- a/src/character.h +++ b/src/character.h @@ -964,7 +964,7 @@ class Character : public Creature, public visitable bool has_bionic_with_flag( const json_character_flag &flag ) const; /** This is to prevent clang complaining about overloading a virtual function, the creature version uses monster flags so confusion is unlikely. */ using Creature::has_flag; - /** Returns true if player has a trait or bionic with a flag */ + /** Returns true if player has a trait, bionic or effect with a flag */ bool has_flag( const json_character_flag &flag ) const; /** Returns the trait id with the given invlet, or an empty string if no trait has that invlet */ trait_id trait_by_invlet( int ch ) const; diff --git a/src/flag.cpp b/src/flag.cpp index dbe17a49a8342..641d9c5966be2 100644 --- a/src/flag.cpp +++ b/src/flag.cpp @@ -76,19 +76,7 @@ const flag_id flag_DURABLE_MELEE( "DURABLE_MELEE" ); const flag_id flag_EATEN_COLD( "EATEN_COLD" ); const flag_id flag_EATEN_HOT( "EATEN_HOT" ); const flag_id flag_EDIBLE_FROZEN( "EDIBLE_FROZEN" ); -const flag_id flag_EFFECT_ACID_IMMUNE( "EFFECT_ACID_IMMUNE" ); -const flag_id flag_EFFECT_BASH_IMMUNE( "EFFECT_BASH_IMMUNE" ); -const flag_id flag_EFFECT_BIO_IMMUNE( "EFFECT_BIO_IMMUNE" ); -const flag_id flag_EFFECT_BULLET_IMMUNE( "EFFECT_BULLET_IMMUNE" ); -const flag_id flag_EFFECT_COLD_IMMUNE( "EFFECT_COLD_IMMUNE" ); -const flag_id flag_EFFECT_CUT_IMMUNE( "EFFECT_CUT_IMMUNE" ); -const flag_id flag_EFFECT_ELECTRIC_IMMUNE( "EFFECT_ELECTRIC_IMMUNE" ); -const flag_id flag_EFFECT_FEATHER_FALL( "EFFECT_FEATHER_FALL" ); -const flag_id flag_EFFECT_HEAT_IMMUNE( "EFFECT_HEAT_IMMUNE" ); const flag_id flag_EFFECT_IMPEDING( "EFFECT_IMPEDING" ); -const flag_id flag_EFFECT_INVISIBLE( "EFFECT_INVISIBLE" ); -const flag_id flag_EFFECT_NIGHT_VISION( "EFFECT_NIGHT_VISION" ); -const flag_id flag_EFFECT_STAB_IMMUNE( "EFFECT_STAB_IMMUNE" ); const flag_id flag_ELECTRIC_IMMUNE( "ELECTRIC_IMMUNE" ); const flag_id flag_ETHEREAL_ITEM( "ETHEREAL_ITEM" ); const flag_id flag_FAKE_MILL( "FAKE_MILL" ); diff --git a/src/flag.h b/src/flag.h index 9c19663da5eaa..316de675b7686 100644 --- a/src/flag.h +++ b/src/flag.h @@ -83,19 +83,7 @@ extern const flag_id flag_DURABLE_MELEE; extern const flag_id flag_EATEN_COLD; extern const flag_id flag_EATEN_HOT; extern const flag_id flag_EDIBLE_FROZEN; -extern const flag_id flag_EFFECT_ACID_IMMUNE; -extern const flag_id flag_EFFECT_BASH_IMMUNE; -extern const flag_id flag_EFFECT_BIO_IMMUNE; -extern const flag_id flag_EFFECT_BULLET_IMMUNE; -extern const flag_id flag_EFFECT_COLD_IMMUNE; -extern const flag_id flag_EFFECT_CUT_IMMUNE; -extern const flag_id flag_EFFECT_ELECTRIC_IMMUNE; -extern const flag_id flag_EFFECT_FEATHER_FALL; -extern const flag_id flag_EFFECT_HEAT_IMMUNE; extern const flag_id flag_EFFECT_IMPEDING; -extern const flag_id flag_EFFECT_INVISIBLE; -extern const flag_id flag_EFFECT_NIGHT_VISION; -extern const flag_id flag_EFFECT_STAB_IMMUNE; extern const flag_id flag_ELECTRIC_IMMUNE; extern const flag_id flag_ETHEREAL_ITEM; extern const flag_id flag_FAKE_MILL; diff --git a/src/game.cpp b/src/game.cpp index 1e7443182b49f..dd8e7e57197ac 100644 --- a/src/game.cpp +++ b/src/game.cpp @@ -10323,7 +10323,7 @@ bool game::phasing_move( const tripoint &dest_loc, const bool via_ramp ) tunneldist += 1; //Being dimensionally anchored prevents quantum shenanigans. if( u.worn_with_flag( flag_DIMENSIONAL_ANCHOR ) || - u.has_effect_with_flag( flag_DIMENSIONAL_ANCHOR ) ) { + u.has_flag( flag_DIMENSIONAL_ANCHOR ) ) { u.add_msg_if_player( m_info, _( "You are repelled by the barrier!" ) ); u.mod_power_level( -250_kJ ); //cost of tunneling one tile. return false; diff --git a/src/monattack.cpp b/src/monattack.cpp index 61c7a9e81b070..ef032c0988352 100644 --- a/src/monattack.cpp +++ b/src/monattack.cpp @@ -2855,7 +2855,7 @@ bool mattack::stare( monster *z ) if( z->sees( player_character ) ) { //dimensional effects don't take against dimensionally anchored foes. if( player_character.worn_with_flag( flag_DIMENSIONAL_ANCHOR ) || - player_character.has_effect_with_flag( flag_DIMENSIONAL_ANCHOR ) ) { + player_character.has_flag( flag_DIMENSIONAL_ANCHOR ) ) { add_msg( m_warning, _( "You feel a strange reverberation across your body." ) ); return true; } diff --git a/src/player.cpp b/src/player.cpp index 209c114f5cbd9..e39b2933610de 100644 --- a/src/player.cpp +++ b/src/player.cpp @@ -139,6 +139,8 @@ static const bionic_id bio_ground_sonar( "bio_ground_sonar" ); static const bionic_id bio_soporific( "bio_soporific" ); static const bionic_id bio_speed( "bio_speed" ); +static const json_character_flag json_flag_FEATHER_FALL( "FEATHER_FALL" ); + stat_mod player::get_pain_penalty() const { stat_mod ret; @@ -833,7 +835,7 @@ int player::get_perceived_pain() const float player::fall_damage_mod() const { - if( has_effect_with_flag( flag_EFFECT_FEATHER_FALL ) ) { + if( has_flag( json_flag_FEATHER_FALL ) ) { return 0.0f; } float ret = 1.0f; diff --git a/src/teleport.cpp b/src/teleport.cpp index 6db51beaeca5f..f4835d28be499 100644 --- a/src/teleport.cpp +++ b/src/teleport.cpp @@ -40,7 +40,7 @@ bool teleport::teleport( Creature &critter, int min_distance, int max_distance, map &here = get_map(); //The teleportee is dimensionally anchored so nothing happens if( p && ( p->worn_with_flag( json_flag_DIMENSIONAL_ANCHOR ) || - p->has_effect_with_flag( json_flag_DIMENSIONAL_ANCHOR ) ) ) { + p->has_flag( json_flag_DIMENSIONAL_ANCHOR ) ) ) { p->add_msg_if_player( m_warning, _( "You feel a strange, inwards force." ) ); return false; } @@ -76,7 +76,7 @@ bool teleport::teleport( Creature &critter, int min_distance, int max_distance, } return false; } else if( poor_player && ( poor_player->worn_with_flag( json_flag_DIMENSIONAL_ANCHOR ) || - poor_player->has_effect_with_flag( json_flag_DIMENSIONAL_ANCHOR ) ) ) { + poor_player->has_flag( json_flag_DIMENSIONAL_ANCHOR ) ) ) { poor_player->add_msg_if_player( m_warning, _( "You feel disjointed." ) ); return false; } else { diff --git a/tests/creature_effect_test.cpp b/tests/creature_effect_test.cpp index b3db98f732e38..7b148b626e6d5 100644 --- a/tests/creature_effect_test.cpp +++ b/tests/creature_effect_test.cpp @@ -314,7 +314,7 @@ TEST_CASE( "has_effect_with_flag", "[creature][effect][has][flag]" ) { const efftype_id effect_downed( "downed" ); const efftype_id effect_invisibility( "invisibility" ); - const flag_id invisibility_flag( "EFFECT_INVISIBLE" ); + const flag_id invisibility_flag( "INVISIBLE" ); monster mummy( mtype_id( "debug_mon" ) ); From 7f9df7635d8fba4aae9c62c5a9004d11272915b9 Mon Sep 17 00:00:00 2001 From: OromisElf Date: Tue, 16 Mar 2021 08:03:29 +0100 Subject: [PATCH 059/453] added electric train engine (#48012) --- data/json/items/vehicle/motors.json | 11 +++++++++++ data/json/vehicleparts/motor.json | 25 +++++++++++++++++++++++++ 2 files changed, 36 insertions(+) diff --git a/data/json/items/vehicle/motors.json b/data/json/items/vehicle/motors.json index 60f6191a764f0..06e1d5ba31d6b 100644 --- a/data/json/items/vehicle/motors.json +++ b/data/json/items/vehicle/motors.json @@ -76,5 +76,16 @@ "category": "veh_parts", "price": 2000, "price_postapoc": 100 + }, + { + "type": "GENERIC", + "id": "motor_train1300", + "name": { "str": "1300hp electric train engine" }, + "description": "A 1300hp extended-use electric engine. Normally used in trains.", + "weight": "2000 kg", + "volume": "250 L", + "price": 120000, + "price_postapoc": 8000, + "copy-from": "motor" } ] diff --git a/data/json/vehicleparts/motor.json b/data/json/vehicleparts/motor.json index 89b44c57c70ce..a2727c273a826 100644 --- a/data/json/vehicleparts/motor.json +++ b/data/json/vehicleparts/motor.json @@ -159,5 +159,30 @@ { "item": "cable", "charges": [ 20, 30 ] } ], "damage_reduction": { "all": 60 } + }, + { + "id": "engine_electric_train", + "copy-from": "engine_motor", + "type": "vehicle_part", + "name": { "str": "1300hp electric train engine" }, + "item": "motor_train1300", + "durability": 500, + "power": 1000000, + "energy_consumption": 1050000, + "damage_modifier": 80, + "requirements": { + "install": { "skills": [ [ "mechanics", 8 ] ], "time": "60 m", "using": [ [ "vehicle_wrench_2", 1 ] ] }, + "removal": { "skills": [ [ "mechanics", 4 ] ], "time": "45 m", "using": [ [ "vehicle_wrench_2", 1 ] ] }, + "repair": { "skills": [ [ "mechanics", 10 ] ], "time": "60 m", "using": [ [ "welding_standard", 20 ] ] } + }, + "breaks_into": [ + { "item": "steel_lump", "count": [ 60, 80 ] }, + { "item": "steel_chunk", "count": [ 24, 40 ] }, + { "item": "scrap", "count": [ 24, 40 ] }, + { "item": "e_scrap", "count": [ 20, 60 ] }, + { "item": "bearing", "count": [ 100, 240 ] }, + { "item": "cable", "charges": [ 80, 120 ] } + ], + "damage_reduction": { "all": 60 } } ] From 56435f3872575633368c8092fb8a984bd98fc69d Mon Sep 17 00:00:00 2001 From: Saicchi Date: Fri, 12 Mar 2021 01:54:45 -0300 Subject: [PATCH 060/453] Allow filtering by level in the recipe craft menu (#47995) --- src/crafting_gui.cpp | 8 ++++++ src/recipe_dictionary.cpp | 58 +++++++++++++++++++++++++++++++++++++++ src/recipe_dictionary.h | 1 + 3 files changed, 67 insertions(+) diff --git a/src/crafting_gui.cpp b/src/crafting_gui.cpp index 2b45bef6193e8..4e67f4a334029 100644 --- a/src/crafting_gui.cpp +++ b/src/crafting_gui.cpp @@ -765,6 +765,11 @@ const recipe *select_crafting_recipe( int &batch_size_out ) recipe_subset::search_type::proficiency, progress_callback ); break; + case 'l': + filtered_recipes = filtered_recipes.reduce( qry_filter_str.substr( 2 ), + recipe_subset::search_type::difficulty, progress_callback ); + break; + default: current.clear(); } @@ -936,6 +941,7 @@ const recipe *select_crafting_recipe( int &batch_size_out ) { 't', _( "soldering iron" ), _( "tool required to craft" ) }, { 'm', _( "yes" ), _( "recipes which are memorized or not" ) }, { 'P', _( "Blacksmithing" ), _( "proficiency used to craft" ) }, + { 'l', _( "5" ), _( "difficulty of the recipe as a number or range" ) }, }; int max_example_length = 0; for( const auto &prefix : prefixes ) { @@ -947,6 +953,8 @@ const recipe *select_crafting_recipe( int &batch_size_out ) _( "The default is to search result names. Some single-character prefixes " "can be used with a colon : to search in other ways. Additional filters " "are separated by commas ,.\n" + "Filtering by difficulty can accept range; " + "l:5~10 for all recipes from difficulty 5 to 10.\n" "\n\n" "Examples:\n" ); diff --git a/src/recipe_dictionary.cpp b/src/recipe_dictionary.cpp index b3e17b2368b74..7e8b837e0baed 100644 --- a/src/recipe_dictionary.cpp +++ b/src/recipe_dictionary.cpp @@ -189,6 +189,64 @@ std::vector recipe_subset::search( case search_type::proficiency: return lcmatch( r->recipe_proficiencies_string(), txt ); + case search_type::difficulty: { + std::string range_start; + std::string range_end; + bool use_range = false; + for( const char &chr : txt ) { + if( std::isdigit( chr ) ) { + if( use_range ) { + range_end += chr; + } else { + range_start += chr; + } + } else if( chr == '~' ) { + use_range = true; + } else { + // unexpected character + return true; + } + } + + int start = 0; + int end = INT_MAX; + + if( use_range ) { + if( !range_start.empty() ) { + start = std::stoi( range_start ); + } + + if( !range_end.empty() ) { + end = std::stoi( range_end ); + } + + if( range_start.empty() && range_end.empty() ) { + return true; + } + } else { + if( !range_start.empty() ) { + start = std::stoi( range_start ); + } + + if( range_start.empty() && range_end.empty() ) { + return true; + } + } + + if( use_range && start > end ) { + int swap = start; + start = end; + end = swap; + } + + if( use_range ) { + // check if number is between two numbers inclusive + return r->difficulty == clamp( r->difficulty, start, end ); + } else { + return r->difficulty == start; + } + } + default: return false; } diff --git a/src/recipe_dictionary.h b/src/recipe_dictionary.h index 8304cec064b38..d21b0c01f2dd4 100644 --- a/src/recipe_dictionary.h +++ b/src/recipe_dictionary.h @@ -137,6 +137,7 @@ class recipe_subset quality_result, description_result, proficiency, + difficulty, }; /** Find marked favorite recipes */ From addde343fb31a664576de00da8c4394ed4e4cca6 Mon Sep 17 00:00:00 2001 From: LaVeyanFiend Date: Thu, 18 Mar 2021 10:11:48 -0400 Subject: [PATCH 061/453] Fix MSC Typo (#48115) --- data/mods/My_Sweet_Cataclysm/sweet_items.json | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/data/mods/My_Sweet_Cataclysm/sweet_items.json b/data/mods/My_Sweet_Cataclysm/sweet_items.json index 9def6b336f864..6c83a070228ae 100644 --- a/data/mods/My_Sweet_Cataclysm/sweet_items.json +++ b/data/mods/My_Sweet_Cataclysm/sweet_items.json @@ -17,7 +17,7 @@ "id": "ruined_candy", "//": "This item should not get any use whatsoever, it is merely conservation.", "symbol": "¨", - "name": { "str_sp": "peices of candy wrapper" }, + "name": { "str_sp": "pieces of candy wrapper" }, "charges": 10, "volume": "1000 ml", "weight": "100 g", From fb47bbf9e4e60fa2324b97f7376ff97ca2fadc6c Mon Sep 17 00:00:00 2001 From: Termineitor244 <53200489+Termineitor244@users.noreply.github.com> Date: Thu, 18 Mar 2021 13:55:31 -0600 Subject: [PATCH 062/453] A livelier Zoo (#48108) --- data/json/mapgen/zoo.json | 110 ++++++++++++++++++++++++-------------- 1 file changed, 70 insertions(+), 40 deletions(-) diff --git a/data/json/mapgen/zoo.json b/data/json/mapgen/zoo.json index 6cb543524d36a..761cf616a6464 100644 --- a/data/json/mapgen/zoo.json +++ b/data/json/mapgen/zoo.json @@ -17,6 +17,15 @@ { "monster": "mon_zoose", "freq": 50, "cost_multiplier": 1 } ] }, + { + "name": "GROUP_PIGS", + "type": "monstergroup", + "default": "mon_pig", + "monsters": [ + { "monster": "mon_pig", "freq": 50, "cost_multiplier": 1 }, + { "monster": "mon_zombie_pig", "freq": 50, "cost_multiplier": 1 } + ] + }, { "method": "json", "om_terrain": "zoo_0_0", @@ -127,16 +136,17 @@ }, "place_item": [ { "item": "rock", "repeat": 1, "x": 9, "y": 15 }, { "item": "pine_bough", "repeat": 1, "x": 9, "y": 21 } ], "place_items": [ - { "chance": 55, "item": "toy_store", "x": 12, "y": [ 6, 7 ] }, + { "chance": 55, "item": "toy_store", "x": 12, "y": [ 6, 7 ], "repeat": [ 1, 16 ] }, { "chance": 75, "item": "vending_food", "x": 20, "y": 2 }, { "chance": 55, "item": "trash", "x": 13, "y": 15 }, { "chance": 55, "item": "trash", "x": 13, "y": 10 }, - { "chance": 55, "item": "snacks", "x": 10, "y": 11 }, - { "chance": 55, "item": "snacks", "x": [ 7, 8 ], "y": 4 }, - { "chance": 55, "item": "candy_shop", "x": 10, "y": [ 6, 7 ] }, - { "chance": 75, "item": "shirts", "x": 10, "y": 12 }, - { "chance": 75, "item": "shirts", "x": 4, "y": 11 }, - { "chance": 75, "item": "vending_drink", "x": 20, "y": 1 } + { "chance": 55, "item": "snacks", "x": 10, "y": 11, "repeat": [ 1, 16 ] }, + { "chance": 55, "item": "snacks", "x": [ 7, 8 ], "y": 4, "repeat": [ 1, 16 ] }, + { "chance": 55, "item": "candy_shop", "x": 10, "y": [ 6, 7 ], "repeat": [ 1, 16 ] }, + { "chance": 75, "item": "shirts", "x": 10, "y": 12, "repeat": [ 1, 5 ] }, + { "chance": 45, "item": "shirts", "x": 4, "y": 11, "repeat": [ 1, 3 ] }, + { "chance": 75, "item": "vending_drink", "x": 20, "y": 1 }, + { "chance": 25, "item": "waitingroom", "x": 18, "y": [ 16, 22 ], "repeat": [ 1, 3 ] } ], "place_monster": [ { "monster": "mon_tiger", "x": 8, "y": 16 }, @@ -211,16 +221,17 @@ "{": "f_rack" }, "place_items": [ - { "chance": 55, "item": "toy_store", "x": 12, "y": [ 6, 7 ] }, + { "chance": 55, "item": "toy_store", "x": 12, "y": [ 6, 7 ], "repeat": [ 1, 16 ] }, { "chance": 75, "item": "vending_food", "x": 20, "y": 2 }, { "chance": 55, "item": "trash", "x": 13, "y": 15 }, { "chance": 55, "item": "trash", "x": 13, "y": 10 }, - { "chance": 55, "item": "snacks", "x": 10, "y": 11 }, - { "chance": 55, "item": "snacks", "x": [ 7, 8 ], "y": 4 }, - { "chance": 55, "item": "candy_shop", "x": 10, "y": [ 6, 7 ] }, - { "chance": 75, "item": "shirts", "x": 10, "y": 12 }, - { "chance": 75, "item": "shirts", "x": 4, "y": 11 }, - { "chance": 75, "item": "vending_drink", "x": 20, "y": 1 } + { "chance": 55, "item": "snacks", "x": 10, "y": 11, "repeat": [ 1, 16 ] }, + { "chance": 55, "item": "snacks", "x": [ 7, 8 ], "y": 4, "repeat": [ 1, 16 ] }, + { "chance": 55, "item": "candy_shop", "x": 10, "y": [ 6, 7 ], "repeat": [ 1, 16 ] }, + { "chance": 75, "item": "shirts", "x": 10, "y": 12, "repeat": [ 1, 5 ] }, + { "chance": 45, "item": "shirts", "x": 4, "y": 11, "repeat": [ 1, 3 ] }, + { "chance": 75, "item": "vending_drink", "x": 20, "y": 1 }, + { "chance": 25, "item": "waitingroom", "x": 18, "y": [ 16, 22 ], "repeat": [ 1, 3 ] } ], "place_item": [ { "item": "rock", "repeat": 1, "x": 9, "y": 15 }, @@ -229,7 +240,7 @@ { "item": "glass_shard", "repeat": [ 42, 84 ], "x": 11, "y": [ 21, 23 ] } ], "place_monster": [ { "monster": "mon_coyote", "x": 8, "y": 16 }, { "monster": "mon_coyote", "x": 9, "y": 17 } ], - "place_monsters": [ { "monster": "GROUP_BEARS", "x": 8, "y": 20 } ] + "place_monsters": [ { "monster": "GROUP_BEARS", "x": 9, "y": 23 } ] } }, { @@ -290,7 +301,7 @@ "-#_|..|...r...b..|||__ss", "-__|..a...r...b..r.|__ss", "-7_|..|...r......r.|__ss", - "-__|..|...r......|||__ss", + "-__|{.|...r......|||__ss", "-_#|c.|..h|rr|...r.|__ss", "B__|..|..h|..|...r.|__ss", "___|..|||||||||+||||____", @@ -340,8 +351,10 @@ ], "place_items": [ { "chance": 45, "item": "trash", "x": 20, "y": 5 }, - { "chance": 65, "item": "vet_softdrug", "x": 10, "y": 18 }, - { "chance": 45, "item": "vet_hardrug", "x": 9, "y": 18 } + { "chance": 65, "item": "vet_softdrug", "x": 10, "y": 18, "repeat": [ 2, 5 ] }, + { "chance": 45, "item": "vet_hardrug", "x": 9, "y": 18, "repeat": [ 2, 5 ] }, + { "chance": 95, "item": "SUS_janitors_closet", "x": 4, "y": 14 }, + { "chance": 25, "item": "waitingroom", "x": [ 16, 17 ], "y": 7, "repeat": [ 1, 3 ] } ], "place_monster": [ { "monster": "mon_bobcat", "x": 8, "y": 5 }, @@ -519,7 +532,10 @@ { "chance": 65, "item": "vending_food", "x": 12, "y": 1 }, { "chance": 55, "item": "trash", "x": 8, "y": 19 }, { "chance": 55, "item": "trash", "x": 12, "y": 6 }, - { "chance": 55, "item": "trash", "x": 10, "y": 2 } + { "chance": 55, "item": "trash", "x": 10, "y": 2 }, + { "chance": 15, "item": "waitingroom", "x": [ 5, 6 ], "y": 19 }, + { "chance": 15, "item": "waitingroom", "x": [ 9, 10 ], "y": 19 }, + { "chance": 15, "item": "waitingroom", "x": [ 15, 16 ], "y": 19 } ], "place_monster": [ { "monster": "mon_deer", "x": 20, "y": 2 }, @@ -614,7 +630,10 @@ { "chance": 65, "item": "vending_food", "x": 12, "y": 1 }, { "chance": 55, "item": "trash", "x": 8, "y": 19 }, { "chance": 55, "item": "trash", "x": 12, "y": 6 }, - { "chance": 55, "item": "trash", "x": 10, "y": 2 } + { "chance": 55, "item": "trash", "x": 10, "y": 2 }, + { "chance": 15, "item": "waitingroom", "x": [ 5, 6 ], "y": 19 }, + { "chance": 15, "item": "waitingroom", "x": [ 9, 10 ], "y": 19 }, + { "chance": 15, "item": "waitingroom", "x": [ 15, 16 ], "y": 19 } ], "place_item": [ { "item": "stick", "repeat": 1, "x": 19, "y": 1 }, @@ -700,7 +719,7 @@ "|||...............-...^|", "-......|-------|..-..^^|", "-......-h....^.-..+...^|", - "-.####&-h..^#..+..|....|", + "-.####&-h..^#..+.L|....|", "||||||||||||||||||||||||", "|i.ctc..i|............&|", "+........C............C|", @@ -734,20 +753,32 @@ "o": "f_oven", "s": "f_sink", "t": "f_table", - "{": "f_fridge" + "{": "f_fridge", + "L": "f_locker" }, "place_items": [ - { "chance": 65, "item": "cannedfood", "x": 22, "y": 21 }, - { "chance": 65, "item": "cannedfood", "x": 22, "y": 19 }, - { "chance": 55, "item": "bowling_food", "x": 5, "y": 21 }, - { "chance": 55, "item": "bowling_food", "x": 15, "y": 16 }, - { "chance": 55, "item": "bowling_food", "x": 9, "y": 15 }, + { "chance": 25, "item": "restaur_table", "x": 4, "y": 14, "repeat": [ 1, 2 ] }, + { "chance": 25, "item": "restaur_table", "x": 5, "y": [ 20, 21 ], "repeat": [ 1, 2 ] }, + { "chance": 25, "item": "restaur_table", "x": 9, "y": [ 20, 21 ], "repeat": [ 1, 2 ] }, + { "chance": 25, "item": "restaur_table", "x": 13, "y": 21, "repeat": [ 1, 2 ] }, + { "chance": 15, "item": "restaur_table", "x": 9, "y": [ 15, 16 ], "repeat": [ 1, 2 ] }, + { "chance": 55, "item": "restaur_kitchen", "x": 22, "y": [ 15, 16 ], "repeat": [ 1, 8 ] }, + { "chance": 55, "item": "restaur_kitchen", "x": 22, "y": [ 19, 21 ], "repeat": [ 1, 8 ] }, + { "chance": 75, "item": "restaur_sink", "x": 22, "y": [ 17, 18 ], "repeat": [ 2, 3 ] }, + { "chance": 55, "item": "SUS_oven", "x": [ 15, 17 ], "y": 16, "repeat": [ 2, 3 ] }, { "chance": 55, "item": "trash", "x": 10, "y": 18 }, { "chance": 55, "item": "trash", "x": 22, "y": 14 }, { "chance": 55, "item": "trash", "x": 6, "y": 12 }, { "chance": 55, "item": "trash", "x": 6, "y": 3 }, - { "chance": 55, "item": "fridgesnacks", "x": [ 15, 16 ], "y": 21 }, - { "chance": 35, "item": "fridge", "x": [ 18, 19 ], "y": 21 } + { "chance": 50, "item": "behindcounter", "x": 17, "y": 21, "repeat": [ 1, 6 ] }, + { "chance": 80, "item": "restaur_fridge", "x": [ 15, 16 ], "y": 21, "repeat": [ 2, 8 ] }, + { "chance": 80, "item": "restaur_fridge", "x": [ 18, 19 ], "y": 21, "repeat": [ 2, 8 ] } + ], + "place_item": [ + { "chance": 60, "item": "birdfood", "x": 12, "y": [ 3, 4 ], "repeat": [ 3, 6 ] }, + { "chance": 60, "item": "birdfood", "x": [ 9, 11 ], "y": 11, "repeat": [ 3, 6 ] }, + { "chance": 35, "item": "birdfood", "x": 20, "y": [ 3, 10 ], "repeat": [ 4, 8 ] }, + { "chance": 90, "item": "birdfood", "x": 17, "y": 12, "repeat": [ 5, 10 ] } ], "sealed_item": { "^": { "item": { "item": "seed_sugar_beet" }, "furniture": "f_plant_seed" } }, "place_monster": [ @@ -997,7 +1028,7 @@ "____..+.g..........fff|-", "____..+.........g..fff|-", "____r.c...........|fff|-", - "____r.c.....gg....|#ff|-", + "____r.c.....gg....|#f}|-", "____r.c....gggg...|||||-", "____r.c.....gg........|-", "____r.c......g........|-", @@ -1020,13 +1051,17 @@ "r": "t_railing_v", "|": "t_brick_wall" }, - "furniture": { "#": "f_hay", "&": "f_trashcan" }, + "furniture": { "#": "f_hay", "&": "f_trashcan", "}": "f_locker" }, "place_item": [ { "item": "rock", "repeat": 1, "x": 8, "y": 9 }, { "item": "rock", "repeat": 1, "x": 16, "y": 15 }, { "item": "stick", "repeat": 1, "x": 8, "y": 17 }, { "item": "stick", "repeat": 1, "x": 21, "y": 18 }, - { "item": "stick", "repeat": 1, "x": 21, "y": 20 } + { "item": "stick", "repeat": 1, "x": 21, "y": 20 }, + { "chance": 15, "item": "cattlefodder", "x": [ 9, 14 ], "y": [ 7, 17 ], "repeat": [ 8, 12 ] }, + { "chance": 15, "item": "birdfood", "x": [ 9, 14 ], "y": [ 7, 17 ], "repeat": [ 8, 12 ] }, + { "chance": 90, "item": "cattlefodder", "x": 21, "y": 14, "repeat": [ 5, 10 ] }, + { "chance": 90, "item": "birdfood", "x": 21, "y": 14, "repeat": [ 4, 8 ] } ], "place_items": [ { "chance": 55, "item": "trash", "x": 3, "y": 22 }, @@ -1034,21 +1069,16 @@ { "chance": 55, "item": "trash", "x": 0, "y": 6 } ], "place_monster": [ - { "monster": "mon_zombie_pig", "x": 10, "y": 7 }, { "monster": "mon_chicken", "x": 14, "y": 7 }, - { "monster": "mon_zombie_pig", "x": 15, "y": 10 }, { "monster": "mon_duck", "x": 11, "y": 11 }, - { "monster": "mon_zombie_pig", "x": 15, "y": 12 }, - { "monster": "mon_pig", "x": 20, "y": 12 }, { "monster": "mon_sheep", "x": 10, "y": 17 }, { "monster": "mon_rabbit", "x": 15, "y": 17 }, { "monster": "mon_sheep", "x": 19, "y": 17 }, { "monster": "mon_sheep", "x": 9, "y": 19 }, { "monster": "mon_sheep", "x": 12, "y": 19 }, - { "monster": "mon_rabbit", "x": 15, "y": 19 }, - { "monster": "mon_pig", "x": 17, "y": 20 }, - { "monster": "mon_pig", "x": 19, "y": 20 } - ] + { "monster": "mon_rabbit", "x": 18, "y": 19 } + ], + "place_monsters": [ { "monster": "GROUP_PIGS", "x": 18, "y": 11 } ] } }, { From e10b094c0c65d5dd916243948aab0cd1da53f429 Mon Sep 17 00:00:00 2001 From: Termineitor244 <53200489+Termineitor244@users.noreply.github.com> Date: Wed, 17 Mar 2021 14:46:59 -0600 Subject: [PATCH 063/453] Increased the probability of condoms in wallets (#48100) --- .../itemgroups/Clothing_Gear/wallets.json | 24 +++++++++---------- 1 file changed, 12 insertions(+), 12 deletions(-) diff --git a/data/json/itemgroups/Clothing_Gear/wallets.json b/data/json/itemgroups/Clothing_Gear/wallets.json index 5e74971899181..92020cbd4f882 100644 --- a/data/json/itemgroups/Clothing_Gear/wallets.json +++ b/data/json/itemgroups/Clothing_Gear/wallets.json @@ -41,7 +41,7 @@ { "item": "coin_quarter", "prob": 10, "count": [ 1, 2 ] }, { "item": "coin_nickel", "prob": 10, "count": [ 1, 2 ] }, { "group": "discount_cards", "prob": 40, "count": [ 1, 3 ] }, - { "item": "condom", "prob": 1 }, + { "item": "condom", "prob": 10 }, [ "scorecard", 20 ] ] }, @@ -57,7 +57,7 @@ { "item": "coin_quarter", "prob": 10, "count": [ 1, 2 ] }, { "item": "coin_nickel", "prob": 10, "count": [ 1, 2 ] }, { "group": "discount_cards", "prob": 40, "count": [ 1, 3 ] }, - { "item": "condom", "prob": 1 }, + { "item": "condom", "prob": 10 }, [ "scorecard", 20 ] ] }, @@ -73,7 +73,7 @@ { "item": "coin_quarter", "prob": 10, "count": [ 1, 2 ] }, { "item": "coin_nickel", "prob": 10, "count": [ 1, 2 ] }, { "group": "discount_cards", "prob": 40, "count": [ 1, 3 ] }, - { "item": "condom", "prob": 1 }, + { "item": "condom", "prob": 10 }, [ "scorecard", 20 ] ] }, @@ -88,7 +88,7 @@ { "item": "coin_quarter", "prob": 50, "count": [ 2, 5 ] }, { "item": "coin_nickel", "prob": 0, "count": [ 1, 6 ] }, { "group": "discount_cards", "prob": 10 }, - { "item": "condom", "prob": 1 }, + { "item": "condom", "prob": 10 }, [ "scorecard", 40 ] ] }, @@ -103,7 +103,7 @@ { "item": "money_ten", "prob": 100, "count": [ 5, 10 ] }, { "item": "money_twenty", "prob": 100, "count": [ 5, 10 ] }, { "group": "discount_cards", "prob": 60, "count": [ 2, 5 ] }, - { "item": "condom", "prob": 1 }, + { "item": "condom", "prob": 10 }, [ "scorecard", 5 ] ] }, @@ -120,7 +120,7 @@ { "item": "coin_quarter", "prob": 10, "count": [ 1, 2 ] }, { "item": "coin_nickel", "prob": 10, "count": [ 1, 2 ] }, { "group": "discount_cards", "prob": 40, "count": [ 1, 3 ] }, - { "item": "condom", "prob": 1 }, + { "item": "condom", "prob": 10 }, [ "scorecard", 20 ] ] }, @@ -137,7 +137,7 @@ { "item": "coin_quarter", "prob": 10, "count": [ 1, 2 ] }, { "item": "coin_nickel", "prob": 10, "count": [ 1, 2 ] }, { "group": "discount_cards", "prob": 40, "count": [ 1, 3 ] }, - { "item": "condom", "prob": 1 }, + { "item": "condom", "prob": 10 }, [ "scorecard", 20 ] ] }, @@ -154,7 +154,7 @@ { "item": "coin_quarter", "prob": 10, "count": [ 1, 2 ] }, { "item": "coin_nickel", "prob": 10, "count": [ 1, 2 ] }, { "group": "discount_cards", "prob": 40, "count": [ 1, 3 ] }, - { "item": "condom", "prob": 1 }, + { "item": "condom", "prob": 10 }, { "item": "labmap", "prob": 20 }, [ "scorecard", 20 ] ] @@ -172,7 +172,7 @@ { "item": "coin_quarter", "prob": 10, "count": [ 1, 2 ] }, { "item": "coin_nickel", "prob": 10, "count": [ 1, 2 ] }, { "group": "discount_cards", "prob": 40, "count": [ 1, 3 ] }, - { "item": "condom", "prob": 1 }, + { "item": "condom", "prob": 10 }, { "item": "labmap", "prob": 20 }, [ "scorecard", 20 ] ] @@ -190,7 +190,7 @@ { "item": "money_ten", "prob": 100, "count": [ 5, 10 ] }, { "item": "money_twenty", "prob": 100, "count": [ 5, 10 ] }, { "group": "discount_cards", "prob": 60, "count": [ 2, 5 ] }, - { "item": "condom", "prob": 1 }, + { "item": "condom", "prob": 10 }, { "item": "labmap", "prob": 20 }, [ "scorecard", 5 ] ] @@ -208,7 +208,7 @@ { "item": "coin_quarter", "prob": 10, "count": [ 1, 2 ] }, { "item": "coin_nickel", "prob": 10, "count": [ 1, 2 ] }, { "group": "discount_cards", "prob": 40, "count": [ 1, 3 ] }, - { "item": "condom", "prob": 1 }, + { "item": "condom", "prob": 10 }, [ "scorecard", 20 ] ] }, @@ -225,7 +225,7 @@ { "item": "coin_quarter", "prob": 10, "count": [ 1, 2 ] }, { "item": "coin_nickel", "prob": 10, "count": [ 1, 2 ] }, { "group": "discount_cards", "prob": 40, "count": [ 1, 3 ] }, - { "item": "condom", "prob": 1 }, + { "item": "condom", "prob": 10 }, [ "scorecard", 20 ] ] }, From ae2991d58a9c3024811395bb6892979d8c9fe6c6 Mon Sep 17 00:00:00 2001 From: Termineitor244 <53200489+Termineitor244@users.noreply.github.com> Date: Wed, 17 Mar 2021 13:10:58 -0600 Subject: [PATCH 064/453] [Magiclysm] Less HP consumed at higher levels of Sacrificial Healing (#48097) --- data/mods/Magiclysm/Spells/druid.json | 2 ++ 1 file changed, 2 insertions(+) diff --git a/data/mods/Magiclysm/Spells/druid.json b/data/mods/Magiclysm/Spells/druid.json index 0a01dbd5d66f7..5acc79f74e387 100644 --- a/data/mods/Magiclysm/Spells/druid.json +++ b/data/mods/Magiclysm/Spells/druid.json @@ -298,6 +298,8 @@ "difficulty": 5, "base_casting_time": 400, "base_energy_cost": 35, + "final_energy_cost": 20, + "energy_increment": -1.5, "max_level": 10, "min_damage": -4, "max_damage": -12, From 198eb2de393562f5871b3d52718f54827ab19285 Mon Sep 17 00:00:00 2001 From: Maleclypse <54345792+Maleclypse@users.noreply.github.com> Date: Thu, 18 Mar 2021 14:58:57 -0500 Subject: [PATCH 065/453] Ki strike scroll (#47962) --- data/mods/MMA/item_groups.json | 5 +++++ data/mods/MMA/martial.json | 24 ++++++++++++++++++++++++ data/mods/MMA/spells.json | 16 ++++++++++++++++ 3 files changed, 45 insertions(+) create mode 100644 data/mods/MMA/spells.json diff --git a/data/mods/MMA/item_groups.json b/data/mods/MMA/item_groups.json index c48fb030c40ac..aa9d2086c1cbc 100644 --- a/data/mods/MMA/item_groups.json +++ b/data/mods/MMA/item_groups.json @@ -20,6 +20,11 @@ [ "manual_mma_hylian", 1 ] ] }, + { + "id": "museum_misc", + "type": "item_group", + "items": [ [ "ki_strike_scroll", 3 ] ] + }, { "type": "item_group", "id": "book_military", diff --git a/data/mods/MMA/martial.json b/data/mods/MMA/martial.json index edfcfc14ff1cd..e6dfff170ef7b 100644 --- a/data/mods/MMA/martial.json +++ b/data/mods/MMA/martial.json @@ -88,5 +88,29 @@ "name": { "str_sp": "Reaping Talons" }, "description": "This book contains the teaching of the Tiger Claw discipline.", "martial_art": "style_mma_tiger_claw" + }, + { + "abstract": "scroll_martial_base", + "type": "TOOL", + "name": { "str": "scroll abstract" }, + "weight": "415 g", + "volume": "250 ml", + "material": [ "paper" ], + "symbol": "!", + "looks_like": "manual_dragon", + "color": "white", + "flags": [ "NO_SALVAGE" ] + }, + { + "id": "ki_strike_scroll", + "copy-from": "scroll_martial_base", + "type": "TOOL", + "name": { "str": "dragon hand scroll" }, + "description": "Focus your ki into magical attacks.", + "price_postapoc": 12000, + "use_action": { "type": "countdown", "name": "Unroll", "message": "You unroll the dragon scroll…" }, + "countdown_interval": 1, + "countdown_destroy": true, + "countdown_action": { "type": "cast_spell", "spell_id": "learn_ki_strike", "no_fail": true, "level": 0 } } ] diff --git a/data/mods/MMA/spells.json b/data/mods/MMA/spells.json new file mode 100644 index 0000000000000..11045438411d7 --- /dev/null +++ b/data/mods/MMA/spells.json @@ -0,0 +1,16 @@ +[ + { + "type": "SPELL", + "id": "learn_ki_strike", + "name": { "str": "Ki Strike Meditations" }, + "effect": "mutate", + "shape": "blast", + "effect_str": "KI_STRIKE", + "description": "This grants a specific mutation.", + "message": "You study the meditations until you could do them in your sleep…", + "min_damage": 10000, + "max_damage": 10000, + "flags": [ "SILENT", "MUTATE_TRAIT" ], + "valid_targets": [ "self", "ally" ] + } +] From 1eb2aa4cb6260e8f39402b80d4f2cdba046f4542 Mon Sep 17 00:00:00 2001 From: Maleclypse <54345792+Maleclypse@users.noreply.github.com> Date: Thu, 18 Mar 2021 14:59:44 -0500 Subject: [PATCH 066/453] Zombie Pig upgrades (#47860) --- data/json/emit.json | 8 +++++ data/json/monstergroups/zanimal_upgrades.json | 11 ++++++ data/json/monsters/mammal.json | 1 + data/json/monsters/zanimal_upgrade.json | 35 +++++++++++++++++++ data/json/monsters/zed-animal.json | 1 + doc/JSON_FLAGS.md | 1 + src/mondeath.cpp | 7 ++++ src/mondeath.h | 2 ++ src/monstergenerator.cpp | 2 ++ 9 files changed, 68 insertions(+) diff --git a/data/json/emit.json b/data/json/emit.json index bf9cd0d863dc0..3268490447224 100644 --- a/data/json/emit.json +++ b/data/json/emit.json @@ -72,6 +72,14 @@ "intensity": 3, "qty": 18 }, + { + "id": "emit_tear_gas_blast", + "type": "emit", + "//": "Large blast of tear gas (example: tear gas canister)", + "field": "fd_tear_gas", + "intensity": 3, + "qty": 200 + }, { "id": "emit_toxic_blast", "type": "emit", diff --git a/data/json/monstergroups/zanimal_upgrades.json b/data/json/monstergroups/zanimal_upgrades.json index 4a0babf23e122..b89ece045da5a 100644 --- a/data/json/monstergroups/zanimal_upgrades.json +++ b/data/json/monstergroups/zanimal_upgrades.json @@ -10,6 +10,17 @@ { "monster": "mon_zombie_dog_acidic", "freq": 45, "cost_multiplier": 2 } ] }, + { + "type": "monstergroup", + "name": "GROUP_ZOMBIE_PIG_UPGRADE", + "default": "mon_zombie_pig", + "//": "No bionics or fungal", + "monsters": [ + { "monster": "mon_zombie_pig", "freq": 45, "cost_multiplier": 5 }, + { "monster": "mon_zpig_brute", "freq": 45, "cost_multiplier": 2 }, + { "monster": "mon_zombie_pig_gas", "freq": 45, "cost_multiplier": 2 } + ] + }, { "type": "monstergroup", "name": "GROUP_ZOLF_UPGRADE", diff --git a/data/json/monsters/mammal.json b/data/json/monsters/mammal.json index 36ffc0328c4c4..8e95ba5dde011 100644 --- a/data/json/monsters/mammal.json +++ b/data/json/monsters/mammal.json @@ -231,6 +231,7 @@ "fear_triggers": [ "SOUND", "PLAYER_CLOSE" ], "placate_triggers": [ "MEAT" ], "death_function": [ "NORMAL" ], + "zombify_into": "mon_zpig_brute", "special_attacks": [ [ "EAT_FOOD", 20 ] ], "flags": [ "SEES", "HEARS", "SMELLS", "PET_MOUNTABLE", "ANIMAL", "PATH_AVOID_DANGER_1", "WARM", "KEENNOSE" ] }, diff --git a/data/json/monsters/zanimal_upgrade.json b/data/json/monsters/zanimal_upgrade.json index 2ecb322e6a50d..8ce388e224e83 100644 --- a/data/json/monsters/zanimal_upgrade.json +++ b/data/json/monsters/zanimal_upgrade.json @@ -92,6 +92,41 @@ { "id": "scratch", "damage_max_instance": [ { "damage_type": "cut", "amount": 15, "armor_multiplier": 0.6 } ] } ] }, + { + "id": "mon_zpig_brute", + "type": "MONSTER", + "name": { "str": "skull pig" }, + "copy-from": "mon_zombie_pig", + "description": "This former wild boar appears to have been a truly massive specimen in life. Stretching eight to nine feet in length, the most arresting feature of this animal is that the enamel of its tusks has spread across its face leaving a skull-like appearance with deep-set eyeholes.", + "diff": 2, + "color": "red", + "proportional": { "hp": 1.5, "speed": 1.5, "attack_cost": 1.5 }, + "relative": { + "melee_dice": 1, + "melee_dice_sides": 5, + "melee_cut": 2, + "armor_bash": 4, + "armor_cut": 6, + "armor_bullet": 5, + "vision_night": 1 + }, + "special_attacks": [ [ "SMASH", 30 ], { "id": "impale" } ], + "extend": { "flags": [ "GROUP_BASH", "PUSH_VEH", "HIT_AND_RUN" ] } + }, + { + "id": "mon_zombie_pig_gas", + "type": "MONSTER", + "name": { "str": "trench pig" }, + "copy-from": "mon_zombie_pig", + "description": "Billowing clouds of yellow-streaked gas precede boar-shaped shadows. Glimpses of a zombie boar are quickly obscured by the gases leaving its body through open wounds.", + "diff": 5, + "color": "red", + "harvest": "exempt", + "emit_fields": [ { "emit_id": "emit_tear_gas_stream", "delay": "1 s" } ], + "death_function": [ "TEARBURST" ], + "special_attacks": [ { "id": "impale" } ], + "extend": { "flags": [ "HIT_AND_RUN" ] } + }, { "id": "mon_wolf_skeleton", "type": "MONSTER", diff --git a/data/json/monsters/zed-animal.json b/data/json/monsters/zed-animal.json index 2b52063c78e5c..21dd7c608a4ca 100644 --- a/data/json/monsters/zed-animal.json +++ b/data/json/monsters/zed-animal.json @@ -223,6 +223,7 @@ "anger_triggers": [ "PLAYER_WEAK", "PLAYER_CLOSE" ], "fear_triggers": [ "FIRE" ], "death_function": [ "NORMAL" ], + "upgrades": { "half_life": 20, "into_group": "GROUP_ZOMBIE_PIG_UPGRADE" }, "flags": [ "SEES", "HEARS", "SMELLS", "STUMBLES", "WARM", "KEENNOSE", "BASHES", "POISON", "NO_BREATHE", "REVIVES", "FILTHY" ], "//": "1d8->2d5, minor bonus over 1d9" }, diff --git a/doc/JSON_FLAGS.md b/doc/JSON_FLAGS.md index 733265f0e4f5a..527a5063091aa 100644 --- a/doc/JSON_FLAGS.md +++ b/doc/JSON_FLAGS.md @@ -898,6 +898,7 @@ Multiple death functions can be used. Not all combinations make sense. - ```NORMAL``` Drop a body, leave gibs. - ```RATKING``` Cure verminitis. - ```SMOKEBURST``` Explode like a huge smoke bomb. +- ```TEARBURST``` Explode like a huge tear gas bomb. - ```THING``` Turn into a full thing. - ```TRIFFID_HEART``` Destroys all roots. - ```VINE_CUT``` Kill adjacent vine if it's cut. diff --git a/src/mondeath.cpp b/src/mondeath.cpp index 605ba0349402e..a23e51f0b22d3 100644 --- a/src/mondeath.cpp +++ b/src/mondeath.cpp @@ -720,6 +720,13 @@ void mdeath::smokeburst( monster &z ) get_map().emit_field( z.pos(), emit_id( "emit_smoke_blast" ) ); } +void mdeath::tearburst( monster &z ) +{ + std::string explode = string_format( _( "a %s explode!" ), z.name() ); + sounds::sound( z.pos(), 24, sounds::sound_t::combat, explode, false, "explosion", "small" ); + get_map().emit_field( z.pos(), emit_id( "emit_tear_gas_blast" ) ); +} + void mdeath::fungalburst( monster &z ) { map &here = get_map(); diff --git a/src/mondeath.h b/src/mondeath.h index 79e289bbac656..a34c3b67088f4 100644 --- a/src/mondeath.h +++ b/src/mondeath.h @@ -66,6 +66,8 @@ void gas( monster &z ); void kill_breathers( monster &z ); // Explode like a huge smoke bomb. void smokeburst( monster &z ); +// Explode like a huge tear gas bomb. +void tearburst( monster &z ); // Explode releasing fungal haze. void fungalburst( monster &z ); // Snicker-snack! diff --git a/src/monstergenerator.cpp b/src/monstergenerator.cpp index fe1d75932681f..223489edcfe5a 100644 --- a/src/monstergenerator.cpp +++ b/src/monstergenerator.cpp @@ -527,6 +527,8 @@ void MonsterGenerator::init_death() death_map["BROKEN_AMMO"] = &mdeath::broken_ammo; // Explode like a huge smoke bomb. death_map["SMOKEBURST"] = &mdeath::smokeburst; + // Explode like a huge tear gas bomb. + death_map["TEARBURST"] = &mdeath::tearburst; // Explode with a cloud of fungal haze. death_map["FUNGALBURST"] = &mdeath::fungalburst; // Snicker-snack! From d09a5dd4832a5b08ef0ef0c3a48df697866b976c Mon Sep 17 00:00:00 2001 From: John Candlebury Date: Thu, 18 Mar 2021 14:01:07 -0600 Subject: [PATCH 067/453] Unhardcode default Scenario/Profession & Make random starts respect Scenario Blacklists (#47918) * Unhardcode default profession/scenario * Random starts respect scenario blacklist --- data/core/game_balance.json | 14 ++++++++++++++ src/newcharacter.cpp | 2 +- src/profession.cpp | 9 ++++++++- src/scenario.cpp | 3 ++- src/worldfactory.cpp | 2 +- 5 files changed, 26 insertions(+), 4 deletions(-) diff --git a/data/core/game_balance.json b/data/core/game_balance.json index dc2794d4782fa..d86b2352b0e91 100644 --- a/data/core/game_balance.json +++ b/data/core/game_balance.json @@ -188,6 +188,20 @@ "stype": "int", "value": 5 }, + { + "type": "EXTERNAL_OPTION", + "name": "GENERIC_PROFESSION_ID", + "info": "The profession selected by default in the character creator menu.", + "stype": "string_input", + "value": "unemployed" + }, + { + "type": "EXTERNAL_OPTION", + "name": "GENERIC_SCENARIO_ID", + "info": "The scenario selected by default in the character creator menu.", + "stype": "string_input", + "value": "evacuee" + }, { "type": "EXTERNAL_OPTION", "name": "WORKBENCH_ALL_OPTIONS", diff --git a/src/newcharacter.cpp b/src/newcharacter.cpp index 43c7c426324ea..bbfe516e17030 100644 --- a/src/newcharacter.cpp +++ b/src/newcharacter.cpp @@ -205,7 +205,7 @@ void avatar::randomize( const bool random_scenario, points_left &points, bool pl if( random_scenario ) { std::vector scenarios; for( const auto &scen : scenario::get_all() ) { - if( !scen.has_flag( flag_CHALLENGE ) && + if( !scen.has_flag( flag_CHALLENGE ) && !scen.scen_is_blacklisted() && ( !scen.has_flag( flag_CITY_START ) || cities_enabled ) ) { scenarios.emplace_back( &scen ); } diff --git a/src/profession.cpp b/src/profession.cpp index 130596909dbfa..7349369fa0551 100644 --- a/src/profession.cpp +++ b/src/profession.cpp @@ -7,6 +7,7 @@ #include #include +#include "game.h" #include "addiction.h" #include "avatar.h" #include "calendar.h" @@ -30,7 +31,6 @@ namespace { generic_factory all_profs( "profession" ); -const string_id generic_profession_id( "unemployed" ); } // namespace static class json_item_substitution @@ -238,6 +238,8 @@ void profession::load( const JsonObject &jo, const std::string & ) const profession *profession::generic() { + const string_id generic_profession_id( + get_option( "GENERIC_PROFESSION_ID" ) ); return &generic_profession_id.obj(); } @@ -333,6 +335,11 @@ void profession::check_definition() const bool profession::has_initialized() { + if( !g || g->new_game ) { + return false; + } + const string_id generic_profession_id( + get_option( "GENERIC_PROFESSION_ID" ) ); return generic_profession_id.is_valid(); } diff --git a/src/scenario.cpp b/src/scenario.cpp index f0afc2e829198..16a7caf257484 100644 --- a/src/scenario.cpp +++ b/src/scenario.cpp @@ -18,7 +18,6 @@ namespace { generic_factory all_scenarios( "scenario" ); -const string_id generic_scenario_id( "evacuee" ); } // namespace /** @relates string_id */ @@ -125,6 +124,8 @@ void scenario::load( const JsonObject &jo, const std::string & ) const scenario *scenario::generic() { + static const string_id generic_scenario_id( + get_option( "GENERIC_SCENARIO_ID" ) ); return &generic_scenario_id.obj(); } diff --git a/src/worldfactory.cpp b/src/worldfactory.cpp index 60a6592ebd239..fd7efe89a955b 100644 --- a/src/worldfactory.cpp +++ b/src/worldfactory.cpp @@ -1609,7 +1609,7 @@ void load_external_option( const JsonObject &jo ) } else { opt.setValue( "false" ); } - } else if( stype == "string" ) { + } else if( stype == "string" || stype == "string_input" ) { opt.setValue( jo.get_string( "value" ) ); } else { jo.throw_error( "Unknown or unsupported stype for external option", "stype" ); From f14723e0453981c312955c75d21571d9b927e0a3 Mon Sep 17 00:00:00 2001 From: anothersimulacrum Date: Tue, 16 Mar 2021 14:46:23 -0700 Subject: [PATCH 068/453] Show in vpart info when a wheel needs other wheels (#48088) This flag is purely cosmetic, but is required to show this info. --- data/json/obsolete.json | 2 +- data/json/vehicleparts/vehicle_parts.json | 12 +++++++++++- data/json/vehicleparts/vp_flags.json | 6 ++++++ data/json/vehicleparts/wheel.json | 18 +++++++++--------- doc/JSON_FLAGS.md | 1 + src/veh_type.cpp | 9 +++++++++ 6 files changed, 37 insertions(+), 11 deletions(-) diff --git a/data/json/obsolete.json b/data/json/obsolete.json index f1d06ff0d61b1..2e00607c3e08c 100644 --- a/data/json/obsolete.json +++ b/data/json/obsolete.json @@ -767,7 +767,7 @@ "removal": { "skills": [ [ "mechanics", 1 ] ], "time": "15 m", "qualities": [ { "id": "WRENCH", "level": 2 } ] }, "repair": { "skills": [ [ "mechanics", 2 ] ], "time": "15 m", "using": [ [ "welding_standard", 5 ] ] } }, - "flags": [ "WHEEL", "NEEDS_JACKING", "NEEDS_WHEEL_MOUNT_MEDIUM" ], + "flags": [ "WHEEL", "UNSTABLE_WHEEL", "NEEDS_JACKING", "NEEDS_WHEEL_MOUNT_MEDIUM" ], "damage_reduction": { "all": 66 } }, { diff --git a/data/json/vehicleparts/vehicle_parts.json b/data/json/vehicleparts/vehicle_parts.json index 3a78173645f3f..f986419fc7d46 100644 --- a/data/json/vehicleparts/vehicle_parts.json +++ b/data/json/vehicleparts/vehicle_parts.json @@ -111,7 +111,17 @@ "repair": { "skills": [ [ "mechanics", 1 ] ], "time": "20 s", "using": [ [ "adhesive", 1 ] ] } }, "breaks_into": "ig_vp_wood_plate", - "flags": [ "ENGINE", "BOARDABLE", "E_STARTS_INSTANTLY", "ANIMAL_CTRL", "HARNESS_any", "STEERABLE", "UNMOUNT_ON_DAMAGE", "WHEEL" ], + "flags": [ + "ENGINE", + "BOARDABLE", + "E_STARTS_INSTANTLY", + "ANIMAL_CTRL", + "HARNESS_any", + "STEERABLE", + "UNMOUNT_ON_DAMAGE", + "UNSTABLE_WHEEL", + "WHEEL" + ], "damage_reduction": { "all": 2 } }, { diff --git a/data/json/vehicleparts/vp_flags.json b/data/json/vehicleparts/vp_flags.json index 6822a4957e721..d30f0c77ee75a 100644 --- a/data/json/vehicleparts/vp_flags.json +++ b/data/json/vehicleparts/vp_flags.json @@ -157,6 +157,12 @@ "context": [ "vehicle_part" ], "info": "If your vehicle consists of a single tile, this wheel is enough to allow it to move." }, + { + "id": "UNSTABLE_WHEEL", + "type": "json_flag", + "context": [ "vehicle_part" ], + "info": "This wheel requires another wheel to be installed to be functional." + }, { "id": "STEERABLE", "type": "json_flag", diff --git a/data/json/vehicleparts/wheel.json b/data/json/vehicleparts/wheel.json index 4750cfb6e89a7..cb06c23df9413 100644 --- a/data/json/vehicleparts/wheel.json +++ b/data/json/vehicleparts/wheel.json @@ -150,7 +150,7 @@ "removal": { "skills": [ [ "mechanics", 2 ] ], "time": "30 m", "using": [ [ "vehicle_fasten", 1 ] ] }, "repair": { "skills": [ [ "mechanics", 3 ] ], "time": "60 m", "using": [ [ "welding_standard", 5 ] ] } }, - "flags": [ "WHEEL", "NEEDS_JACKING", "RAIL" ], + "flags": [ "WHEEL", "UNSTABLE_WHEEL", "NEEDS_JACKING", "RAIL" ], "damage_reduction": { "all": 66 } }, { @@ -197,7 +197,7 @@ "removal": { "skills": [ [ "mechanics", 3 ] ], "time": "30 m", "using": [ [ "vehicle_fasten", 1 ] ] }, "repair": { "skills": [ [ "mechanics", 6 ] ], "time": "60 m", "using": [ [ "welding_standard", 5 ] ] } }, - "flags": [ "ARMOR", "OBSTACLE", "WHEEL", "NEEDS_JACKING", "STEERABLE" ], + "flags": [ "ARMOR", "OBSTACLE", "WHEEL", "UNSTABLE_WHEEL", "NEEDS_JACKING", "STEERABLE" ], "wheel_type": "rigid", "contact_area": 400, "damage_reduction": { "all": 280 } @@ -228,7 +228,7 @@ "removal": { "skills": [ [ "mechanics", 0 ] ], "time": "15 m", "using": [ [ "vehicle_fasten", 1 ] ] }, "repair": { "skills": [ [ "mechanics", 4 ] ], "time": "15 m", "using": [ [ "adhesive", 1 ], [ "plastics", 1 ] ] } }, - "flags": [ "WHEEL", "NEEDS_JACKING", "NEEDS_WHEEL_MOUNT_MEDIUM" ], + "flags": [ "WHEEL", "UNSTABLE_WHEEL", "NEEDS_JACKING", "NEEDS_WHEEL_MOUNT_MEDIUM" ], "damage_reduction": { "bash": 20 } }, { @@ -268,7 +268,7 @@ "removal": { "skills": [ [ "mechanics", 0 ] ], "time": "20 m", "using": [ [ "vehicle_fasten", 1 ] ] }, "repair": { "skills": [ [ "mechanics", 5 ] ], "time": "20 m", "using": [ [ "adhesive", 1 ], [ "plastics", 1 ] ] } }, - "flags": [ "WHEEL", "NEEDS_JACKING", "NEEDS_WHEEL_MOUNT_HEAVY" ], + "flags": [ "WHEEL", "UNSTABLE_WHEEL", "NEEDS_JACKING", "NEEDS_WHEEL_MOUNT_HEAVY" ], "damage_reduction": { "all": 60, "cut": 30, "stab": 16 } }, { @@ -325,7 +325,7 @@ "removal": { "skills": [ [ "mechanics", 0 ] ], "time": "15 m", "using": [ [ "vehicle_fasten", 1 ] ] }, "repair": { "skills": [ [ "mechanics", 2 ] ], "time": "15 m", "using": [ [ "adhesive", 1 ], [ "plastics", 1 ] ] } }, - "flags": [ "WHEEL", "NEEDS_JACKING", "FOLDABLE", "NEEDS_WHEEL_MOUNT_LIGHT" ], + "flags": [ "WHEEL", "UNSTABLE_WHEEL", "NEEDS_JACKING", "FOLDABLE", "NEEDS_WHEEL_MOUNT_LIGHT" ], "damage_reduction": { "bash": 6 } }, { @@ -446,7 +446,7 @@ "removal": { "skills": [ [ "mechanics", 0 ] ], "time": "15 m", "using": [ [ "vehicle_fasten", 1 ] ] }, "repair": { "skills": [ [ "mechanics", 2 ] ], "time": "15 m", "using": [ [ "adhesive", 1 ], [ "plastics", 1 ] ] } }, - "flags": [ "WHEEL", "NEEDS_JACKING", "NEEDS_WHEEL_MOUNT_LIGHT" ], + "flags": [ "WHEEL", "UNSTABLE_WHEEL", "NEEDS_JACKING", "NEEDS_WHEEL_MOUNT_LIGHT" ], "damage_reduction": { "bash": 10 } }, { @@ -507,7 +507,7 @@ "removal": { "skills": [ [ "mechanics", 0 ] ], "time": "15 m", "using": [ [ "vehicle_wrench_2", 1 ] ] }, "repair": { "skills": [ [ "mechanics", 2 ] ], "time": "15 m", "using": [ [ "adhesive", 1 ], [ "plastics", 1 ] ] } }, - "flags": [ "WHEEL", "FOLDABLE", "NEEDS_WHEEL_MOUNT_LIGHT" ] + "flags": [ "WHEEL", "UNSTABLE_WHEEL", "FOLDABLE", "NEEDS_WHEEL_MOUNT_LIGHT" ] }, { "copy-from": "wheel_small_abstract", @@ -638,7 +638,7 @@ "removal": { "skills": [ [ "mechanics", 0 ] ], "time": "15 m", "using": [ [ "vehicle_fasten", 1 ] ] }, "repair": { "skills": [ [ "mechanics", 4 ] ], "time": "15 m", "using": [ [ "adhesive", 1 ], [ "plastics", 1 ] ] } }, - "flags": [ "WHEEL", "NEEDS_JACKING", "NEEDS_WHEEL_MOUNT_MEDIUM" ], + "flags": [ "WHEEL", "UNSTABLE_WHEEL", "NEEDS_JACKING", "NEEDS_WHEEL_MOUNT_MEDIUM" ], "damage_reduction": { "bash": 25 } }, { @@ -674,7 +674,7 @@ "rolling_resistance": 2.15, "wheel_type": "rigid", "contact_area": 60, - "flags": [ "WHEEL", "NEEDS_JACKING" ], + "flags": [ "WHEEL", "UNSTABLE_WHEEL", "NEEDS_JACKING" ], "damage_reduction": { "all": 14 } }, { diff --git a/doc/JSON_FLAGS.md b/doc/JSON_FLAGS.md index 527a5063091aa..9bf8162b1053b 100644 --- a/doc/JSON_FLAGS.md +++ b/doc/JSON_FLAGS.md @@ -1449,6 +1449,7 @@ Those flags are added by the game code to specific items (for example, that spec - ```SOLAR_PANEL``` Recharges vehicle batteries when exposed to sunlight. Has a 1 in 4 chance of being broken on car generation. - ```SPACE_HEATER``` There is separate command to toggle this part. - ```STABLE``` Similar to `WHEEL`, but if the vehicle is only a 1x1 section, this single wheel counts as enough wheels. +- ```UNSTABLE_WHEEL``` The opposite of `STABLE` - this will not provide for the wheeling needs of your vehicle if installed alone. - ```STEERABLE``` This wheel is steerable. - ```STEREO``` - ```TRANSFORM_TERRAIN``` Transform terrain (using rules defined in ```transform_terrain```). diff --git a/src/veh_type.cpp b/src/veh_type.cpp index 69d274810163e..006935b9c11a8 100644 --- a/src/veh_type.cpp +++ b/src/veh_type.cpp @@ -753,6 +753,15 @@ void vpart_info::check() debugmsg( "vehicle part %s has the WHEEL flag, but base item %s is not a wheel. " "THIS WILL CRASH!", part.id.str(), part.base_item.str() ); } + + if( part.has_flag( "WHEEL" ) && !part.has_flag( "UNSTABLE_WHEEL" ) && !part.has_flag( "STABLE" ) ) { + debugmsg( "Wheel '%s' lacks either 'UNSTABLE_WHEEL' or 'STABLE' flag.", vp.first.str() ); + } + + if( part.has_flag( "UNSTABLE_WHEEL" ) && part.has_flag( "STABLE" ) ) { + debugmsg( "Wheel '%s' cannot be both an 'UNSTABLE_WHEEL' and 'STABLE'.", vp.first.str() ); + } + for( auto &q : part.qualities ) { if( !q.first.is_valid() ) { debugmsg( "vehicle part %s has undefined tool quality %s", part.id.c_str(), q.first.c_str() ); From 9a2b76ed1798c8b92b7a153434b3f2b752cb2119 Mon Sep 17 00:00:00 2001 From: OromisElf Date: Thu, 18 Mar 2021 21:07:41 +0100 Subject: [PATCH 069/453] Electrical train (#48033) --- data/json/items/vehicle/motors.json | 2 +- .../mapgen/railroad/railroad_station.json | 6 +- data/json/vehicles/trains.json | 149 ++++++++++++++++++ 3 files changed, 155 insertions(+), 2 deletions(-) diff --git a/data/json/items/vehicle/motors.json b/data/json/items/vehicle/motors.json index 06e1d5ba31d6b..76740c02be3b5 100644 --- a/data/json/items/vehicle/motors.json +++ b/data/json/items/vehicle/motors.json @@ -81,7 +81,7 @@ "type": "GENERIC", "id": "motor_train1300", "name": { "str": "1300hp electric train engine" }, - "description": "A 1300hp extended-use electric engine. Normally used in trains.", + "description": "A 1300hp 3-phase 60 Hz electric engine. Normally used in trains.", "weight": "2000 kg", "volume": "250 L", "price": 120000, diff --git a/data/json/mapgen/railroad/railroad_station.json b/data/json/mapgen/railroad/railroad_station.json index ae692d222af8d..26559f054f17f 100644 --- a/data/json/mapgen/railroad/railroad_station.json +++ b/data/json/mapgen/railroad/railroad_station.json @@ -125,7 +125,11 @@ "7": { "item_group": "vending_food" }, "8": { "item_group": "vending_drink" }, "9": { "item_group": "vending_food" } - } + }, + "place_vehicles": [ + { "vehicle": "train_electrical_loco1300", "x": 5, "y": 90, "chance": 5, "rotation": 90, "status": -1 }, + { "vehicle": "train_electrical_loco1300", "x": 18, "y": 9, "chance": 12, "rotation": 270, "status": 1 } + ] } }, { diff --git a/data/json/vehicles/trains.json b/data/json/vehicles/trains.json index 44aba2971a6a2..b15175495f7dd 100644 --- a/data/json/vehicles/trains.json +++ b/data/json/vehicles/trains.json @@ -250,6 +250,155 @@ { "x": 0, "y": 0, "parts": [ { "part": "fuel_bunker", "fuel": "coal_lump" } ] } ] }, + { + "id": "train_electrical_loco1300", + "type": "vehicle", + "name": "Electrical Locomotive", + "parts": [ + { "x": 0, "y": 0, "parts": [ "hdframe_cross", "aisle_horizontal", "roof" ] }, + { "x": 0, "y": -1, "parts": [ "hdframe_cross", "rail_wheel_steerable", "aisle_horizontal", "roof" ] }, + { "x": 0, "y": -2, "parts": [ "hdframe_vertical_2", "windshield_vertical_left", "inboard_mirror" ] }, + { "x": 0, "y": 1, "parts": [ "hdframe_cross", "lit_aisle_vertical", "roof" ] }, + { "x": 0, "y": 2, "parts": [ "hdframe_cross", "aisle_horizontal", "roof" ] }, + { "x": 0, "y": 3, "parts": [ "hdframe_cross", "rail_wheel_steerable", "aisle_horizontal", "roof" ] }, + { "x": 0, "y": 4, "parts": [ "hdframe_vertical_2", "windshield_vertical_right", "inboard_mirror" ] }, + { "x": 1, "y": -2, "parts": [ "hdframe_vertical_2", "board_vertical_left" ] }, + { "x": 1, "y": -1, "parts": [ "hdframe_cross", "board_vertical_right", "dashboard", "roof" ] }, + { "x": 1, "y": 0, "parts": [ "hdframe_cross", "seat", "controls", "dashboard", "roof", "seatbelt" ] }, + { "x": 1, "y": 1, "parts": [ "hdframe_cross", "cam_control", "aisle_vertical", "dashboard", "roof" ] }, + { "x": 1, "y": 2, "parts": [ "hdframe_cross", "seat", "dashboard", "roof", "seatbelt" ] }, + { "x": 1, "y": 3, "parts": [ "hdframe_cross", "board_vertical_left", "dashboard", "roof" ] }, + { "x": 1, "y": 4, "parts": [ "hdframe_vertical_2", "board_vertical_right" ] }, + { "x": 2, "y": -2, "parts": [ "hdframe_nw", "halfboard_nw" ] }, + { "x": 2, "y": -1, "parts": [ "hdframe_se", "board_horizontal" ] }, + { "x": 2, "y": 0, "parts": [ "hdframe_cross", "windshield_horizontal_front_edge" ] }, + { "x": 2, "y": 1, "parts": [ "hdframe_cross", "windshield_horizontal_front" ] }, + { "x": 2, "y": 2, "parts": [ "hdframe_cross", "windshield_horizontal_front_edge" ] }, + { "x": 2, "y": 3, "parts": [ "hdframe_sw", "board_horizontal" ] }, + { "x": 2, "y": 4, "parts": [ "hdframe_ne", "halfboard_ne" ] }, + { "x": 3, "y": -1, "parts": [ "hdframe_nw", "halfboard_nw", "plating_steel" ] }, + { "x": 3, "y": 0, "parts": [ "hdframe_horizontal_2", "halfboard_horizontal_2", "headlight", "plating_steel" ] }, + { "x": 3, "y": 1, "parts": [ "hdframe_horizontal_2", "halfboard_horizontal_2", "plating_steel" ] }, + { "x": 3, "y": 2, "parts": [ "hdframe_horizontal_2", "halfboard_horizontal_2", "headlight", "plating_steel" ] }, + { "x": 3, "y": 3, "parts": [ "hdframe_ne", "halfboard_ne", "plating_steel" ] }, + { "x": -1, "y": -2, "parts": [ "hdframe_vertical_2", "board_vertical_left" ] }, + { "x": -1, "y": -1, "parts": [ "hdframe_cross", "aisle_horizontal", "roof" ] }, + { "x": -1, "y": 0, "parts": [ "hdframe_cross", "aisle_horizontal", "roof" ] }, + { "x": -1, "y": 1, "parts": [ "hdframe_cross", "aisle_vertical", "roof" ] }, + { "x": -1, "y": 2, "parts": [ "hdframe_cross", "aisle_horizontal", "roof" ] }, + { "x": -1, "y": 3, "parts": [ "hdframe_cross", "aisle_horizontal", "roof" ] }, + { "x": -1, "y": 4, "parts": [ "hdframe_vertical_2", "board_vertical_right" ] }, + { "x": -2, "y": -2, "parts": [ "hdframe_vertical_2", "board_vertical_T_left" ] }, + { "x": -2, "y": -1, "parts": [ "hdframe_cross", "board_horizontal", "roof" ] }, + { "x": -2, "y": 0, "parts": [ "hdframe_cross", "stowboard_horizontal", "roof" ] }, + { "x": -2, "y": 1, "parts": [ "hdframe_cross", "door_sliding", "roof" ] }, + { "x": -2, "y": 2, "parts": [ "hdframe_cross", "stowboard_horizontal", "roof" ] }, + { "x": -2, "y": 3, "parts": [ "hdframe_cross", "board_horizontal", "roof" ] }, + { "x": -2, "y": 4, "parts": [ "hdframe_vertical_2", "board_vertical_T_right" ] }, + { "x": -3, "y": -2, "parts": [ "hdframe_vertical_2", "door_sliding", "door_motor" ] }, + { "x": -3, "y": -1, "parts": [ "hdframe_cross", "rail_wheel", "aisle_horizontal", "roof" ] }, + { "x": -3, "y": 0, "parts": [ "hdframe_cross", "aisle_horizontal", "roof" ] }, + { "x": -3, "y": 1, "parts": [ "hdframe_cross", "aisle_vertical", "roof" ] }, + { "x": -3, "y": 2, "parts": [ "hdframe_cross", "aisle_horizontal", "roof" ] }, + { "x": -3, "y": 3, "parts": [ "hdframe_cross", "rail_wheel", "aisle_horizontal", "roof" ] }, + { "x": -3, "y": 4, "parts": [ "hdframe_vertical_2", "door_sliding", "door_motor" ] }, + { "x": -4, "y": -2, "parts": [ "hdframe_vertical_2", "board_vertical_T_left" ] }, + { "x": -4, "y": -1, "parts": [ "hdframe_cross", "board_horizontal", "roof" ] }, + { "x": -4, "y": 0, "parts": [ "hdframe_cross", "board_ne", "roof" ] }, + { "x": -4, "y": 1, "parts": [ "hdframe_cross", "lit_aisle_vertical", "roof" ] }, + { "x": -4, "y": 2, "parts": [ "hdframe_cross", "board_nw", "roof" ] }, + { "x": -4, "y": 3, "parts": [ "hdframe_cross", "board_horizontal", "roof" ] }, + { "x": -4, "y": 4, "parts": [ "hdframe_vertical_2", "board_vertical_T_right" ] }, + { "x": -5, "y": -2, "parts": [ "hdframe_vertical_2", "board_vertical_left" ] }, + { + "x": -5, + "y": -1, + "parts": [ "hdframe_cross", "engine_electric_train", "large_storage_battery", "spring_plate", "roof" ] + }, + { "x": -5, "y": 0, "parts": [ "hdframe_cross", "board_vertical_right", "roof" ] }, + { "x": -5, "y": 1, "parts": [ "hdframe_cross", "aisle_vertical", "roof" ] }, + { "x": -5, "y": 2, "parts": [ "hdframe_cross", "board_vertical_left", "roof" ] }, + { "x": -5, "y": 3, "parts": [ "hdframe_cross", "large_storage_battery", "spring_plate", "roof" ] }, + { "x": -5, "y": 4, "parts": [ "hdframe_vertical_2", "board_vertical_right" ] }, + { "x": -6, "y": -2, "parts": [ "hdframe_vertical_2", "board_vertical_left" ] }, + { + "x": -6, + "y": -1, + "parts": [ "hdframe_cross", "engine_electric_train", "large_storage_battery", "spring_plate", "roof" ] + }, + { "x": -6, "y": 0, "parts": [ "hdframe_cross", "board_vertical_right", "roof" ] }, + { "x": -6, "y": 1, "parts": [ "hdframe_cross", "aisle_vertical", "roof" ] }, + { "x": -6, "y": 2, "parts": [ "hdframe_cross", "board_vertical_left", "roof" ] }, + { + "x": -6, + "y": 3, + "parts": [ "hdframe_cross", "engine_electric_train", "large_storage_battery", "spring_plate", "roof" ] + }, + { "x": -6, "y": 4, "parts": [ "hdframe_vertical_2", "board_vertical_right" ] }, + { "x": -7, "y": -2, "parts": [ "hdframe_vertical_2", "board_vertical_T_left" ] }, + { "x": -7, "y": -1, "parts": [ "hdframe_cross", "board_horizontal", "roof" ] }, + { "x": -7, "y": 0, "parts": [ "hdframe_cross", "board_se", "roof" ] }, + { "x": -7, "y": 1, "parts": [ "hdframe_cross", "lit_aisle_vertical", "roof" ] }, + { "x": -7, "y": 2, "parts": [ "hdframe_cross", "board_sw", "roof" ] }, + { "x": -7, "y": 3, "parts": [ "hdframe_cross", "board_horizontal", "roof" ] }, + { "x": -7, "y": 4, "parts": [ "hdframe_vertical_2", "board_vertical_T_right" ] }, + { "x": -8, "y": -2, "parts": [ "hdframe_vertical_2", "door_sliding", "door_motor" ] }, + { "x": -8, "y": -1, "parts": [ "hdframe_cross", "rail_wheel", "aisle_horizontal", "roof" ] }, + { "x": -8, "y": 0, "parts": [ "hdframe_cross", "aisle_horizontal", "roof" ] }, + { "x": -8, "y": 1, "parts": [ "hdframe_cross", "aisle_vertical", "roof" ] }, + { "x": -8, "y": 2, "parts": [ "hdframe_cross", "aisle_horizontal", "roof" ] }, + { "x": -8, "y": 3, "parts": [ "hdframe_cross", "rail_wheel", "aisle_horizontal", "roof" ] }, + { "x": -8, "y": 4, "parts": [ "hdframe_vertical_2", "door_sliding", "door_motor" ] }, + { "x": -9, "y": -2, "parts": [ "hdframe_vertical_2", "board_vertical_T_left" ] }, + { "x": -9, "y": -1, "parts": [ "hdframe_cross", "board_horizontal", "roof" ] }, + { "x": -9, "y": 0, "parts": [ "hdframe_cross", "stowboard_horizontal", "roof" ] }, + { "x": -9, "y": 1, "parts": [ "hdframe_cross", "door_sliding", "roof" ] }, + { "x": -9, "y": 2, "parts": [ "hdframe_cross", "stowboard_horizontal", "roof" ] }, + { "x": -9, "y": 3, "parts": [ "hdframe_cross", "board_horizontal", "roof" ] }, + { "x": -9, "y": 4, "parts": [ "hdframe_vertical_2", "board_vertical_T_right" ] }, + { "x": -10, "y": -2, "parts": [ "hdframe_vertical_2", "board_vertical_left" ] }, + { "x": -10, "y": -1, "parts": [ "hdframe_cross", "aisle_horizontal", "roof" ] }, + { "x": -10, "y": 0, "parts": [ "hdframe_cross", "aisle_horizontal", "roof" ] }, + { "x": -10, "y": 1, "parts": [ "hdframe_cross", "aisle_vertical", "roof" ] }, + { "x": -10, "y": 2, "parts": [ "hdframe_cross", "aisle_horizontal", "roof" ] }, + { "x": -10, "y": 3, "parts": [ "hdframe_cross", "aisle_horizontal", "roof" ] }, + { "x": -10, "y": 4, "parts": [ "hdframe_vertical_2", "board_vertical_right" ] }, + { "x": -11, "y": -2, "parts": [ "hdframe_vertical_2", "windshield_vertical_left", "inboard_mirror" ] }, + { "x": -11, "y": -1, "parts": [ "hdframe_cross", "rail_wheel_steerable", "aisle_horizontal", "roof" ] }, + { "x": -11, "y": 0, "parts": [ "hdframe_cross", "aisle_horizontal", "roof" ] }, + { "x": -11, "y": 1, "parts": [ "hdframe_cross", "lit_aisle_vertical", "roof" ] }, + { "x": -11, "y": 2, "parts": [ "hdframe_cross", "aisle_horizontal", "roof" ] }, + { "x": -11, "y": 3, "parts": [ "hdframe_cross", "rail_wheel_steerable", "aisle_horizontal", "roof" ] }, + { "x": -11, "y": 4, "parts": [ "hdframe_vertical_2", "windshield_vertical_right", "inboard_mirror" ] }, + { "x": -12, "y": -2, "parts": [ "hdframe_vertical_2", "board_vertical_left" ] }, + { "x": -12, "y": -1, "parts": [ "hdframe_cross", "board_vertical_right", "dashboard", "roof" ] }, + { "x": -12, "y": 0, "parts": [ "hdframe_cross", "seat", "dashboard", "roof", "seatbelt" ] }, + { "x": -12, "y": 1, "parts": [ "hdframe_cross", "aisle_vertical", "cam_control", "dashboard", "roof" ] }, + { "x": -12, "y": 2, "parts": [ "hdframe_cross", "seat", "seatbelt", "dashboard", "controls", "roof" ] }, + { "x": -12, "y": 3, "parts": [ "hdframe_cross", "board_vertical_left", "dashboard", "roof" ] }, + { "x": -12, "y": 4, "parts": [ "hdframe_vertical_2", "board_vertical_right" ] }, + { "x": -13, "y": -2, "parts": [ "hdframe_sw", "halfboard_sw" ] }, + { "x": -13, "y": -1, "parts": [ "hdframe_ne", "board_horizontal" ] }, + { "x": -13, "y": 0, "parts": [ "hdframe_cross", "windshield_horizontal_front_edge" ] }, + { "x": -13, "y": 1, "parts": [ "hdframe_cross", "windshield_horizontal_front" ] }, + { "x": -13, "y": 2, "parts": [ "hdframe_cross", "windshield_horizontal_front_edge" ] }, + { "x": -13, "y": 3, "parts": [ "hdframe_nw", "board_horizontal" ] }, + { "x": -13, "y": 4, "parts": [ "hdframe_se", "halfboard_se" ] }, + { "x": -14, "y": -1, "parts": [ "hdframe_sw", "halfboard_sw", "plating_steel" ] }, + { + "x": -14, + "y": 0, + "parts": [ "hdframe_horizontal_2", "halfboard_horizontal_2", "headlight", "plating_steel" ] + }, + { "x": -14, "y": 1, "parts": [ "hdframe_horizontal_2", "halfboard_horizontal_2", "plating_steel" ] }, + { + "x": -14, + "y": 2, + "parts": [ "hdframe_horizontal_2", "halfboard_horizontal_2", "headlight", "plating_steel" ] + }, + { "x": -14, "y": 3, "parts": [ "hdframe_se", "halfboard_se", "plating_steel" ] } + ] + }, { "id": "trolley", "type": "vehicle", From d275507be59c984c731d7277742d5b44de0d8c29 Mon Sep 17 00:00:00 2001 From: souricelle <67675144+souricelle@users.noreply.github.com> Date: Thu, 18 Mar 2021 13:17:41 -0700 Subject: [PATCH 070/453] Feral Human Damage/Description Tweak (#48032) --- data/json/items/gun/monster_gun.json | 1 - data/json/monsters/feral_humans.json | 11 +++++++---- 2 files changed, 7 insertions(+), 5 deletions(-) diff --git a/data/json/items/gun/monster_gun.json b/data/json/items/gun/monster_gun.json index ac4bf56fabd71..dd0dc0fd09421 100644 --- a/data/json/items/gun/monster_gun.json +++ b/data/json/items/gun/monster_gun.json @@ -78,7 +78,6 @@ "ammo": [ "rock" ], "ammo_effects": [ "NO_PENETRATE_OBSTACLES", "NEVER_MISFIRES" ], "clip_size": 1, - "ranged_damage": { "damage_type": "bash", "amount": 4 }, "weight": "540 g", "volume": "210 ml", "longest_side": "75 mm", diff --git a/data/json/monsters/feral_humans.json b/data/json/monsters/feral_humans.json index 64cc7499f279f..cf3e8c9898528 100644 --- a/data/json/monsters/feral_humans.json +++ b/data/json/monsters/feral_humans.json @@ -3,7 +3,7 @@ "id": "mon_feral_human_pipe", "type": "MONSTER", "name": { "str": "feral human" }, - "description": "Pupils dilated and what remains to be seen of the iris and sclera are bloodshot. It still breathes but the zombies treat it like one of them.", + "description": "Their pupils are dilated and what remains to be seen of the iris and sclera are bloodshot. This pipe-wielding maniac still breathes, but the zombies treat them like one of their own.", "default_faction": "zombie", "looks_like": "chud", "bodytype": "human", @@ -17,7 +17,7 @@ "color": "magenta", "aggression": 30, "morale": 100, - "melee_skill": 2, + "melee_skill": 3, "melee_dice": 1, "melee_dice_sides": 3, "melee_cut": 0, @@ -62,6 +62,7 @@ { "id": "mon_feral_human_crowbar", "type": "MONSTER", + "description": "Their pupils are dilated and what remains to be seen of the iris and sclera are bloodshot. This crowbar-wielding maniac still breathes, but the zombies treat them like one of their own.", "copy-from": "mon_feral_human_pipe", "melee_dice": 2, "melee_dice_sides": 6, @@ -70,9 +71,11 @@ { "id": "mon_feral_human_axe", "type": "MONSTER", + "description": "Their pupils are dilated and what remains to be seen of the iris and sclera are bloodshot. This axe-wielding maniac still breathes, but the zombies treat them like one of their own.", "copy-from": "mon_feral_human_pipe", - "melee_dice": 3, - "melee_dice_sides": 8, + "melee_dice": 2, + "melee_dice_sides": 7, + "melee_cut": 9, "death_drops": "feral_humans_death_drops_axe" } ] From 5066405dcad7c845464e19bac5a6c43c37b3dd51 Mon Sep 17 00:00:00 2001 From: OromisElf Date: Thu, 18 Mar 2021 21:22:44 +0100 Subject: [PATCH 071/453] updated talk_tags to contain more swears (#47215) --- data/json/npcs/talk_tags.json | 86 +++++++++++++++++++++++++++++++++++ 1 file changed, 86 insertions(+) diff --git a/data/json/npcs/talk_tags.json b/data/json/npcs/talk_tags.json index 148a71851d38e..d8e92c0d6ab68 100644 --- a/data/json/npcs/talk_tags.json +++ b/data/json/npcs/talk_tags.json @@ -105,6 +105,75 @@ "category": "", "//": "generic negative/hostile pronouns", "text": [ + "airhead", + "arse", + "ass", + "assclown", + "assface", + "asstown", + "asswagon", + "bitch", + "bootlicker", + "bugger", + "butchery refuse", + "butthead", + "butt-licker", + "chucklefuck", + "coward", + "cuck", + "cunt", + "damn ", + "damned ", + "dildo", + "dimwit", + "dog", + "dumbshit", + "dumpster", + "dumpster fire", + "dunderfuck", + "effing ", + "emergency ration", + "empty headed ", + "expendable ", + "fart", + "fat-ass", + "frail-ass ", + "frigger", + "fungus eater", + "goddamn ", + "good for nothing", + "inbred", + "lazy", + "lazy ass", + "limp-dick", + "low-life", + "meat face", + "mi-go hugger", + "mushy pizza", + "pissbrain", + "pool noodle", + "prick", + "pussy", + "shitweasel", + "slime hugger", + "smooth brain", + "snowflake", + "toilet licker", + "tool", + "trash", + "turd", + "twat", + "twerp", + "useless", + "wanker", + "waste", + "waste of ammo", + "weapon holder", + "weiner", + "weird ", + "wet sandwich", + "wet sock", + "z fodder", " ", "asshat", "asswipe", @@ -190,6 +259,22 @@ "category": "", "//": "Swears and curses used to emphasize unpleasant events", "text": [ + "ARGH", + "aw fuck", + "balls", + "can't believe it", + "crapper", + "feck", + "For serious?", + "frigg", + "heavens", + "heck", + "hell", + "my luck", + "shards and shatters", + "the audacity", + "the worst!", + "what", "darn", "fuck", "goddamn", @@ -472,6 +557,7 @@ "category": "", "//": "Generic terms of emphasis", "text": [ + "ass-shatteringly", "extremely", "greatly", "highly", From 673c7e95a800abac4bb01a6cf2469c9726d6a942 Mon Sep 17 00:00:00 2001 From: Saicchi <47158232+Saicchi@users.noreply.github.com> Date: Thu, 18 Mar 2021 17:23:28 -0300 Subject: [PATCH 072/453] Better debug learn spell menu (#47946) MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Co-authored-by: Jianxiang Wang (王健翔) --- data/raw/keybindings.json | 21 ++ src/debug_menu.cpp | 655 ++++++++++++++++++++++++++++++++++---- src/debug_menu.h | 6 +- src/magic.cpp | 14 +- src/magic.h | 15 +- src/output.cpp | 4 +- src/output.h | 2 +- 7 files changed, 647 insertions(+), 70 deletions(-) diff --git a/data/raw/keybindings.json b/data/raw/keybindings.json index e69fade2e05bf..b7aebe96d383d 100644 --- a/data/raw/keybindings.json +++ b/data/raw/keybindings.json @@ -2243,6 +2243,27 @@ "category": "DEFAULTMODE", "id": "debug_radiation" }, + { + "type": "keybinding", + "category": "DEBUG_SPELLS", + "id": "TOGGLE_ALL_SPELL", + "name": "Toggle all spells", + "bindings": [ { "input_method": "keyboard_any", "key": "t" } ] + }, + { + "type": "keybinding", + "category": "DEBUG_SPELLS", + "id": "UNLEARN_SPELL", + "name": "Unlearn a spell", + "bindings": [ { "input_method": "keyboard_any", "key": "u" } ] + }, + { + "type": "keybinding", + "category": "DEBUG_SPELLS", + "id": "SHOW_ONLY_LEARNED", + "name": "Show only learned", + "bindings": [ { "input_method": "keyboard_any", "key": "a" } ] + }, { "type": "keybinding", "name": "Switch Sidebar Style", diff --git a/src/debug_menu.cpp b/src/debug_menu.cpp index a5d7d4767bd3c..90f149caf6292 100644 --- a/src/debug_menu.cpp +++ b/src/debug_menu.cpp @@ -72,6 +72,7 @@ #include "monstergenerator.h" #include "morale_types.h" #include "mtype.h" +#include "mutation.h" #include "npc.h" #include "npc_class.h" #include "omdata.h" @@ -112,6 +113,7 @@ static const efftype_id effect_flu( "flu" ); static const mtype_id mon_generator( "mon_generator" ); +static const trait_id trait_NONE( "NONE" ); static const trait_id trait_ASTHMA( "ASTHMA" ); #if defined(TILES) @@ -186,8 +188,7 @@ std::string enum_to_string( debug_menu::debug_menu case debug_menu::debug_menu_index::DISPLAY_REACHABILITY_ZONES: return "DISPLAY_REACHABILITY_ZONES"; case debug_menu::debug_menu_index::DISPLAY_RADIATION: return "DISPLAY_RADIATION"; case debug_menu::debug_menu_index::HOUR_TIMER: return "HOUR_TIMER"; - case debug_menu::debug_menu_index::LEARN_SPELLS: return "LEARN_SPELLS"; - case debug_menu::debug_menu_index::LEVEL_SPELLS: return "LEVEL_SPELLS"; + case debug_menu::debug_menu_index::CHANGE_SPELLS: return "CHANGE_SPELLS"; case debug_menu::debug_menu_index::TEST_MAP_EXTRA_DISTRIBUTION: return "TEST_MAP_EXTRA_DISTRIBUTION"; case debug_menu::debug_menu_index::NESTED_MAPGEN: return "NESTED_MAPGEN"; case debug_menu::debug_menu_index::VEHICLE_BATTERY_CHARGE: return "VEHICLE_BATTERY_CHARGE"; @@ -231,10 +232,8 @@ static int player_uilist() { uilist_entry( debug_menu_index::SET_AUTOMOVE, true, 'a', _( "Set automove route" ) ) }, }; if( !spell_type::get_all().empty() ) { - uilist_initializer.emplace_back( uilist_entry( debug_menu_index::LEARN_SPELLS, true, 'S', - _( "Learn all spells" ) ) ); - uilist_initializer.emplace_back( uilist_entry( debug_menu_index::LEVEL_SPELLS, true, 'L', - _( "Level a spell" ) ) ); + uilist_initializer.emplace_back( uilist_entry( debug_menu_index::CHANGE_SPELLS, true, 'S', + _( "Change spells" ) ) ); } return uilist( _( "Player…" ), uilist_initializer ); @@ -422,6 +421,592 @@ static cata::optional debug_menu_uilist( bool display_all_entr } } +static void spell_description( + std::tuple &spl_data, int width, Character &chrc ) +{ + std::ostringstream description; + + const int spl_level = std::get<1>( spl_data ); + spell spl( std::get<0>( spl_data ).id ); + spl.set_level( spl_level ); + + nc_color gray = c_light_gray; + nc_color yellow = c_yellow; + nc_color light_green = c_light_green; + + // # spell_id + description << colorize( string_format( "# %s", spl.id().str() ), c_cyan ) << '\n'; + + // Name: spell name + description << string_format( _( "Name: %1$s" ), colorize( spl.name(), c_white ) ) << '\n'; + + + // Class: Spell Class + description << string_format( _( "Class: %1$s" ), colorize( spl.spell_class() == trait_NONE ? + _( "Classless" ) : spl.spell_class()->name(), + yellow ) ) << "\n"; + + // Spell description + description << spl.description() << '\n'; + + // Spell Casting flags + description << spell_desc::enumerate_spell_data( spl ) << '\n'; + + // Spell Level: 0 / 0 (MAX) + description << string_format( + //~ %1$s - spell current level, %2$s - spell max level, %3$s - is max level + _( "Spell Level: %1$s / %2$d %3$s" ), + spl_level == -1 ? _( "Unlearned" ) : std::to_string( spl_level ), + spl.get_max_level(), + spl_level == spl.get_max_level() ? _( "(MAX)" ) : "" ) << '\n'; + + // Difficulty: 0 ( 0.0 % Failure Chance) + description << string_format( + //~ %1$d - difficulty, %2$s - failure chance + _( "Difficulty: %1$d ( %2$s )" ), + spl.get_difficulty(), spl.colorized_fail_percent( chrc ) ) << '\n'; + + + const std::string impeded = _( "(impeded)" ); + + // Casting Cost: 0 (impeded) ( 0 current ) + description << string_format( + //~ %1$s - energy cost, %2$s - is casting impeded, %3$s - current character energy + _( "Casting Cost: %1$s %2$s ( %3$s current ) " ), + spl.energy_cost_string( chrc ), + spell_desc::energy_cost_encumbered( spl, chrc ) ? impeded : "", + spl.energy_cur_string( chrc ) ) << '\n'; + + // Casting Time: 0 (impeded) + description << string_format( + //~ %1$s - cast time, %2$s - is casting impeded, %3$s - casting base time + _( "Casting Time: %1$s %2$s ( %3$s base time ) " ), + to_string( time_duration::from_moves( spl.casting_time( chrc ) ) ), + spell_desc::casting_time_encumbered( spl, chrc ) ? impeded : "", + to_string( time_duration::from_moves( std::get<0>( spl_data ).base_casting_time ) ) ) << '\n'; + + std::string targets; + if( spl.is_valid_target( spell_target::none ) ) { + targets = _( "self" ); + } else { + targets = spl.enumerate_targets(); + } + description << string_format( _( "Valid Targets: %1$s" ), targets ) << '\n'; + + std::string target_ids = spl.list_targeted_monster_names(); + if( !target_ids.empty() ) { + description << string_format( _( "Only affects the monsters: %1$s" ), target_ids ) << '\n'; + } + + const int damage = spl.damage(); + const std::string spl_eff = spl.effect(); + std::string damage_string; + std::string range_string; + std::string aoe_string; + // if it's any type of attack spell, the stats are normal. + if( spl_eff == "attack" ) { + if( damage > 0 ) { + std::string dot_string; + if( spl.damage_dot() ) { + //~ amount of damage per second, abbreviated + dot_string = string_format( _( ", %1$d/sec" ), spl.damage_dot() ); + } + damage_string = string_format( _( "Damage: %1$s %2$s%3$s" ), spl.damage_string(), + spl.damage_type_string(), dot_string ); + damage_string = colorize( damage_string, spl.damage_type_color() ); + } else if( damage < 0 ) { + damage_string = string_format( _( "Healing: %1$s" ), colorize( spl.damage_string(), + light_green ) ); + } + + if( spl.aoe() > 0 ) { + std::string aoe_string_temp = _( "Spell Radius" ); + std::string degree_string; + if( spl.shape() == spell_shape::cone ) { + aoe_string_temp = _( "Cone Arc" ); + degree_string = _( "degrees" ); + } else if( spl.shape() == spell_shape::line ) { + aoe_string_temp = _( "Line Width" ); + } + aoe_string = string_format( _( "%1$s: %2$d %3$s" ), aoe_string_temp, spl.aoe(), degree_string ); + } + + } else if( spl_eff == "teleport_random" ) { + if( spl.aoe() > 0 ) { + aoe_string = string_format( _( "Variance: %1$d" ), spl.aoe() ); + } + + } else if( spl_eff == "spawn_item" ) { + damage_string = string_format( _( "Spawn %1$d %2$s" ), spl.damage(), + item::nname( itype_id( spl.effect_data() ), spl.damage() ) ); + + } else if( spl_eff == "summon" ) { + std::string monster_name = "FIXME"; + if( spl.has_flag( spell_flag::SPAWN_GROUP ) ) { + // TODO: Get a more user-friendly group name + if( MonsterGroupManager::isValidMonsterGroup( mongroup_id( spl.effect_data() ) ) ) { + monster_name = string_format( _( "from %1$s" ), spl.effect_data() ); + } else { + debugmsg( "Unknown monster group: %s", spl.effect_data() ); + } + } else { + monster_name = monster( mtype_id( spl.effect_data() ) ).get_name(); + } + damage_string = string_format( _( "Summon: %1$d %2$s" ), spl.damage(), monster_name ); + aoe_string = string_format( _( "Spell Radius: %1$d" ), spl.aoe() ); + + } else if( spl_eff == "targeted_polymorph" ) { + std::string monster_name = spl.effect_data(); + if( spl.has_flag( spell_flag::POLYMORPH_GROUP ) ) { + // TODO: Get a more user-friendly group name + if( MonsterGroupManager::isValidMonsterGroup( mongroup_id( spl.effect_data() ) ) ) { + monster_name = _( "random creature" ); + } else { + debugmsg( "Unknown monster group: %s", spl.effect_data() ); + } + } else if( monster_name.empty() ) { + monster_name = _( "random creature" ); + } else { + monster_name = mtype_id( spl.effect_data() )->nname(); + } + damage_string = string_format( _( "Targets under: %1$dhp become a %2$s" ), spl.damage(), + monster_name ); + + } else if( spl_eff == "ter_transform" ) { + aoe_string = string_format( "Spell Radius: %1$s", spl.aoe_string() ); + + } else if( spl_eff == "banishment" ) { + damage_string = string_format( _( "Damage: %1$s %2$s" ), spl.damage_string(), + spl.damage_type_string() ); + if( spl.aoe() > 0 ) { + aoe_string = string_format( _( "Spell Radius: %1$d" ), spl.aoe() ); + } + } + + // Range / AOE in two columns + description << string_format( _( "Range: %1$s" ), + spl.range() <= 0 ? _( "self" ) : std::to_string( spl.range() ) ) << '\n'; + + + description << aoe_string << '\n'; + + // One line for damage / healing / spawn / summon effect + description << damage_string << '\n'; + + // todo: damage over time here, when it gets implemented + + // Show duration for spells that endure + if( spl.duration() > 0 || spl.has_flag( spell_flag::PERMANENT ) ) { + description << string_format( _( "Duration: %1$s" ), spl.duration_string() ) << '\n'; + } + + // helper function for printing tool and item component requirement lists + const auto print_vec_string = [&]( const std::vector &vec ) { + for( const std::string &line_str : vec ) { + description << line_str << '\n'; + } + }; + + if( spl.has_components() ) { + if( !spl.components().get_components().empty() ) { + print_vec_string( spl.components().get_folded_components_list( width - 2, gray, + chrc.crafting_inventory(), return_true ) ); + } + if( !( spl.components().get_tools().empty() && spl.components().get_qualities().empty() ) ) { + print_vec_string( spl.components().get_folded_tools_list( width - 2, gray, + chrc.crafting_inventory() ) ); + } + } + + std::get<2>( spl_data ) = description.str(); +} + +void change_spells( Character &character ) +{ + if( spell_type::get_all().empty() ) { + add_msg( m_info, _( "There are no spells to change." ) ); + return; + } + + static character_id last_char_id = character.getID(); + + using spell_tuple = std::tuple; + const size_t spells_all_size = spell_type::get_all().size(); + // all spells with cached string list + // the string is rebuilt every time it's empty or its level changed + static std::vector spells_all( spells_all_size ); + // maps which spells will show on the list + std::vector spells_relative( spells_all_size ); + + // number of spells changed, current map is invalid + bool rebuild_string_cache = false; + if( spells_all.size() != spells_all_size || last_char_id != character.getID() ) { + rebuild_string_cache = true; + last_char_id = character.getID(); + spells_all.clear(); + } + + int spname_len = 0; + for( size_t i = 0; i < spells_all_size; ++i ) { + if( rebuild_string_cache ) { + spells_all.emplace_back( spell_type{}, -1, std::string{} ); + std::get<2>( spells_all[i] ).clear(); + } + + if( std::get<0>( spells_all[i] ).id != spell_type::get_all()[i].id ) { + std::get<0>( spells_all[i] ) = spell_type::get_all()[i]; + std::get<1>( spells_all[i] ) = -1; + std::get<2>( spells_all[i] ).clear(); + } + + spells_relative[i] = &spells_all[i]; + + // get max spell name length + spname_len = std::max( spname_len, utf8_width( std::get<0>( spells_all[i] ).name.translated() ) ); + } + spname_len += 2; + + // fill the levels for spells the character knowns + for( const spell *sp : character.magic->get_spells() ) { + auto iterator = std::find_if( spells_all.begin(), + spells_all.end(), [&sp]( spell_tuple & spt ) -> bool { + return std::get<0>( spt ).id == sp->id(); + } ); + std::get<1>( spells_all[iterator - spells_all.begin()] ) = sp->get_level(); + std::get<2>( spells_all[iterator - spells_all.begin()] ).clear(); + } + + auto set_spell = [&character]( spell_type & splt, int spell_level ) { + if( spell_level == -1 ) { + character.magic->get_spellbook().erase( splt.id ); + return; + } else if( !character.magic->knows_spell( splt.id ) ) { + spell spl( splt.id ); + character.magic->get_spellbook().emplace( splt.id, spl ); + } + + character.magic->get_spell( splt.id ).set_exp( spell::exp_for_level( spell_level ) ); + }; + + ui_adaptor spellsui; + border_helper borders; + + struct win_info { + catacurses::window window; + border_helper::border_info *border = nullptr; + int width; + point start; + }; + + struct win_info w_name; + w_name.border = &borders.add_border(); + w_name.width = spname_len + 1; + w_name.start = point_zero; + + struct win_info w_level; + w_level.border = &borders.add_border(); + w_level.width = 11; + w_level.start = {w_name.width, 0}; + + struct win_info w_descborder; + w_descborder.border = &borders.add_border(); + + // desc is inside descborder with a padding of 2 characters + struct win_info w_desc; + + scrollbar scrllbr; + scrllbr.offset_x( 0 ).offset_y( 1 ).border_color( c_magenta ); + + spellsui.on_screen_resize( [&]( ui_adaptor & ui ) { + + w_descborder.start = {w_level.start.x + w_level.width, 0}; + w_descborder.width = TERMX - w_descborder.start.x; + + w_desc.width = w_descborder.width - 4; + w_desc.start = {w_descborder.start.x + 2, 1}; + + w_name.window = catacurses::newwin( TERMY, w_name.width, w_name.start ); + w_level.window = catacurses::newwin( TERMY, w_level.width, w_level.start ); + w_descborder.window = catacurses::newwin( TERMY, w_descborder.width, w_descborder.start ); + w_desc.window = catacurses::newwin( TERMY - 2, w_desc.width, w_desc.start ); + + w_name.border->set( w_name.start, { w_name.width, TERMY } ); + w_level.border->set( w_level.start, { w_level.width, TERMY } ); + w_descborder.border->set( w_descborder.start, { w_descborder.width, TERMY } ); + + scrllbr.viewport_size( TERMY - 2 ); + ui.position( point_zero, { TERMX, TERMY } ); + } ); + spellsui.mark_resize(); + + input_context ctxt( "DEBUG_SPELLS" ); + ctxt.register_action( "UNLEARN_SPELL" ); // Quickly unlearn a spell + ctxt.register_action( "TOGGLE_ALL_SPELL" ); // Cycle level on all spells in spells_relative + ctxt.register_action( "SHOW_ONLY_LEARNED" ); // Removes all unlearned spells in spells_relative + ctxt.register_cardinal(); // left and right change spell level + ctxt.register_action( "QUIT" ); + ctxt.register_action( "CONFIRM" ); // set a spell to a level + ctxt.register_action( "FILTER" ); + ctxt.register_action( "RESET_FILTER" ); + ctxt.register_action( "HELP_KEYBINDINGS" ); + + int spells_start = 0; + int spell_selected = 0; + std::string filterstring; + spellsui.on_redraw( [&]( const ui_adaptor & ) { + werase( w_name.window ); + werase( w_level.window ); + werase( w_descborder.window ); + werase( w_desc.window ); + + borders.draw_border( w_name.window, c_magenta ); + borders.draw_border( w_level.window, c_magenta ); + borders.draw_border( w_descborder.window, c_magenta ); + + center_print( w_name.window, 0, c_magenta, _( "<Spell Name>" ) ); + center_print( w_level.window, 0, c_magenta, _( "<Level>" ) ); + center_print( w_descborder.window, 0, c_magenta, _( "<Description>" ) ); + + nc_color magenta = c_magenta; + const std::string help_keybindings = string_format( + _( "<[%1$s] Keybindings>" ), + ctxt.get_desc( "HELP_KEYBINDINGS" ) ); + print_colored_text( w_descborder.window, + point( w_descborder.width - help_keybindings.length() + 42, TERMY - 1 ), + magenta, magenta, help_keybindings ); + + std::string help_filter; + if( filterstring.empty() ) { + help_filter = string_format( _( "<[%1$s] Filter>" ), + ctxt.get_desc( "FILTER" ) ); + } else { + help_filter = string_format( "<%s>", filterstring ); + } + + print_colored_text( w_name.window, point( 1, TERMY - 1 ), + magenta, magenta, help_filter ); + + const int relative_size = spells_relative.size(); + scrllbr.content_size( relative_size ); + scrllbr.viewport_pos( spell_selected ); + scrllbr.apply( w_name.window ); + + calcStartPos( spells_start, spell_selected, TERMY - 2, relative_size ); + + int line_number = 1; + for( int i = spells_start; i < relative_size; ++i ) { + if( line_number == TERMY - 1 ) { + break; + } + + const spell_type &splt = std::get<0>( *spells_relative[i] ); + const int &spell_level = std::get<1>( *spells_relative[i] ); + + nc_color spell_color = spell_level > -1 ? c_green : c_light_gray; + spell_color = i == spell_selected ? hilite( spell_color ) : spell_color; + + mvwprintz( w_name.window, point( 2, line_number ), + spell_color, splt.name.translated() ); + mvwprintz( w_level.window, point( 2, line_number++ ), spell_color, + _( "%1$-3d/%2$3d" ), spell_level, splt.max_level ); + } + + nc_color gray = c_light_gray; + print_colored_text( w_desc.window, point_zero, gray, gray, + std::get<2>( *spells_relative[spell_selected] ) ); + + wnoutrefresh( w_name.window ); + wnoutrefresh( w_level.window ); + wnoutrefresh( w_descborder.window ); + wnoutrefresh( w_desc.window ); + } ); + + auto update_description = [&]( bool force ) -> void { + if( force || std::get<2>( *spells_relative[spell_selected] ).empty() ) + { + spell_description( *spells_relative[spell_selected], w_desc.width, character ); + } + }; + + // keep the same spell selected + auto spell_middle_or_id = [&]( const spell_id & spellid ) -> void { + if( spellid.is_empty() ) + { + spell_selected = 0; + return; + } + + // in case we don't find anything, keep selection in the middle of screen + const size_t spells_relative_size = spells_relative.size(); + spell_selected = std::min( ( TERMY - 2 ) / 2, static_cast( spells_relative_size ) / 2 ); + for( size_t i = 0; i < spells_relative_size; ++i ) + { + if( std::get<0>( *spells_relative[i] ).id == spellid ) { + spell_selected = i; + break; + } + } + }; + + // reset spells_relative vector + auto reset_spells_relative = [&]() -> void { + for( spell_tuple &spt : spells_all ) + { + spells_relative.emplace_back( &spt ); + } + }; + + auto filter_spells = [&]( ) -> void { + const spell_id &spellid = std::get<0>( *spells_relative[spell_selected] ).id; + spells_relative.clear(); + if( filterstring.empty() ) + { + reset_spells_relative(); + } else + { + for( spell_tuple &spt : spells_all ) { + const spell_type &spl = std::get<0>( spt ); + if( lcmatch( spl.name.translated(), filterstring ) || + lcmatch( spl.id.str(), filterstring ) ) { + spells_relative.emplace_back( &spt ); + } + } + + // no spell found, reset relative list + if( spells_relative.empty() ) { + reset_spells_relative(); + popup( _( "Nothing found." ) ); + } + } + + spell_middle_or_id( spellid ); + }; + + auto toggle_all_spells = [&]( int level ) { + // -2 sets it to max level + for( spell_tuple *spt : spells_relative ) { + std::get<1>( *spt ) = level > -2 ? level : std::get<0>( *spt ).max_level; + set_spell( std::get<0>( *spt ), std::get<1>( *spt ) ); + std::get<2>( *spt ).clear(); + } + }; + + static spell_id last_selected_spellid; + spell_middle_or_id( last_selected_spellid ); + + // 0 -> turn off all spells + // 1 -> set all spells to level 0 + // 2 -> set all spells to their max level + int toggle_spells_state = 1; + + bool showing_only_learned = false; + + bool force_update_description = false; + + while( true ) { + update_description( force_update_description ); + force_update_description = false; + + ui_manager::redraw(); + const std::string action = ctxt.handle_input(); + + if( action == "QUIT" ) { + last_selected_spellid = std::get<0>( *spells_relative[spell_selected] ).id; + break; + + } else if( action == "FILTER" ) { + string_input_popup() + .title( _( "Filter:" ) ) + .width( 16 ) + .description( _( "Filter by spell name or id" ) ) + .edit( filterstring ); + + showing_only_learned = false; + filter_spells( ); + + } else if( action == "RESET_FILTER" ) { + showing_only_learned = false; + filterstring.clear(); + filter_spells(); + + } else if( action == "UP" ) { + if( !spell_selected ) { + spell_selected = spells_relative.size() - 1; + } else { + spell_selected--; + } + + } else if( action == "DOWN" ) { + spell_selected++; + if( static_cast( spell_selected ) == spells_relative.size() ) { + spell_selected = 0; + } + + } else if( action == "LEFT" ) { + int &spell_level = std::get<1>( *spells_relative[spell_selected] ); + spell_level = std::max( -1, spell_level - 1 ); + set_spell( std::get<0>( *spells_relative[spell_selected] ), spell_level ); + force_update_description = true; + + } else if( action == "RIGHT" ) { + int &spell_level = std::get<1>( *spells_relative[spell_selected] ); + spell_level = std::min( spell_level + 1, + std::get<0>( *spells_relative[spell_selected] ).max_level ); + set_spell( std::get<0>( *spells_relative[spell_selected] ), spell_level ); + force_update_description = true; + + } else if( action == "CONFIRM" ) { + int &spell_level = std::get<1>( *spells_relative[spell_selected] ); + query_int( spell_level, _( "Set spell level to? Currently: %1$d" ), spell_level ); + spell_level = clamp( spell_level, -1, std::get<0>( *spells_relative[spell_selected] ).max_level ); + set_spell( std::get<0>( *spells_relative[spell_selected] ), spell_level ); + force_update_description = true; + + } else if( action == "UNLEARN_SPELL" ) { + int &spell_level = std::get<1>( *spells_relative[spell_selected] ); + spell_level = -1; + set_spell( std::get<0>( *spells_relative[spell_selected] ), spell_level ); + force_update_description = true; + + } else if( action == "TOGGLE_ALL_SPELL" ) { + if( toggle_spells_state == 0 ) { + toggle_spells_state = 1; + toggle_all_spells( -1 ); // unlearn all spells + } else if( toggle_spells_state == 1 ) { + toggle_spells_state = 2; + toggle_all_spells( 0 ); // sets all spells to the minimum level + } else { + toggle_spells_state = 0; + toggle_all_spells( -2 ); // max level + } + + } else if( action == "SHOW_ONLY_LEARNED" ) { + showing_only_learned = !showing_only_learned; + + const spell_id &spellid = std::get<0>( *spells_relative[spell_selected] ).id; + spells_relative.clear(); + if( showing_only_learned ) { + for( spell_tuple &spt : spells_all ) { + if( std::get<1>( spt ) > -1 ) { + spells_relative.emplace_back( &spt ); + } + } + + if( spells_relative.empty() ) { + popup( _( "Nothing found." ) ); + showing_only_learned = false; + } + } + + if( !showing_only_learned ) { + reset_spells_relative(); + } + + spell_middle_or_id( spellid ); + } + } +} + void teleport_short() { const cata::optional where = g->look_around(); @@ -580,7 +1165,7 @@ void character_edit_menu() } enum { - D_DESC, D_SKILLS, D_PROF, D_STATS, D_ITEMS, D_DELETE_ITEMS, D_ITEM_WORN, + D_DESC, D_SKILLS, D_PROF, D_STATS, D_SPELLS, D_ITEMS, D_DELETE_ITEMS, D_ITEM_WORN, D_HP, D_STAMINA, D_MORALE, D_PAIN, D_NEEDS, D_HEALTHY, D_STATUS, D_MISSION_ADD, D_MISSION_EDIT, D_TELE, D_MUTATE, D_CLASS, D_ATTITUDE, D_OPINION, D_ADD_EFFECT, D_ASTHMA }; @@ -589,6 +1174,7 @@ void character_edit_menu() nmenu.addentry( D_SKILLS, true, 's', "%s", _( "Edit [s]kills" ) ); nmenu.addentry( D_PROF, true, 'P', "%s", _( "Edit [P]roficiencies" ) ); nmenu.addentry( D_STATS, true, 't', "%s", _( "Edit s[t]ats" ) ); + nmenu.addentry( D_SPELLS, true, 'l', "%s", _( "Edit spe[l]ls" ) ); nmenu.addentry( D_ITEMS, true, 'i', "%s", _( "Grant [i]tems" ) ); nmenu.addentry( D_DELETE_ITEMS, true, 'd', "%s", _( "[d]elete (all) items" ) ); nmenu.addentry( D_ITEM_WORN, true, 'w', "%s", @@ -652,6 +1238,9 @@ void character_edit_menu() } } break; + case D_SPELLS: + change_spells( *p.as_character() ); + break; case D_PROF: wishproficiency( &p ); break; @@ -2075,57 +2664,9 @@ void debug() popup( popup_msg ); } break; - case debug_menu_index::LEARN_SPELLS: - if( spell_type::get_all().empty() ) { - add_msg( m_bad, _( "There are no spells to learn. You must install a mod that adds some." ) ); - } else { - for( const spell_type &learn : spell_type::get_all() ) { - player_character.magic->learn_spell( &learn, player_character, true ); - } - add_msg( m_good, - _( "You have become an Archwizardpriest! What will you do with your newfound power?" ) ); - } - break; - case debug_menu_index::LEVEL_SPELLS: { - std::vector spells = player_character.magic->get_spells(); - if( spells.empty() ) { - add_msg( m_bad, _( "Try learning some spells first." ) ); - return; - } - std::vector uiles; - { - uilist_entry uile( _( "Spell" ) ); - uile.ctxt = string_format( "%s %s", - //~ translation should not exceed 4 console cells - right_justify( _( "LVL" ), 4 ), - //~ translation should not exceed 4 console cells - right_justify( _( "MAX" ), 4 ) ); - uile.enabled = false; - uiles.emplace_back( uile ); - } - int retval = 0; - for( spell *sp : spells ) { - uilist_entry uile( sp->name() ); - uile.ctxt = string_format( "%4d %4d", sp->get_level(), sp->get_max_level() ); - uile.retval = retval++; - uile.enabled = !sp->is_max_level(); - uiles.emplace_back( uile ); - } - int action = uilist( _( "Debug level spell:" ), uiles ); - if( action < 0 ) { - return; - } - int desired_level = 0; - int cur_level = spells[action]->get_level(); - query_int( desired_level, _( "Desired Spell Level: (Current %d)" ), cur_level ); - desired_level = std::min( desired_level, spells[action]->get_max_level() ); - while( cur_level < desired_level ) { - spells[action]->gain_level(); - cur_level = spells[action]->get_level(); - } - add_msg( m_good, _( "%s is now level %d!" ), spells[action]->name(), spells[action]->get_level() ); + case debug_menu_index::CHANGE_SPELLS: + change_spells( player_character ); break; - } case debug_menu_index::TEST_MAP_EXTRA_DISTRIBUTION: MapExtras::debug_spawn_test(); break; diff --git a/src/debug_menu.h b/src/debug_menu.h index ac67b2c17f472..ab4d7656a0426 100644 --- a/src/debug_menu.h +++ b/src/debug_menu.h @@ -16,6 +16,7 @@ template class optional; } // namespace cata +class Character; class player; namespace debug_menu @@ -80,8 +81,7 @@ enum class debug_menu_index : int { DISPLAY_REACHABILITY_ZONES, DISPLAY_RADIATION, HOUR_TIMER, - LEARN_SPELLS, - LEVEL_SPELLS, + CHANGE_SPELLS, TEST_MAP_EXTRA_DISTRIBUTION, NESTED_MAPGEN, VEHICLE_BATTERY_CHARGE, @@ -89,6 +89,8 @@ enum class debug_menu_index : int { last }; +void change_spells( Character &character ); + void teleport_short(); void teleport_long(); void teleport_overmap( bool specific_coordinates = false ); diff --git a/src/magic.cpp b/src/magic.cpp index 9d42d3c71050f..903923f87f284 100644 --- a/src/magic.cpp +++ b/src/magic.cpp @@ -1260,7 +1260,7 @@ int spell::get_max_level() const // helper function to calculate xp needed to be at a certain level // pulled out as a helper function to make it easier to either be used in the future // or easier to tweak the formula -static int exp_for_level( int level ) +int spell::exp_for_level( int level ) { // level 0 never needs xp if( level == 0 ) { @@ -1825,7 +1825,7 @@ class spellcasting_callback : public uilist_callback } }; -static bool casting_time_encumbered( const spell &sp, const Character &guy ) +bool spell_desc::casting_time_encumbered( const spell &sp, const Character &guy ) { int encumb = 0; if( !sp.has_flag( spell_flag::NO_LEGS ) ) { @@ -1841,7 +1841,7 @@ static bool casting_time_encumbered( const spell &sp, const Character &guy ) return encumb > 0; } -static bool energy_cost_encumbered( const spell &sp, const Character &guy ) +bool spell_desc::energy_cost_encumbered( const spell &sp, const Character &guy ) { if( !sp.has_flag( spell_flag::NO_HANDS ) ) { return std::max( 0, guy.encumb( bodypart_id( "hand_l" ) ) + guy.encumb( @@ -1853,7 +1853,7 @@ static bool energy_cost_encumbered( const spell &sp, const Character &guy ) // this prints various things about the spell out in a list // including flags and things like "goes through walls" -static std::string enumerate_spell_data( const spell &sp ) +std::string spell_desc::enumerate_spell_data( const spell &sp ) { std::vector spell_data; if( sp.has_flag( spell_flag::CONCENTRATE ) ) { @@ -1904,7 +1904,7 @@ void spellcasting_callback::draw_spell_info( const spell &sp, const uilist *menu line++; line += fold_and_print( w_menu, point( h_col1, line ), info_width, gray, - enumerate_spell_data( sp ) ); + spell_desc::enumerate_spell_data( sp ) ); if( line <= win_height / 3 ) { line++; } @@ -1930,7 +1930,7 @@ void spellcasting_callback::draw_spell_info( const spell &sp, const uilist *menu line++; } - const bool cost_encumb = energy_cost_encumbered( sp, player_character ); + const bool cost_encumb = spell_desc::energy_cost_encumbered( sp, player_character ); std::string cost_string = cost_encumb ? _( "Casting Cost (impeded)" ) : _( "Casting Cost" ); std::string energy_cur = sp.energy_source() == magic_energy_type::hp ? "" : string_format( _( " (%s current)" ), sp.energy_cur_string( player_character ) ); @@ -1941,7 +1941,7 @@ void spellcasting_callback::draw_spell_info( const spell &sp, const uilist *menu print_colored_text( w_menu, point( h_col1, line++ ), gray, gray, string_format( "%s: %s %s%s", cost_string, sp.energy_cost_string( player_character ), sp.energy_string(), energy_cur ) ); - const bool c_t_encumb = casting_time_encumbered( sp, player_character ); + const bool c_t_encumb = spell_desc::casting_time_encumbered( sp, player_character ); print_colored_text( w_menu, point( h_col1, line++ ), gray, gray, colorize( string_format( "%s: %s", c_t_encumb ? _( "Casting Time (impeded)" ) : _( "Casting Time" ), moves_to_string( sp.casting_time( player_character ) ) ), diff --git a/src/magic.h b/src/magic.h index a4b7ed49c7d6f..7a47b9e271845 100644 --- a/src/magic.h +++ b/src/magic.h @@ -286,7 +286,7 @@ class spell_type // increment of energy cost per spell level float energy_increment = 0.0f; // max or min energy cost, based on sign of energy_increment - int final_energy_cost = 0.0f; + int final_energy_cost = 0; // spell is restricted to being cast by only this class // if spell_class is empty, spell is unrestricted @@ -380,6 +380,14 @@ class spell_type static const float casting_time_increment_default; }; +// functions for spell description +namespace spell_desc +{ +bool casting_time_encumbered( const spell &sp, const Character &guy ); +bool energy_cost_encumbered( const spell &sp, const Character &guy ); +std::string enumerate_spell_data( const spell &sp ); +} // namespace spell_desc + class spell { private: @@ -410,6 +418,7 @@ class spell // sets the message to be different than the spell_type specifies void set_message( const translation &msg ); + static int exp_for_level( int level ); // how much exp you need for the spell to gain a level int exp_to_next_level() const; // progress to the next level, expressed as a percent @@ -600,6 +609,10 @@ class known_magic int select_spell( Character &guy ); // get all known spells std::vector get_spells(); + // directly get the character known spells + std::map &get_spellbook() { + return spellbook; + } // how much mana is available to use to cast spells int available_mana() const; // max mana vailable diff --git a/src/output.cpp b/src/output.cpp index 13872e51592c1..cdd163a12ce1f 100644 --- a/src/output.cpp +++ b/src/output.cpp @@ -616,7 +616,7 @@ border_helper::border_info &border_helper::add_border() return border_info_list.front(); } -void border_helper::draw_border( const catacurses::window &win ) +void border_helper::draw_border( const catacurses::window &win, nc_color border_color ) { if( !border_connection_map.has_value() ) { border_connection_map.emplace(); @@ -654,7 +654,7 @@ void border_helper::draw_border( const catacurses::window &win ) for( const std::pair &conn : border_connection_map.value() ) { if( conn.first.x >= win_beg.x && conn.first.x < win_end.x && conn.first.y >= win_beg.y && conn.first.y < win_end.y ) { - mvwputch( win, conn.first - win_beg, BORDER_COLOR, conn.second.as_curses_line() ); + mvwputch( win, conn.first - win_beg, border_color, conn.second.as_curses_line() ); } } } diff --git a/src/output.h b/src/output.h index 634b76bb730ba..f4732ae2cc447 100644 --- a/src/output.h +++ b/src/output.h @@ -411,7 +411,7 @@ class border_helper }; border_info &add_border(); - void draw_border( const catacurses::window &win ); + void draw_border( const catacurses::window &win, nc_color border_color = BORDER_COLOR ); friend class border_info; private: From 3a7398c6bd0b79bb3e26d74abdc0710f9a459083 Mon Sep 17 00:00:00 2001 From: Xenomorph-III Date: Fri, 19 Mar 2021 09:24:38 +1300 Subject: [PATCH 073/453] Add MRE chocolate to the game (#47935) --- .../locations_commercial.json | 1 + data/json/itemgroups/military.json | 2 +- data/json/items/comestibles/junkfood.json | 16 ++++++++++++++++ 3 files changed, 18 insertions(+), 1 deletion(-) diff --git a/data/json/itemgroups/Locations_MapExtras/locations_commercial.json b/data/json/itemgroups/Locations_MapExtras/locations_commercial.json index 86e767c5ee80d..898c9df2cbba2 100644 --- a/data/json/itemgroups/Locations_MapExtras/locations_commercial.json +++ b/data/json/itemgroups/Locations_MapExtras/locations_commercial.json @@ -629,6 +629,7 @@ "items": [ { "group": "mags_surplus", "prob": 400 }, [ "freeze_dried_meal", 20 ], + [ "chocolate_military", 20 ], [ "knife_combat", 14 ], [ "knife_rm42", 1 ], [ "kukri", 2 ], diff --git a/data/json/itemgroups/military.json b/data/json/itemgroups/military.json index a131b428e8af7..e30aa57f053ec 100644 --- a/data/json/itemgroups/military.json +++ b/data/json/itemgroups/military.json @@ -471,7 +471,7 @@ "subtype": "distribution", "entries": [ { "group": "MRE", "prob": 1035 }, - { "item": "chocolate", "prob": 50 }, + { "item": "chocolate", "prob": 20 }, { "item": "neccowafers", "prob": 30 }, { "item": "can_beans", "prob": 40 }, { "item": "pork_beans", "prob": 40 }, diff --git a/data/json/items/comestibles/junkfood.json b/data/json/items/comestibles/junkfood.json index 1e6b73eaa5ebd..d4dcab3534861 100644 --- a/data/json/items/comestibles/junkfood.json +++ b/data/json/items/comestibles/junkfood.json @@ -1378,6 +1378,22 @@ "vitamins": [ [ "vitA", 3 ], [ "iron", 10 ] ], "fun": 4 }, + { + "type": "COMESTIBLE", + "id": "chocolate_military", + "name": { "str": "military chocolate bar" }, + "color": "brown", + "symbol": "%", + "calories": 600, + "weight": "115 g", + "description": "A thick, dense bar of military chocolate. While tough to chew and not very appetizing, it will provide almost a day's worth of calories in portable form.", + "price": 250, + "price_postapoc": 500, + "material": [ "junk" ], + "volume": "500 ml", + "flags": [ "EDIBLE_FROZEN" ], + "fun": -3 + }, { "type": "COMESTIBLE", "id": "gelatin_dessert_powder", From e194bb866390d6d8e4b1268248fc9e4d7dcfce59 Mon Sep 17 00:00:00 2001 From: Michael Macha Date: Thu, 18 Mar 2021 14:27:38 -0600 Subject: [PATCH 074/453] Update 40x46mm.json (#47859) --- data/json/items/ammo/40x46mm.json | 28 ++++++++++++++++++++++++++++ 1 file changed, 28 insertions(+) diff --git a/data/json/items/ammo/40x46mm.json b/data/json/items/ammo/40x46mm.json index 4b469fef32013..e748f47a91221 100644 --- a/data/json/items/ammo/40x46mm.json +++ b/data/json/items/ammo/40x46mm.json @@ -179,5 +179,33 @@ "name": { "str_sp": "40x46mm-M199 flechette, black powder" }, "description": "An improvised 40x46mm flechette load containing 10 steel darts, loaded into a M199 canister. Due to the limitations of weapons built to fire 40x46mm grenades, it's much less powerful than most people would expect.", "casing": "40x46mm_m199_casing" + }, + { + "id": "40x46mm_hornets_nest_22lr", + "copy-from": "40x46mm_grenade", + "type": "AMMO", + "name": { "str_sp": "40x46mm .22 LR hornet's nest" }, + "proportional": { "dispersion": 1.8 }, + "description": "A set of ten .22 LR bullets compressed into a 40mm adapter. Fires all ten rounds simultaneously.", + "weight": "114 g", + "price": 1500, + "price_postapoc": 2400, + "material": [ "aluminum", "brass", "lead", "powder" ], + "damage": { "damage_type": "bullet", "amount": 100 }, + "casing": "40x46mm_m212_casing" + }, + { + "id": "40x46mm_hornets_nest_410", + "copy-from": "40x46mm_grenade", + "type": "AMMO", + "name": { "str_sp": "40x46mm .410 hornet's nest" }, + "proportional": { "dispersion": 1.4 }, + "description": "A set of four .410 shells compressed into a 40mm adapter. Fires all four rounds at once.", + "weight": "245 g", + "price": 710, + "price_postapoc": 3240, + "material": [ "aluminum", "brass", "lead", "powder" ], + "damage": { "damage_type": "bullet", "amount": 120 }, + "casing": "40x46mm_m212_casing" } ] From fd3a7ceb6bd82de564bce54116a8a7142da6070f Mon Sep 17 00:00:00 2001 From: Viss Valdyr <33199510+Lamandus@users.noreply.github.com> Date: Thu, 18 Mar 2021 21:28:23 +0100 Subject: [PATCH 075/453] Tweaks for crowbar and makeshift crowbar (#47827) --- data/json/items/tool/entry_tools.json | 14 +++++++------- data/mods/TEST_DATA/items.json | 8 ++++---- tests/item_contents_test.cpp | 7 ++++--- tests/iteminfo_test.cpp | 4 ++-- 4 files changed, 17 insertions(+), 16 deletions(-) diff --git a/data/json/items/tool/entry_tools.json b/data/json/items/tool/entry_tools.json index 82d3a8d592ae5..90b2f41e1323d 100644 --- a/data/json/items/tool/entry_tools.json +++ b/data/json/items/tool/entry_tools.json @@ -3,10 +3,10 @@ "id": "crowbar", "type": "TOOL", "name": { "str": "crowbar" }, - "description": "This is a hefty prying tool. Use it to open locked doors without destroying them or to lift manhole covers. You could also wield it to bash some heads in.", - "weight": "500 g", - "volume": "1 L", - "longest_side": "60 cm", + "description": "This is a hefty prying tool. Use it to open locked doors without destroying them, or to lift manhole covers. You could also wield it to bash some heads in.", + "weight": "1200 g", + "volume": "170 ml", + "longest_side": "50 cm", "price": 1300, "price_postapoc": 500, "to_hit": -1, @@ -61,9 +61,9 @@ "id": "makeshift_crowbar", "type": "TOOL", "name": { "str": "makeshift crowbar" }, - "description": "This is a pipe whose ends have been bent and hammered flat to resemble a crowbar. Use it to open locked crates without destroying them, or to lift manhole covers. You could also wield it to fight with, in a pinch.", - "weight": "1000 g", - "volume": "1 L", + "description": "This is a pipe with ends that have been bent and hammered flat so it resembles a crowbar. Use it to open locked crates without destroying them, or to lift manhole covers. You could also wield it to fight with, in a pinch.", + "weight": "1250 g", + "volume": "350 ml", "longest_side": "60 cm", "price": 0, "price_postapoc": 10, diff --git a/data/mods/TEST_DATA/items.json b/data/mods/TEST_DATA/items.json index 3fd587bede745..9e5e5c6b47de8 100644 --- a/data/mods/TEST_DATA/items.json +++ b/data/mods/TEST_DATA/items.json @@ -119,7 +119,7 @@ "min_item_volume": "50 ml", "max_item_length": "70 cm", "max_contains_volume": "1500 ml", - "max_contains_weight": "1000 g", + "max_contains_weight": "1200 g", "moves": 50, "flag_restriction": [ "BELT_CLIP", "SHEATH_KNIFE" ] }, @@ -128,7 +128,7 @@ "min_item_volume": "50 ml", "max_item_length": "70 cm", "max_contains_volume": "1500 ml", - "max_contains_weight": "1000 g", + "max_contains_weight": "1200 g", "moves": 50, "flag_restriction": [ "BELT_CLIP", "SHEATH_KNIFE" ] }, @@ -137,7 +137,7 @@ "min_item_volume": "50 ml", "max_item_length": "70 cm", "max_contains_volume": "1500 ml", - "max_contains_weight": "1000 g", + "max_contains_weight": "1200 g", "moves": 50, "flag_restriction": [ "BELT_CLIP", "SHEATH_KNIFE" ] }, @@ -146,7 +146,7 @@ "min_item_volume": "50 ml", "max_item_length": "70 cm", "max_contains_volume": "1500 ml", - "max_contains_weight": "1000 g", + "max_contains_weight": "1200 g", "moves": 50, "flag_restriction": [ "BELT_CLIP", "SHEATH_KNIFE" ] } diff --git a/tests/item_contents_test.cpp b/tests/item_contents_test.cpp index 7a07eed26732e..72da9133a96e3 100644 --- a/tests/item_contents_test.cpp +++ b/tests/item_contents_test.cpp @@ -54,10 +54,11 @@ TEST_CASE( "item_contents" ) CHECK( tool_belt.weight() == tool_belt_weight + hammer.weight() + tongs.weight() + wrench.weight() + crowbar.weight() ); // check that the tool belt is "full" - CHECK( !tool_belt.contents.can_contain( hammer ).success() ); + CHECK( !tool_belt.contents.can_contain( crowbar ).success() ); - tool_belt.contents.force_insert_item( hammer, item_pocket::pocket_type::CONTAINER ); + tool_belt.contents.force_insert_item( crowbar, item_pocket::pocket_type::CONTAINER ); CHECK( tool_belt.contents.num_item_stacks() == 5 ); + tool_belt.contents.force_insert_item( crowbar, item_pocket::pocket_type::CONTAINER ); tool_belt.contents.overflow( tripoint_zero ); CHECK( tool_belt.contents.num_item_stacks() == 4 ); tool_belt.contents.overflow( tripoint_zero ); @@ -65,7 +66,7 @@ TEST_CASE( "item_contents" ) CHECK( tool_belt.contents.num_item_stacks() == 4 ); tool_belt.contents.remove_items_if( []( item & it ) { - return it.typeId() == itype_id( "hammer" ); + return it.typeId() == itype_id( "crowbar" ); } ); // check to see that removing an item works CHECK( tool_belt.contents.num_item_stacks() == 3 ); diff --git a/tests/iteminfo_test.cpp b/tests/iteminfo_test.cpp index e68e7cd620ef8..1b0bdbfceb82d 100644 --- a/tests/iteminfo_test.cpp +++ b/tests/iteminfo_test.cpp @@ -2461,10 +2461,10 @@ TEST_CASE( "pocket info for a multi-pocket item", "[iteminfo][pocket][multiple]" CHECK( item_info_str( test_belt, pockets ) == "--\n" "Total capacity:\n" - "Volume: 6.00 L Weight: 4.00 kg\n" + "Volume: 6.00 L Weight: 4.80 kg\n" "--\n" "4 Pockets with capacity:\n" - "Volume: 1.50 L Weight: 1.00 kg\n" + "Volume: 1.50 L Weight: 1.20 kg\n" "Maximum item length: 70 cm\n" "Minimum item volume: 0.050 L\n" "Base moves to remove item: 50\n" From eb410294e0bce14e594848c12753632d02254bbe Mon Sep 17 00:00:00 2001 From: Venera3 <72006894+Venera3@users.noreply.github.com> Date: Thu, 18 Mar 2021 21:29:07 +0100 Subject: [PATCH 076/453] Add a new anger/fear trigger (#47792) --- doc/JSON_FLAGS.md | 19 +++++++++++-------- doc/MONSTERS.md | 10 +++++----- src/monmove.cpp | 25 ++++++++++++++++++++++++- src/monstergenerator.cpp | 1 + src/mtype.h | 1 + 5 files changed, 42 insertions(+), 14 deletions(-) diff --git a/doc/JSON_FLAGS.md b/doc/JSON_FLAGS.md index 9bf8162b1053b..809df2239c141 100644 --- a/doc/JSON_FLAGS.md +++ b/doc/JSON_FLAGS.md @@ -858,16 +858,19 @@ Flags used to describe monsters and define their properties and abilities. ### Anger, Fear and Placation Triggers -- ```FIRE``` There's a fire nearby. -- ```FRIEND_ATTACKED``` A monster of the same type was attacked. -- ```FRIEND_DIED``` A monster of the same type died. -- ```HURT``` The monster is hurt. +- ```FIRE``` Triggers if there's a fire within 3 tiles, the strength of the effect equals 5 * the field intensity of the fire. +- ```FRIEND_ATTACKED``` Triggers if the monster sees another monster of the same type being attacked; strength = 15. +- ```FRIEND_DIED``` Triggers if the monster sees another monster of the same type dying; strength = 15. +- ```HURT``` Triggers when the monster is hurt, strength equals 1 + (damage / 3 ). - ```MEAT``` Meat or a corpse is nearby. - Currently nonfunctional! - ```NULL``` Source use only? -- ```PLAYER_CLOSE``` The player gets within a few tiles distance. -- ```PLAYER_WEAK``` The player is hurt. -- ```SOUND``` Heard a sound. -- ```STALK``` Increases if already angry at the player. +- ```PLAYER_CLOSE``` Triggers when a potential enemy is within 5 tiles range - Anger/fear trigger only! +- ```PLAYER_WEAK``` Raises monster aggression by 10 - (percent of hp remaining / 10) if a potential enemy has less than 70% hp remaining - Anger trigger only! +- ```PLAYER_NEAR_BABY``` Increases monster aggression by 8 and morale by 4 if **the player** comes within 3 tiles of its offspring (defined by the baby_monster field in its reproduction data)- Anger trigger only! +- ```SOUND``` Not an actual trigger, monsters above 10 aggression and 0 morale will wander towards, monsters below 0 morale will wander away from the source of the sound for 1 turn (6, if they have the GOODHEARING flag). +- ```STALK``` Raises monster aggresssion by 1, triggers 20% of the time each turn if aggression > 5 - Anger trigger only! +- ```HOSTILE_SEEN``` Increases aggression/ decreases morale by a random amount between 0-2 for every potential enemy it can see, up to 20 aggression - Anger/fear trigger only! +- ```MATING_SEASON``` Increases aggression by 3 if a potential enemy is within 5 tiles range and the season is the same as the monster's mating season (defined by the baby_flags field in its reproduction data) - Anger trigger only! ### Categories diff --git a/doc/MONSTERS.md b/doc/MONSTERS.md index 6dafff1147d43..4630c4e126763 100644 --- a/doc/MONSTERS.md +++ b/doc/MONSTERS.md @@ -47,8 +47,8 @@ Monsters may also have any of these optional properties: | `phase` | (string) Monster's body matter state, ex. SOLID, LIQUID, GAS, PLASMA, NULL | `attack_cost` | (integer) Number of moves per regular attack (??) | `diff` | (integer) Additional monster difficulty for special and ranged attacks -| `aggression` | (integer) From totally passive `-99` to guaranteed hostile `100` -| `morale` | (integer) From lemming `-50` to bear `60` to most zombies and monsters `100` +| `aggression` | (integer) Starting aggression, the monster will become hostile when it reaches 10 +| `morale` | (integer) Starting morale, monster will flee when (current aggression + current morale) < 0 | `mountable_weight_ratio` | (float) For mounts, max ratio of mount to rider weight, ex. `0.2` for `<=20%` | `melee_skill` | (integer) Monster skill in melee combat, from `0-10`, with `4` being an average mob | `dodge` | (integer) Monster's skill at dodging attacks @@ -74,9 +74,9 @@ Monsters may also have any of these optional properties: | `regen_morale` | (bool) True if monster will stop fleeing at max HP to regenerate anger and morale | `special_attacks` | (array of objects) Special attacks the monster has | `flags` | (array of strings) Any number of attributes like SEES, HEARS, SMELLS, STUMBLES, REVIVES -| `fear_triggers` | (array of strings) What makes the monster afraid, ex. FIRE, HURT, PLAYER_CLOSE, SOUND -| `anger_triggers` | (array of strings) What makes the monster angry (same flags as fear) -| `placate_triggers` | (array of strings) What calms the monster (same flags as fear) +| `fear_triggers` | (array of strings) Triggers that lower monster morale (see JSON_FLAGS.md) +| `anger_triggers` | (array of strings) Triggers that raise monster aggression (same flags as fear) +| `placate_triggers` | (array of strings) Triggers that lower monster aggression (same flags as fear) | `revert_to_itype` | (string) Item monster can be converted to when friendly (ex. to deconstruct turrets) | `starting_ammo` | (object) Ammo that newly spawned monsters start with | `upgrades` | (boolean or object) False if monster does not upgrade, or an object do define an upgrade diff --git a/src/monmove.cpp b/src/monmove.cpp index c8e8c3421e605..f6e9f57d51bdc 100644 --- a/src/monmove.cpp +++ b/src/monmove.cpp @@ -326,9 +326,13 @@ void monster::plan() const bool angers_hostile_weak = type->has_anger_trigger( mon_trigger::HOSTILE_WEAK ); const int angers_hostile_near = type->has_anger_trigger( mon_trigger::HOSTILE_CLOSE ) ? 5 : 0; + const int angers_hostile_seen = type->has_anger_trigger( mon_trigger::HOSTILE_SEEN ) ? rng( 0, + 2 ) : 0; const int angers_mating_season = type->has_anger_trigger( mon_trigger::MATING_SEASON ) ? 3 : 0; const int angers_cub_threatened = type->has_anger_trigger( mon_trigger::PLAYER_NEAR_BABY ) ? 8 : 0; const int fears_hostile_near = type->has_fear_trigger( mon_trigger::HOSTILE_CLOSE ) ? 5 : 0; + const int fears_hostile_seen = type->has_fear_trigger( mon_trigger::HOSTILE_SEEN ) ? rng( 0, + 2 ) : 0; map &here = get_map(); std::bitset seen_levels = here.get_inter_level_visibility( pos().z ); @@ -342,6 +346,12 @@ void monster::plan() dist = rate_target( player_character, dist, smart_planning ); fleeing = fleeing || is_fleeing( player_character ); target = &player_character; + if( !fleeing && anger <= 20 ) { + anger += angers_hostile_seen; + } + if( !fleeing ) { + morale -= fears_hostile_seen; + } if( dist <= 5 ) { anger += angers_hostile_near; morale -= fears_hostile_near; @@ -407,7 +417,8 @@ void monster::plan() float rating = rate_target( who, dist, smart_planning ); bool fleeing_from = is_fleeing( who ); - if( rating == dist && ( fleeing || attitude( &who ) == MATT_ATTACK ) ) { + if( rating == dist && ( fleeing || attitude( &who ) == MATT_ATTACK || + attitude( &who ) == MATT_FOLLOW ) ) { ++valid_targets; if( one_in( valid_targets ) ) { target = &who; @@ -443,6 +454,12 @@ void monster::plan() } } } + if( !fleeing && anger <= 20 && valid_targets != 0 ) { + anger += angers_hostile_seen; + } + if( !fleeing && valid_targets != 0 ) { + morale -= fears_hostile_seen; + } } fleeing = fleeing || ( mood == MATT_FLEE ); @@ -486,6 +503,12 @@ void monster::plan() anger += angers_hostile_near; morale -= fears_hostile_near; } + if( !fleeing && anger <= 20 && valid_targets != 0 ) { + anger += angers_hostile_seen; + } + if( !fleeing && valid_targets != 0 ) { + morale -= fears_hostile_seen; + } } } } diff --git a/src/monstergenerator.cpp b/src/monstergenerator.cpp index 223489edcfe5a..18dc7e8886a52 100644 --- a/src/monstergenerator.cpp +++ b/src/monstergenerator.cpp @@ -52,6 +52,7 @@ std::string enum_to_string( mon_trigger data ) case mon_trigger::MEAT: return "MEAT"; case mon_trigger::HOSTILE_WEAK: return "PLAYER_WEAK"; case mon_trigger::HOSTILE_CLOSE: return "PLAYER_CLOSE"; + case mon_trigger::HOSTILE_SEEN: return "HOSTILE_SEEN"; case mon_trigger::HURT: return "HURT"; case mon_trigger::FIRE: return "FIRE"; case mon_trigger::FRIEND_DIED: return "FRIEND_DIED"; diff --git a/src/mtype.h b/src/mtype.h index d5e09a9d623d7..229fb8beb7697 100644 --- a/src/mtype.h +++ b/src/mtype.h @@ -42,6 +42,7 @@ enum class mon_trigger : int { MEAT, // Meat or a corpse nearby HOSTILE_WEAK, // Hurt hostile player/npc/monster seen HOSTILE_CLOSE, // Hostile creature within a few tiles + HOSTILE_SEEN, // Hostile creature in visual range HURT, // We are hurt FIRE, // Fire nearby FRIEND_DIED, // A monster of the same type died From 265dd5d4457664d518dcfbe58f3fc6a6363fd1c4 Mon Sep 17 00:00:00 2001 From: RadHazard Date: Thu, 18 Mar 2021 20:30:08 +0000 Subject: [PATCH 077/453] Add more nutrition debug (#47716) * add stomach and gut kCal to the debug menu * Add detailed stomach and gut data to the needs menu * add debug command to edit the faction camp larder * Add debug command to empty a character's stomach & guts * Add stored & total kCal view to the info box --- src/debug_menu.cpp | 77 ++++++++++++++++++++++++++++++++++++++++------ src/debug_menu.h | 1 + 2 files changed, 69 insertions(+), 9 deletions(-) diff --git a/src/debug_menu.cpp b/src/debug_menu.cpp index 90f149caf6292..d211f0d5a99d3 100644 --- a/src/debug_menu.cpp +++ b/src/debug_menu.cpp @@ -99,6 +99,7 @@ #include "ui.h" #include "ui_manager.h" #include "units.h" +#include "units_utility.h" #include "veh_type.h" #include "vehicle.h" #include "vitamin.h" @@ -191,6 +192,7 @@ std::string enum_to_string( debug_menu::debug_menu case debug_menu::debug_menu_index::CHANGE_SPELLS: return "CHANGE_SPELLS"; case debug_menu::debug_menu_index::TEST_MAP_EXTRA_DISTRIBUTION: return "TEST_MAP_EXTRA_DISTRIBUTION"; case debug_menu::debug_menu_index::NESTED_MAPGEN: return "NESTED_MAPGEN"; + case debug_menu::debug_menu_index::EDIT_CAMP_LARDER: return "EDIT_CAMP_LARDER"; case debug_menu::debug_menu_index::VEHICLE_BATTERY_CHARGE: return "VEHICLE_BATTERY_CHARGE"; case debug_menu::debug_menu_index::GENERATE_EFFECT_LIST: return "GENERATE_EFFECT_LIST"; // *INDENT-ON* @@ -344,6 +346,7 @@ static int map_uilist() { uilist_entry( debug_menu_index::OM_EDITOR, true, 'O', _( "Overmap editor" ) ) }, { uilist_entry( debug_menu_index::MAP_EXTRA, true, 'm', _( "Spawn map extra" ) ) }, { uilist_entry( debug_menu_index::NESTED_MAPGEN, true, 'n', _( "Spawn nested mapgen" ) ) }, + { uilist_entry( debug_menu_index::EDIT_CAMP_LARDER, true, 'l', _( "Edit the faction camp larder" ) ) }, }; return uilist( _( "Map…" ), uilist_initializer ); @@ -1485,13 +1488,43 @@ void character_edit_menu() } break; case D_NEEDS: { + std::pair hunger_pair = p.get_hunger_description(); + std::pair thirst_pair = p.get_thirst_description(); + std::pair fatigue_pair = p.get_fatigue_description(); + + std::stringstream data; + data << string_format( _( "Hunger: %d %s" ), p.get_hunger(), colorize( hunger_pair.first, + hunger_pair.second ) ) << std::endl; + data << string_format( _( "Thirst: %d %s" ), p.get_thirst(), colorize( thirst_pair.first, + thirst_pair.second ) ) << std::endl; + data << string_format( _( "Fatigue: %d %s" ), p.get_fatigue(), colorize( fatigue_pair.first, + fatigue_pair.second ) ) << std::endl; + data << std::endl; + data << _( "Stored kCal: " ) << p.get_stored_kcal() << std::endl; + data << _( "Total kCal: " ) << p.get_stored_kcal() + p.stomach.get_calories() + + p.guts.get_calories() << std::endl; + data << std::endl; + data << _( "Stomach contents" ) << std::endl; + data << _( " Total volume: " ) << vol_to_string( p.stomach.contains() ) << std::endl; + data << _( " Water volume: " ) << vol_to_string( p.stomach.get_water() ) << std::endl; + data << string_format( _( " kCal: %d" ), p.stomach.get_calories() ) << std::endl; + data << std::endl; + data << _( "Gut contents" ) << std::endl; + data << _( " Total volume: " ) << vol_to_string( p.guts.contains() ) << std::endl; + data << _( " Water volume: " ) << vol_to_string( p.guts.get_water() ) << std::endl; + data << string_format( _( " kCal: %d" ), p.guts.get_calories() ) << std::endl; + uilist smenu; + smenu.text = data.str(); smenu.addentry( 0, true, 'h', "%s: %d", _( "Hunger" ), p.get_hunger() ); smenu.addentry( 1, true, 's', "%s: %d", _( "Stored kCal" ), p.get_stored_kcal() ); - smenu.addentry( 2, true, 't', "%s: %d", _( "Thirst" ), p.get_thirst() ); - smenu.addentry( 3, true, 'f', "%s: %d", _( "Fatigue" ), p.get_fatigue() ); - smenu.addentry( 4, true, 'd', "%s: %d", _( "Sleep Deprivation" ), p.get_sleep_deprivation() ); - smenu.addentry( 5, true, 'a', _( "Reset all basic needs" ) ); + smenu.addentry( 2, true, 'S', "%s: %d", _( "Stomach kCal" ), p.stomach.get_calories() ); + smenu.addentry( 3, true, 'G', "%s: %d", _( "Gut kCal" ), p.guts.get_calories() ); + smenu.addentry( 4, true, 't', "%s: %d", _( "Thirst" ), p.get_thirst() ); + smenu.addentry( 5, true, 'f', "%s: %d", _( "Fatigue" ), p.get_fatigue() ); + smenu.addentry( 6, true, 'd', "%s: %d", _( "Sleep Deprivation" ), p.get_sleep_deprivation() ); + smenu.addentry( 7, true, 'a', _( "Reset all basic needs" ) ); + smenu.addentry( 8, true, 'e', _( "Empty stomach and guts" ) ); const auto &vits = vitamin::all(); for( const auto &v : vits ) { @@ -1514,24 +1547,36 @@ void character_edit_menu() break; case 2: + if( query_int( value, _( "Set stomach kCal to? Currently: %d" ), p.stomach.get_calories() ) ) { + p.stomach.mod_calories( value - p.stomach.get_calories() ); + } + break; + + case 3: + if( query_int( value, _( "Set gut kCal to? Currently: %d" ), p.guts.get_calories() ) ) { + p.guts.mod_calories( value - p.guts.get_calories() ); + } + break; + + case 4: if( query_int( value, _( "Set thirst to? Currently: %d" ), p.get_thirst() ) ) { p.set_thirst( value ); } break; - case 3: + case 5: if( query_int( value, _( "Set fatigue to? Currently: %d" ), p.get_fatigue() ) ) { p.set_fatigue( value ); } break; - case 4: + case 6: if( query_int( value, _( "Set sleep deprivation to? Currently: %d" ), p.get_sleep_deprivation() ) ) { p.set_sleep_deprivation( value ); } break; - case 5: + case 7: p.initialize_stomach_contents(); p.set_hunger( 0 ); p.set_thirst( 0 ); @@ -1539,9 +1584,13 @@ void character_edit_menu() p.set_sleep_deprivation( 0 ); p.set_stored_kcal( p.get_healthy_kcal() ); break; + case 8: + p.stomach.empty(); + p.guts.empty(); + break; default: - if( smenu.ret >= 6 && smenu.ret < static_cast( vits.size() + 6 ) ) { - auto iter = std::next( vits.begin(), smenu.ret - 6 ); + if( smenu.ret >= 9 && smenu.ret < static_cast( vits.size() + 9 ) ) { + auto iter = std::next( vits.begin(), smenu.ret - 9 ); if( query_int( value, _( "Set %s to? Currently: %d" ), iter->second.name(), p.vitamin_get( iter->first ) ) ) { p.vitamin_set( iter->first, value ); @@ -2712,6 +2761,16 @@ void debug() break; } + case debug_menu_index::EDIT_CAMP_LARDER: { + faction *your_faction = get_player_character().get_faction(); + int larder; + if( query_int( larder, _( "Set camp larder kCals to? Currently: %d" ), + your_faction->food_supply ) ) { + your_faction->food_supply = larder; + } + break; + } + case debug_menu_index::last: return; } diff --git a/src/debug_menu.h b/src/debug_menu.h index ab4d7656a0426..c40f657c9f327 100644 --- a/src/debug_menu.h +++ b/src/debug_menu.h @@ -86,6 +86,7 @@ enum class debug_menu_index : int { NESTED_MAPGEN, VEHICLE_BATTERY_CHARGE, GENERATE_EFFECT_LIST, + EDIT_CAMP_LARDER, last }; From 74d3c4c878357adecf957db87e82482340b1a3ad Mon Sep 17 00:00:00 2001 From: Maleclypse <54345792+Maleclypse@users.noreply.github.com> Date: Fri, 19 Mar 2021 00:20:36 -0500 Subject: [PATCH 078/453] Update Aftershock README.md (#48123) --- data/mods/Aftershock/README.md | 1 + 1 file changed, 1 insertion(+) diff --git a/data/mods/Aftershock/README.md b/data/mods/Aftershock/README.md index 65effb2a00561..4acaa6a627b6c 100644 --- a/data/mods/Aftershock/README.md +++ b/data/mods/Aftershock/README.md @@ -9,6 +9,7 @@ 4. Missions, locations, and lore snippets. We want this to feel like a world just as real as Cataclysm Prime. Please feel free to reach out to us about ideas and implementations. 5. Alien world basics would be especially desirable at this time. Flora, fauna, terrain, and furniture that make it clear we are no longer on earth. +# Size as of 0.F Stable : 31,084 Lines # Here be dragons! From 42c7c137981232de1461b84378e807af7a2d19ca Mon Sep 17 00:00:00 2001 From: tsulh Date: Sun, 21 Mar 2021 08:02:59 +0200 Subject: [PATCH 079/453] fix a typo (#48131) --- data/json/mutations/mutation_enchantments.json | 2 +- data/mods/TEST_DATA/enchantments.json | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/data/json/mutations/mutation_enchantments.json b/data/json/mutations/mutation_enchantments.json index 344f99a397d78..8421a76188920 100644 --- a/data/json/mutations/mutation_enchantments.json +++ b/data/json/mutations/mutation_enchantments.json @@ -8,7 +8,7 @@ "hit_self": false, "once_in": 15, "message": "Your ink glands spray some ink into %2$s's eyes.", - "npc_message": "%1$s's ink glands spay some ink into %2$s's eyes." + "npc_message": "%1$s's ink glands spray some ink into %2$s's eyes." } ] } diff --git a/data/mods/TEST_DATA/enchantments.json b/data/mods/TEST_DATA/enchantments.json index 150617c6df896..fa9c4ceb3b020 100644 --- a/data/mods/TEST_DATA/enchantments.json +++ b/data/mods/TEST_DATA/enchantments.json @@ -10,7 +10,7 @@ "id": "generic_blinding_spray_1", "hit_self": false, "message": "Your ink glands spray some ink into %2$s's eyes.", - "npc_message": "%1$s's ink glands spay some ink into %2$s's eyes." + "npc_message": "%1$s's ink glands spray some ink into %2$s's eyes." } ], "ench_effects": [ { "effect": "invisibility", "intensity": 1 } ] From 67455fcc9ff494698b3d015963eff402a794af99 Mon Sep 17 00:00:00 2001 From: Kevin Granade Date: Wed, 17 Mar 2021 11:26:26 -0700 Subject: [PATCH 080/453] Remove recycler and associated infrastructure (#48096) --- .../terrain-manufactured.json | 3 +- data/json/materials.json | 34 ++---- data/mods/Dark-Skies-Above/materials.json | 3 +- data/mods/Magiclysm/materials.json | 6 +- doc/JSON_FLAGS.md | 1 - src/iexamine.cpp | 111 ------------------ src/iexamine.h | 1 - src/material.cpp | 36 ------ src/material.h | 7 -- 9 files changed, 15 insertions(+), 187 deletions(-) diff --git a/data/json/furniture_and_terrain/terrain-manufactured.json b/data/json/furniture_and_terrain/terrain-manufactured.json index 19993a1493ca3..405f93674385c 100644 --- a/data/json/furniture_and_terrain/terrain-manufactured.json +++ b/data/json/furniture_and_terrain/terrain-manufactured.json @@ -3,14 +3,13 @@ "type": "terrain", "id": "t_recycler", "name": "metal compactor", - "description": "A hydraulic compactor that can accept items made of various metals, and press them into basic shapes, ready for further crafting.", + "description": "A hydraulic machine for squeezing scrap into more compact chunks. Useless now that there's no power.", "looks_like": "f_machinery_heavy", "symbol": "&", "color": "green", "move_cost": 0, "max_volume": "2000 L", "flags": [ "TRANSPARENT", "REDUCE_SCENT", "PERMEABLE" ], - "examine_action": "recycle_compactor", "bash": { "str_min": 20, "str_max": 150, diff --git a/data/json/materials.json b/data/json/materials.json index 0a0633afbb134..6ecef26451a54 100644 --- a/data/json/materials.json +++ b/data/json/materials.json @@ -126,8 +126,7 @@ "repaired_with": "material_aluminium_ingot", "dmg_adj": [ "dented", "bent", "smashed", "destroyed" ], "bash_dmg_verb": "dented", - "cut_dmg_verb": "scratched", - "compacts_into": [ "material_aluminium_ingot", "aluminum_foil" ] + "cut_dmg_verb": "scratched" }, { "type": "material", @@ -219,8 +218,7 @@ "dmg_adj": [ "marked", "dented", "smashed", "shattered" ], "bash_dmg_verb": "dented", "cut_dmg_verb": "scratched", - "burn_products": [ [ "scrap_bronze", 1 ] ], - "compacts_into": [ "scrap_bronze" ] + "burn_products": [ [ "scrap_bronze", 1 ] ] }, { "type": "material", @@ -365,8 +363,7 @@ "dmg_adj": [ "marked", "dented", "smashed", "shattered" ], "bash_dmg_verb": "dented", "cut_dmg_verb": "scratched", - "burn_products": [ [ "scrap_copper", 1 ] ], - "compacts_into": [ "scrap_copper", "copper" ] + "burn_products": [ [ "scrap_copper", 1 ] ] }, { "type": "material", @@ -654,8 +651,7 @@ "dmg_adj": [ "marked", "dented", "smashed", "shattered" ], "bash_dmg_verb": "dented", "cut_dmg_verb": "scratched", - "burn_products": [ [ "gold_small", 1 ] ], - "compacts_into": [ "gold_small" ] + "burn_products": [ [ "gold_small", 1 ] ] }, { "type": "material", @@ -988,8 +984,7 @@ "dmg_adj": [ "marked", "dented", "smashed", "shattered" ], "bash_dmg_verb": "dented", "cut_dmg_verb": "scratched", - "burn_products": [ [ "lead", 1 ] ], - "compacts_into": [ "lead" ] + "burn_products": [ [ "lead", 1 ] ] }, { "type": "material", @@ -1325,8 +1320,7 @@ "dmg_adj": [ "marked", "dented", "smashed", "shattered" ], "bash_dmg_verb": "dented", "cut_dmg_verb": "scratched", - "burn_products": [ [ "silver_small", 1 ] ], - "compacts_into": [ "silver_small" ] + "burn_products": [ [ "silver_small", 1 ] ] }, { "type": "material", @@ -1347,8 +1341,7 @@ "dmg_adj": [ "marked", "dented", "smashed", "shattered" ], "bash_dmg_verb": "dented", "cut_dmg_verb": "scratched", - "burn_products": [ [ "platinum_small", 1 ] ], - "compacts_into": [ "platinum_small" ] + "burn_products": [ [ "platinum_small", 1 ] ] }, { "type": "material", @@ -1398,9 +1391,7 @@ "dmg_adj": [ "marked", "dented", "smashed", "shattered" ], "bash_dmg_verb": "dented", "cut_dmg_verb": "scratched", - "burn_products": [ [ "scrap", 1 ] ], - "compact_accepts": [ "budget_steel", "hardsteel", "iron" ], - "compacts_into": [ "sheet_metal", "steel_lump", "steel_chunk", "scrap" ] + "burn_products": [ [ "scrap", 1 ] ] }, { "type": "material", @@ -1489,8 +1480,7 @@ "dmg_adj": [ "marked", "dented", "smashed", "shattered" ], "bash_dmg_verb": "dented", "cut_dmg_verb": "scratched", - "burn_products": [ [ "alloy_sheet", 1 ] ], - "compacts_into": [ "alloy_sheet" ] + "burn_products": [ [ "alloy_sheet", 1 ] ] }, { "type": "material", @@ -1564,8 +1554,7 @@ "dmg_adj": [ "marked", "dented", "smashed", "shattered" ], "bash_dmg_verb": "dented", "cut_dmg_verb": "scratched", - "burn_products": [ [ "tin", 1 ] ], - "compacts_into": [ "tin" ] + "burn_products": [ [ "tin", 1 ] ] }, { "type": "material", @@ -2051,7 +2040,6 @@ "repaired_with": "zinc_metal", "dmg_adj": [ "dented", "bent", "smashed", "shattered" ], "bash_dmg_verb": "dented", - "cut_dmg_verb": "scratched", - "compacts_into": [ "zinc_metal" ] + "cut_dmg_verb": "scratched" } ] diff --git a/data/mods/Dark-Skies-Above/materials.json b/data/mods/Dark-Skies-Above/materials.json index 4c31f44276120..08091c770436a 100644 --- a/data/mods/Dark-Skies-Above/materials.json +++ b/data/mods/Dark-Skies-Above/materials.json @@ -18,8 +18,7 @@ "dmg_adj": [ "marked", "dented", "smashed", "shattered" ], "bash_dmg_verb": "dented", "cut_dmg_verb": "scratched", - "burn_products": [ [ "dks_blend_scrap", 1 ] ], - "compacts_into": [ "dks_blend_scrap" ] + "burn_products": [ [ "dks_blend_scrap", 1 ] ] }, { "type": "material", diff --git a/data/mods/Magiclysm/materials.json b/data/mods/Magiclysm/materials.json index 7515f2890a9cc..9e3e6522fe219 100644 --- a/data/mods/Magiclysm/materials.json +++ b/data/mods/Magiclysm/materials.json @@ -86,8 +86,7 @@ "dmg_adj": [ "marked", "dented", "smashed", "shattered" ], "bash_dmg_verb": "dented", "cut_dmg_verb": "scratched", - "burn_products": [ [ "scrap_bronze", 1 ] ], - "compacts_into": [ "orichalcum_lump", "orichalcum_sliver" ] + "burn_products": [ [ "scrap_bronze", 1 ] ] }, { "type": "material", @@ -107,8 +106,7 @@ "repaired_with": "mithril_ingot", "dmg_adj": [ "marked", "dented", "smashed", "shattered" ], "bash_dmg_verb": "dented", - "cut_dmg_verb": "scratched", - "compacts_into": [ "mithril_lump", "mithril_ingot" ] + "cut_dmg_verb": "scratched" }, { "type": "material", diff --git a/doc/JSON_FLAGS.md b/doc/JSON_FLAGS.md index 809df2239c141..b8847cfd14c48 100644 --- a/doc/JSON_FLAGS.md +++ b/doc/JSON_FLAGS.md @@ -635,7 +635,6 @@ List of known flags, used in both `terrain.json` and `furniture.json`. - ```pit_covered``` Uncover the pit. - ```pit``` Cover the pit if you have some planks of wood. - ```portable_structure``` Take down a tent or similar portable structure. -- ```recycle_compactor``` Compress pure metal objects into basic shapes. - ```rubble``` Clear up the rubble if you have a shovel. - ```safe``` Attempt to crack the safe. - ```shelter``` Take down the shelter. diff --git a/src/iexamine.cpp b/src/iexamine.cpp index 155db75fd8429..bccf56c5f897a 100644 --- a/src/iexamine.cpp +++ b/src/iexamine.cpp @@ -3765,116 +3765,6 @@ void iexamine::shrub_wildveggies( player &p, const tripoint &examp ) p.activity.auto_resume = true; } -void iexamine::recycle_compactor( player &, const tripoint &examp ) -{ - // choose what metal to recycle - auto metals = materials::get_compactable(); - uilist choose_metal; - choose_metal.text = _( "Recycle what metal?" ); - for( auto &m : metals ) { - choose_metal.addentry( m.name() ); - } - choose_metal.query(); - int m_idx = choose_metal.ret; - if( m_idx < 0 || m_idx >= static_cast( metals.size() ) ) { - add_msg( _( "Never mind." ) ); - return; - } - material_type m = metals.at( m_idx ); - - map &here = get_map(); - // check inputs and tally total mass - map_stack inputs = here.i_at( examp ); - units::mass sum_weight = 0_gram; - auto ca = m.compact_accepts(); - std::set accepts( ca.begin(), ca.end() ); - accepts.insert( m.id ); - for( auto &input : inputs ) { - if( !input.only_made_of( accepts ) ) { - //~ %1$s: an item in the compactor , %2$s: desired compactor output material - add_msg( _( "You realize this isn't going to work because %1$s is not made purely of %2$s." ), - input.tname(), m.name() ); - return; - } - if( input.is_container() && !input.is_container_empty() ) { - //~ %1$s: an item in the compactor - add_msg( _( "You realize this isn't going to work because %1$s has not been emptied of its contents." ), - input.tname() ); - return; - } - sum_weight += input.weight(); - } - if( sum_weight <= 0_gram ) { - //~ %1$s: desired compactor output material - add_msg( _( "There is no %1$s in the compactor. Drop some metal items onto it and try again." ), - m.name() ); - return; - } - - // See below for recover_factor (rng(6,9)/10), this - // is the normal value of that recover factor. - static const double norm_recover_factor = 8.0 / 10.0; - const units::mass norm_recover_weight = sum_weight * norm_recover_factor; - - // choose output - uilist choose_output; - //~ %1$.3f: total mass of material in compactor, %2$s: weight units , %3$s: compactor output material - choose_output.text = string_format( _( "Compact %1$.3f %2$s of %3$s into:" ), - convert_weight( sum_weight ), weight_units(), m.name() ); - for( const itype_id &ci : m.compacts_into() ) { - item it = item( ci, calendar::turn_zero, item::solitary_tag{} ); - const int amount = norm_recover_weight / it.weight(); - //~ %1$d: number of, %2$s: output item - choose_output.addentry( string_format( _( "about %1$d %2$s" ), amount, - it.tname( amount ) ) ); - } - choose_output.query(); - int o_idx = choose_output.ret; - if( o_idx < 0 || o_idx >= static_cast( m.compacts_into().size() ) ) { - add_msg( _( "Never mind." ) ); - return; - } - - // remove items - for( auto it = inputs.begin(); it != inputs.end(); ) { - it = inputs.erase( it ); - } - - // produce outputs - double recover_factor = rng( 6, 9 ) / 10.0; - sum_weight = sum_weight * recover_factor; - sounds::sound( examp, 80, sounds::sound_t::combat, _( "Ka-klunk!" ), true, "tool", "compactor" ); - bool out_desired = false; - bool out_any = false; - for( auto it = m.compacts_into().begin() + o_idx; it != m.compacts_into().end(); ++it ) { - const units::mass ow = item( *it, calendar::turn_zero, item::solitary_tag{} ).weight(); - int count = sum_weight / ow; - sum_weight -= count * ow; - if( count > 0 ) { - here.spawn_item( examp, *it, count, 1, calendar::turn ); - if( !out_any ) { - out_any = true; - if( it == m.compacts_into().begin() + o_idx ) { - out_desired = true; - } - } - } - } - - // feedback to user - if( !out_any ) { - add_msg( _( "The compactor chews up all the items in its hopper." ) ); - //~ %1$s: compactor output material - add_msg( _( "The compactor beeps: \"No %1$s to process!\"" ), m.name() ); - return; - } - if( !out_desired ) { - //~ %1$s: compactor output material - add_msg( _( "The compactor beeps: \"Insufficient %1$s!\"" ), m.name() ); - add_msg( _( "It spits out an assortment of smaller pieces instead." ) ); - } -} - void trap::examine( const tripoint &examp ) const { avatar &player_character = get_avatar(); @@ -6364,7 +6254,6 @@ iexamine_function iexamine_function_from_string( const std::string &function_nam { "tree_maple", &iexamine::tree_maple }, { "tree_maple_tapped", &iexamine::tree_maple_tapped }, { "shrub_wildveggies", &iexamine::shrub_wildveggies }, - { "recycle_compactor", &iexamine::recycle_compactor }, { "water_source", &iexamine::water_source }, { "clean_water_source", &iexamine::clean_water_source }, { "reload_furniture", &iexamine::reload_furniture }, diff --git a/src/iexamine.h b/src/iexamine.h index b27169671d104..3e6db8e64a8b0 100644 --- a/src/iexamine.h +++ b/src/iexamine.h @@ -81,7 +81,6 @@ void tree_maple_tapped( player &p, const tripoint &examp ); void shrub_marloss( player &p, const tripoint &examp ); void tree_marloss( player &p, const tripoint &examp ); void shrub_wildveggies( player &p, const tripoint &examp ); -void recycle_compactor( player &p, const tripoint &examp ); void water_source( player &p, const tripoint &examp ); void clean_water_source( player &, const tripoint &examp ); void kiln_empty( player &p, const tripoint &examp ); diff --git a/src/material.cpp b/src/material.cpp index 54a6d9f01bf2b..132731241f61b 100644 --- a/src/material.cpp +++ b/src/material.cpp @@ -103,10 +103,6 @@ void material_type::load( const JsonObject &jsobj, const std::string & ) optional( jsobj, was_loaded, "fuel_data", fuel ); jsobj.read( "burn_products", _burn_products, true ); - - optional( jsobj, was_loaded, "compact_accepts", _compact_accepts, - auto_flags_reader() ); - optional( jsobj, was_loaded, "compacts_into", _compacts_into, auto_flags_reader() ); } void material_type::check() const @@ -123,17 +119,6 @@ void material_type::check() const if( !item::type_is_defined( _repaired_with ) ) { debugmsg( "invalid \"repaired_with\" %s for %s.", _repaired_with.c_str(), id.c_str() ); } - for( const material_id &ca : _compact_accepts ) { - if( !ca.is_valid() ) { - debugmsg( "invalid \"compact_accepts\" %s for %s.", ca.c_str(), id.c_str() ); - } - } - for( const itype_id &ci : _compacts_into ) { - if( !item::type_is_defined( ci ) || - !item( ci, calendar::turn_zero ).only_made_of( std::set { id } ) ) { - debugmsg( "invalid \"compacts_into\" %s for %s.", ci.c_str(), id.c_str() ); - } - } } material_id material_type::ident() const @@ -272,16 +257,6 @@ const mat_burn_products &material_type::burn_products() const return _burn_products; } -const material_id_list &material_type::compact_accepts() const -{ - return _compact_accepts; -} - -const mat_compacts_into &material_type::compacts_into() const -{ - return _compacts_into; -} - void materials::load( const JsonObject &jo, const std::string &src ) { material_data.load( jo, src ); @@ -302,17 +277,6 @@ material_list materials::get_all() return material_data.get_all(); } -material_list materials::get_compactable() -{ - material_list all = get_all(); - material_list compactable; - std::copy_if( all.begin(), all.end(), - std::back_inserter( compactable ), []( const material_type & mt ) { - return !mt.compacts_into().empty(); - } ); - return compactable; -} - std::set materials::get_rotting() { static generic_factory::Version version; diff --git a/src/material.h b/src/material.h index 5ecd0914e34c8..13cb439dbea4f 100644 --- a/src/material.h +++ b/src/material.h @@ -23,7 +23,6 @@ enum class damage_type : int; class JsonObject; using mat_burn_products = std::vector>; -using mat_compacts_into = std::vector; using material_list = std::vector; using material_id_list = std::vector; @@ -94,9 +93,6 @@ class material_type //Burn products defined in JSON as "burn_products": [ [ "X", float efficiency ], [ "Y", float efficiency ] ] mat_burn_products _burn_products; - material_id_list _compact_accepts; - mat_compacts_into _compacts_into; - public: material_type(); @@ -143,8 +139,6 @@ class material_type const mat_burn_data &burn_data( size_t intensity ) const; const mat_burn_products &burn_products() const; - const material_id_list &compact_accepts() const; - const mat_compacts_into &compacts_into() const; }; namespace materials @@ -155,7 +149,6 @@ void check(); void reset(); material_list get_all(); -material_list get_compactable(); std::set get_rotting(); } // namespace materials From 9914696c46d4771ce16b38a8977417d42b232bf2 Mon Sep 17 00:00:00 2001 From: ephemeralstoryteller Date: Sun, 21 Mar 2021 02:06:48 -0400 Subject: [PATCH 081/453] [Dark Skies Above] Plague Emissary Fix, Harvest Tweak (#48150) --- data/mods/Dark-Skies-Above/harvest.json | 28 ++++--------------- .../Dark-Skies-Above/items/electronics.json | 6 ++-- 2 files changed, 9 insertions(+), 25 deletions(-) diff --git a/data/mods/Dark-Skies-Above/harvest.json b/data/mods/Dark-Skies-Above/harvest.json index 65b4cdee17af3..75a652a3e5bad 100644 --- a/data/mods/Dark-Skies-Above/harvest.json +++ b/data/mods/Dark-Skies-Above/harvest.json @@ -1,30 +1,14 @@ [ { - "id": "dks_alien_cyborg", - "//": "'alien' but has some metal thrown in to simulate the extensive augments", + "id": "dks_alien_hcyborg", + "//": "a humanoid alien cyborg. metal and scrap simulate augmentation. candidate to receive future bionics", "type": "harvest", "entries": [ - { "drop": "meat_tainted", "type": "flesh", "mass_ratio": 0.25 }, - { "drop": "fat_tainted", "type": "flesh", "mass_ratio": 0.08 }, + { "drop": "mutant_human_flesh", "type": "flesh", "mass_ratio": 0.25 }, + { "drop": "mutant_human_fat", "type": "flesh", "mass_ratio": 0.08 }, { "drop": "bone_tainted", "type": "bone", "mass_ratio": 0.1 }, - { "drop": "cable", "base_num": [ 1, 3 ], "scale_num": [ 0.2, 0.6 ], "max": 8, "type": "flesh" }, - { "drop": "bone_human", "base_num": [ 1, 2 ], "scale_num": [ 0.4, 0.7 ], "max": 10, "type": "bone" }, - { "drop": "scrap", "base_num": [ 1, 5 ], "scale_num": [ 0.3, 0.7 ], "max": 12, "type": "bone" } - ] - }, - { - "//": "e_scrap will be replaced with an alien mind control chip and some aftershock style crafting stuff since I like the tiered crafting idea", - "id": "dks_mhuman_chipped", - "message": "They may have been human, once… whatever the Order has done to them, now they are something else.", - "type": "harvest", - "entries": [ - { "drop": "mutant_human_flesh", "type": "flesh", "mass_ratio": 0.2 }, - { "drop": "hstomach", "scale_num": [ 1, 1 ], "max": 1, "type": "offal" }, - { "drop": "mutant_human_fat", "type": "flesh", "mass_ratio": 0.1 }, - { "drop": "bone_human", "type": "bone", "mass_ratio": 0.12 }, - { "drop": "sinew", "type": "bone", "mass_ratio": 0.001 }, - { "drop": "raw_hleather", "type": "skin", "mass_ratio": 0.01 }, - { "drop": "e_scrap", "type": "bionic", "max": 2 } + { "drop": "dks_elecscrap", "base_num": [ 1, 3 ], "scale_num": [ 0.2, 0.6 ], "max": 8, "type": "flesh" }, + { "drop": "dks_blend_scrap", "base_num": [ 1, 5 ], "scale_num": [ 0.3, 0.7 ], "max": 12, "type": "bone" } ] } ] diff --git a/data/mods/Dark-Skies-Above/items/electronics.json b/data/mods/Dark-Skies-Above/items/electronics.json index d955b72c7eb39..39ea2450b2825 100644 --- a/data/mods/Dark-Skies-Above/items/electronics.json +++ b/data/mods/Dark-Skies-Above/items/electronics.json @@ -15,12 +15,12 @@ }, { "type": "GENERIC", - "id": "broken_dks_emissary_war", + "id": "broken_dks_emissary_plague", "symbol": ",", "color": "green", - "name": { "str": "broken emissary of war", "str_pl": "broken emissaries of war" }, + "name": { "str": "broken emissary of plague", "str_pl": "broken emissaries of plague" }, "category": "other", - "description": "The massive body of a collapsed emissary of war. Still a bit intimidating, perhaps knowing the damage it can cause. Could be gutted for parts, but you'll probably need specialized alien tools.", + "description": "The massive body of a collapsed emissary of plague. Still a bit intimidating, perhaps knowing the damage it can cause. Could be gutted for parts, but you'll probably need specialized alien tools.", "price": 1000, "material": [ "superalloy" ], "volume": "875000 ml", From 1289dcbe99d9075883f3c0e7c26c52b051a58251 Mon Sep 17 00:00:00 2001 From: Mark Langsdorf Date: Sun, 21 Mar 2021 01:08:34 -0500 Subject: [PATCH 082/453] mapgen: allow placing active bomb items for better craters in Dark Skies Above (#48137) * mapgen: allow activated items to be placed on the map Add the new item flag "ACTIVATE_ON_PLACE". Items placed during mapgen with this flag will be activated immediately after they are placed on the map. * Dark Skies Above: use active bombs to create large bomb craters Use the new ACTIVATE_ON_PLACE flag with active bombs with 1 second count-downs in a new map special that randomly wrecks buildings across multiple z-levels. The bombs have max_noise = 0 and explode silently to preserve the avatar's hearing. Co-authored-by: actual-nh <74678550+actual-nh@users.noreply.github.com> --- data/json/flags.json | 6 +++ .../mapgen/map_extras/bombed_crater.json | 47 +++++++++++++++++++ .../overrides/region_settings.json | 2 + doc/MAPGEN.md | 4 +- src/flag.cpp | 1 + src/flag.h | 1 + src/map.cpp | 4 ++ 7 files changed, 63 insertions(+), 2 deletions(-) create mode 100644 data/mods/Dark-Skies-Above/mapgen/map_extras/bombed_crater.json diff --git a/data/json/flags.json b/data/json/flags.json index 0ce224a92a9c3..713a0ebdfa551 100644 --- a/data/json/flags.json +++ b/data/json/flags.json @@ -1820,6 +1820,12 @@ "type": "json_flag", "context": [ "AMMO", "CONSUMABLE" ] }, + { + "id": "ACTIVATE_ON_PLACE", + "type": "json_flag", + "context": [ ], + "info": "This item will be activated when it is placed in mapgen." + }, { "id": "ACT_IN_FIRE", "type": "json_flag", diff --git a/data/mods/Dark-Skies-Above/mapgen/map_extras/bombed_crater.json b/data/mods/Dark-Skies-Above/mapgen/map_extras/bombed_crater.json new file mode 100644 index 0000000000000..cfa896c6537d1 --- /dev/null +++ b/data/mods/Dark-Skies-Above/mapgen/map_extras/bombed_crater.json @@ -0,0 +1,47 @@ +[ + { + "id": "tool_dsa_alien_bomb_act", + "type": "TOOL", + "category": "weapons", + "name": { "str": "active alien bomb" }, + "looks_like": "tool_rdx_charge_act", + "description": "This is an alien bomb. It has been activated and will soon explode, delivering its entire destructive power to everything in sight.", + "weight": "4400 g", + "volume": "10 L", + "price": 0, + "to_hit": -5, + "bashing": 20, + "material": [ "steel" ], + "symbol": "(", + "color": "light_red", + "initial_charges": 1, + "max_charges": 1, + "turns_per_charge": 1, + "explode_in_fire": true, + "explosion": { "power": 40000, "max_noise": 0 }, + "use_action": { + "type": "explosion", + "no_deactivate_msg": "You've already activated the bomb - clear the area immediately!", + "explosion": { "power": 40000, "max_noise": 0 } + }, + "flags": [ "BOMB", "TRADER_AVOID" ] + }, + { + "type": "mapgen", + "method": "json", + "update_mapgen_id": "mx_dsa_bombed_crater", + "object": { + "place_item": [ { "item": "tool_dsa_alien_bomb_act", "x": 12, "y": 12, "amount": 1, "custom-flags": [ "ACTIVATE_ON_PLACE" ] } ] + } + }, + { + "id": "mx_dsa_bombed_crater", + "type": "map_extra", + "name": { "str": "Bomb Crater" }, + "description": "A bomb crater.", + "generator": { "generator_method": "update_mapgen", "generator_id": "mx_dsa_bombed_crater" }, + "sym": ".", + "color": "brown", + "autonote": true + } +] diff --git a/data/mods/Dark-Skies-Above/overrides/region_settings.json b/data/mods/Dark-Skies-Above/overrides/region_settings.json index 35fff324dddea..fddeba421ac44 100644 --- a/data/mods/Dark-Skies-Above/overrides/region_settings.json +++ b/data/mods/Dark-Skies-Above/overrides/region_settings.json @@ -35,6 +35,7 @@ }, "road": { "extras": { + "mx_dsa_bombed_crater": 200, "mx_mayhem": 0, "mx_portal": 0, "mx_portal_in": 0, @@ -57,6 +58,7 @@ "build": { "chance": 2, "extras": { + "mx_dsa_bombed_crater": 200, "mx_house_spider": 0, "mx_house_wasp": 0, "mx_military": 1, diff --git a/doc/MAPGEN.md b/doc/MAPGEN.md index bdaa60394aca9..2e765138c9f9b 100644 --- a/doc/MAPGEN.md +++ b/doc/MAPGEN.md @@ -594,7 +594,8 @@ Example: | repeat | (optional) Value: `[ n1, n2 ]`. Spawn item randomly between `n1` and `n2` times. Only makes sense if the coordinates are random. Example: `[ 1, 3 ]` - repeat 1-3 times. | custom-flags | (optional) Value: `[ "flag1", "flag2" ]`. Spawn item with specific flags. - +The special custom flag "ACTIVATE_ON_PLACE" causes the item to be activated as it is placed. This is useful to have noisemakers that are already turned on as the avatar approaches. It can also be used with explosives with a 1 second countdown to have locations explode as the avatar approaches, creating uniquely ruined terrain. + ## Extra map features with specials **optional** Special map features that do more than just placing furniture / terrain. @@ -1072,4 +1073,3 @@ update_mapgen adds new optional keywords to a few mapgen JSON items. place_npc, place_monster, and place_computer can take an optional target boolean. If they have `"target": true` and are invoked by update_mapgen with a valid mission, then the NPC, monster, or computer will be marked as the target of the mission. - diff --git a/src/flag.cpp b/src/flag.cpp index 641d9c5966be2..5b5b68364f9c0 100644 --- a/src/flag.cpp +++ b/src/flag.cpp @@ -9,6 +9,7 @@ const flag_id flag_NULL = flag_id( "null" ); // intentionally invalid flag const flag_id flag_ACID( "ACID" ); const flag_id flag_ACID_IMMUNE( "ACID_IMMUNE" ); +const flag_id flag_ACTIVATE_ON_PLACE( "ACTIVATE_ON_PLACE" ); const flag_id flag_ACTIVE_CLOAKING( "ACTIVE_CLOAKING" ); const flag_id flag_ACT_IN_FIRE( "ACT_IN_FIRE" ); const flag_id flag_ACT_ON_RANGED_HIT( "ACT_ON_RANGED_HIT" ); diff --git a/src/flag.h b/src/flag.h index 316de675b7686..ce60d0a3f6580 100644 --- a/src/flag.h +++ b/src/flag.h @@ -16,6 +16,7 @@ template class generic_factory; extern const flag_id flag_NULL; extern const flag_id flag_ACID; extern const flag_id flag_ACID_IMMUNE; +extern const flag_id flag_ACTIVATE_ON_PLACE; extern const flag_id flag_ACTIVE_CLOAKING; extern const flag_id flag_ACT_IN_FIRE; extern const flag_id flag_ACT_ON_RANGED_HIT; diff --git a/src/map.cpp b/src/map.cpp index 68747009132bc..e5ae1b3cd4850 100644 --- a/src/map.cpp +++ b/src/map.cpp @@ -4484,6 +4484,10 @@ item &map::add_item( const tripoint &p, item new_item ) new_item.set_var( "reveal_map_center_omt", ms_to_omt_copy( getabs( p ) ) ); } + if( new_item.has_flag( flag_ACTIVATE_ON_PLACE ) ) { + new_item.activate(); + } + current_submap->is_uniform = false; invalidate_max_populated_zlev( p.z ); From 82456afa4ebf16cbdb013a6cc1befae49aa27f87 Mon Sep 17 00:00:00 2001 From: Jamuro-g <76928284+Jamuro-g@users.noreply.github.com> Date: Sun, 21 Mar 2021 07:12:22 +0100 Subject: [PATCH 083/453] food_containers get colored with their foods colortag (#47426) --- src/advanced_inv.cpp | 9 ++++++++- src/item.cpp | 1 - src/pickup.cpp | 10 +++++++++- 3 files changed, 17 insertions(+), 3 deletions(-) diff --git a/src/advanced_inv.cpp b/src/advanced_inv.cpp index 11875e2343d8f..559ec885ea010 100644 --- a/src/advanced_inv.cpp +++ b/src/advanced_inv.cpp @@ -336,7 +336,14 @@ void advanced_inventory::print_items( const advanced_inventory_pane &pane, bool const item &it = *sitem.items.front(); const bool selected = active && index == static_cast( i ); - nc_color thiscolor = active ? it.color_in_inventory() : norm; + nc_color thiscolor; + if( !active ) { + thiscolor = norm; + } else if( it.is_food_container() && !it.is_craft() && it.contents.num_item_stacks() == 1 ) { + thiscolor = it.contents.all_items_top().front()->color_in_inventory(); + } else { + thiscolor = it.color_in_inventory(); + } nc_color thiscolordark = c_dark_gray; nc_color print_color; diff --git a/src/item.cpp b/src/item.cpp index d63317d7ebf9b..9f22033300038 100644 --- a/src/item.cpp +++ b/src/item.cpp @@ -4335,7 +4335,6 @@ nc_color item::color_in_inventory() const // Only reviving corpses are yellow ret = c_yellow; } else if( const item *food = get_food() ) { - // Give color priority to allergy (allergy > inedible by freeze or other conditions) // TODO: refactor u.will_eat to let this section handle coloring priority without duplicating code. if( player_character.allergy_type( *food ) != morale_type( "morale_null" ) ) { diff --git a/src/pickup.cpp b/src/pickup.cpp index f283ceb1cc00f..cbcd2695e38e5 100644 --- a/src/pickup.cpp +++ b/src/pickup.cpp @@ -711,7 +711,15 @@ void Pickup::pick_up( const tripoint &p, int min, from_where get_items_from ) if( cur_it < static_cast( matches.size() ) ) { int true_it = matches[cur_it]; const item &this_item = *stacked_here[true_it].front(); - nc_color icolor = this_item.color_in_inventory(); + + nc_color icolor; + if( this_item.is_food_container() && !this_item.is_craft() && + this_item.contents.num_item_stacks() == 1 ) { + icolor = this_item.contents.all_items_top().front()->color_in_inventory(); + } else { + icolor = this_item.color_in_inventory(); + } + if( cur_it == selected ) { icolor = hilite( c_white ); } From 6f79ce01a1abab7ee156229aa1140cadda2895c8 Mon Sep 17 00:00:00 2001 From: Mark Langsdorf Date: Sun, 21 Mar 2021 07:53:44 -0500 Subject: [PATCH 084/453] Dark Skies Above: spellcheck the descriptions (#48164) Run the descriptive JSON through Fedora32's spellcheck and fix a couple of typoes. --- .../blacklists/location_blacklist.json | 2 +- data/mods/Dark-Skies-Above/items/alien-scrap.json | 2 +- data/mods/Dark-Skies-Above/mongun.json | 2 +- data/mods/Dark-Skies-Above/monsters/alien_fauna.json | 6 +++--- .../mods/Dark-Skies-Above/monsters/alien_robots.json | 2 +- data/mods/Dark-Skies-Above/monsters/strays.json | 12 ++++++------ data/mods/Dark-Skies-Above/obsolete.json | 6 +++--- .../Dark-Skies-Above/overrides/items/carnivore.json | 6 +++--- .../mods/Dark-Skies-Above/overrides/items/tools.json | 2 +- data/mods/Dark-Skies-Above/snippets/fliers.json | 4 ++-- data/mods/Dark-Skies-Above/snippets/graffiti.json | 12 ++++++------ data/mods/Dark-Skies-Above/snippets/newspaper.json | 2 +- 12 files changed, 29 insertions(+), 29 deletions(-) diff --git a/data/mods/Dark-Skies-Above/blacklists/location_blacklist.json b/data/mods/Dark-Skies-Above/blacklists/location_blacklist.json index 80201b69af785..34aa84c366bdd 100644 --- a/data/mods/Dark-Skies-Above/blacklists/location_blacklist.json +++ b/data/mods/Dark-Skies-Above/blacklists/location_blacklist.json @@ -1,6 +1,6 @@ [ { - "//": "mostly removes areas with their own storylines, static NPCs, and the like. some will be readded with time", + "//": "mostly removes areas with their own storylines, static NPCs, and the like. some will be returned with time", "type": "overmap_special", "id": "Necropolis", "overmaps": [ ], diff --git a/data/mods/Dark-Skies-Above/items/alien-scrap.json b/data/mods/Dark-Skies-Above/items/alien-scrap.json index 4e71600bb5630..4aa9e7f4502ce 100644 --- a/data/mods/Dark-Skies-Above/items/alien-scrap.json +++ b/data/mods/Dark-Skies-Above/items/alien-scrap.json @@ -78,7 +78,7 @@ "id": "dks_powercell", "category": "spare_parts", "name": { "str": "alien power cell" }, - "description": "A fist-sized, cylindrical canister that makes you feel a bit tingly when you hold it. Its center houses a faintly glowing red core of some sort. Though fundementally incompatable with earthly technologies, it still might be useful in crafting.", + "description": "A fist-sized, cylindrical canister that makes you feel a bit tingly when you hold it. Its center houses a faintly glowing red core of some sort. Though fundamentally incompatible with earthly technologies, it still might be useful in crafting.", "weight": "80 g", "volume": "30 ml", "price": 15000, diff --git a/data/mods/Dark-Skies-Above/mongun.json b/data/mods/Dark-Skies-Above/mongun.json index 7c722b2b0ec77..cbf5f422aed3e 100644 --- a/data/mods/Dark-Skies-Above/mongun.json +++ b/data/mods/Dark-Skies-Above/mongun.json @@ -18,7 +18,7 @@ "color": "red", "name": { "str": "fake firecannon" }, "ranged_damage": { "damage_type": "heat", "amount": 20, "armor_penetration": 30 }, - "description": "Fires an explosive bolt of firey energy. If you're seeing this, it's a bug.", + "description": "Fires an explosive bolt of fiery energy. If you're seeing this, it's a bug.", "skill": "launcher", "range": 15, "flags": [ "NEVER_JAMS" ], diff --git a/data/mods/Dark-Skies-Above/monsters/alien_fauna.json b/data/mods/Dark-Skies-Above/monsters/alien_fauna.json index ead0b24f258bc..080acdb4c813e 100644 --- a/data/mods/Dark-Skies-Above/monsters/alien_fauna.json +++ b/data/mods/Dark-Skies-Above/monsters/alien_fauna.json @@ -42,7 +42,7 @@ "id": "dks_mon_lurker", "type": "MONSTER", "name": { "str": "lurker" }, - "description": "A long, serpentine body, dark and murky just like the waters it inhabits. Tendrils trail behind it, framing innumerable teeth in a gnashing central mouth. It prefers to lurk just below the surface, drifting and still like an unassuming piece of floatsam until something gets too close.", + "description": "A long, serpentine body, dark and murky just like the waters it inhabits. Tendrils trail behind it, framing innumerable teeth in a gnashing central mouth. It prefers to lurk just below the surface, drifting and still, like an unassuming piece of flotsam until something gets too close.", "looks_like": "dks_mon_lurker_sewer", "default_faction": "lurker", "bodytype": "spider", @@ -84,7 +84,7 @@ "id": "dks_mon_mossliz", "type": "MONSTER", "name": "moss lizard", - "description": "A cow-sized reptoid, covered in what appears to be a thick layer of mossy vegetation and rocks. It trudges about the landscape on sturdy legs, foraging whatever flora it can reach with sharp little teeth. It doesn't seem to mind you too much.", + "description": "A cow-sized reptiloid, covered in what appears to be a thick layer of mossy vegetation and rocks. It trudges about the landscape on sturdy legs, foraging whatever flora it can reach with sharp little teeth. It doesn't seem to mind you too much.", "default_faction": "alien_herbivore", "bodytype": "gator", "categories": [ "ALIEN" ], @@ -130,7 +130,7 @@ "id": "dks_mon_packliz", "type": "MONSTER", "name": "pack lizard", - "description": "A slim reptoid about the size of a big dog, with a thick mane of what looks like rather pretty orange-blue 'feathers' around its head. Frond-like protrusions grow from the top of its head down to the base of its tail, glowing faintly when in the presence of other members of its pack.", + "description": "A slim reptiloid about the size of a big dog, with a rather pretty, thick, orange-blue mane of what look like 'feathers' around its head. Frond-like protrusions grow from the top of its head down to the base of its tail, glowing faintly when in the presence of other members of its pack.", "default_faction": "alien_packliz", "bodytype": "gator", "categories": [ "ALIEN" ], diff --git a/data/mods/Dark-Skies-Above/monsters/alien_robots.json b/data/mods/Dark-Skies-Above/monsters/alien_robots.json index 7885a4fdcbef6..7dab18c2aebfc 100644 --- a/data/mods/Dark-Skies-Above/monsters/alien_robots.json +++ b/data/mods/Dark-Skies-Above/monsters/alien_robots.json @@ -3,7 +3,7 @@ "id": "mon_dks_glowdrone", "type": "MONSTER", "name": { "str": "alien surveillance drone" }, - "description": "A small, sleek, white-plated robot bearing a golden insignia. Capable of limited flight, it hovers about the ruins of the former world, onboard cameras and spotlights impartial witness to the chaos around it. Who knows might be watching on the other side…", + "description": "A small, sleek, white-plated robot bearing a golden insignia. Capable of limited flight, it hovers about the ruins of the former world, on-board cameras and spotlights impartial witness to the chaos around it. Who knows what might be watching on the other side…", "default_faction": "invader_alien", "looks_like": "mon_eyebot", "categories": [ "ALIEN" ], diff --git a/data/mods/Dark-Skies-Above/monsters/strays.json b/data/mods/Dark-Skies-Above/monsters/strays.json index a479d61b33fcd..97cf7eb220967 100644 --- a/data/mods/Dark-Skies-Above/monsters/strays.json +++ b/data/mods/Dark-Skies-Above/monsters/strays.json @@ -74,7 +74,7 @@ "id": "dks_mon_stray_soldier", "type": "MONSTER", "name": { "str": "stray soldier" }, - "description": "A former soldier, no doubt deployed to assist with evacuations and drive off the aliens, dressed from head to toe in partially crystalized combat armor. Though their training could not have prepared them for what they were up against, they still seem to remember enough to take you on.", + "description": "A former soldier, no doubt deployed to assist with evacuations and drive off the aliens, dressed from head to toe in partially crystallized combat armor. Though their training could not have prepared them for what they were up against, they still seem to remember enough to take you on.", "looks_like": "mon_zombie_soldier", "default_faction": "stray", "bodytype": "human", @@ -500,7 +500,7 @@ "id": "dks_mon_stray_predator", "type": "MONSTER", "name": { "str": "stray guardian" }, - "description": "Lithe muscle and pulsating crystal fused together into a mass that must be made up of multiple bodies, propelled forward by multiple grossly enlongated crystal limbs sharpened to dangerous points. It strides about the streets, spearing those who dare intrude on its domain like some sort of horrid spider from beyond the stars.", + "description": "Lithe muscle and pulsating crystal fused together into a mass that must be made up of multiple bodies, propelled forward by multiple grossly elongated crystal limbs sharpened to dangerous points. It strides about the streets, spearing those who dare intrude on its domain like some sort of horrid spider from beyond the stars.", "default_faction": "stray", "looks_like": "mon_zombie_predator", "bodytype": "human", @@ -748,7 +748,7 @@ "id": "dks_mon_stray_wretch_burnt", "type": "MONSTER", "name": { "str": "stray creep" }, - "description": "A terrifying, hairy husk of a creature scrambling about on all fours, a mongrel housepet or the like covered in patches of crystal growths that jut from it like spikes.", + "description": "A terrifying, hairy husk of a creature scrambling about on all fours, a mongrel house pet or the like covered in patches of crystal growths that jut from it like spikes.", "default_faction": "stray", "looks_like": "mon_dog_zombie_rot", "bodytype": "dog", @@ -793,7 +793,7 @@ "id": "dks_mon_stray_wretch", "type": "MONSTER", "name": { "str": "stray wretch", "str_pl": "stray wretches" }, - "description": "This blur of jagged, crystal-fused limbs and hair could have been anything from a housepet to a human at some point, but now it leaps and skitters around like something out of a nightmare.", + "description": "This blur of jagged, crystal-fused limbs and hair could have been anything from a house pet to a human at some point, but now it leaps and skitters around like something out of a nightmare.", "default_faction": "stray", "looks_like": "mon_zombie_dog", "bodytype": "dog", @@ -1112,7 +1112,7 @@ "id": "dks_mon_crystal_whip", "type": "MONSTER", "name": { "str": "flailing crystal mass", "str_pl": "flailing crystal masses" }, - "description": "A tall, singular crystal, growing out of a sizable pile of debris that has sprouted a multitude of thin, whiplike tendrils that constantly snake around it like feelers. It frequently grabs nearby objects and drags them into the pile beneath it, as if hoarding.", + "description": "A tall, singular crystal, growing out of a sizable pile of debris that has sprouted a multitude of thin, whip-like tendrils that constantly snake around it like feelers. It frequently grabs nearby objects and drags them into the pile beneath it, as if hoarding.", "default_faction": "stray", "bodytype": "blob", "categories": [ "ALIEN" ], @@ -1236,7 +1236,7 @@ "id": "dks_mon_crystal_mite", "type": "MONSTER", "name": { "str": "crystal seed" }, - "description": "A tiny, multilegged creature that appears to be made of a chunk of crystal. It skitters around on wire-like legs, eating bits of organic leftovers to gain mass in hopes of one day seeding a crystal colony of its own.", + "description": "A tiny, multi-legged creature that appears to be made of a chunk of crystal. It skitters around on wire-like legs, eating bits of organic leftovers. Possibly to gain mass in hopes of one day seeding a crystal colony of its own.", "default_faction": "stray", "bodytype": "spider", "categories": [ "ALIEN" ], diff --git a/data/mods/Dark-Skies-Above/obsolete.json b/data/mods/Dark-Skies-Above/obsolete.json index 775497a48f981..d9fd020b4da5b 100644 --- a/data/mods/Dark-Skies-Above/obsolete.json +++ b/data/mods/Dark-Skies-Above/obsolete.json @@ -5,7 +5,7 @@ "category": "weapons", "looks_like": "zweihander", "name": { "str": "salvaged consecrator's sword" }, - "description": "A well built and decorated sword forged from dense alien metal. Its ability to conjure fireballs does not seem to respond to your will, but the cutting edge is perfectly servicable.", + "description": "A well built and decorated sword forged from dense alien metal. Its ability to conjure fireballs does not seem to respond to your will, but the cutting edge is perfectly serviceable.", "weight": "5400 g", "volume": "3750 ml", "price": 310000, @@ -27,7 +27,7 @@ "color": "light_gray", "looks_like": "arming_sword", "name": { "str": "salvaged knight's sword" }, - "description": "A well built sword made from dense alien metal, in service of the knights of the New Order. The runes that adorn it no longer glow, but its cutting edge is perfectly servicable.", + "description": "A well built sword made from dense alien metal, in service of the knights of the New Order. The runes that adorn it no longer glow, but its cutting edge is perfectly serviceable.", "price": 100000, "material": [ "superalloy" ], "techniques": [ "WBLOCK_2" ], @@ -96,7 +96,7 @@ "type": "ARMOR", "name": "new order battle shield", "category": "armor", - "description": "A well forged shield made of steel, emblazed with what appears to be a highly stylized depiction of a sword piercing a star.", + "description": "A well forged shield made of steel, emblazoned with what appears to be a highly stylized depiction of a sword piercing a star.", "weight": "3300 g", "volume": "5 L", "price": 110000, diff --git a/data/mods/Dark-Skies-Above/overrides/items/carnivore.json b/data/mods/Dark-Skies-Above/overrides/items/carnivore.json index 2ac90c7661050..66773192c0b29 100644 --- a/data/mods/Dark-Skies-Above/overrides/items/carnivore.json +++ b/data/mods/Dark-Skies-Above/overrides/items/carnivore.json @@ -13,7 +13,7 @@ "id": "meat_tainted", "copy-from": "meat_tainted", "name": { "str": "chunk of alien meat", "str_pl": "chunks of alien meat" }, - "description": "This dense, stringy substance smells strongly like burnt oil, or some sort of industrial chemical. For all intents and purposes, it seems like the 'meat' of the creature, but its bizarre texture and faintly red-purple tint is unlike anything you've ever experienced before. You could eat it, but no doubt it would not only taste henious but also make you sick, being made of material your body was never supposed to injest." + "description": "This dense, stringy substance smells strongly like burnt oil, or some sort of industrial chemical. For all intents and purposes, it seems like the 'meat' of the creature, but its bizarre texture and faintly red-purple tint is unlike anything you've ever experienced before. You could eat it, but no doubt it would not only taste heinous but also make you sick, being made of material your body was never supposed to ingest." }, { "type": "COMESTIBLE", @@ -36,7 +36,7 @@ "category": "other", "copy-from": "fat_tainted", "name": "alien fat", - "description": "A chunk of dense fat that is tough and rubbery. It smells simply henious, like open sewer and pungent chemicals, and is doubtless full of strange material that your body was never supposed to injest. It might at least be able to be used for something, if not quite as well as its earthly variant due to its relative impurities." + "description": "A chunk of dense fat that is tough and rubbery. It smells simply heinous, like open sewer and pungent chemicals, and is doubtless full of strange material that your body was never supposed to injest. It might at least be able to be used for something, if not quite as well as its earthly variant due to its relative impurities." }, { "type": "COMESTIBLE", @@ -51,7 +51,7 @@ "copy-from": "mutant_meat", "type": "COMESTIBLE", "name": { "str": "chunk of unusual meat", "str_pl": "chunks of unusual meat" }, - "description": "Meat from the aliens is typically quite foul, full of toxins and substances not meant to be digested by humans, however this piece almost looks edible - if not for a few sections that still have strange hues and disgusting, spongey texture. Still, with a bit of preperation, it might even be somewhat palatable." + "description": "Meat from the aliens is typically quite foul, full of toxins and substances not meant to be digested by humans. However, this piece almost looks edible - if not for a few sections that still have strange hues and disgusting, spongy texture. Still, with a bit of preparation, it might even be somewhat palatable." }, { "id": "mutant_meat_scrap", diff --git a/data/mods/Dark-Skies-Above/overrides/items/tools.json b/data/mods/Dark-Skies-Above/overrides/items/tools.json index b2fb5b286510b..e5e6269968ac9 100644 --- a/data/mods/Dark-Skies-Above/overrides/items/tools.json +++ b/data/mods/Dark-Skies-Above/overrides/items/tools.json @@ -25,7 +25,7 @@ "copy-from": "e_handcuffs", "type": "TOOL", "name": { "str_sp": "electronic handcuffs" }, - "description": "A pair of electronic handcuffs, used by automated New Order units to detain captives. Their continuous siren clearly identifies the wearer as a person of interet and alerts nearby 'safety teams' to their presence. Wait for their arrival, don't try to escape or to remove the cuffs - they will administer an electric shock.\nHowever, since capture is out of the question, you're probably in for a painful time, unless you get creative…" + "description": "A pair of electronic handcuffs, used by automated New Order units to detain captives. Their continuous siren clearly identifies the wearer as a person of internet and alerts nearby 'safety teams' to their presence. Wait for their arrival, don't try to escape or to remove the cuffs - they will administer an electric shock.\nHowever, since capture is out of the question, you're probably in for a painful time, unless you get creative…" }, { "id": "trimmer_off", diff --git a/data/mods/Dark-Skies-Above/snippets/fliers.json b/data/mods/Dark-Skies-Above/snippets/fliers.json index 8cc46f484f30f..60cb7c04c3fe0 100644 --- a/data/mods/Dark-Skies-Above/snippets/fliers.json +++ b/data/mods/Dark-Skies-Above/snippets/fliers.json @@ -39,7 +39,7 @@ }, { "id": "dks_flier_11", - "text": "This is a government-issued, air-dropped alert. \"EVACUTE IMMEDIATELY. Proceed to your closest FEMA operated community shelter to await police and military escort to safety.\"" + "text": "This is a government-issued, air-dropped alert. \"EVACUATE IMMEDIATELY. Proceed to your closest FEMA operated community shelter to await police and military escort to safety.\"" }, { "id": "dks_flier_12", @@ -59,7 +59,7 @@ }, { "id": "dks_flier_16", - "text": "This is a glossy advertisement from FEMA asking that people donate their canned goods in return for tax writeoffs. From the date on the flier, it doesn't look like the initative ever had time to get off the ground." + "text": "This is a glossy advertisement from FEMA asking that people donate their canned goods in return for tax write-offs. From the date on the flier, it doesn't look like the initiative ever had time to get off the ground." }, { "id": "dks_flier_17", diff --git a/data/mods/Dark-Skies-Above/snippets/graffiti.json b/data/mods/Dark-Skies-Above/snippets/graffiti.json index 421707be4f8d3..061c3095ea3f9 100644 --- a/data/mods/Dark-Skies-Above/snippets/graffiti.json +++ b/data/mods/Dark-Skies-Above/snippets/graffiti.json @@ -13,7 +13,7 @@ { "id": "dks_general_graffiti_7", "text": "MOM" }, { "id": "dks_general_graffiti_8", "text": "FUCK YOU" }, { "id": "dks_general_graffiti_9", "text": "This is a cartoon rendition of an alien." }, - { "id": "dks_general_graffiti_10", "text": "This is a crudely spraypainted tag adorned with skulls." }, + { "id": "dks_general_graffiti_10", "text": "This is a crudely spray-painted tag adorned with skulls." }, { "id": "dks_general_graffiti_11", "text": "I have a secure and loving relationship with your mom and you're going to need to come to terms with that.\n\nDo you want to talk about it? You know where to find me. Love you sweety." @@ -23,7 +23,7 @@ { "id": "dks_general_graffiti_14", "text": " fucked ." }, { "id": "dks_general_graffiti_15", - "text": "This is a spraypainted drawing of an angel with wings made of vines." + "text": "This is a spray-painted drawing of an angel with wings made of vines." }, { "id": "dks_general_graffiti_16", "text": "Mr. is a vampire!" }, { "id": "dks_general_graffiti_17", "text": "Their hiding the truth" }, @@ -39,10 +39,10 @@ "id": "dks_general_graffiti_23", "text": "And they walked upon His Earth, and there was a RECKONING, and only the worthy survived" }, - { "id": "dks_general_graffiti_24", "text": "This is a drawing of a zombie with a bullethole in its head." }, + { "id": "dks_general_graffiti_24", "text": "This is a drawing of a zombie with a bullet hole in its head." }, { "id": "dks_general_graffiti_25", "text": "This is a surprisingly artistic drawing of a penis." }, - { "id": "dks_general_graffiti_26", "text": "This is a simple spraypainted graphic of a forest made of bones." }, - { "id": "dks_general_graffiti_27", "text": "This is a drawing of an alien with a bullethole in its head." }, + { "id": "dks_general_graffiti_26", "text": "This is a simple spray-painted graphic of a forest made of bones." }, + { "id": "dks_general_graffiti_27", "text": "This is a drawing of an alien with a bullet hole in its head." }, { "id": "dks_general_graffiti_28", "text": "we can never go back" }, { "id": "dks_general_graffiti_29", "text": "dont by meth from " }, { "id": "dks_general_graffiti_30", "text": " you owe me fifty bucks" }, @@ -50,7 +50,7 @@ { "id": "dks_general_graffiti_32", "text": "eyes to the skies" }, { "id": "dks_general_graffiti_33", - "text": "This is a spraypainting of an anatomically unlikely woman wearing very little." + "text": "This is a spray-painting of an anatomically unlikely woman wearing very little." } ] }, diff --git a/data/mods/Dark-Skies-Above/snippets/newspaper.json b/data/mods/Dark-Skies-Above/snippets/newspaper.json index d99a7ac8c5992..5e3f767c6a6c9 100644 --- a/data/mods/Dark-Skies-Above/snippets/newspaper.json +++ b/data/mods/Dark-Skies-Above/snippets/newspaper.json @@ -142,7 +142,7 @@ }, { "id": "dks_months_old_news_8", - "text": "FOODPLACE PANTS FEUD. An ongoing legal battle between popular fast food megalith Foodplace and the non-profit Concerned Consumers of Foodpeople has ended with the determination that the Foodperson costume will remain a gender-neutral, nonrevealing unitard. \"Superheroes are meant to have exaggerated anatomy and revealing costumes,\" a spokesperson from CCF said in a press release. \"This is a sad day not just for fans of Foodplace, but for consumers of the fast-food superhero genre overall.\"" + "text": "FOODPLACE PANTS FEUD. An ongoing legal battle between popular fast food megalith Foodplace and the non-profit Concerned Consumers of Foodpeople has ended with the determination that the Foodperson costume will remain a gender-neutral, non-revealing unitard. \"Superheroes are meant to have exaggerated anatomy and revealing costumes,\" a spokesperson from CCF said in a press release. \"This is a sad day not just for fans of Foodplace, but for consumers of the fast-food superhero genre overall.\"" }, { "id": "dks_months_old_news_9", From caee55ca72f2535c5128626b2ff188b8611e8cd1 Mon Sep 17 00:00:00 2001 From: Maleclypse <54345792+Maleclypse@users.noreply.github.com> Date: Thu, 25 Mar 2021 01:51:11 -0500 Subject: [PATCH 085/453] Valentine Card Spawn (#48210) --- data/json/itemgroups/books.json | 6 +++++- 1 file changed, 5 insertions(+), 1 deletion(-) diff --git a/data/json/itemgroups/books.json b/data/json/itemgroups/books.json index 3524ef56ceca3..538cdd0d7e9d5 100644 --- a/data/json/itemgroups/books.json +++ b/data/json/itemgroups/books.json @@ -777,7 +777,11 @@ "id": "newspaper", "type": "item_group", "subtype": "distribution", - "entries": [ { "group": "newspaper_recent", "prob": 80 }, { "group": "newspaper_old", "prob": 20 } ] + "entries": [ + { "group": "newspaper_recent", "prob": 79 }, + { "group": "newspaper_old", "prob": 20 }, + { "item": "valentine_card", "prob": 1 } + ] }, { "id": "newspaper_recent", From 664e7cb8d54d1b49ce625ab05330196c87f81ab8 Mon Sep 17 00:00:00 2001 From: John Candlebury Date: Thu, 25 Mar 2021 00:57:24 -0600 Subject: [PATCH 086/453] Blacklist/Whitelist monsters by species (#48203) * Blacklist/Whitelist monsters by species * Document new blacklist feature --- doc/MODDING.md | 11 ++++++++++- src/mongroup.cpp | 16 ++++++++++++++++ src/mongroup.h | 3 +++ 3 files changed, 29 insertions(+), 1 deletion(-) diff --git a/doc/MODDING.md b/doc/MODDING.md index f84234baf268a..6b6d2fa638421 100644 --- a/doc/MODDING.md +++ b/doc/MODDING.md @@ -135,7 +135,7 @@ Items are where you really want to read the [JSON_INFO.md](JSON_INFO.md) file, j ```` ### Preventing monsters from spawning -This kind of mod is relatively simple, but very useful. If you don't want to deal with certain types of monsters in your world, this is how you do it. There are two ways to go about this, and both will be detailed below. You can blacklist entire monster groups, or you can blacklist certain monsters. In order to do either of those things, you need that monster's ID. These can be found in the relevant data files. For the core game, these are in the `data/json/monsters` directory. +This kind of mod is relatively simple, but very useful. If you don't want to deal with certain types of monsters in your world, this is how you do it. There are two ways to go about this, and both will be detailed below. You can blacklist entire monster groups, blacklist monsters by their specified species, or you can blacklist individual monsters. In order to do any of those things, you need that monster's ID or SPECIES data. These can be found in the relevant data files. For the core game, these are in the `data/json/monsters` directory. The example below is from the `No Ants` mod, and will stop any kind of ant from spawning in-game. ````json [ @@ -158,6 +158,15 @@ The example below is from the `No Ants` mod, and will stop any kind of ant from } ] ```` +The following is an example of how to blacklist monsters by species. In this case, it would remove all fungaloids from the game. +````json +[ + { + "type": "MONSTER_BLACKLIST", + "species": [ "FUNGUS" ] + } +] +```` ### Preventing locations from spawning Preventing certain types of locations from spawning in-game is a little trickier depending on the type of thing you want to target. An overmap building can either be a standard building, or an overmap special. If you want to block things with a specific flag from spawning, you can blacklist those in a very similar manner to monsters. The example below is also from the `No Ants` mod, and stops all anthills from spawning. diff --git a/src/mongroup.cpp b/src/mongroup.cpp index 02c84c8679e93..599a33a4650d6 100644 --- a/src/mongroup.cpp +++ b/src/mongroup.cpp @@ -25,6 +25,9 @@ MonsterGroupManager::t_string_set MonsterGroupManager::monster_blacklist; MonsterGroupManager::t_string_set MonsterGroupManager::monster_whitelist; MonsterGroupManager::t_string_set MonsterGroupManager::monster_categories_blacklist; MonsterGroupManager::t_string_set MonsterGroupManager::monster_categories_whitelist; +MonsterGroupManager::t_string_set MonsterGroupManager::monster_species_blacklist; +MonsterGroupManager::t_string_set MonsterGroupManager::monster_species_whitelist; + static bool monster_whitelist_is_exclusive = false; /** @relates string_id */ @@ -266,6 +269,7 @@ void MonsterGroupManager::LoadMonsterBlacklist( const JsonObject &jo ) { add_array_to_set( monster_blacklist, jo, "monsters" ); add_array_to_set( monster_categories_blacklist, jo, "categories" ); + add_array_to_set( monster_species_blacklist, jo, "species" ); } void MonsterGroupManager::LoadMonsterWhitelist( const JsonObject &jo ) @@ -275,6 +279,8 @@ void MonsterGroupManager::LoadMonsterWhitelist( const JsonObject &jo ) } add_array_to_set( monster_whitelist, jo, "monsters" ); add_array_to_set( monster_categories_whitelist, jo, "categories" ); + add_array_to_set( monster_species_whitelist, jo, "species" ); + } bool MonsterGroupManager::monster_is_blacklisted( const mtype_id &m ) @@ -288,11 +294,21 @@ bool MonsterGroupManager::monster_is_blacklisted( const mtype_id &m ) return false; } } + for( const auto &elem : monster_species_whitelist ) { + if( mt.in_species( species_id( elem ) ) ) { + return false; + } + } for( const auto &elem : monster_categories_blacklist ) { if( mt.categories.count( elem ) > 0 ) { return true; } } + for( const auto &elem : monster_species_blacklist ) { + if( mt.in_species( species_id( elem ) ) ) { + return true; + } + } if( monster_blacklist.count( m.str() ) > 0 ) { return true; } diff --git a/src/mongroup.h b/src/mongroup.h index cd60f6aa344f2..8963df319754f 100644 --- a/src/mongroup.h +++ b/src/mongroup.h @@ -197,6 +197,9 @@ class MonsterGroupManager static t_string_set monster_whitelist; static t_string_set monster_categories_blacklist; static t_string_set monster_categories_whitelist; + static t_string_set monster_species_blacklist; + static t_string_set monster_species_whitelist; + }; #endif // CATA_SRC_MONGROUP_H From 0f7fa9a8873d0b8dbaaf0a452989943c2266975d Mon Sep 17 00:00:00 2001 From: OromisElf Date: Thu, 25 Mar 2021 08:02:00 +0100 Subject: [PATCH 087/453] [Magiclysm] bundles (#48118) --- data/mods/Magiclysm/items/alchemy_items.json | 9 ++++++ .../Magiclysm/items/black_dragon_items.json | 20 +++++++++++++ data/mods/Magiclysm/recipes/alchemy.json | 12 ++++++++ data/mods/Magiclysm/recipes/dragon_black.json | 28 +++++++++++++++++++ 4 files changed, 69 insertions(+) diff --git a/data/mods/Magiclysm/items/alchemy_items.json b/data/mods/Magiclysm/items/alchemy_items.json index b9ee2454e18ef..e3c3a17f1e0b9 100644 --- a/data/mods/Magiclysm/items/alchemy_items.json +++ b/data/mods/Magiclysm/items/alchemy_items.json @@ -209,6 +209,15 @@ "flags": [ "TRADER_AVOID" ], "to_hit": -2 }, + { + "id": "bundle_demon_chitin_piece", + "type": "GENERIC", + "copy-from": "demon_chitin_piece", + "symbol": "=", + "name": { "str": "bundle of demon chitin chunks", "str_pl": "bundles of demon chitin chunks" }, + "proportional": { "price": 10, "weight": 10, "volume": 10 }, + "description": "Pieces of demon spider exoskeleton, bundled tightly together for storage. Disassemble to unpack." + }, { "type": "GENERIC", "id": "demon_chitin_plate", diff --git a/data/mods/Magiclysm/items/black_dragon_items.json b/data/mods/Magiclysm/items/black_dragon_items.json index b80da5799de16..64cda2534e678 100644 --- a/data/mods/Magiclysm/items/black_dragon_items.json +++ b/data/mods/Magiclysm/items/black_dragon_items.json @@ -14,6 +14,16 @@ "to_hit": -4, "description": "A scale from a black dragon. It still has its magical properties and acid resistance." }, + { + "id": "bundle_black_scale", + "type": "GENERIC", + "copy-from": "dragon_black_scale", + "symbol": "=", + "name": { "str": "bundle of black dragon scales", "str_pl": "bundles of black dragon scales" }, + "//": "inspiration from bundle of planks", + "proportional": { "price": 10, "weight": 10, "volume": 10 }, + "description": "Scales from a black dragon, bundled tightly together for storage. Disassemble to unpack." + }, { "type": "COMESTIBLE", "id": "black_dragon_hide_raw", @@ -70,6 +80,16 @@ "category": "spare_parts", "to_hit": -1 }, + { + "id": "bundle_black_hide", + "type": "GENERIC", + "copy-from": "black_dragon_tanned_hide", + "symbol": ",", + "name": { "str": "bundle of black dragon hides", "str_pl": "bundles of black dragon hides" }, + "//": "inspiration from bundle of leather", + "proportional": { "price": 10, "weight": 10, "volume": 4 }, + "description": "Hides from a black dragon, bundled tightly together for storage. Disassemble to unpack." + }, { "id": "boots_black_dragon_scale", "type": "ARMOR", diff --git a/data/mods/Magiclysm/recipes/alchemy.json b/data/mods/Magiclysm/recipes/alchemy.json index 17392e98cf3d8..3825e8ab6ab3c 100644 --- a/data/mods/Magiclysm/recipes/alchemy.json +++ b/data/mods/Magiclysm/recipes/alchemy.json @@ -97,5 +97,17 @@ "category": "CC_ENCHANTED", "subcategory": "CSC_ENCHANTED_OTHER", "autolearn": true + }, + { + "result": "bundle_demon_chitin_piece", + "type": "recipe", + "activity_level": "NO_EXERCISE", + "category": "CC_ENCHANTED", + "subcategory": "CSC_ENCHANTED_MATERIALS", + "skill_used": "fabrication", + "time": "1 m", + "autolearn": true, + "reversible": true, + "components": [ [ [ "demon_chitin_piece", 10 ] ], [ [ "rope_any_short", 1, "LIST" ] ] ] } ] diff --git a/data/mods/Magiclysm/recipes/dragon_black.json b/data/mods/Magiclysm/recipes/dragon_black.json index fcb7b60c4f22c..a39e48973c49d 100644 --- a/data/mods/Magiclysm/recipes/dragon_black.json +++ b/data/mods/Magiclysm/recipes/dragon_black.json @@ -23,6 +23,34 @@ "book_learn": [ [ "black_dragons", 2 ] ], "components": [ [ [ "dragon_essence", 1 ] ], [ [ "black_dragon_hide_raw", 1 ] ] ] }, + { + "result": "bundle_black_scale", + "type": "recipe", + "activity_level": "NO_EXERCISE", + "category": "CC_ENCHANTED", + "subcategory": "CSC_ENCHANTED_MATERIALS", + "skill_used": "fabrication", + "time": "1 m", + "autolearn": true, + "//": "volume of black dragon hide is leather x8 so it neeeds x8 filament", + "using": [ [ "filament", 64 ] ], + "qualities": [ { "id": "SEW", "level": 2 } ], + "components": [ [ [ "dragon_black_scale", 10 ] ], [ [ "rag", 3 ] ] ] + }, + { + "result": "bundle_black_hide", + "type": "recipe", + "activity_level": "NO_EXERCISE", + "category": "CC_ENCHANTED", + "subcategory": "CSC_ENCHANTED_MATERIALS", + "skill_used": "fabrication", + "time": "1 m", + "autolearn": true, + "using": [ [ "filament", 8 ] ], + "qualities": [ { "id": "SEW", "level": 1 } ], + "components": [ [ [ "black_dragon_tanned_hide", 10 ] ] ], + "flags": [ "BLIND_HARD" ] + }, { "result": "suit_black_dragon_hide", "type": "recipe", From 3e5fdbfcd6cac33e0b28ad92e5e4c84221b1f842 Mon Sep 17 00:00:00 2001 From: Jamuro-g <76928284+Jamuro-g@users.noreply.github.com> Date: Thu, 25 Mar 2021 08:15:20 +0100 Subject: [PATCH 088/453] cap pain gain from hauling heavy furniture (#47586) --- src/game.cpp | 14 ++++++++++++++ 1 file changed, 14 insertions(+) diff --git a/src/game.cpp b/src/game.cpp index dd8e7e57197ac..228a4230f54ab 100644 --- a/src/game.cpp +++ b/src/game.cpp @@ -10506,6 +10506,20 @@ bool game::grabbed_furn_move( const tripoint &dp ) // TODO: What is something? add_msg( _( "The %s collides with something." ), furntype.name() ); return true; + } else if( str_req > u.get_str() && u.get_perceived_pain() > 40 && + !u.has_trait( trait_id( "CENOBITE" ) ) && !u.has_trait( trait_id( "MASOCHIST" ) ) && + !u.has_trait( trait_id( "MASOCHIST_MED" ) ) ) { + add_msg( m_bad, _( "You are in too much pain to try moving the heavy %s!" ), + furntype.name() ); + return false; + + } else if( str_req > u.get_str() && u.get_perceived_pain() > 50 && + ( u.has_trait( trait_id( "MASOCHIST" ) ) || u.has_trait( trait_id( "MASOCHIST_MED" ) ) ) ) { + add_msg( m_bad, + _( "Even with your appetite for pain, you are in too much pain to try moving the heavy %s!" ), + furntype.name() ); + return false; + ///\EFFECT_STR determines ability to drag furniture } else if( str_req > u.get_str() && one_in( std::max( 20 - str_req - u.get_str(), 2 ) ) ) { From 57ccd1d66fcbd38e43bf8067465116dc953a0e0a Mon Sep 17 00:00:00 2001 From: Jamuro-g <76928284+Jamuro-g@users.noreply.github.com> Date: Thu, 25 Mar 2021 08:15:54 +0100 Subject: [PATCH 089/453] Fix allows siphon action to transfer tank contents inside same vehicle (#47647) --- src/handle_liquid.cpp | 24 +++++++++++++++++------- 1 file changed, 17 insertions(+), 7 deletions(-) diff --git a/src/handle_liquid.cpp b/src/handle_liquid.cpp index 3d83a03e4b697..dac6d78424828 100644 --- a/src/handle_liquid.cpp +++ b/src/handle_liquid.cpp @@ -247,14 +247,24 @@ static bool get_liquid_target( item &liquid, const item *const source, const int } } for( vehicle *veh : opts ) { - if( veh == source_veh ) { - continue; + if( veh == source_veh && veh->has_part( "FLUIDTANK", false ) ) { + for( const vpart_reference &vp : veh->get_avail_parts( "FLUIDTANK" ) ) { + if( vp.part().get_base().is_reloadable_with( liquid.typeId() ) ) { + menu.addentry( -1, true, MENU_AUTOASSIGN, _( "Fill avaliable tank" ) ); + actions.emplace_back( [ &, veh]() { + target.veh = veh; + target.dest_opt = LD_VEH; + } ); + break; + } + } + } else { + menu.addentry( -1, true, MENU_AUTOASSIGN, _( "Fill nearby vehicle %s" ), veh->name ); + actions.emplace_back( [ &, veh]() { + target.veh = veh; + target.dest_opt = LD_VEH; + } ); } - menu.addentry( -1, true, MENU_AUTOASSIGN, _( "Fill nearby vehicle %s" ), veh->name ); - actions.emplace_back( [ &, veh]() { - target.veh = veh; - target.dest_opt = LD_VEH; - } ); } for( const tripoint &target_pos : here.points_in_radius( player_character.pos(), 1 ) ) { From b7383ca689a66c732eb6929648f18e057914facd Mon Sep 17 00:00:00 2001 From: Saicchi <47158232+Saicchi@users.noreply.github.com> Date: Thu, 25 Mar 2021 04:16:45 -0300 Subject: [PATCH 090/453] Allow filtering debug messages by type (#47619) --- src/activity_actor.cpp | 8 ++- src/activity_handlers.cpp | 10 +-- src/activity_item_handling.cpp | 2 +- src/anatomy.cpp | 4 +- src/avatar.cpp | 6 +- src/ballistics.cpp | 3 +- src/character.cpp | 29 ++++---- src/consumption.cpp | 10 +-- src/creature.cpp | 31 +++++++-- src/creature.h | 87 +++++++++++++++++++++++ src/debug.cpp | 46 ++++++++++++ src/debug.h | 41 +++++++++++ src/effect.cpp | 8 ++- src/explosion.cpp | 13 ++-- src/game.cpp | 15 ++-- src/handle_action.cpp | 123 +++++++++++++++++++++++++++++++-- src/iexamine.cpp | 3 +- src/iuse_actor.cpp | 2 +- src/map.cpp | 11 +-- src/mattack_actors.cpp | 4 +- src/melee.cpp | 22 +++--- src/messages.cpp | 33 +++++++++ src/messages.h | 66 ++++++++++++++++-- src/monattack.cpp | 23 +++--- src/monster.cpp | 19 ++++- src/monster.h | 5 ++ src/npc.cpp | 29 ++++++-- src/npc.h | 8 +++ src/npcmove.cpp | 78 +++++++++++---------- src/npctalk.cpp | 11 +-- src/npctalk_funcs.cpp | 2 +- src/overmap.cpp | 4 +- src/player.cpp | 12 ++++ src/player.h | 6 ++ src/ranged.cpp | 3 +- src/sdlsound.cpp | 4 +- src/sounds.cpp | 40 ++++++----- src/suffer.cpp | 8 +-- src/talker_avatar.cpp | 2 +- src/talker_npc.cpp | 4 +- src/vehicle.cpp | 54 +++++++++------ src/vehicle_move.cpp | 13 ++-- tests/fake_messages.cpp | 19 +++++ 43 files changed, 719 insertions(+), 202 deletions(-) diff --git a/src/activity_actor.cpp b/src/activity_actor.cpp index 06e346b4b4a23..69d6dbd6bb27c 100644 --- a/src/activity_actor.cpp +++ b/src/activity_actor.cpp @@ -1215,7 +1215,9 @@ void lockpick_activity_actor::finish( player_activity &act, Character &who ) // In the meantime, let's roll 3d5-3, giving us a range of 0-12. int lock_roll = rng( 0, 4 ) + rng( 0, 4 ) + rng( 0, 4 ); - add_msg( m_debug, _( "Rolled %i. Mean_roll %g. Difficulty %i." ), pick_roll, mean_roll, lock_roll ); + add_msg_debug( debugmode::DF_ACT_LOCKPICK, _( "Rolled %i. Mean_roll %g. Difficulty %i." ), + pick_roll, + mean_roll, lock_roll ); // Your base skill XP gain is derived from the lock difficulty (which is currently random but shouldn't be). int xp_gain = 3 * lock_roll; @@ -2027,8 +2029,8 @@ void workout_activity_actor::do_turn( player_activity &act, Character &who ) who.add_morale( MORALE_FEELING_GOOD, intensity_modifier, 20, 6_hours, 30_minutes ); } if( calendar::once_every( 2_minutes ) ) { - who.add_msg_if_player( m_debug, who.activity_level_str() ); - who.add_msg_if_player( m_debug, act.id().c_str() ); + who.add_msg_debug_if_player( debugmode::DF_ACT_WORKOUT, who.activity_level_str() ); + who.add_msg_debug_if_player( debugmode::DF_ACT_WORKOUT, act.id().c_str() ); } } else if( !rest_mode ) { rest_mode = true; diff --git a/src/activity_handlers.cpp b/src/activity_handlers.cpp index 76423042b7f4f..507458cc82f55 100644 --- a/src/activity_handlers.cpp +++ b/src/activity_handlers.cpp @@ -418,8 +418,9 @@ static bool check_butcher_cbm( const int roll ) // 90% at roll 0, 72% at roll 1, 60% at roll 2, 51% @ 3, 45% @ 4, 40% @ 5, ... , 25% @ 10 // Roll is roughly a rng(0, -3 + 1st_aid + fine_cut_quality + 1/2 electronics + small_dex_bonus) // Roll is reduced by corpse damage level, but to no less then 0 - add_msg_debug( _( "Roll = %i" ), roll ); - add_msg_debug( _( "Failure chance = %f%%" ), ( 9.0f / ( 10.0f + roll * 2.5f ) ) * 100.0f ); + add_msg_debug( debugmode::DF_ACT_BUTCHER, _( "Roll = %i" ), roll ); + add_msg_debug( debugmode::DF_ACT_BUTCHER, _( "Failure chance = %f%%" ), + ( 9.0f / ( 10.0f + roll * 2.5f ) ) * 100.0f ); const bool failed = x_in_y( 9, ( 10 + roll * 2.5 ) ); return !failed; } @@ -877,7 +878,8 @@ static void butchery_drops_harvest( item *corpse_item, const mtype &mt, player & int roll = roll_butchery() - corpse_item->damage_level(); roll = roll < 0 ? 0 : roll; roll = std::min( entry.max, roll ); - add_msg_debug( _( "Roll penalty for corpse damage = %s" ), 0 - corpse_item->damage_level() ); + add_msg_debug( debugmode::DF_ACT_BUTCHER, _( "Roll penalty for corpse damage = %s" ), + 0 - corpse_item->damage_level() ); if( entry.type == "bionic" ) { butcher_cbm_item( drop_id, p.pos(), calendar::turn, roll, entry.flags, entry.faults ); } else if( entry.type == "bionic_group" ) { @@ -1185,7 +1187,7 @@ void activity_handlers::butcher_finish( player_activity *act, player *p ) skill_level = p->get_skill_level( skill_firstaid ); skill_level += p->max_quality( qual_CUT_FINE ); skill_level += p->get_skill_level( skill_electronics ) / 2; - add_msg_debug( _( "Skill: %s" ), skill_level ); + add_msg_debug( debugmode::DF_ACT_BUTCHER, _( "Skill: %s" ), skill_level ); } const auto roll_butchery = [&]() { diff --git a/src/activity_item_handling.cpp b/src/activity_item_handling.cpp index c0dac279e5fae..226d4f4b61ec3 100644 --- a/src/activity_item_handling.cpp +++ b/src/activity_item_handling.cpp @@ -1613,7 +1613,7 @@ static std::vector> requirements_map( player } } for( const std::tuple &elem : final_map ) { - add_msg_debug( "%s is fetching %s from x: %d y: %d ", p.disp_name(), + add_msg_debug( debugmode::DF_REQUIREMENTS_MAP, "%s is fetching %s from x: %d y: %d ", p.disp_name(), std::get<1>( elem ).str(), std::get<0>( elem ).x, std::get<0>( elem ).y ); } return final_map; diff --git a/src/anatomy.cpp b/src/anatomy.cpp index 12562640cd971..725f9069024d1 100644 --- a/src/anatomy.cpp +++ b/src/anatomy.cpp @@ -181,7 +181,7 @@ bodypart_id anatomy::select_body_part( int size_diff, int hit_roll ) const // Debug for seeing weights. for( const weighted_object &pr : hit_weights ) { - add_msg_debug( "%s = %.3f", pr.obj.obj().name, pr.weight ); + add_msg_debug( debugmode::DF_ANATOMY_BP, "%s = %.3f", pr.obj.obj().name, pr.weight ); } const bodypart_id *ret = hit_weights.pick(); @@ -190,6 +190,6 @@ bodypart_id anatomy::select_body_part( int size_diff, int hit_roll ) const return bodypart_str_id::NULL_ID().id(); } - add_msg_debug( "selected part: %s", ret->id().obj().name ); + add_msg_debug( debugmode::DF_ANATOMY_BP, "selected part: %s", ret->id().obj().name ); return *ret; } diff --git a/src/avatar.cpp b/src/avatar.cpp index b28b60e68c89c..a71170d7a4be0 100644 --- a/src/avatar.cpp +++ b/src/avatar.cpp @@ -420,7 +420,7 @@ bool avatar::read( item &it, const bool continuous ) const int time_taken = time_to_read( it, *reader ); - add_msg_debug( "avatar::read: time_taken = %d", time_taken ); + add_msg_debug( debugmode::DF_AVATAR, "avatar::read: time_taken = %d", time_taken ); player_activity act( ACT_READ, time_taken, continuous ? activity.index : 0, reader->getID().get_value() ); act.targets.emplace_back( item_location( *this, &it ) ); @@ -872,7 +872,7 @@ void avatar::do_read( item &book ) skill_id skill_used = style_to_learn->primary_skill; int difficulty = std::max( 1, style_to_learn->learn_difficulty ); difficulty = std::max( 1, 20 + difficulty * 2 - get_skill_level( skill_used ) * 2 ); - add_msg_debug( _( "Chance to learn one in: %d" ), difficulty ); + add_msg_debug( debugmode::DF_AVATAR, _( "Chance to learn one in: %d" ), difficulty ); if( one_in( difficulty ) ) { m->second.call( *this, book, false, pos() ); @@ -1600,7 +1600,7 @@ bool avatar::wield( item &target, const int obtain_cost ) target.on_takeoff( *this ); } - add_msg_debug( "wielding took %d moves", mv ); + add_msg_debug( debugmode::DF_AVATAR, "wielding took %d moves", mv ); moves -= mv; if( has_item( target ) ) { diff --git a/src/ballistics.cpp b/src/ballistics.cpp index ff3ab4f987880..bd62aa24cdb4b 100644 --- a/src/ballistics.cpp +++ b/src/ballistics.cpp @@ -267,7 +267,8 @@ dealt_projectile_attack projectile_attack( const projectile &proj_arg, const tri trajectory = here.find_clear_path( source, target ); } - add_msg_debug( "missed_by_tiles: %.2f; missed_by: %.2f; target (orig/hit): %d,%d,%d/%d,%d,%d", + add_msg_debug( debugmode::DF_BALLISTIC, + "missed_by_tiles: %.2f; missed_by: %.2f; target (orig/hit): %d,%d,%d/%d,%d,%d", aim.missed_by_tiles, aim.missed_by, target_arg.x, target_arg.y, target_arg.z, target.x, target.y, target.z ); diff --git a/src/character.cpp b/src/character.cpp index 2fbad6bb7b331..ed979ffe9df73 100644 --- a/src/character.cpp +++ b/src/character.cpp @@ -1092,9 +1092,9 @@ bool Character::check_outbounds_activity( const player_activity &act, bool check } activity = player_activity(); } - add_msg_debug( - "npc %s at pos %d %d, activity target is not inbounds at %d %d therefore activity was stashed", - disp_name(), pos().x, pos().y, act.placement.x, act.placement.y ); + add_msg_debug( debugmode::DF_CHARACTER, + "npc %s at pos %d %d, activity target is not inbounds at %d %d therefore activity was stashed", + disp_name(), pos().x, pos().y, act.placement.x, act.placement.y ); return true; } return false; @@ -1120,7 +1120,7 @@ void Character::mount_creature( monster &z ) tripoint pnt = z.pos(); shared_ptr_fast mons = g->shared_from( z ); if( mons == nullptr ) { - add_msg_debug( "mount_creature(): monster not found in critter_tracker" ); + add_msg_debug( debugmode::DF_CHARACTER, "mount_creature(): monster not found in critter_tracker" ); return; } add_effect( effect_riding, 1_turns, true ); @@ -1311,7 +1311,8 @@ void Character::forced_dismount() } add_effect( effect_downed, 5_turns, true ); } else { - add_msg_debug( "Forced_dismount could not find a square to deposit player" ); + add_msg_debug( debugmode::DF_CHARACTER, + "Forced_dismount could not find a square to deposit player" ); } if( is_avatar() ) { avatar &player_character = get_avatar(); @@ -1335,7 +1336,7 @@ void Character::forced_dismount() void Character::dismount() { if( !is_mounted() ) { - add_msg_debug( "dismount called when not riding" ); + add_msg_debug( debugmode::DF_CHARACTER, "dismount called when not riding" ); return; } if( const cata::optional pnt = choose_adjacent( _( "Dismount where?" ) ) ) { @@ -5493,7 +5494,8 @@ void Character::update_health( int external_modifiers ) // Slowly near 0, but it's hard to overpower it near +/-100 set_healthy_mod( std::round( get_healthy_mod() * 0.95f ) ); - add_msg_debug( "Health: %d, Health mod: %d", get_healthy(), get_healthy_mod() ); + add_msg_debug( debugmode::DF_CHAR_HEALTH, "Health: %d, Health mod: %d", get_healthy(), + get_healthy_mod() ); } // Returns the number of multiples of tick_length we would "pass" on our way `from` to `to` @@ -5987,7 +5989,7 @@ needs_rates Character::calc_needs_rates() const rates.kcal = get_bmr(); - add_msg_if_player( m_debug, "Metabolic rate: %.2f", rates.hunger ); + add_msg_debug_if_player( debugmode::DF_CHAR_CALORIES, "Metabolic rate: %.2f", rates.hunger ); static const std::string player_thirst_rate( "PLAYER_THIRST_RATE" ); rates.thirst = get_option< float >( player_thirst_rate ); @@ -6344,7 +6346,7 @@ void Character::get_sick() float health_factor = std::pow( 2.0f, get_healthy() / 50.0f ); int disease_rarity = static_cast( checks_per_year * health_factor / base_diseases_per_year ); - add_msg_debug( "disease_rarity = %d", disease_rarity ); + add_msg_debug( debugmode::DF_CHAR_HEALTH, "disease_rarity = %d", disease_rarity ); if( one_in( disease_rarity ) ) { if( one_in( 6 ) ) { // The flu typically lasts 3-10 days. @@ -8089,7 +8091,7 @@ float Character::healing_rate( float at_rest_quality ) const // Most common case: awake player with no regenerative abilities // ~7e-5 is 1 hp per day, anything less than that is totally negligible static constexpr float eps = 0.000007f; - add_msg_debug( "%s healing: %.6f", name, final_rate ); + add_msg_debug( debugmode::DF_CHAR_HEALTH, "%s healing: %.6f", name, final_rate ); if( std::abs( final_rate ) < eps ) { return 0.0f; } @@ -8605,7 +8607,7 @@ void Character::burn_move_stamina( int moves ) burn_ratio += overburden_percentage; burn_ratio *= move_mode->stamina_mult(); mod_stamina( -( ( moves * burn_ratio ) / 100.0 ) * stamina_move_cost_modifier() ); - add_msg_debug( "Stamina burn: %d", -( ( moves * burn_ratio ) / 100 ) ); + add_msg_debug( debugmode::DF_CHARACTER, "Stamina burn: %d", -( ( moves * burn_ratio ) / 100 ) ); // Chance to suffer pain if overburden and stamina runs out or has trait BADBACK // Starts at 1 in 25, goes down by 5 for every 50% more carried if( ( current_weight > max_weight ) && ( has_trait( trait_BADBACK ) || get_stamina() == 0 ) && @@ -8674,7 +8676,8 @@ void Character::update_stamina( int turns ) } mod_stamina( roll_remainder( stamina_recovery * turns ) ); - add_msg_debug( "Stamina recovery: %d", roll_remainder( stamina_recovery * turns ) ); + add_msg_debug( debugmode::DF_CHARACTER, "Stamina recovery: %d", + roll_remainder( stamina_recovery * turns ) ); // Cap at max set_stamina( std::min( std::max( get_stamina(), 0 ), max_stam ) ); } @@ -10763,7 +10766,7 @@ void Character::check_and_recover_morale() if( !morale->consistent_with( test_morale ) ) { *morale = player_morale( test_morale ); // Recover consistency - add_msg_debug( "%s morale was recovered.", disp_name( true ) ); + add_msg_debug( debugmode::DF_CHARACTER, "%s morale was recovered.", disp_name( true ) ); } } diff --git a/src/consumption.cpp b/src/consumption.cpp index 916aeca94a988..4fb199bc3080d 100644 --- a/src/consumption.cpp +++ b/src/consumption.cpp @@ -1337,7 +1337,7 @@ bool Character::consume_effects( item &food ) // But always round down int h_loss = -rottedness * comest.get_default_nutr(); mod_healthy_mod( h_loss, -200 ); - add_msg_debug( "%d health from %0.2f%% rotten food", h_loss, rottedness ); + add_msg_debug( debugmode::DF_FOOD, "%d health from %0.2f%% rotten food", h_loss, rottedness ); } // Used in hibernation messages. @@ -1423,10 +1423,10 @@ bool Character::consume_effects( item &food ) food_vol * ratio, food_nutrients }; - add_msg_debug( - "Effective volume: %d (solid) %d (liquid)\n multiplier: %g calories: %d, weight: %d", - units::to_milliliter( ingested.solids ), units::to_milliliter( ingested.water ), ratio, - food_nutrients.kcal(), units::to_gram( food_weight ) ); + add_msg_debug( debugmode::DF_FOOD, + "Effective volume: %d (solid) %d (liquid)\n multiplier: %g calories: %d, weight: %d", + units::to_milliliter( ingested.solids ), units::to_milliliter( ingested.water ), ratio, + food_nutrients.kcal(), units::to_gram( food_weight ) ); // Maybe move tapeworm to digestion if( has_effect( effect_tapeworm ) ) { ingested.nutr /= 2; diff --git a/src/creature.cpp b/src/creature.cpp index dad36fef8b48c..60d39652bfe13 100644 --- a/src/creature.cpp +++ b/src/creature.cpp @@ -685,7 +685,8 @@ void projectile::apply_effects_damage( Creature &target, Creature *source, target.add_effect( effect_source( source ), effect_tied, 1_turns, true ); target.as_monster()->tied_item = cata::make_value( drop_item ); } else { - add_msg_debug( "projectile with TANGLE effect, but no drop item specified" ); + add_msg_debug( debugmode::DF_CREATURE, + "projectile with TANGLE effect, but no drop item specified" ); } } else if( ( target.is_npc() || target.is_avatar() ) && !target.is_immune_effect( effect_downed ) ) { @@ -1174,7 +1175,7 @@ void Creature::add_effect( const effect_source &source, const efftype_id &eff_id // Bound intensity by [1, max intensity] if( e.get_intensity() < 1 ) { - add_msg_debug( "Bad intensity, ID: %s", e.get_id().c_str() ); + add_msg_debug( debugmode::DF_CREATURE, "Bad intensity, ID: %s", e.get_id().c_str() ); e.set_intensity( 1 ); } else if( e.get_intensity() > e.get_max_intensity() ) { e.set_intensity( e.get_max_intensity() ); @@ -1214,7 +1215,7 @@ void Creature::add_effect( const effect_source &source, const efftype_id &eff_id } // Bound new effect intensity by [1, max intensity] if( e.get_intensity() < 1 ) { - add_msg_debug( "Bad intensity, ID: %s", e.get_id().c_str() ); + add_msg_debug( debugmode::DF_CREATURE, "Bad intensity, ID: %s", e.get_id().c_str() ); e.set_intensity( 1 ); } else if( e.get_intensity() > e.get_max_intensity() ) { e.set_intensity( e.get_max_intensity() ); @@ -2379,10 +2380,10 @@ bodypart_id Creature::select_body_part( Creature *source, int hit_roll ) const { int szdif = source->get_size() - get_size(); - add_msg_debug( "hit roll = %d", hit_roll ); - add_msg_debug( "source size = %d", source->get_size() ); - add_msg_debug( "target size = %d", get_size() ); - add_msg_debug( "difference = %d", szdif ); + add_msg_debug( debugmode::DF_CREATURE, "hit roll = %d", hit_roll ); + add_msg_debug( debugmode::DF_CREATURE, "source size = %d", source->get_size() ); + add_msg_debug( debugmode::DF_CREATURE, "target size = %d", get_size() ); + add_msg_debug( debugmode::DF_CREATURE, "difference = %d", szdif ); return anatomy_human_anatomy->select_body_part( szdif, hit_roll ); } @@ -2501,6 +2502,11 @@ void Creature::add_msg_if_player( const game_message_params ¶ms, const trans return add_msg_if_player( params, msg.translated() ); } +void Creature::add_msg_debug_if_player( debugmode::debug_filter type, const translation &msg ) const +{ + return add_msg_debug_if_player( type, msg.translated() ); +} + void Creature::add_msg_if_npc( const translation &msg ) const { return add_msg_if_npc( msg.translated() ); @@ -2511,6 +2517,11 @@ void Creature::add_msg_if_npc( const game_message_params ¶ms, const translat return add_msg_if_npc( params, msg.translated() ); } +void Creature::add_msg_debug_if_npc( debugmode::debug_filter type, const translation &msg ) const +{ + return add_msg_debug_if_npc( type, msg.translated() ); +} + void Creature::add_msg_player_or_npc( const translation &pc, const translation &npc ) const { return add_msg_player_or_npc( pc.translated(), npc.translated() ); @@ -2522,6 +2533,12 @@ void Creature::add_msg_player_or_npc( const game_message_params ¶ms, const t return add_msg_player_or_npc( params, pc.translated(), npc.translated() ); } +void Creature::add_msg_debug_player_or_npc( debugmode::debug_filter type, const translation &pc, + const translation &npc ) const +{ + return add_msg_debug_player_or_npc( type, pc.translated(), npc.translated() ); +} + void Creature::add_msg_player_or_say( const translation &pc, const translation &npc ) const { return add_msg_player_or_say( pc.translated(), npc.translated() ); diff --git a/src/creature.h b/src/creature.h index 011f9cca36a26..799826d71e785 100644 --- a/src/creature.h +++ b/src/creature.h @@ -971,6 +971,93 @@ class Creature : public location, public viewer string_format( npc_msg, std::forward( args )... ) ); } + virtual void add_msg_debug_if_player( debugmode::debug_filter /*type*/, + const std::string &/*msg*/ ) const {} + void add_msg_debug_if_player( debugmode::debug_filter /*type*/, const translation &/*msg*/ ) const; + template + void add_msg_debug_if_player( debugmode::debug_filter type, const char *const msg, + Args &&... args ) const { + // expanding for string formatting can be expensive + if( debug_mode ) { + return add_msg_debug_if_player( type, string_format( msg, std::forward( args )... ) ); + } + } + template + void add_msg_debug_if_player( debugmode::debug_filter type, const std::string &msg, + Args &&... args ) const { + if( debug_mode ) { + return add_msg_debug_if_player( type, string_format( msg, std::forward( args )... ) ); + } + } + template + void add_msg_debug_if_player( debugmode::debug_filter type, const translation &msg, + Args &&... args ) const { + if( debug_mode ) { + return add_msg_debug_if_player( type, string_format( msg, std::forward( args )... ) ); + } + } + + virtual void add_msg_debug_if_npc( debugmode::debug_filter /*type*/, + const std::string &/*msg*/ ) const {} + void add_msg_debug_if_npc( debugmode::debug_filter /*type*/, const translation &/*msg*/ ) const; + template + void add_msg_debug_if_npc( debugmode::debug_filter type, const char *const msg, + Args &&... args ) const { + // expanding for string formatting can be expensive + if( debug_mode ) { + return add_msg_debug_if_npc( type, string_format( msg, std::forward( args )... ) ); + } + } + template + void add_msg_debug_if_npc( debugmode::debug_filter type, const std::string &msg, + Args &&... args ) const { + if( debug_mode ) { + return add_msg_debug_if_npc( type, string_format( msg, std::forward( args )... ) ); + } + } + template + void add_msg_debug_if_npc( debugmode::debug_filter type, const translation &msg, + Args &&... args ) const { + if( debug_mode ) { + return add_msg_debug_if_npc( type, string_format( msg, std::forward( args )... ) ); + } + } + + virtual void add_msg_debug_player_or_npc( debugmode::debug_filter /*type*/, + const std::string &/*player_msg*/, + const std::string &/*npc_msg*/ ) const {} + void add_msg_debug_player_or_npc( debugmode::debug_filter /*type*/, + const translation &/*player_msg*/, + const translation &/*npc_msg*/ ) const; + template + void add_msg_debug_player_or_npc( debugmode::debug_filter type, const char *const player_msg, + const char *const npc_msg, Args &&... args ) const { + // expanding for string formatting can be expensive + if( debug_mode ) { + return add_msg_debug_player_or_npc( type, string_format( player_msg, + std::forward( args )... ), + string_format( npc_msg, std::forward( args )... ) ); + } + } + template + void add_msg_debug_player_or_npc( debugmode::debug_filter type, const std::string &player_msg, + const std::string &npc_msg, Args &&... args ) const { + if( debug_mode ) { + return add_msg_debug_player_or_npc( type, string_format( player_msg, + std::forward( args )... ), + string_format( npc_msg, std::forward( args )... ) ); + } + } + template + void add_msg_debug_player_or_npc( debugmode::debug_filter type, const translation &player_msg, + const translation &npc_msg, Args &&... args ) const { + if( debug_mode ) { + return add_msg_debug_player_or_npc( type, string_format( player_msg, + std::forward( args )... ), + string_format( npc_msg, std::forward( args )... ) ); + } + } + virtual void add_msg_player_or_say( const std::string &/*player_msg*/, const std::string &/*npc_speech*/ ) const {} virtual void add_msg_player_or_say( const game_message_params &/*params*/, diff --git a/src/debug.cpp b/src/debug.cpp index cf666f74bc23c..4243f727b281e 100644 --- a/src/debug.cpp +++ b/src/debug.cpp @@ -154,6 +154,52 @@ bool debug_has_error_been_observed() bool debug_mode = false; +namespace debugmode +{ +std::list enabled_filters; +std::string filter_name( debug_filter value ) +{ + // see debug.h for commentary + switch( value ) { + // *INDENT-OFF* + case DF_ACT_BUTCHER: return "DF_ACT_BUTCHER"; + case DF_ACT_LOCKPICK: return "DF_ACT_LOCKPICK"; + case DF_ACT_WORKOUT: return "DF_ACT_WORKOUT"; + case DF_ANATOMY_BP: return "DF_ANATOMY_BP"; + case DF_AVATAR: return "DF_AVATAR"; + case DF_BALLISTIC: return "DF_BALLISTIC"; + case DF_CHARACTER: return "DF_CHARACTER"; + case DF_CHAR_CALORIES: return "DF_CHAR_CALORIES"; + case DF_CHAR_HEALTH: return "DF_CHAR_HEALTH"; + case DF_CREATURE: return "DF_CREATURE"; + case DF_EFFECT: return "DF_EFFECT"; + case DF_EXPLOSION: return "DF_EXPLOSION"; + case DF_FOOD: return "DF_FOOD"; + case DF_GAME: return "DF_GAME"; + case DF_IEXAMINE: return "DF_IEXAMINE"; + case DF_IUSE: return "DF_IUSE"; + case DF_MAP: return "DF_MAP"; + case DF_MATTACK: return "DF_MATTACK"; + case DF_MELEE: return "DF_MELEE"; + case DF_MONSTER: return "DF_MONSTER"; + case DF_NPC: return "DF_NPC"; + case DF_OVERMAP: return "DF_OVERMAP"; + case DF_RANGED: return "DF_RANGED"; + case DF_REQUIREMENTS_MAP: return "DF_REQUIREMENTS_MAP"; + case DF_SOUND: return "DF_SOUND"; + case DF_TALKER: return "DF_TALKER"; + case DF_VEHICLE: return "DF_VEHICLE"; + case DF_VEHICLE_DRAG: return "DF_VEHICLE_DRAG"; + case DF_VEHICLE_MOVE: return "DF_VEHICLE_MOVE"; + // *INDENT-ON* + case DF_LAST: + default: + debugmsg( "Invalid DF_FILTER : %d", value ); + return "DF_INVALID"; + } +} +} // namespace debugmode + struct buffered_prompt_info { std::string filename; std::string line; diff --git a/src/debug.h b/src/debug.h index 91f5634cde5ae..b5cc4bfb5cca6 100644 --- a/src/debug.h +++ b/src/debug.h @@ -3,6 +3,7 @@ #define CATA_SRC_DEBUG_H #include "string_formatter.h" +#include /** * debugmsg(msg, ...) @@ -221,6 +222,46 @@ std::ostream &DebugLog( DebugLevel, DebugClass ); */ extern bool debug_mode; +namespace debugmode +{ +// Please try to keep this alphabetically sorted +enum debug_filter : int { + DF_ACT_BUTCHER = 0, // butcher activity handler + DF_ACT_LOCKPICK, // lockpicking activity actor + DF_ACT_WORKOUT, // workout activity actor + DF_ANATOMY_BP, // anatomy::select_body_part() + DF_AVATAR, // avatar generic + DF_BALLISTIC, // ballistic generic + DF_CHARACTER, // character generic + DF_CHAR_CALORIES, // character stomach and calories + DF_CHAR_HEALTH, // character health related + DF_CREATURE, // creature generic + DF_EFFECT, // effects generic + DF_EXPLOSION, // explosion generic + DF_FOOD, // food generic + DF_GAME, // game generic + DF_IEXAMINE, // iexamine generic + DF_IUSE, // iuse generic + DF_MAP, // map generic + DF_MATTACK, // monster attack generic + DF_MELEE, // melee generic + DF_MONSTER, // monster generic + DF_NPC, // npc generic + DF_OVERMAP, // overmap generic + DF_RANGED, // ranged generic + DF_REQUIREMENTS_MAP, // activity_item_handler requirements_map() + DF_SOUND, // sound generic + DF_TALKER, // talker generic + DF_VEHICLE, // vehicle generic + DF_VEHICLE_DRAG, // vehicle coeff_air_drag() + DF_VEHICLE_MOVE, // vehicle move generic + DF_LAST // This is always the last entry +}; + +extern std::list enabled_filters; +std::string filter_name( debug_filter value ); +} // namespace debugmode + #if defined(BACKTRACE) /** * Write a stack backtrace to the given ostream diff --git a/src/effect.cpp b/src/effect.cpp index 5b9fd444061ec..fad0aae5fc147 100644 --- a/src/effect.cpp +++ b/src/effect.cpp @@ -794,7 +794,8 @@ void effect::set_duration( const time_duration &dur, bool alert ) set_intensity( duration / eff_type->int_dur_factor + 1, alert ); } - add_msg_debug( "ID: %s, Duration %s", get_id().c_str(), to_string( duration ) ); + add_msg_debug( debugmode::DF_EFFECT, "ID: %s, Duration %s", get_id().c_str(), + to_string( duration ) ); } void effect::mod_duration( const time_duration &dur, bool alert ) { @@ -857,7 +858,7 @@ int effect::set_intensity( int val, bool alert ) { if( intensity < 1 ) { // Fix bad intensity - add_msg_debug( "Bad intensity, ID: %s", get_id().c_str() ); + add_msg_debug( debugmode::DF_EFFECT, "Bad intensity, ID: %s", get_id().c_str() ); intensity = 1; } @@ -875,7 +876,8 @@ int effect::set_intensity( int val, bool alert ) int old_intensity = intensity; intensity = val; if( old_intensity != intensity ) { - add_msg_debug( "%s intensity %d->%d", get_id().c_str(), old_intensity, intensity ); + add_msg_debug( debugmode::DF_EFFECT, "%s intensity %d->%d", get_id().c_str(), old_intensity, + intensity ); } return intensity; diff --git a/src/explosion.cpp b/src/explosion.cpp index 738442fd9487d..1dd5b68ac9428 100644 --- a/src/explosion.cpp +++ b/src/explosion.cpp @@ -311,7 +311,8 @@ static void do_blast( const tripoint &p, const float power, continue; } - add_msg_debug( "Blast hits %s with force %.1f", critter->disp_name(), force ); + add_msg_debug( debugmode::DF_EXPLOSION, "Blast hits %s with force %.1f", critter->disp_name(), + force ); Character *pl = critter->as_character(); if( pl == nullptr ) { @@ -320,7 +321,8 @@ static void do_blast( const tripoint &p, const float power, const int actual_dmg = rng_float( dmg * 2, dmg * 3 ); critter->apply_damage( nullptr, bodypart_id( "torso" ), actual_dmg ); critter->check_dead_state(); - add_msg_debug( "Blast hits %s for %d damage", critter->disp_name(), actual_dmg ); + add_msg_debug( debugmode::DF_EXPLOSION, "Blast hits %s for %d damage", critter->disp_name(), + actual_dmg ); continue; } @@ -354,7 +356,8 @@ static void do_blast( const tripoint &p, const float power, const dealt_damage_instance result = pl->deal_damage( nullptr, blp.bp, dmg_instance ); const int res_dmg = result.total_damage(); - add_msg_debug( "%s for %d raw, %d actual", hit_part_name, part_dam, res_dmg ); + add_msg_debug( debugmode::DF_EXPLOSION, "%s for %d raw, %d actual", hit_part_name, part_dam, + res_dmg ); if( res_dmg > 0 ) { pl->add_msg_if_player( m_bad, _( "Your %s is hit for %d damage!" ), hit_part_name, res_dmg ); } @@ -435,10 +438,10 @@ static std::vector shrapnel( const tripoint &src, int power, } else { non_damaging_hits++; } - add_msg_debug( "Shrapnel hit %s at %d m/s at a distance of %d", + add_msg_debug( debugmode::DF_EXPLOSION, "Shrapnel hit %s at %d m/s at a distance of %d", critter->disp_name(), frag.proj.speed, rl_dist( src, target ) ); - add_msg_debug( "Shrapnel dealt %d damage", frag.dealt_dam.total_damage() ); + add_msg_debug( debugmode::DF_EXPLOSION, "Shrapnel dealt %d damage", frag.dealt_dam.total_damage() ); if( critter->is_dead_state() ) { break; } diff --git a/src/game.cpp b/src/game.cpp index 228a4230f54ab..0a6d777e4e4d5 100644 --- a/src/game.cpp +++ b/src/game.cpp @@ -828,7 +828,7 @@ bool game::start_game() mon->friendly = -1; mon->add_effect( effect_pet, 1_turns, true ); } else { - add_msg_debug( "cannot place starting pet, no space!" ); + add_msg_debug( debugmode::DF_GAME, "cannot place starting pet, no space!" ); } } if( u.starting_vehicle && @@ -935,7 +935,7 @@ void game::load_npcs() continue; } - add_msg_debug( "game::load_npcs: Spawning static NPC, %d:%d:%d (%d:%d:%d)", + add_msg_debug( debugmode::DF_NPC, "game::load_npcs: Spawning static NPC, %d:%d:%d (%d:%d:%d)", abs_sub.x, abs_sub.y, abs_sub.z, sm_loc.x, sm_loc.y, sm_loc.z ); temp->place_on_map(); if( !m.inbounds( temp->pos() ) ) { @@ -4576,7 +4576,8 @@ void game::monmove() << " can't move to its location! (" << critter.posx() << ":" << critter.posy() << ":" << critter.posz() << "), " << m.tername( critter.pos() ); - add_msg_debug( "%s can't move to its location! (%d,%d,%d), %s", critter.name(), + add_msg_debug( debugmode::DF_MONSTER, "%s can't move to its location! (%d,%d,%d), %s", + critter.name(), critter.posx(), critter.posy(), critter.posz(), m.tername( critter.pos() ) ); bool okay = false; for( const tripoint &dest : m.points_in_radius( critter.pos(), 3 ) ) { @@ -4674,6 +4675,12 @@ void game::monmove() debugmsg( "NPC %s entered infinite loop. Turning on debug mode", guy.name ); debug_mode = true; + // make sure the filter is active + if( std::find( + debugmode::enabled_filters.begin(), debugmode::enabled_filters.end(), + debugmode::DF_NPC ) == debugmode::enabled_filters.end() ) { + debugmode::enabled_filters.emplace_back( debugmode::DF_NPC ); + } } } @@ -7255,7 +7262,7 @@ look_around_result game::look_around( const bool show_window, tripoint ¢er, lz = clamp( lz + dz, min_levz, max_levz ); center.z = clamp( center.z + dz, min_levz, max_levz ); - add_msg_debug( "levx: %d, levy: %d, levz: %d", + add_msg_debug( debugmode::DF_GAME, "levx: %d, levy: %d, levz: %d", get_map().get_abs_sub().x, get_map().get_abs_sub().y, center.z ); u.view_offset.z = center.z - u.posz(); m.invalidate_map_cache( center.z ); diff --git a/src/handle_action.cpp b/src/handle_action.cpp index 6f38566a9c6b2..2f7582e9290c5 100644 --- a/src/handle_action.cpp +++ b/src/handle_action.cpp @@ -1563,6 +1563,122 @@ void game::open_consume_item_menu() } } +static void handle_debug_mode() +{ + auto debug_mode_setup = []( uilist_entry & entry ) -> void { + entry.txt = string_format( _( "Debug Mode (%1$s)" ), debug_mode ? _( "ON" ) : _( "OFF" ) ); + entry.text_color = debug_mode ? c_green : c_light_gray; + }; + + // returns if entry became active + auto debugmode_entry_setup = []( uilist_entry & entry, bool active ) -> void { + if( active ) + { + entry.extratxt.txt = _( "A" ); + entry.extratxt.color = c_white_green; + entry.text_color = c_green; + } else + { + entry.extratxt.txt = " "; + entry.extratxt.color = c_unset; + entry.text_color = c_light_gray; + } + }; + + static bool first_time = true; + if( first_time ) { + first_time = false; + debugmode::enabled_filters.clear(); + for( int i = 0; i < debugmode::DF_LAST; ++i ) { + debugmode::enabled_filters.emplace_back( static_cast( i ) ); + } + } + + input_context ctxt( "DEFAULTMODE" ); + ctxt.register_action( "debug_mode" ); + + uilist dbmenu; + dbmenu.allow_anykey = true; + dbmenu.title = _( "Debug Mode Filters" ); + dbmenu.text = string_format( _( "Press [%1$s] to quickly toggle debug mode." ), + ctxt.get_desc( "debug_mode" ) ); + + dbmenu.entries.reserve( 1 + debugmode::DF_LAST ); + + dbmenu.addentry( 0, true, 'd', " " ); + debug_mode_setup( dbmenu.entries[0] ); + + dbmenu.addentry( 1, true, 't', _( "Toggle all filters" ) ); + bool toggle_value = true; + + for( int i = 0; i < debugmode::DF_LAST; ++i ) { + uilist_entry entry( i + 2, true, 0, + debugmode::filter_name( static_cast( i ) ) ); + + entry.extratxt.left = 1; + + const bool active = std::find( + debugmode::enabled_filters.begin(), debugmode::enabled_filters.end(), + static_cast( i ) ) != debugmode::enabled_filters.end(); + + if( toggle_value && active ) { + toggle_value = false; + } + + debugmode_entry_setup( entry, active ); + dbmenu.entries.push_back( entry ); + } + + do { + dbmenu.query(); + if( ctxt.input_to_action( dbmenu.ret_evt ) == "debug_mode" ) { + debug_mode = !debug_mode; + if( debug_mode ) { + add_msg( m_info, _( "Debug mode ON!" ) ); + } else { + add_msg( m_info, _( "Debug mode OFF!" ) ); + } + break; + } + + if( dbmenu.ret == 0 ) { + debug_mode = !debug_mode; + debug_mode_setup( dbmenu.entries[0] ); + + } else if( dbmenu.ret == 1 ) { + debugmode::enabled_filters.clear(); + + for( int i = 0; i < debugmode::DF_LAST; ++i ) { + debugmode_entry_setup( dbmenu.entries[i + 2], toggle_value ); + + if( toggle_value ) { + debugmode::enabled_filters.emplace_back( static_cast( i ) ); + } + } + + toggle_value = !toggle_value; + + } else if( dbmenu.ret > 1 ) { + uilist_entry &entry = dbmenu.entries[dbmenu.ret]; + + const auto filter_iter = std::find( + debugmode::enabled_filters.begin(), debugmode::enabled_filters.end(), + static_cast( dbmenu.ret - 2 ) ); + + const bool active = filter_iter != debugmode::enabled_filters.end(); + + debugmode_entry_setup( entry, !active ); + + if( active ) { + debugmode::enabled_filters.erase( filter_iter ); + } else { + debugmode::enabled_filters.push_back( + static_cast( dbmenu.ret - 2 ) ); + } + } + } while( dbmenu.ret != UILIST_CANCEL ); +} + bool game::handle_action() { std::string action; @@ -2586,12 +2702,7 @@ bool game::handle_action() if( MAP_SHARING::isCompetitive() && !MAP_SHARING::isDebugger() ) { break; //don't do anything when sharing and not debugger } - debug_mode = !debug_mode; - if( debug_mode ) { - add_msg( m_info, _( "Debug mode ON!" ) ); - } else { - add_msg( m_info, _( "Debug mode OFF!" ) ); - } + handle_debug_mode(); break; case ACTION_ZOOM_IN: diff --git a/src/iexamine.cpp b/src/iexamine.cpp index bccf56c5f897a..a607d421903c8 100644 --- a/src/iexamine.cpp +++ b/src/iexamine.cpp @@ -3840,7 +3840,8 @@ void trap::examine( const tripoint &examp ) const int roll = std::round( normal_roll( mean_roll, 3 ) ); - add_msg( m_debug, _( "Rolled %i, mean_roll %g. difficulty %i." ), roll, mean_roll, difficulty ); + add_msg_debug( debugmode::DF_IEXAMINE, _( "Rolled %i, mean_roll %g. difficulty %i." ), roll, + mean_roll, difficulty ); //Difficulty 0 traps should succeed regardless of proficiencies. (i.e caltrops and nailboards) if( roll >= difficulty || difficulty == 0 ) { diff --git a/src/iuse_actor.cpp b/src/iuse_actor.cpp index f3803dec34797..8b9d9f21697e9 100644 --- a/src/iuse_actor.cpp +++ b/src/iuse_actor.cpp @@ -3140,7 +3140,7 @@ static player &get_patient( player &healer, const tripoint &pos ) player *const person = g->critter_at( pos ); if( !person ) { // Default to heal self on failure not to break old functionality - add_msg_debug( "No heal target at position %d,%d,%d", pos.x, pos.y, pos.z ); + add_msg_debug( debugmode::DF_IUSE, "No heal target at position %d,%d,%d", pos.x, pos.y, pos.z ); return healer; } diff --git a/src/map.cpp b/src/map.cpp index e5ae1b3cd4850..6dd8906f6dbbc 100644 --- a/src/map.cpp +++ b/src/map.cpp @@ -1075,7 +1075,8 @@ bool map::displace_vehicle( vehicle &veh, const tripoint &dp, const bool adjust_ ( dp + tripoint( 0, 0, ramp_offset ) ) : tripoint_zero ); if( !inbounds( src ) ) { - add_msg_debug( "map::displace_vehicle: coordinates out of bounds %d,%d,%d->%d,%d,%d", + add_msg_debug( debugmode::DF_MAP, + "map::displace_vehicle: coordinates out of bounds %d,%d,%d->%d,%d,%d", src.x, src.y, src.z, dst.x, dst.y, dst.z ); return false; } @@ -1109,7 +1110,7 @@ bool map::displace_vehicle( vehicle &veh, const tripoint &dp, const bool adjust_ } if( !found ) { - add_msg_debug( "displace_vehicle [%s] failed", veh.name ); + add_msg_debug( debugmode::DF_MAP, "displace_vehicle [%s] failed", veh.name ); return false; } @@ -1158,7 +1159,7 @@ bool map::displace_vehicle( vehicle &veh, const tripoint &dp, const bool adjust_ } if( psg->pos() != part_pos ) { - add_msg_debug( "Part/passenger position mismatch: part #%d at %d,%d,%d " + add_msg_debug( debugmode::DF_MAP, "Part/passenger position mismatch: part #%d at %d,%d,%d " "passenger at %d,%d,%d", prt, part_pos.x, part_pos.y, part_pos.z, psg->posx(), psg->posy(), psg->posz() ); } @@ -2313,7 +2314,7 @@ void map::process_falling() } if( !support_cache_dirty.empty() ) { - add_msg_debug( "Checking %d tiles for falling objects", + add_msg_debug( debugmode::DF_MAP, "Checking %d tiles for falling objects", support_cache_dirty.size() ); // We want the cache to stay constant, but falling can change it std::set last_cache = std::move( support_cache_dirty ); @@ -7527,7 +7528,7 @@ void map::spawn_monsters_submap_group( const tripoint &gp, mongroup &group, bool point( rng( 0, SEEX ), rng( 0, SEEY ) ); const int turns = rl_dist( p, rand_dest ) + group.interest; tmp.wander_to( rand_dest, turns ); - add_msg_debug( "%s targeting %d,%d,%d", tmp.disp_name(), + add_msg_debug( debugmode::DF_MAP, "%s targeting %d,%d,%d", tmp.disp_name(), tmp.wander_pos.x, tmp.wander_pos.y, tmp.wander_pos.z ); } diff --git a/src/mattack_actors.cpp b/src/mattack_actors.cpp index c0308f2b68647..77069b8f8e3e4 100644 --- a/src/mattack_actors.cpp +++ b/src/mattack_actors.cpp @@ -271,7 +271,7 @@ bool melee_actor::call( monster &z ) const z.mod_moves( -move_cost ); - add_msg_debug( "%s attempting to melee_attack %s", z.name(), + add_msg_debug( debugmode::DF_MATTACK, "%s attempting to melee_attack %s", z.name(), target->disp_name() ); const int acc = accuracy >= 0 ? accuracy : z.type->melee_skill; @@ -299,7 +299,7 @@ bool melee_actor::call( monster &z ) const dealt_damage.bp_hit = bp_hit.id(); int damage_total = dealt_damage.total_damage(); - add_msg_debug( "%s's melee_attack did %d damage", z.name(), damage_total ); + add_msg_debug( debugmode::DF_MATTACK, "%s's melee_attack did %d damage", z.name(), damage_total ); if( damage_total > 0 ) { on_damage( z, *target, dealt_damage ); } else { diff --git a/src/melee.cpp b/src/melee.cpp index 134aed15759d2..eb9fb2b6facb4 100644 --- a/src/melee.cpp +++ b/src/melee.cpp @@ -767,7 +767,7 @@ bool Character::melee_attack_abstract( Creature &t, bool allow_special, const int deft_bonus = !hits && has_trait( trait_DEFT ) ? 50 : 0; mod_stamina( std::min( -50, mod_sta + melee + deft_bonus ) ); - add_msg_debug( "Stamina burn: %d", std::min( -50, mod_sta ) ); + add_msg_debug( debugmode::DF_MELEE, "Stamina burn: %d", std::min( -50, mod_sta ) ); // Weariness handling - 1 / the value, because it returns what % of the normal speed const float weary_mult = exertion_adjusted_move_multiplier( EXTRA_EXERCISE ); mod_moves( -move_cost * ( 1 / weary_mult ) ); @@ -1560,13 +1560,13 @@ static void print_damage_info( const damage_instance &di ) ss += name_by_dt( du.type ) + ":" + std::to_string( amount ) + ","; } - add_msg_debug( "%stotal: %d", ss, total ); + add_msg_debug( debugmode::DF_MELEE, "%stotal: %d", ss, total ); } void Character::perform_technique( const ma_technique &technique, Creature &t, damage_instance &di, int &move_cost ) { - add_msg_debug( "dmg before tec:" ); + add_msg_debug( debugmode::DF_MELEE, "dmg before tec:" ); print_damage_info( di ); for( damage_unit &du : di.damage_units ) { @@ -1580,7 +1580,7 @@ void Character::perform_technique( const ma_technique &technique, Creature &t, d du.res_pen += technique.armor_penetration( *this, du.type ); } - add_msg_debug( "dmg after tec:" ); + add_msg_debug( debugmode::DF_MELEE, "dmg after tec:" ); print_damage_info( di ); move_cost *= technique.move_cost_multiplier( *this ); @@ -2151,7 +2151,8 @@ std::vector Character::mutation_attacks( Creature &t ) const // Calculate actor ability value to be compared against mutation attack difficulty and add debug message const int proc_value = get_dex() + unarmed; - add_msg_debug( "%s proc chance: %d in %d", pr.c_str(), proc_value, mut_atk.chance ); + add_msg_debug( debugmode::DF_MELEE, "%s proc chance: %d in %d", pr.c_str(), proc_value, + mut_atk.chance ); // If the mutation attack fails to proc, bail out if( !x_in_y( proc_value, mut_atk.chance ) ) { continue; @@ -2162,7 +2163,7 @@ std::vector Character::mutation_attacks( Creature &t ) const [this]( const trait_id & blocker ) { return has_trait( blocker ); } ) ) { - add_msg_debug( "%s not procing: blocked", pr.c_str() ); + add_msg_debug( debugmode::DF_MELEE, "%s not procing: blocked", pr.c_str() ); continue; } @@ -2171,7 +2172,7 @@ std::vector Character::mutation_attacks( Creature &t ) const [this]( const trait_id & need ) { return has_trait( need ); } ) ) { - add_msg_debug( "%s not procing: unmet req", pr.c_str() ); + add_msg_debug( debugmode::DF_MELEE, "%s not procing: unmet req", pr.c_str() ); continue; } @@ -2200,7 +2201,7 @@ std::vector Character::mutation_attacks( Creature &t ) const if( tmp.damage.total_damage() > 0.0f ) { ret.emplace_back( tmp ); } else { - add_msg_debug( "%s not procing: zero damage", pr.c_str() ); + add_msg_debug( debugmode::DF_MELEE, "%s not procing: zero damage", pr.c_str() ); } } } @@ -2443,7 +2444,8 @@ double Character::weapon_value( const item &weap, int ammo ) const // A small bonus for guns you can also use to hit stuff with (bayonets etc.) const double my_val = more + ( less / 2.0 ); - add_msg_debug( "%s (%ld ammo) sum value: %.1f", weap.type->get_id().str(), ammo, my_val ); + add_msg_debug( debugmode::DF_MELEE, "%s (%ld ammo) sum value: %.1f", weap.type->get_id().str(), + ammo, my_val ); if( is_wielding( weap ) ) { cached_info.emplace( "weapon_value", my_val ); } @@ -2470,7 +2472,7 @@ double Character::melee_value( const item &weap ) const my_value *= 1.5; } - add_msg_debug( "%s as melee: %.1f", weap.type->get_id().str(), my_value ); + add_msg_debug( debugmode::DF_MELEE, "%s as melee: %.1f", weap.type->get_id().str(), my_value ); return std::max( 0.0, my_value ); } diff --git a/src/messages.cpp b/src/messages.cpp index 02869d2b07a49..b804c29fa2a27 100644 --- a/src/messages.cpp +++ b/src/messages.cpp @@ -347,6 +347,18 @@ void Messages::add_msg( const game_message_params ¶ms, std::string msg ) player_messages.add_msg_string( std::move( msg ), params ); } +void Messages::add_msg_debug( debugmode::debug_filter type, std::string msg ) +{ + if( debug_mode && + std::find( + debugmode::enabled_filters.begin(), debugmode::enabled_filters.end(), + type ) == debugmode::enabled_filters.end() ) { + return; + } + + player_messages.add_msg_string( std::move( msg ), m_debug ); +} + void Messages::clear_messages() { player_messages.messages.clear(); @@ -886,6 +898,11 @@ void add_msg( const game_message_params ¶ms, std::string msg ) Messages::add_msg( params, std::move( msg ) ); } +void add_msg_debug( debugmode::debug_filter type, std::string msg ) +{ + Messages::add_msg_debug( type, std::move( msg ) ); +} + void add_msg_if_player_sees( const tripoint &target, std::string msg ) { if( get_player_view().sees( target ) ) { @@ -915,3 +932,19 @@ void add_msg_if_player_sees( const Creature &target, const game_message_params & Messages::add_msg( params, std::move( msg ) ); } } + +void add_msg_debug_if_player_sees( const tripoint &target, debugmode::debug_filter type, + std::string msg ) +{ + if( get_player_view().sees( target ) ) { + Messages::add_msg_debug( type, std::move( msg ) ); + } +} + +void add_msg_debug_if_player_sees( const Creature &target, debugmode::debug_filter type, + std::string msg ) +{ + if( get_player_view().sees( target ) ) { + Messages::add_msg_debug( type, std::move( msg ) ); + } +} diff --git a/src/messages.h b/src/messages.h index db482b35564c6..6270cb4259885 100644 --- a/src/messages.h +++ b/src/messages.h @@ -28,6 +28,7 @@ namespace Messages std::vector> recent_messages( size_t count ); void add_msg( std::string msg ); void add_msg( const game_message_params ¶ms, std::string msg ); +void add_msg_debug( debugmode::debug_filter type, std::string msg ); void clear_messages(); void deactivate(); size_t size(); @@ -56,12 +57,6 @@ inline void add_msg( const translation &msg, Args &&... args ) return add_msg( string_format( msg, std::forward( args )... ) ); } -// Prevent potentially expensive evaluation of arguments which won't be printed. -#define add_msg_debug( ... )\ - if( debug_mode ) {\ - add_msg( m_debug, __VA_ARGS__ );\ - }; - void add_msg( const game_message_params ¶ms, std::string msg ); template inline void add_msg( const game_message_params ¶ms, const std::string &msg, Args &&... args ) @@ -80,6 +75,23 @@ inline void add_msg( const game_message_params ¶ms, const char *const msg, A return add_msg( params, string_format( msg, std::forward( args )... ) ); } +void add_msg_debug( debugmode::debug_filter type, std::string msg ); +template +inline void add_msg_debug( debugmode::debug_filter type, const std::string &msg, Args &&... args ) +{ + // expanding for string formatting can be expensive + if( debug_mode ) { + return add_msg_debug( type, string_format( msg, std::forward( args )... ) ); + } +} +template +inline void add_msg_debug( debugmode::debug_filter type, const char *const msg, Args &&... args ) +{ + if( debug_mode ) { + return add_msg_debug( type, string_format( msg, std::forward( args )... ) ); + } +} + void add_msg_if_player_sees( const tripoint &target, std::string msg ); void add_msg_if_player_sees( const Creature &target, std::string msg ); template @@ -162,4 +174,46 @@ inline void add_msg_if_player_sees( const Creature &target, const game_message_p std::forward( args )... ) ); } +void add_msg_debug_if_player_sees( const tripoint &target, debugmode::debug_filter type, + std::string msg ); +void add_msg_debug_if_player_sees( const Creature &target, debugmode::debug_filter type, + std::string msg ); +template +inline void add_msg_debug_if_player_sees( const tripoint &target, debugmode::debug_filter type, + const std::string &msg, Args &&... args ) +{ + // expanding for string formatting can be expensive + if( debug_mode ) { + return add_msg_debug_if_player_sees( target, type, string_format( msg, + std::forward( args )... ) ); + } +} +template +inline void add_msg_debug_if_player_sees( const Creature &target, debugmode::debug_filter type, + const std::string &msg, Args &&... args ) +{ + if( debug_mode ) { + return add_msg_debug_if_player_sees( target, type, string_format( msg, + std::forward( args )... ) ); + } +} +template +inline void add_msg_debug_if_player_sees( const tripoint &target, debugmode::debug_filter type, + const char *const msg, Args &&... args ) +{ + if( debug_mode ) { + return add_msg_debug_if_player_sees( target, type, string_format( msg, + std::forward( args )... ) ); + } +} +template +inline void add_msg_debug_if_player_sees( const Creature &target, debugmode::debug_filter type, + const char *const msg, Args &&... args ) +{ + if( debug_mode ) { + return add_msg_debug_if_player_sees( target, type, string_format( msg, + std::forward( args )... ) ); + } +} + #endif // CATA_SRC_MESSAGES_H diff --git a/src/monattack.cpp b/src/monattack.cpp index ef032c0988352..cc0297f264b7e 100644 --- a/src/monattack.cpp +++ b/src/monattack.cpp @@ -4284,7 +4284,8 @@ bool mattack::absorb_meat( monster *z ) if( player_character.sees( *z ) ) { add_msg( m_warning, _( "The %1$s absorbs the %2$s, growing larger." ), z->name(), current_item.tname() ); - add_msg_debug( "The %1$s now has %2$s out of %3$s hp", z->name(), z->get_hp(), + add_msg_debug( debugmode::DF_MATTACK, "The %1$s now has %2$s out of %3$s hp", z->name(), + z->get_hp(), z->get_hp_max() ); } return true; @@ -5396,7 +5397,7 @@ bool mattack::kamikaze( monster *z ) { if( z->ammo.empty() ) { // We somehow lost our ammo! Toggle this special off so we stop processing - add_msg_debug( "Missing ammo in kamikaze special for %s.", z->name() ); + add_msg_debug( debugmode::DF_MATTACK, "Missing ammo in kamikaze special for %s.", z->name() ); z->disable_special( "KAMIKAZE" ); return true; } @@ -5416,14 +5417,15 @@ bool mattack::kamikaze( monster *z ) const use_function *usage = bomb_type->get_use( "transform" ); if( usage == nullptr ) { // Invalid item usage, Toggle this special off so we stop processing - add_msg_debug( "Invalid bomb transform use in kamikaze special for %s.", z->name() ); + add_msg_debug( debugmode::DF_MATTACK, "Invalid bomb transform use in kamikaze special for %s.", + z->name() ); z->disable_special( "KAMIKAZE" ); return true; } const iuse_transform *actor = dynamic_cast( usage->get_actor_ptr() ); if( actor == nullptr ) { // Invalid bomb item, Toggle this special off so we stop processing - add_msg_debug( "Invalid bomb type in kamikaze special for %s.", z->name() ); + add_msg_debug( debugmode::DF_MATTACK, "Invalid bomb type in kamikaze special for %s.", z->name() ); z->disable_special( "KAMIKAZE" ); return true; } @@ -5448,7 +5450,8 @@ bool mattack::kamikaze( monster *z ) const use_function *use = act_bomb_type->get_use( "explosion" ); if( use == nullptr ) { // Invalid active bomb item usage, Toggle this special off so we stop processing - add_msg_debug( "Invalid active bomb explosion use in kamikaze special for %s.", + add_msg_debug( debugmode::DF_MATTACK, + "Invalid active bomb explosion use in kamikaze special for %s.", z->name() ); z->disable_special( "KAMIKAZE" ); return true; @@ -5456,7 +5459,8 @@ bool mattack::kamikaze( monster *z ) const explosion_iuse *exp_actor = dynamic_cast( use->get_actor_ptr() ); if( exp_actor == nullptr ) { // Invalid active bomb item, Toggle this special off so we stop processing - add_msg_debug( "Invalid active bomb type in kamikaze special for %s.", z->name() ); + add_msg_debug( debugmode::DF_MATTACK, "Invalid active bomb type in kamikaze special for %s.", + z->name() ); z->disable_special( "KAMIKAZE" ); return true; } @@ -5577,7 +5581,7 @@ static int grenade_helper( monster *const z, Creature *const target, const int d // if the player can see it if( get_player_view().sees( *z ) ) { if( data[att].message.empty() ) { - add_msg_debug( "Invalid ammo message in grenadier special." ); + add_msg_debug( debugmode::DF_MATTACK, "Invalid ammo message in grenadier special." ); } else { add_msg( m_bad, data[att].message, z->name() ); } @@ -5588,14 +5592,15 @@ static int grenade_helper( monster *const z, Creature *const target, const int d const use_function *usage = bomb_type->get_use( "place_monster" ); if( usage == nullptr ) { // Invalid bomb item usage, Toggle this special off so we stop processing - add_msg_debug( "Invalid bomb item usage in grenadier special for %s.", z->name() ); + add_msg_debug( debugmode::DF_MATTACK, "Invalid bomb item usage in grenadier special for %s.", + z->name() ); return -1; } const place_monster_iuse *actor = dynamic_cast ( usage->get_actor_ptr() ); if( actor == nullptr ) { // Invalid bomb item, Toggle this special off so we stop processing - add_msg_debug( "Invalid bomb type in grenadier special for %s.", z->name() ); + add_msg_debug( debugmode::DF_MATTACK, "Invalid bomb type in grenadier special for %s.", z->name() ); return -1; } diff --git a/src/monster.cpp b/src/monster.cpp index da358b7188945..edca5c9df481b 100644 --- a/src/monster.cpp +++ b/src/monster.cpp @@ -284,7 +284,8 @@ void monster::setpos( const tripoint &p ) g->update_zombie_pos( *this, p ); position = p; if( has_effect( effect_ridden ) && mounted_player && mounted_player->pos() != pos() ) { - add_msg_debug( "Ridden monster %s moved independently and dumped player", get_name() ); + add_msg_debug( debugmode::DF_MONSTER, "Ridden monster %s moved independently and dumped player", + get_name() ); mounted_player->forced_dismount(); } if( wandering ) { @@ -1490,7 +1491,7 @@ bool monster::block_hit( Creature *, bodypart_id &, damage_instance & ) void monster::absorb_hit( const bodypart_id &, damage_instance &dam ) { for( auto &elem : dam.damage_units ) { - add_msg_debug( "Dam Type: %s :: Ar Pen: %.1f :: Armor Mult: %.1f", + add_msg_debug( debugmode::DF_MONSTER, "Dam Type: %s :: Ar Pen: %.1f :: Armor Mult: %.1f", name_by_dt( elem.type ), elem.res_pen, elem.res_mult ); elem.amount -= std::min( resistances( *this ).get_effective_resist( elem ) + get_worn_armor_val( elem.type ), elem.amount ); @@ -2817,12 +2818,24 @@ void monster::add_msg_if_npc( const game_message_params ¶ms, const std::stri add_msg_if_player_sees( *this, params, replace_with_npc_name( msg ) ); } +void monster::add_msg_debug_if_npc( debugmode::debug_filter type, const std::string &msg ) const +{ + add_msg_debug_if_player_sees( *this, type, replace_with_npc_name( msg ) ); +} + void monster::add_msg_player_or_npc( const game_message_params ¶ms, const std::string &/*player_msg*/, const std::string &npc_msg ) const { add_msg_if_player_sees( *this, params, replace_with_npc_name( npc_msg ) ); } +void monster::add_msg_debug_player_or_npc( debugmode::debug_filter type, + const std::string &/*player_msg*/, + const std::string &npc_msg ) const +{ + add_msg_debug_if_player_sees( *this, type, replace_with_npc_name( npc_msg ) ); +} + units::mass monster::get_carried_weight() { units::mass total_weight = 0_gram; @@ -3108,7 +3121,7 @@ void monster::on_load() healed_speed = get_speed_base() - old_speed; } - add_msg_debug( "on_load() by %s, %d turns, healed %d hp, %d speed", + add_msg_debug( debugmode::DF_MONSTER, "on_load() by %s, %d turns, healed %d hp, %d speed", name(), to_turns( dt ), healed, healed_speed ); } diff --git a/src/monster.h b/src/monster.h index f773b6205c4ee..07450a8c51438 100644 --- a/src/monster.h +++ b/src/monster.h @@ -443,11 +443,16 @@ class monster : public Creature using Creature::add_msg_if_npc; void add_msg_if_npc( const std::string &msg ) const override; void add_msg_if_npc( const game_message_params ¶ms, const std::string &msg ) const override; + using Creature::add_msg_debug_if_npc; + void add_msg_debug_if_npc( debugmode::debug_filter type, const std::string &msg ) const override; using Creature::add_msg_player_or_npc; void add_msg_player_or_npc( const std::string &player_msg, const std::string &npc_msg ) const override; void add_msg_player_or_npc( const game_message_params ¶ms, const std::string &player_msg, const std::string &npc_msg ) const override; + using Creature::add_msg_debug_player_or_npc; + void add_msg_debug_player_or_npc( debugmode::debug_filter type, const std::string &player_msg, + const std::string &npc_msg ) const override; // TEMP VALUES tripoint wander_pos; // Wander destination - Just try to move in that direction int wandf = 0; // Urge to wander - Increased by sound, decrements each move diff --git a/src/npc.cpp b/src/npc.cpp index 3a397284ef590..d6abf20bb4693 100644 --- a/src/npc.cpp +++ b/src/npc.cpp @@ -1342,7 +1342,8 @@ void npc::form_opinion( const player &u ) set_attitude( NPCATT_FLEE_TEMP ); } - add_msg_debug( "%s formed an opinion of u: %s", name, npc_attitude_id( attitude ) ); + add_msg_debug( debugmode::DF_NPC, "%s formed an opinion of u: %s", name, + npc_attitude_id( attitude ) ); } void npc::mutiny() @@ -2206,7 +2207,8 @@ Creature::Attitude npc::attitude_to( const Creature &other ) const void npc::npc_dismount() { if( !mounted_creature || !has_effect( effect_riding ) ) { - add_msg_debug( "NPC %s tried to dismount, but they have no mount, or they are not riding", + add_msg_debug( debugmode::DF_NPC, + "NPC %s tried to dismount, but they have no mount, or they are not riding", disp_name() ); return; } @@ -2218,7 +2220,7 @@ void npc::npc_dismount() } } if( !pnt ) { - add_msg_debug( "NPC %s could not find a place to dismount.", disp_name() ); + add_msg_debug( debugmode::DF_NPC, "NPC %s could not find a place to dismount.", disp_name() ); return; } remove_effect( effect_riding ); @@ -2729,6 +2731,11 @@ void npc::add_msg_if_npc( const game_message_params ¶ms, const std::string & add_msg( params, replace_with_npc_name( msg ) ); } +void npc::add_msg_debug_if_npc( debugmode::debug_filter type, const std::string &msg ) const +{ + add_msg_debug( type, replace_with_npc_name( msg ) ); +} + void npc::add_msg_player_or_npc( const game_message_params ¶ms, const std::string &/*player_msg*/, const std::string &npc_msg ) const @@ -2738,6 +2745,15 @@ void npc::add_msg_player_or_npc( const game_message_params ¶ms, } } +void npc::add_msg_debug_player_or_npc( debugmode::debug_filter type, + const std::string &/*player_msg*/, + const std::string &npc_msg ) const +{ + if( get_player_view().sees( *this ) ) { + add_msg_debug( type, replace_with_npc_name( npc_msg ) ); + } +} + void npc::add_msg_player_or_say( const std::string &/*player_msg*/, const std::string &npc_speech ) const { @@ -2790,7 +2806,7 @@ void npc::on_load() // TODO: Sleeping, healing etc. last_updated = calendar::turn; time_point cur = calendar::turn - dt; - add_msg_debug( "on_load() by %s, %d turns", name, to_turns( dt ) ); + add_msg_debug( debugmode::DF_NPC, "on_load() by %s, %d turns", name, to_turns( dt ) ); // First update with 30 minute granularity, then 5 minutes, then turns for( ; cur < calendar::turn - 30_minutes; cur += 30_minutes + 1_turns ) { update_body( cur, cur + 30_minutes ); @@ -2832,7 +2848,8 @@ void npc::on_load() if( const monster *const mon = g->critter_at( pos() ) ) { mounted_creature = g->shared_from( *mon ); } else { - add_msg_debug( "NPC is meant to be riding, though the mount is not found when %s is loaded", + add_msg_debug( debugmode::DF_NPC, + "NPC is meant to be riding, though the mount is not found when %s is loaded", disp_name() ); } } @@ -3218,7 +3235,7 @@ void npc::set_attitude( npc_attitude new_attitude ) add_effect( effect_npc_flee_player, 24_hours ); } - add_msg_debug( "%s changes attitude from %s to %s", + add_msg_debug( debugmode::DF_NPC, "%s changes attitude from %s to %s", name, npc_attitude_id( attitude ), npc_attitude_id( new_attitude ) ); attitude_group new_group = get_attitude_group( new_attitude ); attitude_group old_group = get_attitude_group( attitude ); diff --git a/src/npc.h b/src/npc.h index d082eb01409f9..7554cb98fb431 100644 --- a/src/npc.h +++ b/src/npc.h @@ -1198,15 +1198,23 @@ class npc : public player using player::add_msg_if_npc; void add_msg_if_npc( const std::string &msg ) const override; void add_msg_if_npc( const game_message_params ¶ms, const std::string &msg ) const override; + using player::add_msg_debug_if_npc; + void add_msg_debug_if_npc( debugmode::debug_filter type, const std::string &msg ) const override; using player::add_msg_player_or_npc; void add_msg_player_or_npc( const std::string &player_msg, const std::string &npc_msg ) const override; void add_msg_player_or_npc( const game_message_params ¶ms, const std::string &player_msg, const std::string &npc_msg ) const override; + using player::add_msg_debug_player_or_npc; + void add_msg_debug_player_or_npc( debugmode::debug_filter type, const std::string &player_msg, + const std::string &npc_msg ) const override; using player::add_msg_if_player; void add_msg_if_player( const std::string &/*msg*/ ) const override {} void add_msg_if_player( const game_message_params &/*type*/, const std::string &/*msg*/ ) const override {} + using player::add_msg_debug_if_player; + void add_msg_debug_if_player( debugmode::debug_filter /*type*/, + const std::string &/*msg*/ ) const override {} using player::add_msg_player_or_say; void add_msg_player_or_say( const std::string &player_msg, const std::string &npc_speech ) const override; diff --git a/src/npcmove.cpp b/src/npcmove.cpp index 1a47a3e300a11..03ea28a6a9eb2 100644 --- a/src/npcmove.cpp +++ b/src/npcmove.cpp @@ -692,7 +692,7 @@ float npc::character_danger( const Character &uc ) const ret *= std::max( 0.5, u.get_speed() / 100.0 ); - add_msg_debug( "%s danger: %1f", u.disp_name(), ret ); + add_msg_debug( debugmode::DF_NPC, "%s danger: %1f", u.disp_name(), ret ); return ret; } @@ -780,7 +780,7 @@ void npc::move() static const std::string no_target_str = "none"; const Creature *target = current_target(); const std::string &target_name = target != nullptr ? target->disp_name() : no_target_str; - add_msg_debug( "NPC %s: target = %s, danger = %.1f, range = %d", + add_msg_debug( debugmode::DF_NPC, "NPC %s: target = %s, danger = %.1f, range = %d", name, target_name, ai_cache.danger, weapon.is_gun() ? confident_shoot_range( weapon, recoil_total() ) : weapon.reach_range( *this ) ); @@ -790,7 +790,7 @@ void npc::move() if( is_player_ally() ) { mutiny(); } - add_msg_debug( "NPC %s turning hostile because is guaranteed_hostile()", name ); + add_msg_debug( debugmode::DF_NPC, "NPC %s turning hostile because is guaranteed_hostile()", name ); if( op_of_u.fear > 10 + personality.aggression + personality.bravery ) { set_attitude( NPCATT_FLEE_TEMP ); // We don't want to take u on! } else { @@ -865,12 +865,12 @@ void npc::move() } } if( action == npc_investigate_sound ) { - add_msg_debug( "NPC %s: investigating sound at x(%d) y(%d)", name, + add_msg_debug( debugmode::DF_NPC, "NPC %s: investigating sound at x(%d) y(%d)", name, ai_cache.s_abs_pos.x, ai_cache.s_abs_pos.y ); } } else if( ai_cache.sound_alerts.empty() && ai_cache.guard_pos ) { tripoint return_guard_pos = *ai_cache.guard_pos; - add_msg_debug( "NPC %s: returning to guard spot at x(%d) y(%d)", name, + add_msg_debug( debugmode::DF_NPC, "NPC %s: returning to guard spot at x(%d) y(%d)", name, return_guard_pos.x, return_guard_pos.y ); action = npc_return_to_guard_pos; } else { @@ -1001,7 +1001,7 @@ void npc::move() action = method_of_attack(); } - add_msg_debug( "%s chose action %s.", name, npc_action_name( action ) ); + add_msg_debug( debugmode::DF_NPC, "%s chose action %s.", name, npc_action_name( action ) ); execute_action( action ); } @@ -1343,7 +1343,7 @@ void npc::execute_action( npc_action action ) break; case npc_noop: - add_msg_debug( "%s skips turn (noop)", disp_name() ); + add_msg_debug( debugmode::DF_NPC, "%s skips turn (noop)", disp_name() ); return; default: @@ -1351,7 +1351,7 @@ void npc::execute_action( npc_action action ) } if( oldmoves == moves ) { - add_msg_debug( "NPC didn't use its moves. Action %s (%d).", + add_msg_debug( debugmode::DF_NPC, "NPC didn't use its moves. Action %s (%d).", npc_action_name( action ), action ); } } @@ -1441,7 +1441,7 @@ npc_action npc::method_of_attack() } ); if( emergency() && alt_attack() ) { - add_msg_debug( "%s is trying an alternate attack", disp_name() ); + add_msg_debug( debugmode::DF_NPC, "%s is trying an alternate attack", disp_name() ); return npc_noop; } @@ -1449,13 +1449,13 @@ npc_action npc::method_of_attack() int reach_range = weapon.reach_range( *this ); if( !trigdist ) { if( reach_range > 1 && reach_range >= dist && clear_shot_reach( pos(), tar ) ) { - add_msg_debug( "%s is trying a reach attack", disp_name() ); + add_msg_debug( debugmode::DF_NPC, "%s is trying a reach attack", disp_name() ); return npc_reach_attack; } } else { if( reach_range > 1 && reach_range >= std::round( trig_dist( pos(), tar ) ) && clear_shot_reach( pos(), tar ) ) { - add_msg_debug( "%s is trying a reach attack", disp_name() ); + add_msg_debug( debugmode::DF_NPC, "%s is trying a reach attack", disp_name() ); return npc_reach_attack; } } @@ -1464,25 +1464,25 @@ npc_action npc::method_of_attack() if( !modes.empty() && sees( *critter ) && has_los && confident_gun_mode_range( modes[ 0 ].second, cur_recoil ) >= dist ) { if( cbm_weapon_index > 0 && !weapon.ammo_sufficient() && can_reload_current() ) { - add_msg_debug( "%s is reloading", disp_name() ); + add_msg_debug( debugmode::DF_NPC, "%s is reloading", disp_name() ); return npc_reload; } if( wont_hit_friend( tar, weapon, false ) ) { weapon.gun_set_mode( modes[ 0 ].first ); - add_msg_debug( "%s is trying to shoot someone", disp_name() ); + add_msg_debug( debugmode::DF_NPC, "%s is trying to shoot someone", disp_name() ); return npc_shoot; } else { if( !dont_move_ff ) { - add_msg_debug( "%s is trying to avoid friendly fire", disp_name() ); + add_msg_debug( debugmode::DF_NPC, "%s is trying to avoid friendly fire", disp_name() ); return npc_avoid_friendly_fire; } } } if( dist == 1 && same_z ) { - add_msg_debug( "%s is trying a melee attack", disp_name() ); + add_msg_debug( debugmode::DF_NPC, "%s is trying a melee attack", disp_name() ); return npc_melee; } @@ -1490,12 +1490,12 @@ npc_action npc::method_of_attack() if( cbm_weapon_index < 0 ) { // TODO: Add a time check now that wielding takes a lot of time if( wield_better_weapon() ) { - add_msg_debug( "%s is changing weapons", disp_name() ); + add_msg_debug( debugmode::DF_NPC, "%s is changing weapons", disp_name() ); return npc_noop; } if( !weapon.ammo_sufficient() && can_reload_current() ) { - add_msg_debug( "%s is reloading", disp_name() ); + add_msg_debug( debugmode::DF_NPC, "%s is reloading", disp_name() ); return npc_reload; } } @@ -1503,10 +1503,10 @@ npc_action npc::method_of_attack() // TODO: Needs a check for transparent but non-passable tiles on the way if( !modes.empty() && sees( *critter ) && aim_per_move( weapon, recoil ) > 0 && confident_shoot_range( weapon, get_most_accurate_sight( weapon ) ) >= dist ) { - add_msg_debug( "%s is aiming" ); + add_msg_debug( debugmode::DF_NPC, "%s is aiming" ); return npc_aim; } - add_msg_debug( "%s can't figure out what to do", disp_name() ); + add_msg_debug( debugmode::DF_NPC, "%s can't figure out what to do", disp_name() ); return ( dont_move || !same_z ) ? npc_undecided : npc_melee; } @@ -2015,7 +2015,7 @@ npc_action npc::address_player() npc_action npc::long_term_goal_action() { - add_msg_debug( "long_term_goal_action()" ); + add_msg_debug( debugmode::DF_NPC, "long_term_goal_action()" ); if( mission == NPC_MISSION_SHOPKEEP || mission == NPC_MISSION_SHELTER || ( is_player_ally() && mission != NPC_MISSION_TRAVELLING ) ) { @@ -2083,7 +2083,7 @@ int npc::confident_gun_mode_range( const gun_mode &gun, int at_recoil ) const double max_dispersion = get_weapon_dispersion( *( gun.target ) ).max() + at_recoil; double even_chance_range = range_with_even_chance_of_good_hit( max_dispersion ); double confident_range = even_chance_range * confidence_mult(); - add_msg_debug( "confident_gun (%s<=%.2f) at %.1f", gun.tname(), confident_range, + add_msg_debug( debugmode::DF_NPC, "confident_gun (%s<=%.2f) at %.1f", gun.tname(), confident_range, max_dispersion ); return std::max( confident_range, 1 ); } @@ -2094,7 +2094,8 @@ int npc::confident_throw_range( const item &thrown, Creature *target ) const double even_chance_range = ( target == nullptr ? 0.5 : target->ranged_target_size() ) / average_dispersion; double confident_range = even_chance_range * confidence_mult(); - add_msg_debug( "confident_throw_range == %d", static_cast( confident_range ) ); + add_msg_debug( debugmode::DF_NPC, "confident_throw_range == %d", + static_cast( confident_range ) ); return static_cast( confident_range ); } @@ -2211,10 +2212,10 @@ bool npc::update_path( const tripoint &p, const bool no_bashing, bool force ) if( new_path.empty() ) { if( !ai_cache.sound_alerts.empty() ) { ai_cache.sound_alerts.erase( ai_cache.sound_alerts.begin() ); - add_msg_debug( "failed to path to sound alert %d,%d,%d->%d,%d,%d", + add_msg_debug( debugmode::DF_NPC, "failed to path to sound alert %d,%d,%d->%d,%d,%d", posx(), posy(), posz(), p.x, p.y, p.z ); } - add_msg_debug( "Failed to path %d,%d,%d->%d,%d,%d", + add_msg_debug( debugmode::DF_NPC, "Failed to path %d,%d,%d->%d,%d,%d", posx(), posy(), posz(), p.x, p.y, p.z ); } @@ -2480,7 +2481,7 @@ void npc::move_to_next() } if( path.empty() ) { - add_msg_debug( "npc::move_to_next() called with an empty path or path " + add_msg_debug( debugmode::DF_NPC, "npc::move_to_next() called with an empty path or path " "containing only current position" ); move_pause(); return; @@ -2980,7 +2981,7 @@ void npc::pick_up_item() } if( !rules.has_flag( ally_rule::allow_pick_up ) && is_player_ally() ) { - add_msg_debug( "%s::pick_up_item(); Canceling on player's request", name ); + add_msg_debug( debugmode::DF_NPC, "%s::pick_up_item(); Canceling on player's request", name ); fetching_item = false; moves -= 1; return; @@ -2998,11 +2999,11 @@ void npc::pick_up_item() // Or player who is leading us doesn't want us to pick it up fetching_item = false; move_pause(); - add_msg_debug( "Canceling pickup - no items or new zone" ); + add_msg_debug( debugmode::DF_NPC, "Canceling pickup - no items or new zone" ); return; } - add_msg_debug( "%s::pick_up_item(); [%d, %d, %d] => [%d, %d, %d]", name, + add_msg_debug( debugmode::DF_NPC, "%s::pick_up_item(); [ % d, % d, % d] => [ % d, % d, % d]", name, posx(), posy(), posz(), wanted_item_pos.x, wanted_item_pos.y, wanted_item_pos.z ); if( const cata::optional dest = nearest_passable( wanted_item_pos, pos() ) ) { update_path( *dest ); @@ -3010,13 +3011,13 @@ void npc::pick_up_item() const int dist_to_pickup = rl_dist( pos(), wanted_item_pos ); if( dist_to_pickup > 1 && !path.empty() ) { - add_msg_debug( "Moving; [%d, %d, %d] => [%d, %d, %d]", + add_msg_debug( debugmode::DF_NPC, "Moving; [%d, %d, %d] => [%d, %d, %d]", posx(), posy(), posz(), path[0].x, path[0].y, path[0].z ); move_to_next(); return; } else if( dist_to_pickup > 1 && path.empty() ) { - add_msg_debug( "Can't find path" ); + add_msg_debug( debugmode::DF_NPC, "Can't find path" ); // This can happen, always do something fetching_item = false; move_pause(); @@ -3113,7 +3114,8 @@ void npc::drop_items( const units::mass &drop_weight, const units::volume &drop_ /* Remove this when someone debugs it back to functionality */ return; - add_msg_debug( "%s is dropping items-%3.2f kg, %3.2f L (%d items, wgt %3.2f/%3.2f kg, " + add_msg_debug( debugmode::DF_NPC, + "%s is dropping items-%3.2f kg, %3.2f L (%d items, wgt %3.2f/%3.2f kg, " "vol %3.2f/%3.2f L)", name, units::to_kilogram( drop_weight ), units::to_liter( drop_volume ), inv->size(), units::to_kilogram( weight_carried() ), units::to_kilogram( weight_capacity() ), @@ -3426,12 +3428,14 @@ bool npc::wield_better_weapon() // Until then, the NPCs should reload the guns as a last resort if( best == &weapon ) { - add_msg_debug( "Wielded %s is best at %.1f, not switching", best->type->get_id().str(), + add_msg_debug( debugmode::DF_NPC, "Wielded %s is best at %.1f, not switching", + best->type->get_id().str(), best_value ); return false; } - add_msg_debug( "Wielding %s at value %.1f", best->type->get_id().str(), best_value ); + add_msg_debug( debugmode::DF_NPC, "Wielding %s at value %.1f", best->type->get_id().str(), + best_value ); wield( *best ); return true; @@ -3439,7 +3443,7 @@ bool npc::wield_better_weapon() bool npc::scan_new_items() { - add_msg_debug( "%s scanning new items", name ); + add_msg_debug( debugmode::DF_NPC, "%s scanning new items", name ); if( wield_better_weapon() ) { return true; } else { @@ -4212,7 +4216,7 @@ void npc::go_to_omt_destination() } } if( goal == no_goal_point || omt_path.empty() ) { - add_msg_debug( "npc::go_to_destination with no goal" ); + add_msg_debug( debugmode::DF_NPC, "npc::go_to_destination with no goal" ); move_pause(); reach_omt_destination(); return; @@ -4260,7 +4264,7 @@ void npc::go_to_omt_destination() } } path = here.route( pos(), centre_sub, get_pathfinding_settings(), get_path_avoid() ); - add_msg_debug( "%s going %s->%s", name, omt_pos.to_string(), goal.to_string() ); + add_msg_debug( debugmode::DF_NPC, "%s going %s->%s", name, omt_pos.to_string(), goal.to_string() ); if( !path.empty() ) { move_to_next(); @@ -4338,7 +4342,7 @@ std::string npc_action_name( npc_action action ) void print_action( const char *prepend, npc_action action ) { if( action != npc_undecided ) { - add_msg_debug( prepend, npc_action_name( action ) ); + add_msg_debug( debugmode::DF_NPC, prepend, npc_action_name( action ) ); } } diff --git a/src/npctalk.cpp b/src/npctalk.cpp index e38b808d2720f..885938b97ac79 100644 --- a/src/npctalk.cpp +++ b/src/npctalk.cpp @@ -631,7 +631,8 @@ void npc::handle_sound( const sounds::sound_t spriority, const std::string &desc const tripoint s_abs_pos = here.getabs( spos ); const tripoint my_abs_pos = here.getabs( pos() ); - add_msg_debug( "%s heard '%s', priority %d at volume %d from %d:%d, my pos %d:%d", + add_msg_debug( debugmode::DF_NPC, + "%s heard '%s', priority %d at volume %d from %d:%d, my pos %d:%d", disp_name(), description, static_cast( spriority ), heard_volume, s_abs_pos.x, s_abs_pos.y, my_abs_pos.x, my_abs_pos.y ); @@ -652,11 +653,11 @@ void npc::handle_sound( const sounds::sound_t spriority, const std::string &desc // but only for bantering purposes, not for investigating. if( spriority < sounds::sound_t::alarm ) { if( player_ally ) { - add_msg_debug( "Allied NPC ignored same faction %s", name ); + add_msg_debug( debugmode::DF_NPC, "Allied NPC ignored same faction %s", name ); return; } if( npc_ally ) { - add_msg_debug( "NPC ignored same faction %s", name ); + add_msg_debug( debugmode::DF_NPC, "NPC ignored same faction %s", name ); return; } } @@ -664,7 +665,7 @@ void npc::handle_sound( const sounds::sound_t spriority, const std::string &desc // and listener is friendly and sound source is combat or alert only. if( spriority < sounds::sound_t::alarm && player_character.sees( spos ) ) { if( is_player_ally() ) { - add_msg_debug( "NPC %s ignored low priority noise that player can see", name ); + add_msg_debug( debugmode::DF_NPC, "NPC %s ignored low priority noise that player can see", name ); return; // discount if sound source is player, or seen by player, // listener is neutral and sound type is worth investigating. @@ -703,7 +704,7 @@ void npc::handle_sound( const sounds::sound_t spriority, const std::string &desc } } if( should_check ) { - add_msg_debug( "%s added noise at pos %d:%d", name, s_abs_pos.x, s_abs_pos.y ); + add_msg_debug( debugmode::DF_NPC, "%s added noise at pos %d:%d", name, s_abs_pos.x, s_abs_pos.y ); dangerous_sound temp_sound; temp_sound.abs_pos = s_abs_pos; temp_sound.volume = heard_volume; diff --git a/src/npctalk_funcs.cpp b/src/npctalk_funcs.cpp index be2aa274fac55..ed10341c7511e 100644 --- a/src/npctalk_funcs.cpp +++ b/src/npctalk_funcs.cpp @@ -210,7 +210,7 @@ void spawn_animal( npc &p, const mtype_id &mon ) mon_ptr->add_effect( effect_pet, 1_turns, true ); } else { // TODO: handle this gracefully (return the money, proper in-character message from npc) - add_msg_debug( "No space to spawn purchased pet" ); + add_msg_debug( debugmode::DF_NPC, "No space to spawn purchased pet" ); } } diff --git a/src/overmap.cpp b/src/overmap.cpp index baa6babc4fa8b..0eb6faa9d4163 100644 --- a/src/overmap.cpp +++ b/src/overmap.cpp @@ -2116,11 +2116,11 @@ void overmap::signal_hordes( const tripoint_rel_sm &p_rel, const int sig_power ) const int min_inc_inter = 3; // Min interest increase to already targeted source const int inc_roll = rng( min_inc_inter, calculated_inter ); mg.inc_interest( inc_roll ); - add_msg_debug( "horde inc interest %d dist %d", inc_roll, dist ); + add_msg_debug( debugmode::DF_OVERMAP, "horde inc interest %d dist %d", inc_roll, dist ); } else { // New signal source mg.set_target( p.xy() ); mg.set_interest( min_capped_inter ); - add_msg_debug( "horde set interest %d dist %d", min_capped_inter, dist ); + add_msg_debug( debugmode::DF_OVERMAP, "horde set interest %d dist %d", min_capped_inter, dist ); } } } diff --git a/src/player.cpp b/src/player.cpp index e39b2933610de..73ce8e43fd20a 100644 --- a/src/player.cpp +++ b/src/player.cpp @@ -2540,6 +2540,11 @@ void player::add_msg_if_player( const game_message_params ¶ms, const std::st Messages::add_msg( params, msg ); } +void player::add_msg_debug_if_player( debugmode::debug_filter type, const std::string &msg ) const +{ + Messages::add_msg_debug( type, msg ); +} + void player::add_msg_player_or_npc( const game_message_params ¶ms, const std::string &player_msg, const std::string &/*npc_msg*/ ) const @@ -2547,6 +2552,13 @@ void player::add_msg_player_or_npc( const game_message_params ¶ms, Messages::add_msg( params, player_msg ); } +void player::add_msg_debug_player_or_npc( debugmode::debug_filter type, + const std::string &player_msg, + const std::string &/*npc_msg*/ ) const +{ + Messages::add_msg_debug( type, player_msg ); +} + void player::add_msg_player_or_say( const std::string &player_msg, const std::string &/*npc_speech*/ ) const { diff --git a/src/player.h b/src/player.h index bd78c984cbe31..eb8a12fac4d7b 100644 --- a/src/player.h +++ b/src/player.h @@ -365,11 +365,17 @@ class player : public Character using Character::add_msg_if_player; void add_msg_if_player( const std::string &msg ) const override; void add_msg_if_player( const game_message_params ¶ms, const std::string &msg ) const override; + using Character::add_msg_debug_if_player; + void add_msg_debug_if_player( debugmode::debug_filter type, + const std::string &msg ) const override; using Character::add_msg_player_or_npc; void add_msg_player_or_npc( const std::string &player_msg, const std::string &npc_str ) const override; void add_msg_player_or_npc( const game_message_params ¶ms, const std::string &player_msg, const std::string &npc_msg ) const override; + using Character::add_msg_debug_player_or_npc; + void add_msg_debug_player_or_npc( debugmode::debug_filter type, const std::string &player_msg, + const std::string &npc_msg ) const override; using Character::add_msg_player_or_say; void add_msg_player_or_say( const std::string &player_msg, const std::string &npc_speech ) const override; diff --git a/src/ranged.cpp b/src/ranged.cpp index aface68e45d3d..65204f8f22ca2 100644 --- a/src/ranged.cpp +++ b/src/ranged.cpp @@ -1959,7 +1959,8 @@ double Character::gun_value( const item &weap, int ammo ) const double gun_value = damage_and_accuracy * capacity_factor; - add_msg_debug( "%s as gun: %.1f total, %.1f dispersion, %.1f damage, %.1f capacity", + add_msg_debug( debugmode::DF_RANGED, + "%s as gun: %.1f total, %.1f dispersion, %.1f damage, %.1f capacity", weap.type->get_id().str(), gun_value, dispersion_factor, damage_factor, capacity_factor ); return std::max( 0.0, gun_value ); diff --git a/src/sdlsound.cpp b/src/sdlsound.cpp index d083b41872123..a2252967b746c 100644 --- a/src/sdlsound.cpp +++ b/src/sdlsound.cpp @@ -465,7 +465,7 @@ void sfx::play_variant_sound( const std::string &id, const std::string &variant, return; } - add_msg_debug( "sound id: %s, variant: %s, volume: %d ", id, variant, volume ); + add_msg_debug( debugmode::DF_SOUND, "sound id: %s, variant: %s, volume: %d ", id, variant, volume ); if( !check_sound( volume ) ) { return; @@ -495,7 +495,7 @@ void sfx::play_variant_sound( const std::string &id, const std::string &variant, return; } - add_msg_debug( "sound id: %s, variant: %s, volume: %d ", id, variant, volume ); + add_msg_debug( debugmode::DF_SOUND, "sound id: %s, variant: %s, volume: %d ", id, variant, volume ); if( !check_sound( volume ) ) { return; diff --git a/src/sounds.cpp b/src/sounds.cpp index 7c09a08e2301b..ee233bd5fca42 100644 --- a/src/sounds.cpp +++ b/src/sounds.cpp @@ -290,7 +290,8 @@ static int get_signal_for_hordes( const centroid ¢r ) sig_power = std::max( sig_power, min_sig_cap ); //Capping extremely high signal to hordes sig_power = std::min( sig_power, max_sig_cap ); - add_msg_debug( "vol %d vol_hordes %d sig_power %d ", vol, vol_hordes, sig_power ); + add_msg_debug( debugmode::DF_SOUND, "vol %d vol_hordes %d sig_power %d ", vol, vol_hordes, + sig_power ); return sig_power; } return 0; @@ -681,7 +682,7 @@ void sfx::do_vehicle_engine_sfx() const Character &player_character = get_player_character(); if( !player_character.in_vehicle ) { fade_audio_channel( ch, 300 ); - add_msg_debug( "STOP interior_engine_sound, OUT OF CAR" ); + add_msg_debug( debugmode::DF_SOUND, "STOP interior_engine_sound, OUT OF CAR" ); return; } if( player_character.in_sleep_state() && !audio_muted ) { @@ -700,7 +701,7 @@ void sfx::do_vehicle_engine_sfx() } if( !veh->engine_on ) { fade_audio_channel( ch, 100 ); - add_msg_debug( "STOP interior_engine_sound" ); + add_msg_debug( debugmode::DF_SOUND, "STOP interior_engine_sound" ); return; } @@ -727,9 +728,9 @@ void sfx::do_vehicle_engine_sfx() if( !is_channel_playing( ch ) ) { play_ambient_variant_sound( id_and_variant.first, id_and_variant.second, sfx::get_heard_volume( player_character.pos() ), ch, 1000 ); - add_msg_debug( "START %s %s", id_and_variant.first, id_and_variant.second ); + add_msg_debug( debugmode::DF_SOUND, "START %s %s", id_and_variant.first, id_and_variant.second ); } else { - add_msg_debug( "PLAYING" ); + add_msg_debug( debugmode::DF_SOUND, "PLAYING" ); } int current_speed = veh->velocity; bool in_reverse = false; @@ -765,11 +766,11 @@ void sfx::do_vehicle_engine_sfx() if( current_gear > previous_gear ) { play_variant_sound( "vehicle", "gear_shift", get_heard_volume( player_character.pos() ), 0_degrees, 0.8, 0.8 ); - add_msg_debug( "GEAR UP" ); + add_msg_debug( debugmode::DF_SOUND, "GEAR UP" ); } else if( current_gear < previous_gear ) { play_variant_sound( "vehicle", "gear_shift", get_heard_volume( player_character.pos() ), 0_degrees, 1.2, 1.2 ); - add_msg_debug( "GEAR DOWN" ); + add_msg_debug( debugmode::DF_SOUND, "GEAR DOWN" ); } if( ( safe_speed != 0 ) ) { if( current_gear == 0 ) { @@ -786,10 +787,10 @@ void sfx::do_vehicle_engine_sfx() if( current_speed != previous_speed ) { Mix_HaltChannel( static_cast( ch ) ); - add_msg_debug( "STOP speed %d =/= %d", current_speed, previous_speed ); + add_msg_debug( debugmode::DF_SOUND, "STOP speed %d =/= %d", current_speed, previous_speed ); play_ambient_variant_sound( id_and_variant.first, id_and_variant.second, sfx::get_heard_volume( player_character.pos() ), ch, 1000, pitch ); - add_msg_debug( "PITCH %f", pitch ); + add_msg_debug( debugmode::DF_SOUND, "PITCH %f", pitch ); } previous_speed = current_speed; previous_gear = current_gear; @@ -807,7 +808,7 @@ void sfx::do_vehicle_exterior_engine_sfx() // early bail-outs for efficiency if( player_character.in_vehicle ) { fade_audio_channel( ch, 300 ); - add_msg_debug( "STOP exterior_engine_sound, IN CAR" ); + add_msg_debug( debugmode::DF_SOUND, "STOP exterior_engine_sound, IN CAR" ); return; } if( player_character.in_sleep_state() && !audio_muted ) { @@ -835,7 +836,7 @@ void sfx::do_vehicle_exterior_engine_sfx() } if( !noise_factor || !veh ) { fade_audio_channel( ch, 300 ); - add_msg_debug( "STOP exterior_engine_sound, NO NOISE" ); + add_msg_debug( debugmode::DF_SOUND, "STOP exterior_engine_sound, NO NOISE" ); return; } @@ -864,26 +865,29 @@ void sfx::do_vehicle_exterior_engine_sfx() if( engine_external_id_and_variant == id_and_variant ) { Mix_SetPosition( ch_int, to_degrees( get_heard_angle( veh->global_pos3() ) ), 0 ); set_channel_volume( ch, vol ); - add_msg_debug( "PLAYING exterior_engine_sound, vol: ex:%d true:%d", vol, Mix_Volume( ch_int, - -1 ) ); + add_msg_debug( debugmode::DF_SOUND, "PLAYING exterior_engine_sound, vol: ex:%d true:%d", vol, + Mix_Volume( ch_int, + -1 ) ); } else { engine_external_id_and_variant = id_and_variant; Mix_HaltChannel( ch_int ); - add_msg_debug( "STOP exterior_engine_sound, change id/var" ); + add_msg_debug( debugmode::DF_SOUND, "STOP exterior_engine_sound, change id/var" ); play_ambient_variant_sound( id_and_variant.first, id_and_variant.second, 128, ch, 0 ); Mix_SetPosition( ch_int, to_degrees( get_heard_angle( veh->global_pos3() ) ), 0 ); set_channel_volume( ch, vol ); - add_msg_debug( "START exterior_engine_sound %s %s vol: %d", id_and_variant.first, + add_msg_debug( debugmode::DF_SOUND, "START exterior_engine_sound %s %s vol: %d", + id_and_variant.first, id_and_variant.second, Mix_Volume( ch_int, -1 ) ); } } else { play_ambient_variant_sound( id_and_variant.first, id_and_variant.second, 128, ch, 0 ); - add_msg_debug( "Vol: %d %d", vol, Mix_Volume( ch_int, -1 ) ); + add_msg_debug( debugmode::DF_SOUND, "Vol: %d %d", vol, Mix_Volume( ch_int, -1 ) ); Mix_SetPosition( ch_int, to_degrees( get_heard_angle( veh->global_pos3() ) ), 0 ); - add_msg_debug( "Vol: %d %d", vol, Mix_Volume( ch_int, -1 ) ); + add_msg_debug( debugmode::DF_SOUND, "Vol: %d %d", vol, Mix_Volume( ch_int, -1 ) ); set_channel_volume( ch, vol ); - add_msg_debug( "START exterior_engine_sound NEW %s %s vol: ex:%d true:%d", id_and_variant.first, + add_msg_debug( debugmode::DF_SOUND, "START exterior_engine_sound NEW %s %s vol: ex:%d true:%d", + id_and_variant.first, id_and_variant.second, vol, Mix_Volume( ch_int, -1 ) ); } } diff --git a/src/suffer.cpp b/src/suffer.cpp index 1a357fd924383..74998c2c59adf 100644 --- a/src/suffer.cpp +++ b/src/suffer.cpp @@ -1702,7 +1702,7 @@ void Character::mend( int rate_multiplier ) needs_splint = false; } - add_msg_debug( "Limb mend healing factor: %.2f", healing_factor ); + add_msg_debug( debugmode::DF_CHAR_HEALTH, "Limb mend healing factor: %.2f", healing_factor ); if( healing_factor <= 0.0f ) { // The section below assumes positive healing rate return; @@ -1951,7 +1951,7 @@ void Character::add_addiction( add_type type, int strength ) i.intensity++; } - add_msg_debug( "Updating addiction: %d intensity, %d sated", + add_msg_debug( debugmode::DF_CHAR_HEALTH, "Updating addiction: %d intensity, %d sated", i.intensity, to_turns( i.sated ) ); return; @@ -1959,10 +1959,10 @@ void Character::add_addiction( add_type type, int strength ) // Add a new addiction const int roll = rng( 0, 100 ); - add_msg_debug( "Addiction: roll %d vs strength %d", roll, strength ); + add_msg_debug( debugmode::DF_CHAR_HEALTH, "Addiction: roll %d vs strength %d", roll, strength ); if( roll < strength ) { const std::string &type_name = addiction_type_name( type ); - add_msg_debug( "%s got addicted to %s", disp_name(), type_name ); + add_msg_debug( debugmode::DF_CHAR_HEALTH, "%s got addicted to %s", disp_name(), type_name ); addictions.emplace_back( type, 1 ); get_event_bus().send( getID(), type ); } diff --git a/src/talker_avatar.cpp b/src/talker_avatar.cpp index 3dd0706c37dd0..e43ca0e9c7e3c 100644 --- a/src/talker_avatar.cpp +++ b/src/talker_avatar.cpp @@ -76,7 +76,7 @@ void talker_avatar::buy_monster( talker &seller, const mtype_id &mtype, int cost for( int i = 0; i < count; i++ ) { monster *const mon_ptr = g->place_critter_around( mtype, me_chr->pos(), 3 ); if( !mon_ptr ) { - add_msg_debug( "Cannot place u_buy_monster, no valid placement locations." ); + add_msg_debug( debugmode::DF_TALKER, "Cannot place u_buy_monster, no valid placement locations." ); break; } monster &tmp = *mon_ptr; diff --git a/src/talker_npc.cpp b/src/talker_npc.cpp index a1e107f65761b..0e065a909b4c2 100644 --- a/src/talker_npc.cpp +++ b/src/talker_npc.cpp @@ -515,9 +515,9 @@ std::string talker_npc::give_item_to( const bool to_use ) int new_ammo = me_npc->ammo_count_for( given ); const double new_weapon_value = me_npc->weapon_value( given, new_ammo ); const double cur_weapon_value = me_npc->weapon_value( me_npc->weapon, our_ammo ); - add_msg_debug( "NPC evaluates own %s (%d ammo): %0.1f", + add_msg_debug( debugmode::DF_TALKER, "NPC evaluates own %s (%d ammo): %0.1f", me_npc->weapon.typeId().str(), our_ammo, cur_weapon_value ); - add_msg_debug( "NPC evaluates your %s (%d ammo): %0.1f", + add_msg_debug( debugmode::DF_TALKER, "NPC evaluates your %s (%d ammo): %0.1f", given.typeId().str(), new_ammo, new_weapon_value ); if( to_use ) { // Eating first, to avoid evaluating bread as a weapon diff --git a/src/vehicle.cpp b/src/vehicle.cpp index 09e5fb3b5bb9a..0063764704479 100644 --- a/src/vehicle.cpp +++ b/src/vehicle.cpp @@ -2095,7 +2095,7 @@ bool vehicle::remove_carried_vehicle( const std::vector &carried_parts ) map &here = get_map(); vehicle *new_vehicle = here.add_vehicle( vproto_id( "none" ), new_pos3, new_dir ); if( new_vehicle == nullptr ) { - add_msg_debug( "Unable to unload bike rack, host face %d, new_dir %d!", + add_msg_debug( debugmode::DF_VEHICLE, "Unable to unload bike rack, host face %d, new_dir %d!", to_degrees( face.dir() ), to_degrees( new_dir ) ); return false; } @@ -3560,7 +3560,7 @@ int vehicle::ground_acceleration( const bool fueled, int at_vel_in_vmi ) const } int engine_power_ratio = total_power_w( fueled ) / weight; int accel_at_vel = 100 * 100 * engine_power_ratio / cmps; - add_msg_debug( "%s: accel at %d vimph is %d", name, target_vmiph, + add_msg_debug( debugmode::DF_VEHICLE, "%s: accel at %d vimph is %d", name, target_vmiph, cmps_to_vmiph( accel_at_vel ) ); return cmps_to_vmiph( accel_at_vel ); } @@ -3592,7 +3592,7 @@ int vehicle::water_acceleration( const bool fueled, int at_vel_in_vmi ) const } int engine_power_ratio = total_power_w( fueled ) / weight; int accel_at_vel = 100 * 100 * engine_power_ratio / cmps; - add_msg_debug( "%s: water accel at %d vimph is %d", name, target_vmiph, + add_msg_debug( debugmode::DF_VEHICLE, "%s: water accel at %d vimph is %d", name, target_vmiph, cmps_to_vmiph( accel_at_vel ) ); return cmps_to_vmiph( accel_at_vel ); } @@ -3678,7 +3678,8 @@ int vehicle::max_ground_velocity( const bool fueled ) const double max_in_mps = simple_cubic_solution( coeff_air_drag(), c_rolling_drag, c_rolling_drag * vehicles::rolling_constant_to_variable, -total_engine_w ); - add_msg_debug( "%s: power %d, c_air %3.2f, c_rolling %3.2f, max_in_mps %3.2f", + add_msg_debug( debugmode::DF_VEHICLE, + "%s: power %d, c_air %3.2f, c_rolling %3.2f, max_in_mps %3.2f", name, total_engine_w, coeff_air_drag(), c_rolling_drag, max_in_mps ); return mps_to_vmiph( max_in_mps ); } @@ -3698,7 +3699,8 @@ int vehicle::max_water_velocity( const bool fueled ) const int total_engine_w = total_power_w( fueled ); double total_drag = coeff_water_drag() + coeff_air_drag(); double max_in_mps = std::cbrt( total_engine_w / total_drag ); - add_msg_debug( "%s: power %d, c_air %3.2f, c_water %3.2f, water max_in_mps %3.2f", + add_msg_debug( debugmode::DF_VEHICLE, + "%s: power %d, c_air %3.2f, c_water %3.2f, water max_in_mps %3.2f", name, total_engine_w, coeff_air_drag(), coeff_water_drag(), max_in_mps ); return mps_to_vmiph( max_in_mps ); } @@ -3888,7 +3890,7 @@ void vehicle::noise_and_smoke( int load, time_duration time ) lvl++; } } - add_msg_debug( "VEH NOISE final: %d", static_cast( noise ) ); + add_msg_debug( debugmode::DF_VEHICLE, "VEH NOISE final: %d", static_cast( noise ) ); vehicle_noise = static_cast( noise ); sounds::sound( global_pos3(), noise, sounds::sound_t::movement, _( is_rotorcraft() ? heli_noise : sounds[lvl].first ), true ); @@ -4027,7 +4029,10 @@ double vehicle::coeff_air_drag() const // tally the results of each row and prorate them relative to vehicle width for( drag_column &dc : drag ) { // even as m_debug you rarely want to see this - // add_msg_debug( "veh %: pro %d, hboard %d, fboard %d, shield %d, seat %d, roof %d, aisle %d, turret %d, panel %d, exposed %d, last %d\n", name, dc.pro, dc.hboard, dc.fboard, dc.shield, dc.seat, dc.roof, dc.aisle, dc.turret, dc.panel, dc.exposed, dc.last ); + add_msg_debug( debugmode::DF_VEHICLE_DRAG, + "veh %: pro %d, hboard %d, fboard %d, shield %d, seat %d, roof %d, aisle %d, turret %d, panel %d, exposed %d, last %d\n", + name, dc.pro, dc.hboard, dc.fboard, dc.shield, dc.seat, dc.roof, dc.aisle, dc.turret, dc.panel, + dc.exposed, dc.last ); double c_air_drag_c = c_air_base; // rams in front of the vehicle mildly worsens air drag @@ -4077,7 +4082,8 @@ double vehicle::coeff_air_drag() const height /= width; c_air_drag /= width; double cross_area = height * tile_to_width( width ); - add_msg_debug( "%s: height %3.2fm, width %3.2fm (%d tiles), c_air %3.2f\n", name, height, + add_msg_debug( debugmode::DF_VEHICLE_DRAG, + "%s: height %3.2fm, width %3.2fm (%d tiles), c_air %3.2f\n", name, height, tile_to_width( width ), width, c_air_drag ); // F_air_drag = c_air_drag * cross_area * 1/2 * air_density * v^2 // coeff_air_resistance = c_air_drag * cross_area * 1/2 * air_density @@ -4162,9 +4168,9 @@ double vehicle::lift_thrust_of_rotorcraft( const bool fuelled, const bool safe ) // lift_thrust in lbthrust double lift_thrust = ( 8.8658 * std::pow( engine_power_in_hp / rotor_area_in_feet, -0.3107 ) ) * engine_power_in_hp; - add_msg_debug( - "lift thrust in lbs of %s = %f, rotor area in feet : %d, engine power in hp %f, thrust in newtons : %f", - name, lift_thrust, rotor_area_in_feet, engine_power_in_hp, engine_power_in_hp * 4.45 ); + add_msg_debug( debugmode::DF_VEHICLE, + "lift thrust in lbs of %s = %f, rotor area in feet : %d, engine power in hp %f, thrust in newtons : %f", + name, lift_thrust, rotor_area_in_feet, engine_power_in_hp, engine_power_in_hp * 4.45 ); // convert to newtons. return lift_thrust * 4.45; } @@ -4319,7 +4325,7 @@ float vehicle::k_traction( float wheel_traction_area ) const } const float mass_penalty = fraction_without_traction * to_kilogram( total_mass() ); float traction = std::min( 1.0f, wheel_traction_area / mass_penalty ); - add_msg_debug( "%s has traction %.2f", name, traction ); + add_msg_debug( debugmode::DF_VEHICLE, "%s has traction %.2f", name, traction ); // For now make it easy until it gets properly balanced: add a low cap of 0.1 return std::max( 0.1f, traction ); @@ -4684,9 +4690,9 @@ void vehicle::consume_fuel( int load, bool idling ) player_character.mod_fatigue( 1 ); } player_character.mod_stamina( -( base_burn + mod ) ); - add_msg_debug( "Load: %d", load ); - add_msg_debug( "Mod: %d", mod ); - add_msg_debug( "Burn: %d", -( base_burn + mod ) ); + add_msg_debug( debugmode::DF_VEHICLE, "Load: %d", load ); + add_msg_debug( debugmode::DF_VEHICLE, "Mod: %d", mod ); + add_msg_debug( debugmode::DF_VEHICLE, "Burn: %d", -( base_burn + mod ) ); } } @@ -5057,7 +5063,7 @@ int vehicle::traverse_vehicle_graph( Vehicle *start_veh, int amount, Func action visited_vehs.insert( current_veh ); connected_vehs.pop(); - add_msg_debug( "Traversing graph with %d power", amount ); + add_msg_debug( debugmode::DF_VEHICLE, "Traversing graph with %d power", amount ); for( int p : current_veh->loose_parts ) { if( !current_veh->part_info( p ).has_flag( "POWER_TRANSFER" ) ) { @@ -5078,11 +5084,13 @@ int vehicle::traverse_vehicle_graph( Vehicle *start_veh, int amount, Func action connected_vehs.push( std::make_pair( target_veh, target_loss ) ); float loss_amount = ( static_cast( amount ) * static_cast( target_loss ) ) / 100.0f; - add_msg_debug( "Visiting remote %p with %d power (loss %f, which is %d percent)", + add_msg_debug( debugmode::DF_VEHICLE, + "Visiting remote %p with %d power (loss %f, which is %d percent)", static_cast( target_veh ), amount, loss_amount, target_loss ); amount = action( target_veh, amount, static_cast( loss_amount ) ); - add_msg_debug( "After remote %p, %d power", static_cast( target_veh ), amount ); + add_msg_debug( debugmode::DF_VEHICLE, "After remote %p, %d power", + static_cast( target_veh ), amount ); if( amount < 1 ) { break; // No more charge to donate away. @@ -5122,7 +5130,7 @@ int vehicle::charge_battery( int amount, bool include_other_vehicles ) } auto charge_visitor = []( vehicle * veh, int amount, int lost ) { - add_msg_debug( "CH: %d", amount - lost ); + add_msg_debug( debugmode::DF_VEHICLE, "CH: %d", amount - lost ); return veh->charge_battery( amount - lost, false ); }; @@ -5159,7 +5167,7 @@ int vehicle::discharge_battery( int amount, bool recurse ) } auto discharge_visitor = []( vehicle * veh, int amount, int lost ) { - add_msg_debug( "CH: %d", amount + lost ); + add_msg_debug( debugmode::DF_VEHICLE, "CH: %d", amount + lost ); return veh->discharge_battery( amount + lost, false ); }; if( amount > 0 && recurse ) { // need more power! @@ -7049,7 +7057,7 @@ void vehicle::update_time( const time_point &update_to ) double intensity = accum_weather.sunlight / default_daylight_level() / to_turns( elapsed ); int energy_bat = power_to_energy_bat( epower_w * intensity, elapsed ); if( energy_bat > 0 ) { - add_msg_debug( "%s got %d kJ energy from solar panels", name, energy_bat ); + add_msg_debug( debugmode::DF_VEHICLE, "%s got %d kJ energy from solar panels", name, energy_bat ); charge_battery( energy_bat ); } } @@ -7059,7 +7067,7 @@ void vehicle::update_time( const time_point &update_to ) int epower_w = total_wind_epower_w(); int energy_bat = power_to_energy_bat( epower_w, elapsed ); if( energy_bat > 0 ) { - add_msg_debug( "%s got %d kJ energy from wind turbines", name, energy_bat ); + add_msg_debug( debugmode::DF_VEHICLE, "%s got %d kJ energy from wind turbines", name, energy_bat ); charge_battery( energy_bat ); } } @@ -7067,7 +7075,7 @@ void vehicle::update_time( const time_point &update_to ) int epower_w = total_water_wheel_epower_w(); int energy_bat = power_to_energy_bat( epower_w, elapsed ); if( energy_bat > 0 ) { - add_msg_debug( "%s got %d kJ energy from water wheels", name, energy_bat ); + add_msg_debug( debugmode::DF_VEHICLE, "%s got %d kJ energy from water wheels", name, energy_bat ); charge_battery( energy_bat ); } } diff --git a/src/vehicle_move.cpp b/src/vehicle_move.cpp index 26891fc625996..8ba870aa24d99 100644 --- a/src/vehicle_move.cpp +++ b/src/vehicle_move.cpp @@ -110,7 +110,8 @@ int vehicle::slowdown( int at_velocity ) const if( slowdown < 0 ) { debugmsg( "vehicle %s has negative drag slowdown %d\n", name, slowdown ); } - add_msg_debug( "%s at %d vimph, f_drag %3.2f, drag accel %d vmiph - extra drag %d", + add_msg_debug( debugmode::DF_VEHICLE_MOVE, + "%s at %d vimph, f_drag %3.2f, drag accel %d vmiph - extra drag %d", name, at_velocity, f_total_drag, slowdown, static_drag() ); // plows slow rolling vehicles, but not falling or floating vehicles if( !( is_falling || is_floating || is_flying ) ) { @@ -374,7 +375,7 @@ void vehicle::smart_controller_handle_turn( bool thrusting, smart_controller_state = cur_state; if( player_in_control( player_character ) ) { - add_msg_debug( _( "Smart controller optimizes engine state." ) ); + add_msg_debug( debugmode::DF_VEHICLE_MOVE, _( "Smart controller optimizes engine state." ) ); } } } else { @@ -744,7 +745,7 @@ bool vehicle::collision( std::vector &colls, colls.push_back( fake_coll ); velocity = 0; vertical_velocity = 0; - add_msg_debug( "Collision check on a dirty vehicle %s", name ); + add_msg_debug( debugmode::DF_VEHICLE_MOVE, "Collision check on a dirty vehicle %s", name ); return true; } @@ -971,7 +972,7 @@ veh_collision vehicle::part_collision( int part, const tripoint &p, continue; } - add_msg_debug( "Deformation energy: %.2f", d_E ); + add_msg_debug( debugmode::DF_VEHICLE_MOVE, "Deformation energy: %.2f", d_E ); // Damage calculation // Damage dealt overall dmg += d_E / 400; @@ -979,7 +980,7 @@ veh_collision vehicle::part_collision( int part, const tripoint &p, // Always if no critters, otherwise if critter is real if( critter == nullptr || !critter->is_hallucination() ) { part_dmg = dmg * k / 100.0f; - add_msg_debug( "Part collision damage: %.2f", part_dmg ); + add_msg_debug( debugmode::DF_VEHICLE_MOVE, "Part collision damage: %.2f", part_dmg ); } // Damage for object const float obj_dmg = dmg * ( 100.0f - k ) / 100.0f; @@ -1038,7 +1039,7 @@ veh_collision vehicle::part_collision( int part, const tripoint &p, critter->get_armor_bash( bodypart_id( "torso" ) ); dam = std::max( 0, dam - armor ); critter->apply_damage( driver, bodypart_id( "torso" ), dam ); - add_msg_debug( "Critter collision damage: %d", dam ); + add_msg_debug( debugmode::DF_VEHICLE_MOVE, "Critter collision damage: %d", dam ); } // Don't fling if vertical - critter got smashed into the ground diff --git a/tests/fake_messages.cpp b/tests/fake_messages.cpp index f38fd46c4ba49..1a5d41906a067 100644 --- a/tests/fake_messages.cpp +++ b/tests/fake_messages.cpp @@ -36,6 +36,11 @@ void Messages::add_msg( const game_message_params &, std::string m ) { add_msg( m ); } +void Messages::add_msg_debug( debugmode::debug_filter, std::string m ) +{ + // cata_test does not need filters + add_msg( m ); +} void Messages::clear_messages() { messages.clear(); @@ -62,6 +67,10 @@ void add_msg( const game_message_params &, std::string m ) { Messages::add_msg( m ); } +void add_msg_debug( debugmode::debug_filter, std::string m ) +{ + Messages::add_msg( m ); +} void add_msg_if_player_sees( const tripoint &, std::string m ) { Messages::add_msg( m ); @@ -78,3 +87,13 @@ void add_msg_if_player_sees( const Creature &, const game_message_params &, std: { Messages::add_msg( m ); } +void add_msg_debug_if_player_sees( const tripoint &, debugmode::debug_filter, + std::string m ) +{ + Messages::add_msg( m ); +} +void add_msg_debug_if_player_sees( const Creature &, debugmode::debug_filter, + std::string m ) +{ + Messages::add_msg( m ); +} From 464bfb287f3901e901aa3349f9d909911a0a403c Mon Sep 17 00:00:00 2001 From: Xenomorph-III Date: Thu, 25 Mar 2021 20:20:04 +1300 Subject: [PATCH 091/453] Give the sports drink positive enjoyment value (#47617) --- data/json/items/comestibles/drink.json | 11 ++++++----- tests/food_fun_for_test.cpp | 22 +++++++++++----------- 2 files changed, 17 insertions(+), 16 deletions(-) diff --git a/data/json/items/comestibles/drink.json b/data/json/items/comestibles/drink.json index cf5f49f876cf7..0a0bc595b8a42 100644 --- a/data/json/items/comestibles/drink.json +++ b/data/json/items/comestibles/drink.json @@ -949,14 +949,14 @@ "symbol": "~", "quench": 60, "calories": 66, - "description": "Consisting of a special blend of electrolytes and simple sugars, this beverage tastes like bottled sweat but rehydrates the body faster than water.", + "description": "A flavoured drink consisting of a special blend of electrolytes and simple sugars. It tastes vaguely like fruit with a slight chemical aftertaste.", "price": 55, "price_postapoc": 50, - "material": [ "water" ], + "material": [ "water", "junk" ], "volume": "250 ml", "phase": "liquid", "flags": [ "EATEN_COLD" ], - "fun": -1, + "fun": 1, "vitamins": [ [ "vitC", 1 ] ] }, { @@ -991,14 +991,15 @@ "symbol": "~", "quench": 60, "calories": 12, - "description": "A basic oral rehydration therapy drink. It will rehydrate you faster than water, but it tastes kind of strange.", + "description": "A basic oral rehydration therapy drink. It will rehydrate you faster than water, but tastes like bottled sweat.", "price": 55, "price_postapoc": 50, "material": [ "water" ], + "flags": [ "EATEN_COLD" ], "volume": "250 ml", "looks_like": "sports_drink", "phase": "liquid", - "fun": -2 + "fun": -1 }, { "type": "COMESTIBLE", diff --git a/tests/food_fun_for_test.cpp b/tests/food_fun_for_test.cpp index c1673a0a6ce8d..9a8b861cb8926 100644 --- a/tests/food_fun_for_test.cpp +++ b/tests/food_fun_for_test.cpp @@ -142,29 +142,29 @@ TEST_CASE( "fun for cold food", "[fun_for][food][cold]" ) } GIVEN( "food that tastes bad, but better when cold" ) { - item sports( "sports_drink" ); - REQUIRE( sports.is_comestible() ); - int sports_fun = sports.get_comestible_fun(); + item rehydration( "rehydration_drink" ); + REQUIRE( rehydration.is_comestible() ); + int rehydration_fun = rehydration.get_comestible_fun(); - REQUIRE( sports_fun < 0 ); - REQUIRE( sports.has_flag( flag_EATEN_COLD ) ); + REQUIRE( rehydration_fun < 0 ); + REQUIRE( rehydration.has_flag( flag_EATEN_COLD ) ); WHEN( "it is cold" ) { - sports.set_flag( flag_COLD ); - REQUIRE( sports.has_flag( flag_COLD ) ); + rehydration.set_flag( flag_COLD ); + REQUIRE( rehydration.has_flag( flag_COLD ) ); THEN( "it doesn't taste bad" ) { - actual_fun = dummy.fun_for( sports ); + actual_fun = dummy.fun_for( rehydration ); CHECK( actual_fun.first > 0 ); } } WHEN( "it is not cold" ) { - REQUIRE_FALSE( sports.has_flag( flag_COLD ) ); + REQUIRE_FALSE( rehydration.has_flag( flag_COLD ) ); THEN( "it tastes as bad as usual" ) { - actual_fun = dummy.fun_for( sports ); - CHECK( actual_fun.first == sports_fun ); + actual_fun = dummy.fun_for( rehydration ); + CHECK( actual_fun.first == rehydration_fun ); } } } From fd0e789f7efdcc357e5f1ab54bc506120e3a813c Mon Sep 17 00:00:00 2001 From: Jamuro-g <76928284+Jamuro-g@users.noreply.github.com> Date: Thu, 25 Mar 2021 08:20:37 +0100 Subject: [PATCH 092/453] fix color coding of container stat summary (#47409) --- src/item.cpp | 14 ++++++++++---- src/item.h | 4 ++-- src/item_contents.cpp | 6 +++--- src/item_pocket.cpp | 6 +++--- 4 files changed, 18 insertions(+), 12 deletions(-) diff --git a/src/item.cpp b/src/item.cpp index 9f22033300038..5afc41861156a 100644 --- a/src/item.cpp +++ b/src/item.cpp @@ -9152,9 +9152,12 @@ iteminfo::iteminfo( const std::string &Type, const std::string &Name, double Val } iteminfo vol_to_info( const std::string &type, const std::string &left, - const units::volume &vol, int decimal_places ) + const units::volume &vol, int decimal_places, bool lower_is_better ) { - iteminfo::flags f = iteminfo::lower_is_better | iteminfo::no_newline; + iteminfo::flags f = iteminfo::no_newline; + if( lower_is_better ) { + f |= iteminfo::lower_is_better; + } int converted_volume_scale = 0; const double converted_volume = round_up( convert_volume( vol.value(), &converted_volume_scale ), decimal_places ); @@ -9166,9 +9169,12 @@ iteminfo vol_to_info( const std::string &type, const std::string &left, } iteminfo weight_to_info( const std::string &type, const std::string &left, - const units::mass &weight, int /* decimal_places */ ) + const units::mass &weight, int /* decimal_places */, bool lower_is_better ) { - iteminfo::flags f = iteminfo::lower_is_better | iteminfo::no_newline; + iteminfo::flags f = iteminfo::no_newline; + if( lower_is_better ) { + f |= iteminfo::lower_is_better; + } const double converted_weight = convert_weight( weight ); f |= iteminfo::is_decimal; return iteminfo( type, left, string_format( " %s", weight_units() ), f, diff --git a/src/item.h b/src/item.h index b0860f2b93334..368995927189b 100644 --- a/src/item.h +++ b/src/item.h @@ -166,9 +166,9 @@ struct enum_traits { }; iteminfo vol_to_info( const std::string &type, const std::string &left, - const units::volume &vol, int decimal_places = 2 ); + const units::volume &vol, int decimal_places = 2, bool lower_is_better = true ); iteminfo weight_to_info( const std::string &type, const std::string &left, - const units::mass &weight, int decimal_places = 2 ); + const units::mass &weight, int decimal_places = 2, bool lower_is_better = true ); inline bool is_crafting_component( const item &component ); diff --git a/src/item_contents.cpp b/src/item_contents.cpp index e9b93f6fae5ca..23cd9a86aac0c 100644 --- a/src/item_contents.cpp +++ b/src/item_contents.cpp @@ -1581,9 +1581,9 @@ void item_contents::info( std::vector &info, const iteminfo_query *par if( found_pockets.size() > 1 || pocket_num[0] > 1 ) { insert_separation_line( info ); info.emplace_back( "CONTAINER", _( "Total capacity:" ) ); - info.push_back( vol_to_info( "CONTAINER", _( "Volume: " ), total_container_capacity() ) ); - info.push_back( weight_to_info( "CONTAINER", _( " Weight: " ), - total_container_weight_capacity() ) ); + info.push_back( vol_to_info( "CONTAINER", _( "Volume: " ), total_container_capacity(), 2, false ) ); + info.push_back( weight_to_info( "CONTAINER", _( " Weight: " ), total_container_weight_capacity(), + 2, false ) ); info.back().bNewLine = true; } diff --git a/src/item_pocket.cpp b/src/item_pocket.cpp index 2ac13bc398231..e24dcdf436702 100644 --- a/src/item_pocket.cpp +++ b/src/item_pocket.cpp @@ -836,8 +836,8 @@ void item_pocket::general_info( std::vector &info, int pocket_number, // Show volume/weight for normal containers, or ammo capacity if ammo_restriction is defined if( data->ammo_restriction.empty() ) { - info.push_back( vol_to_info( "CONTAINER", _( "Volume: " ), volume_capacity() ) ); - info.push_back( weight_to_info( "CONTAINER", _( " Weight: " ), weight_capacity() ) ); + info.push_back( vol_to_info( "CONTAINER", _( "Volume: " ), volume_capacity(), 2, false ) ); + info.push_back( weight_to_info( "CONTAINER", _( " Weight: " ), weight_capacity(), 2, false ) ); info.back().bNewLine = true; } else { for( const ammotype &at : ammo_types() ) { @@ -853,7 +853,7 @@ void item_pocket::general_info( std::vector &info, int pocket_number, info.back().bNewLine = true; info.push_back( iteminfo( "BASE", _( "Maximum item length: " ), string_format( " %s", length_units( data->max_item_length ) ), - iteminfo::lower_is_better, + iteminfo::no_flags, convert_length( data->max_item_length ) ) ); } From 905b51afe2a8967d5c2cad99ef5ddb7ad1ca94d4 Mon Sep 17 00:00:00 2001 From: Jamuro-g <76928284+Jamuro-g@users.noreply.github.com> Date: Thu, 25 Mar 2021 08:21:39 +0100 Subject: [PATCH 093/453] fixed power armor ui (#47475) --- data/mods/TEST_DATA/items.json | 15 ++ src/item.cpp | 242 +++++++++++++++++++-------------- src/item.h | 2 + tests/iteminfo_test.cpp | 5 +- 4 files changed, 157 insertions(+), 107 deletions(-) diff --git a/data/mods/TEST_DATA/items.json b/data/mods/TEST_DATA/items.json index 9e5e5c6b47de8..7e21a5bbb649c 100644 --- a/data/mods/TEST_DATA/items.json +++ b/data/mods/TEST_DATA/items.json @@ -1448,8 +1448,23 @@ "power_armor": true, "material_thickness": 14, "environmental_protection": 16, + "use_action": { "type": "transform", "msg": "The %s engages.", "target": "test_power_armor_on", "active": true }, "flags": [ "WATERPROOF", "STURDY", "ELECTRIC_IMMUNE" ] }, + { + "id": "test_power_armor_on", + "copy-from": "test_power_armor", + "repairs_like": "test_power_armor", + "looks_like": "test_power_armor", + "type": "TOOL_ARMOR", + "name": { "str": "test power armor (on)" }, + "description": "This is a prototype power armor just for testing.", + "flags": [ "USE_UPS", "WATERPROOF", "STURDY", "ELECTRIC_IMMUNE", "TRADER_AVOID", "CLIMATE_CONTROL" ], + "power_draw": 4000000, + "revert_to": "test_power_armor", + "use_action": { "type": "transform", "menu_text": "Turn off", "msg": "The %s armor disengages.", "target": "test_power_armor" }, + "covers": [ "torso", "arm_l", "arm_r", "hand_l", "hand_r", "leg_l", "leg_r", "foot_l", "foot_r" ] + }, { "id": "test_meower_armor", "type": "PET_ARMOR", diff --git a/src/item.cpp b/src/item.cpp index 5afc41861156a..bf408b1787282 100644 --- a/src/item.cpp +++ b/src/item.cpp @@ -2646,6 +2646,119 @@ void item::gunmod_info( std::vector &info, const iteminfo_query *parts } } +void item::armor_encumbrance_info( std::vector &info, int reduce_encumbrance_by ) const +{ + std::string format; + const std::string space = " "; + Character &player_character = get_player_character(); + const bool sizing_matters = get_sizing( player_character ) != sizing::ignore; + + if( has_flag( flag_FIT ) ) { + format = _( " (fits)" ); + } else if( has_flag( flag_VARSIZE ) && sizing_matters ) { + format = _( " (poor fit)" ); + } + if( sizing_matters ) { + const sizing sizing_level = get_sizing( player_character ); + //If we have the wrong size, we do not fit so alert the player + if( sizing_level == sizing::human_sized_small_char ) { + format = _( " (too big)" ); + } else if( sizing_level == sizing::big_sized_small_char ) { + format = _( " (huge!)" ); + } else if( sizing_level == sizing::small_sized_human_char || + sizing_level == sizing::human_sized_big_char ) { + format = _( " (too small)" ); + } else if( sizing_level == sizing::small_sized_big_char ) { + format = _( " (tiny!)" ); + } + } + + info.push_back( iteminfo( "ARMOR", _( "Encumbrance:" ) + format ) ); + + if( const islot_armor *t = find_armor_data() ) { + if( !t->data.empty() ) { + struct armor_portion_type { + int encumber = 0; + int max_encumber = 0; + int coverage = 0; + + bool operator==( const armor_portion_type &other ) { + return encumber == other.encumber + && max_encumber == other.max_encumber + && coverage == other.coverage; + } + }; + struct body_part_display_info { + translation to_display; + armor_portion_type portion; + bool active = false; + }; + + std::map to_display_data; + + for( const armor_portion_data &piece : t->data ) { + if( piece.covers.has_value() ) { + for( const bodypart_str_id &covering_id : piece.covers.value() ) { + if( covering_id != bodypart_str_id::NULL_ID() ) { + to_display_data[covering_id] = { covering_id.obj().name_as_heading, { + std::max( 0, get_encumber( player_character, covering_id ) - reduce_encumbrance_by ), + std::max( 0, get_encumber( player_character, covering_id, encumber_flags::assume_full ) - reduce_encumbrance_by ), + piece.coverage + }, true + }; + } + } + } + } + // Handle things that use both sides to avoid showing L. Arm R. Arm etc when both are the same + if( !t->sided ) { + for( const armor_portion_data &piece : t->data ) { + for( const bodypart_str_id &bp : *piece.covers ) { + bodypart_str_id opposite = bp->opposite_part; + if( opposite != bp && covers( bp ) && covers( opposite ) + && to_display_data.at( bp ).portion == to_display_data.at( opposite ).portion + && to_display_data.at( opposite ).active ) { + to_display_data.at( opposite ).to_display = bp->name_as_heading_multiple; + to_display_data.at( bp ).active = false; + } + } + } + } + for( auto &piece : to_display_data ) { + if( t->sided ) { + const bodypart_str_id &covering_id = piece.first; + if( !covers( covering_id.id() ) ) { + continue; + } + } + if( piece.second.active ) { + info.push_back( iteminfo( "ARMOR", + string_format( _( "%s:" ), piece.second.to_display.translated() ) + space, "", + iteminfo::no_newline | iteminfo::lower_is_better, + piece.second.portion.encumber ) ); + + if( piece.second.portion.encumber != piece.second.portion.max_encumber ) { + info.push_back( iteminfo( "ARMOR", space + _( "When full:" ) + space, "", + iteminfo::no_newline | iteminfo::lower_is_better, + piece.second.portion.max_encumber ) ); + } + + info.push_back( iteminfo( "ARMOR", space + _( "Coverage:" ) + space, "", + iteminfo::no_flags, + piece.second.portion.coverage ) ); + } + } + } + } else if( is_gun() && has_flag( flag_IS_ARMOR ) ) { + //right now all eligible gunmods (shoulder_strap, belt_clip) have the is_armor flag and use the torso + info.push_back( iteminfo( "ARMOR", _( "Torso:" ) + space, "", + iteminfo::no_newline | iteminfo::lower_is_better, get_avg_encumber( get_avatar() ) ) ); + + info.push_back( iteminfo( "ARMOR", space + _( "Coverage:" ) + space, "", + iteminfo::no_flags, get_coverage( body_part_torso.id() ) ) ); + } +} + void item::armor_protection_info( std::vector &info, const iteminfo_query *parts, int /*batch*/, bool /*debug*/ ) const @@ -2697,7 +2810,6 @@ void item::armor_info( std::vector &info, const iteminfo_query *parts, return; } - Character &player_character = get_player_character(); const std::string space = " "; body_part_set covered_parts = get_covered_body_parts(); bool covers_anything = covered_parts.any(); @@ -2796,122 +2908,44 @@ void item::armor_info( std::vector &info, const iteminfo_query *parts, insert_separation_line( info ); - if( parts->test( iteminfo_parts::ARMOR_ENCUMBRANCE ) && covers_anything ) { - std::string format; - const bool sizing_matters = get_sizing( player_character ) != sizing::ignore; - if( has_flag( flag_FIT ) ) { - format = _( " (fits)" ); - } else if( has_flag( flag_VARSIZE ) && sizing_matters ) { - format = _( " (poor fit)" ); - } - if( sizing_matters ) { - const sizing sizing_level = get_sizing( player_character ); - //If we have the wrong size, we do not fit so alert the player - if( sizing_level == sizing::human_sized_small_char ) { - format = _( " (too big)" ); - } else if( sizing_level == sizing::big_sized_small_char ) { - format = _( " (huge!)" ); - } else if( sizing_level == sizing::small_sized_human_char || - sizing_level == sizing::human_sized_big_char ) { - format = _( " (too small)" ); - } else if( sizing_level == sizing::small_sized_big_char ) { - format = _( " (tiny!)" ); - } - } - - info.push_back( iteminfo( "ARMOR", _( "Encumbrance:" ) + format ) ); - - if( const islot_armor *t = find_armor_data() ) { - if( !t->data.empty() ) { - struct armor_portion_type { - int encumber = 0; - int max_encumber = 0; - int coverage = 0; - - bool operator==( const armor_portion_type &other ) { - return encumber == other.encumber - && max_encumber == other.max_encumber - && coverage == other.coverage; - } - }; - struct body_part_display_info { - translation to_display; - armor_portion_type portion; - bool active = false; - }; + if( covers_anything ) { + int power_armor_encumbrance_reduction = 40; + static const itype_id itype_rm13_armor( "rm13_armor" ); - std::map to_display_data; + if( ( is_power_armor() ) || type->get_id() == itype_rm13_armor ) { + item tmp = *this; - for( const armor_portion_data &piece : t->data ) { - if( piece.covers.has_value() ) { - for( const bodypart_str_id &covering_id : piece.covers.value() ) { - if( covering_id != bodypart_str_id::NULL_ID() ) { - to_display_data[covering_id] = { covering_id.obj().name_as_heading, { - get_encumber( player_character, covering_id ), - get_encumber( player_character, covering_id, encumber_flags::assume_full ), - piece.coverage - }, true - }; - } - } - } - } - // Handle things that use both sides to avoid showing L. Arm R. Arm etc when both are the same - if( !t->sided ) { - for( const armor_portion_data &piece : t->data ) { - for( const bodypart_str_id &bp : *piece.covers ) { - bodypart_str_id opposite = bp->opposite_part; - if( opposite != bp && covers( bp ) && covers( opposite ) - && to_display_data.at( bp ).portion == to_display_data.at( opposite ).portion - && to_display_data.at( opposite ).active ) { - to_display_data.at( opposite ).to_display = bp->name_as_heading_multiple; - to_display_data.at( bp ).active = false; - } - } - } + //no need to clutter the ui with inactive versions when the armor is already active + if( !active ) { + if( parts->test( iteminfo_parts::ARMOR_ENCUMBRANCE ) ) { + tmp.armor_encumbrance_info( info ); } - for( auto &piece : to_display_data ) { - if( t->sided ) { - const bodypart_str_id &covering_id = piece.first; - if( !covers( covering_id.id() ) ) { - continue; - } - } - if( piece.second.active ) { - info.push_back( iteminfo( "ARMOR", - string_format( _( "%s:" ), piece.second.to_display.translated() ) + space, "", - iteminfo::no_newline | iteminfo::lower_is_better, - piece.second.portion.encumber ) ); + tmp.armor_protection_info( info, parts, batch, debug ); - if( piece.second.portion.encumber != piece.second.portion.max_encumber ) { - info.push_back( iteminfo( "ARMOR", space + _( "When full:" ) + space, "", - iteminfo::no_newline | iteminfo::lower_is_better, - piece.second.portion.max_encumber ) ); - } + insert_separation_line( info ); + info.push_back( iteminfo( "ARMOR", _( "When active:" ) ) ); + tmp = tmp.convert( itype_id( tmp.typeId().str() + "_on" ) ); + } - info.push_back( iteminfo( "ARMOR", space + _( "Coverage:" ) + space, "", - iteminfo::no_flags, - piece.second.portion.coverage ) ); - } + if( parts->test( iteminfo_parts::ARMOR_ENCUMBRANCE ) ) { + if( type->get_id() == itype_rm13_armor ) { + tmp.armor_encumbrance_info( info ); + } else { + tmp.armor_encumbrance_info( info, power_armor_encumbrance_reduction ); } } - } else if( is_gun() && has_flag( flag_IS_ARMOR ) ) { - //right now all eligible gunmods (shoulder_strap, belt_clip) have the is_armor flag and use the torso - info.push_back( iteminfo( "ARMOR", _( "Torso:" ) + space, "", - iteminfo::no_newline | iteminfo::lower_is_better, get_avg_encumber( get_avatar() ) ) ); - - info.push_back( iteminfo( "ARMOR", space + _( "Coverage:" ) + space, "", - iteminfo::no_flags, get_coverage( body_part_torso.id() ) ) ); + tmp.armor_protection_info( info, parts, batch, debug ); + } else { + if( parts->test( iteminfo_parts::ARMOR_ENCUMBRANCE ) ) { + armor_encumbrance_info( info ); + } + armor_protection_info( info, parts, batch, debug ); } } // Whatever the last entry was, we want a newline at this point info.back().bNewLine = true; - if( covers_anything ) { - armor_protection_info( info, parts, batch, debug ); - } - const units::mass weight_bonus = get_weight_capacity_bonus(); const float weight_modif = get_weight_capacity_modifier(); if( weight_modif != 1 ) { diff --git a/src/item.h b/src/item.h index 368995927189b..f62a7a438f94d 100644 --- a/src/item.h +++ b/src/item.h @@ -2250,6 +2250,8 @@ class item : public visitable /** Helper for checking reloadability. **/ bool is_reloadable_helper( const itype_id &ammo, bool now ) const; + void armor_encumbrance_info( std::vector &info, int reduce_encumbrance_by = 0 ) const; + public: enum class sizing : int { human_sized_human_char = 0, diff --git a/tests/iteminfo_test.cpp b/tests/iteminfo_test.cpp index 1b0bdbfceb82d..719871ce735a0 100644 --- a/tests/iteminfo_test.cpp +++ b/tests/iteminfo_test.cpp @@ -1041,9 +1041,8 @@ TEST_CASE( "armor fit and sizing", "[iteminfo][armor][fit]" ) "* This item can be worn on either side of the body.\n" ); item power_armor( "test_power_armor" ); - CHECK( item_info_str( power_armor, powerarmor ) == - "--\n" - "* This gear is a part of power armor.\n" ); + CHECK_THAT( item_info_str( power_armor, powerarmor ), + Catch::EndsWith( "* This gear is a part of power armor.\n" ) ); } static void expected_armor_values( const item &armor, float bash, float cut, float stab, From 88fea20d1d668bb8b8ae40b37b5adf132c903d92 Mon Sep 17 00:00:00 2001 From: anothersimulacrum Date: Thu, 25 Mar 2021 00:23:40 -0700 Subject: [PATCH 094/453] Add gun variants, allowing to specify multiple guns with the same stat block (#46814) * Add gun variant support This allows genericizing our massive variety of very similar guns into one statblock, without removing the flavor. If a gun or magazine is specified to spawn without a variant, it will pick from the variants available to it, based on their assigned weight. Gun variants can specify an alternate name, description and ascii art for a gun, and variants can be toggled through an option. Add support for migrations to express variants. Add explicit extraction for magazines to handle variants. ASCII art for a variant will fall back to that of the base gun automatically if not specified or invalid. Maybe the naming could better express these are for both guns and magazines, but I think it is fine as is. item::gun_variant makes the assumption you check it has a variant first, so make sure to do that. Move the ammo at the end of gun names option to be next to the gun variant option. item::is_magazine doesn't tell us if type->magazine is safe to use, so !!type->magazine must be used instead of that before accessing type->magazine. * Add hacks to Archive::io to load/save gun variants I couldn't figure out how to specify the lambdas correctly, so I give up, this works. Problem is as follows: In item, I have ``` const gun_variant_data *_gun_variant; ... struct gun_variant_data { std::string id; // other info that doesn't matter } ``` I want to save this as `_gun_variant->id;`, and on load, load the string that was saved and call `item::set_gun_variant(loaded_string);`. This, and many variations of it don't work. ``` // In item:: scope const auto load = [this](const std::string &variant) { set_gun_variant( variant ); }; const auto save = [](const gun_variant_data *gv) { return gv->id; }; ``` Someone who know what's they're doing here may want to fix my laziness. * Add spawning support for gun variants Allow specifying variatns in item groups, mapgen (Item_group::add_item_entry), and in vehicles. * Add documentation for gun variants * Genericize NATO assault rifles Information lost: acr - 250ml barrel volume, folding stock m38dmr - 125 dispersion Move everything using an old rifle into the new generic rifles. The m38dmr is debatable, but I figure it's fine to be generic. Only m4a1s will spawn from unspecified variants at the moment, someone else can figure out what the proper chances should be. * Genericize other 5.56 assault rifles These ones are unique enough to not be simple variants of the NATO assault rifle, but they also don't need a full enumeration of stats. Move the brand-specific information to be a variant, genericize name and descriptions, and make all non-unique stats identical to those of the NATO assault rifle. I'm not sure of a good name for the sig generic version, but I want it to be distinct from the AUTO only or BURST only NATO rifles. * Genericize .45 ACP firearms There may be some consideration needed on collapsing the stat blocks for the pistols/smgs into a single one with copy-from, but this is simply the highest level genericization changes. --- .../monster_drops_lairs.json | 4 +- .../itemgroups/Weapons_Mods_Ammo/gunmod.json | 14 + .../itemgroups/Weapons_Mods_Ammo/guns.json | 27 +- data/json/itemgroups/defense_mode.json | 2 +- data/json/itemgroups/military.json | 32 +- data/json/items/gun/223.json | 425 ++++-------------- data/json/items/gun/308.json | 2 +- data/json/items/gun/45.json | 152 +++++-- data/json/items/magazine/45.json | 60 ++- data/json/items/migration.json | 64 ++- .../mapgen/military/mil_base/mil_base_z0.json | 30 +- data/json/martialarts.json | 11 +- data/json/npcs/NC_ARSONIST.json | 6 +- data/json/npcs/NC_SOLDIER.json | 4 +- .../NPC_scavenger_mercenary.json | 8 +- .../json/npcs/robofac/NPC_ROBOFAC_MERC_1.json | 8 +- data/json/professions.json | 34 +- data/json/recipes/recipe_deconstruction.json | 2 +- data/json/recipes/weapon/magazines.json | 13 +- data/json/recipes/weapon/mods.json | 4 +- data/json/vehicles/helicopters.json | 12 +- .../vehicleparts/blaze_turrets_vanilla.json | 44 +- .../Fuji_Mil_Prof/prof/itemgroups_prof.json | 2 +- .../firearms/gg_firearms_migration.json | 12 +- .../mods/National_Guard_Camp/item_groups.json | 8 +- .../bionic_professions.json | 3 +- doc/ITEM_SPAWN.md | 3 + doc/JSON_INFO.md | 9 + doc/MAPGEN.md | 1 + doc/VEHICLES_JSON.md | 2 + lang/extract_json_strings.py | 27 +- src/cata_io.h | 35 ++ src/item.cpp | 84 +++- src/item.h | 29 ++ src/item_factory.cpp | 25 ++ src/item_factory.h | 1 + src/item_group.cpp | 14 +- src/item_group.h | 8 +- src/itype.h | 14 + src/map.cpp | 7 +- src/map.h | 16 +- src/mapgen.cpp | 12 +- src/options.cpp | 14 +- src/savegame_json.cpp | 7 + src/veh_type.cpp | 8 +- src/veh_type.h | 2 + src/vehicle.cpp | 9 +- src/wish.cpp | 5 +- tests/pocket_test.cpp | 2 +- tests/reload_magazine_test.cpp | 2 +- 50 files changed, 781 insertions(+), 538 deletions(-) diff --git a/data/json/itemgroups/Monsters_Animals_Lairs/monster_drops_lairs.json b/data/json/itemgroups/Monsters_Animals_Lairs/monster_drops_lairs.json index b125fcf754d97..51ffb7422cfda 100644 --- a/data/json/itemgroups/Monsters_Animals_Lairs/monster_drops_lairs.json +++ b/data/json/itemgroups/Monsters_Animals_Lairs/monster_drops_lairs.json @@ -217,9 +217,9 @@ { "item": "savage_111f", "prob": 10 }, { "item": "ak47", "prob": 16 }, { "item": "ak74", "prob": 4 }, - { "item": "m4a1", "prob": 7 }, + { "item": "nato_assault_rifle", "variant": "m4a1", "prob": 7 }, { "item": "m16a4", "prob": 6 }, - { "item": "h&k416a5", "prob": 3 }, + { "item": "nato_assault_rifle", "variant": "h&k416a5", "prob": 3 }, { "item": "m1014", "prob": 1 }, { "item": "steyr_aug", "prob": 6 }, { "item": "v29", "prob": 1 }, diff --git a/data/json/itemgroups/Weapons_Mods_Ammo/gunmod.json b/data/json/itemgroups/Weapons_Mods_Ammo/gunmod.json index c52235ca4c2a5..d482cabfba4b0 100644 --- a/data/json/itemgroups/Weapons_Mods_Ammo/gunmod.json +++ b/data/json/itemgroups/Weapons_Mods_Ammo/gunmod.json @@ -123,6 +123,13 @@ [ "offset_sights", 6 ] ] }, + { + "type": "item_group", + "id": "m38dmr_mods", + "//": "Default mods for the m38dmr variant of the NATO assault rifle", + "subtype": "collection", + "entries": [ { "item": "suppressor" }, { "item": "rifle_scope" }, { "item": "bipod" } ] + }, { "type": "item_group", "id": "sights_shotgun_readied", @@ -137,6 +144,13 @@ "//": "For shotguns that haven't been 'made ready', e.g sitting in a store or garage.", "entries": [ { "group": "sights_shotgun", "prob": 20 }, { "group": "EMPTY_GROUP", "prob": 80 } ] }, + { + "type": "item_group", + "id": "mk23_mods", + "//": "Default mods for the mk23 variant of the USP .45 pistol", + "subtype": "collection", + "entries": [ { "item": "suppressor" }, { "item": "laser_sight" } ] + }, { "type": "item_group", "id": "sights_launcher", diff --git a/data/json/itemgroups/Weapons_Mods_Ammo/guns.json b/data/json/itemgroups/Weapons_Mods_Ammo/guns.json index 55ae85cb79f4d..59485c1ab21fa 100644 --- a/data/json/itemgroups/Weapons_Mods_Ammo/guns.json +++ b/data/json/itemgroups/Weapons_Mods_Ammo/guns.json @@ -145,9 +145,16 @@ "items": [ { "item": "m17", "prob": 100, "charges-min": 0, "charges-max": 17 }, { "item": "glock_18c", "prob": 70, "charges-min": 0, "charges-max": 17 }, - { "item": "mk23", "prob": 10, "charges-min": 0, "charges-max": 12 }, + { + "item": "usp_45", + "variant": "mk23", + "contents-group": "mk23_mods", + "prob": 10, + "charges-min": 0, + "charges-max": 12 + }, { "item": "usp_45", "prob": 15, "charges-min": 0, "charges-max": 12 }, - { "item": "m1911_MEU", "prob": 5, "charges-min": 0, "charges-max": 7 }, + { "item": "m1911", "variant": "m1911_MEU", "prob": 5, "charges-min": 0, "charges-max": 7 }, { "item": "glock_19", "prob": 20, "charges-min": 0, "charges-max": 15 }, { "item": "needlepistol", "prob": 45, "charges-min": 0, "charges-max": 50 }, { "item": "rm103a_pistol", "prob": 35, "charges-min": 0, "charges-max": 10 } @@ -350,7 +357,7 @@ "id": "guns_rifle_rare", "//": "Less common rifles including those only used by police/paramilitary forces.", "items": [ - { "item": "acr", "prob": 25, "charges-min": 0, "charges-max": 30 }, + { "item": "nato_assault_rifle", "variant": "acr", "prob": 25, "charges-min": 0, "charges-max": 30 }, { "item": "colt_lightning", "prob": 15, "charges-min": 0, "charges-max": 10 }, { "item": "fn_fal", "prob": 40, "charges-min": 0, "charges-max": 20 }, { "item": "fs2000", "prob": 6, "charges-min": 0, "charges-max": 30 }, @@ -360,7 +367,7 @@ { "item": "henry_big_boy", "prob": 10, "charges-min": 0, "charges-max": 10 }, { "item": "m14ebr", "prob": 15, "charges-min": 0, "charges-max": 20 }, { "item": "M24", "prob": 15, "charges-min": 0, "charges-max": 5 }, - { "item": "m4a1", "prob": 45, "charges-min": 0, "charges-max": 30 }, + { "item": "nato_assault_rifle", "variant": "m4a1", "prob": 45, "charges-min": 0, "charges-max": 30 }, { "item": "m1903", "prob": 15, "charges-min": 0, "charges-max": 5 }, { "item": "m1918", "prob": 30, "charges-min": 0, "charges-max": 20 }, { "item": "mosin44_ebr", "prob": 10, "charges-min": 0, "charges-max": 5 }, @@ -379,7 +386,7 @@ "id": "guns_rifle_rare_display", "//": "Less common rifles found exclusively in gun stores.", "items": [ - { "item": "acr", "prob": 25, "charges-min": 0, "charges-max": 0 }, + { "item": "nato_assault_rifle", "variant": "acr", "prob": 25, "charges-min": 0, "charges-max": 0 }, { "item": "colt_lightning", "prob": 15, "charges-min": 0, "charges-max": 0 }, { "item": "fn_fal", "prob": 40, "charges-min": 0, "charges-max": 0 }, { "item": "m249_semi", "prob": 5, "charges-min": 0, "charges-max": 0 }, @@ -388,7 +395,7 @@ { "item": "henry_big_boy", "prob": 10, "charges-min": 0, "charges-max": 0 }, { "item": "m14ebr", "prob": 15, "charges-min": 0, "charges-max": 0 }, { "item": "M24", "prob": 15, "charges-min": 0, "charges-max": 0 }, - { "item": "m4a1", "prob": 45, "charges-min": 0, "charges-max": 0 }, + { "item": "nato_assault_rifle", "variant": "m4a1", "prob": 45, "charges-min": 0, "charges-max": 0 }, { "item": "m1903", "prob": 15, "charges-min": 0, "charges-max": 0 }, { "item": "m1918", "prob": 30, "charges-min": 0, "charges-max": 0 }, { "item": "mosin44_ebr", "prob": 10, "charges-min": 0, "charges-max": 0 }, @@ -407,7 +414,7 @@ "id": "guns_rifle_milspec", "//": "Military specification rifles only ever found at military sites.", "items": [ - { "item": "h&k416a5", "prob": 50, "charges-min": 0, "charges-max": 30 }, + { "item": "nato_assault_rifle", "variant": "h&k416a5", "prob": 50, "charges-min": 0, "charges-max": 30 }, { "item": "m107a1", "prob": 30, "charges-min": 0, "charges-max": 10 }, { "item": "m134", "prob": 10, "charges-min": 0, "charges-max": 100 }, { "item": "m14ebr", "prob": 10, "charges-min": 0, "charges-max": 20 }, @@ -415,7 +422,7 @@ { "item": "m2010", "prob": 20, "charges-min": 0, "charges-max": 5 }, { "item": "m240", "prob": 15, "charges-min": 0, "charges-max": 100 }, { "item": "m249", "prob": 25, "charges-min": 0, "charges-max": 10 }, - { "item": "m27iar", "prob": 50, "charges-min": 0, "charges-max": 30 }, + { "item": "nato_assault_rifle", "variant": "m27iar", "prob": 50, "charges-min": 0, "charges-max": 30 }, { "item": "m60", "prob": 15, "charges-min": 0, "charges-max": 100 }, { "item": "rm11b_sniper_rifle", "prob": 15, "charges-min": 0, "charges-max": 10 }, { "item": "rm298", "prob": 10, "charges-min": 0, "charges-max": 100 }, @@ -423,7 +430,7 @@ { "item": "rm614_lmg", "prob": 10, "charges-min": 0, "charges-max": 100 }, { "item": "rm88_battle_rifle", "prob": 25, "charges-min": 0, "charges-max": 50 }, { "item": "sig552", "prob": 100, "charges-min": 0, "charges-max": 30 }, - { "item": "scar_l", "prob": 50, "charges-min": 0, "charges-max": 30 }, + { "item": "nato_assault_rifle", "variant": "scar_l", "prob": 50, "charges-min": 0, "charges-max": 30 }, { "item": "scar_h", "prob": 50, "charges-min": 0, "charges-max": 20 }, { "item": "m110a1", "prob": 50, "charges-min": 0, "charges-max": 20 }, { "item": "acr_300blk", "prob": 15, "charges-min": 0, "charges-max": 30 } @@ -785,7 +792,7 @@ { "item": "hk_mp5k", "prob": 10, "charges-min": 0, "charges-max": 30 }, { "item": "hk_mp5sd", "prob": 5, "charges-min": 0, "charges-max": 30 }, { "item": "m1014", "prob": 10, "charges-min": 0, "charges-max": 8 }, - { "item": "m4a1", "prob": 35, "charges-min": 0, "charges-max": 30 }, + { "item": "nato_assault_rifle", "variant": "m4a1", "prob": 35, "charges-min": 0, "charges-max": 30 }, { "item": "as50", "prob": 5, "charges-min": 0, "charges-max": 10 }, { "item": "hk417_13", "prob": 30, "charges-min": 0, "charges-max": 20 } ] diff --git a/data/json/itemgroups/defense_mode.json b/data/json/itemgroups/defense_mode.json index db399a263863f..08ebc50f2080d 100644 --- a/data/json/itemgroups/defense_mode.json +++ b/data/json/itemgroups/defense_mode.json @@ -35,7 +35,7 @@ { "item": "remington_870" }, { "item": "browning_blr" }, { "item": "ak47" }, - { "item": "m4a1" }, + { "item": "nato_assault_rifle", "variant": "m4a1" }, { "item": "savage_111f" }, { "item": "hk_g3" }, { "item": "hk_g80" }, diff --git a/data/json/itemgroups/military.json b/data/json/itemgroups/military.json index e30aa57f053ec..fff33a56cdce2 100644 --- a/data/json/itemgroups/military.json +++ b/data/json/itemgroups/military.json @@ -4,9 +4,15 @@ "id": "military_standard_assault_rifles", "subtype": "distribution", "entries": [ - { "item": "m4a1", "prob": 88, "charges": [ 0, 30 ] }, - { "item": "m27iar", "prob": 10, "charges": [ 0, 30 ] }, - { "item": "m38dmr", "prob": 1, "charges": [ 0, 30 ] }, + { "item": "nato_assault_rifle", "variant": "m4a1", "prob": 88, "charges": [ 0, 30 ] }, + { "item": "nato_assault_rifle", "variant": "m27iar", "prob": 10, "charges": [ 0, 30 ] }, + { + "item": "nato_assault_rifle", + "variant": "m38dmr", + "contents-group": "m38dmr_mods", + "prob": 1, + "charges": [ 0, 30 ] + }, { "item": "m16a4", "prob": 2, "charges": [ 0, 30 ] } ] }, @@ -38,7 +44,7 @@ { "item": "m17", "prob": 65, "charges": [ 0, 17 ] }, { "item": "m18", "prob": 30, "charges": [ 0, 17 ] }, { "item": "glock_19", "prob": 3, "charges": [ 0, 15 ] }, - { "item": "m1911_MEU", "prob": 2, "charges": [ 0, 7 ] } + { "item": "m1911", "variant": "m1911_MEU", "prob": 2, "charges": [ 0, 7 ] } ] }, { @@ -174,23 +180,23 @@ { "item": "20x66_flechette", "prob": 3 }, { "item": "m9", "prob": 6 }, { "item": "usp_45", "prob": 6 }, - { "item": "m4a1", "prob": 7 }, - { "item": "m4_cqbr", "prob": 1 }, + { "item": "nato_assault_rifle", "variant": "m4a1", "prob": 7 }, + { "item": "nato_assault_rifle", "variant": "m4_cqbr", "prob": 1 }, { "item": "m231pfw", "prob": 1 }, { "item": "m16a4", "prob": 5 }, - { "item": "m16a3", "prob": 1 }, + { "item": "nato_assault_rifle", "variant": "m16a3", "prob": 1 }, { "item": "colt_ro635", "prob": 1 }, { "item": "p226_9mm", "prob": 1 }, { "item": "sp2022", "prob": 1 }, - { "item": "h&k416a5", "prob": 7 }, + { "item": "nato_assault_rifle", "variant": "h&k416a5", "prob": 7 }, { "item": "m1014", "prob": 2 }, - { "item": "scar_l", "prob": 6 }, + { "item": "nato_assault_rifle", "variant": "scar_l", "prob": 6 }, { "item": "scar_h", "prob": 5 }, { "item": "sig_mcx_rattler_sbr", "prob": 1 }, { "item": "m249", "prob": 1 }, { "item": "m240", "prob": 1 }, - { "item": "m27iar", "prob": 1 }, - { "item": "m38dmr", "prob": 1 }, + { "item": "nato_assault_rifle", "variant": "m27iar", "prob": 1 }, + { "item": "nato_assault_rifle", "variant": "m38dmr", "contents-group": "m38dmr_mods", "prob": 1 }, { "item": "plasma_gun", "prob": 1 }, { "item": "m320", "prob": 5 }, { "item": "m320_mod", "prob": 10 }, @@ -376,8 +382,8 @@ { "item": "rm451_flamethrower", "prob": 10, "charges": [ 0, 2000 ] }, { "item": "m249", "prob": 30, "charges": [ 0, 30 ] }, { "item": "m240", "prob": 20, "charges": [ 0, 200 ] }, - { "item": "m27iar", "prob": 30, "charges": [ 0, 30 ] }, - { "item": "m38dmr", "prob": 3, "charges": [ 0, 30 ] }, + { "item": "nato_assault_rifle", "variant": "m27iar", "prob": 30, "charges": [ 0, 30 ] }, + { "item": "nato_assault_rifle", "variant": "m38dmr", "contents-group": "m38dmr_mods", "charges": [ 0, 30 ] }, { "item": "m2browning", "prob": 15, "charges": [ 0, 100 ] }, { "item": "mark19", "prob": 15, "charges": [ 0, 50 ] }, { "item": "556", "prob": 30, "charges": [ 1, 30 ] }, diff --git a/data/json/items/gun/223.json b/data/json/items/gun/223.json index b4ba9a5c2aa08..61f71f6f0ddc7 100644 --- a/data/json/items/gun/223.json +++ b/data/json/items/gun/223.json @@ -1,16 +1,63 @@ [ { - "id": "acr", + "id": "nato_assault_rifle", "copy-from": "rifle_auto", "looks_like": "ar15", "type": "GUN", - "name": { "str": "Remington ACR" }, - "description": "This carbine was developed for military use in the early 21st century. It is damaging and accurate, though its rate of fire is a bit slower than competing .223 carbines.", - "weight": "3719 g", + "name": { "str": "NATO assault rifle" }, + "description": "An assault rifle used by a NATO member state. As per NATO's STANAG agreement, it is chambered in 5.56x45mm.", + "//": "Weight, description, length modeled off of m4a1, price and gun stats average of some nato guns", + "weight": "2880g", "volume": "3310 ml", - "longest_side": "938 mm", - "price": 234300, - "price_postapoc": 6000, + "longest_side": "758 mm", + "price": "325 USD", + "price_postapoc": "48 USD", + "variants": [ + { + "id": "acr", + "name": { "str": "Remington ACR" }, + "description": "This carbine was developed for military use in the early 21st century. It is damaging and accurate, though its rate of fire is a bit slower than competing .223 carbines." + }, + { + "id": "h&k416a5", + "name": { "str": "HK416 A5" }, + "description": "Designed to replace the M4A1, the Heckler and Koch 416A5 features most of the former's strengths, while being considerably more durable." + }, + { + "id": "m27iar", + "name": { "str": "M27 IAR" }, + "description": "A H&K416 carbine outfitted with a heavier barrel to enable higher amounts of suppressive fire while retaining a good degree of mobility.", + "ascii_picture": "m27_iar" + }, + { + "id": "m4a1", + "name": { "str": "M4A1" }, + "description": "A popular carbine, long used by the US military. Though accurate, small, and lightweight, it is infamous for its unreliability when not properly maintained.", + "ascii_picture": "m4a1", + "weight": 1 + }, + { + "id": "m16a3", + "name": { "str": "M16A3" }, + "description": "The M16 is a very common assault rifle descended from the AR-15, used by militaries across the world for over 50 years. It is a gas operated, rotating bolt rifle known for its accuracy and controllable recoil. This one is a relatively rare M16A3, with full auto capability." + }, + { + "id": "scar_l", + "name": { "str": "FN SCAR-L" }, + "description": "A highly accurate and modular assault rifle specially designed for the United States Special Operations Command. The 'L' in its name stands for light, as it uses the lightweight .223 round.", + "ascii_picture": "scar-L" + }, + { + "id": "m38dmr", + "name": { "str": "M38 DMR" }, + "description": "The M38 Designated Marksman Rifle is an M27 IAR, itself derived from a H&K416, selected for accuracy, and outfitted with a variable power scope and a QDSS suppressor." + }, + { + "id": "m4_cqbr", + "name": { "str": "MK 18 CQBR" }, + "description": "This is a shorter M4 carbine with a 10.3 inch barrel, intended for confined spaces and close quarters battle situations." + } + ], "to_hit": -1, "bashing": 12, "material": [ "steel", "plastic" ], @@ -18,7 +65,7 @@ "color": "dark_gray", "ammo": [ "223" ], "ranged_damage": { "damage_type": "bullet", "amount": -1 }, - "dispersion": 150, + "dispersion": 160, "durability": 8, "min_cycle_recoil": 1350, "modes": [ [ "DEFAULT", "semi-auto", 1 ], [ "AUTO", "auto", 4 ] ], @@ -246,74 +293,20 @@ ] }, { - "id": "h&k416a5", - "copy-from": "rifle_auto", + "id": "hk_g36", + "copy-from": "nato_assault_rifle", "looks_like": "ar15", "type": "GUN", - "name": { "str": "HK416 A5" }, - "//": "*Current* milspec gear is now ridiculously overpriced, as seen with the M2010 IRL.", - "description": "Designed to replace the M4A1, the Heckler and Koch 416A5 features most of the former's strengths, while being considerably more durable.", - "weight": "3490 g", - "volume": "4957 ml", - "longest_side": "798 mm", - "price": 540000, - "price_postapoc": 2250, - "to_hit": -1, - "bashing": 12, - "material": [ "steel", "plastic" ], - "symbol": "(", - "color": "dark_gray", - "ammo": [ "223" ], - "ranged_damage": { "damage_type": "bullet", "amount": -2 }, - "dispersion": 180, - "durability": 8, - "min_cycle_recoil": 1350, - "modes": [ [ "DEFAULT", "semi-auto", 1 ], [ "AUTO", "auto", 4 ] ], - "pocket_data": [ + "name": { "str": "G36 assault rifle" }, + "description": "An assault rifle chamber in 5.56x45mm and accepting G36 magazines.", + "variants": [ { - "pocket_type": "MAGAZINE_WELL", - "holster": true, - "max_contains_volume": "20 L", - "max_contains_weight": "20 kg", - "item_restriction": [ - "stanag30", - "stanag5", - "stanag10", - "stanag20", - "stanag40", - "stanag50", - "stanag60", - "stanag60drum", - "stanag90", - "stanag100", - "stanag100drum", - "stanag150", - "survivor223mag" - ] + "id": "hk_g36", + "name": { "str": "H&K G36" }, + "description": "Designed as a replacement for the early H&K G3 battle rifle, the G36 is more accurate, and uses the much-lighter .223 round, allowing for a higher ammo capacity.", + "weight": 1 } - ] - }, - { - "id": "hk_g36", - "copy-from": "rifle_auto", - "looks_like": "ar15", - "type": "GUN", - "name": { "str": "H&K G36" }, - "description": "Designed as a replacement for the early H&K G3 battle rifle, the G36 is more accurate, and uses the much-lighter .223 round, allowing for a higher ammo capacity.", - "weight": "3630 g", - "volume": "4640 ml", - "longest_side": "1004 mm", - "price": 210000, - "price_postapoc": 6000, - "to_hit": -1, - "bashing": 12, - "material": [ "steel", "plastic" ], - "symbol": "(", - "color": "dark_gray", - "ammo": [ "223" ], - "dispersion": 150, - "durability": 8, - "min_cycle_recoil": 1350, + ], "modes": [ [ "DEFAULT", "semi-auto", 1 ], [ "AUTO", "auto", 4 ] ], "pocket_data": [ { @@ -396,164 +389,22 @@ "description": "This is a semi-automatic civilian variant of the M249 machine gun, manufactured for sport shooting and collectors market. Notably, it retains the ability to be belt fed, an uncommon feature in civilian firearms.", "modes": [ [ "DEFAULT", "semi-auto", 1 ] ] }, - { - "id": "m27iar", - "copy-from": "h&k416a5", - "type": "GUN", - "name": { "str": "M27 IAR" }, - "description": "A H&K416 carbine outfitted with a heavier barrel to enable higher amounts of suppressive fire while retaining a good degree of mobility.", - "ascii_picture": "m27_iar", - "weight": "3710 g", - "modes": [ [ "DEFAULT", "semi-auto", 1 ], [ "AUTO", "auto", 4 ] ], - "relative": { "ranged_damage": { "damage_type": "bullet", "amount": 1 }, "durability": 1 }, - "pocket_data": [ - { - "pocket_type": "MAGAZINE_WELL", - "holster": true, - "max_contains_volume": "20 L", - "max_contains_weight": "20 kg", - "item_restriction": [ - "stanag30", - "stanag5", - "stanag10", - "stanag20", - "stanag40", - "stanag50", - "stanag60", - "stanag60drum", - "stanag90", - "stanag100", - "stanag100drum", - "stanag150", - "survivor223mag" - ] - } - ] - }, - { - "id": "m38dmr", - "copy-from": "m27iar", - "name": { "str": "M38 DMR" }, - "type": "GUN", - "description": "The M38 Designated Marksman Rifle is an M27 IAR, itself derived from a H&K416, selected for accuracy, and outfitted with a variable power scope and a QDSS suppressor.", - "dispersion": 125, - "price_postapoc": 3000, - "default_mods": [ "suppressor", "rifle_scope", "bipod" ] - }, - { - "id": "m4a1", - "copy-from": "rifle_auto", - "looks_like": "ar15", - "type": "GUN", - "name": { "str": "M4A1" }, - "description": "A popular carbine, long used by the US military. Though accurate, small, and lightweight, it is infamous for its unreliability when not properly maintained.", - "ascii_picture": "m4a1", - "weight": "2880 g", - "volume": "3310 ml", - "longest_side": "758 mm", - "price": 240000, - "price_postapoc": 5000, - "to_hit": -1, - "bashing": 12, - "material": [ "steel", "plastic" ], - "symbol": "(", - "color": "dark_gray", - "ammo": [ "223" ], - "ranged_damage": { "damage_type": "bullet", "amount": -2 }, - "dispersion": 180, - "durability": 6, - "min_cycle_recoil": 1350, - "modes": [ [ "DEFAULT", "semi-auto", 1 ], [ "AUTO", "auto", 4 ] ], - "pocket_data": [ - { - "pocket_type": "MAGAZINE_WELL", - "holster": true, - "max_contains_volume": "20 L", - "max_contains_weight": "20 kg", - "item_restriction": [ - "stanag30", - "stanag5", - "stanag10", - "stanag20", - "stanag40", - "stanag50", - "stanag60", - "stanag60drum", - "stanag90", - "stanag100", - "stanag100drum", - "stanag150", - "survivor223mag" - ] - } - ] - }, - { - "id": "m4_cqbr", - "copy-from": "m4a1", - "type": "GUN", - "name": { "str": "MK 18 CQBR" }, - "description": "This is a shorter M4 carbine with a 10.3 inch barrel, intended for confined spaces and close quarters battle situations.", - "weight": "2720 g", - "volume": "3110 ml", - "longest_side": "682 mm", - "price": 260000, - "price_postapoc": 6000, - "ranged_damage": { "damage_type": "bullet", "amount": -3 } - }, { "id": "m16a4", - "copy-from": "rifle_semi", + "copy-from": "nato_assault_rifle", "looks_like": "ar15", "type": "GUN", - "name": { "str": "M16A4" }, - "description": "The M16 is a very common assault rifle descended from the AR-15, used by militaries across the world for over 50 years. It is a gas operated, rotating bolt rifle known for its accuracy and controllable recoil.", - "weight": "3260 g", - "volume": "5030 ml", - "longest_side": "1003 mm", - "price": 240000, - "price_postapoc": 5000, - "to_hit": -1, - "bashing": 12, - "material": [ "steel", "plastic" ], - "symbol": "(", - "color": "dark_gray", - "ammo": [ "223" ], - "dispersion": 150, - "durability": 7, - "min_cycle_recoil": 1350, - "modes": [ [ "DEFAULT", "semi-auto", 1 ], [ "BURST", "3 rd.", 3 ] ], - "pocket_data": [ + "name": { "str": "NATO burst rifle" }, + "description": "An assault rifle used by a NATO member state. Unlike other assault rifles, this one does not have an auto-fire mode, and instead has a burst fire mode. As per NATO's STANAG agreement, it is chambered in 5.56x45mm.", + "variants": [ { - "pocket_type": "MAGAZINE_WELL", - "holster": true, - "max_contains_volume": "20 L", - "max_contains_weight": "20 kg", - "item_restriction": [ - "stanag30", - "stanag5", - "stanag10", - "stanag20", - "stanag40", - "stanag50", - "stanag60", - "stanag60drum", - "stanag90", - "stanag100", - "stanag100drum", - "stanag150", - "survivor223mag" - ] + "id": "m16a4", + "name": { "str": "M16A4" }, + "description": "The M16 is a very common assault rifle descended from the AR-15, used by militaries across the world for over 50 years. It is a gas operated, rotating bolt rifle known for its accuracy and controllable recoil.", + "weight": 1 } - ] - }, - { - "id": "m16a3", - "copy-from": "m16a4", - "type": "GUN", - "name": { "str": "M16A3" }, - "description": "The M16 is a very common assault rifle descended from the AR-15, used by militaries across the world for over 50 years. It is a gas operated, rotating bolt rifle known for its accuracy and controllable recoil. This one is a relatively rare M16A3, with full auto capability.", - "modes": [ [ "DEFAULT", "semi-auto", 1 ], [ "AUTO", "auto", 4 ] ] + ], + "modes": [ [ "DEFAULT", "semi-auto", 1 ], [ "BURST", "3 rd.", 3 ] ] }, { "id": "m231pfw", @@ -680,121 +531,39 @@ } ] }, - { - "id": "scar_l", - "copy-from": "rifle_auto", - "looks_like": "ar15", - "type": "GUN", - "name": { "str": "FN SCAR-L" }, - "description": "A highly accurate and modular assault rifle specially designed for the United States Special Operations Command. The 'L' in its name stands for light, as it uses the lightweight .223 round.", - "ascii_picture": "scar-L", - "weight": "3500 g", - "volume": "4970 ml", - "longest_side": "850 mm", - "price": 280000, - "price_postapoc": 6000, - "to_hit": -1, - "bashing": 12, - "material": [ "steel", "plastic" ], - "symbol": "(", - "color": "dark_gray", - "ammo": [ "223" ], - "ranged_damage": { "damage_type": "bullet", "amount": -2 }, - "dispersion": 150, - "durability": 8, - "min_cycle_recoil": 1350, - "modes": [ [ "DEFAULT", "semi-auto", 1 ], [ "AUTO", "auto", 4 ] ], - "pocket_data": [ - { - "pocket_type": "MAGAZINE_WELL", - "holster": true, - "max_contains_volume": "20 L", - "max_contains_weight": "20 kg", - "item_restriction": [ - "stanag30", - "stanag5", - "stanag10", - "stanag20", - "stanag40", - "stanag50", - "stanag60", - "stanag60drum", - "stanag90", - "stanag100", - "stanag100drum", - "stanag150", - "survivor223mag" - ] - } - ] - }, { "id": "sig552", - "copy-from": "rifle_auto", + "copy-from": "nato_assault_rifle", "looks_like": "ar15", "type": "GUN", - "name": { "str": "SIG 552" }, - "description": "A compact selective fire automatic rifle designed for the Swiss military. It features a three-round burst mode and an integrated folding stock.", - "weight": "3200 g", - "volume": "2950 ml", - "longest_side": "741 mm", - "price": 320000, - "price_postapoc": 6000, - "to_hit": -1, - "bashing": 10, - "material": [ "steel", "plastic" ], - "ammo": [ "223" ], - "dispersion": 180, - "durability": 9, - "min_cycle_recoil": 1350, - "modes": [ [ "DEFAULT", "semi-auto", 1 ], [ "BURST", "3 rd.", 3 ], [ "AUTO", "auto", 4 ] ], - "built_in_mods": [ "folding_stock" ], - "pocket_data": [ + "//": "This could use a better name, I just wanted to differentiate it from assault rifles, as it also has a burst mode", + "name": { "str": "NATO assault rifle with burst" }, + "description": "An assault rifle used by a NATO member state. Unlike other assault rifles, this one has a burst fire mode in addition to semi-automatic and fully-automatic modes. As per NATO's STANAG agreement, it is chambered in 5.56x45mm.", + "variants": [ { - "pocket_type": "MAGAZINE_WELL", - "holster": true, - "max_contains_volume": "20 L", - "max_contains_weight": "20 kg", - "item_restriction": [ - "stanag30", - "stanag5", - "stanag10", - "stanag20", - "stanag40", - "stanag50", - "stanag60", - "stanag60drum", - "stanag90", - "stanag100", - "stanag100drum", - "stanag150", - "survivor223mag" - ] + "id": "sig552", + "name": { "str": "SIG 552" }, + "description": "A compact selective fire automatic rifle designed for the Swiss military. It features a three-round burst mode and an integrated folding stock.", + "weight": 1 } - ] + ], + "built_in_mods": [ "folding_stock" ] }, { "id": "steyr_aug", - "copy-from": "rifle_auto", + "copy-from": "nato_assault_rifle", "looks_like": "ar15", "type": "GUN", - "name": { "str": "Steyr AUG" }, - "description": "The Steyr AUG is an Austrian assault rifle that uses a bullpup design. It is used in the armed forces and police forces of many nations, and enjoys low recoil and high accuracy.", - "weight": "3500 g", - "volume": "3520 ml", - "longest_side": "715 mm", - "price": 490000, - "price_postapoc": 6000, - "to_hit": -1, - "bashing": 12, - "material": [ "steel", "plastic" ], - "symbol": "(", - "color": "light_gray", - "ammo": [ "223" ], - "dispersion": 140, - "durability": 8, - "min_cycle_recoil": 1350, - "modes": [ [ "DEFAULT", "semi-auto", 1 ], [ "AUTO", "auto", 4 ] ], + "name": { "str": "AUG assault rifle" }, + "description": "An assault rifle chambered in 5.56x45mm and accepting AUG magazines", + "variants": [ + { + "id": "steyr_aug", + "name": { "str": "Steyr AUG" }, + "description": "The Steyr AUG is an Austrian assault rifle that uses a bullpup design. It is used in the armed forces and police forces of many nations, and enjoys low recoil and high accuracy.", + "weight": 1 + } + ], "built_in_mods": [ "grip" ], "valid_mod_locations": [ [ "accessories", 4 ], diff --git a/data/json/items/gun/308.json b/data/json/items/gun/308.json index a1ce10176e491..5deff26f3b233 100644 --- a/data/json/items/gun/308.json +++ b/data/json/items/gun/308.json @@ -312,7 +312,7 @@ }, { "id": "scar_h", - "copy-from": "scar_l", + "copy-from": "nato_assault_rifle", "looks_like": "ar15", "type": "GUN", "name": { "str_sp": "FN SCAR-H" }, diff --git a/data/json/items/gun/45.json b/data/json/items/gun/45.json index c5519811c56b1..84013736b3b4f 100644 --- a/data/json/items/gun/45.json +++ b/data/json/items/gun/45.json @@ -4,8 +4,21 @@ "looks_like": "hk_mp5", "type": "GUN", "reload_noise_volume": 10, - "name": { "str": "Vector SMG .45" }, - "description": "The Vector SMG is a delayed blowback submachine gun with a unique, in-line design that places both the shooter's hand and shoulder in line with the bore axis, reducing muzzle climb during bursts. This one is chambered in .45 ACP.", + "//": [ + "Yes, I know it's not really a glock smg.", + "It takes glock magazines, and it's own special one that I am also renaming to a glock magazine", + "so, I'm calling it a glock smg." + ], + "name": { "str": "Glock SMG" }, + "description": "This is a submachine gun chambered in .45 ACP, accepting Glock magazines.", + "variants": [ + { + "id": "TDI", + "name": { "str": "Vector SMG .45" }, + "description": "The Vector SMG is a delayed blowback submachine gun with a unique, in-line design that places both the shooter's hand and shoulder in line with the bore axis, reducing muzzle climb during bursts. This one is chambered in .45 ACP.", + "weight": 1 + } + ], "weight": "3100 g", "volume": "4248 ml", "longest_side": "611 mm", @@ -53,8 +66,16 @@ "looks_like": "hk_mp5", "type": "GUN", "reload_noise_volume": 10, - "name": { "str": "H&K UMP45" }, - "description": "Developed as a successor to the MP5 submachine gun, the UMP45 retains the earlier model's supreme accuracy and low recoil, but in the higher .45 caliber.", + "name": { "str": "UMP45 SMG" }, + "description": "This is a submachine gun, chambered in .45 ACP, and accepting UMP45 magazines.", + "variants": [ + { + "id": "hk_ump45", + "name": { "str": "H&K UMP45" }, + "description": "Developed as a successor to the MP5 submachine gun, the UMP45 retains the earlier model's supreme accuracy and low recoil, but in the higher .45 caliber.", + "weight": 1 + } + ], "ascii_picture": "hk_ump", "weight": "2300 g", "volume": "4451 ml", @@ -104,9 +125,22 @@ "copy-from": "pistol_base", "looks_like": "glock_17", "type": "GUN", - "name": { "str": "M1911" }, - "//": "You can get 'em for over US$1K if you want. This is a fairly cheap remake.", - "description": "The M1911 was the US Military standard-issue sidearm for most of the 20th Century. It remains one of the most popular .45 pistols today.", + "name": { "str": "M1911 pistol" }, + "description": "This is a semi-automatic pistol, chambered in .45 ACP and accepting M1991 magaines.", + "variants": [ + { + "id": "m1911", + "name": { "str": "M1911" }, + "//": "You can get 'em for over US$1K if you want. This is a fairly cheap remake.", + "description": "The M1911 was the US Military standard-issue sidearm for most of the 20th Century. It remains one of the most popular .45 pistols today.", + "weight": 1 + }, + { + "id": "m1911_MEU", + "name": { "str": "M45A1" }, + "description": "The M45A1 supplanted earlier M45 MEUSOC pistols in use by Force Recon elements of Marine Expeditionary Units. Where the original M45 pistols were gutted M1911A1's hand-fitted by USMC armorers, the updated M45A1's are hardly different from any other commercial 1911 design save for their dual recoil springs. Most were replaced in 2016 with Glock 19's due to logistics issues." + } + ], "ascii_picture": "m1911", "weight": "1120 g", "volume": "454 ml", @@ -134,27 +168,21 @@ } ] }, - { - "id": "m1911_MEU", - "copy-from": "m1911", - "looks_like": "glock_17", - "type": "GUN", - "name": { "str": "M45A1" }, - "description": "The M45A1 supplanted earlier M45 MEUSOC pistols in use by Force Recon elements of Marine Expeditionary Units. Where the original M45 pistols were gutted M1911A1's hand-fitted by USMC armorers, the updated M45A1's are hardly different from any other commercial 1911 design save for their dual recoil springs. Most were replaced in 2016 with Glock 19's due to logistics issues.", - "weight": "1105 g", - "price": 169900, - "price_postapoc": 2750, - "color": "brown_yellow", - "dispersion": 420, - "durability": 8 - }, { "id": "mac_10", "looks_like": "hk_mp5", "type": "GUN", "reload_noise_volume": 10, - "name": { "str": "MAC-10" }, - "description": "The MAC-10 is a popular machine pistol originally designed for military use. For many years they were the most inexpensive automatic weapon in the US, and enjoyed great popularity among criminals less concerned with quality firearms.", + "name": { "str": "MAC-10 SMG" }, + "description": "This is a submachine gun chambered in .45 ACP, and accepting MAC-10 magazines.", + "variants": [ + { + "id": "mac_10", + "name": { "str": "MAC-10" }, + "description": "The MAC-10 is a popular machine pistol originally designed for military use. For many years they were the most inexpensive automatic weapon in the US, and enjoyed great popularity among criminals less concerned with quality firearms.", + "weight": 1 + } + ], "weight": "2810 g", "volume": "1195 ml", "longest_side": "298 mm", @@ -320,8 +348,16 @@ "looks_like": "hk_mp5", "type": "GUN", "reload_noise_volume": 10, - "name": { "str": "Thompson M1928A1" }, - "description": "An American-made submachine gun developed during the very end of World War I, too late to see action. Infamous during the 1920s for its use by gangsters, and was used during World War II before being mostly replaced with less-expensive alternatives.", + "name": { "str": "Thompson SMG" }, + "description": "This is a submachine gun chambered in .45 ACP, and accepting Thompson magazines.", + "variants": [ + { + "id": "tommygun", + "name": { "str": "Thompson M1928A1" }, + "description": "An American-made submachine gun developed during the very end of World War I, too late to see action. Infamous during the 1920s for its use by gangsters, and was used during World War II before being mostly replaced with less-expensive alternatives.", + "weight": 1 + } + ], "weight": "4899 g", "volume": "1230 ml", "longest_side": "832 mm", @@ -369,7 +405,21 @@ "id": "usp_45", "copy-from": "usp_9mm", "type": "GUN", - "name": { "str": "USP .45" }, + "name": { "str": "USP pistol" }, + "description": "A semi-automatic pistol chambered in .45 ACP, and accepting USP magazines.", + "variants": [ + { + "id": "usp_45", + "name": { "str": "USP .45" }, + "description": "A popular pistol, widely used among law enforcement. Extensively tested for durability, it has been found to stay accurate even after being subjected to extreme abuse.", + "weight": 1 + }, + { + "id": "mk23", + "name": { "str": "MK 23 MOD 0" }, + "description": "Jokingly referred to as \"The World's Only Crew-Served Pistol\", this massive pistol was designed as a primary weapon for select \"special operators\". Its cumbersome nature, the introduction of the derivative HK USP series and the logistics of getting .45 ACP ammunition in theater doomed this behemoth to US SOCOM armories. Like the USP, the Mk 23 is a remarkably reliable gun; someone could probably take out a nuclear equipped walking tank with this in their holster." + } + ], "weight": "887 g", "volume": "483 ml", "longest_side": "241 mm", @@ -389,27 +439,21 @@ } ] }, - { - "id": "mk23", - "copy-from": "usp_45", - "type": "GUN", - "name": { "str": "MK 23 MOD 0" }, - "description": "Jokingly referred to as \"The World's Only Crew-Served Pistol\", this massive pistol was designed as a primary weapon for select \"special operators\". Its cumbersome nature, the introduction of the derivative HK USP series and the logistics of getting .45 ACP ammunition in theater doomed this behemoth to US SOCOM armories. Like the USP, the Mk 23 is a remarkably reliable gun; someone could probably take out a nuclear equipped walking tank with this in their holster.", - "weight": "844 g", - "volume": "698 ml", - "longest_side": "277 mm", - "price": 70000, - "price_postapoc": 3000, - "default_mods": [ "suppressor", "laser_sight" ], - "flags": [ "WATERPROOF_GUN", "NEVER_JAMS" ] - }, { "id": "walther_ppq_45", "copy-from": "pistol_base", "looks_like": "glock_17", "type": "GUN", - "name": { "str": "Walther PPQ 45" }, - "description": "The Walther PPQ is a semi-automatic pistol originating from the Walther P99QA, and maintains compatibility with some of its predecessor's accessories. This model is chambered in .45 ACP.", + "name": { "str": "PPQ pistol" }, + "description": "This is a semi-automatic pistol chambered in .45 ACP, and accepting PPQ magazines", + "variants": [ + { + "id": "walther_ppq_45", + "name": { "str": "Walther PPQ 45" }, + "description": "The Walther PPQ is a semi-automatic pistol originating from the Walther P99QA, and maintains compatibility with some of its predecessor's accessories. This model is chambered in .45 ACP.", + "weight": 1 + } + ], "weight": "799 g", "volume": "472 ml", "longest_side": "224 mm", @@ -438,8 +482,16 @@ "copy-from": "pistol_base", "looks_like": "glock_17", "type": "GUN", - "name": { "str": "Hi-Point Model JHP" }, - "description": "The Hi-Point Model JHP is a blowback operated semi-automatic pistol designed by Hi-Point Firearms, which is known for making inexpensive firearms, and for making said firearms bulky and uncomfortable. Hi-Points have slides made with a zinc pot-metal which is relatively fragile compared to steel slides.", + "name": { "str": "Hi-Point pistol" }, + "description": "This is a semi-automatic pistol chambered in .45 ACP, and accepting Hi-Point magazines", + "variants": [ + { + "id": "hptjhp", + "name": { "str": "Hi-Point Model JHP" }, + "description": "The Hi-Point Model JHP is a blowback operated semi-automatic pistol designed by Hi-Point Firearms, which is known for making inexpensive firearms, and for making said firearms bulky and uncomfortable. Hi-Points have slides made with a zinc pot-metal which is relatively fragile compared to steel slides.", + "weight": 1 + } + ], "weight": "990 g", "volume": "538 ml", "longest_side": "238 mm", @@ -469,8 +521,16 @@ "copy-from": "pistol_base", "looks_like": "glock_17", "type": "GUN", - "name": { "str": "Glock 21" }, - "description": "A full-sized version of the highly successful Glock. This model is chambered in .45 ACP.", + "name": { "str": "Glock pistol" }, + "description": "This is a semi-automatic pistol chambered in .45 ACP, and accepting Glock magazines.", + "variants": [ + { + "id": "glock_21", + "name": { "str": "Glock 21" }, + "description": "A full-sized version of the highly successful Glock. This model is chambered in .45 ACP.", + "weight": 1 + } + ], "ascii_picture": "glock_20", "weight": "835 g", "volume": "490 ml", diff --git a/data/json/items/magazine/45.json b/data/json/items/magazine/45.json index 1296e45516a44..5ed6563fac0a8 100644 --- a/data/json/items/magazine/45.json +++ b/data/json/items/magazine/45.json @@ -38,8 +38,16 @@ "id": "tdi_mag", "looks_like": "mp5mag", "type": "MAGAZINE", - "name": { "str": "Vector SMG 30-round magazine" }, - "description": "A 30-round polymer and steel box magazine for use with the KRISS Vector.", + "name": { "str": "Glock SMG 30-round magazine" }, + "description": "A 30-round polymer and steel box magazine for use with the Glock submachine gun.", + "variants": [ + { + "id": "tdi_mag", + "name": { "str": "Vector SMG 30-round magazine" }, + "description": "A 30-round polymer and steel box magazine for use with the KRISS Vector.", + "weight": 1 + } + ], "weight": "210 g", "volume": "500 ml", "price": 1800, @@ -141,8 +149,16 @@ "id": "usp45mag", "looks_like": "glock17_17", "type": "MAGAZINE", - "name": { "str": "USP .45 12-round magazine" }, - "description": "A standard capacity magazine for use with the H&K USP handgun.", + "name": { "str": "USP .45 pistol 12-round magazine" }, + "description": "A 12 round magazine for use with the USP pistol", + "variants": [ + { + "id": "usp45mag", + "name": { "str": "USP .45 12-round magazine" }, + "description": "A standard capacity magazine for use with the H&K USP handgun.", + "weight": 1 + } + ], "weight": "60 g", "volume": "250 ml", "price": 5900, @@ -158,8 +174,16 @@ "id": "ppq45mag", "looks_like": "glock17_17", "type": "MAGAZINE", - "name": { "str": "PPQ .45 ACP 12-round magazine" }, - "description": "A 12 round steel box magazine for the Walther PPQ .45 ACP.", + "name": { "str": "PPQ .45 12-round amgazine" }, + "description": "A 12 round steel box magazine for the PPQ pistol", + "variants": [ + { + "id": "ppq45mag", + "name": { "str": "PPQ .45 ACP 12-round magazine" }, + "description": "A 12 round steel box magazine for the Walther PPQ .45 ACP.", + "weight": 1 + } + ], "weight": "80 g", "volume": "240 ml", "price": 5000, @@ -192,8 +216,16 @@ "id": "glock_21mag", "looks_like": "glock17_17", "type": "MAGAZINE", - "name": { "str": "Glock 21 13-round magazine" }, - "description": "A standard capacity magazine for use with the Glock 21.", + "name": { "str": "Glock .45 13-round magazine" }, + "description": "A 13 round magazine for use with Glock firearms chambered in .45 ACP.", + "variants": [ + { + "id": "glock_21mag", + "name": { "str": "Glock 21 13-round magazine" }, + "description": "A standard capacity magazine for use with the Glock 21.", + "weight": 1 + } + ], "weight": "85 g", "volume": "105 ml", "price": 4000, @@ -209,8 +241,16 @@ "id": "glock_21mag26", "looks_like": "glock17_17", "type": "MAGAZINE", - "name": { "str": "Glock 21 26-round magazine" }, - "description": "A double capacity magazine for use with the Glock 21.", + "name": { "str": "Glock .45 26-round magazine" }, + "description": "A 26 round magazine for use with Glock firearms chambered in .45 ACP.", + "variants": [ + { + "id": "glock_21mag26", + "name": { "str": "Glock 21 26-round magazine" }, + "description": "A double capacity magazine for use with the Glock 21.", + "weight": 1 + } + ], "weight": "85 g", "volume": "205 ml", "price": 4000, diff --git a/data/json/items/migration.json b/data/json/items/migration.json index 9ca037b6feac4..dbfb65d23c529 100644 --- a/data/json/items/migration.json +++ b/data/json/items/migration.json @@ -1136,7 +1136,7 @@ { "id": [ "l_base_223", "l_car_223", "l_car_223_kit", "l_mbr_223", "l_mbr_223_kit" ], "type": "MIGRATION", - "replace": "h&k416a5" + "replace": "nato_assault_rifle" }, { "id": [ "l_lmg_223", "l_lmg_223_kit" ], @@ -1146,7 +1146,55 @@ { "id": [ "l_dsr_223", "l_dsr_223_kit" ], "type": "MIGRATION", - "replace": "m16a4" + "replace": "nato_assault_rifle" + }, + { + "id": "acr", + "type": "MIGRATION", + "replace": "nato_assault_rifle", + "variant": "acr" + }, + { + "id": "h&k416a5", + "type": "MIGRATION", + "replace": "nato_assault_rifle", + "variant": "h&k416a5" + }, + { + "id": "m27iar", + "type": "MIGRATION", + "replace": "nato_assault_rifle", + "variant": "m27iar" + }, + { + "id": "m4a1", + "type": "MIGRATION", + "replace": "nato_assault_rifle", + "variant": "m4a1" + }, + { + "id": "m16a3", + "type": "MIGRATION", + "replace": "nato_assault_rifle", + "variant": "m16a3" + }, + { + "id": "scar_l", + "type": "MIGRATION", + "replace": "nato_assault_rifle", + "variant": "scar_l" + }, + { + "id": "m38dmr", + "type": "MIGRATION", + "replace": "nato_assault_rifle", + "variant": "m38dmr" + }, + { + "id": "m4_cqbr", + "type": "MIGRATION", + "replace": "nato_assault_rifle", + "variant": "m4_cqbr" }, { "id": "lw223bigmag", @@ -1163,6 +1211,18 @@ "type": "MIGRATION", "replace": "m1911mag" }, + { + "id": "m1911_MEU", + "type": "MIGRATION", + "replace": "m1911", + "variant": "m1911_MEU" + }, + { + "id": "mk23", + "type": "MIGRATION", + "replace": "usp_45", + "variant": "mk23" + }, { "id": "solar_panel_v3", "type": "MIGRATION", diff --git a/data/json/mapgen/military/mil_base/mil_base_z0.json b/data/json/mapgen/military/mil_base/mil_base_z0.json index 217d06746dd9f..782f5b5ee8ef9 100644 --- a/data/json/mapgen/military/mil_base/mil_base_z0.json +++ b/data/json/mapgen/military/mil_base/mil_base_z0.json @@ -752,13 +752,37 @@ { "item": "m203", "x": 10, "y": 11, "chance": 75, "repeat": 5 }, { "item": "mgl", "x": 10, "y": 11, "chance": 75, "repeat": 3 }, { "item": "40x46mm_m433", "x": 10, "y": 12, "chance": 75, "repeat": 20 }, - { "item": "m4a1", "x": 12, "y": [ 9, 11 ], "magazine": 100, "chance": 75, "repeat": 30 }, - { "item": "m27iar", "x": 12, "y": 9, "magazine": 100, "chance": 75, "repeat": 8 }, + { + "item": "nato_assault_rifle", + "variant": "m4a1", + "x": 12, + "y": [ 9, 11 ], + "magazine": 100, + "chance": 75, + "repeat": 30 + }, + { + "item": "nato_assault_rifle", + "variant": "m27iar", + "x": 12, + "y": 9, + "magazine": 100, + "chance": 75, + "repeat": 8 + }, { "item": "m16a4", "x": 12, "y": 9, "magazine": 100, "chance": 75, "repeat": 2 }, { "item": "stanag30", "x": 12, "y": 12, "chance": 75, "repeat": 80 }, { "item": "stanag50", "x": 12, "y": 12, "chance": 75, "repeat": 20 }, { "item": "556", "x": 14, "y": [ 9, 12 ], "chance": 75, "repeat": 150 }, - { "item": "m4a1", "x": 16, "y": [ 9, 11 ], "magazine": 100, "chance": 75, "repeat": 36 }, + { + "item": "nato_assault_rifle", + "variant": "m4a1", + "x": 16, + "y": [ 9, 11 ], + "magazine": 100, + "chance": 75, + "repeat": 36 + }, { "item": "stanag30", "x": 16, "y": 12, "chance": 75, "repeat": 100 }, { "item": "556", "x": 18, "y": [ 9, 12 ], "chance": 75, "repeat": 150 }, { "item": "m249", "x": 20, "y": 9, "chance": 75, "repeat": 6 }, diff --git a/data/json/martialarts.json b/data/json/martialarts.json index ed02807b5f9ba..65f5993f4a772 100644 --- a/data/json/martialarts.json +++ b/data/json/martialarts.json @@ -645,10 +645,8 @@ "hptjhp", "m17", "m1911", - "m1911_MEU", "m1911a1_38super", "m9", - "mk23", "needlepistol", "sw_22", "p226_357sig", @@ -665,7 +663,7 @@ "walther_ppq_9mm", "walther_ppq_40", "walther_ppq_45", - "acr", + "nato_assault_rifle", "acr_300blk", "ak47", "ak74", @@ -674,24 +672,17 @@ "ar15", "ar15_retool_300blk", "fn_fal", - "h&k416a5", "hk417_13", "hk_g3", - "hk_g36", "iwi_tavor_x95_300blk", "m1a", "m110a1", "m14ebr", "m16a4", - "m27iar", - "m38dmr", - "m4a1", "rm51_assault_rifle", "rm88_battle_rifle", "ruger_mini", - "scar_l", "scar_h", - "sig552", "sks", "steyr_aug" ] diff --git a/data/json/npcs/NC_ARSONIST.json b/data/json/npcs/NC_ARSONIST.json index b724d245854b9..fac1c64e31ba5 100644 --- a/data/json/npcs/NC_ARSONIST.json +++ b/data/json/npcs/NC_ARSONIST.json @@ -194,7 +194,11 @@ "type": "item_group", "id": "NC_ARSONIST_rifle", "subtype": "distribution", - "entries": [ { "item": "m4a1", "prob": 35 }, { "item": "m1a", "prob": 35 }, { "item": "ak47", "prob": 35 } ] + "entries": [ + { "item": "nato_assault_rifle", "variant": "m4a1", "prob": 35 }, + { "item": "m1a", "prob": 35 }, + { "item": "ak47", "prob": 35 } + ] }, { "type": "item_group", diff --git a/data/json/npcs/NC_SOLDIER.json b/data/json/npcs/NC_SOLDIER.json index 61d44ec2aeb14..d5e6ccb771832 100644 --- a/data/json/npcs/NC_SOLDIER.json +++ b/data/json/npcs/NC_SOLDIER.json @@ -117,13 +117,13 @@ "type": "item_group", "id": "NC_SOLDIER_rifle", "subtype": "distribution", - "entries": [ { "item": "m4a1", "prob": 90 }, { "item": "m14ebr", "prob": 10 } ] + "entries": [ { "item": "nato_assault_rifle", "variant": "m4a1", "prob": 90 }, { "item": "m14ebr", "prob": 10 } ] }, { "type": "item_group", "id": "NC_SOLDIER_weapon_random", "subtype": "distribution", - "entries": [ { "item": "m4a1", "prob": 35 } ] + "entries": [ { "item": "nato_assault_rifle", "variant": "m4a1", "prob": 35 } ] }, { "type": "item_group", diff --git a/data/json/npcs/refugee_center/surface_visitors/NPC_scavenger_mercenary.json b/data/json/npcs/refugee_center/surface_visitors/NPC_scavenger_mercenary.json index ae95e41ae4a01..4484feb847eae 100644 --- a/data/json/npcs/refugee_center/surface_visitors/NPC_scavenger_mercenary.json +++ b/data/json/npcs/refugee_center/surface_visitors/NPC_scavenger_mercenary.json @@ -73,7 +73,13 @@ "id": "NC_SCAVENGER_MERC_wield", "subtype": "collection", "items": [ - { "item": "m4a1", "ammo-item": "556", "charges": 30, "contents-item": [ "shoulder_strap", "holo_sight", "suppressor" ] } + { + "item": "nato_assault_rifle", + "variant": "m4a1", + "ammo-item": "556", + "charges": 30, + "contents-item": [ "shoulder_strap", "holo_sight", "suppressor" ] + } ] }, { diff --git a/data/json/npcs/robofac/NPC_ROBOFAC_MERC_1.json b/data/json/npcs/robofac/NPC_ROBOFAC_MERC_1.json index 6b61c9176f927..41f2b45f56bc9 100644 --- a/data/json/npcs/robofac/NPC_ROBOFAC_MERC_1.json +++ b/data/json/npcs/robofac/NPC_ROBOFAC_MERC_1.json @@ -65,7 +65,13 @@ "id": "NC_ROBOFAC_MERC_1_wield", "subtype": "collection", "items": [ - { "item": "acr", "ammo-item": "556", "charges": 30, "contents-item": [ "shoulder_strap", "holo_sight", "suppressor" ] } + { + "item": "nato_assault_rifle", + "variant": "acr", + "ammo-item": "556", + "charges": 30, + "contents-item": [ "shoulder_strap", "holo_sight", "suppressor" ] + } ] }, { diff --git a/data/json/professions.json b/data/json/professions.json index 9b4d5e7de891c..b40032f09b937 100644 --- a/data/json/professions.json +++ b/data/json/professions.json @@ -804,7 +804,13 @@ { "item": "legpouch_large", "contents-group": "army_mags_m4" }, { "item": "ear_plugs", "custom-flags": [ "no_auto_equip" ] }, { "item": "knife_combat", "container-item": "sheath" }, - { "item": "m4a1", "ammo-item": "556", "charges": 30, "contents-item": [ "shoulder_strap", "holo_sight" ] } + { + "item": "nato_assault_rifle", + "variant": "m4a1", + "ammo-item": "556", + "charges": 30, + "contents-item": [ "shoulder_strap", "holo_sight" ] + } ] }, "male": [ "boxer_shorts" ], @@ -989,7 +995,13 @@ { "item": "legpouch_large", "contents-group": "army_mags_m4" }, { "item": "ear_plugs", "custom-flags": [ "no_auto_equip" ] }, { "item": "knife_combat", "container-item": "sheath" }, - { "item": "m4a1", "ammo-item": "556", "charges": 30, "contents-item": [ "shoulder_strap", "holo_sight" ] } + { + "item": "nato_assault_rifle", + "variant": "m4a1", + "ammo-item": "556", + "charges": 30, + "contents-item": [ "shoulder_strap", "holo_sight" ] + } ] }, "male": [ "boxer_shorts" ], @@ -1086,7 +1098,13 @@ "items": [ "armor_farmor", "socks", "boots_fur", "hat_fur", "gloves_fur", "vest", "wristwatch" ], "entries": [ { "item": "knife_combat", "container-item": "sheath" }, - { "item": "m4a1", "ammo-item": "556", "charges": 30, "contents-item": "shoulder_strap" }, + { + "item": "nato_assault_rifle", + "variant": "m4a1", + "ammo-item": "556", + "charges": 30, + "contents-item": "shoulder_strap" + }, { "item": "stanag30", "ammo-item": "556", "charges": 30 }, { "item": "stanag30", "ammo-item": "556", "charges": 30 }, { "item": "stanag30", "ammo-item": "556", "charges": 30 } @@ -2792,7 +2810,7 @@ "entries": [ { "item": "ear_plugs", "custom-flags": [ "no_auto_equip" ] }, { "item": "knife_combat", "container-item": "sheath" }, - { "item": "m4a1", "ammo-item": "556", "contents-item": "shoulder_strap" }, + { "item": "nato_assault_rifle", "variant": "m4a1", "ammo-item": "556", "contents-item": "shoulder_strap" }, { "item": "medium_plus_battery_cell", "ammo-item": "battery", @@ -3787,7 +3805,13 @@ { "item": "mask_dust", "custom-flags": [ "no_auto_equip" ] }, { "item": "stethoscope", "custom-flags": [ "no_auto_equip" ] }, { "item": "knife_combat", "container-item": "sheath" }, - { "item": "m4a1", "ammo-item": "556", "charges": 30, "contents-item": [ "shoulder_strap", "holo_sight" ] } + { + "item": "nato_assault_rifle", + "variant": "m4a1", + "ammo-item": "556", + "charges": 30, + "contents-item": [ "shoulder_strap", "holo_sight" ] + } ] }, "male": [ "boxer_shorts" ], diff --git a/data/json/recipes/recipe_deconstruction.json b/data/json/recipes/recipe_deconstruction.json index 43b395ca54024..c10e707bb7de7 100644 --- a/data/json/recipes/recipe_deconstruction.json +++ b/data/json/recipes/recipe_deconstruction.json @@ -1415,7 +1415,7 @@ [ [ "gun_module", 3 ] ], [ [ "flamethrower", 1 ] ], [ [ "tazer", 1 ] ], - [ [ "m4a1", 1 ] ], + [ [ "nato_assault_rifle", 1 ] ], [ [ "pamd68", 1 ] ], [ [ "power_supply", 20 ] ], [ [ "amplifier", 5 ] ], diff --git a/data/json/recipes/weapon/magazines.json b/data/json/recipes/weapon/magazines.json index ab9ec93e9c99f..319728e6bef0b 100644 --- a/data/json/recipes/weapon/magazines.json +++ b/data/json/recipes/weapon/magazines.json @@ -120,18 +120,7 @@ "time": "20 m", "autolearn": true, "tools": [ - [ - [ "acr", -1 ], - [ "ar15", -1 ], - [ "h&k416a5", -1 ], - [ "m249", -1 ], - [ "m27iar", -1 ], - [ "m4a1", -1 ], - [ "m16a4", -1 ], - [ "scar_l", -1 ], - [ "sig552", -1 ], - [ "surv_carbine_223", -1 ] - ], + [ [ "nato_assault_rifle", -1 ], [ "ar15", -1 ], [ "m249", -1 ], [ "m16a4", -1 ], [ "surv_carbine_223", -1 ] ], [ [ "small_repairkit", 10 ], [ "large_repairkit", 5 ] ] ], "using": [ [ "223_casehead", 1 ] ], diff --git a/data/json/recipes/weapon/mods.json b/data/json/recipes/weapon/mods.json index 563c84c5c30a1..5249ee41f0b89 100644 --- a/data/json/recipes/weapon/mods.json +++ b/data/json/recipes/weapon/mods.json @@ -963,9 +963,7 @@ [ "ar15_retool_300blk", -1 ], [ "ar_pistol", -1 ], [ "oa93", -1 ], - [ "h&k416a5", -1 ], - [ "m27iar", -1 ], - [ "m4a1", -1 ], + [ "nato_assault_rifle", -1 ], [ "m16a4", -1 ] ], [ [ "small_repairkit", 40 ], [ "large_repairkit", 40 ] ] diff --git a/data/json/vehicles/helicopters.json b/data/json/vehicles/helicopters.json index 5e7ed7be33e31..ae8b883a006d3 100644 --- a/data/json/vehicles/helicopters.json +++ b/data/json/vehicles/helicopters.json @@ -1030,7 +1030,7 @@ { "x": -9, "y": -1, "chance": 7, "items": [ "rucksack" ] }, { "x": -8, "y": -1, "chance": 5, "items": [ "m9" ] }, { "x": -7, "y": -2, "chance": 5, "items": [ "223" ] }, - { "x": -7, "y": -2, "chance": 5, "magazine": 90, "ammo": 70, "items": [ "m4a1" ] }, + { "x": -7, "y": -2, "chance": 5, "magazine": 90, "ammo": 70, "items": "nato_assault_rifle", "variant": "m4a1" }, { "x": -7, "y": -2, "chance": 7, "items": [ "EMPbomb" ] }, { "x": -7, "y": -2, "chance": 15, "items": [ "mask_gas" ] }, { "x": -7, "y": -2, "chance": 7, "items": [ "flashlight" ], "ammo": 100 }, @@ -1221,7 +1221,7 @@ { "x": -9, "y": -1, "chance": 7, "items": [ "rucksack" ] }, { "x": -8, "y": -1, "chance": 5, "items": [ "m9" ] }, { "x": -7, "y": -2, "chance": 5, "items": [ "223" ] }, - { "x": -7, "y": -2, "chance": 5, "magazine": 90, "ammo": 70, "items": [ "m4a1" ] }, + { "x": -7, "y": -2, "chance": 5, "magazine": 90, "ammo": 70, "items": "nato_assault_rifle", "variant": "m4a1" }, { "x": -7, "y": -2, "chance": 7, "items": [ "EMPbomb" ] }, { "x": -7, "y": -2, "chance": 15, "items": [ "mask_gas" ] }, { "x": -7, "y": -2, "chance": 7, "items": [ "flashlight" ], "ammo": 100 }, @@ -1390,7 +1390,7 @@ { "x": -9, "y": -1, "chance": 7, "items": [ "rucksack" ] }, { "x": -8, "y": -1, "chance": 5, "items": [ "m9" ] }, { "x": -7, "y": -2, "chance": 5, "items": [ "223" ] }, - { "x": -7, "y": -2, "chance": 5, "magazine": 90, "ammo": 70, "items": [ "m4a1" ] }, + { "x": -7, "y": -2, "chance": 5, "magazine": 90, "ammo": 70, "items": "nato_assault_rifle", "variant": "m4a1" }, { "x": -7, "y": -2, "chance": 7, "items": [ "EMPbomb" ] }, { "x": -7, "y": -2, "chance": 15, "items": [ "mask_gas" ] }, { "x": -7, "y": -2, "chance": 7, "items": [ "flashlight" ], "ammo": 100 }, @@ -1507,7 +1507,7 @@ { "x": -6, "y": 1, "chance": 7, "ammo": 70, "items": [ "stanag30" ] }, { "x": -6, "y": 1, "chance": 10, "items": [ "helmet_army" ] }, { "x": -6, "y": 1, "chance": 15, "items": [ "gasfilter_m" ] }, - { "x": -6, "y": 1, "chance": 3, "magazine": 70, "ammo": 70, "items": [ "m4a1" ] }, + { "x": -6, "y": 1, "chance": 100, "magazine": 70, "ammo": 70, "items": "nato_assault_rifle", "variant": "m4a1" }, { "x": -5, "y": 0, "chance": 3, "items": [ "cig_butt" ] }, { "x": -5, "y": 0, "chance": 5, "items": [ "cig" ] }, { "x": -5, "y": 2, "chance": 7, "ammo": 70, "items": [ "stanag30" ] }, @@ -1613,7 +1613,7 @@ { "x": -6, "y": 1, "chance": 7, "ammo": 70, "items": [ "stanag30" ] }, { "x": -6, "y": 1, "chance": 10, "items": [ "helmet_army" ] }, { "x": -6, "y": 1, "chance": 15, "items": [ "gasfilter_m" ] }, - { "x": -6, "y": 1, "chance": 3, "magazine": 70, "ammo": 70, "items": [ "m4a1" ] }, + { "x": -6, "y": 1, "chance": 3, "magazine": 70, "ammo": 70, "items": "nato_assault_rifle", "variant": "m4a1" }, { "x": -5, "y": 0, "chance": 20, "item_groups": [ "remains_soldier" ] }, { "x": -5, "y": 0, "chance": 3, "items": [ "cig_butt" ] }, { "x": -5, "y": 0, "chance": 5, "items": [ "cig" ] }, @@ -1717,7 +1717,7 @@ { "x": -6, "y": 1, "chance": 7, "ammo": 70, "items": [ "stanag30" ] }, { "x": -6, "y": 1, "chance": 10, "items": [ "helmet_army" ] }, { "x": -6, "y": 1, "chance": 15, "items": [ "gasfilter_m" ] }, - { "x": -6, "y": 1, "chance": 3, "magazine": 70, "ammo": 70, "items": [ "m4a1" ] }, + { "x": -6, "y": 1, "chance": 3, "magazine": 70, "ammo": 70, "items": "nato_assault_rifle", "variant": "m4a1" }, { "x": -5, "y": 0, "chance": 20, "item_groups": [ "remains_soldier" ] }, { "x": -5, "y": 0, "chance": 3, "items": [ "cig_butt" ] }, { "x": -5, "y": 0, "chance": 5, "items": [ "cig" ] }, diff --git a/data/mods/BlazeIndustries/vehicleparts/blaze_turrets_vanilla.json b/data/mods/BlazeIndustries/vehicleparts/blaze_turrets_vanilla.json index 7142e33d81d77..4cf46dd686f76 100644 --- a/data/mods/BlazeIndustries/vehicleparts/blaze_turrets_vanilla.json +++ b/data/mods/BlazeIndustries/vehicleparts/blaze_turrets_vanilla.json @@ -9,12 +9,12 @@ "requirements": { "install": { "skills": [ [ "mechanics", 3 ] ] }, "removal": { "skills": [ [ "mechanics", 1 ] ] } } }, { - "id": "mounted_acr", + "id": "mounted_nato_assault_rifle", "copy-from": "turret", "type": "vehicle_part", - "name": { "str": "mounted Remington ACR" }, - "item": "acr", - "breaks_into": [ { "item": "acr", "prob": 50 } ], + "name": { "str": "mounted assault rifle" }, + "item": "nato_assault_rifle", + "breaks_into": [ { "item": "nato_assault_rifle", "prob": 50 } ], "requirements": { "install": { "skills": [ [ "mechanics", 3 ] ] }, "removal": { "skills": [ [ "mechanics", 1 ] ] } } }, { @@ -154,15 +154,6 @@ "breaks_into": [ { "item": "fn_p90", "prob": 50 } ], "requirements": { "install": { "skills": [ [ "mechanics", 3 ] ] }, "removal": { "skills": [ [ "mechanics", 1 ] ] } } }, - { - "id": "mounted_h&k416a5", - "copy-from": "turret", - "type": "vehicle_part", - "name": { "str": "mounted H&K 416A5" }, - "item": "h&k416a5", - "breaks_into": [ { "item": "h&k416a5", "prob": 50 } ], - "requirements": { "install": { "skills": [ [ "mechanics", 3 ] ] }, "removal": { "skills": [ [ "mechanics", 1 ] ] } } - }, { "id": "mounted_hk_g3", "copy-from": "turret", @@ -289,15 +280,6 @@ "breaks_into": [ { "item": "m2010", "prob": 50 } ], "requirements": { "install": { "skills": [ [ "mechanics", 3 ] ] }, "removal": { "skills": [ [ "mechanics", 1 ] ] } } }, - { - "id": "mounted_m27iar", - "copy-from": "turret", - "type": "vehicle_part", - "name": { "str": "mounted M27 IAR" }, - "item": "m27iar", - "breaks_into": [ { "item": "m27iar", "prob": 50 } ], - "requirements": { "install": { "skills": [ [ "mechanics", 3 ] ] }, "removal": { "skills": [ [ "mechanics", 1 ] ] } } - }, { "id": "mounted_m2browning_sawn", "copy-from": "turret", @@ -316,15 +298,6 @@ "breaks_into": [ { "item": "m320", "prob": 50 } ], "requirements": { "install": { "skills": [ [ "mechanics", 4 ] ] }, "removal": { "skills": [ [ "mechanics", 2 ] ] } } }, - { - "id": "mounted_m4a1", - "copy-from": "turret", - "type": "vehicle_part", - "name": { "str": "mounted M4A1" }, - "item": "m4a1", - "breaks_into": [ { "item": "m4a1", "prob": 50 } ], - "requirements": { "install": { "skills": [ [ "mechanics", 3 ] ] }, "removal": { "skills": [ [ "mechanics", 1 ] ] } } - }, { "id": "mounted_m60", "copy-from": "turret", @@ -573,15 +546,6 @@ "breaks_into": [ { "item": "scar_h", "prob": 50 } ], "requirements": { "install": { "skills": [ [ "mechanics", 3 ] ] }, "removal": { "skills": [ [ "mechanics", 1 ] ] } } }, - { - "id": "mounted_scar_l", - "copy-from": "turret", - "type": "vehicle_part", - "name": { "str": "mounted FN SCAR-L" }, - "item": "scar_l", - "breaks_into": [ { "item": "scar_l", "prob": 50 } ], - "requirements": { "install": { "skills": [ [ "mechanics", 3 ] ] }, "removal": { "skills": [ [ "mechanics", 1 ] ] } } - }, { "id": "mounted_shotgun_d", "copy-from": "turret", diff --git a/data/mods/Fuji_Mil_Prof/prof/itemgroups_prof.json b/data/mods/Fuji_Mil_Prof/prof/itemgroups_prof.json index 4e705e6bf5c0c..3c237c4f6d6eb 100644 --- a/data/mods/Fuji_Mil_Prof/prof/itemgroups_prof.json +++ b/data/mods/Fuji_Mil_Prof/prof/itemgroups_prof.json @@ -3,7 +3,7 @@ "type": "item_group", "subtype": "collection", "id": "holster_supp_MEU", - "entries": [ { "item": "m1911_MEU", "ammo-item": "45_acp", "charges": 7, "contents-item": [ "suppressor" ] } ] + "entries": [ { "item": "m1911", "variant": "m1911_MEU", "ammo-item": "45_acp", "charges": 7, "contents-item": [ "suppressor" ] } ] }, { "type": "item_group", diff --git a/data/mods/Generic_Guns/firearms/gg_firearms_migration.json b/data/mods/Generic_Guns/firearms/gg_firearms_migration.json index 76fa0bad19c1a..428c44560049f 100644 --- a/data/mods/Generic_Guns/firearms/gg_firearms_migration.json +++ b/data/mods/Generic_Guns/firearms/gg_firearms_migration.json @@ -86,7 +86,6 @@ "sig_40", "hptjcp", "m1911", - "m1911_MEU", "walther_ppq_45", "hptjhp", "tokarev", @@ -111,7 +110,6 @@ "walther_ppq_40", "tommygun", "usp_45", - "mk23", "fn57", "glock_17", "kpf9", @@ -201,18 +199,12 @@ }, { "id": [ - "h&k416a5", "m1918", "acr_300blk", "hk417_13", - "acr", - "m4a1", - "m16a3", "m16a4", - "m38dmr", - "m4_cqbr", + "nato_assault_rifle", "m231pfw", - "scar_l", "scar_h", "sig_mcx_rattler_sbr", "rm51_assault_rifle", @@ -238,7 +230,7 @@ "replace": "rifle_huge_hmg" }, { - "id": [ "m134", "m249", "m27iar", "m240", "m60", "rm614_lmg", "rm298" ], + "id": [ "m134", "m249", "m240", "m60", "rm614_lmg", "rm298" ], "type": "MIGRATION", "replace": "rifle_lmg" }, diff --git a/data/mods/National_Guard_Camp/item_groups.json b/data/mods/National_Guard_Camp/item_groups.json index 71b4f9af03aa9..0ee98e5838696 100644 --- a/data/mods/National_Guard_Camp/item_groups.json +++ b/data/mods/National_Guard_Camp/item_groups.json @@ -152,7 +152,13 @@ { "group": "robots", "prob": 100 }, { "item": "storage_battery", "prob": 40, "charges-min": 200, "charges-max": 1000 }, { "item": "223", "prob": 20, "charges-min": 10, "charges-max": 30 }, - { "item": "scar_l", "prob": 20, "damage": [ 1, 2 ], "contents-item": [ "stanag30" ] } + { + "item": "nato_assault_rifle", + "variant": "scar_l", + "prob": 20, + "damage": [ 1, 2 ], + "contents-item": [ "stanag30" ] + } ] } ] diff --git a/data/mods/package_bionic_professions/bionic_professions.json b/data/mods/package_bionic_professions/bionic_professions.json index ce95cdd416dd0..e1b6671f659df 100644 --- a/data/mods/package_bionic_professions/bionic_professions.json +++ b/data/mods/package_bionic_professions/bionic_professions.json @@ -483,7 +483,8 @@ { "item": "ear_plugs", "custom-flags": [ "no_auto_equip" ] }, { "item": "sheath", "contents-item": "knife_combat" }, { - "item": "h&k416a5", + "item": "nato_assault_rifle", + "variant": "h&k416a5", "ammo-item": "556", "charges": 30, "contents-item": [ "shoulder_strap", "acog_scope" ] diff --git a/doc/ITEM_SPAWN.md b/doc/ITEM_SPAWN.md index 53817e324d1f8..2e7463624ba2e 100644 --- a/doc/ITEM_SPAWN.md +++ b/doc/ITEM_SPAWN.md @@ -93,6 +93,7 @@ Each entry can have more values (shown above as `...`). They allow further prop "ammo-group": "", "container-group": "", "sealed": +"variant": "artifact": ``` @@ -104,6 +105,8 @@ Each entry can have more values (shown above as `...`). They allow further prop `sealed`: If true, a container will be sealed when the item spawns. Default is `true`. +`variant`: A valid gun variant id for this item. + `artifact`: This object determines that the item or group that is spawned by this entry will become an artifact. Here is an example: ```json "artifact": { "procgen_id": "cult", "rules": { "power_level": 1000, "max_attributes": 5, "max_negative_power": -2000 } } diff --git a/doc/JSON_INFO.md b/doc/JSON_INFO.md index 20dbbaac92b1e..c47be719095e3 100644 --- a/doc/JSON_INFO.md +++ b/doc/JSON_INFO.md @@ -2680,6 +2680,15 @@ Guns can be defined like this: "blackpowder_tolerance": 8,// One in X chance to get clogged up (per shot) when firing blackpowder ammunition (higher is better). Optional, default is 8. "min_cycle_recoil": 0, // Minimum ammo recoil for gun to be able to fire more than once per attack. "burst": 5, // Number of shots fired in burst mode +"variants": [ // Cosmetic variants this gun can have + { + "id": "varianta", // id used in spawning to spawn this variant specifically + "name": { "str": "Variant A pistol" }, // The name used instead of the default name when this variant is selected + "description": "A fancy variant A pistol", // The description used instead of the default when this variant is selected + "ascii_picture": "valid_ascii_art_id", // An ASCII art picture used when this variant is selected. If there is none, the default (if it exists) is used. + "weight": 2 // The relative chance of this variant being selected over other variants when this item is spawned with no explicit variant. Defaults to 0. If it is 0, this variant will not be selected + } +], "clip_size": 100, // Maximum amount of ammo that can be loaded "ups_charges": 0, // Additionally to the normal ammo (if any), a gun can require some charges from an UPS. This also works on mods. Attaching a mod with ups_charges will add/increase ups drain on the weapon. "ammo_to_fire" 1, // Amount of ammo used diff --git a/doc/MAPGEN.md b/doc/MAPGEN.md index 2e765138c9f9b..0724a929dc7f0 100644 --- a/doc/MAPGEN.md +++ b/doc/MAPGEN.md @@ -928,6 +928,7 @@ matching magazine and ammo for guns. | chance | (optional, integer) x in 100 chance of item(s) spawning. Defaults to 100. | ammo | (optional, integer) x in 100 chance of item(s) spawning with the default amount of ammo. Defaults to 0. | magazine | (optional, integer) x in 100 chance of item(s) spawning with the default magazine. Defaults to 0. +| variant | (optional, string), gun variant id for the spawned item ### Plant seeds in a planter with "sealed_item" diff --git a/doc/VEHICLES_JSON.md b/doc/VEHICLES_JSON.md index 0cd720d0c9187..403bfeb9ef866 100644 --- a/doc/VEHICLES_JSON.md +++ b/doc/VEHICLES_JSON.md @@ -70,4 +70,6 @@ TYPE and DATA may be one of: ``` the optional keyword "chance" provides an X in 100 chance that a particular item definition will spawn. +If a single item is specified through `"items"`, a gun variant for it can be specified through `"variant"`. + Multiple lines of items may share the same X and Y values. diff --git a/lang/extract_json_strings.py b/lang/extract_json_strings.py index 4e71e3d7fc231..5f5c9a9b67205 100755 --- a/lang/extract_json_strings.py +++ b/lang/extract_json_strings.py @@ -153,7 +153,6 @@ def warning_supressed(filename): "json_flag", "keybinding", "LOOT_ZONE", - "MAGAZINE", "map_extra", "MOD_INFO", "MONSTER", @@ -476,6 +475,12 @@ def extract_gun(item): if "description" in item: description = item.get("description") writestr(outfile, description) + if "variants" in item: + for variant in item.get("variants"): + vname = variant.get("name") + writestr(outfile, vname, pl_fmt=True) + vdesc = variant.get("description") + writestr(outfile, vdesc) if "modes" in item: modes = item.get("modes") for fire_mode in modes: @@ -490,6 +495,25 @@ def extract_gun(item): if "reload_noise" in item: item_reload_noise = item.get("reload_noise") writestr(outfile, item_reload_noise) + + +def extract_magazine(item): + outfile = get_outfile("magazine") + if "name" in item: + item_name = item.get("name") + if item["type"] in needs_plural: + writestr(outfile, item_name, pl_fmt=True) + else: + writestr(outfile, item_name) + if "description" in item: + description = item.get("description") + writestr(outfile, description) + if "variants" in item: + for variant in item.get("variants"): + vname = variant.get("name") + writestr(outfile, vname, pl_fmt=True) + vdesc = variant.get("description") + writestr(outfile, vdesc) if "use_action" in item: use_action = item.get("use_action") item_name = item.get("name") @@ -976,6 +1000,7 @@ def extract_vehicle_part_category(item): "GUN": extract_gun, "GUNMOD": extract_gunmod, "harvest": extract_harvest, + "MAGAZINE": extract_magazine, "mapgen": extract_mapgen, "martial_art": extract_martial_art, "material": extract_material, diff --git a/src/cata_io.h b/src/cata_io.h index 19f3aeea81bba..93c2ed4d36348 100644 --- a/src/cata_io.h +++ b/src/cata_io.h @@ -292,6 +292,26 @@ class JsonObjectInputArchive : public JsonObject load( ident ); return true; } + /** + * The 'I-give-up' template for gun variant data + */ + template + bool io( const std::string &name, T &pointer, + const LoadFunc &load, + const SaveFunc &save, bool required = false ) { + // Only used by the matching function in the output archive classes. + ( void ) save; + std::string ident; + if( !io( name, ident ) ) { + if( required ) { + JsonObject::throw_error( std::string( "required member is missing: " ) + name ); + } + pointer = nullptr; + return false; + } + load( ident ); + return true; + } template bool io( const std::string &name, T *&pointer, const std::function &load, @@ -421,6 +441,21 @@ class JsonObjectOutputArchive } return io( name, save( *pointer ) ); } + /** + * The I-give-up load function for gun variants + */ + template + bool io( const std::string &name, const T &pointer, + const LoadFunc &, + const SaveFunc &save, bool required = false ) { + if( pointer == nullptr ) { + if( required ) { + throw JsonError( "a required member is null: " + name ); + } + return false; + } + return io( name, save( pointer ) ); + } template bool io( const std::string &name, const T *pointer, const std::function &load, diff --git a/src/item.cpp b/src/item.cpp index bf408b1787282..012a7e7d8f17b 100644 --- a/src/item.cpp +++ b/src/item.cpp @@ -265,6 +265,7 @@ item::item() : bday( calendar::start_of_cataclysm ) type = nullitem(); charges = 0; contents = item_contents( type->pockets ); + select_gun_variant(); } item::item( const itype *type, time_point turn, int qty ) : type( type ), bday( turn ) @@ -290,6 +291,7 @@ item::item( const itype *type, time_point turn, int qty ) : type( type ), bday( set_var( "NANOFAB_ITEM_ID", nanofab_recipe.str() ); } + select_gun_variant(); if( type->gun ) { for( const itype_id &mod : type->gun->built_in_mods ) { item it( mod, turn, qty ); @@ -1014,6 +1016,11 @@ bool item::stacks_with( const item &rhs, bool check_components, bool combine_liq if( is_relic() && rhs.is_relic() && !( *relic_data == *rhs.relic_data ) ) { return false; } + if( has_gun_variant() != rhs.has_gun_variant() || + ( has_gun_variant() && rhs.has_gun_variant() && + gun_variant().id != rhs.gun_variant().id ) ) { + return false; + } if( charges != 0 && rhs.charges != 0 && is_money() ) { // Dealing with nonempty cash cards return true; @@ -1679,6 +1686,8 @@ void item::basic_info( std::vector &info, const iteminfo_query *parts, info.push_back( iteminfo( "DESCRIPTION", snippet.value().translated() ) ); } else if( idescription != item_vars.end() ) { info.push_back( iteminfo( "DESCRIPTION", idescription->second ) ); + } else if( has_gun_variant() ) { + info.push_back( iteminfo( "DESCRIPTION", gun_variant().alt_description.translated() ) ); } else { if( has_flag( flag_MAGIC_FOCUS ) ) { info.push_back( iteminfo( "DESCRIPTION", @@ -4191,7 +4200,10 @@ void item::final_info( std::vector &info, const iteminfo_query *parts, contents_info( info, parts, batch, debug ); if( get_option( "ENABLE_ASCII_ART" ) ) { - const ascii_art_id art = type->picture_id; + ascii_art_id art = type->picture_id; + if( has_gun_variant() && gun_variant().art.is_valid() ) { + art = gun_variant().art; + } if( art.is_valid() ) { for( const std::string &line : art->picture ) { info.push_back( iteminfo( "DESCRIPTION", line ) ); @@ -6785,6 +6797,74 @@ bool item::is_gun() const return !!type->gun; } +void item::select_gun_variant() +{ + weighted_int_list variants; + if( is_gun() ) { + for( const gun_variant_data &gv : type->gun->variants ) { + variants.add( gv.id, gv.weight ); + } + } else if( !!type->magazine ) { + for( const gun_variant_data &gv : type->magazine->variants ) { + variants.add( gv.id, gv.weight ); + } + } else { + return; + } + + const std::string *selected = variants.pick(); + if( !selected ) { + // No variants exist + return; + } + + set_gun_variant( *selected ); +} + +bool item::has_gun_variant( bool check_option ) const +{ + return _gun_variant != nullptr && + ( !check_option || get_option( "SHOW_GUN_VARIANTS" ) ); +} + +const gun_variant_data &item::gun_variant() const +{ + return *_gun_variant; +} + +void item::set_gun_variant( const std::string &variant ) +{ + if( variant.empty() || ( is_gun() && type->gun->variants.empty() ) || ( !!type->magazine && + type->magazine->variants.empty() ) ) { + return; + } + + if( is_gun() ) { + for( const gun_variant_data &option : type->gun->variants ) { + if( option.id == variant ) { + _gun_variant = &option; + return; + } + } + } else if( !!type->magazine ) { + for( const gun_variant_data &option : type->magazine->variants ) { + if( option.id == variant ) { + _gun_variant = &option; + return; + } + } + } else { + return; + } + + debugmsg( "Gun %s has no variant %s!", typeId().str(), variant ); +} + +void item::clear_gun_variant() +{ + _gun_variant = nullptr; +} + bool item::is_firearm() const { return is_gun() && !has_flag( flag_PRIMITIVE_RANGED_WEAPON ); @@ -10463,6 +10543,8 @@ std::string item::type_name( unsigned int quantity ) const } } else if( iter != item_vars.end() ) { return iter->second; + } else if( has_gun_variant() ) { + ret_name = gun_variant().brand_name.translated(); } else { ret_name = type->nname( quantity ); } diff --git a/src/item.h b/src/item.h index f62a7a438f94d..9569cade94e2c 100644 --- a/src/item.h +++ b/src/item.h @@ -51,6 +51,7 @@ class player; class recipe; class relic; struct armor_portion_data; +struct gun_variant_data; struct islot_comestible; struct itype; struct mtype; @@ -1803,6 +1804,27 @@ class item : public visitable */ bool is_gun() const; + /** + * Does this item have a gun variant associated with it + * If check_option, the return of this is dependent on the SHOW_GUN_VARIANTS option + */ + bool has_gun_variant( bool check_option = true ) const; + + /** + * The gun variant associated with this item + */ + const gun_variant_data &gun_variant() const; + + /** + * Set the gun variant of this item + */ + void set_gun_variant( const std::string &variant ); + + /** + * For debug use only + */ + void clear_gun_variant(); + /** Quantity of energy currently loaded in tool or battery */ units::energy energy_remaining() const; @@ -2306,6 +2328,13 @@ class item : public visitable std::string corpse_name; // Name of the late lamented std::set techniques; // item specific techniques + // Select a random variant from the possibilities + // Intended to be called when no explicit variant is set + void select_gun_variant(); + + // If the item has a gun variant, this points to it + const gun_variant_data *_gun_variant = nullptr; + /** * Data for items that represent in-progress crafts. */ diff --git a/src/item_factory.cpp b/src/item_factory.cpp index 8e7c3c998c205..e974b0e910d99 100644 --- a/src/item_factory.cpp +++ b/src/item_factory.cpp @@ -1767,6 +1767,20 @@ void Item_factory::load_wheel( const JsonObject &jo, const std::string &src ) } } +void gun_variant_data::deserialize( JsonIn &jsin ) +{ + load( jsin.get_object() ); +} + +void gun_variant_data::load( const JsonObject &jo ) +{ + mandatory( jo, false, "id", id ); + mandatory( jo, false, "name", brand_name ); + mandatory( jo, false, "description", alt_description ); + optional( jo, false, "ascii_picture", art ); + optional( jo, false, "weight", weight ); +} + void Item_factory::load( islot_gun &slot, const JsonObject &jo, const std::string &src ) { bool strict = src == "dda"; @@ -1801,6 +1815,8 @@ void Item_factory::load( islot_gun &slot, const JsonObject &jo, const std::strin assign( jo, "ammo_effects", slot.ammo_effects, strict ); assign( jo, "ammo_to_fire", slot.ammo_to_fire, strict, 1 ); + optional( jo, false, "variants", slot.variants ); + if( jo.has_array( "valid_mod_locations" ) ) { slot.valid_mod_locations.clear(); for( JsonArray curr : jo.get_array( "valid_mod_locations" ) ) { @@ -2420,6 +2436,8 @@ void Item_factory::load( islot_magazine &slot, const JsonObject &jo, const std:: assign( jo, "default_ammo", slot.default_ammo, strict ); assign( jo, "reload_time", slot.reload_time, strict, 0 ); assign( jo, "linkage", slot.linkage, strict ); + + optional( jo, false, "variants", slot.variants ); } void Item_factory::load_magazine( const JsonObject &jo, const std::string &src ) @@ -3137,6 +3155,7 @@ void Item_factory::load_migration( const JsonObject &jo ) { migration m; assign( jo, "replace", m.replace ); + assign( jo, "variant", m.variant ); assign( jo, "flags", m.flags ); assign( jo, "charges", m.charges ); assign( jo, "contents", m.contents ); @@ -3186,6 +3205,8 @@ void Item_factory::migrate_item( const itype_id &id, item &obj ) obj.charges = iter->second.charges; } + obj.set_gun_variant( iter->second.variant ); + for( const migration::content &it : iter->second.contents ) { int count = it.count; item content( it.id, obj.birthday(), 1 ); @@ -3487,6 +3508,10 @@ void Item_factory::add_entry( Item_group &ig, const JsonObject &obj, const std:: for( const auto &cf : custom_flags ) { modifier.custom_flags.emplace_back( cf ); } + if( obj.has_member( "variant" ) ) { + modifier.variant = obj.get_string( "variant" ); + use_modifier = true; + } if( use_modifier ) { sptr->modifier.emplace( std::move( modifier ) ); diff --git a/src/item_factory.h b/src/item_factory.h index 63d9847e94976..e63ec6784d73e 100644 --- a/src/item_factory.h +++ b/src/item_factory.h @@ -44,6 +44,7 @@ class migration { public: itype_id id; + std::string variant; itype_id replace; std::set flags; int charges = 0; diff --git a/src/item_group.cpp b/src/item_group.cpp index b0cfef5f57ef5..b7bc98a8c8ae4 100644 --- a/src/item_group.cpp +++ b/src/item_group.cpp @@ -391,6 +391,8 @@ void Item_modifier::modify( item &new_item, const std::string &context ) const } } + new_item.set_gun_variant( variant ); + // create container here from modifier or from default to get max charges later item cont; if( container != nullptr ) { @@ -610,11 +612,17 @@ Item_group::Item_group( Type t, int probability, int ammo_chance, int magazine_c } } -void Item_group::add_item_entry( const itype_id &itemid, int probability ) +void Item_group::add_item_entry( const itype_id &itemid, int probability, + const std::string &variant ) { std::string entry_context = "item " + itemid.str() + " within " + context(); - add_entry( std::make_unique( - itemid.str(), Single_item_creator::S_ITEM, probability, entry_context ) ); + std::unique_ptr added = std::make_unique( + itemid.str(), Single_item_creator::S_ITEM, probability, entry_context ); + if( !variant.empty() ) { + added->modifier.emplace(); + added->modifier->variant = variant; + } + add_entry( std::move( added ) ); } void Item_group::add_group_entry( const item_group_id &groupid, int probability ) diff --git a/src/item_group.h b/src/item_group.h index d6c9eae7db489..9987d7f75495f 100644 --- a/src/item_group.h +++ b/src/item_group.h @@ -250,6 +250,11 @@ class Item_modifier */ std::vector custom_flags; + /** + * gun variant id, for guns with variants + */ + std::string variant; + /** * Custom sub set of snippets to be randomly chosen from and then applied to the item. */ @@ -344,7 +349,8 @@ class Item_group : public Item_spawn_data */ using prop_list = std::vector >; - void add_item_entry( const itype_id &itemid, int probability ); + void add_item_entry( const itype_id &itemid, int probability, + const std::string &variant = "" ); void add_group_entry( const item_group_id &groupid, int probability ); /** * Once the relevant data has been read from JSON, this function is always called (either from diff --git a/src/itype.h b/src/itype.h index 471013f573dc6..05c6de659d557 100644 --- a/src/itype.h +++ b/src/itype.h @@ -458,8 +458,21 @@ struct islot_wheel { void deserialize( JsonIn &jsin ); }; +struct gun_variant_data { + std::string id; + translation brand_name; + translation alt_description; + ascii_art_id art; + + int weight = 0; + + void deserialize( JsonIn &jsin ); + void load( const JsonObject &jo ); +}; + // TODO: this shares a lot with the ammo item type, merge into a separate slot type? struct islot_gun : common_ranged_data { + std::vector variants; /** * What skill this gun uses. */ @@ -646,6 +659,7 @@ struct islot_gunmod : common_ranged_data { }; struct islot_magazine { + std::vector variants; /** What type of ammo this magazine can be loaded with */ std::set type; diff --git a/src/map.cpp b/src/map.cpp index 6dd8906f6dbbc..5125e6f4ec4d2 100644 --- a/src/map.cpp +++ b/src/map.cpp @@ -4283,9 +4283,9 @@ void map::spawn_artifact( const tripoint &p, const relic_procgen_id &id ) add_item_or_charges( p, id->create_item( rules ) ); } -void map::spawn_item( const tripoint &p, const itype_id &type_id, - const unsigned quantity, const int charges, - const time_point &birthday, const int damlevel, const std::set &flags ) +void map::spawn_item( const tripoint &p, const itype_id &type_id, const unsigned quantity, + const int charges, const time_point &birthday, const int damlevel, const std::set &flags, + const std::string &variant ) { if( type_id.is_null() ) { return; @@ -4300,6 +4300,7 @@ void map::spawn_item( const tripoint &p, const itype_id &type_id, } // spawn the item item new_item( type_id, birthday ); + new_item.set_gun_variant( variant ); if( one_in( 3 ) && new_item.has_flag( flag_VARSIZE ) ) { new_item.set_flag( flag_FIT ); } diff --git a/src/map.h b/src/map.h index 11a3728a1cd5d..c18cdbf887812 100644 --- a/src/map.h +++ b/src/map.h @@ -1091,12 +1091,13 @@ class map void spawn_item( const tripoint &p, const itype_id &type_id, unsigned quantity = 1, int charges = 0, const time_point &birthday = calendar::start_of_cataclysm, int damlevel = 0, - const std::set &flags = {} ); + const std::set &flags = {}, const std::string &variant = "" ); void spawn_item( const point &p, const itype_id &type_id, unsigned quantity = 1, int charges = 0, const time_point &birthday = calendar::start_of_cataclysm, int damlevel = 0, - const std::set &flags = {} ) { - spawn_item( tripoint( p, abs_sub.z ), type_id, quantity, charges, birthday, damlevel, flags ); + const std::set &flags = {}, const std::string &variant = "" ) { + spawn_item( tripoint( p, abs_sub.z ), type_id, quantity, charges, birthday, damlevel, flags, + variant ); } // FIXME: remove these overloads and require spawn_item to take an @@ -1104,14 +1105,15 @@ class map void spawn_item( const tripoint &p, const std::string &type_id, unsigned quantity = 1, int charges = 0, const time_point &birthday = calendar::start_of_cataclysm, int damlevel = 0, - const std::set &flags = {} ) { - spawn_item( p, itype_id( type_id ), quantity, charges, birthday, damlevel, flags ); + const std::set &flags = {}, const std::string &variant = "" ) { + spawn_item( p, itype_id( type_id ), quantity, charges, birthday, damlevel, flags, variant ); } void spawn_item( const point &p, const std::string &type_id, unsigned quantity = 1, int charges = 0, const time_point &birthday = calendar::start_of_cataclysm, int damlevel = 0, - const std::set &flags = {} ) { - spawn_item( tripoint( p, abs_sub.z ), type_id, quantity, charges, birthday, damlevel, flags ); + const std::set &flags = {}, const std::string &variant = "" ) { + spawn_item( tripoint( p, abs_sub.z ), type_id, quantity, charges, birthday, damlevel, flags, + variant ); } units::volume max_volume( const tripoint &p ); units::volume free_volume( const tripoint &p ); diff --git a/src/mapgen.cpp b/src/mapgen.cpp index 1517e3a0e57a0..03646c4ae5e30 100644 --- a/src/mapgen.cpp +++ b/src/mapgen.cpp @@ -1198,7 +1198,11 @@ class jmapgen_loot : public jmapgen_piece if( group.is_empty() ) { // Migrations are applied to item *groups* on load, but single item spawns must be // migrated individually - result_group.add_item_entry( item_controller->migrate_id( ity ), 100 ); + std::string variant; + if( jsi.has_string( "variant" ) ) { + variant = jsi.get_string( "variant" ); + } + result_group.add_item_entry( item_controller->migrate_id( ity ), 100, variant ); } else { result_group.add_group_entry( group, 100 ); } @@ -1424,6 +1428,7 @@ class jmapgen_spawn_item : public jmapgen_piece { public: itype_id type; + std::string variant; jmapgen_int amount; jmapgen_int chance; std::set flags; @@ -1432,6 +1437,9 @@ class jmapgen_spawn_item : public jmapgen_piece , amount( jsi, "amount", 1, 1 ) , chance( jsi, "chance", 100, 100 ) , flags( jsi.get_tags( "custom-flags" ) ) { + if( jsi.has_string( "variant" ) ) { + variant = jsi.get_string( "variant" ); + } // Itemgroups apply migrations when being loaded, but we need to migrate // individual items here. type = item_controller->migrate_id( type ); @@ -1449,7 +1457,7 @@ class jmapgen_spawn_item : public jmapgen_piece int spawn_count = ( c == 100 ) ? 1 : roll_remainder( c * spawn_rate / 100.0f ); for( int i = 0; i < spawn_count; i++ ) { dat.m.spawn_item( point( x.get(), y.get() ), type, amount.get(), - 0, calendar::start_of_cataclysm, 0, flags ); + 0, calendar::start_of_cataclysm, 0, flags, variant ); } } }; diff --git a/src/options.cpp b/src/options.cpp index da73223a8ce19..9eccc576b928d 100644 --- a/src/options.cpp +++ b/src/options.cpp @@ -1399,6 +1399,16 @@ void options_manager::add_options_interface() add_empty_line(); + add( "SHOW_GUN_VARIANTS", "interface", to_translation( "Show gun brand names" ), + to_translation( "Show brand names for guns, intead of generic functional names - 'm4a1' or 'h&k416a5' instead of 'NATO assault rifle'." ), + false ); + add( "AMMO_IN_NAMES", "interface", to_translation( "Add ammo to weapon/magazine names" ), + to_translation( "If true, the default ammo is added to weapon and magazine names. For example \"Mosin-Nagant M44 (4/5)\" becomes \"Mosin-Nagant M44 (4/5 7.62x54mm)\"." ), + true + ); + + add_empty_line(); + add( "SDL_KEYBOARD_MODE", "interface", to_translation( "Use key code input mode" ), to_translation( "Use key code or symbol input on SDL. " "Symbol is recommended for non-qwerty layouts since currently " @@ -1651,10 +1661,6 @@ void options_manager::add_options_interface() to_translation( "If true, show item symbols in inventory and pick up menu." ), false ); - add( "AMMO_IN_NAMES", "interface", to_translation( "Add ammo to weapon/magazine names" ), - to_translation( "If true, the default ammo is added to weapon and magazine names. For example \"Mosin-Nagant M44 (4/5)\" becomes \"Mosin-Nagant M44 (4/5 7.62x54mm)\"." ), - true - ); add_empty_line(); diff --git a/src/savegame_json.cpp b/src/savegame_json.cpp index 3f6e79ff311e9..0230396e9c70a 100644 --- a/src/savegame_json.cpp +++ b/src/savegame_json.cpp @@ -2470,6 +2470,13 @@ void item::io( Archive &archive ) return i.id.str(); } ); archive.io( "craft_data", craft_data_, decltype( craft_data_ )() ); + const auto gvload = [this]( const std::string & variant ) { + set_gun_variant( variant ); + }; + const auto gvsave = []( const gun_variant_data * gv ) { + return gv->id; + }; + archive.io( "variant", _gun_variant, gvload, gvsave, false ); archive.io( "light", light.luminance, nolight.luminance ); archive.io( "light_width", light.width, nolight.width ); archive.io( "light_dir", light.direction, nolight.direction ); diff --git a/src/veh_type.cpp b/src/veh_type.cpp index 006935b9c11a8..1af5c6fe09cca 100644 --- a/src/veh_type.cpp +++ b/src/veh_type.cpp @@ -1162,7 +1162,13 @@ void vehicle_prototype::load( const JsonObject &jo ) spawn_info.read( "items", next_spawn.item_ids, true ); } else if( spawn_info.has_string( "items" ) ) { //Treat single item as array - next_spawn.item_ids.push_back( itype_id( spawn_info.get_string( "items" ) ) ); + // And read the gun variant (if it exists) + if( spawn_info.has_string( "variant" ) ) { + const std::string variant = spawn_info.get_string( "variant" ); + next_spawn.variant_ids.emplace_back( itype_id( spawn_info.get_string( "items" ) ), variant ); + } else { + next_spawn.item_ids.push_back( itype_id( spawn_info.get_string( "items" ) ) ); + } } if( spawn_info.has_array( "item_groups" ) ) { //Pick from a group of items, just like map::place_items diff --git a/src/veh_type.h b/src/veh_type.h index 475bd7b5cc5b9..923a3d2677d24 100644 --- a/src/veh_type.h +++ b/src/veh_type.h @@ -474,6 +474,8 @@ struct vehicle_item_spawn { /** Chance [0-100%] for items to spawn with their default magazine (if any) */ int with_magazine = 0; std::vector item_ids; + // item_ids, but for items with variants specified + std::vector> variant_ids; std::vector item_groups; }; diff --git a/src/vehicle.cpp b/src/vehicle.cpp index 0063764704479..bacabf0432ed8 100644 --- a/src/vehicle.cpp +++ b/src/vehicle.cpp @@ -5473,7 +5473,7 @@ void vehicle::place_spawn_items() } const float spawn_rate = get_option( "ITEM_SPAWNRATE" ); - for( const vehicle_item_spawn &spawn : type.obj().item_spawns ) { + for( const vehicle_item_spawn &spawn : type->item_spawns ) { int part = part_with_feature( spawn.pos, "CARGO", false ); if( part < 0 ) { debugmsg( "No CARGO parts at (%d, %d) of %s!", spawn.pos.x, spawn.pos.y, name ); @@ -5493,6 +5493,13 @@ void vehicle::place_spawn_items() created.emplace_back( item( e ).in_its_container() ); } } + for( const std::pair &e : spawn.variant_ids ) { + if( rng_float( 0, 1 ) < spawn_rate ) { + item added = item( e.first ).in_its_container(); + added.set_gun_variant( e.second ); + created.push_back( added ); + } + } for( const item_group_id &e : spawn.item_groups ) { item_group::ItemList group_items = item_group::items_from( e, calendar::start_of_cataclysm, spawn_flags::use_spawn_rate ); diff --git a/src/wish.cpp b/src/wish.cpp index 0ca3fbe0cfd89..cc288a1922e9a 100644 --- a/src/wish.cpp +++ b/src/wish.cpp @@ -601,7 +601,10 @@ void debug_menu::wishitem( player *p, const tripoint &pos ) } std::vector> opts; for( const itype *i : item_controller->all() ) { - opts.emplace_back( item( i, calendar::turn_zero ).tname( 1, false ), i ); + item option( i, calendar::turn_zero ); + // Only display the generic name if it has variants + option.clear_gun_variant(); + opts.emplace_back( option.tname( 1, false ), i ); } std::sort( opts.begin(), opts.end(), localized_compare ); std::vector itypes; diff --git a/tests/pocket_test.cpp b/tests/pocket_test.cpp index 490134c2426ce..aa9e60002b537 100644 --- a/tests/pocket_test.cpp +++ b/tests/pocket_test.cpp @@ -1335,7 +1335,7 @@ TEST_CASE( "character best pocket", "[pocket][character][best]" ) TEST_CASE( "guns and gunmods", "[pocket][gunmod]" ) { - item m4a1( "m4a1" ); + item m4a1( "nato_assault_rifle" ); item strap( "shoulder_strap" ); // Guns cannot "contain" gunmods, but gunmods can be inserted into guns CHECK_FALSE( m4a1.contents.can_contain( strap ).success() ); diff --git a/tests/reload_magazine_test.cpp b/tests/reload_magazine_test.cpp index c9bd8ce63a3cf..a598812d2397f 100644 --- a/tests/reload_magazine_test.cpp +++ b/tests/reload_magazine_test.cpp @@ -19,7 +19,7 @@ struct itype; TEST_CASE( "reload_magazine", "[magazine] [visitable] [item] [item_location]" ) { - const itype_id gun_id( "m4a1" ); + const itype_id gun_id( "nato_assault_rifle" ); const ammotype gun_ammo( "223" ); const itype_id ammo_id( "556" ); // any type of compatible ammo const itype_id alt_ammo( "223" ); // any alternative type of compatible ammo From 1aaba6942ab8188567d124a0422c452e67cc99aa Mon Sep 17 00:00:00 2001 From: Bella Date: Sat, 27 Feb 2021 11:19:18 -0600 Subject: [PATCH 095/453] Turbine CBM Obsoletion (#47774) --- data/mods/Aftershock/itemgroups/bionics_groups.json | 6 ++---- data/mods/Aftershock/items/cbms.json | 9 --------- data/mods/Aftershock/items/obsolete.json | 9 +++++++++ data/mods/Aftershock/player/bionics.json | 11 ----------- data/mods/Aftershock/player/obsolete.json | 11 +++++++++++ 5 files changed, 22 insertions(+), 24 deletions(-) diff --git a/data/mods/Aftershock/itemgroups/bionics_groups.json b/data/mods/Aftershock/itemgroups/bionics_groups.json index f5fd0cd54948a..d264c170db869 100644 --- a/data/mods/Aftershock/itemgroups/bionics_groups.json +++ b/data/mods/Aftershock/itemgroups/bionics_groups.json @@ -4,7 +4,6 @@ "type": "item_group", "items": [ [ "bn_bio_solar", 10 ], - [ "afs_bio_wind_turbine", 5 ], [ "afs_bio_missiles", 10 ], [ "afs_bio_linguistic_coprocessor", 10 ], [ "afs_bio_dopamine_stimulators", 10 ], @@ -16,7 +15,7 @@ { "id": "bionics_common", "type": "item_group", - "items": [ [ "bn_bio_solar", 10 ], [ "afs_bio_wind_turbine", 5 ], [ "afs_bio_linguistic_coprocessor", 8 ] ] + "items": [ [ "bn_bio_solar", 10 ], [ "afs_bio_linguistic_coprocessor", 8 ] ] }, { "id": "bionics_mil", @@ -32,14 +31,13 @@ { "id": "bionics_sci", "type": "item_group", - "items": [ [ "bn_bio_solar", 5 ], [ "afs_bio_wind_turbine", 2 ] ] + "items": [ [ "bn_bio_solar", 5 ] ] }, { "id": "bionics_op", "type": "item_group", "items": [ [ "bn_bio_solar", 15 ], - [ "afs_bio_wind_turbine", 10 ], [ "afs_bio_missiles", 10 ], [ "afs_bio_melee_counteraction", 10 ], [ "afs_bio_melee_optimization_unit", 10 ], diff --git a/data/mods/Aftershock/items/cbms.json b/data/mods/Aftershock/items/cbms.json index 627339be2c031..77695b5adf4eb 100644 --- a/data/mods/Aftershock/items/cbms.json +++ b/data/mods/Aftershock/items/cbms.json @@ -8,15 +8,6 @@ "price": 350000, "difficulty": 4 }, - { - "id": "afs_bio_wind_turbine", - "copy-from": "bionic_general", - "type": "BIONIC_ITEM", - "name": { "str": "Wind Turbine CBM" }, - "description": "Installed on your body is a set of small retractable wind turbines. When activated, they will deploy and slowly harvest wind power to recharge your power level.", - "price": 350000, - "difficulty": 4 - }, { "id": "afs_bio_missiles", "copy-from": "bionic_general", diff --git a/data/mods/Aftershock/items/obsolete.json b/data/mods/Aftershock/items/obsolete.json index a2193f7e28f8c..4a8398257ceae 100644 --- a/data/mods/Aftershock/items/obsolete.json +++ b/data/mods/Aftershock/items/obsolete.json @@ -621,6 +621,15 @@ "intelligence": 5, "time": "18 m" }, + { + "id": "afs_bio_wind_turbine", + "copy-from": "bionic_general", + "type": "BIONIC_ITEM", + "name": { "str": "Wind Turbine CBM" }, + "description": "Installed on your body is a set of small retractable wind turbines. When activated, they will deploy and slowly harvest wind power to recharge your power level.", + "price": 350000, + "difficulty": 4 + }, { "id": "afs_brigandine_crafted", "type": "ARMOR", diff --git a/data/mods/Aftershock/player/bionics.json b/data/mods/Aftershock/player/bionics.json index 3b97dcc2f612b..13ba381a399e8 100644 --- a/data/mods/Aftershock/player/bionics.json +++ b/data/mods/Aftershock/player/bionics.json @@ -10,17 +10,6 @@ "time": 1, "flags": [ "BIONIC_POWER_SOURCE", "BIONIC_TOGGLED" ] }, - { - "id": "afs_bio_wind_turbine", - "type": "bionic", - "name": { "str": "Wind Turbines" }, - "description": "Installed on your body is a set of small retractable wind turbines. When activated, they will deploy and slowly harvest wind power to recharge your power level.", - "occupied_bodyparts": [ [ "torso", 10 ] ], - "fuel_options": [ "wind" ], - "fuel_efficiency": 0.25, - "time": 1, - "flags": [ "BIONIC_POWER_SOURCE", "BIONIC_TOGGLED" ] - }, { "id": "afs_bio_missiles", "type": "bionic", diff --git a/data/mods/Aftershock/player/obsolete.json b/data/mods/Aftershock/player/obsolete.json index 2343e05286a9b..e99c10a9aba5d 100644 --- a/data/mods/Aftershock/player/obsolete.json +++ b/data/mods/Aftershock/player/obsolete.json @@ -6,5 +6,16 @@ "description": "Your hands have been outfitted with precise soldering tools, wire cutters, and cable spools. They're too small to use in most crafting, but in the absence of proper machinery, they're essential for creating bionics without better tools.", "occupied_bodyparts": [ [ "hand_l", 1 ], [ "hand_r", 1 ] ], "fake_item": "afs_solderers_item" + }, + { + "id": "afs_bio_wind_turbine", + "type": "bionic", + "name": { "str": "Wind Turbines" }, + "description": "Installed on your body is a set of small retractable wind turbines. When activated, they will deploy and slowly harvest wind power to recharge your power level.", + "occupied_bodyparts": [ [ "torso", 10 ] ], + "fuel_options": [ "wind" ], + "fuel_efficiency": 0.25, + "time": 1, + "flags": [ "BIONIC_POWER_SOURCE", "BIONIC_TOGGLED" ] } ] From 4ad396820cdcbb3fe85eec66b86c8e752992ba08 Mon Sep 17 00:00:00 2001 From: LordMadness <45457447+LordMadness@users.noreply.github.com> Date: Thu, 25 Mar 2021 04:28:14 -0300 Subject: [PATCH 096/453] NPC Interaction Tweak (#47819) --- data/json/npcs/TALK_COMMON_ALLY.json | 107 ++++++++++++++++----------- 1 file changed, 62 insertions(+), 45 deletions(-) diff --git a/data/json/npcs/TALK_COMMON_ALLY.json b/data/json/npcs/TALK_COMMON_ALLY.json index 9c94ae2484536..35f7ea07a2ff6 100644 --- a/data/json/npcs/TALK_COMMON_ALLY.json +++ b/data/json/npcs/TALK_COMMON_ALLY.json @@ -163,12 +163,6 @@ "topic": "TALK_FRIEND_GUARD", "effect": "assign_guard" }, - { - "text": "I want to assign you to work at this camp.", - "condition": { "npc_at_om_location": "FACTION_CAMP_ANY" }, - "topic": "TALK_FRIEND_GUARD", - "effect": "assign_camp" - }, { "text": "Find a horse and mount up!", "condition": { "not": "npc_is_riding" }, @@ -181,46 +175,8 @@ "topic": "TALK_DONE", "effect": "dismount" }, - { - "text": "Please go to this location.", - "topic": "TALK_GOTO_LOCATION", - "condition": { "or": [ "is_by_radio", "u_has_camp" ] }, - "effect": "goto_location" - }, - { - "text": "I want you to build a camp here.", - "topic": "TALK_HALLU_CAMP", - "condition": { "npc_has_trait": "HALLUCINATION" }, - "switch": true - }, - { - "text": "I want you to build a camp here.", - "topic": "TALK_DONE", - "effect": "start_camp", - "condition": { "npc_at_om_location": "FACTION_CAMP_START" }, - "switch": true, - "default": true - }, - { - "text": "Since we can't build a camp here, I want you to tell me where can we build a camp?", - "topic": "TALK_CAMP_SITES", - "condition": { "not": { "npc_at_om_location": "FACTION_CAMP_START" } }, - "switch": true, - "default": true - }, - { - "text": "We need to abandon this camp.", - "condition": { "npc_at_om_location": "FACTION_CAMP_ANY" }, - "topic": "TALK_DONE", - "effect": "abandon_camp" - }, - { - "text": "Show me what needs to be done at the camp.", - "topic": "TALK_DONE", - "effect": "basecamp_mission", - "condition": { "npc_at_om_location": "FACTION_CAMP_ANY" } - }, { "text": "Let's talk about your current activity.", "topic": "TALK_ACTIVITIES" }, + { "text": "Let's talk about the camp.", "topic": "TALK_CAMP" }, { "text": "Let's go.", "topic": "TALK_DONE" } ] }, @@ -931,5 +887,66 @@ "type": "talk_topic", "dynamic_line": "", "responses": [ { "text": "Fair enough.", "topic": "TALK_NONE" } ] + }, + { + "id": "TALK_CAMP", + "type": "talk_topic", + "dynamic_line": "What about the camp?", + "responses": [ + { + "text": "I want to assign you to work at this camp.", + "condition": { "npc_at_om_location": "FACTION_CAMP_ANY" }, + "topic": "TALK_FRIEND_GUARD", + "effect": "assign_camp" + }, + { + "text": "Please go to this location.", + "topic": "TALK_GOTO_LOCATION", + "condition": { "or": [ "is_by_radio", "u_has_camp" ] }, + "effect": "goto_location" + }, + { + "text": "I want you to build a camp here.", + "topic": "TALK_HALLU_CAMP", + "condition": { "npc_has_trait": "HALLUCINATION" }, + "switch": true + }, + { + "text": "I want you to build a camp here.", + "topic": "TALK_DONE", + "effect": "start_camp", + "condition": { "npc_at_om_location": "FACTION_CAMP_START" }, + "switch": true, + "default": true + }, + { + "text": "Since we can't build a camp here, I want you to tell me where can we build a camp?", + "topic": "TALK_CAMP_SITES", + "condition": { "not": { "npc_at_om_location": "FACTION_CAMP_START" } }, + "switch": true, + "default": true + }, + { + "text": "We need to abandon this camp.", + "condition": { "npc_at_om_location": "FACTION_CAMP_ANY" }, + "topic": "TALK_ABANDON" + }, + { + "text": "Show me what needs to be done at the camp.", + "topic": "TALK_DONE", + "effect": "basecamp_mission", + "condition": { "npc_at_om_location": "FACTION_CAMP_ANY" } + }, + { "text": "Never mind.", "topic": "TALK_NONE" } + ] + }, + { + "id": "TALK_ABANDON", + "type": "talk_topic", + "dynamic_line": "Are you sure?", + "responses": [ + { "text": "Yes, I'm sure.", "topic": "TALK_DONE", "effect": "abandon_camp" }, + { "text": "Actually, never mind.", "topic": "TALK_NONE" } + ] } ] From cfb68d583eda3f25177dce2bc57016c1b5a1fa73 Mon Sep 17 00:00:00 2001 From: Jamuro-g Date: Mon, 1 Mar 2021 21:11:49 +0100 Subject: [PATCH 097/453] Added warning when removing gunmods (#47816) --- src/iuse_actor.cpp | 10 +++++++--- 1 file changed, 7 insertions(+), 3 deletions(-) diff --git a/src/iuse_actor.cpp b/src/iuse_actor.cpp index 8b9d9f21697e9..7fe106e1d2066 100644 --- a/src/iuse_actor.cpp +++ b/src/iuse_actor.cpp @@ -3929,9 +3929,13 @@ cata::optional detach_gunmods_actor::use( player &p, item &it, bool, const if( prompt.ret >= 0 ) { gun_copy.remove_item( *mods_copy[prompt.ret] ); - if( game_menus::inv::compare_items( it, gun_copy, _( "Remove modification?" ) ) ) { - p.gunmod_remove( it, *mods[ prompt.ret ] ); - return 0; + if( p.meets_requirements( *mods[prompt.ret], gun_copy ) || + query_yn( _( "Are you sure? You may be lacking the skills needed to reattach this modification." ) ) ) { + + if( game_menus::inv::compare_items( it, gun_copy, _( "Remove modification?" ) ) ) { + p.gunmod_remove( it, *mods[prompt.ret] ); + return 0; + } } } From a7adff64545dda3d5f3d5664fcbe34f0a7bbe79b Mon Sep 17 00:00:00 2001 From: Jamuro-g <76928284+Jamuro-g@users.noreply.github.com> Date: Thu, 25 Mar 2021 08:29:39 +0100 Subject: [PATCH 098/453] Added vehicle racking activity (#47557) --- data/json/player_activities.json | 22 +++++++++ src/activity_actor.cpp | 85 ++++++++++++++++++++++++++++++++ src/activity_actor_definitions.h | 57 +++++++++++++++++++++ src/vehicle.cpp | 9 +++- src/vehicle.h | 4 +- src/vehicle_use.cpp | 37 +++++++------- 6 files changed, 194 insertions(+), 20 deletions(-) diff --git a/data/json/player_activities.json b/data/json/player_activities.json index c5558ddf87138..3ced2d6de6b7b 100644 --- a/data/json/player_activities.json +++ b/data/json/player_activities.json @@ -74,6 +74,28 @@ "no_resume": true, "multi_activity": true }, + { + "id": "ACT_BIKERACK_RACKING", + "type": "activity_type", + "activity_level": "MODERATE_EXERCISE", + "verb": "mounting a vehicle onto rack", + "rooted": true, + "based_on": "time", + "no_resume": true, + "refuel_fires": false, + "auto_needs": false + }, + { + "id": "ACT_BIKERACK_UNRACKING", + "type": "activity_type", + "activity_level": "MODERATE_EXERCISE", + "verb": "taking a vehicle from rack", + "rooted": true, + "based_on": "time", + "no_resume": true, + "refuel_fires": false, + "auto_needs": false + }, { "id": "ACT_MULTIPLE_CHOP_PLANKS", "type": "activity_type", diff --git a/src/activity_actor.cpp b/src/activity_actor.cpp index 69d6dbd6bb27c..de092f22e6349 100644 --- a/src/activity_actor.cpp +++ b/src/activity_actor.cpp @@ -938,6 +938,89 @@ std::unique_ptr hotwire_car_activity_actor::deserialize( JsonIn return actor.clone(); } +void bikerack_racking_activity_actor::start( player_activity &act, Character & ) +{ + act.moves_total = moves_total; + act.moves_left = moves_total; +} + +void bikerack_racking_activity_actor::finish( player_activity &act, Character & ) +{ + if( parent_vehicle.try_to_rack_nearby_vehicle( parts ) ) { + map &here = get_map(); + here.invalidate_map_cache( here.get_abs_sub().z ); + here.rebuild_vehicle_level_caches(); + } else { + debugmsg( "Racking task failed. Parent-Vehicle:" + parent_vehicle.name + + "; Found parts size:" + std::to_string( parts[0].size() ) ); + } + act.set_to_null(); +} + +void bikerack_racking_activity_actor::serialize( JsonOut &jsout ) const +{ + jsout.start_object(); + jsout.member( "moves_total", moves_total ); + jsout.member( "parent_vehicle", parent_vehicle ); + jsout.member( "parts", parts ); + jsout.end_object(); +} + +std::unique_ptr bikerack_racking_activity_actor::deserialize( JsonIn &jsin ) +{ + vehicle veh; + bikerack_racking_activity_actor actor( 0, veh, std::vector>() ); + JsonObject data = jsin.get_object(); + data.read( "moves_total", actor.moves_total ); + data.read( "parent_vehicle", actor.parent_vehicle ); + data.read( "parts", actor.parts ); + + return actor.clone(); +} + +void bikerack_unracking_activity_actor::start( player_activity &act, Character & ) +{ + act.moves_total = moves_total; + act.moves_left = moves_total; +} + +void bikerack_unracking_activity_actor::finish( player_activity &act, Character & ) +{ + if( parent_vehicle.remove_carried_vehicle( parts ) ) { + parent_vehicle.clear_bike_racks( racks ); + map &here = get_map(); + here.invalidate_map_cache( here.get_abs_sub().z ); + here.rebuild_vehicle_level_caches(); + } else { + debugmsg( "Unracking task failed. Parent-Vehicle:" + parent_vehicle.name + + "; Found parts size:" + std::to_string( parts.size() ) ); + } + act.set_to_null(); +} + +void bikerack_unracking_activity_actor::serialize( JsonOut &jsout ) const +{ + jsout.start_object(); + jsout.member( "moves_total", moves_total ); + jsout.member( "parent_vehicle", parent_vehicle ); + jsout.member( "parts", parts ); + jsout.member( "racks", racks ); + jsout.end_object(); +} + +std::unique_ptr bikerack_unracking_activity_actor::deserialize( JsonIn &jsin ) +{ + vehicle veh; + bikerack_unracking_activity_actor actor( 0, veh, std::vector(), std::vector() ); + JsonObject data = jsin.get_object(); + data.read( "moves_total", actor.moves_total ); + data.read( "parent_vehicle", actor.parent_vehicle ); + data.read( "parts", actor.parts ); + data.read( "racks", actor.racks ); + + return actor.clone(); +} + void move_items_activity_actor::do_turn( player_activity &act, Character &who ) { const tripoint dest = relative_destination + who.pos(); @@ -2787,6 +2870,8 @@ const std::unordered_map( * )( Json deserialize_functions = { { activity_id( "ACT_AIM" ), &aim_activity_actor::deserialize }, { activity_id( "ACT_AUTODRIVE" ), &autodrive_activity_actor::deserialize }, + { activity_id( "ACT_BIKERACK_RACKING" ), &bikerack_racking_activity_actor::deserialize }, + { activity_id( "ACT_BIKERACK_UNRACKING" ), &bikerack_unracking_activity_actor::deserialize }, { activity_id( "ACT_CONSUME" ), &consume_activity_actor::deserialize }, { activity_id( "ACT_CRAFT" ), &craft_activity_actor::deserialize }, { activity_id( "ACT_DIG" ), &dig_activity_actor::deserialize }, diff --git a/src/activity_actor_definitions.h b/src/activity_actor_definitions.h index 654363d84cbb9..e2a814625a99b 100644 --- a/src/activity_actor_definitions.h +++ b/src/activity_actor_definitions.h @@ -22,6 +22,7 @@ #include "type_id.h" #include "units.h" #include "units_fwd.h" +#include "vehicle.h" #include "activity_actor.h" @@ -341,6 +342,62 @@ class hotwire_car_activity_actor : public activity_actor static std::unique_ptr deserialize( JsonIn &jsin ); }; +class bikerack_racking_activity_actor : public activity_actor +{ + private: + int moves_total; + vehicle &parent_vehicle; + std::vector> parts; + public: + bikerack_racking_activity_actor( int moves_total, vehicle &parent_vehicle, + std::vector> parts ): moves_total( moves_total ), + parent_vehicle( parent_vehicle ), parts( parts ) {} + + activity_id get_type() const override { + return activity_id( "ACT_BIKERACK_RACKING" ); + } + + void start( player_activity &act, Character & ) override; + void do_turn( player_activity &, Character & ) override {} + void finish( player_activity &act, Character & ) override; + + std::unique_ptr clone() const override { + return std::make_unique( *this ); + } + + void serialize( JsonOut &jsout ) const override; + static std::unique_ptr deserialize( JsonIn &jsin ); +}; + +class bikerack_unracking_activity_actor : public activity_actor +{ + private: + int moves_total; + vehicle &parent_vehicle; + std::vector parts; + std::vector racks; + + public: + bikerack_unracking_activity_actor( int moves_total, vehicle &parent_vehicle, + std::vector parts, std::vector racks ) : moves_total( moves_total ), + parent_vehicle( parent_vehicle ), parts( parts ), racks( racks ) {} + + activity_id get_type() const override { + return activity_id( "ACT_BIKERACK_UNRACKING" ); + } + + void start( player_activity &act, Character & ) override; + void do_turn( player_activity &, Character & ) override {} + void finish( player_activity &act, Character & ) override; + + std::unique_ptr clone() const override { + return std::make_unique( *this ); + } + + void serialize( JsonOut &jsout ) const override; + static std::unique_ptr deserialize( JsonIn &jsin ); +}; + class move_items_activity_actor : public activity_actor { private: diff --git a/src/vehicle.cpp b/src/vehicle.cpp index bacabf0432ed8..bab24e12ea761 100644 --- a/src/vehicle.cpp +++ b/src/vehicle.cpp @@ -1654,7 +1654,8 @@ int vehicle::install_part( const point &dp, const vehicle_part &new_part ) return parts.size() - 1; } -bool vehicle::try_to_rack_nearby_vehicle( std::vector> &list_of_racks ) +bool vehicle::try_to_rack_nearby_vehicle( std::vector> &list_of_racks, + bool do_not_rack ) { map &here = get_map(); for( std::vector &this_bike_rack : list_of_racks ) { @@ -1685,7 +1686,11 @@ bool vehicle::try_to_rack_nearby_vehicle( std::vector> &list_of } partial_matches[ i ].insert( search_pos ); if( partial_matches[ i ] == test_veh->get_points() ) { - return merge_rackable_vehicle( test_veh, this_bike_rack ); + if( do_not_rack ) { + return true; + } else { + return merge_rackable_vehicle( test_veh, this_bike_rack ); + } } ++i; } diff --git a/src/vehicle.h b/src/vehicle.h index 220f5cdbf3752..1232f2233671a 100644 --- a/src/vehicle.h +++ b/src/vehicle.h @@ -907,7 +907,8 @@ class vehicle const std::string &variant = "", bool force = false ); // find a single tile wide vehicle adjacent to a list of part indices - bool try_to_rack_nearby_vehicle( std::vector> &list_of_racks ); + bool try_to_rack_nearby_vehicle( std::vector> &list_of_racks, + bool do_not_rack = false ); // merge a previously found single tile vehicle into this vehicle bool merge_rackable_vehicle( vehicle *carry_veh, const std::vector &rack_parts ); @@ -1780,6 +1781,7 @@ class vehicle void use_dishwasher( int p ); void use_monster_capture( int part, const tripoint &pos ); void use_bike_rack( int part ); + void clear_bike_racks( std::vector &racks ); void use_harness( int part, const tripoint &pos ); void interact_with( const vpart_position &vp ); diff --git a/src/vehicle_use.cpp b/src/vehicle_use.cpp index d8db2d2b6137f..ad7a282830213 100644 --- a/src/vehicle_use.cpp +++ b/src/vehicle_use.cpp @@ -1940,14 +1940,14 @@ void vehicle::use_bike_rack( int part ) full_rack &= carry_size == rack_parts.size(); } int unload_carried = full_rack ? 0 : -1; - bool success = false; - + bool found_rackable_vehicle = try_to_rack_nearby_vehicle( racks_parts, true ); validate_carried_vehicles( carried_vehicles ); validate_carried_vehicles( carrying_racks ); - if( found_vehicle && !full_rack ) { uilist rack_menu; - rack_menu.addentry( 0, true, '0', _( "Load a vehicle on the rack" ) ); + if( found_rackable_vehicle ) { + rack_menu.addentry( 0, true, '0', _( "Load a vehicle on the rack" ) ); + } for( size_t i = 0; i < carried_vehicles.size(); i++ ) { rack_menu.addentry( i + 1, true, '1' + i, string_format( _( "Remove the %s from the rack" ), @@ -1956,21 +1956,24 @@ void vehicle::use_bike_rack( int part ) rack_menu.query(); unload_carried = rack_menu.ret - 1; } + + player_activity new_act; if( unload_carried > -1 ) { - success = remove_carried_vehicle( carried_vehicles[unload_carried] ); - if( success ) { - for( const int &rack_part : carrying_racks[unload_carried] ) { - parts[ rack_part ].remove_flag( vehicle_part::carrying_flag ); - parts[rack_part].remove_flag( vehicle_part::tracked_flag ); - } - } - } else { - success = try_to_rack_nearby_vehicle( racks_parts ); + new_act = player_activity( bikerack_unracking_activity_actor( to_moves( 5_minutes ), *this, + carried_vehicles[unload_carried], carrying_racks[unload_carried] ) ); + get_player_character().assign_activity( new_act, false ); + } else if( found_rackable_vehicle ) { + new_act = player_activity( bikerack_racking_activity_actor( to_moves( 5_minutes ), *this, + racks_parts ) ); + get_player_character().assign_activity( new_act, false ); } - if( success ) { - map &here = get_map(); - here.invalidate_map_cache( here.get_abs_sub().z ); - here.rebuild_vehicle_level_caches(); +} + +void vehicle::clear_bike_racks( std::vector &racks ) +{ + for( const int &rack_part : racks ) { + parts[rack_part].remove_flag( vehicle_part::carrying_flag ); + parts[rack_part].remove_flag( vehicle_part::tracked_flag ); } } From 65afcb93faa726bb934875bc5d653fa9ff4edf3a Mon Sep 17 00:00:00 2001 From: Eric <52087122+Ramza13@users.noreply.github.com> Date: Thu, 25 Mar 2021 03:33:41 -0400 Subject: [PATCH 099/453] Get bionic tools to use power as charges (#47694) --- data/json/bionics.json | 6 ++- data/json/items/fake.json | 4 +- src/activity_actor.cpp | 42 +++---------------- src/activity_actor_definitions.h | 6 --- src/character.cpp | 69 +++++++++++++++++--------------- src/character.h | 2 +- src/iexamine.cpp | 36 ++--------------- src/visitable.cpp | 9 ++--- 8 files changed, 56 insertions(+), 118 deletions(-) diff --git a/data/json/bionics.json b/data/json/bionics.json index 205e9072af9c4..a542a422ccf49 100644 --- a/data/json/bionics.json +++ b/data/json/bionics.json @@ -480,7 +480,9 @@ "type": "bionic", "name": { "str": "Fingerhack" }, "description": "One of your fingers has an electrohack surgically embedded in it; an all-purpose hacking unit used to override control panels and the like (but not computers). Skill in computers is important, and a failed use may damage your circuits.", - "occupied_bodyparts": [ [ "hand_r", 2 ] ] + "occupied_bodyparts": [ [ "hand_r", 2 ] ], + "fake_item": "electrohack", + "flags": [ "BIONIC_TOGGLED" ] }, { "id": "bio_flashbang", @@ -663,7 +665,7 @@ "description": "The index fingers of both hands have powerful fire starters which extend from the tip.", "occupied_bodyparts": [ [ "hand_l", 1 ], [ "hand_r", 1 ] ], "fake_item": "fake_firestarter", - "act_cost": "3 kJ" + "act_cost": "5 kJ" }, { "id": "bio_lockpick", diff --git a/data/json/items/fake.json b/data/json/items/fake.json index aedfce07729c1..0efd8b0a4ebd8 100644 --- a/data/json/items/fake.json +++ b/data/json/items/fake.json @@ -29,7 +29,7 @@ "copy-from": "fake_item", "type": "TOOL", "name": { "str": "integrated toolset" }, - "flags": [ "TRADER_AVOID" ], + "flags": [ "TRADER_AVOID", "FIRESTARTER", "USES_BIONIC_POWER" ], "max_charges": 10000, "use_action": [ "HAMMER", "CROWBAR" ], "qualities": [ @@ -142,7 +142,7 @@ "copy-from": "fake_item", "type": "TOOL", "name": { "str": "bionic firestarter" }, - "flags": [ "FIRESTARTER" ] + "flags": [ "FIRESTARTER", "USES_BIONIC_POWER" ] }, { "id": "migo_bio_gun", diff --git a/src/activity_actor.cpp b/src/activity_actor.cpp index de092f22e6349..a20911641149b 100644 --- a/src/activity_actor.cpp +++ b/src/activity_actor.cpp @@ -721,7 +721,7 @@ static int hack_level( const Character &who ) return who.get_skill_level( skill_computer ) + who.int_cur / 2 - 8; } -static hack_result hack_attempt( Character &who, const bool using_bionic ) +static hack_result hack_attempt( Character &who ) { // TODO: Remove this once player -> Character migration is complete { @@ -735,21 +735,10 @@ static hack_result hack_attempt( Character &who, const bool using_bionic ) int success = std::ceil( normal_roll( hack_level( who ), hack_stddev ) ); if( success < 0 ) { who.add_msg_if_player( _( "You cause a short circuit!" ) ); - if( using_bionic ) { - who.mod_power_level( -25_kJ ); - } else { - who.use_charges( itype_electrohack, 25 ); - } + who.use_charges( itype_electrohack, 25 ); if( success <= -5 ) { - if( !using_bionic ) { - who.add_msg_if_player( m_bad, _( "Your electrohack is ruined!" ) ); - who.use_amount( itype_electrohack, 1 ); - } else { - who.add_msg_if_player( m_bad, _( "Your power is drained!" ) ); - who.mod_power_level( units::from_kilojoule( -rng( 25, - units::to_kilojoule( who.get_power_level() ) ) ) ); - } + who.use_charges( itype_electrohack, 50 ); } return hack_result::FAIL; } else if( success < 6 ) { @@ -777,16 +766,11 @@ static hack_type get_hack_type( const tripoint &examp ) return type; } -hacking_activity_actor::hacking_activity_actor( use_bionic ) - : using_bionic( true ) -{ -} - void hacking_activity_actor::finish( player_activity &act, Character &who ) { tripoint examp = act.placement; hack_type type = get_hack_type( examp ); - switch( hack_attempt( who, using_bionic ) ) { + switch( hack_attempt( who ) ) { case hack_result::UNABLE: who.add_msg_if_player( _( "You cannot hack this." ) ); break; @@ -842,25 +826,11 @@ void hacking_activity_actor::finish( player_activity &act, Character &who ) act.set_to_null(); } -void hacking_activity_actor::serialize( JsonOut &jsout ) const -{ - jsout.start_object(); - jsout.member( "using_bionic", using_bionic ); - jsout.end_object(); -} +void hacking_activity_actor::serialize( JsonOut & ) const {} -std::unique_ptr hacking_activity_actor::deserialize( JsonIn &jsin ) +std::unique_ptr hacking_activity_actor::deserialize( JsonIn & ) { hacking_activity_actor actor; - if( jsin.test_null() ) { - // Old saves might contain a null instead of an object. - // Since we do not know whether a bionic or an item was chosen we assume - // it was an item. - actor.using_bionic = false; - } else { - JsonObject jsobj = jsin.get_object(); - jsobj.read( "using_bionic", actor.using_bionic ); - } return actor.clone(); } diff --git a/src/activity_actor_definitions.h b/src/activity_actor_definitions.h index e2a814625a99b..ddb9d78c65fb5 100644 --- a/src/activity_actor_definitions.h +++ b/src/activity_actor_definitions.h @@ -278,14 +278,8 @@ class gunmod_remove_activity_actor : public activity_actor class hacking_activity_actor : public activity_actor { - private: - bool using_bionic = false; - public: - struct use_bionic {}; - hacking_activity_actor() = default; - explicit hacking_activity_actor( use_bionic ); activity_id get_type() const override { return activity_id( "ACT_HACKING" ); diff --git a/src/character.cpp b/src/character.cpp index ed979ffe9df73..a2a898ea31f3d 100644 --- a/src/character.cpp +++ b/src/character.cpp @@ -224,7 +224,6 @@ static const itype_id itype_rm13_armor_on( "rm13_armor_on" ); static const itype_id itype_rope_6( "rope_6" ); static const itype_id itype_snare_trigger( "snare_trigger" ); static const itype_id itype_string_36( "string_36" ); -static const itype_id itype_toolset( "toolset" ); static const itype_id itype_UPS( "UPS" ); static const itype_id itype_UPS_off( "UPS_off" ); @@ -282,15 +281,12 @@ static const bionic_id bio_gills( "bio_gills" ); static const bionic_id bio_ground_sonar( "bio_ground_sonar" ); static const bionic_id bio_hydraulics( "bio_hydraulics" ); static const bionic_id bio_jointservo( "bio_jointservo" ); -static const bionic_id bio_laser( "bio_laser" ); static const bionic_id bio_leukocyte( "bio_leukocyte" ); -static const bionic_id bio_lighter( "bio_lighter" ); static const bionic_id bio_memory( "bio_memory" ); static const bionic_id bio_railgun( "bio_railgun" ); static const bionic_id bio_recycler( "bio_recycler" ); static const bionic_id bio_shock_absorber( "bio_shock_absorber" ); static const bionic_id bio_tattoo_led( "bio_tattoo_led" ); -static const bionic_id bio_tools( "bio_tools" ); static const bionic_id bio_ups( "bio_ups" ); // Aftershock stuff! static const bionic_id afs_bio_linguistic_coprocessor( "afs_bio_linguistic_coprocessor" ); @@ -381,6 +377,7 @@ static const json_character_flag json_flag_ALARMCLOCK( "ALARMCLOCK" ); static const json_character_flag json_flag_ACID_IMMUNE( "ACID_IMMUNE" ); static const json_character_flag json_flag_BASH_IMMUNE( "BASH_IMMUNE" ); static const json_character_flag json_flag_BIO_IMMUNE( "BIO_IMMUNE" ); +static const json_character_flag json_flag_BIONIC_TOGGLED( "BIONIC_TOGGLED" ); static const json_character_flag json_flag_BLIND( "BLIND" ); static const json_character_flag json_flag_BULLET_IMMUNE( "BULLET_IMMUNE" ); static const json_character_flag json_flag_CLAIRVOYANCE( "CLAIRVOYANCE" ); @@ -11269,12 +11266,16 @@ std::list Character::use_charges( const itype_id &what, int qty, const int if( qty <= 0 ) { return res; + } + for( const auto &bio : *this->my_bionics ) { + const bionic_data &bid = bio.info(); + if( bid.fake_item == what && ( !bid.activated || bio.powered ) ) { + mod_power_level( units::from_kilojoule( -qty ) ); + return res; + } + } - } else if( what == itype_toolset ) { - mod_power_level( units::from_kilojoule( -qty ) ); - return res; - - } else if( what == itype_fire ) { + if( what == itype_fire ) { use_fire( qty ); return res; @@ -11350,21 +11351,30 @@ std::list Character::use_charges( const itype_id &what, int qty, return use_charges( what, qty, -1, filter ); } -const item *Character::find_firestarter_with_charges( const int quantity ) const +item Character::find_firestarter_with_charges( const int quantity ) const { for( const item *i : all_items_with_flag( flag_FIRESTARTER ) ) { if( !i->typeId()->can_have_charges() ) { const use_function *usef = i->type->get_use( "firestarter" ); const firestarter_actor *actor = dynamic_cast( usef->get_actor_ptr() ); if( actor->can_use( *this->as_character(), *i, false, tripoint_zero ).success() ) { - return i; + return *i; } } else if( has_charges( i->typeId(), quantity ) ) { - return i; + return *i; } } - - return nullptr; + for( const auto &bio : *this->my_bionics ) { + const bionic_data &bid = bio.info(); + if( bid.fake_item.is_valid() && ( !bid.has_flag( json_flag_BIONIC_TOGGLED ) || ( !bid.activated || + bio.powered ) ) && get_power_level() > quantity * 5_kJ ) { + item fake( bid.fake_item ); + if( !fake.is_null() && bid.fake_item->has_flag( flag_FIRESTARTER ) ) { + return fake; + } + } + } + return item(); } bool Character::has_fire( const int quantity ) const @@ -11375,13 +11385,7 @@ bool Character::has_fire( const int quantity ) const return true; } else if( has_item_with_flag( flag_FIRE ) ) { return true; - } else if( find_firestarter_with_charges( quantity ) ) { - return true; - } else if( has_active_bionic( bio_tools ) && get_power_level() > quantity * 5_kJ ) { - return true; - } else if( has_bionic( bio_lighter ) && get_power_level() > quantity * 5_kJ ) { - return true; - } else if( has_bionic( bio_laser ) && get_power_level() > quantity * 5_kJ ) { + } else if( !find_firestarter_with_charges( quantity ).is_null() ) { return true; } else if( is_npc() ) { // HACK: A hack to make NPCs use their Molotovs @@ -11430,20 +11434,19 @@ void Character::use_fire( const int quantity ) return; } else if( has_item_with_flag( flag_FIRE ) ) { return; - } else if( const item *firestarter = find_firestarter_with_charges( quantity ) ) { - if( firestarter->typeId()->can_have_charges() ) { - use_charges( firestarter->typeId(), quantity ); + } else { + const item firestarter = find_firestarter_with_charges( quantity ); + if( firestarter.is_null() ) { + return; + } + if( firestarter.type->has_flag( flag_USES_BIONIC_POWER ) ) { + mod_power_level( -quantity * 5_kJ ); + return; + } + if( firestarter.typeId()->can_have_charges() ) { + use_charges( firestarter.typeId(), quantity ); return; } - } else if( has_active_bionic( bio_tools ) && get_power_level() > quantity * 5_kJ ) { - mod_power_level( -quantity * 5_kJ ); - return; - } else if( has_bionic( bio_lighter ) && get_power_level() > quantity * 5_kJ ) { - mod_power_level( -quantity * 5_kJ ); - return; - } else if( has_bionic( bio_laser ) && get_power_level() > quantity * 5_kJ ) { - mod_power_level( -quantity * 5_kJ ); - return; } } diff --git a/src/character.h b/src/character.h index 0df50d945dc29..dca5ede190e09 100644 --- a/src/character.h +++ b/src/character.h @@ -2072,7 +2072,7 @@ class Character : public Creature, public visitable std::list use_charges( const itype_id &what, int qty, int radius, const std::function &filter = return_true ); - const item *find_firestarter_with_charges( int quantity ) const; + item find_firestarter_with_charges( int quantity ) const; bool has_fire( int quantity ) const; void use_fire( int quantity ); void assign_stashed_activity(); diff --git a/src/iexamine.cpp b/src/iexamine.cpp index a607d421903c8..b1988adf56136 100644 --- a/src/iexamine.cpp +++ b/src/iexamine.cpp @@ -207,7 +207,6 @@ static const mtype_id mon_spider_cellar_giant_s( "mon_spider_cellar_giant_s" ); static const mtype_id mon_spider_web_s( "mon_spider_web_s" ); static const mtype_id mon_spider_widow_giant_s( "mon_spider_widow_giant_s" ); -static const bionic_id bio_fingerhack( "bio_fingerhack" ); static const bionic_id bio_lighter( "bio_lighter" ); static const bionic_id bio_lockpick( "bio_lockpick" ); static const bionic_id bio_painkiller( "bio_painkiller" ); @@ -1057,37 +1056,12 @@ static bool try_start_hacking( player &p, const tripoint &examp ) return false; } const bool has_item = p.has_charges( itype_electrohack, 25 ); - const bool has_bionic = p.has_bionic( bio_fingerhack ) && p.get_power_level() >= 25_kJ; - if( !has_item && !has_bionic ) { + if( !has_item ) { add_msg( _( "You don't have a hacking tool with enough charges!" ) ); return false; } - bool use_bionic = has_bionic; - if( has_item && has_bionic ) { - uilist menu; - menu.settext( _( "Use which hacking tool?" ) ); - menu.addentry( 0, true, MENU_AUTOASSIGN, "%s", itype_electrohack->nname( 1 ) ); - menu.addentry( 1, true, MENU_AUTOASSIGN, "%s", bio_fingerhack->name ); - menu.query(); - switch( menu.ret ) { - case 0: - use_bionic = false; - break; - case 1: - use_bionic = true; - break; - default: - return false; - } - } - if( use_bionic ) { - p.mod_power_level( -25_kJ ); - p.assign_activity( player_activity( hacking_activity_actor( - hacking_activity_actor::use_bionic {} ) ) ); - } else { - p.use_charges( itype_electrohack, 25 ); - p.assign_activity( player_activity( hacking_activity_actor() ) ); - } + p.use_charges( itype_electrohack, 25 ); + p.assign_activity( player_activity( hacking_activity_actor() ) ); p.activity.placement = examp; return true; } @@ -4353,9 +4327,7 @@ void iexamine::pay_gas( player &p, const tripoint &examp ) int pricePerUnit = getGasPricePerLiter( discount ); - bool can_hack = ( !p.has_trait( trait_ILLITERATE ) && - ( ( p.has_charges( itype_electrohack, 25 ) ) || - ( p.has_bionic( bio_fingerhack ) && p.get_power_level() > 24_kJ ) ) ); + bool can_hack = ( !p.has_trait( trait_ILLITERATE ) && p.has_charges( itype_electrohack, 25 ) ); uilist amenu; amenu.selected = 1; diff --git a/src/visitable.cpp b/src/visitable.cpp index 889e0991cd157..827167c71b5fd 100644 --- a/src/visitable.cpp +++ b/src/visitable.cpp @@ -39,13 +39,11 @@ static const itype_id itype_apparatus( "apparatus" ); static const itype_id itype_adv_UPS_off( "adv_UPS_off" ); -static const itype_id itype_toolset( "toolset" ); static const itype_id itype_UPS( "UPS" ); static const itype_id itype_UPS_off( "UPS_off" ); static const quality_id qual_BUTCHER( "BUTCHER" ); -static const bionic_id bio_tools( "bio_tools" ); static const bionic_id bio_ups( "bio_ups" ); static const json_character_flag json_flag_BIONIC_TOGGLED( "BIONIC_TOGGLED" ); @@ -822,11 +820,10 @@ int Character::charges_of( const itype_id &what, int limit, { const player *p = dynamic_cast( this ); - if( what == itype_toolset ) { - if( p && p->has_active_bionic( bio_tools ) ) { + for( const auto &bio : *this->my_bionics ) { + const bionic_data &bid = bio.info(); + if( bid.fake_item == what && ( !bid.activated || bio.powered ) ) { return std::min( units::to_kilojoule( p->get_power_level() ), limit ); - } else { - return 0; } } From 0a63f3f58ac7623deb9271b1fe078acf47f8b943 Mon Sep 17 00:00:00 2001 From: "Matthew S. Klosak" Date: Thu, 25 Mar 2021 00:34:17 -0700 Subject: [PATCH 100/453] Migrate some activities to activity actor system (#47913) --- src/activity_actor.cpp | 107 +++++++++++++++++++++++++++++++ src/activity_actor_definitions.h | 84 ++++++++++++++++++++++++ src/activity_handlers.cpp | 37 ----------- src/activity_handlers.h | 4 -- src/iuse.cpp | 12 +--- src/monexamine.cpp | 5 +- 6 files changed, 195 insertions(+), 54 deletions(-) diff --git a/src/activity_actor.cpp b/src/activity_actor.cpp index a20911641149b..0da0e27715dd4 100644 --- a/src/activity_actor.cpp +++ b/src/activity_actor.cpp @@ -2832,6 +2832,109 @@ std::unique_ptr disassemble_activity_actor::deserialize( JsonIn return actor.clone(); } +void meditate_activity_actor::start( player_activity &act, Character & ) +{ + act.moves_total = to_moves( 20_minutes ); + act.moves_left = act.moves_total; +} + +void meditate_activity_actor::finish( player_activity &act, Character &who ) +{ + who.add_msg_if_player( m_good, _( "You pause to engage in spiritual contemplation." ) ); + who.add_morale( MORALE_FEELING_GOOD, 5, 10 ); + act.set_to_null(); +} + +void meditate_activity_actor::serialize( JsonOut &jsout ) const +{ + jsout.write_null(); +} + +std::unique_ptr meditate_activity_actor::deserialize( JsonIn & ) +{ + return meditate_activity_actor().clone(); +} + +void play_with_pet_activity_actor::start( player_activity &act, Character & ) +{ + act.moves_total = rng( 50, 125 ) * 100; + act.moves_left = act.moves_total; +} + +void play_with_pet_activity_actor::finish( player_activity &act, Character &who ) +{ + who.add_morale( MORALE_PLAY_WITH_PET, rng( 3, 10 ), 10, 5_hours, 25_minutes ); + who.add_msg_if_player( m_good, _( "Playing with your %s has lifted your spirits a bit." ), + pet_name ); + act.set_to_null(); +} + +void play_with_pet_activity_actor::serialize( JsonOut &jsout ) const +{ + jsout.start_object(); + + jsout.member( "pet_name", pet_name ); + + jsout.end_object(); +} + +std::unique_ptr play_with_pet_activity_actor::deserialize( JsonIn &jsin ) +{ + play_with_pet_activity_actor actor = play_with_pet_activity_actor(); + + JsonObject data = jsin.get_object(); + + data.read( "pet_name", actor.pet_name ); + + return actor.clone(); +} + +void shave_activity_actor::start( player_activity &act, Character & ) +{ + act.moves_total = to_moves( 5_minutes ); + act.moves_left = act.moves_total; +} + +void shave_activity_actor::finish( player_activity &act, Character &who ) +{ + who.add_msg_if_player( _( "You open up your kit and shave." ) ); + who.add_morale( MORALE_SHAVE, 8, 8, 240_minutes, 3_minutes ); + act.set_to_null(); +} + +void shave_activity_actor::serialize( JsonOut &jsout ) const +{ + jsout.write_null(); +} + +std::unique_ptr shave_activity_actor::deserialize( JsonIn & ) +{ + return shave_activity_actor().clone(); +} + +void haircut_activity_actor::start( player_activity &act, Character & ) +{ + act.moves_total = to_moves( 30_minutes ); + act.moves_left = act.moves_total; +} + +void haircut_activity_actor::finish( player_activity &act, Character &who ) +{ + who.add_msg_if_player( _( "You give your hair a trim." ) ); + who.add_morale( MORALE_HAIRCUT, 3, 3, 480_minutes, 3_minutes ); + act.set_to_null(); +} + +void haircut_activity_actor::serialize( JsonOut &jsout ) const +{ + jsout.write_null(); +} + +std::unique_ptr haircut_activity_actor::deserialize( JsonIn & ) +{ + return haircut_activity_actor().clone(); +} + namespace activity_actors { @@ -2850,15 +2953,19 @@ deserialize_functions = { { activity_id( "ACT_DROP" ), &drop_activity_actor::deserialize }, { activity_id( "ACT_GUNMOD_REMOVE" ), &gunmod_remove_activity_actor::deserialize }, { activity_id( "ACT_HACKING" ), &hacking_activity_actor::deserialize }, + { activity_id( "ACT_HAIRCUT" ), &haircut_activity_actor::deserialize }, { activity_id( "ACT_HOTWIRE_CAR" ), &hotwire_car_activity_actor::deserialize }, { activity_id( "ACT_INSERT_ITEM" ), &insert_item_activity_actor::deserialize }, { activity_id( "ACT_LOCKPICK" ), &lockpick_activity_actor::deserialize }, + { activity_id( "ACT_MEDITATE" ), &meditate_activity_actor::deserialize }, { activity_id( "ACT_MIGRATION_CANCEL" ), &migration_cancel_activity_actor::deserialize }, { activity_id( "ACT_MILK" ), &milk_activity_actor::deserialize }, { activity_id( "ACT_MOVE_ITEMS" ), &move_items_activity_actor::deserialize }, { activity_id( "ACT_OPEN_GATE" ), &open_gate_activity_actor::deserialize }, { activity_id( "ACT_PICKUP" ), &pickup_activity_actor::deserialize }, + { activity_id( "ACT_PLAY_WITH_PET" ), &play_with_pet_activity_actor::deserialize }, { activity_id( "ACT_RELOAD" ), &reload_activity_actor::deserialize }, + { activity_id( "ACT_SHAVE" ), &shave_activity_actor::deserialize }, { activity_id( "ACT_STASH" ), &stash_activity_actor::deserialize }, { activity_id( "ACT_TRY_SLEEP" ), &try_sleep_activity_actor::deserialize }, { activity_id( "ACT_UNLOAD" ), &unload_activity_actor::deserialize }, diff --git a/src/activity_actor_definitions.h b/src/activity_actor_definitions.h index ddb9d78c65fb5..b3fd236b518b2 100644 --- a/src/activity_actor_definitions.h +++ b/src/activity_actor_definitions.h @@ -1007,4 +1007,88 @@ class insert_item_activity_actor : public activity_actor static std::unique_ptr deserialize( JsonIn &jsin ); }; +class meditate_activity_actor : public activity_actor +{ + public: + meditate_activity_actor() = default; + activity_id get_type() const override { + return activity_id( "ACT_MEDITATE" ); + } + + void start( player_activity &act, Character & ) override; + void do_turn( player_activity &, Character & ) override {} + void finish( player_activity &act, Character &who ) override; + + std::unique_ptr clone() const override { + return std::make_unique( *this ); + } + + void serialize( JsonOut & ) const override; + static std::unique_ptr deserialize( JsonIn & ); +}; + +class play_with_pet_activity_actor : public activity_actor +{ + private: + std::string pet_name; + public: + play_with_pet_activity_actor() = default; + explicit play_with_pet_activity_actor( const std::string &pet_name ) : + pet_name( pet_name ) {} + activity_id get_type() const override { + return activity_id( "ACT_PLAY_WITH_PET" ); + } + + void start( player_activity &act, Character & ) override; + void do_turn( player_activity &, Character & ) override {} + void finish( player_activity &act, Character &who ) override; + + std::unique_ptr clone() const override { + return std::make_unique( *this ); + } + + void serialize( JsonOut &jsout ) const override; + static std::unique_ptr deserialize( JsonIn &jsin ); +}; + +class shave_activity_actor : public activity_actor +{ + public: + shave_activity_actor() = default; + activity_id get_type() const override { + return activity_id( "ACT_SHAVE" ); + } + + void start( player_activity &act, Character & ) override; + void do_turn( player_activity &, Character & ) override {} + void finish( player_activity &act, Character &who ) override; + + std::unique_ptr clone() const override { + return std::make_unique( *this ); + } + + void serialize( JsonOut & ) const override; + static std::unique_ptr deserialize( JsonIn & ); +}; + +class haircut_activity_actor : public activity_actor +{ + public: + haircut_activity_actor() = default; + activity_id get_type() const override { + return activity_id( "ACT_HAIRCUT" ); + } + + void start( player_activity &act, Character & ) override; + void do_turn( player_activity &, Character & ) override {} + void finish( player_activity &act, Character &who ) override; + + std::unique_ptr clone() const override { + return std::make_unique( *this ); + } + + void serialize( JsonOut & ) const override; + static std::unique_ptr deserialize( JsonIn & ); +}; + #endif // CATA_SRC_ACTIVITY_ACTOR_DEFINITIONS_H diff --git a/src/activity_handlers.cpp b/src/activity_handlers.cpp index 507458cc82f55..87b98c5d350a9 100644 --- a/src/activity_handlers.cpp +++ b/src/activity_handlers.cpp @@ -136,12 +136,10 @@ static const activity_id ACT_GAME( "ACT_GAME" ); static const activity_id ACT_GENERIC_GAME( "ACT_GENERIC_GAME" ); static const activity_id ACT_GUNMOD_ADD( "ACT_GUNMOD_ADD" ); static const activity_id ACT_HACKSAW( "ACT_HACKSAW" ); -static const activity_id ACT_HAIRCUT( "ACT_HAIRCUT" ); static const activity_id ACT_HAND_CRANK( "ACT_HAND_CRANK" ); static const activity_id ACT_HEATING( "ACT_HEATING" ); static const activity_id ACT_JACKHAMMER( "ACT_JACKHAMMER" ); static const activity_id ACT_LONGSALVAGE( "ACT_LONGSALVAGE" ); -static const activity_id ACT_MEDITATE( "ACT_MEDITATE" ); static const activity_id ACT_MEND_ITEM( "ACT_MEND_ITEM" ); static const activity_id ACT_MIND_SPLICER( "ACT_MIND_SPLICER" ); static const activity_id ACT_MOVE_LOOT( "ACT_MOVE_LOOT" ); @@ -156,14 +154,12 @@ static const activity_id ACT_OPERATION( "ACT_OPERATION" ); static const activity_id ACT_OXYTORCH( "ACT_OXYTORCH" ); static const activity_id ACT_PICKAXE( "ACT_PICKAXE" ); static const activity_id ACT_PLANT_SEED( "ACT_PLANT_SEED" ); -static const activity_id ACT_PLAY_WITH_PET( "ACT_PLAY_WITH_PET" ); static const activity_id ACT_PRY_NAILS( "ACT_PRY_NAILS" ); static const activity_id ACT_PULP( "ACT_PULP" ); static const activity_id ACT_QUARTER( "ACT_QUARTER" ); static const activity_id ACT_READ( "ACT_READ" ); static const activity_id ACT_REPAIR_ITEM( "ACT_REPAIR_ITEM" ); static const activity_id ACT_ROBOT_CONTROL( "ACT_ROBOT_CONTROL" ); -static const activity_id ACT_SHAVE( "ACT_SHAVE" ); static const activity_id ACT_SKIN( "ACT_SKIN" ); static const activity_id ACT_SOCIALIZE( "ACT_SOCIALIZE" ); static const activity_id ACT_SPELLCASTING( "ACT_SPELLCASTING" ); @@ -343,7 +339,6 @@ activity_handlers::finish_functions = { { ACT_GUNMOD_ADD, gunmod_add_finish }, { ACT_TOOLMOD_ADD, toolmod_add_finish }, { ACT_CLEAR_RUBBLE, clear_rubble_finish }, - { ACT_MEDITATE, meditate_finish }, { ACT_READ, read_finish }, { ACT_WAIT, wait_finish }, { ACT_WAIT_WEATHER, wait_weather_finish }, @@ -366,9 +361,6 @@ activity_handlers::finish_functions = { { ACT_CHOP_PLANKS, chop_planks_finish }, { ACT_JACKHAMMER, jackhammer_finish }, { ACT_FILL_PIT, fill_pit_finish }, - { ACT_PLAY_WITH_PET, play_with_pet_finish }, - { ACT_SHAVE, shaving_finish }, - { ACT_HAIRCUT, haircut_finish }, { ACT_ROBOT_CONTROL, robot_control_finish }, { ACT_MIND_SPLICER, mind_splicer_finish }, { ACT_SPELLCASTING, spellcasting_finish }, @@ -2841,13 +2833,6 @@ void activity_handlers::clear_rubble_finish( player_activity *act, player *p ) here.maybe_trigger_trap( pos, *p, true ); } -void activity_handlers::meditate_finish( player_activity *act, player *p ) -{ - p->add_msg_if_player( m_good, _( "You pause to engage in spiritual contemplation." ) ); - p->add_morale( MORALE_FEELING_GOOD, 5, 10 ); - act->set_to_null(); -} - void activity_handlers::wear_do_turn( player_activity *act, player *p ) { activity_on_turn_wear( *act, *p ); @@ -3879,28 +3864,6 @@ void activity_handlers::fill_pit_finish( player_activity *act, player *p ) act->set_to_null(); } -void activity_handlers::play_with_pet_finish( player_activity *act, player *p ) -{ - p->add_morale( MORALE_PLAY_WITH_PET, rng( 3, 10 ), 10, 5_hours, 25_minutes ); - p->add_msg_if_player( m_good, _( "Playing with your %s has lifted your spirits a bit." ), - act->str_values[0] ); - act->set_to_null(); -} - -void activity_handlers::shaving_finish( player_activity *act, player *p ) -{ - p->add_msg_if_player( _( "You open up your kit and shave." ) ); - p->add_morale( MORALE_SHAVE, 8, 8, 240_minutes, 3_minutes ); - act->set_to_null(); -} - -void activity_handlers::haircut_finish( player_activity *act, player *p ) -{ - p->add_msg_if_player( _( "You give your hair a trim." ) ); - p->add_morale( MORALE_HAIRCUT, 3, 3, 480_minutes, 3_minutes ); - act->set_to_null(); -} - std::vector get_sorted_tiles_by_distance( const tripoint &abspos, const std::unordered_set &tiles ) { diff --git a/src/activity_handlers.h b/src/activity_handlers.h index 185258f1a009d..bfb9ff44bd3af 100644 --- a/src/activity_handlers.h +++ b/src/activity_handlers.h @@ -211,7 +211,6 @@ void gunmod_add_finish( player_activity *act, player *p ); void toolmod_add_finish( player_activity *act, player *p ); void clear_rubble_finish( player_activity *act, player *p ); void heat_item_finish( player_activity *act, player *p ); -void meditate_finish( player_activity *act, player *p ); void read_finish( player_activity *act, player *p ); void wait_finish( player_activity *act, player *p ); void wait_weather_finish( player_activity *act, player *p ); @@ -231,9 +230,6 @@ void chop_logs_finish( player_activity *act, player *p ); void chop_planks_finish( player_activity *act, player *p ); void jackhammer_finish( player_activity *act, player *p ); void fill_pit_finish( player_activity *act, player *p ); -void play_with_pet_finish( player_activity *act, player *p ); -void shaving_finish( player_activity *act, player *p ); -void haircut_finish( player_activity *act, player *p ); void robot_control_finish( player_activity *act, player *p ); void mind_splicer_finish( player_activity *act, player *p ); void spellcasting_finish( player_activity *act, player *p ); diff --git a/src/iuse.cpp b/src/iuse.cpp index c22039c0af03b..af595aba5a23c 100644 --- a/src/iuse.cpp +++ b/src/iuse.cpp @@ -126,17 +126,14 @@ static const activity_id ACT_FISH( "ACT_FISH" ); static const activity_id ACT_GAME( "ACT_GAME" ); static const activity_id ACT_GENERIC_GAME( "ACT_GENERIC_GAME" ); static const activity_id ACT_HACKSAW( "ACT_HACKSAW" ); -static const activity_id ACT_HAIRCUT( "ACT_HAIRCUT" ); static const activity_id ACT_HAND_CRANK( "ACT_HAND_CRANK" ); static const activity_id ACT_HEATING( "ACT_HEATING" ); static const activity_id ACT_JACKHAMMER( "ACT_JACKHAMMER" ); -static const activity_id ACT_MEDITATE( "ACT_MEDITATE" ); static const activity_id ACT_MIND_SPLICER( "ACT_MIND_SPLICER" ); static const activity_id ACT_OXYTORCH( "ACT_OXYTORCH" ); static const activity_id ACT_PICKAXE( "ACT_PICKAXE" ); static const activity_id ACT_PRY_NAILS( "ACT_PRY_NAILS" ); static const activity_id ACT_ROBOT_CONTROL( "ACT_ROBOT_CONTROL" ); -static const activity_id ACT_SHAVE( "ACT_SHAVE" ); static const activity_id ACT_VIBE( "ACT_VIBE" ); static const activity_id ACT_WASH( "ACT_WASH" ); @@ -960,8 +957,7 @@ cata::optional iuse::meditate( player *p, item *it, bool t, const tripoint return cata::nullopt; } if( p->has_trait( trait_SPIRITUAL ) ) { - const int moves = to_moves( 20_minutes ); - p->assign_activity( ACT_MEDITATE, moves ); + p->assign_activity( player_activity( meditate_activity_actor() ) ); } else { p->add_msg_if_player( _( "This %s probably meant a lot to someone at one time." ), it->tname() ); @@ -9131,8 +9127,7 @@ cata::optional iuse::shavekit( player *p, item *it, bool, const tripoint & if( !it->ammo_sufficient() ) { p->add_msg_if_player( _( "You need soap to use this." ) ); } else { - const int moves = to_moves( 5_minutes ); - p->assign_activity( ACT_SHAVE, moves ); + p->assign_activity( player_activity( shave_activity_actor() ) ); } return it->type->charges_to_use(); } @@ -9143,8 +9138,7 @@ cata::optional iuse::hairkit( player *p, item *it, bool, const tripoint & ) p->add_msg_if_player( m_info, _( "You can't do that while mounted." ) ); return cata::nullopt; } - const int moves = to_moves( 30_minutes ); - p->assign_activity( ACT_HAIRCUT, moves ); + p->assign_activity( player_activity( haircut_activity_actor() ) ); return it->type->charges_to_use(); } diff --git a/src/monexamine.cpp b/src/monexamine.cpp index 90168ad4cde80..3d23556174d14 100644 --- a/src/monexamine.cpp +++ b/src/monexamine.cpp @@ -44,8 +44,6 @@ static const quality_id qual_SHEAR( "SHEAR" ); static const efftype_id effect_sheared( "sheared" ); -static const activity_id ACT_PLAY_WITH_PET( "ACT_PLAY_WITH_PET" ); - static const efftype_id effect_controlled( "controlled" ); static const efftype_id effect_harnessed( "harnessed" ); static const efftype_id effect_has_bag( "has_bag" ); @@ -747,8 +745,7 @@ void monexamine::play_with( monster &z ) { std::string pet_name = z.get_name(); Character &player_character = get_player_character(); - player_character.assign_activity( ACT_PLAY_WITH_PET, rng( 50, 125 ) * 100 ); - player_character.activity.str_values.push_back( pet_name ); + player_character.assign_activity( player_activity( play_with_pet_activity_actor( pet_name ) ) ); } void monexamine::tie_or_untie( monster &z ) From 6a112d748d55fd2eec268e091d443d3dc8647eaf Mon Sep 17 00:00:00 2001 From: chrispikula Date: Thu, 25 Mar 2021 01:38:10 -0600 Subject: [PATCH 101/453] Moved Scourge and Lobotomizer to weapon category in inventory (#47893) --- data/json/items/melee/misc.json | 10 ++++++---- 1 file changed, 6 insertions(+), 4 deletions(-) diff --git a/data/json/items/melee/misc.json b/data/json/items/melee/misc.json index ff891a10e4a30..9824040db4f42 100644 --- a/data/json/items/melee/misc.json +++ b/data/json/items/melee/misc.json @@ -18,8 +18,9 @@ { "id": "bullwhip_razor", "name": { "str": "scourge" }, - "type": "TOOL", - "description": "The \"cat 'o nine tails\", a handle with nine short leather whips each sporting a razor-sharp metal tip. This ancient instrument of torture causes massive bleeding but is an ineffecient weapon by design.", + "type": "GENERIC", + "category": "weapons", + "description": "The \"cat 'o nine tails\", a handle with nine short leather whips, each sporting a razor-sharp metal tip. This ancient instrument of torture causes massive bleeding, but by design is inefficient as a weapon.", "symbol": "/", "color": "brown", "weight": "3496 g", @@ -34,9 +35,10 @@ }, { "id": "lobotomizer", - "type": "TOOL", + "type": "GENERIC", + "category": "weapons", "name": { "str": "lobotomizer" }, - "description": "This is a hand-forged collapsible tool that has two axe heads and sharp shovel-like tip on one end. It can be used as a shovel, or you could chop some zombies with it instead.", + "description": "This is a hand-forged collapsible tool that has two axe heads and a sharp shovel-like tip on one end. It can be used as a shovel, or you could chop some zombies with it instead.", "weight": "2722 g", "volume": "1750 ml", "price": 25000, From b274be1fb6eb11c24a7d61b60b7bffc8534136d2 Mon Sep 17 00:00:00 2001 From: adamkad1 Date: Thu, 25 Mar 2021 08:38:57 +0100 Subject: [PATCH 102/453] Deluxe scrambled eggs from human meats (#47866) --- data/json/items/comestibles/meat_dishes.json | 6 +++++- data/json/recipes/recipe_food.json | 4 ++++ 2 files changed, 9 insertions(+), 1 deletion(-) diff --git a/data/json/items/comestibles/meat_dishes.json b/data/json/items/comestibles/meat_dishes.json index 13d6eb6577bd1..a6f27f6b5170f 100644 --- a/data/json/items/comestibles/meat_dishes.json +++ b/data/json/items/comestibles/meat_dishes.json @@ -951,7 +951,11 @@ "type": "COMESTIBLE", "id": "deluxe_eggs", "name": { "str_sp": "deluxe scrambled eggs" }, - "conditional_names": [ { "type": "COMPONENT_ID", "condition": "mutant", "name": { "str_sp": "\"deluxe\" scrambled eggs" } } ], + "conditional_names": [ + { "type": "FLAG", "condition": "CANNIBALISM", "name": { "str_sp": "deluxe scrambled eggheads" } }, + { "type": "FLAG", "condition": "STRICT_HUMANITARIANISM", "name": { "str_sp": "birdman's scrambled eggs" } }, + { "type": "COMPONENT_ID", "condition": "mutant", "name": { "str_sp": "\"deluxe\" scrambled eggs" } } + ], "weight": "198 g", "color": "yellow", "spoils_in": "2 days", diff --git a/data/json/recipes/recipe_food.json b/data/json/recipes/recipe_food.json index c3ab7e4257802..aa40e1a7ed67b 100644 --- a/data/json/recipes/recipe_food.json +++ b/data/json/recipes/recipe_food.json @@ -3708,6 +3708,8 @@ [ [ "bacon", 2 ], [ "meat_cooked", 1 ], + [ "human_cooked", 1 ], + [ "demihuman_cooked", 1 ], [ "mutant_meat_cooked", 1 ], [ "meat_smoked", 1 ], [ "dry_meat", 1 ], @@ -3750,6 +3752,8 @@ [ [ "bacon", 2 ], [ "meat_cooked", 1 ], + [ "human_cooked", 1 ], + [ "demihuman_cooked", 1 ], [ "mutant_meat_cooked", 1 ], [ "meat_smoked", 1 ], [ "dry_meat", 1 ], From 4faf07a387156149657155c735ffc2e3eb420074 Mon Sep 17 00:00:00 2001 From: Saicchi <47158232+Saicchi@users.noreply.github.com> Date: Thu, 25 Mar 2021 04:39:53 -0300 Subject: [PATCH 103/453] Improve naming of uilist single letter parameters (#47722) --- src/ui.cpp | 110 ++++++++++++++++----------------- src/ui.h | 174 ++++++++++++++++++++++++++++++++++++++++++++--------- 2 files changed, 203 insertions(+), 81 deletions(-) diff --git a/src/ui.cpp b/src/ui.cpp index d99d07439716f..0165ca5a21570 100644 --- a/src/ui.cpp +++ b/src/ui.cpp @@ -62,74 +62,74 @@ static cata::optional hotkey_from_char( const int ch ) return input_event(); } -uilist_entry::uilist_entry( const std::string &T ) - : retval( -1 ), enabled( true ), hotkey( cata::nullopt ), txt( T ), +uilist_entry::uilist_entry( const std::string &txt ) + : retval( -1 ), enabled( true ), hotkey( cata::nullopt ), txt( txt ), text_color( c_red_red ) { } -uilist_entry::uilist_entry( const std::string &T, const std::string &D ) - : retval( -1 ), enabled( true ), hotkey( cata::nullopt ), txt( T ), - desc( D ), text_color( c_red_red ) +uilist_entry::uilist_entry( const std::string &txt, const std::string &desc ) + : retval( -1 ), enabled( true ), hotkey( cata::nullopt ), txt( txt ), + desc( desc ), text_color( c_red_red ) { } -uilist_entry::uilist_entry( const std::string &T, const int K ) - : retval( -1 ), enabled( true ), hotkey( hotkey_from_char( K ) ), txt( T ), +uilist_entry::uilist_entry( const std::string &txt, const int key ) + : retval( -1 ), enabled( true ), hotkey( hotkey_from_char( key ) ), txt( txt ), text_color( c_red_red ) { } -uilist_entry::uilist_entry( const std::string &T, const cata::optional &K ) - : retval( -1 ), enabled( true ), hotkey( K ), txt( T ), +uilist_entry::uilist_entry( const std::string &txt, const cata::optional &key ) + : retval( -1 ), enabled( true ), hotkey( key ), txt( txt ), text_color( c_red_red ) { } -uilist_entry::uilist_entry( const int R, const bool E, const int K, - const std::string &T ) - : retval( R ), enabled( E ), hotkey( hotkey_from_char( K ) ), txt( T ), +uilist_entry::uilist_entry( const int retval, const bool enabled, const int key, + const std::string &txt ) + : retval( retval ), enabled( enabled ), hotkey( hotkey_from_char( key ) ), txt( txt ), text_color( c_red_red ) { } -uilist_entry::uilist_entry( const int R, const bool E, - const cata::optional &K, - const std::string &T ) - : retval( R ), enabled( E ), hotkey( K ), txt( T ), +uilist_entry::uilist_entry( const int retval, const bool enabled, + const cata::optional &key, + const std::string &txt ) + : retval( retval ), enabled( enabled ), hotkey( key ), txt( txt ), text_color( c_red_red ) { } -uilist_entry::uilist_entry( const int R, const bool E, const int K, - const std::string &T, const std::string &D ) - : retval( R ), enabled( E ), hotkey( hotkey_from_char( K ) ), txt( T ), - desc( D ), text_color( c_red_red ) +uilist_entry::uilist_entry( const int retval, const bool enabled, const int key, + const std::string &txt, const std::string &desc ) + : retval( retval ), enabled( enabled ), hotkey( hotkey_from_char( key ) ), txt( txt ), + desc( desc ), text_color( c_red_red ) { } -uilist_entry::uilist_entry( const int R, const bool E, const int K, - const std::string &T, const std::string &D, - const std::string &C ) - : retval( R ), enabled( E ), hotkey( hotkey_from_char( K ) ), txt( T ), - desc( D ), ctxt( C ), text_color( c_red_red ) +uilist_entry::uilist_entry( const int retval, const bool enabled, const int key, + const std::string &txt, const std::string &desc, + const std::string &column ) + : retval( retval ), enabled( enabled ), hotkey( hotkey_from_char( key ) ), txt( txt ), + desc( desc ), ctxt( column ), text_color( c_red_red ) { } -uilist_entry::uilist_entry( const int R, const bool E, - const cata::optional &K, - const std::string &T, const std::string &D, - const std::string &C ) - : retval( R ), enabled( E ), hotkey( K ), txt( T ), - desc( D ), ctxt( C ), text_color( c_red_red ) +uilist_entry::uilist_entry( const int retval, const bool enabled, + const cata::optional &key, + const std::string &txt, const std::string &desc, + const std::string &column ) + : retval( retval ), enabled( enabled ), hotkey( key ), txt( txt ), + desc( desc ), ctxt( column ), text_color( c_red_red ) { } -uilist_entry::uilist_entry( const int R, const bool E, const int K, - const std::string &T, - const nc_color &H, const nc_color &C ) - : retval( R ), enabled( E ), hotkey( hotkey_from_char( K ) ), txt( T ), - hotkey_color( H ), text_color( C ) +uilist_entry::uilist_entry( const int retval, const bool enabled, const int key, + const std::string &txt, + const nc_color &keycolor, const nc_color &txtcolor ) + : retval( retval ), enabled( enabled ), hotkey( hotkey_from_char( key ) ), txt( txt ), + hotkey_color( keycolor ), text_color( txtcolor ) { } @@ -997,45 +997,47 @@ void uilist::reset() init(); } -void uilist::addentry( const std::string &str ) +void uilist::addentry( const std::string &txt ) { - entries.emplace_back( str ); + entries.emplace_back( txt ); } -void uilist::addentry( int r, bool e, int k, const std::string &str ) +void uilist::addentry( int retval, bool enabled, int key, const std::string &txt ) { - entries.emplace_back( r, e, k, str ); + entries.emplace_back( retval, enabled, key, txt ); } -void uilist::addentry( const int r, const bool e, - const cata::optional &k, - const std::string &str ) +void uilist::addentry( const int retval, const bool enabled, + const cata::optional &key, + const std::string &txt ) { - entries.emplace_back( r, e, k, str ); + entries.emplace_back( retval, enabled, key, txt ); } -void uilist::addentry_desc( const std::string &str, const std::string &desc ) +void uilist::addentry_desc( const std::string &txt, const std::string &desc ) { - entries.emplace_back( str, desc ); + entries.emplace_back( txt, desc ); } -void uilist::addentry_desc( int r, bool e, int k, const std::string &str, const std::string &desc ) +void uilist::addentry_desc( int retval, bool enabled, int key, const std::string &txt, + const std::string &desc ) { - entries.emplace_back( r, e, k, str, desc ); + entries.emplace_back( retval, enabled, key, txt, desc ); } -void uilist::addentry_col( int r, bool e, int k, const std::string &str, const std::string &column, +void uilist::addentry_col( int retval, bool enabled, int key, const std::string &txt, + const std::string &column, const std::string &desc ) { - entries.emplace_back( r, e, k, str, desc, column ); + entries.emplace_back( retval, enabled, key, txt, desc, column ); } -void uilist::addentry_col( const int r, const bool e, - const cata::optional &k, - const std::string &str, const std::string &column, +void uilist::addentry_col( const int retval, const bool enabled, + const cata::optional &key, + const std::string &txt, const std::string &column, const std::string &desc ) { - entries.emplace_back( r, e, k, str, desc, column ); + entries.emplace_back( retval, enabled, key, txt, desc, column ); } void uilist::settext( const std::string &str ) diff --git a/src/ui.h b/src/ui.h index 4677604374f79..8129a0d9e4ccc 100644 --- a/src/ui.h +++ b/src/ui.h @@ -70,24 +70,87 @@ struct uilist_entry { nc_color text_color; mvwzstr extratxt; - // In the following constructors, int K only support letters (a-z, A-Z) and + // In the following constructors, int key only support letters (a-z, A-Z) and // digits (0-9), MENU_AUTOASSIGN, and 0 or ' ' (disable hotkey). Other // values may not work under keycode mode. - explicit uilist_entry( const std::string &T ); - uilist_entry( const std::string &T, const std::string &D ); - uilist_entry( const std::string &T, int K ); - uilist_entry( const std::string &T, const cata::optional &K ); - uilist_entry( int R, bool E, int K, const std::string &T ); - uilist_entry( int R, bool E, const cata::optional &K, - const std::string &T ); - uilist_entry( int R, bool E, int K, const std::string &T, const std::string &D ); - uilist_entry( int R, bool E, int K, const std::string &T, const std::string &D, - const std::string &C ); - uilist_entry( int R, bool E, const cata::optional &K, - const std::string &T, const std::string &D, - const std::string &C ); - uilist_entry( int R, bool E, int K, const std::string &T, - const nc_color &H, const nc_color &C ); + + /** + * @param txt string that will be displayed on the entry first column + */ + explicit uilist_entry( const std::string &txt ); + /** + * @param txt string that will be displayed on the entry first column + * @param desc entry description if menu desc_enabled is true + * @see uilist::desc_enabled + */ + uilist_entry( const std::string &txt, const std::string &desc ); + /** + * @param txt string that will be displayed on the entry first column + * @param key hotkey character that when pressed will return this entry return value + */ + uilist_entry( const std::string &txt, int key ); + /** + * @param txt string that will be displayed on the entry first column + * @param key hotkey character that when pressed will return this entry return value + */ + uilist_entry( const std::string &txt, const cata::optional &key ); + /** + * @param retval return value of this option when selected during menu query + * @param enable is entry enabled. disabled entries will be grayed out and won't be selectable + * @param key hotkey character that when pressed will return this entry return value + * @param txt string that will be displayed on the entry first column + */ + uilist_entry( int retval, bool enabled, int key, const std::string &txt ); + /** + * @param retval return value of this option when selected during menu query + * @param enable is entry enabled. disabled entries will be grayed out and won't be selectable + * @param key hotkey character that when pressed will return this entry return value + * @param txt string that will be displayed on the entry first column + */ + uilist_entry( int retval, bool enabled, const cata::optional &key, + const std::string &txt ); + /** + * @param retval return value of this option when selected during menu query + * @param enable is entry enabled. disabled entries will be grayed out and won't be selectable + * @param key hotkey character that when pressed will return this entry return value + * @param txt string that will be displayed on the entry first column + * @param desc entry description if menu desc_enabled is true + * @see uilist::desc_enabled + */ + uilist_entry( int retval, bool enabled, int key, const std::string &txt, const std::string &desc ); + /** + * @param retval return value of this option when selected during menu query + * @param enable is entry enabled. disabled entries will be grayed out and won't be selectable + * @param key hotkey character that when pressed will return this entry return value + * @param txt string that will be displayed on the entry first column + * @param desc entry description if menu desc_enabled is true + * @param column string that will be displayed on the entry second column + * @see uilist::desc_enabled + */ + uilist_entry( int retval, bool enabled, int key, const std::string &txt, const std::string &desc, + const std::string &column ); + /** + * @param retval return value of this option when selected during menu query + * @param enable is entry enabled. disabled entries will be grayed out and won't be selectable + * @param key hotkey character that when pressed will return this entry return value + * @param txt string that will be displayed on the entry first column + * @param desc entry description if menu desc_enabled is true + * @param column string that will be displayed on the entry second column + * @see uilist::desc_enabled + */ + uilist_entry( int retval, bool enabled, const cata::optional &key, + const std::string &txt, const std::string &desc, + const std::string &column ); + /** + * @param retval return value of this option when selected during menu query + * @param enable is entry enabled. disabled entries will be grayed out and won't be selectable + * @param key hotkey character that when pressed will return this entry return value + * @param txt string that will be displayed on the entry first column + * @param keycolor color of the hotkey character + * @param txtcolor entry text string color + */ + uilist_entry( int retval, bool enabled, int key, const std::string &txt, + const nc_color &keycolor, const nc_color &txtcolor ); template::value>> explicit uilist_entry( Enum e, Args && ... args ) : @@ -214,21 +277,78 @@ class uilist // NOLINT(cata-xy) // In add_entry/add_entry_desc/add_entry_col, int k only support letters // (a-z, A-Z) and digits (0-9), MENU_AUTOASSIGN, and 0 or ' ' (disable // hotkey). Other values may not work under keycode mode. - void addentry( const std::string &str ); - void addentry( int r, bool e, int k, const std::string &str ); - void addentry( int r, bool e, const cata::optional &k, - const std::string &str ); + + /** + * @param txt string that will be displayed on the entry first column + */ + void addentry( const std::string &txt ); + /** + * @param retval return value of this option when selected during menu query + * @param enable is entry enabled. disabled entries will be grayed out and won't be selectable + * @param key hotkey character that when pressed will return this entry return value + * @param txt string that will be displayed on the entry first column + */ + void addentry( int retval, bool enabled, int key, const std::string &txt ); + /** + * @param retval return value of this option when selected during menu query + * @param enable is entry enabled. disabled entries will be grayed out and won't be selectable + * @param key hotkey character that when pressed will return this entry return value + * @param txt string that will be displayed on the entry first column + */ + void addentry( int retval, bool enabled, const cata::optional &key, + const std::string &txt ); + /** + * @param retval return value of this option when selected during menu query + * @param enable is entry enabled. disabled entries will be grayed out and won't be selectable + * @param key hotkey character that when pressed will return this entry return value + * @param txt string that will be displayed on the entry first column + * @param args list of parameters for string_format to format txt + */ template - void addentry( const int r, const bool e, K &&k, const char *const format, Args &&... args ) { - return addentry( r, e, std::forward( k ), + void addentry( const int retval, const bool enabled, K &&key, const char *const format, + Args &&... args ) { + return addentry( retval, enabled, std::forward( key ), string_format( format, std::forward( args )... ) ); } - void addentry_desc( const std::string &str, const std::string &desc ); - void addentry_desc( int r, bool e, int k, const std::string &str, const std::string &desc ); - void addentry_col( int r, bool e, int k, const std::string &str, const std::string &column, + /** + * @param txt string that will be displayed on the entry first column + * @param desc entry description if menu desc_enabled is true + * @see uilist::desc_enabled + */ + void addentry_desc( const std::string &txt, const std::string &desc ); + /** + * @param retval return value of this option when selected during menu query + * @param enable is entry enabled. disabled entries will be grayed out and won't be selectable + * @param key hotkey character that when pressed will return this entry return value + * @param txt string that will be displayed on the entry first column + * @param desc entry description if menu desc_enabled is true + * @see uilist::desc_enabled + */ + void addentry_desc( int retval, bool enabled, int key, const std::string &txt, + const std::string &desc ); + /** + * @param retval return value of this option when selected during menu query + * @param enable is entry enabled. disabled entries will be grayed out and won't be selectable + * @param key hotkey character that when pressed will return this entry return value + * @param txt string that will be displayed on the entry first column + * @param column string that will be displayed on the entry second column + * @param desc entry description if menu desc_enabled is true + * @see uilist::desc_enabled + */ + void addentry_col( int retval, bool enabled, int key, const std::string &txt, + const std::string &column, const std::string &desc = "" ); - void addentry_col( int r, bool e, const cata::optional &k, - const std::string &str, const std::string &column, + /** + * @param retval return value of this option when selected during menu query + * @param enable is entry enabled. disabled entries will be grayed out and won't be selectable + * @param key hotkey character that when pressed will return this entry return value + * @param txt string that will be displayed on the entry first column + * @param column string that will be displayed on the entry second column + * @param desc entry description if menu desc_enabled is true + * @see uilist::desc_enabled + */ + void addentry_col( int retval, bool enabled, const cata::optional &key, + const std::string &txt, const std::string &column, const std::string &desc = std::string() ); void settext( const std::string &str ); From 6b10e56f3cd48693cb7318d3496e488b01d9acc5 Mon Sep 17 00:00:00 2001 From: Eric <52087122+Ramza13@users.noreply.github.com> Date: Thu, 25 Mar 2021 03:41:54 -0400 Subject: [PATCH 104/453] Adds effect_on_condition, allowing json scriptable events to happen at any time. (#48042) Co-authored-by: actual-nh <74678550+actual-nh@users.noreply.github.com> --- doc/EFFECT_ON_CONDITION.md | 33 ++++++ src/bionics.cpp | 2 + src/character.cpp | 2 + src/debug_menu.cpp | 8 ++ src/debug_menu.h | 1 + src/dialogue.h | 4 +- src/effect_on_condition.cpp | 228 ++++++++++++++++++++++++++++++++++++ src/effect_on_condition.h | 79 +++++++++++++ src/game.cpp | 5 +- src/game.h | 5 + src/init.cpp | 5 + src/mission_util.cpp | 2 +- src/npctalk.cpp | 15 ++- src/savegame.cpp | 38 ++++++ src/type_id.h | 3 + 15 files changed, 418 insertions(+), 12 deletions(-) create mode 100644 doc/EFFECT_ON_CONDITION.md create mode 100644 src/effect_on_condition.cpp create mode 100644 src/effect_on_condition.h diff --git a/doc/EFFECT_ON_CONDITION.md b/doc/EFFECT_ON_CONDITION.md new file mode 100644 index 0000000000000..2d764de4002cc --- /dev/null +++ b/doc/EFFECT_ON_CONDITION.md @@ -0,0 +1,33 @@ +### effect_on_condition +An effect_on_condition is an object allowing the combination of dialog conditions and effects with their usage outside of a dialog. When invoked, they will test their condition; on a pass, they will cause their effect. They can be activated automatically with any given frequency. (Note: effect_on_conditions use the npc dialog conditions and effects syntax, which allows checking related to, or targeting an effect at, an npc (for example: `npc_has_trait`). Using these commands in an effect_on_condition is not supported.) + +## Fields + +|Identifier|Type|Description| +|-|-|-| +| `recurrence_min`| int | The effect_on_condition is automatically invoked (activated) with at least this many seconds in-between. +| `recurrence_max`| int | The effect_on_condition is automatically invoked (activated) at least once this many seconds. +| `condition`| condition | The condition(s) under which this effect_on_condition, upon activation, will cause its effect. See the "Dialogue conditions" section of [NPCs](NPCs.md) for the full syntax. +| `deactivate_condition`| condition | *optional* When an effect_on_condition is automatically activated (invoked) and fails its condition(s), `deactivate_condition` will be tested if it exists and there is no `false_effect` entry. If it returns true, this effect_on_condition will no longer be invoked automatically every `recurrence_max` seconds. Whenever the player gains/loses a trait or bionic all deactivated effect_on_conditions will have `deactivate_condition` run; on a return of false, the effect_on_condition will start being run again. This is to allow adding effect_on_conditions for specific traits or bionics that don't waste time running when you don't have the target bionic/trait. See the "Dialogue conditions" section of [NPCs](NPCs.md) for the full syntax. +| `effect`| effect | The effect(s) caused if `condition` returns true upon activation. See the "Dialogue Effects" section of [NPCs](NPCs.md) for the full syntax. +| `false_effect`| effect | The effect(s) caused if `condition` returns false upon activation. See the "Dialogue Effects" section of [NPCs](NPCs.md) for the full syntax. + +## Examples: +```JSON + { + "type": "effect_on_condition", + "id": "test_deactivate", + "recurrence_min": 1, + "recurrence_max": 1, + "condition": { "u_has_trait": "SPIRITUAL" }, + "deactivate_condition": {"not":{ "u_has_trait": "SPIRITUAL" } }, + "effect": { "u_add_effect": "infection", "duration": 1 } + }, + { + "type": "effect_on_condition", + "id": "test_stats", + "recurrence_min": 1, + "recurrence_max": 10, + "condition": { "not": { "u_has_strength": 7 } }, + "effect": { "u_add_effect": "infection", "duration": 1 } + } diff --git a/src/bionics.cpp b/src/bionics.cpp index 72706762976de..2562f37684f43 100644 --- a/src/bionics.cpp +++ b/src/bionics.cpp @@ -2759,6 +2759,7 @@ void Character::add_bionic( const bionic_id &b ) if( !b->enchantments.empty() ) { recalculate_enchantment_cache(); } + effect_on_conditions::process_reactivate(); } void Character::remove_bionic( const bionic_id &b ) @@ -2800,6 +2801,7 @@ void Character::remove_bionic( const bionic_id &b ) if( !b->enchantments.empty() ) { recalculate_enchantment_cache(); } + effect_on_conditions::process_reactivate(); } int Character::num_bionics() const diff --git a/src/character.cpp b/src/character.cpp index a2a898ea31f3d..dfbc04cd40fbc 100644 --- a/src/character.cpp +++ b/src/character.cpp @@ -11613,6 +11613,7 @@ void Character::on_mutation_gain( const trait_id &mid ) magic->on_mutation_gain( mid, *this ); update_type_of_scent( mid ); recalculate_enchantment_cache(); // mutations can have enchantments + effect_on_conditions::process_reactivate(); } void Character::on_mutation_loss( const trait_id &mid ) @@ -11621,6 +11622,7 @@ void Character::on_mutation_loss( const trait_id &mid ) magic->on_mutation_loss( mid ); update_type_of_scent( mid, false ); recalculate_enchantment_cache(); // mutations can have enchantments + effect_on_conditions::process_reactivate(); } void Character::on_stat_change( const std::string &stat, int value ) diff --git a/src/debug_menu.cpp b/src/debug_menu.cpp index d211f0d5a99d3..a7fbc2d575454 100644 --- a/src/debug_menu.cpp +++ b/src/debug_menu.cpp @@ -177,6 +177,7 @@ std::string enum_to_string( debug_menu::debug_menu case debug_menu::debug_menu_index::PRINT_NPC_MAGIC: return "PRINT_NPC_MAGIC"; case debug_menu::debug_menu_index::QUIT_NOSAVE: return "QUIT_NOSAVE"; case debug_menu::debug_menu_index::TEST_WEATHER: return "TEST_WEATHER"; + case debug_menu::debug_menu_index::WRITE_EOCS: return "WRITE_EOCS"; case debug_menu::debug_menu_index::SAVE_SCREENSHOT: return "SAVE_SCREENSHOT"; case debug_menu::debug_menu_index::GAME_REPORT: return "GAME_REPORT"; case debug_menu::debug_menu_index::DISPLAY_SCENTS_LOCAL: return "DISPLAY_SCENTS_LOCAL"; @@ -274,6 +275,7 @@ static int info_uilist( bool display_all_entries = true ) { uilist_entry( debug_menu_index::PRINT_FACTION_INFO, true, 'f', _( "Print faction info to console" ) ) }, { uilist_entry( debug_menu_index::PRINT_NPC_MAGIC, true, 'M', _( "Print NPC magic info to console" ) ) }, { uilist_entry( debug_menu_index::TEST_WEATHER, true, 'W', _( "Test weather" ) ) }, + { uilist_entry( debug_menu_index::WRITE_EOCS, true, 'C', _( "Write effect_on_condition(s) to eocs.output" ) ) }, { uilist_entry( debug_menu_index::TEST_MAP_EXTRA_DISTRIBUTION, true, 'e', _( "Test map extra list" ) ) }, { uilist_entry( debug_menu_index::GENERATE_EFFECT_LIST, true, 'L', _( "Generate effect list" ) ) }, }; @@ -2666,6 +2668,12 @@ void debug() } break; + case debug_menu_index::WRITE_EOCS: { + effect_on_conditions::write_eocs_to_file(); + popup( _( "effect_on_condition list written to eocs.output" ) ); + } + break; + case debug_menu_index::SAVE_SCREENSHOT: { #if defined(TILES) // check that the current '/screenshots' directory exists diff --git a/src/debug_menu.h b/src/debug_menu.h index c40f657c9f327..66498bbd88328 100644 --- a/src/debug_menu.h +++ b/src/debug_menu.h @@ -69,6 +69,7 @@ enum class debug_menu_index : int { PRINT_NPC_MAGIC, QUIT_NOSAVE, TEST_WEATHER, + WRITE_EOCS, SAVE_SCREENSHOT, GAME_REPORT, DISPLAY_SCENTS_LOCAL, diff --git a/src/dialogue.h b/src/dialogue.h index f2b0ac704de9f..fd748bd183fe0 100644 --- a/src/dialogue.h +++ b/src/dialogue.h @@ -172,12 +172,12 @@ struct talk_effect_t { void set_effect_consequence( const talk_effect_fun_t &fun, dialogue_consequence con ); void set_effect_consequence( const std::function &ptr, dialogue_consequence con ); - void load_effect( const JsonObject &jo ); + void load_effect( const JsonObject &jo, const std::string &member_name ); void parse_sub_effect( const JsonObject &jo ); void parse_string_effect( const std::string &effect_id, const JsonObject &jo ); talk_effect_t() = default; - explicit talk_effect_t( const JsonObject & ); + explicit talk_effect_t( const JsonObject &, const std::string & ); /** * Functions that are called when the response is chosen. diff --git a/src/effect_on_condition.cpp b/src/effect_on_condition.cpp new file mode 100644 index 0000000000000..ebdb5d39a9dc2 --- /dev/null +++ b/src/effect_on_condition.cpp @@ -0,0 +1,228 @@ +#include "effect_on_condition.h" + +#include "avatar.h" +#include "cata_utility.h" +#include "character.h" +#include "condition.h" +#include "game.h" +#include "generic_factory.h" +#include "talker.h" +#include "type_id.h" + +namespace +{ +generic_factory +effect_on_condition_factory( "effect_on_condition" ); +} // namespace + +template<> +const effect_on_condition &effect_on_condition_id::obj() const +{ + return effect_on_condition_factory.obj( *this ); +} + +/** @relates string_id */ +template<> +bool string_id::is_valid() const +{ + return effect_on_condition_factory.is_valid( *this ); +} + +void effect_on_conditions::check_consistency() +{ +} + +void effect_on_condition::load( const JsonObject &jo, const std::string & ) +{ + activate_only = true; + if( jo.has_member( "recurrence_min" ) || jo.has_member( "recurrence_max" ) ) { + activate_only = false; + mandatory( jo, was_loaded, "recurrence_min", recurrence_min ); + mandatory( jo, was_loaded, "recurrence_max", recurrence_max ); + if( recurrence_max < recurrence_min ) { + jo.throw_error( "recurrence_max cannot be smaller than recurrence_min." ); + } + } + if( jo.has_member( "deactivate_condition" ) ) { + read_condition( jo, "deactivate_condition", deactivate_condition, false ); + has_deactivate_condition = true; + } + if( jo.has_member( "condition" ) ) { + read_condition( jo, "condition", condition, false ); + has_condition = true; + } + true_effect.load_effect( jo, "effect" ); + + if( jo.has_member( "false_effect" ) ) { + false_effect.load_effect( jo, "false_effect" ); + has_false_effect = true; + } +} + +static time_duration next_recurrence( const effect_on_condition_id &eoc ) +{ + return rng( eoc->recurrence_min, eoc->recurrence_max ); +} + +void effect_on_conditions::load_new_character() +{ + for( const effect_on_condition &eoc : effect_on_conditions::get_all() ) { + if( !eoc.activate_only ) { + queued_eoc new_eoc = queued_eoc{ eoc.id, true, calendar::turn + next_recurrence( eoc.id ) }; + g->queued_effect_on_conditions.push( new_eoc ); + } + } +} + +void effect_on_conditions::queue_effect_on_condition( time_duration duration, + effect_on_condition_id eoc ) +{ + queued_eoc new_eoc = queued_eoc{ eoc, false, calendar::turn + duration }; + g->queued_effect_on_conditions.push( new_eoc ); +} + +void effect_on_conditions::process_effect_on_conditions() +{ + dialogue d; + standard_npc default_npc( "Default" ); + d.alpha = get_talker_for( get_avatar() ); + d.beta = get_talker_for( default_npc ); + std::vector eocs_to_queue; + while( !g->queued_effect_on_conditions.empty() && + g->queued_effect_on_conditions.top().time <= calendar::turn ) { + queued_eoc top = g->queued_effect_on_conditions.top(); + bool activated = top.eoc->activate( d ); + if( top.recurring ) { + if( activated ) { // It worked so add it back + queued_eoc new_eoc = queued_eoc{ top.eoc, true, calendar::turn + next_recurrence( top.eoc ) }; + eocs_to_queue.push_back( new_eoc ); + } else { + if( !top.eoc->check_deactivate() ) { // It failed but shouldn't be deactivated so add it back + queued_eoc new_eoc = queued_eoc{ top.eoc, true, calendar::turn + next_recurrence( top.eoc ) }; + eocs_to_queue.push_back( new_eoc ); + } else { // It failed and should be deactivated for now + g->inactive_effect_on_condition_vector.push_back( top.eoc ); + } + } + } + g->queued_effect_on_conditions.pop(); + } + for( const queued_eoc &q_eoc : eocs_to_queue ) { + g->queued_effect_on_conditions.push( q_eoc ); + } +} + +void effect_on_conditions::process_reactivate() +{ + dialogue d; + standard_npc default_npc( "Default" ); + d.alpha = get_talker_for( get_avatar() ); + d.beta = get_talker_for( default_npc ); + + std::vector ids_to_reactivate; + for( const effect_on_condition_id &eoc : g->inactive_effect_on_condition_vector ) { + if( !eoc->check_deactivate() ) { + ids_to_reactivate.push_back( eoc ); + } + } + for( const effect_on_condition_id &eoc : ids_to_reactivate ) { + g->queued_effect_on_conditions.push( queued_eoc{ eoc, true, calendar::turn + next_recurrence( eoc ) } ); + g->inactive_effect_on_condition_vector.erase( std::remove( + g->inactive_effect_on_condition_vector.begin(), g->inactive_effect_on_condition_vector.end(), eoc ), + g->inactive_effect_on_condition_vector.end() ); + } +} + +bool effect_on_condition::activate( dialogue &d ) const +{ + if( !has_condition || condition( d ) ) { + true_effect.apply( d ); + return true; + } + + if( has_false_effect ) { + false_effect.apply( d ); + } + return false; +} + +bool effect_on_condition::check_deactivate() const +{ + if( !has_deactivate_condition || has_false_effect ) { + return false; + } + dialogue d; + standard_npc default_npc( "Default" ); + d.alpha = get_talker_for( get_avatar() ); + d.beta = get_talker_for( default_npc ); + return deactivate_condition( d ); +} + +void effect_on_conditions::clear() +{ + while( !g->queued_effect_on_conditions.empty() ) { + g->queued_effect_on_conditions.pop(); + } + g->inactive_effect_on_condition_vector.clear(); +} + +void effect_on_conditions::write_eocs_to_file() +{ + write_to_file( "eocs.output", [&]( std::ostream & testfile ) { + testfile << "id;timepoint;recurring" << std::endl; + + testfile << "queued eocs:" << std::endl; + std::vector temp_queue; + while( !g->queued_effect_on_conditions.empty() ) { + temp_queue.push_back( g->queued_effect_on_conditions.top() ); + g->queued_effect_on_conditions.pop(); + } + + for( const auto &queue_entry : temp_queue ) { + time_duration temp = queue_entry.time - calendar::turn; + testfile << queue_entry.eoc.c_str() << ";" << to_string( temp ) << ";" << + ( queue_entry.recurring ? "recur" : "non" ) << std::endl ; + } + + for( const auto &queued : temp_queue ) { + g->queued_effect_on_conditions.push( queued ); + } + + testfile << "inactive eocs:" << std::endl; + for( const effect_on_condition_id &eoc : g->inactive_effect_on_condition_vector ) { + testfile << eoc.c_str() << std::endl; + } + + }, "eocs test file" ); +} + +void effect_on_condition::finalize() +{ +} + +void effect_on_conditions::finalize_all() +{ + effect_on_condition_factory.finalize(); + for( const effect_on_condition &eoc : effect_on_condition_factory.get_all() ) { + const_cast( eoc ).finalize(); + } +} + +void effect_on_condition::check() const +{ +} + +const std::vector &effect_on_conditions::get_all() +{ + return effect_on_condition_factory.get_all(); +} + +void effect_on_conditions::reset() +{ + effect_on_condition_factory.reset(); +} + +void effect_on_conditions::load( const JsonObject &jo, const std::string &src ) +{ + effect_on_condition_factory.load( jo, src ); +} diff --git a/src/effect_on_condition.h b/src/effect_on_condition.h new file mode 100644 index 0000000000000..0d4ffae657845 --- /dev/null +++ b/src/effect_on_condition.h @@ -0,0 +1,79 @@ +#pragma once +#ifndef CATA_SRC_EFFECT_ON_CONDITION_H +#define CATA_SRC_EFFECT_ON_CONDITION_H + +#include +#include + +#include "calendar.h" +#include "dialogue.h" +#include "json.h" +#include "type_id.h" + +template +class generic_factory; + +struct queued_eoc { + public: + effect_on_condition_id eoc; + bool recurring = false; + time_point time; +}; + +struct eoc_compare { + bool operator()( const queued_eoc &lhs, const queued_eoc &rhs ) const { + return lhs.time > rhs.time; + } +}; + +struct effect_on_condition { + public: + friend class generic_factory; + bool was_loaded = false; + effect_on_condition_id id; + + std::function condition; + std::function deactivate_condition; + talk_effect_t true_effect; + talk_effect_t false_effect; + bool has_deactivate_condition = false; + bool has_condition = false; + bool has_false_effect = false; + bool activate_only = true; + + time_duration recurrence_min = 1_seconds; + time_duration recurrence_max = 1_seconds; + bool activate( dialogue &d ) const; + bool check_deactivate() const; + void load( const JsonObject &jo, const std::string &src ); + void finalize(); + void check() const; + effect_on_condition() = default; +}; +namespace effect_on_conditions +{ +/** Get all currently loaded effect_on_conditions */ +const std::vector &get_all(); +/** Finalize all loaded effect_on_conditions */ +void finalize_all(); +/** Clear all loaded effects on condition (invalidating any pointers) */ +void reset(); +/** Load effect on condition from JSON definition */ +void load( const JsonObject &jo, const std::string &src ); +/** Checks all loaded from JSON are valid */ +void check_consistency(); +/** Sets up the initial queue for a new character */ +void load_new_character(); +/** queue an eoc to happen in the future */ +void queue_effect_on_condition( time_duration duration, effect_on_condition_id eoc ); +/** called every turn to process the queued eocs */ +void process_effect_on_conditions(); +/** called after certain events to test whether to reactivate eocs */ +void process_reactivate(); +/** clear all queued and inactive eocs */ +void clear(); +/** write out all queued eocs and inactive eocs to a file for testing */ +void write_eocs_to_file(); +} // namespace effect_on_conditions + +#endif // CATA_SRC_EFFECT_ON_CONDITION_H diff --git a/src/game.cpp b/src/game.cpp index 0a6d777e4e4d5..6a0fb66477c55 100644 --- a/src/game.cpp +++ b/src/game.cpp @@ -645,7 +645,7 @@ void game::setup() // reset follower list follower_ids.clear(); scent.reset(); - + effect_on_conditions::clear(); remoteveh_cache_time = calendar::before_time_starts; remoteveh_cache = nullptr; // back to menu for save loading, new game etc @@ -849,6 +849,8 @@ bool game::start_game() tripoint_abs_omt abs_omt = u.global_omt_location(); const oter_id &cur_ter = overmap_buffer.ter( abs_omt ); get_event_bus().send( abs_omt.raw(), cur_ter ); + + effect_on_conditions::load_new_character(); return true; } @@ -1611,6 +1613,7 @@ bool game::do_turn() ui_manager::redraw(); refresh_display(); } + effect_on_conditions::process_effect_on_conditions(); if( levz >= 0 && !u.is_underwater() ) { handle_weather_effects( weather.weather_id ); diff --git a/src/game.h b/src/game.h index 247d68f7da31e..58e4d83935044 100644 --- a/src/game.h +++ b/src/game.h @@ -9,6 +9,7 @@ #include #include #include +#include #include #include #include @@ -20,6 +21,7 @@ #include "coordinates.h" #include "creature.h" #include "cursesdef.h" +#include "effect_on_condition.h" #include "enums.h" #include "game_constants.h" #include "item_location.h" @@ -1045,6 +1047,9 @@ class game weather_manager weather; + std::vector inactive_effect_on_condition_vector; + std::priority_queue, eoc_compare> queued_effect_on_conditions; + int mostseen = 0; // # of mons seen last turn; if this increases, set safe_mode to SAFE_MODE_STOP private: shared_ptr_fast u_shared_ptr; diff --git a/src/init.cpp b/src/init.cpp index 8a76c67f83184..f5deaf318cb6e 100644 --- a/src/init.cpp +++ b/src/init.cpp @@ -31,6 +31,7 @@ #include "dialogue.h" #include "disease.h" #include "effect.h" +#include "effect_on_condition.h" #include "emit.h" #include "event_statistics.h" #include "faction.h" @@ -239,6 +240,7 @@ void DynamicDataLoader::initialize() add( "json_flag", &json_flag::load_all ); add( "fault", &fault::load_fault ); add( "relic_procgen_data", &relic_procgen_data::load_relic_procgen_data ); + add( "effect_on_condition", &effect_on_conditions::load ); add( "field_type", &field_types::load ); add( "weather_type", &weather_types::load ); add( "ammo_effect", &ammo_effects::load ); @@ -526,6 +528,7 @@ void DynamicDataLoader::unload_data() dreams.clear(); emit::reset(); event_statistic::reset(); + effect_on_conditions::reset(); event_transformation::reset(); faction_template::reset(); fault::reset(); @@ -616,6 +619,7 @@ void DynamicDataLoader::finalize_loaded_data( loading_ui &ui ) { _( "Flags" ), &json_flag::finalize_all }, { _( "Body parts" ), &body_part_type::finalize_all }, { _( "Weather types" ), &weather_types::finalize_all }, + { _( "Effect on conditions" ), &effect_on_conditions::finalize_all }, { _( "Field types" ), &field_types::finalize_all }, { _( "Ammo effects" ), &ammo_effects::finalize_all }, { _( "Emissions" ), &emit::finalize }, @@ -700,6 +704,7 @@ void DynamicDataLoader::check_consistency( loading_ui &ui ) }, { _( "Vitamins" ), &vitamin::check_consistency }, { _( "Weather types" ), &weather_types::check_consistency }, + { _( "Effect on conditions" ), &effect_on_conditions::check_consistency }, { _( "Field types" ), &field_types::check_consistency }, { _( "Ammo effects" ), &ammo_effects::check_consistency }, { _( "Emissions" ), &emit::check_consistency }, diff --git a/src/mission_util.cpp b/src/mission_util.cpp index b3fa1e641feea..2458745988feb 100644 --- a/src/mission_util.cpp +++ b/src/mission_util.cpp @@ -529,7 +529,7 @@ bool mission_type::parse_funcs( const JsonObject &jo, std::functionfind_npc( miss->get_npc_id() ); diff --git a/src/npctalk.cpp b/src/npctalk.cpp index 885938b97ac79..6ad38bee93b2c 100644 --- a/src/npctalk.cpp +++ b/src/npctalk.cpp @@ -2134,9 +2134,9 @@ talk_topic talk_effect_t::apply( dialogue &d ) const return next_topic; } -talk_effect_t::talk_effect_t( const JsonObject &jo ) +talk_effect_t::talk_effect_t( const JsonObject &jo, const std::string &member_name ) { - load_effect( jo ); + load_effect( jo, member_name ); if( jo.has_object( "topic" ) ) { next_topic = load_inline_topic( jo.get_object( "topic" ) ); } else if( jo.has_string( "topic" ) ) { @@ -2414,7 +2414,7 @@ void talk_effect_t::parse_string_effect( const std::string &effect_id, const Jso jo.throw_error( "unknown effect string", effect_id ); } -void talk_effect_t::load_effect( const JsonObject &jo ) +void talk_effect_t::load_effect( const JsonObject &jo, const std::string &member_name ) { if( jo.has_member( "opinion" ) ) { JsonIn *ji = jo.get_raw( "opinion" ); @@ -2426,7 +2426,6 @@ void talk_effect_t::load_effect( const JsonObject &jo ) // Same format as when saving a game (-: mission_opinion.deserialize( *ji ); } - static const std::string member_name( "effect" ); if( !jo.has_member( member_name ) ) { return; } else if( jo.has_string( member_name ) ) { @@ -2487,11 +2486,11 @@ talk_response::talk_response( const JsonObject &jo ) } if( jo.has_member( "success" ) ) { JsonObject success_obj = jo.get_object( "success" ); - success = talk_effect_t( success_obj ); + success = talk_effect_t( success_obj, "effect" ); } else if( jo.has_string( "topic" ) ) { // This is for simple topic switching without a possible failure success.next_topic = talk_topic( jo.get_string( "topic" ) ); - success.load_effect( jo ); + success.load_effect( jo, "effect" ); } else if( jo.has_object( "topic" ) ) { success.next_topic = load_inline_topic( jo.get_object( "topic" ) ); } @@ -2500,7 +2499,7 @@ talk_response::talk_response( const JsonObject &jo ) } if( jo.has_member( "failure" ) ) { JsonObject failure_obj = jo.get_object( "failure" ); - failure = talk_effect_t( failure_obj ); + failure = talk_effect_t( failure_obj, "effect" ); } // TODO: mission_selected @@ -2761,7 +2760,7 @@ json_dynamic_line_effect::json_dynamic_line_effect( const JsonObject &jo, { std::function tmp_condition; read_condition( jo, "condition", tmp_condition, true ); - talk_effect_t tmp_effect = talk_effect_t( jo ); + talk_effect_t tmp_effect = talk_effect_t( jo, "effect" ); // if the topic has a sentinel, it means implicitly add a check for the sentinel value // and do not run the effects if it is set. if it is not set, run the effects and // set the sentinel diff --git a/src/savegame.cpp b/src/savegame.cpp index 96a1b941acfd4..ce41928e5472c 100644 --- a/src/savegame.cpp +++ b/src/savegame.cpp @@ -101,6 +101,26 @@ void game::serialize( std::ostream &fout ) json.member( "stats_tracker", *stats_tracker_ptr ); json.member( "achievements_tracker", *achievements_tracker_ptr ); + //save queued effect_on_conditions + std::vector temp_queue; + while( !g->queued_effect_on_conditions.empty() ) { + temp_queue.push_back( g->queued_effect_on_conditions.top() ); + g->queued_effect_on_conditions.pop(); + } + json.member( "queued_effect_on_conditions" ); + json.start_array(); + + for( const auto &queued : temp_queue ) { + g->queued_effect_on_conditions.push( queued ); + json.start_object(); + json.member( "time", queued.time ); + json.member( "eoc", queued.eoc ); + json.member( "recurring", queued.recurring ); + json.end_object(); + } + json.end_array(); + json.member( "inactive_eocs", inactive_effect_on_condition_vector ); + json.member( "player", u ); Messages::serialize( json ); @@ -232,6 +252,24 @@ void game::unserialize( std::istream &fin ) data.read( "player", u ); data.read( "stats_tracker", *stats_tracker_ptr ); data.read( "achievements_tracker", *achievements_tracker_ptr ); + + //load queued_eocs + for( JsonObject elem : data.get_array( "queued_effect_on_conditions" ) ) { + queued_eoc temp; + temp.time = time_point( elem.get_int( "time" ) ); + temp.eoc = effect_on_condition_id( elem.get_string( "eoc" ) ); + temp.recurring = elem.get_bool( "recurring" ); + g->queued_effect_on_conditions.push( temp ); + } + //load inactive queued_eocs + for( JsonObject elem : data.get_array( "inactive_effect_on_conditions" ) ) { + queued_eoc temp; + temp.time = time_point( elem.get_int( "time" ) ); + temp.eoc = effect_on_condition_id( elem.get_string( "eoc" ) ); + temp.recurring = elem.get_bool( "recurring" ); + g->queued_effect_on_conditions.push( temp ); + } + data.read( "inactive_eocs", inactive_effect_on_condition_vector ); Messages::deserialize( data ); } catch( const JsonError &jsonerr ) { diff --git a/src/type_id.h b/src/type_id.h index b1f9ee6b4b2c7..363f8ae8bb117 100644 --- a/src/type_id.h +++ b/src/type_id.h @@ -36,6 +36,9 @@ using construction_group_str_id = string_id; struct clothing_mod; using clothing_mod_id = string_id; +struct effect_on_condition; +using effect_on_condition_id = string_id; + class effect_type; using efftype_id = string_id; From aa6c02e218e78fee0b28b09b5ee54d86b6c93bb6 Mon Sep 17 00:00:00 2001 From: Salty Panda Date: Thu, 25 Mar 2021 20:30:22 +0100 Subject: [PATCH 105/453] [Magiclysm] Add spellcraft skillbook (#47431) * add spellcraft skillbook * Spawning too * Change spawns --- .../mods/Magiclysm/itemgroups/itemgroups.json | 24 +++++++++--- data/mods/Magiclysm/items/books.json | 39 +++++++++++++++++++ 2 files changed, 58 insertions(+), 5 deletions(-) create mode 100644 data/mods/Magiclysm/items/books.json diff --git a/data/mods/Magiclysm/itemgroups/itemgroups.json b/data/mods/Magiclysm/itemgroups/itemgroups.json index 54f1baa86964e..98a036a4cba1d 100644 --- a/data/mods/Magiclysm/itemgroups/itemgroups.json +++ b/data/mods/Magiclysm/itemgroups/itemgroups.json @@ -32,7 +32,8 @@ { "group": "spellbook_loot_1", "prob": 3 }, { "group": "magic_recipe_basic", "prob": 3 }, { "group": "magic_recipe_advanced", "prob": 1 }, - { "group": "dragon_books", "prob": 3 } + { "group": "dragon_books", "prob": 3 }, + { "item": "spellcraft_theory", "prob": 2 } ] }, { @@ -42,13 +43,23 @@ { "group": "spellbook_loot_0", "prob": 6 }, { "group": "magic_recipe_basic", "prob": 6 }, { "group": "magic_recipe_advanced", "prob": 2 }, - { "group": "dragon_books", "prob": 5 } + { "group": "dragon_books", "prob": 5 }, + { "group": "spellcraft_books", "prob": 4 } ] }, { "type": "item_group", "id": "exotic_books", - "items": [ { "group": "spellbook_loot_1", "prob": 3 }, { "group": "dragon_books", "prob": 2 } ] + "items": [ + { "group": "spellbook_loot_1", "prob": 3 }, + { "group": "dragon_books", "prob": 2 }, + { "group": "spellcraft_books", "prob": 1 } + ] + }, + { + "type": "item_group", + "id": "spellcraft_books", + "items": [ { "item": "spellcraft_theory_basic", "prob": 70 }, { "item": "spellcraft_theory", "prob": 30 } ] }, { "type": "item_group", @@ -131,7 +142,8 @@ { "group": "spell_scroll_tier_1", "prob": 60 }, { "group": "spell_scroll_tier_2", "prob": 30 }, { "group": "magic_recipe_basic", "prob": 50 }, - { "group": "magic_recipe_advanced", "prob": 16 } + { "group": "magic_recipe_advanced", "prob": 16 }, + { "group": "spellcraft_books", "prob": 40 } ] }, { @@ -142,7 +154,8 @@ { "group": "spellbook_tier_0", "prob": 100 }, { "group": "spellbook_tier_0", "prob": 80 }, { "group": "spellbook_tier_0", "prob": 60 }, - { "group": "spellbook_tier_0", "prob": 20 } + { "group": "spellbook_tier_0", "prob": 20 }, + { "item": "spellcraft_theory_basic", "prob": 10 } ] }, { @@ -1014,6 +1027,7 @@ { "group": "enchanted_tokens_tool", "prob": 15 }, { "group": "enchanted_tokens_weapon", "prob": 5 }, { "group": "potions_common", "prob": 35 }, + { "group": "spellcraft_books", "prob": 10 }, { "distribution": [ { "group": "enchanted_wands_lesser", "prob": 15 }, diff --git a/data/mods/Magiclysm/items/books.json b/data/mods/Magiclysm/items/books.json new file mode 100644 index 0000000000000..ba3642e57161e --- /dev/null +++ b/data/mods/Magiclysm/items/books.json @@ -0,0 +1,39 @@ +[ + { + "id": "spellcraft_theory", + "type": "BOOK", + "name": { "str": "Spellcraft Theory", "str_pl": "copies of Spellcraft Theory" }, + "description": "A intermediate textbook on magical theories.", + "weight": "1587 g", + "volume": "1750 ml", + "longest_side": "22 cm", + "price": 8200, + "price_postapoc": 750, + "bashing": 5, + "material": [ "paper" ], + "symbol": "?", + "color": "blue", + "skill": "spellcraft", + "required_level": 2, + "max_level": 4, + "intelligence": 12, + "time": "60 m", + "fun": -1 + }, + { + "id": "spellcraft_theory_basic", + "type": "BOOK", + "copy-from": "spellcraft_theory", + "name": { "str": "Basic Spellcraft Theory", "str_pl": "copies of Basic Spellcraft Theory" }, + "description": "A beginner textbook on magical theories.", + "weight": "1087 g", + "volume": "1450 ml", + "price": 5200, + "price_postapoc": 550, + "required_level": 0, + "max_level": 2, + "intelligence": 9, + "time": "45 m", + "fun": 0 + } +] From 038125151dbf2aeca1d169d72389edb7ff3d6565 Mon Sep 17 00:00:00 2001 From: OromisElf Date: Thu, 25 Mar 2021 20:39:35 +0100 Subject: [PATCH 106/453] added golem core, summon golem spell and ways to find golem core (#47500) * added golem core, summon golem spell and ways to find golem core golemancer can summon a clay golem with a golem core as a focus; golem cores aren't crafteable YET * linted attunements forgot to do that >.> * added a recipe for golem core and a basic golemancy proficiency --- .../Spells/attunements/Golemancer.json | 52 +++++++++++++++++++ .../mods/Magiclysm/itemgroups/itemgroups.json | 4 ++ data/mods/Magiclysm/items/constructs.json | 15 ++++++ data/mods/Magiclysm/proficiencies.json | 10 ++++ .../mods/Magiclysm/recipes/blacksmithing.json | 25 +++++++++ data/mods/Magiclysm/traits/attunements.json | 2 +- 6 files changed, 107 insertions(+), 1 deletion(-) diff --git a/data/mods/Magiclysm/Spells/attunements/Golemancer.json b/data/mods/Magiclysm/Spells/attunements/Golemancer.json index 5656a3651d3b9..eda42f5345646 100644 --- a/data/mods/Magiclysm/Spells/attunements/Golemancer.json +++ b/data/mods/Magiclysm/Spells/attunements/Golemancer.json @@ -1,4 +1,56 @@ [ + { + "id": "summon_golem", + "type": "requirement", + "components": [ [ [ "golemcore", 1 ] ] ] + }, + { + "id": "summon_golem_clay", + "type": "SPELL", + "spell_class": "GOLEMANCER", + "name": "Summon Claygolem", + "description": "Use a golem core as a focus to shape clay into a roughly humanoid shape and animate it for some time.", + "valid_targets": [ "ground" ], + "effect": "summon", + "effect_str": "mon_claygolem", + "shape": "blast", + "base_casting_time": 3500, + "casting_time_increment": -100, + "final_casting_time": 2000, + "base_energy_cost": 500, + "energy_source": "MANA", + "difficulty": 6, + "max_level": 35, + "min_damage": 1, + "max_damage": 1, + "min_duration": 30000, + "max_duration": 90000, + "duration_increment": 1715, + "min_range": 3, + "max_range": 3, + "components": "summon_golem", + "extra_effects": [ { "id": "summon_golem_focus" } ], + "flags": [ "SOMATIC", "VERBAL", "CONCENTRATE" ] + }, + { + "id": "summon_golem_focus", + "type": "SPELL", + "spell_class": "NONE", + "name": "Give back core", + "description": "Gives back a golem's core. You should not see this spell", + "valid_targets": [ "self" ], + "effect": "spawn_item", + "effect_str": "golemcore", + "shape": "blast", + "base_casting_time": 100, + "base_energy_cost": 1000, + "energy_source": "MANA", + "difficulty": 1, + "min_damage": 1, + "max_damage": 1, + "duration_increment": 1, + "flags": [ "PERMANENT", "NO_LEGS", "CONCENTRATE" ] + }, { "type": "SPELL", "id": "golem_push", diff --git a/data/mods/Magiclysm/itemgroups/itemgroups.json b/data/mods/Magiclysm/itemgroups/itemgroups.json index 98a036a4cba1d..4be9b3778fff3 100644 --- a/data/mods/Magiclysm/itemgroups/itemgroups.json +++ b/data/mods/Magiclysm/itemgroups/itemgroups.json @@ -344,6 +344,7 @@ "type": "item_group", "//": "all enchanted miscellanious items", "items": [ + { "item": "golemcore", "prob": 10 }, { "item": "heat_cube", "prob": 100 }, { "item": "mkey_opening", "prob": 100 }, { "item": "mtorch_everburning", "prob": 100 }, @@ -818,6 +819,7 @@ }, { "distribution": [ + { "item": "golemcore", "prob": 20 }, { "item": "animist_doll_skeleton", "prob": 10 }, { "item": "animist_doll_zombie", "prob": 20 }, { "item": "animist_doll_decayed_pouncer", "prob": 3 } @@ -936,6 +938,7 @@ }, { "distribution": [ + { "item": "golemcore", "prob": 10 }, { "item": "recovery_spellbook", "prob": 5 }, { "item": "eshaper_spellbook", "prob": 10 }, { "item": "spell_scroll_recover_stamina", "prob": 50 }, @@ -1058,6 +1061,7 @@ }, { "distribution": [ + { "item": "golemcore", "prob": 3 }, { "item": "light_manipulation_spellbook", "prob": 5 }, { "item": "translocate_spellbook", "prob": 2 }, { "item": "spell_scroll_obfuscated_body", "prob": 50 } diff --git a/data/mods/Magiclysm/items/constructs.json b/data/mods/Magiclysm/items/constructs.json index e1288be2576b5..5b534b18d5aa4 100644 --- a/data/mods/Magiclysm/items/constructs.json +++ b/data/mods/Magiclysm/items/constructs.json @@ -1,4 +1,19 @@ [ + { + "type": "GENERIC", + "id": "golemcore", + "symbol": ".", + "color": "red", + "name": "golem core", + "description": "The \"heart\" of a golem. Makes a soft humming noise when you hold it close to your ear.", + "price": 10000, + "price_postapoc": 5000, + "material": [ "orichalcum_metal" ], + "weight": "5 kg", + "volume": "1 L", + "bashing": 6, + "flags": [ "NO_REPAIR", "FRAGILE_MELEE" ] + }, { "type": "GENERIC", "id": "broken_claygolem", diff --git a/data/mods/Magiclysm/proficiencies.json b/data/mods/Magiclysm/proficiencies.json index 2eaf25d02e2c8..6d13fc27d1d33 100644 --- a/data/mods/Magiclysm/proficiencies.json +++ b/data/mods/Magiclysm/proficiencies.json @@ -19,5 +19,15 @@ "default_time_multiplier": 2, "default_fail_multiplier": 2, "required_proficiencies": [ "prof_alchemy" ] + }, + { + "type": "proficiency", + "id": "prof_golemancy_basic", + "name": { "str": "Basic Golemancy" }, + "description": "Infusing shaped material with your will and the ability to move is hard but you're starting to get it.", + "can_learn": true, + "time_to_learn": "4 h", + "default_time_multiplier": 1.5, + "default_fail_multiplier": 2 } ] diff --git a/data/mods/Magiclysm/recipes/blacksmithing.json b/data/mods/Magiclysm/recipes/blacksmithing.json index 95a4f7c4e0736..5033df4212c0b 100644 --- a/data/mods/Magiclysm/recipes/blacksmithing.json +++ b/data/mods/Magiclysm/recipes/blacksmithing.json @@ -70,5 +70,30 @@ "proficiencies": [ { "proficiency": "prof_alchemy", "required": false, "time_multiplier": 1.5, "fail_multiplier": 5 } ], "tools": [ [ [ "surface_heat", 10, "LIST" ] ] ], "components": [ [ [ "charcoal", 50 ] ], [ [ "crystallized_mana", 10 ] ], [ [ "denat_alcohol", 10 ] ] ] + }, + { + "type": "recipe", + "activity_level": "MODERATE_EXERCISE", + "result": "golemcore", + "category": "CC_ENCHANTED", + "subcategory": "CSC_ENCHANTED_OTHER", + "skill_used": "fabrication", + "skills_required": [ "spellcraft", 6 ], + "difficulty": 5, + "time": "150 m", + "book_learn": [ [ "metal_legends", 6 ] ], + "qualities": [ + { "id": "CHISEL", "level": 2 }, + { "id": "MANA_INFUSE", "level": 2 }, + { "id": "HAMMER_FINE", "level": 1 }, + { "id": "FILE", "level": 2 }, + { "id": "ANVIL", "level": 1 } + ], + "tools": [ [ [ "demon_forge", 30 ] ], [ [ "tongs", -1 ] ] ], + "proficiencies": [ + { "proficiency": "prof_almetallurgy", "required": true }, + { "proficiency": "prof_golemancy_basic", "required": false, "time_multiplier": 1.5, "fail_multiplier": 2 } + ], + "components": [ [ [ "orichalcum_ingot", 4 ] ], [ [ "mercury", 4 ] ], [ [ "crystallized_mana", 100 ] ] ] } ] diff --git a/data/mods/Magiclysm/traits/attunements.json b/data/mods/Magiclysm/traits/attunements.json index 87066d1ac2589..639f6d11c3b8c 100644 --- a/data/mods/Magiclysm/traits/attunements.json +++ b/data/mods/Magiclysm/traits/attunements.json @@ -503,7 +503,7 @@ "valid": false, "description": "The Golemancer is the ancient myth of the clay golem, made reality from constant use of Animist summons and Earthshaper self-strengthening spells. Takes some traits from the golems they create, such as immunity to slowing effects.", "prereqs": [ "ANIMIST", "EARTHSHAPER" ], - "spells_learned": [ [ "golem_push", 5 ] ], + "spells_learned": [ [ "golem_push", 5 ], [ "summon_golem_clay", 5 ] ], "cancels": [ "ARTIFICER", "AURA_MAGE", From 20baf00312104d54f7003819454bc0e46f66e085 Mon Sep 17 00:00:00 2001 From: OromisElf Date: Thu, 25 Mar 2021 20:43:48 +0100 Subject: [PATCH 107/453] new druid spell: seed of growth (#47912) * new druid spell: seed of growth * added comment for future json workers --- data/mods/Magiclysm/Spells/druid.json | 23 +++++++++++++++++++ .../mods/Magiclysm/itemgroups/itemgroups.json | 3 ++- .../mods/Magiclysm/itemgroups/spellbooks.json | 1 + data/mods/Magiclysm/items/ethereal_items.json | 18 +++++++++++++++ data/mods/Magiclysm/items/spell_scrolls.json | 9 ++++++++ 5 files changed, 53 insertions(+), 1 deletion(-) diff --git a/data/mods/Magiclysm/Spells/druid.json b/data/mods/Magiclysm/Spells/druid.json index 5acc79f74e387..dbe29be9b020b 100644 --- a/data/mods/Magiclysm/Spells/druid.json +++ b/data/mods/Magiclysm/Spells/druid.json @@ -398,5 +398,28 @@ "shape": "blast", "effect": "summon", "effect_str": "mon_wolf" + }, + { + "id": "druid_growth", + "type": "SPELL", + "spell_class": "DRUID", + "name": "Seed of Growth", + "description": "Offer some of your life in a ritual to get tokens of growth in return.", + "valid_targets": [ "self" ], + "effect": "spawn_item", + "effect_str": "druid_fertilizer", + "shape": "blast", + "base_casting_time": 360000, + "final_casting_time": 90000, + "casting_time_increment": -15000, + "base_energy_cost": 5, + "energy_source": "HP", + "difficulty": 4, + "max_level": 20, + "min_damage": 5, + "max_damage": 80, + "damage_increment": 4, + "//": "The spell can only be permanent without being at maximum level because of how items with charges work", + "flags": [ "SOMATIC", "NO_LEGS", "PERMANENT" ] } ] diff --git a/data/mods/Magiclysm/itemgroups/itemgroups.json b/data/mods/Magiclysm/itemgroups/itemgroups.json index 4be9b3778fff3..d6eea28c00f7c 100644 --- a/data/mods/Magiclysm/itemgroups/itemgroups.json +++ b/data/mods/Magiclysm/itemgroups/itemgroups.json @@ -996,7 +996,8 @@ { "item": "spell_scroll_druid_woodshaft", "prob": 30 }, { "item": "summon_scroll_smudged", "prob": 2 }, { "item": "spell_scroll_tornskin", "prob": 2 }, - { "item": "spell_scroll_summon_cats", "prob": 50 } + { "item": "spell_scroll_summon_cats", "prob": 50 }, + { "item": "spell_scroll_seed_of_growth", "prob": 15 } ], "prob": 45 }, diff --git a/data/mods/Magiclysm/itemgroups/spellbooks.json b/data/mods/Magiclysm/itemgroups/spellbooks.json index 2d538d1a7aab4..ee790246a596f 100644 --- a/data/mods/Magiclysm/itemgroups/spellbooks.json +++ b/data/mods/Magiclysm/itemgroups/spellbooks.json @@ -13,6 +13,7 @@ [ "spell_scroll_blinding_flash", 50 ], [ "spell_scroll_ethereal_grasp", 50 ], [ "spell_scroll_druid_woodshaft", 50 ], + [ "spell_scroll_seed_of_growth", 35 ], [ "spell_scroll_summon_cats", 65 ], [ "spell_scroll_stonefist", 20 ], [ "spell_scroll_eshaper_piercing_bolt", 40 ], diff --git a/data/mods/Magiclysm/items/ethereal_items.json b/data/mods/Magiclysm/items/ethereal_items.json index fca6f63e3b456..4f96dda1d4d77 100644 --- a/data/mods/Magiclysm/items/ethereal_items.json +++ b/data/mods/Magiclysm/items/ethereal_items.json @@ -378,6 +378,24 @@ "max_charges": 15, "use_action": [ "WATER_PURIFIER" ] }, + { + "type": "COMESTIBLE", + "id": "druid_fertilizer", + "name": { "str": "seed of growth", "str_pl": "seeds of growth" }, + "weight": "27 g", + "color": "white", + "flags": [ "TRADER_AVOID", "FERTILIZER" ], + "comestible_type": "FOOD", + "symbol": "°", + "quench": -10, + "healthy": -2, + "description": "A magical powder that can be scattered on growing crops and make them grow faster.", + "material": [ "powder" ], + "volume": "2 L", + "charges": 60, + "category": "chems", + "fun": -15 + }, { "id": "obfuscating_aura", "type": "ARMOR", diff --git a/data/mods/Magiclysm/items/spell_scrolls.json b/data/mods/Magiclysm/items/spell_scrolls.json index abbf141e0de31..196bd38f10a72 100644 --- a/data/mods/Magiclysm/items/spell_scrolls.json +++ b/data/mods/Magiclysm/items/spell_scrolls.json @@ -1035,5 +1035,14 @@ "name": { "str": "Scroll of freezing touch", "str_pl": "Scrolls of freezing touch" }, "description": "Your hands freeze anything they touch at temperatures so cold it slows down your foes.", "use_action": { "type": "learn_spell", "spells": [ "freezing_touch" ] } + }, + { + "type": "BOOK", + "copy-from": "spell_scroll", + "id": "spell_scroll_seed_of_growth", + "//": "Druid spell", + "name": { "str": "Scroll of seed of growth", "str_pl": "Scrolls of seed of growth" }, + "description": "Offer some of your life in a ritual to get tokens of growth in return.", + "use_action": { "type": "learn_spell", "spells": [ "druid_growth" ] } } ] From c3ba400c9988f847962fd78b4bba18536264f8d6 Mon Sep 17 00:00:00 2001 From: Salty Panda Date: Thu, 25 Mar 2021 22:28:14 +0100 Subject: [PATCH 108/453] [Magiclysm] Overhaul and balance dragon items (#47499) * Overhaul dragon items * Fixes * Small balance fixes after testing, make crafting costs more linear * Update data/mods/Magiclysm/items/black_dragon_items.json Co-authored-by: actual-nh <74678550+actual-nh@users.noreply.github.com> * Update data/mods/Magiclysm/items/black_dragon_items.json Co-authored-by: actual-nh <74678550+actual-nh@users.noreply.github.com> * Make xl visor the same thickness as normal one to avoid error, specify in description that dragon hide/scale is very durable, fix gloves description mentioning Kevlar, add XL backpack * lint * fix xl backpack * Update data/mods/Magiclysm/items/black_dragon_items.json Co-authored-by: actual-nh <74678550+actual-nh@users.noreply.github.com> Co-authored-by: Curtis Merrill --- .../Magiclysm/items/black_dragon_items.json | 216 ++++++++++------- data/mods/Magiclysm/items/tools.json | 4 +- data/mods/Magiclysm/materials.json | 46 +++- data/mods/Magiclysm/proficiencies.json | 22 ++ data/mods/Magiclysm/recipes/alchemy.json | 26 +++ data/mods/Magiclysm/recipes/dragon_black.json | 221 +++++++++++++----- data/mods/Magiclysm/tool_qualities.json | 5 + doc/JSON_INFO.md | 4 +- 8 files changed, 383 insertions(+), 161 deletions(-) diff --git a/data/mods/Magiclysm/items/black_dragon_items.json b/data/mods/Magiclysm/items/black_dragon_items.json index 64cda2534e678..10f2bc1a42cc0 100644 --- a/data/mods/Magiclysm/items/black_dragon_items.json +++ b/data/mods/Magiclysm/items/black_dragon_items.json @@ -7,7 +7,7 @@ "color": "black_white", "name": "black dragon scale", "price": 2500, - "material": [ "black_dragon_hide" ], + "material": [ "black_dragon_scales" ], "weight": "380 g", "volume": "75 ml", "bashing": 0, @@ -95,20 +95,20 @@ "type": "ARMOR", "category": "armor", "name": { "str": "pair of black dragonscale boots", "str_pl": "pairs of black dragonscale boots" }, - "description": "Boots made of black dragonscale. Very protective, and surprisingly light.", + "description": "Boots made of black incredibly durable dragonscale. Very protective, and surprisingly light.", "weight": "945 g", "volume": "3250 ml", "price": 75000, "to_hit": -2, "bashing": 7, - "material": [ "black_dragon_hide" ], + "material": [ "black_dragon_hide", "black_dragon_scales" ], "symbol": "[", "color": "black_white", "covers": [ "foot_l", "foot_r" ], "coverage": 100, "encumbrance": 30, - "warmth": 20, - "material_thickness": 4, + "warmth": 25, + "material_thickness": 5, "environmental_protection": 3, "flags": [ "VARSIZE", "WATERPROOF", "STURDY" ] }, @@ -117,7 +117,7 @@ "type": "ARMOR", "category": "armor", "name": { "str": "pair of black dragonhide boots", "str_pl": "pairs of black dragonhide boots" }, - "description": "Boots made of black dragonhide. Very protective, and surprisingly light.", + "description": "Boots made of very durable black dragonhide. Very protective, and surprisingly light.", "weight": "655 g", "volume": "3250 ml", "price": 50000, @@ -128,9 +128,9 @@ "color": "black_white", "covers": [ "foot_l", "foot_r" ], "coverage": 100, - "encumbrance": 18, + "encumbrance": 20, "warmth": 20, - "material_thickness": 2, + "material_thickness": 3, "environmental_protection": 3, "flags": [ "VARSIZE", "WATERPROOF", "STURDY" ] }, @@ -139,32 +139,47 @@ "type": "ARMOR", "category": "armor", "name": "black dragonscale helmet", - "description": "A helmet made from black dragonscale, held together with black dragonhide. It comes equipped with a full face visor.", + "description": "A helmet made from black incredibly durable dragonscale, held together with black dragonhide. It comes equipped with a full face visor with only a thin slit to see out of. Activate to raise the visor.", + "use_action": { "type": "transform", "target": "helmet_black_dragon_scale_raised", "msg": "You raise your visor." }, "weight": "856 g", "volume": "2500 ml", "price": 58000, "to_hit": -1, "bashing": 10, - "material": [ "black_dragon_hide" ], + "material": [ "black_dragon_hide", "black_dragon_scales" ], "symbol": "[", "color": "black_white", - "covers": [ "head", "eyes", "mouth" ], - "coverage": 100, - "encumbrance": 32, - "warmth": 15, - "material_thickness": 6, + "armor_portion_data": [ + { "covers": [ "head" ], "coverage": 100, "encumbrance": 32 }, + { "covers": [ "eyes", "mouth" ], "coverage": 100, "encumbrance": 20 } + ], + "warmth": 25, + "material_thickness": 5, "environmental_protection": 3, "techniques": [ "WBLOCK_1" ], - "flags": [ "VARSIZE", "WATERPROOF", "STURDY" ] + "qualities": [ [ "GLARE", 1 ] ], + "flags": [ "VARSIZE", "WATERPROOF", "STURDY", "SUN_GLASSES" ] + }, + { + "id": "helmet_black_dragon_scale_raised", + "type": "ARMOR", + "category": "armor", + "copy-from": "helmet_black_dragon_scale", + "name": { "str": "black dragonscale helmet (raised visor)", "str_pl": "black dragonscale helmets (raised visor)" }, + "description": "A helmet made from incredibly durable black dragonscale, held together with black dragonhide. The visor is raised.", + "use_action": { "type": "transform", "target": "helmet_black_dragon_scale", "msg": "You put down your visor." }, + "symbol": "[", + "armor_portion_data": [ { "covers": [ "head" ], "coverage": 100, "encumbrance": 32 } ], + "delete": { "qualities": [ [ "GLARE", 1 ] ], "flags": [ "SUN_GLASSES" ] } }, { "id": "helmet_black_dragon_hide", "type": "ARMOR", "category": "armor", "name": "black dragonhide helmet", - "description": "A helmet made from black dragonhide. It protects your head well, and doesn't cover your face.", + "description": "A helmet made from very durable black dragonhide. It protects your head well, but doesn't cover your face.", "weight": "585 g", - "volume": "2500 ml", + "volume": "2 L", "price": 58000, "to_hit": -1, "bashing": 10, @@ -173,9 +188,9 @@ "color": "black_white", "covers": [ "head" ], "coverage": 100, - "encumbrance": 32, + "encumbrance": 20, "warmth": 15, - "material_thickness": 2, + "material_thickness": 3, "environmental_protection": 1, "techniques": [ "WBLOCK_1" ], "flags": [ "VARSIZE", "WATERPROOF", "STURDY" ] @@ -185,21 +200,21 @@ "type": "ARMOR", "category": "armor", "name": "black dragonscale armor", - "description": "A full suit of black dragon scale mail. It comes with all the accoutrements that cover your torso, legs, and arms, with the benefit of being very light and flexible.", + "description": "A full suit of incredibly durable black dragon scale mail. It comes with all the accoutrements that cover your torso, legs, and arms, with the benefit of being very light and flexible.", "weight": "4250 g", "volume": "12 L", "price": 2000000, "to_hit": -3, "bashing": 6, - "material": [ "black_dragon_hide" ], + "material": [ "black_dragon_hide", "black_dragon_scales" ], "symbol": "[", "color": "black_white", "covers": [ "leg_l", "leg_r", "torso", "arm_l", "arm_r" ], "coverage": 100, "encumbrance": 25, - "warmth": 15, - "material_thickness": 4, - "environmental_protection": 2, + "warmth": 25, + "material_thickness": 5, + "environmental_protection": 3, "flags": [ "VARSIZE", "WATERPROOF", "RAINPROOF", "STURDY" ] }, { @@ -207,9 +222,9 @@ "type": "ARMOR", "category": "armor", "name": "black dragonhide armor", - "description": "A full suit of black dragonhide armor. It comes with all the accoutrements that cover your torso, legs, and arms, with the benefit of being very light and flexible.", + "description": "A full suit of very durable black dragonhide armor. It comes with all the accoutrements that cover your torso, legs, and arms, with the benefit of being very light and flexible.", "weight": "3 kg", - "volume": "12 L", + "volume": "11 L", "price": 2000000, "to_hit": -3, "bashing": 6, @@ -220,8 +235,8 @@ "coverage": 100, "encumbrance": 18, "warmth": 15, - "material_thickness": 4, - "environmental_protection": 1, + "material_thickness": 3, + "environmental_protection": 2, "flags": [ "VARSIZE", "WATERPROOF", "RAINPROOF", "STURDY" ] }, { @@ -229,19 +244,19 @@ "type": "ARMOR", "category": "armor", "name": { "str": "pair of black dragonscale gauntlets", "str_pl": "pairs of black dragonscale gauntlets" }, - "description": "A pair of heavy-duty gauntlets made of black dragonscale that covers your hands.", + "description": "A pair of heavy-duty gauntlets made of incredibly durable black dragonscale that covers your hands.", "weight": "380 g", "volume": "1 L", "price": 180000, "to_hit": 2, - "material": [ "black_dragon_hide" ], + "material": [ "black_dragon_hide", "black_dragon_scales" ], "symbol": "[", "color": "black_white", "covers": [ "hand_l", "hand_r" ], "coverage": 100, "encumbrance": 20, - "warmth": 15, - "material_thickness": 3, + "warmth": 20, + "material_thickness": 4, "environmental_protection": 3, "flags": [ "VARSIZE", "WATERPROOF", "STURDY" ] }, @@ -250,7 +265,7 @@ "type": "ARMOR", "category": "armor", "name": { "str": "pair of black dragonhide gloves", "str_pl": "pairs of black dragonhide gloves" }, - "description": "A pair of customized, Kevlar armored leather gloves, modified to be easy to wear while providing maximum protection under extreme conditions.", + "description": "A pair of gloves made of very durable black dragonhide, modified to be easy to wear while providing maximum protection under extreme conditions.", "weight": "230 g", "volume": "750 ml", "price": 180000, @@ -261,7 +276,7 @@ "covers": [ "hand_l", "hand_r" ], "coverage": 100, "encumbrance": 8, - "warmth": 15, + "warmth": 13, "material_thickness": 2, "environmental_protection": 1, "flags": [ "VARSIZE", "WATERPROOF", "STURDY" ] @@ -271,7 +286,7 @@ "copy-from": "boots_black_dragon_scale", "type": "ARMOR", "name": { "str": "pair of XL black dragonscale boots", "str_pl": "pairs of XL black dragonscale boots" }, - "description": "Massive boots made of black dragonscale, modified to fit even the strangest of bodies. Very protective, and surprisingly light.", + "description": "Massive boots made of incredibly durable black dragonscale, modified to fit even the strangest of bodies. Very protective, and surprisingly light.", "weight": "1545 g", "volume": "6250 ml", "encumbrance": 40, @@ -282,10 +297,10 @@ "copy-from": "boots_black_dragon_hide", "type": "ARMOR", "name": { "str": "pair of XL black dragonhide boots", "str_pl": "pairs of XL black dragonhide boots" }, - "description": "Massive boots made of black dragonhide, modified to fit even the strangest of bodies. Very protective, and surprisingly light.", + "description": "Massive boots made of very durable black dragonhide, modified to fit even the strangest of bodies. Very protective, and surprisingly light.", "weight": "955 g", "volume": "6250 ml", - "encumbrance": 28, + "encumbrance": 25, "flags": [ "OVERSIZE", "VARSIZE", "WATERPROOF", "STURDY" ] }, { @@ -293,7 +308,7 @@ "copy-from": "gauntlets_black_dragon_scale", "type": "ARMOR", "name": { "str": "pair of XL black dragonscale gauntlets", "str_pl": "pairs of XL black dragonscale gauntlets" }, - "description": "A pair of heavy-duty gauntlets made of black dragonscale that covers your hands, or whatever you use as hands.", + "description": "A pair of heavy-duty gauntlets made of incredibly durable black dragonscale that covers your hands, or whatever you use as hands.", "weight": "680 g", "volume": "2 L", "encumbrance": 30, @@ -304,65 +319,34 @@ "copy-from": "gloves_black_dragon_hide", "type": "ARMOR", "name": { "str": "pair of XL black dragonhide gloves", "str_pl": "pairs of XL black dragonhide gloves" }, - "description": "A pair of customized, Kevlar armored leather gloves, modified to be easy to wear while providing maximum protection under extreme conditions. Sized to fit even the strangest of anatomy.", + "description": "A pair of gloves made of very durable black dragonhide, modified to be easy to wear while providing maximum protection under extreme conditions. Sized to fit even the strangest of anatomy.", "weight": "430 g", "volume": "1500 ml", "encumbrance": 18, "flags": [ "OVERSIZE", "VARSIZE", "WATERPROOF", "STURDY" ] }, - { - "id": "boots_xlblack_dragon_scale", - "copy-from": "boots_black_dragon_scale", - "type": "ARMOR", - "name": { "str": "pair of XL black dragonscale boots", "str_pl": "pairs of XL black dragonscale boots" }, - "description": "Massive boots made of black dragonscale, modified to fit even the strangest of bodies. Very protective, and surprisingly light.", - "weight": "1545 g", - "volume": "6250 ml", - "encumbrance": 40, - "flags": [ "OVERSIZE", "VARSIZE", "WATERPROOF", "STURDY" ] - }, - { - "id": "boots_xlblack_dragon_hide", - "copy-from": "boots_black_dragon_hide", - "type": "ARMOR", - "name": { "str": "pair of XL black dragonhide boots", "str_pl": "pairs of XL black dragonhide boots" }, - "description": "Massive boots made of black dragonhide, modified to fit even the strangest of bodies. Very protective, and surprisingly light.", - "weight": "955 g", - "volume": "6250 ml", - "encumbrance": 28, - "flags": [ "OVERSIZE", "VARSIZE", "WATERPROOF", "STURDY" ] - }, { "id": "helmet_xlblack_dragon_scale", "copy-from": "helmet_black_dragon_scale", "type": "ARMOR", "name": { "str": "XL black dragonscale helmet" }, - "description": "A massive helmet made from black dragonscale, held together with black dragonhide. It comes equipped with a full face visor and is large enough to fit even the strangest of heads.", + "description": "A massive helmet made from incredibly durable black dragonscale, held together with black dragonhide. It comes equipped with a full face visor you can raise and is large enough to fit even the strangest of heads.", + "use_action": { "type": "transform", "target": "helmet_xlblack_dragon_scale_raised", "msg": "You raise your visor." }, "weight": "1256 g", "volume": "4500 ml", - "encumbrance": 42, - "flags": [ "OVERSIZE", "VARSIZE", "WATERPROOF", "STURDY" ] + "armor_portion_data": [ { "covers": [ "head" ], "coverage": 100, "encumbrance": 42 } ], + "flags": [ "OVERSIZE", "VARSIZE", "WATERPROOF", "STURDY", "SUN_GLASSES" ] }, { - "id": "helmet_xlblack_dragon_hide", - "copy-from": "helmet_black_dragon_hide", + "id": "helmet_xlblack_dragon_scale_raised", + "copy-from": "helmet_black_dragon_scale_raised", "type": "ARMOR", - "name": { "str": "XL black dragonhide helmet" }, - "description": "A massive helmet made from black dragonhide. It protects your head well, and doesn't cover your face, but is large enough to fit even the strangest of heads.", - "weight": "815 g", - "volume": "4500 ml", - "encumbrance": 42, - "flags": [ "OVERSIZE", "VARSIZE", "WATERPROOF", "STURDY" ] - }, - { - "id": "helmet_xlblack_dragon_scale", - "copy-from": "helmet_black_dragon_scale", - "type": "ARMOR", - "name": { "str": "XL black dragonscale helmet" }, - "description": "A massive helmet made from black dragonscale, held together with black dragonhide. It comes equipped with a full face visor and is large enough to fit even the strangest of heads.", + "name": { "str": "XL black dragonscale helmet (raised visor)", "str_pl": "XL black dragonscale helmets (raised visor)" }, + "description": "A massive helmet made from incredibly durable black dragonscale, held together with black dragonhide. It is large enough to fit even the strangest of heads. The visor is raised", + "use_action": { "type": "transform", "target": "helmet_xlblack_dragon_scale", "msg": "You put down your visor." }, + "armor_portion_data": [ { "covers": [ "head" ], "coverage": 100, "encumbrance": 42 } ], "weight": "1256 g", "volume": "4500 ml", - "encumbrance": 42, "flags": [ "OVERSIZE", "VARSIZE", "WATERPROOF", "STURDY" ] }, { @@ -370,10 +354,10 @@ "copy-from": "helmet_black_dragon_hide", "type": "ARMOR", "name": { "str": "XL black dragonhide helmet" }, - "description": "A massive helmet made from black dragonhide. It protects your head well, and doesn't cover your face, but is large enough to fit even the strangest of heads.", + "description": "A massive helmet made from very durable black dragonhide. It protects your head well, and doesn't cover your face, but is large enough to fit even the strangest of heads.", "weight": "815 g", "volume": "4500 ml", - "encumbrance": 42, + "encumbrance": 26, "flags": [ "OVERSIZE", "VARSIZE", "WATERPROOF", "STURDY" ] }, { @@ -381,7 +365,7 @@ "copy-from": "suit_black_dragon_scale", "type": "ARMOR", "name": { "str": "XL black dragonscale armor" }, - "description": "A massive full suit of black dragon scale mail. It comes with all the accoutrements that cover your torso, legs, and arms; sized to fit even the strangest of bodies.", + "description": "A massive full suit of incredibly durable black dragon scale mail. It comes with all the accoutrements that cover your torso, legs, and arms; sized to fit even the strangest of bodies.", "weight": "6250 g", "volume": "18 L", "encumbrance": 35, @@ -392,10 +376,70 @@ "copy-from": "suit_black_dragon_hide", "type": "ARMOR", "name": { "str": "XL black dragonhide armor" }, - "description": "A massive full suit of black dragonhide armor. It comes with all the accoutrements that cover your torso, legs, and arms; sized to fit even the strangest of bodies.", + "description": "A massive full suit of very durable black dragonhide armor. It comes with all the accoutrements that cover your torso, legs, and arms; sized to fit even the strangest of bodies.", "weight": "5500 g", "volume": "18 L", - "encumbrance": 28, + "encumbrance": 26, "flags": [ "OVERSIZE", "VARSIZE", "WATERPROOF", "RAINPROOF", "STURDY" ] + }, + { + "id": "backpack_black_dragon_hide", + "//": "After adding more dragons, maybe make it more generic", + "type": "ARMOR", + "name": { "str": "dragonhide backpack" }, + "description": "A custom-built backpack. Made of very durable dragon leather and carefully crafted to hold as much stuff as possible.", + "weight": "900 g", + "volume": "5250 ml", + "price": 240000, + "price_postapoc": 3250, + "material": [ "black_dragon_hide" ], + "symbol": "[", + "looks_like": "backpack", + "color": "black", + "covers": [ "torso" ], + "coverage": 40, + "encumbrance": 5, + "max_encumbrance": 30, + "pocket_data": [ + { + "pocket_type": "CONTAINER", + "max_contains_volume": "29 L", + "max_contains_weight": "45 kg", + "max_item_length": "48 cm", + "magazine_well": "5 L", + "moves": 300 + } + ], + "warmth": 8, + "material_thickness": 3, + "environmental_protection": 3, + "flags": [ "WATER_FRIENDLY", "STURDY", "BELTED", "WATERPROOF" ] + }, + { + "id": "backpack_xl_black_dragon_hide", + "copy-from": "backpack_black_dragon_hide", + "type": "ARMOR", + "name": { "str": "XL dragonhide backpack" }, + "weight": "1200 g", + "volume": "6250 ml", + "price": 280000, + "price_postapoc": 3450, + "symbol": "[", + "encumbrance": 8, + "max_encumbrance": 40, + "pocket_data": [ + { + "pocket_type": "CONTAINER", + "max_contains_volume": "38 L", + "max_contains_weight": "52 kg", + "max_item_length": "58 cm", + "magazine_well": "5 L", + "moves": 330 + } + ], + "warmth": 9, + "material_thickness": 4, + "environmental_protection": 3, + "extend": { "flags": [ "OVERSIZE" ] } } ] diff --git a/data/mods/Magiclysm/items/tools.json b/data/mods/Magiclysm/items/tools.json index 7bd18d0a18579..a2fa1a59c78d2 100644 --- a/data/mods/Magiclysm/items/tools.json +++ b/data/mods/Magiclysm/items/tools.json @@ -16,7 +16,7 @@ "color": "red", "pocket_data": [ { "open_container": true, "watertight": true, "max_contains_volume": "16 L", "max_contains_weight": "50 kg" } ], "//": "I went ahead and gave this a level of 2 for when magical mutagens become a thing as I figured dragonblood for instance should need different tools than making alpha mutagen.", - "qualities": [ [ "COOK", 3 ], [ "BOIL", 2 ], [ "CONTAIN", 1 ], [ "MAGIC_MUTAGEN", 2 ] ], + "qualities": [ [ "COOK", 3 ], [ "BOIL", 2 ], [ "CONTAIN", 1 ], [ "MAGIC_MUTAGEN", 2 ], [ "MAGIC_CAULDRON", 1 ] ], "use_action": [ "HEAT_FOOD" ] }, { @@ -34,7 +34,7 @@ "symbol": "U", "color": "yellow", "pocket_data": [ { "open_container": true, "watertight": true, "max_contains_volume": "16 L", "max_contains_weight": "50 kg" } ], - "qualities": [ [ "COOK", 3 ], [ "BOIL", 2 ], [ "CONTAIN", 1 ], [ "MAGIC_MUTAGEN", 1 ] ], + "qualities": [ [ "COOK", 3 ], [ "BOIL", 2 ], [ "CONTAIN", 1 ], [ "MAGIC_MUTAGEN", 1 ], [ "MAGIC_CAULDRON", 2 ] ], "use_action": [ "HEAT_FOOD" ] }, { diff --git a/data/mods/Magiclysm/materials.json b/data/mods/Magiclysm/materials.json index 9e3e6522fe219..00e4b1d76d3bc 100644 --- a/data/mods/Magiclysm/materials.json +++ b/data/mods/Magiclysm/materials.json @@ -24,22 +24,50 @@ "type": "material", "id": "black_dragon_hide", "name": "Black Dragon Hide", - "density": 20, - "specific_heat_liquid": 4.186, - "specific_heat_solid": 2.108, + "density": 9, "latent_heat": 333, - "bash_resist": 5, - "cut_resist": 8, + "bash_resist": 3, + "cut_resist": 7, "bullet_resist": 6, "acid_resist": 40, "fire_resist": 1, - "elec_resist": 1, - "chip_resist": 30, + "elec_resist": 2, + "chip_resist": 20, + "reinforces": true, + "soft": true, + "repaired_with": "black_dragon_tanned_hide", + "dmg_adj": [ "scratched", "cut", "ripped", "shredded" ], + "bash_dmg_verb": "ripped", + "cut_dmg_verb": "scratched", + "burn_data": [ + { "fuel": 0, "smoke": 0, "burn": 0 }, + { "fuel": 1, "smoke": 1, "burn": 1, "volume_per_turn": "100 ml" }, + { "fuel": 2, "smoke": 4, "burn": 2 } + ] + }, + { + "type": "material", + "id": "black_dragon_scales", + "name": "Black Dragon Scale", + "density": 15, + "latent_heat": 533, + "bash_resist": 8, + "cut_resist": 9, + "bullet_resist": 8, + "acid_resist": 40, + "fire_resist": 4, + "elec_resist": 3, + "chip_resist": 35, "reinforces": true, "repaired_with": "dragon_black_scale", - "dmg_adj": [ "scratched", "cut", "cracked", "shattered" ], + "dmg_adj": [ "scratched", "marked", "cracked", "shattered" ], "bash_dmg_verb": "cracked", - "cut_dmg_verb": "chipped" + "cut_dmg_verb": "chipped", + "burn_data": [ + { "fuel": 0, "smoke": 0, "burn": 0 }, + { "fuel": 0, "smoke": 0, "burn": 0 }, + { "fuel": 1, "smoke": 1, "burn": 1, "volume_per_turn": "100 ml" } + ] }, { "type": "material", diff --git a/data/mods/Magiclysm/proficiencies.json b/data/mods/Magiclysm/proficiencies.json index 6d13fc27d1d33..f57b91947089e 100644 --- a/data/mods/Magiclysm/proficiencies.json +++ b/data/mods/Magiclysm/proficiencies.json @@ -20,6 +20,28 @@ "default_fail_multiplier": 2, "required_proficiencies": [ "prof_alchemy" ] }, + { + "type": "proficiency", + "id": "prof_leatherworking_dragon", + "name": { "str": "Dragon leather working" }, + "description": "Working with dragon leather requires a specific set of skills and tools… a set you are familiar with.", + "can_learn": true, + "default_time_multiplier": 1.5, + "default_fail_multiplier": 2, + "time_to_learn": "6 h", + "required_proficiencies": [ "prof_leatherworking" ] + }, + { + "type": "proficiency", + "id": "prof_scaleworking_dragon", + "name": { "str": "Dragon scale working" }, + "description": "Working with dragon scales requires a specific set of skills and tools… a set you are familiar with.", + "can_learn": true, + "default_time_multiplier": 2, + "default_fail_multiplier": 3, + "time_to_learn": "12 h", + "required_proficiencies": [ "prof_leatherworking_dragon" ] + }, { "type": "proficiency", "id": "prof_golemancy_basic", diff --git a/data/mods/Magiclysm/recipes/alchemy.json b/data/mods/Magiclysm/recipes/alchemy.json index 3825e8ab6ab3c..5d695526e2b97 100644 --- a/data/mods/Magiclysm/recipes/alchemy.json +++ b/data/mods/Magiclysm/recipes/alchemy.json @@ -21,6 +21,32 @@ "category": "CC_ENCHANTED", "subcategory": "CSC_ENCHANTED_OTHER" }, + { + "type": "recipe", + "activity_level": "fake", + "result": "dragon_essence", + "id_suffix": "with_blood", + "charges": 2, + "batch_time_factors": [ 40, 3 ], + "qualities": [ + { "id": "CONCENTRATE", "level": 1 }, + { "id": "FINE_DISTILL", "level": 1 }, + { "id": "SEPARATE", "level": 1 }, + { "id": "CONTAIN", "level": 1 }, + { "id": "MANA_FOCUS", "level": 1 }, + { "id": "MAGIC_CAULDRON", "level": 1 } + ], + "tools": [ [ [ "surface_heat", 20, "LIST" ] ] ], + "components": [ [ [ "dragon_scale", 6, "LIST" ], [ "meat_dragon", 60 ] ], [ [ "dragon_blood", 500 ] ] ], + "proficiencies": [ { "proficiency": "prof_alchemy", "required": true } ], + "time": "2 h", + "skill_used": "chemistry", + "difficulty": 5, + "skills_required": [ "spellcraft", 6 ], + "book_learn": [ [ "black_dragons", 5 ] ], + "category": "CC_ENCHANTED", + "subcategory": "CSC_ENCHANTED_OTHER" + }, { "type": "recipe", "activity_level": "fake", diff --git a/data/mods/Magiclysm/recipes/dragon_black.json b/data/mods/Magiclysm/recipes/dragon_black.json index a39e48973c49d..e38b36bcaaf30 100644 --- a/data/mods/Magiclysm/recipes/dragon_black.json +++ b/data/mods/Magiclysm/recipes/dragon_black.json @@ -19,7 +19,12 @@ { "id": "MANA_INFUSE", "level": 1 } ], "tools": [ [ [ "surface_heat", 20, "LIST" ] ] ], - "proficiencies": [ { "proficiency": "prof_leatherworking_basic" } ], + "proficiencies": [ + { "proficiency": "prof_leatherworking_basic" }, + { "proficiency": "prof_leatherworking" }, + { "proficiency": "prof_leatherworking_dragon" }, + { "proficiency": "prof_alchemy" } + ], "book_learn": [ [ "black_dragons", 2 ] ], "components": [ [ [ "dragon_essence", 1 ] ], [ [ "black_dragon_hide_raw", 1 ] ] ] }, @@ -54,7 +59,7 @@ { "result": "suit_black_dragon_hide", "type": "recipe", - "activity_level": "fake", + "activity_level": "LIGHT_EXERCISE", "category": "CC_ENCHANTED", "subcategory": "CSC_ENCHANTED_ARMOR", "skill_used": "tailor", @@ -62,51 +67,61 @@ "skills_required": [ "spellcraft", 3 ], "time": "70 h", "book_learn": [ [ "black_dragons", 5 ] ], - "qualities": [ { "id": "MANA_INFUSE", "level": 1 }, { "id": "CHISEL", "level": 3 } ], + "qualities": [ { "id": "MANA_INFUSE", "level": 1 }, { "id": "CHISEL", "level": 1 } ], "using": [ [ "sewing_standard", 250 ] ], - "proficiencies": [ { "proficiency": "prof_leatherworking_basic" }, { "proficiency": "prof_leatherworking" } ], - "components": [ [ [ "black_dragon_tanned_hide", 40 ] ], [ [ "dragon_black_scale", 150 ] ], [ [ "dragon_essence", 15 ] ] ] + "proficiencies": [ + { "proficiency": "prof_leatherworking_basic" }, + { "proficiency": "prof_leatherworking" }, + { "proficiency": "prof_leatherworking_dragon" } + ], + "components": [ [ [ "black_dragon_tanned_hide", 22 ] ], [ [ "dragon_essence", 11 ] ] ] }, { "result": "suit_black_dragon_scale", "type": "recipe", - "activity_level": "fake", + "activity_level": "LIGHT_EXERCISE", "category": "CC_ENCHANTED", "subcategory": "CSC_ENCHANTED_ARMOR", "skill_used": "fabrication", "difficulty": 7, "skills_required": [ "spellcraft", 5 ], - "time": "340 h", + "time": "290 h", "book_learn": [ [ "black_dragons", 6 ] ], "qualities": [ { "id": "MANA_INFUSE", "level": 2 }, { "id": "CHISEL", "level": 3 } ], - "proficiencies": [ { "proficiency": "prof_leatherworking_basic" }, { "proficiency": "prof_leatherworking" } ], + "proficiencies": [ + { "proficiency": "prof_leatherworking_basic" }, + { "proficiency": "prof_leatherworking" }, + { "proficiency": "prof_leatherworking_dragon" }, + { "proficiency": "prof_scaleworking_dragon" } + ], "using": [ [ "sewing_standard", 250 ], [ "welding_standard", 50 ] ], - "components": [ [ [ "black_dragon_tanned_hide", 40 ] ], [ [ "dragon_black_scale", 1500 ] ], [ [ "dragon_essence", 15 ] ] ] + "components": [ [ [ "black_dragon_tanned_hide", 22 ] ], [ [ "dragon_black_scale", 1100 ] ], [ [ "dragon_essence", 11 ] ] ] }, { "result": "boots_black_dragon_hide", "type": "recipe", - "activity_level": "fake", + "activity_level": "LIGHT_EXERCISE", "category": "CC_ENCHANTED", "subcategory": "CSC_ENCHANTED_ARMOR", "skill_used": "tailor", "difficulty": 5, "skills_required": [ "spellcraft", 3 ], - "time": "30 h", + "time": "25 h", "book_learn": [ [ "black_dragons", 5 ] ], - "qualities": [ { "id": "MANA_INFUSE", "level": 1 }, { "id": "CHISEL", "level": 3 } ], + "qualities": [ { "id": "MANA_INFUSE", "level": 1 }, { "id": "CHISEL", "level": 1 } ], "using": [ [ "sewing_standard", 100 ] ], "proficiencies": [ { "proficiency": "prof_leatherworking_basic" }, { "proficiency": "prof_cobbling" }, - { "proficiency": "prof_leatherworking" } + { "proficiency": "prof_leatherworking" }, + { "proficiency": "prof_leatherworking_dragon" } ], - "components": [ [ [ "black_dragon_tanned_hide", 4 ] ], [ [ "dragon_black_scale", 15 ] ], [ [ "dragon_essence", 2 ] ] ] + "components": [ [ [ "black_dragon_tanned_hide", 4 ] ], [ [ "dragon_essence", 2 ] ] ] }, { "result": "boots_black_dragon_scale", "type": "recipe", - "activity_level": "fake", + "activity_level": "LIGHT_EXERCISE", "category": "CC_ENCHANTED", "subcategory": "CSC_ENCHANTED_ARMOR", "skill_used": "fabrication", @@ -119,30 +134,36 @@ "proficiencies": [ { "proficiency": "prof_leatherworking_basic" }, { "proficiency": "prof_cobbling" }, - { "proficiency": "prof_leatherworking" } + { "proficiency": "prof_leatherworking" }, + { "proficiency": "prof_leatherworking_dragon" }, + { "proficiency": "prof_scaleworking_dragon" } ], "components": [ [ [ "black_dragon_tanned_hide", 6 ] ], [ [ "dragon_black_scale", 75 ] ], [ [ "dragon_essence", 4 ] ] ] }, { "result": "helmet_black_dragon_hide", "type": "recipe", - "activity_level": "fake", + "activity_level": "LIGHT_EXERCISE", "category": "CC_ENCHANTED", "subcategory": "CSC_ENCHANTED_ARMOR", "skill_used": "tailor", "difficulty": 5, "skills_required": [ "spellcraft", 3 ], - "time": "30 h", + "time": "25 h", "book_learn": [ [ "black_dragons", 5 ] ], - "qualities": [ { "id": "MANA_INFUSE", "level": 1 }, { "id": "CHISEL", "level": 3 } ], + "qualities": [ { "id": "MANA_INFUSE", "level": 1 }, { "id": "CHISEL", "level": 1 } ], "using": [ [ "sewing_standard", 100 ] ], - "proficiencies": [ { "proficiency": "prof_leatherworking_basic" }, { "proficiency": "prof_leatherworking" } ], - "components": [ [ [ "black_dragon_tanned_hide", 3 ] ], [ [ "dragon_black_scale", 8 ] ], [ [ "dragon_essence", 2 ] ] ] + "proficiencies": [ + { "proficiency": "prof_leatherworking_basic" }, + { "proficiency": "prof_leatherworking" }, + { "proficiency": "prof_leatherworking_dragon" } + ], + "components": [ [ [ "black_dragon_tanned_hide", 3 ] ], [ [ "dragon_essence", 2 ] ] ] }, { "result": "helmet_black_dragon_scale", "type": "recipe", - "activity_level": "fake", + "activity_level": "LIGHT_EXERCISE", "category": "CC_ENCHANTED", "subcategory": "CSC_ENCHANTED_ARMOR", "skill_used": "fabrication", @@ -152,13 +173,18 @@ "book_learn": [ [ "black_dragons", 6 ] ], "qualities": [ { "id": "MANA_INFUSE", "level": 2 }, { "id": "CHISEL", "level": 3 } ], "using": [ [ "sewing_standard", 100 ], [ "welding_standard", 10 ] ], - "proficiencies": [ { "proficiency": "prof_leatherworking_basic" }, { "proficiency": "prof_leatherworking" } ], + "proficiencies": [ + { "proficiency": "prof_leatherworking_basic" }, + { "proficiency": "prof_leatherworking" }, + { "proficiency": "prof_leatherworking_dragon" }, + { "proficiency": "prof_scaleworking_dragon" } + ], "components": [ [ [ "black_dragon_tanned_hide", 1 ] ], [ [ "dragon_black_scale", 90 ] ], [ [ "dragon_essence", 4 ] ] ] }, { "result": "gloves_black_dragon_hide", "type": "recipe", - "activity_level": "fake", + "activity_level": "LIGHT_EXERCISE", "category": "CC_ENCHANTED", "subcategory": "CSC_ENCHANTED_ARMOR", "skill_used": "tailor", @@ -166,55 +192,62 @@ "skills_required": [ "spellcraft", 3 ], "time": "30 h", "book_learn": [ [ "black_dragons", 5 ] ], - "qualities": [ { "id": "MANA_INFUSE", "level": 1 }, { "id": "CHISEL", "level": 3 } ], + "qualities": [ { "id": "MANA_INFUSE", "level": 1 }, { "id": "CHISEL", "level": 1 } ], "using": [ [ "sewing_standard", 100 ] ], "proficiencies": [ { "proficiency": "prof_leatherworking_basic" }, { "proficiency": "prof_articulation", "required": false, "time_multiplier": 2 }, - { "proficiency": "prof_leatherworking" } + { "proficiency": "prof_leatherworking" }, + { "proficiency": "prof_leatherworking_dragon" } ], - "components": [ [ [ "black_dragon_tanned_hide", 3 ] ], [ [ "dragon_black_scale", 10 ] ], [ [ "dragon_essence", 3 ] ] ] + "components": [ [ [ "black_dragon_tanned_hide", 3 ] ], [ [ "dragon_essence", 3 ] ] ] }, { "result": "gauntlets_black_dragon_scale", "type": "recipe", - "activity_level": "fake", + "activity_level": "LIGHT_EXERCISE", "category": "CC_ENCHANTED", "subcategory": "CSC_ENCHANTED_ARMOR", "skill_used": "fabrication", "difficulty": 7, "skills_required": [ "spellcraft", 5 ], - "time": "30 h", + "time": "40 h", "book_learn": [ [ "black_dragons", 6 ] ], "qualities": [ { "id": "MANA_INFUSE", "level": 2 }, { "id": "CHISEL", "level": 3 } ], "using": [ [ "sewing_standard", 100 ], [ "welding_standard", 10 ] ], "proficiencies": [ { "proficiency": "prof_leatherworking_basic" }, { "proficiency": "prof_articulation", "required": false, "time_multiplier": 2 }, - { "proficiency": "prof_leatherworking" } + { "proficiency": "prof_leatherworking" }, + { "proficiency": "prof_leatherworking_dragon" }, + { "proficiency": "prof_scaleworking_dragon" } ], "components": [ [ [ "black_dragon_tanned_hide", 4 ] ], [ [ "dragon_black_scale", 50 ] ], [ [ "dragon_essence", 5 ] ] ] }, { "result": "suit_xlblack_dragon_hide", "type": "recipe", - "activity_level": "fake", + "activity_level": "LIGHT_EXERCISE", "category": "CC_ENCHANTED", "subcategory": "CSC_ENCHANTED_ARMOR", "skill_used": "tailor", "difficulty": 6, "skills_required": [ "spellcraft", 4 ], - "time": "70 h", + "time": "60 h", "book_learn": [ [ "black_dragons", 5 ] ], - "qualities": [ { "id": "MANA_INFUSE", "level": 1 }, { "id": "CHISEL", "level": 3 } ], + "qualities": [ { "id": "MANA_INFUSE", "level": 1 }, { "id": "CHISEL", "level": 1 } ], "using": [ [ "sewing_standard", 350 ] ], - "proficiencies": [ { "proficiency": "prof_leatherworking_basic" }, { "proficiency": "prof_leatherworking" } ], - "components": [ [ [ "black_dragon_tanned_hide", 60 ] ], [ [ "dragon_black_scale", 250 ] ], [ [ "dragon_essence", 20 ] ] ] + "proficiencies": [ + { "proficiency": "prof_leatherworking_basic" }, + { "proficiency": "prof_leatherworking" }, + { "proficiency": "prof_leatherworking_dragon" } + ], + "components": [ [ [ "black_dragon_tanned_hide", 35 ] ], [ [ "dragon_essence", 18 ] ] ] }, { "result": "suit_xlblack_dragon_scale", "type": "recipe", - "activity_level": "fake", + "activity_level": "LIGHT_EXERCISE", "category": "CC_ENCHANTED", "subcategory": "CSC_ENCHANTED_ARMOR", "skill_used": "fabrication", @@ -224,118 +257,138 @@ "book_learn": [ [ "black_dragons", 6 ] ], "qualities": [ { "id": "MANA_INFUSE", "level": 2 }, { "id": "CHISEL", "level": 3 } ], "using": [ [ "sewing_standard", 350 ], [ "welding_standard", 100 ] ], - "proficiencies": [ { "proficiency": "prof_leatherworking_basic" }, { "proficiency": "prof_leatherworking" } ], - "components": [ [ [ "black_dragon_tanned_hide", 60 ] ], [ [ "dragon_black_scale", 2250 ] ], [ [ "dragon_essence", 25 ] ] ] + "proficiencies": [ + { "proficiency": "prof_leatherworking_basic" }, + { "proficiency": "prof_leatherworking" }, + { "proficiency": "prof_leatherworking_dragon" }, + { "proficiency": "prof_scaleworking_dragon" } + ], + "components": [ [ [ "black_dragon_tanned_hide", 35 ] ], [ [ "dragon_black_scale", 1800 ] ], [ [ "dragon_essence", 20 ] ] ] }, { "result": "boots_xlblack_dragon_hide", "type": "recipe", - "activity_level": "fake", + "activity_level": "LIGHT_EXERCISE", "category": "CC_ENCHANTED", "subcategory": "CSC_ENCHANTED_ARMOR", "skill_used": "tailor", "difficulty": 6, "skills_required": [ "spellcraft", 4 ], - "time": "30 h", + "time": "32 h", "book_learn": [ [ "black_dragons", 5 ] ], - "qualities": [ { "id": "MANA_INFUSE", "level": 1 }, { "id": "CHISEL", "level": 3 } ], + "qualities": [ { "id": "MANA_INFUSE", "level": 1 }, { "id": "CHISEL", "level": 1 } ], "using": [ [ "sewing_standard", 150 ] ], "proficiencies": [ { "proficiency": "prof_leatherworking_basic" }, { "proficiency": "prof_cobbling" }, - { "proficiency": "prof_leatherworking" } + { "proficiency": "prof_leatherworking" }, + { "proficiency": "prof_leatherworking_dragon" } ], - "components": [ [ [ "black_dragon_tanned_hide", 6 ] ], [ [ "dragon_black_scale", 20 ] ], [ [ "dragon_essence", 3 ] ] ] + "components": [ [ [ "black_dragon_tanned_hide", 6 ] ], [ [ "dragon_essence", 3 ] ] ] }, { "result": "boots_xlblack_dragon_scale", "type": "recipe", - "activity_level": "fake", + "activity_level": "LIGHT_EXERCISE", "category": "CC_ENCHANTED", "subcategory": "CSC_ENCHANTED_ARMOR", "skill_used": "fabrication", "difficulty": 8, "skills_required": [ "spellcraft", 6 ], - "time": "30 h", + "time": "40 h", "book_learn": [ [ "black_dragons", 6 ] ], "qualities": [ { "id": "MANA_INFUSE", "level": 2 }, { "id": "CHISEL", "level": 3 } ], "using": [ [ "sewing_standard", 150 ], [ "welding_standard", 20 ] ], "proficiencies": [ { "proficiency": "prof_leatherworking_basic" }, { "proficiency": "prof_cobbling" }, - { "proficiency": "prof_leatherworking" } + { "proficiency": "prof_leatherworking" }, + { "proficiency": "prof_leatherworking_dragon" }, + { "proficiency": "prof_scaleworking_dragon" } ], "components": [ [ [ "black_dragon_tanned_hide", 8 ] ], [ [ "dragon_black_scale", 125 ] ], [ [ "dragon_essence", 6 ] ] ] }, { "result": "helmet_xlblack_dragon_hide", "type": "recipe", - "activity_level": "fake", + "activity_level": "LIGHT_EXERCISE", "category": "CC_ENCHANTED", "subcategory": "CSC_ENCHANTED_ARMOR", "skill_used": "tailor", "difficulty": 6, "skills_required": [ "spellcraft", 4 ], - "time": "30 h", + "time": "32 h", "book_learn": [ [ "black_dragons", 5 ] ], - "qualities": [ { "id": "MANA_INFUSE", "level": 1 }, { "id": "CHISEL", "level": 3 } ], + "qualities": [ { "id": "MANA_INFUSE", "level": 1 }, { "id": "CHISEL", "level": 1 } ], "using": [ [ "sewing_standard", 150 ] ], - "proficiencies": [ { "proficiency": "prof_leatherworking_basic" }, { "proficiency": "prof_leatherworking" } ], - "components": [ [ [ "black_dragon_tanned_hide", 4 ] ], [ [ "dragon_black_scale", 12 ] ], [ [ "dragon_essence", 3 ] ] ] + "proficiencies": [ + { "proficiency": "prof_leatherworking_basic" }, + { "proficiency": "prof_leatherworking" }, + { "proficiency": "prof_leatherworking_dragon" } + ], + "components": [ [ [ "black_dragon_tanned_hide", 4 ] ], [ [ "dragon_essence", 3 ] ] ] }, { "result": "helmet_xlblack_dragon_scale", "type": "recipe", - "activity_level": "fake", + "activity_level": "LIGHT_EXERCISE", "category": "CC_ENCHANTED", "subcategory": "CSC_ENCHANTED_ARMOR", "skill_used": "fabrication", "difficulty": 8, "skills_required": [ "spellcraft", 6 ], - "time": "30 h", + "time": "40 h", "book_learn": [ [ "black_dragons", 6 ] ], "qualities": [ { "id": "MANA_INFUSE", "level": 2 }, { "id": "CHISEL", "level": 3 } ], "using": [ [ "sewing_standard", 150 ], [ "welding_standard", 20 ] ], - "proficiencies": [ { "proficiency": "prof_leatherworking_basic" }, { "proficiency": "prof_leatherworking" } ], + "proficiencies": [ + { "proficiency": "prof_leatherworking_basic" }, + { "proficiency": "prof_leatherworking" }, + { "proficiency": "prof_leatherworking_dragon" }, + { "proficiency": "prof_scaleworking_dragon" } + ], "components": [ [ [ "black_dragon_tanned_hide", 2 ] ], [ [ "dragon_black_scale", 140 ] ], [ [ "dragon_essence", 6 ] ] ] }, { "result": "gloves_xlblack_dragon_hide", "type": "recipe", - "activity_level": "fake", + "activity_level": "LIGHT_EXERCISE", "category": "CC_ENCHANTED", "subcategory": "CSC_ENCHANTED_ARMOR", "skill_used": "tailor", "difficulty": 6, "skills_required": [ "spellcraft", 4 ], - "time": "30 h", + "time": "40 h", "book_learn": [ [ "black_dragons", 5 ] ], - "qualities": [ { "id": "MANA_INFUSE", "level": 1 }, { "id": "CHISEL", "level": 3 } ], + "qualities": [ { "id": "MANA_INFUSE", "level": 1 }, { "id": "CHISEL", "level": 1 } ], "using": [ [ "sewing_standard", 150 ] ], "proficiencies": [ { "proficiency": "prof_leatherworking_basic" }, { "proficiency": "prof_articulation", "required": false, "time_multiplier": 2 }, - { "proficiency": "prof_leatherworking" } + { "proficiency": "prof_leatherworking" }, + { "proficiency": "prof_leatherworking_dragon" } ], - "components": [ [ [ "black_dragon_tanned_hide", 4 ] ], [ [ "dragon_black_scale", 15 ] ], [ [ "dragon_essence", 4 ] ] ] + "components": [ [ [ "black_dragon_tanned_hide", 4 ] ], [ [ "dragon_essence", 4 ] ] ] }, { "result": "gauntlets_xlblack_dragon_scale", "type": "recipe", - "activity_level": "fake", + "activity_level": "LIGHT_EXERCISE", "category": "CC_ENCHANTED", "subcategory": "CSC_ENCHANTED_ARMOR", "skill_used": "fabrication", "difficulty": 8, "skills_required": [ "spellcraft", 6 ], - "time": "30 h", + "time": "50 h", "book_learn": [ [ "black_dragons", 6 ] ], "qualities": [ { "id": "MANA_INFUSE", "level": 2 }, { "id": "CHISEL", "level": 3 } ], "using": [ [ "sewing_standard", 150 ], [ "welding_standard", 20 ] ], "proficiencies": [ { "proficiency": "prof_leatherworking_basic" }, { "proficiency": "prof_articulation", "required": false, "time_multiplier": 2 }, - { "proficiency": "prof_leatherworking" } + { "proficiency": "prof_leatherworking" }, + { "proficiency": "prof_leatherworking_dragon" }, + { "proficiency": "prof_scaleworking_dragon" } ], "components": [ [ [ "black_dragon_tanned_hide", 6 ] ], [ [ "dragon_black_scale", 75 ] ], [ [ "dragon_essence", 7 ] ] ] }, @@ -368,5 +421,49 @@ "qualities": [ { "id": "CHEM", "level": 1 }, { "id": "CONCENTRATE", "level": 1 }, { "id": "MANA_INFUSE", "level": 1 } ], "components": [ [ [ "dragon_essence", 5 ] ], [ [ "mutagen_black_dragon", 1 ] ], [ [ "manatouched_serum", 1 ] ] ], "flags": [ "SECRET" ] + }, + { + "result": "backpack_black_dragon_hide", + "type": "recipe", + "activity_level": "LIGHT_EXERCISE", + "category": "CC_ENCHANTED", + "subcategory": "CSC_ENCHANTED_ARMOR", + "skill_used": "tailor", + "difficulty": 5, + "skills_required": [ [ "spellcraft", 2 ], [ "fabrication", 3 ] ], + "time": "10 h", + "book_learn": [ [ "black_dragons", 4 ] ], + "qualities": [ { "id": "MANA_INFUSE", "level": 1 }, { "id": "CHISEL", "level": 1 } ], + "using": [ [ "sewing_standard", 120 ], [ "fastener_large", 2 ] ], + "proficiencies": [ + { "proficiency": "prof_leatherworking_basic" }, + { "proficiency": "prof_leatherworking" }, + { "proficiency": "prof_leatherworking_dragon" }, + { "proficiency": "prof_closures" }, + { "proficiency": "prof_closures_waterproofing" } + ], + "components": [ [ [ "black_dragon_tanned_hide", 10 ] ], [ [ "dragon_essence", 3 ] ], [ [ "plastic_sheet", 1 ] ] ] + }, + { + "result": "backpack_xl_black_dragon_hide", + "type": "recipe", + "activity_level": "LIGHT_EXERCISE", + "category": "CC_ENCHANTED", + "subcategory": "CSC_ENCHANTED_ARMOR", + "skill_used": "tailor", + "difficulty": 5, + "skills_required": [ [ "spellcraft", 2 ], [ "fabrication", 3 ] ], + "time": "13 h", + "book_learn": [ [ "black_dragons", 4 ] ], + "qualities": [ { "id": "MANA_INFUSE", "level": 1 }, { "id": "CHISEL", "level": 1 } ], + "using": [ [ "sewing_standard", 130 ], [ "fastener_large", 2 ] ], + "proficiencies": [ + { "proficiency": "prof_leatherworking_basic" }, + { "proficiency": "prof_leatherworking" }, + { "proficiency": "prof_leatherworking_dragon" }, + { "proficiency": "prof_closures" }, + { "proficiency": "prof_closures_waterproofing" } + ], + "components": [ [ [ "black_dragon_tanned_hide", 14 ] ], [ [ "dragon_essence", 4 ] ], [ [ "plastic_sheet", 1 ] ] ] } ] diff --git a/data/mods/Magiclysm/tool_qualities.json b/data/mods/Magiclysm/tool_qualities.json index 1c48775418cd3..c20c78040f9a5 100644 --- a/data/mods/Magiclysm/tool_qualities.json +++ b/data/mods/Magiclysm/tool_qualities.json @@ -3,5 +3,10 @@ "type": "tool_quality", "id": "MAGIC_MUTAGEN", "name": "magic mutagen mixer" + }, + { + "type": "tool_quality", + "id": "MAGIC_CAULDRON", + "name": "alchemical cauldron" } ] diff --git a/doc/JSON_INFO.md b/doc/JSON_INFO.md index c47be719095e3..6448af935a0f2 100644 --- a/doc/JSON_INFO.md +++ b/doc/JSON_INFO.md @@ -828,8 +828,8 @@ When you sort your inventory by category, these are the categories that are disp | `dmg_adj` | Adjectives used to describe damage states of a material. | `density` | Affects vehicle collision damage, with denser parts having the advantage over less-dense parts. | `vitamins` | Vitamins in a material. Usually overridden by item specific values. An integer percentage of ideal daily value. -| `specific_heat_liquid` | Specific heat of a material when not frozen (J/(g K)). Default 4.186. -| `specific_heat_solid` | Specific heat of a material when frozen (J/(g K)). Default 2.108. +| `specific_heat_liquid` | Specific heat of a material when not frozen (J/(g K)). Default 4.186 - water. +| `specific_heat_solid` | Specific heat of a material when frozen (J/(g K)). Default 2.108 - water. | `latent_heat` | Latent heat of fusion for a material (J/g). Default 334. | `freezing_point` | Freezing point of this material (C). Default 0 C ( 32 F ). | `edible` | Optional boolean. Default is false. From e6aab95e56bf9ae11dafe9b182a4534a447b1a4b Mon Sep 17 00:00:00 2001 From: Light-Wave <66904273+Light-Wave@users.noreply.github.com> Date: Thu, 25 Mar 2021 22:38:11 +0100 Subject: [PATCH 109/453] [Magiclysm] New spell: Jar of Force (#47952) * Adds Jar of Force spell for magus Adds Jar of Force, a magus spell that summons a jar of force that acts as a 3l jar. It can store liquids and be used to boil things in. * Update data/mods/Magiclysm/Spells/magus.json Co-authored-by: actual-nh <74678550+actual-nh@users.noreply.github.com> Co-authored-by: actual-nh <74678550+actual-nh@users.noreply.github.com> --- data/mods/Magiclysm/Spells/magus.json | 22 +++++++++++++ .../mods/Magiclysm/itemgroups/spellbooks.json | 1 + data/mods/Magiclysm/items/ethereal_items.json | 32 +++++++++++++++++++ data/mods/Magiclysm/items/spell_scrolls.json | 8 +++++ data/mods/Magiclysm/items/spellbooks.json | 7 ++-- 5 files changed, 68 insertions(+), 2 deletions(-) diff --git a/data/mods/Magiclysm/Spells/magus.json b/data/mods/Magiclysm/Spells/magus.json index 627c45e8df2c5..fb33365d86a29 100644 --- a/data/mods/Magiclysm/Spells/magus.json +++ b/data/mods/Magiclysm/Spells/magus.json @@ -339,6 +339,28 @@ "effect": "attack", "effect_str": "foxs_cunning" }, + { + "id": "magus_force_jar", + "type": "SPELL", + "name": { "str": "Jar of Force" }, + "description": "Summon a jar of force in which you can store liquids.", + "effect": "spawn_item", + "effect_str": "jar_3l_force", + "shape": "blast", + "valid_targets": [ "self" ], + "flags": [ "SOMATIC", "CONCENTRATE", "VERBAL" ], + "max_level": 15, + "min_damage": 1, + "max_damage": 1, + "min_duration": 8640000, + "max_duration": 129600000, + "duration_increment": 8640000, + "spell_class": "MAGUS", + "base_casting_time": 400, + "base_energy_cost": 350, + "energy_source": "MANA", + "difficulty": 3 + }, { "id": "magus_summon_impact_sling", "type": "SPELL", diff --git a/data/mods/Magiclysm/itemgroups/spellbooks.json b/data/mods/Magiclysm/itemgroups/spellbooks.json index ee790246a596f..5fadcf918fdfd 100644 --- a/data/mods/Magiclysm/itemgroups/spellbooks.json +++ b/data/mods/Magiclysm/itemgroups/spellbooks.json @@ -80,6 +80,7 @@ [ "spell_scroll_impactsling", 20 ], [ "spell_scroll_boneclub", 20 ], [ "spell_scroll_flamesword", 35 ], + [ "spell_scroll_force_jar", 30 ], [ "spell_scroll_flamebreath", 30 ] ] }, diff --git a/data/mods/Magiclysm/items/ethereal_items.json b/data/mods/Magiclysm/items/ethereal_items.json index 4f96dda1d4d77..32df41e0a69c7 100644 --- a/data/mods/Magiclysm/items/ethereal_items.json +++ b/data/mods/Magiclysm/items/ethereal_items.json @@ -776,6 +776,38 @@ "passive_effects": [ { "has": "WIELD", "condition": "ALWAYS", "values": [ { "value": "ITEM_DAMAGE_COLD", "add": 6 } ] } ] } }, + { + "id": "jar_3l_force", + "type": "GENERIC", + "category": "container", + "name": { "str": "jar of force", "str_pl": "jars of force" }, + "looks_like": "jar_glass_sealed", + "description": "A three-liter container made out of transparent force. Can be used to store liquids.", + "weight": "1 g", + "volume": "3050 ml", + "longest_side": "298 mm", + "price": 0, + "price_postapoc": 0, + "to_hit": -1, + "bashing": 1, + "material": [ ], + "symbol": ")", + "color": "light_cyan", + "pocket_data": [ + { + "pocket_type": "CONTAINER", + "rigid": true, + "watertight": true, + "max_contains_volume": "3 L", + "max_contains_weight": "6 kg" + } + ], + "flags": [ "UNBREAKABLE_MELEE", "NONCONDUCTIVE", "NO_REPAIR", "NO_SALVAGE", "MAGIC_FOCUS", "TRADER_AVOID" ], + "qualities": [ [ "CONTAIN", 1 ], [ "BOIL", 1 ] ], + "relic_data": { + "passive_effects": [ { "has": "WIELD", "condition": "ALWAYS", "values": [ { "value": "ITEM_DAMAGE_PURE", "add": 3 } ] } ] + } + }, { "id": "longsword_holy", "type": "GENERIC", diff --git a/data/mods/Magiclysm/items/spell_scrolls.json b/data/mods/Magiclysm/items/spell_scrolls.json index 196bd38f10a72..e4b7a4e43075a 100644 --- a/data/mods/Magiclysm/items/spell_scrolls.json +++ b/data/mods/Magiclysm/items/spell_scrolls.json @@ -1027,6 +1027,14 @@ "description": "Causes an intense heat at the location, greatly damaging the target.", "use_action": { "type": "learn_spell", "spells": [ "nova_flare" ] } }, + { + "type": "BOOK", + "copy-from": "spell_scroll", + "id": "spell_scroll_force_jar", + "name": { "str": "Scroll of Jar of Force", "str_pl": "Scrolls of Jar of Force" }, + "description": "Summon a jar of force you can use to store liquids in.", + "use_action": { "type": "learn_spell", "spells": [ "magus_force_jar" ] } + }, { "type": "BOOK", "copy-from": "spell_scroll", diff --git a/data/mods/Magiclysm/items/spellbooks.json b/data/mods/Magiclysm/items/spellbooks.json index 3c371e6ef75c8..09b134fcbafae 100644 --- a/data/mods/Magiclysm/items/spellbooks.json +++ b/data/mods/Magiclysm/items/spellbooks.json @@ -59,7 +59,7 @@ "id": "wizard_utility", "type": "BOOK", "name": { "str": "Wizarding Guide to Backpacking", "str_pl": "copies of Wizarding Guide to Backpacking" }, - "//": "1 Magus, 1 Biomancer, 1, Kelvinist, 1 classless spell", + "//": "2 Magus, 1 Biomancer, 1, Kelvinist, 1 classless spell", "description": "This appears to be the spell version of a guide for what things to take with you when backpacking. It's a little bulky, but will certainly prove useful.", "weight": "1 kg", "volume": "1250 ml", @@ -67,7 +67,10 @@ "material": [ "paper" ], "symbol": "?", "color": "red", - "use_action": { "type": "learn_spell", "spells": [ "phase_door", "create_lighter", "pain_split", "protection_aura" ] } + "use_action": { + "type": "learn_spell", + "spells": [ "phase_door", "create_lighter", "pain_split", "protection_aura", "magus_force_jar" ] + } }, { "id": "pyro", From dea9b14eed3b34773a42974375f9259a49882e17 Mon Sep 17 00:00:00 2001 From: John Bytheway Date: Thu, 25 Mar 2021 21:37:14 -0400 Subject: [PATCH 110/453] Detect duplicate values in json definitions of sets (#48225) --- data/json/items/gun/460.json | 2 +- data/json/items/gun/monster_gun.json | 12 +-------- data/json/items/ranged/slings.json | 25 +++---------------- data/mods/Aftershock/items/gun/5x50.json | 2 +- data/mods/CRT_EXPANSION/items/crt_gun.json | 2 +- .../CRT_EXPANSION/items/crt_toolarmor.json | 1 - data/mods/Magiclysm/items/ethereal_items.json | 3 +-- src/json.h | 14 ++++++++--- 8 files changed, 20 insertions(+), 41 deletions(-) diff --git a/data/json/items/gun/460.json b/data/json/items/gun/460.json index d3954498777c3..f93b32285e16c 100644 --- a/data/json/items/gun/460.json +++ b/data/json/items/gun/460.json @@ -18,7 +18,7 @@ "holster": true, "max_contains_volume": "20 L", "max_contains_weight": "20 kg", - "item_restriction": [ "m1911mag", "m1911bigmag", "m1911mag", "m1911bigmag" ] + "item_restriction": [ "m1911mag", "m1911bigmag" ] } ] } diff --git a/data/json/items/gun/monster_gun.json b/data/json/items/gun/monster_gun.json index dd0dc0fd09421..54423b2743f47 100644 --- a/data/json/items/gun/monster_gun.json +++ b/data/json/items/gun/monster_gun.json @@ -63,17 +63,7 @@ "name": { "str": "hurled rubble" }, "description": "Stone at the ready to crush that which isn't part of the blob.", "material": [ "stone" ], - "flags": [ - "PRIMITIVE_RANGED_WEAPON", - "NEVER_JAMS", - "NONCONDUCTIVE", - "NO_REPAIR", - "WATERPROOF_GUN", - "NO_SALVAGE", - "NO_UNLOAD", - "WATERPROOF_GUN", - "NEVER_JAMS" - ], + "flags": [ "PRIMITIVE_RANGED_WEAPON", "NEVER_JAMS", "NONCONDUCTIVE", "NO_REPAIR", "WATERPROOF_GUN", "NO_SALVAGE", "NO_UNLOAD" ], "skill": "throw", "ammo": [ "rock" ], "ammo_effects": [ "NO_PENETRATE_OBSTACLES", "NEVER_MISFIRES" ], diff --git a/data/json/items/ranged/slings.json b/data/json/items/ranged/slings.json index e3ed0d8e240af..cdf1948256f6e 100644 --- a/data/json/items/ranged/slings.json +++ b/data/json/items/ranged/slings.json @@ -10,7 +10,7 @@ "price": 150, "//": "It's little more than a piece of slightly shaped leather", "material": [ "leather" ], - "flags": [ "RELOAD_AND_SHOOT", "NEVER_JAMS", "PRIMITIVE_RANGED_WEAPON", "BELT_CLIP", "WATERPROOF_GUN", "NEVER_JAMS" ], + "flags": [ "RELOAD_AND_SHOOT", "NEVER_JAMS", "PRIMITIVE_RANGED_WEAPON", "BELT_CLIP", "WATERPROOF_GUN" ], "ammo_effects": [ "NEVER_MISFIRES" ], "skill": "throw", "ammo": [ "rock" ], @@ -35,15 +35,7 @@ "description": "A forked piece of wood with an elastic band stretched between two of its tips. Can launch tiny pebbles and similar things at high speeds.", "price": 500, "material": [ "wood" ], - "flags": [ - "FIRE_TWOHAND", - "RELOAD_AND_SHOOT", - "NEVER_JAMS", - "PRIMITIVE_RANGED_WEAPON", - "BELT_CLIP", - "WATERPROOF_GUN", - "NEVER_JAMS" - ], + "flags": [ "FIRE_TWOHAND", "RELOAD_AND_SHOOT", "NEVER_JAMS", "PRIMITIVE_RANGED_WEAPON", "BELT_CLIP", "WATERPROOF_GUN" ], "ammo_effects": [ "NEVER_MISFIRES" ], "skill": "archery", "ammo": [ "pebble" ], @@ -79,8 +71,7 @@ "NONCONDUCTIVE", "SHEATH_SPEAR", "ALWAYS_TWOHAND", - "WATERPROOF_GUN", - "NEVER_JAMS" + "WATERPROOF_GUN" ], "ammo_effects": [ "NEVER_MISFIRES" ], "techniques": [ "WBLOCK_2", "RAPID", "SWEEP" ], @@ -109,15 +100,7 @@ "description": "A modern slingshot with a wrist brace, allowing it to fire tiny objects slightly more forcefully than a simple wooden slingshot.", "price": 3000, "material": [ "steel", "plastic" ], - "flags": [ - "FIRE_TWOHAND", - "RELOAD_AND_SHOOT", - "NEVER_JAMS", - "PRIMITIVE_RANGED_WEAPON", - "BELT_CLIP", - "WATERPROOF_GUN", - "NEVER_JAMS" - ], + "flags": [ "FIRE_TWOHAND", "RELOAD_AND_SHOOT", "NEVER_JAMS", "PRIMITIVE_RANGED_WEAPON", "BELT_CLIP", "WATERPROOF_GUN" ], "ammo_effects": [ "NEVER_MISFIRES" ], "skill": "archery", "ammo": [ "pebble" ], diff --git a/data/mods/Aftershock/items/gun/5x50.json b/data/mods/Aftershock/items/gun/5x50.json index 503efee079558..b71d8d237ec53 100644 --- a/data/mods/Aftershock/items/gun/5x50.json +++ b/data/mods/Aftershock/items/gun/5x50.json @@ -11,7 +11,7 @@ "valid_mod_locations": [ [ "accessories", 2 ] ], "modes": [ [ "DEFAULT", "single", 1 ], [ "MULTI", "4 rd.", 4 ] ], "clip_size": 4, - "flags": [ "NEVER_JAMS", "RELOAD_ONE", "NEVER_JAMS", "RELOAD_EJECT" ], + "flags": [ "NEVER_JAMS", "RELOAD_ONE", "RELOAD_EJECT" ], "pocket_data": [ { "pocket_type": "MAGAZINE", "ammo_restriction": { "5x50": 4 } } ] } ] diff --git a/data/mods/CRT_EXPANSION/items/crt_gun.json b/data/mods/CRT_EXPANSION/items/crt_gun.json index b645c14f8f931..b20bac85e98a9 100644 --- a/data/mods/CRT_EXPANSION/items/crt_gun.json +++ b/data/mods/CRT_EXPANSION/items/crt_gun.json @@ -202,7 +202,7 @@ "price": 9900, "//": "You can get a decent Ruger .177 at walmart for $99", "material": [ "steel", "plastic" ], - "flags": [ "STR_RELOAD", "NON_FOULING", "NON_FOULING" ], + "flags": [ "STR_RELOAD", "NON_FOULING" ], "skill": "rifle", "ammo": [ "pellets" ], "weight": "5023 g", diff --git a/data/mods/CRT_EXPANSION/items/crt_toolarmor.json b/data/mods/CRT_EXPANSION/items/crt_toolarmor.json index 228154a7b7f4c..551b49fd24be8 100644 --- a/data/mods/CRT_EXPANSION/items/crt_toolarmor.json +++ b/data/mods/CRT_EXPANSION/items/crt_toolarmor.json @@ -214,7 +214,6 @@ "OUTER", "LIGHT_35", "CHARGEDIM", - "NO_UNLOAD", "TRADER_AVOID" ], "material_thickness": 3, diff --git a/data/mods/Magiclysm/items/ethereal_items.json b/data/mods/Magiclysm/items/ethereal_items.json index 32df41e0a69c7..a4ac0b348f05d 100644 --- a/data/mods/Magiclysm/items/ethereal_items.json +++ b/data/mods/Magiclysm/items/ethereal_items.json @@ -637,8 +637,7 @@ "TRADER_AVOID", "NO_UNLOAD", "NO_REPAIR", - "WATERPROOF_GUN", - "NEVER_JAMS" + "WATERPROOF_GUN" ], "ammo_effects": [ "NEVER_MISFIRES" ], "weight": "86 g", diff --git a/src/json.h b/src/json.h index 550b12086d25f..f9bbb5dba5ae7 100644 --- a/src/json.h +++ b/src/json.h @@ -466,7 +466,11 @@ class JsonIn while( !end_array() ) { typename T::value_type element; if( read( element, throw_on_error ) ) { - v.insert( std::move( element ) ); + if( !v.insert( std::move( element ) ).second ) { + return error_or_false( + throw_on_error, + "Duplicate entry in set defined by json array" ); + } } else { skip_value(); } @@ -1441,7 +1445,9 @@ Res JsonArray::get_tags( const size_t index ) const } for( const std::string line : jsin->get_array() ) { - res.insert( T( line ) ); + if( !res.insert( T( line ) ).second ) { + jsin->error( "duplicate item in set defined by json array" ); + } } return res; @@ -1466,7 +1472,9 @@ Res JsonObject::get_tags( const std::string &name ) const // otherwise assume it's an array and error if it isn't. for( const std::string line : jsin->get_array() ) { - res.insert( T( line ) ); + if( !res.insert( T( line ) ).second ) { + jsin->error( "duplicate item in set defined by json array" ); + } } return res; From 39f3713141b4d4baa4ee80699572155d4ed4d97e Mon Sep 17 00:00:00 2001 From: Eric <52087122+Ramza13@users.noreply.github.com> Date: Fri, 26 Mar 2021 22:34:11 -0400 Subject: [PATCH 111/453] Change weather to use effect_on_conditions (#48178) * Move weather into effect_on_conditions * Update effect_on_condition.json * LGTM issue --- data/json/effect_on_condition.json | 78 +++++++++++++++ data/json/weather_type.json | 82 ++++------------ doc/NPCs.md | 22 ++++- doc/WEATHER_TYPE.md | 76 ++------------- src/condition.cpp | 132 ++++++++++++++++++++++++-- src/condition.h | 20 +++- src/debug_menu.cpp | 3 +- src/dialogue.h | 4 + src/npctalk.cpp | 124 ++++++++++++++++++++++++ src/npctalk.h | 1 + src/npctalk_funcs.cpp | 7 ++ src/overmap_ui.cpp | 3 +- src/talker.h | 10 ++ src/talker_character.cpp | 20 ++++ src/talker_character.h | 6 ++ src/weather.cpp | 147 ++++------------------------- src/weather.h | 8 +- src/weather_gen.cpp | 77 +++++---------- src/weather_gen.h | 9 +- src/weather_type.cpp | 141 ++------------------------- src/weather_type.h | 79 +--------------- tests/weather_test.cpp | 4 +- 22 files changed, 504 insertions(+), 549 deletions(-) create mode 100644 data/json/effect_on_condition.json diff --git a/data/json/effect_on_condition.json b/data/json/effect_on_condition.json new file mode 100644 index 0000000000000..dc0db08616435 --- /dev/null +++ b/data/json/effect_on_condition.json @@ -0,0 +1,78 @@ +[ + { + "type": "effect_on_condition", + "id": "thunder", + "recurrence_min": 1, + "recurrence_max": 1, + "condition": { + "and": [ + { "or": [ { "is_weather": "thunder" }, { "is_weather": "lightning" } ] }, + { "one_in_chance": 50 }, + { "u_is_height": 0 } + ] + }, + "deactivate_condition": { "not": { "or": [ { "is_weather": "thunder" }, { "is_weather": "lightning" } ] } }, + "effect": [ + { "message": "You hear a distant rumble of thunder.", "sound": true }, + { "sound_effect": "thunder_far", "outdoor_event": true } + ] + }, + { + "type": "effect_on_condition", + "id": "lightning", + "recurrence_min": 1, + "recurrence_max": 1, + "condition": { "and": [ { "is_weather": "lightning" }, { "one_in_chance": 600 }, { "u_is_height": 0 } ] }, + "deactivate_condition": { "not": { "is_weather": "lightning" } }, + "effect": [ + { "message": "A flash of lightning illuminates your surroundings!" }, + { "sound_effect": "thunder_near" }, + "lightning" + ] + }, + { + "type": "effect_on_condition", + "id": "acid_drizzle", + "recurrence_min": 1, + "recurrence_max": 1, + "condition": { "and": [ { "is_weather": "acid_drizzle" }, "u_is_outside", { "not": { "u_has_pain": 30 } } ] }, + "deactivate_condition": { "not": { "is_weather": "acid_drizzle" } }, + "effect": [ { "message": "The acid rain stings, but is mostly harmless for now…" }, { "u_mod_pain": 1 } ] + }, + { + "type": "effect_on_condition", + "id": "acid_rain", + "recurrence_min": 1, + "recurrence_max": 1, + "condition": { + "and": [ + { "is_weather": "acid_rain" }, + "u_is_outside", + { "not": { "u_has_pain": 100 } }, + { + "not": { "or": [ { "u_has_wielded_with_flag": "RAIN_PROTECT" }, { "u_has_worn_with_flag": "RAINPROOF" } ] } + } + ] + }, + "deactivate_condition": { "not": { "is_weather": "acid_rain" } }, + "effect": [ { "message": "The acid rain burns!" }, { "u_mod_pain": 3 } ] + }, + { + "type": "effect_on_condition", + "id": "snow", + "recurrence_min": 6, + "recurrence_max": 6, + "condition": { "and": [ { "is_weather": "snowing" }, "u_is_outside" ] }, + "deactivate_condition": { "not": { "is_weather": "snowing" } }, + "effect": [ { "u_add_wet": 10 } ] + }, + { + "type": "effect_on_condition", + "id": "snowstorm", + "recurrence_min": 6, + "recurrence_max": 6, + "condition": { "and": [ { "is_weather": "snowstorm" }, "u_is_outside" ] }, + "deactivate_condition": { "not": { "is_weather": "snowstorm" } }, + "effect": [ { "u_add_wet": 40 } ] + } +] diff --git a/data/json/weather_type.json b/data/json/weather_type.json index 77fb5a5955120..62e2bebee943c 100644 --- a/data/json/weather_type.json +++ b/data/json/weather_type.json @@ -15,7 +15,7 @@ "rains": false, "acidic": false, "sun_intensity": "high", - "requirements": { "pressure_min": 1020, "humidity_max": 70, "time": "day" } + "condition": { "and": [ "is_day", { "is_pressure": 1020 }, { "not": { "is_humidity": 70 } } ] } }, { "id": "cloudy", @@ -33,7 +33,7 @@ "rains": false, "acidic": false, "sun_intensity": "light", - "requirements": { "pressure_max": 1010, "humidity_min": 40 } + "condition": { "and": [ { "is_humidity": 40 }, { "not": { "is_pressure": 1010 } } ] } }, { "id": "light_drizzle", @@ -54,7 +54,8 @@ "weather_animation": { "factor": 0.01, "color": "light_blue", "sym": "," }, "sound_category": "drizzle", "sun_intensity": "light", - "requirements": { "pressure_max": 1003, "humidity_min": 96, "humidity_and_pressure": false, "required_weathers": [ "cloudy" ] } + "required_weathers": [ "cloudy" ], + "condition": { "or": [ { "is_humidity": 96 }, { "not": { "is_pressure": 1003 } } ] } }, { "id": "drizzle", @@ -75,7 +76,8 @@ "weather_animation": { "factor": 0.01, "color": "light_blue", "sym": "." }, "sound_category": "drizzle", "sun_intensity": "light", - "requirements": { "pressure_max": 1000, "humidity_min": 97, "humidity_and_pressure": false, "required_weathers": [ "light_drizzle" ] } + "required_weathers": [ "light_drizzle" ], + "condition": { "or": [ { "is_humidity": 97 }, { "not": { "is_pressure": 1000 } } ] } }, { "id": "rain", @@ -96,12 +98,8 @@ "weather_animation": { "factor": 0.02, "color": "light_blue", "sym": "," }, "sound_category": "rainy", "sun_intensity": "light", - "requirements": { - "pressure_max": 993, - "humidity_min": 98, - "humidity_and_pressure": false, - "required_weathers": [ "light_drizzle", "drizzle" ] - } + "required_weathers": [ "light_drizzle", "drizzle" ], + "condition": { "or": [ { "is_humidity": 98 }, { "not": { "is_pressure": 993 } } ] } }, { "id": "thunder", @@ -118,19 +116,12 @@ "precip": "heavy", "rains": true, "acidic": false, - "effects": [ - { - "one_in_chance": 50, - "must_be_outside": false, - "sound_message": "You hear a distant rumble of thunder.", - "sound_effect": "thunder_far" - } - ], "tiles_animation": "weather_rain_drop", "weather_animation": { "factor": 0.02, "color": "light_blue", "sym": "." }, "sound_category": "thunder", "sun_intensity": "none", - "requirements": { "pressure_max": 996, "required_weathers": [ "rain" ] } + "required_weathers": [ "rain" ], + "condition": { "not": { "is_pressure": 996 } } }, { "id": "lightning", @@ -147,26 +138,12 @@ "precip": "heavy", "rains": true, "acidic": false, - "effects": [ - { - "one_in_chance": 50, - "must_be_outside": false, - "sound_message": "You hear a distant rumble of thunder.", - "sound_effect": "thunder_far" - }, - { - "one_in_chance": 600, - "must_be_outside": false, - "message": "A flash of lightning illuminates your surroundings!.", - "sound_effect": "thunder_near", - "lightning": true - } - ], "tiles_animation": "weather_rain_drop", "weather_animation": { "factor": 0.04, "color": "light_blue", "sym": "," }, "sound_category": "thunder", "sun_intensity": "none", - "requirements": { "pressure_max": 990, "required_weathers": [ "thunder" ] } + "required_weathers": [ "thunder" ], + "condition": { "not": { "is_pressure": 990 } } }, { "id": "acid_drizzle", @@ -183,21 +160,11 @@ "precip": "light", "rains": true, "acidic": true, - "effects": [ - { - "time_between": "3 minutes", - "must_be_outside": true, - "message": "The acid rain stings, but is mostly harmless for now…", - "rain_proof": true, - "pain_max": 10, - "pain": 1 - } - ], "tiles_animation": "weather_acid_drop", "weather_animation": { "factor": 0.01, "color": "light_green", "sym": "." }, "sound_category": "drizzle", "sun_intensity": "normal", - "requirements": { "required_weathers": [ "drizzle" ] } + "required_weathers": [ "drizzle" ] }, { "id": "acid_rain", @@ -214,21 +181,11 @@ "precip": "heavy", "rains": true, "acidic": true, - "effects": [ - { - "time_between": "2 seconds", - "must_be_outside": true, - "message": "The acid rain burns!", - "rain_proof": true, - "pain_max": 100, - "pain": 3 - } - ], "tiles_animation": "weather_acid_drop", "weather_animation": { "factor": 0.02, "color": "light_green", "sym": "," }, "sound_category": "rainy", "sun_intensity": "none", - "requirements": { "required_weathers": [ "rain" ] } + "required_weathers": [ "rain" ] }, { "id": "flurries", @@ -249,7 +206,8 @@ "weather_animation": { "factor": 0.01, "color": "white", "sym": "." }, "sound_category": "flurries", "sun_intensity": "light", - "requirements": { "temperature_max": 33, "required_weathers": [ "drizzle" ] } + "required_weathers": [ "flurries" ], + "condition": { "not": { "is_temperature": 33 } } }, { "id": "snowing", @@ -266,12 +224,12 @@ "precip": "heavy", "rains": false, "acidic": false, - "effects": [ { "must_be_outside": true, "wet": 10 } ], "tiles_animation": "weather_snowflake", "weather_animation": { "factor": 0.02, "color": "white", "sym": "," }, "sound_category": "snow", "sun_intensity": "light", - "requirements": { "temperature_max": 33, "required_weathers": [ "rain", "thunder", "lightning" ] } + "required_weathers": [ "rain", "thunder", "lightning" ], + "condition": { "not": { "is_temperature": 33 } } }, { "id": "snowstorm", @@ -288,11 +246,11 @@ "precip": "heavy", "rains": false, "acidic": false, - "effects": [ { "must_be_outside": true, "wet": 40 } ], "tiles_animation": "weather_snowflake", "weather_animation": { "factor": 0.04, "color": "white", "sym": "*" }, "sound_category": "snowstorm", "sun_intensity": "none", - "requirements": { "temperature_max": 33, "windpower_min": 15, "required_weathers": [ "thunder", "lightning" ] } + "required_weathers": [ "thunder", "lightning" ], + "condition": { "and": [ { "is_windpower": 15 }, { "not": { "is_temperature": 33 } } ] } } ] diff --git a/doc/NPCs.md b/doc/NPCs.md index 28c9fc1fd9601..5f9e5f18d9a80 100644 --- a/doc/NPCs.md +++ b/doc/NPCs.md @@ -486,6 +486,8 @@ Effect | Description `barber_beard` | Opens a menu allowing the player to choose a new beard style. `u_learn_recipe: recipe_string` | Your character will learn and memorize the recipe `recipe_string`. `npc_first_topic: talk_topic_string` | Changes the initial talk_topic of the NPC in all future dialogues. +`u_mod_pain: pain_int`
`npc_mod_pain: pain_int` | Your character or the NPC will have `pain_int` added or subtracted from its pain. +`u_add_wet: wet_int`
`npc_add_wet: wet_int` | Your character or the NPC will be wet `wet_int` as if they were in the rain. #### Trade / Items @@ -549,6 +551,13 @@ Effect | Description #### Map Updates `mapgen_update: mapgen_update_id_string`
`mapgen_update:` *list of `mapgen_update_id_string`s*, (optional `assign_mission_target` parameters) | With no other parameters, updates the overmap tile at the player's current location with the changes described in `mapgen_update_id` (or for each `mapgen_update_id` in the list). The `assign_mission_target` parameters can be used to change the location of the overmap tile that gets updated. See [the missions docs](MISSIONS_JSON.md) for `assign_mission_target` parameters and [the mapgen docs](MAPGEN.md) for `mapgen_update`. +`lightning` | Lights up the map as if its day time. + +#### General +Effect | Description +---|--- +`message: message_string`, (*optional* `sound: sound_bool`),(*optional* `outdoor_only: outdoor_only_bool`),(*optional* `snippet: snippet_bool`),(*optional* `type: type_string`),(*optional* `popup: popup_bool`) | Displays a message to the player of `message_string`. If `snippet_bool` is true(defaults to false) it will instead display a random snippet from `message_string` category. If `sound` is true(defaults to false) it will only display the message if the player is not deaf. `outdoor_only`(defaults to false) only matters when `sound` is true and will make the message less likely to be heard if the player is underground. Message will display as type of `type_string`. Type affects the color of message and can be any of the following values: good, neutral, bad, mixed, warning, info, debug, headshot, critical, grazing. enums.h has more info on each types use. If `popup_bool` is true the message will be in a modal popup the user has to dismiss to continue. +`sound_effect: sound_effect_id_string`, *optional* `outdoor_event: outdoor_event` | Will play a sound effect of type `sound_effect_id_string`. If `outdoor_event`(defaults to false) is true this will be less likely to play if the player is underground. #### Deprecated @@ -623,6 +632,10 @@ Condition | Type | Description `"u_driving"`
`"npc_driving"` | simple string | `true` if the player character or NPC is operating a vehicle. Note NPCs cannot currently operate vehicles. `"u_has_skill"`
`"npc_has_skill"` | dictionary | `u_has_skill` or `npc_has_skill` must be a dictionary with a `skill` string and a `level` int.
`true` if the player character or NPC has at least the value of `level` in `skill`. `"u_know_recipe"` | string | `true` if the player character knows the recipe specified in `u_know_recipe`. It only counts as known if it is actually memorized--holding a book with the recipe in it will not count. +`"u_has_pain"`
`"npc_has_pain"` | int | `true` if the player character's or NPC's pain is at least the value of `u_has_pain` or `npc_has_pain`. +`"u_is_height"`
`"npc_is_height"` | int | `true` if the player character's or NPC's elevation is at least the value of `u_is_height` or `npc_is_height`. +`"u_has_worn_with_flag"`
`"npc_has_worn_with_flag"` | string | `true` if the player character or NPC is wearing something with the `u_has_worn_with_flag` or `npc_has_worn_with_flag` flag. +`"u_has_wielded_with_flag"`
`"npc_has_wielded_with_flag"` | string | `true` if the player character or NPC is wielding something with the `u_has_wielded_with_flag` or `npc_has_wielded_with_flag` flag. #### Player Only conditions @@ -678,8 +691,13 @@ Condition | Type | Description `"days_since_cataclysm"` | int | `true` if at least `days_since_cataclysm` days have passed since the Cataclysm. `"is_season"` | string | `true` if the current season matches `is_season`, which must be one of "`spring"`, `"summer"`, `"autumn"`, or `"winter"`. `"is_day"` | simple string | `true` if it is currently daytime. -`"is_outside"` | simple string | `true` if the NPC is on a tile without a roof. - +`"u_is_outside"`
`"npc_is_outside"` | simple string | `true` if you or the NPC is on a tile without a roof. +`"one_in_chance"` | int | `true` if a one in `one_in_chance` random chance occurs. +`"is_temperature"` | int | `true` if it is currently at least `"is_temperature"` degrees fahrenheit. +`"is_windpower"` | int | `true` if current windpower is at least `"is_windpower"`. +`"is_humidity"` | int | `true` if current humidity is at least `"is_humidity"`. +`"is_pressure"` | int | `true` if current pressure is at least `"is_pressure"`. +`"is_weather"` | int | `true` if current weather is `"is_weather"`. #### Sample responses with conditions and effects ```json diff --git a/doc/WEATHER_TYPE.md b/doc/WEATHER_TYPE.md index 01612bb348467..b572553cd35c5 100644 --- a/doc/WEATHER_TYPE.md +++ b/doc/WEATHER_TYPE.md @@ -1,6 +1,6 @@ # WEATHER TYPES -Each weather type is a type of weather that occurs, its effects and what causes it. The only required entries are null and clear. +Each weather type is a type of weather that occurs, and what causes it. The only required entries are null and clear. ## `weather_type` properties @@ -26,8 +26,8 @@ Each weather type is a type of weather that occurs, its effects and what causes | `time_between_min` | Optional: the lower bound on the amount of time that will be guaranteed to pass before this weather happens again. Defaults to 0. | | `time_between_max` | Optional: the upper bound on the amount of time that will be guaranteed to pass before this weather happens again. Defaults to 0. | | `weather_animation` | Optional, Information controlling weather animations. Members: factor, color and glyph | -| `effects` | Array for the effects the weather has. Descibed in detail below -| `requirements` | Optional, is what determines what weather it is. All members are optional. When determining current weather, it loops through the entries in order and uses the last one to pass all the requirements. | +| `required_weathers` | a string array of possible weathers it is at this point in the loop. i.e. rain can only happen if the conditions for clouds light drizzle or drizzle are present | +| `condition` | A dialog condition to determine if this weather is happening. See Dialogue conditions section of [NPCs](NPCs.md) #### `weather_type` example @@ -37,9 +37,9 @@ Each weather type is a type of weather that occurs, its effects and what causes "id": "lightning", "type": "weather_type", "name": "Lightning Storm", - "color": "yellow", + "color": "c_yellow", "map_color": "h_yellow", - "sym": "%", + "glyph": "%", "ranged_penalty": 4, "sight_penalty": 1.25, "light_modifier": -45, @@ -48,27 +48,9 @@ Each weather type is a type of weather that occurs, its effects and what causes "precip": "heavy", "rains": true, "acidic": false, - "effects": [ - { - "one_in_chance": 50, - "must_be_outside": false, - "sound_message": "You hear a distant rumble of thunder.", - "sound_effect": "thunder_far" - }, - { - "one_in_chance": 600, - "must_be_outside": false, - "message": "A flash of lightning illuminates your surroundings!.", - "sound_effect": "thunder_near", - "lightning": true - } - ], - "tiles_animation": "weather_rain_drop", - "weather_animation": { "factor": 0.04, "color": "light_blue", "sym": "," }, - "sound_category": "thunder", - "sun_intensity": "none", - "requirements": { "pressure_max": 990, "required_weathers": [ "thunder" ] } - }, + "required_weathers": [ "thunder" ], + "condition": { "not": { "is_pressure": 990 } } + } ] ``` @@ -128,45 +110,3 @@ Each weather type is a type of weather that occurs, its effects and what causes }] } ``` - -### `requirements` properties - -| Identifier | Description | -| ------------------------------ | --------------------------------------------------------------------- | -| `pressure_min` | These are all minimum and maximum values for which the weather will occur. I.e., it will only rain if it is sufficiently humid. | -| `pressure_max` | | -| `humidity_min` | | -| `humidity_max` | | -| `temperature_min` | | -| `temperature_max` | | -| `windpower_min` | | -| `windpower_max` | | -| `humidity_and_pressure` | should logical AND be used for pressure and humidity requirements when they are both defined | -| `acidic` | does this require acidic precipitation | -| `time` | Valid values are: "day", "night", and "both". | -| `required_weathers` | a string array of possible prior weathers; i.e., rain can only happen if the conditions for clouds, light drizzle, or drizzle are present | -| `time_passed_min` | Optional: Time after the Cataclysm when this weather can start appearing; | -| `time_passed_max` | Optional: Time after the Cataclysm when this weather can no longer appear. | -| `one_in_chance` | Optional: This has a 1 in this value chance of happening. This will usually be called every 5 minutes| - - -### `spawns` properties - -| Identifier | Description | -| ------------------------------ | --------------------------------------------------------------------- | -| `max_radius` | Optional: The furthest away a spawn will happen. | -| `min_radius` | Optional: The closest a spawn will happen. | -| `hallucination_count` | Optional: Number of hallucinations of the target to spawn. | -| `real_count` | Optional: Number of real copies to spawn. | -| `target` | Optional: Monster id of target to spawn. If left blank a nearby monster will be used. | -| `target_range` | Optional: If target is left blank how far away to look for something to copy. | - -### `fields` properties - -| Identifier | Description | -| ------------------------------ | --------------------------------------------------------------------- | -| `type` | The string id of the field. | -| `intensity` | Intensity of the field. | -| `age` | Age of the field. | -| `outdoor_only` | Optional: Defaults to true. If true field will only spawn outdoors. | -| `radius` | Optional: Radius around player the effect will spread, defaults to everywhere. | diff --git a/src/condition.cpp b/src/condition.cpp index e5933505c5997..10aae878264d7 100644 --- a/src/condition.cpp +++ b/src/condition.cpp @@ -746,15 +746,75 @@ void conditional_t::set_is_day() } template -void conditional_t::set_is_outside() +void conditional_t::set_is_outside( bool is_npc ) { - condition = []( const T & d ) { - const map &here = get_map(); - const tripoint &pos = here.getabs( d.beta->pos() ); - return !here.has_flag( TFLAG_INDOORS, pos ); + condition = [is_npc]( const T & d ) { + return is_creature_outside( *d.actor( is_npc )->get_character() ); + }; +} + +template +void conditional_t::set_one_in_chance( const JsonObject &jo, const std::string &member ) +{ + const int one_in_chance = jo.get_int( member ); + condition = [one_in_chance]( const T & ) { + return one_in( one_in_chance ); + }; +} + +template +void conditional_t::set_is_temperature( const JsonObject &jo, const std::string &member ) +{ + const int temp_min = jo.get_int( member ); + condition = [temp_min]( const T & ) { + return get_weather().weather_precise->temperature >= temp_min; + }; +} + +template +void conditional_t::set_is_height( const JsonObject &jo, const std::string &member, bool is_npc ) +{ + const int height_min = jo.get_int( member ); + condition = [height_min, is_npc]( const T & d ) { + return d.actor( is_npc )->posz() >= height_min; + }; +} + +template +void conditional_t::set_is_windpower( const JsonObject &jo, const std::string &member ) +{ + const int windpower_min = jo.get_int( member ); + condition = [windpower_min]( const T & ) { + return get_weather().weather_precise->windpower >= windpower_min; + }; +} + +template +void conditional_t::set_is_humidity( const JsonObject &jo, const std::string &member ) +{ + const int humidity_min = jo.get_int( member ); + condition = [humidity_min]( const T & ) { + return get_weather().weather_precise->humidity >= humidity_min; }; } +template +void conditional_t::set_is_pressure( const JsonObject &jo, const std::string &member ) +{ + const int pressure_min = jo.get_int( member ); + condition = [pressure_min]( const T & ) { + return get_weather().weather_precise->pressure >= pressure_min; + }; +} + +template +void conditional_t::set_is_weather( const JsonObject &jo ) +{ + weather_type_id weather = weather_type_id( jo.get_string( "is_weather" ) ); + condition = [weather]( const T & ) { + return get_weather().weather_id == weather; + }; +} template void conditional_t::set_u_has_camp() { @@ -828,6 +888,36 @@ void conditional_t::set_mission_has_generic_rewards() }; } +template +void conditional_t::set_has_worn_with_flag( const JsonObject &jo, const std::string &member, + bool is_npc ) +{ + const std::string flag( jo.get_string( member ) ); + condition = [flag, is_npc]( const T & d ) { + return d.actor( is_npc )->worn_with_flag( flag_id( flag ) ); + }; +} + +template +void conditional_t::set_has_wielded_with_flag( const JsonObject &jo, const std::string &member, + bool is_npc ) +{ + const std::string flag( jo.get_string( member ) ); + condition = [flag, is_npc]( const T & d ) { + return d.actor( is_npc )->wielded_with_flag( flag_id( flag ) ); + }; +} + +template +void conditional_t::set_has_pain( const JsonObject &jo, const std::string &member, + bool is_npc ) +{ + const int min_pain = jo.get_int( member ); + condition = [min_pain, is_npc]( const T & d ) { + return d.actor( is_npc )->pain_cur() >= min_pain; + }; +} + template conditional_t::conditional_t( const JsonObject &jo ) { @@ -1006,6 +1096,34 @@ conditional_t::conditional_t( const JsonObject &jo ) set_has_skill( jo, "npc_has_skill", is_npc ); } else if( jo.has_member( "u_know_recipe" ) ) { set_u_know_recipe( jo, "u_know_recipe" ); + } else if( jo.has_int( "one_in_chance" ) ) { + set_one_in_chance( jo, "one_in_chance" ); + } else if( jo.has_int( "is_temperature" ) ) { + set_is_temperature( jo, "is_temperature" ); + } else if( jo.has_int( "is_windpower" ) ) { + set_is_windpower( jo, "is_windpower" ); + } else if( jo.has_int( "is_humidity" ) ) { + set_is_humidity( jo, "is_humidity" ); + } else if( jo.has_member( "is_pressure" ) ) { + set_is_pressure( jo, "is_pressure" ); + } else if( jo.has_int( "u_is_height" ) ) { + set_is_height( jo, "u_is_height" ); + } else if( jo.has_int( "npc_is_height" ) ) { + set_is_height( jo, "npc_is_height", is_npc ); + } else if( jo.has_string( "u_has_worn_with_flag" ) ) { + set_has_worn_with_flag( jo, "u_has_worn_with_flag" ); + } else if( jo.has_string( "npc_has_worn_with_flag" ) ) { + set_has_worn_with_flag( jo, "npc_has_worn_with_flag", is_npc ); + } else if( jo.has_string( "u_has_wielded_with_flag" ) ) { + set_has_wielded_with_flag( jo, "u_has_wielded_with_flag" ); + } else if( jo.has_string( "npc_has_wielded_with_flag" ) ) { + set_has_wielded_with_flag( jo, "npc_has_wielded_with_flag", is_npc ); + } else if( jo.has_member( "u_has_pain" ) ) { + set_has_pain( jo, "u_has_pain" ); + } else if( jo.has_int( "npc_has_pain" ) ) { + set_has_pain( jo, "npc_has_pain", is_npc ); + } else if( jo.has_string( "is_weather" ) ) { + set_is_weather( jo ); } else { for( const std::string &sub_member : dialogue_data::simple_string_conds ) { if( jo.has_string( sub_member ) ) { @@ -1087,8 +1205,10 @@ conditional_t::conditional_t( const std::string &type ) set_is_day(); } else if( type == "u_has_stolen_item" ) { set_has_stolen_item( is_npc ); - } else if( type == "is_outside" ) { + } else if( type == "u_is_outside" ) { set_is_outside(); + } else if( type == "is_outside" || type == "npc_is_outside" ) { + set_is_outside( is_npc ); } else if( type == "u_has_camp" ) { set_u_has_camp(); } else if( type == "has_pickup_list" ) { diff --git a/src/condition.h b/src/condition.h index ea9fd856de8bd..25af633754c12 100644 --- a/src/condition.h +++ b/src/condition.h @@ -23,7 +23,7 @@ const std::unordered_set simple_string_conds = { { "mission_complete", "mission_incomplete", "mission_has_generic_rewards", "npc_available", "npc_following", "npc_friend", "npc_hostile", "npc_train_skills", "npc_train_styles", "npc_train_spells", - "at_safe_space", "is_day", "npc_has_activity", "is_outside", "u_has_camp", + "at_safe_space", "is_day", "npc_has_activity", "is_outside", "u_is_outside", "npc_is_outside", "u_has_camp", "u_can_stow_weapon", "npc_can_stow_weapon", "u_has_weapon", "npc_has_weapon", "u_driving", "npc_driving", "has_pickup_list", "is_by_radio", "has_reason" @@ -43,7 +43,10 @@ const std::unordered_set complex_conds = { { "npc_cbm_reserve_rule", "npc_cbm_recharge_rule", "days_since_cataclysm", "is_season", "mission_goal", "u_has_var", "npc_has_var", "u_has_skill", "npc_has_skill", "u_know_recipe", "u_compare_var", "npc_compare_var", - "u_compare_time_since_var", "npc_compare_time_since_var" + "u_compare_time_since_var", "npc_compare_time_since_var", "is_weather", "one_in_chance", + "is_temperature", "is_windpower", "is_humidity", "is_pressure", "u_is_height", "npc_is_height", + "u_has_worn_with_flag", "npc_has_worn_with_flag", "u_has_wielded_with_flag", "npc_has_wielded_with_flag", + "u_has_pain", "npc_has_pain" } }; } // namespace dialogue_data @@ -88,6 +91,16 @@ struct conditional_t { void set_has_dexterity( const JsonObject &jo, const std::string &member, bool is_npc = false ); void set_has_intelligence( const JsonObject &jo, const std::string &member, bool is_npc = false ); void set_has_perception( const JsonObject &jo, const std::string &member, bool is_npc = false ); + void set_has_pain( const JsonObject &jo, const std::string &member, bool is_npc = false ); + void set_one_in_chance( const JsonObject &jo, const std::string &member ); + void set_is_temperature( const JsonObject &jo, const std::string &member ); + void set_is_height( const JsonObject &jo, const std::string &member, bool is_npc = false ); + void set_is_windpower( const JsonObject &jo, const std::string &member ); + void set_has_worn_with_flag( const JsonObject &jo, const std::string &member, bool is_npc = false ); + void set_is_humidity( const JsonObject &jo, const std::string &member ); + void set_is_pressure( const JsonObject &jo, const std::string &member ); + void set_has_wielded_with_flag( const JsonObject &jo, const std::string &member, + bool is_npc = false ); void set_is_wearing( const JsonObject &jo, const std::string &member, bool is_npc = false ); void set_has_item( const JsonObject &jo, const std::string &member, bool is_npc = false ); void set_has_items( const JsonObject &jo, const std::string &member, bool is_npc = false ); @@ -108,6 +121,7 @@ struct conditional_t { void set_npc_override( const JsonObject &jo ); void set_days_since( const JsonObject &jo ); void set_is_season( const JsonObject &jo ); + void set_is_weather( const JsonObject &jo ); void set_mission_goal( const JsonObject &jo ); void set_no_assigned_mission(); void set_has_assigned_mission(); @@ -130,7 +144,7 @@ struct conditional_t { void set_is_driving( bool is_npc = false ); void set_is_day(); void set_has_stolen_item( bool is_npc = false ); - void set_is_outside(); + void set_is_outside( bool is_npc = false ); void set_is_by_radio(); void set_u_has_camp(); void set_has_pickup_list(); diff --git a/src/debug_menu.cpp b/src/debug_menu.cpp index a7fbc2d575454..6ad998654ff89 100644 --- a/src/debug_menu.cpp +++ b/src/debug_menu.cpp @@ -2663,8 +2663,7 @@ void debug() } break; case debug_menu_index::TEST_WEATHER: { - get_weather().get_cur_weather_gen().test_weather( g->get_seed(), - get_weather().next_instance_allowed ); + get_weather().get_cur_weather_gen().test_weather( g->get_seed() ); } break; diff --git a/src/dialogue.h b/src/dialogue.h index fd748bd183fe0..65c1a4fe8bb64 100644 --- a/src/dialogue.h +++ b/src/dialogue.h @@ -99,6 +99,10 @@ struct talk_effect_fun_t { void set_remove_effect( const JsonObject &jo, const std::string &member, bool is_npc = false ); void set_add_trait( const JsonObject &jo, const std::string &member, bool is_npc = false ); void set_remove_trait( const JsonObject &jo, const std::string &member, bool is_npc = false ); + void set_message( const JsonObject &jo, const std::string &member ); + void set_mod_pain( const JsonObject &jo, const std::string &member, bool is_npc ); + void set_add_wet( const JsonObject &jo, const std::string &member, bool is_npc ); + void set_sound_effect( const JsonObject &jo, const std::string &member ); void set_add_var( const JsonObject &jo, const std::string &member, bool is_npc = false ); void set_remove_var( const JsonObject &jo, const std::string &member, bool is_npc = false ); void set_adjust_var( const JsonObject &jo, const std::string &member, bool is_npc = false ); diff --git a/src/npctalk.cpp b/src/npctalk.cpp index 6ad38bee93b2c..9596f70fb7af4 100644 --- a/src/npctalk.cpp +++ b/src/npctalk.cpp @@ -80,6 +80,7 @@ static const activity_id ACT_WAIT_NPC( "ACT_WAIT_NPC" ); static const efftype_id effect_narcosis( "narcosis" ); static const efftype_id effect_riding( "riding" ); +static const efftype_id effect_sleep( "sleep" ); static const efftype_id effect_under_operation( "under_operation" ); static const itype_id fuel_type_animal( "animal" ); @@ -2061,6 +2062,116 @@ void talk_effect_fun_t::set_npc_first_topic( const std::string &chat_topic ) }; } +void talk_effect_fun_t::set_message( const JsonObject &jo, const std::string &member ) +{ + std::string message = jo.get_string( member ); + const bool snippet = jo.get_bool( "snippet", false ); + const bool outdoor_only = jo.get_bool( "outdoor_only", false ); + const bool sound = jo.get_bool( "sound", false ); + const bool popup_msg = jo.get_bool( "popup", false ); + game_message_type type = m_neutral; + std::string type_string = jo.get_string( "type", "neutral" ); + if( type_string == "good" ) { + type = m_good; + } else if( type_string == "neutral" ) { + type = m_neutral; + } else if( type_string == "bad" ) { + type = m_bad; + } else if( type_string == "mixed" ) { + type = m_mixed; + } else if( type_string == "warning" ) { + type = m_warning; + } else if( type_string == "info" ) { + type = m_info; + } else if( type_string == "debug" ) { + type = m_debug; + } else if( type_string == "headshot" ) { + type = m_headshot; + } else if( type_string == "critical" ) { + type = m_critical; + } else if( type_string == "grazing" ) { + type = m_grazing; + } else { + jo.throw_error( "Invalid message type." ); + } + + function = [message, outdoor_only, sound, snippet, type, popup_msg]( const dialogue & d ) { + std::string translated_message; + if( snippet ) { + translated_message = SNIPPET.random_from_category( message ).value_or( translation() ).translated(); + } else { + translated_message = _( message ); + } + Character *target = d.alpha->get_character(); + if( !target ) { + return; + } + if( sound ) { + bool display = false; + map &here = get_map(); + if( !target->has_effect( effect_sleep ) && !target->is_deaf() ) { + if( !outdoor_only || here.get_abs_sub().z >= 0 ) { + display = true; + } else if( one_in( std::max( roll_remainder( 2.0f * here.get_abs_sub().z / + target->mutation_value( "hearing_modifier" ) ), 1 ) ) ) { + display = true; + } + } + if( !display ) { + return; + } + } + if( popup_msg ) { + popup( translated_message, PF_NONE ); + } else { + target->add_msg_if_player( type, translated_message ); + } + + }; +} + + +void talk_effect_fun_t::set_mod_pain( const JsonObject &jo, const std::string &member, + bool is_npc ) +{ + int amount = jo.get_int( member ); + function = [is_npc, amount]( const dialogue & d ) { + d.actor( is_npc )->mod_pain( amount ); + }; +} + +void talk_effect_fun_t::set_add_wet( const JsonObject &jo, const std::string &member, + bool is_npc ) +{ + int amount = jo.get_int( member ); + function = [is_npc, amount]( const dialogue & d ) { + Character *target = d.actor( is_npc )->get_character(); + if( target ) { + wet_character( *target, amount ); + } + }; +} + +void talk_effect_fun_t::set_sound_effect( const JsonObject &jo, const std::string &member ) +{ + std::string sound_effect = jo.get_string( member ); + const bool outdoor_event = jo.get_bool( "outdoor_event", false ); + function = [sound_effect, outdoor_event]( const dialogue & d ) { + map &here = get_map(); + + Character *target = d.alpha->get_character(); + if( target && !target->has_effect( effect_sleep ) && !target->is_deaf() ) { + if( !outdoor_event || here.get_abs_sub().z >= 0 ) { + sfx::play_variant_sound( "environment", sound_effect, 80, random_direction() ); + } else if( one_in( std::max( roll_remainder( 2.0f * here.get_abs_sub().z / + target->mutation_value( "hearing_modifier" ) ), 1 ) ) ) { + sfx::play_variant_sound( "environment", sound_effect, + ( 80 * target->mutation_value( "hearing_modifier" ) ), random_direction() ); + } + } + }; +} + void talk_effect_t::set_effect_consequence( const talk_effect_fun_t &fun, dialogue_consequence con ) { @@ -2298,6 +2409,18 @@ void talk_effect_t::parse_sub_effect( const JsonObject &jo ) } else if( jo.has_string( "npc_first_topic" ) ) { const std::string chat_topic = jo.get_string( "npc_first_topic" ); subeffect_fun.set_npc_first_topic( chat_topic ); + } else if( jo.has_string( "sound_effect" ) ) { + subeffect_fun.set_sound_effect( jo, "sound_effect" ); + } else if( jo.has_string( "message" ) ) { + subeffect_fun.set_message( jo, "message" ); + } else if( jo.has_int( "u_mod_pain" ) ) { + subeffect_fun.set_mod_pain( jo, "u_mod_pain", false ); + } else if( jo.has_int( "npc_mod_pain" ) ) { + subeffect_fun.set_mod_pain( jo, "npc_mod_pain", false ); + } else if( jo.has_int( "u_add_wet" ) ) { + subeffect_fun.set_add_wet( jo, "u_add_wet", false ); + } else if( jo.has_int( "npc_add_wet" ) ) { + subeffect_fun.set_add_wet( jo, "npc_add_wet", true ); } else { jo.throw_error( "invalid sub effect syntax: " + jo.str() ); } @@ -2384,6 +2507,7 @@ void talk_effect_t::parse_string_effect( const std::string &effect_id, const Jso WRAP( npc_die ), WRAP( npc_thankful ), WRAP( clear_overrides ), + WRAP( lightning ), WRAP( nothing ) #undef WRAP } diff --git a/src/npctalk.h b/src/npctalk.h index 0fc0587615121..f882fece9fdad 100644 --- a/src/npctalk.h +++ b/src/npctalk.h @@ -67,6 +67,7 @@ void deny_train( npc & ); // p gets "asked_to_train" void deny_personal_info( npc & ); // p gets "asked_personal_info" void hostile( npc & ); // p turns hostile to u void flee( npc & ); +void lightning( npc &p ); void leave( npc & ); // p becomes indifferent void stop_following( npc & ); void stranger_neutral( npc & ); // p is now neutral towards you diff --git a/src/npctalk_funcs.cpp b/src/npctalk_funcs.cpp index ed10341c7511e..45f092e1610e9 100644 --- a/src/npctalk_funcs.cpp +++ b/src/npctalk_funcs.cpp @@ -801,6 +801,13 @@ void talk_function::flee( npc &p ) p.set_attitude( NPCATT_FLEE ); } +void talk_function::lightning( npc & ) +{ + if( get_player_character().posz() >= 0 ) { + get_weather().lightning_active = true; + } +} + void talk_function::leave( npc &p ) { add_msg( _( "%s leaves." ), p.name ); diff --git a/src/overmap_ui.cpp b/src/overmap_ui.cpp index 79c97b7e89cd6..7f294b6c5102d 100644 --- a/src/overmap_ui.cpp +++ b/src/overmap_ui.cpp @@ -220,8 +220,7 @@ static weather_type_id get_weather_at_point( const tripoint_abs_omt &pos ) // TODO: fix point types const tripoint abs_ms_pos = project_to( pos ).raw(); const auto &wgen = overmap_buffer.get_settings( pos ).weather; - const auto weather = wgen.get_weather_conditions( abs_ms_pos, calendar::turn, g->get_seed(), - g->weather.next_instance_allowed ); + const auto weather = wgen.get_weather_conditions( abs_ms_pos, calendar::turn, g->get_seed() ); iter = weather_cache.insert( std::make_pair( pos, weather ) ).first; } return iter->second; diff --git a/src/talker.h b/src/talker.h index 6d9baaab14cf0..c7f1655461fb9 100644 --- a/src/talker.h +++ b/src/talker.h @@ -314,5 +314,15 @@ class talker virtual bool is_safe() const { return true; } + virtual void mod_pain( int ) {} + virtual int pain_cur() const { + return 0; + } + virtual bool worn_with_flag( const flag_id & ) const { + return false; + } + virtual bool wielded_with_flag( const flag_id & ) const { + return false; + } }; #endif // CATA_SRC_TALKER_H diff --git a/src/talker_character.cpp b/src/talker_character.cpp index 449e405a8c1ab..ab6f12029ed57 100644 --- a/src/talker_character.cpp +++ b/src/talker_character.cpp @@ -292,3 +292,23 @@ void talker_character::shout( const std::string &speech, bool order ) { me_chr->shout( speech, order ); } +\ +int talker_character::pain_cur() const +{ + return me_chr->get_pain(); +} + +void talker_character::mod_pain( int amount ) +{ + me_chr->mod_pain( amount ); +} + +bool talker_character::worn_with_flag( const flag_id &flag ) const +{ + return me_chr->worn_with_flag( flag ); +} + +bool talker_character::wielded_with_flag( const flag_id &flag ) const +{ + return me_chr->weapon.has_flag( flag ); +} diff --git a/src/talker_character.h b/src/talker_character.h index 6364f02329648..bc0fb7f38a914 100644 --- a/src/talker_character.h +++ b/src/talker_character.h @@ -55,6 +55,7 @@ class talker_character: public talker int dex_cur() const override; int int_cur() const override; int per_cur() const override; + int pain_cur() const override; bool has_trait( const trait_id &trait_to_check ) const override; void set_mutation( const trait_id &new_trait ) override; void unset_mutation( const trait_id &old_trait ) override; @@ -108,6 +109,11 @@ class talker_character: public talker // speaking void shout( const std::string &speech = "", bool order = false ) override; + bool worn_with_flag( const flag_id &flag ) const override; + bool wielded_with_flag( const flag_id &flag ) const override; + + void mod_pain( int amount ) override; + protected: talker_character() = default; player *me_chr; diff --git a/src/weather.cpp b/src/weather.cpp index 3ae66dcd3f8bc..e78ce253da33b 100644 --- a/src/weather.cpp +++ b/src/weather.cpp @@ -67,7 +67,7 @@ static const flag_id json_flag_SUN_GLASSES( "SUN_GLASSES" ); * @{ */ -static bool is_creature_outside( const Creature &target ) +bool is_creature_outside( const Creature &target ) { map &here = get_map(); return here.is_outside( point( target.posx(), target.posy() ) ) && here.get_abs_sub().z >= 0; @@ -169,7 +169,7 @@ weather_type_id current_weather( const tripoint &location, const time_point &t ) if( g->weather.weather_override != WEATHER_NULL ) { return g->weather.weather_override; } - return wgen.get_weather_conditions( location, t, g->get_seed(), g->weather.next_instance_allowed ); + return wgen.get_weather_conditions( location, t, g->get_seed() ); } ////// Funnels. @@ -401,10 +401,9 @@ static void fill_water_collectors( int mmPerHour, bool acid ) * @see map::decay_fields_and_scent * @see player::drench */ -void wet( Character &target, int amount ) +void wet_character( Character &target, int amount ) { - if( !is_creature_outside( target ) || - amount <= 0 || + if( amount <= 0 || target.has_trait( trait_FEATHERS ) || target.weapon.has_flag( json_flag_RAIN_PROTECT ) || ( !one_in( 50 ) && target.worn_with_flag( json_flag_RAINPROOF ) ) ) { @@ -469,7 +468,7 @@ void handle_weather_effects( const weather_type_id &w ) { //Possible TODO, make npc/monsters affected map &here = get_map(); - Character &player_character = get_player_character(); + Character &target = get_player_character(); if( w->rains && w->precip != precip_class::none ) { fill_water_collectors( precip_mm_per_hour( w->precip ), w->acidic ); @@ -486,129 +485,13 @@ void handle_weather_effects( const weather_type_id &w ) wetness = 60; } here.decay_fields_and_scent( decay_time ); - wet( player_character, wetness ); + // Coarse correction to get us back to previously intended soaking rate. + if( calendar::once_every( 6_seconds ) && is_creature_outside( target ) ) { + wet_character( target, wetness ); + } } glare( w ); g->weather.lightning_active = false; - - for( const weather_effect ¤t_effect : w->effects ) { - if( current_effect.must_be_outside && !is_creature_outside( player_character ) ) { - continue; - } - if( current_effect.time_between > 0_seconds && - !calendar::once_every( current_effect.time_between ) ) { - continue; - } - if( !one_in( current_effect.one_in_chance ) ) { - continue; - } - if( current_effect.lightning && here.get_abs_sub().z >= 0 ) { - g->weather.lightning_active = true; - } - if( current_effect.rain_proof ) { - int chance = 0; - if( w->precip <= precip_class::light ) { - chance = 2; - } else if( w->precip >= precip_class::heavy ) { - chance = 4; - } - if( player_character.weapon.has_flag( json_flag_RAIN_PROTECT ) && one_in( chance ) ) { - add_msg( _( "Your %s protects you from the weather." ), player_character.weapon.tname() ); - continue; - } else { - if( player_character.worn_with_flag( json_flag_RAINPROOF ) && one_in( chance * 2 ) ) { - add_msg( _( "Your clothing protects you from the weather." ) ); - continue; - } else { - bool has_helmet = false; - if( player_character.is_wearing_power_armor( &has_helmet ) && ( has_helmet || - one_in( chance * 2 ) ) ) { - add_msg( _( "Your power armor protects you from the weather." ) ); - continue; - } - } - } - } - if( player_character.get_pain() >= current_effect.pain_max ) { - continue; - } - - bool spawned = current_effect.spawns.empty(); - for( const spawn_type &spawn : current_effect.spawns ) { - monster target_monster; - if( spawn.target.is_empty() ) { - //grab a random nearby hostile creature to create a hallucination or copy of - Creature *copy = g->get_creature_if( [&spawn]( const Creature & critter ) -> bool { - bool not_self = get_player_character().pos() != critter.pos(); - bool in_range = std::round( rl_dist_exact( get_player_character().pos(), critter.pos() ) ) <= spawn.target_range; - bool valid_target = get_player_character().attitude_to( critter ) == Creature::Attitude::HOSTILE; - return not_self && in_range && valid_target; - } ); - if( copy == nullptr ) { - continue; - } - target_monster = *dynamic_cast( copy ); - } else { - target_monster = monster( spawn.target ); - } - - for( int i = 0; i < spawn.hallucination_count; i++ ) { - tripoint point; - if( g->find_nearby_spawn_point( player_character, target_monster.type->id, spawn.min_radius, - spawn.max_radius, point ) ) { - g->spawn_hallucination( point, target_monster.type->id ); - spawned = true; - } - } - for( int i = 0; i < spawn.real_count; i++ ) { - tripoint point; - if( g->find_nearby_spawn_point( player_character, target_monster.type->id, spawn.min_radius, - spawn.max_radius, point ) ) { - g->place_critter_at( target_monster.type->id, point ); - spawned = true; - } - } - } - if( !spawned ) { - continue; - } - for( const weather_field &field : current_effect.fields ) { - for( const tripoint &dest : get_map().points_in_radius( player_character.pos(), field.radius ) ) { - if( !field.outdoor_only || get_map().is_outside( dest ) ) { - get_map().add_field( dest, field.type, field.intensity, field.age ); - } - } - } - if( current_effect.effect_id.is_valid() ) { - if( current_effect.target_part.is_valid() ) { - player_character.add_effect( current_effect.effect_id, current_effect.effect_duration, - current_effect.target_part ); - } else { - player_character.add_effect( current_effect.effect_id, current_effect.effect_duration ); - } - } - if( current_effect.trait_id_to_add.is_valid() ) { - player_character.set_mutation( current_effect.trait_id_to_add ); - } - if( current_effect.trait_id_to_remove.is_valid() ) { - player_character.unset_mutation( current_effect.trait_id_to_remove ); - } - if( current_effect.damage.has_value() ) { - if( current_effect.target_part.is_valid() ) { - player_character.deal_damage( nullptr, current_effect.target_part, current_effect.damage.value() ); - } else { - for( const bodypart_id &bp : player_character.get_all_body_parts() ) { - player_character.deal_damage( nullptr, bp, current_effect.damage.value() ); - } - } - } - player_character.mod_healthy( current_effect.healthy ); - player_character.mod_rad( current_effect.radiation ); - wet( player_character, current_effect.wet ); - player_character.mod_pain( current_effect.pain ); - weather_sound( current_effect.sound_message, current_effect.sound_effect ); - player_character.add_msg_if_player( current_effect.message ); - } } static std::string to_string( const weekdays &d ) @@ -696,6 +579,7 @@ std::string weather_forecast( const point_abs_sm &abs_sm_pos ) // TODO: fix point types const tripoint abs_ms_pos = tripoint( project_to( abs_sm_pos ).raw(), 0 ); + w_point weatherPoint = *g->weather.weather_precise; // TODO: wind direction and speed const time_point last_hour = calendar::turn - ( calendar::turn - calendar::turn_zero ) % 1_hours; @@ -704,7 +588,8 @@ std::string weather_forecast( const point_abs_sm &abs_sm_pos ) const weather_generator wgen = get_weather().get_cur_weather_gen(); for( time_point i = last_hour + d * 12_hours; i < last_hour + ( d + 1 ) * 12_hours; i += 1_hours ) { w_point w = wgen.get_weather( abs_ms_pos, i, g->get_seed() ); - forecast = std::max( forecast, wgen.get_weather_conditions( w, g->weather.next_instance_allowed ) ); + *g->weather.weather_precise = w; + forecast = std::max( forecast, wgen.get_weather_conditions( w ) ); high = std::max( high, w.temperature ); low = std::min( low, w.temperature ); } @@ -729,6 +614,7 @@ std::string weather_forecast( const point_abs_sm &abs_sm_pos ) print_temperature( high ), print_temperature( low ) ); } + *g->weather.weather_precise = weatherPoint; return weather_report; } @@ -1058,13 +944,11 @@ void weather_manager::update_weather() g->get_seed() ); weather_type_id old_weather = weather_id; weather_id = weather_override == WEATHER_NULL ? - weather_gen.get_weather_conditions( w, next_instance_allowed ) + weather_gen.get_weather_conditions( w ) : weather_override; sfx::do_ambient(); temperature = w.temperature; lightning_active = false; - next_instance_allowed[weather_id] = calendar::turn + rng( weather_id->time_between_min, - weather_id->time_between_max ); nextweather = calendar::turn + rng( weather_id->duration_min, weather_id->duration_max ); map &here = get_map(); if( weather_id != old_weather && weather_id->dangerous && @@ -1084,6 +968,9 @@ void weather_manager::update_weather() } here.set_seen_cache_dirty( tripoint_zero ); } + if( weather_id != old_weather ) { + effect_on_conditions::process_reactivate(); + } } } diff --git a/src/weather.h b/src/weather.h index d63dc2e9cdf63..4e3a4c1803c8f 100644 --- a/src/weather.h +++ b/src/weather.h @@ -50,6 +50,7 @@ static constexpr int BODYTEMP_SCORCHING = 9500; #include class Character; +class Creature; class item; struct rl_vec2d; struct trap; @@ -82,7 +83,8 @@ struct weather_sum { float sunlight = 0.0f; int wind_amount = 0; }; - +bool is_creature_outside( const Creature &target ); +void wet_character( Character &target, int amount ); weather_type_id get_bad_weather(); std::string get_shortdirstring( int angle ); @@ -157,7 +159,6 @@ int incident_sunlight( const weather_type_id &wtype, const time_point &t = calendar::turn ); void weather_sound( const translation &sound_message, const std::string &sound_effect ); -void wet( Character &target, int amount ); class weather_manager { @@ -178,7 +179,6 @@ class weather_manager cata::optional wind_direction_override; cata::optional windspeed_override; weather_type_id weather_override; - std::map next_instance_allowed; // not only sets nextweather, but updates weather as well void set_nextweather( time_point t ); // The time at which weather will shift next. @@ -190,8 +190,6 @@ class weather_manager // Returns outdoor or indoor temperature of given location int get_temperature( const tripoint_abs_omt &location ); void clear_temp_cache(); - void on_load(); - static void serialize_all( JsonOut &json ); static void unserialize_all( JsonIn &jsin ); }; diff --git a/src/weather_gen.cpp b/src/weather_gen.cpp index 337ea17b9fe9a..bf2798df042f6 100644 --- a/src/weather_gen.cpp +++ b/src/weather_gen.cpp @@ -8,7 +8,11 @@ #include #include +#include "avatar.h" #include "cata_utility.h" +#include "condition.h" +#include "dialogue.h" +#include "game.h" #include "game_constants.h" #include "json.h" #include "math_defines.h" @@ -168,70 +172,37 @@ w_point weather_generator::get_weather( const tripoint &location, const time_poi } weather_type_id weather_generator::get_weather_conditions( const tripoint &location, - const time_point &t, unsigned seed, - std::map &next_instance_allowed ) const + const time_point &t, unsigned seed ) const { w_point w( get_weather( location, t, seed ) ); - weather_type_id wt = get_weather_conditions( w, next_instance_allowed ); + weather_type_id wt = get_weather_conditions( w ); return wt; } -weather_type_id weather_generator::get_weather_conditions( const w_point &w, - std::map &next_instance_allowed ) const +weather_type_id weather_generator::get_weather_conditions( const w_point & ) const { weather_type_id current_conditions = WEATHER_CLEAR; + dialogue d; + standard_npc default_npc( "Default" ); + d.alpha = get_talker_for( get_avatar() ); + d.beta = get_talker_for( default_npc ); for( const std::string &weather_type : weather_types ) { weather_type_id type = weather_type_id( weather_type ); - const weather_requirements &requires = type->requirements; - if( ( w.time < ( calendar::start_of_cataclysm + requires.time_passed_min ) ) || - ( requires.time_passed_max != 0_seconds && - ( w.time > ( calendar::start_of_cataclysm + requires.time_passed_max ) ) ) ) { - continue; - } - std::map::iterator instance = next_instance_allowed.find( type ); - if( instance != next_instance_allowed.end() && instance->second > calendar::turn ) { - continue; - } - - bool test_pressure = - requires.pressure_max > w.pressure && - requires.pressure_min < w.pressure; - bool test_humidity = - requires.humidity_max > w.humidity && - requires.humidity_min < w.humidity; - if( ( requires.humidity_and_pressure && !( test_pressure && test_humidity ) ) || - ( !requires.humidity_and_pressure && !( test_pressure || test_humidity ) ) ) { - continue; - } - - bool test_temperature = - requires.temperature_max > w.temperature && - requires.temperature_min < w.temperature; - bool test_windspeed = - requires.windpower_max > w.windpower && - requires.windpower_min < w.windpower; - if( !( test_temperature && test_windspeed ) ) { - continue; - } - - if( !requires.required_weathers.empty() ) { - if( std::find( requires.required_weathers.begin(), requires.required_weathers.end(), - current_conditions ) == requires.required_weathers.end() ) { - continue; + bool required_weather = type->required_weathers.empty(); + if( !required_weather ) { + for( const weather_type_id &weather : type->required_weathers ) { + if( weather == current_conditions ) { + required_weather = true; + break; + } } } - if( !( requires.time == weather_time_requirement_type::both || - ( requires.time == weather_time_requirement_type::day && is_day( calendar::turn ) ) || - ( requires.time == weather_time_requirement_type::night && !is_day( calendar::turn ) ) ) ) { + if( required_weather && type->condition( d ) ) { + current_conditions = type; continue; } - if( requires.one_in_chance != 0 && !one_in( requires.one_in_chance ) ) { - continue; - } - - current_conditions = type; } return current_conditions; } @@ -293,13 +264,13 @@ int weather_generator::get_water_temperature() const return water_temperature; } -void weather_generator::test_weather( unsigned seed, - std::map &next_instance_allowed ) const +void weather_generator::test_weather( unsigned seed ) const { // Outputs a Cata year's worth of weather data to a CSV file. // Usage: // weather_generator WEATHERGEN; // Instantiate the class. // WEATHERGEN.test_weather(); // Runs this test. + w_point weatherPoint = *g->weather.weather_precise; write_to_file( "weather.output", [&]( std::ostream & testfile ) { testfile << "|;year;season;day;hour;minute;temperature(F);humidity(%);pressure(mB);weatherdesc;windspeed(mph);winddirection" @@ -309,7 +280,8 @@ void weather_generator::test_weather( unsigned seed, const time_point end = begin + 2 * calendar::year_length(); for( time_point i = begin; i < end; i += 20_minutes ) { w_point w = get_weather( tripoint_zero, i, seed ); - weather_type_id conditions = get_weather_conditions( w, next_instance_allowed ); + weather_type_id conditions = get_weather_conditions( w ); + *g->weather.weather_precise = w; int year = to_turns( i - calendar::turn_zero ) / to_turns ( calendar::year_length() ) + 1; @@ -328,6 +300,7 @@ void weather_generator::test_weather( unsigned seed, } }, "weather test file" ); + *g->weather.weather_precise = weatherPoint; } weather_generator weather_generator::load( const JsonObject &jo ) diff --git a/src/weather_gen.h b/src/weather_gen.h index 972404d9da016..3f7baca8be077 100644 --- a/src/weather_gen.h +++ b/src/weather_gen.h @@ -55,15 +55,12 @@ class weather_generator * relative position (relative to the map you called getabs on). */ w_point get_weather( const tripoint &, const time_point &, unsigned ) const; - weather_type_id get_weather_conditions( const tripoint &, const time_point &, - unsigned seed, std::map &next_instance_allowed ) const; - weather_type_id get_weather_conditions( const w_point &, - std::map &next_instance_allowed ) const; + weather_type_id get_weather_conditions( const tripoint &, const time_point &, unsigned seed ) const; + weather_type_id get_weather_conditions( const w_point & ) const; int get_wind_direction( season_type ) const; int convert_winddir( int ) const; int get_water_temperature() const; - void test_weather( unsigned seed, - std::map &next_instance_allowed ) const; + void test_weather( unsigned seed ) const; double get_weather_temperature( const tripoint &, const time_point &, unsigned ) const; diff --git a/src/weather_type.cpp b/src/weather_type.cpp index 48a76f726e262..e48d9134024a5 100644 --- a/src/weather_type.cpp +++ b/src/weather_type.cpp @@ -4,6 +4,7 @@ #include #include "assign.h" +#include "condition.h" #include "debug.h" #include "generic_factory.h" #include "json.h" @@ -53,23 +54,6 @@ std::string enum_to_string( sun_intensity_type data ) abort(); } -template<> -std::string enum_to_string( weather_time_requirement_type data ) -{ - switch( data ) { - case weather_time_requirement_type::day: - return "day"; - case weather_time_requirement_type::night: - return "night"; - case weather_time_requirement_type::both: - return "both"; - case weather_time_requirement_type::last: - break; - } - debugmsg( "Invalid time_requirement_type" ); - abort(); -} - template<> std::string enum_to_string( weather_sound_category data ) { @@ -91,7 +75,7 @@ std::string enum_to_string( weather_sound_category data case weather_sound_category::last: break; } - debugmsg( "Invalid time_requirement_type" ); + debugmsg( "Invalid weather sound category." ); abort(); } @@ -117,42 +101,12 @@ void weather_type::finalize() void weather_type::check() const { - for( const weather_type_id &required : requirements.required_weathers ) { - if( !required.is_valid() ) { - debugmsg( "Required weather type %s does not exist.", required.c_str() ); + for( const auto &type : required_weathers ) { + if( !type.is_valid() ) { + debugmsg( "Weather type %s does not exist.", type.c_str() ); abort(); } } - for( const weather_effect &effect : effects ) { - if( !effect.effect_id.is_empty() && !effect.effect_id.is_valid() ) { - debugmsg( "Effect type %s does not exist.", effect.effect_id.c_str() ); - abort(); - } - if( !effect.trait_id_to_add.is_empty() && !effect.trait_id_to_add.is_valid() ) { - debugmsg( "Trait %s does not exist.", effect.trait_id_to_add.c_str() ); - abort(); - } - if( !effect.trait_id_to_remove.is_empty() && !effect.trait_id_to_remove.is_valid() ) { - debugmsg( "Trait %s does not exist.", effect.trait_id_to_remove.c_str() ); - abort(); - } - if( !effect.target_part.is_empty() && !effect.target_part.is_valid() ) { - debugmsg( "Target part %s does not exist.", effect.target_part.c_str() ); - abort(); - } - for( const spawn_type &spawn : effect.spawns ) { - if( !spawn.target.is_empty() && !spawn.target.is_valid() ) { - debugmsg( "Spawn target %s does not exist.", spawn.target.c_str() ); - abort(); - } - } - for( const weather_field &field : effect.fields ) { - if( !field.type.is_valid() ) { - debugmsg( "field type %s does not exist.", field.type.c_str() ); - abort(); - } - } - } } void weather_type::load( const JsonObject &jo, const std::string & ) @@ -182,61 +136,7 @@ void weather_type::load( const JsonObject &jo, const std::string & ) if( duration_min > duration_max ) { jo.throw_error( "duration_min must be less than or equal to duration_max" ); } - optional( jo, was_loaded, "time_between_min", time_between_min, 0_seconds ); - optional( jo, was_loaded, "time_between_max", time_between_max, 0_seconds ); - if( time_between_min > time_between_max ) { - jo.throw_error( "time_between_min must be less than or equal to time_between_max" ); - } - for( const JsonObject weather_effect_jo : jo.get_array( "effects" ) ) { - weather_effect effect; - - optional( weather_effect_jo, was_loaded, "message", effect.message ); - optional( weather_effect_jo, was_loaded, "sound_message", effect.sound_message ); - optional( weather_effect_jo, was_loaded, "sound_effect", effect.sound_effect, "" ); - mandatory( weather_effect_jo, was_loaded, "must_be_outside", effect.must_be_outside ); - optional( weather_effect_jo, was_loaded, "one_in_chance", effect.one_in_chance, -1 ); - optional( weather_effect_jo, was_loaded, "time_between", effect.time_between ); - optional( weather_effect_jo, was_loaded, "lightning", effect.lightning, false ); - optional( weather_effect_jo, was_loaded, "rain_proof", effect.rain_proof, false ); - optional( weather_effect_jo, was_loaded, "pain_max", effect.pain_max, INT_MAX ); - optional( weather_effect_jo, was_loaded, "pain", effect.pain, 0 ); - optional( weather_effect_jo, was_loaded, "wet", effect.wet, 0 ); - optional( weather_effect_jo, was_loaded, "radiation", effect.radiation, 0 ); - optional( weather_effect_jo, was_loaded, "healthy", effect.healthy, 0 ); - optional( weather_effect_jo, was_loaded, "effect_id", effect.effect_id ); - optional( weather_effect_jo, was_loaded, "effect_duration", effect.effect_duration ); - optional( weather_effect_jo, was_loaded, "trait_id_to_add", effect.trait_id_to_add ); - optional( weather_effect_jo, was_loaded, "trait_id_to_remove", effect.trait_id_to_remove ); - optional( weather_effect_jo, was_loaded, "target_part", effect.target_part ); - assign( weather_effect_jo, "damage", effect.damage ); - - for( const JsonObject field_jo : weather_effect_jo.get_array( "fields" ) ) { - weather_field new_field; - mandatory( field_jo, was_loaded, "type", new_field.type ); - mandatory( field_jo, was_loaded, "intensity", new_field.intensity ); - mandatory( field_jo, was_loaded, "age", new_field.age ); - optional( field_jo, was_loaded, "outdoor_only", new_field.outdoor_only, true ); - optional( field_jo, was_loaded, "radius", new_field.radius, 10000000 ); - - effect.fields.emplace_back( new_field ); - } - for( const JsonObject spawn_jo : weather_effect_jo.get_array( "spawns" ) ) { - spawn_type spawn; - mandatory( spawn_jo, was_loaded, "max_radius", spawn.max_radius ); - mandatory( spawn_jo, was_loaded, "min_radius", spawn.min_radius ); - if( spawn.min_radius > spawn.max_radius ) { - spawn_jo.throw_error( "min_radius must be less than or equal to max_radius" ); - } - optional( spawn_jo, was_loaded, "hallucination_count", spawn.hallucination_count, 0 ); - optional( spawn_jo, was_loaded, "real_count", spawn.real_count, 0 ); - optional( spawn_jo, was_loaded, "target", spawn.target ); - optional( spawn_jo, was_loaded, "target_range", spawn.target_range, 30 ); - - effect.spawns.emplace_back( spawn ); - } - effects.emplace_back( effect ); - } if( jo.has_member( "weather_animation" ) ) { JsonObject weather_animation_jo = jo.get_object( "weather_animation" ); mandatory( weather_animation_jo, was_loaded, "factor", weather_animation.factor ); @@ -246,35 +146,8 @@ void weather_type::load( const JsonObject &jo, const std::string & ) mandatory( weather_animation_jo, was_loaded, "sym", weather_animation.symbol, unicode_codepoint_from_symbol_reader ); } - - requirements = {}; - if( jo.has_member( "requirements" ) ) { - JsonObject weather_requires = jo.get_object( "requirements" ); - weather_requirements new_requires; - - optional( weather_requires, was_loaded, "pressure_min", new_requires.pressure_min, INT_MIN ); - optional( weather_requires, was_loaded, "pressure_max", new_requires.pressure_max, INT_MAX ); - optional( weather_requires, was_loaded, "humidity_min", new_requires.humidity_min, INT_MIN ); - optional( weather_requires, was_loaded, "humidity_max", new_requires.humidity_max, INT_MAX ); - optional( weather_requires, was_loaded, "temperature_min", new_requires.temperature_min, INT_MIN ); - optional( weather_requires, was_loaded, "temperature_max", new_requires.temperature_max, INT_MAX ); - optional( weather_requires, was_loaded, "windpower_min", new_requires.windpower_min, INT_MIN ); - optional( weather_requires, was_loaded, "windpower_max", new_requires.windpower_max, INT_MAX ); - optional( weather_requires, was_loaded, "humidity_and_pressure", new_requires.humidity_and_pressure, - true ); - optional( weather_requires, was_loaded, "time", new_requires.time, - weather_time_requirement_type::both ); - for( const std::string &required_weather : - weather_requires.get_string_array( "required_weathers" ) ) { - new_requires.required_weathers.push_back( weather_type_id( required_weather ) ); - } - optional( weather_requires, was_loaded, "time_passed_min", new_requires.time_passed_min, - 0_seconds ); - optional( weather_requires, was_loaded, "time_passed_max", new_requires.time_passed_max, - 0_seconds ); - optional( weather_requires, was_loaded, "one_in_chance", new_requires.one_in_chance, 0 ); - requirements = new_requires; - } + optional( jo, was_loaded, "required_weathers", required_weathers ); + read_condition( jo, "condition", condition, true ); } void weather_types::reset() diff --git a/src/weather_type.h b/src/weather_type.h index 0ca6d3de4fd83..d6658cf5e2a9e 100644 --- a/src/weather_type.h +++ b/src/weather_type.h @@ -13,6 +13,7 @@ #include "catacharset.h" #include "color.h" #include "damage.h" +#include "dialogue.h" #include "optional.h" #include "translations.h" #include "type_id.h" @@ -49,18 +50,7 @@ struct enum_traits { static constexpr sun_intensity_type last = sun_intensity_type::last; }; -enum class weather_time_requirement_type : int { - day, - night, - both, - last -}; -template<> -struct enum_traits { - static constexpr weather_time_requirement_type last = weather_time_requirement_type::last; -}; - -enum class weather_sound_category : int { +enum weather_sound_category : int { silent, drizzle, rainy, @@ -88,64 +78,6 @@ struct weather_animation_t { } }; -struct weather_requirements { - int windpower_min = INT_MIN; - int windpower_max = INT_MAX; - int temperature_min = INT_MIN; - int temperature_max = INT_MAX; - int pressure_min = INT_MIN; - int pressure_max = INT_MAX; - int humidity_min = INT_MIN; - int humidity_max = INT_MAX; - bool humidity_and_pressure = true; - weather_time_requirement_type time = weather_time_requirement_type::both; - std::vector required_weathers{}; - time_duration time_passed_min = 0_turns; - time_duration time_passed_max = 0_turns; - int one_in_chance = 0; -}; - -struct weather_field { - field_type_str_id type; - int intensity = 0; - time_duration age = 0_turns; - int radius = 0; - bool outdoor_only = false; -}; - -struct spawn_type { - mtype_id target; - int target_range = 0; - int hallucination_count = 0; - int real_count = 0; - int min_radius = 0; - int max_radius = 0; -}; - -struct weather_effect { - int one_in_chance = 0; - time_duration time_between = 0_turns; - translation message; - bool must_be_outside = false; - translation sound_message; - std::string sound_effect; - bool lightning = false; - bool rain_proof = false; - int pain = 0; - int pain_max = 0; - int wet = 0; - int radiation = 0; - int healthy = 0; - efftype_id effect_id; - time_duration effect_duration = 0_turns; - trait_id trait_id_to_add; - trait_id trait_id_to_remove; - bodypart_str_id target_part; - cata::optional damage; - std::vector spawns; - std::vector fields; -}; - struct weather_type { public: friend class generic_factory; @@ -175,8 +107,6 @@ struct weather_type { bool rains = false; // Whether said precipitation is acidic. bool acidic = false; - // vector for weather effects. - std::vector effects{}; // string for tiles animation std::string tiles_animation; // Information for weather animations @@ -186,11 +116,10 @@ struct weather_type { // strength of the sun sun_intensity_type sun_intensity = sun_intensity_type::none; // when this weather should happen - weather_requirements requirements; + std::function condition; + std::vector required_weathers; time_duration duration_min = 0_turns; time_duration duration_max = 0_turns; - time_duration time_between_min = 0_turns; - time_duration time_between_max = 0_turns; void load( const JsonObject &jo, const std::string &src ); void finalize(); void check() const; diff --git a/tests/weather_test.cpp b/tests/weather_test.cpp index 3b2b4bc3d28dd..30ab91c53bbbe 100644 --- a/tests/weather_test.cpp +++ b/tests/weather_test.cpp @@ -72,10 +72,10 @@ TEST_CASE( "weather realism" ) int minute = to_minutes( time_past_midnight( i ) ); temperature[day][minute] = w.temperature; int hour = to_hours( time_past_new_year( i ) ); - std::map next_instance_allowed; + *get_weather().weather_precise = w; hourly_precip[hour] += precip_mm_per_hour( - wgen.get_weather_conditions( w, next_instance_allowed )->precip ) + wgen.get_weather_conditions( w )->precip ) / 60; } From 54a1a681d4a46e078df6371609d457accaf331a8 Mon Sep 17 00:00:00 2001 From: Dekker3D Date: Tue, 23 Mar 2021 12:43:58 +0100 Subject: [PATCH 112/453] Material volume fixes (#48194) --- data/json/items/resources/plastic.json | 12 ++++-- data/json/items/resources/tailoring.json | 49 ++++++++++++++++-------- 2 files changed, 41 insertions(+), 20 deletions(-) diff --git a/data/json/items/resources/plastic.json b/data/json/items/resources/plastic.json index c1f69d6d06372..d1cc9c7d0da83 100644 --- a/data/json/items/resources/plastic.json +++ b/data/json/items/resources/plastic.json @@ -6,7 +6,8 @@ "name": { "str": "plastic chunk" }, "description": "This is a piece of plastic. It could be used to fabricate, repair, or reinforce plastic items.", "weight": "50 g", - "volume": "250 ml", + "volume": "95 ml", + "//": "Based on a density around 1.05 grams/mL, like PLA and ABS, + 100% for being rigid and probably oddly-shaped.", "price": 0, "price_postapoc": 10, "material": [ "plastic" ], @@ -21,7 +22,8 @@ "name": { "str_sp": "synthetic fabric" }, "description": "This is small bolt of synthetic fabric. Unlike you and other natural materials, it won't degrade much with age. Maybe that's less of a bad thing now.", "weight": "55 g", - "volume": "250 ml", + "volume": "50 ml", + "//": "Density of 1.15 grams per mL", "price": 0, "price_postapoc": 10, "material": [ "nylon" ], @@ -36,7 +38,8 @@ "name": { "str": "Lycra patch", "str_pl": "Lycra patches" }, "description": "This is a small bolt of a synthetic fabric blended with stretchy Lycra fibers. It could be used to make flexible yet strong clothing. Stylish, but bad for the environment; at least you're recycling it.", "weight": "87 g", - "volume": "250 ml", + "volume": "70 ml", + "//": "Density of 1.21-1.35 grams per mL, using 1.28", "price": 0, "price_postapoc": 10, "material": [ "lycra" ], @@ -51,7 +54,8 @@ "name": { "str": "plastic sheet" }, "description": "This is a large sheet of heavy flexible plastic, the sort that might have been used for commercial wrapping or for weather-sealing a home.", "weight": "1000 g", - "volume": "2 L", + "volume": "950 ml", + "//": "Based on a density around 1.05 grams/mL, like PLA and ABS", "price": 0, "price_postapoc": 25, "material": [ "plastic" ], diff --git a/data/json/items/resources/tailoring.json b/data/json/items/resources/tailoring.json index dbc468911f73c..a86c2a7508193 100644 --- a/data/json/items/resources/tailoring.json +++ b/data/json/items/resources/tailoring.json @@ -116,7 +116,8 @@ "name": { "str": "cotton sheet" }, "description": "A sheet of cotton fabric, suitable for making clothing.", "weight": "5 g", - "volume": "300 ml", + "volume": "3 ml", + "//": "Density of 1.55 grams per mL", "price": 1000, "price_postapoc": 100, "material": [ "cotton" ], @@ -132,7 +133,8 @@ "name": { "str_sp": "patchwork cotton clothing parts" }, "description": "A selection of various clothing parts, sewn together from cotton patches in a patchwork fashion. Suitable for making most clothing, though it's much less time-efficient than if using proper material sheets.", "weight": "100 g", - "volume": "60 ml", + "volume": "65 ml", + "//": "Density of 1.55 grams per mL", "price": 200, "price_postapoc": 50, "count": 1 @@ -144,7 +146,8 @@ "name": { "str": "faux fur sheet" }, "description": "A sheet of fake synthetic colorful fur, suitable for making clothing.", "weight": "10 g", - "volume": "4500 ml", + "volume": "25 ml", + "//": "Guesstimated density of 0.44 grams per mL based on felt", "price": 5000, "price_postapoc": 100, "material": [ "faux_fur" ], @@ -160,7 +163,8 @@ "name": { "str_sp": "patchwork faux fur clothing parts" }, "description": "A selection of various clothing parts, sewn together from faux fur patches in a patchwork fashion. Suitable for making most clothing, though it's much less time-efficient than if using proper material sheets.", "weight": "200 g", - "volume": "900 ml", + "volume": "450 ml", + "//": "Guesstimated density of 0.44 grams per mL based on felt", "price": 1000, "price_postapoc": 50, "count": 1 @@ -172,7 +176,8 @@ "name": { "str": "felt sheet" }, "description": "A sheet of felt, suitable for making clothing.", "weight": "8 g", - "volume": "1800 ml", + "volume": "20 ml", + "//": "Density of 0.44 grams per mL", "price": 2500, "price_postapoc": 250, "material": [ "wool" ], @@ -189,6 +194,7 @@ "description": "A selection of various clothing parts, sewn together from felt patches in a patchwork fashion. Suitable for making most clothing, though it's much less time-efficient than if using proper material sheets.", "weight": "160 g", "volume": "360 ml", + "//": "Density of 0.44 grams per mL", "price": 500, "price_postapoc": 100, "count": 1 @@ -200,7 +206,8 @@ "name": { "str": "Kevlar sheet" }, "description": "A sheet of Kevlar synthetic fabric, suitable for making cut-resistant, durable clothing. In this form, unlike rigid plates, it can be stitched.", "weight": "5 g", - "volume": "300 ml", + "volume": "4 ml", + "//": "Density of 1.4 grams per mL", "price": 900, "price_postapoc": 500, "material": [ "kevlar" ], @@ -216,7 +223,8 @@ "name": { "str": "Lycra sheet" }, "description": "A sheet of synthetic fabric blended with stretchy Lycra fibers, suitable for making flexible yet strong clothing.", "weight": "3 g", - "volume": "300 ml", + "volume": "2 ml", + "//": "Density of 1.21-1.35 grams per mL, using 1.28", "price": 5000, "price_postapoc": 100, "material": [ "lycra" ], @@ -232,7 +240,8 @@ "name": { "str": "layered kevlar panel" }, "description": "This is a small 16-layer thick Kevlar panel. It could be used to repair armor made of Kevlar.", "weight": "80 g", - "volume": "600 ml", + "volume": "65 ml", + "//": "Density of 1.4 grams per mL; volume increased ~5% to account for some rigidity", "price": 15000, "material": [ "kevlar_layered" ], "flags": [ "NO_SALVAGE" ], @@ -246,7 +255,8 @@ "name": { "str": "rigid kevlar plate" }, "description": "This is a compressed panel of Kevlar treated with epoxy or other adhesive. It could be used to repair items made of Kevlar.", "weight": "300 g", - "volume": "250 ml", + "volume": "235 ml", + "//": "Density of 1.4 grams per mL + 10% for being rigid and possibly oddly-shaped", "price": 1000, "material": [ "kevlar_rigid" ], "flags": [ "NO_SALVAGE" ], @@ -260,7 +270,8 @@ "name": { "str_sp": "patchwork Lycra clothing parts" }, "description": "A selection of various clothing parts, sewn together from Lycra patches in a patchwork fashion. Suitable for making most clothing, though it's much less time-efficient than if using proper material sheets.", "weight": "60 g", - "volume": "60 ml", + "volume": "45 ml", + "//": "Density of 1.21-1.35 grams per mL, using 1.28", "price": 1000, "price_postapoc": 50, "count": 1 @@ -272,7 +283,8 @@ "name": { "str": "neoprene sheet" }, "description": "A sheet of neoprene, a synthetic rubber, suitable for making underwater gear.", "weight": "6 g", - "volume": "300 ml", + "volume": "5 ml", + "//": "Density of 1.23 grams per mL", "price": 5000, "price_postapoc": 100, "material": [ "neoprene" ], @@ -288,7 +300,8 @@ "name": { "str_sp": "patchwork neoprene clothing parts" }, "description": "A selection of various clothing parts, sewn together from neoprene patches in a patchwork fashion, with waterproofed seams. Suitable for making most clothing, though it's much less time-efficient than if using proper material sheets.", "weight": "120 g", - "volume": "60 ml", + "volume": "100 ml", + "//": "Density of 1.23 grams per mL", "price": 1000, "price_postapoc": 50, "count": 1 @@ -300,7 +313,8 @@ "name": { "str": "Nomex sheet" }, "description": "A sheet of Nomex synthetic fabric, suitable for making heat-resistant clothing.", "weight": "5 g", - "volume": "300 ml", + "volume": "7 ml", + "//": "Density of 0.72-1.1 grams per mL, using ~0.72 to account for possible unwieldiness", "price": 15000, "price_postapoc": 250, "material": [ "nomex" ], @@ -316,7 +330,8 @@ "name": { "str_sp": "patchwork Nomex clothing parts" }, "description": "A selection of various clothing parts, sewn together with Nomex thread from Nomex patches in a patchwork fashion. Suitable for making most clothing, though it's much less time-efficient than if using proper material sheets.", "weight": "100 g", - "volume": "60 ml", + "volume": "110 ml", + "//": "Density of 0.72-1.1 grams per mL, using 0.91", "price": 3000, "price_postapoc": 50, "count": 1 @@ -328,7 +343,8 @@ "name": { "str": "synthetic fabric sheet" }, "description": "A sheet of synthetic fabric, suitable for making clothing.", "weight": "3 g", - "volume": "300 ml", + "volume": "3 ml", + "//": "Density of 1.15 grams per mL", "price": 5000, "price_postapoc": 100, "material": [ "nylon" ], @@ -344,7 +360,8 @@ "name": { "str_sp": "patchwork synthetic fabric clothing parts" }, "description": "A selection of various clothing parts, sewn together from synthetic fabric patches in a patchwork fashion. Suitable for making most clothing, though it's much less time-efficient than if using proper material sheets.", "weight": "60 g", - "volume": "60 ml", + "volume": "50 ml", + "//": "Density of 1.15 grams per mL", "price": 1000, "price_postapoc": 50, "count": 1 From 7f337688415c203c27c4db0f8b7bd31ed3852ee8 Mon Sep 17 00:00:00 2001 From: Saint-of-Grey <42332565+Saint-of-Grey@users.noreply.github.com> Date: Sun, 28 Mar 2021 00:47:10 -0700 Subject: [PATCH 113/453] Update description of LEAVES mutation line (#48215) --- data/json/mutations/mutations.json | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/data/json/mutations/mutations.json b/data/json/mutations/mutations.json index d1ed05dbb5ee6..10b1ad3e70c90 100644 --- a/data/json/mutations/mutations.json +++ b/data/json/mutations/mutations.json @@ -2526,7 +2526,7 @@ "points": 3, "visibility": 8, "ugliness": 3, - "description": "All the hair on your body has turned to long, grass-like leaves. Apart from being physically striking, these provide you with a minor amount of nutrition while in sunlight when your head is uncovered. Slightly reduces wet effects.", + "description": "All the hair on your body has turned to long, grass-like leaves. Apart from being physically striking, these provide you with a minor amount of nutrients while in sunlight when your head is uncovered. Slightly reduces wet effects.", "prereqs": [ "PLANTSKIN", "BARK" ], "changes_to": [ "LEAVES2" ], "category": [ "PLANT", "ELFA" ], @@ -2539,7 +2539,7 @@ "points": 6, "visibility": 10, "ugliness": 5, - "description": "Your leaves have grown in size and prominence, with additional leaves sprouting along your arms. While your arms and head are uncovered, you will photosynthesize additional nutrients while in sunlight. Reduces wet effects.", + "description": "Your leaves have grown in size and prominence, with additional leaves sprouting along your arms. While your arms and head are uncovered, you will photosynthesize nutrients while in sunlight. Reduces wet effects.", "prereqs": [ "LEAVES" ], "prereqs2": [ "TRANSPIRATION" ], "threshreq": [ "THRESH_PLANT" ], @@ -2555,7 +2555,7 @@ "points": 9, "visibility": 12, "ugliness": 6, - "description": "Your leaves are vibrant, large, and green, and have become a major source of nutrition for your body. Whenever your arms and head are uncovered you will gain a large amount of nutrition by standing in the sunlight. Reduces wet effects.", + "description": "Your leaves are vibrant, large, and green, and have become a major source of nutrients for your body. Whenever your arms and head are uncovered you will gain a large amount of nutrients by standing in the sunlight. Reduces wet effects.", "prereqs": [ "LEAVES2" ], "prereqs2": [ "TRANSPIRATION" ], "threshreq": [ "THRESH_PLANT" ], @@ -3165,7 +3165,7 @@ "points": -3, "visibility": 5, "ugliness": 9, - "description": "You prefer to sustain yourself using your roots and direct nutrient extraction/synthesis. You can still consume 'food', though, if you have to: you merely prefer it aged a little.", + "description": "You prefer to sustain your nutritional needs using your roots and direct nutrient extraction/synthesis. Your human parts still need the raw caloric bulk of 'food' to keep them going, though, and you handle it a lot easier if it's had time to… age a little.", "prereqs": [ "ROOTS2" ], "prereqs2": [ "LEAVES" ], "threshreq": [ "THRESH_PLANT" ], From 72974ca33d98faa682d745245f3b26034c72c5be Mon Sep 17 00:00:00 2001 From: Mark Langsdorf Date: Wed, 31 Mar 2021 02:09:51 -0500 Subject: [PATCH 114/453] monsters: Monsters on patrol (#48155) * mapgen: clean up jmapgen_monster formatting Add some whitespace and relocate some single line comments so the jmapgen_monster class looks nice on a 100 character wide screen. * monsters: pass a patrol route to a monster Add the ability to define a patrol route when placing a monster. The patrol route is defined as a series of relative mapsquare points to the original overmap terrain tile's (0,0) mapsquare and is part of the "spawn_data" structure. Patrol routes and progress along the route are saved as part of the monster's data structure. Monsters on a patrol route move on the patrol if they have nothing better to do: patrol movement takes precedence over wandering and stabling, but any valid target overrides the patrol. Monsters on a patrol will move to the next patrol point in the list. As a work-around for impassible destination points, patrol points are considered reached when the monster gets within 2 tiles of them. * monsters: document spawn_data and add patrol in mapgen.doc Document the existing spawn_data field and its ammo subfield, and add the new patrol subfield. patrol is a list of points that the monster will move between, when it would otherwise move idly. --- doc/MAPGEN.md | 26 ++++++++++++++++++++++++++ src/map.cpp | 3 +++ src/mapgen.cpp | 23 ++++++++++++++++++----- src/mapgen.h | 1 + src/monmove.cpp | 15 +++++++++++++-- src/monster.cpp | 10 ++++++++++ src/monster.h | 5 +++++ src/savegame_json.cpp | 8 ++++++++ 8 files changed, 84 insertions(+), 7 deletions(-) diff --git a/doc/MAPGEN.md b/doc/MAPGEN.md index 0724a929dc7f0..bb44511583410 100644 --- a/doc/MAPGEN.md +++ b/doc/MAPGEN.md @@ -543,6 +543,7 @@ Value: `[ array of {objects} ]: [ { "monster": ... } ]` | friendly | Set true to make the monster friendly. Default false. | name | Extra name to display on the monster. | target | Set to true to make this into mission target. Only works when the monster is spawned from a mission. +| spawn_data | An optional object that contains additional details for spawning the monster. Note that high spawn density game setting can cause extra monsters to spawn when `monster` is used. When `group` is used only one monster will spawn. @@ -572,6 +573,31 @@ Example: This places "mon_secubot" at random coordinate (7-18, 7-18). The monster is placed with 30% probability. The placement is repeated by random number of times `[1-3]`. The monster will spawn with 20-30 5.56x45mm rounds. +### "spawn_data" for monsters +This optional object can have two fields: +| Field | Description +| --- | --- +| ammo | A list of objects, each of which has an `"ammo_id"` field and a `"qty"` list of two integers. The monster will spawn with items of "ammo_id", with at least the first number in the "qty" and no more than the second. +| patrol | A list of objects, each of which has an `"x"` field and a `"y"` field. Either value can be a range or a single number. The x,y co-ordinates define a patrol point as an relative mapsquare point offset from the (0, 0) local mapsquare of the overmap terrain tile that the monster spawns in. Patrol points are converted to absolute mapqaure tripoints inside the monster generator. + +Monsters with a patrol point list will move to each patrol point, in order, whenever they have no more pressing action to take on their turn. Upon reaching the last point in the patrol point list, the monster will continue on to the first point in the list. + +Example: +```json +"place_monster": [ + { "monster": "mon_zombie", "x": 12, "y": 12, "spawn_data": { "patrol": [ { "x": 12, "y": 12 } ] } } +] +``` + +This places a "mon_zombie" at (12, 12). The zombie can move freely to chase after enemies, but will always return to the (12, 12) position if it has nothing else to do. + +Example 2: +```json +"place_monster": [ + { "monster": "mon_secubot", "x": 12, "y": 12, "spawn_data": { "ammo": [ { "ammo_id": "556", "qty": [ 20, 30 ] } ], "patrol": [ { "x": -23, "y": -23 }, { "x": 47, "y": -23 }, { "x": 47, "y": 47 }, { "x": 47, "y": -23 } ] } } +] +``` +This places a "mon_secubot" at (12,12). It will patrol the four outmost concerns of the diagonally adjacent overmap terrain tiles in a box pattern. ## Spawn specific items with a "place_item" array **optional** A list of *specific* things to add. WIP: Monsters and vehicles will be here too diff --git a/src/map.cpp b/src/map.cpp index 5125e6f4ec4d2..337777cb37aee 100644 --- a/src/map.cpp +++ b/src/map.cpp @@ -7595,6 +7595,9 @@ void map::spawn_monsters_submap( const tripoint &gp, bool ignore_sight ) const auto place_it = [&]( const tripoint & p ) { monster *const placed = g->place_critter_at( make_shared_fast( tmp ), p ); + if( !i.data.patrol_points_rel_ms.empty() ) { + placed->set_patrol_route( i.data.patrol_points_rel_ms ); + } if( placed ) { placed->on_load(); } diff --git a/src/mapgen.cpp b/src/mapgen.cpp index 03646c4ae5e30..664aada2e175b 100644 --- a/src/mapgen.cpp +++ b/src/mapgen.cpp @@ -1278,7 +1278,8 @@ class jmapgen_monster : public jmapgen_piece chance( jsi, "chance", 100, 100 ) , pack_size( jsi, "pack_size", 1, 1 ) , one_or_none( jsi.get_bool( "one_or_none", - !( jsi.has_member( "repeat" ) || jsi.has_member( "pack_size" ) ) ) ) + !( jsi.has_member( "repeat" ) || + jsi.has_member( "pack_size" ) ) ) ) , friendly( jsi.get_bool( "friendly", false ) ) , name( jsi.get_string( "name", "NONE" ) ) , target( jsi.get_bool( "target", false ) ) { @@ -1319,7 +1320,16 @@ class jmapgen_monster : public jmapgen_piece if( sd.has_array( "ammo" ) ) { const JsonArray &ammos = sd.get_array( "ammo" ); for( const JsonObject adata : ammos ) { - data.ammo.emplace( itype_id( adata.get_string( "ammo_id" ) ), jmapgen_int( adata, "qty" ) ); + data.ammo.emplace( itype_id( adata.get_string( "ammo_id" ) ), + jmapgen_int( adata, "qty" ) ); + } + } + if( sd.has_array( "patrol" ) ) { + const JsonArray &patrol_pts = sd.get_array( "patrol" ); + for( const JsonObject p_pt : patrol_pts ) { + jmapgen_int ptx = jmapgen_int( p_pt, "x" ); + jmapgen_int pty = jmapgen_int( p_pt, "y" ); + data.patrol_points_rel_ms.push_back( point( ptx.get(), pty.get() ) ); } } } @@ -1329,7 +1339,8 @@ class jmapgen_monster : public jmapgen_piece int raw_odds = chance.get(); - // Handle spawn density: Increase odds, but don't let the odds of absence go below half the odds at density 1. + // Handle spawn density: Increase odds, but don't let the odds of absence go below + // half the odds at density 1. // Instead, apply a multiplier to the number of monsters for really high densities. // For example, a 50% chance at spawn density 4 becomes a 75% chance of ~2.7 monsters. int odds_after_density = raw_odds * get_option( "SPAWN_DENSITY" ); @@ -1347,10 +1358,12 @@ class jmapgen_monster : public jmapgen_piece int spawn_count = roll_remainder( density_multiplier ); - if( one_or_none ) { // don't let high spawn density alone cause more than 1 to spawn. + // don't let high spawn density alone cause more than 1 to spawn. + if( one_or_none ) { spawn_count = std::min( spawn_count, 1 ); } - if( raw_odds == 100 ) { // don't spawn less than 1 if odds were 100%, even with low spawn density. + // don't spawn less than 1 if odds were 100%, even with low spawn density. + if( raw_odds == 100 ) { spawn_count = std::max( spawn_count, 1 ); } else { if( !x_in_y( odds_after_density, 100 ) ) { diff --git a/src/mapgen.h b/src/mapgen.h index 7767c4ddc683a..6a1b0b4cbcb70 100644 --- a/src/mapgen.h +++ b/src/mapgen.h @@ -130,6 +130,7 @@ struct jmapgen_setmap { struct spawn_data { std::map ammo; + std::vector patrol_points_rel_ms; }; /** diff --git a/src/monmove.cpp b/src/monmove.cpp index f6e9f57d51bdc..21644a2101bb8 100644 --- a/src/monmove.cpp +++ b/src/monmove.cpp @@ -77,7 +77,7 @@ static constexpr int MONSTER_FOLLOW_DIST = 8; bool monster::wander() { - return ( goal == pos() ); + return ( goal == pos() && patrol_route_abs_ms.empty() ); } bool monster::is_immune_field( const field_type_id &fid ) const @@ -619,6 +619,17 @@ void monster::plan() anger += 10 - static_cast( hp_per / 10 ); } } + } else if( !patrol_route_abs_ms.empty() ) { + // If we have a patrol route and no target, find the current step on the route + tripoint next_stop_loc_ms = here.getlocal( patrol_route_abs_ms.at( next_patrol_point ) ); + + // if there is more than one patrol point, advance to the next one if we're almost there + // this handles impassable obstancles but patrollers can still get stuck + if( ( patrol_route_abs_ms.size() > 1 ) && rl_dist( next_stop_loc_ms, pos() ) < 2 ) { + next_patrol_point = ( next_patrol_point + 1 ) % patrol_route_abs_ms.size(); + next_stop_loc_ms = here.getlocal( patrol_route_abs_ms.at( next_patrol_point ) ); + } + set_dest( next_stop_loc_ms ); } else if( friendly > 0 && one_in( 3 ) ) { // Grow restless with no targets friendly--; @@ -841,7 +852,7 @@ void monster::move() } } - if( current_attitude == MATT_IGNORE || + if( ( current_attitude == MATT_IGNORE && patrol_route_abs_ms.empty() ) || ( current_attitude == MATT_FOLLOW && rl_dist( pos(), goal ) <= MONSTER_FOLLOW_DIST ) ) { moves = 0; stumble(); diff --git a/src/monster.cpp b/src/monster.cpp index edca5c9df481b..991485db63c6b 100644 --- a/src/monster.cpp +++ b/src/monster.cpp @@ -1076,6 +1076,16 @@ void monster::set_goal( const tripoint &p ) goal = p; } +void monster::set_patrol_route( const std::vector &patrol_pts_rel_ms ) +{ + map &here = get_map(); + tripoint base_abs_ms( real_coords( here.getabs( pos().xy() ) ).begin_om_pos(), posz() ); + for( const point &patrol_pt : patrol_pts_rel_ms ) { + patrol_route_abs_ms.push_back( base_abs_ms + patrol_pt ); + } + next_patrol_point = 0; +} + void monster::shift( const point &sm_shift ) { const point ms_shift = sm_to_ms_copy( sm_shift ); diff --git a/src/monster.h b/src/monster.h index 07450a8c51438..0297d4b3e4322 100644 --- a/src/monster.h +++ b/src/monster.h @@ -178,6 +178,7 @@ class monster : public Creature // Movement void shift( const point &sm_shift ); // Shifts the monster to the appropriate submap void set_goal( const tripoint &p ); + void set_patrol_route( const std::vector &patrol_pts_rel_ms ); // Updates current pos AND our plans bool wander(); // Returns true if we have no plans @@ -572,6 +573,10 @@ class monster : public Creature monster_horde_attraction horde_attraction = MHA_NULL; /** Found path. Note: Not used by monsters that don't pathfind! **/ std::vector path; + /** patrol points for monsters that can pathfind and have a patrol route! **/ + std::vector patrol_route_abs_ms; + int next_patrol_point = -1; + std::bitset effect_cache; cata::optional summon_time_limit = cata::nullopt; int turns_since_target = 0; diff --git a/src/savegame_json.cpp b/src/savegame_json.cpp index 0230396e9c70a..fa9df07486e89 100644 --- a/src/savegame_json.cpp +++ b/src/savegame_json.cpp @@ -2100,6 +2100,10 @@ void monster::load( const JsonObject &data ) if( data.read( "wandz", wander_pos.z ) ) { wander_pos.z = position.z; } + if( data.has_int( "next_patrol_point" ) ) { + data.read( "next_patrol_point", next_patrol_point ); + data.read( "patrol_route", patrol_route_abs_ms ); + } if( data.has_object( "tied_item" ) ) { JsonIn *tied_item_json = data.get_raw( "tied_item" ); item newitem; @@ -2251,6 +2255,10 @@ void monster::store( JsonOut &json ) const json.member( "wandy", wander_pos.y ); json.member( "wandz", wander_pos.z ); json.member( "wandf", wandf ); + if( !patrol_route_abs_ms.empty() ) { + json.member( "patrol_route", patrol_route_abs_ms ); + json.member( "next_patrol_point", next_patrol_point ); + } json.member( "hp", hp ); json.member( "special_attacks", special_attacks ); json.member( "friendly", friendly ); From 3845305112f6a35544649845eb2aa77b82774d6f Mon Sep 17 00:00:00 2001 From: zeropol Date: Wed, 31 Mar 2021 09:51:56 +0200 Subject: [PATCH 115/453] Make gym furniture constructible (#48271) --- data/json/construction.json | 45 +++++++++++++++++++++++++++++++ data/json/construction_group.json | 15 +++++++++++ 2 files changed, 60 insertions(+) diff --git a/data/json/construction.json b/data/json/construction.json index df165bd231bfc..e4ce08cf227ef 100644 --- a/data/json/construction.json +++ b/data/json/construction.json @@ -4272,6 +4272,51 @@ "pre_terrain": "t_railroad_rubble", "post_terrain": "t_dirt" }, + { + "type": "construction", + "id": "constr_exercise_machine", + "group": "build_exercise_machine", + "category": "FURN", + "required_skills": [ [ "fabrication", 3 ] ], + "time": "180 m", + "qualities": [ [ { "id": "HAMMER", "level": 2 } ], [ { "id": "SCREW", "level": 1 } ] ], + "components": [ [ [ "pipe", 1 ] ], [ [ "steel_chunk", 1 ] ], [ [ "scrap", 6 ] ], [ [ "lead", 2000 ] ] ], + "pre_special": "check_empty", + "post_terrain": "f_exercise" + }, + { + "type": "construction", + "id": "constr_ergometer_mechanical", + "group": "build_ergometer_mechanical", + "category": "FURN", + "required_skills": [ [ "fabrication", 4 ] ], + "time": "240 m", + "qualities": [ [ { "id": "HAMMER", "level": 2 } ], [ { "id": "SCREW", "level": 1 } ], [ { "id": "WRENCH", "level": 1 } ] ], + "components": [ + [ [ "foot_crank", 1 ] ], + [ [ "plastic_chunk", 10 ] ], + [ [ "scrap", 4 ] ], + [ [ "chain", 1 ] ], + [ [ "pipe", 5 ] ], + [ [ "saddle", 1 ] ], + [ [ "wheel_small", 1 ] ], + [ [ "nail", 8 ] ] + ], + "pre_special": "check_empty", + "post_terrain": "f_ergometer_mechanical" + }, + { + "type": "construction", + "id": "constr_treadmill_mechanical", + "group": "build_treadmill_mechanical", + "category": "FURN", + "required_skills": [ [ "fabrication", 4 ] ], + "time": "240 m", + "qualities": [ [ { "id": "HAMMER", "level": 2 } ], [ { "id": "SCREW", "level": 1 } ], [ { "id": "WRENCH", "level": 1 } ] ], + "components": [ [ [ "plastic_chunk", 14 ] ], [ [ "scrap", 10 ] ], [ [ "pipe", 6 ] ], [ [ "nail", 8 ] ] ], + "pre_special": "check_empty", + "post_terrain": "f_treadmill_mechanical" + }, { "type": "construction", "id": "constr_glass_wall", diff --git a/data/json/construction_group.json b/data/json/construction_group.json index 5495ebfb62d93..e70f44cdf54a2 100644 --- a/data/json/construction_group.json +++ b/data/json/construction_group.json @@ -259,6 +259,11 @@ "id": "build_entertainment_center", "name": "Build Entertainment Center" }, + { + "type": "construction_group", + "id": "build_exercise_machine", + "name": "Build Exercise Machine" + }, { "type": "construction_group", "id": "build_fence", @@ -284,6 +289,11 @@ "id": "build_fire_ring", "name": "Build Fire Ring" }, + { + "type": "construction_group", + "id": "build_treadmill_mechanical", + "name": "Build Gravity Treadmill" + }, { "type": "construction_group", "id": "build_glass_door", @@ -359,6 +369,11 @@ "id": "build_makeshift_door", "name": "Build Makeshift Door" }, + { + "type": "construction_group", + "id": "build_ergometer_mechanical", + "name": "Build Mechanical Ergometer" + }, { "type": "construction_group", "id": "build_metal_bars", From 79d224dc559268c6b54a217dfd8ad75f187180bb Mon Sep 17 00:00:00 2001 From: Maleclypse <54345792+Maleclypse@users.noreply.github.com> Date: Wed, 31 Mar 2021 02:52:44 -0500 Subject: [PATCH 116/453] Add Red Concrete (#48242) Co-authored-by: Binrui Dong --- .../furniture_and_terrain/terrain-floors-indoor.json | 12 ++++++++++++ 1 file changed, 12 insertions(+) diff --git a/data/json/furniture_and_terrain/terrain-floors-indoor.json b/data/json/furniture_and_terrain/terrain-floors-indoor.json index a28bdf373e96f..8af1e8d7a55ea 100644 --- a/data/json/furniture_and_terrain/terrain-floors-indoor.json +++ b/data/json/furniture_and_terrain/terrain-floors-indoor.json @@ -46,6 +46,18 @@ ] } }, + { + "type": "terrain", + "id": "t_thconc_r", + "name": "concrete floor", + "description": "A bare and cold concrete floor with a streak of red paint, could still insulate from the outdoors but roof collapse is possible if supporting walls are broken down.", + "symbol": ".", + "color": "red", + "looks_like": "t_floor_red", + "move_cost": 2, + "roof": "t_flat_roof", + "copy-from": "t_thconc_floor" + }, { "type": "terrain", "id": "t_thconc_floor_olight", From 40d4064c27526dc8658bce38ae660ecd9bfb9937 Mon Sep 17 00:00:00 2001 From: Alexey Mostovoy <1931904+AMurkin@users.noreply.github.com> Date: Wed, 31 Mar 2021 13:25:24 +0300 Subject: [PATCH 117/453] Fix typo --- doc/MAPGEN.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/doc/MAPGEN.md b/doc/MAPGEN.md index bb44511583410..84567b35cb1aa 100644 --- a/doc/MAPGEN.md +++ b/doc/MAPGEN.md @@ -578,7 +578,7 @@ This optional object can have two fields: | Field | Description | --- | --- | ammo | A list of objects, each of which has an `"ammo_id"` field and a `"qty"` list of two integers. The monster will spawn with items of "ammo_id", with at least the first number in the "qty" and no more than the second. -| patrol | A list of objects, each of which has an `"x"` field and a `"y"` field. Either value can be a range or a single number. The x,y co-ordinates define a patrol point as an relative mapsquare point offset from the (0, 0) local mapsquare of the overmap terrain tile that the monster spawns in. Patrol points are converted to absolute mapqaure tripoints inside the monster generator. +| patrol | A list of objects, each of which has an `"x"` field and a `"y"` field. Either value can be a range or a single number. The x,y co-ordinates define a patrol point as an relative mapsquare point offset from the (0, 0) local mapsquare of the overmap terrain tile that the monster spawns in. Patrol points are converted to absolute mapsquare tripoints inside the monster generator. Monsters with a patrol point list will move to each patrol point, in order, whenever they have no more pressing action to take on their turn. Upon reaching the last point in the patrol point list, the monster will continue on to the first point in the list. From eca4d85ab673755df73e4f17448b0a059c5ff27a Mon Sep 17 00:00:00 2001 From: zeropol Date: Thu, 1 Apr 2021 03:58:53 +0200 Subject: [PATCH 118/453] Filter items by book skill ( V, e, / ), fixes #47530 (#48275) * Add a filter to search books by skills they teach * Hide books not skimmed when filtering items The player was able to know which skill a book tech without first skim it. * Fix typographic error * Check non-skill by ID name() is i18n-dependent and it may return something other than "nothing" in different languages. Co-authored-by: Binrui Dong --- src/item.cpp | 10 ++++++++++ src/item.h | 2 ++ src/item_search.cpp | 10 ++++++++++ src/output.cpp | 5 +++-- 4 files changed, 25 insertions(+), 2 deletions(-) diff --git a/src/item.cpp b/src/item.cpp index 012a7e7d8f17b..5bac244aa48bb 100644 --- a/src/item.cpp +++ b/src/item.cpp @@ -7099,6 +7099,16 @@ bool item::is_book() const return !!type->book; } +std::string item::get_book_skill() const +{ + if( is_book() ) { + if( type->book->skill->ident() != skill_id::NULL_ID() ) { + return type->book->skill->name(); + } + } + return ""; +} + bool item::is_map() const { return get_category_shallow().get_id() == item_category_maps; diff --git a/src/item.h b/src/item.h index 9569cade94e2c..75ccd1f5c0602 100644 --- a/src/item.h +++ b/src/item.h @@ -1243,6 +1243,8 @@ class item : public visitable /** Returns true if the item is A: is SOLID and if it B: is of type LIQUID */ bool is_frozen_liquid() const; + /** Returns empty string if the book teach no skill */ + std::string get_book_skill() const; float get_specific_heat_liquid() const; float get_specific_heat_solid() const; float get_latent_heat() const; diff --git a/src/item_search.cpp b/src/item_search.cpp index fd6b92bd44d22..04ff020e4a3e0 100644 --- a/src/item_search.cpp +++ b/src/item_search.cpp @@ -3,7 +3,9 @@ #include #include +#include "avatar.h" #include "cata_utility.h" +#include "game.h" #include "item.h" #include "item_category.h" #include "material.h" @@ -68,6 +70,14 @@ std::function basic_item_filter( std::string filter ) const std::string note = i.get_var( "item_note" ); return !note.empty() && lcmatch( note, filter ); }; + // by book skill + case 's': + return [filter]( const item & i ) { + if( get_avatar().has_identified( i.typeId() ) ) { + return lcmatch( i.get_book_skill(), filter ); + } + return false; + }; // by name default: return [filter]( const item & a ) { diff --git a/src/output.cpp b/src/output.cpp index cdd163a12ce1f..545cbf00c5e07 100644 --- a/src/output.cpp +++ b/src/output.cpp @@ -870,11 +870,12 @@ void draw_item_filter_rules( const catacurses::window &win, int starty, int heig starty += fold_and_print( win, point( 1, starty ), len, c_white, _( "Search [c]ategory, [m]aterial, " - "[q]uality, [n]otes or " + "[q]uality, [n]otes, " + "[s]skill taught by books or " "[d]isassembled components." ) ); fold_and_print( win, point( 1, starty ), len, c_white, //~ An example of how to filter items based on category or material. - _( "Examples: c:food,m:iron,q:hammering,n:toolshelf,d:pipe" ) ); + _( "Examples: c:food,m:iron,q:hammering,n:toolshelf,d:pipe,s:devices" ) ); wnoutrefresh( win ); } From 1a76c290ca2921766b4ce9b4e2739ef0a61433eb Mon Sep 17 00:00:00 2001 From: MarlossCDDA <78324429+MarlossCDDA@users.noreply.github.com> Date: Wed, 31 Mar 2021 22:30:27 -0400 Subject: [PATCH 119/453] Replace "two-by-four" with "plank" in user-facing strings (#47709) * s/two by four/plank there are still some translations that refer to "two by" "four" across two lines, leaving those alone for now because I'm lazy * fix id in doc/VEHICLES_JSON.md, revert translation changes --- .../furniture_and_terrain/terrain-doors.json | 36 +++++++++---------- .../furniture_and_terrain/terrain-traps.json | 6 ++-- .../furniture_and_terrain/terrain-walls.json | 4 +-- .../terrain-windows.json | 6 ++-- data/json/items/armor/arms_armor.json | 2 +- data/json/items/armor/legs_armor.json | 2 +- data/json/items/melee/swords_and_blades.json | 2 +- data/json/items/tool/workshop.json | 2 +- data/json/items/vehicle/plating.json | 2 +- data/json/npcs/Backgrounds/evacuee_5.json | 2 +- data/json/npcs/Backgrounds/no_past_4.json | 2 +- data/json/npcs/hints.json | 2 +- doc/GAME_BALANCE.md | 2 +- doc/VEHICLES_JSON.md | 2 +- src/crafting_gui.cpp | 2 +- src/map.cpp | 2 +- tests/melee_test.cpp | 4 +-- 17 files changed, 40 insertions(+), 40 deletions(-) diff --git a/data/json/furniture_and_terrain/terrain-doors.json b/data/json/furniture_and_terrain/terrain-doors.json index 3e4b6dcae7243..99b668a838b34 100644 --- a/data/json/furniture_and_terrain/terrain-doors.json +++ b/data/json/furniture_and_terrain/terrain-doors.json @@ -578,7 +578,7 @@ "type": "terrain", "id": "t_door_white_b", "name": "damaged wood door", - "description": "A trashed wooden door, that is more of an obstacle than a door. Also, you can see right through it. It could be boarded up with a few two by fours.", + "description": "A trashed wooden door, that is more of an obstacle than a door. Also, you can see right through it. It could be boarded up with a few planks.", "symbol": "&", "looks_like": "t_door_b", "color": "brown", @@ -614,7 +614,7 @@ "type": "terrain", "id": "t_door_gray_b", "name": "damaged wood door", - "description": "A trashed wooden door, that is more of an obstacle than a door. Also, you can see right through it. It could be boarded up with a few two by fours.", + "description": "A trashed wooden door, that is more of an obstacle than a door. Also, you can see right through it. It could be boarded up with a few planks.", "symbol": "&", "looks_like": "t_door_b", "color": "brown", @@ -650,7 +650,7 @@ "type": "terrain", "id": "t_door_red_b", "name": "damaged wood door", - "description": "A trashed wooden door, that is more of an obstacle than a door. Also, you can see right through it. It could be boarded up with a few two by fours.", + "description": "A trashed wooden door, that is more of an obstacle than a door. Also, you can see right through it. It could be boarded up with a few planks.", "symbol": "&", "looks_like": "t_door_b", "color": "brown", @@ -686,7 +686,7 @@ "type": "terrain", "id": "t_door_green_b", "name": "damaged wood door", - "description": "A trashed wooden door, that is more of an obstacle than a door. Also, you can see right through it. It could be boarded up with a few two by fours.", + "description": "A trashed wooden door, that is more of an obstacle than a door. Also, you can see right through it. It could be boarded up with a few planks.", "symbol": "&", "looks_like": "t_door_b", "color": "brown", @@ -722,7 +722,7 @@ "type": "terrain", "id": "t_door_white_frame", "name": "empty door frame", - "description": "An empty door frame made from two by fours and nails. A variety of doors could be constructed here.", + "description": "An empty door frame made from planks and nails. A variety of doors could be constructed here.", "symbol": ".", "looks_like": "t_door_frame", "color": "brown", @@ -747,7 +747,7 @@ "type": "terrain", "id": "t_door_gray_frame", "name": "empty door frame", - "description": "An empty door frame made from two by fours and nails. A variety of doors could be constructed here.", + "description": "An empty door frame made from planks and nails. A variety of doors could be constructed here.", "symbol": ".", "looks_like": "t_door_frame", "color": "brown", @@ -772,7 +772,7 @@ "type": "terrain", "id": "t_door_red_frame", "name": "empty door frame", - "description": "An empty door frame made from two by fours and nails. A variety of doors could be constructed here.", + "description": "An empty door frame made from planks and nails. A variety of doors could be constructed here.", "symbol": ".", "looks_like": "t_door_frame", "color": "brown", @@ -797,7 +797,7 @@ "type": "terrain", "id": "t_door_green_frame", "name": "empty door frame", - "description": "An empty door frame made from two by fours and nails. A variety of doors could be constructed here.", + "description": "An empty door frame made from planks and nails. A variety of doors could be constructed here.", "symbol": ".", "looks_like": "t_door_frame", "color": "brown", @@ -1053,7 +1053,7 @@ "type": "terrain", "id": "t_door_b", "name": "damaged wood door", - "description": "A trashed wooden door, that is more of an obstacle than a door. Also, you can see right through it. It could be boarded up with a few two by fours.", + "description": "A trashed wooden door, that is more of an obstacle than a door. Also, you can see right through it. It could be boarded up with a few planks.", "symbol": "&", "looks_like": "t_door_c", "color": "brown", @@ -1089,7 +1089,7 @@ "type": "terrain", "id": "t_door_lab_b", "name": "damaged wood door", - "description": "A trashed wooden door, that is more of an obstacle than a door. Also, you can see right through it. It could be boarded up with a few two by fours.", + "description": "A trashed wooden door, that is more of an obstacle than a door. Also, you can see right through it. It could be boarded up with a few planks.", "symbol": "&", "looks_like": "t_door_b", "color": "brown", @@ -1274,7 +1274,7 @@ "type": "terrain", "id": "t_rdoor_c", "name": "closed reinforced wood door", - "description": "Just like other wooden doors, except this one has layers of nailed in two by fours and additional hinge for reinforcement. It might be barricaded, but still susceptible to fire.", + "description": "Just like other wooden doors, except this one has layers of nailed in planks and additional hinge for reinforcement. It might be barricaded, but still susceptible to fire.", "symbol": "+", "looks_like": "t_door_c", "color": "red", @@ -1347,7 +1347,7 @@ "type": "terrain", "id": "t_rdoor_o", "name": "open reinforced wood door", - "description": "Just like other wooden doors, except this one has layers of nailed in two by fours for reinforcement. It might be fortified, but still susceptible to fire. It's open so it's not stopping anything right now.", + "description": "Just like other wooden doors, except this one has layers of nailed in planks for reinforcement. It might be fortified, but still susceptible to fire. It's open so it's not stopping anything right now.", "symbol": "'", "looks_like": "t_door_o", "color": "red", @@ -1574,7 +1574,7 @@ "type": "terrain", "id": "t_door_makeshift_c", "name": "closed makeshift door", - "description": "A makeshift screen consisting of two by fours bound together with vertical rope hanging from the top of the doorway. Could be easily taken down and re-purposed.", + "description": "A makeshift screen consisting of planks bound together with vertical rope hanging from the top of the doorway. Could be easily taken down and re-purposed.", "symbol": "+", "looks_like": "t_door_c", "color": "brown", @@ -1636,7 +1636,7 @@ "type": "terrain", "id": "t_door_makeshift_o", "name": "open makeshift door", - "description": "A makeshift screen consisting of two by fours bound together with rope hanging from the top of the doorway. Could be easily taken down and re-purposed. The planks have been rolled up and attached to the top of the doorway, allowing free movement through.", + "description": "A makeshift screen consisting of planks bound together with rope hanging from the top of the doorway. Could be easily taken down and re-purposed. The planks have been rolled up and attached to the top of the doorway, allowing free movement through.", "symbol": "'", "looks_like": "t_door_o", "color": "brown", @@ -1665,7 +1665,7 @@ "type": "terrain", "id": "t_door_frame", "name": "empty door frame", - "description": "An empty door frame made from two by fours and nails. A variety of doors could be constructed here.", + "description": "An empty door frame made from planks and nails. A variety of doors could be constructed here.", "symbol": ".", "looks_like": "t_floor", "color": "brown", @@ -1690,7 +1690,7 @@ "type": "terrain", "id": "t_door_lab_frame", "name": "empty door frame", - "description": "An empty door frame made from two by fours and nails. A variety of doors could be constructed here.", + "description": "An empty door frame made from planks and nails. A variety of doors could be constructed here.", "symbol": ".", "looks_like": "t_door_frame", "color": "brown", @@ -1859,7 +1859,7 @@ "type": "terrain", "id": "t_rdoor_boarded", "name": "boarded up reinforced door", - "description": "An additionally reinforced door of layered two by fours that has been boarded up with more wood to prevent it from opening. Still susceptible to fire.", + "description": "An additionally reinforced door of layered planks that has been boarded up with more wood to prevent it from opening. Still susceptible to fire.", "symbol": "#", "looks_like": "t_door_boarded", "color": "brown", @@ -1887,7 +1887,7 @@ "type": "terrain", "id": "t_rdoor_boarded_damaged", "name": "boarded up damaged reinforced door", - "description": "A battered and torn reinforced door with planks bursting from the joints. The boarded up two by fours are fragmented and in pieces, this doesn't look like an easy repair.", + "description": "A battered and torn reinforced door with planks bursting from the joints. The boarded up planks are fragmented and in pieces, this doesn't look like an easy repair.", "symbol": "#", "looks_like": "t_door_b", "color": "brown", diff --git a/data/json/furniture_and_terrain/terrain-traps.json b/data/json/furniture_and_terrain/terrain-traps.json index 6d6d564d03819..698951e420b17 100644 --- a/data/json/furniture_and_terrain/terrain-traps.json +++ b/data/json/furniture_and_terrain/terrain-traps.json @@ -50,7 +50,7 @@ "type": "terrain", "id": "t_pit_covered", "name": "covered pit", - "description": "A deep pit with a two by four placed across it, looks sturdy enough to cross safely or the plank could be removed to turn it back into trap fall.", + "description": "A deep pit with a plank placed across it, looks sturdy enough to cross safely or the plank could be removed to turn it back into trap fall.", "symbol": "#", "color": "light_red", "move_cost": 2, @@ -75,7 +75,7 @@ "type": "terrain", "id": "t_pit_spiked_covered", "name": "covered spiked pit", - "description": "Menacing with sharp spears along the bottom, this pit has a plank across it to allow someone or something to cross safely. The two by four could be removed to revert it back into a trap.", + "description": "Menacing with sharp spears along the bottom, this pit has a plank across it to allow someone or something to cross safely. The plank could be removed to revert it back into a trap.", "symbol": "#", "color": "light_red", "move_cost": 2, @@ -100,7 +100,7 @@ "type": "terrain", "id": "t_pit_glass_covered", "name": "covered glass pit", - "description": "A two by four has been placed carefully to allow traversal over this ditch full of large glass shards. The wooden board could be removed so it couldn't be safely crossed.", + "description": "A plank has been placed carefully to allow traversal over this ditch full of large glass shards. The wooden board could be removed so it couldn't be safely crossed.", "symbol": "#", "color": "light_cyan", "move_cost": 2, diff --git a/data/json/furniture_and_terrain/terrain-walls.json b/data/json/furniture_and_terrain/terrain-walls.json index f88f870d7d403..488e38d1d221d 100644 --- a/data/json/furniture_and_terrain/terrain-walls.json +++ b/data/json/furniture_and_terrain/terrain-walls.json @@ -40,7 +40,7 @@ "id": "t_wall_half", "name": "half-built wall", "looks_like": "t_wall", - "description": "An incomplete wall of refined wood, dotted with carefully placed nails to provide proper support. It requires some more two by fours and nails before it'd be considered a suitable wall.", + "description": "An incomplete wall of refined wood, dotted with carefully placed nails to provide proper support. It requires some more planks and nails before it'd be considered a suitable wall.", "symbol": "#", "color": "light_red", "move_cost": 4, @@ -649,7 +649,7 @@ "id": "t_wall_wood_chipped", "name": "chipped wood wall", "looks_like": "t_wall_wood", - "description": "A wall of aligned two by fours that's starting to crack and break open. Some cut wood and a number of nails could patch this up quick.", + "description": "A wall of aligned planks that's starting to crack and break open. Some cut wood and a number of nails could patch this up quick.", "symbol": "LINE_OXOX", "color": "light_red", "move_cost": 0, diff --git a/data/json/furniture_and_terrain/terrain-windows.json b/data/json/furniture_and_terrain/terrain-windows.json index 9eef738b9a488..e81066dd1aba7 100644 --- a/data/json/furniture_and_terrain/terrain-windows.json +++ b/data/json/furniture_and_terrain/terrain-windows.json @@ -341,7 +341,7 @@ "id": "t_window_empty", "name": "empty window", "roof": "t_flat_roof", - "description": "An empty window frame consisting of two by fours and nails. You could install a sheet of glass, or even board it up for protection. You could also convert it into a wall if you took the time to construct it.", + "description": "An empty window frame consisting of planks and nails. You could install a sheet of glass, or even board it up for protection. You could also convert it into a wall if you took the time to construct it.", "symbol": "0", "color": "yellow", "move_cost": 4, @@ -396,7 +396,7 @@ "type": "terrain", "id": "t_window_boarded", "name": "boarded up window", - "description": "A glass window that has been covered with nailed down planks, blocking sunlight and visibility. It's not much stronger, but it could be further reinforced with strategically placed two by fours.", + "description": "A glass window that has been covered with nailed down planks, blocking sunlight and visibility. It's not much stronger, but it could be further reinforced with strategically placed planks.", "symbol": "#", "color": "brown", "move_cost": 0, @@ -419,7 +419,7 @@ "id": "t_window_boarded_noglass", "name": "boarded up window", "looks_like": "t_window_boarded", - "description": "An empty window frame that has been covered with nailed down planks, blocking sunlight and visibility. It's not much stronger, but it could be further reinforced with strategically placed two by fours.", + "description": "An empty window frame that has been covered with nailed down planks, blocking sunlight and visibility. It's not much stronger, but it could be further reinforced with strategically placed planks.", "symbol": "#", "color": "brown", "move_cost": 0, diff --git a/data/json/items/armor/arms_armor.json b/data/json/items/armor/arms_armor.json index 4bee254520558..19abbbf64451e 100644 --- a/data/json/items/armor/arms_armor.json +++ b/data/json/items/armor/arms_armor.json @@ -4,7 +4,7 @@ "type": "ARMOR", "category": "armor", "name": { "str": "pair of 2-by-arm guards", "str_pl": "pairs of 2-by-arm guards" }, - "description": "A pair of improvised arm guards made from broken pieces of a two by four that are tied to your arms with rags and string. They offer good protection, but are really uncomfortable to wear.", + "description": "A pair of improvised arm guards made from broken pieces of a plank that are tied to your arms with rags and string. They offer good protection, but are really uncomfortable to wear.", "weight": "300 g", "volume": "1500 ml", "price": 500, diff --git a/data/json/items/armor/legs_armor.json b/data/json/items/armor/legs_armor.json index 3befa36a1ca9e..045001ad7fd5e 100644 --- a/data/json/items/armor/legs_armor.json +++ b/data/json/items/armor/legs_armor.json @@ -4,7 +4,7 @@ "type": "ARMOR", "category": "armor", "name": { "str": "pair of 2-by-shin guards", "str_pl": "pairs of 2-by-shin guards" }, - "description": "A pair of improvised shin guards made from broken pieces of a two by four that are tied to your shins with rags and string. They offer good protection, but are really hard to run with.", + "description": "A pair of improvised shin guards made from broken pieces of a plank that are tied to your shins with rags and string. They offer good protection, but are really hard to run with.", "weight": "300 g", "volume": "1500 ml", "price": 500, diff --git a/data/json/items/melee/swords_and_blades.json b/data/json/items/melee/swords_and_blades.json index d6a5d81e52af2..c577cc76d3ac3 100644 --- a/data/json/items/melee/swords_and_blades.json +++ b/data/json/items/melee/swords_and_blades.json @@ -5,7 +5,7 @@ "symbol": "!", "color": "brown", "name": { "str": "2-by-sword" }, - "description": "A two by four with a crossguard and whittled-down point; not much for slashing, but much better than your bare hands.", + "description": "A plank with a crossguard and whittled-down point; not much for slashing, but much better than your bare hands.", "material": [ "wood" ], "volume": "1250 ml", "weight": "1000 g", diff --git a/data/json/items/tool/workshop.json b/data/json/items/tool/workshop.json index 40987eae92595..5e67c927ca8ad 100644 --- a/data/json/items/tool/workshop.json +++ b/data/json/items/tool/workshop.json @@ -309,7 +309,7 @@ "id": "hammer", "type": "TOOL", "name": { "str": "hammer" }, - "description": "This is a demagnetized steel claw hammer with a wooden grip. With a hammer, nails, and two by fours in your inventory, you could board up adjacent doors and windows. It has myriad other uses as well.", + "description": "This is a demagnetized steel claw hammer with a wooden grip. With a hammer, nails, and planks in your inventory, you could board up adjacent doors and windows. It has myriad other uses as well.", "ascii_picture": "hammer", "longest_side": "25 cm", "weight": "566 g", diff --git a/data/json/items/vehicle/plating.json b/data/json/items/vehicle/plating.json index c7de99d163048..7b9e1b6f01cac 100644 --- a/data/json/items/vehicle/plating.json +++ b/data/json/items/vehicle/plating.json @@ -37,7 +37,7 @@ "type": "GENERIC", "id": "wood_plate", "name": { "str": "wooden armor kit" }, - "description": "A bundle of two-by-fours prepared to be used as vehicle armor.", + "description": "A bundle of planks prepared to be used as vehicle armor.", "weight": "5600 g", "to_hit": -8, "color": "brown", diff --git a/data/json/npcs/Backgrounds/evacuee_5.json b/data/json/npcs/Backgrounds/evacuee_5.json index 054226d4c8b73..bfd88f16a16f2 100644 --- a/data/json/npcs/Backgrounds/evacuee_5.json +++ b/data/json/npcs/Backgrounds/evacuee_5.json @@ -2,7 +2,7 @@ { "id": "BGSS_EVACUEE_5_STORY1", "type": "talk_topic", - "dynamic_line": "My Evac shelter got swarmed by some of those bees, the ones the size of dogs. I took out a few with a two-by-four, but pretty quick I realized it was either head for the hills or get stuck like a pig. The rest is history.", + "dynamic_line": "My Evac shelter got swarmed by some of those bees, the ones the size of dogs. I took out a few with a plank, but pretty quick I realized it was either head for the hills or get stuck like a pig. The rest is history.", "//": "TK: In a future iteration, this evacuee might give you directions to a hive.", "responses": [ { "text": "Giant bees? Tell me more.", "topic": "BGSS_EVACUEE_5_BEES" }, diff --git a/data/json/npcs/Backgrounds/no_past_4.json b/data/json/npcs/Backgrounds/no_past_4.json index d4194568a047a..1770b06b359d7 100644 --- a/data/json/npcs/Backgrounds/no_past_4.json +++ b/data/json/npcs/Backgrounds/no_past_4.json @@ -17,7 +17,7 @@ { "id": "BGSS_NO_PAST_4_STORY2", "type": "talk_topic", - "dynamic_line": "I went on, running when I had to and fighting when I could, like the rest of us. Started learning who I am now. Lost the bat in a fight against some crazy electric lightning shooting zombie. It was arcing electricity through my bat so I dropped it and used a nearby two-by-four, but I wound up having to run and leave the ol' slugger behind. I nearly died that day.", + "dynamic_line": "I went on, running when I had to and fighting when I could, like the rest of us. Started learning who I am now. Lost the bat in a fight against some crazy electric lightning shooting zombie. It was arcing electricity through my bat so I dropped it and used a nearby plank, but I wound up having to run and leave the ol' slugger behind. I nearly died that day.", "responses": [ { "text": "It can't be healthy to abandon your past like that…", diff --git a/data/json/npcs/hints.json b/data/json/npcs/hints.json index d25e659098279..e337a28c28e1c 100644 --- a/data/json/npcs/hints.json +++ b/data/json/npcs/hints.json @@ -44,7 +44,7 @@ "For a good melee weapon, you can't beat a machete. I've seen a guy take down a zombie brute with one! Of course, if you can find a katana, that might be even better…", "A knife spear makes a good weapon in a pinch, but a spike strapped to a stick isn't the sturdiest construction. At least you can strap the spike back on when it comes off.", "You know, a glass bottle can make a good weapon in a pinch. If you break it over someone's head, the shattering glass will hurt them extra. Of course, it might hurt your hands, too…", - "You know what makes a nice weapon? Take a two by four, or a baseball bat or something, and stick a bunch of nails through the end!", + "You know what makes a nice weapon? Take a plank, or a baseball bat or something, and stick a bunch of nails through the end!", "BB guns may seem like a joke, but they've got their uses. They're good for hunting small game, or getting to know the basics of rifles.", "Crossbows are a great weapon for long term use. Most of the time, you can retrieve the bolt after shooting it, so running out of ammo is less of a concern.", "Consider going Robin Hood, if you have the strength to pull the string of a bow. Those larger ones need significant muscle power, but they hit hard, and are silent.", diff --git a/doc/GAME_BALANCE.md b/doc/GAME_BALANCE.md index d5ec2bb898ff6..19f0ce7395460 100644 --- a/doc/GAME_BALANCE.md +++ b/doc/GAME_BALANCE.md @@ -126,7 +126,7 @@ Relative value should put the weapon into one of those categories: <2 - Not weapons. Those items may be pressed into service, but are unlikely to be better than fists. Plastic bottles, rocks, boots. -2-5 - Tools not meant to strike and improvised weapons. Two-by-fours, pointy sticks, pipes, hammers. +2-5 - Tools not meant to strike and improvised weapons. Planks, pointy sticks, pipes, hammers. 6-11 - Dangerous tools or crude dedicated weapons. Golf clubs, two-by-swords, wooden spears, knife spears, hatchets, switchblades, tonfas, quarterstaves. diff --git a/doc/VEHICLES_JSON.md b/doc/VEHICLES_JSON.md index 403bfeb9ef866..4e090f9942544 100644 --- a/doc/VEHICLES_JSON.md +++ b/doc/VEHICLES_JSON.md @@ -30,7 +30,7 @@ Vehicle prototypes do not currently accept copy-from "items": [ // Item spawn list { "x": 0, "y": 0, "items": "helmet_army" }, // individual item { "x": 0, "y": 0, "item_groups": "army_uniform" }, // item or items from an item_group - { "x": 0, "y": 1, "items": [ "matchbook", "two_by_four" ] }, // all items in the list spawn + { "x": 0, "y": 1, "items": [ "matchbook", "2x4" ] }, // all items in the list spawn { "x": 0, "y": 0, "item_groups": [ "army_uniform", "rare_guns" ] } all item_groups are processed ] ``` diff --git a/src/crafting_gui.cpp b/src/crafting_gui.cpp index 4e67f4a334029..ec9a7fc52f1f5 100644 --- a/src/crafting_gui.cpp +++ b/src/crafting_gui.cpp @@ -934,7 +934,7 @@ const recipe *select_crafting_recipe( int &batch_size_out ) //~ Example result description search term { 'q', _( "metal sawing" ), _( "quality of resulting item" ) }, { 'd', _( "reach attack" ), _( "full description of resulting item (slow)" ) }, - { 'c', _( "two by four" ), _( "component required to craft" ) }, + { 'c', _( "plank" ), _( "component required to craft" ) }, { 'p', _( "tailoring" ), _( "primary skill used to craft" ) }, { 's', _( "cooking" ), _( "any skill used to craft" ) }, { 'Q', _( "fine bolt turning" ), _( "quality required to craft" ) }, diff --git a/src/map.cpp b/src/map.cpp index 337777cb37aee..37970915bea06 100644 --- a/src/map.cpp +++ b/src/map.cpp @@ -3030,7 +3030,7 @@ void map::smash_items( const tripoint &p, const int power, const std::string &ca const float volume_factor = std::max( 40, i->volume() / units::legacy_volume_factor ); float damage_chance = 10.0f * power / volume_factor; // Example: - // Power 40 (just below C4 epicenter) vs two-by-four + // Power 40 (just below C4 epicenter) vs plank // damage_chance = 10 * 40 / 40 = 10, material_factor = 8 // Will deal 1 damage, then 20% chance for another point // Power 20 (grenade minus shrapnel) vs glass bottle diff --git a/tests/melee_test.cpp b/tests/melee_test.cpp index 23ba262880001..f40e68d9c5bd9 100644 --- a/tests/melee_test.cpp +++ b/tests/melee_test.cpp @@ -85,7 +85,7 @@ TEST_CASE( "Character attacking a zombie", "[.melee]" ) check_near( prob, 0.6f, 0.1f ); } - SECTION( "8/8/8/8, 3 all skills, two-by-four" ) { + SECTION( "8/8/8/8, 3 all skills, plank" ) { standard_npc dude( "TestCharacter", dude_pos, {}, 3, 8, 8, 8, 8 ); dude.weapon = item( "2x4" ); const float prob = brute_probability( dude, zed, num_iters ); @@ -114,7 +114,7 @@ TEST_CASE( "Character attacking a manhack", "[.melee]" ) check_near( prob, 0.2f, 0.05f ); } - SECTION( "8/8/8/8, 3 all skills, two-by-four" ) { + SECTION( "8/8/8/8, 3 all skills, plank" ) { standard_npc dude( "TestCharacter", dude_pos, {}, 3, 8, 8, 8, 8 ); dude.weapon = item( "2x4" ); const float prob = brute_probability( dude, manhack, num_iters ); From 5464c7a12930bcd510107fa637f433fd1f68080b Mon Sep 17 00:00:00 2001 From: Jamuro-g <76928284+Jamuro-g@users.noreply.github.com> Date: Thu, 1 Apr 2021 04:51:53 +0200 Subject: [PATCH 120/453] Added warning to excessive long attack times (#47835) MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit * added warning to excessive long attack times * restore code * astyle fix * removed unused code * Update src/melee.cpp Co-authored-by: Jianxiang Wang (王健翔) * Update src/melee.cpp Co-authored-by: Jianxiang Wang (王健翔) * switch message block Co-authored-by: Jianxiang Wang (王健翔) --- src/character.h | 1 + src/melee.cpp | 24 +++++++++++++++++++++++- 2 files changed, 24 insertions(+), 1 deletion(-) diff --git a/src/character.h b/src/character.h index dca5ede190e09..eedd8b4dadb43 100644 --- a/src/character.h +++ b/src/character.h @@ -2948,6 +2948,7 @@ class Character : public Creature, public visitable tripoint cached_position; pimpl cached_crafting_inventory; + time_point melee_warning_turn = calendar::turn_zero; protected: /** Subset of learned recipes. Needs to be mutable for lazy initialization. */ mutable pimpl learned_recipes; diff --git a/src/melee.cpp b/src/melee.cpp index eb9fb2b6facb4..856aa4f645486 100644 --- a/src/melee.cpp +++ b/src/melee.cpp @@ -55,6 +55,7 @@ #include "pimpl.h" #include "player.h" #include "point.h" +#include "popup.h" #include "projectile.h" #include "rng.h" #include "sounds.h" @@ -540,9 +541,30 @@ bool Character::melee_attack_abstract( Creature &t, bool allow_special, add_msg( m_bad, _( "This weapon is too unwieldy to attack with!" ) ); return false; } - int move_cost = attack_speed( *cur_weapon ); + if( is_avatar() && move_cost > 1000 && calendar::turn > melee_warning_turn ) { + const auto &action = query_popup() + .context( "CANCEL_ACTIVITY_OR_IGNORE_QUERY" ) + .message( _( "Attacking with your %1$s will take a long time. " + "Are you sure you want to continue?" ), + cur_weapon->display_name() ) + .option( "YES" ) + .option( "NO" ) + .option( "IGNORE" ) + .query() + .action; + + if( action == "NO" ) { + return false; + } + if( action == "IGNORE" ) { + if( melee_warning_turn == calendar::turn_zero || melee_warning_turn <= calendar::turn ) { + melee_warning_turn = calendar::turn + 50_turns; + } + } + } + const bool hits = hit_spread >= 0; if( monster *m = t.as_monster() ) { From af4cea2587b3915b225a9778a0c85ce615748ac2 Mon Sep 17 00:00:00 2001 From: Mark Ponti Date: Wed, 31 Mar 2021 21:11:09 -0700 Subject: [PATCH 121/453] meatballs (#48124) * Update meat_dishes.json * Update meat_dishes.json * Update meat_dishes.json * Update meat_dishes.json * Update recipe_food.json * Update recipe_food.json * Update recipe_food.json * Update recipe_food.json * Update recipe_food.json * Update data/json/recipes/recipe_food.json Co-authored-by: Binrui Dong Co-authored-by: Binrui Dong --- data/json/items/comestibles/meat_dishes.json | 43 ++++++++++++++++++++ data/json/recipes/recipe_food.json | 41 +++++++++++++++++++ 2 files changed, 84 insertions(+) diff --git a/data/json/items/comestibles/meat_dishes.json b/data/json/items/comestibles/meat_dishes.json index a6f27f6b5170f..a9a28f0a6ed53 100644 --- a/data/json/items/comestibles/meat_dishes.json +++ b/data/json/items/comestibles/meat_dishes.json @@ -1389,5 +1389,48 @@ "flags": [ "EATEN_HOT" ], "fun": 7, "vitamins": [ [ "vitC", 3 ], [ "calcium", 19 ], [ "iron", 12 ] ] + }, + { + "type": "COMESTIBLE", + "id": "meatball_raw", + "name": { "str": "raw meatball" }, + "conditional_names": [ + { "type": "FLAG", "condition": "CANNIBALISM", "name": "raw manball" }, + { "type": "FLAG", "condition": "STRICT_HUMANITARIANISM", "name": "raw murderball" }, + { "type": "COMPONENT_ID", "condition": "mutant", "name": { "str_sp": "sinister %s" } } + ], + "weight": "85g", + "color": "pink", + "spoils_in": "1 day", + "comestible_type": "FOOD", + "symbol": "%", + "calories": 230, + "healthy": -1, + "parasites": 32, + "description": "A round, seasoned lump of meat, ready to fry.", + "price": 800, + "price_postapoc": 200, + "material": [ "flesh" ], + "volume": "85 ml", + "vitamins": [ [ "vitA", 2 ], [ "vitC", 2 ], [ "calcium", 8 ], [ "iron", 4 ] ], + "fun": -10 + }, + { + "type": "COMESTIBLE", + "id": "meatball", + "name": { "str": "meatball" }, + "conditional_names": [ + { "type": "FLAG", "condition": "CANNIBALISM", "name": "manball" }, + { "type": "FLAG", "condition": "STRICT_HUMANITARIANISM", "name": "murderball" }, + { "type": "COMPONENT_ID", "condition": "mutant", "name": { "str_sp": "sinister %s" } } + ], + "copy-from": "meatball_raw", + "parasites": 0, + "healthy": 0, + "spoils_in": "4 days", + "price_postapoc": 300, + "description": "A seasoned, fried, round lump of meat. Just like mom used to make!", + "flags": [ "EATEN_HOT" ], + "fun": 6 } ] diff --git a/data/json/recipes/recipe_food.json b/data/json/recipes/recipe_food.json index aa40e1a7ed67b..2b92975413284 100644 --- a/data/json/recipes/recipe_food.json +++ b/data/json/recipes/recipe_food.json @@ -7684,5 +7684,46 @@ [ [ "sugar", 1 ], [ "artificial_sweetener", 1 ] ], [ [ "salt", 1 ], [ "seasoning_salt", 1 ] ] ] + }, + { + "type": "recipe", + "activity_level": "LIGHT_EXERCISE", + "result": "meatball_raw", + "category": "CC_FOOD", + "subcategory": "CSC_FOOD_MEAT", + "skill_used": "cooking", + "difficulty": 4, + "time": "10 m", + "charges": 6, + "book_learn": [ [ "family_cookbook", 2 ], [ "cookbook_italian", 2 ] ], + "batch_time_factors": [ 50, 3 ], + "qualities": [ { "id": "CUT", "level": 1 }, { "id": "COOK", "level": 1 } ], + "components": [ + [ [ "meat_red", 2, "LIST" ] ], + [ [ "bread", 1 ] ], + [ + [ "salt", 2 ], + [ "soysauce", 2 ], + [ "seasoning_italian", 2 ], + [ "wild_herbs", 2 ], + [ "seasoning_salt", 2 ], + [ "pepper", 2 ] + ] + ] + }, + { + "type": "recipe", + "activity_level": "LIGHT_EXERCISE", + "result": "meatball", + "category": "CC_FOOD", + "subcategory": "CSC_FOOD_MEAT", + "skill_used": "cooking", + "time": "15 m", + "autolearn": true, + "batch_time_factors": [ 67, 5 ], + "qualities": [ { "id": "COOK", "level": 1 } ], + "tools": [ [ [ "surface_heat", 2, "LIST" ] ] ], + "charges": 1, + "components": [ [ [ "meatball_raw", 1 ] ] ] } ] From 529c84eb7e19680349663930864f5ed73d71e039 Mon Sep 17 00:00:00 2001 From: Anton Burmistrov Date: Mon, 5 Apr 2021 23:15:13 +0400 Subject: [PATCH 122/453] Jsonify drug dealer map extra (#48327) * Added json-version of drug dealers map extra * Made game use json-version instead of hardcoded one * Updated item group to contain drugs Also increased damage level of corpses to pulped state so they don't revive * Removed hardcoded generation --- .../Locations_MapExtras/map_extras.json | 11 +- data/json/mapgen/map_extras/drug_dealers.json | 51 +++++++ data/json/overmap/map_extras.json | 2 +- src/map_extras.cpp | 128 ------------------ 4 files changed, 62 insertions(+), 130 deletions(-) create mode 100644 data/json/mapgen/map_extras/drug_dealers.json diff --git a/data/json/itemgroups/Locations_MapExtras/map_extras.json b/data/json/itemgroups/Locations_MapExtras/map_extras.json index 7b21d2695145b..1620384f0e575 100644 --- a/data/json/itemgroups/Locations_MapExtras/map_extras.json +++ b/data/json/itemgroups/Locations_MapExtras/map_extras.json @@ -71,12 +71,21 @@ "id": "map_extra_drugdeal", "entries": [ { "group": "drugdealer", "prob": 75 }, + { + "distribution": [ + { "item": "weed", "container-item": "bag_zipper", "charges-min": 20, "charges-max": 30, "prob": 10 }, + { "item": "coke", "container-item": "bag_zipper", "charges-min": 10, "charges-max": 20, "prob": 40 }, + { "item": "meth", "container-item": "bag_zipper", "charges-min": 8, "charges-max": 14, "prob": 30 }, + { "item": "heroin", "container-item": "bag_zipper", "charges-min": 6, "charges-max": 12, "prob": 20 } + ], + "prob": 50 + }, { "item": "pants_cargo", "damage-min": 1, "damage-max": 4 }, { "group": "lab_shoes", "damage-min": 1, "damage-max": 4, "prob": 50 }, { "group": "shirts", "damage-min": 1, "damage-max": 4, "prob": 50 }, { "group": "jackets", "damage-min": 1, "damage-max": 4, "prob": 30 }, { "group": "underwear", "damage-min": 1, "damage-max": 3 }, - { "item": "corpse", "damage": 3 } + { "item": "corpse", "damage": 4 } ] }, { diff --git a/data/json/mapgen/map_extras/drug_dealers.json b/data/json/mapgen/map_extras/drug_dealers.json new file mode 100644 index 0000000000000..5d34b27fa1976 --- /dev/null +++ b/data/json/mapgen/map_extras/drug_dealers.json @@ -0,0 +1,51 @@ +[ + { + "type": "mapgen", + "method": "json", + "nested_mapgen_id": "corpse_blood_gibs_drugs_3x3", + "object": { + "mapgensize": [ 3, 3 ], + "place_items": [ { "item": "map_extra_drugdeal", "x": [ 0, 2 ], "y": [ 0, 2 ], "chance": 100 } ], + "place_fields": [ { "field": "fd_blood", "x": [ 0, 2 ], "y": [ 0, 2 ] }, { "field": "fd_gibs_flesh", "x": [ 0, 2 ], "y": [ 0, 2 ] } ] + } + }, + { + "type": "mapgen", + "method": "json", + "update_mapgen_id": "mx_drugdeal", + "object": { + "rows": [ + " ", + " ", + " ", + " ", + " ", + " ", + " ", + " ", + " ", + " ", + " ", + " 1 ", + " ", + " ", + " ", + " ", + " ", + " ", + " ", + " ", + " ", + " ", + " ", + " " + ], + "terrain": { " ": [ [ "t_region_groundcover_urban", 50 ], [ "t_region_groundcover_barren", 20 ] ] }, + "monsters": { " ": { "monster": "GROUP_NETHER_CAPTURED", "chance": 1, "density": 0.0001 } }, + "nested": { + " ": { "chunks": [ [ "corpse_blood_gibs_drugs_3x3", 1 ], [ "null", 150 ] ] }, + "1": { "chunks": [ "corpse_blood_gibs_drugs_3x3" ] } + } + } + } +] diff --git a/data/json/overmap/map_extras.json b/data/json/overmap/map_extras.json index bb8a7cf44a558..a7d4846738189 100644 --- a/data/json/overmap/map_extras.json +++ b/data/json/overmap/map_extras.json @@ -24,7 +24,7 @@ "type": "map_extra", "name": { "str": "Drug Deal" }, "description": "Several corpses of drug dealers are here.", - "generator": { "generator_method": "map_extra_function", "generator_id": "mx_drugdeal" }, + "generator": { "generator_method": "update_mapgen", "generator_id": "mx_drugdeal" }, "sym": "d", "color": "light_red", "autonote": true diff --git a/src/map_extras.cpp b/src/map_extras.cpp index 948625df39251..5834d5cb92673 100644 --- a/src/map_extras.cpp +++ b/src/map_extras.cpp @@ -916,133 +916,6 @@ static bool mx_bandits_block( map &m, const tripoint &abs_sub ) return false; } -static bool mx_drugdeal( map &m, const tripoint &abs_sub ) -{ - // Decide on a drug type - int num_drugs = 0; - itype_id drugtype; - switch( rng( 1, 10 ) ) { - case 1: - // Weed - num_drugs = rng( 20, 30 ); - drugtype = itype_weed; - break; - case 2: - case 3: - case 4: - case 5: - // Cocaine - num_drugs = rng( 10, 20 ); - drugtype = itype_coke; - break; - case 6: - case 7: - case 8: - // Meth - num_drugs = rng( 8, 14 ); - drugtype = itype_meth; - break; - case 9: - case 10: - // Heroin - num_drugs = rng( 6, 12 ); - drugtype = itype_heroin; - break; - } - int num_bodies_a = dice( 3, 3 ); - int num_bodies_b = dice( 3, 3 ); - bool north_south = one_in( 2 ); - bool a_has_drugs = one_in( 2 ); - - for( int i = 0; i < num_bodies_a; i++ ) { - point p; - point offset; - int tries = 0; - do { // Loop until we find a valid spot to dump a body, or we give up - if( north_south ) { - p.x = rng( 0, SEEX * 2 - 1 ); - p.y = rng( 0, SEEY - 4 ); - offset.x = 0; - offset.y = -1; - } else { - p.x = rng( 0, SEEX - 4 ); - p.y = rng( 0, SEEY * 2 - 1 ); - offset.x = -1; - offset.y = 0; - } - tries++; - } while( tries < 10 && m.impassable( p ) ); - - if( tries < 10 ) { // We found a valid spot! - if( a_has_drugs && num_drugs > 0 ) { - int drugs_placed = rng( 2, 6 ); - if( drugs_placed > num_drugs ) { - drugs_placed = num_drugs; - num_drugs = 0; - } - m.spawn_item( p, drugtype, 0, drugs_placed ); - } - if( one_in( 10 ) ) { - m.add_spawn( mon_zombie_spitter, 1, { p, abs_sub.z } ); - } else { - m.place_items( item_group_id( "map_extra_drugdeal" ), 100, p, p, true, - calendar::start_of_cataclysm ); - int splatter_range = rng( 1, 3 ); - for( int j = 0; j <= splatter_range; j++ ) { - m.add_field( p + tripoint( j * offset.x, j * offset.y, abs_sub.z ), fd_blood, 1, 0_turns ); - } - } - } - } - for( int i = 0; i < num_bodies_b; i++ ) { - point p2; - point offset2; - int tries = 0; - do { // Loop until we find a valid spot to dump a body, or we give up - if( north_south ) { - p2.x = rng( 0, SEEX * 2 - 1 ); - p2.y = rng( SEEY + 3, SEEY * 2 - 1 ); - offset2.x = 0; - offset2.y = 1; - } else { - p2.x = rng( SEEX + 3, SEEX * 2 - 1 ); - p2.y = rng( 0, SEEY * 2 - 1 ); - offset2.x = 1; - offset2.y = 0; - } - tries++; - } while( tries < 10 && m.impassable( p2 ) ); - - if( tries < 10 ) { // We found a valid spot! - if( one_in( 20 ) ) { - m.add_spawn( mon_zombie_smoker, 1, { p2, abs_sub.z } ); - } else { - m.place_items( item_group_id( "map_extra_drugdeal" ), 100, p2, p2, true, - calendar::start_of_cataclysm ); - int splatter_range = rng( 1, 3 ); - for( int j = 0; j <= splatter_range; j++ ) { - m.add_field( p2 + tripoint( j * offset2.x, j * offset2.y, abs_sub.z ), fd_blood, 1, 0_turns ); - } - if( !a_has_drugs && num_drugs > 0 ) { - int drugs_placed = rng( 2, 6 ); - if( drugs_placed > num_drugs ) { - drugs_placed = num_drugs; - num_drugs = 0; - } - m.spawn_item( p2, drugtype, 0, drugs_placed ); - } - } - } - } - int num_monsters = rng( 0, 3 ); - for( int i = 0; i < num_monsters; i++ ) { - point m2( rng( 1, SEEX * 2 - 2 ), rng( 1, SEEY * 2 - 2 ) ); - m.place_spawns( GROUP_NETHER_CAPTURED, 1, m2, m2, 1, true ); - } - - return true; -} - static bool mx_supplydrop( map &m, const tripoint &/*abs_sub*/ ) { const bool intact = x_in_y( 40, @@ -3122,7 +2995,6 @@ FunctionMap builtin_functions = { { "mx_null", mx_null }, { "mx_crater", mx_crater }, { "mx_collegekids", mx_collegekids }, - { "mx_drugdeal", mx_drugdeal }, { "mx_roadworks", mx_roadworks }, { "mx_mayhem", mx_mayhem }, { "mx_roadblock", mx_roadblock }, From 24f9f08b06a69927f30a4aebc48878a941d8d9c3 Mon Sep 17 00:00:00 2001 From: Eric <52087122+Ramza13@users.noreply.github.com> Date: Tue, 6 Apr 2021 00:14:27 -0400 Subject: [PATCH 123/453] Allows defining enchantments inline in bionics/mutations (#48151) --- data/json/bionics.json | 12 ++++-- data/json/enchantments.json | 39 ------------------- .../json/mutations/mutation_enchantments.json | 15 ------- data/json/mutations/mutations.json | 20 ++++++++-- doc/JSON_INFO.md | 4 +- src/bionics.cpp | 7 +++- src/magic_enchantment.cpp | 28 ++++++++++++- src/magic_enchantment.h | 8 +++- src/mutation_data.cpp | 7 +++- 9 files changed, 72 insertions(+), 68 deletions(-) delete mode 100644 data/json/enchantments.json delete mode 100644 data/json/mutations/mutation_enchantments.json diff --git a/data/json/bionics.json b/data/json/bionics.json index a542a422ccf49..fe45fec392185 100644 --- a/data/json/bionics.json +++ b/data/json/bionics.json @@ -281,7 +281,7 @@ "act_cost": "30 kJ", "react_cost": "30 kJ", "time": 1, - "enchantments": [ "ENCH_INVISIBILITY" ], + "enchantments": [ { "condition": "ACTIVE", "ench_effects": [ { "effect": "invisibility", "intensity": 1 } ] } ], "flags": [ "BIONIC_TOGGLED" ] }, { @@ -739,7 +739,13 @@ "description": "When active, this bionic eliminates all light within a 2 tile radius through destructive interference.", "occupied_bodyparts": [ [ "torso", 16 ] ], "flags": [ "BIONIC_TOGGLED" ], - "enchantments": [ "ENCH_SHADOW_CLOUD" ], + "enchantments": [ + { + "condition": "ACTIVE", + "ench_effects": [ { "effect": "invisibility", "intensity": 1 } ], + "emitter": "emit_shadow_field" + } + ], "act_cost": "9 kJ", "react_cost": "9 kJ", "time": 1 @@ -1227,6 +1233,6 @@ "description": "An electrode has been implanted into your brain's ventrolateral preoptic nucleus. It turns on whenever you're trying to fall asleep, creating an artificial but effective sensation of fatigue.", "occupied_bodyparts": [ [ "head", 1 ] ], "flags": [ "BIONIC_TOGGLED" ], - "enchantments": [ "ENCH_BIO_SOPORIFIC" ] + "enchantments": [ { "condition": "ACTIVE", "values": [ { "value": "SLEEPY", "add": 30 } ] } ] } ] diff --git a/data/json/enchantments.json b/data/json/enchantments.json deleted file mode 100644 index 85852553944b5..0000000000000 --- a/data/json/enchantments.json +++ /dev/null @@ -1,39 +0,0 @@ -[ - { - "type": "enchantment", - "id": "ENCH_INVISIBILITY", - "condition": "ACTIVE", - "ench_effects": [ { "effect": "invisibility", "intensity": 1 } ] - }, - { - "type": "enchantment", - "id": "ENCH_SHADOW_CLOUD", - "condition": "ACTIVE", - "ench_effects": [ { "effect": "invisibility", "intensity": 1 } ], - "emitter": "emit_shadow_field" - }, - { - "type": "enchantment", - "id": "ENCH_TRAIT_INSOMNIA", - "condition": "ALWAYS", - "values": [ { "value": "SLEEPY", "add": -12 } ] - }, - { - "type": "enchantment", - "id": "ENCH_TRAIT_EASYSLEEPER", - "condition": "ALWAYS", - "values": [ { "value": "SLEEPY", "add": 24 } ] - }, - { - "type": "enchantment", - "id": "ENCH_TRAIT_EASYSLEEPER2", - "condition": "ALWAYS", - "values": [ { "value": "SLEEPY", "add": 40 } ] - }, - { - "type": "enchantment", - "id": "ENCH_BIO_SOPORIFIC", - "condition": "ACTIVE", - "values": [ { "value": "SLEEPY", "add": 30 } ] - } -] diff --git a/data/json/mutations/mutation_enchantments.json b/data/json/mutations/mutation_enchantments.json deleted file mode 100644 index 8421a76188920..0000000000000 --- a/data/json/mutations/mutation_enchantments.json +++ /dev/null @@ -1,15 +0,0 @@ -[ - { - "type": "enchantment", - "id": "MEP_INK_GLAND_SPRAY", - "hit_me_effect": [ - { - "id": "generic_blinding_spray_1", - "hit_self": false, - "once_in": 15, - "message": "Your ink glands spray some ink into %2$s's eyes.", - "npc_message": "%1$s's ink glands spray some ink into %2$s's eyes." - } - ] - } -] diff --git a/data/json/mutations/mutations.json b/data/json/mutations/mutations.json index 10b1ad3e70c90..01460e1e17bef 100644 --- a/data/json/mutations/mutations.json +++ b/data/json/mutations/mutations.json @@ -305,7 +305,7 @@ "valid": false, "cancels": [ "INSOMNIA" ], "category": [ "MOUSE", "INSECT" ], - "enchantments": [ "ENCH_TRAIT_EASYSLEEPER" ] + "enchantments": [ { "condition": "ALWAYS", "values": [ { "value": "SLEEPY", "add": 24 } ] } ] }, { "type": "mutation", @@ -317,7 +317,7 @@ "cancels": [ "INSOMNIA" ], "threshreq": [ "THRESH_MOUSE" ], "category": [ "MOUSE" ], - "enchantments": [ "ENCH_TRAIT_EASYSLEEPER2" ] + "enchantments": [ { "condition": "ALWAYS", "values": [ { "value": "SLEEPY", "add": 40 } ] } ] }, { "type": "mutation", @@ -1062,7 +1062,7 @@ "starting_trait": true, "valid": false, "category": [ "MEDICAL" ], - "enchantments": [ "ENCH_TRAIT_INSOMNIA" ], + "enchantments": [ { "condition": "ALWAYS", "values": [ { "value": "SLEEPY", "add": -12 } ] } ], "cancels": [ "EASYSLEEPER" ] }, { @@ -2815,7 +2815,19 @@ "visibility": 1, "ugliness": 1, "description": "Several ink glands have grown onto your torso. They can be used to spray defensive ink and blind an attacker in an emergency, as long as the torso isn't covered.", - "enchantments": [ "MEP_INK_GLAND_SPRAY" ], + "enchantments": [ + { + "hit_me_effect": [ + { + "id": "generic_blinding_spray_1", + "hit_self": false, + "once_in": 15, + "message": "Your ink glands spray some ink into %2$s's eyes.", + "npc_message": "%1$s's ink glands spray some ink into %2$s's eyes." + } + ] + } + ], "category": [ "CEPHALOPOD" ] }, { diff --git a/doc/JSON_INFO.md b/doc/JSON_INFO.md index 6448af935a0f2..608692e045f86 100644 --- a/doc/JSON_INFO.md +++ b/doc/JSON_INFO.md @@ -673,7 +673,7 @@ For information about tools with option to export ASCII art in format ready to b | coverage_power_gen_penalty | (_optional_) Fraction of coverage diminishing fuel_efficiency. Float between 0.0 and 1.0. (default: `nullopt`) | power_gen_emission | (_optional_) `emit_id` of the field emitted by this bionic when it produces energy. Emit_ids are defined in `emit.json`. | stat_bonus | (_optional_) List of passive stat bonus. Stat are designated as follow: "DEX", "INT", "STR", "PER". -| enchantments | (_optional_) List of enchantments applied by this CBM (see MAGIC.md for instructions on enchantment. NB: enchantments are not necessarily magic.) +| enchantments | (_optional_) List of enchantments applied by this CBM (see MAGIC.md for instructions on enchantment. NB: enchantments are not necessarily magic.) Values can either be the enchantments's id or an inline definition of the enchantment. | learned_spells | (_optional_) Map of {spell:level} you gain when installing this CBM, and lose when you uninstall this CBM. Spell classes are automatically gained. | learned_proficiencies | (_optional_) Array of proficiency ids you gain when installing this CBM, and lose when uninstalling | installation_requirement | (_optional_) Requirement id pointing to a requirement defining the tools and components necessary to install this CBM. @@ -1936,7 +1936,7 @@ it is present to help catch errors. } ] ], -"enchantments": [ "ench_id_1" ], // List of IDs of enchantments granted by this mutation +"enchantments": [ "ench_id_1" ], // List of enchantments granted by this mutation, can be either string ids of the enchantment or an inline definition of the enchantment "temperature_speed_modifier": 0.5, // If nonzero, become slower when cold, and faster when hot // 1.0 gives +/-1% speed for each degree above or below 65F "mana_modifier": 100 // Positive or negative change to total mana pool diff --git a/src/bionics.cpp b/src/bionics.cpp index 2562f37684f43..e80aaff137285 100644 --- a/src/bionics.cpp +++ b/src/bionics.cpp @@ -306,7 +306,6 @@ void bionic_data::load( const JsonObject &jsobj, const std::string & ) optional( jsobj, was_loaded, "fake_item", fake_item, itype_id() ); - optional( jsobj, was_loaded, "enchantments", enchantments ); optional( jsobj, was_loaded, "spell_on_activation", spell_on_activate ); optional( jsobj, was_loaded, "weight_capacity_modifier", weight_capacity_modifier, 1.0f ); @@ -331,6 +330,12 @@ void bionic_data::load( const JsonObject &jsobj, const std::string & ) optional( jsobj, was_loaded, "vitamin_absorb_mod", vitamin_absorb_mod, 1.0f ); + int enchant_num = 0; + for( JsonValue jv : jsobj.get_array( "enchantments" ) ) { + std::string enchant_name = "INLINE_ENCH_" + name + "_" + std::to_string( enchant_num++ ); + enchantments.push_back( enchantment::load_inline_enchantment( jv, "", enchant_name ) ); + } + if( jsobj.has_array( "stat_bonus" ) ) { // clear data first so that copy-from can override it stat_bonus.clear(); diff --git a/src/magic_enchantment.cpp b/src/magic_enchantment.cpp index cfbd928183c2f..390b78594862e 100644 --- a/src/magic_enchantment.cpp +++ b/src/magic_enchantment.cpp @@ -147,6 +147,29 @@ void enchantment::load_enchantment( const JsonObject &jo, const std::string &src spell_factory.load( jo, src ); } +enchantment_id enchantment::load_inline_enchantment( const JsonValue &jv, const std::string &src, + std::string &inline_id ) +{ + if( jv.test_string() ) { + return enchantment_id( jv.get_string() ); + } else if( jv.test_object() ) { + if( inline_id.empty() ) { + jv.throw_error( "Inline enchantment cannot be created without an id." ); + } + if( spell_factory.is_valid( enchantment_id( inline_id ) ) ) { + jv.throw_error( "Inline enchantment " + inline_id + + " cannot be created as an enchantment already has this id." ); + } + + enchantment inline_enchant; + inline_enchant.load( jv.get_object(), src, inline_id ); + spell_factory.insert( inline_enchant ); + return enchantment_id( inline_id ); + } else { + jv.throw_error( "Enchantment needs to be either string or enchantment object." ); + } +} + bool enchantment::is_active( const Character &guy, const item &parent ) const { if( !guy.has_item( parent ) ) { @@ -197,9 +220,10 @@ void enchantment::add_activation( const time_duration &dur, const fake_spell &fa intermittent_activation[dur].emplace_back( fake ); } -void enchantment::load( const JsonObject &jo, const std::string & ) +void enchantment::load( const JsonObject &jo, const std::string &, + const cata::optional &inline_id ) { - optional( jo, was_loaded, "id", id, enchantment_id( "" ) ); + optional( jo, was_loaded, "id", id, enchantment_id( inline_id.value_or( "" ) ) ); jo.read( "hit_you_effect", hit_you_effect ); jo.read( "hit_me_effect", hit_me_effect ); diff --git a/src/magic_enchantment.h b/src/magic_enchantment.h index 442d56b50b45f..de76442562094 100644 --- a/src/magic_enchantment.h +++ b/src/magic_enchantment.h @@ -120,7 +120,13 @@ class enchantment }; static void load_enchantment( const JsonObject &jo, const std::string &src ); - void load( const JsonObject &jo, const std::string &src = "" ); + void load( const JsonObject &jo, const std::string &src = "", + const cata::optional &inline_id = cata::nullopt ); + + // Takes in a JsonValue which can be either a string or an enchantment object and returns the id of the enchantment the caller will use. + // If the input is a string return it as an enchantment_id otherwise create an enchantment with id inline_id and return inline_id as an enchantment id + static enchantment_id load_inline_enchantment( const JsonValue &jv, const std::string &src, + std::string &inline_id ); // attempts to add two like enchantments together. // if their conditions don't match, return false. else true. diff --git a/src/mutation_data.cpp b/src/mutation_data.cpp index bf16334165fda..2600d3de911a1 100644 --- a/src/mutation_data.cpp +++ b/src/mutation_data.cpp @@ -504,7 +504,12 @@ void mutation_branch::load( const JsonObject &jo, const std::string & ) optional( jo, was_loaded, "active_flags", active_flags, flag_reader{} ); optional( jo, was_loaded, "inactive_flags", inactive_flags, flag_reader{} ); optional( jo, was_loaded, "types", types, string_reader{} ); - optional( jo, was_loaded, "enchantments", enchantments ); + + int enchant_num = 0; + for( JsonValue jv : jo.get_array( "enchantments" ) ) { + std::string enchant_name = "INLINE_ENCH_" + raw_name + "_" + std::to_string( enchant_num++ ); + enchantments.push_back( enchantment::load_inline_enchantment( jv, "", enchant_name ) ); + } for( const std::string s : jo.get_array( "no_cbm_on_bp" ) ) { no_cbm_on_bp.emplace( bodypart_str_id( s ) ); From 9438c637416b99824a015dded404db33d40696a5 Mon Sep 17 00:00:00 2001 From: Eric <52087122+Ramza13@users.noreply.github.com> Date: Tue, 6 Apr 2021 01:19:34 -0400 Subject: [PATCH 124/453] Unhardcode bio_drain bionic faults (#48295) --- data/json/effect_on_condition.json | 17 ++++++++++++-- doc/NPCs.md | 4 +++- src/condition.cpp | 17 +++++++++++++- src/condition.h | 3 ++- src/dialogue.h | 1 + src/npctalk.cpp | 36 +++++++++++++++++++++++++----- src/suffer.cpp | 6 ----- src/talker.h | 3 +++ src/talker_character.cpp | 8 ++++++- src/talker_character.h | 1 + 10 files changed, 78 insertions(+), 18 deletions(-) diff --git a/data/json/effect_on_condition.json b/data/json/effect_on_condition.json index dc0db08616435..ce8a99fc4ff9d 100644 --- a/data/json/effect_on_condition.json +++ b/data/json/effect_on_condition.json @@ -14,7 +14,7 @@ "deactivate_condition": { "not": { "or": [ { "is_weather": "thunder" }, { "is_weather": "lightning" } ] } }, "effect": [ { "message": "You hear a distant rumble of thunder.", "sound": true }, - { "sound_effect": "thunder_far", "outdoor_event": true } + { "sound_effect": "thunder_far", "outdoor_event": true, "id": "environment" } ] }, { @@ -26,7 +26,7 @@ "deactivate_condition": { "not": { "is_weather": "lightning" } }, "effect": [ { "message": "A flash of lightning illuminates your surroundings!" }, - { "sound_effect": "thunder_near" }, + { "sound_effect": "thunder_near", "id": "environment" }, "lightning" ] }, @@ -74,5 +74,18 @@ "condition": { "and": [ { "is_weather": "snowstorm" }, "u_is_outside" ] }, "deactivate_condition": { "not": { "is_weather": "snowstorm" } }, "effect": [ { "u_add_wet": 40 } ] + }, + { + "type": "effect_on_condition", + "id": "bio_drain", + "recurrence_min": "30 minutes", + "recurrence_max": "1 hours 30 minutes", + "condition": { "and": [ { "u_has_bionics": "bio_drain" }, { "u_has_power": "24 kJ" } ] }, + "deactivate_condition": { "not": { "u_has_bionics": "bio_drain" } }, + "effect": [ + { "message": "Your batteries discharge slightly.", "type": "bad" }, + { "sound_effect": "elec_crackle_low", "id": "bionics", "volume": 100 }, + { "u_add_power": "-25kJ" } + ] } ] diff --git a/doc/NPCs.md b/doc/NPCs.md index 5f9e5f18d9a80..0062c4628488a 100644 --- a/doc/NPCs.md +++ b/doc/NPCs.md @@ -488,6 +488,7 @@ Effect | Description `npc_first_topic: talk_topic_string` | Changes the initial talk_topic of the NPC in all future dialogues. `u_mod_pain: pain_int`
`npc_mod_pain: pain_int` | Your character or the NPC will have `pain_int` added or subtracted from its pain. `u_add_wet: wet_int`
`npc_add_wet: wet_int` | Your character or the NPC will be wet `wet_int` as if they were in the rain. +`u_add_power: power_energy`
`npc_add_power: power_energy` | Your character or the NPC will have `power_energy` added or subtracted from its bionic power. #### Trade / Items @@ -557,7 +558,7 @@ Effect | Description Effect | Description ---|--- `message: message_string`, (*optional* `sound: sound_bool`),(*optional* `outdoor_only: outdoor_only_bool`),(*optional* `snippet: snippet_bool`),(*optional* `type: type_string`),(*optional* `popup: popup_bool`) | Displays a message to the player of `message_string`. If `snippet_bool` is true(defaults to false) it will instead display a random snippet from `message_string` category. If `sound` is true(defaults to false) it will only display the message if the player is not deaf. `outdoor_only`(defaults to false) only matters when `sound` is true and will make the message less likely to be heard if the player is underground. Message will display as type of `type_string`. Type affects the color of message and can be any of the following values: good, neutral, bad, mixed, warning, info, debug, headshot, critical, grazing. enums.h has more info on each types use. If `popup_bool` is true the message will be in a modal popup the user has to dismiss to continue. -`sound_effect: sound_effect_id_string`, *optional* `outdoor_event: outdoor_event` | Will play a sound effect of type `sound_effect_id_string`. If `outdoor_event`(defaults to false) is true this will be less likely to play if the player is underground. +`sound_effect: sound_effect_id_string`, *optional* `sound_effect_variant: variant_string`, *optional* `outdoor_event: outdoor_event`,*optional* `volume: volume_int` | Will play a sound effect of id `sound_effect_id_string` and variant `variant_string`. If `volume_int` is defined it will be used otherwise 80 is the default. If `outdoor_event`(defaults to false) is true this will be less likely to play if the player is underground. #### Deprecated @@ -636,6 +637,7 @@ Condition | Type | Description `"u_is_height"`
`"npc_is_height"` | int | `true` if the player character's or NPC's elevation is at least the value of `u_is_height` or `npc_is_height`. `"u_has_worn_with_flag"`
`"npc_has_worn_with_flag"` | string | `true` if the player character or NPC is wearing something with the `u_has_worn_with_flag` or `npc_has_worn_with_flag` flag. `"u_has_wielded_with_flag"`
`"npc_has_wielded_with_flag"` | string | `true` if the player character or NPC is wielding something with the `u_has_wielded_with_flag` or `npc_has_wielded_with_flag` flag. +`"u_has_power"`
`"npc_has_power"` | int | `true` if the player character's or NPC's bionic power is at least the value of `u_has_power` or `npc_has_power`. #### Player Only conditions diff --git a/src/condition.cpp b/src/condition.cpp index 10aae878264d7..e454446372227 100644 --- a/src/condition.cpp +++ b/src/condition.cpp @@ -918,6 +918,17 @@ void conditional_t::set_has_pain( const JsonObject &jo, const std::string &me }; } +template +void conditional_t::set_has_power( const JsonObject &jo, const std::string &member, + bool is_npc ) +{ + units::energy min_power; + assign( jo, member, min_power, false, 0_kJ ); + condition = [min_power, is_npc]( const T & d ) { + return d.actor( is_npc )->power_cur() >= min_power; + }; +} + template conditional_t::conditional_t( const JsonObject &jo ) { @@ -1120,8 +1131,12 @@ conditional_t::conditional_t( const JsonObject &jo ) set_has_wielded_with_flag( jo, "npc_has_wielded_with_flag", is_npc ); } else if( jo.has_member( "u_has_pain" ) ) { set_has_pain( jo, "u_has_pain" ); - } else if( jo.has_int( "npc_has_pain" ) ) { + } else if( jo.has_member( "npc_has_pain" ) ) { set_has_pain( jo, "npc_has_pain", is_npc ); + } else if( jo.has_member( "u_has_power" ) ) { + set_has_power( jo, "u_has_power" ); + } else if( jo.has_member( "npc_has_power" ) ) { + set_has_power( jo, "npc_has_power", is_npc ); } else if( jo.has_string( "is_weather" ) ) { set_is_weather( jo ); } else { diff --git a/src/condition.h b/src/condition.h index 25af633754c12..6c72715de9b9c 100644 --- a/src/condition.h +++ b/src/condition.h @@ -46,7 +46,7 @@ const std::unordered_set complex_conds = { { "u_compare_time_since_var", "npc_compare_time_since_var", "is_weather", "one_in_chance", "is_temperature", "is_windpower", "is_humidity", "is_pressure", "u_is_height", "npc_is_height", "u_has_worn_with_flag", "npc_has_worn_with_flag", "u_has_wielded_with_flag", "npc_has_wielded_with_flag", - "u_has_pain", "npc_has_pain" + "u_has_pain", "npc_has_pain", "u_has_power", "npc_has_power" } }; } // namespace dialogue_data @@ -92,6 +92,7 @@ struct conditional_t { void set_has_intelligence( const JsonObject &jo, const std::string &member, bool is_npc = false ); void set_has_perception( const JsonObject &jo, const std::string &member, bool is_npc = false ); void set_has_pain( const JsonObject &jo, const std::string &member, bool is_npc = false ); + void set_has_power( const JsonObject &jo, const std::string &member, bool is_npc = false ); void set_one_in_chance( const JsonObject &jo, const std::string &member ); void set_is_temperature( const JsonObject &jo, const std::string &member ); void set_is_height( const JsonObject &jo, const std::string &member, bool is_npc = false ); diff --git a/src/dialogue.h b/src/dialogue.h index 65c1a4fe8bb64..fff739417b6ca 100644 --- a/src/dialogue.h +++ b/src/dialogue.h @@ -102,6 +102,7 @@ struct talk_effect_fun_t { void set_message( const JsonObject &jo, const std::string &member ); void set_mod_pain( const JsonObject &jo, const std::string &member, bool is_npc ); void set_add_wet( const JsonObject &jo, const std::string &member, bool is_npc ); + void set_add_power( const JsonObject &jo, const std::string &member, bool is_npc ); void set_sound_effect( const JsonObject &jo, const std::string &member ); void set_add_var( const JsonObject &jo, const std::string &member, bool is_npc = false ); void set_remove_var( const JsonObject &jo, const std::string &member, bool is_npc = false ); diff --git a/src/npctalk.cpp b/src/npctalk.cpp index 9596f70fb7af4..f3f4147976906 100644 --- a/src/npctalk.cpp +++ b/src/npctalk.cpp @@ -2154,24 +2154,44 @@ void talk_effect_fun_t::set_add_wet( const JsonObject &jo, const std::string &me void talk_effect_fun_t::set_sound_effect( const JsonObject &jo, const std::string &member ) { - std::string sound_effect = jo.get_string( member ); + std::string variant = jo.get_string( member ); + std::string id = jo.get_string( "id" ); const bool outdoor_event = jo.get_bool( "outdoor_event", false ); - function = [sound_effect, outdoor_event]( const dialogue & d ) { + const int volume = jo.get_int( "volume", -1 ); + function = [variant, id, outdoor_event, volume]( const dialogue & d ) { map &here = get_map(); - + int local_volume = volume; Character *target = d.alpha->get_character(); if( target && !target->has_effect( effect_sleep ) && !target->is_deaf() ) { if( !outdoor_event || here.get_abs_sub().z >= 0 ) { - sfx::play_variant_sound( "environment", sound_effect, 80, random_direction() ); + if( local_volume == -1 ) { + local_volume = 80; + } + sfx::play_variant_sound( id, variant, local_volume, random_direction() ); } else if( one_in( std::max( roll_remainder( 2.0f * here.get_abs_sub().z / target->mutation_value( "hearing_modifier" ) ), 1 ) ) ) { - sfx::play_variant_sound( "environment", sound_effect, - ( 80 * target->mutation_value( "hearing_modifier" ) ), random_direction() ); + if( local_volume == -1 ) { + local_volume = 80 * target->mutation_value( "hearing_modifier" ); + } + sfx::play_variant_sound( id, variant, local_volume, random_direction() ); } } }; } +void talk_effect_fun_t::set_add_power( const JsonObject &jo, const std::string &member, + bool is_npc ) +{ + units::energy amount; + assign( jo, member, amount, false ); + function = [is_npc, amount]( const dialogue & d ) { + Character *target = d.actor( is_npc )->get_character(); + if( target ) { + target->mod_power_level( amount ); + } + }; +} + void talk_effect_t::set_effect_consequence( const talk_effect_fun_t &fun, dialogue_consequence con ) { @@ -2421,6 +2441,10 @@ void talk_effect_t::parse_sub_effect( const JsonObject &jo ) subeffect_fun.set_add_wet( jo, "u_add_wet", false ); } else if( jo.has_int( "npc_add_wet" ) ) { subeffect_fun.set_add_wet( jo, "npc_add_wet", true ); + } else if( jo.has_member( "u_add_power" ) ) { + subeffect_fun.set_add_power( jo, "u_add_power", false ); + } else if( jo.has_member( "npc_add_power" ) ) { + subeffect_fun.set_add_power( jo, "npc_add_power", true ); } else { jo.throw_error( "invalid sub effect syntax: " + jo.str() ); } diff --git a/src/suffer.cpp b/src/suffer.cpp index 74998c2c59adf..e484c08a01984 100644 --- a/src/suffer.cpp +++ b/src/suffer.cpp @@ -62,7 +62,6 @@ static const bionic_id bio_dis_acid( "bio_dis_acid" ); static const bionic_id bio_dis_shock( "bio_dis_shock" ); -static const bionic_id bio_drain( "bio_drain" ); static const bionic_id bio_geiger( "bio_geiger" ); static const bionic_id bio_gills( "bio_gills" ); static const bionic_id bio_glowy( "bio_glowy" ); @@ -1183,11 +1182,6 @@ void Character::suffer_from_bad_bionics() sfx::play_variant_sound( "bionics", "acid_discharge", 100 ); sfx::do_player_death_hurt( get_player_character(), false ); } - if( has_bionic( bio_drain ) && get_power_level() > 24_kJ && one_turn_in( 1_hours ) ) { - add_msg_if_player( m_bad, _( "Your batteries discharge slightly." ) ); - mod_power_level( -25_kJ ); - sfx::play_variant_sound( "bionics", "elec_crackle_low", 100 ); - } if( has_bionic( bio_noise ) && one_turn_in( 50_minutes ) && !has_effect( effect_narcosis ) ) { // TODO: NPCs with said bionic diff --git a/src/talker.h b/src/talker.h index c7f1655461fb9..a548cc95274d7 100644 --- a/src/talker.h +++ b/src/talker.h @@ -324,5 +324,8 @@ class talker virtual bool wielded_with_flag( const flag_id & ) const { return false; } + virtual units::energy power_cur() const { + return 0_kJ; + } }; #endif // CATA_SRC_TALKER_H diff --git a/src/talker_character.cpp b/src/talker_character.cpp index ab6f12029ed57..b233df97b98a0 100644 --- a/src/talker_character.cpp +++ b/src/talker_character.cpp @@ -292,7 +292,7 @@ void talker_character::shout( const std::string &speech, bool order ) { me_chr->shout( speech, order ); } -\ + int talker_character::pain_cur() const { return me_chr->get_pain(); @@ -312,3 +312,9 @@ bool talker_character::wielded_with_flag( const flag_id &flag ) const { return me_chr->weapon.has_flag( flag ); } + +units::energy talker_character::power_cur() const +{ + return me_chr->get_power_level(); +} + diff --git a/src/talker_character.h b/src/talker_character.h index bc0fb7f38a914..782c0ca41483b 100644 --- a/src/talker_character.h +++ b/src/talker_character.h @@ -56,6 +56,7 @@ class talker_character: public talker int int_cur() const override; int per_cur() const override; int pain_cur() const override; + units::energy power_cur() const override; bool has_trait( const trait_id &trait_to_check ) const override; void set_mutation( const trait_id &new_trait ) override; void unset_mutation( const trait_id &old_trait ) override; From 4043465c00bf15e8538d6b55e791e57b00d41df6 Mon Sep 17 00:00:00 2001 From: LaVeyanFiend <51099123+LaVeyanFiend@users.noreply.github.com> Date: Tue, 6 Apr 2021 09:09:00 -0400 Subject: [PATCH 125/453] Mutations + Bionics: The Cancelling (#47117) --- data/json/bionics.json | 300 ++++++++++++++++++++++++++++++++++++++++- 1 file changed, 293 insertions(+), 7 deletions(-) diff --git a/data/json/bionics.json b/data/json/bionics.json index fe45fec392185..4b41eb3ed56a4 100644 --- a/data/json/bionics.json +++ b/data/json/bionics.json @@ -46,7 +46,78 @@ "bash_protec": [ [ "arm_l", 3 ], [ "arm_r", 3 ] ], "cut_protec": [ [ "arm_l", 3 ], [ "arm_r", 3 ] ], "bullet_protec": [ [ "arm_l", 3 ], [ "arm_r", 3 ] ], - "flags": [ "BIONIC_NPC_USABLE", "BIONIC_SHOCKPROOF" ] + "flags": [ "BIONIC_NPC_USABLE", "BIONIC_SHOCKPROOF" ], + "mutation_conflicts": [ + "THICKSKIN", + "THINSKIN", + "ALBINO", + "SKIN_ROUGH", + "M_SKIN", + "M_SKIN2", + "M_SKIN3", + "SCALES", + "THICK_SCALES", + "SLEEK_SCALES", + "FEATHERS", + "DOWN", + "LIGHTFUR", + "FUR", + "URSINE_FUR", + "LUPINE_FUR", + "FELINE_FUR", + "LYNX_FUR", + "CHITIN", + "CHITIN2", + "CHITIN3", + "CHITIN_FUR", + "CHITIN_FUR2", + "CHITIN_FUR3", + "CF_HAIR", + "SPINES", + "QUILLS", + "BARBS", + "PLANTSKIN", + "BARK", + "THORNS", + "LEAVES", + "LEAVES2", + "LEAVES3", + "SLIMY", + "VISCOUS", + "AMORPHOUS", + "BENDY1", + "BENDY2", + "BENDY3", + "WINGS_BIRD", + "WINGS_INSECT", + "LARGE", + "LARGE_OK", + "HUGE", + "HUGE_OK", + "SMALL", + "SMALL2", + "SMALL_OK", + "WINGS_STUB", + "WINGS_BAT", + "WINGS_BUTTERFLY", + "PALE", + "SPOTS", + "SUNBURN", + "SORES", + "CHLOROMORPH", + "ARM_FEATHERS", + "INSECT_ARMS", + "INSECT_ARMS_OK", + "ARACHNID_ARMS", + "ARACHNID_ARMS_OK", + "ARM_TENTACLES", + "ARM_TENTACLES_4", + "ARM_TENTACLES_8", + "CLAWS_TENTACLES", + "ACIDPROOF", + "TOXICFLESH", + "FRESHWATEROSMOSIS" + ] }, { "id": "bio_armor_eyes", @@ -58,7 +129,7 @@ "bash_protec": [ [ "eyes", 3 ] ], "cut_protec": [ [ "eyes", 3 ] ], "bullet_protec": [ [ "eyes", 3 ] ], - "flags": [ "BIONIC_NPC_USABLE", "BIONIC_SHOCKPROOF" ], + "mutation_conflicts": [ "COMPOUND_EYES", "CEPH_VISION", "CEPH_EYES", "EYEBULGE" ], "social_modifiers": { "intimidate": 10 } }, { @@ -70,7 +141,85 @@ "bash_protec": [ [ "head", 3 ] ], "cut_protec": [ [ "head", 3 ] ], "bullet_protec": [ [ "head", 3 ] ], - "flags": [ "BIONIC_NPC_USABLE", "BIONIC_SHOCKPROOF" ] + "flags": [ "BIONIC_NPC_USABLE", "BIONIC_SHOCKPROOF" ], + "mutation_conflicts": [ + "THICKSKIN", + "THINSKIN", + "ALBINO", + "SKIN_ROUGH", + "M_SKIN", + "M_SKIN2", + "M_SKIN3", + "SCALES", + "THICK_SCALES", + "SLEEK_SCALES", + "FEATHERS", + "DOWN", + "LIGHTFUR", + "FUR", + "URSINE_FUR", + "LUPINE_FUR", + "FELINE_FUR", + "LYNX_FUR", + "CHITIN", + "CHITIN2", + "CHITIN3", + "CHITIN_FUR", + "CHITIN_FUR2", + "CHITIN_FUR3", + "CF_HAIR", + "SPINES", + "QUILLS", + "BARBS", + "PLANTSKIN", + "BARK", + "THORNS", + "LEAVES", + "LEAVES2", + "LEAVES3", + "SLIMY", + "VISCOUS", + "AMORPHOUS", + "LARGE", + "LARGE_OK", + "HUGE", + "HUGE_OK", + "SMALL", + "SMALL2", + "SMALL_OK", + "PALE", + "SPOTS", + "SUNBURN", + "SORES", + "CHLOROMORPH", + "ACIDPROOF", + "TOXICFLESH", + "FRESHWATEROSMOSIS", + "BIOLUM0", + "BIOLUM0_active", + "BIOLUM1", + "BIOLUM1_active", + "BIOLUM2", + "BIOLUM2_active", + "GILLS", + "GILLS_CEPH", + "FLOWERS", + "ROSEBUDS", + "HORNS", + "HORNS_CURLED", + "HORNS_POINTED", + "ANTLERS", + "ANTENNAE", + "HEADBUMPS", + "HAIRROOTS", + "SNOUT", + "MINOTAUR", + "MUZZLE", + "MUZZLE_BEAR", + "MUZZLE_RAT", + "MUZZLE_LONG", + "PROBISCIS" + ] }, { "id": "bio_armor_legs", @@ -81,7 +230,76 @@ "bash_protec": [ [ "leg_l", 3 ], [ "leg_r", 3 ] ], "cut_protec": [ [ "leg_l", 3 ], [ "leg_r", 3 ] ], "bullet_protec": [ [ "leg_l", 3 ], [ "leg_r", 3 ] ], - "flags": [ "BIONIC_NPC_USABLE", "BIONIC_SHOCKPROOF" ] + "flags": [ "BIONIC_NPC_USABLE", "BIONIC_SHOCKPROOF" ], + "mutation_conflicts": [ + "THICKSKIN", + "THINSKIN", + "ALBINO", + "SKIN_ROUGH", + "M_SKIN", + "M_SKIN2", + "M_SKIN3", + "SCALES", + "THICK_SCALES", + "SLEEK_SCALES", + "FEATHERS", + "DOWN", + "LIGHTFUR", + "FUR", + "URSINE_FUR", + "LUPINE_FUR", + "FELINE_FUR", + "LYNX_FUR", + "CHITIN", + "CHITIN2", + "CHITIN3", + "CHITIN_FUR", + "CHITIN_FUR2", + "CHITIN_FUR3", + "CF_HAIR", + "SPINES", + "QUILLS", + "BARBS", + "PLANTSKIN", + "BARK", + "THORNS", + "LEAVES", + "LEAVES2", + "LEAVES3", + "SLIMY", + "VISCOUS", + "AMORPHOUS", + "BENDY1", + "BENDY2", + "BENDY3", + "LARGE", + "LARGE_OK", + "HUGE", + "HUGE_OK", + "SMALL", + "SMALL2", + "SMALL_OK", + "PALE", + "SPOTS", + "SUNBURN", + "SORES", + "CHLOROMORPH", + "ACIDPROOF", + "TOXICFLESH", + "FRESHWATEROSMOSIS", + "TAIL_STUB", + "TAIL_FIN", + "TAIL_LONG", + "TAIL_CATTLE", + "TAIL_RAT", + "TAIL_THICK", + "TAIL_RAPTOR", + "TAIL_FLUFFY", + "TAIL_STING", + "TAIL_CLUB", + "LEG_TENTACLES", + "LEG_TENT_BRACE" + ] }, { "id": "bio_armor_torso", @@ -92,7 +310,73 @@ "bash_protec": [ [ "torso", 3 ] ], "cut_protec": [ [ "torso", 3 ] ], "bullet_protec": [ [ "torso", 3 ] ], - "flags": [ "BIONIC_NPC_USABLE", "BIONIC_SHOCKPROOF" ] + "flags": [ "BIONIC_NPC_USABLE", "BIONIC_SHOCKPROOF" ], + "canceled_mutations": [ "VINES1", "VINES2", "VINES3" ], + "mutation_conflicts": [ + "THICKSKIN", + "THINSKIN", + "ALBINO", + "SKIN_ROUGH", + "M_SKIN", + "M_SKIN2", + "M_SKIN3", + "SCALES", + "THICK_SCALES", + "SLEEK_SCALES", + "FEATHERS", + "DOWN", + "LIGHTFUR", + "FUR", + "URSINE_FUR", + "LUPINE_FUR", + "FELINE_FUR", + "LYNX_FUR", + "CHITIN", + "CHITIN2", + "CHITIN3", + "CHITIN_FUR", + "CHITIN_FUR2", + "CHITIN_FUR3", + "CF_HAIR", + "SPINES", + "QUILLS", + "BARBS", + "PLANTSKIN", + "BARK", + "THORNS", + "LEAVES", + "LEAVES2", + "LEAVES3", + "SLIMY", + "VISCOUS", + "AMORPHOUS", + "BENDY1", + "BENDY2", + "BENDY3", + "LARGE", + "LARGE_OK", + "HUGE", + "HUGE_OK", + "SMALL", + "SMALL2", + "SMALL_OK", + "PALE", + "SPOTS", + "SUNBURN", + "SORES", + "CHLOROMORPH", + "ACIDPROOF", + "TOXICFLESH", + "FRESHWATEROSMOSIS", + "INK_GLANDS", + "INSECT_ARMS", + "INSECT_ARMS_OK", + "ARACHNID_ARMS", + "ARACHNID_ARMS_OK", + "CLAWS_TENTACLES", + "SHELL", + "SHELL2" + ] }, { "id": "bio_batteries", @@ -1133,7 +1417,8 @@ "name": { "str": "Joint Servo" }, "description": "Your leg joints have been equipped with servomotors that provide power-assisted movement. They are optimized for running, but walking also requires less effort when this bionic is online. However, when it's offline it will hamper your movement, as you struggle against its moving parts.", "occupied_bodyparts": [ [ "leg_l", 12 ], [ "leg_r", 12 ] ], - "flags": [ "BIONIC_TOGGLED" ] + "flags": [ "BIONIC_TOGGLED" ], + "mutation_conflicts": [ "LEG_TENTACLES", "LEG_TENT_BRACE" ] }, { "id": "bio_trip", @@ -1169,7 +1454,8 @@ "description": "You will likely spend the rest of your days serving as a walking testament to why you don't opt for the Autodoc's 'Cyborg Identity Package'. A remodulator unit jammed down your throat has given you a creepy robot voice.", "occupied_bodyparts": [ [ "torso", 2 ], [ "mouth", 1 ] ], "flags": [ "BIONIC_FAULTY" ], - "social_modifiers": { "persuade": -20, "lie": 10, "intimidate": 20 } + "social_modifiers": { "persuade": -20, "lie": 10, "intimidate": 20 }, + "canceled_mutations": [ "GROWL", "SNARL", "HISS" ] }, { "id": "bio_watch", From 4b3c89d8a97d6d473475f1a341ff4bd22f186a2f Mon Sep 17 00:00:00 2001 From: Shadestyle <35916758+Shadestyle@users.noreply.github.com> Date: Tue, 6 Apr 2021 13:00:54 -0500 Subject: [PATCH 126/453] Add Underground Pit Digging (#47943) --- data/json/construction.json | 12 +++ data/json/construction_group.json | 5 ++ .../recipe_modular_canteen_common.json | 12 +-- .../recipe_modular_field_common.json | 8 +- .../recipe_modular_field_defenses.json | 80 +++++++++++++------ .../basecamps/recipe_primitive_field.json | 40 +++++++--- 6 files changed, 111 insertions(+), 46 deletions(-) diff --git a/data/json/construction.json b/data/json/construction.json index e4ce08cf227ef..f9cc53d26823a 100644 --- a/data/json/construction.json +++ b/data/json/construction.json @@ -59,6 +59,18 @@ "pre_terrain": "t_pit", "post_terrain": "t_pit_glass" }, + { + "type": "construction", + "id": "constr_pit_underground", + "group": "underground_pit", + "category": "DIG", + "qualities": [ [ { "id": "DIG", "level": 2 } ] ], + "required_skills": [ [ "survival", 3 ] ], + "time": "300 m", + "tools": [ [ [ "pickaxe", -1 ], [ "jackhammer", 140 ], [ "elec_jackhammer", 7000 ] ] ], + "pre_terrain": "t_rock_floor", + "post_terrain": "t_pit" + }, { "type": "construction", "id": "constr_chop_trunk", diff --git a/data/json/construction_group.json b/data/json/construction_group.json index e70f44cdf54a2..919aad6e06529 100644 --- a/data/json/construction_group.json +++ b/data/json/construction_group.json @@ -844,6 +844,11 @@ "id": "dig_a_deep_pit", "name": "Dig a Deep Pit" }, + { + "type": "construction_group", + "id": "underground_pit", + "name": "Dig a Deep Pit Underground" + }, { "type": "construction_group", "id": "dig_a_shallow_pit", diff --git a/data/json/recipes/basecamps/recipe_modular_canteen/recipe_modular_canteen_common.json b/data/json/recipes/basecamps/recipe_modular_canteen/recipe_modular_canteen_common.json index 9b0bf13067490..295a53a00ce0f 100644 --- a/data/json/recipes/basecamps/recipe_modular_canteen/recipe_modular_canteen_common.json +++ b/data/json/recipes/basecamps/recipe_modular_canteen/recipe_modular_canteen_common.json @@ -175,19 +175,19 @@ "blueprint_provides": [ { "id": "fbmk_pantry_furniture" }, { "id": "pantry" } ], "blueprint_excludes": [ { "id": "fbmk_pantry_furniture" } ], "blueprint_needs": { - "time": "1 d 4 h 20 m", - "skills": [ [ "cooking", 3 ], [ "fabrication", 4 ], [ "survival", 4 ] ], + "time": "1 d 9 h 20 m", + "skills": [ [ "survival", 4 ], [ "fabrication", 4 ], [ "cooking", 3 ] ], "inline": { - "tools": [ ], + "tools": [ [ [ "elec_jackhammer", 14000 ], [ "jackhammer", 280 ], [ "pickaxe", -1 ] ] ], "qualities": [ [ { "id": "DIG", "level": 2 } ], [ { "id": "HAMMER", "level": 2 } ], [ { "id": "SAW_W" } ] ], "components": [ [ [ "2x4", 112 ] ], - [ [ "wood_sheet", 24 ], [ "wood_panel", 48 ] ], + [ [ "brick", 80 ], [ "rock", 80 ] ], [ [ "nail", 504 ] ], [ [ "sheet_metal_small", 24 ] ], + [ [ "straw_pile", 24 ], [ "withered", 24 ] ], [ [ "water_faucet", 2 ] ], - [ [ "rock", 80 ], [ "brick", 80 ] ], - [ [ "withered", 24 ], [ "straw_pile", 24 ] ] + [ [ "wood_panel", 48 ], [ "wood_sheet", 24 ] ] ] } } diff --git a/data/json/recipes/basecamps/recipe_modular_field_common.json b/data/json/recipes/basecamps/recipe_modular_field_common.json index 83877967fef30..97a42204ed3f1 100644 --- a/data/json/recipes/basecamps/recipe_modular_field_common.json +++ b/data/json/recipes/basecamps/recipe_modular_field_common.json @@ -897,12 +897,12 @@ "blueprint_provides": [ { "id": "pantry" } ], "blueprint_requires": [ { "id": "fbmh_northeast", "amount": 4 }, { "id": "fbmh_fire_northeast" }, { "id": "fbmh_bed2_northeast" } ], "blueprint_needs": { - "time": "4 h 40 m", - "skills": [ [ "fabrication", 4 ], [ "survival", 4 ] ], + "time": "7 h 10 m", + "skills": [ [ "survival", 4 ], [ "fabrication", 4 ] ], "inline": { - "tools": [ ], + "tools": [ [ [ "elec_jackhammer", 7000 ], [ "jackhammer", 140 ], [ "pickaxe", -1 ] ] ], "qualities": [ [ { "id": "DIG", "level": 2 } ], [ { "id": "HAMMER", "level": 2 } ] ], - "components": [ [ [ "rock", 40 ], [ "brick", 40 ] ], [ [ "2x4", 6 ], [ "stick", 6 ] ], [ [ "withered", 12 ], [ "straw_pile", 12 ] ] ] + "components": [ [ [ "2x4", 6 ], [ "stick", 6 ] ], [ [ "brick", 40 ], [ "rock", 40 ] ], [ [ "straw_pile", 12 ], [ "withered", 12 ] ] ] } } }, diff --git a/data/json/recipes/basecamps/recipe_modular_field_defenses.json b/data/json/recipes/basecamps/recipe_modular_field_defenses.json index 20af1b5d800d4..b1df09f3d343b 100644 --- a/data/json/recipes/basecamps/recipe_modular_field_defenses.json +++ b/data/json/recipes/basecamps/recipe_modular_field_defenses.json @@ -14,9 +14,13 @@ "blueprint_requires": [ { "id": "fbmh_northeast", "amount": 4 }, { "id": "fbmh_fire_northeast" }, { "id": "fbmh_bed2_northeast" } ], "blueprint_excludes": [ { "id": "fbm_no_dig" } ], "blueprint_needs": { - "time": "1 d 21 h", - "skills": [ [ "survival", 1 ] ], - "inline": { "tools": [ ], "qualities": [ [ { "id": "DIG", "level": 2 } ] ], "components": [ ] } + "time": "3 d 18 h", + "skills": [ [ "survival", 3 ] ], + "inline": { + "tools": [ [ [ "elec_jackhammer", 126000 ], [ "jackhammer", 2520 ], [ "pickaxe", -1 ] ] ], + "qualities": [ [ { "id": "DIG", "level": 2 } ] ], + "components": [ ] + } } }, { @@ -34,9 +38,13 @@ "blueprint_requires": [ { "id": "fbmh_northeast", "amount": 4 }, { "id": "fbmh_fire_northeast" }, { "id": "fbmh_bed2_northeast" } ], "blueprint_excludes": [ { "id": "fbm_no_dig" } ], "blueprint_needs": { - "time": "1 d 21 h", - "skills": [ [ "survival", 1 ] ], - "inline": { "tools": [ ], "qualities": [ [ { "id": "DIG", "level": 2 } ] ], "components": [ ] } + "time": "3 d 18 h", + "skills": [ [ "survival", 3 ] ], + "inline": { + "tools": [ [ [ "elec_jackhammer", 126000 ], [ "jackhammer", 2520 ], [ "pickaxe", -1 ] ] ], + "qualities": [ [ { "id": "DIG", "level": 2 } ] ], + "components": [ ] + } } }, { @@ -54,9 +62,13 @@ "blueprint_requires": [ { "id": "fbmh_northeast", "amount": 4 }, { "id": "fbmh_fire_northeast" }, { "id": "fbmh_bed2_northeast" } ], "blueprint_excludes": [ { "id": "fbm_no_dig" }, { "id": "fbmh_trench_northeast" }, { "id": "fbmh_trench_east" } ], "blueprint_needs": { - "time": "12 h 30 m", - "skills": [ [ "survival", 1 ] ], - "inline": { "tools": [ ], "qualities": [ [ { "id": "DIG", "level": 2 } ] ], "components": [ ] } + "time": "1 d 1 h", + "skills": [ [ "survival", 3 ] ], + "inline": { + "tools": [ [ [ "elec_jackhammer", 35000 ], [ "jackhammer", 700 ], [ "pickaxe", -1 ] ] ], + "qualities": [ [ { "id": "DIG", "level": 2 } ] ], + "components": [ ] + } } }, { @@ -74,9 +86,13 @@ "blueprint_requires": [ { "id": "fbmh_northeast", "amount": 4 }, { "id": "fbmh_fire_northeast" }, { "id": "fbmh_bed2_northeast" } ], "blueprint_excludes": [ { "id": "fbm_no_dig" }, { "id": "fbmh_trench_northwest" }, { "id": "fbmh_trench_west" } ], "blueprint_needs": { - "time": "12 h 30 m", - "skills": [ [ "survival", 1 ] ], - "inline": { "tools": [ ], "qualities": [ [ { "id": "DIG", "level": 2 } ] ], "components": [ ] } + "time": "1 d 1 h", + "skills": [ [ "survival", 3 ] ], + "inline": { + "tools": [ [ [ "elec_jackhammer", 35000 ], [ "jackhammer", 700 ], [ "pickaxe", -1 ] ] ], + "qualities": [ [ { "id": "DIG", "level": 2 } ] ], + "components": [ ] + } } }, { @@ -94,9 +110,13 @@ "blueprint_requires": [ { "id": "fbmh_northeast", "amount": 4 }, { "id": "fbmh_fire_northeast" }, { "id": "fbmh_bed2_northeast" } ], "blueprint_excludes": [ { "id": "fbm_no_dig" }, { "id": "fbmh_trench_southeast" }, { "id": "fbmh_trench_east" } ], "blueprint_needs": { - "time": "12 h 30 m", - "skills": [ [ "survival", 1 ] ], - "inline": { "tools": [ ], "qualities": [ [ { "id": "DIG", "level": 2 } ] ], "components": [ ] } + "time": "1 d 1 h", + "skills": [ [ "survival", 3 ] ], + "inline": { + "tools": [ [ [ "elec_jackhammer", 35000 ], [ "jackhammer", 700 ], [ "pickaxe", -1 ] ] ], + "qualities": [ [ { "id": "DIG", "level": 2 } ] ], + "components": [ ] + } } }, { @@ -114,9 +134,13 @@ "blueprint_requires": [ { "id": "fbmh_northeast", "amount": 4 }, { "id": "fbmh_fire_northeast" }, { "id": "fbmh_bed2_northeast" } ], "blueprint_excludes": [ { "id": "fbm_no_dig" }, { "id": "fbmh_trench_southwest" }, { "id": "fbmh_trench_west" } ], "blueprint_needs": { - "time": "12 h 30 m", - "skills": [ [ "survival", 1 ] ], - "inline": { "tools": [ ], "qualities": [ [ { "id": "DIG", "level": 2 } ] ], "components": [ ] } + "time": "1 d 1 h", + "skills": [ [ "survival", 3 ] ], + "inline": { + "tools": [ [ [ "elec_jackhammer", 35000 ], [ "jackhammer", 700 ], [ "pickaxe", -1 ] ] ], + "qualities": [ [ { "id": "DIG", "level": 2 } ] ], + "components": [ ] + } } }, { @@ -134,9 +158,13 @@ "blueprint_requires": [ { "id": "fbmh_northeast", "amount": 4 }, { "id": "fbmh_fire_northeast" }, { "id": "fbmh_bed2_northeast" } ], "blueprint_excludes": [ { "id": "fbm_no_dig" }, { "id": "fbmh_trench_southeast" }, { "id": "fbmh_trench_northeast" } ], "blueprint_needs": { - "time": "2 d 22 h", - "skills": [ [ "survival", 1 ] ], - "inline": { "tools": [ ], "qualities": [ [ { "id": "DIG", "level": 2 } ] ], "components": [ ] } + "time": "5 d 20 h", + "skills": [ [ "survival", 3 ] ], + "inline": { + "tools": [ [ [ "elec_jackhammer", 196000 ], [ "jackhammer", 3920 ], [ "pickaxe", -1 ] ] ], + "qualities": [ [ { "id": "DIG", "level": 2 } ] ], + "components": [ ] + } } }, { @@ -154,9 +182,13 @@ "blueprint_requires": [ { "id": "fbmh_northeast", "amount": 4 }, { "id": "fbmh_fire_northeast" }, { "id": "fbmh_bed2_northeast" } ], "blueprint_excludes": [ { "id": "fbm_no_dig" }, { "id": "fbmh_trench_southwest" }, { "id": "fbmh_trench_northwest" } ], "blueprint_needs": { - "time": "2 d 22 h", - "skills": [ [ "survival", 1 ] ], - "inline": { "tools": [ ], "qualities": [ [ { "id": "DIG", "level": 2 } ] ], "components": [ ] } + "time": "5 d 20 h", + "skills": [ [ "survival", 3 ] ], + "inline": { + "tools": [ [ [ "elec_jackhammer", 196000 ], [ "jackhammer", 3920 ], [ "pickaxe", -1 ] ] ], + "qualities": [ [ { "id": "DIG", "level": 2 } ] ], + "components": [ ] + } } } ] diff --git a/data/json/recipes/basecamps/recipe_primitive_field.json b/data/json/recipes/basecamps/recipe_primitive_field.json index 28900960bfc0f..f0f3fe4b20c45 100644 --- a/data/json/recipes/basecamps/recipe_primitive_field.json +++ b/data/json/recipes/basecamps/recipe_primitive_field.json @@ -508,9 +508,13 @@ "time": "180 m", "blueprint_requires": [ { "id": "not_an_upgrade" } ], "blueprint_needs": { - "time": "5 h", - "skills": [ [ "survival", 1 ] ], - "inline": { "tools": [ ], "qualities": [ [ { "id": "DIG", "level": 2 } ] ], "components": [ ] } + "time": "10 h", + "skills": [ [ "survival", 3 ] ], + "inline": { + "tools": [ [ [ "elec_jackhammer", 14000 ], [ "jackhammer", 280 ], [ "pickaxe", -1 ] ] ], + "qualities": [ [ { "id": "DIG", "level": 2 } ] ], + "components": [ ] + } } }, { @@ -604,9 +608,13 @@ "time": "180 m", "blueprint_requires": [ { "id": "not_an_upgrade" } ], "blueprint_needs": { - "time": "15 h", - "skills": [ [ "survival", 1 ] ], - "inline": { "tools": [ ], "qualities": [ [ { "id": "DIG", "level": 2 } ] ], "components": [ ] } + "time": "1 d 6 h", + "skills": [ [ "survival", 3 ] ], + "inline": { + "tools": [ [ [ "elec_jackhammer", 42000 ], [ "jackhammer", 840 ], [ "pickaxe", -1 ] ] ], + "qualities": [ [ { "id": "DIG", "level": 2 } ] ], + "components": [ ] + } } }, { @@ -764,9 +772,13 @@ "time": "180 m", "blueprint_requires": [ { "id": "not_an_upgrade" } ], "blueprint_needs": { - "time": "12 h 30 m", - "skills": [ [ "survival", 1 ] ], - "inline": { "tools": [ ], "qualities": [ [ { "id": "DIG", "level": 2 } ] ], "components": [ ] } + "time": "1 d 1 h", + "skills": [ [ "survival", 3 ] ], + "inline": { + "tools": [ [ [ "elec_jackhammer", 35000 ], [ "jackhammer", 700 ], [ "pickaxe", -1 ] ] ], + "qualities": [ [ { "id": "DIG", "level": 2 } ] ], + "components": [ ] + } } }, { @@ -1023,9 +1035,13 @@ "blueprint_requires": [ { "id": "not_an_upgrade" } ], "time": "180 m", "blueprint_needs": { - "time": "15 h", - "skills": [ [ "survival", 1 ] ], - "inline": { "tools": [ ], "qualities": [ [ { "id": "DIG", "level": 2 } ] ], "components": [ ] } + "time": "1 d 6 h", + "skills": [ [ "survival", 3 ] ], + "inline": { + "tools": [ [ [ "elec_jackhammer", 42000 ], [ "jackhammer", 840 ], [ "pickaxe", -1 ] ] ], + "qualities": [ [ { "id": "DIG", "level": 2 } ] ], + "components": [ ] + } } }, { From e9ffc8722d73288cda81f31fdaca56f9cb1d1e8f Mon Sep 17 00:00:00 2001 From: casswedson <58050969+casswedson@users.noreply.github.com> Date: Wed, 7 Apr 2021 03:34:10 -0500 Subject: [PATCH 127/453] Misc typographical fixes (#48346) * misc typographical fixes Co-authored-by: actual-nh <74678550+actual-nh@users.noreply.github.com> --- .../furniture-appliances.json | 2 +- .../furniture-recreation.json | 4 ++-- .../furniture_and_terrain/furniture-roof.json | 2 +- .../furniture-storage.json | 2 +- .../terrain-liquids.json | 4 ++-- .../terrain-windows.json | 20 +++++++++---------- data/json/items/armor/helmets.json | 2 +- data/json/items/armor/legs_armor.json | 6 +++--- data/json/items/armor/torso_armor.json | 4 ++-- data/json/items/armor/torso_clothes.json | 2 +- data/json/items/battery.json | 8 ++++---- data/json/items/gun/flintlock.json | 2 +- data/json/items/gun/shot.json | 4 ++-- data/json/items/tool/cooking.json | 2 +- data/json/monsters/jabberwock.json | 2 +- data/json/monsters/zed_acid.json | 2 +- data/json/monsters/zed_misc.json | 2 +- data/json/proficiencies/tailoring.json | 2 +- 18 files changed, 36 insertions(+), 36 deletions(-) diff --git a/data/json/furniture_and_terrain/furniture-appliances.json b/data/json/furniture_and_terrain/furniture-appliances.json index 905cfba830472..4c225a9d544e4 100644 --- a/data/json/furniture_and_terrain/furniture-appliances.json +++ b/data/json/furniture_and_terrain/furniture-appliances.json @@ -546,7 +546,7 @@ "id": "f_satellite", "name": "large satellite dish", "looks_like": "t_radio_tower", - "description": "A large concave metal panel with simple electronics used to receive signals from sattelites. While the hundreds of expensive machines orbitting the planet will likely continue to function indefinately, their various purposes have all been lost.", + "description": "A large, concave metal panel with simple electronics used to receive signals from satellites. While the hundreds of expensive machines orbiting the planet will likely continue to function indefinitely, their various purposes have all been lost.", "symbol": ")", "color": "white_green", "move_cost_mod": -1, diff --git a/data/json/furniture_and_terrain/furniture-recreation.json b/data/json/furniture_and_terrain/furniture-recreation.json index 7176dd4498e48..52759263e3958 100644 --- a/data/json/furniture_and_terrain/furniture-recreation.json +++ b/data/json/furniture_and_terrain/furniture-recreation.json @@ -123,7 +123,7 @@ "type": "furniture", "id": "f_arcade_machine", "name": "arcade machine", - "description": "A bulky upright arcade cabinet, brightly painted and slightyly worn with age. Useless for its intended purpose, it's bound to have valuable parts.", + "description": "A bulky upright arcade cabinet, brightly painted and slightly worn with age. Useless for its intended purpose, it's bound to have valuable parts.", "symbol": "6", "color": "red", "move_cost_mod": -1, @@ -211,7 +211,7 @@ "type": "furniture", "id": "f_ergometer", "name": "ergometer", - "description": "An exercise machine with a set of handles and plates meant to emulate rowing a boat. Without power it can't be operated, but it might have useful parts to be scavanged.", + "description": "An exercise machine with a set of handles and plates meant to emulate rowing a boat. Without power it can't be operated, but it might have useful parts to be scavenged.", "symbol": "5", "color": "dark_gray", "move_cost_mod": 2, diff --git a/data/json/furniture_and_terrain/furniture-roof.json b/data/json/furniture_and_terrain/furniture-roof.json index 372a2787c682d..e58575b943e9a 100644 --- a/data/json/furniture_and_terrain/furniture-roof.json +++ b/data/json/furniture_and_terrain/furniture-roof.json @@ -123,7 +123,7 @@ "type": "furniture", "id": "f_roof_turbine_vent", "name": "roof turbine vent", - "description": "A rotary wind turbine that will catch the wind and pull out air from inside. It is most commonly used for improving air cicrulation, particularly in poorly-ventilated areas like attics.", + "description": "A rotary wind turbine that will catch the wind and pull out air from inside. It is most commonly used for improving air circulation, particularly in poorly-ventilated areas like attics.", "symbol": "&", "color": "light_gray", "move_cost_mod": 2, diff --git a/data/json/furniture_and_terrain/furniture-storage.json b/data/json/furniture_and_terrain/furniture-storage.json index 65502b26f0ab0..f0949f3ed1c35 100644 --- a/data/json/furniture_and_terrain/furniture-storage.json +++ b/data/json/furniture_and_terrain/furniture-storage.json @@ -1128,7 +1128,7 @@ "type": "furniture", "id": "f_foot_locker", "name": "metal foot locker", - "description": "An metal stoarge box, capable of holding any number of things. The lid has has a small lock.", + "description": "A metal storage box, capable of holding any number of things. The lid has a small lock.", "symbol": "O", "color": "white", "move_cost_mod": -1, diff --git a/data/json/furniture_and_terrain/terrain-liquids.json b/data/json/furniture_and_terrain/terrain-liquids.json index 71d33687f9510..e03220ee8c99a 100644 --- a/data/json/furniture_and_terrain/terrain-liquids.json +++ b/data/json/furniture_and_terrain/terrain-liquids.json @@ -377,7 +377,7 @@ "id": "t_lake_bed_concrete_yellow", "//": "for eventual use with water z levels. Currently non-functional. Cement on the lake floor.", "name": "submerged concrete", - "description": "You are standing at the bottom of a body of fresh water on a pad of concrete with yelllow paint. With a watertight container, you could gather fresh water from here. Not safe to drink as is.", + "description": "You are standing at the bottom of a body of fresh water on a pad of yellow-painted concrete. With a watertight container, you could gather fresh water from here. Not safe to drink as is.", "symbol": "#", "looks_like": "t_pavement_y", "color": "yellow", @@ -397,7 +397,7 @@ "type": "terrain", "id": "t_water_hot", "name": "hot spring water", - "description": "Scalding hot water, not particulary safe for swimming. With a watertight container, you could gather fresh water from here. Not safe to drink as is.", + "description": "Scalding hot water, not particularly safe for swimming. With a watertight container, you could gather fresh water from here. Not safe to drink as is.", "symbol": "~", "color": "light_blue", "move_cost": 5, diff --git a/data/json/furniture_and_terrain/terrain-windows.json b/data/json/furniture_and_terrain/terrain-windows.json index e81066dd1aba7..97d5640b7863e 100644 --- a/data/json/furniture_and_terrain/terrain-windows.json +++ b/data/json/furniture_and_terrain/terrain-windows.json @@ -1581,7 +1581,7 @@ "type": "terrain", "id": "t_reinforced_double_pane_glass", "name": "Reinforced double glazed glass window", - "description": "A reinfoced double glazed window inserted into a frame. The outer layer comprises a pane of reinforced glass for extra security.", + "description": "A reinforced, double-glazed window inserted into a frame. For extra security, the outer layer is reinforced glass.", "looks_like": "t_window_no_curtains", "symbol": "\"", "color": "light_cyan", @@ -2749,7 +2749,7 @@ "type": "terrain", "id": "t_plastic_window_with_curtain", "name": "Plastic window with a curtain", - "description": "A makeshift window with a closed curtain. comprising a sheet of translucent, rigid plastic secured in a wooden frame. There are sheets drawn across it to block the light. It'll do in a pinch.", + "description": "A makeshift window with a closed curtain. It's a sheet of translucent, rigid plastic secured in a wooden frame. There are sheets drawn across it to block the light. It'll do in a pinch.", "looks_like": "t_curtains", "symbol": "|", "color": "light_blue", @@ -2785,7 +2785,7 @@ "type": "terrain", "id": "t_plastic_window_with_curtain_open_window_closed", "name": "Plastic window with a curtain", - "description": "A makeshift window with a opened curtain. comprising a sheet of translucent, rigid plastic secured in a wooden frame, with sheets strung about it to block the light as required. It'll do in a pinch.", + "description": "A makeshift window with a opened curtain. It's a sheet of translucent, rigid plastic secured in a wooden frame, with sheets strung about it to block the light as required. It'll do in a pinch.", "looks_like": "t_window_domestic", "symbol": "|", "color": "light_blue", @@ -2830,8 +2830,8 @@ { "type": "terrain", "id": "t_plastic_window_with_curtain_open", - "name": "Plastic window With a curtain", - "description": "An opened makeshift window with a opened curtain. comprising a sheet of translucent, rigid plastic secured in a wooden frame, with sheets strung about it to block the light as required. It'll do in a pinch.", + "name": "Plastic window with open curtains", + "description": "An open makeshift window with open curtains. It's a sheet of translucent, rigid plastic secured in a wooden frame, with sheets strung about it to block the light as required. It'll do in a pinch.", "looks_like": "t_window_open", "symbol": "|", "color": "light_blue", @@ -2958,7 +2958,7 @@ "type": "terrain", "id": "t_reinforced_plastic_window_with_curtain", "name": "Reinforced plastic window with a curtain", - "description": "A makeshift window with a closed curtain. comprising three sheets of translucent, rigid plastic secured in a wooden frame. It'll do in a pinch.", + "description": "A makeshift reinforced window with a closed curtain. It's three sheets of translucent, rigid plastic secured in a wooden frame. There are sheets drawn across it to block the light. It'll do in a pinch.", "looks_like": "t_curtains", "symbol": "|", "color": "light_blue", @@ -3006,8 +3006,8 @@ { "type": "terrain", "id": "t_reinforced_plastic_window_with_curtain_open_window_closed", - "name": "Reinforced plastic window with a curtain", - "description": "A makeshift window with a opened curtain. comprising three sheets of translucent, rigid plastic secured in a wooden frame. It'll do in a pinch.", + "name": "Reinforced plastic window with an open curtain", + "description": "A makeshift reinforced window with a opened curtain. It's three sheets of translucent, rigid plastic secured in a wooden frame, with sheets strung about it to block the light as required. It'll do in a pinch.", "looks_like": "t_window_domestic", "symbol": "|", "color": "light_blue", @@ -3057,8 +3057,8 @@ { "type": "terrain", "id": "t_reinforced_plastic_window_with_curtain_open", - "name": "Reinforced plastic window With a curtain", - "description": "An open makeshift window with a opened curtain. comprising three sheets of translucent, rigid plastic secured in a wooden frame. It'll do in a pinch.", + "name": "Reinforced plastic window with an open curtain", + "description": "An open makeshift reinforced window with a opened curtain. It's three sheets of translucent, rigid plastic secured in a wooden frame, with sheets strung about it to block the light as required. It'll do in a pinch.", "looks_like": "t_window_open", "symbol": "|", "color": "light_blue", diff --git a/data/json/items/armor/helmets.json b/data/json/items/armor/helmets.json index 3fd0ac7760cbb..82532ac251d44 100644 --- a/data/json/items/armor/helmets.json +++ b/data/json/items/armor/helmets.json @@ -441,7 +441,7 @@ "id": "helmet_skull", "type": "ARMOR", "name": { "str": "large wolf skull" }, - "description": "The top part of an unusually large wolf skull equiped with leather straps to secure it on your head. Every inch of it has been carved with a maze of fine intertwined symbols that make your eyes water.", + "description": "The top part of an unusually large wolf skull equipped with leather straps to secure it on your head. Every inch of it has been carved with a maze of fine intertwined symbols that make your eyes water.", "weight": "1 kg", "volume": "3 L", "price": 1400, diff --git a/data/json/items/armor/legs_armor.json b/data/json/items/armor/legs_armor.json index 045001ad7fd5e..0efcba5f75190 100644 --- a/data/json/items/armor/legs_armor.json +++ b/data/json/items/armor/legs_armor.json @@ -145,7 +145,7 @@ "id": "chaps_cut_resistant", "type": "ARMOR", "name": { "str_sp": "chainsaw chaps" }, - "description": "A pair of tough chaps made of kevlar. Chainsaw kickbacks are potentially fatal; personal protective equipment like these chaps help protect your femoral arteries. The layered kevlar is designed to fray on contact with the chain and bind up the tool.", + "description": "A pair of tough chaps made of Kevlar. Chainsaw kickbacks are potentially fatal; personal protective equipment like these chaps help protect your femoral arteries. The layered Kevlar is designed to fray on contact with the chain and bind up the tool.", "weight": "1519 g", "copy-from": "chaps_leather", "price": 7800, @@ -479,7 +479,7 @@ "type": "ARMOR", "category": "armor", "name": { "str_sp": "EOD trousers" }, - "description": "Thick armored trousers constructed from kevlar and nomex for explosive ordnance disposal. It is designed to protect against overpressure, fragmentation, impact and heat.", + "description": "Thick armored trousers constructed from Kevlar and Nomex for explosive ordnance disposal. They are designed to protect against overpressure, fragmentation, impact, and heat.", "weight": "6400 g", "volume": "12 L", "price": 200000, @@ -499,7 +499,7 @@ "type": "ARMOR", "category": "armor", "name": { "str_sp": "light EOD trousers" }, - "description": "Armored trousers constructed from kevlar and nomex designed to protect against overpressure, fragmentation, impact and heat in hostile environments. It is lighter than normal EOD armor to provide more maneuverability.", + "description": "Armored trousers constructed from Kevlar and Nomex, designed to protect against overpressure, fragmentation, impact, and heat in hostile environments. They are lighter than normal EOD armor to provide more maneuverability.", "weight": "3000 g", "volume": "12 L", "price": 200000, diff --git a/data/json/items/armor/torso_armor.json b/data/json/items/armor/torso_armor.json index b5f148f4ffa85..77e2660c19f8a 100644 --- a/data/json/items/armor/torso_armor.json +++ b/data/json/items/armor/torso_armor.json @@ -512,7 +512,7 @@ "type": "TOOL_ARMOR", "category": "armor", "name": { "str": "EOD jacket" }, - "description": "A thick armored jacket constructed from kevlar and nomex for explosive ordnance disposal. It is designed to protect against overpressure, fragmentation, impact and heat.", + "description": "A thick armored jacket constructed from Kevlar and Nomex for explosive ordnance disposal. It is designed to protect against overpressure, fragmentation, impact, and heat.", "weight": "16300 g", "volume": "15 L", "price": 200000, @@ -533,7 +533,7 @@ "type": "TOOL_ARMOR", "category": "armor", "name": { "str": "light EOD jacket" }, - "description": "An armored jacket constructed from kevlar and nomex designed to protect against overpressure, fragmentation, impact and heat in hostile environments. It is lighter than normal EOD armor to provide more maneuverability and can be worn over ballistic armor.", + "description": "An armored jacket constructed from Kevlar and Nomex, designed to protect against overpressure, fragmentation, impact, and heat in hostile environments. It is lighter than normal EOD armor to provide more maneuverability and can be worn over ballistic armor.", "weight": "7000 g", "volume": "15 L", "price": 200000, diff --git a/data/json/items/armor/torso_clothes.json b/data/json/items/armor/torso_clothes.json index 64d7524d89155..ba59311006616 100644 --- a/data/json/items/armor/torso_clothes.json +++ b/data/json/items/armor/torso_clothes.json @@ -31,7 +31,7 @@ "repairs_like": "apron_leather", "type": "ARMOR", "name": { "str": "cut-resistant apron" }, - "description": "An apron made of kevlar fabric which provides excellent protection from cuts.", + "description": "An apron made of Kevlar fabric which provides excellent protection from cuts.", "copy-from": "apron_leather", "price": 3800, "material": [ "kevlar" ] diff --git a/data/json/items/battery.json b/data/json/items/battery.json index 3d510fff74bea..65e9d435e7dd4 100644 --- a/data/json/items/battery.json +++ b/data/json/items/battery.json @@ -41,7 +41,7 @@ "type": "MAGAZINE", "category": "spare_parts", "name": { "str": "ultra-light plutonium fuel battery", "str_pl": "ultra-light plutonium fuel batteries" }, - "description": "This battery uses a thin plutonium-244 rod to stablize an exotic nanocompound. It is universally compatible with small devices. Although it stores a huge amount of power, it cannot be recharged.", + "description": "This battery uses a thin plutonium-244 rod to stabilize an exotic nanocompound. It is universally compatible with small devices. Although it stores a huge amount of power, it cannot be recharged.", "ascii_picture": "ultra_light_battery_plut", "weight": "80 g", "volume": "1 ml", @@ -201,7 +201,7 @@ "type": "MAGAZINE", "category": "spare_parts", "name": { "str": "medium plutonium fuel battery", "str_pl": "medium plutonium fuel batteries" }, - "description": "This battery uses a thin plutonium-244 rod to stablize an exotic nanocompound. It is universally compatible with all kinds of appliances and power tools. Although it stores a huge amount of power, it cannot be recharged.", + "description": "This battery uses a thin plutonium-244 rod to stabilize an exotic nanocompound. It is universally compatible with all kinds of appliances and power tools. Although it stores a huge amount of power, it cannot be recharged.", "ascii_picture": "medium_battery_plut", "weight": "1000 g", "volume": "525ml", @@ -281,7 +281,7 @@ "type": "MAGAZINE", "category": "spare_parts", "name": { "str": "heavy plutonium fuel battery", "str_pl": "heavy plutonium fuel batteries" }, - "description": "This battery uses a thin plutonium-244 rod to stablize an exotic nanocompound. It is universally compatible with all kinds of industrial-grade equipment and large tools. Although it stores a huge amount of power, it cannot be recharged.", + "description": "This battery uses a thin plutonium-244 rod to stabilize an exotic nanocompound. It is universally compatible with all kinds of industrial-grade equipment and large tools. Although it stores a huge amount of power, it cannot be recharged.", "ascii_picture": "heavy_battery_plut", "weight": "1600 g", "volume": "1500ml", @@ -302,7 +302,7 @@ "type": "MAGAZINE", "category": "spare_parts", "name": { "str": "military plutonium fuel cell" }, - "description": "This battery uses a huge plutonium-244 rod to stablize an exotic nanocompound. It was used in military mech-suits, was highly experimental, and had no civilian applications. Although it stores a stupendous amount of power, it cannot be recharged.", + "description": "This battery uses a huge plutonium-244 rod to stabilize an exotic nanocompound. It was used in military mech-suits, was highly experimental, and had no civilian applications. Although it stores a stupendous amount of power, it cannot be recharged.", "weight": "64000 g", "volume": "30 L", "price": 100000, diff --git a/data/json/items/gun/flintlock.json b/data/json/items/gun/flintlock.json index 9dd5c71b5b305..c971757fd9515 100644 --- a/data/json/items/gun/flintlock.json +++ b/data/json/items/gun/flintlock.json @@ -118,7 +118,7 @@ "copy-from": "rifle_flintlock", "type": "GUN", "name": { "str": "flintlock rifle" }, - "description": "Also called a Pennsylvania rifle, this long barreled rifled flintlock gun has signficantly increased accuracy at the cost of taking even longer to reload.", + "description": "Also called a Pennsylvania rifle, this long-barreled rifled flintlock gun has significantly increased accuracy at the cost of taking even longer to reload.", "weight": "3700 g", "volume": "1700 ml", "longest_side": "1278 mm", diff --git a/data/json/items/gun/shot.json b/data/json/items/gun/shot.json index 9cce99d93b790..a0c1f6dde9f75 100644 --- a/data/json/items/gun/shot.json +++ b/data/json/items/gun/shot.json @@ -74,7 +74,7 @@ "looks_like": "remington_870", "type": "GUN", "name": { "str": "handmade lever shotgun" }, - "description": "A short homemade lever-action shotgun with a small internal tube magazine. While still a primitive pipe and 2x4 design, it is a formiddable shotgun in its own right with room for improvement.", + "description": "A short, homemade lever-action shotgun with a small internal tube magazine. While still a primitive design - made from a pipe and a plank - it is a formidable shotgun in its own right with room for improvement.", "weight": "2311 g", "volume": "2 L", "longest_side": "85 cm", @@ -802,7 +802,7 @@ "copy-from": "shotgun_base", "type": "GUN", "name": { "str": "M1897 Trench Gun" }, - "description": "The Winchester 1897 was one of the first commercially successful pump action shotguns. In its 'trench' configuraton it has become a heavily romanticized American icon of World War 1. With its barrel shroud, bayonet lug and 17 inch bayonet, this shotgun is undeniably fearsome in appearance. There aren't any more trenches to clear, so the next zombie infested town will have to suffice.", + "description": "The Winchester 1897 was one of the first commercially-successful pump-action shotguns. In its 'trench' configuration it has become a heavily-romanticized American icon of World War 1. With its barrel shroud, bayonet lug, and 17 inch bayonet, this shotgun is undeniably fearsome in appearance. There aren't any more trenches to clear, so the next zombie-infested town will have to suffice.", "weight": "3629 g", "volume": "2564 ml", "longest_side": "989 mm", diff --git a/data/json/items/tool/cooking.json b/data/json/items/tool/cooking.json index f5665c1d37823..1113ef3e9c028 100644 --- a/data/json/items/tool/cooking.json +++ b/data/json/items/tool/cooking.json @@ -873,7 +873,7 @@ "type": "GENERIC", "category": "tools", "name": { "str": "sieve" }, - "description": "This is no mere strainer for noodles; it's a sieve used to separate particles of certain sizes. You could use this to do a really good job sifting flour, remove dust and soil from grain, or perhaps conduct gradiation tests for any civil engineers you might know. This one has been constructed from steel mesh.", + "description": "This is no mere strainer for noodles; it's a sieve used to separate particles of certain sizes. You could use this to do a really good job sifting flour, remove dust and soil from grain, or perhaps conduct gradation tests for any civil engineers you might know. This one has been constructed from steel mesh.", "volume": "500 ml", "weight": "318 g", "price": 700, diff --git a/data/json/monsters/jabberwock.json b/data/json/monsters/jabberwock.json index 68c50183c508f..8e49506b21980 100644 --- a/data/json/monsters/jabberwock.json +++ b/data/json/monsters/jabberwock.json @@ -3,7 +3,7 @@ "id": "mon_fleshy_shambler", "type": "MONSTER", "name": { "str": "fleshy shambler" }, - "description": "An amalgamation of throbbing organs from various creatures have fused together into this lurching, vaguely humanoid shape. Its myriad roughly formed mouths sussurate in a chorus of sibilant groans and whispers.", + "description": "An amalgamation of throbbing organs from various creatures have fused together into this lurching, vaguely-humanoid shape. Its myriad roughly-formed mouths susurrate in a chorus of sibilant groans and whispers.", "default_faction": "jabberwock", "species": [ "ABERRATION" ], "volume": "80000 ml", diff --git a/data/json/monsters/zed_acid.json b/data/json/monsters/zed_acid.json index a7c46a911faf7..328abbac67496 100644 --- a/data/json/monsters/zed_acid.json +++ b/data/json/monsters/zed_acid.json @@ -260,7 +260,7 @@ "type": "MONSTER", "copy-from": "mon_zombie_dog_acidic", "name": { "str": "blistered horror" }, - "description": "A huge canine with multiple large foul looking blisters covering its body. A corrosive liquid spills from its menancing-looking mouth.", + "description": "A huge canine with multiple large, foul-looking blisters covering its body. A corrosive liquid spills from its menacing-looking mouth.", "color": "yellow_white", "upgrades": false, "relative": { diff --git a/data/json/monsters/zed_misc.json b/data/json/monsters/zed_misc.json index 7303d05206aa1..706b560bf103c 100644 --- a/data/json/monsters/zed_misc.json +++ b/data/json/monsters/zed_misc.json @@ -1131,7 +1131,7 @@ "id": "mon_smoker_brute", "type": "MONSTER", "name": { "str": "ashen brawler" }, - "description": "A gigantic, twisted human frame with a menancing stance and rapid movements. Thick clouds of smoke pour from violent-looking eviscerations spread across its muscular-looking body, and its arms appear to have elongated massively.", + "description": "A gigantic, twisted human frame with a menacing stance and rapid movements. Thick clouds of smoke pour from violent-looking eviscerations spread across its muscular-looking body, and its arms appear to have elongated massively.", "default_faction": "zombie", "bodytype": "human", "species": [ "ZOMBIE", "HUMAN" ], diff --git a/data/json/proficiencies/tailoring.json b/data/json/proficiencies/tailoring.json index 17f08e47ba40c..9568cf3e3ff1e 100644 --- a/data/json/proficiencies/tailoring.json +++ b/data/json/proficiencies/tailoring.json @@ -162,7 +162,7 @@ "type": "proficiency", "id": "prof_polymerworking", "name": { "str": "Advanced polymer sewing" }, - "description": "You know the tricks for working with kevlar, nomex, and other advanced polymer cloth.", + "description": "You know the tricks for working with Kevlar, Nomex, and other advanced polymer cloth.", "can_learn": true, "default_time_multiplier": 2, "default_fail_multiplier": 2.5, From bfbf33ebcfe742860fa3173f69b8029bf0cd724f Mon Sep 17 00:00:00 2001 From: actual-nh <74678550+actual-nh@users.noreply.github.com> Date: Wed, 7 Apr 2021 04:43:54 -0400 Subject: [PATCH 128/453] [Magiclysm] Fix orc archer not spawning with ammo (#46780) --- data/mods/Magiclysm/monsters/Orcs.json | 16 ++++++++++++---- 1 file changed, 12 insertions(+), 4 deletions(-) diff --git a/data/mods/Magiclysm/monsters/Orcs.json b/data/mods/Magiclysm/monsters/Orcs.json index 118db3529dff8..437b5bb9ea7a8 100644 --- a/data/mods/Magiclysm/monsters/Orcs.json +++ b/data/mods/Magiclysm/monsters/Orcs.json @@ -1,4 +1,10 @@ [ + { + "type": "item_group", + "subtype": "collection", + "id": "quiver_orc_archer", + "entries": [ { "item": "arrow_wood_heavy", "count": [ 1, 6 ], "charges": [ 1, 10 ] } ] + }, { "id": "mon_orc_warrior", "type": "MONSTER", @@ -56,10 +62,11 @@ { "item": "armguard_scrap", "prob": 40 }, { "item": "cuirass_scrap", "prob": 40 }, { "item": "longbow", "prob": 100 }, - { "item": "sheath", "contents-item": "knife_combat", "prob": 50 } + { "item": "sheath", "contents-item": "knife_combat", "prob": 50 }, + { "item": "quiver_large", "contents-group": "quiver_orc_archer", "prob": 100 } ] }, - "starting_ammo": { "arrow_wood_heavy": 75 }, + "starting_ammo": { "arrow_wood_heavy": 60 }, "extend": { "special_attacks": [ { @@ -68,7 +75,7 @@ "move_cost": 93, "gun_type": "longbow", "ammo_type": "arrow_wood_heavy", - "fake_skills": [ [ "gun", 6 ], [ "rifle", 7 ] ], + "fake_skills": [ [ "gun", 6 ], [ "archery", 7 ] ], "fake_dex": 9, "fake_per": 5, "require_targeting_player": false, @@ -76,7 +83,8 @@ "ranges": [ [ 3, 13, "DEFAULT" ] ], "no_ammo_sound": "grunting" } - ] + ], + "flags": [ "DROPS_AMMO" ] } }, { From 5ba348e568191dc6142670b70ee4296dcad185bd Mon Sep 17 00:00:00 2001 From: Xenomorph-III Date: Mon, 5 Apr 2021 11:21:45 +1200 Subject: [PATCH 129/453] Reword student description --- data/json/professions.json | 5 ++--- 1 file changed, 2 insertions(+), 3 deletions(-) diff --git a/data/json/professions.json b/data/json/professions.json index b40032f09b937..e8c285cae3f41 100644 --- a/data/json/professions.json +++ b/data/json/professions.json @@ -1897,7 +1897,7 @@ "type": "profession", "id": "student", "name": "Student", - "description": "Just an average high school student, you find yourself facing a test you never studied for, and the stakes are a bit higher than geometry. Maybe there'll be something useful in one of these books you've been lugging around all year.", + "description": "Just an average student, you find yourself facing a test you never studied for, and the stakes are a bit higher than geometry. Maybe there'll be something useful in one of these books you've been lugging around all year.", "points": 1, "items": { "both": { @@ -1911,8 +1911,7 @@ "wristwatch", "textbook_speech", "story_book", - "howto_computer", - "novel_coa" + "howto_computer" ], "entries": [ { "group": "charged_cell_phone" } ] }, From e7723b4c37243de3770501cfea89099d57738cc7 Mon Sep 17 00:00:00 2001 From: souricelle <67675144+souricelle@users.noreply.github.com> Date: Wed, 7 Apr 2021 02:01:53 -0700 Subject: [PATCH 130/453] Add feral scientists and lab security (#47996) --- data/json/harvest.json | 19 ++++ data/json/monsterdrops/feral_humans.json | 66 +++++++++++++ data/json/monstergroups/lab.json | 15 +++ data/json/monsters/feral_humans.json | 121 +++++++++++++++++++++++ data/json/snippets/lab.json | 4 +- 5 files changed, 224 insertions(+), 1 deletion(-) diff --git a/data/json/harvest.json b/data/json/harvest.json index f8658ec5c88fd..0c04a110e268a 100644 --- a/data/json/harvest.json +++ b/data/json/harvest.json @@ -1294,6 +1294,25 @@ { "drop": "bone_tainted", "type": "bone", "mass_ratio": 0.1 } ] }, + { + "id": "CBM_SCI_FERAL", + "type": "harvest", + "entries": [ + { + "drop": "bionics_sci", + "type": "bionic_group", + "flags": [ "NO_STERILE", "NO_PACKED" ], + "faults": [ "fault_bionic_salvaged" ] + }, + { "drop": "human_flesh", "type": "flesh", "mass_ratio": 0.2 }, + { "drop": "hstomach", "scale_num": [ 1, 1 ], "max": 1, "type": "offal" }, + { "drop": "human_fat", "type": "flesh", "mass_ratio": 0.1 }, + { "drop": "blood", "type": "blood", "mass_ratio": 0.1 }, + { "drop": "bone_human", "type": "bone", "mass_ratio": 0.12 }, + { "drop": "sinew", "type": "bone", "mass_ratio": 0.001 }, + { "drop": "raw_hleather", "type": "skin", "mass_ratio": 0.01 } + ] + }, { "id": "CBM_TECH", "type": "harvest", diff --git a/data/json/monsterdrops/feral_humans.json b/data/json/monsterdrops/feral_humans.json index 03e30f201d6c0..df787a4720216 100644 --- a/data/json/monsterdrops/feral_humans.json +++ b/data/json/monsterdrops/feral_humans.json @@ -16,5 +16,71 @@ "subtype": "collection", "id": "feral_humans_death_drops_crowbar", "entries": [ { "item": "crowbar", "prob": 100, "damage": [ 1, 3 ] }, { "group": "default_zombie_clothes", "prob": 100 } ] + }, + { + "type": "item_group", + "subtype": "collection", + "id": "feral_scientists_death_drops_scalpel", + "entries": [ + { "item": "scalpel", "prob": 100, "damage": [ 1, 3 ] }, + { "group": "lab_shoes", "damage": [ 1, 4 ] }, + { "group": "lab_torso", "damage": [ 1, 4 ] }, + { "group": "lab_pants", "damage": [ 1, 4 ] }, + { "group": "underwear", "damage": [ 1, 4 ] }, + { + "collection": [ + { "group": "harddrugs", "prob": 25 }, + { "group": "chem_lab", "prob": 60 }, + { "group": "teleport", "prob": 6 }, + { "group": "goo", "prob": 20 }, + { "group": "cloning_vat", "prob": 1 }, + { "group": "dissection", "prob": 50 }, + { "group": "electronics", "prob": 40 }, + { "group": "bionics", "prob": 10 }, + { "group": "radio", "prob": 15 }, + { "group": "textbooks", "prob": 25 }, + { "group": "autodoc_installation_programs", "prob": 5 } + ] + }, + { "group": "wallets_science", "damage": [ 1, 4 ], "prob": 5 } + ] + }, + { + "id": "feral_security_death_drops_9mm", + "type": "item_group", + "subtype": "collection", + "magazine": 100, + "ammo": 20, + "entries": [ + { "item": "m9", "prob": 100, "damage": [ 2, 4 ] }, + { "group": "cop_gear", "prob": 50, "damage": [ 0, 2 ] }, + { "group": "cop_gloves", "prob": 30, "damage": [ 1, 4 ] }, + { "group": "security_pants", "damage": [ 1, 4 ] }, + { "group": "security_shoes", "prob": 70, "damage": [ 1, 4 ] }, + { "group": "security_torso", "prob": 70, "damage": [ 1, 4 ] }, + { "group": "underwear", "damage": [ 1, 4 ] }, + { "group": "clothing_glasses", "prob": 5 }, + { "group": "clothing_watch", "prob": 5 }, + { "group": "wallets", "damage": [ 1, 4 ] } + ] + }, + { + "id": "feral_security_death_drops_flashlight", + "type": "item_group", + "subtype": "collection", + "magazine": 100, + "ammo": 20, + "entries": [ + { "item": "heavy_flashlight", "prob": 100, "damage": [ 2, 4 ] }, + { "item": "tazer", "prob": 100, "damage": [ 2, 4 ] }, + { "group": "cop_gloves", "prob": 30, "damage": [ 1, 4 ] }, + { "group": "security_pants", "damage": [ 1, 4 ] }, + { "group": "security_shoes", "prob": 70, "damage": [ 1, 4 ] }, + { "group": "security_torso", "prob": 70, "damage": [ 1, 4 ] }, + { "group": "underwear", "damage": [ 1, 4 ] }, + { "group": "clothing_glasses", "prob": 5 }, + { "group": "clothing_watch", "prob": 5 }, + { "group": "wallets", "damage": [ 1, 4 ] } + ] } ] diff --git a/data/json/monstergroups/lab.json b/data/json/monstergroups/lab.json index 00344d5b7347f..e559436d0c53c 100644 --- a/data/json/monstergroups/lab.json +++ b/data/json/monstergroups/lab.json @@ -5,6 +5,7 @@ "default": "mon_zombie_scientist", "monsters": [ { "monster": "mon_zombie_soldier", "freq": 25, "cost_multiplier": 0, "pack_size": [ 1, 4 ] }, + { "monster": "mon_feral_scientist_scalpel", "freq": 20, "cost_multiplier": 0 }, { "monster": "mon_manhack", "freq": 200, "cost_multiplier": 0 }, { "monster": "mon_manhack", "freq": 45, "cost_multiplier": 0, "pack_size": [ 2, 3 ] }, { "monster": "mon_skitterbot", "freq": 100, "cost_multiplier": 0 }, @@ -28,6 +29,9 @@ "default": "mon_zombie_scientist", "monsters": [ { "monster": "mon_blob_small", "freq": 25, "cost_multiplier": 0, "pack_size": [ 1, 4 ] }, + { "monster": "mon_feral_labsecurity_9mm", "freq": 18, "cost_multiplier": 8 }, + { "monster": "mon_feral_labsecurity_flashlight", "freq": 18, "cost_multiplier": 2 }, + { "monster": "mon_feral_scientist_scalpel", "freq": 20, "cost_multiplier": 0 }, { "monster": "mon_zombie", "freq": 200, "cost_multiplier": 0, "pack_size": [ 1, 3 ] }, { "monster": "mon_zombie_fat", "freq": 100, "cost_multiplier": 0, "pack_size": [ 1, 3 ] }, { "monster": "mon_zombie_tough", "freq": 100, "cost_multiplier": 2, "pack_size": [ 1, 3 ] }, @@ -60,6 +64,9 @@ "name": "GROUP_LAB_SURFACE", "default": "mon_zombie_scientist", "monsters": [ + { "monster": "mon_feral_labsecurity_9mm", "freq": 18, "cost_multiplier": 8 }, + { "monster": "mon_feral_labsecurity_flashlight", "freq": 18, "cost_multiplier": 2 }, + { "monster": "mon_feral_scientist_scalpel", "freq": 20, "cost_multiplier": 0 }, { "monster": "mon_zombie_labsecurity", "freq": 400, "cost_multiplier": 2, "pack_size": [ 1, 3 ] }, { "monster": "mon_zombie_scientist", "freq": 600, "cost_multiplier": 1 }, { "monster": "mon_zombie_scientist", "freq": 400, "cost_multiplier": 1, "pack_size": [ 1, 5 ] }, @@ -92,6 +99,8 @@ "name": "GROUP_LAB_SECURITY", "default": "mon_zombie_labsecurity", "monsters": [ + { "monster": "mon_feral_labsecurity_9mm", "freq": 22, "cost_multiplier": 8 }, + { "monster": "mon_feral_labsecurity_flashlight", "freq": 22, "cost_multiplier": 2 }, { "monster": "mon_zombie_labsecurity", "freq": 700, "cost_multiplier": 2 }, { "monster": "mon_science_bot", "freq": 50, "cost_multiplier": 4 }, { "monster": "mon_manhack", "freq": 200, "cost_multiplier": 0 }, @@ -116,6 +125,9 @@ "default": "mon_zombie_scientist", "//": "Mostly scientists, lab personnel and regular zombies.", "monsters": [ + { "monster": "mon_feral_labsecurity_9mm", "freq": 18, "cost_multiplier": 8 }, + { "monster": "mon_feral_labsecurity_flashlight", "freq": 18, "cost_multiplier": 2 }, + { "monster": "mon_feral_scientist_scalpel", "freq": 20, "cost_multiplier": 8 }, { "monster": "mon_zombie", "freq": 75, "cost_multiplier": 0 }, { "monster": "mon_zombie_fat", "freq": 75, "cost_multiplier": 0 }, { "monster": "mon_zombie_tough", "freq": 75, "cost_multiplier": 2 }, @@ -141,6 +153,9 @@ "default": "mon_zombie_scientist", "monsters": [ { "monster": "mon_blob_small", "freq": 40, "cost_multiplier": 0, "pack_size": [ 3, 6 ] }, + { "monster": "mon_feral_labsecurity_9mm", "freq": 18, "cost_multiplier": 8 }, + { "monster": "mon_feral_labsecurity_flashlight", "freq": 18, "cost_multiplier": 2 }, + { "monster": "mon_feral_scientist_scalpel", "freq": 20, "cost_multiplier": 0 }, { "monster": "mon_zombie_scientist", "freq": 40, "cost_multiplier": 0, "pack_size": [ 1, 5 ] }, { "monster": "mon_science_bot", "freq": 40, "cost_multiplier": 2 }, { "monster": "mon_zombie_labsecurity", "freq": 40, "cost_multiplier": 0, "pack_size": [ 2, 3 ] }, diff --git a/data/json/monsters/feral_humans.json b/data/json/monsters/feral_humans.json index cf3e8c9898528..9ef249896e6ed 100644 --- a/data/json/monsters/feral_humans.json +++ b/data/json/monsters/feral_humans.json @@ -77,5 +77,126 @@ "melee_dice_sides": 7, "melee_cut": 9, "death_drops": "feral_humans_death_drops_axe" + }, + { + "id": "mon_feral_scientist_scalpel", + "type": "MONSTER", + "name": { "str": "mad scientist" }, + "description": "A researcher who has stared too long into the abyss, and now shambles about muttering nonsense under their breath. For some reason, the zombies don't seem to mind that this person is obviously still alive. They're clutching a tiny but razor-sharp blade in one shaky hand.", + "default_faction": "science", + "looks_like": "chud", + "bodytype": "human", + "species": [ "HUMAN" ], + "volume": "62500 ml", + "weight": "81500 g", + "hp": 80, + "speed": 100, + "material": [ "flesh" ], + "symbol": "@", + "color": "magenta", + "aggression": 30, + "morale": 100, + "melee_skill": 4, + "melee_dice": 1, + "melee_dice_sides": 3, + "melee_cut": 2, + "dodge": 1, + "harvest": "CBM_SCI_FERAL", + "path_settings": { "max_dist": 10 }, + "vision_day": 50, + "vision_night": 3, + "death_drops": "feral_scientists_death_drops_scalpel", + "death_function": [ "NORMAL" ], + "zombify_into": "mon_zombie_scientist", + "anger_triggers": [ "FRIEND_DIED", "FRIEND_ATTACKED", "HURT", "PLAYER_CLOSE" ], + "flags": [ + "SEES", + "HEARS", + "SMELLS", + "WARM", + "BASHES", + "GROUP_BASH", + "HUMAN", + "CAN_OPEN_DOORS", + "PATH_AVOID_DANGER_2", + "DROPS_AMMO", + "CBM_SCI" + ] + }, + { + "id": "mon_feral_labsecurity_9mm", + "type": "MONSTER", + "name": { "str": "feral security guard" }, + "description": "This security guard still breathes, but has been lost to some terrible madness. They move among the undead, handgun at the ready and saucer pupils scanning for threats in a mockery of their former duty.", + "default_faction": "science", + "looks_like": "chud", + "bodytype": "human", + "species": [ "HUMAN" ], + "volume": "62500 ml", + "weight": "81500 g", + "hp": 80, + "speed": 100, + "material": [ "flesh" ], + "symbol": "@", + "color": "magenta", + "aggression": 30, + "morale": 100, + "melee_skill": 6, + "melee_dice": 2, + "melee_dice_sides": 3, + "armor_bash": 4, + "armor_cut": 6, + "armor_bullet": 4, + "armor_stab": 4, + "dodge": 1, + "harvest": "human", + "vision_day": 50, + "vision_night": 4, + "path_settings": { "max_dist": 10 }, + "diff": 5, + "starting_ammo": { "9mm": 5 }, + "special_attacks": [ + { + "type": "gun", + "cooldown": 10, + "move_cost": 150, + "gun_type": "m9", + "ammo_type": "9mm", + "fake_skills": [ [ "gun", 1 ], [ "handgun", 2 ] ], + "fake_dex": 8, + "fake_per": 10, + "ranges": [ [ 0, 14, "DEFAULT" ] ], + "require_targeting_player": false, + "description": "The feral security guard fires their Beretta M9A1!" + } + ], + "death_drops": "feral_security_death_drops_9mm", + "death_function": [ "NORMAL" ], + "zombify_into": "mon_zombie_labsecurity", + "anger_triggers": [ "FRIEND_DIED", "FRIEND_ATTACKED", "HURT", "PLAYER_WEAK" ], + "flags": [ + "SEES", + "HEARS", + "SMELLS", + "WARM", + "BASHES", + "GROUP_BASH", + "HUMAN", + "CAN_OPEN_DOORS", + "CLIMBS", + "PUSH_MON", + "PATH_AVOID_DANGER_2", + "DROPS_AMMO" + ] + }, + { + "id": "mon_feral_labsecurity_flashlight", + "type": "MONSTER", + "copy-from": "mon_feral_labsecurity_9mm", + "description": "At first glance, this disheveled figure could almost pass for a survivor, but the bloodshot eyes give them away as one of the humans who have gone feral and joined the undead without dying. Their uniform suggests that this was at some point a security guard, and they still carry a stun gun and a heavy-duty flashlight that looks like it could easily double as a club.", + "melee_dice_sides": 6, + "special_attacks": [ [ "TAZER", 10 ] ], + "luminance": 500, + "death_drops": "feral_security_death_drops_flashlight" } ] diff --git a/data/json/snippets/lab.json b/data/json/snippets/lab.json index 05eb5d8b55c9b..7b1deb77238c3 100644 --- a/data/json/snippets/lab.json +++ b/data/json/snippets/lab.json @@ -122,7 +122,9 @@ "Jakobson was killed today by one of S37ZBE's subjects; ironic considering how hard he fought to keep the project active. Alarmingly, his corpse revivified immediately. This suggests that XE037 may have contaminated the lab at large. Even more alarmingly, we received an alert from Dr. Dionne in XEDRA-12 that they have detected similar signs of cross-contamination with XE037. How can this have happened? Even during the breach last week, we managed to keep containment protocols active!", "Termination of a subject which was never a part of S37ZBE has confirmed my fears. XE037 has contaminated most, if not all of the laboratory. We're in communication with XEDRA-12 over their own outbreak, and both labs have been quarantined. While they backtrace the leak, we will start research into a process to destroy XE037 within the human body.", "Dr. Takatoshi sent us interesting news: her lab serendipitously discovered that sufficient rapid teleports in a short span of time can strip out XE037 somehow, without harming the subject. This has the unfortunate issues of needing an absolutely insane amount of electricity, and drawing the attention of what Dr. Takatoshi calls \"subplanar creatures\" and the rest of us call \"horrifying alien monstrosities\". Still, it's a start.", - "Dr. Sidhu figured out a way to track what happens to XE037 when it's stripped out during teleportation, using a high-affinity biotracer and a probe that follows immediately behind the test subject. XE037 migrates out of the body in small but significant quantities with every teleport. We're attributing way too much intelligence to it here, but we can't help but feel this is some kind of intentional 'stowaway' effect, like it's shedding off the body to try to colonize a new dimension. At the meeting, Dr. Sidhu told us to stop anthropomorphizing it. He thinks it's no more a sign of intelligence than a cold virus coming out with a sneeze." + "Dr. Sidhu figured out a way to track what happens to XE037 when it's stripped out during teleportation, using a high-affinity biotracer and a probe that follows immediately behind the test subject. XE037 migrates out of the body in small but significant quantities with every teleport. We're attributing way too much intelligence to it here, but we can't help but feel this is some kind of intentional 'stowaway' effect, like it's shedding off the body to try to colonize a new dimension. At the meeting, Dr. Sidhu told us to stop anthropomorphizing it. He thinks it's no more a sign of intelligence than a cold virus coming out with a sneeze.", + "I've put Dr. Welch and Dr. Bondi on supervised leave following the incident discussed in my previous message. Obviously neither has a history of this kind of behavior or they wouldn't be here, and it's deeply concerning that they both suddenly began acting this way following Wednesday's demonstration. For now we'll keep them on-site until (hopefully) they recover enough to get back to work, but I'd like to formally ask that we start looking at possible replacements.", + "At approximately 11:15 today, I saw Dr. Greene enter the break area from the primary corridor. He is always so rude so I drew my service pistol and fired three shots into his body. Then I shot Dr. Summers and Officer Clark because they were being loud. I am sorry, but I do not know how many times I shot them. I think Hollis tazed me but I was so mad by that point that I could not keep track of what was going on. Then you restrained me and brought me here, so I guess that's my whole report." ] } ] From 444d6bd4b92148acaf6a67b7e6bda5e16492d14d Mon Sep 17 00:00:00 2001 From: John Bytheway Date: Tue, 30 Mar 2021 21:07:41 -0400 Subject: [PATCH 131/453] Split debug_menu function Extract three cases from the giant switch statement into new, separate, functions. --- src/debug_menu.cpp | 393 ++++++++++++++++++++++++--------------------- 1 file changed, 206 insertions(+), 187 deletions(-) diff --git a/src/debug_menu.cpp b/src/debug_menu.cpp index 6ad998654ff89..1ef8722b50c4a 100644 --- a/src/debug_menu.cpp +++ b/src/debug_menu.cpp @@ -1949,6 +1949,205 @@ void draw_benchmark( const int max_difference ) difference / 1000.0, 1000.0 * draw_counter / static_cast( difference ) ); } +static void debug_menu_game_state() +{ + avatar &player_character = get_avatar(); + map &here = get_map(); + tripoint abs_sub = here.get_abs_sub(); + std::string mfus; + std::vector> sorted; + for( int f = 0; f < m_flag::MF_MAX; f++ ) { + sorted.push_back( {static_cast( f ), MonsterGenerator::generator().m_flag_usage_stats[f]} ); + } + std::sort( sorted.begin(), sorted.end(), []( std::pair a, std::pair b ) { + return a.second != b.second ? a.second > b.second : a.first < b.first; + } ); + popup( player_character.total_daily_calories_string() ); + for( auto &m_flag_stat : sorted ) { + mfus += string_format( "%s;%d\n", io::enum_to_string( m_flag_stat.first ), + m_flag_stat.second ); + } + DebugLog( D_INFO, DC_ALL ) << "Monster flag usage statistics:\nFLAG;COUNT\n" << mfus; + std::fill( MonsterGenerator::generator().m_flag_usage_stats.begin(), + MonsterGenerator::generator().m_flag_usage_stats.end(), 0 ); + popup_top( "Monster flag usage statistics were dumped to debug.log and cleared." ); + + std::string s = _( "Location %d:%d in %d:%d, %s\n" ); + s += _( "Current turn: %d.\n" ); + s += ngettext( "%d creature exists.\n", "%d creatures exist.\n", g->num_creatures() ); + + std::unordered_map creature_counts; + for( Creature &critter : g->all_creatures() ) { + std::string this_name = critter.get_name(); + creature_counts[this_name]++; + } + + if( !creature_counts.empty() ) { + std::vector> creature_names_sorted; + for( const std::pair &it : creature_counts ) { + creature_names_sorted.emplace_back( it ); + } + + std::stable_sort( creature_names_sorted.begin(), creature_names_sorted.end(), []( auto a, auto b ) { + return a.second > b.second; + } ); + + s += _( "\nSpecific creature type list:\n" ); + for( const std::pair &crit_name : creature_names_sorted ) { + s += string_format( "%i %s\n", crit_name.second, crit_name.first ); + } + } + + popup_top( + s.c_str(), + player_character.posx(), player_character.posy(), abs_sub.x, abs_sub.y, + overmap_buffer.ter( player_character.global_omt_location() )->get_name(), + to_turns( calendar::turn - calendar::turn_zero ), + g->num_creatures() ); + for( const npc &guy : g->all_npcs() ) { + tripoint t = guy.global_sm_location(); + add_msg( m_info, _( "%s: map ( %d:%d ) pos ( %d:%d )" ), guy.name, t.x, + t.y, guy.posx(), guy.posy() ); + } + + add_msg( m_info, _( "(you: %d:%d)" ), player_character.posx(), player_character.posy() ); + std::string stom = + _( "Stomach Contents: %d ml / %d ml kCal: %d, Water: %d ml" ); + add_msg( m_info, stom.c_str(), units::to_milliliter( player_character.stomach.contains() ), + units::to_milliliter( player_character.stomach.capacity( player_character ) ), + player_character.stomach.get_calories(), + units::to_milliliter( player_character.stomach.get_water() ), player_character.get_hunger() ); + stom = _( "Guts Contents: %d ml / %d ml kCal: %d, Water: %d ml\nHunger: %d, Thirst: %d, kCal: %d / %d" ); + add_msg( m_info, stom.c_str(), units::to_milliliter( player_character.guts.contains() ), + units::to_milliliter( player_character.guts.capacity( player_character ) ), + player_character.guts.get_calories(), units::to_milliliter( player_character.guts.get_water() ), + player_character.get_hunger(), player_character.get_thirst(), player_character.get_stored_kcal(), + player_character.get_healthy_kcal() ); + add_msg( m_info, _( "Body Mass Index: %.0f\nBasal Metabolic Rate: %i" ), player_character.get_bmi(), + player_character.get_bmr() ); + add_msg( m_info, _( "Player activity level: %s" ), player_character.activity_level_str() ); + if( get_option( "STATS_THROUGH_KILLS" ) ) { + add_msg( m_info, _( "Kill xp: %d" ), player_character.kill_xp() ); + } + g->invalidate_main_ui_adaptor(); + g->disp_NPCs(); +} + +static void debug_menu_spawn_vehicle() +{ + avatar &player_character = get_avatar(); + map &here = get_map(); + if( here.veh_at( player_character.pos() ) ) { + dbg( D_ERROR ) << "game:load: There's already vehicle here"; + debugmsg( "There's already vehicle here" ); + } else { + // Vector of name, id so that we can sort by name + std::vector> veh_strings; + for( auto &elem : vehicle_prototype::get_all() ) { + if( elem == vproto_id( "custom" ) ) { + continue; + } + veh_strings.emplace_back( elem->name.translated(), elem ); + } + std::sort( veh_strings.begin(), veh_strings.end(), localized_compare ); + uilist veh_menu; + veh_menu.text = _( "Choose vehicle to spawn" ); + int menu_ind = 0; + for( auto &elem : veh_strings ) { + //~ Menu entry in vehicle wish menu: 1st string: displayed name, 2nd string: internal name of vehicle + veh_menu.addentry( menu_ind, true, MENU_AUTOASSIGN, _( "%1$s (%2$s)" ), + elem.first, elem.second.c_str() ); + ++menu_ind; + } + veh_menu.query(); + if( veh_menu.ret >= 0 && veh_menu.ret < static_cast( veh_strings.size() ) ) { + // Didn't cancel + const vproto_id &selected_opt = veh_strings[veh_menu.ret].second; + tripoint dest = player_character.pos(); + uilist veh_cond_menu; + veh_cond_menu.text = _( "Vehicle condition" ); + veh_cond_menu.addentry( 0, true, MENU_AUTOASSIGN, _( "Light damage" ) ); + veh_cond_menu.addentry( 1, true, MENU_AUTOASSIGN, _( "Undamaged" ) ); + veh_cond_menu.addentry( 2, true, MENU_AUTOASSIGN, _( "Disabled (tires or engine)" ) ); + veh_cond_menu.query(); + + if( veh_cond_menu.ret >= 0 && veh_cond_menu.ret < 3 ) { + // TODO: Allow picking this when add_vehicle has 3d argument + vehicle *veh = here.add_vehicle( + selected_opt, dest, -90_degrees, 100, veh_cond_menu.ret - 1 ); + if( veh != nullptr ) { + here.board_vehicle( dest, &player_character ); + } + } + } + } +} + +static void debug_menu_change_time() +{ + auto set_turn = [&]( const int initial, const time_duration & factor, const char *const msg ) { + const auto text = string_input_popup() + .title( msg ) + .width( 20 ) + .text( std::to_string( initial ) ) + .only_digits( true ) + .query_string(); + if( text.empty() ) { + return; + } + const int new_value = std::atoi( text.c_str() ); + const time_duration offset = ( new_value - initial ) * factor; + // Arbitrary maximal value. + const time_point max = calendar::turn_zero + time_duration::from_turns( + std::numeric_limits::max() / 2 ); + calendar::turn = std::max( std::min( max, calendar::turn + offset ), calendar::turn_zero ); + }; + + uilist smenu; + static const auto years = []( const time_point & p ) { + return static_cast( ( p - calendar::turn_zero ) / calendar::year_length() ); + }; + do { + const int iSel = smenu.ret; + smenu.reset(); + smenu.addentry( 0, true, 'y', "%s: %d", _( "year" ), years( calendar::turn ) ); + smenu.addentry( 1, !calendar::eternal_season(), 's', "%s: %d", + _( "season" ), static_cast( season_of_year( calendar::turn ) ) ); + smenu.addentry( 2, true, 'd', "%s: %d", _( "day" ), day_of_season( calendar::turn ) ); + smenu.addentry( 3, true, 'h', "%s: %d", _( "hour" ), hour_of_day( calendar::turn ) ); + smenu.addentry( 4, true, 'm', "%s: %d", _( "minute" ), minute_of_hour( calendar::turn ) ); + smenu.addentry( 5, true, 't', "%s: %d", _( "turn" ), + to_turns( calendar::turn - calendar::turn_zero ) ); + smenu.selected = iSel; + smenu.query(); + + switch( smenu.ret ) { + case 0: + set_turn( years( calendar::turn ), calendar::year_length(), _( "Set year to?" ) ); + break; + case 1: + set_turn( static_cast( season_of_year( calendar::turn ) ), calendar::season_length(), + _( "Set season to? (0 = spring)" ) ); + break; + case 2: + set_turn( day_of_season( calendar::turn ), 1_days, _( "Set days to?" ) ); + break; + case 3: + set_turn( hour_of_day( calendar::turn ), 1_hours, _( "Set hour to?" ) ); + break; + case 4: + set_turn( minute_of_hour( calendar::turn ), 1_minutes, _( "Set minute to?" ) ); + break; + case 5: + set_turn( to_turns( calendar::turn - calendar::turn_zero ), 1_turns, + string_format( _( "Set turn to? (One day is %i turns)" ), to_turns( 1_days ) ).c_str() ); + break; + default: + break; + } + } while( smenu.ret != UILIST_CANCEL ); +} + void debug() { bool debug_menu_has_hotkey = hotkey_for_action( ACTION_DEBUG, @@ -2036,86 +2235,10 @@ void debug() debug_menu::wishmonster( cata::nullopt ); break; - case debug_menu_index::GAME_STATE: { - std::string mfus; - std::vector> sorted; - for( int f = 0; f < m_flag::MF_MAX; f++ ) { - sorted.push_back( {static_cast( f ), MonsterGenerator::generator().m_flag_usage_stats[f]} ); - } - std::sort( sorted.begin(), sorted.end(), []( std::pair a, std::pair b ) { - return a.second != b.second ? a.second > b.second : a.first < b.first; - } ); - popup( player_character.total_daily_calories_string() ); - for( auto &m_flag_stat : sorted ) { - mfus += string_format( "%s;%d\n", io::enum_to_string( m_flag_stat.first ), - m_flag_stat.second ); - } - DebugLog( D_INFO, DC_ALL ) << "Monster flag usage statistics:\nFLAG;COUNT\n" << mfus; - std::fill( MonsterGenerator::generator().m_flag_usage_stats.begin(), - MonsterGenerator::generator().m_flag_usage_stats.end(), 0 ); - popup_top( "Monster flag usage statistics were dumped to debug.log and cleared." ); - - std::string s = _( "Location %d:%d in %d:%d, %s\n" ); - s += _( "Current turn: %d.\n" ); - s += ngettext( "%d creature exists.\n", "%d creatures exist.\n", g->num_creatures() ); - - std::unordered_map creature_counts; - for( Creature &critter : g->all_creatures() ) { - std::string this_name = critter.get_name(); - creature_counts[this_name]++; - } - - if( !creature_counts.empty() ) { - std::vector> creature_names_sorted; - for( const std::pair &it : creature_counts ) { - creature_names_sorted.emplace_back( it ); - } - - std::stable_sort( creature_names_sorted.begin(), creature_names_sorted.end(), []( auto a, auto b ) { - return a.second > b.second; - } ); - - s += _( "\nSpecific creature type list:\n" ); - for( const std::pair &crit_name : creature_names_sorted ) { - s += string_format( "%i %s\n", crit_name.second, crit_name.first ); - } - } - - popup_top( - s.c_str(), - player_character.posx(), player_character.posy(), abs_sub.x, abs_sub.y, - overmap_buffer.ter( player_character.global_omt_location() )->get_name(), - to_turns( calendar::turn - calendar::turn_zero ), - g->num_creatures() ); - for( const npc &guy : g->all_npcs() ) { - tripoint t = guy.global_sm_location(); - add_msg( m_info, _( "%s: map ( %d:%d ) pos ( %d:%d )" ), guy.name, t.x, - t.y, guy.posx(), guy.posy() ); - } - - add_msg( m_info, _( "(you: %d:%d)" ), player_character.posx(), player_character.posy() ); - std::string stom = - _( "Stomach Contents: %d ml / %d ml kCal: %d, Water: %d ml" ); - add_msg( m_info, stom.c_str(), units::to_milliliter( player_character.stomach.contains() ), - units::to_milliliter( player_character.stomach.capacity( player_character ) ), - player_character.stomach.get_calories(), - units::to_milliliter( player_character.stomach.get_water() ), player_character.get_hunger() ); - stom = _( "Guts Contents: %d ml / %d ml kCal: %d, Water: %d ml\nHunger: %d, Thirst: %d, kCal: %d / %d" ); - add_msg( m_info, stom.c_str(), units::to_milliliter( player_character.guts.contains() ), - units::to_milliliter( player_character.guts.capacity( player_character ) ), - player_character.guts.get_calories(), units::to_milliliter( player_character.guts.get_water() ), - player_character.get_hunger(), player_character.get_thirst(), player_character.get_stored_kcal(), - player_character.get_healthy_kcal() ); - add_msg( m_info, _( "Body Mass Index: %.0f\nBasal Metabolic Rate: %i" ), player_character.get_bmi(), - player_character.get_bmr() ); - add_msg( m_info, _( "Player activity level: %s" ), player_character.activity_level_str() ); - if( get_option( "STATS_THROUGH_KILLS" ) ) { - add_msg( m_info, _( "Kill xp: %d" ), player_character.kill_xp() ); - } - g->invalidate_main_ui_adaptor(); - g->disp_NPCs(); + case debug_menu_index::GAME_STATE: + debug_menu_game_state(); break; - } + case debug_menu_index::KILL_NPCS: for( npc &guy : g->all_npcs() ) { add_msg( _( "%s's head implodes!" ), guy.name ); @@ -2128,50 +2251,7 @@ void debug() break; case debug_menu_index::SPAWN_VEHICLE: - if( here.veh_at( player_character.pos() ) ) { - dbg( D_ERROR ) << "game:load: There's already vehicle here"; - debugmsg( "There's already vehicle here" ); - } else { - // Vector of name, id so that we can sort by name - std::vector> veh_strings; - for( auto &elem : vehicle_prototype::get_all() ) { - if( elem == vproto_id( "custom" ) ) { - continue; - } - veh_strings.emplace_back( elem->name.translated(), elem ); - } - std::sort( veh_strings.begin(), veh_strings.end(), localized_compare ); - uilist veh_menu; - veh_menu.text = _( "Choose vehicle to spawn" ); - int menu_ind = 0; - for( auto &elem : veh_strings ) { - //~ Menu entry in vehicle wish menu: 1st string: displayed name, 2nd string: internal name of vehicle - veh_menu.addentry( menu_ind, true, MENU_AUTOASSIGN, _( "%1$s (%2$s)" ), - elem.first, elem.second.c_str() ); - ++menu_ind; - } - veh_menu.query(); - if( veh_menu.ret >= 0 && veh_menu.ret < static_cast( veh_strings.size() ) ) { - // Didn't cancel - const vproto_id &selected_opt = veh_strings[veh_menu.ret].second; - tripoint dest = player_character.pos(); - uilist veh_cond_menu; - veh_cond_menu.text = _( "Vehicle condition" ); - veh_cond_menu.addentry( 0, true, MENU_AUTOASSIGN, _( "Light damage" ) ); - veh_cond_menu.addentry( 1, true, MENU_AUTOASSIGN, _( "Undamaged" ) ); - veh_cond_menu.addentry( 2, true, MENU_AUTOASSIGN, _( "Disabled (tires or engine)" ) ); - veh_cond_menu.query(); - - if( veh_cond_menu.ret >= 0 && veh_cond_menu.ret < 3 ) { - // TODO: Allow picking this when add_vehicle has 3d argument - vehicle *veh = here.add_vehicle( - selected_opt, dest, -90_degrees, 100, veh_cond_menu.ret - 1 ); - if( veh != nullptr ) { - here.board_vehicle( dest, &player_character ); - } - } - } - } + debug_menu_spawn_vehicle(); break; case debug_menu_index::CHANGE_SKILLS: { @@ -2471,70 +2551,9 @@ void debug() case debug_menu_index::HOUR_TIMER: g->toggle_debug_hour_timer(); break; - case debug_menu_index::CHANGE_TIME: { - auto set_turn = [&]( const int initial, const time_duration & factor, const char *const msg ) { - const auto text = string_input_popup() - .title( msg ) - .width( 20 ) - .text( std::to_string( initial ) ) - .only_digits( true ) - .query_string(); - if( text.empty() ) { - return; - } - const int new_value = std::atoi( text.c_str() ); - const time_duration offset = ( new_value - initial ) * factor; - // Arbitrary maximal value. - const time_point max = calendar::turn_zero + time_duration::from_turns( - std::numeric_limits::max() / 2 ); - calendar::turn = std::max( std::min( max, calendar::turn + offset ), calendar::turn_zero ); - }; - - uilist smenu; - static const auto years = []( const time_point & p ) { - return static_cast( ( p - calendar::turn_zero ) / calendar::year_length() ); - }; - do { - const int iSel = smenu.ret; - smenu.reset(); - smenu.addentry( 0, true, 'y', "%s: %d", _( "year" ), years( calendar::turn ) ); - smenu.addentry( 1, !calendar::eternal_season(), 's', "%s: %d", - _( "season" ), static_cast( season_of_year( calendar::turn ) ) ); - smenu.addentry( 2, true, 'd', "%s: %d", _( "day" ), day_of_season( calendar::turn ) ); - smenu.addentry( 3, true, 'h', "%s: %d", _( "hour" ), hour_of_day( calendar::turn ) ); - smenu.addentry( 4, true, 'm', "%s: %d", _( "minute" ), minute_of_hour( calendar::turn ) ); - smenu.addentry( 5, true, 't', "%s: %d", _( "turn" ), - to_turns( calendar::turn - calendar::turn_zero ) ); - smenu.selected = iSel; - smenu.query(); - - switch( smenu.ret ) { - case 0: - set_turn( years( calendar::turn ), calendar::year_length(), _( "Set year to?" ) ); - break; - case 1: - set_turn( static_cast( season_of_year( calendar::turn ) ), calendar::season_length(), - _( "Set season to? (0 = spring)" ) ); - break; - case 2: - set_turn( day_of_season( calendar::turn ), 1_days, _( "Set days to?" ) ); - break; - case 3: - set_turn( hour_of_day( calendar::turn ), 1_hours, _( "Set hour to?" ) ); - break; - case 4: - set_turn( minute_of_hour( calendar::turn ), 1_minutes, _( "Set minute to?" ) ); - break; - case 5: - set_turn( to_turns( calendar::turn - calendar::turn_zero ), 1_turns, - string_format( _( "Set turn to? (One day is %i turns)" ), to_turns( 1_days ) ).c_str() ); - break; - default: - break; - } - } while( smenu.ret != UILIST_CANCEL ); - } - break; + case debug_menu_index::CHANGE_TIME: + debug_menu_change_time(); + break; case debug_menu_index::SET_AUTOMOVE: { const cata::optional dest = g->look_around(); if( !dest || *dest == player_character.pos() ) { From baf0e24d31c473f26bd8f748485597899f285366 Mon Sep 17 00:00:00 2001 From: John Bytheway Date: Fri, 2 Apr 2021 20:22:28 -0400 Subject: [PATCH 132/453] Split game::handle_action Make this large function smaller by factoring out two parts of it into new functions. --- src/game.h | 2 + src/handle_action.cpp | 1828 +++++++++++++++++++++-------------------- 2 files changed, 931 insertions(+), 899 deletions(-) diff --git a/src/game.h b/src/game.h index 58e4d83935044..513cd6c2bed24 100644 --- a/src/game.h +++ b/src/game.h @@ -887,6 +887,8 @@ class game void process_activity(); // Processes and enacts the player's activity void handle_key_blocking_activity(); // Abort reading etc. void open_consume_item_menu(); // Custom menu for consuming specific group of items + bool do_regular_action( action_id &act, avatar &player_character, + const cata::optional &mouse_target ); bool handle_action(); bool try_get_right_click_action( action_id &act, const tripoint &mouse_target ); bool try_get_left_click_action( action_id &act, const tripoint &mouse_target ); diff --git a/src/handle_action.cpp b/src/handle_action.cpp index 2f7582e9290c5..fce8b3d44c4f9 100644 --- a/src/handle_action.cpp +++ b/src/handle_action.cpp @@ -1679,1050 +1679,1080 @@ static void handle_debug_mode() } while( dbmenu.ret != UILIST_CANCEL ); } -bool game::handle_action() +static bool has_vehicle_control( avatar &player_character ) { - std::string action; - input_context ctxt; - action_id act = ACTION_NULL; - user_turn current_turn; - avatar &player_character = get_avatar(); - // Check if we have an auto-move destination - if( player_character.has_destination() ) { - act = player_character.get_next_auto_move_direction(); - if( act == ACTION_NULL ) { - add_msg( m_info, _( "Auto-move canceled" ) ); - player_character.clear_destination(); - return false; - } - } else if( player_character.has_destination_activity() ) { - // starts destination activity after the player successfully reached his destination - player_character.start_destination_activity(); + if( player_character.is_dead_state() ) { return false; - } else { - // No auto-move, ask player for input - ctxt = get_player_input( action ); } + const optional_vpart_position vp = get_map().veh_at( player_character.pos() ); + if( vp && vp->vehicle().player_in_control( player_character ) ) { + return true; + } + return g->remoteveh() != nullptr; +} - const optional_vpart_position vp = m.veh_at( player_character.pos() ); - bool veh_ctrl = !player_character.is_dead_state() && - ( ( vp && vp->vehicle().player_in_control( player_character ) ) || remoteveh() != nullptr ); - - // If performing an action with right mouse button, co-ordinates - // of location clicked. - cata::optional mouse_target; +static void do_deathcam_action( const action_id &act, avatar &player_character ) +{ + switch( act ) { + case ACTION_TOGGLE_MAP_MEMORY: + player_character.toggle_map_memory(); + break; - if( uquit == QUIT_WATCH && action == "QUIT" ) { - uquit = QUIT_DIED; - return false; - } + case ACTION_CENTER: + player_character.view_offset.x = g->driving_view_offset.x; + player_character.view_offset.y = g->driving_view_offset.y; + break; - if( act == ACTION_NULL ) { - act = look_up_action( action ); + case ACTION_SHIFT_N: + case ACTION_SHIFT_NE: + case ACTION_SHIFT_E: + case ACTION_SHIFT_SE: + case ACTION_SHIFT_S: + case ACTION_SHIFT_SW: + case ACTION_SHIFT_W: + case ACTION_SHIFT_NW: { + static const std::map> shift_delta = { + { ACTION_SHIFT_N, { point_north, point_north_east } }, + { ACTION_SHIFT_NE, { point_north_east, point_east } }, + { ACTION_SHIFT_E, { point_east, point_south_east } }, + { ACTION_SHIFT_SE, { point_south_east, point_south } }, + { ACTION_SHIFT_S, { point_south, point_south_west } }, + { ACTION_SHIFT_SW, { point_south_west, point_west } }, + { ACTION_SHIFT_W, { point_west, point_north_west } }, + { ACTION_SHIFT_NW, { point_north_west, point_north } }, + }; + int soffset = get_option( "MOVE_VIEW_OFFSET" ); + player_character.view_offset += use_tiles && tile_iso ? + shift_delta.at( act ).second * soffset : shift_delta.at( act ).first * soffset; + } + break; + + case ACTION_LOOK: + g->look_around(); + break; - if( act == ACTION_KEYBINDINGS ) { + case ACTION_KEYBINDINGS: // already handled by input context - return false; - } + break; - if( act == ACTION_MAIN_MENU ) { - if( uquit == QUIT_WATCH ) { - return false; - } - // No auto-move actions have or can be set at this point. - player_character.clear_destination(); - destination_preview.clear(); - act = handle_main_menu(); - if( act == ACTION_NULL ) { - return false; - } - } + default: + break; + } +} - if( act == ACTION_ACTIONMENU ) { - if( uquit == QUIT_WATCH ) { - return false; - } - // No auto-move actions have or can be set at this point. - player_character.clear_destination(); - destination_preview.clear(); - act = handle_action_menu(); - if( act == ACTION_NULL ) { - return false; - } -#if defined(__ANDROID__) - if( get_option( "ANDROID_ACTIONMENU_AUTOADD" ) && ctxt.get_category() == "DEFAULTMODE" ) { - add_best_key_for_action_to_quick_shortcuts( act, ctxt.get_category(), false ); +bool game::do_regular_action( action_id &act, avatar &player_character, + const cata::optional &mouse_target ) +{ + switch( act ) { + case ACTION_NULL: + case NUM_ACTIONS: + break; // dummy entries + case ACTION_ACTIONMENU: + case ACTION_MAIN_MENU: + case ACTION_KEYBINDINGS: + break; // handled above + + case ACTION_TIMEOUT: + if( check_safe_mode_allowed( false ) ) { + player_character.pause(); } -#endif - } + break; - if( act == ACTION_KEYBINDINGS ) { - player_character.clear_destination(); - destination_preview.clear(); - act = ctxt.display_menu( true ); - if( act == ACTION_NULL ) { - return false; + case ACTION_PAUSE: + if( check_safe_mode_allowed() ) { + player_character.pause(); } - } + break; - if( can_action_change_worldstate( act ) ) { - user_action_counter += 1; - } + case ACTION_CYCLE_MOVE: + player_character.cycle_move_mode(); + break; - if( act == ACTION_SELECT || act == ACTION_SEC_SELECT ) { - // Mouse button click - if( veh_ctrl ) { - // No mouse use in vehicle - return false; - } + case ACTION_RESET_MOVE: + player_character.reset_move_mode(); + break; - if( player_character.is_dead_state() ) { - // do not allow mouse actions while dead - return false; - } + case ACTION_TOGGLE_RUN: + player_character.toggle_run_mode(); + break; - const cata::optional mouse_pos = ctxt.get_coordinates( w_terrain ); - if( !mouse_pos ) { - return false; - } else if( !player_character.sees( *mouse_pos ) ) { - // Not clicked in visible terrain - return false; + case ACTION_TOGGLE_CROUCH: + player_character.toggle_crouch_mode(); + break; + + case ACTION_OPEN_MOVEMENT: + open_movement_mode_menu(); + break; + + case ACTION_MOVE_FORTH: + case ACTION_MOVE_FORTH_RIGHT: + case ACTION_MOVE_RIGHT: + case ACTION_MOVE_BACK_RIGHT: + case ACTION_MOVE_BACK: + case ACTION_MOVE_BACK_LEFT: + case ACTION_MOVE_LEFT: + case ACTION_MOVE_FORTH_LEFT: + if( !player_character.get_value( "remote_controlling" ).empty() && + ( player_character.has_active_item( itype_radiocontrol ) || + player_character.has_active_bionic( bio_remote ) ) ) { + rcdrive( get_delta_from_movement_action( act, iso_rotate::yes ) ); + } else if( has_vehicle_control( player_character ) ) { + // vehicle control uses x for steering and y for ac/deceleration, + // so no rotation needed + pldrive( get_delta_from_movement_action( act, iso_rotate::no ) ); + } else { + point dest_delta = get_delta_from_movement_action( act, iso_rotate::yes ); + if( auto_travel_mode && !player_character.is_auto_moving() ) { + for( int i = 0; i < SEEX; i++ ) { + tripoint auto_travel_destination( player_character.posx() + dest_delta.x * ( SEEX - i ), + player_character.posy() + dest_delta.y * ( SEEX - i ), + player_character.posz() ); + destination_preview = m.route( player_character.pos(), + auto_travel_destination, + player_character.get_pathfinding_settings(), + player_character.get_path_avoid() ); + if( !destination_preview.empty() ) { + destination_preview.erase( destination_preview.begin() + 1, destination_preview.end() ); + player_character.set_destination( destination_preview ); + break; + } + } + act = player_character.get_next_auto_move_direction(); + const point dest_next = get_delta_from_movement_action( act, iso_rotate::yes ); + if( dest_next == point_zero ) { + player_character.clear_destination(); + } + dest_delta = dest_next; + } + if( !avatar_action::move( player_character, m, dest_delta ) ) { + // auto-move should be canceled due to a failed move or obstacle + player_character.clear_destination(); + } } - mouse_target = mouse_pos; + break; + case ACTION_MOVE_DOWN: + if( player_character.is_mounted() ) { + auto *mon = player_character.mounted_creature.get(); + if( !mon->has_flag( MF_RIDEABLE_MECH ) ) { + add_msg( m_info, _( "You can't go down stairs while you're riding." ) ); + break; + } + } + if( !player_character.in_vehicle ) { + vertical_move( -1, false ); + } else if( has_vehicle_control( player_character ) ) { + const optional_vpart_position vp = get_map().veh_at( player_character.pos() ); + if( vp->vehicle().is_rotorcraft() ) { + pldrive( tripoint_below ); + } + } + break; - if( act == ACTION_SELECT ) { - // Note: The following has the potential side effect of - // setting auto-move destination state in addition to setting - // act. - if( !try_get_left_click_action( act, *mouse_target ) ) { - return false; + case ACTION_MOVE_UP: + if( player_character.is_mounted() ) { + auto *mon = player_character.mounted_creature.get(); + if( !mon->has_flag( MF_RIDEABLE_MECH ) ) { + add_msg( m_info, _( "You can't go up stairs while you're riding." ) ); + break; } - } else if( act == ACTION_SEC_SELECT ) { - if( !try_get_right_click_action( act, *mouse_target ) ) { - return false; + } + if( !player_character.in_vehicle ) { + vertical_move( 1, false ); + } else if( has_vehicle_control( player_character ) ) { + const optional_vpart_position vp = get_map().veh_at( player_character.pos() ); + if( vp->vehicle().is_rotorcraft() ) { + pldrive( tripoint_above ); } } - } else if( act != ACTION_TIMEOUT ) { - // act has not been set for an auto-move, so clearing possible - // auto-move destinations. Since initializing an auto-move with - // the mouse may span across multiple actions, we do not clear the - // auto-move destination if the action is only a timeout, as this - // would require the user to double click quicker than the - // timeout delay. - player_character.clear_destination(); - destination_preview.clear(); - } - } + break; - if( act == ACTION_NULL ) { - const input_event &&evt = ctxt.get_raw_input(); - if( !evt.sequence.empty() ) { - const int ch = evt.get_first_input(); - if( !get_option( "NO_UNKNOWN_COMMAND_MSG" ) ) { - add_msg( m_info, _( "Unknown command: \"%s\" (%ld)" ), evt.long_description(), ch ); - if( const cata::optional hint = - press_x_if_bound( ACTION_KEYBINDINGS ) ) { - add_msg( m_info, _( "%s at any time to see and edit keybindings relevant to " - "the current context." ), - *hint ); + case ACTION_OPEN: + if( player_character.has_active_mutation( trait_SHELL2 ) ) { + add_msg( m_info, _( "You can't open things while you're in your shell." ) ); + } else if( player_character.is_mounted() ) { + add_msg( m_info, _( "You can't open things while you're riding." ) ); + } else if( u.has_effect( effect_incorporeal ) ) { + add_msg( m_info, _( "You lack the substance to affect anything." ) ); + } else { + open(); + } + break; + + case ACTION_CLOSE: + if( player_character.has_active_mutation( trait_SHELL2 ) ) { + add_msg( m_info, _( "You can't close things while you're in your shell." ) ); + } else if( player_character.has_effect( effect_incorporeal ) ) { + add_msg( m_info, _( "You lack the substance to affect anything." ) ); + } else if( player_character.is_mounted() ) { + auto *mon = player_character.mounted_creature.get(); + if( !mon->has_flag( MF_RIDEABLE_MECH ) ) { + add_msg( m_info, _( "You can't close things while you're riding." ) ); } + } else if( mouse_target ) { + doors::close_door( m, player_character, *mouse_target ); + } else { + close(); } - } - return false; - } + break; - // This has no action unless we're in a special game mode. - gamemode->pre_action( act ); + case ACTION_SMASH: + if( has_vehicle_control( player_character ) ) { + handbrake(); + } else if( player_character.has_active_mutation( trait_SHELL2 ) ) { + add_msg( m_info, _( "You can't smash things while you're in your shell." ) ); + } else if( u.has_effect( effect_incorporeal ) ) { + add_msg( m_info, _( "You lack the substance to affect anything." ) ); + } else { + smash(); + } + break; - int soffset = get_option( "MOVE_VIEW_OFFSET" ); + case ACTION_EXAMINE: + if( player_character.has_active_mutation( trait_SHELL2 ) ) { + add_msg( m_info, _( "You can't examine your surroundings while you're in your shell." ) ); + } else if( mouse_target ) { + examine( *mouse_target ); + } else { + examine(); + } + break; - int before_action_moves = player_character.moves; + case ACTION_ADVANCEDINV: + if( player_character.has_active_mutation( trait_SHELL2 ) ) { + add_msg( m_info, _( "You can't move mass quantities while you're in your shell." ) ); + } else if( player_character.is_mounted() ) { + add_msg( m_info, _( "You can't move mass quantities while you're riding." ) ); + } else if( u.has_effect( effect_incorporeal ) ) { + add_msg( m_info, _( "You lack the substance to affect anything." ) ); + } else { + create_advanced_inv(); + } + break; - // These actions are allowed while deathcam is active. Registered in game::get_player_input - if( uquit == QUIT_WATCH || !player_character.is_dead_state() ) { - switch( act ) { - case ACTION_TOGGLE_MAP_MEMORY: - player_character.toggle_map_memory(); - break; + case ACTION_PICKUP: + if( player_character.has_active_mutation( trait_SHELL2 ) ) { + add_msg( m_info, _( "You can't pick anything up while you're in your shell." ) ); + } else if( player_character.is_mounted() ) { + add_msg( m_info, _( "You can't pick anything up while you're riding." ) ); + } else if( u.has_effect( effect_incorporeal ) ) { + add_msg( m_info, _( "You lack the substance to affect anything." ) ); + } else if( mouse_target ) { + pickup( *mouse_target ); + } else { + pickup(); + } + break; - case ACTION_CENTER: - player_character.view_offset.x = driving_view_offset.x; - player_character.view_offset.y = driving_view_offset.y; - break; + case ACTION_PICKUP_FEET: + if( player_character.has_active_mutation( trait_SHELL2 ) ) { + add_msg( m_info, _( "You can't pick anything up while you're in your shell." ) ); + } else if( u.has_effect( effect_incorporeal ) ) { + add_msg( m_info, _( "You lack the substance to affect anything." ) ); + } else { + pickup_feet(); + } + break; - case ACTION_SHIFT_N: - case ACTION_SHIFT_NE: - case ACTION_SHIFT_E: - case ACTION_SHIFT_SE: - case ACTION_SHIFT_S: - case ACTION_SHIFT_SW: - case ACTION_SHIFT_W: - case ACTION_SHIFT_NW: { - static const std::map> shift_delta = { - { ACTION_SHIFT_N, { point_north, point_north_east } }, - { ACTION_SHIFT_NE, { point_north_east, point_east } }, - { ACTION_SHIFT_E, { point_east, point_south_east } }, - { ACTION_SHIFT_SE, { point_south_east, point_south } }, - { ACTION_SHIFT_S, { point_south, point_south_west } }, - { ACTION_SHIFT_SW, { point_south_west, point_west } }, - { ACTION_SHIFT_W, { point_west, point_north_west } }, - { ACTION_SHIFT_NW, { point_north_west, point_north } }, - }; - player_character.view_offset += use_tiles && tile_iso ? - shift_delta.at( act ).second * soffset : shift_delta.at( act ).first * soffset; - } - break; - - case ACTION_LOOK: - look_around(); - break; + case ACTION_GRAB: + if( player_character.has_active_mutation( trait_SHELL2 ) ) { + add_msg( m_info, _( "You can't grab things while you're in your shell." ) ); + } else if( player_character.is_mounted() ) { + add_msg( m_info, _( "You can't grab things while you're riding." ) ); + } else if( u.has_effect( effect_incorporeal ) ) { + add_msg( m_info, _( "You lack the substance to affect anything." ) ); + } else { + grab(); + } + break; - case ACTION_KEYBINDINGS: - // already handled by input context - break; + case ACTION_HAUL: + if( player_character.has_active_mutation( trait_SHELL2 ) ) { + add_msg( m_info, _( "You can't haul things while you're in your shell." ) ); + } else if( player_character.is_mounted() ) { + add_msg( m_info, _( "You can't haul things while you're riding." ) ); + } else if( u.has_effect( effect_incorporeal ) ) { + add_msg( m_info, _( "You lack the substance to affect anything." ) ); + } else { + haul(); + } + break; - default: - break; - } - } + case ACTION_BUTCHER: + if( player_character.has_active_mutation( trait_SHELL2 ) ) { + add_msg( m_info, _( "You can't butcher while you're in your shell." ) ); + } else if( player_character.is_mounted() ) { + add_msg( m_info, _( "You can't butcher while you're riding." ) ); + } else if( u.has_effect( effect_incorporeal ) ) { + add_msg( m_info, _( "You lack the substance to affect anything." ) ); + } else { + butcher(); + } + break; - // actions allowed only while alive - if( !player_character.is_dead_state() ) { - switch( act ) { - case ACTION_NULL: - case NUM_ACTIONS: - break; // dummy entries - case ACTION_ACTIONMENU: - case ACTION_MAIN_MENU: - case ACTION_KEYBINDINGS: - break; // handled above - - case ACTION_TIMEOUT: - if( check_safe_mode_allowed( false ) ) { - player_character.pause(); - } - break; + case ACTION_CHAT: + chat(); + break; - case ACTION_PAUSE: - if( check_safe_mode_allowed() ) { - player_character.pause(); - } - break; + case ACTION_PEEK: + if( player_character.has_active_mutation( trait_SHELL2 ) ) { + add_msg( m_info, _( "You can't peek around corners while you're in your shell." ) ); + } else if( player_character.is_mounted() ) { + add_msg( m_info, _( "You can't peek around corners while you're riding." ) ); + } else { + peek(); + } + break; - case ACTION_CYCLE_MOVE: - player_character.cycle_move_mode(); - break; + case ACTION_LIST_ITEMS: + list_items_monsters(); + break; - case ACTION_RESET_MOVE: - player_character.reset_move_mode(); - break; + case ACTION_ZONES: + zones_manager(); + break; - case ACTION_TOGGLE_RUN: - player_character.toggle_run_mode(); - break; + case ACTION_LOOT: + loot(); + break; - case ACTION_TOGGLE_CROUCH: - player_character.toggle_crouch_mode(); - break; + case ACTION_INVENTORY: + game_menus::inv::common( player_character ); + break; - case ACTION_OPEN_MOVEMENT: - open_movement_mode_menu(); - break; + case ACTION_COMPARE: + game_menus::inv::compare( player_character, cata::nullopt ); + break; - case ACTION_MOVE_FORTH: - case ACTION_MOVE_FORTH_RIGHT: - case ACTION_MOVE_RIGHT: - case ACTION_MOVE_BACK_RIGHT: - case ACTION_MOVE_BACK: - case ACTION_MOVE_BACK_LEFT: - case ACTION_MOVE_LEFT: - case ACTION_MOVE_FORTH_LEFT: - if( !player_character.get_value( "remote_controlling" ).empty() && - ( player_character.has_active_item( itype_radiocontrol ) || - player_character.has_active_bionic( bio_remote ) ) ) { - rcdrive( get_delta_from_movement_action( act, iso_rotate::yes ) ); - } else if( veh_ctrl ) { - // vehicle control uses x for steering and y for ac/deceleration, - // so no rotation needed - pldrive( get_delta_from_movement_action( act, iso_rotate::no ) ); - } else { - point dest_delta = get_delta_from_movement_action( act, iso_rotate::yes ); - if( auto_travel_mode && !player_character.is_auto_moving() ) { - for( int i = 0; i < SEEX; i++ ) { - tripoint auto_travel_destination( player_character.posx() + dest_delta.x * ( SEEX - i ), - player_character.posy() + dest_delta.y * ( SEEX - i ), - player_character.posz() ); - destination_preview = m.route( player_character.pos(), - auto_travel_destination, - player_character.get_pathfinding_settings(), - player_character.get_path_avoid() ); - if( !destination_preview.empty() ) { - destination_preview.erase( destination_preview.begin() + 1, destination_preview.end() ); - player_character.set_destination( destination_preview ); - break; - } - } - act = player_character.get_next_auto_move_direction(); - const point dest_next = get_delta_from_movement_action( act, iso_rotate::yes ); - if( dest_next == point_zero ) { - player_character.clear_destination(); - } - dest_delta = dest_next; - } - if( !avatar_action::move( player_character, m, dest_delta ) ) { - // auto-move should be canceled due to a failed move or obstacle - player_character.clear_destination(); - } - } - break; - case ACTION_MOVE_DOWN: - if( player_character.is_mounted() ) { - auto *mon = player_character.mounted_creature.get(); - if( !mon->has_flag( MF_RIDEABLE_MECH ) ) { - add_msg( m_info, _( "You can't go down stairs while you're riding." ) ); - break; - } - } - if( !player_character.in_vehicle ) { - vertical_move( -1, false ); - } else if( veh_ctrl && vp->vehicle().is_rotorcraft() ) { - pldrive( tripoint_below ); - } - break; + case ACTION_ORGANIZE: + game_menus::inv::swap_letters( player_character ); + break; - case ACTION_MOVE_UP: - if( player_character.is_mounted() ) { - auto *mon = player_character.mounted_creature.get(); - if( !mon->has_flag( MF_RIDEABLE_MECH ) ) { - add_msg( m_info, _( "You can't go up stairs while you're riding." ) ); - break; - } - } - if( !player_character.in_vehicle ) { - vertical_move( 1, false ); - } else if( veh_ctrl && vp->vehicle().is_rotorcraft() ) { - pldrive( tripoint_above ); - } - break; + case ACTION_USE: + // Shell-users are presumed to be able to mess with their inventories, etc + // while in the shell. Eating, gear-changing, and item use are OK. + avatar_action::use_item( player_character ); + break; - case ACTION_OPEN: - if( player_character.has_active_mutation( trait_SHELL2 ) ) { - add_msg( m_info, _( "You can't open things while you're in your shell." ) ); - } else if( player_character.is_mounted() ) { - add_msg( m_info, _( "You can't open things while you're riding." ) ); - } else if( u.has_effect( effect_incorporeal ) ) { - add_msg( m_info, _( "You lack the substance to affect anything." ) ); - } else { - open(); - } - break; + case ACTION_USE_WIELDED: + player_character.use_wielded(); + break; - case ACTION_CLOSE: - if( player_character.has_active_mutation( trait_SHELL2 ) ) { - add_msg( m_info, _( "You can't close things while you're in your shell." ) ); - } else if( player_character.has_effect( effect_incorporeal ) ) { - add_msg( m_info, _( "You lack the substance to affect anything." ) ); - } else if( player_character.is_mounted() ) { - auto *mon = player_character.mounted_creature.get(); - if( !mon->has_flag( MF_RIDEABLE_MECH ) ) { - add_msg( m_info, _( "You can't close things while you're riding." ) ); - } - } else if( mouse_target ) { - doors::close_door( m, player_character, *mouse_target ); - } else { - close(); - } - break; + case ACTION_WEAR: + wear(); + break; - case ACTION_SMASH: - if( veh_ctrl ) { - handbrake(); - } else if( player_character.has_active_mutation( trait_SHELL2 ) ) { - add_msg( m_info, _( "You can't smash things while you're in your shell." ) ); - } else if( u.has_effect( effect_incorporeal ) ) { - add_msg( m_info, _( "You lack the substance to affect anything." ) ); - } else { - smash(); - } - break; + case ACTION_TAKE_OFF: + takeoff(); + break; - case ACTION_EXAMINE: - if( player_character.has_active_mutation( trait_SHELL2 ) ) { - add_msg( m_info, _( "You can't examine your surroundings while you're in your shell." ) ); - } else if( mouse_target ) { - examine( *mouse_target ); - } else { - examine(); - } - break; + case ACTION_EAT: + if( !avatar_action::eat_here( player_character ) ) { + avatar_action::eat( player_character, game_menus::inv::consume( player_character ) ); + } + break; - case ACTION_ADVANCEDINV: - if( player_character.has_active_mutation( trait_SHELL2 ) ) { - add_msg( m_info, _( "You can't move mass quantities while you're in your shell." ) ); - } else if( player_character.is_mounted() ) { - add_msg( m_info, _( "You can't move mass quantities while you're riding." ) ); - } else if( u.has_effect( effect_incorporeal ) ) { - add_msg( m_info, _( "You lack the substance to affect anything." ) ); - } else { - create_advanced_inv(); - } - break; + case ACTION_OPEN_CONSUME: + if( !avatar_action::eat_here( player_character ) ) { + open_consume_item_menu(); + } + break; - case ACTION_PICKUP: - if( player_character.has_active_mutation( trait_SHELL2 ) ) { - add_msg( m_info, _( "You can't pick anything up while you're in your shell." ) ); - } else if( player_character.is_mounted() ) { - add_msg( m_info, _( "You can't pick anything up while you're riding." ) ); - } else if( u.has_effect( effect_incorporeal ) ) { - add_msg( m_info, _( "You lack the substance to affect anything." ) ); - } else if( mouse_target ) { - pickup( *mouse_target ); - } else { - pickup(); - } - break; + case ACTION_READ: + // Shell-users are presumed to have the book just at an opening and read it that way + read(); + break; - case ACTION_PICKUP_FEET: - if( player_character.has_active_mutation( trait_SHELL2 ) ) { - add_msg( m_info, _( "You can't pick anything up while you're in your shell." ) ); - } else if( u.has_effect( effect_incorporeal ) ) { - add_msg( m_info, _( "You lack the substance to affect anything." ) ); - } else { - pickup_feet(); - } - break; + case ACTION_WIELD: + wield(); + break; - case ACTION_GRAB: - if( player_character.has_active_mutation( trait_SHELL2 ) ) { - add_msg( m_info, _( "You can't grab things while you're in your shell." ) ); - } else if( player_character.is_mounted() ) { - add_msg( m_info, _( "You can't grab things while you're riding." ) ); - } else if( u.has_effect( effect_incorporeal ) ) { - add_msg( m_info, _( "You lack the substance to affect anything." ) ); - } else { - grab(); - } - break; + case ACTION_PICK_STYLE: + player_character.martial_arts_data->pick_style( player_character ); + break; - case ACTION_HAUL: - if( player_character.has_active_mutation( trait_SHELL2 ) ) { - add_msg( m_info, _( "You can't haul things while you're in your shell." ) ); - } else if( player_character.is_mounted() ) { - add_msg( m_info, _( "You can't haul things while you're riding." ) ); - } else if( u.has_effect( effect_incorporeal ) ) { - add_msg( m_info, _( "You lack the substance to affect anything." ) ); - } else { - haul(); - } - break; + case ACTION_RELOAD_ITEM: + reload_item(); + break; - case ACTION_BUTCHER: - if( player_character.has_active_mutation( trait_SHELL2 ) ) { - add_msg( m_info, _( "You can't butcher while you're in your shell." ) ); - } else if( player_character.is_mounted() ) { - add_msg( m_info, _( "You can't butcher while you're riding." ) ); - } else if( u.has_effect( effect_incorporeal ) ) { - add_msg( m_info, _( "You lack the substance to affect anything." ) ); - } else { - butcher(); - } - break; + case ACTION_RELOAD_WEAPON: + reload_weapon(); + break; - case ACTION_CHAT: - chat(); - break; + case ACTION_RELOAD_WIELDED: + reload_wielded(); + break; - case ACTION_PEEK: - if( player_character.has_active_mutation( trait_SHELL2 ) ) { - add_msg( m_info, _( "You can't peek around corners while you're in your shell." ) ); - } else if( player_character.is_mounted() ) { - add_msg( m_info, _( "You can't peek around corners while you're riding." ) ); - } else { - peek(); - } - break; + case ACTION_UNLOAD: + avatar_action::unload( player_character ); + break; - case ACTION_LIST_ITEMS: - list_items_monsters(); - break; + case ACTION_MEND: + avatar_action::mend( player_character, item_location() ); + break; - case ACTION_ZONES: - zones_manager(); - break; + case ACTION_THROW: { + item_location loc; + avatar_action::plthrow( player_character, loc ); + break; + } - case ACTION_LOOT: - loot(); - break; + case ACTION_FIRE: + fire(); + break; - case ACTION_INVENTORY: - game_menus::inv::common( player_character ); - break; + case ACTION_CAST_SPELL: + cast_spell(); + break; - case ACTION_COMPARE: - game_menus::inv::compare( player_character, cata::nullopt ); - break; + case ACTION_FIRE_BURST: { + gun_mode_id original_mode = player_character.weapon.gun_get_mode_id(); + if( player_character.weapon.gun_set_mode( gun_mode_id( "AUTO" ) ) ) { + avatar_action::fire_wielded_weapon( player_character ); + player_character.weapon.gun_set_mode( original_mode ); + } + break; + } - case ACTION_ORGANIZE: - game_menus::inv::swap_letters( player_character ); - break; + case ACTION_SELECT_FIRE_MODE: + if( player_character.is_armed() ) { + if( player_character.weapon.is_gun() && !player_character.weapon.is_gunmod() && + player_character.weapon.gun_all_modes().size() > 1 ) { + player_character.weapon.gun_cycle_mode(); + } else if( player_character.weapon.has_flag( flag_RELOAD_ONE ) || + player_character.weapon.has_flag( flag_RELOAD_AND_SHOOT ) ) { + item::reload_option opt = player_character.select_ammo( player_character.weapon, false ); + if( !opt ) { + break; + } else if( player_character.ammo_location && opt.ammo == player_character.ammo_location ) { + player_character.ammo_location = item_location(); + } else { + player_character.ammo_location = opt.ammo; + } + } + } + break; - case ACTION_USE: - // Shell-users are presumed to be able to mess with their inventories, etc - // while in the shell. Eating, gear-changing, and item use are OK. - avatar_action::use_item( player_character ); - break; + case ACTION_DROP: + // You CAN drop things to your own tile while in the shell. + drop(); + break; - case ACTION_USE_WIELDED: - player_character.use_wielded(); - break; + case ACTION_DIR_DROP: + if( player_character.has_active_mutation( trait_SHELL2 ) ) { + add_msg( m_info, _( "You can't drop things to another tile while you're in your shell." ) ); + } else { + drop_in_direction(); + } + break; + case ACTION_BIONICS: + player_character.power_bionics(); + break; + case ACTION_MUTATIONS: + player_character.power_mutations(); + break; - case ACTION_WEAR: - wear(); - break; + case ACTION_SORT_ARMOR: + player_character.sort_armor(); + break; - case ACTION_TAKE_OFF: - takeoff(); - break; + case ACTION_WAIT: + wait(); + break; - case ACTION_EAT: - if( !avatar_action::eat_here( player_character ) ) { - avatar_action::eat( player_character, game_menus::inv::consume( player_character ) ); - } - break; + case ACTION_CRAFT: + if( player_character.has_active_mutation( trait_SHELL2 ) ) { + add_msg( m_info, _( "You can't craft while you're in your shell." ) ); + } else if( player_character.has_effect( effect_incorporeal ) ) { + add_msg( m_info, _( "You lack the substance to affect anything." ) ); + } else if( player_character.is_mounted() ) { + add_msg( m_info, _( "You can't craft while you're riding." ) ); + } else { + player_character.craft(); + } + break; - case ACTION_OPEN_CONSUME: - if( !avatar_action::eat_here( player_character ) ) { - open_consume_item_menu(); - } - break; + case ACTION_RECRAFT: + if( player_character.has_active_mutation( trait_SHELL2 ) ) { + add_msg( m_info, _( "You can't craft while you're in your shell." ) ); + } else if( player_character.has_effect( effect_incorporeal ) ) { + add_msg( m_info, _( "You lack the substance to affect anything." ) ); + } else if( player_character.is_mounted() ) { + add_msg( m_info, _( "You can't craft while you're riding." ) ); + } else { + player_character.recraft(); + } + break; - case ACTION_READ: - // Shell-users are presumed to have the book just at an opening and read it that way - read(); - break; + case ACTION_LONGCRAFT: + if( player_character.has_active_mutation( trait_SHELL2 ) ) { + add_msg( m_info, _( "You can't craft while you're in your shell." ) ); + } else if( player_character.is_mounted() ) { + add_msg( m_info, _( "You can't craft while you're riding." ) ); + } else if( u.has_effect( effect_incorporeal ) ) { + add_msg( m_info, _( "You lack the substance to affect anything." ) ); + } else { + player_character.long_craft(); + } + break; - case ACTION_WIELD: - wield(); - break; + case ACTION_DISASSEMBLE: + if( player_character.controlling_vehicle ) { + add_msg( m_info, _( "You can't disassemble items while driving." ) ); + } else if( player_character.is_mounted() ) { + add_msg( m_info, _( "You can't disassemble items while you're riding." ) ); + } else if( u.has_effect( effect_incorporeal ) ) { + add_msg( m_info, _( "You lack the substance to affect anything." ) ); + } else { + player_character.disassemble(); + } + break; - case ACTION_PICK_STYLE: - player_character.martial_arts_data->pick_style( player_character ); - break; + case ACTION_CONSTRUCT: + if( player_character.in_vehicle ) { + add_msg( m_info, _( "You can't construct while in a vehicle." ) ); + } else if( player_character.has_active_mutation( trait_SHELL2 ) ) { + add_msg( m_info, _( "You can't construct while you're in your shell." ) ); + } else if( player_character.is_mounted() ) { + add_msg( m_info, _( "You can't construct while you're riding." ) ); + } else if( u.has_effect( effect_incorporeal ) ) { + add_msg( m_info, _( "You lack the substance to affect anything." ) ); + } else { + construction_menu( false ); + } + break; - case ACTION_RELOAD_ITEM: - reload_item(); - break; + case ACTION_SLEEP: + if( has_vehicle_control( player_character ) ) { + add_msg( m_info, _( "Vehicle control has moved, %s" ), + press_x( ACTION_CONTROL_VEHICLE, _( "new binding is " ), + _( "new default binding is '^'." ) ) ); + } else { + sleep(); + } + break; - case ACTION_RELOAD_WEAPON: - reload_weapon(); - break; + case ACTION_CONTROL_VEHICLE: + if( player_character.has_active_mutation( trait_SHELL2 ) ) { + add_msg( m_info, _( "You can't operate a vehicle while you're in your shell." ) ); + } else if( player_character.is_mounted() ) { + player_character.dismount(); + } else if( player_character.has_trait( trait_WAYFARER ) ) { + add_msg( m_info, _( "You refuse to take control of this vehicle." ) ); + } else if( u.has_effect( effect_incorporeal ) ) { + add_msg( m_info, _( "You lack the substance to affect anything." ) ); + } else { + control_vehicle(); + } + break; - case ACTION_RELOAD_WIELDED: - reload_wielded(); - break; + case ACTION_TOGGLE_AUTO_TRAVEL_MODE: + auto_travel_mode = !auto_travel_mode; + add_msg( m_info, auto_travel_mode ? _( "Auto travel mode ON!" ) : _( "Auto travel mode OFF!" ) ); + break; - case ACTION_UNLOAD: - avatar_action::unload( player_character ); - break; + case ACTION_TOGGLE_SAFEMODE: + if( safe_mode == SAFE_MODE_OFF ) { + set_safe_mode( SAFE_MODE_ON ); + mostseen = 0; + add_msg( m_info, _( "Safe mode ON!" ) ); + } else { + turnssincelastmon = 0_turns; + set_safe_mode( SAFE_MODE_OFF ); + add_msg( m_info, get_option( "AUTOSAFEMODE" ) + ? _( "Safe mode OFF! (Auto safe mode still enabled!)" ) : _( "Safe mode OFF!" ) ); + } + if( player_character.has_effect( effect_laserlocked ) ) { + player_character.remove_effect( effect_laserlocked ); + safe_mode_warning_logged = false; + } + break; - case ACTION_MEND: - avatar_action::mend( player_character, item_location() ); - break; + case ACTION_TOGGLE_AUTOSAFE: { + auto &autosafemode_option = get_options().get_option( "AUTOSAFEMODE" ); + add_msg( m_info, autosafemode_option.value_as() + ? _( "Auto safe mode OFF!" ) : _( "Auto safe mode ON!" ) ); + autosafemode_option.setNext(); + break; + } - case ACTION_THROW: { - item_location loc; - avatar_action::plthrow( player_character, loc ); - break; + case ACTION_IGNORE_ENEMY: + if( safe_mode == SAFE_MODE_STOP ) { + add_msg( m_info, _( "Ignoring enemy!" ) ); + for( auto &elem : player_character.get_mon_visible().new_seen_mon ) { + monster &critter = *elem; + critter.ignoring = rl_dist( player_character.pos(), critter.pos() ); + } + set_safe_mode( SAFE_MODE_ON ); + } else if( player_character.has_effect( effect_laserlocked ) ) { + if( player_character.has_trait( trait_PROF_CHURL ) ) { + add_msg( m_warning, _( "You make the sign of the cross." ) ); + } else { + add_msg( m_info, _( "Ignoring laser targeting!" ) ); + } + player_character.remove_effect( effect_laserlocked ); + safe_mode_warning_logged = false; } + break; - case ACTION_FIRE: - fire(); - break; + case ACTION_WHITELIST_ENEMY: + if( safe_mode == SAFE_MODE_STOP && !get_safemode().empty() ) { + get_safemode().add_rule( get_safemode().lastmon_whitelist, Creature::Attitude::ANY, 0, + rule_state::WHITELISTED ); + add_msg( m_info, _( "Creature whitelisted: %s" ), get_safemode().lastmon_whitelist ); + set_safe_mode( SAFE_MODE_ON ); + mostseen = 0; + } else { + get_safemode().show(); + } + break; - case ACTION_CAST_SPELL: - cast_spell(); - break; + case ACTION_WORKOUT: + if( query_yn( _( "Start workout?" ) ) ) { + player_character.assign_activity( player_activity( workout_activity_actor( + player_character.pos() ) ) ); + } + break; - case ACTION_FIRE_BURST: { - gun_mode_id original_mode = player_character.weapon.gun_get_mode_id(); - if( player_character.weapon.gun_set_mode( gun_mode_id( "AUTO" ) ) ) { - avatar_action::fire_wielded_weapon( player_character ); - player_character.weapon.gun_set_mode( original_mode ); + case ACTION_SUICIDE: + if( query_yn( _( "Commit suicide?" ) ) ) { + if( query_yn( _( "REALLY commit suicide?" ) ) ) { + player_character.moves = 0; + player_character.place_corpse(); + uquit = QUIT_SUICIDE; } - break; } + break; - case ACTION_SELECT_FIRE_MODE: - if( player_character.is_armed() ) { - if( player_character.weapon.is_gun() && !player_character.weapon.is_gunmod() && - player_character.weapon.gun_all_modes().size() > 1 ) { - player_character.weapon.gun_cycle_mode(); - } else if( player_character.weapon.has_flag( flag_RELOAD_ONE ) || - player_character.weapon.has_flag( flag_RELOAD_AND_SHOOT ) ) { - item::reload_option opt = player_character.select_ammo( player_character.weapon, false ); - if( !opt ) { - break; - } else if( player_character.ammo_location && opt.ammo == player_character.ammo_location ) { - player_character.ammo_location = item_location(); - } else { - player_character.ammo_location = opt.ammo; - } - } + case ACTION_SAVE: + if( query_yn( _( "Save and quit?" ) ) ) { + if( save() ) { + player_character.moves = 0; + uquit = QUIT_SAVED; } - break; + } + break; - case ACTION_DROP: - // You CAN drop things to your own tile while in the shell. - drop(); - break; + case ACTION_QUICKSAVE: + quicksave(); + return false; - case ACTION_DIR_DROP: - if( player_character.has_active_mutation( trait_SHELL2 ) ) { - add_msg( m_info, _( "You can't drop things to another tile while you're in your shell." ) ); - } else { - drop_in_direction(); - } - break; - case ACTION_BIONICS: - player_character.power_bionics(); - break; - case ACTION_MUTATIONS: - player_character.power_mutations(); - break; + case ACTION_QUICKLOAD: + quickload(); + return false; - case ACTION_SORT_ARMOR: - player_character.sort_armor(); - break; + case ACTION_PL_INFO: + player_character.disp_info(); + break; - case ACTION_WAIT: - wait(); - break; + case ACTION_MAP: + ui::omap::display(); + break; - case ACTION_CRAFT: - if( player_character.has_active_mutation( trait_SHELL2 ) ) { - add_msg( m_info, _( "You can't craft while you're in your shell." ) ); - } else if( player_character.has_effect( effect_incorporeal ) ) { - add_msg( m_info, _( "You lack the substance to affect anything." ) ); - } else if( player_character.is_mounted() ) { - add_msg( m_info, _( "You can't craft while you're riding." ) ); - } else { - player_character.craft(); - } - break; + case ACTION_SKY: + if( m.is_outside( player_character.pos() ) ) { + ui::omap::display_visible_weather(); + } else { + add_msg( m_info, _( "You can't see the sky from here." ) ); + } + break; - case ACTION_RECRAFT: - if( player_character.has_active_mutation( trait_SHELL2 ) ) { - add_msg( m_info, _( "You can't craft while you're in your shell." ) ); - } else if( player_character.has_effect( effect_incorporeal ) ) { - add_msg( m_info, _( "You lack the substance to affect anything." ) ); - } else if( player_character.is_mounted() ) { - add_msg( m_info, _( "You can't craft while you're riding." ) ); - } else { - player_character.recraft(); - } - break; + case ACTION_MISSIONS: + list_missions(); + break; - case ACTION_LONGCRAFT: - if( player_character.has_active_mutation( trait_SHELL2 ) ) { - add_msg( m_info, _( "You can't craft while you're in your shell." ) ); - } else if( player_character.is_mounted() ) { - add_msg( m_info, _( "You can't craft while you're riding." ) ); - } else if( u.has_effect( effect_incorporeal ) ) { - add_msg( m_info, _( "You lack the substance to affect anything." ) ); - } else { - player_character.long_craft(); - } - break; + case ACTION_SCORES: + show_scores_ui( *achievements_tracker_ptr, stats(), get_kill_tracker() ); + break; - case ACTION_DISASSEMBLE: - if( player_character.controlling_vehicle ) { - add_msg( m_info, _( "You can't disassemble items while driving." ) ); - } else if( player_character.is_mounted() ) { - add_msg( m_info, _( "You can't disassemble items while you're riding." ) ); - } else if( u.has_effect( effect_incorporeal ) ) { - add_msg( m_info, _( "You lack the substance to affect anything." ) ); - } else { - player_character.disassemble(); - } - break; + case ACTION_FACTIONS: + faction_manager_ptr->display(); + break; - case ACTION_CONSTRUCT: - if( player_character.in_vehicle ) { - add_msg( m_info, _( "You can't construct while in a vehicle." ) ); - } else if( player_character.has_active_mutation( trait_SHELL2 ) ) { - add_msg( m_info, _( "You can't construct while you're in your shell." ) ); - } else if( player_character.is_mounted() ) { - add_msg( m_info, _( "You can't construct while you're riding." ) ); - } else if( u.has_effect( effect_incorporeal ) ) { - add_msg( m_info, _( "You lack the substance to affect anything." ) ); - } else { - construction_menu( false ); - } - break; + case ACTION_MORALE: + player_character.disp_morale(); + break; - case ACTION_SLEEP: - if( veh_ctrl ) { - add_msg( m_info, _( "Vehicle control has moved, %s" ), - press_x( ACTION_CONTROL_VEHICLE, _( "new binding is " ), - _( "new default binding is '^'." ) ) ); - } else { - sleep(); - } - break; + case ACTION_MESSAGES: + Messages::display_messages(); + break; - case ACTION_CONTROL_VEHICLE: - if( player_character.has_active_mutation( trait_SHELL2 ) ) { - add_msg( m_info, _( "You can't operate a vehicle while you're in your shell." ) ); - } else if( player_character.is_mounted() ) { - player_character.dismount(); - } else if( player_character.has_trait( trait_WAYFARER ) ) { - add_msg( m_info, _( "You refuse to take control of this vehicle." ) ); - } else if( u.has_effect( effect_incorporeal ) ) { - add_msg( m_info, _( "You lack the substance to affect anything." ) ); - } else { - control_vehicle(); - } - break; + case ACTION_HELP: + get_help().display_help(); + break; - case ACTION_TOGGLE_AUTO_TRAVEL_MODE: - auto_travel_mode = !auto_travel_mode; - add_msg( m_info, auto_travel_mode ? _( "Auto travel mode ON!" ) : _( "Auto travel mode OFF!" ) ); - break; + case ACTION_OPTIONS: + get_options().show( true ); + break; - case ACTION_TOGGLE_SAFEMODE: - if( safe_mode == SAFE_MODE_OFF ) { - set_safe_mode( SAFE_MODE_ON ); - mostseen = 0; - add_msg( m_info, _( "Safe mode ON!" ) ); - } else { - turnssincelastmon = 0_turns; - set_safe_mode( SAFE_MODE_OFF ); - add_msg( m_info, get_option( "AUTOSAFEMODE" ) - ? _( "Safe mode OFF! (Auto safe mode still enabled!)" ) : _( "Safe mode OFF!" ) ); - } - if( player_character.has_effect( effect_laserlocked ) ) { - player_character.remove_effect( effect_laserlocked ); - safe_mode_warning_logged = false; - } - break; + case ACTION_AUTOPICKUP: + get_auto_pickup().show(); + break; - case ACTION_TOGGLE_AUTOSAFE: { - auto &autosafemode_option = get_options().get_option( "AUTOSAFEMODE" ); - add_msg( m_info, autosafemode_option.value_as() - ? _( "Auto safe mode OFF!" ) : _( "Auto safe mode ON!" ) ); - autosafemode_option.setNext(); - break; - } + case ACTION_AUTONOTES: + get_auto_notes_settings().show_gui(); + break; - case ACTION_IGNORE_ENEMY: - if( safe_mode == SAFE_MODE_STOP ) { - add_msg( m_info, _( "Ignoring enemy!" ) ); - for( auto &elem : player_character.get_mon_visible().new_seen_mon ) { - monster &critter = *elem; - critter.ignoring = rl_dist( player_character.pos(), critter.pos() ); - } - set_safe_mode( SAFE_MODE_ON ); - } else if( player_character.has_effect( effect_laserlocked ) ) { - if( player_character.has_trait( trait_PROF_CHURL ) ) { - add_msg( m_warning, _( "You make the sign of the cross." ) ); - } else { - add_msg( m_info, _( "Ignoring laser targeting!" ) ); - } - player_character.remove_effect( effect_laserlocked ); - safe_mode_warning_logged = false; - } - break; + case ACTION_SAFEMODE: + get_safemode().show(); + break; + + case ACTION_COLOR: + all_colors.show_gui(); + break; - case ACTION_WHITELIST_ENEMY: - if( safe_mode == SAFE_MODE_STOP && !get_safemode().empty() ) { - get_safemode().add_rule( get_safemode().lastmon_whitelist, Creature::Attitude::ANY, 0, - rule_state::WHITELISTED ); - add_msg( m_info, _( "Creature whitelisted: %s" ), get_safemode().lastmon_whitelist ); - set_safe_mode( SAFE_MODE_ON ); - mostseen = 0; - } else { - get_safemode().show(); - } - break; + case ACTION_WORLD_MODS: + world_generator->show_active_world_mods( world_generator->active_world->active_mod_order ); + break; - case ACTION_WORKOUT: - if( query_yn( _( "Start workout?" ) ) ) { - player_character.assign_activity( player_activity( workout_activity_actor( - player_character.pos() ) ) ); - } - break; + case ACTION_DEBUG: + if( MAP_SHARING::isCompetitive() && !MAP_SHARING::isDebugger() ) { + break; //don't do anything when sharing and not debugger + } + debug_menu::debug(); + break; - case ACTION_SUICIDE: - if( query_yn( _( "Commit suicide?" ) ) ) { - if( query_yn( _( "REALLY commit suicide?" ) ) ) { - player_character.moves = 0; - player_character.place_corpse(); - uquit = QUIT_SUICIDE; - } - } - break; + case ACTION_TOGGLE_FULLSCREEN: + toggle_fullscreen(); + break; - case ACTION_SAVE: - if( query_yn( _( "Save and quit?" ) ) ) { - if( save() ) { - player_character.moves = 0; - uquit = QUIT_SAVED; - } - } - break; + case ACTION_TOGGLE_PIXEL_MINIMAP: + toggle_pixel_minimap(); + break; - case ACTION_QUICKSAVE: - quicksave(); - return false; + case ACTION_TOGGLE_PANEL_ADM: + panel_manager::get_manager().show_adm(); + break; - case ACTION_QUICKLOAD: - quickload(); - return false; + case ACTION_RELOAD_TILESET: + reload_tileset(); + break; - case ACTION_PL_INFO: - player_character.disp_info(); - break; + case ACTION_TOGGLE_AUTO_FEATURES: + get_options().get_option( "AUTO_FEATURES" ).setNext(); + get_options().save(); + //~ Auto Features are now ON/OFF + add_msg( _( "%s are now %s." ), + get_options().get_option( "AUTO_FEATURES" ).getMenuText(), + get_option( "AUTO_FEATURES" ) ? _( "ON" ) : _( "OFF" ) ); + break; - case ACTION_MAP: - ui::omap::display(); - break; + case ACTION_TOGGLE_AUTO_PULP_BUTCHER: + get_options().get_option( "AUTO_PULP_BUTCHER" ).setNext(); + get_options().save(); + //~ Auto Pulp/Pulp Adjacent/Butcher is now set to x + add_msg( _( "%s is now set to %s." ), + get_options().get_option( "AUTO_PULP_BUTCHER" ).getMenuText(), + get_options().get_option( "AUTO_PULP_BUTCHER" ).getValueName() ); + break; - case ACTION_SKY: - if( m.is_outside( player_character.pos() ) ) { - ui::omap::display_visible_weather(); - } else { - add_msg( m_info, _( "You can't see the sky from here." ) ); - } - break; + case ACTION_TOGGLE_AUTO_MINING: + get_options().get_option( "AUTO_MINING" ).setNext(); + get_options().save(); + //~ Auto Mining is now ON/OFF + add_msg( _( "%s is now %s." ), + get_options().get_option( "AUTO_MINING" ).getMenuText(), + get_option( "AUTO_MINING" ) ? _( "ON" ) : _( "OFF" ) ); + break; - case ACTION_MISSIONS: - list_missions(); - break; + case ACTION_TOGGLE_THIEF_MODE: + if( player_character.get_value( "THIEF_MODE" ) == "THIEF_ASK" ) { + player_character.set_value( "THIEF_MODE", "THIEF_HONEST" ); + player_character.set_value( "THIEF_MODE_KEEP", "YES" ); + //~ Thief mode cycled between THIEF_ASK/THIEF_HONEST/THIEF_STEAL + add_msg( _( "You will not pick up other peoples belongings." ) ); + } else if( player_character.get_value( "THIEF_MODE" ) == "THIEF_HONEST" ) { + player_character.set_value( "THIEF_MODE", "THIEF_STEAL" ); + player_character.set_value( "THIEF_MODE_KEEP", "YES" ); + //~ Thief mode cycled between THIEF_ASK/THIEF_HONEST/THIEF_STEAL + add_msg( _( "You will pick up also those things that belong to others!" ) ); + } else if( player_character.get_value( "THIEF_MODE" ) == "THIEF_STEAL" ) { + player_character.set_value( "THIEF_MODE", "THIEF_ASK" ); + player_character.set_value( "THIEF_MODE_KEEP", "NO" ); + //~ Thief mode cycled between THIEF_ASK/THIEF_HONEST/THIEF_STEAL + add_msg( _( "You will be reminded not to steal." ) ); + } else { + // ERROR + add_msg( _( "THIEF_MODE CONTAINED BAD VALUE [ %s ]!" ), + player_character.get_value( "THIEF_MODE" ) ); + } + break; - case ACTION_SCORES: - show_scores_ui( *achievements_tracker_ptr, stats(), get_kill_tracker() ); - break; + case ACTION_TOGGLE_AUTO_FORAGING: + get_options().get_option( "AUTO_FORAGING" ).setNext(); + get_options().save(); + //~ Auto Foraging is now set to x + add_msg( _( "%s is now set to %s." ), + get_options().get_option( "AUTO_FORAGING" ).getMenuText(), + get_options().get_option( "AUTO_FORAGING" ).getValueName() ); + break; - case ACTION_FACTIONS: - faction_manager_ptr->display(); - break; + case ACTION_TOGGLE_AUTO_PICKUP: + get_options().get_option( "AUTO_PICKUP" ).setNext(); + get_options().save(); + //~ Auto pickup is now set to x + add_msg( _( "%s is now set to %s." ), + get_options().get_option( "AUTO_PICKUP" ).getMenuText(), + get_options().get_option( "AUTO_PICKUP" ).getValueName() ); + break; - case ACTION_MORALE: - player_character.disp_morale(); - break; + case ACTION_DISPLAY_SCENT: + if( MAP_SHARING::isCompetitive() && !MAP_SHARING::isDebugger() ) { + break; //don't do anything when sharing and not debugger + } + display_scent(); + break; - case ACTION_MESSAGES: - Messages::display_messages(); - break; + case ACTION_DISPLAY_SCENT_TYPE: + if( MAP_SHARING::isCompetitive() && !MAP_SHARING::isDebugger() ) { + break; //don't do anything when sharing and not debugger + } + display_scent(); + break; - case ACTION_HELP: - get_help().display_help(); - break; + case ACTION_DISPLAY_TEMPERATURE: + if( MAP_SHARING::isCompetitive() && !MAP_SHARING::isDebugger() ) { + break; //don't do anything when sharing and not debugger + } + display_temperature(); + break; + case ACTION_DISPLAY_VEHICLE_AI: + if( MAP_SHARING::isCompetitive() && !MAP_SHARING::isDebugger() ) { + break; //don't do anything when sharing and not debugger + } + display_vehicle_ai(); + break; + case ACTION_DISPLAY_VISIBILITY: + if( MAP_SHARING::isCompetitive() && !MAP_SHARING::isDebugger() ) { + break; //don't do anything when sharing and not debugger + } + display_visibility(); + break; - case ACTION_OPTIONS: - get_options().show( true ); - break; + case ACTION_DISPLAY_LIGHTING: + if( MAP_SHARING::isCompetitive() && !MAP_SHARING::isDebugger() ) { + break; //don't do anything when sharing and not debugger + } + display_lighting(); + break; - case ACTION_AUTOPICKUP: - get_auto_pickup().show(); - break; + case ACTION_DISPLAY_RADIATION: + if( MAP_SHARING::isCompetitive() && !MAP_SHARING::isDebugger() ) { + break; //don't do anything when sharing and not debugger + } + display_radiation(); + break; - case ACTION_AUTONOTES: - get_auto_notes_settings().show_gui(); - break; + case ACTION_TOGGLE_HOUR_TIMER: + toggle_debug_hour_timer(); + break; - case ACTION_SAFEMODE: - get_safemode().show(); - break; + case ACTION_DISPLAY_TRANSPARENCY: + if( MAP_SHARING::isCompetitive() && !MAP_SHARING::isDebugger() ) { + break; //don't do anything when sharing and not debugger + } + display_transparency(); + break; - case ACTION_COLOR: - all_colors.show_gui(); - break; + case ACTION_DISPLAY_REACHABILITY_ZONES: + if( MAP_SHARING::isCompetitive() && !MAP_SHARING::isDebugger() ) { + break; //don't do anything when sharing and not debugger + } + display_reachability_zones(); + break; - case ACTION_WORLD_MODS: - world_generator->show_active_world_mods( world_generator->active_world->active_mod_order ); - break; + case ACTION_TOGGLE_DEBUG_MODE: + if( MAP_SHARING::isCompetitive() && !MAP_SHARING::isDebugger() ) { + break; //don't do anything when sharing and not debugger + } + handle_debug_mode(); + break; - case ACTION_DEBUG: - if( MAP_SHARING::isCompetitive() && !MAP_SHARING::isDebugger() ) { - break; //don't do anything when sharing and not debugger - } - debug_menu::debug(); - break; + case ACTION_ZOOM_IN: + zoom_in(); + break; - case ACTION_TOGGLE_FULLSCREEN: - toggle_fullscreen(); - break; + case ACTION_ZOOM_OUT: + zoom_out(); + break; - case ACTION_TOGGLE_PIXEL_MINIMAP: - toggle_pixel_minimap(); - break; + case ACTION_ITEMACTION: + item_action_menu(); + break; - case ACTION_TOGGLE_PANEL_ADM: - panel_manager::get_manager().show_adm(); - break; + case ACTION_AUTOATTACK: + avatar_action::autoattack( player_character, m ); + break; - case ACTION_RELOAD_TILESET: - reload_tileset(); - break; + default: + break; + } - case ACTION_TOGGLE_AUTO_FEATURES: - get_options().get_option( "AUTO_FEATURES" ).setNext(); - get_options().save(); - //~ Auto Features are now ON/OFF - add_msg( _( "%s are now %s." ), - get_options().get_option( "AUTO_FEATURES" ).getMenuText(), - get_option( "AUTO_FEATURES" ) ? _( "ON" ) : _( "OFF" ) ); - break; + return true; +} - case ACTION_TOGGLE_AUTO_PULP_BUTCHER: - get_options().get_option( "AUTO_PULP_BUTCHER" ).setNext(); - get_options().save(); - //~ Auto Pulp/Pulp Adjacent/Butcher is now set to x - add_msg( _( "%s is now set to %s." ), - get_options().get_option( "AUTO_PULP_BUTCHER" ).getMenuText(), - get_options().get_option( "AUTO_PULP_BUTCHER" ).getValueName() ); - break; +bool game::handle_action() +{ + std::string action; + input_context ctxt; + action_id act = ACTION_NULL; + user_turn current_turn; + avatar &player_character = get_avatar(); + // Check if we have an auto-move destination + if( player_character.has_destination() ) { + act = player_character.get_next_auto_move_direction(); + if( act == ACTION_NULL ) { + add_msg( m_info, _( "Auto-move canceled" ) ); + player_character.clear_destination(); + return false; + } + } else if( player_character.has_destination_activity() ) { + // starts destination activity after the player successfully reached his destination + player_character.start_destination_activity(); + return false; + } else { + // No auto-move, ask player for input + ctxt = get_player_input( action ); + } - case ACTION_TOGGLE_AUTO_MINING: - get_options().get_option( "AUTO_MINING" ).setNext(); - get_options().save(); - //~ Auto Mining is now ON/OFF - add_msg( _( "%s is now %s." ), - get_options().get_option( "AUTO_MINING" ).getMenuText(), - get_option( "AUTO_MINING" ) ? _( "ON" ) : _( "OFF" ) ); - break; + bool veh_ctrl = has_vehicle_control( player_character ); - case ACTION_TOGGLE_THIEF_MODE: - if( player_character.get_value( "THIEF_MODE" ) == "THIEF_ASK" ) { - player_character.set_value( "THIEF_MODE", "THIEF_HONEST" ); - player_character.set_value( "THIEF_MODE_KEEP", "YES" ); - //~ Thief mode cycled between THIEF_ASK/THIEF_HONEST/THIEF_STEAL - add_msg( _( "You will not pick up other peoples belongings." ) ); - } else if( player_character.get_value( "THIEF_MODE" ) == "THIEF_HONEST" ) { - player_character.set_value( "THIEF_MODE", "THIEF_STEAL" ); - player_character.set_value( "THIEF_MODE_KEEP", "YES" ); - //~ Thief mode cycled between THIEF_ASK/THIEF_HONEST/THIEF_STEAL - add_msg( _( "You will pick up also those things that belong to others!" ) ); - } else if( player_character.get_value( "THIEF_MODE" ) == "THIEF_STEAL" ) { - player_character.set_value( "THIEF_MODE", "THIEF_ASK" ); - player_character.set_value( "THIEF_MODE_KEEP", "NO" ); - //~ Thief mode cycled between THIEF_ASK/THIEF_HONEST/THIEF_STEAL - add_msg( _( "You will be reminded not to steal." ) ); - } else { - // ERROR - add_msg( _( "THIEF_MODE CONTAINED BAD VALUE [ %s ]!" ), - player_character.get_value( "THIEF_MODE" ) ); - } - break; + // If performing an action with right mouse button, co-ordinates + // of location clicked. + cata::optional mouse_target; - case ACTION_TOGGLE_AUTO_FORAGING: - get_options().get_option( "AUTO_FORAGING" ).setNext(); - get_options().save(); - //~ Auto Foraging is now set to x - add_msg( _( "%s is now set to %s." ), - get_options().get_option( "AUTO_FORAGING" ).getMenuText(), - get_options().get_option( "AUTO_FORAGING" ).getValueName() ); - break; + if( uquit == QUIT_WATCH && action == "QUIT" ) { + uquit = QUIT_DIED; + return false; + } - case ACTION_TOGGLE_AUTO_PICKUP: - get_options().get_option( "AUTO_PICKUP" ).setNext(); - get_options().save(); - //~ Auto pickup is now set to x - add_msg( _( "%s is now set to %s." ), - get_options().get_option( "AUTO_PICKUP" ).getMenuText(), - get_options().get_option( "AUTO_PICKUP" ).getValueName() ); - break; + if( act == ACTION_NULL ) { + act = look_up_action( action ); - case ACTION_DISPLAY_SCENT: - if( MAP_SHARING::isCompetitive() && !MAP_SHARING::isDebugger() ) { - break; //don't do anything when sharing and not debugger - } - display_scent(); - break; + if( act == ACTION_KEYBINDINGS ) { + // already handled by input context + return false; + } - case ACTION_DISPLAY_SCENT_TYPE: - if( MAP_SHARING::isCompetitive() && !MAP_SHARING::isDebugger() ) { - break; //don't do anything when sharing and not debugger - } - display_scent(); - break; + if( act == ACTION_MAIN_MENU ) { + if( uquit == QUIT_WATCH ) { + return false; + } + // No auto-move actions have or can be set at this point. + player_character.clear_destination(); + destination_preview.clear(); + act = handle_main_menu(); + if( act == ACTION_NULL ) { + return false; + } + } - case ACTION_DISPLAY_TEMPERATURE: - if( MAP_SHARING::isCompetitive() && !MAP_SHARING::isDebugger() ) { - break; //don't do anything when sharing and not debugger - } - display_temperature(); - break; - case ACTION_DISPLAY_VEHICLE_AI: - if( MAP_SHARING::isCompetitive() && !MAP_SHARING::isDebugger() ) { - break; //don't do anything when sharing and not debugger - } - display_vehicle_ai(); - break; - case ACTION_DISPLAY_VISIBILITY: - if( MAP_SHARING::isCompetitive() && !MAP_SHARING::isDebugger() ) { - break; //don't do anything when sharing and not debugger - } - display_visibility(); - break; + if( act == ACTION_ACTIONMENU ) { + if( uquit == QUIT_WATCH ) { + return false; + } + // No auto-move actions have or can be set at this point. + player_character.clear_destination(); + destination_preview.clear(); + act = handle_action_menu(); + if( act == ACTION_NULL ) { + return false; + } +#if defined(__ANDROID__) + if( get_option( "ANDROID_ACTIONMENU_AUTOADD" ) && ctxt.get_category() == "DEFAULTMODE" ) { + add_best_key_for_action_to_quick_shortcuts( act, ctxt.get_category(), false ); + } +#endif + } - case ACTION_DISPLAY_LIGHTING: - if( MAP_SHARING::isCompetitive() && !MAP_SHARING::isDebugger() ) { - break; //don't do anything when sharing and not debugger - } - display_lighting(); - break; + if( act == ACTION_KEYBINDINGS ) { + player_character.clear_destination(); + destination_preview.clear(); + act = ctxt.display_menu( true ); + if( act == ACTION_NULL ) { + return false; + } + } - case ACTION_DISPLAY_RADIATION: - if( MAP_SHARING::isCompetitive() && !MAP_SHARING::isDebugger() ) { - break; //don't do anything when sharing and not debugger - } - display_radiation(); - break; + if( can_action_change_worldstate( act ) ) { + user_action_counter += 1; + } - case ACTION_TOGGLE_HOUR_TIMER: - toggle_debug_hour_timer(); - break; + if( act == ACTION_SELECT || act == ACTION_SEC_SELECT ) { + // Mouse button click + if( veh_ctrl ) { + // No mouse use in vehicle + return false; + } - case ACTION_DISPLAY_TRANSPARENCY: - if( MAP_SHARING::isCompetitive() && !MAP_SHARING::isDebugger() ) { - break; //don't do anything when sharing and not debugger - } - display_transparency(); - break; + if( player_character.is_dead_state() ) { + // do not allow mouse actions while dead + return false; + } - case ACTION_DISPLAY_REACHABILITY_ZONES: - if( MAP_SHARING::isCompetitive() && !MAP_SHARING::isDebugger() ) { - break; //don't do anything when sharing and not debugger - } - display_reachability_zones(); - break; + const cata::optional mouse_pos = ctxt.get_coordinates( w_terrain ); + if( !mouse_pos ) { + return false; + } else if( !player_character.sees( *mouse_pos ) ) { + // Not clicked in visible terrain + return false; + } + mouse_target = mouse_pos; - case ACTION_TOGGLE_DEBUG_MODE: - if( MAP_SHARING::isCompetitive() && !MAP_SHARING::isDebugger() ) { - break; //don't do anything when sharing and not debugger + if( act == ACTION_SELECT ) { + // Note: The following has the potential side effect of + // setting auto-move destination state in addition to setting + // act. + if( !try_get_left_click_action( act, *mouse_target ) ) { + return false; } - handle_debug_mode(); - break; + } else if( act == ACTION_SEC_SELECT ) { + if( !try_get_right_click_action( act, *mouse_target ) ) { + return false; + } + } + } else if( act != ACTION_TIMEOUT ) { + // act has not been set for an auto-move, so clearing possible + // auto-move destinations. Since initializing an auto-move with + // the mouse may span across multiple actions, we do not clear the + // auto-move destination if the action is only a timeout, as this + // would require the user to double click quicker than the + // timeout delay. + player_character.clear_destination(); + destination_preview.clear(); + } + } - case ACTION_ZOOM_IN: - zoom_in(); - break; + if( act == ACTION_NULL ) { + const input_event &&evt = ctxt.get_raw_input(); + if( !evt.sequence.empty() ) { + const int ch = evt.get_first_input(); + if( !get_option( "NO_UNKNOWN_COMMAND_MSG" ) ) { + add_msg( m_info, _( "Unknown command: \"%s\" (%ld)" ), evt.long_description(), ch ); + if( const cata::optional hint = + press_x_if_bound( ACTION_KEYBINDINGS ) ) { + add_msg( m_info, _( "%s at any time to see and edit keybindings relevant to " + "the current context." ), + *hint ); + } + } + } + return false; + } - case ACTION_ZOOM_OUT: - zoom_out(); - break; + // This has no action unless we're in a special game mode. + gamemode->pre_action( act ); - case ACTION_ITEMACTION: - item_action_menu(); - break; + int before_action_moves = player_character.moves; - case ACTION_AUTOATTACK: - avatar_action::autoattack( player_character, m ); - break; + // These actions are allowed while deathcam is active. Registered in game::get_player_input + if( uquit == QUIT_WATCH || !player_character.is_dead_state() ) { + do_deathcam_action( act, player_character ); + } - default: - break; + // actions allowed only while alive + if( !player_character.is_dead_state() ) { + if( !do_regular_action( act, player_character, mouse_target ) ) { + return false; } } if( act != ACTION_TIMEOUT ) { From 5312e8f70f72cfb09a03acae00ff8b6bbc81c2a2 Mon Sep 17 00:00:00 2001 From: John Bytheway Date: Sat, 3 Apr 2021 07:22:14 -0400 Subject: [PATCH 133/453] Refactor Character::hardcoded_effects Split some more effects out into their own specific functions to reduce the size of this very large function. --- src/player_hardcoded_effects.cpp | 1263 +++++++++++++++--------------- 1 file changed, 648 insertions(+), 615 deletions(-) diff --git a/src/player_hardcoded_effects.cpp b/src/player_hardcoded_effects.cpp index 9ae508df29920..cc46a9a53e9ac 100644 --- a/src/player_hardcoded_effects.cpp +++ b/src/player_hardcoded_effects.cpp @@ -491,6 +491,649 @@ static void eff_fun_frostbite( Character &u, effect &it ) } } +static void eff_fun_teleglow( Character &u, effect &it ) +{ + // Default we get around 300 duration points per teleport (possibly more + // depending on the source). + // TODO: Include a chance to teleport to the nether realm. + // TODO: This with regards to NPCS + if( !u.is_player() ) { + // NO, no teleporting around the player because an NPC has teleglow! + return; + } + const time_duration dur = it.get_duration(); + Character &player_character = get_player_character(); + map &here = get_map(); + if( dur > 10_hours ) { + // 20 teleports (no decay; in practice at least 21) + if( one_in( 6000 - ( ( dur - 600_minutes ) / 1_minutes ) ) ) { + if( !u.is_npc() ) { + add_msg( _( "Glowing lights surround you, and you teleport." ) ); + } + teleport::teleport( u ); + get_event_bus().send( u.getID() ); + if( one_in( 10 ) ) { + // Set ourselves up for removal + it.set_duration( 0_turns ); + } + } + } + if( one_in( 7200 - ( dur - 360_minutes ) / 4_turns ) ) { + //Spawn a tindalos rift via effect_tindrift rather than it being hard-coded to teleglow + u.add_effect( effect_tindrift, 5_turns ); + + if( one_in( 2 ) ) { + // Set ourselves up for removal + it.set_duration( 0_turns ); + } + } + if( one_in( 7200 - ( ( dur - 600_minutes ) / 30_seconds ) ) && one_in( 20 ) ) { + u.add_msg_if_player( m_bad, _( "You pass out." ) ); + u.fall_asleep( 2_hours ); + if( one_in( 6 ) ) { + // Set ourselves up for removal + it.set_duration( 0_turns ); + } + } + if( dur > 6_hours ) { + // 12 teleports + if( one_in( 24000 - ( dur - 360_minutes ) / 4_turns ) ) { + tripoint dest( 0, 0, u.posz() ); + int &x = dest.x; + int &y = dest.y; + int tries = 0; + do { + x = u.posx() + rng( -4, 4 ); + y = u.posy() + rng( -4, 4 ); + tries++; + if( tries >= 10 ) { + break; + } + } while( g->critter_at( dest ) ); + if( tries < 10 ) { + if( here.impassable( dest ) ) { + here.make_rubble( dest, f_rubble_rock, true ); + } + MonsterGroupResult spawn_details = MonsterGroupManager::GetResultFromGroup( + GROUP_NETHER ); + g->place_critter_at( spawn_details.name, dest ); + if( player_character.sees( dest ) ) { + g->cancel_activity_or_ignore_query( distraction_type::hostile_spotted_far, + _( "A monster appears nearby!" ) ); + add_msg( m_warning, _( "A portal opens nearby, and a monster crawls through!" ) ); + } + if( one_in( 2 ) ) { + // Set ourselves up for removal + it.set_duration( 0_turns ); + } + } + } + if( one_in( 21000 - ( dur - 360_minutes ) / 4_turns ) ) { + u.add_msg_if_player( m_bad, _( "You shudder suddenly." ) ); + u.mutate(); + if( one_in( 4 ) ) { + // Set ourselves up for removal + it.set_duration( 0_turns ); + } + } + } + if( dur > 4_hours ) { + // 8 teleports + if( one_turn_in( 1000_minutes - dur ) && !u.has_effect( effect_valium ) ) { + u.add_effect( effect_shakes, rng( 4_minutes, 8_minutes ) ); + } + if( one_turn_in( 1200_minutes - dur ) ) { + u.add_msg_if_player( m_bad, _( "Your vision is filled with bright lights…" ) ); + u.add_effect( effect_blind, rng( 1_minutes, 2_minutes ) ); + if( one_in( 8 ) ) { + // Set ourselves up for removal + it.set_duration( 0_turns ); + } + } + if( one_in( 5000 ) && !u.has_effect( effect_hallu ) ) { + u.add_effect( effect_hallu, 6_hours ); + if( one_in( 5 ) ) { + // Set ourselves up for removal + it.set_duration( 0_turns ); + } + } + } + if( one_in( 4000 ) ) { + u.add_msg_if_player( m_bad, _( "You're suddenly covered in ectoplasm." ) ); + u.add_effect( effect_boomered, 10_minutes ); + if( one_in( 4 ) ) { + // Set ourselves up for removal + it.set_duration( 0_turns ); + } + } + if( one_in( 10000 ) ) { + if( !u.has_trait( trait_M_IMMUNE ) ) { + u.add_effect( effect_fungus, 1_turns, true ); + } else { + u.add_msg_if_player( m_info, _( "We have many colonists awaiting passage." ) ); + } + // Set ourselves up for removal + it.set_duration( 0_turns ); + } +} + +static void eff_fun_datura( Character &u, effect &it ) +{ + const time_duration dur = it.get_duration(); + if( dur > 100_minutes && u.get_focus() >= 1 && one_in( 24 ) ) { + u.mod_focus( -1 ); + } + if( dur > 200_minutes && one_in( 48 ) && u.get_stim() < 20 ) { + u.mod_stim( 1 ); + } + if( dur > 300_minutes && u.get_focus() >= 1 && one_in( 12 ) ) { + u.mod_focus( -1 ); + } + if( dur > 400_minutes && one_in( 384 ) ) { + u.mod_pain( rng( -1, -8 ) ); + } + if( ( !u.has_effect( effect_hallu ) ) && ( dur > 500_minutes && one_in( 24 ) ) ) { + u.add_effect( effect_hallu, 6_hours ); + } + if( dur > 600_minutes && one_in( 768 ) ) { + u.mod_pain( rng( -3, -24 ) ); + if( dur > 800_minutes && one_in( 16 ) ) { + u.add_msg_if_player( m_bad, + _( "You're experiencing loss of basic motor skills and blurred vision. Your mind recoils in horror, unable to communicate with your spinal column." ) ); + u.add_msg_if_player( m_bad, _( "You stagger and fall!" ) ); + u.add_effect( effect_downed, rng( 1_turns, 4_turns ), false, 0, true ); + if( one_in( 8 ) || x_in_y( u.vomit_mod(), 10 ) ) { + u.vomit(); + } + } + } + if( dur > 700_minutes && u.get_focus() >= 1 ) { + u.mod_focus( -1 ); + } + if( dur > 800_minutes && one_in( 1536 ) ) { + u.add_effect( effect_visuals, rng( 4_minutes, 20_minutes ) ); + u.mod_pain( rng( -8, -40 ) ); + } + if( dur > 1200_minutes && one_in( 1536 ) ) { + u.add_msg_if_player( m_bad, _( "There's some kind of big machine in the sky." ) ); + u.add_effect( effect_visuals, rng( 8_minutes, 40_minutes ) ); + if( one_in( 32 ) ) { + u.add_msg_if_player( m_bad, _( "It's some kind of electric snake, coming right at you!" ) ); + u.mod_pain( rng( 4, 40 ) ); + u.vomit(); + } + } + if( dur > 1400_minutes && one_in( 768 ) ) { + u.add_msg_if_player( m_bad, + _( "Order us some golf shoes, otherwise we'll never get out of this place alive." ) ); + u.add_effect( effect_visuals, rng( 40_minutes, 200_minutes ) ); + if( one_in( 8 ) ) { + u.add_msg_if_player( m_bad, + _( "The possibility of physical and mental collapse is now very real." ) ); + if( one_in( 2 ) || x_in_y( u.vomit_mod(), 10 ) ) { + u.add_msg_if_player( m_bad, _( "No one should be asked to handle this trip." ) ); + u.vomit(); + u.mod_pain( rng( 8, 40 ) ); + } + } + } + + if( dur > 1800_minutes && one_in( 300 * 512 ) ) { + if( !u.has_trait( trait_NOPAIN ) ) { + u.add_msg_if_player( m_bad, + _( "Your heart spasms painfully and stops, dragging you back to reality as you die." ) ); + } else { + u.add_msg_if_player( + _( "You dissolve into beautiful paroxysms of energy. Life fades from your nebulae and you are no more." ) ); + } + get_event_bus().send( u.getID(), it.get_id() ); + u.set_part_hp_cur( bodypart_id( "torso" ), 0 ); + } +} + +static void eff_fun_hypovolemia( Character &u, effect &it ) +{ + // hypovolemia and dehydration are closely related so it will pull water + // from your system to replenish blood quantity + int intense = it.get_intensity(); + + if( calendar::once_every( -u.vitamin_rate( vitamin_blood ) ) && one_in( 5 ) && + u.get_thirst() <= 240 ) { + u.mod_thirst( rng( 0, intense ) ); + } + // bleed out lambda + auto bleed_out = [&] { + if( u.has_effect( effect_bleed ) ) + { + u.add_msg_player_or_npc( m_bad, + _( "You bleed to death!" ), + _( " bleeds to death!" ) ); + get_event_bus().send( u.getID() ); + } else + { + u.add_msg_player_or_npc( m_bad, + _( "Your heart can't keep up the pace and fails!" ), + _( " has a sudden heart attack!" ) ); + get_event_bus().send( u.getID() ); + } + u.set_part_hp_cur( bodypart_id( "torso" ), 0 ); + }; + // this goes first because beyond minimum threshold you just die without delay, + // while stage 4 is on a timer check with an rng grace period + + if( u.vitamin_get( vitamin_blood ) == vitamin_blood->min() ) { + bleed_out(); + } + + // Hypovolemic shock + // stage 1 - early symptoms include headache, fatigue, weakness, thirst, and dizziness. + // stage 2 - person may begin sweating and feeling more anxious and restless. + // stage 3 - heart rate will increase to over 120 bpm; rapid breathing + // mental distress, including anxiety and agitation; skin is pale and cold + cyanosis, sweating + // stage 4 is a life threatening condition; extremely rapid heart rate, breathing very fast and difficult + // drifting in and out of consciousness, sweating heavily, feeling cool to the touch, looking extremely pale + + if( one_in( 1200 / intense ) && !u.in_sleep_state() ) { + std::string warning; + + if( one_in( 5 ) ) { + // no-effect message block + if( intense == 1 ) { + warning = _( "Your skin looks pale and you feel anxious and thirsty. Blood loss?" ); + } else if( intense == 2 ) { + warning = _( "Your pale skin is sweating, your heart is beating fast, and you feel restless. Maybe you lost too much blood?" ); + } else if( intense == 3 ) { + warning = _( "You're unsettlingly white, but your fingertips are bluish. You are agitated and your heart is racing. Your blood loss must be serious." ); + } else { //intense == 4 + warning = _( "You are pale as a ghost, dripping wet from the sweat, and sluggish - despite your heart racing like a train. You are on the brink of collapse from the effects of blood loss." ); + } + u.add_msg_if_player( m_bad, warning ); + } else { + // effect dice, with progression of effects, 3 possible effects per tier + int dice_roll = rng( 0, 2 ) + intense; + switch( dice_roll ) { + case 1: + warning = _( "You feel dizzy and lightheaded." ); + u.add_effect( effect_stunned, rng( 5_seconds * intense, 2_minutes * intense ) ); + break; + case 2: + warning = _( "You feel tired and you breathe heavily." ); + u.mod_fatigue( 3 * intense ); + break; + case 3: + warning = _( "You are anxious and cannot collect your thoughts." ); + u.mod_focus( -rng( 1, u.get_focus() * intense / it.get_max_intensity() ) ); + break; + case 4: + warning = _( "You are sweating profusely, but you feel cold." ); + u.mod_part_temp_conv( bodypart_id( "hand_l" ), - 1000 * intense ); + u.mod_part_temp_conv( bodypart_id( "hand_r" ), -1000 * intense ); + u.mod_part_temp_conv( bodypart_id( "foot_l" ), -1000 * intense ); + u.mod_part_temp_conv( bodypart_id( "foot_r" ), -1000 * intense ); + break; + case 5: + warning = _( "You huff and puff. Your breath is rapid and shallow." ); + u.mod_stamina( -500 * intense ); + break; + case 6: + if( one_in( 2 ) ) { + warning = _( "You drop to the ground, fighting to keep yourself conscious." ); + u.add_effect( effect_downed, rng( 1_minutes, 2_minutes ) ); + break; + } else { + warning = _( "Your mind slips away." ); + u.fall_asleep( rng( 2_minutes, 5_minutes ) ); + break; + } + } + u.add_msg_if_player( m_bad, warning ); + } + } + // this goes last because we don't want in_sleep_state to prevent you from dying + if( intense == 4 && one_in( 900 ) && + rng( 1, -vitamin_blood->min() * 3 / 5 ) > ( -vitamin_blood->min() + u.vitamin_get( + vitamin_blood ) ) ) { + bleed_out(); + } +} + +static void eff_fun_redcells_anemia( Character &u, effect &it ) +{ + // Lack of iron impairs production of hemoglobin and therefore ability to carry + // oxygen by red blood cells. Alternatively hemorrhage causes physical loss of red blood cells. + // This triggers variety of symptoms, focusing on weakness, + // fatigue, cold limbs, later in dizziness, soreness, breathlessness, + // and severe malaise and lethargy. + // Base anemia symptoms: fatigue, loss of stamina, loss of strength, impact on health + // are placed in effect JSON + + int intense = it.get_intensity(); + + // you can only lose as much red blood cells before your body fails to function + if( u.vitamin_get( vitamin_redcells ) <= vitamin_redcells->min() + 5 ) { + u.add_msg_player_or_npc( m_bad, + _( "You cannot breathe and your body gives out!" ), + _( " gasps for air and dies!" ) ); + get_event_bus().send( u.getID() ); + u.set_part_hp_cur( bodypart_id( "torso" ), 0 ); + } + if( one_in( 900 / intense ) && !u.in_sleep_state() ) { + // level 1 symptoms are cold limbs, pale skin, and weakness + switch( dice( 1, 9 ) ) { + case 1: + u.add_msg_if_player( m_bad, _( "Your hands feel unusually cold." ) ); + u.mod_part_temp_conv( bodypart_id( "hand_l" ), -2000 ); + u.mod_part_temp_conv( bodypart_id( "hand_r" ), -2000 ); + break; + case 2: + u.add_msg_if_player( m_bad, _( "Your feet feel unusually cold." ) ); + u.mod_part_temp_conv( bodypart_id( "foot_l" ), -2000 ); + u.mod_part_temp_conv( bodypart_id( "foot_r" ), -2000 ); + break; + case 3: + u.add_msg_if_player( m_bad, _( "Your skin looks very pale." ) ); + break; + case 4: + u.add_msg_if_player( m_bad, _( "You feel weak. Where has your strength gone?" ) ); + break; + case 5: + u.add_msg_if_player( m_bad, _( "You feel feeble. A gust of wind could make you stumble." ) ); + break; + case 6: + u.add_msg_if_player( m_bad, _( "There is an overwhelming aura of tiredness inside of you." ) ); + u.mod_fatigue( intense * 3 ); + break; + case 7: // 7-9 empty for variability, as messages stack on higher intensity + break; + case 8: + break; + case 9: + break; + } + // level 2 anemia introduces dizziness, shakes, headaches, cravings for non-comestibles, + // mouth and tongue soreness + if( intense > 1 ) { + switch( dice( 1, 9 ) ) { + case 1: + u.add_msg_if_player( m_bad, _( "Rest is what you want. Rest is what you need." ) ); + break; + case 2: + u.add_msg_if_player( m_bad, _( "You feel dizzy and can't coordinate the movement of your feet." ) ); + u.add_effect( effect_stunned, rng( 1_minutes, 2_minutes ) ); + break; + case 3: + u.add_msg_if_player( m_bad, _( "Your muscles are quivering." ) ); + u.add_effect( effect_shakes, rng( 4_minutes, 8_minutes ) ); + break; + case 4: + u.add_msg_if_player( m_bad, _( "You crave for ice. The dirt under your feet looks tasty too." ) ); + break; + case 5: + u.add_msg_if_player( m_bad, _( "Your whole mouth is sore, and your tongue is swollen." ) ); + break; + case 6: + u.add_msg_if_player( m_bad, _( "You feel lightheaded. A migraine follows." ) ); + u.mod_pain( intense * 9 ); + break; + case 7: // 7-9 empty for variability, as messages stack on higher intensity + break; + case 8: + break; + case 9: + break; + } + } + // level 3 anemia introduces restless legs, severe tiredness, breathlessness + if( intense > 2 ) { + switch( dice( 1, 9 ) ) { + case 1: + u.add_msg_if_player( m_bad, _( "Your legs are restless. The urge to move them is so strong." ) ); + break; + case 2: + u.add_msg_if_player( m_bad, _( "You feel like you could sleep on a rock." ) ); + u.mod_fatigue( intense * 3 ); + break; + case 3: + u.add_msg_if_player( m_bad, _( "You gasp for air!" ) ); + u.set_stamina( 0 ); + u.add_effect( effect_winded, rng( 30_seconds, 3_minutes ) ); + break; + case 4: + u.add_msg_if_player( m_bad, _( "Can't breathe. Must rest." ) ); + u.set_stamina( 0 ); + break; + case 5: + u.add_msg_if_player( m_bad, + _( "You can't take it any more. Rest first; everything else later." ) ); + u.add_effect( effect_lying_down, rng( 2_minutes, 5_minutes ) ); + break; + case 6: + u.add_msg_if_player( m_bad, _( "You must sit down for a moment. Just a moment." ) ); + u.add_effect( effect_downed, rng( 1_minutes, 2_minutes ) ); + break; + case 7: // 7-9 empty for variability, as messages stack on higher intensity + break; + case 8: + break; + case 9: + break; + } + } + } +} + +static void eff_fun_sleep( Character &u, effect &it ) +{ + int intense = it.get_intensity(); + map &here = get_map(); + + u.set_moves( 0 ); +#if defined(TILES) + if( u.is_player() ) { + SDL_PumpEvents(); + } +#endif // TILES + + if( intense < 1 ) { + it.set_intensity( 1 ); + } else if( intense < 24 ) { + it.mod_intensity( 1 ); + } + + if( u.has_effect( effect_narcosis ) && u.get_fatigue() <= 25 ) { + u.set_fatigue( 25 ); //Prevent us from waking up naturally while under anesthesia + } + + if( u.get_fatigue() < -25 && it.get_duration() > 3_minutes && !u.has_effect( effect_narcosis ) ) { + it.set_duration( 1_turns * dice( 3, 10 ) ); + } + + if( u.get_fatigue() <= 0 && u.get_fatigue() > -20 && !u.has_effect( effect_narcosis ) ) { + u.mod_fatigue( -25 ); + if( u.get_sleep_deprivation() < SLEEP_DEPRIVATION_HARMLESS ) { + u.add_msg_if_player( m_good, _( "You feel well rested." ) ); + } else { + u.add_msg_if_player( m_warning, + _( "You feel physically rested, but you haven't been able to catch up on your missed sleep yet." ) ); + } + it.set_duration( 1_turns * dice( 3, 100 ) ); + } + + // TODO: Move this to update_needs when NPCs can mutate + if( calendar::once_every( 10_minutes ) && ( u.has_trait( trait_CHLOROMORPH ) || + u.has_trait( trait_M_SKIN3 ) || u.has_trait( trait_WATERSLEEP ) ) && + here.is_outside( u.pos() ) ) { + if( u.has_trait( trait_CHLOROMORPH ) ) { + // Hunger and thirst fall before your Chloromorphic physiology! + if( g->natural_light_level( u.posz() ) >= 12 && + get_weather().weather_id->sun_intensity >= sun_intensity_type::light ) { + if( u.get_hunger() >= -30 ) { + u.mod_hunger( -5 ); + // photosynthesis warrants absorbing kcal directly + u.mod_stored_nutr( -5 ); + } + if( u.get_thirst() >= -30 ) { + u.mod_thirst( -5 ); + } + } + } + if( u.has_trait( trait_M_SKIN3 ) ) { + // Spores happen! + if( here.has_flag_ter_or_furn( "FUNGUS", u.pos() ) ) { + if( u.get_fatigue() >= 0 ) { + u.mod_fatigue( -5 ); // Local guides need less sleep on fungal soil + } + if( calendar::once_every( 1_hours ) ) { + u.spores(); // spawn some P O O F Y B O I S + } + } + } + if( u.has_trait( trait_WATERSLEEP ) ) { + u.mod_fatigue( -3 ); // Fish sleep less in water + } + } + + // Check mutation category strengths to see if we're mutated enough to get a dream + mutation_category_id highcat = u.get_highest_category(); + int highest = u.mutation_category_level[highcat]; + + // Determine the strength of effects or dreams based upon category strength + int strength = 0; // Category too weak for any effect or dream + if( u.crossed_threshold() ) { + strength = 4; // Post-human. + } else if( highest >= 20 && highest < 35 ) { + strength = 1; // Low strength + } else if( highest >= 35 && highest < 50 ) { + strength = 2; // Medium strength + } else if( highest >= 50 ) { + strength = 3; // High strength + } + + // Get a dream if category strength is high enough. + if( strength != 0 ) { + //Once every 6 / 3 / 2 hours, with a bit of randomness + if( calendar::once_every( 6_hours / strength ) && one_in( 3 ) ) { + // Select a dream + std::string dream = u.get_category_dream( highcat, strength ); + if( !dream.empty() ) { + u.add_msg_if_player( dream ); + } + // Mycus folks upgrade in their sleep. + if( u.has_trait( trait_THRESH_MYCUS ) ) { + if( one_in( 8 ) ) { + u.mutate_category( mutation_category_id( "MYCUS" ) ); + u.mod_stored_nutr( 10 ); + u.mod_thirst( 10 ); + u.mod_fatigue( 5 ); + } + } + } + } + + bool woke_up = false; + int tirednessVal = rng( 5, 200 ) + rng( 0, std::abs( u.get_fatigue() * 2 * 5 ) ); + if( !u.is_blind() && !u.has_effect( effect_narcosis ) ) { + // People who can see while sleeping are acclimated to the light. + if( !u.has_trait( trait_SEESLEEP ) ) { + if( u.has_trait( trait_HEAVYSLEEPER2 ) && !u.has_trait( trait_HIBERNATE ) ) { + // So you can too sleep through noon + if( ( tirednessVal * 1.25 ) < here.ambient_light_at( u.pos() ) && ( u.get_fatigue() < 10 || + one_in( u.get_fatigue() / 2 ) ) ) { + u.add_msg_if_player( _( "It's too bright to sleep." ) ); + // Set ourselves up for removal + it.set_duration( 0_turns ); + woke_up = true; + } + // Ursine hibernators would likely do so indoors. Plants, though, might be in the sun. + } else if( u.has_trait( trait_HIBERNATE ) ) { + if( ( tirednessVal * 5 ) < here.ambient_light_at( u.pos() ) && ( u.get_fatigue() < 10 || + one_in( u.get_fatigue() / 2 ) ) ) { + u.add_msg_if_player( _( "It's too bright to sleep." ) ); + // Set ourselves up for removal + it.set_duration( 0_turns ); + woke_up = true; + } + } else if( tirednessVal < here.ambient_light_at( u.pos() ) && ( u.get_fatigue() < 10 || + one_in( u.get_fatigue() / 2 ) ) ) { + u.add_msg_if_player( _( "It's too bright to sleep." ) ); + // Set ourselves up for removal + it.set_duration( 0_turns ); + woke_up = true; + } + } else if( u.has_active_mutation( trait_SEESLEEP ) ) { + Creature *hostile_critter = g->is_hostile_very_close(); + if( hostile_critter != nullptr ) { + u.add_msg_if_player( _( "You see %s approaching!" ), + hostile_critter->disp_name() ); + it.set_duration( 0_turns ); + woke_up = true; + } + } + } + + // Have we already woken up? + if( !woke_up && !u.has_effect( effect_narcosis ) ) { + // Cold or heat may wake you up. + // Player will sleep through cold or heat if fatigued enough + for( const bodypart_id &bp : u.get_all_body_parts() ) { + const int curr_temp = u.get_part_temp_cur( bp ); + if( curr_temp < BODYTEMP_VERY_COLD - u.get_fatigue() / 2 ) { + if( one_in( 30000 ) ) { + u.add_msg_if_player( _( "You toss and turn trying to keep warm." ) ); + } + if( curr_temp < BODYTEMP_FREEZING - u.get_fatigue() / 2 || + one_in( curr_temp * 6 + 30000 ) ) { + u.add_msg_if_player( m_bad, _( "It's too cold to sleep." ) ); + // Set ourselves up for removal + it.set_duration( 0_turns ); + woke_up = true; + break; + } + } else if( curr_temp > BODYTEMP_VERY_HOT + u.get_fatigue() / 2 ) { + if( one_in( 30000 ) ) { + u.add_msg_if_player( _( "You toss and turn in the heat." ) ); + } + if( curr_temp > BODYTEMP_SCORCHING + u.get_fatigue() / 2 || + one_in( 90000 - curr_temp ) ) { + u.add_msg_if_player( m_bad, _( "It's too hot to sleep." ) ); + // Set ourselves up for removal + it.set_duration( 0_turns ); + woke_up = true; + break; + } + } + } + if( u.has_trait( trait_SCHIZOPHRENIC ) && one_in( 43200 ) && u.is_player() ) { + if( one_in( 2 ) ) { + u.sound_hallu(); + } else { + int max_count = rng( 1, 3 ); + int count = 0; + for( const tripoint &mp : here.points_in_radius( u.pos(), 1 ) ) { + if( mp == u.pos() ) { + continue; + } + if( here.has_flag( "FLAT", mp ) && + here.pl_sees( mp, 2 ) ) { + g->spawn_hallucination( mp ); + if( ++count > max_count ) { + break; + } + } + } + } + it.set_duration( 0_turns ); + woke_up = true; + } + } + + // A bit of a hack: check if we are about to wake up for any reason, including regular + // timing out of sleep + if( it.get_duration() == 1_turns || woke_up ) { + u.wake_up(); + } +} + void Character::hardcoded_effects( effect &it ) { if( const ma_buff *buff = ma_buff::from_effect( it ) ) { @@ -513,6 +1156,11 @@ void Character::hardcoded_effects( effect &it ) { effect_cold, eff_fun_cold }, { effect_hot, eff_fun_hot }, { effect_frostbite, eff_fun_frostbite }, + { effect_teleglow, eff_fun_teleglow }, + { effect_datura, eff_fun_datura }, + { effect_hypovolemia, eff_fun_hypovolemia }, + { effect_redcells_anemia, eff_fun_redcells_anemia }, + { effect_sleep, eff_fun_sleep }, } }; const efftype_id &id = it.get_id(); @@ -651,126 +1299,6 @@ void Character::hardcoded_effects( effect &it ) remove_effect( effect_tindrift ); } } - } else if( id == effect_teleglow ) { - // Default we get around 300 duration points per teleport (possibly more - // depending on the source). - // TODO: Include a chance to teleport to the nether realm. - // TODO: This with regards to NPCS - if( !is_player() ) { - // NO, no teleporting around the player because an NPC has teleglow! - return; - } - if( dur > 10_hours ) { - // 20 teleports (no decay; in practice at least 21) - if( one_in( 6000 - ( ( dur - 600_minutes ) / 1_minutes ) ) ) { - if( !is_npc() ) { - add_msg( _( "Glowing lights surround you, and you teleport." ) ); - } - teleport::teleport( *this ); - get_event_bus().send( getID() ); - if( one_in( 10 ) ) { - // Set ourselves up for removal - it.set_duration( 0_turns ); - } - } - } - if( one_in( 7200 - ( dur - 360_minutes ) / 4_turns ) ) { - //Spawn a tindalos rift via effect_tindrift rather than it being hard-coded to teleglow - add_effect( effect_tindrift, 5_turns ); - - if( one_in( 2 ) ) { - // Set ourselves up for removal - it.set_duration( 0_turns ); - } - } - if( one_in( 7200 - ( ( dur - 600_minutes ) / 30_seconds ) ) && one_in( 20 ) ) { - add_msg_if_player( m_bad, _( "You pass out." ) ); - fall_asleep( 2_hours ); - if( one_in( 6 ) ) { - // Set ourselves up for removal - it.set_duration( 0_turns ); - } - } - if( dur > 6_hours ) { - // 12 teleports - if( one_in( 24000 - ( dur - 360_minutes ) / 4_turns ) ) { - tripoint dest( 0, 0, posz() ); - int &x = dest.x; - int &y = dest.y; - int tries = 0; - do { - x = posx() + rng( -4, 4 ); - y = posy() + rng( -4, 4 ); - tries++; - if( tries >= 10 ) { - break; - } - } while( g->critter_at( dest ) ); - if( tries < 10 ) { - if( here.impassable( dest ) ) { - here.make_rubble( dest, f_rubble_rock, true ); - } - MonsterGroupResult spawn_details = MonsterGroupManager::GetResultFromGroup( - GROUP_NETHER ); - g->place_critter_at( spawn_details.name, dest ); - if( player_character.sees( dest ) ) { - g->cancel_activity_or_ignore_query( distraction_type::hostile_spotted_far, - _( "A monster appears nearby!" ) ); - add_msg( m_warning, _( "A portal opens nearby, and a monster crawls through!" ) ); - } - if( one_in( 2 ) ) { - // Set ourselves up for removal - it.set_duration( 0_turns ); - } - } - } - if( one_in( 21000 - ( dur - 360_minutes ) / 4_turns ) ) { - add_msg_if_player( m_bad, _( "You shudder suddenly." ) ); - mutate(); - if( one_in( 4 ) ) { - // Set ourselves up for removal - it.set_duration( 0_turns ); - } - } - } - if( dur > 4_hours ) { - // 8 teleports - if( one_turn_in( 1000_minutes - dur ) && !has_effect( effect_valium ) ) { - add_effect( effect_shakes, rng( 4_minutes, 8_minutes ) ); - } - if( one_turn_in( 1200_minutes - dur ) ) { - add_msg_if_player( m_bad, _( "Your vision is filled with bright lights…" ) ); - add_effect( effect_blind, rng( 1_minutes, 2_minutes ) ); - if( one_in( 8 ) ) { - // Set ourselves up for removal - it.set_duration( 0_turns ); - } - } - if( one_in( 5000 ) && !has_effect( effect_hallu ) ) { - add_effect( effect_hallu, 6_hours ); - if( one_in( 5 ) ) { - // Set ourselves up for removal - it.set_duration( 0_turns ); - } - } - } - if( one_in( 4000 ) ) { - add_msg_if_player( m_bad, _( "You're suddenly covered in ectoplasm." ) ); - add_effect( effect_boomered, 10_minutes ); - if( one_in( 4 ) ) { - // Set ourselves up for removal - it.set_duration( 0_turns ); - } - } - if( one_in( 10000 ) ) { - if( !has_trait( trait_M_IMMUNE ) ) { - add_effect( effect_fungus, 1_turns, true ); - } else { - add_msg_if_player( m_info, _( "We have many colonists awaiting passage." ) ); - } - // Set ourselves up for removal - it.set_duration( 0_turns ); - } } else if( id == effect_asthma ) { if( has_effect( effect_adrenaline ) || has_effect( effect_datura ) ) { add_msg_if_player( m_good, _( "Your asthma attack stops." ) ); @@ -831,300 +1359,11 @@ void Character::hardcoded_effects( effect &it ) } } } - } else if( id == effect_datura ) { - if( dur > 100_minutes && get_focus() >= 1 && one_in( 24 ) ) { - mod_focus( -1 ); - } - if( dur > 200_minutes && one_in( 48 ) && get_stim() < 20 ) { - mod_stim( 1 ); - } - if( dur > 300_minutes && get_focus() >= 1 && one_in( 12 ) ) { - mod_focus( -1 ); - } - if( dur > 400_minutes && one_in( 384 ) ) { - mod_pain( rng( -1, -8 ) ); - } - if( ( !has_effect( effect_hallu ) ) && ( dur > 500_minutes && one_in( 24 ) ) ) { - add_effect( effect_hallu, 6_hours ); - } - if( dur > 600_minutes && one_in( 768 ) ) { - mod_pain( rng( -3, -24 ) ); - if( dur > 800_minutes && one_in( 16 ) ) { - add_msg_if_player( m_bad, - _( "You're experiencing loss of basic motor skills and blurred vision. Your mind recoils in horror, unable to communicate with your spinal column." ) ); - add_msg_if_player( m_bad, _( "You stagger and fall!" ) ); - add_effect( effect_downed, rng( 1_turns, 4_turns ), false, 0, true ); - if( one_in( 8 ) || x_in_y( vomit_mod(), 10 ) ) { - vomit(); - } - } - } - if( dur > 700_minutes && get_focus() >= 1 ) { - mod_focus( -1 ); - } - if( dur > 800_minutes && one_in( 1536 ) ) { - add_effect( effect_visuals, rng( 4_minutes, 20_minutes ) ); - mod_pain( rng( -8, -40 ) ); - } - if( dur > 1200_minutes && one_in( 1536 ) ) { - add_msg_if_player( m_bad, _( "There's some kind of big machine in the sky." ) ); - add_effect( effect_visuals, rng( 8_minutes, 40_minutes ) ); - if( one_in( 32 ) ) { - add_msg_if_player( m_bad, _( "It's some kind of electric snake, coming right at you!" ) ); - mod_pain( rng( 4, 40 ) ); - vomit(); - } - } - if( dur > 1400_minutes && one_in( 768 ) ) { - add_msg_if_player( m_bad, - _( "Order us some golf shoes, otherwise we'll never get out of this place alive." ) ); - add_effect( effect_visuals, rng( 40_minutes, 200_minutes ) ); - if( one_in( 8 ) ) { - add_msg_if_player( m_bad, - _( "The possibility of physical and mental collapse is now very real." ) ); - if( one_in( 2 ) || x_in_y( vomit_mod(), 10 ) ) { - add_msg_if_player( m_bad, _( "No one should be asked to handle this trip." ) ); - vomit(); - mod_pain( rng( 8, 40 ) ); - } - } - } - - if( dur > 1800_minutes && one_in( 300 * 512 ) ) { - if( !has_trait( trait_NOPAIN ) ) { - add_msg_if_player( m_bad, - _( "Your heart spasms painfully and stops, dragging you back to reality as you die." ) ); - } else { - add_msg_if_player( - _( "You dissolve into beautiful paroxysms of energy. Life fades from your nebulae and you are no more." ) ); - } - get_event_bus().send( getID(), id ); - set_part_hp_cur( bodypart_id( "torso" ), 0 ); - } - } else if( id == effect_hypovolemia ) { - // hypovolemia and dehydration are closely related so it will pull water - // from your system to replenish blood quantity - if( calendar::once_every( -vitamin_rate( vitamin_blood ) ) && one_in( 5 ) && get_thirst() <= 240 ) { - mod_thirst( rng( 0, intense ) ); - } - // bleed out lambda - auto bleed_out = [&] { - if( has_effect( effect_bleed ) ) - { - add_msg_player_or_npc( m_bad, - _( "You bleed to death!" ), - _( " bleeds to death!" ) ); - get_event_bus().send( getID() ); - } else - { - add_msg_player_or_npc( m_bad, - _( "Your heart can't keep up the pace and fails!" ), - _( " has a sudden heart attack!" ) ); - get_event_bus().send( getID() ); - } - set_part_hp_cur( bodypart_id( "torso" ), 0 ); - }; - // this goes first because beyond minimum threshold you just die without delay, - // while stage 4 is on a timer check with an rng grace period - - if( vitamin_get( vitamin_blood ) == vitamin_blood->min() ) { - bleed_out(); - } - - // Hypovolemic shock - // stage 1 - early symptoms include headache, fatigue, weakness, thirst, and dizziness. - // stage 2 - person may begin sweating and feeling more anxious and restless. - // stage 3 - heart rate will increase to over 120 bpm; rapid breathing - // mental distress, including anxiety and agitation; skin is pale and cold + cyanosis, sweating - // stage 4 is a life threatening condition; extremely rapid heart rate, breathing very fast and difficult - // drifting in and out of consciousness, sweating heavily, feeling cool to the touch, looking extremely pale - - if( one_in( 1200 / intense ) && !in_sleep_state() ) { - std::string warning; - - if( one_in( 5 ) ) { - // no-effect message block - if( intense == 1 ) { - warning = _( "Your skin looks pale and you feel anxious and thirsty. Blood loss?" ); - } else if( intense == 2 ) { - warning = _( "Your pale skin is sweating, your heart is beating fast, and you feel restless. Maybe you lost too much blood?" ); - } else if( intense == 3 ) { - warning = _( "You're unsettlingly white, but your fingertips are bluish. You are agitated and your heart is racing. Your blood loss must be serious." ); - } else { //intense == 4 - warning = _( "You are pale as a ghost, dripping wet from the sweat, and sluggish - despite your heart racing like a train. You are on the brink of collapse from the effects of blood loss." ); - } - add_msg_if_player( m_bad, warning ); - } else { - // effect dice, with progression of effects, 3 possible effects per tier - int dice_roll = rng( 0, 2 ) + intense; - switch( dice_roll ) { - case 1: - warning = _( "You feel dizzy and lightheaded." ); - add_effect( effect_stunned, rng( 5_seconds * intense, 2_minutes * intense ) ); - break; - case 2: - warning = _( "You feel tired and you breathe heavily." ); - mod_fatigue( 3 * intense ); - break; - case 3: - warning = _( "You are anxious and cannot collect your thoughts." ); - mod_focus( -rng( 1, get_focus() * intense / it.get_max_intensity() ) ); - break; - case 4: - warning = _( "You are sweating profusely, but you feel cold." ); - mod_part_temp_conv( bodypart_id( "hand_l" ), - 1000 * intense ); - mod_part_temp_conv( bodypart_id( "hand_r" ), -1000 * intense ); - mod_part_temp_conv( bodypart_id( "foot_l" ), -1000 * intense ); - mod_part_temp_conv( bodypart_id( "foot_r" ), -1000 * intense ); - break; - case 5: - warning = _( "You huff and puff. Your breath is rapid and shallow." ); - mod_stamina( -500 * intense ); - break; - case 6: - if( one_in( 2 ) ) { - warning = _( "You drop to the ground, fighting to keep yourself conscious." ); - add_effect( effect_downed, rng( 1_minutes, 2_minutes ) ); - break; - } else { - warning = _( "Your mind slips away." ); - fall_asleep( rng( 2_minutes, 5_minutes ) ); - break; - } - } - add_msg_if_player( m_bad, warning ); - } - } - // this goes last because we don't want in_sleep_state to prevent you from dying - if( intense == 4 && one_in( 900 ) && - rng( 1, -vitamin_blood->min() * 3 / 5 ) > ( -vitamin_blood->min() + vitamin_get( - vitamin_blood ) ) ) { - bleed_out(); - } } else if( id == effect_anemia ) { // effects: reduces effective redcells regen and depletes redcells at high intensity if( calendar::once_every( vitamin_rate( vitamin_redcells ) ) ) { vitamin_mod( vitamin_redcells, -rng( 0, intense ) ); } - } else if( id == effect_redcells_anemia ) { - // Lack of iron impairs production of hemoglobin and therefore ability to carry - // oxygen by red blood cells. Alternatively hemorrhage causes physical loss of red blood cells. - // This triggers variety of symptoms, focusing on weakness, - // fatigue, cold limbs, later in dizziness, soreness, breathlessness, - // and severe malaise and lethargy. - // Base anemia symptoms: fatigue, loss of stamina, loss of strength, impact on health - // are placed in effect JSON - - // you can only lose as much red blood cells before your body fails to function - if( vitamin_get( vitamin_redcells ) <= vitamin_redcells->min() + 5 ) { - add_msg_player_or_npc( m_bad, - _( "You cannot breathe and your body gives out!" ), - _( " gasps for air and dies!" ) ); - get_event_bus().send( getID() ); - set_part_hp_cur( bodypart_id( "torso" ), 0 ); - } - if( one_in( 900 / intense ) && !in_sleep_state() ) { - // level 1 symptoms are cold limbs, pale skin, and weakness - switch( dice( 1, 9 ) ) { - case 1: - add_msg_if_player( m_bad, _( "Your hands feel unusually cold." ) ); - mod_part_temp_conv( bodypart_id( "hand_l" ), -2000 ); - mod_part_temp_conv( bodypart_id( "hand_r" ), -2000 ); - break; - case 2: - add_msg_if_player( m_bad, _( "Your feet feel unusually cold." ) ); - mod_part_temp_conv( bodypart_id( "foot_l" ), -2000 ); - mod_part_temp_conv( bodypart_id( "foot_r" ), -2000 ); - break; - case 3: - add_msg_if_player( m_bad, _( "Your skin looks very pale." ) ); - break; - case 4: - add_msg_if_player( m_bad, _( "You feel weak. Where has your strength gone?" ) ); - break; - case 5: - add_msg_if_player( m_bad, _( "You feel feeble. A gust of wind could make you stumble." ) ); - break; - case 6: - add_msg_if_player( m_bad, _( "There is an overwhelming aura of tiredness inside of you." ) ); - mod_fatigue( intense * 3 ); - break; - case 7: // 7-9 empty for variability, as messages stack on higher intensity - break; - case 8: - break; - case 9: - break; - } - // level 2 anemia introduces dizziness, shakes, headaches, cravings for non-comestibles, - // mouth and tongue soreness - if( intense > 1 ) { - switch( dice( 1, 9 ) ) { - case 1: - add_msg_if_player( m_bad, _( "Rest is what you want. Rest is what you need." ) ); - break; - case 2: - add_msg_if_player( m_bad, _( "You feel dizzy and can't coordinate the movement of your feet." ) ); - add_effect( effect_stunned, rng( 1_minutes, 2_minutes ) ); - break; - case 3: - add_msg_if_player( m_bad, _( "Your muscles are quivering." ) ); - add_effect( effect_shakes, rng( 4_minutes, 8_minutes ) ); - break; - case 4: - add_msg_if_player( m_bad, _( "You crave for ice. The dirt under your feet looks tasty too." ) ); - break; - case 5: - add_msg_if_player( m_bad, _( "Your whole mouth is sore, and your tongue is swollen." ) ); - break; - case 6: - add_msg_if_player( m_bad, _( "You feel lightheaded. A migraine follows." ) ); - mod_pain( intense * 9 ); - break; - case 7: // 7-9 empty for variability, as messages stack on higher intensity - break; - case 8: - break; - case 9: - break; - } - } - // level 3 anemia introduces restless legs, severe tiredness, breathlessness - if( intense > 2 ) { - switch( dice( 1, 9 ) ) { - case 1: - add_msg_if_player( m_bad, _( "Your legs are restless. The urge to move them is so strong." ) ); - break; - case 2: - add_msg_if_player( m_bad, _( "You feel like you could sleep on a rock." ) ); - mod_fatigue( intense * 3 ); - break; - case 3: - add_msg_if_player( m_bad, _( "You gasp for air!" ) ); - set_stamina( 0 ); - add_effect( effect_winded, rng( 30_seconds, 3_minutes ) ); - break; - case 4: - add_msg_if_player( m_bad, _( "Can't breathe. Must rest." ) ); - set_stamina( 0 ); - break; - case 5: - add_msg_if_player( m_bad, _( "You can't take it any more. Rest first; everything else later." ) ); - add_effect( effect_lying_down, rng( 2_minutes, 5_minutes ) ); - break; - case 6: - add_msg_if_player( m_bad, _( "You must sit down for a moment. Just a moment." ) ); - add_effect( effect_downed, rng( 1_minutes, 2_minutes ) ); - break; - case 7: // 7-9 empty for variability, as messages stack on higher intensity - break; - case 8: - break; - case 9: - break; - } - } - } } else if( id == effect_grabbed ) { set_num_blocks_bonus( get_num_blocks_bonus() - 1 ); int zed_number = 0; @@ -1274,212 +1513,6 @@ void Character::hardcoded_effects( effect &it ) if( dur == 1_turns && !sleeping ) { add_msg_if_player( _( "You try to sleep, but can't…" ) ); } - } else if( id == effect_sleep ) { - set_moves( 0 ); -#if defined(TILES) - if( is_player() ) { - SDL_PumpEvents(); - } -#endif // TILES - - if( intense < 1 ) { - it.set_intensity( 1 ); - } else if( intense < 24 ) { - it.mod_intensity( 1 ); - } - - if( has_effect( effect_narcosis ) && get_fatigue() <= 25 ) { - set_fatigue( 25 ); //Prevent us from waking up naturally while under anesthesia - } - - if( get_fatigue() < -25 && it.get_duration() > 3_minutes && !has_effect( effect_narcosis ) ) { - it.set_duration( 1_turns * dice( 3, 10 ) ); - } - - if( get_fatigue() <= 0 && get_fatigue() > -20 && !has_effect( effect_narcosis ) ) { - mod_fatigue( -25 ); - if( get_sleep_deprivation() < SLEEP_DEPRIVATION_HARMLESS ) { - add_msg_if_player( m_good, _( "You feel well rested." ) ); - } else { - add_msg_if_player( m_warning, - _( "You feel physically rested, but you haven't been able to catch up on your missed sleep yet." ) ); - } - it.set_duration( 1_turns * dice( 3, 100 ) ); - } - - // TODO: Move this to update_needs when NPCs can mutate - if( calendar::once_every( 10_minutes ) && ( has_trait( trait_CHLOROMORPH ) || - has_trait( trait_M_SKIN3 ) || has_trait( trait_WATERSLEEP ) ) && - here.is_outside( pos() ) ) { - if( has_trait( trait_CHLOROMORPH ) ) { - // Hunger and thirst fall before your Chloromorphic physiology! - if( g->natural_light_level( posz() ) >= 12 && - get_weather().weather_id->sun_intensity >= sun_intensity_type::light ) { - if( get_hunger() >= -30 ) { - mod_hunger( -5 ); - // photosynthesis warrants absorbing kcal directly - mod_stored_nutr( -5 ); - } - if( get_thirst() >= -30 ) { - mod_thirst( -5 ); - } - } - } - if( has_trait( trait_M_SKIN3 ) ) { - // Spores happen! - if( here.has_flag_ter_or_furn( "FUNGUS", pos() ) ) { - if( get_fatigue() >= 0 ) { - mod_fatigue( -5 ); // Local guides need less sleep on fungal soil - } - if( calendar::once_every( 1_hours ) ) { - spores(); // spawn some P O O F Y B O I S - } - } - } - if( has_trait( trait_WATERSLEEP ) ) { - mod_fatigue( -3 ); // Fish sleep less in water - } - } - - // Check mutation category strengths to see if we're mutated enough to get a dream - mutation_category_id highcat = get_highest_category(); - int highest = mutation_category_level[highcat]; - - // Determine the strength of effects or dreams based upon category strength - int strength = 0; // Category too weak for any effect or dream - if( crossed_threshold() ) { - strength = 4; // Post-human. - } else if( highest >= 20 && highest < 35 ) { - strength = 1; // Low strength - } else if( highest >= 35 && highest < 50 ) { - strength = 2; // Medium strength - } else if( highest >= 50 ) { - strength = 3; // High strength - } - - // Get a dream if category strength is high enough. - if( strength != 0 ) { - //Once every 6 / 3 / 2 hours, with a bit of randomness - if( calendar::once_every( 6_hours / strength ) && one_in( 3 ) ) { - // Select a dream - std::string dream = get_category_dream( highcat, strength ); - if( !dream.empty() ) { - add_msg_if_player( dream ); - } - // Mycus folks upgrade in their sleep. - if( has_trait( trait_THRESH_MYCUS ) ) { - if( one_in( 8 ) ) { - mutate_category( mutation_category_id( "MYCUS" ) ); - mod_stored_nutr( 10 ); - mod_thirst( 10 ); - mod_fatigue( 5 ); - } - } - } - } - - bool woke_up = false; - int tirednessVal = rng( 5, 200 ) + rng( 0, std::abs( get_fatigue() * 2 * 5 ) ); - if( !is_blind() && !has_effect( effect_narcosis ) ) { - if( !has_trait( - trait_SEESLEEP ) ) { // People who can see while sleeping are acclimated to the light. - if( has_trait( trait_HEAVYSLEEPER2 ) && !has_trait( trait_HIBERNATE ) ) { - // So you can too sleep through noon - if( ( tirednessVal * 1.25 ) < here.ambient_light_at( pos() ) && ( get_fatigue() < 10 || - one_in( get_fatigue() / 2 ) ) ) { - add_msg_if_player( _( "It's too bright to sleep." ) ); - // Set ourselves up for removal - it.set_duration( 0_turns ); - woke_up = true; - } - // Ursine hibernators would likely do so indoors. Plants, though, might be in the sun. - } else if( has_trait( trait_HIBERNATE ) ) { - if( ( tirednessVal * 5 ) < here.ambient_light_at( pos() ) && ( get_fatigue() < 10 || - one_in( get_fatigue() / 2 ) ) ) { - add_msg_if_player( _( "It's too bright to sleep." ) ); - // Set ourselves up for removal - it.set_duration( 0_turns ); - woke_up = true; - } - } else if( tirednessVal < here.ambient_light_at( pos() ) && ( get_fatigue() < 10 || - one_in( get_fatigue() / 2 ) ) ) { - add_msg_if_player( _( "It's too bright to sleep." ) ); - // Set ourselves up for removal - it.set_duration( 0_turns ); - woke_up = true; - } - } else if( has_active_mutation( trait_SEESLEEP ) ) { - Creature *hostile_critter = g->is_hostile_very_close(); - if( hostile_critter != nullptr ) { - add_msg_if_player( _( "You see %s approaching!" ), - hostile_critter->disp_name() ); - it.set_duration( 0_turns ); - woke_up = true; - } - } - } - - // Have we already woken up? - if( !woke_up && !has_effect( effect_narcosis ) ) { - // Cold or heat may wake you up. - // Player will sleep through cold or heat if fatigued enough - for( const bodypart_id &bp : get_all_body_parts() ) { - const int curr_temp = get_part_temp_cur( bp ); - if( curr_temp < BODYTEMP_VERY_COLD - get_fatigue() / 2 ) { - if( one_in( 30000 ) ) { - add_msg_if_player( _( "You toss and turn trying to keep warm." ) ); - } - if( curr_temp < BODYTEMP_FREEZING - get_fatigue() / 2 || - one_in( curr_temp * 6 + 30000 ) ) { - add_msg_if_player( m_bad, _( "It's too cold to sleep." ) ); - // Set ourselves up for removal - it.set_duration( 0_turns ); - woke_up = true; - break; - } - } else if( curr_temp > BODYTEMP_VERY_HOT + get_fatigue() / 2 ) { - if( one_in( 30000 ) ) { - add_msg_if_player( _( "You toss and turn in the heat." ) ); - } - if( curr_temp > BODYTEMP_SCORCHING + get_fatigue() / 2 || - one_in( 90000 - curr_temp ) ) { - add_msg_if_player( m_bad, _( "It's too hot to sleep." ) ); - // Set ourselves up for removal - it.set_duration( 0_turns ); - woke_up = true; - break; - } - } - } - if( has_trait( trait_SCHIZOPHRENIC ) && one_in( 43200 ) && is_player() ) { - if( one_in( 2 ) ) { - sound_hallu(); - } else { - int max_count = rng( 1, 3 ); - int count = 0; - for( const tripoint &mp : here.points_in_radius( pos(), 1 ) ) { - if( mp == pos() ) { - continue; - } - if( here.has_flag( "FLAT", mp ) && - here.pl_sees( mp, 2 ) ) { - g->spawn_hallucination( mp ); - if( ++count > max_count ) { - break; - } - } - } - } - it.set_duration( 0_turns ); - woke_up = true; - } - } - - // A bit of a hack: check if we are about to wake up for any reason, including regular - // timing out of sleep - if( dur == 1_turns || woke_up ) { - wake_up(); - } } else if( id == effect_alarm_clock ) { if( in_sleep_state() ) { const bool asleep = has_effect( effect_sleep ); From 3245753d62809cdeb99124d37a2327f8698d8efc Mon Sep 17 00:00:00 2001 From: John Bytheway Date: Sat, 3 Apr 2021 07:27:33 -0400 Subject: [PATCH 134/453] Split ammo_set_test function Split this large function to reduce its size. --- tests/ammo_set_test.cpp | 660 ++++++++++++++++++++-------------------- 1 file changed, 334 insertions(+), 326 deletions(-) diff --git a/tests/ammo_set_test.cpp b/tests/ammo_set_test.cpp index e258ade67054c..b7958c2712706 100644 --- a/tests/ammo_set_test.cpp +++ b/tests/ammo_set_test.cpp @@ -13,378 +13,386 @@ #include "type_id.h" #include "value_ptr.h" -TEST_CASE( "ammo_set", "[ammo_set][magazine][ammo]" ) +TEST_CASE( "ammo_set items with MAGAZINE pockets", "[ammo_set][magazine][ammo]" ) { - SECTION( "ammo_set items with MAGAZINE pockets" ) { - GIVEN( "empty 9mm CZ 75 20-round magazine" ) { - item cz75mag_20rd( "cz75mag_20rd" ); - REQUIRE( cz75mag_20rd.is_magazine() ); - REQUIRE( cz75mag_20rd.ammo_remaining() == 0 ); - REQUIRE( cz75mag_20rd.ammo_default() ); - itype_id ammo_default_id = cz75mag_20rd.ammo_default(); - itype_id ammo9mm_id( "9mm" ); - REQUIRE( ammo_default_id.str() == ammo9mm_id.str() ); - const ammotype &amtype = ammo9mm_id->ammo->type; - REQUIRE( cz75mag_20rd.ammo_capacity( amtype ) == 20 ); - WHEN( "set 9mm ammo in the magazine w/o quantity" ) { - cz75mag_20rd.ammo_set( ammo9mm_id ); - THEN( "magazine has 20 rounds of 9mm" ) { - CHECK( cz75mag_20rd.ammo_remaining() == 20 ); - CHECK( cz75mag_20rd.ammo_current().str() == ammo9mm_id.str() ); - } + GIVEN( "empty 9mm CZ 75 20-round magazine" ) { + item cz75mag_20rd( "cz75mag_20rd" ); + REQUIRE( cz75mag_20rd.is_magazine() ); + REQUIRE( cz75mag_20rd.ammo_remaining() == 0 ); + REQUIRE( cz75mag_20rd.ammo_default() ); + itype_id ammo_default_id = cz75mag_20rd.ammo_default(); + itype_id ammo9mm_id( "9mm" ); + REQUIRE( ammo_default_id.str() == ammo9mm_id.str() ); + const ammotype &amtype = ammo9mm_id->ammo->type; + REQUIRE( cz75mag_20rd.ammo_capacity( amtype ) == 20 ); + WHEN( "set 9mm ammo in the magazine w/o quantity" ) { + cz75mag_20rd.ammo_set( ammo9mm_id ); + THEN( "magazine has 20 rounds of 9mm" ) { + CHECK( cz75mag_20rd.ammo_remaining() == 20 ); + CHECK( cz75mag_20rd.ammo_current().str() == ammo9mm_id.str() ); } - WHEN( "set 9mm ammo in the magazine -1 quantity" ) { - cz75mag_20rd.ammo_set( ammo9mm_id, -1 ); - THEN( "magazine has 20 rounds of 9mm" ) { - CHECK( cz75mag_20rd.ammo_remaining() == 20 ); - CHECK( cz75mag_20rd.ammo_current().str() == ammo9mm_id.str() ); - } + } + WHEN( "set 9mm ammo in the magazine -1 quantity" ) { + cz75mag_20rd.ammo_set( ammo9mm_id, -1 ); + THEN( "magazine has 20 rounds of 9mm" ) { + CHECK( cz75mag_20rd.ammo_remaining() == 20 ); + CHECK( cz75mag_20rd.ammo_current().str() == ammo9mm_id.str() ); } - WHEN( "set 9mm ammo in the magazine 21 quantity" ) { - cz75mag_20rd.ammo_set( ammo9mm_id, 21 ); - THEN( "magazine has 20 rounds of 9mm" ) { - CHECK( cz75mag_20rd.ammo_remaining() == 20 ); - CHECK( cz75mag_20rd.ammo_current().str() == ammo9mm_id.str() ); - } + } + WHEN( "set 9mm ammo in the magazine 21 quantity" ) { + cz75mag_20rd.ammo_set( ammo9mm_id, 21 ); + THEN( "magazine has 20 rounds of 9mm" ) { + CHECK( cz75mag_20rd.ammo_remaining() == 20 ); + CHECK( cz75mag_20rd.ammo_current().str() == ammo9mm_id.str() ); } - WHEN( "set 9mm ammo in the magazine 20 quantity" ) { - cz75mag_20rd.ammo_set( ammo9mm_id, 20 ); - THEN( "magazine has 20 rounds of 9mm" ) { - CHECK( cz75mag_20rd.ammo_remaining() == 20 ); - CHECK( cz75mag_20rd.ammo_current().str() == ammo9mm_id.str() ); - } + } + WHEN( "set 9mm ammo in the magazine 20 quantity" ) { + cz75mag_20rd.ammo_set( ammo9mm_id, 20 ); + THEN( "magazine has 20 rounds of 9mm" ) { + CHECK( cz75mag_20rd.ammo_remaining() == 20 ); + CHECK( cz75mag_20rd.ammo_current().str() == ammo9mm_id.str() ); } - WHEN( "set 9mm ammo in the magazine 12 quantity" ) { - cz75mag_20rd.ammo_set( ammo9mm_id, 12 ); - THEN( "magazine has 12 rounds of 9mm" ) { - CHECK( cz75mag_20rd.ammo_remaining() == 12 ); - CHECK( cz75mag_20rd.ammo_current().str() == ammo9mm_id.str() ); - } + } + WHEN( "set 9mm ammo in the magazine 12 quantity" ) { + cz75mag_20rd.ammo_set( ammo9mm_id, 12 ); + THEN( "magazine has 12 rounds of 9mm" ) { + CHECK( cz75mag_20rd.ammo_remaining() == 12 ); + CHECK( cz75mag_20rd.ammo_current().str() == ammo9mm_id.str() ); } - WHEN( "set 9mm ammo in the magazine 1 quantity" ) { - cz75mag_20rd.ammo_set( ammo9mm_id, 1 ); - THEN( "magazine has 1 round of 9mm" ) { - CHECK( cz75mag_20rd.ammo_remaining() == 1 ); - CHECK( cz75mag_20rd.ammo_current().str() == ammo9mm_id.str() ); - } + } + WHEN( "set 9mm ammo in the magazine 1 quantity" ) { + cz75mag_20rd.ammo_set( ammo9mm_id, 1 ); + THEN( "magazine has 1 round of 9mm" ) { + CHECK( cz75mag_20rd.ammo_remaining() == 1 ); + CHECK( cz75mag_20rd.ammo_current().str() == ammo9mm_id.str() ); + } + } + WHEN( "set 9mm ammo in the magazine 0 quantity" ) { + cz75mag_20rd.ammo_set( ammo9mm_id, 0 ); + THEN( "magazine has 0 round of null" ) { + CHECK( cz75mag_20rd.ammo_remaining() == 0 ); + CHECK( cz75mag_20rd.ammo_current().is_null() ); + } + } + WHEN( "set 9mm FMJ ammo in the magazine 15 quantity" ) { + itype_id ammo9mmfmj_id( "9mmfmj" ); + cz75mag_20rd.ammo_set( ammo9mmfmj_id, 15 ); + THEN( "magazine has 15 round of 9mm FMJ" ) { + CHECK( cz75mag_20rd.ammo_remaining() == 15 ); + CHECK( cz75mag_20rd.ammo_current().str() == ammo9mmfmj_id.str() ); } - WHEN( "set 9mm ammo in the magazine 0 quantity" ) { - cz75mag_20rd.ammo_set( ammo9mm_id, 0 ); - THEN( "magazine has 0 round of null" ) { + } + WHEN( "set 308 ammo in the 9mm magazine" ) { + itype_id ammo308_id( "308" ); + std::string dmsg = capture_debugmsg_during( [&cz75mag_20rd, &ammo308_id]() { + cz75mag_20rd.ammo_set( ammo308_id, 15 ); + } ); + THEN( "get debugmsg with \"Tried to set invalid ammo of 308 for cz75mag_20rd\"" ) { + CHECK_THAT( dmsg, Catch::EndsWith( "Tried to set invalid ammo of 308 for cz75mag_20rd" ) ); + AND_THEN( "magazine has 0 round of null" ) { CHECK( cz75mag_20rd.ammo_remaining() == 0 ); CHECK( cz75mag_20rd.ammo_current().is_null() ); } } - WHEN( "set 9mm FMJ ammo in the magazine 15 quantity" ) { - itype_id ammo9mmfmj_id( "9mmfmj" ); - cz75mag_20rd.ammo_set( ammo9mmfmj_id, 15 ); - THEN( "magazine has 15 round of 9mm FMJ" ) { - CHECK( cz75mag_20rd.ammo_remaining() == 15 ); - CHECK( cz75mag_20rd.ammo_current().str() == ammo9mmfmj_id.str() ); - } + } + } + GIVEN( "empty M24 gun with capacity of 5 .308 rounds" ) { + item m24( "M24" ); + REQUIRE( m24.is_gun() ); + REQUIRE( m24.is_magazine() ); + REQUIRE( m24.ammo_remaining() == 0 ); + REQUIRE( m24.ammo_default() ); + itype_id ammo_default_id = m24.ammo_default(); + itype_id ammo308_id( "308" ); + itype_id ammo762_51_id( "762_51" ); + REQUIRE( ammo_default_id.str() == ammo762_51_id.str() ); + const ammotype &amtype = ammo308_id->ammo->type; + REQUIRE( m24.ammo_capacity( amtype ) == 5 ); + WHEN( "set 308 ammo in the gun with internal magazine w/o quantity" ) { + m24.ammo_set( ammo308_id ); + THEN( "gun has 5 rounds of 308" ) { + CHECK( m24.ammo_remaining() == 5 ); + CHECK( m24.ammo_current().str() == ammo308_id.str() ); } - WHEN( "set 308 ammo in the 9mm magazine" ) { - itype_id ammo308_id( "308" ); - std::string dmsg = capture_debugmsg_during( [&cz75mag_20rd, &ammo308_id]() { - cz75mag_20rd.ammo_set( ammo308_id, 15 ); - } ); - THEN( "get debugmsg with \"Tried to set invalid ammo of 308 for cz75mag_20rd\"" ) { - CHECK_THAT( dmsg, Catch::EndsWith( "Tried to set invalid ammo of 308 for cz75mag_20rd" ) ); - AND_THEN( "magazine has 0 round of null" ) { - CHECK( cz75mag_20rd.ammo_remaining() == 0 ); - CHECK( cz75mag_20rd.ammo_current().is_null() ); - } - } + } + WHEN( "set 308 ammo in the gun with internal magazine -1 quantity" ) { + m24.ammo_set( ammo308_id, -1 ); + THEN( "gun has 5 rounds of 308" ) { + CHECK( m24.ammo_remaining() == 5 ); + CHECK( m24.ammo_current().str() == ammo308_id.str() ); } } - GIVEN( "empty M24 gun with capacity of 5 .308 rounds" ) { - item m24( "M24" ); - REQUIRE( m24.is_gun() ); - REQUIRE( m24.is_magazine() ); - REQUIRE( m24.ammo_remaining() == 0 ); - REQUIRE( m24.ammo_default() ); - itype_id ammo_default_id = m24.ammo_default(); - itype_id ammo308_id( "308" ); - itype_id ammo762_51_id( "762_51" ); - REQUIRE( ammo_default_id.str() == ammo762_51_id.str() ); - const ammotype &amtype = ammo308_id->ammo->type; - REQUIRE( m24.ammo_capacity( amtype ) == 5 ); - WHEN( "set 308 ammo in the gun with internal magazine w/o quantity" ) { - m24.ammo_set( ammo308_id ); - THEN( "gun has 5 rounds of 308" ) { - CHECK( m24.ammo_remaining() == 5 ); - CHECK( m24.ammo_current().str() == ammo308_id.str() ); - } + WHEN( "set 308 ammo in the gun with internal magazine 500 quantity" ) { + m24.ammo_set( ammo308_id, 500 ); + THEN( "gun has 5 rounds of 308" ) { + CHECK( m24.ammo_remaining() == 5 ); + CHECK( m24.ammo_current().str() == ammo308_id.str() ); } - WHEN( "set 308 ammo in the gun with internal magazine -1 quantity" ) { - m24.ammo_set( ammo308_id, -1 ); - THEN( "gun has 5 rounds of 308" ) { - CHECK( m24.ammo_remaining() == 5 ); - CHECK( m24.ammo_current().str() == ammo308_id.str() ); - } + } + WHEN( "set 308 ammo in the gun with internal magazine 5 quantity" ) { + m24.ammo_set( ammo308_id, 5 ); + THEN( "gun has 5 rounds of 308" ) { + CHECK( m24.ammo_remaining() == 5 ); + CHECK( m24.ammo_current().str() == ammo308_id.str() ); } - WHEN( "set 308 ammo in the gun with internal magazine 500 quantity" ) { - m24.ammo_set( ammo308_id, 500 ); - THEN( "gun has 5 rounds of 308" ) { - CHECK( m24.ammo_remaining() == 5 ); - CHECK( m24.ammo_current().str() == ammo308_id.str() ); - } + } + WHEN( "set 308 ammo in the gun with internal magazine 4 quantity" ) { + m24.ammo_set( ammo308_id, 4 ); + THEN( "gun has 4 rounds of 308" ) { + CHECK( m24.ammo_remaining() == 4 ); + CHECK( m24.ammo_current().str() == ammo308_id.str() ); } - WHEN( "set 308 ammo in the gun with internal magazine 5 quantity" ) { - m24.ammo_set( ammo308_id, 5 ); - THEN( "gun has 5 rounds of 308" ) { - CHECK( m24.ammo_remaining() == 5 ); - CHECK( m24.ammo_current().str() == ammo308_id.str() ); - } + } + WHEN( "set 308 ammo in the gun with internal magazine 1 quantity" ) { + m24.ammo_set( ammo308_id, 1 ); + THEN( "gun has 41rounds of 308" ) { + CHECK( m24.ammo_remaining() == 1 ); + CHECK( m24.ammo_current().str() == ammo308_id.str() ); } - WHEN( "set 308 ammo in the gun with internal magazine 4 quantity" ) { - m24.ammo_set( ammo308_id, 4 ); - THEN( "gun has 4 rounds of 308" ) { - CHECK( m24.ammo_remaining() == 4 ); - CHECK( m24.ammo_current().str() == ammo308_id.str() ); - } + } + WHEN( "set 308 ammo in the gun with internal magazine 0 quantity" ) { + m24.ammo_set( ammo308_id, 0 ); + THEN( "gun has 0 rounds of null" ) { + CHECK( m24.ammo_remaining() == 0 ); + CHECK( m24.ammo_current().is_null() ); } - WHEN( "set 308 ammo in the gun with internal magazine 1 quantity" ) { - m24.ammo_set( ammo308_id, 1 ); - THEN( "gun has 41rounds of 308" ) { - CHECK( m24.ammo_remaining() == 1 ); - CHECK( m24.ammo_current().str() == ammo308_id.str() ); - } + } + WHEN( "set 762_51 ammo in the gun with internal magazine 2 quantity" ) { + m24.ammo_set( ammo762_51_id, 2 ); + THEN( "gun has 2 rounds of 762_51" ) { + CHECK( m24.ammo_remaining() == 2 ); + CHECK( m24.ammo_current().str() == ammo762_51_id.str() ); } - WHEN( "set 308 ammo in the gun with internal magazine 0 quantity" ) { - m24.ammo_set( ammo308_id, 0 ); - THEN( "gun has 0 rounds of null" ) { + } + WHEN( "set 9mm ammo in ammo in the .308 gun" ) { + itype_id ammo9mm_id( "9mm" ); + std::string dmsg = capture_debugmsg_during( [&m24, &ammo9mm_id]() { + m24.ammo_set( ammo9mm_id, 2 ); + } ); + THEN( "get debugmsg with \"Tried to set invalid ammo of 9mm for M24\"" ) { + CHECK_THAT( dmsg, Catch::EndsWith( "Tried to set invalid ammo of 9mm for M24" ) ); + AND_THEN( "gun has 0 round of null" ) { CHECK( m24.ammo_remaining() == 0 ); CHECK( m24.ammo_current().is_null() ); } } - WHEN( "set 762_51 ammo in the gun with internal magazine 2 quantity" ) { - m24.ammo_set( ammo762_51_id, 2 ); - THEN( "gun has 2 rounds of 762_51" ) { - CHECK( m24.ammo_remaining() == 2 ); - CHECK( m24.ammo_current().str() == ammo762_51_id.str() ); - } + } + } +} + +TEST_CASE( "ammo_set items with MAGAZINE_WELL pockets with magazine", + "[ammo_set][magazine][ammo]" ) +{ + GIVEN( "CZ 75 B 9mm gun with empty 9mm CZ 75 20-round magazine" ) { + item cz75( "cz75" ); + item cz75mag_20rd( "cz75mag_20rd" ); + REQUIRE( cz75.is_gun() ); + REQUIRE_FALSE( cz75.is_magazine() ); + REQUIRE( cz75.magazine_current() == nullptr ); + REQUIRE( cz75.magazine_compatible().count( cz75mag_20rd.typeId() ) == 1 ); + REQUIRE( cz75mag_20rd.is_magazine() ); + REQUIRE( cz75mag_20rd.ammo_remaining() == 0 ); + REQUIRE( cz75mag_20rd.ammo_default() ); + itype_id ammo_default_id = cz75mag_20rd.ammo_default(); + itype_id ammo9mm_id( "9mm" ); + REQUIRE( ammo_default_id.str() == ammo9mm_id.str() ); + const ammotype &amtype = ammo9mm_id->ammo->type; + REQUIRE( cz75mag_20rd.ammo_capacity( amtype ) == 20 ); + cz75.put_in( cz75mag_20rd, item_pocket::pocket_type::MAGAZINE_WELL ); + REQUIRE( cz75.magazine_current()->typeId().str() == cz75mag_20rd.typeId().str() ); + REQUIRE( cz75.ammo_capacity( amtype ) == 20 ); + WHEN( "set 9mm ammo in the gun with magazine w/o quantity" ) { + cz75.ammo_set( ammo9mm_id ); + THEN( "gun and current magazine has 20 rounds of 9mm" ) { + CHECK( cz75.ammo_remaining() == 20 ); + CHECK( cz75.ammo_current().str() == ammo9mm_id.str() ); + CHECK( cz75.magazine_current()->ammo_remaining() == 20 ); + CHECK( cz75.magazine_current()->ammo_current().str() == ammo9mm_id.str() ); } - WHEN( "set 9mm ammo in ammo in the .308 gun" ) { - itype_id ammo9mm_id( "9mm" ); - std::string dmsg = capture_debugmsg_during( [&m24, &ammo9mm_id]() { - m24.ammo_set( ammo9mm_id, 2 ); - } ); - THEN( "get debugmsg with \"Tried to set invalid ammo of 9mm for M24\"" ) { - CHECK_THAT( dmsg, Catch::EndsWith( "Tried to set invalid ammo of 9mm for M24" ) ); - AND_THEN( "gun has 0 round of null" ) { - CHECK( m24.ammo_remaining() == 0 ); - CHECK( m24.ammo_current().is_null() ); - } - } + } + WHEN( "set 9mm ammo in the gun with magazine -1 quantity" ) { + cz75.ammo_set( ammo9mm_id, -1 ); + THEN( "gun and current magazine has 20 rounds of 9mm" ) { + CHECK( cz75.ammo_remaining() == 20 ); + CHECK( cz75.ammo_current().str() == ammo9mm_id.str() ); + CHECK( cz75.magazine_current()->ammo_remaining() == 20 ); + CHECK( cz75.magazine_current()->ammo_current().str() == ammo9mm_id.str() ); } } - } - SECTION( "ammo_set items with MAGAZINE_WELL pockets" ) { - GIVEN( "CZ 75 B 9mm gun with empty 9mm CZ 75 20-round magazine" ) { - item cz75( "cz75" ); - item cz75mag_20rd( "cz75mag_20rd" ); - REQUIRE( cz75.is_gun() ); - REQUIRE_FALSE( cz75.is_magazine() ); - REQUIRE( cz75.magazine_current() == nullptr ); - REQUIRE( cz75.magazine_compatible().count( cz75mag_20rd.typeId() ) == 1 ); - REQUIRE( cz75mag_20rd.is_magazine() ); - REQUIRE( cz75mag_20rd.ammo_remaining() == 0 ); - REQUIRE( cz75mag_20rd.ammo_default() ); - itype_id ammo_default_id = cz75mag_20rd.ammo_default(); - itype_id ammo9mm_id( "9mm" ); - REQUIRE( ammo_default_id.str() == ammo9mm_id.str() ); - const ammotype &amtype = ammo9mm_id->ammo->type; - REQUIRE( cz75mag_20rd.ammo_capacity( amtype ) == 20 ); - cz75.put_in( cz75mag_20rd, item_pocket::pocket_type::MAGAZINE_WELL ); - REQUIRE( cz75.magazine_current()->typeId().str() == cz75mag_20rd.typeId().str() ); - REQUIRE( cz75.ammo_capacity( amtype ) == 20 ); - WHEN( "set 9mm ammo in the gun with magazine w/o quantity" ) { - cz75.ammo_set( ammo9mm_id ); - THEN( "gun and current magazine has 20 rounds of 9mm" ) { - CHECK( cz75.ammo_remaining() == 20 ); - CHECK( cz75.ammo_current().str() == ammo9mm_id.str() ); - CHECK( cz75.magazine_current()->ammo_remaining() == 20 ); - CHECK( cz75.magazine_current()->ammo_current().str() == ammo9mm_id.str() ); - } + WHEN( "set 9mm ammo in the gun with magazine 21 quantity" ) { + cz75.ammo_set( ammo9mm_id, 21 ); + THEN( "gun and current magazine has 20 rounds of 9mm" ) { + CHECK( cz75.ammo_remaining() == 20 ); + CHECK( cz75.ammo_current().str() == ammo9mm_id.str() ); + CHECK( cz75.magazine_current()->ammo_remaining() == 20 ); + CHECK( cz75.magazine_current()->ammo_current().str() == ammo9mm_id.str() ); } - WHEN( "set 9mm ammo in the gun with magazine -1 quantity" ) { - cz75.ammo_set( ammo9mm_id, -1 ); - THEN( "gun and current magazine has 20 rounds of 9mm" ) { - CHECK( cz75.ammo_remaining() == 20 ); - CHECK( cz75.ammo_current().str() == ammo9mm_id.str() ); - CHECK( cz75.magazine_current()->ammo_remaining() == 20 ); - CHECK( cz75.magazine_current()->ammo_current().str() == ammo9mm_id.str() ); - } + } + WHEN( "set 9mm ammo in the gun with magazine 20 quantity" ) { + cz75.ammo_set( ammo9mm_id, 20 ); + THEN( "gun and current magazine has 20 rounds of 9mm" ) { + CHECK( cz75.ammo_remaining() == 20 ); + CHECK( cz75.ammo_current().str() == ammo9mm_id.str() ); + CHECK( cz75.magazine_current()->ammo_remaining() == 20 ); + CHECK( cz75.magazine_current()->ammo_current().str() == ammo9mm_id.str() ); } - WHEN( "set 9mm ammo in the gun with magazine 21 quantity" ) { - cz75.ammo_set( ammo9mm_id, 21 ); - THEN( "gun and current magazine has 20 rounds of 9mm" ) { - CHECK( cz75.ammo_remaining() == 20 ); - CHECK( cz75.ammo_current().str() == ammo9mm_id.str() ); - CHECK( cz75.magazine_current()->ammo_remaining() == 20 ); - CHECK( cz75.magazine_current()->ammo_current().str() == ammo9mm_id.str() ); - } + } + WHEN( "set 9mm ammo in the gun with magazine 12 quantity" ) { + cz75.ammo_set( ammo9mm_id, 12 ); + THEN( "gun and current magazine has 12 rounds of 9mm" ) { + CHECK( cz75.ammo_remaining() == 12 ); + CHECK( cz75.ammo_current().str() == ammo9mm_id.str() ); + CHECK( cz75.magazine_current()->ammo_remaining() == 12 ); + CHECK( cz75.magazine_current()->ammo_current().str() == ammo9mm_id.str() ); } - WHEN( "set 9mm ammo in the gun with magazine 20 quantity" ) { - cz75.ammo_set( ammo9mm_id, 20 ); - THEN( "gun and current magazine has 20 rounds of 9mm" ) { - CHECK( cz75.ammo_remaining() == 20 ); - CHECK( cz75.ammo_current().str() == ammo9mm_id.str() ); - CHECK( cz75.magazine_current()->ammo_remaining() == 20 ); - CHECK( cz75.magazine_current()->ammo_current().str() == ammo9mm_id.str() ); - } + } + WHEN( "set 9mm ammo in the current magazine of a gun 1 quantity" ) { + cz75.magazine_current()->ammo_set( ammo9mm_id, 1 ); + THEN( "gun and current magazine has 1 round of 9mm" ) { + CHECK( cz75.ammo_remaining() == 1 ); + CHECK( cz75.ammo_current().str() == ammo9mm_id.str() ); + CHECK( cz75.magazine_current()->ammo_remaining() == 1 ); + CHECK( cz75.magazine_current()->ammo_current().str() == ammo9mm_id.str() ); } - WHEN( "set 9mm ammo in the gun with magazine 12 quantity" ) { - cz75.ammo_set( ammo9mm_id, 12 ); - THEN( "gun and current magazine has 12 rounds of 9mm" ) { - CHECK( cz75.ammo_remaining() == 12 ); - CHECK( cz75.ammo_current().str() == ammo9mm_id.str() ); - CHECK( cz75.magazine_current()->ammo_remaining() == 12 ); - CHECK( cz75.magazine_current()->ammo_current().str() == ammo9mm_id.str() ); - } + } + WHEN( "set 9mm ammo in the gun with magazine 0 quantity" ) { + cz75.ammo_set( ammo9mm_id, 0 ); + THEN( "gun and current magazine has 0 rounds of null" ) { + CHECK( cz75.ammo_remaining() == 0 ); + CHECK( cz75.ammo_current().is_null() ); + CHECK( cz75.magazine_current()->ammo_remaining() == 0 ); + CHECK( cz75.magazine_current()->ammo_current().is_null() ); } - WHEN( "set 9mm ammo in the current magazine of a gun 1 quantity" ) { - cz75.magazine_current()->ammo_set( ammo9mm_id, 1 ); - THEN( "gun and current magazine has 1 round of 9mm" ) { - CHECK( cz75.ammo_remaining() == 1 ); - CHECK( cz75.ammo_current().str() == ammo9mm_id.str() ); - CHECK( cz75.magazine_current()->ammo_remaining() == 1 ); - CHECK( cz75.magazine_current()->ammo_current().str() == ammo9mm_id.str() ); - } + } + WHEN( "set 9mm FMJ ammo in the gun with magazine 10 quantity" ) { + itype_id ammo9mmfmj_id( "9mmfmj" ); + cz75.ammo_set( ammo9mmfmj_id, 10 ); + THEN( "gun and current magazine has 10 rounds of 9mm FMJ" ) { + CHECK( cz75.ammo_remaining() == 10 ); + CHECK( cz75.ammo_current().str() == ammo9mmfmj_id.str() ); + CHECK( cz75.magazine_current()->ammo_remaining() == 10 ); + CHECK( cz75.magazine_current()->ammo_current().str() == ammo9mmfmj_id.str() ); } - WHEN( "set 9mm ammo in the gun with magazine 0 quantity" ) { - cz75.ammo_set( ammo9mm_id, 0 ); - THEN( "gun and current magazine has 0 rounds of null" ) { + } + WHEN( "set 308 ammo in the 9mm gun with magazine" ) { + itype_id ammo308_id( "308" ); + std::string dmsg = capture_debugmsg_during( [&cz75, &ammo308_id]() { + cz75.ammo_set( ammo308_id, 15 ); + } ); + THEN( "get debugmsg with \"Tried to set invalid ammo of 308 for cz75\"" ) { + CHECK_THAT( dmsg, Catch::EndsWith( "Tried to set invalid ammo of 308 for cz75" ) ); + AND_THEN( "gun has 0 round of null" ) { CHECK( cz75.ammo_remaining() == 0 ); CHECK( cz75.ammo_current().is_null() ); - CHECK( cz75.magazine_current()->ammo_remaining() == 0 ); - CHECK( cz75.magazine_current()->ammo_current().is_null() ); - } - } - WHEN( "set 9mm FMJ ammo in the gun with magazine 10 quantity" ) { - itype_id ammo9mmfmj_id( "9mmfmj" ); - cz75.ammo_set( ammo9mmfmj_id, 10 ); - THEN( "gun and current magazine has 10 rounds of 9mm FMJ" ) { - CHECK( cz75.ammo_remaining() == 10 ); - CHECK( cz75.ammo_current().str() == ammo9mmfmj_id.str() ); - CHECK( cz75.magazine_current()->ammo_remaining() == 10 ); - CHECK( cz75.magazine_current()->ammo_current().str() == ammo9mmfmj_id.str() ); - } - } - WHEN( "set 308 ammo in the 9mm gun with magazine" ) { - itype_id ammo308_id( "308" ); - std::string dmsg = capture_debugmsg_during( [&cz75, &ammo308_id]() { - cz75.ammo_set( ammo308_id, 15 ); - } ); - THEN( "get debugmsg with \"Tried to set invalid ammo of 308 for cz75\"" ) { - CHECK_THAT( dmsg, Catch::EndsWith( "Tried to set invalid ammo of 308 for cz75" ) ); - AND_THEN( "gun has 0 round of null" ) { - CHECK( cz75.ammo_remaining() == 0 ); - CHECK( cz75.ammo_current().is_null() ); - } } } } - GIVEN( "CZ 75 B 9mm gun w/o magazine" ) { - item cz75( "cz75" ); - itype_id cz75mag_12rd_id( "cz75mag_12rd" ); - itype_id cz75mag_20rd_id( "cz75mag_20rd" ); - itype_id cz75mag_26rd_id( "cz75mag_26rd" ); - itype_id ammo9mm_id( "9mm" ); - REQUIRE( cz75.is_gun() ); - REQUIRE_FALSE( cz75.is_magazine() ); - REQUIRE( cz75.magazine_current() == nullptr ); - REQUIRE( cz75.magazine_compatible().size() == 3 ); - REQUIRE( cz75.magazine_compatible().count( cz75mag_12rd_id ) == 1 ); - REQUIRE( cz75.magazine_compatible().count( cz75mag_20rd_id ) == 1 ); - REQUIRE( cz75.magazine_compatible().count( cz75mag_26rd_id ) == 1 ); - REQUIRE( cz75.magazine_default().str() == cz75mag_12rd_id.str() ); - const ammotype &amtype = ammo9mm_id->ammo->type; - REQUIRE( cz75.ammo_capacity( amtype ) == 0 ); - REQUIRE( !cz75.ammo_default().is_null() ); - REQUIRE( cz75.magazine_default()->magazine->default_ammo.str() == ammo9mm_id.str() ); - WHEN( "set 9mm ammo in the gun w/o magazine w/o quantity" ) { - cz75.ammo_set( ammo9mm_id ); - THEN( "gun with new cz75mag_12rd magazine has 12 rounds of 9mm" ) { - CHECK( cz75.ammo_remaining() == 12 ); - CHECK( cz75.ammo_current().str() == ammo9mm_id.str() ); - REQUIRE( cz75.magazine_current() != nullptr ); - CHECK( cz75.magazine_current()->typeId().str() == cz75mag_12rd_id.str() ); - CHECK( cz75.magazine_current()->ammo_remaining() == 12 ); - CHECK( cz75.magazine_current()->ammo_current().str() == ammo9mm_id.str() ); - } + } +} + +TEST_CASE( "ammo_set items with MAGAZINE_WELL pockets without magazine", + "[ammo_set][magazine][ammo]" ) +{ + GIVEN( "CZ 75 B 9mm gun w/o magazine" ) { + item cz75( "cz75" ); + itype_id cz75mag_12rd_id( "cz75mag_12rd" ); + itype_id cz75mag_20rd_id( "cz75mag_20rd" ); + itype_id cz75mag_26rd_id( "cz75mag_26rd" ); + itype_id ammo9mm_id( "9mm" ); + REQUIRE( cz75.is_gun() ); + REQUIRE_FALSE( cz75.is_magazine() ); + REQUIRE( cz75.magazine_current() == nullptr ); + REQUIRE( cz75.magazine_compatible().size() == 3 ); + REQUIRE( cz75.magazine_compatible().count( cz75mag_12rd_id ) == 1 ); + REQUIRE( cz75.magazine_compatible().count( cz75mag_20rd_id ) == 1 ); + REQUIRE( cz75.magazine_compatible().count( cz75mag_26rd_id ) == 1 ); + REQUIRE( cz75.magazine_default().str() == cz75mag_12rd_id.str() ); + const ammotype &amtype = ammo9mm_id->ammo->type; + REQUIRE( cz75.ammo_capacity( amtype ) == 0 ); + REQUIRE( !cz75.ammo_default().is_null() ); + REQUIRE( cz75.magazine_default()->magazine->default_ammo.str() == ammo9mm_id.str() ); + WHEN( "set 9mm ammo in the gun w/o magazine w/o quantity" ) { + cz75.ammo_set( ammo9mm_id ); + THEN( "gun with new cz75mag_12rd magazine has 12 rounds of 9mm" ) { + CHECK( cz75.ammo_remaining() == 12 ); + CHECK( cz75.ammo_current().str() == ammo9mm_id.str() ); + REQUIRE( cz75.magazine_current() != nullptr ); + CHECK( cz75.magazine_current()->typeId().str() == cz75mag_12rd_id.str() ); + CHECK( cz75.magazine_current()->ammo_remaining() == 12 ); + CHECK( cz75.magazine_current()->ammo_current().str() == ammo9mm_id.str() ); } - WHEN( "set 9mm ammo in the gun w/o magazine 19 quantity" ) { - cz75.ammo_set( ammo9mm_id, 19 ); - THEN( "gun with new cz75mag_20rd magazine has 19 rounds of 9mm" ) { - CHECK( cz75.ammo_remaining() == 19 ); - CHECK( cz75.ammo_current().str() == ammo9mm_id.str() ); - REQUIRE( cz75.magazine_current() != nullptr ); - CHECK( cz75.magazine_current()->typeId().str() == cz75mag_20rd_id.str() ); - CHECK( cz75.magazine_current()->ammo_remaining() == 19 ); - CHECK( cz75.magazine_current()->ammo_current().str() == ammo9mm_id.str() ); - } + } + WHEN( "set 9mm ammo in the gun w/o magazine 19 quantity" ) { + cz75.ammo_set( ammo9mm_id, 19 ); + THEN( "gun with new cz75mag_20rd magazine has 19 rounds of 9mm" ) { + CHECK( cz75.ammo_remaining() == 19 ); + CHECK( cz75.ammo_current().str() == ammo9mm_id.str() ); + REQUIRE( cz75.magazine_current() != nullptr ); + CHECK( cz75.magazine_current()->typeId().str() == cz75mag_20rd_id.str() ); + CHECK( cz75.magazine_current()->ammo_remaining() == 19 ); + CHECK( cz75.magazine_current()->ammo_current().str() == ammo9mm_id.str() ); } - WHEN( "set 9mm ammo in the gun w/o magazine 21 quantity" ) { - cz75.ammo_set( ammo9mm_id, 21 ); - THEN( "gun with new cz75mag_26rd magazine has 21 rounds of 9mm" ) { - CHECK( cz75.ammo_remaining() == 21 ); - CHECK( cz75.ammo_current().str() == ammo9mm_id.str() ); - REQUIRE( cz75.magazine_current() != nullptr ); - CHECK( cz75.magazine_current()->typeId().str() == cz75mag_26rd_id.str() ); - CHECK( cz75.magazine_current()->ammo_remaining() == 21 ); - CHECK( cz75.magazine_current()->ammo_current().str() == ammo9mm_id.str() ); - } + } + WHEN( "set 9mm ammo in the gun w/o magazine 21 quantity" ) { + cz75.ammo_set( ammo9mm_id, 21 ); + THEN( "gun with new cz75mag_26rd magazine has 21 rounds of 9mm" ) { + CHECK( cz75.ammo_remaining() == 21 ); + CHECK( cz75.ammo_current().str() == ammo9mm_id.str() ); + REQUIRE( cz75.magazine_current() != nullptr ); + CHECK( cz75.magazine_current()->typeId().str() == cz75mag_26rd_id.str() ); + CHECK( cz75.magazine_current()->ammo_remaining() == 21 ); + CHECK( cz75.magazine_current()->ammo_current().str() == ammo9mm_id.str() ); } - WHEN( "set 9mm ammo in the gun w/o magazine 9000 quantity" ) { - cz75.ammo_set( ammo9mm_id, 9000 ); - THEN( "gun with new cz75mag_26rd magazine has 26 rounds of 9mm" ) { - CHECK( cz75.ammo_remaining() == 26 ); - CHECK( cz75.ammo_current().str() == ammo9mm_id.str() ); - REQUIRE( cz75.magazine_current() != nullptr ); - CHECK( cz75.magazine_current()->typeId().str() == cz75mag_26rd_id.str() ); - CHECK( cz75.magazine_current()->ammo_remaining() == 26 ); - CHECK( cz75.magazine_current()->ammo_current().str() == ammo9mm_id.str() ); - } + } + WHEN( "set 9mm ammo in the gun w/o magazine 9000 quantity" ) { + cz75.ammo_set( ammo9mm_id, 9000 ); + THEN( "gun with new cz75mag_26rd magazine has 26 rounds of 9mm" ) { + CHECK( cz75.ammo_remaining() == 26 ); + CHECK( cz75.ammo_current().str() == ammo9mm_id.str() ); + REQUIRE( cz75.magazine_current() != nullptr ); + CHECK( cz75.magazine_current()->typeId().str() == cz75mag_26rd_id.str() ); + CHECK( cz75.magazine_current()->ammo_remaining() == 26 ); + CHECK( cz75.magazine_current()->ammo_current().str() == ammo9mm_id.str() ); } - WHEN( "set 308 ammo in the 9mm gun w/o magazine 2 quantity" ) { - itype_id ammo308_id( "308" ); - std::string dmsg = capture_debugmsg_during( [&cz75, &ammo308_id]() { - cz75.ammo_set( ammo308_id, 2 ); - } ); - THEN( "get debugmsg with \"Tried to set invalid ammo of 308 for cz75\"" ) { - REQUIRE( !dmsg.empty() ); - CHECK_THAT( dmsg, Catch::EndsWith( "Tried to set invalid ammo of 308 for cz75" ) ); - AND_THEN( "gun w/o magazine has 0 round of null" ) { - CHECK( cz75.ammo_remaining() == 0 ); - CHECK( cz75.ammo_current().is_null() ); - CHECK( cz75.magazine_current() == nullptr ); - } + } + WHEN( "set 308 ammo in the 9mm gun w/o magazine 2 quantity" ) { + itype_id ammo308_id( "308" ); + std::string dmsg = capture_debugmsg_during( [&cz75, &ammo308_id]() { + cz75.ammo_set( ammo308_id, 2 ); + } ); + THEN( "get debugmsg with \"Tried to set invalid ammo of 308 for cz75\"" ) { + REQUIRE( !dmsg.empty() ); + CHECK_THAT( dmsg, Catch::EndsWith( "Tried to set invalid ammo of 308 for cz75" ) ); + AND_THEN( "gun w/o magazine has 0 round of null" ) { + CHECK( cz75.ammo_remaining() == 0 ); + CHECK( cz75.ammo_current().is_null() ); + CHECK( cz75.magazine_current() == nullptr ); } } } } - SECTION( "ammo_set items with CONTAINER pockets" ) { - GIVEN( "small box" ) { - item box( "box_small" ); - REQUIRE_FALSE( box.is_gun() ); - REQUIRE_FALSE( box.is_magazine() ); - REQUIRE( box.is_container_empty() ); - REQUIRE( box.magazine_current() == nullptr ); - REQUIRE( box.magazine_compatible().empty() ); - itype_id ammo9mm_id( "9mm" ); - WHEN( "set 9mm ammo in the small box" ) { - std::string dmsg = capture_debugmsg_during( [&box, &ammo9mm_id]() { - box.ammo_set( ammo9mm_id, 10 ); - } ); - THEN( "get debugmsg with \"Tried to set invalid ammo of 9mm for box_small\"" ) { - CHECK_THAT( dmsg, Catch::EndsWith( "Tried to set invalid ammo of 9mm for box_small" ) ); - AND_THEN( "small box still empty" ) { - REQUIRE_FALSE( box.is_gun() ); - REQUIRE_FALSE( box.is_magazine() ); - CHECK( box.is_container_empty() ); - } +} + +TEST_CASE( "ammo_set items with CONTAINER pockets", "[ammo_set][magazine][ammo]" ) +{ + GIVEN( "small box" ) { + item box( "box_small" ); + REQUIRE_FALSE( box.is_gun() ); + REQUIRE_FALSE( box.is_magazine() ); + REQUIRE( box.is_container_empty() ); + REQUIRE( box.magazine_current() == nullptr ); + REQUIRE( box.magazine_compatible().empty() ); + itype_id ammo9mm_id( "9mm" ); + WHEN( "set 9mm ammo in the small box" ) { + std::string dmsg = capture_debugmsg_during( [&box, &ammo9mm_id]() { + box.ammo_set( ammo9mm_id, 10 ); + } ); + THEN( "get debugmsg with \"Tried to set invalid ammo of 9mm for box_small\"" ) { + CHECK_THAT( dmsg, Catch::EndsWith( "Tried to set invalid ammo of 9mm for box_small" ) ); + AND_THEN( "small box still empty" ) { + REQUIRE_FALSE( box.is_gun() ); + REQUIRE_FALSE( box.is_magazine() ); + CHECK( box.is_container_empty() ); } } } From 7542fa9ec80358748f041add52f4f25767e32391 Mon Sep 17 00:00:00 2001 From: John Bytheway Date: Sat, 3 Apr 2021 08:57:42 -0400 Subject: [PATCH 135/453] Refactor iteminfo_test coverage and encumbrance Pull out a bunch of repeated REQUIRES commands into two new helper functions. This dramatically reduces the number of statements in the function, allowing it to pass the clang-tidy check for function size, and I think it also improves readability. --- tests/iteminfo_test.cpp | 447 ++++++++++++++++++++++------------------ 1 file changed, 241 insertions(+), 206 deletions(-) diff --git a/tests/iteminfo_test.cpp b/tests/iteminfo_test.cpp index 719871ce735a0..7cb57da3c2fe9 100644 --- a/tests/iteminfo_test.cpp +++ b/tests/iteminfo_test.cpp @@ -20,6 +20,7 @@ #include "player_helpers.h" #include "recipe.h" #include "recipe_dictionary.h" +#include "stringmaker.h" // IWYU pragma: keep #include "type_id.h" #include "units.h" #include "value_ptr.h" @@ -638,6 +639,44 @@ TEST_CASE( "techniques when wielded", "[iteminfo][weapon][techniques]" ) " Medium blocking ability\n" ); } +static std::vector bodyparts_to_check() +{ + return { + bodypart_id( "torso" ), + bodypart_id( "arm_l" ), + bodypart_id( "arm_r" ), + bodypart_id( "leg_l" ), + bodypart_id( "leg_r" ), + bodypart_id( "hand_l" ), + bodypart_id( "hand_r" ), + bodypart_id( "head" ), + bodypart_id( "mouth" ), + bodypart_id( "foot_l" ), + bodypart_id( "foot_r" ), + }; +} + +static void verify_item_coverage( const item &i, const std::map &expected ) +{ + CAPTURE( i.typeId().str() ); + REQUIRE( i.get_covered_body_parts().any() ); + for( const bodypart_id &bp : bodyparts_to_check() ) { + CAPTURE( bp.id().str() ); + REQUIRE( i.get_coverage( bp ) == expected.at( bp ) ); + } +} + +static void verify_item_encumbrance( const item &i, item::encumber_flags flags, int average, + const std::map &expected ) +{ + CAPTURE( i.typeId().str() ); + REQUIRE( i.get_avg_encumber( get_player_character(), flags ) == average ); + for( const bodypart_id &bp : bodyparts_to_check() ) { + CAPTURE( bp.id().str() ); + REQUIRE( i.get_encumber( get_player_character(), bp, flags ) == expected.at( bp ) ); + } +} + // Related JSON fields: // "covers" // "coverage" @@ -653,18 +692,21 @@ TEST_CASE( "armor coverage, warmth, and encumbrance", "[iteminfo][armor][coverag SECTION( "armor with coverage shows covered body parts, warmth, encumbrance, and protection values" ) { // Long-sleeved shirt covering torso and arms item longshirt( "test_longshirt" ); - REQUIRE( longshirt.get_covered_body_parts().any() ); - REQUIRE( longshirt.get_coverage( bodypart_id( "torso" ) ) == 90 ); - REQUIRE( longshirt.get_coverage( bodypart_id( "arm_l" ) ) == 90 ); - REQUIRE( longshirt.get_coverage( bodypart_id( "arm_r" ) ) == 90 ); - REQUIRE( longshirt.get_coverage( bodypart_id( "leg_l" ) ) == 0 ); - REQUIRE( longshirt.get_coverage( bodypart_id( "leg_r" ) ) == 0 ); - REQUIRE( longshirt.get_coverage( bodypart_id( "hand_l" ) ) == 0 ); - REQUIRE( longshirt.get_coverage( bodypart_id( "hand_r" ) ) == 0 ); - REQUIRE( longshirt.get_coverage( bodypart_id( "head" ) ) == 0 ); - REQUIRE( longshirt.get_coverage( bodypart_id( "mouth" ) ) == 0 ); - REQUIRE( longshirt.get_coverage( bodypart_id( "foot_l" ) ) == 0 ); - REQUIRE( longshirt.get_coverage( bodypart_id( "foot_r" ) ) == 0 ); + verify_item_coverage( + longshirt, { + { bodypart_id( "torso" ), 90 }, + { bodypart_id( "arm_l" ), 90 }, + { bodypart_id( "arm_r" ), 90 }, + { bodypart_id( "leg_l" ), 0 }, + { bodypart_id( "leg_r" ), 0 }, + { bodypart_id( "hand_l" ), 0 }, + { bodypart_id( "hand_r" ), 0 }, + { bodypart_id( "head" ), 0 }, + { bodypart_id( "mouth" ), 0 }, + { bodypart_id( "foot_l" ), 0 }, + { bodypart_id( "foot_r" ), 0 }, + } + ); CHECK( item_info_str( longshirt, { iteminfo_parts::ARMOR_BODYPARTS } ) == "--\n" @@ -677,7 +719,9 @@ TEST_CASE( "armor coverage, warmth, and encumbrance", "[iteminfo][armor][coverag "Layer: Normal.\n" ); // Coverage and warmth are displayed together on a single line - std::vector cov_warm_shirt = { iteminfo_parts::ARMOR_COVERAGE, iteminfo_parts::ARMOR_WARMTH }; + std::vector cov_warm_shirt = { + iteminfo_parts::ARMOR_COVERAGE, iteminfo_parts::ARMOR_WARMTH + }; REQUIRE( longshirt.get_avg_coverage() == 90 ); REQUIRE( longshirt.get_warmth() == 5 ); CHECK( item_info_str( longshirt, cov_warm_shirt ) @@ -685,43 +729,37 @@ TEST_CASE( "armor coverage, warmth, and encumbrance", "[iteminfo][armor][coverag "--\n" "Average Coverage: 90% Warmth: 5\n" ); - REQUIRE( longshirt.get_avg_encumber( get_player_character() ) == 3 ); - REQUIRE( longshirt.get_encumber( get_player_character(), bodypart_id( "torso" ) ) == 3 ); - REQUIRE( longshirt.get_encumber( get_player_character(), bodypart_id( "arm_l" ) ) == 3 ); - REQUIRE( longshirt.get_encumber( get_player_character(), bodypart_id( "arm_r" ) ) == 3 ); - REQUIRE( longshirt.get_encumber( get_player_character(), bodypart_id( "leg_l" ) ) == 0 ); - REQUIRE( longshirt.get_encumber( get_player_character(), bodypart_id( "leg_r" ) ) == 0 ); - REQUIRE( longshirt.get_encumber( get_player_character(), bodypart_id( "hand_l" ) ) == 0 ); - REQUIRE( longshirt.get_encumber( get_player_character(), bodypart_id( "hand_r" ) ) == 0 ); - REQUIRE( longshirt.get_encumber( get_player_character(), bodypart_id( "head" ) ) == 0 ); - REQUIRE( longshirt.get_encumber( get_player_character(), bodypart_id( "mouth" ) ) == 0 ); - REQUIRE( longshirt.get_encumber( get_player_character(), bodypart_id( "foot_l" ) ) == 0 ); - REQUIRE( longshirt.get_encumber( get_player_character(), bodypart_id( "foot_r" ) ) == 0 ); - - REQUIRE( longshirt.get_avg_encumber( get_player_character(), - item::encumber_flags::assume_full ) == 3 ); - REQUIRE( longshirt.get_encumber( get_player_character(), bodypart_id( "torso" ), - item::encumber_flags::assume_full ) == 3 ); - REQUIRE( longshirt.get_encumber( get_player_character(), bodypart_id( "arm_l" ), - item::encumber_flags::assume_full ) == 3 ); - REQUIRE( longshirt.get_encumber( get_player_character(), bodypart_id( "arm_r" ), - item::encumber_flags::assume_full ) == 3 ); - REQUIRE( longshirt.get_encumber( get_player_character(), bodypart_id( "leg_l" ), - item::encumber_flags::assume_full ) == 0 ); - REQUIRE( longshirt.get_encumber( get_player_character(), bodypart_id( "leg_r" ), - item::encumber_flags::assume_full ) == 0 ); - REQUIRE( longshirt.get_encumber( get_player_character(), bodypart_id( "hand_l" ), - item::encumber_flags::assume_full ) == 0 ); - REQUIRE( longshirt.get_encumber( get_player_character(), bodypart_id( "hand_r" ), - item::encumber_flags::assume_full ) == 0 ); - REQUIRE( longshirt.get_encumber( get_player_character(), bodypart_id( "head" ), - item::encumber_flags::assume_full ) == 0 ); - REQUIRE( longshirt.get_encumber( get_player_character(), bodypart_id( "mouth" ), - item::encumber_flags::assume_full ) == 0 ); - REQUIRE( longshirt.get_encumber( get_player_character(), bodypart_id( "foot_l" ), - item::encumber_flags::assume_full ) == 0 ); - REQUIRE( longshirt.get_encumber( get_player_character(), bodypart_id( "foot_r" ), - item::encumber_flags::assume_full ) == 0 ); + verify_item_encumbrance( + longshirt, item::encumber_flags::none, 3, { + { bodypart_id( "torso" ), 3 }, + { bodypart_id( "arm_l" ), 3 }, + { bodypart_id( "arm_r" ), 3 }, + { bodypart_id( "leg_l" ), 0 }, + { bodypart_id( "leg_r" ), 0 }, + { bodypart_id( "hand_l" ), 0 }, + { bodypart_id( "hand_r" ), 0 }, + { bodypart_id( "head" ), 0 }, + { bodypart_id( "mouth" ), 0 }, + { bodypart_id( "foot_l" ), 0 }, + { bodypart_id( "foot_r" ), 0 }, + } + ); + + verify_item_encumbrance( + longshirt, item::encumber_flags::assume_full, 3, { + { bodypart_id( "torso" ), 3 }, + { bodypart_id( "arm_l" ), 3 }, + { bodypart_id( "arm_r" ), 3 }, + { bodypart_id( "leg_l" ), 0 }, + { bodypart_id( "leg_r" ), 0 }, + { bodypart_id( "hand_l" ), 0 }, + { bodypart_id( "hand_r" ), 0 }, + { bodypart_id( "head" ), 0 }, + { bodypart_id( "mouth" ), 0 }, + { bodypart_id( "foot_l" ), 0 }, + { bodypart_id( "foot_r" ), 0 }, + } + ); CHECK( item_info_str( longshirt, { iteminfo_parts::ARMOR_ENCUMBRANCE } ) == "--\n" @@ -753,59 +791,56 @@ TEST_CASE( "armor coverage, warmth, and encumbrance", "[iteminfo][armor][coverag "--\n" "Average Coverage: 95% Warmth: 35\n" ); - REQUIRE( swat_armor.get_coverage( bodypart_id( "torso" ) ) == 95 ); - REQUIRE( swat_armor.get_coverage( bodypart_id( "leg_l" ) ) == 95 ); - REQUIRE( swat_armor.get_coverage( bodypart_id( "leg_r" ) ) == 95 ); - REQUIRE( swat_armor.get_coverage( bodypart_id( "arm_l" ) ) == 95 ); - REQUIRE( swat_armor.get_coverage( bodypart_id( "arm_r" ) ) == 95 ); - REQUIRE( swat_armor.get_coverage( bodypart_id( "head" ) ) == 0 ); - REQUIRE( swat_armor.get_coverage( bodypart_id( "foot_l" ) ) == 0 ); - REQUIRE( swat_armor.get_coverage( bodypart_id( "foot_r" ) ) == 0 ); - REQUIRE( swat_armor.get_coverage( bodypart_id( "eyes" ) ) == 0 ); - REQUIRE( swat_armor.get_coverage( bodypart_id( "mouth" ) ) == 0 ); - REQUIRE( swat_armor.get_coverage( bodypart_id( "hand_r" ) ) == 0 ); - REQUIRE( swat_armor.get_coverage( bodypart_id( "hand_l" ) ) == 0 ); - - REQUIRE( swat_armor.get_avg_encumber( get_player_character() ) == 12 ); - REQUIRE( swat_armor.get_encumber( get_player_character(), bodypart_id( "torso" ) ) == 12 ); - REQUIRE( swat_armor.get_encumber( get_player_character(), bodypart_id( "leg_l" ) ) == 12 ); - REQUIRE( swat_armor.get_encumber( get_player_character(), bodypart_id( "leg_r" ) ) == 12 ); - REQUIRE( swat_armor.get_encumber( get_player_character(), bodypart_id( "arm_l" ) ) == 12 ); - REQUIRE( swat_armor.get_encumber( get_player_character(), bodypart_id( "arm_r" ) ) == 12 ); - REQUIRE( swat_armor.get_encumber( get_player_character(), bodypart_id( "head" ) ) == 0 ); - REQUIRE( swat_armor.get_encumber( get_player_character(), bodypart_id( "foot_l" ) ) == 0 ); - REQUIRE( swat_armor.get_encumber( get_player_character(), bodypart_id( "foot_r" ) ) == 0 ); - REQUIRE( swat_armor.get_encumber( get_player_character(), bodypart_id( "eyes" ) ) == 0 ); - REQUIRE( swat_armor.get_encumber( get_player_character(), bodypart_id( "mouth" ) ) == 0 ); - REQUIRE( swat_armor.get_encumber( get_player_character(), bodypart_id( "hand_l" ) ) == 0 ); - REQUIRE( swat_armor.get_encumber( get_player_character(), bodypart_id( "hand_r" ) ) == 0 ); - - REQUIRE( swat_armor.get_avg_encumber( get_player_character(), - item::encumber_flags::assume_full ) == 25 ); - REQUIRE( swat_armor.get_encumber( get_player_character(), bodypart_id( "torso" ), - item::encumber_flags::assume_full ) == 25 ); - REQUIRE( swat_armor.get_encumber( get_player_character(), bodypart_id( "leg_l" ), - item::encumber_flags::assume_full ) == 25 ); - REQUIRE( swat_armor.get_encumber( get_player_character(), bodypart_id( "leg_r" ), - item::encumber_flags::assume_full ) == 25 ); - REQUIRE( swat_armor.get_encumber( get_player_character(), bodypart_id( "arm_l" ), - item::encumber_flags::assume_full ) == 25 ); - REQUIRE( swat_armor.get_encumber( get_player_character(), bodypart_id( "arm_r" ), - item::encumber_flags::assume_full ) == 25 ); - REQUIRE( swat_armor.get_encumber( get_player_character(), bodypart_id( "foot_l" ), - item::encumber_flags::assume_full ) == 0 ); - REQUIRE( swat_armor.get_encumber( get_player_character(), bodypart_id( "foot_r" ), - item::encumber_flags::assume_full ) == 0 ); - REQUIRE( swat_armor.get_encumber( get_player_character(), bodypart_id( "head" ), - item::encumber_flags::assume_full ) == 0 ); - REQUIRE( swat_armor.get_encumber( get_player_character(), bodypart_id( "eyes" ), - item::encumber_flags::assume_full ) == 0 ); - REQUIRE( swat_armor.get_encumber( get_player_character(), bodypart_id( "mouth" ), - item::encumber_flags::assume_full ) == 0 ); - REQUIRE( swat_armor.get_encumber( get_player_character(), bodypart_id( "hand_l" ), - item::encumber_flags::assume_full ) == 0 ); - REQUIRE( swat_armor.get_encumber( get_player_character(), bodypart_id( "hand_r" ), - item::encumber_flags::assume_full ) == 0 ); + verify_item_coverage( + swat_armor, { + { bodypart_id( "torso" ), 95 }, + { bodypart_id( "leg_l" ), 95 }, + { bodypart_id( "leg_r" ), 95 }, + { bodypart_id( "arm_l" ), 95 }, + { bodypart_id( "arm_r" ), 95 }, + { bodypart_id( "head" ), 0 }, + { bodypart_id( "foot_l" ), 0 }, + { bodypart_id( "foot_r" ), 0 }, + { bodypart_id( "eyes" ), 0 }, + { bodypart_id( "mouth" ), 0 }, + { bodypart_id( "hand_r" ), 0 }, + { bodypart_id( "hand_l" ), 0 }, + } + ); + + verify_item_encumbrance( + swat_armor, item::encumber_flags::none, 12, { + { bodypart_id( "torso" ), 12 }, + { bodypart_id( "leg_l" ), 12 }, + { bodypart_id( "leg_r" ), 12 }, + { bodypart_id( "arm_l" ), 12 }, + { bodypart_id( "arm_r" ), 12 }, + { bodypart_id( "head" ), 0 }, + { bodypart_id( "foot_l" ), 0 }, + { bodypart_id( "foot_r" ), 0 }, + { bodypart_id( "eyes" ), 0 }, + { bodypart_id( "mouth" ), 0 }, + { bodypart_id( "hand_l" ), 0 }, + { bodypart_id( "hand_r" ), 0 }, + } + ); + + verify_item_encumbrance( + swat_armor, item::encumber_flags::assume_full, 25, { + { bodypart_id( "torso" ), 25 }, + { bodypart_id( "leg_l" ), 25 }, + { bodypart_id( "leg_r" ), 25 }, + { bodypart_id( "arm_l" ), 25 }, + { bodypart_id( "arm_r" ), 25 }, + { bodypart_id( "foot_l" ), 0 }, + { bodypart_id( "foot_r" ), 0 }, + { bodypart_id( "head" ), 0 }, + { bodypart_id( "eyes" ), 0 }, + { bodypart_id( "mouth" ), 0 }, + { bodypart_id( "hand_l" ), 0 }, + { bodypart_id( "hand_r" ), 0 }, + } + ); CHECK( item_info_str( swat_armor, { iteminfo_parts::ARMOR_ENCUMBRANCE } ) == "--\n" @@ -842,55 +877,56 @@ TEST_CASE( "armor coverage, warmth, and encumbrance", "[iteminfo][armor][coverag "Average Coverage: 95% Warmth: 70\n" ); REQUIRE( faux_fur_pants.get_avg_coverage() == 95 ); - REQUIRE( faux_fur_pants.get_coverage( bodypart_id( "leg_l" ) ) == 95 ); - REQUIRE( faux_fur_pants.get_coverage( bodypart_id( "leg_r" ) ) == 95 ); - REQUIRE( faux_fur_pants.get_coverage( bodypart_id( "arm_l" ) ) == 0 ); - REQUIRE( faux_fur_pants.get_coverage( bodypart_id( "arm_r" ) ) == 0 ); - REQUIRE( faux_fur_pants.get_coverage( bodypart_id( "foot_r" ) ) == 0 ); - REQUIRE( faux_fur_pants.get_coverage( bodypart_id( "foot_l" ) ) == 0 ); - REQUIRE( faux_fur_pants.get_coverage( bodypart_id( "head" ) ) == 0 ); - REQUIRE( faux_fur_pants.get_coverage( bodypart_id( "eyes" ) ) == 0 ); - REQUIRE( faux_fur_pants.get_coverage( bodypart_id( "mouth" ) ) == 0 ); - REQUIRE( faux_fur_pants.get_coverage( bodypart_id( "hand_l" ) ) == 0 ); - REQUIRE( faux_fur_pants.get_coverage( bodypart_id( "hand_r" ) ) == 0 ); - - REQUIRE( faux_fur_pants.get_avg_encumber( get_player_character() ) == 16 ); - REQUIRE( faux_fur_pants.get_encumber( get_player_character(), bodypart_id( "leg_l" ) ) == 16 ); - REQUIRE( faux_fur_pants.get_encumber( get_player_character(), bodypart_id( "leg_r" ) ) == 16 ); - REQUIRE( faux_fur_pants.get_encumber( get_player_character(), bodypart_id( "arm_l" ) ) == 0 ); - REQUIRE( faux_fur_pants.get_encumber( get_player_character(), bodypart_id( "arm_r" ) ) == 0 ); - REQUIRE( faux_fur_pants.get_encumber( get_player_character(), bodypart_id( "foot_r" ) ) == 0 ); - REQUIRE( faux_fur_pants.get_encumber( get_player_character(), bodypart_id( "foot_l" ) ) == 0 ); - REQUIRE( faux_fur_pants.get_encumber( get_player_character(), bodypart_id( "head" ) ) == 0 ); - REQUIRE( faux_fur_pants.get_encumber( get_player_character(), bodypart_id( "eyes" ) ) == 0 ); - REQUIRE( faux_fur_pants.get_encumber( get_player_character(), bodypart_id( "mouth" ) ) == 0 ); - REQUIRE( faux_fur_pants.get_encumber( get_player_character(), bodypart_id( "hand_l" ) ) == 0 ); - REQUIRE( faux_fur_pants.get_encumber( get_player_character(), bodypart_id( "hand_r" ) ) == 0 ); - - REQUIRE( faux_fur_pants.get_avg_encumber( get_player_character(), - item::encumber_flags::assume_full ) == 20 ); - REQUIRE( faux_fur_pants.get_encumber( get_player_character(), bodypart_id( "leg_l" ), - item::encumber_flags::assume_full ) == 20 ); - REQUIRE( faux_fur_pants.get_encumber( get_player_character(), bodypart_id( "leg_r" ), - item::encumber_flags::assume_full ) == 20 ); - REQUIRE( faux_fur_pants.get_encumber( get_player_character(), bodypart_id( "arm_l" ), - item::encumber_flags::assume_full ) == 0 ); - REQUIRE( faux_fur_pants.get_encumber( get_player_character(), bodypart_id( "arm_r" ), - item::encumber_flags::assume_full ) == 0 ); - REQUIRE( faux_fur_pants.get_encumber( get_player_character(), bodypart_id( "foot_r" ), - item::encumber_flags::assume_full ) == 0 ); - REQUIRE( faux_fur_pants.get_encumber( get_player_character(), bodypart_id( "foot_l" ), - item::encumber_flags::assume_full ) == 0 ); - REQUIRE( faux_fur_pants.get_encumber( get_player_character(), bodypart_id( "head" ), - item::encumber_flags::assume_full ) == 0 ); - REQUIRE( faux_fur_pants.get_encumber( get_player_character(), bodypart_id( "eyes" ), - item::encumber_flags::assume_full ) == 0 ); - REQUIRE( faux_fur_pants.get_encumber( get_player_character(), bodypart_id( "mouth" ), - item::encumber_flags::assume_full ) == 0 ); - REQUIRE( faux_fur_pants.get_encumber( get_player_character(), bodypart_id( "hand_l" ), - item::encumber_flags::assume_full ) == 0 ); - REQUIRE( faux_fur_pants.get_encumber( get_player_character(), bodypart_id( "hand_r" ), - item::encumber_flags::assume_full ) == 0 ); + verify_item_coverage( + faux_fur_pants, { + { bodypart_id( "torso" ), 0 }, + { bodypart_id( "leg_l" ), 95 }, + { bodypart_id( "leg_r" ), 95 }, + { bodypart_id( "arm_l" ), 0 }, + { bodypart_id( "arm_r" ), 0 }, + { bodypart_id( "foot_r" ), 0 }, + { bodypart_id( "foot_l" ), 0 }, + { bodypart_id( "head" ), 0 }, + { bodypart_id( "eyes" ), 0 }, + { bodypart_id( "mouth" ), 0 }, + { bodypart_id( "hand_l" ), 0 }, + { bodypart_id( "hand_r" ), 0 }, + } + ); + + verify_item_encumbrance( + faux_fur_pants, item::encumber_flags::none, 16, { + { bodypart_id( "torso" ), 0 }, + { bodypart_id( "leg_l" ), 16 }, + { bodypart_id( "leg_r" ), 16 }, + { bodypart_id( "arm_l" ), 0 }, + { bodypart_id( "arm_r" ), 0 }, + { bodypart_id( "foot_r" ), 0 }, + { bodypart_id( "foot_l" ), 0 }, + { bodypart_id( "head" ), 0 }, + { bodypart_id( "eyes" ), 0 }, + { bodypart_id( "mouth" ), 0 }, + { bodypart_id( "hand_l" ), 0 }, + { bodypart_id( "hand_r" ), 0 }, + } + ); + + verify_item_encumbrance( + faux_fur_pants, item::encumber_flags::assume_full, 20, { + { bodypart_id( "torso" ), 0 }, + { bodypart_id( "leg_l" ), 20 }, + { bodypart_id( "leg_r" ), 20 }, + { bodypart_id( "arm_l" ), 0 }, + { bodypart_id( "arm_r" ), 0 }, + { bodypart_id( "foot_r" ), 0 }, + { bodypart_id( "foot_l" ), 0 }, + { bodypart_id( "head" ), 0 }, + { bodypart_id( "eyes" ), 0 }, + { bodypart_id( "mouth" ), 0 }, + { bodypart_id( "hand_l" ), 0 }, + { bodypart_id( "hand_r" ), 0 }, + } + ); item faux_fur_suit( "test_portion_faux_fur_pants_suit" ); REQUIRE( faux_fur_suit.get_covered_body_parts().any() ); @@ -907,7 +943,9 @@ TEST_CASE( "armor coverage, warmth, and encumbrance", "[iteminfo][armor][coverag "--\n" "Layer: Normal.\n" ); - std::vector cov_warm_suit = { iteminfo_parts::ARMOR_COVERAGE, iteminfo_parts::ARMOR_WARMTH }; + std::vector cov_warm_suit = { + iteminfo_parts::ARMOR_COVERAGE, iteminfo_parts::ARMOR_WARMTH + }; REQUIRE( faux_fur_suit.get_avg_coverage() == 75 ); REQUIRE( faux_fur_suit.get_warmth() == 5 ); CHECK( item_info_str( faux_fur_suit, cov_warm_suit ) @@ -916,59 +954,56 @@ TEST_CASE( "armor coverage, warmth, and encumbrance", "[iteminfo][armor][coverag "Average Coverage: 75% Warmth: 5\n" ); REQUIRE( faux_fur_suit.get_avg_coverage() == 75 ); - REQUIRE( faux_fur_suit.get_coverage( bodypart_id( "torso" ) ) == 100 ); - REQUIRE( faux_fur_suit.get_coverage( bodypart_id( "leg_l" ) ) == 50 ); - REQUIRE( faux_fur_suit.get_coverage( bodypart_id( "leg_r" ) ) == 100 ); - REQUIRE( faux_fur_suit.get_coverage( bodypart_id( "arm_l" ) ) == 50 ); - REQUIRE( faux_fur_suit.get_coverage( bodypart_id( "arm_r" ) ) == 100 ); - REQUIRE( faux_fur_suit.get_coverage( bodypart_id( "head" ) ) == 50 ); - REQUIRE( faux_fur_suit.get_coverage( bodypart_id( "eyes" ) ) == 0 ); - REQUIRE( faux_fur_suit.get_coverage( bodypart_id( "mouth" ) ) == 0 ); - REQUIRE( faux_fur_suit.get_coverage( bodypart_id( "hand_l" ) ) == 0 ); - REQUIRE( faux_fur_suit.get_coverage( bodypart_id( "hand_r" ) ) == 0 ); - REQUIRE( faux_fur_suit.get_coverage( bodypart_id( "foot_l" ) ) == 0 ); - REQUIRE( faux_fur_suit.get_coverage( bodypart_id( "foot_r" ) ) == 0 ); - - REQUIRE( faux_fur_suit.get_avg_encumber( get_player_character() ) == 7 ); - REQUIRE( faux_fur_suit.get_encumber( get_player_character(), bodypart_id( "torso" ) ) == 10 ); - REQUIRE( faux_fur_suit.get_encumber( get_player_character(), bodypart_id( "leg_l" ) ) == 5 ); - REQUIRE( faux_fur_suit.get_encumber( get_player_character(), bodypart_id( "leg_r" ) ) == 10 ); - REQUIRE( faux_fur_suit.get_encumber( get_player_character(), bodypart_id( "arm_l" ) ) == 5 ); - REQUIRE( faux_fur_suit.get_encumber( get_player_character(), bodypart_id( "arm_r" ) ) == 10 ); - REQUIRE( faux_fur_suit.get_encumber( get_player_character(), bodypart_id( "head" ) ) == 5 ); - REQUIRE( faux_fur_suit.get_encumber( get_player_character(), bodypart_id( "eyes" ) ) == 0 ); - REQUIRE( faux_fur_suit.get_encumber( get_player_character(), bodypart_id( "mouth" ) ) == 0 ); - REQUIRE( faux_fur_suit.get_encumber( get_player_character(), bodypart_id( "foot_l" ) ) == 0 ); - REQUIRE( faux_fur_suit.get_encumber( get_player_character(), bodypart_id( "foot_r" ) ) == 0 ); - REQUIRE( faux_fur_suit.get_encumber( get_player_character(), bodypart_id( "hand_r" ) ) == 0 ); - REQUIRE( faux_fur_suit.get_encumber( get_player_character(), bodypart_id( "hand_r" ) ) == 0 ); - - REQUIRE( faux_fur_suit.get_avg_encumber( get_player_character(), - item::encumber_flags::assume_full ) == 17 ); - REQUIRE( faux_fur_suit.get_encumber( get_player_character(), bodypart_id( "torso" ), - item::encumber_flags::assume_full ) == 25 ); - REQUIRE( faux_fur_suit.get_encumber( get_player_character(), bodypart_id( "leg_l" ), - item::encumber_flags::assume_full ) == 9 ); - REQUIRE( faux_fur_suit.get_encumber( get_player_character(), bodypart_id( "leg_r" ), - item::encumber_flags::assume_full ) == 25 ); - REQUIRE( faux_fur_suit.get_encumber( get_player_character(), bodypart_id( "arm_l" ), - item::encumber_flags::assume_full ) == 9 ); - REQUIRE( faux_fur_suit.get_encumber( get_player_character(), bodypart_id( "arm_r" ), - item::encumber_flags::assume_full ) == 25 ); - REQUIRE( faux_fur_suit.get_encumber( get_player_character(), bodypart_id( "head" ), - item::encumber_flags::assume_full ) == 9 ); - REQUIRE( faux_fur_suit.get_encumber( get_player_character(), bodypart_id( "eyes" ), - item::encumber_flags::assume_full ) == 0 ); - REQUIRE( faux_fur_suit.get_encumber( get_player_character(), bodypart_id( "mouth" ), - item::encumber_flags::assume_full ) == 0 ); - REQUIRE( faux_fur_suit.get_encumber( get_player_character(), bodypart_id( "hand_l" ), - item::encumber_flags::assume_full ) == 0 ); - REQUIRE( faux_fur_suit.get_encumber( get_player_character(), bodypart_id( "hand_r" ), - item::encumber_flags::assume_full ) == 0 ); - REQUIRE( faux_fur_suit.get_encumber( get_player_character(), bodypart_id( "foot_l" ), - item::encumber_flags::assume_full ) == 0 ); - REQUIRE( faux_fur_suit.get_encumber( get_player_character(), bodypart_id( "foot_r" ), - item::encumber_flags::assume_full ) == 0 ); + verify_item_coverage( + faux_fur_suit, { + { bodypart_id( "torso" ), 100 }, + { bodypart_id( "leg_l" ), 50 }, + { bodypart_id( "leg_r" ), 100 }, + { bodypart_id( "arm_l" ), 50 }, + { bodypart_id( "arm_r" ), 100 }, + { bodypart_id( "head" ), 50 }, + { bodypart_id( "eyes" ), 0 }, + { bodypart_id( "mouth" ), 0 }, + { bodypart_id( "hand_l" ), 0 }, + { bodypart_id( "hand_r" ), 0 }, + { bodypart_id( "foot_l" ), 0 }, + { bodypart_id( "foot_r" ), 0 }, + } + ); + + verify_item_encumbrance( + faux_fur_suit, item::encumber_flags::none, 7, { + { bodypart_id( "torso" ), 10 }, + { bodypart_id( "leg_l" ), 5 }, + { bodypart_id( "leg_r" ), 10 }, + { bodypart_id( "arm_l" ), 5 }, + { bodypart_id( "arm_r" ), 10 }, + { bodypart_id( "head" ), 5 }, + { bodypart_id( "eyes" ), 0 }, + { bodypart_id( "mouth" ), 0 }, + { bodypart_id( "foot_l" ), 0 }, + { bodypart_id( "foot_r" ), 0 }, + { bodypart_id( "hand_l" ), 0 }, + { bodypart_id( "hand_r" ), 0 }, + } + ); + + verify_item_encumbrance( + faux_fur_suit, item::encumber_flags::assume_full, 17, { + { bodypart_id( "torso" ), 25 }, + { bodypart_id( "leg_l" ), 9 }, + { bodypart_id( "leg_r" ), 25 }, + { bodypart_id( "arm_l" ), 9 }, + { bodypart_id( "arm_r" ), 25 }, + { bodypart_id( "head" ), 9 }, + { bodypart_id( "eyes" ), 0 }, + { bodypart_id( "mouth" ), 0 }, + { bodypart_id( "hand_l" ), 0 }, + { bodypart_id( "hand_r" ), 0 }, + { bodypart_id( "foot_l" ), 0 }, + { bodypart_id( "foot_r" ), 0 }, + } + ); CHECK( item_info_str( faux_fur_suit, { iteminfo_parts::ARMOR_ENCUMBRANCE } ) == "--\n" From d8c7083223ecb9b035508b688ae44ce2819b0b42 Mon Sep 17 00:00:00 2001 From: John Bytheway Date: Thu, 8 Apr 2021 11:06:26 -0400 Subject: [PATCH 136/453] Fix compilation of magic.cpp (#48430) This got broken by #47946 because exp_for_level was made a member function but one call to it was not updated. Fix that. --- src/magic.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/magic.cpp b/src/magic.cpp index 903923f87f284..c750b9d8a9a8a 100644 --- a/src/magic.cpp +++ b/src/magic.cpp @@ -2388,7 +2388,7 @@ spell fake_spell::get_spell( int min_level_override ) const debugmsg( "ERROR: fake spell %s has higher min_level than max_level", id.c_str() ); return sp; } - sp.set_exp( exp_for_level( level_of_spell ) ); + sp.set_exp( sp.exp_for_level( level_of_spell ) ); return sp; } From fcd93989ec87fc876899b938a0b1b3e0738fade8 Mon Sep 17 00:00:00 2001 From: John Bytheway Date: Fri, 9 Apr 2021 18:08:21 -0400 Subject: [PATCH 137/453] Enable clang-tidy readability-function-size (#48407) * Enable readability-function-size Suppress the remaining cases for functions I don't care to refactor. * Typo in iteminfo_test --- .clang-tidy | 1 - src/mapgen.cpp | 1 + tests/iteminfo_test.cpp | 2 +- tests/line_test.cpp | 2 +- tests/reload_magazine_test.cpp | 1 + tests/visitable_remove_test.cpp | 1 + 6 files changed, 5 insertions(+), 3 deletions(-) diff --git a/.clang-tidy b/.clang-tidy index 5aad02e467092..2b0d987887aec 100644 --- a/.clang-tidy +++ b/.clang-tidy @@ -44,7 +44,6 @@ readability-*,\ -performance-unnecessary-value-param,\ -readability-braces-around-statements,\ -readability-else-after-return,\ --readability-function-size,\ -readability-implicit-bool-conversion,\ -readability-isolate-declaration,\ -readability-magic-numbers,\ diff --git a/src/mapgen.cpp b/src/mapgen.cpp index 664aada2e175b..dc0d5a664d435 100644 --- a/src/mapgen.cpp +++ b/src/mapgen.cpp @@ -3016,6 +3016,7 @@ void map::draw_map( mapgendata &dat ) static const int SOUTH_EDGE = 2 * SEEY - 1; static const int EAST_EDGE = 2 * SEEX - 1; +// NOLINTNEXTLINE(readability-function-size) void map::draw_lab( mapgendata &dat ) { const oter_id &terrain_type = dat.terrain_type(); diff --git a/tests/iteminfo_test.cpp b/tests/iteminfo_test.cpp index 7cb57da3c2fe9..184665b7db455 100644 --- a/tests/iteminfo_test.cpp +++ b/tests/iteminfo_test.cpp @@ -2686,7 +2686,7 @@ TEST_CASE( "item debug info", "[iteminfo][debug][!mayfail][.]" ) nuts.debug_info( info_vec, &debug_query, 1, true ); // FIXME: "last rot" and "last temp" are expected to be 0, but may have values (ex. 43200) - // Neex to figure out what processing to do before this check to make them predictable + // Need to figure out what processing to do before this check to make them predictable CHECK( format_item_info( info_vec, {} ) == "age (hours): 8\n" "charges: 4\n" diff --git a/tests/line_test.cpp b/tests/line_test.cpp index 742eee7936458..c4a34d5fb8822 100644 --- a/tests/line_test.cpp +++ b/tests/line_test.cpp @@ -131,9 +131,9 @@ TEST_CASE( "test_normalized_angle", "[line]" ) CHECK( get_normalized_angle( point_zero, {-10, -10} ) == Approx( 1.0 ) ); } +// NOLINTNEXTLINE(readability-function-size) TEST_CASE( "Test bounds for mapping x/y/z/ offsets to direction enum", "[line]" ) { - // Test the unit cube, which are the only values this function is valid for. REQUIRE( make_xyz_unit( tripoint( -1, -1, 1 ) ) == direction::ABOVENORTHWEST ); REQUIRE( make_xyz_unit( tripoint_north_west ) == direction::NORTHWEST ); diff --git a/tests/reload_magazine_test.cpp b/tests/reload_magazine_test.cpp index a598812d2397f..fa929364d170a 100644 --- a/tests/reload_magazine_test.cpp +++ b/tests/reload_magazine_test.cpp @@ -17,6 +17,7 @@ struct itype; +// NOLINTNEXTLINE(readability-function-size) TEST_CASE( "reload_magazine", "[magazine] [visitable] [item] [item_location]" ) { const itype_id gun_id( "nato_assault_rifle" ); diff --git a/tests/visitable_remove_test.cpp b/tests/visitable_remove_test.cpp index b8eae0f871eda..94ae2875ba185 100644 --- a/tests/visitable_remove_test.cpp +++ b/tests/visitable_remove_test.cpp @@ -37,6 +37,7 @@ static int count_items( const T &src, const itype_id &id ) return n; } +// NOLINTNEXTLINE(readability-function-size) TEST_CASE( "visitable_remove", "[visitable]" ) { const itype_id liquid_id( "water" ); From 6a35324717b618ad4f92c725c3646973614f0ac1 Mon Sep 17 00:00:00 2001 From: John Candlebury Date: Fri, 9 Apr 2021 16:09:33 -0600 Subject: [PATCH 138/453] Aftershock: Cold Suits (#48428) --- .../itemgroups/clothing/winter_outfits.json | 37 +++++ .../Aftershock/items/armor/winter_masks.json | 127 ++++++++++++++++++ .../Aftershock/items/armor/winter_suits.json | 126 +++++++++++++++++ .../maps/mapgen/astrobiology_lab.json | 6 +- .../formless_ruins_dynamic.json | 7 + data/mods/Aftershock/suit_operating_time.md | 106 +++++++++++++++ 6 files changed, 408 insertions(+), 1 deletion(-) create mode 100644 data/mods/Aftershock/itemgroups/clothing/winter_outfits.json create mode 100644 data/mods/Aftershock/items/armor/winter_masks.json create mode 100644 data/mods/Aftershock/items/armor/winter_suits.json create mode 100644 data/mods/Aftershock/suit_operating_time.md diff --git a/data/mods/Aftershock/itemgroups/clothing/winter_outfits.json b/data/mods/Aftershock/itemgroups/clothing/winter_outfits.json new file mode 100644 index 0000000000000..14dd3ca958376 --- /dev/null +++ b/data/mods/Aftershock/itemgroups/clothing/winter_outfits.json @@ -0,0 +1,37 @@ +[ + { + "//": "A group for any advanced civilian piece of clothing", + "id": "afs_wintersuit_civilian_advanced", + "type": "item_group", + "subtype": "distribution", + "items": [ { "group": "afs_wintersuit_science_advanced", "prob": 2 }, { "group": "afs_wintersuit_generic_advanced", "prob": 2 } ] + }, + { + "//": "A group for any generic-flavour advanced civilian piece of clothing", + "id": "afs_wintersuit_generic_advanced", + "type": "item_group", + "subtype": "distribution", + "items": [ { "group": "afs_frontier_cryo_g", "prob": 2 } ] + }, + { + "//": "A group for any science-flavour advanced civilian piece of clothing", + "id": "afs_wintersuit_science_advanced", + "type": "item_group", + "subtype": "distribution", + "items": [ { "group": "afs_magellan_g", "prob": 2 } ] + }, + { + "id": "afs_frontier_cryo_g", + "type": "item_group", + "//": "The matching frontier-cryosuit set. Includes suit, mask and possible future accessories", + "subtype": "collection", + "entries": [ { "item": "afs_frontier_cryo" }, { "item": "afs_frontier_cryomask", "prob": 90 } ] + }, + { + "id": "afs_magellan_g", + "type": "item_group", + "//": "The matching Magellan Exosuit set. Includes suit, mask and possible future accessories", + "subtype": "collection", + "entries": [ { "item": "afs_magellan_suit" }, { "item": "afs_magellan_suit_helmet", "prob": 90 } ] + } +] diff --git a/data/mods/Aftershock/items/armor/winter_masks.json b/data/mods/Aftershock/items/armor/winter_masks.json new file mode 100644 index 0000000000000..a10b724f8639f --- /dev/null +++ b/data/mods/Aftershock/items/armor/winter_masks.json @@ -0,0 +1,127 @@ +[ + { + "id": "afs_magellan_suit_helmet", + "repairs_like": "afs_magellan_suit", + "type": "TOOL_ARMOR", + "category": "armor", + "looks_like": "helmet_motor", + "name": { "str": "Magellan helmet CA." }, + "description": "The high quality helmet of a Magellan exosuit, adapted to handle the freezing but breathable air of Salus IV. In addition to its life support functionality, it features a minor augmented reality UI overlay and a retractable gold-plated visor to protect against glare and UV light. Although not armored as such, it's strong enough to handle minor blunt impacts.", + "weight": "2500 g", + "volume": "2250 ml", + "price": "750 USD", + "to_hit": -1, + "bashing": 7, + "material": [ "plastic", "nomex" ], + "symbol": "[", + "color": "dark_gray", + "ammo": "battery", + "charges_per_use": 1, + "use_action": { + "type": "transform", + "msg": "You activate your %s.", + "target": "afs_magellan_suit_helmet_on", + "active": true, + "need_charges": 1, + "need_charges_msg": "The %s's batteries are dead." + }, + "armor_portion_data": [ + { "covers": [ "head" ], "coverage": 100, "encumbrance": 25 }, + { "covers": [ "eyes" ], "coverage": 100, "encumbrance": 5 }, + { "covers": [ "mouth" ], "coverage": 100, "encumbrance": 15 } + ], + "pocket_data": [ { "pocket_type": "MAGAZINE", "rigid": true, "ammo_restriction": { "battery": 1000 } } ], + "warmth": 10, + "material_thickness": 6, + "environmental_protection": 1, + "flags": [ + "VARSIZE", + "WATERPROOF", + "RAINPROOF", + "STURDY", + "SUN_GLASSES", + "RAD_RESIST", + "OUTER", + "SWIM_GOGGLES", + "RECHARGE", + "NO_RELOAD", + "NO_UNLOAD" + ] + }, + { + "id": "afs_magellan_suit_helmet_on", + "copy-from": "afs_magellan_suit_helmet", + "repairs_like": "afs_magellan_suit", + "type": "TOOL_ARMOR", + "name": { "str": "Magellan helmet CA. (on)", "str_pl": "Magellan helmets CA. (on)" }, + "looks_like": "helmet_motor", + "description": "The temperature control units and augmented reality overlays of this high-tech garment are currently active, and continuously draining battery power. Use it to turn them off.", + "power_draw": 8170, + "warmth": 150, + "revert_to": "afs_magellan_suit_helmet", + "use_action": { "type": "transform", "menu_text": "Turn off", "msg": "Your %s deactivates.", "target": "afs_magellan_suit_helmet" }, + "extend": { + "flags": [ "CLIMATE_CONTROL", "GAS_PROOF", "WATCH", "ALARMCLOCK", "THERMOMETER", "HYGROMETER", "PARTIAL_DEAF", "TRADER_AVOID" ] + }, + "environmental_protection": 15 + }, + { + "id": "afs_frontier_cryomask", + "repairs_like": "nomex_hood", + "type": "TOOL_ARMOR", + "category": "armor", + "looks_like": "helmet_motor", + "name": { "str": "frontier cryomask" }, + "description": "A common, industrially printed respirator cleverly retrofitted into a wearable air heater. While it adequately protects against the cold, most of its original functions have been discarded and it offers no noticeable protection against noxious fumes or other environmental hazards.", + "weight": "2500 g", + "volume": "2250 ml", + "price": "750 USD", + "to_hit": -1, + "bashing": 7, + "material": [ "plastic", "nomex" ], + "symbol": "[", + "color": "dark_gray", + "charges_per_use": 1, + "ammo": "battery", + "use_action": { + "type": "transform", + "msg": "You activate your %s.", + "target": "afs_frontier_cryomask_on", + "active": true, + "need_charges": 1, + "need_charges_msg": "The %s's batteries are dead." + }, + "armor_portion_data": [ + { "covers": [ "eyes" ], "coverage": 100, "encumbrance": 15 }, + { "covers": [ "mouth" ], "coverage": 100, "encumbrance": 20 } + ], + "pocket_data": [ + { + "pocket_type": "MAGAZINE_WELL", + "holster": true, + "rigid": true, + "max_contains_volume": "20 L", + "max_contains_weight": "20 kg", + "item_restriction": [ "medium_battery_cell", "medium_plus_battery_cell", "medium_atomic_battery_cell", "medium_disposable_cell" ] + } + ], + "warmth": 5, + "material_thickness": 2, + "environmental_protection": 2, + "flags": [ "VARSIZE", "WATERPROOF", "RAINPROOF", "STURDY", "SUN_GLASSES", "OUTER" ] + }, + { + "id": "afs_frontier_cryomask_on", + "copy-from": "afs_frontier_cryomask", + "repairs_like": "afs_frontier_cryomask", + "type": "TOOL_ARMOR", + "name": { "str": "frontier cryomask (on)", "str_pl": "frontier cryomasks (on)" }, + "looks_like": "helmet_motor", + "description": "The heater of this high-tech garment is currently active, and continuously draining battery power. Use it to turn the heat off.", + "power_draw": 6944, + "warmth": 150, + "revert_to": "afs_frontier_cryomask", + "use_action": { "type": "transform", "menu_text": "Turn off", "msg": "Your %s deactivates.", "target": "afs_frontier_cryomask" }, + "extend": { "flags": [ "CLIMATE_CONTROL" ] } + } +] diff --git a/data/mods/Aftershock/items/armor/winter_suits.json b/data/mods/Aftershock/items/armor/winter_suits.json new file mode 100644 index 0000000000000..d8a607ba579dc --- /dev/null +++ b/data/mods/Aftershock/items/armor/winter_suits.json @@ -0,0 +1,126 @@ +[ + { + "id": "afs_magellan_suit", + "type": "TOOL_ARMOR", + "category": "armor", + "name": { "str": "Magellan exosuit" }, + "description": "A high-quality, civilian grade EVA suit often employed by well-established frontier research and exploration associations. Designed to support the exploration of challenging terrain, it offers respectable protection against common environmental hazards like extreme temperatures, inhospitable atmospheres, and light radiation. It leaves arms and hands relatively unencumbered to aid the manipulation of scientific instruments.\n\nAn integral battery allows the suit to operate for up to 34 hours, but complicates field recharging.", + "weight": "7800 g", + "volume": "14 L", + "price": "4 kUSD", + "material": [ "nomex", "steel" ], + "symbol": "[", + "looks_like": "robofac_enviro_suit", + "color": "light_gray", + "ammo": "battery", + "charges_per_use": 1, + "use_action": { + "type": "transform", + "msg": "You activate your %s.", + "target": "afs_magellan_suit_on", + "active": true, + "need_charges": 1, + "need_charges_msg": "The %s's batteries are dead." + }, + "armor_portion_data": [ + { "covers": [ "torso" ], "coverage": 100, "encumbrance": 25 }, + { "covers": [ "leg_l", "leg_r" ], "coverage": 100, "encumbrance": 25 }, + { "covers": [ "arm_l", "arm_r" ], "coverage": 100, "encumbrance": 15 }, + { "covers": [ "hand_l", "hand_r" ], "coverage": 100, "encumbrance": 10 }, + { "covers": [ "foot_l", "foot_r" ], "coverage": 100, "encumbrance": 15 } + ], + "pocket_data": [ { "pocket_type": "MAGAZINE", "rigid": true, "ammo_restriction": { "battery": 1000 } } ], + "warmth": 20, + "material_thickness": 2, + "valid_mods": [ "steel_padded" ], + "environmental_protection": 15, + "flags": [ + "VARSIZE", + "WATERPROOF", + "GAS_PROOF", + "POCKETS", + "RAINPROOF", + "STURDY", + "RAD_RESIST", + "RECHARGE", + "OUTER", + "NO_RELOAD", + "NO_UNLOAD" + ] + }, + { + "id": "afs_magellan_suit_on", + "copy-from": "afs_magellan_suit", + "repairs_like": "afs_magellan_suit", + "type": "TOOL_ARMOR", + "name": { "str": "Magellan exosuit (on)", "str_pl": "Magellan exosuits (on)" }, + "looks_like": "afs_cryopod_bodyglove", + "description": "The temperature control units of this high-tech garment are currently active, and continuously draining battery power. Use it to turn them off.", + "power_draw": 8170, + "warmth": 150, + "revert_to": "afs_magellan_suit", + "use_action": { "type": "transform", "menu_text": "Turn off", "msg": "Your %s deactivates.", "target": "afs_magellan_suit" }, + "extend": { "flags": [ "CLIMATE_CONTROL" ] } + }, + { + "id": "afs_frontier_cryo", + "type": "TOOL_ARMOR", + "category": "armor", + "name": { "str": "frontier cryo suit" }, + "description": "A sturdy suit meant to protect against the freezing cold, made from a pair of jumpsuits that have been woven around a heavy insulation layer and crisscrossed with the thermal tubing of a heat regulation unit. The thick insulation allows the suit to function with unrivaled efficiency, but also makes all types of movement difficult.", + "weight": "7800 g", + "volume": "14 L", + "price": "75 USD", + "material": [ "cotton", "plastic" ], + "symbol": "[", + "looks_like": "robofac_enviro_suit", + "color": "cyan", + "ammo": "battery", + "charges_per_use": 1, + "use_action": { + "type": "transform", + "msg": "You activate your %s.", + "target": "afs_frontier_cryo_on", + "active": true, + "need_charges": 1, + "need_charges_msg": "The %s's batteries are dead." + }, + "armor_portion_data": [ + { "covers": [ "head" ], "coverage": 100, "encumbrance": 5 }, + { "covers": [ "torso" ], "coverage": 100, "encumbrance": 35 }, + { "covers": [ "leg_l", "leg_r" ], "coverage": 100, "encumbrance": 25 }, + { "covers": [ "arm_l", "arm_r" ], "coverage": 100, "encumbrance": 25 }, + { "covers": [ "hand_l", "hand_r" ], "coverage": 100, "encumbrance": 25 }, + { "covers": [ "foot_l", "foot_r" ], "coverage": 100, "encumbrance": 15 } + ], + "pocket_data": [ + { + "pocket_type": "MAGAZINE_WELL", + "holster": true, + "rigid": true, + "max_contains_volume": "20 L", + "max_contains_weight": "20 kg", + "item_restriction": [ "medium_battery_cell", "medium_plus_battery_cell", "medium_atomic_battery_cell", "medium_disposable_cell" ] + } + ], + "warmth": 20, + "material_thickness": 4, + "valid_mods": [ "steel_padded" ], + "environmental_protection": 2, + "flags": [ "VARSIZE", "WATERPROOF", "POCKETS", "HELMET_COMPAT", "RAINPROOF", "STURDY", "OUTER" ] + }, + { + "id": "afs_frontier_cryo_on", + "copy-from": "afs_frontier_cryo", + "repairs_like": "afs_frontier_cryo", + "type": "TOOL_ARMOR", + "name": { "str": "frontier cryo suit (on)", "str_pl": "frontier cryo suits (on)" }, + "looks_like": "afs_cryopod_bodyglove", + "description": "The temperature control units of this high-tech garment are currently active, and continuously draining battery power. Use it to turn them off.", + "power_draw": 6944, + "warmth": 150, + "revert_to": "afs_frontier_cryo", + "use_action": { "type": "transform", "menu_text": "Turn off", "msg": "Your %s deactivates.", "target": "afs_frontier_cryo" }, + "extend": { "flags": [ "CLIMATE_CONTROL" ] } + } +] diff --git a/data/mods/Aftershock/maps/mapgen/astrobiology_lab.json b/data/mods/Aftershock/maps/mapgen/astrobiology_lab.json index 67d82df8cbc75..9beaf91e7e9fb 100644 --- a/data/mods/Aftershock/maps/mapgen/astrobiology_lab.json +++ b/data/mods/Aftershock/maps/mapgen/astrobiology_lab.json @@ -63,7 +63,11 @@ { "item": "supplies_reagents_lab", "chance": 70, "repeat": [ 2, 5 ] }, { "item": "supplies_xenoreagents_lab", "chance": 70, "repeat": [ 2, 5 ] } ], - "R": [ { "item": "decontamination_room", "chance": 60 }, { "item": "clothing_work_set", "chance": 30 } ], + "R": [ + { "item": "decontamination_room", "chance": 60 }, + { "item": "clothing_work_set", "chance": 30 }, + { "item": "afs_wintersuit_science_advanced", "chance": 30 } + ], "t": [ { "item": "office_paper", "chance": 60 }, { "item": "tools_science", "chance": 10, "repeat": [ 1, 2 ] } ] }, "item": { "c": { "item": "recipe_lichenlog", "chance": 6 } }, diff --git a/data/mods/Aftershock/maps/mapgen/formless_ruins/formless_ruins_dynamic.json b/data/mods/Aftershock/maps/mapgen/formless_ruins/formless_ruins_dynamic.json index 97449fe566d9a..7f6327ca83929 100644 --- a/data/mods/Aftershock/maps/mapgen/formless_ruins/formless_ruins_dynamic.json +++ b/data/mods/Aftershock/maps/mapgen/formless_ruins/formless_ruins_dynamic.json @@ -8,6 +8,12 @@ { "group": "afs_basic_material_scrapgroup", "prob": 20 } ] }, + { + "id": "afs_formless_ruins_random_suit", + "type": "item_group", + "subtype": "distribution", + "entries": [ { "group": "afs_wintersuit_civilian_advanced", "prob": 50 } ] + }, { "type": "mapgen", "method": "json", @@ -724,6 +730,7 @@ "///.. // " ], "terrain": { "C": "t_metal_floor", "s": "t_metal_floor" }, + "items": { "P": [ { "item": "afs_formless_ruins_random_suit", "chance": 80, "repeat": [ 1, 2 ] } ] }, "furniture": { "P": "f_sleep_pod", "s": "f_sink" }, "place_monsters": [ { "monster": "AFS_GROUP_MOXIE_LOW_RISK", "x": [ 0, 11 ], "y": [ 0, 11 ], "density": 0.1 } ], "palettes": [ "afs_formless_ruins" ] diff --git a/data/mods/Aftershock/suit_operating_time.md b/data/mods/Aftershock/suit_operating_time.md new file mode 100644 index 0000000000000..4a346e910efef --- /dev/null +++ b/data/mods/Aftershock/suit_operating_time.md @@ -0,0 +1,106 @@ +# Powered Armor Balance + +These are guidelines for designing all sorts of Aftershock power armor. + +## Operating time + +We define `operating time` as the amount of time the suit/gear-piece takes to consume 1000 charges of batteries. The following factors, totaled, determine how long the suit should work between battery swaps. + + +#### Additional factors + | Extra Hours | Condition | + |-----------------------|-------------------------------------------------------------------------| + | 4 hours | Base operating time. All suits work for at least 4 hours per full charge | + |-----------------------|-------------------------------------------------------------------------| + | 1hour per every 5 enc | Count only the most encumbered part | + | 1 hours | Less than 40 armor against all hazards | + | 1 hours | Less than 20 armor against all hazards | + | 6 hours | Less than 10 armor against all hazards | + | 2 hours | Has the fragile tag or is made from a very fragile material (ex: glass) | + | 4 hours | Less than 90% coverage of the most encumbered part | + | 4 hours | No protection against gases | + | 12 hours | No protection against the cold | + | 2 hours | No protection against other environmental factors (ex: acid, electricity, radiation) | + | 4 hours | Gear doesn't give passive bonuses to physical attributes (ex: dex or str) or skills (ex: athletics) and won't grant physical-based proficiencies| + | 4 hours | Doesn't grant any combat/movement related spells or enchantments | + | 4 hours | Gear doesn't give passive bonuses to mental attributes (per or int) or skills (ex: applied science) and won't grant knowledge based proficiencies | + | 1 hours | Doesn't grant any mental/knowledge related spells or enchantments | + | 2 hours | Has a non-swappable integral battery. | + | 2 hours | Won't grant night/heat-vision or clairvoyance effects. | + +Once you have determined the operating time using the table above, simply divide the number 277777.78 by the indicated number of hours to obtain your new suit's `power_draw` json value. + +For player convenience, the power draw and battery capacity of all clothing pieces that comprise a single matching outfit (e.g., the Magellan exosuit and its helmet) should be the same. + +#### Example Calculation + +Consider the Magellan exosuit, which has the following definition: +``` + { + "id": "afs_magellan_suit", + "type": "TOOL_ARMOR", + "category": "armor", + "name": { "str": "Magellan exosuit" }, + "description": "A high-quality, civilian grade EVA suit often employed by well-established frontier research and exploration associations. Designed to support the exploration of challenging terrain, it offers respectable protection against common environmental hazards like extreme temperatures, inhospitable atmospheres, and light radiation. It leaves arms and hands relatively unencumbered to aid the manipulation of scientific instruments.\n\nAn integral battery allows the suit to operate for up to 34 hours, but complicates field recharging.", + "weight": "7800 g", + "volume": "14 L", + "price": "4 kUSD", + "material": [ "nomex", "steel" ], + "symbol": "[", + "looks_like": "robofac_enviro_suit", + "color": "light_gray", + "ammo": "battery", + "charges_per_use": 1, + "use_action": { + "type": "transform", + "msg": "You activate your %s.", + "target": "afs_magellan_suit_on", + "active": true, + "need_charges": 1, + "need_charges_msg": "The %s's batteries are dead." + }, + "armor_portion_data": [ + { "covers": [ "torso" ], "coverage": 100, "encumbrance": 25 }, + { "covers": [ "leg_l", "leg_r" ], "coverage": 100, "encumbrance": 25 }, + { "covers": [ "arm_l", "arm_r" ], "coverage": 100, "encumbrance": 15 }, + { "covers": [ "hand_l", "hand_r" ], "coverage": 100, "encumbrance": 10 }, + { "covers": [ "foot_l", "foot_r" ], "coverage": 100, "encumbrance": 15 } + ], + "pocket_data": [ + { "pocket_type": "MAGAZINE", "rigid": true, "ammo_restriction": { "battery": 1000 } } + ], + "warmth": 20, + "material_thickness": 2, + "valid_mods": [ "steel_padded" ], + "environmental_protection": 15, + "flags": [ "VARSIZE", "WATERPROOF", "GAS_PROOF", "POCKETS", "RAINPROOF", "STURDY", "RAD_RESIST", "RECHARGE", "OUTER", "NO_RELOAD", "NO_UNLOAD" ] + }, + +``` +The active version provides no additional bonuses except for cold protection. + +Evaluating the performance time using the table above, the result should be: + +| Suit Qualifies | Extra Hours | Condition | +|----------------|-----------------------|-------------------------------------------------------------------------| +| yes | 4 hours | Base operating time. All suits work for at least 4 hours per full charge | +|----------------|-----------------------|-------------------------------------------------------------------------| +| yes | 5 hours | Count only the most encumbered part | +| yes | 1 hours | Less than 40 armor against all hazards | +| yes | 1 hours | Less than 20 armor against all hazards | +| yes | 6 hours | Less than 10 armor against all hazards | +| no | 2 hours | Has the fragile tag or is made from a very fragile material (ex: glass) | +| no | 4 hours | Less than 90% coverage of the most encumbered part | +| no | 4 hours | No protection against gases | +| no | 12 hours | No protection against the cold | +| no | 2 hours | No protection against other environmental factors (ex: acid, electricity, radiation) | +| yes | 4 hours |Gear doesn't give passive bonuses to physical attributes (ex: dex or str) or skills (ex: athletics) and won't grant physical-based proficiencies| +| yes | 4 hours | Doesn't grant any combat/movement related spells or enchantments | +| yes | 4 hours | Gear doesn't give passive bonuses to mental attributes (per or int) or skills (ex: applied science) and won't grant knowledge based proficiencies | +| yes | 1 hours | Doesn't grant any mental/knowledge related spells or enchantments | +| yes | 2 hours | Has a non-swappable integral battery. | +| yes | 2 hours | Won't grant night/heat-vision or clairvoyance effects, | +|----------------|-----------------------|-------------------------------------------------------------------------| +| Total hours | 34 hours | | + +Due to the fulfilled conditions, the suit should operate for 34 hours when connected to a 1000 charge battery. To calculate its final `power_draw` value, we divide 277777.78 by 34 to obtain a `power_draw` of 8170. \ No newline at end of file From 0d7b448082ebe8ec76d4389c980cd0e6ceebf060 Mon Sep 17 00:00:00 2001 From: slitherrr Date: Thu, 8 Apr 2021 23:01:13 +0000 Subject: [PATCH 139/453] Fix some dialog in refugee trees Add an escape for the Jenny Forcette training tree to prevent an unescapable loop when the avatar is too skilled, and also add a bit of prologue to Boris's ask for the Ash's Laptop quest. --- .../surface_refugees/NPC_Boris_Borichenko.json | 2 +- .../refugee_center/surface_refugees/NPC_Jenny_Forcette.json | 5 ++++- 2 files changed, 5 insertions(+), 2 deletions(-) diff --git a/data/json/npcs/refugee_center/surface_refugees/NPC_Boris_Borichenko.json b/data/json/npcs/refugee_center/surface_refugees/NPC_Boris_Borichenko.json index c0b5d6d9fe7fe..c6a8eeb3109ca 100644 --- a/data/json/npcs/refugee_center/surface_refugees/NPC_Boris_Borichenko.json +++ b/data/json/npcs/refugee_center/surface_refugees/NPC_Boris_Borichenko.json @@ -480,7 +480,7 @@ }, "dialogue": { "describe": "Find Boris' son's laptop.", - "offer": "If you can find it, it would mean so much to me. I will give you directions to the shelter where he left it. It was barely a shelter, broken and torn apart. It should just be on the floor where it was dropped.", + "offer": "My son, Ash, had a laptop on which he kept his writing. If you can find it, it would mean so much to me. I will give you directions to the shelter where he left it. It was barely a shelter, broken and torn apart. It should just be on the floor where it was dropped.", "accepted": "You are a kind soul.", "rejected": "Ah well. I can ask around myself, perhaps.", "advice": "You can tell it is his because he covered it in stickers.", diff --git a/data/json/npcs/refugee_center/surface_refugees/NPC_Jenny_Forcette.json b/data/json/npcs/refugee_center/surface_refugees/NPC_Jenny_Forcette.json index a842d449da979..92126eb22009f 100644 --- a/data/json/npcs/refugee_center/surface_refugees/NPC_Jenny_Forcette.json +++ b/data/json/npcs/refugee_center/surface_refugees/NPC_Jenny_Forcette.json @@ -255,7 +255,10 @@ "id": "TALK_REFUGEE_JENNY_Teach2", "dynamic_line": "All right, fine. Grab some tools and do as I tell you.", "speaker_effect": { "effect": { "npc_add_var": "Jenny_teach", "type": "timer", "context": "flag", "time": true } }, - "responses": [ { "text": "Just say the word, teach.", "topic": "TALK_TRAIN" } ] + "responses": [ + { "text": "Just say the word, teach.", "topic": "TALK_TRAIN" }, + { "text": "Actually, I'd better get going. Let's do this later.", "topic": "TALK_DONE" } + ] }, { "type": "talk_topic", From 0cfe3cb12c833d0d772b2d5ce3b22f78eacb6fe3 Mon Sep 17 00:00:00 2001 From: MitztheKat Date: Fri, 9 Apr 2021 18:15:42 -0400 Subject: [PATCH 140/453] Clarify Wood Saw's log-to-plank ability in its description (#48444) --- data/json/items/tool/woodworking.json | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/data/json/items/tool/woodworking.json b/data/json/items/tool/woodworking.json index 2409520ec0195..6343db479c51c 100644 --- a/data/json/items/tool/woodworking.json +++ b/data/json/items/tool/woodworking.json @@ -262,7 +262,7 @@ "id": "saw", "type": "TOOL", "name": { "str": "wood saw" }, - "description": "This is a thin saw, useful for cutting through wood objects.", + "description": "This is a thin saw, useful for cutting through wood objects. Can turn pre-cut logs into planks by activation.", "weight": "283 g", "volume": "1 L", "longest_side": "46 cm", From 8ebb816134e0e4319de25b0c2bb9c6d56194013e Mon Sep 17 00:00:00 2001 From: ephemeralstoryteller Date: Sat, 10 Apr 2021 03:20:07 -0400 Subject: [PATCH 141/453] [Dark Skies] Lore and JSON Cleanup, Blacklists Mutant Wildlife (#48448) --- data/mods/Dark-Skies-Above/mondrops.json | 90 ------- .../Dark-Skies-Above/overrides/monsters.json | 113 +++++--- .../overrides/professions.json | 247 ++++++++++++++++++ .../Dark-Skies-Above/overrides/scenarios.json | 2 +- .../speech/neworder_speech.json | 24 -- 5 files changed, 330 insertions(+), 146 deletions(-) delete mode 100644 data/mods/Dark-Skies-Above/mondrops.json create mode 100644 data/mods/Dark-Skies-Above/overrides/professions.json diff --git a/data/mods/Dark-Skies-Above/mondrops.json b/data/mods/Dark-Skies-Above/mondrops.json deleted file mode 100644 index c1a8683142ee4..0000000000000 --- a/data/mods/Dark-Skies-Above/mondrops.json +++ /dev/null @@ -1,90 +0,0 @@ -[ - { - "id": "dks_mon_neworder_scout", - "type": "item_group", - "subtype": "collection", - "magazine": 100, - "ammo": 40, - "entries": [ - { "group": "underwear", "damage": [ 0, 1 ] }, - { "item": "dks_neworder_armor_salvaged", "damage": [ 1, 3 ] }, - { "item": "machete" }, - { "group": "clothing_watch", "prob": 20 }, - { "item": "knife_combat", "container-item": "sheath", "prob": 40 }, - { "item": "cash_card", "prob": 20, "charges-min": 0, "charges-max": 50000 }, - { "group": "dks_scout_extras", "prob": 60 } - ] - }, - { - "id": "dks_mon_neworder_cop", - "type": "item_group", - "subtype": "collection", - "magazine": 100, - "ammo": 40, - "entries": [ - { "group": "underwear", "damage": [ 0, 1 ] }, - { "item": "dks_neworder_armor_salvaged", "damage": [ 1, 3 ] }, - { "item": "shocktonfa_off", "charges-min": 10, "charges-max": 1198 }, - { "group": "clothing_watch", "prob": 20 }, - { "item": "dks_riotshield" }, - { "item": "cash_card", "prob": 20, "charges-min": 0, "charges-max": 50000 }, - { "group": "dks_cop_extras", "prob": 60, "count": [ 0, 2 ] } - ] - }, - { - "id": "dks_mon_neworder_pyro", - "type": "item_group", - "subtype": "collection", - "magazine": 100, - "ammo": 40, - "entries": [ - { "group": "underwear", "damage": [ 0, 1 ] }, - { "item": "dks_neworder_armor_salvaged", "damage": [ 1, 3 ] }, - { "group": "clothing_watch", "prob": 20 }, - { "item": "dks_flamesword_salvaged" }, - { "item": "cash_card", "prob": 20, "charges": [ 0, 50000 ] }, - { "group": "dks_knight_extras", "prob": 50, "count": [ 0, 2 ] } - ] - }, - { - "id": "dks_mon_neworder_knight", - "type": "item_group", - "subtype": "collection", - "magazine": 100, - "ammo": 40, - "entries": [ - { "group": "underwear", "damage": [ 0, 1 ] }, - { "item": "dks_neworder_armor_salvaged", "damage": [ 1, 3 ] }, - { "group": "clothing_watch", "prob": 20 }, - { "item": "dks_knightsword_salvaged" }, - { "item": "dks_battleshield" }, - { "item": "cash_card", "prob": 20, "charges": [ 0, 50000 ] }, - { "group": "dks_knight_extras", "prob": 50, "count": [ 0, 2 ] } - ] - }, - { - "id": "dks_cop_extras", - "type": "item_group", - "items": [ - { "group": "full_1st_aid", "prob": 25 }, - { "item": "legrig", "prob": 10 }, - { "item": "dump_pouch", "prob": 10 }, - { "item": "medium_disposable_cell", "prob": 30 } - ] - }, - { - "id": "dks_scout_extras", - "type": "item_group", - "items": [ - { "group": "full_1st_aid", "prob": 25 }, - { "item": "legrig", "prob": 10 }, - { "item": "dump_pouch", "prob": 10 }, - { "item": "binoculars", "prob": 30 } - ] - }, - { - "id": "dks_knight_extras", - "type": "item_group", - "items": [ { "item": "1st_aid", "prob": 25 }, { "item": "legrig", "prob": 10 }, { "item": "dump_pouch", "prob": 10 } ] - } -] diff --git a/data/mods/Dark-Skies-Above/overrides/monsters.json b/data/mods/Dark-Skies-Above/overrides/monsters.json index ea7a618811662..b0278f7d84b82 100644 --- a/data/mods/Dark-Skies-Above/overrides/monsters.json +++ b/data/mods/Dark-Skies-Above/overrides/monsters.json @@ -1,56 +1,107 @@ [ { - "id": "mon_c4_hack", - "copy-from": "mon_c4_hack", + "id": "mon_rattlesnake_giant", + "copy-from": "mon_rattlesnake_giant", "type": "MONSTER", - "name": { "str": "C-4 hack" }, - "extend": { "categories": [ "ALIEN" ] }, - "description": "An automated kamikaze drone, this small flying robot appears to have some C-4 inside." + "name": "giant rattlesnake", + "delete": { "categories": [ "WILDLIFE" ] } }, { - "id": "mon_flashbang_hack", - "copy-from": "mon_flashbang_hack", + "id": "mon_nakedmolerat_giant", + "copy-from": "mon_nakedmolerat_giant", "type": "MONSTER", - "name": { "str": "flashbang hack" }, - "extend": { "categories": [ "ALIEN" ] }, - "description": "An automated kamikaze drone, this small flying robot appears to have a flashbang inside." + "name": "gigantic naked mole-rat", + "delete": { "categories": [ "WILDLIFE" ] } }, { - "id": "mon_gasbomb_hack", - "copy-from": "mon_gasbomb_hack", + "id": "mon_crow_mutant_small", + "copy-from": "mon_crow_mutant_small", "type": "MONSTER", - "name": { "str": "tear gas hack" }, - "extend": { "categories": [ "ALIEN" ] }, - "description": "An automated kamikaze drone, this small flying robot appears to have a tear gas canister inside." + "name": { "str": "oversized crow" }, + "delete": { "categories": [ "WILDLIFE" ] } }, { - "id": "mon_grenade_hack", - "copy-from": "mon_grenade_hack", + "id": "mon_cockatrice", + "copy-from": "mon_cockatrice", "type": "MONSTER", - "name": { "str": "grenade hack" }, - "extend": { "categories": [ "ALIEN" ] }, - "description": "An automated kamikaze drone, this small flying robot appears to have a grenade inside." + "name": { "str": "cockatrice" }, + "delete": { "categories": [ "WILDLIFE" ] } }, { - "id": "mon_manhack", - "copy-from": "mon_manhack", + "id": "mon_bear_mutant_3headed", "type": "MONSTER", - "name": { "str": "manhack" }, - "extend": { "categories": [ "ALIEN" ] }, - "description": "An automated anti-personnel drone, a small flying robot surrounded by whirring blades." + "name": { "str": "Cerbearus", "str_pl": "Cerberuses" }, + "copy-from": "mon_bear_mutant_3headed", + "delete": { "categories": [ "WILDLIFE" ] } }, { - "id": "mon_rattlesnake_giant", - "copy-from": "mon_rattlesnake_giant", + "id": "mon_beaver_mutant_huge", "type": "MONSTER", - "name": "giant rattlesnake", + "name": { "str": "dambreaker" }, + "copy-from": "mon_beaver_mutant_huge", "delete": { "categories": [ "WILDLIFE" ] } }, { - "id": "mon_nakedmolerat_giant", - "copy-from": "mon_nakedmolerat_giant", + "id": "mon_beaver_mutant_avian", "type": "MONSTER", - "name": "gigantic naked mole-rat", + "name": { "str": "feaver" }, + "copy-from": "mon_beaver_mutant_avian", + "delete": { "categories": [ "WILDLIFE" ] } + }, + { + "id": "mon_cat_mutant_prism", + "type": "MONSTER", + "name": { "str": "iridescent cat" }, + "copy-from": "mon_cat_mutant_prism", + "delete": { "categories": [ "WILDLIFE" ] } + }, + { + "id": "mon_cat_mutant_kitten_prism", + "type": "MONSTER", + "name": { "str": "iridescent kitten" }, + "copy-from": "mon_cat_mutant_kitten_prism", + "delete": { "categories": [ "WILDLIFE" ] } + }, + { + "id": "mon_coyote_mutant_shark", + "type": "MONSTER", + "name": { "str": "grinning coyote" }, + "copy-from": "mon_coyote_mutant_shark", + "delete": { "categories": [ "WILDLIFE" ] } + }, + { + "id": "mon_coyote_mutant_venom", + "type": "MONSTER", + "name": { "str": "slavering coyote" }, + "copy-from": "mon_coyote_mutant_venom", + "delete": { "categories": [ "WILDLIFE" ] } + }, + { + "id": "mon_wolf_mutant_huge", + "type": "MONSTER", + "name": { "str": "dire wolf" }, + "copy-from": "mon_wolf_mutant_huge", + "delete": { "categories": [ "WILDLIFE" ] } + }, + { + "id": "mon_deer_mutant_spider", + "type": "MONSTER", + "name": { "str": "spideer" }, + "copy-from": "mon_deer_mutant_spider", + "delete": { "categories": [ "WILDLIFE" ] } + }, + { + "id": "mon_deer_mutant_spider_fawn", + "type": "MONSTER", + "name": { "str": "spideer fawn" }, + "copy-from": "mon_deer_mutant_spider_fawn", + "delete": { "categories": [ "WILDLIFE" ] } + }, + { + "id": "mon_dog_mutant_mongrel", + "type": "MONSTER", + "name": { "str": "mongrel" }, + "copy-from": "mon_dog_mutant_mongrel", "delete": { "categories": [ "WILDLIFE" ] } } ] diff --git a/data/mods/Dark-Skies-Above/overrides/professions.json b/data/mods/Dark-Skies-Above/overrides/professions.json new file mode 100644 index 0000000000000..69bc3430511fa --- /dev/null +++ b/data/mods/Dark-Skies-Above/overrides/professions.json @@ -0,0 +1,247 @@ +[ + { + "type": "profession", + "id": "heroin_addict", + "copy-from": "heroin_addict", + "name": "Heroin Addict", + "description": "The last thing you remember was meeting God behind the local Foodplace. Then the skies opened up and fire rained forth. This doesn't feel like a fever dream." + }, + { + "type": "profession", + "id": "pillhead", + "copy-from": "pillhead", + "name": "Heroin Addict", + "description": "After an accident in your youth, you got addicted to the opiates treating your pain. With the pharmacies shut down and your dealers started growing crystals, satisfying those cravings just got a lot more difficult." + }, + { + "type": "profession", + "id": "naked", + "copy-from": "naked", + "name": "Naked and Afraid", + "description": "You were out filming a reality TV show, naked in the woods. The cast and crew fled when the aliens came, which is pretty bad timing for you. Looks like it's for real this time…" + }, + { + "type": "profession", + "id": "lumberjack", + "copy-from": "lumberjack", + "name": "Lumberjack", + "description": "You're a lumberjack, and you're okay. You felled trees before the world ended, but suspect those crystal ghouls aren't nearly as tough." + }, + { + "type": "profession", + "id": "dancer", + "copy-from": "dancer", + "name": "Ballroom Dancer", + "description": "Things got a little weird on your way to your weekly dance class. Aliens don't seem to know how to dance, but you're not about to let them step on your toes." + }, + { + "type": "profession", + "id": "skaboy", + "copy-from": "skaboy", + "name": { "male": "Rude Boy", "female": "Rude Girl" }, + "description": "Your ska band broke up after the drummer got vaporized. Now you're alone in the Cataclysm with some cigarettes and your mp3 player." + }, + { + "type": "profession", + "id": "imam", + "copy-from": "imam", + "name": { "male": "Imam", "female": "Mourchida" }, + "description": "You spent much of your time prior to the apocalypse at the local mosque, studying the words of the Prophet and the Quran and guiding your community in prayer. Back then they came from far and wide to listen to you; now they come to tear you apart." + }, + { + "type": "profession", + "id": "teacher", + "copy-from": "teacher", + "name": "Teacher", + "description": "You've been teaching kids all your life, experiencing the joy and aggravation of imparting knowledge to young minds. If aliens have any interest in education, they're not showing it." + }, + { + "type": "profession", + "id": "groundskeeper", + "copy-from": "groundskeeper", + "name": "Landscaper", + "description": "You used to mow lawns and trim hedges for the wealthy. Contract work was getting scarce even before the aliens came, but now you've got nothing left except your tools and expertise." + }, + { + "type": "profession", + "id": "homemaker", + "copy-from": "homemaker", + "name": "Nursing Assistant", + "description": "You went on providing in-home care for the elderly even as the whole world fell apart around you. You can only pray that you don't see your former clients among those crystal things…" + }, + { + "type": "profession", + "id": "cosplay", + "copy-from": "cosplay", + "name": "Otaku", + "description": "After many late nights with friends watching anime and eating snacks, you decided to make the trip to the premier anime convention in the Northeast. Now aliens are killing everyone, and even worse, the convention is cancelled! At least you were ready in case your costume tore." + }, + { + "type": "profession", + "id": "lawyer", + "copy-from": "lawyer", + "name": "Lawyer", + "description": "The jury were in the palm of your hand, but after the aliens started invading, you were forced to flee the courtroom in disgrace. Now nobody seems to care about your objections." + }, + { + "type": "profession", + "id": "pizzaboy", + "copy-from": "pizzaboy", + "name": { "male": "Pizza Delivery Boy", "female": "Pizza Delivery Girl" }, + "description": "You were delivering the last pizza of the night to the local cryogenics lab when hungry aliens attempted to make a meal out of you. Fleeing for safety, you find yourself with only your wits and some leftover pizza. And they didn't even leave a tip!" + }, + { + "type": "profession", + "id": "relief_volunteer", + "copy-from": "relief_volunteer", + "name": "Relief Volunteer", + "description": "You were a member of a non-profit organization dedicated to helping out where help was needed. When the storms picked up and the first bombs dropped, you were eager to lend a hand. But you had to cut your plans short when the aliens arrived: they seem less interested in handouts, and more interested in eating you." + }, + { + "type": "profession", + "id": "guru", + "copy-from": "guru", + "name": "Guru", + "description": "You spent many years traveling through the world, becoming wise and learned. Normally, you can answer any question, but even you are not quite sure what to do about the ravenous aliens." + }, + { + "type": "profession", + "id": "preacher", + "copy-from": "preacher", + "name": "Preacher", + "description": "You devoted your life to spreading the good word, always on the road, traveling from town to town. Now everything has gone to hell, you can't host your daily podcast, and the aliens don't seem particularly moved by your sermons." + }, + { + "type": "profession", + "id": "rollerderby", + "copy-from": "rollerderby", + "name": "Roller Derby Player", + "description": "You were hell on wheels. Now the rest of your team is dead, and you probably wouldn't have lived this long if not for your penchant for high-speed violence. Things are looking grim; how long can you race laps around the aliens before you get blocked for good?" + }, + { + "type": "profession", + "id": "game_master", + "copy-from": "game_master", + "name": "Game Master", + "description": "Trying to herd cats into meeting up every week has taught you something: it's usually better to cut your losses and trust your gut. For that reason, when you had two no-shows and the other two got eaten, you ditched. Maybe you can find some new players in the ruins of the world." + }, + { + "type": "profession", + "id": "frat", + "copy-from": "frat", + "name": { "male": "Frat Boy", "female": "Sorority Girl" }, + "description": "You were living the high life, spending your parents' money without a care in the world. At one of your usual crazy parties, a bomb landed right in the hot tub, but you still have a chance to use the last symbol of your luxurious life - your sports car - and get far away." + }, + { + "type": "profession", + "id": "labtech", + "copy-from": "labtech", + "name": "Lab Technician", + "description": "Thanks to years of study and hard work in the lab, you're familiar with the basics of scientific inquiry. Only one question remains: can you avoid getting experimented on in return?" + }, + { + "type": "profession", + "id": "paperboy", + "copy-from": "paperboy", + "name": { "male": "Paperboy", "female": "Papergirl" }, + "description": "You set out this morning to deliver the news of the apocalypse. The aliens don't seem to value the latest news, but at least your trusty bicycle is still in working order." + }, + { + "type": "profession", + "id": "labtech", + "copy-from": "labtech", + "name": "Lab Technician", + "description": "Thanks to years of study and hard work in the lab, you're familiar with the basics of scientific inquiry. Only one question remains: can you avoid getting experimented on in return?" + }, + { + "type": "profession", + "id": "national_guard", + "copy-from": "national_guard", + "name": "National Guard", + "description": "The government activated your National Guard unit to deal with the growing storms and the following bombings. Despite your best efforts, you were unable to form up before all communications ceased and you found yourself alone amongst the enemy." + }, + { + "type": "profession", + "id": "gym_teacher", + "copy-from": "gym_teacher", + "name": "Gym Teacher", + "description": "It was hard enough getting kids to run laps without having to worry about doing it in a warzone. Aliens won't even line up when you blow your whistle." + }, + { + "type": "profession", + "id": "major-general", + "copy-from": "major-general", + "name": "Major General", + "description": "You worked your way up through the ranks, from a no-name private, to a big shot Major General. Now however, it is years since you last fired a weapon in anger, and you've somehow ended up deep behind enemy lines." + }, + { + "type": "profession", + "id": "recruit", + "copy-from": "recruit", + "name": "Military Recruit", + "description": "Joining the military has been your dream for years. You finally got in, just in time for your training to get interrupted by some sort of national emergency. After a hot deployment, as far as you can tell you're one of the last active personnel in this hellhole." + }, + { + "type": "profession", + "id": "combat-mechanic", + "copy-from": "combat-mechanic", + "name": "Combat Mechanic", + "description": "You failed out of high school, and joined the army. You were soon hand picked for extra training in the mechanics trade, keeping the armour running. It's been years since you last touched a rifle, and now the sky is falling…" + }, + { + "type": "profession", + "id": "riot_police", + "copy-from": "riot_police", + "name": "Riot Control Officer", + "description": "You were keeping the peace at a local climate change protest when the bombs started dropping and aliens started appearing in the streets. It was only by luck that you manage to survive the crowd in one piece, and the worst is yet to come." + }, + { + "type": "profession", + "id": "trucker", + "copy-from": "trucker", + "name": "Trucker", + "description": "You once ruled the road in your big rig. When the bombs hit, you hopped in and drove it to safety. Now it's just you and your truck against the world." + }, + { + "type": "profession", + "id": "fencer", + "copy-from": "fencer", + "name": "Competitive Fencer", + "description": "Years of training prepared you for the competitive fencing circuit, but your latest tournament was cut short when aliens invaded the piste. The referee was blown away, so you're not sure if the rules are still in play." + }, + { + "type": "profession", + "id": "politician", + "copy-from": "politician", + "name": "Career Politician", + "description": "You've spent your life appealing to the people, persuading many and promising much throughout your time in office. Now that your voting base is dead or worse and hostile forces are in America's heartland, winning hearts and minds just got that much harder." + }, + { + "type": "profession", + "id": "hazmat_unit", + "copy-from": "hazmat_unit", + "name": "Hazmat Unit", + "description": "You were deployed to autopsy one of the aliens after it was put down. When their friends showed up in force, you knew this was out of your job description." + }, + { + "type": "profession", + "id": "mili_burner", + "copy-from": "mili_burner", + "name": "Military Flamethrower Operator", + "description": "In response to the outbreak, you were dispatched to contain alien invasive species through judicious use of fire. After getting separated from your squad, your priorities have shifted to basic survival." + }, + { + "type": "profession", + "id": "nco", + "copy-from": "nco", + "name": "Non Commissioned Officer", + "description": "You're a veteran of several peace keeping missions. You lead your squad as a sort of parental figure, offering helpful advice on how not to die. Now they've been blasted to pieces by the alien and you're on your own." + }, + { + "type": "profession", + "id": "specops", + "copy-from": "specops", + "name": "Special Operator", + "description": "You were the best of the best, the military's finest. That's why you're still alive, even after all your comrades fell to the aliens. As far as you can tell, you're one of the last active operators in this hellhole." + } +] diff --git a/data/mods/Dark-Skies-Above/overrides/scenarios.json b/data/mods/Dark-Skies-Above/overrides/scenarios.json index 423e9a3fa875a..eb1ae0331df40 100644 --- a/data/mods/Dark-Skies-Above/overrides/scenarios.json +++ b/data/mods/Dark-Skies-Above/overrides/scenarios.json @@ -5,7 +5,7 @@ "copy-from": "evacuee", "allowed_locs": [ "sloc_dks_shelter" ], "name": "Evacuee", - "description": "You have survived the initial wave of panic and managed to avoid being taken to the Designated Living Zones. You begin in the (relative) safety in one of the many government evac shelters.", + "description": "You have survived the initial wave of panic and managed to escape to (relative) safety in one of the many government evac shelters.", "blacklist_professions": true, "professions": [ "churl" ] }, diff --git a/data/mods/Dark-Skies-Above/speech/neworder_speech.json b/data/mods/Dark-Skies-Above/speech/neworder_speech.json index 09bfd1ac33562..3e9d576765f43 100644 --- a/data/mods/Dark-Skies-Above/speech/neworder_speech.json +++ b/data/mods/Dark-Skies-Above/speech/neworder_speech.json @@ -1,28 +1,4 @@ [ - { - "type": "speech", - "speaker": [ "dks_neworder_scout", "dks_neworder_pyro", "dks_neworder_cop", "dks_neworder_knight" ], - "sound": "unintelligble radio chatter.", - "volume": 20 - }, - { - "type": "speech", - "speaker": [ "dks_neworder_scout", "dks_neworder_pyro", "dks_neworder_cop", "dks_neworder_knight" ], - "sound": "unintelligble radio chatter.", - "volume": 20 - }, - { - "type": "speech", - "speaker": [ "dks_neworder_scout", "dks_neworder_pyro", "dks_neworder_cop", "dks_neworder_knight" ], - "sound": "unintelligble radio chatter, followed by a response.", - "volume": 25 - }, - { - "type": "speech", - "speaker": [ "dks_neworder_scout", "dks_neworder_pyro", "dks_neworder_cop", "dks_neworder_knight" ], - "sound": "unintelligble radio chatter.", - "volume": 20 - }, { "type": "speech", "speaker": [ "mon_dks_emissary", "mon_dks_emissary_war", "mon_dks_emissary_flame" ], From 69ed7462f7171af379c774efc240d6e0c4ea2ea1 Mon Sep 17 00:00:00 2001 From: ephemeralstoryteller Date: Sat, 10 Apr 2021 03:21:35 -0400 Subject: [PATCH 142/453] [Dark Skies] Adds ballistic armor to aliens (#48446) --- .../Dark-Skies-Above/monsters/alien_cyborgs.json | 12 ++++++++---- .../mods/Dark-Skies-Above/monsters/alien_robots.json | 6 ++++-- 2 files changed, 12 insertions(+), 6 deletions(-) diff --git a/data/mods/Dark-Skies-Above/monsters/alien_cyborgs.json b/data/mods/Dark-Skies-Above/monsters/alien_cyborgs.json index 6305f45b6b940..c4c5f5c7f78c1 100644 --- a/data/mods/Dark-Skies-Above/monsters/alien_cyborgs.json +++ b/data/mods/Dark-Skies-Above/monsters/alien_cyborgs.json @@ -24,6 +24,7 @@ "melee_cut": 2, "armor_bash": 90, "armor_cut": 90, + "armor_bullet": 100, "armor_acid": 10, "path_settings": { "max_dist": 30 }, "death_drops": { "groups": [ [ "robots", 4 ], [ "eyebot", 1 ], [ "turret_searchlight", 1 ] ] }, @@ -93,6 +94,7 @@ "melee_cut": 2, "armor_bash": 90, "armor_cut": 90, + "armor_bullet": 100, "armor_acid": 10, "path_settings": { "max_dist": 30 }, "emit_fields": [ { "emit_id": "emit_toxic_leak", "delay": "1 s" } ], @@ -161,6 +163,7 @@ "melee_cut": 2, "armor_bash": 90, "armor_cut": 90, + "armor_bullet": 100, "armor_acid": 10, "path_settings": { "max_dist": 30 }, "death_drops": { "groups": [ [ "robots", 4 ], [ "eyebot", 1 ], [ "turret_searchlight", 1 ] ] }, @@ -207,7 +210,7 @@ "id": "dks_mon_lurker_rectified", "type": "MONSTER", "name": { "str": "recycler" }, - "description": "A sleek mass of hairy tentacles originate from a metallic core that looks like a mix between a garbage disposal and a clamp, golden pinpoints of dim light dotting its chassis. It seems adept at collecting small pieces of junk and debris and mulching them in its mouth for unknown purposes - you included.", + "description": "A sleek mass of hairy tentacles originate from a metallic core that looks like a mix between a garbage disposal and a clamp, golden pinpoints of dim light dotting its chassis. It seems adept at collecting small pieces of junk and debris to mulch them into their bae parts - you included.", "default_faction": "invader_alien", "bodytype": "spider", "categories": [ "ALIEN" ], @@ -248,7 +251,7 @@ "id": "dks_mon_bileworm_rectified", "type": "MONSTER", "name": { "str": "tunneler" }, - "description": "A huge creature, encased in metal plating and covered in small golden \"eyes\". Stocky robotic appendages covering its body allow it to smash through rock and propel itself forward with efficiency. Its interior seems to have been replaced by some sort of whirring processing equipment that would be highly unpleasant to be caught up in. Fortunately it doesn't seem very hostile.", + "description": "A huge creature, encased in metal plating and covered in small golden \"eyes\". Stocky robotic appendages covering its body allow it to smash through rock and propel itself forward with efficiency. Its interior seems to have been replaced by some sort of whirring processing equipment that would be highly unpleasant to be caught up in. Fortunately it doesn't seem immediately interested in you.", "looks_like": "mon_worm", "default_faction": "invader_alien", "bodytype": "snake", @@ -266,8 +269,9 @@ "melee_skill": 4, "melee_dice": 4, "melee_dice_sides": 6, - "armor_bash": 4, - "armor_cut": 2, + "armor_bash": 12, + "armor_cut": 6, + "armor_bullet": 6, "vision_night": 15, "harvest": "mutant_meatslug", "special_attacks": [ diff --git a/data/mods/Dark-Skies-Above/monsters/alien_robots.json b/data/mods/Dark-Skies-Above/monsters/alien_robots.json index 7dab18c2aebfc..625d40bb98338 100644 --- a/data/mods/Dark-Skies-Above/monsters/alien_robots.json +++ b/data/mods/Dark-Skies-Above/monsters/alien_robots.json @@ -3,7 +3,7 @@ "id": "mon_dks_glowdrone", "type": "MONSTER", "name": { "str": "alien surveillance drone" }, - "description": "A small, sleek, white-plated robot bearing a golden insignia. Capable of limited flight, it hovers about the ruins of the former world, on-board cameras and spotlights impartial witness to the chaos around it. Who knows what might be watching on the other side…", + "description": "A small, sleek, white-plated robot bearing a golden insignia that is capable of limited flight. It hovers about the ruins of the former world, onboard cameras and spotlights impartial witness to the chaos around it. Who knows might be watching on the other side…", "default_faction": "invader_alien", "looks_like": "mon_eyebot", "categories": [ "ALIEN" ], @@ -18,6 +18,7 @@ "dodge": 3, "armor_bash": 8, "armor_cut": 10, + "armor_bullet": 6, "luminance": 5, "special_attacks": [ [ "SEARCHLIGHT", 1 ] ], "path_settings": { "max_dist": 5 }, @@ -29,7 +30,7 @@ "id": "mon_dks_scidrone", "type": "MONSTER", "name": { "str": "alien seeker drone" }, - "description": "A small, sleek, white-plated robot bearing a golden insignia. Capable of limited flight, it hovers about the ruins of the former world, using a suite of rather sharp looking retractable tools, a bright camera flash, and integrated 'arms' to manipulate the world around it with surprising dexterity and procure samples. It seems to watch you closely once it catches sight of you…", + "description": "A small, sleek, white-plated robot bearing a golden insignia that is capable of limited flight. It hovers about the ruins of the former world, using a suite of sharp retractable tools, a bright camera flash, and integrated 'arms' to manipulate the world around it. It seems to watch its subjects closely…", "default_faction": "invader_alien", "looks_like": "mon_eyebot", "categories": [ "ALIEN" ], @@ -46,6 +47,7 @@ "dodge": 3, "armor_bash": 10, "armor_cut": 12, + "armor_bullet": 8, "luminance": 10, "vision_night": 5, "special_attacks": [ From c0b0933458d7e83477df6d42547711f690b45276 Mon Sep 17 00:00:00 2001 From: ANickelN <52714184+ANickelN@users.noreply.github.com> Date: Sat, 10 Apr 2021 00:26:43 -0700 Subject: [PATCH 143/453] Audit Pocket Length/Volume/Weight Clothing (#48420) --- data/json/items/armor/coats.json | 966 +++++++++++++++++--- data/json/items/armor/legs_armor.json | 160 +++- data/json/items/armor/legs_clothes.json | 606 ++++++++++-- data/json/items/armor/suits_protection.json | 123 ++- data/json/items/armor/swimming.json | 36 +- data/json/items/armor/torso_clothes.json | 143 ++- 6 files changed, 1756 insertions(+), 278 deletions(-) diff --git a/data/json/items/armor/coats.json b/data/json/items/armor/coats.json index 40ce1171431ee..692429dd8785e 100644 --- a/data/json/items/armor/coats.json +++ b/data/json/items/armor/coats.json @@ -20,9 +20,27 @@ { "covers": [ "arm_l", "arm_r" ], "coverage": 100, "encumbrance": [ 22, 22 ] } ], "pocket_data": [ - { "pocket_type": "CONTAINER", "max_contains_volume": "1 L", "max_contains_weight": "3 kg", "moves": 80 }, - { "pocket_type": "CONTAINER", "max_contains_volume": "500 ml", "max_contains_weight": "2 kg", "moves": 80 }, - { "pocket_type": "CONTAINER", "max_contains_volume": "500 ml", "max_contains_weight": "2 kg", "moves": 80 } + { + "pocket_type": "CONTAINER", + "max_contains_volume": "900 ml", + "max_contains_weight": "3 kg", + "max_item_length": "24 cm", + "moves": 80 + }, + { + "pocket_type": "CONTAINER", + "max_contains_volume": "3250 ml", + "max_contains_weight": "5 kg", + "max_item_length": "30 cm", + "moves": 80 + }, + { + "pocket_type": "CONTAINER", + "max_contains_volume": "3250 ml", + "max_contains_weight": "5 kg", + "max_item_length": "30 cm", + "moves": 80 + } ], "warmth": 30, "material_thickness": 2, @@ -71,8 +89,20 @@ { "covers": [ "arm_l", "arm_r" ], "coverage": 95, "encumbrance": [ 26, 26 ] } ], "pocket_data": [ - { "pocket_type": "CONTAINER", "max_contains_volume": "500 ml", "max_contains_weight": "2 kg", "moves": 80 }, - { "pocket_type": "CONTAINER", "max_contains_volume": "500 ml", "max_contains_weight": "2 kg", "moves": 80 } + { + "pocket_type": "CONTAINER", + "max_contains_volume": "500 ml", + "max_contains_weight": "2 kg", + "max_item_length": "16 cm", + "moves": 80 + }, + { + "pocket_type": "CONTAINER", + "max_contains_volume": "500 ml", + "max_contains_weight": "2 kg", + "max_item_length": "16 cm", + "moves": 80 + } ], "warmth": 80, "material_thickness": 2, @@ -128,8 +158,20 @@ { "covers": [ "arm_l", "arm_r" ], "coverage": 95, "encumbrance": [ 30, 30 ] } ], "pocket_data": [ - { "pocket_type": "CONTAINER", "max_contains_volume": "700 ml", "max_contains_weight": "3 kg", "moves": 80 }, - { "pocket_type": "CONTAINER", "max_contains_volume": "700 ml", "max_contains_weight": "3 kg", "moves": 80 } + { + "pocket_type": "CONTAINER", + "max_contains_volume": "700 ml", + "max_contains_weight": "3 kg", + "max_item_length": "16 cm", + "moves": 80 + }, + { + "pocket_type": "CONTAINER", + "max_contains_volume": "700 ml", + "max_contains_weight": "3 kg", + "max_item_length": "16 cm", + "moves": 80 + } ], "warmth": 90, "material_thickness": 2, @@ -157,9 +199,27 @@ { "covers": [ "arm_l", "arm_r" ], "coverage": 90, "encumbrance": [ 2, 2 ] } ], "pocket_data": [ - { "pocket_type": "CONTAINER", "max_contains_volume": "1500 ml", "max_contains_weight": "3 kg", "moves": 80 }, - { "pocket_type": "CONTAINER", "max_contains_volume": "1500 ml", "max_contains_weight": "3 kg", "moves": 80 }, - { "pocket_type": "CONTAINER", "max_contains_volume": "500 ml", "max_contains_weight": "1 kg", "moves": 80 } + { + "pocket_type": "CONTAINER", + "max_contains_volume": "1600 ml", + "max_contains_weight": "3 kg", + "max_item_length": "21 cm", + "moves": 80 + }, + { + "pocket_type": "CONTAINER", + "max_contains_volume": "1600 ml", + "max_contains_weight": "3 kg", + "max_item_length": "21 cm", + "moves": 80 + }, + { + "pocket_type": "CONTAINER", + "max_contains_volume": "900 ml", + "max_contains_weight": "1 kg", + "max_item_length": "13 cm", + "moves": 80 + } ], "warmth": 15, "material_thickness": 0.25, @@ -183,8 +243,20 @@ { "covers": [ "arm_l", "arm_r" ], "coverage": 95, "encumbrance": [ 7, 7 ] } ], "pocket_data": [ - { "pocket_type": "CONTAINER", "max_contains_volume": "1500 ml", "max_contains_weight": "4 kg", "moves": 80 }, - { "pocket_type": "CONTAINER", "max_contains_volume": "1500 ml", "max_contains_weight": "4 kg", "moves": 120 } + { + "pocket_type": "CONTAINER", + "max_contains_volume": "1500 ml", + "max_contains_weight": "4 kg", + "max_item_length": "21 cm", + "moves": 80 + }, + { + "pocket_type": "CONTAINER", + "max_contains_volume": "1500 ml", + "max_contains_weight": "4 kg", + "max_item_length": "21 cm", + "moves": 80 + } ], "warmth": 10, "material_thickness": 0.2, @@ -254,10 +326,34 @@ { "covers": [ "arm_l", "arm_r" ], "coverage": 95, "encumbrance": [ 18, 21 ] } ], "pocket_data": [ - { "pocket_type": "CONTAINER", "max_contains_volume": "1250 ml", "max_contains_weight": "3kg", "moves": 80 }, - { "pocket_type": "CONTAINER", "max_contains_volume": "1250 ml", "max_contains_weight": "3 kg", "moves": 80 }, - { "pocket_type": "CONTAINER", "max_contains_volume": "350 ml", "max_contains_weight": "1 kg", "moves": 120 }, - { "pocket_type": "CONTAINER", "max_contains_volume": "350 ml", "max_contains_weight": "1 kg", "moves": 120 } + { + "pocket_type": "CONTAINER", + "max_contains_volume": "1250 ml", + "max_contains_weight": "3 kg", + "max_item_length": "21 cm", + "moves": 80 + }, + { + "pocket_type": "CONTAINER", + "max_contains_volume": "1250 ml", + "max_contains_weight": "3 kg", + "max_item_length": "21 cm", + "moves": 80 + }, + { + "pocket_type": "CONTAINER", + "max_contains_volume": "900 ml", + "max_contains_weight": "1 kg", + "max_item_length": "13 cm", + "moves": 120 + }, + { + "pocket_type": "CONTAINER", + "max_contains_volume": "900 ml", + "max_contains_weight": "1 kg", + "max_item_length": "13 cm", + "moves": 120 + } ], "warmth": 70, "material_thickness": 2, @@ -285,12 +381,48 @@ { "covers": [ "arm_l", "arm_r" ], "coverage": 90, "encumbrance": [ 7, 7 ] } ], "pocket_data": [ - { "pocket_type": "CONTAINER", "max_contains_volume": "1500 ml", "max_contains_weight": "4 kg", "moves": 80 }, - { "pocket_type": "CONTAINER", "max_contains_volume": "1500 ml", "max_contains_weight": "4 kg", "moves": 80 }, - { "pocket_type": "CONTAINER", "max_contains_volume": "1 L", "max_contains_weight": "2 kg", "moves": 80 }, - { "pocket_type": "CONTAINER", "max_contains_volume": "1 L", "max_contains_weight": "2 kg", "moves": 80 }, - { "pocket_type": "CONTAINER", "max_contains_volume": "500 ml", "max_contains_weight": "1 kg", "moves": 120 }, - { "pocket_type": "CONTAINER", "max_contains_volume": "500 ml", "max_contains_weight": "1 kg", "moves": 120 } + { + "pocket_type": "CONTAINER", + "max_contains_volume": "1500 ml", + "max_contains_weight": "4 kg", + "max_item_length": "24 cm", + "moves": 80 + }, + { + "pocket_type": "CONTAINER", + "max_contains_volume": "1500 ml", + "max_contains_weight": "4 kg", + "max_item_length": "24 cm", + "moves": 80 + }, + { + "pocket_type": "CONTAINER", + "max_contains_volume": "1 L", + "max_contains_weight": "2 kg", + "max_item_length": "21 cm", + "moves": 80 + }, + { + "pocket_type": "CONTAINER", + "max_contains_volume": "1 L", + "max_contains_weight": "2 kg", + "max_item_length": "21 cm", + "moves": 80 + }, + { + "pocket_type": "CONTAINER", + "max_contains_volume": "800 ml", + "max_contains_weight": "1 kg", + "max_item_length": "13 cm", + "moves": 120 + }, + { + "pocket_type": "CONTAINER", + "max_contains_volume": "800 ml", + "max_contains_weight": "1 kg", + "max_item_length": "13 cm", + "moves": 120 + } ], "warmth": 15, "material_thickness": 0.3, @@ -317,12 +449,48 @@ { "covers": [ "arm_l", "arm_r" ], "coverage": 90, "encumbrance": [ 9, 9 ] } ], "pocket_data": [ - { "pocket_type": "CONTAINER", "max_contains_volume": "1500 ml", "max_contains_weight": "4 kg", "moves": 80 }, - { "pocket_type": "CONTAINER", "max_contains_volume": "1500 ml", "max_contains_weight": "4 kg", "moves": 80 }, - { "pocket_type": "CONTAINER", "max_contains_volume": "1 L", "max_contains_weight": "2 kg", "moves": 80 }, - { "pocket_type": "CONTAINER", "max_contains_volume": "1 L", "max_contains_weight": "2 kg", "moves": 80 }, - { "pocket_type": "CONTAINER", "max_contains_volume": "500 ml", "max_contains_weight": "1 kg", "moves": 120 }, - { "pocket_type": "CONTAINER", "max_contains_volume": "500 ml", "max_contains_weight": "1 kg", "moves": 120 } + { + "pocket_type": "CONTAINER", + "max_contains_volume": "1500 ml", + "max_contains_weight": "4 kg", + "max_item_length": "24 cm", + "moves": 80 + }, + { + "pocket_type": "CONTAINER", + "max_contains_volume": "1500 ml", + "max_contains_weight": "4 kg", + "max_item_length": "24 cm", + "moves": 80 + }, + { + "pocket_type": "CONTAINER", + "max_contains_volume": "1 L", + "max_contains_weight": "2 kg", + "max_item_length": "21 cm", + "moves": 80 + }, + { + "pocket_type": "CONTAINER", + "max_contains_volume": "1 L", + "max_contains_weight": "2 kg", + "max_item_length": "21 cm", + "moves": 80 + }, + { + "pocket_type": "CONTAINER", + "max_contains_volume": "800 ml", + "max_contains_weight": "1 kg", + "max_item_length": "13 cm", + "moves": 120 + }, + { + "pocket_type": "CONTAINER", + "max_contains_volume": "800 ml", + "max_contains_weight": "1 kg", + "max_item_length": "13 cm", + "moves": 120 + } ], "warmth": 50, "material_thickness": 3, @@ -385,12 +553,48 @@ { "covers": [ "arm_l", "arm_r" ], "coverage": 90, "encumbrance": [ 8, 8 ] } ], "pocket_data": [ - { "pocket_type": "CONTAINER", "max_contains_volume": "1500 ml", "max_contains_weight": "4 kg", "moves": 80 }, - { "pocket_type": "CONTAINER", "max_contains_volume": "1500 ml", "max_contains_weight": "4 kg", "moves": 80 }, - { "pocket_type": "CONTAINER", "max_contains_volume": "1 L", "max_contains_weight": "2 kg", "moves": 80 }, - { "pocket_type": "CONTAINER", "max_contains_volume": "1 L", "max_contains_weight": "2 kg", "moves": 80 }, - { "pocket_type": "CONTAINER", "max_contains_volume": "500 ml", "max_contains_weight": "1 kg", "moves": 120 }, - { "pocket_type": "CONTAINER", "max_contains_volume": "500 ml", "max_contains_weight": "1 kg", "moves": 120 } + { + "pocket_type": "CONTAINER", + "max_contains_volume": "1500 ml", + "max_contains_weight": "4 kg", + "max_item_length": "24 cm", + "moves": 80 + }, + { + "pocket_type": "CONTAINER", + "max_contains_volume": "1500 ml", + "max_contains_weight": "4 kg", + "max_item_length": "24 cm", + "moves": 80 + }, + { + "pocket_type": "CONTAINER", + "max_contains_volume": "1 L", + "max_contains_weight": "2 kg", + "max_item_length": "21 cm", + "moves": 80 + }, + { + "pocket_type": "CONTAINER", + "max_contains_volume": "1 L", + "max_contains_weight": "2 kg", + "max_item_length": "21 cm", + "moves": 80 + }, + { + "pocket_type": "CONTAINER", + "max_contains_volume": "800 ml", + "max_contains_weight": "1 kg", + "max_item_length": "13 cm", + "moves": 120 + }, + { + "pocket_type": "CONTAINER", + "max_contains_volume": "800 ml", + "max_contains_weight": "1 kg", + "max_item_length": "13 cm", + "moves": 120 + } ], "warmth": 30, "material_thickness": 1.5, @@ -427,12 +631,48 @@ { "covers": [ "arm_l", "arm_r" ], "coverage": 85, "encumbrance": [ 7, 7 ] } ], "pocket_data": [ - { "pocket_type": "CONTAINER", "max_contains_volume": "3 L", "max_contains_weight": "6 kg", "moves": 80 }, - { "pocket_type": "CONTAINER", "max_contains_volume": "3 L", "max_contains_weight": "6 kg", "moves": 80 }, - { "pocket_type": "CONTAINER", "max_contains_volume": "1 L", "max_contains_weight": "2 kg", "moves": 80 }, - { "pocket_type": "CONTAINER", "max_contains_volume": "1 L", "max_contains_weight": "2 kg", "moves": 80 }, - { "pocket_type": "CONTAINER", "max_contains_volume": "500 ml", "max_contains_weight": "1 kg", "moves": 120 }, - { "pocket_type": "CONTAINER", "max_contains_volume": "500 ml", "max_contains_weight": "1 kg", "moves": 120 } + { + "pocket_type": "CONTAINER", + "max_contains_volume": "3 L", + "max_contains_weight": "6 kg", + "max_item_length": "31 cm", + "moves": 80 + }, + { + "pocket_type": "CONTAINER", + "max_contains_volume": "3 L", + "max_contains_weight": "6 kg", + "max_item_length": "31 cm", + "moves": 80 + }, + { + "pocket_type": "CONTAINER", + "max_contains_volume": "1 L", + "max_contains_weight": "2 kg", + "max_item_length": "25 cm", + "moves": 80 + }, + { + "pocket_type": "CONTAINER", + "max_contains_volume": "1 L", + "max_contains_weight": "2 kg", + "max_item_length": "25 cm", + "moves": 80 + }, + { + "pocket_type": "CONTAINER", + "max_contains_volume": "800 ml", + "max_contains_weight": "1 kg", + "max_item_length": "13 cm", + "moves": 120 + }, + { + "pocket_type": "CONTAINER", + "max_contains_volume": "800 ml", + "max_contains_weight": "1 kg", + "max_item_length": "13 cm", + "moves": 120 + } ], "warmth": 10, "material_thickness": 3, @@ -468,10 +708,34 @@ { "covers": [ "arm_l", "arm_r" ], "coverage": 95, "encumbrance": [ 11, 11 ] } ], "pocket_data": [ - { "pocket_type": "CONTAINER", "max_contains_volume": "1750 ml", "max_contains_weight": "4 kg", "moves": 80 }, - { "pocket_type": "CONTAINER", "max_contains_volume": "1750 ml", "max_contains_weight": "4 kg", "moves": 80 }, - { "pocket_type": "CONTAINER", "max_contains_volume": "750 ml", "max_contains_weight": "2 kg", "moves": 120 }, - { "pocket_type": "CONTAINER", "max_contains_volume": "750 ml", "max_contains_weight": "2 kg", "moves": 120 } + { + "pocket_type": "CONTAINER", + "max_contains_volume": "1750 ml", + "max_contains_weight": "4 kg", + "max_item_length": "24 cm", + "moves": 80 + }, + { + "pocket_type": "CONTAINER", + "max_contains_volume": "1750 ml", + "max_contains_weight": "4 kg", + "max_item_length": "24 cm", + "moves": 80 + }, + { + "pocket_type": "CONTAINER", + "max_contains_volume": "900 ml", + "max_contains_weight": "2 kg", + "max_item_length": "13 cm", + "moves": 120 + }, + { + "pocket_type": "CONTAINER", + "max_contains_volume": "900 ml", + "max_contains_weight": "2 kg", + "max_item_length": "13 cm", + "moves": 120 + } ], "warmth": 50, "material_thickness": 4, @@ -540,8 +804,20 @@ { "covers": [ "arm_l", "arm_r" ], "coverage": 85, "encumbrance": [ 5, 5 ] } ], "pocket_data": [ - { "pocket_type": "CONTAINER", "max_contains_volume": "750 ml", "max_contains_weight": "2 kg", "moves": 80 }, - { "pocket_type": "CONTAINER", "max_contains_volume": "750 ml", "max_contains_weight": "2 kg", "moves": 80 } + { + "pocket_type": "CONTAINER", + "max_contains_volume": "750 ml", + "max_contains_weight": "2 kg", + "max_item_length": "13 cm", + "moves": 80 + }, + { + "pocket_type": "CONTAINER", + "max_contains_volume": "750 ml", + "max_contains_weight": "2 kg", + "max_item_length": "13 cm", + "moves": 80 + } ], "warmth": 20, "material_thickness": 2, @@ -567,12 +843,48 @@ { "covers": [ "arm_l", "arm_r" ], "coverage": 95, "encumbrance": [ 7, 9 ] } ], "pocket_data": [ - { "pocket_type": "CONTAINER", "max_contains_volume": "1 L", "max_contains_weight": "2 kg", "moves": 80 }, - { "pocket_type": "CONTAINER", "max_contains_volume": "1 L", "max_contains_weight": "2 kg", "moves": 80 }, - { "pocket_type": "CONTAINER", "max_contains_volume": "750 ml", "max_contains_weight": "2 kg", "moves": 80 }, - { "pocket_type": "CONTAINER", "max_contains_volume": "750 ml", "max_contains_weight": "2 kg", "moves": 80 }, - { "pocket_type": "CONTAINER", "max_contains_volume": "500 ml", "max_contains_weight": "1 kg", "moves": 120 }, - { "pocket_type": "CONTAINER", "max_contains_volume": "500 ml", "max_contains_weight": "1 kg", "moves": 120 } + { + "pocket_type": "CONTAINER", + "max_contains_volume": "1 L", + "max_contains_weight": "2 kg", + "max_item_length": "15 cm", + "moves": 80 + }, + { + "pocket_type": "CONTAINER", + "max_contains_volume": "1 L", + "max_contains_weight": "2 kg", + "max_item_length": "15 cm", + "moves": 80 + }, + { + "pocket_type": "CONTAINER", + "max_contains_volume": "900 ml", + "max_contains_weight": "2 kg", + "max_item_length": "15 cm", + "moves": 80 + }, + { + "pocket_type": "CONTAINER", + "max_contains_volume": "900 ml", + "max_contains_weight": "2 kg", + "max_item_length": "15 cm", + "moves": 80 + }, + { + "pocket_type": "CONTAINER", + "max_contains_volume": "500 ml", + "max_contains_weight": "1 kg", + "max_item_length": "13 cm", + "moves": 120 + }, + { + "pocket_type": "CONTAINER", + "max_contains_volume": "500 ml", + "max_contains_weight": "1 kg", + "max_item_length": "13 cm", + "moves": 120 + } ], "warmth": 20, "material_thickness": 0.3, @@ -597,7 +909,15 @@ { "covers": [ "torso" ], "coverage": 95, "encumbrance": [ 8, 13 ] }, { "covers": [ "arm_l", "arm_r" ], "coverage": 95, "encumbrance": [ 8, 8 ] } ], - "pocket_data": [ { "pocket_type": "CONTAINER", "max_contains_volume": "1250 ml", "max_contains_weight": "2 kg", "moves": 80 } ], + "pocket_data": [ + { + "pocket_type": "CONTAINER", + "max_contains_volume": "1250 ml", + "max_contains_weight": "2 kg", + "max_item_length": "13 cm", + "moves": 80 + } + ], "warmth": 25, "material_thickness": 0.4, "flags": [ "OUTER", "VARSIZE" ] @@ -621,8 +941,20 @@ { "covers": [ "arm_l", "arm_r" ], "coverage": 90, "encumbrance": [ 13, 13 ] } ], "pocket_data": [ - { "pocket_type": "CONTAINER", "max_contains_volume": "350 ml", "max_contains_weight": "1 kg", "moves": 80 }, - { "pocket_type": "CONTAINER", "max_contains_volume": "350 ml", "max_contains_weight": "1 kg", "moves": 80 } + { + "pocket_type": "CONTAINER", + "max_contains_volume": "800 ml", + "max_contains_weight": "1 kg", + "max_item_length": "13 cm", + "moves": 80 + }, + { + "pocket_type": "CONTAINER", + "max_contains_volume": "800 ml", + "max_contains_weight": "1 kg", + "max_item_length": "13 cm", + "moves": 80 + } ], "warmth": 25, "material_thickness": 0.15, @@ -647,8 +979,20 @@ { "covers": [ "arm_l", "arm_r" ], "coverage": 90, "encumbrance": [ 9, 9 ] } ], "pocket_data": [ - { "pocket_type": "CONTAINER", "max_contains_volume": "500 ml", "max_contains_weight": "2 kg", "moves": 80 }, - { "pocket_type": "CONTAINER", "max_contains_volume": "500 ml", "max_contains_weight": "2 kg", "moves": 80 } + { + "pocket_type": "CONTAINER", + "max_contains_volume": "800 ml", + "max_contains_weight": "2 kg", + "max_item_length": "13 cm", + "moves": 80 + }, + { + "pocket_type": "CONTAINER", + "max_contains_volume": "800 ml", + "max_contains_weight": "2 kg", + "max_item_length": "13 cm", + "moves": 80 + } ], "warmth": 35, "material_thickness": 0.2, @@ -673,8 +1017,20 @@ { "covers": [ "arm_l", "arm_r" ], "coverage": 90, "encumbrance": [ 9, 9 ] } ], "pocket_data": [ - { "pocket_type": "CONTAINER", "max_contains_volume": "350 ml", "max_contains_weight": "1 kg", "moves": 80 }, - { "pocket_type": "CONTAINER", "max_contains_volume": "350 ml", "max_contains_weight": "1 kg", "moves": 80 } + { + "pocket_type": "CONTAINER", + "max_contains_volume": "800 ml", + "max_contains_weight": "1 kg", + "max_item_length": "13 cm", + "moves": 80 + }, + { + "pocket_type": "CONTAINER", + "max_contains_volume": "800 ml", + "max_contains_weight": "1 kg", + "max_item_length": "13 cm", + "moves": 80 + } ], "warmth": 30, "material_thickness": 0.2, @@ -705,8 +1061,20 @@ { "covers": [ "arm_l", "arm_r" ], "coverage": 90, "encumbrance": [ 10, 10 ] } ], "pocket_data": [ - { "pocket_type": "CONTAINER", "max_contains_volume": "700 ml", "max_contains_weight": "3 kg", "moves": 80 }, - { "pocket_type": "CONTAINER", "max_contains_volume": "700 ml", "max_contains_weight": "3 kg", "moves": 80 } + { + "pocket_type": "CONTAINER", + "max_contains_volume": "800 ml", + "max_item_length": "13 cm", + "max_contains_weight": "3 kg", + "moves": 80 + }, + { + "pocket_type": "CONTAINER", + "max_contains_volume": "800 ml", + "max_item_length": "13 cm", + "max_contains_weight": "3 kg", + "moves": 80 + } ], "warmth": 30, "material_thickness": 1.5, @@ -734,8 +1102,20 @@ { "covers": [ "arm_l", "arm_r" ], "coverage": 90, "encumbrance": [ 15, 15 ] } ], "pocket_data": [ - { "pocket_type": "CONTAINER", "max_contains_volume": "700 ml", "max_contains_weight": "3 kg", "moves": 80 }, - { "pocket_type": "CONTAINER", "max_contains_volume": "700 ml", "max_contains_weight": "3 kg", "moves": 80 } + { + "pocket_type": "CONTAINER", + "max_contains_volume": "800 ml", + "max_contains_weight": "3 kg", + "max_item_length": "13 cm", + "moves": 80 + }, + { + "pocket_type": "CONTAINER", + "max_contains_volume": "800 ml", + "max_contains_weight": "3 kg", + "max_item_length": "13 cm", + "moves": 80 + } ], "warmth": 30, "material_thickness": 1.0, @@ -762,8 +1142,20 @@ { "covers": [ "arm_l", "arm_r" ], "coverage": 90, "encumbrance": [ 4, 4 ] } ], "pocket_data": [ - { "pocket_type": "CONTAINER", "max_contains_volume": "700 ml", "max_contains_weight": "3 kg", "moves": 80 }, - { "pocket_type": "CONTAINER", "max_contains_volume": "700 ml", "max_contains_weight": "3 kg", "moves": 80 } + { + "pocket_type": "CONTAINER", + "max_contains_volume": "700 ml", + "max_contains_weight": "3 kg", + "max_item_length": "14 cm", + "moves": 80 + }, + { + "pocket_type": "CONTAINER", + "max_contains_volume": "700 ml", + "max_contains_weight": "3 kg", + "max_item_length": "14 cm", + "moves": 80 + } ], "warmth": 15, "material_thickness": 0.5, @@ -788,9 +1180,27 @@ { "covers": [ "arm_l", "arm_r" ], "coverage": 90, "encumbrance": [ 6, 7 ] } ], "pocket_data": [ - { "pocket_type": "CONTAINER", "max_contains_volume": "1 L", "max_contains_weight": "3 kg", "moves": 80 }, - { "pocket_type": "CONTAINER", "max_contains_volume": "350 ml", "max_contains_weight": "3 kg", "moves": 80 }, - { "pocket_type": "CONTAINER", "max_contains_volume": "350 ml", "max_contains_weight": "3 kg", "moves": 80 } + { + "pocket_type": "CONTAINER", + "max_contains_volume": "1300 ml", + "max_contains_weight": "3 kg", + "max_item_length": "21 cm", + "moves": 80 + }, + { + "pocket_type": "CONTAINER", + "max_contains_volume": "800 ml", + "max_contains_weight": "3 kg", + "max_item_length": "13 cm", + "moves": 80 + }, + { + "pocket_type": "CONTAINER", + "max_contains_volume": "800 ml", + "max_contains_weight": "3 kg", + "max_item_length": "13 cm", + "moves": 80 + } ], "warmth": 25, "material_thickness": 0.3, @@ -922,8 +1332,13 @@ { "covers": [ "arm_l", "arm_r" ], "coverage": 90, "encumbrance": [ 2, 2 ] } ], "pocket_data": [ - { "pocket_type": "CONTAINER", "max_contains_volume": "500 ml", "max_contains_weight": "3 kg", "moves": 80 }, - { "pocket_type": "CONTAINER", "max_contains_volume": "500 ml", "max_contains_weight": "3 kg", "moves": 80 } + { + "pocket_type": "CONTAINER", + "max_contains_volume": "500 ml", + "max_contains_weight": "1 kg", + "max_item_length": "13 cm", + "moves": 80 + } ], "warmth": 20, "material_thickness": 0.2, @@ -949,8 +1364,13 @@ { "covers": [ "arm_l", "arm_r" ], "coverage": 80, "encumbrance": [ 1, 1 ] } ], "pocket_data": [ - { "pocket_type": "CONTAINER", "max_contains_volume": "500 ml", "max_contains_weight": "3 kg", "moves": 80 }, - { "pocket_type": "CONTAINER", "max_contains_volume": "500 ml", "max_contains_weight": "3 kg", "moves": 80 } + { + "pocket_type": "CONTAINER", + "max_contains_volume": "500 ml", + "max_contains_weight": "1 kg", + "max_item_length": "13 cm", + "moves": 80 + } ], "warmth": 5, "material_thickness": 0.15, @@ -1018,10 +1438,34 @@ { "covers": [ "arm_l", "arm_r" ], "coverage": 85, "encumbrance": [ 10, 10 ] } ], "pocket_data": [ - { "pocket_type": "CONTAINER", "max_contains_volume": "1500 ml", "max_contains_weight": "2 kg", "moves": 80 }, - { "pocket_type": "CONTAINER", "max_contains_volume": "1500 ml", "max_contains_weight": "2 kg", "moves": 80 }, - { "pocket_type": "CONTAINER", "max_contains_volume": "250 ml", "max_contains_weight": "1 kg", "moves": 120 }, - { "pocket_type": "CONTAINER", "max_contains_volume": "250 ml", "max_contains_weight": "1 kg", "moves": 120 } + { + "pocket_type": "CONTAINER", + "max_contains_volume": "1500 ml", + "max_contains_weight": "2 kg", + "max_item_length": "24 cm", + "moves": 80 + }, + { + "pocket_type": "CONTAINER", + "max_contains_volume": "1500 ml", + "max_contains_weight": "2 kg", + "max_item_length": "24 cm", + "moves": 80 + }, + { + "pocket_type": "CONTAINER", + "max_contains_volume": "800 ml", + "max_contains_weight": "1 kg", + "max_item_length": "13 cm", + "moves": 120 + }, + { + "pocket_type": "CONTAINER", + "max_contains_volume": "800 ml", + "max_contains_weight": "1 kg", + "max_item_length": "13 cm", + "moves": 120 + } ], "warmth": 50, "material_thickness": 1.0, @@ -1049,12 +1493,48 @@ { "covers": [ "arm_l", "arm_r" ], "coverage": 80, "encumbrance": [ 8, 8 ] } ], "pocket_data": [ - { "pocket_type": "CONTAINER", "max_contains_volume": "500 ml", "max_contains_weight": "2 kg", "moves": 120 }, - { "pocket_type": "CONTAINER", "max_contains_volume": "500 ml", "max_contains_weight": "2 kg", "moves": 120 }, - { "pocket_type": "CONTAINER", "max_contains_volume": "500 ml", "max_contains_weight": "2 kg", "moves": 120 }, - { "pocket_type": "CONTAINER", "max_contains_volume": "500 ml", "max_contains_weight": "2 kg", "moves": 120 }, - { "pocket_type": "CONTAINER", "max_contains_volume": "500 ml", "max_contains_weight": "2 kg", "moves": 120 }, - { "pocket_type": "CONTAINER", "max_contains_volume": "500 ml", "max_contains_weight": "1 kg", "moves": 120 } + { + "pocket_type": "CONTAINER", + "max_contains_volume": "800 ml", + "max_contains_weight": "2 kg", + "max_item_length": "13 cm", + "moves": 120 + }, + { + "pocket_type": "CONTAINER", + "max_contains_volume": "800 ml", + "max_contains_weight": "2 kg", + "max_item_length": "13 cm", + "moves": 120 + }, + { + "pocket_type": "CONTAINER", + "max_contains_volume": "800 ml", + "max_contains_weight": "2 kg", + "max_item_length": "13 cm", + "moves": 120 + }, + { + "pocket_type": "CONTAINER", + "max_contains_volume": "800 ml", + "max_contains_weight": "2 kg", + "max_item_length": "13 cm", + "moves": 120 + }, + { + "pocket_type": "CONTAINER", + "max_contains_volume": "800 ml", + "max_contains_weight": "2 kg", + "max_item_length": "13 cm", + "moves": 120 + }, + { + "pocket_type": "CONTAINER", + "max_contains_volume": "800 ml", + "max_contains_weight": "1 kg", + "max_item_length": "13 cm", + "moves": 120 + } ], "warmth": 20, "material_thickness": 2, @@ -1101,10 +1581,34 @@ { "covers": [ "arm_l", "arm_r" ], "coverage": 95, "encumbrance": [ 15, 15 ] } ], "pocket_data": [ - { "pocket_type": "CONTAINER", "max_contains_volume": "700 ml", "max_contains_weight": "2 kg", "moves": 80 }, - { "pocket_type": "CONTAINER", "max_contains_volume": "700 ml", "max_contains_weight": "2 kg", "moves": 80 }, - { "pocket_type": "CONTAINER", "max_contains_volume": "250 ml", "max_contains_weight": "1 kg", "moves": 120 }, - { "pocket_type": "CONTAINER", "max_contains_volume": "250 ml", "max_contains_weight": "1 kg", "moves": 120 } + { + "pocket_type": "CONTAINER", + "max_contains_volume": "1000 ml", + "max_contains_weight": "2 kg", + "max_item_length": "15 cm", + "moves": 80 + }, + { + "pocket_type": "CONTAINER", + "max_contains_volume": "1000 ml", + "max_contains_weight": "2 kg", + "max_item_length": "15 cm", + "moves": 80 + }, + { + "pocket_type": "CONTAINER", + "max_contains_volume": "800 ml", + "max_contains_weight": "1 kg", + "max_item_length": "13 cm", + "moves": 120 + }, + { + "pocket_type": "CONTAINER", + "max_contains_volume": "800 ml", + "max_contains_weight": "1 kg", + "max_item_length": "13 cm", + "moves": 120 + } ], "warmth": 80, "material_thickness": 2, @@ -1132,12 +1636,48 @@ { "covers": [ "leg_l", "leg_r" ], "coverage": 90, "encumbrance": [ 7, 10 ] } ], "pocket_data": [ - { "pocket_type": "CONTAINER", "max_contains_volume": "1500 ml", "max_contains_weight": "4 kg", "moves": 80 }, - { "pocket_type": "CONTAINER", "max_contains_volume": "1500 ml", "max_contains_weight": "4 kg", "moves": 80 }, - { "pocket_type": "CONTAINER", "max_contains_volume": "1 L", "max_contains_weight": "2 kg", "moves": 80 }, - { "pocket_type": "CONTAINER", "max_contains_volume": "1 L", "max_contains_weight": "2 kg", "moves": 80 }, - { "pocket_type": "CONTAINER", "max_contains_volume": "500 ml", "max_contains_weight": "1 kg", "moves": 120 }, - { "pocket_type": "CONTAINER", "max_contains_volume": "500 ml", "max_contains_weight": "1 kg", "moves": 120 } + { + "pocket_type": "CONTAINER", + "max_contains_volume": "1500 ml", + "max_contains_weight": "4 kg", + "max_item_length": "24 cm", + "moves": 80 + }, + { + "pocket_type": "CONTAINER", + "max_contains_volume": "1500 ml", + "max_contains_weight": "4 kg", + "max_item_length": "24 cm", + "moves": 80 + }, + { + "pocket_type": "CONTAINER", + "max_contains_volume": "1 L", + "max_contains_weight": "2 kg", + "max_item_length": "21 cm", + "moves": 80 + }, + { + "pocket_type": "CONTAINER", + "max_contains_volume": "1 L", + "max_contains_weight": "2 kg", + "max_item_length": "21 cm", + "moves": 80 + }, + { + "pocket_type": "CONTAINER", + "max_contains_volume": "800 ml", + "max_contains_weight": "1 kg", + "max_item_length": "13 cm", + "moves": 120 + }, + { + "pocket_type": "CONTAINER", + "max_contains_volume": "800 ml", + "max_contains_weight": "1 kg", + "max_item_length": "13 cm", + "moves": 120 + } ], "warmth": 15, "material_thickness": 0.3, @@ -1164,12 +1704,48 @@ { "covers": [ "leg_l", "leg_r" ], "coverage": 90, "encumbrance": [ 9, 11 ] } ], "pocket_data": [ - { "pocket_type": "CONTAINER", "max_contains_volume": "1500 ml", "max_contains_weight": "4 kg", "moves": 80 }, - { "pocket_type": "CONTAINER", "max_contains_volume": "1500 ml", "max_contains_weight": "4 kg", "moves": 80 }, - { "pocket_type": "CONTAINER", "max_contains_volume": "1 L", "max_contains_weight": "2 kg", "moves": 80 }, - { "pocket_type": "CONTAINER", "max_contains_volume": "1 L", "max_contains_weight": "2 kg", "moves": 80 }, - { "pocket_type": "CONTAINER", "max_contains_volume": "500 ml", "max_contains_weight": "1 kg", "moves": 120 }, - { "pocket_type": "CONTAINER", "max_contains_volume": "500 ml", "max_contains_weight": "1 kg", "moves": 120 } + { + "pocket_type": "CONTAINER", + "max_contains_volume": "1500 ml", + "max_contains_weight": "4 kg", + "max_item_length": "24 cm", + "moves": 80 + }, + { + "pocket_type": "CONTAINER", + "max_contains_volume": "1500 ml", + "max_contains_weight": "4 kg", + "max_item_length": "24 cm", + "moves": 80 + }, + { + "pocket_type": "CONTAINER", + "max_contains_volume": "1 L", + "max_contains_weight": "2 kg", + "max_item_length": "21 cm", + "moves": 80 + }, + { + "pocket_type": "CONTAINER", + "max_contains_volume": "1 L", + "max_contains_weight": "2 kg", + "max_item_length": "21 cm", + "moves": 80 + }, + { + "pocket_type": "CONTAINER", + "max_contains_volume": "800 ml", + "max_contains_weight": "1 kg", + "max_item_length": "13 cm", + "moves": 120 + }, + { + "pocket_type": "CONTAINER", + "max_contains_volume": "800 ml", + "max_contains_weight": "1 kg", + "max_item_length": "13 cm", + "moves": 120 + } ], "warmth": 50, "material_thickness": 0.5, @@ -1207,12 +1783,48 @@ { "covers": [ "leg_l", "leg_r" ], "coverage": 90, "encumbrance": [ 8, 10 ] } ], "pocket_data": [ - { "pocket_type": "CONTAINER", "max_contains_volume": "1500 ml", "max_contains_weight": "4 kg", "moves": 80 }, - { "pocket_type": "CONTAINER", "max_contains_volume": "1500 ml", "max_contains_weight": "4 kg", "moves": 80 }, - { "pocket_type": "CONTAINER", "max_contains_volume": "1 L", "max_contains_weight": "2 kg", "moves": 80 }, - { "pocket_type": "CONTAINER", "max_contains_volume": "1 L", "max_contains_weight": "2 kg", "moves": 80 }, - { "pocket_type": "CONTAINER", "max_contains_volume": "500 ml", "max_contains_weight": "1 kg", "moves": 120 }, - { "pocket_type": "CONTAINER", "max_contains_volume": "500 ml", "max_contains_weight": "1 kg", "moves": 120 } + { + "pocket_type": "CONTAINER", + "max_contains_volume": "1500 ml", + "max_contains_weight": "4 kg", + "max_item_length": "24 cm", + "moves": 80 + }, + { + "pocket_type": "CONTAINER", + "max_contains_volume": "1500 ml", + "max_contains_weight": "4 kg", + "max_item_length": "24 cm", + "moves": 80 + }, + { + "pocket_type": "CONTAINER", + "max_contains_volume": "1 L", + "max_contains_weight": "2 kg", + "max_item_length": "21 cm", + "moves": 80 + }, + { + "pocket_type": "CONTAINER", + "max_contains_volume": "1 L", + "max_contains_weight": "2 kg", + "max_item_length": "21 cm", + "moves": 80 + }, + { + "pocket_type": "CONTAINER", + "max_contains_volume": "800 ml", + "max_contains_weight": "1 kg", + "max_item_length": "13 cm", + "moves": 120 + }, + { + "pocket_type": "CONTAINER", + "max_contains_volume": "800 ml", + "max_contains_weight": "1 kg", + "max_item_length": "13 cm", + "moves": 120 + } ], "warmth": 30, "material_thickness": 1.5, @@ -1564,12 +2176,48 @@ { "covers": [ "arm_l", "arm_r" ], "coverage": 85, "encumbrance": [ 7, 7 ] } ], "pocket_data": [ - { "pocket_type": "CONTAINER", "max_contains_volume": "3 L", "max_contains_weight": "6 kg", "moves": 80 }, - { "pocket_type": "CONTAINER", "max_contains_volume": "3 L", "max_contains_weight": "6 kg", "moves": 80 }, - { "pocket_type": "CONTAINER", "max_contains_volume": "1 L", "max_contains_weight": "2 kg", "moves": 80 }, - { "pocket_type": "CONTAINER", "max_contains_volume": "1 L", "max_contains_weight": "2 kg", "moves": 80 }, - { "pocket_type": "CONTAINER", "max_contains_volume": "500 ml", "max_contains_weight": "1 kg", "moves": 120 }, - { "pocket_type": "CONTAINER", "max_contains_volume": "500 ml", "max_contains_weight": "1 kg", "moves": 120 } + { + "pocket_type": "CONTAINER", + "max_contains_volume": "3 L", + "max_contains_weight": "6 kg", + "max_item_length": "31 cm", + "moves": 80 + }, + { + "pocket_type": "CONTAINER", + "max_contains_volume": "3 L", + "max_contains_weight": "6 kg", + "max_item_length": "31 cm", + "moves": 80 + }, + { + "pocket_type": "CONTAINER", + "max_contains_volume": "1 L", + "max_contains_weight": "2 kg", + "max_item_length": "25 cm", + "moves": 80 + }, + { + "pocket_type": "CONTAINER", + "max_contains_volume": "1 L", + "max_contains_weight": "2 kg", + "max_item_length": "25 cm", + "moves": 80 + }, + { + "pocket_type": "CONTAINER", + "max_contains_volume": "800 ml", + "max_contains_weight": "1 kg", + "max_item_length": "13 cm", + "moves": 120 + }, + { + "pocket_type": "CONTAINER", + "max_contains_volume": "800 ml", + "max_contains_weight": "1 kg", + "max_item_length": "13 cm", + "moves": 120 + } ], "warmth": 10, "material_thickness": 3, @@ -1639,10 +2287,27 @@ { "covers": [ "arm_l", "arm_r" ], "coverage": 95, "encumbrance": [ 13, 13 ] } ], "pocket_data": [ - { "pocket_type": "CONTAINER", "max_contains_volume": "350 ml", "max_contains_weight": "2 kg", "moves": 80 }, - { "pocket_type": "CONTAINER", "max_contains_volume": "350 ml", "max_contains_weight": "2 kg", "moves": 80 }, - { "pocket_type": "CONTAINER", "max_contains_volume": "250 ml", "max_contains_weight": "1 kg", "moves": 120 }, - { "pocket_type": "CONTAINER", "max_contains_volume": "250 ml", "max_contains_weight": "1 kg", "moves": 120 } + { + "pocket_type": "CONTAINER", + "max_contains_volume": "800 ml", + "max_contains_weight": "2 kg", + "max_item_length": "16 cm", + "moves": 80 + }, + { + "pocket_type": "CONTAINER", + "max_contains_volume": "800 ml", + "max_contains_weight": "2 kg", + "max_item_length": "16 cm", + "moves": 80 + }, + { + "pocket_type": "CONTAINER", + "max_contains_volume": "600 ml", + "max_contains_weight": "1 kg", + "max_item_length": "13 cm", + "moves": 120 + } ], "warmth": 30, "material_thickness": 0.5, @@ -1667,10 +2332,27 @@ "encumbrance": 2, "max_encumbrance": 5, "pocket_data": [ - { "pocket_type": "CONTAINER", "max_contains_volume": "500 ml", "max_contains_weight": "2 kg", "moves": 80 }, - { "pocket_type": "CONTAINER", "max_contains_volume": "500 ml", "max_contains_weight": "2 kg", "moves": 80 }, - { "pocket_type": "CONTAINER", "max_contains_volume": "250 ml", "max_contains_weight": "1 kg", "moves": 120 }, - { "pocket_type": "CONTAINER", "max_contains_volume": "250 ml", "max_contains_weight": "1 kg", "moves": 120 } + { + "pocket_type": "CONTAINER", + "max_contains_volume": "800 ml", + "max_contains_weight": "2 kg", + "max_item_length": "16 cm", + "moves": 80 + }, + { + "pocket_type": "CONTAINER", + "max_contains_volume": "800 ml", + "max_contains_weight": "2 kg", + "max_item_length": "16 cm", + "moves": 80 + }, + { + "pocket_type": "CONTAINER", + "max_contains_volume": "600 ml", + "max_contains_weight": "1 kg", + "max_item_length": "13 cm", + "moves": 120 + } ], "warmth": 5, "material_thickness": 0.5, @@ -1695,12 +2377,48 @@ { "covers": [ "arm_l", "arm_r" ], "coverage": 95, "encumbrance": [ 10, 10 ] } ], "pocket_data": [ - { "pocket_type": "CONTAINER", "max_contains_volume": "1 L", "max_contains_weight": "3 kg", "moves": 80 }, - { "pocket_type": "CONTAINER", "max_contains_volume": "1 L", "max_contains_weight": "3 kg", "moves": 80 }, - { "pocket_type": "CONTAINER", "max_contains_volume": "1 L", "max_contains_weight": "3 kg", "moves": 80 }, - { "pocket_type": "CONTAINER", "max_contains_volume": "1 L", "max_contains_weight": "3 kg", "moves": 80 }, - { "pocket_type": "CONTAINER", "max_contains_volume": "500 ml", "max_contains_weight": "1 kg", "moves": 120 }, - { "pocket_type": "CONTAINER", "max_contains_volume": "500 ml", "max_contains_weight": "1 kg", "moves": 120 } + { + "pocket_type": "CONTAINER", + "max_contains_volume": "1 L", + "max_contains_weight": "2 kg", + "max_item_length": "15 cm", + "moves": 80 + }, + { + "pocket_type": "CONTAINER", + "max_contains_volume": "1 L", + "max_contains_weight": "2 kg", + "max_item_length": "15 cm", + "moves": 80 + }, + { + "pocket_type": "CONTAINER", + "max_contains_volume": "900 ml", + "max_contains_weight": "2 kg", + "max_item_length": "15 cm", + "moves": 80 + }, + { + "pocket_type": "CONTAINER", + "max_contains_volume": "900 ml", + "max_contains_weight": "2 kg", + "max_item_length": "15 cm", + "moves": 80 + }, + { + "pocket_type": "CONTAINER", + "max_contains_volume": "500 ml", + "max_contains_weight": "1 kg", + "max_item_length": "13 cm", + "moves": 120 + }, + { + "pocket_type": "CONTAINER", + "max_contains_volume": "500 ml", + "max_contains_weight": "1 kg", + "max_item_length": "13 cm", + "moves": 120 + } ], "warmth": 50, "material_thickness": 1, diff --git a/data/json/items/armor/legs_armor.json b/data/json/items/armor/legs_armor.json index 0efcba5f75190..60502c2801cd6 100644 --- a/data/json/items/armor/legs_armor.json +++ b/data/json/items/armor/legs_armor.json @@ -79,10 +79,34 @@ "encumbrance": 24, "max_encumbrance": 30, "pocket_data": [ - { "pocket_type": "CONTAINER", "max_contains_volume": "500 ml", "max_contains_weight": "1 kg", "moves": 80 }, - { "pocket_type": "CONTAINER", "max_contains_volume": "500 ml", "max_contains_weight": "1 kg", "moves": 80 }, - { "pocket_type": "CONTAINER", "max_contains_volume": "250 ml", "max_contains_weight": "1 kg", "moves": 100 }, - { "pocket_type": "CONTAINER", "max_contains_volume": "250 ml", "max_contains_weight": "1 kg", "moves": 100 } + { + "pocket_type": "CONTAINER", + "max_contains_volume": "3250 ml", + "max_contains_weight": "4 kg", + "max_item_length": "30 cm", + "moves": 80 + }, + { + "pocket_type": "CONTAINER", + "max_contains_volume": "3250 ml", + "max_contains_weight": "4 kg", + "max_item_length": "30 cm", + "moves": 80 + }, + { + "pocket_type": "CONTAINER", + "max_contains_volume": "800 ml", + "max_contains_weight": "2 kg", + "max_item_length": "16 cm", + "moves": 100 + }, + { + "pocket_type": "CONTAINER", + "max_contains_volume": "800 ml", + "max_contains_weight": "2 kg", + "max_item_length": "16 cm", + "moves": 100 + } ], "warmth": 30, "material_thickness": 2, @@ -171,8 +195,20 @@ "encumbrance": 13, "max_encumbrance": 15, "pocket_data": [ - { "pocket_type": "CONTAINER", "max_contains_volume": "250 ml", "max_contains_weight": "1 kg", "moves": 100 }, - { "pocket_type": "CONTAINER", "max_contains_volume": "250 ml", "max_contains_weight": "1 kg", "moves": 100 } + { + "pocket_type": "CONTAINER", + "max_contains_volume": "800 ml", + "max_contains_weight": "1 kg", + "max_item_length": "13 cm", + "moves": 100 + }, + { + "pocket_type": "CONTAINER", + "max_contains_volume": "800 ml", + "max_contains_weight": "1 kg", + "max_item_length": "13 cm", + "moves": 100 + } ], "warmth": 20, "material_thickness": 2, @@ -388,12 +424,48 @@ "encumbrance": 8, "max_encumbrance": 16, "pocket_data": [ - { "pocket_type": "CONTAINER", "max_contains_volume": "700 ml", "max_contains_weight": "2 kg", "moves": 80 }, - { "pocket_type": "CONTAINER", "max_contains_volume": "700 ml", "max_contains_weight": "2 kg", "moves": 80 }, - { "pocket_type": "CONTAINER", "max_contains_volume": "500 ml", "max_contains_weight": "1 kg", "moves": 100 }, - { "pocket_type": "CONTAINER", "max_contains_volume": "500 ml", "max_contains_weight": "1 kg", "moves": 100 }, - { "pocket_type": "CONTAINER", "max_contains_volume": "250 ml", "max_contains_weight": "1 kg", "moves": 100 }, - { "pocket_type": "CONTAINER", "max_contains_volume": "250 ml", "max_contains_weight": "1 kg", "moves": 100 } + { + "pocket_type": "CONTAINER", + "max_contains_volume": "1000 ml", + "max_contains_weight": "2 kg", + "max_item_length": "21 cm", + "moves": 80 + }, + { + "pocket_type": "CONTAINER", + "max_contains_volume": "1000 ml", + "max_contains_weight": "2 kg", + "max_item_length": "21 cm", + "moves": 80 + }, + { + "pocket_type": "CONTAINER", + "max_contains_volume": "800 ml", + "max_contains_weight": "1 kg", + "max_item_length": "15 cm", + "moves": 100 + }, + { + "pocket_type": "CONTAINER", + "max_contains_volume": "800 ml", + "max_contains_weight": "1 kg", + "max_item_length": "15 cm", + "moves": 100 + }, + { + "pocket_type": "CONTAINER", + "max_contains_volume": "500 ml", + "max_contains_weight": "1 kg", + "max_item_length": "13 cm", + "moves": 100 + }, + { + "pocket_type": "CONTAINER", + "max_contains_volume": "500 ml", + "max_contains_weight": "1 kg", + "max_item_length": "13 cm", + "moves": 100 + } ], "warmth": 12, "material_thickness": 3, @@ -450,14 +522,62 @@ "encumbrance": 10, "max_encumbrance": 20, "pocket_data": [ - { "pocket_type": "CONTAINER", "max_contains_volume": "1 L", "max_contains_weight": "3 kg", "moves": 80 }, - { "pocket_type": "CONTAINER", "max_contains_volume": "1 L", "max_contains_weight": "3 kg", "moves": 80 }, - { "pocket_type": "CONTAINER", "max_contains_volume": "500 ml", "max_contains_weight": "2 kg", "moves": 80 }, - { "pocket_type": "CONTAINER", "max_contains_volume": "500 ml", "max_contains_weight": "2 kg", "moves": 80 }, - { "pocket_type": "CONTAINER", "max_contains_volume": "500 ml", "max_contains_weight": "2 kg", "moves": 80 }, - { "pocket_type": "CONTAINER", "max_contains_volume": "500 ml", "max_contains_weight": "2 kg", "moves": 80 }, - { "pocket_type": "CONTAINER", "max_contains_volume": "250 ml", "max_contains_weight": "1 kg", "moves": 100 }, - { "pocket_type": "CONTAINER", "max_contains_volume": "250 ml", "max_contains_weight": "1 kg", "moves": 100 } + { + "pocket_type": "CONTAINER", + "max_contains_volume": "1250 ml", + "max_contains_weight": "3 kg", + "max_item_length": "21 cm", + "moves": 80 + }, + { + "pocket_type": "CONTAINER", + "max_contains_volume": "1250 ml", + "max_contains_weight": "3 kg", + "max_item_length": "21 cm", + "moves": 80 + }, + { + "pocket_type": "CONTAINER", + "max_contains_volume": "800 ml", + "max_contains_weight": "2 kg", + "max_item_length": "15 cm", + "moves": 80 + }, + { + "pocket_type": "CONTAINER", + "max_contains_volume": "800 ml", + "max_contains_weight": "2 kg", + "max_item_length": "15 cm", + "moves": 80 + }, + { + "pocket_type": "CONTAINER", + "max_contains_volume": "800 ml", + "max_contains_weight": "2 kg", + "max_item_length": "15 cm", + "moves": 80 + }, + { + "pocket_type": "CONTAINER", + "max_contains_volume": "800 ml", + "max_contains_weight": "2 kg", + "max_item_length": "15 cm", + "moves": 80 + }, + { + "pocket_type": "CONTAINER", + "max_contains_volume": "500 ml", + "max_contains_weight": "1 kg", + "max_item_length": "13 cm", + "moves": 100 + }, + { + "pocket_type": "CONTAINER", + "max_contains_volume": "500 ml", + "max_contains_weight": "1 kg", + "max_item_length": "13 cm", + "moves": 100 + } ], "warmth": 15, "material_thickness": 4, diff --git a/data/json/items/armor/legs_clothes.json b/data/json/items/armor/legs_clothes.json index 9f84fca637a46..c12b2be167269 100644 --- a/data/json/items/armor/legs_clothes.json +++ b/data/json/items/armor/legs_clothes.json @@ -18,10 +18,13 @@ "encumbrance": 7, "max_encumbrance": 11, "pocket_data": [ - { "pocket_type": "CONTAINER", "max_contains_volume": "350 ml", "max_contains_weight": "1 kg", "moves": 80 }, - { "pocket_type": "CONTAINER", "max_contains_volume": "350 ml", "max_contains_weight": "1 kg", "moves": 80 }, - { "pocket_type": "CONTAINER", "max_contains_volume": "250 ml", "max_contains_weight": "1 kg", "moves": 100 }, - { "pocket_type": "CONTAINER", "max_contains_volume": "250 ml", "max_contains_weight": "1 kg", "moves": 100 } + { + "pocket_type": "CONTAINER", + "max_contains_volume": "500 ml", + "max_contains_weight": "1 kg", + "max_item_length": "165 mm", + "moves": 400 + } ], "warmth": 8, "material_thickness": 0.3, @@ -45,8 +48,20 @@ "covers": [ "leg_l", "leg_r" ], "coverage": 50, "pocket_data": [ - { "pocket_type": "CONTAINER", "max_contains_volume": "500 ml", "max_contains_weight": "1 kg", "moves": 80 }, - { "pocket_type": "CONTAINER", "max_contains_volume": "500 ml", "max_contains_weight": "1 kg", "moves": 80 } + { + "pocket_type": "CONTAINER", + "max_contains_volume": "1000 ml", + "max_contains_weight": "3 kg", + "max_item_length": "17 cm", + "moves": 80 + }, + { + "pocket_type": "CONTAINER", + "max_contains_volume": "1000 ml", + "max_contains_weight": "3 kg", + "max_item_length": "17 cm", + "moves": 80 + } ], "warmth": 5, "material_thickness": 0.1, @@ -93,10 +108,13 @@ { "covers": [ "foot_l", "foot_r" ], "coverage": 100, "encumbrance": [ 19, 19 ] } ], "pocket_data": [ - { "pocket_type": "CONTAINER", "max_contains_volume": "500 ml", "max_contains_weight": "1 kg", "moves": 80 }, - { "pocket_type": "CONTAINER", "max_contains_volume": "500 ml", "max_contains_weight": "1 kg", "moves": 80 }, - { "pocket_type": "CONTAINER", "max_contains_volume": "250 ml", "max_contains_weight": "1 kg", "moves": 100 }, - { "pocket_type": "CONTAINER", "max_contains_volume": "250 ml", "max_contains_weight": "1 kg", "moves": 100 } + { + "pocket_type": "CONTAINER", + "max_contains_volume": "1600 ml", + "max_contains_weight": "4 kg", + "max_item_length": "18 cm", + "moves": 80 + } ], "warmth": 5, "material_thickness": 2, @@ -178,10 +196,34 @@ "encumbrance": 12, "max_encumbrance": 16, "pocket_data": [ - { "pocket_type": "CONTAINER", "max_contains_volume": "350 ml", "max_contains_weight": "1 kg", "moves": 80 }, - { "pocket_type": "CONTAINER", "max_contains_volume": "350 ml", "max_contains_weight": "1 kg", "moves": 80 }, - { "pocket_type": "CONTAINER", "max_contains_volume": "250 ml", "max_contains_weight": "1 kg", "moves": 100 }, - { "pocket_type": "CONTAINER", "max_contains_volume": "250 ml", "max_contains_weight": "1 kg", "moves": 100 } + { + "pocket_type": "CONTAINER", + "max_contains_volume": "1250 ml", + "max_contains_weight": "4 kg", + "max_item_length": "19 cm", + "moves": 80 + }, + { + "pocket_type": "CONTAINER", + "max_contains_volume": "1250 ml", + "max_contains_weight": "4 kg", + "max_item_length": "19 cm", + "moves": 80 + }, + { + "pocket_type": "CONTAINER", + "max_contains_volume": "1080 ml", + "max_contains_weight": "4 kg", + "max_item_length": "165 mm", + "moves": 100 + }, + { + "pocket_type": "CONTAINER", + "max_contains_volume": "1080 ml", + "max_contains_weight": "4 kg", + "max_item_length": "165 mm", + "moves": 100 + } ], "warmth": 10, "material_thickness": 0.25, @@ -207,10 +249,34 @@ "encumbrance": 12, "max_encumbrance": 16, "pocket_data": [ - { "pocket_type": "CONTAINER", "max_contains_volume": "350 ml", "max_contains_weight": "1 kg", "moves": 80 }, - { "pocket_type": "CONTAINER", "max_contains_volume": "350 ml", "max_contains_weight": "1 kg", "moves": 80 }, - { "pocket_type": "CONTAINER", "max_contains_volume": "250 ml", "max_contains_weight": "1 kg", "moves": 100 }, - { "pocket_type": "CONTAINER", "max_contains_volume": "250 ml", "max_contains_weight": "1 kg", "moves": 100 } + { + "pocket_type": "CONTAINER", + "max_contains_volume": "1250 ml", + "max_contains_weight": "4 kg", + "max_item_length": "19 cm", + "moves": 80 + }, + { + "pocket_type": "CONTAINER", + "max_contains_volume": "1250 ml", + "max_contains_weight": "4 kg", + "max_item_length": "19 cm", + "moves": 80 + }, + { + "pocket_type": "CONTAINER", + "max_contains_volume": "1080 ml", + "max_contains_weight": "4 kg", + "max_item_length": "165 mm", + "moves": 100 + }, + { + "pocket_type": "CONTAINER", + "max_contains_volume": "1080 ml", + "max_contains_weight": "4 kg", + "max_item_length": "165 mm", + "moves": 100 + } ], "warmth": 10, "material_thickness": 0.25, @@ -231,7 +297,15 @@ "color": "dark_gray", "covers": [ "leg_l", "leg_r" ], "coverage": 50, - "pocket_data": [ { "pocket_type": "CONTAINER", "max_contains_volume": "250 ml", "max_contains_weight": "1 kg", "moves": 80 } ], + "pocket_data": [ + { + "pocket_type": "CONTAINER", + "max_contains_volume": "1000 ml", + "max_contains_weight": "3 kg", + "max_item_length": "19 cm", + "moves": 80 + } + ], "warmth": 20, "material_thickness": 0.3, "flags": [ "VARSIZE" ] @@ -251,7 +325,15 @@ "color": "dark_gray", "covers": [ "leg_l", "leg_r" ], "coverage": 50, - "pocket_data": [ { "pocket_type": "CONTAINER", "max_contains_volume": "250 ml", "max_contains_weight": "1 kg", "moves": 80 } ], + "pocket_data": [ + { + "pocket_type": "CONTAINER", + "max_contains_volume": "1000 ml", + "max_contains_weight": "3 kg", + "max_item_length": "19 cm", + "moves": 80 + } + ], "warmth": 10, "material_thickness": 1.5, "flags": [ "VARSIZE" ] @@ -388,10 +470,34 @@ "encumbrance": 7, "max_encumbrance": 11, "pocket_data": [ - { "pocket_type": "CONTAINER", "max_contains_volume": "350 ml", "max_contains_weight": "1 kg", "moves": 80 }, - { "pocket_type": "CONTAINER", "max_contains_volume": "350 ml", "max_contains_weight": "1 kg", "moves": 80 }, - { "pocket_type": "CONTAINER", "max_contains_volume": "250 ml", "max_contains_weight": "1 kg", "moves": 100 }, - { "pocket_type": "CONTAINER", "max_contains_volume": "250 ml", "max_contains_weight": "1 kg", "moves": 100 } + { + "pocket_type": "CONTAINER", + "max_contains_volume": "1250 ml", + "max_contains_weight": "4 kg", + "max_item_length": "19 cm", + "moves": 80 + }, + { + "pocket_type": "CONTAINER", + "max_contains_volume": "1250 ml", + "max_contains_weight": "4 kg", + "max_item_length": "19 cm", + "moves": 80 + }, + { + "pocket_type": "CONTAINER", + "max_contains_volume": "1080 ml", + "max_contains_weight": "4 kg", + "max_item_length": "165 mm", + "moves": 100 + }, + { + "pocket_type": "CONTAINER", + "max_contains_volume": "1080 ml", + "max_contains_weight": "4 kg", + "max_item_length": "165 mm", + "moves": 100 + } ], "warmth": 15, "material_thickness": 0.2, @@ -416,12 +522,48 @@ "encumbrance": 9, "max_encumbrance": 18, "pocket_data": [ - { "pocket_type": "CONTAINER", "max_contains_volume": "700 ml", "max_contains_weight": "3 kg", "moves": 80 }, - { "pocket_type": "CONTAINER", "max_contains_volume": "700 ml", "max_contains_weight": "3 kg", "moves": 80 }, - { "pocket_type": "CONTAINER", "max_contains_volume": "500 ml", "max_contains_weight": "2 kg", "moves": 100 }, - { "pocket_type": "CONTAINER", "max_contains_volume": "500 ml", "max_contains_weight": "2 kg", "moves": 100 }, - { "pocket_type": "CONTAINER", "max_contains_volume": "500 ml", "max_contains_weight": "3 kg", "moves": 120 }, - { "pocket_type": "CONTAINER", "max_contains_volume": "500 ml", "max_contains_weight": "3 kg", "moves": 120 } + { + "pocket_type": "CONTAINER", + "max_contains_volume": "1250 ml", + "max_contains_weight": "4 kg", + "max_item_length": "19 cm", + "moves": 80 + }, + { + "pocket_type": "CONTAINER", + "max_contains_volume": "1250 ml", + "max_contains_weight": "4 kg", + "max_item_length": "19 cm", + "moves": 80 + }, + { + "pocket_type": "CONTAINER", + "max_contains_volume": "1250 ml", + "max_contains_weight": "4 kg", + "max_item_length": "19 cm", + "moves": 80 + }, + { + "pocket_type": "CONTAINER", + "max_contains_volume": "1250 ml", + "max_contains_weight": "4 kg", + "max_item_length": "19 cm", + "moves": 80 + }, + { + "pocket_type": "CONTAINER", + "max_contains_volume": "1080 ml", + "max_contains_weight": "4 kg", + "max_item_length": "165 mm", + "moves": 100 + }, + { + "pocket_type": "CONTAINER", + "max_contains_volume": "1080 ml", + "max_contains_weight": "4 kg", + "max_item_length": "165 mm", + "moves": 100 + } ], "warmth": 20, "material_thickness": 0.25, @@ -445,14 +587,48 @@ "encumbrance": 8, "max_encumbrance": 16, "pocket_data": [ - { "pocket_type": "CONTAINER", "max_contains_volume": "700 ml", "max_contains_weight": "3 kg", "moves": 80 }, - { "pocket_type": "CONTAINER", "max_contains_volume": "700 ml", "max_contains_weight": "3 kg", "moves": 80 }, - { "pocket_type": "CONTAINER", "max_contains_volume": "500 ml", "max_contains_weight": "2 kg", "moves": 100 }, - { "pocket_type": "CONTAINER", "max_contains_volume": "500 ml", "max_contains_weight": "2 kg", "moves": 100 }, - { "pocket_type": "CONTAINER", "max_contains_volume": "500 ml", "max_contains_weight": "2 kg", "moves": 100 }, - { "pocket_type": "CONTAINER", "max_contains_volume": "500 ml", "max_contains_weight": "2 kg", "moves": 100 }, - { "pocket_type": "CONTAINER", "max_contains_volume": "500 ml", "max_contains_weight": "3 kg", "moves": 120 }, - { "pocket_type": "CONTAINER", "max_contains_volume": "500 ml", "max_contains_weight": "3 kg", "moves": 120 } + { + "pocket_type": "CONTAINER", + "max_contains_volume": "1250 ml", + "max_contains_weight": "4 kg", + "max_item_length": "19 cm", + "moves": 80 + }, + { + "pocket_type": "CONTAINER", + "max_contains_volume": "1250 ml", + "max_contains_weight": "4 kg", + "max_item_length": "19 cm", + "moves": 80 + }, + { + "pocket_type": "CONTAINER", + "max_contains_volume": "1250 ml", + "max_contains_weight": "4 kg", + "max_item_length": "19 cm", + "moves": 80 + }, + { + "pocket_type": "CONTAINER", + "max_contains_volume": "1250 ml", + "max_contains_weight": "4 kg", + "max_item_length": "19 cm", + "moves": 80 + }, + { + "pocket_type": "CONTAINER", + "max_contains_volume": "1080 ml", + "max_contains_weight": "4 kg", + "max_item_length": "165 mm", + "moves": 100 + }, + { + "pocket_type": "CONTAINER", + "max_contains_volume": "1080 ml", + "max_contains_weight": "4 kg", + "max_item_length": "165 mm", + "moves": 100 + } ], "warmth": 15, "material_thickness": 0.25, @@ -477,10 +653,34 @@ "encumbrance": 2, "max_encumbrance": 5, "pocket_data": [ - { "pocket_type": "CONTAINER", "max_contains_volume": "350 ml", "max_contains_weight": "1 kg", "moves": 80 }, - { "pocket_type": "CONTAINER", "max_contains_volume": "350 ml", "max_contains_weight": "1 kg", "moves": 80 }, - { "pocket_type": "CONTAINER", "max_contains_volume": "250 ml", "max_contains_weight": "1 kg", "moves": 100 }, - { "pocket_type": "CONTAINER", "max_contains_volume": "250 ml", "max_contains_weight": "1 kg", "moves": 100 } + { + "pocket_type": "CONTAINER", + "max_contains_volume": "1250 ml", + "max_contains_weight": "4 kg", + "max_item_length": "19 cm", + "moves": 80 + }, + { + "pocket_type": "CONTAINER", + "max_contains_volume": "1250 ml", + "max_contains_weight": "4 kg", + "max_item_length": "19 cm", + "moves": 80 + }, + { + "pocket_type": "CONTAINER", + "max_contains_volume": "1080 ml", + "max_contains_weight": "4 kg", + "max_item_length": "165 mm", + "moves": 100 + }, + { + "pocket_type": "CONTAINER", + "max_contains_volume": "1080 ml", + "max_contains_weight": "4 kg", + "max_item_length": "165 mm", + "moves": 100 + } ], "warmth": 15, "material_thickness": 0.2, @@ -505,10 +705,34 @@ "encumbrance": 16, "max_encumbrance": 20, "pocket_data": [ - { "pocket_type": "CONTAINER", "max_contains_volume": "350 ml", "max_contains_weight": "1 kg", "moves": 80 }, - { "pocket_type": "CONTAINER", "max_contains_volume": "350 ml", "max_contains_weight": "1 kg", "moves": 80 }, - { "pocket_type": "CONTAINER", "max_contains_volume": "250 ml", "max_contains_weight": "1 kg", "moves": 100 }, - { "pocket_type": "CONTAINER", "max_contains_volume": "250 ml", "max_contains_weight": "1 kg", "moves": 100 } + { + "pocket_type": "CONTAINER", + "max_contains_volume": "1250 ml", + "max_contains_weight": "4 kg", + "max_item_length": "19 cm", + "moves": 80 + }, + { + "pocket_type": "CONTAINER", + "max_contains_volume": "1250 ml", + "max_contains_weight": "4 kg", + "max_item_length": "19 cm", + "moves": 80 + }, + { + "pocket_type": "CONTAINER", + "max_contains_volume": "1080 ml", + "max_contains_weight": "4 kg", + "max_item_length": "165 mm", + "moves": 100 + }, + { + "pocket_type": "CONTAINER", + "max_contains_volume": "1080 ml", + "max_contains_weight": "4 kg", + "max_item_length": "165 mm", + "moves": 100 + } ], "warmth": 80, "material_thickness": 1, @@ -545,8 +769,20 @@ "encumbrance": 15, "max_encumbrance": 17, "pocket_data": [ - { "pocket_type": "CONTAINER", "max_contains_volume": "350 ml", "max_contains_weight": "1 kg", "moves": 80 }, - { "pocket_type": "CONTAINER", "max_contains_volume": "350 ml", "max_contains_weight": "1 kg", "moves": 80 } + { + "pocket_type": "CONTAINER", + "max_contains_volume": "800 ml", + "max_contains_weight": "1 kg", + "max_item_length": "19 cm", + "moves": 80 + }, + { + "pocket_type": "CONTAINER", + "max_contains_volume": "800 ml", + "max_contains_weight": "1 kg", + "max_item_length": "19 cm", + "moves": 80 + } ], "warmth": 25, "material_thickness": 0.75, @@ -572,10 +808,34 @@ "encumbrance": 6, "max_encumbrance": 10, "pocket_data": [ - { "pocket_type": "CONTAINER", "max_contains_volume": "350 ml", "max_contains_weight": "1 kg", "moves": 80 }, - { "pocket_type": "CONTAINER", "max_contains_volume": "350 ml", "max_contains_weight": "1 kg", "moves": 80 }, - { "pocket_type": "CONTAINER", "max_contains_volume": "250 ml", "max_contains_weight": "1 kg", "moves": 100 }, - { "pocket_type": "CONTAINER", "max_contains_volume": "250 ml", "max_contains_weight": "1 kg", "moves": 100 } + { + "pocket_type": "CONTAINER", + "max_contains_volume": "1250 ml", + "max_contains_weight": "4 kg", + "max_item_length": "19 cm", + "moves": 80 + }, + { + "pocket_type": "CONTAINER", + "max_contains_volume": "1250 ml", + "max_contains_weight": "4 kg", + "max_item_length": "19 cm", + "moves": 80 + }, + { + "pocket_type": "CONTAINER", + "max_contains_volume": "1080 ml", + "max_contains_weight": "4 kg", + "max_item_length": "165 mm", + "moves": 100 + }, + { + "pocket_type": "CONTAINER", + "max_contains_volume": "1080 ml", + "max_contains_weight": "4 kg", + "max_item_length": "165 mm", + "moves": 100 + } ], "warmth": 70, "material_thickness": 1, @@ -600,10 +860,34 @@ "covers": [ "leg_l", "leg_r" ], "coverage": 40, "pocket_data": [ - { "pocket_type": "CONTAINER", "max_contains_volume": "500 ml", "max_contains_weight": "1 kg", "moves": 80 }, - { "pocket_type": "CONTAINER", "max_contains_volume": "500 ml", "max_contains_weight": "1 kg", "moves": 80 }, - { "pocket_type": "CONTAINER", "max_contains_volume": "250 ml", "max_contains_weight": "1 kg", "moves": 100 }, - { "pocket_type": "CONTAINER", "max_contains_volume": "250 ml", "max_contains_weight": "1 kg", "moves": 100 } + { + "pocket_type": "CONTAINER", + "max_contains_volume": "1250 ml", + "max_contains_weight": "4 kg", + "max_item_length": "19 cm", + "moves": 80 + }, + { + "pocket_type": "CONTAINER", + "max_contains_volume": "1250 ml", + "max_contains_weight": "4 kg", + "max_item_length": "19 cm", + "moves": 80 + }, + { + "pocket_type": "CONTAINER", + "max_contains_volume": "1080 ml", + "max_contains_weight": "4 kg", + "max_item_length": "165 mm", + "moves": 100 + }, + { + "pocket_type": "CONTAINER", + "max_contains_volume": "1080 ml", + "max_contains_weight": "4 kg", + "max_item_length": "165 mm", + "moves": 100 + } ], "warmth": 5, "material_thickness": 0.2, @@ -628,10 +912,34 @@ "encumbrance": 2, "max_encumbrance": 5, "pocket_data": [ - { "pocket_type": "CONTAINER", "max_contains_volume": "350 ml", "max_contains_weight": "1 kg", "moves": 80 }, - { "pocket_type": "CONTAINER", "max_contains_volume": "350 ml", "max_contains_weight": "1 kg", "moves": 80 }, - { "pocket_type": "CONTAINER", "max_contains_volume": "250 ml", "max_contains_weight": "1 kg", "moves": 100 }, - { "pocket_type": "CONTAINER", "max_contains_volume": "250 ml", "max_contains_weight": "1 kg", "moves": 100 } + { + "pocket_type": "CONTAINER", + "max_contains_volume": "1250 ml", + "max_contains_weight": "4 kg", + "max_item_length": "19 cm", + "moves": 80 + }, + { + "pocket_type": "CONTAINER", + "max_contains_volume": "1250 ml", + "max_contains_weight": "4 kg", + "max_item_length": "19 cm", + "moves": 80 + }, + { + "pocket_type": "CONTAINER", + "max_contains_volume": "1080 ml", + "max_contains_weight": "4 kg", + "max_item_length": "165 mm", + "moves": 100 + }, + { + "pocket_type": "CONTAINER", + "max_contains_volume": "1080 ml", + "max_contains_weight": "4 kg", + "max_item_length": "165 mm", + "moves": 100 + } ], "warmth": 5, "material_thickness": 0.2, @@ -656,12 +964,48 @@ "encumbrance": 2, "max_encumbrance": 5, "pocket_data": [ - { "pocket_type": "CONTAINER", "max_contains_volume": "500 ml", "max_contains_weight": "1 kg", "moves": 80 }, - { "pocket_type": "CONTAINER", "max_contains_volume": "500 ml", "max_contains_weight": "1 kg", "moves": 80 }, - { "pocket_type": "CONTAINER", "max_contains_volume": "500 ml", "max_contains_weight": "1 kg", "moves": 80 }, - { "pocket_type": "CONTAINER", "max_contains_volume": "500 ml", "max_contains_weight": "1 kg", "moves": 80 }, - { "pocket_type": "CONTAINER", "max_contains_volume": "250 ml", "max_contains_weight": "1 kg", "moves": 100 }, - { "pocket_type": "CONTAINER", "max_contains_volume": "250 ml", "max_contains_weight": "1 kg", "moves": 100 } + { + "pocket_type": "CONTAINER", + "max_contains_volume": "1250 ml", + "max_contains_weight": "4 kg", + "max_item_length": "19 cm", + "moves": 80 + }, + { + "pocket_type": "CONTAINER", + "max_contains_volume": "1250 ml", + "max_contains_weight": "4 kg", + "max_item_length": "19 cm", + "moves": 80 + }, + { + "pocket_type": "CONTAINER", + "max_contains_volume": "1250 ml", + "max_contains_weight": "4 kg", + "max_item_length": "19 cm", + "moves": 80 + }, + { + "pocket_type": "CONTAINER", + "max_contains_volume": "1250 ml", + "max_contains_weight": "4 kg", + "max_item_length": "19 cm", + "moves": 80 + }, + { + "pocket_type": "CONTAINER", + "max_contains_volume": "1080 ml", + "max_contains_weight": "4 kg", + "max_item_length": "165 mm", + "moves": 100 + }, + { + "pocket_type": "CONTAINER", + "max_contains_volume": "1080 ml", + "max_contains_weight": "4 kg", + "max_item_length": "165 mm", + "moves": 100 + } ], "warmth": 5, "material_thickness": 0.2, @@ -686,8 +1030,20 @@ "encumbrance": 1, "max_encumbrance": 2, "pocket_data": [ - { "pocket_type": "CONTAINER", "max_contains_volume": "350 ml", "max_contains_weight": "1 kg", "moves": 80 }, - { "pocket_type": "CONTAINER", "max_contains_volume": "350 ml", "max_contains_weight": "1 kg", "moves": 80 } + { + "pocket_type": "CONTAINER", + "max_contains_volume": "1080 ml", + "max_contains_weight": "4 kg", + "max_item_length": "165 mm", + "moves": 100 + }, + { + "pocket_type": "CONTAINER", + "max_contains_volume": "1080 ml", + "max_contains_weight": "4 kg", + "max_item_length": "165 mm", + "moves": 100 + } ], "warmth": 5, "material_thickness": 0.25, @@ -773,10 +1129,34 @@ "encumbrance": 2, "max_encumbrance": 5, "pocket_data": [ - { "pocket_type": "CONTAINER", "max_contains_volume": "350 ml", "max_contains_weight": "1 kg", "moves": 80 }, - { "pocket_type": "CONTAINER", "max_contains_volume": "350 ml", "max_contains_weight": "1 kg", "moves": 80 }, - { "pocket_type": "CONTAINER", "max_contains_volume": "250 ml", "max_contains_weight": "1 kg", "moves": 100 }, - { "pocket_type": "CONTAINER", "max_contains_volume": "250 ml", "max_contains_weight": "1 kg", "moves": 100 } + { + "pocket_type": "CONTAINER", + "max_contains_volume": "1250 ml", + "max_contains_weight": "4 kg", + "max_item_length": "19 cm", + "moves": 80 + }, + { + "pocket_type": "CONTAINER", + "max_contains_volume": "1250 ml", + "max_contains_weight": "4 kg", + "max_item_length": "19 cm", + "moves": 80 + }, + { + "pocket_type": "CONTAINER", + "max_contains_volume": "1080 ml", + "max_contains_weight": "4 kg", + "max_item_length": "165 mm", + "moves": 100 + }, + { + "pocket_type": "CONTAINER", + "max_contains_volume": "1080 ml", + "max_contains_weight": "4 kg", + "max_item_length": "165 mm", + "moves": 100 + } ], "warmth": 15, "material_thickness": 0.2, @@ -802,10 +1182,34 @@ "encumbrance": 2, "max_encumbrance": 5, "pocket_data": [ - { "pocket_type": "CONTAINER", "max_contains_volume": "700 ml", "max_contains_weight": "3 kg", "moves": 80 }, - { "pocket_type": "CONTAINER", "max_contains_volume": "700 ml", "max_contains_weight": "3 kg", "moves": 80 }, - { "pocket_type": "CONTAINER", "max_contains_volume": "250 ml", "max_contains_weight": "1 kg", "moves": 100 }, - { "pocket_type": "CONTAINER", "max_contains_volume": "250 ml", "max_contains_weight": "1 kg", "moves": 100 } + { + "pocket_type": "CONTAINER", + "max_contains_volume": "1250 ml", + "max_contains_weight": "4 kg", + "max_item_length": "19 cm", + "moves": 80 + }, + { + "pocket_type": "CONTAINER", + "max_contains_volume": "1250 ml", + "max_contains_weight": "4 kg", + "max_item_length": "19 cm", + "moves": 80 + }, + { + "pocket_type": "CONTAINER", + "max_contains_volume": "1080 ml", + "max_contains_weight": "4 kg", + "max_item_length": "165 mm", + "moves": 100 + }, + { + "pocket_type": "CONTAINER", + "max_contains_volume": "1080 ml", + "max_contains_weight": "4 kg", + "max_item_length": "165 mm", + "moves": 100 + } ], "warmth": 15, "material_thickness": 0.3, @@ -835,14 +1239,48 @@ "encumbrance": 11, "max_encumbrance": 22, "pocket_data": [ - { "pocket_type": "CONTAINER", "max_contains_volume": "350 ml", "max_contains_weight": "1 kg", "moves": 80 }, - { "pocket_type": "CONTAINER", "max_contains_volume": "350 ml", "max_contains_weight": "1 kg", "moves": 80 }, - { "pocket_type": "CONTAINER", "max_contains_volume": "500 ml", "max_contains_weight": "2 kg", "moves": 100 }, - { "pocket_type": "CONTAINER", "max_contains_volume": "500 ml", "max_contains_weight": "2 kg", "moves": 100 }, - { "pocket_type": "CONTAINER", "max_contains_volume": "500 ml", "max_contains_weight": "2 kg", "moves": 100 }, - { "pocket_type": "CONTAINER", "max_contains_volume": "500 ml", "max_contains_weight": "2 kg", "moves": 100 }, - { "pocket_type": "CONTAINER", "max_contains_volume": "500 ml", "max_contains_weight": "2 kg", "moves": 120 }, - { "pocket_type": "CONTAINER", "max_contains_volume": "500 ml", "max_contains_weight": "2 kg", "moves": 120 } + { + "pocket_type": "CONTAINER", + "max_contains_volume": "1250 ml", + "max_contains_weight": "4 kg", + "max_item_length": "19 cm", + "moves": 80 + }, + { + "pocket_type": "CONTAINER", + "max_contains_volume": "1250 ml", + "max_contains_weight": "4 kg", + "max_item_length": "19 cm", + "moves": 80 + }, + { + "pocket_type": "CONTAINER", + "max_contains_volume": "1250 ml", + "max_contains_weight": "4 kg", + "max_item_length": "19 cm", + "moves": 80 + }, + { + "pocket_type": "CONTAINER", + "max_contains_volume": "1250 ml", + "max_contains_weight": "4 kg", + "max_item_length": "19 cm", + "moves": 80 + }, + { + "pocket_type": "CONTAINER", + "max_contains_volume": "1080 ml", + "max_contains_weight": "4 kg", + "max_item_length": "165 mm", + "moves": 100 + }, + { + "pocket_type": "CONTAINER", + "max_contains_volume": "1080 ml", + "max_contains_weight": "4 kg", + "max_item_length": "165 mm", + "moves": 100 + } ], "warmth": 50, "material_thickness": 0.5, diff --git a/data/json/items/armor/suits_protection.json b/data/json/items/armor/suits_protection.json index d0c6c03f1bae3..b99ed35c402b9 100644 --- a/data/json/items/armor/suits_protection.json +++ b/data/json/items/armor/suits_protection.json @@ -19,10 +19,34 @@ { "covers": [ "arm_l", "arm_r" ], "coverage": 100, "encumbrance": [ 10, 10 ] } ], "pocket_data": [ - { "pocket_type": "CONTAINER", "max_contains_volume": "1 L", "max_contains_weight": "3 kg", "moves": 80 }, - { "pocket_type": "CONTAINER", "max_contains_volume": "1 L", "max_contains_weight": "3 kg", "moves": 80 }, - { "pocket_type": "CONTAINER", "max_contains_volume": "1 L", "max_contains_weight": "3 kg", "moves": 80 }, - { "pocket_type": "CONTAINER", "max_contains_volume": "1 L", "max_contains_weight": "3 kg", "moves": 80 } + { + "pocket_type": "CONTAINER", + "max_contains_volume": "1 L", + "max_contains_weight": "3 kg", + "max_item_length": "18 cm", + "moves": 80 + }, + { + "pocket_type": "CONTAINER", + "max_contains_volume": "1 L", + "max_contains_weight": "3 kg", + "max_item_length": "18 cm", + "moves": 80 + }, + { + "pocket_type": "CONTAINER", + "max_contains_volume": "1 L", + "max_contains_weight": "3 kg", + "max_item_length": "18 cm", + "moves": 80 + }, + { + "pocket_type": "CONTAINER", + "max_contains_volume": "1 L", + "max_contains_weight": "3 kg", + "max_item_length": "18 cm", + "moves": 80 + } ], "warmth": 35, "material_thickness": 7, @@ -73,8 +97,20 @@ { "covers": [ "arm_l", "arm_r" ], "coverage": 90, "encumbrance": [ 18, 18 ] } ], "pocket_data": [ - { "pocket_type": "CONTAINER", "max_contains_volume": "500 ml", "max_contains_weight": "2 kg", "moves": 80 }, - { "pocket_type": "CONTAINER", "max_contains_volume": "500 ml", "max_contains_weight": "2 kg", "moves": 80 } + { + "pocket_type": "CONTAINER", + "max_contains_volume": "500 ml", + "max_contains_weight": "3 kg", + "max_item_length": "165 mm", + "moves": 80 + }, + { + "pocket_type": "CONTAINER", + "max_contains_volume": "500 ml", + "max_contains_weight": "3 kg", + "max_item_length": "165 mm", + "moves": 80 + } ], "warmth": 20, "material_thickness": 5, @@ -156,8 +192,20 @@ { "covers": [ "arm_l", "arm_r" ], "coverage": 90, "encumbrance": [ 21, 21 ] } ], "pocket_data": [ - { "pocket_type": "CONTAINER", "max_contains_volume": "500 ml", "max_contains_weight": "1 kg", "moves": 80 }, - { "pocket_type": "CONTAINER", "max_contains_volume": "500 ml", "max_contains_weight": "2 kg", "moves": 80 } + { + "pocket_type": "CONTAINER", + "max_contains_volume": "500 ml", + "max_contains_weight": "3 kg", + "max_item_length": "165 mm", + "moves": 80 + }, + { + "pocket_type": "CONTAINER", + "max_contains_volume": "500 ml", + "max_contains_weight": "3 kg", + "max_item_length": "165 mm", + "moves": 80 + } ], "warmth": 60, "material_thickness": 4, @@ -193,8 +241,20 @@ { "covers": [ "leg_l", "leg_r" ], "coverage": 90, "encumbrance": [ 12, 12 ] } ], "pocket_data": [ - { "pocket_type": "CONTAINER", "max_contains_volume": "1 L", "max_contains_weight": "3 kg", "moves": 80 }, - { "pocket_type": "CONTAINER", "max_contains_volume": "1 L", "max_contains_weight": "3 kg", "moves": 80 } + { + "pocket_type": "CONTAINER", + "max_contains_volume": "800 ml", + "max_contains_weight": "3 kg", + "max_item_length": "165 mm", + "moves": 80 + }, + { + "pocket_type": "CONTAINER", + "max_contains_volume": "800 ml", + "max_contains_weight": "3 kg", + "max_item_length": "165 mm", + "moves": 80 + } ], "warmth": 25, "material_thickness": 4, @@ -337,10 +397,34 @@ { "covers": [ "arm_l", "arm_r" ], "coverage": 90, "encumbrance": [ 17, 17 ] } ], "pocket_data": [ - { "pocket_type": "CONTAINER", "max_contains_volume": "700 ml", "max_contains_weight": "2 kg", "moves": 80 }, - { "pocket_type": "CONTAINER", "max_contains_volume": "700 ml", "max_contains_weight": "2 kg", "moves": 80 }, - { "pocket_type": "CONTAINER", "max_contains_volume": "250 ml", "max_contains_weight": "1 kg", "moves": 120 }, - { "pocket_type": "CONTAINER", "max_contains_volume": "250 ml", "max_contains_weight": "1 kg", "moves": 120 } + { + "pocket_type": "CONTAINER", + "max_contains_volume": "800 ml", + "max_contains_weight": "3 kg", + "max_item_length": "165 mm", + "moves": 80 + }, + { + "pocket_type": "CONTAINER", + "max_contains_volume": "800 ml", + "max_contains_weight": "3 kg", + "max_item_length": "165 mm", + "moves": 80 + }, + { + "pocket_type": "CONTAINER", + "max_contains_volume": "500 ml", + "max_contains_weight": "3 kg", + "max_item_length": "145 mm", + "moves": 120 + }, + { + "pocket_type": "CONTAINER", + "max_contains_volume": "500 ml", + "max_contains_weight": "3 kg", + "max_item_length": "145 mm", + "moves": 120 + } ], "warmth": 25, "material_thickness": 4, @@ -510,10 +594,13 @@ { "covers": [ "arm_l", "arm_r" ], "coverage": 100, "encumbrance": [ 10, 10 ] } ], "pocket_data": [ - { "pocket_type": "CONTAINER", "max_contains_volume": "700 ml", "max_contains_weight": "2 kg", "moves": 120 }, - { "pocket_type": "CONTAINER", "max_contains_volume": "700 ml", "max_contains_weight": "2 kg", "moves": 120 }, - { "pocket_type": "CONTAINER", "max_contains_volume": "250 ml", "max_contains_weight": "1 kg", "moves": 150 }, - { "pocket_type": "CONTAINER", "max_contains_volume": "250 ml", "max_contains_weight": "1 kg", "moves": 150 } + { + "pocket_type": "CONTAINER", + "max_contains_volume": "1600 ml", + "max_contains_weight": "3 kg", + "max_item_length": "18 cm", + "moves": 120 + } ], "warmth": 25, "material_thickness": 2, diff --git a/data/json/items/armor/swimming.json b/data/json/items/armor/swimming.json index b4af0dfd40176..448ea1349da71 100644 --- a/data/json/items/armor/swimming.json +++ b/data/json/items/armor/swimming.json @@ -58,10 +58,20 @@ { "covers": [ "arm_l", "arm_r" ], "coverage": 100, "encumbrance": [ 11, 11 ] } ], "pocket_data": [ - { "pocket_type": "CONTAINER", "max_contains_volume": "350 ml", "max_contains_weight": "1 kg", "moves": 80 }, - { "pocket_type": "CONTAINER", "max_contains_volume": "350 ml", "max_contains_weight": "1 kg", "moves": 80 }, - { "pocket_type": "CONTAINER", "max_contains_volume": "250 ml", "max_contains_weight": "1 kg", "moves": 100 }, - { "pocket_type": "CONTAINER", "max_contains_volume": "250 ml", "max_contains_weight": "1 kg", "moves": 100 } + { + "pocket_type": "CONTAINER", + "max_contains_volume": "500 ml", + "max_contains_weight": "2 kg", + "max_item_length": "11 cm", + "moves": 130 + }, + { + "pocket_type": "CONTAINER", + "max_contains_volume": "500 ml", + "max_contains_weight": "2 kg", + "max_item_length": "11 cm", + "moves": 130 + } ], "warmth": 50, "material_thickness": 3, @@ -188,10 +198,20 @@ { "covers": [ "arm_l", "arm_r" ], "coverage": 90, "encumbrance": [ 2, 4 ] } ], "pocket_data": [ - { "pocket_type": "CONTAINER", "max_contains_volume": "350 ml", "max_contains_weight": "1 kg", "moves": 80 }, - { "pocket_type": "CONTAINER", "max_contains_volume": "350 ml", "max_contains_weight": "1 kg", "moves": 80 }, - { "pocket_type": "CONTAINER", "max_contains_volume": "250 ml", "max_contains_weight": "1 kg", "moves": 100 }, - { "pocket_type": "CONTAINER", "max_contains_volume": "250 ml", "max_contains_weight": "1 kg", "moves": 100 } + { + "pocket_type": "CONTAINER", + "max_contains_volume": "500 ml", + "max_contains_weight": "2 kg", + "max_item_length": "11 cm", + "moves": 130 + }, + { + "pocket_type": "CONTAINER", + "max_contains_volume": "500 ml", + "max_contains_weight": "2 kg", + "max_item_length": "11 cm", + "moves": 130 + } ], "warmth": 30, "material_thickness": 2, diff --git a/data/json/items/armor/torso_clothes.json b/data/json/items/armor/torso_clothes.json index ba59311006616..50e3773b1c12d 100644 --- a/data/json/items/armor/torso_clothes.json +++ b/data/json/items/armor/torso_clothes.json @@ -18,8 +18,20 @@ { "covers": [ "leg_l", "leg_r" ], "coverage": 70, "encumbrance": [ 2, 2 ] } ], "pocket_data": [ - { "pocket_type": "CONTAINER", "max_contains_volume": "1 L", "max_contains_weight": "3 kg", "moves": 80 }, - { "pocket_type": "CONTAINER", "max_contains_volume": "1 L", "max_contains_weight": "3 kg", "moves": 80 } + { + "pocket_type": "CONTAINER", + "max_contains_volume": "1 L", + "max_contains_weight": "3 kg", + "max_item_length": "21 cm", + "moves": 80 + }, + { + "pocket_type": "CONTAINER", + "max_contains_volume": "1 L", + "max_contains_weight": "3 kg", + "max_item_length": "21 cm", + "moves": 80 + } ], "warmth": 15, "material_thickness": 2, @@ -54,10 +66,27 @@ { "covers": [ "arm_l", "arm_r" ], "coverage": 85, "encumbrance": [ 16, 16 ] } ], "pocket_data": [ - { "pocket_type": "CONTAINER", "max_contains_volume": "250 ml", "max_contains_weight": "2 kg", "moves": 80 }, - { "pocket_type": "CONTAINER", "max_contains_volume": "250 ml", "max_contains_weight": "2 kg", "moves": 80 }, - { "pocket_type": "CONTAINER", "max_contains_volume": "250 ml", "max_contains_weight": "2 kg", "moves": 120 }, - { "pocket_type": "CONTAINER", "max_contains_volume": "250 ml", "max_contains_weight": "2 kg", "moves": 120 } + { + "pocket_type": "CONTAINER", + "max_contains_volume": "750 ml", + "max_contains_weight": "3 kg", + "max_item_length": "11 cm", + "moves": 80 + }, + { + "pocket_type": "CONTAINER", + "max_contains_volume": "750 ml", + "max_contains_weight": "3 kg", + "max_item_length": "11 cm", + "moves": 80 + }, + { + "pocket_type": "CONTAINER", + "max_contains_volume": "350 ml", + "max_contains_weight": "2 kg", + "max_item_length": "9 cm", + "moves": 100 + } ], "warmth": 20, "material_thickness": 1.5, @@ -104,7 +133,15 @@ { "covers": [ "torso" ], "coverage": 90, "encumbrance": [ 4, 5 ] }, { "covers": [ "arm_l", "arm_r" ], "coverage": 90, "encumbrance": [ 4, 4 ] } ], - "pocket_data": [ { "pocket_type": "CONTAINER", "max_contains_volume": "250 ml", "max_contains_weight": "1 kg", "moves": 80 } ], + "pocket_data": [ + { + "pocket_type": "CONTAINER", + "max_contains_volume": "350 ml", + "max_contains_weight": "2 kg", + "max_item_length": "9 cm", + "moves": 80 + } + ], "warmth": 10, "material_thickness": 0.1, "flags": [ "VARSIZE", "FANCY" ] @@ -256,9 +293,13 @@ { "covers": [ "arm_l", "arm_r" ], "coverage": 95, "encumbrance": [ 6, 6 ] } ], "pocket_data": [ - { "pocket_type": "CONTAINER", "max_contains_volume": "2 L", "max_contains_weight": "4 kg", "moves": 80 }, - { "pocket_type": "CONTAINER", "max_contains_volume": "250 ml", "max_contains_weight": "1 kg", "moves": 80 }, - { "pocket_type": "CONTAINER", "max_contains_volume": "250 ml", "max_contains_weight": "1 kg", "moves": 80 } + { + "pocket_type": "CONTAINER", + "max_contains_volume": "3 L", + "max_contains_weight": "4 kg", + "max_item_length": "36 cm", + "moves": 80 + } ], "warmth": 30, "material_thickness": 1, @@ -445,8 +486,13 @@ { "covers": [ "arm_l", "arm_r" ], "coverage": 75, "encumbrance": [ 5, 5 ] } ], "pocket_data": [ - { "pocket_type": "CONTAINER", "max_contains_volume": "250 ml", "max_contains_weight": "1 kg", "moves": 120 }, - { "pocket_type": "CONTAINER", "max_contains_volume": "250 ml", "max_contains_weight": "1 kg", "moves": 120 } + { + "pocket_type": "CONTAINER", + "max_contains_volume": "500 ml", + "max_contains_weight": "3 kg", + "max_item_length": "10 cm", + "moves": 80 + } ], "warmth": 5, "material_thickness": 0.1, @@ -490,8 +536,20 @@ "covers": [ "torso" ], "coverage": 90, "pocket_data": [ - { "pocket_type": "CONTAINER", "max_contains_volume": "500 ml", "max_contains_weight": "1 kg", "moves": 80 }, - { "pocket_type": "CONTAINER", "max_contains_volume": "500 ml", "max_contains_weight": "1 kg", "moves": 80 } + { + "pocket_type": "CONTAINER", + "max_contains_volume": "800 ml", + "max_contains_weight": "3 kg", + "max_item_length": "15 cm", + "moves": 80 + }, + { + "pocket_type": "CONTAINER", + "max_contains_volume": "800 ml", + "max_contains_weight": "3 kg", + "max_item_length": "15 cm", + "moves": 80 + } ], "warmth": 5, "material_thickness": 0.1, @@ -515,7 +573,15 @@ { "covers": [ "torso" ], "coverage": 90, "encumbrance": [ 3, 5 ] }, { "covers": [ "arm_l", "arm_r" ], "coverage": 90, "encumbrance": [ 3, 3 ] } ], - "pocket_data": [ { "pocket_type": "CONTAINER", "max_contains_volume": "500 ml", "max_contains_weight": "1 kg", "moves": 80 } ], + "pocket_data": [ + { + "pocket_type": "CONTAINER", + "max_contains_volume": "650 ml", + "max_contains_weight": "3 kg", + "max_item_length": "15 cm", + "moves": 80 + } + ], "warmth": 15, "material_thickness": 0.2, "flags": [ "VARSIZE" ] @@ -642,7 +708,15 @@ "coverage": 40, "encumbrance": 4, "max_encumbrance": 5, - "pocket_data": [ { "pocket_type": "CONTAINER", "max_contains_volume": "250 ml", "max_contains_weight": "1 kg", "moves": 80 } ], + "pocket_data": [ + { + "pocket_type": "CONTAINER", + "max_contains_volume": "650 ml", + "max_contains_weight": "1 kg", + "max_item_length": "15 cm", + "moves": 80 + } + ], "warmth": 8, "material_thickness": 0.2, "snippet_category": [ @@ -761,7 +835,7 @@ "coverage": 50, "encumbrance": 4, "max_encumbrance": 5, - "pocket_data": [ { "pocket_type": "CONTAINER", "max_contains_volume": "250 ml", "max_contains_weight": "1 kg", "moves": 80 } ], + "pocket_data": [ { "pocket_type": "CONTAINER", "max_contains_volume": "250 ml", "max_contains_weight": "1 kg", "moves": 400 } ], "warmth": 5, "material_thickness": 0.4, "flags": [ "VARSIZE", "FANCY" ] @@ -785,10 +859,27 @@ "encumbrance": 4, "max_encumbrance": 8, "pocket_data": [ - { "pocket_type": "CONTAINER", "max_contains_volume": "350 ml", "max_contains_weight": "1 kg", "moves": 80 }, - { "pocket_type": "CONTAINER", "max_contains_volume": "350 ml", "max_contains_weight": "1 kg", "moves": 80 }, - { "pocket_type": "CONTAINER", "max_contains_volume": "250 ml", "max_contains_weight": "1 kg", "moves": 120 }, - { "pocket_type": "CONTAINER", "max_contains_volume": "250 ml", "max_contains_weight": "1 kg", "moves": 120 } + { + "pocket_type": "CONTAINER", + "max_contains_volume": "650 ml", + "max_contains_weight": "3 kg", + "max_item_length": "15 cm", + "moves": 80 + }, + { + "pocket_type": "CONTAINER", + "max_contains_volume": "800 ml", + "max_contains_weight": "3 kg", + "max_item_length": "15 cm", + "moves": 120 + }, + { + "pocket_type": "CONTAINER", + "max_contains_volume": "800 ml", + "max_contains_weight": "3 kg", + "max_item_length": "15 cm", + "moves": 120 + } ], "warmth": 20, "material_thickness": 1.5, @@ -814,9 +905,13 @@ { "covers": [ "arm_l", "arm_r" ], "coverage": 95, "encumbrance": [ 6, 6 ] } ], "pocket_data": [ - { "pocket_type": "CONTAINER", "max_contains_volume": "2 L", "max_contains_weight": "4 kg", "moves": 80 }, - { "pocket_type": "CONTAINER", "max_contains_volume": "250 ml", "max_contains_weight": "1 kg", "moves": 80 }, - { "pocket_type": "CONTAINER", "max_contains_volume": "250 ml", "max_contains_weight": "1 kg", "moves": 80 } + { + "pocket_type": "CONTAINER", + "max_contains_volume": "3 L", + "max_contains_weight": "4 kg", + "max_item_length": "36 cm", + "moves": 80 + } ], "warmth": 45, "material_thickness": 1, From eec20c36a297db58d8eed208b2ae3e97730c8d47 Mon Sep 17 00:00:00 2001 From: ANickelN <52714184+ANickelN@users.noreply.github.com> Date: Sat, 10 Apr 2021 00:27:14 -0700 Subject: [PATCH 144/453] Fix glass weights, lengths and volumes (#48449) --- data/json/items/resources/glass.json | 26 ++++++----- data/json/materials.json | 26 +++++++++++ tests/vehicle_drag_test.cpp | 66 ++++++++++++++-------------- tests/vehicle_efficiency_test.cpp | 50 ++++++++++----------- 4 files changed, 99 insertions(+), 69 deletions(-) diff --git a/data/json/items/resources/glass.json b/data/json/items/resources/glass.json index 1e9b16ffda269..4db237c921cac 100644 --- a/data/json/items/resources/glass.json +++ b/data/json/items/resources/glass.json @@ -27,13 +27,14 @@ "symbol": "]", "color": "light_cyan", "name": { "str": "sheet of glass", "str_pl": "sheets of glass" }, - "description": "A large sheet of glass. Easily shattered. Useful for repairing windows.", + "description": "A large sheet of glass, around three by four feet. Easily shattered. Useful for repairing windows.", "category": "spare_parts", "price": 5000, "price_postapoc": 100, "material": [ "glass" ], - "weight": "31250 g", - "volume": "12500 ml", + "weight": "6577 g", + "volume": "2655 ml", + "longest_side": "122 cm", "bashing": 4, "to_hit": -5, "use_action": { @@ -50,13 +51,14 @@ "symbol": "]", "color": "light_blue", "name": { "str": "sheet of reinforced glass", "str_pl": "sheets of reinforced glass" }, - "description": "A large sheet of glass strengthened with steel wiring.", + "description": "A large sheet of bulletproof glass, it looks to a little over two inches thick.", "category": "spare_parts", "price": 10000, "price_postapoc": 250, "material": [ "glass", "steel" ], - "weight": "40123 g", - "volume": "12500 ml", + "weight": "137710 g", + "volume": "63713 ml", + "longest_side": "122 cm", "bashing": 6, "to_hit": -6 }, @@ -66,13 +68,14 @@ "symbol": "]", "color": "light_blue", "name": { "str": "pane of reinforced glass", "str_pl": "panes of reinforced glass" }, - "description": "A small pane of glass strengthened with steel wiring.", + "description": "A small pane of bulletproof glass, it looks to be a little over two inches thick.", "category": "spare_parts", "price": 5000, "price_postapoc": 100, "material": [ "glass", "steel" ], - "weight": "10040 g", - "volume": "3 L", + "weight": "11475 g", + "volume": "5300 ml", + "longest_side": "305 mm", "bashing": 4, "to_hit": -2 }, @@ -87,8 +90,9 @@ "price": 10000, "price_postapoc": 100, "material": [ "glass" ], - "weight": "22700 g", - "volume": "22700 ml", + "weight": "17514 g", + "volume": "7070 ml", + "longest_side": "122 cm", "bashing": 6, "to_hit": -5 } diff --git a/data/json/materials.json b/data/json/materials.json index 6ecef26451a54..a62c2a95edb50 100644 --- a/data/json/materials.json +++ b/data/json/materials.json @@ -607,6 +607,32 @@ { "fuel": 1, "smoke": 5, "burn": 5 } ] }, + { + "type": "material", + "id": "lvl4ballisticglass", + "name": "Ballistic Glass", + "//": "Values are based on thickness being a quarter of an inch.", + "density": 30, + "specific_heat_liquid": 0.2, + "specific_heat_solid": 0.2, + "latent_heat": 100, + "bash_resist": 5, + "cut_resist": 10, + "bullet_resist": 9, + "acid_resist": 10, + "fire_resist": 3, + "elec_resist": 4, + "chip_resist": 0, + "dmg_adj": [ "scratched", "cut", "cracked", "shattered" ], + "bash_dmg_verb": "cracked", + "cut_dmg_verb": "scratched", + "burn_data": [ + { "fuel": 0, "smoke": 0, "burn": 0 }, + { "fuel": 0, "smoke": 0, "burn": 0 }, + { "fuel": 0, "smoke": 0, "burn": 1000, "volume_per_turn": "5000 ml", "//": "More like shattering than melting" } + ], + "burn_products": [ [ "glass_shard", 1 ] ] + }, { "type": "material", "id": "glass", diff --git a/tests/vehicle_drag_test.cpp b/tests/vehicle_drag_test.cpp index 6920713743150..af5f69c38b203 100644 --- a/tests/vehicle_drag_test.cpp +++ b/tests/vehicle_drag_test.cpp @@ -239,28 +239,28 @@ TEST_CASE( "vehicle_drag", "[vehicle] [engine]" ) test_vehicle_drag( "superbike", 0.609525, 0.846042, 378.257812, 9912, 11797 ); test_vehicle_drag( "tandem", 0.609525, 0.010590, 19.990625, 1430, 1870 ); test_vehicle_drag( "unicycle", 0.690795, 0.002493, 25.100000, 1377, 1798 ); - test_vehicle_drag( "beetle", 0.785610, 1.802151, 1275.732812, 8969, 10710 ); - test_vehicle_drag( "bubble_car", 0.823988, 1.764712, 1189.742560, 9304, 9651 ); - test_vehicle_drag( "car", 0.294604, 2.473484, 1167.310417, 11916, 14350 ); - test_vehicle_drag( "car_mini", 0.294604, 1.817781, 1286.796875, 12157, 14580 ); - test_vehicle_drag( "car_sports", 0.294604, 2.549405, 1443.767500, 20848, 24904 ); - test_vehicle_drag( "car_sports_atomic", 0.294604, 3.788275, 1787.798958, 23696, 24593 ); - test_vehicle_drag( "car_sports_electric", 0.294604, 3.119641, 1766.701250, 23901, 24797 ); - test_vehicle_drag( "electric_car", 0.304763, 2.311289, 1090.765625, 16266, 16882 ); - test_vehicle_drag( "rara_x", 0.679185, 1.952527, 1092.094907, 9114, 9459 ); - test_vehicle_drag( "suv", 0.294604, 2.914201, 1178.826786, 13988, 16827 ); - test_vehicle_drag( "suv_electric", 0.304763, 2.461925, 995.875893, 16216, 16833 ); + test_vehicle_drag( "beetle", 0.785610, 1.584313, 1121.526562, 9005, 10744 ); + test_vehicle_drag( "bubble_car", 0.823988, 1.002279, 675.721726, 9424, 9769 ); + test_vehicle_drag( "car", 0.294604, 2.255646, 1064.506250, 11995, 14426 ); + test_vehicle_drag( "car_mini", 0.294604, 1.599943, 1132.590625, 12238, 14657 ); + test_vehicle_drag( "car_sports", 0.294604, 2.331567, 1320.402500, 20918, 24972 ); + test_vehicle_drag( "car_sports_atomic", 0.294604, 3.461518, 1633.592708, 23795, 24693 ); + test_vehicle_drag( "car_sports_electric", 0.294604, 2.901803, 1643.336250, 23968, 24864 ); + test_vehicle_drag( "electric_car", 0.304763, 2.093451, 987.961458, 16337, 16954 ); + test_vehicle_drag( "rara_x", 0.679185, 1.544080, 863.641204, 9191, 9535 ); + test_vehicle_drag( "suv", 0.294604, 2.696363, 1090.708929, 14063, 16899 ); + test_vehicle_drag( "suv_electric", 0.304763, 2.244087, 907.758036, 16288, 16904 ); test_vehicle_drag( "golf_cart", 0.943313, 1.472114, 926.312500, 7039, 7303 ); test_vehicle_drag( "golf_cart_4seat", 0.943313, 1.439476, 905.775000, 7044, 7308 ); - test_vehicle_drag( "hearse", 0.355556, 3.216780, 1301.223214, 11046, 13340 ); - test_vehicle_drag( "pickup_technical", 0.838097, 2.958591, 1196.783036, 10176, 12173 ); - test_vehicle_drag( "ambulance", 1.049323, 2.348252, 1927.320833, 11306, 13472 ); - test_vehicle_drag( "car_fbi", 0.457144, 2.743431, 1294.706250, 14625, 17490 ); + test_vehicle_drag( "hearse", 0.355556, 2.672185, 1080.928571, 11212, 13499 ); + test_vehicle_drag( "pickup_technical", 0.838097, 2.631835, 1064.606250, 10223, 12217 ); + test_vehicle_drag( "ambulance", 1.049323, 2.191681, 1798.815625, 11324, 13488 ); + test_vehicle_drag( "car_fbi", 0.457144, 2.525593, 1191.902083, 14675, 17538 ); test_vehicle_drag( "fire_engine", 2.305875, 3.544531, 2327.331250, 8697, 10364 ); test_vehicle_drag( "fire_truck", 1.056510, 8.175862, 5419.870313, 10648, 12841 ); - test_vehicle_drag( "policecar", 0.629843, 2.744534, 1295.227083, 13235, 15807 ); - test_vehicle_drag( "policesuv", 0.629843, 3.096796, 1252.688393, 13173, 15749 ); - test_vehicle_drag( "truck_swat", 0.808830, 7.607580, 6243.900000, 9929, 11682 ); + test_vehicle_drag( "policecar", 0.629843, 2.526697, 1192.422917, 13273, 15844 ); + test_vehicle_drag( "policesuv", 0.629843, 2.878958, 1164.570536, 13211, 15785 ); + test_vehicle_drag( "truck_swat", 0.808830, 8.226852, 6752.165625, 9846, 11602 ); test_vehicle_drag( "oldtractor", 0.537285, 0.893482, 1319.981250, 12446, 14408 ); test_vehicle_drag( "autotractor", 1.425450, 2.044321, 2013.445000, 7779, 8068 ); test_vehicle_drag( "tractor_plow", 0.609525, 0.918444, 1739.562500, 11941, 13822 ); @@ -268,34 +268,34 @@ TEST_CASE( "vehicle_drag", "[vehicle] [engine]" ) test_vehicle_drag( "tractor_seed", 0.609525, 0.804219, 1523.216346, 11963, 13843 ); test_vehicle_drag( "aapc-mg", 1.625400, 8.660271, 4378.969494, 8038, 9427 ); test_vehicle_drag( "apc", 1.625400, 8.538354, 4317.323661, 8047, 9436 ); - test_vehicle_drag( "humvee", 0.616297, 7.288356, 4913.700893, 12935, 15175 ); - test_vehicle_drag( "military_cargo_truck", 0.840757, 9.507160, 4387.005556, 11554, 13581 ); + test_vehicle_drag( "humvee", 0.616298, 7.938499, 5352.017857, 12830, 15073 ); + test_vehicle_drag( "military_cargo_truck", 0.840758, 10.682064, 4929.155556, 11411, 13443 ); test_vehicle_drag( "flatbed_truck", 0.776902, 4.556718, 2039.952841, 10177, 12239 ); - test_vehicle_drag( "pickup", 0.589208, 3.264179, 1320.396429, 11288, 13539 ); + test_vehicle_drag( "pickup", 0.589208, 2.852032, 1153.678571, 11367, 13615 ); test_vehicle_drag( "semi_truck", 0.792020, 10.185646, 5885.327500, 11661, 13732 ); test_vehicle_drag( "truck_trailer", 1.196475, 13.127154, 5818.000000, 0, 0 ); test_vehicle_drag( "tatra_truck", 0.968467, 8.434611, 4507.793605, 14050, 16400 ); - test_vehicle_drag( "animalctrl", 0.396191, 2.829350, 1144.503571, 12832, 15400 ); + test_vehicle_drag( "animalctrl", 0.396191, 2.611512, 1056.385714, 12891, 15457 ); test_vehicle_drag( "autosweeper", 0.986850, 1.844396, 1305.637500, 6884, 7144 ); - test_vehicle_drag( "excavator", 0.659728, 1.793523, 1269.625000, 13204, 15305 ); + test_vehicle_drag( "excavator", 0.659728, 2.439720, 1727.064062, 13095, 15200 ); test_vehicle_drag( "road_roller", 1.823738, 2.768224, 9197.104167, 9430, 10928 ); test_vehicle_drag( "forklift", 0.565988, 1.510686, 712.937500, 8258, 8572 ); - test_vehicle_drag( "trencher", 0.520838, 1.173965, 1334.115865, 8559, 8881 ); - test_vehicle_drag( "armored_car", 0.844628, 7.034173, 4742.334821, 11846, 13860 ); + test_vehicle_drag( "trencher", 0.520838, 1.545528, 1756.367308, 8466, 8788 ); + test_vehicle_drag( "armored_car", 0.844627, 7.682788, 5179.621429, 11764, 13781 ); test_vehicle_drag( "cube_van", 0.518580, 2.707603, 2222.257292, 11852, 14196 ); test_vehicle_drag( "cube_van_cheap", 0.512775, 2.643764, 1905.244207, 10060, 12081 ); - test_vehicle_drag( "hippie_van", 0.375874, 2.698624, 1091.623214, 11022, 13267 ); - test_vehicle_drag( "icecream_truck", 0.681673, 3.271602, 2225.536486, 10796, 12939 ); - test_vehicle_drag( "lux_rv", 1.630929, 4.101402, 2315.010526, 8390, 9759 ); + test_vehicle_drag( "hippie_van", 0.375874, 2.480786, 1003.505357, 11086, 13328 ); + test_vehicle_drag( "icecream_truck", 0.681673, 2.971394, 2021.317399, 10847, 12988 ); + test_vehicle_drag( "lux_rv", 1.630929, 3.669265, 2071.093531, 8426, 9792 ); test_vehicle_drag( "meth_lab", 0.499230, 4.185080, 2538.355452, 11668, 14057 ); - test_vehicle_drag( "rv", 0.541800, 3.107252, 2127.031915, 11611, 13925 ); - test_vehicle_drag( "schoolbus", 0.445050, 4.727095, 2140.748136, 12301, 14426 ); - test_vehicle_drag( "security_van", 0.541800, 8.004081, 6569.327083, 11003, 13010 ); - test_vehicle_drag( "wienermobile", 1.281891, 2.613527, 2145.044792, 10576, 12602 ); + test_vehicle_drag( "rv", 0.541800, 2.939497, 2012.197473, 11645, 13958 ); + test_vehicle_drag( "schoolbus", 0.445050, 3.727552, 1688.087610, 12535, 14652 ); + test_vehicle_drag( "security_van", 0.541800, 8.623353, 7077.592708, 10891, 12901 ); + test_vehicle_drag( "wienermobile", 1.281891, 2.237757, 1836.632292, 10612, 12636 ); test_vehicle_drag( "canoe", 0.609525, 7.741047, 2.191938, 298, 628 ); test_vehicle_drag( "kayak", 0.609525, 2.935863, 1.108417, 710, 1314 ); test_vehicle_drag( "kayak_racing", 0.609525, 2.604776, 0.983417, 779, 1406 ); - test_vehicle_drag( "DUKW", 0.776902, 3.850773, 83.288765, 10283, 12339 ); + test_vehicle_drag( "DUKW", 0.776903, 3.602238, 77.913176, 10321, 12374 ); test_vehicle_drag( "raft", 0.997815, 9.743243, 5.517750, 239, 508 ); test_vehicle_drag( "inflatable_boat", 0.469560, 3.616690, 2.048188, 602, 1173 ); } diff --git a/tests/vehicle_efficiency_test.cpp b/tests/vehicle_efficiency_test.cpp index 4eec7efb70e6f..4d8c1211df14f 100644 --- a/tests/vehicle_efficiency_test.cpp +++ b/tests/vehicle_efficiency_test.cpp @@ -433,41 +433,41 @@ TEST_CASE( "make_vehicle_efficiency_case", "[.]" ) // Fix test for electric vehicles TEST_CASE( "vehicle_efficiency", "[vehicle] [engine]" ) { - test_vehicle( "beetle", 816469, 431300, 338700, 95610, 68060 ); - test_vehicle( "car", 1120618, 617500, 388600, 52730, 25170 ); - test_vehicle( "car_sports", 1155014, 352600, 267600, 36820, 22360 ); - test_vehicle( "electric_car", 1047135, 355300, 201600, 22400, 10780 ); - test_vehicle( "suv", 1320286, 1163000, 630000, 85540, 31840 ); + test_vehicle( "beetle", 717777, 444000, 386700, 111500, 91570 ); + test_vehicle( "car", 1021926, 644100, 436900, 59860, 30240 ); + test_vehicle( "car_sports", 1056322, 354700, 288200, 39690, 27210 ); + test_vehicle( "electric_car", 948443, 372500, 231100, 25020, 14280 ); + test_vehicle( "suv", 1221594, 1210000, 695900, 93430, 37220 ); test_vehicle( "motorcycle", 162585, 120300, 100900, 63320, 51130 ); test_vehicle( "quad_bike", 264845, 116100, 116100, 46770, 46770 ); test_vehicle( "scooter", 55441, 235900, 235900, 174700, 174700 ); - test_vehicle( "superbike", 241585, 109800, 65300, 41990, 24140 ); - test_vehicle( "ambulance", 1850228, 623000, 511100, 77700, 57910 ); - test_vehicle( "fire_engine", 2606611, 1895000, 1585000, 337800, 261900 ); - test_vehicle( "fire_truck", 6441903, 420800, 80000, 19080, 4063 ); - test_vehicle( "truck_swat", 5994144, 682900, 130200, 29610, 7604 ); + test_vehicle( "superbike", 241585, 109800, 65300, 42000, 24140 ); + test_vehicle( "ambulance", 1726863, 623000, 538800, 83190, 69710 ); + test_vehicle( "fire_engine", 2483246, 1912000, 1665000, 355000, 295200 ); + test_vehicle( "fire_truck", 6195173, 428300, 92250, 19710, 4700 ); + test_vehicle( "truck_swat", 6482079, 649500, 97380, 28180, 6083 ); test_vehicle( "tractor_plow", 723658, 681200, 681200, 132700, 132700 ); - test_vehicle( "apc", 5802483, 1626000, 1119000, 130800, 85590 ); - test_vehicle( "humvee", 5503345, 767900, 306900, 25620, 9171 ); - test_vehicle( "road_roller", 8831620, 602500, 147100, 22760, 6925 ); + test_vehicle( "apc", 5900070, 1607000, 1086000, 125600, 80390 ); + test_vehicle( "humvee", 5991280, 739500, 296600, 23790, 7337 ); + test_vehicle( "road_roller", 8658909, 584800, 156400, 22760, 6925 ); test_vehicle( "golf_cart", 444630, 96000, 69390, 35490, 14200 ); // in reverse - test_vehicle( "beetle", 816469, 58970, 58870, 44560, 43060, 0, 0, true ); - test_vehicle( "car", 1120618, 76060, 76060, 44230, 24920, 0, 0, true ); - test_vehicle( "car_sports", 1155014, 353200, 268000, 35220, 19540, 0, 0, true ); - test_vehicle( "electric_car", 1047135, 356400, 202300, 22450, 10810, 0, 0, true ); - test_vehicle( "suv", 1320286, 112000, 111700, 66880, 31640, 0, 0, true ); + test_vehicle( "beetle", 717777, 58800, 58800, 45900, 44560, 0, 0, true ); + test_vehicle( "car", 1021926, 76390, 76260, 48330, 30270, 0, 0, true ); + test_vehicle( "car_sports", 1056322, 355300, 288600, 38670, 24580, 0, 0, true ); + test_vehicle( "electric_car", 948443, 373700, 231800, 25070, 14310, 0, 0, true ); + test_vehicle( "suv", 1221594, 114900, 112400, 70400, 35200, 0, 0, true ); test_vehicle( "motorcycle", 162585, 20070, 19030, 15490, 14890, 0, 0, true ); test_vehicle( "quad_bike", 264845, 19650, 19650, 15440, 15440, 0, 0, true ); test_vehicle( "scooter", 55441, 58790, 58790, 46320, 46320, 0, 0, true ); test_vehicle( "superbike", 241585, 18380, 10570, 13100, 8497, 0, 0, true ); - test_vehicle( "ambulance", 1850228, 58460, 57740, 42480, 39100, 0, 0, true ); - test_vehicle( "fire_engine", 2606611, 258000, 257800, 185600, 179400, 0, 0, true ); - test_vehicle( "fire_truck", 6441903, 58760, 59170, 18580, 3447, 0, 0, true ); - test_vehicle( "truck_swat", 5994144, 129300, 130100, 29350, 7668, 0, 0, true ); + test_vehicle( "ambulance", 1726863, 58600, 57910, 42480, 40260, 0, 0, true ); + test_vehicle( "fire_engine", 2483246, 257400, 257100, 185600, 179400, 0, 0, true ); + test_vehicle( "fire_truck", 6195173, 58700, 58860, 19630, 4471, 0, 0, true ); + test_vehicle( "truck_swat", 6482079, 129900, 130900, 26920, 5308, 0, 0, true ); test_vehicle( "tractor_plow", 723658, 72490, 72490, 53700, 53700, 0, 0, true ); - test_vehicle( "apc", 5802483, 381500, 382100, 123600, 82000, 0, 0, true ); - test_vehicle( "humvee", 5503345, 89940, 89940, 25780, 9086, 0, 0, true ); - test_vehicle( "road_roller", 8831620, 97490, 97690, 22880, 6606, 0, 0, true ); + test_vehicle( "apc", 5900070, 382000, 382600, 123100, 82750, 0, 0, true ); + test_vehicle( "humvee", 5991280, 89490, 89490, 24180, 7595, 0, 0, true ); + test_vehicle( "road_roller", 8658909, 97090, 97190, 22880, 6545, 0, 0, true ); test_vehicle( "golf_cart", 444630, 96150, 28800, 35560, 11150, 0, 0, true ); } From 35f8269a6172eb01aa586d20dbdc8f356687a7b4 Mon Sep 17 00:00:00 2001 From: Mark Langsdorf Date: Sat, 10 Apr 2021 02:30:34 -0500 Subject: [PATCH 145/453] Dark Skies Above: Surveillance drone scan and reinforcements (#48228) --- .../mapgen/map_extras/patrols.json | 25 ++++++ data/mods/Dark-Skies-Above/monattack.json | 26 ++++++ data/mods/Dark-Skies-Above/monspell.json | 15 ++++ .../monsters/alien_cyborgs.json | 34 +++++++ .../monsters/alien_robots.json | 28 +++++- src/monattack.cpp | 89 +++++++++++++++++++ src/monattack.h | 1 + src/monstergenerator.cpp | 1 + src/timed_event.cpp | 23 +++++ src/timed_event.h | 1 + 10 files changed, 242 insertions(+), 1 deletion(-) create mode 100644 data/mods/Dark-Skies-Above/mapgen/map_extras/patrols.json diff --git a/data/mods/Dark-Skies-Above/mapgen/map_extras/patrols.json b/data/mods/Dark-Skies-Above/mapgen/map_extras/patrols.json new file mode 100644 index 0000000000000..2476303940849 --- /dev/null +++ b/data/mods/Dark-Skies-Above/mapgen/map_extras/patrols.json @@ -0,0 +1,25 @@ +[ + { + "type": "mapgen", + "method": "json", + "update_mapgen_id": "mx_dsa_alrp", + "object": { + "place_monster": [ + { + "monster": "dks_mon_skirmsoldier", + "x": 12, + "y": 12, + "repeat": [ 3, 4 ], + "spawn_data": { "patrol": [ { "x": -10, "y": -10 }, { "x": 33, "y": -10 }, { "x": 33, "y": 33 }, { "x": 33, "y": -10 } ] } + } + ] + } + }, + { + "id": "mx_dsa_alrp", + "type": "map_extra", + "name": { "str": "DSA ALRP" }, + "description": "Alien light reconnaissance patrol.", + "generator": { "generator_method": "update_mapgen", "generator_id": "mx_dsa_alrp" } + } +] diff --git a/data/mods/Dark-Skies-Above/monattack.json b/data/mods/Dark-Skies-Above/monattack.json index c7e85ffcb9a47..ae924ef9cf4dc 100644 --- a/data/mods/Dark-Skies-Above/monattack.json +++ b/data/mods/Dark-Skies-Above/monattack.json @@ -42,5 +42,31 @@ "hit_dmg_npc": "The %1$s slashes !", "no_dmg_msg_u": "The %1$s attempts to cut you, but fails to penetrate your armor.", "no_dmg_msg_npc": "The %1$s tries to cut , but fails to penetrate their armor." + }, + { + "type": "monster_attack", + "attack_type": "melee", + "id": "melee_shock", + "cooldown": 20, + "move_cost": 150, + "damage_max_instance": [ { "damage_type": "electric", "amount": 8 }, { "damage_type": "stab", "amount": 6 } ], + "body_parts": [ + [ "foot_l", 2 ], + [ "foot_r", 2 ], + [ "leg_l", 3 ], + [ "leg_r", 3 ], + [ "hand_l", 2 ], + [ "hand_r", 2 ], + [ "head", 3 ], + [ "eyes", 2 ], + [ "mouth", 1 ], + [ "arm_l", 3 ], + [ "arm_r", 3 ], + [ "torso", 4 ] + ], + "hit_dmg_u": "The %1$s lances electricity into you!", + "hit_dmg_npc": "The %1$s lances with electricity!", + "no_dmg_msg_u": "The %1$s attempts to electrify you, but fails to penetrate your armor.", + "no_dmg_msg_npc": "The %1$s tries to electrify , but fails to penetrate their armor." } ] diff --git a/data/mods/Dark-Skies-Above/monspell.json b/data/mods/Dark-Skies-Above/monspell.json index a57b28498426e..5460cc86ac210 100644 --- a/data/mods/Dark-Skies-Above/monspell.json +++ b/data/mods/Dark-Skies-Above/monspell.json @@ -14,5 +14,20 @@ "min_duration": 425, "max_duration": 425, "flags": [ "SILENT", "NO_PROJECTILE" ] + }, + { + "type": "SPELL", + "id": "dks_summon_alrp", + "name": { "str": "Spawn ALRP" }, + "description": "Summons a squad of 3-4 skirmishers.", + "flags": [ "HOSTILE_SUMMON", "RANDOM_DAMAGE", "PERMANENT" ], + "valid_targets": [ "ground", "self" ], + "min_damage": 3, + "max_damage": 4, + "min_aoe": 2, + "max_aoe": 2, + "shape": "blast", + "effect": "summon", + "effect_str": "dks_mon_skirmsoldier" } ] diff --git a/data/mods/Dark-Skies-Above/monsters/alien_cyborgs.json b/data/mods/Dark-Skies-Above/monsters/alien_cyborgs.json index c4c5f5c7f78c1..7a26fb3c5dfbc 100644 --- a/data/mods/Dark-Skies-Above/monsters/alien_cyborgs.json +++ b/data/mods/Dark-Skies-Above/monsters/alien_cyborgs.json @@ -290,5 +290,39 @@ "anger_triggers": [ "FRIEND_ATTACKED", "HURT" ], "death_function": [ "NORMAL" ], "flags": [ "SEES", "HEARS", "SMELLS", "BASHES", "DESTROYS", "ACIDPROOF", "CAN_DIG", "ARTHROPOD_BLOOD" ] + }, + { + "id": "dks_mon_skirmsoldier", + "type": "MONSTER", + "name": { "str": "alien skirmisher" }, + "description": "A slouched bipedal figure, slightly smaller than an average adult human. Beneath woven full-body combat armor and a full suite of cybernetic modifications are glimpses of rubbery, abscessed flesh. It is capable of short, boosted jumps using a device on its back, closing gaps to cause havoc with its wicked integrated melee weapons. Severed organic parts dangle from its equipment, morbid trophies from past battles.", + "default_faction": "invader_alien", + "bodytype": "human", + "categories": [ "ALIEN" ], + "species": [ "ROBOT" ], + "volume": "52500 ml", + "weight": "71500 g", + "hp": 45, + "speed": 90, + "material": [ "steel" ], + "symbol": "$", + "aggression": 100, + "morale": 100, + "color": "light_gray", + "dodge": 1, + "melee_skill": 5, + "melee_dice": 4, + "melee_dice_sides": 3, + "armor_bash": 15, + "armor_stab": 25, + "armor_cut": 6, + "armor_fire": 15, + "armor_bullet": 35, + "vision_night": 5, + "special_attacks": [ { "type": "leap", "cooldown": 10, "max_range": 5 }, { "id": "melee_shock" } ], + "path_settings": { "max_dist": 5 }, + "death_function": [ "NORMAL" ], + "harvest": "dks_alien_cyborg", + "flags": [ "SEES", "HEARS", "SMELLS", "SWARMS", "WARM", "BASHES", "GROUP_BASH", "PRIORITIZE_TARGETS", "PATH_AVOID_DANGER_2" ] } ] diff --git a/data/mods/Dark-Skies-Above/monsters/alien_robots.json b/data/mods/Dark-Skies-Above/monsters/alien_robots.json index 625d40bb98338..e2267a8587ea3 100644 --- a/data/mods/Dark-Skies-Above/monsters/alien_robots.json +++ b/data/mods/Dark-Skies-Above/monsters/alien_robots.json @@ -1,4 +1,29 @@ [ + { + "id": "mon_dsa_alien_dispatch", + "type": "MONSTER", + "name": { "str": "alien dispatch system" }, + "description": "A monstrous intelligence, capable of teleporting drones and skirmishers to the planet, or dispatching larger aliens in drop pods.", + "default_faction": "invader_alien", + "looks_like": "mon_eyebot", + "categories": [ "ALIEN" ], + "species": [ "ROBOT" ], + "volume": "30000 ml", + "weight": "40750 g", + "hp": 400, + "speed": 100, + "material": [ "steel" ], + "symbol": "D", + "color": "red", + "dodge": 3, + "armor_bash": 8, + "armor_cut": 10, + "luminance": 5, + "path_settings": { "max_dist": 5 }, + "death_drops": { "groups": [ [ "robots", 4 ] ] }, + "death_function": [ "MELT" ], + "flags": [ "SEES", "FLIES", "ELECTRONIC", "COLDPROOF", "NO_BREATHE", "NOHEAD", "PRIORITIZE_TARGETS" ] + }, { "id": "mon_dks_glowdrone", "type": "MONSTER", @@ -20,7 +45,7 @@ "armor_cut": 10, "armor_bullet": 6, "luminance": 5, - "special_attacks": [ [ "SEARCHLIGHT", 1 ] ], + "special_attacks": [ [ "SEARCHLIGHT", 1 ], [ "DSA_DRONE_SCAN", 2 ] ], "path_settings": { "max_dist": 5 }, "death_drops": { "groups": [ [ "robots", 4 ], [ "eyebot", 1 ], [ "turret_searchlight", 1 ] ] }, "death_function": [ "BROKEN" ], @@ -52,6 +77,7 @@ "vision_night": 5, "special_attacks": [ [ "TAZER", 12 ], + [ "DSA_DRONE_SCAN", 5 ], { "id": "tool_slash" }, { "type": "spell", diff --git a/src/monattack.cpp b/src/monattack.cpp index cc0297f264b7e..3a3c9ae0a3fa3 100644 --- a/src/monattack.cpp +++ b/src/monattack.cpp @@ -5817,3 +5817,92 @@ bool mattack::speaker( monster *z ) SNIPPET.random_from_category( "speaker_warning" ).value_or( translation() ) ); return true; } + +bool mattack::dsa_drone_scan( monster *z ) +{ + z->moves -= 100; + constexpr int scan_range = 30; + // Select a target: the avatar or a nearby NPC. Must be visible and within scan range + Character *target = &get_player_character(); + Character &you = get_player_character(); + bool avatar_in_range = z->posz() == target->posz() && z->sees( target->pos() ) && + rl_dist( z->pos(), target->pos() ) <= scan_range; + const std::vector available = g->get_npcs_if( [&]( const npc & guy ) { + // TODO: Get rid of the z-level check when z-level vision gets "better" + return z->posz() == guy.posz() && z->sees( guy.pos() ) && + rl_dist( z->pos(), guy.pos() ) <= scan_range; + } ); + if( !avatar_in_range && available.empty() ) { + return true; + } + if( !available.empty() ) { + if( !avatar_in_range || + ( avatar_in_range && x_in_y( available.size(), available.size() + 1 ) ) ) { + target = random_entry( available ); + } + } + const std::string timestamp_str = "dsa_drone_scan_timestamp"; + const std::string weapons_str = "dsa_drone_scan_weapons_count"; + + // only check for weapons once every 10 seconds by timestap variable + int weapons_count = 0; + bool summon_reinforcements = false; + if( !target->get_value( weapons_str ).empty() ) { + weapons_count = std::stoi( target->get_value( weapons_str ) ); + } + + if( !target->get_value( timestamp_str ).empty() ) { + time_point last_check( std::stoi( target->get_value( timestamp_str ) ) ); + if( ( last_check + 10_seconds ) > calendar::turn ) { + return true; + } + // reset the weapons count if it has been more than an hour + if( ( last_check + 1_hours ) < calendar::turn ) { + weapons_count = 0; + } + } + target->set_value( timestamp_str, string_format( "%d", to_turn( calendar::turn ) ) ); + if( weapons_count < 3 ) { + if( target->weapon.is_gun() ) { + const gun_type_type &guntype = target->weapon.gun_type(); + if( guntype == gun_type_type( "rifle" ) || + guntype == gun_type_type( "shotgun" ) || + guntype == gun_type_type( "launcher" ) ) { + weapons_count += 2; + } else { + weapons_count += 1; + } + } else { + for( const item &worn_item : target->worn ) { + if( worn_item.is_gun() ) { + weapons_count += 1; + break; + } + } + } + summon_reinforcements = weapons_count >= 3; + } + target->set_value( weapons_str, string_format( "%d", weapons_count ) ); + + if( you.sees( z->pos() ) ) { + target->add_msg_player_or_npc( _( "The %s shines its light at you." ), + _( "The %s shines its light at ." ), + z->name() ); + } + std::string warning_signal = _( "a dull beep" ); + if( weapons_count == 1 ) { + warning_signal = _( "an ominous hum" ); + } else if( weapons_count == 2 ) { + warning_signal = _( "a threatening whirr" ); + } else if( weapons_count >= 3 ) { + warning_signal = _( "a high-pitched shriek" ); + } + warning_signal = string_format( _( "%s from the %s." ), warning_signal, z->name() ); + sounds::sound( z->pos(), 15 + 10 * weapons_count, sounds::sound_t::alarm, warning_signal ); + if( summon_reinforcements ) { + get_timed_events().add( timed_event_type::DSA_ALRP_SUMMON, + calendar::turn + rng( 5_turns, 10_turns ), + 0, target->global_sm_location() ); + } + return true; +} diff --git a/src/monattack.h b/src/monattack.h index 3f9e344d9ed80..3f976245600f6 100644 --- a/src/monattack.h +++ b/src/monattack.h @@ -107,6 +107,7 @@ bool grenadier( monster *z ); bool grenadier_elite( monster *z ); bool doot( monster *z ); bool zombie_fuse( monster *z ); +bool dsa_drone_scan( monster *z ); void taze( monster *z, Creature *target ); void rifle( monster *z, Creature *target ); // Automated M4 diff --git a/src/monstergenerator.cpp b/src/monstergenerator.cpp index 18dc7e8886a52..31bc369de1767 100644 --- a/src/monstergenerator.cpp +++ b/src/monstergenerator.cpp @@ -652,6 +652,7 @@ void MonsterGenerator::init_attack() add_hardcoded_attack( "GRAB", mattack::grab ); add_hardcoded_attack( "GRAB_DRAG", mattack::grab_drag ); add_hardcoded_attack( "DOOT", mattack::doot ); + add_hardcoded_attack( "DSA_DRONE_SCAN", mattack::dsa_drone_scan ); add_hardcoded_attack( "ZOMBIE_FUSE", mattack::zombie_fuse ); } diff --git a/src/timed_event.cpp b/src/timed_event.cpp index 983f521d77bd9..cc3536bdd20ae 100644 --- a/src/timed_event.cpp +++ b/src/timed_event.cpp @@ -8,6 +8,8 @@ #include "avatar.h" #include "avatar_action.h" #include "character.h" +#include "coordinate_conversions.h" +#include "coordinates.h" #include "debug.h" #include "enums.h" #include "event.h" @@ -15,7 +17,9 @@ #include "game.h" #include "game_constants.h" #include "line.h" +#include "magic.h" #include "map.h" +#include "map_extras.h" #include "map_iterator.h" #include "mapdata.h" #include "memorial_logger.h" @@ -35,6 +39,7 @@ static const mtype_id mon_amigara_horror( "mon_amigara_horror" ); static const mtype_id mon_copbot( "mon_copbot" ); static const mtype_id mon_dark_wyrm( "mon_dark_wyrm" ); static const mtype_id mon_dermatik( "mon_dermatik" ); +static const mtype_id mon_dsa_alien_dispatch( "mon_dsa_alien_dispatch" ); static const mtype_id mon_eyebot( "mon_eyebot" ); static const mtype_id mon_riotbot( "mon_riotbot" ); static const mtype_id mon_sewer_snake( "mon_sewer_snake" ); @@ -241,6 +246,24 @@ void timed_event::actualize() } break; + case timed_event_type::DSA_ALRP_SUMMON: { + const tripoint u_pos = player_character.global_sm_location(); + if( rl_dist( u_pos, map_point ) <= 4 ) { + const tripoint spot = here.getlocal( sm_to_ms_copy( map_point ) ); + monster dispatcher( mon_dsa_alien_dispatch ); + fake_spell summoning( spell_id( "dks_summon_alrp" ), true, 12 ); + summoning.get_spell().cast_all_effects( dispatcher, spot ); + } else { + tinymap mx_map; + tripoint_abs_sm map_pt( map_point ); + mx_map.load( map_pt, false ); + MapExtras::apply_function( "mx_dsa_alrp", mx_map, map_point ); + g->load_npcs(); + here.invalidate_map_cache( map_point.z ); + } + } + break; + default: // Nothing happens for other events break; diff --git a/src/timed_event.h b/src/timed_event.h index d408fa06477c2..bbf04553d576e 100644 --- a/src/timed_event.h +++ b/src/timed_event.h @@ -20,6 +20,7 @@ enum class timed_event_type : int { TEMPLE_SPAWN, DIM, ARTIFACT_LIGHT, + DSA_ALRP_SUMMON, NUM_TIMED_EVENT_TYPES }; From 8b8817576b43f82e1169049edccde0ae61ff8056 Mon Sep 17 00:00:00 2001 From: Brian-Otten <47374323+Brian-Otten@users.noreply.github.com> Date: Sat, 10 Apr 2021 09:44:36 +0200 Subject: [PATCH 146/453] simple makeshift glaive (#48386) --- .../json/items/melee/spears_and_polearms.json | 31 +++++++++++++++++++ data/json/items/tool/misc.json | 21 ------------- data/json/martialarts.json | 3 ++ data/json/recipes/weapon/cutting.json | 27 +++++++++++++++- data/json/recipes/weapon/piercing.json | 6 ---- 5 files changed, 60 insertions(+), 28 deletions(-) diff --git a/data/json/items/melee/spears_and_polearms.json b/data/json/items/melee/spears_and_polearms.json index 94ca953eb09c0..442d787531328 100644 --- a/data/json/items/melee/spears_and_polearms.json +++ b/data/json/items/melee/spears_and_polearms.json @@ -79,6 +79,37 @@ "qualities": [ [ "CUT", 1 ], [ "BUTCHER", -22 ] ], "flags": [ "FRAGILE_MELEE", "NONCONDUCTIVE", "POLEARM", "SHEATH_SPEAR", "REACH_ATTACK", "ALWAYS_TWOHAND" ] }, + { + "id": "makeshift_halberd", + "type": "GENERIC", + "name": { "str": "simple makeshift glaive" }, + "//": "Name changed to simple makeshift glaive, but changing the id would break e.g. tilesets.", + "description": "This is a large blade attached to a stout section of tree branch. It could do a considerable amount of damage.", + "weight": "1800 g", + "volume": "3 L", + "longest_side": "180 cm", + "price": 5000, + "price_postapoc": 250, + "to_hit": -1, + "bashing": 13, + "cutting": 31, + "material": [ "steel", "wood" ], + "symbol": "/", + "color": "light_gray", + "techniques": [ "WBLOCK_1" ], + "qualities": [ [ "CUT", 1 ], [ "BUTCHER", -42 ] ], + "flags": [ "REACH_ATTACK", "POLEARM", "NONCONDUCTIVE", "SHEATH_SPEAR", "FRAGILE_MELEE" ] + }, + { + "id": "makeshift_glaive", + "type": "GENERIC", + "copy-from": "makeshift_halberd", + "name": { "str": "makeshift glaive" }, + "description": "A stout tree branch that has been carefully split and reinforced. At the split point, a sharp blade has been bolted into place and reinforced with layers of sturdy wrapped bindings.", + "price_postapoc": 400, + "qualities": [ [ "CUT", 1 ], [ "BUTCHER", -28 ] ], + "delete": { "flags": [ "FRAGILE_MELEE" ] } + }, { "id": "spear_spike", "type": "TOOL", diff --git a/data/json/items/tool/misc.json b/data/json/items/tool/misc.json index 30912c1d2cd3f..9d03a6636ab21 100644 --- a/data/json/items/tool/misc.json +++ b/data/json/items/tool/misc.json @@ -432,27 +432,6 @@ "charges_per_use": 1, "use_action": [ "WATER_PURIFIER" ] }, - { - "id": "makeshift_halberd", - "type": "GENERIC", - "name": { "str": "makeshift glaive" }, - "//": "Name changed to glaive, but changing the id would break e.g. tilesets.", - "description": "This is a large blade attached to a stout section of tree branch. It could do a considerable amount of damage.", - "weight": "1800 g", - "volume": "3 L", - "longest_side": "180 cm", - "price": 5000, - "price_postapoc": 250, - "to_hit": -1, - "bashing": 13, - "cutting": 31, - "material": [ "steel", "wood" ], - "symbol": "/", - "color": "light_gray", - "techniques": [ "WBLOCK_1" ], - "qualities": [ [ "CUT", 1 ], [ "BUTCHER", -42 ] ], - "flags": [ "REACH_ATTACK", "POLEARM", "NONCONDUCTIVE", "SHEATH_SPEAR", "FRAGILE_MELEE" ] - }, { "type": "GENERIC", "id": "mind_splicer", diff --git a/data/json/martialarts.json b/data/json/martialarts.json index 65f5993f4a772..432fc0d767da0 100644 --- a/data/json/martialarts.json +++ b/data/json/martialarts.json @@ -520,6 +520,7 @@ "lucern_hammer", "lucern_hammerfake", "makeshift_halberd", + "makeshift_glaive", "pickaxe", "poleaxe", "primitive_axe" @@ -1184,6 +1185,7 @@ "machete", "machete_gimmick", "makeshift_halberd", + "makeshift_glaive", "makeshift_knife", "makeshift_machete", "naginata", @@ -1315,6 +1317,7 @@ "naginata_fake", "long_pole", "makeshift_halberd", + "makeshift_glaive", "pike", "pike_inferior", "pike_fake", diff --git a/data/json/recipes/weapon/cutting.json b/data/json/recipes/weapon/cutting.json index 2e403db2c9bd0..a7b30c2414ba6 100644 --- a/data/json/recipes/weapon/cutting.json +++ b/data/json/recipes/weapon/cutting.json @@ -132,6 +132,7 @@ "type": "recipe", "activity_level": "LIGHT_EXERCISE", "result": "makeshift_halberd", + "//": "this makes the simple makeshift glaive, but changing the id would break e.g. tilesets.", "category": "CC_WEAPON", "subcategory": "CSC_WEAPON_CUTTING", "skill_used": "fabrication", @@ -139,7 +140,31 @@ "reversible": true, "autolearn": true, "proficiencies": [ { "proficiency": "prof_carving", "time_multiplier": 1.5, "fail_multiplier": 1 } ], - "components": [ [ [ "duct_tape", 100 ] ], [ [ "blade", 1 ] ], [ [ "stick_long", 1 ] ] ] + "components": [ + [ [ "duct_tape", 100 ] ], + [ [ "blade", 1 ], [ "knife_meat_cleaver", 1 ], [ "knife_vegetable_cleaver", 1 ] ], + [ [ "stick_long", 1 ] ] + ] + }, + { + "type": "recipe", + "activity_level": "MODERATE_EXERCISE", + "result": "makeshift_glaive", + "category": "CC_WEAPON", + "subcategory": "CSC_WEAPON_PIERCING", + "skill_used": "fabrication", + "difficulty": 1, + "time": "45 m", + "reversible": true, + "autolearn": true, + "qualities": [ { "id": "CUT", "level": 1 }, { "id": "HAMMER", "level": 1 }, { "id": "DRILL", "level": 1 } ], + "proficiencies": [ { "proficiency": "prof_carving", "time_multiplier": 1.5, "fail_multiplier": 1.5 } ], + "components": [ + [ [ "duct_tape", 100 ] ], + [ [ "blade", 1 ], [ "knife_meat_cleaver", 1 ], [ "knife_vegetable_cleaver", 1 ] ], + [ [ "stick_long", 1 ] ], + [ [ "cordage", 2, "LIST" ] ] + ] }, { "type": "recipe", diff --git a/data/json/recipes/weapon/piercing.json b/data/json/recipes/weapon/piercing.json index 87e21aa990d2b..0177d47a17d13 100644 --- a/data/json/recipes/weapon/piercing.json +++ b/data/json/recipes/weapon/piercing.json @@ -615,9 +615,6 @@ [ "knife_butcher", 1 ], [ "knife_chef", 1 ], [ "knife_carving", 1 ], - [ "knife_vegetable_cleaver", 1 ], - [ "knife_meat_cleaver", 1 ], - [ "blade", 1 ], [ "knife_combat", 1 ], [ "knife_combat_mod", 1 ], [ "knife_hunting", 1 ], @@ -650,9 +647,6 @@ [ "knife_butcher", 1 ], [ "knife_chef", 1 ], [ "knife_carving", 1 ], - [ "knife_vegetable_cleaver", 1 ], - [ "knife_meat_cleaver", 1 ], - [ "blade", 1 ], [ "knife_combat", 1 ], [ "knife_combat_mod", 1 ], [ "knife_hunting", 1 ], From 235677aaef4470f71a2146e0a1e4142d63cfb774 Mon Sep 17 00:00:00 2001 From: Alexey Mostovoy <1931904+AMurkin@users.noreply.github.com> Date: Sat, 10 Apr 2021 12:41:13 +0300 Subject: [PATCH 147/453] Mark string for translation --- src/iexamine.cpp | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-) diff --git a/src/iexamine.cpp b/src/iexamine.cpp index b1988adf56136..fa0396b306565 100644 --- a/src/iexamine.cpp +++ b/src/iexamine.cpp @@ -4803,8 +4803,9 @@ void iexamine::autodoc( player &p, const tripoint &examp ) } autodoc_header += - string_format( "\n\nInternal supplies:\n Arm splints: %d\n Leg splints: %d", - arm_splints.size(), leg_splints.size() ); + string_format( + _( "\n\nInternal supplies:\n Arm splints: %d\n Leg splints: %d" ), + arm_splints.size(), leg_splints.size() ); uilist amenu; amenu.text = autodoc_header; From 6e6a5a7e95c016aaf89440e9e59bb96f557a8252 Mon Sep 17 00:00:00 2001 From: John Bytheway Date: Sun, 11 Apr 2021 05:18:31 -0400 Subject: [PATCH 148/453] Enable clang-tidy check for noexcept move constructors (#48467) * Mark many things noexcept Mark all our move constructors and move assignment operators noexcept. * Enable performance-noexcept-move-constructors This clang-tidy check looks for mone constructors which were are not noexcept, which can cause poor performance when those classes are e.g. used in a std::vector. --- .clang-tidy | 1 - src/character.cpp | 4 ++-- src/character.h | 4 ++-- src/clone_ptr.h | 4 ++-- src/creature.cpp | 5 +++++ src/creature.h | 8 ++++---- src/item.cpp | 4 ++-- src/item.h | 4 ++-- src/monster.cpp | 4 ++-- src/monster.h | 4 ++-- src/npc.cpp | 4 ++-- src/npc.h | 4 ++-- src/player.cpp | 4 ++-- src/player.h | 4 ++-- src/player_activity.h | 2 +- src/projectile.cpp | 2 +- src/projectile.h | 2 +- src/safe_reference.cpp | 16 ++++++++++++++++ src/safe_reference.h | 2 ++ src/submap.cpp | 4 ++-- src/submap.h | 4 ++-- src/value_ptr.h | 4 ++-- src/veh_type.cpp | 4 ++-- src/veh_type.h | 4 ++-- src/weighted_list.h | 6 ++++++ 25 files changed, 68 insertions(+), 40 deletions(-) diff --git a/.clang-tidy b/.clang-tidy index 2b0d987887aec..e4b6c9c5467d6 100644 --- a/.clang-tidy +++ b/.clang-tidy @@ -37,7 +37,6 @@ readability-*,\ -modernize-use-default-member-init,\ -modernize-use-emplace,\ -performance-inefficient-vector-operation,\ --performance-noexcept-move-constructor,\ -performance-implicit-conversion-in-loop,\ -performance-inefficient-string-concatenation,\ -performance-type-promotion-in-math-fn,\ diff --git a/src/character.cpp b/src/character.cpp index dfbc04cd40fbc..c3377ceb60688 100644 --- a/src/character.cpp +++ b/src/character.cpp @@ -488,8 +488,8 @@ Character::Character() : // *INDENT-ON* Character::~Character() = default; -Character::Character( Character && ) = default; -Character &Character::operator=( Character && ) = default; +Character::Character( Character && ) noexcept = default; +Character &Character::operator=( Character && ) noexcept = default; void Character::setID( character_id i, bool force ) { diff --git a/src/character.h b/src/character.h index eedd8b4dadb43..600a9b78f5db6 100644 --- a/src/character.h +++ b/src/character.h @@ -2747,8 +2747,8 @@ class Character : public Creature, public visitable protected: Character(); - Character( Character && ); - Character &operator=( Character && ); + Character( Character && ) noexcept; + Character &operator=( Character && ) noexcept; struct trait_data { /** Whether the mutation is activated. */ bool powered = false; diff --git a/src/clone_ptr.h b/src/clone_ptr.h index 28859daff3f63..0001a8dc2efe2 100644 --- a/src/clone_ptr.h +++ b/src/clone_ptr.h @@ -14,12 +14,12 @@ class clone_ptr // NOLINTNEXTLINE(google-explicit-constructor) clone_ptr( std::nullptr_t ) {} clone_ptr( const clone_ptr &other ) : p_( other.p_ ? other.p_->clone() : nullptr ) {} - clone_ptr( clone_ptr && ) = default; + clone_ptr( clone_ptr && ) noexcept = default; clone_ptr &operator=( const clone_ptr &other ) { p_ = other.p_ ? other.p_->clone() : nullptr; return *this; } - clone_ptr &operator=( clone_ptr && ) = default; + clone_ptr &operator=( clone_ptr && ) noexcept = default; // implicit conversion from unique_ptr template diff --git a/src/creature.cpp b/src/creature.cpp index 60d39652bfe13..6d8a4f4651fc0 100644 --- a/src/creature.cpp +++ b/src/creature.cpp @@ -114,6 +114,11 @@ Creature::Creature() fake = false; } +Creature::Creature( const Creature & ) = default; +Creature::Creature( Creature && ) noexcept = default; +Creature &Creature::operator=( const Creature & ) = default; +Creature &Creature::operator=( Creature && ) noexcept = default; + Creature::~Creature() = default; std::vector Creature::get_grammatical_genders() const diff --git a/src/creature.h b/src/creature.h index 799826d71e785..3915e0912f098 100644 --- a/src/creature.h +++ b/src/creature.h @@ -1172,10 +1172,10 @@ class Creature : public location, public viewer bool fake = false; Creature(); - Creature( const Creature & ) = default; - Creature( Creature && ) = default; - Creature &operator=( const Creature & ) = default; - Creature &operator=( Creature && ) = default; + Creature( const Creature & ); + Creature( Creature && ) noexcept; + Creature &operator=( const Creature & ); + Creature &operator=( Creature && ) noexcept; protected: virtual void on_stat_change( const std::string &, int ) {} diff --git a/src/item.cpp b/src/item.cpp index 5bac244aa48bb..4c79bc1efe9a0 100644 --- a/src/item.cpp +++ b/src/item.cpp @@ -437,10 +437,10 @@ item::item( const recipe *rec, item &component ) } item::item( const item & ) = default; -item::item( item && ) = default; +item::item( item && ) noexcept = default; item::~item() = default; item &item::operator=( const item & ) = default; -item &item::operator=( item && ) = default; +item &item::operator=( item && ) noexcept = default; item item::make_corpse( const mtype_id &mt, time_point turn, const std::string &name, const int upgrade_time ) diff --git a/src/item.h b/src/item.h index 75ccd1f5c0602..ad11c22a00657 100644 --- a/src/item.h +++ b/src/item.h @@ -180,9 +180,9 @@ class item : public visitable item(); - item( item && ); + item( item && ) noexcept; item( const item & ); - item &operator=( item && ); + item &operator=( item && ) noexcept; item &operator=( const item & ); explicit item( const itype_id &id, time_point turn = calendar::turn, int qty = -1 ); diff --git a/src/monster.cpp b/src/monster.cpp index 991485db63c6b..9b92c0e91c600 100644 --- a/src/monster.cpp +++ b/src/monster.cpp @@ -269,10 +269,10 @@ monster::monster( const mtype_id &id, const tripoint &p ) : monster( id ) } monster::monster( const monster & ) = default; -monster::monster( monster && ) = default; +monster::monster( monster && ) noexcept = default; monster::~monster() = default; monster &monster::operator=( const monster & ) = default; -monster &monster::operator=( monster && ) = default; +monster &monster::operator=( monster && ) noexcept = default; void monster::setpos( const tripoint &p ) { diff --git a/src/monster.h b/src/monster.h index 0297d4b3e4322..4ab96e8b615c5 100644 --- a/src/monster.h +++ b/src/monster.h @@ -90,10 +90,10 @@ class monster : public Creature explicit monster( const mtype_id &id ); monster( const mtype_id &id, const tripoint &pos ); monster( const monster & ); - monster( monster && ); + monster( monster && ) noexcept; ~monster() override; monster &operator=( const monster & ); - monster &operator=( monster && ); + monster &operator=( monster && ) noexcept; bool is_monster() const override { return true; diff --git a/src/npc.cpp b/src/npc.cpp index d6abf20bb4693..5caf6c2deb311 100644 --- a/src/npc.cpp +++ b/src/npc.cpp @@ -202,8 +202,8 @@ standard_npc::standard_npc( const std::string &name, const tripoint &pos, } } -npc::npc( npc && ) = default; -npc &npc::operator=( npc && ) = default; +npc::npc( npc && ) noexcept = default; +npc &npc::operator=( npc && ) noexcept = default; static std::map, npc_template> npc_templates; diff --git a/src/npc.h b/src/npc.h index 7554cb98fb431..3e380f7cafd61 100644 --- a/src/npc.h +++ b/src/npc.h @@ -761,9 +761,9 @@ class npc : public player npc(); npc( const npc & ) = delete; - npc( npc && ); + npc( npc && ) noexcept; npc &operator=( const npc & ) = delete; - npc &operator=( npc && ); + npc &operator=( npc && ) noexcept; ~npc() override; bool is_player() const override { diff --git a/src/player.cpp b/src/player.cpp index 73ce8e43fd20a..8cb7b3633d879 100644 --- a/src/player.cpp +++ b/src/player.cpp @@ -226,8 +226,8 @@ player::player() } player::~player() = default; -player::player( player && ) = default; -player &player::operator=( player && ) = default; +player::player( player && ) noexcept = default; +player &player::operator=( player && ) noexcept = default; void player::normalize() { diff --git a/src/player.h b/src/player.h index eb8a12fac4d7b..c683d4ee8bc7d 100644 --- a/src/player.h +++ b/src/player.h @@ -79,10 +79,10 @@ class player : public Character public: player(); player( const player & ) = delete; - player( player && ); + player( player && ) noexcept; ~player() override; player &operator=( const player & ) = delete; - player &operator=( player && ); + player &operator=( player && ) noexcept; /** Calls Character::normalize() * normalizes HP and body temperature diff --git a/src/player_activity.h b/src/player_activity.h index 82b2e5d9d21f9..d9811ef6d3dda 100644 --- a/src/player_activity.h +++ b/src/player_activity.h @@ -87,7 +87,7 @@ class player_activity player_activity( player_activity && ) noexcept = default; player_activity( const player_activity & ) = default; - player_activity &operator=( player_activity && ) = default; + player_activity &operator=( player_activity && ) noexcept = default; player_activity &operator=( const player_activity & ) = default; explicit operator bool() const { diff --git a/src/projectile.cpp b/src/projectile.cpp index 25a0df1616f51..1a3ed96063911 100644 --- a/src/projectile.cpp +++ b/src/projectile.cpp @@ -25,7 +25,7 @@ projectile::projectile() : projectile::~projectile() = default; -projectile::projectile( projectile && ) = default; +projectile::projectile( projectile && ) noexcept = default; projectile::projectile( const projectile &other ) { diff --git a/src/projectile.h b/src/projectile.h index 09cd211cd5d12..7d246c5812b02 100644 --- a/src/projectile.h +++ b/src/projectile.h @@ -46,7 +46,7 @@ struct projectile { projectile(); projectile( const projectile & ); - projectile( projectile && ); + projectile( projectile && ) noexcept; projectile &operator=( const projectile & ); ~projectile(); diff --git a/src/safe_reference.cpp b/src/safe_reference.cpp index d52082f7a93ee..6dd4c6e6ee924 100644 --- a/src/safe_reference.cpp +++ b/src/safe_reference.cpp @@ -1,5 +1,8 @@ #include "safe_reference.h" +static_assert( std::is_nothrow_move_constructible::value, "" ); +static_assert( std::is_nothrow_move_assignable::value, "" ); + safe_reference_anchor::safe_reference_anchor() { impl = std::make_shared(); @@ -9,8 +12,21 @@ safe_reference_anchor::safe_reference_anchor( const safe_reference_anchor & ) : safe_reference_anchor() {} +// Technically the move constructor and move assignment can throw bad_alloc, +// but we have no way to recover from that so mark it noexcept anyway; will +// cause terminate on out-of-memory. +safe_reference_anchor::safe_reference_anchor( safe_reference_anchor && ) noexcept : + safe_reference_anchor() +{} + safe_reference_anchor &safe_reference_anchor::operator=( const safe_reference_anchor & ) { impl = std::make_shared(); return *this; } + +safe_reference_anchor &safe_reference_anchor::operator=( safe_reference_anchor && ) noexcept +{ + impl = std::make_shared(); + return *this; +} diff --git a/src/safe_reference.h b/src/safe_reference.h index 2c660630e46f0..cdb1488ea1950 100644 --- a/src/safe_reference.h +++ b/src/safe_reference.h @@ -58,7 +58,9 @@ class safe_reference_anchor public: safe_reference_anchor(); safe_reference_anchor( const safe_reference_anchor & ); + safe_reference_anchor( safe_reference_anchor && ) noexcept; safe_reference_anchor &operator=( const safe_reference_anchor & ); + safe_reference_anchor &operator=( safe_reference_anchor && ) noexcept; template safe_reference reference_to( T *object ) { diff --git a/src/submap.cpp b/src/submap.cpp index 07cbedf62a7c8..cc424848e9a11 100644 --- a/src/submap.cpp +++ b/src/submap.cpp @@ -36,10 +36,10 @@ submap::submap() is_uniform = false; } -submap::submap( submap && ) = default; +submap::submap( submap && ) noexcept = default; submap::~submap() = default; -submap &submap::operator=( submap && ) = default; +submap &submap::operator=( submap && ) noexcept = default; static const std::string COSMETICS_GRAFFITI( "GRAFFITI" ); static const std::string COSMETICS_SIGNAGE( "SIGNAGE" ); diff --git a/src/submap.h b/src/submap.h index 5f0d8cfa71316..a08a681b9d32c 100644 --- a/src/submap.h +++ b/src/submap.h @@ -65,10 +65,10 @@ class submap : maptile_soa { public: submap(); - submap( submap && ); + submap( submap && ) noexcept; ~submap(); - submap &operator=( submap && ); + submap &operator=( submap && ) noexcept; trap_id get_trap( const point &p ) const { return trp[p.x][p.y]; diff --git a/src/value_ptr.h b/src/value_ptr.h index 5ade27a90c547..1266c7c7c619a 100644 --- a/src/value_ptr.h +++ b/src/value_ptr.h @@ -19,13 +19,13 @@ class value_ptr : public std::unique_ptr { public: value_ptr() = default; - value_ptr( value_ptr && ) = default; + value_ptr( value_ptr && ) noexcept = default; // NOLINTNEXTLINE(google-explicit-constructor) value_ptr( std::nullptr_t ) {} explicit value_ptr( T *value ) : std::unique_ptr( value ) {} value_ptr( const value_ptr &other ) : std::unique_ptr( other ? new T( *other ) : nullptr ) {} - value_ptr &operator=( value_ptr other ) { + value_ptr &operator=( value_ptr other ) noexcept { std::unique_ptr::operator=( std::move( other ) ); return *this; } diff --git a/src/veh_type.cpp b/src/veh_type.cpp index 1af5c6fe09cca..115dd218f96d5 100644 --- a/src/veh_type.cpp +++ b/src/veh_type.cpp @@ -1069,10 +1069,10 @@ bool string_id::is_valid() const } vehicle_prototype::vehicle_prototype() = default; -vehicle_prototype::vehicle_prototype( vehicle_prototype && ) = default; +vehicle_prototype::vehicle_prototype( vehicle_prototype && ) noexcept = default; vehicle_prototype::~vehicle_prototype() = default; -vehicle_prototype &vehicle_prototype::operator=( vehicle_prototype && ) = default; +vehicle_prototype &vehicle_prototype::operator=( vehicle_prototype && ) noexcept = default; /** *Caches a vehicle definition from a JsonObject to be loaded after itypes is initialized. diff --git a/src/veh_type.h b/src/veh_type.h index 923a3d2677d24..0e7febb173abf 100644 --- a/src/veh_type.h +++ b/src/veh_type.h @@ -495,10 +495,10 @@ struct vehicle_prototype { }; vehicle_prototype(); - vehicle_prototype( vehicle_prototype && ); + vehicle_prototype( vehicle_prototype && ) noexcept; ~vehicle_prototype(); - vehicle_prototype &operator=( vehicle_prototype && ); + vehicle_prototype &operator=( vehicle_prototype && ) noexcept; translation name; std::vector parts; diff --git a/src/weighted_list.h b/src/weighted_list.h index 065986e498b8e..57919982ef016 100644 --- a/src/weighted_list.h +++ b/src/weighted_list.h @@ -19,6 +19,10 @@ template struct weighted_object { template struct weighted_list { weighted_list() : total_weight( 0 ) { } + weighted_list( const weighted_list & ) = default; + weighted_list( weighted_list && ) noexcept = default; + weighted_list &operator=( const weighted_list & ) = default; + weighted_list &operator=( weighted_list && ) noexcept = default; virtual ~weighted_list() = default; /** @@ -224,6 +228,8 @@ template struct weighted_int_list : public weighted_list { std::vector precalc_array; }; +static_assert( std::is_nothrow_move_constructible>::value, "" ); + template struct weighted_float_list : public weighted_list { // TODO: precalc using alias method From 319596a5f401f2ae17b4d3c26280f414b851877a Mon Sep 17 00:00:00 2001 From: Maleclypse <54345792+Maleclypse@users.noreply.github.com> Date: Sun, 11 Apr 2021 04:21:27 -0500 Subject: [PATCH 149/453] Retractable security gates (#48336) --- .../terrain-fences-gates.json | 76 +++++++++++++++++++ data/json/mapgen/mall/mall_ground.json | 10 ++- src/activity_actor.cpp | 3 + src/activity_handlers.cpp | 9 +++ src/iuse.cpp | 6 ++ src/mapdata.cpp | 4 + src/mapdata.h | 1 + 7 files changed, 105 insertions(+), 4 deletions(-) diff --git a/data/json/furniture_and_terrain/terrain-fences-gates.json b/data/json/furniture_and_terrain/terrain-fences-gates.json index eda67920662ac..2ce44e7d8b8b0 100644 --- a/data/json/furniture_and_terrain/terrain-fences-gates.json +++ b/data/json/furniture_and_terrain/terrain-fences-gates.json @@ -128,6 +128,82 @@ ] } }, + { + "type": "terrain", + "id": "t_retractable_gate_l", + "name": "locked retractable gate", + "description": "A retractable security gate. The latch on this one is locked. With the right tools, you could cut the metal fence or disable the lock.", + "symbol": "+", + "color": "cyan", + "move_cost": 0, + "flags": [ "TRANSPARENT", "PERMEABLE", "LOCKED", "PICKABLE", "THIN_OBSTACLE" ], + "connects_to": "WALL", + "examine_action": "locked_object_pickable", + "bash": { + "str_min": 17, + "str_max": 175, + "str_min_blocked": 15, + "str_max_blocked": 175, + "sound": "metal screeching!", + "sound_fail": "clang!", + "ter_set": "t_null", + "items": [ + { "item": "wire", "count": [ 8, 20 ] }, + { "item": "chain", "count": [ 1, 2 ] }, + { "item": "scrap", "count": [ 0, 12 ] } + ] + } + }, + { + "type": "terrain", + "id": "t_retractable_gate_c", + "name": "closed retractable gate", + "description": "A retractable security gate with a latch system to stay closed.", + "symbol": "+", + "color": "cyan", + "move_cost": 0, + "flags": [ "TRANSPARENT", "DOOR", "PERMEABLE", "THIN_OBSTACLE" ], + "connects_to": "WALL", + "open": "t_retractable_gate_o", + "bash": { + "str_min": 17, + "str_max": 175, + "str_min_blocked": 20, + "str_max_blocked": 100, + "sound": "metal screeching!", + "sound_fail": "clang!", + "ter_set": "t_null", + "items": [ + { "item": "wire", "count": [ 6, 15 ] }, + { "item": "chain", "count": [ 1, 2 ] }, + { "item": "scrap", "count": [ 0, 12 ] } + ] + } + }, + { + "type": "terrain", + "id": "t_retractable_gate_o", + "name": "open retractable gate", + "description": "A retractable security gate with a latch system to stay closed. The latch is undone, so the gate has retracted up.", + "symbol": ".", + "color": "cyan", + "move_cost": 2, + "flags": [ "TRANSPARENT", "FLAT", "ROAD" ], + "connects_to": "WALL", + "close": "t_retractable_gate_c", + "bash": { + "str_min": 5, + "str_max": 150, + "sound": "metal screeching!", + "sound_fail": "clang!", + "ter_set": "t_null", + "items": [ + { "item": "wire", "count": [ 6, 15 ] }, + { "item": "pipe", "count": [ 6, 15 ] }, + { "item": "scrap", "count": [ 0, 12 ] } + ] + } + }, { "type": "terrain", "id": "t_fencegate_c", diff --git a/data/json/mapgen/mall/mall_ground.json b/data/json/mapgen/mall/mall_ground.json index 2f1b5032f5244..c42e0f1e7ef94 100644 --- a/data/json/mapgen/mall/mall_ground.json +++ b/data/json/mapgen/mall/mall_ground.json @@ -1434,7 +1434,7 @@ "ւГ˽˽˽˽˽˽˽˽˽˽˽˽˽˽˽˽˽˽˽˽˽˽˽˽˽˽ГГГɱɱ||||||^^99@@@99^9ɅɅɅ9Ʌ9^M^^M^^MMM^MM^H%,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,", "ւГɔɔɔɔɔɔɔ˽˽˽˽˽˽˽˽˽˽˽˽ɔɔɔɔɔɔɔГГɱЯɱHd|T^^^^9999999^9Ʌ999Ʌ9^^^^^^^^^^^^^dH.,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,", "ւГ˽˽˽˽˽˽˽˽˽˽˽˽˽˽˽˽˽˽˽˽˽˽˽˽˽˽ГГɱϻɱHy|T^^M^99ǝǝǝ99^9Ʌ9ɅɅɅ9^^^^^^777777^^H..FFF...,,.....FFF................,,,,,,.........", - "ւГ˽˽˽˽˽˽˽˽˽˽˽˽˽˽˽˽˽˽˽˽˽˽˽˽˽˽ГГɱЯɱHd|T^^M^9999999^9999999^^^^^^7))))7^Ŧ||||||||.,,.||HHH||HHH|^^^|HHH||||.,....,.||||HHH|", + "ւГ˽˽˽˽˽˽˽˽˽˽˽˽˽˽˽˽˽˽˽˽˽˽˽˽˽˽ГГɱЯɱHd|T^^M^9999999^9999999^^^^^^7))))7^Ŧ||||||||.,,.||HHH||HHH|óóó|HHH||||.,....,.||||HHH|", "ւГ˽˽˽˽˽˽˽˽˽˽˽˽˽˽˽˽˽˽˽˽˽˽˽˽˽˽ГГɱЯɱ|θ|T^^M^99@@@99^^^^^^^^^^^^^^7))))7^Ŧ|t_|t|t|.,,.|y:::yc:::y^^^^:::^Cy|.,,³³,,.Hd|Ħ^^^^", "ւГ˽˽˽˽˽˽˽˽˽˽˽˽˽˽˽˽˽˽˽˽˽˽˽˽˽˽ГГɱϻɱ|b^^^^^^9999999^^ĦĦĦ^^HHHH|y^777777^Ŧ|__|_|_|.,,.|b666666666666666666:H.,.°°.,.Hy|Ħ^3KK", "ւГ˽˽˽˽˽˽˽˽˽˽˽˽˽˽˽˽˽˽˽˽˽˽˽˽˽˽ГГɱЯɱ|Ħ^^KK^^^^^^^^^^^^^^^^^^^^|b^^^^^^^^b||=|=|=|.,,F|:664446644446466466:H.,,³³,,.Hd|Ħ^^^^", @@ -1442,7 +1442,7 @@ "ւГɔɔɔɔɔɔɔ˽˽˽˽˽˽˽˽˽˽˽˽ɔɔɔɔɔɔɔГГɱϻɱ|Ħ^^^^^^Ħ^^Δ^;^^K^K^^b|<^^^^^7((((7^Ŧ|______|.,,F|b66666664664646^b::yH.,,³³,,.|ydy=^^?", "ւГ˽˽˽˽˽˽˽˽˽˽˽˽˽˽˽˽˽˽˽˽˽˽˽˽˽˽ГГɱЯɱ|Ħ^^KK^^Ħ^^Δ^;^^K^K^^y|HHHH^^777777^Ŧ|______=.,,.|:66444664666646C|HHH|.,....,.|HHH|JƃJ", "ւГ˽˽˽˽˽˽˽˽˽˽˽˽˽˽˽˽˽˽˽˽˽˽˽˽˽˽ГГɱЯɱ|b^^KK^^Ħ^^Δ^;^^^^^^^^^^^^^^^7((((7^b|j0j0j0|.,,%|:66444664444666b|.....,,,,,,.....|Ħ^^", - "ւГ˽˽˽˽˽˽˽˽˽˽˽˽˽˽˽˽˽˽˽˽˽˽˽˽˽˽ГГɱϻɱ|Ħ^^^^^^Ħ^^^^^^^K^K^^^^^^^^^^777777^Ŧ||||||||.,,u|^66666666666666^^.,,,,,,,,,,,,,,.||||" + "ւГ˽˽˽˽˽˽˽˽˽˽˽˽˽˽˽˽˽˽˽˽˽˽˽˽˽˽ГГɱϻɱ|Ħ^^^^^^Ħ^^^^^^^K^K^^^^^^^^^^777777^Ŧ||||||||.,,u|^66666666666666^ó.,,,,,,,,,,,,,,.||||" ], "palettes": [ "mall_palette_2" ], "terrain": { @@ -1460,6 +1460,7 @@ "*": "t_linoleum_gray", "%": "t_linoleum_gray", "u": "t_linoleum_gray", + "ó": "t_retractable_gate_l", "@": "t_carpet_concrete_yellow", "ǝ": "t_carpet_concrete_yellow", "Ʌ": "t_carpet_concrete_yellow", @@ -1725,8 +1726,8 @@ "object": { "fill_ter": "t_floor", "rows": [ - "ւГ˽˽˽˽˽˽˽˽˽˽˽˽˽˽˽˽˽˽˽˽˽˽˽˽˽˽ГГɱЯɱ|^^^^d^^^^^d^^^^K^K^^d^^^^^^^^^^^^^^T|j0j0j0|.,,u|ƃJJJJ?JJJJJJJ^^^^.,,,,......,,,,.|_@@", - "ւГ˽˽˽˽˽˽˽˽˽˽˽˽˽˽˽˽˽˽˽˽˽˽˽˽˽˽ГГɱЯɱ|C^^^^^^^^^^^3^^^^^^^^^999999^^T|^||||______=.,,*|^^^^A^^^^^^^ƃ^^^^.,,,..1111..,,,.H_@ǝ", + "ւГ˽˽˽˽˽˽˽˽˽˽˽˽˽˽˽˽˽˽˽˽˽˽˽˽˽˽ГГɱЯɱ|^^^^d^^^^^d^^^^K^K^^d^^^^^^^^^^^^^^T|j0j0j0|.,,u|ƃJJJJ?JJJJJJJ^^^ó.,,,,......,,,,.|_@@", + "ւГ˽˽˽˽˽˽˽˽˽˽˽˽˽˽˽˽˽˽˽˽˽˽˽˽˽˽ГГɱЯɱ|C^^^^^^^^^^^3^^^^^^^^^999999^^T|^||||______=.,,*|^^^^A^^^^^^^ƃ^^^ó.,,,..1111..,,,.H_@ǝ", "ւГ˽˽˽˽˽˽˽˽˽˽˽˽˽˽˽˽˽˽˽˽˽˽˽˽˽˽ГГɱЯɱ|b^^KK^^Ħ^^d^3^999999^^9ɅɅɅɅ9^^T|^|bb|______|.,,.|y^Y~~~~^^:::J^::|.,,,.F1³³1F.,,,.H_@9", "ւГɔɔɔɔɔɔɔ˽˽˽˽˽˽˽˽˽˽˽˽ɔɔɔɔɔɔɔГГɱЯɱ|Ħ^^KK^^Ħ^^^^3^9@99@9^^9ɅɅɅɅ9^^T|^=^^|______|F,,.||θ|||||θ|HHH|||||.,,,.F1³³1F.,,,.|_99", "ւГ˽˽˽˽˽˽˽˽˽˽˽˽˽˽˽˽˽˽˽˽˽˽˽˽˽˽ГГɱЯɱ|Ħ^^^^^^Ħ^^d^3^9@99@9^^999999^^T|^|||||=|=|=|F,,.|w_0|P____NNNa|FF|.,,,.F1³³1F.,,,.__99", @@ -1771,6 +1772,7 @@ "*": "t_linoleum_gray", "%": "t_linoleum_gray", "u": "t_linoleum_gray", + "ó": "t_retractable_gate_l", "@": "t_carpet_concrete_yellow", "ǝ": "t_carpet_concrete_yellow", "Ʌ": "t_carpet_concrete_yellow", diff --git a/src/activity_actor.cpp b/src/activity_actor.cpp index 0da0e27715dd4..85c4a29833fa3 100644 --- a/src/activity_actor.cpp +++ b/src/activity_actor.cpp @@ -1217,6 +1217,9 @@ void lockpick_activity_actor::finish( player_activity &act, Character &who ) } else if( ter_type == t_door_locked_peep ) { new_ter_type = t_door_c_peep; open_message = _( "With a satisfying click, the lock on the door opens." ); + } else if( ter_type == t_retractable_gate_l ) { + new_ter_type = t_retractable_gate_c; + open_message = _( "With a satisfying click, the lock on the gate opens." ); } else if( ter_type == t_door_metal_pickable ) { new_ter_type = t_door_metal_c; open_message = _( "With a satisfying click, the lock on the door opens." ); diff --git a/src/activity_handlers.cpp b/src/activity_handlers.cpp index 87b98c5d350a9..b4a45eef7f360 100644 --- a/src/activity_handlers.cpp +++ b/src/activity_handlers.cpp @@ -209,6 +209,7 @@ static const itype_id itype_steel_chunk( "steel_chunk" ); static const itype_id itype_steel_plate( "steel_plate" ); static const itype_id itype_UPS( "UPS" ); static const itype_id itype_wire( "wire" ); +static const itype_id itype_chain( "chain" ); static const itype_id itype_wool_staple( "wool_staple" ); static const zone_type_id zone_type_FARM_PLOT( "FARM_PLOT" ); @@ -2305,6 +2306,10 @@ void activity_handlers::oxytorch_finish( player_activity *act, player *p ) here.ter_set( pos, t_pit ); here.spawn_item( pos, itype_spike, rng( 1, 19 ) ); here.spawn_item( pos, itype_scrap, rng( 1, 8 ) ); + } else if( ter == t_retractable_gate_c || ter == t_retractable_gate_l ) { + here.ter_set( pos, t_strconc_floor ); + here.spawn_item( pos, itype_chain, rng( 1, 2 ) ); + here.spawn_item( pos, itype_wire, rng( 8, 22 ) ); } else if( ter == t_bars ) { if( here.ter( pos + point_east ) == t_sewage || here.ter( pos + point_south ) == t_sewage || @@ -3584,6 +3589,10 @@ void activity_handlers::hacksaw_finish( player_activity *act, player *p ) here.ter_set( pos, t_pit ); here.spawn_item( p->pos(), itype_spike, 19 ); here.spawn_item( p->pos(), itype_scrap, 8 ); + } else if( ter == t_retractable_gate_c || ter == t_retractable_gate_l ) { + here.ter_set( pos, t_strconc_floor ); + here.spawn_item( pos, itype_chain, rng( 1, 2 ) ); + here.spawn_item( pos, itype_wire, rng( 8, 22 ) ); } else if( ter == t_bars ) { if( here.ter( pos + point_east ) == t_sewage || here.ter( pos + point_south ) == t_sewage || diff --git a/src/iuse.cpp b/src/iuse.cpp index af595aba5a23c..fa7214cfe609f 100644 --- a/src/iuse.cpp +++ b/src/iuse.cpp @@ -4995,6 +4995,8 @@ cata::optional iuse::oxytorch( player *p, item *it, bool, const tripoint & t_chainfence, t_chaingate_c, t_chaingate_l, + t_retractable_gate_l, + t_retractable_gate_c, t_bars, t_window_bars_alarm, t_window_bars, @@ -5059,6 +5061,7 @@ cata::optional iuse::oxytorch( player *p, item *it, bool, const tripoint & } else if( ter == t_window_enhanced || ter == t_window_enhanced_noglass ) { turns = to_turns( 5_seconds ); } else if( ter == t_chainfence || ter == t_chaingate_c || + ter == t_retractable_gate_c || ter == t_retractable_gate_l || ter == t_chaingate_l || ter == t_bars || ter == t_window_bars_alarm || ter == t_window_bars || ter == t_window_bars_curtains || ter == t_window_domestic || ter == t_reb_cage || ter == t_metal_grate_window || ter == t_metal_grate_window_with_curtain || @@ -5109,6 +5112,8 @@ cata::optional iuse::hacksaw( player *p, item *it, bool t, const tripoint & t_chainfence, t_chaingate_c, t_chaingate_l, + t_retractable_gate_l, + t_retractable_gate_c, t_window_bars_alarm, t_window_bars, t_window_bars_curtains, @@ -5164,6 +5169,7 @@ cata::optional iuse::hacksaw( player *p, item *it, bool t, const tripoint & } else if( ter == t_window_enhanced || ter == t_window_enhanced_noglass ) { moves = to_moves( 5_minutes ); } else if( ter == t_chainfence || ter == t_chaingate_c || ter == t_chaingate_l || + ter == t_retractable_gate_c || ter == t_retractable_gate_l || ter == t_window_bars_alarm || ter == t_window_bars || ter == t_window_bars_curtains || ter == t_window_bars_domestic || ter == t_reb_cage || ter == t_metal_grate_window || ter == t_metal_grate_window_with_curtain || ter == t_metal_grate_window_with_curtain_open || diff --git a/src/mapdata.cpp b/src/mapdata.cpp index 75431e198f9a5..303eec071f01a 100644 --- a/src/mapdata.cpp +++ b/src/mapdata.cpp @@ -564,6 +564,7 @@ ter_id t_null, t_rdoor_o, t_door_locked_interior, t_door_locked, t_door_locked_peep, t_door_locked_alarm, t_door_frame, t_chaingate_l, t_fencegate_c, t_fencegate_o, t_chaingate_c, t_chaingate_o, + t_retractable_gate_c, t_retractable_gate_l, t_retractable_gate_o, t_door_boarded, t_door_boarded_damaged, t_door_boarded_peep, t_rdoor_boarded, t_rdoor_boarded_damaged, t_door_boarded_damaged_peep, t_door_metal_c, t_door_metal_o, t_door_metal_locked, t_door_metal_pickable, t_mdoor_frame, @@ -747,6 +748,9 @@ void set_ter_ids() t_fencegate_o = ter_id( "t_fencegate_o" ); t_chaingate_c = ter_id( "t_chaingate_c" ); t_chaingate_o = ter_id( "t_chaingate_o" ); + t_retractable_gate_l = ter_id( "t_retractable_gate_l" ); + t_retractable_gate_c = ter_id( "t_retractable_gate_c" ); + t_retractable_gate_o = ter_id( "t_retractable_gate_o" ); t_door_boarded = ter_id( "t_door_boarded" ); t_door_boarded_damaged = ter_id( "t_door_boarded_damaged" ); t_door_boarded_peep = ter_id( "t_door_boarded_peep" ); diff --git a/src/mapdata.h b/src/mapdata.h index cc1457c5fd52c..6a4ee3195a788 100644 --- a/src/mapdata.h +++ b/src/mapdata.h @@ -478,6 +478,7 @@ extern ter_id t_null, t_door_c, t_door_c_peep, t_door_b, t_door_b_peep, t_door_o, t_door_o_peep, t_door_locked_interior, t_door_locked, t_door_locked_peep, t_door_locked_alarm, t_door_frame, t_chaingate_l, t_fencegate_c, t_fencegate_o, t_chaingate_c, t_chaingate_o, + t_retractable_gate_l, t_retractable_gate_c, t_retractable_gate_o, t_door_boarded, t_door_boarded_damaged, t_door_boarded_peep, t_rdoor_boarded, t_rdoor_boarded_damaged, t_door_boarded_damaged_peep, t_door_metal_c, t_door_metal_o, t_door_metal_locked, t_door_metal_pickable, From 08b8db6922585f357b5d15e7f00574ec5ee4b6db Mon Sep 17 00:00:00 2001 From: John Bytheway Date: Sun, 11 Apr 2021 08:27:11 -0400 Subject: [PATCH 150/453] Fix missing harvest entry introduced in #48228 --- data/mods/Dark-Skies-Above/monsters/alien_cyborgs.json | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/data/mods/Dark-Skies-Above/monsters/alien_cyborgs.json b/data/mods/Dark-Skies-Above/monsters/alien_cyborgs.json index 7a26fb3c5dfbc..6eea495a4ba5c 100644 --- a/data/mods/Dark-Skies-Above/monsters/alien_cyborgs.json +++ b/data/mods/Dark-Skies-Above/monsters/alien_cyborgs.json @@ -322,7 +322,7 @@ "special_attacks": [ { "type": "leap", "cooldown": 10, "max_range": 5 }, { "id": "melee_shock" } ], "path_settings": { "max_dist": 5 }, "death_function": [ "NORMAL" ], - "harvest": "dks_alien_cyborg", + "harvest": "dks_alien_hcyborg", "flags": [ "SEES", "HEARS", "SMELLS", "SWARMS", "WARM", "BASHES", "GROUP_BASH", "PRIORITIZE_TARGETS", "PATH_AVOID_DANGER_2" ] } ] From d51914056ce8d4a944f48d056494045bcdc4ea07 Mon Sep 17 00:00:00 2001 From: John Bytheway Date: Mon, 12 Apr 2021 21:37:17 -0400 Subject: [PATCH 151/453] Work around issues with STL move assignments (#48482) --- src/character.cpp | 2 +- src/character.h | 3 ++- src/compatibility.h | 16 ++++++++++++++++ src/item.cpp | 2 +- src/item.h | 3 ++- src/monster.cpp | 2 +- src/monster.h | 3 ++- src/npc.cpp | 2 +- src/npc.h | 2 +- src/player.cpp | 2 +- src/player.h | 2 +- src/veh_type.cpp | 3 ++- src/veh_type.h | 3 ++- 13 files changed, 33 insertions(+), 12 deletions(-) create mode 100644 src/compatibility.h diff --git a/src/character.cpp b/src/character.cpp index c3377ceb60688..ba6fd7c15bfe5 100644 --- a/src/character.cpp +++ b/src/character.cpp @@ -489,7 +489,7 @@ Character::Character() : Character::~Character() = default; Character::Character( Character && ) noexcept = default; -Character &Character::operator=( Character && ) noexcept = default; +Character &Character::operator=( Character && ) noexcept( list_is_noexcept ) = default; void Character::setID( character_id i, bool force ) { diff --git a/src/character.h b/src/character.h index 600a9b78f5db6..9b1db26a0a918 100644 --- a/src/character.h +++ b/src/character.h @@ -2748,7 +2748,8 @@ class Character : public Creature, public visitable protected: Character(); Character( Character && ) noexcept; - Character &operator=( Character && ) noexcept; + Character &operator=( Character && ) noexcept( list_is_noexcept ); + public: struct trait_data { /** Whether the mutation is activated. */ bool powered = false; diff --git a/src/compatibility.h b/src/compatibility.h new file mode 100644 index 0000000000000..528f2eaaff0bf --- /dev/null +++ b/src/compatibility.h @@ -0,0 +1,16 @@ +#ifndef CATA_SRC_COMPATIBILITY_H +#define CATA_SRC_COMPATIBILITY_H + +#include +#include + +// Some older standard libraries don't have all their classes +// nothrow-move-assignable when you might expect them to be. +// Some of our classes can't be in that case, so we need to know when we're in +// that situation. Can probably get rid of this once we're on C++17. +// std::list is a problem on clang-3.8 on Travis CI Ubuntu Xenial. +constexpr bool list_is_noexcept = std::is_nothrow_move_assignable>::value; +// std::string is a problem on gcc-5.3 on Travis CI Ubuntu Xenial. +constexpr bool string_is_noexcept = std::is_nothrow_move_assignable::value; + +#endif // CATA_SRC_COMPATIBILITY_H diff --git a/src/item.cpp b/src/item.cpp index 4c79bc1efe9a0..5e0e921af8217 100644 --- a/src/item.cpp +++ b/src/item.cpp @@ -440,7 +440,7 @@ item::item( const item & ) = default; item::item( item && ) noexcept = default; item::~item() = default; item &item::operator=( const item & ) = default; -item &item::operator=( item && ) noexcept = default; +item &item::operator=( item && ) noexcept( list_is_noexcept ) = default; item item::make_corpse( const mtype_id &mt, time_point turn, const std::string &name, const int upgrade_time ) diff --git a/src/item.h b/src/item.h index ad11c22a00657..7d2785a6ed39f 100644 --- a/src/item.h +++ b/src/item.h @@ -17,6 +17,7 @@ #include "calendar.h" #include "cata_utility.h" +#include "compatibility.h" #include "craft_command.h" #include "enums.h" #include "gun_mode.h" @@ -182,7 +183,7 @@ class item : public visitable item( item && ) noexcept; item( const item & ); - item &operator=( item && ) noexcept; + item &operator=( item && ) noexcept( list_is_noexcept ); item &operator=( const item & ); explicit item( const itype_id &id, time_point turn = calendar::turn, int qty = -1 ); diff --git a/src/monster.cpp b/src/monster.cpp index 9b92c0e91c600..78a3a7f2c3804 100644 --- a/src/monster.cpp +++ b/src/monster.cpp @@ -272,7 +272,7 @@ monster::monster( const monster & ) = default; monster::monster( monster && ) noexcept = default; monster::~monster() = default; monster &monster::operator=( const monster & ) = default; -monster &monster::operator=( monster && ) noexcept = default; +monster &monster::operator=( monster && ) noexcept( string_is_noexcept ) = default; void monster::setpos( const tripoint &p ) { diff --git a/src/monster.h b/src/monster.h index 4ab96e8b615c5..e3c4bf2d3d484 100644 --- a/src/monster.h +++ b/src/monster.h @@ -16,6 +16,7 @@ #include "calendar.h" #include "character_id.h" #include "color.h" +#include "compatibility.h" #include "creature.h" #include "damage.h" #include "enums.h" @@ -93,7 +94,7 @@ class monster : public Creature monster( monster && ) noexcept; ~monster() override; monster &operator=( const monster & ); - monster &operator=( monster && ) noexcept; + monster &operator=( monster && ) noexcept( string_is_noexcept ); bool is_monster() const override { return true; diff --git a/src/npc.cpp b/src/npc.cpp index 5caf6c2deb311..600b0262f0f79 100644 --- a/src/npc.cpp +++ b/src/npc.cpp @@ -203,7 +203,7 @@ standard_npc::standard_npc( const std::string &name, const tripoint &pos, } npc::npc( npc && ) noexcept = default; -npc &npc::operator=( npc && ) noexcept = default; +npc &npc::operator=( npc && ) noexcept( list_is_noexcept ) = default; static std::map, npc_template> npc_templates; diff --git a/src/npc.h b/src/npc.h index 3e380f7cafd61..c931086cb9cc4 100644 --- a/src/npc.h +++ b/src/npc.h @@ -763,7 +763,7 @@ class npc : public player npc( const npc & ) = delete; npc( npc && ) noexcept; npc &operator=( const npc & ) = delete; - npc &operator=( npc && ) noexcept; + npc &operator=( npc && ) noexcept( list_is_noexcept ); ~npc() override; bool is_player() const override { diff --git a/src/player.cpp b/src/player.cpp index 8cb7b3633d879..05c29b7d376ed 100644 --- a/src/player.cpp +++ b/src/player.cpp @@ -227,7 +227,7 @@ player::player() player::~player() = default; player::player( player && ) noexcept = default; -player &player::operator=( player && ) noexcept = default; +player &player::operator=( player && ) noexcept( list_is_noexcept ) = default; void player::normalize() { diff --git a/src/player.h b/src/player.h index c683d4ee8bc7d..cb6f60c6fa213 100644 --- a/src/player.h +++ b/src/player.h @@ -82,7 +82,7 @@ class player : public Character player( player && ) noexcept; ~player() override; player &operator=( const player & ) = delete; - player &operator=( player && ) noexcept; + player &operator=( player && ) noexcept( list_is_noexcept ); /** Calls Character::normalize() * normalizes HP and body temperature diff --git a/src/veh_type.cpp b/src/veh_type.cpp index 115dd218f96d5..8b4bbb98565ae 100644 --- a/src/veh_type.cpp +++ b/src/veh_type.cpp @@ -1072,7 +1072,8 @@ vehicle_prototype::vehicle_prototype() = default; vehicle_prototype::vehicle_prototype( vehicle_prototype && ) noexcept = default; vehicle_prototype::~vehicle_prototype() = default; -vehicle_prototype &vehicle_prototype::operator=( vehicle_prototype && ) noexcept = default; +vehicle_prototype &vehicle_prototype::operator=( vehicle_prototype && + ) noexcept( string_is_noexcept ) = default; /** *Caches a vehicle definition from a JsonObject to be loaded after itypes is initialized. diff --git a/src/veh_type.h b/src/veh_type.h index 0e7febb173abf..1319c7c21e815 100644 --- a/src/veh_type.h +++ b/src/veh_type.h @@ -16,6 +16,7 @@ #include "calendar.h" #include "color.h" +#include "compatibility.h" #include "damage.h" #include "optional.h" #include "point.h" @@ -498,7 +499,7 @@ struct vehicle_prototype { vehicle_prototype( vehicle_prototype && ) noexcept; ~vehicle_prototype(); - vehicle_prototype &operator=( vehicle_prototype && ) noexcept; + vehicle_prototype &operator=( vehicle_prototype && ) noexcept( string_is_noexcept ); translation name; std::vector parts; From 3279ee7b2e476e0c2127a07ed0efc41e66b60db0 Mon Sep 17 00:00:00 2001 From: John Bytheway Date: Tue, 13 Apr 2021 17:37:14 -0400 Subject: [PATCH 152/453] Enable performance-inefficient-vector-operation (#48480) * Add a collection of `vector::reserve` calls. All changes done automatically by clang-tidy. * Enable performance-inefficient-vector-operation --- .clang-tidy | 1 - src/activity_item_handling.cpp | 1 + src/cata_tiles.cpp | 1 + src/debug_menu.cpp | 2 ++ src/faction_camp.cpp | 1 + src/inventory.cpp | 1 + src/item_contents.cpp | 1 + src/magic_spell_effect.cpp | 1 + src/mission_companion.cpp | 1 + src/newcharacter.cpp | 1 + src/npc.h | 1 + src/requirements.cpp | 1 + tests/encumbrance_test.cpp | 1 + tests/generic_factory_test.cpp | 1 + tests/ranged_balance_test.cpp | 1 + tests/string_ids_test.cpp | 3 +++ 16 files changed, 18 insertions(+), 1 deletion(-) diff --git a/.clang-tidy b/.clang-tidy index e4b6c9c5467d6..9b1f40408b7db 100644 --- a/.clang-tidy +++ b/.clang-tidy @@ -36,7 +36,6 @@ readability-*,\ -modernize-return-braced-init-list,\ -modernize-use-default-member-init,\ -modernize-use-emplace,\ --performance-inefficient-vector-operation,\ -performance-implicit-conversion-in-loop,\ -performance-inefficient-string-concatenation,\ -performance-type-promotion-in-math-fn,\ diff --git a/src/activity_item_handling.cpp b/src/activity_item_handling.cpp index 226d4f4b61ec3..43529e831c4fe 100644 --- a/src/activity_item_handling.cpp +++ b/src/activity_item_handling.cpp @@ -2526,6 +2526,7 @@ static requirement_check_result generic_multi_activity_check_requirement( player // come back here after successfully fetching your stuff if( act_prev.coords.empty() ) { std::vector local_src_set; + local_src_set.reserve( src_set.size() ); for( const tripoint &elem : src_set ) { local_src_set.push_back( here.getlocal( elem ) ); } diff --git a/src/cata_tiles.cpp b/src/cata_tiles.cpp index 9b13ffba2d925..e276392fe44aa 100644 --- a/src/cata_tiles.cpp +++ b/src/cata_tiles.cpp @@ -3928,6 +3928,7 @@ std::vector cata_tiles::build_display_list() }; int numdisplays = SDL_GetNumVideoDisplays(); + display_names.reserve( numdisplays ); for( int i = 0 ; i < numdisplays ; i++ ) { display_names.emplace_back( std::to_string( i ), no_translation( SDL_GetDisplayName( i ) ) ); } diff --git a/src/debug_menu.cpp b/src/debug_menu.cpp index 1ef8722b50c4a..8233d04ddc03d 100644 --- a/src/debug_menu.cpp +++ b/src/debug_menu.cpp @@ -1956,6 +1956,7 @@ static void debug_menu_game_state() tripoint abs_sub = here.get_abs_sub(); std::string mfus; std::vector> sorted; + sorted.reserve( m_flag::MF_MAX ); for( int f = 0; f < m_flag::MF_MAX; f++ ) { sorted.push_back( {static_cast( f ), MonsterGenerator::generator().m_flag_usage_stats[f]} ); } @@ -1984,6 +1985,7 @@ static void debug_menu_game_state() if( !creature_counts.empty() ) { std::vector> creature_names_sorted; + creature_names_sorted.reserve( creature_counts.size() ); for( const std::pair &it : creature_counts ) { creature_names_sorted.emplace_back( it ); } diff --git a/src/faction_camp.cpp b/src/faction_camp.cpp index c139c8616ebab..99f2d76bab7cf 100644 --- a/src/faction_camp.cpp +++ b/src/faction_camp.cpp @@ -532,6 +532,7 @@ recipe_id base_camps::select_camp_option( const std::map std::vector pos_names; int choice = 0; + pos_names.reserve( pos_options.size() ); for( const auto &it : pos_options ) { pos_names.push_back( it.second.translated() ); } diff --git a/src/inventory.cpp b/src/inventory.cpp index bb0ae2be85daa..38e1b09796cf2 100644 --- a/src/inventory.cpp +++ b/src/inventory.cpp @@ -451,6 +451,7 @@ void inventory::form_from_zone( map &m, std::unordered_set &zone_pts, bool assign_invlet ) { std::vector pts; + pts.reserve( zone_pts.size() ); for( const tripoint &elem : zone_pts ) { pts.push_back( m.getlocal( elem ) ); } diff --git a/src/item_contents.cpp b/src/item_contents.cpp index 23cd9a86aac0c..2c055e1cdef65 100644 --- a/src/item_contents.cpp +++ b/src/item_contents.cpp @@ -149,6 +149,7 @@ bool pocket_favorite_callback::key( const input_context &, const input_event &ev } std::vector itype_initializer; + itype_initializer.reserve( nearby_itypes.size() ); for( const std::pair &name : nearby_itypes ) { itype_initializer.emplace_back( name.first ); } diff --git a/src/magic_spell_effect.cpp b/src/magic_spell_effect.cpp index 43978f1c511db..20da42d70dd54 100644 --- a/src/magic_spell_effect.cpp +++ b/src/magic_spell_effect.cpp @@ -1229,6 +1229,7 @@ void spell_effect::dash( const spell &sp, Creature &caster, const tripoint &targ ::map &here = get_map(); // uses abs() coordinates std::vector trajectory; + trajectory.reserve( trajectory_local.size() ); for( const tripoint &local_point : trajectory_local ) { trajectory.push_back( here.getabs( local_point ) ); } diff --git a/src/mission_companion.cpp b/src/mission_companion.cpp index 030cc39ea8667..a74d805de20c2 100644 --- a/src/mission_companion.cpp +++ b/src/mission_companion.cpp @@ -2054,6 +2054,7 @@ npc_ptr talk_function::companion_choose_return( const tripoint_abs_omt &omt_pos, } std::vector npcs; + npcs.reserve( available.size() ); for( auto &elem : available ) { npcs.push_back( ( elem )->name ); } diff --git a/src/newcharacter.cpp b/src/newcharacter.cpp index bbfe516e17030..ce53b30ac77b9 100644 --- a/src/newcharacter.cpp +++ b/src/newcharacter.cpp @@ -1447,6 +1447,7 @@ tab_direction set_traits( avatar &u, points_left &points ) // Grab a list of the names of the bionics that block this trait // So that the player know what is preventing them from taking it std::vector conflict_names; + conflict_names.reserve( cbms_blocking_trait.size() ); for( const bionic_id &conflict : cbms_blocking_trait ) { conflict_names.emplace_back( conflict->name.translated() ); } diff --git a/src/npc.h b/src/npc.h index c931086cb9cc4..15f17794716a3 100644 --- a/src/npc.h +++ b/src/npc.h @@ -177,6 +177,7 @@ class job_data const std::pair &b ) { return a.second > b.second; } ); + ret.reserve( pairs.size() ); for( const std::pair &elem : pairs ) { ret.push_back( elem.first ); } diff --git a/src/requirements.cpp b/src/requirements.cpp index ba5f4a0e712fa..8d769b7e2e798 100644 --- a/src/requirements.cpp +++ b/src/requirements.cpp @@ -72,6 +72,7 @@ const requirement_data &string_id::obj() const std::vector requirement_data::get_all() { std::vector ret; + ret.reserve( requirements_all.size() ); for( const std::pair &pair : requirements_all ) { ret.push_back( pair.second ); } diff --git a/tests/encumbrance_test.cpp b/tests/encumbrance_test.cpp index bb495a9eb030b..61eec9fbab457 100644 --- a/tests/encumbrance_test.cpp +++ b/tests/encumbrance_test.cpp @@ -61,6 +61,7 @@ static void test_encumbrance( { CAPTURE( clothing_types ); std::vector clothing; + clothing.reserve( clothing_types.size() ); for( const std::string &type : clothing_types ) { clothing.push_back( item( type ) ); } diff --git a/tests/generic_factory_test.cpp b/tests/generic_factory_test.cpp index 0da6ab03c8d6b..711668efe3f6d 100644 --- a/tests/generic_factory_test.cpp +++ b/tests/generic_factory_test.cpp @@ -380,6 +380,7 @@ TEST_CASE( "string_and_int_ids_benchmark", "[.][generic_factory][int_id][string_ } const int test_flags_size = test_flags.size(); std::vector test_dyn_str_ids; + test_dyn_str_ids.reserve( test_flags.size() ); for( const auto &f : test_flags ) { test_dyn_str_ids.push_back( dyn_str_id( f.str() ) ); } diff --git a/tests/ranged_balance_test.cpp b/tests/ranged_balance_test.cpp index 40997377ae042..7d7b8b9bf838a 100644 --- a/tests/ranged_balance_test.cpp +++ b/tests/ranged_balance_test.cpp @@ -117,6 +117,7 @@ static std::vector firing_test( const dispersion_sources &dis const int range, const std::vector< Threshold > &thresholds ) { std::vector firing_stats; + firing_stats.reserve( thresholds.size() ); for( const Threshold &pear : thresholds ) { firing_stats.push_back( firing_test( dispersion, range, pear ) ); } diff --git a/tests/string_ids_test.cpp b/tests/string_ids_test.cpp index 24d06dfbd0e46..c3e7957968273 100644 --- a/tests/string_ids_test.cpp +++ b/tests/string_ids_test.cpp @@ -37,6 +37,7 @@ TEST_CASE( "string_ids_intern_test", "[string_id]" ) struct test_obj {}; std::vector> ids; // lots of ids to make sure that "interning" map gets expanded + ids.reserve( num_ids ); for( int i = 0; i < num_ids; ++i ) { ids.push_back( string_id( "test_id" + std::to_string( i ) ) ); } @@ -119,6 +120,7 @@ TEST_CASE( "string_id_sorting_test", "[string_id]" ) SECTION( "vector ids sorting" ) { std::vector vec; + vec.reserve( 10 ); for( int i = 0; i < 10; ++i ) { vec.push_back( id( "id" + std::to_string( i ) ) ); } @@ -150,6 +152,7 @@ TEST_CASE( "string_id_creation_benchmark", "[.][string_id][benchmark]" ) { static constexpr int num_test_strings = 30; std::vector test_strings; + test_strings.reserve( num_test_strings ); for( int i = 0; i < num_test_strings; ++i ) { test_strings.push_back( "some_test_string_" + std::to_string( i ) ); } From 9945183fff9a0755b8f1a774f857dcf045d7cd63 Mon Sep 17 00:00:00 2001 From: John Bytheway Date: Wed, 12 Aug 2020 12:24:09 -0400 Subject: [PATCH 153/453] Simplify mapgen logic Previously there were separate dedicated components for terrain and furniture mapgen. But these are also supported in the more general format_placings so it simplifies the code to get rid of the special cases for terrain and furniture. (There's some performance cost here, but I don't think it's significant). --- src/mapgen.cpp | 165 ++++++++++++------------------------------------- src/mapgen.h | 11 ++-- 2 files changed, 45 insertions(+), 131 deletions(-) diff --git a/src/mapgen.cpp b/src/mapgen.cpp index dc0d5a664d435..6e9e446e29654 100644 --- a/src/mapgen.cpp +++ b/src/mapgen.cpp @@ -591,7 +591,6 @@ mapgen_function_json_base::mapgen_function_json_base( const json_source_location &jsrcloc, const std::string &context ) : jsrcloc( jsrcloc ) , context_( context ) - , do_format( false ) , is_ready( false ) , mapgensize( SEEX * 2, SEEY * 2 ) , objects( m_offset, mapgensize ) @@ -1538,6 +1537,11 @@ class jmapgen_terrain : public jmapgen_piece jmapgen_terrain( const JsonObject &jsi, const std::string &/*context*/ ) : jmapgen_terrain( jsi.get_string( "ter" ) ) {} explicit jmapgen_terrain( const std::string &tid ) : id( ter_id( tid ) ) {} + + bool is_nop() const override { + return id.id().is_null(); + } + void apply( const mapgendata &dat, const jmapgen_int &x, const jmapgen_int &y ) const override { dat.m.ter_set( point( x.get(), y.get() ), id ); @@ -2200,12 +2204,6 @@ void mapgen_palette::load_place_mapings( const JsonObject &jo, const std::string if( !jo.has_object( member_name ) ) { return; } - /* This is kind of a hack. Loading furniture/terrain from `jo` is already done in - * mapgen_palette::load_temp, continuing here would load it again and cause trouble. - */ - if( member_name == "terrain" || member_name == "furniture" ) { - return; - } for( const JsonMember member : jo.get_object( member_name ) ) { const map_key key( member ); auto &vect = format_placings[ key ]; @@ -2216,29 +2214,9 @@ void mapgen_palette::load_place_mapings( const JsonObject &jo, const std::string static std::map palettes; -static bool check_furn( const furn_id &id, const std::string &context ) -{ - const furn_t &furn = id.obj(); - if( furn.has_flag( "PLANT" ) ) { - debugmsg( "json mapgen for %s specifies furniture %s, which has flag " - "PLANT. Such furniture must be specified in a \"sealed_item\" special.", - context, furn.id.str() ); - // Only report once per mapgen object, otherwise the reports are - // very repetitive - return true; - } - return false; -} - void mapgen_palette::check() { std::string context = "palette " + id; - for( const std::pair &p : format_furniture ) { - if( check_furn( p.second, context ) ) { - return; - } - } - for( const std::pair>> &p : format_placings ) { for( const shared_ptr_fast &j : p.second ) { @@ -2296,11 +2274,8 @@ void mapgen_palette::add( const mapgen_palette &rh ) for( const auto &placing : rh.format_placings ) { format_placings[ placing.first ] = placing.second; } - for( const auto &placing : rh.format_terrain ) { - format_terrain[ placing.first ] = placing.second; - } - for( const auto &placing : rh.format_furniture ) { - format_furniture[ placing.first ] = placing.second; + for( const auto &placing : rh.keys_with_terrain ) { + keys_with_terrain.insert( placing ); } } @@ -2309,8 +2284,7 @@ mapgen_palette mapgen_palette::load_internal( const JsonObject &jo, const std::s { mapgen_palette new_pal; auto &format_placings = new_pal.format_placings; - auto &format_terrain = new_pal.format_terrain; - auto &format_furniture = new_pal.format_furniture; + auto &keys_with_terrain = new_pal.keys_with_terrain; if( require_id ) { new_pal.id = jo.get_string( "id" ); } @@ -2327,39 +2301,17 @@ mapgen_palette mapgen_palette::load_internal( const JsonObject &jo, const std::s } // mandatory: every character in rows must have matching entry, unless fill_ter is set - // "terrain": { "a": "t_grass", "b": "t_lava" } + // "terrain": { "a": "t_grass", "b": "t_lava" }. To help enforce this we + // keep track of everything in the "terrain" object if( jo.has_member( "terrain" ) ) { for( const JsonMember member : jo.get_object( "terrain" ) ) { - const map_key key( member ); - if( member.test_string() ) { - format_terrain[key] = ter_id( member.get_string() ); - } else { - auto &vect = format_placings[ key ]; - ::load_place_mapings( - member, vect, "terrain " + member.name() + " in palette " + new_pal.id ); - if( !vect.empty() ) { - // Dummy entry to signal that this terrain is actually defined, because - // the code below checks that each square on the map has a valid terrain - // defined somehow. - format_terrain[key] = t_null; - } - } + keys_with_terrain.insert( map_key( member ) ); } } - if( jo.has_object( "furniture" ) ) { - for( const JsonMember member : jo.get_object( "furniture" ) ) { - const map_key key( member ); - if( member.test_string() ) { - format_furniture[key] = furn_id( member.get_string() ); - } else { - auto &vect = format_placings[ key ]; - ::load_place_mapings( - member, vect, "furniture " + member.name() + " in palette " + new_pal.id ); - } - } - } std::string c = "palette " + new_pal.id; + new_pal.load_place_mapings( jo, "terrain", format_placings, c ); + new_pal.load_place_mapings( jo, "furniture", format_placings, c ); new_pal.load_place_mapings( jo, "fields", format_placings, c ); new_pal.load_place_mapings( jo, "npcs", format_placings, c ); new_pal.load_place_mapings( jo, "signs", format_placings, c ); @@ -2387,6 +2339,15 @@ mapgen_palette mapgen_palette::load_internal( const JsonObject &jo, const std::s new_pal.load_place_mapings( jo, "ter_furn_transforms", format_placings, c ); new_pal.load_place_mapings( jo, "faction_owner_character", format_placings, c ); + + for( mapgen_palette::placing_map::value_type &p : format_placings ) { + p.second.erase( + std::remove_if( + p.second.begin(), p.second.end(), + []( const shared_ptr_fast &placing ) { + return placing->is_nop(); + } ), p.second.end() ); + } return new_pal; } @@ -2486,15 +2447,13 @@ bool mapgen_function_json_base::setup_common( const JsonObject &jo ) JsonArray sparray; JsonObject pjo; - format.resize( static_cast( mapgensize.x * mapgensize.y ) ); // just like mapf::basic_bind("stuff",blargle("foo", etc) ), only json input and faster when applying if( jo.has_array( "rows" ) ) { mapgen_palette palette = mapgen_palette::load_temp( jo, "dda" ); - auto &format_terrain = palette.format_terrain; - auto &format_furniture = palette.format_furniture; + auto &keys_with_terrain = palette.keys_with_terrain; auto &format_placings = palette.format_placings; - if( format_terrain.empty() ) { + if( palette.keys_with_terrain.empty() ) { return false; } @@ -2524,12 +2483,10 @@ bool mapgen_function_json_base::setup_common( const JsonObject &jo ) for( int i = m_offset.x; i < expected_dim.x; i++ ) { const point p = point( i, c ) - m_offset; const map_key key = row_keys[i]; - const auto iter_ter = format_terrain.find( key ); - const auto iter_furn = format_furniture.find( key ); + const auto iter_ter = keys_with_terrain.find( key ); const auto fpi = format_placings.find( key ); - const bool has_terrain = iter_ter != format_terrain.end(); - const bool has_furn = iter_furn != format_furniture.end(); + const bool has_terrain = iter_ter != keys_with_terrain.end(); const bool has_placing = fpi != format_placings.end(); if( !has_terrain && !fallback_terrain_exists ) { @@ -2538,8 +2495,7 @@ bool mapgen_function_json_base::setup_common( const JsonObject &jo ) "'%s' is not in 'terrain', and no 'fill_ter' is set!", c + 1, i + 1, key.str ), c, i + 1 ); } - if( !has_terrain && !has_furn && !has_placing && - key.str != " " && key.str != "." ) { + if( !has_terrain && !has_placing && key.str != " " && key.str != "." ) { try { parray.string_error( string_format( "format: rows: row %d column %d: " @@ -2549,12 +2505,6 @@ bool mapgen_function_json_base::setup_common( const JsonObject &jo ) debugmsg( "(json-error)\n%s", e.what() ); } } - if( has_terrain ) { - format[ calc_index( p ) ].ter = iter_ter->second; - } - if( has_furn ) { - format[ calc_index( p ) ].furn = iter_furn->second; - } if( has_placing ) { jmapgen_place where( p ); for( auto &what : fpi->second ) { @@ -2564,7 +2514,6 @@ bool mapgen_function_json_base::setup_common( const JsonObject &jo ) } } fallback_terrain_exists = true; - do_format = true; } // No fill_ter? No format? GTFO. @@ -2622,14 +2571,22 @@ void mapgen_function_json_nested::check() const check_common(); } -void mapgen_function_json_base::check_common() const +static bool check_furn( const furn_id &id, const std::string &context ) { - for( const ter_furn_id &id : format ) { - if( check_furn( id.furn, context_ ) ) { - return; - } + const furn_t &furn = id.obj(); + if( furn.has_flag( "PLANT" ) ) { + debugmsg( "json mapgen for %s specifies furniture %s, which has flag " + "PLANT. Such furniture must be specified in a \"sealed_item\" special.", + context, furn.id.str() ); + // Only report once per mapgen object, otherwise the reports are + // very repetitive + return true; } + return false; +} +void mapgen_function_json_base::check_common() const +{ for( const jmapgen_setmap &setmap : setmap_points ) { if( setmap.op != JMAPGEN_SETMAP_FURN && setmap.op != JMAPGEN_SETMAP_LINE_FURN && @@ -2810,44 +2767,9 @@ bool jmapgen_setmap::has_vehicle_collision( const mapgendata &dat, const point & return false; } -void mapgen_function_json_base::formatted_set_incredibly_simple( map &m, const point &offset ) const -{ - for( int y = 0; y < mapgensize.y; y++ ) { - for( int x = 0; x < mapgensize.x; x++ ) { - point p( x, y ); - const size_t index = calc_index( p ); - const ter_furn_id &tdata = format[index]; - const point map_pos = p + offset; - if( tdata.furn != f_null ) { - if( tdata.ter != t_null ) { - m.set( map_pos, tdata.ter, tdata.furn ); - } else { - m.furn_set( map_pos, tdata.furn ); - } - } else if( tdata.ter != t_null ) { - m.ter_set( map_pos, tdata.ter ); - } - } - } -} - bool mapgen_function_json_base::has_vehicle_collision( const mapgendata &dat, const point &offset ) const { - if( do_format ) { - for( int y = 0; y < mapgensize.y; y++ ) { - for( int x = 0; x < mapgensize.x; x++ ) { - const point p( x, y ); - const ter_furn_id &tdata = format[calc_index( p )]; - const point map_pos = p + offset; - if( ( tdata.furn != f_null || tdata.ter != t_null ) && - dat.m.veh_at( tripoint( map_pos, dat.zlevel() ) ).has_value() ) { - return true; - } - } - } - } - for( const jmapgen_setmap &elem : setmap_points ) { if( elem.has_vehicle_collision( dat, offset ) ) { return true; @@ -2884,9 +2806,6 @@ void mapgen_function_json::generate( mapgendata &md ) m->rotate( ( -static_cast( md.terrain_type()->get_dir() ) + 4 ) % 4 ); } } - if( do_format ) { - formatted_set_incredibly_simple( *m, point_zero ); - } for( auto &elem : setmap_points ) { elem.apply( md, point_zero ); } @@ -2907,10 +2826,6 @@ void mapgen_function_json_nested::nest( const mapgendata &dat, const point &offs // TODO: Make rotation work for submaps, then pass this value into elem & objects apply. //int chosen_rotation = rotation.get() % 4; - if( do_format ) { - formatted_set_incredibly_simple( dat.m, offset ); - } - for( const jmapgen_setmap &elem : setmap_points ) { elem.apply( dat, offset ); } diff --git a/src/mapgen.h b/src/mapgen.h index 6a1b0b4cbcb70..34616459af352 100644 --- a/src/mapgen.h +++ b/src/mapgen.h @@ -8,6 +8,7 @@ #include #include #include +#include #include #include @@ -159,6 +160,9 @@ class jmapgen_piece protected: jmapgen_piece() : repeat( 1, 1 ) { } public: + virtual bool is_nop() const { + return false; + } /** Sanity-check this piece */ virtual void check( const std::string &/*context*/ ) const { } /** Place something on the map from mapgendata &dat, at (x,y). */ @@ -226,8 +230,7 @@ class mapgen_palette using placing_map = std::unordered_map>>; - std::unordered_map format_terrain; - std::unordered_map format_furniture; + std::unordered_set keys_with_terrain; placing_map format_placings; template @@ -338,14 +341,10 @@ class mapgen_function_json_base void check_common() const; - void formatted_set_incredibly_simple( map &m, const point &offset ) const; - - bool do_format; bool is_ready; point mapgensize; point m_offset; - std::vector format; std::vector setmap_points; jmapgen_objects objects; From f86dbb41a670cc89354bc774dbc9d6287c2e500e Mon Sep 17 00:00:00 2001 From: casswedson <58050969+casswedson@users.noreply.github.com> Date: Tue, 13 Apr 2021 23:38:25 -0500 Subject: [PATCH 154/453] fix typo (#48505) --- data/mods/Magiclysm/items/armor.json | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/data/mods/Magiclysm/items/armor.json b/data/mods/Magiclysm/items/armor.json index 1d6a47e552eda..ceb110b3009c4 100644 --- a/data/mods/Magiclysm/items/armor.json +++ b/data/mods/Magiclysm/items/armor.json @@ -72,7 +72,7 @@ "copy-from": "boots_chitin", "type": "ARMOR", "name": { "str": "pair of demon chitin boots", "str_pl": "pairs of demon chitin boots" }, - "description": "Boots crafted from carefully cleaned and pruned pruned red exoskeletons of demon spiders. Fire-resistant and very durable.", + "description": "Boots crafted from carefully cleaned and pruned red exoskeletons of demon spiders. Fire-resistant and very durable.", "material": [ "demon_chitin" ], "proportional": { "weight": 0.9, "encumbrance": 0.9, "price": 10, "warmth": 2 }, "environmental_protection": 8 From a51c59c82eb9d393de326da62679a7b394e907ce Mon Sep 17 00:00:00 2001 From: John Bytheway Date: Tue, 13 Apr 2021 15:31:33 -0400 Subject: [PATCH 155/453] Move HashCombine to clang-tidy-plugin/Utils.h Expecting this to be needed in multiple places now, so move to shared code. --- .../TestsMustRestoreGlobalStateCheck.h | 8 ++------ tools/clang-tidy-plugin/Utils.h | 11 +++++++++++ 2 files changed, 13 insertions(+), 6 deletions(-) diff --git a/tools/clang-tidy-plugin/TestsMustRestoreGlobalStateCheck.h b/tools/clang-tidy-plugin/TestsMustRestoreGlobalStateCheck.h index 92bbea8016388..0b80f96e8a378 100644 --- a/tools/clang-tidy-plugin/TestsMustRestoreGlobalStateCheck.h +++ b/tools/clang-tidy-plugin/TestsMustRestoreGlobalStateCheck.h @@ -6,6 +6,7 @@ #include #include "ClangTidy.h" +#include "Utils.h" namespace clang { @@ -36,12 +37,7 @@ namespace std template<> struct hash { std::size_t operator()( const clang::tidy::cata::RestoredDecl &r ) const noexcept { - hash function_hash; - hash decl_hash; - size_t result = function_hash( r.function ); - result ^= 0x9e3779b9 + ( result << 6 ) + ( result >> 2 ); - result ^= decl_hash( r.variable ); - return result; + return clang::tidy::cata::HashCombine( r.function, r.variable ); } }; } // namespace std diff --git a/tools/clang-tidy-plugin/Utils.h b/tools/clang-tidy-plugin/Utils.h index 5a39a1c45d8b2..df7a355ca45c1 100644 --- a/tools/clang-tidy-plugin/Utils.h +++ b/tools/clang-tidy-plugin/Utils.h @@ -206,6 +206,17 @@ class NameConvention bool valid = true; }; +template +inline size_t HashCombine( const T &t, const U &u ) +{ + std::hash t_hash; + std::hash u_hash; + size_t result = t_hash( t ); + result ^= 0x9e3779b9 + ( result << 6 ) + ( result >> 2 ); + result ^= u_hash( u ); + return result; +} + } // namespace cata } // namespace tidy } // namespace clang From 7f1bcb5ee6f3d8ddcbd7827784edb698e8e72733 Mon Sep 17 00:00:00 2001 From: John Bytheway Date: Tue, 13 Apr 2021 15:32:36 -0400 Subject: [PATCH 156/453] Add initial UnsequencedCallsCheck This check is intended to look for cases where code is calling multiple member functions of the same object, at least one of which is non-const, without an intervening sequence point. This has been the source of some bugs, primarily in JSON parsing, where objects might be extracted from JSON in an unexpected order. --- tools/clang-tidy-plugin/CMakeLists.txt | 1 + tools/clang-tidy-plugin/CataTidyModule.cpp | 2 + .../UnsequencedCallsCheck.cpp | 104 ++++++++++++++++++ .../clang-tidy-plugin/UnsequencedCallsCheck.h | 67 +++++++++++ .../test/unsequenced-calls.cpp | 23 ++++ 5 files changed, 197 insertions(+) create mode 100644 tools/clang-tidy-plugin/UnsequencedCallsCheck.cpp create mode 100644 tools/clang-tidy-plugin/UnsequencedCallsCheck.h create mode 100644 tools/clang-tidy-plugin/test/unsequenced-calls.cpp diff --git a/tools/clang-tidy-plugin/CMakeLists.txt b/tools/clang-tidy-plugin/CMakeLists.txt index 4b493eeab6c5c..54064951c5d67 100644 --- a/tools/clang-tidy-plugin/CMakeLists.txt +++ b/tools/clang-tidy-plugin/CMakeLists.txt @@ -23,6 +23,7 @@ add_library(CataAnalyzerPlugin MODULE TestsMustRestoreGlobalStateCheck.cpp TextStyleCheck.cpp TranslatorCommentsCheck.cpp + UnsequencedCallsCheck.cpp UseLocalizedSortingCheck.cpp UseNamedPointConstantsCheck.cpp UsePointApisCheck.cpp diff --git a/tools/clang-tidy-plugin/CataTidyModule.cpp b/tools/clang-tidy-plugin/CataTidyModule.cpp index 716aa0b509023..b8442e9344f3b 100644 --- a/tools/clang-tidy-plugin/CataTidyModule.cpp +++ b/tools/clang-tidy-plugin/CataTidyModule.cpp @@ -18,6 +18,7 @@ #include "TestsMustRestoreGlobalStateCheck.h" #include "TextStyleCheck.h" #include "TranslatorCommentsCheck.h" +#include "UnsequencedCallsCheck.h" #include "UseLocalizedSortingCheck.h" #include "UseNamedPointConstantsCheck.h" #include "UsePointApisCheck.h" @@ -55,6 +56,7 @@ class CataModule : public ClangTidyModule "cata-tests-must-restore-global-state" ); CheckFactories.registerCheck( "cata-text-style" ); CheckFactories.registerCheck( "cata-translator-comments" ); + CheckFactories.registerCheck( "cata-unsequenced-calls" ); CheckFactories.registerCheck( "cata-use-localized-sorting" ); CheckFactories.registerCheck( "cata-use-named-point-constants" ); diff --git a/tools/clang-tidy-plugin/UnsequencedCallsCheck.cpp b/tools/clang-tidy-plugin/UnsequencedCallsCheck.cpp new file mode 100644 index 0000000000000..c79bde41383ff --- /dev/null +++ b/tools/clang-tidy-plugin/UnsequencedCallsCheck.cpp @@ -0,0 +1,104 @@ +#include "UnsequencedCallsCheck.h" + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#include "Utils.h" + +using namespace clang::ast_matchers; + +namespace clang +{ +namespace tidy +{ +namespace cata +{ + +void UnsequencedCallsCheck::registerMatchers( MatchFinder *Finder ) +{ + Finder->addMatcher( + cxxMemberCallExpr( + on( declRefExpr( to( namedDecl().bind( "on" ) ) ) ) + ).bind( "memberCall" ), + this + ); +} + +// Keep walking up the AST so long as the nodes are expressions. When we reach +// a non-expression, return the previous expression. +// This is a vague approximation to finding the AST node which represents +// everything between two sequence points. +static const Expr *getContainingStatement( + const ast_matchers::MatchFinder::MatchResult &Result, const Expr *Node ) +{ + for( const ast_type_traits::DynTypedNode &parent : Result.Context->getParents( *Node ) ) { + if( const Expr *Candidate = parent.get() ) { + return getContainingStatement( Result, Candidate ); + } + } + + return Node; +} + +void UnsequencedCallsCheck::CheckCall( const MatchFinder::MatchResult &Result ) +{ + const CXXMemberCallExpr *MemberCall = + Result.Nodes.getNodeAs( "memberCall" ); + const NamedDecl *On = + Result.Nodes.getNodeAs( "on" ); + if( !MemberCall || !On ) { + return; + } + + const Expr *ContainingStatement = getContainingStatement( Result, MemberCall ); + + CallContext context{ ContainingStatement, On }; + calls_[context].push_back( MemberCall ); +} + +void UnsequencedCallsCheck::onEndOfTranslationUnit() +{ + for( const std::pair> &p : calls_ ) { + const CallContext &context = p.first; + const std::vector &calls = p.second; + + if( calls.size() < 2 ) { + continue; + } + bool any_non_const = false; + for( const CXXMemberCallExpr *member_call : calls ) { + const CXXMethodDecl *method = member_call->getMethodDecl(); + if( !method->isConst() ) { + any_non_const = true; + break; + } + } + + if( any_non_const ) { + diag( + context.stmt->getBeginLoc(), + "Unsequenced calls to member functions of %0, at least one of which is non-const." + ) << context.on; + } + } +} + +void UnsequencedCallsCheck::check( const MatchFinder::MatchResult &Result ) +{ + CheckCall( Result ); +} + +} // namespace cata +} // namespace tidy +} // namespace clang diff --git a/tools/clang-tidy-plugin/UnsequencedCallsCheck.h b/tools/clang-tidy-plugin/UnsequencedCallsCheck.h new file mode 100644 index 0000000000000..132a139f1798b --- /dev/null +++ b/tools/clang-tidy-plugin/UnsequencedCallsCheck.h @@ -0,0 +1,67 @@ +#ifndef CATA_TOOLS_CLANG_TIDY_PLUGIN_UNSEQUENCEDCALLSCHECK_H +#define CATA_TOOLS_CLANG_TIDY_PLUGIN_UNSEQUENCEDCALLSCHECK_H + +#include +#include + +#include "ClangTidy.h" +#include "Utils.h" + +namespace clang +{ + +namespace tidy +{ +class ClangTidyContext; + +namespace cata +{ + +struct CallContext { + const Expr *stmt; + const NamedDecl *on; + + bool operator==( const CallContext &other ) const { + return stmt == other.stmt && on == other.on; + } +}; + +} // namespace cata +} // namespace tidy +} // namespace clang + +namespace std +{ +template<> +struct hash { + std::size_t operator()( const clang::tidy::cata::CallContext &c ) const noexcept { + return clang::tidy::cata::HashCombine( c.stmt, c.on ); + } +}; +} // namespace std + +namespace clang +{ +namespace tidy +{ +namespace cata +{ + +class UnsequencedCallsCheck : public ClangTidyCheck +{ + public: + UnsequencedCallsCheck( StringRef Name, ClangTidyContext *Context ) + : ClangTidyCheck( Name, Context ) {} + void registerMatchers( ast_matchers::MatchFinder *Finder ) override; + void check( const ast_matchers::MatchFinder::MatchResult &Result ) override; + void onEndOfTranslationUnit() override; + private: + void CheckCall( const ast_matchers::MatchFinder::MatchResult & ); + std::unordered_map> calls_; +}; + +} // namespace cata +} // namespace tidy +} // namespace clang + +#endif // CATA_TOOLS_CLANG_TIDY_PLUGIN_UNSEQUENCEDCALLSCHECK_H diff --git a/tools/clang-tidy-plugin/test/unsequenced-calls.cpp b/tools/clang-tidy-plugin/test/unsequenced-calls.cpp new file mode 100644 index 0000000000000..600208298a494 --- /dev/null +++ b/tools/clang-tidy-plugin/test/unsequenced-calls.cpp @@ -0,0 +1,23 @@ +// RUN: %check_clang_tidy %s cata-unsequenced-calls %t -- -plugins=%cata_plugin -- + +struct A { + // Define a const and a non-const member function + int const_mf() const; + int nonconst_mf(); +}; + +void g( int, int ); + +void f0() +{ + A a; + // Two calls to const functions are fine + g( a.const_mf(), a.const_mf() ); + // But if at least one is non-const, raise a warning + g( a.nonconst_mf(), a.const_mf() ); + // CHECK-MESSAGES: [[@LINE-1]]:5: warning: Unsequenced calls to member functions of 'a', at least one of which is non-const. [cata-unsequenced-calls] + g( a.const_mf(), a.nonconst_mf() ); + // CHECK-MESSAGES: [[@LINE-1]]:5: warning: Unsequenced calls to member functions of 'a', at least one of which is non-const. [cata-unsequenced-calls] + g( a.nonconst_mf(), a.nonconst_mf() ); + // CHECK-MESSAGES: [[@LINE-1]]:5: warning: Unsequenced calls to member functions of 'a', at least one of which is non-const. [cata-unsequenced-calls] +} From 56ac5be01abb7c367340e8135d8302ca6837ec65 Mon Sep 17 00:00:00 2001 From: John Bytheway Date: Tue, 13 Apr 2021 19:32:54 -0400 Subject: [PATCH 157/453] Exempt more things from unsequenced calls check Treat member functions called begin, end, find as special and effectively const. Treat the ternary operator as sequencing its args. --- .../UnsequencedCallsCheck.cpp | 42 +++++++++++++++---- .../test/unsequenced-calls.cpp | 8 +++- 2 files changed, 42 insertions(+), 8 deletions(-) diff --git a/tools/clang-tidy-plugin/UnsequencedCallsCheck.cpp b/tools/clang-tidy-plugin/UnsequencedCallsCheck.cpp index c79bde41383ff..582062342bc1e 100644 --- a/tools/clang-tidy-plugin/UnsequencedCallsCheck.cpp +++ b/tools/clang-tidy-plugin/UnsequencedCallsCheck.cpp @@ -39,12 +39,15 @@ void UnsequencedCallsCheck::registerMatchers( MatchFinder *Finder ) // a non-expression, return the previous expression. // This is a vague approximation to finding the AST node which represents // everything between two sequence points. -static const Expr *getContainingStatement( +static const Expr *getContainingSequenceStatement( const ast_matchers::MatchFinder::MatchResult &Result, const Expr *Node ) { for( const ast_type_traits::DynTypedNode &parent : Result.Context->getParents( *Node ) ) { + if( parent.get() ) { + return Node; + } if( const Expr *Candidate = parent.get() ) { - return getContainingStatement( Result, Candidate ); + return getContainingSequenceStatement( Result, Candidate ); } } @@ -61,25 +64,39 @@ void UnsequencedCallsCheck::CheckCall( const MatchFinder::MatchResult &Result ) return; } - const Expr *ContainingStatement = getContainingStatement( Result, MemberCall ); + const Expr *ContainingStatement = getContainingSequenceStatement( Result, MemberCall ); CallContext context{ ContainingStatement, On }; calls_[context].push_back( MemberCall ); } +static bool IsEffectivelyConstCall( const CXXMemberCallExpr *Call ) +{ + const CXXMethodDecl *method = Call->getMethodDecl(); + if( method->isConst() ) { + return true; + } + StringRef Name = method->getName(); + if( Name == "begin" || Name == "end" || Name == "find" ) { + return true; + } + return false; +} + void UnsequencedCallsCheck::onEndOfTranslationUnit() { - for( const std::pair> &p : calls_ ) { + for( std::pair> &p : calls_ ) { const CallContext &context = p.first; - const std::vector &calls = p.second; + std::vector &calls = p.second; + std::sort( calls.begin(), calls.end() ); + calls.erase( std::unique( calls.begin(), calls.end() ), calls.end() ); if( calls.size() < 2 ) { continue; } bool any_non_const = false; for( const CXXMemberCallExpr *member_call : calls ) { - const CXXMethodDecl *method = member_call->getMethodDecl(); - if( !method->isConst() ) { + if( !IsEffectivelyConstCall( member_call ) ) { any_non_const = true; break; } @@ -90,6 +107,17 @@ void UnsequencedCallsCheck::onEndOfTranslationUnit() context.stmt->getBeginLoc(), "Unsequenced calls to member functions of %0, at least one of which is non-const." ) << context.on; + + for( const CXXMemberCallExpr *member_call : calls ) { + const CXXMethodDecl *method = member_call->getMethodDecl(); + if( IsEffectivelyConstCall( member_call ) ) { + diag( member_call->getBeginLoc(), "Call to const member function %0", + DiagnosticIDs::Note ) << method; + } else { + diag( member_call->getBeginLoc(), "Call to non-const member function %0", + DiagnosticIDs::Note ) << method; + } + } } } } diff --git a/tools/clang-tidy-plugin/test/unsequenced-calls.cpp b/tools/clang-tidy-plugin/test/unsequenced-calls.cpp index 600208298a494..c42bb5be9a2c9 100644 --- a/tools/clang-tidy-plugin/test/unsequenced-calls.cpp +++ b/tools/clang-tidy-plugin/test/unsequenced-calls.cpp @@ -4,6 +4,8 @@ struct A { // Define a const and a non-const member function int const_mf() const; int nonconst_mf(); + int begin(); + int end(); }; void g( int, int ); @@ -13,7 +15,11 @@ void f0() A a; // Two calls to const functions are fine g( a.const_mf(), a.const_mf() ); - // But if at least one is non-const, raise a warning + // Calls to begin/end are also fine + g( a.begin(), a.end() ); + // Calls in a ternary expression are fine + int n = a.nonconst_mf() ? a.nonconst_mf() : a.const_mf(); + // But otherwise, if at least one is non-const, raise a warning g( a.nonconst_mf(), a.const_mf() ); // CHECK-MESSAGES: [[@LINE-1]]:5: warning: Unsequenced calls to member functions of 'a', at least one of which is non-const. [cata-unsequenced-calls] g( a.const_mf(), a.nonconst_mf() ); From d95e3ada10db95593f48825afdd71ee81f410cac Mon Sep 17 00:00:00 2001 From: John Bytheway Date: Tue, 13 Apr 2021 20:20:51 -0400 Subject: [PATCH 158/453] Treat nested calls as sequenced Previously the UnsequencedCallsCheck was giving false positives for calls where one was nested within the other; prevent that. --- .../UnsequencedCallsCheck.cpp | 105 +++++++++++++----- .../clang-tidy-plugin/UnsequencedCallsCheck.h | 17 ++- .../test/unsequenced-calls.cpp | 6 +- 3 files changed, 99 insertions(+), 29 deletions(-) diff --git a/tools/clang-tidy-plugin/UnsequencedCallsCheck.cpp b/tools/clang-tidy-plugin/UnsequencedCallsCheck.cpp index 582062342bc1e..17e517062f462 100644 --- a/tools/clang-tidy-plugin/UnsequencedCallsCheck.cpp +++ b/tools/clang-tidy-plugin/UnsequencedCallsCheck.cpp @@ -13,6 +13,7 @@ #include #include #include +#include #include "Utils.h" @@ -39,21 +40,45 @@ void UnsequencedCallsCheck::registerMatchers( MatchFinder *Finder ) // a non-expression, return the previous expression. // This is a vague approximation to finding the AST node which represents // everything between two sequence points. -static const Expr *getContainingSequenceStatement( - const ast_matchers::MatchFinder::MatchResult &Result, const Expr *Node ) +static const Expr *GetContainingSequenceStatement( ASTContext *Context, const Expr *Node ) { - for( const ast_type_traits::DynTypedNode &parent : Result.Context->getParents( *Node ) ) { + for( const ast_type_traits::DynTypedNode &parent : Context->getParents( *Node ) ) { if( parent.get() ) { return Node; } if( const Expr *Candidate = parent.get() ) { - return getContainingSequenceStatement( Result, Candidate ); + return GetContainingSequenceStatement( Context, Candidate ); } } return Node; } +// Keep walking up the AST so long as the nodes are expressions. When we reach +// a non-expression, return the previous expression. +// This is a vague approximation to finding the AST node which represents +// everything between two sequence points. +static std::vector GetAncestorExpressions( ASTContext *Context, const Expr *Node ) +{ + const Expr *stop = GetContainingSequenceStatement( Context, Node ); + std::vector result; + const Expr *next; + do { + next = nullptr; + for( const ast_type_traits::DynTypedNode &parent : Context->getParents( *Node ) ) { + if( const Expr *candidate = parent.get() ) { + next = candidate; + break; + } + } + if( next ) { + result.push_back( next ); + } + } while( next && next != stop ); + + return result; +} + void UnsequencedCallsCheck::CheckCall( const MatchFinder::MatchResult &Result ) { const CXXMemberCallExpr *MemberCall = @@ -64,10 +89,10 @@ void UnsequencedCallsCheck::CheckCall( const MatchFinder::MatchResult &Result ) return; } - const Expr *ContainingStatement = getContainingSequenceStatement( Result, MemberCall ); + const Expr *ContainingStatement = GetContainingSequenceStatement( Result.Context, MemberCall ); CallContext context{ ContainingStatement, On }; - calls_[context].push_back( MemberCall ); + calls_[context].push_back( { MemberCall, Result.Context } ); } static bool IsEffectivelyConstCall( const CXXMemberCallExpr *Call ) @@ -85,40 +110,68 @@ static bool IsEffectivelyConstCall( const CXXMemberCallExpr *Call ) void UnsequencedCallsCheck::onEndOfTranslationUnit() { - for( std::pair> &p : calls_ ) { + for( std::pair> &p : calls_ ) { const CallContext &context = p.first; - std::vector &calls = p.second; + std::vector &calls = p.second; std::sort( calls.begin(), calls.end() ); calls.erase( std::unique( calls.begin(), calls.end() ), calls.end() ); if( calls.size() < 2 ) { continue; } - bool any_non_const = false; - for( const CXXMemberCallExpr *member_call : calls ) { - if( !IsEffectivelyConstCall( member_call ) ) { - any_non_const = true; - break; + std::unordered_set non_const_calls; + for( const CallWithASTContext &member_call : calls ) { + if( !IsEffectivelyConstCall( member_call.call ) ) { + non_const_calls.insert( member_call.call ); } } - if( any_non_const ) { - diag( - context.stmt->getBeginLoc(), - "Unsequenced calls to member functions of %0, at least one of which is non-const." - ) << context.on; - - for( const CXXMemberCallExpr *member_call : calls ) { - const CXXMethodDecl *method = member_call->getMethodDecl(); - if( IsEffectivelyConstCall( member_call ) ) { - diag( member_call->getBeginLoc(), "Call to const member function %0", - DiagnosticIDs::Note ) << method; + if( non_const_calls.empty() ) { + continue; + } + + // If some of the calls are an ancestor of other of the calls then we + // might not need to report it. + std::vector to_delete; + for( const CallWithASTContext &member_call : calls ) { + for( const Expr *ancestor : + GetAncestorExpressions( member_call.context, member_call.call ) ) { + auto in_set = std::find( calls.begin(), calls.end(), ancestor ); + if( in_set == calls.end() ) { + continue; + } + // We have found a pair with an ancestor relationship. Delete + // the most const one. + if( non_const_calls.count( in_set->call ) ) { + to_delete.push_back( member_call ); } else { - diag( member_call->getBeginLoc(), "Call to non-const member function %0", - DiagnosticIDs::Note ) << method; + to_delete.push_back( *in_set ); } } } + std::sort( to_delete.begin(), to_delete.end() ); + auto new_end = std::set_difference( + calls.begin(), calls.end(), to_delete.begin(), to_delete.end(), calls.begin() ); + calls.erase( new_end, calls.end() ); + if( calls.size() < 2 ) { + continue; + } + + diag( + context.stmt->getBeginLoc(), + "Unsequenced calls to member functions of %0, at least one of which is non-const." + ) << context.on; + + for( const CallWithASTContext &member_call : calls ) { + const CXXMethodDecl *method = member_call.call->getMethodDecl(); + if( IsEffectivelyConstCall( member_call.call ) ) { + diag( member_call.call->getBeginLoc(), "Call to const member function %0", + DiagnosticIDs::Note ) << method; + } else { + diag( member_call.call->getBeginLoc(), "Call to non-const member function %0", + DiagnosticIDs::Note ) << method; + } + } } } diff --git a/tools/clang-tidy-plugin/UnsequencedCallsCheck.h b/tools/clang-tidy-plugin/UnsequencedCallsCheck.h index 132a139f1798b..9d4dec47b85f0 100644 --- a/tools/clang-tidy-plugin/UnsequencedCallsCheck.h +++ b/tools/clang-tidy-plugin/UnsequencedCallsCheck.h @@ -26,6 +26,21 @@ struct CallContext { } }; +struct CallWithASTContext { + const CXXMemberCallExpr *call; + ASTContext *context; + + bool operator==( const CallWithASTContext &other ) const { + return call == other.call; + } + bool operator==( const Expr *other ) const { + return call == other; + } + bool operator<( const CallWithASTContext &other ) const { + return std::less<> {}( call, other.call ); + } +}; + } // namespace cata } // namespace tidy } // namespace clang @@ -57,7 +72,7 @@ class UnsequencedCallsCheck : public ClangTidyCheck void onEndOfTranslationUnit() override; private: void CheckCall( const ast_matchers::MatchFinder::MatchResult & ); - std::unordered_map> calls_; + std::unordered_map> calls_; }; } // namespace cata diff --git a/tools/clang-tidy-plugin/test/unsequenced-calls.cpp b/tools/clang-tidy-plugin/test/unsequenced-calls.cpp index c42bb5be9a2c9..15eee1cf2721f 100644 --- a/tools/clang-tidy-plugin/test/unsequenced-calls.cpp +++ b/tools/clang-tidy-plugin/test/unsequenced-calls.cpp @@ -2,8 +2,8 @@ struct A { // Define a const and a non-const member function - int const_mf() const; - int nonconst_mf(); + int const_mf( int = 0 ) const; + int nonconst_mf( int = 0 ); int begin(); int end(); }; @@ -19,6 +19,8 @@ void f0() g( a.begin(), a.end() ); // Calls in a ternary expression are fine int n = a.nonconst_mf() ? a.nonconst_mf() : a.const_mf(); + // Nested calls are OK + a.nonconst_mf( a.const_mf() ); // But otherwise, if at least one is non-const, raise a warning g( a.nonconst_mf(), a.const_mf() ); // CHECK-MESSAGES: [[@LINE-1]]:5: warning: Unsequenced calls to member functions of 'a', at least one of which is non-const. [cata-unsequenced-calls] From 6ba72e8770e2ecf14d1834e1e3e79036919b30a7 Mon Sep 17 00:00:00 2001 From: John Bytheway Date: Tue, 13 Apr 2021 20:34:38 -0400 Subject: [PATCH 159/453] Treat logical operators as sequencing Most false-positives for UnsequencedCallsCheck were related to logical operators. Handle those properly. --- tools/clang-tidy-plugin/UnsequencedCallsCheck.cpp | 6 ++++++ tools/clang-tidy-plugin/test/unsequenced-calls.cpp | 7 ++++++- 2 files changed, 12 insertions(+), 1 deletion(-) diff --git a/tools/clang-tidy-plugin/UnsequencedCallsCheck.cpp b/tools/clang-tidy-plugin/UnsequencedCallsCheck.cpp index 17e517062f462..65a706f968f0c 100644 --- a/tools/clang-tidy-plugin/UnsequencedCallsCheck.cpp +++ b/tools/clang-tidy-plugin/UnsequencedCallsCheck.cpp @@ -46,6 +46,11 @@ static const Expr *GetContainingSequenceStatement( ASTContext *Context, const Ex if( parent.get() ) { return Node; } + if( const BinaryOperator *op = parent.get() ) { + if( op->isLogicalOp() ) { + return Node; + } + } if( const Expr *Candidate = parent.get() ) { return GetContainingSequenceStatement( Context, Candidate ); } @@ -73,6 +78,7 @@ static std::vector GetAncestorExpressions( ASTContext *Context, co } if( next ) { result.push_back( next ); + Node = next; } } while( next && next != stop ); diff --git a/tools/clang-tidy-plugin/test/unsequenced-calls.cpp b/tools/clang-tidy-plugin/test/unsequenced-calls.cpp index 15eee1cf2721f..08a0a2783ce7a 100644 --- a/tools/clang-tidy-plugin/test/unsequenced-calls.cpp +++ b/tools/clang-tidy-plugin/test/unsequenced-calls.cpp @@ -18,7 +18,10 @@ void f0() // Calls to begin/end are also fine g( a.begin(), a.end() ); // Calls in a ternary expression are fine - int n = a.nonconst_mf() ? a.nonconst_mf() : a.const_mf(); + int n0 = a.nonconst_mf() ? a.nonconst_mf() : a.const_mf(); + // Or by short-circuiting boolean expressions + int n1 = a.nonconst_mf() && a.nonconst_mf(); + int n2 = a.nonconst_mf() || a.nonconst_mf(); // Nested calls are OK a.nonconst_mf( a.const_mf() ); // But otherwise, if at least one is non-const, raise a warning @@ -28,4 +31,6 @@ void f0() // CHECK-MESSAGES: [[@LINE-1]]:5: warning: Unsequenced calls to member functions of 'a', at least one of which is non-const. [cata-unsequenced-calls] g( a.nonconst_mf(), a.nonconst_mf() ); // CHECK-MESSAGES: [[@LINE-1]]:5: warning: Unsequenced calls to member functions of 'a', at least one of which is non-const. [cata-unsequenced-calls] + int n3 = a.nonconst_mf() | a.nonconst_mf(); + // CHECK-MESSAGES: [[@LINE-1]]:14: warning: Unsequenced calls to member functions of 'a', at least one of which is non-const. [cata-unsequenced-calls] } From 5e0389f828028cdc7a93ee275c9d6df17f4a966f Mon Sep 17 00:00:00 2001 From: John Bytheway Date: Tue, 13 Apr 2021 20:49:48 -0400 Subject: [PATCH 160/453] Better identification of effectively const methods Any method with an overload which is const can be treated as effectively const for the purposes of this check (ideally we'd also see whether the resulting use was const, but that's probably more complication than necessary). --- tools/clang-tidy-plugin/UnsequencedCallsCheck.cpp | 11 ++++++++--- tools/clang-tidy-plugin/test/unsequenced-calls.cpp | 2 ++ 2 files changed, 10 insertions(+), 3 deletions(-) diff --git a/tools/clang-tidy-plugin/UnsequencedCallsCheck.cpp b/tools/clang-tidy-plugin/UnsequencedCallsCheck.cpp index 65a706f968f0c..bf5480fd3183b 100644 --- a/tools/clang-tidy-plugin/UnsequencedCallsCheck.cpp +++ b/tools/clang-tidy-plugin/UnsequencedCallsCheck.cpp @@ -107,9 +107,14 @@ static bool IsEffectivelyConstCall( const CXXMemberCallExpr *Call ) if( method->isConst() ) { return true; } - StringRef Name = method->getName(); - if( Name == "begin" || Name == "end" || Name == "find" ) { - return true; + DeclarationName name = method->getDeclName(); + DeclContextLookupResult similar_functions = method->getParent()->lookup( name ); + for( const NamedDecl *similar : similar_functions ) { + if( const CXXMethodDecl *similar_function = dyn_cast( similar ) ) { + if( similar_function->isConst() ) { + return true; + } + } } return false; } diff --git a/tools/clang-tidy-plugin/test/unsequenced-calls.cpp b/tools/clang-tidy-plugin/test/unsequenced-calls.cpp index 08a0a2783ce7a..8846a9dcf6cbc 100644 --- a/tools/clang-tidy-plugin/test/unsequenced-calls.cpp +++ b/tools/clang-tidy-plugin/test/unsequenced-calls.cpp @@ -6,6 +6,8 @@ struct A { int nonconst_mf( int = 0 ); int begin(); int end(); + int begin() const; + int end() const; }; void g( int, int ); From 22d155fdf7d3d26230512ba20909baff9f49a09e Mon Sep 17 00:00:00 2001 From: John Bytheway Date: Wed, 14 Apr 2021 07:09:07 -0400 Subject: [PATCH 161/453] Provide class name in UnsequencedCallsCheck It's useful for the warning message to also provide the type name of the thing on which the member function calls are being made. --- tools/clang-tidy-plugin/UnsequencedCallsCheck.cpp | 7 +++++-- tools/clang-tidy-plugin/test/unsequenced-calls.cpp | 8 ++++---- 2 files changed, 9 insertions(+), 6 deletions(-) diff --git a/tools/clang-tidy-plugin/UnsequencedCallsCheck.cpp b/tools/clang-tidy-plugin/UnsequencedCallsCheck.cpp index bf5480fd3183b..fe9729214855b 100644 --- a/tools/clang-tidy-plugin/UnsequencedCallsCheck.cpp +++ b/tools/clang-tidy-plugin/UnsequencedCallsCheck.cpp @@ -168,10 +168,13 @@ void UnsequencedCallsCheck::onEndOfTranslationUnit() continue; } + const CXXRecordDecl *class_type = calls[0].call->getRecordDecl(); + diag( context.stmt->getBeginLoc(), - "Unsequenced calls to member functions of %0, at least one of which is non-const." - ) << context.on; + "Unsequenced calls to member functions of %0 (of type %1), at least one of which is " + "non-const." + ) << context.on << class_type; for( const CallWithASTContext &member_call : calls ) { const CXXMethodDecl *method = member_call.call->getMethodDecl(); diff --git a/tools/clang-tidy-plugin/test/unsequenced-calls.cpp b/tools/clang-tidy-plugin/test/unsequenced-calls.cpp index 8846a9dcf6cbc..cd73eef2341fc 100644 --- a/tools/clang-tidy-plugin/test/unsequenced-calls.cpp +++ b/tools/clang-tidy-plugin/test/unsequenced-calls.cpp @@ -28,11 +28,11 @@ void f0() a.nonconst_mf( a.const_mf() ); // But otherwise, if at least one is non-const, raise a warning g( a.nonconst_mf(), a.const_mf() ); - // CHECK-MESSAGES: [[@LINE-1]]:5: warning: Unsequenced calls to member functions of 'a', at least one of which is non-const. [cata-unsequenced-calls] + // CHECK-MESSAGES: [[@LINE-1]]:5: warning: Unsequenced calls to member functions of 'a' (of type 'A'), at least one of which is non-const. [cata-unsequenced-calls] g( a.const_mf(), a.nonconst_mf() ); - // CHECK-MESSAGES: [[@LINE-1]]:5: warning: Unsequenced calls to member functions of 'a', at least one of which is non-const. [cata-unsequenced-calls] + // CHECK-MESSAGES: [[@LINE-1]]:5: warning: Unsequenced calls to member functions of 'a' (of type 'A'), at least one of which is non-const. [cata-unsequenced-calls] g( a.nonconst_mf(), a.nonconst_mf() ); - // CHECK-MESSAGES: [[@LINE-1]]:5: warning: Unsequenced calls to member functions of 'a', at least one of which is non-const. [cata-unsequenced-calls] + // CHECK-MESSAGES: [[@LINE-1]]:5: warning: Unsequenced calls to member functions of 'a' (of type 'A'), at least one of which is non-const. [cata-unsequenced-calls] int n3 = a.nonconst_mf() | a.nonconst_mf(); - // CHECK-MESSAGES: [[@LINE-1]]:14: warning: Unsequenced calls to member functions of 'a', at least one of which is non-const. [cata-unsequenced-calls] + // CHECK-MESSAGES: [[@LINE-1]]:14: warning: Unsequenced calls to member functions of 'a' (of type 'A'), at least one of which is non-const. [cata-unsequenced-calls] } From e3cc99d882e8b2e86e857de6242b677d5a0ccc96 Mon Sep 17 00:00:00 2001 From: John Bytheway Date: Wed, 14 Apr 2021 08:21:01 -0400 Subject: [PATCH 162/453] Know that list initialization is sequenced To avoid one more class of false positives in UnsequencedCallsCheck, note that the subexpressions of a list initialization are sequenced. --- .../clang-tidy-plugin/UnsequencedCallsCheck.cpp | 8 +++++++- .../test/unsequenced-calls.cpp | 17 +++++++++++++++++ 2 files changed, 24 insertions(+), 1 deletion(-) diff --git a/tools/clang-tidy-plugin/UnsequencedCallsCheck.cpp b/tools/clang-tidy-plugin/UnsequencedCallsCheck.cpp index fe9729214855b..5c20feb2afe1e 100644 --- a/tools/clang-tidy-plugin/UnsequencedCallsCheck.cpp +++ b/tools/clang-tidy-plugin/UnsequencedCallsCheck.cpp @@ -37,7 +37,8 @@ void UnsequencedCallsCheck::registerMatchers( MatchFinder *Finder ) } // Keep walking up the AST so long as the nodes are expressions. When we reach -// a non-expression, return the previous expression. +// a non-expression or an expressions whose subexpressions we know to be +// sequenced (like a short-circuiting logical operator), return the previous expression. // This is a vague approximation to finding the AST node which represents // everything between two sequence points. static const Expr *GetContainingSequenceStatement( ASTContext *Context, const Expr *Node ) @@ -51,6 +52,11 @@ static const Expr *GetContainingSequenceStatement( ASTContext *Context, const Ex return Node; } } + if( const CXXConstructExpr *construct = parent.get() ) { + if( construct->isListInitialization() ) { + return Node; + } + } if( const Expr *Candidate = parent.get() ) { return GetContainingSequenceStatement( Context, Candidate ); } diff --git a/tools/clang-tidy-plugin/test/unsequenced-calls.cpp b/tools/clang-tidy-plugin/test/unsequenced-calls.cpp index cd73eef2341fc..4da9839a0b289 100644 --- a/tools/clang-tidy-plugin/test/unsequenced-calls.cpp +++ b/tools/clang-tidy-plugin/test/unsequenced-calls.cpp @@ -12,6 +12,10 @@ struct A { void g( int, int ); +struct B { + B( int, int ); +}; + void f0() { A a; @@ -36,3 +40,16 @@ void f0() int n3 = a.nonconst_mf() | a.nonconst_mf(); // CHECK-MESSAGES: [[@LINE-1]]:14: warning: Unsequenced calls to member functions of 'a' (of type 'A'), at least one of which is non-const. [cata-unsequenced-calls] } + +void f1() +{ + A a; + // Calls in args to a 'regular' constructor are dangerous + B b0( a.nonconst_mf(), a.nonconst_mf() ); + // CHECK-MESSAGES: [[@LINE-1]]:7: warning: Unsequenced calls to member functions of 'a' (of type 'A'), at least one of which is non-const. [cata-unsequenced-calls] + + // ...but using an initializer-list style is OK, because those are + // sequenced. + B b1{ a.nonconst_mf(), a.nonconst_mf() }; + B b2 = { a.nonconst_mf(), a.nonconst_mf() }; +} From bc4bdaf401792ccd99ba5585fde595b4d87196c4 Mon Sep 17 00:00:00 2001 From: John Bytheway Date: Wed, 14 Apr 2021 08:22:28 -0400 Subject: [PATCH 163/453] Fix warnings discovered by UnsequencesCallsCheck These are mostly just member functions which should have been const but weren't. There were a few places where I chose to refactor the code and one place got a suppression. I don't think any of these were actual bugs, but in some cases they could have become bugs in the right corner cases. --- src/construction.cpp | 2 +- src/iexamine.cpp | 3 ++- src/item.cpp | 5 +---- src/item.h | 2 +- src/iuse.cpp | 3 ++- src/mapgendata.cpp | 1 + src/melee.cpp | 3 ++- src/mission.cpp | 4 ++-- src/mission.h | 4 ++-- src/monster.cpp | 6 +++--- src/monster.h | 6 +++--- src/npctalk_funcs.cpp | 6 ++++-- src/overmap.h | 6 ++++++ src/pathfinding.cpp | 2 +- src/ranged.cpp | 6 ++++-- src/vehicle.cpp | 2 +- src/vehicle.h | 3 +-- src/vehicle_move.cpp | 2 +- src/visitable.cpp | 8 ++++---- tests/crafting_test.cpp | 3 ++- 20 files changed, 44 insertions(+), 33 deletions(-) diff --git a/src/construction.cpp b/src/construction.cpp index 37bff408b3a50..9b6ebf9726bc2 100644 --- a/src/construction.cpp +++ b/src/construction.cpp @@ -1195,7 +1195,7 @@ void construct::done_grave( const tripoint &p ) Character &player_character = get_player_character(); map &here = get_map(); map_stack its = here.i_at( p ); - for( item it : its ) { + for( const item &it : its ) { if( it.is_corpse() ) { if( it.get_corpse_name().empty() ) { if( it.get_mtype()->has_flag( MF_HUMAN ) ) { diff --git a/src/iexamine.cpp b/src/iexamine.cpp index fa0396b306565..b5f0cca66b6ea 100644 --- a/src/iexamine.cpp +++ b/src/iexamine.cpp @@ -6130,7 +6130,8 @@ void iexamine::workbench_internal( player &p, const tripoint &examp, break; } const recipe &rec = selected_craft->get_making(); - if( p.has_recipe( &rec, p.crafting_inventory(), p.get_crafting_helpers() ) == -1 ) { + const inventory &inv = p.crafting_inventory(); + if( p.has_recipe( &rec, inv, p.get_crafting_helpers() ) == -1 ) { p.add_msg_player_or_npc( _( "You don't know the recipe for the %s and can't continue crafting." ), _( " doesn't know the recipe for the %s and can't continue crafting." ), diff --git a/src/item.cpp b/src/item.cpp index 5e0e921af8217..9aad8c3eea291 100644 --- a/src/item.cpp +++ b/src/item.cpp @@ -10604,11 +10604,8 @@ std::string item::type_name( unsigned int quantity ) const return ret_name; } -std::string item::get_corpse_name() +std::string item::get_corpse_name() const { - if( corpse_name.empty() ) { - return std::string(); - } return corpse_name; } diff --git a/src/item.h b/src/item.h index 7d2785a6ed39f..bd3b4971b1312 100644 --- a/src/item.h +++ b/src/item.h @@ -2087,7 +2087,7 @@ class item : public visitable /** * Returns name of deceased being if it had any or empty string if not **/ - std::string get_corpse_name(); + std::string get_corpse_name() const; /** * Returns the translated item name for the item with given id. * The name is in the proper plural form as specified by the diff --git a/src/iuse.cpp b/src/iuse.cpp index fa7214cfe609f..ac8d2defd9bc4 100644 --- a/src/iuse.cpp +++ b/src/iuse.cpp @@ -9671,7 +9671,8 @@ cata::optional iuse::craft( player *p, item *it, bool, const tripoint & ) return cata::nullopt; } const recipe &rec = it->get_making(); - if( p->has_recipe( &rec, p->crafting_inventory(), p->get_crafting_helpers() ) == -1 ) { + const inventory &inv = p->crafting_inventory(); + if( p->has_recipe( &rec, inv, p->get_crafting_helpers() ) == -1 ) { p->add_msg_player_or_npc( _( "You don't know the recipe for the %s and can't continue crafting." ), _( " doesn't know the recipe for the %s and can't continue crafting." ), diff --git a/src/mapgendata.cpp b/src/mapgendata.cpp index af83b99ceffb3..461111506954a 100644 --- a/src/mapgendata.cpp +++ b/src/mapgendata.cpp @@ -25,6 +25,7 @@ mapgendata::mapgendata( oter_id north, oter_id east, oter_id south, oter_id west mapgendata::mapgendata( const tripoint_abs_omt &over, map &m, const float density, const time_point &when, ::mission *const miss ) +// NOLINTNEXTLINE( cata-unsequenced-calls ) : mapgendata( overmap_buffer.ter( over + tripoint_north ), overmap_buffer.ter( over + tripoint_east ), overmap_buffer.ter( over + tripoint_south ), diff --git a/src/melee.cpp b/src/melee.cpp index 856aa4f645486..2466c12332a46 100644 --- a/src/melee.cpp +++ b/src/melee.cpp @@ -1698,7 +1698,8 @@ void Character::perform_technique( const ma_technique &technique, Creature &t, d } if( technique.disarms && p != nullptr && p->is_armed() ) { - here.add_item_or_charges( p->pos(), p->remove_weapon() ); + item weap = p->remove_weapon(); + here.add_item_or_charges( p->pos(), weap ); if( p->is_player() ) { add_msg_if_npc( _( " disarms you!" ) ); } else { diff --git a/src/mission.cpp b/src/mission.cpp index b68858bf33cf3..64848fb2f96ed 100644 --- a/src/mission.cpp +++ b/src/mission.cpp @@ -733,7 +733,7 @@ character_id mission::get_assigned_player_id() const return player_id; } -std::string mission::name() +std::string mission::name() const { if( type == nullptr ) { return "NULL"; @@ -741,7 +741,7 @@ std::string mission::name() return type->tname(); } -mission_type_id mission::mission_id() +mission_type_id mission::mission_id() const { if( type == nullptr ) { return mission_type_id( "NULL" ); diff --git a/src/mission.h b/src/mission.h index 0792b5ad2c0f0..0e37a2d3f5917 100644 --- a/src/mission.h +++ b/src/mission.h @@ -352,8 +352,8 @@ class mission character_id player_id; public: - std::string name(); - mission_type_id mission_id(); + std::string name() const; + mission_type_id mission_id() const; void serialize( JsonOut &json ) const; void deserialize( JsonIn &jsin ); diff --git a/src/monster.cpp b/src/monster.cpp index 78a3a7f2c3804..69e3ca2beb55a 100644 --- a/src/monster.cpp +++ b/src/monster.cpp @@ -1096,7 +1096,7 @@ void monster::shift( const point &sm_shift ) } } -tripoint monster::move_target() +tripoint monster::move_target() const { return goal; } @@ -2846,7 +2846,7 @@ void monster::add_msg_debug_player_or_npc( debugmode::debug_filter type, add_msg_debug_if_player_sees( *this, type, replace_with_npc_name( npc_msg ) ); } -units::mass monster::get_carried_weight() +units::mass monster::get_carried_weight() const { units::mass total_weight = 0_gram; if( tack_item ) { @@ -2864,7 +2864,7 @@ units::mass monster::get_carried_weight() return total_weight; } -units::volume monster::get_carried_volume() +units::volume monster::get_carried_volume() const { units::volume total_volume = 0_ml; for( const item &it : inv ) { diff --git a/src/monster.h b/src/monster.h index e3c4bf2d3d484..b509c01df8974 100644 --- a/src/monster.h +++ b/src/monster.h @@ -173,7 +173,7 @@ class monster : public Creature void serialize( JsonOut &json ) const; void deserialize( JsonIn &jsin ); - tripoint move_target(); // Returns point at the end of the monster's current plans + tripoint move_target() const; // Returns point at the end of the monster's current plans Creature *attack_target(); // Returns the creature at the end of plans (if hostile) // Movement @@ -467,8 +467,8 @@ class monster : public Creature cata::value_ptr armor_item; // item of armor the monster may be wearing cata::value_ptr storage_item; // storage item for monster carrying items cata::value_ptr battery_item; // item to power mechs - units::mass get_carried_weight(); - units::volume get_carried_volume(); + units::mass get_carried_weight() const; + units::volume get_carried_volume() const; void move_special_item_to_inv( cata::value_ptr &it ); // DEFINING VALUES diff --git a/src/npctalk_funcs.cpp b/src/npctalk_funcs.cpp index 45f092e1610e9..fe2ab3eb640f4 100644 --- a/src/npctalk_funcs.cpp +++ b/src/npctalk_funcs.cpp @@ -918,7 +918,8 @@ void talk_function::drop_weapon( npc &p ) if( p.is_hallucination() ) { return; } - get_map().add_item_or_charges( p.pos(), p.remove_weapon() ); + item weap = p.remove_weapon(); + get_map().add_item_or_charges( p.pos(), weap ); } void talk_function::player_weapon_away( npc &/*p*/ ) @@ -930,7 +931,8 @@ void talk_function::player_weapon_away( npc &/*p*/ ) void talk_function::player_weapon_drop( npc &/*p*/ ) { Character &player_character = get_player_character(); - get_map().add_item_or_charges( player_character.pos(), player_character.remove_weapon() ); + item weap = player_character.remove_weapon(); + get_map().add_item_or_charges( player_character.pos(), weap ); } void talk_function::lead_to_safety( npc &p ) diff --git a/src/overmap.h b/src/overmap.h index 65261344dc234..e1b64da5cfb50 100644 --- a/src/overmap.h +++ b/src/overmap.h @@ -137,9 +137,15 @@ class overmap_special_batch std::vector::iterator begin() { return placements.begin(); } + std::vector::const_iterator begin() const { + return placements.begin(); + } std::vector::iterator end() { return placements.end(); } + std::vector::const_iterator end() const { + return placements.end(); + } std::vector::iterator erase( std::vector::iterator pos ) { return placements.erase( pos ); diff --git a/src/pathfinding.cpp b/src/pathfinding.cpp index e9a6d0b8f58c7..d02963f7c00a8 100644 --- a/src/pathfinding.cpp +++ b/src/pathfinding.cpp @@ -351,7 +351,7 @@ std::vector map::route( const tripoint &f, const tripoint &t, } else if( part >= 0 && bash > 0 ) { // Car obstacle that isn't a door // TODO: Account for armor - int hp = veh->cpart( part ).hp(); + int hp = veh->part( part ).hp(); if( hp / 20 > bash ) { // Threshold damage thing means we just can't bash this down layer.state[index] = ASL_CLOSED; diff --git a/src/ranged.cpp b/src/ranged.cpp index 65204f8f22ca2..6a738950b32bc 100644 --- a/src/ranged.cpp +++ b/src/ranged.cpp @@ -702,7 +702,8 @@ void npc::pretend_fire( npc *source, int shots, item &gun ) add_msg_if_player_sees( *source, m_info, _( "%s shoots something." ), source->disp_name() ); } while( curshot != shots ) { - if( gun.ammo_consume( gun.ammo_required(), pos() ) != gun.ammo_required() ) { + const int required = gun.ammo_required(); + if( gun.ammo_consume( required, pos() ) != required ) { debugmsg( "Unexpected shortage of ammo whilst firing %s", gun.tname().c_str() ); break; } @@ -808,7 +809,8 @@ int player::fire_gun( const tripoint &target, int shots, item &gun ) } } - if( gun.ammo_consume( gun.ammo_required(), pos() ) != gun.ammo_required() ) { + const int required = gun.ammo_required(); + if( gun.ammo_consume( required, pos() ) != required ) { debugmsg( "Unexpected shortage of ammo whilst firing %s", gun.tname() ); break; } diff --git a/src/vehicle.cpp b/src/vehicle.cpp index bab24e12ea761..39e0ab0c4485c 100644 --- a/src/vehicle.cpp +++ b/src/vehicle.cpp @@ -7212,7 +7212,7 @@ vehicle_part &vehicle::part( int part_num ) return parts[part_num]; } -const vehicle_part &vehicle::cpart( int part_num ) const +const vehicle_part &vehicle::part( int part_num ) const { return const_cast( parts[part_num] ); } diff --git a/src/vehicle.h b/src/vehicle.h index 1232f2233671a..02d0110d553e6 100644 --- a/src/vehicle.h +++ b/src/vehicle.h @@ -1831,8 +1831,7 @@ class vehicle int part_count() const; // Returns the vehicle_part with the given part number vehicle_part &part( int part_num ); - // Same as vehicle::part() except with const binding - const vehicle_part &cpart( int part_num ) const; + const vehicle_part &part( int part_num ) const; // Determines whether the given part_num is valid for this vehicle bool valid_part( int part_num ) const; // Forcibly removes a part from this vehicle. Only exists to support faction_camp.cpp diff --git a/src/vehicle_move.cpp b/src/vehicle_move.cpp index 8ba870aa24d99..23aab0a9eb488 100644 --- a/src/vehicle_move.cpp +++ b/src/vehicle_move.cpp @@ -2020,7 +2020,7 @@ float map::vehicle_wheel_traction( const vehicle &veh, float traction_wheel_area = 0.0f; for( int p : wheel_indices ) { const tripoint &pp = veh.global_part_pos3( p ); - const int wheel_area = veh.cpart( p ).wheel_area(); + const int wheel_area = veh.part( p ).wheel_area(); const auto &tr = ter( pp ).obj(); // Deep water and air diff --git a/src/visitable.cpp b/src/visitable.cpp index 827167c71b5fd..03723a66e92f4 100644 --- a/src/visitable.cpp +++ b/src/visitable.cpp @@ -130,11 +130,11 @@ static int has_quality_from_vpart( const vehicle &veh, int part, const quality_i { int qty = 0; - point pos = veh.cpart( part ).mount; + point pos = veh.part( part ).mount; for( const auto &n : veh.parts_at_relative( pos, true ) ) { // only unbroken parts can provide tool qualities - if( !veh.cpart( n ).is_broken() ) { + if( !veh.part( n ).is_broken() ) { auto tq = veh.part_info( n ).qualities; auto iter = tq.find( qual ); @@ -233,11 +233,11 @@ static int max_quality_from_vpart( const vehicle &veh, int part, const quality_i { int res = INT_MIN; - point pos = veh.cpart( part ).mount; + point pos = veh.part( part ).mount; for( const auto &n : veh.parts_at_relative( pos, true ) ) { // only unbroken parts can provide tool qualities - if( !veh.cpart( n ).is_broken() ) { + if( !veh.part( n ).is_broken() ) { auto tq = veh.part_info( n ).qualities; auto iter = tq.find( qual ); diff --git a/tests/crafting_test.cpp b/tests/crafting_test.cpp index ef07576f1abb2..5f040a7999c1b 100644 --- a/tests/crafting_test.cpp +++ b/tests/crafting_test.cpp @@ -371,7 +371,8 @@ static int actually_test_craft( const recipe_id &rid, int interrupt_after_turns, // This really shouldn't be needed, but for some reason the tests fail for mingw builds without it player_character.learn_recipe( &rec ); - REQUIRE( player_character.has_recipe( &rec, player_character.crafting_inventory(), + const inventory &inv = player_character.crafting_inventory(); + REQUIRE( player_character.has_recipe( &rec, inv, player_character.get_crafting_helpers() ) != -1 ); player_character.remove_weapon(); REQUIRE( !player_character.is_armed() ); From fa311b4a125a1b5ce2e3f52f9de4d1ab4abf570c Mon Sep 17 00:00:00 2001 From: John Bytheway Date: Mon, 5 Apr 2021 13:28:43 -0400 Subject: [PATCH 164/453] Add new try_parse_integer API All the existing ways to parse strings to integers are pretty terrible for one reason or another. They offer poor error handling, are verbose, and/or don't make it obvious whether they are influenced by the current locale. Introduce a new API to attempt to simplify the conversion of strings to ints, using a ret_val for error handling, and with explicit control over locale. Also add unit tests. --- src/try_parse_integer.cpp | 36 ++++++++++ src/try_parse_integer.h | 23 +++++++ tests/test_try_parse_integer.cpp | 109 +++++++++++++++++++++++++++++++ 3 files changed, 168 insertions(+) create mode 100644 src/try_parse_integer.cpp create mode 100644 src/try_parse_integer.h create mode 100644 tests/test_try_parse_integer.cpp diff --git a/src/try_parse_integer.cpp b/src/try_parse_integer.cpp new file mode 100644 index 0000000000000..6a0e74921dca8 --- /dev/null +++ b/src/try_parse_integer.cpp @@ -0,0 +1,36 @@ +#include "try_parse_integer.h" + +#include + +#include "translations.h" + +template +ret_val try_parse_integer( const std::string &s, bool use_locale ) +{ + // Using stringstream-based parsing because that's the only one in the + // standard library for which it's possible to turn off the + // locale-dependency. Once we're using C++17 we could use a combination of + // std::from_chars and std::strto* functions, but this should be fine so + // long as the code is not performance-critical. + std::istringstream buffer( s ); + if( !use_locale ) { + buffer.imbue( std::locale::classic() ); + } + T result; + buffer >> result; + if( !buffer ) { + return ret_val::make_failure( + 0, string_format( _( "Could not convert '%s' to an integer" ), s ) ); + } + char c; + buffer >> c; + if( buffer ) { + return ret_val::make_failure( + 0, string_format( _( "Stray characters after integer in '%s'" ), s ) ); + } + return ret_val::make_success( result ); +} + +template ret_val try_parse_integer( const std::string &, bool use_locale ); +template ret_val try_parse_integer( const std::string &, bool use_locale ); +template ret_val try_parse_integer( const std::string &, bool use_locale ); diff --git a/src/try_parse_integer.h b/src/try_parse_integer.h new file mode 100644 index 0000000000000..64d3bfe516108 --- /dev/null +++ b/src/try_parse_integer.h @@ -0,0 +1,23 @@ +#pragma once +#ifndef CATA_SRC_TRY_PARSE_INTEGER_H +#define CATA_SRC_TRY_PARSE_INTEGER_H + +#include "ret_val.h" + +/** + * Convert a string to an integer or provide an error message indicating what + * went wrong in trying to do so. + * + * @param use_locale Whether to use a number-parsing function that might permit + * formats specific to the user's locale. Generally would be true for + * player-input values, and false for values from e.g. game data files. + */ +template +ret_val try_parse_integer( const std::string &, bool use_locale ); + +extern template ret_val try_parse_integer( const std::string &, bool use_locale ); +extern template ret_val try_parse_integer( const std::string &, bool use_locale ); +extern template ret_val try_parse_integer( + const std::string &, bool use_locale ); + +#endif // CATA_SRC_TRY_PARSE_INTEGER_H diff --git a/tests/test_try_parse_integer.cpp b/tests/test_try_parse_integer.cpp new file mode 100644 index 0000000000000..e8464383cdbae --- /dev/null +++ b/tests/test_try_parse_integer.cpp @@ -0,0 +1,109 @@ +#include "catch/catch.hpp" +#include "try_parse_integer.h" + +TEMPLATE_TEST_CASE( "try_parse_int_simple_parsing", "[try_parse_integer]", int, long, long long ) +{ + try { + std::locale::global( std::locale( "en_US.UTF-8" ) ); + } catch( std::runtime_error & ) { + // On platforms where we can't set the locale, the test should still + // pass + } + CAPTURE( setlocale( LC_ALL, nullptr ) ); + CAPTURE( std::locale().name() ); + + bool use_locale = GENERATE( false, true ); + CAPTURE( use_locale ); + + SECTION( "successes" ) { + { + ret_val result = try_parse_integer( "1234", use_locale ); + CAPTURE( result.str() ); + CHECK( result.success() ); + CHECK( result.value() == 1234 ); + } + { + ret_val result = try_parse_integer( "-1234", use_locale ); + CAPTURE( result.str() ); + CHECK( result.success() ); + CHECK( result.value() == -1234 ); + } + { + ret_val result = try_parse_integer( "+1234", use_locale ); + CAPTURE( result.str() ); + CHECK( result.success() ); + CHECK( result.value() == +1234 ); + } + { + ret_val result = try_parse_integer( " 1234", use_locale ); + CAPTURE( result.str() ); + CHECK( result.success() ); + CHECK( result.value() == 1234 ); + } + } + + SECTION( "errors" ) { + { + ret_val result = try_parse_integer( "", use_locale ); + CHECK( !result.success() ); + CHECK( result.str() == "Could not convert '' to an integer" ); + } + { + ret_val result = try_parse_integer( "a", use_locale ); + CHECK( !result.success() ); + CHECK( result.str() == "Could not convert 'a' to an integer" ); + } + { + // Verify that we detect overflow + ret_val result = + try_parse_integer( "999999999999999999999", use_locale ); + CHECK( !result.success() ); + CHECK( result.str() == "Could not convert '999999999999999999999' to an integer" ); + } + } +} + +TEMPLATE_TEST_CASE( "try_parse_int_locale_parsing", "[try_parse_integer]", int, long, long long ) +{ + SECTION( "de_DE" ) { + try { + std::locale::global( std::locale( "de_DE.UTF-8" ) ); + } catch( std::runtime_error & ) { + // On platforms where we can't set the locale, ignore this test + return; + } + CAPTURE( setlocale( LC_ALL, nullptr ) ); + CAPTURE( std::locale().name() ); + { + ret_val result = try_parse_integer( "1.234", true ); + CHECK( result.success() ); + CHECK( result.value() == 1234 ); + } + { + ret_val result = try_parse_integer( "1.234", false ); + CHECK( !result.success() ); + CHECK( result.str() == "Stray characters after integer in '1.234'" ); + } + } + + SECTION( "en_US" ) { + try { + std::locale::global( std::locale( "en_US.UTF-8" ) ); + } catch( std::runtime_error & ) { + // On platforms where we can't set the locale, ignore this test + return; + } + CAPTURE( setlocale( LC_ALL, nullptr ) ); + CAPTURE( std::locale().name() ); + { + ret_val result = try_parse_integer( "1,234", true ); + CHECK( result.success() ); + CHECK( result.value() == 1234 ); + } + { + ret_val result = try_parse_integer( "1,234", false ); + CHECK( !result.success() ); + CHECK( result.str() == "Stray characters after integer in '1,234'" ); + } + } +} From 4a62fe1ee10d28c934561e3825d2497385782917 Mon Sep 17 00:00:00 2001 From: John Bytheway Date: Mon, 5 Apr 2021 14:13:37 -0400 Subject: [PATCH 165/453] Port string_input_popup to try_parse_integer Stop using atoi in favour of the new API. --- src/string_input_popup.cpp | 56 ++++++++++++++++++++++++++++---------- 1 file changed, 42 insertions(+), 14 deletions(-) diff --git a/src/string_input_popup.cpp b/src/string_input_popup.cpp index 3a1fdc8b7e817..0c034f98c982b 100644 --- a/src/string_input_popup.cpp +++ b/src/string_input_popup.cpp @@ -7,6 +7,7 @@ #include "output.h" #include "point.h" #include "translations.h" +#include "try_parse_integer.h" #include "ui.h" #include "ui_manager.h" #include "uistate.h" @@ -283,14 +284,31 @@ void string_input_popup::query( const bool loop, const bool draw_only ) query_string( loop, draw_only ); } +template +T query_int_impl( string_input_popup &p, const bool loop, const bool draw_only ) +{ + do { + ret_val result = try_parse_integer( p.query_string( loop, draw_only ), true ); + if( p.canceled() ) { + return 0; + } + if( result.success() ) { + return result.value(); + } + popup( result.str() ); + } while( loop ); + + return 0; +} + int string_input_popup::query_int( const bool loop, const bool draw_only ) { - return std::atoi( query_string( loop, draw_only ).c_str() ); + return query_int_impl( *this, loop, draw_only ); } int64_t string_input_popup::query_int64_t( const bool loop, const bool draw_only ) { - return std::atoll( query_string( loop, draw_only ).c_str() ); + return query_int_impl( *this, loop, draw_only ); } const std::string &string_input_popup::query_string( const bool loop, const bool draw_only ) @@ -535,25 +553,35 @@ void string_input_popup::edit( std::string &value ) } } +template +static void edit_integer( string_input_popup &p, T &value ) +{ + p.only_digits( true ); + while( true ) { + p.text( std::to_string( value ) ); + p.query(); + if( p.canceled() ) { + break; + } + ret_val parsed_val = try_parse_integer( p.text(), true ); + if( parsed_val.success() ) { + value = parsed_val.value(); + break; + } else { + popup( parsed_val.str() ); + } + } +} + // NOLINTNEXTLINE(cata-no-long) void string_input_popup::edit( long &value ) { - only_digits( true ); - text( std::to_string( value ) ); - query(); - if( !canceled() ) { - value = std::atol( text().c_str() ); - } + edit_integer( *this, value ); } void string_input_popup::edit( int &value ) { - only_digits( true ); - text( std::to_string( value ) ); - query(); - if( !canceled() ) { - value = std::atoi( text().c_str() ); - } + edit_integer( *this, value ); } string_input_popup &string_input_popup::text( const std::string &value ) From 0e252e05ab631d2457700b923ce3c99fe8171b34 Mon Sep 17 00:00:00 2001 From: John Bytheway Date: Mon, 5 Apr 2021 15:21:21 -0400 Subject: [PATCH 166/453] Improve cata-no-long check We need to suppress warnings nested arbitrarily deep in template specializations; previously we were only suppressing warnings where the immediate context was a template specialization. --- tools/clang-tidy-plugin/NoLongCheck.cpp | 48 +++++++++++++++++------- tools/clang-tidy-plugin/test/no-long.cpp | 17 +++++++++ 2 files changed, 52 insertions(+), 13 deletions(-) diff --git a/tools/clang-tidy-plugin/NoLongCheck.cpp b/tools/clang-tidy-plugin/NoLongCheck.cpp index e9d1282d00401..866a236dc1553 100644 --- a/tools/clang-tidy-plugin/NoLongCheck.cpp +++ b/tools/clang-tidy-plugin/NoLongCheck.cpp @@ -87,6 +87,36 @@ static std::string AlternativesFor( QualType Type ) } } +static bool AnyDeclContextIsSpecialization( const Decl *D ) +{ + Decl::Kind contextKind = D->getDeclContext()->getDeclKind(); + TemplateSpecializationKind tsk = TSK_Undeclared; + const Decl *ContextDecl = nullptr; + if( contextKind == Decl::Function || contextKind == Decl::CXXMethod || + contextKind == Decl::CXXConstructor || contextKind == Decl::CXXConversion || + contextKind == Decl::CXXDestructor || contextKind == Decl::CXXDeductionGuide ) { + const FunctionDecl *C = static_cast( D->getDeclContext() ); + ContextDecl = C; + tsk = C->getTemplateSpecializationKind(); + } + if( contextKind == Decl::CXXRecord || contextKind == Decl::ClassTemplateSpecialization || + contextKind == Decl::ClassTemplatePartialSpecialization ) { + const CXXRecordDecl *C = static_cast( D->getDeclContext() ); + ContextDecl = C; + tsk = C->getTemplateSpecializationKind(); + } + if( !ContextDecl ) { + return false; + } + if( tsk != TSK_Undeclared ) { + // This happens for e.g. a parameter 'T a' to an instantiated + // template function where T is long. We don't want to report such + // cases. + return true; + } + return AnyDeclContextIsSpecialization( ContextDecl ); +} + static void CheckDecl( NoLongCheck &Check, const MatchFinder::MatchResult &Result ) { const ValueDecl *MatchedDecl = Result.Nodes.getNodeAs( "decl" ); @@ -103,19 +133,11 @@ static void CheckDecl( NoLongCheck &Check, const MatchFinder::MatchResult &Resul // generated function return; } - Decl::Kind contextKind = MatchedDecl->getDeclContext()->getDeclKind(); - if( contextKind == Decl::Function || contextKind == Decl::CXXMethod || - contextKind == Decl::CXXConstructor || contextKind == Decl::CXXConversion || - contextKind == Decl::CXXDestructor || contextKind == Decl::CXXDeductionGuide ) { - TemplateSpecializationKind tsk = - static_cast( - MatchedDecl->getDeclContext() )->getTemplateSpecializationKind(); - if( tsk == TSK_ImplicitInstantiation ) { - // This happens for e.g. a parameter 'T a' to an instantiated - // template function where T is long. We don't want to report such - // cases. - return; - } + if( AnyDeclContextIsSpecialization( MatchedDecl ) ) { + // This happens for e.g. a parameter 'T a' to an instantiated + // template function where T is long. We don't want to report such + // cases. + return; } Check.diag( MatchedDecl->getLocation(), "Variable %0 declared as %1. %2." ) << diff --git a/tools/clang-tidy-plugin/test/no-long.cpp b/tools/clang-tidy-plugin/test/no-long.cpp index a0a7f1b8d87e6..4f6672c5785a8 100644 --- a/tools/clang-tidy-plugin/test/no-long.cpp +++ b/tools/clang-tidy-plugin/test/no-long.cpp @@ -105,3 +105,20 @@ void Bf() template long g1( T g1p0 ); // CHECK-MESSAGES: warning: Function 'g1' declared as returning 'long'. Prefer int or int64_t to long. [cata-no-long] + +template +struct A1 { + void f( T a1a ) { + } + T a1b; +}; + +template +A1 f5() +{ + return {}; +} + +// Would be nice to get warnings here but haven't found a way to do so. +extern template A1 f5(); +template A1 f5(); From 718445aaded7a4dbde3dc6233afa9a6cccdb4d64 Mon Sep 17 00:00:00 2001 From: John Bytheway Date: Mon, 5 Apr 2021 19:55:48 -0400 Subject: [PATCH 167/453] Stop using atoi in safemode_ui It was only being used to convert an option value, and that functionality is already built into options. --- src/safemode_ui.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/safemode_ui.cpp b/src/safemode_ui.cpp index 82a19efc45126..24b9b5620b22d 100644 --- a/src/safemode_ui.cpp +++ b/src/safemode_ui.cpp @@ -439,7 +439,7 @@ void safemode::show( const std::string &custom_name_in, bool is_safemode_in ) //Let the options class handle the validity of the new value options_manager::cOpt temp_option = get_options().get_option( "SAFEMODEPROXIMITY" ); temp_option.setValue( text ); - current_tab[line].proximity = atoi( temp_option.getValue().c_str() ); + current_tab[line].proximity = temp_option.value_as(); } } } else if( action == "ENABLE_RULE" && !current_tab.empty() ) { From c53ab48ade4dedb245c646c9227851dba910cc16 Mon Sep 17 00:00:00 2001 From: John Bytheway Date: Mon, 5 Apr 2021 20:31:03 -0400 Subject: [PATCH 168/453] Stop using atoi in output.cpp This was using it to convert the result of a string_input_popup, but that functionality is already built in to that class, so just use it. --- src/output.cpp | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/src/output.cpp b/src/output.cpp index 545cbf00c5e07..e8c22e2f1ee70 100644 --- a/src/output.cpp +++ b/src/output.cpp @@ -719,11 +719,11 @@ bool query_int( int &result, const std::string &text ) string_input_popup popup; popup.title( text ); popup.text( "" ).only_digits( true ); - popup.query(); + int temp = popup.query_int(); if( popup.canceled() ) { return false; } - result = atoi( popup.text().c_str() ); + result = temp; return true; } From acd195563bff349fa451c40a8be35377d3f53769 Mon Sep 17 00:00:00 2001 From: John Bytheway Date: Mon, 5 Apr 2021 20:37:28 -0400 Subject: [PATCH 169/453] Stop using atoi in worldfactory.cpp Switch to new try_parse_integer API. --- src/worldfactory.cpp | 9 ++++++++- 1 file changed, 8 insertions(+), 1 deletion(-) diff --git a/src/worldfactory.cpp b/src/worldfactory.cpp index fd7efe89a955b..f6d927cc06a66 100644 --- a/src/worldfactory.cpp +++ b/src/worldfactory.cpp @@ -31,6 +31,7 @@ #include "string_formatter.h" #include "string_input_popup.h" #include "translations.h" +#include "try_parse_integer.h" #include "ui_manager.h" using namespace std::placeholders; @@ -1549,7 +1550,13 @@ void WORLD::load_options( JsonIn &jsin ) jo.get_string( "value" ) ); if( name == "CORE_VERSION" ) { - version = std::max( std::atoi( value.c_str() ), 0 ); + ret_val value_parsed = try_parse_integer( value, false ); + if( value_parsed.success() ) { + version = std::max( value_parsed.value(), 0 ); + } else { + version = 0; + debugmsg( "Error parsing CORE_VERSION: %s", value_parsed.str() ); + } continue; } From 4b7be2df40c19b07927b715954d2126d6cce1f1e Mon Sep 17 00:00:00 2001 From: John Bytheway Date: Mon, 5 Apr 2021 20:50:35 -0400 Subject: [PATCH 170/453] Stop using atoi in debug_menu.cpp Port one use to string_input_popup::query_int, the others to try_parse_integer. --- src/debug_menu.cpp | 41 +++++++++++++++++++++++++++++------------ 1 file changed, 29 insertions(+), 12 deletions(-) diff --git a/src/debug_menu.cpp b/src/debug_menu.cpp index 8233d04ddc03d..f50b9a6978440 100644 --- a/src/debug_menu.cpp +++ b/src/debug_menu.cpp @@ -95,6 +95,7 @@ #include "string_input_popup.h" #include "trait_group.h" #include "translations.h" +#include "try_parse_integer.h" #include "type_id.h" #include "ui.h" #include "ui_manager.h" @@ -1040,17 +1041,33 @@ void teleport_overmap( bool specific_coordinates ) tripoint_abs_omt where; if( specific_coordinates ) { const std::string text = string_input_popup() - .title( "Teleport where?" ) + .title( _( "Teleport where?" ) ) .width( 20 ) .query_string(); if( text.empty() ) { return; } const std::vector coord_strings = string_split( text, ',' ); + if( coord_strings.size() < 2 || coord_strings.size() > 3 ) { + popup( _( "Error interpreting teleport target: " + "expected two or three comma-separated values; got %zu" ), + coord_strings.size() ); + return; + } + std::vector coord_ints; + for( const std::string &coord_string : coord_strings ) { + ret_val parsed_coord = try_parse_integer( coord_string, true ); + if( !parsed_coord.success() ) { + popup( _( "Error interpreting teleport target: %s" ), parsed_coord.str() ); + return; + } + coord_ints.push_back( parsed_coord.value() ); + } + cata_assert( coord_ints.size() >= 2 ); tripoint coord; - coord.x = !coord_strings.empty() ? std::atoi( coord_strings[0].c_str() ) : 0; - coord.y = coord_strings.size() >= 2 ? std::atoi( coord_strings[1].c_str() ) : 0; - coord.z = coord_strings.size() >= 3 ? std::atoi( coord_strings[2].c_str() ) : 0; + coord.x = coord_ints[0]; + coord.y = coord_ints[1]; + coord.z = coord_ints.size() >= 3 ? coord_ints[2] : 0; where = tripoint_abs_omt( OMAPX * coord.x, OMAPY * coord.y, coord.z ); } else { const cata::optional dir_ = choose_direction( _( "Where is the desired overmap?" ) ); @@ -2088,16 +2105,16 @@ static void debug_menu_spawn_vehicle() static void debug_menu_change_time() { auto set_turn = [&]( const int initial, const time_duration & factor, const char *const msg ) { - const auto text = string_input_popup() - .title( msg ) - .width( 20 ) - .text( std::to_string( initial ) ) - .only_digits( true ) - .query_string(); - if( text.empty() ) { + string_input_popup pop; + const int new_value = pop + .title( msg ) + .width( 20 ) + .text( std::to_string( initial ) ) + .only_digits( true ) + .query_int(); + if( pop.canceled() ) { return; } - const int new_value = std::atoi( text.c_str() ); const time_duration offset = ( new_value - initial ) * factor; // Arbitrary maximal value. const time_point max = calendar::turn_zero + time_duration::from_turns( From f23bdd8a2e3b1f67d0e8c2d3aede6daf9ad07c3c Mon Sep 17 00:00:00 2001 From: John Bytheway Date: Mon, 5 Apr 2021 20:59:43 -0400 Subject: [PATCH 171/453] Stop using sscanf in ranged.cpp Port to new try_parse_integer API. --- src/ranged.cpp | 12 ++++++++++-- 1 file changed, 10 insertions(+), 2 deletions(-) diff --git a/src/ranged.cpp b/src/ranged.cpp index 6a738950b32bc..9ee9d44b09a10 100644 --- a/src/ranged.cpp +++ b/src/ranged.cpp @@ -66,6 +66,7 @@ #include "string_formatter.h" #include "translations.h" #include "trap.h" +#include "try_parse_integer.h" #include "type_id.h" #include "ui.h" #include "ui_manager.h" @@ -1593,8 +1594,15 @@ static projectile make_gun_projectile( const item &gun ) if( gun.ammo_data() ) { // Some projectiles have a chance of being recoverable bool recover = std::any_of( fx.begin(), fx.end(), []( const std::string & e ) { - int n; - return sscanf( e.c_str(), "RECOVER_%i", &n ) == 1 && !one_in( n ); + if( !string_starts_with( e, "RECOVER_" ) ) { + return false; + } + ret_val n = try_parse_integer( e.substr( 8 ), false ); + if( !n.success() ) { + debugmsg( "Error parsing ammo RECOVER_ denominator: %s", n.str() ); + return false; + } + return !one_in( n.value() ); } ); if( recover && !fx.count( "IGNITE" ) && !fx.count( "EXPLOSIVE" ) ) { From 24bce912c7b5d33225965d0aa94e0217b73e3cac Mon Sep 17 00:00:00 2001 From: John Bytheway Date: Mon, 5 Apr 2021 21:15:16 -0400 Subject: [PATCH 172/453] Stop using atoi in options.cpp Port to new try_parse_integer API. --- src/options.cpp | 30 +++++++++++++++++++++++++----- 1 file changed, 25 insertions(+), 5 deletions(-) diff --git a/src/options.cpp b/src/options.cpp index 9eccc576b928d..efa1929e888c0 100644 --- a/src/options.cpp +++ b/src/options.cpp @@ -33,6 +33,7 @@ #include "string_formatter.h" #include "string_input_popup.h" #include "translations.h" +#include "try_parse_integer.h" #include "ui_manager.h" #include "worldfactory.h" @@ -852,17 +853,36 @@ void options_manager::cOpt::setValue( const std::string &sSetIn ) bSet = sSetIn == "True" || sSetIn == "true" || sSetIn == "T" || sSetIn == "t"; } else if( sType == "int" ) { - iSet = atoi( sSetIn.c_str() ); + // Some integer values are stored with a '%', e.g. "100%". + std::string without_percent = sSetIn; + if( string_ends_with( without_percent, "%" ) ) { + without_percent.erase( without_percent.end() - 1 ); + } + ret_val val = try_parse_integer( without_percent, false ); + + if( val.success() ) { + iSet = val.value(); - if( iSet < iMin || iSet > iMax ) { + if( iSet < iMin || iSet > iMax ) { + iSet = iDefault; + } + } else { + debugmsg( "Error parsing option as integer: %s", val.str() ); iSet = iDefault; } } else if( sType == "int_map" ) { - iSet = atoi( sSetIn.c_str() ); + ret_val val = try_parse_integer( sSetIn, false ); - auto item = findInt( iSet ); - if( !item ) { + if( val.success() ) { + iSet = val.value(); + + auto item = findInt( iSet ); + if( !item ) { + iSet = iDefault; + } + } else { + debugmsg( "Error parsing option as integer: %s", val.str() ); iSet = iDefault; } From 4db8e2153c56cc6dadaada4f4babb08a8ff597a0 Mon Sep 17 00:00:00 2001 From: John Bytheway Date: Tue, 6 Apr 2021 06:42:56 -0400 Subject: [PATCH 173/453] Stop using sscanf in iexamine.cpp Port to new try_parse_integer API. --- src/iexamine.cpp | 12 +++++++++--- 1 file changed, 9 insertions(+), 3 deletions(-) diff --git a/src/iexamine.cpp b/src/iexamine.cpp index b5f0cca66b6ea..bb4387ec497d3 100644 --- a/src/iexamine.cpp +++ b/src/iexamine.cpp @@ -90,6 +90,7 @@ #include "timed_event.h" #include "translations.h" #include "trap.h" +#include "try_parse_integer.h" #include "ui.h" #include "ui_manager.h" #include "uistate.h" @@ -4127,9 +4128,14 @@ cata::optional iexamine::getNearFilledGasTank( const tripoint ¢er, static int getGasDiscountCardQuality( const item &it ) { for( const flag_id &tag : it.type->get_flags() ) { - int discount_value; - if( sscanf( tag->id.c_str(), "DISCOUNT_VALUE_%i", &discount_value ) == 1 ) { - return discount_value; + if( string_starts_with( tag->id.str(), "DISCOUNT_VALUE_" ) ) { + ret_val discount_value = + try_parse_integer( tag->id.str().substr( 15 ), false ); + if( discount_value.success() ) { + return discount_value.value(); + } else { + debugmsg( "Error parsing ammo DISCOUNT_VALUE_ suffix: %s", discount_value.str() ); + } } } return 0; From 771838a8cc363922ad34531e2739b2457c7830e8 Mon Sep 17 00:00:00 2001 From: John Bytheway Date: Tue, 6 Apr 2021 07:08:11 -0400 Subject: [PATCH 174/453] Stop using atoi in iuse.cpp Port to new try_parse_integer API, via a new helper function. --- src/iuse.cpp | 41 +++++++++++++++++++++++++++-------------- 1 file changed, 27 insertions(+), 14 deletions(-) diff --git a/src/iuse.cpp b/src/iuse.cpp index ac8d2defd9bc4..5b2c9cc2d8fab 100644 --- a/src/iuse.cpp +++ b/src/iuse.cpp @@ -99,6 +99,7 @@ #include "timed_event.h" #include "translations.h" #include "trap.h" +#include "try_parse_integer.h" #include "type_id.h" #include "ui.h" #include "units.h" @@ -6131,6 +6132,17 @@ static void init_memory_card_with_random_stuff( item &it ) } } +static int get_quality_from_string( const std::string &s ) +{ + const ret_val try_quality = try_parse_integer( s, false ); + if( try_quality.success() ) { + return try_quality.value(); + } else { + debugmsg( "Error parsing photo quality: %s", try_quality.str() ); + return 0; + } +} + static bool einkpc_download_memory_card( player &p, item &eink, item &mc ) { bool something_downloaded = false; @@ -6247,22 +6259,22 @@ static bool einkpc_download_memory_card( player &p, item &eink, item &mc ) const std::string mtype = s; getline( f, s, ',' ); - char *chq = &s[0]; - const int quality = atoi( chq ); + const int quality = get_quality_from_string( s ); const size_t eink_strpos = photos.find( "," + mtype + "," ); if( eink_strpos == std::string::npos ) { photos += mtype + "," + string_format( "%d", quality ) + ","; } else { - const size_t strqpos = eink_strpos + mtype.size() + 2; - char *chq = &photos[strqpos]; - const int old_quality = atoi( chq ); + const size_t next_comma = photos.find( ',', strqpos ); + const int old_quality = + get_quality_from_string( photos.substr( strqpos, next_comma ) ); if( quality > old_quality ) { - chq = &string_format( "%d", quality )[0]; - photos[strqpos] = *chq; + const std::string quality_s = string_format( "%d", quality ); + cata_assert( quality_s.size() == 1 ); + photos[strqpos] = quality_s.front(); } } @@ -6516,8 +6528,7 @@ cata::optional iuse::einktabletpc( player *p, item *it, bool t, const tripo const monster dummy( monster_photos.back() ); menu_str = dummy.name(); getline( f, s, ',' ); - char *chq = &s[0]; - const int quality = atoi( chq ); + const int quality = get_quality_from_string( s ); menu_str += " [" + photo_quality_name( quality ) + "]"; pmenu.addentry( k++, true, -1, menu_str.c_str() ); } @@ -7328,11 +7339,14 @@ static void item_save_monsters( player &p, item &it, const std::vector old_quality ) { - monster_photos[ quality_num_pos ] = string_format( "%d", photo_quality )[ 0 ]; + const std::string quality_s = string_format( "%d", photo_quality ); + cata_assert( quality_s.size() == 1 ); + monster_photos[quality_num_pos] = quality_s.front(); } if( !p.is_blind() ) { if( photo_quality > old_quality ) { @@ -7645,8 +7659,7 @@ cata::optional iuse::camera( player *p, item *it, bool, const tripoint & ) descriptions.push_back( dummy.type->get_description() ); getline( f_mon, s, ',' ); - char *chq = &s[0]; - const int quality = atoi( chq ); + const int quality = get_quality_from_string( s ); menu_str += " [" + photo_quality_name( quality ) + "]"; From b18af78658d97ba6b92a3021c2bd500a5bbd4057 Mon Sep 17 00:00:00 2001 From: John Bytheway Date: Tue, 6 Apr 2021 07:17:56 -0400 Subject: [PATCH 175/453] Stop using sscanf in item_factory.cpp Port to try_parse_integer.cpp --- src/item_factory.cpp | 17 ++++++++++++++--- 1 file changed, 14 insertions(+), 3 deletions(-) diff --git a/src/item_factory.cpp b/src/item_factory.cpp index e974b0e910d99..9b4ce667f0f4b 100644 --- a/src/item_factory.cpp +++ b/src/item_factory.cpp @@ -51,6 +51,7 @@ #include "string_formatter.h" #include "text_snippets.h" #include "translations.h" +#include "try_parse_integer.h" #include "ui.h" #include "units.h" #include "value_ptr.h" @@ -215,9 +216,19 @@ void Item_factory::finalize_pre( itype &obj ) // set light_emission based on LIGHT_[X] flag for( const auto &f : obj.item_tags ) { - int ll; - if( sscanf( f.c_str(), "LIGHT_%i", &ll ) == 1 && ll > 0 ) { - obj.light_emission = ll; + if( string_starts_with( f.str(), "LIGHT_" ) ) { + ret_val ll = try_parse_integer( f.str().substr( 6 ), false ); + if( ll.success() ) { + if( ll.value() > 0 ) { + obj.light_emission = ll.value(); + } else { + debugmsg( "item %s specifies light emission of zero, which is redundant", + obj.id.str() ); + } + } else { + debugmsg( "error parsing integer light emission suffic for item %s: %s", + obj.id.str(), ll.str() ); + } } } // remove LIGHT_[X] flags From dd139c45237c81a23caf2de48a329c08c864b981 Mon Sep 17 00:00:00 2001 From: John Bytheway Date: Tue, 6 Apr 2021 07:48:52 -0400 Subject: [PATCH 176/453] Stop using atoi/atof in item.cpp Port to try_parse_integer and strtod. --- src/item.cpp | 43 ++++++++++++++++++++++++++++++++++++------- tests/item_test.cpp | 11 +++++++++++ 2 files changed, 47 insertions(+), 7 deletions(-) diff --git a/src/item.cpp b/src/item.cpp index 9aad8c3eea291..2a1c85141133e 100644 --- a/src/item.cpp +++ b/src/item.cpp @@ -95,6 +95,7 @@ #include "string_id_utils.h" #include "text_snippets.h" #include "translations.h" +#include "try_parse_integer.h" #include "units.h" #include "units_fwd.h" #include "units_utility.h" @@ -1185,7 +1186,19 @@ double item::get_var( const std::string &name, const double default_value ) cons if( it == item_vars.end() ) { return default_value; } - return atof( it->second.c_str() ); + const std::string &val = it->second; + char *end; + errno = 0; + double result = strtod( &val[0], &end ); + if( errno != 0 ) { + debugmsg( "Error parsing floating point value from %s in item::get_var: %s", + val, strerror( errno ) ); + return default_value; + } + if( end != &val[0] + val.size() ) { + debugmsg( "Stray characters at end of floating point value %s in item::get_var", val ); + } + return result; } void item::set_var( const std::string &name, const tripoint &value ) @@ -1200,9 +1213,19 @@ tripoint item::get_var( const std::string &name, const tripoint &default_value ) return default_value; } std::vector values = string_split( it->second, ',' ); - return tripoint( atoi( values[0].c_str() ), - atoi( values[1].c_str() ), - atoi( values[2].c_str() ) ); + cata_assert( values.size() == 3 ); + auto convert_or_error = []( const std::string & s ) { + ret_val result = try_parse_integer( s, false ); + if( result.success() ) { + return result.value(); + } else { + debugmsg( "Error parsing tripoint coordinate in item::get_var: %s", result.str() ); + return 0; + } + }; + return tripoint( convert_or_error( values[0] ), + convert_or_error( values[1] ), + convert_or_error( values[2] ) ); } void item::set_var( const std::string &name, const std::string &value ) @@ -2148,9 +2171,15 @@ void item::ammo_info( std::vector &info, const iteminfo_query *parts, } if( parts->test( iteminfo_parts::AMMO_FX_RECOVER ) ) { for( const std::string &effect : ammo.ammo_effects ) { - if( effect.compare( 0, 8, "RECOVER_" ) == 0 ) { - int recover_chance; - sscanf( effect.c_str(), "RECOVER_%i", &recover_chance ); + if( string_starts_with( effect, "RECOVER_" ) ) { + ret_val try_recover_chance = + try_parse_integer( effect.substr( 8 ), false ); + if( !try_recover_chance.success() ) { + debugmsg( "Error parsing ammo RECOVER_ denominator: %s", + try_recover_chance.str() ); + break; + } + int recover_chance = try_recover_chance.value(); if( recover_chance <= 5 ) { fx.emplace_back( _( "Stands a very low chance of remaining intact once fired." ) ); } else if( recover_chance <= 10 ) { diff --git a/tests/item_test.cpp b/tests/item_test.cpp index ddf729b01c893..33d820e3fc765 100644 --- a/tests/item_test.cpp +++ b/tests/item_test.cpp @@ -286,3 +286,14 @@ TEST_CASE( "items spawn in their default containers", "[item]" ) check_spawning_in_container( "chem_black_powder" ); check_spawning_in_container( "software_useless" ); } + +TEST_CASE( "item variables round-trip accurately", "[item]" ) +{ + item i( "water" ); + i.set_var( "A", 17 ); + CHECK( i.get_var( "A", 0 ) == 17 ); + i.set_var( "B", 0.125 ); + CHECK( i.get_var( "B", 0.0 ) == 0.125 ); + i.set_var( "C", tripoint( 2, 3, 4 ) ); + CHECK( i.get_var( "C", tripoint() ) == tripoint( 2, 3, 4 ) ); +} From fc6faabefe99a7932a6acc6cae18e6aac3f2b0a0 Mon Sep 17 00:00:00 2001 From: John Bytheway Date: Sat, 10 Apr 2021 13:24:08 -0400 Subject: [PATCH 177/453] Disable some tests on Apple platforms It looks like the Mac OS tests show that it doesn't support localized integer parsing. Just disable those tests there; the feature is not super important. --- ...est_try_parse_integer.cpp => try_parse_integer_test.cpp} | 6 ++++++ 1 file changed, 6 insertions(+) rename tests/{test_try_parse_integer.cpp => try_parse_integer_test.cpp} (96%) diff --git a/tests/test_try_parse_integer.cpp b/tests/try_parse_integer_test.cpp similarity index 96% rename from tests/test_try_parse_integer.cpp rename to tests/try_parse_integer_test.cpp index e8464383cdbae..5136e2541bcd6 100644 --- a/tests/test_try_parse_integer.cpp +++ b/tests/try_parse_integer_test.cpp @@ -74,11 +74,15 @@ TEMPLATE_TEST_CASE( "try_parse_int_locale_parsing", "[try_parse_integer]", int, } CAPTURE( setlocale( LC_ALL, nullptr ) ); CAPTURE( std::locale().name() ); + // Disabling on Apple; seems like their C library doesn't do localized integer + // parsing. +#ifndef __APPLE__ { ret_val result = try_parse_integer( "1.234", true ); CHECK( result.success() ); CHECK( result.value() == 1234 ); } +#endif { ret_val result = try_parse_integer( "1.234", false ); CHECK( !result.success() ); @@ -95,11 +99,13 @@ TEMPLATE_TEST_CASE( "try_parse_int_locale_parsing", "[try_parse_integer]", int, } CAPTURE( setlocale( LC_ALL, nullptr ) ); CAPTURE( std::locale().name() ); +#ifndef __APPLE__ { ret_val result = try_parse_integer( "1,234", true ); CHECK( result.success() ); CHECK( result.value() == 1234 ); } +#endif { ret_val result = try_parse_integer( "1,234", false ); CHECK( !result.success() ); From f498993bf6ab5810b5331ae323c90e6084ded902 Mon Sep 17 00:00:00 2001 From: John Bytheway Date: Sun, 13 Sep 2020 14:51:23 -0400 Subject: [PATCH 178/453] Enable cert-err34-c --- .clang-tidy | 1 - 1 file changed, 1 deletion(-) diff --git a/.clang-tidy b/.clang-tidy index 9b1f40408b7db..c986d1a99bac9 100644 --- a/.clang-tidy +++ b/.clang-tidy @@ -24,7 +24,6 @@ readability-*,\ -bugprone-misplaced-widening-cast,\ -bugprone-narrowing-conversions,\ -bugprone-unused-return-value,\ --cert-err34-c,\ -cert-flp30-c,\ -cert-msc30-c,\ -cert-msc32-c,\ From 993ae80d55a6568099e6ab6e8a2d05d7594b5a6a Mon Sep 17 00:00:00 2001 From: John Bytheway Date: Sat, 10 Apr 2021 21:24:01 -0400 Subject: [PATCH 179/453] Fix parsing of (tri)points These were being parsed by istringstream, without a classic locale, which could lead to incorrect results in some locales. This got picked up in CI as a side-effect of other changes made to the tests in this PR. --- src/point.cpp | 2 ++ 1 file changed, 2 insertions(+) diff --git a/src/point.cpp b/src/point.cpp index 614a4064061d6..a0237ef931612 100644 --- a/src/point.cpp +++ b/src/point.cpp @@ -10,6 +10,7 @@ point point::from_string( const std::string &s ) { std::istringstream is( s ); + is.imbue( std::locale::classic() ); point result; is >> result; if( !is ) { @@ -29,6 +30,7 @@ std::string point::to_string() const tripoint tripoint::from_string( const std::string &s ) { std::istringstream is( s ); + is.imbue( std::locale::classic() ); tripoint result; is >> result; if( !is ) { From 9504108bc6f36d985510a015bf1334c48c8eec28 Mon Sep 17 00:00:00 2001 From: John Bytheway Date: Sat, 10 Apr 2021 22:09:55 -0400 Subject: [PATCH 180/453] Make iteminfo tests more flexible to localization One integer formatted as part of the iteminfo tests can appear in different formats depending on localization. This caused a CI test failure. Allow either format to avoid that failure. --- tests/iteminfo_test.cpp | 19 ++++++++++++++----- 1 file changed, 14 insertions(+), 5 deletions(-) diff --git a/tests/iteminfo_test.cpp b/tests/iteminfo_test.cpp index 184665b7db455..133c2d123dcbb 100644 --- a/tests/iteminfo_test.cpp +++ b/tests/iteminfo_test.cpp @@ -2197,11 +2197,20 @@ TEST_CASE( "bionic info", "[iteminfo][bionic]" ) "* This bionic can produce power from the following fuel:" " Alcohol\n" ); - // NOTE: No trailing newline - CHECK( item_info_str( power, {} ) == - "--\n" - "Power Capacity:" - " 100000000 mJ" ); + std::string power_info = item_info_str( power, {} ); + { + CAPTURE( power_info ); + // NOTE: No trailing newline + // Multiple alternatives due to potential localizations + CHECK( ( power_info == + "--\n" + "Power Capacity:" + " 100000000 mJ" || + power_info == + "--\n" + "Power Capacity:" + " 100,000,000 mJ" ) ); + } // NOTE: Funky trailing space CHECK( item_info_str( nostril, {} ) == From 293501cc53f8b868b2f13ee339af07dcecccbb7e Mon Sep 17 00:00:00 2001 From: John Bytheway Date: Wed, 14 Apr 2021 20:09:19 -0400 Subject: [PATCH 181/453] Work around Mac OS parsing issues Simply always set the classic locale on those platforms. --- src/try_parse_integer.cpp | 9 +++++++++ 1 file changed, 9 insertions(+) diff --git a/src/try_parse_integer.cpp b/src/try_parse_integer.cpp index 6a0e74921dca8..a4187920fa72b 100644 --- a/src/try_parse_integer.cpp +++ b/src/try_parse_integer.cpp @@ -13,9 +13,18 @@ ret_val try_parse_integer( const std::string &s, bool use_locale ) // std::from_chars and std::strto* functions, but this should be fine so // long as the code is not performance-critical. std::istringstream buffer( s ); +#ifdef __APPLE__ + // On Apple platforms we always use the classic locale, because the other + // locales seem to behave strangely. See + // https://github.com/CleverRaven/Cataclysm-DDA/pull/48431 for more + // discussion. + static_cast( use_locale ); + buffer.imbue( std::locale::classic() ); +#else if( !use_locale ) { buffer.imbue( std::locale::classic() ); } +#endif T result; buffer >> result; if( !buffer ) { From 7ebc8fc89932af499e1c37598c084df5210cd017 Mon Sep 17 00:00:00 2001 From: John Bytheway Date: Fri, 16 Apr 2021 08:15:40 -0400 Subject: [PATCH 182/453] Enable clang-tidy cert-msc{30,32,50,51}-cpp These all relate to pseudorandom number generators. --- .clang-tidy | 4 ---- 1 file changed, 4 deletions(-) diff --git a/.clang-tidy b/.clang-tidy index c986d1a99bac9..86d26ffc3eb03 100644 --- a/.clang-tidy +++ b/.clang-tidy @@ -25,10 +25,6 @@ readability-*,\ -bugprone-narrowing-conversions,\ -bugprone-unused-return-value,\ -cert-flp30-c,\ --cert-msc30-c,\ --cert-msc32-c,\ --cert-msc50-cpp,\ --cert-msc51-cpp,\ -misc-non-private-member-variables-in-classes,\ -modernize-avoid-c-arrays,\ -modernize-pass-by-value,\ From 2772c2cf48b1ebc0704109767d304e465245b7bb Mon Sep 17 00:00:00 2001 From: John Bytheway Date: Fri, 16 Apr 2021 10:22:36 -0400 Subject: [PATCH 183/453] Enable performance-implicit-conversion-in-loop --- .clang-tidy | 1 - 1 file changed, 1 deletion(-) diff --git a/.clang-tidy b/.clang-tidy index 86d26ffc3eb03..242dacf57f694 100644 --- a/.clang-tidy +++ b/.clang-tidy @@ -31,7 +31,6 @@ readability-*,\ -modernize-return-braced-init-list,\ -modernize-use-default-member-init,\ -modernize-use-emplace,\ --performance-implicit-conversion-in-loop,\ -performance-inefficient-string-concatenation,\ -performance-type-promotion-in-math-fn,\ -performance-unnecessary-value-param,\ From 80fc3fa0dd9979b48c754448a36fd05e8dc134fd Mon Sep 17 00:00:00 2001 From: John Candlebury Date: Wed, 14 Apr 2021 18:50:17 -0600 Subject: [PATCH 184/453] Add cold resistance gear to escape pod --- data/mods/Aftershock/itemgroups/spaceship_groups.json | 1 + data/mods/Aftershock/items/ethereal.json | 7 ++++--- 2 files changed, 5 insertions(+), 3 deletions(-) diff --git a/data/mods/Aftershock/itemgroups/spaceship_groups.json b/data/mods/Aftershock/itemgroups/spaceship_groups.json index 2e664bacb8d8e..98bd8743490a3 100644 --- a/data/mods/Aftershock/itemgroups/spaceship_groups.json +++ b/data/mods/Aftershock/itemgroups/spaceship_groups.json @@ -12,6 +12,7 @@ { "item": "whistle_multitool" }, { "item": "water_clean", "container-item": "bottle_twoliter", "count": 3 }, { "item": "afs_escapepod_ration", "count": 3 }, + { "item": "cold_res_cream", "count": 3 }, { "item": "light_plus_battery_cell", "charges": 150, "container-item": "flashlight" }, { "item": "light_plus_battery_cell", "charges": 150, "container-item": "water_purifier" }, { "item": "medium_plus_battery_cell", "ammo-item": "battery", "charges": 600, "container-item": "mil_mess_kit" }, diff --git a/data/mods/Aftershock/items/ethereal.json b/data/mods/Aftershock/items/ethereal.json index bdcdd089fdaa1..3ae15d5addf67 100644 --- a/data/mods/Aftershock/items/ethereal.json +++ b/data/mods/Aftershock/items/ethereal.json @@ -8,10 +8,10 @@ "volume": "1ml", "price": 3646, "symbol": "o", + "warmth": 150, "color": "green", "covers": [ "leg_l", "leg_r", "torso", "arm_l", "arm_r", "hand_l", "hand_r", "head", "foot_l", "foot_r", "mouth", "eyes" ], - "flags": [ "AURA", "SEMITANGIBLE", "OVERSIZE", "ONLY_ONE", "TRADER_AVOID", "NO_TAKEOFF", "NONCONDUCTIVE" ], - "relic_data": { "passive_effects": [ { "has": "WORN", "condition": "ALWAYS", "mutations": [ "AFS_CRYOADAPTATION" ] } ] } + "flags": [ "AURA", "SEMITANGIBLE", "OVERSIZE", "ONLY_ONE", "TRADER_AVOID", "NO_TAKEOFF", "CLIMATE_CONTROL", "NONCONDUCTIVE" ] }, { "id": "cold_res_cream_greater", @@ -22,9 +22,10 @@ "volume": "1ml", "price": 3646, "symbol": "o", + "warmth": 150, "color": "green", "covers": [ "leg_l", "leg_r", "torso", "arm_l", "arm_r", "hand_l", "hand_r", "head", "foot_l", "foot_r", "mouth", "eyes" ], - "flags": [ "AURA", "SEMITANGIBLE", "OVERSIZE", "ONLY_ONE", "TRADER_AVOID", "NO_TAKEOFF", "NONCONDUCTIVE" ], + "flags": [ "AURA", "SEMITANGIBLE", "OVERSIZE", "ONLY_ONE", "TRADER_AVOID", "NO_TAKEOFF", "CLIMATE_CONTROL", "NONCONDUCTIVE" ], "relic_data": { "passive_effects": [ { "has": "WORN", "condition": "ALWAYS", "values": [ { "value": "ARMOR_COLD", "multiply": -0.25 } ] } ] } From d279f09b1ef1dedbacb4f25e09587cd6c43b0899 Mon Sep 17 00:00:00 2001 From: John Bytheway Date: Mon, 19 Apr 2021 10:25:06 -0400 Subject: [PATCH 185/453] Move Mingw CI build to GitHub actions (#48572) * Move Mingw CI build to GitHub actions The Mingw cross-compile on Travis has been consistently exceeding the 50 minute time limit for jobs, and causing all PRs to have failed checks. This is not helpful. Try to recreate an equivalent job on GitHub actions in the general build matrix, and disable the Travis version on PRs (leaving it enabled for master). * Fetch key before adding mxe repo * Convey some variables from requirements to build GitHub doesn't retain environment by default between steps. We need to explicitly save the variables we want transferred from requirements.sh to build.sh. * Install wine for Mingw build Looks like wine was installed by default on Travis, but not GitHub, so we explicitly install it in requirements.sh. * Pre-run wine in requirements.sh I think there might be race conditions associated with launching three wine processes simultaneously. Try to avoid that by running one in advance. --- .github/workflows/matrix.yml | 11 ++++++++++ .travis.yml | 3 ++- build-scripts/requirements.sh | 40 +++++++++++++++++++++++++++++++---- 3 files changed, 49 insertions(+), 5 deletions(-) diff --git a/.github/workflows/matrix.yml b/.github/workflows/matrix.yml index 473ec2d77281a..ae83fbee9b178 100644 --- a/.github/workflows/matrix.yml +++ b/.github/workflows/matrix.yml @@ -73,16 +73,27 @@ jobs: tiles: 1 native: osx title: Clang 12, macOS 10.15, Tiles + - compiler: g++ + os: ubuntu-latest + cmake: 0 + tiles: 1 + title: GCC, Ubuntu cross-compile to MinGW-Win64, Tiles + ldflags: -static-libgcc -static-libstdc++ + mxe_target: i686-w64-mingw32.static + wine: wine name: ${{ matrix.title }} runs-on: ${{ matrix.os }} env: CMAKE: ${{ matrix.cmake }} COMPILER: ${{ matrix.compiler }} + MXE_TARGET: ${{ matrix.mxe_target }} + WINE: ${{ matrix.wine }} OS: ${{ matrix.os }} TILES: ${{ matrix.tiles }} SOUND: ${{ matrix.tiles }} SANITIZE: ${{ matrix.sanitize }} TEST_STAGE: ${{ matrix.test-stage }} + LDFLAGS: ${{ matrix.ldflags }} EXTRA_TEST_OPTS: --error-format=github-action NATIVE: ${{ matrix.native }} GOLD: ${{ matrix.gold }} diff --git a/.travis.yml b/.travis.yml index 194cd80956d65..ea18507a555e5 100644 --- a/.travis.yml +++ b/.travis.yml @@ -99,7 +99,8 @@ jobs: - stage: "Platforms and Tidy" # MXE variant using alternate repository http://mirror.mxe.cc/repos/apt env: COMPILER=g++ LDFLAGS="-static-libgcc -static-libstdc++" MXE_TARGET="i686-w64-mingw32.static" WINE="wine" TILES=1 SOUND=1 - name: "Mingw-w64 Make cross-compile to Windows with Tiles and Sound" + name: "MinGW-Win64 Make cross-compile to Windows with Tiles and Sound" + if: type != pull_request compiler: gcc addons: &gcc apt: diff --git a/build-scripts/requirements.sh b/build-scripts/requirements.sh index 78b47ed1287e7..84b98290270ec 100644 --- a/build-scripts/requirements.sh +++ b/build-scripts/requirements.sh @@ -54,8 +54,9 @@ fi # Influenced by https://github.com/zer0main/battleship/blob/master/build/windows/requirements.sh if [ -n "${MXE_TARGET}" ]; then - sudo add-apt-repository 'deb [arch=amd64] https://mirror.mxe.cc/repos/apt xenial main' - $travis_retry sudo apt-key adv --keyserver keyserver.ubuntu.com --recv-keys 84C7C89FC632241A6999ED0A580873F586B72ED9 + $travis_retry sudo apt-key adv --keyserver keyserver.ubuntu.com --recv-keys 84C7C89FC632241A6999ED0A580873F586B72ED9 + sudo add-apt-repository 'deb [arch=amd64] https://mirror.mxe.cc/repos/apt xenial main' + sudo dpkg --add-architecture i386 # We need to treat apt-get update warnings as errors for which the exit code # is not sufficient. The following workaround inspired by # https://unix.stackexchange.com/questions/175146/apt-get-update-exit-status/ @@ -66,9 +67,18 @@ if [ -n "${MXE_TARGET}" ]; then MXE2_TARGET=$(echo "$MXE_TARGET" | sed 's/_/-/g') export MXE_DIR=/usr/lib/mxe/usr/bin - $travis_retry sudo apt-get --yes install mxe-${MXE2_TARGET}-gcc mxe-${MXE2_TARGET}-gettext mxe-${MXE2_TARGET}-glib mxe-${MXE2_TARGET}-sdl2 mxe-${MXE2_TARGET}-sdl2-ttf mxe-${MXE2_TARGET}-sdl2-image mxe-${MXE2_TARGET}-sdl2-mixer + $travis_retry sudo apt-get --yes install \ + mxe-${MXE2_TARGET}-gcc \ + mxe-${MXE2_TARGET}-gettext \ + mxe-${MXE2_TARGET}-glib \ + mxe-${MXE2_TARGET}-sdl2 \ + mxe-${MXE2_TARGET}-sdl2-ttf \ + mxe-${MXE2_TARGET}-sdl2-image \ + mxe-${MXE2_TARGET}-sdl2-mixer \ + wine \ + wine32 export PLATFORM='i686-w64-mingw32.static' - export CROSS_COMPILATION='${MXE_DIR}/${PLATFORM}-' + export CROSS_COMPILATION="${MXE_DIR}/${PLATFORM}-" # Need to overwrite CXX to make the Makefile $CROSS logic work right. export CXX="$COMPILER" export CCACHE=1 @@ -97,4 +107,26 @@ if [[ "$NATIVE" == "android" ]]; then yes | sdkmanager "ndk-bundle" fi +if [ -n "$WINE" ] +then + # The build script will try to run things under wine in parallel, and I + # think there are race conditions that can cause that to break. So, run + # something benign under wine in advance to trigger it to configure all the + # one-time init stuff + wine hostname +fi + +# On GitHub actions environment variables are not saved between steps by +# default, so we need to explicitly save the ones that we care about +if [ -n "$GITHUB_ENV" ] +then + for v in CROSS_COMPILATION CXX + do + if [ -n "${!v}" ] + then + printf "%s='%s'\n" "$v" "${!v}" >> "$GITHUB_ENV" + fi + done +fi + set +x From cd0cb3909765184bf583abbd6780803e405e2eee Mon Sep 17 00:00:00 2001 From: Binrui Dong Date: Tue, 20 Apr 2021 02:34:48 -0400 Subject: [PATCH 186/453] Enable ClangBuildAnalyzer on PRs to 0.F-dev (#48586) --- .github/workflows/CBA.yml | 2 ++ 1 file changed, 2 insertions(+) diff --git a/.github/workflows/CBA.yml b/.github/workflows/CBA.yml index bcb252a8df318..0b37cc7bc912b 100644 --- a/.github/workflows/CBA.yml +++ b/.github/workflows/CBA.yml @@ -4,6 +4,7 @@ on: push: branches: - master + - 0.F-dev paths: - '**.cpp' - '**.h' @@ -15,6 +16,7 @@ on: pull_request: branches: - master + - 0.F-dev paths: - '**.cpp' - '**.h' From c1a42b4347192daa2fb25c9bf15a3bc453255455 Mon Sep 17 00:00:00 2001 From: John Bytheway Date: Tue, 20 Apr 2021 02:36:09 -0400 Subject: [PATCH 187/453] More robust sunburn tests; better burn feedback. (#48527) * Translator notes on sunburn suffer strings These strings were wrong; they had punctuation that they shouldn't have. Remove that punctuation and add translator note to clarify why it shouldn't have been there in the first place. * Remove redundant escapes These '%' should not have been escaped. Un-escape them. * List all burned bodyparts in message Previously only the most exposed bodypart would be listed in the message regarding sunburn / irritation. Instead, list all parts. * Switch sunburn test to IsBinomialObservation This test relied on some arbitrary constants, so it was difficult to know how reasonable failures were. Switch it to a more statistically well-founded approach. * Make IsBinomialObservation more lenient by default This was calibrated to a false positive rate of one in ten thousand. That's too high for the rate at which we run tests. Default to one in one hundred thousand instead. * Improve translatability of sunburn messaging The "%s your %s" string was surely basically impossible to translate. Incorporate the first part into the string to make that easier, and provide the number of bodyparts for languages where that matters. --- src/suffer.cpp | 88 ++++++++++++++++++++++---------------- tests/char_suffer_test.cpp | 18 +++++--- tests/test_statistics.h | 2 +- 3 files changed, 64 insertions(+), 44 deletions(-) diff --git a/src/suffer.cpp b/src/suffer.cpp index e484c08a01984..01e198c3e6971 100644 --- a/src/suffer.cpp +++ b/src/suffer.cpp @@ -43,6 +43,7 @@ #include "npc.h" #include "optional.h" #include "options.h" +#include "output.h" #include "overmapbuffer.h" #include "pimpl.h" #include "player_activity.h" @@ -806,26 +807,23 @@ void Character::suffer_from_sunburn() return; } - std::string sunlight_effect; if( has_trait( trait_ALBINO ) || has_effect( effect_datura ) ) { // Albinism and datura have the same effects, once per minute on average if( !one_turn_in( 1_minutes ) ) { return; } - sunlight_effect = _( "The sunlight is really irritating." ); } else if( has_trait( trait_SUNBURN ) ) { // Sunburn effects occur about 3 times per minute if( !one_turn_in( 20_seconds ) ) { return; } - sunlight_effect = _( "The sunlight burns!" ); } // Sunglasses can keep the sun off the eyes. if( !has_flag( json_flag_GLARE_RESIST ) && !( wearing_something_on( bodypart_id( "eyes" ) ) && ( worn_with_flag( flag_SUN_GLASSES ) || worn_with_flag( flag_BLIND ) ) ) ) { - add_msg_if_player( m_bad, _( "%s your eyes." ), sunlight_effect ); + add_msg_if_player( m_bad, _( "The sunlight is really irritating your eyes." ) ); // Pain (1/60) or loss of focus (59/60) if( one_turn_in( 1_minutes ) ) { mod_pain( 1 ); @@ -842,12 +840,8 @@ void Character::suffer_from_sunburn() // Minimum exposure threshold for pain const float MIN_EXPOSURE = 0.01f; - // Count how many body parts are above the threshold - int count_affected_bp = 0; - // Get the most exposed body part, and how exposed it is. This is to tell the player what body - // part is most irritated by sun, so they know what needs to be covered up better. - bodypart_id most_exposed_bp; - float max_exposure = 0.0f; + // Track body parts above the threshold + std::vector> affected_bodyparts; // Check each bodypart with exposure above the minimum for( const std::pair &bp_exp : bp_exposure ) { const float exposure = bp_exp.second; @@ -855,40 +849,60 @@ void Character::suffer_from_sunburn() if( exposure <= MIN_EXPOSURE || bp_exp.first == bodypart_id( "eyes" ) ) { continue; } - ++count_affected_bp; - if( exposure > max_exposure ) { - max_exposure = exposure; - most_exposed_bp = bp_exp.first; - } + affected_bodyparts.emplace_back( exposure, bp_exp.first ); } // If all body parts are protected, there is no suffering - if( count_affected_bp == 0 || most_exposed_bp == bodypart_str_id::NULL_ID() ) { + if( affected_bodyparts.empty() ) { return; } - // Check if both arms/legs are affected - int count_limbs = 1; - const bodypart_id &other_bp = most_exposed_bp->opposite_part; - const bodypart_id &other_bp_rev = other_bp->opposite_part; - // If these are different, we have a left/right part like a leg or arm. - // If same, it's a central body part with no opposite, like head or torso. - // Only used to generate a simpler message when both arms or both legs are affected. - if( other_bp != other_bp_rev ) { - const auto found = bp_exposure.find( other_bp ); - // Is opposite part exposed? - if( found != bp_exposure.end() && found->second > MIN_EXPOSURE ) { - ++count_limbs; - } - } - // Get singular or plural body part name; append "and other body parts" if appropriate - std::string bp_name = body_part_name( most_exposed_bp, count_limbs ); - if( count_affected_bp == count_limbs ) { - add_msg_if_player( m_bad, _( "%s your %s." ), sunlight_effect, bp_name ); - } else { - add_msg_if_player( m_bad, _( "%s your %s and other body parts." ), sunlight_effect, - bp_name ); + // Sort most affected bodyparts to the front + std::sort( affected_bodyparts.begin(), affected_bodyparts.end(), std::greater<> {} ); + + std::vector affected_part_names; + std::unordered_set excluded_other_parts; + + for( const std::pair &exp_bp : affected_bodyparts ) { + const bodypart_id &bp = exp_bp.second; + if( excluded_other_parts.count( bp ) ) { + continue; + } + const bodypart_id &opposite_bp = bp->opposite_part; + // If these are different, we have a left/right part like a leg or arm. + // If same, it's a central body part with no opposite, like head or torso. + // Used to generate a simpler message when both arms or both legs are affected. + int count_limbs = 1; + if( bp != opposite_bp ) { + const auto found = bp_exposure.find( opposite_bp ); + // Is opposite part exposed? + if( found != bp_exposure.end() && found->second > MIN_EXPOSURE ) { + ++count_limbs; + excluded_other_parts.insert( opposite_bp ); + } + } + // Get singular or plural body part name; append "and other body parts" if appropriate + std::string bp_name = body_part_name( bp, count_limbs ); + affected_part_names.push_back( bp_name ); + } + + std::string all_parts_list = enumerate_as_string( affected_part_names ); + + std::string message; + if( has_trait( trait_ALBINO ) || has_effect( effect_datura ) ) { + //~ %s is a list of body parts. The plurality integer is the total + //~ number of body parts + message = ngettext( "The sunlight is really irritating your %s.", + "The sunlight is really irritating your %s.", + affected_bodyparts.size() ); + } else if( has_trait( trait_SUNBURN ) ) { + //~ %s is a list of body parts. The plurality integer is the total + //~ number of body parts + message = ngettext( "The sunlight burns your %s.", + "The sunlight burns your %s.", + affected_bodyparts.size() ); } + add_msg_if_player( m_bad, message, all_parts_list ); // Wake up from skin irritation/burning if( has_effect( effect_sleep ) ) { diff --git a/tests/char_suffer_test.cpp b/tests/char_suffer_test.cpp index 1261d45fac566..57bdadb2053e3 100644 --- a/tests/char_suffer_test.cpp +++ b/tests/char_suffer_test.cpp @@ -15,6 +15,7 @@ #include "item.h" #include "map_helpers.h" #include "player_helpers.h" +#include "test_statistics.h" #include "type_id.h" // Tests for Character suffering @@ -273,25 +274,30 @@ TEST_CASE( "suffering from sunburn", "[char][suffer][sunburn]" ) } - WHEN( "torso and arms are 90%% covered" ) { + WHEN( "torso and arms are 90% covered" ) { dummy.worn.clear(); dummy.wear_item( longshirt, false ); - THEN( "damage to torso is 90%% less than other parts" ) { - bp_hp_lost = test_suffer_bodypart_hp_lost( dummy, 10_minutes ); + THEN( "damage to torso is 90% less than other parts" ) { + time_duration t = 10_minutes; + int num_turns = t / 1_turns; + + bp_hp_lost = test_suffer_bodypart_hp_lost( dummy, t ); for( const bodypart_id &bp : body_parts_with_hp ) { CAPTURE( bp.id().str() ); if( bp.id().str() == "torso" ) { // Torso has only 10% chance losing 2 HP, 3x per minute - CHECK( bp_hp_lost[bp] == Approx( 6 ).margin( 12 ) ); + CHECK_THAT( bp_hp_lost[bp] / 2, + IsBinomialObservation( num_turns, 1.0 / 200 ) ); } else if( bp.id().str() == "arm_l" || bp.id().str() == "arm_r" ) { // Arms have 10% chance of losing 1 HP, 3x per minute (6 in 10m) // But hands are exposed, and still lose 1 HP, 3x per minute (30 in 10m) - CHECK( bp_hp_lost[bp] == Approx( 36 ).margin( 30 ) ); + CHECK_THAT( bp_hp_lost[bp], + IsBinomialObservation( num_turns, 1.0 / 200 + 1.0 / 20 ) ); } else { // All other parts lose 1 HP, 3x per minute (30 in 10m) // but legs+feet combine, and head+mouth combine (60 in 10m) - CHECK( bp_hp_lost[bp] == Approx( 60 ).margin( 40 ) ); + CHECK_THAT( bp_hp_lost[bp], IsBinomialObservation( num_turns, 2.0 / 20 ) ); } } } diff --git a/tests/test_statistics.h b/tests/test_statistics.h index 3cbb2fe779643..03d59f0224040 100644 --- a/tests/test_statistics.h +++ b/tests/test_statistics.h @@ -223,7 +223,7 @@ class BinomialMatcher : public Catch::MatcherBase // distribution. Uses a normal approximation to the binomial, and permits a // deviation up to max_deviation (measured in standard deviations). inline BinomialMatcher IsBinomialObservation( - const int num_samples, const double p, const double max_deviation = Z99_99 ) + const int num_samples, const double p, const double max_deviation = Z99_999 ) { return BinomialMatcher( num_samples, p, max_deviation ); } From 547c8e6cd68f0eff5dcd78cfdcbb464bde272701 Mon Sep 17 00:00:00 2001 From: John Bytheway Date: Tue, 20 Apr 2021 02:36:36 -0400 Subject: [PATCH 188/453] Enable clang-tidy check bugprone-unused-return-value (#48546) * Fix bugprone-unused-return-value Biggest change here was to mapbuffer, which now stores submaps via unique_ptr rather than raw pointers, simplifying the destructor. Unfortunately, we have to retain the strange pointer-based API for mapbuffer, because the submap ownership logic in map is so convoluted. That can be fixed another day. Also, renamed mapbuffer::reset() to clear(), for consistency. In trait_group, removed a couple of calls to reset() that this warning was highlighting. They didn't do anything anyway. * Enable clang-tidy bugprone-unused-return-value --- .clang-tidy | 1 - src/game.cpp | 8 ++++---- src/main_menu.cpp | 8 ++++---- src/mapbuffer.cpp | 37 ++++++++++++++++--------------------- src/mapbuffer.h | 8 ++++---- src/trait_group.cpp | 2 -- 6 files changed, 28 insertions(+), 36 deletions(-) diff --git a/.clang-tidy b/.clang-tidy index 242dacf57f694..534a499defb7f 100644 --- a/.clang-tidy +++ b/.clang-tidy @@ -23,7 +23,6 @@ performance-*,\ readability-*,\ -bugprone-misplaced-widening-cast,\ -bugprone-narrowing-conversions,\ --bugprone-unused-return-value,\ -cert-flp30-c,\ -misc-non-private-member-variables-in-classes,\ -modernize-avoid-c-arrays,\ diff --git a/src/game.cpp b/src/game.cpp index 6a0fb66477c55..204de8e152ea2 100644 --- a/src/game.cpp +++ b/src/game.cpp @@ -416,7 +416,7 @@ bool game::check_mod_data( const std::vector &opts, loading_ui &ui ) std::string world_name = world_generator->active_world->world_name; world_generator->delete_world( world_name, true ); - MAPBUFFER.reset(); + MAPBUFFER.clear(); overmap_buffer.clear(); } @@ -460,7 +460,7 @@ bool game::check_mod_data( const std::vector &opts, loading_ui &ui ) std::string world_name = world_generator->active_world->world_name; world_generator->delete_world( world_name, true ); - MAPBUFFER.reset(); + MAPBUFFER.clear(); overmap_buffer.clear(); } return true; @@ -1285,7 +1285,7 @@ bool game::cleanup_at_end() sfx::fade_audio_group( sfx::group::context_themes, 300 ); sfx::fade_audio_group( sfx::group::fatigue, 300 ); - MAPBUFFER.reset(); + MAPBUFFER.clear(); overmap_buffer.clear(); #if defined(__ANDROID__) @@ -12254,7 +12254,7 @@ void game::quickload() if( active_world->save_exists( save_t::from_player_name( u.name ) ) ) { if( moves_since_last_save != 0 ) { // See if we need to reload anything - MAPBUFFER.reset(); + MAPBUFFER.clear(); overmap_buffer.clear(); try { setup(); diff --git a/src/main_menu.cpp b/src/main_menu.cpp index 2ec0ff896802f..01e583dad960d 100644 --- a/src/main_menu.cpp +++ b/src/main_menu.cpp @@ -882,7 +882,7 @@ bool main_menu::new_character_tab() } if( !player_character.create( play_type ) ) { load_char_templates(); - MAPBUFFER.reset(); + MAPBUFFER.clear(); overmap_buffer.clear(); continue; } @@ -954,7 +954,7 @@ bool main_menu::new_character_tab() } if( !player_character.create( character_type::TEMPLATE, templates[sel3] ) ) { load_char_templates(); - MAPBUFFER.reset(); + MAPBUFFER.clear(); overmap_buffer.clear(); continue; } @@ -1247,7 +1247,7 @@ void main_menu::world_tab() player_character.save_template( player_character.name, points ); player_character = avatar(); - MAPBUFFER.reset(); + MAPBUFFER.clear(); overmap_buffer.clear(); load_char_templates(); @@ -1323,7 +1323,7 @@ void main_menu::world_tab() world_generator->delete_world( all_worldnames[sel2 - 1], do_delete ); savegames.clear(); - MAPBUFFER.reset(); + MAPBUFFER.clear(); overmap_buffer.clear(); if( do_delete ) { diff --git a/src/mapbuffer.cpp b/src/mapbuffer.cpp index 3b212578c3526..19dc38e18fec5 100644 --- a/src/mapbuffer.cpp +++ b/src/mapbuffer.cpp @@ -43,36 +43,32 @@ static std::string find_dirname( const tripoint &om_addr ) mapbuffer MAPBUFFER; mapbuffer::mapbuffer() = default; +mapbuffer::~mapbuffer() = default; -mapbuffer::~mapbuffer() +void mapbuffer::clear() { - reset(); -} - -void mapbuffer::reset() -{ - for( auto &elem : submaps ) { - delete elem.second; - } submaps.clear(); } -bool mapbuffer::add_submap( const tripoint &p, submap *sm ) +bool mapbuffer::add_submap( const tripoint &p, std::unique_ptr &sm ) { - if( submaps.count( p ) != 0 ) { + if( submaps.count( p ) ) { return false; } - submaps[p] = sm; + submaps[p] = std::move( sm ); return true; } -bool mapbuffer::add_submap( const tripoint &p, std::unique_ptr &sm ) +bool mapbuffer::add_submap( const tripoint &p, submap *sm ) { - const bool result = add_submap( p, sm.get() ); - if( result ) { - sm.release(); + // FIXME: get rid of this overload and make submap ownership semantics sane. + std::unique_ptr temp( sm ); + bool result = add_submap( p, temp ); + if( !result ) { + // NOLINTNEXTLINE( bugprone-unused-return-value ) + temp.release(); } return result; } @@ -84,7 +80,6 @@ void mapbuffer::remove_submap( tripoint addr ) debugmsg( "Tried to remove non-existing submap %d,%d,%d", addr.x, addr.y, addr.z ); return; } - delete m_target->second; submaps.erase( m_target ); } @@ -102,7 +97,7 @@ submap *mapbuffer::lookup_submap( const tripoint &p ) return nullptr; } - return iter->second; + return iter->second.get(); } void mapbuffer::save( bool delete_after_save ) @@ -182,7 +177,7 @@ void mapbuffer::save_quad( const std::string &dirname, const std::string &filena submap_addr.x += offsets_offset.x; submap_addr.y += offsets_offset.y; submap_addrs.push_back( submap_addr ); - submap *sm = submaps[submap_addr]; + submap *sm = submaps[submap_addr].get(); if( sm != nullptr && !sm->is_uniform ) { all_uniform = false; } @@ -211,7 +206,7 @@ void mapbuffer::save_quad( const std::string &dirname, const std::string &filena continue; } - submap *sm = submaps[submap_addr]; + submap *sm = submaps[submap_addr].get(); if( sm == nullptr ) { continue; @@ -272,7 +267,7 @@ submap *mapbuffer::unserialize_submaps( const tripoint &p ) quad_path, p.x, p.y, p.z ); return nullptr; } - return submaps[ p ]; + return submaps[ p ].get(); } void mapbuffer::deserialize( JsonIn &jsin ) diff --git a/src/mapbuffer.h b/src/mapbuffer.h index c90bb587f681e..f2cd10cdbcdbf 100644 --- a/src/mapbuffer.h +++ b/src/mapbuffer.h @@ -28,7 +28,7 @@ class mapbuffer void save( bool delete_after_save = false ); /** Delete all buffered submaps. **/ - void reset(); + void clear(); /** Add a new submap to the buffer. * @@ -38,10 +38,10 @@ class mapbuffer * is released (set to NULL). * @return true if the submap has been stored here. False if there * is already a submap with the specified coordinates. The submap - * is not stored than and the caller must take of the submap object - * on their own (and properly delete it). + * is not stored and the given unique_ptr retains ownsership. */ bool add_submap( const tripoint &p, std::unique_ptr &sm ); + // Old overload that we should stop using, but it's complicated bool add_submap( const tripoint &p, submap *sm ); /** Get a submap stored in this buffer. @@ -55,7 +55,7 @@ class mapbuffer submap *lookup_submap( const tripoint &p ); private: - using submap_map_t = std::map; + using submap_map_t = std::map>; public: inline submap_map_t::iterator begin() { diff --git a/src/trait_group.cpp b/src/trait_group.cpp index 4100a4f21e7f4..386914d0b6616 100644 --- a/src/trait_group.cpp +++ b/src/trait_group.cpp @@ -276,7 +276,6 @@ void Trait_group_collection::add_entry( std::unique_ptr ptr ptr->probability = std::min( 100, ptr->probability ); creators.push_back( std::move( ptr ) ); - ptr.release(); } void Trait_group_distribution::add_entry( std::unique_ptr ptr ) @@ -289,7 +288,6 @@ void Trait_group_distribution::add_entry( std::unique_ptr p sum_prob += ptr->probability; creators.push_back( std::move( ptr ) ); - ptr.release(); } Trait_list Trait_group_distribution::create( RecursionList &rec ) const From e49f8182377b88d24210cf5fe2c4d2ec8c328408 Mon Sep 17 00:00:00 2001 From: LyleSY Date: Tue, 20 Apr 2021 03:06:02 -0400 Subject: [PATCH 189/453] [DinoMod] Dinosaur Jr. bugfix (#48585) --- data/mods/DinoMod/monsters/juvenile.json | 12 ++++++------ 1 file changed, 6 insertions(+), 6 deletions(-) diff --git a/data/mods/DinoMod/monsters/juvenile.json b/data/mods/DinoMod/monsters/juvenile.json index b43e12fd839a1..f4a7aea83346d 100644 --- a/data/mods/DinoMod/monsters/juvenile.json +++ b/data/mods/DinoMod/monsters/juvenile.json @@ -295,7 +295,7 @@ "id": "mon_apatosaurus_juvenile", "type": "MONSTER", "name": "brown and magenta four-legged juvenile", - "description": "A small four-legged plant-eating dinosaur juvenile with huge shiny eyes, it could be from a number of different species.", + "description": "A huge four-legged plant-eating juvenile sauropod with a long neck and tail, it could be from a number of different species.", "copy-from": "mon_gallimimus_juvenile", "color": "brown_magenta", "volume": "1000 L", @@ -322,7 +322,7 @@ "id": "mon_brontosaurus_juvenile", "type": "MONSTER", "name": "brown and magenta four-legged juvenile", - "description": "A small four-legged plant-eating dinosaur juvenile with huge shiny eyes, it could be from a number of different species.", + "description": "A huge four-legged plant-eating juvenile sauropod with a long neck and tail, it could be from a number of different species.", "copy-from": "mon_gallimimus_juvenile", "color": "brown_magenta", "volume": "1000 L", @@ -349,7 +349,7 @@ "id": "mon_diplodocus_juvenile", "type": "MONSTER", "name": "brown and magenta four-legged juvenile", - "description": "A small four-legged plant-eating dinosaur juvenile with huge shiny eyes, it could be from a number of different species.", + "description": "A huge four-legged plant-eating juvenile sauropod with a long neck and tail, it could be from a number of different species.", "copy-from": "mon_gallimimus_juvenile", "color": "brown_magenta", "volume": "1000 L", @@ -376,7 +376,7 @@ "id": "mon_camarasaurus_juvenile", "type": "MONSTER", "name": "brown and magenta four-legged juvenile", - "description": "A small four-legged plant-eating dinosaur juvenile with huge shiny eyes, it could be from a number of different species.", + "description": "A huge four-legged plant-eating juvenile sauropod with a long neck and tail, it could be from a number of different species.", "copy-from": "mon_gallimimus_juvenile", "color": "brown_magenta", "volume": "1000 L", @@ -403,7 +403,7 @@ "id": "mon_brachiosaurus_juvenile", "type": "MONSTER", "name": "brown and magenta four-legged juvenile", - "description": "A small four-legged plant-eating dinosaur juvenile with huge shiny eyes, it could be from a number of different species.", + "description": "A huge four-legged plant-eating juvenile sauropod with a long neck and tail, it could be from a number of different species.", "copy-from": "mon_gallimimus_juvenile", "color": "brown_magenta", "volume": "1000 L", @@ -430,7 +430,7 @@ "id": "mon_alamosaurus_juvenile", "type": "MONSTER", "name": "brown and magenta four-legged juvenile", - "description": "A small four-legged plant-eating dinosaur juvenile with huge shiny eyes, it could be from a number of different species.", + "description": "A huge four-legged plant-eating juvenile sauropod with a long neck and tail, it could be from a number of different species.", "copy-from": "mon_gallimimus_juvenile", "color": "brown_magenta", "volume": "1000 L", From 1c49a26b4ea415cdaabbe64639aac04f1e552f96 Mon Sep 17 00:00:00 2001 From: Maleclypse <54345792+Maleclypse@users.noreply.github.com> Date: Tue, 20 Apr 2021 02:23:32 -0500 Subject: [PATCH 190/453] CRT filenames, fixes and Lore Background (#48506) --- .../advanced_gear.json} | 0 data/mods/CRT_EXPANSION/monsters/crt_monster.json | 14 +++++++------- .../CRT_EXPANSION/monsters/crt_monstergroups.json | 2 +- data/mods/CRT_EXPANSION/readme/README.md | 4 ++-- 4 files changed, 10 insertions(+), 10 deletions(-) rename data/mods/CRT_EXPANSION/{deadspace/deadspaceitems.json => crt_gear/advanced_gear.json} (100%) diff --git a/data/mods/CRT_EXPANSION/deadspace/deadspaceitems.json b/data/mods/CRT_EXPANSION/crt_gear/advanced_gear.json similarity index 100% rename from data/mods/CRT_EXPANSION/deadspace/deadspaceitems.json rename to data/mods/CRT_EXPANSION/crt_gear/advanced_gear.json diff --git a/data/mods/CRT_EXPANSION/monsters/crt_monster.json b/data/mods/CRT_EXPANSION/monsters/crt_monster.json index 0f78397d0cda6..8717d5a9c1754 100644 --- a/data/mods/CRT_EXPANSION/monsters/crt_monster.json +++ b/data/mods/CRT_EXPANSION/monsters/crt_monster.json @@ -2,7 +2,7 @@ { "id": "mon_slasher", "type": "MONSTER", - "name": "Slasher Necromorph", + "name": "Slasher Bio-Recombinant", "description": "A horrifically twisted human body. Two massive, bladed appendages have burst through its shoulders where they are poised above its head as it stalks about with terrifying purpose.", "default_faction": "zombie", "categories": [ "CLASSIC" ], @@ -48,7 +48,7 @@ { "id": "mon_slasher_weak", "type": "MONSTER", - "name": "Weak Slasher Necromorph", + "name": "Weak Slasher Bio-Recombinant", "description": "A horrifically mutilated human body. Two scrawny blades have freshly bursted through its hand to deal with prey and the haunting visage of a jawless maw and a gaping wound in its forehead sends chills down your spine. The awkward steps it takes slows it down greatly.", "default_faction": "zombie", "categories": [ "CLASSIC" ], @@ -94,7 +94,7 @@ { "id": "mon_waster", "type": "MONSTER", - "name": "Waster Necromorph", + "name": "Waster Bio-Recombinant", "description": "Clad in heavy assault gear, an eerie light green glows beneath its helmet from sunken eye sockets and a gaping mouth. Strange blade like points have burst out of it's forearms making it a formidable force to be reckoned with.", "default_faction": "zombie", "species": [ "ZOMBIE", "HUMAN" ], @@ -128,7 +128,7 @@ { "id": "mon_leaper", "type": "MONSTER", - "name": "Leaper Necromorph", + "name": "Leaper Bio-Recombinant", "description": "This once-human body is barely recognizable, scrambling about on its abdomen as it leaps forward with immense arm strength. With elongated fangs that can easily mutilate your flesh, the grotesque face roars incessantly. The lower body has fused together into one giant tail with a barbed spike.", "default_faction": "zombie", "species": [ "ZOMBIE", "HUMAN" ], @@ -169,7 +169,7 @@ { "id": "mon_twitcher", "type": "MONSTER", - "name": "Twitcher Necromorph", + "name": "Twitcher Bio-Recombinant", "description": "With narrow blades coming out of its hands, this corpse spasmically dashes to-and-fro with surprising speed. It carries itself quite steadily when idle, further observation shows that the person before this husk was a C.R.I.T S-I G.E.A.R operator.", "default_faction": "zombie", "species": [ "ZOMBIE", "HUMAN" ], @@ -218,7 +218,7 @@ { "id": "mon_pack", "type": "MONSTER", - "name": "Pack Necromorph", + "name": "Pack Bio-Recombinant", "description": "A shrieking mutated child zombie. The face is is mainly blank with eyes swollen shut and a torn-open mouth with flaps of flesh hanging to the side. A pair of seemingly purposeless appendages sprout from its shoulders before ending in its arms. Its small hands end in sharp claws.", "default_faction": "zombie", "species": [ "ZOMBIE" ], @@ -253,7 +253,7 @@ { "id": "mon_puker", "type": "MONSTER", - "name": "Puker Necromorph", + "name": "Puker Bio-Recombinant", "description": "A rather mutilated corpse covered in gaping sores. Hanging arms with hands that have long corroded away reveal jagged edges that could easily pierce into your flesh. A sticky, frothing yellow sludge flows from its exposed internal organs to its unhinged jaw where it drips, hissing as it eats through material.", "default_faction": "zombie", "species": [ "ZOMBIE", "HUMAN" ], diff --git a/data/mods/CRT_EXPANSION/monsters/crt_monstergroups.json b/data/mods/CRT_EXPANSION/monsters/crt_monstergroups.json index 8686d5986acf5..43b96f6ac0fe5 100644 --- a/data/mods/CRT_EXPANSION/monsters/crt_monstergroups.json +++ b/data/mods/CRT_EXPANSION/monsters/crt_monstergroups.json @@ -1,7 +1,7 @@ [ { "type": "monstergroup", - "name": "GROUP_NECROMORPH", + "name": "GROUP_BIORECOMBINANT", "default": "mon_slasher_weak", "monsters": [ { "monster": "mon_slasher_weak", "freq": 300, "cost_multiplier": 0, "pack_size": [ 2, 4 ] }, diff --git a/data/mods/CRT_EXPANSION/readme/README.md b/data/mods/CRT_EXPANSION/readme/README.md index 16d67176f6697..c21f0c3b2b4f7 100644 --- a/data/mods/CRT_EXPANSION/readme/README.md +++ b/data/mods/CRT_EXPANSION/readme/README.md @@ -24,7 +24,7 @@ More techniques, more play styles. Tries to open up melee and offer more than "d I tried to keep the damage balanced and also added scaling damage and movecosts to make it so certain attacks or weapons carry different risks. -# Dead Space -Yeah, the suit is the R.I.G and many other things come from these games. Awesome series! Some Necromorphs will spawn in labs as well, so beware. +# Lore +The logic behind the C.R.T Expansion is that in this version of the Cataclysm is that there was a much longer build up of the dead rising and random portals appearing before the final Cataclysmic Portal Storm erupted. Governments used this time to create special response forces similar to the Fringe universe. Despite the extra time that the world had to prepare, the Cataclysm still mostly went off as basic DDA. Eventually there will be more special locations showing off some of these preparations and the failures they experienced. Anyways, have fun and report any bugs you find. From 454408503dd5d48aace721ab87d4a4659fd07c8d Mon Sep 17 00:00:00 2001 From: Maleclypse <54345792+Maleclypse@users.noreply.github.com> Date: Tue, 20 Apr 2021 02:36:47 -0500 Subject: [PATCH 191/453] [Aftershock] Greeting Card snippets (#48209) --- .../Aftershock/itemgroups/item_groups.json | 5 +++ data/mods/Aftershock/items/lore_items.json | 17 ++++++++++ .../Aftershock/snippets/personal_cards.json | 32 +++++++++++++++++++ .../Aftershock/{ => snippets}/snippets.json | 0 4 files changed, 54 insertions(+) create mode 100644 data/mods/Aftershock/items/lore_items.json create mode 100644 data/mods/Aftershock/snippets/personal_cards.json rename data/mods/Aftershock/{ => snippets}/snippets.json (100%) diff --git a/data/mods/Aftershock/itemgroups/item_groups.json b/data/mods/Aftershock/itemgroups/item_groups.json index ee3f72098ce77..2fb7809900440 100644 --- a/data/mods/Aftershock/itemgroups/item_groups.json +++ b/data/mods/Aftershock/itemgroups/item_groups.json @@ -77,6 +77,11 @@ "type": "item_group", "items": [ [ "afs_atompot", 3 ] ] }, + { + "id": "newspaper", + "type": "item_group", + "items": [ [ "afs_personal_card", 2 ] ] + }, { "id": "livingroom", "type": "item_group", diff --git a/data/mods/Aftershock/items/lore_items.json b/data/mods/Aftershock/items/lore_items.json new file mode 100644 index 0000000000000..3f7869e9aa7a6 --- /dev/null +++ b/data/mods/Aftershock/items/lore_items.json @@ -0,0 +1,17 @@ +[ + { + "type": "GENERIC", + "id": "afs_personal_card", + "category": "books", + "symbol": ",", + "color": "red", + "name": { "str": "personal message card" }, + "snippet_category": "afs_personal_card", + "description": "A creased card with images and a personal message.", + "price": 0, + "price_postapoc": 0, + "material": [ "paper" ], + "weight": "3 g", + "volume": "5 ml" + } +] diff --git a/data/mods/Aftershock/snippets/personal_cards.json b/data/mods/Aftershock/snippets/personal_cards.json new file mode 100644 index 0000000000000..a3a0b6390a7a3 --- /dev/null +++ b/data/mods/Aftershock/snippets/personal_cards.json @@ -0,0 +1,32 @@ +[ + { + "type": "snippet", + "category": "afs_personal_card", + "text": [ + { + "id": "afs_card_1", + "text": "There is a picture of a shuttle taking off with happy people waving from the viewports. \"Salus is cold.\n\n Our love is true\n\n I hope to see you\n\n On Croatan 2\n\n My dearest, please join me. I don't believe there are many shuttles left before people will be stuck here forever.\"" + }, + { + "id": "afs_card_2", + "text": "A person wrapped up in bandages in a hospital bed is pictured on the front of this card. \"Get well soon!!!\n\n Torrance, I'm sorry you feel ill but many new colonists forget to process any foodstuffs from Salus IV to remove the macronutrient.\"" + }, + { + "id": "afs_card_3", + "text": "A picture of a bloody steak. This card appears particularly old. \"Gauchos Steaks. Deliveries made monthly from Brazil to Salus IV. Sign up today!\"" + }, + { + "id": "afs_card_4", + "text": "A glossy image of flowers and funeral statuary. \"I'm sorry for your loss. Ebby was an excellent grandparent and we hate for you that he was infected with the Moxphoria and wandered into the wastes.\"" + }, + { + "id": "afs_card_5", + "text": "An orbital view of Salus IV. \"Happy Colonization Day!\n\n Leonid,\n\n This place is cold as Hell but we've made a life out here in the last ten years.\"" + }, + { + "id": "afs_card_6", + "text": "An old style movie theater. \"Showing the vintage film Aelita!\n\n Tovarishch,\n\n Come with me to the movies. My grandfather says that this movie is one of the classics.\"" + } + ] + } +] diff --git a/data/mods/Aftershock/snippets.json b/data/mods/Aftershock/snippets/snippets.json similarity index 100% rename from data/mods/Aftershock/snippets.json rename to data/mods/Aftershock/snippets/snippets.json From 54a4e7fdcf98dce72dcfdc23a4365da6ca76e31c Mon Sep 17 00:00:00 2001 From: Eric <52087122+Ramza13@users.noreply.github.com> Date: Tue, 20 Apr 2021 03:39:35 -0400 Subject: [PATCH 192/453] Unhardcode bio recycler, add hunger enchantment (#47637) --- data/json/bionics.json | 12 +++++++++++- doc/MAGIC.md | 1 + src/character.cpp | 10 +--------- src/magic_enchantment.cpp | 1 + src/magic_enchantment.h | 1 + 5 files changed, 15 insertions(+), 10 deletions(-) diff --git a/data/json/bionics.json b/data/json/bionics.json index 4b41eb3ed56a4..88761e77559f5 100644 --- a/data/json/bionics.json +++ b/data/json/bionics.json @@ -1190,7 +1190,17 @@ "name": { "str": "Recycler Unit" }, "description": "Your digestive system has been outfitted with a series of filters and processors, allowing you to reclaim waste liquid and, to a lesser degree, nutrients. The net effect is a greatly reduced need to eat and drink.", "occupied_bodyparts": [ [ "torso", 15 ] ], - "flags": [ "BIONIC_NPC_USABLE" ] + "flags": [ "BIONIC_NPC_USABLE" ], + "enchantments": [ + { + "condition": "ALWAYS", + "values": [ + { "value": "HUNGER", "multiply": -0.5 }, + { "value": "THIRST", "multiply": -0.5 }, + { "value": "METABOLISM", "multiply": -0.5 } + ] + } + ] }, { "id": "bio_remote", diff --git a/doc/MAGIC.md b/doc/MAGIC.md index adb40c129e92e..d444fd769b22a 100644 --- a/doc/MAGIC.md +++ b/doc/MAGIC.md @@ -477,6 +477,7 @@ Effects for the character that has the enchantment: * REGEN_STAMINA * MAX_HP * REGEN_HP +* HUNGER * THIRST * FATIGUE * PAIN diff --git a/src/character.cpp b/src/character.cpp index ba6fd7c15bfe5..15b491daab3d1 100644 --- a/src/character.cpp +++ b/src/character.cpp @@ -284,7 +284,6 @@ static const bionic_id bio_jointservo( "bio_jointservo" ); static const bionic_id bio_leukocyte( "bio_leukocyte" ); static const bionic_id bio_memory( "bio_memory" ); static const bionic_id bio_railgun( "bio_railgun" ); -static const bionic_id bio_recycler( "bio_recycler" ); static const bionic_id bio_shock_absorber( "bio_shock_absorber" ); static const bionic_id bio_tattoo_led( "bio_tattoo_led" ); static const bionic_id bio_ups( "bio_ups" ); @@ -5978,7 +5977,6 @@ void Character::update_needs( int rate_multiplier ) needs_rates Character::calc_needs_rates() const { const effect &sleep = get_effect( effect_sleep ); - const bool has_recycler = has_bionic( bio_recycler ); const bool asleep = !sleep.is_null(); needs_rates rates; @@ -6001,13 +5999,6 @@ needs_rates Character::calc_needs_rates() const static const std::string fatigue_modifier( "fatigue_modifier" ); rates.fatigue *= 1.0f + mutation_value( fatigue_modifier ); - // Note: intentionally not in metabolic rate - if( has_recycler ) { - // Recycler won't help much with mutant metabolism - it is intended for human one - rates.hunger = std::min( rates.hunger, std::max( 0.5f, rates.hunger - 0.5f ) ); - rates.thirst = std::min( rates.thirst, std::max( 0.5f, rates.thirst - 0.5f ) ); - } - if( asleep ) { static const std::string fatigue_regen_modifier( "fatigue_regen_modifier" ); rates.recovery = 1.0f + mutation_value( fatigue_regen_modifier ); @@ -6052,6 +6043,7 @@ needs_rates Character::calc_needs_rates() const rates.thirst *= 0.25f; } + rates.hunger = enchantment_cache->modify_value( enchant_vals::mod::HUNGER, rates.hunger ); rates.fatigue = enchantment_cache->modify_value( enchant_vals::mod::FATIGUE, rates.fatigue ); rates.thirst = enchantment_cache->modify_value( enchant_vals::mod::THIRST, rates.thirst ); diff --git a/src/magic_enchantment.cpp b/src/magic_enchantment.cpp index 390b78594862e..9d03db6ce1472 100644 --- a/src/magic_enchantment.cpp +++ b/src/magic_enchantment.cpp @@ -67,6 +67,7 @@ namespace io case enchant_vals::mod::REGEN_STAMINA: return "REGEN_STAMINA"; case enchant_vals::mod::MAX_HP: return "MAX_HP"; case enchant_vals::mod::REGEN_HP: return "REGEN_HP"; + case enchant_vals::mod::HUNGER: return "HUNGER"; case enchant_vals::mod::THIRST: return "THIRST"; case enchant_vals::mod::FATIGUE: return "FATIGUE"; case enchant_vals::mod::PAIN: return "PAIN"; diff --git a/src/magic_enchantment.h b/src/magic_enchantment.h index de76442562094..8eb15161b5555 100644 --- a/src/magic_enchantment.h +++ b/src/magic_enchantment.h @@ -43,6 +43,7 @@ enum class mod : int { REGEN_STAMINA, MAX_HP, // for all limbs! use with caution REGEN_HP, + HUNGER, // hunger rate THIRST, // thirst rate FATIGUE, // fatigue rate PAIN, // cost or regen over time From f2a3e3d14d440d18aa594b194dabadd360fa5dea Mon Sep 17 00:00:00 2001 From: John Bytheway Date: Sat, 17 Apr 2021 11:55:07 -0400 Subject: [PATCH 193/453] Improve UnsequencedCallsCheck Previously this check triggered false warnings on expressions in different elements of an initializer list expression. Prevent that, and add some test cases. --- tools/clang-tidy-plugin/UnsequencedCallsCheck.cpp | 3 +++ tools/clang-tidy-plugin/test/unsequenced-calls.cpp | 14 ++++++++++++++ 2 files changed, 17 insertions(+) diff --git a/tools/clang-tidy-plugin/UnsequencedCallsCheck.cpp b/tools/clang-tidy-plugin/UnsequencedCallsCheck.cpp index 5c20feb2afe1e..2182b38aa73a8 100644 --- a/tools/clang-tidy-plugin/UnsequencedCallsCheck.cpp +++ b/tools/clang-tidy-plugin/UnsequencedCallsCheck.cpp @@ -47,6 +47,9 @@ static const Expr *GetContainingSequenceStatement( ASTContext *Context, const Ex if( parent.get() ) { return Node; } + if( parent.get() ) { + return Node; + } if( const BinaryOperator *op = parent.get() ) { if( op->isLogicalOp() ) { return Node; diff --git a/tools/clang-tidy-plugin/test/unsequenced-calls.cpp b/tools/clang-tidy-plugin/test/unsequenced-calls.cpp index 4da9839a0b289..58e8f6478bccb 100644 --- a/tools/clang-tidy-plugin/test/unsequenced-calls.cpp +++ b/tools/clang-tidy-plugin/test/unsequenced-calls.cpp @@ -53,3 +53,17 @@ void f1() B b1{ a.nonconst_mf(), a.nonconst_mf() }; B b2 = { a.nonconst_mf(), a.nonconst_mf() }; } + +struct B2 { + int a; + int b; +}; + +void f2() +{ + A a; + // Aggregate initialization is also OK. + B2 b1{ a.nonconst_mf(), a.nonconst_mf() }; + B2 b2 = { a.nonconst_mf(), a.nonconst_mf() }; + B2{ a.nonconst_mf(), a.nonconst_mf() }; +} From 300997876a7ac49fdab11c5bee11b3128925ce3b Mon Sep 17 00:00:00 2001 From: John Bytheway Date: Sun, 18 Apr 2021 07:06:36 -0400 Subject: [PATCH 194/453] Fix inefficient string concatenations Fix all the warnings triggered by the clang-tidy check performance-inefficient-string-concatenation. This highlights two things: concatenation of a bunch of strings using operator+, and appending to a string using 'a = a + b' rather than 'a += b'. In both cases it only highlights the issue in a loop. Some of these cases were pretty benign, some looked more serious. Even the more serious cases were not, as far as I could tell, in performance-critical code, but some were probably changing O(n) loops into O(n^2) loops, so they are good to fix. To help remediate these issues, added two new helped functions: str_cat and str_append, inspired by Abseil's StrCat and StrAppend. --- src/basecamp.cpp | 2 +- src/cata_tiles.cpp | 9 +++-- src/cata_utility.h | 30 ++++++++++++++ src/chkjson/chkjson.cpp | 5 ++- src/debug.cpp | 3 +- src/faction_camp.cpp | 20 +++++----- src/game.cpp | 4 +- src/help.cpp | 10 +++-- src/item.cpp | 6 ++- src/iuse.cpp | 14 ++++--- src/mapgen.cpp | 9 +++-- src/mission_companion.cpp | 42 ++++++++++---------- src/mod_manager.cpp | 3 +- src/newcharacter.cpp | 2 +- src/npctrade.cpp | 2 +- src/options.cpp | 3 +- src/veh_interact.cpp | 10 ++--- src/worldfactory.cpp | 7 ++-- tests/string_test.cpp | 23 +++++++++++ tools/clang-tidy-plugin/HeaderGuardCheck.cpp | 9 +++-- tools/clang-tidy-plugin/Utils.h | 10 +++++ 21 files changed, 152 insertions(+), 71 deletions(-) diff --git a/src/basecamp.cpp b/src/basecamp.cpp index f727c4f0d8a8c..11fe7a3f52e8e 100644 --- a/src/basecamp.cpp +++ b/src/basecamp.cpp @@ -219,7 +219,7 @@ std::string basecamp::om_upgrade_description( const std::string &bldg, bool trun std::string comp; for( auto &elem : component_print_buffer ) { - comp = comp + elem + "\n"; + str_append( comp, elem, "\n" ); } comp = string_format( _( "Notes:\n%s\n\nSkills used: %s\n%s\n" ), making.description, making.required_all_skills_string(), comp ); diff --git a/src/cata_tiles.cpp b/src/cata_tiles.cpp index e276392fe44aa..1355bec28a05d 100644 --- a/src/cata_tiles.cpp +++ b/src/cata_tiles.cpp @@ -926,7 +926,7 @@ void tileset_loader::load_tilejson_from_file( const JsonObject &config ) // fetch additional tiles for( const JsonObject subentry : entry.get_array( "additional_tiles" ) ) { const std::string s_id = subentry.get_string( "id" ); - const std::string m_id = t_id + "_" + s_id; + const std::string m_id = str_cat( t_id, "_", s_id ); tile_type &curr_subtile = load_tile( subentry, m_id ); curr_subtile.offset = sprite_offset; curr_subtile.rotates = true; @@ -1679,12 +1679,15 @@ bool cata_tiles::find_overlay_looks_like( const bool male, const std::string &ov } for( int cnt = 0; cnt < 10 && !looks_like.empty(); cnt++ ) { - draw_id = ( male ? "overlay_male_" : "overlay_female_" ) + over_type + looks_like; + draw_id.clear(); + str_append( draw_id, + ( male ? "overlay_male_" : "overlay_female_" ), over_type, looks_like ); if( tileset_ptr->find_tile_type( draw_id ) ) { exists = true; break; } - draw_id = "overlay_" + over_type + looks_like; + draw_id.clear(); + str_append( draw_id, "overlay_", over_type, looks_like ); if( tileset_ptr->find_tile_type( draw_id ) ) { exists = true; break; diff --git a/src/cata_utility.h b/src/cata_utility.h index 7ca37e414ded5..490967d3f71a6 100644 --- a/src/cata_utility.h +++ b/src/cata_utility.h @@ -442,6 +442,36 @@ bool return_true( const T & ) */ std::string join( const std::vector &strings, const std::string &joiner ); +/** + * Append all arguments after the first to the first. + * + * This provides a way to append several strings to a single root string + * in a single line without an expression like 'a += b + c' which can cause an + * unnecessary allocation in the 'b + c' expression. + */ +template +std::string &str_append( std::string &root, T &&...a ) +{ + // Using initializer list as a poor man's fold expression until C++17. + static_cast( + std::array { { + ( root.append( std::forward( a ) ), false )... + } + } ); + return root; +} + +/** + * Concatenates a bunch of strings with append, to minimze unnecessary + * allocations + */ +template +std::string str_cat( T0 &&a0, T &&...a ) +{ + std::string result( std::forward( a0 ) ); + return str_append( result, std::forward( a )... ); +} + /** * Erases elements from a set that match given predicate function. * Will work on vector, albeit not optimally performance-wise. diff --git a/src/chkjson/chkjson.cpp b/src/chkjson/chkjson.cpp index 07b24e7a5fb3b..278be0c4521f5 100644 --- a/src/chkjson/chkjson.cpp +++ b/src/chkjson/chkjson.cpp @@ -38,6 +38,7 @@ static std::vector get_files_from_path( std::string extension, std: while( !directories.empty() ) { path = directories.top(); + std::string path_with_slash = path + "/"; directories.pop(); DIR *root = opendir( path.c_str() ); @@ -52,7 +53,7 @@ static std::vector get_files_from_path( std::string extension, std: if( stat( root_file->d_name, &_buff ) != 0x4 ) { // ignore '.' and '..' folder names, which are current and parent folder relative paths if( ( strcmp( root_file->d_name, "." ) != 0 ) && ( strcmp( root_file->d_name, ".." ) != 0 ) ) { - std::string subpath = path + "/" + root_file->d_name; + std::string subpath = path_with_slash + root_file->d_name; if( recursive_search ) { subdir = opendir( subpath.c_str() ); @@ -66,7 +67,7 @@ static std::vector get_files_from_path( std::string extension, std: // check to see if it is a file with the appropriate extension std::string tmp = root_file->d_name; if( tmp.find( c_extension, match_extension ? tmp.size() - extsz : 0 ) != std::string::npos ) { - std::string fullpath = path + "/" + tmp; + std::string fullpath = path_with_slash + tmp; files.push_back( fullpath ); } } diff --git a/src/debug.cpp b/src/debug.cpp index 4243f727b281e..8fa5335dd5434 100644 --- a/src/debug.cpp +++ b/src/debug.cpp @@ -684,11 +684,12 @@ static std::string debug_resolve_binary( const std::string &binary, std::ostream return binary; } + std::string suffix = "/" + binary; for( const std::string &path_elem : string_split( path, ':' ) ) { if( path_elem.empty() ) { continue; } - std::string candidate = path_elem + "/" + binary; + std::string candidate = path_elem + suffix; if( 0 == access( candidate.c_str(), X_OK ) ) { return candidate; } diff --git a/src/faction_camp.cpp b/src/faction_camp.cpp index 99f2d76bab7cf..30593e04732d9 100644 --- a/src/faction_camp.cpp +++ b/src/faction_camp.cpp @@ -477,16 +477,16 @@ static bool update_time_left( std::string &entry, const comp_list &npc_list ) Character &player_character = get_player_character(); for( const auto &comp : npc_list ) { if( comp->companion_mission_time_ret < calendar::turn ) { - entry = entry + _( " [DONE]\n" ); + entry += _( " [DONE]\n" ); avail = true; } else { - entry = entry + " [" + - to_string( comp->companion_mission_time_ret - calendar::turn ) + - _( " left]\n" ); + entry += " [" + + to_string( comp->companion_mission_time_ret - calendar::turn ) + + _( " left]\n" ); avail = player_character.has_trait( trait_DEBUG_HS ); } } - entry = entry + _( "\n\nDo you wish to bring your allies back into your party?" ); + entry += _( "\n\nDo you wish to bring your allies back into your party?" ); return avail; } @@ -496,11 +496,11 @@ static bool update_time_fixed( std::string &entry, const comp_list &npc_list, bool avail = false; for( const auto &comp : npc_list ) { time_duration elapsed = calendar::turn - comp->companion_mission_time; - entry = entry + " " + comp->name + " [" + to_string( elapsed ) + "/" + - to_string( duration ) + "]\n"; + entry += " " + comp->name + " [" + to_string( elapsed ) + "/" + + to_string( duration ) + "]\n"; avail |= elapsed >= duration; } - entry = entry + _( "\n\nDo you wish to bring your allies back into your party?" ); + entry += _( "\n\nDo you wish to bring your allies back into your party?" ); return avail; } @@ -3596,7 +3596,7 @@ std::string basecamp::craft_description( const recipe_id &itm ) std::string comp; for( auto &elem : component_print_buffer ) { - comp = comp + elem + "\n"; + str_append( comp, elem, "\n" ); } comp = string_format( _( "Skill used: %s\nDifficulty: %d\n%s\nTime: %s\n" ), making.skill_used.obj().name(), making.difficulty, comp, @@ -3706,7 +3706,7 @@ std::string basecamp::gathering_description( const std::string &bldg ) itemnames2.insert( std::pair( e.second, e.first ) ); } for( const auto &e : itemnames2 ) { - output = output + "> " + e.second + "\n"; + str_append( output, "> ", e.second, "\n" ); } return output; } diff --git a/src/game.cpp b/src/game.cpp index 204de8e152ea2..32e507b953046 100644 --- a/src/game.cpp +++ b/src/game.cpp @@ -3334,8 +3334,8 @@ void game::display_faction_epilogues() }; scrollable_text( new_win, elem.second.name, std::accumulate( epilogue.begin() + 1, epilogue.end(), epilogue.front(), - []( const std::string & lhs, const std::string & rhs ) -> std::string { - return lhs + "\n" + rhs; + []( std::string lhs, const std::string & rhs ) -> std::string { + return std::move( lhs ) + "\n" + rhs; } ) ); } } diff --git a/src/help.cpp b/src/help.cpp index 8cb5986d5ccba..210c2887a9e0b 100644 --- a/src/help.cpp +++ b/src/help.cpp @@ -196,12 +196,14 @@ void help::display_help() const size_t pos2 = line_proc.find( ">", pos, 1 ); std::string action = line_proc.substr( pos + 7, pos2 - pos - 7 ); - auto replace = "" + press_x( look_up_action( action ), "", "" ) + ""; + std::string replace = "" + + press_x( look_up_action( action ), "", "" ) + ""; if( replace.empty() ) { debugmsg( "Help json: Unknown action: %s", action ); } else { - line_proc = string_replace( line_proc, "", replace ); + line_proc = string_replace( + line_proc, "", replace ); } pos = line_proc.find( " &info, int reduce_encum } } } + const std::string when_full_message = space + _( "When full:" ) + space; + const std::string coverage_message = space + _( "Coverage:" ) + space; for( auto &piece : to_display_data ) { if( t->sided ) { const bodypart_str_id &covering_id = piece.first; @@ -2776,12 +2778,12 @@ void item::armor_encumbrance_info( std::vector &info, int reduce_encum piece.second.portion.encumber ) ); if( piece.second.portion.encumber != piece.second.portion.max_encumber ) { - info.push_back( iteminfo( "ARMOR", space + _( "When full:" ) + space, "", + info.push_back( iteminfo( "ARMOR", when_full_message, "", iteminfo::no_newline | iteminfo::lower_is_better, piece.second.portion.max_encumber ) ); } - info.push_back( iteminfo( "ARMOR", space + _( "Coverage:" ) + space, "", + info.push_back( iteminfo( "ARMOR", coverage_message, "", iteminfo::no_flags, piece.second.portion.coverage ) ); } diff --git a/src/iuse.cpp b/src/iuse.cpp index 5b2c9cc2d8fab..70cbebe7f091a 100644 --- a/src/iuse.cpp +++ b/src/iuse.cpp @@ -6952,8 +6952,12 @@ static object_names_collection enumerate_objects_around_point( const tripoint &p const std::string trap_name = colorized_trap_name_at( point_around_figure ); const std::string field_desc = colorized_field_description_at( point_around_figure ); + auto augment_description = [&]( std::string & desc ) { + desc = str_cat( trap_name, desc, field_desc ); + }; + if( !furn_desc.empty() ) { - furn_desc = trap_name + furn_desc + field_desc; + augment_description( furn_desc ); if( point == point_around_figure && create_figure_desc ) { description_furniture_on_figure = furn_desc; } else { @@ -6986,7 +6990,7 @@ static object_names_collection enumerate_objects_around_point( const tripoint &p local_vehicles_recorded.insert( veh_hash ); } else if( !item.is_null() ) { std::string item_name = colorized_item_name( item ); - item_name = trap_name + item_name + field_desc; + augment_description( item_name ); if( point == point_around_figure && create_figure_desc ) { //~ %1$s: terrain description, %2$s: item name description_terrain_on_figure = string_format( pgettext( "terrain and item", "%1$s with a %2$s" ), @@ -6995,21 +6999,21 @@ static object_names_collection enumerate_objects_around_point( const tripoint &p ret_obj.items[ item_name ] ++; } } else if( !unusual_ter_desc.empty() ) { - unusual_ter_desc = trap_name + unusual_ter_desc + field_desc; + augment_description( unusual_ter_desc ); if( point == point_around_figure && create_figure_desc ) { description_furniture_on_figure = unusual_ter_desc; } else { ret_obj.furniture[ unusual_ter_desc ] ++; } } else if( !ter_desc.empty() && ( !field_desc.empty() || !trap_name.empty() ) ) { - ter_desc = trap_name + ter_desc + field_desc; + augment_description( ter_desc ); if( point == point_around_figure && create_figure_desc ) { description_terrain_on_figure = ter_desc; } else { ret_obj.terrain[ ter_desc ] ++; } } else { - ter_desc = trap_name + ter_desc + field_desc; + augment_description( ter_desc ); if( point == point_around_figure && create_figure_desc ) { description_terrain_on_figure = ter_desc; } diff --git a/src/mapgen.cpp b/src/mapgen.cpp index 6e9e446e29654..12bf05145f44e 100644 --- a/src/mapgen.cpp +++ b/src/mapgen.cpp @@ -2197,8 +2197,8 @@ void mapgen_palette::load_place_mapings( const JsonObject &jo, const std::string continue; } auto &vect = format_placings[ key ]; - ::load_place_mapings( sub.get_member( member_name ), vect, - member_name + " in mapping in " + context ); + std::string this_context = string_format( "%s in mapping in %s", member_name, context ); + ::load_place_mapings( sub.get_member( member_name ), vect, this_context ); } } if( !jo.has_object( member_name ) ) { @@ -2207,8 +2207,9 @@ void mapgen_palette::load_place_mapings( const JsonObject &jo, const std::string for( const JsonMember member : jo.get_object( member_name ) ) { const map_key key( member ); auto &vect = format_placings[ key ]; - ::load_place_mapings( - member, vect, member_name + " " + member.name() + " in " + context ); + std::string this_context = + string_format( "%s %s in %s", member_name, member.name(), context ); + ::load_place_mapings( member, vect, this_context ); } } diff --git a/src/mission_companion.cpp b/src/mission_companion.cpp index a74d805de20c2..9b158d9695340 100644 --- a/src/mission_companion.cpp +++ b/src/mission_companion.cpp @@ -154,10 +154,10 @@ void talk_function::scavenger_patrol( mission_data &mission_key, npc &p ) if( !npc_list.empty() ) { entry = _( "Profit: $25-$500\nDanger: Low\nTime: 10 hour missions\n\nPatrol Roster:\n" ); for( auto &elem : npc_list ) { - entry = entry + " " + elem->name + " [" + std::to_string( to_hours( calendar::turn - - elem->companion_mission_time ) ) + _( " hours]\n" ); + entry += " " + elem->name + " [" + std::to_string( to_hours( calendar::turn - + elem->companion_mission_time ) ) + _( " hours]\n" ); } - entry = entry + _( "\n\nDo you wish to bring your allies back into your party?" ); + entry += _( "\n\nDo you wish to bring your allies back into your party?" ); mission_key.add( "Retrieve Scavenging Patrol", _( "Retrieve Scavenging Patrol" ), entry ); } } @@ -176,10 +176,10 @@ void talk_function::scavenger_raid( mission_data &mission_key, npc &p ) entry = _( "Profit: $200-$1000\nDanger: Medium\nTime: 10 hour missions\n\n" "Raid Roster:\n" ); for( auto &elem : npc_list ) { - entry = entry + " " + elem->name + " [" + std::to_string( to_hours( calendar::turn - - elem->companion_mission_time ) ) + _( " hours]\n" ); + entry += " " + elem->name + " [" + std::to_string( to_hours( calendar::turn - + elem->companion_mission_time ) ) + _( " hours]\n" ); } - entry = entry + _( "\n\nDo you wish to bring your allies back into your party?" ); + entry += _( "\n\nDo you wish to bring your allies back into your party?" ); mission_key.add( "Retrieve Scavenging Raid", _( "Retrieve Scavenging Raid" ), entry ); } } @@ -194,10 +194,10 @@ void talk_function::commune_menial( mission_data &mission_key, npc &p ) "them basic skills and build reputation with the outpost. Don't expect " "much of a reward though.\n\nLabor Roster:\n" ); for( auto &elem : npc_list ) { - entry = entry + " " + elem->name + " [" + std::to_string( to_hours( calendar::turn - - elem->companion_mission_time ) ) + _( " hours]\n" ); + entry += " " + elem->name + " [" + std::to_string( to_hours( calendar::turn - + elem->companion_mission_time ) ) + _( " hours]\n" ); } - entry = entry + _( "\n\nDo you wish to bring your allies back into your party?" ); + entry += _( "\n\nDo you wish to bring your allies back into your party?" ); mission_key.add( "Recover Ally from Menial Labor", _( "Recover Ally from Menial Labor" ), entry ); } @@ -214,10 +214,10 @@ void talk_function::commune_carpentry( mission_data &mission_key, npc &p ) if( !npc_list.empty() ) { entry = _( "Profit: $12/hour\nDanger: Minimal\nTime: 1 hour minimum\n\nLabor Roster:\n" ); for( auto &elem : npc_list ) { - entry = entry + " " + elem->name + " [" + std::to_string( to_hours( calendar::turn - - elem->companion_mission_time ) ) + _( " hours]\n" ); + entry += " " + elem->name + " [" + std::to_string( to_hours( calendar::turn - + elem->companion_mission_time ) ) + _( " hours]\n" ); } - entry = entry + _( "\n\nDo you wish to bring your allies back into your party?" ); + entry += _( "\n\nDo you wish to bring your allies back into your party?" ); mission_key.add( "Recover Ally from Carpentry Work", _( "Recover Ally from Carpentry Work" ), entry ); } @@ -306,10 +306,10 @@ void talk_function::commune_forage( mission_data &mission_key, npc &p ) if( !npc_list.empty() ) { entry = _( "Profit: $10/hour\nDanger: Low\nTime: 4 hour minimum\n\nLabor Roster:\n" ); for( auto &elem : npc_list ) { - entry = entry + " " + elem->name + " [" + std::to_string( to_hours( calendar::turn - - elem->companion_mission_time ) ) + _( " hours]\n" ); + entry += " " + elem->name + " [" + std::to_string( to_hours( calendar::turn - + elem->companion_mission_time ) ) + _( " hours]\n" ); } - entry = entry + _( "\n\nDo you wish to bring your allies back into your party?" ); + entry += _( "\n\nDo you wish to bring your allies back into your party?" ); mission_key.add( "Recover Ally from Foraging", _( "Recover Ally from Foraging" ), entry ); } } @@ -333,13 +333,13 @@ void talk_function::commune_refuge_caravan( mission_data &mission_key, npc &p ) "\nRoster:\n" ); for( auto &elem : npc_list ) { if( elem->companion_mission_time == calendar::before_time_starts ) { - entry = entry + " " + elem->name + _( " [READY]\n" ); + entry += " " + elem->name + _( " [READY]\n" ); npc_list_aux.push_back( elem ); } else if( calendar::turn >= elem->companion_mission_time ) { - entry = entry + " " + elem->name + _( " [COMPLETE]\n" ); + entry += " " + elem->name + _( " [COMPLETE]\n" ); } else { - entry = entry + " " + elem->name + " [" + std::to_string( std::abs( to_hours - ( calendar::turn - elem->companion_mission_time ) ) ) + _( " Hours]\n" ); + entry += " " + elem->name + " [" + std::to_string( std::abs( to_hours + ( calendar::turn - elem->companion_mission_time ) ) ) + _( " Hours]\n" ); } } if( !npc_list_aux.empty() ) { @@ -348,7 +348,7 @@ void talk_function::commune_refuge_caravan( mission_data &mission_key, npc &p ) const std::string entry_suffix = _( " [READY]\n" ); for( auto &elem : npc_list_aux ) { if( elem->companion_mission_time == calendar::before_time_starts ) { - entry_aux = entry_aux + " " + elem->name + entry_suffix; + entry_aux += " " + elem->name + entry_suffix; } } entry_aux = entry_aux + _( "\n\n" @@ -357,7 +357,7 @@ void talk_function::commune_refuge_caravan( mission_data &mission_key, npc &p ) mission_key.add( "Begin Commune-Refugee Center Run", _( "Begin Commune-Refugee Center Run" ), entry ); } - entry = entry + _( "\n\nDo you wish to bring your allies back into your party?" ); + entry += _( "\n\nDo you wish to bring your allies back into your party?" ); mission_key.add( "Recover Commune-Refugee Center", _( "Recover Commune-Refugee Center" ), entry ); } diff --git a/src/mod_manager.cpp b/src/mod_manager.cpp index 7e44725965381..0d93784e09066 100644 --- a/src/mod_manager.cpp +++ b/src/mod_manager.cpp @@ -344,8 +344,7 @@ bool mod_manager::copy_mod_contents( const t_mod_list &mods_to_copy, // trim file paths from full length down to just /data forward for( auto &input_file : input_files ) { - std::string output_path = input_file; - output_path = cur_mod_dir + output_path.substr( start_index ); + std::string output_path = cur_mod_dir + input_file.substr( start_index ); copy_file( input_file, output_path ); } } diff --git a/src/newcharacter.cpp b/src/newcharacter.cpp index ce53b30ac77b9..b87e83453c0f2 100644 --- a/src/newcharacter.cpp +++ b/src/newcharacter.cpp @@ -2081,7 +2081,7 @@ tab_direction set_skills( avatar &u, points_left &points ) } ); if( elem.first == currentSkill->name() ) { - rec_disp = "\n\n" + colorize( rec_temp, c_brown ) + rec_disp; + rec_disp = "\n\n" + colorize( rec_temp, c_brown ) + std::move( rec_disp ); } else { rec_disp += "\n\n" + colorize( "[" + elem.first + "]\n" + rec_temp, c_light_gray ); } diff --git a/src/npctrade.cpp b/src/npctrade.cpp index e124282a06056..ee35e356637db 100644 --- a/src/npctrade.cpp +++ b/src/npctrade.cpp @@ -378,7 +378,7 @@ void trading_window::update_win( npc &np, const std::string &deal ) std::string itname = it->display_name(); if( np.will_exchange_items_freely() && ip.loc.where() != item_location::type::character ) { - itname = itname + " (" + ip.loc.describe( &player_character ) + ")"; + itname += " (" + ip.loc.describe( &player_character ) + ")"; color = c_light_blue; } diff --git a/src/options.cpp b/src/options.cpp index efa1929e888c0..fde6714ef6d4e 100644 --- a/src/options.cpp +++ b/src/options.cpp @@ -913,9 +913,10 @@ static std::vector build_resource_list( resource_option.clear(); const auto resource_dirs = get_directories_with( filename, dirname, true ); + const std::string slash_filename = "/" + filename; for( const std::string &resource_dir : resource_dirs ) { - read_from_file( resource_dir + "/" + filename, [&]( std::istream & fin ) { + read_from_file( resource_dir + slash_filename, [&]( std::istream & fin ) { std::string resource_name; std::string view_name; // should only have 2 values inside it, otherwise is going to only load the last 2 values diff --git a/src/veh_interact.cpp b/src/veh_interact.cpp index f15fdfd1beb30..d50e3f589903f 100644 --- a/src/veh_interact.cpp +++ b/src/veh_interact.cpp @@ -1459,7 +1459,7 @@ void veh_interact::calc_overview() int offset = 1; std::string fmtstring = "%s %s %5.1fL"; if( pt.is_leaking() ) { - fmtstring = "%s %s " + leak_marker + "%5.1fL" + leak_marker; + fmtstring = str_cat( "%s %s ", leak_marker, "%5.1fL", leak_marker ); offset = 0; } right_print( w, y, offset, pt_ammo_cur->color, @@ -1467,7 +1467,7 @@ void veh_interact::calc_overview() round_up( units::to_liter( it.volume() ), 1 ) ) ); } else { if( pt.is_leaking() ) { - std::string outputstr = leak_marker + " " + leak_marker; + std::string outputstr = str_cat( leak_marker, " ", leak_marker ); right_print( w, y, 0, c_light_gray, outputstr ); } } @@ -1480,7 +1480,7 @@ void veh_interact::calc_overview() int offset = 1; std::string fmtstring = "%s %5.1fL"; if( pt.is_leaking() ) { - fmtstring = "%s " + leak_marker + "%5.1fL" + leak_marker; + fmtstring = str_cat( "%s ", leak_marker, "%5.1fL", leak_marker ); offset = 0; } right_print( w, y, offset, pt_ammo_cur->color, @@ -1507,7 +1507,7 @@ void veh_interact::calc_overview() int offset = 1; std::string fmtstring = "%i %3i%%"; if( pt.is_leaking() ) { - fmtstring = "%i " + leak_marker + "%3i%%" + leak_marker; + fmtstring = str_cat( "%i ", leak_marker, "%3i%%", leak_marker ); offset = 0; } right_print( w, y, offset, item::find_type( pt.ammo_current() )->color, @@ -1522,7 +1522,7 @@ void veh_interact::calc_overview() int offset = 1; std::string fmtstring = "%s %5i"; if( pt.is_leaking() ) { - fmtstring = "%s " + leak_marker + "%5i" + leak_marker; + fmtstring = str_cat( "%s ", leak_marker, "%5i", leak_marker ); offset = 0; } right_print( w, y, offset, item::find_type( pt.ammo_current() )->color, diff --git a/src/worldfactory.cpp b/src/worldfactory.cpp index f6d927cc06a66..73b7b87f03527 100644 --- a/src/worldfactory.cpp +++ b/src/worldfactory.cpp @@ -742,19 +742,20 @@ void worldfactory::draw_mod_list( const catacurses::window &w, int &start, size_ } const mod_id &mod_entry_id = *iter; - std::string mod_entry_name = string_format( _( " [%s]" ), mod_entry_id.str() ); + std::string mod_entry_name; nc_color mod_entry_color = c_white; if( mod_entry_id.is_valid() ) { const MOD_INFORMATION &mod = *mod_entry_id; - mod_entry_name = mod.name() + mod_entry_name; + mod_entry_name = mod.name(); if( mod.obsolete ) { mod_entry_color = c_dark_gray; } } else { mod_entry_color = c_light_red; - mod_entry_name = _( "N/A" ) + mod_entry_name; + mod_entry_name = _( "N/A" ); } + mod_entry_name += string_format( _( " [%s]" ), mod_entry_id.str() ); trim_and_print( w, point( 4, iNum - start ), wwidth, mod_entry_color, mod_entry_name ); if( w_shift ) { diff --git a/tests/string_test.cpp b/tests/string_test.cpp index 4293374abc27e..b998ada26c14c 100644 --- a/tests/string_test.cpp +++ b/tests/string_test.cpp @@ -38,3 +38,26 @@ TEST_CASE( "trim_by_length" ) CHECK( trim_by_length( "MRE 主菜(鸡肉意大利香蒜沙司通心粉)(新鲜)", 36 ) == "MRE 主菜(鸡肉意大利香蒜沙司通心粉…" ); } + +TEST_CASE( "str_cat" ) +{ + CHECK( str_cat( " " ) == " " ); + CHECK( str_cat( "a", "b", "c" ) == "abc" ); + CHECK( str_cat( "a", std::string( "b" ), "c" ) == "abc" ); + std::string a( "a" ); + std::string b( "b" ); + std::string result = str_cat( a, std::move( b ), a ); + CHECK( result == "aba" ); +} + +TEST_CASE( "str_append" ) +{ + std::string root( "a" ); + CHECK( str_append( root, " " ) == "a " ); + CHECK( str_append( root, "b", "c" ) == "a bc" ); + CHECK( str_append( root, std::string( "b" ), "c" ) == "a bcbc" ); + std::string a( "a" ); + std::string b( "b" ); + str_append( root, a, std::move( b ), a ); + CHECK( root == "a bcbcaba" ); +} diff --git a/tools/clang-tidy-plugin/HeaderGuardCheck.cpp b/tools/clang-tidy-plugin/HeaderGuardCheck.cpp index e51841b191fbe..16894eaddd4fd 100644 --- a/tools/clang-tidy-plugin/HeaderGuardCheck.cpp +++ b/tools/clang-tidy-plugin/HeaderGuardCheck.cpp @@ -9,6 +9,8 @@ #include #endif +#include "Utils.h" + namespace clang { namespace tidy @@ -360,12 +362,13 @@ class HeaderGuardPPCallbacks : public PPCallbacks Newlines = "\n"; } + std::string ToInsertHeader = StrCat( + "#ifndef ", CPPVar, "\n#define ", CPPVar, Newlines ); Check->diag( InsertLoc, "Header is missing header guard." ) - << FixItHint::CreateInsertion( - InsertLoc, "#ifndef " + CPPVar + "\n#define " + CPPVar + Newlines ) + << FixItHint::CreateInsertion( InsertLoc, ToInsertHeader ) << FixItHint::CreateInsertion( SM.getLocForEndOfFile( FID ), - "\n#" + formatEndIf( CPPVar ) + "\n" ); + StrCat( "\n#", formatEndIf( CPPVar ), "\n" ) ); } } private: diff --git a/tools/clang-tidy-plugin/Utils.h b/tools/clang-tidy-plugin/Utils.h index df7a355ca45c1..c84f1c0ddb9d4 100644 --- a/tools/clang-tidy-plugin/Utils.h +++ b/tools/clang-tidy-plugin/Utils.h @@ -217,6 +217,16 @@ inline size_t HashCombine( const T &t, const U &u ) return result; } +template +std::string StrCat( T0 &&a0, T &&...a ) +{ + std::string result( std::forward( a0 ) ); + // Using initializer list as a poor man's fold expression until C++17. + static_cast( + std::array { ( result.append( std::forward( a ) ), false )... } ); + return result; +} + } // namespace cata } // namespace tidy } // namespace clang From de0604d55aba3f68a0ba9ed91c623dc65512ed34 Mon Sep 17 00:00:00 2001 From: John Bytheway Date: Fri, 16 Apr 2021 15:22:05 -0400 Subject: [PATCH 195/453] Enable performance-inefficient-string-concatenation --- .clang-tidy | 1 - 1 file changed, 1 deletion(-) diff --git a/.clang-tidy b/.clang-tidy index 534a499defb7f..6b5239d0b8b2f 100644 --- a/.clang-tidy +++ b/.clang-tidy @@ -30,7 +30,6 @@ readability-*,\ -modernize-return-braced-init-list,\ -modernize-use-default-member-init,\ -modernize-use-emplace,\ --performance-inefficient-string-concatenation,\ -performance-type-promotion-in-math-fn,\ -performance-unnecessary-value-param,\ -readability-braces-around-statements,\ From fa7d8654829c29bbc519541963164922ce5adbbb Mon Sep 17 00:00:00 2001 From: John Bytheway Date: Tue, 20 Apr 2021 13:23:47 -0400 Subject: [PATCH 196/453] Enable clang-tidy check cert-flp30-c This is just an alias for clang-analyzer-security.FloatLoopCounter which we're already running, so it just required suppressions in the same places. --- .clang-tidy | 1 - tests/rng_test.cpp | 4 ++-- 2 files changed, 2 insertions(+), 3 deletions(-) diff --git a/.clang-tidy b/.clang-tidy index 534a499defb7f..fb40f83698acb 100644 --- a/.clang-tidy +++ b/.clang-tidy @@ -23,7 +23,6 @@ performance-*,\ readability-*,\ -bugprone-misplaced-widening-cast,\ -bugprone-narrowing-conversions,\ --cert-flp30-c,\ -misc-non-private-member-variables-in-classes,\ -modernize-avoid-c-arrays,\ -modernize-pass-by-value,\ diff --git a/tests/rng_test.cpp b/tests/rng_test.cpp index d1ba612048fd9..ff2fcafc7a734 100644 --- a/tests/rng_test.cpp +++ b/tests/rng_test.cpp @@ -54,11 +54,11 @@ static void check_x_in_y( double x, double y ) TEST_CASE( "x_in_y_distribution" ) { float y_increment = 0.01f; - // NOLINTNEXTLINE(clang-analyzer-security.FloatLoopCounter) + // NOLINTNEXTLINE(clang-analyzer-security.FloatLoopCounter,cert-flp30-c) for( float y = 0.1f; y < 500.0f; y += y_increment ) { y_increment *= 1.1f; float x_increment = 0.1f; - // NOLINTNEXTLINE(clang-analyzer-security.FloatLoopCounter) + // NOLINTNEXTLINE(clang-analyzer-security.FloatLoopCounter,cert-flp30-c) for( float x = 0.1f; x < y; x += x_increment ) { check_x_in_y( x, y ); x_increment *= 1.1f; From efc87c8b17b4272af44c578695c15f98528f3ab3 Mon Sep 17 00:00:00 2001 From: John Bytheway Date: Tue, 20 Apr 2021 21:34:09 -0400 Subject: [PATCH 197/453] Improve messages for some JSON errors Several of the top-level save files were not providing filenames with their JSON error messages, because the filename was never passed to the JsonIn constructor. Arrange for it to be so passed, to improve those errors and assist with debugging. --- src/game.cpp | 13 ++++++++----- src/game.h | 4 ++-- src/memorial_logger.cpp | 4 ++-- src/memorial_logger.h | 2 +- src/savegame.cpp | 8 ++++---- tests/memorial_test.cpp | 6 +++--- 6 files changed, 20 insertions(+), 17 deletions(-) diff --git a/src/game.cpp b/src/game.cpp index 204de8e152ea2..08195d444d082 100644 --- a/src/game.cpp +++ b/src/game.cpp @@ -2932,7 +2932,8 @@ bool game::load( const save_t &name ) u.name = name.player_name(); // This should be initialized more globally (in player/Character constructor) u.weapon = item(); - if( !read_from_file( playerpath + SAVE_EXTENSION, std::bind( &game::unserialize, this, _1 ) ) ) { + const std::string save_filename = playerpath + SAVE_EXTENSION; + if( !read_from_file( save_filename, std::bind( &game::unserialize, this, _1, save_filename ) ) ) { return false; } @@ -2940,12 +2941,14 @@ bool game::load( const save_t &name ) u.deserialize_map_memory( jsin ); } ); - read_from_file_optional( worldpath + name.base_path() + SAVE_EXTENSION_LOG, - std::bind( &memorial_logger::load, &memorial(), _1 ) ); + const std::string log_filename = worldpath + name.base_path() + SAVE_EXTENSION_LOG; + read_from_file_optional( log_filename, + std::bind( &memorial_logger::load, &memorial(), _1, log_filename ) ); #if defined(__ANDROID__) - read_from_file_optional( worldpath + name.base_path() + SAVE_EXTENSION_SHORTCUTS, - std::bind( &game::load_shortcuts, this, _1 ) ); + const std::string shortcuts_filename = worldpath + name.base_path() + SAVE_EXTENSION_SHORTCUTS; + read_from_file_optional( shortcuts_filename, + std::bind( &game::load_shortcuts, this, _1, shortcuts_filename ) ); #endif // Now that the player's worn items are updated, their sight limits need to be diff --git a/src/game.h b/src/game.h index 513cd6c2bed24..727b456dbf845 100644 --- a/src/game.h +++ b/src/game.h @@ -210,7 +210,7 @@ class game void setup(); /** Saving and loading functions. */ void serialize( std::ostream &fout ); // for save - void unserialize( std::istream &fin ); // for load + void unserialize( std::istream &fin, const std::string &path ); // for load void unserialize_master( std::istream &fin ); // for load /** write statistics to stdout and @return true if successful */ @@ -752,7 +752,7 @@ class game bool load( const save_t &name ); // Load a player-specific save file void load_master(); // Load the master data file, with factions &c #if defined(__ANDROID__) - void load_shortcuts( std::istream &fin ); + void load_shortcuts( std::istream &fin, const std::string &path ); #endif bool start_game(); // Starts a new game in the active world diff --git a/src/memorial_logger.cpp b/src/memorial_logger.cpp index 9de81018cf371..c5982bb223d8f 100644 --- a/src/memorial_logger.cpp +++ b/src/memorial_logger.cpp @@ -140,7 +140,7 @@ void memorial_logger::add( const std::string &male_msg, * In new format the entries are stored as json. * @param fin The stream to read the memorial entries from. */ -void memorial_logger::load( std::istream &fin ) +void memorial_logger::load( std::istream &fin, const std::string &path ) { log.clear(); if( fin.peek() == '|' ) { @@ -155,7 +155,7 @@ void memorial_logger::load( std::istream &fin ) log.emplace_back( entry ); } } else { - JsonIn jsin( fin ); + JsonIn jsin( fin, path ); if( !jsin.read( log ) ) { debugmsg( "Error reading JSON memorial log" ); } diff --git a/src/memorial_logger.h b/src/memorial_logger.h index c4f426f32d4b4..250ec0a8a7d4f 100644 --- a/src/memorial_logger.h +++ b/src/memorial_logger.h @@ -63,7 +63,7 @@ class memorial_logger : public event_subscriber } // Loads the memorial log from a file - void load( std::istream & ); + void load( std::istream &, const std::string &path ); void save( std::ostream & ) const; // Dumps all memorial events into a single newline-delimited string // (this is the content of the temporary file used to preserve the log diff --git a/src/savegame.cpp b/src/savegame.cpp index ce41928e5472c..86d99ff82e023 100644 --- a/src/savegame.cpp +++ b/src/savegame.cpp @@ -175,7 +175,7 @@ static void chkversion( std::istream &fin ) /* * Parse an open .sav file. */ -void game::unserialize( std::istream &fin ) +void game::unserialize( std::istream &fin, const std::string &path ) { chkversion( fin ); int tmpturn = 0; @@ -183,7 +183,7 @@ void game::unserialize( std::istream &fin ) int tmprun = 0; tripoint_om_sm lev; point_abs_om com; - JsonIn jsin( fin ); + JsonIn jsin( fin, path ); try { JsonObject data = jsin.get_object(); @@ -303,9 +303,9 @@ void scent_map::deserialize( const std::string &data, bool is_type ) #if defined(__ANDROID__) ///// quick shortcuts -void game::load_shortcuts( std::istream &fin ) +void game::load_shortcuts( std::istream &fin, const std::string &path ) { - JsonIn jsin( fin ); + JsonIn jsin( fin, path ); try { JsonObject data = jsin.get_object(); diff --git a/tests/memorial_test.cpp b/tests/memorial_test.cpp index 41b976094de5b..01c0727fa17dd 100644 --- a/tests/memorial_test.cpp +++ b/tests/memorial_test.cpp @@ -294,7 +294,7 @@ TEST_CASE( "convert_legacy_memorial_log", "[memorial]" ) memorial_logger logger; { std::istringstream is( input ); - logger.load( is ); + logger.load( is, "" ); std::ostringstream os; logger.save( os ); CHECK( os.str() == json_value ); @@ -303,7 +303,7 @@ TEST_CASE( "convert_legacy_memorial_log", "[memorial]" ) // Then verify that the new format is unchanged { std::istringstream is( json_value ); - logger.load( is ); + logger.load( is, "" ); std::ostringstream os; logger.save( os ); CHECK( os.str() == json_value ); @@ -328,6 +328,6 @@ TEST_CASE( "memorial_log_dumping", "[memorial]" ) memorial_logger logger; std::istringstream is( json_value ); - logger.load( is ); + logger.load( is, "" ); CHECK( logger.dump() == expected_output ); } From b39179061d4b15063f4047f3ef84943eb5c52e20 Mon Sep 17 00:00:00 2001 From: John Bytheway Date: Wed, 21 Apr 2021 11:01:55 -0400 Subject: [PATCH 198/453] Improve error message for JSON files with a BOM (#48595) * Improve error message for JSON files with a BOM Previously, JSON files starting with a BOM would have a strange and unhelpful error message that could easily confuse new contributors who had edited a file in Notepad. Add a check for this case and try to provide a more helpful error. Also, expand on this issue in CONTRIBUTING.md, and add some more links to the wiki guide for first time contributors. Co-authored-by: Binrui Dong --- .github/CONTRIBUTING.md | 20 ++++++++++++++++++-- doc/MODDING.md | 5 +++++ src/json.cpp | 27 +++++++++++++++++++++++++++ src/json.h | 11 ++++------- 4 files changed, 54 insertions(+), 9 deletions(-) diff --git a/.github/CONTRIBUTING.md b/.github/CONTRIBUTING.md index fc2f76faaa571..bd959ede62aea 100644 --- a/.github/CONTRIBUTING.md +++ b/.github/CONTRIBUTING.md @@ -2,12 +2,28 @@ **Opening a new issue?** Please read [ISSUES.md](../ISSUES.md) first. -Contributing to Cataclysm: Dark Days Ahead is easy — simply fork the repository here on GitHub, make your changes, and then send us a pull request. +**Want an introductory guide for creating game content?** You might want to +read the [Guide to adding new content to CDDA for first time +contributors](https://github.com/CleverRaven/Cataclysm-DDA/wiki/Guide-to-adding-new-content-to-CDDA-for-first-time-contributors) +on the CDDA wiki. Cataclysm:Dark Days Ahead is released under the Creative Commons Attribution ShareAlike 3.0 license. The code and content of the game is free to use, modify, and redistribute for any purpose whatsoever. See http://creativecommons.org/licenses/by-sa/3.0/ for details. This means any contribution you make to the project will also be covered by the same license, and this license is irrevocable. -## Guidelines +## Using a good text editor + +Most of the Cataclysm: Dark Days Ahead game data is defined in JSON files. +These files are intended to be easy for you to edit, but there are some +pitfalls. Using Windows Notepad can get you into trouble, because it likes to +insert a special character called a BOM at the start of the file, which CDDA +does not want. + +If you're going to be editing JSON files consider getting a more fully-featured +editor such as [Notepad++](https://notepad-plus-plus.org/). + +## Contributing to GitHub + +Contributing to Cataclysm: Dark Days Ahead is easy — simply fork the repository here on GitHub, make your changes, and then send us a pull request. There are a couple of guidelines we suggest sticking to: diff --git a/doc/MODDING.md b/doc/MODDING.md index 6b6d2fa638421..1db912b8cff7d 100644 --- a/doc/MODDING.md +++ b/doc/MODDING.md @@ -4,6 +4,11 @@ Certain features of the game can be modified without rebuilding the game from so The majority of modding is done by editing JSON files. An in-depth review of all json files and their appropriate fields is available in [JSON_INFO.md](JSON_INFO.md). +## Other guides + +You might want to read the [Guide to adding new content to CDDA for first time +contributors](https://github.com/CleverRaven/Cataclysm-DDA/wiki/Guide-to-adding-new-content-to-CDDA-for-first-time-contributors) on the CDDA wiki. + ## The basics ### Creating a barebones mod diff --git a/src/json.cpp b/src/json.cpp index 0f2df3195ee3b..b6657d2301cc6 100644 --- a/src/json.cpp +++ b/src/json.cpp @@ -747,6 +747,33 @@ void add_array_to_set( std::set &s, const JsonObject &json, const s } } +JsonIn::JsonIn( std::istream &s ) : stream( &s ) +{ + sanity_check_stream(); +} + +JsonIn::JsonIn( std::istream &s, const std::string &path ) + : stream( &s ) + , path( make_shared_fast( path ) ) +{ + sanity_check_stream(); +} + +JsonIn::JsonIn( std::istream &s, const json_source_location &loc ) + : stream( &s ), path( loc.path ) +{ + seek( loc.offset ); + sanity_check_stream(); +} + +void JsonIn::sanity_check_stream() +{ + char c = stream->peek(); + if( c == '\xef' ) { + error( _( "This JSON file looks like it starts with a Byte Order Mark (BOM) or is otherwise corrupted. This can happen if you edit files in Windows Notepad. See doc/CONTRIBUTING.md for more advice." ) ); + } +} + int JsonIn::tell() { return stream->tellg(); diff --git a/src/json.h b/src/json.h index f9bbb5dba5ae7..f192a81828c87 100644 --- a/src/json.h +++ b/src/json.h @@ -189,18 +189,15 @@ class JsonIn shared_ptr_fast path; bool ate_separator = false; + void sanity_check_stream(); void skip_separator(); void skip_pair_separator(); void end_value(); public: - explicit JsonIn( std::istream &s ) : stream( &s ) {} - JsonIn( std::istream &s, const std::string &path ) - : stream( &s ), path( make_shared_fast( path ) ) {} - JsonIn( std::istream &s, const json_source_location &loc ) - : stream( &s ), path( loc.path ) { - seek( loc.offset ); - } + explicit JsonIn( std::istream &s ); + JsonIn( std::istream &s, const std::string &path ); + JsonIn( std::istream &s, const json_source_location &loc ); JsonIn( const JsonIn & ) = delete; JsonIn &operator=( const JsonIn & ) = delete; From 289d6c4b99083e953b625229f193de8657c3526a Mon Sep 17 00:00:00 2001 From: John Bytheway Date: Thu, 22 Apr 2021 20:59:16 -0400 Subject: [PATCH 199/453] Improve tripoint formatting in debug messages (#48611) --- src/debug_menu.cpp | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/src/debug_menu.cpp b/src/debug_menu.cpp index f50b9a6978440..bd4646ff5a065 100644 --- a/src/debug_menu.cpp +++ b/src/debug_menu.cpp @@ -1022,7 +1022,7 @@ void teleport_short() } g->place_player( *where ); const tripoint new_pos( player_location.pos() ); - add_msg( _( "You teleport to point (%d,%d,%d)." ), new_pos.x, new_pos.y, new_pos.z ); + add_msg( _( "You teleport to point %s." ), new_pos.to_string() ); } void teleport_long() @@ -1032,7 +1032,7 @@ void teleport_long() return; } g->place_player_overmap( where ); - add_msg( _( "You teleport to submap (%s)." ), where.to_string() ); + add_msg( _( "You teleport to submap %s." ), where.to_string() ); } void teleport_overmap( bool specific_coordinates ) From a0eb08f52fd1ac164c1abce511f1a29a93ba5aa7 Mon Sep 17 00:00:00 2001 From: John Bytheway Date: Fri, 23 Apr 2021 17:06:12 -0400 Subject: [PATCH 200/453] Omit tests that are failing on Mingw (#48622) * Omit tests that are failing on Mingw These string_formatter tests fail on Mingw and it looks like it's simply a bug in the standard library there. I don't know that we can reasonably fix them (short of implementing printf ourselves) and they're showing up in the GitHub UI for every PR, which is potentially confusing for contributors. * Remove !mayfail marking on string_formatter test This should no longer be expected to fail, with the troublesome tests excised. --- tests/string_formatter_test.cpp | 9 +++++++-- 1 file changed, 7 insertions(+), 2 deletions(-) diff --git a/tests/string_formatter_test.cpp b/tests/string_formatter_test.cpp index 18e4d50bb0fc5..18f2fae922e4a 100644 --- a/tests/string_formatter_test.cpp +++ b/tests/string_formatter_test.cpp @@ -101,8 +101,7 @@ void mingw_test( const char *const old_pattern, const char *const new_pattern, c CHECK( original_result == new_result ); } -// Marking mayfail due to failure in MXE's MinGW on Travis on Ubuntu Xenial. -TEST_CASE( "string_formatter", "[!mayfail]" ) +TEST_CASE( "string_formatter" ) { test_typed_printf( "%hhi", "%i" ); test_typed_printf( "%hhu", "%u" ); @@ -221,7 +220,10 @@ TEST_CASE( "string_formatter", "[!mayfail]" ) importet_test( 38, "42 ", "%0-15d", 42 ); importet_test( 39, "-42 ", "%0-15d", -42 ); importet_test( 43, "42.90", "%.2f", 42.8952 ); +#if !(defined(__MINGW32__) || defined(__MINGW64__)) + // Omit this one that fails on Mingw importet_test( 44, "42.90", "%.2F", 42.8952 ); +#endif importet_test( 45, "42.8952000000", "%.10f", 42.8952 ); importet_test( 46, "42.90", "%1.2f", 42.8952 ); importet_test( 47, " 42.90", "%6.2f", 42.8952 ); @@ -515,6 +517,8 @@ TEST_CASE( "string_formatter", "[!mayfail]" ) importet_test( 365, " 00edcb5433", "%20.10x", 3989525555U ); importet_test( 366, " 1234ABCD", "%20.5X", 305441741 ); importet_test( 367, " 00EDCB5433", "%20.10X", 3989525555U ); +#if !(defined(__MINGW32__) || defined(__MINGW64__)) + // Omit these ones that fail on Mingw importet_test( 369, " 01024", "%020.5d", 1024 ); importet_test( 370, " -01024", "%020.5d", -1024 ); importet_test( 371, " 01024", "%020.5i", 1024 ); @@ -527,6 +531,7 @@ TEST_CASE( "string_formatter", "[!mayfail]" ) importet_test( 378, " 00edcb5433", "%020.10x", 3989525555U ); importet_test( 379, " 1234ABCD", "%020.5X", 305441741 ); importet_test( 380, " 00EDCB5433", "%020.10X", 3989525555U ); +#endif importet_test( 381, "", "%.0s", "Hallo heimur" ); importet_test( 382, " ", "%20.0s", "Hallo heimur" ); importet_test( 383, "", "%.s", "Hallo heimur" ); From 68027554b2d3ed8493efe1c1483566bdd444a18e Mon Sep 17 00:00:00 2001 From: John Bytheway Date: Mon, 26 Apr 2021 21:26:25 -0400 Subject: [PATCH 201/453] Triage clang-tidy readability-braces-around-statements (#48653) * Triage readability-braces-around-statements I tried running this clang-tidy check. It caught only one debatably useful case and had two false-positives due to a bug. This is mostly because this situation is already covered by astyle. I decided to take the opportunity to add comments for each of the disabled checks where we've decided we don't want to enable them. This one could be enabled once we're using a newer version of clang-tidy. Co-authored-by: actual-nh <74678550+actual-nh@users.noreply.github.com> Co-authored-by: Kevin Granade --- .clang-tidy | 26 +++++++++++++++++++++++++- 1 file changed, 25 insertions(+), 1 deletion(-) diff --git a/.clang-tidy b/.clang-tidy index a53ca3ca5bc02..1a30c0a992e36 100644 --- a/.clang-tidy +++ b/.clang-tidy @@ -4,6 +4,30 @@ # this codebase and we do not intend to fix. The disabled checks appearing # thereafter in a separate alphabetical list have yet to be triaged. We may # fix their errors or recategorise them as checks we don't care about. +# +# Comments on the checks we have decided are not worthwhile: +# +# * cert-dcl21-cpp (postfix operator++ and operator-- should return const objects) +# This is an unconventional code style, and conflicts with +# readability-const-return-type. +# +# * cert-env33-c (calls to system, popen) +# Unlikely to catch bugs, and using system is convenient for portability. +# +# * cert-err58-cpp (exceptions from static variable declarations) +# We have lots of memory allocations in static variable declarations, and +# that's fine. +# +# * modernize-use-auto +# We prefer an almost-always-avoid-auto style. +# +# * modernize-use-trailing-return-type +# An arbitrary style convention we haven't adopted. +# +# * readability-braces-around-statements +# Covered by astyle and buggy in clang-tidy 8. Can enable once we have a newer +# clang-tidy. + Checks: "\ bugprone-*,\ cata-*,\ @@ -21,6 +45,7 @@ modernize-*,\ -modernize-use-trailing-return-type,\ performance-*,\ readability-*,\ +-readability-braces-around-statements,\ -bugprone-misplaced-widening-cast,\ -bugprone-narrowing-conversions,\ -misc-non-private-member-variables-in-classes,\ @@ -31,7 +56,6 @@ readability-*,\ -modernize-use-emplace,\ -performance-type-promotion-in-math-fn,\ -performance-unnecessary-value-param,\ --readability-braces-around-statements,\ -readability-else-after-return,\ -readability-implicit-bool-conversion,\ -readability-isolate-declaration,\ From 03c09047482e39b165f125b5b792bc1df3d62d73 Mon Sep 17 00:00:00 2001 From: krulunio Date: Thu, 29 Apr 2021 09:04:56 +0200 Subject: [PATCH 202/453] Split military outposts and bunkers #### Summary None #### Additional context I plan to add those locations as possible base camp locations, having them under same OMTs makes my plan near impossible --- data/json/mapgen/bunker.json | 4 +-- data/json/mapgen/outpost.json | 2 +- .../overmap/overmap_special/specials.json | 27 +++++++++++++++++-- .../overmap_terrain_military.json | 19 +++++++++++++ 4 files changed, 47 insertions(+), 5 deletions(-) diff --git a/data/json/mapgen/bunker.json b/data/json/mapgen/bunker.json index b5df262465190..75bbb4a50dea6 100644 --- a/data/json/mapgen/bunker.json +++ b/data/json/mapgen/bunker.json @@ -112,7 +112,7 @@ { "type": "mapgen", "method": "json", - "om_terrain": [ "bunker_basement" ], + "om_terrain": [ "bunker_basement_1" ], "weight": 250, "object": { "fill_ter": "t_floor", @@ -211,7 +211,7 @@ { "type": "mapgen", "method": "json", - "om_terrain": [ "bunker_basement" ], + "om_terrain": [ "bunker_basement_1" ], "weight": 500, "object": { "fill_ter": "t_floor", diff --git a/data/json/mapgen/outpost.json b/data/json/mapgen/outpost.json index d4cc2ee7ccddb..9fd42f451c407 100644 --- a/data/json/mapgen/outpost.json +++ b/data/json/mapgen/outpost.json @@ -149,7 +149,7 @@ { "type": "mapgen", "method": "json", - "om_terrain": [ "outpost" ], + "om_terrain": [ "outpost_cross" ], "weight": 100, "object": { "rows": [ diff --git a/data/json/overmap/overmap_special/specials.json b/data/json/overmap/overmap_special/specials.json index 326b01007d486..4d75c9f61d145 100644 --- a/data/json/overmap/overmap_special/specials.json +++ b/data/json/overmap/overmap_special/specials.json @@ -821,7 +821,21 @@ "connections": [ { "point": [ 0, -1, 0 ], "from": [ 0, 0, 0 ] } ], "locations": [ "forest" ], "city_distance": [ 20, -1 ], - "occurrences": [ 50, 100 ], + "occurrences": [ 25, 100 ], + "flags": [ "MILITARY", "UNIQUE" ] + }, + { + "type": "overmap_special", + "id": "Military Bunker", + "overmaps": [ + { "point": [ 0, -1, 0 ], "overmap": "road_end_north" }, + { "point": [ 0, 0, 0 ], "overmap": "bunker_south" }, + { "point": [ 0, 0, -1 ], "overmap": "bunker_basement_1" } + ], + "connections": [ { "point": [ 0, -1, 0 ], "from": [ 0, 0, 0 ] } ], + "locations": [ "forest" ], + "city_distance": [ 20, -1 ], + "occurrences": [ 25, 100 ], "flags": [ "MILITARY", "UNIQUE" ] }, { @@ -830,7 +844,16 @@ "overmaps": [ { "point": [ 0, 0, 0 ], "overmap": "outpost_north" } ], "locations": [ "wilderness" ], "city_distance": [ 15, -1 ], - "occurrences": [ 50, 100 ], + "occurrences": [ 25, 100 ], + "flags": [ "MILITARY", "UNIQUE" ] + }, + { + "type": "overmap_special", + "id": "Military Outpost", + "overmaps": [ { "point": [ 0, 0, 0 ], "overmap": "outpost_cross_north" } ], + "locations": [ "wilderness" ], + "city_distance": [ 15, -1 ], + "occurrences": [ 25, 100 ], "flags": [ "MILITARY", "UNIQUE" ] }, { diff --git a/data/json/overmap/overmap_terrain/overmap_terrain_military.json b/data/json/overmap/overmap_terrain/overmap_terrain_military.json index 2fae29b7adae8..5a1343ef167a5 100644 --- a/data/json/overmap/overmap_terrain/overmap_terrain_military.json +++ b/data/json/overmap/overmap_terrain/overmap_terrain_military.json @@ -153,6 +153,15 @@ "see_cost": 2, "flags": [ "KNOWN_UP", "NO_ROTATE", "RISK_HIGH", "SOURCE_WEAPON", "SOURCE_AMMO" ] }, + { + "type": "overmap_terrain", + "id": "bunker_basement_1", + "name": "military bunker", + "sym": "B", + "color": "red", + "see_cost": 2, + "flags": [ "KNOWN_UP", "NO_ROTATE", "RISK_HIGH", "SOURCE_WEAPON", "SOURCE_AMMO" ] + }, { "type": "overmap_terrain", "id": "outpost", @@ -163,6 +172,16 @@ "extras": "build", "flags": [ "RISK_HIGH", "SOURCE_WEAPON", "SOURCE_AMMO" ] }, + { + "type": "overmap_terrain", + "id": "outpost_cross", + "name": "military outpost", + "sym": "M", + "color": "red", + "see_cost": 2, + "extras": "build", + "flags": [ "RISK_HIGH", "SOURCE_WEAPON", "SOURCE_AMMO" ] + }, { "type": "overmap_terrain", "id": [ "silo", "silo_1", "silo_2", "silo_3", "silo_4", "silo_finale" ], From 51efa5105db2b6b9f778ffbb630050a7bf36e390 Mon Sep 17 00:00:00 2001 From: actual-nh <74678550+actual-nh@users.noreply.github.com> Date: Thu, 29 Apr 2021 15:15:28 -0400 Subject: [PATCH 203/453] Correct description of epidemiologist in newspaper (#48684) He's not a correspondent unless he's a reporter. --- data/json/snippets/newspapers.json | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/data/json/snippets/newspapers.json b/data/json/snippets/newspapers.json index 51269f1dfd27c..c059b05a82094 100644 --- a/data/json/snippets/newspapers.json +++ b/data/json/snippets/newspapers.json @@ -348,7 +348,7 @@ }, { "id": "weeks_old_news_12", - "text": "PSYCHIC EMANATIONS? A seemingly far-fetched theory about ongoing riots sweeping the nation has been gaining traction after a leaked document about experiments in magnetic control of brain-waves. \"Two weeks ago, I'd have told you this is ridiculous,\" said Dr. Andrew Morton, an epidemiologist and our leading correspondent for the medical basis for the riots. \"Now? I'll consider anything. With the caveat that I don't think any of this is possible, magnetic weaponry altering our brain waves and making people into crazy violent psychopaths is more plausible than a lot of the theories running around. I certainly prefer this one to that 'zombies' suggestion from a few days ago.\"" + "text": "PSYCHIC EMANATIONS? A seemingly far-fetched theory about ongoing riots sweeping the nation has been gaining traction after a leaked document about experiments in magnetic control of brain-waves. \"Two weeks ago, I'd have told you this is ridiculous,\" said Dr. Andrew Morton, an epidemiologist and our leading expert on the medical basis for the riots. \"Now? I'll consider anything. With the caveat that I don't think any of this is possible, magnetic weaponry altering our brain waves and making people into crazy violent psychopaths is more plausible than a lot of the theories running around. I certainly prefer this one to that 'zombies' suggestion from a few days ago.\"" }, { "id": "weeks_old_news_13", From ada99d413a768f1226d194041ff1e7cb03a94509 Mon Sep 17 00:00:00 2001 From: John Bytheway Date: Fri, 30 Apr 2021 07:52:41 -0400 Subject: [PATCH 204/453] Enable performance-type-promotion-in-math-fn Enable this clang-tidy check that has no associated warnings. --- .clang-tidy | 1 - 1 file changed, 1 deletion(-) diff --git a/.clang-tidy b/.clang-tidy index 1a30c0a992e36..9f3a11e18bec3 100644 --- a/.clang-tidy +++ b/.clang-tidy @@ -54,7 +54,6 @@ readability-*,\ -modernize-return-braced-init-list,\ -modernize-use-default-member-init,\ -modernize-use-emplace,\ --performance-type-promotion-in-math-fn,\ -performance-unnecessary-value-param,\ -readability-else-after-return,\ -readability-implicit-bool-conversion,\ From c90c9e9d3b7d5e0366e381476cbd8a0d7464e2c1 Mon Sep 17 00:00:00 2001 From: John Bytheway Date: Fri, 30 Apr 2021 15:46:53 -0400 Subject: [PATCH 205/453] Remove unused global statics --- src/character.cpp | 2 -- src/debug_menu.cpp | 1 - src/game_inventory.cpp | 2 -- src/item.cpp | 1 - src/iuse.cpp | 8 -------- src/map_extras.cpp | 6 ------ src/melee.cpp | 2 -- src/suffer.cpp | 3 --- src/visitable.cpp | 2 -- tests/clzones_test.cpp | 1 - tests/vehicle_part_test.cpp | 4 ++-- tools/clang-tidy-plugin/CataTidyModule.cpp | 1 + 12 files changed, 3 insertions(+), 30 deletions(-) diff --git a/src/character.cpp b/src/character.cpp index 15b491daab3d1..87583300e5c15 100644 --- a/src/character.cpp +++ b/src/character.cpp @@ -252,8 +252,6 @@ static const trait_id trait_CHITIN_FUR3( "CHITIN_FUR3" ); static const trait_id trait_CLUMSY( "CLUMSY" ); static const trait_id trait_DEBUG_NODMG( "DEBUG_NODMG" ); static const trait_id trait_DEFT( "DEFT" ); -static const trait_id trait_EASYSLEEPER( "EASYSLEEPER" ); -static const trait_id trait_EASYSLEEPER2( "EASYSLEEPER2" ); static const trait_id trait_EATHEALTH( "EATHEALTH" ); static const trait_id trait_FAT( "FAT" ); static const trait_id trait_FELINE_FUR( "FELINE_FUR" ); diff --git a/src/debug_menu.cpp b/src/debug_menu.cpp index bd4646ff5a065..850b391a78caf 100644 --- a/src/debug_menu.cpp +++ b/src/debug_menu.cpp @@ -111,7 +111,6 @@ #include "weighted_list.h" static const efftype_id effect_asthma( "asthma" ); -static const efftype_id effect_flu( "flu" ); static const mtype_id mon_generator( "mon_generator" ); diff --git a/src/game_inventory.cpp b/src/game_inventory.cpp index 0198fd600e926..30d26aac9e111 100644 --- a/src/game_inventory.cpp +++ b/src/game_inventory.cpp @@ -63,8 +63,6 @@ static const activity_id ACT_CONSUME_FOOD_MENU( "ACT_CONSUME_FOOD_MENU" ); static const activity_id ACT_CONSUME_DRINK_MENU( "ACT_CONSUME_DRINK_MENU" ); static const activity_id ACT_CONSUME_MEDS_MENU( "ACT_CONSUME_MEDS_MENU" ); -static const fault_id fault_bionic_salvaged( "fault_bionic_salvaged" ); - static const quality_id qual_ANESTHESIA( "ANESTHESIA" ); static const bionic_id bio_painkiller( "bio_painkiller" ); diff --git a/src/item.cpp b/src/item.cpp index 4a79e9de3d7af..00d6036e2c1e3 100644 --- a/src/item.cpp +++ b/src/item.cpp @@ -162,7 +162,6 @@ static const bionic_id bio_digestion( "bio_digestion" ); static const trait_id trait_CARNIVORE( "CARNIVORE" ); static const trait_id trait_JITTERY( "JITTERY" ); static const trait_id trait_LIGHTWEIGHT( "LIGHTWEIGHT" ); -static const trait_id trait_SAPROVORE( "SAPROVORE" ); static const trait_id trait_TOLERANCE( "TOLERANCE" ); static const trait_id trait_WOOLALLERGY( "WOOLALLERGY" ); diff --git a/src/iuse.cpp b/src/iuse.cpp index 70cbebe7f091a..2278aeabd2e1b 100644 --- a/src/iuse.cpp +++ b/src/iuse.cpp @@ -121,7 +121,6 @@ static const activity_id ACT_CHOP_PLANKS( "ACT_CHOP_PLANKS" ); static const activity_id ACT_CHOP_TREE( "ACT_CHOP_TREE" ); static const activity_id ACT_CHURN( "ACT_CHURN" ); static const activity_id ACT_CLEAR_RUBBLE( "ACT_CLEAR_RUBBLE" ); -static const activity_id ACT_CRAFT( "ACT_CRAFT" ); static const activity_id ACT_FILL_PIT( "ACT_FILL_PIT" ); static const activity_id ACT_FISH( "ACT_FISH" ); static const activity_id ACT_GAME( "ACT_GAME" ); @@ -143,7 +142,6 @@ static const efftype_id effect_antibiotic( "antibiotic" ); static const efftype_id effect_antibiotic_visible( "antibiotic_visible" ); static const efftype_id effect_antifungal( "antifungal" ); static const efftype_id effect_asthma( "asthma" ); -static const efftype_id effect_attention( "attention" ); static const efftype_id effect_beartrap( "beartrap" ); static const efftype_id effect_bite( "bite" ); static const efftype_id effect_bleed( "bleed" ); @@ -206,7 +204,6 @@ static const efftype_id effect_strong_antibiotic_visible( "strong_antibiotic_vis static const efftype_id effect_stunned( "stunned" ); static const efftype_id effect_tapeworm( "tapeworm" ); static const efftype_id effect_teargas( "teargas" ); -static const efftype_id effect_teleglow( "teleglow" ); static const efftype_id effect_tetanus( "tetanus" ); static const efftype_id effect_tied( "tied" ); static const efftype_id effect_took_antiasthmatic( "took_antiasthmatic" ); @@ -350,23 +347,18 @@ static const species_id species_FUNGUS( "FUNGUS" ); static const species_id species_HALLUCINATION( "HALLUCINATION" ); static const species_id species_INSECT( "INSECT" ); static const species_id species_ROBOT( "ROBOT" ); -static const species_id species_ZOMBIE( "ZOMBIE" ); static const vitamin_id vitamin_blood( "blood" ); static const vitamin_id vitamin_redcells( "redcells" ); static const mongroup_id GROUP_FISH( "GROUP_FISH" ); -static const mtype_id mon_bee( "mon_bee" ); static const mtype_id mon_blob( "mon_blob" ); static const mtype_id mon_dog_thing( "mon_dog_thing" ); -static const mtype_id mon_fly( "mon_fly" ); static const mtype_id mon_hallu_multicooker( "mon_hallu_multicooker" ); static const mtype_id mon_hologram( "mon_hologram" ); -static const mtype_id mon_shadow( "mon_shadow" ); static const mtype_id mon_spore( "mon_spore" ); static const mtype_id mon_vortex( "mon_vortex" ); -static const mtype_id mon_wasp( "mon_wasp" ); static const bionic_id bio_shock( "bio_shock" ); static const bionic_id bio_tools( "bio_tools" ); diff --git a/src/map_extras.cpp b/src/map_extras.cpp index 5834d5cb92673..c55ddea0ee287 100644 --- a/src/map_extras.cpp +++ b/src/map_extras.cpp @@ -84,12 +84,10 @@ static const itype_id itype_bag_canvas( "bag_canvas" ); static const itype_id itype_bottle_glass( "bottle_glass" ); static const itype_id itype_bullwhip( "bullwhip" ); static const itype_id itype_chunk_sulfur( "chunk_sulfur" ); -static const itype_id itype_coke( "coke" ); static const itype_id itype_crowbar( "crowbar" ); static const itype_id itype_fedora( "fedora" ); static const itype_id itype_glasses_eye( "glasses_eye" ); static const itype_id itype_hatchet( "hatchet" ); -static const itype_id itype_heroin( "heroin" ); static const itype_id itype_holybook_bible1( "holybook_bible1" ); static const itype_id itype_indoor_volleyball( "indoor_volleyball" ); static const itype_id itype_jacket_leather( "jacket_leather" ); @@ -98,7 +96,6 @@ static const itype_id itype_landmine( "landmine" ); static const itype_id itype_machete( "machete" ); static const itype_id itype_material_sand( "material_sand" ); static const itype_id itype_material_soil( "material_soil" ); -static const itype_id itype_meth( "meth" ); static const itype_id itype_rag_bloody( "rag_bloody" ); static const itype_id itype_remington_870_breacher( "remington_870_breacher" ); static const itype_id itype_shot_hull( "shot_hull" ); @@ -113,7 +110,6 @@ static const itype_id itype_tux( "tux" ); static const itype_id itype_umbrella( "umbrella" ); static const itype_id itype_usp_45( "usp_45" ); static const itype_id itype_vodka( "vodka" ); -static const itype_id itype_weed( "weed" ); static const itype_id itype_wheel( "wheel" ); static const itype_id itype_withered( "withered" ); static const itype_id itype_wrench( "wrench" ); @@ -154,9 +150,7 @@ static const mtype_id mon_wolf( "mon_wolf" ); static const mtype_id mon_zombie_bio_op( "mon_zombie_bio_op" ); static const mtype_id mon_zombie_military_pilot( "mon_zombie_military_pilot" ); static const mtype_id mon_zombie_scientist( "mon_zombie_scientist" ); -static const mtype_id mon_zombie_smoker( "mon_zombie_smoker" ); static const mtype_id mon_zombie_soldier( "mon_zombie_soldier" ); -static const mtype_id mon_zombie_spitter( "mon_zombie_spitter" ); static const mtype_id mon_zombie_tough( "mon_zombie_tough" ); class npc_template; diff --git a/src/melee.cpp b/src/melee.cpp index 2466c12332a46..e09e46acdeb7f 100644 --- a/src/melee.cpp +++ b/src/melee.cpp @@ -85,7 +85,6 @@ static const skill_id skill_unarmed( "unarmed" ); static const skill_id skill_bashing( "bashing" ); static const skill_id skill_melee( "melee" ); -static const efftype_id effect_badpoison( "badpoison" ); static const efftype_id effect_beartrap( "beartrap" ); static const efftype_id effect_bouldering( "bouldering" ); static const efftype_id effect_contacts( "contacts" ); @@ -98,7 +97,6 @@ static const efftype_id effect_hit_by_player( "hit_by_player" ); static const efftype_id effect_incorporeal( "incorporeal" ); static const efftype_id effect_lightsnare( "lightsnare" ); static const efftype_id effect_narcosis( "narcosis" ); -static const efftype_id effect_poison( "poison" ); static const efftype_id effect_stunned( "stunned" ); static const efftype_id effect_venom_dmg( "venom_dmg" ); static const efftype_id effect_venom_weaken( "venom_weaken" ); diff --git a/src/suffer.cpp b/src/suffer.cpp index 01e198c3e6971..125cffd0e5c73 100644 --- a/src/suffer.cpp +++ b/src/suffer.cpp @@ -138,7 +138,6 @@ static const trait_id trait_RADIOACTIVE2( "RADIOACTIVE2" ); static const trait_id trait_RADIOACTIVE3( "RADIOACTIVE3" ); static const trait_id trait_RADIOGENIC( "RADIOGENIC" ); static const trait_id trait_REGEN_LIZ( "REGEN_LIZ" ); -static const trait_id trait_ROOTS3( "ROOTS3" ); static const trait_id trait_SCHIZOPHRENIC( "SCHIZOPHRENIC" ); static const trait_id trait_SHARKTEETH( "SHARKTEETH" ); static const trait_id trait_SHELL2( "SHELL2" ); @@ -162,8 +161,6 @@ static const mtype_id mon_zombie_fat( "mon_zombie_fat" ); static const mtype_id mon_zombie_fireman( "mon_zombie_fireman" ); static const mtype_id mon_zombie_soldier( "mon_zombie_soldier" ); -static const std::string flag_PLOWABLE( "PLOWABLE" ); - static const json_character_flag json_flag_GLARE_RESIST( "GLARE_RESIST" ); static float addiction_scaling( float at_min, float at_max, float add_lvl ) diff --git a/src/visitable.cpp b/src/visitable.cpp index 03723a66e92f4..0009541f66e61 100644 --- a/src/visitable.cpp +++ b/src/visitable.cpp @@ -46,8 +46,6 @@ static const quality_id qual_BUTCHER( "BUTCHER" ); static const bionic_id bio_ups( "bio_ups" ); -static const json_character_flag json_flag_BIONIC_TOGGLED( "BIONIC_TOGGLED" ); - /** @relates visitable */ item *read_only_visitable::find_parent( const item &it ) const { diff --git a/tests/clzones_test.cpp b/tests/clzones_test.cpp index 9e8fd6cd9ba02..d88f26996784f 100644 --- a/tests/clzones_test.cpp +++ b/tests/clzones_test.cpp @@ -12,7 +12,6 @@ #include "ret_val.h" #include "type_id.h" -static const zone_type_id zone_type_LOOT_UNSORTED( "LOOT_UNSORTED" ); static const zone_type_id zone_type_LOOT_FOOD( "LOOT_FOOD" ); static const zone_type_id zone_type_LOOT_PFOOD( "LOOT_PFOOD" ); static const zone_type_id zone_type_LOOT_DRINK( "LOOT_DRINK" ); diff --git a/tests/vehicle_part_test.cpp b/tests/vehicle_part_test.cpp index 1cc0113dcd578..3c861c2c52d57 100644 --- a/tests/vehicle_part_test.cpp +++ b/tests/vehicle_part_test.cpp @@ -31,8 +31,8 @@ #include "vpart_position.h" #include "vpart_range.h" -static time_point midnight = calendar::turn_zero + 0_hours; -static time_point midday = calendar::turn_zero + 12_hours; +static time_point midnight = calendar::turn_zero; +static time_point midday = midnight + 12_hours; static void set_time( const time_point &time ) { diff --git a/tools/clang-tidy-plugin/CataTidyModule.cpp b/tools/clang-tidy-plugin/CataTidyModule.cpp index b8442e9344f3b..e72f158a7ec41 100644 --- a/tools/clang-tidy-plugin/CataTidyModule.cpp +++ b/tools/clang-tidy-plugin/CataTidyModule.cpp @@ -69,6 +69,7 @@ class CataModule : public ClangTidyModule } // namespace cata // Register the MiscTidyModule using this statically initialized variable. +// NOLINTNEXTLINE(cata-unused-statics) static ClangTidyModuleRegistry::Add X( "cata-module", "Adds Cataclysm-DDA checks." ); From 91e2d2eedc50ad5ab482c8523ae8fe5da3fd93e7 Mon Sep 17 00:00:00 2001 From: John Bytheway Date: Fri, 30 Apr 2021 13:38:31 -0400 Subject: [PATCH 206/453] Check for unused static variables We have a lot of global static string_ids. We want to be able to detect when they are no longer used. This check tries to do this. --- tools/clang-tidy-plugin/CMakeLists.txt | 1 + tools/clang-tidy-plugin/CataTidyModule.cpp | 2 + .../clang-tidy-plugin/UnusedStaticsCheck.cpp | 82 +++++++++++++++++++ tools/clang-tidy-plugin/UnusedStaticsCheck.h | 36 ++++++++ .../clang-tidy-plugin/test/unused-statics.cpp | 31 +++++++ 5 files changed, 152 insertions(+) create mode 100644 tools/clang-tidy-plugin/UnusedStaticsCheck.cpp create mode 100644 tools/clang-tidy-plugin/UnusedStaticsCheck.h create mode 100644 tools/clang-tidy-plugin/test/unused-statics.cpp diff --git a/tools/clang-tidy-plugin/CMakeLists.txt b/tools/clang-tidy-plugin/CMakeLists.txt index 54064951c5d67..f7e804152cf0e 100644 --- a/tools/clang-tidy-plugin/CMakeLists.txt +++ b/tools/clang-tidy-plugin/CMakeLists.txt @@ -24,6 +24,7 @@ add_library(CataAnalyzerPlugin MODULE TextStyleCheck.cpp TranslatorCommentsCheck.cpp UnsequencedCallsCheck.cpp + UnusedStaticsCheck.cpp UseLocalizedSortingCheck.cpp UseNamedPointConstantsCheck.cpp UsePointApisCheck.cpp diff --git a/tools/clang-tidy-plugin/CataTidyModule.cpp b/tools/clang-tidy-plugin/CataTidyModule.cpp index e72f158a7ec41..8a28b0713e206 100644 --- a/tools/clang-tidy-plugin/CataTidyModule.cpp +++ b/tools/clang-tidy-plugin/CataTidyModule.cpp @@ -19,6 +19,7 @@ #include "TextStyleCheck.h" #include "TranslatorCommentsCheck.h" #include "UnsequencedCallsCheck.h" +#include "UnusedStaticsCheck.h" #include "UseLocalizedSortingCheck.h" #include "UseNamedPointConstantsCheck.h" #include "UsePointApisCheck.h" @@ -57,6 +58,7 @@ class CataModule : public ClangTidyModule CheckFactories.registerCheck( "cata-text-style" ); CheckFactories.registerCheck( "cata-translator-comments" ); CheckFactories.registerCheck( "cata-unsequenced-calls" ); + CheckFactories.registerCheck( "cata-unused-statics" ); CheckFactories.registerCheck( "cata-use-localized-sorting" ); CheckFactories.registerCheck( "cata-use-named-point-constants" ); diff --git a/tools/clang-tidy-plugin/UnusedStaticsCheck.cpp b/tools/clang-tidy-plugin/UnusedStaticsCheck.cpp new file mode 100644 index 0000000000000..c69b60ddf2ff2 --- /dev/null +++ b/tools/clang-tidy-plugin/UnusedStaticsCheck.cpp @@ -0,0 +1,82 @@ +#include "UnusedStaticsCheck.h" +#include "Utils.h" +#include + +using namespace clang::ast_matchers; + +namespace clang +{ +namespace tidy +{ +namespace cata +{ + +void UnusedStaticsCheck::registerMatchers( MatchFinder *Finder ) +{ + Finder->addMatcher( + varDecl( + anyOf( hasParent( namespaceDecl() ), hasParent( translationUnitDecl() ) ), + hasStaticStorageDuration() + ).bind( "decl" ), + this + ); + Finder->addMatcher( + declRefExpr( to( varDecl().bind( "decl" ) ) ).bind( "ref" ), + this + ); +} + +void UnusedStaticsCheck::check( const MatchFinder::MatchResult &Result ) +{ + const VarDecl *ThisDecl = Result.Nodes.getNodeAs( "decl" ); + if( !ThisDecl ) { + return; + } + + const DeclRefExpr *Ref = Result.Nodes.getNodeAs( "ref" ); + if( Ref ) { + used_decls_.insert( ThisDecl ); + } + + const SourceManager &SM = *Result.SourceManager; + + // Ignore cases in header files + if( !SM.isInMainFile( ThisDecl->getBeginLoc() ) ) { + return; + } + + // Ignore cases that are not the first declaration + if( ThisDecl->getPreviousDecl() ) { + return; + } + + // Ignore cases that are not static linkage + Linkage Lnk = ThisDecl->getFormalLinkage(); + if( Lnk != InternalLinkage && Lnk != UniqueExternalLinkage ) { + return; + } + + SourceLocation DeclLoc = ThisDecl->getBeginLoc(); + SourceLocation ExpansionLoc = SM.getFileLoc( DeclLoc ); + if( DeclLoc != ExpansionLoc ) { + // We are inside a macro expansion + return; + } + + decls_.push_back( ThisDecl ); +} + +void UnusedStaticsCheck::onEndOfTranslationUnit() +{ + for( const VarDecl *V : decls_ ) { + if( used_decls_.count( V ) ) { + continue; + } + + diag( V->getBeginLoc(), "Variable %0 declared but not used." ) << V; + } +} + +} // namespace cata +} // namespace tidy +} // namespace clang diff --git a/tools/clang-tidy-plugin/UnusedStaticsCheck.h b/tools/clang-tidy-plugin/UnusedStaticsCheck.h new file mode 100644 index 0000000000000..0711759ca9bea --- /dev/null +++ b/tools/clang-tidy-plugin/UnusedStaticsCheck.h @@ -0,0 +1,36 @@ +#ifndef CATA_TOOLS_CLANG_TIDY_PLUGIN_UNUSEDSTATICSCHECK_H +#define CATA_TOOLS_CLANG_TIDY_PLUGIN_UNUSEDSTATICSCHECK_H + +#include +#include + +#include "ClangTidy.h" + +namespace clang +{ + +namespace tidy +{ +class ClangTidyContext; + +namespace cata +{ + +class UnusedStaticsCheck : public ClangTidyCheck +{ + public: + UnusedStaticsCheck( StringRef Name, ClangTidyContext *Context ) + : ClangTidyCheck( Name, Context ) {} + void registerMatchers( ast_matchers::MatchFinder *Finder ) override; + void check( const ast_matchers::MatchFinder::MatchResult &Result ) override; + void onEndOfTranslationUnit() override; + private: + std::unordered_set used_decls_; + std::vector decls_; +}; + +} // namespace cata +} // namespace tidy +} // namespace clang + +#endif // CATA_TOOLS_CLANG_TIDY_PLUGIN_UNUSEDSTATICSCHECK_H diff --git a/tools/clang-tidy-plugin/test/unused-statics.cpp b/tools/clang-tidy-plugin/test/unused-statics.cpp new file mode 100644 index 0000000000000..e10370b7479c6 --- /dev/null +++ b/tools/clang-tidy-plugin/test/unused-statics.cpp @@ -0,0 +1,31 @@ +// RUN: %check_clang_tidy %s cata-unused-statics %t -- -plugins=%cata_plugin -- + +class A0 {}; + +static A0 a0; +// CHECK-MESSAGES: warning: Variable 'a0' declared but not used. [cata-unused-statics] + +namespace cata +{ + +class A1 {}; + +static A1 a1; +// CHECK-MESSAGES: warning: Variable 'a1' declared but not used. [cata-unused-statics] + +} + +namespace +{ + +class A2 {}; + +A2 a2; +// CHECK-MESSAGES: warning: Variable 'a2' declared but not used. [cata-unused-statics] + +} + +// No warnings inside macros +class A3 {}; +#define M3 static A3 a3; +M3 From 39d2a73c1451c3cce2b99cf8ea693265acccca7b Mon Sep 17 00:00:00 2001 From: John Bytheway Date: Wed, 28 Apr 2021 08:53:32 -0400 Subject: [PATCH 207/453] Fix StringMaker ODR violations in tests Catch2 provides a customization point for converting our types to strings by specializing the StringMaker template. We have some specializations in stringmaker.h, but this feature was only working intermittently. I finally figured out that was due to an ODR violation. The test files that didn't include stringmaker.h were compiling a different specialization than the ones that did. Re-jig the test includes so that any file including catch.hpp also includes stringmaker.h, thereby ensuring that the custom specializations are used everywhere and there is no ODR violation. I achieved this by adding a new cata_catch.h header and making all existing headers include catch.hpp via the new header. --- tests/active_item_cache_test.cpp | 2 +- tests/active_item_test.cpp | 2 +- tests/activity_tracker_test.cpp | 2 +- tests/algo_test.cpp | 2 +- tests/ammo_set_test.cpp | 2 +- tests/ammo_test.cpp | 2 +- tests/archery_damage_test.cpp | 2 +- tests/assertion_helpers.h | 2 +- tests/battery_mod_test.cpp | 2 +- tests/behavior_test.cpp | 2 +- tests/bionics_test.cpp | 2 +- tests/calendar_test.cpp | 2 +- tests/cata_catch.h | 15 +++++++++++++++ tests/cata_generators.h | 2 +- tests/cata_utility_test.cpp | 2 +- tests/cata_variant_test.cpp | 2 +- tests/catacharset_test.cpp | 2 +- tests/char_biometrics_test.cpp | 2 +- tests/char_edible_rating_test.cpp | 2 +- tests/char_exposure_test.cpp | 2 +- tests/char_healing_test.cpp | 2 +- tests/char_sight_test.cpp | 2 +- tests/char_stamina_test.cpp | 2 +- tests/char_suffer_test.cpp | 2 +- tests/char_validity_check_test.cpp | 2 +- tests/clzones_test.cpp | 2 +- tests/colony_test.cpp | 2 +- tests/comestible_test.cpp | 2 +- tests/coordinate_test.cpp | 2 +- tests/crafting_test.cpp | 2 +- tests/creature_effect_test.cpp | 2 +- tests/creature_in_field_test.cpp | 2 +- tests/creature_test.cpp | 2 +- tests/effect_test.cpp | 2 +- tests/effective_dps_test.cpp | 2 +- tests/enchantments_test.cpp | 2 +- tests/encumbrance_test.cpp | 2 +- tests/event_test.cpp | 2 +- tests/explosion_balance_test.cpp | 2 +- tests/field_test.cpp | 2 +- tests/flat_set_test.cpp | 2 +- tests/focus_test.cpp | 2 +- tests/fold_string_test.cpp | 2 +- tests/food_fun_for_test.cpp | 2 +- tests/generic_factory_test.cpp | 2 +- tests/ground_destroy_test.cpp | 2 +- tests/hash_test.cpp | 2 +- tests/health_test.cpp | 2 +- tests/iexamine_test.cpp | 2 +- tests/invlet_test.cpp | 2 +- tests/item_contents_test.cpp | 2 +- tests/item_group_test.cpp | 2 +- tests/item_location_test.cpp | 2 +- tests/item_stackable_test.cpp | 2 +- tests/item_test.cpp | 2 +- tests/item_tname_test.cpp | 2 +- tests/item_type_name_test.cpp | 2 +- tests/iteminfo_test.cpp | 11 +++++------ tests/itemname_test.cpp | 2 +- tests/iuse_actor_test.cpp | 2 +- tests/iuse_test.cpp | 2 +- tests/json_test.cpp | 2 +- tests/line_test.cpp | 2 +- tests/list_test.cpp | 2 +- tests/magic_spell_effect_test.cpp | 2 +- tests/magic_spell_test.cpp | 2 +- tests/make_static_test.cpp | 2 +- tests/map_extra_test.cpp | 2 +- tests/map_iterator_test.cpp | 2 +- tests/map_memory_test.cpp | 2 +- tests/map_test.cpp | 2 +- tests/map_test_case.h | 2 +- tests/mapgen_function_test.cpp | 2 +- tests/math_functions_test.cpp | 2 +- tests/melee_dodge_hit_test.cpp | 2 +- tests/melee_test.cpp | 2 +- tests/memorial_test.cpp | 2 +- tests/modify_morale_test.cpp | 2 +- tests/mondefense_test.cpp | 2 +- tests/monfactions_test.cpp | 2 +- tests/monster_attack_test.cpp | 2 +- tests/monster_test.cpp | 2 +- tests/monster_vision_test.cpp | 2 +- tests/moon_test.cpp | 2 +- tests/morale_test.cpp | 2 +- tests/mutation_test.cpp | 2 +- tests/name_test.cpp | 2 +- tests/new_character_test.cpp | 3 +-- tests/npc_talk_test.cpp | 2 +- tests/npc_test.cpp | 2 +- tests/optional_test.cpp | 2 +- tests/overmap_noise_test.cpp | 2 +- tests/overmap_test.cpp | 2 +- tests/player_helpers.cpp | 2 +- tests/player_test.cpp | 2 +- tests/pocket_test.cpp | 2 +- tests/point_test.cpp | 2 +- tests/projectile_test.cpp | 2 +- tests/ranged_balance_test.cpp | 2 +- tests/reachability_cache_test.cpp | 2 +- tests/reading_test.cpp | 2 +- tests/recipe_test.cpp | 2 +- tests/reload_magazine_test.cpp | 2 +- tests/reload_option_test.cpp | 2 +- tests/reloading_test.cpp | 2 +- tests/requirements_test.cpp | 2 +- tests/rewrite_vsnprintf_test.cpp | 2 +- tests/rng_test.cpp | 2 +- tests/rot_test.cpp | 2 +- tests/safe_reference_test.cpp | 2 +- tests/shadowcasting_test.cpp | 2 +- tests/simple_pathfinding_test.cpp | 2 +- tests/stats_tracker_test.cpp | 2 +- tests/stomach_contents_test.cpp | 2 +- tests/string_formatter_test.cpp | 2 +- tests/string_ids_test.cpp | 2 +- tests/string_test.cpp | 2 +- tests/stringmaker.h | 2 +- tests/submap_load_test.cpp | 2 +- tests/submap_test.cpp | 2 +- tests/sun_test.cpp | 2 +- tests/temp_crafting_inv_test.cpp | 2 +- tests/temperature_test.cpp | 2 +- tests/test_main.cpp | 2 +- tests/test_statistics.h | 2 +- tests/text_snippets_test.cpp | 2 +- tests/throwing_test.cpp | 2 +- tests/translations_test.cpp | 2 +- tests/try_parse_integer_test.cpp | 2 +- tests/units_test.cpp | 2 +- tests/unseal_and_spill_test.cpp | 2 +- tests/value_ptr_test.cpp | 2 +- tests/vehicle_drag_test.cpp | 2 +- tests/vehicle_efficiency_test.cpp | 2 +- tests/vehicle_interact_test.cpp | 2 +- tests/vehicle_part_test.cpp | 2 +- tests/vehicle_power_test.cpp | 2 +- tests/vehicle_ramp_test.cpp | 2 +- tests/vehicle_split_test.cpp | 2 +- tests/vehicle_test.cpp | 2 +- tests/vehicle_turrets_test.cpp | 2 +- tests/vision_test.cpp | 2 +- tests/visitable_remove_test.cpp | 2 +- tests/visitable_test.cpp | 2 +- tests/weary_test.cpp | 2 +- tests/weather_test.cpp | 2 +- tests/wield_times_test.cpp | 2 +- 147 files changed, 165 insertions(+), 152 deletions(-) create mode 100644 tests/cata_catch.h diff --git a/tests/active_item_cache_test.cpp b/tests/active_item_cache_test.cpp index 8307cd1bc0d1f..a92816bc935dd 100644 --- a/tests/active_item_cache_test.cpp +++ b/tests/active_item_cache_test.cpp @@ -1,7 +1,7 @@ #include #include "calendar.h" -#include "catch/catch.hpp" +#include "cata_catch.h" #include "game_constants.h" #include "item.h" #include "map.h" diff --git a/tests/active_item_test.cpp b/tests/active_item_test.cpp index 5676d0f94d683..2a89e295f5097 100644 --- a/tests/active_item_test.cpp +++ b/tests/active_item_test.cpp @@ -3,7 +3,7 @@ #include "avatar.h" #include "calendar.h" -#include "catch/catch.hpp" +#include "cata_catch.h" #include "item.h" #include "map.h" #include "map_helpers.h" diff --git a/tests/activity_tracker_test.cpp b/tests/activity_tracker_test.cpp index e22e3a725daa5..3aeaf38ad981e 100644 --- a/tests/activity_tracker_test.cpp +++ b/tests/activity_tracker_test.cpp @@ -1,4 +1,4 @@ -#include "catch/catch.hpp" +#include "cata_catch.h" #include "activity_tracker.h" #include "calendar.h" diff --git a/tests/algo_test.cpp b/tests/algo_test.cpp index 73a7d42919d30..529955f1cb81b 100644 --- a/tests/algo_test.cpp +++ b/tests/algo_test.cpp @@ -1,6 +1,6 @@ #pragma GCC diagnostic ignored "-Wunused-macros" #define CATCH_CONFIG_ENABLE_PAIR_STRINGMAKER -#include "catch/catch.hpp" +#include "cata_catch.h" #include #include diff --git a/tests/ammo_set_test.cpp b/tests/ammo_set_test.cpp index b7958c2712706..84ce9572866ad 100644 --- a/tests/ammo_set_test.cpp +++ b/tests/ammo_set_test.cpp @@ -4,7 +4,7 @@ #include #include -#include "catch/catch.hpp" +#include "cata_catch.h" #include "debug.h" #include "item.h" #include "item_pocket.h" diff --git a/tests/ammo_test.cpp b/tests/ammo_test.cpp index d33472650edce..ba7544744dfb8 100644 --- a/tests/ammo_test.cpp +++ b/tests/ammo_test.cpp @@ -1,4 +1,4 @@ -#include "catch/catch.hpp" +#include "cata_catch.h" #include diff --git a/tests/archery_damage_test.cpp b/tests/archery_damage_test.cpp index 78f8a1d0cd2cf..34ee5ceeec6ba 100644 --- a/tests/archery_damage_test.cpp +++ b/tests/archery_damage_test.cpp @@ -16,7 +16,7 @@ #include #include -#include "catch/catch.hpp" +#include "cata_catch.h" #include "damage.h" #include "game_constants.h" #include "item.h" diff --git a/tests/assertion_helpers.h b/tests/assertion_helpers.h index b35d54f1bf433..f8cc5358a8187 100644 --- a/tests/assertion_helpers.h +++ b/tests/assertion_helpers.h @@ -2,7 +2,7 @@ #ifndef CATA_TESTS_ASSERTION_HELPERS_H #define CATA_TESTS_ASSERTION_HELPERS_H -#include "catch/catch.hpp" +#include "cata_catch.h" #include diff --git a/tests/battery_mod_test.cpp b/tests/battery_mod_test.cpp index c83f42d3b60b4..5f903de2f456b 100644 --- a/tests/battery_mod_test.cpp +++ b/tests/battery_mod_test.cpp @@ -7,7 +7,7 @@ #include #include "avatar.h" -#include "catch/catch.hpp" +#include "cata_catch.h" #include "debug.h" #include "item.h" #include "item_contents.h" diff --git a/tests/behavior_test.cpp b/tests/behavior_test.cpp index 145abed552152..b458c5ceb8385 100644 --- a/tests/behavior_test.cpp +++ b/tests/behavior_test.cpp @@ -6,7 +6,7 @@ #include "behavior.h" #include "behavior_strategy.h" -#include "catch/catch.hpp" +#include "cata_catch.h" #include "character_oracle.h" #include "item.h" #include "item_location.h" diff --git a/tests/bionics_test.cpp b/tests/bionics_test.cpp index 3474dd778715c..28f12d95e495b 100644 --- a/tests/bionics_test.cpp +++ b/tests/bionics_test.cpp @@ -7,7 +7,7 @@ #include "avatar.h" #include "bionics.h" #include "calendar.h" -#include "catch/catch.hpp" +#include "cata_catch.h" #include "item.h" #include "item_pocket.h" #include "npc.h" diff --git a/tests/calendar_test.cpp b/tests/calendar_test.cpp index 7ca3c60cbbb9d..925b3fe123c4a 100644 --- a/tests/calendar_test.cpp +++ b/tests/calendar_test.cpp @@ -2,7 +2,7 @@ #include #include "calendar.h" -#include "catch/catch.hpp" +#include "cata_catch.h" TEST_CASE( "time_duration_to_string", "[calendar]" ) { diff --git a/tests/cata_catch.h b/tests/cata_catch.h new file mode 100644 index 0000000000000..f03278aead309 --- /dev/null +++ b/tests/cata_catch.h @@ -0,0 +1,15 @@ +#pragma once +#ifndef CATA_TESTS_CATA_CATCH_H +#define CATA_TESTS_CATA_CATCH_H + +// To avoid ODR violations, it's important that whenever a file includes +// catch.hpp it also includes stringmaker.h, so that all specializations of +// StringMaker match. Therefore, all test code should include catch.hpp via +// this file. + +// IWYU pragma: begin_exports +#include "catch/catch.hpp" +#include "stringmaker.h" +// IWYU pragma: end_exports + +#endif // CATA_TESTS_CATA_CATCH_H diff --git a/tests/cata_generators.h b/tests/cata_generators.h index 85dbc1c6a0e9f..e6009f863ab90 100644 --- a/tests/cata_generators.h +++ b/tests/cata_generators.h @@ -4,7 +4,7 @@ // Some Catch2 Generators for generating our data types -#include "catch/catch.hpp" +#include "cata_catch.h" #include "game_constants.h" struct point; diff --git a/tests/cata_utility_test.cpp b/tests/cata_utility_test.cpp index bccb6b4c2bad0..50a32cb6fa466 100644 --- a/tests/cata_utility_test.cpp +++ b/tests/cata_utility_test.cpp @@ -9,7 +9,7 @@ #include "assertion_helpers.h" #include "cata_utility.h" -#include "catch/catch.hpp" +#include "cata_catch.h" #include "debug_menu.h" #include "units.h" #include "units_utility.h" diff --git a/tests/cata_variant_test.cpp b/tests/cata_variant_test.cpp index cf7ec3673d9d9..dc2637d3cdae5 100644 --- a/tests/cata_variant_test.cpp +++ b/tests/cata_variant_test.cpp @@ -3,7 +3,7 @@ #include #include "cata_variant.h" -#include "catch/catch.hpp" +#include "cata_catch.h" #include "character_id.h" #include "debug_menu.h" #include "enum_conversions.h" diff --git a/tests/catacharset_test.cpp b/tests/catacharset_test.cpp index 76c10fe23fba3..77545b40a581f 100644 --- a/tests/catacharset_test.cpp +++ b/tests/catacharset_test.cpp @@ -8,7 +8,7 @@ #include #include "catacharset.h" -#include "catch/catch.hpp" +#include "cata_catch.h" #include "translations.h" TEST_CASE( "utf8_width", "[catacharset]" ) diff --git a/tests/char_biometrics_test.cpp b/tests/char_biometrics_test.cpp index 5e9a395d91658..80625e3740036 100644 --- a/tests/char_biometrics_test.cpp +++ b/tests/char_biometrics_test.cpp @@ -4,7 +4,7 @@ #include "avatar.h" #include "calendar.h" -#include "catch/catch.hpp" +#include "cata_catch.h" #include "creature.h" #include "game_constants.h" #include "options.h" diff --git a/tests/char_edible_rating_test.cpp b/tests/char_edible_rating_test.cpp index 37cb87cea01f9..93d9e6594b0bb 100644 --- a/tests/char_edible_rating_test.cpp +++ b/tests/char_edible_rating_test.cpp @@ -4,7 +4,7 @@ #include "avatar.h" #include "calendar.h" -#include "catch/catch.hpp" +#include "cata_catch.h" #include "character.h" #include "flag.h" #include "item.h" diff --git a/tests/char_exposure_test.cpp b/tests/char_exposure_test.cpp index ce631de3dc86c..7e41c320379c2 100644 --- a/tests/char_exposure_test.cpp +++ b/tests/char_exposure_test.cpp @@ -2,7 +2,7 @@ #include #include -#include "catch/catch.hpp" +#include "cata_catch.h" #include "character.h" #include "item.h" #include "player_helpers.h" diff --git a/tests/char_healing_test.cpp b/tests/char_healing_test.cpp index d48aa99681517..98be7bd3b2f5d 100644 --- a/tests/char_healing_test.cpp +++ b/tests/char_healing_test.cpp @@ -2,7 +2,7 @@ #include "avatar.h" #include "calendar.h" -#include "catch/catch.hpp" +#include "cata_catch.h" #include "character.h" #include "options.h" #include "player.h" diff --git a/tests/char_sight_test.cpp b/tests/char_sight_test.cpp index 9f1e80477fa82..fe788b1bec57e 100644 --- a/tests/char_sight_test.cpp +++ b/tests/char_sight_test.cpp @@ -2,7 +2,7 @@ #include #include "calendar.h" -#include "catch/catch.hpp" +#include "cata_catch.h" #include "character.h" #include "flag.h" #include "game.h" diff --git a/tests/char_stamina_test.cpp b/tests/char_stamina_test.cpp index 62be669f530dc..b561e14d4f6a1 100644 --- a/tests/char_stamina_test.cpp +++ b/tests/char_stamina_test.cpp @@ -1,4 +1,4 @@ -#include "catch/catch.hpp" +#include "cata_catch.h" #include "calendar.h" #include "character.h" diff --git a/tests/char_suffer_test.cpp b/tests/char_suffer_test.cpp index 57bdadb2053e3..ceba9cc43c70d 100644 --- a/tests/char_suffer_test.cpp +++ b/tests/char_suffer_test.cpp @@ -7,7 +7,7 @@ #include "avatar.h" #include "calendar.h" -#include "catch/catch.hpp" +#include "cata_catch.h" #include "character.h" #include "creature.h" #include "flag.h" diff --git a/tests/char_validity_check_test.cpp b/tests/char_validity_check_test.cpp index e8b63149ffe1f..77425e53ab188 100644 --- a/tests/char_validity_check_test.cpp +++ b/tests/char_validity_check_test.cpp @@ -1,4 +1,4 @@ -#include "catch/catch.hpp" +#include "cata_catch.h" #include "char_validity_check.h" TEST_CASE( "char_validity_check" ) diff --git a/tests/clzones_test.cpp b/tests/clzones_test.cpp index d88f26996784f..ba98117dace0d 100644 --- a/tests/clzones_test.cpp +++ b/tests/clzones_test.cpp @@ -1,7 +1,7 @@ #include #include -#include "catch/catch.hpp" +#include "cata_catch.h" #include "clzones.h" #include "item.h" #include "item_category.h" diff --git a/tests/colony_test.cpp b/tests/colony_test.cpp index f210cd7e1f36a..45943c4bc29ba 100644 --- a/tests/colony_test.cpp +++ b/tests/colony_test.cpp @@ -4,7 +4,7 @@ #include #include // range-insert testing -#include "catch/catch.hpp" +#include "cata_catch.h" #include "colony.h" #include "colony_list_test_helpers.h" diff --git a/tests/comestible_test.cpp b/tests/comestible_test.cpp index c00c217ba7f4c..1975c0e40b3a8 100644 --- a/tests/comestible_test.cpp +++ b/tests/comestible_test.cpp @@ -8,7 +8,7 @@ #include #include -#include "catch/catch.hpp" +#include "cata_catch.h" #include "character.h" #include "item.h" #include "item_contents.h" diff --git a/tests/coordinate_test.cpp b/tests/coordinate_test.cpp index 80f1f1220579c..774fb7db8076f 100644 --- a/tests/coordinate_test.cpp +++ b/tests/coordinate_test.cpp @@ -4,7 +4,7 @@ #include #include "cata_generators.h" -#include "catch/catch.hpp" +#include "cata_catch.h" #include "coordinate_conversions.h" #include "coordinates.h" #include "point.h" diff --git a/tests/crafting_test.cpp b/tests/crafting_test.cpp index 5f040a7999c1b..f89f22e74f3b7 100644 --- a/tests/crafting_test.cpp +++ b/tests/crafting_test.cpp @@ -14,7 +14,7 @@ #include "avatar.h" #include "calendar.h" #include "cata_utility.h" -#include "catch/catch.hpp" +#include "cata_catch.h" #include "character.h" #include "game.h" #include "inventory.h" diff --git a/tests/creature_effect_test.cpp b/tests/creature_effect_test.cpp index 7b148b626e6d5..fa15b090bec9f 100644 --- a/tests/creature_effect_test.cpp +++ b/tests/creature_effect_test.cpp @@ -1,6 +1,6 @@ #include "avatar.h" #include "calendar.h" -#include "catch/catch.hpp" +#include "cata_catch.h" #include "monster.h" #include "mtype.h" #include "type_id.h" diff --git a/tests/creature_in_field_test.cpp b/tests/creature_in_field_test.cpp index 9838043d8d7a1..8bec189edfdee 100644 --- a/tests/creature_in_field_test.cpp +++ b/tests/creature_in_field_test.cpp @@ -1,4 +1,4 @@ -#include "catch/catch.hpp" +#include "cata_catch.h" #include "map.h" #include "map_helpers.h" #include "monster.h" diff --git a/tests/creature_test.cpp b/tests/creature_test.cpp index 8e37b9d108077..f8a7ffb2765da 100644 --- a/tests/creature_test.cpp +++ b/tests/creature_test.cpp @@ -3,7 +3,7 @@ #include #include "bodypart.h" -#include "catch/catch.hpp" +#include "cata_catch.h" #include "character.h" #include "creature.h" #include "enum_traits.h" diff --git a/tests/effect_test.cpp b/tests/effect_test.cpp index d0f691b89cc93..56f448e0a5990 100644 --- a/tests/effect_test.cpp +++ b/tests/effect_test.cpp @@ -4,7 +4,7 @@ #include #include "calendar.h" -#include "catch/catch.hpp" +#include "cata_catch.h" #include "character.h" #include "character_id.h" #include "damage.h" diff --git a/tests/effective_dps_test.cpp b/tests/effective_dps_test.cpp index 7c263f5bbf4e2..b1de9b8d8bf54 100644 --- a/tests/effective_dps_test.cpp +++ b/tests/effective_dps_test.cpp @@ -3,7 +3,7 @@ #include #include "avatar.h" -#include "catch/catch.hpp" +#include "cata_catch.h" #include "item.h" #include "melee.h" #include "monster.h" diff --git a/tests/enchantments_test.cpp b/tests/enchantments_test.cpp index e25833385fda0..e1e983347f6f0 100644 --- a/tests/enchantments_test.cpp +++ b/tests/enchantments_test.cpp @@ -1,5 +1,5 @@ #include "avatar.h" -#include "catch/catch.hpp" +#include "cata_catch.h" #include "field.h" #include "item.h" #include "item_location.h" diff --git a/tests/encumbrance_test.cpp b/tests/encumbrance_test.cpp index 61eec9fbab457..97d4c74d7b74e 100644 --- a/tests/encumbrance_test.cpp +++ b/tests/encumbrance_test.cpp @@ -5,7 +5,7 @@ #include #include "bodypart.h" -#include "catch/catch.hpp" +#include "cata_catch.h" #include "character.h" #include "item.h" #include "npc.h" diff --git a/tests/event_test.cpp b/tests/event_test.cpp index bc96b9f9057aa..2480ea3536b23 100644 --- a/tests/event_test.cpp +++ b/tests/event_test.cpp @@ -3,7 +3,7 @@ #include "calendar.h" #include "cata_variant.h" -#include "catch/catch.hpp" +#include "cata_catch.h" #include "character_id.h" #include "event.h" #include "event_bus.h" diff --git a/tests/explosion_balance_test.cpp b/tests/explosion_balance_test.cpp index a95c167f7f21e..d57cfd1ac3972 100644 --- a/tests/explosion_balance_test.cpp +++ b/tests/explosion_balance_test.cpp @@ -5,7 +5,7 @@ #include #include "avatar.h" -#include "catch/catch.hpp" +#include "cata_catch.h" #include "creature.h" #include "explosion.h" #include "game.h" diff --git a/tests/field_test.cpp b/tests/field_test.cpp index 61f5ee0ab0d04..f2050c4781796 100644 --- a/tests/field_test.cpp +++ b/tests/field_test.cpp @@ -3,7 +3,7 @@ #include "avatar.h" #include "calendar.h" -#include "catch/catch.hpp" +#include "cata_catch.h" #include "field.h" #include "field_type.h" #include "item.h" diff --git a/tests/flat_set_test.cpp b/tests/flat_set_test.cpp index d1c05285f11c0..e5fd16cebda3f 100644 --- a/tests/flat_set_test.cpp +++ b/tests/flat_set_test.cpp @@ -5,7 +5,7 @@ #include #include "assertion_helpers.h" -#include "catch/catch.hpp" +#include "cata_catch.h" #include "flat_set.h" #if 0 diff --git a/tests/focus_test.cpp b/tests/focus_test.cpp index 1f8d76e9d979b..d1f50cacca873 100644 --- a/tests/focus_test.cpp +++ b/tests/focus_test.cpp @@ -1,7 +1,7 @@ #include #include "avatar.h" -#include "catch/catch.hpp" +#include "cata_catch.h" #include "player_helpers.h" #include "skill.h" #include "type_id.h" diff --git a/tests/fold_string_test.cpp b/tests/fold_string_test.cpp index 3ec6dedceb897..35cd74cca7b48 100644 --- a/tests/fold_string_test.cpp +++ b/tests/fold_string_test.cpp @@ -1,4 +1,4 @@ -#include "catch/catch.hpp" +#include "cata_catch.h" #include #include diff --git a/tests/food_fun_for_test.cpp b/tests/food_fun_for_test.cpp index 9a8b861cb8926..740163f4dc7cb 100644 --- a/tests/food_fun_for_test.cpp +++ b/tests/food_fun_for_test.cpp @@ -4,7 +4,7 @@ #include "avatar.h" #include "calendar.h" -#include "catch/catch.hpp" +#include "cata_catch.h" #include "flag.h" #include "item.h" #include "itype.h" diff --git a/tests/generic_factory_test.cpp b/tests/generic_factory_test.cpp index 711668efe3f6d..321d3f2285f74 100644 --- a/tests/generic_factory_test.cpp +++ b/tests/generic_factory_test.cpp @@ -6,7 +6,7 @@ #include #include -#include "catch/catch.hpp" +#include "cata_catch.h" #include "colony_list_test_helpers.h" #include "flat_set.h" #include "generic_factory.h" diff --git a/tests/ground_destroy_test.cpp b/tests/ground_destroy_test.cpp index d00b0b88af5f8..52d922eba3236 100644 --- a/tests/ground_destroy_test.cpp +++ b/tests/ground_destroy_test.cpp @@ -2,7 +2,7 @@ #include #include "avatar.h" -#include "catch/catch.hpp" +#include "cata_catch.h" #include "item.h" #include "itype.h" #include "map.h" diff --git a/tests/hash_test.cpp b/tests/hash_test.cpp index 6fd981a276119..c912d82007a58 100644 --- a/tests/hash_test.cpp +++ b/tests/hash_test.cpp @@ -4,7 +4,7 @@ #include #include -#include "catch/catch.hpp" +#include "cata_catch.h" #include "point.h" // A larger number for this would be GREAT, but the test isn't efficient enough to make it larger. diff --git a/tests/health_test.cpp b/tests/health_test.cpp index ee314c2e32fbd..9ee73fea642f2 100644 --- a/tests/health_test.cpp +++ b/tests/health_test.cpp @@ -1,4 +1,4 @@ -#include "catch/catch.hpp" +#include "cata_catch.h" #include #include diff --git a/tests/iexamine_test.cpp b/tests/iexamine_test.cpp index a0f53f5be620b..9438eb5ae18bc 100644 --- a/tests/iexamine_test.cpp +++ b/tests/iexamine_test.cpp @@ -1,4 +1,4 @@ -#include "catch/catch.hpp" +#include "cata_catch.h" #include "iexamine.h" #include "mapdata.h" diff --git a/tests/invlet_test.cpp b/tests/invlet_test.cpp index be0fb49138c11..148d425a907c8 100644 --- a/tests/invlet_test.cpp +++ b/tests/invlet_test.cpp @@ -10,7 +10,7 @@ #include "activity_actor_definitions.h" #include "avatar.h" -#include "catch/catch.hpp" +#include "cata_catch.h" #include "inventory.h" #include "item.h" #include "item_location.h" diff --git a/tests/item_contents_test.cpp b/tests/item_contents_test.cpp index 72da9133a96e3..17cf135c4a004 100644 --- a/tests/item_contents_test.cpp +++ b/tests/item_contents_test.cpp @@ -1,6 +1,6 @@ #include -#include "catch/catch.hpp" +#include "cata_catch.h" #include "item.h" #include "item_contents.h" #include "item_pocket.h" diff --git a/tests/item_group_test.cpp b/tests/item_group_test.cpp index 50fb442229de6..9ffa89d7d6704 100644 --- a/tests/item_group_test.cpp +++ b/tests/item_group_test.cpp @@ -6,7 +6,7 @@ #include #include -#include "catch/catch.hpp" +#include "cata_catch.h" #include "flag.h" #include "item.h" #include "item_contents.h" diff --git a/tests/item_location_test.cpp b/tests/item_location_test.cpp index 16c1fc0121187..814aa8dd72cda 100644 --- a/tests/item_location_test.cpp +++ b/tests/item_location_test.cpp @@ -2,7 +2,7 @@ #include #include -#include "catch/catch.hpp" +#include "cata_catch.h" #include "character.h" #include "item.h" #include "item_contents.h" diff --git a/tests/item_stackable_test.cpp b/tests/item_stackable_test.cpp index 098d56eeba4f3..c410e31bcd249 100644 --- a/tests/item_stackable_test.cpp +++ b/tests/item_stackable_test.cpp @@ -2,7 +2,7 @@ #include #include -#include "catch/catch.hpp" +#include "cata_catch.h" #include "item_factory.h" #include "itype.h" #include "type_id.h" diff --git a/tests/item_test.cpp b/tests/item_test.cpp index 33d820e3fc765..0c7614ebf5308 100644 --- a/tests/item_test.cpp +++ b/tests/item_test.cpp @@ -1,4 +1,4 @@ -#include "catch/catch.hpp" +#include "cata_catch.h" #include "item.h" #include diff --git a/tests/item_tname_test.cpp b/tests/item_tname_test.cpp index 0bd11764836e1..85428439d247c 100644 --- a/tests/item_tname_test.cpp +++ b/tests/item_tname_test.cpp @@ -4,7 +4,7 @@ #include #include "calendar.h" -#include "catch/catch.hpp" +#include "cata_catch.h" #include "character.h" #include "flag.h" #include "item.h" diff --git a/tests/item_type_name_test.cpp b/tests/item_type_name_test.cpp index be6bd8468821e..d1aece474e16f 100644 --- a/tests/item_type_name_test.cpp +++ b/tests/item_type_name_test.cpp @@ -2,7 +2,7 @@ #include #include "calendar.h" -#include "catch/catch.hpp" +#include "cata_catch.h" #include "item.h" #include "type_id.h" diff --git a/tests/iteminfo_test.cpp b/tests/iteminfo_test.cpp index 133c2d123dcbb..7c3a238772d75 100644 --- a/tests/iteminfo_test.cpp +++ b/tests/iteminfo_test.cpp @@ -8,7 +8,7 @@ #include "avatar.h" #include "bodypart.h" #include "calendar.h" -#include "catch/catch.hpp" +#include "cata_catch.h" #include "character.h" #include "flag.h" #include "item.h" @@ -20,7 +20,6 @@ #include "player_helpers.h" #include "recipe.h" #include "recipe_dictionary.h" -#include "stringmaker.h" // IWYU pragma: keep #include "type_id.h" #include "units.h" #include "value_ptr.h" @@ -658,10 +657,10 @@ static std::vector bodyparts_to_check() static void verify_item_coverage( const item &i, const std::map &expected ) { - CAPTURE( i.typeId().str() ); + CAPTURE( i.typeId() ); REQUIRE( i.get_covered_body_parts().any() ); for( const bodypart_id &bp : bodyparts_to_check() ) { - CAPTURE( bp.id().str() ); + CAPTURE( bp.id() ); REQUIRE( i.get_coverage( bp ) == expected.at( bp ) ); } } @@ -669,10 +668,10 @@ static void verify_item_coverage( const item &i, const std::map &expected ) { - CAPTURE( i.typeId().str() ); + CAPTURE( i.typeId() ); REQUIRE( i.get_avg_encumber( get_player_character(), flags ) == average ); for( const bodypart_id &bp : bodyparts_to_check() ) { - CAPTURE( bp.id().str() ); + CAPTURE( bp.id() ); REQUIRE( i.get_encumber( get_player_character(), bp, flags ) == expected.at( bp ) ); } } diff --git a/tests/itemname_test.cpp b/tests/itemname_test.cpp index 3ebd49c418019..d080e29ecaa60 100644 --- a/tests/itemname_test.cpp +++ b/tests/itemname_test.cpp @@ -3,7 +3,7 @@ #include #include "calendar.h" -#include "catch/catch.hpp" +#include "cata_catch.h" #include "character.h" #include "flag.h" #include "item.h" diff --git a/tests/iuse_actor_test.cpp b/tests/iuse_actor_test.cpp index f65e19a4edf61..0c86943101502 100644 --- a/tests/iuse_actor_test.cpp +++ b/tests/iuse_actor_test.cpp @@ -8,7 +8,7 @@ #include "avatar.h" #include "calendar.h" -#include "catch/catch.hpp" +#include "cata_catch.h" #include "colony.h" #include "game.h" #include "item.h" diff --git a/tests/iuse_test.cpp b/tests/iuse_test.cpp index 43f49654d56bb..00e66b1a820dd 100644 --- a/tests/iuse_test.cpp +++ b/tests/iuse_test.cpp @@ -5,7 +5,7 @@ #include "avatar.h" #include "calendar.h" -#include "catch/catch.hpp" +#include "cata_catch.h" #include "flag.h" #include "item.h" #include "itype.h" diff --git a/tests/json_test.cpp b/tests/json_test.cpp index 99985e66e6aec..1f31ca0671f41 100644 --- a/tests/json_test.cpp +++ b/tests/json_test.cpp @@ -13,7 +13,7 @@ #include "bodypart.h" #include "cached_options.h" #include "cata_utility.h" -#include "catch/catch.hpp" +#include "cata_catch.h" #include "colony.h" #include "damage.h" #include "debug.h" diff --git a/tests/line_test.cpp b/tests/line_test.cpp index c4a34d5fb8822..0efa68e05ad52 100644 --- a/tests/line_test.cpp +++ b/tests/line_test.cpp @@ -9,7 +9,7 @@ #include #include "cata_generators.h" -#include "catch/catch.hpp" +#include "cata_catch.h" #include "coordinates.h" #include "line.h" #include "point.h" diff --git a/tests/list_test.cpp b/tests/list_test.cpp index 258b9d2ce1546..8c9327ef21a43 100644 --- a/tests/list_test.cpp +++ b/tests/list_test.cpp @@ -6,7 +6,7 @@ #include #include // range-insert testing -#include "catch/catch.hpp" +#include "cata_catch.h" #include "colony_list_test_helpers.h" #include "list.h" diff --git a/tests/magic_spell_effect_test.cpp b/tests/magic_spell_effect_test.cpp index db5ce789c30fe..842953eafddc0 100644 --- a/tests/magic_spell_effect_test.cpp +++ b/tests/magic_spell_effect_test.cpp @@ -1,7 +1,7 @@ #include #include -#include "catch/catch.hpp" +#include "cata_catch.h" #include "json.h" #include "magic.h" #include "magic_spell_effect_helpers.h" diff --git a/tests/magic_spell_test.cpp b/tests/magic_spell_test.cpp index 5654f69369bb3..cc2835ffcf6c6 100644 --- a/tests/magic_spell_test.cpp +++ b/tests/magic_spell_test.cpp @@ -3,7 +3,7 @@ #include #include "avatar.h" -#include "catch/catch.hpp" +#include "cata_catch.h" #include "game.h" #include "magic.h" #include "map_helpers.h" diff --git a/tests/make_static_test.cpp b/tests/make_static_test.cpp index a8f9fbf2590c7..7409f412b85c9 100644 --- a/tests/make_static_test.cpp +++ b/tests/make_static_test.cpp @@ -2,7 +2,7 @@ #include #include -#include "catch/catch.hpp" +#include "cata_catch.h" #include "make_static.h" #include "string_id.h" diff --git a/tests/map_extra_test.cpp b/tests/map_extra_test.cpp index 263acc80c8c2b..79cedaa631f94 100644 --- a/tests/map_extra_test.cpp +++ b/tests/map_extra_test.cpp @@ -4,7 +4,7 @@ #include #include -#include "catch/catch.hpp" +#include "cata_catch.h" #include "coordinates.h" #include "enums.h" #include "map.h" diff --git a/tests/map_iterator_test.cpp b/tests/map_iterator_test.cpp index 7b1706e0eb3c0..4d701f3d0a928 100644 --- a/tests/map_iterator_test.cpp +++ b/tests/map_iterator_test.cpp @@ -1,4 +1,4 @@ -#include "catch/catch.hpp" +#include "cata_catch.h" #include #include diff --git a/tests/map_memory_test.cpp b/tests/map_memory_test.cpp index 993fdb1995964..fcc28128043ea 100644 --- a/tests/map_memory_test.cpp +++ b/tests/map_memory_test.cpp @@ -3,7 +3,7 @@ #include #include -#include "catch/catch.hpp" +#include "cata_catch.h" #include "game_constants.h" #include "json.h" #include "lru_cache.h" diff --git a/tests/map_test.cpp b/tests/map_test.cpp index 38c0ab96bc28f..57300e9dda09c 100644 --- a/tests/map_test.cpp +++ b/tests/map_test.cpp @@ -1,4 +1,4 @@ -#include "catch/catch.hpp" +#include "cata_catch.h" #include "map.h" #include diff --git a/tests/map_test_case.h b/tests/map_test_case.h index 3f31cbc71fff7..7bbf8f4937d99 100644 --- a/tests/map_test_case.h +++ b/tests/map_test_case.h @@ -7,7 +7,7 @@ #include #include -#include "catch/catch.hpp" +#include "cata_catch.h" #include "map.h" #include "mapdata.h" #include "optional.h" diff --git a/tests/mapgen_function_test.cpp b/tests/mapgen_function_test.cpp index 0334b2a92a364..943d87116b3a3 100644 --- a/tests/mapgen_function_test.cpp +++ b/tests/mapgen_function_test.cpp @@ -1,4 +1,4 @@ -#include "catch/catch.hpp" +#include "cata_catch.h" #include "mapgen.h" #include "type_id.h" diff --git a/tests/math_functions_test.cpp b/tests/math_functions_test.cpp index 7cbeb9b8bf757..69422d33e0e36 100644 --- a/tests/math_functions_test.cpp +++ b/tests/math_functions_test.cpp @@ -1,4 +1,4 @@ -#include "catch/catch.hpp" +#include "cata_catch.h" #include #include diff --git a/tests/melee_dodge_hit_test.cpp b/tests/melee_dodge_hit_test.cpp index eb683648d3e84..fa100edb8a735 100644 --- a/tests/melee_dodge_hit_test.cpp +++ b/tests/melee_dodge_hit_test.cpp @@ -4,7 +4,7 @@ #include "avatar.h" #include "calendar.h" -#include "catch/catch.hpp" +#include "cata_catch.h" #include "creature.h" #include "flag.h" #include "game.h" diff --git a/tests/melee_test.cpp b/tests/melee_test.cpp index f40e68d9c5bd9..d9da5a05602b9 100644 --- a/tests/melee_test.cpp +++ b/tests/melee_test.cpp @@ -3,7 +3,7 @@ #include #include "calendar.h" -#include "catch/catch.hpp" +#include "cata_catch.h" #include "creature.h" #include "game_constants.h" #include "item.h" diff --git a/tests/memorial_test.cpp b/tests/memorial_test.cpp index 01c0727fa17dd..eb8d06f3cc1ec 100644 --- a/tests/memorial_test.cpp +++ b/tests/memorial_test.cpp @@ -9,7 +9,7 @@ #include "achievement.h" #include "avatar.h" #include "bodypart.h" -#include "catch/catch.hpp" +#include "cata_catch.h" #include "character_id.h" #include "debug_menu.h" #include "event.h" diff --git a/tests/modify_morale_test.cpp b/tests/modify_morale_test.cpp index 1651644d9f35f..a60d643e03f00 100644 --- a/tests/modify_morale_test.cpp +++ b/tests/modify_morale_test.cpp @@ -6,7 +6,7 @@ #include #include "avatar.h" -#include "catch/catch.hpp" +#include "cata_catch.h" #include "flag.h" #include "item.h" #include "item_contents.h" diff --git a/tests/mondefense_test.cpp b/tests/mondefense_test.cpp index 26363f0587aca..fcc2691daf582 100644 --- a/tests/mondefense_test.cpp +++ b/tests/mondefense_test.cpp @@ -1,4 +1,4 @@ -#include "catch/catch.hpp" +#include "cata_catch.h" #include "creature.h" #include "item.h" diff --git a/tests/monfactions_test.cpp b/tests/monfactions_test.cpp index af64e6cce353b..8e10516a32245 100644 --- a/tests/monfactions_test.cpp +++ b/tests/monfactions_test.cpp @@ -1,7 +1,7 @@ #include #include -#include "catch/catch.hpp" +#include "cata_catch.h" #include "monfaction.h" #include "type_id.h" diff --git a/tests/monster_attack_test.cpp b/tests/monster_attack_test.cpp index 7e9159d0d5463..6c1bb9051d833 100644 --- a/tests/monster_attack_test.cpp +++ b/tests/monster_attack_test.cpp @@ -3,7 +3,7 @@ #include "cached_options.h" #include "calendar.h" -#include "catch/catch.hpp" +#include "cata_catch.h" #include "character.h" #include "game.h" #include "line.h" diff --git a/tests/monster_test.cpp b/tests/monster_test.cpp index 3e391a9e27f01..68983eeb63016 100644 --- a/tests/monster_test.cpp +++ b/tests/monster_test.cpp @@ -10,7 +10,7 @@ #include #include "cata_utility.h" -#include "catch/catch.hpp" +#include "cata_catch.h" #include "character.h" #include "game.h" #include "game_constants.h" diff --git a/tests/monster_vision_test.cpp b/tests/monster_vision_test.cpp index 6785a193bdf53..6fb433b48b7a3 100644 --- a/tests/monster_vision_test.cpp +++ b/tests/monster_vision_test.cpp @@ -1,6 +1,6 @@ #include "cached_options.h" #include "calendar.h" -#include "catch/catch.hpp" +#include "cata_catch.h" #include "map.h" #include "map_helpers.h" #include "mapdata.h" diff --git a/tests/moon_test.cpp b/tests/moon_test.cpp index 65d7c14aae968..55ef7e7bd8f3a 100644 --- a/tests/moon_test.cpp +++ b/tests/moon_test.cpp @@ -2,7 +2,7 @@ #include #include "calendar.h" -#include "catch/catch.hpp" +#include "cata_catch.h" #include "enum_conversions.h" // MOON TESTS diff --git a/tests/morale_test.cpp b/tests/morale_test.cpp index a43425f496253..2e59f0189d245 100644 --- a/tests/morale_test.cpp +++ b/tests/morale_test.cpp @@ -1,4 +1,4 @@ -#include "catch/catch.hpp" +#include "cata_catch.h" #include "bodypart.h" #include "item.h" diff --git a/tests/mutation_test.cpp b/tests/mutation_test.cpp index 96cec2e7de7fb..8997db26b78a5 100644 --- a/tests/mutation_test.cpp +++ b/tests/mutation_test.cpp @@ -4,7 +4,7 @@ #include #include -#include "catch/catch.hpp" +#include "cata_catch.h" #include "character.h" #include "mutation.h" #include "npc.h" diff --git a/tests/name_test.cpp b/tests/name_test.cpp index 1f525c93384c9..a6c7c6168b671 100644 --- a/tests/name_test.cpp +++ b/tests/name_test.cpp @@ -2,7 +2,7 @@ #include #include -#include "catch/catch.hpp" +#include "cata_catch.h" #include "enum_traits.h" #include "name.h" diff --git a/tests/new_character_test.cpp b/tests/new_character_test.cpp index 6a1ac5e14cf5d..579699eb3c47d 100644 --- a/tests/new_character_test.cpp +++ b/tests/new_character_test.cpp @@ -10,14 +10,13 @@ #include #include "avatar.h" -#include "catch/catch.hpp" +#include "cata_catch.h" #include "inventory.h" #include "item.h" #include "pimpl.h" #include "profession.h" #include "scenario.h" #include "string_formatter.h" -#include "stringmaker.h" // IWYU pragma: keep #include "type_id.h" #include "visitable.h" diff --git a/tests/npc_talk_test.cpp b/tests/npc_talk_test.cpp index 8da6c8e8a311c..5a5a9ef7d5d34 100644 --- a/tests/npc_talk_test.cpp +++ b/tests/npc_talk_test.cpp @@ -8,7 +8,7 @@ #include "avatar.h" #include "calendar.h" -#include "catch/catch.hpp" +#include "cata_catch.h" #include "character.h" #include "character_id.h" #include "coordinate_conversions.h" diff --git a/tests/npc_test.cpp b/tests/npc_test.cpp index 178747affd4fd..9ddd6e13526a0 100644 --- a/tests/npc_test.cpp +++ b/tests/npc_test.cpp @@ -7,7 +7,7 @@ #include #include "calendar.h" -#include "catch/catch.hpp" +#include "cata_catch.h" #include "character.h" #include "common_types.h" #include "faction.h" diff --git a/tests/optional_test.cpp b/tests/optional_test.cpp index ce0d6b575925b..3e72261b5d85e 100644 --- a/tests/optional_test.cpp +++ b/tests/optional_test.cpp @@ -1,7 +1,7 @@ #include #include -#include "catch/catch.hpp" +#include "cata_catch.h" #include "optional.h" TEST_CASE( "optional_assignment_works", "[optional]" ) diff --git a/tests/overmap_noise_test.cpp b/tests/overmap_noise_test.cpp index 979340ddd7ef4..7df43907f4295 100644 --- a/tests/overmap_noise_test.cpp +++ b/tests/overmap_noise_test.cpp @@ -1,6 +1,6 @@ #include -#include "catch/catch.hpp" +#include "cata_catch.h" #include "coordinates.h" #include "game_constants.h" #include "overmap_noise.h" diff --git a/tests/overmap_test.cpp b/tests/overmap_test.cpp index 9435dab132c36..ce609cbb1e69c 100644 --- a/tests/overmap_test.cpp +++ b/tests/overmap_test.cpp @@ -2,7 +2,7 @@ #include #include "calendar.h" -#include "catch/catch.hpp" +#include "cata_catch.h" #include "common_types.h" #include "coordinates.h" #include "enums.h" diff --git a/tests/player_helpers.cpp b/tests/player_helpers.cpp index 58dc5de7b4914..2442d881cca55 100644 --- a/tests/player_helpers.cpp +++ b/tests/player_helpers.cpp @@ -7,7 +7,7 @@ #include "avatar.h" #include "bionics.h" -#include "catch/catch.hpp" +#include "cata_catch.h" #include "character.h" #include "character_id.h" #include "character_martial_arts.h" diff --git a/tests/player_test.cpp b/tests/player_test.cpp index 584e7b54febe6..612a8a5b9e11f 100644 --- a/tests/player_test.cpp +++ b/tests/player_test.cpp @@ -3,7 +3,7 @@ #include #include "calendar.h" -#include "catch/catch.hpp" +#include "cata_catch.h" #include "character.h" #include "item.h" #include "type_id.h" diff --git a/tests/pocket_test.cpp b/tests/pocket_test.cpp index aa9e60002b537..e97efc2e7b938 100644 --- a/tests/pocket_test.cpp +++ b/tests/pocket_test.cpp @@ -8,7 +8,7 @@ #include #include "calendar.h" -#include "catch/catch.hpp" +#include "cata_catch.h" #include "debug.h" #include "enums.h" #include "flag.h" diff --git a/tests/point_test.cpp b/tests/point_test.cpp index c657ddd6ebba8..33a510f5b04f5 100644 --- a/tests/point_test.cpp +++ b/tests/point_test.cpp @@ -2,7 +2,7 @@ #include #include -#include "catch/catch.hpp" +#include "cata_catch.h" #include "coordinates.h" #include "cuboid_rectangle.h" #include "point.h" diff --git a/tests/projectile_test.cpp b/tests/projectile_test.cpp index 9d7793498d95f..7e3efc0fcc83c 100644 --- a/tests/projectile_test.cpp +++ b/tests/projectile_test.cpp @@ -5,7 +5,7 @@ #include #include "ballistics.h" -#include "catch/catch.hpp" +#include "cata_catch.h" #include "character.h" #include "damage.h" #include "dispersion.h" diff --git a/tests/ranged_balance_test.cpp b/tests/ranged_balance_test.cpp index 7d7b8b9bf838a..b4623a4b9ccec 100644 --- a/tests/ranged_balance_test.cpp +++ b/tests/ranged_balance_test.cpp @@ -11,7 +11,7 @@ #include "bodypart.h" #include "calendar.h" #include "cata_utility.h" -#include "catch/catch.hpp" +#include "cata_catch.h" #include "creature.h" #include "dispersion.h" #include "game_constants.h" diff --git a/tests/reachability_cache_test.cpp b/tests/reachability_cache_test.cpp index f6defcb9747ee..c5ec897f7d30f 100644 --- a/tests/reachability_cache_test.cpp +++ b/tests/reachability_cache_test.cpp @@ -4,7 +4,7 @@ #include #include "cached_options.h" -#include "catch/catch.hpp" +#include "cata_catch.h" #include "map.h" #include "map_helpers.h" #include "map_iterator.h" diff --git a/tests/reading_test.cpp b/tests/reading_test.cpp index b2f6c48e20af6..8f6a45c8c219d 100644 --- a/tests/reading_test.cpp +++ b/tests/reading_test.cpp @@ -6,7 +6,7 @@ #include "avatar.h" #include "calendar.h" -#include "catch/catch.hpp" +#include "cata_catch.h" #include "character.h" #include "item.h" #include "itype.h" diff --git a/tests/recipe_test.cpp b/tests/recipe_test.cpp index 4cc53a1996901..49e3e1907329a 100644 --- a/tests/recipe_test.cpp +++ b/tests/recipe_test.cpp @@ -2,7 +2,7 @@ #include #include "calendar.h" -#include "catch/catch.hpp" +#include "cata_catch.h" #include "character.h" #include "json.h" #include "recipe.h" diff --git a/tests/reload_magazine_test.cpp b/tests/reload_magazine_test.cpp index fa929364d170a..76fb218827abd 100644 --- a/tests/reload_magazine_test.cpp +++ b/tests/reload_magazine_test.cpp @@ -6,7 +6,7 @@ #include "avatar.h" #include "calendar.h" -#include "catch/catch.hpp" +#include "cata_catch.h" #include "character.h" #include "inventory.h" #include "item.h" diff --git a/tests/reload_option_test.cpp b/tests/reload_option_test.cpp index cd894ee6cc95d..6778426537b93 100644 --- a/tests/reload_option_test.cpp +++ b/tests/reload_option_test.cpp @@ -3,7 +3,7 @@ #include "avatar.h" #include "calendar.h" -#include "catch/catch.hpp" +#include "cata_catch.h" #include "item.h" #include "item_location.h" #include "item_pocket.h" diff --git a/tests/reloading_test.cpp b/tests/reloading_test.cpp index 29ab9e5895add..f75d39fbcf676 100644 --- a/tests/reloading_test.cpp +++ b/tests/reloading_test.cpp @@ -6,7 +6,7 @@ #include "avatar.h" #include "calendar.h" -#include "catch/catch.hpp" +#include "cata_catch.h" #include "game.h" #include "item.h" #include "item_contents.h" diff --git a/tests/requirements_test.cpp b/tests/requirements_test.cpp index 367d97cf893f4..eb73a620fa326 100644 --- a/tests/requirements_test.cpp +++ b/tests/requirements_test.cpp @@ -3,7 +3,7 @@ #include #include -#include "catch/catch.hpp" +#include "cata_catch.h" #include "requirements.h" #include "type_id.h" diff --git a/tests/rewrite_vsnprintf_test.cpp b/tests/rewrite_vsnprintf_test.cpp index 69a83f49b5fe1..f1e17ae8cc29e 100644 --- a/tests/rewrite_vsnprintf_test.cpp +++ b/tests/rewrite_vsnprintf_test.cpp @@ -3,7 +3,7 @@ #include // the rewrite_vsnprintf function is explicitly defined for non-MS compilers in output.cpp -#include "catch/catch.hpp" +#include "cata_catch.h" #include "output.h" TEST_CASE( "Test vsnprintf_rewrite" ) diff --git a/tests/rng_test.cpp b/tests/rng_test.cpp index ff2fcafc7a734..c19277b1ad77e 100644 --- a/tests/rng_test.cpp +++ b/tests/rng_test.cpp @@ -1,7 +1,7 @@ #include #include -#include "catch/catch.hpp" +#include "cata_catch.h" #include "optional.h" #include "rng.h" #include "test_statistics.h" diff --git a/tests/rot_test.cpp b/tests/rot_test.cpp index 4a9bd41abf721..3eb05e471575b 100644 --- a/tests/rot_test.cpp +++ b/tests/rot_test.cpp @@ -1,5 +1,5 @@ #include "calendar.h" -#include "catch/catch.hpp" +#include "cata_catch.h" #include "enums.h" #include "item.h" #include "point.h" diff --git a/tests/safe_reference_test.cpp b/tests/safe_reference_test.cpp index a0b7681a8793e..2b0589073509f 100644 --- a/tests/safe_reference_test.cpp +++ b/tests/safe_reference_test.cpp @@ -1,4 +1,4 @@ -#include "catch/catch.hpp" +#include "cata_catch.h" #include diff --git a/tests/shadowcasting_test.cpp b/tests/shadowcasting_test.cpp index a5813893e3cd4..c5c04c1368789 100644 --- a/tests/shadowcasting_test.cpp +++ b/tests/shadowcasting_test.cpp @@ -7,7 +7,7 @@ #include #include -#include "catch/catch.hpp" +#include "cata_catch.h" #include "cuboid_rectangle.h" #include "game_constants.h" #include "level_cache.h" diff --git a/tests/simple_pathfinding_test.cpp b/tests/simple_pathfinding_test.cpp index 617ed3a8121e5..621d756ed6c1c 100644 --- a/tests/simple_pathfinding_test.cpp +++ b/tests/simple_pathfinding_test.cpp @@ -1,4 +1,4 @@ -#include "catch/catch.hpp" +#include "cata_catch.h" #include "simple_pathfinding.h" #include "coordinates.h" diff --git a/tests/stats_tracker_test.cpp b/tests/stats_tracker_test.cpp index 3519444cb965a..3f1289b6a46f1 100644 --- a/tests/stats_tracker_test.cpp +++ b/tests/stats_tracker_test.cpp @@ -1,4 +1,4 @@ -#include "catch/catch.hpp" +#include "cata_catch.h" #include "stats_tracker.h" #include diff --git a/tests/stomach_contents_test.cpp b/tests/stomach_contents_test.cpp index f28cb10819775..90680b265b9bc 100644 --- a/tests/stomach_contents_test.cpp +++ b/tests/stomach_contents_test.cpp @@ -4,7 +4,7 @@ #include "avatar.h" #include "calendar.h" -#include "catch/catch.hpp" +#include "cata_catch.h" #include "character.h" #include "item.h" #include "player.h" diff --git a/tests/string_formatter_test.cpp b/tests/string_formatter_test.cpp index 18f2fae922e4a..badd7eed5d87f 100644 --- a/tests/string_formatter_test.cpp +++ b/tests/string_formatter_test.cpp @@ -4,7 +4,7 @@ #include #include -#include "catch/catch.hpp" +#include "cata_catch.h" #include "string_formatter.h" // Same as @ref string_format, but does not swallow errors and throws them instead. diff --git a/tests/string_ids_test.cpp b/tests/string_ids_test.cpp index c3e7957968273..5cc963592b0f4 100644 --- a/tests/string_ids_test.cpp +++ b/tests/string_ids_test.cpp @@ -6,7 +6,7 @@ #include #include -#include "catch/catch.hpp" +#include "cata_catch.h" #include "field_type.h" #include "string_id_utils.h" #include "type_id.h" diff --git a/tests/string_test.cpp b/tests/string_test.cpp index b998ada26c14c..7dab191d90caa 100644 --- a/tests/string_test.cpp +++ b/tests/string_test.cpp @@ -1,7 +1,7 @@ #include #include -#include "catch/catch.hpp" +#include "cata_catch.h" #include "output.h" static void test_remove_color_tags( const std::string &original, const std::string &expected ) diff --git a/tests/stringmaker.h b/tests/stringmaker.h index d5c6938869512..d0eac3c374539 100644 --- a/tests/stringmaker.h +++ b/tests/stringmaker.h @@ -3,7 +3,7 @@ #define CATA_TESTS_STRINGMAKER_H #include "cuboid_rectangle.h" -#include "catch/catch.hpp" +#include "cata_catch.h" #include "cata_variant.h" #include "dialogue.h" #include "item.h" diff --git a/tests/submap_load_test.cpp b/tests/submap_load_test.cpp index 5493f52efba1e..00fa6290ae26a 100644 --- a/tests/submap_load_test.cpp +++ b/tests/submap_load_test.cpp @@ -7,7 +7,7 @@ #include #include "calendar.h" -#include "catch/catch.hpp" +#include "cata_catch.h" #include "colony.h" #include "construction.h" #include "field.h" diff --git a/tests/submap_test.cpp b/tests/submap_test.cpp index 2d63ec3b1120b..e38f81d375d88 100644 --- a/tests/submap_test.cpp +++ b/tests/submap_test.cpp @@ -1,4 +1,4 @@ -#include "catch/catch.hpp" +#include "cata_catch.h" #include "submap.h" #include "game_constants.h" diff --git a/tests/sun_test.cpp b/tests/sun_test.cpp index 7c067532b3464..5ffbe45abb807 100644 --- a/tests/sun_test.cpp +++ b/tests/sun_test.cpp @@ -1,4 +1,4 @@ -#include "catch/catch.hpp" +#include "cata_catch.h" #include "calendar.h" // IWYU pragma: associated #include diff --git a/tests/temp_crafting_inv_test.cpp b/tests/temp_crafting_inv_test.cpp index 7e91aeca5145a..0d9da91e815b7 100644 --- a/tests/temp_crafting_inv_test.cpp +++ b/tests/temp_crafting_inv_test.cpp @@ -1,6 +1,6 @@ #include "../src/temp_crafting_inventory.h" #include "calendar.h" -#include "catch/catch.hpp" +#include "cata_catch.h" #include "item.h" #include "type_id.h" diff --git a/tests/temperature_test.cpp b/tests/temperature_test.cpp index 24d1677b61e6f..c18262d9c49cf 100644 --- a/tests/temperature_test.cpp +++ b/tests/temperature_test.cpp @@ -1,6 +1,6 @@ #include "calendar.h" #include "cata_utility.h" -#include "catch/catch.hpp" +#include "cata_catch.h" #include "enums.h" #include "flag.h" #include "game_constants.h" diff --git a/tests/test_main.cpp b/tests/test_main.cpp index a53e34208d546..f8c37bdbc2a29 100644 --- a/tests/test_main.cpp +++ b/tests/test_main.cpp @@ -17,7 +17,7 @@ #include #include "calendar.h" -#include "catch/catch.hpp" +#include "cata_catch.h" #include "coordinates.h" #ifndef _WIN32 #include diff --git a/tests/test_statistics.h b/tests/test_statistics.h index 03d59f0224040..9d5f99b18ad1c 100644 --- a/tests/test_statistics.h +++ b/tests/test_statistics.h @@ -9,7 +9,7 @@ #include #include -#include "catch/catch.hpp" +#include "cata_catch.h" // Z-value for confidence interval constexpr double Z95 = 1.96; diff --git a/tests/text_snippets_test.cpp b/tests/text_snippets_test.cpp index 8c6a6f50921ec..b5b98d70f580e 100644 --- a/tests/text_snippets_test.cpp +++ b/tests/text_snippets_test.cpp @@ -1,6 +1,6 @@ #include -#include "catch/catch.hpp" +#include "cata_catch.h" #include "optional.h" #include "text_snippets.h" #include "translations.h" diff --git a/tests/throwing_test.cpp b/tests/throwing_test.cpp index 4072d08fced58..3d947e1d66eec 100644 --- a/tests/throwing_test.cpp +++ b/tests/throwing_test.cpp @@ -5,7 +5,7 @@ #include "avatar.h" #include "calendar.h" -#include "catch/catch.hpp" +#include "cata_catch.h" #include "damage.h" #include "game.h" #include "game_constants.h" diff --git a/tests/translations_test.cpp b/tests/translations_test.cpp index 5293be188d3b4..c8516298de3e9 100644 --- a/tests/translations_test.cpp +++ b/tests/translations_test.cpp @@ -2,7 +2,7 @@ #include #include -#include "catch/catch.hpp" +#include "cata_catch.h" #include "translations.h" // wrapping in another macro to prevent collection of the test string for translation diff --git a/tests/try_parse_integer_test.cpp b/tests/try_parse_integer_test.cpp index 5136e2541bcd6..a40e9f48428b9 100644 --- a/tests/try_parse_integer_test.cpp +++ b/tests/try_parse_integer_test.cpp @@ -1,4 +1,4 @@ -#include "catch/catch.hpp" +#include "cata_catch.h" #include "try_parse_integer.h" TEMPLATE_TEST_CASE( "try_parse_int_simple_parsing", "[try_parse_integer]", int, long, long long ) diff --git a/tests/units_test.cpp b/tests/units_test.cpp index 0af40be98d23e..b849df756939a 100644 --- a/tests/units_test.cpp +++ b/tests/units_test.cpp @@ -4,7 +4,7 @@ #include "calendar.h" #include "cata_utility.h" -#include "catch/catch.hpp" +#include "cata_catch.h" #include "json.h" #include "math_defines.h" #include "options_helpers.h" diff --git a/tests/unseal_and_spill_test.cpp b/tests/unseal_and_spill_test.cpp index 6fdcacdde764f..a3cd35838942c 100644 --- a/tests/unseal_and_spill_test.cpp +++ b/tests/unseal_and_spill_test.cpp @@ -9,7 +9,7 @@ #include "avatar.h" #include "cached_options.h" -#include "catch/catch.hpp" +#include "cata_catch.h" #include "character.h" #include "colony.h" #include "item.h" diff --git a/tests/value_ptr_test.cpp b/tests/value_ptr_test.cpp index 407507f1dfb75..187f2de2bba4d 100644 --- a/tests/value_ptr_test.cpp +++ b/tests/value_ptr_test.cpp @@ -1,6 +1,6 @@ #include -#include "catch/catch.hpp" +#include "cata_catch.h" #include "value_ptr.h" TEST_CASE( "value_ptr copy constructor", "[value_ptr]" ) diff --git a/tests/vehicle_drag_test.cpp b/tests/vehicle_drag_test.cpp index af5f69c38b203..8ddb70e5b0313 100644 --- a/tests/vehicle_drag_test.cpp +++ b/tests/vehicle_drag_test.cpp @@ -4,7 +4,7 @@ #include #include "calendar.h" -#include "catch/catch.hpp" +#include "cata_catch.h" #include "character.h" #include "map.h" #include "map_helpers.h" diff --git a/tests/vehicle_efficiency_test.cpp b/tests/vehicle_efficiency_test.cpp index 4d8c1211df14f..10943a343f4d2 100644 --- a/tests/vehicle_efficiency_test.cpp +++ b/tests/vehicle_efficiency_test.cpp @@ -11,7 +11,7 @@ #include #include "calendar.h" -#include "catch/catch.hpp" +#include "cata_catch.h" #include "character.h" #include "enums.h" #include "item.h" diff --git a/tests/vehicle_interact_test.cpp b/tests/vehicle_interact_test.cpp index 8e831385e3b6c..9830483ad66cd 100644 --- a/tests/vehicle_interact_test.cpp +++ b/tests/vehicle_interact_test.cpp @@ -4,7 +4,7 @@ #include #include "calendar.h" -#include "catch/catch.hpp" +#include "cata_catch.h" #include "character.h" #include "inventory.h" #include "item.h" diff --git a/tests/vehicle_part_test.cpp b/tests/vehicle_part_test.cpp index 3c861c2c52d57..d69bca02778da 100644 --- a/tests/vehicle_part_test.cpp +++ b/tests/vehicle_part_test.cpp @@ -9,7 +9,7 @@ #include "activity_type.h" #include "calendar.h" -#include "catch/catch.hpp" +#include "cata_catch.h" #include "character.h" #include "damage.h" #include "game.h" diff --git a/tests/vehicle_power_test.cpp b/tests/vehicle_power_test.cpp index 33b9aa9f0ade5..027ec23060543 100644 --- a/tests/vehicle_power_test.cpp +++ b/tests/vehicle_power_test.cpp @@ -2,7 +2,7 @@ #include #include "calendar.h" -#include "catch/catch.hpp" +#include "cata_catch.h" #include "character.h" #include "map.h" #include "map_helpers.h" diff --git a/tests/vehicle_ramp_test.cpp b/tests/vehicle_ramp_test.cpp index b359e184444e1..b34a5983627a8 100644 --- a/tests/vehicle_ramp_test.cpp +++ b/tests/vehicle_ramp_test.cpp @@ -7,7 +7,7 @@ #include #include "calendar.h" -#include "catch/catch.hpp" +#include "cata_catch.h" #include "character.h" #include "game.h" #include "game_constants.h" diff --git a/tests/vehicle_split_test.cpp b/tests/vehicle_split_test.cpp index b890ec7565ddf..d9a343c70aeff 100644 --- a/tests/vehicle_split_test.cpp +++ b/tests/vehicle_split_test.cpp @@ -1,7 +1,7 @@ #include #include -#include "catch/catch.hpp" +#include "cata_catch.h" #include "character.h" #include "map.h" #include "point.h" diff --git a/tests/vehicle_test.cpp b/tests/vehicle_test.cpp index 57f530b009712..44c41cfc2b5a9 100644 --- a/tests/vehicle_test.cpp +++ b/tests/vehicle_test.cpp @@ -1,7 +1,7 @@ #include #include "avatar.h" -#include "catch/catch.hpp" +#include "cata_catch.h" #include "character.h" #include "damage.h" #include "enums.h" diff --git a/tests/vehicle_turrets_test.cpp b/tests/vehicle_turrets_test.cpp index 37a42c74b6abc..5c9d76b5527e1 100644 --- a/tests/vehicle_turrets_test.cpp +++ b/tests/vehicle_turrets_test.cpp @@ -1,4 +1,4 @@ -#include "catch/catch.hpp" +#include "cata_catch.h" #include #include diff --git a/tests/vision_test.cpp b/tests/vision_test.cpp index 94c7bff2a11a2..4557c9864a6e6 100644 --- a/tests/vision_test.cpp +++ b/tests/vision_test.cpp @@ -8,7 +8,7 @@ #include "cached_options.h" #include "calendar.h" -#include "catch/catch.hpp" +#include "cata_catch.h" #include "character.h" #include "game.h" #include "item.h" diff --git a/tests/visitable_remove_test.cpp b/tests/visitable_remove_test.cpp index 94ae2875ba185..b31263c8a9c3e 100644 --- a/tests/visitable_remove_test.cpp +++ b/tests/visitable_remove_test.cpp @@ -7,7 +7,7 @@ #include "calendar.h" #include "cata_utility.h" -#include "catch/catch.hpp" +#include "cata_catch.h" #include "character.h" #include "inventory.h" #include "item.h" diff --git a/tests/visitable_test.cpp b/tests/visitable_test.cpp index 0bcfd78eee6d0..f69aa2f742f4f 100644 --- a/tests/visitable_test.cpp +++ b/tests/visitable_test.cpp @@ -1,4 +1,4 @@ -#include "catch/catch.hpp" +#include "cata_catch.h" #include "calendar.h" #include "inventory.h" diff --git a/tests/weary_test.cpp b/tests/weary_test.cpp index 29824ccaad7ae..f804b5bd540c6 100644 --- a/tests/weary_test.cpp +++ b/tests/weary_test.cpp @@ -2,7 +2,7 @@ #include "activity_scheduling_helper.h" #include "avatar.h" #include "calendar.h" -#include "catch/catch.hpp" +#include "cata_catch.h" #include "player_helpers.h" #include "point.h" #include "type_id.h" diff --git a/tests/weather_test.cpp b/tests/weather_test.cpp index 30ab91c53bbbe..2f6148594aaea 100644 --- a/tests/weather_test.cpp +++ b/tests/weather_test.cpp @@ -4,7 +4,7 @@ #include #include "calendar.h" -#include "catch/catch.hpp" +#include "cata_catch.h" #include "options_helpers.h" #include "point.h" #include "type_id.h" diff --git a/tests/wield_times_test.cpp b/tests/wield_times_test.cpp index b304f25afe798..77f8ef8586743 100644 --- a/tests/wield_times_test.cpp +++ b/tests/wield_times_test.cpp @@ -1,4 +1,4 @@ -#include "catch/catch.hpp" +#include "cata_catch.h" #include From 5cba383f16579d4d604d2c78c08e79c38504a8e4 Mon Sep 17 00:00:00 2001 From: John Bytheway Date: Mon, 3 May 2021 07:41:49 -0400 Subject: [PATCH 208/453] Enable clang-tidy readability-isolate-declaration (#48629) * Enable clang-tidy readability-isolate-declaration Enable this clang-tidy check and apply the changes it suggests. Perform some minor refactoring on the result to move some declarations to first use. * Refactor some point code These changes were suggested by clang-tidy as a result of the earlier tweaks to isolate declarations. --- .clang-tidy | 1 - src/activity_item_handling.cpp | 6 ++-- src/advanced_inv.cpp | 6 ++-- src/armor_layers.cpp | 3 +- src/cata_tiles.cpp | 4 ++- src/character.cpp | 3 +- src/chkjson/chkjson.cpp | 3 +- src/colony.h | 3 +- src/computer_session.cpp | 4 +-- src/crafting_gui.cpp | 3 +- src/explosion.cpp | 6 ++-- src/iuse.cpp | 10 +++++-- src/lightmap.cpp | 3 +- src/list.h | 28 ++++++++++-------- src/main_menu.cpp | 6 ++-- src/map.h | 3 +- src/map_extras.cpp | 53 +++++++++++++++++++--------------- src/mapgen.cpp | 12 +++++--- src/mapgen_functions.cpp | 3 +- src/messages.cpp | 3 +- src/mission_ui.cpp | 3 +- src/mod_manager.cpp | 3 +- src/newcharacter.cpp | 14 ++++----- src/npcmove.cpp | 4 ++- src/ranged.cpp | 6 ++-- src/reachability_cache.cpp | 4 ++- src/savegame_json.cpp | 3 +- src/sdltiles.cpp | 3 +- src/simplexnoise.cpp | 44 +++++++++++++++++++++++----- src/veh_interact.cpp | 4 ++- src/vehicle.cpp | 6 ++-- src/vehicle_move.cpp | 15 ++++++---- src/worldfactory.cpp | 3 +- tests/colony_test.cpp | 12 ++++++-- tests/invlet_test.cpp | 4 +-- 35 files changed, 190 insertions(+), 101 deletions(-) diff --git a/.clang-tidy b/.clang-tidy index 9f3a11e18bec3..4f11f89b67c59 100644 --- a/.clang-tidy +++ b/.clang-tidy @@ -57,7 +57,6 @@ readability-*,\ -performance-unnecessary-value-param,\ -readability-else-after-return,\ -readability-implicit-bool-conversion,\ --readability-isolate-declaration,\ -readability-magic-numbers,\ -readability-named-parameter,\ " diff --git a/src/activity_item_handling.cpp b/src/activity_item_handling.cpp index 43529e831c4fe..2224b514502b3 100644 --- a/src/activity_item_handling.cpp +++ b/src/activity_item_handling.cpp @@ -1989,8 +1989,10 @@ void activity_on_turn_move_loot( player_activity &act, player &p ) // the boolean in this pair being true indicates the item is from a vehicle storage space auto items = std::vector>(); - vehicle *src_veh, *dest_veh; - int src_part, dest_part; + vehicle *src_veh; + vehicle *dest_veh; + int src_part; + int dest_part; //Check source for cargo part //map_stack and vehicle_stack are different types but inherit from item_stack diff --git a/src/advanced_inv.cpp b/src/advanced_inv.cpp index 559ec885ea010..13a3c66e58278 100644 --- a/src/advanced_inv.cpp +++ b/src/advanced_inv.cpp @@ -939,7 +939,8 @@ bool advanced_inventory::move_all_items() std::vector target_items; std::vector target_items_favorites; std::vector quantities; - item_stack::iterator stack_begin, stack_end; + item_stack::iterator stack_begin; + item_stack::iterator stack_end; if( panes[src].in_vehicle() ) { vehicle_stack targets = sarea.veh->get_items( sarea.vstor ); stack_begin = targets.begin(); @@ -1015,7 +1016,8 @@ bool advanced_inventory::move_all_items() std::vector quantities; - item_stack::iterator stack_begin, stack_end; + item_stack::iterator stack_begin; + item_stack::iterator stack_end; if( panes[src].in_vehicle() ) { vehicle_stack targets = sarea.veh->get_items( sarea.vstor ); stack_begin = targets.begin(); diff --git a/src/armor_layers.cpp b/src/armor_layers.cpp index 18a8611f5fa57..7883df1a5f18b 100644 --- a/src/armor_layers.cpp +++ b/src/armor_layers.cpp @@ -667,7 +667,8 @@ void player::sort_armor() } else if( rightListOffset + rightListLines > rightListSize ) { rightListOffset = rightListSize - rightListLines; } - int pos = 1, curr = 0; + int pos = 1; + int curr = 0; for( const bodypart_id &cover : rl ) { if( cover == bodypart_id( "bp_null" ) ) { continue; diff --git a/src/cata_tiles.cpp b/src/cata_tiles.cpp index 1355bec28a05d..5033e910bfda4 100644 --- a/src/cata_tiles.cpp +++ b/src/cata_tiles.cpp @@ -2010,7 +2010,9 @@ bool cata_tiles::draw_from_id_string( const std::string &id, TILE_CATEGORY categ }; // use a fair mix function to turn the "random" seed into a random int // taken from public domain code at http://burtleburtle.net/bob/c/lookup3.c 2015/12/11 - unsigned int a = seed, b = -seed, c = seed * seed; + unsigned int a = seed; + unsigned int b = -seed; + unsigned int c = seed * seed; c ^= b; c -= rot32( b, 14 ); a ^= c; diff --git a/src/character.cpp b/src/character.cpp index 87583300e5c15..5660cf0508a31 100644 --- a/src/character.cpp +++ b/src/character.cpp @@ -10651,7 +10651,8 @@ void Character::apply_persistent_morale() } // Characters with higher tiers of Nomad suffer worse morale penalties, faster. int max_unhappiness; - float min_time, max_time; + float min_time; + float max_time; if( has_trait( trait_NOMAD ) ) { max_unhappiness = 20; min_time = to_moves( 12_hours ); diff --git a/src/chkjson/chkjson.cpp b/src/chkjson/chkjson.cpp index 278be0c4521f5..22639af3afe4c 100644 --- a/src/chkjson/chkjson.cpp +++ b/src/chkjson/chkjson.cpp @@ -32,7 +32,8 @@ static std::vector get_files_from_path( std::string extension, std: root_path = "."; } - std::stack directories, tempstack; + std::stack directories; + std::stack tempstack; directories.push( root_path ); std::string path; diff --git a/src/colony.h b/src/colony.h index 2717614e8efe2..f6dc265d7bfdc 100644 --- a/src/colony.h +++ b/src/colony.h @@ -3029,7 +3029,8 @@ class colony : private element_allocator_type using diff_type = typename iterator_type::difference_type; diff_type distance = 0; - iterator_type iterator1 = first, iterator2 = last; + iterator_type iterator1 = first; + iterator_type iterator2 = last; const bool swap = first > last; if( swap ) { // Less common case diff --git a/src/computer_session.cpp b/src/computer_session.cpp index 0aaf5995ed18d..0f0ddc253463d 100644 --- a/src/computer_session.cpp +++ b/src/computer_session.cpp @@ -780,8 +780,8 @@ void computer_session::action_repeater_mod() avatar &player_character = get_avatar(); if( player_character.has_amount( itype_radio_repeater_mod, 1 ) ) { for( mission *miss : player_character.get_active_missions() ) { - static const mission_type_id commo_3 = mission_type_id( "MISSION_OLD_GUARD_NEC_COMMO_3" ), - commo_4 = mission_type_id( "MISSION_OLD_GUARD_NEC_COMMO_4" ); + static const mission_type_id commo_3 = mission_type_id( "MISSION_OLD_GUARD_NEC_COMMO_3" ); + static const mission_type_id commo_4 = mission_type_id( "MISSION_OLD_GUARD_NEC_COMMO_4" ); if( miss->mission_id() == commo_3 || miss->mission_id() == commo_4 ) { miss->step_complete( 1 ); print_error( _( "Repeater mod installed…" ) ); diff --git a/src/crafting_gui.cpp b/src/crafting_gui.cpp index ec9a7fc52f1f5..a5629e5723052 100644 --- a/src/crafting_gui.cpp +++ b/src/crafting_gui.cpp @@ -535,7 +535,8 @@ const recipe *select_crafting_recipe( int &batch_size_out ) const int max_recipe_name_width = 27; cata::optional cursor_pos; - int recmin = 0, recmax = current.size(); + int recmin = 0; + int recmax = current.size(); if( recmax > dataLines ) { if( line <= recmin + dataHalfLines ) { for( int i = recmin; i < recmin + dataLines; ++i ) { diff --git a/src/explosion.cpp b/src/explosion.cpp index 1dd5b68ac9428..384d0553afca6 100644 --- a/src/explosion.cpp +++ b/src/explosion.cpp @@ -799,8 +799,10 @@ void resonance_cascade( const tripoint &p ) player_character.pos() ) ) ); player_character.add_effect( effect_teleglow, rng( minglow, maxglow ) * 100 ); } - int startx = ( p.x < 8 ? 0 : p.x - 8 ), endx = ( p.x + 8 >= SEEX * 3 ? SEEX * 3 - 1 : p.x + 8 ); - int starty = ( p.y < 8 ? 0 : p.y - 8 ), endy = ( p.y + 8 >= SEEY * 3 ? SEEY * 3 - 1 : p.y + 8 ); + int startx = ( p.x < 8 ? 0 : p.x - 8 ); + int endx = ( p.x + 8 >= SEEX * 3 ? SEEX * 3 - 1 : p.x + 8 ); + int starty = ( p.y < 8 ? 0 : p.y - 8 ); + int endy = ( p.y + 8 >= SEEY * 3 ? SEEY * 3 - 1 : p.y + 8 ); tripoint dest( startx, starty, p.z ); map &here = get_map(); for( int &i = dest.x; i <= endx; i++ ) { diff --git a/src/iuse.cpp b/src/iuse.cpp index 2278aeabd2e1b..586682082764c 100644 --- a/src/iuse.cpp +++ b/src/iuse.cpp @@ -7095,7 +7095,11 @@ static extended_photo_def photo_def_for_camera_point( const tripoint &aim_point, } if( guy || mon ) { - std::string figure_appearance, figure_name, pose, pronoun_sex, figure_effects; + std::string figure_appearance; + std::string figure_name; + std::string pose; + std::string pronoun_sex; + std::string figure_effects; Creature *creature; if( mon && mon->has_effect( effect_ridden ) ) { // only player can ride, see monexamine::mount_pet @@ -7168,8 +7172,8 @@ static extended_photo_def photo_def_for_camera_point( const tripoint &aim_point, std::string ter_name = colorized_ter_name_flags_at( aim_point, {}, {} ); const std::string field_desc = colorized_field_description_at( aim_point ); - bool found_vehicle_aim_point = here.veh_at( aim_point ).has_value(), - found_furniture_aim_point = !furn_desc.empty(); + bool found_vehicle_aim_point = here.veh_at( aim_point ).has_value(); + bool found_furniture_aim_point = !furn_desc.empty(); // colorized_feature_description_at do not update flag if no furniture found, so need to check again if( !found_furniture_aim_point ) { found_item_aim_point = !item.is_null(); diff --git a/src/lightmap.cpp b/src/lightmap.cpp index 13a73f439db0a..9c0de7c0b5aff 100644 --- a/src/lightmap.cpp +++ b/src/lightmap.cpp @@ -155,7 +155,8 @@ bool map::build_transparency_cache( const int zlev ) }; if( cur_submap->is_uniform ) { - float value, dummy; + float value; + float dummy; std::tie( value, dummy ) = calc_transp( sm_offset ); // if rebuild_all==true all values were already set to LIGHT_TRANSPARENCY_OPEN_AIR if( !rebuild_all || value != LIGHT_TRANSPARENCY_OPEN_AIR ) { diff --git a/src/list.h b/src/list.h index 4a8a5bdc690a1..8126a026c68b6 100644 --- a/src/list.h +++ b/src/list.h @@ -495,8 +495,9 @@ template = block_pointer ); @@ -510,8 +511,9 @@ template free_list_head == nullptr ) ? nullptr : - last_searched_group, closest_freelist_right = ( last_searched_group->free_list_head == nullptr ) ? - nullptr : last_searched_group; + last_searched_group; + group_pointer_type closest_freelist_right = ( last_searched_group->free_list_head == nullptr ) ? + nullptr : last_searched_group; while( true ) { if( right_not_beyond_back ) { @@ -653,10 +655,12 @@ template ( this ), static_cast( &source ), sizeof( group_vector ) ); std::memcpy( static_cast( &source ), static_cast( &temp ), sizeof( group_vector ) ); } else { - const group_pointer_type swap_last_endpoint_group = last_endpoint_group, - swap_block_pointer = block_pointer, swap_last_searched_group = last_searched_group; - const size_type swap_size = size, swap_element_capacity = element_allocator_pair.capacity, - swap_capacity = group_allocator_pair.capacity; + const group_pointer_type swap_last_endpoint_group = last_endpoint_group; + const group_pointer_type swap_block_pointer = block_pointer; + const group_pointer_type swap_last_searched_group = last_searched_group; + const size_type swap_size = size; + const size_type swap_element_capacity = element_allocator_pair.capacity; + const size_type swap_capacity = group_allocator_pair.capacity; last_endpoint_group = source.last_endpoint_group; block_pointer = source.block_pointer; @@ -2201,11 +2205,11 @@ template next, - current2 = source.begin_iterator.node_pointer->next; + node_pointer_type current1 = begin_iterator.node_pointer->next; + node_pointer_type current2 = source.begin_iterator.node_pointer->next; node_pointer_type previous = source.begin_iterator.node_pointer; - const node_pointer_type source_end = source.end_iterator.node_pointer, - this_end = end_iterator.node_pointer; + const node_pointer_type source_end = source.end_iterator.node_pointer; + const node_pointer_type this_end = end_iterator.node_pointer; begin_iterator.node_pointer->next = source.begin_iterator.node_pointer; source.begin_iterator.node_pointer->previous = begin_iterator.node_pointer; diff --git a/src/main_menu.cpp b/src/main_menu.cpp index 01e583dad960d..79a464c2eb188 100644 --- a/src/main_menu.cpp +++ b/src/main_menu.cpp @@ -1022,7 +1022,8 @@ bool main_menu::load_character_tab( bool transfer ) int line = menu_offset.y - 2 - i; std::string world_name = all_worldnames[i]; int savegames_count = world_generator->get_world( world_name )->world_saves.size(); - nc_color color1, color2; + nc_color color1; + nc_color color2; if( world_name == "TUTORIAL" || world_name == "DEFENSE" ) { color1 = c_light_cyan; color2 = h_light_cyan; @@ -1209,7 +1210,8 @@ void main_menu::world_tab() for( auto it = all_worldnames.begin(); it != all_worldnames.end(); ++it, i++ ) { int savegames_count = world_generator->get_world( *it )->world_saves.size(); int line = menu_offset.y - 2 - i; - nc_color color1, color2; + nc_color color1; + nc_color color2; if( *it == "TUTORIAL" || *it == "DEFENSE" ) { color1 = c_light_cyan; color2 = h_light_cyan; diff --git a/src/map.h b/src/map.h index c18cdbf887812..953bf435a1b17 100644 --- a/src/map.h +++ b/src/map.h @@ -328,7 +328,8 @@ class map return cache.r_hor_cache->has_potential_los( from.xy(), to.xy(), cache ) && cache.r_hor_cache->has_potential_los( to.xy(), from.xy(), cache ) ; } - tripoint upper, lower; + tripoint upper; + tripoint lower; std::tie( upper, lower ) = from.z > to.z ? std::make_pair( from, to ) : std::make_pair( to, from ); // z-bounds depend on the invariant that both points are inbounds and their z are different return get_cache( lower.z ).r_up_cache->has_potential_los( diff --git a/src/map_extras.cpp b/src/map_extras.cpp index c55ddea0ee287..4ba83bd8f6529 100644 --- a/src/map_extras.cpp +++ b/src/map_extras.cpp @@ -1048,7 +1048,6 @@ static bool mx_minefield( map &, const tripoint &abs_sub ) const int num_mines = rng( 6, 20 ); const std::string text = _( "DANGER! MINEFIELD!" ); - int x, y, x1, y1 = 0; bool did_something = false; @@ -1121,23 +1120,23 @@ static bool mx_minefield( map &, const tripoint &abs_sub ) //Spawn 6-20 mines in the lower submap. //Spawn ordinary mine on asphalt, otherwise spawn buried mine for( int i = 0; i < num_mines; i++ ) { - const int x = rng( 3, SEEX * 2 - 4 ), y = rng( SEEY, SEEY * 2 - 2 ); - if( m.has_flag( flag_DIGGABLE, point( x, y ) ) ) { - place_trap_if_clear( m, point( x, y ), tr_landmine_buried ); + const point p( rng( 3, SEEX * 2 - 4 ), rng( SEEY, SEEY * 2 - 2 ) ); + if( m.has_flag( flag_DIGGABLE, p ) ) { + place_trap_if_clear( m, p, tr_landmine_buried ); } else { - place_trap_if_clear( m, point( x, y ), tr_landmine ); + place_trap_if_clear( m, p, tr_landmine ); } } //Spawn 6-20 puddles of blood on tiles without mines for( int i = 0; i < num_mines; i++ ) { - const int x = rng( 3, SEEX * 2 - 4 ), y = rng( SEEY, SEEY * 2 - 2 ); - if( m.tr_at( { x, y, abs_sub.z } ).is_null() ) { - m.add_field( { x, y, abs_sub.z }, fd_blood, rng( 1, 3 ) ); + const point p2( rng( 3, SEEX * 2 - 4 ), rng( SEEY, SEEY * 2 - 2 ) ); + if( m.tr_at( { p2, abs_sub.z } ).is_null() ) { + m.add_field( { p2, abs_sub.z }, fd_blood, rng( 1, 3 ) ); //10% chance to spawn a corpse of dead people/zombie on a tile with blood if( one_in( 10 ) ) { - m.add_corpse( { x, y, abs_sub.z } ); - for( const auto &loc : m.points_in_radius( { x, y, abs_sub.z }, 1 ) ) { + m.add_corpse( { p2, abs_sub.z } ); + for( const auto &loc : m.points_in_radius( { p2, abs_sub.z }, 1 ) ) { //50% chance to spawn gibs in every tile around corpse in 1-tile radius if( one_in( 2 ) ) { m.add_field( { loc.xy(), abs_sub.z }, fd_gibs_flesh, rng( 1, 3 ) ); @@ -1148,8 +1147,8 @@ static bool mx_minefield( map &, const tripoint &abs_sub ) } //Set two warning signs on the last horizontal line of the submap - x = rng( 3, SEEX ); - x1 = rng( SEEX + 1, SEEX * 2 - 4 ); + const int x = rng( 3, SEEX ); + const int x1 = rng( SEEX + 1, SEEX * 2 - 4 ); m.furn_set( point( x, SEEY * 2 - 1 ), furn_str_id( "f_sign_warning" ) ); m.set_signage( tripoint( x, SEEY * 2 - 1, abs_sub.z ), text ); m.furn_set( point( x1, SEEY * 2 - 1 ), furn_str_id( "f_sign_warning" ) ); @@ -1224,7 +1223,8 @@ static bool mx_minefield( map &, const tripoint &abs_sub ) //Spawn 6-20 mines in the upper submap. //Spawn ordinary mine on asphalt, otherwise spawn buried mine for( int i = 0; i < num_mines; i++ ) { - const int x = rng( 3, SEEX * 2 - 4 ), y = rng( 1, SEEY ); + const int x = rng( 3, SEEX * 2 - 4 ); + const int y = rng( 1, SEEY ); if( m.has_flag( flag_DIGGABLE, point( x, y ) ) ) { place_trap_if_clear( m, point( x, y ), tr_landmine_buried ); } else { @@ -1234,7 +1234,8 @@ static bool mx_minefield( map &, const tripoint &abs_sub ) //Spawn 6-20 puddles of blood on tiles without mines for( int i = 0; i < num_mines; i++ ) { - const int x = rng( 3, SEEX * 2 - 4 ), y = rng( 1, SEEY ); + const int x = rng( 3, SEEX * 2 - 4 ); + const int y = rng( 1, SEEY ); if( m.tr_at( { x, y, abs_sub.z } ).is_null() ) { m.add_field( { x, y, abs_sub.z }, fd_blood, rng( 1, 3 ) ); //10% chance to spawn a corpse of dead people/zombie on a tile with blood @@ -1251,8 +1252,8 @@ static bool mx_minefield( map &, const tripoint &abs_sub ) } //Set two warning signs on the first horizontal line of the submap - x = rng( 3, SEEX ); - x1 = rng( SEEX + 1, SEEX * 2 - 4 ); + const int x = rng( 3, SEEX ); + const int x1 = rng( SEEX + 1, SEEX * 2 - 4 ); m.furn_set( point( x, 0 ), furn_str_id( "f_sign_warning" ) ); m.set_signage( tripoint( x, 0, abs_sub.z ), text ); m.furn_set( point( x1, 0 ), furn_str_id( "f_sign_warning" ) ); @@ -1371,7 +1372,8 @@ static bool mx_minefield( map &, const tripoint &abs_sub ) //Spawn 6-20 mines in the rightmost submap. //Spawn ordinary mine on asphalt, otherwise spawn buried mine for( int i = 0; i < num_mines; i++ ) { - const int x = rng( SEEX + 1, SEEX * 2 - 2 ), y = rng( 3, SEEY * 2 - 4 ); + const int x = rng( SEEX + 1, SEEX * 2 - 2 ); + const int y = rng( 3, SEEY * 2 - 4 ); if( m.has_flag( flag_DIGGABLE, point( x, y ) ) ) { place_trap_if_clear( m, point( x, y ), tr_landmine_buried ); } else { @@ -1381,7 +1383,8 @@ static bool mx_minefield( map &, const tripoint &abs_sub ) //Spawn 6-20 puddles of blood on tiles without mines for( int i = 0; i < num_mines; i++ ) { - const int x = rng( SEEX + 1, SEEX * 2 - 2 ), y = rng( 3, SEEY * 2 - 4 ); + const int x = rng( SEEX + 1, SEEX * 2 - 2 ); + const int y = rng( 3, SEEY * 2 - 4 ); if( m.tr_at( { x, y, abs_sub.z } ).is_null() ) { m.add_field( { x, y, abs_sub.z }, fd_blood, rng( 1, 3 ) ); //10% chance to spawn a corpse of dead people/zombie on a tile with blood @@ -1398,8 +1401,8 @@ static bool mx_minefield( map &, const tripoint &abs_sub ) } //Set two warning signs on the last vertical line of the submap - y = rng( 3, SEEY ); - y1 = rng( SEEY + 1, SEEY * 2 - 4 ); + const int y = rng( 3, SEEY ); + const int y1 = rng( SEEY + 1, SEEY * 2 - 4 ); m.furn_set( point( SEEX * 2 - 1, y ), furn_str_id( "f_sign_warning" ) ); m.set_signage( tripoint( SEEX * 2 - 1, y, abs_sub.z ), text ); m.furn_set( point( SEEX * 2 - 1, y1 ), furn_str_id( "f_sign_warning" ) ); @@ -1510,7 +1513,8 @@ static bool mx_minefield( map &, const tripoint &abs_sub ) //Spawn 6-20 mines in the leftmost submap. //Spawn ordinary mine on asphalt, otherwise spawn buried mine for( int i = 0; i < num_mines; i++ ) { - const int x = rng( 1, SEEX ), y = rng( 3, SEEY * 2 - 4 ); + const int x = rng( 1, SEEX ); + const int y = rng( 3, SEEY * 2 - 4 ); if( m.has_flag( flag_DIGGABLE, point( x, y ) ) ) { place_trap_if_clear( m, point( x, y ), tr_landmine_buried ); } else { @@ -1520,7 +1524,8 @@ static bool mx_minefield( map &, const tripoint &abs_sub ) //Spawn 6-20 puddles of blood on tiles without mines for( int i = 0; i < num_mines; i++ ) { - const int x = rng( 1, SEEX ), y = rng( 3, SEEY * 2 - 4 ); + const int x = rng( 1, SEEX ); + const int y = rng( 3, SEEY * 2 - 4 ); if( m.tr_at( { x, y, abs_sub.z } ).is_null() ) { m.add_field( { x, y, abs_sub.z }, fd_blood, rng( 1, 3 ) ); //10% chance to spawn a corpse of dead people/zombie on a tile with blood @@ -1537,8 +1542,8 @@ static bool mx_minefield( map &, const tripoint &abs_sub ) } //Set two warning signs on the first vertical line of the submap - y = rng( 3, SEEY ); - y1 = rng( SEEY + 1, SEEY * 2 - 4 ); + const int y = rng( 3, SEEY ); + const int y1 = rng( SEEY + 1, SEEY * 2 - 4 ); m.furn_set( point( 0, y ), furn_str_id( "f_sign_warning" ) ); m.set_signage( tripoint( 0, y, abs_sub.z ), text ); m.furn_set( point( 0, y1 ), furn_str_id( "f_sign_warning" ) ); diff --git a/src/mapgen.cpp b/src/mapgen.cpp index 12bf05145f44e..d6ebf48bb3446 100644 --- a/src/mapgen.cpp +++ b/src/mapgen.cpp @@ -4091,7 +4091,8 @@ void map::draw_temple( const mapgendata &dat ) square( this, t_rock, point( SEEX + 2, 0 ), point( EAST_EDGE, 1 ) ); square( this, t_rock, point( SEEX + 2, SEEY * 2 - 2 ), point( EAST_EDGE, SOUTH_EDGE ) ); square( this, t_rock, point( SEEX + 5, 2 ), point( EAST_EDGE, SEEY * 2 - 3 ) ); - int x = rng( SEEX - 1, SEEX + 2 ), y = 2; + int x = rng( SEEX - 1, SEEX + 2 ); + int y = 2; std::vector path; // Path, from end to start while( x < SEEX - 1 || x > SEEX + 2 || y < SEEY * 2 - 2 ) { static const std::vector terrains = { @@ -4239,8 +4240,10 @@ void map::draw_mine( mapgendata &dat ) point end_location( rng( SEEX + 1, SEEX * 2 - 7 ), rng( SEEY + 1, SEEY * 2 - 7 ) ); const int num = rng( 2, 4 ); for( int i = 0; i < num; i++ ) { - int lx1 = start_location.x + rng( -1, 1 ), lx2 = end_location.x + rng( -1, 1 ), - ly1 = start_location.y + rng( -1, 1 ), ly2 = end_location.y + rng( -1, 1 ); + int lx1 = start_location.x + rng( -1, 1 ); + int lx2 = end_location.x + rng( -1, 1 ); + int ly1 = start_location.y + rng( -1, 1 ); + int ly2 = end_location.y + rng( -1, 1 ); line( this, t_lava, point( lx1, ly1 ), point( lx2, ly2 ) ); } } @@ -4490,7 +4493,8 @@ void map::draw_mine( mapgendata &dat ) computer *tmpcomp = nullptr; switch( rn ) { case 1: { // Wyrms - const int x = rng( SEEX, SEEX + 1 ), y = rng( SEEY, SEEY + 1 ); + const int x = rng( SEEX, SEEX + 1 ); + const int y = rng( SEEY, SEEY + 1 ); ter_set( point( x, y ), t_pedestal_wyrm ); spawn_item( point( x, y ), "petrified_eye" ); } diff --git a/src/mapgen_functions.cpp b/src/mapgen_functions.cpp index c9e85d53f6142..b7034c9cd4c58 100644 --- a/src/mapgen_functions.cpp +++ b/src/mapgen_functions.cpp @@ -802,7 +802,8 @@ void mapgen_road( mapgendata &dat ) if( curvedir_nesw[dir] != 0 ) { for( int x = 1; x < 4; x++ ) { for( int y = 0; y < x; y++ ) { - int ty = y, tx = ( curvedir_nesw[dir] == -1 ? x : SEEX * 2 - 1 - x ); + int ty = y; + int tx = ( curvedir_nesw[dir] == -1 ? x : SEEX * 2 - 1 - x ); coord_rotate_cw( tx, ty, dir ); m->ter_set( point( tx, ty ), t_pavement ); } diff --git a/src/messages.cpp b/src/messages.cpp index b804c29fa2a27..848dacb0fefe0 100644 --- a/src/messages.cpp +++ b/src/messages.cpp @@ -572,7 +572,8 @@ void Messages::dialog::show() .apply( w ); // Range of window lines to print - size_t line_from = 0, line_to; + size_t line_from = 0; + size_t line_to; if( offset < folded_filtered.size() ) { line_to = std::min( max_lines, folded_filtered.size() - offset ); } else { diff --git a/src/mission_ui.cpp b/src/mission_ui.cpp index 908f52e52e3d3..e2729e8dd187e 100644 --- a/src/mission_ui.cpp +++ b/src/mission_ui.cpp @@ -70,7 +70,8 @@ void game::list_missions() }; draw_tabs( w_missions, tabs, tab ); draw_border_below_tabs( w_missions ); - int x1 = 2, x2 = 2; + int x1 = 2; + int x2 = 2; for( const std::pair &t : tabs ) { x2 = x1 + utf8_width( t.second ) + 1; if( t.first == tab ) { diff --git a/src/mod_manager.cpp b/src/mod_manager.cpp index 0d93784e09066..3d8f8178af2da 100644 --- a/src/mod_manager.cpp +++ b/src/mod_manager.cpp @@ -443,7 +443,8 @@ static inline bool compare_mod_by_name_and_category( const MOD_INFORMATION *cons void mod_manager::set_usable_mods() { - std::vector available_cores, available_supplementals; + std::vector available_cores; + std::vector available_supplementals; std::vector ordered_mods; std::vector mods; diff --git a/src/newcharacter.cpp b/src/newcharacter.cpp index b87e83453c0f2..5b96fdd1d3a19 100644 --- a/src/newcharacter.cpp +++ b/src/newcharacter.cpp @@ -1230,7 +1230,11 @@ tab_direction set_traits( avatar &u, points_left &points ) } for( int iCurrentPage = 0; iCurrentPage < 3; iCurrentPage++ ) { - nc_color col_on_act, col_off_act, col_on_pas, col_off_pas, hi_on, hi_off, col_tr; + nc_color col_on_act; + nc_color col_off_act; + nc_color col_on_pas; + nc_color col_off_pas; + nc_color col_tr; switch( iCurrentPage ) { case 0: col_on_act = COL_TR_GOOD_ON_ACT; @@ -1238,8 +1242,6 @@ tab_direction set_traits( avatar &u, points_left &points ) col_on_pas = COL_TR_GOOD_ON_PAS; col_off_pas = COL_TR_GOOD_OFF_PAS; col_tr = COL_TR_GOOD; - hi_on = hilite( col_on_act ); - hi_off = hilite( col_off_act ); break; case 1: col_on_act = COL_TR_BAD_ON_ACT; @@ -1247,8 +1249,6 @@ tab_direction set_traits( avatar &u, points_left &points ) col_on_pas = COL_TR_BAD_ON_PAS; col_off_pas = COL_TR_BAD_OFF_PAS; col_tr = COL_TR_BAD; - hi_on = hilite( col_on_act ); - hi_off = hilite( col_off_act ); break; default: col_on_act = COL_TR_NEUT_ON_ACT; @@ -1256,10 +1256,10 @@ tab_direction set_traits( avatar &u, points_left &points ) col_on_pas = COL_TR_NEUT_ON_PAS; col_off_pas = COL_TR_NEUT_OFF_PAS; col_tr = COL_TR_NEUT; - hi_on = hilite( col_on_act ); - hi_off = hilite( col_off_act ); break; } + nc_color hi_on = hilite( col_on_act ); + nc_color hi_off = hilite( col_off_act ); int &start = iStartPos[iCurrentPage]; int current = iCurrentLine[iCurrentPage]; diff --git a/src/npcmove.cpp b/src/npcmove.cpp index 03ea28a6a9eb2..a27cd05da9531 100644 --- a/src/npcmove.cpp +++ b/src/npcmove.cpp @@ -3123,7 +3123,9 @@ void npc::drop_items( const units::mass &drop_weight, const units::volume &drop_ units::mass weight_dropped = units::from_gram( 0 ); units::volume volume_dropped = units::from_liter( 0 ); - std::vector rWgt, rVol; // Weight/Volume to value ratios + // Weight/Volume to value ratios + std::vector rWgt; + std::vector rVol; // First fill our ratio vectors, so we know which things to drop first invslice slice = inv->slice(); diff --git a/src/ranged.cpp b/src/ranged.cpp index 9ee9d44b09a10..a3d9eaae8a7ba 100644 --- a/src/ranged.cpp +++ b/src/ranged.cpp @@ -1287,8 +1287,10 @@ static int print_ranged_chance( const player &p, const catacurses::window &w, in } std::string label_m = _( "Moves" ); - std::vector t_aims( 4 ), t_confidence( 20 ); - int aim_iter = 0, conf_iter = 0; + std::vector t_aims( 4 ); + std::vector t_confidence( 20 ); + int aim_iter = 0; + int conf_iter = 0; nc_color col = c_dark_gray; diff --git a/src/reachability_cache.cpp b/src/reachability_cache.cpp index adfdc1562ee03..db2d84aa165eb 100644 --- a/src/reachability_cache.cpp +++ b/src/reachability_cache.cpp @@ -60,7 +60,9 @@ void reachability_cache::rebuild( Q q, static_assert( MAPSIZE_X == SEEX * MAPSIZE, "reachability cache uses outdated map dimensions" ); // start is inclusive, end is exclusive (1 step outside of the range) - point dir, start, end; + point dir; + point start; + point end; if( q == Q::SW || q == Q::NW ) { std::tie( dir.x, start.x, end.x ) = std::make_tuple( 1, 0, MAPSIZE_X ); diff --git a/src/savegame_json.cpp b/src/savegame_json.cpp index fa9df07486e89..cb9e3871edfef 100644 --- a/src/savegame_json.cpp +++ b/src/savegame_json.cpp @@ -4288,7 +4288,8 @@ void submap::load( JsonIn &jsin, const std::string &member_name, int version ) int i = jsin.get_int(); int j = jsin.get_int(); const point p( i, j ); - std::string type, str; + std::string type; + std::string str; // Try to read as current format if( jsin.test_string() ) { type = jsin.get_string(); diff --git a/src/sdltiles.cpp b/src/sdltiles.cpp index e2139fce49573..6e57ba056dd8e 100644 --- a/src/sdltiles.cpp +++ b/src/sdltiles.cpp @@ -2904,7 +2904,8 @@ static void init_term_size_and_scaling_factor() if( scaling_factor > 1 ) { - int max_width, max_height; + int max_width; + int max_height; int current_display_id = std::stoi( get_option( "DISPLAY" ) ); SDL_DisplayMode current_display; diff --git a/src/simplexnoise.cpp b/src/simplexnoise.cpp index 0d3f05763f050..b0530f7df3d03 100644 --- a/src/simplexnoise.cpp +++ b/src/simplexnoise.cpp @@ -204,7 +204,10 @@ float raw_noise_2d( const float x, const float y ) // For the 2D case, the simplex shape is an equilateral triangle. // Determine which simplex we are in. - int i1, j1; // Offsets for second (middle) corner of simplex in (i,j) coordinates + + // Offsets for second (middle) corner of simplex in (i,j) coordinates + int i1; + int j1; if( x0 > y0 ) { i1 = 1; // lower triangle, XY order: (0,0)->(1,0)->(1,1) j1 = 0; @@ -261,7 +264,11 @@ float raw_noise_2d( const float x, const float y ) // 3D raw Simplex noise float raw_noise_3d( const float x, const float y, const float z ) { - float n0, n1, n2, n3; // Noise contributions from the four corners + // Noise contributions from the four corners + float n0; + float n1; + float n2; + float n3; // Skew the input space to determine which simplex cell we're in float F3 = 1.0f / 3.0f; @@ -281,8 +288,12 @@ float raw_noise_3d( const float x, const float y, const float z ) // For the 3D case, the simplex shape is a slightly irregular tetrahedron. // Determine which simplex we are in. - int i1, j1, k1; // Offsets for second corner of simplex in (i,j,k) coordinates - int i2, j2, k2; // Offsets for third corner of simplex in (i,j,k) coordinates + int i1; // Offsets for second corner of simplex in (i,j,k) coordinates + int j1; + int k1; + int i2; // Offsets for third corner of simplex in (i,j,k) coordinates + int j2; + int k2; if( x0 >= y0 ) { if( y0 >= z0 ) { @@ -399,7 +410,12 @@ float raw_noise_4d( const float x, const float y, const float z, const float w ) // The skewing and unskewing factors are hairy again for the 4D case static const float F4 = ( std::sqrt( 5.0f ) - 1.0f ) / 4.0f; static const float G4 = ( 5.0f - std::sqrt( 5.0f ) ) / 20.0f; - float n0, n1, n2, n3, n4; // Noise contributions from the five corners + // Noise contributions from the five corners + float n0; + float n1; + float n2; + float n3; + float n4; // Skew the (x,y,z,w) space to determine which cell of 24 simplices we're in float s = ( x + y + z + w ) * F4; // Factor for 4D skewing @@ -434,9 +450,21 @@ float raw_noise_4d( const float x, const float y, const float z, const float w ) int c6 = ( z0 > w0 ) ? 1 : 0; int c = c1 + c2 + c3 + c4 + c5 + c6; - int i1, j1, k1, l1; // The integer offsets for the second simplex corner - int i2, j2, k2, l2; // The integer offsets for the third simplex corner - int i3, j3, k3, l3; // The integer offsets for the fourth simplex corner + // The integer offsets for the second simplex corner + int i1; + int j1; + int k1; + int l1; + // The integer offsets for the third simplex corner + int i2; + int j2; + int k2; + int l2; + // The integer offsets for the fourth simplex corner + int i3; + int j3; + int k3; + int l3; // simplex[c] is a 4-vector with the numbers 0, 1, 2 and 3 in some order. // Many values of c will never occur, since e.g. x>y>z>w makes x vehicle::use_charges( const vpart_position &vp, const itype_id & const cata::optional cargo_vp = vp.part_with_feature( "CARGO", true ); const auto tool_wants_battery = []( const itype_id & type ) { - item tool( type, calendar::turn_zero ), mag( tool.magazine_default() ); + item tool( type, calendar::turn_zero ); + item mag( tool.magazine_default() ); mag.contents.clear_items(); return tool.contents.insert_item( mag, item_pocket::pocket_type::MAGAZINE_WELL ).success() && diff --git a/src/vehicle_move.cpp b/src/vehicle_move.cpp index 23aab0a9eb488..4f05a0879a341 100644 --- a/src/vehicle_move.cpp +++ b/src/vehicle_move.cpp @@ -169,7 +169,8 @@ void vehicle::smart_controller_handle_turn( bool thrusting, return; } - int cur_battery_level, max_battery_level; + int cur_battery_level; + int max_battery_level; std::tie( cur_battery_level, max_battery_level ) = battery_power_level(); int battery_level_percent = max_battery_level == 0 ? 0 : cur_battery_level * 100 / max_battery_level; @@ -1640,7 +1641,8 @@ bool vehicle::allow_manual_turn_on_rails( units::angle &corrected_turn_dir ) con if( turn_dir != face.dir() ) { corrected_turn_dir = get_corrected_turn_dir( turn_dir, face.dir() ); - int wheels_on_rail, turning_wheels_that_are_one_axis; + int wheels_on_rail; + int turning_wheels_that_are_one_axis; precalculate_vehicle_turning( corrected_turn_dir, true, TFLAG_RAIL, wheels_on_rail, turning_wheels_that_are_one_axis ); if( is_wheel_state_correct_to_turn_on_rails( wheels_on_rail, rail_wheelcache.size(), @@ -1657,19 +1659,22 @@ bool vehicle::allow_auto_turn_on_rails( units::angle &corrected_turn_dir ) const // check if autoturn is possible if( turn_dir == face.dir() ) { // precalculate wheels for every direction - int straight_wheels_on_rail, straight_turning_wheels_that_are_one_axis; + int straight_wheels_on_rail; + int straight_turning_wheels_that_are_one_axis; precalculate_vehicle_turning( face.dir(), true, TFLAG_RAIL, straight_wheels_on_rail, straight_turning_wheels_that_are_one_axis ); units::angle left_turn_dir = get_corrected_turn_dir( face.dir() - 45_degrees, face.dir() ); - int leftturn_wheels_on_rail, leftturn_turning_wheels_that_are_one_axis; + int leftturn_wheels_on_rail; + int leftturn_turning_wheels_that_are_one_axis; precalculate_vehicle_turning( left_turn_dir, true, TFLAG_RAIL, leftturn_wheels_on_rail, leftturn_turning_wheels_that_are_one_axis ); units::angle right_turn_dir = get_corrected_turn_dir( face.dir() + 45_degrees, face.dir() ); - int rightturn_wheels_on_rail, rightturn_turning_wheels_that_are_one_axis; + int rightturn_wheels_on_rail; + int rightturn_turning_wheels_that_are_one_axis; precalculate_vehicle_turning( right_turn_dir, true, TFLAG_RAIL, rightturn_wheels_on_rail, rightturn_turning_wheels_that_are_one_axis ); diff --git a/src/worldfactory.cpp b/src/worldfactory.cpp index 73b7b87f03527..0730b6cc2a43b 100644 --- a/src/worldfactory.cpp +++ b/src/worldfactory.cpp @@ -416,7 +416,8 @@ WORLDPTR worldfactory::pick_world( bool show_prompt ) mapLines[3] = true; std::map > world_pages; - size_t sel = 0, selpage = 0; + size_t sel = 0; + size_t selpage = 0; catacurses::window w_worlds_border; catacurses::window w_worlds_tooltip; diff --git a/tests/colony_test.cpp b/tests/colony_test.cpp index f210cd7e1f36a..e88199b335765 100644 --- a/tests/colony_test.cpp +++ b/tests/colony_test.cpp @@ -638,7 +638,11 @@ TEST_CASE( "colony range erase", "[colony]" ) CHECK( count == 400 ); CHECK( test_colony.size() == 400 ); - unsigned int size, range1, range2, loop_count, internal_loop_count; + unsigned int size; + unsigned int range1; + unsigned int range2; + unsigned int loop_count; + unsigned int internal_loop_count; for( loop_count = 0; loop_count < 50; ++loop_count ) { test_colony.clear(); @@ -887,7 +891,8 @@ TEST_CASE( "colony perfect forwarding", "[colony]" ) TEST_CASE( "colony emplace", "[colony]" ) { cata::colony test_colony; - int sum1 = 0, sum2 = 0; + int sum1 = 0; + int sum2 = 0; for( int i = 0; i < 100; ++i ) { test_colony.emplace( i ); @@ -949,7 +954,8 @@ TEST_CASE( "colony group size and capacity", "[colony]" ) TEST_CASE( "colony splice", "[colony]" ) { - cata::colony test_colony_1, test_colony_2; + cata::colony test_colony_1; + cata::colony test_colony_2; SECTION( "small splice 1" ) { int i = 0; diff --git a/tests/invlet_test.cpp b/tests/invlet_test.cpp index be0fb49138c11..6b1eb49b3c1d8 100644 --- a/tests/invlet_test.cpp +++ b/tests/invlet_test.cpp @@ -513,8 +513,8 @@ static void invlet_test( player &dummy, const inventory_location from, const inv break; } - invlet_state final_first_invlet_state = check_invlet( dummy, *final_first, invlet ), - final_second_invlet_state = check_invlet( dummy, *final_second, invlet ); + invlet_state final_first_invlet_state = check_invlet( dummy, *final_first, invlet ); + invlet_state final_second_invlet_state = check_invlet( dummy, *final_second, invlet ); INFO( test_action_desc( action, from, to, first_invlet_state, second_invlet_state, expected_first_invlet_state, expected_second_invlet_state, final_first_invlet_state, From 73cc97d883654880b931197af5a6fd61c3189739 Mon Sep 17 00:00:00 2001 From: John Bytheway Date: Mon, 3 May 2021 07:42:57 -0400 Subject: [PATCH 209/453] New clang-tidy check for static int_ids (#48688) * Initial check for static int_ids int_ids with static storage duration are dangerous because they can start to refer to the wrong thing when game data reloads. This has caused problems in the past. Add a check for such variables, and some tests. * Remove some static int_ids Fix issues detected by new check by replacing some static int_ids with their respective string_ids. Some were just unused, so got deleted instead. Some cases suppressed, including the furniture and terrain ids, since they were the most numerous and widely used, so that seemed the riskiest change. --- src/editmap.cpp | 1 + src/field_type.h | 1 + src/map.cpp | 4 +- src/mapdata.cpp | 21 ----- src/mapdata.h | 2 + src/overmap.cpp | 19 ++-- tests/submap_load_test.cpp | 24 ++--- tools/clang-tidy-plugin/CMakeLists.txt | 1 + tools/clang-tidy-plugin/CataTidyModule.cpp | 3 + .../StaticIntIdConstantsCheck.cpp | 87 +++++++++++++++++++ .../StaticIntIdConstantsCheck.h | 32 +++++++ .../StaticStringIdConstantsCheck.cpp | 1 + .../test/static-int_id-constants.cpp | 50 +++++++++++ 13 files changed, 197 insertions(+), 49 deletions(-) create mode 100644 tools/clang-tidy-plugin/StaticIntIdConstantsCheck.cpp create mode 100644 tools/clang-tidy-plugin/StaticIntIdConstantsCheck.h create mode 100644 tools/clang-tidy-plugin/test/static-int_id-constants.cpp diff --git a/src/editmap.cpp b/src/editmap.cpp index 0c680f0513925..eeed0847399bc 100644 --- a/src/editmap.cpp +++ b/src/editmap.cpp @@ -62,6 +62,7 @@ static constexpr tripoint editmap_boundary_max( MAPSIZE_X, MAPSIZE_Y, OVERMAP_HE static constexpr half_open_cuboid editmap_boundaries( editmap_boundary_min, editmap_boundary_max ); +// NOLINTNEXTLINE(cata-static-int_id-constants) static const ter_id undefined_ter_id( -1 ); static std::vector fld_string( const std::string &str, int width ) diff --git a/src/field_type.h b/src/field_type.h index f0b82656dc2d9..4099cd26fe513 100644 --- a/src/field_type.h +++ b/src/field_type.h @@ -111,6 +111,7 @@ struct field_intensity_level { std::vector field_effects; }; +// NOLINTNEXTLINE(cata-static-int_id-constants) const field_type_id INVALID_FIELD_TYPE_ID = field_type_id( -1 ); extern const field_type_str_id fd_null; extern const field_type_str_id fd_fire; diff --git a/src/map.cpp b/src/map.cpp index 37970915bea06..b67d922b39632 100644 --- a/src/map.cpp +++ b/src/map.cpp @@ -6884,8 +6884,8 @@ static void generate_uniform( const tripoint &p, const ter_id &terrain_type ) void map::loadn( const tripoint &grid, const bool update_vehicles, bool _actualize ) { // Cache empty overmap types - static const oter_id rock( "empty_rock" ); - static const oter_id air( "open_air" ); + static const oter_str_id rock( "empty_rock" ); + static const oter_str_id air( "open_air" ); dbg( D_INFO ) << "map::loadn(game[" << g.get() << "], worldx[" << abs_sub.x << "], worldy[" << abs_sub.y << "], grid " << grid << ")"; diff --git a/src/mapdata.cpp b/src/mapdata.cpp index 303eec071f01a..feac1e25f9447 100644 --- a/src/mapdata.cpp +++ b/src/mapdata.cpp @@ -646,8 +646,6 @@ ter_id t_null, t_railroad_track_on_tie, t_railroad_track_h_on_tie, t_railroad_track_v_on_tie, t_railroad_track_d_on_tie; -static ter_id t_nanofab, t_nanofab_body, t_wall_b, t_wall_g, t_wall_p, t_wall_r, t_wall_w; - // TODO: Put this crap into an inclusion, which should be generated automatically using JSON data void set_ter_ids() @@ -723,11 +721,6 @@ void set_ter_ids() t_reinforced_door_glass_o = ter_id( "t_reinforced_door_glass_o" ); t_bars = ter_id( "t_bars" ); t_reb_cage = ter_id( "t_reb_cage" ); - t_wall_b = ter_id( "t_wall_b" ); - t_wall_g = ter_id( "t_wall_g" ); - t_wall_p = ter_id( "t_wall_p" ); - t_wall_r = ter_id( "t_wall_r" ); - t_wall_w = ter_id( "t_wall_w" ); t_door_c = ter_id( "t_door_c" ); t_door_c_peep = ter_id( "t_door_c_peep" ); t_door_b = ter_id( "t_door_b" ); @@ -894,8 +887,6 @@ void set_ter_ids() t_rootcellar = ter_id( "t_rootcellar" ); t_cvdbody = ter_id( "t_cvdbody" ); t_cvdmachine = ter_id( "t_cvdmachine" ); - t_nanofab = ter_id( "t_nanofab" ); - t_nanofab_body = ter_id( "t_nanofab_body" ); t_stairs_down = ter_id( "t_stairs_down" ); t_stairs_up = ter_id( "t_stairs_up" ); t_manhole = ter_id( "t_manhole" ); @@ -1020,9 +1011,6 @@ furn_id f_null, f_sign, f_street_light, f_traffic_light; -static furn_id f_ball_mach, f_bluebell, f_dahlia, f_dandelion, f_datura, f_floor_canvas, - f_indoor_plant_y, f_lane, f_statue; - void set_furn_ids() { f_null = furn_id( "f_null" ); @@ -1036,7 +1024,6 @@ void set_furn_ids() f_sandbag_wall = furn_id( "f_sandbag_wall" ); f_bulletin = furn_id( "f_bulletin" ); f_indoor_plant = furn_id( "f_indoor_plant" ); - f_indoor_plant_y = furn_id( "f_indoor_plant_y" ); f_bed = furn_id( "f_bed" ); f_toilet = furn_id( "f_toilet" ); f_makeshift_bed = furn_id( "f_makeshift_bed" ); @@ -1053,9 +1040,7 @@ void set_furn_ids() f_trashcan = furn_id( "f_trashcan" ); f_desk = furn_id( "f_desk" ); f_exercise = furn_id( "f_exercise" ); - f_ball_mach = furn_id( "f_ball_mach" ); f_bench = furn_id( "f_bench" ); - f_lane = furn_id( "f_lane" ); f_table = furn_id( "f_table" ); f_pool_table = furn_id( "f_pool_table" ); f_counter = furn_id( "f_counter" ); @@ -1094,10 +1079,6 @@ void set_furn_ids() f_fungal_mass = furn_id( "f_fungal_mass" ); f_fungal_clump = furn_id( "f_fungal_clump" ); f_flower_fungal = furn_id( "f_flower_fungal" ); - f_bluebell = furn_id( "f_bluebell" ); - f_dahlia = furn_id( "f_dahlia" ); - f_datura = furn_id( "f_datura" ); - f_dandelion = furn_id( "f_dandelion" ); f_cattails = furn_id( "f_cattails" ); f_lilypad = furn_id( "f_lilypad" ); f_lotus = furn_id( "f_lotus" ); @@ -1112,13 +1093,11 @@ void set_furn_ids() f_fvat_full = furn_id( "f_fvat_full" ); f_wood_keg = furn_id( "f_wood_keg" ); f_standing_tank = furn_id( "f_standing_tank" ); - f_statue = furn_id( "f_statue" ); f_egg_sackbw = furn_id( "f_egg_sackbw" ); f_egg_sackcs = furn_id( "f_egg_sackcs" ); f_egg_sackws = furn_id( "f_egg_sackws" ); f_egg_sacke = furn_id( "f_egg_sacke" ); f_flower_marloss = furn_id( "f_flower_marloss" ); - f_floor_canvas = furn_id( "f_floor_canvas" ); f_kiln_empty = furn_id( "f_kiln_empty" ); f_kiln_full = furn_id( "f_kiln_full" ); f_kiln_metal_empty = furn_id( "f_kiln_metal_empty" ); diff --git a/src/mapdata.h b/src/mapdata.h index 6a4ee3195a788..1d42eca694d0b 100644 --- a/src/mapdata.h +++ b/src/mapdata.h @@ -441,6 +441,7 @@ provided for terrains added by mods. A string equivalent is always present, i.e. t_basalt "t_basalt" */ +// NOLINTNEXTLINE(cata-static-int_id-constants) extern ter_id t_null, t_hole, // Real nothingness; makes you fall a z-level // Ground @@ -567,6 +568,7 @@ runtime index: furn_id furn_id refers to a position in the furnlist[] where the furn_t struct is stored. See note about ter_id above. */ +// NOLINTNEXTLINE(cata-static-int_id-constants) extern furn_id f_null, f_hay, f_cattails, f_lotus, f_lilypad, f_rubble, f_rubble_rock, f_wreckage, f_ash, diff --git a/src/overmap.cpp b/src/overmap.cpp index 0eb6faa9d4163..c32f2effbaa74 100644 --- a/src/overmap.cpp +++ b/src/overmap.cpp @@ -77,13 +77,11 @@ using oter_type_id = int_id; using oter_type_str_id = string_id; //////////////// -static oter_id ot_null, - ot_crater, - ot_field, - ot_forest, - ot_forest_thick, - ot_forest_water, - ot_river_center; +static oter_id ot_null; +static const oter_str_id ot_forest( "ot_forest" ); +static const oter_str_id ot_forest_thick( "ot_forest_thick" ); +static const oter_str_id ot_forest_water( "ot_forest_water" ); +static const oter_str_id ot_river_center( "ot_river_center" ); const oter_type_t oter_type_t::null_type{}; @@ -327,13 +325,6 @@ bool operator!=( const int_id &lhs, const char *rhs ) static void set_oter_ids() // FIXME: constify { ot_null = oter_str_id::NULL_ID(); - // NOT required. - ot_crater = oter_id( "crater" ); - ot_field = oter_id( "field" ); - ot_forest = oter_id( "forest" ); - ot_forest_thick = oter_id( "forest_thick" ); - ot_forest_water = oter_id( "forest_water" ); - ot_river_center = oter_id( "river_center" ); } std::string overmap_land_use_code::get_symbol() const diff --git a/tests/submap_load_test.cpp b/tests/submap_load_test.cpp index 5493f52efba1e..fd2f238484ee8 100644 --- a/tests/submap_load_test.cpp +++ b/tests/submap_load_test.cpp @@ -926,7 +926,7 @@ TEST_CASE( "submap_furniture_load", "[submap][load]" ) REQUIRE( furn_ne == f_bookcase ); REQUIRE( furn_sw == f_dresser ); REQUIRE( furn_se == f_crate_o ); - REQUIRE( furn_ra == STATIC( furn_id( "f_gas_tank" ) ) ); + REQUIRE( furn_ra == STATIC( furn_str_id( "f_gas_tank" ) ) ); // Also, check we have no other furniture for( int x = 0; x < SEEX; ++x ) { @@ -963,11 +963,11 @@ TEST_CASE( "submap_trap_load", "[submap][load]" ) INFO( string_format( "se: %s", trap_se.id().str() ) ); INFO( string_format( "ra: %s", trap_ra.id().str() ) ); // Require to prevent the lower CHECK from being spammy - REQUIRE( trap_nw == STATIC( trap_id( "tr_rollmat" ) ) ); - REQUIRE( trap_ne == STATIC( trap_id( "tr_bubblewrap" ) ) ); - REQUIRE( trap_sw == STATIC( trap_id( "tr_beartrap" ) ) ); - REQUIRE( trap_se == STATIC( trap_id( "tr_funnel" ) ) ); - REQUIRE( trap_ra == STATIC( trap_id( "tr_landmine" ) ) ); + REQUIRE( trap_nw == STATIC( trap_str_id( "tr_rollmat" ) ) ); + REQUIRE( trap_ne == STATIC( trap_str_id( "tr_bubblewrap" ) ) ); + REQUIRE( trap_sw == STATIC( trap_str_id( "tr_beartrap" ) ) ); + REQUIRE( trap_se == STATIC( trap_str_id( "tr_funnel" ) ) ); + REQUIRE( trap_ra == STATIC( trap_str_id( "tr_landmine" ) ) ); // Also, check we have no other traps for( int x = 0; x < SEEX; ++x ) { @@ -1113,12 +1113,12 @@ TEST_CASE( "submap_field_load", "[submap][load]" ) const field &field_sw = sm.get_field( corner_sw ); const field &field_se = sm.get_field( corner_se ); const field &field_ra = sm.get_field( random_pt ); - const field_entry *fd_nw = field_nw.find_field( STATIC( field_type_id( "fd_web" ) ) ); - const field_entry *fd_ne = field_ne.find_field( STATIC( field_type_id( "fd_laser" ) ) ); - const field_entry *fd_sw = field_sw.find_field( STATIC( field_type_id( "fd_electricity" ) ) ); - const field_entry *fd_se = field_se.find_field( STATIC( field_type_id( "fd_acid" ) ) ); - const field_entry *fd_ra = field_ra.find_field( STATIC( field_type_id( "fd_nuke_gas" ) ) ); - const field_entry *fd_ow = field_nw.find_field( STATIC( field_type_id( "fd_smoke" ) ) ); + const field_entry *fd_nw = field_nw.find_field( STATIC( field_type_str_id( "fd_web" ) ) ); + const field_entry *fd_ne = field_ne.find_field( STATIC( field_type_str_id( "fd_laser" ) ) ); + const field_entry *fd_sw = field_sw.find_field( STATIC( field_type_str_id( "fd_electricity" ) ) ); + const field_entry *fd_se = field_se.find_field( STATIC( field_type_str_id( "fd_acid" ) ) ); + const field_entry *fd_ra = field_ra.find_field( STATIC( field_type_str_id( "fd_nuke_gas" ) ) ); + const field_entry *fd_ow = field_nw.find_field( STATIC( field_type_str_id( "fd_smoke" ) ) ); // No nullptrs for me REQUIRE( fd_nw != nullptr ); REQUIRE( fd_ow != nullptr ); diff --git a/tools/clang-tidy-plugin/CMakeLists.txt b/tools/clang-tidy-plugin/CMakeLists.txt index f7e804152cf0e..cf0c237645db7 100644 --- a/tools/clang-tidy-plugin/CMakeLists.txt +++ b/tools/clang-tidy-plugin/CMakeLists.txt @@ -17,6 +17,7 @@ add_library(CataAnalyzerPlugin MODULE PointInitializationCheck.cpp SimplifyPointConstructorsCheck.cpp StaticDeclarationsCheck.cpp + StaticIntIdConstantsCheck.cpp StaticStringIdConstantsCheck.cpp StringLiteralIterator.cpp TestFilenameCheck.cpp diff --git a/tools/clang-tidy-plugin/CataTidyModule.cpp b/tools/clang-tidy-plugin/CataTidyModule.cpp index 8a28b0713e206..b7cb4df22c32c 100644 --- a/tools/clang-tidy-plugin/CataTidyModule.cpp +++ b/tools/clang-tidy-plugin/CataTidyModule.cpp @@ -13,6 +13,7 @@ #include "PointInitializationCheck.h" #include "SimplifyPointConstructorsCheck.h" #include "StaticDeclarationsCheck.h" +#include "StaticIntIdConstantsCheck.h" #include "StaticStringIdConstantsCheck.h" #include "TestFilenameCheck.h" #include "TestsMustRestoreGlobalStateCheck.h" @@ -50,6 +51,8 @@ class CataModule : public ClangTidyModule CheckFactories.registerCheck( "cata-simplify-point-constructors" ); CheckFactories.registerCheck( "cata-static-declarations" ); + CheckFactories.registerCheck( + "cata-static-int_id-constants" ); CheckFactories.registerCheck( "cata-static-string_id-constants" ); CheckFactories.registerCheck( "cata-test-filename" ); diff --git a/tools/clang-tidy-plugin/StaticIntIdConstantsCheck.cpp b/tools/clang-tidy-plugin/StaticIntIdConstantsCheck.cpp new file mode 100644 index 0000000000000..c7e54a18e1b57 --- /dev/null +++ b/tools/clang-tidy-plugin/StaticIntIdConstantsCheck.cpp @@ -0,0 +1,87 @@ +#include "StaticIntIdConstantsCheck.h" +#include "Utils.h" +#include + +using namespace clang::ast_matchers; + +namespace clang +{ +namespace tidy +{ +namespace cata +{ + +void StaticIntIdConstantsCheck::registerMatchers( MatchFinder *Finder ) +{ + Finder->addMatcher( + varDecl( + hasType( + namedDecl( + anyOf( + hasName( "int_id" ), + typedefNameDecl( + hasType( + hasCanonicalType( + hasDeclaration( namedDecl( hasName( "int_id" ) ) ) + ) + ) + ) + ) + ).bind( "typeDecl" ) + ) + ).bind( "varDecl" ), + this + ); +} + +static void CheckConstructor( StaticIntIdConstantsCheck &Check, + const MatchFinder::MatchResult &Result ) +{ + const VarDecl *IntIdVarDecl = Result.Nodes.getNodeAs( "varDecl" ); + const TypeDecl *IntIdTypeDecl = Result.Nodes.getNodeAs( "typeDecl" ); + if( !IntIdVarDecl || !IntIdTypeDecl ) { + return; + } + + StringRef VarName = IntIdVarDecl->getName(); + if( VarName.endswith( "null" ) || VarName.endswith( "NULL" ) ) { + // Null constants are OK because they probably don't vary + return; + } + + const VarDecl *PreviousDecl = dyn_cast_or_null( IntIdVarDecl->getPreviousDecl() ); + + if( PreviousDecl ) { + // Only complain about each variable once + return; + } + + std::string Adjective; + + if( IntIdVarDecl->hasGlobalStorage() ) { + Adjective = "Global"; + } + + if( IntIdVarDecl->isStaticDataMember() || IntIdVarDecl->isStaticLocal() ) { + Adjective = "Static"; + } + + if( Adjective.empty() ) { + return; + } + + Check.diag( + IntIdVarDecl->getBeginLoc(), + "%2 declaration of %0 is dangerous because %1 is a specialization of int_id and it " + "will not update automatically when game data changes. Consider switching to a string_id." + ) << IntIdVarDecl << IntIdTypeDecl << Adjective; +} + +void StaticIntIdConstantsCheck::check( const MatchFinder::MatchResult &Result ) +{ + CheckConstructor( *this, Result ); +} + +} // namespace cata +} // namespace tidy +} // namespace clang diff --git a/tools/clang-tidy-plugin/StaticIntIdConstantsCheck.h b/tools/clang-tidy-plugin/StaticIntIdConstantsCheck.h new file mode 100644 index 0000000000000..0a9ec7ad42ac4 --- /dev/null +++ b/tools/clang-tidy-plugin/StaticIntIdConstantsCheck.h @@ -0,0 +1,32 @@ +#ifndef CATA_TOOLS_CLANG_TIDY_PLUGIN_STATICINTIDCONSTANTSCHECK_H +#define CATA_TOOLS_CLANG_TIDY_PLUGIN_STATICINTIDCONSTANTSCHECK_H + +#include +#include + +#include "ClangTidy.h" + +namespace clang +{ + +namespace tidy +{ +class ClangTidyContext; + +namespace cata +{ + +class StaticIntIdConstantsCheck : public ClangTidyCheck +{ + public: + StaticIntIdConstantsCheck( StringRef Name, ClangTidyContext *Context ) + : ClangTidyCheck( Name, Context ) {} + void registerMatchers( ast_matchers::MatchFinder *Finder ) override; + void check( const ast_matchers::MatchFinder::MatchResult &Result ) override; +}; + +} // namespace cata +} // namespace tidy +} // namespace clang + +#endif // CATA_TOOLS_CLANG_TIDY_PLUGIN_STATICINTIDCONSTANTSCHECK_H diff --git a/tools/clang-tidy-plugin/StaticStringIdConstantsCheck.cpp b/tools/clang-tidy-plugin/StaticStringIdConstantsCheck.cpp index 7249cb0ac137b..a57bb6c145b68 100644 --- a/tools/clang-tidy-plugin/StaticStringIdConstantsCheck.cpp +++ b/tools/clang-tidy-plugin/StaticStringIdConstantsCheck.cpp @@ -68,6 +68,7 @@ static std::string GetPrefixFor( const CXXRecordDecl *Type ) { "mutation_branch", "trait_" }, { "mutation_category_trait", "mutation_category_" }, { "npc_class", "" }, + { "oter_t", "" }, { "quality", "qual_" }, { "Skill", "skill_" }, { "ter_t", "ter_" }, diff --git a/tools/clang-tidy-plugin/test/static-int_id-constants.cpp b/tools/clang-tidy-plugin/test/static-int_id-constants.cpp new file mode 100644 index 0000000000000..b6fc5530e313b --- /dev/null +++ b/tools/clang-tidy-plugin/test/static-int_id-constants.cpp @@ -0,0 +1,50 @@ +// RUN: %check_clang_tidy %s cata-static-int_id-constants %t -- -plugins=%cata_plugin -- -isystem %cata_include + +template +class int_id +{ + public: + int_id(); + explicit int_id( int ); +}; + +struct furn_t; +using furn_id = int_id; + +extern furn_id f_hay; +// CHECK-MESSAGES: warning: Global declaration of 'f_hay' is dangerous because 'furn_id' is a specialization of int_id and it will not update automatically when game data changes. Consider switching to a string_id. [cata-static-int_id-constants] + +// No warning for second decl os same variable. +furn_id f_hay; + +static int_id f_ball_mach; +// CHECK-MESSAGES: warning: Global declaration of 'f_ball_mach' is dangerous because 'int_id' is a specialization of int_id and it will not update automatically when game data changes. Consider switching to a string_id. [cata-static-int_id-constants] + +namespace foo +{ + +const furn_id f_dahlia; +// CHECK-MESSAGES: warning: Global declaration of 'f_dahlia' is dangerous because 'furn_id' is a specialization of int_id and it will not update automatically when game data changes. Consider switching to a string_id. [cata-static-int_id-constants] + +} // namespace foo + +class A +{ + static furn_id f_bluebell; + // CHECK-MESSAGES: warning: Static declaration of 'f_bluebell' is dangerous because 'furn_id' is a specialization of int_id and it will not update automatically when game data changes. Consider switching to a string_id. [cata-static-int_id-constants] + + // No warning for regular class data members + furn_id my_furn; +}; + +void f() +{ + static furn_id f_floor_canvas; + // CHECK-MESSAGES: warning: Static declaration of 'f_floor_canvas' is dangerous because 'furn_id' is a specialization of int_id and it will not update automatically when game data changes. Consider switching to a string_id. [cata-static-int_id-constants] + + // No warning for regular local variables + furn_id f; + + // No warning for other types + static int i; +} From cdd01fd0b2ea7a530648b27354af873a537806f1 Mon Sep 17 00:00:00 2001 From: Qrox Date: Wed, 5 May 2021 22:42:20 +0800 Subject: [PATCH 210/453] Fix json formatter build and string extraction script --- lang/extract_json_strings.py | 10 ++++++++++ src/translations.h | 8 ++++++++ 2 files changed, 18 insertions(+) diff --git a/lang/extract_json_strings.py b/lang/extract_json_strings.py index 5f5c9a9b67205..e6fb4bd5bd9c5 100755 --- a/lang/extract_json_strings.py +++ b/lang/extract_json_strings.py @@ -267,6 +267,13 @@ def extract_construction(item): writestr(outfile, item["pre_note"]) +def extract_effect_on_condition(item): + outfile = get_outfile("effect_on_condition") + extract_talk_effects(item["effect"], outfile) + if "false_effect" in item: + extract_talk_effects(item["false_effect"], outfile) + + def extract_harvest(item): outfile = get_outfile("harvest") if "message" in item: @@ -716,6 +723,8 @@ def extract_talk_effects(effects, outfile): comment = "Nickname for creature '{}'".format( eff["u_buy_monster"]) writestr(outfile, eff["name"], comment=comment) + if "message" in eff: + writestr(outfile, eff["message"]) def extract_talk_response(response, outfile): @@ -995,6 +1004,7 @@ def extract_vehicle_part_category(item): "clothing_mod": extract_clothing_mod, "conduct": extract_achievement, "construction": extract_construction, + "effect_on_condition": extract_effect_on_condition, "effect_type": extract_effect_type, "fault": extract_fault, "GUN": extract_gun, diff --git a/src/translations.h b/src/translations.h index 63061314389c0..6f63bbe0df496 100644 --- a/src/translations.h +++ b/src/translations.h @@ -92,12 +92,16 @@ class local_translation_cache std::string cached_translation; public: const std::string &operator()( const std::string &arg ) { +#ifndef CATA_IN_TOOL if( cached_lang_version != get_current_language_version() || cached_arg != arg ) { cached_lang_version = get_current_language_version(); cached_arg = arg; cached_translation = _translate_internal( arg ); } return cached_translation; +#else + return arg; +#endif } }; @@ -111,6 +115,7 @@ class local_translation_cache const char *cached_translation = nullptr; public: const char *operator()( const char *arg ) { +#ifndef CATA_IN_TOOL if( cached_lang_version != get_current_language_version() || cached_arg != arg ) { cached_lang_version = get_current_language_version(); cached_translation = _translate_internal( arg ); @@ -120,6 +125,9 @@ class local_translation_cache // mimic gettext() behavior: return `arg` if no translation is found // `same_as_arg` is needed to ensure that the current `arg` is returned (not a cached one) return same_as_arg ? arg : cached_translation; +#else + return arg; +#endif } }; From 552d7faee95274f935adfb2898fe88f0898087c5 Mon Sep 17 00:00:00 2001 From: John Bytheway Date: Fri, 14 May 2021 14:45:12 -0400 Subject: [PATCH 211/453] clang-tidy modernize-use-emplace (#48661) * Port code to emplace_back This is clang-tidy making automated changes to convert push_back into emplace_back whenever the argument to push_back is either a constructor call for the type in question of an expression of a type implicitly convertible to the type in question. This should eliminate one move-construction of the inserted object for each call. * Enable clang-tidy modernize-use-emplace --- .clang-tidy | 1 - src/activity_handlers.cpp | 4 +- src/activity_item_handling.cpp | 36 +- src/armor_layers.cpp | 24 +- src/avatar.cpp | 4 +- src/bionics.cpp | 16 +- src/bionics_ui.cpp | 4 +- src/character.cpp | 2 +- src/clzones.cpp | 2 +- src/construction.cpp | 4 +- src/crafting.cpp | 2 +- src/crafting_gui.cpp | 6 +- src/creature.cpp | 8 +- src/debug_menu.cpp | 3 +- src/dialogue_win.cpp | 2 +- src/editmap.cpp | 4 +- src/effect.cpp | 46 +- src/event_field_transformations.cpp | 2 +- src/faction_camp.cpp | 18 +- src/game.cpp | 16 +- src/handle_liquid.cpp | 2 +- src/iexamine.cpp | 24 +- src/inventory_ui.cpp | 4 +- src/item.cpp | 911 ++++++++++++++-------------- src/item_contents.cpp | 8 +- src/item_factory.cpp | 6 +- src/item_pocket.cpp | 32 +- src/iuse.cpp | 28 +- src/iuse_actor.cpp | 12 +- src/iuse_software_lightson.cpp | 6 +- src/iuse_software_minesweeper.cpp | 6 +- src/iuse_software_snake.cpp | 54 +- src/iuse_software_sokoban.cpp | 14 +- src/lightmap.cpp | 2 +- src/line.cpp | 12 +- src/main_menu.cpp | 59 +- src/map.cpp | 6 +- src/map_field.cpp | 20 +- src/map_item_stack.cpp | 2 +- src/mapgen.cpp | 54 +- src/mattack_actors.cpp | 2 +- src/memorial_logger.cpp | 2 +- src/mission.cpp | 8 +- src/mod_manager.cpp | 2 +- src/monattack.cpp | 2 +- src/monexamine.cpp | 8 +- src/mongroup.cpp | 8 +- src/monmove.cpp | 6 +- src/newcharacter.cpp | 8 +- src/npcmove.cpp | 8 +- src/npctalk.cpp | 4 +- src/output.cpp | 4 +- src/overmap.cpp | 36 +- src/overmap_ui.cpp | 2 +- src/panels.cpp | 28 +- src/past_games_info.cpp | 2 +- src/pixel_minimap.cpp | 2 +- src/player.cpp | 4 +- src/player_activity.cpp | 6 +- src/player_display.cpp | 32 +- src/profession.cpp | 2 +- src/proficiency.cpp | 6 +- src/ranged.cpp | 2 +- src/recipe.cpp | 2 +- src/safemode_ui.cpp | 23 +- src/talker_avatar.cpp | 2 +- src/talker_npc.cpp | 28 +- src/translations.cpp | 2 +- src/veh_interact.cpp | 6 +- src/veh_type.cpp | 9 +- src/vehicle_use.cpp | 46 +- src/wish.cpp | 2 +- src/worldfactory.cpp | 10 +- tests/behavior_test.cpp | 2 +- tests/crafting_test.cpp | 6 +- tests/encumbrance_test.cpp | 2 +- tests/generic_factory_test.cpp | 4 +- tests/invlet_test.cpp | 6 +- tests/iteminfo_test.cpp | 2 +- tests/modify_morale_test.cpp | 18 +- tests/npc_talk_test.cpp | 2 +- tests/player_helpers.cpp | 2 +- tests/ranged_balance_test.cpp | 2 +- tests/reading_test.cpp | 12 +- tests/reload_option_test.cpp | 8 +- tests/reloading_test.cpp | 2 +- tests/string_ids_test.cpp | 6 +- tests/vehicle_part_test.cpp | 6 +- tests/visitable_remove_test.cpp | 2 +- 89 files changed, 929 insertions(+), 933 deletions(-) diff --git a/.clang-tidy b/.clang-tidy index 4f11f89b67c59..1e041e5b16011 100644 --- a/.clang-tidy +++ b/.clang-tidy @@ -53,7 +53,6 @@ readability-*,\ -modernize-pass-by-value,\ -modernize-return-braced-init-list,\ -modernize-use-default-member-init,\ --modernize-use-emplace,\ -performance-unnecessary-value-param,\ -readability-else-after-return,\ -readability-implicit-bool-conversion,\ diff --git a/src/activity_handlers.cpp b/src/activity_handlers.cpp index b4a45eef7f360..355fd41ad6f99 100644 --- a/src/activity_handlers.cpp +++ b/src/activity_handlers.cpp @@ -1555,7 +1555,7 @@ void activity_handlers::fill_liquid_do_turn( player_activity *act, player *p ) act_ref.set_to_null(); } else { if( act_ref.str_values.empty() ) { - act_ref.str_values.push_back( std::string() ); + act_ref.str_values.emplace_back( ); } act_ref.str_values.at( 0 ) = serialize( liquid ); } @@ -3951,7 +3951,7 @@ void activity_handlers::fertilize_plot_do_turn( player_activity *act, player *p auto check_fertilizer = [&]( bool ask_user = true ) -> void { if( act->str_values.empty() ) { - act->str_values.push_back( "" ); + act->str_values.emplace_back( "" ); } fertilizer = itype_id( act->str_values[0] ); diff --git a/src/activity_item_handling.cpp b/src/activity_item_handling.cpp index 2224b514502b3..9695de399a8da 100644 --- a/src/activity_item_handling.cpp +++ b/src/activity_item_handling.cpp @@ -513,13 +513,13 @@ void activity_handlers::washing_finish( player_activity *act, player *p ) } std::vector comps; - comps.push_back( item_comp( itype_water, required.water ) ); - comps.push_back( item_comp( itype_water_clean, required.water ) ); + comps.emplace_back( itype_water, required.water ); + comps.emplace_back( itype_water_clean, required.water ); p->consume_items( comps, 1, is_liquid_crafting_component ); std::vector comps1; - comps1.push_back( item_comp( itype_soap, required.cleanser ) ); - comps1.push_back( item_comp( itype_detergent, required.cleanser ) ); + comps1.emplace_back( itype_soap, required.cleanser ); + comps1.emplace_back( itype_detergent, required.cleanser ); p->consume_items( comps1 ); p->add_msg_if_player( m_good, _( "You washed your items." ) ); @@ -1469,7 +1469,7 @@ static std::vector> requirements_map( player continue; } } - requirement_map.push_back( std::make_tuple( point_elem, map_elem.first, map_elem.second ) ); + requirement_map.emplace_back( point_elem, map_elem.first, map_elem.second ); } } // Ok we now have a list of all the items that match the requirements, their points, and a quantity for each one. @@ -1493,8 +1493,8 @@ static std::vector> requirements_map( player } if( item_quantity >= quantity_required ) { // it's just this spot that can fulfil the requirement on its own - final_map.push_back( std::make_tuple( pos_here, item_here, std::min( quantity_here, - quantity_required ) ) ); + final_map.emplace_back( pos_here, item_here, std::min( quantity_here, + quantity_required ) ); if( quantity_here >= quantity_required ) { line_found = true; break; @@ -1520,10 +1520,10 @@ static std::vector> requirements_map( player int quantity_here2 = std::get<2>( *it ); if( comp_elem.type == item_here2 ) { if( quantity_here2 >= remainder ) { - final_map.push_back( std::make_tuple( pos_here2, item_here2, remainder ) ); + final_map.emplace_back( pos_here2, item_here2, remainder ); line_found = true; } else { - final_map.push_back( std::make_tuple( pos_here2, item_here2, remainder ) ); + final_map.emplace_back( pos_here2, item_here2, remainder ); remainder -= quantity_here2; } } @@ -1551,8 +1551,8 @@ static std::vector> requirements_map( player } if( item_quantity >= quantity_required ) { // it's just this spot that can fulfil the requirement on its own - final_map.push_back( std::make_tuple( pos_here, item_here, std::min( quantity_here, - quantity_required ) ) ); + final_map.emplace_back( pos_here, item_here, std::min( quantity_here, + quantity_required ) ); if( quantity_here >= quantity_required ) { line_found = true; break; @@ -1578,10 +1578,10 @@ static std::vector> requirements_map( player int quantity_here2 = std::get<2>( *it ); if( comp_elem.type == item_here2 ) { if( quantity_here2 >= remainder ) { - final_map.push_back( std::make_tuple( pos_here2, item_here2, remainder ) ); + final_map.emplace_back( pos_here2, item_here2, remainder ); line_found = true; } else { - final_map.push_back( std::make_tuple( pos_here2, item_here2, remainder ) ); + final_map.emplace_back( pos_here2, item_here2, remainder ); remainder -= quantity_here2; } } @@ -1604,7 +1604,7 @@ static std::vector> requirements_map( player item test_item = item( item_here, calendar::turn_zero ); if( test_item.has_quality( tool_qual, qual_level ) ) { // it's just this spot that can fulfil the requirement on its own - final_map.push_back( std::make_tuple( pos_here, item_here, 1 ) ); + final_map.emplace_back( pos_here, item_here, 1 ); line_found = true; break; } @@ -2002,14 +2002,14 @@ void activity_on_turn_move_loot( player_activity &act, player &p ) src_veh = &vp->vehicle(); src_part = vp->part_index(); for( auto &it : src_veh->get_items( src_part ) ) { - items.push_back( std::make_pair( &it, true ) ); + items.emplace_back( &it, true ); } } else { src_veh = nullptr; src_part = -1; } for( item &it : here.i_at( src_loc ) ) { - items.push_back( std::make_pair( &it, false ) ); + items.emplace_back( &it, false ); } //Skip items that have already been processed @@ -2158,7 +2158,7 @@ static bool mine_activity( player &p, const tripoint &src_loc ) moves /= 2; } p.assign_activity( powered ? ACT_JACKHAMMER : ACT_PICKAXE, moves ); - p.activity.targets.push_back( item_location( p, chosen_item ) ); + p.activity.targets.emplace_back( p, chosen_item ); p.activity.placement = here.getabs( src_loc ); return true; @@ -2648,7 +2648,7 @@ static bool generic_multi_activity_do( player &p, const activity_id &act_id, item *best_rod = p.best_quality_item( qual_FISHING ); p.assign_activity( ACT_FISH, to_moves( 5_hours ), 0, 0, best_rod->tname() ); - p.activity.targets.push_back( item_location( p, best_rod ) ); + p.activity.targets.emplace_back( p, best_rod ); p.activity.coord_set = g->get_fishable_locations( ACTIVITY_SEARCH_DISTANCE, src_loc ); return false; } else if( reason == do_activity_reason::NEEDS_MINING ) { diff --git a/src/armor_layers.cpp b/src/armor_layers.cpp index 7883df1a5f18b..65583dffff262 100644 --- a/src/armor_layers.cpp +++ b/src/armor_layers.cpp @@ -330,40 +330,40 @@ std::vector clothing_flags_description( const item &worn_item ) std::vector description_stack; if( worn_item.has_flag( flag_FIT ) ) { - description_stack.push_back( _( "It fits you well." ) ); + description_stack.emplace_back( _( "It fits you well." ) ); } else if( worn_item.has_flag( flag_VARSIZE ) ) { - description_stack.push_back( _( "It could be refitted." ) ); + description_stack.emplace_back( _( "It could be refitted." ) ); } if( worn_item.has_flag( flag_HOOD ) ) { - description_stack.push_back( _( "It has a hood." ) ); + description_stack.emplace_back( _( "It has a hood." ) ); } if( worn_item.has_flag( flag_POCKETS ) ) { - description_stack.push_back( _( "It has pockets." ) ); + description_stack.emplace_back( _( "It has pockets." ) ); } if( worn_item.has_flag( flag_WATERPROOF ) ) { - description_stack.push_back( _( "It is waterproof." ) ); + description_stack.emplace_back( _( "It is waterproof." ) ); } if( worn_item.has_flag( flag_WATER_FRIENDLY ) ) { - description_stack.push_back( _( "It is water friendly." ) ); + description_stack.emplace_back( _( "It is water friendly." ) ); } if( worn_item.has_flag( flag_FANCY ) ) { - description_stack.push_back( _( "It looks fancy." ) ); + description_stack.emplace_back( _( "It looks fancy." ) ); } if( worn_item.has_flag( flag_SUPER_FANCY ) ) { - description_stack.push_back( _( "It looks really fancy." ) ); + description_stack.emplace_back( _( "It looks really fancy." ) ); } if( worn_item.has_flag( flag_FLOTATION ) ) { - description_stack.push_back( _( "You will not drown today." ) ); + description_stack.emplace_back( _( "You will not drown today." ) ); } if( worn_item.has_flag( flag_OVERSIZE ) ) { - description_stack.push_back( _( "It is very bulky." ) ); + description_stack.emplace_back( _( "It is very bulky." ) ); } if( worn_item.has_flag( flag_SWIM_GOGGLES ) ) { - description_stack.push_back( _( "It helps you to see clearly underwater." ) ); + description_stack.emplace_back( _( "It helps you to see clearly underwater." ) ); } if( worn_item.has_flag( flag_SEMITANGIBLE ) ) { - description_stack.push_back( _( "It can occupy the same space as other things." ) ); + description_stack.emplace_back( _( "It can occupy the same space as other things." ) ); } return description_stack; diff --git a/src/avatar.cpp b/src/avatar.cpp index a71170d7a4be0..21fb23ce969ed 100644 --- a/src/avatar.cpp +++ b/src/avatar.cpp @@ -745,11 +745,11 @@ void avatar::do_read( item &book ) player *n = g->find_npc( character_id( activity.values[i] ) ); if( n != nullptr ) { const std::string &s = activity.get_str_value( i, "1" ); - learners.push_back( { n, strtod( s.c_str(), nullptr ) } ); + learners.emplace_back( n, strtod( s.c_str(), nullptr ) ); } // Otherwise they must have died/teleported or something } - learners.push_back( { this, 1.0 } ); + learners.emplace_back( this, 1.0 ); //whether to continue reading or not bool continuous = false; // NPCs who learned a little about the skill diff --git a/src/bionics.cpp b/src/bionics.cpp index e80aaff137285..a064a5ce3877e 100644 --- a/src/bionics.cpp +++ b/src/bionics.cpp @@ -2199,13 +2199,13 @@ bool Character::uninstall_bionic( const bionic_id &b_id, player &installer, bool activity.values.push_back( success ); activity.values.push_back( units::to_kilojoule( b_id->capacity ) ); activity.values.push_back( pl_skill ); - activity.str_values.push_back( "uninstall" ); + activity.str_values.emplace_back( "uninstall" ); activity.str_values.push_back( b_id.str() ); - activity.str_values.push_back( "" ); // installer_name is unused for uninstall + activity.str_values.emplace_back( "" ); // installer_name is unused for uninstall if( autodoc ) { - activity.str_values.push_back( "true" ); + activity.str_values.emplace_back( "true" ); } else { - activity.str_values.push_back( "false" ); + activity.str_values.emplace_back( "false" ); } for( const std::pair &elem : b_id->occupied_bodyparts ) { add_effect( effect_under_operation, difficulty * 20_minutes, elem.first.id(), true, difficulty ); @@ -2486,18 +2486,18 @@ bool Character::install_bionics( const itype &type, player &installer, bool auto activity.values.push_back( success ); activity.values.push_back( units::to_millijoule( bioid->capacity ) ); activity.values.push_back( pl_skill ); - activity.str_values.push_back( "install" ); + activity.str_values.emplace_back( "install" ); activity.str_values.push_back( bioid.str() ); if( installer.has_trait( trait_PROF_MED ) || installer.has_trait( trait_PROF_AUTODOC ) ) { activity.str_values.push_back( installer.disp_name( true ) ); } else { - activity.str_values.push_back( "NOT_MED" ); + activity.str_values.emplace_back( "NOT_MED" ); } if( autodoc ) { - activity.str_values.push_back( "true" ); + activity.str_values.emplace_back( "true" ); } else { - activity.str_values.push_back( "false" ); + activity.str_values.emplace_back( "false" ); } for( const std::pair &elem : bioid->occupied_bodyparts ) { add_effect( effect_under_operation, difficulty * 20_minutes, elem.first.id(), true, difficulty ); diff --git a/src/bionics_ui.cpp b/src/bionics_ui.cpp index f02653a929e2a..96c6b08f17428 100644 --- a/src/bionics_ui.cpp +++ b/src/bionics_ui.cpp @@ -314,10 +314,10 @@ static std::string build_bionic_poweronly_string( const bionic &bio ) bio_data.charge_time ) ); } if( bio_data.has_flag( STATIC( json_character_flag( "BIONIC_TOGGLED" ) ) ) ) { - properties.push_back( bio.powered ? _( "ON" ) : _( "OFF" ) ); + properties.emplace_back( bio.powered ? _( "ON" ) : _( "OFF" ) ); } if( bio.incapacitated_time > 0_turns ) { - properties.push_back( _( "(incapacitated)" ) ); + properties.emplace_back( _( "(incapacitated)" ) ); } if( bio.get_safe_fuel_thresh() > 0 && ( !bio.info().fuel_opts.empty() || bio.info().is_remote_fueled ) ) { diff --git a/src/character.cpp b/src/character.cpp index 5660cf0508a31..3c7655e57c8fa 100644 --- a/src/character.cpp +++ b/src/character.cpp @@ -3493,7 +3493,7 @@ std::vector Character::find_reloadables() node->remaining_ammo_capacity() > 0; } if( reloadable ) { - reloadables.push_back( item_location( *this, node ) ); + reloadables.emplace_back( *this, node ); } return VisitResponse::NEXT; } ); diff --git a/src/clzones.cpp b/src/clzones.cpp index 177fc14c0bd1c..1e4c5319441cb 100644 --- a/src/clzones.cpp +++ b/src/clzones.cpp @@ -1240,7 +1240,7 @@ void zone_manager::zone_edited( zone_data &zone ) } } //Add it to the list of changed zones - changed_vzones.push_back( std::make_pair( zone_data( zone ), &zone ) ); + changed_vzones.emplace_back( zone_data( zone ), &zone ); } } diff --git a/src/construction.cpp b/src/construction.cpp index 9b6ebf9726bc2..d083073c34a9d 100644 --- a/src/construction.cpp +++ b/src/construction.cpp @@ -519,7 +519,7 @@ construction_id construction_menu( const bool blueprint ) } current_buffer_location += construct_buffers[i].size(); if( i < construct_buffers.size() - 1 ) { - full_construct_buffer.push_back( std::string() ); + full_construct_buffer.emplace_back( ); current_buffer_location++; } } @@ -1781,7 +1781,7 @@ void finalize_constructions() if( !vp.has_flag( flag_INITIAL_PART ) ) { continue; } - frame_items.push_back( item_comp( vp.base_item, 1 ) ); + frame_items.emplace_back( vp.base_item, 1 ); } if( frame_items.empty() ) { diff --git a/src/crafting.cpp b/src/crafting.cpp index d46768cb2e0e5..9b6062e8316ae 100644 --- a/src/crafting.cpp +++ b/src/crafting.cpp @@ -2314,7 +2314,7 @@ void Character::disassemble_all( bool one_pass ) bool found_any = false; std::vector to_disassemble; for( item &it : get_map().i_at( pos() ) ) { - to_disassemble.push_back( item_location( map_cursor( pos() ), &it ) ); + to_disassemble.emplace_back( map_cursor( pos() ), &it ); } for( item_location &it_loc : to_disassemble ) { // Prevent disassembling an in process disassembly because it could have been created by a previous iteration of this loop diff --git a/src/crafting_gui.cpp b/src/crafting_gui.cpp index a5629e5723052..dc8ea31b791f0 100644 --- a/src/crafting_gui.cpp +++ b/src/crafting_gui.cpp @@ -680,7 +680,7 @@ const recipe *select_crafting_recipe( int &batch_size_out ) current.clear(); for( int i = 1; i <= 50; i++ ) { current.push_back( chosen ); - available.push_back( availability( chosen, i ) ); + available.emplace_back( chosen, i ); } } else { static_popup popup; @@ -1091,7 +1091,7 @@ std::string peek_related_recipe( const recipe *current, const recipe_subset &ava const requirement_data &req = current->simple_requirements(); for( const std::vector &comp_list : req.get_components() ) { for( const item_comp &a : comp_list ) { - related_components.push_back( { a.type, item::nname( a.type, 1 ) } ); + related_components.emplace_back( a.type, item::nname( a.type, 1 ) ); } } std::sort( related_components.begin(), related_components.end(), compare_second ); @@ -1104,7 +1104,7 @@ std::string peek_related_recipe( const recipe *current, const recipe_subset &ava get_player_character().get_learned_recipes().of_component( tid ); for( const auto &b : known_recipes ) { if( available.contains( b ) ) { - related_results.push_back( { b->result(), b->result_name() } ); + related_results.emplace_back( b->result(), b->result_name() ); } } std::stable_sort( related_results.begin(), related_results.end(), compare_second ); diff --git a/src/creature.cpp b/src/creature.cpp index 6d8a4f4651fc0..583b9ec6ceb60 100644 --- a/src/creature.cpp +++ b/src/creature.cpp @@ -1427,7 +1427,7 @@ void Creature::process_effects() // Add any effects that others remove to the removal list for( const auto &removed_effect : _it.second.get_removes_effects() ) { rem_ids.push_back( removed_effect ); - rem_bps.push_back( bodypart_str_id::NULL_ID() ); + rem_bps.emplace_back( bodypart_str_id::NULL_ID() ); } effect &e = _it.second; const int prev_int = e.get_intensity(); @@ -2115,7 +2115,7 @@ std::vector Creature::get_all_body_parts( get_body_part_flags flags if( only_main && elem.first->main_part != elem.first ) { continue; } - all_bps.push_back( elem.first ); + all_bps.emplace_back( elem.first ); } if( flags & get_body_part_flags::sorted ) { @@ -2596,11 +2596,11 @@ void Creature::describe_infrared( std::vector &buf ) const size_str = "invalid"; break; } - buf.push_back( _( "You see a figure radiating heat." ) ); + buf.emplace_back( _( "You see a figure radiating heat." ) ); buf.push_back( string_format( _( "It is %s in size." ), size_str ) ); } void Creature::describe_specials( std::vector &buf ) const { - buf.push_back( _( "You sense a creature here." ) ); + buf.emplace_back( _( "You sense a creature here." ) ); } diff --git a/src/debug_menu.cpp b/src/debug_menu.cpp index 850b391a78caf..ff26a6bef399e 100644 --- a/src/debug_menu.cpp +++ b/src/debug_menu.cpp @@ -1974,7 +1974,8 @@ static void debug_menu_game_state() std::vector> sorted; sorted.reserve( m_flag::MF_MAX ); for( int f = 0; f < m_flag::MF_MAX; f++ ) { - sorted.push_back( {static_cast( f ), MonsterGenerator::generator().m_flag_usage_stats[f]} ); + sorted.emplace_back( static_cast( f ), + MonsterGenerator::generator().m_flag_usage_stats[f] ); } std::sort( sorted.begin(), sorted.end(), []( std::pair a, std::pair b ) { return a.second != b.second ? a.second > b.second : a.first < b.first; diff --git a/src/dialogue_win.cpp b/src/dialogue_win.cpp index 7a8f6a3c331c6..2d7681d3fb623 100644 --- a/src/dialogue_win.cpp +++ b/src/dialogue_win.cpp @@ -71,7 +71,7 @@ size_t dialogue_window::add_to_history( const std::string &text ) // Empty line between lines of dialogue void dialogue_window::add_history_separator() { - history.push_back( "" ); + history.emplace_back( "" ); } void dialogue_window::print_history( const size_t hilight_lines ) diff --git a/src/editmap.cpp b/src/editmap.cpp index eeed0847399bc..e658635e93d46 100644 --- a/src/editmap.cpp +++ b/src/editmap.cpp @@ -2095,7 +2095,7 @@ void editmap::mapgen_retarget() for( int y = target.y - SEEY + 1; y < target.y + SEEY + 1; y++ ) { if( x == target.x - SEEX + 1 || x == target.x + SEEX || y == target.y - SEEY + 1 || y == target.y + SEEY ) { - target_list.push_back( tripoint( x, y, target.z ) ); + target_list.emplace_back( x, y, target.z ); } } } @@ -2161,7 +2161,7 @@ void editmap::edit_mapgen() for( int y = target.y - SEEY + 1; y < target.y + SEEY + 1; y++ ) { if( x == target.x - SEEX + 1 || x == target.x + SEEX || y == target.y - SEEY + 1 || y == target.y + SEEY ) { - target_list.push_back( tripoint( x, y, target.z ) ); + target_list.emplace_back( x, y, target.z ); } } } diff --git a/src/effect.cpp b/src/effect.cpp index fad0aae5fc147..e5d4b91774938 100644 --- a/src/effect.cpp +++ b/src/effect.cpp @@ -517,7 +517,7 @@ bool effect_type::load_decay_msgs( const JsonObject &jo, const std::string &memb } else { rate = m_neutral; } - decay_msgs.push_back( std::make_pair( msg, rate ) ); + decay_msgs.emplace_back( msg, rate ); } return true; } @@ -627,32 +627,32 @@ std::string effect::disp_desc( bool reduced ) const // place to add them. int val = 0; val = get_avg_mod( "PAIN", reduced ); - values.push_back( desc_freq( get_percentage( "PAIN", val, reduced ), val, _( "pain" ), - _( "pain" ) ) ); + values.emplace_back( get_percentage( "PAIN", val, reduced ), val, _( "pain" ), + _( "pain" ) ); val = get_avg_mod( "HURT", reduced ); - values.push_back( desc_freq( get_percentage( "HURT", val, reduced ), val, _( "damage" ), - _( "damage" ) ) ); + values.emplace_back( get_percentage( "HURT", val, reduced ), val, _( "damage" ), + _( "damage" ) ); val = get_avg_mod( "STAMINA", reduced ); - values.push_back( desc_freq( get_percentage( "STAMINA", val, reduced ), val, - _( "stamina recovery" ), _( "fatigue" ) ) ); + values.emplace_back( get_percentage( "STAMINA", val, reduced ), val, + _( "stamina recovery" ), _( "fatigue" ) ); val = get_avg_mod( "THIRST", reduced ); - values.push_back( desc_freq( get_percentage( "THIRST", val, reduced ), val, _( "thirst" ), - _( "quench" ) ) ); + values.emplace_back( get_percentage( "THIRST", val, reduced ), val, _( "thirst" ), + _( "quench" ) ); val = get_avg_mod( "HUNGER", reduced ); - values.push_back( desc_freq( get_percentage( "HUNGER", val, reduced ), val, _( "hunger" ), - _( "sate" ) ) ); + values.emplace_back( get_percentage( "HUNGER", val, reduced ), val, _( "hunger" ), + _( "sate" ) ); val = get_avg_mod( "FATIGUE", reduced ); - values.push_back( desc_freq( get_percentage( "FATIGUE", val, reduced ), val, _( "sleepiness" ), - _( "rest" ) ) ); + values.emplace_back( get_percentage( "FATIGUE", val, reduced ), val, _( "sleepiness" ), + _( "rest" ) ); val = get_avg_mod( "COUGH", reduced ); - values.push_back( desc_freq( get_percentage( "COUGH", val, reduced ), val, _( "coughing" ), - _( "coughing" ) ) ); + values.emplace_back( get_percentage( "COUGH", val, reduced ), val, _( "coughing" ), + _( "coughing" ) ); val = get_avg_mod( "VOMIT", reduced ); - values.push_back( desc_freq( get_percentage( "VOMIT", val, reduced ), val, _( "vomiting" ), - _( "vomiting" ) ) ); + values.emplace_back( get_percentage( "VOMIT", val, reduced ), val, _( "vomiting" ), + _( "vomiting" ) ); val = get_avg_mod( "SLEEP", reduced ); - values.push_back( desc_freq( get_percentage( "SLEEP", val, reduced ), val, _( "blackouts" ), - _( "blackouts" ) ) ); + values.emplace_back( get_percentage( "SLEEP", val, reduced ), val, _( "blackouts" ), + _( "blackouts" ) ); for( auto &i : values ) { if( i.val > 0 ) { @@ -1312,16 +1312,16 @@ void load_effect_type( const JsonObject &jo ) jo.read( "blood_analysis_description", new_etype.blood_analysis_description ); for( auto &&f : jo.get_string_array( "resist_traits" ) ) { // *NOPAD* - new_etype.resist_traits.push_back( trait_id( f ) ); + new_etype.resist_traits.emplace_back( f ); } for( auto &&f : jo.get_string_array( "resist_effects" ) ) { // *NOPAD* - new_etype.resist_effects.push_back( efftype_id( f ) ); + new_etype.resist_effects.emplace_back( f ); } for( auto &&f : jo.get_string_array( "removes_effects" ) ) { // *NOPAD* - new_etype.removes_effects.push_back( efftype_id( f ) ); + new_etype.removes_effects.emplace_back( f ); } for( auto &&f : jo.get_string_array( "blocks_effects" ) ) { // *NOPAD* - new_etype.blocks_effects.push_back( efftype_id( f ) ); + new_etype.blocks_effects.emplace_back( f ); } if( jo.has_string( "max_duration" ) ) { diff --git a/src/event_field_transformations.cpp b/src/event_field_transformations.cpp index 0dc6badbd3030..4699b19ac8a4e 100644 --- a/src/event_field_transformations.cpp +++ b/src/event_field_transformations.cpp @@ -60,7 +60,7 @@ static std::vector species_of_monster( const cata_variant &v ) std::vector result; result.reserve( species.size() ); for( const species_id &s : species ) { - result.push_back( cata_variant( s ) ); + result.emplace_back( s ); } return result; } diff --git a/src/faction_camp.cpp b/src/faction_camp.cpp index 30593e04732d9..06122ffd7d1a1 100644 --- a/src/faction_camp.cpp +++ b/src/faction_camp.cpp @@ -2783,10 +2783,10 @@ void basecamp::recruit_return( const std::string &task, int score ) description += _( "Select an option:" ); std::vector rec_options; - rec_options.push_back( _( "Increase Food" ) ); - rec_options.push_back( _( "Decrease Food" ) ); - rec_options.push_back( _( "Make Offer" ) ); - rec_options.push_back( _( "Not Interested" ) ); + rec_options.emplace_back( _( "Increase Food" ) ); + rec_options.emplace_back( _( "Decrease Food" ) ); + rec_options.emplace_back( _( "Make Offer" ) ); + rec_options.emplace_back( _( "Not Interested" ) ); rec_m = uilist( description, rec_options ); if( rec_m < 0 || rec_m == 3 || static_cast( rec_m ) >= rec_options.size() ) { @@ -3297,19 +3297,19 @@ void om_range_mark( const tripoint_abs_omt &origin, int range, bool add_notes, std::vector note_pts; //North Limit for( int x = origin.x() - range; x < origin.x() + range + 1; x++ ) { - note_pts.push_back( tripoint_abs_omt( x, origin.y() - range, origin.z() ) ); + note_pts.emplace_back( x, origin.y() - range, origin.z() ); } //South for( int x = origin.x() - range; x < origin.x() + range + 1; x++ ) { - note_pts.push_back( tripoint_abs_omt( x, origin.y() + range, origin.z() ) ); + note_pts.emplace_back( x, origin.y() + range, origin.z() ); } //West for( int y = origin.y() - range; y < origin.y() + range + 1; y++ ) { - note_pts.push_back( tripoint_abs_omt( origin.x() - range, y, origin.z() ) ); + note_pts.emplace_back( origin.x() - range, y, origin.z() ); } //East for( int y = origin.y() - range; y < origin.y() + range + 1; y++ ) { - note_pts.push_back( tripoint_abs_omt( origin.x() + range, y, origin.z() ) ); + note_pts.emplace_back( origin.x() + range, y, origin.z() ); } for( auto pt : note_pts ) { @@ -3541,7 +3541,7 @@ std::vector> talk_function::om_building std::string om_rnear_id = omt_rnear.id().c_str(); if( !purge || ( om_rnear_id.find( "faction_base_" ) != std::string::npos && om_rnear_id.find( "faction_base_camp" ) == std::string::npos ) ) { - om_camp_region.push_back( std::make_pair( om_rnear_id, omt_near_pos ) ); + om_camp_region.emplace_back( om_rnear_id, omt_near_pos ); } } return om_camp_region; diff --git a/src/game.cpp b/src/game.cpp index a2de0bcc7a5c7..022e1f27532b8 100644 --- a/src/game.cpp +++ b/src/game.cpp @@ -862,15 +862,15 @@ vehicle *game::place_vehicle_nearby( if( search_types.empty() ) { vehicle veh( id ); if( veh.max_ground_velocity() > 0 ) { - search_types.push_back( "road" ); - search_types.push_back( "field" ); + search_types.emplace_back( "road" ); + search_types.emplace_back( "field" ); } else if( veh.can_float() ) { - search_types.push_back( "river" ); - search_types.push_back( "lake" ); + search_types.emplace_back( "river" ); + search_types.emplace_back( "lake" ); } else { // some default locations - search_types.push_back( "road" ); - search_types.push_back( "field" ); + search_types.emplace_back( "road" ); + search_types.emplace_back( "field" ); } } for( const std::string &search_type : search_types ) { @@ -10144,7 +10144,7 @@ point game::place_player( const tripoint &dest_loc ) u.assign_activity( activity_id( "ACT_PULP" ), calendar::INDEFINITELY_LONG, 0 ); u.activity.placement = m.getabs( pos ); u.activity.auto_resume = true; - u.activity.str_values.push_back( "auto_pulp_no_acid" ); + u.activity.str_values.emplace_back( "auto_pulp_no_acid" ); return; } } @@ -12393,7 +12393,7 @@ game::Creature_range::Creature_range( game &game_ref ) : u( &game_ref.u, []( pla const auto &monsters = game_ref.critter_tracker->get_monsters_list(); items.insert( items.end(), monsters.begin(), monsters.end() ); items.insert( items.end(), game_ref.active_npc.begin(), game_ref.active_npc.end() ); - items.push_back( u ); + items.emplace_back( u ); } game::npc_range::npc_range( game &game_ref ) diff --git a/src/handle_liquid.cpp b/src/handle_liquid.cpp index dac6d78424828..cea3863606784 100644 --- a/src/handle_liquid.cpp +++ b/src/handle_liquid.cpp @@ -86,7 +86,7 @@ static void serialize_liquid_target( player_activity &act, const item_location & act.values.push_back( static_cast( liquid_target_type::CONTAINER ) ); act.values.push_back( 0 ); // dummy act.targets.push_back( container_item ); - act.coords.push_back( tripoint() ); // dummy + act.coords.emplace_back( ); // dummy } static void serialize_liquid_target( player_activity &act, const tripoint &pos ) diff --git a/src/iexamine.cpp b/src/iexamine.cpp index bb4387ec497d3..21340ebaa2ae0 100644 --- a/src/iexamine.cpp +++ b/src/iexamine.cpp @@ -748,7 +748,7 @@ class atm_menu // the next turn. Putting this here makes sure there will be something to be // done next turn. u.assign_activity( ACT_ATM, 0, transfer_all_money ); - u.activity.targets.push_back( item_location( u, dst ) ); + u.activity.targets.emplace_back( u, dst ); break; } // should we check for max capacity here? @@ -1384,7 +1384,7 @@ void iexamine::pit( player &p, const tripoint &examp ) return; } std::vector planks; - planks.push_back( item_comp( itype_2x4, 1 ) ); + planks.emplace_back( itype_2x4, 1 ); map &here = get_map(); if( query_yn( _( "Place a plank over the pit?" ) ) ) { @@ -3565,7 +3565,7 @@ void iexamine::tree_maple( player &p, const tripoint &examp ) } std::vector comps; - comps.push_back( item_comp( itype_tree_spile, 1 ) ); + comps.emplace_back( itype_tree_spile, 1 ); p.consume_items( comps, 1, is_crafting_component ); p.mod_moves( -to_moves( 20_seconds ) ); @@ -4032,7 +4032,7 @@ void iexamine::sign( player &p, const tripoint &examp ) } ); tools.reserve( filter.size() ); for( const item *writing_item : filter ) { - tools.push_back( tool_comp( writing_item->typeId(), 1 ) ); + tools.emplace_back( writing_item->typeId(), 1 ); } if( !tools.empty() ) { @@ -4757,9 +4757,9 @@ void iexamine::autodoc( player &p, const tripoint &examp ) } case 2: { std::vector choice_names; - choice_names.push_back( _( "Personality_Override" ) ); + choice_names.emplace_back( _( "Personality_Override" ) ); for( size_t i = 0; i < 6; i++ ) { - choice_names.push_back( _( "C0RR#PTED?D#TA" ) ); + choice_names.emplace_back( _( "C0RR#PTED?D#TA" ) ); } int choice_index = uilist( _( "Choose bionic to uninstall" ), choice_names ); if( choice_index == 0 ) { @@ -4838,7 +4838,7 @@ void iexamine::autodoc( player &p, const tripoint &examp ) } ); for( const item *anesthesia_item : a_filter ) { if( anesthesia_item->ammo_remaining() >= 1 ) { - anesth_kit.push_back( tool_comp( anesthesia_item->typeId(), 1 ) ); + anesth_kit.emplace_back( anesthesia_item->typeId(), 1 ); drug_count += anesthesia_item->ammo_remaining(); } } @@ -4868,7 +4868,7 @@ void iexamine::autodoc( player &p, const tripoint &examp ) if( !install_programs.empty() ) { has_install_program = true; - progs.push_back( item_comp( install_programs[0]->typeId(), 1 ) ); + progs.emplace_back( install_programs[0]->typeId(), 1 ); } const int weight = units::to_kilogram( patient.bodyweight() ) / 10; @@ -5428,7 +5428,7 @@ static void smoker_load_food( player &p, const tripoint &examp, entries.push_back( smokable_item ); } names.push_back( item::nname( smokable_item->typeId(), 1 ) ); - comps.push_back( item_comp( smokable_item->typeId(), count ) ); + comps.emplace_back( smokable_item->typeId(), count ); } } @@ -5477,7 +5477,7 @@ static void smoker_load_food( player &p, const tripoint &examp, // reload comps with chosen items and quantity comps.clear(); - comps.push_back( item_comp( what->typeId(), amount ) ); + comps.emplace_back( what->typeId(), amount ); Character &player_character = get_player_character(); // select from where to get the items from and place them @@ -5537,7 +5537,7 @@ static void mill_load_food( player &p, const tripoint &examp, entries.push_back( millable_item ); } names.push_back( item::nname( millable_item->typeId(), 1 ) ); - comps.push_back( item_comp( millable_item->typeId(), count ) ); + comps.emplace_back( millable_item->typeId(), count ); } } @@ -5586,7 +5586,7 @@ static void mill_load_food( player &p, const tripoint &examp, // reload comps with chosen items and quantity comps.clear(); - comps.push_back( item_comp( what->typeId(), amount ) ); + comps.emplace_back( what->typeId(), amount ); Character &player_character = get_player_character(); // select from where to get the items from and place them diff --git a/src/inventory_ui.cpp b/src/inventory_ui.cpp index 50cc19b8a8028..d03385cbfd43a 100644 --- a/src/inventory_ui.cpp +++ b/src/inventory_ui.cpp @@ -1044,8 +1044,8 @@ void inventory_column::draw( const catacurses::window &win, const point &p, const int hx_max = p.x + get_width() + contained_offset; inclusive_rectangle rect = inclusive_rectangle( point( x1, yy ), point( hx_max - 1, yy ) ); - rect_entry_map.push_back( std::pair, inventory_entry *>( rect, - &entry ) ); + rect_entry_map.emplace_back( rect, + &entry ); if( selected && visible_cells() > 1 ) { for( int hx = x1; hx < hx_max; ++hx ) { diff --git a/src/item.cpp b/src/item.cpp index 00d6036e2c1e3..d76a35c0978a0 100644 --- a/src/item.cpp +++ b/src/item.cpp @@ -1506,7 +1506,7 @@ void item::validate_ownership() const static void insert_separation_line( std::vector &info ) { if( info.empty() || info.back().sName != "--" ) { - info.push_back( iteminfo( "DESCRIPTION", "--" ) ); + info.emplace_back( "DESCRIPTION", "--" ); } } @@ -1673,7 +1673,7 @@ void item::basic_info( std::vector &info, const iteminfo_query *parts, []( const material_type * material ) { return string_format( "%s", material->name() ); }, enumeration_conjunction::none ); - info.push_back( iteminfo( "BASE", string_format( _( "Material: %s" ), material_list ) ) ); + info.emplace_back( "BASE", string_format( _( "Material: %s" ), material_list ) ); } } if( parts->test( iteminfo_parts::BASE_VOLUME ) ) { @@ -1684,18 +1684,18 @@ void item::basic_info( std::vector &info, const iteminfo_query *parts, info.back().bNewLine = true; } if( parts->test( iteminfo_parts::BASE_LENGTH ) && length() > 0_mm ) { - info.push_back( iteminfo( "BASE", _( "Length: " ), - string_format( " %s", length_units( length() ) ), - iteminfo::lower_is_better, - convert_length( length() ) ) ); + info.emplace_back( "BASE", _( "Length: " ), + string_format( " %s", length_units( length() ) ), + iteminfo::lower_is_better, + convert_length( length() ) ); } if( parts->test( iteminfo_parts::BASE_OWNER ) && !owner.is_null() ) { - info.push_back( iteminfo( "BASE", string_format( _( "Owner: %s" ), - _( get_owner_name() ) ) ) ); + info.emplace_back( "BASE", string_format( _( "Owner: %s" ), + _( get_owner_name() ) ) ); } if( parts->test( iteminfo_parts::BASE_CATEGORY ) ) { - info.push_back( iteminfo( "BASE", _( "Category: " ), - "
" + get_category_shallow().name() + "
" ) ); + info.emplace_back( "BASE", _( "Category: " ), + "
" + get_category_shallow().name() + "
" ); } if( parts->test( iteminfo_parts::DESCRIPTION ) ) { @@ -1705,16 +1705,16 @@ void item::basic_info( std::vector &info, const iteminfo_query *parts, const cata::optional snippet = SNIPPET.get_snippet_by_id( snip_id ); if( snippet.has_value() ) { // Just use the dynamic description - info.push_back( iteminfo( "DESCRIPTION", snippet.value().translated() ) ); + info.emplace_back( "DESCRIPTION", snippet.value().translated() ); } else if( idescription != item_vars.end() ) { - info.push_back( iteminfo( "DESCRIPTION", idescription->second ) ); + info.emplace_back( "DESCRIPTION", idescription->second ); } else if( has_gun_variant() ) { - info.push_back( iteminfo( "DESCRIPTION", gun_variant().alt_description.translated() ) ); + info.emplace_back( "DESCRIPTION", gun_variant().alt_description.translated() ); } else { if( has_flag( flag_MAGIC_FOCUS ) ) { - info.push_back( iteminfo( "DESCRIPTION", - _( "This item is a magical focus. " - "You can cast spells with it in your hand." ) ) ); + info.emplace_back( "DESCRIPTION", + _( "This item is a magical focus. " + "You can cast spells with it in your hand." ) ); } if( is_craft() ) { const std::string desc = ( typeId() == itype_disassembly ) ? @@ -1722,11 +1722,11 @@ void item::basic_info( std::vector &info, const iteminfo_query *parts, "It is %d percent complete." ) : _( "This is an in progress %s. " "It is %d percent complete." ); const int percent_progress = item_counter / 100000; - info.push_back( iteminfo( "DESCRIPTION", string_format( desc, - craft_data_->making->result_name(), - percent_progress ) ) ); + info.emplace_back( "DESCRIPTION", string_format( desc, + craft_data_->making->result_name(), + percent_progress ) ); } else { - info.push_back( iteminfo( "DESCRIPTION", type->description.translated() ) ); + info.emplace_back( "DESCRIPTION", type->description.translated() ); } } insert_separation_line( info ); @@ -1760,13 +1760,13 @@ void item::basic_info( std::vector &info, const iteminfo_query *parts, } if( has_var( "contained_name" ) && parts->test( iteminfo_parts::BASE_CONTENTS ) ) { - info.push_back( iteminfo( "BASE", string_format( _( "Contains: %s" ), - get_var( "contained_name" ) ) ) ); + info.emplace_back( "BASE", string_format( _( "Contains: %s" ), + get_var( "contained_name" ) ) ); } if( count_by_charges() && !is_food() && !is_medication() && parts->test( iteminfo_parts::BASE_AMOUNT ) ) { - info.push_back( iteminfo( "BASE", _( "Amount: " ), "", iteminfo::no_flags, - charges * batch ) ); + info.emplace_back( "BASE", _( "Amount: " ), "", iteminfo::no_flags, + charges * batch ); } } @@ -1775,66 +1775,66 @@ void item::debug_info( std::vector &info, const iteminfo_query *parts, { if( debug && parts->test( iteminfo_parts::BASE_DEBUG ) ) { if( g != nullptr ) { - info.push_back( iteminfo( "BASE", string_format( "itype_id: %s", - typeId().str() ) ) ); + info.emplace_back( "BASE", string_format( "itype_id: %s", + typeId().str() ) ); if( !old_owner.is_null() ) { - info.push_back( iteminfo( "BASE", string_format( _( "Old owner: %s" ), - _( get_old_owner_name() ) ) ) ); - } - info.push_back( iteminfo( "BASE", _( "age (hours): " ), "", iteminfo::lower_is_better, - to_hours( age() ) ) ); - info.push_back( iteminfo( "BASE", _( "charges: " ), "", iteminfo::lower_is_better, - charges ) ); - info.push_back( iteminfo( "BASE", _( "damage: " ), "", iteminfo::lower_is_better, - damage_ ) ); - info.push_back( iteminfo( "BASE", _( "active: " ), "", iteminfo::lower_is_better, - active ) ); - info.push_back( iteminfo( "BASE", _( "burn: " ), "", iteminfo::lower_is_better, - burnt ) ); + info.emplace_back( "BASE", string_format( _( "Old owner: %s" ), + _( get_old_owner_name() ) ) ); + } + info.emplace_back( "BASE", _( "age (hours): " ), "", iteminfo::lower_is_better, + to_hours( age() ) ); + info.emplace_back( "BASE", _( "charges: " ), "", iteminfo::lower_is_better, + charges ); + info.emplace_back( "BASE", _( "damage: " ), "", iteminfo::lower_is_better, + damage_ ); + info.emplace_back( "BASE", _( "active: " ), "", iteminfo::lower_is_better, + active ); + info.emplace_back( "BASE", _( "burn: " ), "", iteminfo::lower_is_better, + burnt ); const std::string tags_listed = enumerate_as_string( item_tags, []( const flag_id & f ) { return f.str(); }, enumeration_conjunction::none ); - info.push_back( iteminfo( "BASE", string_format( _( "tags: %s" ), tags_listed ) ) ); + info.emplace_back( "BASE", string_format( _( "tags: %s" ), tags_listed ) ); for( auto const &imap : item_vars ) { - info.push_back( iteminfo( "BASE", - string_format( _( "item var: %s, %s" ), imap.first, - imap.second ) ) ); + info.emplace_back( "BASE", + string_format( _( "item var: %s, %s" ), imap.first, + imap.second ) ); } const std::string space = " "; if( goes_bad() ) { - info.push_back( iteminfo( "BASE", _( "age (turns): " ), - "", iteminfo::lower_is_better, - to_turns( age() ) ) ); - info.push_back( iteminfo( "BASE", _( "rot (turns): " ), - "", iteminfo::lower_is_better, - to_turns( rot ) ) ); - info.push_back( iteminfo( "BASE", space + _( "max rot (turns): " ), - "", iteminfo::lower_is_better, - to_turns( get_shelf_life() ) ) ); + info.emplace_back( "BASE", _( "age (turns): " ), + "", iteminfo::lower_is_better, + to_turns( age() ) ); + info.emplace_back( "BASE", _( "rot (turns): " ), + "", iteminfo::lower_is_better, + to_turns( rot ) ); + info.emplace_back( "BASE", space + _( "max rot (turns): " ), + "", iteminfo::lower_is_better, + to_turns( get_shelf_life() ) ); } if( has_temperature() ) { - info.push_back( iteminfo( "BASE", _( "last temp: " ), - "", iteminfo::lower_is_better, - to_turn( last_temp_check ) ) ); - info.push_back( iteminfo( "BASE", _( "Temp: " ), "", iteminfo::lower_is_better, - temperature ) ); - info.push_back( iteminfo( "BASE", _( "Spec ener: " ), "", - iteminfo::lower_is_better, - specific_energy ) ); - info.push_back( iteminfo( "BASE", _( "Spec heat lq: " ), "", - iteminfo::lower_is_better | iteminfo::is_decimal, - get_specific_heat_liquid() ) ); - info.push_back( iteminfo( "BASE", _( "Spec heat sld: " ), "", - iteminfo::lower_is_better | iteminfo::is_decimal, - get_specific_heat_solid() ) ); - info.push_back( iteminfo( "BASE", _( "latent heat: " ), "", - iteminfo::lower_is_better, - get_latent_heat() ) ); - info.push_back( iteminfo( "BASE", _( "Freeze point: " ), "", - iteminfo::lower_is_better | iteminfo::is_decimal, - get_freeze_point() ) ); + info.emplace_back( "BASE", _( "last temp: " ), + "", iteminfo::lower_is_better, + to_turn( last_temp_check ) ); + info.emplace_back( "BASE", _( "Temp: " ), "", iteminfo::lower_is_better, + temperature ); + info.emplace_back( "BASE", _( "Spec ener: " ), "", + iteminfo::lower_is_better, + specific_energy ); + info.emplace_back( "BASE", _( "Spec heat lq: " ), "", + iteminfo::lower_is_better | iteminfo::is_decimal, + get_specific_heat_liquid() ); + info.emplace_back( "BASE", _( "Spec heat sld: " ), "", + iteminfo::lower_is_better | iteminfo::is_decimal, + get_specific_heat_solid() ); + info.emplace_back( "BASE", _( "latent heat: " ), "", + iteminfo::lower_is_better, + get_latent_heat() ); + info.emplace_back( "BASE", _( "Freeze point: " ), "", + iteminfo::lower_is_better | iteminfo::is_decimal, + get_freeze_point() ); } } } @@ -1845,29 +1845,29 @@ void item::med_info( const item *med_item, std::vector &info, const it { const cata::value_ptr &med_com = med_item->get_comestible(); if( med_com->quench != 0 && parts->test( iteminfo_parts::MED_QUENCH ) ) { - info.push_back( iteminfo( "MED", _( "Quench: " ), med_com->quench ) ); + info.emplace_back( "MED", _( "Quench: " ), med_com->quench ); } Character &player_character = get_player_character(); if( med_item->get_comestible_fun() != 0 && parts->test( iteminfo_parts::MED_JOY ) ) { - info.push_back( iteminfo( "MED", _( "Enjoyability: " ), - player_character.fun_for( *med_item ).first ) ); + info.emplace_back( "MED", _( "Enjoyability: " ), + player_character.fun_for( *med_item ).first ); } if( med_com->stim != 0 && parts->test( iteminfo_parts::MED_STIMULATION ) ) { std::string name = string_format( "%s %s", _( "Stimulation:" ), med_com->stim > 0 ? _( "Upper" ) : _( "Downer" ) ); - info.push_back( iteminfo( "MED", name ) ); + info.emplace_back( "MED", name ); } if( parts->test( iteminfo_parts::MED_PORTIONS ) ) { - info.push_back( iteminfo( "MED", _( "Portions: " ), - std::abs( static_cast( med_item->charges ) * batch ) ) ); + info.emplace_back( "MED", _( "Portions: " ), + std::abs( static_cast( med_item->charges ) * batch ) ); } if( parts->test( iteminfo_parts::MED_CONSUME_TIME ) ) { - info.push_back( iteminfo( "MED", _( "Consume time: " ), - to_string( player_character.get_consume_time( *med_item ) ) ) ); + info.emplace_back( "MED", _( "Consume time: " ), + to_string( player_character.get_consume_time( *med_item ) ) ); } if( med_com->addict && parts->test( iteminfo_parts::DESCRIPTION_MED_ADDICTING ) ) { @@ -1904,51 +1904,51 @@ void item::food_info( const item *food_item, std::vector &info, 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, min_nutr.kcal() ) ); + info.emplace_back( "FOOD", _( "Calories (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() ) ); + info.emplace_back( "FOOD", _( "-" ), + "", iteminfo::no_newline, max_nutr.kcal() ); } } if( parts->test( iteminfo_parts::FOOD_QUENCH ) ) { const std::string space = " "; - info.push_back( iteminfo( "FOOD", space + _( "Quench: " ), - food_item->get_comestible()->quench ) ); + info.emplace_back( "FOOD", space + _( "Quench: " ), + food_item->get_comestible()->quench ); } if( parts->test( iteminfo_parts::FOOD_SATIATION ) ) { if( max_nutr.kcal() == min_nutr.kcal() ) { - info.push_back( iteminfo( "FOOD", _( "Satiety: " ), - satiety_bar( player_character.compute_calories_per_effective_volume( *food_item ) ) ) ); + info.emplace_back( "FOOD", _( "Satiety: " ), + satiety_bar( player_character.compute_calories_per_effective_volume( *food_item ) ) ); } else { - info.push_back( iteminfo( "FOOD", _( "Satiety: " ), - satiety_bar( player_character.compute_calories_per_effective_volume( *food_item, &min_nutr ) ), - iteminfo::no_newline - ) ); - info.push_back( iteminfo( "FOOD", _( " - " ), - satiety_bar( player_character.compute_calories_per_effective_volume( *food_item, &max_nutr ) ) ) ); + info.emplace_back( "FOOD", _( "Satiety: " ), + satiety_bar( player_character.compute_calories_per_effective_volume( *food_item, &min_nutr ) ), + iteminfo::no_newline + ); + info.emplace_back( "FOOD", _( " - " ), + satiety_bar( player_character.compute_calories_per_effective_volume( *food_item, &max_nutr ) ) ); } } } const std::pair fun_for_food_item = player_character.fun_for( *food_item ); if( fun_for_food_item.first != 0 && parts->test( iteminfo_parts::FOOD_JOY ) ) { - info.push_back( iteminfo( "FOOD", _( "Enjoyability: " ), fun_for_food_item.first ) ); + info.emplace_back( "FOOD", _( "Enjoyability: " ), fun_for_food_item.first ); } if( parts->test( iteminfo_parts::FOOD_PORTIONS ) ) { - info.push_back( iteminfo( "FOOD", _( "Portions: " ), - std::abs( static_cast( food_item->charges ) * batch ) ) ); + info.emplace_back( "FOOD", _( "Portions: " ), + std::abs( static_cast( food_item->charges ) * batch ) ); } if( food_item->corpse != nullptr && parts->test( iteminfo_parts::FOOD_SMELL ) && ( debug || ( g != nullptr && player_character.has_trait( trait_CARNIVORE ) ) ) ) { - info.push_back( iteminfo( "FOOD", _( "Smells like: " ) + food_item->corpse->nname() ) ); + info.emplace_back( "FOOD", _( "Smells like: " ) + food_item->corpse->nname() ); } if( parts->test( iteminfo_parts::FOOD_CONSUME_TIME ) ) { - info.push_back( iteminfo( "FOOD", _( "Consume time: " ), - to_string( player_character.get_consume_time( *food_item ) ) ) ); + info.emplace_back( "FOOD", _( "Consume time: " ), + to_string( player_character.get_consume_time( *food_item ) ) ); } auto format_vitamin = [&]( const std::pair &v, bool display_vitamins ) { @@ -2062,19 +2062,19 @@ void item::food_info( const item *food_item, std::vector &info, } if( food_item->rotten() ) { if( player_character.has_bionic( bio_digestion ) ) { - info.push_back( iteminfo( "DESCRIPTION", - _( "This food has started to rot, " - "but your bionic digestion can tolerate " - "it." ) ) ); + info.emplace_back( "DESCRIPTION", + _( "This food has started to rot, " + "but your bionic digestion can tolerate " + "it." ) ); } else if( player_character.has_flag( json_flag_IMMUNE_SPOIL ) ) { - info.push_back( iteminfo( "DESCRIPTION", - _( "This food has started to rot, " - "but you can tolerate it." ) ) ); + info.emplace_back( "DESCRIPTION", + _( "This food has started to rot, " + "but you can tolerate it." ) ); } else { - info.push_back( iteminfo( "DESCRIPTION", - _( "This food has started to rot. " - "Eating it would be a very bad " - "idea." ) ) ); + info.emplace_back( "DESCRIPTION", + _( "This food has started to rot. " + "Eating it would be a very bad " + "idea." ) ); } } } @@ -2267,8 +2267,8 @@ void item::gun_info( const item *mod, std::vector &info, const iteminf if( parts->test( iteminfo_parts::GUN_DAMAGE ) ) { insert_separation_line( info ); - info.push_back( iteminfo( "GUN", _( "Ranged damage: " ), "", iteminfo::no_newline, - mod->gun_damage( false ).total_damage() ) ); + info.emplace_back( "GUN", _( "Ranged damage: " ), "", iteminfo::no_newline, + mod->gun_damage( false ).total_damage() ); } if( mod->ammo_required() ) { @@ -2279,36 +2279,36 @@ void item::gun_info( const item *mod, std::vector &info, const iteminf } if( dmg_mult != 1.0f ) { if( parts->test( iteminfo_parts::GUN_DAMAGE_AMMOPROP ) ) { - info.push_back( iteminfo( "GUN", "ammo_mult", "*", - iteminfo::no_newline | iteminfo::no_name | iteminfo::is_decimal, dmg_mult ) ); + info.emplace_back( "GUN", "ammo_mult", "*", + iteminfo::no_newline | iteminfo::no_name | iteminfo::is_decimal, dmg_mult ); } } else { if( parts->test( iteminfo_parts::GUN_DAMAGE_LOADEDAMMO ) ) { damage_instance ammo_dam = curammo->ammo->damage; - info.push_back( iteminfo( "GUN", "ammo_damage", "", - iteminfo::no_newline | iteminfo::no_name | - iteminfo::show_plus, ammo_dam.total_damage() ) ); + info.emplace_back( "GUN", "ammo_damage", "", + iteminfo::no_newline | iteminfo::no_name | + iteminfo::show_plus, ammo_dam.total_damage() ); } } if( damage_level() > 0 ) { int dmg_penalty = damage_level() * -2; - info.push_back( iteminfo( "GUN", "damaged_weapon_penalty", "", - iteminfo::no_newline | iteminfo::no_name, dmg_penalty ) ); + info.emplace_back( "GUN", "damaged_weapon_penalty", "", + iteminfo::no_newline | iteminfo::no_name, dmg_penalty ); } if( parts->test( iteminfo_parts::GUN_DAMAGE_TOTAL ) ) { - info.push_back( iteminfo( "GUN", "sum_of_damage", _( " = " ), - iteminfo::no_newline | iteminfo::no_name, - loaded_mod->gun_damage( true ).total_damage() ) ); + info.emplace_back( "GUN", "sum_of_damage", _( " = " ), + iteminfo::no_newline | iteminfo::no_name, + loaded_mod->gun_damage( true ).total_damage() ); } } info.back().bNewLine = true; if( mod->ammo_required() && curammo->ammo->critical_multiplier != 1.0 ) { if( parts->test( iteminfo_parts::AMMO_DAMAGE_CRIT_MULTIPLIER ) ) { - info.push_back( iteminfo( "GUN", _( "Critical multiplier: " ), "", - iteminfo::no_flags, curammo->ammo->critical_multiplier ) ); + info.emplace_back( "GUN", _( "Critical multiplier: " ), "", + iteminfo::no_flags, curammo->ammo->critical_multiplier ); } } @@ -2322,43 +2322,43 @@ void item::gun_info( const item *mod, std::vector &info, const iteminf // TODO: This doesn't cover multiple damage types if( parts->test( iteminfo_parts::GUN_ARMORPIERCE ) ) { - info.push_back( iteminfo( "GUN", _( "Armor-pierce: " ), "", - iteminfo::no_newline, get_ranged_pierce( gun ) ) ); + info.emplace_back( "GUN", _( "Armor-pierce: " ), "", + iteminfo::no_newline, get_ranged_pierce( gun ) ); } if( mod->ammo_required() ) { int ammo_pierce = get_ranged_pierce( *curammo->ammo ); // ammo_armor_pierce and sum_of_armor_pierce don't need to translate. if( parts->test( iteminfo_parts::GUN_ARMORPIERCE_LOADEDAMMO ) ) { - info.push_back( iteminfo( "GUN", "ammo_armor_pierce", "", - iteminfo::no_newline | iteminfo::no_name | - iteminfo::show_plus, ammo_pierce ) ); + info.emplace_back( "GUN", "ammo_armor_pierce", "", + iteminfo::no_newline | iteminfo::no_name | + iteminfo::show_plus, ammo_pierce ); } if( parts->test( iteminfo_parts::GUN_ARMORPIERCE_TOTAL ) ) { - info.push_back( iteminfo( "GUN", "sum_of_armor_pierce", _( " = " ), - iteminfo::no_name, - get_ranged_pierce( gun ) + ammo_pierce ) ); + info.emplace_back( "GUN", "sum_of_armor_pierce", _( " = " ), + iteminfo::no_name, + get_ranged_pierce( gun ) + ammo_pierce ); } } info.back().bNewLine = true; if( parts->test( iteminfo_parts::GUN_DISPERSION ) ) { - info.push_back( iteminfo( "GUN", _( "Dispersion: " ), "", - iteminfo::no_newline | iteminfo::lower_is_better, - mod->gun_dispersion( false, false ) ) ); + info.emplace_back( "GUN", _( "Dispersion: " ), "", + iteminfo::no_newline | iteminfo::lower_is_better, + mod->gun_dispersion( false, false ) ); } if( mod->ammo_required() ) { int ammo_dispersion = curammo->ammo->dispersion; // ammo_dispersion and sum_of_dispersion don't need to translate. if( parts->test( iteminfo_parts::GUN_DISPERSION_LOADEDAMMO ) ) { - info.push_back( iteminfo( "GUN", "ammo_dispersion", "", - iteminfo::no_newline | iteminfo::lower_is_better | - iteminfo::no_name | iteminfo::show_plus, - ammo_dispersion ) ); + info.emplace_back( "GUN", "ammo_dispersion", "", + iteminfo::no_newline | iteminfo::lower_is_better | + iteminfo::no_name | iteminfo::show_plus, + ammo_dispersion ); } if( parts->test( iteminfo_parts::GUN_DISPERSION_TOTAL ) ) { - info.push_back( iteminfo( "GUN", "sum_of_dispersion", _( " = " ), - iteminfo::lower_is_better | iteminfo::no_name, - loaded_mod->gun_dispersion( true, false ) ) ); + info.emplace_back( "GUN", "sum_of_dispersion", _( " = " ), + iteminfo::lower_is_better | iteminfo::no_name, + loaded_mod->gun_dispersion( true, false ) ); } } info.back().bNewLine = true; @@ -2369,17 +2369,17 @@ void item::gun_info( const item *mod, std::vector &info, const iteminf int adj_disp = eff_disp - act_disp; if( parts->test( iteminfo_parts::GUN_DISPERSION_SIGHT ) ) { - info.push_back( iteminfo( "GUN", _( "Sight dispersion: " ), "", - iteminfo::no_newline | iteminfo::lower_is_better, - act_disp ) ); + info.emplace_back( "GUN", _( "Sight dispersion: " ), "", + iteminfo::no_newline | iteminfo::lower_is_better, + act_disp ); if( adj_disp ) { - info.push_back( iteminfo( "GUN", "sight_adj_disp", "", - iteminfo::no_newline | iteminfo::lower_is_better | - iteminfo::no_name | iteminfo::show_plus, adj_disp ) ); - info.push_back( iteminfo( "GUN", "sight_eff_disp", _( " = " ), - iteminfo::lower_is_better | iteminfo::no_name, - eff_disp ) ); + info.emplace_back( "GUN", "sight_adj_disp", "", + iteminfo::no_newline | iteminfo::lower_is_better | + iteminfo::no_name | iteminfo::show_plus, adj_disp ); + info.emplace_back( "GUN", "sight_eff_disp", _( " = " ), + iteminfo::lower_is_better | iteminfo::no_name, + eff_disp ); } } @@ -2416,8 +2416,8 @@ void item::gun_info( const item *mod, std::vector &info, const iteminf } if( parts->test( iteminfo_parts::GUN_USEDSKILL ) ) { - info.push_back( iteminfo( "GUN", _( "Skill used: " ), - "" + skill.name() + "" ) ); + info.emplace_back( "GUN", _( "Skill used: " ), + "" + skill.name() + "" ); } if( mod->magazine_integral() || mod->magazine_current() ) { @@ -2542,7 +2542,7 @@ void item::gun_info( const item *mod, std::vector &info, const iteminf iternum++; } mod_str += "."; - info.push_back( iteminfo( "DESCRIPTION", mod_str ) ); + info.emplace_back( "DESCRIPTION", mod_str ); } if( mod->casings_count() && parts->test( iteminfo_parts::DESCRIPTION_GUN_CASINGS ) ) { @@ -2554,8 +2554,8 @@ void item::gun_info( const item *mod, std::vector &info, const iteminf if( is_gun() && has_flag( flag_FIRE_TWOHAND ) && parts->test( iteminfo_parts::DESCRIPTION_TWOHANDED ) ) { - info.push_back( iteminfo( "DESCRIPTION", - _( "This weapon needs two free hands to fire." ) ) ); + info.emplace_back( "DESCRIPTION", + _( "This weapon needs two free hands to fire." ) ); } } @@ -2568,52 +2568,52 @@ void item::gunmod_info( std::vector &info, const iteminfo_query *parts const islot_gunmod &mod = *type->gunmod; if( is_gun() && parts->test( iteminfo_parts::DESCRIPTION_GUNMOD ) ) { - info.push_back( iteminfo( "DESCRIPTION", - _( "This mod must be attached to a gun, " - "it can not be fired separately." ) ) ); + info.emplace_back( "DESCRIPTION", + _( "This mod must be attached to a gun, " + "it can not be fired separately." ) ); } if( has_flag( flag_REACH_ATTACK ) && parts->test( iteminfo_parts::DESCRIPTION_GUNMOD_REACH ) ) { - info.push_back( iteminfo( "DESCRIPTION", - _( "When attached to a gun, allows making " - "reach melee attacks with it." ) ) ); + info.emplace_back( "DESCRIPTION", + _( "When attached to a gun, allows making " + "reach melee attacks with it." ) ); } if( is_gunmod() && has_flag( flag_DISABLE_SIGHTS ) && parts->test( iteminfo_parts::DESCRIPTION_GUNMOD_DISABLESSIGHTS ) ) { - info.push_back( iteminfo( "DESCRIPTION", - _( "This mod obscures sights of the " - "base weapon." ) ) ); + info.emplace_back( "DESCRIPTION", + _( "This mod obscures sights of the " + "base weapon." ) ); } if( is_gunmod() && has_flag( flag_CONSUMABLE ) && parts->test( iteminfo_parts::DESCRIPTION_GUNMOD_CONSUMABLE ) ) { - info.push_back( iteminfo( "DESCRIPTION", - _( "This mod might suffer wear when firing " - "the base weapon." ) ) ); + info.emplace_back( "DESCRIPTION", + _( "This mod might suffer wear when firing " + "the base weapon." ) ); } if( mod.dispersion != 0 && parts->test( iteminfo_parts::GUNMOD_DISPERSION ) ) { - info.push_back( iteminfo( "GUNMOD", _( "Dispersion modifier: " ), "", - iteminfo::lower_is_better | iteminfo::show_plus, - mod.dispersion ) ); + info.emplace_back( "GUNMOD", _( "Dispersion modifier: " ), "", + iteminfo::lower_is_better | iteminfo::show_plus, + mod.dispersion ); } if( mod.sight_dispersion != -1 && parts->test( iteminfo_parts::GUNMOD_DISPERSION_SIGHT ) ) { - info.push_back( iteminfo( "GUNMOD", _( "Sight dispersion: " ), "", - iteminfo::lower_is_better, mod.sight_dispersion ) ); + info.emplace_back( "GUNMOD", _( "Sight dispersion: " ), "", + iteminfo::lower_is_better, mod.sight_dispersion ); } if( mod.aim_speed >= 0 && parts->test( iteminfo_parts::GUNMOD_AIMSPEED ) ) { - info.push_back( iteminfo( "GUNMOD", _( "Aim speed: " ), "", - iteminfo::lower_is_better, mod.aim_speed ) ); + info.emplace_back( "GUNMOD", _( "Aim speed: " ), "", + iteminfo::lower_is_better, mod.aim_speed ); } int total_damage = static_cast( mod.damage.total_damage() ); if( total_damage != 0 && parts->test( iteminfo_parts::GUNMOD_DAMAGE ) ) { - info.push_back( iteminfo( "GUNMOD", _( "Damage: " ), "", iteminfo::show_plus, - total_damage ) ); + info.emplace_back( "GUNMOD", _( "Damage: " ), "", iteminfo::show_plus, + total_damage ); } int pierce = get_ranged_pierce( mod ); if( get_ranged_pierce( mod ) != 0 && parts->test( iteminfo_parts::GUNMOD_ARMORPIERCE ) ) { - info.push_back( iteminfo( "GUNMOD", _( "Armor-pierce: " ), "", iteminfo::show_plus, - pierce ) ); + info.emplace_back( "GUNMOD", _( "Armor-pierce: " ), "", iteminfo::show_plus, + pierce ); } if( mod.handling != 0 && parts->test( iteminfo_parts::GUNMOD_HANDLING ) ) { info.emplace_back( "GUNMOD", _( "Handling modifier: " ), "", @@ -2621,8 +2621,8 @@ void item::gunmod_info( std::vector &info, const iteminfo_query *parts } if( !type->mod->ammo_modifier.empty() && parts->test( iteminfo_parts::GUNMOD_AMMO ) ) { for( const ammotype &at : type->mod->ammo_modifier ) { - info.push_back( iteminfo( "GUNMOD", string_format( _( "Ammo: %s" ), - at->name() ) ) ); + info.emplace_back( "GUNMOD", string_format( _( "Ammo: %s" ), + at->name() ) ); } } if( mod.reload_modifier != 0 && parts->test( iteminfo_parts::GUNMOD_RELOAD ) ) { @@ -2630,8 +2630,8 @@ void item::gunmod_info( std::vector &info, const iteminfo_query *parts iteminfo::lower_is_better, mod.reload_modifier ); } if( mod.min_str_required_mod > 0 && parts->test( iteminfo_parts::GUNMOD_STRENGTH ) ) { - info.push_back( iteminfo( "GUNMOD", _( "Minimum strength required modifier: " ), - mod.min_str_required_mod ) ); + info.emplace_back( "GUNMOD", _( "Minimum strength required modifier: " ), + mod.min_str_required_mod ); } if( !mod.add_mod.empty() && parts->test( iteminfo_parts::GUNMOD_ADD_MOD ) ) { insert_separation_line( info ); @@ -2649,7 +2649,7 @@ void item::gunmod_info( std::vector &info, const iteminfo_query *parts iternum++; } mod_loc_str += "."; - info.push_back( iteminfo( "GUNMOD", mod_loc_str ) ); + info.emplace_back( "GUNMOD", mod_loc_str ); } insert_separation_line( info ); @@ -2659,12 +2659,12 @@ void item::gunmod_info( std::vector &info, const iteminfo_query *parts enumerate_as_string( mod.usable.begin(), mod.usable.end(), []( const gun_type_type & used_on ) { return string_format( "%s", used_on.name() ); } ); - info.push_back( iteminfo( "GUNMOD", used_on_str ) ); + info.emplace_back( "GUNMOD", used_on_str ); } if( parts->test( iteminfo_parts::GUNMOD_LOCATION ) ) { - info.push_back( iteminfo( "GUNMOD", string_format( _( "Location: %s" ), - mod.location.name() ) ) ); + info.emplace_back( "GUNMOD", string_format( _( "Location: %s" ), + mod.location.name() ) ); } if( !mod.blacklist_mod.empty() && parts->test( iteminfo_parts::GUNMOD_BLACKLIST_MOD ) ) { @@ -2679,7 +2679,7 @@ void item::gunmod_info( std::vector &info, const iteminfo_query *parts iternum++; } mod_black_str += "."; - info.push_back( iteminfo( "GUNMOD", mod_black_str ) ); + info.emplace_back( "GUNMOD", mod_black_str ); } } @@ -2710,7 +2710,7 @@ void item::armor_encumbrance_info( std::vector &info, int reduce_encum } } - info.push_back( iteminfo( "ARMOR", _( "Encumbrance:" ) + format ) ); + info.emplace_back( "ARMOR", _( "Encumbrance:" ) + format ); if( const islot_armor *t = find_armor_data() ) { if( !t->data.empty() ) { @@ -2771,30 +2771,30 @@ void item::armor_encumbrance_info( std::vector &info, int reduce_encum } } if( piece.second.active ) { - info.push_back( iteminfo( "ARMOR", - string_format( _( "%s:" ), piece.second.to_display.translated() ) + space, "", - iteminfo::no_newline | iteminfo::lower_is_better, - piece.second.portion.encumber ) ); + info.emplace_back( "ARMOR", + string_format( _( "%s:" ), piece.second.to_display.translated() ) + space, "", + iteminfo::no_newline | iteminfo::lower_is_better, + piece.second.portion.encumber ); if( piece.second.portion.encumber != piece.second.portion.max_encumber ) { - info.push_back( iteminfo( "ARMOR", when_full_message, "", - iteminfo::no_newline | iteminfo::lower_is_better, - piece.second.portion.max_encumber ) ); + info.emplace_back( "ARMOR", when_full_message, "", + iteminfo::no_newline | iteminfo::lower_is_better, + piece.second.portion.max_encumber ); } - info.push_back( iteminfo( "ARMOR", coverage_message, "", - iteminfo::no_flags, - piece.second.portion.coverage ) ); + info.emplace_back( "ARMOR", coverage_message, "", + iteminfo::no_flags, + piece.second.portion.coverage ); } } } } else if( is_gun() && has_flag( flag_IS_ARMOR ) ) { //right now all eligible gunmods (shoulder_strap, belt_clip) have the is_armor flag and use the torso - info.push_back( iteminfo( "ARMOR", _( "Torso:" ) + space, "", - iteminfo::no_newline | iteminfo::lower_is_better, get_avg_encumber( get_avatar() ) ) ); + info.emplace_back( "ARMOR", _( "Torso:" ) + space, "", + iteminfo::no_newline | iteminfo::lower_is_better, get_avg_encumber( get_avatar() ) ); - info.push_back( iteminfo( "ARMOR", space + _( "Coverage:" ) + space, "", - iteminfo::no_flags, get_coverage( body_part_torso.id() ) ) ); + info.emplace_back( "ARMOR", space + _( "Coverage:" ) + space, "", + iteminfo::no_flags, get_coverage( body_part_torso.id() ) ); } } @@ -2808,36 +2808,36 @@ void item::armor_protection_info( std::vector &info, const iteminfo_qu if( parts->test( iteminfo_parts::ARMOR_PROTECTION ) ) { const std::string space = " "; - info.push_back( iteminfo( "ARMOR", _( "Protection: Bash: " ), "", - iteminfo::no_newline | iteminfo::is_decimal, bash_resist() ) ); - info.push_back( iteminfo( "ARMOR", space + _( "Cut: " ), "", - iteminfo::no_newline | iteminfo::is_decimal, cut_resist() ) ); - info.push_back( iteminfo( "ARMOR", space + _( "Ballistic: " ), "", iteminfo::is_decimal, - bullet_resist() ) ); - info.push_back( iteminfo( "ARMOR", space + _( "Acid: " ), "", - iteminfo::no_newline | iteminfo::is_decimal, acid_resist() ) ); - info.push_back( iteminfo( "ARMOR", space + _( "Fire: " ), "", - iteminfo::no_newline | iteminfo::is_decimal, fire_resist() ) ); - info.push_back( iteminfo( "ARMOR", space + _( "Environmental: " ), - get_base_env_resist( *this ) ) ); + info.emplace_back( "ARMOR", _( "Protection: Bash: " ), "", + iteminfo::no_newline | iteminfo::is_decimal, bash_resist() ); + info.emplace_back( "ARMOR", space + _( "Cut: " ), "", + iteminfo::no_newline | iteminfo::is_decimal, cut_resist() ); + info.emplace_back( "ARMOR", space + _( "Ballistic: " ), "", iteminfo::is_decimal, + bullet_resist() ); + info.emplace_back( "ARMOR", space + _( "Acid: " ), "", + iteminfo::no_newline | iteminfo::is_decimal, acid_resist() ); + info.emplace_back( "ARMOR", space + _( "Fire: " ), "", + iteminfo::no_newline | iteminfo::is_decimal, fire_resist() ); + info.emplace_back( "ARMOR", space + _( "Environmental: " ), + get_base_env_resist( *this ) ); if( type->can_use( "GASMASK" ) || type->can_use( "DIVE_TANK" ) ) { - info.push_back( iteminfo( "ARMOR", - _( "Protection when active: " ) ) ); - info.push_back( iteminfo( "ARMOR", space + _( "Acid: " ), "", - iteminfo::no_newline | iteminfo::is_decimal, - acid_resist( false, get_base_env_resist_w_filter() ) ) ); - info.push_back( iteminfo( "ARMOR", space + _( "Fire: " ), "", - iteminfo::no_newline | iteminfo::is_decimal, - fire_resist( false, get_base_env_resist_w_filter() ) ) ); - info.push_back( iteminfo( "ARMOR", space + _( "Environmental: " ), - get_env_resist( get_base_env_resist_w_filter() ) ) ); + info.emplace_back( "ARMOR", + _( "Protection when active: " ) ); + info.emplace_back( "ARMOR", space + _( "Acid: " ), "", + iteminfo::no_newline | iteminfo::is_decimal, + acid_resist( false, get_base_env_resist_w_filter() ) ); + info.emplace_back( "ARMOR", space + _( "Fire: " ), "", + iteminfo::no_newline | iteminfo::is_decimal, + fire_resist( false, get_base_env_resist_w_filter() ) ); + info.emplace_back( "ARMOR", space + _( "Environmental: " ), + get_env_resist( get_base_env_resist_w_filter() ) ); } if( damage() > 0 ) { - info.push_back( iteminfo( "ARMOR", - _( "Protection values are reduced by damage and " - "you may be able to improve them by repairing this " - "item." ) ) ); + info.emplace_back( "ARMOR", + _( "Protection values are reduced by damage and " + "you may be able to improve them by repairing this " + "item." ) ); } } } @@ -2913,7 +2913,7 @@ void item::armor_info( std::vector &info, const iteminfo_query *parts, coverage += _( " Nothing." ); } - info.push_back( iteminfo( "ARMOR", coverage ) ); + info.emplace_back( "ARMOR", coverage ); } if( parts->test( iteminfo_parts::ARMOR_LAYER ) && covers_anything ) { @@ -2934,15 +2934,15 @@ void item::armor_info( std::vector &info, const iteminfo_query *parts, layering += _( " Normal." ); } - info.push_back( iteminfo( "ARMOR", layering ) ); + info.emplace_back( "ARMOR", layering ); } if( parts->test( iteminfo_parts::ARMOR_COVERAGE ) && covers_anything ) { - info.push_back( iteminfo( "ARMOR", _( "Average Coverage: " ), "%", - iteminfo::no_newline, get_avg_coverage() ) ); + info.emplace_back( "ARMOR", _( "Average Coverage: " ), "%", + iteminfo::no_newline, get_avg_coverage() ); } if( parts->test( iteminfo_parts::ARMOR_WARMTH ) && covers_anything ) { - info.push_back( iteminfo( "ARMOR", space + _( "Warmth: " ), get_warmth() ) ); + info.emplace_back( "ARMOR", space + _( "Warmth: " ), get_warmth() ); } insert_separation_line( info ); @@ -2962,7 +2962,7 @@ void item::armor_info( std::vector &info, const iteminfo_query *parts, tmp.armor_protection_info( info, parts, batch, debug ); insert_separation_line( info ); - info.push_back( iteminfo( "ARMOR", _( "When active:" ) ) ); + info.emplace_back( "ARMOR", _( "When active:" ) ); tmp = tmp.convert( itype_id( tmp.typeId().str() + "_on" ) ); } @@ -2994,9 +2994,9 @@ void item::armor_info( std::vector &info, const iteminfo_query *parts, } else { modifier = "x"; } - info.push_back( iteminfo( "ARMOR", - _( "Weight capacity modifier: " ), modifier, - iteminfo::no_newline | iteminfo::is_decimal, weight_modif ) ); + info.emplace_back( "ARMOR", + _( "Weight capacity modifier: " ), modifier, + iteminfo::no_newline | iteminfo::is_decimal, weight_modif ); } if( weight_bonus != 0_gram ) { std::string bonus; @@ -3005,9 +3005,9 @@ void item::armor_info( std::vector &info, const iteminfo_query *parts, } else { bonus = string_format( " %s", weight_units() ); } - info.push_back( iteminfo( "ARMOR", _( "Weight capacity bonus: " ), bonus, - iteminfo::no_newline | iteminfo::is_decimal, - convert_weight( weight_bonus ) ) ); + info.emplace_back( "ARMOR", _( "Weight capacity bonus: " ), bonus, + iteminfo::no_newline | iteminfo::is_decimal, + convert_weight( weight_bonus ) ); } } @@ -3032,9 +3032,9 @@ void item::armor_fit_info( std::vector &info, const iteminfo_query *pa if( has_flag( flag_HELMET_COMPAT ) && parts->test( iteminfo_parts::DESCRIPTION_FLAGS_HELMETCOMPAT ) ) { - info.push_back( iteminfo( "DESCRIPTION", - _( "* This item can be worn with a " - "helmet." ) ) ); + info.emplace_back( "DESCRIPTION", + _( "* This item can be worn with a " + "helmet." ) ); } if( parts->test( iteminfo_parts::DESCRIPTION_FLAGS_FITS ) ) { @@ -3118,7 +3118,7 @@ void item::armor_fit_info( std::vector &info, const iteminfo_query *pa } if( !resize_str.empty() ) { std::string info_str = string_format( _( "* This clothing %s." ), resize_str ); - info.push_back( iteminfo( "DESCRIPTION", info_str ) ); + info.emplace_back( "DESCRIPTION", info_str ); } } else { switch( sizing_level ) { @@ -3141,7 +3141,7 @@ void item::armor_fit_info( std::vector &info, const iteminfo_query *pa } std::string info_str = string_format( _( "* This clothing can be " "refitted%s." ), resize_str ); - info.push_back( iteminfo( "DESCRIPTION", info_str ) ); + info.emplace_back( "DESCRIPTION", info_str ); } } else { info.emplace_back( "DESCRIPTION", _( "* This clothing can not be refitted, " @@ -3150,32 +3150,32 @@ void item::armor_fit_info( std::vector &info, const iteminfo_query *pa } if( is_sided() && parts->test( iteminfo_parts::DESCRIPTION_FLAGS_SIDED ) ) { - info.push_back( iteminfo( "DESCRIPTION", - _( "* This item can be worn on either side of " - "the body." ) ) ); + info.emplace_back( "DESCRIPTION", + _( "* This item can be worn on either side of " + "the body." ) ); } if( is_power_armor() && parts->test( iteminfo_parts::DESCRIPTION_FLAGS_POWERARMOR ) ) { - info.push_back( iteminfo( "DESCRIPTION", - _( "* This gear is a part of power armor." ) ) ); + info.emplace_back( "DESCRIPTION", + _( "* This gear is a part of power armor." ) ); if( parts->test( iteminfo_parts::DESCRIPTION_FLAGS_POWERARMOR_RADIATIONHINT ) ) { if( covers( bodypart_id( "head" ) ) ) { - info.push_back( iteminfo( "DESCRIPTION", - _( "* When worn with a power armor suit, it will " - "fully protect you from " - "radiation." ) ) ); + info.emplace_back( "DESCRIPTION", + _( "* When worn with a power armor suit, it will " + "fully protect you from " + "radiation." ) ); } else { - info.push_back( iteminfo( "DESCRIPTION", - _( "* When worn with a power armor helmet, it will " - "fully protect you from " - "radiation." ) ) ); + info.emplace_back( "DESCRIPTION", + _( "* When worn with a power armor helmet, it will " + "fully protect you from " + "radiation." ) ); } } } if( typeId() == itype_rad_badge && parts->test( iteminfo_parts::DESCRIPTION_IRRADIATION ) ) { - info.push_back( iteminfo( "DESCRIPTION", - string_format( _( "* The film strip on the badge is %s." ), - rad_badge_color( irradiation ) ) ) ); + info.emplace_back( "DESCRIPTION", + string_format( _( "* The film strip on the badge is %s." ), + rad_badge_color( irradiation ) ) ); } } @@ -3190,31 +3190,31 @@ void item::book_info( std::vector &info, const iteminfo_query *parts, const islot_book &book = *type->book; // Some things about a book you CAN tell by it's cover. if( !book.skill && !type->can_use( "MA_MANUAL" ) && parts->test( iteminfo_parts::BOOK_SUMMARY ) ) { - info.push_back( iteminfo( "BOOK", _( "Just for fun." ) ) ); + info.emplace_back( "BOOK", _( "Just for fun." ) ); } avatar &player_character = get_avatar(); if( type->can_use( "MA_MANUAL" ) && parts->test( iteminfo_parts::BOOK_SUMMARY ) ) { - info.push_back( iteminfo( "BOOK", - _( "Some sort of martial arts training " - "manual." ) ) ); + info.emplace_back( "BOOK", + _( "Some sort of martial arts training " + "manual." ) ); if( player_character.has_identified( typeId() ) ) { const matype_id style_to_learn = martial_art_learned_from( *type ); - info.push_back( iteminfo( "BOOK", - string_format( _( "You can learn %s style " - "from it." ), style_to_learn->name ) ) ); - info.push_back( iteminfo( "BOOK", - string_format( _( "This fighting style is %s " - "to learn." ), - martialart_difficulty( style_to_learn ) ) ) ); - info.push_back( iteminfo( "BOOK", - string_format( _( "It'd be easier to master if you'd have " - "skill expertise in %s." ), - style_to_learn->primary_skill->name() ) ) ); + info.emplace_back( "BOOK", + string_format( _( "You can learn %s style " + "from it." ), style_to_learn->name ) ); + info.emplace_back( "BOOK", + string_format( _( "This fighting style is %s " + "to learn." ), + martialart_difficulty( style_to_learn ) ) ); + info.emplace_back( "BOOK", + string_format( _( "It'd be easier to master if you'd have " + "skill expertise in %s." ), + style_to_learn->primary_skill->name() ) ); } } if( book.req == 0 && parts->test( iteminfo_parts::BOOK_REQUIREMENTS_BEGINNER ) ) { - info.push_back( iteminfo( "BOOK", _( "It can be understood by " - "beginners." ) ) ); + info.emplace_back( "BOOK", _( "It can be understood by " + "beginners." ) ); } if( player_character.has_identified( typeId() ) ) { if( book.skill ) { @@ -3223,31 +3223,31 @@ void item::book_info( std::vector &info, const iteminfo_query *parts, const std::string skill_name = book.skill->name(); std::string fmt = string_format( _( "Can bring your %s skill to " "." ), skill_name ); - info.push_back( iteminfo( "BOOK", "", fmt, iteminfo::no_flags, book.level ) ); + info.emplace_back( "BOOK", "", fmt, iteminfo::no_flags, book.level ); fmt = string_format( _( "Your current %s skill is ." ), skill_name ); - info.push_back( iteminfo( "BOOK", "", fmt, iteminfo::no_flags, skill.level() ) ); + info.emplace_back( "BOOK", "", fmt, iteminfo::no_flags, skill.level() ); } if( book.req != 0 && parts->test( iteminfo_parts::BOOK_SKILLRANGE_MIN ) ) { const std::string fmt = string_format( _( "Requires %s level to " "understand." ), book.skill.obj().name() ); - info.push_back( iteminfo( "BOOK", "", fmt, - iteminfo::lower_is_better, book.req ) ); + info.emplace_back( "BOOK", "", fmt, + iteminfo::lower_is_better, book.req ); } } if( book.intel != 0 && parts->test( iteminfo_parts::BOOK_REQUIREMENTS_INT ) ) { - info.push_back( iteminfo( "BOOK", "", - _( "Requires intelligence of to easily " - "read." ), iteminfo::lower_is_better, book.intel ) ); + info.emplace_back( "BOOK", "", + _( "Requires intelligence of to easily " + "read." ), iteminfo::lower_is_better, book.intel ); } if( player_character.book_fun_for( *this, player_character ) != 0 && parts->test( iteminfo_parts::BOOK_MORALECHANGE ) ) { - info.push_back( iteminfo( "BOOK", "", - _( "Reading this book affects your morale by " ), - iteminfo::show_plus, player_character.book_fun_for( *this, player_character ) ) ); + info.emplace_back( "BOOK", "", + _( "Reading this book affects your morale by " ), + iteminfo::show_plus, player_character.book_fun_for( *this, player_character ) ); } if( parts->test( iteminfo_parts::BOOK_TIMEPERCHAPTER ) ) { std::string fmt = ngettext( @@ -3262,8 +3262,8 @@ void item::book_info( std::vector &info, const iteminfo_query *parts, "A training session with this book takes " " minutes.", book.time ); } - info.push_back( iteminfo( "BOOK", "", fmt, - iteminfo::lower_is_better, book.time ) ); + info.emplace_back( "BOOK", "", fmt, + iteminfo::lower_is_better, book.time ); } if( book.chapters > 0 && parts->test( iteminfo_parts::BOOK_NUMUNREADCHAPTERS ) ) { @@ -3271,7 +3271,7 @@ void item::book_info( std::vector &info, const iteminfo_query *parts, std::string fmt = ngettext( "This book has unread chapter.", "This book has unread chapters.", unread ); - info.push_back( iteminfo( "BOOK", "", fmt, iteminfo::no_flags, unread ) ); + info.emplace_back( "BOOK", "", fmt, iteminfo::no_flags, unread ); } if( !book.proficiencies.empty() ) { @@ -3284,7 +3284,7 @@ void item::book_info( std::vector &info, const iteminfo_query *parts, book.proficiencies.begin(), book.proficiencies.end(), enumerate_profs ) ); - info.push_back( iteminfo( "BOOK", profs ) ); + info.emplace_back( "BOOK", profs ); } if( parts->test( iteminfo_parts::BOOK_INCLUDED_RECIPES ) ) { @@ -3317,22 +3317,22 @@ void item::book_info( std::vector &info, const iteminfo_query *parts, recipe_list.size(), enumerate_as_string( recipe_list ) ); insert_separation_line( info ); - info.push_back( iteminfo( "DESCRIPTION", recipe_line ) ); + info.emplace_back( "DESCRIPTION", recipe_line ); } if( recipe_list.size() != book.recipes.size() && parts->test( iteminfo_parts::DESCRIPTION_BOOK_ADDITIONAL_RECIPES ) ) { - info.push_back( iteminfo( "DESCRIPTION", - _( "It might help you figuring out some more " - "recipes." ) ) ); + info.emplace_back( "DESCRIPTION", + _( "It might help you figuring out some more " + "recipes." ) ); } } } else { if( parts->test( iteminfo_parts::BOOK_UNREAD ) ) { - info.push_back( iteminfo( "BOOK", - _( "You need to read this book to see its " - "contents." ) ) ); + info.emplace_back( "BOOK", + _( "You need to read this book to see its " + "contents." ) ); } } } @@ -3406,24 +3406,24 @@ void item::tool_info( std::vector &info, const iteminfo_query *parts, // UPS, rechargeable power cells, and bionic power if( has_flag( flag_USE_UPS ) && parts->test( iteminfo_parts::DESCRIPTION_RECHARGE_UPSMODDED ) ) { - info.push_back( iteminfo( "DESCRIPTION", - _( "* This tool has been modified to use a universal " - "power supply and is not compatible" - " with standard batteries." ) ) ); + info.emplace_back( "DESCRIPTION", + _( "* This tool has been modified to use a universal " + "power supply and is not compatible" + " with standard batteries." ) ); } else if( has_flag( flag_RECHARGE ) && has_flag( flag_NO_RELOAD ) && parts->test( iteminfo_parts::DESCRIPTION_RECHARGE_NORELOAD ) ) { - info.push_back( iteminfo( "DESCRIPTION", - _( "* This tool has a rechargeable power cell " - "and is not compatible with " - "standard batteries." ) ) ); + info.emplace_back( "DESCRIPTION", + _( "* This tool has a rechargeable power cell " + "and is not compatible with " + "standard batteries." ) ); } else if( has_flag( flag_RECHARGE ) && parts->test( iteminfo_parts::DESCRIPTION_RECHARGE_UPSCAPABLE ) ) { - info.push_back( iteminfo( "DESCRIPTION", - _( "* This tool has a rechargeable power cell " - "and can be recharged in any UPS-compatible " - "recharging station. You could charge it with " - "standard batteries, but unloading it is " - "impossible." ) ) ); + info.emplace_back( "DESCRIPTION", + _( "* This tool has a rechargeable power cell " + "and can be recharged in any UPS-compatible " + "recharging station. You could charge it with " + "standard batteries, but unloading it is " + "impossible." ) ); } else if( has_flag( flag_USES_BIONIC_POWER ) ) { info.emplace_back( "DESCRIPTION", _( "* This tool runs on bionic power." ) ); @@ -3444,7 +3444,7 @@ void item::tool_info( std::vector &info, const iteminfo_query *parts, feedback = _( "Almost completely burned out." ); } feedback = _( "Fuel: " ) + feedback; - info.push_back( iteminfo( "DESCRIPTION", feedback ) ); + info.emplace_back( "DESCRIPTION", feedback ); } } @@ -3455,11 +3455,11 @@ void item::component_info( std::vector &info, const iteminfo_query *pa return; } if( is_craft() ) { - info.push_back( iteminfo( "DESCRIPTION", string_format( _( "Using: %s" ), - components_to_string() ) ) ); + info.emplace_back( "DESCRIPTION", string_format( _( "Using: %s" ), + components_to_string() ) ); } else { - info.push_back( iteminfo( "DESCRIPTION", string_format( _( "Made from: %s" ), - components_to_string() ) ) ); + info.emplace_back( "DESCRIPTION", string_format( _( "Made from: %s" ), + components_to_string() ) ); } } @@ -3536,7 +3536,7 @@ void item::disassembly_info( std::vector &info, const iteminfo_query * } insert_separation_line( info ); - info.push_back( iteminfo( "DESCRIPTION", descr ) ); + info.emplace_back( "DESCRIPTION", descr ); } } @@ -3597,15 +3597,15 @@ void item::bionic_info( std::vector &info, const iteminfo_query *parts // TODO: Unhide when enforcing limits if( get_option < bool >( "CBM_SLOTS_ENABLED" ) && parts->test( iteminfo_parts::DESCRIPTION_CBM_SLOTS ) ) { - info.push_back( iteminfo( "DESCRIPTION", list_occupied_bps( type->bionic->id, - _( "This bionic is installed in the following body " - "part(s):" ) ) ) ); + info.emplace_back( "DESCRIPTION", list_occupied_bps( type->bionic->id, + _( "This bionic is installed in the following body " + "part(s):" ) ) ); } insert_separation_line( info ); if( is_bionic() && has_flag( flag_NO_STERILE ) ) { - info.push_back( iteminfo( "DESCRIPTION", - _( "* This bionic is not sterile, use an autoclave and an autoclave pouch to sterilize it. " ) ) ); + info.emplace_back( "DESCRIPTION", + _( "* This bionic is not sterile, use an autoclave and an autoclave pouch to sterilize it. " ) ); } insert_separation_line( info ); @@ -3614,79 +3614,78 @@ void item::bionic_info( std::vector &info, const iteminfo_query *parts if( !fuels.empty() ) { const int &fuel_numb = fuels.size(); - info.push_back( iteminfo( "DESCRIPTION", - ngettext( "* This bionic can produce power from the following fuel: ", - "* This bionic can produce power from the following fuels: ", - fuel_numb ) + enumerate_as_string( fuels.begin(), - fuels.end(), []( const material_id & id ) -> std::string { return "" + id->name() + ""; } ) ) ); + info.emplace_back( "DESCRIPTION", + ngettext( "* This bionic can produce power from the following fuel: ", + "* This bionic can produce power from the following fuels: ", + fuel_numb ) + enumerate_as_string( fuels.begin(), + fuels.end(), []( const material_id & id ) -> std::string { return "" + id->name() + ""; } ) ); } insert_separation_line( info ); if( bid->capacity > 0_mJ ) { - info.push_back( iteminfo( "CBM", _( "Power Capacity:" ), _( " mJ" ), - iteminfo::no_newline, - units::to_millijoule( bid->capacity ) ) ); + info.emplace_back( "CBM", _( "Power Capacity:" ), _( " mJ" ), + iteminfo::no_newline, + units::to_millijoule( bid->capacity ) ); } insert_separation_line( info ); // TODO refactor these almost identical blocks if( !bid->encumbrance.empty() ) { - info.push_back( iteminfo( "DESCRIPTION", _( "Encumbrance:" ), - iteminfo::no_newline ) ); + info.emplace_back( "DESCRIPTION", _( "Encumbrance:" ), + iteminfo::no_newline ); for( const std::pair &element : sorted_lex( bid->encumbrance ) ) { - info.push_back( - iteminfo( "CBM", " " + body_part_name_as_heading( element.first.id(), 1 ), - " ", iteminfo::no_newline, element.second ) ); + info.emplace_back( "CBM", " " + body_part_name_as_heading( element.first.id(), 1 ), + " ", iteminfo::no_newline, element.second ); } } if( !bid->env_protec.empty() ) { - info.push_back( iteminfo( "DESCRIPTION", - _( "Environmental Protection:" ), - iteminfo::no_newline ) ); + info.emplace_back( "DESCRIPTION", + _( "Environmental Protection:" ), + iteminfo::no_newline ); for( const std::pair< bodypart_str_id, size_t > &element : sorted_lex( bid->env_protec ) ) { - info.push_back( iteminfo( "CBM", " " + body_part_name_as_heading( element.first, 1 ), - " ", iteminfo::no_newline, element.second ) ); + info.emplace_back( "CBM", " " + body_part_name_as_heading( element.first, 1 ), + " ", iteminfo::no_newline, element.second ); } } if( !bid->bash_protec.empty() ) { - info.push_back( iteminfo( "DESCRIPTION", - _( "Bash Protection:" ), - iteminfo::no_newline ) ); + info.emplace_back( "DESCRIPTION", + _( "Bash Protection:" ), + iteminfo::no_newline ); for( const std::pair< bodypart_str_id, size_t > &element : sorted_lex( bid->bash_protec ) ) { - info.push_back( iteminfo( "CBM", " " + body_part_name_as_heading( element.first, 1 ), - " ", iteminfo::no_newline, element.second ) ); + info.emplace_back( "CBM", " " + body_part_name_as_heading( element.first, 1 ), + " ", iteminfo::no_newline, element.second ); } } if( !bid->cut_protec.empty() ) { - info.push_back( iteminfo( "DESCRIPTION", - _( "Cut Protection:" ), - iteminfo::no_newline ) ); + info.emplace_back( "DESCRIPTION", + _( "Cut Protection:" ), + iteminfo::no_newline ); for( const std::pair< bodypart_str_id, size_t > &element : sorted_lex( bid->cut_protec ) ) { - info.push_back( iteminfo( "CBM", " " + body_part_name_as_heading( element.first, 1 ), - " ", iteminfo::no_newline, element.second ) ); + info.emplace_back( "CBM", " " + body_part_name_as_heading( element.first, 1 ), + " ", iteminfo::no_newline, element.second ); } } if( !bid->bullet_protec.empty() ) { - info.push_back( iteminfo( "DESCRIPTION", _( "Ballistic Protection:" ), - iteminfo::no_newline ) ); + info.emplace_back( "DESCRIPTION", _( "Ballistic Protection:" ), + iteminfo::no_newline ); for( const std::pair< bodypart_str_id, size_t > &element : sorted_lex( bid->bullet_protec ) ) { - info.push_back( iteminfo( "CBM", " " + body_part_name_as_heading( element.first, 1 ), - " ", iteminfo::no_newline, element.second ) ); + info.emplace_back( "CBM", " " + body_part_name_as_heading( element.first, 1 ), + " ", iteminfo::no_newline, element.second ); } } if( !bid->stat_bonus.empty() ) { - info.push_back( iteminfo( "DESCRIPTION", _( "Stat Bonus:" ), - iteminfo::no_newline ) ); + info.emplace_back( "DESCRIPTION", _( "Stat Bonus:" ), + iteminfo::no_newline ); for( const auto &element : bid->stat_bonus ) { - info.push_back( iteminfo( "CBM", " " + get_stat_name( element.first ), " ", - iteminfo::no_newline, element.second ) ); + info.emplace_back( "CBM", " " + get_stat_name( element.first ), " ", + iteminfo::no_newline, element.second ); } } @@ -3699,10 +3698,10 @@ void item::bionic_info( std::vector &info, const iteminfo_query *parts } else { modifier = "x"; } - info.push_back( iteminfo( "CBM", - _( "Weight capacity modifier: " ), modifier, - iteminfo::no_newline | iteminfo::is_decimal, - weight_modif ) ); + info.emplace_back( "CBM", + _( "Weight capacity modifier: " ), modifier, + iteminfo::no_newline | iteminfo::is_decimal, + weight_modif ); } if( weight_bonus != 0_gram ) { std::string bonus; @@ -3711,9 +3710,9 @@ void item::bionic_info( std::vector &info, const iteminfo_query *parts } else { bonus = string_format( " %s", weight_units() ); } - info.push_back( iteminfo( "CBM", _( "Weight capacity bonus: " ), bonus, - iteminfo::no_newline | iteminfo::is_decimal, - convert_weight( weight_bonus ) ) ); + info.emplace_back( "CBM", _( "Weight capacity bonus: " ), bonus, + iteminfo::no_newline | iteminfo::is_decimal, + convert_weight( weight_bonus ) ); } } @@ -3729,30 +3728,30 @@ void item::combat_info( std::vector &info, const iteminfo_query *parts insert_separation_line( info ); std::string sep; if( dmg_bash || dmg_cut || dmg_stab ) { - info.push_back( iteminfo( "BASE", _( "Melee damage: " ), "", iteminfo::no_newline ) ); + info.emplace_back( "BASE", _( "Melee damage: " ), "", iteminfo::no_newline ); } if( dmg_bash ) { - info.push_back( iteminfo( "BASE", _( "Bash: " ), "", iteminfo::no_newline, dmg_bash ) ); + info.emplace_back( "BASE", _( "Bash: " ), "", iteminfo::no_newline, dmg_bash ); sep = space; } if( dmg_cut ) { - info.push_back( iteminfo( "BASE", sep + _( "Cut: " ), "", iteminfo::no_newline, dmg_cut ) ); + info.emplace_back( "BASE", sep + _( "Cut: " ), "", iteminfo::no_newline, dmg_cut ); sep = space; } if( dmg_stab ) { - info.push_back( iteminfo( "BASE", sep + _( "Pierce: " ), "", iteminfo::no_newline, dmg_stab ) ); + info.emplace_back( "BASE", sep + _( "Pierce: " ), "", iteminfo::no_newline, dmg_stab ); } } if( dmg_bash || dmg_cut || dmg_stab ) { if( parts->test( iteminfo_parts::BASE_TOHIT ) ) { - info.push_back( iteminfo( "BASE", space + _( "To-hit bonus: " ), "", - iteminfo::show_plus, type->m_to_hit ) ); + info.emplace_back( "BASE", space + _( "To-hit bonus: " ), "", + iteminfo::show_plus, type->m_to_hit ); } if( parts->test( iteminfo_parts::BASE_MOVES ) ) { - info.push_back( iteminfo( "BASE", _( "Moves per attack: " ), "", - iteminfo::lower_is_better, attack_time() ) ); + info.emplace_back( "BASE", _( "Moves per attack: " ), "", + iteminfo::lower_is_better, attack_time() ); } @@ -3777,11 +3776,11 @@ void item::combat_info( std::vector &info, const iteminfo_query *parts if( !all_techniques.empty() ) { const std::vector all_tec_sorted = sorted_lex( all_techniques ); insert_separation_line( info ); - info.push_back( iteminfo( "DESCRIPTION", _( "Techniques when wielded: " ) + + info.emplace_back( "DESCRIPTION", _( "Techniques when wielded: " ) + enumerate_as_string( all_tec_sorted.begin(), all_tec_sorted.end(), []( const matec_id & tid ) { return string_format( "%s: %s", tid.obj().name, tid.obj().description ); - } ) ) ); + } ) ); } } @@ -3792,9 +3791,9 @@ void item::combat_info( std::vector &info, const iteminfo_query *parts typeId() ); if( !valid_styles.empty() ) { insert_separation_line( info ); - info.push_back( iteminfo( "DESCRIPTION", - _( "You know how to use this with these martial arts " - "styles: " ) + valid_styles ) ); + info.emplace_back( "DESCRIPTION", + _( "You know how to use this with these martial arts " + "styles: " ) + valid_styles ); } } @@ -3802,13 +3801,13 @@ void item::combat_info( std::vector &info, const iteminfo_query *parts parts->test( iteminfo_parts::DESCRIPTION_GUNMOD_ADDREACHATTACK ) ) { insert_separation_line( info ); if( has_flag( flag_REACH3 ) ) { - info.push_back( iteminfo( "DESCRIPTION", - _( "* This item can be used to make long reach " - "attacks." ) ) ); + info.emplace_back( "DESCRIPTION", + _( "* This item can be used to make long reach " + "attacks." ) ); } else { - info.push_back( iteminfo( "DESCRIPTION", - _( "* This item can be used to make reach " - "attacks." ) ) ); + info.emplace_back( "DESCRIPTION", + _( "* This item can be used to make reach " + "attacks." ) ); } } @@ -3822,50 +3821,50 @@ void item::combat_info( std::vector &info, const iteminfo_query *parts int attack_cost = player_character.attack_speed( *this ); insert_separation_line( info ); if( parts->test( iteminfo_parts::DESCRIPTION_MELEEDMG ) ) { - info.push_back( iteminfo( "DESCRIPTION", _( "Average melee damage:" ) ) ); + info.emplace_back( "DESCRIPTION", _( "Average melee damage:" ) ); } // Chance of critical hit if( parts->test( iteminfo_parts::DESCRIPTION_MELEEDMG_CRIT ) ) { - info.push_back( iteminfo( "DESCRIPTION", - string_format( _( "Critical hit chance %d%% - %d%%" ), + info.emplace_back( "DESCRIPTION", + string_format( _( "Critical hit chance %d%% - %d%%" ), static_cast( player_character.crit_chance( 0, 100, *this ) * 100 ), static_cast( player_character.crit_chance( 100, 0, *this ) * - 100 ) ) ) ); + 100 ) ) ); } // Bash damage if( parts->test( iteminfo_parts::DESCRIPTION_MELEEDMG_BASH ) ) { // NOTE: Using "BASE" instead of "DESCRIPTION", so numerical formatting will work // (output.cpp:format_item_info does not interpolate for DESCRIPTION info) - info.push_back( iteminfo( "BASE", _( "Bashing: " ), "", iteminfo::no_newline, - non_crit.type_damage( damage_type::BASH ) ) ); - info.push_back( iteminfo( "BASE", space + _( "Critical bash: " ), "", iteminfo::no_flags, - crit.type_damage( damage_type::BASH ) ) ); + info.emplace_back( "BASE", _( "Bashing: " ), "", iteminfo::no_newline, + non_crit.type_damage( damage_type::BASH ) ); + info.emplace_back( "BASE", space + _( "Critical bash: " ), "", iteminfo::no_flags, + crit.type_damage( damage_type::BASH ) ); } // Cut damage if( ( non_crit.type_damage( damage_type::CUT ) > 0.0f || crit.type_damage( damage_type::CUT ) > 0.0f ) && parts->test( iteminfo_parts::DESCRIPTION_MELEEDMG_CUT ) ) { - info.push_back( iteminfo( "BASE", _( "Cutting: " ), "", iteminfo::no_newline, - non_crit.type_damage( damage_type::CUT ) ) ); - info.push_back( iteminfo( "BASE", space + _( "Critical cut: " ), "", iteminfo::no_flags, - crit.type_damage( damage_type::CUT ) ) ); + info.emplace_back( "BASE", _( "Cutting: " ), "", iteminfo::no_newline, + non_crit.type_damage( damage_type::CUT ) ); + info.emplace_back( "BASE", space + _( "Critical cut: " ), "", iteminfo::no_flags, + crit.type_damage( damage_type::CUT ) ); } // Pierce/stab damage if( ( non_crit.type_damage( damage_type::STAB ) > 0.0f || crit.type_damage( damage_type::STAB ) > 0.0f ) && parts->test( iteminfo_parts::DESCRIPTION_MELEEDMG_PIERCE ) ) { - info.push_back( iteminfo( "BASE", _( "Piercing: " ), "", iteminfo::no_newline, - non_crit.type_damage( damage_type::STAB ) ) ); - info.push_back( iteminfo( "BASE", space + _( "Critical pierce: " ), "", iteminfo::no_flags, - crit.type_damage( damage_type::STAB ) ) ); + info.emplace_back( "BASE", _( "Piercing: " ), "", iteminfo::no_newline, + non_crit.type_damage( damage_type::STAB ) ); + info.emplace_back( "BASE", space + _( "Critical pierce: " ), "", iteminfo::no_flags, + crit.type_damage( damage_type::STAB ) ); } // Moves if( parts->test( iteminfo_parts::DESCRIPTION_MELEEDMG_MOVES ) ) { - info.push_back( iteminfo( "BASE", _( "Moves per attack: " ), "", - iteminfo::lower_is_better, attack_cost ) ); + info.emplace_back( "BASE", _( "Moves per attack: " ), "", + iteminfo::lower_is_better, attack_cost ); } insert_separation_line( info ); } @@ -3951,14 +3950,14 @@ void item::final_info( std::vector &info, const iteminfo_query *parts, if( parts->test( iteminfo_parts::DESCRIPTION_CONDUCTIVITY ) ) { if( !conductive() ) { - info.push_back( iteminfo( "BASE", _( "* This item does not " - "conduct electricity." ) ) ); + info.emplace_back( "BASE", _( "* This item does not " + "conduct electricity." ) ); } else if( has_flag( flag_CONDUCTIVE ) ) { - info.push_back( iteminfo( "BASE", - _( "* This item effectively conducts " - "electricity, as it has no guard." ) ) ); + info.emplace_back( "BASE", + _( "* This item effectively conducts " + "electricity, as it has no guard." ) ); } else { - info.push_back( iteminfo( "BASE", _( "* This item conducts electricity." ) ) ); + info.emplace_back( "BASE", _( "* This item conducts electricity." ) ); } } @@ -4024,16 +4023,16 @@ void item::final_info( std::vector &info, const iteminfo_query *parts, if( has_flag( flag_LEAK_DAM ) && has_flag( flag_RADIOACTIVE ) && damage() > 0 && parts->test( iteminfo_parts::DESCRIPTION_RADIOACTIVITY_DAMAGED ) ) { - info.push_back( iteminfo( "DESCRIPTION", - _( "* The casing of this item has cracked, " - "revealing an ominous green glow." ) ) ); + info.emplace_back( "DESCRIPTION", + _( "* The casing of this item has cracked, " + "revealing an ominous green glow." ) ); } if( has_flag( flag_LEAK_ALWAYS ) && has_flag( flag_RADIOACTIVE ) && parts->test( iteminfo_parts::DESCRIPTION_RADIOACTIVITY_ALWAYS ) ) { - info.push_back( iteminfo( "DESCRIPTION", - _( "* This object is surrounded by a " - "sickly green glow." ) ) ); + info.emplace_back( "DESCRIPTION", + _( "* This object is surrounded by a " + "sickly green glow." ) ); } if( is_brewable() ) { @@ -4043,25 +4042,25 @@ void item::final_info( std::vector &info, const iteminfo_query *parts, int btime_i = to_days( btime ); if( btime <= 2_days ) { btime_i = to_hours( btime ); - info.push_back( iteminfo( "DESCRIPTION", - string_format( ngettext( "* Once set in a vat, this " + info.emplace_back( "DESCRIPTION", + string_format( ngettext( "* Once set in a vat, this " "will ferment in around %d hour.", "* Once set in a vat, this will ferment in " - "around %d hours.", btime_i ), btime_i ) ) ); + "around %d hours.", btime_i ), btime_i ) ); } else { - info.push_back( iteminfo( "DESCRIPTION", - string_format( ngettext( "* Once set in a vat, this " + info.emplace_back( "DESCRIPTION", + string_format( ngettext( "* Once set in a vat, this " "will ferment in around %d day.", "* Once set in a vat, this will ferment in " - "around %d days.", btime_i ), btime_i ) ) ); + "around %d days.", btime_i ), btime_i ) ); } } if( parts->test( iteminfo_parts::DESCRIPTION_BREWABLE_PRODUCTS ) ) { for( const itype_id &res : brewed.brewing_results() ) { - info.push_back( iteminfo( "DESCRIPTION", - string_format( _( "* Fermenting this will produce " - "%s." ), - nname( res, brewed.charges ) ) ) ); + info.emplace_back( "DESCRIPTION", + string_format( _( "* Fermenting this will produce " + "%s." ), + nname( res, brewed.charges ) ) ); } } } @@ -4105,13 +4104,13 @@ void item::final_info( std::vector &info, const iteminfo_query *parts, } const int time_to_do = tt->time_to_do( *this ); if( time_to_do <= 0 ) { - info.push_back( iteminfo( "DESCRIPTION", - _( "It's done and can be activated." ) ) ); + info.emplace_back( "DESCRIPTION", + _( "It's done and can be activated." ) ); } else { const std::string time = to_string_clipped( time_duration::from_turns( time_to_do ) ); - info.push_back( iteminfo( "DESCRIPTION", - string_format( _( "It will be done in %s." ), - time.c_str() ) ) ); + info.emplace_back( "DESCRIPTION", + string_format( _( "It will be done in %s." ), + time.c_str() ) ); } } } @@ -4138,7 +4137,7 @@ void item::final_info( std::vector &info, const iteminfo_query *parts, //~ %1$s: inscription text ntext = string_format( pgettext( "carving", "Note: %1$s" ), item_note->second ); } - info.push_back( iteminfo( "DESCRIPTION", ntext ) ); + info.emplace_back( "DESCRIPTION", ntext ); } if( parts->test( iteminfo_parts::DESCRIPTION_DIE ) && this->get_var( "die_num_sides", 0 ) != 0 ) { @@ -4154,15 +4153,15 @@ void item::final_info( std::vector &info, const iteminfo_query *parts, const int price_postapoc = price( true ) * batch; if( parts->test( iteminfo_parts::BASE_PRICE ) ) { insert_separation_line( info ); - info.push_back( iteminfo( "BASE", _( "Price: " ), _( "$" ), - iteminfo::is_decimal | iteminfo::lower_is_better | iteminfo::no_newline, - static_cast( price_preapoc ) / 100 ) ); + info.emplace_back( "BASE", _( "Price: " ), _( "$" ), + iteminfo::is_decimal | iteminfo::lower_is_better | iteminfo::no_newline, + static_cast( price_preapoc ) / 100 ); } if( price_preapoc != price_postapoc && parts->test( iteminfo_parts::BASE_BARTER ) ) { const std::string space = " "; - info.push_back( iteminfo( "BASE", space + _( "Barter value: " ), _( "$" ), - iteminfo::is_decimal | iteminfo::lower_is_better, - static_cast( price_postapoc ) / 100 ) ); + info.emplace_back( "BASE", space + _( "Barter value: " ), _( "$" ), + iteminfo::is_decimal | iteminfo::lower_is_better, + static_cast( price_postapoc ) / 100 ); } // Recipes using this item as an ingredient @@ -4176,17 +4175,17 @@ void item::final_info( std::vector &info, const iteminfo_query *parts, if( item_recipes.empty() ) { insert_separation_line( info ); - info.push_back( iteminfo( "DESCRIPTION", - _( "You know of nothing you could craft with it." ) ) ); + info.emplace_back( "DESCRIPTION", + _( "You know of nothing you could craft with it." ) ); } else { if( item_recipes.size() > 24 ) { insert_separation_line( info ); - info.push_back( iteminfo( "DESCRIPTION", - _( "You know dozens of things you could craft with it." ) ) ); + info.emplace_back( "DESCRIPTION", + _( "You know dozens of things you could craft with it." ) ); } else if( item_recipes.size() > 12 ) { insert_separation_line( info ); - info.push_back( iteminfo( "DESCRIPTION", - _( "You could use it to craft various other things." ) ) ); + info.emplace_back( "DESCRIPTION", + _( "You could use it to craft various other things." ) ); } else { // Extract item names from recipes and sort them std::vector> result_names; @@ -4209,9 +4208,9 @@ void item::final_info( std::vector &info, const iteminfo_query *parts, } } ); insert_separation_line( info ); - info.push_back( iteminfo( "DESCRIPTION", - string_format( _( "You could use it to craft: %s" ), - recipes ) ) ); + info.emplace_back( "DESCRIPTION", + string_format( _( "You could use it to craft: %s" ), + recipes ) ); } } } @@ -4220,9 +4219,9 @@ void item::final_info( std::vector &info, const iteminfo_query *parts, const ret_val can_wear = player_character.can_wear( *this, true ); if( ! can_wear.success() ) { insert_separation_line( info ); - info.push_back( iteminfo( "DESCRIPTION", - // can_wear returns a translated string - string_format( "%s", can_wear.str() ) ) ); + info.emplace_back( "DESCRIPTION", + // can_wear returns a translated string + string_format( "%s", can_wear.str() ) ); } } @@ -4236,7 +4235,7 @@ void item::final_info( std::vector &info, const iteminfo_query *parts, } if( art.is_valid() ) { for( const std::string &line : art->picture ) { - info.push_back( iteminfo( "DESCRIPTION", line ) ); + info.emplace_back( "DESCRIPTION", line ); } } } @@ -7567,7 +7566,7 @@ std::vector> item::get_available_recipes( const C for( const islot_book::recipe_with_description_t &elem : type->book->recipes ) { if( u.get_skill_level( elem.recipe->skill_used ) >= elem.skill_level ) { - recipe_entries.push_back( std::make_pair( elem.recipe, elem.skill_level ) ); + recipe_entries.emplace_back( elem.recipe, elem.skill_level ); } } } else if( has_var( "EIPC_RECIPES" ) ) { @@ -7584,7 +7583,7 @@ std::vector> item::get_available_recipes( const C next_string_index - first_string_index ); const recipe *r = &recipe_id( new_recipe ).obj(); if( u.get_skill_level( r->skill_used ) >= r->difficulty ) { - recipe_entries.push_back( std::make_pair( r, r->difficulty ) ); + recipe_entries.emplace_back( r, r->difficulty ); } first_string_index = next_string_index + 1; } @@ -10796,7 +10795,7 @@ std::vector item::get_uncraft_components() const if( iter != ret.end() ) { iter->count += component.count(); } else { - ret.push_back( item_comp( component.typeId(), component.count() ) ); + ret.emplace_back( component.typeId(), component.count() ); } } } diff --git a/src/item_contents.cpp b/src/item_contents.cpp index 2c055e1cdef65..911b5274ced9c 100644 --- a/src/item_contents.cpp +++ b/src/item_contents.cpp @@ -201,7 +201,7 @@ item_contents::item_contents( const std::vector &pockets ) { for( const pocket_data &data : pockets ) { - contents.push_back( item_pocket( &data ) ); + contents.emplace_back( &data ); } } @@ -1252,7 +1252,7 @@ void item_contents::update_modified_pockets( // in case the debugmsg wasn't clear, this should never happen debugmsg( "Oops! deleted some items when updating pockets that were added via toolmods" ); } - contents.push_back( item_pocket( *mag_or_mag_well ) ); + contents.emplace_back( *mag_or_mag_well ); pocket_iter = contents.erase( pocket_iter ); } else { ++pocket_iter; @@ -1268,7 +1268,7 @@ void item_contents::update_modified_pockets( // we've deleted all of the superfluous copies already, so time to add the new pockets for( const pocket_data *container_pocket : container_pockets ) { - contents.push_back( item_pocket( container_pocket ) ); + contents.emplace_back( container_pocket ); } } @@ -1549,7 +1549,7 @@ int item_contents::best_quality( const quality_id &id ) const static void insert_separation_line( std::vector &info ) { if( info.empty() || info.back().sName != "--" ) { - info.push_back( iteminfo( "DESCRIPTION", "--" ) ); + info.emplace_back( "DESCRIPTION", "--" ); } } diff --git a/src/item_factory.cpp b/src/item_factory.cpp index 9b4ce667f0f4b..c7f736d1e3eef 100644 --- a/src/item_factory.cpp +++ b/src/item_factory.cpp @@ -2575,7 +2575,7 @@ void hflesh_to_flesh( itype &item_template ) // Only add "flesh" material if not already present if( old_size != mats.size() && std::find( mats.begin(), mats.end(), material_id( "flesh" ) ) == mats.end() ) { - mats.push_back( material_id( "flesh" ) ); + mats.emplace_back( "flesh" ); } } @@ -3402,10 +3402,10 @@ bool Item_factory::load_sub_ref( std::unique_ptr &ptr, const Js iname, gname ) ); } if( obj.has_string( iname ) ) { - entries.push_back( std::make_pair( obj.get_string( iname ), false ) ); + entries.emplace_back( obj.get_string( iname ), false ); } if( obj.has_string( gname ) ) { - entries.push_back( std::make_pair( obj.get_string( gname ), true ) ); + entries.emplace_back( obj.get_string( gname ), true ); } const std::string subcontext = name + " of " + parent.context(); diff --git a/src/item_pocket.cpp b/src/item_pocket.cpp index e24dcdf436702..77528f33c5b26 100644 --- a/src/item_pocket.cpp +++ b/src/item_pocket.cpp @@ -822,7 +822,7 @@ void item_pocket::set_item_defaults() static void insert_separation_line( std::vector &info ) { if( info.empty() || info.back().sName != "--" ) { - info.push_back( iteminfo( "DESCRIPTION", "--" ) ); + info.emplace_back( "DESCRIPTION", "--" ); } } @@ -851,10 +851,10 @@ void item_pocket::general_info( std::vector &info, int pocket_number, if( data->max_item_length != 0_mm ) { info.back().bNewLine = true; - info.push_back( iteminfo( "BASE", _( "Maximum item length: " ), - string_format( " %s", length_units( data->max_item_length ) ), - iteminfo::no_flags, - convert_length( data->max_item_length ) ) ); + info.emplace_back( "BASE", _( "Maximum item length: " ), + string_format( " %s", length_units( data->max_item_length ) ), + iteminfo::no_flags, + convert_length( data->max_item_length ) ); } if( data->min_item_volume > 0_ml ) { @@ -1677,19 +1677,19 @@ std::string enumerate( cata::flat_set container ) void item_pocket::favorite_settings::info( std::vector &info ) const { - info.push_back( iteminfo( "BASE", string_format( "%s %d", _( "Priority:" ), priority_rating ) ) ); - info.push_back( iteminfo( "BASE", string_format( _( "Item Whitelist: %s" ), - item_whitelist.empty() ? _( "(empty)" ) : + info.emplace_back( "BASE", string_format( "%s %d", _( "Priority:" ), priority_rating ) ); + info.emplace_back( "BASE", string_format( _( "Item Whitelist: %s" ), + item_whitelist.empty() ? _( "(empty)" ) : enumerate_as_string( item_whitelist.begin(), item_whitelist.end(), []( const itype_id & id ) { return id->nname( 1 ); - } ) ) ) ); - info.push_back( iteminfo( "BASE", string_format( _( "Item Blacklist: %s" ), - item_blacklist.empty() ? _( "(empty)" ) : + } ) ) ); + info.emplace_back( "BASE", string_format( _( "Item Blacklist: %s" ), + item_blacklist.empty() ? _( "(empty)" ) : enumerate_as_string( item_blacklist.begin(), item_blacklist.end(), []( const itype_id & id ) { return id->nname( 1 ); - } ) ) ) ); - info.push_back( iteminfo( "BASE", string_format( _( "Category Whitelist: %s" ), - category_whitelist.empty() ? _( "(empty)" ) : enumerate( category_whitelist ) ) ) ); - info.push_back( iteminfo( "BASE", string_format( _( "Category Blacklist: %s" ), - category_blacklist.empty() ? _( "(empty)" ) : enumerate( category_blacklist ) ) ) ); + } ) ) ); + info.emplace_back( "BASE", string_format( _( "Category Whitelist: %s" ), + category_whitelist.empty() ? _( "(empty)" ) : enumerate( category_whitelist ) ) ); + info.emplace_back( "BASE", string_format( _( "Category Blacklist: %s" ), + category_blacklist.empty() ? _( "(empty)" ) : enumerate( category_blacklist ) ) ); } diff --git a/src/iuse.cpp b/src/iuse.cpp index 586682082764c..a8be2c0d1c8bb 100644 --- a/src/iuse.cpp +++ b/src/iuse.cpp @@ -1856,7 +1856,7 @@ cata::optional iuse::fishing_rod( player *p, item *it, bool, const tripoint } p->add_msg_if_player( _( "You cast your line and wait to hook something…" ) ); p->assign_activity( ACT_FISH, to_moves( 5_hours ), 0, 0, it->tname() ); - p->activity.targets.push_back( item_location( *p, it ) ); + p->activity.targets.emplace_back( *p, it ); p->activity.coord_set = g->get_fishable_locations( 60, *found ); return 0; } @@ -2128,7 +2128,7 @@ cata::optional iuse::pack_cbm( player *p, item *it, bool, const tripoint & } std::vector comps; - comps.push_back( item_comp( it->typeId(), 1 ) ); + comps.emplace_back( it->typeId(), 1 ); p->consume_items( comps, 1, is_crafting_component ); return 0; @@ -3378,7 +3378,7 @@ cata::optional iuse::jackhammer( player *p, item *it, bool, const tripoint } p->assign_activity( ACT_JACKHAMMER, moves ); - p->activity.targets.push_back( item_location( *p, it ) ); + p->activity.targets.emplace_back( *p, it ); p->activity.placement = here.getabs( pnt ); // You can mine either furniture or terrain, and furniture goes first, @@ -3490,7 +3490,7 @@ cata::optional iuse::pickaxe( player *p, item *it, bool, const tripoint &po } p->assign_activity( ACT_PICKAXE, moves, -1 ); - p->activity.targets.push_back( item_location( *p, it ) ); + p->activity.targets.emplace_back( *p, it ); p->activity.placement = here.getabs( pnt ); // You can mine either furniture or terrain, and furniture goes first, @@ -4497,11 +4497,11 @@ cata::optional iuse::portable_game( player *p, item *it, bool active, const if( loaded_software == "null" ) { p->assign_activity( ACT_GENERIC_GAME, to_moves( 1_hours ), -1, p->get_item_position( it ), "gaming" ); - p->activity.targets.push_back( item_location( *p, it ) ); + p->activity.targets.emplace_back( *p, it ); return 0; } p->assign_activity( ACT_GAME, moves, -1, 0, "gaming" ); - p->activity.targets.push_back( item_location( *p, it ) ); + p->activity.targets.emplace_back( *p, it ); std::map game_data; game_data.clear(); int game_score = 0; @@ -4588,7 +4588,7 @@ cata::optional iuse::hand_crank( player *p, item *it, bool, const tripoint p->add_msg_if_player( _( "You start cranking the %s to charge its %s." ), it->tname(), it->magazine_current()->tname() ); p->assign_activity( ACT_HAND_CRANK, moves, -1, 0, "hand-cranking" ); - p->activity.targets.push_back( item_location( *p, it ) ); + p->activity.targets.emplace_back( *p, it ); } else { p->add_msg_if_player( _( "You could use the %s to charge its %s, but it's already charged." ), it->tname(), magazine->tname() ); @@ -4634,7 +4634,7 @@ cata::optional iuse::vibe( player *p, item *it, bool, const tripoint & ) it->tname() ); } p->assign_activity( ACT_VIBE, moves, -1, 0, "de-stressing" ); - p->activity.targets.push_back( item_location( *p, it ) ); + p->activity.targets.emplace_back( *p, it ); } return it->type->charges_to_use(); } @@ -4806,7 +4806,7 @@ cata::optional iuse::mind_splicer( player *p, item *it, bool, const tripoin skill_firstaid ) - 1 ) - 10_minutes * ( p->get_dex() - 8 ), 30_minutes ); player_activity act( ACT_MIND_SPLICER, to_moves( time ) ); - act.targets.push_back( item_location( *p, &data_card ) ); + act.targets.emplace_back( *p, &data_card ); p->assign_activity( act ); return it->type->charges_to_use(); } @@ -5081,7 +5081,7 @@ cata::optional iuse::oxytorch( player *p, item *it, bool, const tripoint & // placing ter here makes resuming tasks work better p->assign_activity( ACT_OXYTORCH, moves, static_cast( ter ) ); - p->activity.targets.push_back( item_location( *p, it ) ); + p->activity.targets.emplace_back( *p, it ); p->activity.placement = pnt; p->activity.values.push_back( charges ); @@ -5397,7 +5397,7 @@ static bool heat_item( player &p ) } p.add_msg_if_player( m_info, _( "You start heating up the food." ) ); p.assign_activity( ACT_HEATING, duration ); - p.activity.targets.push_back( item_location( p, target ) ); + p.activity.targets.emplace_back( p, target ); return true; } @@ -6515,7 +6515,7 @@ cata::optional iuse::einktabletpc( player *p, item *it, bool t, const tripo if( s.empty() ) { continue; } - monster_photos.push_back( mtype_id( s ) ); + monster_photos.emplace_back( s ); std::string menu_str; const monster dummy( monster_photos.back() ); menu_str = dummy.name(); @@ -7650,7 +7650,7 @@ cata::optional iuse::camera( player *p, item *it, bool, const tripoint & ) continue; } - monster_photos.push_back( mtype_id( s ) ); + monster_photos.emplace_back( s ); std::string menu_str; @@ -9609,7 +9609,7 @@ cata::optional iuse::break_stick( player *p, item *it, bool, const tripoint return 0; } std::vector comps; - comps.push_back( item_comp( it->typeId(), 1 ) ); + comps.emplace_back( it->typeId(), 1 ); p->consume_items( comps, 1, is_crafting_component ); int chance = rng( 0, 100 ); map &here = get_map(); diff --git a/src/iuse_actor.cpp b/src/iuse_actor.cpp index 7fe106e1d2066..0f11c2f8e6b8d 100644 --- a/src/iuse_actor.cpp +++ b/src/iuse_actor.cpp @@ -1116,7 +1116,7 @@ void reveal_map_actor::load( const JsonObject &obj ) ter_match_type = jo.get_enum_value( "om_terrain_match_type", ot_match_type::contains ); } - omt_types.push_back( std::make_pair( ter, ter_match_type ) ); + omt_types.emplace_back( ter, ter_match_type ); } } @@ -1323,7 +1323,7 @@ cata::optional firestarter_actor::use( player &p, item &it, bool t, moves_modifier + moves_cost_fast / 100.0 + 2; p.assign_activity( ACT_START_FIRE, moves, potential_skill_gain, 0, it.tname() ); - p.activity.targets.push_back( item_location( p, &it ) ); + p.activity.targets.emplace_back( p, &it ); p.activity.values.push_back( g->natural_light_level( pos.z ) ); p.activity.placement = pos; // charges to use are handled by the activity @@ -3180,8 +3180,8 @@ cata::optional heal_actor::use( player &p, item &it, bool, const tripoint & // Assign first aid long action. /** @EFFECT_FIRSTAID speeds up firstaid activity */ p.assign_activity( ACT_FIRSTAID, cost, 0, 0, it.tname() ); - p.activity.targets.push_back( item_location( p, &it ) ); - p.activity.str_values.push_back( hpp.c_str() ); + p.activity.targets.emplace_back( p, &it ); + p.activity.str_values.emplace_back( hpp.c_str() ); p.moves = 0; return 0; } @@ -4246,7 +4246,7 @@ void sew_advanced_actor::load( const JsonObject &obj ) materials.emplace( line ); } for( const std::string line : obj.get_array( "clothing_mods" ) ) { - clothing_mods.push_back( clothing_mod_id( line ) ); + clothing_mods.emplace_back( line ); } // TODO: Make skill non-mandatory while still erroring on invalid skill @@ -4430,7 +4430,7 @@ cata::optional sew_advanced_actor::use( player &p, item &it, bool, const tr const auto &repair_item = clothing_mods[choice].obj().item_string; std::vector comps; - comps.push_back( item_comp( repair_item, items_needed ) ); + comps.emplace_back( repair_item, items_needed ); p.moves -= to_moves( 30_seconds * p.fine_detail_vision_mod() ); p.practice( used_skill, items_needed * 3 + 3 ); /** @EFFECT_TAILOR randomly improves clothing modification efforts */ diff --git a/src/iuse_software_lightson.cpp b/src/iuse_software_lightson.cpp index c2d31d366fe64..5da853e453317 100644 --- a/src/iuse_software_lightson.cpp +++ b/src/iuse_software_lightson.cpp @@ -154,9 +154,9 @@ int lightson_game::start_game() ui.on_redraw( [&]( const ui_adaptor & ) { std::vector shortcuts; - shortcuts.push_back( _( " toggle lights" ) ); - shortcuts.push_back( _( "eset" ) ); - shortcuts.push_back( _( "uit" ) ); + shortcuts.emplace_back( _( " toggle lights" ) ); + shortcuts.emplace_back( _( "eset" ) ); + shortcuts.emplace_back( _( "uit" ) ); int iWidth = 0; for( auto &shortcut : shortcuts ) { diff --git a/src/iuse_software_minesweeper.cpp b/src/iuse_software_minesweeper.cpp index 3b48b64ed08c1..ef59e867203c3 100644 --- a/src/iuse_software_minesweeper.cpp +++ b/src/iuse_software_minesweeper.cpp @@ -183,9 +183,9 @@ int minesweeper_game::start_game() draw_border( w_minesweeper_border ); std::vector shortcuts; - shortcuts.push_back( _( "ew level" ) ); - shortcuts.push_back( _( "lag" ) ); - shortcuts.push_back( _( "uit" ) ); + shortcuts.emplace_back( _( "ew level" ) ); + shortcuts.emplace_back( _( "lag" ) ); + shortcuts.emplace_back( _( "uit" ) ); int iWidth = 0; for( auto &shortcut : shortcuts ) { diff --git a/src/iuse_software_snake.cpp b/src/iuse_software_snake.cpp index a5baba6558447..0ae65f9f414c2 100644 --- a/src/iuse_software_snake.cpp +++ b/src/iuse_software_snake.cpp @@ -61,18 +61,18 @@ void snake_game::snake_over( const catacurses::window &w_snake, int iScore ) mvwputch( w_snake, point( 71, body_length + 2 ), c_green, 'v' ); std::vector game_over_text; - game_over_text.push_back( R"( ________ _____ _____ ___________)" ); - game_over_text.push_back( R"( / _____/ / _ \ / \ \_ _____/)" ); - game_over_text.push_back( R"(/ \ ___ / /_\ \ / \ / \ | __)_ )" ); - game_over_text.push_back( R"(\ \_\ \/ | \/ Y \ | \)" ); - game_over_text.push_back( R"( \______ /\____|__ /\____|__ //_______ /)" ); - game_over_text.push_back( R"( \/ \/ \/ \/ )" ); - game_over_text.push_back( R"( ________ ____ _________________________ )" ); - game_over_text.push_back( R"( \_____ \\ \ / /\_ _____/\______ \ )" ); - game_over_text.push_back( R"( / | \\ Y / | __)_ | _/ )" ); - game_over_text.push_back( R"( / | \\ / | \ | | \ )" ); - game_over_text.push_back( R"( \_______ / \___/ /_______ / |____|_ / )" ); - game_over_text.push_back( R"( \/ \/ \/ )" ); + game_over_text.emplace_back( R"( ________ _____ _____ ___________)" ); + game_over_text.emplace_back( R"( / _____/ / _ \ / \ \_ _____/)" ); + game_over_text.emplace_back( R"(/ \ ___ / /_\ \ / \ / \ | __)_ )" ); + game_over_text.emplace_back( R"(\ \_\ \/ | \/ Y \ | \)" ); + game_over_text.emplace_back( R"( \______ /\____|__ /\____|__ //_______ /)" ); + game_over_text.emplace_back( R"( \/ \/ \/ \/ )" ); + game_over_text.emplace_back( R"( ________ ____ _________________________ )" ); + game_over_text.emplace_back( R"( \_____ \\ \ / /\_ _____/\______ \ )" ); + game_over_text.emplace_back( R"( / | \\ Y / | __)_ | _/ )" ); + game_over_text.emplace_back( R"( / | \\ / | \ | | \ )" ); + game_over_text.emplace_back( R"( \_______ / \___/ /_______ / |____|_ / )" ); + game_over_text.emplace_back( R"( \/ \/ \/ )" ); for( size_t i = 0; i < game_over_text.size(); i++ ) { mvwprintz( w_snake, point( 17, i + 3 ), c_light_red, game_over_text[i] ); @@ -103,7 +103,7 @@ int snake_game::start_game() ui.mark_resize(); //Snake start position - vSnakeBody.push_back( std::make_pair( FULL_SCREEN_HEIGHT / 2, FULL_SCREEN_WIDTH / 2 ) ); + vSnakeBody.emplace_back( FULL_SCREEN_HEIGHT / 2, FULL_SCREEN_WIDTH / 2 ); mSnakeBody[FULL_SCREEN_HEIGHT / 2][FULL_SCREEN_WIDTH / 2] = true; //Snake start direction @@ -144,28 +144,28 @@ int snake_game::start_game() do { //Check if we hit a border if( vSnakeBody[vSnakeBody.size() - 1].first + iDirY == 0 ) { - vSnakeBody.push_back( std::make_pair( vSnakeBody[vSnakeBody.size() - 1].first + - iDirY + FULL_SCREEN_HEIGHT - 2, - vSnakeBody[vSnakeBody.size() - 1].second + iDirX ) ); + vSnakeBody.emplace_back( vSnakeBody[vSnakeBody.size() - 1].first + + iDirY + FULL_SCREEN_HEIGHT - 2, + vSnakeBody[vSnakeBody.size() - 1].second + iDirX ); } else if( vSnakeBody[vSnakeBody.size() - 1].first + iDirY == FULL_SCREEN_HEIGHT - 1 ) { - vSnakeBody.push_back( std::make_pair( vSnakeBody[vSnakeBody.size() - 1].first + - iDirY - FULL_SCREEN_HEIGHT + 2, - vSnakeBody[vSnakeBody.size() - 1].second + iDirX ) ); + vSnakeBody.emplace_back( vSnakeBody[vSnakeBody.size() - 1].first + + iDirY - FULL_SCREEN_HEIGHT + 2, + vSnakeBody[vSnakeBody.size() - 1].second + iDirX ); } else if( vSnakeBody[vSnakeBody.size() - 1].second + iDirX == 0 ) { - vSnakeBody.push_back( std::make_pair( vSnakeBody[vSnakeBody.size() - 1].first + iDirY, - vSnakeBody[vSnakeBody.size() - 1].second + - iDirX + FULL_SCREEN_WIDTH - 2 ) ); + vSnakeBody.emplace_back( vSnakeBody[vSnakeBody.size() - 1].first + iDirY, + vSnakeBody[vSnakeBody.size() - 1].second + + iDirX + FULL_SCREEN_WIDTH - 2 ); } else if( vSnakeBody[vSnakeBody.size() - 1].second + iDirX == FULL_SCREEN_WIDTH - 1 ) { - vSnakeBody.push_back( std::make_pair( vSnakeBody[vSnakeBody.size() - 1].first + iDirY, - vSnakeBody[vSnakeBody.size() - 1].second + - iDirX - FULL_SCREEN_WIDTH + 2 ) ); + vSnakeBody.emplace_back( vSnakeBody[vSnakeBody.size() - 1].first + iDirY, + vSnakeBody[vSnakeBody.size() - 1].second + + iDirX - FULL_SCREEN_WIDTH + 2 ); } else { - vSnakeBody.push_back( std::make_pair( vSnakeBody[vSnakeBody.size() - 1].first + iDirY, - vSnakeBody[vSnakeBody.size() - 1].second + iDirX ) ); + vSnakeBody.emplace_back( vSnakeBody[vSnakeBody.size() - 1].first + iDirY, + vSnakeBody[vSnakeBody.size() - 1].second + iDirX ); } //Check if we hit ourselves diff --git a/src/iuse_software_sokoban.cpp b/src/iuse_software_sokoban.cpp index d321c0b39baec..bd46d21555229 100644 --- a/src/iuse_software_sokoban.cpp +++ b/src/iuse_software_sokoban.cpp @@ -248,11 +248,11 @@ int sokoban_game::start_game() draw_border( w_sokoban, BORDER_COLOR, _( "Sokoban" ), hilite( c_white ) ); std::vector shortcuts; - shortcuts.push_back( _( "<+> next" ) ); // '+': next - shortcuts.push_back( _( "<-> prev" ) ); // '-': prev - shortcuts.push_back( _( "eset" ) ); // 'r': reset - shortcuts.push_back( _( "uit" ) ); // 'q': quit - shortcuts.push_back( _( "ndo move" ) ); // 'u': undo move + shortcuts.emplace_back( _( "<+> next" ) ); // '+': next + shortcuts.emplace_back( _( "<-> prev" ) ); // '-': prev + shortcuts.emplace_back( _( "eset" ) ); // 'r': reset + shortcuts.emplace_back( _( "uit" ) ); // 'q': quit + shortcuts.emplace_back( _( "ndo move" ) ); // 'u': undo move int indent = 10; for( auto &shortcut : shortcuts ) { @@ -378,7 +378,7 @@ int sokoban_game::start_game() bMovePlayer = true; mLevel[iPlayerY + iDirY * 2][iPlayerX + iDirX * 2] = sMovePackTo == "." ? "*" : "$"; - vUndo.push_back( cUndo( point( iDirX, iDirY ), sMoveTo ) ); + vUndo.emplace_back( point( iDirX, iDirY ), sMoveTo ); iMoves--; } @@ -388,7 +388,7 @@ int sokoban_game::start_game() if( bMovePlayer ) { //move player - vUndo.push_back( cUndo( point( iPlayerX, iPlayerY ), mLevel[iPlayerY][iPlayerX] ) ); + vUndo.emplace_back( point( iPlayerX, iPlayerY ), mLevel[iPlayerY][iPlayerX] ); mLevel[iPlayerY][iPlayerX] = mLevel[iPlayerY][iPlayerX] == "+" ? "." : " "; mLevel[iPlayerY + iDirY][iPlayerX + iDirX] = sMoveTo == "." || sMoveTo == "*" ? "+" : "@"; diff --git a/src/lightmap.cpp b/src/lightmap.cpp index 9c0de7c0b5aff..e82fb2c985608 100644 --- a/src/lightmap.cpp +++ b/src/lightmap.cpp @@ -493,7 +493,7 @@ void map::generate_lightmap( const int zlev ) } const float light_override = cur->get_intensity_level().local_light_override; if( light_override >= 0.0f ) { - lm_override.push_back( std::pair( p, light_override ) ); + lm_override.emplace_back( p, light_override ); } } } diff --git a/src/line.cpp b/src/line.cpp index 98bf894853642..4c3959731b03f 100644 --- a/src/line.cpp +++ b/src/line.cpp @@ -548,16 +548,16 @@ std::vector squares_in_direction( const point &p1, const point &p2 ) adjacent_squares.push_back( center_square ); if( p1.x == center_square.x ) { // Horizontally adjacent. - adjacent_squares.push_back( point( p1.x + 1, center_square.y ) ); - adjacent_squares.push_back( point( p1.x - 1, center_square.y ) ); + adjacent_squares.emplace_back( p1.x + 1, center_square.y ); + adjacent_squares.emplace_back( p1.x - 1, center_square.y ); } else if( p1.y == center_square.y ) { // Vertically adjacent. - adjacent_squares.push_back( point( center_square.x, p1.y + 1 ) ); - adjacent_squares.push_back( point( center_square.x, p1.y - 1 ) ); + adjacent_squares.emplace_back( center_square.x, p1.y + 1 ); + adjacent_squares.emplace_back( center_square.x, p1.y - 1 ); } else { // Diagonally adjacent. - adjacent_squares.push_back( point( p1.x, center_square.y ) ); - adjacent_squares.push_back( point( center_square.x, p1.y ) ); + adjacent_squares.emplace_back( p1.x, center_square.y ); + adjacent_squares.emplace_back( center_square.x, p1.y ); } return adjacent_squares; } diff --git a/src/main_menu.cpp b/src/main_menu.cpp index 79a464c2eb188..45ea33525edeb 100644 --- a/src/main_menu.cpp +++ b/src/main_menu.cpp @@ -351,15 +351,15 @@ void main_menu::init_strings() // fill menu with translated menu items vMenuItems.clear(); - vMenuItems.push_back( pgettext( "Main Menu", "OTD" ) ); - vMenuItems.push_back( pgettext( "Main Menu", "ew Game" ) ); - vMenuItems.push_back( pgettext( "Main Menu", "Lod" ) ); - vMenuItems.push_back( pgettext( "Main Menu", "orld" ) ); - vMenuItems.push_back( pgettext( "Main Menu", "pecial" ) ); - vMenuItems.push_back( pgettext( "Main Menu", "Setings" ) ); - vMenuItems.push_back( pgettext( "Main Menu", "Hlp" ) ); - vMenuItems.push_back( pgettext( "Main Menu", "redits" ) ); - vMenuItems.push_back( pgettext( "Main Menu", "uit" ) ); + vMenuItems.emplace_back( pgettext( "Main Menu", "OTD" ) ); + vMenuItems.emplace_back( pgettext( "Main Menu", "ew Game" ) ); + vMenuItems.emplace_back( pgettext( "Main Menu", "Lod" ) ); + vMenuItems.emplace_back( pgettext( "Main Menu", "orld" ) ); + vMenuItems.emplace_back( pgettext( "Main Menu", "pecial" ) ); + vMenuItems.emplace_back( pgettext( "Main Menu", "Setings" ) ); + vMenuItems.emplace_back( pgettext( "Main Menu", "Hlp" ) ); + vMenuItems.emplace_back( pgettext( "Main Menu", "redits" ) ); + vMenuItems.emplace_back( pgettext( "Main Menu", "uit" ) ); // determine hotkeys from translated menu item text vMenuHotkeys.clear(); @@ -368,11 +368,11 @@ void main_menu::init_strings() } vWorldSubItems.clear(); - vWorldSubItems.push_back( pgettext( "Main Menu|World", "elete World" ) ); - vWorldSubItems.push_back( pgettext( "Main Menu|World", "eset World" ) ); - vWorldSubItems.push_back( pgettext( "Main Menu|World", "how World Mods" ) ); - vWorldSubItems.push_back( pgettext( "Main Menu|World", "opy World Settings" ) ); - vWorldSubItems.push_back( pgettext( "Main Menu|World", "Character to emplate" ) ); + vWorldSubItems.emplace_back( pgettext( "Main Menu|World", "elete World" ) ); + vWorldSubItems.emplace_back( pgettext( "Main Menu|World", "eset World" ) ); + vWorldSubItems.emplace_back( pgettext( "Main Menu|World", "how World Mods" ) ); + vWorldSubItems.emplace_back( pgettext( "Main Menu|World", "opy World Settings" ) ); + vWorldSubItems.emplace_back( pgettext( "Main Menu|World", "Character to emplate" ) ); vWorldHotkeys.clear(); for( const std::string &item : vWorldSubItems ) { @@ -380,11 +380,11 @@ void main_menu::init_strings() } vSettingsSubItems.clear(); - vSettingsSubItems.push_back( pgettext( "Main Menu|Settings", "ptions" ) ); - vSettingsSubItems.push_back( pgettext( "Main Menu|Settings", "Kybindings" ) ); - vSettingsSubItems.push_back( pgettext( "Main Menu|Settings", "utopickup" ) ); - vSettingsSubItems.push_back( pgettext( "Main Menu|Settings", "afemode" ) ); - vSettingsSubItems.push_back( pgettext( "Main Menu|Settings", "olors" ) ); + vSettingsSubItems.emplace_back( pgettext( "Main Menu|Settings", "ptions" ) ); + vSettingsSubItems.emplace_back( pgettext( "Main Menu|Settings", "Kybindings" ) ); + vSettingsSubItems.emplace_back( pgettext( "Main Menu|Settings", "utopickup" ) ); + vSettingsSubItems.emplace_back( pgettext( "Main Menu|Settings", "afemode" ) ); + vSettingsSubItems.emplace_back( pgettext( "Main Menu|Settings", "olors" ) ); vSettingsHotkeys.clear(); for( const std::string &item : vSettingsSubItems ) { @@ -747,23 +747,22 @@ bool main_menu::opening_screen() bool main_menu::new_character_tab() { std::vector vSubItems; - vSubItems.push_back( pgettext( "Main Menu|New Game", "ustom Character" ) ); - vSubItems.push_back( pgettext( "Main Menu|New Game", "reset Character" ) ); - vSubItems.push_back( pgettext( "Main Menu|New Game", "andom Character" ) ); + vSubItems.emplace_back( pgettext( "Main Menu|New Game", "ustom Character" ) ); + vSubItems.emplace_back( pgettext( "Main Menu|New Game", "reset Character" ) ); + vSubItems.emplace_back( pgettext( "Main Menu|New Game", "andom Character" ) ); if( !MAP_SHARING::isSharing() ) { // "Play Now" function doesn't play well together with shared maps - vSubItems.push_back( pgettext( "Main Menu|New Game", "Play Now! (ixed Scenario)" ) ); - vSubItems.push_back( pgettext( "Main Menu|New Game", "Play ow!" ) ); + vSubItems.emplace_back( pgettext( "Main Menu|New Game", "Play Now! (ixed Scenario)" ) ); + vSubItems.emplace_back( pgettext( "Main Menu|New Game", "Play ow!" ) ); } std::vector hints; - hints.push_back( + hints.emplace_back( _( "Allows you to fully customize points pool, scenario, and character's profession, stats, traits, skills and other parameters." ) ); - hints.push_back( - _( "Select from one of previously created character templates." ) ); - hints.push_back( + hints.emplace_back( _( "Select from one of previously created character templates." ) ); + hints.emplace_back( _( "Creates random character, but lets you preview the generated character and the scenario and change character and/or scenario if needed." ) ); - hints.push_back( + hints.emplace_back( _( "Puts you right in the game, randomly choosing character's traits, profession, skills and other parameters. Scenario is fixed to Evacuee." ) ); - hints.push_back( + hints.emplace_back( _( "Puts you right in the game, randomly choosing scenario and character's traits, profession, skills and other parameters." ) ); std::vector> vNewGameHotkeys; diff --git a/src/map.cpp b/src/map.cpp index b67d922b39632..ac8bc7579cdbf 100644 --- a/src/map.cpp +++ b/src/map.cpp @@ -3078,7 +3078,7 @@ void map::smash_items( const tripoint &p, const int power, const std::string &ca // But save the contents, except for irremovable gunmods for( item *elem : i->contents.all_items_top() ) { if( !elem->is_irremovable() ) { - contents.push_back( item( *elem ) ); + contents.emplace_back( *elem ); } } @@ -3491,7 +3491,7 @@ void map::bash_items( const tripoint &p, bash_params ¶ms ) params.did_bash = true; smashed_glass = true; for( const item *bashed_content : bashed_item->contents.all_items_top() ) { - smashed_contents.push_back( item( *bashed_content ) ); + smashed_contents.emplace_back( *bashed_content ); } bashed_item = bashed_items.erase( bashed_item ); } else { @@ -5149,7 +5149,7 @@ std::list > map::get_rc_items( const tripoint &p ) map_stack items = i_at( pos ); for( auto &elem : items ) { if( elem.has_flag( flag_RADIO_ACTIVATION ) || elem.has_flag( flag_RADIO_CONTAINER ) ) { - rc_pairs.push_back( std::make_pair( pos, &elem ) ); + rc_pairs.emplace_back( pos, &elem ); } } } diff --git a/src/map_field.cpp b/src/map_field.cpp index dfa2eacfc8623..59d7b0e00f42e 100644 --- a/src/map_field.cpp +++ b/src/map_field.cpp @@ -979,7 +979,7 @@ void field_processor_fd_fire( const tripoint &p, field_entry &cur, field_proc_da const std::list content_list = fuel->contents.all_items_top(); for( item *it : content_list ) { if( !it->is_irremovable() ) { - new_content.push_back( item( *it ) ); + new_content.emplace_back( *it ); } } fuel = items_here.erase( fuel ); @@ -1516,19 +1516,19 @@ void map::player_in_field( player &u ) if( !u.is_on_ground() ) { switch( adjusted_intensity ) { case 3: - parts_burned.push_back( bodypart_id( "hand_l" ) ); - parts_burned.push_back( bodypart_id( "hand_r" ) ); - parts_burned.push_back( bodypart_id( "arm_l" ) ); - parts_burned.push_back( bodypart_id( "arm_r" ) ); + parts_burned.emplace_back( "hand_l" ); + parts_burned.emplace_back( "hand_r" ); + parts_burned.emplace_back( "arm_l" ); + parts_burned.emplace_back( "arm_r" ); /* fallthrough */ case 2: - parts_burned.push_back( bodypart_id( "torso" ) ); + parts_burned.emplace_back( "torso" ); /* fallthrough */ case 1: - parts_burned.push_back( bodypart_id( "foot_l" ) ); - parts_burned.push_back( bodypart_id( "foot_r" ) ); - parts_burned.push_back( bodypart_id( "leg_l" ) ); - parts_burned.push_back( bodypart_id( "leg_r" ) ); + parts_burned.emplace_back( "foot_l" ); + parts_burned.emplace_back( "foot_r" ); + parts_burned.emplace_back( "leg_l" ); + parts_burned.emplace_back( "leg_r" ); } } else { // Lying in the fire is BAAAD news, hits every body part. diff --git a/src/map_item_stack.cpp b/src/map_item_stack.cpp index 362ee16528200..4d18fb414bdd9 100644 --- a/src/map_item_stack.cpp +++ b/src/map_item_stack.cpp @@ -21,7 +21,7 @@ map_item_stack::item_group::item_group( const tripoint &p, const int arg_count, map_item_stack::map_item_stack() : example( nullptr ), totalcount( 0 ) { - vIG.push_back( item_group() ); + vIG.emplace_back( ); } map_item_stack::map_item_stack( const item *const it, const tripoint &pos ) : example( it ), diff --git a/src/mapgen.cpp b/src/mapgen.cpp index d6ebf48bb3446..763673c2bcca1 100644 --- a/src/mapgen.cpp +++ b/src/mapgen.cpp @@ -1328,7 +1328,7 @@ class jmapgen_monster : public jmapgen_piece for( const JsonObject p_pt : patrol_pts ) { jmapgen_int ptx = jmapgen_int( p_pt, "x" ); jmapgen_int pty = jmapgen_int( p_pt, "y" ); - data.patrol_points_rel_ms.push_back( point( ptx.get(), pty.get() ) ); + data.patrol_points_rel_ms.emplace_back( ptx.get(), pty.get() ); } } } @@ -3224,37 +3224,37 @@ void map::draw_lab( mapgendata &dat ) if( is_ot_match( "stairs", terrain_type, ot_match_type::contains ) ) { // Stairs going down std::vector stair_points; if( tw != 0 ) { - stair_points.push_back( point( SEEX - 1, 2 ) ); - stair_points.push_back( point( SEEX - 1, 2 ) ); - stair_points.push_back( point( SEEX, 2 ) ); - stair_points.push_back( point( SEEX, 2 ) ); + stair_points.emplace_back( SEEX - 1, 2 ); + stair_points.emplace_back( SEEX - 1, 2 ); + stair_points.emplace_back( SEEX, 2 ); + stair_points.emplace_back( SEEX, 2 ); } if( rw != 1 ) { - stair_points.push_back( point( SEEX * 2 - 3, SEEY - 1 ) ); - stair_points.push_back( point( SEEX * 2 - 3, SEEY - 1 ) ); - stair_points.push_back( point( SEEX * 2 - 3, SEEY ) ); - stair_points.push_back( point( SEEX * 2 - 3, SEEY ) ); + stair_points.emplace_back( SEEX * 2 - 3, SEEY - 1 ); + stair_points.emplace_back( SEEX * 2 - 3, SEEY - 1 ); + stair_points.emplace_back( SEEX * 2 - 3, SEEY ); + stair_points.emplace_back( SEEX * 2 - 3, SEEY ); } if( bw != 1 ) { - stair_points.push_back( point( SEEX - 1, SEEY * 2 - 3 ) ); - stair_points.push_back( point( SEEX - 1, SEEY * 2 - 3 ) ); - stair_points.push_back( point( SEEX, SEEY * 2 - 3 ) ); - stair_points.push_back( point( SEEX, SEEY * 2 - 3 ) ); + stair_points.emplace_back( SEEX - 1, SEEY * 2 - 3 ); + stair_points.emplace_back( SEEX - 1, SEEY * 2 - 3 ); + stair_points.emplace_back( SEEX, SEEY * 2 - 3 ); + stair_points.emplace_back( SEEX, SEEY * 2 - 3 ); } if( lw != 0 ) { - stair_points.push_back( point( 2, SEEY - 1 ) ); - stair_points.push_back( point( 2, SEEY - 1 ) ); - stair_points.push_back( point( 2, SEEY ) ); - stair_points.push_back( point( 2, SEEY ) ); + stair_points.emplace_back( 2, SEEY - 1 ); + stair_points.emplace_back( 2, SEEY - 1 ); + stair_points.emplace_back( 2, SEEY ); + stair_points.emplace_back( 2, SEEY ); } - stair_points.push_back( point( static_cast( SEEX / 2 ), SEEY ) ); - stair_points.push_back( point( static_cast( SEEX / 2 ), SEEY - 1 ) ); - stair_points.push_back( point( static_cast( SEEX / 2 ) + SEEX, SEEY ) ); - stair_points.push_back( point( static_cast( SEEX / 2 ) + SEEX, SEEY - 1 ) ); - stair_points.push_back( point( SEEX, static_cast( SEEY / 2 ) ) ); - stair_points.push_back( point( SEEX + 2, static_cast( SEEY / 2 ) ) ); - stair_points.push_back( point( SEEX, static_cast( SEEY / 2 ) + SEEY ) ); - stair_points.push_back( point( SEEX + 2, static_cast( SEEY / 2 ) + SEEY ) ); + stair_points.emplace_back( static_cast( SEEX / 2 ), SEEY ); + stair_points.emplace_back( static_cast( SEEX / 2 ), SEEY - 1 ); + stair_points.emplace_back( static_cast( SEEX / 2 ) + SEEX, SEEY ); + stair_points.emplace_back( static_cast( SEEX / 2 ) + SEEX, SEEY - 1 ); + stair_points.emplace_back( SEEX, static_cast( SEEY / 2 ) ); + stair_points.emplace_back( SEEX + 2, static_cast( SEEY / 2 ) ); + stair_points.emplace_back( SEEX, static_cast( SEEY / 2 ) + SEEY ); + stair_points.emplace_back( SEEX + 2, static_cast( SEEY / 2 ) + SEEY ); const point p = random_entry( stair_points ); ter_set( p, t_stairs_down ); } @@ -4098,7 +4098,7 @@ void map::draw_temple( const mapgendata &dat ) static const std::vector terrains = { t_floor_red, t_floor_green, t_floor_blue, }; - path.push_back( point( x, y ) ); + path.emplace_back( x, y ); ter_set( point( x, y ), random_entry( terrains ) ); if( y == SEEY * 2 - 2 ) { if( x < SEEX - 1 ) { @@ -4111,7 +4111,7 @@ void map::draw_temple( const mapgendata &dat ) for( int nx = x - 1; nx <= x + 1; nx++ ) { for( int ny = y; ny <= y + 1; ny++ ) { if( ter( point( nx, ny ) ) == t_rock_floor ) { - next.push_back( point( nx, ny ) ); + next.emplace_back( nx, ny ); } } } diff --git a/src/mattack_actors.cpp b/src/mattack_actors.cpp index 77069b8f8e3e4..a54ebc7400933 100644 --- a/src/mattack_actors.cpp +++ b/src/mattack_actors.cpp @@ -548,7 +548,7 @@ void gun_actor::shoot( monster &z, Creature &target, const gun_mode_id &mode ) c standard_npc tmp( _( "The " ) + z.name(), z.pos(), {}, 8, fake_str, fake_dex, fake_int, fake_per ); - tmp.worn.push_back( item( "backpack" ) ); + tmp.worn.emplace_back( "backpack" ); tmp.set_fake( true ); tmp.set_attitude( z.friendly ? NPCATT_FOLLOW : NPCATT_KILL ); tmp.recoil = 0; // no need to aim diff --git a/src/memorial_logger.cpp b/src/memorial_logger.cpp index c5982bb223d8f..2475bb41d5c07 100644 --- a/src/memorial_logger.cpp +++ b/src/memorial_logger.cpp @@ -130,7 +130,7 @@ void memorial_logger::add( const std::string &male_msg, const oter_type_str_id cur_oter_type = cur_ter->get_type_id(); const std::string &oter_name = cur_ter->get_name(); - log.push_back( { calendar::turn, cur_oter_type, oter_name, msg } ); + log.emplace_back( calendar::turn, cur_oter_type, oter_name, msg ); } /** diff --git a/src/mission.cpp b/src/mission.cpp index 64848fb2f96ed..5df75c4ecfa90 100644 --- a/src/mission.cpp +++ b/src/mission.cpp @@ -358,7 +358,7 @@ void mission::wrap_up() container, itype_id( "null" ), specific_container_required ); for( std::pair &cnt : matches ) { - comps.push_back( item_comp( cnt.first, cnt.second ) ); + comps.emplace_back( cnt.first, cnt.second ); } @@ -367,10 +367,10 @@ void mission::wrap_up() if( remove_container ) { std::vector container_comp = std::vector(); if( !empty_container.is_null() ) { - container_comp.push_back( item_comp( empty_container, type->item_count ) ); + container_comp.emplace_back( empty_container, type->item_count ); player_character.consume_items( container_comp ); } else { - container_comp.push_back( item_comp( container, type->item_count ) ); + container_comp.emplace_back( container, type->item_count ); player_character.consume_items( container_comp ); } } @@ -390,7 +390,7 @@ void mission::wrap_up() } } } else { - comps.push_back( item_comp( type->item_id, item_count ) ); + comps.emplace_back( type->item_id, item_count ); player_character.consume_items( comps ); } } diff --git a/src/mod_manager.cpp b/src/mod_manager.cpp index 3d8f8178af2da..4d0216cabdc81 100644 --- a/src/mod_manager.cpp +++ b/src/mod_manager.cpp @@ -293,7 +293,7 @@ bool mod_manager::copy_mod_contents( const t_mod_list &mods_to_copy, return true; } std::vector search_extensions; - search_extensions.push_back( ".json" ); + search_extensions.emplace_back( ".json" ); DebugLog( D_INFO, DC_ALL ) << "Copying mod contents into directory: " << output_base_path; diff --git a/src/monattack.cpp b/src/monattack.cpp index 3a3c9ae0a3fa3..b05b54ab5c72b 100644 --- a/src/monattack.cpp +++ b/src/monattack.cpp @@ -985,7 +985,7 @@ bool mattack::resurrect( monster *z ) int raise_score = ( i.damage_level() + 1 ) * mt->hp + i.burnt; lowest_raise_score = std::min( lowest_raise_score, raise_score ); if( raise_score <= raising_level ) { - corpses.push_back( std::make_pair( p, &i ) ); + corpses.emplace_back( p, &i ); } } } diff --git a/src/monexamine.cpp b/src/monexamine.cpp index 3d23556174d14..29aa3a909ef21 100644 --- a/src/monexamine.cpp +++ b/src/monexamine.cpp @@ -302,10 +302,10 @@ void monexamine::shear_animal( monster &z ) // pin the sheep in place if it isn't already if( !z.has_effect( effect_tied ) ) { z.add_effect( effect_tied, 1_turns, true ); - player_character.activity.str_values.push_back( "temp_tie" ); + player_character.activity.str_values.emplace_back( "temp_tie" ); } - player_character.activity.targets.push_back( item_location( player_character, - player_character.best_quality_item( qual_SHEAR ) ) ); + player_character.activity.targets.emplace_back( player_character, + player_character.best_quality_item( qual_SHEAR ) ); add_msg( _( "You start shearing the %s." ), z.get_name() ); } @@ -805,7 +805,7 @@ void monexamine::milk_source( monster &source_mon ) bool temp_tie = !source_mon.has_effect( effect_tied ); if( temp_tie ) { source_mon.add_effect( effect_tied, 1_turns, true ); - str_values.push_back( "temp_tie" ); + str_values.emplace_back( "temp_tie" ); } player_character.assign_activity( player_activity( milk_activity_actor( moves, coords, str_values ) ) ); diff --git a/src/mongroup.cpp b/src/mongroup.cpp index 599a33a4650d6..7c4ffcdaf57e7 100644 --- a/src/mongroup.cpp +++ b/src/mongroup.cpp @@ -128,13 +128,13 @@ MonsterGroupResult MonsterGroupManager::GetResultFromGroup( //Collect valid time of day ranges if( elem == "DAY" || elem == "NIGHT" || elem == "DUSK" || elem == "DAWN" ) { if( elem == "DAY" ) { - valid_times_of_day.push_back( std::make_pair( sunrise, sunset ) ); + valid_times_of_day.emplace_back( sunrise, sunset ); } else if( elem == "NIGHT" ) { - valid_times_of_day.push_back( std::make_pair( sunset, sunrise ) ); + valid_times_of_day.emplace_back( sunset, sunrise ); } else if( elem == "DUSK" ) { - valid_times_of_day.push_back( std::make_pair( sunset - 1_hours, sunset + 1_hours ) ); + valid_times_of_day.emplace_back( sunset - 1_hours, sunset + 1_hours ); } else if( elem == "DAWN" ) { - valid_times_of_day.push_back( std::make_pair( sunrise - 1_hours, sunrise + 1_hours ) ); + valid_times_of_day.emplace_back( sunrise - 1_hours, sunrise + 1_hours ); } } diff --git a/src/monmove.cpp b/src/monmove.cpp index 21644a2101bb8..1687bc7cb05b3 100644 --- a/src/monmove.cpp +++ b/src/monmove.cpp @@ -1401,7 +1401,7 @@ static std::vector get_bashing_zone( const tripoint &bashee, const tri for( const tripoint &p : path ) { std::vector swath = squares_in_direction( previous.xy(), p.xy() ); for( const point &q : swath ) { - zone.push_back( tripoint( q, bashee.z ) ); + zone.emplace_back( q, bashee.z ); } previous = p; @@ -1928,9 +1928,9 @@ void monster::stumble() for( const tripoint &dest : here.points_in_radius( pos(), 1 ) ) { if( dest != pos() ) { if( here.has_flag( TFLAG_RAMP_DOWN, dest ) ) { - valid_stumbles.push_back( tripoint( dest.xy(), dest.z - 1 ) ); + valid_stumbles.emplace_back( dest.xy(), dest.z - 1 ); } else if( here.has_flag( TFLAG_RAMP_UP, dest ) ) { - valid_stumbles.push_back( tripoint( dest.xy(), dest.z + 1 ) ); + valid_stumbles.emplace_back( dest.xy(), dest.z + 1 ); } else { valid_stumbles.push_back( dest ); } diff --git a/src/newcharacter.cpp b/src/newcharacter.cpp index 5b96fdd1d3a19..7a04272a385c8 100644 --- a/src/newcharacter.cpp +++ b/src/newcharacter.cpp @@ -2862,10 +2862,10 @@ tab_direction set_description( avatar &you, const bool allow_reroll, std::vector vStatNames; mvwprintz( w_stats, point_zero, COL_HEADER, _( "Stats:" ) ); - vStatNames.push_back( _( "Strength:" ) ); - vStatNames.push_back( _( "Dexterity:" ) ); - vStatNames.push_back( _( "Intelligence:" ) ); - vStatNames.push_back( _( "Perception:" ) ); + vStatNames.emplace_back( _( "Strength:" ) ); + vStatNames.emplace_back( _( "Dexterity:" ) ); + vStatNames.emplace_back( _( "Intelligence:" ) ); + vStatNames.emplace_back( _( "Perception:" ) ); int pos = 0; for( size_t i = 0; i < vStatNames.size(); i++ ) { pos = ( utf8_width( vStatNames[i] ) > pos ? diff --git a/src/npcmove.cpp b/src/npcmove.cpp index a27cd05da9531..2f3aa940d2244 100644 --- a/src/npcmove.cpp +++ b/src/npcmove.cpp @@ -1267,7 +1267,7 @@ void npc::execute_action( npc_action action ) my_spot = priority; } - seats.push_back( std::make_pair( priority, static_cast( vp.part_index() ) ) ); + seats.emplace_back( priority, static_cast( vp.part_index() ) ); } if( my_spot >= 3 ) { @@ -1406,7 +1406,7 @@ npc_action npc::method_of_attack() std::vector> modes; if( rules.has_flag( ally_rule::use_guns ) || !is_player_ally() ) { for( const auto &e : weapon.gun_all_modes() ) { - modes.push_back( e ); + modes.emplace_back( e ); } modes.erase( std::remove_if( modes.begin(), modes.end(), @@ -3149,7 +3149,7 @@ void npc::drop_items( const units::mass &drop_weight, const units::volume &drop_ } } if( !added_wgt ) { - rWgt.push_back( ratio_index( wgt_ratio, i ) ); + rWgt.emplace_back( wgt_ratio, i ); } for( size_t j = 0; j < rVol.size() && !added_vol; j++ ) { if( vol_ratio > rVol[j].ratio ) { @@ -3158,7 +3158,7 @@ void npc::drop_items( const units::mass &drop_weight, const units::volume &drop_ } } if( !added_vol ) { - rVol.push_back( ratio_index( vol_ratio, i ) ); + rVol.emplace_back( vol_ratio, i ); } } diff --git a/src/npctalk.cpp b/src/npctalk.cpp index f3f4147976906..4f9830e3b91be 100644 --- a/src/npctalk.cpp +++ b/src/npctalk.cpp @@ -1343,7 +1343,7 @@ void parse_tags( std::string &phrase, const Character &u, const Character &me, void dialogue::add_topic( const std::string &topic_id ) { - topic_stack.push_back( talk_topic( topic_id ) ); + topic_stack.emplace_back( topic_id ); } void dialogue::add_topic( const talk_topic &topic ) @@ -1767,7 +1767,7 @@ void talk_effect_fun_t::set_u_buy_item( const itype_id &item_name, int cost, int // Update structure used by mission descriptions. if( cost <= 0 ) { - likely_rewards.push_back( std::pair( count, item_name ) ); + likely_rewards.emplace_back( count, item_name ); } } diff --git a/src/output.cpp b/src/output.cpp index e8c22e2f1ee70..4d9f402a0d509 100644 --- a/src/output.cpp +++ b/src/output.cpp @@ -2116,7 +2116,7 @@ void scrollingcombattext::add( const point &pos, direction p_oDir, iter->advanceStepOffset(); } } - vSCT.push_back( cSCT( pos, p_oDir, p_sText, p_gmt, p_sText2, p_gmt2, p_sType ) ); + vSCT.emplace_back( pos, p_oDir, p_sText, p_gmt, p_sText2, p_gmt2, p_sType ); } } @@ -2354,7 +2354,7 @@ std::vector string_split( const std::string &text_in, char delim_in } if( text_in.back() == delim_in ) { - elems.push_back( "" ); + elems.emplace_back( "" ); } return elems; diff --git a/src/overmap.cpp b/src/overmap.cpp index c32f2effbaa74..5931f6a842eef 100644 --- a/src/overmap.cpp +++ b/src/overmap.cpp @@ -1545,35 +1545,35 @@ bool overmap::generate_sub( const int z ) sewer_points.emplace_back( i, j ); } else if( oter_above == "anthill" || oter_above == "acid_anthill" ) { const int size = rng( MIN_ANT_SIZE, MAX_ANT_SIZE ); - ant_points.push_back( city( p.xy(), size ) ); + ant_points.emplace_back( p.xy(), size ); } else if( oter_above == "slimepit_down" ) { const int size = rng( MIN_GOO_SIZE, MAX_GOO_SIZE ); - goo_points.push_back( city( p.xy(), size ) ); + goo_points.emplace_back( p.xy(), size ); } else if( oter_above == "forest_water" ) { ter_set( p, oter_id( "cavern" ) ); chip_rock( p ); } else if( oter_above == "lab_core" || ( z == -1 && oter_above == "lab_stairs" ) ) { - lab_points.push_back( city( p.xy(), rng( 1, 5 + z ) ) ); + lab_points.emplace_back( p.xy(), rng( 1, 5 + z ) ); } else if( oter_above == "lab_stairs" ) { ter_set( p, oter_id( "lab" ) ); } else if( oter_above == "ice_lab_core" || ( z == -1 && oter_above == "ice_lab_stairs" ) ) { - ice_lab_points.push_back( city( p.xy(), rng( 1, 5 + z ) ) ); + ice_lab_points.emplace_back( p.xy(), rng( 1, 5 + z ) ); } else if( oter_above == "ice_lab_stairs" ) { ter_set( p, oter_id( "ice_lab" ) ); } else if( oter_above == "central_lab_core" ) { - central_lab_points.push_back( city( p.xy(), rng( std::max( 1, 7 + z ), 9 + z ) ) ); + central_lab_points.emplace_back( p.xy(), rng( std::max( 1, 7 + z ), 9 + z ) ); } else if( oter_above == "central_lab_stairs" ) { ter_set( p, oter_id( "central_lab" ) ); } else if( is_ot_match( "hidden_lab_stairs", oter_above, ot_match_type::contains ) ) { - lab_points.push_back( city( p.xy(), rng( 1, 5 + z ) ) ); + lab_points.emplace_back( p.xy(), rng( 1, 5 + z ) ); } else if( is_ot_match( "mine_entrance", oter_ground, ot_match_type::prefix ) && z == -2 ) { - mine_points.push_back( city( ( p + tripoint_west ).xy(), rng( 6 + z, 10 + z ) ) ); + mine_points.emplace_back( ( p + tripoint_west ).xy(), rng( 6 + z, 10 + z ) ); requires_sub = true; } else if( oter_above == "mine_down" ) { ter_set( p, oter_id( "mine" ) ); - mine_points.push_back( city( p.xy(), rng( 6 + z, 10 + z ) ) ); + mine_points.emplace_back( p.xy(), rng( 6 + z, 10 + z ) ); // technically not all finales need a sub level, // but at this point we don't know requires_sub = true; @@ -2604,10 +2604,10 @@ void overmap::place_rivers( const overmap *north, const overmap *east, const ove while( river_start.empty() || river_start.size() + 1 < river_end.size() ) { new_rivers.clear(); if( north == nullptr && one_in( river_chance ) ) { - new_rivers.push_back( point_om_omt( rng( 10, OMAPX - 11 ), 0 ) ); + new_rivers.emplace_back( rng( 10, OMAPX - 11 ), 0 ); } if( west == nullptr && one_in( river_chance ) ) { - new_rivers.push_back( point_om_omt( 0, rng( 10, OMAPY - 11 ) ) ); + new_rivers.emplace_back( 0, rng( 10, OMAPY - 11 ) ); } river_start.push_back( random_entry( new_rivers ) ); } @@ -2616,10 +2616,10 @@ void overmap::place_rivers( const overmap *north, const overmap *east, const ove while( river_end.empty() || river_end.size() + 1 < river_start.size() ) { new_rivers.clear(); if( south == nullptr && one_in( river_chance ) ) { - new_rivers.push_back( point_om_omt( rng( 10, OMAPX - 11 ), OMAPY - 1 ) ); + new_rivers.emplace_back( rng( 10, OMAPX - 11 ), OMAPY - 1 ); } if( east == nullptr && one_in( river_chance ) ) { - new_rivers.push_back( point_om_omt( OMAPX - 1, rng( 10, OMAPY - 11 ) ) ); + new_rivers.emplace_back( OMAPX - 1, rng( 10, OMAPY - 11 ) ); } river_end.push_back( random_entry( new_rivers ) ); } @@ -2650,8 +2650,8 @@ void overmap::place_rivers( const overmap *north, const overmap *east, const ove } } else if( !river_end.empty() ) { if( river_start.size() != river_end.size() ) { - river_start.push_back( point_om_omt( rng( OMAPX / 4, ( OMAPX * 3 ) / 4 ), - rng( OMAPY / 4, ( OMAPY * 3 ) / 4 ) ) ); + river_start.emplace_back( rng( OMAPX / 4, ( OMAPX * 3 ) / 4 ), + rng( OMAPY / 4, ( OMAPY * 3 ) / 4 ) ); } for( size_t i = 0; i < river_start.size(); i++ ) { place_river( river_start[i], river_end[i] ); @@ -4421,21 +4421,21 @@ void overmap::place_radios() // Since location have id such as "radio_tower_1_north", we must check the beginning of the id if( is_ot_match( "radio_tower", ter( pos_omt ), ot_match_type::prefix ) ) { if( one_in( 3 ) ) { - radios.push_back( radio_tower( pos_sm, strength(), "", radio_type::WEATHER_RADIO ) ); + radios.emplace_back( pos_sm, strength(), "", radio_type::WEATHER_RADIO ); } else { message = SNIPPET.expand( SNIPPET.random_from_category( "radio_archive" ).value_or( translation() ).translated() ); - radios.push_back( radio_tower( pos_sm, strength(), message ) ); + radios.emplace_back( pos_sm, strength(), message ); } } else if( is_ot_match( "lmoe", ter( pos_omt ), ot_match_type::prefix ) ) { message = string_format( _( "This is automated emergency shelter beacon %d%d." " Supplies, amenities and shelter are stocked." ), i, j ); - radios.push_back( radio_tower( pos_sm, strength() / 2, message ) ); + radios.emplace_back( pos_sm, strength() / 2, message ); } else if( is_ot_match( "fema_entrance", ter( pos_omt ), ot_match_type::prefix ) ) { message = string_format( _( "This is FEMA camp %d%d." " Supplies are limited, please bring supplemental food, water, and bedding." " This is FEMA camp %d%d. A designated long-term emergency shelter." ), i, j, i, j ); - radios.push_back( radio_tower( pos_sm, strength(), message ) ); + radios.emplace_back( pos_sm, strength(), message ); } } } diff --git a/src/overmap_ui.cpp b/src/overmap_ui.cpp index 7f294b6c5102d..7af7a90245283 100644 --- a/src/overmap_ui.cpp +++ b/src/overmap_ui.cpp @@ -654,7 +654,7 @@ void draw( npc *npc_to_add = elem.get(); if( npc_to_add->mission == NPC_MISSION_TRAVELLING && !npc_to_add->omt_path.empty() ) { for( auto &elem : npc_to_add->omt_path ) { - path_route.push_back( tripoint_abs_omt( elem.xy(), npc_to_add->posz() ) ); + path_route.emplace_back( elem.xy(), npc_to_add->posz() ); } } } diff --git a/src/panels.cpp b/src/panels.cpp index 9132293f7551d..4425efc018454 100644 --- a/src/panels.cpp +++ b/src/panels.cpp @@ -1112,20 +1112,20 @@ static void draw_stealth( avatar &u, const catacurses::window &w ) static void draw_time_graphic( const catacurses::window &w ) { std::vector > vGlyphs; - vGlyphs.push_back( std::make_pair( '_', c_red ) ); - vGlyphs.push_back( std::make_pair( '_', c_cyan ) ); - vGlyphs.push_back( std::make_pair( '.', c_brown ) ); - vGlyphs.push_back( std::make_pair( ',', c_blue ) ); - vGlyphs.push_back( std::make_pair( '+', c_yellow ) ); - vGlyphs.push_back( std::make_pair( 'c', c_light_blue ) ); - vGlyphs.push_back( std::make_pair( '*', c_yellow ) ); - vGlyphs.push_back( std::make_pair( 'C', c_white ) ); - vGlyphs.push_back( std::make_pair( '+', c_yellow ) ); - vGlyphs.push_back( std::make_pair( 'c', c_light_blue ) ); - vGlyphs.push_back( std::make_pair( '.', c_brown ) ); - vGlyphs.push_back( std::make_pair( ',', c_blue ) ); - vGlyphs.push_back( std::make_pair( '_', c_red ) ); - vGlyphs.push_back( std::make_pair( '_', c_cyan ) ); + vGlyphs.emplace_back( '_', c_red ); + vGlyphs.emplace_back( '_', c_cyan ); + vGlyphs.emplace_back( '.', c_brown ); + vGlyphs.emplace_back( ',', c_blue ); + vGlyphs.emplace_back( '+', c_yellow ); + vGlyphs.emplace_back( 'c', c_light_blue ); + vGlyphs.emplace_back( '*', c_yellow ); + vGlyphs.emplace_back( 'C', c_white ); + vGlyphs.emplace_back( '+', c_yellow ); + vGlyphs.emplace_back( 'c', c_light_blue ); + vGlyphs.emplace_back( '.', c_brown ); + vGlyphs.emplace_back( ',', c_blue ); + vGlyphs.emplace_back( '_', c_red ); + vGlyphs.emplace_back( '_', c_cyan ); const int iHour = hour_of_day( calendar::turn ); wprintz( w, c_white, "[" ); diff --git a/src/past_games_info.cpp b/src/past_games_info.cpp index d34c2bd08a09a..fa35621131500 100644 --- a/src/past_games_info.cpp +++ b/src/past_games_info.cpp @@ -116,7 +116,7 @@ void past_games_info::ensure_loaded() std::istringstream iss( read_entire_file( filename ) ); try { JsonIn jsin( iss ); - info_.push_back( past_game_info( jsin ) ); + info_.emplace_back( jsin ); } catch( const JsonError &err ) { debugmsg( "Error reading memorial file %s: %s", filename, err.what() ); } catch( const too_old_memorial_file_error & ) { diff --git a/src/pixel_minimap.cpp b/src/pixel_minimap.cpp index 1bd963238bff2..e9acb49a43de2 100644 --- a/src/pixel_minimap.cpp +++ b/src/pixel_minimap.cpp @@ -334,7 +334,7 @@ void pixel_minimap::update_cache_at( const tripoint &sm_pos ) if( current_color != color ) { current_color = color; - cache_item.update_list.push_back( { x, y } ); + cache_item.update_list.emplace_back( x, y ); } } } diff --git a/src/player.cpp b/src/player.cpp index 05c29b7d376ed..5b5e9ac6dcdfd 100644 --- a/src/player.cpp +++ b/src/player.cpp @@ -2237,8 +2237,8 @@ void player::gunmod_add( item &gun, item &mod ) const int moves = !has_trait( trait_DEBUG_HS ) ? mod.type->gunmod->install_time : 0; assign_activity( activity_id( "ACT_GUNMOD_ADD" ), moves, -1, 0, tool ); - activity.targets.push_back( item_location( *this, &gun ) ); - activity.targets.push_back( item_location( *this, &mod ) ); + activity.targets.emplace_back( *this, &gun ); + activity.targets.emplace_back( *this, &mod ); activity.values.push_back( 0 ); // dummy value activity.values.push_back( roll ); // chance of success (%) activity.values.push_back( risk ); // chance of damage (%) diff --git a/src/player_activity.cpp b/src/player_activity.cpp index f0417d4e5250f..e7e4a877c8b76 100644 --- a/src/player_activity.cpp +++ b/src/player_activity.cpp @@ -64,11 +64,11 @@ void player_activity::migrate_item_position( Character &guy ) type == ACT_ATM; if( simple_action_replace ) { - targets.push_back( item_location( guy, &guy.i_at( position ) ) ); + targets.emplace_back( guy, &guy.i_at( position ) ); } else if( type == ACT_GUNMOD_ADD ) { // this activity has two indices; "position" = gun and "values[0]" = mod - targets.push_back( item_location( guy, &guy.i_at( position ) ) ); - targets.push_back( item_location( guy, &guy.i_at( values[0] ) ) ); + targets.emplace_back( guy, &guy.i_at( position ) ); + targets.emplace_back( guy, &guy.i_at( values[0] ) ); } } diff --git a/src/player_display.cpp b/src/player_display.cpp index 835f085759dd7..cc403e8e0c21b 100644 --- a/src/player_display.cpp +++ b/src/player_display.cpp @@ -1192,7 +1192,7 @@ void player::disp_info() if( tmp.empty() ) { continue; } - effect_name_and_text.push_back( { tmp, _effect_it.second.disp_desc() } ); + effect_name_and_text.emplace_back( tmp, _effect_it.second.disp_desc() ); } } if( get_perceived_pain() > 0 ) { @@ -1208,7 +1208,7 @@ void player::disp_info() add_if( ppen.intelligence, _( "Intelligence -%d" ) ); add_if( ppen.perception, _( "Perception -%d" ) ); add_if( ppen.speed, _( "Speed -%d %%" ) ); - effect_name_and_text.push_back( { _( "Pain" ), pain_text } ); + effect_name_and_text.emplace_back( _( "Pain" ), pain_text ); } const float bmi = get_bmi(); @@ -1237,30 +1237,30 @@ void player::disp_info() str_penalty * 50.0f ); } - effect_name_and_text.push_back( { starvation_name, starvation_text } ); + effect_name_and_text.emplace_back( starvation_name, starvation_text ); } if( has_trait( trait_id( "TROGLO" ) ) && g->is_in_sunlight( pos() ) && get_weather().weather_id->sun_intensity >= sun_intensity_type::high ) { - effect_name_and_text.push_back( { _( "In Sunlight" ), - _( "The sunlight irritates you.\n" - "Strength - 1; Dexterity - 1; Intelligence - 1; Perception - 1" ) - } ); + effect_name_and_text.emplace_back( _( "In Sunlight" ), + _( "The sunlight irritates you.\n" + "Strength - 1; Dexterity - 1; Intelligence - 1; Perception - 1" ) + ); } else if( has_trait( trait_id( "TROGLO2" ) ) && g->is_in_sunlight( pos() ) ) { - effect_name_and_text.push_back( { _( "In Sunlight" ), - _( "The sunlight irritates you badly.\n" - "Strength - 2; Dexterity - 2; Intelligence - 2; Perception - 2" ) - } ); + effect_name_and_text.emplace_back( _( "In Sunlight" ), + _( "The sunlight irritates you badly.\n" + "Strength - 2; Dexterity - 2; Intelligence - 2; Perception - 2" ) + ); } else if( has_trait( trait_id( "TROGLO3" ) ) && g->is_in_sunlight( pos() ) ) { - effect_name_and_text.push_back( { _( "In Sunlight" ), - _( "The sunlight irritates you terribly.\n" - "Strength - 4; Dexterity - 4; Intelligence - 4; Perception - 4" ) - } ); + effect_name_and_text.emplace_back( _( "In Sunlight" ), + _( "The sunlight irritates you terribly.\n" + "Strength - 4; Dexterity - 4; Intelligence - 4; Perception - 4" ) + ); } for( auto &elem : addictions ) { if( elem.sated < 0_turns && elem.intensity >= MIN_ADDICTION_LEVEL ) { - effect_name_and_text.push_back( { addiction_name( elem ), addiction_text( elem ) } ); + effect_name_and_text.emplace_back( addiction_name( elem ), addiction_text( elem ) ); } } diff --git a/src/profession.cpp b/src/profession.cpp index 7349369fa0551..92f84f13f2139 100644 --- a/src/profession.cpp +++ b/src/profession.cpp @@ -608,7 +608,7 @@ void json_item_substitution::load( const JsonObject &jo ) if( check_duplicate_item( old_it ) ) { sub.throw_error( "Duplicate definition of item" ); } - s.trait_reqs.present.push_back( trait_id( jo.get_string( "trait" ) ) ); + s.trait_reqs.present.emplace_back( jo.get_string( "trait" ) ); for( const JsonValue info : sub.get_array( "new" ) ) { s.infos.emplace_back( info ); } diff --git a/src/proficiency.cpp b/src/proficiency.cpp index 593d244ad9588..9da433d251633 100644 --- a/src/proficiency.cpp +++ b/src/proficiency.cpp @@ -120,11 +120,11 @@ std::vector proficiency_set::display() const std::vector> sorted_learning; for( const proficiency_id &cur : known ) { - sorted_known.push_back( { cur->name(), cur } ); + sorted_known.emplace_back( cur->name(), cur ); } for( const learning_proficiency &cur : learning ) { - sorted_learning.push_back( { cur.id->name(), cur.id } ); + sorted_learning.emplace_back( cur.id->name(), cur.id ); } std::sort( sorted_known.begin(), sorted_known.end(), localized_compare ); @@ -170,7 +170,7 @@ bool proficiency_set::practice( const proficiency_id &practicing, const time_dur return false; } if( !has_practiced( practicing ) ) { - learning.push_back( learning_proficiency( practicing, 0_seconds ) ); + learning.emplace_back( practicing, 0_seconds ); } learning_proficiency ¤t = fetch_learning( practicing ); diff --git a/src/ranged.cpp b/src/ranged.cpp index a3d9eaae8a7ba..7966a97f9e30f 100644 --- a/src/ranged.cpp +++ b/src/ranged.cpp @@ -2670,7 +2670,7 @@ std::vector> target_ui::list_friendlies_in_lof() ( cr->is_npc() && a != Creature::Attitude::HOSTILE ) || ( !cr->is_npc() && a == Creature::Attitude::FRIENDLY ) ) { - ret.push_back( g->shared_from( *cr ) ); + ret.emplace_back( g->shared_from( *cr ) ); } } } diff --git a/src/recipe.cpp b/src/recipe.cpp index 43ca504e20504..2679182ce9ae9 100644 --- a/src/recipe.cpp +++ b/src/recipe.cpp @@ -814,7 +814,7 @@ std::string recipe::primary_skill_string( const Character *c, bool print_skill_l std::vector< std::pair > skillList; if( !skill_used.is_null() ) { - skillList.push_back( std::pair( skill_used, difficulty ) ); + skillList.emplace_back( skill_used, difficulty ); } return required_skills_as_string( skillList.begin(), skillList.end(), c, print_skill_level ); diff --git a/src/safemode_ui.cpp b/src/safemode_ui.cpp index 24b9b5620b22d..1b51dc0b2f6fc 100644 --- a/src/safemode_ui.cpp +++ b/src/safemode_ui.cpp @@ -303,16 +303,16 @@ void safemode::show( const std::string &custom_name_in, bool is_safemode_in ) } } else if( action == "ADD_DEFAULT_RULESET" ) { changes_made = true; - current_tab.push_back( rules_class( "*", true, false, Creature::Attitude::HOSTILE, - get_option( "SAFEMODEPROXIMITY" ) - , Categories::HOSTILE_SPOTTED ) ); - current_tab.push_back( rules_class( "*", true, true, Creature::Attitude::HOSTILE, 5, - Categories::SOUND ) ); + current_tab.emplace_back( "*", true, false, Creature::Attitude::HOSTILE, + get_option( "SAFEMODEPROXIMITY" ) + , Categories::HOSTILE_SPOTTED ); + current_tab.emplace_back( "*", true, true, Creature::Attitude::HOSTILE, 5, + Categories::SOUND ); line = current_tab.size() - 1; } else if( action == "ADD_RULE" ) { changes_made = true; - current_tab.push_back( rules_class( "", true, false, Creature::Attitude::HOSTILE, - get_option( "SAFEMODEPROXIMITY" ), Categories::HOSTILE_SPOTTED ) ); + current_tab.emplace_back( "", true, false, Creature::Attitude::HOSTILE, + get_option( "SAFEMODEPROXIMITY" ), Categories::HOSTILE_SPOTTED ); line = current_tab.size() - 1; } else if( action == "REMOVE_RULE" && !current_tab.empty() ) { changes_made = true; @@ -640,8 +640,8 @@ void safemode::add_rule( const std::string &rule_in, const Creature::Attitude at const int proximity_in, const rule_state state_in ) { - character_rules.push_back( rules_class( rule_in, true, ( state_in == rule_state::WHITELISTED ), - attitude_in, proximity_in, Categories::HOSTILE_SPOTTED ) ); + character_rules.emplace_back( rule_in, true, ( state_in == rule_state::WHITELISTED ), + attitude_in, proximity_in, Categories::HOSTILE_SPOTTED ); create_rules(); if( !get_option( "SAFEMODE" ) && @@ -891,8 +891,7 @@ void safemode::deserialize( JsonIn &jsin ) const Categories cat = jo.has_member( "category" ) ? static_cast ( jo.get_int( "category" ) ) : Categories::HOSTILE_SPOTTED; - temp_rules.push_back( - rules_class( rule, active, whitelist, attitude, proximity, cat ) - ); + temp_rules.emplace_back( rule, active, whitelist, attitude, proximity, cat + ); } } diff --git a/src/talker_avatar.cpp b/src/talker_avatar.cpp index e43ca0e9c7e3c..75d303e70627f 100644 --- a/src/talker_avatar.cpp +++ b/src/talker_avatar.cpp @@ -31,7 +31,7 @@ std::vector talker_avatar::get_topics( bool ) std::vector add_topics; if( has_trait( trait_PROF_FOODP ) && !( is_wearing( itype_id( "foodperson_mask" ) ) || is_wearing( itype_id( "foodperson_mask_on" ) ) ) ) { - add_topics.push_back( "TALK_NOFACE" ); + add_topics.emplace_back( "TALK_NOFACE" ); } return add_topics; } diff --git a/src/talker_npc.cpp b/src/talker_npc.cpp index 0e065a909b4c2..ac51ee3df2fcd 100644 --- a/src/talker_npc.cpp +++ b/src/talker_npc.cpp @@ -108,19 +108,19 @@ std::vector talker_npc::get_topics( bool radio_contact ) add_topics.push_back( me_npc->chatbin.first_topic ); if( radio_contact ) { - add_topics.push_back( "TALK_RADIO" ); + add_topics.emplace_back( "TALK_RADIO" ); } else if( me_npc->is_leader() ) { - add_topics.push_back( "TALK_LEADER" ); + add_topics.emplace_back( "TALK_LEADER" ); } else if( me_npc->is_player_ally() && ( me_npc->is_walking_with() || me_npc->has_activity() ) ) { - add_topics.push_back( "TALK_FRIEND" ); + add_topics.emplace_back( "TALK_FRIEND" ); } else if( me_npc->get_attitude() == NPCATT_RECOVER_GOODS ) { - add_topics.push_back( "TALK_STOLE_ITEM" ); + add_topics.emplace_back( "TALK_STOLE_ITEM" ); } int most_difficult_mission = 0; for( auto &mission : me_npc->chatbin.missions ) { const auto &type = mission->get_type(); if( type.urgent && type.difficulty > most_difficult_mission ) { - add_topics.push_back( "TALK_MISSION_DESCRIBE_URGENT" ); + add_topics.emplace_back( "TALK_MISSION_DESCRIBE_URGENT" ); me_npc->chatbin.mission_selected = mission; most_difficult_mission = type.difficulty; } @@ -136,7 +136,7 @@ std::vector talker_npc::get_topics( bool radio_contact ) if( ( type.urgent && !chosen_urgent ) || ( type.difficulty > most_difficult_mission && ( type.urgent || !chosen_urgent ) ) ) { chosen_urgent = type.urgent; - add_topics.push_back( "TALK_MISSION_INQUIRE" ); + add_topics.emplace_back( "TALK_MISSION_INQUIRE" ); me_npc->chatbin.mission_selected = mission; most_difficult_mission = type.difficulty; } @@ -144,13 +144,13 @@ std::vector talker_npc::get_topics( bool radio_contact ) // Needs if( me_npc->has_effect( effect_npc_suspend ) ) { - add_topics.push_back( "TALK_REBOOT" ); + add_topics.emplace_back( "TALK_REBOOT" ); } if( me_npc->has_effect( effect_sleep ) || me_npc->has_effect( effect_lying_down ) ) { if( me_npc->has_effect( effect_narcosis ) ) { - add_topics.push_back( "TALK_SEDATED" ); + add_topics.emplace_back( "TALK_SEDATED" ); } else { - add_topics.push_back( "TALK_WAKE_UP" ); + add_topics.emplace_back( "TALK_WAKE_UP" ); } } @@ -163,25 +163,25 @@ std::vector talker_npc::get_topics( bool radio_contact ) if( add_topics.back() == "TALK_MUG" || add_topics.back() == "TALK_STRANGER_AGGRESSIVE" ) { me_npc->make_angry(); - add_topics.push_back( "TALK_DEAF_ANGRY" ); + add_topics.emplace_back( "TALK_DEAF_ANGRY" ); } else { - add_topics.push_back( "TALK_DEAF" ); + add_topics.emplace_back( "TALK_DEAF" ); } } if( player_character.is_mute() ) { if( add_topics.back() == "TALK_MUG" || add_topics.back() == "TALK_STRANGER_AGGRESSIVE" ) { me_npc->make_angry(); - add_topics.push_back( "TALK_MUTE_ANGRY" ); + add_topics.emplace_back( "TALK_MUTE_ANGRY" ); } else { - add_topics.push_back( "TALK_MUTE" ); + add_topics.emplace_back( "TALK_MUTE" ); } } if( me_npc->has_trait( trait_PROF_FOODP ) && !( me_npc->is_wearing( itype_id( "foodperson_mask_on" ) ) || me_npc->is_wearing( itype_id( "foodperson_mask" ) ) ) ) { - add_topics.push_back( "TALK_NPC_NOFACE" ); + add_topics.emplace_back( "TALK_NPC_NOFACE" ); } me_npc->decide_needs(); diff --git a/src/translations.cpp b/src/translations.cpp index 65778e5fc5ac4..fcdf23799d57c 100644 --- a/src/translations.cpp +++ b/src/translations.cpp @@ -430,7 +430,7 @@ std::string gettext_gendered( const GenderMap &genders, const std::string &msg ) sanity_check_genders( language_genders ); if( language_genders.empty() ) { - language_genders.push_back( "n" ); + language_genders.emplace_back( "n" ); } std::vector chosen_genders; diff --git a/src/veh_interact.cpp b/src/veh_interact.cpp index 75fd7eb984529..63dfd31bcdc20 100644 --- a/src/veh_interact.cpp +++ b/src/veh_interact.cpp @@ -912,15 +912,15 @@ void veh_interact::do_install() for( const vpart_category &cat : vpart_category::all() ) { tab_list.push_back( cat ); if( cat.get_id() == "_all" ) { - tab_filters.push_back( []( const vpart_info * ) { + tab_filters.emplace_back( []( const vpart_info * ) { return true; } ); } else if( cat.get_id() == "_filter" ) { - tab_filters.push_back( [&filter]( const vpart_info * p ) { + tab_filters.emplace_back( [&filter]( const vpart_info * p ) { return lcmatch( p->name(), filter ); } ); } else { - tab_filters.push_back( [ &, cat = cat.get_id()]( const vpart_info * p ) { + tab_filters.emplace_back( [ &, cat = cat.get_id()]( const vpart_info * p ) { return p->has_category( cat ); } ); } diff --git a/src/veh_type.cpp b/src/veh_type.cpp index 8b4bbb98565ae..4f6fef9421c9b 100644 --- a/src/veh_type.cpp +++ b/src/veh_type.cpp @@ -267,7 +267,7 @@ void vpart_info::load_engine( cata::optional &eptr, const JsonObj if( !fuel_opts.empty() ) { e_info.fuel_opts.clear(); for( const std::string line : fuel_opts ) { - e_info.fuel_opts.push_back( itype_id( line ) ); + e_info.fuel_opts.emplace_back( line ); } } else if( e_info.fuel_opts.empty() && fuel_type != itype_id( "null" ) ) { e_info.fuel_opts.push_back( fuel_type ); @@ -1168,17 +1168,16 @@ void vehicle_prototype::load( const JsonObject &jo ) const std::string variant = spawn_info.get_string( "variant" ); next_spawn.variant_ids.emplace_back( itype_id( spawn_info.get_string( "items" ) ), variant ); } else { - next_spawn.item_ids.push_back( itype_id( spawn_info.get_string( "items" ) ) ); + next_spawn.item_ids.emplace_back( spawn_info.get_string( "items" ) ); } } if( spawn_info.has_array( "item_groups" ) ) { //Pick from a group of items, just like map::place_items for( const std::string line : spawn_info.get_array( "item_groups" ) ) { - next_spawn.item_groups.push_back( item_group_id( line ) ); + next_spawn.item_groups.emplace_back( line ); } } else if( spawn_info.has_string( "item_groups" ) ) { - next_spawn.item_groups.push_back( - item_group_id( spawn_info.get_string( "item_groups" ) ) ); + next_spawn.item_groups.emplace_back( spawn_info.get_string( "item_groups" ) ); } vproto.item_spawns.push_back( std::move( next_spawn ) ); } diff --git a/src/vehicle_use.cpp b/src/vehicle_use.cpp index ad7a282830213..9dbe7ce27cfeb 100644 --- a/src/vehicle_use.cpp +++ b/src/vehicle_use.cpp @@ -136,7 +136,7 @@ void vehicle::add_toggle_to_opts( std::vector &options, name ); options.emplace_back( -1, allow, key, msg ); - actions.push_back( [ = ] { + actions.emplace_back( [ = ] { for( const vpart_reference &vp : found ) { vehicle_part &e = vp.part(); @@ -324,14 +324,14 @@ void vehicle::set_electronics_menu_options( std::vector &options, if( has_part( "DOOR_MOTOR" ) ) { options.emplace_back( _( "Toggle doors" ), keybind( "TOGGLE_DOORS" ) ); - actions.push_back( [&] { control_doors(); refresh(); } ); + actions.emplace_back( [&] { control_doors(); refresh(); } ); } if( camera_on || ( has_part( "CAMERA" ) && has_part( "CAMERA_CONTROL" ) ) ) { options.emplace_back( camera_on ? colorize( _( "Turn off camera system" ), c_pink ) : _( "Turn on camera system" ), keybind( "TOGGLE_CAMERA" ) ); - actions.push_back( [&] { + actions.emplace_back( [&] { if( camera_on ) { camera_on = false; @@ -626,7 +626,7 @@ void vehicle::use_controls( const tripoint &pos ) if( remote ) { options.emplace_back( _( "Stop controlling" ), keybind( "RELEASE_CONTROLS" ) ); - actions.push_back( [&] { + actions.emplace_back( [&] { player_character.controlling_vehicle = false; g->setremoteveh( nullptr ); add_msg( _( "You stop controlling the vehicle." ) ); @@ -638,7 +638,7 @@ void vehicle::use_controls( const tripoint &pos ) } else if( veh_pointer_or_null( get_map().veh_at( pos ) ) == this ) { if( player_character.controlling_vehicle ) { options.emplace_back( _( "Let go of controls" ), keybind( "RELEASE_CONTROLS" ) ); - actions.push_back( [&] { + actions.emplace_back( [&] { player_character.controlling_vehicle = false; add_msg( _( "You let go of the controls." ) ); refresh(); @@ -661,7 +661,7 @@ void vehicle::use_controls( const tripoint &pos ) if( has_part( "ENGINE" ) ) { if( player_character.controlling_vehicle || ( remote && engine_on ) ) { options.emplace_back( _( "Stop driving" ), keybind( "TOGGLE_ENGINE" ) ); - actions.push_back( [&] { + actions.emplace_back( [&] { if( engine_on && has_engine_type_not( fuel_type_muscle, true ) ) { add_msg( _( "You turn the engine off and let go of the controls." ) ); @@ -704,7 +704,7 @@ void vehicle::use_controls( const tripoint &pos ) } else if( has_engine_type_not( fuel_type_muscle, true ) ) { options.emplace_back( engine_on ? _( "Turn off the engine" ) : _( "Turn on the engine" ), keybind( "TOGGLE_ENGINE" ) ); - actions.push_back( [&] { + actions.emplace_back( [&] { if( engine_on ) { engine_on = false; @@ -722,13 +722,13 @@ void vehicle::use_controls( const tripoint &pos ) if( has_part( "HORN" ) ) { options.emplace_back( _( "Honk horn" ), keybind( "SOUND_HORN" ) ); - actions.push_back( [&] { honk_horn(); refresh(); } ); + actions.emplace_back( [&] { honk_horn(); refresh(); } ); } if( has_part( "AUTOPILOT" ) && ( has_part( "CTRL_ELECTRONIC" ) || has_part( "REMOTE_CONTROLS" ) ) ) { options.emplace_back( _( "Control autopilot" ), keybind( "CONTROL_AUTOPILOT" ) ); - actions.push_back( [&] { toggle_autopilot(); refresh(); } ); + actions.emplace_back( [&] { toggle_autopilot(); refresh(); } ); } options.emplace_back( cruise_on ? _( "Disable cruise control" ) : _( "Enable cruise control" ), @@ -742,28 +742,28 @@ void vehicle::use_controls( const tripoint &pos ) if( has_electronic_controls ) { set_electronics_menu_options( options, actions ); options.emplace_back( _( "Control multiple electronics" ), keybind( "CONTROL_MANY_ELECTRONICS" ) ); - actions.push_back( [&] { control_electronics(); refresh(); } ); + actions.emplace_back( [&] { control_electronics(); refresh(); } ); } options.emplace_back( tracking_on ? _( "Forget vehicle position" ) : _( "Remember vehicle position" ), keybind( "TOGGLE_TRACKING" ) ); - actions.push_back( [&] { toggle_tracking(); } ); + actions.emplace_back( [&] { toggle_tracking(); } ); if( ( is_foldable() || tags.count( "convertible" ) ) && !remote ) { options.emplace_back( string_format( _( "Fold %s" ), name ), keybind( "FOLD_VEHICLE" ) ); - actions.push_back( [&] { fold_up(); } ); + actions.emplace_back( [&] { fold_up(); } ); } if( has_part( "ENGINE" ) ) { options.emplace_back( _( "Control individual engines" ), keybind( "CONTROL_ENGINES" ) ); - actions.push_back( [&] { control_engines(); refresh(); } ); + actions.emplace_back( [&] { control_engines(); refresh(); } ); } if( has_part( "SMART_ENGINE_CONTROLLER" ) ) { options.emplace_back( _( "Smart controller settings" ), keybind( "TOGGLE_SMART_ENGINE_CONTROLLER" ) ); - actions.push_back( [&] { + actions.emplace_back( [&] { if( !smart_controller_cfg ) { smart_controller_cfg = smart_controller_config(); @@ -783,11 +783,11 @@ void vehicle::use_controls( const tripoint &pos ) if( is_alarm_on ) { if( velocity == 0 && !remote ) { options.emplace_back( _( "Try to disarm alarm" ), keybind( "TOGGLE_ALARM" ) ); - actions.push_back( [&] { smash_security_system(); refresh(); } ); + actions.emplace_back( [&] { smash_security_system(); refresh(); } ); } else if( has_electronic_controls && has_part( "SECURITY" ) ) { options.emplace_back( _( "Trigger alarm" ), keybind( "TOGGLE_ALARM" ) ); - actions.push_back( [&] { + actions.emplace_back( [&] { is_alarm_on = true; add_msg( _( "You trigger the alarm" ) ); refresh(); @@ -797,21 +797,21 @@ void vehicle::use_controls( const tripoint &pos ) if( has_part( "TURRET" ) ) { options.emplace_back( _( "Set turret targeting modes" ), keybind( "TURRET_TARGET_MODE" ) ); - actions.push_back( [&] { turrets_set_targeting(); refresh(); } ); + actions.emplace_back( [&] { turrets_set_targeting(); refresh(); } ); options.emplace_back( _( "Set turret firing modes" ), keybind( "TURRET_FIRE_MODE" ) ); - actions.push_back( [&] { turrets_set_mode(); refresh(); } ); + actions.emplace_back( [&] { turrets_set_mode(); refresh(); } ); // We can also fire manual turrets with ACTION_FIRE while standing at the controls. options.emplace_back( _( "Aim turrets manually" ), keybind( "TURRET_MANUAL_AIM" ) ); - actions.push_back( [&] { turrets_aim_and_fire_all_manual( true ); refresh(); } ); + actions.emplace_back( [&] { turrets_aim_and_fire_all_manual( true ); refresh(); } ); // This lets us manually override and set the target for the automatic turrets instead. options.emplace_back( _( "Aim automatic turrets" ), keybind( "TURRET_MANUAL_OVERRIDE" ) ); - actions.push_back( [&] { turrets_override_automatic_aim(); refresh(); } ); + actions.emplace_back( [&] { turrets_override_automatic_aim(); refresh(); } ); options.emplace_back( _( "Aim individual turret" ), keybind( "TURRET_SINGLE_FIRE" ) ); - actions.push_back( [&] { turrets_aim_and_fire_single(); refresh(); } ); + actions.emplace_back( [&] { turrets_aim_and_fire_single(); refresh(); } ); } uilist menu; @@ -1732,7 +1732,7 @@ void vehicle::use_washing_machine( int p ) } std::vector detergent; - detergent.push_back( item_comp( det_types[chosen_detergent], 5 ) ); + detergent.emplace_back( det_types[chosen_detergent], 5 ); player_character.consume_items( detergent, 1, is_crafting_component ); add_msg( m_good, @@ -1789,7 +1789,7 @@ void vehicle::use_dishwasher( int p ) } std::vector detergent; - detergent.push_back( item_comp( itype_detergent, 5 ) ); + detergent.emplace_back( itype_detergent, 5 ); player_character.consume_items( detergent, 1, is_crafting_component ); add_msg( m_good, diff --git a/src/wish.cpp b/src/wish.cpp index cc288a1922e9a..a6be648885d9d 100644 --- a/src/wish.cpp +++ b/src/wish.cpp @@ -845,7 +845,7 @@ void debug_menu::wishproficiency( player *p ) know_all = player_know; } - sorted_profs.push_back( { cur.prof_id(), player_know } ); + sorted_profs.emplace_back( cur.prof_id(), player_know ); } std::sort( sorted_profs.begin(), sorted_profs.end(), localized_compare ); diff --git a/src/worldfactory.cpp b/src/worldfactory.cpp index 0730b6cc2a43b..66ed9ae9fb180 100644 --- a/src/worldfactory.cpp +++ b/src/worldfactory.cpp @@ -118,9 +118,9 @@ worldfactory::worldfactory() , mman_ui( *mman ) { // prepare tab display order - tabs.push_back( std::bind( &worldfactory::show_worldgen_tab_modselection, this, _1, _2, _3 ) ); - tabs.push_back( std::bind( &worldfactory::show_worldgen_tab_options, this, _1, _2, _3 ) ); - tabs.push_back( std::bind( &worldfactory::show_worldgen_tab_confirm, this, _1, _2, _3 ) ); + tabs.emplace_back( std::bind( &worldfactory::show_worldgen_tab_modselection, this, _1, _2, _3 ) ); + tabs.emplace_back( std::bind( &worldfactory::show_worldgen_tab_options, this, _1, _2, _3 ) ); + tabs.emplace_back( std::bind( &worldfactory::show_worldgen_tab_confirm, this, _1, _2, _3 ) ); } worldfactory::~worldfactory() = default; @@ -969,8 +969,8 @@ int worldfactory::show_worldgen_tab_modselection( const catacurses::window &win, ui.on_screen_resize( init_windows ); std::vector headers; - headers.push_back( _( "Mod List" ) ); - headers.push_back( _( "Mod Load Order" ) ); + headers.emplace_back( _( "Mod List" ) ); + headers.emplace_back( _( "Mod Load Order" ) ); size_t active_header = 0; int startsel[2] = {0, 0}; diff --git a/tests/behavior_test.cpp b/tests/behavior_test.cpp index b458c5ceb8385..c54ada29b7539 100644 --- a/tests/behavior_test.cpp +++ b/tests/behavior_test.cpp @@ -160,7 +160,7 @@ TEST_CASE( "check_npc_behavior_tree", "[npc][behavior]" ) test_npc.update_bodytemp(); REQUIRE( oracle.needs_warmth_badly( "" ) == behavior::status_t::running ); CHECK( npc_needs.tick( &oracle ) == "idle" ); - test_npc.worn.push_back( item( "backpack" ) ); + test_npc.worn.emplace_back( "backpack" ); item &sweater = test_npc.i_add( item( itype_id( "sweater" ) ) ); CHECK( oracle.can_wear_warmer_clothes( "" ) == behavior::status_t::running ); CHECK( npc_needs.tick( &oracle ) == "wear_warmer_clothes" ); diff --git a/tests/crafting_test.cpp b/tests/crafting_test.cpp index f89f22e74f3b7..020f6a1da5e1b 100644 --- a/tests/crafting_test.cpp +++ b/tests/crafting_test.cpp @@ -165,7 +165,7 @@ TEST_CASE( "available_recipes", "[recipes]" ) } GIVEN( "an appropriate book" ) { - dummy.worn.push_back( item( "backpack" ) ); + dummy.worn.emplace_back( "backpack" ); item &craftbook = dummy.i_add( item( "manual_electronics" ) ); REQUIRE( craftbook.is_book() ); REQUIRE_FALSE( craftbook.type->book->recipes.empty() ); @@ -209,7 +209,7 @@ TEST_CASE( "available_recipes", "[recipes]" ) GIVEN( "an eink pc with a sushi recipe" ) { const recipe *r2 = &recipe_id( "sushi_rice" ).obj(); - dummy.worn.push_back( item( "backpack" ) ); + dummy.worn.emplace_back( "backpack" ); item &eink = dummy.i_add( item( "eink_tablet_pc" ) ); eink.set_var( "EIPC_RECIPES", ",sushi_rice," ); REQUIRE_FALSE( dummy.knows_recipe( r2 ) ); @@ -399,7 +399,7 @@ TEST_CASE( "UPS shows as a crafting component", "[crafting][ups]" ) { avatar dummy; clear_character( dummy ); - dummy.worn.push_back( item( "backpack" ) ); + dummy.worn.emplace_back( "backpack" ); item &ups = dummy.i_add( item( "UPS_off", calendar::turn_zero, 500 ) ); REQUIRE( dummy.has_item( ups ) ); REQUIRE( ups.charges == 500 ); diff --git a/tests/encumbrance_test.cpp b/tests/encumbrance_test.cpp index 97d4c74d7b74e..11de147f86488 100644 --- a/tests/encumbrance_test.cpp +++ b/tests/encumbrance_test.cpp @@ -63,7 +63,7 @@ static void test_encumbrance( std::vector clothing; clothing.reserve( clothing_types.size() ); for( const std::string &type : clothing_types ) { - clothing.push_back( item( type ) ); + clothing.emplace_back( type ); } test_encumbrance_items( clothing, body_part, expected_encumbrance ); } diff --git a/tests/generic_factory_test.cpp b/tests/generic_factory_test.cpp index 321d3f2285f74..bd48552245b48 100644 --- a/tests/generic_factory_test.cpp +++ b/tests/generic_factory_test.cpp @@ -347,7 +347,7 @@ TEST_CASE( "string_and_int_ids_benchmark", "[.][generic_factory][int_id][string_ std_uo_set_int_ids.emplace( int_id ); // do not add duplicates if( std_uo_set_int_ids.size() > vector_int_ids.size() ) { - vector_int_ids.push_back( flag ); + vector_int_ids.emplace_back( flag ); } } } item; @@ -382,7 +382,7 @@ TEST_CASE( "string_and_int_ids_benchmark", "[.][generic_factory][int_id][string_ std::vector test_dyn_str_ids; test_dyn_str_ids.reserve( test_flags.size() ); for( const auto &f : test_flags ) { - test_dyn_str_ids.push_back( dyn_str_id( f.str() ) ); + test_dyn_str_ids.emplace_back( f.str() ); } DYNAMIC_SECTION( "number_ids_in_collection: " << flags_in_item << "; only_hits: " << hits ) { diff --git a/tests/invlet_test.cpp b/tests/invlet_test.cpp index 0d3b8c7c0005b..bb8aaf0db7dde 100644 --- a/tests/invlet_test.cpp +++ b/tests/invlet_test.cpp @@ -464,7 +464,7 @@ static void invlet_test( player &dummy, const inventory_location from, const inv dummy.worn.clear(); dummy.remove_weapon(); get_map().i_clear( dummy.pos() ); - dummy.worn.push_back( item( "backpack" ) ); + dummy.worn.emplace_back( "backpack" ); // some two items that can be wielded, worn, and picked up item tshirt( "tshirt" ); @@ -546,7 +546,7 @@ static void stack_invlet_test( player &dummy, inventory_location from, inventory dummy.worn.clear(); dummy.remove_weapon(); get_map().i_clear( dummy.pos() ); - dummy.worn.push_back( item( "backpack" ) ); + dummy.worn.emplace_back( "backpack" ); // some stackable item that can be wielded and worn item tshirt1( "tshirt" ); @@ -682,7 +682,7 @@ static void merge_invlet_test( player &dummy, inventory_location from ) dummy.worn.clear(); dummy.remove_weapon(); get_map().i_clear( dummy.pos() ); - dummy.worn.push_back( item( "backpack" ) ); + dummy.worn.emplace_back( "backpack" ); // some stackable item item tshirt1( "tshirt" ); diff --git a/tests/iteminfo_test.cpp b/tests/iteminfo_test.cpp index 7c3a238772d75..422b8f86e8c17 100644 --- a/tests/iteminfo_test.cpp +++ b/tests/iteminfo_test.cpp @@ -2347,7 +2347,7 @@ TEST_CASE( "show available recipes with item as an ingredient", "[iteminfo][reci std::vector crafting = { iteminfo_parts::DESCRIPTION_APPLICABLE_RECIPES }; GIVEN( "character has a potassium iodide tablet and no skill" ) { - player_character.worn.push_back( item( "backpack" ) ); + player_character.worn.emplace_back( "backpack" ); item &iodine = player_character.i_add( item( "iodine" ) ); player_character.empty_skills(); REQUIRE( !player_character.knows_recipe( purtab ) ); diff --git a/tests/modify_morale_test.cpp b/tests/modify_morale_test.cpp index a60d643e03f00..cf5c4ea204837 100644 --- a/tests/modify_morale_test.cpp +++ b/tests/modify_morale_test.cpp @@ -46,7 +46,7 @@ static const trait_id trait_VEGETARIAN( "VEGETARIAN" ); TEST_CASE( "food enjoyability", "[food][modify_morale][fun]" ) { avatar dummy; - dummy.worn.push_back( item( "backpack" ) ); + dummy.worn.emplace_back( "backpack" ); std::pair fun; GIVEN( "food with positive fun" ) { @@ -80,7 +80,7 @@ TEST_CASE( "dining with table and chair", "[food][modify_morale][table][chair]" dummy.set_body(); const tripoint avatar_pos( 60, 60, 0 ); dummy.setpos( avatar_pos ); - dummy.worn.push_back( item( "backpack" ) ); + dummy.worn.emplace_back( "backpack" ); // Morale bonus only applies to unspoiled food that is not junk item &bread = dummy.i_add( item( "sourdough_bread" ) ); @@ -194,7 +194,7 @@ TEST_CASE( "dining with table and chair", "[food][modify_morale][table][chair]" TEST_CASE( "eating hot food", "[food][modify_morale][hot]" ) { avatar dummy; - dummy.worn.push_back( item( "backpack" ) ); + dummy.worn.emplace_back( "backpack" ); GIVEN( "some food that tastes better when hot" ) { item &bread = dummy.i_add( item( "sourdough_bread" ) ); @@ -268,7 +268,7 @@ TEST_CASE( "cannibalism", "[food][modify_morale][cannibal]" ) { avatar dummy; dummy.set_body(); - dummy.worn.push_back( item( "backpack" ) ); + dummy.worn.emplace_back( "backpack" ); item &human = dummy.i_add( item( "bone_human" ) ); REQUIRE( human.has_flag( flag_CANNIBALISM ) ); @@ -344,7 +344,7 @@ TEST_CASE( "sweet junk food", "[food][modify_morale][junk][sweet]" ) { avatar dummy; dummy.set_body(); - dummy.worn.push_back( item( "backpack" ) ); + dummy.worn.emplace_back( "backpack" ); GIVEN( "some sweet junk food" ) { item &necco = dummy.i_add( item( "neccowafers" ) ); @@ -398,7 +398,7 @@ TEST_CASE( "junk food that is not ingested", "[modify_morale][junk][no_ingest]" { avatar dummy; dummy.set_body(); - dummy.worn.push_back( item( "backpack" ) ); + dummy.worn.emplace_back( "backpack" ); item &caff_gum = dummy.i_add( item( "caff_gum" ) ); @@ -464,7 +464,7 @@ TEST_CASE( "food allergies and intolerances", "[food][modify_morale][allergy]" ) { avatar dummy; dummy.set_body(); - dummy.worn.push_back( item( "backpack" ) ); + dummy.worn.emplace_back( "backpack" ); int penalty = -75; GIVEN( "character is vegetarian" ) { @@ -551,7 +551,7 @@ TEST_CASE( "saprophage character", "[food][modify_morale][saprophage]" ) { avatar dummy; dummy.set_body(); - dummy.worn.push_back( item( "backpack" ) ); + dummy.worn.emplace_back( "backpack" ); GIVEN( "character is a saprophage, preferring rotted food" ) { dummy.clear_morale(); @@ -588,7 +588,7 @@ TEST_CASE( "ursine honey", "[food][modify_morale][ursine][honey]" ) { avatar dummy; dummy.set_body(); - dummy.worn.push_back( item( "backpack" ) ); + dummy.worn.emplace_back( "backpack" ); item &honeycomb = dummy.i_add( item( "honeycomb" ) ); REQUIRE( honeycomb.has_flag( flag_URSINE_HONEY ) ); diff --git a/tests/npc_talk_test.cpp b/tests/npc_talk_test.cpp index 5a5a9ef7d5d34..1b5f9937793ba 100644 --- a/tests/npc_talk_test.cpp +++ b/tests/npc_talk_test.cpp @@ -616,7 +616,7 @@ TEST_CASE( "npc_talk_items", "[npc_talk]" ) }; player_character.cash = 1000; player_character.int_cur = 8; - player_character.worn.push_back( item( "backpack" ) ); + player_character.worn.emplace_back( "backpack" ); d.add_topic( "TALK_TEST_EFFECTS" ); gen_response_lines( d, 19 ); // add and remove effect diff --git a/tests/player_helpers.cpp b/tests/player_helpers.cpp index 2442d881cca55..7907569b12b1e 100644 --- a/tests/player_helpers.cpp +++ b/tests/player_helpers.cpp @@ -123,7 +123,7 @@ void arm_shooter( npc &shooter, const std::string &gun_type, shooter.remove_weapon(); // XL so arrows can fit. if( !shooter.is_wearing( itype_id( "debug_backpack" ) ) ) { - shooter.worn.push_back( item( "debug_backpack" ) ); + shooter.worn.emplace_back( "debug_backpack" ); } const itype_id &gun_id{ itype_id( gun_type ) }; diff --git a/tests/ranged_balance_test.cpp b/tests/ranged_balance_test.cpp index b4623a4b9ccec..bc27c11728a90 100644 --- a/tests/ranged_balance_test.cpp +++ b/tests/ranged_balance_test.cpp @@ -227,7 +227,7 @@ TEST_CASE( "unskilled_shooter_accuracy", "[ranged] [balance] [slow]" ) clear_map(); standard_npc shooter( "Shooter", shooter_pos, {}, 0, 8, 8, 8, 7 ); shooter.set_body(); - shooter.worn.push_back( item( "backpack" ) ); + shooter.worn.emplace_back( "backpack" ); equip_shooter( shooter, { "bastsandals", "armguard_chitin", "armor_chitin", "beekeeping_gloves", "mask_guy_fawkes", "cowboy_hat" } ); assert_encumbrance( shooter, 10 ); diff --git a/tests/reading_test.cpp b/tests/reading_test.cpp index 8f6a45c8c219d..a362594c8fb65 100644 --- a/tests/reading_test.cpp +++ b/tests/reading_test.cpp @@ -44,7 +44,7 @@ TEST_CASE( "identifying unread books", "[reading][book][identify]" ) { clear_avatar(); Character &dummy = get_avatar(); - dummy.worn.push_back( item( "backpack" ) ); + dummy.worn.emplace_back( "backpack" ); GIVEN( "character has some unidentified books" ) { item &book1 = dummy.i_add( item( "novel_western" ) ); @@ -70,7 +70,7 @@ TEST_CASE( "reading a book for fun", "[reading][book][fun]" ) clear_avatar(); Character &dummy = get_avatar(); dummy.set_body(); - dummy.worn.push_back( item( "backpack" ) ); + dummy.worn.emplace_back( "backpack" ); GIVEN( "a fun book" ) { item &book = dummy.i_add( item( "novel_western" ) ); @@ -141,7 +141,7 @@ TEST_CASE( "character reading speed", "[reading][character][speed]" ) { clear_avatar(); Character &dummy = get_avatar(); - dummy.worn.push_back( item( "backpack" ) ); + dummy.worn.emplace_back( "backpack" ); // Note: read_speed() returns number of moves; // 6000 == 60 seconds @@ -186,7 +186,7 @@ TEST_CASE( "character reading speed", "[reading][character][speed]" ) TEST_CASE( "estimated reading time for a book", "[reading][book][time]" ) { avatar dummy; - dummy.worn.push_back( item( "backpack" ) ); + dummy.worn.emplace_back( "backpack" ); // Easy, medium, and hard books item &child = dummy.i_add( item( "child_book" ) ); @@ -274,7 +274,7 @@ TEST_CASE( "reasons for not being able to read", "[reading][reasons]" ) { avatar dummy; dummy.set_body(); - dummy.worn.push_back( item( "backpack" ) ); + dummy.worn.emplace_back( "backpack" ); std::vector reasons; std::vector expect_reasons; @@ -369,7 +369,7 @@ TEST_CASE( "determining book mastery", "[reading][book][mastery]" ) avatar dummy; dummy.set_body(); - dummy.worn.push_back( item( "backpack" ) ); + dummy.worn.emplace_back( "backpack" ); item &child = dummy.i_add( item( "child_book" ) ); item &alpha = dummy.i_add( item( "recipe_alpha" ) ); diff --git a/tests/reload_option_test.cpp b/tests/reload_option_test.cpp index 6778426537b93..416649bbe26be 100644 --- a/tests/reload_option_test.cpp +++ b/tests/reload_option_test.cpp @@ -15,7 +15,7 @@ TEST_CASE( "revolver_reload_option", "[reload],[reload_option],[gun]" ) { avatar dummy; - dummy.worn.push_back( item( "backpack" ) ); + dummy.worn.emplace_back( "backpack" ); item &gun = dummy.i_add( item( "sw_619", calendar::turn_zero, 0 ) ); const ammotype &gun_ammo_type = item::find_type( gun.ammo_default() )->ammo->type; @@ -46,7 +46,7 @@ TEST_CASE( "revolver_reload_option", "[reload],[reload_option],[gun]" ) TEST_CASE( "magazine_reload_option", "[reload],[reload_option],[gun]" ) { avatar dummy; - dummy.worn.push_back( item( "backpack" ) ); + dummy.worn.emplace_back( "backpack" ); item &magazine = dummy.i_add( item( "glockmag", calendar::turn_zero, 0 ) ); const ammotype &mag_ammo_type = item::find_type( magazine.ammo_default() )->ammo->type; @@ -69,7 +69,7 @@ TEST_CASE( "belt_reload_option", "[reload],[reload_option],[gun]" ) { avatar dummy; dummy.set_body(); - dummy.worn.push_back( item( "backpack" ) ); + dummy.worn.emplace_back( "backpack" ); item &belt = dummy.i_add( item( "belt308", calendar::turn_zero, 0 ) ); const ammotype &belt_ammo_type = item::find_type( belt.ammo_default() )->ammo->type; @@ -96,7 +96,7 @@ TEST_CASE( "belt_reload_option", "[reload],[reload_option],[gun]" ) TEST_CASE( "canteen_reload_option", "[reload],[reload_option],[liquid]" ) { avatar dummy; - dummy.worn.push_back( item( "backpack" ) ); + dummy.worn.emplace_back( "backpack" ); item &bottle = dummy.i_add( item( "bottle_plastic" ) ); item water( "water_clean", calendar::turn_zero, 2 ); diff --git a/tests/reloading_test.cpp b/tests/reloading_test.cpp index f75d39fbcf676..56b7b5d929c3a 100644 --- a/tests/reloading_test.cpp +++ b/tests/reloading_test.cpp @@ -211,7 +211,7 @@ TEST_CASE( "automatic_reloading_action", "[reload],[gun]" ) GIVEN( "a player wielding an unloaded gun, carrying an unloaded magazine, and carrying ammo for the magazine" ) { dummy.worn.clear(); - dummy.worn.push_back( item( "backpack" ) ); + dummy.worn.emplace_back( "backpack" ); item &ammo = dummy.i_add( item( "9mm", calendar::turn_zero, 50 ) ); const cata::value_ptr &ammo_type = ammo.type->ammo; REQUIRE( ammo_type ); diff --git a/tests/string_ids_test.cpp b/tests/string_ids_test.cpp index 5cc963592b0f4..f8479470721a2 100644 --- a/tests/string_ids_test.cpp +++ b/tests/string_ids_test.cpp @@ -39,7 +39,7 @@ TEST_CASE( "string_ids_intern_test", "[string_id]" ) // lots of ids to make sure that "interning" map gets expanded ids.reserve( num_ids ); for( int i = 0; i < num_ids; ++i ) { - ids.push_back( string_id( "test_id" + std::to_string( i ) ) ); + ids.emplace_back( "test_id" + std::to_string( i ) ); } // check that interning works @@ -107,7 +107,7 @@ TEST_CASE( "string_id_sorting_test", "[string_id]" ) SECTION( "vector of pairs sorting" ) { std::vector> vec; for( int i = 9; i >= 0; i-- ) { - vec.push_back( {id( "id" + std::to_string( i ) ), i} ); + vec.emplace_back( id( "id" + std::to_string( i ) ), i ); } int i = 0; @@ -122,7 +122,7 @@ TEST_CASE( "string_id_sorting_test", "[string_id]" ) std::vector vec; vec.reserve( 10 ); for( int i = 0; i < 10; ++i ) { - vec.push_back( id( "id" + std::to_string( i ) ) ); + vec.emplace_back( "id" + std::to_string( i ) ); } int i = 0; diff --git a/tests/vehicle_part_test.cpp b/tests/vehicle_part_test.cpp index d69bca02778da..4f8a4b8964982 100644 --- a/tests/vehicle_part_test.cpp +++ b/tests/vehicle_part_test.cpp @@ -196,19 +196,19 @@ TEST_CASE( "craft_available_via_vehicle_rig", "[vehicle][vehicle_craft]" ) } SECTION( "cook oatmeal without battery" ) { std::vector items; - items.push_back( item( itype_id( "oatmeal" ) ) ); + items.emplace_back( itype_id( "oatmeal" ) ); test_craft_via_rig( items, 0, 0, 1, 1, recipe_id( "oatmeal_cooked" ).obj(), false ); } SECTION( "cook oatmeal without water" ) { std::vector items; - items.push_back( item( itype_id( "oatmeal" ) ) ); + items.emplace_back( itype_id( "oatmeal" ) ); test_craft_via_rig( items, 2, 2, 0, 0, recipe_id( "oatmeal_cooked" ).obj(), false ); } SECTION( "cook oatmeal successfully" ) { std::vector items; - items.push_back( item( itype_id( "oatmeal" ) ) ); + items.emplace_back( itype_id( "oatmeal" ) ); test_craft_via_rig( items, 2, 0, 1, 0, recipe_id( "oatmeal_cooked" ).obj(), true ); } diff --git a/tests/visitable_remove_test.cpp b/tests/visitable_remove_test.cpp index b31263c8a9c3e..15544be8a2c4f 100644 --- a/tests/visitable_remove_test.cpp +++ b/tests/visitable_remove_test.cpp @@ -50,7 +50,7 @@ TEST_CASE( "visitable_remove", "[visitable]" ) Character &p = get_player_character(); p.worn.clear(); - p.worn.push_back( item( "backpack" ) ); + p.worn.emplace_back( "backpack" ); p.inv->clear(); p.remove_weapon(); p.wear_item( item( "backpack" ) ); // so we don't drop anything From a36f1be5ffe6fb6ae4f94cbfd044e40417d18c0f Mon Sep 17 00:00:00 2001 From: krulunio Date: Thu, 20 May 2021 10:01:59 +0200 Subject: [PATCH 212/453] Add mansion basecamp and related expansions Expansions are simple and sometimes useless, I don't know what to do with them. Upgrade paths are short, because: 1. mansions are already built, not much to add to them 2. I don't know how to properly make expansions on rotatable terrain --- .../fbmc_mansion/fbmc_mansion_+1.json | 65 ++++++ .../fbmc_mansion/fbmc_mansion_+2.json | 23 ++ .../fbmc_mansion/fbmc_mansion_+3.json | 23 ++ .../fbmc_mansion/fbmc_mansion_+4.json | 52 +++++ .../fbmc_mansion/fbmc_mansion_common.json | 34 +++ .../fbmc_mansion/fbmc_mansion_expansion.json | 182 +++++++++++++++ data/json/mapgen_palettes/basecamps.json | 12 + .../overmap_terrain_faction_base.json | 120 ++++++++++ .../fbmc_mansion/fbmc_mansion_+1.json | 104 +++++++++ .../fbmc_mansion/fbmc_mansion_+2.json | 78 +++++++ .../fbmc_mansion/fbmc_mansion_+3.json | 78 +++++++ .../fbmc_mansion/fbmc_mansion_+4.json | 104 +++++++++ .../fbmc_mansion_expansion_surveys.json | 212 ++++++++++++++++++ .../json/recipes/basecamps/recipe_groups.json | 80 ++++++- 14 files changed, 1165 insertions(+), 2 deletions(-) create mode 100644 data/json/mapgen/basecamps/fbmc_mansion/fbmc_mansion_+1.json create mode 100644 data/json/mapgen/basecamps/fbmc_mansion/fbmc_mansion_+2.json create mode 100644 data/json/mapgen/basecamps/fbmc_mansion/fbmc_mansion_+3.json create mode 100644 data/json/mapgen/basecamps/fbmc_mansion/fbmc_mansion_+4.json create mode 100644 data/json/mapgen/basecamps/fbmc_mansion/fbmc_mansion_common.json create mode 100644 data/json/mapgen/basecamps/fbmc_mansion/fbmc_mansion_expansion.json create mode 100644 data/json/mapgen_palettes/basecamps.json create mode 100644 data/json/recipes/basecamps/fbmc_mansion/fbmc_mansion_+1.json create mode 100644 data/json/recipes/basecamps/fbmc_mansion/fbmc_mansion_+2.json create mode 100644 data/json/recipes/basecamps/fbmc_mansion/fbmc_mansion_+3.json create mode 100644 data/json/recipes/basecamps/fbmc_mansion/fbmc_mansion_+4.json create mode 100644 data/json/recipes/basecamps/fbmc_mansion/fbmc_mansion_expansion_surveys.json diff --git a/data/json/mapgen/basecamps/fbmc_mansion/fbmc_mansion_+1.json b/data/json/mapgen/basecamps/fbmc_mansion/fbmc_mansion_+1.json new file mode 100644 index 0000000000000..fc125b95fb49f --- /dev/null +++ b/data/json/mapgen/basecamps/fbmc_mansion/fbmc_mansion_+1.json @@ -0,0 +1,65 @@ +[ + { + "type": "mapgen", + "update_mapgen_id": "fbmc_mansion_+1", + "method": "json", + "object": { + "set": [ + { "point": "furniture", "id": "f_bulletin", "x": 9, "y": 9 } + ] + } + }, + { + "type": "mapgen", + "update_mapgen_id": "fbmc_mansion_+1_radio", + "method": "json", + "object": { + "set": [ + { "point": "terrain", "id": "t_radio_tower", "x": 8, "y": 9 }, + { "point": "terrain", "id": "t_radio_controls", "x": 8, "y": 10 } + ] + } + }, + { + "type": "mapgen", + "method": "json", + "nested_mapgen_id": "fbmc_mansion_+1_prefarm", + "object": { + "mapgensize": [ 12, 12 ], + "rows": [ + "dddd dddd", + "d d", + "d d", + "d d", + " ", + " ", + " ", + " ", + "d d", + "d d", + "d d", + "dddd dddd" + ], + "palettes": [ "fbmc_mansion_pallete" ] + } + }, + { + "type": "mapgen", + "update_mapgen_id": "fbmc_mansion_+1_farm", + "method": "json", + "object": { "place_nested": [ + { "chunks": [ "fbmc_mansion_+1_prefarm" ], "x": 6, "y": 6 }, + { "chunks": [ "fbmc_mansion_farm_field" ], "x": 6, "y": 5 }, + { "chunks": [ "fbmc_mansion_farm_field" ], "x": 13, "y": 5 }, + { "chunks": [ "fbmc_mansion_farm_field" ], "x": 1, "y": 17 }, + { "chunks": [ "fbmc_mansion_farm_field" ], "x": 6, "y": 17 }, + { "chunks": [ "fbmc_mansion_farm_field" ], "x": 1, "y": 20 }, + { "chunks": [ "fbmc_mansion_farm_field" ], "x": 6, "y": 20 }, + { "chunks": [ "fbmc_mansion_farm_field" ], "x": 13, "y": 17 }, + { "chunks": [ "fbmc_mansion_farm_field" ], "x": 18, "y": 17 }, + { "chunks": [ "fbmc_mansion_farm_field" ], "x": 13, "y": 20 }, + { "chunks": [ "fbmc_mansion_farm_field" ], "x": 18, "y": 20 } + ] + } + } +] \ No newline at end of file diff --git a/data/json/mapgen/basecamps/fbmc_mansion/fbmc_mansion_+2.json b/data/json/mapgen/basecamps/fbmc_mansion/fbmc_mansion_+2.json new file mode 100644 index 0000000000000..a96149d602e29 --- /dev/null +++ b/data/json/mapgen/basecamps/fbmc_mansion/fbmc_mansion_+2.json @@ -0,0 +1,23 @@ +[ + { + "type": "mapgen", + "update_mapgen_id": "fbmc_mansion_+2", + "method": "json", + "object": { + "set": [ + { "point": "furniture", "id": "f_bulletin", "x": 18, "y": 6 } + ] + } + }, + { + "type": "mapgen", + "update_mapgen_id": "fbmc_mansion_+2_radio", + "method": "json", + "object": { + "set": [ + { "point": "terrain", "id": "t_radio_tower", "x": 12, "y": 0 }, + { "point": "terrain", "id": "t_radio_controls", "x": 12, "y": 1 } + ] + } + } +] \ No newline at end of file diff --git a/data/json/mapgen/basecamps/fbmc_mansion/fbmc_mansion_+3.json b/data/json/mapgen/basecamps/fbmc_mansion/fbmc_mansion_+3.json new file mode 100644 index 0000000000000..9d072287f84c4 --- /dev/null +++ b/data/json/mapgen/basecamps/fbmc_mansion/fbmc_mansion_+3.json @@ -0,0 +1,23 @@ +[ + { + "type": "mapgen", + "update_mapgen_id": "fbmc_mansion_+3", + "method": "json", + "object": { + "set": [ + { "point": "furniture", "id": "f_bulletin", "x": 17, "y": 20 } + ] + } + }, + { + "type": "mapgen", + "update_mapgen_id": "fbmc_mansion_+3_radio", + "method": "json", + "object": { + "set": [ + { "point": "terrain", "id": "t_radio_tower", "x": 6, "y": 0 }, + { "point": "terrain", "id": "t_radio_controls", "x": 6, "y": 1 } + ] + } + } +] \ No newline at end of file diff --git a/data/json/mapgen/basecamps/fbmc_mansion/fbmc_mansion_+4.json b/data/json/mapgen/basecamps/fbmc_mansion/fbmc_mansion_+4.json new file mode 100644 index 0000000000000..30e2d5bc241f8 --- /dev/null +++ b/data/json/mapgen/basecamps/fbmc_mansion/fbmc_mansion_+4.json @@ -0,0 +1,52 @@ +[ + { + "type": "mapgen", + "update_mapgen_id": "fbmc_mansion_+4", + "method": "json", + "object": { + "set": [ + { "point": "furniture", "id": "f_bulletin", "x": 9, "y": 2 } + ] + } + }, + { + "type": "mapgen", + "update_mapgen_id": "fbmc_mansion_+4_radio", + "method": "json", + "object": { + "set": [ + { "point": "terrain", "id": "t_radio_tower", "x": 14, "y": 10 }, + { "point": "terrain", "id": "t_radio_controls", "x": 14, "y": 11 } + ] + } + }, + { + "type": "mapgen", + "method": "json", + "nested_mapgen_id": "fbmc_mansion_+4_prefarm", + "object": { + "mapgensize": [ 6, 6 ], + "rows": [ + "dddddd", + "dddddd", + "dddddd", + "dddddd", + " ", + " " + ], + "palettes": [ "fbmc_mansion_pallete" ] + } + }, + { + "type": "mapgen", + "update_mapgen_id": "fbmc_mansion_+4_farm", + "method": "json", + "object": { "place_nested": [ + { "chunks": [ "fbmc_mansion_+4_prefarm" ], "x": 4, "y": 10 }, + { "chunks": [ "fbmc_mansion_+4_prefarm" ], "x": 14, "y": 10 }, + { "chunks": [ "fbmc_mansion_farm_field" ], "x": 4, "y": 11 }, + { "chunks": [ "fbmc_mansion_farm_field" ], "x": 14, "y": 11 } + ] + } + } +] \ No newline at end of file diff --git a/data/json/mapgen/basecamps/fbmc_mansion/fbmc_mansion_common.json b/data/json/mapgen/basecamps/fbmc_mansion/fbmc_mansion_common.json new file mode 100644 index 0000000000000..87116349d41fb --- /dev/null +++ b/data/json/mapgen/basecamps/fbmc_mansion/fbmc_mansion_common.json @@ -0,0 +1,34 @@ +[ + { + "type": "mapgen", + "method": "json", + "nested_mapgen_id": "fbmc_mansion_farm_field", + "object": { + "mapgensize": [ 5, 5 ], + "rows": [ + "fffff", + "fffff", + " ", + " ", + " " + ], + "palettes": [ "fbmc_mansion_pallete" ] + } + }, + { + "type": "mapgen", + "method": "json", + "nested_mapgen_id": "fbmc_mansion_farm_field_thin", + "object": { + "mapgensize": [ 5, 5 ], + "rows": [ + "fffff", + " ", + " ", + " ", + " " + ], + "palettes": [ "fbmc_mansion_pallete" ] + } + } +] \ No newline at end of file diff --git a/data/json/mapgen/basecamps/fbmc_mansion/fbmc_mansion_expansion.json b/data/json/mapgen/basecamps/fbmc_mansion/fbmc_mansion_expansion.json new file mode 100644 index 0000000000000..dd5274f304328 --- /dev/null +++ b/data/json/mapgen/basecamps/fbmc_mansion/fbmc_mansion_expansion.json @@ -0,0 +1,182 @@ +[ + { + "type": "mapgen", + "update_mapgen_id": "faction_base_mansion_e1", + "method": "json", + "object": { + "set": [ + { "point": "furniture", "id": "f_null", "x": 0, "y": 0 } + ] + } + }, + { + "type": "mapgen", + "update_mapgen_id": "faction_base_mansion_e2", + "method": "json", + "object": { + "set": [ + { "point": "furniture", "id": "f_null", "x": 0, "y": 0 } + ] + } + }, + { + "type": "mapgen", + "update_mapgen_id": "faction_base_mansion_t1", + "method": "json", + "object": { + "set": [ + { "point": "furniture", "id": "f_null", "x": 0, "y": 0 } + ] + } + }, + { + "type": "mapgen", + "update_mapgen_id": "faction_base_mansion_t2", + "method": "json", + "object": { + "set": [ + { "point": "furniture", "id": "f_null", "x": 0, "y": 0 } + ] + } + }, + { + "type": "mapgen", + "update_mapgen_id": "faction_base_mansion_t3", + "method": "json", + "object": { + "set": [ + { "point": "furniture", "id": "f_null", "x": 0, "y": 0 } + ] + } + }, + { + "type": "mapgen", + "update_mapgen_id": "faction_base_mansion_t4", + "method": "json", + "object": { + "set": [ + { "point": "furniture", "id": "f_null", "x": 0, "y": 0 } + ] + } + }, + { + "type": "mapgen", + "update_mapgen_id": "faction_base_mansion_t5", + "method": "json", + "object": { + "set": [ + { "point": "furniture", "id": "f_null", "x": 0, "y": 0 } + ] + } + }, + { + "type": "mapgen", + "update_mapgen_id": "faction_base_mansion_t6", + "method": "json", + "object": { + "set": [ + { "point": "furniture", "id": "f_null", "x": 0, "y": 0 } + ] + } + }, + { + "type": "mapgen", + "update_mapgen_id": "faction_base_mansion_t7", + "method": "json", + "object": { + "set": [ + { "point": "furniture", "id": "f_null", "x": 0, "y": 0 } + ] + } + }, + { + "type": "mapgen", + "update_mapgen_id": "faction_base_mansion_+1", + "method": "json", + "object": { + "set": [ + { "point": "furniture", "id": "f_null", "x": 0, "y": 0 } + ] + } + }, + { + "type": "mapgen", + "update_mapgen_id": "faction_base_mansion_+2", + "method": "json", + "object": { + "set": [ + { "point": "furniture", "id": "f_null", "x": 0, "y": 0 } + ] + } + }, + { + "type": "mapgen", + "update_mapgen_id": "faction_base_mansion_+3", + "method": "json", + "object": { + "set": [ + { "point": "furniture", "id": "f_null", "x": 0, "y": 0 } + ] + } + }, + { + "type": "mapgen", + "update_mapgen_id": "faction_base_mansion_+4", + "method": "json", + "object": { + "set": [ + { "point": "furniture", "id": "f_null", "x": 0, "y": 0 } + ] + } + }, + { + "type": "mapgen", + "update_mapgen_id": "faction_base_mansion_c1", + "method": "json", + "object": { + "set": [ + { "point": "furniture", "id": "f_null", "x": 0, "y": 0 } + ] + } + }, + { + "type": "mapgen", + "update_mapgen_id": "faction_base_mansion_c2", + "method": "json", + "object": { + "set": [ + { "point": "furniture", "id": "f_null", "x": 0, "y": 0 } + ] + } + }, + { + "type": "mapgen", + "update_mapgen_id": "faction_base_mansion_c3", + "method": "json", + "object": { + "set": [ + { "point": "furniture", "id": "f_null", "x": 0, "y": 0 } + ] + } + }, + { + "type": "mapgen", + "update_mapgen_id": "faction_base_mansion_c4", + "method": "json", + "object": { + "set": [ + { "point": "furniture", "id": "f_null", "x": 0, "y": 0 } + ] + } + }, + { + "type": "mapgen", + "update_mapgen_id": "faction_base_mansion_c5", + "method": "json", + "object": { + "set": [ + { "point": "furniture", "id": "f_null", "x": 0, "y": 0 } + ] + } + } +] \ No newline at end of file diff --git a/data/json/mapgen_palettes/basecamps.json b/data/json/mapgen_palettes/basecamps.json new file mode 100644 index 0000000000000..e88348cbf6c9c --- /dev/null +++ b/data/json/mapgen_palettes/basecamps.json @@ -0,0 +1,12 @@ +[ + { + "type": "palette", + "id": "fbmc_mansion_pallete", + "terrain": { + "d": "t_dirt", + "f": "t_dirtmound", + "W": "t_wall_wood", + "D": "t_rdoor_c" + } + } +] \ No newline at end of file diff --git a/data/json/overmap/overmap_terrain/overmap_terrain_faction_base.json b/data/json/overmap/overmap_terrain/overmap_terrain_faction_base.json index aceb9c17e4519..1ed36875a82ac 100644 --- a/data/json/overmap/overmap_terrain/overmap_terrain_faction_base.json +++ b/data/json/overmap/overmap_terrain/overmap_terrain_faction_base.json @@ -189,5 +189,125 @@ "name": "canteen survey", "color": "i_green", "delete": { "flags": [ "SOURCE_PEOPLE" ] } + }, + { + "type": "overmap_terrain", + "id": "faction_base_mansion_e1", + "name": "mansion base entrance", + "sym": "M", + "color": "white", + "flags": [ "SOURCE_PEOPLE", "NO_ROTATE" ] + }, + { + "type": "overmap_terrain", + "id": "faction_base_mansion_e2", + "name": "mansion base entrance", + "sym": "M", + "color": "white", + "flags": [ "SOURCE_PEOPLE", "NO_ROTATE" ] + }, + { + "type": "overmap_terrain", + "id": "faction_base_mansion_t1", + "name": "mansion base swimming pool", + "sym": "M", + "color": "blue", + "flags": [ "SOURCE_PEOPLE", "NO_ROTATE" ] + }, + { + "type": "overmap_terrain", + "id": "faction_base_mansion_t2", + "name": "mansion base bedrooms", + "sym": "M", + "color": "light_green", + "flags": [ "SOURCE_PEOPLE", "NO_ROTATE" ] + }, + { + "type": "overmap_terrain", + "id": "faction_base_mansion_t3", + "name": "mansion base ???", + "sym": "M", + "color": "white", + "flags": [ "SOURCE_PEOPLE", "NO_ROTATE" ] + }, + { + "type": "overmap_terrain", + "id": "faction_base_mansion_t4", + "name": "mansion base kitchen", + "sym": "M", + "color": "pink", + "flags": [ "SOURCE_PEOPLE", "NO_ROTATE" ] + }, + { + "type": "overmap_terrain", + "id": "faction_base_mansion_t5", + "name": "mansion base library", + "sym": "M", + "color": "brown", + "flags": [ "SOURCE_PEOPLE", "NO_ROTATE" ] + }, + { + "type": "overmap_terrain", + "id": "faction_base_mansion_t6", + "name": "mansion base bedroom", + "sym": "M", + "color": "light_green", + "flags": [ "SOURCE_PEOPLE", "NO_ROTATE" ] + }, + { + "type": "overmap_terrain", + "id": "faction_base_mansion_t7", + "name": "mansion base living rooms", + "sym": "M", + "color": "green", + "flags": [ "SOURCE_PEOPLE", "NO_ROTATE" ] + }, + { + "type": "overmap_terrain", + "id": "faction_base_mansion_c1", + "name": "mansion base swimming pool", + "sym": "M", + "color": "blue", + "flags": [ "SOURCE_PEOPLE", "NO_ROTATE" ] + }, + { + "type": "overmap_terrain", + "id": "faction_base_mansion_c2", + "name": "mansion base bar", + "sym": "M", + "color": "magenta", + "flags": [ "SOURCE_PEOPLE", "NO_ROTATE" ] + }, + { + "type": "overmap_terrain", + "id": "faction_base_mansion_c3", + "name": "mansion base living rooms", + "sym": "M", + "color": "green", + "flags": [ "SOURCE_PEOPLE", "NO_ROTATE" ] + }, + { + "type": "overmap_terrain", + "id": "faction_base_mansion_c4", + "name": "mansion base bedroom", + "sym": "M", + "color": "light_green", + "flags": [ "SOURCE_PEOPLE", "NO_ROTATE" ] + }, + { + "type": "overmap_terrain", + "id": "faction_base_mansion_c5", + "name": "mansion base kitchen", + "sym": "M", + "color": "pink", + "flags": [ "SOURCE_PEOPLE", "NO_ROTATE" ] + }, + { + "type": "overmap_terrain", + "id": "faction_base_lake_shore", + "name": "fishing spot", + "sym": "+", + "color": "i_light_blue", + "flags": [ "SOURCE_PEOPLE", "NO_ROTATE", "LAKE_SHORE", "SOURCE_DRINK" ] } ] diff --git a/data/json/recipes/basecamps/fbmc_mansion/fbmc_mansion_+1.json b/data/json/recipes/basecamps/fbmc_mansion/fbmc_mansion_+1.json new file mode 100644 index 0000000000000..7d0edfaf04c6d --- /dev/null +++ b/data/json/recipes/basecamps/fbmc_mansion/fbmc_mansion_+1.json @@ -0,0 +1,104 @@ +[ + { + "type": "recipe", + "result": "faction_base_mansion_+1_0", + "description": "We should survey the base site and set up a bulletin board.", + "category": "CC_BUILDING", + "subcategory": "CSC_BUILDING_BASES", + "skill_used": "fabrication", + "autolearn": false, + "never_learn": true, + "time": "1 h", + "construction_blueprint": "fbmc_mansion_+1", + "blueprint_provides": [ + { "id": "fbmc_mansion_+1" }, + { "id": "primitive_camp_recipes_1" }, + { "id": "gathering" }, + { "id": "firewood" }, + { "id": "foraging" }, + { "id": "sorting" }, + { "id": "logging" }, + { "id": "tool_storage" }, + { "id": "bed", "amount": 8 } + ], + "blueprint_requires": [ { "id": "not_an_upgrade" } ], + "blueprint_name": "basic survey", + "check_blueprint_needs": false + }, + { + "type": "recipe", + "result": "faction_base_mansion_+1_garden", + "description": "Let's remove plants from garden and plow a few plots.", + "category": "CC_BUILDING", + "subcategory": "CSC_BUILDING_BASES", + "skill_used": "fabrication", + "autolearn": false, + "never_learn": true, + "construction_blueprint": "fbmc_mansion_+1_farm", + "blueprint_name": "prepare garden", + "blueprint_requires": [ { "id": "fbmc_mansion_+1" } ], + "blueprint_provides": [ + { "id": "fbmc_mansion_+1_farm" }, + { "id": "farming" }, + { "id": "farm_recipes_1" } + ], + "blueprint_excludes": [ { "id": "fbmc_mansion_+1_farm" } ], + "blueprint_needs": { + "time": "7 h", + "inline": { + "tools": [ ], + "qualities": [ [ { "id": "DIG", "level": 1 } ] ] + } + } + }, + { + "type": "recipe", + "result": "faction_base_mansion_+1_radio", + "description": "Let's set up a radio tower to improve our recruitment efforts.", + "category": "CC_BUILDING", + "subcategory": "CSC_BUILDING_BASES", + "autolearn": false, + "never_learn": true, + "construction_blueprint": "fbmc_mansion_+1_radio", + "blueprint_name": "build a radio tower and console", + "blueprint_requires": [ { "id": "fbmc_mansion_+1_farm" } ], + "blueprint_provides": [ + { "id": "fbmc_mansion_+1_radio" }, + { "id": "recruiting" }, + { "id": "radio" } + ], + "blueprint_excludes": [ { "id": "fbmc_mansion_+1_radio" } ], + "blueprint_needs": { + "time": "2 d", + "skills": [ [ "fabrication", 3 ] ], + "inline": { + "tools": [ ], + "qualities": [ [ { "id": "HAMMER", "level": 2 } ], [ { "id": "SAW_M" } ], [ { "id": "SCREW" } ], [ { "id": "WRENCH" } ] ], + "components": [ + [ + [ "wind_turbine", 4 ], + [ "xl_wind_turbine", 1 ], + [ "solar_panel", 4 ], + [ "reinforced_solar_panel", 4 ], + [ "solar_panel_v2", 2 ], + [ "reinforced_solar_panel_v2", 2 ], + [ "solar_panel_v3", 1 ] + ], + [ [ "storage_battery", 1 ], [ "medium_storage_battery", 4 ], [ "small_storage_battery", 32 ] ], + [ [ "sheet_metal", 2 ], [ "wire", 8 ] ], + [ [ "pipe", 24 ] ], + [ [ "processor", 2 ] ], + [ [ "RAM", 2 ] ], + [ [ "large_lcd_screen", 1 ] ], + [ [ "e_scrap", 8 ] ], + [ [ "frame", 1 ] ], + [ [ "circuit", 4 ] ], + [ [ "power_supply", 2 ] ], + [ [ "amplifier", 2 ] ], + [ [ "cable", 80 ] ], + [ [ "motor_small", 1 ], [ "motor_tiny", 2 ] ] + ] + } + } + } +] diff --git a/data/json/recipes/basecamps/fbmc_mansion/fbmc_mansion_+2.json b/data/json/recipes/basecamps/fbmc_mansion/fbmc_mansion_+2.json new file mode 100644 index 0000000000000..50dc6066206f3 --- /dev/null +++ b/data/json/recipes/basecamps/fbmc_mansion/fbmc_mansion_+2.json @@ -0,0 +1,78 @@ +[ + { + "type": "recipe", + "result": "faction_base_mansion_+2_0", + "description": "We should survey the base site and set up a bulletin board.", + "category": "CC_BUILDING", + "subcategory": "CSC_BUILDING_BASES", + "skill_used": "fabrication", + "autolearn": false, + "never_learn": true, + "time": "1 h", + "construction_blueprint": "fbmc_mansion_+2", + "blueprint_provides": [ + { "id": "fbmc_mansion_+2" }, + { "id": "primitive_camp_recipes_1" }, + { "id": "gathering" }, + { "id": "firewood" }, + { "id": "foraging" }, + { "id": "sorting" }, + { "id": "logging" }, + { "id": "tool_storage" }, + { "id": "bed", "amount": 8 } + ], + "blueprint_requires": [ { "id": "not_an_upgrade" } ], + "blueprint_name": "basic survey", + "check_blueprint_needs": false + }, + { + "type": "recipe", + "result": "faction_base_mansion_+2_radio", + "description": "Let's set up a radio tower to improve our recruitment efforts.", + "category": "CC_BUILDING", + "subcategory": "CSC_BUILDING_BASES", + "autolearn": false, + "never_learn": true, + "construction_blueprint": "fbmc_mansion_+2_radio", + "blueprint_name": "build a radio tower and console", + "blueprint_requires": [ { "id": "fbmc_mansion_+2" } ], + "blueprint_provides": [ + { "id": "fbmc_mansion_+2_radio" }, + { "id": "recruiting" }, + { "id": "radio" } + ], + "blueprint_excludes": [ { "id": "fbmc_mansion_+2_radio" } ], + "blueprint_needs": { + "time": "2 d", + "skills": [ [ "fabrication", 3 ] ], + "inline": { + "tools": [ ], + "qualities": [ [ { "id": "HAMMER", "level": 2 } ], [ { "id": "SAW_M" } ], [ { "id": "SCREW" } ], [ { "id": "WRENCH" } ] ], + "components": [ + [ + [ "wind_turbine", 4 ], + [ "xl_wind_turbine", 1 ], + [ "solar_panel", 4 ], + [ "reinforced_solar_panel", 4 ], + [ "solar_panel_v2", 2 ], + [ "reinforced_solar_panel_v2", 2 ], + [ "solar_panel_v3", 1 ] + ], + [ [ "storage_battery", 1 ], [ "medium_storage_battery", 4 ], [ "small_storage_battery", 32 ] ], + [ [ "sheet_metal", 2 ], [ "wire", 8 ] ], + [ [ "pipe", 24 ] ], + [ [ "processor", 2 ] ], + [ [ "RAM", 2 ] ], + [ [ "large_lcd_screen", 1 ] ], + [ [ "e_scrap", 8 ] ], + [ [ "frame", 1 ] ], + [ [ "circuit", 4 ] ], + [ [ "power_supply", 2 ] ], + [ [ "amplifier", 2 ] ], + [ [ "cable", 80 ] ], + [ [ "motor_small", 1 ], [ "motor_tiny", 2 ] ] + ] + } + } + } +] diff --git a/data/json/recipes/basecamps/fbmc_mansion/fbmc_mansion_+3.json b/data/json/recipes/basecamps/fbmc_mansion/fbmc_mansion_+3.json new file mode 100644 index 0000000000000..7bf5a0a53e9e6 --- /dev/null +++ b/data/json/recipes/basecamps/fbmc_mansion/fbmc_mansion_+3.json @@ -0,0 +1,78 @@ +[ + { + "type": "recipe", + "result": "faction_base_mansion_+3_0", + "description": "We should survey the base site and set up a bulletin board.", + "category": "CC_BUILDING", + "subcategory": "CSC_BUILDING_BASES", + "skill_used": "fabrication", + "autolearn": false, + "never_learn": true, + "time": "1 h", + "construction_blueprint": "fbmc_mansion_+3", + "blueprint_provides": [ + { "id": "fbmc_mansion_+3" }, + { "id": "primitive_camp_recipes_1" }, + { "id": "gathering" }, + { "id": "firewood" }, + { "id": "foraging" }, + { "id": "sorting" }, + { "id": "logging" }, + { "id": "tool_storage" }, + { "id": "bed", "amount": 8 } + ], + "blueprint_requires": [ { "id": "not_an_upgrade" } ], + "blueprint_name": "basic survey", + "check_blueprint_needs": false + }, + { + "type": "recipe", + "result": "faction_base_mansion_+3_radio", + "description": "Let's set up a radio tower to improve our recruitment efforts.", + "category": "CC_BUILDING", + "subcategory": "CSC_BUILDING_BASES", + "autolearn": false, + "never_learn": true, + "construction_blueprint": "fbmc_mansion_+3_radio", + "blueprint_name": "build a radio tower and console", + "blueprint_requires": [ { "id": "fbmc_mansion_+3" } ], + "blueprint_provides": [ + { "id": "fbmc_mansion_+3_radio" }, + { "id": "recruiting" }, + { "id": "radio" } + ], + "blueprint_excludes": [ { "id": "fbmc_mansion_+3_radio" } ], + "blueprint_needs": { + "time": "2 d", + "skills": [ [ "fabrication", 3 ] ], + "inline": { + "tools": [ ], + "qualities": [ [ { "id": "HAMMER", "level": 2 } ], [ { "id": "SAW_M" } ], [ { "id": "SCREW" } ], [ { "id": "WRENCH" } ] ], + "components": [ + [ + [ "wind_turbine", 4 ], + [ "xl_wind_turbine", 1 ], + [ "solar_panel", 4 ], + [ "reinforced_solar_panel", 4 ], + [ "solar_panel_v2", 2 ], + [ "reinforced_solar_panel_v2", 2 ], + [ "solar_panel_v3", 1 ] + ], + [ [ "storage_battery", 1 ], [ "medium_storage_battery", 4 ], [ "small_storage_battery", 32 ] ], + [ [ "sheet_metal", 2 ], [ "wire", 8 ] ], + [ [ "pipe", 24 ] ], + [ [ "processor", 2 ] ], + [ [ "RAM", 2 ] ], + [ [ "large_lcd_screen", 1 ] ], + [ [ "e_scrap", 8 ] ], + [ [ "frame", 1 ] ], + [ [ "circuit", 4 ] ], + [ [ "power_supply", 2 ] ], + [ [ "amplifier", 2 ] ], + [ [ "cable", 80 ] ], + [ [ "motor_small", 1 ], [ "motor_tiny", 2 ] ] + ] + } + } + } +] diff --git a/data/json/recipes/basecamps/fbmc_mansion/fbmc_mansion_+4.json b/data/json/recipes/basecamps/fbmc_mansion/fbmc_mansion_+4.json new file mode 100644 index 0000000000000..57b315b86c57b --- /dev/null +++ b/data/json/recipes/basecamps/fbmc_mansion/fbmc_mansion_+4.json @@ -0,0 +1,104 @@ +[ + { + "type": "recipe", + "result": "faction_base_mansion_+4_0", + "description": "We should survey the base site and set up a bulletin board.", + "category": "CC_BUILDING", + "subcategory": "CSC_BUILDING_BASES", + "skill_used": "fabrication", + "autolearn": false, + "never_learn": true, + "time": "1 h", + "construction_blueprint": "fbmc_mansion_+4", + "blueprint_provides": [ + { "id": "fbmc_mansion_+4" }, + { "id": "primitive_camp_recipes_1" }, + { "id": "gathering" }, + { "id": "firewood" }, + { "id": "foraging" }, + { "id": "sorting" }, + { "id": "logging" }, + { "id": "tool_storage" }, + { "id": "bed", "amount": 8 } + ], + "blueprint_requires": [ { "id": "not_an_upgrade" } ], + "blueprint_name": "basic survey", + "check_blueprint_needs": false + }, + { + "type": "recipe", + "result": "faction_base_mansion_+4_garden", + "description": "Let's remove plants from garden and plow a few plots.", + "category": "CC_BUILDING", + "subcategory": "CSC_BUILDING_BASES", + "skill_used": "fabrication", + "autolearn": false, + "never_learn": true, + "construction_blueprint": "fbmc_mansion_+4_farm", + "blueprint_name": "prepare garden", + "blueprint_requires": [ { "id": "fbmc_mansion_+4" } ], + "blueprint_provides": [ + { "id": "fbmc_mansion_+4_farm" }, + { "id": "farming" }, + { "id": "farm_recipes_1" } + ], + "blueprint_excludes": [ { "id": "fbmc_mansion_+1_farm" } ], + "blueprint_needs": { + "time": "2 h", + "inline": { + "tools": [ ], + "qualities": [ [ { "id": "DIG", "level": 1 } ] ] + } + } + }, + { + "type": "recipe", + "result": "faction_base_mansion_+4_radio", + "description": "Let's set up a radio tower to improve our recruitment efforts.", + "category": "CC_BUILDING", + "subcategory": "CSC_BUILDING_BASES", + "autolearn": false, + "never_learn": true, + "construction_blueprint": "fbmc_mansion_+4_radio", + "blueprint_name": "build a radio tower and console", + "blueprint_requires": [ { "id": "fbmc_mansion_+4_farm" } ], + "blueprint_provides": [ + { "id": "fbmc_mansion_+4_radio" }, + { "id": "recruiting" }, + { "id": "radio" } + ], + "blueprint_excludes": [ { "id": "fbmc_mansion_+4_radio" } ], + "blueprint_needs": { + "time": "2 d", + "skills": [ [ "fabrication", 3 ] ], + "inline": { + "tools": [ ], + "qualities": [ [ { "id": "HAMMER", "level": 2 } ], [ { "id": "SAW_M" } ], [ { "id": "SCREW" } ], [ { "id": "WRENCH" } ] ], + "components": [ + [ + [ "wind_turbine", 4 ], + [ "xl_wind_turbine", 1 ], + [ "solar_panel", 4 ], + [ "reinforced_solar_panel", 4 ], + [ "solar_panel_v2", 2 ], + [ "reinforced_solar_panel_v2", 2 ], + [ "solar_panel_v3", 1 ] + ], + [ [ "storage_battery", 1 ], [ "medium_storage_battery", 4 ], [ "small_storage_battery", 32 ] ], + [ [ "sheet_metal", 2 ], [ "wire", 8 ] ], + [ [ "pipe", 24 ] ], + [ [ "processor", 2 ] ], + [ [ "RAM", 2 ] ], + [ [ "large_lcd_screen", 1 ] ], + [ [ "e_scrap", 8 ] ], + [ [ "frame", 1 ] ], + [ [ "circuit", 4 ] ], + [ [ "power_supply", 2 ] ], + [ [ "amplifier", 2 ] ], + [ [ "cable", 80 ] ], + [ [ "motor_small", 1 ], [ "motor_tiny", 2 ] ] + ] + } + } + } +] diff --git a/data/json/recipes/basecamps/fbmc_mansion/fbmc_mansion_expansion_surveys.json b/data/json/recipes/basecamps/fbmc_mansion/fbmc_mansion_expansion_surveys.json new file mode 100644 index 0000000000000..c8cf5ee17a87a --- /dev/null +++ b/data/json/recipes/basecamps/fbmc_mansion/fbmc_mansion_expansion_surveys.json @@ -0,0 +1,212 @@ +[ + { + "type": "recipe", + "result": "faction_base_mansion_e1", + "description": "Survey mansion's entrance.", + "category": "CC_BUILDING", + "subcategory": "CSC_BUILDING_BASES", + "skill_used": "fabrication", + "autolearn": false, + "never_learn": true, + "construction_blueprint": "faction_base_mansion_e1", + "blueprint_name": "entrance survey", + "time": "180 m", + "blueprint_requires": [ { "id": "not_an_upgrade" } ], + "blueprint_provides": [ { "id": "faction_base_mansion_e1" }, { "id": "farming" }, { "id": "reseeding" }, { "id": "farm_recipes_1" } ] + }, + { + "type": "recipe", + "result": "faction_base_mansion_e2", + "description": "Survey mansion's entrance.", + "category": "CC_BUILDING", + "subcategory": "CSC_BUILDING_BASES", + "skill_used": "fabrication", + "autolearn": false, + "never_learn": true, + "construction_blueprint": "faction_base_mansion_e2", + "blueprint_name": "entrance survey", + "time": "180 m", + "blueprint_requires": [ { "id": "not_an_upgrade" } ], + "blueprint_provides": [ { "id": "faction_base_mansion_e2" }, { "id": "farming" }, { "id": "reseeding" }, { "id": "farm_recipes_1" } ] + }, + { + "type": "recipe", + "result": "faction_base_mansion_t1", + "description": "Survey mansion's swimming pool.", + "category": "CC_BUILDING", + "subcategory": "CSC_BUILDING_BASES", + "skill_used": "fabrication", + "autolearn": false, + "never_learn": true, + "construction_blueprint": "faction_base_mansion_t1", + "blueprint_name": "swimming pool survey", + "time": "180 m", + "blueprint_requires": [ { "id": "not_an_upgrade" } ], + "blueprint_provides": [ { "id": "faction_base_mansion_t1" }, { "id": "farming" }, { "id": "reseeding" }, { "id": "farm_recipes_1" } ] + }, + { + "type": "recipe", + "result": "faction_base_mansion_t2", + "description": "Survey mansion's bedrooms.", + "category": "CC_BUILDING", + "subcategory": "CSC_BUILDING_BASES", + "skill_used": "fabrication", + "autolearn": false, + "never_learn": true, + "construction_blueprint": "faction_base_mansion_t2", + "blueprint_name": "bedrooms survey", + "time": "180 m", + "blueprint_requires": [ { "id": "not_an_upgrade" } ], + "blueprint_provides": [ { "id": "faction_base_mansion_t2" } ] + }, + { + "type": "recipe", + "result": "faction_base_mansion_t3", + "description": "Survey mansion's ???.", + "category": "CC_BUILDING", + "subcategory": "CSC_BUILDING_BASES", + "skill_used": "fabrication", + "autolearn": false, + "never_learn": true, + "construction_blueprint": "faction_base_mansion_t3", + "blueprint_name": "??? survey", + "time": "180 m", + "blueprint_requires": [ { "id": "not_an_upgrade" } ], + "blueprint_provides": [ { "id": "faction_base_mansion_t3" } ] + }, + { + "type": "recipe", + "result": "faction_base_mansion_t4", + "description": "Survey mansion's kitchen.", + "category": "CC_BUILDING", + "subcategory": "CSC_BUILDING_BASES", + "skill_used": "fabrication", + "autolearn": false, + "never_learn": true, + "construction_blueprint": "faction_base_mansion_t4", + "blueprint_name": "kitchen survey", + "time": "180 m", + "blueprint_requires": [ { "id": "not_an_upgrade" } ], + "blueprint_provides": [ { "id": "faction_base_mansion_t4" }, { "id": "kitchen" }, { "id": "kitchen_recipes_1" }, { "id": "kitchen_recipes_2" }, { "id": "kitchen_recipes_3" }, { "id": "saltworks_recipes_1" }, { "id": "saltworks_recipes_2" }, { "id": "saltworks_recipes_3" } ] + }, + { + "type": "recipe", + "result": "faction_base_mansion_t5", + "description": "Survey mansion's library.", + "category": "CC_BUILDING", + "subcategory": "CSC_BUILDING_BASES", + "skill_used": "fabrication", + "autolearn": false, + "never_learn": true, + "construction_blueprint": "faction_base_mansion_t5", + "blueprint_name": "library survey", + "time": "180 m", + "blueprint_requires": [ { "id": "not_an_upgrade" } ], + "blueprint_provides": [ { "id": "faction_base_mansion_t5" }, { "id": "kitchen" }, { "id": "library_recipes_1" } ] + }, + { + "type": "recipe", + "result": "faction_base_mansion_t6", + "description": "Survey mansion's bedroom.", + "category": "CC_BUILDING", + "subcategory": "CSC_BUILDING_BASES", + "skill_used": "fabrication", + "autolearn": false, + "never_learn": true, + "construction_blueprint": "faction_base_mansion_t6", + "blueprint_name": "bedroom survey", + "time": "180 m", + "blueprint_requires": [ { "id": "not_an_upgrade" } ], + "blueprint_provides": [ { "id": "faction_base_mansion_t6" } ] + }, + { + "type": "recipe", + "result": "faction_base_mansion_t7", + "description": "Survey mansion's living rooms.", + "category": "CC_BUILDING", + "subcategory": "CSC_BUILDING_BASES", + "skill_used": "fabrication", + "autolearn": false, + "never_learn": true, + "construction_blueprint": "faction_base_mansion_t7", + "blueprint_name": "living rooms survey", + "time": "180 m", + "blueprint_requires": [ { "id": "not_an_upgrade" } ], + "blueprint_provides": [ { "id": "faction_base_mansion_t7" } ] + }, + { + "type": "recipe", + "result": "faction_base_mansion_c1", + "description": "Survey mansion's swimming pool.", + "category": "CC_BUILDING", + "subcategory": "CSC_BUILDING_BASES", + "skill_used": "fabrication", + "autolearn": false, + "never_learn": true, + "construction_blueprint": "faction_base_mansion_c1", + "blueprint_name": "swimming survey", + "time": "180 m", + "blueprint_requires": [ { "id": "not_an_upgrade" } ], + "blueprint_provides": [ { "id": "faction_base_mansion_c1" } ] + }, + { + "type": "recipe", + "result": "faction_base_mansion_c2", + "description": "Survey mansion's bar.", + "category": "CC_BUILDING", + "subcategory": "CSC_BUILDING_BASES", + "skill_used": "fabrication", + "autolearn": false, + "never_learn": true, + "construction_blueprint": "faction_base_mansion_c2", + "blueprint_name": "bar survey", + "time": "180 m", + "blueprint_requires": [ { "id": "not_an_upgrade" } ], + "blueprint_provides": [ { "id": "faction_base_mansion_c2" }, { "id": "kitchen" }, { "id": "kitchen_recipes_1" }, { "id": "kitchen_recipes_2" }, { "id": "kitchen_recipes_3" } ] + }, + { + "type": "recipe", + "result": "faction_base_mansion_c3", + "description": "Survey mansion's living rooms.", + "category": "CC_BUILDING", + "subcategory": "CSC_BUILDING_BASES", + "skill_used": "fabrication", + "autolearn": false, + "never_learn": true, + "construction_blueprint": "faction_base_mansion_c3", + "blueprint_name": "living rooms survey", + "time": "180 m", + "blueprint_requires": [ { "id": "not_an_upgrade" } ], + "blueprint_provides": [ { "id": "faction_base_mansion_c3" } ] + }, + { + "type": "recipe", + "result": "faction_base_mansion_c4", + "description": "Survey mansion's bedroom.", + "category": "CC_BUILDING", + "subcategory": "CSC_BUILDING_BASES", + "skill_used": "fabrication", + "autolearn": false, + "never_learn": true, + "construction_blueprint": "faction_base_mansion_c4", + "blueprint_name": "bedroom survey", + "time": "180 m", + "blueprint_requires": [ { "id": "not_an_upgrade" } ], + "blueprint_provides": [ { "id": "faction_base_mansion_c4" } ] + }, + { + "type": "recipe", + "result": "faction_base_mansion_c5", + "description": "Survey mansion's kitchen.", + "category": "CC_BUILDING", + "subcategory": "CSC_BUILDING_BASES", + "skill_used": "fabrication", + "autolearn": false, + "never_learn": true, + "construction_blueprint": "faction_base_mansion_c5", + "blueprint_name": "kitchen survey", + "time": "180 m", + "blueprint_requires": [ { "id": "not_an_upgrade" } ], + "blueprint_provides": [ { "id": "faction_base_mansion_c5" }, { "id": "kitchen" }, { "id": "kitchen_recipes_1" }, { "id": "kitchen_recipes_2" }, { "id": "kitchen_recipes_3" }, { "id": "saltworks_recipes_1" }, { "id": "saltworks_recipes_2" }, { "id": "saltworks_recipes_3" } ] + } +] diff --git a/data/json/recipes/basecamps/recipe_groups.json b/data/json/recipes/basecamps/recipe_groups.json index 44399021cf29b..2140baa817029 100644 --- a/data/json/recipes/basecamps/recipe_groups.json +++ b/data/json/recipes/basecamps/recipe_groups.json @@ -24,7 +24,27 @@ "id": "faction_base_shelter_2_0", "description": "Central Stairs Evac Shelter Base", "om_terrains": [ "shelter_2", "shelter_2_vandal" ] - } + }, + { + "id": "faction_base_mansion_+1_0", + "description": "Mansion Fountain Garden Base", + "om_terrains": [ "mansion_+1" ] + }, + { + "id": "faction_base_mansion_+2_0", + "description": "Mansion Dance Floor Room Base", + "om_terrains": [ "mansion_+2" ] + }, + { + "id": "faction_base_mansion_+3_0", + "description": "Mansion Basketball Room Base", + "om_terrains": [ "mansion_+3" ] + }, + { + "id": "faction_base_mansion_+4_0", + "description": "Mansion Garden With Columns Base", + "om_terrains": [ "mansion_+4" ] + } ] }, { @@ -38,7 +58,63 @@ { "id": "faction_base_livestock_0", "description": "Livestock Area", "om_terrains": [ "field" ] }, { "id": "faction_base_storehouse_0", "description": "Central Storage Building", "om_terrains": [ "field" ] }, { "id": "faction_base_saltworks_0", "description": "Saltworks Area", "om_terrains": [ "field" ] }, - { "id": "faction_base_workshop_0", "description": "Fabrication Workshop", "om_terrains": [ "field" ] } + { "id": "faction_base_workshop_0", "description": "Fabrication Workshop", "om_terrains": [ "field" ] }, + { "id": "faction_base_mansion_e1", + "description": "Mansion's Entrance", + "om_terrains": [ "mansion_e1" ] + }, + { "id": "faction_base_mansion_e2", + "description": "Mansion's Entrance", + "om_terrains": [ "mansion_e2" ] + }, + { "id": "faction_base_mansion_t1", + "description": "Mansion's Swimming Pool", + "om_terrains": [ "mansion_t1" ] + }, + { "id": "faction_base_mansion_t2", + "description": "Mansion's Bedrooms", + "om_terrains": [ "mansion_t2" ] + }, + { "id": "faction_base_mansion_t3", + "description": "Mansion's ???", + "om_terrains": [ "mansion_t3" ] + }, + { "id": "faction_base_mansion_t4", + "description": "Mansion's Kitchen", + "om_terrains": [ "mansion_t4" ] + }, + { "id": "faction_base_mansion_t5", + "description": "Mansion's Library", + "om_terrains": [ "mansion_t5" ] + }, + { "id": "faction_base_mansion_t6", + "description": "Mansion's Bedroom", + "om_terrains": [ "mansion_t6" ] + }, + { "id": "faction_base_mansion_t7", + "description": "Mansion's Living Rooms", + "om_terrains": [ "mansion_t7" ] + }, + { "id": "faction_base_mansion_c1", + "description": "Mansion's Swimming Pool", + "om_terrains": [ "mansion_c1" ] + }, + { "id": "faction_base_mansion_c2", + "description": "Mansion's Bar", + "om_terrains": [ "mansion_c2" ] + }, + { "id": "faction_base_mansion_c3", + "description": "Mansion's Living Rooms", + "om_terrains": [ "mansion_c3" ] + }, + { "id": "faction_base_mansion_c4", + "description": "Mansion's Bedroom", + "om_terrains": [ "mansion_c4" ] + }, + { "id": "faction_base_mansion_c5", + "description": "Mansion's Kitchen", + "om_terrains": [ "mansion_c5" ] + } ] }, { From a369270925e280d0128dc1aa9e66098d340a0704 Mon Sep 17 00:00:00 2001 From: krulunio Date: Thu, 20 May 2021 11:24:01 +0200 Subject: [PATCH 213/453] Add radio tower basecamp and related stuff This adds: 1. radio tower basecamp (2 variants; allows using bottom of tower as base for shack, for faster building and less materials than normally) 2. unique upgrade: repairing whole tower (requires ~4-8 times more materials and time than building radio in field camp, fabrication 3, computer 4 and electronics 8 skills; gives access to hacking recipes) 3. hacking recipes (allows "downloading" sd-cards, various software and satelitte map; divided into 3 groups: general, science and satellite, in case someone adds i.e. lab basecamp, with only science recipes) 4. satellite map (reveals fields, forests, roads, lakes and rivers; instead of showing where is specific type of building, it shows where is any building) --- data/json/items/book/maps.json | 23 + .../fbmc_radio_tower_beds.json | 202 +++++ .../fbmc_radio_tower_common.json | 276 +++++++ .../fbmc_radio_tower_log.json | 80 ++ .../fbmc_radio_tower_metal.json | 80 ++ .../fbmc_radio_tower_migo_resin.json | 106 +++ .../fbmc_radio_tower_rammed_earth.json | 80 ++ .../fbmc_radio_tower_rock.json | 80 ++ .../fbmc_radio_tower_wad.json | 80 ++ .../fbmc_radio_tower_wood.json | 106 +++ .../json/mapgen/basecamps/modular_shacks.json | 764 ++++++++++++++++++ .../recipe_modular_radio_tower_beds.json | 282 +++++++ .../recipe_modular_radio_tower_common.json | 229 ++++++ .../recipe_modular_radio_tower_log.json | 114 +++ .../recipe_modular_radio_tower_metal.json | 114 +++ ...recipe_modular_radio_tower_migo_resin.json | 153 ++++ ...cipe_modular_radio_tower_rammed_earth.json | 114 +++ .../recipe_modular_radio_tower_rock.json | 114 +++ .../recipe_modular_radio_tower_wad.json | 114 +++ .../recipe_modular_radio_tower_wood.json | 156 ++++ .../json/recipes/basecamps/recipe_groups.json | 40 +- data/json/recipes/recipe_companion.json | 116 +++ 22 files changed, 3422 insertions(+), 1 deletion(-) create mode 100644 data/json/mapgen/basecamps/fbmc_radio_tower/fbmc_radio_tower_beds.json create mode 100644 data/json/mapgen/basecamps/fbmc_radio_tower/fbmc_radio_tower_common.json create mode 100644 data/json/mapgen/basecamps/fbmc_radio_tower/fbmc_radio_tower_log.json create mode 100644 data/json/mapgen/basecamps/fbmc_radio_tower/fbmc_radio_tower_metal.json create mode 100644 data/json/mapgen/basecamps/fbmc_radio_tower/fbmc_radio_tower_migo_resin.json create mode 100644 data/json/mapgen/basecamps/fbmc_radio_tower/fbmc_radio_tower_rammed_earth.json create mode 100644 data/json/mapgen/basecamps/fbmc_radio_tower/fbmc_radio_tower_rock.json create mode 100644 data/json/mapgen/basecamps/fbmc_radio_tower/fbmc_radio_tower_wad.json create mode 100644 data/json/mapgen/basecamps/fbmc_radio_tower/fbmc_radio_tower_wood.json create mode 100644 data/json/mapgen/basecamps/modular_shacks.json create mode 100644 data/json/recipes/basecamps/fbmc_radio_tower/recipe_modular_radio_tower_beds.json create mode 100644 data/json/recipes/basecamps/fbmc_radio_tower/recipe_modular_radio_tower_common.json create mode 100644 data/json/recipes/basecamps/fbmc_radio_tower/recipe_modular_radio_tower_log.json create mode 100644 data/json/recipes/basecamps/fbmc_radio_tower/recipe_modular_radio_tower_metal.json create mode 100644 data/json/recipes/basecamps/fbmc_radio_tower/recipe_modular_radio_tower_migo_resin.json create mode 100644 data/json/recipes/basecamps/fbmc_radio_tower/recipe_modular_radio_tower_rammed_earth.json create mode 100644 data/json/recipes/basecamps/fbmc_radio_tower/recipe_modular_radio_tower_rock.json create mode 100644 data/json/recipes/basecamps/fbmc_radio_tower/recipe_modular_radio_tower_wad.json create mode 100644 data/json/recipes/basecamps/fbmc_radio_tower/recipe_modular_radio_tower_wood.json diff --git a/data/json/items/book/maps.json b/data/json/items/book/maps.json index 0217ae0e222a4..48eb819c90fc5 100644 --- a/data/json/items/book/maps.json +++ b/data/json/items/book/maps.json @@ -165,5 +165,28 @@ ], "message": "You add roads and restaurants to your map." } + }, + { + "id": "satellitemap", + "copy-from": "abstractmap", + "type": "GENERIC", + "name": { "str": "satellite map" }, + "description": "This is a printed satellite map of the local area. Due to it's low quality and lack of map legend, you are unable to recognise most buildings. Using it will add terrain and roads to your map.", + "color": "gray", + "use_action": { + "type": "reveal_map", + "radius": 90, + "terrain": [ + "hiway", + "road", + "bridge", + "field", + "swamp", + "forest", + "lake", + "river" + ], + "message": "You add terrain and roads to your map." + } } ] diff --git a/data/json/mapgen/basecamps/fbmc_radio_tower/fbmc_radio_tower_beds.json b/data/json/mapgen/basecamps/fbmc_radio_tower/fbmc_radio_tower_beds.json new file mode 100644 index 0000000000000..245d0fcddb5a5 --- /dev/null +++ b/data/json/mapgen/basecamps/fbmc_radio_tower/fbmc_radio_tower_beds.json @@ -0,0 +1,202 @@ +[ + { + "type": "mapgen", + "update_mapgen_id": "fbmc_radio_tower_mattress_beds_controls_room", + "method": "json", + "object": { "place_nested": [ + { "chunks": [ "fbmc_mattress_bed_horizontal" ], "x": 15, "y": 12 }, + { "chunks": [ "fbmc_mattress_bed_horizontal" ], "x": 15, "y": 15 } + ] + } + }, + { + "type": "mapgen", + "update_mapgen_id": "fbmc_radio_tower_mattress_beds_0", + "method": "json", + "object": { "place_nested": [ + { "chunks": [ "fbmc_mattress_bed_vertical" ], "x": 11, "y": 4 }, + { "chunks": [ "fbmc_mattress_bed_vertical" ], "x": 14, "y": 4 } + ] + } + }, + { + "type": "mapgen", + "update_mapgen_id": "fbmc_radio_tower_mattress_beds_1", + "method": "json", + "object": { "place_nested": [ + { "chunks": [ "fbmc_mattress_bed_vertical" ], "x": 16, "y": 4 }, + { "chunks": [ "fbmc_mattress_bed_vertical" ], "x": 19, "y": 4 } + ] + } + }, + { + "type": "mapgen", + "update_mapgen_id": "fbmc_radio_tower_mattress_beds_2", + "method": "json", + "object": { "place_nested": [ + { "chunks": [ "fbmc_mattress_bed_vertical" ], "x": 2, "y": 18 }, + { "chunks": [ "fbmc_mattress_bed_vertical" ], "x": 5, "y": 18 } + ] + } + }, + { + "type": "mapgen", + "update_mapgen_id": "fbmc_radio_tower_mattress_beds_3", + "method": "json", + "object": { "place_nested": [ + { "chunks": [ "fbmc_mattress_bed_vertical" ], "x": 7, "y": 18 }, + { "chunks": [ "fbmc_mattress_bed_vertical" ], "x": 10, "y": 18 } + ] + } + }, + { + "type": "mapgen", + "update_mapgen_id": "fbmc_radio_tower_mattress_beds_4", + "method": "json", + "object": { "place_nested": [ + { "chunks": [ "fbmc_mattress_bed_vertical" ], "x": 12, "y": 18 }, + { "chunks": [ "fbmc_mattress_bed_vertical" ], "x": 15, "y": 18 } + ] + } + }, + { + "type": "mapgen", + "update_mapgen_id": "fbmc_radio_tower_mattress_beds_5", + "method": "json", + "object": { "place_nested": [ + { "chunks": [ "fbmc_mattress_bed_vertical" ], "x": 17, "y": 18 }, + { "chunks": [ "fbmc_mattress_bed_vertical" ], "x": 20, "y": 18 } + ] + } + }, + { + "type": "mapgen", + "update_mapgen_id": "fbmc_radio_tower_mattress_beds_6", + "method": "json", + "object": { "place_nested": [ + { "chunks": [ "fbmc_mattress_bed_horizontal" ], "x": 17, "y": 17 }, + { "chunks": [ "fbmc_mattress_bed_horizontal" ], "x": 17, "y": 20 } + ] + } + }, + { + "type": "mapgen", + "update_mapgen_id": "fbmc_radio_tower_mattress_beds_7", + "method": "json", + "object": { "place_nested": [ + { "chunks": [ "fbmc_mattress_bed_horizontal" ], "x": 4, "y": 11 }, + { "chunks": [ "fbmc_mattress_bed_horizontal" ], "x": 4, "y": 14 } + ] + } + }, + { + "type": "mapgen", + "update_mapgen_id": "fbmc_radio_tower_mattress_beds_8", + "method": "json", + "object": { "place_nested": [ + { "chunks": [ "fbmc_mattress_bed_horizontal" ], "x": 4, "y": 16 }, + { "chunks": [ "fbmc_mattress_bed_horizontal" ], "x": 4, "y": 19 } + ] + } + }, + { + "type": "mapgen", + "update_mapgen_id": "fbmc_radio_tower_straw_beds_controls_room", + "method": "json", + "object": { "place_nested": [ + { "chunks": [ "fbmc_straw_bed_horizontal" ], "x": 15, "y": 12 }, + { "chunks": [ "fbmc_straw_bed_horizontal" ], "x": 15, "y": 15 } + ] + } + }, + { + "type": "mapgen", + "update_mapgen_id": "fbmc_radio_tower_straw_beds_0", + "method": "json", + "object": { "place_nested": [ + { "chunks": [ "fbmc_straw_bed_vertical" ], "x": 11, "y": 4 }, + { "chunks": [ "fbmc_straw_bed_vertical" ], "x": 14, "y": 4 } + ] + } + }, + { + "type": "mapgen", + "update_mapgen_id": "fbmc_radio_tower_straw_beds_1", + "method": "json", + "object": { "place_nested": [ + { "chunks": [ "fbmc_straw_bed_vertical" ], "x": 16, "y": 4 }, + { "chunks": [ "fbmc_straw_bed_vertical" ], "x": 19, "y": 4 } + ] + } + }, + { + "type": "mapgen", + "update_mapgen_id": "fbmc_radio_tower_straw_beds_2", + "method": "json", + "object": { "place_nested": [ + { "chunks": [ "fbmc_straw_bed_vertical" ], "x": 2, "y": 18 }, + { "chunks": [ "fbmc_straw_bed_vertical" ], "x": 5, "y": 18 } + ] + } + }, + { + "type": "mapgen", + "update_mapgen_id": "fbmc_radio_tower_straw_beds_3", + "method": "json", + "object": { "place_nested": [ + { "chunks": [ "fbmc_straw_bed_vertical" ], "x": 7, "y": 18 }, + { "chunks": [ "fbmc_straw_bed_vertical" ], "x": 10, "y": 18 } + ] + } + }, + { + "type": "mapgen", + "update_mapgen_id": "fbmc_radio_tower_straw_beds_4", + "method": "json", + "object": { "place_nested": [ + { "chunks": [ "fbmc_straw_bed_vertical" ], "x": 12, "y": 18 }, + { "chunks": [ "fbmc_straw_bed_vertical" ], "x": 15, "y": 18 } + ] + } + }, + { + "type": "mapgen", + "update_mapgen_id": "fbmc_radio_tower_straw_beds_5", + "method": "json", + "object": { "place_nested": [ + { "chunks": [ "fbmc_straw_bed_vertical" ], "x": 17, "y": 18 }, + { "chunks": [ "fbmc_straw_bed_vertical" ], "x": 20, "y": 18 } + ] + } + }, + { + "type": "mapgen", + "update_mapgen_id": "fbmc_radio_tower_straw_beds_6", + "method": "json", + "object": { "place_nested": [ + { "chunks": [ "fbmc_straw_bed_horizontal" ], "x": 17, "y": 17 }, + { "chunks": [ "fbmc_straw_bed_horizontal" ], "x": 17, "y": 20 } + ] + } + }, + { + "type": "mapgen", + "update_mapgen_id": "fbmc_radio_tower_straw_beds_7", + "method": "json", + "object": { "place_nested": [ + { "chunks": [ "fbmc_straw_bed_horizontal" ], "x": 4, "y": 11 }, + { "chunks": [ "fbmc_straw_bed_horizontal" ], "x": 4, "y": 14 } + ] + } + }, + { + "type": "mapgen", + "update_mapgen_id": "fbmc_radio_tower_straw_beds_8", + "method": "json", + "object": { "place_nested": [ + { "chunks": [ "fbmc_straw_bed_horizontal" ], "x": 4, "y": 16 }, + { "chunks": [ "fbmc_straw_bed_horizontal" ], "x": 4, "y": 19 } + ] + } + } +] \ No newline at end of file diff --git a/data/json/mapgen/basecamps/fbmc_radio_tower/fbmc_radio_tower_common.json b/data/json/mapgen/basecamps/fbmc_radio_tower/fbmc_radio_tower_common.json new file mode 100644 index 0000000000000..c44e8abf8fc50 --- /dev/null +++ b/data/json/mapgen/basecamps/fbmc_radio_tower/fbmc_radio_tower_common.json @@ -0,0 +1,276 @@ +[ + { + "type": "mapgen", + "update_mapgen_id": "fbmc_radio_tower_0", + "method": "json", + "object": { + "set": [ + { "point": "furniture", "id": "f_bulletin", "x": 9, "y": 8 } + ] + } + }, + { + "type": "mapgen", + "update_mapgen_id": "fbmc_radio_tower_1", + "method": "json", + "object": { + "set": [ + { "point": "furniture", "id": "f_bulletin", "x": 9, "y": 8 } + ] + } + }, + { + "type": "mapgen", + "update_mapgen_id": "fbmc_radio_tower_controls_room_wood", + "method": "json", + "object": { + "set": [ + { "point": "terrain", "id": "t_wall_wood", "x": 19, "y": 15 }, + { "point": "terrain", "id": "t_wall_wood", "x": 16, "y": 16 }, + { "point": "terrain", "id": "t_wall_wood", "x": 17, "y": 16 } + ] + } + }, + { + "type": "mapgen", + "update_mapgen_id": "fbmc_radio_tower_controls_room_migo_resin", + "method": "json", + "object": { + "set": [ + { "point": "terrain", "id": "t_wall_resin", "x": 19, "y": 15 }, + { "point": "terrain", "id": "t_wall_resin", "x": 16, "y": 16 }, + { "point": "terrain", "id": "t_wall_resin", "x": 17, "y": 16 } + ] + } + }, + { + "type": "mapgen", + "update_mapgen_id": "fbmc_radio_tower_fix_controls", + "method": "json", + "object": { + "set": [ + { "point": "furniture", "id": "f_null", "x": 0, "y": 0 } + ] + } + }, + { + "type": "mapgen", + "update_mapgen_id": "faction_base_radio_tower_fix_tower", + "method": "json", + "object": { + "set": [ + { "point": "furniture", "id": "f_null", "x": 0, "y": 0 } + ] + } + }, + { + "type": "mapgen", + "update_mapgen_id": "fbmc_radio_tower_root_cellar", + "method": "json", + "object": { + "set": [ + { "point": "terrain", "id": "t_rootcellar", "x": 19, "y": 9 } + ] + } + }, + { + "type": "mapgen", + "update_mapgen_id": "fbmc_radio_tower_water_well", + "method": "json", + "object": { + "set": [ + { "point": "terrain", "id": "t_water_pump", "x": 19, "y": 10 } + ] + } + }, + { + "type": "mapgen", + "nested_mapgen_id": "fbmc_radio_tower_0_prepalisade_nested", + "method": "json", + "object": { + "mapgensize": [ 24, 24 ], + "rows": [ + " ", + " ", + " ", + "pppppppppp ", + "p ", + "p ", + "p ", + "p ", + "p p ", + "p p ", + "p p ", + "p p ", + "p p ", + "p p ", + "p p ", + "p ", + " ", + " ", + " ", + " ", + " ", + " ", + " ", + " " + ], + "terrain": { + "p": "t_pit" + } + } + }, + { + "type": "mapgen", + "nested_mapgen_id": "fbmc_radio_tower_1_prepalisade_nested", + "method": "json", + "object": { + "mapgensize": [ 24, 24 ], + "rows": [ + "ppppppppppp ", + "p p ", + "p p ", + "p ", + "p ", + "p ", + "p ", + "p ", + "p ", + "p p ", + "p p ", + "p p ", + "ppp ", + " ", + " ", + " ", + " ", + " ", + " ", + " ", + " ", + " pppppp ", + " ", + " " + ], + "terrain": { + "p": "t_pit" + } + } + }, + { + "type": "mapgen", + "nested_mapgen_id": "fbmc_radio_tower_0_palisade_nested", + "method": "json", + "object": { + "mapgensize": [ 24, 24 ], + "rows": [ + " ", + " ", + " ", + "ppgggggggp ", + "p r ", + "p ", + "p ", + "p ", + "p p ", + "p p ", + "p p ", + "p p ", + "pr p ", + "g p ", + "g p ", + "p ", + " ", + " ", + " ", + " ", + " ", + " ", + " ", + " " + ], + "terrain": { + "p": "t_palisade", + "g": "t_palisade_gate", + "r": "t_palisade_pulley" + } + } + }, + { + "type": "mapgen", + "nested_mapgen_id": "fbmc_radio_tower_1_palisade_nested", + "method": "json", + "object": { + "mapgensize": [ 24, 24 ], + "rows": [ + "ppgggggggpp ", + "p rp ", + "p p ", + "p ", + "p ", + "p ", + "p ", + "p ", + "p ", + "p p ", + "p p ", + "p p ", + "ppp ", + " ", + " ", + " ", + " ", + " ", + " ", + " ", + " r ", + " ppgggp ", + " ", + " " + ], + "terrain": { + "p": "t_palisade", + "g": "t_palisade_gate", + "r": "t_palisade_pulley" + } + } + }, + { + "type": "mapgen", + "update_mapgen_id": "fbmc_radio_tower_0_prepalisade", + "method": "json", + "object": { "place_nested": [ + { "chunks": [ "fbmc_radio_tower_0_prepalisade_nested" ], "x": 0, "y": 0 } + ], + "place_items": [ { "x": 4, "y": 9, "item": "digging_soil_loam_50L", "chance": 99, "repeat": 870 } ] + } + }, + { + "type": "mapgen", + "update_mapgen_id": "fbmc_radio_tower_1_prepalisade", + "method": "json", + "object": { "place_nested": [ + { "chunks": [ "fbmc_radio_tower_1_prepalisade_nested" ], "x": 0, "y": 0 } + ], + "place_items": [ { "x": 4, "y": 9, "item": "digging_soil_loam_50L", "chance": 99, "repeat": 1080 } ] + } + }, + { + "type": "mapgen", + "update_mapgen_id": "fbmc_radio_tower_0_palisade", + "method": "json", + "object": { "place_nested": [ + { "chunks": [ "fbmc_radio_tower_0_palisade_nested" ], "x": 0, "y": 0 } + ] + } + }, + { + "type": "mapgen", + "update_mapgen_id": "fbmc_radio_tower_1_palisade", + "method": "json", + "object": { "place_nested": [ + { "chunks": [ "fbmc_radio_tower_1_palisade_nested" ], "x": 0, "y": 0 } + ] + } + } +] \ No newline at end of file diff --git a/data/json/mapgen/basecamps/fbmc_radio_tower/fbmc_radio_tower_log.json b/data/json/mapgen/basecamps/fbmc_radio_tower/fbmc_radio_tower_log.json new file mode 100644 index 0000000000000..3264b72d2a481 --- /dev/null +++ b/data/json/mapgen/basecamps/fbmc_radio_tower/fbmc_radio_tower_log.json @@ -0,0 +1,80 @@ +[ + { + "type": "mapgen", + "update_mapgen_id": "fbmc_radio_tower_log_shack_1", + "method": "json", + "object": { "place_nested": [ + { "chunks": [ "fbmc_log_shack_north" ], "x": 16, "y": 3 } + ] + } + }, + { + "type": "mapgen", + "update_mapgen_id": "fbmc_radio_tower_log_shack_2", + "method": "json", + "object": { "place_nested": [ + { "chunks": [ "fbmc_log_wall_vertical" ], "x": 1, "y": 15 }, + { "chunks": [ "fbmc_log_shack_south" ], "x": 2, "y": 15 } + ] + } + }, + { + "type": "mapgen", + "update_mapgen_id": "fbmc_radio_tower_log_shack_3", + "method": "json", + "object": { "place_nested": [ + { "chunks": [ "fbmc_log_shack_south" ], "x": 7, "y": 15 } + ] + } + }, + { + "type": "mapgen", + "update_mapgen_id": "fbmc_radio_tower_log_shack_4", + "method": "json", + "object": { "place_nested": [ + { "chunks": [ "fbmc_log_shack_south" ], "x": 12, "y": 15 } + ] + } + }, + { + "type": "mapgen", + "update_mapgen_id": "fbmc_radio_tower_log_shack_5", + "method": "json", + "object": { "place_nested": [ + { "chunks": [ "fbmc_log_shack_south" ], "x": 17, "y": 15 } + ] + } + }, + { + "type": "mapgen", + "update_mapgen_id": "fbmc_radio_tower_log_shack_6", + "method": "json", + "object": { "place_nested": [ + { "chunks": [ "fbmc_log_shack_west" ], "x": 14, "y": 17 } + ] + } + }, + { + "type": "mapgen", + "update_mapgen_id": "fbmc_radio_tower_log_shack_7", + "method": "json", + "object": { "place_nested": [ + { "chunks": [ "fbmc_log_wall_horizontal" ], "x": 3, "y": 10 }, + { "chunks": [ "fbmc_log_shack_east" ], "x": 3, "y": 11 } + ], + "set": [ + { "point": "terrain", "id": "t_dirt", "x": 9, "y": 13 }, + { "point": "terrain", "id": "t_dirt", "x": 11, "y": 16 } + ] + } + }, + { + "type": "mapgen", + "update_mapgen_id": "fbmc_radio_tower_log_shack_8", + "method": "json", + "object": { "place_nested": [ + { "chunks": [ "fbmc_log_shack_east" ], "x": 3, "y": 16 } + ] + } + } +] \ No newline at end of file diff --git a/data/json/mapgen/basecamps/fbmc_radio_tower/fbmc_radio_tower_metal.json b/data/json/mapgen/basecamps/fbmc_radio_tower/fbmc_radio_tower_metal.json new file mode 100644 index 0000000000000..cabc9d56a3e4b --- /dev/null +++ b/data/json/mapgen/basecamps/fbmc_radio_tower/fbmc_radio_tower_metal.json @@ -0,0 +1,80 @@ +[ + { + "type": "mapgen", + "update_mapgen_id": "fbmc_radio_tower_metal_shack_1", + "method": "json", + "object": { "place_nested": [ + { "chunks": [ "fbmc_metal_shack_north" ], "x": 16, "y": 3 } + ] + } + }, + { + "type": "mapgen", + "update_mapgen_id": "fbmc_radio_tower_metal_shack_2", + "method": "json", + "object": { "place_nested": [ + { "chunks": [ "fbmc_metal_wall_vertical" ], "x": 1, "y": 15 }, + { "chunks": [ "fbmc_metal_shack_south" ], "x": 2, "y": 15 } + ] + } + }, + { + "type": "mapgen", + "update_mapgen_id": "fbmc_radio_tower_metal_shack_3", + "method": "json", + "object": { "place_nested": [ + { "chunks": [ "fbmc_metal_shack_south" ], "x": 7, "y": 15 } + ] + } + }, + { + "type": "mapgen", + "update_mapgen_id": "fbmc_radio_tower_metal_shack_4", + "method": "json", + "object": { "place_nested": [ + { "chunks": [ "fbmc_metal_shack_south" ], "x": 12, "y": 15 } + ] + } + }, + { + "type": "mapgen", + "update_mapgen_id": "fbmc_radio_tower_metal_shack_5", + "method": "json", + "object": { "place_nested": [ + { "chunks": [ "fbmc_metal_shack_south" ], "x": 17, "y": 15 } + ] + } + }, + { + "type": "mapgen", + "update_mapgen_id": "fbmc_radio_tower_metal_shack_6", + "method": "json", + "object": { "place_nested": [ + { "chunks": [ "fbmc_metal_shack_west" ], "x": 14, "y": 17 } + ] + } + }, + { + "type": "mapgen", + "update_mapgen_id": "fbmc_radio_tower_metal_shack_7", + "method": "json", + "object": { "place_nested": [ + { "chunks": [ "fbmc_metal_wall_horizontal" ], "x": 3, "y": 10 }, + { "chunks": [ "fbmc_metal_shack_east" ], "x": 3, "y": 11 } + ], + "set": [ + { "point": "terrain", "id": "t_dirt", "x": 9, "y": 13 }, + { "point": "terrain", "id": "t_dirt", "x": 11, "y": 16 } + ] + } + }, + { + "type": "mapgen", + "update_mapgen_id": "fbmc_radio_tower_metal_shack_8", + "method": "json", + "object": { "place_nested": [ + { "chunks": [ "fbmc_metal_shack_east" ], "x": 3, "y": 16 } + ] + } + } +] \ No newline at end of file diff --git a/data/json/mapgen/basecamps/fbmc_radio_tower/fbmc_radio_tower_migo_resin.json b/data/json/mapgen/basecamps/fbmc_radio_tower/fbmc_radio_tower_migo_resin.json new file mode 100644 index 0000000000000..fd2dcc807a607 --- /dev/null +++ b/data/json/mapgen/basecamps/fbmc_radio_tower/fbmc_radio_tower_migo_resin.json @@ -0,0 +1,106 @@ +[ + { + "type": "mapgen", + "method": "json", + "nested_mapgen_id": "fbmc_radio_tower_migo_resin_shack", + "object": { + "mapgensize": [ 6, 6 ], + "rows": [ + "wwwwww", + "w....w", + "w....w", + "w....w", + "w ...w", + "ww+vww" + ], + "palettes": [ "fbmh_migo_resin_palette" ] + } + }, + { + "type": "mapgen", + "update_mapgen_id": "fbmc_radio_tower_migo_resin_shack_0", + "method": "json", + "object": { "place_nested": [ + { "chunks": [ "fbmc_radio_tower_migo_resin_shack" ], "x": 10, "y": 3 } + ] + } + }, + { + "type": "mapgen", + "update_mapgen_id": "fbmc_radio_tower_migo_resin_shack_1", + "method": "json", + "object": { "place_nested": [ + { "chunks": [ "fbmc_migo_resin_shack_north" ], "x": 16, "y": 3 } + ] + } + }, + { + "type": "mapgen", + "update_mapgen_id": "fbmc_radio_tower_migo_resin_shack_2", + "method": "json", + "object": { "place_nested": [ + { "chunks": [ "fbmc_migo_resin_wall_vertical" ], "x": 1, "y": 15 }, + { "chunks": [ "fbmc_migo_resin_shack_south" ], "x": 2, "y": 15 } + ] + } + }, + { + "type": "mapgen", + "update_mapgen_id": "fbmc_radio_tower_migo_resin_shack_3", + "method": "json", + "object": { "place_nested": [ + { "chunks": [ "fbmc_migo_resin_shack_south" ], "x": 7, "y": 15 } + ] + } + }, + { + "type": "mapgen", + "update_mapgen_id": "fbmc_radio_tower_migo_resin_shack_4", + "method": "json", + "object": { "place_nested": [ + { "chunks": [ "fbmc_migo_resin_shack_south" ], "x": 12, "y": 15 } + ] + } + }, + { + "type": "mapgen", + "update_mapgen_id": "fbmc_radio_tower_migo_resin_shack_5", + "method": "json", + "object": { "place_nested": [ + { "chunks": [ "fbmc_migo_resin_shack_south" ], "x": 17, "y": 15 } + ] + } + }, + { + "type": "mapgen", + "update_mapgen_id": "fbmc_radio_tower_migo_resin_shack_6", + "method": "json", + "object": { "place_nested": [ + { "chunks": [ "fbmc_migo_resin_shack_west" ], "x": 14, "y": 17 } + ] + } + }, + { + "type": "mapgen", + "update_mapgen_id": "fbmc_radio_tower_migo_resin_shack_7", + "method": "json", + "object": { "place_nested": [ + { "chunks": [ "fbmc_migo_resin_wall_horizontal" ], "x": 3, "y": 10 }, + { "chunks": [ "fbmc_migo_resin_shack_east" ], "x": 3, "y": 11 } + ], + "set": [ + { "point": "terrain", "id": "t_dirt", "x": 9, "y": 13 }, + { "point": "terrain", "id": "t_dirt", "x": 11, "y": 16 } + ] + } + }, + { + "type": "mapgen", + "update_mapgen_id": "fbmc_radio_tower_migo_resin_shack_8", + "method": "json", + "object": { "place_nested": [ + { "chunks": [ "fbmc_migo_resin_shack_east" ], "x": 3, "y": 16 } + ] + } + } +] \ No newline at end of file diff --git a/data/json/mapgen/basecamps/fbmc_radio_tower/fbmc_radio_tower_rammed_earth.json b/data/json/mapgen/basecamps/fbmc_radio_tower/fbmc_radio_tower_rammed_earth.json new file mode 100644 index 0000000000000..79e63a3935373 --- /dev/null +++ b/data/json/mapgen/basecamps/fbmc_radio_tower/fbmc_radio_tower_rammed_earth.json @@ -0,0 +1,80 @@ +[ + { + "type": "mapgen", + "update_mapgen_id": "fbmc_radio_tower_rammed_earth_shack_1", + "method": "json", + "object": { "place_nested": [ + { "chunks": [ "fbmc_rammed_earth_shack_north" ], "x": 16, "y": 3 } + ] + } + }, + { + "type": "mapgen", + "update_mapgen_id": "fbmc_radio_tower_rammed_earth_shack_2", + "method": "json", + "object": { "place_nested": [ + { "chunks": [ "fbmc_rammed_earth_wall_vertical" ], "x": 1, "y": 15 }, + { "chunks": [ "fbmc_rammed_earth_shack_south" ], "x": 2, "y": 15 } + ] + } + }, + { + "type": "mapgen", + "update_mapgen_id": "fbmc_radio_tower_rammed_earth_shack_3", + "method": "json", + "object": { "place_nested": [ + { "chunks": [ "fbmc_rammed_earth_shack_south" ], "x": 7, "y": 15 } + ] + } + }, + { + "type": "mapgen", + "update_mapgen_id": "fbmc_radio_tower_rammed_earth_shack_4", + "method": "json", + "object": { "place_nested": [ + { "chunks": [ "fbmc_rammed_earth_shack_south" ], "x": 12, "y": 15 } + ] + } + }, + { + "type": "mapgen", + "update_mapgen_id": "fbmc_radio_tower_rammed_earth_shack_5", + "method": "json", + "object": { "place_nested": [ + { "chunks": [ "fbmc_rammed_earth_shack_south" ], "x": 17, "y": 15 } + ] + } + }, + { + "type": "mapgen", + "update_mapgen_id": "fbmc_radio_tower_rammed_earth_shack_6", + "method": "json", + "object": { "place_nested": [ + { "chunks": [ "fbmc_rammed_earth_shack_west" ], "x": 14, "y": 17 } + ] + } + }, + { + "type": "mapgen", + "update_mapgen_id": "fbmc_radio_tower_rammed_earth_shack_7", + "method": "json", + "object": { "place_nested": [ + { "chunks": [ "fbmc_rammed_earth_wall_horizontal" ], "x": 3, "y": 10 }, + { "chunks": [ "fbmc_rammed_earth_shack_east" ], "x": 3, "y": 11 } + ], + "set": [ + { "point": "terrain", "id": "t_dirt", "x": 9, "y": 13 }, + { "point": "terrain", "id": "t_dirt", "x": 11, "y": 16 } + ] + } + }, + { + "type": "mapgen", + "update_mapgen_id": "fbmc_radio_tower_rammed_earth_shack_8", + "method": "json", + "object": { "place_nested": [ + { "chunks": [ "fbmc_rammed_earth_shack_east" ], "x": 3, "y": 16 } + ] + } + } +] \ No newline at end of file diff --git a/data/json/mapgen/basecamps/fbmc_radio_tower/fbmc_radio_tower_rock.json b/data/json/mapgen/basecamps/fbmc_radio_tower/fbmc_radio_tower_rock.json new file mode 100644 index 0000000000000..04421a60520ea --- /dev/null +++ b/data/json/mapgen/basecamps/fbmc_radio_tower/fbmc_radio_tower_rock.json @@ -0,0 +1,80 @@ +[ + { + "type": "mapgen", + "update_mapgen_id": "fbmc_radio_tower_rock_shack_1", + "method": "json", + "object": { "place_nested": [ + { "chunks": [ "fbmc_rock_shack_north" ], "x": 16, "y": 3 } + ] + } + }, + { + "type": "mapgen", + "update_mapgen_id": "fbmc_radio_tower_rock_shack_2", + "method": "json", + "object": { "place_nested": [ + { "chunks": [ "fbmc_rock_wall_vertical" ], "x": 1, "y": 15 }, + { "chunks": [ "fbmc_rock_shack_south" ], "x": 2, "y": 15 } + ] + } + }, + { + "type": "mapgen", + "update_mapgen_id": "fbmc_radio_tower_rock_shack_3", + "method": "json", + "object": { "place_nested": [ + { "chunks": [ "fbmc_rock_shack_south" ], "x": 7, "y": 15 } + ] + } + }, + { + "type": "mapgen", + "update_mapgen_id": "fbmc_radio_tower_rock_shack_4", + "method": "json", + "object": { "place_nested": [ + { "chunks": [ "fbmc_rock_shack_south" ], "x": 12, "y": 15 } + ] + } + }, + { + "type": "mapgen", + "update_mapgen_id": "fbmc_radio_tower_rock_shack_5", + "method": "json", + "object": { "place_nested": [ + { "chunks": [ "fbmc_rock_shack_south" ], "x": 17, "y": 15 } + ] + } + }, + { + "type": "mapgen", + "update_mapgen_id": "fbmc_radio_tower_rock_shack_6", + "method": "json", + "object": { "place_nested": [ + { "chunks": [ "fbmc_rock_shack_west" ], "x": 14, "y": 17 } + ] + } + }, + { + "type": "mapgen", + "update_mapgen_id": "fbmc_radio_tower_rock_shack_7", + "method": "json", + "object": { "place_nested": [ + { "chunks": [ "fbmc_rock_wall_horizontal" ], "x": 3, "y": 10 }, + { "chunks": [ "fbmc_rock_shack_east" ], "x": 3, "y": 11 } + ], + "set": [ + { "point": "terrain", "id": "t_dirt", "x": 9, "y": 13 }, + { "point": "terrain", "id": "t_dirt", "x": 11, "y": 16 } + ] + } + }, + { + "type": "mapgen", + "update_mapgen_id": "fbmc_radio_tower_rock_shack_8", + "method": "json", + "object": { "place_nested": [ + { "chunks": [ "fbmc_rock_shack_east" ], "x": 3, "y": 16 } + ] + } + } +] \ No newline at end of file diff --git a/data/json/mapgen/basecamps/fbmc_radio_tower/fbmc_radio_tower_wad.json b/data/json/mapgen/basecamps/fbmc_radio_tower/fbmc_radio_tower_wad.json new file mode 100644 index 0000000000000..69cc4a5016673 --- /dev/null +++ b/data/json/mapgen/basecamps/fbmc_radio_tower/fbmc_radio_tower_wad.json @@ -0,0 +1,80 @@ +[ + { + "type": "mapgen", + "update_mapgen_id": "fbmc_radio_tower_wad_shack_1", + "method": "json", + "object": { "place_nested": [ + { "chunks": [ "fbmc_wad_shack_north" ], "x": 16, "y": 3 } + ] + } + }, + { + "type": "mapgen", + "update_mapgen_id": "fbmc_radio_tower_wad_shack_2", + "method": "json", + "object": { "place_nested": [ + { "chunks": [ "fbmc_wad_wall_vertical" ], "x": 1, "y": 15 }, + { "chunks": [ "fbmc_wad_shack_south" ], "x": 2, "y": 15 } + ] + } + }, + { + "type": "mapgen", + "update_mapgen_id": "fbmc_radio_tower_wad_shack_3", + "method": "json", + "object": { "place_nested": [ + { "chunks": [ "fbmc_wad_shack_south" ], "x": 7, "y": 15 } + ] + } + }, + { + "type": "mapgen", + "update_mapgen_id": "fbmc_radio_tower_wad_shack_4", + "method": "json", + "object": { "place_nested": [ + { "chunks": [ "fbmc_wad_shack_south" ], "x": 12, "y": 15 } + ] + } + }, + { + "type": "mapgen", + "update_mapgen_id": "fbmc_radio_tower_wad_shack_5", + "method": "json", + "object": { "place_nested": [ + { "chunks": [ "fbmc_wad_shack_south" ], "x": 17, "y": 15 } + ] + } + }, + { + "type": "mapgen", + "update_mapgen_id": "fbmc_radio_tower_wad_shack_6", + "method": "json", + "object": { "place_nested": [ + { "chunks": [ "fbmc_wad_shack_west" ], "x": 14, "y": 17 } + ] + } + }, + { + "type": "mapgen", + "update_mapgen_id": "fbmc_radio_tower_wad_shack_7", + "method": "json", + "object": { "place_nested": [ + { "chunks": [ "fbmc_wad_wall_horizontal" ], "x": 3, "y": 10 }, + { "chunks": [ "fbmc_wad_shack_east" ], "x": 3, "y": 11 } + ], + "set": [ + { "point": "terrain", "id": "t_dirt", "x": 9, "y": 13 }, + { "point": "terrain", "id": "t_dirt", "x": 11, "y": 16 } + ] + } + }, + { + "type": "mapgen", + "update_mapgen_id": "fbmc_radio_tower_wad_shack_8", + "method": "json", + "object": { "place_nested": [ + { "chunks": [ "fbmc_wad_shack_east" ], "x": 3, "y": 16 } + ] + } + } +] \ No newline at end of file diff --git a/data/json/mapgen/basecamps/fbmc_radio_tower/fbmc_radio_tower_wood.json b/data/json/mapgen/basecamps/fbmc_radio_tower/fbmc_radio_tower_wood.json new file mode 100644 index 0000000000000..002ee406bf94e --- /dev/null +++ b/data/json/mapgen/basecamps/fbmc_radio_tower/fbmc_radio_tower_wood.json @@ -0,0 +1,106 @@ +[ + { + "type": "mapgen", + "method": "json", + "nested_mapgen_id": "fbmc_radio_tower_wood_shack", + "object": { + "mapgensize": [ 6, 6 ], + "rows": [ + "wwwwww", + "w....w", + "w....w", + "w....w", + "w ...w", + "ww+vww" + ], + "palettes": [ "fbmh_wood_palette" ] + } + }, + { + "type": "mapgen", + "update_mapgen_id": "fbmc_radio_tower_wood_shack_0", + "method": "json", + "object": { "place_nested": [ + { "chunks": [ "fbmc_radio_tower_wood_shack" ], "x": 10, "y": 3 } + ] + } + }, + { + "type": "mapgen", + "update_mapgen_id": "fbmc_radio_tower_wood_shack_1", + "method": "json", + "object": { "place_nested": [ + { "chunks": [ "fbmc_wood_shack_north" ], "x": 16, "y": 3 } + ] + } + }, + { + "type": "mapgen", + "update_mapgen_id": "fbmc_radio_tower_wood_shack_2", + "method": "json", + "object": { "place_nested": [ + { "chunks": [ "fbmc_wood_wall_vertical" ], "x": 1, "y": 15 }, + { "chunks": [ "fbmc_wood_shack_south" ], "x": 2, "y": 15 } + ] + } + }, + { + "type": "mapgen", + "update_mapgen_id": "fbmc_radio_tower_wood_shack_3", + "method": "json", + "object": { "place_nested": [ + { "chunks": [ "fbmc_wood_shack_south" ], "x": 7, "y": 15 } + ] + } + }, + { + "type": "mapgen", + "update_mapgen_id": "fbmc_radio_tower_wood_shack_4", + "method": "json", + "object": { "place_nested": [ + { "chunks": [ "fbmc_wood_shack_south" ], "x": 12, "y": 15 } + ] + } + }, + { + "type": "mapgen", + "update_mapgen_id": "fbmc_radio_tower_wood_shack_5", + "method": "json", + "object": { "place_nested": [ + { "chunks": [ "fbmc_wood_shack_south" ], "x": 17, "y": 15 } + ] + } + }, + { + "type": "mapgen", + "update_mapgen_id": "fbmc_radio_tower_wood_shack_6", + "method": "json", + "object": { "place_nested": [ + { "chunks": [ "fbmc_wood_shack_west" ], "x": 14, "y": 17 } + ] + } + }, + { + "type": "mapgen", + "update_mapgen_id": "fbmc_radio_tower_wood_shack_7", + "method": "json", + "object": { "place_nested": [ + { "chunks": [ "fbmc_wood_wall_horizontal" ], "x": 3, "y": 10 }, + { "chunks": [ "fbmc_wood_shack_east" ], "x": 3, "y": 11 } + ], + "set": [ + { "point": "terrain", "id": "t_dirt", "x": 9, "y": 13 }, + { "point": "terrain", "id": "t_dirt", "x": 11, "y": 16 } + ] + } + }, + { + "type": "mapgen", + "update_mapgen_id": "fbmc_radio_tower_wood_shack_8", + "method": "json", + "object": { "place_nested": [ + { "chunks": [ "fbmc_wood_shack_east" ], "x": 3, "y": 16 } + ] + } + } +] \ No newline at end of file diff --git a/data/json/mapgen/basecamps/modular_shacks.json b/data/json/mapgen/basecamps/modular_shacks.json new file mode 100644 index 0000000000000..7086a52098f83 --- /dev/null +++ b/data/json/mapgen/basecamps/modular_shacks.json @@ -0,0 +1,764 @@ +[ + { + "type": "mapgen", + "method": "json", + "nested_mapgen_id": "fbmc_mattress_bed_horizontal", + "object": { + "mapgensize": [ 2, 2 ], + "set": [ + { "point": "furniture", "id": "f_bed", "x": 0, "y": 0 }, + { "point": "furniture", "id": "f_bed", "x": 1, "y": 0 } + ] + } + }, + { + "type": "mapgen", + "method": "json", + "nested_mapgen_id": "fbmc_mattress_bed_vertical", + "object": { + "mapgensize": [ 2, 2 ], + "set": [ + { "point": "furniture", "id": "f_bed", "x": 0, "y": 0 }, + { "point": "furniture", "id": "f_bed", "x": 0, "y": 1 } + ] + } + }, + { + "type": "mapgen", + "method": "json", + "nested_mapgen_id": "fbmc_straw_bed_horizontal", + "object": { + "mapgensize": [ 2, 2 ], + "set": [ + { "point": "furniture", "id": "f_straw_bed", "x": 0, "y": 0 }, + { "point": "furniture", "id": "f_straw_bed", "x": 1, "y": 0 } + ] + } + }, + { + "type": "mapgen", + "method": "json", + "nested_mapgen_id": "fbmc_straw_bed_vertical", + "object": { + "mapgensize": [ 2, 2 ], + "set": [ + { "point": "furniture", "id": "f_straw_bed", "x": 0, "y": 0 }, + { "point": "furniture", "id": "f_straw_bed", "x": 0, "y": 1 } + ] + } + }, + { + "type": "mapgen", + "method": "json", + "nested_mapgen_id": "fbmc_log_shack_north", + "object": { + "mapgensize": [ 6, 6 ], + "rows": [ + "wwwww ", + "....w ", + "....w ", + "....w ", + "....w ", + "w+vww " + ], + "palettes": [ "fbmh_log_palette" ] + } + }, + { + "type": "mapgen", + "method": "json", + "nested_mapgen_id": "fbmc_log_shack_south", + "object": { + "mapgensize": [ 6, 6 ], + "rows": [ + "w+vww ", + "....w ", + "....w ", + "....w ", + "....w ", + "wwwww " + ], + "palettes": [ "fbmh_log_palette" ] + } + }, + { + "type": "mapgen", + "method": "json", + "nested_mapgen_id": "fbmc_log_shack_west", + "object": { + "mapgensize": [ 6, 6 ], + "rows": [ + "w....w", + "v....w", + "+....w", + "w....w", + "wwwwww", + " " + ], + "palettes": [ "fbmh_log_palette" ] + } + }, + { + "type": "mapgen", + "method": "json", + "nested_mapgen_id": "fbmc_log_shack_east", + "object": { + "mapgensize": [ 6, 6 ], + "rows": [ + "w....w", + "w....v", + "w....+", + "w....w", + "wwwwww", + " " + ], + "palettes": [ "fbmh_log_palette" ] + } + }, + { + "type": "mapgen", + "method": "json", + "nested_mapgen_id": "fbmc_log_wall_horizontal", + "object": { + "mapgensize": [ 6, 6 ], + "rows": [ + "wwwwww", + " ", + " ", + " ", + " ", + " " + ], + "palettes": [ "fbmh_log_palette" ] + } + }, + { + "type": "mapgen", + "method": "json", + "nested_mapgen_id": "fbmc_log_wall_vertical", + "object": { + "mapgensize": [ 6, 6 ], + "rows": [ + "w ", + "w ", + "w ", + "w ", + "w ", + "w " + ], + "palettes": [ "fbmh_log_palette" ] + } + }, + { + "type": "mapgen", + "method": "json", + "nested_mapgen_id": "fbmc_metal_shack_north", + "object": { + "mapgensize": [ 6, 6 ], + "rows": [ + "wwwww ", + "....w ", + "....w ", + "....w ", + "....w ", + "w+vww " + ], + "palettes": [ "fbmh_metal_palette" ] + } + }, + { + "type": "mapgen", + "method": "json", + "nested_mapgen_id": "fbmc_metal_shack_south", + "object": { + "mapgensize": [ 6, 6 ], + "rows": [ + "w+vww ", + "....w ", + "....w ", + "....w ", + "....w ", + "wwwww " + ], + "palettes": [ "fbmh_metal_palette" ] + } + }, + { + "type": "mapgen", + "method": "json", + "nested_mapgen_id": "fbmc_metal_shack_west", + "object": { + "mapgensize": [ 6, 6 ], + "rows": [ + "w....w", + "v....w", + "+....w", + "w....w", + "wwwwww", + " " + ], + "palettes": [ "fbmh_metal_palette" ] + } + }, + { + "type": "mapgen", + "method": "json", + "nested_mapgen_id": "fbmc_metal_shack_east", + "object": { + "mapgensize": [ 6, 6 ], + "rows": [ + "w....w", + "w....v", + "w....+", + "w....w", + "wwwwww", + " " + ], + "palettes": [ "fbmh_metal_palette" ] + } + }, + { + "type": "mapgen", + "method": "json", + "nested_mapgen_id": "fbmc_metal_wall_horizontal", + "object": { + "mapgensize": [ 6, 6 ], + "rows": [ + "wwwwww", + " ", + " ", + " ", + " ", + " " + ], + "palettes": [ "fbmh_metal_palette" ] + } + }, + { + "type": "mapgen", + "method": "json", + "nested_mapgen_id": "fbmc_metal_wall_vertical", + "object": { + "mapgensize": [ 6, 6 ], + "rows": [ + "w ", + "w ", + "w ", + "w ", + "w ", + "w " + ], + "palettes": [ "fbmh_metal_palette" ] + } + }, + { + "type": "mapgen", + "method": "json", + "nested_mapgen_id": "fbmc_migo_resin_shack_north", + "object": { + "mapgensize": [ 6, 6 ], + "rows": [ + "wwwww ", + "....w ", + "....w ", + "....w ", + "....w ", + "w+vww " + ], + "palettes": [ "fbmh_migo_resin_palette" ] + } + }, + { + "type": "mapgen", + "method": "json", + "nested_mapgen_id": "fbmc_migo_resin_shack_south", + "object": { + "mapgensize": [ 6, 6 ], + "rows": [ + "w+vww ", + "....w ", + "....w ", + "....w ", + "....w ", + "wwwww " + ], + "palettes": [ "fbmh_migo_resin_palette" ] + } + }, + { + "type": "mapgen", + "method": "json", + "nested_mapgen_id": "fbmc_migo_resin_shack_west", + "object": { + "mapgensize": [ 6, 6 ], + "rows": [ + "w....w", + "v....w", + "+....w", + "w....w", + "wwwwww", + " " + ], + "palettes": [ "fbmh_migo_resin_palette" ] + } + }, + { + "type": "mapgen", + "method": "json", + "nested_mapgen_id": "fbmc_migo_resin_shack_east", + "object": { + "mapgensize": [ 6, 6 ], + "rows": [ + "w....w", + "w....v", + "w....+", + "w....w", + "wwwwww", + " " + ], + "palettes": [ "fbmh_migo_resin_palette" ] + } + }, + { + "type": "mapgen", + "method": "json", + "nested_mapgen_id": "fbmc_migo_resin_wall_horizontal", + "object": { + "mapgensize": [ 6, 6 ], + "rows": [ + "wwwwww", + " ", + " ", + " ", + " ", + " " + ], + "palettes": [ "fbmh_migo_resin_palette" ] + } + }, + { + "type": "mapgen", + "method": "json", + "nested_mapgen_id": "fbmc_migo_resin_wall_vertical", + "object": { + "mapgensize": [ 6, 6 ], + "rows": [ + "w ", + "w ", + "w ", + "w ", + "w ", + "w " + ], + "palettes": [ "fbmh_migo_resin_palette" ] + } + }, + { + "type": "mapgen", + "method": "json", + "nested_mapgen_id": "fbmc_rammed_earth_shack_north", + "object": { + "mapgensize": [ 6, 6 ], + "rows": [ + "wwwww ", + "....w ", + "....w ", + "....w ", + "....w ", + "w+vww " + ], + "palettes": [ "fbmh_rammed_earth_palette" ] + } + }, + { + "type": "mapgen", + "method": "json", + "nested_mapgen_id": "fbmc_rammed_earth_shack_south", + "object": { + "mapgensize": [ 6, 6 ], + "rows": [ + "w+vww ", + "....w ", + "....w ", + "....w ", + "....w ", + "wwwww " + ], + "palettes": [ "fbmh_rammed_earth_palette" ] + } + }, + { + "type": "mapgen", + "method": "json", + "nested_mapgen_id": "fbmc_rammed_earth_shack_west", + "object": { + "mapgensize": [ 6, 6 ], + "rows": [ + "w....w", + "v....w", + "+....w", + "w....w", + "wwwwww", + " " + ], + "palettes": [ "fbmh_rammed_earth_palette" ] + } + }, + { + "type": "mapgen", + "method": "json", + "nested_mapgen_id": "fbmc_rammed_earth_shack_east", + "object": { + "mapgensize": [ 6, 6 ], + "rows": [ + "w....w", + "w....v", + "w....+", + "w....w", + "wwwwww", + " " + ], + "palettes": [ "fbmh_rammed_earth_palette" ] + } + }, + { + "type": "mapgen", + "method": "json", + "nested_mapgen_id": "fbmc_rammed_earth_wall_horizontal", + "object": { + "mapgensize": [ 6, 6 ], + "rows": [ + "wwwwww", + " ", + " ", + " ", + " ", + " " + ], + "palettes": [ "fbmh_rammed_earth_palette" ] + } + }, + { + "type": "mapgen", + "method": "json", + "nested_mapgen_id": "fbmc_rammed_earth_wall_vertical", + "object": { + "mapgensize": [ 6, 6 ], + "rows": [ + "w ", + "w ", + "w ", + "w ", + "w ", + "w " + ], + "palettes": [ "fbmh_rammed_earth_palette" ] + } + }, + { + "type": "mapgen", + "method": "json", + "nested_mapgen_id": "fbmc_rock_shack_north", + "object": { + "mapgensize": [ 6, 6 ], + "rows": [ + "wwwww ", + "....w ", + "....w ", + "....w ", + "....w ", + "w+vww " + ], + "palettes": [ "fbmh_rock_palette" ] + } + }, + { + "type": "mapgen", + "method": "json", + "nested_mapgen_id": "fbmc_rock_shack_south", + "object": { + "mapgensize": [ 6, 6 ], + "rows": [ + "w+vww ", + "....w ", + "....w ", + "....w ", + "....w ", + "wwwww " + ], + "palettes": [ "fbmh_rock_palette" ] + } + }, + { + "type": "mapgen", + "method": "json", + "nested_mapgen_id": "fbmc_rock_shack_west", + "object": { + "mapgensize": [ 6, 6 ], + "rows": [ + "w....w", + "v....w", + "+....w", + "w....w", + "wwwwww", + " " + ], + "palettes": [ "fbmh_rock_palette" ] + } + }, + { + "type": "mapgen", + "method": "json", + "nested_mapgen_id": "fbmc_rock_shack_east", + "object": { + "mapgensize": [ 6, 6 ], + "rows": [ + "w....w", + "w....v", + "w....+", + "w....w", + "wwwwww", + " " + ], + "palettes": [ "fbmh_rock_palette" ] + } + }, + { + "type": "mapgen", + "method": "json", + "nested_mapgen_id": "fbmc_rock_wall_horizontal", + "object": { + "mapgensize": [ 6, 6 ], + "rows": [ + "wwwwww", + " ", + " ", + " ", + " ", + " " + ], + "palettes": [ "fbmh_rock_palette" ] + } + }, + { + "type": "mapgen", + "method": "json", + "nested_mapgen_id": "fbmc_rock_wall_vertical", + "object": { + "mapgensize": [ 6, 6 ], + "rows": [ + "w ", + "w ", + "w ", + "w ", + "w ", + "w " + ], + "palettes": [ "fbmh_rock_palette" ] + } + }, + { + "type": "mapgen", + "method": "json", + "nested_mapgen_id": "fbmc_wad_shack_north", + "object": { + "mapgensize": [ 6, 6 ], + "rows": [ + "wwwww ", + "....w ", + "....w ", + "....w ", + "....w ", + "w+vww " + ], + "palettes": [ "fbmh_wad_palette" ] + } + }, + { + "type": "mapgen", + "method": "json", + "nested_mapgen_id": "fbmc_wad_shack_south", + "object": { + "mapgensize": [ 6, 6 ], + "rows": [ + "w+vww ", + "....w ", + "....w ", + "....w ", + "....w ", + "wwwww " + ], + "palettes": [ "fbmh_wad_palette" ] + } + }, + { + "type": "mapgen", + "method": "json", + "nested_mapgen_id": "fbmc_wad_shack_west", + "object": { + "mapgensize": [ 6, 6 ], + "rows": [ + "w....w", + "v....w", + "+....w", + "w....w", + "wwwwww", + " " + ], + "palettes": [ "fbmh_wad_palette" ] + } + }, + { + "type": "mapgen", + "method": "json", + "nested_mapgen_id": "fbmc_wad_shack_east", + "object": { + "mapgensize": [ 6, 6 ], + "rows": [ + "w....w", + "w....v", + "w....+", + "w....w", + "wwwwww", + " " + ], + "palettes": [ "fbmh_wad_palette" ] + } + }, + { + "type": "mapgen", + "method": "json", + "nested_mapgen_id": "fbmc_wad_wall_horizontal", + "object": { + "mapgensize": [ 6, 6 ], + "rows": [ + "wwwwww", + " ", + " ", + " ", + " ", + " " + ], + "palettes": [ "fbmh_wad_palette" ] + } + }, + { + "type": "mapgen", + "method": "json", + "nested_mapgen_id": "fbmc_wad_wall_vertical", + "object": { + "mapgensize": [ 6, 6 ], + "rows": [ + "w ", + "w ", + "w ", + "w ", + "w ", + "w " + ], + "palettes": [ "fbmh_wad_palette" ] + } + }, + { + "type": "mapgen", + "method": "json", + "nested_mapgen_id": "fbmc_wood_shack_north", + "object": { + "mapgensize": [ 6, 6 ], + "rows": [ + "wwwww ", + "....w ", + "....w ", + "....w ", + "....w ", + "w+vww " + ], + "palettes": [ "fbmh_wood_palette" ] + } + }, + { + "type": "mapgen", + "method": "json", + "nested_mapgen_id": "fbmc_wood_shack_south", + "object": { + "mapgensize": [ 6, 6 ], + "rows": [ + "w+vww ", + "....w ", + "....w ", + "....w ", + "....w ", + "wwwww " + ], + "palettes": [ "fbmh_wood_palette" ] + } + }, + { + "type": "mapgen", + "method": "json", + "nested_mapgen_id": "fbmc_wood_shack_west", + "object": { + "mapgensize": [ 6, 6 ], + "rows": [ + "w....w", + "v....w", + "+....w", + "w....w", + "wwwwww", + " " + ], + "palettes": [ "fbmh_wood_palette" ] + } + }, + { + "type": "mapgen", + "method": "json", + "nested_mapgen_id": "fbmc_wood_shack_east", + "object": { + "mapgensize": [ 6, 6 ], + "rows": [ + "w....w", + "w....v", + "w....+", + "w....w", + "wwwwww", + " " + ], + "palettes": [ "fbmh_wood_palette" ] + } + }, + { + "type": "mapgen", + "method": "json", + "nested_mapgen_id": "fbmc_wood_wall_horizontal", + "object": { + "mapgensize": [ 6, 6 ], + "rows": [ + "wwwwww", + " ", + " ", + " ", + " ", + " " + ], + "palettes": [ "fbmh_wood_palette" ] + } + }, + { + "type": "mapgen", + "method": "json", + "nested_mapgen_id": "fbmc_wood_wall_vertical", + "object": { + "mapgensize": [ 6, 6 ], + "rows": [ + "w ", + "w ", + "w ", + "w ", + "w ", + "w " + ], + "palettes": [ "fbmh_wood_palette" ] + } + } +] \ No newline at end of file diff --git a/data/json/recipes/basecamps/fbmc_radio_tower/recipe_modular_radio_tower_beds.json b/data/json/recipes/basecamps/fbmc_radio_tower/recipe_modular_radio_tower_beds.json new file mode 100644 index 0000000000000..d7dfb2c621c25 --- /dev/null +++ b/data/json/recipes/basecamps/fbmc_radio_tower/recipe_modular_radio_tower_beds.json @@ -0,0 +1,282 @@ +[ + { + "type": "recipe", + "result": "faction_base_radio_tower_mattress_beds_controls_room", + "description": "We should remove some of display racks and counters, then build a pair of mattress beds inside radio control's room for our survivors.", + "category": "CC_BUILDING", + "subcategory": "CSC_BUILDING_BASES", + "autolearn": false, + "never_learn": true, + "construction_blueprint": "fbmc_radio_tower_mattress_beds_controls_room", + "blueprint_provides": [ { "id": "fbmc_radio_tower_beds_controls_room" }, { "id": "bed", "amount": 2 } ], + "blueprint_excludes": [ { "id": "fbmc_radio_tower_beds_controls_room" } ], + "blueprint_requires": [ { "id": "fbmc_radio_tower_controls_room" } ], + "blueprint_name": "pair of mattress beds in radio control's room" + }, + { + "type": "recipe", + "result": "faction_base_radio_tower_mattress_beds_0", + "description": "We should build a pair of mattress beds inside radio tower shack for our survivors.", + "category": "CC_BUILDING", + "subcategory": "CSC_BUILDING_BASES", + "autolearn": false, + "never_learn": true, + "construction_blueprint": "fbmc_radio_tower_mattress_beds_0", + "blueprint_provides": [ { "id": "fbmc_radio_tower_beds_0" }, { "id": "bed", "amount": 2 } ], + "blueprint_excludes": [ { "id": "fbmc_radio_tower_beds_0" } ], + "blueprint_requires": [ { "id": "fbmc_radio_tower_shack_0" } ], + "blueprint_name": "pair of mattress beds in radio tower" + }, + { + "type": "recipe", + "result": "faction_base_radio_tower_mattress_beds_1", + "description": "We should build a pair of mattress beds in the northeast side shack for our survivors.", + "category": "CC_BUILDING", + "subcategory": "CSC_BUILDING_BASES", + "autolearn": false, + "never_learn": true, + "construction_blueprint": "fbmc_radio_tower_mattress_beds_1", + "blueprint_provides": [ { "id": "fbmc_radio_tower_beds_1" }, { "id": "bed", "amount": 2 } ], + "blueprint_excludes": [ { "id": "fbmc_radio_tower_beds_1" } ], + "blueprint_requires": [ { "id": "fbmc_radio_tower_shack_1" } ], + "blueprint_name": "pair of mattress beds in NE side shack" + }, + { + "type": "recipe", + "result": "faction_base_radio_tower_mattress_beds_2", + "description": "We should build a pair of mattress beds in the southwest corner shack for our survivors.", + "category": "CC_BUILDING", + "subcategory": "CSC_BUILDING_BASES", + "autolearn": false, + "never_learn": true, + "construction_blueprint": "fbmc_radio_tower_mattress_beds_2", + "blueprint_provides": [ { "id": "fbmc_radio_tower_beds_2" }, { "id": "bed", "amount": 2 } ], + "blueprint_excludes": [ { "id": "fbmc_radio_tower_beds_2" } ], + "blueprint_requires": [ { "id": "fbmc_radio_tower_shack_2" } ], + "blueprint_name": "pair of mattress beds in SW corner shack" + }, + { + "type": "recipe", + "result": "faction_base_radio_tower_mattress_beds_3", + "description": "We should build a pair of mattress beds in the southwest side shack for our survivors.", + "category": "CC_BUILDING", + "subcategory": "CSC_BUILDING_BASES", + "autolearn": false, + "never_learn": true, + "construction_blueprint": "fbmc_radio_tower_mattress_beds_3", + "blueprint_provides": [ { "id": "fbmc_radio_tower_beds_3" }, { "id": "bed", "amount": 2 } ], + "blueprint_excludes": [ { "id": "fbmc_radio_tower_beds_3" } ], + "blueprint_requires": [ { "id": "fbmc_radio_tower_shack_3" } ], + "blueprint_name": "pair of mattress beds in SW side shack" + }, + { + "type": "recipe", + "result": "faction_base_radio_tower_mattress_beds_4", + "description": "We should build a pair of mattress beds in the southeast side shack for our survivors.", + "category": "CC_BUILDING", + "subcategory": "CSC_BUILDING_BASES", + "autolearn": false, + "never_learn": true, + "construction_blueprint": "fbmc_radio_tower_mattress_beds_4", + "blueprint_provides": [ { "id": "fbmc_radio_tower_beds_4" }, { "id": "bed", "amount": 2 } ], + "blueprint_excludes": [ { "id": "fbmc_radio_tower_beds_4" } ], + "blueprint_requires": [ { "id": "fbmc_radio_tower_shack_4" } ], + "blueprint_name": "pair of mattress beds in SE side shack" + }, + { + "type": "recipe", + "result": "faction_base_radio_tower_mattress_beds_5", + "description": "We should build a pair of mattress beds in the southeast corner shack for our survivors.", + "category": "CC_BUILDING", + "subcategory": "CSC_BUILDING_BASES", + "autolearn": false, + "never_learn": true, + "construction_blueprint": "fbmc_radio_tower_mattress_beds_5", + "blueprint_provides": [ { "id": "fbmc_radio_tower_beds_5" }, { "id": "bed", "amount": 2 } ], + "blueprint_excludes": [ { "id": "fbmc_radio_tower_beds_5" } ], + "blueprint_requires": [ { "id": "fbmc_radio_tower_shack_5" } ], + "blueprint_name": "pair of mattress beds in SE corner shack" + }, + { + "type": "recipe", + "result": "faction_base_radio_tower_mattress_beds_6", + "description": "We should build a pair of mattress beds in the southeast corner shack for our survivors.", + "category": "CC_BUILDING", + "subcategory": "CSC_BUILDING_BASES", + "autolearn": false, + "never_learn": true, + "construction_blueprint": "fbmc_radio_tower_mattress_beds_6", + "blueprint_provides": [ { "id": "fbmc_radio_tower_beds_6" }, { "id": "bed", "amount": 2 } ], + "blueprint_excludes": [ { "id": "fbmc_radio_tower_beds_6" } ], + "blueprint_requires": [ { "id": "fbmc_radio_tower_shack_6" } ], + "blueprint_name": "pair of mattress beds in SE corner shack" + }, + { + "type": "recipe", + "result": "faction_base_radio_tower_mattress_beds_7", + "description": "We should build a pair of mattress beds in the southwest corner shack for our survivors.", + "category": "CC_BUILDING", + "subcategory": "CSC_BUILDING_BASES", + "autolearn": false, + "never_learn": true, + "construction_blueprint": "fbmc_radio_tower_mattress_beds_7", + "blueprint_provides": [ { "id": "fbmc_radio_tower_beds_7" }, { "id": "bed", "amount": 2 } ], + "blueprint_excludes": [ { "id": "fbmc_radio_tower_beds_7" } ], + "blueprint_requires": [ { "id": "fbmc_radio_tower_shack_7" } ], + "blueprint_name": "pair of mattress beds in SW corner shack" + }, + { + "type": "recipe", + "result": "faction_base_radio_tower_mattress_beds_8", + "description": "We should build a pair of mattress beds in the south side shack for our survivors.", + "category": "CC_BUILDING", + "subcategory": "CSC_BUILDING_BASES", + "autolearn": false, + "never_learn": true, + "construction_blueprint": "fbmc_radio_tower_mattress_beds_8", + "blueprint_provides": [ { "id": "fbmc_radio_tower_beds_8" }, { "id": "bed", "amount": 2 } ], + "blueprint_excludes": [ { "id": "fbmc_radio_tower_beds_8" } ], + "blueprint_requires": [ { "id": "fbmc_radio_tower_shack_8" } ], + "blueprint_name": "pair of mattress beds in S side shack" + }, + { + "type": "recipe", + "result": "faction_base_radio_tower_straw_beds_controls_room", + "description": "We should remove some of display racks and counters, then build a pair of straw beds inside radio control's room for our survivors.", + "category": "CC_BUILDING", + "subcategory": "CSC_BUILDING_BASES", + "autolearn": false, + "never_learn": true, + "construction_blueprint": "fbmc_radio_tower_straw_beds_controls_room", + "blueprint_provides": [ { "id": "fbmc_radio_tower_beds_controls_room" }, { "id": "bed", "amount": 2 } ], + "blueprint_excludes": [ { "id": "fbmc_radio_tower_beds_controls_room" } ], + "blueprint_requires": [ { "id": "fbmc_radio_tower_controls_room" } ], + "blueprint_name": "pair of straw beds in radio control's room" + }, + { + "type": "recipe", + "result": "faction_base_radio_tower_straw_beds_0", + "description": "We should build a pair of straw beds inside radio tower shack for our survivors.", + "category": "CC_BUILDING", + "subcategory": "CSC_BUILDING_BASES", + "autolearn": false, + "never_learn": true, + "construction_blueprint": "fbmc_radio_tower_straw_beds_0", + "blueprint_provides": [ { "id": "fbmc_radio_tower_beds_0" }, { "id": "bed", "amount": 2 } ], + "blueprint_excludes": [ { "id": "fbmc_radio_tower_beds_0" } ], + "blueprint_requires": [ { "id": "fbmc_radio_tower_shack_0" } ], + "blueprint_name": "pair of straw beds in radio tower" + }, + { + "type": "recipe", + "result": "faction_base_radio_tower_straw_beds_1", + "description": "We should build a pair of straw beds in the northeast side shack for our survivors.", + "category": "CC_BUILDING", + "subcategory": "CSC_BUILDING_BASES", + "autolearn": false, + "never_learn": true, + "construction_blueprint": "fbmc_radio_tower_straw_beds_1", + "blueprint_provides": [ { "id": "fbmc_radio_tower_beds_1" }, { "id": "bed", "amount": 2 } ], + "blueprint_excludes": [ { "id": "fbmc_radio_tower_beds_1" } ], + "blueprint_requires": [ { "id": "fbmc_radio_tower_shack_1" } ], + "blueprint_name": "pair of straw beds in NE side shack" + }, + { + "type": "recipe", + "result": "faction_base_radio_tower_straw_beds_2", + "description": "We should build a pair of straw beds in the southwest corner shack for our survivors.", + "category": "CC_BUILDING", + "subcategory": "CSC_BUILDING_BASES", + "autolearn": false, + "never_learn": true, + "construction_blueprint": "fbmc_radio_tower_straw_beds_2", + "blueprint_provides": [ { "id": "fbmc_radio_tower_beds_2" }, { "id": "bed", "amount": 2 } ], + "blueprint_excludes": [ { "id": "fbmc_radio_tower_beds_2" } ], + "blueprint_requires": [ { "id": "fbmc_radio_tower_shack_2" } ], + "blueprint_name": "pair of straw beds in SW corner shack" + }, + { + "type": "recipe", + "result": "faction_base_radio_tower_straw_beds_3", + "description": "We should build a pair of straw beds in the southwest side shack for our survivors.", + "category": "CC_BUILDING", + "subcategory": "CSC_BUILDING_BASES", + "autolearn": false, + "never_learn": true, + "construction_blueprint": "fbmc_radio_tower_straw_beds_3", + "blueprint_provides": [ { "id": "fbmc_radio_tower_beds_3" }, { "id": "bed", "amount": 2 } ], + "blueprint_excludes": [ { "id": "fbmc_radio_tower_beds_3" } ], + "blueprint_requires": [ { "id": "fbmc_radio_tower_shack_3" } ], + "blueprint_name": "pair of straw beds in SW side shack" + }, + { + "type": "recipe", + "result": "faction_base_radio_tower_straw_beds_4", + "description": "We should build a pair of straw beds in the southeast side shack for our survivors.", + "category": "CC_BUILDING", + "subcategory": "CSC_BUILDING_BASES", + "autolearn": false, + "never_learn": true, + "construction_blueprint": "fbmc_radio_tower_straw_beds_4", + "blueprint_provides": [ { "id": "fbmc_radio_tower_beds_4" }, { "id": "bed", "amount": 2 } ], + "blueprint_excludes": [ { "id": "fbmc_radio_tower_beds_4" } ], + "blueprint_requires": [ { "id": "fbmc_radio_tower_shack_4" } ], + "blueprint_name": "pair of straw beds in SE side shack" + }, + { + "type": "recipe", + "result": "faction_base_radio_tower_straw_beds_5", + "description": "We should build a pair of straw beds in the southeast corner shack for our survivors.", + "category": "CC_BUILDING", + "subcategory": "CSC_BUILDING_BASES", + "autolearn": false, + "never_learn": true, + "construction_blueprint": "fbmc_radio_tower_straw_beds_5", + "blueprint_provides": [ { "id": "fbmc_radio_tower_beds_5" }, { "id": "bed", "amount": 2 } ], + "blueprint_excludes": [ { "id": "fbmc_radio_tower_beds_5" } ], + "blueprint_requires": [ { "id": "fbmc_radio_tower_shack_5" } ], + "blueprint_name": "pair of straw beds in SE corner shack" + }, + { + "type": "recipe", + "result": "faction_base_radio_tower_straw_beds_6", + "description": "We should build a pair of straw beds in the southeast corner shack for our survivors.", + "category": "CC_BUILDING", + "subcategory": "CSC_BUILDING_BASES", + "autolearn": false, + "never_learn": true, + "construction_blueprint": "fbmc_radio_tower_straw_beds_6", + "blueprint_provides": [ { "id": "fbmc_radio_tower_beds_6" }, { "id": "bed", "amount": 2 } ], + "blueprint_excludes": [ { "id": "fbmc_radio_tower_beds_6" } ], + "blueprint_requires": [ { "id": "fbmc_radio_tower_shack_6" } ], + "blueprint_name": "pair of straw beds in SE corner shack" + }, + { + "type": "recipe", + "result": "faction_base_radio_tower_straw_beds_7", + "description": "We should build a pair of straw beds in the southwest corner shack for our survivors.", + "category": "CC_BUILDING", + "subcategory": "CSC_BUILDING_BASES", + "autolearn": false, + "never_learn": true, + "construction_blueprint": "fbmc_radio_tower_straw_beds_7", + "blueprint_provides": [ { "id": "fbmc_radio_tower_beds_7" }, { "id": "bed", "amount": 2 } ], + "blueprint_excludes": [ { "id": "fbmc_radio_tower_beds_7" } ], + "blueprint_requires": [ { "id": "fbmc_radio_tower_shack_7" } ], + "blueprint_name": "pair of straw beds in SW corner shack" + }, + { + "type": "recipe", + "result": "faction_base_radio_tower_straw_beds_8", + "description": "We should build a pair of straw beds in the south side shack for our survivors.", + "category": "CC_BUILDING", + "subcategory": "CSC_BUILDING_BASES", + "autolearn": false, + "never_learn": true, + "construction_blueprint": "fbmc_radio_tower_straw_beds_8", + "blueprint_provides": [ { "id": "fbmc_radio_tower_beds_8" }, { "id": "bed", "amount": 2 } ], + "blueprint_excludes": [ { "id": "fbmc_radio_tower_beds_8" } ], + "blueprint_requires": [ { "id": "fbmc_radio_tower_shack_8" } ], + "blueprint_name": "pair of straw beds in S side shack" + } +] \ No newline at end of file diff --git a/data/json/recipes/basecamps/fbmc_radio_tower/recipe_modular_radio_tower_common.json b/data/json/recipes/basecamps/fbmc_radio_tower/recipe_modular_radio_tower_common.json new file mode 100644 index 0000000000000..ad97906f1fd6a --- /dev/null +++ b/data/json/recipes/basecamps/fbmc_radio_tower/recipe_modular_radio_tower_common.json @@ -0,0 +1,229 @@ +[ + { + "type": "recipe", + "result": "faction_base_radio_tower_0", + "description": "We should survey the base site and set up a bulletin board.", + "category": "CC_BUILDING", + "subcategory": "CSC_BUILDING_BASES", + "skill_used": "fabrication", + "autolearn": false, + "never_learn": true, + "time": "1 h", + "construction_blueprint": "fbmc_radio_tower_0", + "blueprint_provides": [ + { "id": "fbmc_radio_tower_0" }, + { "id": "fbmc_radio_tower" }, + { "id": "primitive_camp_recipes_1" }, + { "id": "gathering" }, + { "id": "firewood" }, + { "id": "foraging" }, + { "id": "sorting" }, + { "id": "logging" } + ], + "blueprint_requires": [ { "id": "not_an_upgrade" } ], + "blueprint_name": "basic survey", + "check_blueprint_needs": false + }, + { + "type": "recipe", + "result": "faction_base_radio_tower_1_0", + "description": "We should survey the base site and set up a bulletin board.", + "category": "CC_BUILDING", + "subcategory": "CSC_BUILDING_BASES", + "skill_used": "fabrication", + "autolearn": false, + "never_learn": true, + "time": "1 h", + "construction_blueprint": "fbmc_radio_tower_1", + "blueprint_provides": [ + { "id": "fbmc_radio_tower_1" }, + { "id": "primitive_camp_recipes_1" }, + { "id": "gathering" }, + { "id": "firewood" }, + { "id": "foraging" }, + { "id": "sorting" }, + { "id": "logging" } + ], + "blueprint_requires": [ { "id": "not_an_upgrade" } ], + "blueprint_name": "basic survey", + "check_blueprint_needs": false + }, + { + "type": "recipe", + "result": "faction_base_radio_tower_root_cellar", + "description": "Digging a root cellar will give us a way to preserve food.", + "category": "CC_BUILDING", + "subcategory": "CSC_BUILDING_BASES", + "autolearn": false, + "never_learn": true, + "construction_blueprint": "fbmc_radio_tower_root_cellar", + "blueprint_name": "root cellar", + "blueprint_provides": [ { "id": "pantry" }, { "id": "fbmc_radio_tower_root_cellar" } ], + "blueprint_requires": [ { "id": "bed", "amount": 4 } ], + "blueprint_excludes": [ { "id": "fbmc_radio_tower_root_cellar" } ] + }, + { + "type": "recipe", + "result": "faction_base_radio_tower_water_well", + "description": "Digging a well will give us easy access to water.", + "category": "CC_BUILDING", + "subcategory": "CSC_BUILDING_BASES", + "autolearn": false, + "never_learn": true, + "construction_blueprint": "fbmc_radio_tower_water_well", + "blueprint_name": "water well", + "blueprint_provides": [ { "id": "fbmc_radio_tower_water_well" } ], + "blueprint_requires": [ { "id": "bed", "amount": 4 } ], + "blueprint_excludes": [ { "id": "fbmc_radio_tower_water_well" } ] + }, + { + "type": "recipe", + "result": "faction_base_radio_tower_fix_controls", + "description": "Let's fix up radio tower and controls to improve our recruitment efforts.", + "category": "CC_BUILDING", + "subcategory": "CSC_BUILDING_BASES", + "autolearn": false, + "never_learn": true, + "construction_blueprint": "fbmc_radio_tower_fix_controls", + "blueprint_name": "fix radio tower and controls", + "blueprint_requires": [ { "id": "fbmc_radio_tower_water_well" }, { "id": "fbmc_radio_tower_root_cellar" } ], + "blueprint_provides": [ { "id": "fbmc_radio_tower_fix_controls" }, { "id": "recruiting" }, { "id": "radio" } ], + "blueprint_excludes": [ { "id": "fbmc_radio_tower_fix_controls" } ], + "blueprint_needs": { + "time": "10 h", + "skills": [ [ "fabrication", 3 ] ], + "inline": { + "tools": [ ], + "qualities": [ [ { "id": "HAMMER", "level": 2 } ], [ { "id": "SAW_M" } ], [ { "id": "SCREW" } ], [ { "id": "WRENCH" } ] ], + "components": [ + [ + [ "wind_turbine", 4 ], + [ "xl_wind_turbine", 1 ], + [ "solar_panel", 4 ], + [ "reinforced_solar_panel", 4 ], + [ "solar_panel_v2", 2 ], + [ "reinforced_solar_panel_v2", 2 ] + ], + [ [ "storage_battery", 1 ], [ "medium_storage_battery", 4 ], [ "small_storage_battery", 32 ] ], + [ [ "processor", 1 ] ], + [ [ "RAM", 1 ] ], + [ [ "large_lcd_screen", 1 ] ], + [ [ "e_scrap", 2 ] ], + [ [ "circuit", 2 ] ], + [ [ "power_supply", 1 ] ], + [ [ "amplifier", 1 ] ], + [ [ "cable", 160 ] ] + ] + } + } + }, + { + "type": "recipe", + "result": "faction_base_radio_tower_0_prepalisade", + "description": "We should dig pits for palisade around camp.", + "category": "CC_BUILDING", + "subcategory": "CSC_BUILDING_BASES", + "autolearn": false, + "never_learn": true, + "construction_blueprint": "fbmc_radio_tower_0_prepalisade", + "blueprint_provides": [ + { "id": "fbmc_radio_tower_0_prepalisade" } + ], + "blueprint_requires": [ { "id": "fbmc_radio_tower_0" }, { "id": "fbmc_radio_tower_shack_5" } ], + "blueprint_excludes": [ { "id": "fbmc_radio_tower_prepalisade" } ], + "blueprint_name": "dig pits" + }, + { + "type": "recipe", + "result": "faction_base_radio_tower_1_prepalisade", + "description": "We should dig pits for palisade around camp.", + "category": "CC_BUILDING", + "subcategory": "CSC_BUILDING_BASES", + "autolearn": false, + "never_learn": true, + "construction_blueprint": "fbmc_radio_tower_1_prepalisade", + "blueprint_provides": [ + { "id": "fbmc_radio_tower_1_prepalisade" } + ], + "blueprint_requires": [ { "id": "fbmc_radio_tower_1" }, { "id": "fbmc_radio_tower_shack_8" } ], + "blueprint_excludes": [ { "id": "fbmc_radio_tower_prepalisade" } ], + "blueprint_name": "dig pits" + }, + { + "type": "recipe", + "result": "faction_base_radio_tower_0_palisade", + "description": "We should build palisade around camp.", + "category": "CC_BUILDING", + "subcategory": "CSC_BUILDING_BASES", + "autolearn": false, + "never_learn": true, + "construction_blueprint": "fbmc_radio_tower_0_palisade", + "blueprint_provides": [ + { "id": "fbmc_radio_tower_0_palisade" }, { "id": "fbmc_radio_tower_palisade" } + ], + "blueprint_requires": [ { "id": "fbmc_radio_tower_0_prepalisade" } ], + "blueprint_excludes": [ { "id": "fbmc_radio_tower_palisade" } ], + "blueprint_name": "build palisade" + }, + { + "type": "recipe", + "result": "faction_base_radio_tower_1_palisade", + "description": "We should dig pits for palisade around camp.", + "category": "CC_BUILDING", + "subcategory": "CSC_BUILDING_BASES", + "autolearn": false, + "never_learn": true, + "construction_blueprint": "fbmc_radio_tower_1_palisade", + "blueprint_provides": [ + { "id": "fbmc_radio_tower_1_palisade" }, { "id": "fbmc_radio_tower_palisade" } + ], + "blueprint_requires": [ { "id": "fbmc_radio_tower_1_prepalisade" } ], + "blueprint_excludes": [ { "id": "fbmc_radio_tower_palisade" } ], + "blueprint_name": "build palisade" + }, + { + "type": "recipe", + "result": "faction_base_radio_tower_fix_tower", + "description": "We could try to fix whole tower and supply it with enough power, which could give us remote access to computer systems connected to backbone network or communication satellites.", + "category": "CC_BUILDING", + "subcategory": "CSC_BUILDING_BASES", + "autolearn": false, + "never_learn": true, + "construction_blueprint": "faction_base_radio_tower_fix_tower", + "blueprint_name": "fix whole radio tower", + "blueprint_requires": [ { "id": "bed", "amount": 12 }, { "id": "fbmc_radio_tower_palisade" }, { "id": "fbmc_radio_tower_fix_controls" } ], + "blueprint_provides": [ { "id": "faction_base_radio_tower_fix_tower" }, { "id": "hack_recipes_general" }, { "id": "hack_recipes_science" }, { "id": "hack_recipes_satellite" } ], + "blueprint_excludes": [ { "id": "faction_base_radio_tower_fix_tower" } ], + "using": [ [ "soldering_standard", 200 ], [ "welding_standard", 80 ] ], + "blueprint_needs": { + "time": "3 d", + "skills": [ [ "fabrication", 3 ], [ "computer", 4 ], [ "electronics", 8 ] ], + "inline": { + "tools": [ [ [ "laptop", 600 ] ], [ [ "radio_book", -1 ] ] ], + "qualities": [ [ { "id": "HAMMER", "level": 2 } ], [ { "id": "SAW_M" } ], [ { "id": "SCREW", "level": 2 } ], [ { "id": "SCREW_FINE" } ], [ { "id": "WRENCH", "level": 2 } ], [ { "id": "WRENCH_FINE" } ], [ { "id": "GLARE", "level": 2 } ] ], + "components": [ + [ + [ "wind_turbine", 16 ], + [ "xl_wind_turbine", 4 ], + [ "solar_panel", 16 ], + [ "reinforced_solar_panel", 16 ], + [ "solar_panel_v2", 8 ], + [ "reinforced_solar_panel_v2", 8 ] + ], + [ [ "storage_battery", 4 ], [ "medium_storage_battery", 16 ] ], + [ [ "sheet_metal", 8 ], [ "wire", 32 ] ], + [ [ "pipe", 24 ] ], + [ [ "processor", 16 ] ], + [ [ "RAM", 16 ] ], + [ [ "e_scrap", 40 ] ], + [ [ "frame", 1 ] ], + [ [ "circuit", 32 ] ], + [ [ "power_supply", 16 ] ], + [ [ "amplifier", 16 ] ], + [ [ "cable", 400 ] ], + [ [ "software_electronics_reference", 1 ] ] + ] + } + } + } +] diff --git a/data/json/recipes/basecamps/fbmc_radio_tower/recipe_modular_radio_tower_log.json b/data/json/recipes/basecamps/fbmc_radio_tower/recipe_modular_radio_tower_log.json new file mode 100644 index 0000000000000..baee6307f949b --- /dev/null +++ b/data/json/recipes/basecamps/fbmc_radio_tower/recipe_modular_radio_tower_log.json @@ -0,0 +1,114 @@ +[ + { + "type": "recipe", + "result": "faction_base_radio_tower_log_shack_1", + "description": "We need some shelter, so build a log shack with a wooden roof on the northeast side of the camp.", + "category": "CC_BUILDING", + "subcategory": "CSC_BUILDING_BASES", + "autolearn": false, + "never_learn": true, + "construction_blueprint": "fbmc_radio_tower_log_shack_1", + "blueprint_provides": [ { "id": "fbmc_radio_tower_shack_1" } ], + "blueprint_excludes": [ { "id": "fbmc_radio_tower_shack_1" } ], + "blueprint_requires": [ { "id": "fbmc_radio_tower_shack_0" } ], + "blueprint_name": "log shack" + }, + { + "type": "recipe", + "result": "faction_base_radio_tower_log_shack_2", + "description": "We need some shelter, so build a log shack with a wooden roof on the northeast side of the camp.", + "category": "CC_BUILDING", + "subcategory": "CSC_BUILDING_BASES", + "autolearn": false, + "never_learn": true, + "construction_blueprint": "fbmc_radio_tower_log_shack_2", + "blueprint_provides": [ { "id": "fbmc_radio_tower_shack_2" } ], + "blueprint_excludes": [ { "id": "fbmc_radio_tower_shack_2" } ], + "blueprint_requires": [ { "id": "fbmc_radio_tower_shack_1" }, { "id": "fbmc_radio_tower_0" } ], + "blueprint_name": "log shack" + }, + { + "type": "recipe", + "result": "faction_base_radio_tower_log_shack_3", + "description": "We need some shelter, so build a log shack with a wooden roof on the northeast side of the camp.", + "category": "CC_BUILDING", + "subcategory": "CSC_BUILDING_BASES", + "autolearn": false, + "never_learn": true, + "construction_blueprint": "fbmc_radio_tower_log_shack_3", + "blueprint_provides": [ { "id": "fbmc_radio_tower_shack_3" } ], + "blueprint_excludes": [ { "id": "fbmc_radio_tower_shack_3" } ], + "blueprint_requires": [ { "id": "fbmc_radio_tower_shack_2" } ], + "blueprint_name": "log shack" + }, + { + "type": "recipe", + "result": "faction_base_radio_tower_log_shack_4", + "description": "We need some shelter, so build a log shack with a wooden roof on the northeast side of the camp.", + "category": "CC_BUILDING", + "subcategory": "CSC_BUILDING_BASES", + "autolearn": false, + "never_learn": true, + "construction_blueprint": "fbmc_radio_tower_log_shack_4", + "blueprint_provides": [ { "id": "fbmc_radio_tower_shack_4" } ], + "blueprint_excludes": [ { "id": "fbmc_radio_tower_shack_4" } ], + "blueprint_requires": [ { "id": "fbmc_radio_tower_shack_3" } ], + "blueprint_name": "log shack" + }, + { + "type": "recipe", + "result": "faction_base_radio_tower_log_shack_5", + "description": "We need some shelter, so build a log shack with a wooden roof on the northeast side of the camp.", + "category": "CC_BUILDING", + "subcategory": "CSC_BUILDING_BASES", + "autolearn": false, + "never_learn": true, + "construction_blueprint": "fbmc_radio_tower_log_shack_5", + "blueprint_provides": [ { "id": "fbmc_radio_tower_shack_5" } ], + "blueprint_excludes": [ { "id": "fbmc_radio_tower_shack_5" } ], + "blueprint_requires": [ { "id": "fbmc_radio_tower_shack_4" } ], + "blueprint_name": "log shack" + }, + { + "type": "recipe", + "result": "faction_base_radio_tower_log_shack_6", + "description": "We need some shelter, so build a log shack with a wooden roof on the southeast corner of the camp.", + "category": "CC_BUILDING", + "subcategory": "CSC_BUILDING_BASES", + "autolearn": false, + "never_learn": true, + "construction_blueprint": "fbmc_radio_tower_log_shack_6", + "blueprint_provides": [ { "id": "fbmc_radio_tower_shack_6" } ], + "blueprint_excludes": [ { "id": "fbmc_radio_tower_shack_6" } ], + "blueprint_requires": [ { "id": "fbmc_radio_tower_shack_1" }, { "id": "fbmc_radio_tower_1" } ], + "blueprint_name": "log shack" + }, + { + "type": "recipe", + "result": "faction_base_radio_tower_log_shack_7", + "description": "We need some shelter, so build a log shack with a wooden roof on the southwest corner of the camp.", + "category": "CC_BUILDING", + "subcategory": "CSC_BUILDING_BASES", + "autolearn": false, + "never_learn": true, + "construction_blueprint": "fbmc_radio_tower_log_shack_7", + "blueprint_provides": [ { "id": "fbmc_radio_tower_shack_7" } ], + "blueprint_excludes": [ { "id": "fbmc_radio_tower_shack_7" } ], + "blueprint_requires": [ { "id": "fbmc_radio_tower_shack_6" } ], + "blueprint_name": "log shack" + }, + { + "type": "recipe", + "result": "faction_base_radio_tower_log_shack_8", + "description": "We need some shelter, so build a log shack with a wooden roof on the south side of the camp.", + "category": "CC_BUILDING", + "subcategory": "CSC_BUILDING_BASES", + "autolearn": false, + "never_learn": true, + "construction_blueprint": "fbmc_radio_tower_log_shack_8", + "blueprint_provides": [ { "id": "fbmc_radio_tower_shack_8" } ], + "blueprint_excludes": [ { "id": "fbmc_radio_tower_shack_8" } ], + "blueprint_requires": [ { "id": "fbmc_radio_tower_shack_7" } ], + "blueprint_name": "log shack" + } +] \ No newline at end of file diff --git a/data/json/recipes/basecamps/fbmc_radio_tower/recipe_modular_radio_tower_metal.json b/data/json/recipes/basecamps/fbmc_radio_tower/recipe_modular_radio_tower_metal.json new file mode 100644 index 0000000000000..9edc34542163e --- /dev/null +++ b/data/json/recipes/basecamps/fbmc_radio_tower/recipe_modular_radio_tower_metal.json @@ -0,0 +1,114 @@ +[ + { + "type": "recipe", + "result": "faction_base_radio_tower_metal_shack_1", + "description": "We need some shelter, so build a metal shack with a metal roof on the northeast side of the camp.", + "category": "CC_BUILDING", + "subcategory": "CSC_BUILDING_BASES", + "autolearn": false, + "never_learn": true, + "construction_blueprint": "fbmc_radio_tower_metal_shack_1", + "blueprint_provides": [ { "id": "fbmc_radio_tower_shack_1" } ], + "blueprint_excludes": [ { "id": "fbmc_radio_tower_shack_1" } ], + "blueprint_requires": [ { "id": "fbmc_radio_tower_shack_0" } ], + "blueprint_name": "metal shack" + }, + { + "type": "recipe", + "result": "faction_base_radio_tower_metal_shack_2", + "description": "We need some shelter, so build a metal shack with a metal roof on the southwest corner of the camp.", + "category": "CC_BUILDING", + "subcategory": "CSC_BUILDING_BASES", + "autolearn": false, + "never_learn": true, + "construction_blueprint": "fbmc_radio_tower_metal_shack_2", + "blueprint_provides": [ { "id": "fbmc_radio_tower_shack_2" } ], + "blueprint_excludes": [ { "id": "fbmc_radio_tower_shack_2" } ], + "blueprint_requires": [ { "id": "fbmc_radio_tower_shack_1" }, { "id": "fbmc_radio_tower_0" } ], + "blueprint_name": "metal shack" + }, + { + "type": "recipe", + "result": "faction_base_radio_tower_metal_shack_3", + "description": "We need some shelter, so build a metal shack with a metal roof on the southwest side of the camp.", + "category": "CC_BUILDING", + "subcategory": "CSC_BUILDING_BASES", + "autolearn": false, + "never_learn": true, + "construction_blueprint": "fbmc_radio_tower_metal_shack_3", + "blueprint_provides": [ { "id": "fbmc_radio_tower_shack_3" } ], + "blueprint_excludes": [ { "id": "fbmc_radio_tower_shack_3" } ], + "blueprint_requires": [ { "id": "fbmc_radio_tower_shack_2" } ], + "blueprint_name": "metal shack" + }, + { + "type": "recipe", + "result": "faction_base_radio_tower_metal_shack_4", + "description": "We need some shelter, so build a metal shack with a metal roof on the southeast side of the camp.", + "category": "CC_BUILDING", + "subcategory": "CSC_BUILDING_BASES", + "autolearn": false, + "never_learn": true, + "construction_blueprint": "fbmc_radio_tower_metal_shack_4", + "blueprint_provides": [ { "id": "fbmc_radio_tower_shack_4" } ], + "blueprint_excludes": [ { "id": "fbmc_radio_tower_shack_4" } ], + "blueprint_requires": [ { "id": "fbmc_radio_tower_shack_3" } ], + "blueprint_name": "metal shack" + }, + { + "type": "recipe", + "result": "faction_base_radio_tower_metal_shack_5", + "description": "We need some shelter, so build a metal shack with a metal roof on the southeast corner of the camp.", + "category": "CC_BUILDING", + "subcategory": "CSC_BUILDING_BASES", + "autolearn": false, + "never_learn": true, + "construction_blueprint": "fbmc_radio_tower_metal_shack_5", + "blueprint_provides": [ { "id": "fbmc_radio_tower_shack_5" } ], + "blueprint_excludes": [ { "id": "fbmc_radio_tower_shack_5" } ], + "blueprint_requires": [ { "id": "fbmc_radio_tower_shack_4" } ], + "blueprint_name": "metal shack" + }, + { + "type": "recipe", + "result": "faction_base_radio_tower_metal_shack_6", + "description": "We need some shelter, so build a metal shack with a metal roof on the southeast corner of the camp.", + "category": "CC_BUILDING", + "subcategory": "CSC_BUILDING_BASES", + "autolearn": false, + "never_learn": true, + "construction_blueprint": "fbmc_radio_tower_metal_shack_6", + "blueprint_provides": [ { "id": "fbmc_radio_tower_shack_6" } ], + "blueprint_excludes": [ { "id": "fbmc_radio_tower_shack_6" } ], + "blueprint_requires": [ { "id": "fbmc_radio_tower_shack_1" }, { "id": "fbmc_radio_tower_1" } ], + "blueprint_name": "metal shack" + }, + { + "type": "recipe", + "result": "faction_base_radio_tower_metal_shack_7", + "description": "We need some shelter, so build a metal shack with a metal roof on the southwest corner of the camp.", + "category": "CC_BUILDING", + "subcategory": "CSC_BUILDING_BASES", + "autolearn": false, + "never_learn": true, + "construction_blueprint": "fbmc_radio_tower_metal_shack_7", + "blueprint_provides": [ { "id": "fbmc_radio_tower_shack_7" } ], + "blueprint_excludes": [ { "id": "fbmc_radio_tower_shack_7" } ], + "blueprint_requires": [ { "id": "fbmc_radio_tower_shack_6" } ], + "blueprint_name": "metal shack" + }, + { + "type": "recipe", + "result": "faction_base_radio_tower_metal_shack_8", + "description": "We need some shelter, so build a metal shack with a metal roof on the south side of the camp.", + "category": "CC_BUILDING", + "subcategory": "CSC_BUILDING_BASES", + "autolearn": false, + "never_learn": true, + "construction_blueprint": "fbmc_radio_tower_metal_shack_8", + "blueprint_provides": [ { "id": "fbmc_radio_tower_shack_8" } ], + "blueprint_excludes": [ { "id": "fbmc_radio_tower_shack_8" } ], + "blueprint_requires": [ { "id": "fbmc_radio_tower_shack_7" } ], + "blueprint_name": "metal shack" + } +] \ No newline at end of file diff --git a/data/json/recipes/basecamps/fbmc_radio_tower/recipe_modular_radio_tower_migo_resin.json b/data/json/recipes/basecamps/fbmc_radio_tower/recipe_modular_radio_tower_migo_resin.json new file mode 100644 index 0000000000000..a29a9f61d1457 --- /dev/null +++ b/data/json/recipes/basecamps/fbmc_radio_tower/recipe_modular_radio_tower_migo_resin.json @@ -0,0 +1,153 @@ +[ + { + "type": "recipe", + "activity_level": "MODERATE_EXERCISE", + "result": "faction_base_radio_tower_1_controls_room_migo_resin", + "description": "We need some shelter, so build migo resin walls over windows in radio control's room.", + "category": "CC_BUILDING", + "subcategory": "CSC_BUILDING_BASES", + "autolearn": false, + "never_learn": true, + "construction_blueprint": "fbmc_radio_tower_controls_room_migo_resin", + "blueprint_name": "barricade radio control's room", + "blueprint_provides": [ { "id": "fbmc_radio_tower_controls_room" }, { "id": "fbmc_radio_tower" } ], + "blueprint_requires": [ { "id": "fbmc_radio_tower_1" } ], + "blueprint_excludes": [ { "id": "fbmc_radio_tower_controls_room" } ] + }, + { + "type": "recipe", + "result": "faction_base_radio_tower_migo_resin_shack_0", + "description": "We need some shelter, so build a mi-go resin shack with a mi-go resin roof inside radio tower.", + "category": "CC_BUILDING", + "subcategory": "CSC_BUILDING_BASES", + "autolearn": false, + "never_learn": true, + "construction_blueprint": "fbmc_radio_tower_migo_resin_shack_0", + "blueprint_provides": [ { "id": "fbmc_radio_tower_shack_0" } ], + "blueprint_excludes": [ { "id": "fbmc_radio_tower_shack_0" } ], + "blueprint_requires": [ { "id": "fbmc_radio_tower" } ], + "blueprint_needs": { + "time": "29 h", + "skills": [ [ "fabrication", 2 ] ], + "inline": { + "qualities": [ [ { "id": "SMOOTH", "level": 1 } ] ], + "components": [ + [ [ "alien_pod_resin", 52 ] ] + ] + } + }, + "blueprint_name": "mi-go resin shack" + }, + { + "type": "recipe", + "result": "faction_base_radio_tower_migo_resin_shack_1", + "description": "We need some shelter, so build a mi-go resin shack with a mi-go resin roof on the northeast side of the camp.", + "category": "CC_BUILDING", + "subcategory": "CSC_BUILDING_BASES", + "autolearn": false, + "never_learn": true, + "construction_blueprint": "fbmc_radio_tower_migo_resin_shack_1", + "blueprint_provides": [ { "id": "fbmc_radio_tower_shack_1" } ], + "blueprint_excludes": [ { "id": "fbmc_radio_tower_shack_1" } ], + "blueprint_requires": [ { "id": "fbmc_radio_tower_shack_0" } ], + "blueprint_name": "mi-go resin shack" + }, + { + "type": "recipe", + "result": "faction_base_radio_tower_migo_resin_shack_2", + "description": "We need some shelter, so build a mi-go resin shack with a mi-go resin roof on the southwest corner of the camp.", + "category": "CC_BUILDING", + "subcategory": "CSC_BUILDING_BASES", + "autolearn": false, + "never_learn": true, + "construction_blueprint": "fbmc_radio_tower_migo_resin_shack_2", + "blueprint_provides": [ { "id": "fbmc_radio_tower_shack_2" } ], + "blueprint_excludes": [ { "id": "fbmc_radio_tower_shack_2" } ], + "blueprint_requires": [ { "id": "fbmc_radio_tower_shack_1" }, { "id": "fbmc_radio_tower_0" } ], + "blueprint_name": "mi-go resin shack" + }, + { + "type": "recipe", + "result": "faction_base_radio_tower_migo_resin_shack_3", + "description": "We need some shelter, so build a mi-go resin shack with a mi-go resin roof on the southwest side of the camp.", + "category": "CC_BUILDING", + "subcategory": "CSC_BUILDING_BASES", + "autolearn": false, + "never_learn": true, + "construction_blueprint": "fbmc_radio_tower_migo_resin_shack_3", + "blueprint_provides": [ { "id": "fbmc_radio_tower_shack_3" } ], + "blueprint_excludes": [ { "id": "fbmc_radio_tower_shack_3" } ], + "blueprint_requires": [ { "id": "fbmc_radio_tower_shack_2" } ], + "blueprint_name": "mi-go resin shack" + }, + { + "type": "recipe", + "result": "faction_base_radio_tower_migo_resin_shack_4", + "description": "We need some shelter, so build a mi-go resin shack with a mi-go resin roof on the southeast side of the camp.", + "category": "CC_BUILDING", + "subcategory": "CSC_BUILDING_BASES", + "autolearn": false, + "never_learn": true, + "construction_blueprint": "fbmc_radio_tower_migo_resin_shack_4", + "blueprint_provides": [ { "id": "fbmc_radio_tower_shack_4" } ], + "blueprint_excludes": [ { "id": "fbmc_radio_tower_shack_4" } ], + "blueprint_requires": [ { "id": "fbmc_radio_tower_shack_3" } ], + "blueprint_name": "mi-go resin shack" + }, + { + "type": "recipe", + "result": "faction_base_radio_tower_migo_resin_shack_5", + "description": "We need some shelter, so build a mi-go resin shack with a mi-go resin roof on the southeast corner of the camp.", + "category": "CC_BUILDING", + "subcategory": "CSC_BUILDING_BASES", + "autolearn": false, + "never_learn": true, + "construction_blueprint": "fbmc_radio_tower_migo_resin_shack_5", + "blueprint_provides": [ { "id": "fbmc_radio_tower_shack_5" } ], + "blueprint_excludes": [ { "id": "fbmc_radio_tower_shack_5" } ], + "blueprint_requires": [ { "id": "fbmc_radio_tower_shack_4" } ], + "blueprint_name": "mi-go resin shack" + }, + { + "type": "recipe", + "result": "faction_base_radio_tower_migo_resin_shack_6", + "description": "We need some shelter, so build a mi-go resin shack with a mi-go resin roof on the southeast corner of the camp.", + "category": "CC_BUILDING", + "subcategory": "CSC_BUILDING_BASES", + "autolearn": false, + "never_learn": true, + "construction_blueprint": "fbmc_radio_tower_migo_resin_shack_6", + "blueprint_provides": [ { "id": "fbmc_radio_tower_shack_6" } ], + "blueprint_excludes": [ { "id": "fbmc_radio_tower_shack_6" } ], + "blueprint_requires": [ { "id": "fbmc_radio_tower_shack_1" }, { "id": "fbmc_radio_tower_1" } ], + "blueprint_name": "mi-go resin shack" + }, + { + "type": "recipe", + "result": "faction_base_radio_tower_migo_resin_shack_7", + "description": "We need some shelter, so build a mi-go resin shack with a mi-go resin roof on the southwest corner of the camp.", + "category": "CC_BUILDING", + "subcategory": "CSC_BUILDING_BASES", + "autolearn": false, + "never_learn": true, + "construction_blueprint": "fbmc_radio_tower_migo_resin_shack_7", + "blueprint_provides": [ { "id": "fbmc_radio_tower_shack_7" } ], + "blueprint_excludes": [ { "id": "fbmc_radio_tower_shack_7" } ], + "blueprint_requires": [ { "id": "fbmc_radio_tower_shack_6" } ], + "blueprint_name": "mi-go resin shack" + }, + { + "type": "recipe", + "result": "faction_base_radio_tower_migo_resin_shack_8", + "description": "We need some shelter, so build a mi-go resin shack with a mi-go resin roof on the south side of the camp.", + "category": "CC_BUILDING", + "subcategory": "CSC_BUILDING_BASES", + "autolearn": false, + "never_learn": true, + "construction_blueprint": "fbmc_radio_tower_migo_resin_shack_8", + "blueprint_provides": [ { "id": "fbmc_radio_tower_shack_8" } ], + "blueprint_excludes": [ { "id": "fbmc_radio_tower_shack_8" } ], + "blueprint_requires": [ { "id": "fbmc_radio_tower_shack_7" } ], + "blueprint_name": "mi-go resin shack" + } +] \ No newline at end of file diff --git a/data/json/recipes/basecamps/fbmc_radio_tower/recipe_modular_radio_tower_rammed_earth.json b/data/json/recipes/basecamps/fbmc_radio_tower/recipe_modular_radio_tower_rammed_earth.json new file mode 100644 index 0000000000000..ae6a81a43a694 --- /dev/null +++ b/data/json/recipes/basecamps/fbmc_radio_tower/recipe_modular_radio_tower_rammed_earth.json @@ -0,0 +1,114 @@ +[ + { + "type": "recipe", + "result": "faction_base_radio_tower_rammed_earth_shack_1", + "description": "We need some shelter, so build a rammed earth shack with a sod roof on the northeast side of the camp.", + "category": "CC_BUILDING", + "subcategory": "CSC_BUILDING_BASES", + "autolearn": false, + "never_learn": true, + "construction_blueprint": "fbmc_radio_tower_rammed_earth_shack_1", + "blueprint_provides": [ { "id": "fbmc_radio_tower_shack_1" } ], + "blueprint_excludes": [ { "id": "fbmc_radio_tower_shack_1" } ], + "blueprint_requires": [ { "id": "fbmc_radio_tower_shack_0" } ], + "blueprint_name": "rammed earth shack" + }, + { + "type": "recipe", + "result": "faction_base_radio_tower_rammed_earth_shack_2", + "description": "We need some shelter, so build a rammed earth shack with a sod roof on the southwest corner of the camp.", + "category": "CC_BUILDING", + "subcategory": "CSC_BUILDING_BASES", + "autolearn": false, + "never_learn": true, + "construction_blueprint": "fbmc_radio_tower_rammed_earth_shack_2", + "blueprint_provides": [ { "id": "fbmc_radio_tower_shack_2" } ], + "blueprint_excludes": [ { "id": "fbmc_radio_tower_shack_2" } ], + "blueprint_requires": [ { "id": "fbmc_radio_tower_shack_1" }, { "id": "fbmc_radio_tower_0" } ], + "blueprint_name": "rammed earth shack" + }, + { + "type": "recipe", + "result": "faction_base_radio_tower_rammed_earth_shack_3", + "description": "We need some shelter, so build a rammed earth shack with a sod roof on the southwest side of the camp.", + "category": "CC_BUILDING", + "subcategory": "CSC_BUILDING_BASES", + "autolearn": false, + "never_learn": true, + "construction_blueprint": "fbmc_radio_tower_rammed_earth_shack_3", + "blueprint_provides": [ { "id": "fbmc_radio_tower_shack_3" } ], + "blueprint_excludes": [ { "id": "fbmc_radio_tower_shack_3" } ], + "blueprint_requires": [ { "id": "fbmc_radio_tower_shack_2" } ], + "blueprint_name": "rammed earth shack" + }, + { + "type": "recipe", + "result": "faction_base_radio_tower_rammed_earth_shack_4", + "description": "We need some shelter, so build a rammed earth shack with a sod roof on the southeast side of the camp.", + "category": "CC_BUILDING", + "subcategory": "CSC_BUILDING_BASES", + "autolearn": false, + "never_learn": true, + "construction_blueprint": "fbmc_radio_tower_rammed_earth_shack_4", + "blueprint_provides": [ { "id": "fbmc_radio_tower_shack_4" } ], + "blueprint_excludes": [ { "id": "fbmc_radio_tower_shack_4" } ], + "blueprint_requires": [ { "id": "fbmc_radio_tower_shack_3" } ], + "blueprint_name": "rammed earth shack" + }, + { + "type": "recipe", + "result": "faction_base_radio_tower_rammed_earth_shack_5", + "description": "We need some shelter, so build a rammed earth shack with a sod roof on the southeast corner of the camp.", + "category": "CC_BUILDING", + "subcategory": "CSC_BUILDING_BASES", + "autolearn": false, + "never_learn": true, + "construction_blueprint": "fbmc_radio_tower_rammed_earth_shack_5", + "blueprint_provides": [ { "id": "fbmc_radio_tower_shack_5" } ], + "blueprint_excludes": [ { "id": "fbmc_radio_tower_shack_5" } ], + "blueprint_requires": [ { "id": "fbmc_radio_tower_shack_4" } ], + "blueprint_name": "rammed earth shack" + }, + { + "type": "recipe", + "result": "faction_base_radio_tower_rammed_earth_shack_6", + "description": "We need some shelter, so build a rammed earth shack with a sod roof on the southeast corner of the camp.", + "category": "CC_BUILDING", + "subcategory": "CSC_BUILDING_BASES", + "autolearn": false, + "never_learn": true, + "construction_blueprint": "fbmc_radio_tower_rammed_earth_shack_6", + "blueprint_provides": [ { "id": "fbmc_radio_tower_shack_6" } ], + "blueprint_excludes": [ { "id": "fbmc_radio_tower_shack_6" } ], + "blueprint_requires": [ { "id": "fbmc_radio_tower_shack_1" }, { "id": "fbmc_radio_tower_1" } ], + "blueprint_name": "rammed earth shack" + }, + { + "type": "recipe", + "result": "faction_base_radio_tower_rammed_earth_shack_7", + "description": "We need some shelter, so build a rammed earth shack with a sod roof on the south side of the camp.", + "category": "CC_BUILDING", + "subcategory": "CSC_BUILDING_BASES", + "autolearn": false, + "never_learn": true, + "construction_blueprint": "fbmc_radio_tower_rammed_earth_shack_7", + "blueprint_provides": [ { "id": "fbmc_radio_tower_shack_7" } ], + "blueprint_excludes": [ { "id": "fbmc_radio_tower_shack_7" } ], + "blueprint_requires": [ { "id": "fbmc_radio_tower_shack_6" } ], + "blueprint_name": "rammed earth shack" + }, + { + "type": "recipe", + "result": "faction_base_radio_tower_rammed_earth_shack_8", + "description": "We need some shelter, so build a rammed earth shack with a sod roof on the southwest corner of the camp.", + "category": "CC_BUILDING", + "subcategory": "CSC_BUILDING_BASES", + "autolearn": false, + "never_learn": true, + "construction_blueprint": "fbmc_radio_tower_rammed_earth_shack_8", + "blueprint_provides": [ { "id": "fbmc_radio_tower_shack_8" } ], + "blueprint_excludes": [ { "id": "fbmc_radio_tower_shack_8" } ], + "blueprint_requires": [ { "id": "fbmc_radio_tower_shack_7" } ], + "blueprint_name": "rammed earth shack" + } +] \ No newline at end of file diff --git a/data/json/recipes/basecamps/fbmc_radio_tower/recipe_modular_radio_tower_rock.json b/data/json/recipes/basecamps/fbmc_radio_tower/recipe_modular_radio_tower_rock.json new file mode 100644 index 0000000000000..a897f8f0c4926 --- /dev/null +++ b/data/json/recipes/basecamps/fbmc_radio_tower/recipe_modular_radio_tower_rock.json @@ -0,0 +1,114 @@ +[ + { + "type": "recipe", + "result": "faction_base_radio_tower_rock_shack_1", + "description": "We need some shelter, so build a stone shack with a wooden roof on the northeast side of the camp.", + "category": "CC_BUILDING", + "subcategory": "CSC_BUILDING_BASES", + "autolearn": false, + "never_learn": true, + "construction_blueprint": "fbmc_radio_tower_rock_shack_1", + "blueprint_provides": [ { "id": "fbmc_radio_tower_shack_1" } ], + "blueprint_excludes": [ { "id": "fbmc_radio_tower_shack_1" } ], + "blueprint_requires": [ { "id": "fbmc_radio_tower_shack_0" } ], + "blueprint_name": "stone shack" + }, + { + "type": "recipe", + "result": "faction_base_radio_tower_rock_shack_2", + "description": "We need some shelter, so build a stone shack with a wooden roof on the southwest corner of the camp.", + "category": "CC_BUILDING", + "subcategory": "CSC_BUILDING_BASES", + "autolearn": false, + "never_learn": true, + "construction_blueprint": "fbmc_radio_tower_rock_shack_2", + "blueprint_provides": [ { "id": "fbmc_radio_tower_shack_2" } ], + "blueprint_excludes": [ { "id": "fbmc_radio_tower_shack_2" } ], + "blueprint_requires": [ { "id": "fbmc_radio_tower_shack_1" }, { "id": "fbmc_radio_tower_0" } ], + "blueprint_name": "stone shack" + }, + { + "type": "recipe", + "result": "faction_base_radio_tower_rock_shack_3", + "description": "We need some shelter, so build a stone shack with a wooden roof on the southwest side of the camp.", + "category": "CC_BUILDING", + "subcategory": "CSC_BUILDING_BASES", + "autolearn": false, + "never_learn": true, + "construction_blueprint": "fbmc_radio_tower_rock_shack_3", + "blueprint_provides": [ { "id": "fbmc_radio_tower_shack_3" } ], + "blueprint_excludes": [ { "id": "fbmc_radio_tower_shack_3" } ], + "blueprint_requires": [ { "id": "fbmc_radio_tower_shack_2" } ], + "blueprint_name": "stone shack" + }, + { + "type": "recipe", + "result": "faction_base_radio_tower_rock_shack_4", + "description": "We need some shelter, so build a stone shack with a wooden roof on the southeast side of the camp.", + "category": "CC_BUILDING", + "subcategory": "CSC_BUILDING_BASES", + "autolearn": false, + "never_learn": true, + "construction_blueprint": "fbmc_radio_tower_rock_shack_4", + "blueprint_provides": [ { "id": "fbmc_radio_tower_shack_4" } ], + "blueprint_excludes": [ { "id": "fbmc_radio_tower_shack_4" } ], + "blueprint_requires": [ { "id": "fbmc_radio_tower_shack_3" } ], + "blueprint_name": "stone shack" + }, + { + "type": "recipe", + "result": "faction_base_radio_tower_rock_shack_5", + "description": "We need some shelter, so build a stone shack with a wooden roof on the southeast corner of the camp.", + "category": "CC_BUILDING", + "subcategory": "CSC_BUILDING_BASES", + "autolearn": false, + "never_learn": true, + "construction_blueprint": "fbmc_radio_tower_rock_shack_5", + "blueprint_provides": [ { "id": "fbmc_radio_tower_shack_5" } ], + "blueprint_excludes": [ { "id": "fbmc_radio_tower_shack_5" } ], + "blueprint_requires": [ { "id": "fbmc_radio_tower_shack_4" } ], + "blueprint_name": "stone shack" + }, + { + "type": "recipe", + "result": "faction_base_radio_tower_rock_shack_6", + "description": "We need some shelter, so build a stone shack with a wooden roof on the southeast corner of the camp.", + "category": "CC_BUILDING", + "subcategory": "CSC_BUILDING_BASES", + "autolearn": false, + "never_learn": true, + "construction_blueprint": "fbmc_radio_tower_rock_shack_6", + "blueprint_provides": [ { "id": "fbmc_radio_tower_shack_6" } ], + "blueprint_excludes": [ { "id": "fbmc_radio_tower_shack_6" } ], + "blueprint_requires": [ { "id": "fbmc_radio_tower_shack_1" }, { "id": "fbmc_radio_tower_1" } ], + "blueprint_name": "stone shack" + }, + { + "type": "recipe", + "result": "faction_base_radio_tower_rock_shack_7", + "description": "We need some shelter, so build a stone shack with a wooden roof on the southwest corner of the camp.", + "category": "CC_BUILDING", + "subcategory": "CSC_BUILDING_BASES", + "autolearn": false, + "never_learn": true, + "construction_blueprint": "fbmc_radio_tower_rock_shack_7", + "blueprint_provides": [ { "id": "fbmc_radio_tower_shack_7" } ], + "blueprint_excludes": [ { "id": "fbmc_radio_tower_shack_7" } ], + "blueprint_requires": [ { "id": "fbmc_radio_tower_shack_6" } ], + "blueprint_name": "stone shack" + }, + { + "type": "recipe", + "result": "faction_base_radio_tower_rock_shack_8", + "description": "We need some shelter, so build a stone shack with a wooden roof on the south side of the camp.", + "category": "CC_BUILDING", + "subcategory": "CSC_BUILDING_BASES", + "autolearn": false, + "never_learn": true, + "construction_blueprint": "fbmc_radio_tower_rock_shack_8", + "blueprint_provides": [ { "id": "fbmc_radio_tower_shack_8" } ], + "blueprint_excludes": [ { "id": "fbmc_radio_tower_shack_8" } ], + "blueprint_requires": [ { "id": "fbmc_radio_tower_shack_7" } ], + "blueprint_name": "stone shack" + } +] \ No newline at end of file diff --git a/data/json/recipes/basecamps/fbmc_radio_tower/recipe_modular_radio_tower_wad.json b/data/json/recipes/basecamps/fbmc_radio_tower/recipe_modular_radio_tower_wad.json new file mode 100644 index 0000000000000..2742b3ecaa910 --- /dev/null +++ b/data/json/recipes/basecamps/fbmc_radio_tower/recipe_modular_radio_tower_wad.json @@ -0,0 +1,114 @@ +[ + { + "type": "recipe", + "result": "faction_base_radio_tower_wad_shack_1", + "description": "We need some shelter, so build a wattle and daub shack with a sod roof on the northeast side of the camp.", + "category": "CC_BUILDING", + "subcategory": "CSC_BUILDING_BASES", + "autolearn": false, + "never_learn": true, + "construction_blueprint": "fbmc_radio_tower_wad_shack_1", + "blueprint_provides": [ { "id": "fbmc_radio_tower_shack_1" } ], + "blueprint_excludes": [ { "id": "fbmc_radio_tower_shack_1" } ], + "blueprint_requires": [ { "id": "fbmc_radio_tower_shack_0" } ], + "blueprint_name": "wattle and daub shack" + }, + { + "type": "recipe", + "result": "faction_base_radio_tower_wad_shack_2", + "description": "We need some shelter, so build a wattle and daub shack with a sod roof on the southwest corner of the camp.", + "category": "CC_BUILDING", + "subcategory": "CSC_BUILDING_BASES", + "autolearn": false, + "never_learn": true, + "construction_blueprint": "fbmc_radio_tower_wad_shack_2", + "blueprint_provides": [ { "id": "fbmc_radio_tower_shack_2" } ], + "blueprint_excludes": [ { "id": "fbmc_radio_tower_shack_2" } ], + "blueprint_requires": [ { "id": "fbmc_radio_tower_shack_1" }, { "id": "fbmc_radio_tower_0" } ], + "blueprint_name": "wattle and daub shack" + }, + { + "type": "recipe", + "result": "faction_base_radio_tower_wad_shack_3", + "description": "We need some shelter, so build a wattle and daub shack with a sod roof on the southwest side of the camp.", + "category": "CC_BUILDING", + "subcategory": "CSC_BUILDING_BASES", + "autolearn": false, + "never_learn": true, + "construction_blueprint": "fbmc_radio_tower_wad_shack_3", + "blueprint_provides": [ { "id": "fbmc_radio_tower_shack_3" } ], + "blueprint_excludes": [ { "id": "fbmc_radio_tower_shack_3" } ], + "blueprint_requires": [ { "id": "fbmc_radio_tower_shack_2" } ], + "blueprint_name": "wattle and daub shack" + }, + { + "type": "recipe", + "result": "faction_base_radio_tower_wad_shack_4", + "description": "We need some shelter, so build a wattle and daub shack with a sod roof on the southeast side of the camp.", + "category": "CC_BUILDING", + "subcategory": "CSC_BUILDING_BASES", + "autolearn": false, + "never_learn": true, + "construction_blueprint": "fbmc_radio_tower_wad_shack_4", + "blueprint_provides": [ { "id": "fbmc_radio_tower_shack_4" } ], + "blueprint_excludes": [ { "id": "fbmc_radio_tower_shack_4" } ], + "blueprint_requires": [ { "id": "fbmc_radio_tower_shack_3" } ], + "blueprint_name": "wattle and daub shack" + }, + { + "type": "recipe", + "result": "faction_base_radio_tower_wad_shack_5", + "description": "We need some shelter, so build a wattle and daub shack with a sod roof on the southeast corner of the camp.", + "category": "CC_BUILDING", + "subcategory": "CSC_BUILDING_BASES", + "autolearn": false, + "never_learn": true, + "construction_blueprint": "fbmc_radio_tower_wad_shack_5", + "blueprint_provides": [ { "id": "fbmc_radio_tower_shack_5" } ], + "blueprint_excludes": [ { "id": "fbmc_radio_tower_shack_5" } ], + "blueprint_requires": [ { "id": "fbmc_radio_tower_shack_4" } ], + "blueprint_name": "wattle and daub shack" + }, + { + "type": "recipe", + "result": "faction_base_radio_tower_wad_shack_6", + "description": "We need some shelter, so build a wattle and daub shack with a sod roof on the southeast corner of the camp.", + "category": "CC_BUILDING", + "subcategory": "CSC_BUILDING_BASES", + "autolearn": false, + "never_learn": true, + "construction_blueprint": "fbmc_radio_tower_wad_shack_6", + "blueprint_provides": [ { "id": "fbmc_radio_tower_shack_6" } ], + "blueprint_excludes": [ { "id": "fbmc_radio_tower_shack_6" } ], + "blueprint_requires": [ { "id": "fbmc_radio_tower_shack_1" }, { "id": "fbmc_radio_tower_1" } ], + "blueprint_name": "wattle and daub shack" + }, + { + "type": "recipe", + "result": "faction_base_radio_tower_wad_shack_7", + "description": "We need some shelter, so build a wattle and daub shack with a sod roof on the southwest corner of the camp.", + "category": "CC_BUILDING", + "subcategory": "CSC_BUILDING_BASES", + "autolearn": false, + "never_learn": true, + "construction_blueprint": "fbmc_radio_tower_wad_shack_7", + "blueprint_provides": [ { "id": "fbmc_radio_tower_shack_7" } ], + "blueprint_excludes": [ { "id": "fbmc_radio_tower_shack_7" } ], + "blueprint_requires": [ { "id": "fbmc_radio_tower_shack_6" } ], + "blueprint_name": "wattle and daub shack" + }, + { + "type": "recipe", + "result": "faction_base_radio_tower_wad_shack_5", + "description": "We need some shelter, so build a wattle and daub shack with a sod roof on the south side of the camp.", + "category": "CC_BUILDING", + "subcategory": "CSC_BUILDING_BASES", + "autolearn": false, + "never_learn": true, + "construction_blueprint": "fbmc_radio_tower_wad_shack_8", + "blueprint_provides": [ { "id": "fbmc_radio_tower_shack_8" } ], + "blueprint_excludes": [ { "id": "fbmc_radio_tower_shack_8" } ], + "blueprint_requires": [ { "id": "fbmc_radio_tower_shack_7" } ], + "blueprint_name": "wattle and daub shack" + } +] \ No newline at end of file diff --git a/data/json/recipes/basecamps/fbmc_radio_tower/recipe_modular_radio_tower_wood.json b/data/json/recipes/basecamps/fbmc_radio_tower/recipe_modular_radio_tower_wood.json new file mode 100644 index 0000000000000..ccf4a3a225853 --- /dev/null +++ b/data/json/recipes/basecamps/fbmc_radio_tower/recipe_modular_radio_tower_wood.json @@ -0,0 +1,156 @@ +[ + { + "type": "recipe", + "result": "faction_base_radio_tower_1_controls_room_wood", + "description": "We need some shelter, so build wooden walls over windows in radio control's room.", + "category": "CC_BUILDING", + "subcategory": "CSC_BUILDING_BASES", + "autolearn": false, + "never_learn": true, + "construction_blueprint": "fbmc_radio_tower_controls_room_wood", + "blueprint_name": "barricade radio control's room", + "blueprint_provides": [ { "id": "fbmc_radio_tower_controls_room" }, { "id": "fbmc_radio_tower" } ], + "blueprint_requires": [ { "id": "fbmc_radio_tower_1" } ], + "blueprint_excludes": [ { "id": "fbmc_radio_tower_controls_room" } ] + }, + { + "type": "recipe", + "result": "faction_base_radio_tower_wood_shack_0", + "description": "We need some shelter, so build a wooden shack with a wooden roof inside radio tower.", + "category": "CC_BUILDING", + "subcategory": "CSC_BUILDING_BASES", + "autolearn": false, + "never_learn": true, + "construction_blueprint": "fbmc_radio_tower_wood_shack_0", + "blueprint_provides": [ { "id": "fbmc_radio_tower_shack_0" } ], + "blueprint_excludes": [ { "id": "fbmc_radio_tower_shack_0" } ], + "blueprint_requires": [ { "id": "fbmc_radio_tower" } ], + "blueprint_needs": { + "time": "40 h", + "skills": [ [ "fabrication", 3 ] ], + "inline": { + "qualities": [ [ { "id": "HAMMER", "level": 2 } ], [ { "id": "SAW_W", "level": 2 } ] ], + "components": [ + [ [ "2x4", 230 ] ], + [ [ "glass_sheet", 1 ] ], + [ [ "hinge", 2 ] ], + [ [ "nail", 1100 ] ], + [ [ "wood_panel", 54 ] ] + ] + } + }, + "blueprint_name": "wooden shack" + }, + { + "type": "recipe", + "result": "faction_base_radio_tower_wood_shack_1", + "description": "We need some shelter, so build a wooden shack with a wooden roof on the northeast side of the camp.", + "category": "CC_BUILDING", + "subcategory": "CSC_BUILDING_BASES", + "autolearn": false, + "never_learn": true, + "construction_blueprint": "fbmc_radio_tower_wood_shack_1", + "blueprint_provides": [ { "id": "fbmc_radio_tower_shack_1" } ], + "blueprint_excludes": [ { "id": "fbmc_radio_tower_shack_1" } ], + "blueprint_requires": [ { "id": "fbmc_radio_tower_shack_0" } ], + "blueprint_name": "wooden shack" + }, + { + "type": "recipe", + "result": "faction_base_radio_tower_wood_shack_2", + "description": "We need some shelter, so build a wooden shack with a wooden roof on the southwest corner of the camp.", + "category": "CC_BUILDING", + "subcategory": "CSC_BUILDING_BASES", + "autolearn": false, + "never_learn": true, + "construction_blueprint": "fbmc_radio_tower_wood_shack_2", + "blueprint_provides": [ { "id": "fbmc_radio_tower_shack_2" } ], + "blueprint_excludes": [ { "id": "fbmc_radio_tower_shack_2" } ], + "blueprint_requires": [ { "id": "fbmc_radio_tower_shack_1" }, { "id": "fbmc_radio_tower_0" } ], + "blueprint_name": "wooden shack" + }, + { + "type": "recipe", + "result": "faction_base_radio_tower_wood_shack_3", + "description": "We need some shelter, so build a wooden shack with a wooden roof on the southwest side of the camp.", + "category": "CC_BUILDING", + "subcategory": "CSC_BUILDING_BASES", + "autolearn": false, + "never_learn": true, + "construction_blueprint": "fbmc_radio_tower_wood_shack_3", + "blueprint_provides": [ { "id": "fbmc_radio_tower_shack_3" } ], + "blueprint_excludes": [ { "id": "fbmc_radio_tower_shack_3" } ], + "blueprint_requires": [ { "id": "fbmc_radio_tower_shack_2" } ], + "blueprint_name": "wooden shack" + }, + { + "type": "recipe", + "result": "faction_base_radio_tower_wood_shack_4", + "description": "We need some shelter, so build a wooden shack with a wooden roof on the southeast side of the camp.", + "category": "CC_BUILDING", + "subcategory": "CSC_BUILDING_BASES", + "autolearn": false, + "never_learn": true, + "construction_blueprint": "fbmc_radio_tower_wood_shack_4", + "blueprint_provides": [ { "id": "fbmc_radio_tower_shack_4" } ], + "blueprint_excludes": [ { "id": "fbmc_radio_tower_shack_4" } ], + "blueprint_requires": [ { "id": "fbmc_radio_tower_shack_3" } ], + "blueprint_name": "wooden shack" + }, + { + "type": "recipe", + "result": "faction_base_radio_tower_wood_shack_5", + "description": "We need some shelter, so build a wooden shack with a wooden roof on the southeast corner of the camp.", + "category": "CC_BUILDING", + "subcategory": "CSC_BUILDING_BASES", + "autolearn": false, + "never_learn": true, + "construction_blueprint": "fbmc_radio_tower_wood_shack_5", + "blueprint_provides": [ { "id": "fbmc_radio_tower_shack_5" } ], + "blueprint_excludes": [ { "id": "fbmc_radio_tower_shack_5" } ], + "blueprint_requires": [ { "id": "fbmc_radio_tower_shack_4" } ], + "blueprint_name": "wooden shack" + }, + { + "type": "recipe", + "result": "faction_base_radio_tower_wood_shack_6", + "description": "We need some shelter, so build a wooden shack with a wooden roof on the southeast corner of the camp.", + "category": "CC_BUILDING", + "subcategory": "CSC_BUILDING_BASES", + "autolearn": false, + "never_learn": true, + "construction_blueprint": "fbmc_radio_tower_wood_shack_6", + "blueprint_provides": [ { "id": "fbmc_radio_tower_shack_6" } ], + "blueprint_excludes": [ { "id": "fbmc_radio_tower_shack_6" } ], + "blueprint_requires": [ { "id": "fbmc_radio_tower_shack_1" }, { "id": "fbmc_radio_tower_1" } ], + "blueprint_name": "wooden shack" + }, + { + "type": "recipe", + "result": "faction_base_radio_tower_wood_shack_7", + "description": "We need some shelter, so build a wooden shack with a wooden roof on the southwest corner of the camp.", + "category": "CC_BUILDING", + "subcategory": "CSC_BUILDING_BASES", + "autolearn": false, + "never_learn": true, + "construction_blueprint": "fbmc_radio_tower_wood_shack_7", + "blueprint_provides": [ { "id": "fbmc_radio_tower_shack_7" } ], + "blueprint_excludes": [ { "id": "fbmc_radio_tower_shack_7" } ], + "blueprint_requires": [ { "id": "fbmc_radio_tower_shack_6" } ], + "blueprint_name": "wooden shack" + }, + { + "type": "recipe", + "result": "faction_base_radio_tower_wood_shack_8", + "description": "We need some shelter, so build a wooden shack with a wooden roof on the south side of the camp.", + "category": "CC_BUILDING", + "subcategory": "CSC_BUILDING_BASES", + "autolearn": false, + "never_learn": true, + "construction_blueprint": "fbmc_radio_tower_wood_shack_8", + "blueprint_provides": [ { "id": "fbmc_radio_tower_shack_8" } ], + "blueprint_excludes": [ { "id": "fbmc_radio_tower_shack_8" } ], + "blueprint_requires": [ { "id": "fbmc_radio_tower_shack_7" } ], + "blueprint_name": "wooden shack" + } +] \ No newline at end of file diff --git a/data/json/recipes/basecamps/recipe_groups.json b/data/json/recipes/basecamps/recipe_groups.json index 2140baa817029..744d0e7eebb8b 100644 --- a/data/json/recipes/basecamps/recipe_groups.json +++ b/data/json/recipes/basecamps/recipe_groups.json @@ -44,6 +44,16 @@ "id": "faction_base_mansion_+4_0", "description": "Mansion Garden With Columns Base", "om_terrains": [ "mansion_+4" ] + }, + { + "id": "faction_base_radio_tower_0", + "description": "Radio Tower Without Building Base", + "om_terrains": [ "radio_tower" ] + }, + { + "id": "faction_base_radio_tower_1_0", + "description": "Radio Tower With Building Base", + "om_terrains": [ "radio_tower_1" ] } ] }, @@ -338,7 +348,7 @@ { "type": "recipe_group", "id": "blacksmith_recipes_7", - "building_type": "SMITH", + "building_type": "BASE", "recipes": [ { "id": "sheet_metal_npc_drop", "description": " Craft: Sheet Metal, Drop Hammer" }, { "id": "chain_npc_drop", "description": " Craft: Chain, Drop Hammer" }, @@ -347,5 +357,33 @@ { "id": "pipe_npc_drop", "description": " Craft: Pipe, Drop Hammer" }, { "id": "rebar_npc_drop", "description": " Craft: Rebar, Drop Hammer" } ] + }, + { + "type": "recipe_group", + "id": "hack_recipes_general", + "building_type": "BASE", + "recipes": [ + { "id": "mobile_memory_card_npc_hack", "description": " Hack & Download: random data, SD-Memory card" }, + { "id": "software_useless_npc_hack", "description": " Hack & Download: misc software, USB drive" }, + { "id": "software_math_npc_hack", "description": " Hack & Download: MatheMAX, USB drive" } + ] + }, + { + "type": "recipe_group", + "id": "hack_recipes_science", + "building_type": "BASE", + "recipes": [ + { "id": "mobile_memory_card_science_npc_hack", "description": " Hack & Download: science data, SD-Memory card" }, + { "id": "software_medical_npc_hack", "description": " Hack & Download: MediSoft, USB drive" }, + { "id": "software_electronics_reference_npc_hack", "description": " Hack & Download: IC datasheet archives, USB drive" } + ] + }, + { + "type": "recipe_group", + "id": "hack_recipes_satellite", + "building_type": "BASE", + "recipes": [ + { "id": "satellitemap_npc_hack", "description": " Hack & Download: Satellite Map, traced" } + ] } ] diff --git a/data/json/recipes/recipe_companion.json b/data/json/recipes/recipe_companion.json index accf5343f7c67..57fcf081da7b3 100644 --- a/data/json/recipes/recipe_companion.json +++ b/data/json/recipes/recipe_companion.json @@ -107,5 +107,121 @@ "qualities": [ { "id": "ANVIL", "level": 3 }, { "id": "HAMMER", "level": 5 }, { "id": "CHISEL", "level": 3 } ], "tools": [ [ [ "tongs", -1 ] ], [ [ "swage", -1 ] ], [ [ "forge", 10 ], [ "oxy_torch", 2 ] ] ], "components": [ [ [ "scrap", 3 ] ] ] + }, + { + "type": "recipe", + "activity_level": "fake", + "result": "mobile_memory_card", + "id_suffix": "npc_hack", + "category": "CC_OTHER", + "subcategory": "CSC_OTHER_MATERIALS", + "skill_used": "computer", + "difficulty": 2, + "time": "60 m", + "autolearn": false, + "never_learn": true, + "skills_required": [ [ "computer", 2 ] ], + "tools": [ [ [ "laptop", 120 ] ] ], + "components": [ [ [ "mobile_memory_card_used", 1 ] ] ] + }, + { + "type": "recipe", + "activity_level": "fake", + "result": "software_useless", + "id_suffix": "npc_hack", + "category": "CC_OTHER", + "subcategory": "CSC_OTHER_MATERIALS", + "skill_used": "computer", + "difficulty": 3, + "time": "120 m", + "autolearn": false, + "never_learn": true, + "skills_required": [ [ "computer", 3 ] ], + "tools": [ [ [ "laptop", 240 ] ] ], + "components": [ [ [ "usb_drive", 1 ] ] ], + "container": "usb_drive" + }, + { + "type": "recipe", + "activity_level": "fake", + "result": "software_math", + "id_suffix": "npc_hack", + "category": "CC_OTHER", + "subcategory": "CSC_OTHER_MATERIALS", + "skill_used": "computer", + "difficulty": 4, + "time": "150 m", + "autolearn": false, + "never_learn": true, + "skills_required": [ [ "computer", 4 ] ], + "tools": [ [ [ "laptop", 300 ] ], [ [ "software_hacking", -1 ] ] ], + "components": [ [ [ "usb_drive", 1 ] ] ], + "container": "usb_drive" + }, + { + "type": "recipe", + "activity_level": "fake", + "result": "mobile_memory_card_science", + "id_suffix": "npc_hack", + "category": "CC_OTHER", + "subcategory": "CSC_OTHER_MATERIALS", + "skill_used": "computer", + "difficulty": 5, + "time": "180 m", + "autolearn": false, + "never_learn": true, + "skills_required": [ [ "computer", 5 ] ], + "tools": [ [ [ "laptop", 360 ] ], [ [ "software_hacking", -1 ] ] ], + "components": [ [ [ "mobile_memory_card_used", 1 ] ] ] + }, + { + "type": "recipe", + "activity_level": "fake", + "result": "software_medical", + "id_suffix": "npc_hack", + "category": "CC_OTHER", + "subcategory": "CSC_OTHER_MATERIALS", + "skill_used": "computer", + "difficulty": 5, + "time": "210 m", + "autolearn": false, + "never_learn": true, + "skills_required": [ [ "computer", 5 ] ], + "tools": [ [ [ "laptop", 420 ] ], [ [ "software_hacking", -1 ] ] ], + "components": [ [ [ "usb_drive", 1 ] ] ], + "container": "usb_drive" + }, + { + "type": "recipe", + "activity_level": "fake", + "result": "software_electronics_reference", + "id_suffix": "npc_hack", + "category": "CC_OTHER", + "subcategory": "CSC_OTHER_MATERIALS", + "skill_used": "computer", + "difficulty": 6, + "time": "240 m", + "autolearn": false, + "never_learn": true, + "skills_required": [ [ "computer", 6 ] ], + "tools": [ [ [ "laptop", 480 ] ], [ [ "software_hacking", -1 ] ] ], + "components": [ [ [ "usb_drive", 1 ] ] ], + "container": "usb_drive" + }, + { + "type": "recipe", + "activity_level": "fake", + "result": "satellitemap", + "id_suffix": "npc_hack", + "category": "CC_OTHER", + "subcategory": "CSC_OTHER_MATERIALS", + "skill_used": "computer", + "difficulty": 8, + "time": "480 m", + "autolearn": false, + "never_learn": true, + "skills_required": [ [ "computer", 8 ] ], + "tools": [ [ [ "laptop", 600 ] ], [ [ "pencil", 50 ] ], [ [ "software_hacking", -1 ] ] ], + "components": [ [ [ "paper", 25 ] ] ] } ] From 43c26a34e66fa2dfac959109869cd6ac6954afd9 Mon Sep 17 00:00:00 2001 From: krulunio Date: Thu, 20 May 2021 11:30:46 +0200 Subject: [PATCH 214/453] making recipe_groups.json more readable --- .../json/recipes/basecamps/recipe_groups.json | 90 ++++++++++++++----- 1 file changed, 68 insertions(+), 22 deletions(-) diff --git a/data/json/recipes/basecamps/recipe_groups.json b/data/json/recipes/basecamps/recipe_groups.json index 744d0e7eebb8b..ae6b3789f6536 100644 --- a/data/json/recipes/basecamps/recipe_groups.json +++ b/data/json/recipes/basecamps/recipe_groups.json @@ -4,7 +4,11 @@ "id": "all_faction_base_types", "building_type": "NONE", "recipes": [ - { "id": "faction_base_modular_hub_field_0", "description": "Field Camp", "om_terrains": [ "field" ] }, + { + "id": "faction_base_modular_hub_field_0", + "description": "Field Camp", + "om_terrains": [ "field" ] + }, { "id": "faction_base_firestation_0", "description": "Side Bunkroom Firestation Base", @@ -62,66 +66,108 @@ "id": "all_faction_base_expansions", "building_type": "NONE", "recipes": [ - { "id": "faction_base_farm_0", "description": "Farm", "om_terrains": [ "field" ] }, - { "id": "faction_base_garage_0", "description": "Garage", "om_terrains": [ "field" ] }, - { "id": "faction_base_canteen_0", "description": "Canteen", "om_terrains": [ "field" ] }, - { "id": "faction_base_livestock_0", "description": "Livestock Area", "om_terrains": [ "field" ] }, - { "id": "faction_base_storehouse_0", "description": "Central Storage Building", "om_terrains": [ "field" ] }, - { "id": "faction_base_saltworks_0", "description": "Saltworks Area", "om_terrains": [ "field" ] }, - { "id": "faction_base_workshop_0", "description": "Fabrication Workshop", "om_terrains": [ "field" ] }, - { "id": "faction_base_mansion_e1", + { + "id": "faction_base_farm_0", + "description": "Farm", + "om_terrains": [ "field" ] + }, + { + "id": "faction_base_garage_0", + "description": "Garage", + "om_terrains": [ "field" ] + }, + { + "id": "faction_base_canteen_0", + "description": "Canteen", + "om_terrains": [ "field" ] + }, + { + "id": "faction_base_livestock_0", + "description": "Livestock Area", + "om_terrains": [ "field" ] + }, + { + "id": "faction_base_storehouse_0", + "description": "Central Storage Building", + "om_terrains": [ "field" ] + }, + { + "id": "faction_base_saltworks_0", + "description": "Saltworks Area", + "om_terrains": [ "field" ] + }, + { + "id": "faction_base_workshop_0", + "description": "Fabrication Workshop", + "om_terrains": [ "field" ] + }, + { + "id": "faction_base_mansion_e1", "description": "Mansion's Entrance", "om_terrains": [ "mansion_e1" ] }, - { "id": "faction_base_mansion_e2", + { + "id": "faction_base_mansion_e2", "description": "Mansion's Entrance", "om_terrains": [ "mansion_e2" ] }, - { "id": "faction_base_mansion_t1", + { + "id": "faction_base_mansion_t1", "description": "Mansion's Swimming Pool", "om_terrains": [ "mansion_t1" ] }, - { "id": "faction_base_mansion_t2", + { + "id": "faction_base_mansion_t2", "description": "Mansion's Bedrooms", "om_terrains": [ "mansion_t2" ] }, - { "id": "faction_base_mansion_t3", + { + "id": "faction_base_mansion_t3", "description": "Mansion's ???", "om_terrains": [ "mansion_t3" ] }, - { "id": "faction_base_mansion_t4", + { + "id": "faction_base_mansion_t4", "description": "Mansion's Kitchen", "om_terrains": [ "mansion_t4" ] }, - { "id": "faction_base_mansion_t5", + { + "id": "faction_base_mansion_t5", "description": "Mansion's Library", "om_terrains": [ "mansion_t5" ] }, - { "id": "faction_base_mansion_t6", + { + "id": "faction_base_mansion_t6", "description": "Mansion's Bedroom", "om_terrains": [ "mansion_t6" ] }, - { "id": "faction_base_mansion_t7", + { + "id": "faction_base_mansion_t7", "description": "Mansion's Living Rooms", "om_terrains": [ "mansion_t7" ] }, - { "id": "faction_base_mansion_c1", + { + "id": "faction_base_mansion_c1", "description": "Mansion's Swimming Pool", "om_terrains": [ "mansion_c1" ] }, - { "id": "faction_base_mansion_c2", + { + "id": "faction_base_mansion_c2", "description": "Mansion's Bar", "om_terrains": [ "mansion_c2" ] }, - { "id": "faction_base_mansion_c3", + { + "id": "faction_base_mansion_c3", "description": "Mansion's Living Rooms", "om_terrains": [ "mansion_c3" ] }, - { "id": "faction_base_mansion_c4", + { + "id": "faction_base_mansion_c4", "description": "Mansion's Bedroom", "om_terrains": [ "mansion_c4" ] }, - { "id": "faction_base_mansion_c5", + { + "id": "faction_base_mansion_c5", "description": "Mansion's Kitchen", "om_terrains": [ "mansion_c5" ] } From d6145752a65be43c6bdd93bfccbe7d5a8edc924f Mon Sep 17 00:00:00 2001 From: krulunio Date: Thu, 20 May 2021 14:54:40 +0200 Subject: [PATCH 215/453] Revert "making recipe_groups.json more readable" This reverts commit 43c26a34e66fa2dfac959109869cd6ac6954afd9. --- .../json/recipes/basecamps/recipe_groups.json | 90 +++++-------------- 1 file changed, 22 insertions(+), 68 deletions(-) diff --git a/data/json/recipes/basecamps/recipe_groups.json b/data/json/recipes/basecamps/recipe_groups.json index ae6b3789f6536..744d0e7eebb8b 100644 --- a/data/json/recipes/basecamps/recipe_groups.json +++ b/data/json/recipes/basecamps/recipe_groups.json @@ -4,11 +4,7 @@ "id": "all_faction_base_types", "building_type": "NONE", "recipes": [ - { - "id": "faction_base_modular_hub_field_0", - "description": "Field Camp", - "om_terrains": [ "field" ] - }, + { "id": "faction_base_modular_hub_field_0", "description": "Field Camp", "om_terrains": [ "field" ] }, { "id": "faction_base_firestation_0", "description": "Side Bunkroom Firestation Base", @@ -66,108 +62,66 @@ "id": "all_faction_base_expansions", "building_type": "NONE", "recipes": [ - { - "id": "faction_base_farm_0", - "description": "Farm", - "om_terrains": [ "field" ] - }, - { - "id": "faction_base_garage_0", - "description": "Garage", - "om_terrains": [ "field" ] - }, - { - "id": "faction_base_canteen_0", - "description": "Canteen", - "om_terrains": [ "field" ] - }, - { - "id": "faction_base_livestock_0", - "description": "Livestock Area", - "om_terrains": [ "field" ] - }, - { - "id": "faction_base_storehouse_0", - "description": "Central Storage Building", - "om_terrains": [ "field" ] - }, - { - "id": "faction_base_saltworks_0", - "description": "Saltworks Area", - "om_terrains": [ "field" ] - }, - { - "id": "faction_base_workshop_0", - "description": "Fabrication Workshop", - "om_terrains": [ "field" ] - }, - { - "id": "faction_base_mansion_e1", + { "id": "faction_base_farm_0", "description": "Farm", "om_terrains": [ "field" ] }, + { "id": "faction_base_garage_0", "description": "Garage", "om_terrains": [ "field" ] }, + { "id": "faction_base_canteen_0", "description": "Canteen", "om_terrains": [ "field" ] }, + { "id": "faction_base_livestock_0", "description": "Livestock Area", "om_terrains": [ "field" ] }, + { "id": "faction_base_storehouse_0", "description": "Central Storage Building", "om_terrains": [ "field" ] }, + { "id": "faction_base_saltworks_0", "description": "Saltworks Area", "om_terrains": [ "field" ] }, + { "id": "faction_base_workshop_0", "description": "Fabrication Workshop", "om_terrains": [ "field" ] }, + { "id": "faction_base_mansion_e1", "description": "Mansion's Entrance", "om_terrains": [ "mansion_e1" ] }, - { - "id": "faction_base_mansion_e2", + { "id": "faction_base_mansion_e2", "description": "Mansion's Entrance", "om_terrains": [ "mansion_e2" ] }, - { - "id": "faction_base_mansion_t1", + { "id": "faction_base_mansion_t1", "description": "Mansion's Swimming Pool", "om_terrains": [ "mansion_t1" ] }, - { - "id": "faction_base_mansion_t2", + { "id": "faction_base_mansion_t2", "description": "Mansion's Bedrooms", "om_terrains": [ "mansion_t2" ] }, - { - "id": "faction_base_mansion_t3", + { "id": "faction_base_mansion_t3", "description": "Mansion's ???", "om_terrains": [ "mansion_t3" ] }, - { - "id": "faction_base_mansion_t4", + { "id": "faction_base_mansion_t4", "description": "Mansion's Kitchen", "om_terrains": [ "mansion_t4" ] }, - { - "id": "faction_base_mansion_t5", + { "id": "faction_base_mansion_t5", "description": "Mansion's Library", "om_terrains": [ "mansion_t5" ] }, - { - "id": "faction_base_mansion_t6", + { "id": "faction_base_mansion_t6", "description": "Mansion's Bedroom", "om_terrains": [ "mansion_t6" ] }, - { - "id": "faction_base_mansion_t7", + { "id": "faction_base_mansion_t7", "description": "Mansion's Living Rooms", "om_terrains": [ "mansion_t7" ] }, - { - "id": "faction_base_mansion_c1", + { "id": "faction_base_mansion_c1", "description": "Mansion's Swimming Pool", "om_terrains": [ "mansion_c1" ] }, - { - "id": "faction_base_mansion_c2", + { "id": "faction_base_mansion_c2", "description": "Mansion's Bar", "om_terrains": [ "mansion_c2" ] }, - { - "id": "faction_base_mansion_c3", + { "id": "faction_base_mansion_c3", "description": "Mansion's Living Rooms", "om_terrains": [ "mansion_c3" ] }, - { - "id": "faction_base_mansion_c4", + { "id": "faction_base_mansion_c4", "description": "Mansion's Bedroom", "om_terrains": [ "mansion_c4" ] }, - { - "id": "faction_base_mansion_c5", + { "id": "faction_base_mansion_c5", "description": "Mansion's Kitchen", "om_terrains": [ "mansion_c5" ] } From 50691322ac9708c981d62dba587dded94ade762f Mon Sep 17 00:00:00 2001 From: krulunio Date: Thu, 20 May 2021 14:54:56 +0200 Subject: [PATCH 216/453] Revert "Add radio tower basecamp and related stuff" This reverts commit a369270925e280d0128dc1aa9e66098d340a0704. --- data/json/items/book/maps.json | 23 - .../fbmc_radio_tower_beds.json | 202 ----- .../fbmc_radio_tower_common.json | 276 ------- .../fbmc_radio_tower_log.json | 80 -- .../fbmc_radio_tower_metal.json | 80 -- .../fbmc_radio_tower_migo_resin.json | 106 --- .../fbmc_radio_tower_rammed_earth.json | 80 -- .../fbmc_radio_tower_rock.json | 80 -- .../fbmc_radio_tower_wad.json | 80 -- .../fbmc_radio_tower_wood.json | 106 --- .../json/mapgen/basecamps/modular_shacks.json | 764 ------------------ .../recipe_modular_radio_tower_beds.json | 282 ------- .../recipe_modular_radio_tower_common.json | 229 ------ .../recipe_modular_radio_tower_log.json | 114 --- .../recipe_modular_radio_tower_metal.json | 114 --- ...recipe_modular_radio_tower_migo_resin.json | 153 ---- ...cipe_modular_radio_tower_rammed_earth.json | 114 --- .../recipe_modular_radio_tower_rock.json | 114 --- .../recipe_modular_radio_tower_wad.json | 114 --- .../recipe_modular_radio_tower_wood.json | 156 ---- .../json/recipes/basecamps/recipe_groups.json | 40 +- data/json/recipes/recipe_companion.json | 116 --- 22 files changed, 1 insertion(+), 3422 deletions(-) delete mode 100644 data/json/mapgen/basecamps/fbmc_radio_tower/fbmc_radio_tower_beds.json delete mode 100644 data/json/mapgen/basecamps/fbmc_radio_tower/fbmc_radio_tower_common.json delete mode 100644 data/json/mapgen/basecamps/fbmc_radio_tower/fbmc_radio_tower_log.json delete mode 100644 data/json/mapgen/basecamps/fbmc_radio_tower/fbmc_radio_tower_metal.json delete mode 100644 data/json/mapgen/basecamps/fbmc_radio_tower/fbmc_radio_tower_migo_resin.json delete mode 100644 data/json/mapgen/basecamps/fbmc_radio_tower/fbmc_radio_tower_rammed_earth.json delete mode 100644 data/json/mapgen/basecamps/fbmc_radio_tower/fbmc_radio_tower_rock.json delete mode 100644 data/json/mapgen/basecamps/fbmc_radio_tower/fbmc_radio_tower_wad.json delete mode 100644 data/json/mapgen/basecamps/fbmc_radio_tower/fbmc_radio_tower_wood.json delete mode 100644 data/json/mapgen/basecamps/modular_shacks.json delete mode 100644 data/json/recipes/basecamps/fbmc_radio_tower/recipe_modular_radio_tower_beds.json delete mode 100644 data/json/recipes/basecamps/fbmc_radio_tower/recipe_modular_radio_tower_common.json delete mode 100644 data/json/recipes/basecamps/fbmc_radio_tower/recipe_modular_radio_tower_log.json delete mode 100644 data/json/recipes/basecamps/fbmc_radio_tower/recipe_modular_radio_tower_metal.json delete mode 100644 data/json/recipes/basecamps/fbmc_radio_tower/recipe_modular_radio_tower_migo_resin.json delete mode 100644 data/json/recipes/basecamps/fbmc_radio_tower/recipe_modular_radio_tower_rammed_earth.json delete mode 100644 data/json/recipes/basecamps/fbmc_radio_tower/recipe_modular_radio_tower_rock.json delete mode 100644 data/json/recipes/basecamps/fbmc_radio_tower/recipe_modular_radio_tower_wad.json delete mode 100644 data/json/recipes/basecamps/fbmc_radio_tower/recipe_modular_radio_tower_wood.json diff --git a/data/json/items/book/maps.json b/data/json/items/book/maps.json index 48eb819c90fc5..0217ae0e222a4 100644 --- a/data/json/items/book/maps.json +++ b/data/json/items/book/maps.json @@ -165,28 +165,5 @@ ], "message": "You add roads and restaurants to your map." } - }, - { - "id": "satellitemap", - "copy-from": "abstractmap", - "type": "GENERIC", - "name": { "str": "satellite map" }, - "description": "This is a printed satellite map of the local area. Due to it's low quality and lack of map legend, you are unable to recognise most buildings. Using it will add terrain and roads to your map.", - "color": "gray", - "use_action": { - "type": "reveal_map", - "radius": 90, - "terrain": [ - "hiway", - "road", - "bridge", - "field", - "swamp", - "forest", - "lake", - "river" - ], - "message": "You add terrain and roads to your map." - } } ] diff --git a/data/json/mapgen/basecamps/fbmc_radio_tower/fbmc_radio_tower_beds.json b/data/json/mapgen/basecamps/fbmc_radio_tower/fbmc_radio_tower_beds.json deleted file mode 100644 index 245d0fcddb5a5..0000000000000 --- a/data/json/mapgen/basecamps/fbmc_radio_tower/fbmc_radio_tower_beds.json +++ /dev/null @@ -1,202 +0,0 @@ -[ - { - "type": "mapgen", - "update_mapgen_id": "fbmc_radio_tower_mattress_beds_controls_room", - "method": "json", - "object": { "place_nested": [ - { "chunks": [ "fbmc_mattress_bed_horizontal" ], "x": 15, "y": 12 }, - { "chunks": [ "fbmc_mattress_bed_horizontal" ], "x": 15, "y": 15 } - ] - } - }, - { - "type": "mapgen", - "update_mapgen_id": "fbmc_radio_tower_mattress_beds_0", - "method": "json", - "object": { "place_nested": [ - { "chunks": [ "fbmc_mattress_bed_vertical" ], "x": 11, "y": 4 }, - { "chunks": [ "fbmc_mattress_bed_vertical" ], "x": 14, "y": 4 } - ] - } - }, - { - "type": "mapgen", - "update_mapgen_id": "fbmc_radio_tower_mattress_beds_1", - "method": "json", - "object": { "place_nested": [ - { "chunks": [ "fbmc_mattress_bed_vertical" ], "x": 16, "y": 4 }, - { "chunks": [ "fbmc_mattress_bed_vertical" ], "x": 19, "y": 4 } - ] - } - }, - { - "type": "mapgen", - "update_mapgen_id": "fbmc_radio_tower_mattress_beds_2", - "method": "json", - "object": { "place_nested": [ - { "chunks": [ "fbmc_mattress_bed_vertical" ], "x": 2, "y": 18 }, - { "chunks": [ "fbmc_mattress_bed_vertical" ], "x": 5, "y": 18 } - ] - } - }, - { - "type": "mapgen", - "update_mapgen_id": "fbmc_radio_tower_mattress_beds_3", - "method": "json", - "object": { "place_nested": [ - { "chunks": [ "fbmc_mattress_bed_vertical" ], "x": 7, "y": 18 }, - { "chunks": [ "fbmc_mattress_bed_vertical" ], "x": 10, "y": 18 } - ] - } - }, - { - "type": "mapgen", - "update_mapgen_id": "fbmc_radio_tower_mattress_beds_4", - "method": "json", - "object": { "place_nested": [ - { "chunks": [ "fbmc_mattress_bed_vertical" ], "x": 12, "y": 18 }, - { "chunks": [ "fbmc_mattress_bed_vertical" ], "x": 15, "y": 18 } - ] - } - }, - { - "type": "mapgen", - "update_mapgen_id": "fbmc_radio_tower_mattress_beds_5", - "method": "json", - "object": { "place_nested": [ - { "chunks": [ "fbmc_mattress_bed_vertical" ], "x": 17, "y": 18 }, - { "chunks": [ "fbmc_mattress_bed_vertical" ], "x": 20, "y": 18 } - ] - } - }, - { - "type": "mapgen", - "update_mapgen_id": "fbmc_radio_tower_mattress_beds_6", - "method": "json", - "object": { "place_nested": [ - { "chunks": [ "fbmc_mattress_bed_horizontal" ], "x": 17, "y": 17 }, - { "chunks": [ "fbmc_mattress_bed_horizontal" ], "x": 17, "y": 20 } - ] - } - }, - { - "type": "mapgen", - "update_mapgen_id": "fbmc_radio_tower_mattress_beds_7", - "method": "json", - "object": { "place_nested": [ - { "chunks": [ "fbmc_mattress_bed_horizontal" ], "x": 4, "y": 11 }, - { "chunks": [ "fbmc_mattress_bed_horizontal" ], "x": 4, "y": 14 } - ] - } - }, - { - "type": "mapgen", - "update_mapgen_id": "fbmc_radio_tower_mattress_beds_8", - "method": "json", - "object": { "place_nested": [ - { "chunks": [ "fbmc_mattress_bed_horizontal" ], "x": 4, "y": 16 }, - { "chunks": [ "fbmc_mattress_bed_horizontal" ], "x": 4, "y": 19 } - ] - } - }, - { - "type": "mapgen", - "update_mapgen_id": "fbmc_radio_tower_straw_beds_controls_room", - "method": "json", - "object": { "place_nested": [ - { "chunks": [ "fbmc_straw_bed_horizontal" ], "x": 15, "y": 12 }, - { "chunks": [ "fbmc_straw_bed_horizontal" ], "x": 15, "y": 15 } - ] - } - }, - { - "type": "mapgen", - "update_mapgen_id": "fbmc_radio_tower_straw_beds_0", - "method": "json", - "object": { "place_nested": [ - { "chunks": [ "fbmc_straw_bed_vertical" ], "x": 11, "y": 4 }, - { "chunks": [ "fbmc_straw_bed_vertical" ], "x": 14, "y": 4 } - ] - } - }, - { - "type": "mapgen", - "update_mapgen_id": "fbmc_radio_tower_straw_beds_1", - "method": "json", - "object": { "place_nested": [ - { "chunks": [ "fbmc_straw_bed_vertical" ], "x": 16, "y": 4 }, - { "chunks": [ "fbmc_straw_bed_vertical" ], "x": 19, "y": 4 } - ] - } - }, - { - "type": "mapgen", - "update_mapgen_id": "fbmc_radio_tower_straw_beds_2", - "method": "json", - "object": { "place_nested": [ - { "chunks": [ "fbmc_straw_bed_vertical" ], "x": 2, "y": 18 }, - { "chunks": [ "fbmc_straw_bed_vertical" ], "x": 5, "y": 18 } - ] - } - }, - { - "type": "mapgen", - "update_mapgen_id": "fbmc_radio_tower_straw_beds_3", - "method": "json", - "object": { "place_nested": [ - { "chunks": [ "fbmc_straw_bed_vertical" ], "x": 7, "y": 18 }, - { "chunks": [ "fbmc_straw_bed_vertical" ], "x": 10, "y": 18 } - ] - } - }, - { - "type": "mapgen", - "update_mapgen_id": "fbmc_radio_tower_straw_beds_4", - "method": "json", - "object": { "place_nested": [ - { "chunks": [ "fbmc_straw_bed_vertical" ], "x": 12, "y": 18 }, - { "chunks": [ "fbmc_straw_bed_vertical" ], "x": 15, "y": 18 } - ] - } - }, - { - "type": "mapgen", - "update_mapgen_id": "fbmc_radio_tower_straw_beds_5", - "method": "json", - "object": { "place_nested": [ - { "chunks": [ "fbmc_straw_bed_vertical" ], "x": 17, "y": 18 }, - { "chunks": [ "fbmc_straw_bed_vertical" ], "x": 20, "y": 18 } - ] - } - }, - { - "type": "mapgen", - "update_mapgen_id": "fbmc_radio_tower_straw_beds_6", - "method": "json", - "object": { "place_nested": [ - { "chunks": [ "fbmc_straw_bed_horizontal" ], "x": 17, "y": 17 }, - { "chunks": [ "fbmc_straw_bed_horizontal" ], "x": 17, "y": 20 } - ] - } - }, - { - "type": "mapgen", - "update_mapgen_id": "fbmc_radio_tower_straw_beds_7", - "method": "json", - "object": { "place_nested": [ - { "chunks": [ "fbmc_straw_bed_horizontal" ], "x": 4, "y": 11 }, - { "chunks": [ "fbmc_straw_bed_horizontal" ], "x": 4, "y": 14 } - ] - } - }, - { - "type": "mapgen", - "update_mapgen_id": "fbmc_radio_tower_straw_beds_8", - "method": "json", - "object": { "place_nested": [ - { "chunks": [ "fbmc_straw_bed_horizontal" ], "x": 4, "y": 16 }, - { "chunks": [ "fbmc_straw_bed_horizontal" ], "x": 4, "y": 19 } - ] - } - } -] \ No newline at end of file diff --git a/data/json/mapgen/basecamps/fbmc_radio_tower/fbmc_radio_tower_common.json b/data/json/mapgen/basecamps/fbmc_radio_tower/fbmc_radio_tower_common.json deleted file mode 100644 index c44e8abf8fc50..0000000000000 --- a/data/json/mapgen/basecamps/fbmc_radio_tower/fbmc_radio_tower_common.json +++ /dev/null @@ -1,276 +0,0 @@ -[ - { - "type": "mapgen", - "update_mapgen_id": "fbmc_radio_tower_0", - "method": "json", - "object": { - "set": [ - { "point": "furniture", "id": "f_bulletin", "x": 9, "y": 8 } - ] - } - }, - { - "type": "mapgen", - "update_mapgen_id": "fbmc_radio_tower_1", - "method": "json", - "object": { - "set": [ - { "point": "furniture", "id": "f_bulletin", "x": 9, "y": 8 } - ] - } - }, - { - "type": "mapgen", - "update_mapgen_id": "fbmc_radio_tower_controls_room_wood", - "method": "json", - "object": { - "set": [ - { "point": "terrain", "id": "t_wall_wood", "x": 19, "y": 15 }, - { "point": "terrain", "id": "t_wall_wood", "x": 16, "y": 16 }, - { "point": "terrain", "id": "t_wall_wood", "x": 17, "y": 16 } - ] - } - }, - { - "type": "mapgen", - "update_mapgen_id": "fbmc_radio_tower_controls_room_migo_resin", - "method": "json", - "object": { - "set": [ - { "point": "terrain", "id": "t_wall_resin", "x": 19, "y": 15 }, - { "point": "terrain", "id": "t_wall_resin", "x": 16, "y": 16 }, - { "point": "terrain", "id": "t_wall_resin", "x": 17, "y": 16 } - ] - } - }, - { - "type": "mapgen", - "update_mapgen_id": "fbmc_radio_tower_fix_controls", - "method": "json", - "object": { - "set": [ - { "point": "furniture", "id": "f_null", "x": 0, "y": 0 } - ] - } - }, - { - "type": "mapgen", - "update_mapgen_id": "faction_base_radio_tower_fix_tower", - "method": "json", - "object": { - "set": [ - { "point": "furniture", "id": "f_null", "x": 0, "y": 0 } - ] - } - }, - { - "type": "mapgen", - "update_mapgen_id": "fbmc_radio_tower_root_cellar", - "method": "json", - "object": { - "set": [ - { "point": "terrain", "id": "t_rootcellar", "x": 19, "y": 9 } - ] - } - }, - { - "type": "mapgen", - "update_mapgen_id": "fbmc_radio_tower_water_well", - "method": "json", - "object": { - "set": [ - { "point": "terrain", "id": "t_water_pump", "x": 19, "y": 10 } - ] - } - }, - { - "type": "mapgen", - "nested_mapgen_id": "fbmc_radio_tower_0_prepalisade_nested", - "method": "json", - "object": { - "mapgensize": [ 24, 24 ], - "rows": [ - " ", - " ", - " ", - "pppppppppp ", - "p ", - "p ", - "p ", - "p ", - "p p ", - "p p ", - "p p ", - "p p ", - "p p ", - "p p ", - "p p ", - "p ", - " ", - " ", - " ", - " ", - " ", - " ", - " ", - " " - ], - "terrain": { - "p": "t_pit" - } - } - }, - { - "type": "mapgen", - "nested_mapgen_id": "fbmc_radio_tower_1_prepalisade_nested", - "method": "json", - "object": { - "mapgensize": [ 24, 24 ], - "rows": [ - "ppppppppppp ", - "p p ", - "p p ", - "p ", - "p ", - "p ", - "p ", - "p ", - "p ", - "p p ", - "p p ", - "p p ", - "ppp ", - " ", - " ", - " ", - " ", - " ", - " ", - " ", - " ", - " pppppp ", - " ", - " " - ], - "terrain": { - "p": "t_pit" - } - } - }, - { - "type": "mapgen", - "nested_mapgen_id": "fbmc_radio_tower_0_palisade_nested", - "method": "json", - "object": { - "mapgensize": [ 24, 24 ], - "rows": [ - " ", - " ", - " ", - "ppgggggggp ", - "p r ", - "p ", - "p ", - "p ", - "p p ", - "p p ", - "p p ", - "p p ", - "pr p ", - "g p ", - "g p ", - "p ", - " ", - " ", - " ", - " ", - " ", - " ", - " ", - " " - ], - "terrain": { - "p": "t_palisade", - "g": "t_palisade_gate", - "r": "t_palisade_pulley" - } - } - }, - { - "type": "mapgen", - "nested_mapgen_id": "fbmc_radio_tower_1_palisade_nested", - "method": "json", - "object": { - "mapgensize": [ 24, 24 ], - "rows": [ - "ppgggggggpp ", - "p rp ", - "p p ", - "p ", - "p ", - "p ", - "p ", - "p ", - "p ", - "p p ", - "p p ", - "p p ", - "ppp ", - " ", - " ", - " ", - " ", - " ", - " ", - " ", - " r ", - " ppgggp ", - " ", - " " - ], - "terrain": { - "p": "t_palisade", - "g": "t_palisade_gate", - "r": "t_palisade_pulley" - } - } - }, - { - "type": "mapgen", - "update_mapgen_id": "fbmc_radio_tower_0_prepalisade", - "method": "json", - "object": { "place_nested": [ - { "chunks": [ "fbmc_radio_tower_0_prepalisade_nested" ], "x": 0, "y": 0 } - ], - "place_items": [ { "x": 4, "y": 9, "item": "digging_soil_loam_50L", "chance": 99, "repeat": 870 } ] - } - }, - { - "type": "mapgen", - "update_mapgen_id": "fbmc_radio_tower_1_prepalisade", - "method": "json", - "object": { "place_nested": [ - { "chunks": [ "fbmc_radio_tower_1_prepalisade_nested" ], "x": 0, "y": 0 } - ], - "place_items": [ { "x": 4, "y": 9, "item": "digging_soil_loam_50L", "chance": 99, "repeat": 1080 } ] - } - }, - { - "type": "mapgen", - "update_mapgen_id": "fbmc_radio_tower_0_palisade", - "method": "json", - "object": { "place_nested": [ - { "chunks": [ "fbmc_radio_tower_0_palisade_nested" ], "x": 0, "y": 0 } - ] - } - }, - { - "type": "mapgen", - "update_mapgen_id": "fbmc_radio_tower_1_palisade", - "method": "json", - "object": { "place_nested": [ - { "chunks": [ "fbmc_radio_tower_1_palisade_nested" ], "x": 0, "y": 0 } - ] - } - } -] \ No newline at end of file diff --git a/data/json/mapgen/basecamps/fbmc_radio_tower/fbmc_radio_tower_log.json b/data/json/mapgen/basecamps/fbmc_radio_tower/fbmc_radio_tower_log.json deleted file mode 100644 index 3264b72d2a481..0000000000000 --- a/data/json/mapgen/basecamps/fbmc_radio_tower/fbmc_radio_tower_log.json +++ /dev/null @@ -1,80 +0,0 @@ -[ - { - "type": "mapgen", - "update_mapgen_id": "fbmc_radio_tower_log_shack_1", - "method": "json", - "object": { "place_nested": [ - { "chunks": [ "fbmc_log_shack_north" ], "x": 16, "y": 3 } - ] - } - }, - { - "type": "mapgen", - "update_mapgen_id": "fbmc_radio_tower_log_shack_2", - "method": "json", - "object": { "place_nested": [ - { "chunks": [ "fbmc_log_wall_vertical" ], "x": 1, "y": 15 }, - { "chunks": [ "fbmc_log_shack_south" ], "x": 2, "y": 15 } - ] - } - }, - { - "type": "mapgen", - "update_mapgen_id": "fbmc_radio_tower_log_shack_3", - "method": "json", - "object": { "place_nested": [ - { "chunks": [ "fbmc_log_shack_south" ], "x": 7, "y": 15 } - ] - } - }, - { - "type": "mapgen", - "update_mapgen_id": "fbmc_radio_tower_log_shack_4", - "method": "json", - "object": { "place_nested": [ - { "chunks": [ "fbmc_log_shack_south" ], "x": 12, "y": 15 } - ] - } - }, - { - "type": "mapgen", - "update_mapgen_id": "fbmc_radio_tower_log_shack_5", - "method": "json", - "object": { "place_nested": [ - { "chunks": [ "fbmc_log_shack_south" ], "x": 17, "y": 15 } - ] - } - }, - { - "type": "mapgen", - "update_mapgen_id": "fbmc_radio_tower_log_shack_6", - "method": "json", - "object": { "place_nested": [ - { "chunks": [ "fbmc_log_shack_west" ], "x": 14, "y": 17 } - ] - } - }, - { - "type": "mapgen", - "update_mapgen_id": "fbmc_radio_tower_log_shack_7", - "method": "json", - "object": { "place_nested": [ - { "chunks": [ "fbmc_log_wall_horizontal" ], "x": 3, "y": 10 }, - { "chunks": [ "fbmc_log_shack_east" ], "x": 3, "y": 11 } - ], - "set": [ - { "point": "terrain", "id": "t_dirt", "x": 9, "y": 13 }, - { "point": "terrain", "id": "t_dirt", "x": 11, "y": 16 } - ] - } - }, - { - "type": "mapgen", - "update_mapgen_id": "fbmc_radio_tower_log_shack_8", - "method": "json", - "object": { "place_nested": [ - { "chunks": [ "fbmc_log_shack_east" ], "x": 3, "y": 16 } - ] - } - } -] \ No newline at end of file diff --git a/data/json/mapgen/basecamps/fbmc_radio_tower/fbmc_radio_tower_metal.json b/data/json/mapgen/basecamps/fbmc_radio_tower/fbmc_radio_tower_metal.json deleted file mode 100644 index cabc9d56a3e4b..0000000000000 --- a/data/json/mapgen/basecamps/fbmc_radio_tower/fbmc_radio_tower_metal.json +++ /dev/null @@ -1,80 +0,0 @@ -[ - { - "type": "mapgen", - "update_mapgen_id": "fbmc_radio_tower_metal_shack_1", - "method": "json", - "object": { "place_nested": [ - { "chunks": [ "fbmc_metal_shack_north" ], "x": 16, "y": 3 } - ] - } - }, - { - "type": "mapgen", - "update_mapgen_id": "fbmc_radio_tower_metal_shack_2", - "method": "json", - "object": { "place_nested": [ - { "chunks": [ "fbmc_metal_wall_vertical" ], "x": 1, "y": 15 }, - { "chunks": [ "fbmc_metal_shack_south" ], "x": 2, "y": 15 } - ] - } - }, - { - "type": "mapgen", - "update_mapgen_id": "fbmc_radio_tower_metal_shack_3", - "method": "json", - "object": { "place_nested": [ - { "chunks": [ "fbmc_metal_shack_south" ], "x": 7, "y": 15 } - ] - } - }, - { - "type": "mapgen", - "update_mapgen_id": "fbmc_radio_tower_metal_shack_4", - "method": "json", - "object": { "place_nested": [ - { "chunks": [ "fbmc_metal_shack_south" ], "x": 12, "y": 15 } - ] - } - }, - { - "type": "mapgen", - "update_mapgen_id": "fbmc_radio_tower_metal_shack_5", - "method": "json", - "object": { "place_nested": [ - { "chunks": [ "fbmc_metal_shack_south" ], "x": 17, "y": 15 } - ] - } - }, - { - "type": "mapgen", - "update_mapgen_id": "fbmc_radio_tower_metal_shack_6", - "method": "json", - "object": { "place_nested": [ - { "chunks": [ "fbmc_metal_shack_west" ], "x": 14, "y": 17 } - ] - } - }, - { - "type": "mapgen", - "update_mapgen_id": "fbmc_radio_tower_metal_shack_7", - "method": "json", - "object": { "place_nested": [ - { "chunks": [ "fbmc_metal_wall_horizontal" ], "x": 3, "y": 10 }, - { "chunks": [ "fbmc_metal_shack_east" ], "x": 3, "y": 11 } - ], - "set": [ - { "point": "terrain", "id": "t_dirt", "x": 9, "y": 13 }, - { "point": "terrain", "id": "t_dirt", "x": 11, "y": 16 } - ] - } - }, - { - "type": "mapgen", - "update_mapgen_id": "fbmc_radio_tower_metal_shack_8", - "method": "json", - "object": { "place_nested": [ - { "chunks": [ "fbmc_metal_shack_east" ], "x": 3, "y": 16 } - ] - } - } -] \ No newline at end of file diff --git a/data/json/mapgen/basecamps/fbmc_radio_tower/fbmc_radio_tower_migo_resin.json b/data/json/mapgen/basecamps/fbmc_radio_tower/fbmc_radio_tower_migo_resin.json deleted file mode 100644 index fd2dcc807a607..0000000000000 --- a/data/json/mapgen/basecamps/fbmc_radio_tower/fbmc_radio_tower_migo_resin.json +++ /dev/null @@ -1,106 +0,0 @@ -[ - { - "type": "mapgen", - "method": "json", - "nested_mapgen_id": "fbmc_radio_tower_migo_resin_shack", - "object": { - "mapgensize": [ 6, 6 ], - "rows": [ - "wwwwww", - "w....w", - "w....w", - "w....w", - "w ...w", - "ww+vww" - ], - "palettes": [ "fbmh_migo_resin_palette" ] - } - }, - { - "type": "mapgen", - "update_mapgen_id": "fbmc_radio_tower_migo_resin_shack_0", - "method": "json", - "object": { "place_nested": [ - { "chunks": [ "fbmc_radio_tower_migo_resin_shack" ], "x": 10, "y": 3 } - ] - } - }, - { - "type": "mapgen", - "update_mapgen_id": "fbmc_radio_tower_migo_resin_shack_1", - "method": "json", - "object": { "place_nested": [ - { "chunks": [ "fbmc_migo_resin_shack_north" ], "x": 16, "y": 3 } - ] - } - }, - { - "type": "mapgen", - "update_mapgen_id": "fbmc_radio_tower_migo_resin_shack_2", - "method": "json", - "object": { "place_nested": [ - { "chunks": [ "fbmc_migo_resin_wall_vertical" ], "x": 1, "y": 15 }, - { "chunks": [ "fbmc_migo_resin_shack_south" ], "x": 2, "y": 15 } - ] - } - }, - { - "type": "mapgen", - "update_mapgen_id": "fbmc_radio_tower_migo_resin_shack_3", - "method": "json", - "object": { "place_nested": [ - { "chunks": [ "fbmc_migo_resin_shack_south" ], "x": 7, "y": 15 } - ] - } - }, - { - "type": "mapgen", - "update_mapgen_id": "fbmc_radio_tower_migo_resin_shack_4", - "method": "json", - "object": { "place_nested": [ - { "chunks": [ "fbmc_migo_resin_shack_south" ], "x": 12, "y": 15 } - ] - } - }, - { - "type": "mapgen", - "update_mapgen_id": "fbmc_radio_tower_migo_resin_shack_5", - "method": "json", - "object": { "place_nested": [ - { "chunks": [ "fbmc_migo_resin_shack_south" ], "x": 17, "y": 15 } - ] - } - }, - { - "type": "mapgen", - "update_mapgen_id": "fbmc_radio_tower_migo_resin_shack_6", - "method": "json", - "object": { "place_nested": [ - { "chunks": [ "fbmc_migo_resin_shack_west" ], "x": 14, "y": 17 } - ] - } - }, - { - "type": "mapgen", - "update_mapgen_id": "fbmc_radio_tower_migo_resin_shack_7", - "method": "json", - "object": { "place_nested": [ - { "chunks": [ "fbmc_migo_resin_wall_horizontal" ], "x": 3, "y": 10 }, - { "chunks": [ "fbmc_migo_resin_shack_east" ], "x": 3, "y": 11 } - ], - "set": [ - { "point": "terrain", "id": "t_dirt", "x": 9, "y": 13 }, - { "point": "terrain", "id": "t_dirt", "x": 11, "y": 16 } - ] - } - }, - { - "type": "mapgen", - "update_mapgen_id": "fbmc_radio_tower_migo_resin_shack_8", - "method": "json", - "object": { "place_nested": [ - { "chunks": [ "fbmc_migo_resin_shack_east" ], "x": 3, "y": 16 } - ] - } - } -] \ No newline at end of file diff --git a/data/json/mapgen/basecamps/fbmc_radio_tower/fbmc_radio_tower_rammed_earth.json b/data/json/mapgen/basecamps/fbmc_radio_tower/fbmc_radio_tower_rammed_earth.json deleted file mode 100644 index 79e63a3935373..0000000000000 --- a/data/json/mapgen/basecamps/fbmc_radio_tower/fbmc_radio_tower_rammed_earth.json +++ /dev/null @@ -1,80 +0,0 @@ -[ - { - "type": "mapgen", - "update_mapgen_id": "fbmc_radio_tower_rammed_earth_shack_1", - "method": "json", - "object": { "place_nested": [ - { "chunks": [ "fbmc_rammed_earth_shack_north" ], "x": 16, "y": 3 } - ] - } - }, - { - "type": "mapgen", - "update_mapgen_id": "fbmc_radio_tower_rammed_earth_shack_2", - "method": "json", - "object": { "place_nested": [ - { "chunks": [ "fbmc_rammed_earth_wall_vertical" ], "x": 1, "y": 15 }, - { "chunks": [ "fbmc_rammed_earth_shack_south" ], "x": 2, "y": 15 } - ] - } - }, - { - "type": "mapgen", - "update_mapgen_id": "fbmc_radio_tower_rammed_earth_shack_3", - "method": "json", - "object": { "place_nested": [ - { "chunks": [ "fbmc_rammed_earth_shack_south" ], "x": 7, "y": 15 } - ] - } - }, - { - "type": "mapgen", - "update_mapgen_id": "fbmc_radio_tower_rammed_earth_shack_4", - "method": "json", - "object": { "place_nested": [ - { "chunks": [ "fbmc_rammed_earth_shack_south" ], "x": 12, "y": 15 } - ] - } - }, - { - "type": "mapgen", - "update_mapgen_id": "fbmc_radio_tower_rammed_earth_shack_5", - "method": "json", - "object": { "place_nested": [ - { "chunks": [ "fbmc_rammed_earth_shack_south" ], "x": 17, "y": 15 } - ] - } - }, - { - "type": "mapgen", - "update_mapgen_id": "fbmc_radio_tower_rammed_earth_shack_6", - "method": "json", - "object": { "place_nested": [ - { "chunks": [ "fbmc_rammed_earth_shack_west" ], "x": 14, "y": 17 } - ] - } - }, - { - "type": "mapgen", - "update_mapgen_id": "fbmc_radio_tower_rammed_earth_shack_7", - "method": "json", - "object": { "place_nested": [ - { "chunks": [ "fbmc_rammed_earth_wall_horizontal" ], "x": 3, "y": 10 }, - { "chunks": [ "fbmc_rammed_earth_shack_east" ], "x": 3, "y": 11 } - ], - "set": [ - { "point": "terrain", "id": "t_dirt", "x": 9, "y": 13 }, - { "point": "terrain", "id": "t_dirt", "x": 11, "y": 16 } - ] - } - }, - { - "type": "mapgen", - "update_mapgen_id": "fbmc_radio_tower_rammed_earth_shack_8", - "method": "json", - "object": { "place_nested": [ - { "chunks": [ "fbmc_rammed_earth_shack_east" ], "x": 3, "y": 16 } - ] - } - } -] \ No newline at end of file diff --git a/data/json/mapgen/basecamps/fbmc_radio_tower/fbmc_radio_tower_rock.json b/data/json/mapgen/basecamps/fbmc_radio_tower/fbmc_radio_tower_rock.json deleted file mode 100644 index 04421a60520ea..0000000000000 --- a/data/json/mapgen/basecamps/fbmc_radio_tower/fbmc_radio_tower_rock.json +++ /dev/null @@ -1,80 +0,0 @@ -[ - { - "type": "mapgen", - "update_mapgen_id": "fbmc_radio_tower_rock_shack_1", - "method": "json", - "object": { "place_nested": [ - { "chunks": [ "fbmc_rock_shack_north" ], "x": 16, "y": 3 } - ] - } - }, - { - "type": "mapgen", - "update_mapgen_id": "fbmc_radio_tower_rock_shack_2", - "method": "json", - "object": { "place_nested": [ - { "chunks": [ "fbmc_rock_wall_vertical" ], "x": 1, "y": 15 }, - { "chunks": [ "fbmc_rock_shack_south" ], "x": 2, "y": 15 } - ] - } - }, - { - "type": "mapgen", - "update_mapgen_id": "fbmc_radio_tower_rock_shack_3", - "method": "json", - "object": { "place_nested": [ - { "chunks": [ "fbmc_rock_shack_south" ], "x": 7, "y": 15 } - ] - } - }, - { - "type": "mapgen", - "update_mapgen_id": "fbmc_radio_tower_rock_shack_4", - "method": "json", - "object": { "place_nested": [ - { "chunks": [ "fbmc_rock_shack_south" ], "x": 12, "y": 15 } - ] - } - }, - { - "type": "mapgen", - "update_mapgen_id": "fbmc_radio_tower_rock_shack_5", - "method": "json", - "object": { "place_nested": [ - { "chunks": [ "fbmc_rock_shack_south" ], "x": 17, "y": 15 } - ] - } - }, - { - "type": "mapgen", - "update_mapgen_id": "fbmc_radio_tower_rock_shack_6", - "method": "json", - "object": { "place_nested": [ - { "chunks": [ "fbmc_rock_shack_west" ], "x": 14, "y": 17 } - ] - } - }, - { - "type": "mapgen", - "update_mapgen_id": "fbmc_radio_tower_rock_shack_7", - "method": "json", - "object": { "place_nested": [ - { "chunks": [ "fbmc_rock_wall_horizontal" ], "x": 3, "y": 10 }, - { "chunks": [ "fbmc_rock_shack_east" ], "x": 3, "y": 11 } - ], - "set": [ - { "point": "terrain", "id": "t_dirt", "x": 9, "y": 13 }, - { "point": "terrain", "id": "t_dirt", "x": 11, "y": 16 } - ] - } - }, - { - "type": "mapgen", - "update_mapgen_id": "fbmc_radio_tower_rock_shack_8", - "method": "json", - "object": { "place_nested": [ - { "chunks": [ "fbmc_rock_shack_east" ], "x": 3, "y": 16 } - ] - } - } -] \ No newline at end of file diff --git a/data/json/mapgen/basecamps/fbmc_radio_tower/fbmc_radio_tower_wad.json b/data/json/mapgen/basecamps/fbmc_radio_tower/fbmc_radio_tower_wad.json deleted file mode 100644 index 69cc4a5016673..0000000000000 --- a/data/json/mapgen/basecamps/fbmc_radio_tower/fbmc_radio_tower_wad.json +++ /dev/null @@ -1,80 +0,0 @@ -[ - { - "type": "mapgen", - "update_mapgen_id": "fbmc_radio_tower_wad_shack_1", - "method": "json", - "object": { "place_nested": [ - { "chunks": [ "fbmc_wad_shack_north" ], "x": 16, "y": 3 } - ] - } - }, - { - "type": "mapgen", - "update_mapgen_id": "fbmc_radio_tower_wad_shack_2", - "method": "json", - "object": { "place_nested": [ - { "chunks": [ "fbmc_wad_wall_vertical" ], "x": 1, "y": 15 }, - { "chunks": [ "fbmc_wad_shack_south" ], "x": 2, "y": 15 } - ] - } - }, - { - "type": "mapgen", - "update_mapgen_id": "fbmc_radio_tower_wad_shack_3", - "method": "json", - "object": { "place_nested": [ - { "chunks": [ "fbmc_wad_shack_south" ], "x": 7, "y": 15 } - ] - } - }, - { - "type": "mapgen", - "update_mapgen_id": "fbmc_radio_tower_wad_shack_4", - "method": "json", - "object": { "place_nested": [ - { "chunks": [ "fbmc_wad_shack_south" ], "x": 12, "y": 15 } - ] - } - }, - { - "type": "mapgen", - "update_mapgen_id": "fbmc_radio_tower_wad_shack_5", - "method": "json", - "object": { "place_nested": [ - { "chunks": [ "fbmc_wad_shack_south" ], "x": 17, "y": 15 } - ] - } - }, - { - "type": "mapgen", - "update_mapgen_id": "fbmc_radio_tower_wad_shack_6", - "method": "json", - "object": { "place_nested": [ - { "chunks": [ "fbmc_wad_shack_west" ], "x": 14, "y": 17 } - ] - } - }, - { - "type": "mapgen", - "update_mapgen_id": "fbmc_radio_tower_wad_shack_7", - "method": "json", - "object": { "place_nested": [ - { "chunks": [ "fbmc_wad_wall_horizontal" ], "x": 3, "y": 10 }, - { "chunks": [ "fbmc_wad_shack_east" ], "x": 3, "y": 11 } - ], - "set": [ - { "point": "terrain", "id": "t_dirt", "x": 9, "y": 13 }, - { "point": "terrain", "id": "t_dirt", "x": 11, "y": 16 } - ] - } - }, - { - "type": "mapgen", - "update_mapgen_id": "fbmc_radio_tower_wad_shack_8", - "method": "json", - "object": { "place_nested": [ - { "chunks": [ "fbmc_wad_shack_east" ], "x": 3, "y": 16 } - ] - } - } -] \ No newline at end of file diff --git a/data/json/mapgen/basecamps/fbmc_radio_tower/fbmc_radio_tower_wood.json b/data/json/mapgen/basecamps/fbmc_radio_tower/fbmc_radio_tower_wood.json deleted file mode 100644 index 002ee406bf94e..0000000000000 --- a/data/json/mapgen/basecamps/fbmc_radio_tower/fbmc_radio_tower_wood.json +++ /dev/null @@ -1,106 +0,0 @@ -[ - { - "type": "mapgen", - "method": "json", - "nested_mapgen_id": "fbmc_radio_tower_wood_shack", - "object": { - "mapgensize": [ 6, 6 ], - "rows": [ - "wwwwww", - "w....w", - "w....w", - "w....w", - "w ...w", - "ww+vww" - ], - "palettes": [ "fbmh_wood_palette" ] - } - }, - { - "type": "mapgen", - "update_mapgen_id": "fbmc_radio_tower_wood_shack_0", - "method": "json", - "object": { "place_nested": [ - { "chunks": [ "fbmc_radio_tower_wood_shack" ], "x": 10, "y": 3 } - ] - } - }, - { - "type": "mapgen", - "update_mapgen_id": "fbmc_radio_tower_wood_shack_1", - "method": "json", - "object": { "place_nested": [ - { "chunks": [ "fbmc_wood_shack_north" ], "x": 16, "y": 3 } - ] - } - }, - { - "type": "mapgen", - "update_mapgen_id": "fbmc_radio_tower_wood_shack_2", - "method": "json", - "object": { "place_nested": [ - { "chunks": [ "fbmc_wood_wall_vertical" ], "x": 1, "y": 15 }, - { "chunks": [ "fbmc_wood_shack_south" ], "x": 2, "y": 15 } - ] - } - }, - { - "type": "mapgen", - "update_mapgen_id": "fbmc_radio_tower_wood_shack_3", - "method": "json", - "object": { "place_nested": [ - { "chunks": [ "fbmc_wood_shack_south" ], "x": 7, "y": 15 } - ] - } - }, - { - "type": "mapgen", - "update_mapgen_id": "fbmc_radio_tower_wood_shack_4", - "method": "json", - "object": { "place_nested": [ - { "chunks": [ "fbmc_wood_shack_south" ], "x": 12, "y": 15 } - ] - } - }, - { - "type": "mapgen", - "update_mapgen_id": "fbmc_radio_tower_wood_shack_5", - "method": "json", - "object": { "place_nested": [ - { "chunks": [ "fbmc_wood_shack_south" ], "x": 17, "y": 15 } - ] - } - }, - { - "type": "mapgen", - "update_mapgen_id": "fbmc_radio_tower_wood_shack_6", - "method": "json", - "object": { "place_nested": [ - { "chunks": [ "fbmc_wood_shack_west" ], "x": 14, "y": 17 } - ] - } - }, - { - "type": "mapgen", - "update_mapgen_id": "fbmc_radio_tower_wood_shack_7", - "method": "json", - "object": { "place_nested": [ - { "chunks": [ "fbmc_wood_wall_horizontal" ], "x": 3, "y": 10 }, - { "chunks": [ "fbmc_wood_shack_east" ], "x": 3, "y": 11 } - ], - "set": [ - { "point": "terrain", "id": "t_dirt", "x": 9, "y": 13 }, - { "point": "terrain", "id": "t_dirt", "x": 11, "y": 16 } - ] - } - }, - { - "type": "mapgen", - "update_mapgen_id": "fbmc_radio_tower_wood_shack_8", - "method": "json", - "object": { "place_nested": [ - { "chunks": [ "fbmc_wood_shack_east" ], "x": 3, "y": 16 } - ] - } - } -] \ No newline at end of file diff --git a/data/json/mapgen/basecamps/modular_shacks.json b/data/json/mapgen/basecamps/modular_shacks.json deleted file mode 100644 index 7086a52098f83..0000000000000 --- a/data/json/mapgen/basecamps/modular_shacks.json +++ /dev/null @@ -1,764 +0,0 @@ -[ - { - "type": "mapgen", - "method": "json", - "nested_mapgen_id": "fbmc_mattress_bed_horizontal", - "object": { - "mapgensize": [ 2, 2 ], - "set": [ - { "point": "furniture", "id": "f_bed", "x": 0, "y": 0 }, - { "point": "furniture", "id": "f_bed", "x": 1, "y": 0 } - ] - } - }, - { - "type": "mapgen", - "method": "json", - "nested_mapgen_id": "fbmc_mattress_bed_vertical", - "object": { - "mapgensize": [ 2, 2 ], - "set": [ - { "point": "furniture", "id": "f_bed", "x": 0, "y": 0 }, - { "point": "furniture", "id": "f_bed", "x": 0, "y": 1 } - ] - } - }, - { - "type": "mapgen", - "method": "json", - "nested_mapgen_id": "fbmc_straw_bed_horizontal", - "object": { - "mapgensize": [ 2, 2 ], - "set": [ - { "point": "furniture", "id": "f_straw_bed", "x": 0, "y": 0 }, - { "point": "furniture", "id": "f_straw_bed", "x": 1, "y": 0 } - ] - } - }, - { - "type": "mapgen", - "method": "json", - "nested_mapgen_id": "fbmc_straw_bed_vertical", - "object": { - "mapgensize": [ 2, 2 ], - "set": [ - { "point": "furniture", "id": "f_straw_bed", "x": 0, "y": 0 }, - { "point": "furniture", "id": "f_straw_bed", "x": 0, "y": 1 } - ] - } - }, - { - "type": "mapgen", - "method": "json", - "nested_mapgen_id": "fbmc_log_shack_north", - "object": { - "mapgensize": [ 6, 6 ], - "rows": [ - "wwwww ", - "....w ", - "....w ", - "....w ", - "....w ", - "w+vww " - ], - "palettes": [ "fbmh_log_palette" ] - } - }, - { - "type": "mapgen", - "method": "json", - "nested_mapgen_id": "fbmc_log_shack_south", - "object": { - "mapgensize": [ 6, 6 ], - "rows": [ - "w+vww ", - "....w ", - "....w ", - "....w ", - "....w ", - "wwwww " - ], - "palettes": [ "fbmh_log_palette" ] - } - }, - { - "type": "mapgen", - "method": "json", - "nested_mapgen_id": "fbmc_log_shack_west", - "object": { - "mapgensize": [ 6, 6 ], - "rows": [ - "w....w", - "v....w", - "+....w", - "w....w", - "wwwwww", - " " - ], - "palettes": [ "fbmh_log_palette" ] - } - }, - { - "type": "mapgen", - "method": "json", - "nested_mapgen_id": "fbmc_log_shack_east", - "object": { - "mapgensize": [ 6, 6 ], - "rows": [ - "w....w", - "w....v", - "w....+", - "w....w", - "wwwwww", - " " - ], - "palettes": [ "fbmh_log_palette" ] - } - }, - { - "type": "mapgen", - "method": "json", - "nested_mapgen_id": "fbmc_log_wall_horizontal", - "object": { - "mapgensize": [ 6, 6 ], - "rows": [ - "wwwwww", - " ", - " ", - " ", - " ", - " " - ], - "palettes": [ "fbmh_log_palette" ] - } - }, - { - "type": "mapgen", - "method": "json", - "nested_mapgen_id": "fbmc_log_wall_vertical", - "object": { - "mapgensize": [ 6, 6 ], - "rows": [ - "w ", - "w ", - "w ", - "w ", - "w ", - "w " - ], - "palettes": [ "fbmh_log_palette" ] - } - }, - { - "type": "mapgen", - "method": "json", - "nested_mapgen_id": "fbmc_metal_shack_north", - "object": { - "mapgensize": [ 6, 6 ], - "rows": [ - "wwwww ", - "....w ", - "....w ", - "....w ", - "....w ", - "w+vww " - ], - "palettes": [ "fbmh_metal_palette" ] - } - }, - { - "type": "mapgen", - "method": "json", - "nested_mapgen_id": "fbmc_metal_shack_south", - "object": { - "mapgensize": [ 6, 6 ], - "rows": [ - "w+vww ", - "....w ", - "....w ", - "....w ", - "....w ", - "wwwww " - ], - "palettes": [ "fbmh_metal_palette" ] - } - }, - { - "type": "mapgen", - "method": "json", - "nested_mapgen_id": "fbmc_metal_shack_west", - "object": { - "mapgensize": [ 6, 6 ], - "rows": [ - "w....w", - "v....w", - "+....w", - "w....w", - "wwwwww", - " " - ], - "palettes": [ "fbmh_metal_palette" ] - } - }, - { - "type": "mapgen", - "method": "json", - "nested_mapgen_id": "fbmc_metal_shack_east", - "object": { - "mapgensize": [ 6, 6 ], - "rows": [ - "w....w", - "w....v", - "w....+", - "w....w", - "wwwwww", - " " - ], - "palettes": [ "fbmh_metal_palette" ] - } - }, - { - "type": "mapgen", - "method": "json", - "nested_mapgen_id": "fbmc_metal_wall_horizontal", - "object": { - "mapgensize": [ 6, 6 ], - "rows": [ - "wwwwww", - " ", - " ", - " ", - " ", - " " - ], - "palettes": [ "fbmh_metal_palette" ] - } - }, - { - "type": "mapgen", - "method": "json", - "nested_mapgen_id": "fbmc_metal_wall_vertical", - "object": { - "mapgensize": [ 6, 6 ], - "rows": [ - "w ", - "w ", - "w ", - "w ", - "w ", - "w " - ], - "palettes": [ "fbmh_metal_palette" ] - } - }, - { - "type": "mapgen", - "method": "json", - "nested_mapgen_id": "fbmc_migo_resin_shack_north", - "object": { - "mapgensize": [ 6, 6 ], - "rows": [ - "wwwww ", - "....w ", - "....w ", - "....w ", - "....w ", - "w+vww " - ], - "palettes": [ "fbmh_migo_resin_palette" ] - } - }, - { - "type": "mapgen", - "method": "json", - "nested_mapgen_id": "fbmc_migo_resin_shack_south", - "object": { - "mapgensize": [ 6, 6 ], - "rows": [ - "w+vww ", - "....w ", - "....w ", - "....w ", - "....w ", - "wwwww " - ], - "palettes": [ "fbmh_migo_resin_palette" ] - } - }, - { - "type": "mapgen", - "method": "json", - "nested_mapgen_id": "fbmc_migo_resin_shack_west", - "object": { - "mapgensize": [ 6, 6 ], - "rows": [ - "w....w", - "v....w", - "+....w", - "w....w", - "wwwwww", - " " - ], - "palettes": [ "fbmh_migo_resin_palette" ] - } - }, - { - "type": "mapgen", - "method": "json", - "nested_mapgen_id": "fbmc_migo_resin_shack_east", - "object": { - "mapgensize": [ 6, 6 ], - "rows": [ - "w....w", - "w....v", - "w....+", - "w....w", - "wwwwww", - " " - ], - "palettes": [ "fbmh_migo_resin_palette" ] - } - }, - { - "type": "mapgen", - "method": "json", - "nested_mapgen_id": "fbmc_migo_resin_wall_horizontal", - "object": { - "mapgensize": [ 6, 6 ], - "rows": [ - "wwwwww", - " ", - " ", - " ", - " ", - " " - ], - "palettes": [ "fbmh_migo_resin_palette" ] - } - }, - { - "type": "mapgen", - "method": "json", - "nested_mapgen_id": "fbmc_migo_resin_wall_vertical", - "object": { - "mapgensize": [ 6, 6 ], - "rows": [ - "w ", - "w ", - "w ", - "w ", - "w ", - "w " - ], - "palettes": [ "fbmh_migo_resin_palette" ] - } - }, - { - "type": "mapgen", - "method": "json", - "nested_mapgen_id": "fbmc_rammed_earth_shack_north", - "object": { - "mapgensize": [ 6, 6 ], - "rows": [ - "wwwww ", - "....w ", - "....w ", - "....w ", - "....w ", - "w+vww " - ], - "palettes": [ "fbmh_rammed_earth_palette" ] - } - }, - { - "type": "mapgen", - "method": "json", - "nested_mapgen_id": "fbmc_rammed_earth_shack_south", - "object": { - "mapgensize": [ 6, 6 ], - "rows": [ - "w+vww ", - "....w ", - "....w ", - "....w ", - "....w ", - "wwwww " - ], - "palettes": [ "fbmh_rammed_earth_palette" ] - } - }, - { - "type": "mapgen", - "method": "json", - "nested_mapgen_id": "fbmc_rammed_earth_shack_west", - "object": { - "mapgensize": [ 6, 6 ], - "rows": [ - "w....w", - "v....w", - "+....w", - "w....w", - "wwwwww", - " " - ], - "palettes": [ "fbmh_rammed_earth_palette" ] - } - }, - { - "type": "mapgen", - "method": "json", - "nested_mapgen_id": "fbmc_rammed_earth_shack_east", - "object": { - "mapgensize": [ 6, 6 ], - "rows": [ - "w....w", - "w....v", - "w....+", - "w....w", - "wwwwww", - " " - ], - "palettes": [ "fbmh_rammed_earth_palette" ] - } - }, - { - "type": "mapgen", - "method": "json", - "nested_mapgen_id": "fbmc_rammed_earth_wall_horizontal", - "object": { - "mapgensize": [ 6, 6 ], - "rows": [ - "wwwwww", - " ", - " ", - " ", - " ", - " " - ], - "palettes": [ "fbmh_rammed_earth_palette" ] - } - }, - { - "type": "mapgen", - "method": "json", - "nested_mapgen_id": "fbmc_rammed_earth_wall_vertical", - "object": { - "mapgensize": [ 6, 6 ], - "rows": [ - "w ", - "w ", - "w ", - "w ", - "w ", - "w " - ], - "palettes": [ "fbmh_rammed_earth_palette" ] - } - }, - { - "type": "mapgen", - "method": "json", - "nested_mapgen_id": "fbmc_rock_shack_north", - "object": { - "mapgensize": [ 6, 6 ], - "rows": [ - "wwwww ", - "....w ", - "....w ", - "....w ", - "....w ", - "w+vww " - ], - "palettes": [ "fbmh_rock_palette" ] - } - }, - { - "type": "mapgen", - "method": "json", - "nested_mapgen_id": "fbmc_rock_shack_south", - "object": { - "mapgensize": [ 6, 6 ], - "rows": [ - "w+vww ", - "....w ", - "....w ", - "....w ", - "....w ", - "wwwww " - ], - "palettes": [ "fbmh_rock_palette" ] - } - }, - { - "type": "mapgen", - "method": "json", - "nested_mapgen_id": "fbmc_rock_shack_west", - "object": { - "mapgensize": [ 6, 6 ], - "rows": [ - "w....w", - "v....w", - "+....w", - "w....w", - "wwwwww", - " " - ], - "palettes": [ "fbmh_rock_palette" ] - } - }, - { - "type": "mapgen", - "method": "json", - "nested_mapgen_id": "fbmc_rock_shack_east", - "object": { - "mapgensize": [ 6, 6 ], - "rows": [ - "w....w", - "w....v", - "w....+", - "w....w", - "wwwwww", - " " - ], - "palettes": [ "fbmh_rock_palette" ] - } - }, - { - "type": "mapgen", - "method": "json", - "nested_mapgen_id": "fbmc_rock_wall_horizontal", - "object": { - "mapgensize": [ 6, 6 ], - "rows": [ - "wwwwww", - " ", - " ", - " ", - " ", - " " - ], - "palettes": [ "fbmh_rock_palette" ] - } - }, - { - "type": "mapgen", - "method": "json", - "nested_mapgen_id": "fbmc_rock_wall_vertical", - "object": { - "mapgensize": [ 6, 6 ], - "rows": [ - "w ", - "w ", - "w ", - "w ", - "w ", - "w " - ], - "palettes": [ "fbmh_rock_palette" ] - } - }, - { - "type": "mapgen", - "method": "json", - "nested_mapgen_id": "fbmc_wad_shack_north", - "object": { - "mapgensize": [ 6, 6 ], - "rows": [ - "wwwww ", - "....w ", - "....w ", - "....w ", - "....w ", - "w+vww " - ], - "palettes": [ "fbmh_wad_palette" ] - } - }, - { - "type": "mapgen", - "method": "json", - "nested_mapgen_id": "fbmc_wad_shack_south", - "object": { - "mapgensize": [ 6, 6 ], - "rows": [ - "w+vww ", - "....w ", - "....w ", - "....w ", - "....w ", - "wwwww " - ], - "palettes": [ "fbmh_wad_palette" ] - } - }, - { - "type": "mapgen", - "method": "json", - "nested_mapgen_id": "fbmc_wad_shack_west", - "object": { - "mapgensize": [ 6, 6 ], - "rows": [ - "w....w", - "v....w", - "+....w", - "w....w", - "wwwwww", - " " - ], - "palettes": [ "fbmh_wad_palette" ] - } - }, - { - "type": "mapgen", - "method": "json", - "nested_mapgen_id": "fbmc_wad_shack_east", - "object": { - "mapgensize": [ 6, 6 ], - "rows": [ - "w....w", - "w....v", - "w....+", - "w....w", - "wwwwww", - " " - ], - "palettes": [ "fbmh_wad_palette" ] - } - }, - { - "type": "mapgen", - "method": "json", - "nested_mapgen_id": "fbmc_wad_wall_horizontal", - "object": { - "mapgensize": [ 6, 6 ], - "rows": [ - "wwwwww", - " ", - " ", - " ", - " ", - " " - ], - "palettes": [ "fbmh_wad_palette" ] - } - }, - { - "type": "mapgen", - "method": "json", - "nested_mapgen_id": "fbmc_wad_wall_vertical", - "object": { - "mapgensize": [ 6, 6 ], - "rows": [ - "w ", - "w ", - "w ", - "w ", - "w ", - "w " - ], - "palettes": [ "fbmh_wad_palette" ] - } - }, - { - "type": "mapgen", - "method": "json", - "nested_mapgen_id": "fbmc_wood_shack_north", - "object": { - "mapgensize": [ 6, 6 ], - "rows": [ - "wwwww ", - "....w ", - "....w ", - "....w ", - "....w ", - "w+vww " - ], - "palettes": [ "fbmh_wood_palette" ] - } - }, - { - "type": "mapgen", - "method": "json", - "nested_mapgen_id": "fbmc_wood_shack_south", - "object": { - "mapgensize": [ 6, 6 ], - "rows": [ - "w+vww ", - "....w ", - "....w ", - "....w ", - "....w ", - "wwwww " - ], - "palettes": [ "fbmh_wood_palette" ] - } - }, - { - "type": "mapgen", - "method": "json", - "nested_mapgen_id": "fbmc_wood_shack_west", - "object": { - "mapgensize": [ 6, 6 ], - "rows": [ - "w....w", - "v....w", - "+....w", - "w....w", - "wwwwww", - " " - ], - "palettes": [ "fbmh_wood_palette" ] - } - }, - { - "type": "mapgen", - "method": "json", - "nested_mapgen_id": "fbmc_wood_shack_east", - "object": { - "mapgensize": [ 6, 6 ], - "rows": [ - "w....w", - "w....v", - "w....+", - "w....w", - "wwwwww", - " " - ], - "palettes": [ "fbmh_wood_palette" ] - } - }, - { - "type": "mapgen", - "method": "json", - "nested_mapgen_id": "fbmc_wood_wall_horizontal", - "object": { - "mapgensize": [ 6, 6 ], - "rows": [ - "wwwwww", - " ", - " ", - " ", - " ", - " " - ], - "palettes": [ "fbmh_wood_palette" ] - } - }, - { - "type": "mapgen", - "method": "json", - "nested_mapgen_id": "fbmc_wood_wall_vertical", - "object": { - "mapgensize": [ 6, 6 ], - "rows": [ - "w ", - "w ", - "w ", - "w ", - "w ", - "w " - ], - "palettes": [ "fbmh_wood_palette" ] - } - } -] \ No newline at end of file diff --git a/data/json/recipes/basecamps/fbmc_radio_tower/recipe_modular_radio_tower_beds.json b/data/json/recipes/basecamps/fbmc_radio_tower/recipe_modular_radio_tower_beds.json deleted file mode 100644 index d7dfb2c621c25..0000000000000 --- a/data/json/recipes/basecamps/fbmc_radio_tower/recipe_modular_radio_tower_beds.json +++ /dev/null @@ -1,282 +0,0 @@ -[ - { - "type": "recipe", - "result": "faction_base_radio_tower_mattress_beds_controls_room", - "description": "We should remove some of display racks and counters, then build a pair of mattress beds inside radio control's room for our survivors.", - "category": "CC_BUILDING", - "subcategory": "CSC_BUILDING_BASES", - "autolearn": false, - "never_learn": true, - "construction_blueprint": "fbmc_radio_tower_mattress_beds_controls_room", - "blueprint_provides": [ { "id": "fbmc_radio_tower_beds_controls_room" }, { "id": "bed", "amount": 2 } ], - "blueprint_excludes": [ { "id": "fbmc_radio_tower_beds_controls_room" } ], - "blueprint_requires": [ { "id": "fbmc_radio_tower_controls_room" } ], - "blueprint_name": "pair of mattress beds in radio control's room" - }, - { - "type": "recipe", - "result": "faction_base_radio_tower_mattress_beds_0", - "description": "We should build a pair of mattress beds inside radio tower shack for our survivors.", - "category": "CC_BUILDING", - "subcategory": "CSC_BUILDING_BASES", - "autolearn": false, - "never_learn": true, - "construction_blueprint": "fbmc_radio_tower_mattress_beds_0", - "blueprint_provides": [ { "id": "fbmc_radio_tower_beds_0" }, { "id": "bed", "amount": 2 } ], - "blueprint_excludes": [ { "id": "fbmc_radio_tower_beds_0" } ], - "blueprint_requires": [ { "id": "fbmc_radio_tower_shack_0" } ], - "blueprint_name": "pair of mattress beds in radio tower" - }, - { - "type": "recipe", - "result": "faction_base_radio_tower_mattress_beds_1", - "description": "We should build a pair of mattress beds in the northeast side shack for our survivors.", - "category": "CC_BUILDING", - "subcategory": "CSC_BUILDING_BASES", - "autolearn": false, - "never_learn": true, - "construction_blueprint": "fbmc_radio_tower_mattress_beds_1", - "blueprint_provides": [ { "id": "fbmc_radio_tower_beds_1" }, { "id": "bed", "amount": 2 } ], - "blueprint_excludes": [ { "id": "fbmc_radio_tower_beds_1" } ], - "blueprint_requires": [ { "id": "fbmc_radio_tower_shack_1" } ], - "blueprint_name": "pair of mattress beds in NE side shack" - }, - { - "type": "recipe", - "result": "faction_base_radio_tower_mattress_beds_2", - "description": "We should build a pair of mattress beds in the southwest corner shack for our survivors.", - "category": "CC_BUILDING", - "subcategory": "CSC_BUILDING_BASES", - "autolearn": false, - "never_learn": true, - "construction_blueprint": "fbmc_radio_tower_mattress_beds_2", - "blueprint_provides": [ { "id": "fbmc_radio_tower_beds_2" }, { "id": "bed", "amount": 2 } ], - "blueprint_excludes": [ { "id": "fbmc_radio_tower_beds_2" } ], - "blueprint_requires": [ { "id": "fbmc_radio_tower_shack_2" } ], - "blueprint_name": "pair of mattress beds in SW corner shack" - }, - { - "type": "recipe", - "result": "faction_base_radio_tower_mattress_beds_3", - "description": "We should build a pair of mattress beds in the southwest side shack for our survivors.", - "category": "CC_BUILDING", - "subcategory": "CSC_BUILDING_BASES", - "autolearn": false, - "never_learn": true, - "construction_blueprint": "fbmc_radio_tower_mattress_beds_3", - "blueprint_provides": [ { "id": "fbmc_radio_tower_beds_3" }, { "id": "bed", "amount": 2 } ], - "blueprint_excludes": [ { "id": "fbmc_radio_tower_beds_3" } ], - "blueprint_requires": [ { "id": "fbmc_radio_tower_shack_3" } ], - "blueprint_name": "pair of mattress beds in SW side shack" - }, - { - "type": "recipe", - "result": "faction_base_radio_tower_mattress_beds_4", - "description": "We should build a pair of mattress beds in the southeast side shack for our survivors.", - "category": "CC_BUILDING", - "subcategory": "CSC_BUILDING_BASES", - "autolearn": false, - "never_learn": true, - "construction_blueprint": "fbmc_radio_tower_mattress_beds_4", - "blueprint_provides": [ { "id": "fbmc_radio_tower_beds_4" }, { "id": "bed", "amount": 2 } ], - "blueprint_excludes": [ { "id": "fbmc_radio_tower_beds_4" } ], - "blueprint_requires": [ { "id": "fbmc_radio_tower_shack_4" } ], - "blueprint_name": "pair of mattress beds in SE side shack" - }, - { - "type": "recipe", - "result": "faction_base_radio_tower_mattress_beds_5", - "description": "We should build a pair of mattress beds in the southeast corner shack for our survivors.", - "category": "CC_BUILDING", - "subcategory": "CSC_BUILDING_BASES", - "autolearn": false, - "never_learn": true, - "construction_blueprint": "fbmc_radio_tower_mattress_beds_5", - "blueprint_provides": [ { "id": "fbmc_radio_tower_beds_5" }, { "id": "bed", "amount": 2 } ], - "blueprint_excludes": [ { "id": "fbmc_radio_tower_beds_5" } ], - "blueprint_requires": [ { "id": "fbmc_radio_tower_shack_5" } ], - "blueprint_name": "pair of mattress beds in SE corner shack" - }, - { - "type": "recipe", - "result": "faction_base_radio_tower_mattress_beds_6", - "description": "We should build a pair of mattress beds in the southeast corner shack for our survivors.", - "category": "CC_BUILDING", - "subcategory": "CSC_BUILDING_BASES", - "autolearn": false, - "never_learn": true, - "construction_blueprint": "fbmc_radio_tower_mattress_beds_6", - "blueprint_provides": [ { "id": "fbmc_radio_tower_beds_6" }, { "id": "bed", "amount": 2 } ], - "blueprint_excludes": [ { "id": "fbmc_radio_tower_beds_6" } ], - "blueprint_requires": [ { "id": "fbmc_radio_tower_shack_6" } ], - "blueprint_name": "pair of mattress beds in SE corner shack" - }, - { - "type": "recipe", - "result": "faction_base_radio_tower_mattress_beds_7", - "description": "We should build a pair of mattress beds in the southwest corner shack for our survivors.", - "category": "CC_BUILDING", - "subcategory": "CSC_BUILDING_BASES", - "autolearn": false, - "never_learn": true, - "construction_blueprint": "fbmc_radio_tower_mattress_beds_7", - "blueprint_provides": [ { "id": "fbmc_radio_tower_beds_7" }, { "id": "bed", "amount": 2 } ], - "blueprint_excludes": [ { "id": "fbmc_radio_tower_beds_7" } ], - "blueprint_requires": [ { "id": "fbmc_radio_tower_shack_7" } ], - "blueprint_name": "pair of mattress beds in SW corner shack" - }, - { - "type": "recipe", - "result": "faction_base_radio_tower_mattress_beds_8", - "description": "We should build a pair of mattress beds in the south side shack for our survivors.", - "category": "CC_BUILDING", - "subcategory": "CSC_BUILDING_BASES", - "autolearn": false, - "never_learn": true, - "construction_blueprint": "fbmc_radio_tower_mattress_beds_8", - "blueprint_provides": [ { "id": "fbmc_radio_tower_beds_8" }, { "id": "bed", "amount": 2 } ], - "blueprint_excludes": [ { "id": "fbmc_radio_tower_beds_8" } ], - "blueprint_requires": [ { "id": "fbmc_radio_tower_shack_8" } ], - "blueprint_name": "pair of mattress beds in S side shack" - }, - { - "type": "recipe", - "result": "faction_base_radio_tower_straw_beds_controls_room", - "description": "We should remove some of display racks and counters, then build a pair of straw beds inside radio control's room for our survivors.", - "category": "CC_BUILDING", - "subcategory": "CSC_BUILDING_BASES", - "autolearn": false, - "never_learn": true, - "construction_blueprint": "fbmc_radio_tower_straw_beds_controls_room", - "blueprint_provides": [ { "id": "fbmc_radio_tower_beds_controls_room" }, { "id": "bed", "amount": 2 } ], - "blueprint_excludes": [ { "id": "fbmc_radio_tower_beds_controls_room" } ], - "blueprint_requires": [ { "id": "fbmc_radio_tower_controls_room" } ], - "blueprint_name": "pair of straw beds in radio control's room" - }, - { - "type": "recipe", - "result": "faction_base_radio_tower_straw_beds_0", - "description": "We should build a pair of straw beds inside radio tower shack for our survivors.", - "category": "CC_BUILDING", - "subcategory": "CSC_BUILDING_BASES", - "autolearn": false, - "never_learn": true, - "construction_blueprint": "fbmc_radio_tower_straw_beds_0", - "blueprint_provides": [ { "id": "fbmc_radio_tower_beds_0" }, { "id": "bed", "amount": 2 } ], - "blueprint_excludes": [ { "id": "fbmc_radio_tower_beds_0" } ], - "blueprint_requires": [ { "id": "fbmc_radio_tower_shack_0" } ], - "blueprint_name": "pair of straw beds in radio tower" - }, - { - "type": "recipe", - "result": "faction_base_radio_tower_straw_beds_1", - "description": "We should build a pair of straw beds in the northeast side shack for our survivors.", - "category": "CC_BUILDING", - "subcategory": "CSC_BUILDING_BASES", - "autolearn": false, - "never_learn": true, - "construction_blueprint": "fbmc_radio_tower_straw_beds_1", - "blueprint_provides": [ { "id": "fbmc_radio_tower_beds_1" }, { "id": "bed", "amount": 2 } ], - "blueprint_excludes": [ { "id": "fbmc_radio_tower_beds_1" } ], - "blueprint_requires": [ { "id": "fbmc_radio_tower_shack_1" } ], - "blueprint_name": "pair of straw beds in NE side shack" - }, - { - "type": "recipe", - "result": "faction_base_radio_tower_straw_beds_2", - "description": "We should build a pair of straw beds in the southwest corner shack for our survivors.", - "category": "CC_BUILDING", - "subcategory": "CSC_BUILDING_BASES", - "autolearn": false, - "never_learn": true, - "construction_blueprint": "fbmc_radio_tower_straw_beds_2", - "blueprint_provides": [ { "id": "fbmc_radio_tower_beds_2" }, { "id": "bed", "amount": 2 } ], - "blueprint_excludes": [ { "id": "fbmc_radio_tower_beds_2" } ], - "blueprint_requires": [ { "id": "fbmc_radio_tower_shack_2" } ], - "blueprint_name": "pair of straw beds in SW corner shack" - }, - { - "type": "recipe", - "result": "faction_base_radio_tower_straw_beds_3", - "description": "We should build a pair of straw beds in the southwest side shack for our survivors.", - "category": "CC_BUILDING", - "subcategory": "CSC_BUILDING_BASES", - "autolearn": false, - "never_learn": true, - "construction_blueprint": "fbmc_radio_tower_straw_beds_3", - "blueprint_provides": [ { "id": "fbmc_radio_tower_beds_3" }, { "id": "bed", "amount": 2 } ], - "blueprint_excludes": [ { "id": "fbmc_radio_tower_beds_3" } ], - "blueprint_requires": [ { "id": "fbmc_radio_tower_shack_3" } ], - "blueprint_name": "pair of straw beds in SW side shack" - }, - { - "type": "recipe", - "result": "faction_base_radio_tower_straw_beds_4", - "description": "We should build a pair of straw beds in the southeast side shack for our survivors.", - "category": "CC_BUILDING", - "subcategory": "CSC_BUILDING_BASES", - "autolearn": false, - "never_learn": true, - "construction_blueprint": "fbmc_radio_tower_straw_beds_4", - "blueprint_provides": [ { "id": "fbmc_radio_tower_beds_4" }, { "id": "bed", "amount": 2 } ], - "blueprint_excludes": [ { "id": "fbmc_radio_tower_beds_4" } ], - "blueprint_requires": [ { "id": "fbmc_radio_tower_shack_4" } ], - "blueprint_name": "pair of straw beds in SE side shack" - }, - { - "type": "recipe", - "result": "faction_base_radio_tower_straw_beds_5", - "description": "We should build a pair of straw beds in the southeast corner shack for our survivors.", - "category": "CC_BUILDING", - "subcategory": "CSC_BUILDING_BASES", - "autolearn": false, - "never_learn": true, - "construction_blueprint": "fbmc_radio_tower_straw_beds_5", - "blueprint_provides": [ { "id": "fbmc_radio_tower_beds_5" }, { "id": "bed", "amount": 2 } ], - "blueprint_excludes": [ { "id": "fbmc_radio_tower_beds_5" } ], - "blueprint_requires": [ { "id": "fbmc_radio_tower_shack_5" } ], - "blueprint_name": "pair of straw beds in SE corner shack" - }, - { - "type": "recipe", - "result": "faction_base_radio_tower_straw_beds_6", - "description": "We should build a pair of straw beds in the southeast corner shack for our survivors.", - "category": "CC_BUILDING", - "subcategory": "CSC_BUILDING_BASES", - "autolearn": false, - "never_learn": true, - "construction_blueprint": "fbmc_radio_tower_straw_beds_6", - "blueprint_provides": [ { "id": "fbmc_radio_tower_beds_6" }, { "id": "bed", "amount": 2 } ], - "blueprint_excludes": [ { "id": "fbmc_radio_tower_beds_6" } ], - "blueprint_requires": [ { "id": "fbmc_radio_tower_shack_6" } ], - "blueprint_name": "pair of straw beds in SE corner shack" - }, - { - "type": "recipe", - "result": "faction_base_radio_tower_straw_beds_7", - "description": "We should build a pair of straw beds in the southwest corner shack for our survivors.", - "category": "CC_BUILDING", - "subcategory": "CSC_BUILDING_BASES", - "autolearn": false, - "never_learn": true, - "construction_blueprint": "fbmc_radio_tower_straw_beds_7", - "blueprint_provides": [ { "id": "fbmc_radio_tower_beds_7" }, { "id": "bed", "amount": 2 } ], - "blueprint_excludes": [ { "id": "fbmc_radio_tower_beds_7" } ], - "blueprint_requires": [ { "id": "fbmc_radio_tower_shack_7" } ], - "blueprint_name": "pair of straw beds in SW corner shack" - }, - { - "type": "recipe", - "result": "faction_base_radio_tower_straw_beds_8", - "description": "We should build a pair of straw beds in the south side shack for our survivors.", - "category": "CC_BUILDING", - "subcategory": "CSC_BUILDING_BASES", - "autolearn": false, - "never_learn": true, - "construction_blueprint": "fbmc_radio_tower_straw_beds_8", - "blueprint_provides": [ { "id": "fbmc_radio_tower_beds_8" }, { "id": "bed", "amount": 2 } ], - "blueprint_excludes": [ { "id": "fbmc_radio_tower_beds_8" } ], - "blueprint_requires": [ { "id": "fbmc_radio_tower_shack_8" } ], - "blueprint_name": "pair of straw beds in S side shack" - } -] \ No newline at end of file diff --git a/data/json/recipes/basecamps/fbmc_radio_tower/recipe_modular_radio_tower_common.json b/data/json/recipes/basecamps/fbmc_radio_tower/recipe_modular_radio_tower_common.json deleted file mode 100644 index ad97906f1fd6a..0000000000000 --- a/data/json/recipes/basecamps/fbmc_radio_tower/recipe_modular_radio_tower_common.json +++ /dev/null @@ -1,229 +0,0 @@ -[ - { - "type": "recipe", - "result": "faction_base_radio_tower_0", - "description": "We should survey the base site and set up a bulletin board.", - "category": "CC_BUILDING", - "subcategory": "CSC_BUILDING_BASES", - "skill_used": "fabrication", - "autolearn": false, - "never_learn": true, - "time": "1 h", - "construction_blueprint": "fbmc_radio_tower_0", - "blueprint_provides": [ - { "id": "fbmc_radio_tower_0" }, - { "id": "fbmc_radio_tower" }, - { "id": "primitive_camp_recipes_1" }, - { "id": "gathering" }, - { "id": "firewood" }, - { "id": "foraging" }, - { "id": "sorting" }, - { "id": "logging" } - ], - "blueprint_requires": [ { "id": "not_an_upgrade" } ], - "blueprint_name": "basic survey", - "check_blueprint_needs": false - }, - { - "type": "recipe", - "result": "faction_base_radio_tower_1_0", - "description": "We should survey the base site and set up a bulletin board.", - "category": "CC_BUILDING", - "subcategory": "CSC_BUILDING_BASES", - "skill_used": "fabrication", - "autolearn": false, - "never_learn": true, - "time": "1 h", - "construction_blueprint": "fbmc_radio_tower_1", - "blueprint_provides": [ - { "id": "fbmc_radio_tower_1" }, - { "id": "primitive_camp_recipes_1" }, - { "id": "gathering" }, - { "id": "firewood" }, - { "id": "foraging" }, - { "id": "sorting" }, - { "id": "logging" } - ], - "blueprint_requires": [ { "id": "not_an_upgrade" } ], - "blueprint_name": "basic survey", - "check_blueprint_needs": false - }, - { - "type": "recipe", - "result": "faction_base_radio_tower_root_cellar", - "description": "Digging a root cellar will give us a way to preserve food.", - "category": "CC_BUILDING", - "subcategory": "CSC_BUILDING_BASES", - "autolearn": false, - "never_learn": true, - "construction_blueprint": "fbmc_radio_tower_root_cellar", - "blueprint_name": "root cellar", - "blueprint_provides": [ { "id": "pantry" }, { "id": "fbmc_radio_tower_root_cellar" } ], - "blueprint_requires": [ { "id": "bed", "amount": 4 } ], - "blueprint_excludes": [ { "id": "fbmc_radio_tower_root_cellar" } ] - }, - { - "type": "recipe", - "result": "faction_base_radio_tower_water_well", - "description": "Digging a well will give us easy access to water.", - "category": "CC_BUILDING", - "subcategory": "CSC_BUILDING_BASES", - "autolearn": false, - "never_learn": true, - "construction_blueprint": "fbmc_radio_tower_water_well", - "blueprint_name": "water well", - "blueprint_provides": [ { "id": "fbmc_radio_tower_water_well" } ], - "blueprint_requires": [ { "id": "bed", "amount": 4 } ], - "blueprint_excludes": [ { "id": "fbmc_radio_tower_water_well" } ] - }, - { - "type": "recipe", - "result": "faction_base_radio_tower_fix_controls", - "description": "Let's fix up radio tower and controls to improve our recruitment efforts.", - "category": "CC_BUILDING", - "subcategory": "CSC_BUILDING_BASES", - "autolearn": false, - "never_learn": true, - "construction_blueprint": "fbmc_radio_tower_fix_controls", - "blueprint_name": "fix radio tower and controls", - "blueprint_requires": [ { "id": "fbmc_radio_tower_water_well" }, { "id": "fbmc_radio_tower_root_cellar" } ], - "blueprint_provides": [ { "id": "fbmc_radio_tower_fix_controls" }, { "id": "recruiting" }, { "id": "radio" } ], - "blueprint_excludes": [ { "id": "fbmc_radio_tower_fix_controls" } ], - "blueprint_needs": { - "time": "10 h", - "skills": [ [ "fabrication", 3 ] ], - "inline": { - "tools": [ ], - "qualities": [ [ { "id": "HAMMER", "level": 2 } ], [ { "id": "SAW_M" } ], [ { "id": "SCREW" } ], [ { "id": "WRENCH" } ] ], - "components": [ - [ - [ "wind_turbine", 4 ], - [ "xl_wind_turbine", 1 ], - [ "solar_panel", 4 ], - [ "reinforced_solar_panel", 4 ], - [ "solar_panel_v2", 2 ], - [ "reinforced_solar_panel_v2", 2 ] - ], - [ [ "storage_battery", 1 ], [ "medium_storage_battery", 4 ], [ "small_storage_battery", 32 ] ], - [ [ "processor", 1 ] ], - [ [ "RAM", 1 ] ], - [ [ "large_lcd_screen", 1 ] ], - [ [ "e_scrap", 2 ] ], - [ [ "circuit", 2 ] ], - [ [ "power_supply", 1 ] ], - [ [ "amplifier", 1 ] ], - [ [ "cable", 160 ] ] - ] - } - } - }, - { - "type": "recipe", - "result": "faction_base_radio_tower_0_prepalisade", - "description": "We should dig pits for palisade around camp.", - "category": "CC_BUILDING", - "subcategory": "CSC_BUILDING_BASES", - "autolearn": false, - "never_learn": true, - "construction_blueprint": "fbmc_radio_tower_0_prepalisade", - "blueprint_provides": [ - { "id": "fbmc_radio_tower_0_prepalisade" } - ], - "blueprint_requires": [ { "id": "fbmc_radio_tower_0" }, { "id": "fbmc_radio_tower_shack_5" } ], - "blueprint_excludes": [ { "id": "fbmc_radio_tower_prepalisade" } ], - "blueprint_name": "dig pits" - }, - { - "type": "recipe", - "result": "faction_base_radio_tower_1_prepalisade", - "description": "We should dig pits for palisade around camp.", - "category": "CC_BUILDING", - "subcategory": "CSC_BUILDING_BASES", - "autolearn": false, - "never_learn": true, - "construction_blueprint": "fbmc_radio_tower_1_prepalisade", - "blueprint_provides": [ - { "id": "fbmc_radio_tower_1_prepalisade" } - ], - "blueprint_requires": [ { "id": "fbmc_radio_tower_1" }, { "id": "fbmc_radio_tower_shack_8" } ], - "blueprint_excludes": [ { "id": "fbmc_radio_tower_prepalisade" } ], - "blueprint_name": "dig pits" - }, - { - "type": "recipe", - "result": "faction_base_radio_tower_0_palisade", - "description": "We should build palisade around camp.", - "category": "CC_BUILDING", - "subcategory": "CSC_BUILDING_BASES", - "autolearn": false, - "never_learn": true, - "construction_blueprint": "fbmc_radio_tower_0_palisade", - "blueprint_provides": [ - { "id": "fbmc_radio_tower_0_palisade" }, { "id": "fbmc_radio_tower_palisade" } - ], - "blueprint_requires": [ { "id": "fbmc_radio_tower_0_prepalisade" } ], - "blueprint_excludes": [ { "id": "fbmc_radio_tower_palisade" } ], - "blueprint_name": "build palisade" - }, - { - "type": "recipe", - "result": "faction_base_radio_tower_1_palisade", - "description": "We should dig pits for palisade around camp.", - "category": "CC_BUILDING", - "subcategory": "CSC_BUILDING_BASES", - "autolearn": false, - "never_learn": true, - "construction_blueprint": "fbmc_radio_tower_1_palisade", - "blueprint_provides": [ - { "id": "fbmc_radio_tower_1_palisade" }, { "id": "fbmc_radio_tower_palisade" } - ], - "blueprint_requires": [ { "id": "fbmc_radio_tower_1_prepalisade" } ], - "blueprint_excludes": [ { "id": "fbmc_radio_tower_palisade" } ], - "blueprint_name": "build palisade" - }, - { - "type": "recipe", - "result": "faction_base_radio_tower_fix_tower", - "description": "We could try to fix whole tower and supply it with enough power, which could give us remote access to computer systems connected to backbone network or communication satellites.", - "category": "CC_BUILDING", - "subcategory": "CSC_BUILDING_BASES", - "autolearn": false, - "never_learn": true, - "construction_blueprint": "faction_base_radio_tower_fix_tower", - "blueprint_name": "fix whole radio tower", - "blueprint_requires": [ { "id": "bed", "amount": 12 }, { "id": "fbmc_radio_tower_palisade" }, { "id": "fbmc_radio_tower_fix_controls" } ], - "blueprint_provides": [ { "id": "faction_base_radio_tower_fix_tower" }, { "id": "hack_recipes_general" }, { "id": "hack_recipes_science" }, { "id": "hack_recipes_satellite" } ], - "blueprint_excludes": [ { "id": "faction_base_radio_tower_fix_tower" } ], - "using": [ [ "soldering_standard", 200 ], [ "welding_standard", 80 ] ], - "blueprint_needs": { - "time": "3 d", - "skills": [ [ "fabrication", 3 ], [ "computer", 4 ], [ "electronics", 8 ] ], - "inline": { - "tools": [ [ [ "laptop", 600 ] ], [ [ "radio_book", -1 ] ] ], - "qualities": [ [ { "id": "HAMMER", "level": 2 } ], [ { "id": "SAW_M" } ], [ { "id": "SCREW", "level": 2 } ], [ { "id": "SCREW_FINE" } ], [ { "id": "WRENCH", "level": 2 } ], [ { "id": "WRENCH_FINE" } ], [ { "id": "GLARE", "level": 2 } ] ], - "components": [ - [ - [ "wind_turbine", 16 ], - [ "xl_wind_turbine", 4 ], - [ "solar_panel", 16 ], - [ "reinforced_solar_panel", 16 ], - [ "solar_panel_v2", 8 ], - [ "reinforced_solar_panel_v2", 8 ] - ], - [ [ "storage_battery", 4 ], [ "medium_storage_battery", 16 ] ], - [ [ "sheet_metal", 8 ], [ "wire", 32 ] ], - [ [ "pipe", 24 ] ], - [ [ "processor", 16 ] ], - [ [ "RAM", 16 ] ], - [ [ "e_scrap", 40 ] ], - [ [ "frame", 1 ] ], - [ [ "circuit", 32 ] ], - [ [ "power_supply", 16 ] ], - [ [ "amplifier", 16 ] ], - [ [ "cable", 400 ] ], - [ [ "software_electronics_reference", 1 ] ] - ] - } - } - } -] diff --git a/data/json/recipes/basecamps/fbmc_radio_tower/recipe_modular_radio_tower_log.json b/data/json/recipes/basecamps/fbmc_radio_tower/recipe_modular_radio_tower_log.json deleted file mode 100644 index baee6307f949b..0000000000000 --- a/data/json/recipes/basecamps/fbmc_radio_tower/recipe_modular_radio_tower_log.json +++ /dev/null @@ -1,114 +0,0 @@ -[ - { - "type": "recipe", - "result": "faction_base_radio_tower_log_shack_1", - "description": "We need some shelter, so build a log shack with a wooden roof on the northeast side of the camp.", - "category": "CC_BUILDING", - "subcategory": "CSC_BUILDING_BASES", - "autolearn": false, - "never_learn": true, - "construction_blueprint": "fbmc_radio_tower_log_shack_1", - "blueprint_provides": [ { "id": "fbmc_radio_tower_shack_1" } ], - "blueprint_excludes": [ { "id": "fbmc_radio_tower_shack_1" } ], - "blueprint_requires": [ { "id": "fbmc_radio_tower_shack_0" } ], - "blueprint_name": "log shack" - }, - { - "type": "recipe", - "result": "faction_base_radio_tower_log_shack_2", - "description": "We need some shelter, so build a log shack with a wooden roof on the northeast side of the camp.", - "category": "CC_BUILDING", - "subcategory": "CSC_BUILDING_BASES", - "autolearn": false, - "never_learn": true, - "construction_blueprint": "fbmc_radio_tower_log_shack_2", - "blueprint_provides": [ { "id": "fbmc_radio_tower_shack_2" } ], - "blueprint_excludes": [ { "id": "fbmc_radio_tower_shack_2" } ], - "blueprint_requires": [ { "id": "fbmc_radio_tower_shack_1" }, { "id": "fbmc_radio_tower_0" } ], - "blueprint_name": "log shack" - }, - { - "type": "recipe", - "result": "faction_base_radio_tower_log_shack_3", - "description": "We need some shelter, so build a log shack with a wooden roof on the northeast side of the camp.", - "category": "CC_BUILDING", - "subcategory": "CSC_BUILDING_BASES", - "autolearn": false, - "never_learn": true, - "construction_blueprint": "fbmc_radio_tower_log_shack_3", - "blueprint_provides": [ { "id": "fbmc_radio_tower_shack_3" } ], - "blueprint_excludes": [ { "id": "fbmc_radio_tower_shack_3" } ], - "blueprint_requires": [ { "id": "fbmc_radio_tower_shack_2" } ], - "blueprint_name": "log shack" - }, - { - "type": "recipe", - "result": "faction_base_radio_tower_log_shack_4", - "description": "We need some shelter, so build a log shack with a wooden roof on the northeast side of the camp.", - "category": "CC_BUILDING", - "subcategory": "CSC_BUILDING_BASES", - "autolearn": false, - "never_learn": true, - "construction_blueprint": "fbmc_radio_tower_log_shack_4", - "blueprint_provides": [ { "id": "fbmc_radio_tower_shack_4" } ], - "blueprint_excludes": [ { "id": "fbmc_radio_tower_shack_4" } ], - "blueprint_requires": [ { "id": "fbmc_radio_tower_shack_3" } ], - "blueprint_name": "log shack" - }, - { - "type": "recipe", - "result": "faction_base_radio_tower_log_shack_5", - "description": "We need some shelter, so build a log shack with a wooden roof on the northeast side of the camp.", - "category": "CC_BUILDING", - "subcategory": "CSC_BUILDING_BASES", - "autolearn": false, - "never_learn": true, - "construction_blueprint": "fbmc_radio_tower_log_shack_5", - "blueprint_provides": [ { "id": "fbmc_radio_tower_shack_5" } ], - "blueprint_excludes": [ { "id": "fbmc_radio_tower_shack_5" } ], - "blueprint_requires": [ { "id": "fbmc_radio_tower_shack_4" } ], - "blueprint_name": "log shack" - }, - { - "type": "recipe", - "result": "faction_base_radio_tower_log_shack_6", - "description": "We need some shelter, so build a log shack with a wooden roof on the southeast corner of the camp.", - "category": "CC_BUILDING", - "subcategory": "CSC_BUILDING_BASES", - "autolearn": false, - "never_learn": true, - "construction_blueprint": "fbmc_radio_tower_log_shack_6", - "blueprint_provides": [ { "id": "fbmc_radio_tower_shack_6" } ], - "blueprint_excludes": [ { "id": "fbmc_radio_tower_shack_6" } ], - "blueprint_requires": [ { "id": "fbmc_radio_tower_shack_1" }, { "id": "fbmc_radio_tower_1" } ], - "blueprint_name": "log shack" - }, - { - "type": "recipe", - "result": "faction_base_radio_tower_log_shack_7", - "description": "We need some shelter, so build a log shack with a wooden roof on the southwest corner of the camp.", - "category": "CC_BUILDING", - "subcategory": "CSC_BUILDING_BASES", - "autolearn": false, - "never_learn": true, - "construction_blueprint": "fbmc_radio_tower_log_shack_7", - "blueprint_provides": [ { "id": "fbmc_radio_tower_shack_7" } ], - "blueprint_excludes": [ { "id": "fbmc_radio_tower_shack_7" } ], - "blueprint_requires": [ { "id": "fbmc_radio_tower_shack_6" } ], - "blueprint_name": "log shack" - }, - { - "type": "recipe", - "result": "faction_base_radio_tower_log_shack_8", - "description": "We need some shelter, so build a log shack with a wooden roof on the south side of the camp.", - "category": "CC_BUILDING", - "subcategory": "CSC_BUILDING_BASES", - "autolearn": false, - "never_learn": true, - "construction_blueprint": "fbmc_radio_tower_log_shack_8", - "blueprint_provides": [ { "id": "fbmc_radio_tower_shack_8" } ], - "blueprint_excludes": [ { "id": "fbmc_radio_tower_shack_8" } ], - "blueprint_requires": [ { "id": "fbmc_radio_tower_shack_7" } ], - "blueprint_name": "log shack" - } -] \ No newline at end of file diff --git a/data/json/recipes/basecamps/fbmc_radio_tower/recipe_modular_radio_tower_metal.json b/data/json/recipes/basecamps/fbmc_radio_tower/recipe_modular_radio_tower_metal.json deleted file mode 100644 index 9edc34542163e..0000000000000 --- a/data/json/recipes/basecamps/fbmc_radio_tower/recipe_modular_radio_tower_metal.json +++ /dev/null @@ -1,114 +0,0 @@ -[ - { - "type": "recipe", - "result": "faction_base_radio_tower_metal_shack_1", - "description": "We need some shelter, so build a metal shack with a metal roof on the northeast side of the camp.", - "category": "CC_BUILDING", - "subcategory": "CSC_BUILDING_BASES", - "autolearn": false, - "never_learn": true, - "construction_blueprint": "fbmc_radio_tower_metal_shack_1", - "blueprint_provides": [ { "id": "fbmc_radio_tower_shack_1" } ], - "blueprint_excludes": [ { "id": "fbmc_radio_tower_shack_1" } ], - "blueprint_requires": [ { "id": "fbmc_radio_tower_shack_0" } ], - "blueprint_name": "metal shack" - }, - { - "type": "recipe", - "result": "faction_base_radio_tower_metal_shack_2", - "description": "We need some shelter, so build a metal shack with a metal roof on the southwest corner of the camp.", - "category": "CC_BUILDING", - "subcategory": "CSC_BUILDING_BASES", - "autolearn": false, - "never_learn": true, - "construction_blueprint": "fbmc_radio_tower_metal_shack_2", - "blueprint_provides": [ { "id": "fbmc_radio_tower_shack_2" } ], - "blueprint_excludes": [ { "id": "fbmc_radio_tower_shack_2" } ], - "blueprint_requires": [ { "id": "fbmc_radio_tower_shack_1" }, { "id": "fbmc_radio_tower_0" } ], - "blueprint_name": "metal shack" - }, - { - "type": "recipe", - "result": "faction_base_radio_tower_metal_shack_3", - "description": "We need some shelter, so build a metal shack with a metal roof on the southwest side of the camp.", - "category": "CC_BUILDING", - "subcategory": "CSC_BUILDING_BASES", - "autolearn": false, - "never_learn": true, - "construction_blueprint": "fbmc_radio_tower_metal_shack_3", - "blueprint_provides": [ { "id": "fbmc_radio_tower_shack_3" } ], - "blueprint_excludes": [ { "id": "fbmc_radio_tower_shack_3" } ], - "blueprint_requires": [ { "id": "fbmc_radio_tower_shack_2" } ], - "blueprint_name": "metal shack" - }, - { - "type": "recipe", - "result": "faction_base_radio_tower_metal_shack_4", - "description": "We need some shelter, so build a metal shack with a metal roof on the southeast side of the camp.", - "category": "CC_BUILDING", - "subcategory": "CSC_BUILDING_BASES", - "autolearn": false, - "never_learn": true, - "construction_blueprint": "fbmc_radio_tower_metal_shack_4", - "blueprint_provides": [ { "id": "fbmc_radio_tower_shack_4" } ], - "blueprint_excludes": [ { "id": "fbmc_radio_tower_shack_4" } ], - "blueprint_requires": [ { "id": "fbmc_radio_tower_shack_3" } ], - "blueprint_name": "metal shack" - }, - { - "type": "recipe", - "result": "faction_base_radio_tower_metal_shack_5", - "description": "We need some shelter, so build a metal shack with a metal roof on the southeast corner of the camp.", - "category": "CC_BUILDING", - "subcategory": "CSC_BUILDING_BASES", - "autolearn": false, - "never_learn": true, - "construction_blueprint": "fbmc_radio_tower_metal_shack_5", - "blueprint_provides": [ { "id": "fbmc_radio_tower_shack_5" } ], - "blueprint_excludes": [ { "id": "fbmc_radio_tower_shack_5" } ], - "blueprint_requires": [ { "id": "fbmc_radio_tower_shack_4" } ], - "blueprint_name": "metal shack" - }, - { - "type": "recipe", - "result": "faction_base_radio_tower_metal_shack_6", - "description": "We need some shelter, so build a metal shack with a metal roof on the southeast corner of the camp.", - "category": "CC_BUILDING", - "subcategory": "CSC_BUILDING_BASES", - "autolearn": false, - "never_learn": true, - "construction_blueprint": "fbmc_radio_tower_metal_shack_6", - "blueprint_provides": [ { "id": "fbmc_radio_tower_shack_6" } ], - "blueprint_excludes": [ { "id": "fbmc_radio_tower_shack_6" } ], - "blueprint_requires": [ { "id": "fbmc_radio_tower_shack_1" }, { "id": "fbmc_radio_tower_1" } ], - "blueprint_name": "metal shack" - }, - { - "type": "recipe", - "result": "faction_base_radio_tower_metal_shack_7", - "description": "We need some shelter, so build a metal shack with a metal roof on the southwest corner of the camp.", - "category": "CC_BUILDING", - "subcategory": "CSC_BUILDING_BASES", - "autolearn": false, - "never_learn": true, - "construction_blueprint": "fbmc_radio_tower_metal_shack_7", - "blueprint_provides": [ { "id": "fbmc_radio_tower_shack_7" } ], - "blueprint_excludes": [ { "id": "fbmc_radio_tower_shack_7" } ], - "blueprint_requires": [ { "id": "fbmc_radio_tower_shack_6" } ], - "blueprint_name": "metal shack" - }, - { - "type": "recipe", - "result": "faction_base_radio_tower_metal_shack_8", - "description": "We need some shelter, so build a metal shack with a metal roof on the south side of the camp.", - "category": "CC_BUILDING", - "subcategory": "CSC_BUILDING_BASES", - "autolearn": false, - "never_learn": true, - "construction_blueprint": "fbmc_radio_tower_metal_shack_8", - "blueprint_provides": [ { "id": "fbmc_radio_tower_shack_8" } ], - "blueprint_excludes": [ { "id": "fbmc_radio_tower_shack_8" } ], - "blueprint_requires": [ { "id": "fbmc_radio_tower_shack_7" } ], - "blueprint_name": "metal shack" - } -] \ No newline at end of file diff --git a/data/json/recipes/basecamps/fbmc_radio_tower/recipe_modular_radio_tower_migo_resin.json b/data/json/recipes/basecamps/fbmc_radio_tower/recipe_modular_radio_tower_migo_resin.json deleted file mode 100644 index a29a9f61d1457..0000000000000 --- a/data/json/recipes/basecamps/fbmc_radio_tower/recipe_modular_radio_tower_migo_resin.json +++ /dev/null @@ -1,153 +0,0 @@ -[ - { - "type": "recipe", - "activity_level": "MODERATE_EXERCISE", - "result": "faction_base_radio_tower_1_controls_room_migo_resin", - "description": "We need some shelter, so build migo resin walls over windows in radio control's room.", - "category": "CC_BUILDING", - "subcategory": "CSC_BUILDING_BASES", - "autolearn": false, - "never_learn": true, - "construction_blueprint": "fbmc_radio_tower_controls_room_migo_resin", - "blueprint_name": "barricade radio control's room", - "blueprint_provides": [ { "id": "fbmc_radio_tower_controls_room" }, { "id": "fbmc_radio_tower" } ], - "blueprint_requires": [ { "id": "fbmc_radio_tower_1" } ], - "blueprint_excludes": [ { "id": "fbmc_radio_tower_controls_room" } ] - }, - { - "type": "recipe", - "result": "faction_base_radio_tower_migo_resin_shack_0", - "description": "We need some shelter, so build a mi-go resin shack with a mi-go resin roof inside radio tower.", - "category": "CC_BUILDING", - "subcategory": "CSC_BUILDING_BASES", - "autolearn": false, - "never_learn": true, - "construction_blueprint": "fbmc_radio_tower_migo_resin_shack_0", - "blueprint_provides": [ { "id": "fbmc_radio_tower_shack_0" } ], - "blueprint_excludes": [ { "id": "fbmc_radio_tower_shack_0" } ], - "blueprint_requires": [ { "id": "fbmc_radio_tower" } ], - "blueprint_needs": { - "time": "29 h", - "skills": [ [ "fabrication", 2 ] ], - "inline": { - "qualities": [ [ { "id": "SMOOTH", "level": 1 } ] ], - "components": [ - [ [ "alien_pod_resin", 52 ] ] - ] - } - }, - "blueprint_name": "mi-go resin shack" - }, - { - "type": "recipe", - "result": "faction_base_radio_tower_migo_resin_shack_1", - "description": "We need some shelter, so build a mi-go resin shack with a mi-go resin roof on the northeast side of the camp.", - "category": "CC_BUILDING", - "subcategory": "CSC_BUILDING_BASES", - "autolearn": false, - "never_learn": true, - "construction_blueprint": "fbmc_radio_tower_migo_resin_shack_1", - "blueprint_provides": [ { "id": "fbmc_radio_tower_shack_1" } ], - "blueprint_excludes": [ { "id": "fbmc_radio_tower_shack_1" } ], - "blueprint_requires": [ { "id": "fbmc_radio_tower_shack_0" } ], - "blueprint_name": "mi-go resin shack" - }, - { - "type": "recipe", - "result": "faction_base_radio_tower_migo_resin_shack_2", - "description": "We need some shelter, so build a mi-go resin shack with a mi-go resin roof on the southwest corner of the camp.", - "category": "CC_BUILDING", - "subcategory": "CSC_BUILDING_BASES", - "autolearn": false, - "never_learn": true, - "construction_blueprint": "fbmc_radio_tower_migo_resin_shack_2", - "blueprint_provides": [ { "id": "fbmc_radio_tower_shack_2" } ], - "blueprint_excludes": [ { "id": "fbmc_radio_tower_shack_2" } ], - "blueprint_requires": [ { "id": "fbmc_radio_tower_shack_1" }, { "id": "fbmc_radio_tower_0" } ], - "blueprint_name": "mi-go resin shack" - }, - { - "type": "recipe", - "result": "faction_base_radio_tower_migo_resin_shack_3", - "description": "We need some shelter, so build a mi-go resin shack with a mi-go resin roof on the southwest side of the camp.", - "category": "CC_BUILDING", - "subcategory": "CSC_BUILDING_BASES", - "autolearn": false, - "never_learn": true, - "construction_blueprint": "fbmc_radio_tower_migo_resin_shack_3", - "blueprint_provides": [ { "id": "fbmc_radio_tower_shack_3" } ], - "blueprint_excludes": [ { "id": "fbmc_radio_tower_shack_3" } ], - "blueprint_requires": [ { "id": "fbmc_radio_tower_shack_2" } ], - "blueprint_name": "mi-go resin shack" - }, - { - "type": "recipe", - "result": "faction_base_radio_tower_migo_resin_shack_4", - "description": "We need some shelter, so build a mi-go resin shack with a mi-go resin roof on the southeast side of the camp.", - "category": "CC_BUILDING", - "subcategory": "CSC_BUILDING_BASES", - "autolearn": false, - "never_learn": true, - "construction_blueprint": "fbmc_radio_tower_migo_resin_shack_4", - "blueprint_provides": [ { "id": "fbmc_radio_tower_shack_4" } ], - "blueprint_excludes": [ { "id": "fbmc_radio_tower_shack_4" } ], - "blueprint_requires": [ { "id": "fbmc_radio_tower_shack_3" } ], - "blueprint_name": "mi-go resin shack" - }, - { - "type": "recipe", - "result": "faction_base_radio_tower_migo_resin_shack_5", - "description": "We need some shelter, so build a mi-go resin shack with a mi-go resin roof on the southeast corner of the camp.", - "category": "CC_BUILDING", - "subcategory": "CSC_BUILDING_BASES", - "autolearn": false, - "never_learn": true, - "construction_blueprint": "fbmc_radio_tower_migo_resin_shack_5", - "blueprint_provides": [ { "id": "fbmc_radio_tower_shack_5" } ], - "blueprint_excludes": [ { "id": "fbmc_radio_tower_shack_5" } ], - "blueprint_requires": [ { "id": "fbmc_radio_tower_shack_4" } ], - "blueprint_name": "mi-go resin shack" - }, - { - "type": "recipe", - "result": "faction_base_radio_tower_migo_resin_shack_6", - "description": "We need some shelter, so build a mi-go resin shack with a mi-go resin roof on the southeast corner of the camp.", - "category": "CC_BUILDING", - "subcategory": "CSC_BUILDING_BASES", - "autolearn": false, - "never_learn": true, - "construction_blueprint": "fbmc_radio_tower_migo_resin_shack_6", - "blueprint_provides": [ { "id": "fbmc_radio_tower_shack_6" } ], - "blueprint_excludes": [ { "id": "fbmc_radio_tower_shack_6" } ], - "blueprint_requires": [ { "id": "fbmc_radio_tower_shack_1" }, { "id": "fbmc_radio_tower_1" } ], - "blueprint_name": "mi-go resin shack" - }, - { - "type": "recipe", - "result": "faction_base_radio_tower_migo_resin_shack_7", - "description": "We need some shelter, so build a mi-go resin shack with a mi-go resin roof on the southwest corner of the camp.", - "category": "CC_BUILDING", - "subcategory": "CSC_BUILDING_BASES", - "autolearn": false, - "never_learn": true, - "construction_blueprint": "fbmc_radio_tower_migo_resin_shack_7", - "blueprint_provides": [ { "id": "fbmc_radio_tower_shack_7" } ], - "blueprint_excludes": [ { "id": "fbmc_radio_tower_shack_7" } ], - "blueprint_requires": [ { "id": "fbmc_radio_tower_shack_6" } ], - "blueprint_name": "mi-go resin shack" - }, - { - "type": "recipe", - "result": "faction_base_radio_tower_migo_resin_shack_8", - "description": "We need some shelter, so build a mi-go resin shack with a mi-go resin roof on the south side of the camp.", - "category": "CC_BUILDING", - "subcategory": "CSC_BUILDING_BASES", - "autolearn": false, - "never_learn": true, - "construction_blueprint": "fbmc_radio_tower_migo_resin_shack_8", - "blueprint_provides": [ { "id": "fbmc_radio_tower_shack_8" } ], - "blueprint_excludes": [ { "id": "fbmc_radio_tower_shack_8" } ], - "blueprint_requires": [ { "id": "fbmc_radio_tower_shack_7" } ], - "blueprint_name": "mi-go resin shack" - } -] \ No newline at end of file diff --git a/data/json/recipes/basecamps/fbmc_radio_tower/recipe_modular_radio_tower_rammed_earth.json b/data/json/recipes/basecamps/fbmc_radio_tower/recipe_modular_radio_tower_rammed_earth.json deleted file mode 100644 index ae6a81a43a694..0000000000000 --- a/data/json/recipes/basecamps/fbmc_radio_tower/recipe_modular_radio_tower_rammed_earth.json +++ /dev/null @@ -1,114 +0,0 @@ -[ - { - "type": "recipe", - "result": "faction_base_radio_tower_rammed_earth_shack_1", - "description": "We need some shelter, so build a rammed earth shack with a sod roof on the northeast side of the camp.", - "category": "CC_BUILDING", - "subcategory": "CSC_BUILDING_BASES", - "autolearn": false, - "never_learn": true, - "construction_blueprint": "fbmc_radio_tower_rammed_earth_shack_1", - "blueprint_provides": [ { "id": "fbmc_radio_tower_shack_1" } ], - "blueprint_excludes": [ { "id": "fbmc_radio_tower_shack_1" } ], - "blueprint_requires": [ { "id": "fbmc_radio_tower_shack_0" } ], - "blueprint_name": "rammed earth shack" - }, - { - "type": "recipe", - "result": "faction_base_radio_tower_rammed_earth_shack_2", - "description": "We need some shelter, so build a rammed earth shack with a sod roof on the southwest corner of the camp.", - "category": "CC_BUILDING", - "subcategory": "CSC_BUILDING_BASES", - "autolearn": false, - "never_learn": true, - "construction_blueprint": "fbmc_radio_tower_rammed_earth_shack_2", - "blueprint_provides": [ { "id": "fbmc_radio_tower_shack_2" } ], - "blueprint_excludes": [ { "id": "fbmc_radio_tower_shack_2" } ], - "blueprint_requires": [ { "id": "fbmc_radio_tower_shack_1" }, { "id": "fbmc_radio_tower_0" } ], - "blueprint_name": "rammed earth shack" - }, - { - "type": "recipe", - "result": "faction_base_radio_tower_rammed_earth_shack_3", - "description": "We need some shelter, so build a rammed earth shack with a sod roof on the southwest side of the camp.", - "category": "CC_BUILDING", - "subcategory": "CSC_BUILDING_BASES", - "autolearn": false, - "never_learn": true, - "construction_blueprint": "fbmc_radio_tower_rammed_earth_shack_3", - "blueprint_provides": [ { "id": "fbmc_radio_tower_shack_3" } ], - "blueprint_excludes": [ { "id": "fbmc_radio_tower_shack_3" } ], - "blueprint_requires": [ { "id": "fbmc_radio_tower_shack_2" } ], - "blueprint_name": "rammed earth shack" - }, - { - "type": "recipe", - "result": "faction_base_radio_tower_rammed_earth_shack_4", - "description": "We need some shelter, so build a rammed earth shack with a sod roof on the southeast side of the camp.", - "category": "CC_BUILDING", - "subcategory": "CSC_BUILDING_BASES", - "autolearn": false, - "never_learn": true, - "construction_blueprint": "fbmc_radio_tower_rammed_earth_shack_4", - "blueprint_provides": [ { "id": "fbmc_radio_tower_shack_4" } ], - "blueprint_excludes": [ { "id": "fbmc_radio_tower_shack_4" } ], - "blueprint_requires": [ { "id": "fbmc_radio_tower_shack_3" } ], - "blueprint_name": "rammed earth shack" - }, - { - "type": "recipe", - "result": "faction_base_radio_tower_rammed_earth_shack_5", - "description": "We need some shelter, so build a rammed earth shack with a sod roof on the southeast corner of the camp.", - "category": "CC_BUILDING", - "subcategory": "CSC_BUILDING_BASES", - "autolearn": false, - "never_learn": true, - "construction_blueprint": "fbmc_radio_tower_rammed_earth_shack_5", - "blueprint_provides": [ { "id": "fbmc_radio_tower_shack_5" } ], - "blueprint_excludes": [ { "id": "fbmc_radio_tower_shack_5" } ], - "blueprint_requires": [ { "id": "fbmc_radio_tower_shack_4" } ], - "blueprint_name": "rammed earth shack" - }, - { - "type": "recipe", - "result": "faction_base_radio_tower_rammed_earth_shack_6", - "description": "We need some shelter, so build a rammed earth shack with a sod roof on the southeast corner of the camp.", - "category": "CC_BUILDING", - "subcategory": "CSC_BUILDING_BASES", - "autolearn": false, - "never_learn": true, - "construction_blueprint": "fbmc_radio_tower_rammed_earth_shack_6", - "blueprint_provides": [ { "id": "fbmc_radio_tower_shack_6" } ], - "blueprint_excludes": [ { "id": "fbmc_radio_tower_shack_6" } ], - "blueprint_requires": [ { "id": "fbmc_radio_tower_shack_1" }, { "id": "fbmc_radio_tower_1" } ], - "blueprint_name": "rammed earth shack" - }, - { - "type": "recipe", - "result": "faction_base_radio_tower_rammed_earth_shack_7", - "description": "We need some shelter, so build a rammed earth shack with a sod roof on the south side of the camp.", - "category": "CC_BUILDING", - "subcategory": "CSC_BUILDING_BASES", - "autolearn": false, - "never_learn": true, - "construction_blueprint": "fbmc_radio_tower_rammed_earth_shack_7", - "blueprint_provides": [ { "id": "fbmc_radio_tower_shack_7" } ], - "blueprint_excludes": [ { "id": "fbmc_radio_tower_shack_7" } ], - "blueprint_requires": [ { "id": "fbmc_radio_tower_shack_6" } ], - "blueprint_name": "rammed earth shack" - }, - { - "type": "recipe", - "result": "faction_base_radio_tower_rammed_earth_shack_8", - "description": "We need some shelter, so build a rammed earth shack with a sod roof on the southwest corner of the camp.", - "category": "CC_BUILDING", - "subcategory": "CSC_BUILDING_BASES", - "autolearn": false, - "never_learn": true, - "construction_blueprint": "fbmc_radio_tower_rammed_earth_shack_8", - "blueprint_provides": [ { "id": "fbmc_radio_tower_shack_8" } ], - "blueprint_excludes": [ { "id": "fbmc_radio_tower_shack_8" } ], - "blueprint_requires": [ { "id": "fbmc_radio_tower_shack_7" } ], - "blueprint_name": "rammed earth shack" - } -] \ No newline at end of file diff --git a/data/json/recipes/basecamps/fbmc_radio_tower/recipe_modular_radio_tower_rock.json b/data/json/recipes/basecamps/fbmc_radio_tower/recipe_modular_radio_tower_rock.json deleted file mode 100644 index a897f8f0c4926..0000000000000 --- a/data/json/recipes/basecamps/fbmc_radio_tower/recipe_modular_radio_tower_rock.json +++ /dev/null @@ -1,114 +0,0 @@ -[ - { - "type": "recipe", - "result": "faction_base_radio_tower_rock_shack_1", - "description": "We need some shelter, so build a stone shack with a wooden roof on the northeast side of the camp.", - "category": "CC_BUILDING", - "subcategory": "CSC_BUILDING_BASES", - "autolearn": false, - "never_learn": true, - "construction_blueprint": "fbmc_radio_tower_rock_shack_1", - "blueprint_provides": [ { "id": "fbmc_radio_tower_shack_1" } ], - "blueprint_excludes": [ { "id": "fbmc_radio_tower_shack_1" } ], - "blueprint_requires": [ { "id": "fbmc_radio_tower_shack_0" } ], - "blueprint_name": "stone shack" - }, - { - "type": "recipe", - "result": "faction_base_radio_tower_rock_shack_2", - "description": "We need some shelter, so build a stone shack with a wooden roof on the southwest corner of the camp.", - "category": "CC_BUILDING", - "subcategory": "CSC_BUILDING_BASES", - "autolearn": false, - "never_learn": true, - "construction_blueprint": "fbmc_radio_tower_rock_shack_2", - "blueprint_provides": [ { "id": "fbmc_radio_tower_shack_2" } ], - "blueprint_excludes": [ { "id": "fbmc_radio_tower_shack_2" } ], - "blueprint_requires": [ { "id": "fbmc_radio_tower_shack_1" }, { "id": "fbmc_radio_tower_0" } ], - "blueprint_name": "stone shack" - }, - { - "type": "recipe", - "result": "faction_base_radio_tower_rock_shack_3", - "description": "We need some shelter, so build a stone shack with a wooden roof on the southwest side of the camp.", - "category": "CC_BUILDING", - "subcategory": "CSC_BUILDING_BASES", - "autolearn": false, - "never_learn": true, - "construction_blueprint": "fbmc_radio_tower_rock_shack_3", - "blueprint_provides": [ { "id": "fbmc_radio_tower_shack_3" } ], - "blueprint_excludes": [ { "id": "fbmc_radio_tower_shack_3" } ], - "blueprint_requires": [ { "id": "fbmc_radio_tower_shack_2" } ], - "blueprint_name": "stone shack" - }, - { - "type": "recipe", - "result": "faction_base_radio_tower_rock_shack_4", - "description": "We need some shelter, so build a stone shack with a wooden roof on the southeast side of the camp.", - "category": "CC_BUILDING", - "subcategory": "CSC_BUILDING_BASES", - "autolearn": false, - "never_learn": true, - "construction_blueprint": "fbmc_radio_tower_rock_shack_4", - "blueprint_provides": [ { "id": "fbmc_radio_tower_shack_4" } ], - "blueprint_excludes": [ { "id": "fbmc_radio_tower_shack_4" } ], - "blueprint_requires": [ { "id": "fbmc_radio_tower_shack_3" } ], - "blueprint_name": "stone shack" - }, - { - "type": "recipe", - "result": "faction_base_radio_tower_rock_shack_5", - "description": "We need some shelter, so build a stone shack with a wooden roof on the southeast corner of the camp.", - "category": "CC_BUILDING", - "subcategory": "CSC_BUILDING_BASES", - "autolearn": false, - "never_learn": true, - "construction_blueprint": "fbmc_radio_tower_rock_shack_5", - "blueprint_provides": [ { "id": "fbmc_radio_tower_shack_5" } ], - "blueprint_excludes": [ { "id": "fbmc_radio_tower_shack_5" } ], - "blueprint_requires": [ { "id": "fbmc_radio_tower_shack_4" } ], - "blueprint_name": "stone shack" - }, - { - "type": "recipe", - "result": "faction_base_radio_tower_rock_shack_6", - "description": "We need some shelter, so build a stone shack with a wooden roof on the southeast corner of the camp.", - "category": "CC_BUILDING", - "subcategory": "CSC_BUILDING_BASES", - "autolearn": false, - "never_learn": true, - "construction_blueprint": "fbmc_radio_tower_rock_shack_6", - "blueprint_provides": [ { "id": "fbmc_radio_tower_shack_6" } ], - "blueprint_excludes": [ { "id": "fbmc_radio_tower_shack_6" } ], - "blueprint_requires": [ { "id": "fbmc_radio_tower_shack_1" }, { "id": "fbmc_radio_tower_1" } ], - "blueprint_name": "stone shack" - }, - { - "type": "recipe", - "result": "faction_base_radio_tower_rock_shack_7", - "description": "We need some shelter, so build a stone shack with a wooden roof on the southwest corner of the camp.", - "category": "CC_BUILDING", - "subcategory": "CSC_BUILDING_BASES", - "autolearn": false, - "never_learn": true, - "construction_blueprint": "fbmc_radio_tower_rock_shack_7", - "blueprint_provides": [ { "id": "fbmc_radio_tower_shack_7" } ], - "blueprint_excludes": [ { "id": "fbmc_radio_tower_shack_7" } ], - "blueprint_requires": [ { "id": "fbmc_radio_tower_shack_6" } ], - "blueprint_name": "stone shack" - }, - { - "type": "recipe", - "result": "faction_base_radio_tower_rock_shack_8", - "description": "We need some shelter, so build a stone shack with a wooden roof on the south side of the camp.", - "category": "CC_BUILDING", - "subcategory": "CSC_BUILDING_BASES", - "autolearn": false, - "never_learn": true, - "construction_blueprint": "fbmc_radio_tower_rock_shack_8", - "blueprint_provides": [ { "id": "fbmc_radio_tower_shack_8" } ], - "blueprint_excludes": [ { "id": "fbmc_radio_tower_shack_8" } ], - "blueprint_requires": [ { "id": "fbmc_radio_tower_shack_7" } ], - "blueprint_name": "stone shack" - } -] \ No newline at end of file diff --git a/data/json/recipes/basecamps/fbmc_radio_tower/recipe_modular_radio_tower_wad.json b/data/json/recipes/basecamps/fbmc_radio_tower/recipe_modular_radio_tower_wad.json deleted file mode 100644 index 2742b3ecaa910..0000000000000 --- a/data/json/recipes/basecamps/fbmc_radio_tower/recipe_modular_radio_tower_wad.json +++ /dev/null @@ -1,114 +0,0 @@ -[ - { - "type": "recipe", - "result": "faction_base_radio_tower_wad_shack_1", - "description": "We need some shelter, so build a wattle and daub shack with a sod roof on the northeast side of the camp.", - "category": "CC_BUILDING", - "subcategory": "CSC_BUILDING_BASES", - "autolearn": false, - "never_learn": true, - "construction_blueprint": "fbmc_radio_tower_wad_shack_1", - "blueprint_provides": [ { "id": "fbmc_radio_tower_shack_1" } ], - "blueprint_excludes": [ { "id": "fbmc_radio_tower_shack_1" } ], - "blueprint_requires": [ { "id": "fbmc_radio_tower_shack_0" } ], - "blueprint_name": "wattle and daub shack" - }, - { - "type": "recipe", - "result": "faction_base_radio_tower_wad_shack_2", - "description": "We need some shelter, so build a wattle and daub shack with a sod roof on the southwest corner of the camp.", - "category": "CC_BUILDING", - "subcategory": "CSC_BUILDING_BASES", - "autolearn": false, - "never_learn": true, - "construction_blueprint": "fbmc_radio_tower_wad_shack_2", - "blueprint_provides": [ { "id": "fbmc_radio_tower_shack_2" } ], - "blueprint_excludes": [ { "id": "fbmc_radio_tower_shack_2" } ], - "blueprint_requires": [ { "id": "fbmc_radio_tower_shack_1" }, { "id": "fbmc_radio_tower_0" } ], - "blueprint_name": "wattle and daub shack" - }, - { - "type": "recipe", - "result": "faction_base_radio_tower_wad_shack_3", - "description": "We need some shelter, so build a wattle and daub shack with a sod roof on the southwest side of the camp.", - "category": "CC_BUILDING", - "subcategory": "CSC_BUILDING_BASES", - "autolearn": false, - "never_learn": true, - "construction_blueprint": "fbmc_radio_tower_wad_shack_3", - "blueprint_provides": [ { "id": "fbmc_radio_tower_shack_3" } ], - "blueprint_excludes": [ { "id": "fbmc_radio_tower_shack_3" } ], - "blueprint_requires": [ { "id": "fbmc_radio_tower_shack_2" } ], - "blueprint_name": "wattle and daub shack" - }, - { - "type": "recipe", - "result": "faction_base_radio_tower_wad_shack_4", - "description": "We need some shelter, so build a wattle and daub shack with a sod roof on the southeast side of the camp.", - "category": "CC_BUILDING", - "subcategory": "CSC_BUILDING_BASES", - "autolearn": false, - "never_learn": true, - "construction_blueprint": "fbmc_radio_tower_wad_shack_4", - "blueprint_provides": [ { "id": "fbmc_radio_tower_shack_4" } ], - "blueprint_excludes": [ { "id": "fbmc_radio_tower_shack_4" } ], - "blueprint_requires": [ { "id": "fbmc_radio_tower_shack_3" } ], - "blueprint_name": "wattle and daub shack" - }, - { - "type": "recipe", - "result": "faction_base_radio_tower_wad_shack_5", - "description": "We need some shelter, so build a wattle and daub shack with a sod roof on the southeast corner of the camp.", - "category": "CC_BUILDING", - "subcategory": "CSC_BUILDING_BASES", - "autolearn": false, - "never_learn": true, - "construction_blueprint": "fbmc_radio_tower_wad_shack_5", - "blueprint_provides": [ { "id": "fbmc_radio_tower_shack_5" } ], - "blueprint_excludes": [ { "id": "fbmc_radio_tower_shack_5" } ], - "blueprint_requires": [ { "id": "fbmc_radio_tower_shack_4" } ], - "blueprint_name": "wattle and daub shack" - }, - { - "type": "recipe", - "result": "faction_base_radio_tower_wad_shack_6", - "description": "We need some shelter, so build a wattle and daub shack with a sod roof on the southeast corner of the camp.", - "category": "CC_BUILDING", - "subcategory": "CSC_BUILDING_BASES", - "autolearn": false, - "never_learn": true, - "construction_blueprint": "fbmc_radio_tower_wad_shack_6", - "blueprint_provides": [ { "id": "fbmc_radio_tower_shack_6" } ], - "blueprint_excludes": [ { "id": "fbmc_radio_tower_shack_6" } ], - "blueprint_requires": [ { "id": "fbmc_radio_tower_shack_1" }, { "id": "fbmc_radio_tower_1" } ], - "blueprint_name": "wattle and daub shack" - }, - { - "type": "recipe", - "result": "faction_base_radio_tower_wad_shack_7", - "description": "We need some shelter, so build a wattle and daub shack with a sod roof on the southwest corner of the camp.", - "category": "CC_BUILDING", - "subcategory": "CSC_BUILDING_BASES", - "autolearn": false, - "never_learn": true, - "construction_blueprint": "fbmc_radio_tower_wad_shack_7", - "blueprint_provides": [ { "id": "fbmc_radio_tower_shack_7" } ], - "blueprint_excludes": [ { "id": "fbmc_radio_tower_shack_7" } ], - "blueprint_requires": [ { "id": "fbmc_radio_tower_shack_6" } ], - "blueprint_name": "wattle and daub shack" - }, - { - "type": "recipe", - "result": "faction_base_radio_tower_wad_shack_5", - "description": "We need some shelter, so build a wattle and daub shack with a sod roof on the south side of the camp.", - "category": "CC_BUILDING", - "subcategory": "CSC_BUILDING_BASES", - "autolearn": false, - "never_learn": true, - "construction_blueprint": "fbmc_radio_tower_wad_shack_8", - "blueprint_provides": [ { "id": "fbmc_radio_tower_shack_8" } ], - "blueprint_excludes": [ { "id": "fbmc_radio_tower_shack_8" } ], - "blueprint_requires": [ { "id": "fbmc_radio_tower_shack_7" } ], - "blueprint_name": "wattle and daub shack" - } -] \ No newline at end of file diff --git a/data/json/recipes/basecamps/fbmc_radio_tower/recipe_modular_radio_tower_wood.json b/data/json/recipes/basecamps/fbmc_radio_tower/recipe_modular_radio_tower_wood.json deleted file mode 100644 index ccf4a3a225853..0000000000000 --- a/data/json/recipes/basecamps/fbmc_radio_tower/recipe_modular_radio_tower_wood.json +++ /dev/null @@ -1,156 +0,0 @@ -[ - { - "type": "recipe", - "result": "faction_base_radio_tower_1_controls_room_wood", - "description": "We need some shelter, so build wooden walls over windows in radio control's room.", - "category": "CC_BUILDING", - "subcategory": "CSC_BUILDING_BASES", - "autolearn": false, - "never_learn": true, - "construction_blueprint": "fbmc_radio_tower_controls_room_wood", - "blueprint_name": "barricade radio control's room", - "blueprint_provides": [ { "id": "fbmc_radio_tower_controls_room" }, { "id": "fbmc_radio_tower" } ], - "blueprint_requires": [ { "id": "fbmc_radio_tower_1" } ], - "blueprint_excludes": [ { "id": "fbmc_radio_tower_controls_room" } ] - }, - { - "type": "recipe", - "result": "faction_base_radio_tower_wood_shack_0", - "description": "We need some shelter, so build a wooden shack with a wooden roof inside radio tower.", - "category": "CC_BUILDING", - "subcategory": "CSC_BUILDING_BASES", - "autolearn": false, - "never_learn": true, - "construction_blueprint": "fbmc_radio_tower_wood_shack_0", - "blueprint_provides": [ { "id": "fbmc_radio_tower_shack_0" } ], - "blueprint_excludes": [ { "id": "fbmc_radio_tower_shack_0" } ], - "blueprint_requires": [ { "id": "fbmc_radio_tower" } ], - "blueprint_needs": { - "time": "40 h", - "skills": [ [ "fabrication", 3 ] ], - "inline": { - "qualities": [ [ { "id": "HAMMER", "level": 2 } ], [ { "id": "SAW_W", "level": 2 } ] ], - "components": [ - [ [ "2x4", 230 ] ], - [ [ "glass_sheet", 1 ] ], - [ [ "hinge", 2 ] ], - [ [ "nail", 1100 ] ], - [ [ "wood_panel", 54 ] ] - ] - } - }, - "blueprint_name": "wooden shack" - }, - { - "type": "recipe", - "result": "faction_base_radio_tower_wood_shack_1", - "description": "We need some shelter, so build a wooden shack with a wooden roof on the northeast side of the camp.", - "category": "CC_BUILDING", - "subcategory": "CSC_BUILDING_BASES", - "autolearn": false, - "never_learn": true, - "construction_blueprint": "fbmc_radio_tower_wood_shack_1", - "blueprint_provides": [ { "id": "fbmc_radio_tower_shack_1" } ], - "blueprint_excludes": [ { "id": "fbmc_radio_tower_shack_1" } ], - "blueprint_requires": [ { "id": "fbmc_radio_tower_shack_0" } ], - "blueprint_name": "wooden shack" - }, - { - "type": "recipe", - "result": "faction_base_radio_tower_wood_shack_2", - "description": "We need some shelter, so build a wooden shack with a wooden roof on the southwest corner of the camp.", - "category": "CC_BUILDING", - "subcategory": "CSC_BUILDING_BASES", - "autolearn": false, - "never_learn": true, - "construction_blueprint": "fbmc_radio_tower_wood_shack_2", - "blueprint_provides": [ { "id": "fbmc_radio_tower_shack_2" } ], - "blueprint_excludes": [ { "id": "fbmc_radio_tower_shack_2" } ], - "blueprint_requires": [ { "id": "fbmc_radio_tower_shack_1" }, { "id": "fbmc_radio_tower_0" } ], - "blueprint_name": "wooden shack" - }, - { - "type": "recipe", - "result": "faction_base_radio_tower_wood_shack_3", - "description": "We need some shelter, so build a wooden shack with a wooden roof on the southwest side of the camp.", - "category": "CC_BUILDING", - "subcategory": "CSC_BUILDING_BASES", - "autolearn": false, - "never_learn": true, - "construction_blueprint": "fbmc_radio_tower_wood_shack_3", - "blueprint_provides": [ { "id": "fbmc_radio_tower_shack_3" } ], - "blueprint_excludes": [ { "id": "fbmc_radio_tower_shack_3" } ], - "blueprint_requires": [ { "id": "fbmc_radio_tower_shack_2" } ], - "blueprint_name": "wooden shack" - }, - { - "type": "recipe", - "result": "faction_base_radio_tower_wood_shack_4", - "description": "We need some shelter, so build a wooden shack with a wooden roof on the southeast side of the camp.", - "category": "CC_BUILDING", - "subcategory": "CSC_BUILDING_BASES", - "autolearn": false, - "never_learn": true, - "construction_blueprint": "fbmc_radio_tower_wood_shack_4", - "blueprint_provides": [ { "id": "fbmc_radio_tower_shack_4" } ], - "blueprint_excludes": [ { "id": "fbmc_radio_tower_shack_4" } ], - "blueprint_requires": [ { "id": "fbmc_radio_tower_shack_3" } ], - "blueprint_name": "wooden shack" - }, - { - "type": "recipe", - "result": "faction_base_radio_tower_wood_shack_5", - "description": "We need some shelter, so build a wooden shack with a wooden roof on the southeast corner of the camp.", - "category": "CC_BUILDING", - "subcategory": "CSC_BUILDING_BASES", - "autolearn": false, - "never_learn": true, - "construction_blueprint": "fbmc_radio_tower_wood_shack_5", - "blueprint_provides": [ { "id": "fbmc_radio_tower_shack_5" } ], - "blueprint_excludes": [ { "id": "fbmc_radio_tower_shack_5" } ], - "blueprint_requires": [ { "id": "fbmc_radio_tower_shack_4" } ], - "blueprint_name": "wooden shack" - }, - { - "type": "recipe", - "result": "faction_base_radio_tower_wood_shack_6", - "description": "We need some shelter, so build a wooden shack with a wooden roof on the southeast corner of the camp.", - "category": "CC_BUILDING", - "subcategory": "CSC_BUILDING_BASES", - "autolearn": false, - "never_learn": true, - "construction_blueprint": "fbmc_radio_tower_wood_shack_6", - "blueprint_provides": [ { "id": "fbmc_radio_tower_shack_6" } ], - "blueprint_excludes": [ { "id": "fbmc_radio_tower_shack_6" } ], - "blueprint_requires": [ { "id": "fbmc_radio_tower_shack_1" }, { "id": "fbmc_radio_tower_1" } ], - "blueprint_name": "wooden shack" - }, - { - "type": "recipe", - "result": "faction_base_radio_tower_wood_shack_7", - "description": "We need some shelter, so build a wooden shack with a wooden roof on the southwest corner of the camp.", - "category": "CC_BUILDING", - "subcategory": "CSC_BUILDING_BASES", - "autolearn": false, - "never_learn": true, - "construction_blueprint": "fbmc_radio_tower_wood_shack_7", - "blueprint_provides": [ { "id": "fbmc_radio_tower_shack_7" } ], - "blueprint_excludes": [ { "id": "fbmc_radio_tower_shack_7" } ], - "blueprint_requires": [ { "id": "fbmc_radio_tower_shack_6" } ], - "blueprint_name": "wooden shack" - }, - { - "type": "recipe", - "result": "faction_base_radio_tower_wood_shack_8", - "description": "We need some shelter, so build a wooden shack with a wooden roof on the south side of the camp.", - "category": "CC_BUILDING", - "subcategory": "CSC_BUILDING_BASES", - "autolearn": false, - "never_learn": true, - "construction_blueprint": "fbmc_radio_tower_wood_shack_8", - "blueprint_provides": [ { "id": "fbmc_radio_tower_shack_8" } ], - "blueprint_excludes": [ { "id": "fbmc_radio_tower_shack_8" } ], - "blueprint_requires": [ { "id": "fbmc_radio_tower_shack_7" } ], - "blueprint_name": "wooden shack" - } -] \ No newline at end of file diff --git a/data/json/recipes/basecamps/recipe_groups.json b/data/json/recipes/basecamps/recipe_groups.json index 744d0e7eebb8b..2140baa817029 100644 --- a/data/json/recipes/basecamps/recipe_groups.json +++ b/data/json/recipes/basecamps/recipe_groups.json @@ -44,16 +44,6 @@ "id": "faction_base_mansion_+4_0", "description": "Mansion Garden With Columns Base", "om_terrains": [ "mansion_+4" ] - }, - { - "id": "faction_base_radio_tower_0", - "description": "Radio Tower Without Building Base", - "om_terrains": [ "radio_tower" ] - }, - { - "id": "faction_base_radio_tower_1_0", - "description": "Radio Tower With Building Base", - "om_terrains": [ "radio_tower_1" ] } ] }, @@ -348,7 +338,7 @@ { "type": "recipe_group", "id": "blacksmith_recipes_7", - "building_type": "BASE", + "building_type": "SMITH", "recipes": [ { "id": "sheet_metal_npc_drop", "description": " Craft: Sheet Metal, Drop Hammer" }, { "id": "chain_npc_drop", "description": " Craft: Chain, Drop Hammer" }, @@ -357,33 +347,5 @@ { "id": "pipe_npc_drop", "description": " Craft: Pipe, Drop Hammer" }, { "id": "rebar_npc_drop", "description": " Craft: Rebar, Drop Hammer" } ] - }, - { - "type": "recipe_group", - "id": "hack_recipes_general", - "building_type": "BASE", - "recipes": [ - { "id": "mobile_memory_card_npc_hack", "description": " Hack & Download: random data, SD-Memory card" }, - { "id": "software_useless_npc_hack", "description": " Hack & Download: misc software, USB drive" }, - { "id": "software_math_npc_hack", "description": " Hack & Download: MatheMAX, USB drive" } - ] - }, - { - "type": "recipe_group", - "id": "hack_recipes_science", - "building_type": "BASE", - "recipes": [ - { "id": "mobile_memory_card_science_npc_hack", "description": " Hack & Download: science data, SD-Memory card" }, - { "id": "software_medical_npc_hack", "description": " Hack & Download: MediSoft, USB drive" }, - { "id": "software_electronics_reference_npc_hack", "description": " Hack & Download: IC datasheet archives, USB drive" } - ] - }, - { - "type": "recipe_group", - "id": "hack_recipes_satellite", - "building_type": "BASE", - "recipes": [ - { "id": "satellitemap_npc_hack", "description": " Hack & Download: Satellite Map, traced" } - ] } ] diff --git a/data/json/recipes/recipe_companion.json b/data/json/recipes/recipe_companion.json index 57fcf081da7b3..accf5343f7c67 100644 --- a/data/json/recipes/recipe_companion.json +++ b/data/json/recipes/recipe_companion.json @@ -107,121 +107,5 @@ "qualities": [ { "id": "ANVIL", "level": 3 }, { "id": "HAMMER", "level": 5 }, { "id": "CHISEL", "level": 3 } ], "tools": [ [ [ "tongs", -1 ] ], [ [ "swage", -1 ] ], [ [ "forge", 10 ], [ "oxy_torch", 2 ] ] ], "components": [ [ [ "scrap", 3 ] ] ] - }, - { - "type": "recipe", - "activity_level": "fake", - "result": "mobile_memory_card", - "id_suffix": "npc_hack", - "category": "CC_OTHER", - "subcategory": "CSC_OTHER_MATERIALS", - "skill_used": "computer", - "difficulty": 2, - "time": "60 m", - "autolearn": false, - "never_learn": true, - "skills_required": [ [ "computer", 2 ] ], - "tools": [ [ [ "laptop", 120 ] ] ], - "components": [ [ [ "mobile_memory_card_used", 1 ] ] ] - }, - { - "type": "recipe", - "activity_level": "fake", - "result": "software_useless", - "id_suffix": "npc_hack", - "category": "CC_OTHER", - "subcategory": "CSC_OTHER_MATERIALS", - "skill_used": "computer", - "difficulty": 3, - "time": "120 m", - "autolearn": false, - "never_learn": true, - "skills_required": [ [ "computer", 3 ] ], - "tools": [ [ [ "laptop", 240 ] ] ], - "components": [ [ [ "usb_drive", 1 ] ] ], - "container": "usb_drive" - }, - { - "type": "recipe", - "activity_level": "fake", - "result": "software_math", - "id_suffix": "npc_hack", - "category": "CC_OTHER", - "subcategory": "CSC_OTHER_MATERIALS", - "skill_used": "computer", - "difficulty": 4, - "time": "150 m", - "autolearn": false, - "never_learn": true, - "skills_required": [ [ "computer", 4 ] ], - "tools": [ [ [ "laptop", 300 ] ], [ [ "software_hacking", -1 ] ] ], - "components": [ [ [ "usb_drive", 1 ] ] ], - "container": "usb_drive" - }, - { - "type": "recipe", - "activity_level": "fake", - "result": "mobile_memory_card_science", - "id_suffix": "npc_hack", - "category": "CC_OTHER", - "subcategory": "CSC_OTHER_MATERIALS", - "skill_used": "computer", - "difficulty": 5, - "time": "180 m", - "autolearn": false, - "never_learn": true, - "skills_required": [ [ "computer", 5 ] ], - "tools": [ [ [ "laptop", 360 ] ], [ [ "software_hacking", -1 ] ] ], - "components": [ [ [ "mobile_memory_card_used", 1 ] ] ] - }, - { - "type": "recipe", - "activity_level": "fake", - "result": "software_medical", - "id_suffix": "npc_hack", - "category": "CC_OTHER", - "subcategory": "CSC_OTHER_MATERIALS", - "skill_used": "computer", - "difficulty": 5, - "time": "210 m", - "autolearn": false, - "never_learn": true, - "skills_required": [ [ "computer", 5 ] ], - "tools": [ [ [ "laptop", 420 ] ], [ [ "software_hacking", -1 ] ] ], - "components": [ [ [ "usb_drive", 1 ] ] ], - "container": "usb_drive" - }, - { - "type": "recipe", - "activity_level": "fake", - "result": "software_electronics_reference", - "id_suffix": "npc_hack", - "category": "CC_OTHER", - "subcategory": "CSC_OTHER_MATERIALS", - "skill_used": "computer", - "difficulty": 6, - "time": "240 m", - "autolearn": false, - "never_learn": true, - "skills_required": [ [ "computer", 6 ] ], - "tools": [ [ [ "laptop", 480 ] ], [ [ "software_hacking", -1 ] ] ], - "components": [ [ [ "usb_drive", 1 ] ] ], - "container": "usb_drive" - }, - { - "type": "recipe", - "activity_level": "fake", - "result": "satellitemap", - "id_suffix": "npc_hack", - "category": "CC_OTHER", - "subcategory": "CSC_OTHER_MATERIALS", - "skill_used": "computer", - "difficulty": 8, - "time": "480 m", - "autolearn": false, - "never_learn": true, - "skills_required": [ [ "computer", 8 ] ], - "tools": [ [ [ "laptop", 600 ] ], [ [ "pencil", 50 ] ], [ [ "software_hacking", -1 ] ] ], - "components": [ [ [ "paper", 25 ] ] ] } ] From 95a7e1139bf58b484cb22657f0bb5ed93b3fe7cd Mon Sep 17 00:00:00 2001 From: krulunio Date: Thu, 20 May 2021 14:55:01 +0200 Subject: [PATCH 217/453] Revert "Split military outposts and bunkers" This reverts commit 03c09047482e39b165f125b5b792bc1df3d62d73. --- data/json/mapgen/bunker.json | 4 +-- data/json/mapgen/outpost.json | 2 +- .../overmap/overmap_special/specials.json | 27 ++----------------- .../overmap_terrain_military.json | 19 ------------- 4 files changed, 5 insertions(+), 47 deletions(-) diff --git a/data/json/mapgen/bunker.json b/data/json/mapgen/bunker.json index 75bbb4a50dea6..b5df262465190 100644 --- a/data/json/mapgen/bunker.json +++ b/data/json/mapgen/bunker.json @@ -112,7 +112,7 @@ { "type": "mapgen", "method": "json", - "om_terrain": [ "bunker_basement_1" ], + "om_terrain": [ "bunker_basement" ], "weight": 250, "object": { "fill_ter": "t_floor", @@ -211,7 +211,7 @@ { "type": "mapgen", "method": "json", - "om_terrain": [ "bunker_basement_1" ], + "om_terrain": [ "bunker_basement" ], "weight": 500, "object": { "fill_ter": "t_floor", diff --git a/data/json/mapgen/outpost.json b/data/json/mapgen/outpost.json index 9fd42f451c407..d4cc2ee7ccddb 100644 --- a/data/json/mapgen/outpost.json +++ b/data/json/mapgen/outpost.json @@ -149,7 +149,7 @@ { "type": "mapgen", "method": "json", - "om_terrain": [ "outpost_cross" ], + "om_terrain": [ "outpost" ], "weight": 100, "object": { "rows": [ diff --git a/data/json/overmap/overmap_special/specials.json b/data/json/overmap/overmap_special/specials.json index 4d75c9f61d145..326b01007d486 100644 --- a/data/json/overmap/overmap_special/specials.json +++ b/data/json/overmap/overmap_special/specials.json @@ -821,21 +821,7 @@ "connections": [ { "point": [ 0, -1, 0 ], "from": [ 0, 0, 0 ] } ], "locations": [ "forest" ], "city_distance": [ 20, -1 ], - "occurrences": [ 25, 100 ], - "flags": [ "MILITARY", "UNIQUE" ] - }, - { - "type": "overmap_special", - "id": "Military Bunker", - "overmaps": [ - { "point": [ 0, -1, 0 ], "overmap": "road_end_north" }, - { "point": [ 0, 0, 0 ], "overmap": "bunker_south" }, - { "point": [ 0, 0, -1 ], "overmap": "bunker_basement_1" } - ], - "connections": [ { "point": [ 0, -1, 0 ], "from": [ 0, 0, 0 ] } ], - "locations": [ "forest" ], - "city_distance": [ 20, -1 ], - "occurrences": [ 25, 100 ], + "occurrences": [ 50, 100 ], "flags": [ "MILITARY", "UNIQUE" ] }, { @@ -844,16 +830,7 @@ "overmaps": [ { "point": [ 0, 0, 0 ], "overmap": "outpost_north" } ], "locations": [ "wilderness" ], "city_distance": [ 15, -1 ], - "occurrences": [ 25, 100 ], - "flags": [ "MILITARY", "UNIQUE" ] - }, - { - "type": "overmap_special", - "id": "Military Outpost", - "overmaps": [ { "point": [ 0, 0, 0 ], "overmap": "outpost_cross_north" } ], - "locations": [ "wilderness" ], - "city_distance": [ 15, -1 ], - "occurrences": [ 25, 100 ], + "occurrences": [ 50, 100 ], "flags": [ "MILITARY", "UNIQUE" ] }, { diff --git a/data/json/overmap/overmap_terrain/overmap_terrain_military.json b/data/json/overmap/overmap_terrain/overmap_terrain_military.json index 5a1343ef167a5..2fae29b7adae8 100644 --- a/data/json/overmap/overmap_terrain/overmap_terrain_military.json +++ b/data/json/overmap/overmap_terrain/overmap_terrain_military.json @@ -153,15 +153,6 @@ "see_cost": 2, "flags": [ "KNOWN_UP", "NO_ROTATE", "RISK_HIGH", "SOURCE_WEAPON", "SOURCE_AMMO" ] }, - { - "type": "overmap_terrain", - "id": "bunker_basement_1", - "name": "military bunker", - "sym": "B", - "color": "red", - "see_cost": 2, - "flags": [ "KNOWN_UP", "NO_ROTATE", "RISK_HIGH", "SOURCE_WEAPON", "SOURCE_AMMO" ] - }, { "type": "overmap_terrain", "id": "outpost", @@ -172,16 +163,6 @@ "extras": "build", "flags": [ "RISK_HIGH", "SOURCE_WEAPON", "SOURCE_AMMO" ] }, - { - "type": "overmap_terrain", - "id": "outpost_cross", - "name": "military outpost", - "sym": "M", - "color": "red", - "see_cost": 2, - "extras": "build", - "flags": [ "RISK_HIGH", "SOURCE_WEAPON", "SOURCE_AMMO" ] - }, { "type": "overmap_terrain", "id": [ "silo", "silo_1", "silo_2", "silo_3", "silo_4", "silo_finale" ], From b1e2233d272770053353a2abbc19ad5f34661ea5 Mon Sep 17 00:00:00 2001 From: krulunio Date: Fri, 21 May 2021 08:22:16 +0200 Subject: [PATCH 218/453] Revert "Revert "Split military outposts and bunkers"" This reverts commit 95a7e1139bf58b484cb22657f0bb5ed93b3fe7cd. --- data/json/mapgen/bunker.json | 4 +-- data/json/mapgen/outpost.json | 2 +- .../overmap/overmap_special/specials.json | 27 +++++++++++++++++-- .../overmap_terrain_military.json | 19 +++++++++++++ 4 files changed, 47 insertions(+), 5 deletions(-) diff --git a/data/json/mapgen/bunker.json b/data/json/mapgen/bunker.json index b5df262465190..75bbb4a50dea6 100644 --- a/data/json/mapgen/bunker.json +++ b/data/json/mapgen/bunker.json @@ -112,7 +112,7 @@ { "type": "mapgen", "method": "json", - "om_terrain": [ "bunker_basement" ], + "om_terrain": [ "bunker_basement_1" ], "weight": 250, "object": { "fill_ter": "t_floor", @@ -211,7 +211,7 @@ { "type": "mapgen", "method": "json", - "om_terrain": [ "bunker_basement" ], + "om_terrain": [ "bunker_basement_1" ], "weight": 500, "object": { "fill_ter": "t_floor", diff --git a/data/json/mapgen/outpost.json b/data/json/mapgen/outpost.json index d4cc2ee7ccddb..9fd42f451c407 100644 --- a/data/json/mapgen/outpost.json +++ b/data/json/mapgen/outpost.json @@ -149,7 +149,7 @@ { "type": "mapgen", "method": "json", - "om_terrain": [ "outpost" ], + "om_terrain": [ "outpost_cross" ], "weight": 100, "object": { "rows": [ diff --git a/data/json/overmap/overmap_special/specials.json b/data/json/overmap/overmap_special/specials.json index 326b01007d486..4d75c9f61d145 100644 --- a/data/json/overmap/overmap_special/specials.json +++ b/data/json/overmap/overmap_special/specials.json @@ -821,7 +821,21 @@ "connections": [ { "point": [ 0, -1, 0 ], "from": [ 0, 0, 0 ] } ], "locations": [ "forest" ], "city_distance": [ 20, -1 ], - "occurrences": [ 50, 100 ], + "occurrences": [ 25, 100 ], + "flags": [ "MILITARY", "UNIQUE" ] + }, + { + "type": "overmap_special", + "id": "Military Bunker", + "overmaps": [ + { "point": [ 0, -1, 0 ], "overmap": "road_end_north" }, + { "point": [ 0, 0, 0 ], "overmap": "bunker_south" }, + { "point": [ 0, 0, -1 ], "overmap": "bunker_basement_1" } + ], + "connections": [ { "point": [ 0, -1, 0 ], "from": [ 0, 0, 0 ] } ], + "locations": [ "forest" ], + "city_distance": [ 20, -1 ], + "occurrences": [ 25, 100 ], "flags": [ "MILITARY", "UNIQUE" ] }, { @@ -830,7 +844,16 @@ "overmaps": [ { "point": [ 0, 0, 0 ], "overmap": "outpost_north" } ], "locations": [ "wilderness" ], "city_distance": [ 15, -1 ], - "occurrences": [ 50, 100 ], + "occurrences": [ 25, 100 ], + "flags": [ "MILITARY", "UNIQUE" ] + }, + { + "type": "overmap_special", + "id": "Military Outpost", + "overmaps": [ { "point": [ 0, 0, 0 ], "overmap": "outpost_cross_north" } ], + "locations": [ "wilderness" ], + "city_distance": [ 15, -1 ], + "occurrences": [ 25, 100 ], "flags": [ "MILITARY", "UNIQUE" ] }, { diff --git a/data/json/overmap/overmap_terrain/overmap_terrain_military.json b/data/json/overmap/overmap_terrain/overmap_terrain_military.json index 2fae29b7adae8..5a1343ef167a5 100644 --- a/data/json/overmap/overmap_terrain/overmap_terrain_military.json +++ b/data/json/overmap/overmap_terrain/overmap_terrain_military.json @@ -153,6 +153,15 @@ "see_cost": 2, "flags": [ "KNOWN_UP", "NO_ROTATE", "RISK_HIGH", "SOURCE_WEAPON", "SOURCE_AMMO" ] }, + { + "type": "overmap_terrain", + "id": "bunker_basement_1", + "name": "military bunker", + "sym": "B", + "color": "red", + "see_cost": 2, + "flags": [ "KNOWN_UP", "NO_ROTATE", "RISK_HIGH", "SOURCE_WEAPON", "SOURCE_AMMO" ] + }, { "type": "overmap_terrain", "id": "outpost", @@ -163,6 +172,16 @@ "extras": "build", "flags": [ "RISK_HIGH", "SOURCE_WEAPON", "SOURCE_AMMO" ] }, + { + "type": "overmap_terrain", + "id": "outpost_cross", + "name": "military outpost", + "sym": "M", + "color": "red", + "see_cost": 2, + "extras": "build", + "flags": [ "RISK_HIGH", "SOURCE_WEAPON", "SOURCE_AMMO" ] + }, { "type": "overmap_terrain", "id": [ "silo", "silo_1", "silo_2", "silo_3", "silo_4", "silo_finale" ], From 223b4fa58859fb3f2a3171ae630bb04c600037d6 Mon Sep 17 00:00:00 2001 From: krulunio Date: Fri, 21 May 2021 08:23:19 +0200 Subject: [PATCH 219/453] Revert "Add mansion basecamp and related expansions" This reverts commit a36f1be5ffe6fb6ae4f94cbfd044e40417d18c0f. --- .../fbmc_mansion/fbmc_mansion_+1.json | 65 ------ .../fbmc_mansion/fbmc_mansion_+2.json | 23 -- .../fbmc_mansion/fbmc_mansion_+3.json | 23 -- .../fbmc_mansion/fbmc_mansion_+4.json | 52 ----- .../fbmc_mansion/fbmc_mansion_common.json | 34 --- .../fbmc_mansion/fbmc_mansion_expansion.json | 182 --------------- data/json/mapgen_palettes/basecamps.json | 12 - .../overmap_terrain_faction_base.json | 120 ---------- .../fbmc_mansion/fbmc_mansion_+1.json | 104 --------- .../fbmc_mansion/fbmc_mansion_+2.json | 78 ------- .../fbmc_mansion/fbmc_mansion_+3.json | 78 ------- .../fbmc_mansion/fbmc_mansion_+4.json | 104 --------- .../fbmc_mansion_expansion_surveys.json | 212 ------------------ .../json/recipes/basecamps/recipe_groups.json | 80 +------ 14 files changed, 2 insertions(+), 1165 deletions(-) delete mode 100644 data/json/mapgen/basecamps/fbmc_mansion/fbmc_mansion_+1.json delete mode 100644 data/json/mapgen/basecamps/fbmc_mansion/fbmc_mansion_+2.json delete mode 100644 data/json/mapgen/basecamps/fbmc_mansion/fbmc_mansion_+3.json delete mode 100644 data/json/mapgen/basecamps/fbmc_mansion/fbmc_mansion_+4.json delete mode 100644 data/json/mapgen/basecamps/fbmc_mansion/fbmc_mansion_common.json delete mode 100644 data/json/mapgen/basecamps/fbmc_mansion/fbmc_mansion_expansion.json delete mode 100644 data/json/mapgen_palettes/basecamps.json delete mode 100644 data/json/recipes/basecamps/fbmc_mansion/fbmc_mansion_+1.json delete mode 100644 data/json/recipes/basecamps/fbmc_mansion/fbmc_mansion_+2.json delete mode 100644 data/json/recipes/basecamps/fbmc_mansion/fbmc_mansion_+3.json delete mode 100644 data/json/recipes/basecamps/fbmc_mansion/fbmc_mansion_+4.json delete mode 100644 data/json/recipes/basecamps/fbmc_mansion/fbmc_mansion_expansion_surveys.json diff --git a/data/json/mapgen/basecamps/fbmc_mansion/fbmc_mansion_+1.json b/data/json/mapgen/basecamps/fbmc_mansion/fbmc_mansion_+1.json deleted file mode 100644 index fc125b95fb49f..0000000000000 --- a/data/json/mapgen/basecamps/fbmc_mansion/fbmc_mansion_+1.json +++ /dev/null @@ -1,65 +0,0 @@ -[ - { - "type": "mapgen", - "update_mapgen_id": "fbmc_mansion_+1", - "method": "json", - "object": { - "set": [ - { "point": "furniture", "id": "f_bulletin", "x": 9, "y": 9 } - ] - } - }, - { - "type": "mapgen", - "update_mapgen_id": "fbmc_mansion_+1_radio", - "method": "json", - "object": { - "set": [ - { "point": "terrain", "id": "t_radio_tower", "x": 8, "y": 9 }, - { "point": "terrain", "id": "t_radio_controls", "x": 8, "y": 10 } - ] - } - }, - { - "type": "mapgen", - "method": "json", - "nested_mapgen_id": "fbmc_mansion_+1_prefarm", - "object": { - "mapgensize": [ 12, 12 ], - "rows": [ - "dddd dddd", - "d d", - "d d", - "d d", - " ", - " ", - " ", - " ", - "d d", - "d d", - "d d", - "dddd dddd" - ], - "palettes": [ "fbmc_mansion_pallete" ] - } - }, - { - "type": "mapgen", - "update_mapgen_id": "fbmc_mansion_+1_farm", - "method": "json", - "object": { "place_nested": [ - { "chunks": [ "fbmc_mansion_+1_prefarm" ], "x": 6, "y": 6 }, - { "chunks": [ "fbmc_mansion_farm_field" ], "x": 6, "y": 5 }, - { "chunks": [ "fbmc_mansion_farm_field" ], "x": 13, "y": 5 }, - { "chunks": [ "fbmc_mansion_farm_field" ], "x": 1, "y": 17 }, - { "chunks": [ "fbmc_mansion_farm_field" ], "x": 6, "y": 17 }, - { "chunks": [ "fbmc_mansion_farm_field" ], "x": 1, "y": 20 }, - { "chunks": [ "fbmc_mansion_farm_field" ], "x": 6, "y": 20 }, - { "chunks": [ "fbmc_mansion_farm_field" ], "x": 13, "y": 17 }, - { "chunks": [ "fbmc_mansion_farm_field" ], "x": 18, "y": 17 }, - { "chunks": [ "fbmc_mansion_farm_field" ], "x": 13, "y": 20 }, - { "chunks": [ "fbmc_mansion_farm_field" ], "x": 18, "y": 20 } - ] - } - } -] \ No newline at end of file diff --git a/data/json/mapgen/basecamps/fbmc_mansion/fbmc_mansion_+2.json b/data/json/mapgen/basecamps/fbmc_mansion/fbmc_mansion_+2.json deleted file mode 100644 index a96149d602e29..0000000000000 --- a/data/json/mapgen/basecamps/fbmc_mansion/fbmc_mansion_+2.json +++ /dev/null @@ -1,23 +0,0 @@ -[ - { - "type": "mapgen", - "update_mapgen_id": "fbmc_mansion_+2", - "method": "json", - "object": { - "set": [ - { "point": "furniture", "id": "f_bulletin", "x": 18, "y": 6 } - ] - } - }, - { - "type": "mapgen", - "update_mapgen_id": "fbmc_mansion_+2_radio", - "method": "json", - "object": { - "set": [ - { "point": "terrain", "id": "t_radio_tower", "x": 12, "y": 0 }, - { "point": "terrain", "id": "t_radio_controls", "x": 12, "y": 1 } - ] - } - } -] \ No newline at end of file diff --git a/data/json/mapgen/basecamps/fbmc_mansion/fbmc_mansion_+3.json b/data/json/mapgen/basecamps/fbmc_mansion/fbmc_mansion_+3.json deleted file mode 100644 index 9d072287f84c4..0000000000000 --- a/data/json/mapgen/basecamps/fbmc_mansion/fbmc_mansion_+3.json +++ /dev/null @@ -1,23 +0,0 @@ -[ - { - "type": "mapgen", - "update_mapgen_id": "fbmc_mansion_+3", - "method": "json", - "object": { - "set": [ - { "point": "furniture", "id": "f_bulletin", "x": 17, "y": 20 } - ] - } - }, - { - "type": "mapgen", - "update_mapgen_id": "fbmc_mansion_+3_radio", - "method": "json", - "object": { - "set": [ - { "point": "terrain", "id": "t_radio_tower", "x": 6, "y": 0 }, - { "point": "terrain", "id": "t_radio_controls", "x": 6, "y": 1 } - ] - } - } -] \ No newline at end of file diff --git a/data/json/mapgen/basecamps/fbmc_mansion/fbmc_mansion_+4.json b/data/json/mapgen/basecamps/fbmc_mansion/fbmc_mansion_+4.json deleted file mode 100644 index 30e2d5bc241f8..0000000000000 --- a/data/json/mapgen/basecamps/fbmc_mansion/fbmc_mansion_+4.json +++ /dev/null @@ -1,52 +0,0 @@ -[ - { - "type": "mapgen", - "update_mapgen_id": "fbmc_mansion_+4", - "method": "json", - "object": { - "set": [ - { "point": "furniture", "id": "f_bulletin", "x": 9, "y": 2 } - ] - } - }, - { - "type": "mapgen", - "update_mapgen_id": "fbmc_mansion_+4_radio", - "method": "json", - "object": { - "set": [ - { "point": "terrain", "id": "t_radio_tower", "x": 14, "y": 10 }, - { "point": "terrain", "id": "t_radio_controls", "x": 14, "y": 11 } - ] - } - }, - { - "type": "mapgen", - "method": "json", - "nested_mapgen_id": "fbmc_mansion_+4_prefarm", - "object": { - "mapgensize": [ 6, 6 ], - "rows": [ - "dddddd", - "dddddd", - "dddddd", - "dddddd", - " ", - " " - ], - "palettes": [ "fbmc_mansion_pallete" ] - } - }, - { - "type": "mapgen", - "update_mapgen_id": "fbmc_mansion_+4_farm", - "method": "json", - "object": { "place_nested": [ - { "chunks": [ "fbmc_mansion_+4_prefarm" ], "x": 4, "y": 10 }, - { "chunks": [ "fbmc_mansion_+4_prefarm" ], "x": 14, "y": 10 }, - { "chunks": [ "fbmc_mansion_farm_field" ], "x": 4, "y": 11 }, - { "chunks": [ "fbmc_mansion_farm_field" ], "x": 14, "y": 11 } - ] - } - } -] \ No newline at end of file diff --git a/data/json/mapgen/basecamps/fbmc_mansion/fbmc_mansion_common.json b/data/json/mapgen/basecamps/fbmc_mansion/fbmc_mansion_common.json deleted file mode 100644 index 87116349d41fb..0000000000000 --- a/data/json/mapgen/basecamps/fbmc_mansion/fbmc_mansion_common.json +++ /dev/null @@ -1,34 +0,0 @@ -[ - { - "type": "mapgen", - "method": "json", - "nested_mapgen_id": "fbmc_mansion_farm_field", - "object": { - "mapgensize": [ 5, 5 ], - "rows": [ - "fffff", - "fffff", - " ", - " ", - " " - ], - "palettes": [ "fbmc_mansion_pallete" ] - } - }, - { - "type": "mapgen", - "method": "json", - "nested_mapgen_id": "fbmc_mansion_farm_field_thin", - "object": { - "mapgensize": [ 5, 5 ], - "rows": [ - "fffff", - " ", - " ", - " ", - " " - ], - "palettes": [ "fbmc_mansion_pallete" ] - } - } -] \ No newline at end of file diff --git a/data/json/mapgen/basecamps/fbmc_mansion/fbmc_mansion_expansion.json b/data/json/mapgen/basecamps/fbmc_mansion/fbmc_mansion_expansion.json deleted file mode 100644 index dd5274f304328..0000000000000 --- a/data/json/mapgen/basecamps/fbmc_mansion/fbmc_mansion_expansion.json +++ /dev/null @@ -1,182 +0,0 @@ -[ - { - "type": "mapgen", - "update_mapgen_id": "faction_base_mansion_e1", - "method": "json", - "object": { - "set": [ - { "point": "furniture", "id": "f_null", "x": 0, "y": 0 } - ] - } - }, - { - "type": "mapgen", - "update_mapgen_id": "faction_base_mansion_e2", - "method": "json", - "object": { - "set": [ - { "point": "furniture", "id": "f_null", "x": 0, "y": 0 } - ] - } - }, - { - "type": "mapgen", - "update_mapgen_id": "faction_base_mansion_t1", - "method": "json", - "object": { - "set": [ - { "point": "furniture", "id": "f_null", "x": 0, "y": 0 } - ] - } - }, - { - "type": "mapgen", - "update_mapgen_id": "faction_base_mansion_t2", - "method": "json", - "object": { - "set": [ - { "point": "furniture", "id": "f_null", "x": 0, "y": 0 } - ] - } - }, - { - "type": "mapgen", - "update_mapgen_id": "faction_base_mansion_t3", - "method": "json", - "object": { - "set": [ - { "point": "furniture", "id": "f_null", "x": 0, "y": 0 } - ] - } - }, - { - "type": "mapgen", - "update_mapgen_id": "faction_base_mansion_t4", - "method": "json", - "object": { - "set": [ - { "point": "furniture", "id": "f_null", "x": 0, "y": 0 } - ] - } - }, - { - "type": "mapgen", - "update_mapgen_id": "faction_base_mansion_t5", - "method": "json", - "object": { - "set": [ - { "point": "furniture", "id": "f_null", "x": 0, "y": 0 } - ] - } - }, - { - "type": "mapgen", - "update_mapgen_id": "faction_base_mansion_t6", - "method": "json", - "object": { - "set": [ - { "point": "furniture", "id": "f_null", "x": 0, "y": 0 } - ] - } - }, - { - "type": "mapgen", - "update_mapgen_id": "faction_base_mansion_t7", - "method": "json", - "object": { - "set": [ - { "point": "furniture", "id": "f_null", "x": 0, "y": 0 } - ] - } - }, - { - "type": "mapgen", - "update_mapgen_id": "faction_base_mansion_+1", - "method": "json", - "object": { - "set": [ - { "point": "furniture", "id": "f_null", "x": 0, "y": 0 } - ] - } - }, - { - "type": "mapgen", - "update_mapgen_id": "faction_base_mansion_+2", - "method": "json", - "object": { - "set": [ - { "point": "furniture", "id": "f_null", "x": 0, "y": 0 } - ] - } - }, - { - "type": "mapgen", - "update_mapgen_id": "faction_base_mansion_+3", - "method": "json", - "object": { - "set": [ - { "point": "furniture", "id": "f_null", "x": 0, "y": 0 } - ] - } - }, - { - "type": "mapgen", - "update_mapgen_id": "faction_base_mansion_+4", - "method": "json", - "object": { - "set": [ - { "point": "furniture", "id": "f_null", "x": 0, "y": 0 } - ] - } - }, - { - "type": "mapgen", - "update_mapgen_id": "faction_base_mansion_c1", - "method": "json", - "object": { - "set": [ - { "point": "furniture", "id": "f_null", "x": 0, "y": 0 } - ] - } - }, - { - "type": "mapgen", - "update_mapgen_id": "faction_base_mansion_c2", - "method": "json", - "object": { - "set": [ - { "point": "furniture", "id": "f_null", "x": 0, "y": 0 } - ] - } - }, - { - "type": "mapgen", - "update_mapgen_id": "faction_base_mansion_c3", - "method": "json", - "object": { - "set": [ - { "point": "furniture", "id": "f_null", "x": 0, "y": 0 } - ] - } - }, - { - "type": "mapgen", - "update_mapgen_id": "faction_base_mansion_c4", - "method": "json", - "object": { - "set": [ - { "point": "furniture", "id": "f_null", "x": 0, "y": 0 } - ] - } - }, - { - "type": "mapgen", - "update_mapgen_id": "faction_base_mansion_c5", - "method": "json", - "object": { - "set": [ - { "point": "furniture", "id": "f_null", "x": 0, "y": 0 } - ] - } - } -] \ No newline at end of file diff --git a/data/json/mapgen_palettes/basecamps.json b/data/json/mapgen_palettes/basecamps.json deleted file mode 100644 index e88348cbf6c9c..0000000000000 --- a/data/json/mapgen_palettes/basecamps.json +++ /dev/null @@ -1,12 +0,0 @@ -[ - { - "type": "palette", - "id": "fbmc_mansion_pallete", - "terrain": { - "d": "t_dirt", - "f": "t_dirtmound", - "W": "t_wall_wood", - "D": "t_rdoor_c" - } - } -] \ No newline at end of file diff --git a/data/json/overmap/overmap_terrain/overmap_terrain_faction_base.json b/data/json/overmap/overmap_terrain/overmap_terrain_faction_base.json index 1ed36875a82ac..aceb9c17e4519 100644 --- a/data/json/overmap/overmap_terrain/overmap_terrain_faction_base.json +++ b/data/json/overmap/overmap_terrain/overmap_terrain_faction_base.json @@ -189,125 +189,5 @@ "name": "canteen survey", "color": "i_green", "delete": { "flags": [ "SOURCE_PEOPLE" ] } - }, - { - "type": "overmap_terrain", - "id": "faction_base_mansion_e1", - "name": "mansion base entrance", - "sym": "M", - "color": "white", - "flags": [ "SOURCE_PEOPLE", "NO_ROTATE" ] - }, - { - "type": "overmap_terrain", - "id": "faction_base_mansion_e2", - "name": "mansion base entrance", - "sym": "M", - "color": "white", - "flags": [ "SOURCE_PEOPLE", "NO_ROTATE" ] - }, - { - "type": "overmap_terrain", - "id": "faction_base_mansion_t1", - "name": "mansion base swimming pool", - "sym": "M", - "color": "blue", - "flags": [ "SOURCE_PEOPLE", "NO_ROTATE" ] - }, - { - "type": "overmap_terrain", - "id": "faction_base_mansion_t2", - "name": "mansion base bedrooms", - "sym": "M", - "color": "light_green", - "flags": [ "SOURCE_PEOPLE", "NO_ROTATE" ] - }, - { - "type": "overmap_terrain", - "id": "faction_base_mansion_t3", - "name": "mansion base ???", - "sym": "M", - "color": "white", - "flags": [ "SOURCE_PEOPLE", "NO_ROTATE" ] - }, - { - "type": "overmap_terrain", - "id": "faction_base_mansion_t4", - "name": "mansion base kitchen", - "sym": "M", - "color": "pink", - "flags": [ "SOURCE_PEOPLE", "NO_ROTATE" ] - }, - { - "type": "overmap_terrain", - "id": "faction_base_mansion_t5", - "name": "mansion base library", - "sym": "M", - "color": "brown", - "flags": [ "SOURCE_PEOPLE", "NO_ROTATE" ] - }, - { - "type": "overmap_terrain", - "id": "faction_base_mansion_t6", - "name": "mansion base bedroom", - "sym": "M", - "color": "light_green", - "flags": [ "SOURCE_PEOPLE", "NO_ROTATE" ] - }, - { - "type": "overmap_terrain", - "id": "faction_base_mansion_t7", - "name": "mansion base living rooms", - "sym": "M", - "color": "green", - "flags": [ "SOURCE_PEOPLE", "NO_ROTATE" ] - }, - { - "type": "overmap_terrain", - "id": "faction_base_mansion_c1", - "name": "mansion base swimming pool", - "sym": "M", - "color": "blue", - "flags": [ "SOURCE_PEOPLE", "NO_ROTATE" ] - }, - { - "type": "overmap_terrain", - "id": "faction_base_mansion_c2", - "name": "mansion base bar", - "sym": "M", - "color": "magenta", - "flags": [ "SOURCE_PEOPLE", "NO_ROTATE" ] - }, - { - "type": "overmap_terrain", - "id": "faction_base_mansion_c3", - "name": "mansion base living rooms", - "sym": "M", - "color": "green", - "flags": [ "SOURCE_PEOPLE", "NO_ROTATE" ] - }, - { - "type": "overmap_terrain", - "id": "faction_base_mansion_c4", - "name": "mansion base bedroom", - "sym": "M", - "color": "light_green", - "flags": [ "SOURCE_PEOPLE", "NO_ROTATE" ] - }, - { - "type": "overmap_terrain", - "id": "faction_base_mansion_c5", - "name": "mansion base kitchen", - "sym": "M", - "color": "pink", - "flags": [ "SOURCE_PEOPLE", "NO_ROTATE" ] - }, - { - "type": "overmap_terrain", - "id": "faction_base_lake_shore", - "name": "fishing spot", - "sym": "+", - "color": "i_light_blue", - "flags": [ "SOURCE_PEOPLE", "NO_ROTATE", "LAKE_SHORE", "SOURCE_DRINK" ] } ] diff --git a/data/json/recipes/basecamps/fbmc_mansion/fbmc_mansion_+1.json b/data/json/recipes/basecamps/fbmc_mansion/fbmc_mansion_+1.json deleted file mode 100644 index 7d0edfaf04c6d..0000000000000 --- a/data/json/recipes/basecamps/fbmc_mansion/fbmc_mansion_+1.json +++ /dev/null @@ -1,104 +0,0 @@ -[ - { - "type": "recipe", - "result": "faction_base_mansion_+1_0", - "description": "We should survey the base site and set up a bulletin board.", - "category": "CC_BUILDING", - "subcategory": "CSC_BUILDING_BASES", - "skill_used": "fabrication", - "autolearn": false, - "never_learn": true, - "time": "1 h", - "construction_blueprint": "fbmc_mansion_+1", - "blueprint_provides": [ - { "id": "fbmc_mansion_+1" }, - { "id": "primitive_camp_recipes_1" }, - { "id": "gathering" }, - { "id": "firewood" }, - { "id": "foraging" }, - { "id": "sorting" }, - { "id": "logging" }, - { "id": "tool_storage" }, - { "id": "bed", "amount": 8 } - ], - "blueprint_requires": [ { "id": "not_an_upgrade" } ], - "blueprint_name": "basic survey", - "check_blueprint_needs": false - }, - { - "type": "recipe", - "result": "faction_base_mansion_+1_garden", - "description": "Let's remove plants from garden and plow a few plots.", - "category": "CC_BUILDING", - "subcategory": "CSC_BUILDING_BASES", - "skill_used": "fabrication", - "autolearn": false, - "never_learn": true, - "construction_blueprint": "fbmc_mansion_+1_farm", - "blueprint_name": "prepare garden", - "blueprint_requires": [ { "id": "fbmc_mansion_+1" } ], - "blueprint_provides": [ - { "id": "fbmc_mansion_+1_farm" }, - { "id": "farming" }, - { "id": "farm_recipes_1" } - ], - "blueprint_excludes": [ { "id": "fbmc_mansion_+1_farm" } ], - "blueprint_needs": { - "time": "7 h", - "inline": { - "tools": [ ], - "qualities": [ [ { "id": "DIG", "level": 1 } ] ] - } - } - }, - { - "type": "recipe", - "result": "faction_base_mansion_+1_radio", - "description": "Let's set up a radio tower to improve our recruitment efforts.", - "category": "CC_BUILDING", - "subcategory": "CSC_BUILDING_BASES", - "autolearn": false, - "never_learn": true, - "construction_blueprint": "fbmc_mansion_+1_radio", - "blueprint_name": "build a radio tower and console", - "blueprint_requires": [ { "id": "fbmc_mansion_+1_farm" } ], - "blueprint_provides": [ - { "id": "fbmc_mansion_+1_radio" }, - { "id": "recruiting" }, - { "id": "radio" } - ], - "blueprint_excludes": [ { "id": "fbmc_mansion_+1_radio" } ], - "blueprint_needs": { - "time": "2 d", - "skills": [ [ "fabrication", 3 ] ], - "inline": { - "tools": [ ], - "qualities": [ [ { "id": "HAMMER", "level": 2 } ], [ { "id": "SAW_M" } ], [ { "id": "SCREW" } ], [ { "id": "WRENCH" } ] ], - "components": [ - [ - [ "wind_turbine", 4 ], - [ "xl_wind_turbine", 1 ], - [ "solar_panel", 4 ], - [ "reinforced_solar_panel", 4 ], - [ "solar_panel_v2", 2 ], - [ "reinforced_solar_panel_v2", 2 ], - [ "solar_panel_v3", 1 ] - ], - [ [ "storage_battery", 1 ], [ "medium_storage_battery", 4 ], [ "small_storage_battery", 32 ] ], - [ [ "sheet_metal", 2 ], [ "wire", 8 ] ], - [ [ "pipe", 24 ] ], - [ [ "processor", 2 ] ], - [ [ "RAM", 2 ] ], - [ [ "large_lcd_screen", 1 ] ], - [ [ "e_scrap", 8 ] ], - [ [ "frame", 1 ] ], - [ [ "circuit", 4 ] ], - [ [ "power_supply", 2 ] ], - [ [ "amplifier", 2 ] ], - [ [ "cable", 80 ] ], - [ [ "motor_small", 1 ], [ "motor_tiny", 2 ] ] - ] - } - } - } -] diff --git a/data/json/recipes/basecamps/fbmc_mansion/fbmc_mansion_+2.json b/data/json/recipes/basecamps/fbmc_mansion/fbmc_mansion_+2.json deleted file mode 100644 index 50dc6066206f3..0000000000000 --- a/data/json/recipes/basecamps/fbmc_mansion/fbmc_mansion_+2.json +++ /dev/null @@ -1,78 +0,0 @@ -[ - { - "type": "recipe", - "result": "faction_base_mansion_+2_0", - "description": "We should survey the base site and set up a bulletin board.", - "category": "CC_BUILDING", - "subcategory": "CSC_BUILDING_BASES", - "skill_used": "fabrication", - "autolearn": false, - "never_learn": true, - "time": "1 h", - "construction_blueprint": "fbmc_mansion_+2", - "blueprint_provides": [ - { "id": "fbmc_mansion_+2" }, - { "id": "primitive_camp_recipes_1" }, - { "id": "gathering" }, - { "id": "firewood" }, - { "id": "foraging" }, - { "id": "sorting" }, - { "id": "logging" }, - { "id": "tool_storage" }, - { "id": "bed", "amount": 8 } - ], - "blueprint_requires": [ { "id": "not_an_upgrade" } ], - "blueprint_name": "basic survey", - "check_blueprint_needs": false - }, - { - "type": "recipe", - "result": "faction_base_mansion_+2_radio", - "description": "Let's set up a radio tower to improve our recruitment efforts.", - "category": "CC_BUILDING", - "subcategory": "CSC_BUILDING_BASES", - "autolearn": false, - "never_learn": true, - "construction_blueprint": "fbmc_mansion_+2_radio", - "blueprint_name": "build a radio tower and console", - "blueprint_requires": [ { "id": "fbmc_mansion_+2" } ], - "blueprint_provides": [ - { "id": "fbmc_mansion_+2_radio" }, - { "id": "recruiting" }, - { "id": "radio" } - ], - "blueprint_excludes": [ { "id": "fbmc_mansion_+2_radio" } ], - "blueprint_needs": { - "time": "2 d", - "skills": [ [ "fabrication", 3 ] ], - "inline": { - "tools": [ ], - "qualities": [ [ { "id": "HAMMER", "level": 2 } ], [ { "id": "SAW_M" } ], [ { "id": "SCREW" } ], [ { "id": "WRENCH" } ] ], - "components": [ - [ - [ "wind_turbine", 4 ], - [ "xl_wind_turbine", 1 ], - [ "solar_panel", 4 ], - [ "reinforced_solar_panel", 4 ], - [ "solar_panel_v2", 2 ], - [ "reinforced_solar_panel_v2", 2 ], - [ "solar_panel_v3", 1 ] - ], - [ [ "storage_battery", 1 ], [ "medium_storage_battery", 4 ], [ "small_storage_battery", 32 ] ], - [ [ "sheet_metal", 2 ], [ "wire", 8 ] ], - [ [ "pipe", 24 ] ], - [ [ "processor", 2 ] ], - [ [ "RAM", 2 ] ], - [ [ "large_lcd_screen", 1 ] ], - [ [ "e_scrap", 8 ] ], - [ [ "frame", 1 ] ], - [ [ "circuit", 4 ] ], - [ [ "power_supply", 2 ] ], - [ [ "amplifier", 2 ] ], - [ [ "cable", 80 ] ], - [ [ "motor_small", 1 ], [ "motor_tiny", 2 ] ] - ] - } - } - } -] diff --git a/data/json/recipes/basecamps/fbmc_mansion/fbmc_mansion_+3.json b/data/json/recipes/basecamps/fbmc_mansion/fbmc_mansion_+3.json deleted file mode 100644 index 7bf5a0a53e9e6..0000000000000 --- a/data/json/recipes/basecamps/fbmc_mansion/fbmc_mansion_+3.json +++ /dev/null @@ -1,78 +0,0 @@ -[ - { - "type": "recipe", - "result": "faction_base_mansion_+3_0", - "description": "We should survey the base site and set up a bulletin board.", - "category": "CC_BUILDING", - "subcategory": "CSC_BUILDING_BASES", - "skill_used": "fabrication", - "autolearn": false, - "never_learn": true, - "time": "1 h", - "construction_blueprint": "fbmc_mansion_+3", - "blueprint_provides": [ - { "id": "fbmc_mansion_+3" }, - { "id": "primitive_camp_recipes_1" }, - { "id": "gathering" }, - { "id": "firewood" }, - { "id": "foraging" }, - { "id": "sorting" }, - { "id": "logging" }, - { "id": "tool_storage" }, - { "id": "bed", "amount": 8 } - ], - "blueprint_requires": [ { "id": "not_an_upgrade" } ], - "blueprint_name": "basic survey", - "check_blueprint_needs": false - }, - { - "type": "recipe", - "result": "faction_base_mansion_+3_radio", - "description": "Let's set up a radio tower to improve our recruitment efforts.", - "category": "CC_BUILDING", - "subcategory": "CSC_BUILDING_BASES", - "autolearn": false, - "never_learn": true, - "construction_blueprint": "fbmc_mansion_+3_radio", - "blueprint_name": "build a radio tower and console", - "blueprint_requires": [ { "id": "fbmc_mansion_+3" } ], - "blueprint_provides": [ - { "id": "fbmc_mansion_+3_radio" }, - { "id": "recruiting" }, - { "id": "radio" } - ], - "blueprint_excludes": [ { "id": "fbmc_mansion_+3_radio" } ], - "blueprint_needs": { - "time": "2 d", - "skills": [ [ "fabrication", 3 ] ], - "inline": { - "tools": [ ], - "qualities": [ [ { "id": "HAMMER", "level": 2 } ], [ { "id": "SAW_M" } ], [ { "id": "SCREW" } ], [ { "id": "WRENCH" } ] ], - "components": [ - [ - [ "wind_turbine", 4 ], - [ "xl_wind_turbine", 1 ], - [ "solar_panel", 4 ], - [ "reinforced_solar_panel", 4 ], - [ "solar_panel_v2", 2 ], - [ "reinforced_solar_panel_v2", 2 ], - [ "solar_panel_v3", 1 ] - ], - [ [ "storage_battery", 1 ], [ "medium_storage_battery", 4 ], [ "small_storage_battery", 32 ] ], - [ [ "sheet_metal", 2 ], [ "wire", 8 ] ], - [ [ "pipe", 24 ] ], - [ [ "processor", 2 ] ], - [ [ "RAM", 2 ] ], - [ [ "large_lcd_screen", 1 ] ], - [ [ "e_scrap", 8 ] ], - [ [ "frame", 1 ] ], - [ [ "circuit", 4 ] ], - [ [ "power_supply", 2 ] ], - [ [ "amplifier", 2 ] ], - [ [ "cable", 80 ] ], - [ [ "motor_small", 1 ], [ "motor_tiny", 2 ] ] - ] - } - } - } -] diff --git a/data/json/recipes/basecamps/fbmc_mansion/fbmc_mansion_+4.json b/data/json/recipes/basecamps/fbmc_mansion/fbmc_mansion_+4.json deleted file mode 100644 index 57b315b86c57b..0000000000000 --- a/data/json/recipes/basecamps/fbmc_mansion/fbmc_mansion_+4.json +++ /dev/null @@ -1,104 +0,0 @@ -[ - { - "type": "recipe", - "result": "faction_base_mansion_+4_0", - "description": "We should survey the base site and set up a bulletin board.", - "category": "CC_BUILDING", - "subcategory": "CSC_BUILDING_BASES", - "skill_used": "fabrication", - "autolearn": false, - "never_learn": true, - "time": "1 h", - "construction_blueprint": "fbmc_mansion_+4", - "blueprint_provides": [ - { "id": "fbmc_mansion_+4" }, - { "id": "primitive_camp_recipes_1" }, - { "id": "gathering" }, - { "id": "firewood" }, - { "id": "foraging" }, - { "id": "sorting" }, - { "id": "logging" }, - { "id": "tool_storage" }, - { "id": "bed", "amount": 8 } - ], - "blueprint_requires": [ { "id": "not_an_upgrade" } ], - "blueprint_name": "basic survey", - "check_blueprint_needs": false - }, - { - "type": "recipe", - "result": "faction_base_mansion_+4_garden", - "description": "Let's remove plants from garden and plow a few plots.", - "category": "CC_BUILDING", - "subcategory": "CSC_BUILDING_BASES", - "skill_used": "fabrication", - "autolearn": false, - "never_learn": true, - "construction_blueprint": "fbmc_mansion_+4_farm", - "blueprint_name": "prepare garden", - "blueprint_requires": [ { "id": "fbmc_mansion_+4" } ], - "blueprint_provides": [ - { "id": "fbmc_mansion_+4_farm" }, - { "id": "farming" }, - { "id": "farm_recipes_1" } - ], - "blueprint_excludes": [ { "id": "fbmc_mansion_+1_farm" } ], - "blueprint_needs": { - "time": "2 h", - "inline": { - "tools": [ ], - "qualities": [ [ { "id": "DIG", "level": 1 } ] ] - } - } - }, - { - "type": "recipe", - "result": "faction_base_mansion_+4_radio", - "description": "Let's set up a radio tower to improve our recruitment efforts.", - "category": "CC_BUILDING", - "subcategory": "CSC_BUILDING_BASES", - "autolearn": false, - "never_learn": true, - "construction_blueprint": "fbmc_mansion_+4_radio", - "blueprint_name": "build a radio tower and console", - "blueprint_requires": [ { "id": "fbmc_mansion_+4_farm" } ], - "blueprint_provides": [ - { "id": "fbmc_mansion_+4_radio" }, - { "id": "recruiting" }, - { "id": "radio" } - ], - "blueprint_excludes": [ { "id": "fbmc_mansion_+4_radio" } ], - "blueprint_needs": { - "time": "2 d", - "skills": [ [ "fabrication", 3 ] ], - "inline": { - "tools": [ ], - "qualities": [ [ { "id": "HAMMER", "level": 2 } ], [ { "id": "SAW_M" } ], [ { "id": "SCREW" } ], [ { "id": "WRENCH" } ] ], - "components": [ - [ - [ "wind_turbine", 4 ], - [ "xl_wind_turbine", 1 ], - [ "solar_panel", 4 ], - [ "reinforced_solar_panel", 4 ], - [ "solar_panel_v2", 2 ], - [ "reinforced_solar_panel_v2", 2 ], - [ "solar_panel_v3", 1 ] - ], - [ [ "storage_battery", 1 ], [ "medium_storage_battery", 4 ], [ "small_storage_battery", 32 ] ], - [ [ "sheet_metal", 2 ], [ "wire", 8 ] ], - [ [ "pipe", 24 ] ], - [ [ "processor", 2 ] ], - [ [ "RAM", 2 ] ], - [ [ "large_lcd_screen", 1 ] ], - [ [ "e_scrap", 8 ] ], - [ [ "frame", 1 ] ], - [ [ "circuit", 4 ] ], - [ [ "power_supply", 2 ] ], - [ [ "amplifier", 2 ] ], - [ [ "cable", 80 ] ], - [ [ "motor_small", 1 ], [ "motor_tiny", 2 ] ] - ] - } - } - } -] diff --git a/data/json/recipes/basecamps/fbmc_mansion/fbmc_mansion_expansion_surveys.json b/data/json/recipes/basecamps/fbmc_mansion/fbmc_mansion_expansion_surveys.json deleted file mode 100644 index c8cf5ee17a87a..0000000000000 --- a/data/json/recipes/basecamps/fbmc_mansion/fbmc_mansion_expansion_surveys.json +++ /dev/null @@ -1,212 +0,0 @@ -[ - { - "type": "recipe", - "result": "faction_base_mansion_e1", - "description": "Survey mansion's entrance.", - "category": "CC_BUILDING", - "subcategory": "CSC_BUILDING_BASES", - "skill_used": "fabrication", - "autolearn": false, - "never_learn": true, - "construction_blueprint": "faction_base_mansion_e1", - "blueprint_name": "entrance survey", - "time": "180 m", - "blueprint_requires": [ { "id": "not_an_upgrade" } ], - "blueprint_provides": [ { "id": "faction_base_mansion_e1" }, { "id": "farming" }, { "id": "reseeding" }, { "id": "farm_recipes_1" } ] - }, - { - "type": "recipe", - "result": "faction_base_mansion_e2", - "description": "Survey mansion's entrance.", - "category": "CC_BUILDING", - "subcategory": "CSC_BUILDING_BASES", - "skill_used": "fabrication", - "autolearn": false, - "never_learn": true, - "construction_blueprint": "faction_base_mansion_e2", - "blueprint_name": "entrance survey", - "time": "180 m", - "blueprint_requires": [ { "id": "not_an_upgrade" } ], - "blueprint_provides": [ { "id": "faction_base_mansion_e2" }, { "id": "farming" }, { "id": "reseeding" }, { "id": "farm_recipes_1" } ] - }, - { - "type": "recipe", - "result": "faction_base_mansion_t1", - "description": "Survey mansion's swimming pool.", - "category": "CC_BUILDING", - "subcategory": "CSC_BUILDING_BASES", - "skill_used": "fabrication", - "autolearn": false, - "never_learn": true, - "construction_blueprint": "faction_base_mansion_t1", - "blueprint_name": "swimming pool survey", - "time": "180 m", - "blueprint_requires": [ { "id": "not_an_upgrade" } ], - "blueprint_provides": [ { "id": "faction_base_mansion_t1" }, { "id": "farming" }, { "id": "reseeding" }, { "id": "farm_recipes_1" } ] - }, - { - "type": "recipe", - "result": "faction_base_mansion_t2", - "description": "Survey mansion's bedrooms.", - "category": "CC_BUILDING", - "subcategory": "CSC_BUILDING_BASES", - "skill_used": "fabrication", - "autolearn": false, - "never_learn": true, - "construction_blueprint": "faction_base_mansion_t2", - "blueprint_name": "bedrooms survey", - "time": "180 m", - "blueprint_requires": [ { "id": "not_an_upgrade" } ], - "blueprint_provides": [ { "id": "faction_base_mansion_t2" } ] - }, - { - "type": "recipe", - "result": "faction_base_mansion_t3", - "description": "Survey mansion's ???.", - "category": "CC_BUILDING", - "subcategory": "CSC_BUILDING_BASES", - "skill_used": "fabrication", - "autolearn": false, - "never_learn": true, - "construction_blueprint": "faction_base_mansion_t3", - "blueprint_name": "??? survey", - "time": "180 m", - "blueprint_requires": [ { "id": "not_an_upgrade" } ], - "blueprint_provides": [ { "id": "faction_base_mansion_t3" } ] - }, - { - "type": "recipe", - "result": "faction_base_mansion_t4", - "description": "Survey mansion's kitchen.", - "category": "CC_BUILDING", - "subcategory": "CSC_BUILDING_BASES", - "skill_used": "fabrication", - "autolearn": false, - "never_learn": true, - "construction_blueprint": "faction_base_mansion_t4", - "blueprint_name": "kitchen survey", - "time": "180 m", - "blueprint_requires": [ { "id": "not_an_upgrade" } ], - "blueprint_provides": [ { "id": "faction_base_mansion_t4" }, { "id": "kitchen" }, { "id": "kitchen_recipes_1" }, { "id": "kitchen_recipes_2" }, { "id": "kitchen_recipes_3" }, { "id": "saltworks_recipes_1" }, { "id": "saltworks_recipes_2" }, { "id": "saltworks_recipes_3" } ] - }, - { - "type": "recipe", - "result": "faction_base_mansion_t5", - "description": "Survey mansion's library.", - "category": "CC_BUILDING", - "subcategory": "CSC_BUILDING_BASES", - "skill_used": "fabrication", - "autolearn": false, - "never_learn": true, - "construction_blueprint": "faction_base_mansion_t5", - "blueprint_name": "library survey", - "time": "180 m", - "blueprint_requires": [ { "id": "not_an_upgrade" } ], - "blueprint_provides": [ { "id": "faction_base_mansion_t5" }, { "id": "kitchen" }, { "id": "library_recipes_1" } ] - }, - { - "type": "recipe", - "result": "faction_base_mansion_t6", - "description": "Survey mansion's bedroom.", - "category": "CC_BUILDING", - "subcategory": "CSC_BUILDING_BASES", - "skill_used": "fabrication", - "autolearn": false, - "never_learn": true, - "construction_blueprint": "faction_base_mansion_t6", - "blueprint_name": "bedroom survey", - "time": "180 m", - "blueprint_requires": [ { "id": "not_an_upgrade" } ], - "blueprint_provides": [ { "id": "faction_base_mansion_t6" } ] - }, - { - "type": "recipe", - "result": "faction_base_mansion_t7", - "description": "Survey mansion's living rooms.", - "category": "CC_BUILDING", - "subcategory": "CSC_BUILDING_BASES", - "skill_used": "fabrication", - "autolearn": false, - "never_learn": true, - "construction_blueprint": "faction_base_mansion_t7", - "blueprint_name": "living rooms survey", - "time": "180 m", - "blueprint_requires": [ { "id": "not_an_upgrade" } ], - "blueprint_provides": [ { "id": "faction_base_mansion_t7" } ] - }, - { - "type": "recipe", - "result": "faction_base_mansion_c1", - "description": "Survey mansion's swimming pool.", - "category": "CC_BUILDING", - "subcategory": "CSC_BUILDING_BASES", - "skill_used": "fabrication", - "autolearn": false, - "never_learn": true, - "construction_blueprint": "faction_base_mansion_c1", - "blueprint_name": "swimming survey", - "time": "180 m", - "blueprint_requires": [ { "id": "not_an_upgrade" } ], - "blueprint_provides": [ { "id": "faction_base_mansion_c1" } ] - }, - { - "type": "recipe", - "result": "faction_base_mansion_c2", - "description": "Survey mansion's bar.", - "category": "CC_BUILDING", - "subcategory": "CSC_BUILDING_BASES", - "skill_used": "fabrication", - "autolearn": false, - "never_learn": true, - "construction_blueprint": "faction_base_mansion_c2", - "blueprint_name": "bar survey", - "time": "180 m", - "blueprint_requires": [ { "id": "not_an_upgrade" } ], - "blueprint_provides": [ { "id": "faction_base_mansion_c2" }, { "id": "kitchen" }, { "id": "kitchen_recipes_1" }, { "id": "kitchen_recipes_2" }, { "id": "kitchen_recipes_3" } ] - }, - { - "type": "recipe", - "result": "faction_base_mansion_c3", - "description": "Survey mansion's living rooms.", - "category": "CC_BUILDING", - "subcategory": "CSC_BUILDING_BASES", - "skill_used": "fabrication", - "autolearn": false, - "never_learn": true, - "construction_blueprint": "faction_base_mansion_c3", - "blueprint_name": "living rooms survey", - "time": "180 m", - "blueprint_requires": [ { "id": "not_an_upgrade" } ], - "blueprint_provides": [ { "id": "faction_base_mansion_c3" } ] - }, - { - "type": "recipe", - "result": "faction_base_mansion_c4", - "description": "Survey mansion's bedroom.", - "category": "CC_BUILDING", - "subcategory": "CSC_BUILDING_BASES", - "skill_used": "fabrication", - "autolearn": false, - "never_learn": true, - "construction_blueprint": "faction_base_mansion_c4", - "blueprint_name": "bedroom survey", - "time": "180 m", - "blueprint_requires": [ { "id": "not_an_upgrade" } ], - "blueprint_provides": [ { "id": "faction_base_mansion_c4" } ] - }, - { - "type": "recipe", - "result": "faction_base_mansion_c5", - "description": "Survey mansion's kitchen.", - "category": "CC_BUILDING", - "subcategory": "CSC_BUILDING_BASES", - "skill_used": "fabrication", - "autolearn": false, - "never_learn": true, - "construction_blueprint": "faction_base_mansion_c5", - "blueprint_name": "kitchen survey", - "time": "180 m", - "blueprint_requires": [ { "id": "not_an_upgrade" } ], - "blueprint_provides": [ { "id": "faction_base_mansion_c5" }, { "id": "kitchen" }, { "id": "kitchen_recipes_1" }, { "id": "kitchen_recipes_2" }, { "id": "kitchen_recipes_3" }, { "id": "saltworks_recipes_1" }, { "id": "saltworks_recipes_2" }, { "id": "saltworks_recipes_3" } ] - } -] diff --git a/data/json/recipes/basecamps/recipe_groups.json b/data/json/recipes/basecamps/recipe_groups.json index 2140baa817029..44399021cf29b 100644 --- a/data/json/recipes/basecamps/recipe_groups.json +++ b/data/json/recipes/basecamps/recipe_groups.json @@ -24,27 +24,7 @@ "id": "faction_base_shelter_2_0", "description": "Central Stairs Evac Shelter Base", "om_terrains": [ "shelter_2", "shelter_2_vandal" ] - }, - { - "id": "faction_base_mansion_+1_0", - "description": "Mansion Fountain Garden Base", - "om_terrains": [ "mansion_+1" ] - }, - { - "id": "faction_base_mansion_+2_0", - "description": "Mansion Dance Floor Room Base", - "om_terrains": [ "mansion_+2" ] - }, - { - "id": "faction_base_mansion_+3_0", - "description": "Mansion Basketball Room Base", - "om_terrains": [ "mansion_+3" ] - }, - { - "id": "faction_base_mansion_+4_0", - "description": "Mansion Garden With Columns Base", - "om_terrains": [ "mansion_+4" ] - } + } ] }, { @@ -58,63 +38,7 @@ { "id": "faction_base_livestock_0", "description": "Livestock Area", "om_terrains": [ "field" ] }, { "id": "faction_base_storehouse_0", "description": "Central Storage Building", "om_terrains": [ "field" ] }, { "id": "faction_base_saltworks_0", "description": "Saltworks Area", "om_terrains": [ "field" ] }, - { "id": "faction_base_workshop_0", "description": "Fabrication Workshop", "om_terrains": [ "field" ] }, - { "id": "faction_base_mansion_e1", - "description": "Mansion's Entrance", - "om_terrains": [ "mansion_e1" ] - }, - { "id": "faction_base_mansion_e2", - "description": "Mansion's Entrance", - "om_terrains": [ "mansion_e2" ] - }, - { "id": "faction_base_mansion_t1", - "description": "Mansion's Swimming Pool", - "om_terrains": [ "mansion_t1" ] - }, - { "id": "faction_base_mansion_t2", - "description": "Mansion's Bedrooms", - "om_terrains": [ "mansion_t2" ] - }, - { "id": "faction_base_mansion_t3", - "description": "Mansion's ???", - "om_terrains": [ "mansion_t3" ] - }, - { "id": "faction_base_mansion_t4", - "description": "Mansion's Kitchen", - "om_terrains": [ "mansion_t4" ] - }, - { "id": "faction_base_mansion_t5", - "description": "Mansion's Library", - "om_terrains": [ "mansion_t5" ] - }, - { "id": "faction_base_mansion_t6", - "description": "Mansion's Bedroom", - "om_terrains": [ "mansion_t6" ] - }, - { "id": "faction_base_mansion_t7", - "description": "Mansion's Living Rooms", - "om_terrains": [ "mansion_t7" ] - }, - { "id": "faction_base_mansion_c1", - "description": "Mansion's Swimming Pool", - "om_terrains": [ "mansion_c1" ] - }, - { "id": "faction_base_mansion_c2", - "description": "Mansion's Bar", - "om_terrains": [ "mansion_c2" ] - }, - { "id": "faction_base_mansion_c3", - "description": "Mansion's Living Rooms", - "om_terrains": [ "mansion_c3" ] - }, - { "id": "faction_base_mansion_c4", - "description": "Mansion's Bedroom", - "om_terrains": [ "mansion_c4" ] - }, - { "id": "faction_base_mansion_c5", - "description": "Mansion's Kitchen", - "om_terrains": [ "mansion_c5" ] - } + { "id": "faction_base_workshop_0", "description": "Fabrication Workshop", "om_terrains": [ "field" ] } ] }, { From 3845e7486002ab1df769c0c22a0cc945c0176e53 Mon Sep 17 00:00:00 2001 From: Maleclypse <54345792+Maleclypse@users.noreply.github.com> Date: Thu, 18 Feb 2021 01:19:49 -0600 Subject: [PATCH 220/453] Valentine Cards (#47438) --- data/json/items/newspaper.json | 15 ++++++++++ data/json/snippets/valentines.json | 45 ++++++++++++++++++++++++++++++ 2 files changed, 60 insertions(+) create mode 100644 data/json/snippets/valentines.json diff --git a/data/json/items/newspaper.json b/data/json/items/newspaper.json index ca49cfd403468..ee55cd8e2bdaf 100644 --- a/data/json/items/newspaper.json +++ b/data/json/items/newspaper.json @@ -14,6 +14,21 @@ "weight": "3 g", "volume": "5 ml" }, + { + "type": "GENERIC", + "id": "valentine_card", + "category": "books", + "symbol": ",", + "color": "red", + "name": { "str": "valentine card" }, + "snippet_category": "valentine", + "description": "A creased holiday card. It appears to be a Valentine's Day card from before the Cataclysm.", + "price": 0, + "price_postapoc": 0, + "material": [ "paper" ], + "weight": "3 g", + "volume": "5 ml" + }, { "type": "GENERIC", "id": "survnote", diff --git a/data/json/snippets/valentines.json b/data/json/snippets/valentines.json new file mode 100644 index 0000000000000..71d3624a7bb92 --- /dev/null +++ b/data/json/snippets/valentines.json @@ -0,0 +1,45 @@ +[ + { + "type": "snippet", + "category": "valentine", + "text": [ + { + "id": "valentine_1", + "text": "There is a picture of a kitten pouncing; blood faintly drips from its claws. \"I'd kill! For you to be my valentine.\"" + }, + { + "id": "valentine_2", + "text": "A police robot stalks between office cubicles while an indistinct person hides under a desk. \"Don't hide from love!\"" + }, + { "id": "valentine_3", "text": "A picture of a bloody steak. \"My love can feed you.\"" }, + { + "id": "valentine_4", + "text": "A rustic campground at night lit by a campfire. \"We should go away together. Where no one can find us.\"" + }, + { + "id": "valentine_5", + "text": "A girl with a giant spoon stirs a cauldron with a boy inside and a fire below. \"You suit my taste just right, Valentine\"" + }, + { + "id": "valentine_6", + "text": "A person stepping out from the forest. \"Don't be afraid, it's me, your valentine!\"" + }, + { + "id": "valentine_7", + "text": "A building that says 'Crematorium' on it. \"Ashes to ashes, dust to dust, show me a Valentine, that I can trust\"" + }, + { + "id": "valentine_8", + "text": "A popular RPG character. \"We should adventure together.\" In the background, a village in flames." + }, + { + "id": "valentine_9", + "text": "A picture of a room that looks like your bedroom. \"I can't wait to see you again, Valentine. Sweet dreams.\"" + }, + { + "id": "valentine_10", + "text": "A girl smiles into the camera. Behind here a house is on fire. \"I'm burning, I'm burning, I'm burning for you, my valentine!\"" + } + ] + } +] From 6f0d2deabd00cc009bec0a38e2d3f9eb3be438c2 Mon Sep 17 00:00:00 2001 From: LaVeyanFiend <51099123+LaVeyanFiend@users.noreply.github.com> Date: Thu, 18 Feb 2021 02:34:00 -0500 Subject: [PATCH 221/453] Add a proficiency for handloading, and a new profession (#47244) --- data/json/items/book/fabrication.json | 1 + data/json/professions.json | 43 ++++++++++++ data/json/proficiencies/misc.json | 10 +++ data/json/recipes/ammo/40x46mm.json | 12 ++++ data/json/recipes/ammo/40x53mm.json | 6 ++ data/json/recipes/ammo/pistol.json | 65 +++++++++++++++++++ data/json/recipes/ammo/rifle.json | 54 ++++++++++++++- data/json/recipes/ammo/shot.json | 18 +++++ data/json/recipes/recipe_ammo.json | 5 ++ .../recipes/recipes_grenade_propelled.json | 2 + .../Generic_Guns/recipes/recipes_pistol.json | 6 ++ .../Generic_Guns/recipes/recipes_rifle.json | 4 ++ .../Generic_Guns/recipes/recipes_shot.json | 18 +++++ 13 files changed, 243 insertions(+), 1 deletion(-) diff --git a/data/json/items/book/fabrication.json b/data/json/items/book/fabrication.json index 3de5357d9ddac..1854df6c1c4f1 100644 --- a/data/json/items/book/fabrication.json +++ b/data/json/items/book/fabrication.json @@ -155,6 +155,7 @@ "skill": "fabrication", "required_level": 3, "max_level": 6, + "proficiencies": [ { "proficiency": "prof_handloading", "time_factor": 0.8, "fail_factor": 0.5 } ], "intelligence": 9, "time": "30 m" }, diff --git a/data/json/professions.json b/data/json/professions.json index ddc6ec5764117..6f9853a31e3ed 100644 --- a/data/json/professions.json +++ b/data/json/professions.json @@ -136,6 +136,15 @@ { "item": "38_speedloader", "ammo-item": "357mag_fmj", "charges": 7 } ] }, + { + "type": "item_group", + "subtype": "collection", + "id": "m1911_10_magazines_reloaded", + "entries": [ + { "item": "m1911_10mag", "ammo-item": "reloaded_10mm_fmj", "charges": 8 }, + { "item": "m1911_10mag", "ammo-item": "reloaded_10mm_fmj", "charges": 8 } + ] + }, { "type": "item_group", "subtype": "collection", @@ -3912,5 +3921,39 @@ "male": [ "boxer_shorts" ], "female": [ "bra", "panties" ] } + }, + { + "type": "profession", + "id": "handloader", + "name": "Hobby Handloader", + "description": "Out of financial concerns and an appreciation for power, you took up handloading for your mighty handgun. Now that the gunstores are closed, your skills ensure you won't be running out of ammo anytime soon.", + "points": 5, + "proficiencies": [ "prof_handloading" ], + "items": { + "both": { + "items": [ + "pants", + "dress_shirt", + "wristwatch", + "socks", + "boots", + "jacket_light", + "gloves_fingerless", + "press", + "puller", + "slingpack", + "hat_ball" + ], + "entries": [ + { "group": "charged_cell_phone" }, + { "group": "m1911_10_magazines_reloaded" }, + { "item": "ear_plugs", "custom-flags": [ "no_auto_equip" ] }, + { "item": "m1911_10", "ammo-item": "reloaded_10mm_fmj", "charges": 8, "container-item": "holster" } + ] + }, + "male": [ "briefs" ], + "female": [ "bra", "panties" ] + }, + "skills": [ { "level": 3, "name": "fabrication" }, { "level": 3, "name": "gun" }, { "level": 3, "name": "pistol" } ] } ] diff --git a/data/json/proficiencies/misc.json b/data/json/proficiencies/misc.json index ce099486ce465..1db2662f4a661 100644 --- a/data/json/proficiencies/misc.json +++ b/data/json/proficiencies/misc.json @@ -134,5 +134,15 @@ "default_fail_multiplier": 2, "time_to_learn": "10 h", "required_proficiencies": [ "prof_fine_metalsmithing", "prof_redsmithing" ] + }, + { + "type": "proficiency", + "id": "prof_handloading", + "name": { "str": "Handloading" }, + "description": "You know how to accurately measure powder and projectile weights for reloading firearm cartridges.", + "can_learn": true, + "default_time_multiplier": 1.5, + "default_fail_multiplier": 5, + "time_to_learn": "8 h" } ] diff --git a/data/json/recipes/ammo/40x46mm.json b/data/json/recipes/ammo/40x46mm.json index e6ae3fa91ea05..a19c439a1d90d 100644 --- a/data/json/recipes/ammo/40x46mm.json +++ b/data/json/recipes/ammo/40x46mm.json @@ -15,6 +15,7 @@ "reversible": true, "//": "186 mg gunpowder rounded to 2 100 mg 'pieces', same as factory M576 load.", "using": [ [ "shot_forming", 1 ], [ "ammo_bullet", 8 ] ], + "proficiencies": [ { "proficiency": "prof_handloading" } ], "tools": [ [ [ "press", -1 ] ], [ [ "swage", -1 ] ] ], "qualities": [ { "id": "CUT", "level": 1 } ], "components": [ @@ -40,6 +41,7 @@ "charges": 1, "reversible": true, "using": [ [ "shot_forming", 1 ], [ "ammo_bullet", 8 ] ], + "proficiencies": [ { "proficiency": "prof_handloading" } ], "tools": [ [ [ "press", -1 ] ], [ [ "swage", -1 ] ] ], "qualities": [ { "id": "CUT", "level": 1 } ], "//": "186 mg gunpowder rounded to 2 100 mg 'pieces', same as factory M576 load.", @@ -66,6 +68,7 @@ "charges": 1, "reversible": true, "using": [ [ "bullet_forming", 1 ], [ "ammo_bullet", 8 ] ], + "proficiencies": [ { "proficiency": "prof_handloading" } ], "tools": [ [ [ "press", -1 ] ], [ [ "swage", -1 ] ] ], "qualities": [ { "id": "CUT", "level": 1 } ], "//": "186 mg gunpowder rounded to 2 100 mg 'pieces', same as factory M576 load.", @@ -92,6 +95,7 @@ "charges": 1, "reversible": true, "using": [ [ "bullet_forming", 1 ], [ "ammo_bullet", 8 ] ], + "proficiencies": [ { "proficiency": "prof_handloading" } ], "tools": [ [ [ "press", -1 ] ], [ [ "swage", -1 ] ] ], "qualities": [ { "id": "CUT", "level": 1 } ], "//": "186 mg gunpowder rounded to 2 100 mg 'pieces', same as factory M576 load.", @@ -120,6 +124,7 @@ "tools": [ [ [ "press", -1 ] ], [ [ "swage", -1 ] ] ], "qualities": [ { "id": "CUT", "level": 1 } ], "//": "186 mg gunpowder rounded to 2 100 mg 'pieces', same as factory M576 load.", + "proficiencies": [ { "proficiency": "prof_handloading" } ], "components": [ [ [ "sheet_metal_small", 1 ] ], [ [ "paper", 1 ], [ "wax", 1 ] ], @@ -146,6 +151,7 @@ "tools": [ [ [ "press", -1 ] ], [ [ "swage", -1 ] ] ], "qualities": [ { "id": "CUT", "level": 1 } ], "//": "186 mg gunpowder rounded to 2 100 mg 'pieces', same as factory M576 load.", + "proficiencies": [ { "proficiency": "prof_handloading" } ], "components": [ [ [ "sheet_metal_small", 1 ] ], [ [ "paper", 1 ], [ "wax", 1 ] ], @@ -170,6 +176,7 @@ "charges": 1, "reversible": true, "using": [ [ "shot_forming", 1 ], [ "ammo_bullet", 8 ] ], + "proficiencies": [ { "proficiency": "prof_handloading" } ], "tools": [ [ [ "press", -1 ] ], [ [ "swage", -1 ] ] ], "qualities": [ { "id": "CUT", "level": 1 } ], "components": [ @@ -195,6 +202,7 @@ "charges": 1, "reversible": true, "using": [ [ "shot_forming", 1 ], [ "ammo_bullet", 8 ] ], + "proficiencies": [ { "proficiency": "prof_handloading" } ], "tools": [ [ [ "press", -1 ] ], [ [ "swage", -1 ] ] ], "qualities": [ { "id": "CUT", "level": 1 } ], "components": [ @@ -220,6 +228,7 @@ "charges": 1, "reversible": true, "using": [ [ "bullet_forming", 1 ], [ "ammo_bullet", 8 ] ], + "proficiencies": [ { "proficiency": "prof_handloading" } ], "tools": [ [ [ "press", -1 ] ], [ [ "swage", -1 ] ] ], "qualities": [ { "id": "CUT", "level": 1 } ], "components": [ @@ -245,6 +254,7 @@ "charges": 1, "reversible": true, "using": [ [ "bullet_forming", 1 ], [ "ammo_bullet", 8 ] ], + "proficiencies": [ { "proficiency": "prof_handloading" } ], "tools": [ [ [ "press", -1 ] ], [ [ "swage", -1 ] ] ], "qualities": [ { "id": "CUT", "level": 1 } ], "components": [ @@ -271,6 +281,7 @@ "reversible": true, "tools": [ [ [ "press", -1 ] ], [ [ "swage", -1 ] ] ], "qualities": [ { "id": "CUT", "level": 1 } ], + "proficiencies": [ { "proficiency": "prof_handloading" } ], "components": [ [ [ "sheet_metal_small", 1 ] ], [ [ "paper", 1 ], [ "wax", 1 ] ], @@ -296,6 +307,7 @@ "reversible": true, "tools": [ [ [ "press", -1 ] ], [ [ "swage", -1 ] ] ], "qualities": [ { "id": "CUT", "level": 1 } ], + "proficiencies": [ { "proficiency": "prof_handloading" } ], "components": [ [ [ "sheet_metal_small", 1 ] ], [ [ "paper", 1 ], [ "wax", 1 ] ], diff --git a/data/json/recipes/ammo/40x53mm.json b/data/json/recipes/ammo/40x53mm.json index 6d3778b2df483..e03a7bc5438e3 100644 --- a/data/json/recipes/ammo/40x53mm.json +++ b/data/json/recipes/ammo/40x53mm.json @@ -14,6 +14,7 @@ "charges": 1, "reversible": true, "using": [ [ "shot_forming", 12 ], [ "ammo_bullet", 126 ] ], + "proficiencies": [ { "proficiency": "prof_handloading" } ], "tools": [ [ [ "press", -1 ] ], [ [ "swage", -1 ] ] ], "qualities": [ { "id": "CUT", "level": 1 } ], "//": "11.5x the propellant and 11.5x the payload of 12 gauge 00 shot load. 13409 mg gunpowder rounded to 134 100 mg 'pieces'", @@ -40,6 +41,7 @@ "charges": 1, "reversible": true, "using": [ [ "bullet_forming", 12 ], [ "ammo_bullet", 115 ] ], + "proficiencies": [ { "proficiency": "prof_handloading" } ], "tools": [ [ [ "press", -1 ] ], [ [ "swage", -1 ] ] ], "qualities": [ { "id": "CUT", "level": 1 } ], "//": "11.5x the propellant and 11.5x the payload of 12 gauge slug load. 19366 mg gunpowder rounded to 194 100 mg 'pieces'", @@ -68,6 +70,7 @@ "tools": [ [ [ "press", -1 ] ], [ [ "swage", -1 ] ] ], "qualities": [ { "id": "CUT", "level": 1 } ], "//": "11.5x the propellant and 11.5x the payload of 12 gauge flechette load. 8625 mg gunpowder rounded to 86 100 mg 'pieces'", + "proficiencies": [ { "proficiency": "prof_handloading" } ], "components": [ [ [ "sheet_metal_small", 1 ] ], [ [ "paper", 1 ], [ "wax", 1 ] ], @@ -92,6 +95,7 @@ "charges": 1, "reversible": true, "using": [ [ "shot_forming", 12 ], [ "ammo_bullet", 126 ] ], + "proficiencies": [ { "proficiency": "prof_handloading" } ], "tools": [ [ [ "press", -1 ] ], [ [ "swage", -1 ] ] ], "qualities": [ { "id": "CUT", "level": 1 } ], "components": [ @@ -117,6 +121,7 @@ "charges": 1, "reversible": true, "using": [ [ "bullet_forming", 12 ], [ "ammo_bullet", 115 ] ], + "proficiencies": [ { "proficiency": "prof_handloading" } ], "tools": [ [ [ "press", -1 ] ], [ [ "swage", -1 ] ] ], "qualities": [ { "id": "CUT", "level": 1 } ], "components": [ @@ -143,6 +148,7 @@ "reversible": true, "tools": [ [ [ "press", -1 ] ], [ [ "swage", -1 ] ] ], "qualities": [ { "id": "CUT", "level": 1 } ], + "proficiencies": [ { "proficiency": "prof_handloading" } ], "components": [ [ [ "sheet_metal_small", 1 ] ], [ [ "paper", 1 ], [ "wax", 1 ] ], diff --git a/data/json/recipes/ammo/pistol.json b/data/json/recipes/ammo/pistol.json index 66607ed15581f..6f1669fb514b7 100644 --- a/data/json/recipes/ammo/pistol.json +++ b/data/json/recipes/ammo/pistol.json @@ -14,6 +14,7 @@ "charges": 1, "reversible": true, "using": [ [ "bullet_forming", 2 ], [ "ammo_bullet", 2 ], [ "ammo_9mm", 1 ] ], + "proficiencies": [ { "proficiency": "prof_handloading" } ], "components": [ [ [ "chem_black_powder", 3 ] ], [ [ "copper", 1 ] ] ] }, { @@ -31,6 +32,7 @@ "charges": 1, "reversible": true, "using": [ [ "bullet_forming", 2 ], [ "ammo_bullet", 2 ], [ "ammo_9mm", 1 ] ], + "proficiencies": [ { "proficiency": "prof_handloading" } ], "components": [ [ [ "chem_black_powder", 3 ] ], [ [ "copper", 1 ] ] ] }, { @@ -48,6 +50,7 @@ "charges": 1, "reversible": true, "using": [ [ "bullet_forming", 2 ], [ "ammo_bullet", 4 ] ], + "proficiencies": [ { "proficiency": "prof_handloading" } ], "components": [ [ [ "40_casing", 1 ] ], [ [ "smpistol_primer", 1 ] ], [ [ "chem_black_powder", 3 ] ], [ [ "copper", 1 ] ] ] }, { @@ -65,6 +68,7 @@ "charges": 1, "reversible": true, "using": [ [ "bullet_forming", 2 ], [ "ammo_bullet", 4 ] ], + "proficiencies": [ { "proficiency": "prof_handloading" } ], "components": [ [ [ "40_casing", 1 ] ], [ [ "smpistol_primer", 1 ] ], [ [ "chem_black_powder", 6 ] ], [ [ "copper", 1 ] ] ] }, { @@ -82,6 +86,7 @@ "charges": 1, "reversible": true, "using": [ [ "bullet_forming", 2 ], [ "ammo_bullet", 2 ] ], + "proficiencies": [ { "proficiency": "prof_handloading" } ], "components": [ [ [ "32_casing", 1 ] ], [ [ "smpistol_primer", 1 ] ], [ [ "chem_black_powder", 2 ] ], [ [ "copper", 1 ] ] ] }, { @@ -99,6 +104,7 @@ "charges": 1, "reversible": true, "using": [ [ "bullet_forming", 2 ], [ "ammo_bullet", 2 ] ], + "proficiencies": [ { "proficiency": "prof_handloading" } ], "components": [ [ [ "38_casing", 1 ] ], [ [ "smpistol_primer", 1 ] ], [ [ "chem_black_powder", 3 ] ], [ [ "copper", 1 ] ] ] }, { @@ -116,6 +122,7 @@ "charges": 1, "reversible": true, "using": [ [ "bullet_forming", 5 ], [ "ammo_bullet", 4 ] ], + "proficiencies": [ { "proficiency": "prof_handloading" } ], "components": [ [ [ "44_casing", 1 ] ], [ [ "lgpistol_primer", 1 ] ], [ [ "chem_black_powder", 7 ] ], [ [ "copper", 2 ] ] ] }, { @@ -133,6 +140,7 @@ "charges": 1, "reversible": true, "using": [ [ "bullet_forming", 3 ], [ "ammo_bullet", 4 ] ], + "proficiencies": [ { "proficiency": "prof_handloading" } ], "components": [ [ [ "45_casing", 1 ] ], [ [ "lgpistol_primer", 1 ] ], [ [ "chem_black_powder", 3 ] ], [ [ "copper", 2 ] ] ] }, { @@ -150,6 +158,7 @@ "charges": 1, "reversible": true, "using": [ [ "bullet_forming", 3 ], [ "ammo_bullet", 4 ] ], + "proficiencies": [ { "proficiency": "prof_handloading" } ], "components": [ [ [ "45_casing", 1 ] ], [ [ "lgpistol_primer", 1 ] ], [ [ "chem_black_powder", 5 ] ], [ [ "copper", 1 ] ] ] }, { @@ -167,6 +176,7 @@ "charges": 1, "reversible": true, "using": [ [ "bullet_forming", 2 ], [ "ammo_bullet", 1 ] ], + "proficiencies": [ { "proficiency": "prof_handloading" } ], "components": [ [ [ "46mm_casing", 1 ] ], [ [ "smpistol_primer", 1 ] ], [ [ "chem_black_powder", 4 ] ], [ [ "copper", 1 ] ] ] }, { @@ -184,6 +194,7 @@ "charges": 1, "reversible": true, "using": [ [ "bullet_forming", 3 ], [ "ammo_bullet", 3 ] ], + "proficiencies": [ { "proficiency": "prof_handloading" } ], "components": [ [ [ "460_casing", 1 ] ], [ [ "lgpistol_primer", 1 ] ], [ [ "chem_black_powder", 8 ] ], [ [ "copper", 2 ] ] ] }, { @@ -201,6 +212,7 @@ "charges": 1, "reversible": true, "using": [ [ "bullet_forming", 3 ], [ "ammo_bullet", 3 ] ], + "proficiencies": [ { "proficiency": "prof_handloading" } ], "components": [ [ [ "460_casing", 1 ] ], [ [ "lgpistol_primer", 1 ] ], [ [ "chem_black_powder", 8 ] ], [ [ "copper", 2 ] ] ] }, { @@ -218,6 +230,7 @@ "charges": 1, "reversible": true, "using": [ [ "bullet_forming", 6 ], [ "ammo_bullet", 8 ] ], + "proficiencies": [ { "proficiency": "prof_handloading" } ], "components": [ [ [ "500_casing", 1 ] ], [ [ "lgrifle_primer", 1 ] ], [ [ "chem_black_powder", 19 ] ], [ [ "copper", 5 ] ] ] }, { @@ -235,6 +248,7 @@ "charges": 1, "reversible": true, "using": [ [ "bullet_forming", 2 ], [ "ammo_bullet", 2 ], [ "ammo_762_25", 1 ] ], + "proficiencies": [ { "proficiency": "prof_handloading" } ], "components": [ [ [ "chem_black_powder", 4 ] ], [ [ "copper", 1 ] ] ] }, { @@ -252,6 +266,7 @@ "charges": 1, "reversible": true, "using": [ [ "bullet_forming", 2 ], [ "ammo_bullet", 2 ] ], + "proficiencies": [ { "proficiency": "prof_handloading" } ], "components": [ [ [ "9x18mm_casing", 1 ] ], [ [ "smpistol_primer", 1 ] ], [ [ "chem_black_powder", 4 ] ], [ [ "copper", 1 ] ] ] }, { @@ -269,6 +284,7 @@ "charges": 1, "reversible": true, "using": [ [ "bullet_forming", 2 ], [ "ammo_bullet", 2 ] ], + "proficiencies": [ { "proficiency": "prof_handloading" } ], "components": [ [ [ "9x18mm_casing", 1 ] ], [ [ "smpistol_primer", 1 ] ], [ [ "chem_black_powder", 4 ] ], [ [ "copper", 1 ] ] ] }, { @@ -286,6 +302,7 @@ "charges": 1, "reversible": true, "using": [ [ "bullet_forming", 2 ], [ "ammo_bullet", 2 ], [ "ammo_380", 1 ] ], + "proficiencies": [ { "proficiency": "prof_handloading" } ], "components": [ [ [ "chem_black_powder", 3 ] ], [ [ "copper", 1 ] ] ] }, { @@ -303,6 +320,7 @@ "charges": 1, "reversible": true, "using": [ [ "bullet_forming", 2 ], [ "ammo_bullet", 2 ], [ "ammo_380", 1 ] ], + "proficiencies": [ { "proficiency": "prof_handloading" } ], "components": [ [ [ "chem_black_powder", 3 ] ], [ [ "copper", 1 ] ] ] }, { @@ -320,6 +338,7 @@ "charges": 1, "reversible": true, "using": [ [ "bullet_forming", 2 ], [ "ammo_bullet", 1 ], [ "ammo_57", 1 ] ], + "proficiencies": [ { "proficiency": "prof_handloading" } ], "components": [ [ [ "chem_black_powder", 4 ] ], [ [ "copper", 1 ] ] ] }, { @@ -338,6 +357,7 @@ "reversible": true, "using": [ [ "ammo_bullet", 1 ] ], "qualities": [ { "id": "CUT", "level": 1 } ], + "proficiencies": [ { "proficiency": "prof_handloading" } ], "components": [ [ [ "chem_black_powder", 4 ] ], [ [ "smpistol_primer", 1 ] ], [ [ "paper", 1 ], [ "aluminum_foil", 1 ] ] ] }, { @@ -356,6 +376,7 @@ "reversible": true, "using": [ [ "ammo_bullet", 2 ] ], "qualities": [ { "id": "CUT", "level": 1 } ], + "proficiencies": [ { "proficiency": "prof_handloading" } ], "components": [ [ [ "chem_black_powder", 4 ] ], [ [ "lgpistol_primer", 1 ] ], [ [ "paper", 1 ], [ "aluminum_foil", 1 ] ] ] }, { @@ -374,6 +395,7 @@ "reversible": true, "using": [ [ "bullet_forming", 2 ], [ "ammo_bullet", 2 ] ], "//": "207 mg gunpowder rounded to 2 100 mg 'pieces'", + "proficiencies": [ { "proficiency": "prof_handloading" } ], "components": [ [ [ "32_casing", 1 ] ], [ [ "smpistol_primer", 1 ] ], @@ -397,6 +419,7 @@ "reversible": true, "using": [ [ "bullet_forming", 2 ], [ "ammo_bullet", 2 ] ], "//": "315 mg gunpowder rounded to 3 100 mg 'pieces'", + "proficiencies": [ { "proficiency": "prof_handloading" } ], "components": [ [ [ "38_casing", 1 ] ], [ [ "smpistol_primer", 1 ] ], @@ -420,6 +443,7 @@ "reversible": true, "using": [ [ "bullet_forming", 2 ], [ "ammo_bullet", 3 ] ], "//": "315 mg gunpowder rounded to 3 100 mg 'pieces'", + "proficiencies": [ { "proficiency": "prof_handloading" } ], "components": [ [ [ "38_casing", 1 ] ], [ [ "smpistol_primer", 1 ] ], @@ -442,6 +466,7 @@ "reversible": true, "using": [ [ "bullet_forming", 2 ], [ "ammo_bullet", 1 ], [ "ammo_38super", 1 ] ], "//": "323 mg gunpowder rounded to 3 100 mg 'pieces'", + "proficiencies": [ { "proficiency": "prof_handloading" } ], "components": [ [ [ "gunpowder", 3 ], [ "gunpowder_pistol", 3 ], [ "gunpowder_shotgun", 3 ] ], [ [ "copper", 1 ] ] ] }, { @@ -460,6 +485,7 @@ "reversible": true, "using": [ [ "bullet_forming", 2 ], [ "ammo_bullet", 7 ], [ "ammo_357sig", 1 ] ], "//": "370 mg gunpowder rounded to 4 100 mg 'pieces'", + "proficiencies": [ { "proficiency": "prof_handloading" } ], "components": [ [ [ "gunpowder", 4 ], [ "gunpowder_rifle", 4 ], [ "gunpowder_magnum_pistol", 4 ] ], [ [ "copper", 1 ] ] ] }, { @@ -478,6 +504,7 @@ "reversible": true, "using": [ [ "bullet_forming", 2 ], [ "ammo_bullet", 8 ], [ "ammo_357sig", 1 ] ], "//": "531 mg gunpowder rounded to 5 100 mg 'pieces'", + "proficiencies": [ { "proficiency": "prof_handloading" } ], "components": [ [ [ "gunpowder", 5 ], [ "gunpowder_rifle", 5 ], [ "gunpowder_magnum_pistol", 5 ] ], [ [ "copper", 1 ] ] ] }, { @@ -495,6 +522,7 @@ "charges": 1, "reversible": true, "using": [ [ "bullet_forming", 2 ], [ "ammo_bullet", 7 ], [ "ammo_357sig", 1 ] ], + "proficiencies": [ { "proficiency": "prof_handloading" } ], "components": [ [ [ "chem_black_powder", 4 ] ], [ [ "copper", 1 ] ] ] }, { @@ -512,6 +540,7 @@ "charges": 1, "reversible": true, "using": [ [ "bullet_forming", 2 ], [ "ammo_bullet", 8 ], [ "ammo_357sig", 1 ] ], + "proficiencies": [ { "proficiency": "prof_handloading" } ], "components": [ [ [ "chem_black_powder", 5 ] ], [ [ "copper", 1 ] ] ] }, { @@ -530,6 +559,7 @@ "reversible": true, "using": [ [ "bullet_forming", 2 ], [ "ammo_bullet", 3 ], [ "ammo_357mag", 1 ] ], "//": "520 mg gunpowder rounded to 5 100 mg 'pieces'", + "proficiencies": [ { "proficiency": "prof_handloading" } ], "components": [ [ [ "gunpowder", 5 ], [ "gunpowder_rifle", 5 ], [ "gunpowder_magnum_pistol", 5 ] ], [ [ "copper", 1 ] ] ] }, { @@ -548,6 +578,7 @@ "reversible": true, "using": [ [ "bullet_forming", 2 ], [ "ammo_bullet", 4 ], [ "ammo_357mag", 1 ] ], "//": "520 mg gunpowder rounded to 5 100 mg 'pieces'", + "proficiencies": [ { "proficiency": "prof_handloading" } ], "components": [ [ [ "gunpowder", 5 ], [ "gunpowder_rifle", 5 ], [ "gunpowder_magnum_pistol", 5 ] ], [ [ "copper", 1 ] ] ] }, { @@ -565,6 +596,7 @@ "charges": 1, "reversible": true, "using": [ [ "bullet_forming", 2 ], [ "ammo_bullet", 3 ], [ "ammo_357mag", 1 ] ], + "proficiencies": [ { "proficiency": "prof_handloading" } ], "components": [ [ [ "chem_black_powder", 5 ] ], [ [ "copper", 1 ] ] ] }, { @@ -582,6 +614,7 @@ "charges": 1, "reversible": true, "using": [ [ "bullet_forming", 2 ], [ "ammo_bullet", 4 ], [ "ammo_357mag", 1 ] ], + "proficiencies": [ { "proficiency": "prof_handloading" } ], "components": [ [ [ "chem_black_powder", 5 ] ], [ [ "copper", 1 ] ] ] }, { @@ -599,6 +632,7 @@ "charges": 1, "reversible": true, "using": [ [ "bullet_forming", 2 ], [ "ammo_bullet", 3 ] ], + "proficiencies": [ { "proficiency": "prof_handloading" } ], "components": [ [ [ "38_casing", 1 ] ], [ [ "smpistol_primer", 1 ] ], [ [ "chem_black_powder", 3 ] ] ] }, { @@ -617,6 +651,7 @@ "reversible": true, "using": [ [ "bullet_forming", 2 ], [ "ammo_bullet", 2 ] ], "//": "453 mg gunpowder rounded to 5 100 mg 'pieces'", + "proficiencies": [ { "proficiency": "prof_handloading" } ], "components": [ [ [ "38_casing", 1 ] ], [ [ "smpistol_primer", 1 ] ], @@ -639,6 +674,7 @@ "reversible": true, "using": [ [ "bullet_forming", 2 ], [ "ammo_bullet", 4 ] ], "//": "320 mg gunpowder rounded to 3 100 mg 'pieces'", + "proficiencies": [ { "proficiency": "prof_handloading" } ], "components": [ [ [ "40_casing", 1 ] ], [ [ "smpistol_primer", 1 ] ], @@ -662,6 +698,7 @@ "reversible": true, "using": [ [ "bullet_forming", 2 ], [ "ammo_bullet", 4 ] ], "//": "576 mg gunpowder rounded to 6 100 mg 'pieces'", + "proficiencies": [ { "proficiency": "prof_handloading" } ], "components": [ [ [ "40_casing", 1 ] ], [ [ "smpistol_primer", 1 ] ], @@ -685,6 +722,7 @@ "reversible": true, "using": [ [ "bullet_forming", 2 ], [ "ammo_bullet", 3 ], [ "ammo_10mm", 1 ] ], "//": "330 mg gunpowder rounded to 3 100 mg 'pieces'", + "proficiencies": [ { "proficiency": "prof_handloading" } ], "components": [ [ [ "gunpowder", 3 ], [ "gunpowder_magnum_pistol", 3 ] ], [ [ "copper", 1 ] ] ] }, { @@ -702,6 +740,7 @@ "charges": 1, "reversible": true, "using": [ [ "bullet_forming", 2 ], [ "ammo_bullet", 3 ], [ "ammo_10mm", 1 ] ], + "proficiencies": [ { "proficiency": "prof_handloading" } ], "components": [ [ [ "chem_black_powder", 3 ] ], [ [ "copper", 1 ] ] ] }, { @@ -720,6 +759,7 @@ "reversible": true, "using": [ [ "bullet_forming", 5 ], [ "ammo_bullet", 4 ] ], "//": "660 mg gunpowder rounded to 7 100 mg 'pieces'", + "proficiencies": [ { "proficiency": "prof_handloading" } ], "components": [ [ [ "44_casing", 1 ] ], [ [ "lgpistol_primer", 1 ] ], @@ -743,6 +783,7 @@ "reversible": true, "using": [ [ "bullet_forming", 5 ], [ "ammo_bullet", 4 ] ], "//": "660 mg gunpowder rounded to 7 100 mg 'pieces'", + "proficiencies": [ { "proficiency": "prof_handloading" } ], "components": [ [ [ "44_casing", 1 ] ], [ [ "lgpistol_primer", 1 ] ], @@ -765,6 +806,7 @@ "charges": 1, "reversible": true, "using": [ [ "bullet_forming", 5 ], [ "ammo_bullet", 4 ] ], + "proficiencies": [ { "proficiency": "prof_handloading" } ], "components": [ [ [ "44_casing", 1 ] ], [ [ "lgpistol_primer", 1 ] ], [ [ "chem_black_powder", 7 ] ], [ [ "copper", 2 ] ] ] }, { @@ -783,6 +825,7 @@ "reversible": true, "using": [ [ "bullet_forming", 3 ], [ "ammo_bullet", 4 ] ], "//": "330 mg gunpowder rounded to 3 100 mg 'pieces'", + "proficiencies": [ { "proficiency": "prof_handloading" } ], "components": [ [ [ "45_casing", 1 ] ], [ [ "lgpistol_primer", 1 ] ], @@ -806,6 +849,7 @@ "reversible": true, "using": [ [ "bullet_forming", 3 ], [ "ammo_bullet", 4 ] ], "//": "466 mg gunpowder rounded to 5 100 mg 'pieces'", + "proficiencies": [ { "proficiency": "prof_handloading" } ], "components": [ [ [ "45_casing", 1 ] ], [ [ "lgpistol_primer", 1 ] ], @@ -829,6 +873,7 @@ "reversible": true, "using": [ [ "bullet_forming", 3 ], [ "ammo_bullet", 4 ] ], "//": "513 mg gunpowder rounded to 5 100 mg 'pieces'", + "proficiencies": [ { "proficiency": "prof_handloading" } ], "components": [ [ [ "45_casing", 1 ] ], [ [ "lgpistol_primer", 1 ] ], @@ -852,6 +897,7 @@ "reversible": true, "using": [ [ "bullet_forming", 5 ], [ "ammo_bullet", 6 ] ], "//": "1574 mg gunpowder rounded to 16 100 mg 'pieces'", + "proficiencies": [ { "proficiency": "prof_handloading" } ], "components": [ [ [ "454_casing", 1 ] ], [ [ "smrifle_primer", 1 ] ], @@ -874,6 +920,7 @@ "charges": 1, "reversible": true, "using": [ [ "bullet_forming", 5 ], [ "ammo_bullet", 6 ] ], + "proficiencies": [ { "proficiency": "prof_handloading" } ], "components": [ [ [ "454_casing", 1 ] ], [ [ "smrifle_primer", 1 ] ], [ [ "chem_black_powder", 16 ] ], [ [ "copper", 2 ] ] ] }, { @@ -892,6 +939,7 @@ "reversible": true, "using": [ [ "bullet_forming", 3 ], [ "ammo_bullet", 5 ], [ "ammo_45colt", 1 ] ], "//": "505 mg gunpowder rounded to 5 100 mg 'pieces'", + "proficiencies": [ { "proficiency": "prof_handloading" } ], "components": [ [ [ "gunpowder", 5 ], [ "gunpowder_pistol", 5 ], [ "gunpowder_shotgun", 5 ] ], [ [ "copper", 2 ] ] ] }, { @@ -909,6 +957,7 @@ "charges": 1, "reversible": true, "using": [ [ "bullet_forming", 3 ], [ "ammo_bullet", 5 ], [ "ammo_45colt", 1 ] ], + "proficiencies": [ { "proficiency": "prof_handloading" } ], "components": [ [ [ "chem_black_powder", 5 ] ], [ [ "copper", 2 ] ] ] }, { @@ -927,6 +976,7 @@ "reversible": true, "//": "Unable to find load data, used 5.7 data as cartridges are similar. 388 mg gunpowder rounded to 4 100 mg 'pieces'", "using": [ [ "bullet_forming", 2 ], [ "ammo_bullet", 1 ] ], + "proficiencies": [ { "proficiency": "prof_handloading" } ], "components": [ [ [ "46mm_casing", 1 ] ], [ [ "smpistol_primer", 1 ] ], @@ -950,6 +1000,7 @@ "reversible": true, "using": [ [ "bullet_forming", 3 ], [ "ammo_bullet", 3 ] ], "//": "842 mg gunpowder rounded to 8 100 mg 'pieces'", + "proficiencies": [ { "proficiency": "prof_handloading" } ], "components": [ [ [ "460_casing", 1 ] ], [ [ "lgpistol_primer", 1 ] ], @@ -973,6 +1024,7 @@ "reversible": true, "using": [ [ "bullet_forming", 3 ], [ "ammo_bullet", 3 ] ], "//": "842 mg gunpowder rounded to 8 100 mg 'pieces'", + "proficiencies": [ { "proficiency": "prof_handloading" } ], "components": [ [ [ "460_casing", 1 ] ], [ [ "lgpistol_primer", 1 ] ], @@ -996,6 +1048,7 @@ "reversible": true, "using": [ [ "bullet_forming", 6 ], [ "ammo_bullet", 8 ] ], "//": "1943 mg gunpowder rounded to 19 100 mg 'pieces'", + "proficiencies": [ { "proficiency": "prof_handloading" } ], "components": [ [ [ "500_casing", 1 ] ], [ [ "lgrifle_primer", 1 ] ], @@ -1019,6 +1072,7 @@ "reversible": true, "using": [ [ "bullet_forming", 2 ], [ "ammo_bullet", 1 ] ], "//": "388 mg gunpowder rounded to 4 100 mg 'pieces'", + "proficiencies": [ { "proficiency": "prof_handloading" } ], "components": [ [ [ "57mm_casing", 1 ] ], [ [ "smrifle_primer", 1 ] ], @@ -1041,6 +1095,7 @@ "charges": 1, "reversible": true, "using": [ [ "bullet_forming", 2 ], [ "ammo_bullet", 2 ], [ "ammo_762_25", 1 ] ], + "proficiencies": [ { "proficiency": "prof_handloading" } ], "//": "390 mg gunpowder rounded to 4 100 mg 'pieces'", "components": [ [ [ "gunpowder", 4 ], [ "gunpowder_pistol", 4 ] ], [ [ "copper", 1 ] ] ] }, @@ -1059,6 +1114,7 @@ "charges": 1, "reversible": true, "using": [ [ "bullet_forming", 2 ], [ "ammo_bullet", 2 ], [ "ammo_9mm", 1 ] ], + "proficiencies": [ { "proficiency": "prof_handloading" } ], "//": "290 mg gunpowder rounded to 3 100 mg 'pieces'", "components": [ [ [ "gunpowder", 3 ], [ "gunpowder_pistol", 3 ], [ "gunpowder_shotgun", 3 ] ], [ [ "copper", 1 ] ] ] }, @@ -1077,6 +1133,7 @@ "charges": 1, "reversible": true, "using": [ [ "bullet_forming", 2 ], [ "ammo_bullet", 2 ], [ "ammo_9mm", 1 ] ], + "proficiencies": [ { "proficiency": "prof_handloading" } ], "//": "537 mg gunpowder rounded to 5 100 mg 'pieces'", "components": [ [ [ "gunpowder", 5 ], [ "gunpowder_pistol", 5 ] ], [ [ "copper", 1 ] ] ] }, @@ -1095,6 +1152,7 @@ "charges": 1, "reversible": true, "using": [ [ "bullet_forming", 2 ], [ "ammo_bullet", 2 ], [ "ammo_9mm", 1 ] ], + "proficiencies": [ { "proficiency": "prof_handloading" } ], "//": "Arbitrary powder amount as +p+ is not a real standard but an informal one which has about 20% higher pressure than standard 9mm, while +p is a standard that has 10% higher pressure. 580 mg gunpowder rounded to 6 100 mg 'pieces'", "components": [ [ [ "gunpowder", 6 ], [ "gunpowder_pistol", 6 ] ], [ [ "copper", 1 ] ] ] }, @@ -1113,6 +1171,7 @@ "charges": 1, "reversible": true, "using": [ [ "bullet_forming", 2 ], [ "ammo_bullet", 2 ], [ "ammo_9mm", 1 ] ], + "proficiencies": [ { "proficiency": "prof_handloading" } ], "//": "290 mg gunpowder rounded to 3 100 mg 'pieces'", "components": [ [ [ "gunpowder", 3 ], [ "gunpowder_pistol", 3 ], [ "gunpowder_shotgun", 3 ] ], [ [ "copper", 1 ] ] ] }, @@ -1132,6 +1191,7 @@ "reversible": true, "using": [ [ "bullet_forming", 2 ], [ "ammo_bullet", 2 ] ], "//": "401 mg gunpowder rounded to 4 100 mg 'pieces'", + "proficiencies": [ { "proficiency": "prof_handloading" } ], "components": [ [ [ "9x18mm_casing", 1 ] ], [ [ "smpistol_primer", 1 ] ], @@ -1155,6 +1215,7 @@ "reversible": true, "using": [ [ "bullet_forming", 2 ], [ "ammo_bullet", 2 ] ], "//": "401 mg gunpowder rounded to 4 100 mg 'pieces'", + "proficiencies": [ { "proficiency": "prof_handloading" } ], "components": [ [ [ "9x18mm_casing", 1 ] ], [ [ "smpistol_primer", 1 ] ], @@ -1177,6 +1238,7 @@ "charges": 1, "reversible": true, "using": [ [ "bullet_forming", 2 ], [ "ammo_bullet", 2 ] ], + "proficiencies": [ { "proficiency": "prof_handloading" } ], "//": "Arbitrary powder amount as +p+ is not a real standard but an informal one which has about 20% higher pressure than standard 9mm, while +p is a standard that has 10% higher pressure. 481 mg gunpowder rounded to 5 100 mg 'pieces'", "components": [ [ [ "9x18mm_casing", 1 ] ], @@ -1200,6 +1262,7 @@ "charges": 1, "reversible": true, "using": [ [ "bullet_forming", 2 ], [ "ammo_bullet", 2 ], [ "ammo_380", 1 ] ], + "proficiencies": [ { "proficiency": "prof_handloading" } ], "//": "278 mg gunpowder rounded to 3 100 mg 'pieces'", "components": [ [ [ "gunpowder", 3 ], [ "gunpowder_pistol", 3 ], [ "gunpowder_shotgun", 3 ] ], [ [ "copper", 1 ] ] ] }, @@ -1218,6 +1281,7 @@ "charges": 1, "reversible": true, "using": [ [ "bullet_forming", 2 ], [ "ammo_bullet", 2 ], [ "ammo_380", 1 ] ], + "proficiencies": [ { "proficiency": "prof_handloading" } ], "//": "320 mg gunpowder rounded to 3 100 mg 'pieces'", "components": [ [ [ "gunpowder", 3 ], [ "gunpowder_pistol", 3 ], [ "gunpowder_shotgun", 3 ] ], [ [ "copper", 1 ] ] ] }, @@ -1236,6 +1300,7 @@ "charges": 1, "reversible": true, "using": [ [ "bullet_forming", 2 ], [ "ammo_bullet", 2 ], [ "ammo_380", 1 ] ], + "proficiencies": [ { "proficiency": "prof_handloading" } ], "//": "278 mg gunpowder rounded to 3 100 mg 'pieces'", "components": [ [ [ "gunpowder", 3 ], [ "gunpowder_pistol", 3 ], [ "gunpowder_shotgun", 3 ] ], [ [ "copper", 1 ] ] ] } diff --git a/data/json/recipes/ammo/rifle.json b/data/json/recipes/ammo/rifle.json index 12a35a9055660..1b02e79926de9 100644 --- a/data/json/recipes/ammo/rifle.json +++ b/data/json/recipes/ammo/rifle.json @@ -15,6 +15,7 @@ "reversible": true, "using": [ [ "ammo_bullet", 10 ] ], "qualities": [ { "id": "CUT", "level": 1 } ], + "proficiencies": [ { "proficiency": "prof_handloading" } ], "components": [ [ [ "chem_black_powder", 30 ] ], [ [ "paper", 1 ] ] ] }, { @@ -33,6 +34,7 @@ "reversible": true, "using": [ [ "ammo_bullet", 10 ] ], "qualities": [ { "id": "CUT", "level": 1 } ], + "proficiencies": [ { "proficiency": "prof_handloading" } ], "components": [ [ [ "chem_black_powder", 30 ] ], [ [ "paper", 1 ] ] ] }, { @@ -51,6 +53,7 @@ "reversible": true, "using": [ [ "bullet_forming", 3 ], [ "ammo_bullet", 1 ] ], "//": "65 mg gunpowder rounded to 1 100 mg 'pieces'", + "proficiencies": [ { "proficiency": "prof_handloading" } ], "components": [ [ [ "22_casing_new", 1 ] ], [ [ "gunpowder", 1 ], [ "gunpowder_pistol", 1 ] ], [ [ "copper", 1 ] ] ] }, { @@ -69,6 +72,7 @@ "reversible": true, "using": [ [ "bullet_forming", 2 ], [ "ammo_bullet", 1 ] ], "//": "65 mg gunpowder rounded to 1 100 mg 'pieces'", + "proficiencies": [ { "proficiency": "prof_handloading" } ], "components": [ [ [ "22_casing_new", 1 ] ], [ [ "gunpowder", 1 ], [ "gunpowder_pistol", 1 ] ] ] }, { @@ -86,6 +90,7 @@ "charges": 1, "reversible": true, "using": [ [ "bullet_forming", 3 ], [ "ammo_bullet", 1 ] ], + "proficiencies": [ { "proficiency": "prof_handloading" } ], "components": [ [ [ "22_casing_new", 1 ] ], [ [ "chem_black_powder", 1 ] ], [ [ "copper", 1 ] ] ] }, { @@ -103,6 +108,7 @@ "charges": 1, "reversible": true, "using": [ [ "bullet_forming", 2 ], [ "ammo_bullet", 1 ] ], + "proficiencies": [ { "proficiency": "prof_handloading" } ], "components": [ [ [ "22_casing_new", 1 ] ], [ [ "chem_black_powder", 1 ] ] ] }, { @@ -121,6 +127,7 @@ "reversible": true, "using": [ [ "bullet_forming", 4 ], [ "ammo_bullet", 1 ] ], "//": "1500 mg gunpowder rounded to 15 100 mg 'pieces'", + "proficiencies": [ { "proficiency": "prof_handloading" } ], "components": [ [ [ "223_casing", 1 ] ], [ [ "smrifle_primer", 1 ] ], @@ -143,6 +150,7 @@ "charges": 1, "reversible": true, "using": [ [ "bullet_forming", 4 ], [ "ammo_bullet", 1 ] ], + "proficiencies": [ { "proficiency": "prof_handloading" } ], "components": [ [ [ "223_casing", 1 ] ], [ [ "smrifle_primer", 1 ] ], [ [ "chem_black_powder", 15 ] ], [ [ "copper", 1 ] ] ] }, { @@ -161,6 +169,7 @@ "reversible": true, "using": [ [ "bullet_forming", 8 ], [ "ammo_bullet", 3 ], [ "ammo_270win", 1 ] ], "//": "2974 mg gunpowder rounded to 30 100 mg 'pieces'", + "proficiencies": [ { "proficiency": "prof_handloading" } ], "components": [ [ [ "gunpowder", 30 ], [ "gunpowder_magnum_pistol", 30 ], [ "gunpowder_rifle", 30 ] ], [ [ "copper", 1 ] ] ] }, { @@ -178,6 +187,7 @@ "charges": 1, "reversible": true, "using": [ [ "bullet_forming", 8 ], [ "ammo_bullet", 3 ], [ "ammo_270win", 1 ] ], + "proficiencies": [ { "proficiency": "prof_handloading" } ], "components": [ [ [ "chem_black_powder", 30 ] ], [ [ "copper", 1 ] ] ] }, { @@ -196,6 +206,7 @@ "reversible": true, "using": [ [ "bullet_forming", 12 ], [ "ammo_bullet", 4 ] ], "//": "4327 mg gunpowder rounded to 43 100 mg 'pieces'", + "proficiencies": [ { "proficiency": "prof_handloading" } ], "components": [ [ [ "300_casing", 1 ] ], [ [ "lgrifle_primer", 1 ] ], @@ -218,6 +229,7 @@ "charges": 1, "reversible": true, "using": [ [ "bullet_forming", 12 ], [ "ammo_bullet", 4 ] ], + "proficiencies": [ { "proficiency": "prof_handloading" } ], "components": [ [ [ "300_casing", 1 ] ], [ [ "lgrifle_primer", 1 ] ], [ [ "chem_black_powder", 43 ] ], [ [ "copper", 2 ] ] ] }, { @@ -236,6 +248,7 @@ "reversible": true, "using": [ [ "bullet_forming", 12 ], [ "ammo_bullet", 3 ] ], "//": "3200 mg gunpowder rounded to 32 100 mg 'pieces'", + "proficiencies": [ { "proficiency": "prof_handloading" } ], "components": [ [ [ "3006_casing", 1 ] ], [ [ "lgrifle_primer", 1 ] ], @@ -259,6 +272,7 @@ "reversible": true, "using": [ [ "bullet_forming", 12 ], [ "ammo_bullet", 4 ] ], "//": "3300 mg gunpowder rounded to 33 100 mg 'pieces'", + "proficiencies": [ { "proficiency": "prof_handloading" } ], "components": [ [ [ "3006_casing", 1 ] ], [ [ "lgrifle_primer", 1 ] ], @@ -282,6 +296,7 @@ "reversible": true, "using": [ [ "bullet_forming", 12 ], [ "ammo_bullet", 4 ] ], "//": "3300 mg gunpowder rounded to 33 100 mg 'pieces'", + "proficiencies": [ { "proficiency": "prof_handloading" } ], "components": [ [ [ "3006_casing", 1 ] ], [ [ "lgrifle_primer", 1 ] ], @@ -310,6 +325,7 @@ "charges": 1, "reversible": true, "using": [ [ "bullet_forming", 12 ], [ "ammo_bullet", 4 ] ], + "proficiencies": [ { "proficiency": "prof_handloading" } ], "components": [ [ [ "3006_casing", 1 ] ], [ [ "lgrifle_primer", 1 ] ], [ [ "chem_black_powder", 32 ] ], [ [ "copper", 2 ] ] ] }, { @@ -327,6 +343,7 @@ "charges": 1, "reversible": true, "using": [ [ "bullet_forming", 12 ], [ "ammo_bullet", 4 ] ], + "proficiencies": [ { "proficiency": "prof_handloading" } ], "components": [ [ [ "3006_casing", 1 ] ], [ [ "lgrifle_primer", 1 ] ], [ [ "chem_black_powder", 33 ] ], [ [ "copper", 2 ] ] ] }, { @@ -344,6 +361,7 @@ "charges": 1, "reversible": true, "using": [ [ "bullet_forming", 12 ], [ "ammo_bullet", 4 ] ], + "proficiencies": [ { "proficiency": "prof_handloading" } ], "components": [ [ [ "3006_casing", 1 ] ], [ [ "lgrifle_primer", 1 ] ], @@ -368,6 +386,7 @@ "reversible": true, "using": [ [ "bullet_forming", 9 ], [ "ammo_bullet", 3 ] ], "//": "2800 mg gunpowder rounded to 28 100 mg 'pieces'", + "proficiencies": [ { "proficiency": "prof_handloading" } ], "components": [ [ [ "308_casing", 1 ], [ "762_51_casing", 1 ] ], [ [ "lgrifle_primer", 1 ] ], @@ -395,6 +414,7 @@ "charges": 1, "reversible": true, "using": [ [ "bullet_forming", 9 ], [ "ammo_bullet", 3 ] ], + "proficiencies": [ { "proficiency": "prof_handloading" } ], "components": [ [ [ "308_casing", 1 ], [ "762_51_casing", 1 ] ], [ [ "lgrifle_primer", 1 ] ], @@ -418,6 +438,7 @@ "reversible": true, "using": [ [ "bullet_forming", 15 ], [ "ammo_bullet", 5 ] ], "//": "2844 mg gunpowder rounded to 28 100 mg 'pieces'", + "proficiencies": [ { "proficiency": "prof_handloading" } ], "components": [ [ [ "4570_casing", 1 ] ], [ [ "lgrifle_primer", 1 ] ], @@ -442,6 +463,7 @@ "reversible": true, "using": [ [ "bullet_forming", 15 ], [ "ammo_bullet", 3 ] ], "//": "3000 mg gunpowder rounded to 30 100 mg 'pieces'", + "proficiencies": [ { "proficiency": "prof_handloading" } ], "components": [ [ [ "4570_casing", 1 ] ], [ [ "lgrifle_primer", 1 ] ], @@ -465,6 +487,7 @@ "reversible": true, "using": [ [ "bullet_forming", 15 ], [ "ammo_bullet", 8 ] ], "//": "1944 mg gunpowder rounded to 19 100 mg 'pieces'", + "proficiencies": [ { "proficiency": "prof_handloading" } ], "components": [ [ [ "4570_casing", 1 ] ], [ [ "lgrifle_primer", 1 ] ], @@ -487,6 +510,7 @@ "charges": 1, "reversible": true, "using": [ [ "bullet_forming", 15 ], [ "ammo_bullet", 8 ] ], + "proficiencies": [ { "proficiency": "prof_handloading" } ], "components": [ [ [ "4570_casing", 1 ] ], [ [ "lgrifle_primer", 1 ] ], [ [ "chem_black_powder", 19 ] ], [ [ "copper", 3 ] ] ] }, { @@ -503,7 +527,7 @@ "book_learn": [ [ "recipe_caseless", 4 ] ], "charges": 1, "reversible": true, - "proficiencies": [ { "proficiency": "prof_plasticworking" } ], + "proficiencies": [ { "proficiency": "prof_plasticworking" }, { "proficiency": "prof_handloading" } ], "using": [ [ "bullet_forming", 2 ], [ "ammo_bullet", 2 ], [ "plastic_molding", 1 ] ], "//": "3000 mg gunpowder rounded to 30 100 mg 'pieces'", "components": [ @@ -529,6 +553,7 @@ "reversible": true, "using": [ [ "bullet_forming", 18 ], [ "ammo_bullet", 12 ] ], "//": "15800 mg gunpowder rounded to 158 100 mg 'pieces'", + "proficiencies": [ { "proficiency": "prof_handloading" } ], "components": [ [ [ "50_casing", 1 ] ], [ [ "lgrifle_primer", 1 ] ], @@ -551,6 +576,7 @@ "charges": 1, "reversible": true, "using": [ [ "bullet_forming", 18 ], [ "ammo_bullet", 12 ] ], + "proficiencies": [ { "proficiency": "prof_handloading" } ], "components": [ [ [ "50_casing", 1 ] ], [ [ "lgrifle_primer", 1 ] ], [ [ "chem_black_powder", 158 ] ], [ [ "copper", 6 ] ] ] }, { @@ -569,6 +595,7 @@ "reversible": true, "using": [ [ "bullet_forming", 21 ], [ "ammo_bullet", 12 ] ], "//": "15800 mg gunpowder rounded to 158 100 mg 'pieces'", + "proficiencies": [ { "proficiency": "prof_handloading" } ], "components": [ [ [ "50_casing", 1 ] ], [ [ "lgrifle_primer", 1 ] ], @@ -592,6 +619,7 @@ "charges": 1, "reversible": true, "using": [ [ "bullet_forming", 21 ], [ "ammo_bullet", 12 ] ], + "proficiencies": [ { "proficiency": "prof_handloading" } ], "components": [ [ [ "50_casing", 1 ] ], [ [ "lgrifle_primer", 1 ] ], @@ -616,6 +644,7 @@ "reversible": true, "using": [ [ "bullet_forming", 21 ] ], "//": "15800 mg gunpowder rounded to 158 100 mg 'pieces'", + "proficiencies": [ { "proficiency": "prof_handloading" } ], "components": [ [ [ "50_casing", 1 ] ], [ [ "lgrifle_primer", 1 ] ], @@ -639,6 +668,7 @@ "charges": 1, "reversible": true, "using": [ [ "bullet_forming", 21 ] ], + "proficiencies": [ { "proficiency": "prof_handloading" } ], "components": [ [ [ "50_casing", 1 ] ], [ [ "lgrifle_primer", 1 ] ], @@ -663,6 +693,7 @@ "reversible": true, "using": [ [ "bullet_forming", 4 ], [ "ammo_bullet", 1 ] ], "//": "1295 mg gunpowder rounded to 13 100 mg 'pieces'", + "proficiencies": [ { "proficiency": "prof_handloading" } ], "components": [ [ [ "545_casing", 1 ] ], [ [ "smrifle_primer", 1 ] ], @@ -685,6 +716,7 @@ "charges": 1, "reversible": true, "using": [ [ "bullet_forming", 4 ], [ "ammo_bullet", 1 ] ], + "proficiencies": [ { "proficiency": "prof_handloading" } ], "components": [ [ [ "545_casing", 1 ] ], [ [ "smrifle_primer", 1 ] ], [ [ "chem_black_powder", 13 ] ], [ [ "copper", 1 ] ] ] }, { @@ -703,6 +735,7 @@ "reversible": true, "using": [ [ "bullet_forming", 4 ], [ "ammo_bullet", 1 ] ], "//": "1295 mg gunpowder rounded to 13 100 mg 'pieces'", + "proficiencies": [ { "proficiency": "prof_handloading" } ], "components": [ [ [ "545_casing", 1 ] ], [ [ "smrifle_primer", 1 ] ], @@ -725,6 +758,7 @@ "charges": 1, "reversible": true, "using": [ [ "bullet_forming", 4 ], [ "ammo_bullet", 1 ] ], + "proficiencies": [ { "proficiency": "prof_handloading" } ], "components": [ [ [ "545_casing", 1 ] ], [ [ "smrifle_primer", 1 ] ], [ [ "chem_black_powder", 13 ] ], [ [ "copper", 1 ] ] ] }, { @@ -742,6 +776,7 @@ "charges": 1, "reversible": true, "using": [ [ "bullet_forming", 4 ], [ "ammo_bullet", 3 ], [ "ammo_300blk", 1 ] ], + "proficiencies": [ { "proficiency": "prof_handloading" } ], "//": "1133 mg gunpowder rounded to 11 100 mg 'pieces'", "components": [ [ [ "gunpowder", 11 ] ], [ [ "copper", 1 ] ] ] }, @@ -760,6 +795,7 @@ "charges": 1, "reversible": true, "using": [ [ "bullet_forming", 4 ], [ "ammo_bullet", 3 ], [ "ammo_300blk", 1 ] ], + "proficiencies": [ { "proficiency": "prof_handloading" } ], "components": [ [ [ "chem_black_powder", 11 ] ], [ [ "copper", 1 ] ] ] }, { @@ -778,6 +814,7 @@ "reversible": true, "using": [ [ "bullet_forming", 20 ] ], "//": "1717 mg gunpowder rounded to 17 100 mg 'pieces'", + "proficiencies": [ { "proficiency": "prof_handloading" } ], "components": [ [ [ "223_casing", 1 ] ], [ [ "smrifle_primer", 1 ] ], @@ -802,6 +839,7 @@ "reversible": true, "using": [ [ "bullet_forming", 4 ], [ "ammo_bullet", 1 ] ], "//": "1717 mg gunpowder rounded to 17 100 mg 'pieces'", + "proficiencies": [ { "proficiency": "prof_handloading" } ], "components": [ [ [ "223_casing", 1 ] ], [ [ "smrifle_primer", 1 ] ], @@ -825,6 +863,7 @@ "charges": 1, "reversible": true, "using": [ [ "bullet_forming", 20 ] ], + "proficiencies": [ { "proficiency": "prof_handloading" } ], "components": [ [ [ "223_casing", 1 ] ], [ [ "smrifle_primer", 1 ] ], @@ -848,6 +887,7 @@ "charges": 1, "reversible": true, "using": [ [ "bullet_forming", 4 ], [ "ammo_bullet", 1 ] ], + "proficiencies": [ { "proficiency": "prof_handloading" } ], "components": [ [ [ "223_casing", 1 ] ], [ [ "smrifle_primer", 1 ] ], @@ -872,6 +912,7 @@ "reversible": true, "using": [ [ "bullet_forming", 20 ], [ "ammo_bullet", 18 ] ], "//": "16523 mg gunpowder rounded to 165 100 mg 'pieces'", + "proficiencies": [ { "proficiency": "prof_handloading" } ], "components": [ [ [ "700nx_casing", 1 ] ], [ [ "lgrifle_primer", 1 ] ], @@ -894,6 +935,7 @@ "charges": 1, "reversible": true, "using": [ [ "bullet_forming", 20 ], [ "ammo_bullet", 18 ] ], + "proficiencies": [ { "proficiency": "prof_handloading" } ], "components": [ [ [ "700nx_casing", 1 ] ], [ [ "lgrifle_primer", 1 ] ], [ [ "chem_black_powder", 165 ] ], [ [ "copper", 10 ] ] ] }, { @@ -912,6 +954,7 @@ "reversible": true, "using": [ [ "bullet_forming", 9 ], [ "ammo_bullet", 3 ] ], "//": "2462 mg gunpowder rounded to 25 100 mg 'pieces'", + "proficiencies": [ { "proficiency": "prof_handloading" } ], "components": [ [ [ "308_casing", 1 ], [ "762_51_casing", 1 ] ], [ [ "lgrifle_primer", 1 ] ], @@ -935,6 +978,7 @@ "reversible": true, "using": [ [ "bullet_forming", 9 ], [ "ammo_bullet", 3 ] ], "//": "2462 mg gunpowder rounded to 25 100 mg 'pieces'", + "proficiencies": [ { "proficiency": "prof_handloading" } ], "components": [ [ [ "308_casing", 1 ], [ "762_51_casing", 1 ] ], [ [ "lgrifle_primer", 1 ] ], @@ -963,6 +1007,7 @@ "charges": 1, "reversible": true, "using": [ [ "bullet_forming", 9 ], [ "ammo_bullet", 3 ] ], + "proficiencies": [ { "proficiency": "prof_handloading" } ], "components": [ [ [ "308_casing", 1 ], [ "762_51_casing", 1 ] ], [ [ "lgrifle_primer", 1 ] ], @@ -985,6 +1030,7 @@ "charges": 1, "reversible": true, "using": [ [ "bullet_forming", 9 ], [ "ammo_bullet", 3 ] ], + "proficiencies": [ { "proficiency": "prof_handloading" } ], "components": [ [ [ "308_casing", 1 ], [ "762_51_casing", 1 ] ], [ [ "lgrifle_primer", 1 ] ], @@ -1008,6 +1054,7 @@ "charges": 1, "reversible": true, "using": [ [ "bullet_forming", 10 ], [ "ammo_bullet", 3 ] ], + "proficiencies": [ { "proficiency": "prof_handloading" } ], "//": "2851 mg gunpowder rounded to 29 100 mg 'pieces'", "components": [ [ [ "762R_casing", 1 ] ], @@ -1036,6 +1083,7 @@ "charges": 1, "reversible": true, "using": [ [ "bullet_forming", 10 ], [ "ammo_bullet", 3 ] ], + "proficiencies": [ { "proficiency": "prof_handloading" } ], "components": [ [ [ "762R_casing", 1 ] ], [ [ "lgrifle_primer", 1 ] ], [ [ "chem_black_powder", 29 ] ], [ [ "copper", 2 ] ] ] }, { @@ -1053,6 +1101,7 @@ "charges": 1, "reversible": true, "using": [ [ "bullet_forming", 5 ], [ "ammo_bullet", 2 ] ], + "proficiencies": [ { "proficiency": "prof_handloading" } ], "//": "1535 mg gunpowder rounded to 15 100 mg 'pieces'", "components": [ [ [ "762_casing", 1 ] ], @@ -1077,6 +1126,7 @@ "charges": 1, "reversible": true, "using": [ [ "bullet_forming", 5 ], [ "ammo_bullet", 2 ] ], + "proficiencies": [ { "proficiency": "prof_handloading" } ], "components": [ [ [ "762_casing", 1 ] ], [ [ "lgrifle_primer", 1 ] ], @@ -1100,6 +1150,7 @@ "charges": 1, "reversible": true, "using": [ [ "bullet_forming", 5 ], [ "ammo_bullet", 3 ] ], + "proficiencies": [ { "proficiency": "prof_handloading" } ], "//": "1535 mg gunpowder rounded to 15 100 mg 'pieces'", "components": [ [ [ "762_casing", 1 ] ], @@ -1123,6 +1174,7 @@ "charges": 1, "reversible": true, "using": [ [ "bullet_forming", 5 ], [ "ammo_bullet", 3 ] ], + "proficiencies": [ { "proficiency": "prof_handloading" } ], "components": [ [ [ "762_casing", 1 ] ], [ [ "lgrifle_primer", 1 ] ], [ [ "chem_black_powder", 15 ] ], [ [ "copper", 2 ] ] ] } ] diff --git a/data/json/recipes/ammo/shot.json b/data/json/recipes/ammo/shot.json index 649c15cc5ab55..81f5a7e544f77 100644 --- a/data/json/recipes/ammo/shot.json +++ b/data/json/recipes/ammo/shot.json @@ -15,6 +15,7 @@ "reversible": true, "//": "Assumes standard 9 pellet 00 load. 1166 mg gunpowder rounded to 12 100 mg 'pieces'", "using": [ [ "shot_forming", 1 ], [ "ammo_bullet", 11 ], [ "ammo_shot", 1 ] ], + "proficiencies": [ { "proficiency": "prof_handloading" } ], "tools": [ [ [ "press", -1 ] ] ], "components": [ [ [ "gunpowder", 12 ], [ "gunpowder_pistol", 12 ], [ "gunpowder_shotgun", 12 ] ] ] }, @@ -33,6 +34,7 @@ "charges": 1, "reversible": true, "using": [ [ "shot_forming", 1 ], [ "ammo_bullet", 8 ], [ "ammo_410shot", 1 ] ], + "proficiencies": [ { "proficiency": "prof_handloading" } ], "tools": [ [ [ "press", -1 ] ] ], "//": "971 mg gunpowder rounded to 10 100 mg 'pieces'", "components": [ [ [ "gunpowder", 10 ], [ "gunpowder_pistol", 10 ], [ "gunpowder_shotgun", 10 ] ] ] @@ -52,6 +54,7 @@ "charges": 1, "reversible": true, "using": [ [ "shot_forming", 1 ], [ "ammo_bullet", 10 ], [ "ammo_shot", 1 ] ], + "proficiencies": [ { "proficiency": "prof_handloading" } ], "tools": [ [ [ "press", -1 ] ] ], "//": "1490 mg gunpowder rounded to 15 100 mg 'pieces'", "components": [ [ [ "gunpowder", 15 ], [ "gunpowder_pistol", 15 ], [ "gunpowder_shotgun", 15 ] ] ] @@ -70,6 +73,7 @@ "book_learn": [ [ "recipe_bullets", 3 ], [ "manual_shotgun", 3 ] ], "charges": 1, "using": [ [ "ammo_shot", 1 ] ], + "proficiencies": [ { "proficiency": "prof_handloading" } ], "tools": [ [ [ "press", -1 ] ] ], "//": "same charge as a 1 oz load, could find no refference to actual loading data. 1490 mg gunpowder rounded to 15 100 mg 'pieces'", "components": [ [ [ "gunpowder", 15 ], [ "gunpowder_pistol", 15 ], [ "gunpowder_shotgun", 15 ] ], [ [ "magnesium", 5 ] ] ] @@ -89,6 +93,7 @@ "charges": 1, "reversible": true, "using": [ [ "ammo_shot", 1 ] ], + "proficiencies": [ { "proficiency": "prof_handloading" } ], "tools": [ [ [ "press", -1 ] ] ], "//": "Wikipedia states the shells contain 20 7.3 grain flechettes for a 146 grain or 1/3 oz load. http://www.sabotdesigns.com/002.html lists flechette velocity at 1950 fps. Gunpowder charge is calculated as if it was a solid slug for sake of ease. 750 mg gunpowder rounded to 8 100 mg 'pieces", "components": [ [ [ "gunpowder", 8 ], [ "gunpowder_pistol", 8 ], [ "gunpowder_shotgun", 8 ] ], [ [ "combatnail", 10 ] ] ] @@ -109,6 +114,7 @@ "reversible": true, "//": "assumes 1 oz slug. 1684 mg gunpowder rounded to 17 100 mg 'pieces'", "using": [ [ "bullet_forming", 1 ], [ "ammo_bullet", 10 ], [ "ammo_shot", 1 ] ], + "proficiencies": [ { "proficiency": "prof_handloading" } ], "components": [ [ [ "gunpowder", 17 ], [ "gunpowder_pistol", 17 ], [ "gunpowder_shotgun", 17 ] ] ] }, { @@ -126,6 +132,7 @@ "charges": 1, "reversible": true, "using": [ [ "shot_forming", 1 ], [ "ammo_bullet", 11 ], [ "ammo_shot", 1 ] ], + "proficiencies": [ { "proficiency": "prof_handloading" } ], "tools": [ [ [ "press", -1 ] ] ], "components": [ [ [ "chem_black_powder", 12 ] ] ] }, @@ -145,6 +152,7 @@ "reversible": true, "//": "assumes 1 oz load", "using": [ [ "shot_forming", 1 ], [ "ammo_bullet", 10 ], [ "ammo_shot", 1 ] ], + "proficiencies": [ { "proficiency": "prof_handloading" } ], "tools": [ [ [ "press", -1 ] ] ], "components": [ [ [ "chem_black_powder", 15 ] ] ] }, @@ -163,6 +171,7 @@ "charges": 1, "reversible": true, "using": [ [ "ammo_shot", 1 ] ], + "proficiencies": [ { "proficiency": "prof_handloading" } ], "tools": [ [ [ "press", -1 ] ] ], "components": [ [ [ "chem_black_powder", 15 ] ], [ [ "magnesium", 5 ] ] ] }, @@ -181,6 +190,7 @@ "charges": 1, "reversible": true, "using": [ [ "ammo_shot", 1 ] ], + "proficiencies": [ { "proficiency": "prof_handloading" } ], "tools": [ [ [ "press", -1 ] ] ], "components": [ [ [ "chem_black_powder", 8 ] ], [ [ "combatnail", 10 ] ] ] }, @@ -199,6 +209,7 @@ "charges": 1, "reversible": true, "using": [ [ "bullet_forming", 1 ], [ "ammo_bullet", 10 ], [ "ammo_shot", 1 ] ], + "proficiencies": [ { "proficiency": "prof_handloading" } ], "components": [ [ [ "chem_black_powder", 17 ] ] ] }, { @@ -272,6 +283,7 @@ "tools": [ [ [ "press", -1 ] ] ], "//": "1166 mg gunpowder rounded to 12 100 mg 'pieces'; recipe makes two shells", "//1": "currently halved inputs (rounding up) and result pending fix of casing duplication", + "proficiencies": [ { "proficiency": "prof_handloading" } ], "components": [ [ [ "gunpowder", 12 ], [ "gunpowder_pistol", 12 ], [ "gunpowder_shotgun", 12 ] ], [ @@ -304,6 +316,7 @@ "charges": 1, "reversible": true, "using": [ [ "ammo_shot", 1 ] ], + "proficiencies": [ { "proficiency": "prof_handloading" } ], "tools": [ [ [ "press", -1 ] ] ], "//1": "currently halved inputs (rounding up) and result pending fix of casing duplication", "components": [ @@ -365,6 +378,7 @@ "book_learn": [ [ "recipe_bullets", 3 ], [ "manual_shotgun", 2 ], [ "pocket_survival", 2 ], [ "mag_survival", 2 ] ], "charges": 1, "using": [ [ "ammo_shot", 1 ] ], + "proficiencies": [ { "proficiency": "prof_handloading" } ], "tools": [ [ [ "press", -1 ] ] ], "components": [ [ [ "incendiary", 25 ] ] ] }, @@ -383,6 +397,7 @@ "charges": 1, "reversible": true, "using": [ [ "ammo_bullet", 8 ] ], + "proficiencies": [ { "proficiency": "prof_handloading" } ], "qualities": [ { "id": "CUT", "level": 1 } ], "components": [ [ [ "chem_black_powder", 15 ] ], [ [ "shotgun_primer", 1 ] ], [ [ "paper", 1 ], [ "aluminum_foil", 1 ] ] ] }, @@ -401,6 +416,7 @@ "charges": 1, "reversible": true, "using": [ [ "ammo_bullet", 16 ] ], + "proficiencies": [ { "proficiency": "prof_handloading" } ], "qualities": [ { "id": "CUT", "level": 1 } ], "components": [ [ [ "chem_black_powder", 15 ] ], [ [ "shotgun_primer", 1 ] ], [ [ "paper", 1 ], [ "aluminum_foil", 1 ] ] ] }, @@ -419,6 +435,7 @@ "charges": 1, "reversible": true, "using": [ [ "ammo_bullet", 16 ] ], + "proficiencies": [ { "proficiency": "prof_handloading" } ], "qualities": [ { "id": "CUT", "level": 1 } ], "components": [ [ [ "chem_black_powder", 12 ] ], @@ -442,6 +459,7 @@ "charges": 1, "reversible": true, "using": [ [ "ammo_bullet", 8 ] ], + "proficiencies": [ { "proficiency": "prof_handloading" } ], "qualities": [ { "id": "CUT", "level": 1 } ], "components": [ [ [ "chem_black_powder", 15 ] ], [ [ "shotgun_primer", 1 ] ], [ [ "paper", 1 ], [ "aluminum_foil", 1 ] ] ] } diff --git a/data/json/recipes/recipe_ammo.json b/data/json/recipes/recipe_ammo.json index 63e3924fc1b53..15a33ee65b177 100644 --- a/data/json/recipes/recipe_ammo.json +++ b/data/json/recipes/recipe_ammo.json @@ -556,6 +556,7 @@ "autolearn": true, "book_learn": [ [ "recipe_bullets", 2 ], [ "manual_shotgun", 2 ] ], "qualities": [ { "id": "CUT", "level": 1 } ], + "proficiencies": [ { "proficiency": "prof_handloading" } ], "components": [ [ [ "gunpowder", 20 ], [ "chem_black_powder", 20 ] ], [ @@ -584,6 +585,7 @@ "autolearn": true, "book_learn": [ [ "recipe_bullets", 2 ], [ "manual_shotgun", 2 ] ], "qualities": [ { "id": "CUT", "level": 1 }, { "id": "SAW_M", "level": 1 } ], + "proficiencies": [ { "proficiency": "prof_handloading" } ], "components": [ [ [ "gunpowder", 20 ], [ "chem_black_powder", 20 ] ], [ [ "scrap", 1 ], [ "nail", 8 ], [ "copper", 16 ], [ "lead", 16 ] ], @@ -603,6 +605,7 @@ "autolearn": true, "book_learn": [ [ "recipe_bullets", 2 ], [ "manual_shotgun", 2 ] ], "qualities": [ { "id": "CUT", "level": 1 }, { "id": "SAW_M", "level": 1 } ], + "proficiencies": [ { "proficiency": "prof_handloading" } ], "components": [ [ [ "gunpowder", 20 ], [ "chem_black_powder", 20 ] ], [ [ "rebar", 1 ], [ "spear_rebar", 1 ], [ "rebar_rail", 1 ], [ "steel_rail", 1 ], [ "scrap", 1 ] ], @@ -624,6 +627,7 @@ "book_learn": [ [ "recipe_bullets", 2 ], [ "manual_shotgun", 2 ] ], "qualities": [ { "id": "CUT", "level": 1 }, { "id": "HAMMER", "level": 1 } ], "using": [ [ "surface_heat", 2 ] ], + "proficiencies": [ { "proficiency": "prof_handloading" } ], "components": [ [ [ "gunpowder", 20 ], [ "chem_black_powder", 20 ] ], [ [ "lead", 24 ] ], [ [ "paper", 1 ], [ "aluminum_foil", 1 ] ] ] }, { @@ -639,6 +643,7 @@ "autolearn": true, "book_learn": [ [ "recipe_bullets", 2 ], [ "manual_shotgun", 2 ] ], "qualities": [ { "id": "CUT", "level": 1 } ], + "proficiencies": [ { "proficiency": "prof_handloading" } ], "components": [ [ [ "gunpowder", 20 ], [ "chem_black_powder", 20 ] ], [ [ "nail", 8 ], [ "combatnail", 8 ] ], diff --git a/data/mods/Generic_Guns/recipes/recipes_grenade_propelled.json b/data/mods/Generic_Guns/recipes/recipes_grenade_propelled.json index 8d0dbedf2d1a9..5099e347436ba 100644 --- a/data/mods/Generic_Guns/recipes/recipes_grenade_propelled.json +++ b/data/mods/Generic_Guns/recipes/recipes_grenade_propelled.json @@ -14,6 +14,7 @@ "charges": 1, "reversible": true, "using": [ [ "bullet_forming", 2 ], [ "ammo_bullet", 12 ], [ "req_grenade", -1 ] ], + "proficiencies": [ { "proficiency": "prof_handloading" } ], "tools": [ [ [ "press", -1 ] ], [ [ "swage", -1 ] ] ], "qualities": [ { "id": "CUT", "level": 1 } ], "components": [ @@ -37,6 +38,7 @@ "charges": 1, "reversible": true, "using": [ [ "bullet_forming", 2 ], [ "ammo_bullet", 12 ], [ "req_grenade", -1 ] ], + "proficiencies": [ { "proficiency": "prof_handloading" } ], "tools": [ [ [ "press", -1 ] ], [ [ "swage", -1 ] ] ], "qualities": [ { "id": "CUT", "level": 1 } ], "components": [ diff --git a/data/mods/Generic_Guns/recipes/recipes_pistol.json b/data/mods/Generic_Guns/recipes/recipes_pistol.json index 5912d6bf07e73..ba751161e446f 100644 --- a/data/mods/Generic_Guns/recipes/recipes_pistol.json +++ b/data/mods/Generic_Guns/recipes/recipes_pistol.json @@ -14,6 +14,7 @@ "charges": 1, "reversible": true, "using": [ [ "req_pistol_tiny", 1 ], [ "bullet_forming", 2 ], [ "ammo_bullet", 2 ] ], + "proficiencies": [ { "proficiency": "prof_handloading" } ], "components": [ [ [ "gunpowder", 2 ], [ "gunpowder_pistol", 2 ], [ "gunpowder_shotgun", 2 ] ] ] }, { @@ -29,6 +30,7 @@ "activity_level": "fake", "copy-from": "reloaded_tiny_pistol_jhp", "using": [ [ "req_pistol_tiny", 1 ], [ "bullet_forming", 2 ], [ "ammo_bullet", 2 ] ], + "proficiencies": [ { "proficiency": "prof_handloading" } ], "components": [ [ [ "gunpowder", 2 ], [ "gunpowder_pistol", 2 ] ], [ [ "copper", 1 ] ] ] }, { @@ -53,6 +55,7 @@ "charges": 1, "reversible": true, "using": [ [ "req_pistol", 1 ], [ "bullet_forming", 2 ], [ "ammo_bullet", 2 ] ], + "proficiencies": [ { "proficiency": "prof_handloading" } ], "components": [ [ [ "gunpowder", 4 ], [ "gunpowder_pistol", 4 ], [ "gunpowder_shotgun", 4 ] ] ] }, { @@ -68,6 +71,7 @@ "activity_level": "fake", "copy-from": "reloaded_pistol_jhp", "using": [ [ "req_pistol", 1 ], [ "bullet_forming", 2 ], [ "ammo_bullet", 2 ] ], + "proficiencies": [ { "proficiency": "prof_handloading" } ], "components": [ [ [ "gunpowder", 4 ], [ "gunpowder_pistol", 4 ], [ "gunpowder_shotgun", 4 ] ], [ [ "copper", 1 ], [ "pistol_tiny_casing", 1 ] ] @@ -95,6 +99,7 @@ "charges": 1, "reversible": true, "using": [ [ "req_pistol_magnum", 1 ], [ "bullet_forming", 5 ], [ "ammo_bullet", 5 ] ], + "proficiencies": [ { "proficiency": "prof_handloading" } ], "components": [ [ [ "gunpowder", 6 ], [ "gunpowder_rifle", 6 ], [ "gunpowder_magnum_pistol", 6 ] ] ] }, { @@ -110,6 +115,7 @@ "activity_level": "fake", "copy-from": "reloaded_pistol_magnum_jhp", "using": [ [ "req_pistol_magnum", 1 ], [ "bullet_forming", 5 ], [ "ammo_bullet", 4 ] ], + "proficiencies": [ { "proficiency": "prof_handloading" } ], "components": [ [ [ "gunpowder", 6 ], [ "gunpowder_rifle", 6 ], [ "gunpowder_magnum_pistol", 6 ] ], [ [ "copper", 2 ], [ "pistol_magnum_casing", 1 ] ] diff --git a/data/mods/Generic_Guns/recipes/recipes_rifle.json b/data/mods/Generic_Guns/recipes/recipes_rifle.json index 0a76716d1647a..9cb81f6eee452 100644 --- a/data/mods/Generic_Guns/recipes/recipes_rifle.json +++ b/data/mods/Generic_Guns/recipes/recipes_rifle.json @@ -14,6 +14,7 @@ "charges": 1, "reversible": true, "using": [ [ "ammo_bullet", 10 ] ], + "proficiencies": [ { "proficiency": "prof_handloading" } ], "qualities": [ { "id": "CUT", "level": 1 } ], "components": [ [ [ "chem_black_powder", 5 ] ], [ [ "paper", 1 ] ] ] }, @@ -32,6 +33,7 @@ "charges": 1, "reversible": true, "using": [ [ "ammo_bullet", 10 ] ], + "proficiencies": [ { "proficiency": "prof_handloading" } ], "qualities": [ { "id": "CUT", "level": 1 } ], "components": [ [ [ "chem_black_powder", 5 ] ], [ [ "paper", 1 ] ] ] }, @@ -50,6 +52,7 @@ "charges": 1, "reversible": true, "using": [ [ "req_rifle", 1 ], [ "bullet_forming", 9 ], [ "ammo_bullet", 6 ] ], + "proficiencies": [ { "proficiency": "prof_handloading" } ], "components": [ [ [ "gunpowder", 12 ], [ "gunpowder_magnum_pistol", 12 ], [ "gunpowder_rifle", 12 ], [ "gunpowder_large_rifle", 12 ] ] ] @@ -94,6 +97,7 @@ "charges": 1, "reversible": true, "using": [ [ "req_rifle_huge", 1 ], [ "bullet_forming", 18 ], [ "ammo_bullet", 12 ] ], + "proficiencies": [ { "proficiency": "prof_handloading" } ], "components": [ [ [ "gunpowder", 30 ], [ "gunpowder_large_rifle", 30 ] ] ] }, { diff --git a/data/mods/Generic_Guns/recipes/recipes_shot.json b/data/mods/Generic_Guns/recipes/recipes_shot.json index a2994f101900e..f5c4724219eaf 100644 --- a/data/mods/Generic_Guns/recipes/recipes_shot.json +++ b/data/mods/Generic_Guns/recipes/recipes_shot.json @@ -14,6 +14,7 @@ "charges": 1, "reversible": true, "using": [ [ "shot_forming", 1 ], [ "ammo_bullet", 10 ], [ "req_shot", 1 ] ], + "proficiencies": [ { "proficiency": "prof_handloading" } ], "tools": [ [ [ "press", -1 ] ] ], "components": [ [ [ "gunpowder", 6 ], [ "gunpowder_pistol", 6 ], [ "gunpowder_shotgun", 6 ] ] ] }, @@ -32,6 +33,7 @@ "charges": 1, "reversible": true, "using": [ [ "shot_forming", 1 ], [ "ammo_bullet", 10 ], [ "req_shot", 1 ] ], + "proficiencies": [ { "proficiency": "prof_handloading" } ], "tools": [ [ [ "press", -1 ] ] ], "components": [ [ [ "chem_black_powder", 6 ] ] ] }, @@ -51,6 +53,7 @@ "charges": 1, "reversible": true, "using": [ [ "shot_forming", 1 ], [ "ammo_bullet", 10 ], [ "req_shot", 1 ] ], + "proficiencies": [ { "proficiency": "prof_handloading" } ], "tools": [ [ [ "press_dowel", -1 ] ] ] }, { @@ -69,6 +72,7 @@ "tools": [ [ [ "press", -1 ] ] ], "book_learn": [ [ "recipe_bullets", 1 ], [ "manual_shotgun", 1 ] ], "using": [ [ "shot_forming", 1 ], [ "ammo_bullet", 10 ], [ "req_shot", 1 ] ], + "proficiencies": [ { "proficiency": "prof_handloading" } ], "components": [ [ [ "gunpowder", 3 ], [ "gunpowder_pistol", 3 ], [ "gunpowder_shotgun", 3 ] ] ] }, { @@ -85,6 +89,7 @@ "charges": 1, "reversible": true, "using": [ [ "shot_forming", 1 ], [ "ammo_bullet", 10 ], [ "req_shot", 1 ] ], + "proficiencies": [ { "proficiency": "prof_handloading" } ], "components": [ [ [ "chem_black_powder", 3 ] ] ] }, { @@ -103,6 +108,7 @@ "reversible": true, "book_learn": [ [ "survival_book", 1 ], [ "mag_survival", 1 ] ], "tools": [ [ [ "press_dowel", -1 ] ] ], + "proficiencies": [ { "proficiency": "prof_handloading" } ], "components": [ [ [ "chem_black_powder", 3 ] ] ] }, { @@ -121,6 +127,7 @@ "tools": [ [ [ "press", -1 ] ] ], "book_learn": [ [ "recipe_bullets", 3 ], [ "manual_shotgun", 3 ] ], "using": [ [ "req_shot", 1 ] ], + "proficiencies": [ { "proficiency": "prof_handloading" } ], "components": [ [ [ "gunpowder", 3 ], [ "gunpowder_pistol", 3 ], [ "gunpowder_shotgun", 3 ] ], [ [ "magnesium", 5 ] ] ] }, { @@ -139,6 +146,7 @@ "tools": [ [ [ "press", -1 ] ] ], "book_learn": [ [ "recipe_bullets", 3 ], [ "manual_shotgun", 3 ] ], "using": [ [ "req_shot", 1 ] ], + "proficiencies": [ { "proficiency": "prof_handloading" } ], "components": [ [ [ "chem_black_powder", 3 ] ], [ [ "magnesium", 5 ] ] ] }, { @@ -156,6 +164,7 @@ "charges": 1, "reversible": true, "using": [ [ "shot_forming", 1 ], [ "ammo_bullet", 10 ], [ "req_shot", 1 ] ], + "proficiencies": [ { "proficiency": "prof_handloading" } ], "book_learn": [ [ "survival_book", 1 ], [ "mag_survival", 1 ] ], "tools": [ [ [ "press_dowel", -1 ] ] ] }, @@ -175,6 +184,7 @@ "difficulty": 3, "book_learn": [ [ "recipe_bullets", 3 ], [ "manual_shotgun", 3 ] ], "using": [ [ "bullet_forming", 1 ], [ "ammo_bullet", 20 ], [ "req_shot", 1 ] ], + "proficiencies": [ { "proficiency": "prof_handloading" } ], "components": [ [ [ "gunpowder", 6 ], [ "gunpowder_pistol", 6 ], [ "gunpowder_shotgun", 6 ] ] ] }, { @@ -193,6 +203,7 @@ "difficulty": 3, "book_learn": [ [ "recipe_bullets", 3 ], [ "manual_shotgun", 3 ] ], "using": [ [ "bullet_forming", 1 ], [ "ammo_bullet", 20 ], [ "req_shot", 1 ] ], + "proficiencies": [ { "proficiency": "prof_handloading" } ], "components": [ [ [ "chem_black_powder", 6 ] ] ] }, { @@ -210,6 +221,7 @@ "charges": 1, "reversible": true, "using": [ [ "shot_forming", 1 ], [ "ammo_bullet", 10 ], [ "req_shot", 1 ] ], + "proficiencies": [ { "proficiency": "prof_handloading" } ], "book_learn": [ [ "survival_book", 1 ], [ "mag_survival", 1 ] ], "tools": [ [ [ "press_dowel", -1 ] ] ] }, @@ -229,6 +241,7 @@ "tools": [ [ [ "press", -1 ] ] ], "book_learn": [ [ "recipe_bullets", 4 ], [ "manual_shotgun", 4 ] ], "using": [ [ "req_shot", 1 ] ], + "proficiencies": [ { "proficiency": "prof_handloading" } ], "components": [ [ [ "gunpowder", 6 ], [ "gunpowder_pistol", 6 ], [ "gunpowder_shotgun", 6 ] ], [ [ "combatnail", 10 ] ] ] }, { @@ -247,6 +260,7 @@ "tools": [ [ [ "press", -1 ] ] ], "book_learn": [ [ "recipe_bullets", 4 ], [ "manual_shotgun", 4 ] ], "using": [ [ "req_shot", 1 ] ], + "proficiencies": [ { "proficiency": "prof_handloading" } ], "components": [ [ [ "chem_black_powder", 6 ] ], [ [ "combatnail", 10 ] ] ] }, { @@ -264,6 +278,7 @@ "charges": 1, "reversible": true, "using": [ [ "shot_forming", 1 ], [ "ammo_bullet", 10 ], [ "req_shot", 1 ] ], + "proficiencies": [ { "proficiency": "prof_handloading" } ], "book_learn": [ [ "survival_book", 1 ], [ "mag_survival", 1 ] ], "tools": [ [ [ "press_dowel", -1 ] ] ] }, @@ -282,6 +297,7 @@ "reversible": true, "tools": [ [ [ "press", -1 ] ] ], "using": [ [ "req_shot", 1 ] ], + "proficiencies": [ { "proficiency": "prof_handloading" } ], "components": [ [ [ "gunpowder", 6 ], [ "gunpowder_pistol", 6 ], [ "gunpowder_shotgun", 6 ] ], [ @@ -314,6 +330,7 @@ "reversible": true, "tools": [ [ [ "press", -1 ] ] ], "using": [ [ "req_shot", 1 ] ], + "proficiencies": [ { "proficiency": "prof_handloading" } ], "components": [ [ [ "chem_black_powder", 6 ] ], [ @@ -346,6 +363,7 @@ "charges": 1, "reversible": true, "using": [ [ "shot_forming", 1 ], [ "ammo_bullet", 10 ], [ "req_shot", 1 ] ], + "proficiencies": [ { "proficiency": "prof_handloading" } ], "book_learn": [ [ "survival_book", 1 ], [ "mag_survival", 1 ] ], "tools": [ [ [ "press_dowel", -1 ] ] ] } From 9db34156cd5e3f081477e93dd6e4b94040942f5b Mon Sep 17 00:00:00 2001 From: slimeboy460 <68845349+slimeboy460@users.noreply.github.com> Date: Wed, 17 Feb 2021 21:35:17 -1000 Subject: [PATCH 222/453] Drug Dealer Profession (#47255) --- data/json/professions.json | 17 +++++++++++++++++ 1 file changed, 17 insertions(+) diff --git a/data/json/professions.json b/data/json/professions.json index 6f9853a31e3ed..9b4d5e7de891c 100644 --- a/data/json/professions.json +++ b/data/json/professions.json @@ -3922,6 +3922,23 @@ "female": [ "bra", "panties" ] } }, + { + "type": "profession", + "id": "local_drug_dealer", + "name": "Drug Dealer", + "description": "You were about to make your biggest sale yet, but when you met the buyer he tried to bite you. To top it off, it seems that this wasn't some sort of bad high for the user, as the whole town tried going for your throat too.", + "points": 2, + "skills": [ { "level": 1, "name": "melee" }, { "level": 2, "name": "stabbing" }, { "level": 2, "name": "speech" } ], + "items": { + "both": { + "items": [ "hoodie", "jeans", "mbag", "socks", "sneakers", "bandana", "gloves_medical", "switchblade" ], + "entries": [ { "item": "crack", "charges": 25, "container-item": "bag_zipper" } ] + }, + "male": [ "briefs" ], + "female": [ "sports_bra", "boy_shorts" ] + }, + "traits": [ "LIAR" ] + }, { "type": "profession", "id": "handloader", From 740d7907b5a63cbf2e9cd95f7e7f4babee827e72 Mon Sep 17 00:00:00 2001 From: ToxiClay Date: Wed, 23 Dec 2020 17:27:35 -0500 Subject: [PATCH 223/453] Add hallula bread (#46282) --- data/json/items/comestibles/bread.json | 22 ++++++++++++++++++++++ data/json/recipes/food/bread.json | 25 +++++++++++++++++++++++++ 2 files changed, 47 insertions(+) diff --git a/data/json/items/comestibles/bread.json b/data/json/items/comestibles/bread.json index 1fabede92c375..d7f66d42cba2d 100644 --- a/data/json/items/comestibles/bread.json +++ b/data/json/items/comestibles/bread.json @@ -304,5 +304,27 @@ "flags": [ "EATEN_HOT", "EATEN_COLD" ], "fun": 3, "vitamins": [ [ "calcium", 2 ], [ "iron", 6 ] ] + }, + { + "type": "COMESTIBLE", + "id": "hallula", + "name": { "str_sp": "hallula" }, + "weight": "45 g", + "color": "brown", + "spoils_in": "10 days", + "container": "bag_plastic", + "comestible_type": "FOOD", + "symbol": "%", + "healthy": 1, + "calories": 61, + "description": "This type of bread is popular in Chile and Bolivia. Prepared using animal lard or oil, it resembles a large, round scone. In the pre-Cataclysm world, it would usually be filled with savory ingredients rather than sweet ones.", + "price": "272 cent", + "price_postapoc": "4 USD", + "material": [ "wheat" ], + "volume": "48 ml", + "charges": 16, + "flags": [ "EATEN_HOT", "EATEN_COLD" ], + "fun": 4, + "vitamins": [ [ "calcium", 2 ], [ "iron", 6 ] ] } ] diff --git a/data/json/recipes/food/bread.json b/data/json/recipes/food/bread.json index 63671d90fd276..c9996e42485f4 100644 --- a/data/json/recipes/food/bread.json +++ b/data/json/recipes/food/bread.json @@ -47,5 +47,30 @@ [ [ "salt", 1 ] ] ], "//": "Later: this needs baking soda. Also possibility of rewrite to use portions of components' charges." + }, + { + "type": "recipe", + "activity_level": "LIGHT_EXERCISE", + "result": "hallula", + "category": "CC_FOOD", + "subcategory": "CSC_FOOD_BREAD", + "skill_used": "cooking", + "difficulty": 3, + "charges": 8, + "time": "30 m", + "batch_time_factors": [ 50, 5 ], + "book_learn": [ [ "family_cookbook", 1 ], [ "baking_book", 2 ], [ "cookbook", 2 ] ], + "qualities": [ { "id": "COOK", "level": 3 } ], + "tools": [ [ [ "surface_heat", 8, "LIST" ] ] ], + "components": [ + [ [ "flour", 3 ] ], + [ [ "yeast", 2 ] ], + [ [ "sugar", 1 ] ], + [ [ "salt", 1 ] ], + [ [ "water", 1 ] ], + [ [ "any_butter_or_oil", 2, "LIST" ] ] + ], + "//": "I'm not sure whether this should also be rewritten to use a portion of charges, or scaled up so that the smallest component in the recipe becomes a single charge.", + "//2": "Since milk is only used sparingly in the creation of hallula, to give it a glazed appearance, Cataclysm practicality suggests omitting it." } ] From 69450fbd104f62270dc49d08fbd522e27a1ff56b Mon Sep 17 00:00:00 2001 From: Jamuro-g <76928284+Jamuro-g@users.noreply.github.com> Date: Thu, 18 Feb 2021 08:37:34 +0100 Subject: [PATCH 224/453] Arm mounted pouch (#46946) --- data/json/itemgroups/activities_hobbies.json | 2 ++ data/json/items/armor/storage.json | 30 ++++++++++++++++++++ data/json/recipes/armor/storage.json | 14 +++++++++ 3 files changed, 46 insertions(+) diff --git a/data/json/itemgroups/activities_hobbies.json b/data/json/itemgroups/activities_hobbies.json index 04328bb8792f8..f8967629f8a8d 100644 --- a/data/json/itemgroups/activities_hobbies.json +++ b/data/json/itemgroups/activities_hobbies.json @@ -143,6 +143,7 @@ { "item": "multitool", "prob": 12 }, { "item": "throwing_knife", "prob": 7 }, { "item": "slingpack", "prob": 18 }, + { "item": "armrig", "prob": 3 }, { "item": "manual_cutting", "prob": 12 }, { "item": "manual_launcher", "prob": 1 }, { "item": "recipe_bullets", "prob": 8 }, @@ -207,6 +208,7 @@ [ "backpack_hiking", 12 ], [ "bigback", 3 ], [ "travelpack", 6 ], + [ "armrig", 3 ], [ "cowboy_hat", 4 ], [ "10gal_hat", 4 ], { "item": "bb", "prob": 8, "charges": [ 1, 500 ] }, diff --git a/data/json/items/armor/storage.json b/data/json/items/armor/storage.json index bd554b679a081..d71ba7e2f0ae4 100644 --- a/data/json/items/armor/storage.json +++ b/data/json/items/armor/storage.json @@ -808,6 +808,36 @@ "material_thickness": 0.2, "flags": [ "VARSIZE", "WATER_FRIENDLY", "BELTED" ] }, + { + "id": "armrig", + "type": "ARMOR", + "name": { "str": "armband pouch", "str_pl": "armband pouches" }, + "description": "A small pouch that can be worn on the upper arm using buckled straps. This is a favoured item among sports & camping enthusiasts.", + "weight": "205 g", + "volume": "550 ml", + "price": 3000, + "price_postapoc": 250, + "material": [ "cotton", "plastic" ], + "symbol": "[", + "looks_like": "armguard_soft", + "color": "dark_gray", + "covers": [ "arm_l", "arm_r" ], + "sided": true, + "coverage": 20, + "encumbrance": 2, + "max_encumbrance": 7, + "pocket_data": [ + { + "pocket_type": "CONTAINER", + "max_contains_volume": "500 ml", + "max_contains_weight": "1 kg", + "max_item_length": "15 cm", + "moves": 200 + } + ], + "material_thickness": 2, + "flags": [ "VARSIZE", "WATER_FRIENDLY", "BELTED" ] + }, { "id": "makeshift_knapsack", "type": "ARMOR", diff --git a/data/json/recipes/armor/storage.json b/data/json/recipes/armor/storage.json index 2162ba1e41869..bfba4c0ceb523 100644 --- a/data/json/recipes/armor/storage.json +++ b/data/json/recipes/armor/storage.json @@ -380,6 +380,20 @@ "proficiencies": [ { "proficiency": "prof_closures" }, { "proficiency": "prof_leatherworking_basic" } ], "components": [ [ [ "2x4", 2 ] ], [ [ "nail", 10 ] ] ] }, + { + "result": "armrig", + "type": "recipe", + "activity_level": "LIGHT_EXERCISE", + "category": "CC_ARMOR", + "subcategory": "CSC_ARMOR_STORAGE", + "skill_used": "tailor", + "difficulty": 3, + "time": "1 h", + "autolearn": true, + "reversible": true, + "using": [ [ "tailoring_cotton", 2 ], [ "fastener_small", 1 ] ], + "proficiencies": [ { "proficiency": "prof_closures" } ] + }, { "result": "chestpouch", "type": "recipe", From 665b1dd8f6feea2a58a4af7d8e039ddf683299cb Mon Sep 17 00:00:00 2001 From: Xenomorph-III Date: Thu, 18 Feb 2021 20:44:39 +1300 Subject: [PATCH 225/453] Tazer drone iii (#47353) --- data/json/items/corpses/inactive_bots.json | 26 ++++++++++++++++++++++ data/json/items/generic.json | 18 +++++++++++++++ data/json/monstergroups/lab.json | 2 ++ data/json/monsters/drones.json | 14 ++++++++++++ data/json/recipes/other/bots.json | 26 ++++++++++++++++++++++ 5 files changed, 86 insertions(+) diff --git a/data/json/items/corpses/inactive_bots.json b/data/json/items/corpses/inactive_bots.json index 4eb2412326a20..abe50e4bbf6cb 100644 --- a/data/json/items/corpses/inactive_bots.json +++ b/data/json/items/corpses/inactive_bots.json @@ -740,5 +740,31 @@ "moves": 150, "skills": [ "electronics", "computer" ] } + }, + { + "id": "bot_tazer_hack", + "type": "TOOL", + "name": { "str": "inactive tazer hack" }, + "description": "This is an inactive tazer hack. Hacks are fist-sized robots that fly through the air. This one has a tazer and attacks by flying at its target and delivering an electric shock. Use this item to reprogram and release the tazer hack. Electronics and computer skills determine if the targeting matrix is reprogrammed successfully.", + "weight": "4700 g", + "volume": "750 ml", + "price": 64500, + "price_postapoc": 3000, + "to_hit": -3, + "bashing": 6, + "cutting": 6, + "material": [ "aluminum", "plastic" ], + "symbol": ",", + "color": "cyan", + "use_action": { + "type": "place_monster", + "monster_id": "mon_tazer_hack", + "friendly_msg": "The tazer hack flies from your hand and surveys the area!", + "hostile_msg": "You misprogram the tazer hack; run!", + "difficulty": 3, + "moves": 60, + "place_randomly": true, + "skills": [ "electronics", "computer" ] + } } ] diff --git a/data/json/items/generic.json b/data/json/items/generic.json index 95a5a41754364..4d2c75ea1a39a 100644 --- a/data/json/items/generic.json +++ b/data/json/items/generic.json @@ -3393,5 +3393,23 @@ ] } ] + }, + { + "type": "GENERIC", + "id": "broken_tazer_hack", + "symbol": ",", + "color": "green", + "name": { "str": "broken tazer hack" }, + "category": "other", + "description": "A broken tazer hack, with its propellers still and tazer inert. Could be gutted for parts.", + "price": 1000, + "price_postapoc": 10, + "material": [ "steel", "plastic" ], + "weight": "100 kg", + "volume": "65 L", + "bashing": 4, + "cutting": 4, + "to_hit": -3, + "flags": [ "TRADER_AVOID", "NO_REPAIR" ] } ] diff --git a/data/json/monstergroups/lab.json b/data/json/monstergroups/lab.json index c86bd401acc88..ad71a5a8e059b 100644 --- a/data/json/monstergroups/lab.json +++ b/data/json/monstergroups/lab.json @@ -97,6 +97,7 @@ { "monster": "mon_zombie_labsecurity", "freq": 700, "cost_multiplier": 2 }, { "monster": "mon_science_bot", "freq": 50, "cost_multiplier": 4 }, { "monster": "mon_manhack", "freq": 200, "cost_multiplier": 0 }, + { "monster": "mon_tazer_hack", "freq": 150, "cost_multiplier": 0 }, { "monster": "mon_manhack", "freq": 45, "cost_multiplier": 0, "pack_size": [ 2, 3 ] }, { "monster": "mon_skitterbot", "freq": 85, "cost_multiplier": 0 }, { "monster": "mon_skitterbot", "freq": 85, "cost_multiplier": 0, "pack_size": [ 2, 3 ] }, @@ -148,6 +149,7 @@ { "monster": "mon_zombie_labsecurity", "freq": 40, "cost_multiplier": 0, "pack_size": [ 2, 3 ] }, { "monster": "mon_zombie_hazmat", "freq": 40, "cost_multiplier": 1, "pack_size": [ 1, 3 ] }, { "monster": "mon_manhack", "freq": 20, "cost_multiplier": 1, "pack_size": [ 3, 12 ] }, + { "monster": "mon_tazer_hack", "freq": 20, "cost_multiplier": 1, "pack_size": [ 1, 5 ] }, { "monster": "mon_mutant_experimental", "freq": 10, "cost_multiplier": 0, "pack_size": [ 1, 3 ] }, { "monster": "mon_skitterbot", "freq": 10, "cost_multiplier": 0, "pack_size": [ 2, 3 ] }, { "monster": "mon_zombie_phase_skulker", "freq": 10, "cost_multiplier": 0, "pack_size": [ 2, 3 ] }, diff --git a/data/json/monsters/drones.json b/data/json/monsters/drones.json index 4147a56358957..550fa09c3f8a3 100644 --- a/data/json/monsters/drones.json +++ b/data/json/monsters/drones.json @@ -185,5 +185,19 @@ "PRIORITIZE_TARGETS", "HIT_AND_RUN" ] + }, + { + "id": "mon_tazer_hack", + "copy-from": "base_drone", + "type": "MONSTER", + "name": { "str": "tazer hack" }, + "description": "An automated drone, this small quadcopter robot appears to have a tazer strapped to the front. While extremely fast, it is very fragile.", + "diff": 10, + "speed": 350, + "color": "cyan", + "armor_cut": 2, + "armor_bullet": 1, + "revert_to_itype": "bot_tazer_hack", + "special_attacks": [ [ "TAZER", 5 ] ] } ] diff --git a/data/json/recipes/other/bots.json b/data/json/recipes/other/bots.json index 413f27a8c981b..8ff9c11997cfd 100644 --- a/data/json/recipes/other/bots.json +++ b/data/json/recipes/other/bots.json @@ -791,5 +791,31 @@ [ [ "floodlight", 1 ] ], [ [ "turret_chassis", 1 ] ] ] + }, + { + "type": "recipe", + "activity_level": "LIGHT_EXERCISE", + "result": "bot_tazer_hack", + "category": "CC_ELECTRONIC", + "subcategory": "CSC_ELECTRONIC_OTHER", + "skill_used": "electronics", + "skills_required": [ [ "mechanics", 4 ], [ "computer", 4 ] ], + "difficulty": 6, + "time": "50 m", + "reversible": true, + "decomp_learn": 7, + "book_learn": [ [ "recipe_lab_elec", 5 ], [ "textbook_robots", 6 ] ], + "using": [ [ "soldering_standard", 10 ] ], + "qualities": [ { "id": "SCREW", "level": 1 } ], + "components": [ + [ [ "tazer", 1 ] ], + [ [ "ai_module_basic", 1 ] ], + [ [ "RAM", 1 ] ], + [ [ "small_storage_battery", 1 ] ], + [ [ "scrap", 1 ] ], + [ [ "quad_rotors", 1 ] ], + [ [ "sensor_module", 1 ] ], + [ [ "identification_module", 1 ] ] + ] } ] From 594ff1b910bbf7444281e3fb572a3493438558e8 Mon Sep 17 00:00:00 2001 From: grawprog <77870049+grawprog@users.noreply.github.com> Date: Wed, 17 Feb 2021 23:47:51 -0800 Subject: [PATCH 226/453] Added Gelatin and Several Gelatin Based Recipes (#47080) --- data/json/itemgroups/Food/food.json | 9 +- data/json/itemgroups/SUS/fridges.json | 7 + .../json/itemgroups/collections_domestic.json | 2 + data/json/items/comestibles/junkfood.json | 129 ++++++++++++ data/json/items/comestibles/other.json | 83 ++++++++ data/json/recipes/food/dry.json | 14 ++ data/json/recipes/food/other.json | 197 ++++++++++++++++++ data/json/recipes/recipe_food.json | 9 +- .../json/requirements/cooking_components.json | 33 +++ 9 files changed, 479 insertions(+), 4 deletions(-) diff --git a/data/json/itemgroups/Food/food.json b/data/json/itemgroups/Food/food.json index 99d9cf752b614..a3b1cfab1acbc 100644 --- a/data/json/itemgroups/Food/food.json +++ b/data/json/itemgroups/Food/food.json @@ -46,7 +46,10 @@ { "item": "dry_beans", "prob": 40 }, { "item": "dry_lentils", "prob": 30 }, { "item": "dry_rice", "prob": 40 }, - { "item": "freeze_dried_meal", "prob": 10 } + { "item": "freeze_dried_meal", "prob": 10 }, + { "item": "gelatin_powder", "prob": 40 }, + { "item": "chem_agar", "prob": 15 }, + { "item": "gelatin_dessert_powder", "prob": 40 } ] }, { @@ -426,6 +429,7 @@ { "item": "candy", "prob": 70 }, { "item": "candy2", "prob": 70 }, { "item": "candy3", "prob": 70 }, + { "item": "candy4", "prob": 70 }, { "item": "cow_candy", "prob": 20 }, { "item": "maltballs", "prob": 60 }, { "item": "mintpatties", "prob": 60 }, @@ -553,7 +557,8 @@ { "item": "pie", "prob": 20 }, { "item": "pie_veggy", "prob": 18 }, { "item": "pie_meat", "prob": 18 }, - { "item": "pie_maple", "prob": 9 } + { "item": "pie_maple", "prob": 9 }, + { "item": "gelatin_dessert_processed", "prob": 40 } ] }, { diff --git a/data/json/itemgroups/SUS/fridges.json b/data/json/itemgroups/SUS/fridges.json index d99955ed69801..75a7f9e8b6fe8 100644 --- a/data/json/itemgroups/SUS/fridges.json +++ b/data/json/itemgroups/SUS/fridges.json @@ -39,6 +39,8 @@ { "item": "yoghurt", "prob": 80 }, { "item": "butter", "prob": 80 }, { "item": "pudding", "prob": 30 }, + { "item": "gelatin_dessert_processed", "prob": 20 }, + { "item": "egg_bird_unfert", "prob": 85, "count-min": 1, "count-max": 12 }, { "item": "egg_bird_unfert", "prob": 85, "charges-min": 1, "charges-max": 12, "container-item": "carton_egg" }, { "item": "bacon", "prob": 25 }, { @@ -520,6 +522,8 @@ { "item": "onion_rings", "charges-min": 1, "prob": 10 }, { "item": "pizza_veggy", "charges-min": 1, "prob": 20 }, { "item": "nachosv", "charges-min": 1, "prob": 20 }, + { "item": "gelatin_dessert_vegan", "prob": 30 }, + { "item": "gelatin_dessert_vegan_fruit", "prob": 30 }, { "distribution": [ { @@ -623,6 +627,8 @@ { "item": "yoghurt", "prob": 20 }, { "item": "butter", "prob": 20 }, { "item": "pudding", "prob": 20 }, + { "item": "gelatin_dessert_processed", "prob": 10 }, + { "item": "egg_bird_unfert", "prob": 20, "count-min": 1, "count-max": 12 }, { "item": "egg_bird_unfert", "prob": 20, "charges-min": 1, "charges-max": 12, "container-item": "carton_egg" }, { "item": "bacon", "prob": 25 }, { @@ -880,6 +886,7 @@ { "item": "yoghurt", "count": [ 1, 3 ], "prob": 75 }, { "item": "butter", "prob": 50 }, { "item": "pudding", "prob": 30 }, + { "item": "gelatin_dessert_processed", "prob": 10 }, { "item": "veggy_salad", "charges-min": 1, "prob": 19 }, { "item": "blt", "charges-min": 1, "prob": 13 }, { "item": "protein_shake", "charges-min": 1, "prob": 6 }, diff --git a/data/json/itemgroups/collections_domestic.json b/data/json/itemgroups/collections_domestic.json index 428fa249a7c5e..cf4dc12db2eeb 100644 --- a/data/json/itemgroups/collections_domestic.json +++ b/data/json/itemgroups/collections_domestic.json @@ -564,6 +564,7 @@ { "item": "noodles_fast", "prob": 30 }, { "item": "ravioli", "prob": 25 }, { "item": "sauce_red", "prob": 20 }, + { "item": "gelatin_dessert_powder", "prob": 20 }, { "item": "sauce_pesto", "prob": 15 }, { "item": "bread", "prob": 14 }, { "item": "cornbread", "prob": 7 }, @@ -579,6 +580,7 @@ { "item": "can_cheese", "prob": 8 }, { "item": "yoghurt", "prob": 8 }, { "item": "pudding", "prob": 10 }, + { "item": "gelatin_dessert_processed", "prob": 10 }, { "item": "veggy_pickled", "prob": 8, "charges": 2, "container-item": "jar_glass_sealed" }, { "item": "sauerkraut", "prob": 5, "charges": 4, "container-item": "jar_glass_sealed" }, { "item": "meat_pickled", "prob": 4, "charges": 2, "container-item": "jar_glass_sealed" }, diff --git a/data/json/items/comestibles/junkfood.json b/data/json/items/comestibles/junkfood.json index ba0922582c693..4831417945a6c 100644 --- a/data/json/items/comestibles/junkfood.json +++ b/data/json/items/comestibles/junkfood.json @@ -317,6 +317,48 @@ "charges": 3, "fun": 3 }, + { + "type": "COMESTIBLE", + "id": "candy4", + "name": { "str_sp": "gummy candy" }, + "weight": "46 g", + "color": "yellow", + "spoils_in": "360 days", + "container": "bag_plastic", + "comestible_type": "FOOD", + "symbol": "%", + "healthy": -1, + "calories": 85, + "description": "A handful of colorful fruit and soda pop flavored gummy candies.", + "price": 180, + "price_postapoc": 200, + "material": [ "junk", "flesh" ], + "volume": "90 ml", + "flags": [ "EDIBLE_FROZEN" ], + "charges": 3, + "fun": 5 + }, + { + "type": "COMESTIBLE", + "id": "candy5", + "name": { "str_sp": "gummy candy" }, + "weight": "46 g", + "color": "light_green", + "spoils_in": "360 days", + "container": "bag_plastic", + "comestible_type": "FOOD", + "symbol": "%", + "healthy": -1, + "calories": 85, + "description": "A handful of colorful fruit and soda pop flavored vegan gummy candies made from agar. They have kind of a strange texture, but they're still tasty.", + "price": 180, + "price_postapoc": 200, + "material": [ "junk", "veggy" ], + "volume": "90 ml", + "flags": [ "EDIBLE_FROZEN" ], + "charges": 3, + "fun": 4 + }, { "type": "COMESTIBLE", "id": "candy3gator", @@ -1290,5 +1332,92 @@ "flags": [ "EATEN_HOT" ], "vitamins": [ [ "vitA", 3 ], [ "iron", 10 ] ], "fun": 4 + }, + { + "type": "COMESTIBLE", + "id": "gelatin_dessert_powder", + "name": "gelatin dessert powder", + "weight": "175 g", + "color": "white", + "spoils_in": "1461 days", + "container": "box_small", + "comestible_type": "FOOD", + "symbol": "%", + "quench": -8, + "calories": 400, + "description": "A small box of gelatin dessert powder. Just add water and set. Comes in a variety of flavors.", + "price": 5, + "price_postapoc": 10, + "material": [ "flesh", "junk" ], + "volume": "250ml", + "flags": [ "EATEN_COLD" ], + "fun": -2 + }, + { + "type": "COMESTIBLE", + "id": "gelatin_dessert_base", + "name": "unflavored gelatin dessert", + "weight": "232 g", + "color": "white", + "spoils_in": "7 days 12 hours", + "container": "cup_plastic", + "comestible_type": "FOOD", + "symbol": "%", + "calories": 100, + "description": "An unflavored jiggly, sugary treat made from gelatin and sugar. This would taste better with some flavor.", + "price": 210, + "price_postapoc": 250, + "material": [ "flesh", "junk" ], + "volume": "250 ml", + "phase": "solid", + "fun": 5 + }, + { + "type": "COMESTIBLE", + "id": "gelatin_dessert_processed", + "name": "processed gelatin dessert", + "description": "A jiggly, sugary treat made from gelatin and sugar. Comes in a variety of flavors. A kid favorite pre-Cataclysm.", + "fun": 20, + "copy-from": "gelatin_dessert_base" + }, + { + "type": "COMESTIBLE", + "id": "gelatin_dessert_homemade", + "name": "homemade gelatin dessert", + "color": "light_red", + "description": "A homemade jiggly, sugary treat made from gelatin and sugar flavored with fruit juice. A kid favorite pre-Cataclysm.", + "fun": 25, + "copy-from": "gelatin_dessert_base" + }, + { + "type": "COMESTIBLE", + "id": "gelatin_dessert_fruit", + "name": "fruit filled gelatin dessert", + "color": "light_red", + "description": "A jiggly, sugary treat made from gelatin and sugar flavored with fruit juice and set with fruit. A kid favorite pre-Cataclysm and a healthy treat", + "fun": 20, + "healthy": 1, + "copy-from": "gelatin_dessert_base" + }, + { + "type": "COMESTIBLE", + "id": "gelatin_dessert_vegan", + "name": "vegan gelatin dessert", + "color": "light_green", + "description": "A vegan friendly homemade jiggly, sugary treat made from agar and sugar flavored with fruit juice. A kid favorite pre-Cataclysm. They'll never know the difference.", + "fun": 20, + "material": [ "veggy", "junk" ], + "copy-from": "gelatin_dessert_base" + }, + { + "type": "COMESTIBLE", + "id": "gelatin_dessert_vegan_fruit", + "name": "fruit filled vegan gelatin dessert", + "color": "light_green", + "description": "A vegan friendly jiggly, sugary treat made from agar and sugar flavored with fruit juice and set with fruit. A kid favorite pre-Cataclysm and a healthy treat", + "fun": 15, + "material": [ "veggy", "junk" ], + "healthy": 1, + "copy-from": "gelatin_dessert_base" } ] diff --git a/data/json/items/comestibles/other.json b/data/json/items/comestibles/other.json index e17fdd5481181..7fff34d328366 100644 --- a/data/json/items/comestibles/other.json +++ b/data/json/items/comestibles/other.json @@ -188,6 +188,50 @@ "charges": 4, "fun": -10 }, + { + "type": "COMESTIBLE", + "id": "gelatin_powder", + "name": { "str_sp": "powdered gelatin" }, + "weight": "11 g", + "color": "yellow", + "container": "bag_plastic", + "comestible_type": "FOOD", + "symbol": "%", + "quench": -1, + "calories": 6, + "description": "Dried and powdered gelatin, used as a gelling agent when mixed with water.", + "price": 150, + "price_postapoc": 50, + "material": "powder", + "volume": "250 ml", + "flags": [ "EDIBLE_FROZEN" ], + "charges": 25, + "fun": -10 + }, + { + "type": "COMESTIBLE", + "id": "gelatin_fresh", + "name": { "str_sp": "fresh gelatin" }, + "conditional_names": [ + { "type": "COMPONENT_ID", "condition": "mutant", "name": { "str_sp": "abomination %s" } }, + { "type": "FLAG", "condition": "CANNIBALISM", "name": { "str_sp": "amoral %s" } }, + { "type": "FLAG", "condition": "STRICT_HUMANITARIANISM", "name": { "str_sp": "Orwell's %s" } } + ], + "weight": "25 g", + "color": "yellow", + "spoils_in": "7 days", + "comestible_type": "FOOD", + "symbol": "%", + "calories": 6, + "//": "Same as the meat it's been made from. It's additional ingredient compared to smoking, jerking, and dehydrating, so there's no incentive otherwise.", + "description": "Fresh ", + "price": 150, + "price_postapoc": 50, + "material": [ "flesh" ], + "volume": "250 ml", + "vitamins": [ [ "vitA", 10 ], [ "vitC", 15 ], [ "calcium", 2 ], [ "iron", 8 ] ], + "flags": [ "EATEN_COLD", "FREEZERBURN" ] + }, { "type": "COMESTIBLE", "id": "meal_bone_tainted", @@ -868,5 +912,44 @@ "price_postapoc": 200, "freezing_point": -459, "description": "A small packet of commercial instant coffee powder. No creamer or sweetener added." + }, + { + "type": "COMESTIBLE", + "id": "acid_soaked_hide", + "name": "acid soaked hide", + "description": "Raw hide soaking in a dilute acid solution to extract collagen. After 24 hours the solution can be strained to extract fresh gelatin.", + "weight": "500 g", + "color": "yellow", + "sealed": false, + "symbol": "~", + "calories": 9, + "quench": 6, + "fun": -10, + "price": 0, + "volume": "10L", + "price_postapoc": 10, + "phase": "liquid", + "comestible_type": "DRINK", + "flags": [ "NUTRIENT_OVERRIDE" ], + "brewable": { "time": "24 hours", "results": [ "gelatin_extracted" ] } + }, + { + "type": "COMESTIBLE", + "id": "gelatin_extracted", + "name": "extracted gelatin", + "description": "Freshly extracted gelatin in a dilute acid solution. It needs to be strained to separate the gelatin from the acid.", + "weight": "500 g", + "color": "yellow", + "sealed": false, + "symbol": "~", + "calories": 9, + "quench": 6, + "fun": -10, + "price": 0, + "volume": "10L", + "price_postapoc": 10, + "phase": "liquid", + "comestible_type": "DRINK", + "flags": [ "NUTRIENT_OVERRIDE" ] } ] diff --git a/data/json/recipes/food/dry.json b/data/json/recipes/food/dry.json index 0fedb62d4ee58..91593ee23709f 100644 --- a/data/json/recipes/food/dry.json +++ b/data/json/recipes/food/dry.json @@ -396,5 +396,19 @@ "batch_time_factors": [ 67, 5 ], "tools": [ [ [ "dehydrator", 25 ], [ "char_smoker", 25 ] ], [ [ "surface_heat", 5, "LIST" ] ] ], "components": [ [ [ "raw_lentils", 1 ] ] ] + }, + { + "type": "recipe", + "activity_level": "NO_EXERCISE", + "result": "gelatin_powder", + "category": "CC_FOOD", + "subcategory": "CSC_FOOD_DRY", + "skill_used": "cooking", + "difficulty": 2, + "time": "18 m", + "autolearn": true, + "batch_time_factors": [ 67, 5 ], + "tools": [ [ [ "dehydrator", 25 ], [ "char_smoker", 25 ] ] ], + "components": [ [ [ "gelatin_fresh", 1 ] ] ] } ] diff --git a/data/json/recipes/food/other.json b/data/json/recipes/food/other.json index f7f915c4fd061..11602abce0cf8 100644 --- a/data/json/recipes/food/other.json +++ b/data/json/recipes/food/other.json @@ -42,5 +42,202 @@ "time": "15 m", "charges": 2, "components": [ [ [ "water_clean", 1 ] ], [ [ "freeze_dried_meal", 1 ] ] ] + }, + { + "type": "recipe", + "activity_level": "NO_EXERCISE", + "result": "acid_soaked_hide", + "result_mult": 1, + "category": "CC_FOOD", + "subcategory": "CSC_FOOD_OTHER", + "skill_used": "cooking", + "difficulty": 3, + "time": "8 m", + "batch_time_factors": [ 50, 4 ], + "book_learn": [ [ "textbook_chemistry", 3 ], [ "adv_chemistry", 3 ] ], + "components": [ + [ [ "formic_acid", 10 ] ], + [ [ "water", 10 ], [ "water_clean", 10 ] ], + [ [ "raw_leather", 1 ], [ "raw_tainted_leather", 1 ], [ "raw_hleather", 1 ], [ "raw_demihumanleather", 1 ] ] + ] + }, + { + "type": "recipe", + "activity_level": "LIGHT_EXERCISE", + "result": "gelatin_fresh", + "byproducts": [ [ "formic_acid" ], [ "ruined_chunks" ] ], + "result_mult": 12, + "category": "CC_FOOD", + "subcategory": "CSC_FOOD_OTHER", + "skill_used": "cooking", + "difficulty": 2, + "time": "120 m", + "batch_time_factors": [ 90, 1 ], + "charges": 1, + "autolearn": true, + "tools": [ [ "colander_steel" ] ], + "components": [ [ [ "gelatin_extracted", 1 ] ] ] + }, + { + "type": "recipe", + "activity_level": "NO_EXERCISE", + "result": "gelatin_dessert_processed", + "category": "CC_FOOD", + "subcategory": "CSC_FOOD_OTHER", + "skill_used": "cooking", + "difficulty": 1, + "time": "60 m", + "batch_time_factors": [ 20, 1 ], + "charges": 5, + "autolearn": true, + "qualities": [ { "id": "BOIL", "level": 1 }, { "id": "CONTAIN", "level": 1 } ], + "tools": [ [ [ "surface_heat", 16, "LIST" ] ] ], + "components": [ [ [ "water", 1 ], [ "water_clean", 1 ] ], [ [ "gelatin_dessert_powder", 1 ] ] ] + }, + { + "type": "recipe", + "activity_level": "NO_EXERCISE", + "result": "gelatin_dessert_base", + "category": "CC_FOOD", + "subcategory": "CSC_FOOD_OTHER", + "skill_used": "cooking", + "difficulty": 1, + "time": "60 m", + "batch_time_factors": [ 20, 1 ], + "charges": 5, + "autolearn": true, + "qualities": [ { "id": "BOIL", "level": 1 }, { "id": "CONTAIN", "level": 1 } ], + "tools": [ [ [ "surface_heat", 16, "LIST" ] ] ], + "components": [ [ [ "water", 2 ], [ "water_clean", 2 ] ], [ [ "gelatin_powder", 10 ], [ "gelatin_fresh", 1 ] ], [ [ "sugar", 20 ] ] ] + }, + { + "type": "recipe", + "activity_level": "NO_EXERCISE", + "result": "gelatin_dessert_homemade", + "category": "CC_FOOD", + "subcategory": "CSC_FOOD_OTHER", + "skill_used": "cooking", + "difficulty": 1, + "time": "60 m", + "batch_time_factors": [ 20, 1 ], + "charges": 5, + "book_learn": [ [ "sweets_book", 1 ], [ "baking_book", 1 ], [ "mag_cooking", 3 ], [ "family_cookbook", 3 ] ], + "qualities": [ { "id": "BOIL", "level": 1 }, { "id": "CONTAIN", "level": 1 } ], + "tools": [ [ [ "surface_heat", 16, "LIST" ] ] ], + "components": [ + [ [ "water", 1 ], [ "water_clean", 1 ], [ "sweet_water", 1 ] ], + [ [ "gelatin_powder", 5 ], [ "gelatin_fresh", 1 ] ], + [ [ "sugar", 20 ] ], + [ [ "sweet_juice", 1, "LIST" ], [ "soda_pop", 1, "LIST" ] ] + ] + }, + { + "type": "recipe", + "activity_level": "NO_EXERCISE", + "result": "gelatin_dessert_fruit", + "category": "CC_FOOD", + "subcategory": "CSC_FOOD_OTHER", + "skill_used": "cooking", + "difficulty": 1, + "time": "60 m", + "batch_time_factors": [ 20, 1 ], + "charges": 5, + "book_learn": [ [ "sweets_book", 1 ], [ "baking_book", 1 ], [ "mag_cooking", 3 ], [ "family_cookbook", 3 ] ], + "qualities": [ { "id": "BOIL", "level": 1 }, { "id": "CONTAIN", "level": 1 } ], + "tools": [ [ [ "surface_heat", 16, "LIST" ] ] ], + "components": [ + [ [ "water", 1 ], [ "water_clean", 1 ], [ "sweet_water", 1 ] ], + [ [ "gelatin_powder", 5 ], [ "gelatin_fresh", 1 ] ], + [ [ "sugar", 10 ] ], + [ [ "sweet_juice", 1, "LIST" ], [ "soda_pop", 1, "LIST" ] ], + [ [ "sweet_fruit", 1, "LIST" ] ] + ] + }, + { + "type": "recipe", + "activity_level": "NO_EXERCISE", + "result": "gelatin_dessert_vegan", + "category": "CC_FOOD", + "subcategory": "CSC_FOOD_OTHER", + "skill_used": "cooking", + "difficulty": 1, + "time": "60 m", + "batch_time_factors": [ 20, 1 ], + "charges": 5, + "book_learn": [ [ "sweets_book", 1 ], [ "baking_book", 1 ], [ "mag_cooking", 1 ], [ "family_cookbook", 1 ] ], + "qualities": [ { "id": "BOIL", "level": 1 }, { "id": "CONTAIN", "level": 1 } ], + "tools": [ [ [ "surface_heat", 16, "LIST" ] ] ], + "components": [ + [ [ "water", 1 ], [ "water_clean", 1 ], [ "sweet_water", 1 ] ], + [ [ "chem_agar", 5 ] ], + [ [ "sugar", 20 ] ], + [ [ "sweet_juice", 1, "LIST" ], [ "soda_pop", 1, "LIST" ] ] + ] + }, + { + "type": "recipe", + "activity_level": "NO_EXERCISE", + "result": "gelatin_dessert_vegan_fruit", + "category": "CC_FOOD", + "subcategory": "CSC_FOOD_OTHER", + "skill_used": "cooking", + "difficulty": 1, + "time": "60 m", + "batch_time_factors": [ 20, 1 ], + "charges": 5, + "book_learn": [ [ "sweets_book", 1 ], [ "baking_book", 1 ], [ "mag_cooking", 1 ], [ "family_cookbook", 1 ] ], + "qualities": [ { "id": "BOIL", "level": 1 }, { "id": "CONTAIN", "level": 1 } ], + "tools": [ [ [ "surface_heat", 16, "LIST" ] ] ], + "components": [ + [ [ "water", 1 ], [ "water_clean", 1 ], [ "sweet_water", 1 ] ], + [ [ "chem_agar", 5 ] ], + [ [ "sugar", 20 ] ], + [ [ "sweet_juice", 1, "LIST" ], [ "soda_pop", 1, "LIST" ] ], + [ [ "sweet_fruit", 1, "LIST" ] ] + ] + }, + { + "type": "recipe", + "activity_level": "NO_EXERCISE", + "result": "candy4", + "category": "CC_FOOD", + "subcategory": "CSC_FOOD_OTHER", + "skill_used": "cooking", + "difficulty": 2, + "time": "60 m", + "batch_time_factors": [ 20, 1 ], + "charges": 12, + "book_learn": [ [ "sweets_book", 2 ], [ "baking_book", 2 ], [ "family_cookbook", 2 ] ], + "qualities": [ { "id": "BOIL", "level": 1 } ], + "tools": [ [ [ "surface_heat", 16, "LIST" ] ], [ [ "mold_plastic", 1 ] ] ], + "components": [ + [ [ "water", 1 ], [ "water_clean", 1 ], [ "sweet_water", 1 ] ], + [ [ "beet_syrup", 1 ] ], + [ [ "gelatin_powder", 25 ], [ "gelatin_fresh", 2 ] ], + [ [ "sugar", 50 ] ], + [ [ "sweet_juice", 1, "LIST" ], [ "soda_pop", 1, "LIST" ] ] + ] + }, + { + "type": "recipe", + "activity_level": "NO_EXERCISE", + "result": "candy5", + "category": "CC_FOOD", + "subcategory": "CSC_FOOD_OTHER", + "skill_used": "cooking", + "difficulty": 2, + "time": "60 m", + "batch_time_factors": [ 20, 1 ], + "charges": 12, + "book_learn": [ [ "sweets_book", 2 ], [ "baking_book", 2 ], [ "family_cookbook", 2 ] ], + "qualities": [ { "id": "BOIL", "level": 1 } ], + "tools": [ [ [ "surface_heat", 16, "LIST" ] ], [ [ "mold_plastic", 1 ] ] ], + "components": [ + [ [ "water", 1 ], [ "water_clean", 1 ], [ "sweet_water", 1 ] ], + [ [ "beet_syrup", 1 ] ], + [ [ "chem_agar", 25 ] ], + [ [ "sugar", 50 ] ], + [ [ "sweet_juice", 1, "LIST" ], [ "soda_pop", 1, "LIST" ] ] + ] } ] diff --git a/data/json/recipes/recipe_food.json b/data/json/recipes/recipe_food.json index 7a36e0ed04bfc..607b12345d3d4 100644 --- a/data/json/recipes/recipe_food.json +++ b/data/json/recipes/recipe_food.json @@ -2284,7 +2284,7 @@ "qualities": [ { "id": "COOK", "level": 2 } ], "tools": [ [ [ "surface_heat", 7, "LIST" ] ] ], "components": [ - [ [ "broth_bone", 1 ] ], + [ [ "gelatin_fresh", 1 ], [ "gelatin_powder", 25 ], [ "chem_agar", 25 ] ], [ [ "meat_red", 1, "LIST" ], [ "meat_cooked", 1 ], @@ -2315,7 +2315,11 @@ "batch_time_factors": [ 50, 5 ], "qualities": [ { "id": "COOK", "level": 2 } ], "tools": [ [ [ "surface_heat", 7, "LIST" ] ] ], - "components": [ [ [ "broth_bone", 1 ] ], [ [ "veggy_any", 4, "LIST" ] ], [ [ "water_clean", 2 ], [ "water", 2 ] ] ] + "components": [ + [ [ "gelatin_fresh", 1 ], [ "gelatin_powder", 25 ], [ "chem_agar", 25 ] ], + [ [ "veggy_any", 4, "LIST" ] ], + [ [ "water_clean", 1 ], [ "water", 1 ] ] + ] }, { "type": "recipe", @@ -2470,6 +2474,7 @@ "type": "recipe", "activity_level": "NO_EXERCISE", "result": "broth_bone", + "byproducts": [ [ "gelatin_fresh" ] ], "charges": 1, "category": "CC_FOOD", "subcategory": "CSC_FOOD_OTHER", diff --git a/data/json/requirements/cooking_components.json b/data/json/requirements/cooking_components.json index 296049cfb5ae5..3068d9ff991ba 100644 --- a/data/json/requirements/cooking_components.json +++ b/data/json/requirements/cooking_components.json @@ -831,5 +831,38 @@ [ "mixed_alcohol_weak", 1 ] ] ] + }, + { + "id": "soda_pop", + "type": "requirement", + "//": "Soda's and such. Anything carbonated that isn't alcholic or an energy drink.", + "components": [ + [ + [ "cola", 1 ], + [ "creamsoda", 1 ], + [ "crispycran", 1 ], + [ "lemonlime", 1 ], + [ "orangesoda", 1 ], + [ "purple_drink", 1 ], + [ "rootbeer", 1 ], + [ "spezi", 1 ] + ] + ] + }, + { + "id": "sweet_juice", + "type": "requirement", + "//": "Non-carbonated, sweet fruit based drinks.", + "components": [ + [ + [ "oj", 1 ], + [ "lemonade", 1 ], + [ "apple_cider", 1 ], + [ "cranberry_juice", 1 ], + [ "juice", 1 ], + [ "juice_pasteurized", 1 ], + [ "kompot", 1 ] + ] + ] } ] From 1c1866b96727bb324fae2906f34f4eb9f6edc180 Mon Sep 17 00:00:00 2001 From: Xaleth Date: Thu, 18 Feb 2021 01:50:42 -0600 Subject: [PATCH 227/453] Content: bread in a can (#45680) --- data/json/itemgroups/Food/food.json | 2 ++ data/json/itemgroups/food_service.json | 2 +- data/json/items/comestibles/bread.json | 10 +++++----- data/json/items/comestibles/wheat.json | 6 +++--- data/json/items/containers.json | 4 ++-- data/json/recipes/food/bread.json | 11 ++++++----- 6 files changed, 19 insertions(+), 16 deletions(-) diff --git a/data/json/itemgroups/Food/food.json b/data/json/itemgroups/Food/food.json index a3b1cfab1acbc..17d8462984bb5 100644 --- a/data/json/itemgroups/Food/food.json +++ b/data/json/itemgroups/Food/food.json @@ -134,6 +134,7 @@ { "item": "apple_canned", "prob": 1 }, { "item": "can_cheese", "prob": 1 }, { "item": "fish_canned", "prob": 1 }, + { "item": "brown_bread", "prob": 1 }, { "item": "can_spam", "prob": 1 }, { "item": "can_sardine", "prob": 1 }, { "item": "ravioli", "prob": 1 }, @@ -189,6 +190,7 @@ { "item": "can_chowder", "prob": 35 }, { "item": "can_herring", "prob": 30 }, { "item": "can_chicken", "prob": 40 }, + { "item": "brown_bread", "prob": 20 }, { "item": "broth", "prob": 15 }, { "item": "crackers", "prob": 10 }, { "item": "oyster_crackers", "prob": 10 }, diff --git a/data/json/itemgroups/food_service.json b/data/json/itemgroups/food_service.json index 6c53e003c029d..97a77205dea06 100644 --- a/data/json/itemgroups/food_service.json +++ b/data/json/itemgroups/food_service.json @@ -661,7 +661,7 @@ "subtype": "distribution", "entries": [ { "item": "bread", "prob": 65 }, - { "item": "brown_bread", "prob": 50 }, + { "item": "brown_bread", "prob": 50, "container-item": "bag_plastic" }, { "item": "cake2", "prob": 10 }, { "item": "cake3", "prob": 10 }, { "item": "cornbread", "prob": 35 }, diff --git a/data/json/items/comestibles/bread.json b/data/json/items/comestibles/bread.json index d7f66d42cba2d..89e5844a82cd0 100644 --- a/data/json/items/comestibles/bread.json +++ b/data/json/items/comestibles/bread.json @@ -290,20 +290,20 @@ "weight": "45 g", "color": "brown", "spoils_in": "10 days", - "container": "bag_plastic", + "container": "can_medium", "comestible_type": "FOOD", "symbol": "%", "healthy": 1, - "calories": 74, + "calories": 130, "description": "A sweet bread, like cake.", "price": "272 cent", - "price_postapoc": "4 USD", + "price_postapoc": "2 USD", "material": [ "wheat" ], - "volume": "48 ml", + "volume": "480 ml", "charges": 10, "flags": [ "EATEN_HOT", "EATEN_COLD" ], "fun": 3, - "vitamins": [ [ "calcium", 2 ], [ "iron", 6 ] ] + "vitamins": [ [ "calcium", 4 ], [ "iron", 4 ] ] }, { "type": "COMESTIBLE", diff --git a/data/json/items/comestibles/wheat.json b/data/json/items/comestibles/wheat.json index db88bd2b7d909..5e3af87f6e18a 100644 --- a/data/json/items/comestibles/wheat.json +++ b/data/json/items/comestibles/wheat.json @@ -147,10 +147,10 @@ "type": "COMESTIBLE", "id": "bread_flour", "name": { "str_sp": "bread flour" }, - "weight": "13 g", + "weight": "60 g", "color": "white", "spoils_in": "360 days", - "container": "bag_paper_powder_small", + "container": "bag_paper_powder", "comestible_type": "FOOD", "symbol": "%", "quench": -1, @@ -159,7 +159,7 @@ "price": "200 cent", "price_postapoc": "95 cent", "material": [ "wheat", "powder" ], - "volume": "250 ml", + "volume": "2400 ml", "flags": [ "EDIBLE_FROZEN", "RAW" ], "charges": 20, "vitamins": [ [ "iron", 4 ] ], diff --git a/data/json/items/containers.json b/data/json/items/containers.json index 386e968bb0f87..6e7b00783a66d 100644 --- a/data/json/items/containers.json +++ b/data/json/items/containers.json @@ -162,7 +162,7 @@ "flags": [ "TRADER_AVOID" ] }, { - "id": "bag_paper_powder_small", + "id": "bag_paper_powder", "type": "GENERIC", "category": "container", "name": { "str": "small powder paper bag" }, @@ -177,7 +177,7 @@ { "pocket_type": "CONTAINER", "watertight": false, - "max_contains_volume": "2 L", + "max_contains_volume": "2500 ml", "max_contains_weight": "2 kg", "moves": 200 } diff --git a/data/json/recipes/food/bread.json b/data/json/recipes/food/bread.json index c9996e42485f4..77e84cf6bf0eb 100644 --- a/data/json/recipes/food/bread.json +++ b/data/json/recipes/food/bread.json @@ -33,17 +33,18 @@ "skill_used": "cooking", "difficulty": 3, "charges": 10, - "time": "30 m", + "time": "1 h 30 m", "batch_time_factors": [ 50, 5 ], + "autolearn": false, "book_learn": [ [ "family_cookbook", 1 ], [ "baking_book", 2 ], [ "cookbook", 2 ], [ "cookbook_daintydishes", 2 ] ], "qualities": [ { "id": "COOK", "level": 3 } ], "tools": [ [ [ "surface_heat", 8, "LIST" ] ] ], "components": [ [ [ "bread_flour", 1 ] ], - [ [ "flour", 1 ] ], - [ [ "cornmeal", 1 ] ], - [ [ "molasses", 1 ] ], - [ [ "water", 1 ] ], + [ [ "flour", 5 ] ], + [ [ "cornmeal", 5 ] ], + [ [ "molasses", 2 ] ], + [ [ "water", 1 ], [ "water_clean", 1 ] ], [ [ "salt", 1 ] ] ], "//": "Later: this needs baking soda. Also possibility of rewrite to use portions of components' charges." From d5b21b7da0012565ac8ee00400045bfa03b65b47 Mon Sep 17 00:00:00 2001 From: El-Jekozo <72350516+El-Jekozo@users.noreply.github.com> Date: Thu, 18 Feb 2021 09:51:50 +0200 Subject: [PATCH 228/453] New random mission (#44999) --- data/json/npcs/TALK_COMMON_MISSION.json | 14 ++++++++ data/json/npcs/missiondef.json | 48 +++++++++++++++++++++++++ 2 files changed, 62 insertions(+) diff --git a/data/json/npcs/TALK_COMMON_MISSION.json b/data/json/npcs/TALK_COMMON_MISSION.json index 4bcee75e8b9cb..f60741645f8b4 100644 --- a/data/json/npcs/TALK_COMMON_MISSION.json +++ b/data/json/npcs/TALK_COMMON_MISSION.json @@ -324,5 +324,19 @@ { "text": "Thank you.", "topic": "TALK_NONE", "effect": "clear_mission" }, { "text": "Thanks, bye.", "topic": "TALK_DONE", "effect": "clear_mission" } ] + }, + { + "//": "MISSION_PYROMANIAC mission set this topic as starting topic for mission giver.", + "type": "talk_topic", + "id": "MISSION_PYROMANIAC", + "dynamic_line": "Are we there yet, ? I can't wait to burn that building!", + "responses": [ + { + "text": "We're here. Let's do it!", + "topic": "TALK_MISSION_INQUIRE", + "condition": { "and": [ "mission_complete", { "u_has_items": { "item": "gasoline", "count": 200 } } ] } + }, + { "text": "Be patient, , we're getting there soon.", "topic": "TALK_DONE" } + ] } ] diff --git a/data/json/npcs/missiondef.json b/data/json/npcs/missiondef.json index 0ad333b4a54fc..109e4a3df41a2 100644 --- a/data/json/npcs/missiondef.json +++ b/data/json/npcs/missiondef.json @@ -817,5 +817,53 @@ "success_lie": "OK, then hand them over.", "failure": "Well, that's a shame." } + }, + { + "id": "MISSION_PYROMANIAC", + "type": "mission_definition", + "name": { "str": "Angry pyromaniac" }, + "goal": "MGOAL_GO_TO", + "difficulty": 0, + "value": 0, + "//": "NPC will ask player to burn tagged house. Will follow player after accepting mission.", + "//2": "Change first topic to do proper checks. MGOAL_GO_TO to check if player stands on tagged tile.", + "//3": "At the end of the mission, will place fire on tagged tile and NPC will join player faction.", + "has_generic_rewards": false, + "start": { + "effect": [ "follow_only", { "npc_first_topic": "MISSION_PYROMANIAC" } ], + "assign_mission_target": { + "om_terrain": "house", + "om_terrain_replace": "forest", + "om_terrain_match_type": "PREFIX", + "search_range": 75, + "random": true, + "z": 0 + } + }, + "end": { + "effect": [ "follow", { "u_consume_item": "gasoline", "count": 200 }, { "mapgen_update": "MISSION_PYROMANIAC_BURN" } ] + }, + "origins": [ "ORIGIN_OPENER_NPC" ], + "dialogue": { + "describe": "Oh man, I want to burn it so bad…", + "offer": "I'm so infuriated! I've got an enemy that ruined my life, and now I want to get revenge! I don't care about , I just want to burn his house! Would you help me, ?", + "accepted": "Good. Let's go to his house and burn it down! Oh, by the way, could you bring gasoline with you, ? I was so angry I forgot to bring it with me…", + "rejected": "Seriously? It's such an easy job…", + "advice": "Maybe we can find some gasoline at gas station.", + "inquire": "Are you ready, ?", + "success": "Sweet, sweet revenge! Ah, smells so nice! Feels like the smell of napalm in the morning! All his stuff, and probably even that , will burn to ashes in a matter of minutes. You helped me get my revenge, so I'll follow you to the end, !", + "success_lie": "What?! You liar!", + "failure": "Wow, you failed? How…" + } + }, + { + "//": "For MISSION_PYROMANIAC. Will spawn fire on tile where PC is standing.", + "type": "mapgen", + "update_mapgen_id": "MISSION_PYROMANIAC_BURN", + "method": "json", + "object": { + "place_liquids": [ { "liquid": "gasoline", "x": [ 5, 20 ], "y": [ 5, 20 ], "amount": 5, "repeat": 40 } ], + "place_fields": [ { "field": "fd_fire", "x": [ 5, 20 ], "y": [ 5, 20 ], "repeat": 40 } ] + } } ] From 69d09cc6941eab9b045da2397fb3c9c0c7a622e0 Mon Sep 17 00:00:00 2001 From: RobertoVGoulart Date: Thu, 18 Feb 2021 04:53:41 -0300 Subject: [PATCH 229/453] Mycus fruit Juice (#44952) --- data/json/items/comestibles/drink.json | 25 +++++++++++++++++++++++++ data/json/recipes/recipe_food.json | 14 ++++++++++++++ 2 files changed, 39 insertions(+) diff --git a/data/json/items/comestibles/drink.json b/data/json/items/comestibles/drink.json index 534a4b82288d4..86ac6d0e05ebd 100644 --- a/data/json/items/comestibles/drink.json +++ b/data/json/items/comestibles/drink.json @@ -862,6 +862,31 @@ "vitamins": [ [ "vitC", 50 ], [ "calcium", 3 ] ], "fun": 3 }, + { + "type": "COMESTIBLE", + "id": "mycus_juice", + "name": "mycus juice", + "weight": "263 g", + "color": "light_gray", + "use_action": [ "MYCUS" ], + "spoils_in": "5 days", + "container": "bottle_plastic", + "comestible_type": "DRINK", + "symbol": "~", + "quench": 100, + "healthy": 2, + "calories": 462, + "description": "Freshly-squeezed from the fruit of the mycus.", + "price": 0, + "price_postapoc": 0, + "material": [ "water", "mushroom" ], + "primary_material": "water", + "volume": "250 ml", + "phase": "liquid", + "flags": [ "EATEN_COLD", "MYCUS_OK", "NUTRIENT_OVERRIDE" ], + "vitamins": [ [ "vitA", 16 ], [ "vitB", 16 ], [ "vitC", 20 ], [ "calcium", 20 ], [ "iron", 16 ] ], + "fun": 30 + }, { "type": "COMESTIBLE", "id": "rootbeer", diff --git a/data/json/recipes/recipe_food.json b/data/json/recipes/recipe_food.json index 607b12345d3d4..197af978fa36f 100644 --- a/data/json/recipes/recipe_food.json +++ b/data/json/recipes/recipe_food.json @@ -7419,6 +7419,20 @@ ] ] }, + { + "type": "recipe", + "activity_level": "LIGHT_EXERCISE", + "result": "mycus_juice", + "category": "CC_FOOD", + "subcategory": "CSC_FOOD_DRINKS", + "skill_used": "cooking", + "difficulty": 1, + "time": "5 m", + "autolearn": true, + "qualities": [ { "id": "HAMMER", "level": 1 }, { "id": "CONTAIN", "level": 1 } ], + "tools": [ [ [ "rag", -1 ] ] ], + "components": [ [ [ "mycus_fruit", 1 ] ], [ [ "water", 1 ], [ "water_clean", 1 ] ] ] + }, { "type": "recipe", "activity_level": "NO_EXERCISE", From f1b674d8a79aebaab0adac94ce5b3b4c640de345 Mon Sep 17 00:00:00 2001 From: Zukulini Date: Thu, 18 Feb 2021 01:56:41 -0600 Subject: [PATCH 230/453] Milleable corn (#46254) --- data/json/itemgroups/Food/food.json | 2 + data/json/items/comestibles/raw_veggy.json | 46 ++++++++++-- data/json/items/comestibles/veggy_dishes.json | 46 ++++++++++-- data/json/recipes/food/dry.json | 31 ++++++++ data/json/recipes/food/pasta.json | 2 + data/json/recipes/other/other.json | 4 +- data/json/recipes/recipe_food.json | 72 ++++++++++++++++--- .../json/requirements/cooking_components.json | 14 +++- 8 files changed, 193 insertions(+), 24 deletions(-) diff --git a/data/json/itemgroups/Food/food.json b/data/json/itemgroups/Food/food.json index 17d8462984bb5..8ed9a6d47d3d8 100644 --- a/data/json/itemgroups/Food/food.json +++ b/data/json/itemgroups/Food/food.json @@ -39,6 +39,7 @@ { "item": "dry_meat", "prob": 10 }, { "item": "dry_fish", "prob": 10 }, { "item": "dry_veggy", "prob": 10 }, + { "item": "dry_corn", "prob": 1 }, { "item": "dry_fruit", "prob": 10 }, { "item": "oatmeal", "prob": 40 }, { "item": "fruit_leather", "prob": 15 }, @@ -221,6 +222,7 @@ { "item": "dry_meat", "prob": 10 }, { "item": "dry_fish", "prob": 10 }, { "item": "dry_veggy", "prob": 10 }, + { "item": "dry_corn", "prob": 1 }, { "item": "dry_fruit", "prob": 10 }, { "item": "oatmeal", "prob": 40 }, { "item": "toastem", "prob": 30 }, diff --git a/data/json/items/comestibles/raw_veggy.json b/data/json/items/comestibles/raw_veggy.json index b19ded32d195f..cb384ab5531e4 100644 --- a/data/json/items/comestibles/raw_veggy.json +++ b/data/json/items/comestibles/raw_veggy.json @@ -209,24 +209,62 @@ { "type": "COMESTIBLE", "id": "corn", - "name": { "str_sp": "corn" }, - "weight": "153 g", + "name": { "str": "corn cob" }, + "weight": "690 g", "color": "light_green", "spoils_in": "5 days", "comestible_type": "FOOD", "symbol": "%", "healthy": 1, "calories": 132, - "description": "Delicious golden kernels.", + "description": "A corn cob full of delicious golden kernels. You can eat them on the cob or shell it for cooking.", "price": 170, "//": "Thinking this is a single ear here.", "price_postapoc": 50, "material": [ "veggy" ], "volume": "750 ml", + "flags": [ "EATEN_HOT", "RAW" ], + "vitamins": [ [ "vitA", 2 ], [ "vitC", 12 ], [ "iron", 4 ] ], + "use_action": { "type": "transform", "target": "empty_corn_cob", "moves": 500 } + }, + { + "type": "COMESTIBLE", + "id": "corn_kernels", + "name": { "str_sp": "corn kernels" }, + "weight": "210 g", + "color": "yellow", + "spoils_in": "5 days", + "comestible_type": "FOOD", + "symbol": "%", + "healthy": 1, + "calories": 132, + "description": "Delicious golden kernels.", + "price": 200, + "price_postapoc": 60, + "material": [ "veggy" ], + "volume": "285 ml", "flags": [ "EATEN_HOT", "SMOKABLE", "RAW" ], - "smoking_result": "dry_veggy", + "smoking_result": "dry_corn", "vitamins": [ [ "vitA", 2 ], [ "vitC", 12 ], [ "iron", 4 ] ] }, + { + "type": "COMESTIBLE", + "id": "empty_corn_cob", + "name": { "str_sp": "empty corn cob" }, + "weight": "480 g", + "color": "yellow", + "spoils_in": "5 days", + "comestible_type": "FOOD", + "symbol": "%", + "healthy": 1, + "description": "An empty corn cob. It may seem useless, but it can be used to make stock, a delicious jelly, or as fuel.", + "price": 1, + "price_postapoc": 1, + "material": [ "veggy" ], + "volume": "465 ml", + "fun": -8, + "flags": [ "RAW" ] + }, { "type": "COMESTIBLE", "id": "cotton_boll", diff --git a/data/json/items/comestibles/veggy_dishes.json b/data/json/items/comestibles/veggy_dishes.json index adc2170fc9dc7..0205681ab45c4 100644 --- a/data/json/items/comestibles/veggy_dishes.json +++ b/data/json/items/comestibles/veggy_dishes.json @@ -227,20 +227,20 @@ "type": "COMESTIBLE", "id": "cornmeal", "name": { "str_sp": "cornmeal" }, - "weight": "19 g", + "weight": "60 g", "color": "yellow", "spoils_in": "360 days", "container": "box_small", "comestible_type": "FOOD", "symbol": "%", "quench": -1, - "calories": 47, - "vitamins": [ [ "iron", 3 ] ], + "calories": 44, + "vitamins": [ [ "vitA", 2 ], [ "vitC", 12 ], [ "iron", 4 ] ], "description": "This yellow cornmeal is useful for baking.", "price": 450, "price_postapoc": 25, "material": [ "veggy", "powder" ], - "volume": "250 ml", + "volume": "1070 ml", "flags": [ "EDIBLE_FROZEN" ], "charges": 10, "fun": -5 @@ -667,6 +667,27 @@ "flags": [ "EDIBLE_FROZEN" ], "charges": 2 }, + { + "type": "COMESTIBLE", + "id": "dry_corn", + "name": { "str_sp": "dehydrated corn kernels" }, + "weight": "180 g", + "color": "yellow", + "comestible_type": "FOOD", + "symbol": "%", + "quench": -10, + "healthy": 1, + "calories": 132, + "description": "A handful of dried corn kernels.", + "price": 60, + "price_postapoc": 50, + "material": [ "veggy" ], + "milling": { "into": "cornmeal", "conversion_rate": 3 }, + "volume": "255 ml", + "flags": [ "EDIBLE_FROZEN", "RAW" ], + "vitamins": [ [ "vitA", 2 ], [ "vitC", 12 ], [ "iron", 4 ] ], + "fun": -10 + }, { "type": "COMESTIBLE", "id": "rehydrated_veggy", @@ -680,6 +701,23 @@ "delete": { "flags": [ "RAW" ] }, "fun": 2 }, + { + "type": "COMESTIBLE", + "id": "rehydrated_corn_kernels", + "name": { "str_sp": "rehydrated corn kernels" }, + "copy-from": "veggy", + "weight": "70 g", + "color": "yellow", + "spoils_in": "1 day", + "description": "Reconstituted corn kernels; much more enjoyable to eat now that they have been rehydrated.", + "price": 900, + "price_postapoc": 50, + "smoking_result": "dry_corn", + "volume": "95 ml", + "delete": { "flags": [ "RAW" ] }, + "vitamins": [ [ "vitA", 2 ], [ "vitC", 12 ], [ "iron", 4 ] ], + "fun": 2 + }, { "type": "COMESTIBLE", "id": "veggy_salad", diff --git a/data/json/recipes/food/dry.json b/data/json/recipes/food/dry.json index 91593ee23709f..7d18e8d7061fb 100644 --- a/data/json/recipes/food/dry.json +++ b/data/json/recipes/food/dry.json @@ -240,6 +240,37 @@ [ [ "veggy_any_fresh_uncooked", 1, "LIST" ], [ "dandelion_cooked", 1 ], [ "burdock_cooked", 1 ], [ "wild_herbs", 40 ] ] ] }, + { + "type": "recipe", + "activity_level": "NO_EXERCISE", + "result": "dry_corn", + "charges": 1, + "category": "CC_FOOD", + "subcategory": "CSC_FOOD_DRY", + "skill_used": "cooking", + "difficulty": 2, + "time": "18 m", + "autolearn": true, + "batch_time_factors": [ 67, 5 ], + "tools": [ [ [ "dehydrator", 25 ], [ "char_smoker", 25 ] ] ], + "components": [ [ [ "corn_kernels", 1 ] ] ] + }, + { + "type": "recipe", + "activity_level": "NO_EXERCISE", + "result": "dry_corn", + "charges": 1, + "category": "CC_FOOD", + "id_suffix": "frozen_ingredients", + "subcategory": "CSC_FOOD_DRY", + "skill_used": "cooking", + "difficulty": 2, + "time": "20 m", + "autolearn": true, + "batch_time_factors": [ 67, 5 ], + "tools": [ [ [ "dehydrator", 25 ], [ "char_smoker", 25 ] ], [ [ "surface_heat", 5, "LIST" ] ] ], + "components": [ [ [ "corn_kernels", 1 ] ] ] + }, { "result": "dry_veggy_tainted", "charges": 1, diff --git a/data/json/recipes/food/pasta.json b/data/json/recipes/food/pasta.json index 2ed02574899ee..bdf3c328df838 100644 --- a/data/json/recipes/food/pasta.json +++ b/data/json/recipes/food/pasta.json @@ -112,7 +112,9 @@ [ "veggy", 2 ], [ "veggy_wild", 2 ], [ "rehydrated_veggy", 2 ], + [ "rehydrated_corn_kernels", 2 ], [ "dry_veggy", 2 ], + [ "dry_corn", 2 ], [ "mushroom", 2 ], [ "mushroom_cooked", 2 ], [ "morel_cooked", 2 ], diff --git a/data/json/recipes/other/other.json b/data/json/recipes/other/other.json index f0ed6b762dccb..5db4e4f6aad83 100644 --- a/data/json/recipes/other/other.json +++ b/data/json/recipes/other/other.json @@ -15,8 +15,8 @@ [ "fish", 1 ], [ "dry_meat", 1 ], [ "dry_fish", 1 ], - [ "corn", 1 ], - [ "irradiated_corn", 1 ], + [ "corn_kernels", 1 ], + [ "rehydrated_corn_kernels", 1 ], [ "irradiated_carrot", 1 ], [ "carrot", 1 ], [ "bread", 1 ], diff --git a/data/json/recipes/recipe_food.json b/data/json/recipes/recipe_food.json index 197af978fa36f..e032cfc4a730c 100644 --- a/data/json/recipes/recipe_food.json +++ b/data/json/recipes/recipe_food.json @@ -486,6 +486,19 @@ "qualities": [ { "id": "CONTAIN", "level": 1 } ], "components": [ [ [ "dry_veggy", 1 ] ], [ [ "water_clean", 1 ] ] ] }, + { + "type": "recipe", + "activity_level": "NO_EXERCISE", + "result": "rehydrated_corn_kernels", + "category": "CC_FOOD", + "subcategory": "CSC_FOOD_VEGGI", + "skill_used": "cooking", + "time": "3 m", + "autolearn": true, + "flags": [ "BLIND_HARD" ], + "qualities": [ { "id": "CONTAIN", "level": 1 } ], + "components": [ [ [ "dry_corn", 1 ] ], [ [ "water_clean", 1 ] ] ] + }, { "type": "recipe", "activity_level": "NO_EXERCISE", @@ -678,7 +691,9 @@ [ "irradiated_celery", 3 ], [ "veggy_wild", 3 ], [ "veggy", 3 ], - [ "rehydrated_veggy", 3 ] + [ "rehydrated_veggy", 3 ], + [ "rehydrated_corn_kernels", 3 ], + [ "corn_kernels", 3 ] ], [ [ "lettuce", 2 ], @@ -833,7 +848,9 @@ [ "irradiated_celery", 3 ], [ "veggy_wild", 3 ], [ "veggy", 3 ], - [ "rehydrated_veggy", 3 ] + [ "rehydrated_veggy", 3 ], + [ "rehydrated_corn_kernels", 3 ], + [ "corn_kernels", 3 ] ], [ [ "soysauce", 1 ], [ "horseradish", 1 ], [ "salt", 1 ], [ "seasoning_salt", 1 ] ] ] @@ -2397,6 +2414,7 @@ [ [ "jerky", 2 ], [ "dry_meat", 2 ], [ "meat_smoked", 2 ], [ "dry_fish", 2 ], [ "fish_smoked", 2 ] ], [ [ "dry_veggy", 2 ], + [ "dry_corn", 2 ], [ "dry_fruit", 2 ], [ "dry_mushroom", 2 ], [ "juice_pulp", 4 ], @@ -3989,8 +4007,11 @@ [ "mustard_powder", 20 ], [ "garlic_clove", 6 ], [ "rehydrated_veggy", 1 ], + [ "rehydrated_corn_kernels", 1 ], + [ "corn_kernels", 1 ], [ "dry_mushroom", 1 ], - [ "dry_veggy", 1 ] + [ "dry_veggy", 1 ], + [ "dry_corn", 1 ] ] ] }, @@ -4113,6 +4134,9 @@ [ "veggy_salted", 2 ], [ "rehydrated_veggy", 2 ], [ "dry_veggy", 2 ], + [ "rehydrated_corn_kernels", 2 ], + [ "dry_corn", 2 ], + [ "corn_kernels", 2 ], [ "mushroom", 2 ], [ "dry_mushroom", 2 ], [ "morel_cooked", 2 ], @@ -4149,6 +4173,9 @@ [ "veggy_salted", 2 ], [ "rehydrated_veggy", 2 ], [ "dry_veggy", 2 ], + [ "rehydrated_corn_kernels", 2 ], + [ "dry_corn", 2 ], + [ "corn_kernels", 2 ], [ "mushroom", 2 ], [ "dry_mushroom", 2 ], [ "morel_cooked", 2 ], @@ -4186,11 +4213,14 @@ [ "veggy_wild", 2 ], [ "veggy_salted", 2 ], [ "rehydrated_veggy", 2 ], + [ "rehydrated_corn_kernels", 2 ], + [ "corn_kernels", 2 ], [ "mushroom", 2 ], [ "dry_mushroom", 2 ], [ "morel_cooked", 2 ], [ "mushroom_cooked", 2 ], - [ "dry_veggy", 2 ] + [ "dry_veggy", 2 ], + [ "dry_corn", 2 ] ], [ [ "tomato", 1 ], [ "irradiated_tomato", 1 ], [ "can_tomato", 1 ] ], [ [ "meat_red", 1, "LIST" ], [ "dry_meat", 1 ], [ "can_chicken", 1 ] ], @@ -4220,7 +4250,8 @@ [ "tofu", 2 ], [ "dry_tofu", 2 ], [ "mushroom_cooked", 2 ], - [ "dry_veggy", 2 ] + [ "dry_veggy", 2 ], + [ "dry_corn", 2 ] ], [ [ "sauce_pesto", 1 ], @@ -4268,7 +4299,8 @@ [ "dry_mushroom", 2 ], [ "morel_cooked", 2 ], [ "mushroom_cooked", 2 ], - [ "dry_veggy", 2 ] + [ "dry_veggy", 2 ], + [ "dry_corn", 2 ] ], [ [ "cheese", 2 ], [ "can_cheese", 2 ], [ "cheese_hard", 2 ] ], [ [ "sauce_pesto", 1 ], [ "sauce_red", 1 ], [ "seasoning_italian", 5 ], [ "wild_herbs", 10 ] ], @@ -4409,7 +4441,8 @@ [ "coffee_syrup", 5 ], [ "cola", 6 ], [ "con_milk", 1 ], - [ "corn", 3 ], + [ "corn_kernels", 3 ], + [ "rehydrated_corn_kernels", 3 ], [ "honey_bottled", 1 ], [ "honey_glassed", 1 ], [ "honeycomb", 1 ], @@ -4630,7 +4663,7 @@ "autolearn": true, "batch_time_factors": [ 83, 3 ], "tools": [ [ [ "surface_heat", 5, "LIST" ] ], [ [ "rock_quern", -1 ], [ "clay_quern", -1 ] ] ], - "components": [ [ [ "corn", 1 ], [ "irradiated_corn", 1 ], [ "kernels", 1 ] ] ] + "components": [ [ [ "dry_corn", 1 ], [ "kernels", 1 ] ] ] }, { "type": "recipe", @@ -4913,6 +4946,8 @@ [ "irradiated_tomato", 1 ], [ "irradiated_broccoli", 1 ], [ "rehydrated_veggy", 1 ], + [ "rehydrated_corn_kernels", 1 ], + [ "corn_kernels", 1 ], [ "morel_cooked", 1 ], [ "mushroom_cooked", 1 ], [ "sauerkraut_onions", 1 ], @@ -5833,6 +5868,8 @@ [ "irradiated_tomato", 1 ], [ "irradiated_broccoli", 1 ], [ "rehydrated_veggy", 1 ], + [ "rehydrated_corn_kernels", 1 ], + [ "corn_kernels", 1 ], [ "morel_cooked", 1 ], [ "mushroom_cooked", 1 ], [ "sauerkraut_onions", 1 ], @@ -6419,7 +6456,20 @@ "autolearn": true, "batch_time_factors": [ 83, 3 ], "tools": [ [ [ "food_processor", 20 ] ] ], - "components": [ [ [ "corn", 1 ], [ "irradiated_corn", 1 ], [ "kernels", 1 ] ] ] + "components": [ [ [ "dry_corn", 1 ] ] ] + }, + { + "result": "corn_kernels", + "type": "recipe", + "activity_level": "LIGHT_EXERCISE", + "category": "CC_FOOD", + "subcategory": "CSC_FOOD_OTHER", + "byproducts": [ [ "empty_corn_cob", 1 ] ], + "skill_used": "cooking", + "time": "20 s", + "autolearn": true, + "qualities": [ { "id": "CUT", "level": 1 } ], + "components": [ [ [ "corn", 1 ], [ "irradiated_corn", 1 ] ] ] }, { "result": "flour", @@ -6517,7 +6567,7 @@ "components": [ [ [ "can_corn", 1 ], - [ "corn", 1 ], + [ "corn_kernels", 1 ], [ "oats", 1 ], [ "buckwheat", 1 ], [ "wheat", 1 ], @@ -6755,7 +6805,7 @@ "autolearn": true, "batch_time_factors": [ 83, 3 ], "tools": [ [ [ "surface_heat", 5, "LIST" ] ], [ [ "mortar_pestle", -1 ] ] ], - "components": [ [ [ "corn", 1 ], [ "irradiated_corn", 1 ], [ "kernels", 1 ] ] ] + "components": [ [ [ "dry_corn", 1 ] ] ] }, { "type": "recipe", diff --git a/data/json/requirements/cooking_components.json b/data/json/requirements/cooking_components.json index 3068d9ff991ba..62f1e3568fd05 100644 --- a/data/json/requirements/cooking_components.json +++ b/data/json/requirements/cooking_components.json @@ -382,6 +382,8 @@ [ "can_corn", 1 ], [ "hominy", 1 ], [ "dry_veggy", 1 ], + [ "dry_corn", 1 ], + [ "corn_kernels", 1 ], [ "con_milk", 1 ], [ "flatbread", 1 ], [ "tortilla_corn", 1 ], @@ -447,8 +449,11 @@ [ [ "veggy_wild", 2 ], [ "veggy", 2 ], + [ "corn_kernels", 2 ], [ "rehydrated_veggy", 2 ], + [ "rehydrated_corn_kernels", 2 ], [ "dry_veggy", 2 ], + [ "dry_corn", 2 ], [ "dry_beans", 2 ], [ "can_beans", 2 ], [ "raw_beans", 2 ], @@ -665,6 +670,8 @@ [ "raw_dandelion", 1 ], [ "raw_burdock", 1 ], [ "rehydrated_veggy", 1 ], + [ "rehydrated_corn_kernels", 1 ], + [ "corn_kernels", 1 ], [ "veggy", 1 ], [ "veggy_wild", 1 ], [ "veggy_salted", 1 ], @@ -675,7 +682,7 @@ { "id": "veggy_any_uncooked", "type": "requirement", - "components": [ [ [ "rehydrated_veggy", 1 ], [ "veggy_any_fresh_uncooked", 1, "LIST" ] ] ] + "components": [ [ [ "rehydrated_veggy", 1 ], [ "rehydrated_corn_kernels", 1 ], [ "veggy_any_fresh_uncooked", 1, "LIST" ] ] ] }, { "id": "veggy_any_fresh_uncooked", @@ -691,8 +698,7 @@ [ "cattail_stalk", 1 ], [ "celery", 1 ], [ "irradiated_celery", 1 ], - [ "corn", 1 ], - [ "irradiated_corn", 1 ], + [ "corn_kernels", 1 ], [ "cucumber", 1 ], [ "irradiated_cucumber", 1 ], [ "lettuce", 1 ], @@ -750,6 +756,8 @@ "components": [ [ [ "veggy_any", 1, "LIST" ], + [ "empty_corn_cob", 1 ], + [ "corn", 1 ], [ "powder_eggs", 1 ], [ "eggs_bird", 1, "LIST" ], [ "egg_reptile", 1 ], From 4f782785116b06ce46f95234f77feb375cf64a1b Mon Sep 17 00:00:00 2001 From: klorpa <30924131+klorpa@users.noreply.github.com> Date: Thu, 18 Feb 2021 02:07:00 -0600 Subject: [PATCH 231/453] Talk Tag Additions (#47010) --- data/json/items/armor/storage.json | 2 +- data/json/npcs/talk_tags.json | 41 +++++++++++++++++++++++++++++- data/json/npcs/talk_tags_chat.json | 28 +++++++++++++------- doc/MARTIALART_JSON.md | 2 +- doc/PROFICIENCY.md | 2 +- 5 files changed, 62 insertions(+), 13 deletions(-) diff --git a/data/json/items/armor/storage.json b/data/json/items/armor/storage.json index d71ba7e2f0ae4..b410c75b32f3b 100644 --- a/data/json/items/armor/storage.json +++ b/data/json/items/armor/storage.json @@ -1047,7 +1047,7 @@ "warmth": 8, "material_thickness": 2, "properties": [ [ "creature_size_capacity", "SMALL" ] ], - "use_action": "CAPTURE_MONSTER_ACT", + "use_action": [ "CAPTURE_MONSTER_ACT" ], "flags": [ "BELTED", "WATERPROOF" ] }, { diff --git a/data/json/npcs/talk_tags.json b/data/json/npcs/talk_tags.json index 2b25404c7ca4b..a75f1f17c1ee8 100644 --- a/data/json/npcs/talk_tags.json +++ b/data/json/npcs/talk_tags.json @@ -63,6 +63,7 @@ "I'm sorry . I'm afraid I can't do that.", "Wish I could, .", "Nothing to trade, sorry .", + "I don't want to trade right now.", "Maybe next time?" ] }, @@ -79,6 +80,7 @@ "Great idea! Call me when you find SOMEONE ELSE to do it.", "I'm afraid I can't help you there.", "Not exactly the settlin' type.", + "I can't help you with that right now.", "I'm more of a free spirit, can't settle, sorry." ] }, @@ -445,6 +447,7 @@ "Time for bed! See you in the morning.", "There's a bed calling my name, and I'm going to it.", "Good night! Wake me if you need me.", + "Well, I'm going to bed now.", "Calling it a night for now. You get some rest too, okay?" ] }, @@ -608,6 +611,7 @@ "Drop your weapon, !", "Put down your !", "Alright, drop the !", + "Hey, put that weapon down!", "Please put down your weapon. I'll give you to the count of three. One…", "Let's take it easy now, okay? Put the weapon down." ] @@ -777,6 +781,7 @@ "Bombs away!", "Shrapnel, incoming! Watch it!", "Making some noise!", + "It's gonna blow!", "Hit the deck!" ] }, @@ -944,6 +949,9 @@ "! This is the end,", "I can take on", "Time to die,", + "Prepare to die,", + "See you in hell,", + "Rot in hell,", "Say your prayers," ] }, @@ -980,6 +988,7 @@ "Hold up, gotta plug this hole in me.", "Watch my back while I stitch my arm back on .", "Gotta bandage this or I'll bleed out. Give me a sec.", + "Let me fix myself up here for a second.", "I ain't got time to ble-wait, that's a lot of blood. Give me a second while I patch this." ] }, @@ -996,6 +1005,8 @@ "What was that?", "Huh? Is someone there?", "Who's there?", + "Did anyone else hear that?", + "Sounds like someone said something.", "Who goes there?" ] }, @@ -1010,6 +1021,8 @@ "What's that noise?", "Is something over there?", "Sounds like something bad's going on.", + "What's going on over there?", + "Sounds like a fight's going on.", "What was that?" ] }, @@ -1024,6 +1037,9 @@ "Did you hear that? Sounded like", "What is making that sound? I can hear the", "I could swear I heard", + "Huh? I think I just heard", + "Huh? That sounded like", + "I think that was the sound of", "I could have sworn I just heard" ] }, @@ -1067,6 +1083,7 @@ "Mmm, that weed smells good.", "Man, I can smell the weed, can I have some?", "Are you sure it's a good idea to smoke that now?", + "Are you getting stoned right now?", "Is that the devil's lettuce I smell?" ] }, @@ -1091,7 +1108,14 @@ "type": "snippet", "category": "", "//": "Complaint when the NPC is near the avatar who is smoking crack.", - "text": [ "Ew, smells like burning rubber!", "Ugh, that smells rancid!", "Why are you smoking crack cocaine?", "" ] + "text": [ + "Ew, smells like burning rubber!", + "Ugh, that smells rancid!", + "Why are you smoking crack cocaine?", + "Crack cocaine smells awful!", + "Are you seriously going to be a crackhead around me?", + "" + ] }, { "type": "snippet", @@ -1114,6 +1138,7 @@ "Pass some ethanol, I need to power my ethanol burner.", "Waiter! I need a refill, my ethanol burner is running out of charge!", "I require ethanol for my internal power supply. Anything on you?", + "I need some ethanol to power up my CBMs.", "Got any alcohol to spare? Need to recharge my drives. Methanol, would do." ] }, @@ -1125,6 +1150,7 @@ "I need some junk to power my internal furnace.", "I can't recharge my CBMs without some firewood for my internal furnace.", "I need something to use as fuel for my furnace.", + "I need something to burn for my furnace. Can you help?", "Hey, , can I get some waste paper or withered plants? I need to recharge." ] }, @@ -1135,6 +1161,8 @@ "text": [ "I need some fuel to power my bionics.", "I can't recharge my CBMs without some fuel.", + "Could I get some fuel for my bionics?", + "I need more fuel. Can you help me out here?", "Hey, , can I get some fuel? I need to recharge." ] }, @@ -1163,6 +1191,7 @@ "What was the Cataclysm like for you?", "How did you make it through the initial chaos?", "Tell me how you survived the initial wave of the Cataclysm.", + "How did you survive those first few days?", "Was it rough surviving thus far?" ] }, @@ -1173,6 +1202,8 @@ "text": [ "How do you think we ended up here? What even happened?", "What's going on? Like, big picture, what the hell happened?", + "What do you think the cataclysm even was?", + "So how do you think the end of the world happened?", "Have you heard anything about how the apocalypse came about?" ] }, @@ -1184,6 +1215,7 @@ "Let's talk about something else.", "Let's change the subject.", "I'd like to ask you about something else.", + "I'd like to talk about about something else.", "Moving on…", "Anyway…" ] @@ -1294,6 +1326,7 @@ "Retreat! Retreat!", "Book it!", "Leg it!", + "I'm getting the hell out of here!", "Thank fuck for all the cardio!" ] }, @@ -1306,6 +1339,7 @@ "! Die, you ! I want to live!", "My feet failed me! Arms, don't fail me!", "Can't run! Have to fight!", + "I can't run away from this!", "If I die, I'm taking you all with me!" ] }, @@ -1322,6 +1356,7 @@ "Somebody get some water!", "Fire, fire, FIRE!", "Get an extinguisher!", + "Somebody get some water or something!", "Danger hot!" ] }, @@ -1355,6 +1390,7 @@ "Clean water, the taste that refreshes!", "I was parched, but not I am not.", "Water is nice, but I should get a grog ration.", + "Nothing quite like clean water.", "That wasn't Evian, but I'm not thirsty." ] }, @@ -1366,6 +1402,7 @@ "And now I have eaten and am not hungry.", "That food was good, but I miss real restaurants.", "Well, that satisfied me.", + "Nice to have food once in a while.", "I just had some food, but I'm still peckish. Would you mind if I ate more?" ] }, @@ -1376,6 +1413,8 @@ "text": [ "Hey, , we're out of food.", "Hey, the larder is empty! We're going to starve.", + "There's no food in the larder!", + "We need more food in the basecamp larder; it's empty.", "Uhm, , I don't meant to criticize, but we should focus on distributing some food into the basecamp larder." ] }, diff --git a/data/json/npcs/talk_tags_chat.json b/data/json/npcs/talk_tags_chat.json index 55a9b672fd038..a7520f39c32c7 100644 --- a/data/json/npcs/talk_tags_chat.json +++ b/data/json/npcs/talk_tags_chat.json @@ -19,6 +19,8 @@ "text": [ "Yeah, this summer heat is hitting me hard, you know?", "Enjoying the summer.", + "Not quite like the summers from before, huh?", + "Can't wait for this summer to be over.", "Kinda wishing it would cool off a bit, to be honest." ] }, @@ -29,6 +31,8 @@ "text": [ "OK, maybe it'll stop me from freezing in this weather.", "Gotta say, I'm not minding the snow.", + "Not quite like the winters from before, huh?", + "Can't wait for this winter to be over.", "It's weird the zombies don't freeze." ] }, @@ -36,7 +40,13 @@ "type": "snippet", "category": "", "//": "A sentence about being sick to go before a more general chitchat message.", - "text": [ "Well, I'm feeling pretty sick… but sure." ] + "text": [ + "A nice chat might improve my health somewhat.", + "Alright, but I'm feeling a bit under the weather.", + "I'm not feeling too well, but I can still talk for a bit.", + "We can talk, even though I'm not feeling too well.", + "Well, I'm feeling pretty sick… but sure." + ] }, { "type": "snippet", @@ -58,7 +68,7 @@ "What the heck. How's life been treating you?", "So, how about that weather, eh?", "Nice of you to make time. How's it been for you lately?", - "My dogs’ve been barkin’ lately, you know?", + "My dogs've been barkin' lately, you know?", "I feel great today. Not sure what it is, just one of those days." ] }, @@ -70,11 +80,11 @@ "I just can't believe it's over. I keep running my head back to the days it all fell apart. The riots. The lies. The psychos. It never really felt like it was going to go like this.", "You ever think there's any truth to the crap they were spouting before the world ended? Mind control drugs in the water, bio-terrorism? Some of it would make sense, but it seems so far-fetched. Then again, we're dealing with actual zombies.", "I wonder if I should be getting more religious now, or less. You know what I'm sayin', ?", - "I been thinkin’ about rearranging my gear. It’s a real mess. Don’t wanna go for my weapon and accidentally pull out a granola bar, right?", - "You ever wonder why we even bother? We’re all just gonna be zombies eventually anyway. I mean, not that I’m gonna stop fighting, but what’s the damn point?", + "I been thinkin' about rearranging my gear. It's a real mess. Don't wanna go for my weapon and accidentally pull out a granola bar, right?", + "You ever wonder why we even bother? We're all just gonna be zombies eventually anyway. I mean, not that I'm gonna stop fighting, but what's the damn point?", "I wish I could go bust a cap in one of those zombies right now, without all the fuss about being scared for my life.", "Every time I close my eyes, I can still see the riots. Do you get that, or is it just me?", - "You ever feel like the whole time before the apocalypse was just a dream you’re waking up from?", + "You ever feel like the whole time before the apocalypse was just a dream you're waking up from?", "When do you think you realized the world was ending? For me, it was that damned YouTube video with the lady killing the baby. Holy shit, you know?", "I wonder if the government's still out there, holed up in some bunker.", "Remember some of the crazy news from the end of the world? The stuff that got drowned out by the riot coverage I mean. Like, didn't the governor of Rhode Island secede from the Union or something?", @@ -89,9 +99,9 @@ "text": [ "I can't stop wondering who fucked up to make all this happen. Obviously we can't trust the news, they claimed the zombies were \"rioters\" for weeks. Why? Where did this come from?", "If what they told us about the Chinese was even partly true, do you think it's like this in China? Or maybe the US is some kind of quarantine zone, and at least some of the world is still out there.", - "Have you noticed injuries aren’t healing the same as usual? I started spotting it before the world ended, but it’s become more pronounced. There’s hardly even a granulation step after a cut closes.", - "I still don’t understand how these zombies are powered. They’re like perpetual motion machines.", - "So many parts of this still don't fit together. Who created the zombies? What powers them? Maybe the rumours of mind control drugs were true all along, and someone found a way to bioengineer living dead." + "Have you noticed injuries aren't healing the same as usual? I started spotting it before the world ended, but it's become more pronounced. There's hardly even a granulation step after a cut closes.", + "I still don't understand how these zombies are powered. They're like perpetual motion machines.", + "So many parts of this still don't fit together. Who created the zombies? What powers them? Maybe the rumors of mind control drugs were true all along, and someone found a way to bioengineer living dead." ] }, { @@ -103,7 +113,7 @@ "", "How do these zombies even keep going? What are they eating? Do you think they'll ever rot away?", "I been thinkin', one of these days, we're gonna run out of toilet paper. What then?", - "Do you think it’s weird how we’ll, like, open a locked building and find a lone zombie inside? How’d it even get there?", + "Do you think it's weird how we'll, like, open a locked building and find a lone zombie inside? How'd it even get there?", "Sometimes I wonder if we're all psychos, not just the ones that went crazy and rioted. I never would have thought I could do the things I've done since the world ended.", "You read any good books lately? I'm glad we still got books.", "You know what I miss? Movie theaters. You think Hollywood survived this? Maybe there's a bunch of zombie actors out there, filmin' shit out of reflex. Hah, I'd watch that shit." diff --git a/doc/MARTIALART_JSON.md b/doc/MARTIALART_JSON.md index 2331a993b9fc1..48a89d7eeaffd 100644 --- a/doc/MARTIALART_JSON.md +++ b/doc/MARTIALART_JSON.md @@ -61,7 +61,7 @@ "aoe": "spin", // This technique has an area-of-effect; doesn't work against solo targets "block_counter": true, // This technique may automatically counterattack on a successful block "dodge_counter": true, // This technique may automatically counterattack on a successful dodge -"weighting": 2, // Affects likelihood this technique will be seleted when many are available +"weighting": 2, // Affects likelihood this technique will be selected when many are available "defensive": true, // Game won't try to select this technique when attacking "miss_recovery": true, // Misses while attacking will use fewer moves "messages" : [ // What is printed when this technique is used by the player and by an npc diff --git a/doc/PROFICIENCY.md b/doc/PROFICIENCY.md index 1aa7481c5ed3a..80a57222aaa54 100644 --- a/doc/PROFICIENCY.md +++ b/doc/PROFICIENCY.md @@ -38,7 +38,7 @@ Optional. Float When used in recipes these values are the amount the time to complete the recipe, and the chance to fail the recipe, will be multiplied by. - For proficiencies that represent core basic knowledge and foundational principles, the `time` should usually be low (1.5 or so), and the `fail` should be high (4 or more). -- For "flavour" proficiencies that offer a small boost, these should be around 1.5 each. +- For "flavor" proficiencies that offer a small boost, these should be around 1.5 each. - Most other proficiencies should be in the 2-3 range for both values. ### `time_to_learn` From f66d33223a9677b177dafb07ee84bf06793c6324 Mon Sep 17 00:00:00 2001 From: UmbralReaper <67179462+UmbralReaper@users.noreply.github.com> Date: Sat, 20 Feb 2021 19:53:41 +1000 Subject: [PATCH 232/453] Fix typo in Valentines Card (#47583) --- data/json/snippets/valentines.json | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/data/json/snippets/valentines.json b/data/json/snippets/valentines.json index 71d3624a7bb92..966bf1253dad7 100644 --- a/data/json/snippets/valentines.json +++ b/data/json/snippets/valentines.json @@ -38,7 +38,7 @@ }, { "id": "valentine_10", - "text": "A girl smiles into the camera. Behind here a house is on fire. \"I'm burning, I'm burning, I'm burning for you, my valentine!\"" + "text": "A girl smiles into the camera. Behind her a house is on fire. \"I'm burning, I'm burning, I'm burning for you, my valentine!\"" } ] } From 70e4379703404b51a365355e10e175ec8135bce8 Mon Sep 17 00:00:00 2001 From: SariusSkelrets <68650913+SariusSkelrets@users.noreply.github.com> Date: Tue, 23 Feb 2021 02:35:57 -0500 Subject: [PATCH 233/453] (CrazyCataclysm) Crazy Hallucinations (#47386) --- data/mods/CrazyCataclysm/crazy_monsters.json | 14 ++++++++++++++ 1 file changed, 14 insertions(+) diff --git a/data/mods/CrazyCataclysm/crazy_monsters.json b/data/mods/CrazyCataclysm/crazy_monsters.json index 57808d7c97670..30a5246dfd178 100644 --- a/data/mods/CrazyCataclysm/crazy_monsters.json +++ b/data/mods/CrazyCataclysm/crazy_monsters.json @@ -14,6 +14,20 @@ "copy-from": "mon_zombie_electric", "special_attacks": [ [ "SHOCKING_REVEAL", 25 ] ] }, + { + "id": "halloween_dragon", + "type": "MONSTER", + "name": { "str": "inflatable dragon" }, + "copy-from": "mon_dragon_dummy", + "delete": { "flags": [ "NOT_HALLUCINATION" ] } + }, + { + "id": "halloween_ghost", + "type": "MONSTER", + "name": { "str": "inflatable ghost" }, + "copy-from": "mon_halloween_ghost", + "delete": { "flags": [ "NOT_HALLUCINATION" ] } + }, { "id": "mon_zombie_skeltal", "type": "MONSTER", From f9a14b740257f445179be1757f0339d6cca08ffa Mon Sep 17 00:00:00 2001 From: Fosheze <50811445+Fosheze@users.noreply.github.com> Date: Tue, 23 Feb 2021 01:39:26 -0600 Subject: [PATCH 234/453] Mealgurb (#47685) --- data/mods/Aftershock/items/comestibles/bug_brew.json | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/data/mods/Aftershock/items/comestibles/bug_brew.json b/data/mods/Aftershock/items/comestibles/bug_brew.json index 36657471e1eff..bcbf8d7cbd91d 100644 --- a/data/mods/Aftershock/items/comestibles/bug_brew.json +++ b/data/mods/Aftershock/items/comestibles/bug_brew.json @@ -2,7 +2,7 @@ { "type": "COMESTIBLE", "id": "afs_mealgrub_medium", - "name": { "str": "mealgurb growth medium" }, + "name": { "str": "mealgrub growth medium" }, "description": "All sort of organic substances rendered into a nutritious goop that can be used as a growth medium in grub aquaculture. Urban myth claims that its original formula was just bottled industrial runoff. Whatever the case, mealgrubs thrive within it.", "weight": "100 g", "container": "jug_plastic", @@ -25,7 +25,7 @@ { "type": "COMESTIBLE", "id": "afs_mealgrub_spores", - "name": { "str_sp": "mealgurb spores" }, + "name": { "str_sp": "mealgrub spores" }, "description": "Mealgrubs are a staple aquacultural product, treasured for their ability to process nearly any organic substance into safe for consumption animal protein. As the result of very heavy handed gene-modding these are propietary organism, and strictly speaking, its illegal to grow them without a licence.", "weight": "100 g", "container": "bottle_plastic_small", From a00edbbfc6dbee89cce02eca1d0415bfddaf40ad Mon Sep 17 00:00:00 2001 From: Lamandus <33199510+Lamandus@users.noreply.github.com> Date: Tue, 23 Feb 2021 08:46:59 +0100 Subject: [PATCH 235/453] Add duct tape blindfold for old reciepe plus tweaks for reciepe (#47527) --- data/json/items/tool_armor.json | 22 ++++++++++++++++++++++ data/json/recipes/armor/head.json | 7 ++----- data/json/recipes/recipe_obsolete.json | 6 ++++++ 3 files changed, 30 insertions(+), 5 deletions(-) diff --git a/data/json/items/tool_armor.json b/data/json/items/tool_armor.json index 56219a9427799..afe219e96dfbf 100644 --- a/data/json/items/tool_armor.json +++ b/data/json/items/tool_armor.json @@ -114,6 +114,28 @@ "environmental_protection": 1, "flags": [ "BLIND" ] }, + { + "id": "blindfold_duct", + "type": "ARMOR", + "name": { "str": "duct tape blindfold" }, + "//": "A folded bandana still takes up some space on the head.", + "description": "A simple covering tied over the eyes to block sight, made out of duct tape. Useful for sleeping in bright areas.", + "weight": "20 g", + "volume": "60 ml", + "price": 10, + "price_postapoc": 5, + "material": [ "plastic" ], + "symbol": "[", + "looks_like": "blindfold", + "color": "dark_gray", + "covers": [ "eyes" ], + "coverage": 95, + "encumbrance": 10, + "warmth": 0, + "material_thickness": 1, + "environmental_protection": 1, + "flags": [ "BLIND" ] + }, { "id": "ear_plugs", "type": "ARMOR", diff --git a/data/json/recipes/armor/head.json b/data/json/recipes/armor/head.json index db1dd5992ce26..6fcd875e6fd29 100644 --- a/data/json/recipes/armor/head.json +++ b/data/json/recipes/armor/head.json @@ -42,18 +42,15 @@ "components": [ [ [ "felt_patch", 4 ] ] ] }, { - "result": "blindfold", + "result": "blindfold_duct", "type": "recipe", "activity_level": "NO_EXERCISE", - "id_suffix": "from_tape", "category": "CC_ARMOR", "subcategory": "CSC_ARMOR_HEAD", "skill_used": "fabrication", - "difficulty": 1, "time": "3 m", - "reversible": true, "autolearn": true, - "components": [ [ [ "duct_tape", 10 ] ] ], + "components": [ [ [ "duct_tape", 50 ] ] ], "flags": [ "BLIND_EASY" ] }, { diff --git a/data/json/recipes/recipe_obsolete.json b/data/json/recipes/recipe_obsolete.json index 40c0171aa442e..40b4b52c04c91 100644 --- a/data/json/recipes/recipe_obsolete.json +++ b/data/json/recipes/recipe_obsolete.json @@ -2752,6 +2752,12 @@ "result": "mp3", "obsolete": true }, + { + "type": "recipe", + "result": "blindfold", + "id_suffix": "from_tape", + "obsolete": true + }, { "type": "recipe", "result": "towel", From df028233a2836d94c5d5470e212ccd010a0ffb92 Mon Sep 17 00:00:00 2001 From: Curtis Merrill Date: Tue, 23 Feb 2021 02:51:26 -0500 Subject: [PATCH 236/453] Prepare npc, spell, character, and item for new ai (#47207) --- src/character.cpp | 2 +- src/character.h | 7 +- src/creature.h | 7 ++ src/item.cpp | 20 +++--- src/item.h | 3 +- src/magic.cpp | 92 ++++++++++++++++++++++-- src/magic.h | 14 +++- src/magic_spell_effect.cpp | 11 +-- src/npc.cpp | 25 +++++++ src/npc.h | 15 ++++ src/npcmove.cpp | 36 +++++++--- src/ranged.cpp | 132 +++++++++++++++++++++++----------- tests/player_helpers.cpp | 46 ++++++++++++ tests/player_helpers.h | 4 ++ tests/ranged_balance_test.cpp | 47 +----------- 15 files changed, 338 insertions(+), 123 deletions(-) diff --git a/src/character.cpp b/src/character.cpp index 3e30fc389f685..499cea2665838 100644 --- a/src/character.cpp +++ b/src/character.cpp @@ -2673,7 +2673,7 @@ int Character::get_mod_stat_from_bionic( const character_stat &Stat ) const return ret; } -int Character::get_standard_stamina_cost( item *thrown_item ) +int Character::get_standard_stamina_cost( const item *thrown_item ) const { // Previously calculated as 2_gram * std::max( 1, str_cur ) // using 16_gram normalizes it to 8 str. Same effort expenditure diff --git a/src/character.h b/src/character.h index d46b7db26de3a..a348e13a42716 100644 --- a/src/character.h +++ b/src/character.h @@ -501,7 +501,7 @@ class Character : public Creature, public visitable void mod_stat( const std::string &stat, float modifier ) override; - int get_standard_stamina_cost( item *thrown_item = nullptr ); + int get_standard_stamina_cost( const item *thrown_item = nullptr ) const; /**Get bonus to max_hp from excess stored fat*/ int get_fat_to_hp() const; @@ -1635,6 +1635,10 @@ class Character : public Creature, public visitable */ int item_reload_cost( const item &it, const item &ammo, int qty ) const; + projectile thrown_item_projectile( const item &thrown ) const; + int thrown_item_adjusted_damage( const item &thrown ) const; + // calculates the total damage possible from a thrown item, without resistances and such. + int thrown_item_total_damage_raw( const item &thrown ) const; /** Maximum thrown range with a given item, taking all active effects into account. */ int throw_range( const item & ) const; /** Dispersion of a thrown item, against a given target, taking into account whether or not the throw was blind. */ @@ -1847,6 +1851,7 @@ class Character : public Creature, public visitable // gets all the spells known by this character that have this spell class // spells returned are a copy, do not try to edit them from here, instead use known_magic::get_spell std::vector spells_known_of_class( const trait_id &spell_class ) const; + bool cast_spell( spell &sp, bool fake_spell, cata::optional target ); void make_bleed( const effect_source &source, const bodypart_id &bp, time_duration duration, int intensity = 1, bool permanent = false, bool force = false, bool defferred = false ); diff --git a/src/creature.h b/src/creature.h index 720fd01dc6493..011f9cca36a26 100644 --- a/src/creature.h +++ b/src/creature.h @@ -44,6 +44,7 @@ class anatomy; class avatar; class field; class field_entry; +class npc; class player; class time_duration; struct point; @@ -263,6 +264,12 @@ class Creature : public location, public viewer virtual const avatar *as_avatar() const { return nullptr; } + virtual const npc *as_npc() { + return nullptr; + } + virtual const npc *as_npc() const { + return nullptr; + } virtual monster *as_monster() { return nullptr; } diff --git a/src/item.cpp b/src/item.cpp index 67d8ac5162046..0f3829f5837ec 100644 --- a/src/item.cpp +++ b/src/item.cpp @@ -1498,7 +1498,7 @@ static const double hits_by_accuracy[41] = { 9993, 9997, 9998, 9999, 10000 // 16 to 20 }; -double item::effective_dps( const Character &guy, monster &mon ) const +double item::effective_dps( const Character &guy, Creature &mon ) const { const float mon_dodge = mon.get_dodge(); float base_hit = guy.get_dex() / 4.0f + guy.get_hit_weapon( *this ); @@ -1533,19 +1533,19 @@ double item::effective_dps( const Character &guy, monster &mon ) const // sum average damage past armor and return the number of moves required to achieve // that damage const auto calc_effective_damage = [ &, moves_per_attack]( const double num_strikes, - const bool crit, const Character & guy, monster & mon ) { - monster temp_mon = mon; + const bool crit, const Character & guy, Creature & mon ) { + Creature *temp_mon = &mon; double subtotal_damage = 0; damage_instance base_damage; guy.roll_all_damage( crit, base_damage, true, *this ); damage_instance dealt_damage = base_damage; - temp_mon.absorb_hit( bodypart_id( "torso" ), dealt_damage ); + temp_mon->absorb_hit( bodypart_id( "torso" ), dealt_damage ); dealt_damage_instance dealt_dams; for( const damage_unit &dmg_unit : dealt_damage.damage_units ) { int cur_damage = 0; int total_pain = 0; - temp_mon.deal_damage_handle_type( effect_source::empty(), dmg_unit, bodypart_id( "torso" ), - cur_damage, total_pain ); + temp_mon->deal_damage_handle_type( effect_source::empty(), dmg_unit, bodypart_id( "torso" ), + cur_damage, total_pain ); if( cur_damage > 0 ) { dealt_dams.dealt_dams[ static_cast( dmg_unit.type )] += cur_damage; } @@ -1555,20 +1555,20 @@ double item::effective_dps( const Character &guy, monster &mon ) const double subtotal_moves = moves_per_attack * num_strikes; if( has_technique( RAPID ) ) { - monster temp_rs_mon = mon; + Creature *temp_rs_mon = &mon; damage_instance rs_base_damage; guy.roll_all_damage( crit, rs_base_damage, true, *this ); damage_instance dealt_rs_damage = rs_base_damage; for( damage_unit &dmg_unit : dealt_rs_damage.damage_units ) { dmg_unit.damage_multiplier *= 0.66; } - temp_rs_mon.absorb_hit( bodypart_id( "torso" ), dealt_rs_damage ); + temp_rs_mon->absorb_hit( bodypart_id( "torso" ), dealt_rs_damage ); dealt_damage_instance rs_dealt_dams; for( const damage_unit &dmg_unit : dealt_rs_damage.damage_units ) { int cur_damage = 0; int total_pain = 0; - temp_rs_mon.deal_damage_handle_type( effect_source::empty(), dmg_unit, bodypart_id( "torso" ), - cur_damage, total_pain ); + temp_rs_mon->deal_damage_handle_type( effect_source::empty(), dmg_unit, bodypart_id( "torso" ), + cur_damage, total_pain ); if( cur_damage > 0 ) { rs_dealt_dams.dealt_dams[ static_cast( dmg_unit.type ) ] += cur_damage; } diff --git a/src/item.h b/src/item.h index 6290008679cd7..6f5064ce44ad8 100644 --- a/src/item.h +++ b/src/item.h @@ -34,6 +34,7 @@ #include "visitable.h" class Character; +class Creature; class JsonIn; class JsonObject; class JsonOut; @@ -624,7 +625,7 @@ class item : public visitable * Calculate the item's effective damage per second past armor when wielded by a * character against a monster. */ - double effective_dps( const Character &guy, monster &mon ) const; + double effective_dps( const Character &guy, Creature &mon ) const; /** * calculate effective dps against a stock set of monsters. by default, assume g->u * is wielding diff --git a/src/magic.cpp b/src/magic.cpp index f988ccad0c60f..e46b3acaee3ce 100644 --- a/src/magic.cpp +++ b/src/magic.cpp @@ -8,6 +8,7 @@ #include #include +#include "avatar.h" #include "calendar.h" #include "cata_utility.h" #include "catacharset.h" @@ -33,14 +34,17 @@ #include "make_static.h" #include "magic_enchantment.h" #include "map.h" +#include "map_iterator.h" #include "messages.h" #include "mongroup.h" #include "monster.h" #include "mtype.h" #include "mutation.h" +#include "npc.h" #include "output.h" #include "pimpl.h" #include "point.h" +#include "projectile.h" #include "requirements.h" #include "rng.h" #include "sounds.h" @@ -565,6 +569,18 @@ int spell::min_leveled_damage() const return type->min_damage + std::round( get_level() * type->damage_increment ); } +float spell::dps( const Character &caster, const Creature & ) const +{ + if( type->effect_name != "attack" ) { + return 0.0f; + } + const float time_modifier = 100.0f / casting_time( caster ); + const float failure_modifier = 1.0f - spell_fail( caster ); + const float raw_dps = damage() + damage_dot() * duration_turns() / 1_turns; + // TODO: calculate true dps with armor and resistances and any caster bonuses + return raw_dps * time_modifier * failure_modifier; +} + int spell::damage() const { const int leveled_damage = min_leveled_damage(); @@ -679,6 +695,45 @@ int spell::range() const } } +std::vector spell::targetable_locations( const Character &source ) const +{ + + const tripoint char_pos = source.pos(); + const bool select_ground = is_valid_target( spell_target::ground ); + const bool ignore_walls = has_flag( spell_flag::NO_PROJECTILE ); + map &here = get_map(); + + // TODO: put this in a namespace for reuse + const auto has_obstruction = [&]( const tripoint & at ) { + for( const tripoint &line_point : line_to( char_pos, at ) ) { + if( here.impassable( line_point ) ) { + return true; + } + } + return false; + }; + + std::vector selectable_targets; + for( const tripoint &query : here.points_in_radius( char_pos, range() ) ) { + if( !ignore_walls && has_obstruction( query ) ) { + // it's blocked somewhere! + continue; + } + + if( !select_ground ) { + if( !source.sees( query ) ) { + // can't target a critter you can't see + continue; + } + } + + if( is_valid_target( source, query ) ) { + selectable_targets.push_back( query ); + } + } + return selectable_targets; +} + int spell::min_leveled_duration() const { return type->min_duration + std::round( get_level() * type->duration_increment ); @@ -792,14 +847,17 @@ bool spell::is_spell_class( const trait_id &mid ) const return mid == type->spell_class; } -bool spell::can_cast( Character &guy ) const +bool spell::can_cast( const Character &guy ) const { if( guy.has_trait_flag( STATIC( json_character_flag( "NO_SPELLCASTING" ) ) ) ) { return false; } + // only required because crafting_inventory always rebuilds the cache. maybe a const version doesn't write to cache. + Character &guy_inv = const_cast( guy ); + if( !type->spell_components.is_empty() && - !type->spell_components->can_make_with_inventory( guy.crafting_inventory( guy.pos(), 0 ), + !type->spell_components->can_make_with_inventory( guy_inv.crafting_inventory( guy.pos(), 0 ), return_true ) ) { return false; } @@ -1076,13 +1134,22 @@ void spell::create_field( const tripoint &at ) const } } -void spell::make_sound( const tripoint &target ) const +int spell::sound_volume() const { + int loudness = 0; if( !has_flag( spell_flag::SILENT ) ) { - int loudness = std::abs( damage() ) / 3; + loudness = std::abs( damage() ) / 3; if( has_flag( spell_flag::LOUD ) ) { loudness += 1 + damage() / 3; } + } + return loudness; +} + +void spell::make_sound( const tripoint &target ) const +{ + const int loudness = sound_volume(); + if( loudness > 0 ) { make_sound( target, loudness ); } } @@ -1307,6 +1374,23 @@ dealt_damage_instance spell::get_dealt_damage_instance() const return dmg; } +dealt_projectile_attack spell::get_projectile_attack( const tripoint &target, + Creature &hit_critter ) const +{ + projectile bolt; + bolt.speed = 10000; + bolt.impact = get_damage_instance(); + bolt.proj_effects.emplace( "magic" ); + + dealt_projectile_attack atk; + atk.end_point = target; + atk.hit_critter = &hit_critter; + atk.proj = bolt; + atk.missed_by = 0.0; + + return atk; +} + std::string spell::effect_data() const { return type->effect_str; diff --git a/src/magic.h b/src/magic.h index 9480ab9768a0d..fe4195a46d1b2 100644 --- a/src/magic.h +++ b/src/magic.h @@ -30,6 +30,7 @@ class JsonOut; class nc_color; class spell; class time_duration; +struct dealt_projectile_attack; struct requirement_data; namespace spell_effect @@ -441,7 +442,11 @@ class spell int damage_dot() const; damage_over_time_data damage_over_time( const std::vector &bps ) const; dealt_damage_instance get_dealt_damage_instance() const; + dealt_projectile_attack get_projectile_attack( const tripoint &target, + Creature &hit_critter ) const; damage_instance get_damage_instance() const; + // calculate damage per second against a target + float dps( const Character &caster, const Creature &target ) const; // how big is the spell's radius int aoe() const; std::set effect_area( const spell_effect::override_parameters ¶ms, @@ -449,6 +454,12 @@ class spell std::set effect_area( const tripoint &source, const tripoint &target ) const; // distance spell can be cast int range() const; + /** + * all of the tripoints the spell can be cast at. + * if the spell can't be cast through walls, does not return anything behind walls + * if the spell can't target the ground, can't target unseen locations, etc. + */ + std::vector targetable_locations( const Character &source ) const; // how much energy does the spell cost int energy_cost( const Character &guy ) const; // how long does this spell's effect last @@ -464,7 +475,7 @@ class spell const requirement_data &components() const; bool has_components() const; // can the Character cast this spell? - bool can_cast( Character &guy ) const; + bool can_cast( const Character &guy ) const; // can the Character learn this spell? bool can_learn( const Character &guy ) const; // is this spell valid @@ -525,6 +536,7 @@ class spell // tries to create a field at the location specified void create_field( const tripoint &at ) const; + int sound_volume() const; // makes a spell sound at the location void make_sound( const tripoint &target ) const; void make_sound( const tripoint &target, int loudness ) const; diff --git a/src/magic_spell_effect.cpp b/src/magic_spell_effect.cpp index c010c0cac8a8c..43978f1c511db 100644 --- a/src/magic_spell_effect.cpp +++ b/src/magic_spell_effect.cpp @@ -480,16 +480,7 @@ static void damage_targets( const spell &sp, Creature &caster, continue; } - projectile bolt; - bolt.speed = 10000; - bolt.impact = sp.get_damage_instance(); - bolt.proj_effects.emplace( "magic" ); - - dealt_projectile_attack atk; - atk.end_point = target; - atk.hit_critter = cr; - atk.proj = bolt; - atk.missed_by = 0.0; + dealt_projectile_attack atk = sp.get_projectile_attack( target, *cr ); if( !sp.effect_data().empty() ) { add_effect_to_target( target, sp ); } diff --git a/src/npc.cpp b/src/npc.cpp index 15b76458f380a..3cc5ecc497d87 100644 --- a/src/npc.cpp +++ b/src/npc.cpp @@ -2149,6 +2149,26 @@ bool npc::is_travelling() const Creature::Attitude npc::attitude_to( const Creature &other ) const { + const auto same_as = []( const Creature * lhs, const Creature * rhs ) { + return &lhs == &rhs; + }; + + for( const weak_ptr_fast &buddy : ai_cache.friends ) { + if( same_as( &other, buddy.lock().get() ) ) { + return Creature::Attitude::FRIENDLY; + } + } + for( const weak_ptr_fast &enemy : ai_cache.hostile_guys ) { + if( same_as( &other, enemy.lock().get() ) ) { + return Creature::Attitude::HOSTILE; + } + } + for( const weak_ptr_fast &neutral : ai_cache.neutral_guys ) { + if( same_as( &other, neutral.lock().get() ) ) { + return Creature::Attitude::NEUTRAL; + } + } + if( other.is_npc() || other.is_player() ) { const player &guy = dynamic_cast( other ); // check faction relationships first @@ -2646,6 +2666,11 @@ std::string npc_attitude_id( npc_attitude att ) return iter->second; } +int npc::closest_enemy_to_friendly_distance() const +{ + return ai_cache.closest_enemy_to_friendly_distance(); +} + std::string npc_attitude_name( npc_attitude att ) { switch( att ) { diff --git a/src/npc.h b/src/npc.h index f0a2abdc1e183..d082eb01409f9 100644 --- a/src/npc.h +++ b/src/npc.h @@ -573,11 +573,17 @@ struct npc_short_term_cache { double my_weapon_value = 0; // Use weak_ptr to avoid circular references between Creatures + // attitude of creatures the npc can see + std::vector> hostile_guys; + std::vector> neutral_guys; std::vector> friends; std::vector dangerous_explosives; std::map threat_map; // Cache of locations the NPC has searched recently in npc::find_item() lru_cache searched_tiles; + // returns the value of the distance between a friendly creature and the closest enemy to that friendly creature. + // returns -1 if not applicable + int closest_enemy_to_friendly_distance() const; }; // DO NOT USE! This is old, use strings as talk topic instead, e.g. "TALK_AGREE_FOLLOW" instead of @@ -766,6 +772,12 @@ class npc : public player bool is_npc() const override { return true; } + const npc *as_npc() override { + return this; + } + const npc *as_npc() const override { + return this; + } void load_npc_template( const string_id &ident ); void npc_dismount(); weak_ptr_fast chosen_mount; @@ -1239,6 +1251,9 @@ class npc : public player std::vector miss_ids; cata::optional assigned_camp = cata::nullopt; + // accessors to ai_cache functions + int closest_enemy_to_friendly_distance() const; + private: npc_attitude attitude = NPCATT_NULL; // What we want to do to the player npc_attitude previous_attitude = NPCATT_NULL; diff --git a/src/npcmove.cpp b/src/npcmove.cpp index 1134c0e69c436..1a47a3e300a11 100644 --- a/src/npcmove.cpp +++ b/src/npcmove.cpp @@ -371,6 +371,23 @@ static bool too_close( const tripoint &critter_pos, const tripoint &ally_pos, co return rl_dist( critter_pos, ally_pos ) <= def_radius; } +int npc_short_term_cache::closest_enemy_to_friendly_distance() const +{ + int distance = INT_MAX; + for( const weak_ptr_fast &buddy : friends ) { + if( buddy.expired() ) { + continue; + } + for( const weak_ptr_fast &enemy : hostile_guys ) { + if( enemy.expired() ) { + continue; + } + distance = std::min( distance, rl_dist( buddy.lock()->pos(), enemy.lock()->pos() ) ); + } + } + return distance; +} + void npc::assess_danger() { float assessment = 0.0f; @@ -454,7 +471,6 @@ void npc::assess_danger() } // find our Character friends and enemies - std::vector> hostile_guys; const bool clairvoyant = clairvoyance(); for( const npc &guy : g->all_npcs() ) { if( &guy == this ) { @@ -467,12 +483,12 @@ void npc::assess_danger() if( has_faction_relationship( guy, npc_factions::watch_your_back ) ) { ai_cache.friends.emplace_back( g->shared_from( guy ) ); } else if( attitude_to( guy ) != Attitude::NEUTRAL && sees( guy.pos() ) ) { - hostile_guys.emplace_back( g->shared_from( guy ) ); + ai_cache.hostile_guys.emplace_back( g->shared_from( guy ) ); } } if( sees( player_character.pos() ) ) { if( is_enemy() ) { - hostile_guys.emplace_back( g->shared_from( player_character ) ); + ai_cache.hostile_guys.emplace_back( g->shared_from( player_character ) ); } else if( is_friendly( player_character ) ) { ai_cache.friends.emplace_back( g->shared_from( player_character ) ); } @@ -488,11 +504,14 @@ void npc::assess_danger() continue; } if( att != Attitude::HOSTILE && ( critter.friendly || !is_enemy() ) ) { + ai_cache.neutral_guys.emplace_back( g->shared_from( critter ) ); continue; } if( !sees( critter ) ) { continue; } + + ai_cache.hostile_guys.emplace_back( g->shared_from( critter ) ); float critter_threat = evaluate_enemy( critter ); // warn and consider the odds for distant enemies int dist = rl_dist( pos(), critter.pos() ); @@ -548,7 +567,7 @@ void npc::assess_danger() } } - if( assessment == 0.0 && hostile_guys.empty() ) { + if( assessment == 0.0 && ai_cache.hostile_guys.empty() ) { ai_cache.danger_assessment = assessment; return; } @@ -594,7 +613,7 @@ void npc::assess_danger() return foe_threat; }; - for( const weak_ptr_fast &guy : hostile_guys ) { + for( const weak_ptr_fast &guy : ai_cache.hostile_guys ) { player *foe = dynamic_cast( guy.lock().get() ); if( foe && foe->is_npc() ) { assessment += handle_hostile( *foe, evaluate_enemy( *foe ), translate_marker( "bandit" ), @@ -603,11 +622,10 @@ void npc::assess_danger() } for( const weak_ptr_fast &guy : ai_cache.friends ) { - player *ally = dynamic_cast( guy.lock().get() ); - if( !( ally && ally->is_npc() ) ) { + if( !( guy.lock() && guy.lock()->is_npc() ) ) { continue; } - float guy_threat = evaluate_enemy( *ally ); + float guy_threat = evaluate_enemy( *guy.lock() ); float min_danger = assessment >= NPC_DANGER_VERY_LOW ? NPC_DANGER_VERY_LOW : -10.0f; assessment = std::max( min_danger, assessment - guy_threat * 0.5f ); } @@ -702,6 +720,8 @@ void npc::regen_ai_cache() } float old_assessment = ai_cache.danger_assessment; ai_cache.friends.clear(); + ai_cache.hostile_guys.clear(); + ai_cache.neutral_guys.clear(); ai_cache.target = shared_ptr_fast(); ai_cache.ally = shared_ptr_fast(); ai_cache.can_heal.clear_all(); diff --git a/src/ranged.cpp b/src/ranged.cpp index a6da99c1a2153..aface68e45d3d 100644 --- a/src/ranged.cpp +++ b/src/ranged.cpp @@ -113,6 +113,8 @@ static const std::string flag_MOUNTABLE( "MOUNTABLE" ); static const trait_id trait_PYROMANIA( "PYROMANIA" ); +static const std::set ferric = { material_id( "iron" ), material_id( "steel" ) }; + // Maximum duration of aim-and-fire loop, in turns static constexpr int AIF_DURATION_LIMIT = 10; @@ -962,64 +964,112 @@ int Character::throwing_dispersion( const item &to_throw, Creature *critter, return std::max( 0, dispersion ); } -dealt_projectile_attack player::throw_item( const tripoint &target, const item &to_throw, - const cata::optional &blind_throw_from_pos ) +static cata::optional character_throw_assist( const Character &guy ) { - // Copy the item, we may alter it before throwing - item thrown = to_throw; - - const int move_cost = throw_cost( *this, to_throw ); - mod_moves( -move_cost ); - - const int throwing_skill = get_skill_level( skill_throw ); - units::volume volume = to_throw.volume(); - units::mass weight = to_throw.weight(); - - bool throw_assist = false; - int throw_assist_str = 0; - if( is_mounted() ) { - auto *mons = mounted_creature.get(); + cata::optional throw_assist = cata::nullopt; + if( guy.is_mounted() ) { + auto *mons = guy.mounted_creature.get(); if( mons->mech_str_addition() != 0 ) { - throw_assist = true; - throw_assist_str = mons->mech_str_addition(); + throw_assist = mons->mech_str_addition(); mons->use_mech_power( -3 ); } } - if( !throw_assist ) { - const int stamina_cost = get_standard_stamina_cost( &thrown ); - mod_stamina( stamina_cost + throwing_skill ); - } + return throw_assist; +} - const skill_id &skill_used = skill_throw; - int skill_level = std::min( MAX_SKILL, get_skill_level( skill_throw ) ); +static int throwing_skill_adjusted( const Character &guy ) +{ + int skill_level = std::min( MAX_SKILL, guy.get_skill_level( skill_throw ) ); // if you are lying on the floor, you can't really throw that well - if( has_effect( effect_downed ) ) { + if( guy.has_effect( effect_downed ) ) { skill_level = std::max( 0, skill_level - 5 ); } - // We'll be constructing a projectile - projectile proj; - proj.impact = thrown.base_damage_thrown(); - proj.speed = 10 + skill_level; - auto &impact = proj.impact; - auto &proj_effects = proj.proj_effects; - - static const std::set ferric = { material_id( "iron" ), material_id( "steel" ) }; + return skill_level; +} - bool do_railgun = has_active_bionic( bio_railgun ) && thrown.made_of_any( ferric ) && - !throw_assist; +int Character::thrown_item_adjusted_damage( const item &thrown ) const +{ + const cata::optional throw_assist = character_throw_assist( *this ); + const bool do_railgun = has_active_bionic( bio_railgun ) && thrown.made_of_any( ferric ) && + !throw_assist; // The damage dealt due to item's weight, player's strength, and skill level // Up to str/2 or weight/100g (lower), so 10 str is 5 damage before multipliers // Railgun doubles the effective strength ///\EFFECT_STR increases throwing damage double stats_mod = do_railgun ? get_str() : ( get_str() / 2.0 ); - stats_mod = throw_assist ? throw_assist_str / 2.0 : stats_mod; + stats_mod = throw_assist ? *throw_assist / 2.0 : stats_mod; // modify strength impact based on skill level, clamped to [0.15 - 1] // mod = mod * [ ( ( skill / max_skill ) * 0.85 ) + 0.15 ] stats_mod *= ( std::min( MAX_SKILL, get_skill_level( skill_throw ) ) / static_cast( MAX_SKILL ) ) * 0.85 + 0.15; - impact.add_damage( damage_type::BASH, std::min( weight / 100.0_gram, stats_mod ) ); + return stats_mod; +} + +projectile Character::thrown_item_projectile( const item &thrown ) const +{ + // We'll be constructing a projectile + projectile proj; + proj.impact = thrown.base_damage_thrown(); + proj.speed = 10 + throwing_skill_adjusted( *this ); + return proj; +} + +int Character::thrown_item_total_damage_raw( const item &thrown ) const +{ + projectile proj = thrown_item_projectile( thrown ); + const units::volume volume = thrown.volume(); + proj.impact.add_damage( damage_type::BASH, std::min( thrown.weight() / 100.0_gram, + static_cast( thrown_item_adjusted_damage( thrown ) ) ) ); + // Item will shatter upon landing, destroying the item, dealing damage, and making noise + if( !thrown.active && thrown.made_of( material_id( "glass" ) ) && + rng( 0, units::to_milliliter( 2_liter - volume ) ) < get_str() * 100 ) { + proj.impact.add_damage( damage_type::CUT, units::to_milliliter( volume ) / 500.0f ); + } + // Some minor (skill/2) armor piercing for skillful throws + // Not as much as in melee, though + const int skill_level = throwing_skill_adjusted( *this ); + for( damage_unit &du : proj.impact.damage_units ) { + du.res_pen += skill_level / 2.0f; + } + + int total_damage = 0; + for( damage_unit &du : proj.impact.damage_units ) { + total_damage += du.amount * du.damage_multiplier; + } + return total_damage; +} + +dealt_projectile_attack player::throw_item( const tripoint &target, const item &to_throw, + const cata::optional &blind_throw_from_pos ) +{ + // Copy the item, we may alter it before throwing + item thrown = to_throw; + + const int move_cost = throw_cost( *this, to_throw ); + mod_moves( -move_cost ); + + const int throwing_skill = get_skill_level( skill_throw ); + const units::volume volume = to_throw.volume(); + const units::mass weight = to_throw.weight(); + const cata::optional throw_assist = character_throw_assist( *this ); + + if( !throw_assist ) { + const int stamina_cost = get_standard_stamina_cost( &thrown ); + mod_stamina( stamina_cost + throwing_skill ); + } + + const int skill_level = throwing_skill_adjusted( *this ); + projectile proj = thrown_item_projectile( thrown ); + damage_instance &impact = proj.impact; + std::set &proj_effects = proj.proj_effects; + + const bool do_railgun = has_active_bionic( bio_railgun ) && thrown.made_of_any( ferric ) && + !throw_assist; + + impact.add_damage( damage_type::BASH, std::min( weight / 100.0_gram, + static_cast( thrown_item_adjusted_damage( thrown ) ) ) ); if( thrown.has_flag( flag_ACT_ON_RANGED_HIT ) ) { proj_effects.insert( "ACT_ON_RANGED_HIT" ); @@ -1096,7 +1146,7 @@ dealt_projectile_attack player::throw_item( const tripoint &target, const item & float range = rl_dist( throw_from, target ); proj.range = range; - int skill_lvl = get_skill_level( skill_used ); + int skill_lvl = get_skill_level( skill_throw ); // Avoid awarding tons of xp for lucky throws against hard to hit targets const float range_factor = std::min( range, skill_lvl + 3 ); // We're aiming to get a damaging hit, not just an accurate one - reward proper weapons @@ -1109,14 +1159,14 @@ dealt_projectile_attack player::throw_item( const tripoint &target, const item & const double missed_by = dealt_attack.missed_by; if( missed_by <= 0.1 && dealt_attack.hit_critter != nullptr ) { - practice( skill_used, final_xp_mult, MAX_SKILL ); + practice( skill_throw, final_xp_mult, MAX_SKILL ); // TODO: Check target for existence of head get_event_bus().send( getID() ); } else if( dealt_attack.hit_critter != nullptr && missed_by > 0.0f ) { - practice( skill_used, final_xp_mult / ( 1.0f + missed_by ), MAX_SKILL ); + practice( skill_throw, final_xp_mult / ( 1.0f + missed_by ), MAX_SKILL ); } else { // Pure grindy practice - cap gain at lvl 2 - practice( skill_used, 5, 2 ); + practice( skill_throw, 5, 2 ); } // Reset last target pos last_target_pos = cata::nullopt; diff --git a/tests/player_helpers.cpp b/tests/player_helpers.cpp index 6658c7490792f..58dc5de7b4914 100644 --- a/tests/player_helpers.cpp +++ b/tests/player_helpers.cpp @@ -116,6 +116,52 @@ void clear_character( player &dummy ) dummy.setpos( spot ); } +void arm_shooter( npc &shooter, const std::string &gun_type, + const std::vector &mods, + const std::string &ammo_type ) +{ + shooter.remove_weapon(); + // XL so arrows can fit. + if( !shooter.is_wearing( itype_id( "debug_backpack" ) ) ) { + shooter.worn.push_back( item( "debug_backpack" ) ); + } + + const itype_id &gun_id{ itype_id( gun_type ) }; + // Give shooter a loaded gun of the requested type. + item &gun = shooter.i_add( item( gun_id ) ); + itype_id ammo_id; + // if ammo is not supplied we want the default + if( ammo_type.empty() ) { + if( gun.ammo_default().is_null() ) { + ammo_id = item( gun.magazine_default() ).ammo_default(); + } else { + ammo_id = gun.ammo_default(); + } + } else { + ammo_id = itype_id( ammo_type ); + } + const ammotype &type_of_ammo = item::find_type( ammo_id )->ammo->type; + if( gun.magazine_integral() ) { + item &ammo = shooter.i_add( item( ammo_id, calendar::turn, gun.ammo_capacity( type_of_ammo ) ) ); + REQUIRE( gun.is_reloadable_with( ammo_id ) ); + REQUIRE( shooter.can_reload( gun, ammo_id ) ); + gun.reload( shooter, item_location( shooter, &ammo ), gun.ammo_capacity( type_of_ammo ) ); + } else { + const itype_id magazine_id = gun.magazine_default(); + item &magazine = shooter.i_add( item( magazine_id ) ); + item &ammo = shooter.i_add( item( ammo_id, calendar::turn, + magazine.ammo_capacity( type_of_ammo ) ) ); + REQUIRE( magazine.is_reloadable_with( ammo_id ) ); + REQUIRE( shooter.can_reload( magazine, ammo_id ) ); + magazine.reload( shooter, item_location( shooter, &ammo ), magazine.ammo_capacity( type_of_ammo ) ); + gun.reload( shooter, item_location( shooter, &magazine ), magazine.ammo_capacity( type_of_ammo ) ); + } + for( const auto &mod : mods ) { + gun.put_in( item( itype_id( mod ) ), item_pocket::pocket_type::MOD ); + } + shooter.wield( gun ); +} + void clear_avatar() { clear_character( get_avatar() ); diff --git a/tests/player_helpers.h b/tests/player_helpers.h index df2fecc801109..59e79903a0737 100644 --- a/tests/player_helpers.h +++ b/tests/player_helpers.h @@ -21,4 +21,8 @@ void give_and_activate_bionic( player &, bionic_id const & ); item tool_with_ammo( const std::string &tool, int qty ); +void arm_shooter( npc &shooter, const std::string &gun_type, + const std::vector &mods = {}, + const std::string &ammo_type = "" ); + #endif // CATA_TESTS_PLAYER_HELPERS_H diff --git a/tests/ranged_balance_test.cpp b/tests/ranged_balance_test.cpp index 32c3e64d6294e..40997377ae042 100644 --- a/tests/ranged_balance_test.cpp +++ b/tests/ranged_balance_test.cpp @@ -24,6 +24,7 @@ #include "map_helpers.h" #include "npc.h" #include "pimpl.h" +#include "player_helpers.h" #include "point.h" #include "ret_val.h" #include "test_statistics.h" @@ -76,52 +77,6 @@ std::ostream &operator<<( std::ostream &stream, const dispersion_sources &source return stream; } -static void arm_shooter( npc &shooter, const std::string &gun_type, - const std::vector &mods = {}, - const std::string &ammo_type = "" ) -{ - shooter.remove_weapon(); - // XL so arrows can fit. - if( !shooter.is_wearing( itype_id( "debug_backpack" ) ) ) { - shooter.worn.push_back( item( "debug_backpack" ) ); - } - - const itype_id &gun_id{ itype_id( gun_type ) }; - // Give shooter a loaded gun of the requested type. - item &gun = shooter.i_add( item( gun_id ) ); - itype_id ammo_id; - // if ammo is not supplied we want the default - if( ammo_type.empty() ) { - if( gun.ammo_default().is_null() ) { - ammo_id = item( gun.magazine_default() ).ammo_default(); - } else { - ammo_id = gun.ammo_default(); - } - } else { - ammo_id = itype_id( ammo_type ); - } - const ammotype &type_of_ammo = item::find_type( ammo_id )->ammo->type; - if( gun.magazine_integral() ) { - item &ammo = shooter.i_add( item( ammo_id, calendar::turn, gun.ammo_capacity( type_of_ammo ) ) ); - REQUIRE( gun.is_reloadable_with( ammo_id ) ); - REQUIRE( shooter.can_reload( gun, ammo_id ) ); - gun.reload( shooter, item_location( shooter, &ammo ), gun.ammo_capacity( type_of_ammo ) ); - } else { - const itype_id magazine_id = gun.magazine_default(); - item &magazine = shooter.i_add( item( magazine_id ) ); - item &ammo = shooter.i_add( item( ammo_id, calendar::turn, - magazine.ammo_capacity( type_of_ammo ) ) ); - REQUIRE( magazine.is_reloadable_with( ammo_id ) ); - REQUIRE( shooter.can_reload( magazine, ammo_id ) ); - magazine.reload( shooter, item_location( shooter, &ammo ), magazine.ammo_capacity( type_of_ammo ) ); - gun.reload( shooter, item_location( shooter, &magazine ), magazine.ammo_capacity( type_of_ammo ) ); - } - for( const auto &mod : mods ) { - gun.put_in( item( itype_id( mod ) ), item_pocket::pocket_type::MOD ); - } - shooter.wield( gun ); -} - static void equip_shooter( npc &shooter, const std::vector &apparel ) { CHECK( !shooter.in_vehicle ); From b3cc2773a8973b3256aa54fed534c9b50b89458b Mon Sep 17 00:00:00 2001 From: NeviNovat <51816321+NeviNovat@users.noreply.github.com> Date: Tue, 23 Feb 2021 09:54:12 +0200 Subject: [PATCH 237/453] Make acetylene torch cut metal walls. (#46255) --- src/activity_handlers.cpp | 4 ++++ src/iuse.cpp | 8 +++++--- src/mapdata.cpp | 4 ++++ src/mapdata.h | 2 ++ 4 files changed, 15 insertions(+), 3 deletions(-) diff --git a/src/activity_handlers.cpp b/src/activity_handlers.cpp index 07b87fc21484a..8deb436a90773 100644 --- a/src/activity_handlers.cpp +++ b/src/activity_handlers.cpp @@ -2299,6 +2299,10 @@ void activity_handlers::oxytorch_finish( player_activity *act, player *p ) here.ter_set( pos, t_mdoor_frame ); here.spawn_item( pos, itype_steel_plate, rng( 0, 1 ) ); here.spawn_item( pos, itype_steel_chunk, rng( 3, 8 ) ); + } else if( ter == t_wall_metal ) { + here.ter_set( pos, t_scrap_wall_halfway ); + here.spawn_item( pos, itype_steel_plate, rng( 2, 3 ) ); + here.spawn_item( pos, itype_steel_chunk, rng( 12, 20 ) ); } else if( ter == t_window_enhanced || ter == t_window_enhanced_noglass ) { here.ter_set( pos, t_window_empty ); here.spawn_item( pos, itype_steel_plate, rng( 0, 1 ) ); diff --git a/src/iuse.cpp b/src/iuse.cpp index 3e31ef343c070..6d9bee87a8ee8 100644 --- a/src/iuse.cpp +++ b/src/iuse.cpp @@ -5015,7 +5015,8 @@ cata::optional iuse::oxytorch( player *p, item *it, bool, const tripoint & t_metal_grate_window_with_curtain_open, t_metal_grate_window_noglass, t_metal_grate_window_with_curtain_noglass, - t_metal_grate_window_with_curtain_open_noglass + t_metal_grate_window_with_curtain_open_noglass, + t_wall_metal }; const std::set allowed_furn_id { f_rack, @@ -5070,8 +5071,9 @@ cata::optional iuse::oxytorch( player *p, item *it, bool, const tripoint & ter == t_metal_grate_window_with_curtain_open_noglass ) { turns = to_turns( 10_seconds ); } else if( ter == t_door_metal_locked || ter == t_door_metal_c || ter == t_door_bar_c || - ter == t_door_bar_locked || ter == t_door_metal_pickable || furn == f_safe_l || - furn == f_gunsafe_ml || furn == f_gunsafe_mj || furn == f_gun_safe_el ) { + ter == t_door_bar_locked || ter == t_door_metal_pickable || ter == t_wall_metal || + furn == f_safe_l || furn == f_gunsafe_ml || furn == f_gunsafe_mj || + furn == f_gun_safe_el ) { turns = to_turns( 15_seconds ); } else { return cata::nullopt; diff --git a/src/mapdata.cpp b/src/mapdata.cpp index 221ae0cabdacd..7b53b9bc9a32d 100644 --- a/src/mapdata.cpp +++ b/src/mapdata.cpp @@ -561,6 +561,8 @@ ter_id t_null, t_wall_half, t_wall_wood, t_wall_wood_chipped, t_wall_wood_broken, t_wall, t_concrete_wall, t_brick_wall, t_wall_metal, + t_scrap_wall, + t_scrap_wall_halfway, t_wall_glass, t_wall_glass_alarm, t_reinforced_glass, t_reinforced_glass_shutter, t_reinforced_glass_shutter_open, @@ -717,6 +719,8 @@ void set_ter_ids() t_concrete_wall = ter_id( "t_concrete_wall" ); t_brick_wall = ter_id( "t_brick_wall" ); t_wall_metal = ter_id( "t_wall_metal" ); + t_scrap_wall = ter_id( "t_scrap_wall" ); + t_scrap_wall_halfway = ter_id( "t_scrap_wall_halfway" ); t_wall_glass = ter_id( "t_wall_glass" ); t_wall_glass_alarm = ter_id( "t_wall_glass_alarm" ); t_reinforced_glass = ter_id( "t_reinforced_glass" ); diff --git a/src/mapdata.h b/src/mapdata.h index 0a704247ac7b0..65d6e89bb29f5 100644 --- a/src/mapdata.h +++ b/src/mapdata.h @@ -473,6 +473,8 @@ extern ter_id t_null, t_wall_half, t_wall_wood, t_wall_wood_chipped, t_wall_wood_broken, t_wall, t_concrete_wall, t_brick_wall, t_wall_metal, + t_scrap_wall, + t_scrap_wall_halfway, t_wall_glass, t_wall_glass_alarm, t_reinforced_glass, t_reinforced_glass_shutter, t_reinforced_glass_shutter_open, From ceacd058ebcadb5045316573902c25c69386498a Mon Sep 17 00:00:00 2001 From: Karol1223 <68503002+Karol1223@users.noreply.github.com> Date: Tue, 23 Feb 2021 08:55:42 +0100 Subject: [PATCH 238/453] Added disassembly recipes for several items (#46316) --- data/json/recipes/recipe_deconstruction.json | 167 +++++++++++++++++++ 1 file changed, 167 insertions(+) diff --git a/data/json/recipes/recipe_deconstruction.json b/data/json/recipes/recipe_deconstruction.json index 1243aac242b42..801331e7981a6 100644 --- a/data/json/recipes/recipe_deconstruction.json +++ b/data/json/recipes/recipe_deconstruction.json @@ -5025,5 +5025,172 @@ "time": "5 m", "qualities": [ { "id": "HAMMER", "level": 1 } ], "components": [ [ [ "material_rocksalt", 10 ] ] ] + }, + { + "result": "knife_butter", + "type": "uncraft", + "activity_level": "MODERATE_EXERCISE", + "time": "12 s", + "qualities": [ { "id": "HAMMER", "level": 1 } ], + "components": [ [ [ "scrap", 1 ] ] ] + }, + { + "result": "flask_hip", + "type": "uncraft", + "activity_level": "MODERATE_EXERCISE", + "time": "12 s", + "qualities": [ { "id": "HAMMER", "level": 1 } ], + "components": [ [ [ "scrap", 2 ] ] ] + }, + { + "result": "clamp", + "type": "uncraft", + "activity_level": "MODERATE_EXERCISE", + "time": "1 m", + "qualities": [ { "id": "HAMMER", "level": 1 }, { "id": "SAW_M", "level": 1 } ], + "components": [ [ [ "scrap", 6 ] ] ] + }, + { + "result": "e_tool", + "type": "uncraft", + "activity_level": "MODERATE_EXERCISE", + "time": "2 m", + "qualities": [ { "id": "SAW_M", "level": 1 } ], + "components": [ [ [ "sheet_metal_small", 2 ] ], [ [ "scrap", 2 ] ] ] + }, + { + "result": "harmonica_holder", + "type": "uncraft", + "activity_level": "MODERATE_EXERCISE", + "time": "12 s", + "qualities": [ { "id": "HAMMER", "level": 1 } ], + "components": [ [ [ "scrap", 2 ] ] ] + }, + { + "result": "coin_quarter", + "type": "uncraft", + "activity_level": "MODERATE_EXERCISE", + "time": "2 s", + "qualities": [ { "id": "HAMMER", "level": 1 } ], + "components": [ [ [ "silver_small", 5 ] ] ] + }, + { + "result": "coin_nickel", + "type": "uncraft", + "activity_level": "MODERATE_EXERCISE", + "time": "2 s", + "qualities": [ { "id": "HAMMER", "level": 1 } ], + "components": [ [ [ "copper", 5 ] ] ] + }, + { + "result": "spray_can", + "type": "uncraft", + "activity_level": "MODERATE_EXERCISE", + "time": "2 m", + "qualities": [ { "id": "SAW_M", "level": 1 } ], + "components": [ [ [ "sheet_metal_small", 1 ] ], [ [ "scrap", 1 ] ] ] + }, + { + "result": "can_medium", + "type": "uncraft", + "activity_level": "MODERATE_EXERCISE", + "time": "12 s", + "qualities": [ { "id": "HAMMER", "level": 1 } ], + "components": [ [ [ "scrap", 1 ] ] ] + }, + { + "result": "can_food_big", + "type": "uncraft", + "activity_level": "MODERATE_EXERCISE", + "time": "1 m", + "qualities": [ { "id": "SAW_M", "level": 1 } ], + "components": [ [ [ "sheet_metal_small", 2 ] ], [ [ "scrap", 3 ] ] ] + }, + { + "result": "multitool", + "type": "uncraft", + "activity_level": "MODERATE_EXERCISE", + "time": "40 s", + "qualities": [ { "id": "HAMMER", "level": 1 }, { "id": "SCREW", "level": 1 } ], + "components": [ [ [ "scrap", 3 ] ] ] + }, + { + "result": "thermos", + "type": "uncraft", + "activity_level": "MODERATE_EXERCISE", + "time": "2 m", + "qualities": [ { "id": "SAW_M", "level": 1 } ], + "components": [ [ [ "sheet_metal_small", 2 ] ] ] + }, + { + "result": "scissors", + "type": "uncraft", + "activity_level": "MODERATE_EXERCISE", + "time": "12 s", + "qualities": [ { "id": "HAMMER", "level": 1 } ], + "components": [ [ [ "scrap", 2 ] ] ] + }, + { + "result": "shavingkit", + "type": "uncraft", + "activity_level": "MODERATE_EXERCISE", + "time": "12 s", + "qualities": [ { "id": "HAMMER", "level": 1 } ], + "components": [ [ [ "plastic_chunk", 2 ] ] ] + }, + { + "result": "hammer", + "type": "uncraft", + "activity_level": "MODERATE_EXERCISE", + "time": "30 s", + "qualities": [ { "id": "HAMMER", "level": 1 } ], + "components": [ [ [ "splinter", 1 ] ], [ [ "steel_chunk", 2 ] ] ] + }, + { + "result": "tongs", + "type": "uncraft", + "activity_level": "MODERATE_EXERCISE", + "time": "2 m", + "qualities": [ { "id": "HAMMER", "level": 1 }, { "id": "SAW_M", "level": 1 } ], + "components": [ [ [ "steel_chunk", 2 ] ] ] + }, + { + "result": "umbrella", + "type": "uncraft", + "activity_level": "MODERATE_EXERCISE", + "time": "1 m", + "qualities": [ { "id": "CUT", "level": 1 } ], + "components": [ [ [ "plastic_chunk", 2 ] ] ] + }, + { + "result": "mask_dust", + "type": "uncraft", + "activity_level": "LIGHT_EXERCISE", + "time": "12 s", + "components": [ [ [ "string_6", 1 ] ], [ [ "rag", 1 ] ] ] + }, + { + "result": "horn_bicycle", + "type": "uncraft", + "activity_level": "MODERATE_EXERCISE", + "time": "12 s", + "qualities": [ { "id": "CUT", "level": 1 } ], + "components": [ [ [ "plastic_chunk", 3 ] ] ] + }, + { + "result": "cards_magic", + "type": "uncraft", + "activity_level": "NO_EXERCISE", + "time": "2 s", + "components": [ [ [ "paper", 20 ] ] ], + "flags": [ "BLIND_EASY" ] + }, + { + "result": "webbing_belt", + "type": "uncraft", + "activity_level": "LIGHT_EXERCISE", + "time": "30 s", + "qualities": [ { "id": "CUT", "level": 1 } ], + "components": [ [ [ "nylon", 3 ] ], [ [ "scrap", 1 ] ] ] } ] From 8f4b95fc4d099eaaa04115b73b07a932f889cc95 Mon Sep 17 00:00:00 2001 From: Hirmuolio <22011552+Hirmuolio@users.noreply.github.com> Date: Tue, 23 Feb 2021 09:57:15 +0200 Subject: [PATCH 239/453] Celsius temperature for freezing point (#47028) --- data/json/items/chemicals_and_resources.json | 8 +- data/json/items/classes/comestible.json | 2 +- data/json/items/comestibles/alcohol.json | 94 +++++++++---------- data/json/items/comestibles/drink.json | 2 +- data/json/items/comestibles/drink_other.json | 10 +- data/json/items/comestibles/egg.json | 2 +- data/json/items/comestibles/junkfood.json | 2 +- data/json/items/comestibles/med.json | 2 +- data/json/items/comestibles/mutagen.json | 2 +- data/json/items/comestibles/nuts.json | 2 +- data/json/items/comestibles/other.json | 18 ++-- data/json/items/comestibles/protein.json | 2 +- data/json/items/comestibles/seed.json | 2 +- data/json/items/comestibles/spice.json | 4 +- data/mods/Magiclysm/items/alchemy_items.json | 2 +- .../Magiclysm/items/cast_spell_items.json | 6 +- data/mods/Magiclysm/items/mutagen.json | 2 +- data/mods/TEST_DATA/items.json | 2 +- doc/JSON_INFO.md | 4 +- src/cata_utility.cpp | 5 + src/cata_utility.h | 7 ++ src/item.cpp | 10 +- src/item.h | 2 +- src/itype.h | 4 +- src/material.cpp | 4 +- src/material.h | 4 +- 26 files changed, 108 insertions(+), 96 deletions(-) diff --git a/data/json/items/chemicals_and_resources.json b/data/json/items/chemicals_and_resources.json index 02431bc4db41e..5608d816e56a5 100644 --- a/data/json/items/chemicals_and_resources.json +++ b/data/json/items/chemicals_and_resources.json @@ -224,7 +224,7 @@ "charges": 2, "category": "chems", "fun": -30, - "freezing_point": 17, + "freezing_point": -8, "conditional_names": [ { "type": "FLAG", "condition": "DIRTY", "name": "bleach spill" } ] }, { @@ -248,7 +248,7 @@ "charges": 2, "category": "chems", "fun": -30, - "freezing_point": -108 + "freezing_point": -78 }, { "type": "COMESTIBLE", @@ -365,7 +365,7 @@ "volume": "250 ml", "phase": "liquid", "category": "chems", - "freezing_point": 28, + "freezing_point": -2, "fun": -1 }, { @@ -386,7 +386,7 @@ "volume": "250 ml", "phase": "liquid", "category": "chems", - "freezing_point": 28, + "freezing_point": -2, "fun": -1 }, { diff --git a/data/json/items/classes/comestible.json b/data/json/items/classes/comestible.json index 7bf287864d6b2..f7401bdd4c5e7 100644 --- a/data/json/items/classes/comestible.json +++ b/data/json/items/classes/comestible.json @@ -13,6 +13,6 @@ "material": [ "powder" ], "symbol": "%", "charges": 100, - "freezing_point": -459 + "freezing_point": -274 } ] diff --git a/data/json/items/comestibles/alcohol.json b/data/json/items/comestibles/alcohol.json index f1ae939e677a8..6616bfec72467 100644 --- a/data/json/items/comestibles/alcohol.json +++ b/data/json/items/comestibles/alcohol.json @@ -24,7 +24,7 @@ "charges": 5, "flags": [ "EATEN_COLD", "MYCUS_OK" ], "fun": 25, - "freezing_point": 17 + "freezing_point": -8 }, { "type": "COMESTIBLE", @@ -52,7 +52,7 @@ "charges": 5, "flags": [ "EATEN_COLD" ], "fun": 15, - "freezing_point": 17 + "freezing_point": -8 }, { "type": "COMESTIBLE", @@ -80,7 +80,7 @@ "charges": 5, "flags": [ "EATEN_COLD" ], "fun": 15, - "freezing_point": 17 + "freezing_point": -8 }, { "type": "COMESTIBLE", @@ -106,7 +106,7 @@ "phase": "liquid", "charges": 5, "fun": 15, - "freezing_point": 17 + "freezing_point": -8 }, { "type": "COMESTIBLE", @@ -133,7 +133,7 @@ "charges": 5, "flags": [ "EATEN_COLD" ], "fun": 16, - "freezing_point": 15 + "freezing_point": -9 }, { "type": "COMESTIBLE", @@ -160,7 +160,7 @@ "charges": 5, "flags": [ "EATEN_COLD" ], "fun": 15, - "freezing_point": 17 + "freezing_point": -8 }, { "type": "COMESTIBLE", @@ -187,7 +187,7 @@ "charges": 5, "flags": [ "EATEN_COLD" ], "fun": 15, - "freezing_point": 17 + "freezing_point": -8 }, { "type": "COMESTIBLE", @@ -213,7 +213,7 @@ "volume": "250 ml", "phase": "liquid", "flags": [ "EATEN_COLD" ], - "freezing_point": 23, + "freezing_point": -5, "fun": 14, "vitamins": [ [ "calcium", 1 ] ] }, @@ -240,7 +240,7 @@ "material": [ "alcohol" ], "volume": "250 ml", "flags": [ "EATEN_COLD" ], - "freezing_point": -22, + "freezing_point": -30, "phase": "liquid", "charges": 7, "fun": 15 @@ -269,7 +269,7 @@ "phase": "liquid", "charges": 7, "flags": [ "EATEN_COLD", "NUTRIENT_OVERRIDE" ], - "freezing_point": -22, + "freezing_point": -30, "fun": 15 }, { @@ -296,7 +296,7 @@ "phase": "liquid", "charges": 7, "flags": [ "EATEN_COLD" ], - "freezing_point": -22, + "freezing_point": -30, "fun": 15 }, { @@ -324,7 +324,7 @@ "charges": 7, "fun": 15, "flags": [ "EATEN_COLD" ], - "freezing_point": -22 + "freezing_point": -30 }, { "type": "COMESTIBLE", @@ -351,7 +351,7 @@ "charges": 7, "fun": 18, "flags": [ "EATEN_COLD" ], - "freezing_point": -22 + "freezing_point": -30 }, { "type": "COMESTIBLE", @@ -375,7 +375,7 @@ "material": [ "alcohol" ], "volume": "250 ml", "flags": [ "EDIBLE_FROZEN" ], - "freezing_point": 0, + "freezing_point": -17, "phase": "liquid", "charges": 7, "fun": 10 @@ -407,7 +407,7 @@ "charges": 7, "flags": [ "EATEN_COLD" ], "fun": 10, - "freezing_point": 22 + "freezing_point": -6 }, { "type": "COMESTIBLE", @@ -433,7 +433,7 @@ "phase": "liquid", "charges": 7, "flags": [ "EATEN_COLD" ], - "freezing_point": -22, + "freezing_point": -30, "fun": 5 }, { @@ -461,7 +461,7 @@ "volume": "250 ml", "phase": "liquid", "flags": [ "EATEN_COLD", "NUTRIENT_OVERRIDE" ], - "freezing_point": -22, + "freezing_point": -30, "fun": 4 }, { @@ -490,7 +490,7 @@ "charges": 7, "flags": [ "EATEN_COLD" ], "fun": 2, - "freezing_point": 20 + "freezing_point": -7 }, { "type": "COMESTIBLE", @@ -514,7 +514,7 @@ "material": [ "alcohol" ], "volume": "250 ml", "flags": [ "EATEN_COLD" ], - "freezing_point": -22, + "freezing_point": -30, "phase": "liquid", "charges": 7, "fun": 12 @@ -597,7 +597,7 @@ "volume": "250 ml", "phase": "liquid", "flags": [ "EATEN_COLD" ], - "freezing_point": -29, + "freezing_point": -34, "fun": 20, "vitamins": [ [ "vitA", 2 ], [ "vitC", 118 ], [ "calcium", 2 ], [ "iron", 1 ] ] }, @@ -625,7 +625,7 @@ "volume": "250 ml", "phase": "liquid", "flags": [ "EATEN_COLD" ], - "freezing_point": -29, + "freezing_point": -34, "fun": 20, "vitamins": [ [ "vitC", 135 ], [ "calcium", 1 ], [ "iron", 1 ] ] }, @@ -653,7 +653,7 @@ "volume": "250 ml", "phase": "liquid", "flags": [ "EATEN_COLD" ], - "freezing_point": -22, + "freezing_point": -30, "fun": 20 }, { @@ -679,7 +679,7 @@ "volume": "250 ml", "phase": "liquid", "flags": [ "EATEN_COLD" ], - "freezing_point": 23, + "freezing_point": -5, "fun": 10, "vitamins": [ [ "calcium", 1 ] ] }, @@ -707,7 +707,7 @@ "phase": "liquid", "charges": 7, "flags": [ "EATEN_COLD" ], - "freezing_point": 23, + "freezing_point": -5, "fun": 14 }, { @@ -736,7 +736,7 @@ "charges": 7, "flags": [ "EATEN_COLD" ], "fun": 16, - "freezing_point": 25 + "freezing_point": -4 }, { "type": "COMESTIBLE", @@ -763,7 +763,7 @@ "charges": 7, "flags": [ "EATEN_COLD" ], "fun": 16, - "freezing_point": 25 + "freezing_point": -4 }, { "type": "COMESTIBLE", @@ -790,7 +790,7 @@ "phase": "liquid", "charges": 7, "flags": [ "EATEN_COLD" ], - "freezing_point": 23, + "freezing_point": -5, "fun": 12 }, { @@ -817,7 +817,7 @@ "volume": "250 ml", "phase": "liquid", "flags": [ "EATEN_COLD" ], - "freezing_point": 23, + "freezing_point": -5, "fun": 8, "vitamins": [ [ "calcium", 1 ] ] }, @@ -846,7 +846,7 @@ "phase": "liquid", "charges": 7, "flags": [ "EATEN_COLD" ], - "freezing_point": -49, + "freezing_point": -45, "fun": 12 }, { @@ -873,7 +873,7 @@ "volume": "250 ml", "phase": "liquid", "flags": [ "EATEN_COLD" ], - "freezing_point": 23, + "freezing_point": -5, "fun": 10, "vitamins": [ [ "calcium", 1 ] ] }, @@ -901,7 +901,7 @@ "volume": "250 ml", "phase": "liquid", "flags": [ "EATEN_COLD" ], - "freezing_point": 23, + "freezing_point": -5, "fun": 14, "vitamins": [ [ "calcium", 1 ] ] }, @@ -929,7 +929,7 @@ "volume": "250 ml", "phase": "liquid", "flags": [ "EATEN_COLD" ], - "freezing_point": 23, + "freezing_point": -5, "fun": 14, "vitamins": [ [ "calcium", 1 ] ] }, @@ -956,7 +956,7 @@ "primary_material": "alcohol", "volume": "250 ml", "phase": "liquid", - "freezing_point": 23, + "freezing_point": -5, "fun": 14, "vitamins": [ [ "calcium", 1 ], [ "iron", 1 ] ], "flags": [ "EATEN_COLD" ] @@ -985,7 +985,7 @@ "volume": "250 ml", "phase": "liquid", "flags": [ "EATEN_COLD" ], - "freezing_point": 23, + "freezing_point": -5, "fun": 14, "vitamins": [ [ "calcium", 1 ] ] }, @@ -1015,7 +1015,7 @@ "fun": 18, "vitamins": [ [ "calcium", 1 ], [ "iron", 1 ] ], "flags": [ "EATEN_COLD" ], - "freezing_point": 23 + "freezing_point": -5 }, { "type": "COMESTIBLE", @@ -1044,7 +1044,7 @@ "flags": [ "EATEN_COLD", "EDIBLE_FROZEN" ], "fun": 8, "vitamins": [ [ "vitC", 20 ] ], - "freezing_point": -22 + "freezing_point": -30 }, { "type": "COMESTIBLE", @@ -1073,7 +1073,7 @@ "flags": [ "EATEN_COLD", "EDIBLE_FROZEN" ], "fun": -12, "vitamins": [ [ "vitC", 20 ] ], - "freezing_point": -22 + "freezing_point": -30 }, { "type": "COMESTIBLE", @@ -1098,7 +1098,7 @@ "material": [ "alcohol" ], "volume": "250 ml", "flags": [ "EATEN_COLD" ], - "freezing_point": -22, + "freezing_point": -30, "phase": "liquid", "charges": 7, "fun": 17 @@ -1155,7 +1155,7 @@ "material": [ "alcohol" ], "volume": "250 ml", "flags": [ "EATEN_COLD" ], - "freezing_point": -22, + "freezing_point": -30, "phase": "liquid", "charges": 7, "fun": 17 @@ -1205,7 +1205,7 @@ "phase": "liquid", "charges": 5, "flags": [ "EATEN_COLD" ], - "freezing_point": -27, + "freezing_point": -33, "fun": 20 }, { @@ -1233,7 +1233,7 @@ "phase": "liquid", "charges": 2, "flags": [ "EATEN_COLD" ], - "freezing_point": -22, + "freezing_point": -30, "fun": 20 }, { @@ -1259,7 +1259,7 @@ "volume": "500 ml", "phase": "liquid", "flags": [ "EATEN_COLD" ], - "freezing_point": -22, + "freezing_point": -30, "fun": 20 }, { @@ -1285,7 +1285,7 @@ "volume": "250 ml", "phase": "liquid", "flags": [ "EATEN_COLD" ], - "freezing_point": -22, + "freezing_point": -30, "fun": 20 }, { @@ -1368,7 +1368,7 @@ "flags": [ "EATEN_COLD", "FREEZERBURN" ], "fun": 20, "vitamins": [ [ "vitA", 5 ], [ "vitC", 3 ], [ "calcium", 12 ], [ "iron", 2 ] ], - "freezing_point": 12 + "freezing_point": -11 }, { "type": "COMESTIBLE", @@ -1394,7 +1394,7 @@ "charges": 5, "phase": "liquid", "flags": [ "EATEN_COLD" ], - "freezing_point": -22, + "freezing_point": -30, "fun": 20 }, { @@ -1421,7 +1421,7 @@ "volume": "250 ml", "phase": "liquid", "flags": [ "EATEN_COLD" ], - "freezing_point": -29, + "freezing_point": -34, "fun": 25, "vitamins": [ [ "vitA", 2 ], [ "vitC", 23 ], [ "calcium", 1 ], [ "iron", 2 ] ] }, @@ -1449,7 +1449,7 @@ "volume": "250 ml", "phase": "liquid", "flags": [ "EATEN_COLD" ], - "freezing_point": 23, + "freezing_point": -5, "fun": 10, "vitamins": [ [ "calcium", 1 ] ] } diff --git a/data/json/items/comestibles/drink.json b/data/json/items/comestibles/drink.json index 86ac6d0e05ebd..767e3acc26509 100644 --- a/data/json/items/comestibles/drink.json +++ b/data/json/items/comestibles/drink.json @@ -1013,7 +1013,7 @@ "volume": "250 ml", "phase": "liquid", "fun": 2, - "freezing_point": 22 + "freezing_point": -5 }, { "type": "COMESTIBLE", diff --git a/data/json/items/comestibles/drink_other.json b/data/json/items/comestibles/drink_other.json index 153549c05982e..e5cb02f33e9f8 100644 --- a/data/json/items/comestibles/drink_other.json +++ b/data/json/items/comestibles/drink_other.json @@ -46,7 +46,7 @@ "flags": [ "EATEN_COLD", "RAW" ], "phase": "liquid", "vitamins": [ ], - "freezing_point": 30 + "freezing_point": -1 }, { "id": "mayonnaise", @@ -69,7 +69,7 @@ "fun": -1, "flags": [ "FREEZERBURN" ], "phase": "liquid", - "freezing_point": 25 + "freezing_point": -4 }, { "id": "ketchup", @@ -155,7 +155,7 @@ "phase": "liquid", "charges": 16, "fun": -4, - "freezing_point": 28 + "freezing_point": -2 }, { "type": "COMESTIBLE", @@ -179,7 +179,7 @@ "fun": -25, "flags": [ "NUTRIENT_OVERRIDE" ], "vitamins": [ ], - "freezing_point": 14 + "freezing_point": -26 }, { "type": "COMESTIBLE", @@ -213,7 +213,7 @@ "fun": 2, "flags": [ "USE_EAT_VERB" ], "vitamins": [ [ "calcium", 18 ], [ "iron", 23 ] ], - "freezing_point": -20 + "freezing_point": -29 }, { "id": "horseradish", diff --git a/data/json/items/comestibles/egg.json b/data/json/items/comestibles/egg.json index f6e1070108758..5d17be2fbaa06 100644 --- a/data/json/items/comestibles/egg.json +++ b/data/json/items/comestibles/egg.json @@ -303,7 +303,7 @@ "flags": [ "EDIBLE_FROZEN" ], "charges": 16, "fun": -4, - "freezing_point": -459, + "freezing_point": -274, "vitamins": [ [ "vitB", 2 ] ] }, { diff --git a/data/json/items/comestibles/junkfood.json b/data/json/items/comestibles/junkfood.json index 4831417945a6c..f3288ba8378ac 100644 --- a/data/json/items/comestibles/junkfood.json +++ b/data/json/items/comestibles/junkfood.json @@ -518,7 +518,7 @@ "charges": 16, "fun": 5, "vitamins": [ [ "calcium", 2 ] ], - "freezing_point": -70 + "freezing_point": -57 }, { "type": "COMESTIBLE", diff --git a/data/json/items/comestibles/med.json b/data/json/items/comestibles/med.json index a43233a3f92f3..c2d2c1cace9a0 100644 --- a/data/json/items/comestibles/med.json +++ b/data/json/items/comestibles/med.json @@ -438,7 +438,7 @@ "phase": "liquid", "charges": 4, "flags": [ "EATEN_COLD" ], - "freezing_point": -49, + "freezing_point": -45, "fun": 30 }, { diff --git a/data/json/items/comestibles/mutagen.json b/data/json/items/comestibles/mutagen.json index c61ea57a91b56..c17dbe2d332bf 100644 --- a/data/json/items/comestibles/mutagen.json +++ b/data/json/items/comestibles/mutagen.json @@ -21,7 +21,7 @@ "flags": [ "NUTRIENT_OVERRIDE" ], "vitamins": [ ], "material": [ "water" ], - "freezing_point": 17 + "freezing_point": -8 }, { "abstract": "iv_mutagen_flavor", diff --git a/data/json/items/comestibles/nuts.json b/data/json/items/comestibles/nuts.json index cc75f8256ba3e..c141fc7c2045c 100644 --- a/data/json/items/comestibles/nuts.json +++ b/data/json/items/comestibles/nuts.json @@ -428,7 +428,7 @@ "charges": 4, "flags": [ "EATEN_HOT" ], "fun": 5, - "freezing_point": -80 + "freezing_point": -62 }, { "id": "peanutbutter", diff --git a/data/json/items/comestibles/other.json b/data/json/items/comestibles/other.json index 7fff34d328366..7aea6e36a17d6 100644 --- a/data/json/items/comestibles/other.json +++ b/data/json/items/comestibles/other.json @@ -284,7 +284,7 @@ "price_postapoc": 0, "material": [ "paper" ], "volume": "250 ml", - "freezing_point": -459, + "freezing_point": -274, "charges": 50, "fun": -20 }, @@ -303,7 +303,7 @@ "price_postapoc": 0, "material": [ "cardboard" ], "volume": "250 ml", - "freezing_point": -459, + "freezing_point": -274, "charges": 10, "fun": -20 }, @@ -570,7 +570,7 @@ "calories": 2, "charges": 20, "fun": -5, - "freezing_point": -459 + "freezing_point": -274 }, { "type": "COMESTIBLE", @@ -667,7 +667,7 @@ "calories": 170, "vitamins": [ [ "vitA", 20 ], [ "vitC", 45 ], [ "calcium", 5 ], [ "iron", 5 ] ], "fun": 5, - "freezing_point": -459, + "freezing_point": -274, "color": "brown", "flags": [ "INEDIBLE", "CATTLE" ], "use_action": [ "CATTLEFODDER" ] @@ -689,7 +689,7 @@ "calories": 400, "vitamins": [ [ "calcium", 1 ], [ "iron", 7 ] ], "fun": 5, - "freezing_point": -459, + "freezing_point": -274, "color": "brown", "flags": [ "INEDIBLE", "BIRD", "NUTRIENT_OVERRIDE" ], "use_action": [ "BIRDFOOD" ] @@ -738,7 +738,7 @@ "calories": 380, "vitamins": [ [ "vitA", 25 ], [ "iron", 25 ], [ "vitB", 20 ], [ "calcium", 30 ] ], "fun": -15, - "freezing_point": -459, + "freezing_point": -274, "color": "brown", "flags": [ "LUPINE" ], "use_action": [ "DOGFOOD" ] @@ -787,7 +787,7 @@ "calories": 380, "vitamins": [ [ "vitA", 25 ], [ "iron", 25 ], [ "vitB", 20 ], [ "calcium", 30 ] ], "fun": -15, - "freezing_point": -459, + "freezing_point": -274, "color": "brown", "flags": [ "FELINE" ], "use_action": [ "CATFOOD" ] @@ -856,7 +856,7 @@ "material": [ "paper" ], "price": 50, "price_postapoc": 200, - "freezing_point": -459, + "freezing_point": -274, "description": "A paper sachet with tea leaves inside. Put it into boiling water to make a cup of black tea." }, { @@ -910,7 +910,7 @@ "material": [ "plastic" ], "price": 50, "price_postapoc": 200, - "freezing_point": -459, + "freezing_point": -274, "description": "A small packet of commercial instant coffee powder. No creamer or sweetener added." }, { diff --git a/data/json/items/comestibles/protein.json b/data/json/items/comestibles/protein.json index e2606881a9660..c53ec23f5d907 100644 --- a/data/json/items/comestibles/protein.json +++ b/data/json/items/comestibles/protein.json @@ -51,7 +51,7 @@ "color": "white", "container": "bottle_plastic_small", "calories": 100, - "freezing_point": -459, + "freezing_point": -274, "vitamins": [ ] }, { diff --git a/data/json/items/comestibles/seed.json b/data/json/items/comestibles/seed.json index 9d1470d6ff7c9..8baf3413c641b 100644 --- a/data/json/items/comestibles/seed.json +++ b/data/json/items/comestibles/seed.json @@ -678,7 +678,7 @@ "primary_material": "dried_vegetable", "volume": "250 ml", "flags": [ "SMOKED" ], - "freezing_point": -459, + "freezing_point": -274, "charges": 4, "fun": 3 }, diff --git a/data/json/items/comestibles/spice.json b/data/json/items/comestibles/spice.json index bfc6cd92eb589..9afad56556cdf 100644 --- a/data/json/items/comestibles/spice.json +++ b/data/json/items/comestibles/spice.json @@ -19,7 +19,7 @@ "volume": "250 ml", "color": "red", "primary_material": "water", - "freezing_point": -22, + "freezing_point": -30, "phase": "liquid" }, { @@ -142,7 +142,7 @@ "charges": 10, "healthy": -1, "fun": -15, - "freezing_point": -22, + "freezing_point": -30, "phase": "liquid" }, { diff --git a/data/mods/Magiclysm/items/alchemy_items.json b/data/mods/Magiclysm/items/alchemy_items.json index 44c9abcd4c0b8..b9ee2454e18ef 100644 --- a/data/mods/Magiclysm/items/alchemy_items.json +++ b/data/mods/Magiclysm/items/alchemy_items.json @@ -176,7 +176,7 @@ "container": "flask_glass", "charges": 1, "phase": "liquid", - "freezing_point": -100 + "freezing_point": -73 }, { "id": "stirge_proboscis", diff --git a/data/mods/Magiclysm/items/cast_spell_items.json b/data/mods/Magiclysm/items/cast_spell_items.json index 8ebb9e3283124..bd5f1a5a49a02 100644 --- a/data/mods/Magiclysm/items/cast_spell_items.json +++ b/data/mods/Magiclysm/items/cast_spell_items.json @@ -19,7 +19,7 @@ "flags": [ "EATEN_COLD", "NUTRIENT_OVERRIDE" ], "phase": "liquid", "price": 2500, - "freezing_point": 40 + "freezing_point": 4 }, { "id": "mana_potion", @@ -56,7 +56,7 @@ "flags": [ "EATEN_COLD", "NUTRIENT_OVERRIDE" ], "phase": "liquid", "price": 3000, - "freezing_point": 40 + "freezing_point": 4 }, { "id": "ogres_strength_potion", @@ -139,7 +139,7 @@ "flags": [ "TRADER_AVOID", "NUTRIENT_OVERRIDE" ], "phase": "liquid", "price": 2500, - "freezing_point": 10 + "freezing_point": -12 }, { "id": "twisted_restore_potion_improved", diff --git a/data/mods/Magiclysm/items/mutagen.json b/data/mods/Magiclysm/items/mutagen.json index 5e12fc705c9a1..b7dcd25032157 100644 --- a/data/mods/Magiclysm/items/mutagen.json +++ b/data/mods/Magiclysm/items/mutagen.json @@ -20,7 +20,7 @@ "charges": 2, "use_action": { "type": "mutagen_iv", "mutation_category": "MANATOUCHED" }, "flags": [ "EATEN_COLD", "NUTRIENT_OVERRIDE" ], - "freezing_point": -22, + "freezing_point": -30, "fun": -15 }, { diff --git a/data/mods/TEST_DATA/items.json b/data/mods/TEST_DATA/items.json index e3b6be5073653..3fd587bede745 100644 --- a/data/mods/TEST_DATA/items.json +++ b/data/mods/TEST_DATA/items.json @@ -1341,7 +1341,7 @@ "charges": 7, "flags": [ "EATEN_COLD" ], "fun": -5, - "freezing_point": 20 + "freezing_point": -7 }, { "id": "test_nuclear_carafe", diff --git a/doc/JSON_INFO.md b/doc/JSON_INFO.md index 36e76dc71bfc0..0db98fd82ecb9 100644 --- a/doc/JSON_INFO.md +++ b/doc/JSON_INFO.md @@ -829,7 +829,7 @@ When you sort your inventory by category, these are the categories that are disp | `specific_heat_liquid` | Specific heat of a material when not frozen (J/(g K)). Default 4.186. | `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 ). +| `freezing_point` | Freezing point of this material (C). Default 0 C ( 32 F ). | `edible` | Optional boolean. Default is false. | `rotting` | Optional boolean. Default is false. | `soft` | Optional boolean. Default is false. @@ -2596,7 +2596,7 @@ CBMs can be defined like this: "charges" : 4, // Number of uses when spawned "stack_size" : 8, // (Optional) How many uses are in the above-defined volume. If omitted, is the same as 'charges' "fun" : 50 // Morale effects when used -"freezing_point": 32, // (Optional) Temperature in F at which item freezes, default is water (32F/0C) +"freezing_point": 32, // (Optional) Temperature in C at which item freezes, default is water (32F/0C) "cooks_like": "meat_cooked", // (Optional) If the item is used in a recipe, replaces it with its cooks_like "parasites": 10, // (Optional) Probability of becoming parasitised when eating "contamination": [ { "disease": "bad_food", "probability": 5 } ], // (Optional) List of diseases carried by this comestible and their associated probability. Values must be in the [0, 100] range. diff --git a/src/cata_utility.cpp b/src/cata_utility.cpp index 55423a14645a9..93926db360f9f 100644 --- a/src/cata_utility.cpp +++ b/src/cata_utility.cpp @@ -214,6 +214,11 @@ double temp_to_kelvin( double fahrenheit ) return temp_to_celsius( fahrenheit ) + 273.15; } +double celsius_to_kelvin( double celsius ) +{ + return celsius + 273.15; +} + double kelvin_to_fahrenheit( double kelvin ) { return 1.8 * ( kelvin - 273.15 ) + 32; diff --git a/src/cata_utility.h b/src/cata_utility.h index 182156cb70c1d..7ca37e414ded5 100644 --- a/src/cata_utility.h +++ b/src/cata_utility.h @@ -199,6 +199,13 @@ double temp_to_celsius( double fahrenheit ); */ double temp_to_kelvin( double fahrenheit ); +/** + * Convert a temperature from degrees Celsius to Kelvin. + * + * @return Temperature in degrees K. + */ +double celsius_to_kelvin( double celsius ); + /** * Convert a temperature from Kelvin to degrees Fahrenheit. * diff --git a/src/item.cpp b/src/item.cpp index 0f3829f5837ec..e81a28752e244 100644 --- a/src/item.cpp +++ b/src/item.cpp @@ -1802,7 +1802,7 @@ void item::debug_info( std::vector &info, const iteminfo_query *parts, iteminfo::lower_is_better, get_latent_heat() ) ); info.push_back( iteminfo( "BASE", _( "Freeze point: " ), "", - iteminfo::lower_is_better, + iteminfo::lower_is_better | iteminfo::is_decimal, get_freeze_point() ) ); } } @@ -8807,7 +8807,7 @@ void item::set_item_specific_energy( const float new_specific_energy ) const float specific_heat_liquid = get_specific_heat_liquid(); // J/g K const float specific_heat_solid = get_specific_heat_solid(); // J/g K const float latent_heat = get_latent_heat(); // J/kg - const float freezing_temperature = temp_to_kelvin( get_freeze_point() ); // K + const float freezing_temperature = celsius_to_kelvin( get_freeze_point() ); // K const float completely_frozen_specific_energy = specific_heat_solid * freezing_temperature; // Energy that the item would have if it was completely solid at freezing temperature const float completely_liquid_specific_energy = completely_frozen_specific_energy + @@ -8870,7 +8870,7 @@ float item::get_specific_energy_from_temperature( const float new_temperature ) const float specific_heat_liquid = get_specific_heat_liquid(); // J/g K const float specific_heat_solid = get_specific_heat_solid(); // J/g K const float latent_heat = get_latent_heat(); // J/kg - const float freezing_temperature = temp_to_kelvin( get_freeze_point() ); // K + const float freezing_temperature = celsius_to_kelvin( get_freeze_point() ); // K const float completely_frozen_energy = specific_heat_solid * freezing_temperature; // Energy that the item would have if it was completely solid at freezing temperature const float completely_liquid_energy = completely_frozen_energy + @@ -8888,7 +8888,7 @@ float item::get_specific_energy_from_temperature( const float new_temperature ) void item::set_item_temperature( float new_temperature ) { - const float freezing_temperature = temp_to_kelvin( get_freeze_point() ); // K + const float freezing_temperature = celsius_to_kelvin( get_freeze_point() ); // K const float specific_heat_solid = get_specific_heat_solid(); // J/g K const float latent_heat = get_latent_heat(); // J/kg @@ -9530,7 +9530,7 @@ void item::calc_temp( const int temp, const float insulation, const time_duratio const float specific_heat_liquid = get_specific_heat_liquid(); const float specific_heat_solid = get_specific_heat_solid(); const float latent_heat = get_latent_heat(); - const float freezing_temperature = temp_to_kelvin( get_freeze_point() ); // K + const float freezing_temperature = celsius_to_kelvin( get_freeze_point() ); // K const float completely_frozen_specific_energy = specific_heat_solid * freezing_temperature; // Energy that the item would have if it was completely solid at freezing temperature const float completely_liquid_specific_energy = completely_frozen_specific_energy + diff --git a/src/item.h b/src/item.h index 6f5064ce44ad8..b0860f2b93334 100644 --- a/src/item.h +++ b/src/item.h @@ -1245,7 +1245,7 @@ class item : public visitable float get_specific_heat_liquid() const; float get_specific_heat_solid() const; float get_latent_heat() const; - float get_freeze_point() const; // Fahrenheit + float get_freeze_point() const; // Celsius // If this is food, returns itself. If it contains food, return that // contents. Otherwise, returns nullptr. diff --git a/src/itype.h b/src/itype.h index a4894e37834ba..471013f573dc6 100644 --- a/src/itype.h +++ b/src/itype.h @@ -161,8 +161,8 @@ struct islot_comestible { /**Amount of radiation you get from this comestible*/ int radiation = 0; - /** freezing point in degrees Fahrenheit, below this temperature item can freeze */ - int freeze_point = temperatures::freezing; + /** freezing point in degrees celsius, below this temperature item can freeze */ + float freeze_point = 0; /**List of diseases carried by this comestible and their associated probability*/ std::map contamination; diff --git a/src/material.cpp b/src/material.cpp index 32e8cbf57e267..54a6d9f01bf2b 100644 --- a/src/material.cpp +++ b/src/material.cpp @@ -68,7 +68,7 @@ void material_type::load( const JsonObject &jsobj, const std::string & ) optional( jsobj, was_loaded, "specific_heat_liquid", _specific_heat_liquid ); optional( jsobj, was_loaded, "specific_heat_solid", _specific_heat_solid ); optional( jsobj, was_loaded, "latent_heat", _latent_heat ); - optional( jsobj, was_loaded, "freeze_point", _freeze_point ); + optional( jsobj, was_loaded, "freezing_point", _freeze_point ); assign( jsobj, "salvaged_into", _salvaged_into ); optional( jsobj, was_loaded, "repaired_with", _repaired_with, itype_id::NULL_ID() ); @@ -227,7 +227,7 @@ float material_type::latent_heat() const return _latent_heat; } -int material_type::freeze_point() const +float material_type::freeze_point() const { return _freeze_point; } diff --git a/src/material.h b/src/material.h index c20e83c02128f..5ecd0914e34c8 100644 --- a/src/material.h +++ b/src/material.h @@ -75,7 +75,7 @@ class material_type float _specific_heat_liquid = 4.186f; float _specific_heat_solid = 2.108f; float _latent_heat = 334.0f; - int _freeze_point = 32; // Fahrenheit + float _freeze_point = 0; // Celsius bool _edible = false; bool _rotting = false; bool _soft = false; @@ -127,7 +127,7 @@ class material_type float specific_heat_liquid() const; float specific_heat_solid() const; float latent_heat() const; - int freeze_point() const; + float freeze_point() const; int density() const; bool edible() const; bool rotting() const; From b86aafc78c502269da1f2e42b5305a94181704da Mon Sep 17 00:00:00 2001 From: Charlie Gardai <32105250+Moltenhead@users.noreply.github.com> Date: Tue, 23 Feb 2021 08:58:57 +0100 Subject: [PATCH 240/453] Stand up peek (#47257) --- src/avatar.cpp | 7 +++++++ src/avatar.h | 2 ++ src/game.cpp | 26 +++++++++++++++++++++++--- src/game.h | 9 +++++++++ 4 files changed, 41 insertions(+), 3 deletions(-) diff --git a/src/avatar.cpp b/src/avatar.cpp index 4fe74ab391b7c..b28b60e68c89c 100644 --- a/src/avatar.cpp +++ b/src/avatar.cpp @@ -1526,6 +1526,13 @@ void avatar::toggle_crouch_mode() } } +void avatar::activate_crouch_mode() +{ + if( !is_crouching() ) { + set_movement_mode( move_mode_id( "crouch" ) ); + } +} + void avatar::reset_move_mode() { if( !is_walking() ) { diff --git a/src/avatar.h b/src/avatar.h index 1fa81646c7d7e..427aac2176d3c 100644 --- a/src/avatar.h +++ b/src/avatar.h @@ -237,6 +237,8 @@ class avatar : public player void toggle_run_mode(); // Toggles crouching on/off. void toggle_crouch_mode(); + // Activate crouch mode if not in crouch mode. + void activate_crouch_mode(); bool wield( item_location target ); bool wield( item &target ) override; diff --git a/src/game.cpp b/src/game.cpp index 6d488c0d2984b..60d2970d93199 100644 --- a/src/game.cpp +++ b/src/game.cpp @@ -6116,10 +6116,20 @@ void game::peek( const tripoint &p ) u.moves -= 200; tripoint prev = u.pos(); u.setpos( p ); + const bool is_same_pos = u.pos() == prev; + const bool is_standup_peek = is_same_pos && u.is_crouching(); tripoint center = p; - const look_around_result result = look_around( /*show_window=*/true, center, center, false, false, - true ); - u.setpos( prev ); + + look_around_result result; + const look_around_params looka_params = { true, center, center, false, false, true }; + if( is_standup_peek ) { // Non moving peek from crouch is a standup peek + u.reset_move_mode(); + result = look_around( looka_params ); + u.activate_crouch_mode(); + } else { // Else is normal peek + result = look_around( looka_params ); + u.setpos( prev ); + } if( result.peek_action && *result.peek_action == PA_BLIND_THROW ) { item_location loc; @@ -6127,6 +6137,7 @@ void game::peek( const tripoint &p ) } m.invalidate_map_cache( p.z ); } + //////////////////////////////////////////////////////////////////////////////////////////// cata::optional game::look_debug() { @@ -7037,6 +7048,8 @@ cata::optional game::look_around() return result.position; } +//look_around_result game::look_around( const bool show_window, tripoint ¢er, +// const tripoint &start_point, bool has_first_point, bool select_zone, bool peeking ) look_around_result game::look_around( const bool show_window, tripoint ¢er, const tripoint &start_point, bool has_first_point, bool select_zone, bool peeking ) { @@ -7355,6 +7368,13 @@ look_around_result game::look_around( const bool show_window, tripoint ¢er, return result; } +look_around_result game::look_around( look_around_params looka_params ) +{ + return look_around( looka_params.show_window, looka_params.center, looka_params.start_point, + looka_params.has_first_point, + looka_params.select_zone, looka_params.peeking ); +} + std::vector game::find_nearby_items( int iRadius ) { std::map temp_items; diff --git a/src/game.h b/src/game.h index c7ae2a8a0e4af..ed032374b833f 100644 --- a/src/game.h +++ b/src/game.h @@ -123,6 +123,14 @@ struct look_around_result { cata::optional position; cata::optional peek_action; }; +struct look_around_params { + const bool show_window; + tripoint ¢er; + const tripoint &start_point; + bool has_first_point; + bool select_zone; + bool peeking; +}; struct w_map { int id; @@ -570,6 +578,7 @@ class game cata::optional look_around(); look_around_result look_around( bool show_window, tripoint ¢er, const tripoint &start_point, bool has_first_point, bool select_zone, bool peeking ); + look_around_result look_around( look_around_params ); // Shared method to print "look around" info void pre_print_all_tile_info( const tripoint &lp, const catacurses::window &w_info, From e0809ea804630bdd4bddbf6091f575a5fe236b20 Mon Sep 17 00:00:00 2001 From: Mom-Bun <43492737+Mom-Bun@users.noreply.github.com> Date: Wed, 24 Feb 2021 03:54:04 -0600 Subject: [PATCH 241/453] [AFTERSHOCK] Basic Ballistic Weapons (#47559) --- .../itemgroups/spaceship_groups.json | 2 +- .../itemgroups/weapons/energy_gun_groups.json | 92 +++++++++++++++++ data/mods/Aftershock/items/ammo/10mm.json | 42 ++++++++ data/mods/Aftershock/items/ammo/25mm.json | 23 +++++ data/mods/Aftershock/items/ammo/7.50mm.json | 42 ++++++++ data/mods/Aftershock/items/ammo_type.json | 18 ++++ data/mods/Aftershock/items/casing.json | 15 +++ data/mods/Aftershock/items/gun/10mm.json | 35 +++++++ data/mods/Aftershock/items/gun/25mm.json | 47 +++++++++ data/mods/Aftershock/items/gun/7.50mm.json | 98 +++++++++++++++++++ .../Aftershock/items/gun/combination.json | 19 ---- data/mods/Aftershock/items/magazine/10mm.json | 19 ++++ data/mods/Aftershock/items/magazine/25mm.json | 18 ++++ .../Aftershock/items/magazine/7.50mm.json | 37 +++++++ .../mods/Aftershock/items/magazine/alien.json | 1 - .../Aftershock/vehicles/vehicle_parts.json | 28 ++++++ 16 files changed, 515 insertions(+), 21 deletions(-) create mode 100644 data/mods/Aftershock/items/ammo/10mm.json create mode 100644 data/mods/Aftershock/items/ammo/25mm.json create mode 100644 data/mods/Aftershock/items/ammo/7.50mm.json create mode 100644 data/mods/Aftershock/items/casing.json create mode 100644 data/mods/Aftershock/items/gun/10mm.json create mode 100644 data/mods/Aftershock/items/gun/25mm.json create mode 100644 data/mods/Aftershock/items/gun/7.50mm.json delete mode 100644 data/mods/Aftershock/items/gun/combination.json create mode 100644 data/mods/Aftershock/items/magazine/10mm.json create mode 100644 data/mods/Aftershock/items/magazine/25mm.json create mode 100644 data/mods/Aftershock/items/magazine/7.50mm.json diff --git a/data/mods/Aftershock/itemgroups/spaceship_groups.json b/data/mods/Aftershock/itemgroups/spaceship_groups.json index 53f1b65c30d41..2e664bacb8d8e 100644 --- a/data/mods/Aftershock/itemgroups/spaceship_groups.json +++ b/data/mods/Aftershock/itemgroups/spaceship_groups.json @@ -19,7 +19,7 @@ { "item": "emer_blanket", "count": 2 }, { "item": "afs_radiobeacon" }, { "item": "afs_landfall_gun", "container-item": "back_holster" }, - { "item": "22_lr", "charges": 18 }, + { "item": "afs_7.50mm_rp", "charges": 18 }, { "item": "afs_landfall_kit_2_instructions" } ] } diff --git a/data/mods/Aftershock/itemgroups/weapons/energy_gun_groups.json b/data/mods/Aftershock/itemgroups/weapons/energy_gun_groups.json index 1516ee5b1b817..829ca018ce3d8 100644 --- a/data/mods/Aftershock/itemgroups/weapons/energy_gun_groups.json +++ b/data/mods/Aftershock/itemgroups/weapons/energy_gun_groups.json @@ -40,5 +40,97 @@ "subtype": "distribution", "ammo": 100, "items": [ [ "afs_4g_plasma", 30 ] ] + }, + { + "type": "item_group", + "id": "guns_pistol_rare", + "items": [ { "item": "afs_orion_84K", "prob": 15, "charges-min": 0, "charges-max": 20 } ] + }, + { + "type": "item_group", + "id": "guns_pistol_rare_display", + "items": [ { "item": "afs_orion_84K", "prob": 15, "charges-min": 0, "charges-max": 0 } ] + }, + { + "type": "item_group", + "id": "guns_pistol_obscure", + "items": [ { "item": "afs_orion_84K", "prob": 50, "charges-min": 0, "charges-max": 20 } ] + }, + { + "type": "item_group", + "id": "guns_rifle_rare_display", + "items": [ + { "item": "afs_gibrifle", "prob": 1, "charges-min": 0, "charges-max": 0 }, + { "item": "afs_Accipitermg", "prob": 1, "charges-min": 0, "charges-max": 0 } + ] + }, + { + "type": "item_group", + "id": "guns_rifle_rare", + "items": [ + { "item": "afs_gibrifle", "prob": 25, "charges-min": 0, "charges-max": 30 }, + { "item": "afs_Accipitermg", "prob": 20, "charges-min": 0, "charges-max": 30 } + ] + }, + { + "type": "item_group", + "id": "guns_rifle_milspec", + "items": [ + { "item": "afs_gibrifle", "prob": 50, "charges-min": 0, "charges-max": 30 }, + { "item": "afs_Accipitermg", "prob": 45, "charges-min": 0, "charges-max": 30 } + ] + }, + { + "type": "item_group", + "id": "guns_shotgun_milspec", + "items": [ { "item": "afs_gibs_shotgun", "prob": 20, "charges-min": 0, "charges-max": 40 } ] + }, + { + "type": "item_group", + "id": "mags_pistol_rare", + "items": [ [ "afs_84k_20mag", 15 ] ] + }, + { + "type": "item_group", + "id": "mags_rifle_rare", + "items": [ [ "afs_UICASTA30", 40 ], [ "afs_UICASTA100drum", 20 ] ] + }, + { + "type": "item_group", + "id": "mags_shotgun_rare", + "items": [ [ "afs_25mm_mag", 50 ] ] + }, + { + "type": "item_group", + "id": "ammo_pistol_rare", + "subtype": "distribution", + "entries": [ { "item": "afs_10mm_caseless_FMJ", "prob": 20 }, { "item": "afs_10mm_caseless_JHP", "prob": 15 } ] + }, + { + "type": "item_group", + "id": "ammo_rifle_rare", + "//": "Less common rifle ammo including that only used by police/paramilitary forces.", + "subtype": "distribution", + "entries": [ { "item": "afs_7.50mm_caseless", "prob": 40 }, { "item": "afs_7.50mm_rp", "prob": 50 } ] + }, + { + "type": "item_group", + "id": "ammo_rifle_milspec", + "subtype": "distribution", + "entries": [ { "item": "afs_7.50mm_caseless", "prob": 40 }, { "item": "afs_7.50mm_rp", "prob": 50 } ] + }, + { + "type": "item_group", + "id": "ammo_shotgun_rare", + "//": "Less common shotgun ammo including that only used by police/paramilitary forces.", + "subtype": "distribution", + "entries": [ { "item": "afs_25mm_shot", "prob": 10 } ] + }, + { + "type": "item_group", + "id": "ammo_shotgun_milspec", + "//": "Military specification shotgun ammo found at military sites.", + "subtype": "distribution", + "entries": [ { "item": "afs_25mm_shot", "prob": 10 } ] } ] diff --git a/data/mods/Aftershock/items/ammo/10mm.json b/data/mods/Aftershock/items/ammo/10mm.json new file mode 100644 index 0000000000000..6f9a8ff576377 --- /dev/null +++ b/data/mods/Aftershock/items/ammo/10mm.json @@ -0,0 +1,42 @@ +[ + { + "id": "afs_10mm_caseless_FMJ", + "type": "AMMO", + "name": { "str_sp": "10mm FMJ caseless" }, + "description": "Standardized 10mm ammunition with a brass jacketed projectile. For as long as you can remember bullets like these have been used for military, law enforcement, and civilian use. Being caseless, these cannot be disassembled or reloaded.", + "weight": "9 g", + "volume": "117 ml", + "price": 400, + "material": [ "lead" ], + "symbol": "=", + "color": "yellow", + "count": 40, + "stack_size": 40, + "ammo_type": "afs_10mm", + "range": 14, + "damage": { "damage_type": "bullet", "amount": 29, "armor_penetration": 4 }, + "dispersion": 60, + "recoil": 650, + "effects": [ "COOKOFF" ] + }, + { + "id": "afs_10mm_caseless_JHP", + "type": "AMMO", + "name": { "str_sp": "10mm JHP caseless" }, + "description": "Standardized 10mm ammunition with a hollow point projectile. While they have inferior penetration to FMJ rounds, their expansion slightly increases stopping power against unarmed targets and reduces overpenetration. Being caseless, these cannot be disassembled or reloaded.", + "weight": "7 g", + "volume": "115 ml", + "price": 150, + "material": [ "lead" ], + "symbol": "=", + "color": "yellow", + "count": 40, + "stack_size": 40, + "ammo_type": "afs_10mm", + "range": 14, + "damage": { "damage_type": "bullet", "amount": 31 }, + "dispersion": 60, + "recoil": 600, + "effects": [ "COOKOFF" ] + } +] diff --git a/data/mods/Aftershock/items/ammo/25mm.json b/data/mods/Aftershock/items/ammo/25mm.json new file mode 100644 index 0000000000000..e9d0a9c5c4b0b --- /dev/null +++ b/data/mods/Aftershock/items/ammo/25mm.json @@ -0,0 +1,23 @@ +[ + { + "id": "afs_25mm_shot", + "type": "AMMO", + "name": { "str_sp": "25mm canister shot" }, + "description": "A 25mm grenade with a canister shot load, deals devastating damage against moderately armored foes within mid to close range. Relatively low tech and affordable when compared to other 25mm grenades, these are often fielded by frontier outfits due to their adequate performance in anti-drone and close quarters combat.", + "weight": "130 g", + "volume": "230 ml", + "price": 8000, + "material": [ "superalloy", "powder", "lead" ], + "symbol": "=", + "color": "pink", + "count": 6, + "stack_size": 1, + "ammo_type": "afs_25mm", + "casing": "afs_25_casing", + "range": 24, + "damage": { "damage_type": "bullet", "amount": 60, "armor_penetration": 15 }, + "dispersion": 75, + "recoil": 2200, + "effects": [ "NEVER_MISFIRES" ] + } +] diff --git a/data/mods/Aftershock/items/ammo/7.50mm.json b/data/mods/Aftershock/items/ammo/7.50mm.json new file mode 100644 index 0000000000000..43a949af6248a --- /dev/null +++ b/data/mods/Aftershock/items/ammo/7.50mm.json @@ -0,0 +1,42 @@ +[ + { + "id": "afs_7.50mm_caseless", + "type": "AMMO", + "name": { "str_sp": "7.50mm caseless" }, + "description": "An intermediate bullet with an acceptable all-round performance. Due to their role as UICA's standard issue rifle cartridge, these are ubiquitous wherever Earth makes its presence be known. Being caseless, these cannot be disassembled or reloaded.", + "weight": "12 g", + "volume": "194 ml", + "price": 280, + "material": [ "lead" ], + "symbol": "=", + "color": "yellow", + "count": 30, + "stack_size": 47, + "ammo_type": "afs_7.50mm", + "range": 36, + "damage": { "damage_type": "bullet", "amount": 44, "armor_penetration": 2 }, + "dispersion": 30, + "recoil": 1500, + "effects": [ "COOKOFF" ] + }, + { + "id": "afs_7.50mm_rp", + "type": "AMMO", + "name": { "str_sp": "7.50mm RP" }, + "description": "Civilian-legal 7.50mm ammunition featuring a reduced propellant case and unjacketed projectiles. The 7.50mm RP round is extremely weak with very low stopping power, short range, and negligible recoil. While cheaper than military grade rounds, its only really useful for rifle training, and for hunting small animals. Being caseless, these cannot be disassembled or reloaded.", + "weight": "3 g", + "volume": "65 ml", + "price": 150, + "material": [ "lead" ], + "symbol": "=", + "color": "yellow", + "count": 80, + "stack_size": 100, + "ammo_type": "afs_7.50mm", + "range": 13, + "damage": { "damage_type": "bullet", "amount": 12 }, + "dispersion": 60, + "recoil": 150, + "effects": [ "COOKOFF" ] + } +] diff --git a/data/mods/Aftershock/items/ammo_type.json b/data/mods/Aftershock/items/ammo_type.json index 4701fc308abba..c27192d8af173 100644 --- a/data/mods/Aftershock/items/ammo_type.json +++ b/data/mods/Aftershock/items/ammo_type.json @@ -22,5 +22,23 @@ "id": "afs_shydrogen", "name": "solid hydrogen", "default": "afs_shydrogen" + }, + { + "type": "ammunition_type", + "id": "afs_25mm", + "name": "25mm", + "default": "afs_25mm_shot" + }, + { + "type": "ammunition_type", + "id": "afs_10mm", + "name": "10mm", + "default": "afs_10mm_caseless_JHP" + }, + { + "type": "ammunition_type", + "id": "afs_7.50mm", + "name": "7.50mm", + "default": "afs_7.50mm_caseless" } ] diff --git a/data/mods/Aftershock/items/casing.json b/data/mods/Aftershock/items/casing.json new file mode 100644 index 0000000000000..581288094ed15 --- /dev/null +++ b/data/mods/Aftershock/items/casing.json @@ -0,0 +1,15 @@ +[ + { + "id": "afs_25_casing", + "type": "GENERIC", + "category": "spare_parts", + "name": { "str": "25mm casing" }, + "description": "A large casing from a spent 25mm cartridge.", + "weight": "50 g", + "volume": "45ml", + "material": [ "superalloy" ], + "symbol": "=", + "stackable": true, + "color": "dark_gray" + } +] diff --git a/data/mods/Aftershock/items/gun/10mm.json b/data/mods/Aftershock/items/gun/10mm.json new file mode 100644 index 0000000000000..1dfe73939b256 --- /dev/null +++ b/data/mods/Aftershock/items/gun/10mm.json @@ -0,0 +1,35 @@ +[ + { + "id": "afs_orion_84K", + "copy-from": "pistol_base", + "looks_like": "glock_17", + "type": "GUN", + "name": { "str": "Seyfert 84K" }, + "description": "Commonly carried by shipping crews that can afford it, Seyfert Armistice's 84K pistol doesn't particularly shine or show anything special but it keeps you safe on long journeys in the vast dark of Orion's Arm.", + "weight": "780 g", + "volume": "480 ml", + "longest_side": "205 mm", + "price": 59200, + "to_hit": -2, + "bashing": 8, + "material": [ "plastic", "superalloy" ], + "symbol": "(", + "color": "dark_gray", + "ammo": "afs_10mm", + "ranged_damage": { "damage_type": "bullet", "amount": -5 }, + "dispersion": 480, + "durability": 8, + "blackpowder_tolerance": 48, + "min_cycle_recoil": 570, + "pocket_data": [ + { + "magazine_well": "103 ml", + "pocket_type": "MAGAZINE_WELL", + "holster": true, + "max_contains_volume": "20 L", + "max_contains_weight": "20 kg", + "item_restriction": [ "afs_84k_20mag" ] + } + ] + } +] diff --git a/data/mods/Aftershock/items/gun/25mm.json b/data/mods/Aftershock/items/gun/25mm.json new file mode 100644 index 0000000000000..5868bc0ba49d6 --- /dev/null +++ b/data/mods/Aftershock/items/gun/25mm.json @@ -0,0 +1,47 @@ +[ + { + "id": "afs_gibs_shotgun", + "looks_like": "m79", + "type": "GUN", + "reload_noise_volume": 10, + "name": { "str": "Gibson S86" }, + "description": "Manufactured by Gibson Armory, the S86 is a light-weight grenade launcher designed to take care of moderately armored opponents. While the S86 firepower is nothing to truly gawk at, it still packs quite a punch both for the target and user and is usually mounted as it is impossible to fire with average strength.", + "weight": "2700 g", + "volume": "2800 ml", + "longest_side": "736 mm", + "price": 550000, + "to_hit": -3, + "bashing": 10, + "material": [ "superalloy", "plastic" ], + "symbol": "(", + "color": "brown", + "min_strength": 18, + "ranged_damage": { "damage_type": "bullet", "amount": 10 }, + "skill": "launcher", + "modes": [ [ "DEFAULT", "DOUBLE", 4 ] ], + "dispersion": 90, + "durability": 6, + "ammo": [ "afs_25mm" ], + "clip_size": 1, + "pocket_data": [ + { + "pocket_type": "MAGAZINE_WELL", + "holster": true, + "max_contains_volume": "20 L", + "max_contains_weight": "20 kg", + "item_restriction": [ "afs_25mm_mag" ] + } + ], + "reload": 400, + "valid_mod_locations": [ + [ "accessories", 2 ], + [ "barrel", 1 ], + [ "sights", 1 ], + [ "sling", 1 ], + [ "grip mount", 1 ], + [ "rail mount", 1 ], + [ "stock mount", 1 ], + [ "underbarrel mount", 1 ] + ] + } +] diff --git a/data/mods/Aftershock/items/gun/7.50mm.json b/data/mods/Aftershock/items/gun/7.50mm.json new file mode 100644 index 0000000000000..483e77a8f31f9 --- /dev/null +++ b/data/mods/Aftershock/items/gun/7.50mm.json @@ -0,0 +1,98 @@ +[ + { + "id": "afs_landfall_gun", + "type": "GUN", + "copy-from": "rifle_22", + "name": { "str": "landfall survival gun" }, + "description": "A lightweight, bolt-action gun that is barely more than a 6.55mm barrel mounted within a flimsy metal assembly. Cheaply made and outdated in all respects, it's only useful in the most extenuating of circumstances.", + "price": 5000, + "material": [ "steel", "plastic" ], + "flags": [ "NEVER_JAMS", "RELOAD_EJECT" ], + "dispersion": 250, + "longest_side": "60 cm", + "reload": 100, + "durability": 5, + "blackpowder_tolerance": 60, + "ammo": [ "afs_7.50mm" ], + "pocket_data": [ { "pocket_type": "MAGAZINE", "rigid": true, "ammo_restriction": { "afs_7.50mm": 1 } } ], + "faults": [ "fault_gun_blackpowder", "fault_gun_dirt" ] + }, + { + "id": "afs_Accipitermg", + "copy-from": "rifle_auto", + "looks_like": "ar15", + "type": "GUN", + "name": { "str": "Accipiter Hawk-00" }, + "description": "A light machine gun manufactured by Accipiter Firearms and distributed by Wraitheon. The Hawk-00's high rate of fire makes it ideally suited to lay down suppressive fire; but also makes it exceedingly hard to control while unmounted.", + "weight": "7500 g", + "volume": "10610 ml", + "longest_side": "1035 mm", + "price": 750000, + "to_hit": -1, + "bashing": 12, + "material": [ "superalloy", "plastic" ], + "symbol": "(", + "color": "dark_gray", + "ammo": [ "afs_7.50mm" ], + "dispersion": 200, + "durability": 7, + "min_cycle_recoil": 1350, + "reload": 400, + "modes": [ [ "DEFAULT", "burst", 4 ] ], + "built_in_mods": [ "bipod" ], + "valid_mod_locations": [ + [ "accessories", 4 ], + [ "barrel", 1 ], + [ "bore", 1 ], + [ "brass catcher", 1 ], + [ "grip", 1 ], + [ "mechanism", 4 ], + [ "muzzle", 1 ], + [ "rail", 1 ], + [ "sights", 1 ], + [ "sling", 1 ], + [ "stock", 1 ] + ], + "pocket_data": [ + { + "pocket_type": "MAGAZINE_WELL", + "holster": true, + "max_contains_volume": "20 L", + "max_contains_weight": "20 kg", + "item_restriction": [ "afs_UICASTA30", "afs_UICASTA100drum" ] + } + ] + }, + { + "id": "afs_gibrifle", + "copy-from": "rifle_semi", + "looks_like": "ar15", + "type": "GUN", + "name": { "str": "G&W SR-P9" }, + "description": "An eminently sturdy and reliable bullpup rifle issued by UICA's military during early reclamation expeditions. Although its been out of service for nearly two decades, many a private military and contractor has found a use for the SR-P9, and it remains common long past its initial introduction into service.", + "weight": "3170 g", + "volume": "3100 ml", + "longest_side": "630 mm", + "price": 125000, + "to_hit": -1, + "bashing": 12, + "material": [ "superalloy", "plastic" ], + "ranged_damage": { "damage_type": "bullet", "amount": -7 }, + "modes": [ [ "DEFAULT", "semi-auto", 1 ], [ "BURST", "burst", 2 ] ], + "symbol": "(", + "color": "dark_gray", + "ammo": [ "afs_7.50mm" ], + "dispersion": 150, + "durability": 10, + "min_cycle_recoil": 1350, + "pocket_data": [ + { + "pocket_type": "MAGAZINE_WELL", + "holster": true, + "max_contains_volume": "20 L", + "max_contains_weight": "20 kg", + "item_restriction": [ "afs_UICASTA30" ] + } + ] + } +] diff --git a/data/mods/Aftershock/items/gun/combination.json b/data/mods/Aftershock/items/gun/combination.json deleted file mode 100644 index 694a5f95fea72..0000000000000 --- a/data/mods/Aftershock/items/gun/combination.json +++ /dev/null @@ -1,19 +0,0 @@ -[ - { - "id": "afs_landfall_gun", - "type": "GUN", - "copy-from": "rifle_22", - "name": { "str": "landfall survival gun" }, - "description": "A lightweight, bolt-action gun that is barely more than a .22 barrel mounted within a flimsy metal assembly. Cheaply made and outdated in all respects, it's only useful in the most extenuating of circumstances.", - "price": 5000, - "price_postapoc": 5000, - "material": [ "steel", "plastic" ], - "flags": [ "NEVER_JAMS", "RELOAD_EJECT" ], - "dispersion": 250, - "longest_side": "60 cm", - "reload": 100, - "durability": 5, - "blackpowder_tolerance": 60, - "faults": [ "fault_gun_blackpowder", "fault_gun_dirt" ] - } -] diff --git a/data/mods/Aftershock/items/magazine/10mm.json b/data/mods/Aftershock/items/magazine/10mm.json new file mode 100644 index 0000000000000..e211e6613d77e --- /dev/null +++ b/data/mods/Aftershock/items/magazine/10mm.json @@ -0,0 +1,19 @@ +[ + { + "id": "afs_84k_20mag", + "looks_like": "glock17_17", + "type": "MAGAZINE", + "name": { "str": "84k 10mm 20-round magazine" }, + "description": "A 20-round magazine for use with the Seyfert 84k.", + "weight": "70 g", + "volume": "103 ml", + "longest_side": "114 mm", + "price": 2400, + "material": [ "plastic", "superalloy" ], + "symbol": "#", + "color": "light_gray", + "ammo_type": [ "afs_10mm" ], + "flags": [ "MAG_COMPACT" ], + "pocket_data": [ { "pocket_type": "MAGAZINE", "rigid": true, "ammo_restriction": { "afs_10mm": 20 } } ] + } +] diff --git a/data/mods/Aftershock/items/magazine/25mm.json b/data/mods/Aftershock/items/magazine/25mm.json new file mode 100644 index 0000000000000..64c3ac9736f93 --- /dev/null +++ b/data/mods/Aftershock/items/magazine/25mm.json @@ -0,0 +1,18 @@ +[ + { + "id": "afs_25mm_mag", + "looks_like": "stanag30", + "type": "MAGAZINE", + "name": { "str": "25mm 40-round magazine" }, + "description": "A 40-round magazine for use with 25mm firearms.", + "weight": "340 g", + "volume": "2 L", + "price": 70000, + "material": [ "superalloy", "plastic" ], + "symbol": "#", + "color": "dark_gray", + "ammo_type": [ "afs_25mm" ], + "reload_time": 60, + "pocket_data": [ { "pocket_type": "MAGAZINE", "rigid": true, "ammo_restriction": { "afs_25mm": 40 } } ] + } +] diff --git a/data/mods/Aftershock/items/magazine/7.50mm.json b/data/mods/Aftershock/items/magazine/7.50mm.json new file mode 100644 index 0000000000000..0967b6f04edd1 --- /dev/null +++ b/data/mods/Aftershock/items/magazine/7.50mm.json @@ -0,0 +1,37 @@ +[ + { + "id": "afs_UICASTA30", + "looks_like": "stanag30", + "type": "MAGAZINE", + "name": { "str": "UICASTA 30-round magazine" }, + "description": "A standardized 30-round magazine compatible with most UICA issue rifles.", + "weight": "265 g", + "volume": "290 ml", + "longest_side": "190 mm", + "price": 8000, + "material": [ "superalloy" ], + "symbol": "#", + "color": "light_gray", + "ammo_type": [ "afs_7.50mm" ], + "flags": [ "MAG_COMPACT" ], + "pocket_data": [ { "pocket_type": "MAGAZINE", "rigid": true, "ammo_restriction": { "afs_7.50mm": 30 } } ] + }, + { + "id": "afs_UICASTA100drum", + "looks_like": "stanag30", + "type": "MAGAZINE", + "name": { "str": "UICASTA 100-round double drum magazine" }, + "description": "A standardized 100-round double drum magazine compatible with most UICA issue rifles.", + "weight": "1700 g", + "volume": "1200 ml", + "longest_side": "300 mm", + "price": 14000, + "material": [ "plastic", "superalloy" ], + "symbol": "#", + "color": "light_gray", + "ammo_type": [ "afs_7.50mm" ], + "reload_time": 200, + "flags": [ "MAG_BULKY" ], + "pocket_data": [ { "pocket_type": "MAGAZINE", "rigid": true, "ammo_restriction": { "afs_7.50mm": 100 } } ] + } +] diff --git a/data/mods/Aftershock/items/magazine/alien.json b/data/mods/Aftershock/items/magazine/alien.json index f9b12cb95b11b..7fbeaab6184aa 100644 --- a/data/mods/Aftershock/items/magazine/alien.json +++ b/data/mods/Aftershock/items/magazine/alien.json @@ -8,7 +8,6 @@ "weight": "1000 g", "volume": "1225ml", "price": 100000, - "price_postapoc": 5000, "material": [ "iron", "plastic" ], "symbol": "=", "color": "yellow", diff --git a/data/mods/Aftershock/vehicles/vehicle_parts.json b/data/mods/Aftershock/vehicles/vehicle_parts.json index b7aad54ed241c..377859a40a80c 100644 --- a/data/mods/Aftershock/vehicles/vehicle_parts.json +++ b/data/mods/Aftershock/vehicles/vehicle_parts.json @@ -28,6 +28,34 @@ "removal": { "skills": [ [ "mechanics", 3 ] ] } } }, + { + "id": "afs_mounted_gibs_shotgun", + "copy-from": "turret", + "type": "vehicle_part", + "name": { "str": "mounted Gibson S86" }, + "item": "afs_gibs_shotgun", + "color": "magenta", + "broken_color": "magenta", + "breaks_into": [ { "item": "scrap", "count": 9 }, { "item": "steel_chunk", "count": 4 }, { "item": "steel_lump", "count": 1 } ], + "requirements": { + "install": { "skills": [ [ "mechanics", 5 ], [ "electronics", 5 ] ] }, + "removal": { "skills": [ [ "mechanics", 3 ] ] } + } + }, + { + "id": "afs_mounted_Accipitermg", + "copy-from": "turret", + "type": "vehicle_part", + "name": { "str": "mounted Accipiter Hawk-00" }, + "item": "afs_Accipitermg", + "color": "magenta", + "broken_color": "magenta", + "breaks_into": [ { "item": "scrap", "count": 9 }, { "item": "steel_chunk", "count": 4 }, { "item": "steel_lump", "count": 1 } ], + "requirements": { + "install": { "skills": [ [ "mechanics", 5 ], [ "electronics", 5 ] ] }, + "removal": { "skills": [ [ "mechanics", 3 ] ] } + } + }, { "id": "afs_laser_rifle", "copy-from": "turret", From 296d1a198ba0e4a26f7ec8fa6518b27ef9bd0b1e Mon Sep 17 00:00:00 2001 From: OromisElf Date: Wed, 24 Feb 2021 10:56:22 +0100 Subject: [PATCH 242/453] makes glass walls and glass doors constructable (#47692) --- data/json/construction.json | 31 +++++++++++++++++++++++++++++++ data/json/construction_group.json | 10 ++++++++++ 2 files changed, 41 insertions(+) diff --git a/data/json/construction.json b/data/json/construction.json index d7eadbd567952..2241de455e644 100644 --- a/data/json/construction.json +++ b/data/json/construction.json @@ -4275,5 +4275,36 @@ "byproducts": [ { "item": "pebble", "count": [ 70, 100 ] } ], "pre_terrain": "t_railroad_rubble", "post_terrain": "t_dirt" + }, + { + "type": "construction", + "id": "constr_glass_wall", + "group": "build_glass_wall", + "category": "CONSTRUCT", + "required_skills": [ [ "fabrication", 3 ] ], + "time": "60 m", + "qualities": [ [ { "id": "HAMMER_SOFT", "level": 1 } ] ], + "components": [ + [ [ "frame_wood", 1 ] ], + [ [ "chunk_rubber", 16 ] ], + [ [ "glass_sheet", 2 ] ], + [ [ "superglue", 2 ], [ "duct_tape", 10 ] ] + ], + "pre_note": "Must be supported on at least two sides.", + "pre_special": "check_support", + "post_terrain": "t_wall_glass" + }, + { + "type": "construction", + "id": "constr_glass_wall_door", + "group": "build_glass_door", + "category": "CONSTRUCT", + "required_skills": [ [ "fabrication", 3 ] ], + "time": "60 m", + "qualities": [ [ { "id": "HAMMER_SOFT", "level": 1 } ] ], + "components": [ [ [ "frame_wood", 1 ] ], [ [ "chunk_rubber", 16 ] ], [ [ "glass_sheet", 2 ] ], [ [ "rag", 8 ] ] ], + "pre_note": "Must be supported on at least two sides.", + "pre_special": "check_support", + "post_terrain": "t_door_glass_c" } ] diff --git a/data/json/construction_group.json b/data/json/construction_group.json index 2ae0acb904d0d..5495ebfb62d93 100644 --- a/data/json/construction_group.json +++ b/data/json/construction_group.json @@ -284,6 +284,16 @@ "id": "build_fire_ring", "name": "Build Fire Ring" }, + { + "type": "construction_group", + "id": "build_glass_door", + "name": "Build Glass Door" + }, + { + "type": "construction_group", + "id": "build_glass_wall", + "name": "Build Glass Wall" + }, { "type": "construction_group", "id": "build_high_end_of_a_concrete_ramp", From 8f63962daf82518a130c338fa298a5f4d5d59ce0 Mon Sep 17 00:00:00 2001 From: Maleclypse <54345792+Maleclypse@users.noreply.github.com> Date: Wed, 24 Feb 2021 04:10:27 -0600 Subject: [PATCH 243/453] Crackers as bread and jam&cheese sandwich (#47649) --- data/json/items/comestibles/sandwich.json | 21 +++++++++++++++++++ data/json/recipes/recipe_food.json | 15 +++++++++++++ .../json/requirements/cooking_components.json | 3 ++- 3 files changed, 38 insertions(+), 1 deletion(-) diff --git a/data/json/items/comestibles/sandwich.json b/data/json/items/comestibles/sandwich.json index bcacfb4ddf8fe..5c63db38b7143 100644 --- a/data/json/items/comestibles/sandwich.json +++ b/data/json/items/comestibles/sandwich.json @@ -113,6 +113,27 @@ "fun": 6, "vitamins": [ [ "vitC", 6 ], [ "calcium", 7 ], [ "iron", 12 ] ] }, + { + "type": "COMESTIBLE", + "id": "sandwich_jam_cheese", + "name": { "str": "jam and cheese sandwich", "str_pl": "jam and cheese sandwiches" }, + "weight": "140 g", + "color": "brown", + "spoils_in": "1 day 13 hours", + "container": "wrapper", + "comestible_type": "FOOD", + "symbol": "%", + "quench": 1, + "calories": 382, + "description": "A delicious jam and cheese sandwich.", + "price": 200, + "price_postapoc": 200, + "material": [ "fruit", "wheat", "milk" ], + "primary_material": "wheat", + "volume": "250 ml", + "fun": 6, + "vitamins": [ [ "vitC", 6 ], [ "calcium", 7 ], [ "iron", 12 ] ] + }, { "type": "COMESTIBLE", "id": "sandwich_jam_butter", diff --git a/data/json/recipes/recipe_food.json b/data/json/recipes/recipe_food.json index e032cfc4a730c..6b8706fc18a1b 100644 --- a/data/json/recipes/recipe_food.json +++ b/data/json/recipes/recipe_food.json @@ -5948,6 +5948,21 @@ "autolearn": true, "components": [ [ [ "bread_sandwich", 2, "LIST" ] ], [ [ "jam_fruit", 1 ] ] ] }, + { + "type": "recipe", + "activity_level": "LIGHT_EXERCISE", + "result": "sandwich_jam_cheese", + "category": "CC_FOOD", + "subcategory": "CSC_FOOD_VEGGI", + "skill_used": "cooking", + "time": "1 m", + "autolearn": true, + "components": [ + [ [ "bread_sandwich", 2, "LIST" ] ], + [ [ "jam_fruit", 1 ] ], + [ [ "cheese", 1 ], [ "cheese_hard", 1 ], [ "can_cheese", 1 ] ] + ] + }, { "type": "recipe", "activity_level": "LIGHT_EXERCISE", diff --git a/data/json/requirements/cooking_components.json b/data/json/requirements/cooking_components.json index 62f1e3568fd05..f951bc13d5150 100644 --- a/data/json/requirements/cooking_components.json +++ b/data/json/requirements/cooking_components.json @@ -30,7 +30,8 @@ [ "wastebread", 1 ], [ "sourdough_bread", 1 ], [ "biscuit", 1 ], - [ "brioche", 1 ] + [ "brioche", 1 ], + [ "crackers", 1 ] ] ] }, From 3639cd2e21eb1aa062b7546c5c54a66235ba36b8 Mon Sep 17 00:00:00 2001 From: casswedson <58050969+casswedson@users.noreply.github.com> Date: Sun, 28 Feb 2021 02:53:00 -0500 Subject: [PATCH 244/453] [Aftershock] misc typograpical fixes (#47783) --- data/mods/Aftershock/items/armor.json | 2 +- data/mods/Aftershock/items/books.json | 2 +- data/mods/Aftershock/items/comestibles/alienfood.json | 4 ++-- data/mods/Aftershock/items/comestibles/bug_brew.json | 6 +++--- data/mods/Aftershock/items/comestibles/cheap_food.json | 2 +- data/mods/Aftershock/items/comestibles/comestibles.json | 2 +- data/mods/Aftershock/items/gun/laser.json | 4 ++-- data/mods/Aftershock/items/gunmods/laser_gunmods.json | 2 +- data/mods/Aftershock/items/items.json | 2 +- data/mods/Aftershock/items/magazine/8x40mm.json | 2 +- data/mods/Aftershock/items/tools.json | 2 +- data/mods/Aftershock/items/weapons.json | 2 +- data/mods/Aftershock/maps/furniture.json | 6 +++--- data/mods/Aftershock/maps/terrain_floraxeno.json | 2 +- data/mods/Aftershock/maps/terrain_groundxeno.json | 2 +- data/mods/Aftershock/mobs/robots.json | 4 ++-- data/mods/Aftershock/mobs/water_mobs.json | 4 ++-- data/mods/Aftershock/mutations/mutations.json | 4 ++-- data/mods/Aftershock/mutations/obsolete.json | 2 +- data/mods/Aftershock/player/professions.json | 4 ++-- data/mods/Aftershock/scenarios.json | 2 +- 21 files changed, 31 insertions(+), 31 deletions(-) diff --git a/data/mods/Aftershock/items/armor.json b/data/mods/Aftershock/items/armor.json index 063723b459c8c..e1aa04b0d5b65 100644 --- a/data/mods/Aftershock/items/armor.json +++ b/data/mods/Aftershock/items/armor.json @@ -334,7 +334,7 @@ "type": "ARMOR", "id": "xllegpouch_large", "name": { "str": "XL leg ammo pouch", "str_pl": "XL leg ammo pouches" }, - "description": "An XL fabric ammo pouch that can be strapped to your leg and capable of holding two magazine close at hand.", + "description": "An XL fabric ammo pouch that can be strapped to your leg; capable of holding two magazines close at hand.", "weight": "120 g", "volume": "250 ml", "copy-from": "legpouch_large", diff --git a/data/mods/Aftershock/items/books.json b/data/mods/Aftershock/items/books.json index abc292f69fb8f..207f3f928304f 100644 --- a/data/mods/Aftershock/items/books.json +++ b/data/mods/Aftershock/items/books.json @@ -114,7 +114,7 @@ "id": "cyrus'_notes", "type": "BOOK", "name": { "str": "Cyrus Whateley's Notes on Repurposing mi-go victims", "str_pl": "copies of Cyrus Whateley's Notes" }, - "description": "A folio of notes written by a madman. They seem to suggestion ways to re-animate the dead and create various affronts to the natural order.", + "description": "A folio of notes written by a madman. They seem to suggest ways to re-animate the dead and create various affronts to the natural order.", "weight": "2063 g", "volume": "2 L", "price": 929200, diff --git a/data/mods/Aftershock/items/comestibles/alienfood.json b/data/mods/Aftershock/items/comestibles/alienfood.json index 387e9678d112f..fca6482f85682 100644 --- a/data/mods/Aftershock/items/comestibles/alienfood.json +++ b/data/mods/Aftershock/items/comestibles/alienfood.json @@ -236,7 +236,7 @@ "copy-from": "flesh", "type": "COMESTIBLE", "name": "alien stomach", - "description": "A balloon like organ you can only guess is a stomach. It is surprisingly durable.", + "description": "A balloon-like organ you can only guess is a stomach. It is surprisingly durable.", "weight": "72 g", "volume": "250 ml", "price_postapoc": 25, @@ -254,7 +254,7 @@ "copy-from": "alien_stomach", "type": "COMESTIBLE", "name": "large alien stomach", - "description": "A balloon like organ of a large alien. It is surprisingly durable.", + "description": "A balloon-like organ of a large alien you can only guess is a stomach. It is surprisingly durable.", "proportional": { "weight": 2.0, "volume": 2.0, "price": 1.5, "calories": 2.0 } }, { diff --git a/data/mods/Aftershock/items/comestibles/bug_brew.json b/data/mods/Aftershock/items/comestibles/bug_brew.json index bcbf8d7cbd91d..b4cc64ef268ed 100644 --- a/data/mods/Aftershock/items/comestibles/bug_brew.json +++ b/data/mods/Aftershock/items/comestibles/bug_brew.json @@ -3,7 +3,7 @@ "type": "COMESTIBLE", "id": "afs_mealgrub_medium", "name": { "str": "mealgrub growth medium" }, - "description": "All sort of organic substances rendered into a nutritious goop that can be used as a growth medium in grub aquaculture. Urban myth claims that its original formula was just bottled industrial runoff. Whatever the case, mealgrubs thrive within it.", + "description": "All sorts of organic substances rendered into a nutritious goop that can be used as a growth medium in grub aquaculture. Urban myth claims that its original formula was just bottled industrial runoff. Whatever the case, mealgrubs thrive within it.", "weight": "100 g", "container": "jug_plastic", "comestible_type": "DRINK", @@ -26,7 +26,7 @@ "type": "COMESTIBLE", "id": "afs_mealgrub_spores", "name": { "str_sp": "mealgrub spores" }, - "description": "Mealgrubs are a staple aquacultural product, treasured for their ability to process nearly any organic substance into safe for consumption animal protein. As the result of very heavy handed gene-modding these are propietary organism, and strictly speaking, its illegal to grow them without a licence.", + "description": "Mealgrubs are a staple aquacultural product, treasured for their ability to process nearly any organic substance into safe for consumption animal protein. As the result of very heavy-handed gene-modding these are proprietary organisms, and strictly speaking, it's illegal to grow them without a license.", "weight": "100 g", "container": "bottle_plastic_small", "comestible_type": "DRINK", @@ -99,7 +99,7 @@ "calories": 360, "healthy": 3, "charges": 5, - "description": "A handful of edible and heavily genemoded grubs, each only slightly thinner than your thumb. Engineered in the wake of the XXII century to feed an overpopulated Earth and its fledging colonies these are sturdy, easily grown and scalable crop.\n\nRemoved from their growth solution they'll quickly die and desiccate, as these already have. They could be safely be eaten with no further processing, for a nutritious if somewhat striking meal.", + "description": "A handful of edible and heavily genemoded grubs, each only slightly thinner than your thumb. Engineered in the wake of the XXII century to feed an overpopulated Earth and its fledgling colonies these are sturdy, easily grown and scalable crop.\n\nRemoved from their growth solution they'll quickly die and desiccate, as these already have. They could be safely eaten with no further processing, for a nutritious if somewhat striking meal.", "fun": 0, "freezing_point": -9999, "vitamins": [ [ "calcium", 2 ], [ "iron", 2 ], [ "vitA", 1 ], [ "vitB", 2 ], [ "bad_food", 1 ] ] diff --git a/data/mods/Aftershock/items/comestibles/cheap_food.json b/data/mods/Aftershock/items/comestibles/cheap_food.json index b5a15933f321b..e2967601a7aee 100644 --- a/data/mods/Aftershock/items/comestibles/cheap_food.json +++ b/data/mods/Aftershock/items/comestibles/cheap_food.json @@ -56,7 +56,7 @@ "weight": "10 g", "color": "yellow", "healthy": 2, - "description": "An golden can of sundew, the leading soft drink of the world. Staring at the can, you feel a craving so intense that you are unsure whether its genuine, or if it has been carefully engineered and implanted into your mind.", + "description": "A golden can of Sundew, the leading soft drink of the world. Staring at the can, you feel a craving so intense that you are unsure whether it's genuine, or if it has been carefully engineered and implanted into your mind.", "price": 1000, "looks_like": "diesel", "container": "can_drink", diff --git a/data/mods/Aftershock/items/comestibles/comestibles.json b/data/mods/Aftershock/items/comestibles/comestibles.json index f6c008a621f9f..601a46c16c416 100644 --- a/data/mods/Aftershock/items/comestibles/comestibles.json +++ b/data/mods/Aftershock/items/comestibles/comestibles.json @@ -45,7 +45,7 @@ { "id": "cream_prot_cold", "name": { "str": "heat retention cream" }, - "description": "Rub this on your skin when you are expecting exposure extreme cold temperatures. Cannot protect from instant frostbite. Smells like the inside of a sheep.", + "description": "Rub this on your skin when you are expecting exposure to extreme cold temperatures. Cannot protect from instant frostbite. Smells like the inside of a sheep.", "use_action": { "type": "cast_spell", "spell_id": "cream_prot_cold", "no_fail": true, "level": 0 }, "type": "COMESTIBLE", "weight": "265 g", diff --git a/data/mods/Aftershock/items/gun/laser.json b/data/mods/Aftershock/items/gun/laser.json index 1f73494f232db..f661f9c21a156 100644 --- a/data/mods/Aftershock/items/gun/laser.json +++ b/data/mods/Aftershock/items/gun/laser.json @@ -22,7 +22,7 @@ "type": "GUN", "copy-from": "afs_sentinel_stunner", "name": { "str": "wrist-trilaser" }, - "description": "A powerful tri-barreled laser weapon, still mounted to the robotic hand of the wraitheon drone it originally belonged too. Can still be fired when connected to an UPS.", + "description": "A powerful tri-barreled laser weapon, still mounted to the robotic hand of the wraitheon drone it originally belonged to. Can still be fired when connected to an UPS.", "color": "red", "range": 10, "ranged_damage": { "damage_type": "heat", "amount": 25, "armor_penetration": 4 }, @@ -126,7 +126,7 @@ "type": "GUN", "name": { "str": "Av-22" }, "copy-from": "v29", - "description": "A common pulse-laser pistol cleared for civilian use. Recoiless, energy-efficient, and easy to use, the av-22 is often carried as a defense weapon by those who lack the practice required to effectively use ballistic weaponry. Due to its low power, it must be fired in sequence mode to stand a chance against hardened foes.", + "description": "A common pulse-laser pistol cleared for civilian use. Recoilless, energy-efficient, and easy to use, the av-22 is often carried as a defense weapon by those who lack the practice required to effectively use ballistic weaponry. Due to its low power, it must be fired in sequence mode to stand a chance against hardened foes.", "price": "500 USD", "price_postapoc": "500 USD", "ammo": [ "battery" ], diff --git a/data/mods/Aftershock/items/gunmods/laser_gunmods.json b/data/mods/Aftershock/items/gunmods/laser_gunmods.json index 3e24a390659a6..1a166a6ab7779 100644 --- a/data/mods/Aftershock/items/gunmods/laser_gunmods.json +++ b/data/mods/Aftershock/items/gunmods/laser_gunmods.json @@ -4,7 +4,7 @@ "type": "GUNMOD", "copy-from": "electrolaser_conversion", "name": { "str": "electrolaser conversion" }, - "description": "A set of high-tech electronics and optics. This convert a laser pistol into a less-lethal electrolaser capable of stunning targets, at the cost of decreased damage output and increased power consumption.", + "description": "A set of high-tech electronics and optics. This converts a laser pistol into a less-lethal electrolaser capable of stunning targets, at the cost of decreased damage output and increased power consumption.", "damage_modifier": { "damage_type": "heat", "amount": -4 }, "range_modifier": -10, "ammo_to_fire_multiplier": 1.2 diff --git a/data/mods/Aftershock/items/items.json b/data/mods/Aftershock/items/items.json index 72acc78c9a8d6..2850b072dc91f 100644 --- a/data/mods/Aftershock/items/items.json +++ b/data/mods/Aftershock/items/items.json @@ -159,7 +159,7 @@ "id": "afs_titanium_tooth", "type": "GENERIC", "name": { "str": "titanium tooth" }, - "description": "A dental implant made of pure titanium, used to replace teeth due to its bio-compatibility and durability.", + "description": "A dental implant made of pure titanium, used to replace teeth due to its biocompatibility and durability.", "price": 5000, "price_postapoc": 50, "weight": "10 g", diff --git a/data/mods/Aftershock/items/magazine/8x40mm.json b/data/mods/Aftershock/items/magazine/8x40mm.json index 7ce95637cb29a..601ae05442828 100644 --- a/data/mods/Aftershock/items/magazine/8x40mm.json +++ b/data/mods/Aftershock/items/magazine/8x40mm.json @@ -4,7 +4,7 @@ "looks_like": "38_speedloader", "type": "MAGAZINE", "name": { "str": "RMGS5 8x40mm speedloader" }, - "description": "This speedloader, made by Rivtech for use with RM99 revolver, can hold 5 rounds of 8x40mm caseless rounds and quickly reload a compatible revolver.", + "description": "This speedloader, made by Rivtech for use with the RM99 revolver, can hold 5 rounds of 8x40mm caseless rounds and quickly reload a compatible revolver.", "weight": "92 g", "volume": "250 ml", "price": 8000, diff --git a/data/mods/Aftershock/items/tools.json b/data/mods/Aftershock/items/tools.json index c5478a27f0976..634d7b151cc72 100644 --- a/data/mods/Aftershock/items/tools.json +++ b/data/mods/Aftershock/items/tools.json @@ -134,7 +134,7 @@ "copy-from": "afs_power_cutter", "type": "TOOL", "name": { "str": "power cutter (on)", "str_pl": "power cutters (on)" }, - "description": "A huge, gas-powered saw with a diamond blade, currently a whirling blur. It's consuming gasoline, but can be used a fantastic tool for cutting metal. You can also use it as a terrifying weapon, if you're into that sort of thing.", + "description": "A huge, gas-powered saw with a diamond blade, currently a whirling blur. It's consuming gasoline, but can be used as a fantastic tool for cutting metal. You can also use it as a terrifying weapon, if you're into that sort of thing.", "cutting": 80, "turns_per_charge": 3, "revert_to": "afs_power_cutter", diff --git a/data/mods/Aftershock/items/weapons.json b/data/mods/Aftershock/items/weapons.json index d54d0bd5df043..fab508133ca3c 100644 --- a/data/mods/Aftershock/items/weapons.json +++ b/data/mods/Aftershock/items/weapons.json @@ -86,7 +86,7 @@ "looks_like": "recurbow", "color": "white", "name": { "str": "Alien lune" }, - "description": "A delicate strand of light links the antipodes of this cresent-shaped device. If the strand is interrupted, the device clanks and shudders before violently emitting a bolt of plasma from its apex.", + "description": "A delicate strand of light links the antipodes of this crescent-shaped device. If the strand is interrupted, the device clanks and shudders before violently emitting a bolt of plasma from its apex.", "price": 1000000, "price_postapoc": 20000, "material": [ "superalloy", "hardsteel" ], diff --git a/data/mods/Aftershock/maps/furniture.json b/data/mods/Aftershock/maps/furniture.json index 25e5c9d6ad353..0331899aa3867 100644 --- a/data/mods/Aftershock/maps/furniture.json +++ b/data/mods/Aftershock/maps/furniture.json @@ -4,7 +4,7 @@ "id": "f_afs_escape_pod_seat", "name": "escape pod seat", "copy-from": "f_seat_airplane", - "description": "The cushioned and upright facing seat of single-seater escape pod. A storage space beneath it holds survival supplies.", + "description": "The cushioned and upright facing seat of a single-seater escape pod. A storage space beneath it holds survival supplies.", "symbol": "H", "color": "light_red", "flags": [ "TRANSPARENT", "FLAMMABLE_ASH", "ORGANIC", "MOUNTABLE", "CAN_SIT" ], @@ -358,7 +358,7 @@ "id": "f_neuralnet_inserter", "name": "neural net inserter", "looks_like": "f_drill_press", - "description": "This device looks like a cross between some kind of nightmare dentistry equipment and socketing tool mounted on a slide that lets it drop precisely down. Useful for those project that require putting delicate items into hard to reach spaces.", + "description": "This device looks like a cross between some kind of nightmare dentistry equipment and socketing tool mounted on a slide that lets it drop precisely down. Useful for those projects that require putting delicate items into hard to reach spaces.", "symbol": "7", "color": "yellow_red", "move_cost_mod": -1, @@ -800,7 +800,7 @@ "type": "furniture", "id": "f_toposcan_terminal", "name": "DIRT data interface", - "description": "All-in-one integrated console for a Driving Intelligent Realtime Topography rover-mounted vehicular terrain scanner system. In other words, useless display monitor.", + "description": "All-in-one integrated console for a Driving Intelligent Realtime Topography rover-mounted vehicular terrain scanner system. In other words, a useless display monitor.", "looks_like": "f_console", "symbol": "?", "color": "light_gray", diff --git a/data/mods/Aftershock/maps/terrain_floraxeno.json b/data/mods/Aftershock/maps/terrain_floraxeno.json index 942bf4cba1afd..3a67dc85bae55 100644 --- a/data/mods/Aftershock/maps/terrain_floraxeno.json +++ b/data/mods/Aftershock/maps/terrain_floraxeno.json @@ -3,7 +3,7 @@ "type": "terrain", "id": "t_tree_worm", "name": "leviathan annelids", - "description": "Several massive protusions emerge from the ground, coiled together into a tower. At the top, blue and purple tentacles sway in the wind.", + "description": "Several massive protrusions emerge from the ground, coiled together into a tower. At the top, blue and purple tentacles sway in the wind.", "symbol": "I", "color": "magenta", "move_cost": 0, diff --git a/data/mods/Aftershock/maps/terrain_groundxeno.json b/data/mods/Aftershock/maps/terrain_groundxeno.json index c19729963bec1..f21d78887f670 100644 --- a/data/mods/Aftershock/maps/terrain_groundxeno.json +++ b/data/mods/Aftershock/maps/terrain_groundxeno.json @@ -417,7 +417,7 @@ "type": "terrain", "id": "t_moxfloor", "name": "bleached coral floor", - "description": "Small outgrowths of white coral spring from a underlying lattice of black, pulsating veins.", + "description": "Small outgrowths of white coral spring from an underlying lattice of black, pulsating veins.", "symbol": ".", "looks_like": "t_fungus", "color": "light_red", diff --git a/data/mods/Aftershock/mobs/robots.json b/data/mods/Aftershock/mobs/robots.json index e7f41166e18a7..6bd58ca042a00 100644 --- a/data/mods/Aftershock/mobs/robots.json +++ b/data/mods/Aftershock/mobs/robots.json @@ -174,7 +174,7 @@ "id": "afs_mon_sentinel_lx", "type": "MONSTER", "name": { "str": "Wraitheon Sentinel-lx" }, - "description": "Its exterior plates sable and gold, this luxurious variant of a Wraitheon drone was once kept as a bodyguard by society's wealthiest. Still with its wrist sword extended, it resembles an ancient knight, standing an eternal watch.", + "description": "Its exterior plates are sable and gold, this luxurious variant of a Wraitheon drone was once kept as a bodyguard by society's wealthiest. Still with its wrist sword extended, it resembles an ancient knight, standing an eternal watch.", "default_faction": "WraitheonRobotics", "species": [ "ROBOT" ], "diff": 10, @@ -534,7 +534,7 @@ "type": "MONSTER", "copy-from": "mon_milbot_base", "name": "Wraitheon Hashashiyyin", - "description": "he Hashashiyyin is unorthodox in its design as a military humaniform. While it keeps the strength of most Wraitheon humaniforms, it also prioritizes stealth. It comes equipped with an integrated 5x50mm flechette gun.", + "description": "The Hashashiyyin is unorthodox in its design as a military humaniform. While it keeps the strength of most Wraitheon humaniforms, it also prioritizes stealth. It comes equipped with an integrated 5x50mm flechette gun.", "diff": 15, "melee_damage": [ { "damage_type": "electric", "amount": 6 } ], "starting_ammo": { "5x50dart": 1000 }, diff --git a/data/mods/Aftershock/mobs/water_mobs.json b/data/mods/Aftershock/mobs/water_mobs.json index f905de14fee6a..74d02d52527aa 100644 --- a/data/mods/Aftershock/mobs/water_mobs.json +++ b/data/mods/Aftershock/mobs/water_mobs.json @@ -3,7 +3,7 @@ "id": "mon_deep_go", "type": "MONSTER", "name": { "str": "deep one" }, - "description": "An alien that appears to have evolved for survival in the depths. Its tubular grey body bears numerous sets of paired appendages of with clawed portrusions, and a pair of thick muscular fins. You see glimpses of its shape, shifting in and out of the water.", + "description": "An alien that appears to have evolved for survival in the depths. Its tubular grey body bears numerous sets of paired appendages with clawed protrusions, and a pair of thick muscular fins. You see glimpses of its shape, shifting in and out of the water.", "default_faction": "mi-go", "bodytype": "migo", "species": [ "NETHER" ], @@ -54,7 +54,7 @@ "id": "mon_deep_go_slaver", "type": "MONSTER", "name": { "str": "deep one slaver" }, - "description": "An alien that appears to have evolved for survival in the depths. Its tubular grey body bears numerous sets of paired appendages of with clawed portrusions, and a pair of thick muscular fins. You see glimpses of its shape, shifting in and out of the water. It is carrying a conical object that hums with an odd keening sound.", + "description": "An alien that appears to have evolved for survival in the depths. Its tubular grey body bears numerous sets of paired appendages with clawed protrusions, and a pair of thick muscular fins. You see glimpses of its shape, shifting in and out of the water. It is carrying a conical object that hums with an odd keening sound.", "default_faction": "mi-go", "bodytype": "migo", "species": [ "NETHER" ], diff --git a/data/mods/Aftershock/mutations/mutations.json b/data/mods/Aftershock/mutations/mutations.json index 1a35967601017..24122b71cf8ab 100644 --- a/data/mods/Aftershock/mutations/mutations.json +++ b/data/mods/Aftershock/mutations/mutations.json @@ -269,7 +269,7 @@ "id": "EERIE", "name": "Eerie", "points": 1, - "description": "You are offputting to others. You're mannerisms have changed as if human interaction is becoming foreign.", + "description": "You are off-putting to others. Your mannerisms have changed as if human interaction is becoming foreign.", "category": [ "MIGO" ], "social_modifiers": { "persuade": -15, "lie": -10 }, "ugliness": 2 @@ -629,7 +629,7 @@ "name": "Trumpeting Voice", "points": -1, "mixed_effect": true, - "description": "You have a trumpeting, elephantine voice. Threatening NPCs will be easier, but lying will very hard.", + "description": "You have a trumpeting, elephantine voice. Threatening NPCs will be easier, but lying will be very hard.", "changes_to": [ "SNARL" ], "category": [ "MASTODON" ], "social_modifiers": { "lie": -30, "intimidate": 10 } diff --git a/data/mods/Aftershock/mutations/obsolete.json b/data/mods/Aftershock/mutations/obsolete.json index f68356232f2bd..5b24fe475aa15 100644 --- a/data/mods/Aftershock/mutations/obsolete.json +++ b/data/mods/Aftershock/mutations/obsolete.json @@ -284,7 +284,7 @@ "points": -2, "visibility": 4, "ugliness": 5, - "description": "You smell like exactly like a shaggy elephant would, assuming it sweated, which you do. Monsters that track scent will find you very easily, and humans will react poorly.", + "description": "You smell exactly like a shaggy elephant would, assuming it sweated, which you do. Monsters that track scent will find you very easily, and humans will react poorly.", "valid": false, "scent_intensity": 1200, "prereqs": [ "ELEPHANTINE_SMELL" ], diff --git a/data/mods/Aftershock/player/professions.json b/data/mods/Aftershock/player/professions.json index 35ee54c408a08..f23c6ca95c82c 100644 --- a/data/mods/Aftershock/player/professions.json +++ b/data/mods/Aftershock/player/professions.json @@ -107,7 +107,7 @@ "type": "profession", "id": "afs_atomic_pitchman", "name": { "male": "Atomic Pitchman", "female": "Atomic Pitchwoman" }, - "description": "You were hired to market Rivtech's products through TV and were on your way to the studio when the bombs hit. You enter now the end of the world with nothing but the snazzy clothes on your back and a bunch of plutonium-powered toys.", + "description": "You were hired to market Rivtech's products through TV and were on your way to the studio when the bombs hit. You now enter the end of the world with nothing but the snazzy clothes on your back and a bunch of plutonium-powered toys.", "points": 3, "skills": [ { "level": 1, "name": "speech" } ], "items": { @@ -192,7 +192,7 @@ "id": "afs_wraitheon_executive", "name": "Wraitheon Executive", "description": { - "str": "You were one of the chief executives of the Megacorporation Wraitheon Robotics ltd. and consistently ranked among the most powerful and influential persons of the world. Still, the apocalypse has caught you unprepared, and now after the dissolution of your company and the crumbling of your network of influence, your were left powerless and destitute, and must rely on your two robotic bodyguards to survive.", + "str": "You were one of the chief executives of the Megacorporation Wraitheon Robotics ltd. and consistently ranked among the most powerful and influential persons of the world. Still, the apocalypse has caught you unprepared, and now after the dissolution of your company and the crumbling of your network of influence, you are left powerless and destitute, and must rely on your two robotic bodyguards to survive.", "//NOLINT(cata-text-style)": "not a period" }, "points": 8, diff --git a/data/mods/Aftershock/scenarios.json b/data/mods/Aftershock/scenarios.json index d088fd7efa4da..2028f491d72e2 100644 --- a/data/mods/Aftershock/scenarios.json +++ b/data/mods/Aftershock/scenarios.json @@ -88,7 +88,7 @@ "id": "escape_pod", "name": "Stranded Spacer", "points": 1, - "description": "What was to be a routine cargo transfer ended in tragedy when, in a brief moment of chaos, your space ship was intercepted and destroyed by a StO missile. As soon as the MAW alarm flared to life, you scrambled to the nearest escape pod and barely managed reach the uncertain safety of the planet below.", + "description": "What was to be a routine cargo transfer ended in tragedy when, in a brief moment of chaos, your space ship was intercepted and destroyed by a StO missile. As soon as the MAW alarm flared to life, you scrambled to the nearest escape pod and barely managed to reach the uncertain safety of the planet below.", "allowed_locs": [ "sloc_escape_pod" ], "professions": [ "afs_espatier", "afs_rating" ], "flags": [ "LONE_START" ], From 2d28500a8a1f62b172dfba1ba1eb3326467dae9c Mon Sep 17 00:00:00 2001 From: Lamandus <33199510+Lamandus@users.noreply.github.com> Date: Wed, 3 Mar 2021 23:47:20 +0100 Subject: [PATCH 245/453] Tweaks for teas (#47848) --- data/json/items/comestibles/drink.json | 29 ++++++++++++---------- data/json/items/comestibles/other.json | 3 +-- data/json/items/comestibles/raw_veggy.json | 9 ++++--- 3 files changed, 22 insertions(+), 19 deletions(-) diff --git a/data/json/items/comestibles/drink.json b/data/json/items/comestibles/drink.json index 767e3acc26509..cf5f49f876cf7 100644 --- a/data/json/items/comestibles/drink.json +++ b/data/json/items/comestibles/drink.json @@ -102,7 +102,8 @@ "description": "A healthy beverage made from bee balm steeped in boiling water. Can be used to reduce negative effects of common cold or flu.", "price": 100, "price_postapoc": 25, - "fun": 1 + "fun": 1, + "flags": [ "EATEN_HOT" ] }, { "type": "COMESTIBLE", @@ -162,10 +163,11 @@ "spoils_in": "10 days", "quench": 34, "healthy": 1, - "calories": 0, + "calories": 1, "description": "A healthy beverage made from chamomile flowers steeped in boiling water. Can be used to treat insomnia.", "price": 100, "price_postapoc": 25, + "flags": [ "EATEN_HOT", "NUTRIENT_OVERRIDE" ], "fun": 1 }, { @@ -388,14 +390,14 @@ "symbol": "~", "quench": 48, "healthy": 1, - "calories": 26, + "calories": 1, "description": "A healthy beverage made from dandelion roots steeped in boiling water.", "price": 50, "price_postapoc": 25, "volume": "250 ml", "material": [ "water" ], "phase": "liquid", - "flags": [ "EATEN_HOT" ], + "flags": [ "EATEN_HOT", "NUTRIENT_OVERRIDE" ], "fun": 2 }, { @@ -496,14 +498,14 @@ "symbol": "~", "quench": 44, "healthy": 1, - "calories": 9, + "calories": 1, "description": "A healthy beverage made from herbs steeped in boiling water.", "price": 100, "price_postapoc": 25, "volume": "250 ml", "material": [ "water" ], "phase": "liquid", - "flags": [ "EATEN_HOT" ], + "flags": [ "EATEN_HOT", "NUTRIENT_OVERRIDE" ], "fun": 4 }, { @@ -646,11 +648,11 @@ "spoils_in": "10 days", "quench": 34, "healthy": 1, - "calories": 0, "description": "A healthy beverage made from lotus flowers steeped in boiling water.", "price": 100, "price_postapoc": 25, - "fun": 1 + "fun": 1, + "flags": [ "EATEN_HOT", "NUTRIENT_OVERRIDE" ] }, { "id": "mex_chocolate", @@ -769,7 +771,8 @@ "phase": "liquid", "charges": 2, "vitamins": [ [ "vitA", 5 ], [ "vitB", 3 ], [ "vitC", 2 ], [ "calcium", 12 ] ], - "fun": 10 + "fun": 10, + "flags": [ "EATEN_HOT" ] }, { "type": "COMESTIBLE", @@ -832,6 +835,7 @@ "price": 0, "price_postapoc": 25, "volume": "250 ml", + "calories": 1, "material": [ "water" ], "phase": "liquid", "flags": [ "EATEN_HOT", "NUTRIENT_OVERRIDE" ], @@ -964,11 +968,12 @@ "spoils_in": "10 days", "quench": 34, "healthy": 1, - "calories": 0, + "calories": 1, "description": "A healthy beverage made from spurge flowers steeped in boiling water. Can be used to prevent asthma attacks.", "price": 100, "price_postapoc": 25, "fun": 1, + "flags": [ "EATEN_HOT", "NUTRIENT_OVERRIDE" ], "use_action": { "type": "consume_drug", "activation_message": "You no longer need to worry about asthma attacks, at least for a while.", @@ -1027,7 +1032,7 @@ "comestible_type": "DRINK", "symbol": "~", "quench": 40, - "calories": 2, + "calories": 1, "description": "The beverage of gentlemen everywhere, made from applying hot water to oxidized leaves of the tea plant /Camellia sinensis/.", "price": 90, "price_postapoc": 25, @@ -1133,7 +1138,6 @@ "color": "green", "fatigue_mod": 7, "stim": 2, - "calories": 2, "description": "Made from applying hot water to leaves of the tea plant /Camellia sinensis/. Green tea has a lighter, fresher taste than black and is traditionally preferred in Asian cultures." }, { @@ -1142,7 +1146,6 @@ "name": { "str": "fruit tea" }, "copy-from": "tea", "color": "red", - "calories": 0, "fatigue_mod": 0, "stim": 0, "description": "A tasty beverage made with herbs and dried fruit from plants other than the tea plant. While colloquially called 'tea', technically it's an infusion.", diff --git a/data/json/items/comestibles/other.json b/data/json/items/comestibles/other.json index 7aea6e36a17d6..7f30fadddfd09 100644 --- a/data/json/items/comestibles/other.json +++ b/data/json/items/comestibles/other.json @@ -853,6 +853,7 @@ "color": "white", "symbol": "?", "container": "box_tea", + "calories": 1, "material": [ "paper" ], "price": 50, "price_postapoc": 200, @@ -878,7 +879,6 @@ "type": "COMESTIBLE", "name": { "str": "herbal tea bag" }, "copy-from": "tea_bag", - "calories": 9, "description": "A paper sachet with dried wild herbs inside. Put it into boiling water to make a cup of herbal tea." }, { @@ -886,7 +886,6 @@ "type": "COMESTIBLE", "name": { "str": "dandelion tea bag" }, "copy-from": "tea_bag", - "calories": 26, "description": "A paper sachet with dried dandelion roots inside. Put it into boiling water to make a cup of dandelion tea." }, { diff --git a/data/json/items/comestibles/raw_veggy.json b/data/json/items/comestibles/raw_veggy.json index cb384ab5531e4..4a9eb15fbc77d 100644 --- a/data/json/items/comestibles/raw_veggy.json +++ b/data/json/items/comestibles/raw_veggy.json @@ -736,22 +736,23 @@ "type": "COMESTIBLE", "id": "tea_raw", "name": { "str": "black tea leaf", "str_pl": "black tea leaves" }, - "weight": "14 g", + "weight": "3 g", "color": "green", "fatigue_mod": 3, "stim": 1, "container": "bag_plastic", "comestible_type": "FOOD", "symbol": "%", - "calories": 17, + "calories": 1, "description": "Dried leaves of a tropical plant. You can boil them into tea, or you can just eat them raw. They aren't too filling though.", "price": 1030, "price_postapoc": 250, "material": [ "veggy" ], "primary_material": "dried_vegetable", - "volume": "250 ml", + "volume": "320 ml", "flags": [ "EDIBLE_FROZEN", "RAW", "IRREPLACEABLE_CONSUMABLE" ], - "charges": 20, + "charges": 33, + "//": "Tea is sold by weight not by volume. 1 kg of tea has a volume of 3,4 liters. We use smaller packs of at least 100 mg. Such a tea has a volume of 340 ml minus package makes it around 320 ml. 3 g per serving makes 33 charges.", "fun": -1 }, { From 1829713d5a6b07e5492e9332fda34994b9469710 Mon Sep 17 00:00:00 2001 From: actual-nh <74678550+actual-nh@users.noreply.github.com> Date: Tue, 2 Mar 2021 19:46:22 -0500 Subject: [PATCH 246/453] Have travis run for 0.F-dev (#47844) Currently, .travis.yml has a 'development' branch specified as one to run tests for; the current equivalent is the 0.F-dev branch. --- .travis.yml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/.travis.yml b/.travis.yml index 0c488ee209c36..13e4b8e6293d3 100644 --- a/.travis.yml +++ b/.travis.yml @@ -27,7 +27,7 @@ os: linux branches: only: - master - - development + - 0.F-dev # Overall strategy for what sorts of builds to include: # We want a build for each compiler and each platform. From 6d6cf37d24564b08805ff7b02563d87e1664e1fd Mon Sep 17 00:00:00 2001 From: Lamandus <33199510+Lamandus@users.noreply.github.com> Date: Wed, 3 Mar 2021 23:51:31 +0100 Subject: [PATCH 247/453] Tweakes to copper and metal pipes. (#47825) --- data/json/items/resources/metal.json | 10 ++++++---- 1 file changed, 6 insertions(+), 4 deletions(-) diff --git a/data/json/items/resources/metal.json b/data/json/items/resources/metal.json index 45d9ae1a6123c..a1496900e4f17 100644 --- a/data/json/items/resources/metal.json +++ b/data/json/items/resources/metal.json @@ -3,16 +3,17 @@ "type": "GENERIC", "id": "pipe", "name": { "str": "pipe" }, - "description": "A steel pipe, makes a good melee weapon. Useful in a few crafting recipes.", + "description": "A steel pipe; makes a good melee weapon. Useful in a few crafting recipes.", "category": "spare_parts", "weight": "1250 g", + "longest_side": "60 cm", "to_hit": 1, "color": "dark_gray", "symbol": "/", "material": [ "steel" ], "qualities": [ [ "HAMMER", 1 ] ], "techniques": [ "WBLOCK_1" ], - "volume": "1 L", + "volume": "370 ml", "bashing": 12, "price": 7500, "price_postapoc": 10 @@ -57,15 +58,16 @@ "type": "GENERIC", "id": "cu_pipe", "name": { "str": "copper tubing" }, - "description": "A copper tube, too thin to be much use as a melee weapon, but will do if nothing else is available. Useful in a few crafting recipes.", + "description": "A copper tube; too thin to be much use as a melee weapon, but will do if nothing else is available. Useful in a few crafting recipes.", "category": "spare_parts", "weight": "345 g", + "longest_side": "60 cm", "to_hit": -1, "color": "light_red", "symbol": "/", "material": [ "copper" ], "techniques": [ "WBLOCK_1" ], - "volume": "500 ml", + "volume": "370 ml", "bashing": 5, "price": 7500, "price_postapoc": 10 From 502d92be2e772dd005e41f861c8a009f374c4d56 Mon Sep 17 00:00:00 2001 From: Maleclypse <54345792+Maleclypse@users.noreply.github.com> Date: Wed, 3 Mar 2021 17:00:47 -0600 Subject: [PATCH 248/453] Fried eggs deluxe, sandwiches, and condiment list (#47786) --- data/json/items/comestibles/egg.json | 48 ++++++++++++++ data/json/recipes/recipe_food.json | 65 +++++++++++++++++++ .../json/requirements/cooking_components.json | 17 +++++ 3 files changed, 130 insertions(+) diff --git a/data/json/items/comestibles/egg.json b/data/json/items/comestibles/egg.json index 5d17be2fbaa06..d06956948c024 100644 --- a/data/json/items/comestibles/egg.json +++ b/data/json/items/comestibles/egg.json @@ -354,6 +354,54 @@ "fun": 2, "flags": [ "EATEN_HOT", "FREEZERBURN" ] }, + { + "type": "COMESTIBLE", + "id": "deluxe_fried_eggs", + "name": { "str_sp": "deluxe fried eggs" }, + "copy-from": "scrambled_eggs", + "color": "yellow", + "symbol": "%", + "quench": -1, + "calories": 322, + "description": "Deluxe sunny-side up eggs fried with a runny yolk and just a bit of crisp on the edges with cheese or a vegetable, garnish and condiment.", + "price": 500, + "price_postapoc": 120, + "material": [ "egg", "veggy" ], + "fun": 2, + "flags": [ "EATEN_HOT", "FREEZERBURN" ] + }, + { + "type": "COMESTIBLE", + "id": "fried_egg_sandwich", + "name": { "str_sp": "fried egg sandwich" }, + "copy-from": "scrambled_eggs", + "color": "yellow", + "symbol": "%", + "quench": -1, + "calories": 422, + "description": "Sunny-side up eggs fried with a runny yolk and just a bit of crisp on the edges. Made into a sandwich, just like Sunday morning.", + "price": 500, + "price_postapoc": 120, + "material": [ "egg", "wheat" ], + "fun": 2, + "flags": [ "EATEN_HOT", "FREEZERBURN" ] + }, + { + "type": "COMESTIBLE", + "id": "deluxe_fried_egg_sandwich", + "name": { "str_sp": "deluxe fried egg sandwich" }, + "copy-from": "scrambled_eggs", + "color": "yellow", + "symbol": "%", + "quench": -1, + "calories": 422, + "description": "Deluxe sunny-side up eggs fried with a runny yolk and just a bit of crisp on the edges. Made into a sandwich, just like Sunday morning.", + "price": 500, + "price_postapoc": 120, + "material": [ "egg", "wheat" ], + "fun": 2, + "flags": [ "EATEN_HOT", "FREEZERBURN" ] + }, { "type": "COMESTIBLE", "id": "pickled_egg", diff --git a/data/json/recipes/recipe_food.json b/data/json/recipes/recipe_food.json index 6b8706fc18a1b..16da46e19d8e1 100644 --- a/data/json/recipes/recipe_food.json +++ b/data/json/recipes/recipe_food.json @@ -3611,6 +3611,71 @@ "tools": [ [ [ "surface_heat", 2, "LIST" ] ] ], "components": [ [ [ "eggs_bird", 2, "LIST" ], [ "egg_reptile", 2 ] ], [ [ "any_butter_or_oil", 2, "LIST" ] ] ] }, + { + "type": "recipe", + "activity_level": "LIGHT_EXERCISE", + "result": "deluxe_fried_eggs", + "category": "CC_FOOD", + "subcategory": "CSC_FOOD_OTHER", + "skill_used": "cooking", + "difficulty": 2, + "time": "8 m", + "autolearn": true, + "batch_time_factors": [ 80, 2 ], + "qualities": [ { "id": "COOK", "level": 2 } ], + "tools": [ [ [ "surface_heat", 2, "LIST" ] ] ], + "components": [ + [ [ "eggs_bird", 2, "LIST" ], [ "egg_reptile", 2 ] ], + [ [ "any_butter_or_oil", 2, "LIST" ] ], + [ [ "mushroom", 1 ], [ "mushroom_morel", 1 ], [ "garlic_clove", 1 ], [ "onion", 1 ] ], + [ [ "cheese", 1 ], [ "cheese_hard", 1 ], [ "can_cheese", 1 ], [ "veggy_green", 1, "LIST" ] ], + [ [ "salt_preservation", 2, "LIST" ] ], + [ [ "condiment", 2, "LIST" ] ] + ] + }, + { + "type": "recipe", + "activity_level": "LIGHT_EXERCISE", + "result": "fried_egg_sandwich", + "category": "CC_FOOD", + "subcategory": "CSC_FOOD_OTHER", + "skill_used": "cooking", + "difficulty": 2, + "time": "6 m", + "autolearn": true, + "batch_time_factors": [ 80, 2 ], + "qualities": [ { "id": "COOK", "level": 2 } ], + "tools": [ [ [ "surface_heat", 2, "LIST" ] ] ], + "components": [ + [ [ "eggs_bird", 2, "LIST" ], [ "egg_reptile", 2 ] ], + [ [ "any_butter_or_oil", 2, "LIST" ] ], + [ [ "bread_sandwich", 2, "LIST" ] ], + [ [ "condiment", 2, "LIST" ] ] + ] + }, + { + "type": "recipe", + "activity_level": "LIGHT_EXERCISE", + "result": "deluxe_fried_egg_sandwich", + "category": "CC_FOOD", + "subcategory": "CSC_FOOD_OTHER", + "skill_used": "cooking", + "difficulty": 2, + "time": "8 m", + "autolearn": true, + "batch_time_factors": [ 80, 2 ], + "qualities": [ { "id": "COOK", "level": 2 } ], + "tools": [ [ [ "surface_heat", 2, "LIST" ] ] ], + "components": [ + [ [ "eggs_bird", 2, "LIST" ], [ "egg_reptile", 2 ] ], + [ [ "any_butter_or_oil", 2, "LIST" ] ], + [ [ "mushroom", 1 ], [ "mushroom_morel", 1 ], [ "garlic_clove", 1 ], [ "onion", 1 ] ], + [ [ "cheese", 1 ], [ "cheese_hard", 1 ], [ "can_cheese", 1 ], [ "veggy_green", 1, "LIST" ] ], + [ [ "salt_preservation", 2, "LIST" ] ], + [ [ "condiment", 2, "LIST" ] ], + [ [ "bread_sandwich", 2, "LIST" ] ] + ] + }, { "type": "recipe", "activity_level": "NO_EXERCISE", diff --git a/data/json/requirements/cooking_components.json b/data/json/requirements/cooking_components.json index f951bc13d5150..5b2913d707145 100644 --- a/data/json/requirements/cooking_components.json +++ b/data/json/requirements/cooking_components.json @@ -544,6 +544,23 @@ ] ] }, + { + "id": "condiment", + "type": "requirement", + "//": " Should be about a teaspoon, or smallest serving", + "components": [ + [ + [ "mayonnaise", 1 ], + [ "mustard", 1 ], + [ "soysauce", 1 ], + [ "hot_sauce", 1 ], + [ "ketchup", 1 ], + [ "horseradish", 1 ], + [ "sauerkraut", 1 ], + [ "butter", 1 ] + ] + ] + }, { "id": "salt_preservation", "type": "requirement", From 9800743c025ac8fb32110a766d42f24ebe389add Mon Sep 17 00:00:00 2001 From: Maleclypse <54345792+Maleclypse@users.noreply.github.com> Date: Wed, 3 Mar 2021 17:02:28 -0600 Subject: [PATCH 249/453] Homemade toastems, buttercream frosting and recipes (#47696) --- data/json/items/comestibles/junkfood.json | 45 +++++++++++++++++++ data/json/recipes/recipe_food.json | 53 +++++++++++++++++++++++ 2 files changed, 98 insertions(+) diff --git a/data/json/items/comestibles/junkfood.json b/data/json/items/comestibles/junkfood.json index f3288ba8378ac..1e6b73eaa5ebd 100644 --- a/data/json/items/comestibles/junkfood.json +++ b/data/json/items/comestibles/junkfood.json @@ -37,6 +37,14 @@ "description": "Dry toaster pastries, usually coated with solid frosting. Sadly, these are not.", "fun": 10 }, + { + "type": "COMESTIBLE", + "id": "toastem4", + "name": { "str": "homemade toast-em" }, + "copy-from": "toastem", + "description": "Homemade toaster pastries, lacking icing but at least fruit filled.", + "fun": 10 + }, { "type": "COMESTIBLE", "id": "toasterpastryfrozen", @@ -68,6 +76,43 @@ "description": "A delicious fruit-filled pastry that you've cooked. It even comes with frosting!", "fun": 20 }, + { + "type": "COMESTIBLE", + "id": "homemade_toasterpastry", + "name": { "str": "toaster pastry", "str_pl": "toaster pastries" }, + "copy-from": "toasterpastryfrozen", + "quench": 4, + "description": "A delicious homemade fruit-filled pastry that you've cooked.", + "fun": 20 + }, + { + "type": "COMESTIBLE", + "id": "homemade_toasterpastry2", + "name": { "str": "toaster pastry with buttercream", "str_pl": "toaster pastries with buttercream" }, + "copy-from": "toasterpastryfrozen", + "quench": 4, + "description": "A delicious homemade fruit-filled pastry that you've cooked. It even comes with buttercream!", + "fun": 30 + }, + { + "type": "COMESTIBLE", + "id": "buttercream", + "name": { "str": "buttercream icing", "str_pl": "cups of buttercream icing" }, + "weight": "32 g", + "color": "brown", + "container": "bag_plastic", + "comestible_type": "FOOD", + "symbol": "%", + "calories": 288, + "description": "Smooth sugary buttercream icing. Almost good enough to forget the end of everything.", + "price": 100, + "price_postapoc": 400, + "material": [ "junk" ], + "volume": "1 L", + "charges": 8, + "flags": [ "EDIBLE_FROZEN" ], + "fun": 6 + }, { "type": "COMESTIBLE", "id": "chips2", diff --git a/data/json/recipes/recipe_food.json b/data/json/recipes/recipe_food.json index 16da46e19d8e1..c3ab7e4257802 100644 --- a/data/json/recipes/recipe_food.json +++ b/data/json/recipes/recipe_food.json @@ -5382,6 +5382,20 @@ "book_learn": [ [ "mag_glam", 1 ] ], "components": [ [ [ "bread_sandwich", 1, "LIST" ] ], [ [ "any_butter", 1, "LIST" ] ], [ [ "sprinkles", 3 ] ] ] }, + { + "type": "recipe", + "activity_level": "LIGHT_EXERCISE", + "result": "toastem4", + "category": "CC_FOOD", + "subcategory": "CSC_FOOD_SNACK", + "skill_used": "cooking", + "time": "40 m", + "charges": 6, + "book_learn": [ [ "baking_book", 1 ] ], + "qualities": [ { "id": "CUT", "level": 1 }, { "id": "COOK", "level": 2 } ], + "tools": [ [ [ "surface_heat", 20, "LIST" ] ] ], + "components": [ [ [ "flour", 12 ] ], [ [ "eggs_bird", 1, "LIST" ] ], [ [ "jam_fruit", 9 ] ], [ [ "cornmeal", 1 ] ] ] + }, { "type": "recipe", "activity_level": "LIGHT_EXERCISE", @@ -5395,6 +5409,45 @@ "tools": [ [ [ "surface_heat", 10, "LIST" ] ] ], "components": [ [ [ "toasterpastryfrozen", 1 ] ] ] }, + { + "type": "recipe", + "activity_level": "LIGHT_EXERCISE", + "result": "homemade_toasterpastry", + "category": "CC_FOOD", + "subcategory": "CSC_FOOD_SNACK", + "skill_used": "cooking", + "time": "2 m 30 s", + "charges": 1, + "autolearn": true, + "tools": [ [ [ "surface_heat", 10, "LIST" ] ] ], + "components": [ [ [ "toastem4", 1 ] ] ] + }, + { + "type": "recipe", + "activity_level": "LIGHT_EXERCISE", + "result": "homemade_toasterpastry2", + "category": "CC_FOOD", + "subcategory": "CSC_FOOD_SNACK", + "skill_used": "cooking", + "time": "2 m 30 s", + "charges": 1, + "autolearn": true, + "tools": [ [ [ "surface_heat", 10, "LIST" ] ] ], + "components": [ [ [ "toastem4", 1 ] ], [ [ "buttercream", 1 ] ] ] + }, + { + "type": "recipe", + "activity_level": "LIGHT_EXERCISE", + "result": "buttercream", + "category": "CC_FOOD", + "subcategory": "CSC_FOOD_SNACK", + "skill_used": "cooking", + "difficulty": 1, + "time": "6 m 30 s", + "autolearn": true, + "qualities": [ { "id": "COOK", "level": 1 } ], + "components": [ [ [ "milk_cream", 1 ] ], [ [ "butter", 16 ] ], [ [ "sugar_standard", 1, "LIST" ] ] ] + }, { "type": "recipe", "activity_level": "LIGHT_EXERCISE", From a453378705686c892edf420e6e77cce9f2ae77fb Mon Sep 17 00:00:00 2001 From: Fris0uman Date: Fri, 19 Feb 2021 18:20:04 +0100 Subject: [PATCH 250/453] [My Sweet Cataclysm] Chocolate Cows don't drop "cow pies" (#47609) --- data/mods/My_Sweet_Cataclysm/sweet_items.json | 17 +++++++++++++++++ .../mods/My_Sweet_Cataclysm/sweet_monsters.json | 2 ++ 2 files changed, 19 insertions(+) diff --git a/data/mods/My_Sweet_Cataclysm/sweet_items.json b/data/mods/My_Sweet_Cataclysm/sweet_items.json index 274223cca9368..9def6b336f864 100644 --- a/data/mods/My_Sweet_Cataclysm/sweet_items.json +++ b/data/mods/My_Sweet_Cataclysm/sweet_items.json @@ -28,6 +28,23 @@ "calories": 10, "vitamins": [ ] }, + { + "type": "COMESTIBLE", + "comestible_type": "FOOD", + "id": "feces_candy", + "symbol": "^", + "name": { "str_sp": "sticky sludge" }, + "charges": 10, + "volume": "1000 ml", + "weight": "100 g", + "color": "white", + "looks_like": "ruined_candy", + "description": "A pile of weird sticky sludge. It looks absolutly disgusting but smells kind of sweet.", + "material": [ "junk" ], + "calories": 10, + "fun": -12, + "vitamins": [ ] + }, { "id": "rock_candy_chunk", "type": "TOOL", diff --git a/data/mods/My_Sweet_Cataclysm/sweet_monsters.json b/data/mods/My_Sweet_Cataclysm/sweet_monsters.json index 81894d4a8f671..5d5e1d9266c71 100644 --- a/data/mods/My_Sweet_Cataclysm/sweet_monsters.json +++ b/data/mods/My_Sweet_Cataclysm/sweet_monsters.json @@ -491,6 +491,7 @@ "description": "The domestic cow, a baleful, ruminating farm animal. It is quite muscular, and the males can have a violent streak to accompany their nasty-looking horns. This one looks to be made entirely of chocolate.", "copy-from": "mon_cow_calf", "harvest": "choc_cows", + "biosignature": { "biosig_item": "feces_candy", "biosig_timer": "1 d" }, "upgrades": { "age_grow": 180, "into": "mon_cow_choc" } }, { @@ -501,6 +502,7 @@ "copy-from": "mon_cow", "harvest": "choc_cows", "starting_ammo": { "milk_raw_choc": 40 }, + "biosignature": { "biosig_item": "feces_candy", "biosig_timer": "1 d" }, "reproduction": { "baby_monster": "mon_cow_calf_choc", "baby_count": 1, "baby_timer": 343 } }, { From cb1d9a5dd90b420ca0a1906c0fb5d3ef9e6958af Mon Sep 17 00:00:00 2001 From: Fris0uman Date: Wed, 3 Mar 2021 18:22:23 +0100 Subject: [PATCH 251/453] Remove unused FATIGUE energy source from spells (#47852) --- data/mods/Magiclysm/Spells/debug.json | 15 --------------- doc/MAGIC.md | 2 +- src/activity_handlers.cpp | 3 --- src/magic.cpp | 12 ------------ src/magic.h | 1 - 5 files changed, 1 insertion(+), 32 deletions(-) diff --git a/data/mods/Magiclysm/Spells/debug.json b/data/mods/Magiclysm/Spells/debug.json index a0ac89ceecd15..c99193044fa48 100644 --- a/data/mods/Magiclysm/Spells/debug.json +++ b/data/mods/Magiclysm/Spells/debug.json @@ -112,21 +112,6 @@ "base_energy_cost": 100, "energy_source": "STAMINA" }, - { - "id": "debug_fatigue", - "type": "SPELL", - "name": "Debug Fatigue Spell", - "description": "Uses a little fatigue", - "message": "Debug spell %s cast.", - "valid_targets": [ "self" ], - "effect": "none", - "shape": "blast", - "min_range": 1, - "max_range": 1, - "base_casting_time": 100, - "base_energy_cost": 100, - "energy_source": "FATIGUE" - }, { "id": "debug_polymorph", "type": "SPELL", diff --git a/doc/MAGIC.md b/doc/MAGIC.md index eb74d0bf4b570..9d66f225036f4 100644 --- a/doc/MAGIC.md +++ b/doc/MAGIC.md @@ -21,7 +21,7 @@ In `data/mods/Magiclysm` there is a template spell, copied here for your perusal "spell_class": "NONE", // "base_casting_time": 100, // this is the casting time (in moves) "base_energy_cost": 10, // the amount of energy (of the requisite type) to cast the spell - "energy_source": "MANA", // the type of energy used to cast the spell. types are: MANA, BIONIC, HP, STAMINA, FATIGUE, NONE (none will not use mana) + "energy_source": "MANA", // the type of energy used to cast the spell. types are: MANA, BIONIC, HP, STAMINA, NONE (none will not use mana) "components": [requirement_id] // an id from a requirement, like the ones you use for crafting. spell components require to cast. "difficulty": 12, // the difficulty to learn/cast the spell "max_level": 10, // maximum level you can achieve in the spell diff --git a/src/activity_handlers.cpp b/src/activity_handlers.cpp index 8deb436a90773..76423042b7f4f 100644 --- a/src/activity_handlers.cpp +++ b/src/activity_handlers.cpp @@ -4275,9 +4275,6 @@ void activity_handlers::spellcasting_finish( player_activity *act, player *p ) case magic_energy_type::hp: blood_magic( p, cost ); break; - case magic_energy_type::fatigue: - p->mod_fatigue( cost ); - break; case magic_energy_type::none: default: break; diff --git a/src/magic.cpp b/src/magic.cpp index e46b3acaee3ce..49eb84e3851e4 100644 --- a/src/magic.cpp +++ b/src/magic.cpp @@ -153,7 +153,6 @@ std::string enum_to_string( magic_energy_type data ) { switch( data ) { case magic_energy_type::bionic: return "BIONIC"; - case magic_energy_type::fatigue: return "FATIGUE"; case magic_energy_type::hp: return "HP"; case magic_energy_type::mana: return "MANA"; case magic_energy_type::none: return "NONE"; @@ -1047,8 +1046,6 @@ std::string spell::energy_string() const return _( "stamina" ); case magic_energy_type::bionic: return _( "kJ" ); - case magic_energy_type::fatigue: - return _( "fatigue" ); default: return ""; } @@ -1070,9 +1067,6 @@ std::string spell::energy_cost_string( const Character &guy ) const auto pair = get_hp_bar( energy_cost( guy ), guy.get_stamina_max() ); return colorize( pair.first, pair.second ); } - if( energy_source() == magic_energy_type::fatigue ) { - return colorize( std::to_string( energy_cost( guy ) ), c_cyan ); - } debugmsg( "ERROR: Spell %s has invalid energy source.", id().c_str() ); return _( "error: energy_type" ); } @@ -1095,10 +1089,6 @@ std::string spell::energy_cur_string( const Character &guy ) const if( energy_source() == magic_energy_type::hp ) { return ""; } - if( energy_source() == magic_energy_type::fatigue ) { - const std::pair pair = guy.get_fatigue_description(); - return colorize( pair.first, pair.second ); - } debugmsg( "ERROR: Spell %s has invalid energy source.", id().c_str() ); return _( "error: energy_type" ); } @@ -1729,8 +1719,6 @@ bool known_magic::has_enough_energy( const Character &guy, const spell &sp ) con } } return false; - case magic_energy_type::fatigue: - return guy.get_fatigue() < fatigue_levels::EXHAUSTED; case magic_energy_type::none: return true; default: diff --git a/src/magic.h b/src/magic.h index fe4195a46d1b2..a4b7ed49c7d6f 100644 --- a/src/magic.h +++ b/src/magic.h @@ -82,7 +82,6 @@ enum class magic_energy_type : int { mana, stamina, bionic, - fatigue, none, last }; From af0d47bdb18de58ff98405293c1b8c0bab69b71e Mon Sep 17 00:00:00 2001 From: Curtis Merrill Date: Wed, 3 Mar 2021 18:19:31 -0500 Subject: [PATCH 252/453] [Magiclysm] add owlbear origin snippet (#47752) --- data/mods/Magiclysm/snippets/survivor_notes.json | 12 ++++++++++++ 1 file changed, 12 insertions(+) create mode 100644 data/mods/Magiclysm/snippets/survivor_notes.json diff --git a/data/mods/Magiclysm/snippets/survivor_notes.json b/data/mods/Magiclysm/snippets/survivor_notes.json new file mode 100644 index 0000000000000..cd03a44abc5b0 --- /dev/null +++ b/data/mods/Magiclysm/snippets/survivor_notes.json @@ -0,0 +1,12 @@ +[ + { + "type": "snippet", + "category": "note", + "text": [ + { + "id": "magiclysm_note_1", + "text": "\"(Spell Name) RECIPE V3\n---\nRare Ingredients:\n- 17 drams owl's blood - less no effect, more turns bear into large owl\n- 1 gastrolith, large american alligator\n- 3 teeth or claws from a honey badger\n- 8 pounds bear meat, preferably polar bear, grizzly will suffice\nBring a large pot (meat must fully submerge) filled about half way with potion starter fluid (high grade) to a boil. Add gastrolith and teeth/claws after boiling, add the blood, stir counterclockwise for a minute while chanting standard polymorph spell. Continue until concoction has a slight glow. Add the bear meat, remove from heat, cover for 24 hours.\nBear MUST eat all 8 pounds of the meat (claws and gastrolith optional).\n---\n*I've finally gotten my hands on enough polar bear meat. The grizzly variations are a bit lackluster.*\nThere are flecks of blood on the page.\"" + } + ] + } +] From f404c3f00f85ec1ce80b5d5c94f502d17057f4c6 Mon Sep 17 00:00:00 2001 From: Curtis Merrill Date: Wed, 3 Mar 2021 18:19:47 -0500 Subject: [PATCH 253/453] [Magiclysm] add lesser banishment spell, buff greater banishment (#47537) --- data/mods/Magiclysm/Spells/animist.json | 21 +++++++++++++++++++ .../Spells/attunements/Blood_Mage.json | 7 +++++-- .../mods/Magiclysm/itemgroups/spellbooks.json | 1 + data/mods/Magiclysm/items/spell_scrolls.json | 9 ++++++++ 4 files changed, 36 insertions(+), 2 deletions(-) diff --git a/data/mods/Magiclysm/Spells/animist.json b/data/mods/Magiclysm/Spells/animist.json index d778743be6535..1d864efb1aa0d 100644 --- a/data/mods/Magiclysm/Spells/animist.json +++ b/data/mods/Magiclysm/Spells/animist.json @@ -221,6 +221,27 @@ "max_range": 30, "range_increment": 1.0 }, + { + "id": "banishment_lesser", + "type": "SPELL", + "name": "Lesser Banishment", + "description": "Banish a monster to the lesser-known nether dimension. If a monster is more powerful than you can handle, the spell drains your life force to make up the difference.", + "valid_targets": [ "hostile" ], + "flags": [ "SOMATIC", "VERBAL" ], + "effect": "banishment", + "shape": "blast", + "min_damage": 40, + "damage_increment": 10, + "max_damage": 290, + "min_range": 6, + "max_range": 6, + "base_energy_cost": 600, + "spell_class": "ANIMIST", + "difficulty": 9, + "max_level": 25, + "base_casting_time": 100, + "energy_source": "MANA" + }, { "id": "summon_wisps", "type": "SPELL", diff --git a/data/mods/Magiclysm/Spells/attunements/Blood_Mage.json b/data/mods/Magiclysm/Spells/attunements/Blood_Mage.json index 778b5d1c0f1e9..e075473efd142 100644 --- a/data/mods/Magiclysm/Spells/attunements/Blood_Mage.json +++ b/data/mods/Magiclysm/Spells/attunements/Blood_Mage.json @@ -13,11 +13,14 @@ "max_damage": 640, "min_range": 6, "max_range": 6, + "min_aoe": 0, + "max_aoe": 2, + "aoe_increment": 0.04, "base_energy_cost": 400, "spell_class": "BLOOD_MAGE", - "difficulty": 9, + "difficulty": 6, "max_level": 35, - "base_casting_time": 500, + "base_casting_time": 100, "energy_source": "MANA" }, { diff --git a/data/mods/Magiclysm/itemgroups/spellbooks.json b/data/mods/Magiclysm/itemgroups/spellbooks.json index bdfc1c30fabd5..2d538d1a7aab4 100644 --- a/data/mods/Magiclysm/itemgroups/spellbooks.json +++ b/data/mods/Magiclysm/itemgroups/spellbooks.json @@ -134,6 +134,7 @@ [ "spell_scroll_druidic_healing", 20 ], [ "spell_scroll_summon_magic_motorcycle", 5 ], [ "bio_sneeze_beam", 50 ], + [ "spell_scroll_banishment_lesser", 30 ], [ "spell_scroll_nova_flare", 25 ], [ "spell_scroll_freezing_touch", 40 ] ] diff --git a/data/mods/Magiclysm/items/spell_scrolls.json b/data/mods/Magiclysm/items/spell_scrolls.json index 7698667b2b643..abbf141e0de31 100644 --- a/data/mods/Magiclysm/items/spell_scrolls.json +++ b/data/mods/Magiclysm/items/spell_scrolls.json @@ -801,6 +801,15 @@ "description": "With a shout and a gesture, the target starts bleeding from old wounds.", "use_action": { "type": "learn_spell", "spells": [ "bleed" ] } }, + { + "type": "BOOK", + "copy-from": "spell_scroll", + "id": "spell_scroll_banishment_lesser", + "//": "Animist spell", + "name": { "str": "Scroll of Lesser Banishment", "str_pl": "Scrolls of Lesser Banishment" }, + "description": "Banish a monster to the lesser-known nether dimension. If a monster is more powerful than you can handle, the spell drains your life force to make up the difference.", + "use_action": { "type": "learn_spell", "spells": [ "banishment_lesser" ] } + }, { "type": "BOOK", "copy-from": "spell_scroll", From 95da05d1d55cc244a11e8c682031003d1f304084 Mon Sep 17 00:00:00 2001 From: Ramza13 <52087122+Ramza13@users.noreply.github.com> Date: Tue, 23 Feb 2021 18:22:29 -0500 Subject: [PATCH 254/453] Unhardcode bio_heatsink and bio_climate (#47713) --- data/json/bionics.json | 4 +++- doc/JSON_FLAGS.md | 2 ++ src/character.cpp | 10 +++++----- src/map_field.cpp | 8 ++++---- 4 files changed, 14 insertions(+), 10 deletions(-) diff --git a/data/json/bionics.json b/data/json/bionics.json index c195c15de4a95..3cc9c890c775f 100644 --- a/data/json/bionics.json +++ b/data/json/bionics.json @@ -258,7 +258,8 @@ "act_cost": "100 J", "react_cost": "100 J", "time": 1, - "flags": [ "BIONIC_TOGGLED" ] + "flags": [ "BIONIC_TOGGLED" ], + "active_flags": [ "CLIMATE_CONTROL" ] }, { "id": "bio_cloak", @@ -582,6 +583,7 @@ [ "foot_r", 1 ] ], "flags": [ "BIONIC_TOGGLED", "BIONIC_NPC_USABLE" ], + "active_flags": [ "HEATSINK" ], "act_cost": "1 kJ", "react_cost": "1 kJ", "time": 1 diff --git a/doc/JSON_FLAGS.md b/doc/JSON_FLAGS.md index 7b8a9e220adee..1965590eb035d 100644 --- a/doc/JSON_FLAGS.md +++ b/doc/JSON_FLAGS.md @@ -1514,3 +1514,5 @@ Gun fault flags: - ```ALARMCLOCK``` You always can set alarms. - ```PARAIMMUNE``` You are immune to parasites. - ```IMMUNE_SPOIL``` You are immune to negative outcomes from spoiled food. +- ```CLIMATE_CONTROL``` You are resistant to extreme temperatures. +- ```HEATSINK``` You are resistant to extreme heat. \ No newline at end of file diff --git a/src/character.cpp b/src/character.cpp index 499cea2665838..5fd2b63266d39 100644 --- a/src/character.cpp +++ b/src/character.cpp @@ -276,12 +276,10 @@ static const trait_id trait_WOOLALLERGY( "WOOLALLERGY" ); static const bionic_id bio_ads( "bio_ads" ); static const bionic_id bio_blaster( "bio_blaster" ); -static const bionic_id bio_climate( "bio_climate" ); static const bionic_id bio_voice( "bio_voice" ); static const bionic_id bio_flashlight( "bio_flashlight" ); static const bionic_id bio_gills( "bio_gills" ); static const bionic_id bio_ground_sonar( "bio_ground_sonar" ); -static const bionic_id bio_heatsink( "bio_heatsink" ); static const bionic_id bio_hydraulics( "bio_hydraulics" ); static const bionic_id bio_jointservo( "bio_jointservo" ); static const bionic_id bio_laser( "bio_laser" ); @@ -387,6 +385,7 @@ static const json_character_flag json_flag_BLIND( "BLIND" ); static const json_character_flag json_flag_BULLET_IMMUNE( "BULLET_IMMUNE" ); static const json_character_flag json_flag_CLAIRVOYANCE( "CLAIRVOYANCE" ); static const json_character_flag json_flag_CLAIRVOYANCE_PLUS( "CLAIRVOYANCE_PLUS" ); +static const json_character_flag json_flag_CLIMATE_CONTROL( "CLIMATE_CONTROL" ); static const json_character_flag json_flag_COLD_IMMUNE( "COLD_IMMUNE" ); static const json_character_flag json_flag_CUT_IMMUNE( "CUT_IMMUNE" ); static const json_character_flag json_flag_DEAF( "DEAF" ); @@ -394,6 +393,7 @@ static const json_character_flag json_flag_ELECTRIC_IMMUNE( "ELECTRIC_IMMUNE" ); static const json_character_flag json_flag_ENHANCED_VISION( "ENHANCED_VISION" ); static const json_character_flag json_flag_EYE_MEMBRANE( "EYE_MEMBRANE" ); static const json_character_flag json_flag_HEATPROOF( "HEATPROOF" ); +static const json_character_flag json_flag_HEATSINK( "HEATSINK" ); static const json_character_flag json_flag_IMMUNE_HEARING_DAMAGE( "IMMUNE_HEARING_DAMAGE" ); static const json_character_flag json_flag_INFRARED( "INFRARED" ); static const json_character_flag json_flag_NIGHT_VISION( "NIGHT_VISION" ); @@ -4552,7 +4552,7 @@ bool Character::in_climate_control() { bool regulated_area = false; // Check - if( has_active_bionic( bio_climate ) ) { + if( has_flag( json_flag_CLIMATE_CONTROL ) ) { return true; } map &here = get_map(); @@ -6434,7 +6434,7 @@ void Character::update_bodytemp() const bool has_sleep = has_effect( effect_sleep ); const bool has_sleep_state = has_sleep || in_sleep_state(); const bool heat_immune = has_flag( json_flag_HEATPROOF ); - const bool has_heatsink = has_bionic( bio_heatsink ) || is_wearing( itype_rm13_armor_on ) || + const bool has_heatsink = has_flag( json_flag_HEATSINK ) || is_wearing( itype_rm13_armor_on ) || heat_immune; const bool has_common_cold = has_effect( effect_common_cold ); const bool has_climate_control = in_climate_control(); @@ -7452,7 +7452,7 @@ bool Character::is_immune_field( const field_type_id &fid ) const return is_elec_immune(); } if( ft.has_fire ) { - return has_active_bionic( bio_heatsink ) || is_wearing( itype_rm13_armor_on ); + return has_flag( json_flag_HEATSINK ) || is_wearing( itype_rm13_armor_on ); } if( ft.has_acid ) { return !is_on_ground() && get_env_resist( body_part_foot_l ) >= 15 && diff --git a/src/map_field.cpp b/src/map_field.cpp index ae320217bbc59..dfa2eacfc8623 100644 --- a/src/map_field.cpp +++ b/src/map_field.cpp @@ -72,8 +72,6 @@ static const itype_id itype_rock( "rock" ); static const species_id species_FUNGUS( "FUNGUS" ); -static const bionic_id bio_heatsink( "bio_heatsink" ); - static const efftype_id effect_badpoison( "badpoison" ); static const efftype_id effect_blind( "blind" ); static const efftype_id effect_corroding( "corroding" ); @@ -93,6 +91,8 @@ static const trait_id trait_M_SKIN3( "M_SKIN3" ); static const trait_id trait_THRESH_MARLOSS( "THRESH_MARLOSS" ); static const trait_id trait_THRESH_MYCUS( "THRESH_MYCUS" ); +static const json_character_flag json_flag_HEATSINK( "HEATSINK" ); + using namespace map_field_processing; void map::create_burnproducts( const tripoint &p, const item &fuel, const units::mass &burned_mass ) @@ -1472,7 +1472,7 @@ void map::player_in_field( player &u ) } if( ft == fd_fire ) { // Heatsink or suit prevents ALL fire damage. - if( !u.has_active_bionic( bio_heatsink ) && !u.is_wearing( itype_rm13_armor_on ) ) { + if( !u.has_flag( json_flag_HEATSINK ) && !u.is_wearing( itype_rm13_armor_on ) ) { // To modify power of a field based on... whatever is relevant for the effect. int adjusted_intensity = cur.get_field_intensity(); @@ -1587,7 +1587,7 @@ void map::player_in_field( player &u ) if( !inside ) { // Fireballs can't touch you inside a car. // Heatsink or suit stops fire. - if( !u.has_active_bionic( bio_heatsink ) && + if( !u.has_flag( json_flag_HEATSINK ) && !u.is_wearing( itype_rm13_armor_on ) ) { u.add_msg_player_or_npc( m_bad, _( "You're torched by flames!" ), _( " is torched by flames!" ) ); From 67ed6fa8ff55ae30fec6195ca9aa98087642f0c3 Mon Sep 17 00:00:00 2001 From: Maleclypse <54345792+Maleclypse@users.noreply.github.com> Date: Thu, 4 Mar 2021 00:44:54 -0600 Subject: [PATCH 255/453] Hunting lodge Location (#44378) --- data/json/itemgroups/SUS/lodge.json | 80 ++++++ data/json/mapgen/hunting_lodge.json | 180 ++++++++++++++ data/json/mapgen/nested/lodge_nested.json | 228 +++++++++++++++++ data/json/mapgen_palettes/lodge_palette.json | 235 ++++++++++++++++++ .../overmap/overmap_special/specials.json | 18 ++ .../overmap_terrain/overmap_terrain.json | 28 +++ data/json/scenarios.json | 3 + data/json/start_locations.json | 6 + 8 files changed, 778 insertions(+) create mode 100644 data/json/itemgroups/SUS/lodge.json create mode 100644 data/json/mapgen/hunting_lodge.json create mode 100644 data/json/mapgen/nested/lodge_nested.json create mode 100644 data/json/mapgen_palettes/lodge_palette.json diff --git a/data/json/itemgroups/SUS/lodge.json b/data/json/itemgroups/SUS/lodge.json new file mode 100644 index 0000000000000..d3e03875adf68 --- /dev/null +++ b/data/json/itemgroups/SUS/lodge.json @@ -0,0 +1,80 @@ +[ + { + "id": "SUS_hunting_archery", + "type": "item_group", + "//": "items found in an archery space", + "subtype": "collection", + "entries": [ + { "item": "compbow", "prob": 50 }, + { "item": "compbow_high", "prob": 20 }, + { "item": "compbow_low", "prob": 40 }, + { "item": "recurbow", "prob": 30 }, + { "item": "reflexrecurvebow", "prob": 10 } + ] + }, + { + "id": "SUS_hunting_rifle", + "type": "item_group", + "//": "items found in a rifle hunting space", + "subtype": "collection", + "entries": [ + { "item": "ar15", "prob": 150, "charges-min": 0, "charges-max": 30 }, + { "item": "marlin_9a", "prob": 20, "charges-min": 0, "charges-max": 19 }, + { "item": "remington700_270", "prob": 10, "charges-min": 0, "charges-max": 4 }, + { "item": "remington_700", "prob": 40, "charges-min": 0, "charges-max": 4 }, + { "item": "ruger_1022", "prob": 70, "charges-min": 0, "charges-max": 10 }, + { "item": "ruger_mini", "prob": 10, "charges-min": 0, "charges-max": 5 }, + { "item": "win70", "prob": 20, "charges-min": 0, "charges-max": 3 }, + { "item": "colt_lightning", "prob": 2, "charges-min": 0, "charges-max": 10 }, + { "item": "henry_big_boy", "prob": 2, "charges-min": 0, "charges-max": 10 }, + { "item": "weatherby_5", "prob": 2, "charges-min": 0, "charges-max": 3 } + ] + }, + { + "id": "hunting_lodge_weapons", + "type": "item_group", + "//": "items found in a shotgun hunting space", + "subtype": "distribution", + "entries": [ + { "group": "guns_shotgun_common", "prob": 30 }, + { "group": "SUS_hunting_rifle", "prob": 20 }, + { "group": "SUS_hunting_archery", "prob": 15 } + ] + }, + { + "id": "cannibal_weapons", + "type": "item_group", + "//": "items found in a most dangerous game space", + "subtype": "distribution", + "entries": [ + { "group": "guns_shotgun_common", "prob": 30 }, + { "group": "SUS_hunting_rifle", "prob": 20 }, + { "group": "guns_smg_rare", "prob": 15 } + ] + }, + { + "id": "lodge_archery_ammo", + "type": "item_group", + "//": "archery ammo", + "subtype": "collection", + "entries": [ + { "item": "arrow_metal", "prob": 20 }, + { "item": "arrow_metal_bodkin", "prob": 20 }, + { "item": "arrow_metal_target", "prob": 30 }, + { "item": "arrow_cf", "prob": 10 } + ] + }, + { + "id": "cannibal_food", + "type": "item_group", + "subtype": "collection", + "entries": [ + { "item": "machete", "prob": 20 }, + { "group": "preserved_food", "custom-flags": [ "CANNIBALISM" ], "prob": 30 }, + { "group": "preserved_food", "prob": 20 }, + { "group": "dry_goods", "prob": 30 }, + { "group": "dry_goods", "custom-flags": [ "CANNIBALISM" ], "prob": 60 }, + { "group": "pantry", "prob": 10 } + ] + } +] diff --git a/data/json/mapgen/hunting_lodge.json b/data/json/mapgen/hunting_lodge.json new file mode 100644 index 0000000000000..c675c04bebdcd --- /dev/null +++ b/data/json/mapgen/hunting_lodge.json @@ -0,0 +1,180 @@ +[ + { + "type": "mapgen", + "method": "json", + "om_terrain": [ [ "lodge_ground1", "lodge_ground2" ] ], + "weight": 100, + "object": { + "fill_ter": "t_floor", + "rows": [ + ".%##W###W###W###W###+##W#################%......", + ".*#c B#c B#B c#B c# #h s# >#*......", + ".*Wd B#d B#B d#B d# #h T# W*......", + ".*##=###=###=###=## ##=## #*......", + ".*# #*......", + ".*W W*......", + ".*# YY YY AAAAAAAA a OOO >#*......", + ".%########+######################## ###%......", + ".*********G~~~~~~~~~~~~~~~~~~~~~~%# #***......", + "~~~~~~~~~~G~~~~~~~~~~~*############ #*........", + "oooooooooooooooo~~~~~~*w #%........", + "oooooooooooooooo~~~~~~*#Y w*........", + "ooooooooooooooooGGGGGGG+ ttttt bw*........", + "ooooooooooooooooGGGGGGG+ ttttt bw*........", + "oooooooooooooooo~~~~~G*#Y w*........", + "oooooooooooooooo~~~~~G*w w*........", + "~~~~~~~~~~~~~~~~~~~~~G*##### ########*........", + "~~~~~~~~~~~~~~~~~~~~~G***#<# #********........", + "~~~~~~~~~~~~~~~~%~~~~GGGG+ # #%****...........", + "......*###-###-###-######### #####*...........", + ".....0*#UU URU URU URU #12C 5 F#*...........", + ".....0*#R z C uW*...........", + ".....0*#UU URU URU URU #3CC& 4CVuF#*...........", + "......%###-###-###-##########+######%..........." + ], + "palettes": [ "lodge_palette" ], + "place_monsters": [ { "monster": "GROUP_ZOMBIE", "x": 29, "y": 4 } ], + "place_nested": [ + { + "chunks": [ [ "lodge_pantry_15x15", 80 ], [ "lodge_cannibal_15x15", 20 ], [ "lodge_hunting_15x15", 50 ] ], + "x": 8, + "y": 9 + } + ] + } + }, + { + "type": "mapgen", + "method": "json", + "om_terrain": [ [ "lodge_2ndfloor1", "lodge_2ndfloor2" ] ], + "weight": 100, + "object": { + "fill_ter": "t_floor", + "rows": [ + " ##W###W###W###W###w##W################# ", + " # <# ", + " W W ", + " # # ", + " # # ", + " W W ", + " # <# ", + " ########w#######wwww#############www### ", + " ", + " ", + " ", + " ", + " ", + " ", + " ", + " ", + " ", + " ", + " ", + " ", + " ", + " ", + " ", + " " + ], + "palettes": [ "lodge_2ndfloor_palette" ] + } + }, + { + "type": "mapgen", + "method": "json", + "om_terrain": [ [ "lodge_basement_residential1", "lodge_basement_residential2" ] ], + "weight": 100, + "object": { + "fill_ter": "t_rock", + "rows": [ + " %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% ", + " % % ", + " % % ", + " % % ", + " % % ", + " % % ", + " % % ", + " %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% %%% ", + " % % ", + " %%%%%%%%%%%%%% % ", + " % BB% ", + " % % ", + " % % ", + " % % ", + " % % ", + " % % ", + " %%%%% %%%%%%%% ", + " %<| % ", + " % + % ", + " %%%%%%% ", + " ", + " ", + " ", + " " + ], + "palettes": [ "basement_residential" ], + "place_monsters": [ { "monster": "GROUP_ZOMBIE", "x": 7, "y": 4 } ], + "place_nested": [ + { "chunks": [ [ "lodge_game_6x6", 80 ], [ "lodge_dungeon_6x6", 20 ], [ "lodge_drug_6x6", 50 ] ], "x": 2, "y": 1 }, + { "chunks": [ [ "5x5_sauna_W", 30 ], [ "5x5_pool", 10 ], [ "5x5_gym_W", 60 ] ], "x": 24, "y": 1 }, + { + "chunks": [ [ "room_6x6_woodworker", 5 ], [ "room_6x6_bike", 15 ], [ "room_6x6_office_E", 5 ] ], + "x": 24, + "y": 10 + } + ] + } + }, + { + "type": "mapgen", + "method": "json", + "om_terrain": [ "lodge_basement_laboratory_entrance" ], + "//": "doesn't work rebuild later", + "object": { + "fill_ter": "t_rock", + "rotation": [ 0, 3 ], + "rows": [ + "##--------------------##", + "##| |>>| |##", + "##| |MM| |##", + "##| |..| |##", + "##| |..| |##", + "##| |..| |##", + "##| |..| |##", + "##| |..| |##", + "##|---+---|..|---+---|##", + "##|.......M..M.......|##", + "##|.......M..M.......|##", + "|----+----|..|----+----|", + "|.........|..|d.......d|", + "|.ccccccc.|..|xh..h..hx|", + "|.........|7.|d..dxd..d|", + "|---------|..|---------|", + "########--|LL6--########", + "########=,,,,,,=########", + "########=,,,,,,=########", + "########=,,,,,,=########", + "########===WW===########", + "##########=,,=##########", + "##########=<<=##########", + "##########====##########" + ], + "palettes": [ "lab_palette" ], + "terrain": { + "=": "t_wall", + ",": "t_rock_floor", + "6": "t_card_science", + "7": "t_rock_floor", + "<": "t_stairs_up", + ">": "t_stairs_down" + }, + "furniture": { "C": "f_centrifuge" }, + "mapping": { "c": { "items": { "item": "chem_lab", "chance": 30 } }, "d": { "items": { "item": "office", "chance": 30 } } }, + "monster": { "7": { "monster": "mon_turret_rifle" } }, + "place_nested": [ + { "chunks": [ "lab_spawn_7x7_crossdoors" ], "x": 3, "y": 1 }, + { "chunks": [ "lab_spawn_7x7_crossdoors" ], "x": 14, "y": 1 } + ] + } + } +] diff --git a/data/json/mapgen/nested/lodge_nested.json b/data/json/mapgen/nested/lodge_nested.json new file mode 100644 index 0000000000000..7f89e90c344b3 --- /dev/null +++ b/data/json/mapgen/nested/lodge_nested.json @@ -0,0 +1,228 @@ +[ + { + "type": "mapgen", + "method": "json", + "nested_mapgen_id": "lodge_cannibal_15x15", + "object": { + "mapgensize": [ 15, 15 ], + "rows": [ + " ", + " ", + " ", + " ", + " ", + " ", + " ", + " ", + " ", + " ", + " ", + "DF ARF LRL ORa ", + "R ", + "SF DRA LRa ORO ", + "DF ARF LRL LRa ", + "R ", + "SF DRA LRa LRL ", + " " + ], + "palettes": [ "lodge_items" ] + } + }, + { + "type": "mapgen", + "method": "json", + "nested_mapgen_id": "lodge_hunting_15x15", + "object": { + "mapgensize": [ 15, 15 ], + "rows": [ + " ", + " ", + " ", + " ", + " ", + " ", + " ", + " ", + " ", + " ", + " ", + "DF ARF BRB BRa ", + "R ", + "SF DRA BRa BRB ", + " " + ], + "palettes": [ "lodge_items" ] + } + }, + { + "type": "mapgen", + "method": "json", + "nested_mapgen_id": "lodge_pantry_15x15", + "object": { + "mapgensize": [ 15, 15 ], + "rows": [ + " ", + " ", + " ", + " ", + " ", + " ", + " ", + " ", + " ", + " ", + " ", + "SS SRa SRS SRS ", + "R ", + "SS SRA BRB SRS ", + " " + ], + "palettes": [ "lodge_items" ] + } + }, + { + "type": "mapgen", + "method": "json", + "nested_mapgen_id": "lodge_game_6x6", + "object": { + "mapgensize": [ 6, 6 ], + "rows": [ + "E CC T", + " ", + " BB ", + " BB ", + " BB ", + "E T" + ], + "terrain": { + ".": "t_floor", + "B": "t_floor", + "C": "t_floor", + "y": "t_floor", + "T": "t_floor", + "E": "t_floor", + " ": "t_carpet_red", + "h": "t_carpet_red", + "A": "t_carpet_red", + "d": "t_carpet_red", + "f": "t_carpet_red", + "O": "t_carpet_red", + "=": "t_carpet_red" + }, + "furniture": { "A": "f_stool", "B": "f_table", "E": "f_armchair", "C": "f_bookcase", "T": "f_floor_lamp" }, + "items": { "C": [ { "item": "games", "chance": 80, "repeat": [ 3, 6 ] } ] } + } + }, + { + "type": "mapgen", + "method": "json", + "nested_mapgen_id": "lodge_dungeon_6x6", + "object": { + "mapgensize": [ 6, 6 ], + "rows": [ + " tc td", + " t t ", + " tttt ", + " ", + " h ", + "C T" + ], + "terrain": { + ".": "t_floor", + "B": "t_floor", + "C": "t_floor", + "c": "t_floor", + "y": "t_floor", + "T": "t_floor", + "t": "t_reb_cage", + "E": "t_floor", + " ": "t_carpet_red", + "h": "t_carpet_red", + "A": "t_carpet_red", + "d": "t_carpet_red", + "f": "t_carpet_red", + "O": "t_carpet_red", + "=": "t_carpet_red" + }, + "furniture": { + "A": "f_stool", + "B": "f_workbench", + "E": "f_armchair", + "C": "f_rack_wood", + "T": "f_floor_lamp", + "d": "f_mannequin", + "b": "f_bench", + "f": "f_table", + "h": "f_butcher_rack", + "y": [ "f_indoor_plant_y", "f_indoor_plant" ] + }, + "items": { + "C": [ + { "item": "SUS_tailoring_materials", "chance": 80, "repeat": [ 3, 6 ] }, + { "item": "leather_shop_repair", "chance": 40, "repeat": [ 2, 4 ] }, + { "item": "bullwhip", "chance": 100 } + ], + "c": [ + { "item": "bone", "chance": 80, "repeat": [ 4, 8 ] }, + { "item": "pants", "chance": 100 }, + { "item": "shirts", "chance": 100 }, + { "item": "leather_shop_accessories", "chance": 10 } + ] + } + } + }, + { + "type": "mapgen", + "method": "json", + "nested_mapgen_id": "lodge_drug_6x6", + "object": { + "mapgensize": [ 6, 6 ], + "rows": [ + "E CC T", + " ", + " BB ", + " BB ", + " BB ", + "E T" + ], + "terrain": { + ".": "t_floor", + "B": "t_floor", + "C": "t_floor", + "y": "t_floor", + "T": "t_floor", + "E": "t_floor", + " ": "t_carpet_red", + "h": "t_carpet_red", + "A": "t_carpet_red", + "d": "t_carpet_red", + "f": "t_carpet_red", + "O": "t_carpet_red", + "=": "t_carpet_red" + }, + "furniture": { + "A": "f_stool", + "B": "f_workbench", + "E": "f_armchair", + "C": "f_rack_wood", + "T": "f_floor_lamp", + "d": "f_mannequin", + "b": "f_bench", + "f": "f_table", + "h": "f_chair", + "y": [ "f_indoor_plant_y", "f_indoor_plant" ] + }, + "items": { + "C": [ + { "item": "straw_doll", "chance": 80, "repeat": [ 6, 14 ] }, + { "item": "bag_body_bag", "chance": 40, "repeat": [ 2, 4 ] } + ], + "B": [ + { "item": "coke", "chance": 60, "repeat": [ 13, 126 ] }, + { "item": "funnel", "chance": 60, "repeat": [ 0, 1 ] }, + { "item": "plastic_bag", "chance": 90, "repeat": [ 20, 60 ] } + ] + } + } + } +] diff --git a/data/json/mapgen_palettes/lodge_palette.json b/data/json/mapgen_palettes/lodge_palette.json new file mode 100644 index 0000000000000..dd7b0b86e68a3 --- /dev/null +++ b/data/json/mapgen_palettes/lodge_palette.json @@ -0,0 +1,235 @@ +[ + { + "type": "palette", + "id": "lodge_palette", + "terrain": { + "#": "t_rock_wall", + "+": [ [ "t_door_c", 3 ], "t_door_locked" ], + "=": "t_door_c", + "z": "t_door_metal_locked", + ".": [ [ "t_region_groundcover", 4 ], "t_region_groundcover_forest" ], + "~": [ [ "t_region_groundcover_barren", 3 ], "t_region_groundcover" ], + "*": [ [ "t_region_groundcover", 15 ], "t_region_shrub" ], + "G": "t_sidewalk", + "o": "t_pavement", + "P": "t_water_pump", + "R": "t_floor", + "r": "t_floor", + "S": "t_floor", + "-": "t_window_bars_curtains", + "w": "t_double_pane_glass_with_curtain_open_window_closed", + "W": [ [ "t_double_pane_glass_with_curtain", 2 ], "t_double_pane_glass_with_curtain_open_window_closed" ], + "%": "t_gutter_downspout", + "q": "t_swater_sh", + "Q": "t_water_dp", + "H": "t_chickenwire_gate_c", + "I": "t_chickenwire_fence", + "<": "t_wood_stairs_down", + ">": "t_wood_stairs_up" + }, + "furniture": { + "a": "f_armchair", + "A": "f_bookcase", + "b": "f_bench", + "B": "f_bed", + "C": "f_counter", + "c": "f_chair", + "d": "f_desk", + "D": "f_dresser", + "F": "f_fridge", + "h": "f_bathtub", + "l": "f_stool", + "L": "f_locker", + "O": "f_sofa", + "R": [ "f_rack", "f_utility_shelf" ], + "S": "f_woodstove", + "s": "f_sink", + "t": "f_table", + "T": "f_toilet", + "U": "f_utility_shelf", + "V": "f_oven", + "u": "f_cupboard", + "Y": "f_rack_coat", + "Z": "f_fireplace", + "y": [ "f_indoor_plant_y", "f_indoor_plant" ], + "1": "f_cupboard", + "2": "f_cupboard", + "3": "f_cupboard", + "4": "f_cupboard", + "5": "f_sink", + "&": "f_trashcan", + "0": "f_standing_tank" + }, + "liquids": { "0": { "liquid": "water_clean", "amount": [ 10, 900 ] } }, + "items": { + "a": { "item": "livingroom", "chance": 20 }, + "A": [ + { "item": "homebooks", "chance": 60, "repeat": [ 1, 3 ] }, + { "item": "magazines", "chance": 60, "repeat": [ 1, 8 ] }, + { "item": "manuals", "chance": 30 } + ], + "B": { "item": "bed", "chance": 60 }, + "d": [ { "item": "livingroom", "chance": 40 }, { "item": "office", "chance": 40 } ], + "D": [ + { "item": "SUS_dresser_mens", "chance": 50, "repeat": [ 1, 4 ] }, + { "item": "SUS_dresser_womens", "chance": 50, "repeat": [ 1, 4 ] } + ], + "F": { "item": "SUS_fridge", "chance": 35 }, + "h": { "item": "shower", "chance": 20 }, + "L": [ + { "item": "tools_earthworking", "chance": 30, "repeat": [ 1, 4 ] }, + { "item": "tools_home", "chance": 30, "repeat": [ 1, 4 ] } + ], + "O": { "item": "livingroom", "chance": 20 }, + "S": { "item": "stash_wood", "chance": 60, "repeat": [ 2, 4 ] }, + "&": { "item": "trash", "chance": 20 }, + "R": [ + { "item": "camping", "chance": 50 }, + { "item": "gear_survival", "chance": 30 }, + { "item": "cannedfood", "chance": 50 }, + { "item": "stash_food", "chance": 50 } + ], + "s": { "item": "SUS_bathroom_sink", "chance": 60 }, + "t": { "item": "dining", "chance": 30, "repeat": [ 1, 2 ] }, + "U": { "item": "camping", "chance": 30, "repeat": [ 1, 4 ] }, + "u": { "item": "SUS_pantry", "chance": 50 }, + "V": { "item": "SUS_oven", "chance": 70 }, + "Y": { "item": "coat_rack", "chance": 35, "repeat": [ 1, 4 ] }, + "1": [ { "item": "SUS_dishes", "chance": 35 }, { "item": "SUS_silverware", "chance": 35 } ], + "2": { "item": "SUS_cookware", "chance": 35 }, + "3": [ { "item": "SUS_utensils", "chance": 35 }, { "item": "SUS_knife_drawer", "chance": 35 } ], + "4": [ { "item": "SUS_junk_drawer", "chance": 35 }, { "item": "SUS_spice_collection", "chance": 35 } ], + "5": { "item": "SUS_kitchen_sink", "chance": 35 } + }, + "toilets": { "T": { } } + }, + { + "type": "palette", + "id": "lodge_2ndfloor_palette", + "terrain": { + "#": "t_rock_wall", + "+": [ [ "t_door_c", 3 ], "t_door_locked" ], + "=": "t_door_c", + " ": "t_open_air", + ".": "t_gutter_north", + "~": "t_gutter_south", + "*": "t_gutter_east", + "R": "t_floor", + "p": "t_floor", + "r": "t_rock_floor", + "S": "t_rock_floor", + "-": "t_window_bars_curtains", + "w": "t_double_pane_glass_with_curtain_open_window_closed", + "W": [ [ "t_double_pane_glass_with_curtain", 2 ], "t_double_pane_glass_with_curtain_open_window_closed" ], + "%": "t_gutter_downspout", + "q": "t_swater_sh", + "Q": "t_water_dp", + "H": "t_chickenwire_gate_c", + "I": "t_chickenwire_fence", + "<": "t_wood_stairs_down", + ">": "t_wood_stairs_up" + }, + "furniture": { + "a": "f_armchair", + "A": "f_bookcase", + "b": "f_bench", + "B": "f_bed", + "C": "f_counter", + "c": "f_chair", + "d": "f_desk", + "D": "f_dresser", + "F": "f_fridge", + "h": "f_bathtub", + "l": "f_stool", + "L": "f_locker", + "O": "f_sofa", + "p": "f_pool_table", + "R": [ "f_rack", "f_utility_shelf" ], + "S": "f_woodstove", + "s": "f_sink", + "t": "f_table", + "T": "f_toilet", + "Y": "f_rack_coat", + "Z": "f_fireplace", + "y": [ "f_indoor_plant_y", "f_indoor_plant" ], + "5": "f_sink", + "&": "f_trashcan" + }, + "liquids": { "0": { "liquid": "water_clean", "amount": [ 10, 900 ] } }, + "items": { + "a": { "item": "livingroom", "chance": 20 }, + "A": [ + { "item": "homebooks", "chance": 60, "repeat": [ 1, 3 ] }, + { "item": "magazines", "chance": 60, "repeat": [ 1, 8 ] }, + { "item": "manuals", "chance": 30 } + ], + "B": { "item": "bed", "chance": 60 }, + "d": [ { "item": "livingroom", "chance": 40 }, { "item": "office", "chance": 40 } ], + "D": [ + { "item": "SUS_dresser_mens", "chance": 50, "repeat": [ 1, 4 ] }, + { "item": "SUS_dresser_womens", "chance": 50, "repeat": [ 1, 4 ] } + ], + "F": { "item": "SUS_fridge", "chance": 35 }, + "h": { "item": "shower", "chance": 20 }, + "L": [ + { "item": "tools_earthworking", "chance": 30, "repeat": [ 1, 4 ] }, + { "item": "tools_home", "chance": 30, "repeat": [ 1, 4 ] } + ], + "O": { "item": "livingroom", "chance": 20 }, + "S": { "item": "stash_wood", "chance": 60, "repeat": [ 2, 4 ] }, + "&": { "item": "trash", "chance": 20 }, + "R": [ + { "item": "camping", "chance": 50 }, + { "item": "gear_survival", "chance": 30 }, + { "item": "cannedfood", "chance": 50 }, + { "item": "stash_food", "chance": 50 } + ], + "s": { "item": "SUS_bathroom_sink", "chance": 60 }, + "t": { "item": "dining", "chance": 30, "repeat": [ 1, 2 ] }, + "U": { "item": "camping", "chance": 30, "repeat": [ 1, 4 ] }, + "u": { "item": "SUS_pantry", "chance": 50 }, + "V": { "item": "SUS_oven", "chance": 70 }, + "Y": { "item": "coat_rack", "chance": 35, "repeat": [ 1, 4 ] }, + "1": [ { "item": "SUS_dishes", "chance": 35 }, { "item": "SUS_silverware", "chance": 35 } ], + "2": { "item": "SUS_cookware", "chance": 35 }, + "3": [ { "item": "SUS_utensils", "chance": 35 }, { "item": "SUS_knife_drawer", "chance": 35 } ], + "4": [ { "item": "SUS_junk_drawer", "chance": 35 }, { "item": "SUS_spice_collection", "chance": 35 } ], + "5": { "item": "SUS_kitchen_sink", "chance": 35 } + }, + "toilets": { "T": { } } + }, + { + "type": "palette", + "id": "lodge_items", + "terrain": { + "a": "t_floor", + "A": "t_floor", + "B": "t_floor", + "D": "t_floor", + "F": "t_floor", + "h": "t_floor", + "L": "t_floor", + "O": "t_floor", + "S": "t_floor", + "&": "t_floor", + "R": "t_floor" + }, + "items": { + "a": { "item": "clothing_hunting", "chance": 20, "repeat": [ 1, 6 ] }, + "A": { "item": "tools_hunting", "chance": 60, "repeat": [ 1, 8 ] }, + "B": { "item": "tools_hunting", "chance": 60 }, + "D": { "item": "hunting_lodge_weapons" }, + "F": { "item": "lodge_archery_ammo", "chance": 30, "repeat": [ 1, 4 ] }, + "h": { "item": "cannibal_weapons", "repeat": [ 1, 4 ] }, + "L": { "item": "cannibal_food", "repeat": [ 1, 4 ] }, + "S": { "item": "stash_wood", "chance": 60, "repeat": [ 2, 4 ] }, + "&": { "item": "trash", "chance": 20 }, + "R": [ + { "item": "camping", "chance": 50 }, + { "item": "gear_survival", "chance": 30 }, + { "item": "cannedfood", "chance": 50, "repeat": [ 3, 8 ] }, + { "item": "stash_food", "chance": 50, "repeat": [ 3, 8 ] } + ] + } + } +] diff --git a/data/json/overmap/overmap_special/specials.json b/data/json/overmap/overmap_special/specials.json index a967b44cbfa00..a224570fb4db6 100644 --- a/data/json/overmap/overmap_special/specials.json +++ b/data/json/overmap/overmap_special/specials.json @@ -249,6 +249,24 @@ "occurrences": [ 0, 2 ], "flags": [ "CLASSIC", "WILDERNESS" ] }, + { + "type": "overmap_special", + "id": "Hunting Lodge", + "overmaps": [ + { "point": [ 0, 0, 0 ], "overmap": "lodge_ground1_north" }, + { "point": [ 1, 0, 0 ], "overmap": "lodge_ground2_north" }, + { "point": [ 0, 0, 1 ], "overmap": "lodge_2ndfloor1_north" }, + { "point": [ 1, 0, 1 ], "overmap": "lodge_2ndfloor2_north" }, + { "point": [ 0, 0, -1 ], "overmap": "lodge_basement_residential1_north" }, + { "point": [ 1, 0, -1 ], "overmap": "lodge_basement_residential2_north" } + ], + "connections": [ { "point": [ 0, -1, 0 ], "terrain": "road", "existing": true } ], + "locations": [ "land", "swamp" ], + "city_distance": [ 15, -1 ], + "city_sizes": [ 1, 8 ], + "occurrences": [ 0, 2 ], + "flags": [ "CLASSIC", "WILDERNESS" ] + }, { "type": "overmap_special", "id": "Gas Station", diff --git a/data/json/overmap/overmap_terrain/overmap_terrain.json b/data/json/overmap/overmap_terrain/overmap_terrain.json index 8fc28084fd9c0..171b70dada0cf 100644 --- a/data/json/overmap/overmap_terrain/overmap_terrain.json +++ b/data/json/overmap/overmap_terrain/overmap_terrain.json @@ -219,6 +219,34 @@ "see_cost": 5, "extras": "build" }, + { + "type": "overmap_terrain", + "id": [ "lodge_ground1", "lodge_ground2" ], + "name": "hunting lodge", + "sym": "L", + "copy-from": "generic_forest", + "color": "light_green", + "see_cost": 4, + "extend": { "flags": [ "SOURCE_GUN", "SOURCE_AMMO" ] } + }, + { + "type": "overmap_terrain", + "id": [ "lodge_2ndfloor1", "lodge_2ndfloor2" ], + "name": "second floor hunting lodge", + "copy-from": "generic_forest", + "sym": "L", + "see_cost": 4, + "color": "light_green" + }, + { + "type": "overmap_terrain", + "id": [ "lodge_basement_residential1", "lodge_basement_residential2", "lodge_basement_laboratory_entrance" ], + "name": "hunting lodge basement", + "copy-from": "generic_forest", + "sym": "L", + "see_cost": 4, + "color": "light_green" + }, { "type": "overmap_terrain", "id": "dirtroad1_aban1", diff --git a/data/json/scenarios.json b/data/json/scenarios.json index f7a7522da5496..634bcf79b105f 100644 --- a/data/json/scenarios.json +++ b/data/json/scenarios.json @@ -95,6 +95,7 @@ "sloc_horse_ranch", "sloc_lighthouse_ground", "sloc_cabin_lake", + "sloc_lodge_ground", "sloc_freshwater_research_station" ], "start_name": "Safe Building", @@ -296,6 +297,7 @@ "sloc_hermit_shack", "sloc_farm_survivalist", "sloc_campsite", + "sloc_lodge_ground", "sloc_campground" ], "start_name": "Outside Town", @@ -314,6 +316,7 @@ "sloc_field", "sloc_forest", "sloc_cabin", + "sloc_lodge_ground", "sloc_hermit_shack", "sloc_farm_survivalist", "sloc_campsite", diff --git a/data/json/start_locations.json b/data/json/start_locations.json index 99848e24e71e2..7041747c9d520 100644 --- a/data/json/start_locations.json +++ b/data/json/start_locations.json @@ -457,6 +457,12 @@ "name": "Freshwater Research Station", "terrain": [ "sealab_small_surface" ] }, + { + "type": "start_location", + "id": "sloc_lodge_ground", + "name": "Hunting Lodge", + "terrain": [ "lodge_ground" ] + }, { "type": "start_location", "id": "sloc_gas_station", From 1fd4af5b88bc91e54330174fec0ce792e53f323c Mon Sep 17 00:00:00 2001 From: LyleSY Date: Thu, 4 Mar 2021 01:57:22 -0500 Subject: [PATCH 256/453] fungal evolution (#47247) --- data/json/monstergroups/fungi.json | 12 +++++++---- data/json/monsters/fungus.json | 33 ++++++++++++++++++++++++++++++ 2 files changed, 41 insertions(+), 4 deletions(-) diff --git a/data/json/monstergroups/fungi.json b/data/json/monstergroups/fungi.json index a506431db6685..baac22efbea7c 100644 --- a/data/json/monstergroups/fungi.json +++ b/data/json/monstergroups/fungi.json @@ -4,8 +4,9 @@ "name": "GROUP_FUNGI", "default": "mon_spore", "monsters": [ - { "monster": "mon_fungaloid", "freq": 300, "cost_multiplier": 0 }, - { "monster": "mon_fungaloid_young", "freq": 100, "cost_multiplier": 0 }, + { "monster": "mon_fungaloid", "freq": 400, "cost_multiplier": 0 }, + { "monster": "mon_fungaloid_shambler", "freq": 200, "cost_multiplier": 0 }, + { "monster": "mon_fungaloid_young", "freq": 200, "cost_multiplier": 0 }, { "monster": "mon_zombie_fungus", "freq": 0, "cost_multiplier": 0 }, { "monster": "mon_boomer_fungus", "freq": 0, "cost_multiplier": 0 }, { "monster": "mon_zombie_child_fungus", "freq": 0, "cost_multiplier": 0 }, @@ -18,8 +19,9 @@ "name": "GROUP_FUNGI_FUNGALOID", "default": "mon_fungaloid", "monsters": [ - { "monster": "mon_fungaloid", "freq": 300, "cost_multiplier": 0 }, - { "monster": "mon_fungaloid_young", "freq": 100, "cost_multiplier": 0, "pack_size": [ 2, 3 ] } + { "monster": "mon_fungaloid", "freq": 500, "cost_multiplier": 0 }, + { "monster": "mon_fungaloid_shambler", "freq": 250, "cost_multiplier": 0 }, + { "monster": "mon_fungaloid_young", "freq": 250, "cost_multiplier": 0, "pack_size": [ 2, 3 ] } ] }, { @@ -28,6 +30,7 @@ "default": "mon_fungal_tendril", "monsters": [ { "monster": "mon_fungaloid", "freq": 10, "cost_multiplier": 0 }, + { "monster": "mon_fungaloid_shambler", "freq": 30, "cost_multiplier": 0 }, { "monster": "mon_fungaloid_young", "freq": 30, "cost_multiplier": 0 }, { "monster": "mon_zombie_fungus", "freq": 75, "cost_multiplier": 0 }, { "monster": "mon_boomer_fungus", "freq": 50, "cost_multiplier": 0 }, @@ -42,6 +45,7 @@ "default": "mon_fungal_blossom", "monsters": [ { "monster": "mon_fungaloid", "freq": 20, "cost_multiplier": 0 }, + { "monster": "mon_fungaloid_shambler", "freq": 50, "cost_multiplier": 0 }, { "monster": "mon_fungaloid_young", "freq": 50, "cost_multiplier": 0 }, { "monster": "mon_zombie_fungus", "freq": 100, "cost_multiplier": 0 }, { "monster": "mon_boomer_fungus", "freq": 50, "cost_multiplier": 0 }, diff --git a/data/json/monsters/fungus.json b/data/json/monsters/fungus.json index d8efb3e515a99..c38ae3e704fcb 100644 --- a/data/json/monsters/fungus.json +++ b/data/json/monsters/fungus.json @@ -172,8 +172,41 @@ "harvest": "fungaloid", "special_attacks": [ [ "FUNGUS", 30 ] ], "death_function": [ "FUNGUS", "NORMAL" ], + "upgrades": { "half_life": 14, "into": "mon_fungaloid_shambler" }, "flags": [ "STUMBLES", "POISON", "NO_BREATHE", "NOHEAD" ] }, + { + "id": "mon_fungaloid_shambler", + "type": "MONSTER", + "name": { "str": "fungaloid shambler" }, + "description": "A large white fungus, a bulging gray stalk supporting a bloom at the top. Spores float from its gills and tendrils extend from the base. Chunks of rock, metal, bone, and wood are held by tendrils as a kind of armor.", + "copy-from": "mon_fungaloid", + "volume": "12 L", + "weight": "160 kg", + "hp": 150, + "speed": 20, + "armor_cut": 10, + "armor_bullet": 20, + "armor_stab": 20, + "armor_acid": 3, + "special_attacks": [ + [ "FUNGUS", 20 ], + { + "type": "gun", + "cooldown": 5, + "move_cost": 150, + "gun_type": "feral_human_thrown_rock", + "fake_skills": [ [ "gun", 2 ], [ "throw", 2 ] ], + "fake_dex": 6, + "fake_per": 6, + "require_targeting_player": false, + "ranges": [ [ 2, 5, "DEFAULT" ] ], + "description": "The fungaloid shambler throws a rock!" + } + ], + "death_drops": [ { "group": "wreckage", "count": 5 }, { "group": "trash_forest", "count": 5 } ], + "upgrades": { } + }, { "id": "mon_fungaloid_queen", "type": "MONSTER", From 01ddffc1b46dd7271a072e90e81b75c67f84d15a Mon Sep 17 00:00:00 2001 From: FuelType-Memes <42695732+FuelType-Memes@users.noreply.github.com> Date: Thu, 4 Mar 2021 09:58:46 +0300 Subject: [PATCH 257/453] Add book strap carrier (#47665) --- .../itemgroups/Clothing_Gear/clothing.json | 1 + .../Clothing_Gear/gear_civilian.json | 1 + data/json/itemgroups/art_antiques_crafts.json | 3 +- data/json/items/armor/storage.json | 31 +++++++++++++++++++ data/json/recipes/armor/storage.json | 13 ++++++++ .../mods/Magiclysm/itemgroups/itemgroups.json | 10 +++++- 6 files changed, 57 insertions(+), 2 deletions(-) diff --git a/data/json/itemgroups/Clothing_Gear/clothing.json b/data/json/itemgroups/Clothing_Gear/clothing.json index 92b6d2762745f..38006e9cecf33 100644 --- a/data/json/itemgroups/Clothing_Gear/clothing.json +++ b/data/json/itemgroups/Clothing_Gear/clothing.json @@ -3015,6 +3015,7 @@ { "distribution": [ { "item": "case_violin", "prob": 5 }, + { "item": "bookstrap", "prob": 5 }, { "item": "quiver", "prob": 20 }, { "item": "quiver_large", "prob": 15 }, { "item": "solarpack", "prob": 5 }, diff --git a/data/json/itemgroups/Clothing_Gear/gear_civilian.json b/data/json/itemgroups/Clothing_Gear/gear_civilian.json index ee282114dc97d..b9021c3d1629e 100644 --- a/data/json/itemgroups/Clothing_Gear/gear_civilian.json +++ b/data/json/itemgroups/Clothing_Gear/gear_civilian.json @@ -100,6 +100,7 @@ [ "slingpack", 19 ], [ "travelpack", 10 ], [ "petpack", 1 ], + [ "bookstrap", 1 ], [ "pockknife", 14 ], [ "roller_shoes_off", 10 ], [ "knife_swissarmy", 10 ], diff --git a/data/json/itemgroups/art_antiques_crafts.json b/data/json/itemgroups/art_antiques_crafts.json index 1fc319800412c..d1e5a376777c1 100644 --- a/data/json/itemgroups/art_antiques_crafts.json +++ b/data/json/itemgroups/art_antiques_crafts.json @@ -194,7 +194,8 @@ { "item": "coin_quarter", "prob": 1 }, { "item": "bronze_medal", "prob": 1 }, { "item": "silver_medal", "prob": 1 }, - { "item": "gold_medal", "prob": 1 } + { "item": "gold_medal", "prob": 1 }, + { "item": "bookstrap", "prob": 5 } ] }, { diff --git a/data/json/items/armor/storage.json b/data/json/items/armor/storage.json index b410c75b32f3b..fd01f42405db0 100644 --- a/data/json/items/armor/storage.json +++ b/data/json/items/armor/storage.json @@ -1964,5 +1964,36 @@ "warmth": 2, "material_thickness": 1, "flags": [ "BELTED", "WATER_FRIENDLY" ] + }, + { + "id": "bookstrap", + "type": "ARMOR", + "name": { "str": "bookstrap" }, + "description": "An old-fashioned book strap carrier. Guaranteed to make you feel like a proper scholar.", + "weight": "204 g", + "volume": "350 ml", + "price": 12000, + "price_postapoc": 450, + "material": [ "leather" ], + "symbol": "[", + "looks_like": "leather_belt", + "color": "brown", + "covers": [ "leg_l", "leg_r" ], + "sided": true, + "coverage": 5, + "encumbrance": 0, + "max_encumbrance": 11, + "pocket_data": [ + { + "pocket_type": "CONTAINER", + "min_item_volume": "500 ml", + "max_contains_volume": "3 L", + "max_contains_weight": "4 kg", + "max_item_length": "40 cm", + "moves": 400 + } + ], + "material_thickness": 1, + "flags": [ "BELTED", "WATER_FRIENDLY" ] } ] diff --git a/data/json/recipes/armor/storage.json b/data/json/recipes/armor/storage.json index bfba4c0ceb523..a6d04c82dd0ea 100644 --- a/data/json/recipes/armor/storage.json +++ b/data/json/recipes/armor/storage.json @@ -1376,5 +1376,18 @@ { "proficiency": "prof_leatherworking" }, { "proficiency": "prof_leatherworking_basic" } ] + }, + { + "result": "bookstrap", + "type": "recipe", + "activity_level": "LIGHT_EXERCISE", + "category": "CC_ARMOR", + "subcategory": "CSC_ARMOR_STORAGE", + "skill_used": "tailor", + "time": "1 h 30 m", + "autolearn": true, + "reversible": true, + "using": [ [ "tailoring_leather_small", 4 ], [ "clasps", 2 ] ], + "proficiencies": [ { "proficiency": "prof_closures" }, { "proficiency": "prof_leatherworking_basic" } ] } ] diff --git a/data/mods/Magiclysm/itemgroups/itemgroups.json b/data/mods/Magiclysm/itemgroups/itemgroups.json index c8e672809f894..54f1baa86964e 100644 --- a/data/mods/Magiclysm/itemgroups/itemgroups.json +++ b/data/mods/Magiclysm/itemgroups/itemgroups.json @@ -237,7 +237,15 @@ { "type": "item_group", "id": "magic_shop_clothes", - "items": [ [ "cloak", 3 ], [ "cloak_wool", 5 ], [ "jedi_cloak", 3 ], [ "robe", 5 ], [ "tophat", 5 ], [ "leathersandals", 6 ] ] + "items": [ + [ "cloak", 3 ], + [ "cloak_wool", 5 ], + [ "jedi_cloak", 3 ], + [ "robe", 5 ], + [ "tophat", 5 ], + [ "leathersandals", 6 ], + [ "bookstrap", 2 ] + ] }, { "type": "item_group", From 21a0c9afb1bd048710851acad26628217b084c47 Mon Sep 17 00:00:00 2001 From: Anton Burmistrov Date: Thu, 4 Mar 2021 11:00:34 +0400 Subject: [PATCH 258/453] Partial mine jsonify; new zombie miner (#47790) * Moved mine_entrance OMT from the list of hardcoded locations to industial locations Also removed mine_shaft OMT and replaced it with mine_shaft_middle and mine_shaft_lower OMTs. Also added mine_entrance_roof OMT. * Added mine_entrance and mine_shaft to the list of obsoleted terrains * Added a zombie miner and its death drops * Created a json-version of mine entrance and its roof * Created a json-version of mine shaft (middle and lower variants) * Changed overmap special definition of a mine to include new json chunks * Applied migration of hardcoded mine_entrance and mine_shaft OMTs to new json variants * Made hardcoded mine chunks generate to the west of lower section of new mine shaft OMT Also removed mine_entrance and mine_shaft from the list of hardocoded mapgen. * Completely removed build_mine_room function as all mine rooms are now defined in json Also removed hardcoded generation of mine entrance and mine shaft. * Removed mentions of mine rooms from mapgen.h * Updated alt_map_key mod * Updated graphical overmap mod * Added missing harvest * Appease clang and constify * Quickfix * Appease clang one more time --- data/json/mapgen/mine/mine_entrance.json | 194 ++++++++ data/json/mapgen/mine/mine_shaft.json | 88 ++++ data/json/monsterdrops/zombie_technician.json | 24 + data/json/monsters/zed_misc.json | 35 ++ data/json/obsolete_terrains.json | 4 +- .../overmap/overmap_special/specials.json | 8 +- .../overmap_terrain_hardcoded.json | 18 - .../overmap_terrain_industrial.json | 36 ++ .../go_overmap_terrain_hardcoded.json | 16 +- data/mods/alt_map_key/overmap_terrain.json | 17 +- src/mapgen.cpp | 445 ++++-------------- src/mapgen.h | 5 - src/overmap.cpp | 15 +- src/savegame.cpp | 4 +- 14 files changed, 517 insertions(+), 392 deletions(-) create mode 100644 data/json/mapgen/mine/mine_entrance.json create mode 100644 data/json/mapgen/mine/mine_shaft.json diff --git a/data/json/mapgen/mine/mine_entrance.json b/data/json/mapgen/mine/mine_entrance.json new file mode 100644 index 0000000000000..71f2e6a6508c2 --- /dev/null +++ b/data/json/mapgen/mine/mine_entrance.json @@ -0,0 +1,194 @@ +[ + { + "type": "mapgen", + "method": "json", + "om_terrain": "mine_entrance", + "object": { + "rows": [ + "fffffffffffФФfffffffffff", + "f v ,,,,,,,,,,,, !f", + "f/ ,,,,,,,,,,,,,,,,,f", + "|-000--000-0+0|00--00|,f", + "|dddrFFddcW..2|2..Fdd|,f", + "0dC.....Cc....?....dC|,f", + "0............a|b...d.|,f", + "0..C...|*-|-*-|b.....|,f", + "|rddd1p|.l|&_s|a36561|,f", + "|-000--|--|---|------|,f", + "f ,,,,,,,,,,,,,,,,,f", + "|----|+|----| ,,,,,,,/f", + "|I.hĎ|.|дh.I| ,|---%--|", + "0BB..+.+..BB0 ,|eEE~~4|", + "|----|.|----| ,|~EE~~4|", + "|I.hĎ|.|дh.I| ,|------|", + "0BB..+.+..BB0 ,|888888|", + "|----|.|----| ,?~~~~~8|", + "|I.hD|.|Дh.I| ,|888888|", + "0BB..+.+..BB0 ,|------|", + "|----|.|----| ,^`````@|", + "|&___+.+____| ,^``````|", + "|R__s|.|Й__7|/ №|999``$|", + "|----|0|----|fff|------|" + ], + "fill_ter": "t_floor", + "terrain": { + " ": [ [ "t_region_groundcover", 4 ], [ "t_region_shrub", 2 ], [ "t_region_tree", 1 ] ], + "!": "t_manhole_cover", + "/": "t_gutter_downspout", + "|": "t_wall", + "-": "t_wall", + "_": "t_linoleum_white", + "&": "t_linoleum_white", + "*": "t_door_c", + "?": "t_door_locked_alarm", + "+": "t_door_locked", + "%": "t_door_metal_c", + "^": "t_door_metal_locked", + "№": "t_gates_mech_control", + ",": "t_sidewalk", + ".": "t_floor", + "~": "t_thconc_floor", + "`": "t_thconc_floor", + "0": "t_metal_grate_window_with_curtain", + "4": "t_thconc_floor", + "8": "t_thconc_floor", + "9": "t_thconc_floor", + "E": "t_elevator", + "e": "t_elevator_control_off", + "f": "t_chainfence", + "L": "t_door_metal_locked", + "R": "t_linoleum_white", + "s": "t_linoleum_white", + "v": "t_dirt", + "w": "t_window_alarm", + "W": "t_water_dispenser", + "Й": "t_linoleum_white", + "Ф": "t_chaingate_l" + }, + "furniture": { + "1": "f_shredder", + "2": "f_rack_coat", + "3": "f_server", + "4": "f_metal_bench", + "5": "f_console", + "6": "f_console_broken", + "7": "f_shower", + "8": "f_utility_shelf", + "9": "f_utility_shelf", + "a": "f_air_conditioner", + "B": "f_bed", + "b": "f_bookcase", + "c": "f_counter", + "C": "f_chair", + "d": "f_desk", + "D": "f_desk", + "Ď": "f_desk", + "F": "f_filing_cabinet", + "h": "f_chair", + "I": "f_dresser", + "l": "f_locker", + "p": [ "f_indoor_plant", "f_indoor_plant_y" ], + "R": "f_trashcan", + "r": "f_trashcan", + "s": "f_sink", + "v": "f_vent_pipe", + "Д": "f_desk", + "д": "f_desk", + "Й": "f_rack_coat" + }, + "toilets": { "&": { } }, + "items": { + "2": { "item": "coat_rack", "chance": 60, "repeat": 2 }, + "8": { "item": "mine_storage", "chance": 50, "repeat": 4 }, + "9": { "item": "car_kit", "chance": 60, "repeat": 2 }, + "B": { "item": "bed", "chance": 50 }, + "b": { "item": "lab_bookshelves", "chance": 60, "repeat": 2 }, + "c": { "item": "office_supplies", "chance": 60 }, + "D": { "item": "SUS_junk_drawer_artsy", "chance": 90 }, + "Ď": { "item": "SUS_junk_drawer_messy", "chance": 90 }, + "d": { "item": "SUS_office_desk", "chance": 90 }, + "F": { "item": "SUS_office_filing_cabinet", "chance": 90 }, + "I": { "item": "SUS_dresser_mens", "chance": 60 }, + "l": { "item": "SUS_janitors_closet", "chance": 85 }, + "R": { "item": "trash_cart", "chance": 50 }, + "r": { "item": "trash_cart", "chance": 50 }, + "s": { "item": "SUS_bathroom_sink", "chance": 70 }, + "Д": { "item": "SUS_junk_drawer_handy", "chance": 90 }, + "д": { "item": "SUS_junk_drawer_tidy", "chance": 90 } + }, + "monster": { + ",": { "monster": "mon_zombie_miner", "chance": 5 }, + ".": { "monster": "mon_zombie_miner", "chance": 5 }, + "`": { "monster": "mon_zombie_miner", "chance": 5 }, + " ": { "monster": "mon_zombie_miner", "chance": 5 }, + "~": { "monster": "mon_zombie_miner", "chance": 5 } + }, + "computers": { + "5": { + "name": "NEPowerOS", + "security": 2, + "options": [ { "name": "Divert power to elevator", "action": "elevator_on" } ], + "failures": [ { "action": "alarm" } ] + } + }, + "gaspumps": { "@": { "fuel": "gasoline", "amount": [ 10000, 50000 ] }, "$": { "fuel": "diesel", "amount": [ 10000, 50000 ] } }, + "nested": { "`": { "chunks": [ [ "mechanical_fluid", 10 ], [ "gasoline_diesel_motor_oil", 80 ], [ "null", 80 ] ] } } + } + }, + { + "type": "mapgen", + "method": "json", + "om_terrain": "mine_entrance_roof", + "object": { + "rows": [ + " ", + " ", + " ", + "Ю--------------------| ", + "|....................| ", + "|....................| ", + "|....................| ", + "|....................| ", + "|....................| ", + "|--------------------| ", + " ", + "|-----------| ", + "|...........| |------Ю", + "|...........| |......|", + "|...........| |......|", + "|...........| |......|", + "|...........| |......|", + "|...........| |......|", + "|...........| |......|", + "|...........| |......|", + "|...........| |......|", + "|...........| |......|", + "|...........| |......|", + "|-----------Ю |------|" + ], + "terrain": { " ": "t_open_air", "|": "t_gutter_north", "-": "t_gutter_west", "Ю": "t_gutter_drop", ".": "t_flat_roof" } + } + }, + { + "type": "mapgen", + "method": "json", + "nested_mapgen_id": "mechanical_fluid", + "object": { + "mapgensize": [ 1, 1 ], + "place_fields": [ { "field": "fd_mechanical_fluid", "x": 0, "y": 0, "intensity": 1, "age": 10 } ] + } + }, + { + "type": "mapgen", + "method": "json", + "nested_mapgen_id": "gasoline_diesel_motor_oil", + "object": { + "mapgensize": [ 1, 1 ], + "place_liquids": [ + { "liquid": "gasoline", "x": 0, "y": 0, "chance": 20 }, + { "liquid": "diesel", "x": 0, "y": 0, "chance": 20 }, + { "liquid": "motor_oil", "x": 0, "y": 0, "chance": 20 } + ] + } + } +] diff --git a/data/json/mapgen/mine/mine_shaft.json b/data/json/mapgen/mine/mine_shaft.json new file mode 100644 index 0000000000000..674b1d3d59031 --- /dev/null +++ b/data/json/mapgen/mine/mine_shaft.json @@ -0,0 +1,88 @@ +[ + { + "type": "mapgen", + "method": "json", + "om_terrain": "mine_shaft_middle", + "object": { + "fill_ter": "t_rock", + "rows": [ + " <# ", + " # ", + " # ", + " # ", + " # ", + " # ", + " # ", + " # ", + " # ", + " # ", + " # ", + " # ", + " # ", + " ....#># ", + " ....### ", + " ", + " ", + " ", + " ", + " ", + " ", + " ", + " ", + " " + ], + "terrain": { "<": "t_ladder_up", ">": "t_ladder_down", "#": "t_grate", ".": "t_hole" } + } + }, + { + "type": "mapgen", + "method": "json", + "om_terrain": "mine_shaft_lower", + "object": { + "fill_ter": "t_rock_floor", + "rows": [ + "###### ## ########", + "####### ##########", + "######## ##########", + "######## ########", + " ###### #########", + " ## ##########", + "# ########## ", + " ###### ######### ", + "######## #### #", + "###### ", + "###### ######", + "##### ######", + "### |------| ######", + "# |!@@..<|-| ###", + " |.@@....S| ", + "### |---....S| #", + " +.......S| ", + " |.......S| ####", + "## |LLLLLL|-| ######", + "#### |------| ######", + "###### ######", + "####### ## #######", + "######## ## #######", + "######### # ########" + ], + "terrain": { + "<": "t_ladder_up", + "-": "t_wall", + "|": "t_wall", + ".": "t_thconc_floor", + "+": "t_door_metal_c", + "!": "t_elevator_control", + "@": "t_elevator", + "#": [ [ "t_rock", 4 ], [ "t_rock_floor", 1 ] ], + "L": "t_thconc_floor", + "S": "t_thconc_floor" + }, + "furniture": { "L": "f_locker", "S": "f_utility_shelf" }, + "items": { + "L": [ { "item": "clothing_work_set", "chance": 50 }, { "item": "hardware_clothing", "chance": 50 } ], + "S": { "item": "mine_equipment", "chance": 80 } + } + } + } +] diff --git a/data/json/monsterdrops/zombie_technician.json b/data/json/monsterdrops/zombie_technician.json index 08f86d38970f2..4b460cefd2293 100644 --- a/data/json/monsterdrops/zombie_technician.json +++ b/data/json/monsterdrops/zombie_technician.json @@ -13,5 +13,29 @@ { "group": "supplies_electronics", "prob": 50 }, { "item": "id_industrial", "prob": 20 } ] + }, + { + "id": "mon_zombie_miner_death_drops", + "type": "item_group", + "subtype": "collection", + "entries": [ + { "group": "clothing_work_boots", "damage": [ 1, 4 ] }, + { "group": "clothing_work_glasses", "prob": 60, "damage": [ 1, 4 ] }, + { "group": "clothing_work_gloves", "prob": 75, "damage": [ 1, 4 ] }, + { "group": "clothing_work_mask", "prob": 40, "damage": [ 1, 4 ] }, + { "item": "ear_plugs", "prob": 15, "damage": [ 1, 4 ] }, + { "item": "tool_belt", "prob": 25, "damage": [ 1, 4 ] }, + { + "distribution": [ + { + "collection": [ { "group": "clothing_work_pants", "damage": [ 1, 4 ] }, { "group": "clothing_work_torso", "damage": [ 1, 4 ] } ], + "prob": 75 + }, + { "item": "jumpsuit", "prob": 25, "damage": [ 1, 4 ] } + ] + }, + { "group": "underwear", "damage": [ 1, 4 ] }, + { "item": "miner_hat", "prob": 90, "damage": [ 1, 4 ] } + ] } ] diff --git a/data/json/monsters/zed_misc.json b/data/json/monsters/zed_misc.json index e96b80f8362f8..9a8810708c313 100644 --- a/data/json/monsters/zed_misc.json +++ b/data/json/monsters/zed_misc.json @@ -1313,6 +1313,41 @@ "RANGED_ATTACKER" ] }, + { + "id": "mon_zombie_miner", + "type": "MONSTER", + "name": { "str": "zombie miner" }, + "description": "This zombie's face, hands, work clothes, and miner's helmet are fully covered with stains of coal dust.", + "default_faction": "zombie", + "looks_like": "mon_zombie_technician", + "bodytype": "human", + "species": [ "ZOMBIE", "HUMAN" ], + "diff": 2, + "volume": "62500 ml", + "weight": "81500 g", + "hp": 85, + "speed": 75, + "material": [ "flesh" ], + "symbol": "Z", + "color": "i_light_cyan", + "aggression": 70, + "morale": 100, + "melee_skill": 5, + "melee_dice": 2, + "melee_dice_sides": 3, + "melee_cut": 0, + "dodge": 1, + "armor_bash": 2, + "armor_cut": 2, + "armor_bullet": 2, + "vision_day": 15, + "vision_night": 2, + "harvest": "zombie", + "special_attacks": [ { "type": "bite", "cooldown": 20 } ], + "death_drops": "mon_zombie_miner_death_drops", + "death_function": [ "NORMAL" ], + "flags": [ "SEES", "HEARS", "SMELLS", "WARM", "BASHES", "GROUP_BASH", "POISON", "NO_BREATHE", "REVIVES", "FILTHY" ] + }, { "id": "mon_zombie_thorny", "type": "MONSTER", diff --git a/data/json/obsolete_terrains.json b/data/json/obsolete_terrains.json index 3bd39eb0b7947..9d6f430d64b54 100644 --- a/data/json/obsolete_terrains.json +++ b/data/json/obsolete_terrains.json @@ -23,7 +23,9 @@ "office_tower_1_entrance", "office_tower_1", "office_tower_b_entrance", - "office_tower_b" + "office_tower_b", + "mine_entrance", + "mine_shaft" ] } ] diff --git a/data/json/overmap/overmap_special/specials.json b/data/json/overmap/overmap_special/specials.json index a224570fb4db6..845aed0757c17 100644 --- a/data/json/overmap/overmap_special/specials.json +++ b/data/json/overmap/overmap_special/specials.json @@ -1126,7 +1126,13 @@ { "type": "overmap_special", "id": "Mine Entrance", - "overmaps": [ { "point": [ 0, 0, 0 ], "overmap": "s_lot_north" }, { "point": [ 0, 1, 0 ], "overmap": "mine_entrance" } ], + "overmaps": [ + { "point": [ 0, 0, 0 ], "overmap": "s_lot_north" }, + { "point": [ 0, 1, 0 ], "overmap": "mine_entrance_north" }, + { "point": [ 0, 1, 1 ], "overmap": "mine_entrance_roof_north" }, + { "point": [ 0, 1, -1 ], "overmap": "mine_shaft_middle_north" }, + { "point": [ 0, 1, -2 ], "overmap": "mine_shaft_lower_north" } + ], "connections": [ { "point": [ 0, -1, 0 ], "terrain": "road", "connection": "local_road", "from": [ 0, 0, 0 ] } ], "locations": [ "wilderness" ], "city_distance": [ 10, 40 ], diff --git a/data/json/overmap/overmap_terrain/overmap_terrain_hardcoded.json b/data/json/overmap/overmap_terrain/overmap_terrain_hardcoded.json index 55f6ceb154e70..9135c4c7402d7 100644 --- a/data/json/overmap/overmap_terrain/overmap_terrain_hardcoded.json +++ b/data/json/overmap/overmap_terrain/overmap_terrain_hardcoded.json @@ -103,24 +103,6 @@ "see_cost": 5, "flags": [ "KNOWN_DOWN", "NO_ROTATE" ] }, - { - "type": "overmap_terrain", - "id": "mine_entrance", - "name": "mine entrance", - "sym": "M", - "color": "magenta", - "see_cost": 5, - "flags": [ "KNOWN_DOWN", "NO_ROTATE" ] - }, - { - "type": "overmap_terrain", - "id": "mine_shaft", - "name": "mine shaft", - "sym": "O", - "color": "dark_gray", - "see_cost": 5, - "flags": [ "KNOWN_UP", "KNOWN_DOWN", "NO_ROTATE" ] - }, { "type": "overmap_terrain", "id": "mine", diff --git a/data/json/overmap/overmap_terrain/overmap_terrain_industrial.json b/data/json/overmap/overmap_terrain/overmap_terrain_industrial.json index 0485bde2cc4ff..805072815c9a4 100644 --- a/data/json/overmap/overmap_terrain/overmap_terrain_industrial.json +++ b/data/json/overmap/overmap_terrain/overmap_terrain_industrial.json @@ -357,5 +357,41 @@ "see_cost": 5, "extras": "build", "mondensity": 2 + }, + { + "type": "overmap_terrain", + "id": "mine_entrance", + "name": "mine entrance", + "sym": "M", + "color": "magenta", + "see_cost": 5, + "flags": [ "KNOWN_DOWN" ] + }, + { + "type": "overmap_terrain", + "id": "mine_entrance_roof", + "name": "mine entrance roof", + "sym": "M", + "color": "magenta", + "see_cost": 5, + "flags": [ "KNOWN_DOWN" ] + }, + { + "type": "overmap_terrain", + "id": "mine_shaft_middle", + "name": "mine shaft", + "sym": "O", + "color": "dark_gray", + "see_cost": 5, + "flags": [ "KNOWN_UP", "KNOWN_DOWN" ] + }, + { + "type": "overmap_terrain", + "id": "mine_shaft_lower", + "name": "mine shaft", + "sym": "O", + "color": "dark_gray", + "see_cost": 5, + "flags": [ "KNOWN_UP" ] } ] diff --git a/data/mods/Graphical_Overmap/go_overmap_terrain_hardcoded.json b/data/mods/Graphical_Overmap/go_overmap_terrain_hardcoded.json index bfad7b7e1e650..cabc893f2281c 100644 --- a/data/mods/Graphical_Overmap/go_overmap_terrain_hardcoded.json +++ b/data/mods/Graphical_Overmap/go_overmap_terrain_hardcoded.json @@ -73,8 +73,20 @@ }, { "type": "overmap_terrain", - "id": "mine_shaft", - "copy-from": "mine_shaft", + "id": "mine_entrance_roof", + "copy-from": "mine_entrance_roof", + "sym": "\u00D3" + }, + { + "type": "overmap_terrain", + "id": "mine_shaft_middle", + "copy-from": "mine_shaft_middle", + "sym": "\u00D3" + }, + { + "type": "overmap_terrain", + "id": "mine_shaft_lower", + "copy-from": "mine_shaft_lower", "sym": "\u00D3" }, { diff --git a/data/mods/alt_map_key/overmap_terrain.json b/data/mods/alt_map_key/overmap_terrain.json index 0d60bd267ba3c..b36f4871df532 100644 --- a/data/mods/alt_map_key/overmap_terrain.json +++ b/data/mods/alt_map_key/overmap_terrain.json @@ -1836,11 +1836,18 @@ }, { "type": "overmap_terrain", - "id": "mine_shaft", - "copy-from": "mine_shaft", - "name": "mine shaft", - "sym": "m", - "color": "i_black" + "id": "mine_entrance_roof", + "copy-from": "mine_entrance_roof" + }, + { + "type": "overmap_terrain", + "id": "mine_shaft_middle", + "copy-from": "mine_shaft_middle" + }, + { + "type": "overmap_terrain", + "id": "mine_shaft_lower", + "copy-from": "mine_shaft_lower" }, { "type": "overmap_terrain", diff --git a/src/mapgen.cpp b/src/mapgen.cpp index 87be7a15af895..f71fed4becd0e 100644 --- a/src/mapgen.cpp +++ b/src/mapgen.cpp @@ -103,8 +103,6 @@ static const trait_id trait_NPC_STATIC_NPC( "NPC_STATIC_NPC" ); static constexpr int MON_RADIUS = 3; static void science_room( map *m, const point &p1, const point &p2, int z, int rotate ); -static void build_mine_room( room_type type, const point &p1, const point &p2, - const mapgendata &dat ); // (x,y,z) are absolute coordinates of a submap // x%2 and y%2 must be 0! @@ -4254,48 +4252,7 @@ void map::draw_temple( const mapgendata &dat ) void map::draw_mine( mapgendata &dat ) { const oter_id &terrain_type = dat.terrain_type(); - if( terrain_type == "mine_entrance" ) { - dat.fill_groundcover(); - int tries = 0; - bool build_shaft = true; - do { - point p1( rng( 1, 2 * SEEX - 10 ), rng( 1, 2 * SEEY - 10 ) ); - point p2( p1 + point( rng( 4, 9 ), rng( 4, 9 ) ) ); - if( build_shaft ) { - build_mine_room( room_mine_shaft, p1, p2, dat ); - build_shaft = false; - } else { - bool okay = true; - for( int x = p1.x - 1; x <= p2.x + 1 && okay; x++ ) { - for( int y = p1.y - 1; y <= p2.y + 1 && okay; y++ ) { - okay = dat.is_groundcover( ter( point( x, y ) ) ); - } - } - if( okay ) { - room_type type = static_cast( rng( room_mine_office, room_mine_housing ) ); - build_mine_room( type, p1, p2, dat ); - tries = 0; - } else { - tries++; - } - } - } while( tries < 5 ); - int ladderx = rng( 0, EAST_EDGE ), laddery = rng( 0, SOUTH_EDGE ); - while( !dat.is_groundcover( ter( point( ladderx, laddery ) ) ) ) { - ladderx = rng( 0, EAST_EDGE ); - laddery = rng( 0, SOUTH_EDGE ); - } - ter_set( point( ladderx, laddery ), t_manhole_cover ); - } else if( terrain_type == "mine_shaft" ) { - // Not intended to actually be inhabited! - fill_background( this, t_rock ); - square( this, t_hole, point( SEEX - 3, SEEY - 3 ), point( SEEX + 2, SEEY + 2 ) ); - line( this, t_grate, point( SEEX - 3, SEEY - 4 ), point( SEEX + 2, SEEY - 4 ) ); - ter_set( point( SEEX - 3, SEEY - 5 ), t_ladder_up ); - ter_set( point( SEEX + 2, SEEY - 5 ), t_ladder_down ); - rotate( rng( 0, 3 ) ); - } else if( terrain_type == "mine" || - terrain_type == "mine_down" ) { + if( terrain_type == "mine" || terrain_type == "mine_down" ) { if( is_ot_match( "mine", dat.north(), ot_match_type::prefix ) ) { dat.n_fac = ( one_in( 10 ) ? 0 : -2 ); } else { @@ -4329,140 +4286,117 @@ void map::draw_mine( mapgendata &dat ) } } - if( dat.above() == "mine_shaft" ) { // We need the entrance room - square( this, t_floor, point( 10, 10 ), point( 15, 15 ) ); - line( this, t_wall, point( 9, 9 ), point( 16, 9 ) ); - line( this, t_wall, point( 9, 16 ), point( 16, 16 ) ); - line( this, t_wall, point( 9, 10 ), point( 9, 15 ) ); - line( this, t_wall, point( 16, 10 ), point( 16, 15 ) ); - line( this, t_wall, point( 10, 11 ), point( 12, 11 ) ); - ter_set( point( 10, 10 ), t_elevator_control ); - ter_set( point( 11, 10 ), t_elevator ); - ter_set( point( 10, 12 ), t_ladder_up ); - line_furn( this, f_counter, point( 10, 15 ), point( 15, 15 ) ); - place_items( item_group_id( "mine_equipment" ), 86, point( 10, 15 ), point( 15, 15 ), - false, calendar::start_of_cataclysm ); - if( one_in( 2 ) ) { - ter_set( point( 9, 12 ), t_door_c ); - } else { - ter_set( point( 16, 12 ), t_door_c ); - } - - } else { // Not an entrance; maybe some hazards! - switch( rng( 0, 6 ) ) { - case 0: - break; // Nothing! Lucky! + // Not an entrance; maybe some hazards! + switch( rng( 0, 6 ) ) { + case 0: + break; // Nothing! Lucky! - case 1: { // Toxic gas - int cx = rng( 9, 14 ); - int cy = rng( 9, 14 ); - ter_set( point( cx, cy ), t_rock ); - add_field( {cx, cy, abs_sub.z}, fd_gas_vent, 2 ); - } - break; + case 1: { // Toxic gas + point gas_vent_location( rng( 9, 14 ), rng( 9, 14 ) ); + ter_set( point( gas_vent_location ), t_rock ); + add_field( { gas_vent_location, abs_sub.z}, fd_gas_vent, 2 ); + } + break; - case 2: { // Lava - int x1 = rng( 6, SEEX ); - int y1 = rng( 6, SEEY ); - int x2 = rng( SEEX + 1, SEEX * 2 - 7 ); - int y2 = rng( SEEY + 1, SEEY * 2 - 7 ); - int num = rng( 2, 4 ); - for( int i = 0; i < num; i++ ) { - int lx1 = x1 + rng( -1, 1 ), lx2 = x2 + rng( -1, 1 ), - ly1 = y1 + rng( -1, 1 ), ly2 = y2 + rng( -1, 1 ); - line( this, t_lava, point( lx1, ly1 ), point( lx2, ly2 ) ); - } + case 2: { // Lava + point start_location( rng( 6, SEEX ), rng( 6, SEEY ) ); + point end_location( rng( SEEX + 1, SEEX * 2 - 7 ), rng( SEEY + 1, SEEY * 2 - 7 ) ); + const int num = rng( 2, 4 ); + for( int i = 0; i < num; i++ ) { + int lx1 = start_location.x + rng( -1, 1 ), lx2 = end_location.x + rng( -1, 1 ), + ly1 = start_location.y + rng( -1, 1 ), ly2 = end_location.y + rng( -1, 1 ); + line( this, t_lava, point( lx1, ly1 ), point( lx2, ly2 ) ); } - break; + } + break; - case 3: { // Wrecked equipment - int x = rng( 9, 14 ); - int y = rng( 9, 14 ); - for( int i = x - 3; i < x + 3; i++ ) { - for( int j = y - 3; j < y + 3; j++ ) { - if( !one_in( 4 ) ) { - make_rubble( tripoint( i, j, abs_sub.z ), f_wreckage, true ); - } + case 3: { // Wrecked equipment + point wreck_location( rng( 9, 14 ), rng( 9, 14 ) ); + for( int i = wreck_location.x - 3; i < wreck_location.x + 3; i++ ) { + for( int j = wreck_location.y - 3; j < wreck_location.y + 3; j++ ) { + if( !one_in( 4 ) ) { + make_rubble( tripoint( i, j, abs_sub.z ), f_wreckage, true ); } } - place_items( item_group_id( "wreckage" ), 70, point( x - 3, y - 3 ), - point( x + 2, y + 2 ), false, calendar::start_of_cataclysm ); } - break; + place_items( item_group_id( "wreckage" ), 70, wreck_location + point( -3, -3 ), + wreck_location + point( 2, 2 ), false, calendar::start_of_cataclysm ); + } + break; - case 4: { // Dead miners - int num_bodies = rng( 4, 8 ); - for( int i = 0; i < num_bodies; i++ ) { - if( const auto body = random_point( *this, [this]( const tripoint & p ) { - return move_cost( p ) == 2; - } ) ) { - add_item( *body, item::make_corpse() ); - place_items( item_group_id( "mine_equipment" ), 60, *body, *body, - false, calendar::start_of_cataclysm ); - } + case 4: { // Dead miners + const int num_bodies = rng( 4, 8 ); + for( int i = 0; i < num_bodies; i++ ) { + if( const auto body = random_point( *this, [this]( const tripoint & p ) { + return move_cost( p ) == 2; + } ) ) { + add_item( *body, item::make_corpse() ); + place_items( item_group_id( "mine_equipment" ), 60, *body, *body, + false, calendar::start_of_cataclysm ); } } - break; + } + break; - case 5: { // Dark worm! - int num_worms = rng( 1, 5 ); - for( int i = 0; i < num_worms; i++ ) { - std::vector sides; - if( dat.n_fac == 6 ) { - sides.push_back( direction::NORTH ); - } - if( dat.e_fac == 6 ) { - sides.push_back( direction::EAST ); - } - if( dat.s_fac == 6 ) { - sides.push_back( direction::SOUTH ); - } - if( dat.w_fac == 6 ) { - sides.push_back( direction::WEST ); - } - if( sides.empty() ) { - place_spawns( GROUP_DARK_WYRM, 1, point( SEEX, SEEY ), point( SEEX, SEEY ), 1, true ); - i = num_worms; - } else { - point p; - switch( random_entry( sides ) ) { - case direction::NORTH: - p = point( rng( 1, SEEX * 2 - 2 ), rng( 1, 5 ) ); - break; - case direction::EAST: - p = point( SEEX * 2 - rng( 2, 6 ), rng( 1, SEEY * 2 - 2 ) ); - break; - case direction::SOUTH: - p = point( rng( 1, SEEX * 2 - 2 ), SEEY * 2 - rng( 2, 6 ) ); - break; - case direction::WEST: - p = point( rng( 1, 5 ), rng( 1, SEEY * 2 - 2 ) ); - break; - default: - break; - } - ter_set( p, t_rock_floor ); - place_spawns( GROUP_DARK_WYRM, 1, p, p, 1, true ); + case 5: { // Dark worm! + const int num_worms = rng( 1, 5 ); + for( int i = 0; i < num_worms; i++ ) { + std::vector sides; + if( dat.n_fac == 6 ) { + sides.push_back( direction::NORTH ); + } + if( dat.e_fac == 6 ) { + sides.push_back( direction::EAST ); + } + if( dat.s_fac == 6 ) { + sides.push_back( direction::SOUTH ); + } + if( dat.w_fac == 6 ) { + sides.push_back( direction::WEST ); + } + if( sides.empty() ) { + place_spawns( GROUP_DARK_WYRM, 1, point( SEEX, SEEY ), point( SEEX, SEEY ), 1, true ); + i = num_worms; + } else { + point p; + switch( random_entry( sides ) ) { + case direction::NORTH: + p = point( rng( 1, SEEX * 2 - 2 ), rng( 1, 5 ) ); + break; + case direction::EAST: + p = point( SEEX * 2 - rng( 2, 6 ), rng( 1, SEEY * 2 - 2 ) ); + break; + case direction::SOUTH: + p = point( rng( 1, SEEX * 2 - 2 ), SEEY * 2 - rng( 2, 6 ) ); + break; + case direction::WEST: + p = point( rng( 1, 5 ), rng( 1, SEEY * 2 - 2 ) ); + break; + default: + break; } + ter_set( p, t_rock_floor ); + place_spawns( GROUP_DARK_WYRM, 1, p, p, 1, true ); } } - break; + } + break; - case 6: { // Spiral - int orx = rng( SEEX - 4, SEEX ), ory = rng( SEEY - 4, SEEY ); - line( this, t_rock, point( orx, ory ), point( orx + 5, ory ) ); - line( this, t_rock, point( orx + 5, ory ), point( orx + 5, ory + 5 ) ); - line( this, t_rock, point( orx + 1, ory + 5 ), point( orx + 5, ory + 5 ) ); - line( this, t_rock, point( orx + 1, ory + 2 ), point( orx + 1, ory + 4 ) ); - line( this, t_rock, point( orx + 1, ory + 2 ), point( orx + 3, ory + 2 ) ); - ter_set( point( orx + 3, ory + 3 ), t_rock ); - add_item( point( orx + 2, ory + 3 ), item::make_corpse() ); - place_items( item_group_id( "mine_equipment" ), 60, point( orx + 2, ory + 3 ), - point( orx + 2, ory + 3 ), false, calendar::start_of_cataclysm ); - } - break; + case 6: { // Spiral + const int orx = rng( SEEX - 4, SEEX ), ory = rng( SEEY - 4, SEEY ); + line( this, t_rock, point( orx, ory ), point( orx + 5, ory ) ); + line( this, t_rock, point( orx + 5, ory ), point( orx + 5, ory + 5 ) ); + line( this, t_rock, point( orx + 1, ory + 5 ), point( orx + 5, ory + 5 ) ); + line( this, t_rock, point( orx + 1, ory + 2 ), point( orx + 1, ory + 4 ) ); + line( this, t_rock, point( orx + 1, ory + 2 ), point( orx + 3, ory + 2 ) ); + ter_set( point( orx + 3, ory + 3 ), t_rock ); + add_item( point( orx + 2, ory + 3 ), item::make_corpse() ); + place_items( item_group_id( "mine_equipment" ), 60, point( orx + 2, ory + 3 ), + point( orx + 2, ory + 3 ), false, calendar::start_of_cataclysm ); } + break; } + if( terrain_type == "mine_down" ) { // Don't forget to build a slope down! std::vector open; if( dat.n_fac == 4 ) { @@ -4634,14 +4568,14 @@ void map::draw_mine( mapgendata &dat ) computer *tmpcomp = nullptr; switch( rn ) { case 1: { // Wyrms - int x = rng( SEEX, SEEX + 1 ), y = rng( SEEY, SEEY + 1 ); + const int x = rng( SEEX, SEEX + 1 ), y = rng( SEEY, SEEY + 1 ); ter_set( point( x, y ), t_pedestal_wyrm ); spawn_item( point( x, y ), "petrified_eye" ); } break; // That's it! game::examine handles the pedestal/wyrm spawns case 2: { // The Thing dog - int num_bodies = rng( 4, 8 ); + const int num_bodies = rng( 4, 8 ); for( int i = 0; i < num_bodies; i++ ) { int x = rng( 4, SEEX * 2 - 5 ); int y = rng( 4, SEEX * 2 - 5 ); @@ -6126,191 +6060,6 @@ void science_room( map *m, const point &p1, const point &p2, int z, int rotate ) } } -void build_mine_room( room_type type, const point &p1, const point &p2, const mapgendata &dat ) -{ - map *const m = &dat.m; - std::vector possibilities; - point mid( static_cast( ( p1.x + p2.x ) / 2 ), static_cast( ( p1.y + p2.y ) / 2 ) ); - if( p2.x < SEEX ) { - possibilities.push_back( direction::EAST ); - } - if( p1.x > SEEX + 1 ) { - possibilities.push_back( direction::WEST ); - } - if( p1.y > SEEY + 1 ) { - possibilities.push_back( direction::NORTH ); - } - if( p2.y < SEEY ) { - possibilities.push_back( direction::SOUTH ); - } - - if( possibilities.empty() ) { // We're in the middle of the map! - if( mid.x <= SEEX ) { - possibilities.push_back( direction::EAST ); - } else { - possibilities.push_back( direction::WEST ); - } - if( mid.y <= SEEY ) { - possibilities.push_back( direction::SOUTH ); - } else { - possibilities.push_back( direction::NORTH ); - } - } - - const direction door_side = random_entry( possibilities ); - point door_point; - switch( door_side ) { - case direction::NORTH: - door_point.x = mid.x; - door_point.y = p1.y; - break; - case direction::EAST: - door_point.x = p2.x; - door_point.y = mid.y; - break; - case direction::SOUTH: - door_point.x = mid.x; - door_point.y = p2.y; - break; - case direction::WEST: - door_point.x = p1.x; - door_point.y = mid.y; - break; - default: - break; - } - square( m, t_floor, p1, p2 ); - line( m, t_wall, p1, point( p2.x, p1.y ) ); - line( m, t_wall, point( p1.x, p2.y ), p2 ); - line( m, t_wall, p1 + point_south, point( p1.x, p2.y - 1 ) ); - line( m, t_wall, point( p2.x, p1.y + 1 ), p2 + point_north ); - // Main build switch! - switch( type ) { - case room_mine_shaft: { - m->furn_set( p1 + point_south_east, furn_str_id( "f_console" ) ); - line( m, t_wall, point( p2.x - 2, p1.y + 2 ), point( p2.x - 1, p1.y + 2 ) ); - m->ter_set( point( p2.x - 2, p1.y + 1 ), t_elevator ); - m->ter_set( point( p2.x - 1, p1.y + 1 ), t_elevator_control_off ); - computer *tmpcomp = m->add_computer( p1 + tripoint( 1, 1, m->get_abs_sub().z ), - _( "NEPowerOS" ), 2 ); - tmpcomp->add_option( _( "Divert power to elevator" ), COMPACT_ELEVATOR_ON, 0 ); - tmpcomp->add_failure( COMPFAIL_ALARM ); - } - break; - - case room_mine_office: - line_furn( m, f_counter, point( mid.x, p1.y + 2 ), point( mid.x, p2.y - 2 ) ); - line( m, t_window, point( mid.x - 1, p1.y ), point( mid.x + 1, p1.y ) ); - line( m, t_window, point( mid.x - 1, p2.y ), point( mid.x + 1, p2.y ) ); - line( m, t_window, point( p1.x, mid.y - 1 ), point( p1.x, mid.y + 1 ) ); - line( m, t_window, point( p2.x, mid.y - 1 ), point( p2.x, mid.y + 1 ) ); - m->place_items( item_group_id( "office" ), 80, p1 + point_south_east, - p2 + point_north_west, false, calendar::start_of_cataclysm ); - break; - - case room_mine_storage: - m->place_items( item_group_id( "mine_storage" ), 85, p1 + point( 2, 2 ), - p2 + point( -2, -2 ), false, calendar::start_of_cataclysm ); - break; - - case room_mine_fuel: { - int spacing = rng( 2, 4 ); - if( door_side == direction::NORTH || door_side == direction::SOUTH ) { - int y = ( door_side == direction::NORTH ? p1.y + 2 : p2.y - 2 ); - for( int x = p1.x + 1; x <= p2.x - 1; x += spacing ) { - m->place_gas_pump( point( x, y ), rng( 10000, 50000 ) ); - } - } else { - int x = ( door_side == direction::EAST ? p2.x - 2 : p1.x + 2 ); - for( int y = p1.y + 1; y <= p2.y - 1; y += spacing ) { - m->place_gas_pump( point( x, y ), rng( 10000, 50000 ) ); - } - } - } - break; - - case room_mine_housing: - if( door_side == direction::NORTH || door_side == direction::SOUTH ) { - for( int y = p1.y + 2; y <= p2.y - 2; y += 2 ) { - m->ter_set( point( p1.x, y ), t_window ); - m->furn_set( point( p1.x + 1, y ), f_bed ); - m->place_items( item_group_id( "bed" ), 60, point( p1.x + 1, y ), - point( p1.x + 1, y ), false, calendar::start_of_cataclysm ); - m->furn_set( point( p1.x + 2, y ), f_bed ); - m->place_items( item_group_id( "bed" ), 60, point( p1.x + 2, y ), - point( p1.x + 2, y ), false, calendar::start_of_cataclysm ); - m->ter_set( point( p2.x, y ), t_window ); - m->furn_set( point( p2.x - 1, y ), f_bed ); - m->place_items( item_group_id( "bed" ), 60, point( p2.x - 1, y ), - point( p2.x - 1, y ), false, calendar::start_of_cataclysm ); - m->furn_set( point( p2.x - 2, y ), f_bed ); - m->place_items( item_group_id( "bed" ), 60, point( p2.x - 2, y ), - point( p2.x - 2, y ), false, calendar::start_of_cataclysm ); - m->furn_set( point( p1.x + 1, y + 1 ), f_dresser ); - m->place_items( item_group_id( "dresser" ), 78, point( p1.x + 1, y + 1 ), - point( p1.x + 1, y + 1 ), false, calendar::start_of_cataclysm ); - m->furn_set( point( p2.x - 1, y + 1 ), f_dresser ); - m->place_items( item_group_id( "dresser" ), 78, point( p2.x - 1, y + 1 ), - point( p2.x - 1, y + 1 ), false, calendar::start_of_cataclysm ); - } - } else { - for( int x = p1.x + 2; x <= p2.x - 2; x += 2 ) { - m->ter_set( point( x, p1.y ), t_window ); - m->furn_set( point( x, p1.y + 1 ), f_bed ); - m->place_items( item_group_id( "bed" ), 60, point( x, p1.y + 1 ), - point( x, p1.y + 1 ), false, calendar::start_of_cataclysm ); - m->furn_set( point( x, p1.y + 2 ), f_bed ); - m->place_items( item_group_id( "bed" ), 60, point( x, p1.y + 2 ), - point( x, p1.y + 2 ), false, calendar::start_of_cataclysm ); - m->ter_set( point( x, p2.y ), t_window ); - m->furn_set( point( x, p2.y - 1 ), f_bed ); - m->place_items( item_group_id( "bed" ), 60, point( x, p2.y - 1 ), - point( x, p2.y - 1 ), false, calendar::start_of_cataclysm ); - m->furn_set( point( x, p2.y - 2 ), f_bed ); - m->place_items( item_group_id( "bed" ), 60, point( x, p2.y - 2 ), - point( x, p2.y - 2 ), false, calendar::start_of_cataclysm ); - m->furn_set( point( x + 1, p1.y + 1 ), f_dresser ); - m->place_items( item_group_id( "dresser" ), 78, point( x + 1, p1.y + 1 ), - point( x + 1, p1.y + 1 ), false, calendar::start_of_cataclysm ); - m->furn_set( point( x + 1, p2.y - 1 ), f_dresser ); - m->place_items( item_group_id( "dresser" ), 78, point( x + 1, p2.y - 1 ), - point( x + 1, p2.y - 1 ), false, calendar::start_of_cataclysm ); - } - } - m->place_items( item_group_id( "bedroom" ), 65, p1 + point_south_east, - p2 + point_north_west, false, calendar::start_of_cataclysm ); - break; - default: - //Suppress warnings - break; - } - - if( type == room_mine_fuel ) { // Fuel stations are open on one side - switch( door_side ) { - case direction::NORTH: - line( m, t_floor, p1, point( p2.x, p1.y ) ); - break; - case direction::EAST: - line( m, t_floor, point( p2.x, p1.y + 1 ), p2 + point_north ); - break; - case direction::SOUTH: - line( m, t_floor, point( p1.x, p2.y ), p2 ); - break; - case direction::WEST: - line( m, t_floor, p1 + point_south, point( p1.x, p2.y - 1 ) ); - break; - default: - break; - } - } else { - if( type == room_mine_storage ) { // Storage has a locked door - m->ter_set( door_point, t_door_locked ); - } else { - m->ter_set( door_point, t_door_c ); - } - } -} - void map::create_anomaly( const tripoint &cp, artifact_natural_property prop, bool create_rubble ) { // TODO: Z diff --git a/src/mapgen.h b/src/mapgen.h index 4dda960cc54bc..7767c4ddc683a 100644 --- a/src/mapgen.h +++ b/src/mapgen.h @@ -458,11 +458,6 @@ enum room_type { room_bedroom, room_backyard, room_study, - room_mine_shaft, - room_mine_office, - room_mine_storage, - room_mine_fuel, - room_mine_housing, room_split }; diff --git a/src/overmap.cpp b/src/overmap.cpp index 0f1e722f01ca7..e40aa24ce7671 100644 --- a/src/overmap.cpp +++ b/src/overmap.cpp @@ -744,9 +744,7 @@ bool oter_t::is_hardcoded() const "looted_building", // pseudo-terrain "mine", "mine_down", - "mine_entrance", "mine_finale", - "mine_shaft", "office_tower_1", "office_tower_1_entrance", "office_tower_b", @@ -1513,7 +1511,6 @@ bool overmap::generate_sub( const int z ) std::vector central_lab_points; std::vector lab_train_points; std::vector central_lab_train_points; - std::vector shaft_points; std::vector mine_points; // These are so common that it's worth checking first as int. const oter_id skip_above[5] = { @@ -1583,10 +1580,10 @@ bool overmap::generate_sub( const int z ) ter_set( p, oter_id( "central_lab" ) ); } else if( is_ot_match( "hidden_lab_stairs", oter_above, ot_match_type::contains ) ) { lab_points.push_back( city( p.xy(), rng( 1, 5 + z ) ) ); - } else if( oter_above == "mine_entrance" ) { - shaft_points.push_back( p.xy() ); - } else if( oter_above == "mine_shaft" || - oter_above == "mine_down" ) { + } else if( is_ot_match( "mine_entrance", oter_ground, ot_match_type::type ) && z == -2 ) { + mine_points.push_back( city( ( p + tripoint_west ).xy(), rng( 6 + z, 10 + z ) ) ); + requires_sub = true; + } else if( oter_above == "mine_down" ) { ter_set( p, oter_id( "mine" ) ); mine_points.push_back( city( p.xy(), rng( 6 + z, 10 + z ) ) ); // technically not all finales need a sub level, @@ -1746,10 +1743,6 @@ bool overmap::generate_sub( const int z ) build_mine( tripoint_om_omt( i.pos, z ), i.size ); } - for( auto &i : shaft_points ) { - ter_set( tripoint_om_omt( i, z ), oter_id( "mine_shaft" ) ); - requires_sub = true; - } for( auto &i : ant_points ) { const tripoint_om_omt p_loc( i.pos, z ); if( ter( p_loc ) != "empty_rock" ) { diff --git a/src/savegame.cpp b/src/savegame.cpp index 941fc16a7f334..96a1b941acfd4 100644 --- a/src/savegame.cpp +++ b/src/savegame.cpp @@ -348,7 +348,7 @@ void overmap::convert_terrain( if( old == "fema" || old == "fema_entrance" || old == "fema_1_3" || old == "fema_2_1" || old == "fema_2_2" || old == "fema_2_3" || old == "fema_3_1" || old == "fema_3_2" || old == "fema_3_3" || - old == "s_lot" ) { + old == "s_lot" || old == "mine_entrance" ) { ter_set( pos, oter_id( old + "_north" ) ); } else if( old.compare( 0, 6, "bridge" ) == 0 ) { ter_set( pos, oter_id( old ) ); @@ -361,6 +361,8 @@ void overmap::convert_terrain( } } else if( old.compare( 0, 10, "mass_grave" ) == 0 ) { ter_set( pos, oter_id( "field" ) ); + } else if( old == "mine_shaft" ) { + ter_set( pos, oter_id( "mine_shaft_middle_north" ) ); } else if( old.compare( 0, 23, "office_tower_1_entrance" ) == 0 ) { ter_set( pos, oter_id( "office_tower_ne_north" ) ); ter_set( pos + point_west, oter_id( "office_tower_nw_north" ) ); From 9a2919b37b5afc0d7da8a4aa2ce8c512e06906d9 Mon Sep 17 00:00:00 2001 From: actual-nh <74678550+actual-nh@users.noreply.github.com> Date: Thu, 4 Mar 2021 16:19:20 -0500 Subject: [PATCH 259/453] Add 0.F-dev to matrix.yml (#47875) (Getting 0.F-dev working with Travis appears to require additional settings by someone with permissions.) This change enables both pushes and pull requests of 0.F-dev to get checked by the General Matrix. As it is, if one bases a PR off of 0.F-dev, it doesn't get checked by Github. --- .github/workflows/matrix.yml | 2 ++ 1 file changed, 2 insertions(+) diff --git a/.github/workflows/matrix.yml b/.github/workflows/matrix.yml index 8e68f1c1fef23..5510159801530 100644 --- a/.github/workflows/matrix.yml +++ b/.github/workflows/matrix.yml @@ -4,6 +4,7 @@ on: push: branches: - master + - 0.F-dev paths-ignore: - 'android/**' - 'build-data/osx/**' @@ -18,6 +19,7 @@ on: pull_request: branches: - master + - 0.F-dev paths-ignore: - 'android/**' - 'build-data/osx/**' From f71af2f8976959d611edeaba649aa3c936decad8 Mon Sep 17 00:00:00 2001 From: actual-nh <74678550+actual-nh@users.noreply.github.com> Date: Fri, 5 Mar 2021 05:12:40 -0500 Subject: [PATCH 260/453] 0.F-dev workflows (#47875) --- .github/workflows/clang-tidy.yml | 2 ++ .github/workflows/cmake-format.yml | 2 ++ .github/workflows/flake8.yml | 2 ++ .github/workflows/pr-validator.yml | 1 + 4 files changed, 7 insertions(+) diff --git a/.github/workflows/clang-tidy.yml b/.github/workflows/clang-tidy.yml index 56ee2ee858be7..6d888a7be574c 100644 --- a/.github/workflows/clang-tidy.yml +++ b/.github/workflows/clang-tidy.yml @@ -4,6 +4,7 @@ on: push: branches: - master + - 0.F-dev paths: - '**.cpp' - '**.h' @@ -15,6 +16,7 @@ on: pull_request: branches: - master + - 0.F-dev paths: - '**.cpp' - '**.h' diff --git a/.github/workflows/cmake-format.yml b/.github/workflows/cmake-format.yml index bba76717aaef4..563127694ade7 100644 --- a/.github/workflows/cmake-format.yml +++ b/.github/workflows/cmake-format.yml @@ -4,6 +4,7 @@ on: push: branches: - master + - 0.F-dev paths: - '**/CMakeLists.txt' - '**.cmake' @@ -11,6 +12,7 @@ on: pull_request: branches: - master + - 0.F-dev paths: - '**/CMakeLists.txt' - '**.cmake' diff --git a/.github/workflows/flake8.yml b/.github/workflows/flake8.yml index ed7b63dbbc07a..4434a75707c6d 100644 --- a/.github/workflows/flake8.yml +++ b/.github/workflows/flake8.yml @@ -4,11 +4,13 @@ on: push: branches: - master + - 0.F-dev paths: - '**.py' pull_request: branches: - master + - 0.F-dev paths: - '**.py' diff --git a/.github/workflows/pr-validator.yml b/.github/workflows/pr-validator.yml index 2897f6a160c1b..62c6095211c5e 100644 --- a/.github/workflows/pr-validator.yml +++ b/.github/workflows/pr-validator.yml @@ -3,6 +3,7 @@ on: pull_request: branches: - master + - 0.F-dev types: [opened, edited, synchronize] jobs: validate: From 303bcd9f0cd932c2f14040c3cc819934ee479f7f Mon Sep 17 00:00:00 2001 From: actual-nh Date: Sat, 6 Mar 2021 14:33:47 -0500 Subject: [PATCH 261/453] Alter brown bread recipe to match canned version (#47915) Fixes #47874. --- data/json/recipes/food/bread.json | 2 ++ 1 file changed, 2 insertions(+) diff --git a/data/json/recipes/food/bread.json b/data/json/recipes/food/bread.json index 77e84cf6bf0eb..d8ae2930a9b1a 100644 --- a/data/json/recipes/food/bread.json +++ b/data/json/recipes/food/bread.json @@ -44,6 +44,8 @@ [ [ "flour", 5 ] ], [ [ "cornmeal", 5 ] ], [ [ "molasses", 2 ] ], + [ [ "sugar", 1 ] ], + [ [ "molasses", 1 ], [ "sugar", 13 ] ], [ [ "water", 1 ], [ "water_clean", 1 ] ], [ [ "salt", 1 ] ] ], From 7946e425c4dc7807bca92fe05abf71d3eb79ec6b Mon Sep 17 00:00:00 2001 From: Anton Burmistrov Date: Tue, 9 Mar 2021 00:34:10 +0400 Subject: [PATCH 262/453] Mine entrance expand (#47928) * Added mine_materials item group * Added Trolley vehicle * Expanded and tweaked above-ground and underground levels of mine entrance --- .../Locations_MapExtras/locations.json | 20 +++ data/json/mapgen/mine/mine_entrance.json | 131 +++++++++++------- data/json/mapgen/mine/mine_shaft.json | 88 ++++++------ .../overmap/overmap_special/specials.json | 10 +- .../overmap_terrain_industrial.json | 9 +- data/json/vehicles/trains.json | 7 + 6 files changed, 163 insertions(+), 102 deletions(-) diff --git a/data/json/itemgroups/Locations_MapExtras/locations.json b/data/json/itemgroups/Locations_MapExtras/locations.json index 7d728d02b06ca..a3670f5a8f9ca 100644 --- a/data/json/itemgroups/Locations_MapExtras/locations.json +++ b/data/json/itemgroups/Locations_MapExtras/locations.json @@ -1218,6 +1218,26 @@ [ "tool_anfo_charge", 2 ] ] }, + { + "type": "item_group", + "id": "mine_materials", + "subtype": "collection", + "entries": [ + { "item": "coal_lump", "prob": 20, "count": [ 1, 10 ] }, + { "item": "rock", "prob": 40, "count": [ 1, 10 ] }, + { "item": "rock_large", "prob": 10, "count": [ 1, 10 ] }, + { "item": "rock_flaking", "prob": 20, "count": [ 1, 10 ] }, + { "item": "material_shrd_limestone", "prob": 40, "count": [ 1, 10 ] }, + { "item": "material_limestone", "prob": 40, "count": [ 1, 10 ] }, + { "item": "material_niter", "prob": 5, "count": [ 1, 10 ] }, + { "item": "material_sand", "prob": 50, "charges": 500, "container-item": "bag_canvas" }, + { "item": "material_soil", "prob": 50, "charges": 500, "container-item": "bag_canvas" }, + { "item": "chunk_sulfur", "prob": 5, "count": [ 1, 10 ] }, + { "item": "material_rocksalt", "prob": 5, "count": [ 1, 10 ] }, + { "item": "material_rhodonite", "prob": 5, "count": [ 1, 10 ] }, + { "item": "material_zincite", "prob": 5, "count": [ 1, 10 ] } + ] + }, { "type": "item_group", "id": "mine_equipment", diff --git a/data/json/mapgen/mine/mine_entrance.json b/data/json/mapgen/mine/mine_entrance.json index 71f2e6a6508c2..f6b517c69f266 100644 --- a/data/json/mapgen/mine/mine_entrance.json +++ b/data/json/mapgen/mine/mine_entrance.json @@ -2,33 +2,33 @@ { "type": "mapgen", "method": "json", - "om_terrain": "mine_entrance", + "om_terrain": [ [ "mine_entrance", "mine_entrance_loading_zone" ] ], "object": { "rows": [ - "fffffffffffФФfffffffffff", - "f v ,,,,,,,,,,,, !f", - "f/ ,,,,,,,,,,,,,,,,,f", - "|-000--000-0+0|00--00|,f", - "|dddrFFddcW..2|2..Fdd|,f", - "0dC.....Cc....?....dC|,f", - "0............a|b...d.|,f", - "0..C...|*-|-*-|b.....|,f", - "|rddd1p|.l|&_s|a36561|,f", - "|-000--|--|---|------|,f", - "f ,,,,,,,,,,,,,,,,,f", - "|----|+|----| ,,,,,,,/f", - "|I.hĎ|.|дh.I| ,|---%--|", - "0BB..+.+..BB0 ,|eEE~~4|", - "|----|.|----| ,|~EE~~4|", - "|I.hĎ|.|дh.I| ,|------|", - "0BB..+.+..BB0 ,|888888|", - "|----|.|----| ,?~~~~~8|", - "|I.hD|.|Дh.I| ,|888888|", - "0BB..+.+..BB0 ,|------|", - "|----|.|----| ,^`````@|", - "|&___+.+____| ,^``````|", - "|R__s|.|Й__7|/ №|999``$|", - "|----|0|----|fff|------|" + "fffffffffffФФfffffffffffffffФФФФФffffffФФФФФff ", + "f v ,,,,,,,,,,,, ! f ;;;;;;;;;;;;;;;; f ", + "f/ ,,,,,,,,,,,,,,,,, f ;;;;;;;;;;;;;;;; f ", + "|-000--000-0+0|00--00|, f ;;;;;;;;;;;;;;;; f ", + "|dddrFFddcW..2|2..Fdd|, f ;°°°;;;;;;;;;°;; f ", + "0dC.....Cc....?....dC|, f ;°°°;;;;;;;;°°°; f ", + "0............a|b...d.|, f ;°°°;;;;;;;°°°°° f ", + "0..C...|*-|-*-|b.....|, f °°°°°;;;;;;;°°°; f ", + "|rddd1p|.l|&_s|a36561|, f ;°°°;;;;;;;;°°°; f ", + "|-000--|--|---|------|, f ;;°;;;;;;;;;°°°; f ", + "f ,,,,,,,,,,,,,,,,,,,,,,;;;;;;;;;;;;;;;; f ", + "|----|+|----| ,,,,,,,,,,,,,;;;;;;;;;;;;;;;; f ", + "|I.hĎ|.|дh.I| ,|---%-------;;;;;;;;;;;;;;;; f ", + "0BB..+.+..BB0 ,|eEE~~~eEE®®;;;;;;Ø;;;;;;;;; f ", + "|----|.|----| ,|~EE~~~~EE==;;;;;;;;;;;;;;;; f ", + "|I.hĎ|.|дh.I| ,|------|EE=~;;;;;;;;;;;;;;;; f ", + "0BB..+.+..BB0 ,|TTogTr|~~=~;;;;;;;;;;;;;;;; f ", + "|----|.|----| ,0S....Ć|8~=~8| |````| f ", + "|I.hD|.|Дh.I| ,|a....Ĉ|8~=~8| |$``@| f ", + "0BB..+.+..BB0 ,|----+-|8~=~8| |````| f ", + "|----|.|----| ,|hth..h|8~=~8| |````| f ", + "|&___+.+____| ,+.....t|8~~~8| |````| f ", + "|R__s|.|Й__7|/ /|hth..h|88888|/ /|9999| f ", + "|----|0|----|fff|-0--0-|-----|fff|----|fffffff " ], "fill_ter": "t_floor", "terrain": { @@ -43,12 +43,15 @@ "?": "t_door_locked_alarm", "+": "t_door_locked", "%": "t_door_metal_c", - "^": "t_door_metal_locked", - "№": "t_gates_mech_control", ",": "t_sidewalk", + ";": "t_pavement", + "°": "t_pavement_y", + "Ø": "t_pavement", ".": "t_floor", "~": "t_thconc_floor", "`": "t_thconc_floor", + "®": "t_thconc_floor", + "=": "t_conveyor", "0": "t_metal_grate_window_with_curtain", "4": "t_thconc_floor", "8": "t_thconc_floor", @@ -66,6 +69,7 @@ "Ф": "t_chaingate_l" }, "furniture": { + "®": "f_machinery_heavy", "1": "f_shredder", "2": "f_rack_coat", "3": "f_server", @@ -79,18 +83,25 @@ "B": "f_bed", "b": "f_bookcase", "c": "f_counter", + "Ć": "f_cupboard", + "Ĉ": "f_cupboard", "C": "f_chair", "d": "f_desk", "D": "f_desk", "Ď": "f_desk", "F": "f_filing_cabinet", + "g": "f_fridge", "h": "f_chair", "I": "f_dresser", "l": "f_locker", + "o": "f_oven", "p": [ "f_indoor_plant", "f_indoor_plant_y" ], "R": "f_trashcan", "r": "f_trashcan", + "S": "f_sink", "s": "f_sink", + "T": "f_counter", + "t": "f_table", "v": "f_vent_pipe", "Д": "f_desk", "д": "f_desk", @@ -99,20 +110,33 @@ "toilets": { "&": { } }, "items": { "2": { "item": "coat_rack", "chance": 60, "repeat": 2 }, - "8": { "item": "mine_storage", "chance": 50, "repeat": 4 }, + "8": { "item": "mine_materials", "chance": 50, "repeat": 4 }, "9": { "item": "car_kit", "chance": 60, "repeat": 2 }, "B": { "item": "bed", "chance": 50 }, "b": { "item": "lab_bookshelves", "chance": 60, "repeat": 2 }, "c": { "item": "office_supplies", "chance": 60 }, + "Ć": [ + { "item": "SUS_silverware", "chance": 80 }, + { "item": "SUS_utensils", "chance": 80 }, + { "item": "SUS_knife_drawer", "chance": 80 }, + { "item": "SUS_dishes", "chance": 80 }, + { "item": "SUS_cookware", "chance": 80 } + ], + "Ĉ": { "item": "SUS_pantry", "chance": 80 }, "D": { "item": "SUS_junk_drawer_artsy", "chance": 90 }, "Ď": { "item": "SUS_junk_drawer_messy", "chance": 90 }, "d": { "item": "SUS_office_desk", "chance": 90 }, "F": { "item": "SUS_office_filing_cabinet", "chance": 90 }, + "g": { "item": "SUS_fridge", "chance": 80 }, "I": { "item": "SUS_dresser_mens", "chance": 60 }, "l": { "item": "SUS_janitors_closet", "chance": 85 }, + "o": { "item": "SUS_oven", "chance": 70 }, "R": { "item": "trash_cart", "chance": 50 }, "r": { "item": "trash_cart", "chance": 50 }, + "S": { "item": "SUS_kitchen_sink", "chance": 90 }, "s": { "item": "SUS_bathroom_sink", "chance": 70 }, + "T": { "item": "SUS_appliances_cupboard", "chance": 10 }, + "t": { "item": "dining", "chance": 45 }, "Д": { "item": "SUS_junk_drawer_handy", "chance": 90 }, "д": { "item": "SUS_junk_drawer_tidy", "chance": 90 } }, @@ -132,39 +156,40 @@ } }, "gaspumps": { "@": { "fuel": "gasoline", "amount": [ 10000, 50000 ] }, "$": { "fuel": "diesel", "amount": [ 10000, 50000 ] } }, + "vehicles": { "Ø": { "vehicle": "tatra_truck", "chance": 50, "fuel": 40 } }, "nested": { "`": { "chunks": [ [ "mechanical_fluid", 10 ], [ "gasoline_diesel_motor_oil", 80 ], [ "null", 80 ] ] } } } }, { "type": "mapgen", "method": "json", - "om_terrain": "mine_entrance_roof", + "om_terrain": [ [ "mine_entrance_roof", "mine_entrance_loading_zone_roof" ] ], "object": { "rows": [ - " ", - " ", - " ", - "Ю--------------------| ", - "|....................| ", - "|....................| ", - "|....................| ", - "|....................| ", - "|....................| ", - "|--------------------| ", - " ", - "|-----------| ", - "|...........| |------Ю", - "|...........| |......|", - "|...........| |......|", - "|...........| |......|", - "|...........| |......|", - "|...........| |......|", - "|...........| |......|", - "|...........| |......|", - "|...........| |......|", - "|...........| |......|", - "|...........| |......|", - "|-----------Ю |------|" + " ", + " ", + " ", + "Ю--------------------| ", + "|....................| ", + "|....................| ", + "|....................| ", + "|....................| ", + "|....................| ", + "|--------------------| ", + " ", + "|-----------| ", + "|...........| |------------| ", + "|...........| |............| ", + "|...........| |............| ", + "|...........| |............| ", + "|...........| |............| ", + "|...........| |............| |----| ", + "|...........| |............| |....| ", + "|...........| |............| |....| ", + "|...........| |............| |....| ", + "|...........| |............| |....| ", + "|...........| |............| |....| ", + "|-----------Ю Ю------------Ю Ю----| " ], "terrain": { " ": "t_open_air", "|": "t_gutter_north", "-": "t_gutter_west", "Ю": "t_gutter_drop", ".": "t_flat_roof" } } diff --git a/data/json/mapgen/mine/mine_shaft.json b/data/json/mapgen/mine/mine_shaft.json index 674b1d3d59031..3d56375160457 100644 --- a/data/json/mapgen/mine/mine_shaft.json +++ b/data/json/mapgen/mine/mine_shaft.json @@ -6,21 +6,21 @@ "object": { "fill_ter": "t_rock", "rows": [ - " <# ", - " # ", - " # ", - " # ", - " # ", - " # ", - " # ", - " # ", - " # ", - " # ", - " # ", - " # ", - " # ", - " ....#># ", - " ....### ", + " <#", + " #", + " #", + " #", + " #", + " #", + " #", + " #", + " #", + " #", + " #", + " #", + " #>#", + " ....###", + " .... ", " ", " ", " ", @@ -37,34 +37,34 @@ { "type": "mapgen", "method": "json", - "om_terrain": "mine_shaft_lower", + "om_terrain": [ [ "mine_shaft_lower", "mine_shaft_lower_east" ] ], "object": { "fill_ter": "t_rock_floor", "rows": [ - "###### ## ########", - "####### ##########", - "######## ##########", - "######## ########", - " ###### #########", - " ## ##########", - "# ########## ", - " ###### ######### ", - "######## #### #", - "###### ", - "###### ######", - "##### ######", - "### |------| ######", - "# |!@@..<|-| ###", - " |.@@....S| ", - "### |---....S| #", - " +.......S| ", - " |.......S| ####", - "## |LLLLLL|-| ######", - "#### |------| ######", - "###### ######", - "####### ## #######", - "######## ## #######", - "######### # ########" + "###### ## #################### #######", + "###### ## ################### ########", + "###### ## ############# #### #########", + "####### ############### ### ##########", + "######## ############### ## ###########", + "######## ############## ############", + " ###### ################ ##########", + " ## ################# ###########", + "# ##### ###### ###########", + " #### ## ", + "###### ### #### #### ", + "###### |-| #### ##### ", + "###### |----|<|--| ", + "##### |!@@...!@@| #### #####", + "### |.@@....@@| ######### ######", + " +.......@@| ########## ######", + "*****************=========| # ######## ####", + " +.......®®| ####### ####", + " |.........| ######### ####", + "# |.........| ######### #", + "## |LLLL|SSSS| ######### #", + "#### |----|----| ######## #", + "###### ######### ", + "####### ## ####### ######## " ], "terrain": { "<": "t_ladder_up", @@ -75,14 +75,18 @@ "!": "t_elevator_control", "@": "t_elevator", "#": [ [ "t_rock", 4 ], [ "t_rock_floor", 1 ] ], + "=": "t_conveyor", + "*": "t_railroad_track_small", + "®": "t_thconc_floor", "L": "t_thconc_floor", "S": "t_thconc_floor" }, - "furniture": { "L": "f_locker", "S": "f_utility_shelf" }, + "furniture": { "®": "f_machinery_heavy", "L": "f_locker", "S": "f_utility_shelf" }, "items": { "L": [ { "item": "clothing_work_set", "chance": 50 }, { "item": "hardware_clothing", "chance": 50 } ], "S": { "item": "mine_equipment", "chance": 80 } - } + }, + "place_vehicles": [ { "vehicle": "trolley", "x": 10, "y": 16, "chance": 100, "status": 0 } ] } } ] diff --git a/data/json/overmap/overmap_special/specials.json b/data/json/overmap/overmap_special/specials.json index 845aed0757c17..326b01007d486 100644 --- a/data/json/overmap/overmap_special/specials.json +++ b/data/json/overmap/overmap_special/specials.json @@ -1129,11 +1129,17 @@ "overmaps": [ { "point": [ 0, 0, 0 ], "overmap": "s_lot_north" }, { "point": [ 0, 1, 0 ], "overmap": "mine_entrance_north" }, + { "point": [ 1, 1, 0 ], "overmap": "mine_entrance_loading_zone_north" }, + { "point": [ 1, 0, 0 ], "overmap": "road_end_north" }, { "point": [ 0, 1, 1 ], "overmap": "mine_entrance_roof_north" }, { "point": [ 0, 1, -1 ], "overmap": "mine_shaft_middle_north" }, - { "point": [ 0, 1, -2 ], "overmap": "mine_shaft_lower_north" } + { "point": [ 0, 1, -2 ], "overmap": "mine_shaft_lower_north" }, + { "point": [ 1, 1, -2 ], "overmap": "mine_shaft_lower_east_north" } + ], + "connections": [ + { "point": [ 0, -1, 0 ], "terrain": "road", "connection": "local_road", "from": [ 0, 0, 0 ] }, + { "point": [ 1, -1, 0 ], "terrain": "road", "connection": "local_road", "from": [ 1, 0, 0 ] } ], - "connections": [ { "point": [ 0, -1, 0 ], "terrain": "road", "connection": "local_road", "from": [ 0, 0, 0 ] } ], "locations": [ "wilderness" ], "city_distance": [ 10, 40 ], "city_sizes": [ 4, -1 ], diff --git a/data/json/overmap/overmap_terrain/overmap_terrain_industrial.json b/data/json/overmap/overmap_terrain/overmap_terrain_industrial.json index 805072815c9a4..4b946bab6f2a4 100644 --- a/data/json/overmap/overmap_terrain/overmap_terrain_industrial.json +++ b/data/json/overmap/overmap_terrain/overmap_terrain_industrial.json @@ -360,7 +360,7 @@ }, { "type": "overmap_terrain", - "id": "mine_entrance", + "id": [ "mine_entrance", "mine_entrance_loading_zone" ], "name": "mine entrance", "sym": "M", "color": "magenta", @@ -369,12 +369,11 @@ }, { "type": "overmap_terrain", - "id": "mine_entrance_roof", + "id": [ "mine_entrance_roof", "mine_entrance_loading_zone_roof" ], "name": "mine entrance roof", "sym": "M", "color": "magenta", - "see_cost": 5, - "flags": [ "KNOWN_DOWN" ] + "see_cost": 5 }, { "type": "overmap_terrain", @@ -387,7 +386,7 @@ }, { "type": "overmap_terrain", - "id": "mine_shaft_lower", + "id": [ "mine_shaft_lower", "mine_shaft_lower_east" ], "name": "mine shaft", "sym": "O", "color": "dark_gray", diff --git a/data/json/vehicles/trains.json b/data/json/vehicles/trains.json index 21dcea76870b3..44aba2971a6a2 100644 --- a/data/json/vehicles/trains.json +++ b/data/json/vehicles/trains.json @@ -249,5 +249,12 @@ { "x": 0, "y": 0, "parts": [ "frame_vertical_2", "seat", "rail_wheel_small_pair", "controls" ] }, { "x": 0, "y": 0, "parts": [ { "part": "fuel_bunker", "fuel": "coal_lump" } ] } ] + }, + { + "id": "trolley", + "type": "vehicle", + "name": "Trolley", + "blueprint": [ "O" ], + "parts": [ { "x": 0, "y": 0, "parts": [ "frame_vertical", "cargo_space", "rail_wheel_small_pair" ] } ] } ] From 7629605153804c3eb96f00ed31d85bc0b1a0a48d Mon Sep 17 00:00:00 2001 From: LyleSY Date: Mon, 8 Mar 2021 15:36:30 -0500 Subject: [PATCH 263/453] [DinoMod] Mushroom Madness (#47907) --- data/mods/DinoMod/monstergroups/fungi.json | 85 +++- data/mods/DinoMod/monsters/fungus.json | 427 ++++++++++++++++++++- 2 files changed, 485 insertions(+), 27 deletions(-) diff --git a/data/mods/DinoMod/monstergroups/fungi.json b/data/mods/DinoMod/monstergroups/fungi.json index 569949fcec0f3..e4ea76ddb0158 100644 --- a/data/mods/DinoMod/monstergroups/fungi.json +++ b/data/mods/DinoMod/monstergroups/fungi.json @@ -1,24 +1,42 @@ [ - { - "type": "monstergroup", - "name": "GROUP_FUNGI", - "default": "mon_spore", - "monsters": [ - { "monster": "mon_zpinosaurus_fungus", "freq": 0, "cost_multiplier": 0 }, - { "monster": "mon_zyrannosaurus_fungus", "freq": 0, "cost_multiplier": 0 }, - { "monster": "mon_zankylosaurus_fungus", "freq": 0, "cost_multiplier": 0 }, - { "monster": "mon_zeinonychus_fungus", "freq": 0, "cost_multiplier": 0 } - ] - }, { "type": "monstergroup", "name": "GROUP_FUNGI_TOWER", "default": "mon_fungal_tendril", "monsters": [ - { "monster": "mon_zpinosaurus_fungus", "freq": 50, "cost_multiplier": 0 }, - { "monster": "mon_zyrannosaurus_fungus", "freq": 50, "cost_multiplier": 0 }, - { "monster": "mon_zankylosaurus_fungus", "freq": 250, "cost_multiplier": 0 }, - { "monster": "mon_zeinonychus_fungus", "freq": 75, "cost_multiplier": 0 } + { "monster": "mon_zilophosaurus_fungus", "freq": 1, "cost_multiplier": 0, "starts": 72 }, + { "monster": "mon_zeratosaurus_fungus", "freq": 1, "cost_multiplier": 0, "starts": 72 }, + { "monster": "mon_zallosaurus_fungus", "freq": 1, "cost_multiplier": 0, "starts": 144 }, + { "monster": "mon_zacrocanthosaurus_fungus", "freq": 1, "cost_multiplier": 0, "starts": 144 }, + { "monster": "mon_ziats_fungus", "freq": 1, "cost_multiplier": 0, "starts": 144 }, + { "monster": "mon_zalbertosaurus_fungus", "freq": 1, "cost_multiplier": 0, "starts": 72 }, + { "monster": "mon_zyrannosaurus_fungus", "freq": 1, "cost_multiplier": 0, "starts": 144 }, + { "monster": "mon_zallimimus_fungus", "freq": 1, "cost_multiplier": 0, "starts": 72 }, + { "monster": "mon_zothronychus_fungus", "freq": 1, "cost_multiplier": 0, "starts": 72 }, + { "monster": "mon_zeinonychus_fungus", "freq": 1, "cost_multiplier": 0, "starts": 72 }, + { "monster": "mon_zutahraptor_fungus", "freq": 1, "cost_multiplier": 0, "starts": 144 }, + { "monster": "mon_zapatosaurus_fungus", "freq": 1, "cost_multiplier": 0, "starts": 72 }, + { "monster": "mon_zrontosaurus_fungus", "freq": 1, "cost_multiplier": 0, "starts": 72 }, + { "monster": "mon_ziplodocus_fungus", "freq": 1, "cost_multiplier": 0, "starts": 72 }, + { "monster": "mon_zamarasaurus_fungus", "freq": 1, "cost_multiplier": 0, "starts": 72 }, + { "monster": "mon_zrachiosaurus_fungus", "freq": 1, "cost_multiplier": 0, "starts": 72 }, + { "monster": "mon_zalamosaurus_fungus", "freq": 1, "cost_multiplier": 0, "starts": 72 }, + { "monster": "mon_ztegosaurus_fungus", "freq": 1, "cost_multiplier": 0, "starts": 72 }, + { "monster": "mon_zyoplosaurus_fungus", "freq": 1, "cost_multiplier": 0, "starts": 72 }, + { "monster": "mon_zankylosaurus_fungus", "freq": 1, "cost_multiplier": 0, "starts": 72 }, + { "monster": "mon_zodosaurus_fungus", "freq": 1, "cost_multiplier": 0, "starts": 72 }, + { "monster": "mon_zedmontonia_fungus", "freq": 1, "cost_multiplier": 0, "starts": 72 }, + { "monster": "mon_zamptosaurus_fungus", "freq": 1, "cost_multiplier": 0, "starts": 72 }, + { "monster": "mon_zaiasaura_fungus", "freq": 1, "cost_multiplier": 0, "starts": 72 }, + { "monster": "mon_zarasaurolophus_fungus", "freq": 1, "cost_multiplier": 0, "starts": 72 }, + { "monster": "mon_zorythosaurus_fungus", "freq": 1, "cost_multiplier": 0, "starts": 72 }, + { "monster": "mon_zedmontosaurus_fungus", "freq": 1, "cost_multiplier": 0, "starts": 72 }, + { "monster": "mon_zachycephalosaurus_fungus", "freq": 1, "cost_multiplier": 0, "starts": 72 }, + { "monster": "mon_zachyrhinosaurus_fungus", "freq": 1, "cost_multiplier": 0, "starts": 72 }, + { "monster": "mon_zentaceratops_fungus", "freq": 1, "cost_multiplier": 0, "starts": 72 }, + { "monster": "mon_zosmoceratops_fungus", "freq": 1, "cost_multiplier": 0, "starts": 72 }, + { "monster": "mon_zorosaurus_fungus", "freq": 1, "cost_multiplier": 0, "starts": 72 }, + { "monster": "mon_zriceratops_fungus", "freq": 1, "cost_multiplier": 0, "starts": 72 } ] }, { @@ -26,10 +44,39 @@ "name": "GROUP_FUNGI_FLOWERS", "default": "mon_fungal_blossom", "monsters": [ - { "monster": "mon_zpinosaurus_fungus", "freq": 50, "cost_multiplier": 0 }, - { "monster": "mon_zyrannosaurus_fungus", "freq": 50, "cost_multiplier": 0 }, - { "monster": "mon_zankylosaurus_fungus", "freq": 250, "cost_multiplier": 0 }, - { "monster": "mon_zeinonychus_fungus", "freq": 75, "cost_multiplier": 0 } + { "monster": "mon_zilophosaurus_fungus", "freq": 1, "cost_multiplier": 0, "starts": 72 }, + { "monster": "mon_zeratosaurus_fungus", "freq": 1, "cost_multiplier": 0, "starts": 72 }, + { "monster": "mon_zallosaurus_fungus", "freq": 1, "cost_multiplier": 0, "starts": 144 }, + { "monster": "mon_zacrocanthosaurus_fungus", "freq": 1, "cost_multiplier": 0, "starts": 144 }, + { "monster": "mon_ziats_fungus", "freq": 1, "cost_multiplier": 0, "starts": 144 }, + { "monster": "mon_zalbertosaurus_fungus", "freq": 1, "cost_multiplier": 0, "starts": 72 }, + { "monster": "mon_zyrannosaurus_fungus", "freq": 1, "cost_multiplier": 0, "starts": 144 }, + { "monster": "mon_zallimimus_fungus", "freq": 1, "cost_multiplier": 0, "starts": 72 }, + { "monster": "mon_zothronychus_fungus", "freq": 1, "cost_multiplier": 0, "starts": 72 }, + { "monster": "mon_zeinonychus_fungus", "freq": 1, "cost_multiplier": 0, "starts": 72 }, + { "monster": "mon_zutahraptor_fungus", "freq": 1, "cost_multiplier": 0, "starts": 144 }, + { "monster": "mon_zapatosaurus_fungus", "freq": 1, "cost_multiplier": 0, "starts": 72 }, + { "monster": "mon_zrontosaurus_fungus", "freq": 1, "cost_multiplier": 0, "starts": 72 }, + { "monster": "mon_ziplodocus_fungus", "freq": 1, "cost_multiplier": 0, "starts": 72 }, + { "monster": "mon_zamarasaurus_fungus", "freq": 1, "cost_multiplier": 0, "starts": 72 }, + { "monster": "mon_zrachiosaurus_fungus", "freq": 1, "cost_multiplier": 0, "starts": 72 }, + { "monster": "mon_zalamosaurus_fungus", "freq": 1, "cost_multiplier": 0, "starts": 72 }, + { "monster": "mon_ztegosaurus_fungus", "freq": 1, "cost_multiplier": 0, "starts": 72 }, + { "monster": "mon_zyoplosaurus_fungus", "freq": 1, "cost_multiplier": 0, "starts": 72 }, + { "monster": "mon_zankylosaurus_fungus", "freq": 1, "cost_multiplier": 0, "starts": 72 }, + { "monster": "mon_zodosaurus_fungus", "freq": 1, "cost_multiplier": 0, "starts": 72 }, + { "monster": "mon_zedmontonia_fungus", "freq": 1, "cost_multiplier": 0, "starts": 72 }, + { "monster": "mon_zamptosaurus_fungus", "freq": 1, "cost_multiplier": 0, "starts": 72 }, + { "monster": "mon_zaiasaura_fungus", "freq": 1, "cost_multiplier": 0, "starts": 72 }, + { "monster": "mon_zarasaurolophus_fungus", "freq": 1, "cost_multiplier": 0, "starts": 72 }, + { "monster": "mon_zorythosaurus_fungus", "freq": 1, "cost_multiplier": 0, "starts": 72 }, + { "monster": "mon_zedmontosaurus_fungus", "freq": 1, "cost_multiplier": 0, "starts": 72 }, + { "monster": "mon_zachycephalosaurus_fungus", "freq": 1, "cost_multiplier": 0, "starts": 72 }, + { "monster": "mon_zachyrhinosaurus_fungus", "freq": 1, "cost_multiplier": 0, "starts": 72 }, + { "monster": "mon_zentaceratops_fungus", "freq": 1, "cost_multiplier": 0, "starts": 72 }, + { "monster": "mon_zosmoceratops_fungus", "freq": 1, "cost_multiplier": 0, "starts": 72 }, + { "monster": "mon_zorosaurus_fungus", "freq": 1, "cost_multiplier": 0, "starts": 72 }, + { "monster": "mon_zriceratops_fungus", "freq": 1, "cost_multiplier": 0, "starts": 72 } ] } ] diff --git a/data/mods/DinoMod/monsters/fungus.json b/data/mods/DinoMod/monsters/fungus.json index 8bc86b455790e..fa1f15212e239 100644 --- a/data/mods/DinoMod/monsters/fungus.json +++ b/data/mods/DinoMod/monsters/fungus.json @@ -1,4 +1,40 @@ [ + { + "id": "mon_zilophosaurus_fungus", + "type": "MONSTER", + "name": { "str": "fungal Dilophosaurus zombie" }, + "description": "Once a predator dinosaur with sharp teeth and two prominent bony crests on its head, fungal tendrils now sprout from its mouth, eyes, and other orifices, holding together a shambling mass of mold-covered flesh with a colorful frill of interwoven mushrooms.", + "copy-from": "mon_zilophosaurus", + "default_faction": "fungus", + "species": [ "FUNGUS" ], + "diff": 2, + "proportional": { "hp": 0.75, "speed": 0.65 }, + "color": "light_gray", + "relative": { "melee_skill": -1, "melee_dice": -1, "melee_dice_sides": 3, "armor_bash": 3 }, + "vision_day": 5, + "vision_night": 5, + "special_attacks": [ [ "FUNGUS", 200 ], { "type": "bite", "cooldown": 5 } ], + "upgrades": { }, + "flags": [ "SEES", "SMELLS", "POISON", "STUMBLES", "NO_BREATHE", "FILTHY", "WARM" ] + }, + { + "id": "mon_zeratosaurus_fungus", + "type": "MONSTER", + "name": { "str": "fungal zombie dragon" }, + "description": "Once an enormous, scaly dinosaur studded with bony spikes with colorful horns, fungal tendrils now sprout from its mouth, eyes, and other orifices, holding together a shambling mass of mold-covered scales and spikes.", + "copy-from": "mon_zeratosaurus", + "default_faction": "fungus", + "species": [ "FUNGUS" ], + "diff": 2, + "proportional": { "hp": 0.75, "speed": 0.65 }, + "color": "light_gray", + "relative": { "melee_skill": -1, "melee_dice": -1, "melee_dice_sides": 3, "armor_bash": 3 }, + "vision_day": 5, + "vision_night": 5, + "special_attacks": [ [ "FUNGUS", 200 ], { "type": "bite", "cooldown": 5 } ], + "upgrades": { }, + "flags": [ "SEES", "SMELLS", "HEARS", "BASHES", "POISON", "STUMBLES", "NO_BREATHE", "FILTHY", "WARM", "SWIMS" ] + }, { "id": "mon_zpinosaurus_fungus", "type": "MONSTER", @@ -17,6 +53,78 @@ "upgrades": { }, "flags": [ "SEES", "SMELLS", "POISON", "STUMBLES", "BASHES", "DESTROYS", "NO_BREATHE", "FILTHY", "WARM", "SWIMS" ] }, + { + "id": "mon_zallosaurus_fungus", + "type": "MONSTER", + "name": { "str": "fungal Allosaurus zombie" }, + "description": "Once a large predatory bipedal dinosaur with a broad scaly back, fungal tendrils now sprout from its mouth, eyes, and other orifices, holding together a shambling mass of mold-covered flesh.", + "copy-from": "mon_zallosaurus", + "default_faction": "fungus", + "species": [ "FUNGUS" ], + "diff": 2, + "proportional": { "hp": 0.75, "speed": 0.65 }, + "color": "light_gray", + "relative": { "melee_skill": -1, "melee_dice": -1, "melee_dice_sides": 3, "armor_bash": 3 }, + "vision_day": 5, + "vision_night": 5, + "special_attacks": [ [ "FUNGUS", 200 ], { "type": "bite", "cooldown": 5 } ], + "upgrades": { }, + "flags": [ "SEES", "SMELLS", "POISON", "STUMBLES", "BASHES", "NO_BREATHE", "FILTHY", "WARM" ] + }, + { + "id": "mon_zacrocanthosaurus_fungus", + "type": "MONSTER", + "name": { "str": "fungal Acrocanthosaurus zombie" }, + "description": "Once a huge predatory bipedal dinosaur, with a tall ridge running down the length of its back covered with heavy muscles and showing teeth curved and serrated like sawblades, fungal tendrils now sprout from its mouth, eyes, and other orifices, holding together a shambling mass of mold-covered flesh.", + "copy-from": "mon_zacrocanthosaurus", + "default_faction": "fungus", + "species": [ "FUNGUS" ], + "diff": 2, + "proportional": { "hp": 0.75, "speed": 0.65 }, + "color": "light_gray", + "relative": { "melee_skill": -1, "melee_dice": -1, "melee_dice_sides": 3, "armor_bash": 3 }, + "vision_day": 5, + "vision_night": 5, + "special_attacks": [ [ "FUNGUS", 200 ], [ "GRAB", 10 ], [ "LUNGE", 20 ] ], + "upgrades": { }, + "flags": [ "SEES", "SMELLS", "POISON", "STUMBLES", "BASHES", "NO_BREATHE", "FILTHY", "WARM" ] + }, + { + "id": "mon_ziats_fungus", + "type": "MONSTER", + "name": { "str": "fungal Siats zombie" }, + "description": "Once a huge predatory bipedal dinosaur with long claws and strong arms for grappling, fungal tendrils now sprout from its mouth, eyes, and other orifices, holding together a shambling mass of mold-covered flesh.", + "copy-from": "mon_ziats", + "default_faction": "fungus", + "species": [ "FUNGUS" ], + "diff": 2, + "proportional": { "hp": 0.75, "speed": 0.65 }, + "color": "light_gray", + "relative": { "melee_skill": -1, "melee_dice": -1, "melee_dice_sides": 3, "armor_bash": 3 }, + "vision_day": 5, + "vision_night": 5, + "special_attacks": [ [ "FUNGUS", 200 ], [ "BIO_OP_TAKEDOWN", 20 ], [ "RANGED_PULL", 20 ], [ "GRAB_DRAG", 10 ] ], + "upgrades": { }, + "flags": [ "SEES", "SMELLS", "POISON", "STUMBLES", "BASHES", "NO_BREATHE", "FILTHY", "WARM" ] + }, + { + "id": "mon_zalbertosaurus_fungus", + "type": "MONSTER", + "name": { "str": "fungal Albertosaurus zombie" }, + "description": "Once a huge predatory bipedal dinosaur with long claws and massive jaws, fungal tendrils now sprout from its mouth, eyes, and other orifices, holding together a shambling mass of mold-covered flesh.", + "copy-from": "mon_zalbertosaurus", + "default_faction": "fungus", + "species": [ "FUNGUS" ], + "diff": 2, + "proportional": { "hp": 0.75, "speed": 0.65 }, + "color": "light_gray", + "relative": { "melee_skill": -1, "melee_dice": -1, "melee_dice_sides": 3, "armor_bash": 3 }, + "vision_day": 5, + "vision_night": 5, + "special_attacks": [ [ "FUNGUS", 200 ], { "type": "bite", "cooldown": 5 }, [ "GRAB", 7 ], [ "scratch", 20 ], [ "LUNGE", 5 ] ], + "upgrades": { }, + "flags": [ "SEES", "SMELLS", "POISON", "STUMBLES", "BASHES", "DESTROYS", "NO_BREATHE", "FILTHY", "WARM" ] + }, { "id": "mon_zyrannosaurus_fungus", "type": "MONSTER", @@ -36,11 +144,11 @@ "flags": [ "SEES", "SMELLS", "POISON", "STUMBLES", "BASHES", "DESTROYS", "NO_BREATHE", "FILTHY", "WARM" ] }, { - "id": "mon_zankylosaurus_fungus", + "id": "mon_zallimimus_fungus", "type": "MONSTER", - "name": { "str": "fungal Ankylosaurus zombie" }, - "description": "Once something like a giant armadillo dinosaur hybrid with a spiked tail, fungal tendrils now sprout from its mouth, eyes, and other orifices, holding together an enormous shambling mass of mold-covered flesh.", - "copy-from": "mon_zankylosaurus", + "name": { "str": "fungal Gallimimus zombie" }, + "description": "Once a featherd bipedal plant eating dinosaur, fungal tendrils now sprout from its mouth, eyes, and other orifices, holding together an enormous shambling mass of mold-covered feathers.", + "copy-from": "mon_zallimimus", "default_faction": "fungus", "species": [ "FUNGUS" ], "diff": 2, @@ -49,15 +157,33 @@ "relative": { "melee_skill": -1, "melee_dice": -1, "melee_dice_sides": 3, "armor_bash": 3 }, "vision_day": 5, "vision_night": 5, - "special_attacks": [ [ "FUNGUS", 200 ] ], + "special_attacks": [ [ "FUNGUS", 200 ], [ "scratch", 10 ], { "type": "bite", "cooldown": 5 } ], "upgrades": { }, - "flags": [ "SEES", "SMELLS", "POISON", "STUMBLES", "NO_BREATHE", "FILTHY", "WARM", "BASHES" ] + "flags": [ "SEES", "SMELLS", "HEARS", "PET_MOUNTABLE", "POISON", "STUMBLES", "NO_BREATHE", "FILTHY", "WARM" ] + }, + { + "id": "mon_zothronychus_fungus", + "type": "MONSTER", + "name": { "str": "fungal Nothronychus zombie" }, + "description": "Once a large feathered bipedal plant eating dinosaur with sharp curved claws, fungal tendrils now sprout from its mouth, eyes, and other orifices, holding together a shambling mass of mold-covered feathers.", + "copy-from": "mon_zothronychus", + "default_faction": "fungus", + "species": [ "FUNGUS" ], + "diff": 2, + "proportional": { "hp": 0.75, "speed": 0.65 }, + "color": "light_gray", + "relative": { "melee_skill": -1, "melee_dice": -1, "melee_dice_sides": 3, "armor_bash": 3 }, + "vision_day": 5, + "vision_night": 5, + "special_attacks": [ [ "FUNGUS", 200 ], [ "LONGSWIPE", 30 ] ], + "upgrades": { }, + "flags": [ "SEES", "SMELLS", "HEARS", "KEENNOSE", "POISON", "STUMBLES", "NO_BREATHE", "FILTHY", "WARM", "BASHES" ] }, { "id": "mon_zeinonychus_fungus", "type": "MONSTER", "name": { "str": "fungal Deinonychus zombie" }, - "description": "Once a medium-sized feathered carnivorous dinosaur, fungal tendrils now sprout from its mouth, eyes, and other orifices, holding together an enormous shambling mass of mold-covered flesh.", + "description": "Once a feathered meat eating dinosaur with a large, sickle-shaped talon on each foot, fungal tendrils now sprout from its mouth, eyes, and other orifices, holding together an enormous shambling mass of mold-covered flesh.", "copy-from": "mon_zeinonychus", "default_faction": "fungus", "species": [ "FUNGUS" ], @@ -67,8 +193,293 @@ "relative": { "melee_skill": -1, "melee_dice": -1, "melee_dice_sides": 3, "armor_bash": 3 }, "vision_day": 5, "vision_night": 5, - "special_attacks": [ [ "FUNGUS", 200 ], { "type": "bite", "cooldown": 5 } ], + "special_attacks": [ + [ "FUNGUS", 200 ], + { "type": "leap", "cooldown": 5, "max_range": 5, "allow_no_target": true }, + [ "scratch", 10 ], + { "type": "bite", "cooldown": 5 } + ], "upgrades": { }, "flags": [ "SEES", "SMELLS", "KEENNOSE", "POISON", "STUMBLES", "NO_BREATHE", "FILTHY", "WARM" ] + }, + { + "id": "mon_zutahraptor_fungus", + "type": "MONSTER", + "name": { "str": "fungal Utahraptor zombie" }, + "description": "Once a large feathered meat eating dinosaur with a sickle-shaped talon on each foot, fungal tendrils now sprout from its mouth, eyes, and other orifices, holding together an enormous shambling mass of mold-covered flesh.", + "copy-from": "mon_zutahraptor", + "default_faction": "fungus", + "species": [ "FUNGUS" ], + "diff": 2, + "proportional": { "hp": 0.75, "speed": 0.65 }, + "color": "light_gray", + "relative": { "melee_skill": -1, "melee_dice": -1, "melee_dice_sides": 3, "armor_bash": 3 }, + "vision_day": 5, + "vision_night": 5, + "special_attacks": [ + [ "FUNGUS", 200 ], + { "type": "leap", "cooldown": 5, "max_range": 5, "allow_no_target": true }, + [ "scratch", 10 ], + { "type": "bite", "cooldown": 5 } + ], + "upgrades": { }, + "flags": [ "SEES", "SMELLS", "KEENNOSE", "POISON", "STUMBLES", "NO_BREATHE", "FILTHY", "WARM" ] + }, + { + "id": "mon_zapatosaurus_fungus", + "type": "MONSTER", + "name": { "str": "fungal Apatosaurus zombie" }, + "description": "Once a massive, long-necked, four-legged plant eating dinosaur with a long, whip-like tail, fungal tendrils now sprout from its mouth, eyes, and other orifices, holding together an enormous shambling mass of mold-covered flesh.", + "copy-from": "mon_zapatosaurus", + "default_faction": "fungus", + "species": [ "FUNGUS" ], + "diff": 2, + "proportional": { "hp": 0.75, "speed": 0.65 }, + "color": "light_gray", + "relative": { "melee_skill": -1, "melee_dice": -1, "melee_dice_sides": 3, "armor_bash": 3 }, + "vision_day": 5, + "vision_night": 5, + "special_attacks": [ + [ "FUNGUS", 200 ], + { "id": "slam", "cooldown": 10, "damage_max_instance": [ { "damage_type": "bash", "amount": 12 } ] }, + [ "SMASH", 30 ] + ], + "upgrades": { }, + "flags": [ "SEES", "SMELLS", "POISON", "STUMBLES", "NO_BREATHE", "FILTHY", "WARM", "BASHES" ] + }, + { + "id": "mon_zrontosaurus_fungus", + "type": "MONSTER", + "name": { "str": "fungal Brontosaurus zombie" }, + "description": "Once a massive, long-necked, four-legged plant eating dinosaur with a bulky torso and long, whip-like tail, fungal tendrils now sprout from its mouth, eyes, and other orifices, holding together an enormous shambling mass of mold-covered flesh.", + "copy-from": "mon_zapatosaurus_fungus" + }, + { + "id": "mon_ziplodocus_fungus", + "type": "MONSTER", + "name": { "str": "fungal Diplodocus zombie" }, + "description": "Once a huge, long-necked, four-legged plant eating dinosaur with a tiny head and long, whip-like tail, fungal tendrils now sprout from its mouth, eyes, and other orifices, holding together an enormous shambling mass of mold-covered flesh.", + "copy-from": "mon_zapatosaurus_fungus" + }, + { + "id": "mon_zamarasaurus_fungus", + "type": "MONSTER", + "name": { "str": "fungal Camarasaurus zombie" }, + "description": "Once a huge, long-necked, four-legged plant eating dinosaur with a long, whip-like tail, fungal tendrils now sprout from its mouth, eyes, and other orifices, holding together an enormous shambling mass of mold-covered flesh.", + "copy-from": "mon_zapatosaurus_fungus" + }, + { + "id": "mon_zrachiosaurus_fungus", + "type": "MONSTER", + "name": { "str": "fungal Brachiosaurus zombie" }, + "description": "Once a gigantic, long-necked, four-legged plant eating dinosaur with longer forelegs and a long, whip-like tail, fungal tendrils now sprout from its mouth, eyes, and other orifices, holding together an enormous shambling mass of mold-covered flesh.", + "copy-from": "mon_zapatosaurus_fungus", + "proportional": { "hp": 2, "speed": 0.65 } + }, + { + "id": "mon_zalamosaurus_fungus", + "type": "MONSTER", + "name": { "str": "fungal Alamosaurus zombie" }, + "description": "Once a gigantic, long-necked, four-legged plant eating dinosaur with longer forelegs and spiked tail protected by natural bone armor, fungal tendrils now sprout from its mouth, eyes, and other orifices, holding together an enormous shambling mass of mold-covered flesh.", + "copy-from": "mon_zapatosaurus_fungus", + "proportional": { "hp": 1.5, "speed": 0.8, "armor_bash": 2, "armor_cut": 2 } + }, + { + "id": "mon_ztegosaurus_fungus", + "type": "MONSTER", + "name": { "str": "fungal Stegosaurus zombie" }, + "description": "Once a large four legged plant eating dinosaur with heavy bone plates jutting from its back and spiked tail, fungal tendrils now sprout from its mouth, eyes, and other orifices, holding together a shambling mass of mold-covered flesh.", + "copy-from": "mon_ztegosaurus", + "default_faction": "fungus", + "species": [ "FUNGUS" ], + "diff": 2, + "proportional": { "hp": 0.75, "speed": 0.65 }, + "color": "light_gray", + "relative": { "melee_skill": -1, "melee_dice": -1, "melee_dice_sides": 3, "armor_bash": 3 }, + "vision_day": 5, + "vision_night": 5, + "special_attacks": [ + [ "FUNGUS", 200 ], + { "id": "slam", "cooldown": 10, "damage_max_instance": [ { "damage_type": "bash", "amount": 12 } ] }, + [ "SMASH", 30 ] + ], + "upgrades": { }, + "flags": [ "SEES", "SMELLS", "POISON", "STUMBLES", "NO_BREATHE", "FILTHY", "WARM", "BASHES" ] + }, + { + "id": "mon_zyoplosaurus_fungus", + "type": "MONSTER", + "name": { "str": "fungal Dyoplosaurus zombie" }, + "description": "Once something like a giant armadillo dinosaur hybrid with a spiked club tail, fungal tendrils now sprout from its mouth, eyes, and other orifices, holding together a shambling mass of mold-covered flesh and bone.", + "copy-from": "mon_zankylosaurus_fungus", + "proportional": { "hp": 0.35, "speed": 1.2 } + }, + { + "id": "mon_zankylosaurus_fungus", + "type": "MONSTER", + "name": { "str": "fungal Ankylosaurus zombie" }, + "description": "Once something like a giant armadillo dinosaur hybrid with a spiked tail, fungal tendrils now sprout from its mouth, eyes, and other orifices, holding together an enormous shambling mass of mold-covered flesh and bone.", + "copy-from": "mon_zankylosaurus", + "default_faction": "fungus", + "species": [ "FUNGUS" ], + "diff": 2, + "proportional": { "hp": 0.75, "speed": 0.65 }, + "color": "light_gray", + "relative": { "melee_skill": -1, "melee_dice": -1, "melee_dice_sides": 3, "armor_bash": 3 }, + "vision_day": 5, + "vision_night": 5, + "special_attacks": [ + [ "FUNGUS", 200 ], + [ "scratch", 10 ], + { "type": "bite", "cooldown": 5 }, + { "id": "slam", "cooldown": 10, "damage_max_instance": [ { "damage_type": "bash", "amount": 12 } ] }, + [ "SMASH", 30 ] + ], + "upgrades": { }, + "flags": [ "SEES", "SMELLS", "POISON", "STUMBLES", "NO_BREATHE", "FILTHY", "WARM", "BASHES" ] + }, + { + "id": "mon_zodosaurus_fungus", + "type": "MONSTER", + "name": { "str": "fungal Nodosaurus zombie" }, + "description": "Once something like a giant armadillo dinosaur hybrid, fungal tendrils now sprout from its mouth, eyes, and other orifices, holding together a shambling mass of mold-covered flesh and bone.", + "copy-from": "mon_zankylosaurus_fungus", + "proportional": { "hp": 0.6 }, + "special_attacks": [ [ "FUNGUS", 200 ], [ "scratch", 10 ], { "type": "bite", "cooldown": 5 } ] + }, + { + "id": "mon_zedmontonia_fungus", + "type": "MONSTER", + "name": { "str": "fungal Edmontonia zombie" }, + "description": "Once something like a giant armadillo dinosaur hybrid with long bony spikes, fungal tendrils now sprout from its mouth, eyes, and other orifices, holding together a shambling mass of mold-covered flesh and bone.", + "copy-from": "mon_zankylosaurus_fungus", + "melee_cut": 10, + "proportional": { "hp": 0.65 }, + "special_attacks": [ [ "FUNGUS", 200 ], [ "scratch", 10 ], { "type": "bite", "cooldown": 5 } ] + }, + { + "id": "mon_zamptosaurus_fungus", + "type": "MONSTER", + "name": { "str": "fungal Camptosaurus zombie" }, + "description": "Once a large feathered bipedal dinosaur with strong legs, broad shoulders and a pointed beak, fungal tendrils now sprout from its mouth, eyes, and other orifices, holding together an enormous shambling mass of mold-covered feathers.", + "copy-from": "mon_zamptosaurus", + "default_faction": "fungus", + "species": [ "FUNGUS" ], + "diff": 2, + "proportional": { "hp": 0.75, "speed": 0.65 }, + "color": "light_gray", + "relative": { "melee_skill": -1, "melee_dice": -1, "melee_dice_sides": 3, "armor_bash": 3 }, + "vision_day": 5, + "vision_night": 5, + "special_attacks": [ [ "FUNGUS", 200 ], [ "scratch", 10 ], { "type": "bite", "cooldown": 5 } ], + "upgrades": { }, + "flags": [ "SEES", "SMELLS", "POISON", "STUMBLES", "NO_BREATHE", "FILTHY", "WARM", "BASHES" ] + }, + { + "id": "mon_zaiasaura_fungus", + "type": "MONSTER", + "name": { "str": "fungal Maiasaura zombie" }, + "description": "Once a huge four legged plant eating dinosaur with hooves, a heavy tail, and a flat beak, fungal tendrils now sprout from its mouth, eyes, and other orifices, holding together a shambling mass of mold-covered flesh and bone.", + "copy-from": "mon_zamptosaurus_fungus", + "proportional": { "hp": 3 } + }, + { + "id": "mon_zarasaurolophus_fungus", + "type": "MONSTER", + "name": { "str": "fungal Parasaurolophus zombie" }, + "description": "Once a huge four legged plant eating dinosaur with a blunt head crest, fungal tendrils now sprout from its mouth, eyes, and other orifices, holding together a shambling mass of mold-covered flesh and bone.", + "copy-from": "mon_zamptosaurus_fungus", + "proportional": { "hp": 4 } + }, + { + "id": "mon_zorythosaurus_fungus", + "type": "MONSTER", + "name": { "str": "fungal Corythosaurus zombie" }, + "description": "Once a huge four legged plant eating dinosaur with a short beak and a tall head crest, fungal tendrils now sprout from its mouth, eyes, and other orifices, holding together a shambling mass of mold-covered flesh and bone.", + "copy-from": "mon_zamptosaurus_fungus", + "proportional": { "hp": 4 }, + "special_attacks": [ [ "FUNGUS", 200 ], [ "scratch", 10 ], { "type": "bite", "cooldown": 5 }, [ "SHRIEK", 5 ] ] + }, + { + "id": "mon_zedmontosaurus_fungus", + "type": "MONSTER", + "name": { "str": "fungal Edmontosaurus zombie" }, + "description": "Once a huge four legged plant eating dinosaur with a broad toothless beak, fungal tendrils now sprout from its mouth, eyes, and other orifices, holding together a shambling mass of mold-covered flesh and bone.", + "copy-from": "mon_zamptosaurus_fungus", + "proportional": { "hp": 5 } + }, + { + "id": "mon_zachycephalosaurus_fungus", + "type": "MONSTER", + "name": { "str": "fungal Pachycephalosaurus zombie" }, + "description": "Once a feathered bipedal dinosaur with a hard-looking domed head, fungal tendrils now sprout from its mouth, eyes, and other orifices, holding together a shambling mass of mold-covered feathers.", + "copy-from": "mon_zachycephalosaurus", + "default_faction": "fungus", + "species": [ "FUNGUS" ], + "diff": 2, + "proportional": { "hp": 0.75, "speed": 0.65 }, + "color": "light_gray", + "relative": { "melee_skill": -1, "melee_dice": -1, "melee_dice_sides": 3, "armor_bash": 3 }, + "vision_day": 5, + "vision_night": 5, + "special_attacks": [ [ "FUNGUS", 200 ], [ "scratch", 10 ], { "type": "bite", "cooldown": 5 } ], + "upgrades": { }, + "flags": [ "SEES", "SMELLS", "POISON", "STUMBLES", "NO_BREATHE", "FILTHY", "WARM", "PET_MOUNTABLE" ] + }, + { + "id": "mon_zachyrhinosaurus_fungus", + "type": "MONSTER", + "name": { "str": "fungal Pachyrhinosaurus zombie" }, + "description": "Once a massive four legged plant eating dinosaur with a tall bony crest from which four long horns and a short nose horn emerge, fungal tendrils now sprout from its mouth, eyes, and other orifices, holding together a shambling mass of mold-covered flesh.", + "copy-from": "mon_zriceratops_fungus", + "proportional": { "hp": 0.65 }, + "special_attacks": [ + [ "FUNGUS", 200 ], + { "id": "slam", "cooldown": 10, "damage_max_instance": [ { "damage_type": "bash", "amount": 12 } ] }, + [ "SMASH", 30 ] + ] + }, + { + "id": "mon_zentaceratops_fungus", + "type": "MONSTER", + "name": { "str": "fungal Pentaceraterror" }, + "description": "Once a massive four legged plant eating dinosaur with a tall bony crest from which four long horns and a short nose horn emerge, fungal tendrils now sprout from its mouth, eyes, and other orifices, holding together a shambling mass of mold-covered flesh.", + "copy-from": "mon_zriceratops_fungus", + "proportional": { "armor_bash": 2 } + }, + { + "id": "mon_zosmoceratops_fungus", + "type": "MONSTER", + "name": { "str": "fungal Kosmoceratops zombie" }, + "description": "Once a massive four legged plant eating dinosaur with a tall bony crest from which fifteen horns and spikes emerge, fungal tendrils now sprout from its mouth, eyes, and other orifices, holding together a shambling mass of mold-covered flesh.", + "copy-from": "mon_zriceratops_fungus", + "proportional": { "melee_dice": 2, "melee_cut": 0.65 } + }, + { + "id": "mon_zorosaurus_fungus", + "type": "MONSTER", + "name": { "str": "fungal Torosaurus zombie" }, + "description": "Once a massive four legged plant eating dinosaur with a tall bony crest from which two wicked looking horns emerge, fungal tendrils now sprout from its mouth, eyes, and other orifices, holding together a shambling mass of mold-covered flesh.", + "copy-from": "mon_zriceratops_fungus", + "proportional": { "melee_dice": 2, "melee_cut": 0.65 }, + "special_attacks": [ [ "FUNGUS", 200 ], { "id": "impale" }, [ "STRETCH_ATTACK", 5 ] ] + }, + { + "id": "mon_zriceratops_fungus", + "type": "MONSTER", + "name": { "str": "fungal Triceraterror" }, + "description": "Once a massive four legged plant eating dinosaur with a bony head crest from which three wicked looking horns emerge, fungal tendrils now sprout from its mouth, eyes, and other orifices, holding together a shambling mass of mold-covered flesh.", + "copy-from": "mon_zriceratops", + "default_faction": "fungus", + "species": [ "FUNGUS" ], + "diff": 2, + "proportional": { "hp": 0.75, "speed": 0.65 }, + "color": "light_gray", + "relative": { "melee_skill": -1, "melee_dice": -1, "melee_dice_sides": 3, "armor_bash": 3 }, + "vision_day": 5, + "vision_night": 5, + "special_attacks": [ [ "FUNGUS", 200 ], { "id": "impale" } ], + "upgrades": { }, + "flags": [ "SEES", "SMELLS", "POISON", "STUMBLES", "NO_BREATHE", "FILTHY", "WARM", "PET_MOUNTABLE", "BASHES" ] } ] From 7fd2aa1b90811b0fe1a672104fcd96b6d6ac8774 Mon Sep 17 00:00:00 2001 From: casswedson Date: Mon, 8 Mar 2021 21:19:54 -0500 Subject: [PATCH 264/453] misc typograpical fixes (#47953) --- data/mods/CRT_EXPANSION/deadspace/deadspaceitems.json | 2 +- data/mods/CRT_EXPANSION/items/crt_ammo.json | 2 +- data/mods/CRT_EXPANSION/items/crt_armor.json | 2 +- data/mods/CRT_EXPANSION/items/crt_gun.json | 2 +- data/mods/CRT_EXPANSION/items/crt_toolarmor.json | 10 +++++----- data/mods/CRT_EXPANSION/items/crt_tools.json | 2 +- data/mods/CRT_EXPANSION/martial/CRT_Bladework.json | 2 +- .../CRT_EXPANSION/mutations/crt_wendigo_mutations.json | 2 +- data/mods/CRT_EXPANSION/mutations/wendigo_mut_cat.json | 2 +- data/mods/CRT_EXPANSION/scenarios/crt_classes.json | 10 +++++----- data/mods/Generic_Guns/firearms/pistol.json | 2 +- data/mods/Generic_Guns/firearms/pistol_magnum.json | 4 ++-- data/mods/Generic_Guns/firearms/rifle.json | 2 +- data/mods/Generic_Guns/firearms/rifle_huge.json | 2 +- data/mods/Generic_Guns/magazines/rifle.json | 2 +- 15 files changed, 24 insertions(+), 24 deletions(-) diff --git a/data/mods/CRT_EXPANSION/deadspace/deadspaceitems.json b/data/mods/CRT_EXPANSION/deadspace/deadspaceitems.json index 943cd8b7731ce..6f646b8f256e9 100644 --- a/data/mods/CRT_EXPANSION/deadspace/deadspaceitems.json +++ b/data/mods/CRT_EXPANSION/deadspace/deadspaceitems.json @@ -39,7 +39,7 @@ "type": "ARMOR", "category": "armor", "name": "CRIT Engineering Suit", - "description": "An airtight, flexible suit of woven composite fibers complete with segmented plates of armor. A complex system digitizes items in an individual pocket universe for storage while built in joint-torsion ratchets generate the neccessary energy required to power the interface.", + "description": "An airtight, flexible suit of woven composite fibers complete with segmented plates of armor. A complex system digitizes items in an individual pocket universe for storage while built in joint-torsion ratchets generate the necessary energy required to power the interface.", "weight": "13460 g", "volume": "14 L", "price": 900000000, diff --git a/data/mods/CRT_EXPANSION/items/crt_ammo.json b/data/mods/CRT_EXPANSION/items/crt_ammo.json index b207d694a30e0..7fa03d67f224a 100644 --- a/data/mods/CRT_EXPANSION/items/crt_ammo.json +++ b/data/mods/CRT_EXPANSION/items/crt_ammo.json @@ -47,7 +47,7 @@ "copy-from": "pellet", "type": "AMMO", "name": { "str_sp": "alloy pellets" }, - "description": "An gimmicky alloy pellet with the purpose of reaching a higher velocity than a normal lead pellet for breaking the sound barrier resulting in an extremely loud crack, not so useful for stealth.", + "description": "A gimmicky alloy pellet with the purpose of reaching a higher velocity than a normal lead pellet for breaking the sound barrier resulting in an extremely loud crack, not so useful for stealth.", "material": [ "steel" ], "symbol": "=", "color": "dark_gray", diff --git a/data/mods/CRT_EXPANSION/items/crt_armor.json b/data/mods/CRT_EXPANSION/items/crt_armor.json index ecc0eb6c43e57..2f6d322632d9b 100644 --- a/data/mods/CRT_EXPANSION/items/crt_armor.json +++ b/data/mods/CRT_EXPANSION/items/crt_armor.json @@ -261,7 +261,7 @@ "type": "ARMOR", "category": "armor", "name": { "str": "pair of CRIT Enforcer docks", "str_pl": "pairs of CRIT Enforcer docks" }, - "description": "CRIT Enforcer docks. Metal plates vaguely molded into the shape of oversized feet which clamp down onto your own footwear keep your feet out of harms way. It looks terrible and feels clunky unlike most of C.R.I.T's designs, but they do seem to be worth using if you were to be in the middle of a warzone.", + "description": "CRIT Enforcer docks. Metal plates vaguely molded into the shape of oversized feet which clamp down onto your own footwear keep your feet out of harms way. It looks terrible and feels clunky unlike most of C.R.I.T's designs, but they do seem to be worth using if you were to be in the middle of a war zone.", "weight": "2060 g", "volume": "1500 ml", "price": 100000, diff --git a/data/mods/CRT_EXPANSION/items/crt_gun.json b/data/mods/CRT_EXPANSION/items/crt_gun.json index 29500fede4f49..b645c14f8f931 100644 --- a/data/mods/CRT_EXPANSION/items/crt_gun.json +++ b/data/mods/CRT_EXPANSION/items/crt_gun.json @@ -252,7 +252,7 @@ "id": "ds_rivet_gun", "type": "GUN", "name": "Rivet Driver", - "description": "Experimental double purpose tool under development in C.R.I.T R&D. It takes a regular nail and then enlongates it within a fraction of a second before firing it out, upon reaching a target, the fragile stake explodes into shards inside the target.", + "description": "Experimental double purpose tool under development in C.R.I.T R&D. It takes a regular nail and then elongates it within a fraction of a second before firing it out, upon reaching a target, the fragile stake explodes into shards inside the target.", "weight": "1650 g", "volume": "750 ml", "price": 1000000, diff --git a/data/mods/CRT_EXPANSION/items/crt_toolarmor.json b/data/mods/CRT_EXPANSION/items/crt_toolarmor.json index b1666136f844e..228154a7b7f4c 100644 --- a/data/mods/CRT_EXPANSION/items/crt_toolarmor.json +++ b/data/mods/CRT_EXPANSION/items/crt_toolarmor.json @@ -3,8 +3,8 @@ "id": "crt_gasmask", "type": "TOOL_ARMOR", "category": "armor", - "name": { "str": "CRIT gasmask (off)", "str_pl": "CRIT gasmasks (off)" }, - "description": "This is a heavily modified Spec Ops modified gasmask, fitted with top-of-the-line electronics and lined with Kevlar for extra protection in order to keep one's head where it should be. Various filters and other high tech wizardry allow for enhanced oxygen intake and safety even under bombardment. It has an integrated HUD and the option to turn it on for more features.", + "name": { "str": "CRIT gas mask (off)", "str_pl": "CRIT gas masks (off)" }, + "description": "This is a heavily modified Spec Ops modified gas mask, fitted with top-of-the-line electronics and lined with Kevlar for extra protection in order to keep one's head where it should be. Various filters and other high tech wizardry allow for enhanced oxygen intake and safety even under bombardment. It has an integrated HUD and the option to turn it on for more features.", "weight": "5 kg", "volume": "1 L", "price": 2500000, @@ -45,8 +45,8 @@ "id": "crt_gasmask_on", "type": "TOOL_ARMOR", "category": "armor", - "name": { "str": "CRIT gasmask (on)", "str_pl": "CRIT gasmasks (on)" }, - "description": "This a heavily modified gasmask. It is currently on and draining power for the HUD, low-level nightvision and other protective elements.", + "name": { "str": "CRIT gas mask (on)", "str_pl": "CRIT gas masks (on)" }, + "description": "This a heavily modified gas mask. It is currently on and draining power for the HUD, low-level night vision and other protective elements.", "weight": "5 kg", "volume": "1 L", "price": 2500000, @@ -88,7 +88,7 @@ "type": "TOOL_ARMOR", "category": "armor", "name": { "str": "CRIT EM vest (off)", "str_pl": "CRIT EM vests (off)" }, - "description": "The Enhanced Movement vest is embedded with high-tech filaments and reactive servos which protects its wearer and assists in movement at the cost high power usage. It is commonly worn by C.R.I.T Spec Ops for its ease of use and manuverability. Turn it on for suit mode, extra protection and movement.", + "description": "The Enhanced Movement vest is embedded with high-tech filaments and reactive servos which protects its wearer and assists in movement at the cost high power usage. It is commonly worn by C.R.I.T Spec Ops for its ease of use and maneuverability. Turn it on for suit mode, extra protection and movement.", "weight": "10 kg", "volume": "6250 ml", "price": 7000000, diff --git a/data/mods/CRT_EXPANSION/items/crt_tools.json b/data/mods/CRT_EXPANSION/items/crt_tools.json index d98d70f31e0ea..d01795aa7d2b3 100644 --- a/data/mods/CRT_EXPANSION/items/crt_tools.json +++ b/data/mods/CRT_EXPANSION/items/crt_tools.json @@ -63,7 +63,7 @@ "type": "TOOL", "category": "weapons", "name": "CRIT Reso-blade", - "description": "CRIT melee weapon. Alien runes adorn the carbon steel blade. The blade oddly seems to lack sharpness, and yet upon closer oberservation, a hum of energy thrums from within.", + "description": "CRIT melee weapon. Alien runes adorn the carbon steel blade. The blade oddly seems to lack sharpness, and yet upon closer inspection, a hum of energy thrums from within.", "color": "dark_gray", "material": [ "hardsteel" ], "//": "Legacy artifact data is set for always on wield dex +2 and speed up times 2", diff --git a/data/mods/CRT_EXPANSION/martial/CRT_Bladework.json b/data/mods/CRT_EXPANSION/martial/CRT_Bladework.json index 751e3c3d2fc7d..75efd9a3e449c 100644 --- a/data/mods/CRT_EXPANSION/martial/CRT_Bladework.json +++ b/data/mods/CRT_EXPANSION/martial/CRT_Bladework.json @@ -16,7 +16,7 @@ "type": "martial_art", "id": "style_crt_blade", "name": "CRIT Blade-work", - "description": "An offensive style centered around rapid slashes and prodding. Each attack landed increases combat ability but leaves you increasingly vunerable", + "description": "An offensive style centered around rapid slashes and prodding. Each attack landed increases combat ability but leaves you increasingly vulnerable", "initiate": [ "You prepare to whittle down your enemies.", "%s initiates blade-work." ], "arm_block": 99, "leg_block": 99, diff --git a/data/mods/CRT_EXPANSION/mutations/crt_wendigo_mutations.json b/data/mods/CRT_EXPANSION/mutations/crt_wendigo_mutations.json index db237d5336376..87efffb5b22a9 100644 --- a/data/mods/CRT_EXPANSION/mutations/crt_wendigo_mutations.json +++ b/data/mods/CRT_EXPANSION/mutations/crt_wendigo_mutations.json @@ -14,7 +14,7 @@ "id": "NMELD", "name": "Nature's Boon", "points": 3, - "description": "Your very prescence is masked by nature itself. You are slightly harder to detect.", + "description": "Your very presence is masked by nature itself. You are slightly harder to detect.", "valid": false, "purifiable": false, "prereqs": [ "WEAKSCENT" ], diff --git a/data/mods/CRT_EXPANSION/mutations/wendigo_mut_cat.json b/data/mods/CRT_EXPANSION/mutations/wendigo_mut_cat.json index 1cf8a61f0880b..3ba2aa896727e 100644 --- a/data/mods/CRT_EXPANSION/mutations/wendigo_mut_cat.json +++ b/data/mods/CRT_EXPANSION/mutations/wendigo_mut_cat.json @@ -28,7 +28,7 @@ "copy-from": "iv_mutagen_flavor", "type": "COMESTIBLE", "name": "wendigo serum", - "description": "A super-concentrated peat-brown substance with glittering green flecks that reminds you of a a tree. You need a syringe to inject it… if you really want to?", + "description": "A super-concentrated peat-brown substance with glittering green flecks that reminds you of a tree. You need a syringe to inject it… if you really want to?", "color": "light_gray", "healthy": -2, "use_action": { "type": "mutagen_iv", "mutation_category": "WENDIGO" } diff --git a/data/mods/CRT_EXPANSION/scenarios/crt_classes.json b/data/mods/CRT_EXPANSION/scenarios/crt_classes.json index 89f6d4d92a68a..041172c84f5a0 100644 --- a/data/mods/CRT_EXPANSION/scenarios/crt_classes.json +++ b/data/mods/CRT_EXPANSION/scenarios/crt_classes.json @@ -32,7 +32,7 @@ "type": "profession", "id": "crt_dude", "name": "CRIT Janitor", - "description": "*Sigh* Your life has been a wreck. Hopping place to place you finally found a job at C.R.I.T… as a janitor of sorts. The pay was good and you got some sneak-peeks on some pretty cool stuff. After all non-essential personel were purged you found yourself stuck with nothing but the uniform they gave you and your job's sign-bonus equipment.", + "description": "*Sigh* Your life has been a wreck. Hopping place to place you finally found a job at C.R.I.T… as a janitor of sorts. The pay was good and you got some sneak-peeks on some pretty cool stuff. After all non-essential personnel were purged you found yourself stuck with nothing but the uniform they gave you and your job's sign-bonus equipment.", "points": 6, "skills": [ { "level": 2, "name": "tailor" }, @@ -112,7 +112,7 @@ "type": "profession", "id": "crt_rifleman", "name": "CRIT Grunt", - "description": "You were part of the infantry; first to hit the ground running, clear a FOB and then come back to relax with your squad. Those days ended when the cataclysm reared its ugly head. Your lines were torn through like wet paper when the otherworldy abominations arived. Now fleeing for your life, will you have what it takes to survive or is this hellish landcape your resting place?", + "description": "You were part of the infantry; first to hit the ground running, clear a FOB and then come back to relax with your squad. Those days ended when the cataclysm reared its ugly head. Your lines were torn through like wet paper when the otherworldly abominations arrived. Now fleeing for your life, will you have what it takes to survive or is this hellish landscape your resting place?", "points": 8, "traits": [ "MARTIAL_CRT" ], "skills": [ { "level": 3, "name": "gun" }, { "level": 3, "name": "rifle" }, { "level": 1, "name": "stabbing" } ], @@ -199,7 +199,7 @@ "type": "profession", "id": "crt_saw", "name": "CRIT Automatic Rifleman", - "description": "You were assigned the billet of specializing in creating dead zones and providing support fire. When the cataclysm struck, your trusty LMG couldn't keep the veritable tide of undead from overtaking your squad. Now running with all the strength your body can muster, will you have what it takes to survive or is this hellish landcape something you just can't suppress?", + "description": "You were assigned the billet of specializing in creating dead zones and providing support fire. When the cataclysm struck, your trusty LMG couldn't keep the veritable tide of undead from overtaking your squad. Now running with all the strength your body can muster, will you have what it takes to survive or is this hellish landscape something you just can't suppress?", "points": 10, "traits": [ "MARTIAL_CRT" ], "skills": [ { "level": 3, "name": "gun" }, { "level": 3, "name": "rifle" }, { "level": 1, "name": "pistol" } ], @@ -332,7 +332,7 @@ "type": "profession", "id": "crt_juggernaught", "name": "CRIT Lone Wolf", - "description": "STR 10 recommended. You are fully armored badass granted the full authority of a U.S Marshal. Sent in as the one man army capable of handling anything. Dropped into warzones, you singlehandedly laid out entire battalions by yourself. Time to hang them all.", + "description": "STR 10 recommended. You are fully armored badass granted the full authority of a U.S Marshal. Sent in as the one man army capable of handling anything. Dropped into war zones, you singlehandedly laid out entire battalions by yourself. Time to hang them all.", "traits": [ "MARTIAL_CRT", "PROF_FED" ], "CBMs": [ "bio_weight", @@ -664,7 +664,7 @@ "type": "profession", "id": "crt_vamp", "name": "CRIT Night Walker", - "description": "Your base in New England fell to the unholy onslaught of the Cataclysm. However, as a a top researcher in the R&D department, you had chosen to slowly mutate yourself into something more than human. Even if the concotion was less than perfect, your old flimsy body feels empowered. With the new flesh that is now your own, bare your fangs and fight until the next dawn.", + "description": "Your base in New England fell to the unholy onslaught of the Cataclysm. However, as a top researcher in the R&D department, you had chosen to slowly mutate yourself into something more than human. Even if the concoction was less than perfect, your old flimsy body feels empowered. With the new flesh that is now your own, bare your fangs and fight until the next dawn.", "traits": [ "MARTIAL_CRT", "THRESH_VAMP", diff --git a/data/mods/Generic_Guns/firearms/pistol.json b/data/mods/Generic_Guns/firearms/pistol.json index 7a69b3b076ab1..fe459c467a140 100644 --- a/data/mods/Generic_Guns/firearms/pistol.json +++ b/data/mods/Generic_Guns/firearms/pistol.json @@ -15,7 +15,7 @@ "type": "GUN", "name": { "str": "machine pistol" }, "ammo": [ "ammo_pistol" ], - "description": "This pistol is a tiny machinegun you can stuff into a holster, with which you could dump its magazine at a blistering rate into any close range foes. Machine pistols mostly see use by vehicle crewmen or bodygaurds of VIPs. Due to its preposterous rate of fire it is difficult to control.", + "description": "This pistol is a tiny machinegun you can stuff into a holster, with which you could dump its magazine at a blistering rate into any close range foes. Machine pistols mostly see use by vehicle crewmen or bodyguards of VIPs. Due to its preposterous rate of fire it is difficult to control.", "pocket_data": [ { "pocket_type": "MAGAZINE_WELL", diff --git a/data/mods/Generic_Guns/firearms/pistol_magnum.json b/data/mods/Generic_Guns/firearms/pistol_magnum.json index 58b5fb14f5f09..e9c3e018c6bd2 100644 --- a/data/mods/Generic_Guns/firearms/pistol_magnum.json +++ b/data/mods/Generic_Guns/firearms/pistol_magnum.json @@ -6,7 +6,7 @@ "name": { "str": "hand cannon" }, "ammo": [ "ammo_pistol", "ammo_pistol_magnum" ], "//": "We're just going to prtend that .357 and .44 magnum deagles will run .38's and .44 special just fine", - "description": "This large pistol is almost as heavy as a small carbine, and just about as powerful too. Chambered in hard hitting magnum calibers, it is suitable for hunting medium game, humans, or offsetting any of one's perceived deficiencies. Though tradtionally such magnums are revolvers, this one is a magazine fed semi-automatic.", + "description": "This large pistol is almost as heavy as a small carbine, and just about as powerful too. Chambered in hard hitting magnum calibers, it is suitable for hunting medium game, humans, or offsetting any of one's perceived deficiencies. Though traditionally such magnums are revolvers, this one is a magazine fed semi-automatic.", "pocket_data": [ { "pocket_type": "MAGAZINE_WELL", @@ -34,7 +34,7 @@ "type": "GUN", "name": { "str": "handmade magnum carbine" }, "ammo": [ "ammo_pistol_magnum", "ammo_pistol" ], - "description": "A crudely constructed carbine, chambered for magnum pistol ammo and standard pistol ammo. It feeds from commerical magnum pistol magazines, and locks with a rudimentary lever action system. Its powerful cartridge and relative precision should serve well against zombies and medium game.", + "description": "A crudely constructed carbine, chambered for magnum pistol ammo and standard pistol ammo. It feeds from commercial magnum pistol magazines, and locks with a rudimentary lever action system. Its powerful cartridge and relative precision should serve well against zombies and medium game.", "weight": "2114 g", "volume": "2 L", "price": 10000, diff --git a/data/mods/Generic_Guns/firearms/rifle.json b/data/mods/Generic_Guns/firearms/rifle.json index 4870b21236a9d..80ef35b8a6516 100644 --- a/data/mods/Generic_Guns/firearms/rifle.json +++ b/data/mods/Generic_Guns/firearms/rifle.json @@ -59,7 +59,7 @@ "type": "GUN", "name": "sporter carbine", "ammo": [ "ammo_rifle" ], - "description": "Though often mislabeled an asssault rifle, this common, cheap magazine fed carbine isn't capable of automatic fire. While almost as effective as a proper rifle, the wider variety of components and varying levels of maintenance make these less reliable than their military brethren. These rifles are just as adequate for taking on anything smaller than large game, however.", + "description": "Though often mislabeled an assault rifle, this common, cheap magazine fed carbine isn't capable of automatic fire. While almost as effective as a proper rifle, the wider variety of components and varying levels of maintenance make these less reliable than their military brethren. These rifles are just as adequate for taking on anything smaller than large game, however.", "pocket_data": [ { "pocket_type": "MAGAZINE_WELL", diff --git a/data/mods/Generic_Guns/firearms/rifle_huge.json b/data/mods/Generic_Guns/firearms/rifle_huge.json index b3773574befc9..51c386db8255f 100644 --- a/data/mods/Generic_Guns/firearms/rifle_huge.json +++ b/data/mods/Generic_Guns/firearms/rifle_huge.json @@ -23,7 +23,7 @@ "type": "GUN", "name": { "str": "elephant rifle" }, "ammo": [ "ammo_rifle_huge" ], - "description": "Elegantly engraved, with deep glossy blued steel and figured wood, this break-action double rifle is almost too nice to shoot. Your shoulder might beg you not to; the chambers are almost wide enough for two fingers and the recoil is monstruous. You could probably kill anything with this, especially if you were to fire both barrels at once.", + "description": "Elegantly engraved, with deep glossy blued steel and figured wood, this break-action double rifle is almost too nice to shoot. Your shoulder might beg you not to; the chambers are almost wide enough for two fingers and the recoil is monstrous. You could probably kill anything with this, especially if you were to fire both barrels at once.", "modes": [ [ "DEFAULT", "single", 1 ], [ "DOUBLE", "double", 2 ] ], "extend": { "flags": [ "RELOAD_ONE" ] }, "clip_size": 2, diff --git a/data/mods/Generic_Guns/magazines/rifle.json b/data/mods/Generic_Guns/magazines/rifle.json index ac8667a01e991..c2e1553b397ad 100644 --- a/data/mods/Generic_Guns/magazines/rifle.json +++ b/data/mods/Generic_Guns/magazines/rifle.json @@ -18,7 +18,7 @@ "type": "MAGAZINE", "material": [ "aluminum" ], "name": "standard rifle magazine", - "description": "A 30 round standard capacity magazine for service rifles, cheaper than the cost of a meal due to its adoption by nearly every other common rifle. They're made of aluminum and were originally meant to be dispsoable, so they're not the most durable; don't let them get damaged.", + "description": "A 30 round standard capacity magazine for service rifles, cheaper than the cost of a meal due to its adoption by nearly every other common rifle. They're made of aluminum and were originally meant to be disposable, so they're not the most durable; don't let them get damaged.", "volume": "500 ml", "ammo_type": [ "ammo_rifle" ], "pocket_data": [ { "pocket_type": "MAGAZINE", "ammo_restriction": { "ammo_rifle": 30 }, "rigid": true } ] From 02c401e3d28b97982ba5897a5f9a18a7b4843119 Mon Sep 17 00:00:00 2001 From: OromisElf Date: Tue, 9 Mar 2021 12:04:12 +0100 Subject: [PATCH 265/453] body pillow recipe makes makeshift body pillow now (#47917) --- data/json/items/generic.json | 9 +++++++++ data/json/recipes/recipe_obsolete.json | 5 +++++ data/json/recipes/recipe_others.json | 2 +- 3 files changed, 15 insertions(+), 1 deletion(-) diff --git a/data/json/items/generic.json b/data/json/items/generic.json index 4d2c75ea1a39a..d608f53aa1719 100644 --- a/data/json/items/generic.json +++ b/data/json/items/generic.json @@ -2400,6 +2400,15 @@ "flags": [ "SLEEP_AID" ], "category": "other" }, + { + "type": "GENERIC", + "id": "bodypillow_makeshift", + "copy-from": "bodypillow", + "name": { "str": "makeshift body pillow" }, + "description": "A big, body-sized pillow. Someone drew a vaguely humanoid figure on it. Its heartwarming smile fills you with joy.", + "price": 100, + "price_postapoc": 50 + }, { "type": "GENERIC", "id": "down_pillow", diff --git a/data/json/recipes/recipe_obsolete.json b/data/json/recipes/recipe_obsolete.json index 40b4b52c04c91..9c56edb33c045 100644 --- a/data/json/recipes/recipe_obsolete.json +++ b/data/json/recipes/recipe_obsolete.json @@ -2777,5 +2777,10 @@ "type": "recipe", "result": "rifle_223", "obsolete": true + }, + { + "type": "recipe", + "result": "bodypillow", + "obsolete": true } ] diff --git a/data/json/recipes/recipe_others.json b/data/json/recipes/recipe_others.json index 3f3fb8664bdc4..4886c50cb5789 100644 --- a/data/json/recipes/recipe_others.json +++ b/data/json/recipes/recipe_others.json @@ -56,7 +56,7 @@ { "type": "recipe", "activity_level": "LIGHT_EXERCISE", - "result": "bodypillow", + "result": "bodypillow_makeshift", "category": "CC_OTHER", "subcategory": "CSC_OTHER_OTHER", "skill_used": "tailor", From 9fcc6a5d0940833d2e9a26e787fcf5988ec3778a Mon Sep 17 00:00:00 2001 From: Maleclypse <54345792+Maleclypse@users.noreply.github.com> Date: Sun, 14 Mar 2021 15:36:34 -0500 Subject: [PATCH 266/453] Traffic Bollards and an example of deployment (#48017) --- .../furniture_and_terrain/terrain-walls.json | 20 +++++++++++++++ data/json/mapgen/sub_station.json | 2 +- data/json/mapgen_palettes/subway.json | 1 + .../Magiclysm/worldgen/forge_of_wonders.json | 25 ++++++++++--------- 4 files changed, 35 insertions(+), 13 deletions(-) diff --git a/data/json/furniture_and_terrain/terrain-walls.json b/data/json/furniture_and_terrain/terrain-walls.json index 69f2cb631d5d0..69cc70c69b254 100644 --- a/data/json/furniture_and_terrain/terrain-walls.json +++ b/data/json/furniture_and_terrain/terrain-walls.json @@ -1352,6 +1352,26 @@ "items": [ { "item": "rock", "count": [ 10, 22 ] } ] } }, + { + "type": "terrain", + "id": "t_bollard", + "name": "bollard", + "looks_like": "t_fence_post", + "description": "A set of concrete and steel bollards designed to harden areas against vehicle ram attacks. It requires a few more steps to walk in between the bollards sticking up out of the ground.", + "symbol": "1", + "color": "light_gray", + "move_cost": 6, + "coverage": 20, + "flags": [ "WALL", "PERMEABLE" ], + "bash": { + "str_min": 350, + "str_max": 650, + "sound": "crash!", + "sound_fail": "whump!", + "ter_set": "t_sidewalk", + "items": [ { "item": "rock", "count": [ 6, 13 ] }, { "item": "steel_chunk", "count": [ 1, 3 ] } ] + } + }, { "type": "terrain", "id": "t_support_l", diff --git a/data/json/mapgen/sub_station.json b/data/json/mapgen/sub_station.json index 200c1be0667f0..8e345e70aa6ba 100644 --- a/data/json/mapgen/sub_station.json +++ b/data/json/mapgen/sub_station.json @@ -8,7 +8,7 @@ "fill_ter": "t_thconc_floor", "rows": [ "SSSSSSSSSSSSSSSSSSSSSSSS", - "SSSSSSSSSSSSSSSSSSSSSSSS", + "SSSttttttttttttttttttSSS", "SS||-;;-||-;;-||-;;-||SS", "SS| | | |SS", "SS| |SS", diff --git a/data/json/mapgen_palettes/subway.json b/data/json/mapgen_palettes/subway.json index 1502b7ebaad56..7c7ec2270d7f6 100644 --- a/data/json/mapgen_palettes/subway.json +++ b/data/json/mapgen_palettes/subway.json @@ -8,6 +8,7 @@ "-": "t_wall_glass", ";": "t_door_glass_c", "S": "t_sidewalk", + "t": "t_bollard", "*": "t_region_shrub_decorative", ">": "t_stairs_down", "<": "t_stairs_up", diff --git a/data/mods/Magiclysm/worldgen/forge_of_wonders.json b/data/mods/Magiclysm/worldgen/forge_of_wonders.json index e5681b712e32c..cf7833a7587e7 100644 --- a/data/mods/Magiclysm/worldgen/forge_of_wonders.json +++ b/data/mods/Magiclysm/worldgen/forge_of_wonders.json @@ -23,25 +23,25 @@ "rows": [ " T 2 ++++++ 2 ", " T +++++++ Y ", - " Y ++++++++ T ", + " Y 55555555 T ", " +++++++ ", " ########||||#########################||&&&&&&&||###############||||##############||||############### ", " #..................................##...........##............................4............4.......# ", - " #..4.@.@...........................##...........##..................XXXXXXXXXXXXXXXXXXXXXXXXXXXXXX.# ", - " #...fffff.................2........##...........##..................X$$$$$$$$$$$$$$$$$$$$$$$$$$$$X.# ", - " #...fffff..........................##...........##..................#$$$$$$$$$$$$$$$$$$$$$$$$$$$$X.# ", - " #....@.@.........................................................XXX#$$$$$$$$$$$$$$$$$$$$$$$$$$$$X.| ", - " #........................................44......................X94#$$$$$$$$$$$$$$$$$$$$$$$$$$$$X.| ", - " #............4...........................44......................X89#$$$$$$$$$$$$$$$$$$$$$$$$$$$$X.| ", - " #................................................................X94#$$$$$$$$$$$$$$$$$$$$$$$$$$$$X.| ", - " #...........@.@..................................................XXX#$$$$$$$$$$$$$$$$$$$$$$$$$$$$X.| ", - " #.........zZZZZZ....................................................#$$$$$$$$$$$$$$$$$$$$$$$$$$$$X.# ", + " #..4.@.@...........................##...........##............5.....XXXXXXXXXXXXXXXXXXXXXXXXXXXXXX.# ", + " #...fffff.................2........##...........##.............5....X$$$$$$$$$$$$$$$$$$$$$$$$$$$$X.# ", + " #...fffff..........................##...........##............5.....#$$$$$$$$$$$$$$$$$$$$$$$$$$$$X.# ", + " #....@.@.......................................................5.XXX#$$$$$$$$$$$$$$$$$$$$$$$$$$$$X.| ", + " #........................................44...................5..X94#$$$$$$$$$$$$$$$$$$$$$$$$$$$$X.| ", + " #............4...........................44....................5.X89#$$$$$$$$$$$$$$$$$$$$$$$$$$$$X.| ", + " #.............................................................5..X94#$$$$$$$$$$$$$$$$$$$$$$$$$$$$X.| ", + " #...........@.@................................................5.XXX#$$$$$$$$$$$$$$$$$$$$$$$$$$$$X.| ", + " #.........zZZZZZ..............................................5.....#$$$$$$$$$$$$$$$$$$$$$$$$$$$$X.# ", " #..........ZZZZZz...................................##...........##.X$$$$$$$$$$$$$$$$$$$$$$$$$$$$X.# ", " |...........@.@............4...................2....##...........##.XXXXXXXXXXXXXXXXXXXXXXXXXXXXXX.# ", " |...................................................##...........##.....4...............4..........# ", " |...................................#####|||##########||&&&&&&&||##################|||############## ", " |...................................# +++++++ ", - " |...................................# ++++++++ 2 ", + " |...................................# 55555555 2 ", " #...................................# 2 +++++++ ", " #.......................4...........# ++++++++ 2 ", " #...................................# ++++++++ Y ", @@ -113,7 +113,8 @@ "9": "t_vault_vent", "2": "t_strconc_floor", "4": "t_thconc_floor_echandelier", - "+": "t_railroad_rubble" + "+": "t_railroad_rubble", + "5": "t_bollard" }, "furniture": { "h": "f_demon_forge", From c3218bdf3a1513bfeff3f316b6b9cba23471b0c2 Mon Sep 17 00:00:00 2001 From: akirashirosawa <38557723+akirashirosawa@users.noreply.github.com> Date: Sun, 14 Mar 2021 10:49:46 +0300 Subject: [PATCH 267/453] add description for Uyen's missions (#48026) --- .../surface_refugees/NPC_Uyen_Tran.json | 11 ++++++----- 1 file changed, 6 insertions(+), 5 deletions(-) diff --git a/data/json/npcs/refugee_center/surface_refugees/NPC_Uyen_Tran.json b/data/json/npcs/refugee_center/surface_refugees/NPC_Uyen_Tran.json index 0653bd650cbe7..5d87f6d91f973 100644 --- a/data/json/npcs/refugee_center/surface_refugees/NPC_Uyen_Tran.json +++ b/data/json/npcs/refugee_center/surface_refugees/NPC_Uyen_Tran.json @@ -157,9 +157,8 @@ { "id": "MISSION_REFUGEE_Uyen_1", "type": "mission_definition", - "name": { - "str": "Find 50 doses of antiseptic for Uyen Tran in the refugee center, in exchange for Merch." - }, + "name": { "str": "Find 50 doses of antiseptic" }, + "description": "Find 50 doses of antiseptic for Uyen Tran in the refugee center, in exchange for Merch.", "goal": "MGOAL_FIND_ITEM", "difficulty": 2, "value": 0, @@ -189,7 +188,8 @@ { "id": "MISSION_REFUGEE_Uyen_2", "type": "mission_definition", - "name": { "str": "Find 30 bandages for Uyen Tran in the refugee center, in exchange for Merch." }, + "name": { "str": "Find 30 bandages" }, + "description": "Find 30 bandages for Uyen Tran in the refugee center, in exchange for Merch.", "goal": "MGOAL_FIND_ITEM", "difficulty": 2, "value": 0, @@ -219,7 +219,8 @@ { "id": "MISSION_REFUGEE_Uyen_3", "type": "mission_definition", - "name": { "str": "Find 6 bottles of Prozac for Uyen Tran in the refugee center, in exchange for Merch." }, + "name": { "str": "Find 6 bottles of Prozac" }, + "description": "Find 6 bottles of Prozac for Uyen Tran in the refugee center, in exchange for Merch.", "goal": "MGOAL_FIND_ITEM", "difficulty": 2, "value": 0, From 66b6ea46beea82ec76f411572a0b830801d53bb4 Mon Sep 17 00:00:00 2001 From: anothersimulacrum Date: Sun, 14 Mar 2021 13:46:12 -0700 Subject: [PATCH 268/453] JSONize some trap features, replace trap int_id externs with string_ids (#47933) * JSONize trap sonar detectibility Add trap flags - just the same as normal flags, but for traps! Stick them in their own separate file to avoid confusion. * JSONize trap memorial messages light_snare and heavy_snare seem to no longer exist, or I couldn't find any reference to them but this and tilesets. Updated dissector trap message, and added a trap message to some traps (the hallway ones, one or two of the similar-but-not-the-same variants of existing traps). * JSONize trap temperature convection Not quite sure how to describe it, went the lazy route. * Move traps externs from int to string ids When loading the game without this content, these will now only give an error on the use of these, instead of at the end data loading for traps. Previously there were performance concerns with this, but this should be fine since #44261 - see #44500. tr_null must remain an int id, as it used in the string to int id conversion. This is fine, as it will always be loaded (it's in data/core). Move the ledge trap over to data/core as well, because everything will need the 'open space' trap. --- data/core/traps.json | 17 ++++++ data/json/flags/trap.json | 12 ++++ data/json/traps.json | 78 ++++++++++++++++++++++---- doc/JSON_FLAGS.md | 4 ++ doc/JSON_INFO.md | 1 + src/game.cpp | 3 +- src/memorial_logger.cpp | 114 +------------------------------------- src/trap.cpp | 85 ++++++++++++---------------- src/trap.h | 66 ++++++++++++++-------- 9 files changed, 184 insertions(+), 196 deletions(-) create mode 100644 data/core/traps.json create mode 100644 data/json/flags/trap.json diff --git a/data/core/traps.json b/data/core/traps.json new file mode 100644 index 0000000000000..da83ec74d9697 --- /dev/null +++ b/data/core/traps.json @@ -0,0 +1,17 @@ +[ + { + "//": "We're always going to need a 'nothing here' tile, we currently use traps for this.", + "type": "trap", + "id": "tr_ledge", + "name": "ledge", + "color": "i_cyan", + "memorial_male": { "ctxt": "memorial_female", "str": "Fell down a ledge." }, + "memorial_female": { "ctxt": "memorial_female", "str": "Fell down a ledge." }, + "symbol": " ", + "visibility": 0, + "avoidance": 99999, + "difficulty": 99, + "action": "ledge", + "vehicle_data": { "is_falling": true } + } +] diff --git a/data/json/flags/trap.json b/data/json/flags/trap.json new file mode 100644 index 0000000000000..f213b6d193ef2 --- /dev/null +++ b/data/json/flags/trap.json @@ -0,0 +1,12 @@ +[ + { + "type": "json_flag", + "id": "SONAR_DETECTABLE", + "context": [ ] + }, + { + "type": "json_flag", + "id": "CONVECTS_TEMPERATURE", + "context": [ ] + } +] diff --git a/data/json/traps.json b/data/json/traps.json index 0cfb8c4e069db..d48d932157a79 100644 --- a/data/json/traps.json +++ b/data/json/traps.json @@ -4,6 +4,8 @@ "id": "tr_bubblewrap", "name": "bubble wrap", "color": "light_cyan", + "memorial_male": { "ctxt": "memorial_male", "str": "Stepped on bubble wrap." }, + "memorial_female": { "ctxt": "memorial_female", "str": "Stepped on bubble wrap." }, "symbol": "_", "visibility": 0, "avoidance": 8, @@ -17,6 +19,8 @@ "id": "tr_glass", "name": "glass shards", "color": "light_cyan", + "memorial_male": { "ctxt": "memorial_male", "str": "Stepped on glass." }, + "memorial_female": { "ctxt": "memorial_female", "str": "Stepped on glass." }, "symbol": "_", "visibility": 6, "avoidance": 8, @@ -103,6 +107,8 @@ "id": "tr_microlab_shifting_hall", "name": "microlab shifting hall", "color": "brown", + "memorial_male": { "ctxt": "memorial_male", "str": "Triggered a dimensional anomaly." }, + "memorial_female": { "ctxt": "memorial_female", "str": "Triggered a dimensional anomaly." }, "symbol": ".", "visibility": 99, "avoidance": 99, @@ -116,6 +122,8 @@ "id": "tr_microlab_shifting_hall_2", "name": "microlab shifting hall", "color": "brown", + "memorial_male": { "ctxt": "memorial_male", "str": "Triggered a dimensional anomaly." }, + "memorial_female": { "ctxt": "memorial_female", "str": "Triggered a dimensional anomaly." }, "symbol": ".", "visibility": 99, "avoidance": 99, @@ -130,6 +138,8 @@ "trigger_weight": "200 g", "name": "bear trap", "color": "blue", + "memorial_male": { "ctxt": "memorial_male", "str": "Caught by a beartrap." }, + "memorial_female": { "ctxt": "memorial_female", "str": "Caught by a beartrap." }, "symbol": "^", "visibility": 2, "avoidance": 7, @@ -152,12 +162,15 @@ "trigger_weight": "200 g", "name": "buried bear trap", "color": "blue", + "memorial_male": { "ctxt": "memorial_male", "str": "Caught by a beartrap." }, + "memorial_female": { "ctxt": "memorial_female", "str": "Caught by a beartrap." }, "symbol": "^", "visibility": 9, "avoidance": 8, "difficulty": 4, "action": "beartrap", "drops": [ "beartrap" ], + "flags": [ "SONAR_DETECTABLE" ], "vehicle_data": { "damage": 300, "sound_volume": 8, @@ -173,6 +186,8 @@ "id": "tr_nailboard", "name": "spiked board", "color": "light_gray", + "memorial_male": { "ctxt": "memorial_male", "str": "Stepped on a spiked board." }, + "memorial_female": { "ctxt": "memorial_female", "str": "Stepped on a spiked board." }, "symbol": "_", "visibility": 1, "avoidance": 6, @@ -186,6 +201,8 @@ "id": "tr_caltrops", "name": "caltrops", "color": "dark_gray", + "memorial_male": { "ctxt": "memorial_male", "str": "Stepped on a caltrop." }, + "memorial_female": { "ctxt": "memorial_female", "str": "stepped on a caltrop." }, "symbol": "_", "visibility": 4, "avoidance": 6, @@ -199,6 +216,8 @@ "id": "tr_caltrops_glass", "name": "glass caltrops", "color": "dark_gray", + "memorial_male": { "ctxt": "memorial_male", "str": "Stepped on a glass caltrop." }, + "memorial_female": { "ctxt": "memorial_female", "str": "Stepped on a glass caltrop." }, "symbol": "_", "visibility": 6, "avoidance": 6, @@ -212,6 +231,8 @@ "id": "tr_tripwire", "name": "tripwire", "color": "light_red", + "memorial_male": { "ctxt": "memorial_male", "str": "Tripped on a tripwire." }, + "memorial_female": { "ctxt": "memorial_female", "str": "Tripped on a tripwire." }, "symbol": "^", "visibility": 6, "avoidance": 4, @@ -225,6 +246,8 @@ "trigger_weight": "200 g", "name": "crossbow trap", "color": "green", + "memorial_male": { "ctxt": "memorial_male", "str": "Trigged a crossbow trap." }, + "memorial_female": { "ctxt": "memorial_female", "str": "Trigged a crossbow trap." }, "symbol": "^", "visibility": 5, "avoidance": 4, @@ -248,6 +271,8 @@ "trigger_weight": "200 g", "name": "shotgun trap", "color": "red", + "memorial_male": { "ctxt": "memorial_male", "str": "Triggered a shotgun trap." }, + "memorial_female": { "ctxt": "memorial_female", "str": "Triggered a shotgun trap." }, "symbol": "^", "visibility": 4, "avoidance": 5, @@ -270,6 +295,8 @@ "trigger_weight": "200 g", "name": "shotgun trap", "color": "red", + "memorial_male": { "ctxt": "memorial_male", "str": "Triggered a shotgun trap." }, + "memorial_female": { "ctxt": "memorial_female", "str": "Triggered a shotgun trap." }, "symbol": "^", "visibility": 4, "avoidance": 5, @@ -293,6 +320,8 @@ "trigger_weight": "200 g", "name": "shotgun trap", "color": "red", + "memorial_male": { "ctxt": "memorial_male", "str": "Triggered a shotgun trap." }, + "memorial_female": { "ctxt": "memorial_female", "str": "Triggered a shotgun trap." }, "symbol": "^", "visibility": 4, "avoidance": 5, @@ -329,6 +358,8 @@ "id": "tr_blade", "name": "spinning blade", "color": "cyan", + "memorial_male": { "ctxt": "memorial_male", "str": "Triggered a blade trap." }, + "memorial_female": { "ctxt": "memorial_female", "str": "Triggered a blade trap." }, "symbol": "\\", "visibility": 0, "avoidance": 4, @@ -342,6 +373,8 @@ "trigger_weight": "200 g", "name": "land mine", "color": "red", + "memorial_male": { "ctxt": "memorial_male", "str": "Stepped on a land mine." }, + "memorial_female": { "ctxt": "memorial_female", "str": "Stepped on a land mine." }, "symbol": "^", "visibility": 1, "avoidance": 14, @@ -364,12 +397,15 @@ "trigger_weight": "200 g", "name": "buried land mine", "color": "red", + "memorial_male": { "ctxt": "memorial_male", "str": "Stepped on a land mine." }, + "memorial_female": { "ctxt": "memorial_female", "str": "Stepped on a land mine." }, "symbol": "_", "visibility": 10, "avoidance": 14, "difficulty": 10, "action": "landmine", "drops": [ "landmine" ], + "flags": [ "SONAR_DETECTABLE" ], "vehicle_data": { "do_explosion": true, "damage": 1000, @@ -386,6 +422,8 @@ "trigger_weight": "200 g", "name": "teleport pad", "color": "magenta", + "memorial_male": { "ctxt": "memorial_male", "str": "Triggered a teleport trap." }, + "memorial_female": { "ctxt": "memorial_female", "str": "Triggered a teleport trap." }, "symbol": "_", "visibility": 0, "avoidance": 15, @@ -398,6 +436,8 @@ "id": "tr_goo", "name": "goo pit", "color": "dark_gray", + "memorial_male": { "ctxt": "memorial_male", "str": "Stepped into thick goo." }, + "memorial_female": { "ctxt": "memorial_female", "str": "Stepped into thick goo." }, "symbol": "_", "visibility": 0, "avoidance": 15, @@ -409,6 +449,8 @@ "id": "tr_dissector", "name": "exposed high-energy conduit", "color": "cyan", + "memorial_male": { "ctxt": "memorial_male", "str": "Stepped into an exposed high-energy conduit." }, + "memorial_female": { "ctxt": "memorial_female", "str": "Stepped into an exposed high-energy conduit." }, "symbol": "7", "visibility": 2, "avoidance": 20, @@ -421,11 +463,14 @@ "id": "tr_sinkhole", "name": "sinkhole", "color": "brown", + "memorial_male": { "ctxt": "memorial_male", "str": "Stepped into a sinkhole." }, + "memorial_female": { "ctxt": "memorial_female", "str": "Stepped into a sinkhole." }, "symbol": "_", "visibility": 10, "avoidance": 14, "difficulty": 99, "action": "sinkhole", + "flags": [ "SONAR_DETECTABLE" ], "vehicle_data": { "damage": 500 } }, { @@ -433,6 +478,8 @@ "id": "tr_pit", "name": "pit", "color": "brown", + "memorial_male": { "ctxt": "memorial_male", "str": "Fell in a pit." }, + "memorial_female": { "ctxt": "memorial_female", "str": "Fell in a pit." }, "symbol": "0", "visibility": 0, "avoidance": 8, @@ -445,6 +492,8 @@ "id": "tr_spike_pit", "name": "spiked pit", "color": "blue", + "memorial_male": { "ctxt": "memorial_male", "str": "Fell into a spiked pit." }, + "memorial_female": { "ctxt": "memorial_female", "str": "Fell into a spiked pit." }, "symbol": "0", "visibility": 0, "avoidance": 8, @@ -457,11 +506,14 @@ "id": "tr_lava", "name": "lava", "color": "red", + "memorial_male": { "ctxt": "memorial_male", "str": "Stepped into lava." }, + "memorial_female": { "ctxt": "memorial_female", "str": "Stepped into lava." }, "symbol": "~", "visibility": 0, "avoidance": 99, "difficulty": 99, "action": "lava", + "flags": [ "CONVECTS_TEMPERATURE" ], "vehicle_data": { "damage": 500 } }, { @@ -469,30 +521,22 @@ "id": "tr_portal", "name": "shimmering portal", "color": "magenta", + "memorial_male": { "ctxt": "memorial_male", "str": "Triggered a teleoport trap." }, + "memorial_female": { "ctxt": "memorial_female", "str": "Triggered a teleoport trap." }, "symbol": "%", "visibility": 0, "avoidance": 99, "difficulty": 99, "action": "portal" }, - { - "type": "trap", - "id": "tr_ledge", - "name": "ledge", - "color": "i_cyan", - "symbol": " ", - "visibility": 0, - "avoidance": 99999, - "difficulty": 99, - "action": "ledge", - "vehicle_data": { "is_falling": true } - }, { "type": "trap", "id": "tr_boobytrap", "trigger_weight": "200 g", "name": "booby trap", "color": "light_cyan", + "memorial_male": { "ctxt": "memorial_male", "str": "Triggered a booby trap." }, + "memorial_female": { "ctxt": "memorial_female", "str": "Triggered a booby trap." }, "symbol": "^", "visibility": 5, "avoidance": 4, @@ -514,6 +558,8 @@ "id": "tr_temple_flood", "name": "ledge", "color": "light_gray", + "memorial_male": { "ctxt": "memorial_male", "str": "Triggered a flood trap." }, + "memorial_female": { "ctxt": "memorial_female", "str": "Triggered a flood trap." }, "symbol": "^", "visibility": 9, "avoidance": 20, @@ -561,6 +607,8 @@ "id": "tr_shadow", "name": "", "color": "white", + "memorial_male": { "ctxt": "memorial_male", "str": "Triggered a shadow trap." }, + "memorial_female": { "ctxt": "memorial_female", "str": "Triggered a shadow trap." }, "symbol": "^", "visibility": 99, "avoidance": 99, @@ -573,6 +621,8 @@ "id": "tr_drain", "name": "", "color": "white", + "memorial_male": { "ctxt": "memorial_male", "str": "Triggered a life-draining trap." }, + "memorial_female": { "ctxt": "memorial_female", "str": "Triggered a life-draining trap." }, "symbol": "^", "visibility": 99, "avoidance": 99, @@ -585,6 +635,8 @@ "id": "tr_snake", "name": "", "color": "white", + "memorial_male": { "ctxt": "memorial_male", "str": "Triggered a shadow snake trap." }, + "memorial_female": { "ctxt": "memorial_female", "str": "Triggered a shadow snake trap." }, "symbol": "^", "visibility": 99, "avoidance": 99, @@ -597,6 +649,8 @@ "id": "tr_glass_pit", "name": "glass pit", "color": "cyan", + "memorial_male": { "ctxt": "memorial_male", "str": "Fell into a pit filled with glass shards." }, + "memorial_female": { "ctxt": "memorial_female", "str": "Fell into a pit filled with glass shards." }, "symbol": "0", "visibility": 0, "avoidance": 8, diff --git a/doc/JSON_FLAGS.md b/doc/JSON_FLAGS.md index 1965590eb035d..64930dca6b222 100644 --- a/doc/JSON_FLAGS.md +++ b/doc/JSON_FLAGS.md @@ -206,6 +206,10 @@ These are handled through `ammo_types.json`. You can tag a weapon with these to - ```WIDE``` Prevents `HARDTOSHOOT` monster flag from having any effect. Implied by ```SHOT``` or liquid ammo. - ```NON_FOULING``` This ammo does not cause dirtying or blackpowder fouling on the gun when fired. +## Traps + +- ```SONAR_DETECTABLE``` This trap can be identified with ground-penetrating SONAR. +- ```CONVECTS_TEMPERATURE``` This trap convects temperature, like lava. ## Armor diff --git a/doc/JSON_INFO.md b/doc/JSON_INFO.md index 0db98fd82ecb9..b941b4e2060fe 100644 --- a/doc/JSON_INFO.md +++ b/doc/JSON_INFO.md @@ -1977,6 +1977,7 @@ it is present to help catch errors. "spell_data": { "id": "bear_trap" }, // data required for trapfunc::spell() "trigger_weight": "200 g", // If an item with this weight or more is thrown onto the trap, it triggers. TODO: what is the default? "drops": [ "beartrap" ], // For disassembly? + "flags": [ "EXAMPLE_FLAG" ], // A set of valid flags for this trap "vehicle_data": { "damage": 300, "sound_volume": 8, diff --git a/src/game.cpp b/src/game.cpp index 60d2970d93199..1b34f2b915dbe 100644 --- a/src/game.cpp +++ b/src/game.cpp @@ -1867,10 +1867,11 @@ int get_heat_radiation( const tripoint &location, bool direct ) int get_convection_temperature( const tripoint &location ) { + static const flag_id trap_convects( "CONVECTS_TEMPERATURE" ); int temp_mod = 0; map &here = get_map(); // Directly on lava tiles - int lava_mod = here.tr_at( location ) == tr_lava ? + int lava_mod = here.tr_at( location ).has_flag( trap_convects ) ? fd_fire->get_intensity_level().convection_temperature_mod : 0; // Modifier from fields for( auto fd : here.field_at( location ) ) { diff --git a/src/memorial_logger.cpp b/src/memorial_logger.cpp index 122180f7b8bd7..9de81018cf371 100644 --- a/src/memorial_logger.cpp +++ b/src/memorial_logger.cpp @@ -49,6 +49,7 @@ #include "skill.h" #include "stats_tracker.h" #include "translations.h" +#include "trap.h" #include "type_id.h" #include "units.h" @@ -57,36 +58,6 @@ static const efftype_id effect_datura( "datura" ); static const efftype_id effect_drunk( "drunk" ); static const efftype_id effect_jetinjector( "jetinjector" ); -static const trap_str_id tr_bubblewrap( "tr_bubblewrap" ); -static const trap_str_id tr_glass( "tr_glass" ); -static const trap_str_id tr_beartrap( "tr_beartrap" ); -static const trap_str_id tr_nailboard( "tr_nailboard" ); -static const trap_str_id tr_caltrops( "tr_caltrops" ); -static const trap_str_id tr_caltrops_glass( "tr_caltrops_glass" ); -static const trap_str_id tr_tripwire( "tr_tripwire" ); -static const trap_str_id tr_crossbow( "tr_crossbow" ); -static const trap_str_id tr_shotgun_2( "tr_shotgun_2" ); -static const trap_str_id tr_shotgun_1( "tr_shotgun_1" ); -static const trap_str_id tr_blade( "tr_blade" ); -static const trap_str_id tr_landmine( "tr_landmine" ); -static const trap_str_id tr_light_snare( "tr_light_snare" ); -static const trap_str_id tr_heavy_snare( "tr_heavy_snare" ); -static const trap_str_id tr_telepad( "tr_telepad" ); -static const trap_str_id tr_goo( "tr_goo" ); -static const trap_str_id tr_dissector( "tr_dissector" ); -static const trap_str_id tr_sinkhole( "tr_sinkhole" ); -static const trap_str_id tr_pit( "tr_pit" ); -static const trap_str_id tr_spike_pit( "tr_spike_pit" ); -static const trap_str_id tr_lava( "tr_lava" ); -static const trap_str_id tr_portal( "tr_portal" ); -static const trap_str_id tr_ledge( "tr_ledge" ); -static const trap_str_id tr_boobytrap( "tr_boobytrap" ); -static const trap_str_id tr_temple_flood( "tr_temple_flood" ); -static const trap_str_id tr_shadow( "tr_shadow" ); -static const trap_str_id tr_drain( "tr_drain" ); -static const trap_str_id tr_snake( "tr_snake" ); -static const trap_str_id tr_glass_pit( "tr_glass_pit" ); - static const trait_id trait_CANNIBAL( "CANNIBAL" ); static const trait_id trait_PSYCHOPATH( "PSYCHOPATH" ); static const trait_id trait_SAPIOVORE( "SAPIOVORE" ); @@ -655,87 +626,8 @@ void memorial_logger::notify( const cata::event &e ) character_id ch = e.get( "character" ); if( ch == avatar_id ) { trap_str_id trap = e.get( "trap" ); - if( trap == tr_bubblewrap ) { - add( pgettext( "memorial_male", "Stepped on bubble wrap." ), - pgettext( "memorial_female", "Stepped on bubble wrap." ) ); - } else if( trap == tr_glass ) { - add( pgettext( "memorial_male", "Stepped on glass." ), - pgettext( "memorial_female", "Stepped on glass." ) ); - } else if( trap == tr_beartrap ) { - add( pgettext( "memorial_male", "Caught by a beartrap." ), - pgettext( "memorial_female", "Caught by a beartrap." ) ); - } else if( trap == tr_nailboard ) { - add( pgettext( "memorial_male", "Stepped on a spiked board." ), - pgettext( "memorial_female", "Stepped on a spiked board." ) ); - } else if( trap == tr_caltrops ) { - add( pgettext( "memorial_male", "Stepped on a caltrop." ), - pgettext( "memorial_female", "Stepped on a caltrop." ) ); - } else if( trap == tr_caltrops_glass ) { - add( pgettext( "memorial_male", "Stepped on a glass caltrop." ), - pgettext( "memorial_female", "Stepped on a glass caltrop." ) ); - } else if( trap == tr_tripwire ) { - add( pgettext( "memorial_male", "Tripped on a tripwire." ), - pgettext( "memorial_female", "Tripped on a tripwire." ) ); - } else if( trap == tr_crossbow ) { - add( pgettext( "memorial_male", "Triggered a crossbow trap." ), - pgettext( "memorial_female", "Triggered a crossbow trap." ) ); - } else if( trap == tr_shotgun_1 || trap == tr_shotgun_2 ) { - add( pgettext( "memorial_male", "Triggered a shotgun trap." ), - pgettext( "memorial_female", "Triggered a shotgun trap." ) ); - } else if( trap == tr_blade ) { - add( pgettext( "memorial_male", "Triggered a blade trap." ), - pgettext( "memorial_female", "Triggered a blade trap." ) ); - } else if( trap == tr_light_snare ) { - add( pgettext( "memorial_male", "Triggered a light snare." ), - pgettext( "memorial_female", "Triggered a light snare." ) ); - } else if( trap == tr_heavy_snare ) { - add( pgettext( "memorial_male", "Triggered a heavy snare." ), - pgettext( "memorial_female", "Triggered a heavy snare." ) ); - } else if( trap == tr_landmine ) { - add( pgettext( "memorial_male", "Stepped on a land mine." ), - pgettext( "memorial_female", "Stepped on a land mine." ) ); - } else if( trap == tr_boobytrap ) { - add( pgettext( "memorial_male", "Triggered a booby trap." ), - pgettext( "memorial_female", "Triggered a booby trap." ) ); - } else if( trap == tr_telepad || trap == tr_portal ) { - add( pgettext( "memorial_male", "Triggered a teleport trap." ), - pgettext( "memorial_female", "Triggered a teleport trap." ) ); - } else if( trap == tr_goo ) { - add( pgettext( "memorial_male", "Stepped into thick goo." ), - pgettext( "memorial_female", "Stepped into thick goo." ) ); - } else if( trap == tr_dissector ) { - add( pgettext( "memorial_male", "Stepped into a dissector." ), - pgettext( "memorial_female", "Stepped into a dissector." ) ); - } else if( trap == tr_pit ) { - add( pgettext( "memorial_male", "Fell in a pit." ), - pgettext( "memorial_female", "Fell in a pit." ) ); - } else if( trap == tr_spike_pit ) { - add( pgettext( "memorial_male", "Fell into a spiked pit." ), - pgettext( "memorial_female", "Fell into a spiked pit." ) ); - } else if( trap == tr_glass_pit ) { - add( pgettext( "memorial_male", "Fell into a pit filled with glass shards." ), - pgettext( "memorial_female", "Fell into a pit filled with glass shards." ) ); - } else if( trap == tr_lava ) { - add( pgettext( "memorial_male", "Stepped into lava." ), - pgettext( "memorial_female", "Stepped into lava." ) ); - } else if( trap == tr_sinkhole ) { - add( pgettext( "memorial_male", "Stepped into a sinkhole." ), - pgettext( "memorial_female", "Stepped into a sinkhole." ) ); - } else if( trap == tr_ledge ) { - add( pgettext( "memorial_male", "Fell down a ledge." ), - pgettext( "memorial_female", "Fell down a ledge." ) ); - } else if( trap == tr_temple_flood ) { - add( pgettext( "memorial_male", "Triggered a flood trap." ), - pgettext( "memorial_female", "Triggered a flood trap." ) ); - } else if( trap == tr_shadow ) { - add( pgettext( "memorial_male", "Triggered a shadow trap." ), - pgettext( "memorial_female", "Triggered a shadow trap." ) ); - } else if( trap == tr_drain ) { - add( pgettext( "memorial_male", "Triggered a life-draining trap." ), - pgettext( "memorial_female", "Triggered a life-draining trap." ) ); - } else if( trap == tr_snake ) { - add( pgettext( "memorial_male", "Triggered a shadow snake trap." ), - pgettext( "memorial_female", "Triggered a shadow snake trap." ) ); + if( trap->has_memorial_msg() ) { + add( trap->memorial_msg( true ), trap->memorial_msg( false ) ); } } break; diff --git a/src/trap.cpp b/src/trap.cpp index d40d52ee58d58..3eb7195b13042 100644 --- a/src/trap.cpp +++ b/src/trap.cpp @@ -110,6 +110,17 @@ void trap::load( const JsonObject &jo, const std::string & ) mandatory( jo, was_loaded, "visibility", visibility ); mandatory( jo, was_loaded, "avoidance", avoidance ); mandatory( jo, was_loaded, "difficulty", difficulty ); + + optional( jo, was_loaded, "memorial_male", memorial_male ); + optional( jo, was_loaded, "memorial_female", memorial_female ); + + // Require either none, or both + if( !!memorial_male != !!memorial_female ) { + jo.throw_error( "Only one gender of memorial message specified for trap %s, but none or both required.", + id.str() ); + } + + optional( jo, was_loaded, "flags", _flags ); optional( jo, was_loaded, "trap_radius", trap_radius, 0 ); // TODO: Is there a generic_factory version of this? act = trap_function_from_string( jo.get_string( "action" ) ); @@ -195,8 +206,8 @@ bool trap::is_trivial_to_spot() const bool trap::detected_by_ground_sonar() const { - // @TODO make this a property - return loadid == tr_beartrap_buried || loadid == tr_landmine_buried || loadid == tr_sinkhole; + static const flag_id sonar_detectable = flag_id( "SONAR_DETECTABLE" ); + return has_flag( sonar_detectable ); } bool trap::detect_trap( const tripoint &pos, const Character &p ) const @@ -322,29 +333,28 @@ void trap::on_disarmed( map &m, const tripoint &p ) const ////////////////////////// // convenient int-lookup names for hard-coded functions -trap_id -tr_null, -tr_beartrap_buried, -tr_shotgun_2, -tr_shotgun_1, -tr_blade, -tr_landmine, -tr_landmine_buried, -tr_telepad, -tr_goo, -tr_dissector, -tr_sinkhole, -tr_pit, -tr_lava, -tr_portal, -tr_ledge, -tr_temple_flood, -tr_temple_toggle, -tr_glow, -tr_hum, -tr_shadow, -tr_drain, -tr_snake; +trap_id tr_null; +const trap_str_id tr_beartrap_buried( "tr_beartrap_buried" ); +const trap_str_id tr_shotgun_2( "tr_shotgun_2" ); +const trap_str_id tr_shotgun_1( "tr_shotgun_1" ); +const trap_str_id tr_blade( "tr_blade" ); +const trap_str_id tr_landmine( "tr_landmine" ); +const trap_str_id tr_landmine_buried( "tr_landmine_buried" ); +const trap_str_id tr_telepad( "tr_telepad" ); +const trap_str_id tr_goo( "tr_goo" ); +const trap_str_id tr_dissector( "tr_dissector" ); +const trap_str_id tr_sinkhole( "tr_sinkhole" ); +const trap_str_id tr_pit( "tr_pit" ); +const trap_str_id tr_lava( "tr_lava" ); +const trap_str_id tr_portal( "tr_portal" ); +const trap_str_id tr_ledge( "tr_ledge" ); +const trap_str_id tr_temple_flood( "tr_temple_flood" ); +const trap_str_id tr_temple_toggle( "tr_temple_toggle" ); +const trap_str_id tr_glow( "tr_glow" ); +const trap_str_id tr_hum( "tr_hum" ); +const trap_str_id tr_shadow( "tr_shadow" ); +const trap_str_id tr_drain( "tr_drain" ); +const trap_str_id tr_snake( "tr_snake" ); void trap::check_consistency() { @@ -378,31 +388,8 @@ void trap::finalize() funnel_traps.push_back( &t ); } } - const auto trapfind = []( const char *id ) { - return trap_str_id( id ).id(); - }; + tr_null = trap_str_id::NULL_ID().id(); - tr_beartrap_buried = trapfind( "tr_beartrap_buried" ); - tr_shotgun_2 = trapfind( "tr_shotgun_2" ); - tr_shotgun_1 = trapfind( "tr_shotgun_1" ); - tr_blade = trapfind( "tr_blade" ); - tr_landmine = trapfind( "tr_landmine" ); - tr_landmine_buried = trapfind( "tr_landmine_buried" ); - tr_telepad = trapfind( "tr_telepad" ); - tr_goo = trapfind( "tr_goo" ); - tr_dissector = trapfind( "tr_dissector" ); - tr_sinkhole = trapfind( "tr_sinkhole" ); - tr_pit = trapfind( "tr_pit" ); - tr_lava = trapfind( "tr_lava" ); - tr_portal = trapfind( "tr_portal" ); - tr_ledge = trapfind( "tr_ledge" ); - tr_temple_flood = trapfind( "tr_temple_flood" ); - tr_temple_toggle = trapfind( "tr_temple_toggle" ); - tr_glow = trapfind( "tr_glow" ); - tr_hum = trapfind( "tr_hum" ); - tr_shadow = trapfind( "tr_shadow" ); - tr_drain = trapfind( "tr_drain" ); - tr_snake = trapfind( "tr_snake" ); } std::string trap::debug_describe() const diff --git a/src/trap.h b/src/trap.h index 295d45eb92c33..91f7f55e728d9 100644 --- a/src/trap.h +++ b/src/trap.h @@ -137,6 +137,12 @@ struct trap { std::string map_regen; trap_function act; translation name_; + + cata::optional memorial_male; + cata::optional memorial_female; + + cata::flat_set _flags; + /** * If an item with this weight or more is thrown onto the trap, it triggers. */ @@ -166,6 +172,21 @@ struct trap { return loadid != id; } + bool has_flag( const flag_id &flag ) const { + return _flags.count( flag ); + } + + bool has_memorial_msg() const { + return memorial_male && memorial_female; + } + + std::string memorial_msg( bool male ) const { + if( male ) { + return memorial_male->translated(); + } + return memorial_female->translated(); + } + /** * Called when the player examines a tile. This is supposed to handled * all kind of interaction of the player with the trap, including removal. @@ -322,28 +343,27 @@ struct trap { const trap_function &trap_function_from_string( const std::string &function_name ); -extern trap_id -tr_null, -tr_beartrap_buried, -tr_shotgun_2, -tr_shotgun_1, -tr_blade, -tr_landmine, -tr_landmine_buried, -tr_telepad, -tr_goo, -tr_dissector, -tr_sinkhole, -tr_pit, -tr_lava, -tr_portal, -tr_ledge, -tr_temple_flood, -tr_temple_toggle, -tr_glow, -tr_hum, -tr_shadow, -tr_drain, -tr_snake; +extern trap_id tr_null; +extern const trap_str_id tr_beartrap_buried; +extern const trap_str_id tr_shotgun_2; +extern const trap_str_id tr_shotgun_1; +extern const trap_str_id tr_blade; +extern const trap_str_id tr_landmine; +extern const trap_str_id tr_landmine_buried; +extern const trap_str_id tr_telepad; +extern const trap_str_id tr_goo; +extern const trap_str_id tr_dissector; +extern const trap_str_id tr_sinkhole; +extern const trap_str_id tr_pit; +extern const trap_str_id tr_lava; +extern const trap_str_id tr_portal; +extern const trap_str_id tr_ledge; +extern const trap_str_id tr_temple_flood; +extern const trap_str_id tr_temple_toggle; +extern const trap_str_id tr_glow; +extern const trap_str_id tr_hum; +extern const trap_str_id tr_shadow; +extern const trap_str_id tr_drain; +extern const trap_str_id tr_snake; #endif // CATA_SRC_TRAP_H From a08c4819dcc15eeefa2651859042ee7451c49465 Mon Sep 17 00:00:00 2001 From: anothersimulacrum Date: Mon, 1 Mar 2021 17:07:51 -0800 Subject: [PATCH 269/453] Clean up character mutation gain a bit (#47821) Reduce duplicated code. I presume there's a reason that set_mutations didn't just call set_mutation, and the only difference is that it doesn't do the cache updates till the end, so preserve that behaviour. --- src/character.h | 7 +++++++ src/mutation.cpp | 40 +++++++++++++++++++--------------------- 2 files changed, 26 insertions(+), 21 deletions(-) diff --git a/src/character.h b/src/character.h index a348e13a42716..1ee1982608254 100644 --- a/src/character.h +++ b/src/character.h @@ -974,6 +974,13 @@ class Character : public Creature, public visitable /** Add or removes a mutation on the player, but does not trigger mutation loss/gain effects. */ void set_mutations( const std::vector &traits ); void set_mutation( const trait_id & ); + protected: + // Set a mutation, but don't do any of the necessary updates + // Only call this from one of the above two functions + void set_mutation_unsafe( const trait_id & ); + public: + // Do the mutation updates necessary when adding a mutation (nonspecific cache updates) + void do_mutation_updates(); void unset_mutation( const trait_id & ); /**Unset switched mutation and set target mutation instead*/ void switch_mutations( const trait_id &switched, const trait_id &target, bool start_powered ); diff --git a/src/mutation.cpp b/src/mutation.cpp index ea289fdce0c25..c8229f05af92d 100644 --- a/src/mutation.cpp +++ b/src/mutation.cpp @@ -158,27 +158,7 @@ void Character::toggle_trait( const trait_id &trait_ ) } } -void Character::set_mutations( const std::vector &traits ) -{ - for( const trait_id &trait : traits ) { - const auto iter = my_mutations.find( trait ); - if( iter != my_mutations.end() ) { - continue; - } - my_mutations.emplace( trait, trait_data{} ); - cached_mutations.push_back( &trait.obj() ); - mutation_effect( trait, false ); - } - recalc_sight_limits(); - calc_encumbrance(); - - // If the stamina is higher than the max (Languorous), set it back to max - if( get_stamina() > get_stamina_max() ) { - set_stamina( get_stamina_max() ); - } -} - -void Character::set_mutation( const trait_id &trait ) +void Character::set_mutation_unsafe( const trait_id &trait ) { const auto iter = my_mutations.find( trait ); if( iter != my_mutations.end() ) { @@ -187,6 +167,10 @@ void Character::set_mutation( const trait_id &trait ) my_mutations.emplace( trait, trait_data{} ); cached_mutations.push_back( &trait.obj() ); mutation_effect( trait, false ); +} + +void Character::do_mutation_updates() +{ recalc_sight_limits(); calc_encumbrance(); @@ -196,6 +180,20 @@ void Character::set_mutation( const trait_id &trait ) } } +void Character::set_mutations( const std::vector &traits ) +{ + for( const trait_id &trait : traits ) { + set_mutation_unsafe( trait ); + } + do_mutation_updates(); +} + +void Character::set_mutation( const trait_id &trait ) +{ + set_mutation_unsafe( trait ); + do_mutation_updates(); +} + void Character::unset_mutation( const trait_id &trait_ ) { // Take copy of argument because it might be a reference into a container From 919364c182bedec3ed4b42589a0e42a785835260 Mon Sep 17 00:00:00 2001 From: anothersimulacrum Date: Sun, 14 Mar 2021 13:48:23 -0700 Subject: [PATCH 270/453] Allow CBMs to specify mutations that prevent installation. (#47822) * Move CBM installation checks to Character Reduce code duplication, encapsulate things better, and make this available outside of the inventory menus. * Allow mutations to prevent installing CBMs Bionics can currently cancel mutations when installed, but can't have mutations prevent installation. --- doc/JSON_INFO.md | 2 ++ src/bionics.cpp | 50 +++++++++++++++++++++++++++++++++ src/bionics.h | 4 +++ src/character.h | 3 ++ src/game_inventory.cpp | 64 ++++-------------------------------------- src/mutation.cpp | 12 ++++++++ 6 files changed, 77 insertions(+), 58 deletions(-) diff --git a/doc/JSON_INFO.md b/doc/JSON_INFO.md index b941b4e2060fe..62854253daf15 100644 --- a/doc/JSON_INFO.md +++ b/doc/JSON_INFO.md @@ -655,6 +655,7 @@ For information about tools with option to export ASCII art in format ready to b | weight_capacity_bonus | (_optional_) Bonus to weight carrying capacity in grams, can be negative. Strings can be used - "5000 g" or "5 kg" (default: `0`) | weight_capacity_modifier | (_optional_) Factor modifying base weight carrying capacity. (default: `1`) | canceled_mutations | (_optional_) A list of mutations/traits that are removed when this bionic is installed (e.g. because it replaces the fault biological part). +| mutation_conflicts | (_optional_) A list of mutations that prevent this bionic from being installed. | included_bionics | (_optional_) Additional bionics that are installed automatically when this bionic is installed. This can be used to install several bionics from one CBM item, which is useful as each of those can be activated independently. | included | (_optional_) Whether this bionic is included with another. If true this bionic does not require a CBM item to be defined. (default: `false`) | env_protec | (_optional_) How much environmental protection does this bionic provide on the specified body parts. @@ -692,6 +693,7 @@ For information about tools with option to export ASCII art in format ready to b "encumbrance" : [ [ "torso", 10 ], [ "arm_l", 10 ], [ "arm_r", 10 ], [ "leg_l", 10 ], [ "leg_r", 10 ], [ "foot_l", 10 ], [ "foot_r", 10 ] ], "description" : "You have a battery draining attachment, and thus can make use of the energy contained in normal, everyday batteries. Use 'E' to consume batteries.", "canceled_mutations": ["HYPEROPIC"], + "mutation_conflicts": [ "HUGE" ], "installation_requirement": "sewing_standard", "included_bionics": ["bio_blindfold"] }, diff --git a/src/bionics.cpp b/src/bionics.cpp index 20a28a9ef7bcb..72706762976de 100644 --- a/src/bionics.cpp +++ b/src/bionics.cpp @@ -192,6 +192,7 @@ static const trait_id trait_PROF_MED( "PROF_MED" ); static const trait_id trait_THRESH_MEDICAL( "THRESH_MEDICAL" ); static const json_character_flag json_flag_BIONIC_GUN( "BIONIC_GUN" ); +static const json_character_flag json_flag_BIONIC_NPC_USABLE( "BIONIC_NPC_USABLE" ); static const json_character_flag json_flag_BIONIC_WEAPON( "BIONIC_WEAPON" ); static const json_character_flag json_flag_BIONIC_TOGGLED( "BIONIC_TOGGLED" ); @@ -317,6 +318,7 @@ void bionic_data::load( const JsonObject &jsobj, const std::string & ) optional( jsobj, was_loaded, "learned_spells", learned_spells ); optional( jsobj, was_loaded, "learned_proficiencies", proficiencies ); optional( jsobj, was_loaded, "canceled_mutations", canceled_mutations ); + optional( jsobj, was_loaded, "mutation_conflicts", mutation_conflicts ); optional( jsobj, was_loaded, "included_bionics", included_bionics ); optional( jsobj, was_loaded, "included", included ); optional( jsobj, was_loaded, "upgraded_bionic", upgraded_bionic ); @@ -2316,6 +2318,54 @@ bool Character::uninstall_bionic( const bionic &target_cbm, monster &installer, return false; } +ret_val Character::is_installable( const item_location &loc, const bool by_autodoc ) const +{ + const item *it = loc.get_item(); + const itype *itemtype = it->type; + const bionic_id &bid = itemtype->bionic->id; + + const auto has_trait_lambda = [this]( const trait_id & candidate ) { + return has_trait( candidate ); + }; + + if( it->has_flag( flag_FILTHY ) ) { + // NOLINTNEXTLINE(cata-text-style): single space after the period for symmetry + const std::string msg = by_autodoc ? _( "/!\\ CBM is highly contaminated. /!\\" ) : + _( "CBM is filthy." ); + return ret_val::make_failure( msg ); + } else if( it->has_flag( flag_NO_STERILE ) ) { + const std::string msg = by_autodoc ? + // NOLINTNEXTLINE(cata-text-style): single space after the period for symmetry + _( "/!\\ CBM is not sterile. /!\\ Please use autoclave to sterilize." ) : + _( "CBM is not sterile." ); + return ret_val::make_failure( msg ); + } else if( it->has_fault( fault_id( "fault_bionic_salvaged" ) ) ) { + return ret_val::make_failure( _( "CBM already deployed. Please reset to factory state." ) ); + } else if( has_bionic( bid ) ) { + return ret_val::make_failure( _( "CBM is already installed." ) ); + } else if( !can_install_cbm_on_bp( get_occupied_bodyparts( bid ) ) ) { + return ret_val::make_failure( _( "CBM not compatible with patient's body." ) ); + } else if( std::any_of( bid->mutation_conflicts.begin(), bid->mutation_conflicts.end(), + has_trait_lambda ) ) { + return ret_val::make_failure( _( "CBM not compatible with patient's body." ) ); + } else if( bid->upgraded_bionic && + !has_bionic( bid->upgraded_bionic ) && + it->is_upgrade() ) { + return ret_val::make_failure( _( "No base version installed." ) ); + } else if( std::any_of( bid->available_upgrades.begin(), + bid->available_upgrades.end(), + std::bind( &Character::has_bionic, this, + std::placeholders::_1 ) ) ) { + return ret_val::make_failure( _( "Superior version installed." ) ); + } else if( is_npc() && !bid->has_flag( json_flag_BIONIC_NPC_USABLE ) ) { + return ret_val::make_failure( _( "CBM not compatible with patient." ) ); + } else if( units::energy_max - get_max_power_level() < bid->capacity ) { + return ret_val::make_failure( _( "Max power capacity already reached." ) ); + } + + return ret_val::make_success( std::string() ); +} + bool Character::can_install_bionics( const itype &type, Character &installer, bool autodoc, int skill_level ) { diff --git a/src/bionics.h b/src/bionics.h index 8f18e22307110..0dfee95903409 100644 --- a/src/bionics.h +++ b/src/bionics.h @@ -113,6 +113,10 @@ struct bionic_data { * E.g. enhanced optic bionic may cancel HYPEROPIC trait. */ std::vector canceled_mutations; + /** + * Mutations/traits that prevent installing this CBM + */ + std::set mutation_conflicts; /** * The spells you learn when you install this bionic, and what level you learn them at. diff --git a/src/character.h b/src/character.h index 1ee1982608254..660e5b0c792a3 100644 --- a/src/character.h +++ b/src/character.h @@ -1310,6 +1310,9 @@ class Character : public Creature, public visitable /**Is the installation possible*/ bool can_install_bionics( const itype &type, Character &installer, bool autodoc = false, int skill_level = -1 ); + /** Is this bionic elligible to be installed in the player? */ + // Should be ret_val, but ret_val.h doesn't like it + ret_val is_installable( const item_location &loc, bool by_autodoc ) const; std::map bionic_installation_issues( const bionic_id &bioid ); /** Initialize all the values needed to start the operation player_activity */ bool install_bionics( const itype &type, player &installer, bool autodoc = false, diff --git a/src/game_inventory.cpp b/src/game_inventory.cpp index 638c4b43e96b6..1fb79e7692c1b 100644 --- a/src/game_inventory.cpp +++ b/src/game_inventory.cpp @@ -74,8 +74,6 @@ static const trait_id trait_NOPAIN( "NOPAIN" ); static const trait_id trait_SAPROPHAGE( "SAPROPHAGE" ); static const trait_id trait_SAPROVORE( "SAPROVORE" ); -static const json_character_flag json_flag_BIONIC_NPC_USABLE( "BIONIC_NPC_USABLE" ); - using item_filter = std::function; using item_location_filter = std::function; @@ -1816,41 +1814,15 @@ class bionic_install_preset: public inventory_selector_preset } std::string get_denial( const item_location &loc ) const override { - const item *it = loc.get_item(); - const itype *itemtype = it->type; - const bionic_id &bid = itemtype->bionic->id; - - if( it->has_flag( flag_FILTHY ) ) { - // NOLINTNEXTLINE(cata-text-style): single space after the period for symmetry - return _( "/!\\ CBM is highly contaminated. /!\\" ); - } else if( it->has_flag( flag_NO_STERILE ) ) { - // NOLINTNEXTLINE(cata-text-style): single space after the period for symmetry - return _( "/!\\ CBM is not sterile. /!\\ Please use autoclave to sterilize." ); - } else if( it->has_fault( fault_id( "fault_bionic_salvaged" ) ) ) { - return _( "CBM already deployed. Please reset to factory state." ); - } else if( pa.has_bionic( bid ) ) { - return _( "CBM already installed." ); - } else if( !pa.can_install_cbm_on_bp( get_occupied_bodyparts( bid ) ) ) { - return _( "CBM not compatible with patient's body." ); - } else if( bid->upgraded_bionic && - !pa.has_bionic( bid->upgraded_bionic ) && - it->is_upgrade() ) { - return _( "No base version installed." ); - } else if( std::any_of( bid->available_upgrades.begin(), - bid->available_upgrades.end(), - std::bind( &player::has_bionic, &pa, - std::placeholders::_1 ) ) ) { - return _( "Superior version installed." ); - } else if( pa.is_npc() && !bid->has_flag( json_flag_BIONIC_NPC_USABLE ) ) { - return _( "CBM not compatible with patient." ); - } else if( units::energy_max - pa.get_max_power_level() < bid->capacity ) { - return _( "Max power capacity already reached." ); - } else if( !p.has_enough_anesth( *itemtype, pa ) ) { + const ret_val installable = pa.is_installable( loc, true ); + if( installable.success() && !p.has_enough_anesth( *loc.get_item()->type, pa ) ) { const int weight = units::to_kilogram( pa.bodyweight() ) / 10; const int duration = loc.get_item()->type->bionic->difficulty * 2; const requirement_data req_anesth = *requirement_id( "anesthetic" ) * duration * weight; return string_format( _( "%i mL" ), req_anesth.get_tools().front().front().count ); + } else if( !installable.success() ) { + return installable.str(); } return std::string(); @@ -1929,32 +1901,8 @@ class bionic_install_surgeon_preset : public inventory_selector_preset } std::string get_denial( const item_location &loc ) const override { - const item *it = loc.get_item(); - const itype *itemtype = it->type; - const bionic_id &bid = itemtype->bionic->id; - - if( it->has_flag( flag_FILTHY ) ) { - return _( "CBM is filthy." ); - } else if( it->has_flag( flag_NO_STERILE ) ) { - return _( "CBM is not sterile." ); - } else if( it->has_fault( fault_bionic_salvaged ) ) { - return _( "CBM is already deployed." ); - } else if( pa.has_bionic( bid ) ) { - return _( "CBM is already installed." ); - } else if( bid->upgraded_bionic && - !pa.has_bionic( bid->upgraded_bionic ) && - it->is_upgrade() ) { - return _( "No base version installed." ); - } else if( std::any_of( bid->available_upgrades.begin(), - bid->available_upgrades.end(), - std::bind( &player::has_bionic, &pa, - std::placeholders::_1 ) ) ) { - return _( "Superior version installed." ); - } else if( pa.is_npc() && !bid->has_flag( json_flag_BIONIC_NPC_USABLE ) ) { - return _( "CBM is not compatible with patient." ); - } - - return std::string(); + const ret_val installable = pa.is_installable( loc, false ); + return installable.str(); } protected: diff --git a/src/mutation.cpp b/src/mutation.cpp index c8229f05af92d..3824b264a35ac 100644 --- a/src/mutation.cpp +++ b/src/mutation.cpp @@ -854,6 +854,10 @@ bool Character::mutation_ok( const trait_id &mutation, bool force_good, bool for return false; } } + + if( bid->mutation_conflicts.count( mutation ) != 0 ) { + return false; + } } const mutation_branch &mdata = mutation.obj(); @@ -1182,6 +1186,14 @@ bool Character::mutate_towards( const trait_id &mut ) return false; } + // Just prevent it when it conflicts with a CBM, for now + // TODO: Consequences? + for( const bionic_id &bid : get_bionics() ) { + if( bid->mutation_conflicts.count( mut ) != 0 ) { + return false; + } + } + for( size_t i = 0; !has_threshreq && i < threshreq.size(); i++ ) { if( has_trait( threshreq[i] ) ) { has_threshreq = true; From 4c9d8218b5e25dcd6f25da866a19526cc5451638 Mon Sep 17 00:00:00 2001 From: Anton Burmistrov Date: Mon, 15 Mar 2021 00:49:21 +0400 Subject: [PATCH 271/453] Spiral mine jsonify (#48003) --- .../furniture_and_terrain/terrain-walls.json | 20 ++ data/json/mapgen/mine/mine_shaft.json | 20 +- data/json/mapgen/mine/mine_spiral.json | 190 ++++++++++++++++++ data/json/mapgen/nested/mine_nested.json | 76 +++++++ data/json/npcs/mine/spiral_madman.json | 126 ++++++++++++ data/json/npcs/talk_tags.json | 16 ++ data/json/obsolete_terrains.json | 4 +- data/json/overmap/overmap_special/mine.json | 63 ++++++ .../overmap_terrain_hardcoded.json | 18 -- .../overmap_terrain_industrial.json | 25 +++ .../go_overmap_terrain_hardcoded.json | 24 +-- data/mods/alt_map_key/overmap_terrain.json | 16 -- src/map.h | 1 - src/mapgen.cpp | 97 +-------- src/overmap.cpp | 11 +- 15 files changed, 546 insertions(+), 161 deletions(-) create mode 100644 data/json/mapgen/mine/mine_spiral.json create mode 100644 data/json/mapgen/nested/mine_nested.json create mode 100644 data/json/npcs/mine/spiral_madman.json create mode 100644 data/json/overmap/overmap_special/mine.json diff --git a/data/json/furniture_and_terrain/terrain-walls.json b/data/json/furniture_and_terrain/terrain-walls.json index 69cc70c69b254..34759ba834000 100644 --- a/data/json/furniture_and_terrain/terrain-walls.json +++ b/data/json/furniture_and_terrain/terrain-walls.json @@ -1482,5 +1482,25 @@ "ter_set": "t_null", "items": [ { "item": "rock", "count": [ 3, 8 ] }, { "item": "pebble", "count": [ 20, 38 ] } ] } + }, + { + "type": "terrain", + "id": "t_pillar", + "name": "pillar", + "looks_like": "t_column", + "description": "A concrete column that helps keep the mine's ceiling and walls from collapsing.", + "symbol": "1", + "color": "light_gray", + "move_cost": 0, + "coverage": 80, + "flags": [ "WALL", "PERMEABLE", "MINEABLE" ], + "bash": { + "str_min": 120, + "str_max": 200, + "sound": "crash!", + "sound_fail": "whump!", + "ter_set": "t_reb_cage", + "items": [ { "item": "rock", "count": [ 10, 22 ] } ] + } } ] diff --git a/data/json/mapgen/mine/mine_shaft.json b/data/json/mapgen/mine/mine_shaft.json index 3d56375160457..8fee0022eb3de 100644 --- a/data/json/mapgen/mine/mine_shaft.json +++ b/data/json/mapgen/mine/mine_shaft.json @@ -43,28 +43,28 @@ "rows": [ "###### ## #################### #######", "###### ## ################### ########", - "###### ## ############# #### #########", + "######№ ## №############# #### #########", "####### ############### ### ##########", "######## ############### ## ###########", "######## ############## ############", " ###### ################ ##########", - " ## ################# ###########", - "# ##### ###### ###########", + " ##№ ################# ###########", + "# №##### №###### ###########", " #### ## ", "###### ### #### #### ", "###### |-| #### ##### ", "###### |----|<|--| ", "##### |!@@...!@@| #### #####", - "### |.@@....@@| ######### ######", + "###№ |.@@....@@| ######### ######", " +.......@@| ########## ######", "*****************=========| # ######## ####", - " +.......®®| ####### ####", + " +.......®®| №####### ####", " |.........| ######### ####", "# |.........| ######### #", - "## |LLLL|SSSS| ######### #", - "#### |----|----| ######## #", + "## |LLLL|SSSS| №######### #", + "####№ |----|----| ######## #", "###### ######### ", - "####### ## ####### ######## " + "####### ## №####### ######## " ], "terrain": { "<": "t_ladder_up", @@ -78,6 +78,7 @@ "=": "t_conveyor", "*": "t_railroad_track_small", "®": "t_thconc_floor", + "№": "t_pillar", "L": "t_thconc_floor", "S": "t_thconc_floor" }, @@ -86,7 +87,8 @@ "L": [ { "item": "clothing_work_set", "chance": 50 }, { "item": "hardware_clothing", "chance": 50 } ], "S": { "item": "mine_equipment", "chance": 80 } }, - "place_vehicles": [ { "vehicle": "trolley", "x": 10, "y": 16, "chance": 100, "status": 0 } ] + "place_vehicles": [ { "vehicle": "trolley", "x": 10, "y": 16, "chance": 100, "status": 0 } ], + "monsters": { " ": { "monster": "GROUP_MINER", "chance": 1, "density": 0.0005 } } } } ] diff --git a/data/json/mapgen/mine/mine_spiral.json b/data/json/mapgen/mine/mine_spiral.json new file mode 100644 index 0000000000000..e69daee9f44c2 --- /dev/null +++ b/data/json/mapgen/mine/mine_spiral.json @@ -0,0 +1,190 @@ +[ + { + "type": "monstergroup", + "name": "GROUP_MINER", + "default": "mon_zombie_miner", + "monsters": [ ] + }, + { + "type": "mapgen", + "method": "json", + "om_terrain": [ [ "mine_spiral_west", "mine_spiral_central", "mine_spiral_east" ] ], + "object": { + "fill_ter": "t_rock_floor", + "rows": [ + "########################################################################", + "@@@@@@@@@@@@@@@@@@@@@@@@@###############################################", + "@ @###############################################", + "@ ##################### @###############################################", + "@ #@@@@@@@@@@@@@@@@@@@# @###############################################", + "@ #@ @# @###############################################", + "@ #@ ############### @# @###############################################", + "@ #@ #@@@@@@@@@@@### @# @###############################################", + "@ #@ #@ ># @# @###############################################", + "@ #@ #@ @@@@@@@@@### @# @###############################################", + "@ #@ #@ ############ @# @###############################################", + "@ #@ #@ @# @###############################################", + "@ #@ #@@@@@@@@@@@@@@@@# @#####################@@@@@@@@@@@@@@@@@@@@@@@@@@", + "@ #@ ################## @#####################! @@@@@@@@@@@!@@@@@@@@@@ !", + "@ #@ @##################### ", + "@ #@@@@@@@@@@@@@@@@########################### ", + "@ ############################################**************************", + "@ @@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@## #### ", + "@ # ## ", + "@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@##### ! @@@@@@@@@@!@@@@@@@@@@ !", + "###############################################@@@@@@@@@@@@@@@@@@@@@@@@@", + "########################################################################", + "########################################################################", + "########################################################################" + ], + "terrain": { + "@": [ [ "t_rock", 4 ], [ "t_rock_floor", 1 ] ], + "#": "t_rock", + "*": "t_railroad_track_small", + "!": "t_pillar", + ">": "t_slope_down" + }, + "items": { " ": { "item": "mine_equipment", "chance": 1 } }, + "monsters": { " ": { "monster": "GROUP_MINER", "chance": 1, "density": 0.001 } } + } + }, + { + "type": "mapgen", + "method": "json", + "om_terrain": [ + [ "mine_spiral_-1_nw", "mine_spiral_-1_n", "mine_spiral_-1_ne" ], + [ "mine_spiral_-1_sw", "mine_spiral_-1_s", "mine_spiral_-1_se" ] + ], + "object": { + "fill_ter": "t_rock_floor", + "rows": [ + "####################################@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@", + "####################################@ @", + "########@@@@@@@@@@@@@@@@@@@@@@@@@@@@@ 1 1 ###### @", + "########@ # @", + "########@ @@@@@@@@@@@@@@@@@@@@@@@@@@@ # #### @", + "########@ @##################@######@ # #~ # @", + "########@ @# @######@ # # @", + "########@ @# @@@@@@@@@@@@@@@ @######@ ###### @", + "########@ @# @#############@ @######@ @", + "########@ @# @####< #@ @######@ @", + "########@ @# @########### #@ @######@ @", + "########@ @# @@@@@@@@@@@@ #@ @######@ 1 1 1 @", + "########@ @# #@ @######@ @", + "########@ @################@ @######@ @", + "########@ @@@@@@@@@@@@@@@@@@ @######@ @", + "########@ @######@ @", + "########@@@@@@@@@@@@@@@@@@@@@@######@ @", + "####################################@ @", + "####################################@@@@@@@@@@@@@@@@@@@@@@@ @", + "##########################################################@ @", + "##########################################################@ @", + "#####@@@@@@@@@@@@@@@@@@####@@@@@@@@@@@@@@@@@@@############@ @", + "##### #### @############@ @", + "##### #### #### #### ############@ @", + "#####%%%%%%######%%%%%%####!!!!!!######$$$$$$ ############@ @", + "#####% ###### %####! ##### $ ############@ @", + "#####% %%%%######%%%% %####! !!!!##### $$$$ $ ############@ @", + "#####% % %######% % %####! ! !##### $ >$ $ ############@ @", + "#####% %######% %####! !##### $ $ ############@ @", + "#####%%%%%%######%%%%%%####!!!!!!##### $$$$$$ ############@ @", + "#### ###### ## ##### ############@ @", + "### ###### @####@ @############@ @", + "#@ @@@@@@@######@@@@@@@@@@@@@@@@@####@@@@@@@@############@ @", + "#@ @#####################################################@ @", + "#@ @####################################################### @", + "#@ @@@@@@@######@@@@@@@@@@@@@@@@######@@@@@@@@@@@@@@@@@@@### @", + "### ###### ###### ## @", + "#### ###### ## ###### ### #### ##", + "##### ###### #### ###### ##### ###### ###", + "#####^^^^^^######^^^^^^####&&&&&&######&&&&&&######******######******###", + "#####^ ###### ^####& ###### &######* ###### *###", + "#####^ ^^^^######^^^^ ^####& &&&&######&&&& &######* ****######**** *###", + "#####^ ^ ^######^ ^ ^####& & &######& & &######* * *######* * *###", + "#####^ ^######^ ^####& &######& &######* *######* *###", + "#####^^^^^^######^^^^^^####&&&&&&######&&&&&&######******######******###", + "##### #### #### #### ###### ###### ###", + "##### @##@ @####@ ###", + "#####@@@@@@@@@@@@@@@@@@@##@@@@@@@@@@@@@@@@@@@@####@@@@@@@@@@@@@@@@@@@###" + ], + "terrain": { + "@": [ [ "t_rock", 4 ], [ "t_rock_floor", 1 ] ], + "#": "t_rock", + ">": "t_slope_down", + "<": "t_slope_up", + "$": "t_lava" + }, + "furniture": { "&": "f_wreckage", "^": "f_rubble", "%": "f_rubble_rock", "!": "f_rubble_landfill" }, + "nested": { + "1": { "chunks": [ [ "spiral_cw", 25 ], [ "spiral_ccw", 25 ], [ "spiral_boulder_cw", 25 ], [ "spiral_boulder_ccw", 25 ] ] } + }, + "item": { "*": { "item": "rock", "chance": 100 } }, + "npcs": { "~": { "class": "spiral_madman" } } + } + }, + { + "type": "mapgen", + "method": "json", + "om_terrain": [ + [ "mine_spiral_finale_nw", "mine_spiral_finale_n", "mine_spiral_finale_ne" ], + [ "mine_spiral_finale_sw", "mine_spiral_finale_s", "mine_spiral_finale_se" ] + ], + "object": { + "fill_ter": "t_rock_floor", + "rows": [ + "###### 1 1 1 1 1 1 1 1 ", + "# ", + "# #### ", + "# #! # ", + "# # ", + "###### ", + " ", + " ###### ", + " # ", + " #### # ", + " # !# # ", + " # # ", + " ###### ", + " ", + "###### 1 1 1 1 1 1 ###### ", + "# # ", + "# #### #### # ", + "# #! # # # # ", + "# # # # ", + "###### ###### ", + " ", + "###### ###### ###### ", + "# # # ", + "# #### #### # #### # ", + "# # # # !# # # # # ", + "# # # # # # ", + "###### ###### ###### ", + " < ", + "###### 1 ###### 1 1 1 ###### ", + "# # # ", + "# #### # #### #### # ", + "# #! # # #! # # # # ", + "# # # # # # ", + "###### ###### ###### ", + " ", + "###### ###### ", + "# # ", + "# #### #### # ", + "# # # # !# # ", + "# # # # ", + "###### ###### ", + " ", + "###### 1 1 1 1 1 1 1 1 ", + "# ", + "# #### ", + "# #! # ", + "# # ", + "###### " + ], + "terrain": { "@": [ [ "t_rock", 4 ], [ "t_rock_floor", 1 ] ], "#": "t_rock", "<": "t_slope_up" }, + "monsters": { " ": { "monster": "GROUP_SPIRAL", "chance": 1, "density": 0.001 } }, + "nested": { "1": { "chunks": [ [ "spiral_cw", 50 ], [ "spiral_ccw", 50 ] ] } }, + "items": { "!": { "item": "spiral", "chance": 60 } } + } + } +] diff --git a/data/json/mapgen/nested/mine_nested.json b/data/json/mapgen/nested/mine_nested.json new file mode 100644 index 0000000000000..ee70e895db90f --- /dev/null +++ b/data/json/mapgen/nested/mine_nested.json @@ -0,0 +1,76 @@ +[ + { + "type": "palette", + "id": "mine_palette", + "terrain": { "#": "t_rock", " ": "t_rock_floor", "$": "t_rock_floor" }, + "furniture": { "$": "f_boulder_large" } + }, + { + "type": "mapgen", + "method": "json", + "nested_mapgen_id": "spiral_cw", + "object": { + "palettes": [ "mine_palette" ], + "mapgensize": [ 6, 6 ], + "rows": [ + "######", + " #", + "#### #", + "# # #", + "# #", + "######" + ] + } + }, + { + "type": "mapgen", + "method": "json", + "nested_mapgen_id": "spiral_ccw", + "object": { + "palettes": [ "mine_palette" ], + "mapgensize": [ 6, 6 ], + "rows": [ + "######", + "# ", + "# ####", + "# # #", + "# #", + "######" + ] + } + }, + { + "type": "mapgen", + "method": "json", + "nested_mapgen_id": "spiral_boulder_cw", + "object": { + "palettes": [ "mine_palette" ], + "mapgensize": [ 6, 6 ], + "rows": [ + "$$$$$$", + " $", + "$$$$ $", + "$ $ $", + "$ $", + "$$$$$$" + ] + } + }, + { + "type": "mapgen", + "method": "json", + "nested_mapgen_id": "spiral_boulder_ccw", + "object": { + "palettes": [ "mine_palette" ], + "mapgensize": [ 6, 6 ], + "rows": [ + "$$$$$$", + "$ ", + "$ $$$$", + "$ $ $", + "$ $", + "$$$$$$" + ] + } + } +] diff --git a/data/json/npcs/mine/spiral_madman.json b/data/json/npcs/mine/spiral_madman.json new file mode 100644 index 0000000000000..5a130d2345717 --- /dev/null +++ b/data/json/npcs/mine/spiral_madman.json @@ -0,0 +1,126 @@ +[ + { + "type": "npc", + "id": "spiral_madman", + "//": "Former miner, poor fellow succumbed to spiral madness.", + "name_suffix": "miner", + "class": "NC_SPIRAL_MADMAN", + "attitude": 0, + "mission": 8, + "chat": "TALK_SPIRAL_MADMAN_FIRST_MEETING", + "faction": "no_faction" + }, + { + "type": "npc_class", + "id": "NC_SPIRAL_MADMAN", + "name": { "str": "Miner" }, + "job_description": "Spirals.", + "traits": [ { "group": "NPC_starting_traits" }, { "group": "Appearance_demographics" } ], + "bonus_str": { "rng": [ 2, 4 ] }, + "bonus_dex": { "rng": [ 0, 2 ] }, + "worn_override": "NC_SPIRAL_MADMAN_worn", + "weapon_override": "NC_SPIRAL_MADMAN_wield" + }, + { + "type": "item_group", + "id": "NC_SPIRAL_MADMAN_worn", + "subtype": "collection", + "entries": [ + { "group": "clothing_work_boots", "damage": [ 0, 2 ] }, + { "group": "clothing_work_glasses", "prob": 60, "damage": [ 0, 2 ] }, + { "group": "clothing_work_gloves", "prob": 75, "damage": [ 0, 2 ] }, + { "group": "clothing_work_mask", "prob": 40, "damage": [ 0, 2 ] }, + { "item": "ear_plugs", "prob": 15, "damage": [ 0, 2 ] }, + { "item": "tool_belt", "prob": 25, "damage": [ 0, 2 ] }, + { + "distribution": [ + { + "collection": [ { "group": "clothing_work_pants", "damage": [ 0, 2 ] }, { "group": "clothing_work_torso", "damage": [ 0, 2 ] } ], + "prob": 75 + }, + { "item": "jumpsuit", "prob": 25, "damage": [ 0, 2 ] } + ] + }, + { "group": "underwear", "damage": [ 0, 1 ] }, + { "item": "miner_hat", "prob": 90, "damage": [ 0, 2 ] } + ] + }, + { + "type": "item_group", + "id": "NC_SPIRAL_MADMAN_wield", + "items": [ + [ "pickaxe", 50 ], + [ "shovel", 50 ], + [ "bucket", 20 ], + [ "gasoline_lantern", 10 ], + [ "electric_lantern", 10 ], + [ "oil_lamp", 10 ], + [ "jackhammer", 5 ], + [ "elec_jackhammer", 5 ] + ] + }, + { + "id": "TALK_SPIRAL_MADMAN_FIRST_MEETING", + "type": "talk_topic", + "dynamic_line": "Spirals?", + "speaker_effect": { "effect": { "u_add_var": "first_meeting", "type": "dialogue", "context": "first_meeting", "value": "yes" } }, + "responses": [ + { + "text": "Hello there!", + "topic": "TALK_SPIRAL_MADMAN_GENERIC", + "condition": { "not": { "u_has_var": "first_meeting", "type": "dialogue", "context": "first_meeting", "value": "yes" } } + }, + { + "text": "I'm outta here. Bye.", + "topic": "TALK_DONE", + "condition": { "not": { "u_has_var": "first_meeting", "type": "dialogue", "context": "first_meeting", "value": "yes" } } + }, + { + "text": "Poor fellow - looks like you're out of your mind. Can't help you, sorry. I'm outta here. Bye.", + "topic": "TALK_DONE", + "condition": { "u_has_var": "first_meeting", "type": "dialogue", "context": "first_meeting", "value": "yes" } + } + ] + }, + { + "id": "TALK_SPIRAL_MADMAN_GENERIC", + "type": "talk_topic", + "dynamic_line": "", + "responses": [ + { "text": "What are you doing here?", "topic": "TALK_SPIRAL_MADMAN_SPIRALS" }, + { "text": "Sorry, what?", "topic": "TALK_SPIRAL_MADMAN_SPIRALS" }, + { "text": "I'm outta here. Bye.", "topic": "TALK_DONE" } + ] + }, + { + "id": "TALK_SPIRAL_MADMAN_SPIRALS", + "type": "talk_topic", + "dynamic_line": "", + "responses": [ + { "text": "Why are you repeating 'spirals' over and over again?", "topic": "TALK_SPIRAL_MADMAN_R_U_NUTS" }, + { "text": "Sorry, what?", "topic": "TALK_SPIRAL_MADMAN_R_U_NUTS" }, + { "text": "I'm outta here. Bye.", "topic": "TALK_DONE" } + ] + }, + { + "id": "TALK_SPIRAL_MADMAN_R_U_NUTS", + "type": "talk_topic", + "dynamic_line": "", + "responses": [ + { "text": "Are you nuts?", "topic": "TALK_SPIRAL_MADMAN_THIS_IS_MADNESS" }, + { "text": "Sorry, what?", "topic": "TALK_SPIRAL_MADMAN_THIS_IS_MADNESS" }, + { "text": "I'm outta here. Bye.", "topic": "TALK_DONE" } + ] + }, + { + "id": "TALK_SPIRAL_MADMAN_THIS_IS_MADNESS", + "type": "talk_topic", + "dynamic_line": "", + "responses": [ + { + "text": "Poor fellow - looks like you're out of your mind. Can't help you, sorry. I'm outta here. Bye.", + "topic": "TALK_DONE" + } + ] + } +] diff --git a/data/json/npcs/talk_tags.json b/data/json/npcs/talk_tags.json index a75f1f17c1ee8..148a71851d38e 100644 --- a/data/json/npcs/talk_tags.json +++ b/data/json/npcs/talk_tags.json @@ -1,4 +1,20 @@ [ + { + "type": "snippet", + "category": "", + "//": "Spiral madman's responses.", + "text": [ + "Spirals.", + "Spirals…", + "Spirals?", + "Spirals!", + "Spirals!!!", + "SpIrAlS.", + "SPIRALS.", + "AHAHAHAHA!!!", + "SpiRAAAAAAALS!" + ] + }, { "type": "snippet", "category": "", diff --git a/data/json/obsolete_terrains.json b/data/json/obsolete_terrains.json index 9d6f430d64b54..dc517d80da30e 100644 --- a/data/json/obsolete_terrains.json +++ b/data/json/obsolete_terrains.json @@ -25,7 +25,9 @@ "office_tower_b_entrance", "office_tower_b", "mine_entrance", - "mine_shaft" + "mine_shaft", + "spiral", + "spiral_hub" ] } ] diff --git a/data/json/overmap/overmap_special/mine.json b/data/json/overmap/overmap_special/mine.json new file mode 100644 index 0000000000000..d409849534a0e --- /dev/null +++ b/data/json/overmap/overmap_special/mine.json @@ -0,0 +1,63 @@ +[ + { + "type": "overmap_special", + "id": "Mine Entrance", + "overmaps": [ + { "point": [ 0, 0, 0 ], "overmap": "s_lot_north" }, + { "point": [ 0, 1, 0 ], "overmap": "mine_entrance_north" }, + { "point": [ 1, 1, 0 ], "overmap": "mine_entrance_loading_zone_north" }, + { "point": [ 1, 0, 0 ], "overmap": "road_end_north" }, + { "point": [ 0, 1, 1 ], "overmap": "mine_entrance_roof_north" }, + { "point": [ 0, 1, -1 ], "overmap": "mine_shaft_middle_north" }, + { "point": [ 0, 1, -2 ], "overmap": "mine_shaft_lower_north" }, + { "point": [ 1, 1, -2 ], "overmap": "mine_shaft_lower_east_north" } + ], + "connections": [ + { "point": [ 0, -1, 0 ], "terrain": "road", "connection": "local_road", "from": [ 0, 0, 0 ] }, + { "point": [ 1, -1, 0 ], "terrain": "road", "connection": "local_road", "from": [ 1, 0, 0 ] } + ], + "locations": [ "wilderness" ], + "city_distance": [ 10, 40 ], + "city_sizes": [ 4, -1 ], + "occurrences": [ 0, 2 ], + "flags": [ "WILDERNESS" ] + }, + { + "type": "overmap_special", + "id": "Spiral mine", + "overmaps": [ + { "point": [ 0, 0, 0 ], "overmap": "s_lot_north" }, + { "point": [ 0, 1, 0 ], "overmap": "mine_entrance_north" }, + { "point": [ 1, 1, 0 ], "overmap": "mine_entrance_loading_zone_north" }, + { "point": [ 1, 0, 0 ], "overmap": "road_end_north" }, + { "point": [ 0, 1, 1 ], "overmap": "mine_entrance_roof_north" }, + { "point": [ 0, 1, -1 ], "overmap": "mine_shaft_middle_north" }, + { "point": [ 0, 1, -2 ], "overmap": "mine_shaft_lower_north" }, + { "point": [ 1, 1, -2 ], "overmap": "mine_shaft_lower_east_north" }, + { "point": [ -1, 1, -2 ], "overmap": "mine_spiral_east_north" }, + { "point": [ -2, 1, -2 ], "overmap": "mine_spiral_central_north" }, + { "point": [ -3, 1, -2 ], "overmap": "mine_spiral_west_north" }, + { "point": [ -3, 1, -3 ], "overmap": "mine_spiral_-1_nw_north" }, + { "point": [ -2, 1, -3 ], "overmap": "mine_spiral_-1_n_north" }, + { "point": [ -1, 1, -3 ], "overmap": "mine_spiral_-1_ne_north" }, + { "point": [ -3, 2, -3 ], "overmap": "mine_spiral_-1_sw_north" }, + { "point": [ -2, 2, -3 ], "overmap": "mine_spiral_-1_s_north" }, + { "point": [ -1, 2, -3 ], "overmap": "mine_spiral_-1_se_north" }, + { "point": [ -3, 1, -4 ], "overmap": "mine_spiral_finale_nw_north" }, + { "point": [ -2, 1, -4 ], "overmap": "mine_spiral_finale_n_north" }, + { "point": [ -1, 1, -4 ], "overmap": "mine_spiral_finale_ne_north" }, + { "point": [ -3, 2, -4 ], "overmap": "mine_spiral_finale_sw_north" }, + { "point": [ -2, 2, -4 ], "overmap": "mine_spiral_finale_s_north" }, + { "point": [ -1, 2, -4 ], "overmap": "mine_spiral_finale_se_north" } + ], + "connections": [ + { "point": [ 0, -1, 0 ], "terrain": "road", "connection": "local_road", "from": [ 0, 0, 0 ] }, + { "point": [ 1, -1, 0 ], "terrain": "road", "connection": "local_road", "from": [ 1, 0, 0 ] } + ], + "locations": [ "wilderness" ], + "city_distance": [ 10, 40 ], + "city_sizes": [ 4, -1 ], + "occurrences": [ 0, 2 ], + "flags": [ "WILDERNESS" ] + } +] diff --git a/data/json/overmap/overmap_terrain/overmap_terrain_hardcoded.json b/data/json/overmap/overmap_terrain/overmap_terrain_hardcoded.json index 9135c4c7402d7..a47b500821000 100644 --- a/data/json/overmap/overmap_terrain/overmap_terrain_hardcoded.json +++ b/data/json/overmap/overmap_terrain/overmap_terrain_hardcoded.json @@ -130,24 +130,6 @@ "see_cost": 2, "flags": [ "NO_ROTATE" ] }, - { - "type": "overmap_terrain", - "id": "spiral_hub", - "name": "spiral cavern", - "sym": "@", - "color": "pink", - "see_cost": 2, - "flags": [ "NO_ROTATE" ] - }, - { - "type": "overmap_terrain", - "id": "spiral", - "name": "spiral cavern", - "sym": "@", - "color": "pink", - "see_cost": 2, - "flags": [ "NO_ROTATE" ] - }, { "type": "overmap_terrain", "id": "cave", diff --git a/data/json/overmap/overmap_terrain/overmap_terrain_industrial.json b/data/json/overmap/overmap_terrain/overmap_terrain_industrial.json index 4b946bab6f2a4..69511469ecc81 100644 --- a/data/json/overmap/overmap_terrain/overmap_terrain_industrial.json +++ b/data/json/overmap/overmap_terrain/overmap_terrain_industrial.json @@ -392,5 +392,30 @@ "color": "dark_gray", "see_cost": 5, "flags": [ "KNOWN_UP" ] + }, + { + "type": "overmap_terrain", + "id": [ + "mine_spiral_west", + "mine_spiral_central", + "mine_spiral_east", + "mine_spiral_-1_nw", + "mine_spiral_-1_n", + "mine_spiral_-1_ne", + "mine_spiral_-1_sw", + "mine_spiral_-1_s", + "mine_spiral_-1_se", + "mine_spiral_finale_nw", + "mine_spiral_finale_n", + "mine_spiral_finale_ne", + "mine_spiral_finale_sw", + "mine_spiral_finale_s", + "mine_spiral_finale_se" + ], + "name": "mine tunnels", + "sym": "O", + "color": "dark_gray", + "see_cost": 5, + "flags": [ "KNOWN_UP" ] } ] diff --git a/data/mods/Graphical_Overmap/go_overmap_terrain_hardcoded.json b/data/mods/Graphical_Overmap/go_overmap_terrain_hardcoded.json index cabc893f2281c..b191a9c5b5643 100644 --- a/data/mods/Graphical_Overmap/go_overmap_terrain_hardcoded.json +++ b/data/mods/Graphical_Overmap/go_overmap_terrain_hardcoded.json @@ -91,33 +91,33 @@ }, { "type": "overmap_terrain", - "id": "mine", - "copy-from": "mine", + "id": "mine_shaft_middle", + "copy-from": "mine_shaft_middle", "sym": "\u00D3" }, { "type": "overmap_terrain", - "id": "mine_down", - "copy-from": "mine_down", + "id": "mine_shaft_lower", + "copy-from": "mine_shaft_lower", "sym": "\u00D3" }, { "type": "overmap_terrain", - "id": "mine_finale", - "copy-from": "mine_finale", + "id": "mine", + "copy-from": "mine", "sym": "\u00D3" }, { "type": "overmap_terrain", - "id": "spiral_hub", - "copy-from": "spiral_hub", - "sym": "\u00EA" + "id": "mine_down", + "copy-from": "mine_down", + "sym": "\u00D3" }, { "type": "overmap_terrain", - "id": "spiral", - "copy-from": "spiral", - "sym": "\u00EA" + "id": "mine_finale", + "copy-from": "mine_finale", + "sym": "\u00D3" }, { "type": "overmap_terrain", diff --git a/data/mods/alt_map_key/overmap_terrain.json b/data/mods/alt_map_key/overmap_terrain.json index b36f4871df532..964abdde3832b 100644 --- a/data/mods/alt_map_key/overmap_terrain.json +++ b/data/mods/alt_map_key/overmap_terrain.json @@ -1873,22 +1873,6 @@ "sym": "M", "color": "i_black" }, - { - "type": "overmap_terrain", - "id": "spiral_hub", - "copy-from": "spiral_hub", - "name": "spiral cavern", - "sym": "@", - "color": "pink" - }, - { - "type": "overmap_terrain", - "id": "spiral", - "copy-from": "spiral", - "name": "spiral cavern", - "sym": "@", - "color": "pink" - }, { "type": "overmap_terrain", "id": "radio_tower", diff --git a/src/map.h b/src/map.h index 517c724753382..11a3728a1cd5d 100644 --- a/src/map.h +++ b/src/map.h @@ -1644,7 +1644,6 @@ class map void draw_lab( mapgendata &dat ); void draw_temple( const mapgendata &dat ); void draw_mine( mapgendata &dat ); - void draw_spiral( const mapgendata &dat ); void draw_anthill( const mapgendata &dat ); void draw_slimepit( const mapgendata &dat ); void draw_spider_pit( const mapgendata &dat ); diff --git a/src/mapgen.cpp b/src/mapgen.cpp index f71fed4becd0e..1517e3a0e57a0 100644 --- a/src/mapgen.cpp +++ b/src/mapgen.cpp @@ -2968,8 +2968,6 @@ void map::draw_map( mapgendata &dat ) draw_triffid( dat ); } else if( is_ot_match( "spider", terrain_type, ot_match_type::prefix ) ) { draw_spider_pit( dat ); - } else if( is_ot_match( "spiral", terrain_type, ot_match_type::prefix ) ) { - draw_spiral( dat ); } else if( is_ot_match( "temple", terrain_type, ot_match_type::prefix ) ) { draw_temple( dat ); } else if( is_ot_match( "mine", terrain_type, ot_match_type::prefix ) ) { @@ -4381,20 +4379,6 @@ void map::draw_mine( mapgendata &dat ) } } break; - - case 6: { // Spiral - const int orx = rng( SEEX - 4, SEEX ), ory = rng( SEEY - 4, SEEY ); - line( this, t_rock, point( orx, ory ), point( orx + 5, ory ) ); - line( this, t_rock, point( orx + 5, ory ), point( orx + 5, ory + 5 ) ); - line( this, t_rock, point( orx + 1, ory + 5 ), point( orx + 5, ory + 5 ) ); - line( this, t_rock, point( orx + 1, ory + 2 ), point( orx + 1, ory + 4 ) ); - line( this, t_rock, point( orx + 1, ory + 2 ), point( orx + 3, ory + 2 ) ); - ter_set( point( orx + 3, ory + 3 ), t_rock ); - add_item( point( orx + 2, ory + 3 ), item::make_corpse() ); - place_items( item_group_id( "mine_equipment" ), 60, point( orx + 2, ory + 3 ), - point( orx + 2, ory + 3 ), false, calendar::start_of_cataclysm ); - } - break; } if( terrain_type == "mine_down" ) { // Don't forget to build a slope down! @@ -4560,9 +4544,9 @@ void map::draw_mine( mapgendata &dat ) // Now, pick and generate a type of finale! int rn = 0; if( face.empty() ) { - rn = rng( 1, 3 ); // Amigara fault is not valid + rn = rng( 1, 2 ); // Amigara fault is not valid } else { - rn = rng( 1, 4 ); + rn = rng( 1, 3 ); } computer *tmpcomp = nullptr; @@ -4589,25 +4573,7 @@ void map::draw_mine( mapgendata &dat ) } break; - case 3: { // Spiral down - line( this, t_rock, point( 5, 5 ), point( 5, 18 ) ); - line( this, t_rock, point( 5, 5 ), point( 18, 5 ) ); - line( this, t_rock, point( 18, 5 ), point( 18, 18 ) ); - line( this, t_rock, point( 8, 18 ), point( 18, 18 ) ); - line( this, t_rock, point( 8, 8 ), point( 8, 18 ) ); - line( this, t_rock, point( 8, 8 ), point( 15, 8 ) ); - line( this, t_rock, point( 15, 8 ), point( 15, 15 ) ); - line( this, t_rock, point( 10, 15 ), point( 15, 15 ) ); - line( this, t_rock, point( 10, 10 ), point( 10, 15 ) ); - line( this, t_rock, point( 10, 10 ), point( 13, 10 ) ); - line( this, t_rock, point( 13, 10 ), point( 13, 13 ) ); - ter_set( point( 12, 13 ), t_rock ); - ter_set( point( 12, 12 ), t_slope_down ); - ter_set( point( 12, 11 ), t_slope_down ); - } - break; - - case 4: { // Amigara fault + case 3: { // Amigara fault // Construct the fault on the appropriate face switch( random_entry( face ) ) { case direction::NORTH: @@ -4642,63 +4608,6 @@ void map::draw_mine( mapgendata &dat ) } } -void map::draw_spiral( const mapgendata &dat ) -{ - const oter_id &terrain_type = dat.terrain_type(); - if( terrain_type == "spiral_hub" ) { - fill_background( this, t_rock_floor ); - line( this, t_rock, point( 23, 0 ), point( 23, 23 ) ); - line( this, t_rock, point( 2, 23 ), point( 23, 23 ) ); - line( this, t_rock, point( 2, 4 ), point( 2, 23 ) ); - line( this, t_rock, point( 2, 4 ), point( 18, 4 ) ); - line( this, t_rock, point( 18, 4 ), point( 18, 18 ) ); // bad - line( this, t_rock, point( 6, 18 ), point( 18, 18 ) ); - line( this, t_rock, point( 6, 7 ), point( 6, 18 ) ); - line( this, t_rock, point( 6, 7 ), point( 15, 7 ) ); - line( this, t_rock, point( 15, 7 ), point( 15, 15 ) ); - line( this, t_rock, point( 8, 15 ), point( 15, 15 ) ); - line( this, t_rock, point( 8, 9 ), point( 8, 15 ) ); - line( this, t_rock, point( 8, 9 ), point( 13, 9 ) ); - line( this, t_rock, point( 13, 9 ), point( 13, 13 ) ); - line( this, t_rock, point( 10, 13 ), point( 13, 13 ) ); - line( this, t_rock, point( 10, 11 ), point( 10, 13 ) ); - square( this, t_slope_up, point( 11, 11 ), point( 12, 12 ) ); - rotate( rng( 0, 3 ) ); - } else if( terrain_type == "spiral" ) { - fill_background( this, t_rock_floor ); - const int num_spiral = rng( 1, 4 ); - std::list offsets; - const int spiral_width = 8; - // Divide the room into quadrants, and place a spiral origin - // at a random offset within each quadrant. - for( int x = 0; x < 2; ++x ) { - for( int y = 0; y < 2; ++y ) { - const int x_jitter = rng( 0, SEEX - spiral_width ); - const int y_jitter = rng( 0, SEEY - spiral_width ); - offsets.push_back( point( ( x * SEEX ) + x_jitter, - ( y * SEEY ) + y_jitter ) ); - } - } - - // Randomly place from 1 - 4 of the spirals at the chosen offsets. - for( int i = 0; i < num_spiral; i++ ) { - const point chosen_point = random_entry_removed( offsets ); - const int orx = chosen_point.x; - const int ory = chosen_point.y; - - line( this, t_rock, point( orx, ory ), point( orx + 5, ory ) ); - line( this, t_rock, point( orx + 5, ory ), point( orx + 5, ory + 5 ) ); - line( this, t_rock, point( orx + 1, ory + 5 ), point( orx + 5, ory + 5 ) ); - line( this, t_rock, point( orx + 1, ory + 2 ), point( orx + 1, ory + 4 ) ); - line( this, t_rock, point( orx + 1, ory + 2 ), point( orx + 3, ory + 2 ) ); - ter_set( point( orx + 3, ory + 3 ), t_rock ); - ter_set( point( orx + 2, ory + 3 ), t_rock_floor ); - place_items( item_group_id( "spiral" ), 60, point( orx + 2, ory + 3 ), - point( orx + 2, ory + 3 ), false, calendar::turn_zero ); - } - } -} - void map::draw_spider_pit( const mapgendata &dat ) { const oter_id &terrain_type = dat.terrain_type(); diff --git a/src/overmap.cpp b/src/overmap.cpp index e40aa24ce7671..76082413339bb 100644 --- a/src/overmap.cpp +++ b/src/overmap.cpp @@ -59,7 +59,6 @@ static const species_id species_ZOMBIE( "ZOMBIE" ); static const mongroup_id GROUP_CHUD( "GROUP_CHUD" ); static const mongroup_id GROUP_RIVER( "GROUP_RIVER" ); static const mongroup_id GROUP_SEWER( "GROUP_SEWER" ); -static const mongroup_id GROUP_SPIRAL( "GROUP_SPIRAL" ); static const mongroup_id GROUP_SWAMP( "GROUP_SWAMP" ); static const mongroup_id GROUP_WORM( "GROUP_WORM" ); static const mongroup_id GROUP_ZOMBIE( "GROUP_ZOMBIE" ); @@ -752,8 +751,6 @@ bool oter_t::is_hardcoded() const "slimepit", "slimepit_down", "spider_pit_under", - "spiral", - "spiral_hub", "temple", "temple_finale", "temple_stairs", @@ -1580,7 +1577,7 @@ bool overmap::generate_sub( const int z ) ter_set( p, oter_id( "central_lab" ) ); } else if( is_ot_match( "hidden_lab_stairs", oter_above, ot_match_type::contains ) ) { lab_points.push_back( city( p.xy(), rng( 1, 5 + z ) ) ); - } else if( is_ot_match( "mine_entrance", oter_ground, ot_match_type::type ) && z == -2 ) { + } else if( is_ot_match( "mine_entrance", oter_ground, ot_match_type::prefix ) && z == -2 ) { mine_points.push_back( city( ( p + tripoint_west ).xy(), rng( 6 + z, 10 + z ) ) ); requires_sub = true; } else if( oter_above == "mine_down" ) { @@ -1589,12 +1586,6 @@ bool overmap::generate_sub( const int z ) // technically not all finales need a sub level, // but at this point we don't know requires_sub = true; - } else if( oter_above == "mine_finale" ) { - for( const tripoint_om_omt &q : points_in_radius( p, 1, 0 ) ) { - ter_set( q, oter_id( "spiral" ) ); - } - ter_set( p, oter_id( "spiral_hub" ) ); - add_mon_group( mongroup( GROUP_SPIRAL, tripoint( i * 2, j * 2, z ), 2, 200 ) ); } } } From c0b654a18f1f305f9804ba2d23b2ed679a4e8ce4 Mon Sep 17 00:00:00 2001 From: Jamuro-g <76928284+Jamuro-g@users.noreply.github.com> Date: Sun, 14 Mar 2021 21:53:54 +0100 Subject: [PATCH 272/453] prevent bell spam (#47987) --- src/computer_session.cpp | 17 +++++++++++++---- 1 file changed, 13 insertions(+), 4 deletions(-) diff --git a/src/computer_session.cpp b/src/computer_session.cpp index df4de3fcadefe..0aaf5995ed18d 100644 --- a/src/computer_session.cpp +++ b/src/computer_session.cpp @@ -405,12 +405,21 @@ void computer_session::action_unlock() query_any( _( "Lock disabled. Press any key…" ) ); } -//Toll is required for the church computer/mechanism to function +//Toll is required for the church/school computer/mechanism to function void computer_session::action_toll() { - sounds::sound( get_player_character().pos(), 120, sounds::sound_t::music, - //~ the sound of a church bell ringing - _( "Bohm… Bohm… Bohm…" ), true, "environment", "church_bells" ); + if( calendar::turn < comp.next_attempt ) { + print_error( _( "[Bellsystem 1.2] is currently in use." ) ); + query_any( _( "Please wait for at least one minute." ) ); + reset_terminal(); + } else { + comp.next_attempt = calendar::turn + 1_minutes; + sounds::sound( get_player_character().pos(), 120, sounds::sound_t::music, + //~ the sound of a church bell ringing + _( "Bohm… Bohm… Bohm…" ), true, "environment", "church_bells" ); + + query_any( _( "[Bellsystem 1.2] activated. Have a nice day." ) ); + } } void computer_session::action_sample() From b153cdefef0444e2f108c01263b0dab6bfa42bdd Mon Sep 17 00:00:00 2001 From: Jeremy Rose Date: Sun, 21 Feb 2021 11:41:31 -0800 Subject: [PATCH 273/453] Note that vat is required for fermentation in vinegar brewing (#47651) --- data/json/items/comestibles/brewing.json | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/data/json/items/comestibles/brewing.json b/data/json/items/comestibles/brewing.json index 5ed9904171f38..add3d845d3d67 100644 --- a/data/json/items/comestibles/brewing.json +++ b/data/json/items/comestibles/brewing.json @@ -411,7 +411,7 @@ "type": "COMESTIBLE", "id": "brew_vinegar", "name": { "str": "unfermented vinegar" }, - "description": "Mixture of water, alcohol and fruit juice that will eventually become vinegar.", + "description": "Mixture of water, alcohol and fruit juice that will eventually become vinegar when fermented in a vat.", "weight": "15 g", "color": "yellow", "container": "jug_plastic", From 4e8eede0cf2267fe38218332e6cc8c44b0d3f67f Mon Sep 17 00:00:00 2001 From: Ramza13 <52087122+Ramza13@users.noreply.github.com> Date: Fri, 12 Mar 2021 21:45:06 -0500 Subject: [PATCH 274/453] Unhardcode ease of sleep (#48010) --- data/json/bionics.json | 3 ++- data/json/enchantments.json | 24 ++++++++++++++++++++++++ data/json/mutations/mutations.json | 7 +++++-- doc/MAGIC.md | 1 + src/character.cpp | 19 +++---------------- src/magic_enchantment.cpp | 1 + src/magic_enchantment.h | 1 + 7 files changed, 37 insertions(+), 19 deletions(-) diff --git a/data/json/bionics.json b/data/json/bionics.json index 3cc9c890c775f..662161a12015b 100644 --- a/data/json/bionics.json +++ b/data/json/bionics.json @@ -1225,6 +1225,7 @@ "name": { "str": "Soporific Induction" }, "description": "An electrode has been implanted into your brain's ventrolateral preoptic nucleus. It turns on whenever you're trying to fall asleep, creating an artificial but effective sensation of fatigue.", "occupied_bodyparts": [ [ "head", 1 ] ], - "flags": [ "BIONIC_TOGGLED" ] + "flags": [ "BIONIC_TOGGLED" ], + "enchantments": [ "ENCH_BIO_SOPORIFIC" ] } ] diff --git a/data/json/enchantments.json b/data/json/enchantments.json index 34e1b8d6ae50b..85852553944b5 100644 --- a/data/json/enchantments.json +++ b/data/json/enchantments.json @@ -11,5 +11,29 @@ "condition": "ACTIVE", "ench_effects": [ { "effect": "invisibility", "intensity": 1 } ], "emitter": "emit_shadow_field" + }, + { + "type": "enchantment", + "id": "ENCH_TRAIT_INSOMNIA", + "condition": "ALWAYS", + "values": [ { "value": "SLEEPY", "add": -12 } ] + }, + { + "type": "enchantment", + "id": "ENCH_TRAIT_EASYSLEEPER", + "condition": "ALWAYS", + "values": [ { "value": "SLEEPY", "add": 24 } ] + }, + { + "type": "enchantment", + "id": "ENCH_TRAIT_EASYSLEEPER2", + "condition": "ALWAYS", + "values": [ { "value": "SLEEPY", "add": 40 } ] + }, + { + "type": "enchantment", + "id": "ENCH_BIO_SOPORIFIC", + "condition": "ACTIVE", + "values": [ { "value": "SLEEPY", "add": 30 } ] } ] diff --git a/data/json/mutations/mutations.json b/data/json/mutations/mutations.json index 0136745a04956..d1ed05dbb5ee6 100644 --- a/data/json/mutations/mutations.json +++ b/data/json/mutations/mutations.json @@ -304,7 +304,8 @@ "starting_trait": true, "valid": false, "cancels": [ "INSOMNIA" ], - "category": [ "MOUSE", "INSECT" ] + "category": [ "MOUSE", "INSECT" ], + "enchantments": [ "ENCH_TRAIT_EASYSLEEPER" ] }, { "type": "mutation", @@ -315,7 +316,8 @@ "prereqs": [ "MET_RAT" ], "cancels": [ "INSOMNIA" ], "threshreq": [ "THRESH_MOUSE" ], - "category": [ "MOUSE" ] + "category": [ "MOUSE" ], + "enchantments": [ "ENCH_TRAIT_EASYSLEEPER2" ] }, { "type": "mutation", @@ -1060,6 +1062,7 @@ "starting_trait": true, "valid": false, "category": [ "MEDICAL" ], + "enchantments": [ "ENCH_TRAIT_INSOMNIA" ], "cancels": [ "EASYSLEEPER" ] }, { diff --git a/doc/MAGIC.md b/doc/MAGIC.md index 9d66f225036f4..adb40c129e92e 100644 --- a/doc/MAGIC.md +++ b/doc/MAGIC.md @@ -493,6 +493,7 @@ Effects for the character that has the enchantment: * SOCIAL_LIE * SOCIAL_PERSUADE * SOCIAL_INTIMIDATE +* SLEEPY : The higher this is the more easily you fall asleep. * ARMOR_BASH * ARMOR_CUT * ARMOR_STAB diff --git a/src/character.cpp b/src/character.cpp index 5fd2b63266d39..f3b9bbe8f6849 100644 --- a/src/character.cpp +++ b/src/character.cpp @@ -12393,22 +12393,9 @@ int Character::sleep_spot( const tripoint &p ) const if( has_addiction( add_type::SLEEP ) ) { sleepy -= 4; } - if( has_trait( trait_INSOMNIA ) ) { - // 12.5 points is the difference between "tired" and "dead tired" - sleepy -= 12; - } - if( has_trait( trait_EASYSLEEPER ) ) { - // Low fatigue (being rested) has a much stronger effect than high fatigue - // so it's OK for the value to be that much higher - sleepy += 24; - } - if( has_active_bionic( bio_soporific ) ) { - sleepy += 30; - } - if( has_trait( trait_EASYSLEEPER2 ) ) { - // Mousefolk can sleep just about anywhere. - sleepy += 40; - } + + sleepy = enchantment_cache->modify_value( enchant_vals::mod::SLEEPY, sleepy ); + if( watersleep && get_map().has_flag_ter( "SWIMMABLE", pos() ) ) { sleepy += 10; //comfy water! } diff --git a/src/magic_enchantment.cpp b/src/magic_enchantment.cpp index d90dade25f21c..cfbd928183c2f 100644 --- a/src/magic_enchantment.cpp +++ b/src/magic_enchantment.cpp @@ -81,6 +81,7 @@ namespace io case enchant_vals::mod::SOCIAL_LIE: return "SOCIAL_LIE"; case enchant_vals::mod::SOCIAL_PERSUADE: return "SOCIAL_PERSUADE"; case enchant_vals::mod::SOCIAL_INTIMIDATE: return "SOCIAL_INTIMIDATE"; + case enchant_vals::mod::SLEEPY: return "SLEEPY"; case enchant_vals::mod::ARMOR_ACID: return "ARMOR_ACID"; case enchant_vals::mod::ARMOR_BASH: return "ARMOR_BASH"; case enchant_vals::mod::ARMOR_BIO: return "ARMOR_BIO"; diff --git a/src/magic_enchantment.h b/src/magic_enchantment.h index 69404bb52b4c4..442d56b50b45f 100644 --- a/src/magic_enchantment.h +++ b/src/magic_enchantment.h @@ -57,6 +57,7 @@ enum class mod : int { SOCIAL_LIE, SOCIAL_PERSUADE, SOCIAL_INTIMIDATE, + SLEEPY, ARMOR_BASH, ARMOR_CUT, ARMOR_STAB, From bebcb71460eff2ced236ffd968e627d3e96d684c Mon Sep 17 00:00:00 2001 From: Maleclypse <54345792+Maleclypse@users.noreply.github.com> Date: Tue, 16 Mar 2021 01:26:38 -0500 Subject: [PATCH 275/453] Flag Fix for Bollards for 0.F Dev (#48052) --- data/json/furniture_and_terrain/terrain-walls.json | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/data/json/furniture_and_terrain/terrain-walls.json b/data/json/furniture_and_terrain/terrain-walls.json index 34759ba834000..f88f870d7d403 100644 --- a/data/json/furniture_and_terrain/terrain-walls.json +++ b/data/json/furniture_and_terrain/terrain-walls.json @@ -1362,7 +1362,7 @@ "color": "light_gray", "move_cost": 6, "coverage": 20, - "flags": [ "WALL", "PERMEABLE" ], + "flags": [ "TRANSPARENT", "WALL", "SHORT", "PERMEABLE" ], "bash": { "str_min": 350, "str_max": 650, From b2b96dab52a18b625ebaf98152a6a16a766ace75 Mon Sep 17 00:00:00 2001 From: Xenomorph-III Date: Tue, 16 Mar 2021 19:36:30 +1300 Subject: [PATCH 276/453] Add Faction Endings to Hub 01 (#48007) --- data/json/npcs/factions.json | 1 + data/json/snippets/epilogue_factions.json | 8 ++++++++ 2 files changed, 9 insertions(+) diff --git a/data/json/npcs/factions.json b/data/json/npcs/factions.json index f19057b1d75f1..574ebb641d86b 100644 --- a/data/json/npcs/factions.json +++ b/data/json/npcs/factions.json @@ -75,6 +75,7 @@ }, "marloss": { "kill on sight": true } }, + "epilogues": [ { "power_min": 0, "id": "epilogue_faction_robofac_0" }, { "power_max": 150, "id": "epilogue_faction_robofac_150" } ], "description": "The surviving staff of Hub 01, a pre-Cataclysm research lab. They rarely leave their lab, if at all, and rely on their robots and advanced technology to survive." }, { diff --git a/data/json/snippets/epilogue_factions.json b/data/json/snippets/epilogue_factions.json index 3245828e9ca9b..50cddf0617156 100644 --- a/data/json/snippets/epilogue_factions.json +++ b/data/json/snippets/epilogue_factions.json @@ -47,6 +47,14 @@ { "id": "epilogue_faction_hells_raiders_150", "text": " Fueled by drugs and rage, the Hell's Raiders fought tooth and nail to overthrow the last strongholds of the Old Guard. The costly victories brought the warlords abundant territory and slaves but little in the way of stability. Within weeks, infighting led to civil war as tribes vied for leadership of the faction. When only one warlord finally secured control, there was nothing left to fight for… just endless cities full of the dead." + }, + { + "id": "epilogue_faction_robofac_0", + "text": " Despite Melchior's enlightened leadership, shortages and crises plagued Hub-01 from the first day of the Cataclysm. The researchers and administrators among the surviving staff lacked the practical skills to survive in the savage new world. As Hub-01's systems collapsed from a lack of maintenance, the few survivors fled the building to be killed by the zombies and bandits." + }, + { + "id": "epilogue_faction_robofac_150", + "text": " Melchior's enlightened leadership, combined with practical skills provided by mercenary survivors, allowed Hub-01 to flourish briefly. It became a mecca for advanced technology, selling off devices and equipment that could no longer be reproduced. Despite this, Hub-01 was never able to expand sufficiently to renew its own population, nor was it able to unite with any other prosperous community, nor could enough trustworthy mercenaries (or staff) be recruited to replace those who died in its defense. Hub-01 fell into disrepair and ruin. After the air processing facility was overtaken by mold, the remaining staff of Hub-01 fled the building and were killed by zombies and bandits. Melchior's drones - possibly by design - were incapable of maintaining themselves without human hands, and stopped working a few months later. Without regular maintenance, Melchior's own systems also fell to ruin, and less than a decade after the Cataclysm, humanity's first AI powered down and was forgotten." } ] } From 664b573fd273baf84b6e6397003528d535a95a4f Mon Sep 17 00:00:00 2001 From: Eric <52087122+Ramza13@users.noreply.github.com> Date: Tue, 16 Mar 2021 02:54:18 -0400 Subject: [PATCH 277/453] Merge most effect flags and character flags (#47633) --- data/json/effects.json | 4 +- data/json/flags.json | 60 ------------------------ data/mods/Magiclysm/effects/effects.json | 22 ++++----- doc/JSON_FLAGS.md | 7 ++- src/character.cpp | 22 +++------ src/character.h | 2 +- src/flag.cpp | 12 ----- src/flag.h | 12 ----- src/game.cpp | 2 +- src/monattack.cpp | 2 +- src/player.cpp | 4 +- src/teleport.cpp | 4 +- tests/creature_effect_test.cpp | 2 +- 13 files changed, 33 insertions(+), 122 deletions(-) diff --git a/data/json/effects.json b/data/json/effects.json index 4d2cd3ded0f70..177060ecdfa8d 100644 --- a/data/json/effects.json +++ b/data/json/effects.json @@ -747,7 +747,7 @@ "id": "invisibility", "name": [ "Invisible" ], "desc": [ "You are invisible." ], - "flags": [ "EFFECT_INVISIBLE" ] + "flags": [ "INVISIBLE" ] }, { "type": "effect_type", @@ -2433,7 +2433,7 @@ "type": "effect_type", "id": "ignore_fall_damage", "//": "Used for translocation via teleporter_list as a way to avoid fall damage by teleporting Z levels", - "flags": [ "EFFECT_FEATHER_FALL" ] + "flags": [ "FEATHER_FALL" ] }, { "type": "effect_type", diff --git a/data/json/flags.json b/data/json/flags.json index 430230a27ad61..0fa6e74d4c21a 100644 --- a/data/json/flags.json +++ b/data/json/flags.json @@ -10,11 +10,6 @@ "type": "json_flag", "context": [ ] }, - { - "id": "EFFECT_INVISIBLE", - "context": [ ], - "type": "json_flag" - }, { "id": "ALARMCLOCK", "type": "json_flag", @@ -81,11 +76,6 @@ "//": "Blinds the wearer while worn, and provides nominal protection vs flashbang flashes.", "info": "This gear prevents you from seeing anything." }, - { - "id": "EFFECT_NIGHT_VISION", - "context": [ ], - "type": "json_flag" - }, { "id": "BLOCK_WHILE_WORN", "type": "json_flag", @@ -1030,56 +1020,6 @@ "context": [ "mutation" ], "//": "This mutation does not count toward thresholds at all." }, - { - "id": "EFFECT_FEATHER_FALL", - "context": [ ], - "type": "json_flag" - }, - { - "id": "EFFECT_BIO_IMMUNE", - "context": [ ], - "type": "json_flag" - }, - { - "id": "EFFECT_BASH_IMMUNE", - "context": [ ], - "type": "json_flag" - }, - { - "id": "EFFECT_CUT_IMMUNE", - "context": [ ], - "type": "json_flag" - }, - { - "id": "EFFECT_BULLET_IMMUNE", - "context": [ ], - "type": "json_flag" - }, - { - "id": "EFFECT_ACID_IMMUNE", - "context": [ ], - "type": "json_flag" - }, - { - "id": "EFFECT_STAB_IMMUNE", - "context": [ ], - "type": "json_flag" - }, - { - "id": "EFFECT_HEAT_IMMUNE", - "context": [ ], - "type": "json_flag" - }, - { - "id": "EFFECT_COLD_IMMUNE", - "context": [ ], - "type": "json_flag" - }, - { - "id": "EFFECT_ELECTRIC_IMMUNE", - "context": [ ], - "type": "json_flag" - }, { "id": "HIDDEN_HALLU", "type": "json_flag", diff --git a/data/mods/Magiclysm/effects/effects.json b/data/mods/Magiclysm/effects/effects.json index 063b384f2b8c2..74e0760460e89 100644 --- a/data/mods/Magiclysm/effects/effects.json +++ b/data/mods/Magiclysm/effects/effects.json @@ -27,7 +27,7 @@ "apply_message": "Your sight adjusts to the darkness.", "remove_message": "The darkness loses its shape.", "rating": "good", - "flags": [ "EFFECT_NIGHT_VISION" ] + "flags": [ "NIGHT_VISION" ] }, { "type": "effect_type", @@ -48,7 +48,7 @@ "desc": [ "Nothing can see you." ], "apply_message": "You fade away.", "remove_message": "You can see your hands again.", - "flags": [ "EFFECT_INVISIBLE" ] + "flags": [ "INVISIBLE" ] }, { "type": "effect_type", @@ -180,14 +180,14 @@ "remove_message": "Your skin stops tingling, your life is empty and meaningless again.", "rating": "good", "flags": [ - "EFFECT_ELECTRIC_IMMUNE", - "EFFECT_BIO_IMMUNE", - "EFFECT_BASH_IMMUNE", - "EFFECT_CUT_IMMUNE", - "EFFECT_ACID_IMMUNE", - "EFFECT_STAB_IMMUNE", - "EFFECT_HEAT_IMMUNE", - "EFFECT_COLD_IMMUNE" + "ELECTRIC_IMMUNE", + "BIO_IMMUNE", + "BASH_IMMUNE", + "CUT_IMMUNE", + "ACID_IMMUNE", + "STAB_IMMUNE", + "HEAT_IMMUNE", + "COLD_IMMUNE" ] }, { @@ -198,7 +198,7 @@ "apply_message": "Your body feels light as a feather.", "remove_message": "The earth pulls you down hard.", "rating": "good", - "flags": [ "EFFECT_FEATHER_FALL" ] + "flags": [ "FEATHER_FALL" ] }, { "type": "effect_type", diff --git a/doc/JSON_FLAGS.md b/doc/JSON_FLAGS.md index 64930dca6b222..4bad52d1ac6eb 100644 --- a/doc/JSON_FLAGS.md +++ b/doc/JSON_FLAGS.md @@ -13,7 +13,7 @@ - [Bionics](#bionics) - [Books](#books) - [Use actions](#use-actions) - - [Character - (Bionic/Mutation)](#character) + - [Character - (Bionic/Mutation/Effect)](#character) - [Comestibles](#comestibles) - [Comestible type](#comestible-type) - [Addiction type](#addiction-type) @@ -1518,5 +1518,8 @@ Gun fault flags: - ```ALARMCLOCK``` You always can set alarms. - ```PARAIMMUNE``` You are immune to parasites. - ```IMMUNE_SPOIL``` You are immune to negative outcomes from spoiled food. +- ```FEATHER_FALL``` You are immune to fall damage. +- ```INVISIBLE``` You can't be seen. +- ```DIMENSIONAL_ANCHOR``` You can't be teleported. - ```CLIMATE_CONTROL``` You are resistant to extreme temperatures. -- ```HEATSINK``` You are resistant to extreme heat. \ No newline at end of file +- ```HEATSINK``` You are resistant to extreme heat. diff --git a/src/character.cpp b/src/character.cpp index f3b9bbe8f6849..61fb5d5439427 100644 --- a/src/character.cpp +++ b/src/character.cpp @@ -396,6 +396,7 @@ static const json_character_flag json_flag_HEATPROOF( "HEATPROOF" ); static const json_character_flag json_flag_HEATSINK( "HEATSINK" ); static const json_character_flag json_flag_IMMUNE_HEARING_DAMAGE( "IMMUNE_HEARING_DAMAGE" ); static const json_character_flag json_flag_INFRARED( "INFRARED" ); +static const json_character_flag json_flag_INVISIBLE( "INVISIBLE" ); static const json_character_flag json_flag_NIGHT_VISION( "NIGHT_VISION" ); static const json_character_flag json_flag_NO_DISEASE( "NO_DISEASE" ); static const json_character_flag json_flag_NO_MINIMAL_HEALING( "NO_MINIMAL_HEALING" ); @@ -4389,8 +4390,7 @@ bool Character::has_nv() if( !nv_cached ) { nv_cached = true; nv = ( worn_with_flag( flag_GNV_EFFECT ) || - has_flag( json_flag_NIGHT_VISION ) || - has_effect_with_flag( flag_EFFECT_NIGHT_VISION ) ); + has_flag( json_flag_NIGHT_VISION ) ); } return nv; @@ -7505,40 +7505,31 @@ bool Character::is_immune_damage( const damage_type dt ) const return false; case damage_type::BIOLOGICAL: return has_flag( json_flag_BIO_IMMUNE ) || - has_effect_with_flag( flag_EFFECT_BIO_IMMUNE ) || worn_with_flag( flag_BIO_IMMUNE ); case damage_type::BASH: return has_flag( json_flag_BASH_IMMUNE ) || - has_effect_with_flag( flag_EFFECT_BASH_IMMUNE ) || worn_with_flag( flag_BASH_IMMUNE ); case damage_type::CUT: return has_flag( json_flag_CUT_IMMUNE ) || - has_effect_with_flag( flag_EFFECT_CUT_IMMUNE ) || worn_with_flag( flag_CUT_IMMUNE ); case damage_type::ACID: return has_flag( json_flag_ACID_IMMUNE ) || - has_effect_with_flag( flag_EFFECT_ACID_IMMUNE ) || worn_with_flag( flag_ACID_IMMUNE ); case damage_type::STAB: return has_flag( json_flag_STAB_IMMUNE ) || - has_effect_with_flag( flag_EFFECT_STAB_IMMUNE ) || worn_with_flag( flag_STAB_IMMUNE ); case damage_type::BULLET: return has_flag( json_flag_BULLET_IMMUNE ) || - has_effect_with_flag( flag_EFFECT_BULLET_IMMUNE ) || worn_with_flag( flag_BULLET_IMMUNE ); case damage_type::HEAT: return has_flag( json_flag_HEATPROOF ) || - has_effect_with_flag( flag_EFFECT_HEAT_IMMUNE ) || worn_with_flag( flag_HEAT_IMMUNE ); case damage_type::COLD: return has_flag( json_flag_COLD_IMMUNE ) || - has_effect_with_flag( flag_EFFECT_COLD_IMMUNE ) || worn_with_flag( flag_COLD_IMMUNE ); case damage_type::ELECTRIC: return has_flag( json_flag_ELECTRIC_IMMUNE ) || - worn_with_flag( flag_ELECTRIC_IMMUNE ) || - has_effect_with_flag( flag_EFFECT_ELECTRIC_IMMUNE ); + worn_with_flag( flag_ELECTRIC_IMMUNE ); default: return true; } @@ -7628,14 +7619,13 @@ tripoint_abs_omt Character::global_omt_location() const bool Character::is_blind() const { return ( worn_with_flag( flag_BLIND ) || - has_effect( effect_blind ) || has_flag( json_flag_BLIND ) ); } bool Character::is_invisible() const { return ( - has_effect_with_flag( flag_EFFECT_INVISIBLE ) || + has_flag( json_flag_INVISIBLE ) || is_wearing_active_optcloak() || has_trait( trait_DEBUG_CLOAK ) ); @@ -13141,6 +13131,6 @@ bool Character::has_bionic_with_flag( const json_character_flag &flag ) const bool Character::has_flag( const json_character_flag &flag ) const { - // If this is a performance problem create a map of flags stored for a character and updated on trait, mutation, bionic add/remove, activate/deactivate - return has_trait_flag( flag ) || has_bionic_with_flag( flag ); + // If this is a performance problem create a map of flags stored for a character and updated on trait, mutation, bionic add/remove, activate/deactivate, effect gain/loss + return has_trait_flag( flag ) || has_bionic_with_flag( flag ) || has_effect_with_flag( flag ); } diff --git a/src/character.h b/src/character.h index 660e5b0c792a3..0df50d945dc29 100644 --- a/src/character.h +++ b/src/character.h @@ -964,7 +964,7 @@ class Character : public Creature, public visitable bool has_bionic_with_flag( const json_character_flag &flag ) const; /** This is to prevent clang complaining about overloading a virtual function, the creature version uses monster flags so confusion is unlikely. */ using Creature::has_flag; - /** Returns true if player has a trait or bionic with a flag */ + /** Returns true if player has a trait, bionic or effect with a flag */ bool has_flag( const json_character_flag &flag ) const; /** Returns the trait id with the given invlet, or an empty string if no trait has that invlet */ trait_id trait_by_invlet( int ch ) const; diff --git a/src/flag.cpp b/src/flag.cpp index dbe17a49a8342..641d9c5966be2 100644 --- a/src/flag.cpp +++ b/src/flag.cpp @@ -76,19 +76,7 @@ const flag_id flag_DURABLE_MELEE( "DURABLE_MELEE" ); const flag_id flag_EATEN_COLD( "EATEN_COLD" ); const flag_id flag_EATEN_HOT( "EATEN_HOT" ); const flag_id flag_EDIBLE_FROZEN( "EDIBLE_FROZEN" ); -const flag_id flag_EFFECT_ACID_IMMUNE( "EFFECT_ACID_IMMUNE" ); -const flag_id flag_EFFECT_BASH_IMMUNE( "EFFECT_BASH_IMMUNE" ); -const flag_id flag_EFFECT_BIO_IMMUNE( "EFFECT_BIO_IMMUNE" ); -const flag_id flag_EFFECT_BULLET_IMMUNE( "EFFECT_BULLET_IMMUNE" ); -const flag_id flag_EFFECT_COLD_IMMUNE( "EFFECT_COLD_IMMUNE" ); -const flag_id flag_EFFECT_CUT_IMMUNE( "EFFECT_CUT_IMMUNE" ); -const flag_id flag_EFFECT_ELECTRIC_IMMUNE( "EFFECT_ELECTRIC_IMMUNE" ); -const flag_id flag_EFFECT_FEATHER_FALL( "EFFECT_FEATHER_FALL" ); -const flag_id flag_EFFECT_HEAT_IMMUNE( "EFFECT_HEAT_IMMUNE" ); const flag_id flag_EFFECT_IMPEDING( "EFFECT_IMPEDING" ); -const flag_id flag_EFFECT_INVISIBLE( "EFFECT_INVISIBLE" ); -const flag_id flag_EFFECT_NIGHT_VISION( "EFFECT_NIGHT_VISION" ); -const flag_id flag_EFFECT_STAB_IMMUNE( "EFFECT_STAB_IMMUNE" ); const flag_id flag_ELECTRIC_IMMUNE( "ELECTRIC_IMMUNE" ); const flag_id flag_ETHEREAL_ITEM( "ETHEREAL_ITEM" ); const flag_id flag_FAKE_MILL( "FAKE_MILL" ); diff --git a/src/flag.h b/src/flag.h index 9c19663da5eaa..316de675b7686 100644 --- a/src/flag.h +++ b/src/flag.h @@ -83,19 +83,7 @@ extern const flag_id flag_DURABLE_MELEE; extern const flag_id flag_EATEN_COLD; extern const flag_id flag_EATEN_HOT; extern const flag_id flag_EDIBLE_FROZEN; -extern const flag_id flag_EFFECT_ACID_IMMUNE; -extern const flag_id flag_EFFECT_BASH_IMMUNE; -extern const flag_id flag_EFFECT_BIO_IMMUNE; -extern const flag_id flag_EFFECT_BULLET_IMMUNE; -extern const flag_id flag_EFFECT_COLD_IMMUNE; -extern const flag_id flag_EFFECT_CUT_IMMUNE; -extern const flag_id flag_EFFECT_ELECTRIC_IMMUNE; -extern const flag_id flag_EFFECT_FEATHER_FALL; -extern const flag_id flag_EFFECT_HEAT_IMMUNE; extern const flag_id flag_EFFECT_IMPEDING; -extern const flag_id flag_EFFECT_INVISIBLE; -extern const flag_id flag_EFFECT_NIGHT_VISION; -extern const flag_id flag_EFFECT_STAB_IMMUNE; extern const flag_id flag_ELECTRIC_IMMUNE; extern const flag_id flag_ETHEREAL_ITEM; extern const flag_id flag_FAKE_MILL; diff --git a/src/game.cpp b/src/game.cpp index 1b34f2b915dbe..8eae9a73844a4 100644 --- a/src/game.cpp +++ b/src/game.cpp @@ -10309,7 +10309,7 @@ bool game::phasing_move( const tripoint &dest_loc, const bool via_ramp ) tunneldist += 1; //Being dimensionally anchored prevents quantum shenanigans. if( u.worn_with_flag( flag_DIMENSIONAL_ANCHOR ) || - u.has_effect_with_flag( flag_DIMENSIONAL_ANCHOR ) ) { + u.has_flag( flag_DIMENSIONAL_ANCHOR ) ) { u.add_msg_if_player( m_info, _( "You are repelled by the barrier!" ) ); u.mod_power_level( -250_kJ ); //cost of tunneling one tile. return false; diff --git a/src/monattack.cpp b/src/monattack.cpp index 9f37f42b9a4df..8a3a8a9e92538 100644 --- a/src/monattack.cpp +++ b/src/monattack.cpp @@ -2855,7 +2855,7 @@ bool mattack::stare( monster *z ) if( z->sees( player_character ) ) { //dimensional effects don't take against dimensionally anchored foes. if( player_character.worn_with_flag( flag_DIMENSIONAL_ANCHOR ) || - player_character.has_effect_with_flag( flag_DIMENSIONAL_ANCHOR ) ) { + player_character.has_flag( flag_DIMENSIONAL_ANCHOR ) ) { add_msg( m_warning, _( "You feel a strange reverberation across your body." ) ); return true; } diff --git a/src/player.cpp b/src/player.cpp index f40ef895da110..962cfdbcf2809 100644 --- a/src/player.cpp +++ b/src/player.cpp @@ -139,6 +139,8 @@ static const bionic_id bio_ground_sonar( "bio_ground_sonar" ); static const bionic_id bio_soporific( "bio_soporific" ); static const bionic_id bio_speed( "bio_speed" ); +static const json_character_flag json_flag_FEATHER_FALL( "FEATHER_FALL" ); + stat_mod player::get_pain_penalty() const { stat_mod ret; @@ -833,7 +835,7 @@ int player::get_perceived_pain() const float player::fall_damage_mod() const { - if( has_effect_with_flag( flag_EFFECT_FEATHER_FALL ) ) { + if( has_flag( json_flag_FEATHER_FALL ) ) { return 0.0f; } float ret = 1.0f; diff --git a/src/teleport.cpp b/src/teleport.cpp index 6db51beaeca5f..f4835d28be499 100644 --- a/src/teleport.cpp +++ b/src/teleport.cpp @@ -40,7 +40,7 @@ bool teleport::teleport( Creature &critter, int min_distance, int max_distance, map &here = get_map(); //The teleportee is dimensionally anchored so nothing happens if( p && ( p->worn_with_flag( json_flag_DIMENSIONAL_ANCHOR ) || - p->has_effect_with_flag( json_flag_DIMENSIONAL_ANCHOR ) ) ) { + p->has_flag( json_flag_DIMENSIONAL_ANCHOR ) ) ) { p->add_msg_if_player( m_warning, _( "You feel a strange, inwards force." ) ); return false; } @@ -76,7 +76,7 @@ bool teleport::teleport( Creature &critter, int min_distance, int max_distance, } return false; } else if( poor_player && ( poor_player->worn_with_flag( json_flag_DIMENSIONAL_ANCHOR ) || - poor_player->has_effect_with_flag( json_flag_DIMENSIONAL_ANCHOR ) ) ) { + poor_player->has_flag( json_flag_DIMENSIONAL_ANCHOR ) ) ) { poor_player->add_msg_if_player( m_warning, _( "You feel disjointed." ) ); return false; } else { diff --git a/tests/creature_effect_test.cpp b/tests/creature_effect_test.cpp index b3db98f732e38..7b148b626e6d5 100644 --- a/tests/creature_effect_test.cpp +++ b/tests/creature_effect_test.cpp @@ -314,7 +314,7 @@ TEST_CASE( "has_effect_with_flag", "[creature][effect][has][flag]" ) { const efftype_id effect_downed( "downed" ); const efftype_id effect_invisibility( "invisibility" ); - const flag_id invisibility_flag( "EFFECT_INVISIBLE" ); + const flag_id invisibility_flag( "INVISIBLE" ); monster mummy( mtype_id( "debug_mon" ) ); From 86cd7fd9b4194869a22e196be49185c4c6b172e4 Mon Sep 17 00:00:00 2001 From: OromisElf Date: Tue, 16 Mar 2021 08:03:29 +0100 Subject: [PATCH 278/453] added electric train engine (#48012) --- data/json/items/vehicle/motors.json | 11 +++++++++++ data/json/vehicleparts/motor.json | 25 +++++++++++++++++++++++++ 2 files changed, 36 insertions(+) diff --git a/data/json/items/vehicle/motors.json b/data/json/items/vehicle/motors.json index 60f6191a764f0..06e1d5ba31d6b 100644 --- a/data/json/items/vehicle/motors.json +++ b/data/json/items/vehicle/motors.json @@ -76,5 +76,16 @@ "category": "veh_parts", "price": 2000, "price_postapoc": 100 + }, + { + "type": "GENERIC", + "id": "motor_train1300", + "name": { "str": "1300hp electric train engine" }, + "description": "A 1300hp extended-use electric engine. Normally used in trains.", + "weight": "2000 kg", + "volume": "250 L", + "price": 120000, + "price_postapoc": 8000, + "copy-from": "motor" } ] diff --git a/data/json/vehicleparts/motor.json b/data/json/vehicleparts/motor.json index 89b44c57c70ce..a2727c273a826 100644 --- a/data/json/vehicleparts/motor.json +++ b/data/json/vehicleparts/motor.json @@ -159,5 +159,30 @@ { "item": "cable", "charges": [ 20, 30 ] } ], "damage_reduction": { "all": 60 } + }, + { + "id": "engine_electric_train", + "copy-from": "engine_motor", + "type": "vehicle_part", + "name": { "str": "1300hp electric train engine" }, + "item": "motor_train1300", + "durability": 500, + "power": 1000000, + "energy_consumption": 1050000, + "damage_modifier": 80, + "requirements": { + "install": { "skills": [ [ "mechanics", 8 ] ], "time": "60 m", "using": [ [ "vehicle_wrench_2", 1 ] ] }, + "removal": { "skills": [ [ "mechanics", 4 ] ], "time": "45 m", "using": [ [ "vehicle_wrench_2", 1 ] ] }, + "repair": { "skills": [ [ "mechanics", 10 ] ], "time": "60 m", "using": [ [ "welding_standard", 20 ] ] } + }, + "breaks_into": [ + { "item": "steel_lump", "count": [ 60, 80 ] }, + { "item": "steel_chunk", "count": [ 24, 40 ] }, + { "item": "scrap", "count": [ 24, 40 ] }, + { "item": "e_scrap", "count": [ 20, 60 ] }, + { "item": "bearing", "count": [ 100, 240 ] }, + { "item": "cable", "charges": [ 80, 120 ] } + ], + "damage_reduction": { "all": 60 } } ] From b8d03fe683727e6df083710260292f17fee25dbd Mon Sep 17 00:00:00 2001 From: Saicchi Date: Fri, 12 Mar 2021 01:54:45 -0300 Subject: [PATCH 279/453] Allow filtering by level in the recipe craft menu (#47995) --- src/crafting_gui.cpp | 8 ++++++ src/recipe_dictionary.cpp | 58 +++++++++++++++++++++++++++++++++++++++ src/recipe_dictionary.h | 1 + 3 files changed, 67 insertions(+) diff --git a/src/crafting_gui.cpp b/src/crafting_gui.cpp index 2b45bef6193e8..4e67f4a334029 100644 --- a/src/crafting_gui.cpp +++ b/src/crafting_gui.cpp @@ -765,6 +765,11 @@ const recipe *select_crafting_recipe( int &batch_size_out ) recipe_subset::search_type::proficiency, progress_callback ); break; + case 'l': + filtered_recipes = filtered_recipes.reduce( qry_filter_str.substr( 2 ), + recipe_subset::search_type::difficulty, progress_callback ); + break; + default: current.clear(); } @@ -936,6 +941,7 @@ const recipe *select_crafting_recipe( int &batch_size_out ) { 't', _( "soldering iron" ), _( "tool required to craft" ) }, { 'm', _( "yes" ), _( "recipes which are memorized or not" ) }, { 'P', _( "Blacksmithing" ), _( "proficiency used to craft" ) }, + { 'l', _( "5" ), _( "difficulty of the recipe as a number or range" ) }, }; int max_example_length = 0; for( const auto &prefix : prefixes ) { @@ -947,6 +953,8 @@ const recipe *select_crafting_recipe( int &batch_size_out ) _( "The default is to search result names. Some single-character prefixes " "can be used with a colon : to search in other ways. Additional filters " "are separated by commas ,.\n" + "Filtering by difficulty can accept range; " + "l:5~10 for all recipes from difficulty 5 to 10.\n" "\n\n" "Examples:\n" ); diff --git a/src/recipe_dictionary.cpp b/src/recipe_dictionary.cpp index b3e17b2368b74..7e8b837e0baed 100644 --- a/src/recipe_dictionary.cpp +++ b/src/recipe_dictionary.cpp @@ -189,6 +189,64 @@ std::vector recipe_subset::search( case search_type::proficiency: return lcmatch( r->recipe_proficiencies_string(), txt ); + case search_type::difficulty: { + std::string range_start; + std::string range_end; + bool use_range = false; + for( const char &chr : txt ) { + if( std::isdigit( chr ) ) { + if( use_range ) { + range_end += chr; + } else { + range_start += chr; + } + } else if( chr == '~' ) { + use_range = true; + } else { + // unexpected character + return true; + } + } + + int start = 0; + int end = INT_MAX; + + if( use_range ) { + if( !range_start.empty() ) { + start = std::stoi( range_start ); + } + + if( !range_end.empty() ) { + end = std::stoi( range_end ); + } + + if( range_start.empty() && range_end.empty() ) { + return true; + } + } else { + if( !range_start.empty() ) { + start = std::stoi( range_start ); + } + + if( range_start.empty() && range_end.empty() ) { + return true; + } + } + + if( use_range && start > end ) { + int swap = start; + start = end; + end = swap; + } + + if( use_range ) { + // check if number is between two numbers inclusive + return r->difficulty == clamp( r->difficulty, start, end ); + } else { + return r->difficulty == start; + } + } + default: return false; } diff --git a/src/recipe_dictionary.h b/src/recipe_dictionary.h index 8304cec064b38..d21b0c01f2dd4 100644 --- a/src/recipe_dictionary.h +++ b/src/recipe_dictionary.h @@ -137,6 +137,7 @@ class recipe_subset quality_result, description_result, proficiency, + difficulty, }; /** Find marked favorite recipes */ From 9245f0e09e484b63d2cfd3befe3ca58c47868aac Mon Sep 17 00:00:00 2001 From: LaVeyanFiend Date: Thu, 18 Mar 2021 10:11:48 -0400 Subject: [PATCH 280/453] Fix MSC Typo (#48115) --- data/mods/My_Sweet_Cataclysm/sweet_items.json | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/data/mods/My_Sweet_Cataclysm/sweet_items.json b/data/mods/My_Sweet_Cataclysm/sweet_items.json index 9def6b336f864..6c83a070228ae 100644 --- a/data/mods/My_Sweet_Cataclysm/sweet_items.json +++ b/data/mods/My_Sweet_Cataclysm/sweet_items.json @@ -17,7 +17,7 @@ "id": "ruined_candy", "//": "This item should not get any use whatsoever, it is merely conservation.", "symbol": "¨", - "name": { "str_sp": "peices of candy wrapper" }, + "name": { "str_sp": "pieces of candy wrapper" }, "charges": 10, "volume": "1000 ml", "weight": "100 g", From 8f591ba59640659fd53e60ec56642e72055a31d0 Mon Sep 17 00:00:00 2001 From: Termineitor244 <53200489+Termineitor244@users.noreply.github.com> Date: Thu, 18 Mar 2021 13:55:31 -0600 Subject: [PATCH 281/453] A livelier Zoo (#48108) --- data/json/mapgen/zoo.json | 110 ++++++++++++++++++++++++-------------- 1 file changed, 70 insertions(+), 40 deletions(-) diff --git a/data/json/mapgen/zoo.json b/data/json/mapgen/zoo.json index 6cb543524d36a..761cf616a6464 100644 --- a/data/json/mapgen/zoo.json +++ b/data/json/mapgen/zoo.json @@ -17,6 +17,15 @@ { "monster": "mon_zoose", "freq": 50, "cost_multiplier": 1 } ] }, + { + "name": "GROUP_PIGS", + "type": "monstergroup", + "default": "mon_pig", + "monsters": [ + { "monster": "mon_pig", "freq": 50, "cost_multiplier": 1 }, + { "monster": "mon_zombie_pig", "freq": 50, "cost_multiplier": 1 } + ] + }, { "method": "json", "om_terrain": "zoo_0_0", @@ -127,16 +136,17 @@ }, "place_item": [ { "item": "rock", "repeat": 1, "x": 9, "y": 15 }, { "item": "pine_bough", "repeat": 1, "x": 9, "y": 21 } ], "place_items": [ - { "chance": 55, "item": "toy_store", "x": 12, "y": [ 6, 7 ] }, + { "chance": 55, "item": "toy_store", "x": 12, "y": [ 6, 7 ], "repeat": [ 1, 16 ] }, { "chance": 75, "item": "vending_food", "x": 20, "y": 2 }, { "chance": 55, "item": "trash", "x": 13, "y": 15 }, { "chance": 55, "item": "trash", "x": 13, "y": 10 }, - { "chance": 55, "item": "snacks", "x": 10, "y": 11 }, - { "chance": 55, "item": "snacks", "x": [ 7, 8 ], "y": 4 }, - { "chance": 55, "item": "candy_shop", "x": 10, "y": [ 6, 7 ] }, - { "chance": 75, "item": "shirts", "x": 10, "y": 12 }, - { "chance": 75, "item": "shirts", "x": 4, "y": 11 }, - { "chance": 75, "item": "vending_drink", "x": 20, "y": 1 } + { "chance": 55, "item": "snacks", "x": 10, "y": 11, "repeat": [ 1, 16 ] }, + { "chance": 55, "item": "snacks", "x": [ 7, 8 ], "y": 4, "repeat": [ 1, 16 ] }, + { "chance": 55, "item": "candy_shop", "x": 10, "y": [ 6, 7 ], "repeat": [ 1, 16 ] }, + { "chance": 75, "item": "shirts", "x": 10, "y": 12, "repeat": [ 1, 5 ] }, + { "chance": 45, "item": "shirts", "x": 4, "y": 11, "repeat": [ 1, 3 ] }, + { "chance": 75, "item": "vending_drink", "x": 20, "y": 1 }, + { "chance": 25, "item": "waitingroom", "x": 18, "y": [ 16, 22 ], "repeat": [ 1, 3 ] } ], "place_monster": [ { "monster": "mon_tiger", "x": 8, "y": 16 }, @@ -211,16 +221,17 @@ "{": "f_rack" }, "place_items": [ - { "chance": 55, "item": "toy_store", "x": 12, "y": [ 6, 7 ] }, + { "chance": 55, "item": "toy_store", "x": 12, "y": [ 6, 7 ], "repeat": [ 1, 16 ] }, { "chance": 75, "item": "vending_food", "x": 20, "y": 2 }, { "chance": 55, "item": "trash", "x": 13, "y": 15 }, { "chance": 55, "item": "trash", "x": 13, "y": 10 }, - { "chance": 55, "item": "snacks", "x": 10, "y": 11 }, - { "chance": 55, "item": "snacks", "x": [ 7, 8 ], "y": 4 }, - { "chance": 55, "item": "candy_shop", "x": 10, "y": [ 6, 7 ] }, - { "chance": 75, "item": "shirts", "x": 10, "y": 12 }, - { "chance": 75, "item": "shirts", "x": 4, "y": 11 }, - { "chance": 75, "item": "vending_drink", "x": 20, "y": 1 } + { "chance": 55, "item": "snacks", "x": 10, "y": 11, "repeat": [ 1, 16 ] }, + { "chance": 55, "item": "snacks", "x": [ 7, 8 ], "y": 4, "repeat": [ 1, 16 ] }, + { "chance": 55, "item": "candy_shop", "x": 10, "y": [ 6, 7 ], "repeat": [ 1, 16 ] }, + { "chance": 75, "item": "shirts", "x": 10, "y": 12, "repeat": [ 1, 5 ] }, + { "chance": 45, "item": "shirts", "x": 4, "y": 11, "repeat": [ 1, 3 ] }, + { "chance": 75, "item": "vending_drink", "x": 20, "y": 1 }, + { "chance": 25, "item": "waitingroom", "x": 18, "y": [ 16, 22 ], "repeat": [ 1, 3 ] } ], "place_item": [ { "item": "rock", "repeat": 1, "x": 9, "y": 15 }, @@ -229,7 +240,7 @@ { "item": "glass_shard", "repeat": [ 42, 84 ], "x": 11, "y": [ 21, 23 ] } ], "place_monster": [ { "monster": "mon_coyote", "x": 8, "y": 16 }, { "monster": "mon_coyote", "x": 9, "y": 17 } ], - "place_monsters": [ { "monster": "GROUP_BEARS", "x": 8, "y": 20 } ] + "place_monsters": [ { "monster": "GROUP_BEARS", "x": 9, "y": 23 } ] } }, { @@ -290,7 +301,7 @@ "-#_|..|...r...b..|||__ss", "-__|..a...r...b..r.|__ss", "-7_|..|...r......r.|__ss", - "-__|..|...r......|||__ss", + "-__|{.|...r......|||__ss", "-_#|c.|..h|rr|...r.|__ss", "B__|..|..h|..|...r.|__ss", "___|..|||||||||+||||____", @@ -340,8 +351,10 @@ ], "place_items": [ { "chance": 45, "item": "trash", "x": 20, "y": 5 }, - { "chance": 65, "item": "vet_softdrug", "x": 10, "y": 18 }, - { "chance": 45, "item": "vet_hardrug", "x": 9, "y": 18 } + { "chance": 65, "item": "vet_softdrug", "x": 10, "y": 18, "repeat": [ 2, 5 ] }, + { "chance": 45, "item": "vet_hardrug", "x": 9, "y": 18, "repeat": [ 2, 5 ] }, + { "chance": 95, "item": "SUS_janitors_closet", "x": 4, "y": 14 }, + { "chance": 25, "item": "waitingroom", "x": [ 16, 17 ], "y": 7, "repeat": [ 1, 3 ] } ], "place_monster": [ { "monster": "mon_bobcat", "x": 8, "y": 5 }, @@ -519,7 +532,10 @@ { "chance": 65, "item": "vending_food", "x": 12, "y": 1 }, { "chance": 55, "item": "trash", "x": 8, "y": 19 }, { "chance": 55, "item": "trash", "x": 12, "y": 6 }, - { "chance": 55, "item": "trash", "x": 10, "y": 2 } + { "chance": 55, "item": "trash", "x": 10, "y": 2 }, + { "chance": 15, "item": "waitingroom", "x": [ 5, 6 ], "y": 19 }, + { "chance": 15, "item": "waitingroom", "x": [ 9, 10 ], "y": 19 }, + { "chance": 15, "item": "waitingroom", "x": [ 15, 16 ], "y": 19 } ], "place_monster": [ { "monster": "mon_deer", "x": 20, "y": 2 }, @@ -614,7 +630,10 @@ { "chance": 65, "item": "vending_food", "x": 12, "y": 1 }, { "chance": 55, "item": "trash", "x": 8, "y": 19 }, { "chance": 55, "item": "trash", "x": 12, "y": 6 }, - { "chance": 55, "item": "trash", "x": 10, "y": 2 } + { "chance": 55, "item": "trash", "x": 10, "y": 2 }, + { "chance": 15, "item": "waitingroom", "x": [ 5, 6 ], "y": 19 }, + { "chance": 15, "item": "waitingroom", "x": [ 9, 10 ], "y": 19 }, + { "chance": 15, "item": "waitingroom", "x": [ 15, 16 ], "y": 19 } ], "place_item": [ { "item": "stick", "repeat": 1, "x": 19, "y": 1 }, @@ -700,7 +719,7 @@ "|||...............-...^|", "-......|-------|..-..^^|", "-......-h....^.-..+...^|", - "-.####&-h..^#..+..|....|", + "-.####&-h..^#..+.L|....|", "||||||||||||||||||||||||", "|i.ctc..i|............&|", "+........C............C|", @@ -734,20 +753,32 @@ "o": "f_oven", "s": "f_sink", "t": "f_table", - "{": "f_fridge" + "{": "f_fridge", + "L": "f_locker" }, "place_items": [ - { "chance": 65, "item": "cannedfood", "x": 22, "y": 21 }, - { "chance": 65, "item": "cannedfood", "x": 22, "y": 19 }, - { "chance": 55, "item": "bowling_food", "x": 5, "y": 21 }, - { "chance": 55, "item": "bowling_food", "x": 15, "y": 16 }, - { "chance": 55, "item": "bowling_food", "x": 9, "y": 15 }, + { "chance": 25, "item": "restaur_table", "x": 4, "y": 14, "repeat": [ 1, 2 ] }, + { "chance": 25, "item": "restaur_table", "x": 5, "y": [ 20, 21 ], "repeat": [ 1, 2 ] }, + { "chance": 25, "item": "restaur_table", "x": 9, "y": [ 20, 21 ], "repeat": [ 1, 2 ] }, + { "chance": 25, "item": "restaur_table", "x": 13, "y": 21, "repeat": [ 1, 2 ] }, + { "chance": 15, "item": "restaur_table", "x": 9, "y": [ 15, 16 ], "repeat": [ 1, 2 ] }, + { "chance": 55, "item": "restaur_kitchen", "x": 22, "y": [ 15, 16 ], "repeat": [ 1, 8 ] }, + { "chance": 55, "item": "restaur_kitchen", "x": 22, "y": [ 19, 21 ], "repeat": [ 1, 8 ] }, + { "chance": 75, "item": "restaur_sink", "x": 22, "y": [ 17, 18 ], "repeat": [ 2, 3 ] }, + { "chance": 55, "item": "SUS_oven", "x": [ 15, 17 ], "y": 16, "repeat": [ 2, 3 ] }, { "chance": 55, "item": "trash", "x": 10, "y": 18 }, { "chance": 55, "item": "trash", "x": 22, "y": 14 }, { "chance": 55, "item": "trash", "x": 6, "y": 12 }, { "chance": 55, "item": "trash", "x": 6, "y": 3 }, - { "chance": 55, "item": "fridgesnacks", "x": [ 15, 16 ], "y": 21 }, - { "chance": 35, "item": "fridge", "x": [ 18, 19 ], "y": 21 } + { "chance": 50, "item": "behindcounter", "x": 17, "y": 21, "repeat": [ 1, 6 ] }, + { "chance": 80, "item": "restaur_fridge", "x": [ 15, 16 ], "y": 21, "repeat": [ 2, 8 ] }, + { "chance": 80, "item": "restaur_fridge", "x": [ 18, 19 ], "y": 21, "repeat": [ 2, 8 ] } + ], + "place_item": [ + { "chance": 60, "item": "birdfood", "x": 12, "y": [ 3, 4 ], "repeat": [ 3, 6 ] }, + { "chance": 60, "item": "birdfood", "x": [ 9, 11 ], "y": 11, "repeat": [ 3, 6 ] }, + { "chance": 35, "item": "birdfood", "x": 20, "y": [ 3, 10 ], "repeat": [ 4, 8 ] }, + { "chance": 90, "item": "birdfood", "x": 17, "y": 12, "repeat": [ 5, 10 ] } ], "sealed_item": { "^": { "item": { "item": "seed_sugar_beet" }, "furniture": "f_plant_seed" } }, "place_monster": [ @@ -997,7 +1028,7 @@ "____..+.g..........fff|-", "____..+.........g..fff|-", "____r.c...........|fff|-", - "____r.c.....gg....|#ff|-", + "____r.c.....gg....|#f}|-", "____r.c....gggg...|||||-", "____r.c.....gg........|-", "____r.c......g........|-", @@ -1020,13 +1051,17 @@ "r": "t_railing_v", "|": "t_brick_wall" }, - "furniture": { "#": "f_hay", "&": "f_trashcan" }, + "furniture": { "#": "f_hay", "&": "f_trashcan", "}": "f_locker" }, "place_item": [ { "item": "rock", "repeat": 1, "x": 8, "y": 9 }, { "item": "rock", "repeat": 1, "x": 16, "y": 15 }, { "item": "stick", "repeat": 1, "x": 8, "y": 17 }, { "item": "stick", "repeat": 1, "x": 21, "y": 18 }, - { "item": "stick", "repeat": 1, "x": 21, "y": 20 } + { "item": "stick", "repeat": 1, "x": 21, "y": 20 }, + { "chance": 15, "item": "cattlefodder", "x": [ 9, 14 ], "y": [ 7, 17 ], "repeat": [ 8, 12 ] }, + { "chance": 15, "item": "birdfood", "x": [ 9, 14 ], "y": [ 7, 17 ], "repeat": [ 8, 12 ] }, + { "chance": 90, "item": "cattlefodder", "x": 21, "y": 14, "repeat": [ 5, 10 ] }, + { "chance": 90, "item": "birdfood", "x": 21, "y": 14, "repeat": [ 4, 8 ] } ], "place_items": [ { "chance": 55, "item": "trash", "x": 3, "y": 22 }, @@ -1034,21 +1069,16 @@ { "chance": 55, "item": "trash", "x": 0, "y": 6 } ], "place_monster": [ - { "monster": "mon_zombie_pig", "x": 10, "y": 7 }, { "monster": "mon_chicken", "x": 14, "y": 7 }, - { "monster": "mon_zombie_pig", "x": 15, "y": 10 }, { "monster": "mon_duck", "x": 11, "y": 11 }, - { "monster": "mon_zombie_pig", "x": 15, "y": 12 }, - { "monster": "mon_pig", "x": 20, "y": 12 }, { "monster": "mon_sheep", "x": 10, "y": 17 }, { "monster": "mon_rabbit", "x": 15, "y": 17 }, { "monster": "mon_sheep", "x": 19, "y": 17 }, { "monster": "mon_sheep", "x": 9, "y": 19 }, { "monster": "mon_sheep", "x": 12, "y": 19 }, - { "monster": "mon_rabbit", "x": 15, "y": 19 }, - { "monster": "mon_pig", "x": 17, "y": 20 }, - { "monster": "mon_pig", "x": 19, "y": 20 } - ] + { "monster": "mon_rabbit", "x": 18, "y": 19 } + ], + "place_monsters": [ { "monster": "GROUP_PIGS", "x": 18, "y": 11 } ] } }, { From c6d27ee802ca5e53d30b52c3b358438c253b2516 Mon Sep 17 00:00:00 2001 From: Termineitor244 <53200489+Termineitor244@users.noreply.github.com> Date: Wed, 17 Mar 2021 14:46:59 -0600 Subject: [PATCH 282/453] Increased the probability of condoms in wallets (#48100) --- .../itemgroups/Clothing_Gear/wallets.json | 24 +++++++++---------- 1 file changed, 12 insertions(+), 12 deletions(-) diff --git a/data/json/itemgroups/Clothing_Gear/wallets.json b/data/json/itemgroups/Clothing_Gear/wallets.json index 5e74971899181..92020cbd4f882 100644 --- a/data/json/itemgroups/Clothing_Gear/wallets.json +++ b/data/json/itemgroups/Clothing_Gear/wallets.json @@ -41,7 +41,7 @@ { "item": "coin_quarter", "prob": 10, "count": [ 1, 2 ] }, { "item": "coin_nickel", "prob": 10, "count": [ 1, 2 ] }, { "group": "discount_cards", "prob": 40, "count": [ 1, 3 ] }, - { "item": "condom", "prob": 1 }, + { "item": "condom", "prob": 10 }, [ "scorecard", 20 ] ] }, @@ -57,7 +57,7 @@ { "item": "coin_quarter", "prob": 10, "count": [ 1, 2 ] }, { "item": "coin_nickel", "prob": 10, "count": [ 1, 2 ] }, { "group": "discount_cards", "prob": 40, "count": [ 1, 3 ] }, - { "item": "condom", "prob": 1 }, + { "item": "condom", "prob": 10 }, [ "scorecard", 20 ] ] }, @@ -73,7 +73,7 @@ { "item": "coin_quarter", "prob": 10, "count": [ 1, 2 ] }, { "item": "coin_nickel", "prob": 10, "count": [ 1, 2 ] }, { "group": "discount_cards", "prob": 40, "count": [ 1, 3 ] }, - { "item": "condom", "prob": 1 }, + { "item": "condom", "prob": 10 }, [ "scorecard", 20 ] ] }, @@ -88,7 +88,7 @@ { "item": "coin_quarter", "prob": 50, "count": [ 2, 5 ] }, { "item": "coin_nickel", "prob": 0, "count": [ 1, 6 ] }, { "group": "discount_cards", "prob": 10 }, - { "item": "condom", "prob": 1 }, + { "item": "condom", "prob": 10 }, [ "scorecard", 40 ] ] }, @@ -103,7 +103,7 @@ { "item": "money_ten", "prob": 100, "count": [ 5, 10 ] }, { "item": "money_twenty", "prob": 100, "count": [ 5, 10 ] }, { "group": "discount_cards", "prob": 60, "count": [ 2, 5 ] }, - { "item": "condom", "prob": 1 }, + { "item": "condom", "prob": 10 }, [ "scorecard", 5 ] ] }, @@ -120,7 +120,7 @@ { "item": "coin_quarter", "prob": 10, "count": [ 1, 2 ] }, { "item": "coin_nickel", "prob": 10, "count": [ 1, 2 ] }, { "group": "discount_cards", "prob": 40, "count": [ 1, 3 ] }, - { "item": "condom", "prob": 1 }, + { "item": "condom", "prob": 10 }, [ "scorecard", 20 ] ] }, @@ -137,7 +137,7 @@ { "item": "coin_quarter", "prob": 10, "count": [ 1, 2 ] }, { "item": "coin_nickel", "prob": 10, "count": [ 1, 2 ] }, { "group": "discount_cards", "prob": 40, "count": [ 1, 3 ] }, - { "item": "condom", "prob": 1 }, + { "item": "condom", "prob": 10 }, [ "scorecard", 20 ] ] }, @@ -154,7 +154,7 @@ { "item": "coin_quarter", "prob": 10, "count": [ 1, 2 ] }, { "item": "coin_nickel", "prob": 10, "count": [ 1, 2 ] }, { "group": "discount_cards", "prob": 40, "count": [ 1, 3 ] }, - { "item": "condom", "prob": 1 }, + { "item": "condom", "prob": 10 }, { "item": "labmap", "prob": 20 }, [ "scorecard", 20 ] ] @@ -172,7 +172,7 @@ { "item": "coin_quarter", "prob": 10, "count": [ 1, 2 ] }, { "item": "coin_nickel", "prob": 10, "count": [ 1, 2 ] }, { "group": "discount_cards", "prob": 40, "count": [ 1, 3 ] }, - { "item": "condom", "prob": 1 }, + { "item": "condom", "prob": 10 }, { "item": "labmap", "prob": 20 }, [ "scorecard", 20 ] ] @@ -190,7 +190,7 @@ { "item": "money_ten", "prob": 100, "count": [ 5, 10 ] }, { "item": "money_twenty", "prob": 100, "count": [ 5, 10 ] }, { "group": "discount_cards", "prob": 60, "count": [ 2, 5 ] }, - { "item": "condom", "prob": 1 }, + { "item": "condom", "prob": 10 }, { "item": "labmap", "prob": 20 }, [ "scorecard", 5 ] ] @@ -208,7 +208,7 @@ { "item": "coin_quarter", "prob": 10, "count": [ 1, 2 ] }, { "item": "coin_nickel", "prob": 10, "count": [ 1, 2 ] }, { "group": "discount_cards", "prob": 40, "count": [ 1, 3 ] }, - { "item": "condom", "prob": 1 }, + { "item": "condom", "prob": 10 }, [ "scorecard", 20 ] ] }, @@ -225,7 +225,7 @@ { "item": "coin_quarter", "prob": 10, "count": [ 1, 2 ] }, { "item": "coin_nickel", "prob": 10, "count": [ 1, 2 ] }, { "group": "discount_cards", "prob": 40, "count": [ 1, 3 ] }, - { "item": "condom", "prob": 1 }, + { "item": "condom", "prob": 10 }, [ "scorecard", 20 ] ] }, From 125bb4b6bfa20d37b53c2f20cb2391f6b7214da6 Mon Sep 17 00:00:00 2001 From: Termineitor244 <53200489+Termineitor244@users.noreply.github.com> Date: Wed, 17 Mar 2021 13:10:58 -0600 Subject: [PATCH 283/453] [Magiclysm] Less HP consumed at higher levels of Sacrificial Healing (#48097) --- data/mods/Magiclysm/Spells/druid.json | 2 ++ 1 file changed, 2 insertions(+) diff --git a/data/mods/Magiclysm/Spells/druid.json b/data/mods/Magiclysm/Spells/druid.json index 0a01dbd5d66f7..5acc79f74e387 100644 --- a/data/mods/Magiclysm/Spells/druid.json +++ b/data/mods/Magiclysm/Spells/druid.json @@ -298,6 +298,8 @@ "difficulty": 5, "base_casting_time": 400, "base_energy_cost": 35, + "final_energy_cost": 20, + "energy_increment": -1.5, "max_level": 10, "min_damage": -4, "max_damage": -12, From 0dbbf2cd789966be001855b4d49216b01cd05600 Mon Sep 17 00:00:00 2001 From: Maleclypse <54345792+Maleclypse@users.noreply.github.com> Date: Thu, 18 Mar 2021 14:58:57 -0500 Subject: [PATCH 284/453] Ki strike scroll (#47962) --- data/mods/MMA/item_groups.json | 5 +++++ data/mods/MMA/martial.json | 24 ++++++++++++++++++++++++ data/mods/MMA/spells.json | 16 ++++++++++++++++ 3 files changed, 45 insertions(+) create mode 100644 data/mods/MMA/spells.json diff --git a/data/mods/MMA/item_groups.json b/data/mods/MMA/item_groups.json index c48fb030c40ac..aa9d2086c1cbc 100644 --- a/data/mods/MMA/item_groups.json +++ b/data/mods/MMA/item_groups.json @@ -20,6 +20,11 @@ [ "manual_mma_hylian", 1 ] ] }, + { + "id": "museum_misc", + "type": "item_group", + "items": [ [ "ki_strike_scroll", 3 ] ] + }, { "type": "item_group", "id": "book_military", diff --git a/data/mods/MMA/martial.json b/data/mods/MMA/martial.json index edfcfc14ff1cd..e6dfff170ef7b 100644 --- a/data/mods/MMA/martial.json +++ b/data/mods/MMA/martial.json @@ -88,5 +88,29 @@ "name": { "str_sp": "Reaping Talons" }, "description": "This book contains the teaching of the Tiger Claw discipline.", "martial_art": "style_mma_tiger_claw" + }, + { + "abstract": "scroll_martial_base", + "type": "TOOL", + "name": { "str": "scroll abstract" }, + "weight": "415 g", + "volume": "250 ml", + "material": [ "paper" ], + "symbol": "!", + "looks_like": "manual_dragon", + "color": "white", + "flags": [ "NO_SALVAGE" ] + }, + { + "id": "ki_strike_scroll", + "copy-from": "scroll_martial_base", + "type": "TOOL", + "name": { "str": "dragon hand scroll" }, + "description": "Focus your ki into magical attacks.", + "price_postapoc": 12000, + "use_action": { "type": "countdown", "name": "Unroll", "message": "You unroll the dragon scroll…" }, + "countdown_interval": 1, + "countdown_destroy": true, + "countdown_action": { "type": "cast_spell", "spell_id": "learn_ki_strike", "no_fail": true, "level": 0 } } ] diff --git a/data/mods/MMA/spells.json b/data/mods/MMA/spells.json new file mode 100644 index 0000000000000..11045438411d7 --- /dev/null +++ b/data/mods/MMA/spells.json @@ -0,0 +1,16 @@ +[ + { + "type": "SPELL", + "id": "learn_ki_strike", + "name": { "str": "Ki Strike Meditations" }, + "effect": "mutate", + "shape": "blast", + "effect_str": "KI_STRIKE", + "description": "This grants a specific mutation.", + "message": "You study the meditations until you could do them in your sleep…", + "min_damage": 10000, + "max_damage": 10000, + "flags": [ "SILENT", "MUTATE_TRAIT" ], + "valid_targets": [ "self", "ally" ] + } +] From 783bdcb789671c8d81dba987f04fee3d7bc54235 Mon Sep 17 00:00:00 2001 From: Maleclypse <54345792+Maleclypse@users.noreply.github.com> Date: Thu, 18 Mar 2021 14:59:44 -0500 Subject: [PATCH 285/453] Zombie Pig upgrades (#47860) --- data/json/emit.json | 8 +++++ data/json/monstergroups/zanimal_upgrades.json | 11 ++++++ data/json/monsters/mammal.json | 1 + data/json/monsters/zanimal_upgrade.json | 35 +++++++++++++++++++ data/json/monsters/zed-animal.json | 1 + doc/JSON_FLAGS.md | 1 + src/mondeath.cpp | 7 ++++ src/mondeath.h | 2 ++ src/monstergenerator.cpp | 2 ++ 9 files changed, 68 insertions(+) diff --git a/data/json/emit.json b/data/json/emit.json index bf9cd0d863dc0..3268490447224 100644 --- a/data/json/emit.json +++ b/data/json/emit.json @@ -72,6 +72,14 @@ "intensity": 3, "qty": 18 }, + { + "id": "emit_tear_gas_blast", + "type": "emit", + "//": "Large blast of tear gas (example: tear gas canister)", + "field": "fd_tear_gas", + "intensity": 3, + "qty": 200 + }, { "id": "emit_toxic_blast", "type": "emit", diff --git a/data/json/monstergroups/zanimal_upgrades.json b/data/json/monstergroups/zanimal_upgrades.json index f43793c5b2942..d6910ccb8e695 100644 --- a/data/json/monstergroups/zanimal_upgrades.json +++ b/data/json/monstergroups/zanimal_upgrades.json @@ -10,6 +10,17 @@ { "monster": "mon_zombie_dog_acidic", "freq": 330, "cost_multiplier": 2 } ] }, + { + "type": "monstergroup", + "name": "GROUP_ZOMBIE_PIG_UPGRADE", + "default": "mon_zombie_pig", + "//": "No bionics or fungal", + "monsters": [ + { "monster": "mon_zombie_pig", "freq": 45, "cost_multiplier": 5 }, + { "monster": "mon_zpig_brute", "freq": 45, "cost_multiplier": 2 }, + { "monster": "mon_zombie_pig_gas", "freq": 45, "cost_multiplier": 2 } + ] + }, { "type": "monstergroup", "name": "GROUP_ZOLF_UPGRADE", diff --git a/data/json/monsters/mammal.json b/data/json/monsters/mammal.json index a00caa8af85f8..018ec160d3c90 100644 --- a/data/json/monsters/mammal.json +++ b/data/json/monsters/mammal.json @@ -231,6 +231,7 @@ "fear_triggers": [ "SOUND", "PLAYER_CLOSE" ], "placate_triggers": [ "MEAT" ], "death_function": [ "NORMAL" ], + "zombify_into": "mon_zpig_brute", "special_attacks": [ [ "EAT_FOOD", 20 ] ], "flags": [ "SEES", "HEARS", "SMELLS", "PET_MOUNTABLE", "ANIMAL", "PATH_AVOID_DANGER_1", "WARM", "KEENNOSE" ] }, diff --git a/data/json/monsters/zanimal_upgrade.json b/data/json/monsters/zanimal_upgrade.json index 53cae8fb5fa48..077f5b4e2167f 100644 --- a/data/json/monsters/zanimal_upgrade.json +++ b/data/json/monsters/zanimal_upgrade.json @@ -92,6 +92,41 @@ { "id": "scratch", "damage_max_instance": [ { "damage_type": "cut", "amount": 15, "armor_multiplier": 0.6 } ] } ] }, + { + "id": "mon_zpig_brute", + "type": "MONSTER", + "name": { "str": "skull pig" }, + "copy-from": "mon_zombie_pig", + "description": "This former wild boar appears to have been a truly massive specimen in life. Stretching eight to nine feet in length, the most arresting feature of this animal is that the enamel of its tusks has spread across its face leaving a skull-like appearance with deep-set eyeholes.", + "diff": 2, + "color": "red", + "proportional": { "hp": 1.5, "speed": 1.5, "attack_cost": 1.5 }, + "relative": { + "melee_dice": 1, + "melee_dice_sides": 5, + "melee_cut": 2, + "armor_bash": 4, + "armor_cut": 6, + "armor_bullet": 5, + "vision_night": 1 + }, + "special_attacks": [ [ "SMASH", 30 ], { "id": "impale" } ], + "extend": { "flags": [ "GROUP_BASH", "PUSH_VEH", "HIT_AND_RUN" ] } + }, + { + "id": "mon_zombie_pig_gas", + "type": "MONSTER", + "name": { "str": "trench pig" }, + "copy-from": "mon_zombie_pig", + "description": "Billowing clouds of yellow-streaked gas precede boar-shaped shadows. Glimpses of a zombie boar are quickly obscured by the gases leaving its body through open wounds.", + "diff": 5, + "color": "red", + "harvest": "exempt", + "emit_fields": [ { "emit_id": "emit_tear_gas_stream", "delay": "1 s" } ], + "death_function": [ "TEARBURST" ], + "special_attacks": [ { "id": "impale" } ], + "extend": { "flags": [ "HIT_AND_RUN" ] } + }, { "id": "mon_wolf_skeleton", "type": "MONSTER", diff --git a/data/json/monsters/zed-animal.json b/data/json/monsters/zed-animal.json index 2b52063c78e5c..21dd7c608a4ca 100644 --- a/data/json/monsters/zed-animal.json +++ b/data/json/monsters/zed-animal.json @@ -223,6 +223,7 @@ "anger_triggers": [ "PLAYER_WEAK", "PLAYER_CLOSE" ], "fear_triggers": [ "FIRE" ], "death_function": [ "NORMAL" ], + "upgrades": { "half_life": 20, "into_group": "GROUP_ZOMBIE_PIG_UPGRADE" }, "flags": [ "SEES", "HEARS", "SMELLS", "STUMBLES", "WARM", "KEENNOSE", "BASHES", "POISON", "NO_BREATHE", "REVIVES", "FILTHY" ], "//": "1d8->2d5, minor bonus over 1d9" }, diff --git a/doc/JSON_FLAGS.md b/doc/JSON_FLAGS.md index 4bad52d1ac6eb..c3b5bc3e35d43 100644 --- a/doc/JSON_FLAGS.md +++ b/doc/JSON_FLAGS.md @@ -863,6 +863,7 @@ Multiple death functions can be used. Not all combinations make sense. - ```NORMAL``` Drop a body, leave gibs. - ```RATKING``` Cure verminitis. - ```SMOKEBURST``` Explode like a huge smoke bomb. +- ```TEARBURST``` Explode like a huge tear gas bomb. - ```THING``` Turn into a full thing. - ```TRIFFID_HEART``` Destroys all roots. - ```VINE_CUT``` Kill adjacent vine if it's cut. diff --git a/src/mondeath.cpp b/src/mondeath.cpp index 605ba0349402e..a23e51f0b22d3 100644 --- a/src/mondeath.cpp +++ b/src/mondeath.cpp @@ -720,6 +720,13 @@ void mdeath::smokeburst( monster &z ) get_map().emit_field( z.pos(), emit_id( "emit_smoke_blast" ) ); } +void mdeath::tearburst( monster &z ) +{ + std::string explode = string_format( _( "a %s explode!" ), z.name() ); + sounds::sound( z.pos(), 24, sounds::sound_t::combat, explode, false, "explosion", "small" ); + get_map().emit_field( z.pos(), emit_id( "emit_tear_gas_blast" ) ); +} + void mdeath::fungalburst( monster &z ) { map &here = get_map(); diff --git a/src/mondeath.h b/src/mondeath.h index 79e289bbac656..a34c3b67088f4 100644 --- a/src/mondeath.h +++ b/src/mondeath.h @@ -66,6 +66,8 @@ void gas( monster &z ); void kill_breathers( monster &z ); // Explode like a huge smoke bomb. void smokeburst( monster &z ); +// Explode like a huge tear gas bomb. +void tearburst( monster &z ); // Explode releasing fungal haze. void fungalburst( monster &z ); // Snicker-snack! diff --git a/src/monstergenerator.cpp b/src/monstergenerator.cpp index fe1d75932681f..223489edcfe5a 100644 --- a/src/monstergenerator.cpp +++ b/src/monstergenerator.cpp @@ -527,6 +527,8 @@ void MonsterGenerator::init_death() death_map["BROKEN_AMMO"] = &mdeath::broken_ammo; // Explode like a huge smoke bomb. death_map["SMOKEBURST"] = &mdeath::smokeburst; + // Explode like a huge tear gas bomb. + death_map["TEARBURST"] = &mdeath::tearburst; // Explode with a cloud of fungal haze. death_map["FUNGALBURST"] = &mdeath::fungalburst; // Snicker-snack! From dd4df4fd5e70c7b0e1ae3ecbd687a0fd93da257a Mon Sep 17 00:00:00 2001 From: John Candlebury Date: Thu, 18 Mar 2021 14:01:07 -0600 Subject: [PATCH 286/453] Unhardcode default Scenario/Profession & Make random starts respect Scenario Blacklists (#47918) * Unhardcode default profession/scenario * Random starts respect scenario blacklist --- data/core/game_balance.json | 14 ++++++++++++++ src/newcharacter.cpp | 2 +- src/profession.cpp | 9 ++++++++- src/scenario.cpp | 3 ++- src/worldfactory.cpp | 2 +- 5 files changed, 26 insertions(+), 4 deletions(-) diff --git a/data/core/game_balance.json b/data/core/game_balance.json index dc2794d4782fa..d86b2352b0e91 100644 --- a/data/core/game_balance.json +++ b/data/core/game_balance.json @@ -188,6 +188,20 @@ "stype": "int", "value": 5 }, + { + "type": "EXTERNAL_OPTION", + "name": "GENERIC_PROFESSION_ID", + "info": "The profession selected by default in the character creator menu.", + "stype": "string_input", + "value": "unemployed" + }, + { + "type": "EXTERNAL_OPTION", + "name": "GENERIC_SCENARIO_ID", + "info": "The scenario selected by default in the character creator menu.", + "stype": "string_input", + "value": "evacuee" + }, { "type": "EXTERNAL_OPTION", "name": "WORKBENCH_ALL_OPTIONS", diff --git a/src/newcharacter.cpp b/src/newcharacter.cpp index 43c7c426324ea..bbfe516e17030 100644 --- a/src/newcharacter.cpp +++ b/src/newcharacter.cpp @@ -205,7 +205,7 @@ void avatar::randomize( const bool random_scenario, points_left &points, bool pl if( random_scenario ) { std::vector scenarios; for( const auto &scen : scenario::get_all() ) { - if( !scen.has_flag( flag_CHALLENGE ) && + if( !scen.has_flag( flag_CHALLENGE ) && !scen.scen_is_blacklisted() && ( !scen.has_flag( flag_CITY_START ) || cities_enabled ) ) { scenarios.emplace_back( &scen ); } diff --git a/src/profession.cpp b/src/profession.cpp index 130596909dbfa..7349369fa0551 100644 --- a/src/profession.cpp +++ b/src/profession.cpp @@ -7,6 +7,7 @@ #include #include +#include "game.h" #include "addiction.h" #include "avatar.h" #include "calendar.h" @@ -30,7 +31,6 @@ namespace { generic_factory all_profs( "profession" ); -const string_id generic_profession_id( "unemployed" ); } // namespace static class json_item_substitution @@ -238,6 +238,8 @@ void profession::load( const JsonObject &jo, const std::string & ) const profession *profession::generic() { + const string_id generic_profession_id( + get_option( "GENERIC_PROFESSION_ID" ) ); return &generic_profession_id.obj(); } @@ -333,6 +335,11 @@ void profession::check_definition() const bool profession::has_initialized() { + if( !g || g->new_game ) { + return false; + } + const string_id generic_profession_id( + get_option( "GENERIC_PROFESSION_ID" ) ); return generic_profession_id.is_valid(); } diff --git a/src/scenario.cpp b/src/scenario.cpp index f0afc2e829198..16a7caf257484 100644 --- a/src/scenario.cpp +++ b/src/scenario.cpp @@ -18,7 +18,6 @@ namespace { generic_factory all_scenarios( "scenario" ); -const string_id generic_scenario_id( "evacuee" ); } // namespace /** @relates string_id */ @@ -125,6 +124,8 @@ void scenario::load( const JsonObject &jo, const std::string & ) const scenario *scenario::generic() { + static const string_id generic_scenario_id( + get_option( "GENERIC_SCENARIO_ID" ) ); return &generic_scenario_id.obj(); } diff --git a/src/worldfactory.cpp b/src/worldfactory.cpp index 73450d2d3edb1..51e94d63ca1cb 100644 --- a/src/worldfactory.cpp +++ b/src/worldfactory.cpp @@ -1599,7 +1599,7 @@ void load_external_option( const JsonObject &jo ) } else { opt.setValue( "false" ); } - } else if( stype == "string" ) { + } else if( stype == "string" || stype == "string_input" ) { opt.setValue( jo.get_string( "value" ) ); } else { jo.throw_error( "Unknown or unsupported stype for external option", "stype" ); From caef8ba5ffbb3e45c33aa7f50326bbe4b6d1725d Mon Sep 17 00:00:00 2001 From: anothersimulacrum Date: Tue, 16 Mar 2021 14:46:23 -0700 Subject: [PATCH 287/453] Show in vpart info when a wheel needs other wheels (#48088) This flag is purely cosmetic, but is required to show this info. --- data/json/obsolete.json | 2 +- data/json/vehicleparts/vehicle_parts.json | 12 +++++++++++- data/json/vehicleparts/vp_flags.json | 6 ++++++ data/json/vehicleparts/wheel.json | 18 +++++++++--------- doc/JSON_FLAGS.md | 1 + src/veh_type.cpp | 9 +++++++++ 6 files changed, 37 insertions(+), 11 deletions(-) diff --git a/data/json/obsolete.json b/data/json/obsolete.json index 87ff797204f2f..2b553d919ccad 100644 --- a/data/json/obsolete.json +++ b/data/json/obsolete.json @@ -766,7 +766,7 @@ "removal": { "skills": [ [ "mechanics", 1 ] ], "time": "15 m", "qualities": [ { "id": "WRENCH", "level": 2 } ] }, "repair": { "skills": [ [ "mechanics", 2 ] ], "time": "15 m", "using": [ [ "welding_standard", 5 ] ] } }, - "flags": [ "WHEEL", "NEEDS_JACKING", "NEEDS_WHEEL_MOUNT_MEDIUM" ], + "flags": [ "WHEEL", "UNSTABLE_WHEEL", "NEEDS_JACKING", "NEEDS_WHEEL_MOUNT_MEDIUM" ], "damage_reduction": { "all": 66 } }, { diff --git a/data/json/vehicleparts/vehicle_parts.json b/data/json/vehicleparts/vehicle_parts.json index 3a78173645f3f..f986419fc7d46 100644 --- a/data/json/vehicleparts/vehicle_parts.json +++ b/data/json/vehicleparts/vehicle_parts.json @@ -111,7 +111,17 @@ "repair": { "skills": [ [ "mechanics", 1 ] ], "time": "20 s", "using": [ [ "adhesive", 1 ] ] } }, "breaks_into": "ig_vp_wood_plate", - "flags": [ "ENGINE", "BOARDABLE", "E_STARTS_INSTANTLY", "ANIMAL_CTRL", "HARNESS_any", "STEERABLE", "UNMOUNT_ON_DAMAGE", "WHEEL" ], + "flags": [ + "ENGINE", + "BOARDABLE", + "E_STARTS_INSTANTLY", + "ANIMAL_CTRL", + "HARNESS_any", + "STEERABLE", + "UNMOUNT_ON_DAMAGE", + "UNSTABLE_WHEEL", + "WHEEL" + ], "damage_reduction": { "all": 2 } }, { diff --git a/data/json/vehicleparts/vp_flags.json b/data/json/vehicleparts/vp_flags.json index 6822a4957e721..d30f0c77ee75a 100644 --- a/data/json/vehicleparts/vp_flags.json +++ b/data/json/vehicleparts/vp_flags.json @@ -157,6 +157,12 @@ "context": [ "vehicle_part" ], "info": "If your vehicle consists of a single tile, this wheel is enough to allow it to move." }, + { + "id": "UNSTABLE_WHEEL", + "type": "json_flag", + "context": [ "vehicle_part" ], + "info": "This wheel requires another wheel to be installed to be functional." + }, { "id": "STEERABLE", "type": "json_flag", diff --git a/data/json/vehicleparts/wheel.json b/data/json/vehicleparts/wheel.json index 4750cfb6e89a7..cb06c23df9413 100644 --- a/data/json/vehicleparts/wheel.json +++ b/data/json/vehicleparts/wheel.json @@ -150,7 +150,7 @@ "removal": { "skills": [ [ "mechanics", 2 ] ], "time": "30 m", "using": [ [ "vehicle_fasten", 1 ] ] }, "repair": { "skills": [ [ "mechanics", 3 ] ], "time": "60 m", "using": [ [ "welding_standard", 5 ] ] } }, - "flags": [ "WHEEL", "NEEDS_JACKING", "RAIL" ], + "flags": [ "WHEEL", "UNSTABLE_WHEEL", "NEEDS_JACKING", "RAIL" ], "damage_reduction": { "all": 66 } }, { @@ -197,7 +197,7 @@ "removal": { "skills": [ [ "mechanics", 3 ] ], "time": "30 m", "using": [ [ "vehicle_fasten", 1 ] ] }, "repair": { "skills": [ [ "mechanics", 6 ] ], "time": "60 m", "using": [ [ "welding_standard", 5 ] ] } }, - "flags": [ "ARMOR", "OBSTACLE", "WHEEL", "NEEDS_JACKING", "STEERABLE" ], + "flags": [ "ARMOR", "OBSTACLE", "WHEEL", "UNSTABLE_WHEEL", "NEEDS_JACKING", "STEERABLE" ], "wheel_type": "rigid", "contact_area": 400, "damage_reduction": { "all": 280 } @@ -228,7 +228,7 @@ "removal": { "skills": [ [ "mechanics", 0 ] ], "time": "15 m", "using": [ [ "vehicle_fasten", 1 ] ] }, "repair": { "skills": [ [ "mechanics", 4 ] ], "time": "15 m", "using": [ [ "adhesive", 1 ], [ "plastics", 1 ] ] } }, - "flags": [ "WHEEL", "NEEDS_JACKING", "NEEDS_WHEEL_MOUNT_MEDIUM" ], + "flags": [ "WHEEL", "UNSTABLE_WHEEL", "NEEDS_JACKING", "NEEDS_WHEEL_MOUNT_MEDIUM" ], "damage_reduction": { "bash": 20 } }, { @@ -268,7 +268,7 @@ "removal": { "skills": [ [ "mechanics", 0 ] ], "time": "20 m", "using": [ [ "vehicle_fasten", 1 ] ] }, "repair": { "skills": [ [ "mechanics", 5 ] ], "time": "20 m", "using": [ [ "adhesive", 1 ], [ "plastics", 1 ] ] } }, - "flags": [ "WHEEL", "NEEDS_JACKING", "NEEDS_WHEEL_MOUNT_HEAVY" ], + "flags": [ "WHEEL", "UNSTABLE_WHEEL", "NEEDS_JACKING", "NEEDS_WHEEL_MOUNT_HEAVY" ], "damage_reduction": { "all": 60, "cut": 30, "stab": 16 } }, { @@ -325,7 +325,7 @@ "removal": { "skills": [ [ "mechanics", 0 ] ], "time": "15 m", "using": [ [ "vehicle_fasten", 1 ] ] }, "repair": { "skills": [ [ "mechanics", 2 ] ], "time": "15 m", "using": [ [ "adhesive", 1 ], [ "plastics", 1 ] ] } }, - "flags": [ "WHEEL", "NEEDS_JACKING", "FOLDABLE", "NEEDS_WHEEL_MOUNT_LIGHT" ], + "flags": [ "WHEEL", "UNSTABLE_WHEEL", "NEEDS_JACKING", "FOLDABLE", "NEEDS_WHEEL_MOUNT_LIGHT" ], "damage_reduction": { "bash": 6 } }, { @@ -446,7 +446,7 @@ "removal": { "skills": [ [ "mechanics", 0 ] ], "time": "15 m", "using": [ [ "vehicle_fasten", 1 ] ] }, "repair": { "skills": [ [ "mechanics", 2 ] ], "time": "15 m", "using": [ [ "adhesive", 1 ], [ "plastics", 1 ] ] } }, - "flags": [ "WHEEL", "NEEDS_JACKING", "NEEDS_WHEEL_MOUNT_LIGHT" ], + "flags": [ "WHEEL", "UNSTABLE_WHEEL", "NEEDS_JACKING", "NEEDS_WHEEL_MOUNT_LIGHT" ], "damage_reduction": { "bash": 10 } }, { @@ -507,7 +507,7 @@ "removal": { "skills": [ [ "mechanics", 0 ] ], "time": "15 m", "using": [ [ "vehicle_wrench_2", 1 ] ] }, "repair": { "skills": [ [ "mechanics", 2 ] ], "time": "15 m", "using": [ [ "adhesive", 1 ], [ "plastics", 1 ] ] } }, - "flags": [ "WHEEL", "FOLDABLE", "NEEDS_WHEEL_MOUNT_LIGHT" ] + "flags": [ "WHEEL", "UNSTABLE_WHEEL", "FOLDABLE", "NEEDS_WHEEL_MOUNT_LIGHT" ] }, { "copy-from": "wheel_small_abstract", @@ -638,7 +638,7 @@ "removal": { "skills": [ [ "mechanics", 0 ] ], "time": "15 m", "using": [ [ "vehicle_fasten", 1 ] ] }, "repair": { "skills": [ [ "mechanics", 4 ] ], "time": "15 m", "using": [ [ "adhesive", 1 ], [ "plastics", 1 ] ] } }, - "flags": [ "WHEEL", "NEEDS_JACKING", "NEEDS_WHEEL_MOUNT_MEDIUM" ], + "flags": [ "WHEEL", "UNSTABLE_WHEEL", "NEEDS_JACKING", "NEEDS_WHEEL_MOUNT_MEDIUM" ], "damage_reduction": { "bash": 25 } }, { @@ -674,7 +674,7 @@ "rolling_resistance": 2.15, "wheel_type": "rigid", "contact_area": 60, - "flags": [ "WHEEL", "NEEDS_JACKING" ], + "flags": [ "WHEEL", "UNSTABLE_WHEEL", "NEEDS_JACKING" ], "damage_reduction": { "all": 14 } }, { diff --git a/doc/JSON_FLAGS.md b/doc/JSON_FLAGS.md index c3b5bc3e35d43..cc51f33b43343 100644 --- a/doc/JSON_FLAGS.md +++ b/doc/JSON_FLAGS.md @@ -1414,6 +1414,7 @@ Those flags are added by the game code to specific items (for example, that spec - ```SOLAR_PANEL``` Recharges vehicle batteries when exposed to sunlight. Has a 1 in 4 chance of being broken on car generation. - ```SPACE_HEATER``` There is separate command to toggle this part. - ```STABLE``` Similar to `WHEEL`, but if the vehicle is only a 1x1 section, this single wheel counts as enough wheels. +- ```UNSTABLE_WHEEL``` The opposite of `STABLE` - this will not provide for the wheeling needs of your vehicle if installed alone. - ```STEERABLE``` This wheel is steerable. - ```STEREO``` - ```TRANSFORM_TERRAIN``` Transform terrain (using rules defined in ```transform_terrain```). diff --git a/src/veh_type.cpp b/src/veh_type.cpp index 69d274810163e..006935b9c11a8 100644 --- a/src/veh_type.cpp +++ b/src/veh_type.cpp @@ -753,6 +753,15 @@ void vpart_info::check() debugmsg( "vehicle part %s has the WHEEL flag, but base item %s is not a wheel. " "THIS WILL CRASH!", part.id.str(), part.base_item.str() ); } + + if( part.has_flag( "WHEEL" ) && !part.has_flag( "UNSTABLE_WHEEL" ) && !part.has_flag( "STABLE" ) ) { + debugmsg( "Wheel '%s' lacks either 'UNSTABLE_WHEEL' or 'STABLE' flag.", vp.first.str() ); + } + + if( part.has_flag( "UNSTABLE_WHEEL" ) && part.has_flag( "STABLE" ) ) { + debugmsg( "Wheel '%s' cannot be both an 'UNSTABLE_WHEEL' and 'STABLE'.", vp.first.str() ); + } + for( auto &q : part.qualities ) { if( !q.first.is_valid() ) { debugmsg( "vehicle part %s has undefined tool quality %s", part.id.c_str(), q.first.c_str() ); From 3d32cbe1a0b50973cfa84f8e8933421b9eb9036b Mon Sep 17 00:00:00 2001 From: OromisElf Date: Thu, 18 Mar 2021 21:07:41 +0100 Subject: [PATCH 288/453] Electrical train (#48033) --- data/json/items/vehicle/motors.json | 2 +- .../mapgen/railroad/railroad_station.json | 6 +- data/json/vehicles/trains.json | 149 ++++++++++++++++++ 3 files changed, 155 insertions(+), 2 deletions(-) diff --git a/data/json/items/vehicle/motors.json b/data/json/items/vehicle/motors.json index 06e1d5ba31d6b..76740c02be3b5 100644 --- a/data/json/items/vehicle/motors.json +++ b/data/json/items/vehicle/motors.json @@ -81,7 +81,7 @@ "type": "GENERIC", "id": "motor_train1300", "name": { "str": "1300hp electric train engine" }, - "description": "A 1300hp extended-use electric engine. Normally used in trains.", + "description": "A 1300hp 3-phase 60 Hz electric engine. Normally used in trains.", "weight": "2000 kg", "volume": "250 L", "price": 120000, diff --git a/data/json/mapgen/railroad/railroad_station.json b/data/json/mapgen/railroad/railroad_station.json index ae692d222af8d..26559f054f17f 100644 --- a/data/json/mapgen/railroad/railroad_station.json +++ b/data/json/mapgen/railroad/railroad_station.json @@ -125,7 +125,11 @@ "7": { "item_group": "vending_food" }, "8": { "item_group": "vending_drink" }, "9": { "item_group": "vending_food" } - } + }, + "place_vehicles": [ + { "vehicle": "train_electrical_loco1300", "x": 5, "y": 90, "chance": 5, "rotation": 90, "status": -1 }, + { "vehicle": "train_electrical_loco1300", "x": 18, "y": 9, "chance": 12, "rotation": 270, "status": 1 } + ] } }, { diff --git a/data/json/vehicles/trains.json b/data/json/vehicles/trains.json index 44aba2971a6a2..b15175495f7dd 100644 --- a/data/json/vehicles/trains.json +++ b/data/json/vehicles/trains.json @@ -250,6 +250,155 @@ { "x": 0, "y": 0, "parts": [ { "part": "fuel_bunker", "fuel": "coal_lump" } ] } ] }, + { + "id": "train_electrical_loco1300", + "type": "vehicle", + "name": "Electrical Locomotive", + "parts": [ + { "x": 0, "y": 0, "parts": [ "hdframe_cross", "aisle_horizontal", "roof" ] }, + { "x": 0, "y": -1, "parts": [ "hdframe_cross", "rail_wheel_steerable", "aisle_horizontal", "roof" ] }, + { "x": 0, "y": -2, "parts": [ "hdframe_vertical_2", "windshield_vertical_left", "inboard_mirror" ] }, + { "x": 0, "y": 1, "parts": [ "hdframe_cross", "lit_aisle_vertical", "roof" ] }, + { "x": 0, "y": 2, "parts": [ "hdframe_cross", "aisle_horizontal", "roof" ] }, + { "x": 0, "y": 3, "parts": [ "hdframe_cross", "rail_wheel_steerable", "aisle_horizontal", "roof" ] }, + { "x": 0, "y": 4, "parts": [ "hdframe_vertical_2", "windshield_vertical_right", "inboard_mirror" ] }, + { "x": 1, "y": -2, "parts": [ "hdframe_vertical_2", "board_vertical_left" ] }, + { "x": 1, "y": -1, "parts": [ "hdframe_cross", "board_vertical_right", "dashboard", "roof" ] }, + { "x": 1, "y": 0, "parts": [ "hdframe_cross", "seat", "controls", "dashboard", "roof", "seatbelt" ] }, + { "x": 1, "y": 1, "parts": [ "hdframe_cross", "cam_control", "aisle_vertical", "dashboard", "roof" ] }, + { "x": 1, "y": 2, "parts": [ "hdframe_cross", "seat", "dashboard", "roof", "seatbelt" ] }, + { "x": 1, "y": 3, "parts": [ "hdframe_cross", "board_vertical_left", "dashboard", "roof" ] }, + { "x": 1, "y": 4, "parts": [ "hdframe_vertical_2", "board_vertical_right" ] }, + { "x": 2, "y": -2, "parts": [ "hdframe_nw", "halfboard_nw" ] }, + { "x": 2, "y": -1, "parts": [ "hdframe_se", "board_horizontal" ] }, + { "x": 2, "y": 0, "parts": [ "hdframe_cross", "windshield_horizontal_front_edge" ] }, + { "x": 2, "y": 1, "parts": [ "hdframe_cross", "windshield_horizontal_front" ] }, + { "x": 2, "y": 2, "parts": [ "hdframe_cross", "windshield_horizontal_front_edge" ] }, + { "x": 2, "y": 3, "parts": [ "hdframe_sw", "board_horizontal" ] }, + { "x": 2, "y": 4, "parts": [ "hdframe_ne", "halfboard_ne" ] }, + { "x": 3, "y": -1, "parts": [ "hdframe_nw", "halfboard_nw", "plating_steel" ] }, + { "x": 3, "y": 0, "parts": [ "hdframe_horizontal_2", "halfboard_horizontal_2", "headlight", "plating_steel" ] }, + { "x": 3, "y": 1, "parts": [ "hdframe_horizontal_2", "halfboard_horizontal_2", "plating_steel" ] }, + { "x": 3, "y": 2, "parts": [ "hdframe_horizontal_2", "halfboard_horizontal_2", "headlight", "plating_steel" ] }, + { "x": 3, "y": 3, "parts": [ "hdframe_ne", "halfboard_ne", "plating_steel" ] }, + { "x": -1, "y": -2, "parts": [ "hdframe_vertical_2", "board_vertical_left" ] }, + { "x": -1, "y": -1, "parts": [ "hdframe_cross", "aisle_horizontal", "roof" ] }, + { "x": -1, "y": 0, "parts": [ "hdframe_cross", "aisle_horizontal", "roof" ] }, + { "x": -1, "y": 1, "parts": [ "hdframe_cross", "aisle_vertical", "roof" ] }, + { "x": -1, "y": 2, "parts": [ "hdframe_cross", "aisle_horizontal", "roof" ] }, + { "x": -1, "y": 3, "parts": [ "hdframe_cross", "aisle_horizontal", "roof" ] }, + { "x": -1, "y": 4, "parts": [ "hdframe_vertical_2", "board_vertical_right" ] }, + { "x": -2, "y": -2, "parts": [ "hdframe_vertical_2", "board_vertical_T_left" ] }, + { "x": -2, "y": -1, "parts": [ "hdframe_cross", "board_horizontal", "roof" ] }, + { "x": -2, "y": 0, "parts": [ "hdframe_cross", "stowboard_horizontal", "roof" ] }, + { "x": -2, "y": 1, "parts": [ "hdframe_cross", "door_sliding", "roof" ] }, + { "x": -2, "y": 2, "parts": [ "hdframe_cross", "stowboard_horizontal", "roof" ] }, + { "x": -2, "y": 3, "parts": [ "hdframe_cross", "board_horizontal", "roof" ] }, + { "x": -2, "y": 4, "parts": [ "hdframe_vertical_2", "board_vertical_T_right" ] }, + { "x": -3, "y": -2, "parts": [ "hdframe_vertical_2", "door_sliding", "door_motor" ] }, + { "x": -3, "y": -1, "parts": [ "hdframe_cross", "rail_wheel", "aisle_horizontal", "roof" ] }, + { "x": -3, "y": 0, "parts": [ "hdframe_cross", "aisle_horizontal", "roof" ] }, + { "x": -3, "y": 1, "parts": [ "hdframe_cross", "aisle_vertical", "roof" ] }, + { "x": -3, "y": 2, "parts": [ "hdframe_cross", "aisle_horizontal", "roof" ] }, + { "x": -3, "y": 3, "parts": [ "hdframe_cross", "rail_wheel", "aisle_horizontal", "roof" ] }, + { "x": -3, "y": 4, "parts": [ "hdframe_vertical_2", "door_sliding", "door_motor" ] }, + { "x": -4, "y": -2, "parts": [ "hdframe_vertical_2", "board_vertical_T_left" ] }, + { "x": -4, "y": -1, "parts": [ "hdframe_cross", "board_horizontal", "roof" ] }, + { "x": -4, "y": 0, "parts": [ "hdframe_cross", "board_ne", "roof" ] }, + { "x": -4, "y": 1, "parts": [ "hdframe_cross", "lit_aisle_vertical", "roof" ] }, + { "x": -4, "y": 2, "parts": [ "hdframe_cross", "board_nw", "roof" ] }, + { "x": -4, "y": 3, "parts": [ "hdframe_cross", "board_horizontal", "roof" ] }, + { "x": -4, "y": 4, "parts": [ "hdframe_vertical_2", "board_vertical_T_right" ] }, + { "x": -5, "y": -2, "parts": [ "hdframe_vertical_2", "board_vertical_left" ] }, + { + "x": -5, + "y": -1, + "parts": [ "hdframe_cross", "engine_electric_train", "large_storage_battery", "spring_plate", "roof" ] + }, + { "x": -5, "y": 0, "parts": [ "hdframe_cross", "board_vertical_right", "roof" ] }, + { "x": -5, "y": 1, "parts": [ "hdframe_cross", "aisle_vertical", "roof" ] }, + { "x": -5, "y": 2, "parts": [ "hdframe_cross", "board_vertical_left", "roof" ] }, + { "x": -5, "y": 3, "parts": [ "hdframe_cross", "large_storage_battery", "spring_plate", "roof" ] }, + { "x": -5, "y": 4, "parts": [ "hdframe_vertical_2", "board_vertical_right" ] }, + { "x": -6, "y": -2, "parts": [ "hdframe_vertical_2", "board_vertical_left" ] }, + { + "x": -6, + "y": -1, + "parts": [ "hdframe_cross", "engine_electric_train", "large_storage_battery", "spring_plate", "roof" ] + }, + { "x": -6, "y": 0, "parts": [ "hdframe_cross", "board_vertical_right", "roof" ] }, + { "x": -6, "y": 1, "parts": [ "hdframe_cross", "aisle_vertical", "roof" ] }, + { "x": -6, "y": 2, "parts": [ "hdframe_cross", "board_vertical_left", "roof" ] }, + { + "x": -6, + "y": 3, + "parts": [ "hdframe_cross", "engine_electric_train", "large_storage_battery", "spring_plate", "roof" ] + }, + { "x": -6, "y": 4, "parts": [ "hdframe_vertical_2", "board_vertical_right" ] }, + { "x": -7, "y": -2, "parts": [ "hdframe_vertical_2", "board_vertical_T_left" ] }, + { "x": -7, "y": -1, "parts": [ "hdframe_cross", "board_horizontal", "roof" ] }, + { "x": -7, "y": 0, "parts": [ "hdframe_cross", "board_se", "roof" ] }, + { "x": -7, "y": 1, "parts": [ "hdframe_cross", "lit_aisle_vertical", "roof" ] }, + { "x": -7, "y": 2, "parts": [ "hdframe_cross", "board_sw", "roof" ] }, + { "x": -7, "y": 3, "parts": [ "hdframe_cross", "board_horizontal", "roof" ] }, + { "x": -7, "y": 4, "parts": [ "hdframe_vertical_2", "board_vertical_T_right" ] }, + { "x": -8, "y": -2, "parts": [ "hdframe_vertical_2", "door_sliding", "door_motor" ] }, + { "x": -8, "y": -1, "parts": [ "hdframe_cross", "rail_wheel", "aisle_horizontal", "roof" ] }, + { "x": -8, "y": 0, "parts": [ "hdframe_cross", "aisle_horizontal", "roof" ] }, + { "x": -8, "y": 1, "parts": [ "hdframe_cross", "aisle_vertical", "roof" ] }, + { "x": -8, "y": 2, "parts": [ "hdframe_cross", "aisle_horizontal", "roof" ] }, + { "x": -8, "y": 3, "parts": [ "hdframe_cross", "rail_wheel", "aisle_horizontal", "roof" ] }, + { "x": -8, "y": 4, "parts": [ "hdframe_vertical_2", "door_sliding", "door_motor" ] }, + { "x": -9, "y": -2, "parts": [ "hdframe_vertical_2", "board_vertical_T_left" ] }, + { "x": -9, "y": -1, "parts": [ "hdframe_cross", "board_horizontal", "roof" ] }, + { "x": -9, "y": 0, "parts": [ "hdframe_cross", "stowboard_horizontal", "roof" ] }, + { "x": -9, "y": 1, "parts": [ "hdframe_cross", "door_sliding", "roof" ] }, + { "x": -9, "y": 2, "parts": [ "hdframe_cross", "stowboard_horizontal", "roof" ] }, + { "x": -9, "y": 3, "parts": [ "hdframe_cross", "board_horizontal", "roof" ] }, + { "x": -9, "y": 4, "parts": [ "hdframe_vertical_2", "board_vertical_T_right" ] }, + { "x": -10, "y": -2, "parts": [ "hdframe_vertical_2", "board_vertical_left" ] }, + { "x": -10, "y": -1, "parts": [ "hdframe_cross", "aisle_horizontal", "roof" ] }, + { "x": -10, "y": 0, "parts": [ "hdframe_cross", "aisle_horizontal", "roof" ] }, + { "x": -10, "y": 1, "parts": [ "hdframe_cross", "aisle_vertical", "roof" ] }, + { "x": -10, "y": 2, "parts": [ "hdframe_cross", "aisle_horizontal", "roof" ] }, + { "x": -10, "y": 3, "parts": [ "hdframe_cross", "aisle_horizontal", "roof" ] }, + { "x": -10, "y": 4, "parts": [ "hdframe_vertical_2", "board_vertical_right" ] }, + { "x": -11, "y": -2, "parts": [ "hdframe_vertical_2", "windshield_vertical_left", "inboard_mirror" ] }, + { "x": -11, "y": -1, "parts": [ "hdframe_cross", "rail_wheel_steerable", "aisle_horizontal", "roof" ] }, + { "x": -11, "y": 0, "parts": [ "hdframe_cross", "aisle_horizontal", "roof" ] }, + { "x": -11, "y": 1, "parts": [ "hdframe_cross", "lit_aisle_vertical", "roof" ] }, + { "x": -11, "y": 2, "parts": [ "hdframe_cross", "aisle_horizontal", "roof" ] }, + { "x": -11, "y": 3, "parts": [ "hdframe_cross", "rail_wheel_steerable", "aisle_horizontal", "roof" ] }, + { "x": -11, "y": 4, "parts": [ "hdframe_vertical_2", "windshield_vertical_right", "inboard_mirror" ] }, + { "x": -12, "y": -2, "parts": [ "hdframe_vertical_2", "board_vertical_left" ] }, + { "x": -12, "y": -1, "parts": [ "hdframe_cross", "board_vertical_right", "dashboard", "roof" ] }, + { "x": -12, "y": 0, "parts": [ "hdframe_cross", "seat", "dashboard", "roof", "seatbelt" ] }, + { "x": -12, "y": 1, "parts": [ "hdframe_cross", "aisle_vertical", "cam_control", "dashboard", "roof" ] }, + { "x": -12, "y": 2, "parts": [ "hdframe_cross", "seat", "seatbelt", "dashboard", "controls", "roof" ] }, + { "x": -12, "y": 3, "parts": [ "hdframe_cross", "board_vertical_left", "dashboard", "roof" ] }, + { "x": -12, "y": 4, "parts": [ "hdframe_vertical_2", "board_vertical_right" ] }, + { "x": -13, "y": -2, "parts": [ "hdframe_sw", "halfboard_sw" ] }, + { "x": -13, "y": -1, "parts": [ "hdframe_ne", "board_horizontal" ] }, + { "x": -13, "y": 0, "parts": [ "hdframe_cross", "windshield_horizontal_front_edge" ] }, + { "x": -13, "y": 1, "parts": [ "hdframe_cross", "windshield_horizontal_front" ] }, + { "x": -13, "y": 2, "parts": [ "hdframe_cross", "windshield_horizontal_front_edge" ] }, + { "x": -13, "y": 3, "parts": [ "hdframe_nw", "board_horizontal" ] }, + { "x": -13, "y": 4, "parts": [ "hdframe_se", "halfboard_se" ] }, + { "x": -14, "y": -1, "parts": [ "hdframe_sw", "halfboard_sw", "plating_steel" ] }, + { + "x": -14, + "y": 0, + "parts": [ "hdframe_horizontal_2", "halfboard_horizontal_2", "headlight", "plating_steel" ] + }, + { "x": -14, "y": 1, "parts": [ "hdframe_horizontal_2", "halfboard_horizontal_2", "plating_steel" ] }, + { + "x": -14, + "y": 2, + "parts": [ "hdframe_horizontal_2", "halfboard_horizontal_2", "headlight", "plating_steel" ] + }, + { "x": -14, "y": 3, "parts": [ "hdframe_se", "halfboard_se", "plating_steel" ] } + ] + }, { "id": "trolley", "type": "vehicle", From 2ec29873acbde31711d6be83a4c9a4aa138076b1 Mon Sep 17 00:00:00 2001 From: souricelle <67675144+souricelle@users.noreply.github.com> Date: Thu, 18 Mar 2021 13:17:41 -0700 Subject: [PATCH 289/453] Feral Human Damage/Description Tweak (#48032) --- data/json/items/gun/monster_gun.json | 1 - data/json/monsters/feral_humans.json | 11 +++++++---- 2 files changed, 7 insertions(+), 5 deletions(-) diff --git a/data/json/items/gun/monster_gun.json b/data/json/items/gun/monster_gun.json index ac4bf56fabd71..dd0dc0fd09421 100644 --- a/data/json/items/gun/monster_gun.json +++ b/data/json/items/gun/monster_gun.json @@ -78,7 +78,6 @@ "ammo": [ "rock" ], "ammo_effects": [ "NO_PENETRATE_OBSTACLES", "NEVER_MISFIRES" ], "clip_size": 1, - "ranged_damage": { "damage_type": "bash", "amount": 4 }, "weight": "540 g", "volume": "210 ml", "longest_side": "75 mm", diff --git a/data/json/monsters/feral_humans.json b/data/json/monsters/feral_humans.json index 5da68311d39a5..355a9d25b7ce3 100644 --- a/data/json/monsters/feral_humans.json +++ b/data/json/monsters/feral_humans.json @@ -3,7 +3,7 @@ "id": "mon_feral_human_pipe", "type": "MONSTER", "name": { "str": "feral human" }, - "description": "Pupils dilated and what remains to be seen of the iris and sclera are bloodshot. It still breathes but the zombies treat it like one of them.", + "description": "Their pupils are dilated and what remains to be seen of the iris and sclera are bloodshot. This pipe-wielding maniac still breathes, but the zombies treat them like one of their own.", "default_faction": "zombie", "looks_like": "chud", "bodytype": "human", @@ -17,7 +17,7 @@ "color": "magenta", "aggression": 30, "morale": 100, - "melee_skill": 2, + "melee_skill": 3, "melee_dice": 1, "melee_dice_sides": 3, "melee_cut": 0, @@ -63,6 +63,7 @@ { "id": "mon_feral_human_crowbar", "type": "MONSTER", + "description": "Their pupils are dilated and what remains to be seen of the iris and sclera are bloodshot. This crowbar-wielding maniac still breathes, but the zombies treat them like one of their own.", "copy-from": "mon_feral_human_pipe", "melee_dice": 2, "melee_dice_sides": 6, @@ -71,9 +72,11 @@ { "id": "mon_feral_human_axe", "type": "MONSTER", + "description": "Their pupils are dilated and what remains to be seen of the iris and sclera are bloodshot. This axe-wielding maniac still breathes, but the zombies treat them like one of their own.", "copy-from": "mon_feral_human_pipe", - "melee_dice": 3, - "melee_dice_sides": 8, + "melee_dice": 2, + "melee_dice_sides": 7, + "melee_cut": 9, "death_drops": "feral_humans_death_drops_axe" } ] From c698f1ade6d32515c183b6be969f4267fd46485e Mon Sep 17 00:00:00 2001 From: OromisElf Date: Thu, 18 Mar 2021 21:22:44 +0100 Subject: [PATCH 290/453] updated talk_tags to contain more swears (#47215) --- data/json/npcs/talk_tags.json | 86 +++++++++++++++++++++++++++++++++++ 1 file changed, 86 insertions(+) diff --git a/data/json/npcs/talk_tags.json b/data/json/npcs/talk_tags.json index 148a71851d38e..d8e92c0d6ab68 100644 --- a/data/json/npcs/talk_tags.json +++ b/data/json/npcs/talk_tags.json @@ -105,6 +105,75 @@ "category": "", "//": "generic negative/hostile pronouns", "text": [ + "airhead", + "arse", + "ass", + "assclown", + "assface", + "asstown", + "asswagon", + "bitch", + "bootlicker", + "bugger", + "butchery refuse", + "butthead", + "butt-licker", + "chucklefuck", + "coward", + "cuck", + "cunt", + "damn ", + "damned ", + "dildo", + "dimwit", + "dog", + "dumbshit", + "dumpster", + "dumpster fire", + "dunderfuck", + "effing ", + "emergency ration", + "empty headed ", + "expendable ", + "fart", + "fat-ass", + "frail-ass ", + "frigger", + "fungus eater", + "goddamn ", + "good for nothing", + "inbred", + "lazy", + "lazy ass", + "limp-dick", + "low-life", + "meat face", + "mi-go hugger", + "mushy pizza", + "pissbrain", + "pool noodle", + "prick", + "pussy", + "shitweasel", + "slime hugger", + "smooth brain", + "snowflake", + "toilet licker", + "tool", + "trash", + "turd", + "twat", + "twerp", + "useless", + "wanker", + "waste", + "waste of ammo", + "weapon holder", + "weiner", + "weird ", + "wet sandwich", + "wet sock", + "z fodder", " ", "asshat", "asswipe", @@ -190,6 +259,22 @@ "category": "", "//": "Swears and curses used to emphasize unpleasant events", "text": [ + "ARGH", + "aw fuck", + "balls", + "can't believe it", + "crapper", + "feck", + "For serious?", + "frigg", + "heavens", + "heck", + "hell", + "my luck", + "shards and shatters", + "the audacity", + "the worst!", + "what", "darn", "fuck", "goddamn", @@ -472,6 +557,7 @@ "category": "", "//": "Generic terms of emphasis", "text": [ + "ass-shatteringly", "extremely", "greatly", "highly", From 4d5c4872b3d16425350434da5cee35a4622d20ed Mon Sep 17 00:00:00 2001 From: Saicchi <47158232+Saicchi@users.noreply.github.com> Date: Thu, 18 Mar 2021 17:23:28 -0300 Subject: [PATCH 291/453] Better debug learn spell menu (#47946) MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Co-authored-by: Jianxiang Wang (王健翔) --- data/raw/keybindings.json | 21 ++ src/debug_menu.cpp | 655 ++++++++++++++++++++++++++++++++++---- src/debug_menu.h | 6 +- src/magic.cpp | 14 +- src/magic.h | 15 +- src/output.cpp | 4 +- src/output.h | 2 +- 7 files changed, 647 insertions(+), 70 deletions(-) diff --git a/data/raw/keybindings.json b/data/raw/keybindings.json index e69fade2e05bf..b7aebe96d383d 100644 --- a/data/raw/keybindings.json +++ b/data/raw/keybindings.json @@ -2243,6 +2243,27 @@ "category": "DEFAULTMODE", "id": "debug_radiation" }, + { + "type": "keybinding", + "category": "DEBUG_SPELLS", + "id": "TOGGLE_ALL_SPELL", + "name": "Toggle all spells", + "bindings": [ { "input_method": "keyboard_any", "key": "t" } ] + }, + { + "type": "keybinding", + "category": "DEBUG_SPELLS", + "id": "UNLEARN_SPELL", + "name": "Unlearn a spell", + "bindings": [ { "input_method": "keyboard_any", "key": "u" } ] + }, + { + "type": "keybinding", + "category": "DEBUG_SPELLS", + "id": "SHOW_ONLY_LEARNED", + "name": "Show only learned", + "bindings": [ { "input_method": "keyboard_any", "key": "a" } ] + }, { "type": "keybinding", "name": "Switch Sidebar Style", diff --git a/src/debug_menu.cpp b/src/debug_menu.cpp index a5d7d4767bd3c..90f149caf6292 100644 --- a/src/debug_menu.cpp +++ b/src/debug_menu.cpp @@ -72,6 +72,7 @@ #include "monstergenerator.h" #include "morale_types.h" #include "mtype.h" +#include "mutation.h" #include "npc.h" #include "npc_class.h" #include "omdata.h" @@ -112,6 +113,7 @@ static const efftype_id effect_flu( "flu" ); static const mtype_id mon_generator( "mon_generator" ); +static const trait_id trait_NONE( "NONE" ); static const trait_id trait_ASTHMA( "ASTHMA" ); #if defined(TILES) @@ -186,8 +188,7 @@ std::string enum_to_string( debug_menu::debug_menu case debug_menu::debug_menu_index::DISPLAY_REACHABILITY_ZONES: return "DISPLAY_REACHABILITY_ZONES"; case debug_menu::debug_menu_index::DISPLAY_RADIATION: return "DISPLAY_RADIATION"; case debug_menu::debug_menu_index::HOUR_TIMER: return "HOUR_TIMER"; - case debug_menu::debug_menu_index::LEARN_SPELLS: return "LEARN_SPELLS"; - case debug_menu::debug_menu_index::LEVEL_SPELLS: return "LEVEL_SPELLS"; + case debug_menu::debug_menu_index::CHANGE_SPELLS: return "CHANGE_SPELLS"; case debug_menu::debug_menu_index::TEST_MAP_EXTRA_DISTRIBUTION: return "TEST_MAP_EXTRA_DISTRIBUTION"; case debug_menu::debug_menu_index::NESTED_MAPGEN: return "NESTED_MAPGEN"; case debug_menu::debug_menu_index::VEHICLE_BATTERY_CHARGE: return "VEHICLE_BATTERY_CHARGE"; @@ -231,10 +232,8 @@ static int player_uilist() { uilist_entry( debug_menu_index::SET_AUTOMOVE, true, 'a', _( "Set automove route" ) ) }, }; if( !spell_type::get_all().empty() ) { - uilist_initializer.emplace_back( uilist_entry( debug_menu_index::LEARN_SPELLS, true, 'S', - _( "Learn all spells" ) ) ); - uilist_initializer.emplace_back( uilist_entry( debug_menu_index::LEVEL_SPELLS, true, 'L', - _( "Level a spell" ) ) ); + uilist_initializer.emplace_back( uilist_entry( debug_menu_index::CHANGE_SPELLS, true, 'S', + _( "Change spells" ) ) ); } return uilist( _( "Player…" ), uilist_initializer ); @@ -422,6 +421,592 @@ static cata::optional debug_menu_uilist( bool display_all_entr } } +static void spell_description( + std::tuple &spl_data, int width, Character &chrc ) +{ + std::ostringstream description; + + const int spl_level = std::get<1>( spl_data ); + spell spl( std::get<0>( spl_data ).id ); + spl.set_level( spl_level ); + + nc_color gray = c_light_gray; + nc_color yellow = c_yellow; + nc_color light_green = c_light_green; + + // # spell_id + description << colorize( string_format( "# %s", spl.id().str() ), c_cyan ) << '\n'; + + // Name: spell name + description << string_format( _( "Name: %1$s" ), colorize( spl.name(), c_white ) ) << '\n'; + + + // Class: Spell Class + description << string_format( _( "Class: %1$s" ), colorize( spl.spell_class() == trait_NONE ? + _( "Classless" ) : spl.spell_class()->name(), + yellow ) ) << "\n"; + + // Spell description + description << spl.description() << '\n'; + + // Spell Casting flags + description << spell_desc::enumerate_spell_data( spl ) << '\n'; + + // Spell Level: 0 / 0 (MAX) + description << string_format( + //~ %1$s - spell current level, %2$s - spell max level, %3$s - is max level + _( "Spell Level: %1$s / %2$d %3$s" ), + spl_level == -1 ? _( "Unlearned" ) : std::to_string( spl_level ), + spl.get_max_level(), + spl_level == spl.get_max_level() ? _( "(MAX)" ) : "" ) << '\n'; + + // Difficulty: 0 ( 0.0 % Failure Chance) + description << string_format( + //~ %1$d - difficulty, %2$s - failure chance + _( "Difficulty: %1$d ( %2$s )" ), + spl.get_difficulty(), spl.colorized_fail_percent( chrc ) ) << '\n'; + + + const std::string impeded = _( "(impeded)" ); + + // Casting Cost: 0 (impeded) ( 0 current ) + description << string_format( + //~ %1$s - energy cost, %2$s - is casting impeded, %3$s - current character energy + _( "Casting Cost: %1$s %2$s ( %3$s current ) " ), + spl.energy_cost_string( chrc ), + spell_desc::energy_cost_encumbered( spl, chrc ) ? impeded : "", + spl.energy_cur_string( chrc ) ) << '\n'; + + // Casting Time: 0 (impeded) + description << string_format( + //~ %1$s - cast time, %2$s - is casting impeded, %3$s - casting base time + _( "Casting Time: %1$s %2$s ( %3$s base time ) " ), + to_string( time_duration::from_moves( spl.casting_time( chrc ) ) ), + spell_desc::casting_time_encumbered( spl, chrc ) ? impeded : "", + to_string( time_duration::from_moves( std::get<0>( spl_data ).base_casting_time ) ) ) << '\n'; + + std::string targets; + if( spl.is_valid_target( spell_target::none ) ) { + targets = _( "self" ); + } else { + targets = spl.enumerate_targets(); + } + description << string_format( _( "Valid Targets: %1$s" ), targets ) << '\n'; + + std::string target_ids = spl.list_targeted_monster_names(); + if( !target_ids.empty() ) { + description << string_format( _( "Only affects the monsters: %1$s" ), target_ids ) << '\n'; + } + + const int damage = spl.damage(); + const std::string spl_eff = spl.effect(); + std::string damage_string; + std::string range_string; + std::string aoe_string; + // if it's any type of attack spell, the stats are normal. + if( spl_eff == "attack" ) { + if( damage > 0 ) { + std::string dot_string; + if( spl.damage_dot() ) { + //~ amount of damage per second, abbreviated + dot_string = string_format( _( ", %1$d/sec" ), spl.damage_dot() ); + } + damage_string = string_format( _( "Damage: %1$s %2$s%3$s" ), spl.damage_string(), + spl.damage_type_string(), dot_string ); + damage_string = colorize( damage_string, spl.damage_type_color() ); + } else if( damage < 0 ) { + damage_string = string_format( _( "Healing: %1$s" ), colorize( spl.damage_string(), + light_green ) ); + } + + if( spl.aoe() > 0 ) { + std::string aoe_string_temp = _( "Spell Radius" ); + std::string degree_string; + if( spl.shape() == spell_shape::cone ) { + aoe_string_temp = _( "Cone Arc" ); + degree_string = _( "degrees" ); + } else if( spl.shape() == spell_shape::line ) { + aoe_string_temp = _( "Line Width" ); + } + aoe_string = string_format( _( "%1$s: %2$d %3$s" ), aoe_string_temp, spl.aoe(), degree_string ); + } + + } else if( spl_eff == "teleport_random" ) { + if( spl.aoe() > 0 ) { + aoe_string = string_format( _( "Variance: %1$d" ), spl.aoe() ); + } + + } else if( spl_eff == "spawn_item" ) { + damage_string = string_format( _( "Spawn %1$d %2$s" ), spl.damage(), + item::nname( itype_id( spl.effect_data() ), spl.damage() ) ); + + } else if( spl_eff == "summon" ) { + std::string monster_name = "FIXME"; + if( spl.has_flag( spell_flag::SPAWN_GROUP ) ) { + // TODO: Get a more user-friendly group name + if( MonsterGroupManager::isValidMonsterGroup( mongroup_id( spl.effect_data() ) ) ) { + monster_name = string_format( _( "from %1$s" ), spl.effect_data() ); + } else { + debugmsg( "Unknown monster group: %s", spl.effect_data() ); + } + } else { + monster_name = monster( mtype_id( spl.effect_data() ) ).get_name(); + } + damage_string = string_format( _( "Summon: %1$d %2$s" ), spl.damage(), monster_name ); + aoe_string = string_format( _( "Spell Radius: %1$d" ), spl.aoe() ); + + } else if( spl_eff == "targeted_polymorph" ) { + std::string monster_name = spl.effect_data(); + if( spl.has_flag( spell_flag::POLYMORPH_GROUP ) ) { + // TODO: Get a more user-friendly group name + if( MonsterGroupManager::isValidMonsterGroup( mongroup_id( spl.effect_data() ) ) ) { + monster_name = _( "random creature" ); + } else { + debugmsg( "Unknown monster group: %s", spl.effect_data() ); + } + } else if( monster_name.empty() ) { + monster_name = _( "random creature" ); + } else { + monster_name = mtype_id( spl.effect_data() )->nname(); + } + damage_string = string_format( _( "Targets under: %1$dhp become a %2$s" ), spl.damage(), + monster_name ); + + } else if( spl_eff == "ter_transform" ) { + aoe_string = string_format( "Spell Radius: %1$s", spl.aoe_string() ); + + } else if( spl_eff == "banishment" ) { + damage_string = string_format( _( "Damage: %1$s %2$s" ), spl.damage_string(), + spl.damage_type_string() ); + if( spl.aoe() > 0 ) { + aoe_string = string_format( _( "Spell Radius: %1$d" ), spl.aoe() ); + } + } + + // Range / AOE in two columns + description << string_format( _( "Range: %1$s" ), + spl.range() <= 0 ? _( "self" ) : std::to_string( spl.range() ) ) << '\n'; + + + description << aoe_string << '\n'; + + // One line for damage / healing / spawn / summon effect + description << damage_string << '\n'; + + // todo: damage over time here, when it gets implemented + + // Show duration for spells that endure + if( spl.duration() > 0 || spl.has_flag( spell_flag::PERMANENT ) ) { + description << string_format( _( "Duration: %1$s" ), spl.duration_string() ) << '\n'; + } + + // helper function for printing tool and item component requirement lists + const auto print_vec_string = [&]( const std::vector &vec ) { + for( const std::string &line_str : vec ) { + description << line_str << '\n'; + } + }; + + if( spl.has_components() ) { + if( !spl.components().get_components().empty() ) { + print_vec_string( spl.components().get_folded_components_list( width - 2, gray, + chrc.crafting_inventory(), return_true ) ); + } + if( !( spl.components().get_tools().empty() && spl.components().get_qualities().empty() ) ) { + print_vec_string( spl.components().get_folded_tools_list( width - 2, gray, + chrc.crafting_inventory() ) ); + } + } + + std::get<2>( spl_data ) = description.str(); +} + +void change_spells( Character &character ) +{ + if( spell_type::get_all().empty() ) { + add_msg( m_info, _( "There are no spells to change." ) ); + return; + } + + static character_id last_char_id = character.getID(); + + using spell_tuple = std::tuple; + const size_t spells_all_size = spell_type::get_all().size(); + // all spells with cached string list + // the string is rebuilt every time it's empty or its level changed + static std::vector spells_all( spells_all_size ); + // maps which spells will show on the list + std::vector spells_relative( spells_all_size ); + + // number of spells changed, current map is invalid + bool rebuild_string_cache = false; + if( spells_all.size() != spells_all_size || last_char_id != character.getID() ) { + rebuild_string_cache = true; + last_char_id = character.getID(); + spells_all.clear(); + } + + int spname_len = 0; + for( size_t i = 0; i < spells_all_size; ++i ) { + if( rebuild_string_cache ) { + spells_all.emplace_back( spell_type{}, -1, std::string{} ); + std::get<2>( spells_all[i] ).clear(); + } + + if( std::get<0>( spells_all[i] ).id != spell_type::get_all()[i].id ) { + std::get<0>( spells_all[i] ) = spell_type::get_all()[i]; + std::get<1>( spells_all[i] ) = -1; + std::get<2>( spells_all[i] ).clear(); + } + + spells_relative[i] = &spells_all[i]; + + // get max spell name length + spname_len = std::max( spname_len, utf8_width( std::get<0>( spells_all[i] ).name.translated() ) ); + } + spname_len += 2; + + // fill the levels for spells the character knowns + for( const spell *sp : character.magic->get_spells() ) { + auto iterator = std::find_if( spells_all.begin(), + spells_all.end(), [&sp]( spell_tuple & spt ) -> bool { + return std::get<0>( spt ).id == sp->id(); + } ); + std::get<1>( spells_all[iterator - spells_all.begin()] ) = sp->get_level(); + std::get<2>( spells_all[iterator - spells_all.begin()] ).clear(); + } + + auto set_spell = [&character]( spell_type & splt, int spell_level ) { + if( spell_level == -1 ) { + character.magic->get_spellbook().erase( splt.id ); + return; + } else if( !character.magic->knows_spell( splt.id ) ) { + spell spl( splt.id ); + character.magic->get_spellbook().emplace( splt.id, spl ); + } + + character.magic->get_spell( splt.id ).set_exp( spell::exp_for_level( spell_level ) ); + }; + + ui_adaptor spellsui; + border_helper borders; + + struct win_info { + catacurses::window window; + border_helper::border_info *border = nullptr; + int width; + point start; + }; + + struct win_info w_name; + w_name.border = &borders.add_border(); + w_name.width = spname_len + 1; + w_name.start = point_zero; + + struct win_info w_level; + w_level.border = &borders.add_border(); + w_level.width = 11; + w_level.start = {w_name.width, 0}; + + struct win_info w_descborder; + w_descborder.border = &borders.add_border(); + + // desc is inside descborder with a padding of 2 characters + struct win_info w_desc; + + scrollbar scrllbr; + scrllbr.offset_x( 0 ).offset_y( 1 ).border_color( c_magenta ); + + spellsui.on_screen_resize( [&]( ui_adaptor & ui ) { + + w_descborder.start = {w_level.start.x + w_level.width, 0}; + w_descborder.width = TERMX - w_descborder.start.x; + + w_desc.width = w_descborder.width - 4; + w_desc.start = {w_descborder.start.x + 2, 1}; + + w_name.window = catacurses::newwin( TERMY, w_name.width, w_name.start ); + w_level.window = catacurses::newwin( TERMY, w_level.width, w_level.start ); + w_descborder.window = catacurses::newwin( TERMY, w_descborder.width, w_descborder.start ); + w_desc.window = catacurses::newwin( TERMY - 2, w_desc.width, w_desc.start ); + + w_name.border->set( w_name.start, { w_name.width, TERMY } ); + w_level.border->set( w_level.start, { w_level.width, TERMY } ); + w_descborder.border->set( w_descborder.start, { w_descborder.width, TERMY } ); + + scrllbr.viewport_size( TERMY - 2 ); + ui.position( point_zero, { TERMX, TERMY } ); + } ); + spellsui.mark_resize(); + + input_context ctxt( "DEBUG_SPELLS" ); + ctxt.register_action( "UNLEARN_SPELL" ); // Quickly unlearn a spell + ctxt.register_action( "TOGGLE_ALL_SPELL" ); // Cycle level on all spells in spells_relative + ctxt.register_action( "SHOW_ONLY_LEARNED" ); // Removes all unlearned spells in spells_relative + ctxt.register_cardinal(); // left and right change spell level + ctxt.register_action( "QUIT" ); + ctxt.register_action( "CONFIRM" ); // set a spell to a level + ctxt.register_action( "FILTER" ); + ctxt.register_action( "RESET_FILTER" ); + ctxt.register_action( "HELP_KEYBINDINGS" ); + + int spells_start = 0; + int spell_selected = 0; + std::string filterstring; + spellsui.on_redraw( [&]( const ui_adaptor & ) { + werase( w_name.window ); + werase( w_level.window ); + werase( w_descborder.window ); + werase( w_desc.window ); + + borders.draw_border( w_name.window, c_magenta ); + borders.draw_border( w_level.window, c_magenta ); + borders.draw_border( w_descborder.window, c_magenta ); + + center_print( w_name.window, 0, c_magenta, _( "<Spell Name>" ) ); + center_print( w_level.window, 0, c_magenta, _( "<Level>" ) ); + center_print( w_descborder.window, 0, c_magenta, _( "<Description>" ) ); + + nc_color magenta = c_magenta; + const std::string help_keybindings = string_format( + _( "<[%1$s] Keybindings>" ), + ctxt.get_desc( "HELP_KEYBINDINGS" ) ); + print_colored_text( w_descborder.window, + point( w_descborder.width - help_keybindings.length() + 42, TERMY - 1 ), + magenta, magenta, help_keybindings ); + + std::string help_filter; + if( filterstring.empty() ) { + help_filter = string_format( _( "<[%1$s] Filter>" ), + ctxt.get_desc( "FILTER" ) ); + } else { + help_filter = string_format( "<%s>", filterstring ); + } + + print_colored_text( w_name.window, point( 1, TERMY - 1 ), + magenta, magenta, help_filter ); + + const int relative_size = spells_relative.size(); + scrllbr.content_size( relative_size ); + scrllbr.viewport_pos( spell_selected ); + scrllbr.apply( w_name.window ); + + calcStartPos( spells_start, spell_selected, TERMY - 2, relative_size ); + + int line_number = 1; + for( int i = spells_start; i < relative_size; ++i ) { + if( line_number == TERMY - 1 ) { + break; + } + + const spell_type &splt = std::get<0>( *spells_relative[i] ); + const int &spell_level = std::get<1>( *spells_relative[i] ); + + nc_color spell_color = spell_level > -1 ? c_green : c_light_gray; + spell_color = i == spell_selected ? hilite( spell_color ) : spell_color; + + mvwprintz( w_name.window, point( 2, line_number ), + spell_color, splt.name.translated() ); + mvwprintz( w_level.window, point( 2, line_number++ ), spell_color, + _( "%1$-3d/%2$3d" ), spell_level, splt.max_level ); + } + + nc_color gray = c_light_gray; + print_colored_text( w_desc.window, point_zero, gray, gray, + std::get<2>( *spells_relative[spell_selected] ) ); + + wnoutrefresh( w_name.window ); + wnoutrefresh( w_level.window ); + wnoutrefresh( w_descborder.window ); + wnoutrefresh( w_desc.window ); + } ); + + auto update_description = [&]( bool force ) -> void { + if( force || std::get<2>( *spells_relative[spell_selected] ).empty() ) + { + spell_description( *spells_relative[spell_selected], w_desc.width, character ); + } + }; + + // keep the same spell selected + auto spell_middle_or_id = [&]( const spell_id & spellid ) -> void { + if( spellid.is_empty() ) + { + spell_selected = 0; + return; + } + + // in case we don't find anything, keep selection in the middle of screen + const size_t spells_relative_size = spells_relative.size(); + spell_selected = std::min( ( TERMY - 2 ) / 2, static_cast( spells_relative_size ) / 2 ); + for( size_t i = 0; i < spells_relative_size; ++i ) + { + if( std::get<0>( *spells_relative[i] ).id == spellid ) { + spell_selected = i; + break; + } + } + }; + + // reset spells_relative vector + auto reset_spells_relative = [&]() -> void { + for( spell_tuple &spt : spells_all ) + { + spells_relative.emplace_back( &spt ); + } + }; + + auto filter_spells = [&]( ) -> void { + const spell_id &spellid = std::get<0>( *spells_relative[spell_selected] ).id; + spells_relative.clear(); + if( filterstring.empty() ) + { + reset_spells_relative(); + } else + { + for( spell_tuple &spt : spells_all ) { + const spell_type &spl = std::get<0>( spt ); + if( lcmatch( spl.name.translated(), filterstring ) || + lcmatch( spl.id.str(), filterstring ) ) { + spells_relative.emplace_back( &spt ); + } + } + + // no spell found, reset relative list + if( spells_relative.empty() ) { + reset_spells_relative(); + popup( _( "Nothing found." ) ); + } + } + + spell_middle_or_id( spellid ); + }; + + auto toggle_all_spells = [&]( int level ) { + // -2 sets it to max level + for( spell_tuple *spt : spells_relative ) { + std::get<1>( *spt ) = level > -2 ? level : std::get<0>( *spt ).max_level; + set_spell( std::get<0>( *spt ), std::get<1>( *spt ) ); + std::get<2>( *spt ).clear(); + } + }; + + static spell_id last_selected_spellid; + spell_middle_or_id( last_selected_spellid ); + + // 0 -> turn off all spells + // 1 -> set all spells to level 0 + // 2 -> set all spells to their max level + int toggle_spells_state = 1; + + bool showing_only_learned = false; + + bool force_update_description = false; + + while( true ) { + update_description( force_update_description ); + force_update_description = false; + + ui_manager::redraw(); + const std::string action = ctxt.handle_input(); + + if( action == "QUIT" ) { + last_selected_spellid = std::get<0>( *spells_relative[spell_selected] ).id; + break; + + } else if( action == "FILTER" ) { + string_input_popup() + .title( _( "Filter:" ) ) + .width( 16 ) + .description( _( "Filter by spell name or id" ) ) + .edit( filterstring ); + + showing_only_learned = false; + filter_spells( ); + + } else if( action == "RESET_FILTER" ) { + showing_only_learned = false; + filterstring.clear(); + filter_spells(); + + } else if( action == "UP" ) { + if( !spell_selected ) { + spell_selected = spells_relative.size() - 1; + } else { + spell_selected--; + } + + } else if( action == "DOWN" ) { + spell_selected++; + if( static_cast( spell_selected ) == spells_relative.size() ) { + spell_selected = 0; + } + + } else if( action == "LEFT" ) { + int &spell_level = std::get<1>( *spells_relative[spell_selected] ); + spell_level = std::max( -1, spell_level - 1 ); + set_spell( std::get<0>( *spells_relative[spell_selected] ), spell_level ); + force_update_description = true; + + } else if( action == "RIGHT" ) { + int &spell_level = std::get<1>( *spells_relative[spell_selected] ); + spell_level = std::min( spell_level + 1, + std::get<0>( *spells_relative[spell_selected] ).max_level ); + set_spell( std::get<0>( *spells_relative[spell_selected] ), spell_level ); + force_update_description = true; + + } else if( action == "CONFIRM" ) { + int &spell_level = std::get<1>( *spells_relative[spell_selected] ); + query_int( spell_level, _( "Set spell level to? Currently: %1$d" ), spell_level ); + spell_level = clamp( spell_level, -1, std::get<0>( *spells_relative[spell_selected] ).max_level ); + set_spell( std::get<0>( *spells_relative[spell_selected] ), spell_level ); + force_update_description = true; + + } else if( action == "UNLEARN_SPELL" ) { + int &spell_level = std::get<1>( *spells_relative[spell_selected] ); + spell_level = -1; + set_spell( std::get<0>( *spells_relative[spell_selected] ), spell_level ); + force_update_description = true; + + } else if( action == "TOGGLE_ALL_SPELL" ) { + if( toggle_spells_state == 0 ) { + toggle_spells_state = 1; + toggle_all_spells( -1 ); // unlearn all spells + } else if( toggle_spells_state == 1 ) { + toggle_spells_state = 2; + toggle_all_spells( 0 ); // sets all spells to the minimum level + } else { + toggle_spells_state = 0; + toggle_all_spells( -2 ); // max level + } + + } else if( action == "SHOW_ONLY_LEARNED" ) { + showing_only_learned = !showing_only_learned; + + const spell_id &spellid = std::get<0>( *spells_relative[spell_selected] ).id; + spells_relative.clear(); + if( showing_only_learned ) { + for( spell_tuple &spt : spells_all ) { + if( std::get<1>( spt ) > -1 ) { + spells_relative.emplace_back( &spt ); + } + } + + if( spells_relative.empty() ) { + popup( _( "Nothing found." ) ); + showing_only_learned = false; + } + } + + if( !showing_only_learned ) { + reset_spells_relative(); + } + + spell_middle_or_id( spellid ); + } + } +} + void teleport_short() { const cata::optional where = g->look_around(); @@ -580,7 +1165,7 @@ void character_edit_menu() } enum { - D_DESC, D_SKILLS, D_PROF, D_STATS, D_ITEMS, D_DELETE_ITEMS, D_ITEM_WORN, + D_DESC, D_SKILLS, D_PROF, D_STATS, D_SPELLS, D_ITEMS, D_DELETE_ITEMS, D_ITEM_WORN, D_HP, D_STAMINA, D_MORALE, D_PAIN, D_NEEDS, D_HEALTHY, D_STATUS, D_MISSION_ADD, D_MISSION_EDIT, D_TELE, D_MUTATE, D_CLASS, D_ATTITUDE, D_OPINION, D_ADD_EFFECT, D_ASTHMA }; @@ -589,6 +1174,7 @@ void character_edit_menu() nmenu.addentry( D_SKILLS, true, 's', "%s", _( "Edit [s]kills" ) ); nmenu.addentry( D_PROF, true, 'P', "%s", _( "Edit [P]roficiencies" ) ); nmenu.addentry( D_STATS, true, 't', "%s", _( "Edit s[t]ats" ) ); + nmenu.addentry( D_SPELLS, true, 'l', "%s", _( "Edit spe[l]ls" ) ); nmenu.addentry( D_ITEMS, true, 'i', "%s", _( "Grant [i]tems" ) ); nmenu.addentry( D_DELETE_ITEMS, true, 'd', "%s", _( "[d]elete (all) items" ) ); nmenu.addentry( D_ITEM_WORN, true, 'w', "%s", @@ -652,6 +1238,9 @@ void character_edit_menu() } } break; + case D_SPELLS: + change_spells( *p.as_character() ); + break; case D_PROF: wishproficiency( &p ); break; @@ -2075,57 +2664,9 @@ void debug() popup( popup_msg ); } break; - case debug_menu_index::LEARN_SPELLS: - if( spell_type::get_all().empty() ) { - add_msg( m_bad, _( "There are no spells to learn. You must install a mod that adds some." ) ); - } else { - for( const spell_type &learn : spell_type::get_all() ) { - player_character.magic->learn_spell( &learn, player_character, true ); - } - add_msg( m_good, - _( "You have become an Archwizardpriest! What will you do with your newfound power?" ) ); - } - break; - case debug_menu_index::LEVEL_SPELLS: { - std::vector spells = player_character.magic->get_spells(); - if( spells.empty() ) { - add_msg( m_bad, _( "Try learning some spells first." ) ); - return; - } - std::vector uiles; - { - uilist_entry uile( _( "Spell" ) ); - uile.ctxt = string_format( "%s %s", - //~ translation should not exceed 4 console cells - right_justify( _( "LVL" ), 4 ), - //~ translation should not exceed 4 console cells - right_justify( _( "MAX" ), 4 ) ); - uile.enabled = false; - uiles.emplace_back( uile ); - } - int retval = 0; - for( spell *sp : spells ) { - uilist_entry uile( sp->name() ); - uile.ctxt = string_format( "%4d %4d", sp->get_level(), sp->get_max_level() ); - uile.retval = retval++; - uile.enabled = !sp->is_max_level(); - uiles.emplace_back( uile ); - } - int action = uilist( _( "Debug level spell:" ), uiles ); - if( action < 0 ) { - return; - } - int desired_level = 0; - int cur_level = spells[action]->get_level(); - query_int( desired_level, _( "Desired Spell Level: (Current %d)" ), cur_level ); - desired_level = std::min( desired_level, spells[action]->get_max_level() ); - while( cur_level < desired_level ) { - spells[action]->gain_level(); - cur_level = spells[action]->get_level(); - } - add_msg( m_good, _( "%s is now level %d!" ), spells[action]->name(), spells[action]->get_level() ); + case debug_menu_index::CHANGE_SPELLS: + change_spells( player_character ); break; - } case debug_menu_index::TEST_MAP_EXTRA_DISTRIBUTION: MapExtras::debug_spawn_test(); break; diff --git a/src/debug_menu.h b/src/debug_menu.h index ac67b2c17f472..ab4d7656a0426 100644 --- a/src/debug_menu.h +++ b/src/debug_menu.h @@ -16,6 +16,7 @@ template class optional; } // namespace cata +class Character; class player; namespace debug_menu @@ -80,8 +81,7 @@ enum class debug_menu_index : int { DISPLAY_REACHABILITY_ZONES, DISPLAY_RADIATION, HOUR_TIMER, - LEARN_SPELLS, - LEVEL_SPELLS, + CHANGE_SPELLS, TEST_MAP_EXTRA_DISTRIBUTION, NESTED_MAPGEN, VEHICLE_BATTERY_CHARGE, @@ -89,6 +89,8 @@ enum class debug_menu_index : int { last }; +void change_spells( Character &character ); + void teleport_short(); void teleport_long(); void teleport_overmap( bool specific_coordinates = false ); diff --git a/src/magic.cpp b/src/magic.cpp index 49eb84e3851e4..0e12bcef19813 100644 --- a/src/magic.cpp +++ b/src/magic.cpp @@ -1260,7 +1260,7 @@ int spell::get_max_level() const // helper function to calculate xp needed to be at a certain level // pulled out as a helper function to make it easier to either be used in the future // or easier to tweak the formula -static int exp_for_level( int level ) +int spell::exp_for_level( int level ) { // level 0 never needs xp if( level == 0 ) { @@ -1825,7 +1825,7 @@ class spellcasting_callback : public uilist_callback } }; -static bool casting_time_encumbered( const spell &sp, const Character &guy ) +bool spell_desc::casting_time_encumbered( const spell &sp, const Character &guy ) { int encumb = 0; if( !sp.has_flag( spell_flag::NO_LEGS ) ) { @@ -1841,7 +1841,7 @@ static bool casting_time_encumbered( const spell &sp, const Character &guy ) return encumb > 0; } -static bool energy_cost_encumbered( const spell &sp, const Character &guy ) +bool spell_desc::energy_cost_encumbered( const spell &sp, const Character &guy ) { if( !sp.has_flag( spell_flag::NO_HANDS ) ) { return std::max( 0, guy.encumb( bodypart_id( "hand_l" ) ) + guy.encumb( @@ -1853,7 +1853,7 @@ static bool energy_cost_encumbered( const spell &sp, const Character &guy ) // this prints various things about the spell out in a list // including flags and things like "goes through walls" -static std::string enumerate_spell_data( const spell &sp ) +std::string spell_desc::enumerate_spell_data( const spell &sp ) { std::vector spell_data; if( sp.has_flag( spell_flag::CONCENTRATE ) ) { @@ -1904,7 +1904,7 @@ void spellcasting_callback::draw_spell_info( const spell &sp, const uilist *menu line++; line += fold_and_print( w_menu, point( h_col1, line ), info_width, gray, - enumerate_spell_data( sp ) ); + spell_desc::enumerate_spell_data( sp ) ); if( line <= win_height / 3 ) { line++; } @@ -1930,7 +1930,7 @@ void spellcasting_callback::draw_spell_info( const spell &sp, const uilist *menu line++; } - const bool cost_encumb = energy_cost_encumbered( sp, player_character ); + const bool cost_encumb = spell_desc::energy_cost_encumbered( sp, player_character ); std::string cost_string = cost_encumb ? _( "Casting Cost (impeded)" ) : _( "Casting Cost" ); std::string energy_cur = sp.energy_source() == magic_energy_type::hp ? "" : string_format( _( " (%s current)" ), sp.energy_cur_string( player_character ) ); @@ -1941,7 +1941,7 @@ void spellcasting_callback::draw_spell_info( const spell &sp, const uilist *menu print_colored_text( w_menu, point( h_col1, line++ ), gray, gray, string_format( "%s: %s %s%s", cost_string, sp.energy_cost_string( player_character ), sp.energy_string(), energy_cur ) ); - const bool c_t_encumb = casting_time_encumbered( sp, player_character ); + const bool c_t_encumb = spell_desc::casting_time_encumbered( sp, player_character ); print_colored_text( w_menu, point( h_col1, line++ ), gray, gray, colorize( string_format( "%s: %s", c_t_encumb ? _( "Casting Time (impeded)" ) : _( "Casting Time" ), moves_to_string( sp.casting_time( player_character ) ) ), diff --git a/src/magic.h b/src/magic.h index a4b7ed49c7d6f..7a47b9e271845 100644 --- a/src/magic.h +++ b/src/magic.h @@ -286,7 +286,7 @@ class spell_type // increment of energy cost per spell level float energy_increment = 0.0f; // max or min energy cost, based on sign of energy_increment - int final_energy_cost = 0.0f; + int final_energy_cost = 0; // spell is restricted to being cast by only this class // if spell_class is empty, spell is unrestricted @@ -380,6 +380,14 @@ class spell_type static const float casting_time_increment_default; }; +// functions for spell description +namespace spell_desc +{ +bool casting_time_encumbered( const spell &sp, const Character &guy ); +bool energy_cost_encumbered( const spell &sp, const Character &guy ); +std::string enumerate_spell_data( const spell &sp ); +} // namespace spell_desc + class spell { private: @@ -410,6 +418,7 @@ class spell // sets the message to be different than the spell_type specifies void set_message( const translation &msg ); + static int exp_for_level( int level ); // how much exp you need for the spell to gain a level int exp_to_next_level() const; // progress to the next level, expressed as a percent @@ -600,6 +609,10 @@ class known_magic int select_spell( Character &guy ); // get all known spells std::vector get_spells(); + // directly get the character known spells + std::map &get_spellbook() { + return spellbook; + } // how much mana is available to use to cast spells int available_mana() const; // max mana vailable diff --git a/src/output.cpp b/src/output.cpp index 13872e51592c1..cdd163a12ce1f 100644 --- a/src/output.cpp +++ b/src/output.cpp @@ -616,7 +616,7 @@ border_helper::border_info &border_helper::add_border() return border_info_list.front(); } -void border_helper::draw_border( const catacurses::window &win ) +void border_helper::draw_border( const catacurses::window &win, nc_color border_color ) { if( !border_connection_map.has_value() ) { border_connection_map.emplace(); @@ -654,7 +654,7 @@ void border_helper::draw_border( const catacurses::window &win ) for( const std::pair &conn : border_connection_map.value() ) { if( conn.first.x >= win_beg.x && conn.first.x < win_end.x && conn.first.y >= win_beg.y && conn.first.y < win_end.y ) { - mvwputch( win, conn.first - win_beg, BORDER_COLOR, conn.second.as_curses_line() ); + mvwputch( win, conn.first - win_beg, border_color, conn.second.as_curses_line() ); } } } diff --git a/src/output.h b/src/output.h index 634b76bb730ba..f4732ae2cc447 100644 --- a/src/output.h +++ b/src/output.h @@ -411,7 +411,7 @@ class border_helper }; border_info &add_border(); - void draw_border( const catacurses::window &win ); + void draw_border( const catacurses::window &win, nc_color border_color = BORDER_COLOR ); friend class border_info; private: From 089f172af8327cf65ea551918da5e65bcea3dc65 Mon Sep 17 00:00:00 2001 From: Xenomorph-III Date: Fri, 19 Mar 2021 09:24:38 +1300 Subject: [PATCH 292/453] Add MRE chocolate to the game (#47935) --- .../locations_commercial.json | 1 + data/json/itemgroups/military.json | 2 +- data/json/items/comestibles/junkfood.json | 16 ++++++++++++++++ 3 files changed, 18 insertions(+), 1 deletion(-) diff --git a/data/json/itemgroups/Locations_MapExtras/locations_commercial.json b/data/json/itemgroups/Locations_MapExtras/locations_commercial.json index 86e767c5ee80d..898c9df2cbba2 100644 --- a/data/json/itemgroups/Locations_MapExtras/locations_commercial.json +++ b/data/json/itemgroups/Locations_MapExtras/locations_commercial.json @@ -629,6 +629,7 @@ "items": [ { "group": "mags_surplus", "prob": 400 }, [ "freeze_dried_meal", 20 ], + [ "chocolate_military", 20 ], [ "knife_combat", 14 ], [ "knife_rm42", 1 ], [ "kukri", 2 ], diff --git a/data/json/itemgroups/military.json b/data/json/itemgroups/military.json index a131b428e8af7..e30aa57f053ec 100644 --- a/data/json/itemgroups/military.json +++ b/data/json/itemgroups/military.json @@ -471,7 +471,7 @@ "subtype": "distribution", "entries": [ { "group": "MRE", "prob": 1035 }, - { "item": "chocolate", "prob": 50 }, + { "item": "chocolate", "prob": 20 }, { "item": "neccowafers", "prob": 30 }, { "item": "can_beans", "prob": 40 }, { "item": "pork_beans", "prob": 40 }, diff --git a/data/json/items/comestibles/junkfood.json b/data/json/items/comestibles/junkfood.json index 1e6b73eaa5ebd..d4dcab3534861 100644 --- a/data/json/items/comestibles/junkfood.json +++ b/data/json/items/comestibles/junkfood.json @@ -1378,6 +1378,22 @@ "vitamins": [ [ "vitA", 3 ], [ "iron", 10 ] ], "fun": 4 }, + { + "type": "COMESTIBLE", + "id": "chocolate_military", + "name": { "str": "military chocolate bar" }, + "color": "brown", + "symbol": "%", + "calories": 600, + "weight": "115 g", + "description": "A thick, dense bar of military chocolate. While tough to chew and not very appetizing, it will provide almost a day's worth of calories in portable form.", + "price": 250, + "price_postapoc": 500, + "material": [ "junk" ], + "volume": "500 ml", + "flags": [ "EDIBLE_FROZEN" ], + "fun": -3 + }, { "type": "COMESTIBLE", "id": "gelatin_dessert_powder", From a89bdfdb7fb4d9b3dc6c6be25afff0048ac5f353 Mon Sep 17 00:00:00 2001 From: Michael Macha Date: Thu, 18 Mar 2021 14:27:38 -0600 Subject: [PATCH 293/453] Update 40x46mm.json (#47859) --- data/json/items/ammo/40x46mm.json | 28 ++++++++++++++++++++++++++++ 1 file changed, 28 insertions(+) diff --git a/data/json/items/ammo/40x46mm.json b/data/json/items/ammo/40x46mm.json index 4b469fef32013..e748f47a91221 100644 --- a/data/json/items/ammo/40x46mm.json +++ b/data/json/items/ammo/40x46mm.json @@ -179,5 +179,33 @@ "name": { "str_sp": "40x46mm-M199 flechette, black powder" }, "description": "An improvised 40x46mm flechette load containing 10 steel darts, loaded into a M199 canister. Due to the limitations of weapons built to fire 40x46mm grenades, it's much less powerful than most people would expect.", "casing": "40x46mm_m199_casing" + }, + { + "id": "40x46mm_hornets_nest_22lr", + "copy-from": "40x46mm_grenade", + "type": "AMMO", + "name": { "str_sp": "40x46mm .22 LR hornet's nest" }, + "proportional": { "dispersion": 1.8 }, + "description": "A set of ten .22 LR bullets compressed into a 40mm adapter. Fires all ten rounds simultaneously.", + "weight": "114 g", + "price": 1500, + "price_postapoc": 2400, + "material": [ "aluminum", "brass", "lead", "powder" ], + "damage": { "damage_type": "bullet", "amount": 100 }, + "casing": "40x46mm_m212_casing" + }, + { + "id": "40x46mm_hornets_nest_410", + "copy-from": "40x46mm_grenade", + "type": "AMMO", + "name": { "str_sp": "40x46mm .410 hornet's nest" }, + "proportional": { "dispersion": 1.4 }, + "description": "A set of four .410 shells compressed into a 40mm adapter. Fires all four rounds at once.", + "weight": "245 g", + "price": 710, + "price_postapoc": 3240, + "material": [ "aluminum", "brass", "lead", "powder" ], + "damage": { "damage_type": "bullet", "amount": 120 }, + "casing": "40x46mm_m212_casing" } ] From b0bbed16e79db847d86dee4467df58206d927e44 Mon Sep 17 00:00:00 2001 From: Viss Valdyr <33199510+Lamandus@users.noreply.github.com> Date: Thu, 18 Mar 2021 21:28:23 +0100 Subject: [PATCH 294/453] Tweaks for crowbar and makeshift crowbar (#47827) --- data/json/items/tool/entry_tools.json | 14 +++++++------- data/mods/TEST_DATA/items.json | 8 ++++---- tests/item_contents_test.cpp | 7 ++++--- tests/iteminfo_test.cpp | 4 ++-- 4 files changed, 17 insertions(+), 16 deletions(-) diff --git a/data/json/items/tool/entry_tools.json b/data/json/items/tool/entry_tools.json index 82d3a8d592ae5..90b2f41e1323d 100644 --- a/data/json/items/tool/entry_tools.json +++ b/data/json/items/tool/entry_tools.json @@ -3,10 +3,10 @@ "id": "crowbar", "type": "TOOL", "name": { "str": "crowbar" }, - "description": "This is a hefty prying tool. Use it to open locked doors without destroying them or to lift manhole covers. You could also wield it to bash some heads in.", - "weight": "500 g", - "volume": "1 L", - "longest_side": "60 cm", + "description": "This is a hefty prying tool. Use it to open locked doors without destroying them, or to lift manhole covers. You could also wield it to bash some heads in.", + "weight": "1200 g", + "volume": "170 ml", + "longest_side": "50 cm", "price": 1300, "price_postapoc": 500, "to_hit": -1, @@ -61,9 +61,9 @@ "id": "makeshift_crowbar", "type": "TOOL", "name": { "str": "makeshift crowbar" }, - "description": "This is a pipe whose ends have been bent and hammered flat to resemble a crowbar. Use it to open locked crates without destroying them, or to lift manhole covers. You could also wield it to fight with, in a pinch.", - "weight": "1000 g", - "volume": "1 L", + "description": "This is a pipe with ends that have been bent and hammered flat so it resembles a crowbar. Use it to open locked crates without destroying them, or to lift manhole covers. You could also wield it to fight with, in a pinch.", + "weight": "1250 g", + "volume": "350 ml", "longest_side": "60 cm", "price": 0, "price_postapoc": 10, diff --git a/data/mods/TEST_DATA/items.json b/data/mods/TEST_DATA/items.json index 3fd587bede745..9e5e5c6b47de8 100644 --- a/data/mods/TEST_DATA/items.json +++ b/data/mods/TEST_DATA/items.json @@ -119,7 +119,7 @@ "min_item_volume": "50 ml", "max_item_length": "70 cm", "max_contains_volume": "1500 ml", - "max_contains_weight": "1000 g", + "max_contains_weight": "1200 g", "moves": 50, "flag_restriction": [ "BELT_CLIP", "SHEATH_KNIFE" ] }, @@ -128,7 +128,7 @@ "min_item_volume": "50 ml", "max_item_length": "70 cm", "max_contains_volume": "1500 ml", - "max_contains_weight": "1000 g", + "max_contains_weight": "1200 g", "moves": 50, "flag_restriction": [ "BELT_CLIP", "SHEATH_KNIFE" ] }, @@ -137,7 +137,7 @@ "min_item_volume": "50 ml", "max_item_length": "70 cm", "max_contains_volume": "1500 ml", - "max_contains_weight": "1000 g", + "max_contains_weight": "1200 g", "moves": 50, "flag_restriction": [ "BELT_CLIP", "SHEATH_KNIFE" ] }, @@ -146,7 +146,7 @@ "min_item_volume": "50 ml", "max_item_length": "70 cm", "max_contains_volume": "1500 ml", - "max_contains_weight": "1000 g", + "max_contains_weight": "1200 g", "moves": 50, "flag_restriction": [ "BELT_CLIP", "SHEATH_KNIFE" ] } diff --git a/tests/item_contents_test.cpp b/tests/item_contents_test.cpp index 7a07eed26732e..72da9133a96e3 100644 --- a/tests/item_contents_test.cpp +++ b/tests/item_contents_test.cpp @@ -54,10 +54,11 @@ TEST_CASE( "item_contents" ) CHECK( tool_belt.weight() == tool_belt_weight + hammer.weight() + tongs.weight() + wrench.weight() + crowbar.weight() ); // check that the tool belt is "full" - CHECK( !tool_belt.contents.can_contain( hammer ).success() ); + CHECK( !tool_belt.contents.can_contain( crowbar ).success() ); - tool_belt.contents.force_insert_item( hammer, item_pocket::pocket_type::CONTAINER ); + tool_belt.contents.force_insert_item( crowbar, item_pocket::pocket_type::CONTAINER ); CHECK( tool_belt.contents.num_item_stacks() == 5 ); + tool_belt.contents.force_insert_item( crowbar, item_pocket::pocket_type::CONTAINER ); tool_belt.contents.overflow( tripoint_zero ); CHECK( tool_belt.contents.num_item_stacks() == 4 ); tool_belt.contents.overflow( tripoint_zero ); @@ -65,7 +66,7 @@ TEST_CASE( "item_contents" ) CHECK( tool_belt.contents.num_item_stacks() == 4 ); tool_belt.contents.remove_items_if( []( item & it ) { - return it.typeId() == itype_id( "hammer" ); + return it.typeId() == itype_id( "crowbar" ); } ); // check to see that removing an item works CHECK( tool_belt.contents.num_item_stacks() == 3 ); diff --git a/tests/iteminfo_test.cpp b/tests/iteminfo_test.cpp index 7bd2648e7708b..50f65d312926c 100644 --- a/tests/iteminfo_test.cpp +++ b/tests/iteminfo_test.cpp @@ -2470,10 +2470,10 @@ TEST_CASE( "pocket info for a multi-pocket item", "[iteminfo][pocket][multiple]" CHECK( item_info_str( test_belt, pockets ) == "--\n" "Total capacity:\n" - "Volume: 6.00 L Weight: 4.00 kg\n" + "Volume: 6.00 L Weight: 4.80 kg\n" "--\n" "4 Pockets with capacity:\n" - "Volume: 1.50 L Weight: 1.00 kg\n" + "Volume: 1.50 L Weight: 1.20 kg\n" "Maximum item length: 70 cm\n" "Minimum item volume: 0.050 L\n" "Base moves to remove item: 50\n" From f0a63e643a503ce20cb12591a46033ce292cbb9b Mon Sep 17 00:00:00 2001 From: Venera3 <72006894+Venera3@users.noreply.github.com> Date: Thu, 18 Mar 2021 21:29:07 +0100 Subject: [PATCH 295/453] Add a new anger/fear trigger (#47792) --- doc/JSON_FLAGS.md | 19 +++++++++++-------- doc/MONSTERS.md | 10 +++++----- src/monmove.cpp | 25 ++++++++++++++++++++++++- src/monstergenerator.cpp | 1 + src/mtype.h | 1 + 5 files changed, 42 insertions(+), 14 deletions(-) diff --git a/doc/JSON_FLAGS.md b/doc/JSON_FLAGS.md index cc51f33b43343..204ad72fee97a 100644 --- a/doc/JSON_FLAGS.md +++ b/doc/JSON_FLAGS.md @@ -823,16 +823,19 @@ Flags used to describe monsters and define their properties and abilities. ### Anger, Fear and Placation Triggers -- ```FIRE``` There's a fire nearby. -- ```FRIEND_ATTACKED``` A monster of the same type was attacked. -- ```FRIEND_DIED``` A monster of the same type died. -- ```HURT``` The monster is hurt. +- ```FIRE``` Triggers if there's a fire within 3 tiles, the strength of the effect equals 5 * the field intensity of the fire. +- ```FRIEND_ATTACKED``` Triggers if the monster sees another monster of the same type being attacked; strength = 15. +- ```FRIEND_DIED``` Triggers if the monster sees another monster of the same type dying; strength = 15. +- ```HURT``` Triggers when the monster is hurt, strength equals 1 + (damage / 3 ). - ```MEAT``` Meat or a corpse is nearby. - Currently nonfunctional! - ```NULL``` Source use only? -- ```PLAYER_CLOSE``` The player gets within a few tiles distance. -- ```PLAYER_WEAK``` The player is hurt. -- ```SOUND``` Heard a sound. -- ```STALK``` Increases if already angry at the player. +- ```PLAYER_CLOSE``` Triggers when a potential enemy is within 5 tiles range - Anger/fear trigger only! +- ```PLAYER_WEAK``` Raises monster aggression by 10 - (percent of hp remaining / 10) if a potential enemy has less than 70% hp remaining - Anger trigger only! +- ```PLAYER_NEAR_BABY``` Increases monster aggression by 8 and morale by 4 if **the player** comes within 3 tiles of its offspring (defined by the baby_monster field in its reproduction data)- Anger trigger only! +- ```SOUND``` Not an actual trigger, monsters above 10 aggression and 0 morale will wander towards, monsters below 0 morale will wander away from the source of the sound for 1 turn (6, if they have the GOODHEARING flag). +- ```STALK``` Raises monster aggresssion by 1, triggers 20% of the time each turn if aggression > 5 - Anger trigger only! +- ```HOSTILE_SEEN``` Increases aggression/ decreases morale by a random amount between 0-2 for every potential enemy it can see, up to 20 aggression - Anger/fear trigger only! +- ```MATING_SEASON``` Increases aggression by 3 if a potential enemy is within 5 tiles range and the season is the same as the monster's mating season (defined by the baby_flags field in its reproduction data) - Anger trigger only! ### Categories diff --git a/doc/MONSTERS.md b/doc/MONSTERS.md index edae93eac052a..6e16aea25d22d 100644 --- a/doc/MONSTERS.md +++ b/doc/MONSTERS.md @@ -47,8 +47,8 @@ Monsters may also have any of these optional properties: | `phase` | (string) Monster's body matter state, ex. SOLID, LIQUID, GAS, PLASMA, NULL | `attack_cost` | (integer) Number of moves per regular attack (??) | `diff` | (integer) Additional monster difficulty for special and ranged attacks -| `aggression` | (integer) From totally passive `-99` to guaranteed hostile `100` -| `morale` | (integer) From lemming `-50` to bear `60` to most zombies and monsters `100` +| `aggression` | (integer) Starting aggression, the monster will become hostile when it reaches 10 +| `morale` | (integer) Starting morale, monster will flee when (current aggression + current morale) < 0 | `mountable_weight_ratio` | (float) For mounts, max ratio of mount to rider weight, ex. `0.2` for `<=20%` | `melee_skill` | (integer) Monster skill in melee combat, from `0-10`, with `4` being an average mob | `dodge` | (integer) Monster's skill at dodging attacks @@ -74,9 +74,9 @@ Monsters may also have any of these optional properties: | `regen_morale` | (bool) True if monster will stop fleeing at max HP to regenerate anger and morale | `special_attacks` | (array of objects) Special attacks the monster has | `flags` | (array of strings) Any number of attributes like SEES, HEARS, SMELLS, STUMBLES, REVIVES -| `fear_triggers` | (array of strings) What makes the monster afraid, ex. FIRE, HURT, PLAYER_CLOSE, SOUND -| `anger_triggers` | (array of strings) What makes the monster angry (same flags as fear) -| `placate_triggers` | (array of strings) What calms the monster (same flags as fear) +| `fear_triggers` | (array of strings) Triggers that lower monster morale (see JSON_FLAGS.md) +| `anger_triggers` | (array of strings) Triggers that raise monster aggression (same flags as fear) +| `placate_triggers` | (array of strings) Triggers that lower monster aggression (same flags as fear) | `revert_to_itype` | (string) Item monster can be converted to when friendly (ex. to deconstruct turrets) | `starting_ammo` | (object) Ammo that newly spawned monsters start with | `upgrades` | (boolean or object) False if monster does not upgrade, or an object do define an upgrade diff --git a/src/monmove.cpp b/src/monmove.cpp index c8e8c3421e605..f6e9f57d51bdc 100644 --- a/src/monmove.cpp +++ b/src/monmove.cpp @@ -326,9 +326,13 @@ void monster::plan() const bool angers_hostile_weak = type->has_anger_trigger( mon_trigger::HOSTILE_WEAK ); const int angers_hostile_near = type->has_anger_trigger( mon_trigger::HOSTILE_CLOSE ) ? 5 : 0; + const int angers_hostile_seen = type->has_anger_trigger( mon_trigger::HOSTILE_SEEN ) ? rng( 0, + 2 ) : 0; const int angers_mating_season = type->has_anger_trigger( mon_trigger::MATING_SEASON ) ? 3 : 0; const int angers_cub_threatened = type->has_anger_trigger( mon_trigger::PLAYER_NEAR_BABY ) ? 8 : 0; const int fears_hostile_near = type->has_fear_trigger( mon_trigger::HOSTILE_CLOSE ) ? 5 : 0; + const int fears_hostile_seen = type->has_fear_trigger( mon_trigger::HOSTILE_SEEN ) ? rng( 0, + 2 ) : 0; map &here = get_map(); std::bitset seen_levels = here.get_inter_level_visibility( pos().z ); @@ -342,6 +346,12 @@ void monster::plan() dist = rate_target( player_character, dist, smart_planning ); fleeing = fleeing || is_fleeing( player_character ); target = &player_character; + if( !fleeing && anger <= 20 ) { + anger += angers_hostile_seen; + } + if( !fleeing ) { + morale -= fears_hostile_seen; + } if( dist <= 5 ) { anger += angers_hostile_near; morale -= fears_hostile_near; @@ -407,7 +417,8 @@ void monster::plan() float rating = rate_target( who, dist, smart_planning ); bool fleeing_from = is_fleeing( who ); - if( rating == dist && ( fleeing || attitude( &who ) == MATT_ATTACK ) ) { + if( rating == dist && ( fleeing || attitude( &who ) == MATT_ATTACK || + attitude( &who ) == MATT_FOLLOW ) ) { ++valid_targets; if( one_in( valid_targets ) ) { target = &who; @@ -443,6 +454,12 @@ void monster::plan() } } } + if( !fleeing && anger <= 20 && valid_targets != 0 ) { + anger += angers_hostile_seen; + } + if( !fleeing && valid_targets != 0 ) { + morale -= fears_hostile_seen; + } } fleeing = fleeing || ( mood == MATT_FLEE ); @@ -486,6 +503,12 @@ void monster::plan() anger += angers_hostile_near; morale -= fears_hostile_near; } + if( !fleeing && anger <= 20 && valid_targets != 0 ) { + anger += angers_hostile_seen; + } + if( !fleeing && valid_targets != 0 ) { + morale -= fears_hostile_seen; + } } } } diff --git a/src/monstergenerator.cpp b/src/monstergenerator.cpp index 223489edcfe5a..18dc7e8886a52 100644 --- a/src/monstergenerator.cpp +++ b/src/monstergenerator.cpp @@ -52,6 +52,7 @@ std::string enum_to_string( mon_trigger data ) case mon_trigger::MEAT: return "MEAT"; case mon_trigger::HOSTILE_WEAK: return "PLAYER_WEAK"; case mon_trigger::HOSTILE_CLOSE: return "PLAYER_CLOSE"; + case mon_trigger::HOSTILE_SEEN: return "HOSTILE_SEEN"; case mon_trigger::HURT: return "HURT"; case mon_trigger::FIRE: return "FIRE"; case mon_trigger::FRIEND_DIED: return "FRIEND_DIED"; diff --git a/src/mtype.h b/src/mtype.h index d5e09a9d623d7..229fb8beb7697 100644 --- a/src/mtype.h +++ b/src/mtype.h @@ -42,6 +42,7 @@ enum class mon_trigger : int { MEAT, // Meat or a corpse nearby HOSTILE_WEAK, // Hurt hostile player/npc/monster seen HOSTILE_CLOSE, // Hostile creature within a few tiles + HOSTILE_SEEN, // Hostile creature in visual range HURT, // We are hurt FIRE, // Fire nearby FRIEND_DIED, // A monster of the same type died From bd933360e5608069cde1af182fec74226839e653 Mon Sep 17 00:00:00 2001 From: RadHazard Date: Thu, 18 Mar 2021 20:30:08 +0000 Subject: [PATCH 296/453] Add more nutrition debug (#47716) * add stomach and gut kCal to the debug menu * Add detailed stomach and gut data to the needs menu * add debug command to edit the faction camp larder * Add debug command to empty a character's stomach & guts * Add stored & total kCal view to the info box --- src/debug_menu.cpp | 77 ++++++++++++++++++++++++++++++++++++++++------ src/debug_menu.h | 1 + 2 files changed, 69 insertions(+), 9 deletions(-) diff --git a/src/debug_menu.cpp b/src/debug_menu.cpp index 90f149caf6292..d211f0d5a99d3 100644 --- a/src/debug_menu.cpp +++ b/src/debug_menu.cpp @@ -99,6 +99,7 @@ #include "ui.h" #include "ui_manager.h" #include "units.h" +#include "units_utility.h" #include "veh_type.h" #include "vehicle.h" #include "vitamin.h" @@ -191,6 +192,7 @@ std::string enum_to_string( debug_menu::debug_menu case debug_menu::debug_menu_index::CHANGE_SPELLS: return "CHANGE_SPELLS"; case debug_menu::debug_menu_index::TEST_MAP_EXTRA_DISTRIBUTION: return "TEST_MAP_EXTRA_DISTRIBUTION"; case debug_menu::debug_menu_index::NESTED_MAPGEN: return "NESTED_MAPGEN"; + case debug_menu::debug_menu_index::EDIT_CAMP_LARDER: return "EDIT_CAMP_LARDER"; case debug_menu::debug_menu_index::VEHICLE_BATTERY_CHARGE: return "VEHICLE_BATTERY_CHARGE"; case debug_menu::debug_menu_index::GENERATE_EFFECT_LIST: return "GENERATE_EFFECT_LIST"; // *INDENT-ON* @@ -344,6 +346,7 @@ static int map_uilist() { uilist_entry( debug_menu_index::OM_EDITOR, true, 'O', _( "Overmap editor" ) ) }, { uilist_entry( debug_menu_index::MAP_EXTRA, true, 'm', _( "Spawn map extra" ) ) }, { uilist_entry( debug_menu_index::NESTED_MAPGEN, true, 'n', _( "Spawn nested mapgen" ) ) }, + { uilist_entry( debug_menu_index::EDIT_CAMP_LARDER, true, 'l', _( "Edit the faction camp larder" ) ) }, }; return uilist( _( "Map…" ), uilist_initializer ); @@ -1485,13 +1488,43 @@ void character_edit_menu() } break; case D_NEEDS: { + std::pair hunger_pair = p.get_hunger_description(); + std::pair thirst_pair = p.get_thirst_description(); + std::pair fatigue_pair = p.get_fatigue_description(); + + std::stringstream data; + data << string_format( _( "Hunger: %d %s" ), p.get_hunger(), colorize( hunger_pair.first, + hunger_pair.second ) ) << std::endl; + data << string_format( _( "Thirst: %d %s" ), p.get_thirst(), colorize( thirst_pair.first, + thirst_pair.second ) ) << std::endl; + data << string_format( _( "Fatigue: %d %s" ), p.get_fatigue(), colorize( fatigue_pair.first, + fatigue_pair.second ) ) << std::endl; + data << std::endl; + data << _( "Stored kCal: " ) << p.get_stored_kcal() << std::endl; + data << _( "Total kCal: " ) << p.get_stored_kcal() + p.stomach.get_calories() + + p.guts.get_calories() << std::endl; + data << std::endl; + data << _( "Stomach contents" ) << std::endl; + data << _( " Total volume: " ) << vol_to_string( p.stomach.contains() ) << std::endl; + data << _( " Water volume: " ) << vol_to_string( p.stomach.get_water() ) << std::endl; + data << string_format( _( " kCal: %d" ), p.stomach.get_calories() ) << std::endl; + data << std::endl; + data << _( "Gut contents" ) << std::endl; + data << _( " Total volume: " ) << vol_to_string( p.guts.contains() ) << std::endl; + data << _( " Water volume: " ) << vol_to_string( p.guts.get_water() ) << std::endl; + data << string_format( _( " kCal: %d" ), p.guts.get_calories() ) << std::endl; + uilist smenu; + smenu.text = data.str(); smenu.addentry( 0, true, 'h', "%s: %d", _( "Hunger" ), p.get_hunger() ); smenu.addentry( 1, true, 's', "%s: %d", _( "Stored kCal" ), p.get_stored_kcal() ); - smenu.addentry( 2, true, 't', "%s: %d", _( "Thirst" ), p.get_thirst() ); - smenu.addentry( 3, true, 'f', "%s: %d", _( "Fatigue" ), p.get_fatigue() ); - smenu.addentry( 4, true, 'd', "%s: %d", _( "Sleep Deprivation" ), p.get_sleep_deprivation() ); - smenu.addentry( 5, true, 'a', _( "Reset all basic needs" ) ); + smenu.addentry( 2, true, 'S', "%s: %d", _( "Stomach kCal" ), p.stomach.get_calories() ); + smenu.addentry( 3, true, 'G', "%s: %d", _( "Gut kCal" ), p.guts.get_calories() ); + smenu.addentry( 4, true, 't', "%s: %d", _( "Thirst" ), p.get_thirst() ); + smenu.addentry( 5, true, 'f', "%s: %d", _( "Fatigue" ), p.get_fatigue() ); + smenu.addentry( 6, true, 'd', "%s: %d", _( "Sleep Deprivation" ), p.get_sleep_deprivation() ); + smenu.addentry( 7, true, 'a', _( "Reset all basic needs" ) ); + smenu.addentry( 8, true, 'e', _( "Empty stomach and guts" ) ); const auto &vits = vitamin::all(); for( const auto &v : vits ) { @@ -1514,24 +1547,36 @@ void character_edit_menu() break; case 2: + if( query_int( value, _( "Set stomach kCal to? Currently: %d" ), p.stomach.get_calories() ) ) { + p.stomach.mod_calories( value - p.stomach.get_calories() ); + } + break; + + case 3: + if( query_int( value, _( "Set gut kCal to? Currently: %d" ), p.guts.get_calories() ) ) { + p.guts.mod_calories( value - p.guts.get_calories() ); + } + break; + + case 4: if( query_int( value, _( "Set thirst to? Currently: %d" ), p.get_thirst() ) ) { p.set_thirst( value ); } break; - case 3: + case 5: if( query_int( value, _( "Set fatigue to? Currently: %d" ), p.get_fatigue() ) ) { p.set_fatigue( value ); } break; - case 4: + case 6: if( query_int( value, _( "Set sleep deprivation to? Currently: %d" ), p.get_sleep_deprivation() ) ) { p.set_sleep_deprivation( value ); } break; - case 5: + case 7: p.initialize_stomach_contents(); p.set_hunger( 0 ); p.set_thirst( 0 ); @@ -1539,9 +1584,13 @@ void character_edit_menu() p.set_sleep_deprivation( 0 ); p.set_stored_kcal( p.get_healthy_kcal() ); break; + case 8: + p.stomach.empty(); + p.guts.empty(); + break; default: - if( smenu.ret >= 6 && smenu.ret < static_cast( vits.size() + 6 ) ) { - auto iter = std::next( vits.begin(), smenu.ret - 6 ); + if( smenu.ret >= 9 && smenu.ret < static_cast( vits.size() + 9 ) ) { + auto iter = std::next( vits.begin(), smenu.ret - 9 ); if( query_int( value, _( "Set %s to? Currently: %d" ), iter->second.name(), p.vitamin_get( iter->first ) ) ) { p.vitamin_set( iter->first, value ); @@ -2712,6 +2761,16 @@ void debug() break; } + case debug_menu_index::EDIT_CAMP_LARDER: { + faction *your_faction = get_player_character().get_faction(); + int larder; + if( query_int( larder, _( "Set camp larder kCals to? Currently: %d" ), + your_faction->food_supply ) ) { + your_faction->food_supply = larder; + } + break; + } + case debug_menu_index::last: return; } diff --git a/src/debug_menu.h b/src/debug_menu.h index ab4d7656a0426..c40f657c9f327 100644 --- a/src/debug_menu.h +++ b/src/debug_menu.h @@ -86,6 +86,7 @@ enum class debug_menu_index : int { NESTED_MAPGEN, VEHICLE_BATTERY_CHARGE, GENERATE_EFFECT_LIST, + EDIT_CAMP_LARDER, last }; From e12723623d93a2b28d9d17fb44934db9e94129b6 Mon Sep 17 00:00:00 2001 From: Maleclypse <54345792+Maleclypse@users.noreply.github.com> Date: Fri, 19 Mar 2021 00:20:36 -0500 Subject: [PATCH 297/453] Update Aftershock README.md (#48123) --- data/mods/Aftershock/README.md | 1 + 1 file changed, 1 insertion(+) diff --git a/data/mods/Aftershock/README.md b/data/mods/Aftershock/README.md index 65effb2a00561..4acaa6a627b6c 100644 --- a/data/mods/Aftershock/README.md +++ b/data/mods/Aftershock/README.md @@ -9,6 +9,7 @@ 4. Missions, locations, and lore snippets. We want this to feel like a world just as real as Cataclysm Prime. Please feel free to reach out to us about ideas and implementations. 5. Alien world basics would be especially desirable at this time. Flora, fauna, terrain, and furniture that make it clear we are no longer on earth. +# Size as of 0.F Stable : 31,084 Lines # Here be dragons! From d6d80927ea74a1280a10a578fbf2baf5326f971d Mon Sep 17 00:00:00 2001 From: tsulh Date: Sun, 21 Mar 2021 08:02:59 +0200 Subject: [PATCH 298/453] fix a typo (#48131) --- data/json/mutations/mutation_enchantments.json | 2 +- data/mods/TEST_DATA/enchantments.json | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/data/json/mutations/mutation_enchantments.json b/data/json/mutations/mutation_enchantments.json index 344f99a397d78..8421a76188920 100644 --- a/data/json/mutations/mutation_enchantments.json +++ b/data/json/mutations/mutation_enchantments.json @@ -8,7 +8,7 @@ "hit_self": false, "once_in": 15, "message": "Your ink glands spray some ink into %2$s's eyes.", - "npc_message": "%1$s's ink glands spay some ink into %2$s's eyes." + "npc_message": "%1$s's ink glands spray some ink into %2$s's eyes." } ] } diff --git a/data/mods/TEST_DATA/enchantments.json b/data/mods/TEST_DATA/enchantments.json index 150617c6df896..fa9c4ceb3b020 100644 --- a/data/mods/TEST_DATA/enchantments.json +++ b/data/mods/TEST_DATA/enchantments.json @@ -10,7 +10,7 @@ "id": "generic_blinding_spray_1", "hit_self": false, "message": "Your ink glands spray some ink into %2$s's eyes.", - "npc_message": "%1$s's ink glands spay some ink into %2$s's eyes." + "npc_message": "%1$s's ink glands spray some ink into %2$s's eyes." } ], "ench_effects": [ { "effect": "invisibility", "intensity": 1 } ] From 6f46661838207a4cce4d0a02ae327094873b83a1 Mon Sep 17 00:00:00 2001 From: Kevin Granade Date: Wed, 17 Mar 2021 11:26:26 -0700 Subject: [PATCH 299/453] Remove recycler and associated infrastructure (#48096) --- .../terrain-manufactured.json | 3 +- data/json/materials.json | 34 ++---- data/mods/Dark-Skies-Above/materials.json | 3 +- data/mods/Magiclysm/materials.json | 6 +- doc/JSON_FLAGS.md | 34 ++++++ src/iexamine.cpp | 111 ------------------ src/iexamine.h | 1 - src/material.cpp | 36 ------ src/material.h | 7 -- 9 files changed, 49 insertions(+), 186 deletions(-) diff --git a/data/json/furniture_and_terrain/terrain-manufactured.json b/data/json/furniture_and_terrain/terrain-manufactured.json index 19993a1493ca3..405f93674385c 100644 --- a/data/json/furniture_and_terrain/terrain-manufactured.json +++ b/data/json/furniture_and_terrain/terrain-manufactured.json @@ -3,14 +3,13 @@ "type": "terrain", "id": "t_recycler", "name": "metal compactor", - "description": "A hydraulic compactor that can accept items made of various metals, and press them into basic shapes, ready for further crafting.", + "description": "A hydraulic machine for squeezing scrap into more compact chunks. Useless now that there's no power.", "looks_like": "f_machinery_heavy", "symbol": "&", "color": "green", "move_cost": 0, "max_volume": "2000 L", "flags": [ "TRANSPARENT", "REDUCE_SCENT", "PERMEABLE" ], - "examine_action": "recycle_compactor", "bash": { "str_min": 20, "str_max": 150, diff --git a/data/json/materials.json b/data/json/materials.json index 0a0633afbb134..6ecef26451a54 100644 --- a/data/json/materials.json +++ b/data/json/materials.json @@ -126,8 +126,7 @@ "repaired_with": "material_aluminium_ingot", "dmg_adj": [ "dented", "bent", "smashed", "destroyed" ], "bash_dmg_verb": "dented", - "cut_dmg_verb": "scratched", - "compacts_into": [ "material_aluminium_ingot", "aluminum_foil" ] + "cut_dmg_verb": "scratched" }, { "type": "material", @@ -219,8 +218,7 @@ "dmg_adj": [ "marked", "dented", "smashed", "shattered" ], "bash_dmg_verb": "dented", "cut_dmg_verb": "scratched", - "burn_products": [ [ "scrap_bronze", 1 ] ], - "compacts_into": [ "scrap_bronze" ] + "burn_products": [ [ "scrap_bronze", 1 ] ] }, { "type": "material", @@ -365,8 +363,7 @@ "dmg_adj": [ "marked", "dented", "smashed", "shattered" ], "bash_dmg_verb": "dented", "cut_dmg_verb": "scratched", - "burn_products": [ [ "scrap_copper", 1 ] ], - "compacts_into": [ "scrap_copper", "copper" ] + "burn_products": [ [ "scrap_copper", 1 ] ] }, { "type": "material", @@ -654,8 +651,7 @@ "dmg_adj": [ "marked", "dented", "smashed", "shattered" ], "bash_dmg_verb": "dented", "cut_dmg_verb": "scratched", - "burn_products": [ [ "gold_small", 1 ] ], - "compacts_into": [ "gold_small" ] + "burn_products": [ [ "gold_small", 1 ] ] }, { "type": "material", @@ -988,8 +984,7 @@ "dmg_adj": [ "marked", "dented", "smashed", "shattered" ], "bash_dmg_verb": "dented", "cut_dmg_verb": "scratched", - "burn_products": [ [ "lead", 1 ] ], - "compacts_into": [ "lead" ] + "burn_products": [ [ "lead", 1 ] ] }, { "type": "material", @@ -1325,8 +1320,7 @@ "dmg_adj": [ "marked", "dented", "smashed", "shattered" ], "bash_dmg_verb": "dented", "cut_dmg_verb": "scratched", - "burn_products": [ [ "silver_small", 1 ] ], - "compacts_into": [ "silver_small" ] + "burn_products": [ [ "silver_small", 1 ] ] }, { "type": "material", @@ -1347,8 +1341,7 @@ "dmg_adj": [ "marked", "dented", "smashed", "shattered" ], "bash_dmg_verb": "dented", "cut_dmg_verb": "scratched", - "burn_products": [ [ "platinum_small", 1 ] ], - "compacts_into": [ "platinum_small" ] + "burn_products": [ [ "platinum_small", 1 ] ] }, { "type": "material", @@ -1398,9 +1391,7 @@ "dmg_adj": [ "marked", "dented", "smashed", "shattered" ], "bash_dmg_verb": "dented", "cut_dmg_verb": "scratched", - "burn_products": [ [ "scrap", 1 ] ], - "compact_accepts": [ "budget_steel", "hardsteel", "iron" ], - "compacts_into": [ "sheet_metal", "steel_lump", "steel_chunk", "scrap" ] + "burn_products": [ [ "scrap", 1 ] ] }, { "type": "material", @@ -1489,8 +1480,7 @@ "dmg_adj": [ "marked", "dented", "smashed", "shattered" ], "bash_dmg_verb": "dented", "cut_dmg_verb": "scratched", - "burn_products": [ [ "alloy_sheet", 1 ] ], - "compacts_into": [ "alloy_sheet" ] + "burn_products": [ [ "alloy_sheet", 1 ] ] }, { "type": "material", @@ -1564,8 +1554,7 @@ "dmg_adj": [ "marked", "dented", "smashed", "shattered" ], "bash_dmg_verb": "dented", "cut_dmg_verb": "scratched", - "burn_products": [ [ "tin", 1 ] ], - "compacts_into": [ "tin" ] + "burn_products": [ [ "tin", 1 ] ] }, { "type": "material", @@ -2051,7 +2040,6 @@ "repaired_with": "zinc_metal", "dmg_adj": [ "dented", "bent", "smashed", "shattered" ], "bash_dmg_verb": "dented", - "cut_dmg_verb": "scratched", - "compacts_into": [ "zinc_metal" ] + "cut_dmg_verb": "scratched" } ] diff --git a/data/mods/Dark-Skies-Above/materials.json b/data/mods/Dark-Skies-Above/materials.json index 4c31f44276120..08091c770436a 100644 --- a/data/mods/Dark-Skies-Above/materials.json +++ b/data/mods/Dark-Skies-Above/materials.json @@ -18,8 +18,7 @@ "dmg_adj": [ "marked", "dented", "smashed", "shattered" ], "bash_dmg_verb": "dented", "cut_dmg_verb": "scratched", - "burn_products": [ [ "dks_blend_scrap", 1 ] ], - "compacts_into": [ "dks_blend_scrap" ] + "burn_products": [ [ "dks_blend_scrap", 1 ] ] }, { "type": "material", diff --git a/data/mods/Magiclysm/materials.json b/data/mods/Magiclysm/materials.json index 7515f2890a9cc..9e3e6522fe219 100644 --- a/data/mods/Magiclysm/materials.json +++ b/data/mods/Magiclysm/materials.json @@ -86,8 +86,7 @@ "dmg_adj": [ "marked", "dented", "smashed", "shattered" ], "bash_dmg_verb": "dented", "cut_dmg_verb": "scratched", - "burn_products": [ [ "scrap_bronze", 1 ] ], - "compacts_into": [ "orichalcum_lump", "orichalcum_sliver" ] + "burn_products": [ [ "scrap_bronze", 1 ] ] }, { "type": "material", @@ -107,8 +106,7 @@ "repaired_with": "mithril_ingot", "dmg_adj": [ "marked", "dented", "smashed", "shattered" ], "bash_dmg_verb": "dented", - "cut_dmg_verb": "scratched", - "compacts_into": [ "mithril_lump", "mithril_ingot" ] + "cut_dmg_verb": "scratched" }, { "type": "material", diff --git a/doc/JSON_FLAGS.md b/doc/JSON_FLAGS.md index 204ad72fee97a..b8847cfd14c48 100644 --- a/doc/JSON_FLAGS.md +++ b/doc/JSON_FLAGS.md @@ -609,6 +609,40 @@ List of known flags, used in both `terrain.json` and `furniture.json`. - ```WORKOUT_LEGS``` This furniture is for training your legs. Needed for checks like `is_limb_broken()`. - ```WORKOUT_ARMS``` This furniture is for training your arms. Needed for checks like `is_limb_broken()`. +### Examine Actions + +- ```aggie_plant``` Harvest plants. +- ```autodoc``` Brings the autodoc consoles menu. Needs the ```AUTODOC``` flag to function properly and an adjacent furniture with the ```AUTODOC_COUCH``` flag. +- ```autoclave_empty``` Start the autoclave cycle if it contains filthy CBM, and the player has enough water. +- ```autoclave_full``` Check on the progress of the cycle, and collect sterile CBM once cycle is completed. +- ```bars``` Take advantage of AMORPHOUS and slip through the bars. +- ```bulletin_board``` Use this to arrange tasks for your faction camp. +- ```cardreader``` Use the cardreader with a valid card, or attempt to hack. +- ```chainfence``` Hop over the chain fence. +- ```controls_gate``` Controls the attached gate. +- ```dirtmound``` Plant seeds and plants. +- ```elevator``` Use the elevator to change floors. +- ```fault``` Displays descriptive message, but otherwise unused. +- ```flower_poppy``` Pick the mutated poppy. +- ```fswitch``` Flip the switch and the rocks will shift. +- ```fungus``` Release spores as the terrain crumbles away. +- ```gaspump``` Use the gas-pump. +- ```locked_object``` Locked, but can be pried open. Adding 'PICKABLE' flag allows opening with a lockpick as well. Prying/lockpicking results are hardcoded. +- ```locked_object_pickable``` Locked, but can be opened with a lockpick. Requires 'PICKABLE' flag, lockpicking results are hardcoded. +- ```none``` None +- ```pedestal_temple``` Opens the temple if you have a petrified eye. +- ```pedestal_wyrm``` Spawn wyrms. +- ```pit_covered``` Uncover the pit. +- ```pit``` Cover the pit if you have some planks of wood. +- ```portable_structure``` Take down a tent or similar portable structure. +- ```rubble``` Clear up the rubble if you have a shovel. +- ```safe``` Attempt to crack the safe. +- ```shelter``` Take down the shelter. +- ```shrub_marloss``` Pick a marloss bush. +- ```shrub_wildveggies``` Pick a wild veggies shrub. +- ```slot_machine``` Gamble. +- ```toilet``` Either drink or get water out of the toilet. +- ```water_source``` Drink or get water from a water source. ### Fungal Conversions Only diff --git a/src/iexamine.cpp b/src/iexamine.cpp index 2d97af436c974..c919dcc0973b3 100644 --- a/src/iexamine.cpp +++ b/src/iexamine.cpp @@ -3722,116 +3722,6 @@ void iexamine::shrub_wildveggies( player &p, const tripoint &examp ) p.activity.auto_resume = true; } -void iexamine::recycle_compactor( player &, const tripoint &examp ) -{ - // choose what metal to recycle - auto metals = materials::get_compactable(); - uilist choose_metal; - choose_metal.text = _( "Recycle what metal?" ); - for( auto &m : metals ) { - choose_metal.addentry( m.name() ); - } - choose_metal.query(); - int m_idx = choose_metal.ret; - if( m_idx < 0 || m_idx >= static_cast( metals.size() ) ) { - add_msg( _( "Never mind." ) ); - return; - } - material_type m = metals.at( m_idx ); - - map &here = get_map(); - // check inputs and tally total mass - map_stack inputs = here.i_at( examp ); - units::mass sum_weight = 0_gram; - auto ca = m.compact_accepts(); - std::set accepts( ca.begin(), ca.end() ); - accepts.insert( m.id ); - for( auto &input : inputs ) { - if( !input.only_made_of( accepts ) ) { - //~ %1$s: an item in the compactor , %2$s: desired compactor output material - add_msg( _( "You realize this isn't going to work because %1$s is not made purely of %2$s." ), - input.tname(), m.name() ); - return; - } - if( input.is_container() && !input.is_container_empty() ) { - //~ %1$s: an item in the compactor - add_msg( _( "You realize this isn't going to work because %1$s has not been emptied of its contents." ), - input.tname() ); - return; - } - sum_weight += input.weight(); - } - if( sum_weight <= 0_gram ) { - //~ %1$s: desired compactor output material - add_msg( _( "There is no %1$s in the compactor. Drop some metal items onto it and try again." ), - m.name() ); - return; - } - - // See below for recover_factor (rng(6,9)/10), this - // is the normal value of that recover factor. - static const double norm_recover_factor = 8.0 / 10.0; - const units::mass norm_recover_weight = sum_weight * norm_recover_factor; - - // choose output - uilist choose_output; - //~ %1$.3f: total mass of material in compactor, %2$s: weight units , %3$s: compactor output material - choose_output.text = string_format( _( "Compact %1$.3f %2$s of %3$s into:" ), - convert_weight( sum_weight ), weight_units(), m.name() ); - for( const itype_id &ci : m.compacts_into() ) { - item it = item( ci, calendar::turn_zero, item::solitary_tag{} ); - const int amount = norm_recover_weight / it.weight(); - //~ %1$d: number of, %2$s: output item - choose_output.addentry( string_format( _( "about %1$d %2$s" ), amount, - it.tname( amount ) ) ); - } - choose_output.query(); - int o_idx = choose_output.ret; - if( o_idx < 0 || o_idx >= static_cast( m.compacts_into().size() ) ) { - add_msg( _( "Never mind." ) ); - return; - } - - // remove items - for( auto it = inputs.begin(); it != inputs.end(); ) { - it = inputs.erase( it ); - } - - // produce outputs - double recover_factor = rng( 6, 9 ) / 10.0; - sum_weight = sum_weight * recover_factor; - sounds::sound( examp, 80, sounds::sound_t::combat, _( "Ka-klunk!" ), true, "tool", "compactor" ); - bool out_desired = false; - bool out_any = false; - for( auto it = m.compacts_into().begin() + o_idx; it != m.compacts_into().end(); ++it ) { - const units::mass ow = item( *it, calendar::turn_zero, item::solitary_tag{} ).weight(); - int count = sum_weight / ow; - sum_weight -= count * ow; - if( count > 0 ) { - here.spawn_item( examp, *it, count, 1, calendar::turn ); - if( !out_any ) { - out_any = true; - if( it == m.compacts_into().begin() + o_idx ) { - out_desired = true; - } - } - } - } - - // feedback to user - if( !out_any ) { - add_msg( _( "The compactor chews up all the items in its hopper." ) ); - //~ %1$s: compactor output material - add_msg( _( "The compactor beeps: \"No %1$s to process!\"" ), m.name() ); - return; - } - if( !out_desired ) { - //~ %1$s: compactor output material - add_msg( _( "The compactor beeps: \"Insufficient %1$s!\"" ), m.name() ); - add_msg( _( "It spits out an assortment of smaller pieces instead." ) ); - } -} - void trap::examine( const tripoint &examp ) const { avatar &player_character = get_avatar(); @@ -6320,7 +6210,6 @@ iexamine_function iexamine_function_from_string( const std::string &function_nam { "tree_maple", &iexamine::tree_maple }, { "tree_maple_tapped", &iexamine::tree_maple_tapped }, { "shrub_wildveggies", &iexamine::shrub_wildveggies }, - { "recycle_compactor", &iexamine::recycle_compactor }, { "water_source", &iexamine::water_source }, { "clean_water_source", &iexamine::clean_water_source }, { "reload_furniture", &iexamine::reload_furniture }, diff --git a/src/iexamine.h b/src/iexamine.h index 97c1a437ffe89..bedfadce9e90a 100644 --- a/src/iexamine.h +++ b/src/iexamine.h @@ -98,7 +98,6 @@ void tree_maple_tapped( player &p, const tripoint &examp ); void shrub_marloss( player &p, const tripoint &examp ); void tree_marloss( player &p, const tripoint &examp ); void shrub_wildveggies( player &p, const tripoint &examp ); -void recycle_compactor( player &p, const tripoint &examp ); void water_source( player &p, const tripoint &examp ); void clean_water_source( player &, const tripoint &examp ); void kiln_empty( player &p, const tripoint &examp ); diff --git a/src/material.cpp b/src/material.cpp index 54a6d9f01bf2b..132731241f61b 100644 --- a/src/material.cpp +++ b/src/material.cpp @@ -103,10 +103,6 @@ void material_type::load( const JsonObject &jsobj, const std::string & ) optional( jsobj, was_loaded, "fuel_data", fuel ); jsobj.read( "burn_products", _burn_products, true ); - - optional( jsobj, was_loaded, "compact_accepts", _compact_accepts, - auto_flags_reader() ); - optional( jsobj, was_loaded, "compacts_into", _compacts_into, auto_flags_reader() ); } void material_type::check() const @@ -123,17 +119,6 @@ void material_type::check() const if( !item::type_is_defined( _repaired_with ) ) { debugmsg( "invalid \"repaired_with\" %s for %s.", _repaired_with.c_str(), id.c_str() ); } - for( const material_id &ca : _compact_accepts ) { - if( !ca.is_valid() ) { - debugmsg( "invalid \"compact_accepts\" %s for %s.", ca.c_str(), id.c_str() ); - } - } - for( const itype_id &ci : _compacts_into ) { - if( !item::type_is_defined( ci ) || - !item( ci, calendar::turn_zero ).only_made_of( std::set { id } ) ) { - debugmsg( "invalid \"compacts_into\" %s for %s.", ci.c_str(), id.c_str() ); - } - } } material_id material_type::ident() const @@ -272,16 +257,6 @@ const mat_burn_products &material_type::burn_products() const return _burn_products; } -const material_id_list &material_type::compact_accepts() const -{ - return _compact_accepts; -} - -const mat_compacts_into &material_type::compacts_into() const -{ - return _compacts_into; -} - void materials::load( const JsonObject &jo, const std::string &src ) { material_data.load( jo, src ); @@ -302,17 +277,6 @@ material_list materials::get_all() return material_data.get_all(); } -material_list materials::get_compactable() -{ - material_list all = get_all(); - material_list compactable; - std::copy_if( all.begin(), all.end(), - std::back_inserter( compactable ), []( const material_type & mt ) { - return !mt.compacts_into().empty(); - } ); - return compactable; -} - std::set materials::get_rotting() { static generic_factory::Version version; diff --git a/src/material.h b/src/material.h index 5ecd0914e34c8..13cb439dbea4f 100644 --- a/src/material.h +++ b/src/material.h @@ -23,7 +23,6 @@ enum class damage_type : int; class JsonObject; using mat_burn_products = std::vector>; -using mat_compacts_into = std::vector; using material_list = std::vector; using material_id_list = std::vector; @@ -94,9 +93,6 @@ class material_type //Burn products defined in JSON as "burn_products": [ [ "X", float efficiency ], [ "Y", float efficiency ] ] mat_burn_products _burn_products; - material_id_list _compact_accepts; - mat_compacts_into _compacts_into; - public: material_type(); @@ -143,8 +139,6 @@ class material_type const mat_burn_data &burn_data( size_t intensity ) const; const mat_burn_products &burn_products() const; - const material_id_list &compact_accepts() const; - const mat_compacts_into &compacts_into() const; }; namespace materials @@ -155,7 +149,6 @@ void check(); void reset(); material_list get_all(); -material_list get_compactable(); std::set get_rotting(); } // namespace materials From 66439e397d8fb1f6a4627f0ec0ce2d1e4ebf1fb0 Mon Sep 17 00:00:00 2001 From: ephemeralstoryteller Date: Sun, 21 Mar 2021 02:06:48 -0400 Subject: [PATCH 300/453] [Dark Skies Above] Plague Emissary Fix, Harvest Tweak (#48150) --- data/mods/Dark-Skies-Above/harvest.json | 28 ++++--------------- .../Dark-Skies-Above/items/electronics.json | 6 ++-- 2 files changed, 9 insertions(+), 25 deletions(-) diff --git a/data/mods/Dark-Skies-Above/harvest.json b/data/mods/Dark-Skies-Above/harvest.json index 65b4cdee17af3..75a652a3e5bad 100644 --- a/data/mods/Dark-Skies-Above/harvest.json +++ b/data/mods/Dark-Skies-Above/harvest.json @@ -1,30 +1,14 @@ [ { - "id": "dks_alien_cyborg", - "//": "'alien' but has some metal thrown in to simulate the extensive augments", + "id": "dks_alien_hcyborg", + "//": "a humanoid alien cyborg. metal and scrap simulate augmentation. candidate to receive future bionics", "type": "harvest", "entries": [ - { "drop": "meat_tainted", "type": "flesh", "mass_ratio": 0.25 }, - { "drop": "fat_tainted", "type": "flesh", "mass_ratio": 0.08 }, + { "drop": "mutant_human_flesh", "type": "flesh", "mass_ratio": 0.25 }, + { "drop": "mutant_human_fat", "type": "flesh", "mass_ratio": 0.08 }, { "drop": "bone_tainted", "type": "bone", "mass_ratio": 0.1 }, - { "drop": "cable", "base_num": [ 1, 3 ], "scale_num": [ 0.2, 0.6 ], "max": 8, "type": "flesh" }, - { "drop": "bone_human", "base_num": [ 1, 2 ], "scale_num": [ 0.4, 0.7 ], "max": 10, "type": "bone" }, - { "drop": "scrap", "base_num": [ 1, 5 ], "scale_num": [ 0.3, 0.7 ], "max": 12, "type": "bone" } - ] - }, - { - "//": "e_scrap will be replaced with an alien mind control chip and some aftershock style crafting stuff since I like the tiered crafting idea", - "id": "dks_mhuman_chipped", - "message": "They may have been human, once… whatever the Order has done to them, now they are something else.", - "type": "harvest", - "entries": [ - { "drop": "mutant_human_flesh", "type": "flesh", "mass_ratio": 0.2 }, - { "drop": "hstomach", "scale_num": [ 1, 1 ], "max": 1, "type": "offal" }, - { "drop": "mutant_human_fat", "type": "flesh", "mass_ratio": 0.1 }, - { "drop": "bone_human", "type": "bone", "mass_ratio": 0.12 }, - { "drop": "sinew", "type": "bone", "mass_ratio": 0.001 }, - { "drop": "raw_hleather", "type": "skin", "mass_ratio": 0.01 }, - { "drop": "e_scrap", "type": "bionic", "max": 2 } + { "drop": "dks_elecscrap", "base_num": [ 1, 3 ], "scale_num": [ 0.2, 0.6 ], "max": 8, "type": "flesh" }, + { "drop": "dks_blend_scrap", "base_num": [ 1, 5 ], "scale_num": [ 0.3, 0.7 ], "max": 12, "type": "bone" } ] } ] diff --git a/data/mods/Dark-Skies-Above/items/electronics.json b/data/mods/Dark-Skies-Above/items/electronics.json index d955b72c7eb39..39ea2450b2825 100644 --- a/data/mods/Dark-Skies-Above/items/electronics.json +++ b/data/mods/Dark-Skies-Above/items/electronics.json @@ -15,12 +15,12 @@ }, { "type": "GENERIC", - "id": "broken_dks_emissary_war", + "id": "broken_dks_emissary_plague", "symbol": ",", "color": "green", - "name": { "str": "broken emissary of war", "str_pl": "broken emissaries of war" }, + "name": { "str": "broken emissary of plague", "str_pl": "broken emissaries of plague" }, "category": "other", - "description": "The massive body of a collapsed emissary of war. Still a bit intimidating, perhaps knowing the damage it can cause. Could be gutted for parts, but you'll probably need specialized alien tools.", + "description": "The massive body of a collapsed emissary of plague. Still a bit intimidating, perhaps knowing the damage it can cause. Could be gutted for parts, but you'll probably need specialized alien tools.", "price": 1000, "material": [ "superalloy" ], "volume": "875000 ml", From 96688df73ac0ce7c1cfb3ee4c2d9c6dd6cf20bb1 Mon Sep 17 00:00:00 2001 From: Mark Langsdorf Date: Sun, 21 Mar 2021 01:08:34 -0500 Subject: [PATCH 301/453] mapgen: allow placing active bomb items for better craters in Dark Skies Above (#48137) * mapgen: allow activated items to be placed on the map Add the new item flag "ACTIVATE_ON_PLACE". Items placed during mapgen with this flag will be activated immediately after they are placed on the map. * Dark Skies Above: use active bombs to create large bomb craters Use the new ACTIVATE_ON_PLACE flag with active bombs with 1 second count-downs in a new map special that randomly wrecks buildings across multiple z-levels. The bombs have max_noise = 0 and explode silently to preserve the avatar's hearing. Co-authored-by: actual-nh <74678550+actual-nh@users.noreply.github.com> --- data/json/flags.json | 6 +++ .../mapgen/map_extras/bombed_crater.json | 47 +++++++++++++++++++ .../overrides/region_settings.json | 2 + doc/MAPGEN.md | 4 +- src/flag.cpp | 1 + src/flag.h | 1 + src/map.cpp | 4 ++ 7 files changed, 63 insertions(+), 2 deletions(-) create mode 100644 data/mods/Dark-Skies-Above/mapgen/map_extras/bombed_crater.json diff --git a/data/json/flags.json b/data/json/flags.json index 0fa6e74d4c21a..f1e549ad6edba 100644 --- a/data/json/flags.json +++ b/data/json/flags.json @@ -1838,6 +1838,12 @@ "type": "json_flag", "context": [ "AMMO", "CONSUMABLE" ] }, + { + "id": "ACTIVATE_ON_PLACE", + "type": "json_flag", + "context": [ ], + "info": "This item will be activated when it is placed in mapgen." + }, { "id": "ACT_IN_FIRE", "type": "json_flag", diff --git a/data/mods/Dark-Skies-Above/mapgen/map_extras/bombed_crater.json b/data/mods/Dark-Skies-Above/mapgen/map_extras/bombed_crater.json new file mode 100644 index 0000000000000..cfa896c6537d1 --- /dev/null +++ b/data/mods/Dark-Skies-Above/mapgen/map_extras/bombed_crater.json @@ -0,0 +1,47 @@ +[ + { + "id": "tool_dsa_alien_bomb_act", + "type": "TOOL", + "category": "weapons", + "name": { "str": "active alien bomb" }, + "looks_like": "tool_rdx_charge_act", + "description": "This is an alien bomb. It has been activated and will soon explode, delivering its entire destructive power to everything in sight.", + "weight": "4400 g", + "volume": "10 L", + "price": 0, + "to_hit": -5, + "bashing": 20, + "material": [ "steel" ], + "symbol": "(", + "color": "light_red", + "initial_charges": 1, + "max_charges": 1, + "turns_per_charge": 1, + "explode_in_fire": true, + "explosion": { "power": 40000, "max_noise": 0 }, + "use_action": { + "type": "explosion", + "no_deactivate_msg": "You've already activated the bomb - clear the area immediately!", + "explosion": { "power": 40000, "max_noise": 0 } + }, + "flags": [ "BOMB", "TRADER_AVOID" ] + }, + { + "type": "mapgen", + "method": "json", + "update_mapgen_id": "mx_dsa_bombed_crater", + "object": { + "place_item": [ { "item": "tool_dsa_alien_bomb_act", "x": 12, "y": 12, "amount": 1, "custom-flags": [ "ACTIVATE_ON_PLACE" ] } ] + } + }, + { + "id": "mx_dsa_bombed_crater", + "type": "map_extra", + "name": { "str": "Bomb Crater" }, + "description": "A bomb crater.", + "generator": { "generator_method": "update_mapgen", "generator_id": "mx_dsa_bombed_crater" }, + "sym": ".", + "color": "brown", + "autonote": true + } +] diff --git a/data/mods/Dark-Skies-Above/overrides/region_settings.json b/data/mods/Dark-Skies-Above/overrides/region_settings.json index 35fff324dddea..fddeba421ac44 100644 --- a/data/mods/Dark-Skies-Above/overrides/region_settings.json +++ b/data/mods/Dark-Skies-Above/overrides/region_settings.json @@ -35,6 +35,7 @@ }, "road": { "extras": { + "mx_dsa_bombed_crater": 200, "mx_mayhem": 0, "mx_portal": 0, "mx_portal_in": 0, @@ -57,6 +58,7 @@ "build": { "chance": 2, "extras": { + "mx_dsa_bombed_crater": 200, "mx_house_spider": 0, "mx_house_wasp": 0, "mx_military": 1, diff --git a/doc/MAPGEN.md b/doc/MAPGEN.md index bdaa60394aca9..2e765138c9f9b 100644 --- a/doc/MAPGEN.md +++ b/doc/MAPGEN.md @@ -594,7 +594,8 @@ Example: | repeat | (optional) Value: `[ n1, n2 ]`. Spawn item randomly between `n1` and `n2` times. Only makes sense if the coordinates are random. Example: `[ 1, 3 ]` - repeat 1-3 times. | custom-flags | (optional) Value: `[ "flag1", "flag2" ]`. Spawn item with specific flags. - +The special custom flag "ACTIVATE_ON_PLACE" causes the item to be activated as it is placed. This is useful to have noisemakers that are already turned on as the avatar approaches. It can also be used with explosives with a 1 second countdown to have locations explode as the avatar approaches, creating uniquely ruined terrain. + ## Extra map features with specials **optional** Special map features that do more than just placing furniture / terrain. @@ -1072,4 +1073,3 @@ update_mapgen adds new optional keywords to a few mapgen JSON items. place_npc, place_monster, and place_computer can take an optional target boolean. If they have `"target": true` and are invoked by update_mapgen with a valid mission, then the NPC, monster, or computer will be marked as the target of the mission. - diff --git a/src/flag.cpp b/src/flag.cpp index 641d9c5966be2..5b5b68364f9c0 100644 --- a/src/flag.cpp +++ b/src/flag.cpp @@ -9,6 +9,7 @@ const flag_id flag_NULL = flag_id( "null" ); // intentionally invalid flag const flag_id flag_ACID( "ACID" ); const flag_id flag_ACID_IMMUNE( "ACID_IMMUNE" ); +const flag_id flag_ACTIVATE_ON_PLACE( "ACTIVATE_ON_PLACE" ); const flag_id flag_ACTIVE_CLOAKING( "ACTIVE_CLOAKING" ); const flag_id flag_ACT_IN_FIRE( "ACT_IN_FIRE" ); const flag_id flag_ACT_ON_RANGED_HIT( "ACT_ON_RANGED_HIT" ); diff --git a/src/flag.h b/src/flag.h index 316de675b7686..ce60d0a3f6580 100644 --- a/src/flag.h +++ b/src/flag.h @@ -16,6 +16,7 @@ template class generic_factory; extern const flag_id flag_NULL; extern const flag_id flag_ACID; extern const flag_id flag_ACID_IMMUNE; +extern const flag_id flag_ACTIVATE_ON_PLACE; extern const flag_id flag_ACTIVE_CLOAKING; extern const flag_id flag_ACT_IN_FIRE; extern const flag_id flag_ACT_ON_RANGED_HIT; diff --git a/src/map.cpp b/src/map.cpp index e6ed9c2bb73b3..1102a2a0b890e 100644 --- a/src/map.cpp +++ b/src/map.cpp @@ -4484,6 +4484,10 @@ item &map::add_item( const tripoint &p, item new_item ) new_item.set_var( "reveal_map_center_omt", ms_to_omt_copy( getabs( p ) ) ); } + if( new_item.has_flag( flag_ACTIVATE_ON_PLACE ) ) { + new_item.activate(); + } + current_submap->is_uniform = false; invalidate_max_populated_zlev( p.z ); From 7e47a1597f5a58b1d8e851e8c2eb2462923b7282 Mon Sep 17 00:00:00 2001 From: Jamuro-g <76928284+Jamuro-g@users.noreply.github.com> Date: Sun, 21 Mar 2021 07:12:22 +0100 Subject: [PATCH 302/453] food_containers get colored with their foods colortag (#47426) --- src/advanced_inv.cpp | 9 ++++++++- src/item.cpp | 1 - src/pickup.cpp | 10 +++++++++- 3 files changed, 17 insertions(+), 3 deletions(-) diff --git a/src/advanced_inv.cpp b/src/advanced_inv.cpp index 11875e2343d8f..559ec885ea010 100644 --- a/src/advanced_inv.cpp +++ b/src/advanced_inv.cpp @@ -336,7 +336,14 @@ void advanced_inventory::print_items( const advanced_inventory_pane &pane, bool const item &it = *sitem.items.front(); const bool selected = active && index == static_cast( i ); - nc_color thiscolor = active ? it.color_in_inventory() : norm; + nc_color thiscolor; + if( !active ) { + thiscolor = norm; + } else if( it.is_food_container() && !it.is_craft() && it.contents.num_item_stacks() == 1 ) { + thiscolor = it.contents.all_items_top().front()->color_in_inventory(); + } else { + thiscolor = it.color_in_inventory(); + } nc_color thiscolordark = c_dark_gray; nc_color print_color; diff --git a/src/item.cpp b/src/item.cpp index e81a28752e244..4edfbca3b29c7 100644 --- a/src/item.cpp +++ b/src/item.cpp @@ -4335,7 +4335,6 @@ nc_color item::color_in_inventory() const // Only reviving corpses are yellow ret = c_yellow; } else if( const item *food = get_food() ) { - // Give color priority to allergy (allergy > inedible by freeze or other conditions) // TODO: refactor u.will_eat to let this section handle coloring priority without duplicating code. if( player_character.allergy_type( *food ) != morale_type( "morale_null" ) ) { diff --git a/src/pickup.cpp b/src/pickup.cpp index f283ceb1cc00f..cbcd2695e38e5 100644 --- a/src/pickup.cpp +++ b/src/pickup.cpp @@ -711,7 +711,15 @@ void Pickup::pick_up( const tripoint &p, int min, from_where get_items_from ) if( cur_it < static_cast( matches.size() ) ) { int true_it = matches[cur_it]; const item &this_item = *stacked_here[true_it].front(); - nc_color icolor = this_item.color_in_inventory(); + + nc_color icolor; + if( this_item.is_food_container() && !this_item.is_craft() && + this_item.contents.num_item_stacks() == 1 ) { + icolor = this_item.contents.all_items_top().front()->color_in_inventory(); + } else { + icolor = this_item.color_in_inventory(); + } + if( cur_it == selected ) { icolor = hilite( c_white ); } From 039d8f839942b0ffe1fc8da1a387f8a7e53f3a8f Mon Sep 17 00:00:00 2001 From: Mark Langsdorf Date: Sun, 21 Mar 2021 07:53:44 -0500 Subject: [PATCH 303/453] Dark Skies Above: spellcheck the descriptions (#48164) Run the descriptive JSON through Fedora32's spellcheck and fix a couple of typoes. --- .../blacklists/location_blacklist.json | 2 +- data/mods/Dark-Skies-Above/items/alien-scrap.json | 2 +- data/mods/Dark-Skies-Above/mongun.json | 2 +- data/mods/Dark-Skies-Above/monsters/alien_fauna.json | 6 +++--- .../mods/Dark-Skies-Above/monsters/alien_robots.json | 2 +- data/mods/Dark-Skies-Above/monsters/strays.json | 12 ++++++------ data/mods/Dark-Skies-Above/obsolete.json | 6 +++--- .../Dark-Skies-Above/overrides/items/carnivore.json | 6 +++--- .../mods/Dark-Skies-Above/overrides/items/tools.json | 2 +- data/mods/Dark-Skies-Above/snippets/fliers.json | 4 ++-- data/mods/Dark-Skies-Above/snippets/graffiti.json | 12 ++++++------ data/mods/Dark-Skies-Above/snippets/newspaper.json | 2 +- 12 files changed, 29 insertions(+), 29 deletions(-) diff --git a/data/mods/Dark-Skies-Above/blacklists/location_blacklist.json b/data/mods/Dark-Skies-Above/blacklists/location_blacklist.json index 80201b69af785..34aa84c366bdd 100644 --- a/data/mods/Dark-Skies-Above/blacklists/location_blacklist.json +++ b/data/mods/Dark-Skies-Above/blacklists/location_blacklist.json @@ -1,6 +1,6 @@ [ { - "//": "mostly removes areas with their own storylines, static NPCs, and the like. some will be readded with time", + "//": "mostly removes areas with their own storylines, static NPCs, and the like. some will be returned with time", "type": "overmap_special", "id": "Necropolis", "overmaps": [ ], diff --git a/data/mods/Dark-Skies-Above/items/alien-scrap.json b/data/mods/Dark-Skies-Above/items/alien-scrap.json index 4e71600bb5630..4aa9e7f4502ce 100644 --- a/data/mods/Dark-Skies-Above/items/alien-scrap.json +++ b/data/mods/Dark-Skies-Above/items/alien-scrap.json @@ -78,7 +78,7 @@ "id": "dks_powercell", "category": "spare_parts", "name": { "str": "alien power cell" }, - "description": "A fist-sized, cylindrical canister that makes you feel a bit tingly when you hold it. Its center houses a faintly glowing red core of some sort. Though fundementally incompatable with earthly technologies, it still might be useful in crafting.", + "description": "A fist-sized, cylindrical canister that makes you feel a bit tingly when you hold it. Its center houses a faintly glowing red core of some sort. Though fundamentally incompatible with earthly technologies, it still might be useful in crafting.", "weight": "80 g", "volume": "30 ml", "price": 15000, diff --git a/data/mods/Dark-Skies-Above/mongun.json b/data/mods/Dark-Skies-Above/mongun.json index 7c722b2b0ec77..cbf5f422aed3e 100644 --- a/data/mods/Dark-Skies-Above/mongun.json +++ b/data/mods/Dark-Skies-Above/mongun.json @@ -18,7 +18,7 @@ "color": "red", "name": { "str": "fake firecannon" }, "ranged_damage": { "damage_type": "heat", "amount": 20, "armor_penetration": 30 }, - "description": "Fires an explosive bolt of firey energy. If you're seeing this, it's a bug.", + "description": "Fires an explosive bolt of fiery energy. If you're seeing this, it's a bug.", "skill": "launcher", "range": 15, "flags": [ "NEVER_JAMS" ], diff --git a/data/mods/Dark-Skies-Above/monsters/alien_fauna.json b/data/mods/Dark-Skies-Above/monsters/alien_fauna.json index ead0b24f258bc..080acdb4c813e 100644 --- a/data/mods/Dark-Skies-Above/monsters/alien_fauna.json +++ b/data/mods/Dark-Skies-Above/monsters/alien_fauna.json @@ -42,7 +42,7 @@ "id": "dks_mon_lurker", "type": "MONSTER", "name": { "str": "lurker" }, - "description": "A long, serpentine body, dark and murky just like the waters it inhabits. Tendrils trail behind it, framing innumerable teeth in a gnashing central mouth. It prefers to lurk just below the surface, drifting and still like an unassuming piece of floatsam until something gets too close.", + "description": "A long, serpentine body, dark and murky just like the waters it inhabits. Tendrils trail behind it, framing innumerable teeth in a gnashing central mouth. It prefers to lurk just below the surface, drifting and still, like an unassuming piece of flotsam until something gets too close.", "looks_like": "dks_mon_lurker_sewer", "default_faction": "lurker", "bodytype": "spider", @@ -84,7 +84,7 @@ "id": "dks_mon_mossliz", "type": "MONSTER", "name": "moss lizard", - "description": "A cow-sized reptoid, covered in what appears to be a thick layer of mossy vegetation and rocks. It trudges about the landscape on sturdy legs, foraging whatever flora it can reach with sharp little teeth. It doesn't seem to mind you too much.", + "description": "A cow-sized reptiloid, covered in what appears to be a thick layer of mossy vegetation and rocks. It trudges about the landscape on sturdy legs, foraging whatever flora it can reach with sharp little teeth. It doesn't seem to mind you too much.", "default_faction": "alien_herbivore", "bodytype": "gator", "categories": [ "ALIEN" ], @@ -130,7 +130,7 @@ "id": "dks_mon_packliz", "type": "MONSTER", "name": "pack lizard", - "description": "A slim reptoid about the size of a big dog, with a thick mane of what looks like rather pretty orange-blue 'feathers' around its head. Frond-like protrusions grow from the top of its head down to the base of its tail, glowing faintly when in the presence of other members of its pack.", + "description": "A slim reptiloid about the size of a big dog, with a rather pretty, thick, orange-blue mane of what look like 'feathers' around its head. Frond-like protrusions grow from the top of its head down to the base of its tail, glowing faintly when in the presence of other members of its pack.", "default_faction": "alien_packliz", "bodytype": "gator", "categories": [ "ALIEN" ], diff --git a/data/mods/Dark-Skies-Above/monsters/alien_robots.json b/data/mods/Dark-Skies-Above/monsters/alien_robots.json index 7885a4fdcbef6..7dab18c2aebfc 100644 --- a/data/mods/Dark-Skies-Above/monsters/alien_robots.json +++ b/data/mods/Dark-Skies-Above/monsters/alien_robots.json @@ -3,7 +3,7 @@ "id": "mon_dks_glowdrone", "type": "MONSTER", "name": { "str": "alien surveillance drone" }, - "description": "A small, sleek, white-plated robot bearing a golden insignia. Capable of limited flight, it hovers about the ruins of the former world, onboard cameras and spotlights impartial witness to the chaos around it. Who knows might be watching on the other side…", + "description": "A small, sleek, white-plated robot bearing a golden insignia. Capable of limited flight, it hovers about the ruins of the former world, on-board cameras and spotlights impartial witness to the chaos around it. Who knows what might be watching on the other side…", "default_faction": "invader_alien", "looks_like": "mon_eyebot", "categories": [ "ALIEN" ], diff --git a/data/mods/Dark-Skies-Above/monsters/strays.json b/data/mods/Dark-Skies-Above/monsters/strays.json index a479d61b33fcd..97cf7eb220967 100644 --- a/data/mods/Dark-Skies-Above/monsters/strays.json +++ b/data/mods/Dark-Skies-Above/monsters/strays.json @@ -74,7 +74,7 @@ "id": "dks_mon_stray_soldier", "type": "MONSTER", "name": { "str": "stray soldier" }, - "description": "A former soldier, no doubt deployed to assist with evacuations and drive off the aliens, dressed from head to toe in partially crystalized combat armor. Though their training could not have prepared them for what they were up against, they still seem to remember enough to take you on.", + "description": "A former soldier, no doubt deployed to assist with evacuations and drive off the aliens, dressed from head to toe in partially crystallized combat armor. Though their training could not have prepared them for what they were up against, they still seem to remember enough to take you on.", "looks_like": "mon_zombie_soldier", "default_faction": "stray", "bodytype": "human", @@ -500,7 +500,7 @@ "id": "dks_mon_stray_predator", "type": "MONSTER", "name": { "str": "stray guardian" }, - "description": "Lithe muscle and pulsating crystal fused together into a mass that must be made up of multiple bodies, propelled forward by multiple grossly enlongated crystal limbs sharpened to dangerous points. It strides about the streets, spearing those who dare intrude on its domain like some sort of horrid spider from beyond the stars.", + "description": "Lithe muscle and pulsating crystal fused together into a mass that must be made up of multiple bodies, propelled forward by multiple grossly elongated crystal limbs sharpened to dangerous points. It strides about the streets, spearing those who dare intrude on its domain like some sort of horrid spider from beyond the stars.", "default_faction": "stray", "looks_like": "mon_zombie_predator", "bodytype": "human", @@ -748,7 +748,7 @@ "id": "dks_mon_stray_wretch_burnt", "type": "MONSTER", "name": { "str": "stray creep" }, - "description": "A terrifying, hairy husk of a creature scrambling about on all fours, a mongrel housepet or the like covered in patches of crystal growths that jut from it like spikes.", + "description": "A terrifying, hairy husk of a creature scrambling about on all fours, a mongrel house pet or the like covered in patches of crystal growths that jut from it like spikes.", "default_faction": "stray", "looks_like": "mon_dog_zombie_rot", "bodytype": "dog", @@ -793,7 +793,7 @@ "id": "dks_mon_stray_wretch", "type": "MONSTER", "name": { "str": "stray wretch", "str_pl": "stray wretches" }, - "description": "This blur of jagged, crystal-fused limbs and hair could have been anything from a housepet to a human at some point, but now it leaps and skitters around like something out of a nightmare.", + "description": "This blur of jagged, crystal-fused limbs and hair could have been anything from a house pet to a human at some point, but now it leaps and skitters around like something out of a nightmare.", "default_faction": "stray", "looks_like": "mon_zombie_dog", "bodytype": "dog", @@ -1112,7 +1112,7 @@ "id": "dks_mon_crystal_whip", "type": "MONSTER", "name": { "str": "flailing crystal mass", "str_pl": "flailing crystal masses" }, - "description": "A tall, singular crystal, growing out of a sizable pile of debris that has sprouted a multitude of thin, whiplike tendrils that constantly snake around it like feelers. It frequently grabs nearby objects and drags them into the pile beneath it, as if hoarding.", + "description": "A tall, singular crystal, growing out of a sizable pile of debris that has sprouted a multitude of thin, whip-like tendrils that constantly snake around it like feelers. It frequently grabs nearby objects and drags them into the pile beneath it, as if hoarding.", "default_faction": "stray", "bodytype": "blob", "categories": [ "ALIEN" ], @@ -1236,7 +1236,7 @@ "id": "dks_mon_crystal_mite", "type": "MONSTER", "name": { "str": "crystal seed" }, - "description": "A tiny, multilegged creature that appears to be made of a chunk of crystal. It skitters around on wire-like legs, eating bits of organic leftovers to gain mass in hopes of one day seeding a crystal colony of its own.", + "description": "A tiny, multi-legged creature that appears to be made of a chunk of crystal. It skitters around on wire-like legs, eating bits of organic leftovers. Possibly to gain mass in hopes of one day seeding a crystal colony of its own.", "default_faction": "stray", "bodytype": "spider", "categories": [ "ALIEN" ], diff --git a/data/mods/Dark-Skies-Above/obsolete.json b/data/mods/Dark-Skies-Above/obsolete.json index 775497a48f981..d9fd020b4da5b 100644 --- a/data/mods/Dark-Skies-Above/obsolete.json +++ b/data/mods/Dark-Skies-Above/obsolete.json @@ -5,7 +5,7 @@ "category": "weapons", "looks_like": "zweihander", "name": { "str": "salvaged consecrator's sword" }, - "description": "A well built and decorated sword forged from dense alien metal. Its ability to conjure fireballs does not seem to respond to your will, but the cutting edge is perfectly servicable.", + "description": "A well built and decorated sword forged from dense alien metal. Its ability to conjure fireballs does not seem to respond to your will, but the cutting edge is perfectly serviceable.", "weight": "5400 g", "volume": "3750 ml", "price": 310000, @@ -27,7 +27,7 @@ "color": "light_gray", "looks_like": "arming_sword", "name": { "str": "salvaged knight's sword" }, - "description": "A well built sword made from dense alien metal, in service of the knights of the New Order. The runes that adorn it no longer glow, but its cutting edge is perfectly servicable.", + "description": "A well built sword made from dense alien metal, in service of the knights of the New Order. The runes that adorn it no longer glow, but its cutting edge is perfectly serviceable.", "price": 100000, "material": [ "superalloy" ], "techniques": [ "WBLOCK_2" ], @@ -96,7 +96,7 @@ "type": "ARMOR", "name": "new order battle shield", "category": "armor", - "description": "A well forged shield made of steel, emblazed with what appears to be a highly stylized depiction of a sword piercing a star.", + "description": "A well forged shield made of steel, emblazoned with what appears to be a highly stylized depiction of a sword piercing a star.", "weight": "3300 g", "volume": "5 L", "price": 110000, diff --git a/data/mods/Dark-Skies-Above/overrides/items/carnivore.json b/data/mods/Dark-Skies-Above/overrides/items/carnivore.json index 2ac90c7661050..66773192c0b29 100644 --- a/data/mods/Dark-Skies-Above/overrides/items/carnivore.json +++ b/data/mods/Dark-Skies-Above/overrides/items/carnivore.json @@ -13,7 +13,7 @@ "id": "meat_tainted", "copy-from": "meat_tainted", "name": { "str": "chunk of alien meat", "str_pl": "chunks of alien meat" }, - "description": "This dense, stringy substance smells strongly like burnt oil, or some sort of industrial chemical. For all intents and purposes, it seems like the 'meat' of the creature, but its bizarre texture and faintly red-purple tint is unlike anything you've ever experienced before. You could eat it, but no doubt it would not only taste henious but also make you sick, being made of material your body was never supposed to injest." + "description": "This dense, stringy substance smells strongly like burnt oil, or some sort of industrial chemical. For all intents and purposes, it seems like the 'meat' of the creature, but its bizarre texture and faintly red-purple tint is unlike anything you've ever experienced before. You could eat it, but no doubt it would not only taste heinous but also make you sick, being made of material your body was never supposed to ingest." }, { "type": "COMESTIBLE", @@ -36,7 +36,7 @@ "category": "other", "copy-from": "fat_tainted", "name": "alien fat", - "description": "A chunk of dense fat that is tough and rubbery. It smells simply henious, like open sewer and pungent chemicals, and is doubtless full of strange material that your body was never supposed to injest. It might at least be able to be used for something, if not quite as well as its earthly variant due to its relative impurities." + "description": "A chunk of dense fat that is tough and rubbery. It smells simply heinous, like open sewer and pungent chemicals, and is doubtless full of strange material that your body was never supposed to injest. It might at least be able to be used for something, if not quite as well as its earthly variant due to its relative impurities." }, { "type": "COMESTIBLE", @@ -51,7 +51,7 @@ "copy-from": "mutant_meat", "type": "COMESTIBLE", "name": { "str": "chunk of unusual meat", "str_pl": "chunks of unusual meat" }, - "description": "Meat from the aliens is typically quite foul, full of toxins and substances not meant to be digested by humans, however this piece almost looks edible - if not for a few sections that still have strange hues and disgusting, spongey texture. Still, with a bit of preperation, it might even be somewhat palatable." + "description": "Meat from the aliens is typically quite foul, full of toxins and substances not meant to be digested by humans. However, this piece almost looks edible - if not for a few sections that still have strange hues and disgusting, spongy texture. Still, with a bit of preparation, it might even be somewhat palatable." }, { "id": "mutant_meat_scrap", diff --git a/data/mods/Dark-Skies-Above/overrides/items/tools.json b/data/mods/Dark-Skies-Above/overrides/items/tools.json index b2fb5b286510b..e5e6269968ac9 100644 --- a/data/mods/Dark-Skies-Above/overrides/items/tools.json +++ b/data/mods/Dark-Skies-Above/overrides/items/tools.json @@ -25,7 +25,7 @@ "copy-from": "e_handcuffs", "type": "TOOL", "name": { "str_sp": "electronic handcuffs" }, - "description": "A pair of electronic handcuffs, used by automated New Order units to detain captives. Their continuous siren clearly identifies the wearer as a person of interet and alerts nearby 'safety teams' to their presence. Wait for their arrival, don't try to escape or to remove the cuffs - they will administer an electric shock.\nHowever, since capture is out of the question, you're probably in for a painful time, unless you get creative…" + "description": "A pair of electronic handcuffs, used by automated New Order units to detain captives. Their continuous siren clearly identifies the wearer as a person of internet and alerts nearby 'safety teams' to their presence. Wait for their arrival, don't try to escape or to remove the cuffs - they will administer an electric shock.\nHowever, since capture is out of the question, you're probably in for a painful time, unless you get creative…" }, { "id": "trimmer_off", diff --git a/data/mods/Dark-Skies-Above/snippets/fliers.json b/data/mods/Dark-Skies-Above/snippets/fliers.json index 8cc46f484f30f..60cb7c04c3fe0 100644 --- a/data/mods/Dark-Skies-Above/snippets/fliers.json +++ b/data/mods/Dark-Skies-Above/snippets/fliers.json @@ -39,7 +39,7 @@ }, { "id": "dks_flier_11", - "text": "This is a government-issued, air-dropped alert. \"EVACUTE IMMEDIATELY. Proceed to your closest FEMA operated community shelter to await police and military escort to safety.\"" + "text": "This is a government-issued, air-dropped alert. \"EVACUATE IMMEDIATELY. Proceed to your closest FEMA operated community shelter to await police and military escort to safety.\"" }, { "id": "dks_flier_12", @@ -59,7 +59,7 @@ }, { "id": "dks_flier_16", - "text": "This is a glossy advertisement from FEMA asking that people donate their canned goods in return for tax writeoffs. From the date on the flier, it doesn't look like the initative ever had time to get off the ground." + "text": "This is a glossy advertisement from FEMA asking that people donate their canned goods in return for tax write-offs. From the date on the flier, it doesn't look like the initiative ever had time to get off the ground." }, { "id": "dks_flier_17", diff --git a/data/mods/Dark-Skies-Above/snippets/graffiti.json b/data/mods/Dark-Skies-Above/snippets/graffiti.json index 421707be4f8d3..061c3095ea3f9 100644 --- a/data/mods/Dark-Skies-Above/snippets/graffiti.json +++ b/data/mods/Dark-Skies-Above/snippets/graffiti.json @@ -13,7 +13,7 @@ { "id": "dks_general_graffiti_7", "text": "MOM" }, { "id": "dks_general_graffiti_8", "text": "FUCK YOU" }, { "id": "dks_general_graffiti_9", "text": "This is a cartoon rendition of an alien." }, - { "id": "dks_general_graffiti_10", "text": "This is a crudely spraypainted tag adorned with skulls." }, + { "id": "dks_general_graffiti_10", "text": "This is a crudely spray-painted tag adorned with skulls." }, { "id": "dks_general_graffiti_11", "text": "I have a secure and loving relationship with your mom and you're going to need to come to terms with that.\n\nDo you want to talk about it? You know where to find me. Love you sweety." @@ -23,7 +23,7 @@ { "id": "dks_general_graffiti_14", "text": " fucked ." }, { "id": "dks_general_graffiti_15", - "text": "This is a spraypainted drawing of an angel with wings made of vines." + "text": "This is a spray-painted drawing of an angel with wings made of vines." }, { "id": "dks_general_graffiti_16", "text": "Mr. is a vampire!" }, { "id": "dks_general_graffiti_17", "text": "Their hiding the truth" }, @@ -39,10 +39,10 @@ "id": "dks_general_graffiti_23", "text": "And they walked upon His Earth, and there was a RECKONING, and only the worthy survived" }, - { "id": "dks_general_graffiti_24", "text": "This is a drawing of a zombie with a bullethole in its head." }, + { "id": "dks_general_graffiti_24", "text": "This is a drawing of a zombie with a bullet hole in its head." }, { "id": "dks_general_graffiti_25", "text": "This is a surprisingly artistic drawing of a penis." }, - { "id": "dks_general_graffiti_26", "text": "This is a simple spraypainted graphic of a forest made of bones." }, - { "id": "dks_general_graffiti_27", "text": "This is a drawing of an alien with a bullethole in its head." }, + { "id": "dks_general_graffiti_26", "text": "This is a simple spray-painted graphic of a forest made of bones." }, + { "id": "dks_general_graffiti_27", "text": "This is a drawing of an alien with a bullet hole in its head." }, { "id": "dks_general_graffiti_28", "text": "we can never go back" }, { "id": "dks_general_graffiti_29", "text": "dont by meth from " }, { "id": "dks_general_graffiti_30", "text": " you owe me fifty bucks" }, @@ -50,7 +50,7 @@ { "id": "dks_general_graffiti_32", "text": "eyes to the skies" }, { "id": "dks_general_graffiti_33", - "text": "This is a spraypainting of an anatomically unlikely woman wearing very little." + "text": "This is a spray-painting of an anatomically unlikely woman wearing very little." } ] }, diff --git a/data/mods/Dark-Skies-Above/snippets/newspaper.json b/data/mods/Dark-Skies-Above/snippets/newspaper.json index d99a7ac8c5992..5e3f767c6a6c9 100644 --- a/data/mods/Dark-Skies-Above/snippets/newspaper.json +++ b/data/mods/Dark-Skies-Above/snippets/newspaper.json @@ -142,7 +142,7 @@ }, { "id": "dks_months_old_news_8", - "text": "FOODPLACE PANTS FEUD. An ongoing legal battle between popular fast food megalith Foodplace and the non-profit Concerned Consumers of Foodpeople has ended with the determination that the Foodperson costume will remain a gender-neutral, nonrevealing unitard. \"Superheroes are meant to have exaggerated anatomy and revealing costumes,\" a spokesperson from CCF said in a press release. \"This is a sad day not just for fans of Foodplace, but for consumers of the fast-food superhero genre overall.\"" + "text": "FOODPLACE PANTS FEUD. An ongoing legal battle between popular fast food megalith Foodplace and the non-profit Concerned Consumers of Foodpeople has ended with the determination that the Foodperson costume will remain a gender-neutral, non-revealing unitard. \"Superheroes are meant to have exaggerated anatomy and revealing costumes,\" a spokesperson from CCF said in a press release. \"This is a sad day not just for fans of Foodplace, but for consumers of the fast-food superhero genre overall.\"" }, { "id": "dks_months_old_news_9", From c23eb34d3a7df5f313b70e9428f2969a9bcd690e Mon Sep 17 00:00:00 2001 From: Maleclypse <54345792+Maleclypse@users.noreply.github.com> Date: Thu, 25 Mar 2021 01:51:11 -0500 Subject: [PATCH 304/453] Valentine Card Spawn (#48210) --- data/json/itemgroups/books.json | 6 +++++- 1 file changed, 5 insertions(+), 1 deletion(-) diff --git a/data/json/itemgroups/books.json b/data/json/itemgroups/books.json index 3524ef56ceca3..538cdd0d7e9d5 100644 --- a/data/json/itemgroups/books.json +++ b/data/json/itemgroups/books.json @@ -777,7 +777,11 @@ "id": "newspaper", "type": "item_group", "subtype": "distribution", - "entries": [ { "group": "newspaper_recent", "prob": 80 }, { "group": "newspaper_old", "prob": 20 } ] + "entries": [ + { "group": "newspaper_recent", "prob": 79 }, + { "group": "newspaper_old", "prob": 20 }, + { "item": "valentine_card", "prob": 1 } + ] }, { "id": "newspaper_recent", From d612b6415a4fcbede4590046013ffe84e6ac8315 Mon Sep 17 00:00:00 2001 From: John Candlebury Date: Thu, 25 Mar 2021 00:57:24 -0600 Subject: [PATCH 305/453] Blacklist/Whitelist monsters by species (#48203) * Blacklist/Whitelist monsters by species * Document new blacklist feature --- doc/MODDING.md | 11 ++++++++++- src/mongroup.cpp | 16 ++++++++++++++++ src/mongroup.h | 3 +++ 3 files changed, 29 insertions(+), 1 deletion(-) diff --git a/doc/MODDING.md b/doc/MODDING.md index f84234baf268a..6b6d2fa638421 100644 --- a/doc/MODDING.md +++ b/doc/MODDING.md @@ -135,7 +135,7 @@ Items are where you really want to read the [JSON_INFO.md](JSON_INFO.md) file, j ```` ### Preventing monsters from spawning -This kind of mod is relatively simple, but very useful. If you don't want to deal with certain types of monsters in your world, this is how you do it. There are two ways to go about this, and both will be detailed below. You can blacklist entire monster groups, or you can blacklist certain monsters. In order to do either of those things, you need that monster's ID. These can be found in the relevant data files. For the core game, these are in the `data/json/monsters` directory. +This kind of mod is relatively simple, but very useful. If you don't want to deal with certain types of monsters in your world, this is how you do it. There are two ways to go about this, and both will be detailed below. You can blacklist entire monster groups, blacklist monsters by their specified species, or you can blacklist individual monsters. In order to do any of those things, you need that monster's ID or SPECIES data. These can be found in the relevant data files. For the core game, these are in the `data/json/monsters` directory. The example below is from the `No Ants` mod, and will stop any kind of ant from spawning in-game. ````json [ @@ -158,6 +158,15 @@ The example below is from the `No Ants` mod, and will stop any kind of ant from } ] ```` +The following is an example of how to blacklist monsters by species. In this case, it would remove all fungaloids from the game. +````json +[ + { + "type": "MONSTER_BLACKLIST", + "species": [ "FUNGUS" ] + } +] +```` ### Preventing locations from spawning Preventing certain types of locations from spawning in-game is a little trickier depending on the type of thing you want to target. An overmap building can either be a standard building, or an overmap special. If you want to block things with a specific flag from spawning, you can blacklist those in a very similar manner to monsters. The example below is also from the `No Ants` mod, and stops all anthills from spawning. diff --git a/src/mongroup.cpp b/src/mongroup.cpp index 02c84c8679e93..599a33a4650d6 100644 --- a/src/mongroup.cpp +++ b/src/mongroup.cpp @@ -25,6 +25,9 @@ MonsterGroupManager::t_string_set MonsterGroupManager::monster_blacklist; MonsterGroupManager::t_string_set MonsterGroupManager::monster_whitelist; MonsterGroupManager::t_string_set MonsterGroupManager::monster_categories_blacklist; MonsterGroupManager::t_string_set MonsterGroupManager::monster_categories_whitelist; +MonsterGroupManager::t_string_set MonsterGroupManager::monster_species_blacklist; +MonsterGroupManager::t_string_set MonsterGroupManager::monster_species_whitelist; + static bool monster_whitelist_is_exclusive = false; /** @relates string_id */ @@ -266,6 +269,7 @@ void MonsterGroupManager::LoadMonsterBlacklist( const JsonObject &jo ) { add_array_to_set( monster_blacklist, jo, "monsters" ); add_array_to_set( monster_categories_blacklist, jo, "categories" ); + add_array_to_set( monster_species_blacklist, jo, "species" ); } void MonsterGroupManager::LoadMonsterWhitelist( const JsonObject &jo ) @@ -275,6 +279,8 @@ void MonsterGroupManager::LoadMonsterWhitelist( const JsonObject &jo ) } add_array_to_set( monster_whitelist, jo, "monsters" ); add_array_to_set( monster_categories_whitelist, jo, "categories" ); + add_array_to_set( monster_species_whitelist, jo, "species" ); + } bool MonsterGroupManager::monster_is_blacklisted( const mtype_id &m ) @@ -288,11 +294,21 @@ bool MonsterGroupManager::monster_is_blacklisted( const mtype_id &m ) return false; } } + for( const auto &elem : monster_species_whitelist ) { + if( mt.in_species( species_id( elem ) ) ) { + return false; + } + } for( const auto &elem : monster_categories_blacklist ) { if( mt.categories.count( elem ) > 0 ) { return true; } } + for( const auto &elem : monster_species_blacklist ) { + if( mt.in_species( species_id( elem ) ) ) { + return true; + } + } if( monster_blacklist.count( m.str() ) > 0 ) { return true; } diff --git a/src/mongroup.h b/src/mongroup.h index cd60f6aa344f2..8963df319754f 100644 --- a/src/mongroup.h +++ b/src/mongroup.h @@ -197,6 +197,9 @@ class MonsterGroupManager static t_string_set monster_whitelist; static t_string_set monster_categories_blacklist; static t_string_set monster_categories_whitelist; + static t_string_set monster_species_blacklist; + static t_string_set monster_species_whitelist; + }; #endif // CATA_SRC_MONGROUP_H From 52f66734e898dfbcac5e54f668b68f61b2b4edaf Mon Sep 17 00:00:00 2001 From: OromisElf Date: Thu, 25 Mar 2021 08:02:00 +0100 Subject: [PATCH 306/453] [Magiclysm] bundles (#48118) --- data/mods/Magiclysm/items/alchemy_items.json | 9 ++++++ .../Magiclysm/items/black_dragon_items.json | 20 +++++++++++++ data/mods/Magiclysm/recipes/alchemy.json | 12 ++++++++ data/mods/Magiclysm/recipes/dragon_black.json | 28 +++++++++++++++++++ 4 files changed, 69 insertions(+) diff --git a/data/mods/Magiclysm/items/alchemy_items.json b/data/mods/Magiclysm/items/alchemy_items.json index b9ee2454e18ef..e3c3a17f1e0b9 100644 --- a/data/mods/Magiclysm/items/alchemy_items.json +++ b/data/mods/Magiclysm/items/alchemy_items.json @@ -209,6 +209,15 @@ "flags": [ "TRADER_AVOID" ], "to_hit": -2 }, + { + "id": "bundle_demon_chitin_piece", + "type": "GENERIC", + "copy-from": "demon_chitin_piece", + "symbol": "=", + "name": { "str": "bundle of demon chitin chunks", "str_pl": "bundles of demon chitin chunks" }, + "proportional": { "price": 10, "weight": 10, "volume": 10 }, + "description": "Pieces of demon spider exoskeleton, bundled tightly together for storage. Disassemble to unpack." + }, { "type": "GENERIC", "id": "demon_chitin_plate", diff --git a/data/mods/Magiclysm/items/black_dragon_items.json b/data/mods/Magiclysm/items/black_dragon_items.json index b80da5799de16..64cda2534e678 100644 --- a/data/mods/Magiclysm/items/black_dragon_items.json +++ b/data/mods/Magiclysm/items/black_dragon_items.json @@ -14,6 +14,16 @@ "to_hit": -4, "description": "A scale from a black dragon. It still has its magical properties and acid resistance." }, + { + "id": "bundle_black_scale", + "type": "GENERIC", + "copy-from": "dragon_black_scale", + "symbol": "=", + "name": { "str": "bundle of black dragon scales", "str_pl": "bundles of black dragon scales" }, + "//": "inspiration from bundle of planks", + "proportional": { "price": 10, "weight": 10, "volume": 10 }, + "description": "Scales from a black dragon, bundled tightly together for storage. Disassemble to unpack." + }, { "type": "COMESTIBLE", "id": "black_dragon_hide_raw", @@ -70,6 +80,16 @@ "category": "spare_parts", "to_hit": -1 }, + { + "id": "bundle_black_hide", + "type": "GENERIC", + "copy-from": "black_dragon_tanned_hide", + "symbol": ",", + "name": { "str": "bundle of black dragon hides", "str_pl": "bundles of black dragon hides" }, + "//": "inspiration from bundle of leather", + "proportional": { "price": 10, "weight": 10, "volume": 4 }, + "description": "Hides from a black dragon, bundled tightly together for storage. Disassemble to unpack." + }, { "id": "boots_black_dragon_scale", "type": "ARMOR", diff --git a/data/mods/Magiclysm/recipes/alchemy.json b/data/mods/Magiclysm/recipes/alchemy.json index 17392e98cf3d8..3825e8ab6ab3c 100644 --- a/data/mods/Magiclysm/recipes/alchemy.json +++ b/data/mods/Magiclysm/recipes/alchemy.json @@ -97,5 +97,17 @@ "category": "CC_ENCHANTED", "subcategory": "CSC_ENCHANTED_OTHER", "autolearn": true + }, + { + "result": "bundle_demon_chitin_piece", + "type": "recipe", + "activity_level": "NO_EXERCISE", + "category": "CC_ENCHANTED", + "subcategory": "CSC_ENCHANTED_MATERIALS", + "skill_used": "fabrication", + "time": "1 m", + "autolearn": true, + "reversible": true, + "components": [ [ [ "demon_chitin_piece", 10 ] ], [ [ "rope_any_short", 1, "LIST" ] ] ] } ] diff --git a/data/mods/Magiclysm/recipes/dragon_black.json b/data/mods/Magiclysm/recipes/dragon_black.json index fcb7b60c4f22c..a39e48973c49d 100644 --- a/data/mods/Magiclysm/recipes/dragon_black.json +++ b/data/mods/Magiclysm/recipes/dragon_black.json @@ -23,6 +23,34 @@ "book_learn": [ [ "black_dragons", 2 ] ], "components": [ [ [ "dragon_essence", 1 ] ], [ [ "black_dragon_hide_raw", 1 ] ] ] }, + { + "result": "bundle_black_scale", + "type": "recipe", + "activity_level": "NO_EXERCISE", + "category": "CC_ENCHANTED", + "subcategory": "CSC_ENCHANTED_MATERIALS", + "skill_used": "fabrication", + "time": "1 m", + "autolearn": true, + "//": "volume of black dragon hide is leather x8 so it neeeds x8 filament", + "using": [ [ "filament", 64 ] ], + "qualities": [ { "id": "SEW", "level": 2 } ], + "components": [ [ [ "dragon_black_scale", 10 ] ], [ [ "rag", 3 ] ] ] + }, + { + "result": "bundle_black_hide", + "type": "recipe", + "activity_level": "NO_EXERCISE", + "category": "CC_ENCHANTED", + "subcategory": "CSC_ENCHANTED_MATERIALS", + "skill_used": "fabrication", + "time": "1 m", + "autolearn": true, + "using": [ [ "filament", 8 ] ], + "qualities": [ { "id": "SEW", "level": 1 } ], + "components": [ [ [ "black_dragon_tanned_hide", 10 ] ] ], + "flags": [ "BLIND_HARD" ] + }, { "result": "suit_black_dragon_hide", "type": "recipe", From 206e767136052816c5d04237ccd2c121cdbf5d41 Mon Sep 17 00:00:00 2001 From: Jamuro-g <76928284+Jamuro-g@users.noreply.github.com> Date: Thu, 25 Mar 2021 08:15:20 +0100 Subject: [PATCH 307/453] cap pain gain from hauling heavy furniture (#47586) --- src/game.cpp | 14 ++++++++++++++ 1 file changed, 14 insertions(+) diff --git a/src/game.cpp b/src/game.cpp index 8eae9a73844a4..871f4d27e261e 100644 --- a/src/game.cpp +++ b/src/game.cpp @@ -10492,6 +10492,20 @@ bool game::grabbed_furn_move( const tripoint &dp ) // TODO: What is something? add_msg( _( "The %s collides with something." ), furntype.name() ); return true; + } else if( str_req > u.get_str() && u.get_perceived_pain() > 40 && + !u.has_trait( trait_id( "CENOBITE" ) ) && !u.has_trait( trait_id( "MASOCHIST" ) ) && + !u.has_trait( trait_id( "MASOCHIST_MED" ) ) ) { + add_msg( m_bad, _( "You are in too much pain to try moving the heavy %s!" ), + furntype.name() ); + return false; + + } else if( str_req > u.get_str() && u.get_perceived_pain() > 50 && + ( u.has_trait( trait_id( "MASOCHIST" ) ) || u.has_trait( trait_id( "MASOCHIST_MED" ) ) ) ) { + add_msg( m_bad, + _( "Even with your appetite for pain, you are in too much pain to try moving the heavy %s!" ), + furntype.name() ); + return false; + ///\EFFECT_STR determines ability to drag furniture } else if( str_req > u.get_str() && one_in( std::max( 20 - str_req - u.get_str(), 2 ) ) ) { From 1065fd497b1b6af57d869e4f268aede2b7a5a8c2 Mon Sep 17 00:00:00 2001 From: Jamuro-g <76928284+Jamuro-g@users.noreply.github.com> Date: Thu, 25 Mar 2021 08:15:54 +0100 Subject: [PATCH 308/453] Fix allows siphon action to transfer tank contents inside same vehicle (#47647) --- src/handle_liquid.cpp | 24 +++++++++++++++++------- 1 file changed, 17 insertions(+), 7 deletions(-) diff --git a/src/handle_liquid.cpp b/src/handle_liquid.cpp index 3d83a03e4b697..dac6d78424828 100644 --- a/src/handle_liquid.cpp +++ b/src/handle_liquid.cpp @@ -247,14 +247,24 @@ static bool get_liquid_target( item &liquid, const item *const source, const int } } for( vehicle *veh : opts ) { - if( veh == source_veh ) { - continue; + if( veh == source_veh && veh->has_part( "FLUIDTANK", false ) ) { + for( const vpart_reference &vp : veh->get_avail_parts( "FLUIDTANK" ) ) { + if( vp.part().get_base().is_reloadable_with( liquid.typeId() ) ) { + menu.addentry( -1, true, MENU_AUTOASSIGN, _( "Fill avaliable tank" ) ); + actions.emplace_back( [ &, veh]() { + target.veh = veh; + target.dest_opt = LD_VEH; + } ); + break; + } + } + } else { + menu.addentry( -1, true, MENU_AUTOASSIGN, _( "Fill nearby vehicle %s" ), veh->name ); + actions.emplace_back( [ &, veh]() { + target.veh = veh; + target.dest_opt = LD_VEH; + } ); } - menu.addentry( -1, true, MENU_AUTOASSIGN, _( "Fill nearby vehicle %s" ), veh->name ); - actions.emplace_back( [ &, veh]() { - target.veh = veh; - target.dest_opt = LD_VEH; - } ); } for( const tripoint &target_pos : here.points_in_radius( player_character.pos(), 1 ) ) { From 3ce71e3790d01283415797f5f429e733c3266248 Mon Sep 17 00:00:00 2001 From: Saicchi <47158232+Saicchi@users.noreply.github.com> Date: Thu, 25 Mar 2021 04:16:45 -0300 Subject: [PATCH 309/453] Allow filtering debug messages by type (#47619) --- src/activity_actor.cpp | 8 ++- src/activity_handlers.cpp | 10 +-- src/activity_item_handling.cpp | 2 +- src/anatomy.cpp | 4 +- src/avatar.cpp | 6 +- src/ballistics.cpp | 3 +- src/character.cpp | 29 ++++---- src/consumption.cpp | 10 +-- src/creature.cpp | 31 +++++++-- src/creature.h | 87 +++++++++++++++++++++++ src/debug.cpp | 46 ++++++++++++ src/debug.h | 41 +++++++++++ src/effect.cpp | 8 ++- src/explosion.cpp | 13 ++-- src/game.cpp | 15 ++-- src/handle_action.cpp | 123 +++++++++++++++++++++++++++++++-- src/iexamine.cpp | 3 +- src/iuse_actor.cpp | 2 +- src/map.cpp | 11 +-- src/mattack_actors.cpp | 4 +- src/melee.cpp | 22 +++--- src/messages.cpp | 33 +++++++++ src/messages.h | 66 ++++++++++++++++-- src/monattack.cpp | 23 +++--- src/monster.cpp | 19 ++++- src/monster.h | 5 ++ src/npc.cpp | 29 ++++++-- src/npc.h | 8 +++ src/npcmove.cpp | 78 +++++++++++---------- src/npctalk.cpp | 11 +-- src/npctalk_funcs.cpp | 2 +- src/overmap.cpp | 4 +- src/player.cpp | 12 ++++ src/player.h | 6 ++ src/ranged.cpp | 3 +- src/sdlsound.cpp | 4 +- src/sounds.cpp | 40 ++++++----- src/suffer.cpp | 8 +-- src/talker_avatar.cpp | 2 +- src/talker_npc.cpp | 4 +- src/vehicle.cpp | 54 +++++++++------ src/vehicle_move.cpp | 13 ++-- tests/fake_messages.cpp | 19 +++++ 43 files changed, 719 insertions(+), 202 deletions(-) diff --git a/src/activity_actor.cpp b/src/activity_actor.cpp index cf8322393e80e..9bd47f22f659e 100644 --- a/src/activity_actor.cpp +++ b/src/activity_actor.cpp @@ -1215,7 +1215,9 @@ void lockpick_activity_actor::finish( player_activity &act, Character &who ) // In the meantime, let's roll 3d5-3, giving us a range of 0-12. int lock_roll = rng( 0, 4 ) + rng( 0, 4 ) + rng( 0, 4 ); - add_msg( m_debug, _( "Rolled %i. Mean_roll %g. Difficulty %i." ), pick_roll, mean_roll, lock_roll ); + add_msg_debug( debugmode::DF_ACT_LOCKPICK, _( "Rolled %i. Mean_roll %g. Difficulty %i." ), + pick_roll, + mean_roll, lock_roll ); // Your base skill XP gain is derived from the lock difficulty (which is currently random but shouldn't be). int xp_gain = 3 * lock_roll; @@ -2027,8 +2029,8 @@ void workout_activity_actor::do_turn( player_activity &act, Character &who ) who.add_morale( MORALE_FEELING_GOOD, intensity_modifier, 20, 6_hours, 30_minutes ); } if( calendar::once_every( 2_minutes ) ) { - who.add_msg_if_player( m_debug, who.activity_level_str() ); - who.add_msg_if_player( m_debug, act.id().c_str() ); + who.add_msg_debug_if_player( debugmode::DF_ACT_WORKOUT, who.activity_level_str() ); + who.add_msg_debug_if_player( debugmode::DF_ACT_WORKOUT, act.id().c_str() ); } } else if( !rest_mode ) { rest_mode = true; diff --git a/src/activity_handlers.cpp b/src/activity_handlers.cpp index 76423042b7f4f..507458cc82f55 100644 --- a/src/activity_handlers.cpp +++ b/src/activity_handlers.cpp @@ -418,8 +418,9 @@ static bool check_butcher_cbm( const int roll ) // 90% at roll 0, 72% at roll 1, 60% at roll 2, 51% @ 3, 45% @ 4, 40% @ 5, ... , 25% @ 10 // Roll is roughly a rng(0, -3 + 1st_aid + fine_cut_quality + 1/2 electronics + small_dex_bonus) // Roll is reduced by corpse damage level, but to no less then 0 - add_msg_debug( _( "Roll = %i" ), roll ); - add_msg_debug( _( "Failure chance = %f%%" ), ( 9.0f / ( 10.0f + roll * 2.5f ) ) * 100.0f ); + add_msg_debug( debugmode::DF_ACT_BUTCHER, _( "Roll = %i" ), roll ); + add_msg_debug( debugmode::DF_ACT_BUTCHER, _( "Failure chance = %f%%" ), + ( 9.0f / ( 10.0f + roll * 2.5f ) ) * 100.0f ); const bool failed = x_in_y( 9, ( 10 + roll * 2.5 ) ); return !failed; } @@ -877,7 +878,8 @@ static void butchery_drops_harvest( item *corpse_item, const mtype &mt, player & int roll = roll_butchery() - corpse_item->damage_level(); roll = roll < 0 ? 0 : roll; roll = std::min( entry.max, roll ); - add_msg_debug( _( "Roll penalty for corpse damage = %s" ), 0 - corpse_item->damage_level() ); + add_msg_debug( debugmode::DF_ACT_BUTCHER, _( "Roll penalty for corpse damage = %s" ), + 0 - corpse_item->damage_level() ); if( entry.type == "bionic" ) { butcher_cbm_item( drop_id, p.pos(), calendar::turn, roll, entry.flags, entry.faults ); } else if( entry.type == "bionic_group" ) { @@ -1185,7 +1187,7 @@ void activity_handlers::butcher_finish( player_activity *act, player *p ) skill_level = p->get_skill_level( skill_firstaid ); skill_level += p->max_quality( qual_CUT_FINE ); skill_level += p->get_skill_level( skill_electronics ) / 2; - add_msg_debug( _( "Skill: %s" ), skill_level ); + add_msg_debug( debugmode::DF_ACT_BUTCHER, _( "Skill: %s" ), skill_level ); } const auto roll_butchery = [&]() { diff --git a/src/activity_item_handling.cpp b/src/activity_item_handling.cpp index c138f43973a08..935ae8acbf1c2 100644 --- a/src/activity_item_handling.cpp +++ b/src/activity_item_handling.cpp @@ -1613,7 +1613,7 @@ static std::vector> requirements_map( player } } for( const std::tuple &elem : final_map ) { - add_msg_debug( "%s is fetching %s from x: %d y: %d ", p.disp_name(), + add_msg_debug( debugmode::DF_REQUIREMENTS_MAP, "%s is fetching %s from x: %d y: %d ", p.disp_name(), std::get<1>( elem ).str(), std::get<0>( elem ).x, std::get<0>( elem ).y ); } return final_map; diff --git a/src/anatomy.cpp b/src/anatomy.cpp index 12562640cd971..725f9069024d1 100644 --- a/src/anatomy.cpp +++ b/src/anatomy.cpp @@ -181,7 +181,7 @@ bodypart_id anatomy::select_body_part( int size_diff, int hit_roll ) const // Debug for seeing weights. for( const weighted_object &pr : hit_weights ) { - add_msg_debug( "%s = %.3f", pr.obj.obj().name, pr.weight ); + add_msg_debug( debugmode::DF_ANATOMY_BP, "%s = %.3f", pr.obj.obj().name, pr.weight ); } const bodypart_id *ret = hit_weights.pick(); @@ -190,6 +190,6 @@ bodypart_id anatomy::select_body_part( int size_diff, int hit_roll ) const return bodypart_str_id::NULL_ID().id(); } - add_msg_debug( "selected part: %s", ret->id().obj().name ); + add_msg_debug( debugmode::DF_ANATOMY_BP, "selected part: %s", ret->id().obj().name ); return *ret; } diff --git a/src/avatar.cpp b/src/avatar.cpp index b28b60e68c89c..a71170d7a4be0 100644 --- a/src/avatar.cpp +++ b/src/avatar.cpp @@ -420,7 +420,7 @@ bool avatar::read( item &it, const bool continuous ) const int time_taken = time_to_read( it, *reader ); - add_msg_debug( "avatar::read: time_taken = %d", time_taken ); + add_msg_debug( debugmode::DF_AVATAR, "avatar::read: time_taken = %d", time_taken ); player_activity act( ACT_READ, time_taken, continuous ? activity.index : 0, reader->getID().get_value() ); act.targets.emplace_back( item_location( *this, &it ) ); @@ -872,7 +872,7 @@ void avatar::do_read( item &book ) skill_id skill_used = style_to_learn->primary_skill; int difficulty = std::max( 1, style_to_learn->learn_difficulty ); difficulty = std::max( 1, 20 + difficulty * 2 - get_skill_level( skill_used ) * 2 ); - add_msg_debug( _( "Chance to learn one in: %d" ), difficulty ); + add_msg_debug( debugmode::DF_AVATAR, _( "Chance to learn one in: %d" ), difficulty ); if( one_in( difficulty ) ) { m->second.call( *this, book, false, pos() ); @@ -1600,7 +1600,7 @@ bool avatar::wield( item &target, const int obtain_cost ) target.on_takeoff( *this ); } - add_msg_debug( "wielding took %d moves", mv ); + add_msg_debug( debugmode::DF_AVATAR, "wielding took %d moves", mv ); moves -= mv; if( has_item( target ) ) { diff --git a/src/ballistics.cpp b/src/ballistics.cpp index d8f820baf29bc..cc67f832ed393 100644 --- a/src/ballistics.cpp +++ b/src/ballistics.cpp @@ -282,7 +282,8 @@ dealt_projectile_attack projectile_attack( const projectile &proj_arg, const tri trajectory = here.find_clear_path( source, target ); } - add_msg_debug( "missed_by_tiles: %.2f; missed_by: %.2f; target (orig/hit): %d,%d,%d/%d,%d,%d", + add_msg_debug( debugmode::DF_BALLISTIC, + "missed_by_tiles: %.2f; missed_by: %.2f; target (orig/hit): %d,%d,%d/%d,%d,%d", aim.missed_by_tiles, aim.missed_by, target_arg.x, target_arg.y, target_arg.z, target.x, target.y, target.z ); diff --git a/src/character.cpp b/src/character.cpp index 61fb5d5439427..c608f9aae1406 100644 --- a/src/character.cpp +++ b/src/character.cpp @@ -1092,9 +1092,9 @@ bool Character::check_outbounds_activity( const player_activity &act, bool check } activity = player_activity(); } - add_msg_debug( - "npc %s at pos %d %d, activity target is not inbounds at %d %d therefore activity was stashed", - disp_name(), pos().x, pos().y, act.placement.x, act.placement.y ); + add_msg_debug( debugmode::DF_CHARACTER, + "npc %s at pos %d %d, activity target is not inbounds at %d %d therefore activity was stashed", + disp_name(), pos().x, pos().y, act.placement.x, act.placement.y ); return true; } return false; @@ -1120,7 +1120,7 @@ void Character::mount_creature( monster &z ) tripoint pnt = z.pos(); shared_ptr_fast mons = g->shared_from( z ); if( mons == nullptr ) { - add_msg_debug( "mount_creature(): monster not found in critter_tracker" ); + add_msg_debug( debugmode::DF_CHARACTER, "mount_creature(): monster not found in critter_tracker" ); return; } add_effect( effect_riding, 1_turns, true ); @@ -1311,7 +1311,8 @@ void Character::forced_dismount() } add_effect( effect_downed, 5_turns, true ); } else { - add_msg_debug( "Forced_dismount could not find a square to deposit player" ); + add_msg_debug( debugmode::DF_CHARACTER, + "Forced_dismount could not find a square to deposit player" ); } if( is_avatar() ) { avatar &player_character = get_avatar(); @@ -1335,7 +1336,7 @@ void Character::forced_dismount() void Character::dismount() { if( !is_mounted() ) { - add_msg_debug( "dismount called when not riding" ); + add_msg_debug( debugmode::DF_CHARACTER, "dismount called when not riding" ); return; } if( const cata::optional pnt = choose_adjacent( _( "Dismount where?" ) ) ) { @@ -5496,7 +5497,8 @@ void Character::update_health( int external_modifiers ) // Slowly near 0, but it's hard to overpower it near +/-100 set_healthy_mod( std::round( get_healthy_mod() * 0.95f ) ); - add_msg_debug( "Health: %d, Health mod: %d", get_healthy(), get_healthy_mod() ); + add_msg_debug( debugmode::DF_CHAR_HEALTH, "Health: %d, Health mod: %d", get_healthy(), + get_healthy_mod() ); } // Returns the number of multiples of tick_length we would "pass" on our way `from` to `to` @@ -5990,7 +5992,7 @@ needs_rates Character::calc_needs_rates() const rates.kcal = get_bmr(); - add_msg_if_player( m_debug, "Metabolic rate: %.2f", rates.hunger ); + add_msg_debug_if_player( debugmode::DF_CHAR_CALORIES, "Metabolic rate: %.2f", rates.hunger ); static const std::string player_thirst_rate( "PLAYER_THIRST_RATE" ); rates.thirst = get_option< float >( player_thirst_rate ); @@ -6347,7 +6349,7 @@ void Character::get_sick() float health_factor = std::pow( 2.0f, get_healthy() / 50.0f ); int disease_rarity = static_cast( checks_per_year * health_factor / base_diseases_per_year ); - add_msg_debug( "disease_rarity = %d", disease_rarity ); + add_msg_debug( debugmode::DF_CHAR_HEALTH, "disease_rarity = %d", disease_rarity ); if( one_in( disease_rarity ) ) { if( one_in( 6 ) ) { // The flu typically lasts 3-10 days. @@ -8093,7 +8095,7 @@ float Character::healing_rate( float at_rest_quality ) const // Most common case: awake player with no regenerative abilities // ~7e-5 is 1 hp per day, anything less than that is totally negligible static constexpr float eps = 0.000007f; - add_msg_debug( "%s healing: %.6f", name, final_rate ); + add_msg_debug( debugmode::DF_CHAR_HEALTH, "%s healing: %.6f", name, final_rate ); if( std::abs( final_rate ) < eps ) { return 0.0f; } @@ -8609,7 +8611,7 @@ void Character::burn_move_stamina( int moves ) burn_ratio += overburden_percentage; burn_ratio *= move_mode->stamina_mult(); mod_stamina( -( ( moves * burn_ratio ) / 100.0 ) * stamina_move_cost_modifier() ); - add_msg_debug( "Stamina burn: %d", -( ( moves * burn_ratio ) / 100 ) ); + add_msg_debug( debugmode::DF_CHARACTER, "Stamina burn: %d", -( ( moves * burn_ratio ) / 100 ) ); // Chance to suffer pain if overburden and stamina runs out or has trait BADBACK // Starts at 1 in 25, goes down by 5 for every 50% more carried if( ( current_weight > max_weight ) && ( has_trait( trait_BADBACK ) || get_stamina() == 0 ) && @@ -8678,7 +8680,8 @@ void Character::update_stamina( int turns ) } mod_stamina( roll_remainder( stamina_recovery * turns ) ); - add_msg_debug( "Stamina recovery: %d", roll_remainder( stamina_recovery * turns ) ); + add_msg_debug( debugmode::DF_CHARACTER, "Stamina recovery: %d", + roll_remainder( stamina_recovery * turns ) ); // Cap at max set_stamina( std::min( std::max( get_stamina(), 0 ), max_stam ) ); } @@ -10762,7 +10765,7 @@ void Character::check_and_recover_morale() if( !morale->consistent_with( test_morale ) ) { *morale = player_morale( test_morale ); // Recover consistency - add_msg_debug( "%s morale was recovered.", disp_name( true ) ); + add_msg_debug( debugmode::DF_CHARACTER, "%s morale was recovered.", disp_name( true ) ); } } diff --git a/src/consumption.cpp b/src/consumption.cpp index e88fbe8b2a16a..673e606a3446e 100644 --- a/src/consumption.cpp +++ b/src/consumption.cpp @@ -1337,7 +1337,7 @@ bool Character::consume_effects( item &food ) // But always round down int h_loss = -rottedness * comest.get_default_nutr(); mod_healthy_mod( h_loss, -200 ); - add_msg_debug( "%d health from %0.2f%% rotten food", h_loss, rottedness ); + add_msg_debug( debugmode::DF_FOOD, "%d health from %0.2f%% rotten food", h_loss, rottedness ); } // Used in hibernation messages. @@ -1423,10 +1423,10 @@ bool Character::consume_effects( item &food ) food_vol * ratio, food_nutrients }; - add_msg_debug( - "Effective volume: %d (solid) %d (liquid)\n multiplier: %g calories: %d, weight: %d", - units::to_milliliter( ingested.solids ), units::to_milliliter( ingested.water ), ratio, - food_nutrients.kcal(), units::to_gram( food_weight ) ); + add_msg_debug( debugmode::DF_FOOD, + "Effective volume: %d (solid) %d (liquid)\n multiplier: %g calories: %d, weight: %d", + units::to_milliliter( ingested.solids ), units::to_milliliter( ingested.water ), ratio, + food_nutrients.kcal(), units::to_gram( food_weight ) ); // Maybe move tapeworm to digestion if( has_effect( effect_tapeworm ) ) { ingested.nutr /= 2; diff --git a/src/creature.cpp b/src/creature.cpp index dad36fef8b48c..60d39652bfe13 100644 --- a/src/creature.cpp +++ b/src/creature.cpp @@ -685,7 +685,8 @@ void projectile::apply_effects_damage( Creature &target, Creature *source, target.add_effect( effect_source( source ), effect_tied, 1_turns, true ); target.as_monster()->tied_item = cata::make_value( drop_item ); } else { - add_msg_debug( "projectile with TANGLE effect, but no drop item specified" ); + add_msg_debug( debugmode::DF_CREATURE, + "projectile with TANGLE effect, but no drop item specified" ); } } else if( ( target.is_npc() || target.is_avatar() ) && !target.is_immune_effect( effect_downed ) ) { @@ -1174,7 +1175,7 @@ void Creature::add_effect( const effect_source &source, const efftype_id &eff_id // Bound intensity by [1, max intensity] if( e.get_intensity() < 1 ) { - add_msg_debug( "Bad intensity, ID: %s", e.get_id().c_str() ); + add_msg_debug( debugmode::DF_CREATURE, "Bad intensity, ID: %s", e.get_id().c_str() ); e.set_intensity( 1 ); } else if( e.get_intensity() > e.get_max_intensity() ) { e.set_intensity( e.get_max_intensity() ); @@ -1214,7 +1215,7 @@ void Creature::add_effect( const effect_source &source, const efftype_id &eff_id } // Bound new effect intensity by [1, max intensity] if( e.get_intensity() < 1 ) { - add_msg_debug( "Bad intensity, ID: %s", e.get_id().c_str() ); + add_msg_debug( debugmode::DF_CREATURE, "Bad intensity, ID: %s", e.get_id().c_str() ); e.set_intensity( 1 ); } else if( e.get_intensity() > e.get_max_intensity() ) { e.set_intensity( e.get_max_intensity() ); @@ -2379,10 +2380,10 @@ bodypart_id Creature::select_body_part( Creature *source, int hit_roll ) const { int szdif = source->get_size() - get_size(); - add_msg_debug( "hit roll = %d", hit_roll ); - add_msg_debug( "source size = %d", source->get_size() ); - add_msg_debug( "target size = %d", get_size() ); - add_msg_debug( "difference = %d", szdif ); + add_msg_debug( debugmode::DF_CREATURE, "hit roll = %d", hit_roll ); + add_msg_debug( debugmode::DF_CREATURE, "source size = %d", source->get_size() ); + add_msg_debug( debugmode::DF_CREATURE, "target size = %d", get_size() ); + add_msg_debug( debugmode::DF_CREATURE, "difference = %d", szdif ); return anatomy_human_anatomy->select_body_part( szdif, hit_roll ); } @@ -2501,6 +2502,11 @@ void Creature::add_msg_if_player( const game_message_params ¶ms, const trans return add_msg_if_player( params, msg.translated() ); } +void Creature::add_msg_debug_if_player( debugmode::debug_filter type, const translation &msg ) const +{ + return add_msg_debug_if_player( type, msg.translated() ); +} + void Creature::add_msg_if_npc( const translation &msg ) const { return add_msg_if_npc( msg.translated() ); @@ -2511,6 +2517,11 @@ void Creature::add_msg_if_npc( const game_message_params ¶ms, const translat return add_msg_if_npc( params, msg.translated() ); } +void Creature::add_msg_debug_if_npc( debugmode::debug_filter type, const translation &msg ) const +{ + return add_msg_debug_if_npc( type, msg.translated() ); +} + void Creature::add_msg_player_or_npc( const translation &pc, const translation &npc ) const { return add_msg_player_or_npc( pc.translated(), npc.translated() ); @@ -2522,6 +2533,12 @@ void Creature::add_msg_player_or_npc( const game_message_params ¶ms, const t return add_msg_player_or_npc( params, pc.translated(), npc.translated() ); } +void Creature::add_msg_debug_player_or_npc( debugmode::debug_filter type, const translation &pc, + const translation &npc ) const +{ + return add_msg_debug_player_or_npc( type, pc.translated(), npc.translated() ); +} + void Creature::add_msg_player_or_say( const translation &pc, const translation &npc ) const { return add_msg_player_or_say( pc.translated(), npc.translated() ); diff --git a/src/creature.h b/src/creature.h index 011f9cca36a26..799826d71e785 100644 --- a/src/creature.h +++ b/src/creature.h @@ -971,6 +971,93 @@ class Creature : public location, public viewer string_format( npc_msg, std::forward( args )... ) ); } + virtual void add_msg_debug_if_player( debugmode::debug_filter /*type*/, + const std::string &/*msg*/ ) const {} + void add_msg_debug_if_player( debugmode::debug_filter /*type*/, const translation &/*msg*/ ) const; + template + void add_msg_debug_if_player( debugmode::debug_filter type, const char *const msg, + Args &&... args ) const { + // expanding for string formatting can be expensive + if( debug_mode ) { + return add_msg_debug_if_player( type, string_format( msg, std::forward( args )... ) ); + } + } + template + void add_msg_debug_if_player( debugmode::debug_filter type, const std::string &msg, + Args &&... args ) const { + if( debug_mode ) { + return add_msg_debug_if_player( type, string_format( msg, std::forward( args )... ) ); + } + } + template + void add_msg_debug_if_player( debugmode::debug_filter type, const translation &msg, + Args &&... args ) const { + if( debug_mode ) { + return add_msg_debug_if_player( type, string_format( msg, std::forward( args )... ) ); + } + } + + virtual void add_msg_debug_if_npc( debugmode::debug_filter /*type*/, + const std::string &/*msg*/ ) const {} + void add_msg_debug_if_npc( debugmode::debug_filter /*type*/, const translation &/*msg*/ ) const; + template + void add_msg_debug_if_npc( debugmode::debug_filter type, const char *const msg, + Args &&... args ) const { + // expanding for string formatting can be expensive + if( debug_mode ) { + return add_msg_debug_if_npc( type, string_format( msg, std::forward( args )... ) ); + } + } + template + void add_msg_debug_if_npc( debugmode::debug_filter type, const std::string &msg, + Args &&... args ) const { + if( debug_mode ) { + return add_msg_debug_if_npc( type, string_format( msg, std::forward( args )... ) ); + } + } + template + void add_msg_debug_if_npc( debugmode::debug_filter type, const translation &msg, + Args &&... args ) const { + if( debug_mode ) { + return add_msg_debug_if_npc( type, string_format( msg, std::forward( args )... ) ); + } + } + + virtual void add_msg_debug_player_or_npc( debugmode::debug_filter /*type*/, + const std::string &/*player_msg*/, + const std::string &/*npc_msg*/ ) const {} + void add_msg_debug_player_or_npc( debugmode::debug_filter /*type*/, + const translation &/*player_msg*/, + const translation &/*npc_msg*/ ) const; + template + void add_msg_debug_player_or_npc( debugmode::debug_filter type, const char *const player_msg, + const char *const npc_msg, Args &&... args ) const { + // expanding for string formatting can be expensive + if( debug_mode ) { + return add_msg_debug_player_or_npc( type, string_format( player_msg, + std::forward( args )... ), + string_format( npc_msg, std::forward( args )... ) ); + } + } + template + void add_msg_debug_player_or_npc( debugmode::debug_filter type, const std::string &player_msg, + const std::string &npc_msg, Args &&... args ) const { + if( debug_mode ) { + return add_msg_debug_player_or_npc( type, string_format( player_msg, + std::forward( args )... ), + string_format( npc_msg, std::forward( args )... ) ); + } + } + template + void add_msg_debug_player_or_npc( debugmode::debug_filter type, const translation &player_msg, + const translation &npc_msg, Args &&... args ) const { + if( debug_mode ) { + return add_msg_debug_player_or_npc( type, string_format( player_msg, + std::forward( args )... ), + string_format( npc_msg, std::forward( args )... ) ); + } + } + virtual void add_msg_player_or_say( const std::string &/*player_msg*/, const std::string &/*npc_speech*/ ) const {} virtual void add_msg_player_or_say( const game_message_params &/*params*/, diff --git a/src/debug.cpp b/src/debug.cpp index cf666f74bc23c..4243f727b281e 100644 --- a/src/debug.cpp +++ b/src/debug.cpp @@ -154,6 +154,52 @@ bool debug_has_error_been_observed() bool debug_mode = false; +namespace debugmode +{ +std::list enabled_filters; +std::string filter_name( debug_filter value ) +{ + // see debug.h for commentary + switch( value ) { + // *INDENT-OFF* + case DF_ACT_BUTCHER: return "DF_ACT_BUTCHER"; + case DF_ACT_LOCKPICK: return "DF_ACT_LOCKPICK"; + case DF_ACT_WORKOUT: return "DF_ACT_WORKOUT"; + case DF_ANATOMY_BP: return "DF_ANATOMY_BP"; + case DF_AVATAR: return "DF_AVATAR"; + case DF_BALLISTIC: return "DF_BALLISTIC"; + case DF_CHARACTER: return "DF_CHARACTER"; + case DF_CHAR_CALORIES: return "DF_CHAR_CALORIES"; + case DF_CHAR_HEALTH: return "DF_CHAR_HEALTH"; + case DF_CREATURE: return "DF_CREATURE"; + case DF_EFFECT: return "DF_EFFECT"; + case DF_EXPLOSION: return "DF_EXPLOSION"; + case DF_FOOD: return "DF_FOOD"; + case DF_GAME: return "DF_GAME"; + case DF_IEXAMINE: return "DF_IEXAMINE"; + case DF_IUSE: return "DF_IUSE"; + case DF_MAP: return "DF_MAP"; + case DF_MATTACK: return "DF_MATTACK"; + case DF_MELEE: return "DF_MELEE"; + case DF_MONSTER: return "DF_MONSTER"; + case DF_NPC: return "DF_NPC"; + case DF_OVERMAP: return "DF_OVERMAP"; + case DF_RANGED: return "DF_RANGED"; + case DF_REQUIREMENTS_MAP: return "DF_REQUIREMENTS_MAP"; + case DF_SOUND: return "DF_SOUND"; + case DF_TALKER: return "DF_TALKER"; + case DF_VEHICLE: return "DF_VEHICLE"; + case DF_VEHICLE_DRAG: return "DF_VEHICLE_DRAG"; + case DF_VEHICLE_MOVE: return "DF_VEHICLE_MOVE"; + // *INDENT-ON* + case DF_LAST: + default: + debugmsg( "Invalid DF_FILTER : %d", value ); + return "DF_INVALID"; + } +} +} // namespace debugmode + struct buffered_prompt_info { std::string filename; std::string line; diff --git a/src/debug.h b/src/debug.h index 91f5634cde5ae..b5cc4bfb5cca6 100644 --- a/src/debug.h +++ b/src/debug.h @@ -3,6 +3,7 @@ #define CATA_SRC_DEBUG_H #include "string_formatter.h" +#include /** * debugmsg(msg, ...) @@ -221,6 +222,46 @@ std::ostream &DebugLog( DebugLevel, DebugClass ); */ extern bool debug_mode; +namespace debugmode +{ +// Please try to keep this alphabetically sorted +enum debug_filter : int { + DF_ACT_BUTCHER = 0, // butcher activity handler + DF_ACT_LOCKPICK, // lockpicking activity actor + DF_ACT_WORKOUT, // workout activity actor + DF_ANATOMY_BP, // anatomy::select_body_part() + DF_AVATAR, // avatar generic + DF_BALLISTIC, // ballistic generic + DF_CHARACTER, // character generic + DF_CHAR_CALORIES, // character stomach and calories + DF_CHAR_HEALTH, // character health related + DF_CREATURE, // creature generic + DF_EFFECT, // effects generic + DF_EXPLOSION, // explosion generic + DF_FOOD, // food generic + DF_GAME, // game generic + DF_IEXAMINE, // iexamine generic + DF_IUSE, // iuse generic + DF_MAP, // map generic + DF_MATTACK, // monster attack generic + DF_MELEE, // melee generic + DF_MONSTER, // monster generic + DF_NPC, // npc generic + DF_OVERMAP, // overmap generic + DF_RANGED, // ranged generic + DF_REQUIREMENTS_MAP, // activity_item_handler requirements_map() + DF_SOUND, // sound generic + DF_TALKER, // talker generic + DF_VEHICLE, // vehicle generic + DF_VEHICLE_DRAG, // vehicle coeff_air_drag() + DF_VEHICLE_MOVE, // vehicle move generic + DF_LAST // This is always the last entry +}; + +extern std::list enabled_filters; +std::string filter_name( debug_filter value ); +} // namespace debugmode + #if defined(BACKTRACE) /** * Write a stack backtrace to the given ostream diff --git a/src/effect.cpp b/src/effect.cpp index 5b9fd444061ec..fad0aae5fc147 100644 --- a/src/effect.cpp +++ b/src/effect.cpp @@ -794,7 +794,8 @@ void effect::set_duration( const time_duration &dur, bool alert ) set_intensity( duration / eff_type->int_dur_factor + 1, alert ); } - add_msg_debug( "ID: %s, Duration %s", get_id().c_str(), to_string( duration ) ); + add_msg_debug( debugmode::DF_EFFECT, "ID: %s, Duration %s", get_id().c_str(), + to_string( duration ) ); } void effect::mod_duration( const time_duration &dur, bool alert ) { @@ -857,7 +858,7 @@ int effect::set_intensity( int val, bool alert ) { if( intensity < 1 ) { // Fix bad intensity - add_msg_debug( "Bad intensity, ID: %s", get_id().c_str() ); + add_msg_debug( debugmode::DF_EFFECT, "Bad intensity, ID: %s", get_id().c_str() ); intensity = 1; } @@ -875,7 +876,8 @@ int effect::set_intensity( int val, bool alert ) int old_intensity = intensity; intensity = val; if( old_intensity != intensity ) { - add_msg_debug( "%s intensity %d->%d", get_id().c_str(), old_intensity, intensity ); + add_msg_debug( debugmode::DF_EFFECT, "%s intensity %d->%d", get_id().c_str(), old_intensity, + intensity ); } return intensity; diff --git a/src/explosion.cpp b/src/explosion.cpp index 738442fd9487d..1dd5b68ac9428 100644 --- a/src/explosion.cpp +++ b/src/explosion.cpp @@ -311,7 +311,8 @@ static void do_blast( const tripoint &p, const float power, continue; } - add_msg_debug( "Blast hits %s with force %.1f", critter->disp_name(), force ); + add_msg_debug( debugmode::DF_EXPLOSION, "Blast hits %s with force %.1f", critter->disp_name(), + force ); Character *pl = critter->as_character(); if( pl == nullptr ) { @@ -320,7 +321,8 @@ static void do_blast( const tripoint &p, const float power, const int actual_dmg = rng_float( dmg * 2, dmg * 3 ); critter->apply_damage( nullptr, bodypart_id( "torso" ), actual_dmg ); critter->check_dead_state(); - add_msg_debug( "Blast hits %s for %d damage", critter->disp_name(), actual_dmg ); + add_msg_debug( debugmode::DF_EXPLOSION, "Blast hits %s for %d damage", critter->disp_name(), + actual_dmg ); continue; } @@ -354,7 +356,8 @@ static void do_blast( const tripoint &p, const float power, const dealt_damage_instance result = pl->deal_damage( nullptr, blp.bp, dmg_instance ); const int res_dmg = result.total_damage(); - add_msg_debug( "%s for %d raw, %d actual", hit_part_name, part_dam, res_dmg ); + add_msg_debug( debugmode::DF_EXPLOSION, "%s for %d raw, %d actual", hit_part_name, part_dam, + res_dmg ); if( res_dmg > 0 ) { pl->add_msg_if_player( m_bad, _( "Your %s is hit for %d damage!" ), hit_part_name, res_dmg ); } @@ -435,10 +438,10 @@ static std::vector shrapnel( const tripoint &src, int power, } else { non_damaging_hits++; } - add_msg_debug( "Shrapnel hit %s at %d m/s at a distance of %d", + add_msg_debug( debugmode::DF_EXPLOSION, "Shrapnel hit %s at %d m/s at a distance of %d", critter->disp_name(), frag.proj.speed, rl_dist( src, target ) ); - add_msg_debug( "Shrapnel dealt %d damage", frag.dealt_dam.total_damage() ); + add_msg_debug( debugmode::DF_EXPLOSION, "Shrapnel dealt %d damage", frag.dealt_dam.total_damage() ); if( critter->is_dead_state() ) { break; } diff --git a/src/game.cpp b/src/game.cpp index 871f4d27e261e..fec01e90318dd 100644 --- a/src/game.cpp +++ b/src/game.cpp @@ -827,7 +827,7 @@ bool game::start_game() mon->friendly = -1; mon->add_effect( effect_pet, 1_turns, true ); } else { - add_msg_debug( "cannot place starting pet, no space!" ); + add_msg_debug( debugmode::DF_GAME, "cannot place starting pet, no space!" ); } } if( u.starting_vehicle && @@ -934,7 +934,7 @@ void game::load_npcs() continue; } - add_msg_debug( "game::load_npcs: Spawning static NPC, %d:%d:%d (%d:%d:%d)", + add_msg_debug( debugmode::DF_NPC, "game::load_npcs: Spawning static NPC, %d:%d:%d (%d:%d:%d)", abs_sub.x, abs_sub.y, abs_sub.z, sm_loc.x, sm_loc.y, sm_loc.z ); temp->place_on_map(); if( !m.inbounds( temp->pos() ) ) { @@ -4562,7 +4562,8 @@ void game::monmove() << " can't move to its location! (" << critter.posx() << ":" << critter.posy() << ":" << critter.posz() << "), " << m.tername( critter.pos() ); - add_msg_debug( "%s can't move to its location! (%d,%d,%d), %s", critter.name(), + add_msg_debug( debugmode::DF_MONSTER, "%s can't move to its location! (%d,%d,%d), %s", + critter.name(), critter.posx(), critter.posy(), critter.posz(), m.tername( critter.pos() ) ); bool okay = false; for( const tripoint &dest : m.points_in_radius( critter.pos(), 3 ) ) { @@ -4660,6 +4661,12 @@ void game::monmove() debugmsg( "NPC %s entered infinite loop. Turning on debug mode", guy.name ); debug_mode = true; + // make sure the filter is active + if( std::find( + debugmode::enabled_filters.begin(), debugmode::enabled_filters.end(), + debugmode::DF_NPC ) == debugmode::enabled_filters.end() ) { + debugmode::enabled_filters.emplace_back( debugmode::DF_NPC ); + } } } @@ -7241,7 +7248,7 @@ look_around_result game::look_around( const bool show_window, tripoint ¢er, lz = clamp( lz + dz, min_levz, max_levz ); center.z = clamp( center.z + dz, min_levz, max_levz ); - add_msg_debug( "levx: %d, levy: %d, levz: %d", + add_msg_debug( debugmode::DF_GAME, "levx: %d, levy: %d, levz: %d", get_map().get_abs_sub().x, get_map().get_abs_sub().y, center.z ); u.view_offset.z = center.z - u.posz(); m.invalidate_map_cache( center.z ); diff --git a/src/handle_action.cpp b/src/handle_action.cpp index 6f38566a9c6b2..2f7582e9290c5 100644 --- a/src/handle_action.cpp +++ b/src/handle_action.cpp @@ -1563,6 +1563,122 @@ void game::open_consume_item_menu() } } +static void handle_debug_mode() +{ + auto debug_mode_setup = []( uilist_entry & entry ) -> void { + entry.txt = string_format( _( "Debug Mode (%1$s)" ), debug_mode ? _( "ON" ) : _( "OFF" ) ); + entry.text_color = debug_mode ? c_green : c_light_gray; + }; + + // returns if entry became active + auto debugmode_entry_setup = []( uilist_entry & entry, bool active ) -> void { + if( active ) + { + entry.extratxt.txt = _( "A" ); + entry.extratxt.color = c_white_green; + entry.text_color = c_green; + } else + { + entry.extratxt.txt = " "; + entry.extratxt.color = c_unset; + entry.text_color = c_light_gray; + } + }; + + static bool first_time = true; + if( first_time ) { + first_time = false; + debugmode::enabled_filters.clear(); + for( int i = 0; i < debugmode::DF_LAST; ++i ) { + debugmode::enabled_filters.emplace_back( static_cast( i ) ); + } + } + + input_context ctxt( "DEFAULTMODE" ); + ctxt.register_action( "debug_mode" ); + + uilist dbmenu; + dbmenu.allow_anykey = true; + dbmenu.title = _( "Debug Mode Filters" ); + dbmenu.text = string_format( _( "Press [%1$s] to quickly toggle debug mode." ), + ctxt.get_desc( "debug_mode" ) ); + + dbmenu.entries.reserve( 1 + debugmode::DF_LAST ); + + dbmenu.addentry( 0, true, 'd', " " ); + debug_mode_setup( dbmenu.entries[0] ); + + dbmenu.addentry( 1, true, 't', _( "Toggle all filters" ) ); + bool toggle_value = true; + + for( int i = 0; i < debugmode::DF_LAST; ++i ) { + uilist_entry entry( i + 2, true, 0, + debugmode::filter_name( static_cast( i ) ) ); + + entry.extratxt.left = 1; + + const bool active = std::find( + debugmode::enabled_filters.begin(), debugmode::enabled_filters.end(), + static_cast( i ) ) != debugmode::enabled_filters.end(); + + if( toggle_value && active ) { + toggle_value = false; + } + + debugmode_entry_setup( entry, active ); + dbmenu.entries.push_back( entry ); + } + + do { + dbmenu.query(); + if( ctxt.input_to_action( dbmenu.ret_evt ) == "debug_mode" ) { + debug_mode = !debug_mode; + if( debug_mode ) { + add_msg( m_info, _( "Debug mode ON!" ) ); + } else { + add_msg( m_info, _( "Debug mode OFF!" ) ); + } + break; + } + + if( dbmenu.ret == 0 ) { + debug_mode = !debug_mode; + debug_mode_setup( dbmenu.entries[0] ); + + } else if( dbmenu.ret == 1 ) { + debugmode::enabled_filters.clear(); + + for( int i = 0; i < debugmode::DF_LAST; ++i ) { + debugmode_entry_setup( dbmenu.entries[i + 2], toggle_value ); + + if( toggle_value ) { + debugmode::enabled_filters.emplace_back( static_cast( i ) ); + } + } + + toggle_value = !toggle_value; + + } else if( dbmenu.ret > 1 ) { + uilist_entry &entry = dbmenu.entries[dbmenu.ret]; + + const auto filter_iter = std::find( + debugmode::enabled_filters.begin(), debugmode::enabled_filters.end(), + static_cast( dbmenu.ret - 2 ) ); + + const bool active = filter_iter != debugmode::enabled_filters.end(); + + debugmode_entry_setup( entry, !active ); + + if( active ) { + debugmode::enabled_filters.erase( filter_iter ); + } else { + debugmode::enabled_filters.push_back( + static_cast( dbmenu.ret - 2 ) ); + } + } + } while( dbmenu.ret != UILIST_CANCEL ); +} + bool game::handle_action() { std::string action; @@ -2586,12 +2702,7 @@ bool game::handle_action() if( MAP_SHARING::isCompetitive() && !MAP_SHARING::isDebugger() ) { break; //don't do anything when sharing and not debugger } - debug_mode = !debug_mode; - if( debug_mode ) { - add_msg( m_info, _( "Debug mode ON!" ) ); - } else { - add_msg( m_info, _( "Debug mode OFF!" ) ); - } + handle_debug_mode(); break; case ACTION_ZOOM_IN: diff --git a/src/iexamine.cpp b/src/iexamine.cpp index c919dcc0973b3..8c62a54cfef80 100644 --- a/src/iexamine.cpp +++ b/src/iexamine.cpp @@ -3797,7 +3797,8 @@ void trap::examine( const tripoint &examp ) const int roll = std::round( normal_roll( mean_roll, 3 ) ); - add_msg( m_debug, _( "Rolled %i, mean_roll %g. difficulty %i." ), roll, mean_roll, difficulty ); + add_msg_debug( debugmode::DF_IEXAMINE, _( "Rolled %i, mean_roll %g. difficulty %i." ), roll, + mean_roll, difficulty ); //Difficulty 0 traps should succeed regardless of proficiencies. (i.e caltrops and nailboards) if( roll >= difficulty || difficulty == 0 ) { diff --git a/src/iuse_actor.cpp b/src/iuse_actor.cpp index f0fe3e01b5a4a..e92e185e78781 100644 --- a/src/iuse_actor.cpp +++ b/src/iuse_actor.cpp @@ -3136,7 +3136,7 @@ static player &get_patient( player &healer, const tripoint &pos ) player *const person = g->critter_at( pos ); if( !person ) { // Default to heal self on failure not to break old functionality - add_msg_debug( "No heal target at position %d,%d,%d", pos.x, pos.y, pos.z ); + add_msg_debug( debugmode::DF_IUSE, "No heal target at position %d,%d,%d", pos.x, pos.y, pos.z ); return healer; } diff --git a/src/map.cpp b/src/map.cpp index 1102a2a0b890e..3ad76f462f746 100644 --- a/src/map.cpp +++ b/src/map.cpp @@ -1075,7 +1075,8 @@ bool map::displace_vehicle( vehicle &veh, const tripoint &dp, const bool adjust_ ( dp + tripoint( 0, 0, ramp_offset ) ) : tripoint_zero ); if( !inbounds( src ) ) { - add_msg_debug( "map::displace_vehicle: coordinates out of bounds %d,%d,%d->%d,%d,%d", + add_msg_debug( debugmode::DF_MAP, + "map::displace_vehicle: coordinates out of bounds %d,%d,%d->%d,%d,%d", src.x, src.y, src.z, dst.x, dst.y, dst.z ); return false; } @@ -1109,7 +1110,7 @@ bool map::displace_vehicle( vehicle &veh, const tripoint &dp, const bool adjust_ } if( !found ) { - add_msg_debug( "displace_vehicle [%s] failed", veh.name ); + add_msg_debug( debugmode::DF_MAP, "displace_vehicle [%s] failed", veh.name ); return false; } @@ -1158,7 +1159,7 @@ bool map::displace_vehicle( vehicle &veh, const tripoint &dp, const bool adjust_ } if( psg->pos() != part_pos ) { - add_msg_debug( "Part/passenger position mismatch: part #%d at %d,%d,%d " + add_msg_debug( debugmode::DF_MAP, "Part/passenger position mismatch: part #%d at %d,%d,%d " "passenger at %d,%d,%d", prt, part_pos.x, part_pos.y, part_pos.z, psg->posx(), psg->posy(), psg->posz() ); } @@ -2313,7 +2314,7 @@ void map::process_falling() } if( !support_cache_dirty.empty() ) { - add_msg_debug( "Checking %d tiles for falling objects", + add_msg_debug( debugmode::DF_MAP, "Checking %d tiles for falling objects", support_cache_dirty.size() ); // We want the cache to stay constant, but falling can change it std::set last_cache = std::move( support_cache_dirty ); @@ -7530,7 +7531,7 @@ void map::spawn_monsters_submap_group( const tripoint &gp, mongroup &group, bool point( rng( 0, SEEX ), rng( 0, SEEY ) ); const int turns = rl_dist( p, rand_dest ) + group.interest; tmp.wander_to( rand_dest, turns ); - add_msg_debug( "%s targeting %d,%d,%d", tmp.disp_name(), + add_msg_debug( debugmode::DF_MAP, "%s targeting %d,%d,%d", tmp.disp_name(), tmp.wander_pos.x, tmp.wander_pos.y, tmp.wander_pos.z ); } diff --git a/src/mattack_actors.cpp b/src/mattack_actors.cpp index c0308f2b68647..77069b8f8e3e4 100644 --- a/src/mattack_actors.cpp +++ b/src/mattack_actors.cpp @@ -271,7 +271,7 @@ bool melee_actor::call( monster &z ) const z.mod_moves( -move_cost ); - add_msg_debug( "%s attempting to melee_attack %s", z.name(), + add_msg_debug( debugmode::DF_MATTACK, "%s attempting to melee_attack %s", z.name(), target->disp_name() ); const int acc = accuracy >= 0 ? accuracy : z.type->melee_skill; @@ -299,7 +299,7 @@ bool melee_actor::call( monster &z ) const dealt_damage.bp_hit = bp_hit.id(); int damage_total = dealt_damage.total_damage(); - add_msg_debug( "%s's melee_attack did %d damage", z.name(), damage_total ); + add_msg_debug( debugmode::DF_MATTACK, "%s's melee_attack did %d damage", z.name(), damage_total ); if( damage_total > 0 ) { on_damage( z, *target, dealt_damage ); } else { diff --git a/src/melee.cpp b/src/melee.cpp index 134aed15759d2..eb9fb2b6facb4 100644 --- a/src/melee.cpp +++ b/src/melee.cpp @@ -767,7 +767,7 @@ bool Character::melee_attack_abstract( Creature &t, bool allow_special, const int deft_bonus = !hits && has_trait( trait_DEFT ) ? 50 : 0; mod_stamina( std::min( -50, mod_sta + melee + deft_bonus ) ); - add_msg_debug( "Stamina burn: %d", std::min( -50, mod_sta ) ); + add_msg_debug( debugmode::DF_MELEE, "Stamina burn: %d", std::min( -50, mod_sta ) ); // Weariness handling - 1 / the value, because it returns what % of the normal speed const float weary_mult = exertion_adjusted_move_multiplier( EXTRA_EXERCISE ); mod_moves( -move_cost * ( 1 / weary_mult ) ); @@ -1560,13 +1560,13 @@ static void print_damage_info( const damage_instance &di ) ss += name_by_dt( du.type ) + ":" + std::to_string( amount ) + ","; } - add_msg_debug( "%stotal: %d", ss, total ); + add_msg_debug( debugmode::DF_MELEE, "%stotal: %d", ss, total ); } void Character::perform_technique( const ma_technique &technique, Creature &t, damage_instance &di, int &move_cost ) { - add_msg_debug( "dmg before tec:" ); + add_msg_debug( debugmode::DF_MELEE, "dmg before tec:" ); print_damage_info( di ); for( damage_unit &du : di.damage_units ) { @@ -1580,7 +1580,7 @@ void Character::perform_technique( const ma_technique &technique, Creature &t, d du.res_pen += technique.armor_penetration( *this, du.type ); } - add_msg_debug( "dmg after tec:" ); + add_msg_debug( debugmode::DF_MELEE, "dmg after tec:" ); print_damage_info( di ); move_cost *= technique.move_cost_multiplier( *this ); @@ -2151,7 +2151,8 @@ std::vector Character::mutation_attacks( Creature &t ) const // Calculate actor ability value to be compared against mutation attack difficulty and add debug message const int proc_value = get_dex() + unarmed; - add_msg_debug( "%s proc chance: %d in %d", pr.c_str(), proc_value, mut_atk.chance ); + add_msg_debug( debugmode::DF_MELEE, "%s proc chance: %d in %d", pr.c_str(), proc_value, + mut_atk.chance ); // If the mutation attack fails to proc, bail out if( !x_in_y( proc_value, mut_atk.chance ) ) { continue; @@ -2162,7 +2163,7 @@ std::vector Character::mutation_attacks( Creature &t ) const [this]( const trait_id & blocker ) { return has_trait( blocker ); } ) ) { - add_msg_debug( "%s not procing: blocked", pr.c_str() ); + add_msg_debug( debugmode::DF_MELEE, "%s not procing: blocked", pr.c_str() ); continue; } @@ -2171,7 +2172,7 @@ std::vector Character::mutation_attacks( Creature &t ) const [this]( const trait_id & need ) { return has_trait( need ); } ) ) { - add_msg_debug( "%s not procing: unmet req", pr.c_str() ); + add_msg_debug( debugmode::DF_MELEE, "%s not procing: unmet req", pr.c_str() ); continue; } @@ -2200,7 +2201,7 @@ std::vector Character::mutation_attacks( Creature &t ) const if( tmp.damage.total_damage() > 0.0f ) { ret.emplace_back( tmp ); } else { - add_msg_debug( "%s not procing: zero damage", pr.c_str() ); + add_msg_debug( debugmode::DF_MELEE, "%s not procing: zero damage", pr.c_str() ); } } } @@ -2443,7 +2444,8 @@ double Character::weapon_value( const item &weap, int ammo ) const // A small bonus for guns you can also use to hit stuff with (bayonets etc.) const double my_val = more + ( less / 2.0 ); - add_msg_debug( "%s (%ld ammo) sum value: %.1f", weap.type->get_id().str(), ammo, my_val ); + add_msg_debug( debugmode::DF_MELEE, "%s (%ld ammo) sum value: %.1f", weap.type->get_id().str(), + ammo, my_val ); if( is_wielding( weap ) ) { cached_info.emplace( "weapon_value", my_val ); } @@ -2470,7 +2472,7 @@ double Character::melee_value( const item &weap ) const my_value *= 1.5; } - add_msg_debug( "%s as melee: %.1f", weap.type->get_id().str(), my_value ); + add_msg_debug( debugmode::DF_MELEE, "%s as melee: %.1f", weap.type->get_id().str(), my_value ); return std::max( 0.0, my_value ); } diff --git a/src/messages.cpp b/src/messages.cpp index 02869d2b07a49..b804c29fa2a27 100644 --- a/src/messages.cpp +++ b/src/messages.cpp @@ -347,6 +347,18 @@ void Messages::add_msg( const game_message_params ¶ms, std::string msg ) player_messages.add_msg_string( std::move( msg ), params ); } +void Messages::add_msg_debug( debugmode::debug_filter type, std::string msg ) +{ + if( debug_mode && + std::find( + debugmode::enabled_filters.begin(), debugmode::enabled_filters.end(), + type ) == debugmode::enabled_filters.end() ) { + return; + } + + player_messages.add_msg_string( std::move( msg ), m_debug ); +} + void Messages::clear_messages() { player_messages.messages.clear(); @@ -886,6 +898,11 @@ void add_msg( const game_message_params ¶ms, std::string msg ) Messages::add_msg( params, std::move( msg ) ); } +void add_msg_debug( debugmode::debug_filter type, std::string msg ) +{ + Messages::add_msg_debug( type, std::move( msg ) ); +} + void add_msg_if_player_sees( const tripoint &target, std::string msg ) { if( get_player_view().sees( target ) ) { @@ -915,3 +932,19 @@ void add_msg_if_player_sees( const Creature &target, const game_message_params & Messages::add_msg( params, std::move( msg ) ); } } + +void add_msg_debug_if_player_sees( const tripoint &target, debugmode::debug_filter type, + std::string msg ) +{ + if( get_player_view().sees( target ) ) { + Messages::add_msg_debug( type, std::move( msg ) ); + } +} + +void add_msg_debug_if_player_sees( const Creature &target, debugmode::debug_filter type, + std::string msg ) +{ + if( get_player_view().sees( target ) ) { + Messages::add_msg_debug( type, std::move( msg ) ); + } +} diff --git a/src/messages.h b/src/messages.h index db482b35564c6..6270cb4259885 100644 --- a/src/messages.h +++ b/src/messages.h @@ -28,6 +28,7 @@ namespace Messages std::vector> recent_messages( size_t count ); void add_msg( std::string msg ); void add_msg( const game_message_params ¶ms, std::string msg ); +void add_msg_debug( debugmode::debug_filter type, std::string msg ); void clear_messages(); void deactivate(); size_t size(); @@ -56,12 +57,6 @@ inline void add_msg( const translation &msg, Args &&... args ) return add_msg( string_format( msg, std::forward( args )... ) ); } -// Prevent potentially expensive evaluation of arguments which won't be printed. -#define add_msg_debug( ... )\ - if( debug_mode ) {\ - add_msg( m_debug, __VA_ARGS__ );\ - }; - void add_msg( const game_message_params ¶ms, std::string msg ); template inline void add_msg( const game_message_params ¶ms, const std::string &msg, Args &&... args ) @@ -80,6 +75,23 @@ inline void add_msg( const game_message_params ¶ms, const char *const msg, A return add_msg( params, string_format( msg, std::forward( args )... ) ); } +void add_msg_debug( debugmode::debug_filter type, std::string msg ); +template +inline void add_msg_debug( debugmode::debug_filter type, const std::string &msg, Args &&... args ) +{ + // expanding for string formatting can be expensive + if( debug_mode ) { + return add_msg_debug( type, string_format( msg, std::forward( args )... ) ); + } +} +template +inline void add_msg_debug( debugmode::debug_filter type, const char *const msg, Args &&... args ) +{ + if( debug_mode ) { + return add_msg_debug( type, string_format( msg, std::forward( args )... ) ); + } +} + void add_msg_if_player_sees( const tripoint &target, std::string msg ); void add_msg_if_player_sees( const Creature &target, std::string msg ); template @@ -162,4 +174,46 @@ inline void add_msg_if_player_sees( const Creature &target, const game_message_p std::forward( args )... ) ); } +void add_msg_debug_if_player_sees( const tripoint &target, debugmode::debug_filter type, + std::string msg ); +void add_msg_debug_if_player_sees( const Creature &target, debugmode::debug_filter type, + std::string msg ); +template +inline void add_msg_debug_if_player_sees( const tripoint &target, debugmode::debug_filter type, + const std::string &msg, Args &&... args ) +{ + // expanding for string formatting can be expensive + if( debug_mode ) { + return add_msg_debug_if_player_sees( target, type, string_format( msg, + std::forward( args )... ) ); + } +} +template +inline void add_msg_debug_if_player_sees( const Creature &target, debugmode::debug_filter type, + const std::string &msg, Args &&... args ) +{ + if( debug_mode ) { + return add_msg_debug_if_player_sees( target, type, string_format( msg, + std::forward( args )... ) ); + } +} +template +inline void add_msg_debug_if_player_sees( const tripoint &target, debugmode::debug_filter type, + const char *const msg, Args &&... args ) +{ + if( debug_mode ) { + return add_msg_debug_if_player_sees( target, type, string_format( msg, + std::forward( args )... ) ); + } +} +template +inline void add_msg_debug_if_player_sees( const Creature &target, debugmode::debug_filter type, + const char *const msg, Args &&... args ) +{ + if( debug_mode ) { + return add_msg_debug_if_player_sees( target, type, string_format( msg, + std::forward( args )... ) ); + } +} + #endif // CATA_SRC_MESSAGES_H diff --git a/src/monattack.cpp b/src/monattack.cpp index 8a3a8a9e92538..ceaf9593c1517 100644 --- a/src/monattack.cpp +++ b/src/monattack.cpp @@ -4284,7 +4284,8 @@ bool mattack::absorb_meat( monster *z ) if( player_character.sees( *z ) ) { add_msg( m_warning, _( "The %1$s absorbs the %2$s, growing larger." ), z->name(), current_item.tname() ); - add_msg_debug( "The %1$s now has %2$s out of %3$s hp", z->name(), z->get_hp(), + add_msg_debug( debugmode::DF_MATTACK, "The %1$s now has %2$s out of %3$s hp", z->name(), + z->get_hp(), z->get_hp_max() ); } return true; @@ -5396,7 +5397,7 @@ bool mattack::kamikaze( monster *z ) { if( z->ammo.empty() ) { // We somehow lost our ammo! Toggle this special off so we stop processing - add_msg_debug( "Missing ammo in kamikaze special for %s.", z->name() ); + add_msg_debug( debugmode::DF_MATTACK, "Missing ammo in kamikaze special for %s.", z->name() ); z->disable_special( "KAMIKAZE" ); return true; } @@ -5416,14 +5417,15 @@ bool mattack::kamikaze( monster *z ) const use_function *usage = bomb_type->get_use( "transform" ); if( usage == nullptr ) { // Invalid item usage, Toggle this special off so we stop processing - add_msg_debug( "Invalid bomb transform use in kamikaze special for %s.", z->name() ); + add_msg_debug( debugmode::DF_MATTACK, "Invalid bomb transform use in kamikaze special for %s.", + z->name() ); z->disable_special( "KAMIKAZE" ); return true; } const iuse_transform *actor = dynamic_cast( usage->get_actor_ptr() ); if( actor == nullptr ) { // Invalid bomb item, Toggle this special off so we stop processing - add_msg_debug( "Invalid bomb type in kamikaze special for %s.", z->name() ); + add_msg_debug( debugmode::DF_MATTACK, "Invalid bomb type in kamikaze special for %s.", z->name() ); z->disable_special( "KAMIKAZE" ); return true; } @@ -5448,7 +5450,8 @@ bool mattack::kamikaze( monster *z ) const use_function *use = act_bomb_type->get_use( "explosion" ); if( use == nullptr ) { // Invalid active bomb item usage, Toggle this special off so we stop processing - add_msg_debug( "Invalid active bomb explosion use in kamikaze special for %s.", + add_msg_debug( debugmode::DF_MATTACK, + "Invalid active bomb explosion use in kamikaze special for %s.", z->name() ); z->disable_special( "KAMIKAZE" ); return true; @@ -5456,7 +5459,8 @@ bool mattack::kamikaze( monster *z ) const explosion_iuse *exp_actor = dynamic_cast( use->get_actor_ptr() ); if( exp_actor == nullptr ) { // Invalid active bomb item, Toggle this special off so we stop processing - add_msg_debug( "Invalid active bomb type in kamikaze special for %s.", z->name() ); + add_msg_debug( debugmode::DF_MATTACK, "Invalid active bomb type in kamikaze special for %s.", + z->name() ); z->disable_special( "KAMIKAZE" ); return true; } @@ -5577,7 +5581,7 @@ static int grenade_helper( monster *const z, Creature *const target, const int d // if the player can see it if( get_player_view().sees( *z ) ) { if( data[att].message.empty() ) { - add_msg_debug( "Invalid ammo message in grenadier special." ); + add_msg_debug( debugmode::DF_MATTACK, "Invalid ammo message in grenadier special." ); } else { add_msg( m_bad, data[att].message, z->name() ); } @@ -5588,14 +5592,15 @@ static int grenade_helper( monster *const z, Creature *const target, const int d const use_function *usage = bomb_type->get_use( "place_monster" ); if( usage == nullptr ) { // Invalid bomb item usage, Toggle this special off so we stop processing - add_msg_debug( "Invalid bomb item usage in grenadier special for %s.", z->name() ); + add_msg_debug( debugmode::DF_MATTACK, "Invalid bomb item usage in grenadier special for %s.", + z->name() ); return -1; } const place_monster_iuse *actor = dynamic_cast ( usage->get_actor_ptr() ); if( actor == nullptr ) { // Invalid bomb item, Toggle this special off so we stop processing - add_msg_debug( "Invalid bomb type in grenadier special for %s.", z->name() ); + add_msg_debug( debugmode::DF_MATTACK, "Invalid bomb type in grenadier special for %s.", z->name() ); return -1; } diff --git a/src/monster.cpp b/src/monster.cpp index da358b7188945..edca5c9df481b 100644 --- a/src/monster.cpp +++ b/src/monster.cpp @@ -284,7 +284,8 @@ void monster::setpos( const tripoint &p ) g->update_zombie_pos( *this, p ); position = p; if( has_effect( effect_ridden ) && mounted_player && mounted_player->pos() != pos() ) { - add_msg_debug( "Ridden monster %s moved independently and dumped player", get_name() ); + add_msg_debug( debugmode::DF_MONSTER, "Ridden monster %s moved independently and dumped player", + get_name() ); mounted_player->forced_dismount(); } if( wandering ) { @@ -1490,7 +1491,7 @@ bool monster::block_hit( Creature *, bodypart_id &, damage_instance & ) void monster::absorb_hit( const bodypart_id &, damage_instance &dam ) { for( auto &elem : dam.damage_units ) { - add_msg_debug( "Dam Type: %s :: Ar Pen: %.1f :: Armor Mult: %.1f", + add_msg_debug( debugmode::DF_MONSTER, "Dam Type: %s :: Ar Pen: %.1f :: Armor Mult: %.1f", name_by_dt( elem.type ), elem.res_pen, elem.res_mult ); elem.amount -= std::min( resistances( *this ).get_effective_resist( elem ) + get_worn_armor_val( elem.type ), elem.amount ); @@ -2817,12 +2818,24 @@ void monster::add_msg_if_npc( const game_message_params ¶ms, const std::stri add_msg_if_player_sees( *this, params, replace_with_npc_name( msg ) ); } +void monster::add_msg_debug_if_npc( debugmode::debug_filter type, const std::string &msg ) const +{ + add_msg_debug_if_player_sees( *this, type, replace_with_npc_name( msg ) ); +} + void monster::add_msg_player_or_npc( const game_message_params ¶ms, const std::string &/*player_msg*/, const std::string &npc_msg ) const { add_msg_if_player_sees( *this, params, replace_with_npc_name( npc_msg ) ); } +void monster::add_msg_debug_player_or_npc( debugmode::debug_filter type, + const std::string &/*player_msg*/, + const std::string &npc_msg ) const +{ + add_msg_debug_if_player_sees( *this, type, replace_with_npc_name( npc_msg ) ); +} + units::mass monster::get_carried_weight() { units::mass total_weight = 0_gram; @@ -3108,7 +3121,7 @@ void monster::on_load() healed_speed = get_speed_base() - old_speed; } - add_msg_debug( "on_load() by %s, %d turns, healed %d hp, %d speed", + add_msg_debug( debugmode::DF_MONSTER, "on_load() by %s, %d turns, healed %d hp, %d speed", name(), to_turns( dt ), healed, healed_speed ); } diff --git a/src/monster.h b/src/monster.h index f773b6205c4ee..07450a8c51438 100644 --- a/src/monster.h +++ b/src/monster.h @@ -443,11 +443,16 @@ class monster : public Creature using Creature::add_msg_if_npc; void add_msg_if_npc( const std::string &msg ) const override; void add_msg_if_npc( const game_message_params ¶ms, const std::string &msg ) const override; + using Creature::add_msg_debug_if_npc; + void add_msg_debug_if_npc( debugmode::debug_filter type, const std::string &msg ) const override; using Creature::add_msg_player_or_npc; void add_msg_player_or_npc( const std::string &player_msg, const std::string &npc_msg ) const override; void add_msg_player_or_npc( const game_message_params ¶ms, const std::string &player_msg, const std::string &npc_msg ) const override; + using Creature::add_msg_debug_player_or_npc; + void add_msg_debug_player_or_npc( debugmode::debug_filter type, const std::string &player_msg, + const std::string &npc_msg ) const override; // TEMP VALUES tripoint wander_pos; // Wander destination - Just try to move in that direction int wandf = 0; // Urge to wander - Increased by sound, decrements each move diff --git a/src/npc.cpp b/src/npc.cpp index 3cc5ecc497d87..1586fd686b8cd 100644 --- a/src/npc.cpp +++ b/src/npc.cpp @@ -1356,7 +1356,8 @@ void npc::form_opinion( const player &u ) set_attitude( NPCATT_FLEE_TEMP ); } - add_msg_debug( "%s formed an opinion of u: %s", name, npc_attitude_id( attitude ) ); + add_msg_debug( debugmode::DF_NPC, "%s formed an opinion of u: %s", name, + npc_attitude_id( attitude ) ); } void npc::mutiny() @@ -2220,7 +2221,8 @@ Creature::Attitude npc::attitude_to( const Creature &other ) const void npc::npc_dismount() { if( !mounted_creature || !has_effect( effect_riding ) ) { - add_msg_debug( "NPC %s tried to dismount, but they have no mount, or they are not riding", + add_msg_debug( debugmode::DF_NPC, + "NPC %s tried to dismount, but they have no mount, or they are not riding", disp_name() ); return; } @@ -2232,7 +2234,7 @@ void npc::npc_dismount() } } if( !pnt ) { - add_msg_debug( "NPC %s could not find a place to dismount.", disp_name() ); + add_msg_debug( debugmode::DF_NPC, "NPC %s could not find a place to dismount.", disp_name() ); return; } remove_effect( effect_riding ); @@ -2743,6 +2745,11 @@ void npc::add_msg_if_npc( const game_message_params ¶ms, const std::string & add_msg( params, replace_with_npc_name( msg ) ); } +void npc::add_msg_debug_if_npc( debugmode::debug_filter type, const std::string &msg ) const +{ + add_msg_debug( type, replace_with_npc_name( msg ) ); +} + void npc::add_msg_player_or_npc( const game_message_params ¶ms, const std::string &/*player_msg*/, const std::string &npc_msg ) const @@ -2752,6 +2759,15 @@ void npc::add_msg_player_or_npc( const game_message_params ¶ms, } } +void npc::add_msg_debug_player_or_npc( debugmode::debug_filter type, + const std::string &/*player_msg*/, + const std::string &npc_msg ) const +{ + if( get_player_view().sees( *this ) ) { + add_msg_debug( type, replace_with_npc_name( npc_msg ) ); + } +} + void npc::add_msg_player_or_say( const std::string &/*player_msg*/, const std::string &npc_speech ) const { @@ -2804,7 +2820,7 @@ void npc::on_load() // TODO: Sleeping, healing etc. last_updated = calendar::turn; time_point cur = calendar::turn - dt; - add_msg_debug( "on_load() by %s, %d turns", name, to_turns( dt ) ); + add_msg_debug( debugmode::DF_NPC, "on_load() by %s, %d turns", name, to_turns( dt ) ); // First update with 30 minute granularity, then 5 minutes, then turns for( ; cur < calendar::turn - 30_minutes; cur += 30_minutes + 1_turns ) { update_body( cur, cur + 30_minutes ); @@ -2846,7 +2862,8 @@ void npc::on_load() if( const monster *const mon = g->critter_at( pos() ) ) { mounted_creature = g->shared_from( *mon ); } else { - add_msg_debug( "NPC is meant to be riding, though the mount is not found when %s is loaded", + add_msg_debug( debugmode::DF_NPC, + "NPC is meant to be riding, though the mount is not found when %s is loaded", disp_name() ); } } @@ -3232,7 +3249,7 @@ void npc::set_attitude( npc_attitude new_attitude ) add_effect( effect_npc_flee_player, 24_hours ); } - add_msg_debug( "%s changes attitude from %s to %s", + add_msg_debug( debugmode::DF_NPC, "%s changes attitude from %s to %s", name, npc_attitude_id( attitude ), npc_attitude_id( new_attitude ) ); attitude_group new_group = get_attitude_group( new_attitude ); attitude_group old_group = get_attitude_group( attitude ); diff --git a/src/npc.h b/src/npc.h index d082eb01409f9..7554cb98fb431 100644 --- a/src/npc.h +++ b/src/npc.h @@ -1198,15 +1198,23 @@ class npc : public player using player::add_msg_if_npc; void add_msg_if_npc( const std::string &msg ) const override; void add_msg_if_npc( const game_message_params ¶ms, const std::string &msg ) const override; + using player::add_msg_debug_if_npc; + void add_msg_debug_if_npc( debugmode::debug_filter type, const std::string &msg ) const override; using player::add_msg_player_or_npc; void add_msg_player_or_npc( const std::string &player_msg, const std::string &npc_msg ) const override; void add_msg_player_or_npc( const game_message_params ¶ms, const std::string &player_msg, const std::string &npc_msg ) const override; + using player::add_msg_debug_player_or_npc; + void add_msg_debug_player_or_npc( debugmode::debug_filter type, const std::string &player_msg, + const std::string &npc_msg ) const override; using player::add_msg_if_player; void add_msg_if_player( const std::string &/*msg*/ ) const override {} void add_msg_if_player( const game_message_params &/*type*/, const std::string &/*msg*/ ) const override {} + using player::add_msg_debug_if_player; + void add_msg_debug_if_player( debugmode::debug_filter /*type*/, + const std::string &/*msg*/ ) const override {} using player::add_msg_player_or_say; void add_msg_player_or_say( const std::string &player_msg, const std::string &npc_speech ) const override; diff --git a/src/npcmove.cpp b/src/npcmove.cpp index 1a47a3e300a11..03ea28a6a9eb2 100644 --- a/src/npcmove.cpp +++ b/src/npcmove.cpp @@ -692,7 +692,7 @@ float npc::character_danger( const Character &uc ) const ret *= std::max( 0.5, u.get_speed() / 100.0 ); - add_msg_debug( "%s danger: %1f", u.disp_name(), ret ); + add_msg_debug( debugmode::DF_NPC, "%s danger: %1f", u.disp_name(), ret ); return ret; } @@ -780,7 +780,7 @@ void npc::move() static const std::string no_target_str = "none"; const Creature *target = current_target(); const std::string &target_name = target != nullptr ? target->disp_name() : no_target_str; - add_msg_debug( "NPC %s: target = %s, danger = %.1f, range = %d", + add_msg_debug( debugmode::DF_NPC, "NPC %s: target = %s, danger = %.1f, range = %d", name, target_name, ai_cache.danger, weapon.is_gun() ? confident_shoot_range( weapon, recoil_total() ) : weapon.reach_range( *this ) ); @@ -790,7 +790,7 @@ void npc::move() if( is_player_ally() ) { mutiny(); } - add_msg_debug( "NPC %s turning hostile because is guaranteed_hostile()", name ); + add_msg_debug( debugmode::DF_NPC, "NPC %s turning hostile because is guaranteed_hostile()", name ); if( op_of_u.fear > 10 + personality.aggression + personality.bravery ) { set_attitude( NPCATT_FLEE_TEMP ); // We don't want to take u on! } else { @@ -865,12 +865,12 @@ void npc::move() } } if( action == npc_investigate_sound ) { - add_msg_debug( "NPC %s: investigating sound at x(%d) y(%d)", name, + add_msg_debug( debugmode::DF_NPC, "NPC %s: investigating sound at x(%d) y(%d)", name, ai_cache.s_abs_pos.x, ai_cache.s_abs_pos.y ); } } else if( ai_cache.sound_alerts.empty() && ai_cache.guard_pos ) { tripoint return_guard_pos = *ai_cache.guard_pos; - add_msg_debug( "NPC %s: returning to guard spot at x(%d) y(%d)", name, + add_msg_debug( debugmode::DF_NPC, "NPC %s: returning to guard spot at x(%d) y(%d)", name, return_guard_pos.x, return_guard_pos.y ); action = npc_return_to_guard_pos; } else { @@ -1001,7 +1001,7 @@ void npc::move() action = method_of_attack(); } - add_msg_debug( "%s chose action %s.", name, npc_action_name( action ) ); + add_msg_debug( debugmode::DF_NPC, "%s chose action %s.", name, npc_action_name( action ) ); execute_action( action ); } @@ -1343,7 +1343,7 @@ void npc::execute_action( npc_action action ) break; case npc_noop: - add_msg_debug( "%s skips turn (noop)", disp_name() ); + add_msg_debug( debugmode::DF_NPC, "%s skips turn (noop)", disp_name() ); return; default: @@ -1351,7 +1351,7 @@ void npc::execute_action( npc_action action ) } if( oldmoves == moves ) { - add_msg_debug( "NPC didn't use its moves. Action %s (%d).", + add_msg_debug( debugmode::DF_NPC, "NPC didn't use its moves. Action %s (%d).", npc_action_name( action ), action ); } } @@ -1441,7 +1441,7 @@ npc_action npc::method_of_attack() } ); if( emergency() && alt_attack() ) { - add_msg_debug( "%s is trying an alternate attack", disp_name() ); + add_msg_debug( debugmode::DF_NPC, "%s is trying an alternate attack", disp_name() ); return npc_noop; } @@ -1449,13 +1449,13 @@ npc_action npc::method_of_attack() int reach_range = weapon.reach_range( *this ); if( !trigdist ) { if( reach_range > 1 && reach_range >= dist && clear_shot_reach( pos(), tar ) ) { - add_msg_debug( "%s is trying a reach attack", disp_name() ); + add_msg_debug( debugmode::DF_NPC, "%s is trying a reach attack", disp_name() ); return npc_reach_attack; } } else { if( reach_range > 1 && reach_range >= std::round( trig_dist( pos(), tar ) ) && clear_shot_reach( pos(), tar ) ) { - add_msg_debug( "%s is trying a reach attack", disp_name() ); + add_msg_debug( debugmode::DF_NPC, "%s is trying a reach attack", disp_name() ); return npc_reach_attack; } } @@ -1464,25 +1464,25 @@ npc_action npc::method_of_attack() if( !modes.empty() && sees( *critter ) && has_los && confident_gun_mode_range( modes[ 0 ].second, cur_recoil ) >= dist ) { if( cbm_weapon_index > 0 && !weapon.ammo_sufficient() && can_reload_current() ) { - add_msg_debug( "%s is reloading", disp_name() ); + add_msg_debug( debugmode::DF_NPC, "%s is reloading", disp_name() ); return npc_reload; } if( wont_hit_friend( tar, weapon, false ) ) { weapon.gun_set_mode( modes[ 0 ].first ); - add_msg_debug( "%s is trying to shoot someone", disp_name() ); + add_msg_debug( debugmode::DF_NPC, "%s is trying to shoot someone", disp_name() ); return npc_shoot; } else { if( !dont_move_ff ) { - add_msg_debug( "%s is trying to avoid friendly fire", disp_name() ); + add_msg_debug( debugmode::DF_NPC, "%s is trying to avoid friendly fire", disp_name() ); return npc_avoid_friendly_fire; } } } if( dist == 1 && same_z ) { - add_msg_debug( "%s is trying a melee attack", disp_name() ); + add_msg_debug( debugmode::DF_NPC, "%s is trying a melee attack", disp_name() ); return npc_melee; } @@ -1490,12 +1490,12 @@ npc_action npc::method_of_attack() if( cbm_weapon_index < 0 ) { // TODO: Add a time check now that wielding takes a lot of time if( wield_better_weapon() ) { - add_msg_debug( "%s is changing weapons", disp_name() ); + add_msg_debug( debugmode::DF_NPC, "%s is changing weapons", disp_name() ); return npc_noop; } if( !weapon.ammo_sufficient() && can_reload_current() ) { - add_msg_debug( "%s is reloading", disp_name() ); + add_msg_debug( debugmode::DF_NPC, "%s is reloading", disp_name() ); return npc_reload; } } @@ -1503,10 +1503,10 @@ npc_action npc::method_of_attack() // TODO: Needs a check for transparent but non-passable tiles on the way if( !modes.empty() && sees( *critter ) && aim_per_move( weapon, recoil ) > 0 && confident_shoot_range( weapon, get_most_accurate_sight( weapon ) ) >= dist ) { - add_msg_debug( "%s is aiming" ); + add_msg_debug( debugmode::DF_NPC, "%s is aiming" ); return npc_aim; } - add_msg_debug( "%s can't figure out what to do", disp_name() ); + add_msg_debug( debugmode::DF_NPC, "%s can't figure out what to do", disp_name() ); return ( dont_move || !same_z ) ? npc_undecided : npc_melee; } @@ -2015,7 +2015,7 @@ npc_action npc::address_player() npc_action npc::long_term_goal_action() { - add_msg_debug( "long_term_goal_action()" ); + add_msg_debug( debugmode::DF_NPC, "long_term_goal_action()" ); if( mission == NPC_MISSION_SHOPKEEP || mission == NPC_MISSION_SHELTER || ( is_player_ally() && mission != NPC_MISSION_TRAVELLING ) ) { @@ -2083,7 +2083,7 @@ int npc::confident_gun_mode_range( const gun_mode &gun, int at_recoil ) const double max_dispersion = get_weapon_dispersion( *( gun.target ) ).max() + at_recoil; double even_chance_range = range_with_even_chance_of_good_hit( max_dispersion ); double confident_range = even_chance_range * confidence_mult(); - add_msg_debug( "confident_gun (%s<=%.2f) at %.1f", gun.tname(), confident_range, + add_msg_debug( debugmode::DF_NPC, "confident_gun (%s<=%.2f) at %.1f", gun.tname(), confident_range, max_dispersion ); return std::max( confident_range, 1 ); } @@ -2094,7 +2094,8 @@ int npc::confident_throw_range( const item &thrown, Creature *target ) const double even_chance_range = ( target == nullptr ? 0.5 : target->ranged_target_size() ) / average_dispersion; double confident_range = even_chance_range * confidence_mult(); - add_msg_debug( "confident_throw_range == %d", static_cast( confident_range ) ); + add_msg_debug( debugmode::DF_NPC, "confident_throw_range == %d", + static_cast( confident_range ) ); return static_cast( confident_range ); } @@ -2211,10 +2212,10 @@ bool npc::update_path( const tripoint &p, const bool no_bashing, bool force ) if( new_path.empty() ) { if( !ai_cache.sound_alerts.empty() ) { ai_cache.sound_alerts.erase( ai_cache.sound_alerts.begin() ); - add_msg_debug( "failed to path to sound alert %d,%d,%d->%d,%d,%d", + add_msg_debug( debugmode::DF_NPC, "failed to path to sound alert %d,%d,%d->%d,%d,%d", posx(), posy(), posz(), p.x, p.y, p.z ); } - add_msg_debug( "Failed to path %d,%d,%d->%d,%d,%d", + add_msg_debug( debugmode::DF_NPC, "Failed to path %d,%d,%d->%d,%d,%d", posx(), posy(), posz(), p.x, p.y, p.z ); } @@ -2480,7 +2481,7 @@ void npc::move_to_next() } if( path.empty() ) { - add_msg_debug( "npc::move_to_next() called with an empty path or path " + add_msg_debug( debugmode::DF_NPC, "npc::move_to_next() called with an empty path or path " "containing only current position" ); move_pause(); return; @@ -2980,7 +2981,7 @@ void npc::pick_up_item() } if( !rules.has_flag( ally_rule::allow_pick_up ) && is_player_ally() ) { - add_msg_debug( "%s::pick_up_item(); Canceling on player's request", name ); + add_msg_debug( debugmode::DF_NPC, "%s::pick_up_item(); Canceling on player's request", name ); fetching_item = false; moves -= 1; return; @@ -2998,11 +2999,11 @@ void npc::pick_up_item() // Or player who is leading us doesn't want us to pick it up fetching_item = false; move_pause(); - add_msg_debug( "Canceling pickup - no items or new zone" ); + add_msg_debug( debugmode::DF_NPC, "Canceling pickup - no items or new zone" ); return; } - add_msg_debug( "%s::pick_up_item(); [%d, %d, %d] => [%d, %d, %d]", name, + add_msg_debug( debugmode::DF_NPC, "%s::pick_up_item(); [ % d, % d, % d] => [ % d, % d, % d]", name, posx(), posy(), posz(), wanted_item_pos.x, wanted_item_pos.y, wanted_item_pos.z ); if( const cata::optional dest = nearest_passable( wanted_item_pos, pos() ) ) { update_path( *dest ); @@ -3010,13 +3011,13 @@ void npc::pick_up_item() const int dist_to_pickup = rl_dist( pos(), wanted_item_pos ); if( dist_to_pickup > 1 && !path.empty() ) { - add_msg_debug( "Moving; [%d, %d, %d] => [%d, %d, %d]", + add_msg_debug( debugmode::DF_NPC, "Moving; [%d, %d, %d] => [%d, %d, %d]", posx(), posy(), posz(), path[0].x, path[0].y, path[0].z ); move_to_next(); return; } else if( dist_to_pickup > 1 && path.empty() ) { - add_msg_debug( "Can't find path" ); + add_msg_debug( debugmode::DF_NPC, "Can't find path" ); // This can happen, always do something fetching_item = false; move_pause(); @@ -3113,7 +3114,8 @@ void npc::drop_items( const units::mass &drop_weight, const units::volume &drop_ /* Remove this when someone debugs it back to functionality */ return; - add_msg_debug( "%s is dropping items-%3.2f kg, %3.2f L (%d items, wgt %3.2f/%3.2f kg, " + add_msg_debug( debugmode::DF_NPC, + "%s is dropping items-%3.2f kg, %3.2f L (%d items, wgt %3.2f/%3.2f kg, " "vol %3.2f/%3.2f L)", name, units::to_kilogram( drop_weight ), units::to_liter( drop_volume ), inv->size(), units::to_kilogram( weight_carried() ), units::to_kilogram( weight_capacity() ), @@ -3426,12 +3428,14 @@ bool npc::wield_better_weapon() // Until then, the NPCs should reload the guns as a last resort if( best == &weapon ) { - add_msg_debug( "Wielded %s is best at %.1f, not switching", best->type->get_id().str(), + add_msg_debug( debugmode::DF_NPC, "Wielded %s is best at %.1f, not switching", + best->type->get_id().str(), best_value ); return false; } - add_msg_debug( "Wielding %s at value %.1f", best->type->get_id().str(), best_value ); + add_msg_debug( debugmode::DF_NPC, "Wielding %s at value %.1f", best->type->get_id().str(), + best_value ); wield( *best ); return true; @@ -3439,7 +3443,7 @@ bool npc::wield_better_weapon() bool npc::scan_new_items() { - add_msg_debug( "%s scanning new items", name ); + add_msg_debug( debugmode::DF_NPC, "%s scanning new items", name ); if( wield_better_weapon() ) { return true; } else { @@ -4212,7 +4216,7 @@ void npc::go_to_omt_destination() } } if( goal == no_goal_point || omt_path.empty() ) { - add_msg_debug( "npc::go_to_destination with no goal" ); + add_msg_debug( debugmode::DF_NPC, "npc::go_to_destination with no goal" ); move_pause(); reach_omt_destination(); return; @@ -4260,7 +4264,7 @@ void npc::go_to_omt_destination() } } path = here.route( pos(), centre_sub, get_pathfinding_settings(), get_path_avoid() ); - add_msg_debug( "%s going %s->%s", name, omt_pos.to_string(), goal.to_string() ); + add_msg_debug( debugmode::DF_NPC, "%s going %s->%s", name, omt_pos.to_string(), goal.to_string() ); if( !path.empty() ) { move_to_next(); @@ -4338,7 +4342,7 @@ std::string npc_action_name( npc_action action ) void print_action( const char *prepend, npc_action action ) { if( action != npc_undecided ) { - add_msg_debug( prepend, npc_action_name( action ) ); + add_msg_debug( debugmode::DF_NPC, prepend, npc_action_name( action ) ); } } diff --git a/src/npctalk.cpp b/src/npctalk.cpp index 886ed573b9319..facc2caad6eff 100644 --- a/src/npctalk.cpp +++ b/src/npctalk.cpp @@ -631,7 +631,8 @@ void npc::handle_sound( const sounds::sound_t spriority, const std::string &desc const tripoint s_abs_pos = here.getabs( spos ); const tripoint my_abs_pos = here.getabs( pos() ); - add_msg_debug( "%s heard '%s', priority %d at volume %d from %d:%d, my pos %d:%d", + add_msg_debug( debugmode::DF_NPC, + "%s heard '%s', priority %d at volume %d from %d:%d, my pos %d:%d", disp_name(), description, static_cast( spriority ), heard_volume, s_abs_pos.x, s_abs_pos.y, my_abs_pos.x, my_abs_pos.y ); @@ -652,11 +653,11 @@ void npc::handle_sound( const sounds::sound_t spriority, const std::string &desc // but only for bantering purposes, not for investigating. if( spriority < sounds::sound_t::alarm ) { if( player_ally ) { - add_msg_debug( "Allied NPC ignored same faction %s", name ); + add_msg_debug( debugmode::DF_NPC, "Allied NPC ignored same faction %s", name ); return; } if( npc_ally ) { - add_msg_debug( "NPC ignored same faction %s", name ); + add_msg_debug( debugmode::DF_NPC, "NPC ignored same faction %s", name ); return; } } @@ -664,7 +665,7 @@ void npc::handle_sound( const sounds::sound_t spriority, const std::string &desc // and listener is friendly and sound source is combat or alert only. if( spriority < sounds::sound_t::alarm && player_character.sees( spos ) ) { if( is_player_ally() ) { - add_msg_debug( "NPC %s ignored low priority noise that player can see", name ); + add_msg_debug( debugmode::DF_NPC, "NPC %s ignored low priority noise that player can see", name ); return; // discount if sound source is player, or seen by player, // listener is neutral and sound type is worth investigating. @@ -703,7 +704,7 @@ void npc::handle_sound( const sounds::sound_t spriority, const std::string &desc } } if( should_check ) { - add_msg_debug( "%s added noise at pos %d:%d", name, s_abs_pos.x, s_abs_pos.y ); + add_msg_debug( debugmode::DF_NPC, "%s added noise at pos %d:%d", name, s_abs_pos.x, s_abs_pos.y ); dangerous_sound temp_sound; temp_sound.abs_pos = s_abs_pos; temp_sound.volume = heard_volume; diff --git a/src/npctalk_funcs.cpp b/src/npctalk_funcs.cpp index be2aa274fac55..ed10341c7511e 100644 --- a/src/npctalk_funcs.cpp +++ b/src/npctalk_funcs.cpp @@ -210,7 +210,7 @@ void spawn_animal( npc &p, const mtype_id &mon ) mon_ptr->add_effect( effect_pet, 1_turns, true ); } else { // TODO: handle this gracefully (return the money, proper in-character message from npc) - add_msg_debug( "No space to spawn purchased pet" ); + add_msg_debug( debugmode::DF_NPC, "No space to spawn purchased pet" ); } } diff --git a/src/overmap.cpp b/src/overmap.cpp index 76082413339bb..4719edfc7f780 100644 --- a/src/overmap.cpp +++ b/src/overmap.cpp @@ -2116,11 +2116,11 @@ void overmap::signal_hordes( const tripoint_rel_sm &p_rel, const int sig_power ) const int min_inc_inter = 3; // Min interest increase to already targeted source const int inc_roll = rng( min_inc_inter, calculated_inter ); mg.inc_interest( inc_roll ); - add_msg_debug( "horde inc interest %d dist %d", inc_roll, dist ); + add_msg_debug( debugmode::DF_OVERMAP, "horde inc interest %d dist %d", inc_roll, dist ); } else { // New signal source mg.set_target( p.xy() ); mg.set_interest( min_capped_inter ); - add_msg_debug( "horde set interest %d dist %d", min_capped_inter, dist ); + add_msg_debug( debugmode::DF_OVERMAP, "horde set interest %d dist %d", min_capped_inter, dist ); } } } diff --git a/src/player.cpp b/src/player.cpp index 962cfdbcf2809..2fb5b0e81c8b8 100644 --- a/src/player.cpp +++ b/src/player.cpp @@ -2541,6 +2541,11 @@ void player::add_msg_if_player( const game_message_params ¶ms, const std::st Messages::add_msg( params, msg ); } +void player::add_msg_debug_if_player( debugmode::debug_filter type, const std::string &msg ) const +{ + Messages::add_msg_debug( type, msg ); +} + void player::add_msg_player_or_npc( const game_message_params ¶ms, const std::string &player_msg, const std::string &/*npc_msg*/ ) const @@ -2548,6 +2553,13 @@ void player::add_msg_player_or_npc( const game_message_params ¶ms, Messages::add_msg( params, player_msg ); } +void player::add_msg_debug_player_or_npc( debugmode::debug_filter type, + const std::string &player_msg, + const std::string &/*npc_msg*/ ) const +{ + Messages::add_msg_debug( type, player_msg ); +} + void player::add_msg_player_or_say( const std::string &player_msg, const std::string &/*npc_speech*/ ) const { diff --git a/src/player.h b/src/player.h index bd78c984cbe31..eb8a12fac4d7b 100644 --- a/src/player.h +++ b/src/player.h @@ -365,11 +365,17 @@ class player : public Character using Character::add_msg_if_player; void add_msg_if_player( const std::string &msg ) const override; void add_msg_if_player( const game_message_params ¶ms, const std::string &msg ) const override; + using Character::add_msg_debug_if_player; + void add_msg_debug_if_player( debugmode::debug_filter type, + const std::string &msg ) const override; using Character::add_msg_player_or_npc; void add_msg_player_or_npc( const std::string &player_msg, const std::string &npc_str ) const override; void add_msg_player_or_npc( const game_message_params ¶ms, const std::string &player_msg, const std::string &npc_msg ) const override; + using Character::add_msg_debug_player_or_npc; + void add_msg_debug_player_or_npc( debugmode::debug_filter type, const std::string &player_msg, + const std::string &npc_msg ) const override; using Character::add_msg_player_or_say; void add_msg_player_or_say( const std::string &player_msg, const std::string &npc_speech ) const override; diff --git a/src/ranged.cpp b/src/ranged.cpp index aface68e45d3d..65204f8f22ca2 100644 --- a/src/ranged.cpp +++ b/src/ranged.cpp @@ -1959,7 +1959,8 @@ double Character::gun_value( const item &weap, int ammo ) const double gun_value = damage_and_accuracy * capacity_factor; - add_msg_debug( "%s as gun: %.1f total, %.1f dispersion, %.1f damage, %.1f capacity", + add_msg_debug( debugmode::DF_RANGED, + "%s as gun: %.1f total, %.1f dispersion, %.1f damage, %.1f capacity", weap.type->get_id().str(), gun_value, dispersion_factor, damage_factor, capacity_factor ); return std::max( 0.0, gun_value ); diff --git a/src/sdlsound.cpp b/src/sdlsound.cpp index d083b41872123..a2252967b746c 100644 --- a/src/sdlsound.cpp +++ b/src/sdlsound.cpp @@ -465,7 +465,7 @@ void sfx::play_variant_sound( const std::string &id, const std::string &variant, return; } - add_msg_debug( "sound id: %s, variant: %s, volume: %d ", id, variant, volume ); + add_msg_debug( debugmode::DF_SOUND, "sound id: %s, variant: %s, volume: %d ", id, variant, volume ); if( !check_sound( volume ) ) { return; @@ -495,7 +495,7 @@ void sfx::play_variant_sound( const std::string &id, const std::string &variant, return; } - add_msg_debug( "sound id: %s, variant: %s, volume: %d ", id, variant, volume ); + add_msg_debug( debugmode::DF_SOUND, "sound id: %s, variant: %s, volume: %d ", id, variant, volume ); if( !check_sound( volume ) ) { return; diff --git a/src/sounds.cpp b/src/sounds.cpp index 7c09a08e2301b..ee233bd5fca42 100644 --- a/src/sounds.cpp +++ b/src/sounds.cpp @@ -290,7 +290,8 @@ static int get_signal_for_hordes( const centroid ¢r ) sig_power = std::max( sig_power, min_sig_cap ); //Capping extremely high signal to hordes sig_power = std::min( sig_power, max_sig_cap ); - add_msg_debug( "vol %d vol_hordes %d sig_power %d ", vol, vol_hordes, sig_power ); + add_msg_debug( debugmode::DF_SOUND, "vol %d vol_hordes %d sig_power %d ", vol, vol_hordes, + sig_power ); return sig_power; } return 0; @@ -681,7 +682,7 @@ void sfx::do_vehicle_engine_sfx() const Character &player_character = get_player_character(); if( !player_character.in_vehicle ) { fade_audio_channel( ch, 300 ); - add_msg_debug( "STOP interior_engine_sound, OUT OF CAR" ); + add_msg_debug( debugmode::DF_SOUND, "STOP interior_engine_sound, OUT OF CAR" ); return; } if( player_character.in_sleep_state() && !audio_muted ) { @@ -700,7 +701,7 @@ void sfx::do_vehicle_engine_sfx() } if( !veh->engine_on ) { fade_audio_channel( ch, 100 ); - add_msg_debug( "STOP interior_engine_sound" ); + add_msg_debug( debugmode::DF_SOUND, "STOP interior_engine_sound" ); return; } @@ -727,9 +728,9 @@ void sfx::do_vehicle_engine_sfx() if( !is_channel_playing( ch ) ) { play_ambient_variant_sound( id_and_variant.first, id_and_variant.second, sfx::get_heard_volume( player_character.pos() ), ch, 1000 ); - add_msg_debug( "START %s %s", id_and_variant.first, id_and_variant.second ); + add_msg_debug( debugmode::DF_SOUND, "START %s %s", id_and_variant.first, id_and_variant.second ); } else { - add_msg_debug( "PLAYING" ); + add_msg_debug( debugmode::DF_SOUND, "PLAYING" ); } int current_speed = veh->velocity; bool in_reverse = false; @@ -765,11 +766,11 @@ void sfx::do_vehicle_engine_sfx() if( current_gear > previous_gear ) { play_variant_sound( "vehicle", "gear_shift", get_heard_volume( player_character.pos() ), 0_degrees, 0.8, 0.8 ); - add_msg_debug( "GEAR UP" ); + add_msg_debug( debugmode::DF_SOUND, "GEAR UP" ); } else if( current_gear < previous_gear ) { play_variant_sound( "vehicle", "gear_shift", get_heard_volume( player_character.pos() ), 0_degrees, 1.2, 1.2 ); - add_msg_debug( "GEAR DOWN" ); + add_msg_debug( debugmode::DF_SOUND, "GEAR DOWN" ); } if( ( safe_speed != 0 ) ) { if( current_gear == 0 ) { @@ -786,10 +787,10 @@ void sfx::do_vehicle_engine_sfx() if( current_speed != previous_speed ) { Mix_HaltChannel( static_cast( ch ) ); - add_msg_debug( "STOP speed %d =/= %d", current_speed, previous_speed ); + add_msg_debug( debugmode::DF_SOUND, "STOP speed %d =/= %d", current_speed, previous_speed ); play_ambient_variant_sound( id_and_variant.first, id_and_variant.second, sfx::get_heard_volume( player_character.pos() ), ch, 1000, pitch ); - add_msg_debug( "PITCH %f", pitch ); + add_msg_debug( debugmode::DF_SOUND, "PITCH %f", pitch ); } previous_speed = current_speed; previous_gear = current_gear; @@ -807,7 +808,7 @@ void sfx::do_vehicle_exterior_engine_sfx() // early bail-outs for efficiency if( player_character.in_vehicle ) { fade_audio_channel( ch, 300 ); - add_msg_debug( "STOP exterior_engine_sound, IN CAR" ); + add_msg_debug( debugmode::DF_SOUND, "STOP exterior_engine_sound, IN CAR" ); return; } if( player_character.in_sleep_state() && !audio_muted ) { @@ -835,7 +836,7 @@ void sfx::do_vehicle_exterior_engine_sfx() } if( !noise_factor || !veh ) { fade_audio_channel( ch, 300 ); - add_msg_debug( "STOP exterior_engine_sound, NO NOISE" ); + add_msg_debug( debugmode::DF_SOUND, "STOP exterior_engine_sound, NO NOISE" ); return; } @@ -864,26 +865,29 @@ void sfx::do_vehicle_exterior_engine_sfx() if( engine_external_id_and_variant == id_and_variant ) { Mix_SetPosition( ch_int, to_degrees( get_heard_angle( veh->global_pos3() ) ), 0 ); set_channel_volume( ch, vol ); - add_msg_debug( "PLAYING exterior_engine_sound, vol: ex:%d true:%d", vol, Mix_Volume( ch_int, - -1 ) ); + add_msg_debug( debugmode::DF_SOUND, "PLAYING exterior_engine_sound, vol: ex:%d true:%d", vol, + Mix_Volume( ch_int, + -1 ) ); } else { engine_external_id_and_variant = id_and_variant; Mix_HaltChannel( ch_int ); - add_msg_debug( "STOP exterior_engine_sound, change id/var" ); + add_msg_debug( debugmode::DF_SOUND, "STOP exterior_engine_sound, change id/var" ); play_ambient_variant_sound( id_and_variant.first, id_and_variant.second, 128, ch, 0 ); Mix_SetPosition( ch_int, to_degrees( get_heard_angle( veh->global_pos3() ) ), 0 ); set_channel_volume( ch, vol ); - add_msg_debug( "START exterior_engine_sound %s %s vol: %d", id_and_variant.first, + add_msg_debug( debugmode::DF_SOUND, "START exterior_engine_sound %s %s vol: %d", + id_and_variant.first, id_and_variant.second, Mix_Volume( ch_int, -1 ) ); } } else { play_ambient_variant_sound( id_and_variant.first, id_and_variant.second, 128, ch, 0 ); - add_msg_debug( "Vol: %d %d", vol, Mix_Volume( ch_int, -1 ) ); + add_msg_debug( debugmode::DF_SOUND, "Vol: %d %d", vol, Mix_Volume( ch_int, -1 ) ); Mix_SetPosition( ch_int, to_degrees( get_heard_angle( veh->global_pos3() ) ), 0 ); - add_msg_debug( "Vol: %d %d", vol, Mix_Volume( ch_int, -1 ) ); + add_msg_debug( debugmode::DF_SOUND, "Vol: %d %d", vol, Mix_Volume( ch_int, -1 ) ); set_channel_volume( ch, vol ); - add_msg_debug( "START exterior_engine_sound NEW %s %s vol: ex:%d true:%d", id_and_variant.first, + add_msg_debug( debugmode::DF_SOUND, "START exterior_engine_sound NEW %s %s vol: ex:%d true:%d", + id_and_variant.first, id_and_variant.second, vol, Mix_Volume( ch_int, -1 ) ); } } diff --git a/src/suffer.cpp b/src/suffer.cpp index 8731701f326c8..6af3cbb4763ce 100644 --- a/src/suffer.cpp +++ b/src/suffer.cpp @@ -1702,7 +1702,7 @@ void Character::mend( int rate_multiplier ) needs_splint = false; } - add_msg_debug( "Limb mend healing factor: %.2f", healing_factor ); + add_msg_debug( debugmode::DF_CHAR_HEALTH, "Limb mend healing factor: %.2f", healing_factor ); if( healing_factor <= 0.0f ) { // The section below assumes positive healing rate return; @@ -1951,7 +1951,7 @@ void Character::add_addiction( add_type type, int strength ) i.intensity++; } - add_msg_debug( "Updating addiction: %d intensity, %d sated", + add_msg_debug( debugmode::DF_CHAR_HEALTH, "Updating addiction: %d intensity, %d sated", i.intensity, to_turns( i.sated ) ); return; @@ -1959,10 +1959,10 @@ void Character::add_addiction( add_type type, int strength ) // Add a new addiction const int roll = rng( 0, 100 ); - add_msg_debug( "Addiction: roll %d vs strength %d", roll, strength ); + add_msg_debug( debugmode::DF_CHAR_HEALTH, "Addiction: roll %d vs strength %d", roll, strength ); if( roll < strength ) { const std::string &type_name = addiction_type_name( type ); - add_msg_debug( "%s got addicted to %s", disp_name(), type_name ); + add_msg_debug( debugmode::DF_CHAR_HEALTH, "%s got addicted to %s", disp_name(), type_name ); addictions.emplace_back( type, 1 ); get_event_bus().send( getID(), type ); } diff --git a/src/talker_avatar.cpp b/src/talker_avatar.cpp index 3dd0706c37dd0..e43ca0e9c7e3c 100644 --- a/src/talker_avatar.cpp +++ b/src/talker_avatar.cpp @@ -76,7 +76,7 @@ void talker_avatar::buy_monster( talker &seller, const mtype_id &mtype, int cost for( int i = 0; i < count; i++ ) { monster *const mon_ptr = g->place_critter_around( mtype, me_chr->pos(), 3 ); if( !mon_ptr ) { - add_msg_debug( "Cannot place u_buy_monster, no valid placement locations." ); + add_msg_debug( debugmode::DF_TALKER, "Cannot place u_buy_monster, no valid placement locations." ); break; } monster &tmp = *mon_ptr; diff --git a/src/talker_npc.cpp b/src/talker_npc.cpp index a1e107f65761b..0e065a909b4c2 100644 --- a/src/talker_npc.cpp +++ b/src/talker_npc.cpp @@ -515,9 +515,9 @@ std::string talker_npc::give_item_to( const bool to_use ) int new_ammo = me_npc->ammo_count_for( given ); const double new_weapon_value = me_npc->weapon_value( given, new_ammo ); const double cur_weapon_value = me_npc->weapon_value( me_npc->weapon, our_ammo ); - add_msg_debug( "NPC evaluates own %s (%d ammo): %0.1f", + add_msg_debug( debugmode::DF_TALKER, "NPC evaluates own %s (%d ammo): %0.1f", me_npc->weapon.typeId().str(), our_ammo, cur_weapon_value ); - add_msg_debug( "NPC evaluates your %s (%d ammo): %0.1f", + add_msg_debug( debugmode::DF_TALKER, "NPC evaluates your %s (%d ammo): %0.1f", given.typeId().str(), new_ammo, new_weapon_value ); if( to_use ) { // Eating first, to avoid evaluating bread as a weapon diff --git a/src/vehicle.cpp b/src/vehicle.cpp index 09e5fb3b5bb9a..0063764704479 100644 --- a/src/vehicle.cpp +++ b/src/vehicle.cpp @@ -2095,7 +2095,7 @@ bool vehicle::remove_carried_vehicle( const std::vector &carried_parts ) map &here = get_map(); vehicle *new_vehicle = here.add_vehicle( vproto_id( "none" ), new_pos3, new_dir ); if( new_vehicle == nullptr ) { - add_msg_debug( "Unable to unload bike rack, host face %d, new_dir %d!", + add_msg_debug( debugmode::DF_VEHICLE, "Unable to unload bike rack, host face %d, new_dir %d!", to_degrees( face.dir() ), to_degrees( new_dir ) ); return false; } @@ -3560,7 +3560,7 @@ int vehicle::ground_acceleration( const bool fueled, int at_vel_in_vmi ) const } int engine_power_ratio = total_power_w( fueled ) / weight; int accel_at_vel = 100 * 100 * engine_power_ratio / cmps; - add_msg_debug( "%s: accel at %d vimph is %d", name, target_vmiph, + add_msg_debug( debugmode::DF_VEHICLE, "%s: accel at %d vimph is %d", name, target_vmiph, cmps_to_vmiph( accel_at_vel ) ); return cmps_to_vmiph( accel_at_vel ); } @@ -3592,7 +3592,7 @@ int vehicle::water_acceleration( const bool fueled, int at_vel_in_vmi ) const } int engine_power_ratio = total_power_w( fueled ) / weight; int accel_at_vel = 100 * 100 * engine_power_ratio / cmps; - add_msg_debug( "%s: water accel at %d vimph is %d", name, target_vmiph, + add_msg_debug( debugmode::DF_VEHICLE, "%s: water accel at %d vimph is %d", name, target_vmiph, cmps_to_vmiph( accel_at_vel ) ); return cmps_to_vmiph( accel_at_vel ); } @@ -3678,7 +3678,8 @@ int vehicle::max_ground_velocity( const bool fueled ) const double max_in_mps = simple_cubic_solution( coeff_air_drag(), c_rolling_drag, c_rolling_drag * vehicles::rolling_constant_to_variable, -total_engine_w ); - add_msg_debug( "%s: power %d, c_air %3.2f, c_rolling %3.2f, max_in_mps %3.2f", + add_msg_debug( debugmode::DF_VEHICLE, + "%s: power %d, c_air %3.2f, c_rolling %3.2f, max_in_mps %3.2f", name, total_engine_w, coeff_air_drag(), c_rolling_drag, max_in_mps ); return mps_to_vmiph( max_in_mps ); } @@ -3698,7 +3699,8 @@ int vehicle::max_water_velocity( const bool fueled ) const int total_engine_w = total_power_w( fueled ); double total_drag = coeff_water_drag() + coeff_air_drag(); double max_in_mps = std::cbrt( total_engine_w / total_drag ); - add_msg_debug( "%s: power %d, c_air %3.2f, c_water %3.2f, water max_in_mps %3.2f", + add_msg_debug( debugmode::DF_VEHICLE, + "%s: power %d, c_air %3.2f, c_water %3.2f, water max_in_mps %3.2f", name, total_engine_w, coeff_air_drag(), coeff_water_drag(), max_in_mps ); return mps_to_vmiph( max_in_mps ); } @@ -3888,7 +3890,7 @@ void vehicle::noise_and_smoke( int load, time_duration time ) lvl++; } } - add_msg_debug( "VEH NOISE final: %d", static_cast( noise ) ); + add_msg_debug( debugmode::DF_VEHICLE, "VEH NOISE final: %d", static_cast( noise ) ); vehicle_noise = static_cast( noise ); sounds::sound( global_pos3(), noise, sounds::sound_t::movement, _( is_rotorcraft() ? heli_noise : sounds[lvl].first ), true ); @@ -4027,7 +4029,10 @@ double vehicle::coeff_air_drag() const // tally the results of each row and prorate them relative to vehicle width for( drag_column &dc : drag ) { // even as m_debug you rarely want to see this - // add_msg_debug( "veh %: pro %d, hboard %d, fboard %d, shield %d, seat %d, roof %d, aisle %d, turret %d, panel %d, exposed %d, last %d\n", name, dc.pro, dc.hboard, dc.fboard, dc.shield, dc.seat, dc.roof, dc.aisle, dc.turret, dc.panel, dc.exposed, dc.last ); + add_msg_debug( debugmode::DF_VEHICLE_DRAG, + "veh %: pro %d, hboard %d, fboard %d, shield %d, seat %d, roof %d, aisle %d, turret %d, panel %d, exposed %d, last %d\n", + name, dc.pro, dc.hboard, dc.fboard, dc.shield, dc.seat, dc.roof, dc.aisle, dc.turret, dc.panel, + dc.exposed, dc.last ); double c_air_drag_c = c_air_base; // rams in front of the vehicle mildly worsens air drag @@ -4077,7 +4082,8 @@ double vehicle::coeff_air_drag() const height /= width; c_air_drag /= width; double cross_area = height * tile_to_width( width ); - add_msg_debug( "%s: height %3.2fm, width %3.2fm (%d tiles), c_air %3.2f\n", name, height, + add_msg_debug( debugmode::DF_VEHICLE_DRAG, + "%s: height %3.2fm, width %3.2fm (%d tiles), c_air %3.2f\n", name, height, tile_to_width( width ), width, c_air_drag ); // F_air_drag = c_air_drag * cross_area * 1/2 * air_density * v^2 // coeff_air_resistance = c_air_drag * cross_area * 1/2 * air_density @@ -4162,9 +4168,9 @@ double vehicle::lift_thrust_of_rotorcraft( const bool fuelled, const bool safe ) // lift_thrust in lbthrust double lift_thrust = ( 8.8658 * std::pow( engine_power_in_hp / rotor_area_in_feet, -0.3107 ) ) * engine_power_in_hp; - add_msg_debug( - "lift thrust in lbs of %s = %f, rotor area in feet : %d, engine power in hp %f, thrust in newtons : %f", - name, lift_thrust, rotor_area_in_feet, engine_power_in_hp, engine_power_in_hp * 4.45 ); + add_msg_debug( debugmode::DF_VEHICLE, + "lift thrust in lbs of %s = %f, rotor area in feet : %d, engine power in hp %f, thrust in newtons : %f", + name, lift_thrust, rotor_area_in_feet, engine_power_in_hp, engine_power_in_hp * 4.45 ); // convert to newtons. return lift_thrust * 4.45; } @@ -4319,7 +4325,7 @@ float vehicle::k_traction( float wheel_traction_area ) const } const float mass_penalty = fraction_without_traction * to_kilogram( total_mass() ); float traction = std::min( 1.0f, wheel_traction_area / mass_penalty ); - add_msg_debug( "%s has traction %.2f", name, traction ); + add_msg_debug( debugmode::DF_VEHICLE, "%s has traction %.2f", name, traction ); // For now make it easy until it gets properly balanced: add a low cap of 0.1 return std::max( 0.1f, traction ); @@ -4684,9 +4690,9 @@ void vehicle::consume_fuel( int load, bool idling ) player_character.mod_fatigue( 1 ); } player_character.mod_stamina( -( base_burn + mod ) ); - add_msg_debug( "Load: %d", load ); - add_msg_debug( "Mod: %d", mod ); - add_msg_debug( "Burn: %d", -( base_burn + mod ) ); + add_msg_debug( debugmode::DF_VEHICLE, "Load: %d", load ); + add_msg_debug( debugmode::DF_VEHICLE, "Mod: %d", mod ); + add_msg_debug( debugmode::DF_VEHICLE, "Burn: %d", -( base_burn + mod ) ); } } @@ -5057,7 +5063,7 @@ int vehicle::traverse_vehicle_graph( Vehicle *start_veh, int amount, Func action visited_vehs.insert( current_veh ); connected_vehs.pop(); - add_msg_debug( "Traversing graph with %d power", amount ); + add_msg_debug( debugmode::DF_VEHICLE, "Traversing graph with %d power", amount ); for( int p : current_veh->loose_parts ) { if( !current_veh->part_info( p ).has_flag( "POWER_TRANSFER" ) ) { @@ -5078,11 +5084,13 @@ int vehicle::traverse_vehicle_graph( Vehicle *start_veh, int amount, Func action connected_vehs.push( std::make_pair( target_veh, target_loss ) ); float loss_amount = ( static_cast( amount ) * static_cast( target_loss ) ) / 100.0f; - add_msg_debug( "Visiting remote %p with %d power (loss %f, which is %d percent)", + add_msg_debug( debugmode::DF_VEHICLE, + "Visiting remote %p with %d power (loss %f, which is %d percent)", static_cast( target_veh ), amount, loss_amount, target_loss ); amount = action( target_veh, amount, static_cast( loss_amount ) ); - add_msg_debug( "After remote %p, %d power", static_cast( target_veh ), amount ); + add_msg_debug( debugmode::DF_VEHICLE, "After remote %p, %d power", + static_cast( target_veh ), amount ); if( amount < 1 ) { break; // No more charge to donate away. @@ -5122,7 +5130,7 @@ int vehicle::charge_battery( int amount, bool include_other_vehicles ) } auto charge_visitor = []( vehicle * veh, int amount, int lost ) { - add_msg_debug( "CH: %d", amount - lost ); + add_msg_debug( debugmode::DF_VEHICLE, "CH: %d", amount - lost ); return veh->charge_battery( amount - lost, false ); }; @@ -5159,7 +5167,7 @@ int vehicle::discharge_battery( int amount, bool recurse ) } auto discharge_visitor = []( vehicle * veh, int amount, int lost ) { - add_msg_debug( "CH: %d", amount + lost ); + add_msg_debug( debugmode::DF_VEHICLE, "CH: %d", amount + lost ); return veh->discharge_battery( amount + lost, false ); }; if( amount > 0 && recurse ) { // need more power! @@ -7049,7 +7057,7 @@ void vehicle::update_time( const time_point &update_to ) double intensity = accum_weather.sunlight / default_daylight_level() / to_turns( elapsed ); int energy_bat = power_to_energy_bat( epower_w * intensity, elapsed ); if( energy_bat > 0 ) { - add_msg_debug( "%s got %d kJ energy from solar panels", name, energy_bat ); + add_msg_debug( debugmode::DF_VEHICLE, "%s got %d kJ energy from solar panels", name, energy_bat ); charge_battery( energy_bat ); } } @@ -7059,7 +7067,7 @@ void vehicle::update_time( const time_point &update_to ) int epower_w = total_wind_epower_w(); int energy_bat = power_to_energy_bat( epower_w, elapsed ); if( energy_bat > 0 ) { - add_msg_debug( "%s got %d kJ energy from wind turbines", name, energy_bat ); + add_msg_debug( debugmode::DF_VEHICLE, "%s got %d kJ energy from wind turbines", name, energy_bat ); charge_battery( energy_bat ); } } @@ -7067,7 +7075,7 @@ void vehicle::update_time( const time_point &update_to ) int epower_w = total_water_wheel_epower_w(); int energy_bat = power_to_energy_bat( epower_w, elapsed ); if( energy_bat > 0 ) { - add_msg_debug( "%s got %d kJ energy from water wheels", name, energy_bat ); + add_msg_debug( debugmode::DF_VEHICLE, "%s got %d kJ energy from water wheels", name, energy_bat ); charge_battery( energy_bat ); } } diff --git a/src/vehicle_move.cpp b/src/vehicle_move.cpp index fa8839d6a87fb..2db0620d7e6bc 100644 --- a/src/vehicle_move.cpp +++ b/src/vehicle_move.cpp @@ -110,7 +110,8 @@ int vehicle::slowdown( int at_velocity ) const if( slowdown < 0 ) { debugmsg( "vehicle %s has negative drag slowdown %d\n", name, slowdown ); } - add_msg_debug( "%s at %d vimph, f_drag %3.2f, drag accel %d vmiph - extra drag %d", + add_msg_debug( debugmode::DF_VEHICLE_MOVE, + "%s at %d vimph, f_drag %3.2f, drag accel %d vmiph - extra drag %d", name, at_velocity, f_total_drag, slowdown, static_drag() ); // plows slow rolling vehicles, but not falling or floating vehicles if( !( is_falling || is_floating || is_flying ) ) { @@ -374,7 +375,7 @@ void vehicle::smart_controller_handle_turn( bool thrusting, smart_controller_state = cur_state; if( player_in_control( player_character ) ) { - add_msg_debug( _( "Smart controller optimizes engine state." ) ); + add_msg_debug( debugmode::DF_VEHICLE_MOVE, _( "Smart controller optimizes engine state." ) ); } } } else { @@ -744,7 +745,7 @@ bool vehicle::collision( std::vector &colls, colls.push_back( fake_coll ); velocity = 0; vertical_velocity = 0; - add_msg_debug( "Collision check on a dirty vehicle %s", name ); + add_msg_debug( debugmode::DF_VEHICLE_MOVE, "Collision check on a dirty vehicle %s", name ); return true; } @@ -971,7 +972,7 @@ veh_collision vehicle::part_collision( int part, const tripoint &p, continue; } - add_msg_debug( "Deformation energy: %.2f", d_E ); + add_msg_debug( debugmode::DF_VEHICLE_MOVE, "Deformation energy: %.2f", d_E ); // Damage calculation // Damage dealt overall dmg += d_E / 400; @@ -979,7 +980,7 @@ veh_collision vehicle::part_collision( int part, const tripoint &p, // Always if no critters, otherwise if critter is real if( critter == nullptr || !critter->is_hallucination() ) { part_dmg = dmg * k / 100.0f; - add_msg_debug( "Part collision damage: %.2f", part_dmg ); + add_msg_debug( debugmode::DF_VEHICLE_MOVE, "Part collision damage: %.2f", part_dmg ); } // Damage for object const float obj_dmg = dmg * ( 100.0f - k ) / 100.0f; @@ -1038,7 +1039,7 @@ veh_collision vehicle::part_collision( int part, const tripoint &p, critter->get_armor_bash( bodypart_id( "torso" ) ); dam = std::max( 0, dam - armor ); critter->apply_damage( driver, bodypart_id( "torso" ), dam ); - add_msg_debug( "Critter collision damage: %d", dam ); + add_msg_debug( debugmode::DF_VEHICLE_MOVE, "Critter collision damage: %d", dam ); } // Don't fling if vertical - critter got smashed into the ground diff --git a/tests/fake_messages.cpp b/tests/fake_messages.cpp index f38fd46c4ba49..1a5d41906a067 100644 --- a/tests/fake_messages.cpp +++ b/tests/fake_messages.cpp @@ -36,6 +36,11 @@ void Messages::add_msg( const game_message_params &, std::string m ) { add_msg( m ); } +void Messages::add_msg_debug( debugmode::debug_filter, std::string m ) +{ + // cata_test does not need filters + add_msg( m ); +} void Messages::clear_messages() { messages.clear(); @@ -62,6 +67,10 @@ void add_msg( const game_message_params &, std::string m ) { Messages::add_msg( m ); } +void add_msg_debug( debugmode::debug_filter, std::string m ) +{ + Messages::add_msg( m ); +} void add_msg_if_player_sees( const tripoint &, std::string m ) { Messages::add_msg( m ); @@ -78,3 +87,13 @@ void add_msg_if_player_sees( const Creature &, const game_message_params &, std: { Messages::add_msg( m ); } +void add_msg_debug_if_player_sees( const tripoint &, debugmode::debug_filter, + std::string m ) +{ + Messages::add_msg( m ); +} +void add_msg_debug_if_player_sees( const Creature &, debugmode::debug_filter, + std::string m ) +{ + Messages::add_msg( m ); +} From 8c1157897c70ca34f4e9e87f7ee51f36c960de39 Mon Sep 17 00:00:00 2001 From: Xenomorph-III Date: Thu, 25 Mar 2021 20:20:04 +1300 Subject: [PATCH 310/453] Give the sports drink positive enjoyment value (#47617) --- data/json/items/comestibles/drink.json | 11 ++++++----- tests/food_fun_for_test.cpp | 22 +++++++++++----------- 2 files changed, 17 insertions(+), 16 deletions(-) diff --git a/data/json/items/comestibles/drink.json b/data/json/items/comestibles/drink.json index cf5f49f876cf7..0a0bc595b8a42 100644 --- a/data/json/items/comestibles/drink.json +++ b/data/json/items/comestibles/drink.json @@ -949,14 +949,14 @@ "symbol": "~", "quench": 60, "calories": 66, - "description": "Consisting of a special blend of electrolytes and simple sugars, this beverage tastes like bottled sweat but rehydrates the body faster than water.", + "description": "A flavoured drink consisting of a special blend of electrolytes and simple sugars. It tastes vaguely like fruit with a slight chemical aftertaste.", "price": 55, "price_postapoc": 50, - "material": [ "water" ], + "material": [ "water", "junk" ], "volume": "250 ml", "phase": "liquid", "flags": [ "EATEN_COLD" ], - "fun": -1, + "fun": 1, "vitamins": [ [ "vitC", 1 ] ] }, { @@ -991,14 +991,15 @@ "symbol": "~", "quench": 60, "calories": 12, - "description": "A basic oral rehydration therapy drink. It will rehydrate you faster than water, but it tastes kind of strange.", + "description": "A basic oral rehydration therapy drink. It will rehydrate you faster than water, but tastes like bottled sweat.", "price": 55, "price_postapoc": 50, "material": [ "water" ], + "flags": [ "EATEN_COLD" ], "volume": "250 ml", "looks_like": "sports_drink", "phase": "liquid", - "fun": -2 + "fun": -1 }, { "type": "COMESTIBLE", diff --git a/tests/food_fun_for_test.cpp b/tests/food_fun_for_test.cpp index c1673a0a6ce8d..9a8b861cb8926 100644 --- a/tests/food_fun_for_test.cpp +++ b/tests/food_fun_for_test.cpp @@ -142,29 +142,29 @@ TEST_CASE( "fun for cold food", "[fun_for][food][cold]" ) } GIVEN( "food that tastes bad, but better when cold" ) { - item sports( "sports_drink" ); - REQUIRE( sports.is_comestible() ); - int sports_fun = sports.get_comestible_fun(); + item rehydration( "rehydration_drink" ); + REQUIRE( rehydration.is_comestible() ); + int rehydration_fun = rehydration.get_comestible_fun(); - REQUIRE( sports_fun < 0 ); - REQUIRE( sports.has_flag( flag_EATEN_COLD ) ); + REQUIRE( rehydration_fun < 0 ); + REQUIRE( rehydration.has_flag( flag_EATEN_COLD ) ); WHEN( "it is cold" ) { - sports.set_flag( flag_COLD ); - REQUIRE( sports.has_flag( flag_COLD ) ); + rehydration.set_flag( flag_COLD ); + REQUIRE( rehydration.has_flag( flag_COLD ) ); THEN( "it doesn't taste bad" ) { - actual_fun = dummy.fun_for( sports ); + actual_fun = dummy.fun_for( rehydration ); CHECK( actual_fun.first > 0 ); } } WHEN( "it is not cold" ) { - REQUIRE_FALSE( sports.has_flag( flag_COLD ) ); + REQUIRE_FALSE( rehydration.has_flag( flag_COLD ) ); THEN( "it tastes as bad as usual" ) { - actual_fun = dummy.fun_for( sports ); - CHECK( actual_fun.first == sports_fun ); + actual_fun = dummy.fun_for( rehydration ); + CHECK( actual_fun.first == rehydration_fun ); } } } From 104d8c7dd2d77b19289f8c598c75747ecce03d11 Mon Sep 17 00:00:00 2001 From: Jamuro-g <76928284+Jamuro-g@users.noreply.github.com> Date: Thu, 25 Mar 2021 08:20:37 +0100 Subject: [PATCH 311/453] fix color coding of container stat summary (#47409) --- src/item.cpp | 14 ++++++++++---- src/item.h | 4 ++-- src/item_contents.cpp | 6 +++--- src/item_pocket.cpp | 6 +++--- 4 files changed, 18 insertions(+), 12 deletions(-) diff --git a/src/item.cpp b/src/item.cpp index 4edfbca3b29c7..391b68f5b27b2 100644 --- a/src/item.cpp +++ b/src/item.cpp @@ -9152,9 +9152,12 @@ iteminfo::iteminfo( const std::string &Type, const std::string &Name, double Val } iteminfo vol_to_info( const std::string &type, const std::string &left, - const units::volume &vol, int decimal_places ) + const units::volume &vol, int decimal_places, bool lower_is_better ) { - iteminfo::flags f = iteminfo::lower_is_better | iteminfo::no_newline; + iteminfo::flags f = iteminfo::no_newline; + if( lower_is_better ) { + f |= iteminfo::lower_is_better; + } int converted_volume_scale = 0; const double converted_volume = round_up( convert_volume( vol.value(), &converted_volume_scale ), decimal_places ); @@ -9166,9 +9169,12 @@ iteminfo vol_to_info( const std::string &type, const std::string &left, } iteminfo weight_to_info( const std::string &type, const std::string &left, - const units::mass &weight, int /* decimal_places */ ) + const units::mass &weight, int /* decimal_places */, bool lower_is_better ) { - iteminfo::flags f = iteminfo::lower_is_better | iteminfo::no_newline; + iteminfo::flags f = iteminfo::no_newline; + if( lower_is_better ) { + f |= iteminfo::lower_is_better; + } const double converted_weight = convert_weight( weight ); f |= iteminfo::is_decimal; return iteminfo( type, left, string_format( " %s", weight_units() ), f, diff --git a/src/item.h b/src/item.h index b0860f2b93334..368995927189b 100644 --- a/src/item.h +++ b/src/item.h @@ -166,9 +166,9 @@ struct enum_traits { }; iteminfo vol_to_info( const std::string &type, const std::string &left, - const units::volume &vol, int decimal_places = 2 ); + const units::volume &vol, int decimal_places = 2, bool lower_is_better = true ); iteminfo weight_to_info( const std::string &type, const std::string &left, - const units::mass &weight, int decimal_places = 2 ); + const units::mass &weight, int decimal_places = 2, bool lower_is_better = true ); inline bool is_crafting_component( const item &component ); diff --git a/src/item_contents.cpp b/src/item_contents.cpp index e9b93f6fae5ca..23cd9a86aac0c 100644 --- a/src/item_contents.cpp +++ b/src/item_contents.cpp @@ -1581,9 +1581,9 @@ void item_contents::info( std::vector &info, const iteminfo_query *par if( found_pockets.size() > 1 || pocket_num[0] > 1 ) { insert_separation_line( info ); info.emplace_back( "CONTAINER", _( "Total capacity:" ) ); - info.push_back( vol_to_info( "CONTAINER", _( "Volume: " ), total_container_capacity() ) ); - info.push_back( weight_to_info( "CONTAINER", _( " Weight: " ), - total_container_weight_capacity() ) ); + info.push_back( vol_to_info( "CONTAINER", _( "Volume: " ), total_container_capacity(), 2, false ) ); + info.push_back( weight_to_info( "CONTAINER", _( " Weight: " ), total_container_weight_capacity(), + 2, false ) ); info.back().bNewLine = true; } diff --git a/src/item_pocket.cpp b/src/item_pocket.cpp index 2ac13bc398231..e24dcdf436702 100644 --- a/src/item_pocket.cpp +++ b/src/item_pocket.cpp @@ -836,8 +836,8 @@ void item_pocket::general_info( std::vector &info, int pocket_number, // Show volume/weight for normal containers, or ammo capacity if ammo_restriction is defined if( data->ammo_restriction.empty() ) { - info.push_back( vol_to_info( "CONTAINER", _( "Volume: " ), volume_capacity() ) ); - info.push_back( weight_to_info( "CONTAINER", _( " Weight: " ), weight_capacity() ) ); + info.push_back( vol_to_info( "CONTAINER", _( "Volume: " ), volume_capacity(), 2, false ) ); + info.push_back( weight_to_info( "CONTAINER", _( " Weight: " ), weight_capacity(), 2, false ) ); info.back().bNewLine = true; } else { for( const ammotype &at : ammo_types() ) { @@ -853,7 +853,7 @@ void item_pocket::general_info( std::vector &info, int pocket_number, info.back().bNewLine = true; info.push_back( iteminfo( "BASE", _( "Maximum item length: " ), string_format( " %s", length_units( data->max_item_length ) ), - iteminfo::lower_is_better, + iteminfo::no_flags, convert_length( data->max_item_length ) ) ); } From 0b091cba3302aa47236dc05d68e308f52f30a7bf Mon Sep 17 00:00:00 2001 From: Jamuro-g <76928284+Jamuro-g@users.noreply.github.com> Date: Thu, 25 Mar 2021 08:21:39 +0100 Subject: [PATCH 312/453] fixed power armor ui (#47475) --- data/mods/TEST_DATA/items.json | 15 ++ src/item.cpp | 242 +++++++++++++++++++-------------- src/item.h | 2 + tests/iteminfo_test.cpp | 5 +- 4 files changed, 157 insertions(+), 107 deletions(-) diff --git a/data/mods/TEST_DATA/items.json b/data/mods/TEST_DATA/items.json index 9e5e5c6b47de8..7e21a5bbb649c 100644 --- a/data/mods/TEST_DATA/items.json +++ b/data/mods/TEST_DATA/items.json @@ -1448,8 +1448,23 @@ "power_armor": true, "material_thickness": 14, "environmental_protection": 16, + "use_action": { "type": "transform", "msg": "The %s engages.", "target": "test_power_armor_on", "active": true }, "flags": [ "WATERPROOF", "STURDY", "ELECTRIC_IMMUNE" ] }, + { + "id": "test_power_armor_on", + "copy-from": "test_power_armor", + "repairs_like": "test_power_armor", + "looks_like": "test_power_armor", + "type": "TOOL_ARMOR", + "name": { "str": "test power armor (on)" }, + "description": "This is a prototype power armor just for testing.", + "flags": [ "USE_UPS", "WATERPROOF", "STURDY", "ELECTRIC_IMMUNE", "TRADER_AVOID", "CLIMATE_CONTROL" ], + "power_draw": 4000000, + "revert_to": "test_power_armor", + "use_action": { "type": "transform", "menu_text": "Turn off", "msg": "The %s armor disengages.", "target": "test_power_armor" }, + "covers": [ "torso", "arm_l", "arm_r", "hand_l", "hand_r", "leg_l", "leg_r", "foot_l", "foot_r" ] + }, { "id": "test_meower_armor", "type": "PET_ARMOR", diff --git a/src/item.cpp b/src/item.cpp index 391b68f5b27b2..ffefcfaa8c2a8 100644 --- a/src/item.cpp +++ b/src/item.cpp @@ -2646,6 +2646,119 @@ void item::gunmod_info( std::vector &info, const iteminfo_query *parts } } +void item::armor_encumbrance_info( std::vector &info, int reduce_encumbrance_by ) const +{ + std::string format; + const std::string space = " "; + Character &player_character = get_player_character(); + const bool sizing_matters = get_sizing( player_character ) != sizing::ignore; + + if( has_flag( flag_FIT ) ) { + format = _( " (fits)" ); + } else if( has_flag( flag_VARSIZE ) && sizing_matters ) { + format = _( " (poor fit)" ); + } + if( sizing_matters ) { + const sizing sizing_level = get_sizing( player_character ); + //If we have the wrong size, we do not fit so alert the player + if( sizing_level == sizing::human_sized_small_char ) { + format = _( " (too big)" ); + } else if( sizing_level == sizing::big_sized_small_char ) { + format = _( " (huge!)" ); + } else if( sizing_level == sizing::small_sized_human_char || + sizing_level == sizing::human_sized_big_char ) { + format = _( " (too small)" ); + } else if( sizing_level == sizing::small_sized_big_char ) { + format = _( " (tiny!)" ); + } + } + + info.push_back( iteminfo( "ARMOR", _( "Encumbrance:" ) + format ) ); + + if( const islot_armor *t = find_armor_data() ) { + if( !t->data.empty() ) { + struct armor_portion_type { + int encumber = 0; + int max_encumber = 0; + int coverage = 0; + + bool operator==( const armor_portion_type &other ) { + return encumber == other.encumber + && max_encumber == other.max_encumber + && coverage == other.coverage; + } + }; + struct body_part_display_info { + translation to_display; + armor_portion_type portion; + bool active = false; + }; + + std::map to_display_data; + + for( const armor_portion_data &piece : t->data ) { + if( piece.covers.has_value() ) { + for( const bodypart_str_id &covering_id : piece.covers.value() ) { + if( covering_id != bodypart_str_id::NULL_ID() ) { + to_display_data[covering_id] = { covering_id.obj().name_as_heading, { + std::max( 0, get_encumber( player_character, covering_id ) - reduce_encumbrance_by ), + std::max( 0, get_encumber( player_character, covering_id, encumber_flags::assume_full ) - reduce_encumbrance_by ), + piece.coverage + }, true + }; + } + } + } + } + // Handle things that use both sides to avoid showing L. Arm R. Arm etc when both are the same + if( !t->sided ) { + for( const armor_portion_data &piece : t->data ) { + for( const bodypart_str_id &bp : *piece.covers ) { + bodypart_str_id opposite = bp->opposite_part; + if( opposite != bp && covers( bp ) && covers( opposite ) + && to_display_data.at( bp ).portion == to_display_data.at( opposite ).portion + && to_display_data.at( opposite ).active ) { + to_display_data.at( opposite ).to_display = bp->name_as_heading_multiple; + to_display_data.at( bp ).active = false; + } + } + } + } + for( auto &piece : to_display_data ) { + if( t->sided ) { + const bodypart_str_id &covering_id = piece.first; + if( !covers( covering_id.id() ) ) { + continue; + } + } + if( piece.second.active ) { + info.push_back( iteminfo( "ARMOR", + string_format( _( "%s:" ), piece.second.to_display.translated() ) + space, "", + iteminfo::no_newline | iteminfo::lower_is_better, + piece.second.portion.encumber ) ); + + if( piece.second.portion.encumber != piece.second.portion.max_encumber ) { + info.push_back( iteminfo( "ARMOR", space + _( "When full:" ) + space, "", + iteminfo::no_newline | iteminfo::lower_is_better, + piece.second.portion.max_encumber ) ); + } + + info.push_back( iteminfo( "ARMOR", space + _( "Coverage:" ) + space, "", + iteminfo::no_flags, + piece.second.portion.coverage ) ); + } + } + } + } else if( is_gun() && has_flag( flag_IS_ARMOR ) ) { + //right now all eligible gunmods (shoulder_strap, belt_clip) have the is_armor flag and use the torso + info.push_back( iteminfo( "ARMOR", _( "Torso:" ) + space, "", + iteminfo::no_newline | iteminfo::lower_is_better, get_avg_encumber( get_avatar() ) ) ); + + info.push_back( iteminfo( "ARMOR", space + _( "Coverage:" ) + space, "", + iteminfo::no_flags, get_coverage( body_part_torso.id() ) ) ); + } +} + void item::armor_protection_info( std::vector &info, const iteminfo_query *parts, int /*batch*/, bool /*debug*/ ) const @@ -2697,7 +2810,6 @@ void item::armor_info( std::vector &info, const iteminfo_query *parts, return; } - Character &player_character = get_player_character(); const std::string space = " "; body_part_set covered_parts = get_covered_body_parts(); bool covers_anything = covered_parts.any(); @@ -2796,122 +2908,44 @@ void item::armor_info( std::vector &info, const iteminfo_query *parts, insert_separation_line( info ); - if( parts->test( iteminfo_parts::ARMOR_ENCUMBRANCE ) && covers_anything ) { - std::string format; - const bool sizing_matters = get_sizing( player_character ) != sizing::ignore; - if( has_flag( flag_FIT ) ) { - format = _( " (fits)" ); - } else if( has_flag( flag_VARSIZE ) && sizing_matters ) { - format = _( " (poor fit)" ); - } - if( sizing_matters ) { - const sizing sizing_level = get_sizing( player_character ); - //If we have the wrong size, we do not fit so alert the player - if( sizing_level == sizing::human_sized_small_char ) { - format = _( " (too big)" ); - } else if( sizing_level == sizing::big_sized_small_char ) { - format = _( " (huge!)" ); - } else if( sizing_level == sizing::small_sized_human_char || - sizing_level == sizing::human_sized_big_char ) { - format = _( " (too small)" ); - } else if( sizing_level == sizing::small_sized_big_char ) { - format = _( " (tiny!)" ); - } - } - - info.push_back( iteminfo( "ARMOR", _( "Encumbrance:" ) + format ) ); - - if( const islot_armor *t = find_armor_data() ) { - if( !t->data.empty() ) { - struct armor_portion_type { - int encumber = 0; - int max_encumber = 0; - int coverage = 0; - - bool operator==( const armor_portion_type &other ) { - return encumber == other.encumber - && max_encumber == other.max_encumber - && coverage == other.coverage; - } - }; - struct body_part_display_info { - translation to_display; - armor_portion_type portion; - bool active = false; - }; + if( covers_anything ) { + int power_armor_encumbrance_reduction = 40; + static const itype_id itype_rm13_armor( "rm13_armor" ); - std::map to_display_data; + if( ( is_power_armor() ) || type->get_id() == itype_rm13_armor ) { + item tmp = *this; - for( const armor_portion_data &piece : t->data ) { - if( piece.covers.has_value() ) { - for( const bodypart_str_id &covering_id : piece.covers.value() ) { - if( covering_id != bodypart_str_id::NULL_ID() ) { - to_display_data[covering_id] = { covering_id.obj().name_as_heading, { - get_encumber( player_character, covering_id ), - get_encumber( player_character, covering_id, encumber_flags::assume_full ), - piece.coverage - }, true - }; - } - } - } - } - // Handle things that use both sides to avoid showing L. Arm R. Arm etc when both are the same - if( !t->sided ) { - for( const armor_portion_data &piece : t->data ) { - for( const bodypart_str_id &bp : *piece.covers ) { - bodypart_str_id opposite = bp->opposite_part; - if( opposite != bp && covers( bp ) && covers( opposite ) - && to_display_data.at( bp ).portion == to_display_data.at( opposite ).portion - && to_display_data.at( opposite ).active ) { - to_display_data.at( opposite ).to_display = bp->name_as_heading_multiple; - to_display_data.at( bp ).active = false; - } - } - } + //no need to clutter the ui with inactive versions when the armor is already active + if( !active ) { + if( parts->test( iteminfo_parts::ARMOR_ENCUMBRANCE ) ) { + tmp.armor_encumbrance_info( info ); } - for( auto &piece : to_display_data ) { - if( t->sided ) { - const bodypart_str_id &covering_id = piece.first; - if( !covers( covering_id.id() ) ) { - continue; - } - } - if( piece.second.active ) { - info.push_back( iteminfo( "ARMOR", - string_format( _( "%s:" ), piece.second.to_display.translated() ) + space, "", - iteminfo::no_newline | iteminfo::lower_is_better, - piece.second.portion.encumber ) ); + tmp.armor_protection_info( info, parts, batch, debug ); - if( piece.second.portion.encumber != piece.second.portion.max_encumber ) { - info.push_back( iteminfo( "ARMOR", space + _( "When full:" ) + space, "", - iteminfo::no_newline | iteminfo::lower_is_better, - piece.second.portion.max_encumber ) ); - } + insert_separation_line( info ); + info.push_back( iteminfo( "ARMOR", _( "When active:" ) ) ); + tmp = tmp.convert( itype_id( tmp.typeId().str() + "_on" ) ); + } - info.push_back( iteminfo( "ARMOR", space + _( "Coverage:" ) + space, "", - iteminfo::no_flags, - piece.second.portion.coverage ) ); - } + if( parts->test( iteminfo_parts::ARMOR_ENCUMBRANCE ) ) { + if( type->get_id() == itype_rm13_armor ) { + tmp.armor_encumbrance_info( info ); + } else { + tmp.armor_encumbrance_info( info, power_armor_encumbrance_reduction ); } } - } else if( is_gun() && has_flag( flag_IS_ARMOR ) ) { - //right now all eligible gunmods (shoulder_strap, belt_clip) have the is_armor flag and use the torso - info.push_back( iteminfo( "ARMOR", _( "Torso:" ) + space, "", - iteminfo::no_newline | iteminfo::lower_is_better, get_avg_encumber( get_avatar() ) ) ); - - info.push_back( iteminfo( "ARMOR", space + _( "Coverage:" ) + space, "", - iteminfo::no_flags, get_coverage( body_part_torso.id() ) ) ); + tmp.armor_protection_info( info, parts, batch, debug ); + } else { + if( parts->test( iteminfo_parts::ARMOR_ENCUMBRANCE ) ) { + armor_encumbrance_info( info ); + } + armor_protection_info( info, parts, batch, debug ); } } // Whatever the last entry was, we want a newline at this point info.back().bNewLine = true; - if( covers_anything ) { - armor_protection_info( info, parts, batch, debug ); - } - const units::mass weight_bonus = get_weight_capacity_bonus(); const float weight_modif = get_weight_capacity_modifier(); if( weight_modif != 1 ) { diff --git a/src/item.h b/src/item.h index 368995927189b..f62a7a438f94d 100644 --- a/src/item.h +++ b/src/item.h @@ -2250,6 +2250,8 @@ class item : public visitable /** Helper for checking reloadability. **/ bool is_reloadable_helper( const itype_id &ammo, bool now ) const; + void armor_encumbrance_info( std::vector &info, int reduce_encumbrance_by = 0 ) const; + public: enum class sizing : int { human_sized_human_char = 0, diff --git a/tests/iteminfo_test.cpp b/tests/iteminfo_test.cpp index 50f65d312926c..9c56537dc2b6d 100644 --- a/tests/iteminfo_test.cpp +++ b/tests/iteminfo_test.cpp @@ -1041,9 +1041,8 @@ TEST_CASE( "armor fit and sizing", "[iteminfo][armor][fit]" ) "* This item can be worn on either side of the body.\n" ); item power_armor( "test_power_armor" ); - CHECK( item_info_str( power_armor, powerarmor ) == - "--\n" - "* This gear is a part of power armor.\n" ); + CHECK_THAT( item_info_str( power_armor, powerarmor ), + Catch::EndsWith( "* This gear is a part of power armor.\n" ) ); } static void expected_armor_values( const item &armor, float bash, float cut, float stab, From aa94817506ad052ebd2192e9bf3048e59bbbcd84 Mon Sep 17 00:00:00 2001 From: anothersimulacrum Date: Thu, 25 Mar 2021 00:23:40 -0700 Subject: [PATCH 313/453] Add gun variants, allowing to specify multiple guns with the same stat block (#46814) * Add gun variant support This allows genericizing our massive variety of very similar guns into one statblock, without removing the flavor. If a gun or magazine is specified to spawn without a variant, it will pick from the variants available to it, based on their assigned weight. Gun variants can specify an alternate name, description and ascii art for a gun, and variants can be toggled through an option. Add support for migrations to express variants. Add explicit extraction for magazines to handle variants. ASCII art for a variant will fall back to that of the base gun automatically if not specified or invalid. Maybe the naming could better express these are for both guns and magazines, but I think it is fine as is. item::gun_variant makes the assumption you check it has a variant first, so make sure to do that. Move the ammo at the end of gun names option to be next to the gun variant option. item::is_magazine doesn't tell us if type->magazine is safe to use, so !!type->magazine must be used instead of that before accessing type->magazine. * Add hacks to Archive::io to load/save gun variants I couldn't figure out how to specify the lambdas correctly, so I give up, this works. Problem is as follows: In item, I have ``` const gun_variant_data *_gun_variant; ... struct gun_variant_data { std::string id; // other info that doesn't matter } ``` I want to save this as `_gun_variant->id;`, and on load, load the string that was saved and call `item::set_gun_variant(loaded_string);`. This, and many variations of it don't work. ``` // In item:: scope const auto load = [this](const std::string &variant) { set_gun_variant( variant ); }; const auto save = [](const gun_variant_data *gv) { return gv->id; }; ``` Someone who know what's they're doing here may want to fix my laziness. * Add spawning support for gun variants Allow specifying variatns in item groups, mapgen (Item_group::add_item_entry), and in vehicles. * Add documentation for gun variants * Genericize NATO assault rifles Information lost: acr - 250ml barrel volume, folding stock m38dmr - 125 dispersion Move everything using an old rifle into the new generic rifles. The m38dmr is debatable, but I figure it's fine to be generic. Only m4a1s will spawn from unspecified variants at the moment, someone else can figure out what the proper chances should be. * Genericize other 5.56 assault rifles These ones are unique enough to not be simple variants of the NATO assault rifle, but they also don't need a full enumeration of stats. Move the brand-specific information to be a variant, genericize name and descriptions, and make all non-unique stats identical to those of the NATO assault rifle. I'm not sure of a good name for the sig generic version, but I want it to be distinct from the AUTO only or BURST only NATO rifles. * Genericize .45 ACP firearms There may be some consideration needed on collapsing the stat blocks for the pistols/smgs into a single one with copy-from, but this is simply the highest level genericization changes. --- .../monster_drops_lairs.json | 4 +- .../itemgroups/Weapons_Mods_Ammo/gunmod.json | 14 + .../itemgroups/Weapons_Mods_Ammo/guns.json | 27 +- data/json/itemgroups/defense_mode.json | 2 +- data/json/itemgroups/military.json | 32 +- data/json/items/gun/223.json | 425 ++++-------------- data/json/items/gun/308.json | 2 +- data/json/items/gun/45.json | 152 +++++-- data/json/items/magazine/45.json | 60 ++- data/json/items/migration.json | 64 ++- .../mapgen/military/mil_base/mil_base_z0.json | 30 +- data/json/martialarts.json | 11 +- data/json/npcs/NC_ARSONIST.json | 6 +- data/json/npcs/NC_SOLDIER.json | 4 +- .../NPC_scavenger_mercenary.json | 8 +- .../json/npcs/robofac/NPC_ROBOFAC_MERC_1.json | 8 +- data/json/professions.json | 34 +- data/json/recipes/recipe_deconstruction.json | 2 +- data/json/recipes/weapon/magazines.json | 13 +- data/json/recipes/weapon/mods.json | 4 +- data/json/vehicles/helicopters.json | 12 +- .../vehicleparts/blaze_turrets_vanilla.json | 44 +- .../Fuji_Mil_Prof/prof/itemgroups_prof.json | 2 +- .../firearms/gg_firearms_migration.json | 12 +- .../mods/National_Guard_Camp/item_groups.json | 8 +- .../bionic_professions.json | 3 +- doc/ITEM_SPAWN.md | 3 + doc/JSON_INFO.md | 9 + doc/MAPGEN.md | 1 + doc/VEHICLES_JSON.md | 2 + lang/extract_json_strings.py | 27 +- src/cata_io.h | 35 ++ src/item.cpp | 84 +++- src/item.h | 29 ++ src/item_factory.cpp | 25 ++ src/item_factory.h | 1 + src/item_group.cpp | 14 +- src/item_group.h | 8 +- src/itype.h | 14 + src/map.cpp | 7 +- src/map.h | 16 +- src/mapgen.cpp | 12 +- src/options.cpp | 14 +- src/savegame_json.cpp | 7 + src/veh_type.cpp | 8 +- src/veh_type.h | 2 + src/vehicle.cpp | 9 +- src/wish.cpp | 5 +- tests/pocket_test.cpp | 2 +- tests/reload_magazine_test.cpp | 2 +- 50 files changed, 781 insertions(+), 538 deletions(-) diff --git a/data/json/itemgroups/Monsters_Animals_Lairs/monster_drops_lairs.json b/data/json/itemgroups/Monsters_Animals_Lairs/monster_drops_lairs.json index b125fcf754d97..51ffb7422cfda 100644 --- a/data/json/itemgroups/Monsters_Animals_Lairs/monster_drops_lairs.json +++ b/data/json/itemgroups/Monsters_Animals_Lairs/monster_drops_lairs.json @@ -217,9 +217,9 @@ { "item": "savage_111f", "prob": 10 }, { "item": "ak47", "prob": 16 }, { "item": "ak74", "prob": 4 }, - { "item": "m4a1", "prob": 7 }, + { "item": "nato_assault_rifle", "variant": "m4a1", "prob": 7 }, { "item": "m16a4", "prob": 6 }, - { "item": "h&k416a5", "prob": 3 }, + { "item": "nato_assault_rifle", "variant": "h&k416a5", "prob": 3 }, { "item": "m1014", "prob": 1 }, { "item": "steyr_aug", "prob": 6 }, { "item": "v29", "prob": 1 }, diff --git a/data/json/itemgroups/Weapons_Mods_Ammo/gunmod.json b/data/json/itemgroups/Weapons_Mods_Ammo/gunmod.json index c52235ca4c2a5..d482cabfba4b0 100644 --- a/data/json/itemgroups/Weapons_Mods_Ammo/gunmod.json +++ b/data/json/itemgroups/Weapons_Mods_Ammo/gunmod.json @@ -123,6 +123,13 @@ [ "offset_sights", 6 ] ] }, + { + "type": "item_group", + "id": "m38dmr_mods", + "//": "Default mods for the m38dmr variant of the NATO assault rifle", + "subtype": "collection", + "entries": [ { "item": "suppressor" }, { "item": "rifle_scope" }, { "item": "bipod" } ] + }, { "type": "item_group", "id": "sights_shotgun_readied", @@ -137,6 +144,13 @@ "//": "For shotguns that haven't been 'made ready', e.g sitting in a store or garage.", "entries": [ { "group": "sights_shotgun", "prob": 20 }, { "group": "EMPTY_GROUP", "prob": 80 } ] }, + { + "type": "item_group", + "id": "mk23_mods", + "//": "Default mods for the mk23 variant of the USP .45 pistol", + "subtype": "collection", + "entries": [ { "item": "suppressor" }, { "item": "laser_sight" } ] + }, { "type": "item_group", "id": "sights_launcher", diff --git a/data/json/itemgroups/Weapons_Mods_Ammo/guns.json b/data/json/itemgroups/Weapons_Mods_Ammo/guns.json index 55ae85cb79f4d..59485c1ab21fa 100644 --- a/data/json/itemgroups/Weapons_Mods_Ammo/guns.json +++ b/data/json/itemgroups/Weapons_Mods_Ammo/guns.json @@ -145,9 +145,16 @@ "items": [ { "item": "m17", "prob": 100, "charges-min": 0, "charges-max": 17 }, { "item": "glock_18c", "prob": 70, "charges-min": 0, "charges-max": 17 }, - { "item": "mk23", "prob": 10, "charges-min": 0, "charges-max": 12 }, + { + "item": "usp_45", + "variant": "mk23", + "contents-group": "mk23_mods", + "prob": 10, + "charges-min": 0, + "charges-max": 12 + }, { "item": "usp_45", "prob": 15, "charges-min": 0, "charges-max": 12 }, - { "item": "m1911_MEU", "prob": 5, "charges-min": 0, "charges-max": 7 }, + { "item": "m1911", "variant": "m1911_MEU", "prob": 5, "charges-min": 0, "charges-max": 7 }, { "item": "glock_19", "prob": 20, "charges-min": 0, "charges-max": 15 }, { "item": "needlepistol", "prob": 45, "charges-min": 0, "charges-max": 50 }, { "item": "rm103a_pistol", "prob": 35, "charges-min": 0, "charges-max": 10 } @@ -350,7 +357,7 @@ "id": "guns_rifle_rare", "//": "Less common rifles including those only used by police/paramilitary forces.", "items": [ - { "item": "acr", "prob": 25, "charges-min": 0, "charges-max": 30 }, + { "item": "nato_assault_rifle", "variant": "acr", "prob": 25, "charges-min": 0, "charges-max": 30 }, { "item": "colt_lightning", "prob": 15, "charges-min": 0, "charges-max": 10 }, { "item": "fn_fal", "prob": 40, "charges-min": 0, "charges-max": 20 }, { "item": "fs2000", "prob": 6, "charges-min": 0, "charges-max": 30 }, @@ -360,7 +367,7 @@ { "item": "henry_big_boy", "prob": 10, "charges-min": 0, "charges-max": 10 }, { "item": "m14ebr", "prob": 15, "charges-min": 0, "charges-max": 20 }, { "item": "M24", "prob": 15, "charges-min": 0, "charges-max": 5 }, - { "item": "m4a1", "prob": 45, "charges-min": 0, "charges-max": 30 }, + { "item": "nato_assault_rifle", "variant": "m4a1", "prob": 45, "charges-min": 0, "charges-max": 30 }, { "item": "m1903", "prob": 15, "charges-min": 0, "charges-max": 5 }, { "item": "m1918", "prob": 30, "charges-min": 0, "charges-max": 20 }, { "item": "mosin44_ebr", "prob": 10, "charges-min": 0, "charges-max": 5 }, @@ -379,7 +386,7 @@ "id": "guns_rifle_rare_display", "//": "Less common rifles found exclusively in gun stores.", "items": [ - { "item": "acr", "prob": 25, "charges-min": 0, "charges-max": 0 }, + { "item": "nato_assault_rifle", "variant": "acr", "prob": 25, "charges-min": 0, "charges-max": 0 }, { "item": "colt_lightning", "prob": 15, "charges-min": 0, "charges-max": 0 }, { "item": "fn_fal", "prob": 40, "charges-min": 0, "charges-max": 0 }, { "item": "m249_semi", "prob": 5, "charges-min": 0, "charges-max": 0 }, @@ -388,7 +395,7 @@ { "item": "henry_big_boy", "prob": 10, "charges-min": 0, "charges-max": 0 }, { "item": "m14ebr", "prob": 15, "charges-min": 0, "charges-max": 0 }, { "item": "M24", "prob": 15, "charges-min": 0, "charges-max": 0 }, - { "item": "m4a1", "prob": 45, "charges-min": 0, "charges-max": 0 }, + { "item": "nato_assault_rifle", "variant": "m4a1", "prob": 45, "charges-min": 0, "charges-max": 0 }, { "item": "m1903", "prob": 15, "charges-min": 0, "charges-max": 0 }, { "item": "m1918", "prob": 30, "charges-min": 0, "charges-max": 0 }, { "item": "mosin44_ebr", "prob": 10, "charges-min": 0, "charges-max": 0 }, @@ -407,7 +414,7 @@ "id": "guns_rifle_milspec", "//": "Military specification rifles only ever found at military sites.", "items": [ - { "item": "h&k416a5", "prob": 50, "charges-min": 0, "charges-max": 30 }, + { "item": "nato_assault_rifle", "variant": "h&k416a5", "prob": 50, "charges-min": 0, "charges-max": 30 }, { "item": "m107a1", "prob": 30, "charges-min": 0, "charges-max": 10 }, { "item": "m134", "prob": 10, "charges-min": 0, "charges-max": 100 }, { "item": "m14ebr", "prob": 10, "charges-min": 0, "charges-max": 20 }, @@ -415,7 +422,7 @@ { "item": "m2010", "prob": 20, "charges-min": 0, "charges-max": 5 }, { "item": "m240", "prob": 15, "charges-min": 0, "charges-max": 100 }, { "item": "m249", "prob": 25, "charges-min": 0, "charges-max": 10 }, - { "item": "m27iar", "prob": 50, "charges-min": 0, "charges-max": 30 }, + { "item": "nato_assault_rifle", "variant": "m27iar", "prob": 50, "charges-min": 0, "charges-max": 30 }, { "item": "m60", "prob": 15, "charges-min": 0, "charges-max": 100 }, { "item": "rm11b_sniper_rifle", "prob": 15, "charges-min": 0, "charges-max": 10 }, { "item": "rm298", "prob": 10, "charges-min": 0, "charges-max": 100 }, @@ -423,7 +430,7 @@ { "item": "rm614_lmg", "prob": 10, "charges-min": 0, "charges-max": 100 }, { "item": "rm88_battle_rifle", "prob": 25, "charges-min": 0, "charges-max": 50 }, { "item": "sig552", "prob": 100, "charges-min": 0, "charges-max": 30 }, - { "item": "scar_l", "prob": 50, "charges-min": 0, "charges-max": 30 }, + { "item": "nato_assault_rifle", "variant": "scar_l", "prob": 50, "charges-min": 0, "charges-max": 30 }, { "item": "scar_h", "prob": 50, "charges-min": 0, "charges-max": 20 }, { "item": "m110a1", "prob": 50, "charges-min": 0, "charges-max": 20 }, { "item": "acr_300blk", "prob": 15, "charges-min": 0, "charges-max": 30 } @@ -785,7 +792,7 @@ { "item": "hk_mp5k", "prob": 10, "charges-min": 0, "charges-max": 30 }, { "item": "hk_mp5sd", "prob": 5, "charges-min": 0, "charges-max": 30 }, { "item": "m1014", "prob": 10, "charges-min": 0, "charges-max": 8 }, - { "item": "m4a1", "prob": 35, "charges-min": 0, "charges-max": 30 }, + { "item": "nato_assault_rifle", "variant": "m4a1", "prob": 35, "charges-min": 0, "charges-max": 30 }, { "item": "as50", "prob": 5, "charges-min": 0, "charges-max": 10 }, { "item": "hk417_13", "prob": 30, "charges-min": 0, "charges-max": 20 } ] diff --git a/data/json/itemgroups/defense_mode.json b/data/json/itemgroups/defense_mode.json index db399a263863f..08ebc50f2080d 100644 --- a/data/json/itemgroups/defense_mode.json +++ b/data/json/itemgroups/defense_mode.json @@ -35,7 +35,7 @@ { "item": "remington_870" }, { "item": "browning_blr" }, { "item": "ak47" }, - { "item": "m4a1" }, + { "item": "nato_assault_rifle", "variant": "m4a1" }, { "item": "savage_111f" }, { "item": "hk_g3" }, { "item": "hk_g80" }, diff --git a/data/json/itemgroups/military.json b/data/json/itemgroups/military.json index e30aa57f053ec..fff33a56cdce2 100644 --- a/data/json/itemgroups/military.json +++ b/data/json/itemgroups/military.json @@ -4,9 +4,15 @@ "id": "military_standard_assault_rifles", "subtype": "distribution", "entries": [ - { "item": "m4a1", "prob": 88, "charges": [ 0, 30 ] }, - { "item": "m27iar", "prob": 10, "charges": [ 0, 30 ] }, - { "item": "m38dmr", "prob": 1, "charges": [ 0, 30 ] }, + { "item": "nato_assault_rifle", "variant": "m4a1", "prob": 88, "charges": [ 0, 30 ] }, + { "item": "nato_assault_rifle", "variant": "m27iar", "prob": 10, "charges": [ 0, 30 ] }, + { + "item": "nato_assault_rifle", + "variant": "m38dmr", + "contents-group": "m38dmr_mods", + "prob": 1, + "charges": [ 0, 30 ] + }, { "item": "m16a4", "prob": 2, "charges": [ 0, 30 ] } ] }, @@ -38,7 +44,7 @@ { "item": "m17", "prob": 65, "charges": [ 0, 17 ] }, { "item": "m18", "prob": 30, "charges": [ 0, 17 ] }, { "item": "glock_19", "prob": 3, "charges": [ 0, 15 ] }, - { "item": "m1911_MEU", "prob": 2, "charges": [ 0, 7 ] } + { "item": "m1911", "variant": "m1911_MEU", "prob": 2, "charges": [ 0, 7 ] } ] }, { @@ -174,23 +180,23 @@ { "item": "20x66_flechette", "prob": 3 }, { "item": "m9", "prob": 6 }, { "item": "usp_45", "prob": 6 }, - { "item": "m4a1", "prob": 7 }, - { "item": "m4_cqbr", "prob": 1 }, + { "item": "nato_assault_rifle", "variant": "m4a1", "prob": 7 }, + { "item": "nato_assault_rifle", "variant": "m4_cqbr", "prob": 1 }, { "item": "m231pfw", "prob": 1 }, { "item": "m16a4", "prob": 5 }, - { "item": "m16a3", "prob": 1 }, + { "item": "nato_assault_rifle", "variant": "m16a3", "prob": 1 }, { "item": "colt_ro635", "prob": 1 }, { "item": "p226_9mm", "prob": 1 }, { "item": "sp2022", "prob": 1 }, - { "item": "h&k416a5", "prob": 7 }, + { "item": "nato_assault_rifle", "variant": "h&k416a5", "prob": 7 }, { "item": "m1014", "prob": 2 }, - { "item": "scar_l", "prob": 6 }, + { "item": "nato_assault_rifle", "variant": "scar_l", "prob": 6 }, { "item": "scar_h", "prob": 5 }, { "item": "sig_mcx_rattler_sbr", "prob": 1 }, { "item": "m249", "prob": 1 }, { "item": "m240", "prob": 1 }, - { "item": "m27iar", "prob": 1 }, - { "item": "m38dmr", "prob": 1 }, + { "item": "nato_assault_rifle", "variant": "m27iar", "prob": 1 }, + { "item": "nato_assault_rifle", "variant": "m38dmr", "contents-group": "m38dmr_mods", "prob": 1 }, { "item": "plasma_gun", "prob": 1 }, { "item": "m320", "prob": 5 }, { "item": "m320_mod", "prob": 10 }, @@ -376,8 +382,8 @@ { "item": "rm451_flamethrower", "prob": 10, "charges": [ 0, 2000 ] }, { "item": "m249", "prob": 30, "charges": [ 0, 30 ] }, { "item": "m240", "prob": 20, "charges": [ 0, 200 ] }, - { "item": "m27iar", "prob": 30, "charges": [ 0, 30 ] }, - { "item": "m38dmr", "prob": 3, "charges": [ 0, 30 ] }, + { "item": "nato_assault_rifle", "variant": "m27iar", "prob": 30, "charges": [ 0, 30 ] }, + { "item": "nato_assault_rifle", "variant": "m38dmr", "contents-group": "m38dmr_mods", "charges": [ 0, 30 ] }, { "item": "m2browning", "prob": 15, "charges": [ 0, 100 ] }, { "item": "mark19", "prob": 15, "charges": [ 0, 50 ] }, { "item": "556", "prob": 30, "charges": [ 1, 30 ] }, diff --git a/data/json/items/gun/223.json b/data/json/items/gun/223.json index b4ba9a5c2aa08..61f71f6f0ddc7 100644 --- a/data/json/items/gun/223.json +++ b/data/json/items/gun/223.json @@ -1,16 +1,63 @@ [ { - "id": "acr", + "id": "nato_assault_rifle", "copy-from": "rifle_auto", "looks_like": "ar15", "type": "GUN", - "name": { "str": "Remington ACR" }, - "description": "This carbine was developed for military use in the early 21st century. It is damaging and accurate, though its rate of fire is a bit slower than competing .223 carbines.", - "weight": "3719 g", + "name": { "str": "NATO assault rifle" }, + "description": "An assault rifle used by a NATO member state. As per NATO's STANAG agreement, it is chambered in 5.56x45mm.", + "//": "Weight, description, length modeled off of m4a1, price and gun stats average of some nato guns", + "weight": "2880g", "volume": "3310 ml", - "longest_side": "938 mm", - "price": 234300, - "price_postapoc": 6000, + "longest_side": "758 mm", + "price": "325 USD", + "price_postapoc": "48 USD", + "variants": [ + { + "id": "acr", + "name": { "str": "Remington ACR" }, + "description": "This carbine was developed for military use in the early 21st century. It is damaging and accurate, though its rate of fire is a bit slower than competing .223 carbines." + }, + { + "id": "h&k416a5", + "name": { "str": "HK416 A5" }, + "description": "Designed to replace the M4A1, the Heckler and Koch 416A5 features most of the former's strengths, while being considerably more durable." + }, + { + "id": "m27iar", + "name": { "str": "M27 IAR" }, + "description": "A H&K416 carbine outfitted with a heavier barrel to enable higher amounts of suppressive fire while retaining a good degree of mobility.", + "ascii_picture": "m27_iar" + }, + { + "id": "m4a1", + "name": { "str": "M4A1" }, + "description": "A popular carbine, long used by the US military. Though accurate, small, and lightweight, it is infamous for its unreliability when not properly maintained.", + "ascii_picture": "m4a1", + "weight": 1 + }, + { + "id": "m16a3", + "name": { "str": "M16A3" }, + "description": "The M16 is a very common assault rifle descended from the AR-15, used by militaries across the world for over 50 years. It is a gas operated, rotating bolt rifle known for its accuracy and controllable recoil. This one is a relatively rare M16A3, with full auto capability." + }, + { + "id": "scar_l", + "name": { "str": "FN SCAR-L" }, + "description": "A highly accurate and modular assault rifle specially designed for the United States Special Operations Command. The 'L' in its name stands for light, as it uses the lightweight .223 round.", + "ascii_picture": "scar-L" + }, + { + "id": "m38dmr", + "name": { "str": "M38 DMR" }, + "description": "The M38 Designated Marksman Rifle is an M27 IAR, itself derived from a H&K416, selected for accuracy, and outfitted with a variable power scope and a QDSS suppressor." + }, + { + "id": "m4_cqbr", + "name": { "str": "MK 18 CQBR" }, + "description": "This is a shorter M4 carbine with a 10.3 inch barrel, intended for confined spaces and close quarters battle situations." + } + ], "to_hit": -1, "bashing": 12, "material": [ "steel", "plastic" ], @@ -18,7 +65,7 @@ "color": "dark_gray", "ammo": [ "223" ], "ranged_damage": { "damage_type": "bullet", "amount": -1 }, - "dispersion": 150, + "dispersion": 160, "durability": 8, "min_cycle_recoil": 1350, "modes": [ [ "DEFAULT", "semi-auto", 1 ], [ "AUTO", "auto", 4 ] ], @@ -246,74 +293,20 @@ ] }, { - "id": "h&k416a5", - "copy-from": "rifle_auto", + "id": "hk_g36", + "copy-from": "nato_assault_rifle", "looks_like": "ar15", "type": "GUN", - "name": { "str": "HK416 A5" }, - "//": "*Current* milspec gear is now ridiculously overpriced, as seen with the M2010 IRL.", - "description": "Designed to replace the M4A1, the Heckler and Koch 416A5 features most of the former's strengths, while being considerably more durable.", - "weight": "3490 g", - "volume": "4957 ml", - "longest_side": "798 mm", - "price": 540000, - "price_postapoc": 2250, - "to_hit": -1, - "bashing": 12, - "material": [ "steel", "plastic" ], - "symbol": "(", - "color": "dark_gray", - "ammo": [ "223" ], - "ranged_damage": { "damage_type": "bullet", "amount": -2 }, - "dispersion": 180, - "durability": 8, - "min_cycle_recoil": 1350, - "modes": [ [ "DEFAULT", "semi-auto", 1 ], [ "AUTO", "auto", 4 ] ], - "pocket_data": [ + "name": { "str": "G36 assault rifle" }, + "description": "An assault rifle chamber in 5.56x45mm and accepting G36 magazines.", + "variants": [ { - "pocket_type": "MAGAZINE_WELL", - "holster": true, - "max_contains_volume": "20 L", - "max_contains_weight": "20 kg", - "item_restriction": [ - "stanag30", - "stanag5", - "stanag10", - "stanag20", - "stanag40", - "stanag50", - "stanag60", - "stanag60drum", - "stanag90", - "stanag100", - "stanag100drum", - "stanag150", - "survivor223mag" - ] + "id": "hk_g36", + "name": { "str": "H&K G36" }, + "description": "Designed as a replacement for the early H&K G3 battle rifle, the G36 is more accurate, and uses the much-lighter .223 round, allowing for a higher ammo capacity.", + "weight": 1 } - ] - }, - { - "id": "hk_g36", - "copy-from": "rifle_auto", - "looks_like": "ar15", - "type": "GUN", - "name": { "str": "H&K G36" }, - "description": "Designed as a replacement for the early H&K G3 battle rifle, the G36 is more accurate, and uses the much-lighter .223 round, allowing for a higher ammo capacity.", - "weight": "3630 g", - "volume": "4640 ml", - "longest_side": "1004 mm", - "price": 210000, - "price_postapoc": 6000, - "to_hit": -1, - "bashing": 12, - "material": [ "steel", "plastic" ], - "symbol": "(", - "color": "dark_gray", - "ammo": [ "223" ], - "dispersion": 150, - "durability": 8, - "min_cycle_recoil": 1350, + ], "modes": [ [ "DEFAULT", "semi-auto", 1 ], [ "AUTO", "auto", 4 ] ], "pocket_data": [ { @@ -396,164 +389,22 @@ "description": "This is a semi-automatic civilian variant of the M249 machine gun, manufactured for sport shooting and collectors market. Notably, it retains the ability to be belt fed, an uncommon feature in civilian firearms.", "modes": [ [ "DEFAULT", "semi-auto", 1 ] ] }, - { - "id": "m27iar", - "copy-from": "h&k416a5", - "type": "GUN", - "name": { "str": "M27 IAR" }, - "description": "A H&K416 carbine outfitted with a heavier barrel to enable higher amounts of suppressive fire while retaining a good degree of mobility.", - "ascii_picture": "m27_iar", - "weight": "3710 g", - "modes": [ [ "DEFAULT", "semi-auto", 1 ], [ "AUTO", "auto", 4 ] ], - "relative": { "ranged_damage": { "damage_type": "bullet", "amount": 1 }, "durability": 1 }, - "pocket_data": [ - { - "pocket_type": "MAGAZINE_WELL", - "holster": true, - "max_contains_volume": "20 L", - "max_contains_weight": "20 kg", - "item_restriction": [ - "stanag30", - "stanag5", - "stanag10", - "stanag20", - "stanag40", - "stanag50", - "stanag60", - "stanag60drum", - "stanag90", - "stanag100", - "stanag100drum", - "stanag150", - "survivor223mag" - ] - } - ] - }, - { - "id": "m38dmr", - "copy-from": "m27iar", - "name": { "str": "M38 DMR" }, - "type": "GUN", - "description": "The M38 Designated Marksman Rifle is an M27 IAR, itself derived from a H&K416, selected for accuracy, and outfitted with a variable power scope and a QDSS suppressor.", - "dispersion": 125, - "price_postapoc": 3000, - "default_mods": [ "suppressor", "rifle_scope", "bipod" ] - }, - { - "id": "m4a1", - "copy-from": "rifle_auto", - "looks_like": "ar15", - "type": "GUN", - "name": { "str": "M4A1" }, - "description": "A popular carbine, long used by the US military. Though accurate, small, and lightweight, it is infamous for its unreliability when not properly maintained.", - "ascii_picture": "m4a1", - "weight": "2880 g", - "volume": "3310 ml", - "longest_side": "758 mm", - "price": 240000, - "price_postapoc": 5000, - "to_hit": -1, - "bashing": 12, - "material": [ "steel", "plastic" ], - "symbol": "(", - "color": "dark_gray", - "ammo": [ "223" ], - "ranged_damage": { "damage_type": "bullet", "amount": -2 }, - "dispersion": 180, - "durability": 6, - "min_cycle_recoil": 1350, - "modes": [ [ "DEFAULT", "semi-auto", 1 ], [ "AUTO", "auto", 4 ] ], - "pocket_data": [ - { - "pocket_type": "MAGAZINE_WELL", - "holster": true, - "max_contains_volume": "20 L", - "max_contains_weight": "20 kg", - "item_restriction": [ - "stanag30", - "stanag5", - "stanag10", - "stanag20", - "stanag40", - "stanag50", - "stanag60", - "stanag60drum", - "stanag90", - "stanag100", - "stanag100drum", - "stanag150", - "survivor223mag" - ] - } - ] - }, - { - "id": "m4_cqbr", - "copy-from": "m4a1", - "type": "GUN", - "name": { "str": "MK 18 CQBR" }, - "description": "This is a shorter M4 carbine with a 10.3 inch barrel, intended for confined spaces and close quarters battle situations.", - "weight": "2720 g", - "volume": "3110 ml", - "longest_side": "682 mm", - "price": 260000, - "price_postapoc": 6000, - "ranged_damage": { "damage_type": "bullet", "amount": -3 } - }, { "id": "m16a4", - "copy-from": "rifle_semi", + "copy-from": "nato_assault_rifle", "looks_like": "ar15", "type": "GUN", - "name": { "str": "M16A4" }, - "description": "The M16 is a very common assault rifle descended from the AR-15, used by militaries across the world for over 50 years. It is a gas operated, rotating bolt rifle known for its accuracy and controllable recoil.", - "weight": "3260 g", - "volume": "5030 ml", - "longest_side": "1003 mm", - "price": 240000, - "price_postapoc": 5000, - "to_hit": -1, - "bashing": 12, - "material": [ "steel", "plastic" ], - "symbol": "(", - "color": "dark_gray", - "ammo": [ "223" ], - "dispersion": 150, - "durability": 7, - "min_cycle_recoil": 1350, - "modes": [ [ "DEFAULT", "semi-auto", 1 ], [ "BURST", "3 rd.", 3 ] ], - "pocket_data": [ + "name": { "str": "NATO burst rifle" }, + "description": "An assault rifle used by a NATO member state. Unlike other assault rifles, this one does not have an auto-fire mode, and instead has a burst fire mode. As per NATO's STANAG agreement, it is chambered in 5.56x45mm.", + "variants": [ { - "pocket_type": "MAGAZINE_WELL", - "holster": true, - "max_contains_volume": "20 L", - "max_contains_weight": "20 kg", - "item_restriction": [ - "stanag30", - "stanag5", - "stanag10", - "stanag20", - "stanag40", - "stanag50", - "stanag60", - "stanag60drum", - "stanag90", - "stanag100", - "stanag100drum", - "stanag150", - "survivor223mag" - ] + "id": "m16a4", + "name": { "str": "M16A4" }, + "description": "The M16 is a very common assault rifle descended from the AR-15, used by militaries across the world for over 50 years. It is a gas operated, rotating bolt rifle known for its accuracy and controllable recoil.", + "weight": 1 } - ] - }, - { - "id": "m16a3", - "copy-from": "m16a4", - "type": "GUN", - "name": { "str": "M16A3" }, - "description": "The M16 is a very common assault rifle descended from the AR-15, used by militaries across the world for over 50 years. It is a gas operated, rotating bolt rifle known for its accuracy and controllable recoil. This one is a relatively rare M16A3, with full auto capability.", - "modes": [ [ "DEFAULT", "semi-auto", 1 ], [ "AUTO", "auto", 4 ] ] + ], + "modes": [ [ "DEFAULT", "semi-auto", 1 ], [ "BURST", "3 rd.", 3 ] ] }, { "id": "m231pfw", @@ -680,121 +531,39 @@ } ] }, - { - "id": "scar_l", - "copy-from": "rifle_auto", - "looks_like": "ar15", - "type": "GUN", - "name": { "str": "FN SCAR-L" }, - "description": "A highly accurate and modular assault rifle specially designed for the United States Special Operations Command. The 'L' in its name stands for light, as it uses the lightweight .223 round.", - "ascii_picture": "scar-L", - "weight": "3500 g", - "volume": "4970 ml", - "longest_side": "850 mm", - "price": 280000, - "price_postapoc": 6000, - "to_hit": -1, - "bashing": 12, - "material": [ "steel", "plastic" ], - "symbol": "(", - "color": "dark_gray", - "ammo": [ "223" ], - "ranged_damage": { "damage_type": "bullet", "amount": -2 }, - "dispersion": 150, - "durability": 8, - "min_cycle_recoil": 1350, - "modes": [ [ "DEFAULT", "semi-auto", 1 ], [ "AUTO", "auto", 4 ] ], - "pocket_data": [ - { - "pocket_type": "MAGAZINE_WELL", - "holster": true, - "max_contains_volume": "20 L", - "max_contains_weight": "20 kg", - "item_restriction": [ - "stanag30", - "stanag5", - "stanag10", - "stanag20", - "stanag40", - "stanag50", - "stanag60", - "stanag60drum", - "stanag90", - "stanag100", - "stanag100drum", - "stanag150", - "survivor223mag" - ] - } - ] - }, { "id": "sig552", - "copy-from": "rifle_auto", + "copy-from": "nato_assault_rifle", "looks_like": "ar15", "type": "GUN", - "name": { "str": "SIG 552" }, - "description": "A compact selective fire automatic rifle designed for the Swiss military. It features a three-round burst mode and an integrated folding stock.", - "weight": "3200 g", - "volume": "2950 ml", - "longest_side": "741 mm", - "price": 320000, - "price_postapoc": 6000, - "to_hit": -1, - "bashing": 10, - "material": [ "steel", "plastic" ], - "ammo": [ "223" ], - "dispersion": 180, - "durability": 9, - "min_cycle_recoil": 1350, - "modes": [ [ "DEFAULT", "semi-auto", 1 ], [ "BURST", "3 rd.", 3 ], [ "AUTO", "auto", 4 ] ], - "built_in_mods": [ "folding_stock" ], - "pocket_data": [ + "//": "This could use a better name, I just wanted to differentiate it from assault rifles, as it also has a burst mode", + "name": { "str": "NATO assault rifle with burst" }, + "description": "An assault rifle used by a NATO member state. Unlike other assault rifles, this one has a burst fire mode in addition to semi-automatic and fully-automatic modes. As per NATO's STANAG agreement, it is chambered in 5.56x45mm.", + "variants": [ { - "pocket_type": "MAGAZINE_WELL", - "holster": true, - "max_contains_volume": "20 L", - "max_contains_weight": "20 kg", - "item_restriction": [ - "stanag30", - "stanag5", - "stanag10", - "stanag20", - "stanag40", - "stanag50", - "stanag60", - "stanag60drum", - "stanag90", - "stanag100", - "stanag100drum", - "stanag150", - "survivor223mag" - ] + "id": "sig552", + "name": { "str": "SIG 552" }, + "description": "A compact selective fire automatic rifle designed for the Swiss military. It features a three-round burst mode and an integrated folding stock.", + "weight": 1 } - ] + ], + "built_in_mods": [ "folding_stock" ] }, { "id": "steyr_aug", - "copy-from": "rifle_auto", + "copy-from": "nato_assault_rifle", "looks_like": "ar15", "type": "GUN", - "name": { "str": "Steyr AUG" }, - "description": "The Steyr AUG is an Austrian assault rifle that uses a bullpup design. It is used in the armed forces and police forces of many nations, and enjoys low recoil and high accuracy.", - "weight": "3500 g", - "volume": "3520 ml", - "longest_side": "715 mm", - "price": 490000, - "price_postapoc": 6000, - "to_hit": -1, - "bashing": 12, - "material": [ "steel", "plastic" ], - "symbol": "(", - "color": "light_gray", - "ammo": [ "223" ], - "dispersion": 140, - "durability": 8, - "min_cycle_recoil": 1350, - "modes": [ [ "DEFAULT", "semi-auto", 1 ], [ "AUTO", "auto", 4 ] ], + "name": { "str": "AUG assault rifle" }, + "description": "An assault rifle chambered in 5.56x45mm and accepting AUG magazines", + "variants": [ + { + "id": "steyr_aug", + "name": { "str": "Steyr AUG" }, + "description": "The Steyr AUG is an Austrian assault rifle that uses a bullpup design. It is used in the armed forces and police forces of many nations, and enjoys low recoil and high accuracy.", + "weight": 1 + } + ], "built_in_mods": [ "grip" ], "valid_mod_locations": [ [ "accessories", 4 ], diff --git a/data/json/items/gun/308.json b/data/json/items/gun/308.json index a1ce10176e491..5deff26f3b233 100644 --- a/data/json/items/gun/308.json +++ b/data/json/items/gun/308.json @@ -312,7 +312,7 @@ }, { "id": "scar_h", - "copy-from": "scar_l", + "copy-from": "nato_assault_rifle", "looks_like": "ar15", "type": "GUN", "name": { "str_sp": "FN SCAR-H" }, diff --git a/data/json/items/gun/45.json b/data/json/items/gun/45.json index c5519811c56b1..84013736b3b4f 100644 --- a/data/json/items/gun/45.json +++ b/data/json/items/gun/45.json @@ -4,8 +4,21 @@ "looks_like": "hk_mp5", "type": "GUN", "reload_noise_volume": 10, - "name": { "str": "Vector SMG .45" }, - "description": "The Vector SMG is a delayed blowback submachine gun with a unique, in-line design that places both the shooter's hand and shoulder in line with the bore axis, reducing muzzle climb during bursts. This one is chambered in .45 ACP.", + "//": [ + "Yes, I know it's not really a glock smg.", + "It takes glock magazines, and it's own special one that I am also renaming to a glock magazine", + "so, I'm calling it a glock smg." + ], + "name": { "str": "Glock SMG" }, + "description": "This is a submachine gun chambered in .45 ACP, accepting Glock magazines.", + "variants": [ + { + "id": "TDI", + "name": { "str": "Vector SMG .45" }, + "description": "The Vector SMG is a delayed blowback submachine gun with a unique, in-line design that places both the shooter's hand and shoulder in line with the bore axis, reducing muzzle climb during bursts. This one is chambered in .45 ACP.", + "weight": 1 + } + ], "weight": "3100 g", "volume": "4248 ml", "longest_side": "611 mm", @@ -53,8 +66,16 @@ "looks_like": "hk_mp5", "type": "GUN", "reload_noise_volume": 10, - "name": { "str": "H&K UMP45" }, - "description": "Developed as a successor to the MP5 submachine gun, the UMP45 retains the earlier model's supreme accuracy and low recoil, but in the higher .45 caliber.", + "name": { "str": "UMP45 SMG" }, + "description": "This is a submachine gun, chambered in .45 ACP, and accepting UMP45 magazines.", + "variants": [ + { + "id": "hk_ump45", + "name": { "str": "H&K UMP45" }, + "description": "Developed as a successor to the MP5 submachine gun, the UMP45 retains the earlier model's supreme accuracy and low recoil, but in the higher .45 caliber.", + "weight": 1 + } + ], "ascii_picture": "hk_ump", "weight": "2300 g", "volume": "4451 ml", @@ -104,9 +125,22 @@ "copy-from": "pistol_base", "looks_like": "glock_17", "type": "GUN", - "name": { "str": "M1911" }, - "//": "You can get 'em for over US$1K if you want. This is a fairly cheap remake.", - "description": "The M1911 was the US Military standard-issue sidearm for most of the 20th Century. It remains one of the most popular .45 pistols today.", + "name": { "str": "M1911 pistol" }, + "description": "This is a semi-automatic pistol, chambered in .45 ACP and accepting M1991 magaines.", + "variants": [ + { + "id": "m1911", + "name": { "str": "M1911" }, + "//": "You can get 'em for over US$1K if you want. This is a fairly cheap remake.", + "description": "The M1911 was the US Military standard-issue sidearm for most of the 20th Century. It remains one of the most popular .45 pistols today.", + "weight": 1 + }, + { + "id": "m1911_MEU", + "name": { "str": "M45A1" }, + "description": "The M45A1 supplanted earlier M45 MEUSOC pistols in use by Force Recon elements of Marine Expeditionary Units. Where the original M45 pistols were gutted M1911A1's hand-fitted by USMC armorers, the updated M45A1's are hardly different from any other commercial 1911 design save for their dual recoil springs. Most were replaced in 2016 with Glock 19's due to logistics issues." + } + ], "ascii_picture": "m1911", "weight": "1120 g", "volume": "454 ml", @@ -134,27 +168,21 @@ } ] }, - { - "id": "m1911_MEU", - "copy-from": "m1911", - "looks_like": "glock_17", - "type": "GUN", - "name": { "str": "M45A1" }, - "description": "The M45A1 supplanted earlier M45 MEUSOC pistols in use by Force Recon elements of Marine Expeditionary Units. Where the original M45 pistols were gutted M1911A1's hand-fitted by USMC armorers, the updated M45A1's are hardly different from any other commercial 1911 design save for their dual recoil springs. Most were replaced in 2016 with Glock 19's due to logistics issues.", - "weight": "1105 g", - "price": 169900, - "price_postapoc": 2750, - "color": "brown_yellow", - "dispersion": 420, - "durability": 8 - }, { "id": "mac_10", "looks_like": "hk_mp5", "type": "GUN", "reload_noise_volume": 10, - "name": { "str": "MAC-10" }, - "description": "The MAC-10 is a popular machine pistol originally designed for military use. For many years they were the most inexpensive automatic weapon in the US, and enjoyed great popularity among criminals less concerned with quality firearms.", + "name": { "str": "MAC-10 SMG" }, + "description": "This is a submachine gun chambered in .45 ACP, and accepting MAC-10 magazines.", + "variants": [ + { + "id": "mac_10", + "name": { "str": "MAC-10" }, + "description": "The MAC-10 is a popular machine pistol originally designed for military use. For many years they were the most inexpensive automatic weapon in the US, and enjoyed great popularity among criminals less concerned with quality firearms.", + "weight": 1 + } + ], "weight": "2810 g", "volume": "1195 ml", "longest_side": "298 mm", @@ -320,8 +348,16 @@ "looks_like": "hk_mp5", "type": "GUN", "reload_noise_volume": 10, - "name": { "str": "Thompson M1928A1" }, - "description": "An American-made submachine gun developed during the very end of World War I, too late to see action. Infamous during the 1920s for its use by gangsters, and was used during World War II before being mostly replaced with less-expensive alternatives.", + "name": { "str": "Thompson SMG" }, + "description": "This is a submachine gun chambered in .45 ACP, and accepting Thompson magazines.", + "variants": [ + { + "id": "tommygun", + "name": { "str": "Thompson M1928A1" }, + "description": "An American-made submachine gun developed during the very end of World War I, too late to see action. Infamous during the 1920s for its use by gangsters, and was used during World War II before being mostly replaced with less-expensive alternatives.", + "weight": 1 + } + ], "weight": "4899 g", "volume": "1230 ml", "longest_side": "832 mm", @@ -369,7 +405,21 @@ "id": "usp_45", "copy-from": "usp_9mm", "type": "GUN", - "name": { "str": "USP .45" }, + "name": { "str": "USP pistol" }, + "description": "A semi-automatic pistol chambered in .45 ACP, and accepting USP magazines.", + "variants": [ + { + "id": "usp_45", + "name": { "str": "USP .45" }, + "description": "A popular pistol, widely used among law enforcement. Extensively tested for durability, it has been found to stay accurate even after being subjected to extreme abuse.", + "weight": 1 + }, + { + "id": "mk23", + "name": { "str": "MK 23 MOD 0" }, + "description": "Jokingly referred to as \"The World's Only Crew-Served Pistol\", this massive pistol was designed as a primary weapon for select \"special operators\". Its cumbersome nature, the introduction of the derivative HK USP series and the logistics of getting .45 ACP ammunition in theater doomed this behemoth to US SOCOM armories. Like the USP, the Mk 23 is a remarkably reliable gun; someone could probably take out a nuclear equipped walking tank with this in their holster." + } + ], "weight": "887 g", "volume": "483 ml", "longest_side": "241 mm", @@ -389,27 +439,21 @@ } ] }, - { - "id": "mk23", - "copy-from": "usp_45", - "type": "GUN", - "name": { "str": "MK 23 MOD 0" }, - "description": "Jokingly referred to as \"The World's Only Crew-Served Pistol\", this massive pistol was designed as a primary weapon for select \"special operators\". Its cumbersome nature, the introduction of the derivative HK USP series and the logistics of getting .45 ACP ammunition in theater doomed this behemoth to US SOCOM armories. Like the USP, the Mk 23 is a remarkably reliable gun; someone could probably take out a nuclear equipped walking tank with this in their holster.", - "weight": "844 g", - "volume": "698 ml", - "longest_side": "277 mm", - "price": 70000, - "price_postapoc": 3000, - "default_mods": [ "suppressor", "laser_sight" ], - "flags": [ "WATERPROOF_GUN", "NEVER_JAMS" ] - }, { "id": "walther_ppq_45", "copy-from": "pistol_base", "looks_like": "glock_17", "type": "GUN", - "name": { "str": "Walther PPQ 45" }, - "description": "The Walther PPQ is a semi-automatic pistol originating from the Walther P99QA, and maintains compatibility with some of its predecessor's accessories. This model is chambered in .45 ACP.", + "name": { "str": "PPQ pistol" }, + "description": "This is a semi-automatic pistol chambered in .45 ACP, and accepting PPQ magazines", + "variants": [ + { + "id": "walther_ppq_45", + "name": { "str": "Walther PPQ 45" }, + "description": "The Walther PPQ is a semi-automatic pistol originating from the Walther P99QA, and maintains compatibility with some of its predecessor's accessories. This model is chambered in .45 ACP.", + "weight": 1 + } + ], "weight": "799 g", "volume": "472 ml", "longest_side": "224 mm", @@ -438,8 +482,16 @@ "copy-from": "pistol_base", "looks_like": "glock_17", "type": "GUN", - "name": { "str": "Hi-Point Model JHP" }, - "description": "The Hi-Point Model JHP is a blowback operated semi-automatic pistol designed by Hi-Point Firearms, which is known for making inexpensive firearms, and for making said firearms bulky and uncomfortable. Hi-Points have slides made with a zinc pot-metal which is relatively fragile compared to steel slides.", + "name": { "str": "Hi-Point pistol" }, + "description": "This is a semi-automatic pistol chambered in .45 ACP, and accepting Hi-Point magazines", + "variants": [ + { + "id": "hptjhp", + "name": { "str": "Hi-Point Model JHP" }, + "description": "The Hi-Point Model JHP is a blowback operated semi-automatic pistol designed by Hi-Point Firearms, which is known for making inexpensive firearms, and for making said firearms bulky and uncomfortable. Hi-Points have slides made with a zinc pot-metal which is relatively fragile compared to steel slides.", + "weight": 1 + } + ], "weight": "990 g", "volume": "538 ml", "longest_side": "238 mm", @@ -469,8 +521,16 @@ "copy-from": "pistol_base", "looks_like": "glock_17", "type": "GUN", - "name": { "str": "Glock 21" }, - "description": "A full-sized version of the highly successful Glock. This model is chambered in .45 ACP.", + "name": { "str": "Glock pistol" }, + "description": "This is a semi-automatic pistol chambered in .45 ACP, and accepting Glock magazines.", + "variants": [ + { + "id": "glock_21", + "name": { "str": "Glock 21" }, + "description": "A full-sized version of the highly successful Glock. This model is chambered in .45 ACP.", + "weight": 1 + } + ], "ascii_picture": "glock_20", "weight": "835 g", "volume": "490 ml", diff --git a/data/json/items/magazine/45.json b/data/json/items/magazine/45.json index 1296e45516a44..5ed6563fac0a8 100644 --- a/data/json/items/magazine/45.json +++ b/data/json/items/magazine/45.json @@ -38,8 +38,16 @@ "id": "tdi_mag", "looks_like": "mp5mag", "type": "MAGAZINE", - "name": { "str": "Vector SMG 30-round magazine" }, - "description": "A 30-round polymer and steel box magazine for use with the KRISS Vector.", + "name": { "str": "Glock SMG 30-round magazine" }, + "description": "A 30-round polymer and steel box magazine for use with the Glock submachine gun.", + "variants": [ + { + "id": "tdi_mag", + "name": { "str": "Vector SMG 30-round magazine" }, + "description": "A 30-round polymer and steel box magazine for use with the KRISS Vector.", + "weight": 1 + } + ], "weight": "210 g", "volume": "500 ml", "price": 1800, @@ -141,8 +149,16 @@ "id": "usp45mag", "looks_like": "glock17_17", "type": "MAGAZINE", - "name": { "str": "USP .45 12-round magazine" }, - "description": "A standard capacity magazine for use with the H&K USP handgun.", + "name": { "str": "USP .45 pistol 12-round magazine" }, + "description": "A 12 round magazine for use with the USP pistol", + "variants": [ + { + "id": "usp45mag", + "name": { "str": "USP .45 12-round magazine" }, + "description": "A standard capacity magazine for use with the H&K USP handgun.", + "weight": 1 + } + ], "weight": "60 g", "volume": "250 ml", "price": 5900, @@ -158,8 +174,16 @@ "id": "ppq45mag", "looks_like": "glock17_17", "type": "MAGAZINE", - "name": { "str": "PPQ .45 ACP 12-round magazine" }, - "description": "A 12 round steel box magazine for the Walther PPQ .45 ACP.", + "name": { "str": "PPQ .45 12-round amgazine" }, + "description": "A 12 round steel box magazine for the PPQ pistol", + "variants": [ + { + "id": "ppq45mag", + "name": { "str": "PPQ .45 ACP 12-round magazine" }, + "description": "A 12 round steel box magazine for the Walther PPQ .45 ACP.", + "weight": 1 + } + ], "weight": "80 g", "volume": "240 ml", "price": 5000, @@ -192,8 +216,16 @@ "id": "glock_21mag", "looks_like": "glock17_17", "type": "MAGAZINE", - "name": { "str": "Glock 21 13-round magazine" }, - "description": "A standard capacity magazine for use with the Glock 21.", + "name": { "str": "Glock .45 13-round magazine" }, + "description": "A 13 round magazine for use with Glock firearms chambered in .45 ACP.", + "variants": [ + { + "id": "glock_21mag", + "name": { "str": "Glock 21 13-round magazine" }, + "description": "A standard capacity magazine for use with the Glock 21.", + "weight": 1 + } + ], "weight": "85 g", "volume": "105 ml", "price": 4000, @@ -209,8 +241,16 @@ "id": "glock_21mag26", "looks_like": "glock17_17", "type": "MAGAZINE", - "name": { "str": "Glock 21 26-round magazine" }, - "description": "A double capacity magazine for use with the Glock 21.", + "name": { "str": "Glock .45 26-round magazine" }, + "description": "A 26 round magazine for use with Glock firearms chambered in .45 ACP.", + "variants": [ + { + "id": "glock_21mag26", + "name": { "str": "Glock 21 26-round magazine" }, + "description": "A double capacity magazine for use with the Glock 21.", + "weight": 1 + } + ], "weight": "85 g", "volume": "205 ml", "price": 4000, diff --git a/data/json/items/migration.json b/data/json/items/migration.json index 9ca037b6feac4..dbfb65d23c529 100644 --- a/data/json/items/migration.json +++ b/data/json/items/migration.json @@ -1136,7 +1136,7 @@ { "id": [ "l_base_223", "l_car_223", "l_car_223_kit", "l_mbr_223", "l_mbr_223_kit" ], "type": "MIGRATION", - "replace": "h&k416a5" + "replace": "nato_assault_rifle" }, { "id": [ "l_lmg_223", "l_lmg_223_kit" ], @@ -1146,7 +1146,55 @@ { "id": [ "l_dsr_223", "l_dsr_223_kit" ], "type": "MIGRATION", - "replace": "m16a4" + "replace": "nato_assault_rifle" + }, + { + "id": "acr", + "type": "MIGRATION", + "replace": "nato_assault_rifle", + "variant": "acr" + }, + { + "id": "h&k416a5", + "type": "MIGRATION", + "replace": "nato_assault_rifle", + "variant": "h&k416a5" + }, + { + "id": "m27iar", + "type": "MIGRATION", + "replace": "nato_assault_rifle", + "variant": "m27iar" + }, + { + "id": "m4a1", + "type": "MIGRATION", + "replace": "nato_assault_rifle", + "variant": "m4a1" + }, + { + "id": "m16a3", + "type": "MIGRATION", + "replace": "nato_assault_rifle", + "variant": "m16a3" + }, + { + "id": "scar_l", + "type": "MIGRATION", + "replace": "nato_assault_rifle", + "variant": "scar_l" + }, + { + "id": "m38dmr", + "type": "MIGRATION", + "replace": "nato_assault_rifle", + "variant": "m38dmr" + }, + { + "id": "m4_cqbr", + "type": "MIGRATION", + "replace": "nato_assault_rifle", + "variant": "m4_cqbr" }, { "id": "lw223bigmag", @@ -1163,6 +1211,18 @@ "type": "MIGRATION", "replace": "m1911mag" }, + { + "id": "m1911_MEU", + "type": "MIGRATION", + "replace": "m1911", + "variant": "m1911_MEU" + }, + { + "id": "mk23", + "type": "MIGRATION", + "replace": "usp_45", + "variant": "mk23" + }, { "id": "solar_panel_v3", "type": "MIGRATION", diff --git a/data/json/mapgen/military/mil_base/mil_base_z0.json b/data/json/mapgen/military/mil_base/mil_base_z0.json index 217d06746dd9f..782f5b5ee8ef9 100644 --- a/data/json/mapgen/military/mil_base/mil_base_z0.json +++ b/data/json/mapgen/military/mil_base/mil_base_z0.json @@ -752,13 +752,37 @@ { "item": "m203", "x": 10, "y": 11, "chance": 75, "repeat": 5 }, { "item": "mgl", "x": 10, "y": 11, "chance": 75, "repeat": 3 }, { "item": "40x46mm_m433", "x": 10, "y": 12, "chance": 75, "repeat": 20 }, - { "item": "m4a1", "x": 12, "y": [ 9, 11 ], "magazine": 100, "chance": 75, "repeat": 30 }, - { "item": "m27iar", "x": 12, "y": 9, "magazine": 100, "chance": 75, "repeat": 8 }, + { + "item": "nato_assault_rifle", + "variant": "m4a1", + "x": 12, + "y": [ 9, 11 ], + "magazine": 100, + "chance": 75, + "repeat": 30 + }, + { + "item": "nato_assault_rifle", + "variant": "m27iar", + "x": 12, + "y": 9, + "magazine": 100, + "chance": 75, + "repeat": 8 + }, { "item": "m16a4", "x": 12, "y": 9, "magazine": 100, "chance": 75, "repeat": 2 }, { "item": "stanag30", "x": 12, "y": 12, "chance": 75, "repeat": 80 }, { "item": "stanag50", "x": 12, "y": 12, "chance": 75, "repeat": 20 }, { "item": "556", "x": 14, "y": [ 9, 12 ], "chance": 75, "repeat": 150 }, - { "item": "m4a1", "x": 16, "y": [ 9, 11 ], "magazine": 100, "chance": 75, "repeat": 36 }, + { + "item": "nato_assault_rifle", + "variant": "m4a1", + "x": 16, + "y": [ 9, 11 ], + "magazine": 100, + "chance": 75, + "repeat": 36 + }, { "item": "stanag30", "x": 16, "y": 12, "chance": 75, "repeat": 100 }, { "item": "556", "x": 18, "y": [ 9, 12 ], "chance": 75, "repeat": 150 }, { "item": "m249", "x": 20, "y": 9, "chance": 75, "repeat": 6 }, diff --git a/data/json/martialarts.json b/data/json/martialarts.json index 2f157333afe72..025e18de40ff9 100644 --- a/data/json/martialarts.json +++ b/data/json/martialarts.json @@ -645,10 +645,8 @@ "hptjhp", "m17", "m1911", - "m1911_MEU", "m1911a1_38super", "m9", - "mk23", "needlepistol", "sw_22", "p226_357sig", @@ -665,7 +663,7 @@ "walther_ppq_9mm", "walther_ppq_40", "walther_ppq_45", - "acr", + "nato_assault_rifle", "acr_300blk", "ak47", "ak74", @@ -674,24 +672,17 @@ "ar15", "ar15_retool_300blk", "fn_fal", - "h&k416a5", "hk417_13", "hk_g3", - "hk_g36", "iwi_tavor_x95_300blk", "m1a", "m110a1", "m14ebr", "m16a4", - "m27iar", - "m38dmr", - "m4a1", "rm51_assault_rifle", "rm88_battle_rifle", "ruger_mini", - "scar_l", "scar_h", - "sig552", "sks", "steyr_aug", "tanto", diff --git a/data/json/npcs/NC_ARSONIST.json b/data/json/npcs/NC_ARSONIST.json index b724d245854b9..fac1c64e31ba5 100644 --- a/data/json/npcs/NC_ARSONIST.json +++ b/data/json/npcs/NC_ARSONIST.json @@ -194,7 +194,11 @@ "type": "item_group", "id": "NC_ARSONIST_rifle", "subtype": "distribution", - "entries": [ { "item": "m4a1", "prob": 35 }, { "item": "m1a", "prob": 35 }, { "item": "ak47", "prob": 35 } ] + "entries": [ + { "item": "nato_assault_rifle", "variant": "m4a1", "prob": 35 }, + { "item": "m1a", "prob": 35 }, + { "item": "ak47", "prob": 35 } + ] }, { "type": "item_group", diff --git a/data/json/npcs/NC_SOLDIER.json b/data/json/npcs/NC_SOLDIER.json index 61d44ec2aeb14..d5e6ccb771832 100644 --- a/data/json/npcs/NC_SOLDIER.json +++ b/data/json/npcs/NC_SOLDIER.json @@ -117,13 +117,13 @@ "type": "item_group", "id": "NC_SOLDIER_rifle", "subtype": "distribution", - "entries": [ { "item": "m4a1", "prob": 90 }, { "item": "m14ebr", "prob": 10 } ] + "entries": [ { "item": "nato_assault_rifle", "variant": "m4a1", "prob": 90 }, { "item": "m14ebr", "prob": 10 } ] }, { "type": "item_group", "id": "NC_SOLDIER_weapon_random", "subtype": "distribution", - "entries": [ { "item": "m4a1", "prob": 35 } ] + "entries": [ { "item": "nato_assault_rifle", "variant": "m4a1", "prob": 35 } ] }, { "type": "item_group", diff --git a/data/json/npcs/refugee_center/surface_visitors/NPC_scavenger_mercenary.json b/data/json/npcs/refugee_center/surface_visitors/NPC_scavenger_mercenary.json index ae95e41ae4a01..4484feb847eae 100644 --- a/data/json/npcs/refugee_center/surface_visitors/NPC_scavenger_mercenary.json +++ b/data/json/npcs/refugee_center/surface_visitors/NPC_scavenger_mercenary.json @@ -73,7 +73,13 @@ "id": "NC_SCAVENGER_MERC_wield", "subtype": "collection", "items": [ - { "item": "m4a1", "ammo-item": "556", "charges": 30, "contents-item": [ "shoulder_strap", "holo_sight", "suppressor" ] } + { + "item": "nato_assault_rifle", + "variant": "m4a1", + "ammo-item": "556", + "charges": 30, + "contents-item": [ "shoulder_strap", "holo_sight", "suppressor" ] + } ] }, { diff --git a/data/json/npcs/robofac/NPC_ROBOFAC_MERC_1.json b/data/json/npcs/robofac/NPC_ROBOFAC_MERC_1.json index 6b61c9176f927..41f2b45f56bc9 100644 --- a/data/json/npcs/robofac/NPC_ROBOFAC_MERC_1.json +++ b/data/json/npcs/robofac/NPC_ROBOFAC_MERC_1.json @@ -65,7 +65,13 @@ "id": "NC_ROBOFAC_MERC_1_wield", "subtype": "collection", "items": [ - { "item": "acr", "ammo-item": "556", "charges": 30, "contents-item": [ "shoulder_strap", "holo_sight", "suppressor" ] } + { + "item": "nato_assault_rifle", + "variant": "acr", + "ammo-item": "556", + "charges": 30, + "contents-item": [ "shoulder_strap", "holo_sight", "suppressor" ] + } ] }, { diff --git a/data/json/professions.json b/data/json/professions.json index 9b4d5e7de891c..b40032f09b937 100644 --- a/data/json/professions.json +++ b/data/json/professions.json @@ -804,7 +804,13 @@ { "item": "legpouch_large", "contents-group": "army_mags_m4" }, { "item": "ear_plugs", "custom-flags": [ "no_auto_equip" ] }, { "item": "knife_combat", "container-item": "sheath" }, - { "item": "m4a1", "ammo-item": "556", "charges": 30, "contents-item": [ "shoulder_strap", "holo_sight" ] } + { + "item": "nato_assault_rifle", + "variant": "m4a1", + "ammo-item": "556", + "charges": 30, + "contents-item": [ "shoulder_strap", "holo_sight" ] + } ] }, "male": [ "boxer_shorts" ], @@ -989,7 +995,13 @@ { "item": "legpouch_large", "contents-group": "army_mags_m4" }, { "item": "ear_plugs", "custom-flags": [ "no_auto_equip" ] }, { "item": "knife_combat", "container-item": "sheath" }, - { "item": "m4a1", "ammo-item": "556", "charges": 30, "contents-item": [ "shoulder_strap", "holo_sight" ] } + { + "item": "nato_assault_rifle", + "variant": "m4a1", + "ammo-item": "556", + "charges": 30, + "contents-item": [ "shoulder_strap", "holo_sight" ] + } ] }, "male": [ "boxer_shorts" ], @@ -1086,7 +1098,13 @@ "items": [ "armor_farmor", "socks", "boots_fur", "hat_fur", "gloves_fur", "vest", "wristwatch" ], "entries": [ { "item": "knife_combat", "container-item": "sheath" }, - { "item": "m4a1", "ammo-item": "556", "charges": 30, "contents-item": "shoulder_strap" }, + { + "item": "nato_assault_rifle", + "variant": "m4a1", + "ammo-item": "556", + "charges": 30, + "contents-item": "shoulder_strap" + }, { "item": "stanag30", "ammo-item": "556", "charges": 30 }, { "item": "stanag30", "ammo-item": "556", "charges": 30 }, { "item": "stanag30", "ammo-item": "556", "charges": 30 } @@ -2792,7 +2810,7 @@ "entries": [ { "item": "ear_plugs", "custom-flags": [ "no_auto_equip" ] }, { "item": "knife_combat", "container-item": "sheath" }, - { "item": "m4a1", "ammo-item": "556", "contents-item": "shoulder_strap" }, + { "item": "nato_assault_rifle", "variant": "m4a1", "ammo-item": "556", "contents-item": "shoulder_strap" }, { "item": "medium_plus_battery_cell", "ammo-item": "battery", @@ -3787,7 +3805,13 @@ { "item": "mask_dust", "custom-flags": [ "no_auto_equip" ] }, { "item": "stethoscope", "custom-flags": [ "no_auto_equip" ] }, { "item": "knife_combat", "container-item": "sheath" }, - { "item": "m4a1", "ammo-item": "556", "charges": 30, "contents-item": [ "shoulder_strap", "holo_sight" ] } + { + "item": "nato_assault_rifle", + "variant": "m4a1", + "ammo-item": "556", + "charges": 30, + "contents-item": [ "shoulder_strap", "holo_sight" ] + } ] }, "male": [ "boxer_shorts" ], diff --git a/data/json/recipes/recipe_deconstruction.json b/data/json/recipes/recipe_deconstruction.json index 801331e7981a6..e243db8b47a05 100644 --- a/data/json/recipes/recipe_deconstruction.json +++ b/data/json/recipes/recipe_deconstruction.json @@ -1415,7 +1415,7 @@ [ [ "gun_module", 3 ] ], [ [ "flamethrower", 1 ] ], [ [ "tazer", 1 ] ], - [ [ "m4a1", 1 ] ], + [ [ "nato_assault_rifle", 1 ] ], [ [ "pamd68", 1 ] ], [ [ "power_supply", 20 ] ], [ [ "amplifier", 5 ] ], diff --git a/data/json/recipes/weapon/magazines.json b/data/json/recipes/weapon/magazines.json index ab9ec93e9c99f..319728e6bef0b 100644 --- a/data/json/recipes/weapon/magazines.json +++ b/data/json/recipes/weapon/magazines.json @@ -120,18 +120,7 @@ "time": "20 m", "autolearn": true, "tools": [ - [ - [ "acr", -1 ], - [ "ar15", -1 ], - [ "h&k416a5", -1 ], - [ "m249", -1 ], - [ "m27iar", -1 ], - [ "m4a1", -1 ], - [ "m16a4", -1 ], - [ "scar_l", -1 ], - [ "sig552", -1 ], - [ "surv_carbine_223", -1 ] - ], + [ [ "nato_assault_rifle", -1 ], [ "ar15", -1 ], [ "m249", -1 ], [ "m16a4", -1 ], [ "surv_carbine_223", -1 ] ], [ [ "small_repairkit", 10 ], [ "large_repairkit", 5 ] ] ], "using": [ [ "223_casehead", 1 ] ], diff --git a/data/json/recipes/weapon/mods.json b/data/json/recipes/weapon/mods.json index 563c84c5c30a1..5249ee41f0b89 100644 --- a/data/json/recipes/weapon/mods.json +++ b/data/json/recipes/weapon/mods.json @@ -963,9 +963,7 @@ [ "ar15_retool_300blk", -1 ], [ "ar_pistol", -1 ], [ "oa93", -1 ], - [ "h&k416a5", -1 ], - [ "m27iar", -1 ], - [ "m4a1", -1 ], + [ "nato_assault_rifle", -1 ], [ "m16a4", -1 ] ], [ [ "small_repairkit", 40 ], [ "large_repairkit", 40 ] ] diff --git a/data/json/vehicles/helicopters.json b/data/json/vehicles/helicopters.json index 5e7ed7be33e31..ae8b883a006d3 100644 --- a/data/json/vehicles/helicopters.json +++ b/data/json/vehicles/helicopters.json @@ -1030,7 +1030,7 @@ { "x": -9, "y": -1, "chance": 7, "items": [ "rucksack" ] }, { "x": -8, "y": -1, "chance": 5, "items": [ "m9" ] }, { "x": -7, "y": -2, "chance": 5, "items": [ "223" ] }, - { "x": -7, "y": -2, "chance": 5, "magazine": 90, "ammo": 70, "items": [ "m4a1" ] }, + { "x": -7, "y": -2, "chance": 5, "magazine": 90, "ammo": 70, "items": "nato_assault_rifle", "variant": "m4a1" }, { "x": -7, "y": -2, "chance": 7, "items": [ "EMPbomb" ] }, { "x": -7, "y": -2, "chance": 15, "items": [ "mask_gas" ] }, { "x": -7, "y": -2, "chance": 7, "items": [ "flashlight" ], "ammo": 100 }, @@ -1221,7 +1221,7 @@ { "x": -9, "y": -1, "chance": 7, "items": [ "rucksack" ] }, { "x": -8, "y": -1, "chance": 5, "items": [ "m9" ] }, { "x": -7, "y": -2, "chance": 5, "items": [ "223" ] }, - { "x": -7, "y": -2, "chance": 5, "magazine": 90, "ammo": 70, "items": [ "m4a1" ] }, + { "x": -7, "y": -2, "chance": 5, "magazine": 90, "ammo": 70, "items": "nato_assault_rifle", "variant": "m4a1" }, { "x": -7, "y": -2, "chance": 7, "items": [ "EMPbomb" ] }, { "x": -7, "y": -2, "chance": 15, "items": [ "mask_gas" ] }, { "x": -7, "y": -2, "chance": 7, "items": [ "flashlight" ], "ammo": 100 }, @@ -1390,7 +1390,7 @@ { "x": -9, "y": -1, "chance": 7, "items": [ "rucksack" ] }, { "x": -8, "y": -1, "chance": 5, "items": [ "m9" ] }, { "x": -7, "y": -2, "chance": 5, "items": [ "223" ] }, - { "x": -7, "y": -2, "chance": 5, "magazine": 90, "ammo": 70, "items": [ "m4a1" ] }, + { "x": -7, "y": -2, "chance": 5, "magazine": 90, "ammo": 70, "items": "nato_assault_rifle", "variant": "m4a1" }, { "x": -7, "y": -2, "chance": 7, "items": [ "EMPbomb" ] }, { "x": -7, "y": -2, "chance": 15, "items": [ "mask_gas" ] }, { "x": -7, "y": -2, "chance": 7, "items": [ "flashlight" ], "ammo": 100 }, @@ -1507,7 +1507,7 @@ { "x": -6, "y": 1, "chance": 7, "ammo": 70, "items": [ "stanag30" ] }, { "x": -6, "y": 1, "chance": 10, "items": [ "helmet_army" ] }, { "x": -6, "y": 1, "chance": 15, "items": [ "gasfilter_m" ] }, - { "x": -6, "y": 1, "chance": 3, "magazine": 70, "ammo": 70, "items": [ "m4a1" ] }, + { "x": -6, "y": 1, "chance": 100, "magazine": 70, "ammo": 70, "items": "nato_assault_rifle", "variant": "m4a1" }, { "x": -5, "y": 0, "chance": 3, "items": [ "cig_butt" ] }, { "x": -5, "y": 0, "chance": 5, "items": [ "cig" ] }, { "x": -5, "y": 2, "chance": 7, "ammo": 70, "items": [ "stanag30" ] }, @@ -1613,7 +1613,7 @@ { "x": -6, "y": 1, "chance": 7, "ammo": 70, "items": [ "stanag30" ] }, { "x": -6, "y": 1, "chance": 10, "items": [ "helmet_army" ] }, { "x": -6, "y": 1, "chance": 15, "items": [ "gasfilter_m" ] }, - { "x": -6, "y": 1, "chance": 3, "magazine": 70, "ammo": 70, "items": [ "m4a1" ] }, + { "x": -6, "y": 1, "chance": 3, "magazine": 70, "ammo": 70, "items": "nato_assault_rifle", "variant": "m4a1" }, { "x": -5, "y": 0, "chance": 20, "item_groups": [ "remains_soldier" ] }, { "x": -5, "y": 0, "chance": 3, "items": [ "cig_butt" ] }, { "x": -5, "y": 0, "chance": 5, "items": [ "cig" ] }, @@ -1717,7 +1717,7 @@ { "x": -6, "y": 1, "chance": 7, "ammo": 70, "items": [ "stanag30" ] }, { "x": -6, "y": 1, "chance": 10, "items": [ "helmet_army" ] }, { "x": -6, "y": 1, "chance": 15, "items": [ "gasfilter_m" ] }, - { "x": -6, "y": 1, "chance": 3, "magazine": 70, "ammo": 70, "items": [ "m4a1" ] }, + { "x": -6, "y": 1, "chance": 3, "magazine": 70, "ammo": 70, "items": "nato_assault_rifle", "variant": "m4a1" }, { "x": -5, "y": 0, "chance": 20, "item_groups": [ "remains_soldier" ] }, { "x": -5, "y": 0, "chance": 3, "items": [ "cig_butt" ] }, { "x": -5, "y": 0, "chance": 5, "items": [ "cig" ] }, diff --git a/data/mods/BlazeIndustries/vehicleparts/blaze_turrets_vanilla.json b/data/mods/BlazeIndustries/vehicleparts/blaze_turrets_vanilla.json index 7142e33d81d77..4cf46dd686f76 100644 --- a/data/mods/BlazeIndustries/vehicleparts/blaze_turrets_vanilla.json +++ b/data/mods/BlazeIndustries/vehicleparts/blaze_turrets_vanilla.json @@ -9,12 +9,12 @@ "requirements": { "install": { "skills": [ [ "mechanics", 3 ] ] }, "removal": { "skills": [ [ "mechanics", 1 ] ] } } }, { - "id": "mounted_acr", + "id": "mounted_nato_assault_rifle", "copy-from": "turret", "type": "vehicle_part", - "name": { "str": "mounted Remington ACR" }, - "item": "acr", - "breaks_into": [ { "item": "acr", "prob": 50 } ], + "name": { "str": "mounted assault rifle" }, + "item": "nato_assault_rifle", + "breaks_into": [ { "item": "nato_assault_rifle", "prob": 50 } ], "requirements": { "install": { "skills": [ [ "mechanics", 3 ] ] }, "removal": { "skills": [ [ "mechanics", 1 ] ] } } }, { @@ -154,15 +154,6 @@ "breaks_into": [ { "item": "fn_p90", "prob": 50 } ], "requirements": { "install": { "skills": [ [ "mechanics", 3 ] ] }, "removal": { "skills": [ [ "mechanics", 1 ] ] } } }, - { - "id": "mounted_h&k416a5", - "copy-from": "turret", - "type": "vehicle_part", - "name": { "str": "mounted H&K 416A5" }, - "item": "h&k416a5", - "breaks_into": [ { "item": "h&k416a5", "prob": 50 } ], - "requirements": { "install": { "skills": [ [ "mechanics", 3 ] ] }, "removal": { "skills": [ [ "mechanics", 1 ] ] } } - }, { "id": "mounted_hk_g3", "copy-from": "turret", @@ -289,15 +280,6 @@ "breaks_into": [ { "item": "m2010", "prob": 50 } ], "requirements": { "install": { "skills": [ [ "mechanics", 3 ] ] }, "removal": { "skills": [ [ "mechanics", 1 ] ] } } }, - { - "id": "mounted_m27iar", - "copy-from": "turret", - "type": "vehicle_part", - "name": { "str": "mounted M27 IAR" }, - "item": "m27iar", - "breaks_into": [ { "item": "m27iar", "prob": 50 } ], - "requirements": { "install": { "skills": [ [ "mechanics", 3 ] ] }, "removal": { "skills": [ [ "mechanics", 1 ] ] } } - }, { "id": "mounted_m2browning_sawn", "copy-from": "turret", @@ -316,15 +298,6 @@ "breaks_into": [ { "item": "m320", "prob": 50 } ], "requirements": { "install": { "skills": [ [ "mechanics", 4 ] ] }, "removal": { "skills": [ [ "mechanics", 2 ] ] } } }, - { - "id": "mounted_m4a1", - "copy-from": "turret", - "type": "vehicle_part", - "name": { "str": "mounted M4A1" }, - "item": "m4a1", - "breaks_into": [ { "item": "m4a1", "prob": 50 } ], - "requirements": { "install": { "skills": [ [ "mechanics", 3 ] ] }, "removal": { "skills": [ [ "mechanics", 1 ] ] } } - }, { "id": "mounted_m60", "copy-from": "turret", @@ -573,15 +546,6 @@ "breaks_into": [ { "item": "scar_h", "prob": 50 } ], "requirements": { "install": { "skills": [ [ "mechanics", 3 ] ] }, "removal": { "skills": [ [ "mechanics", 1 ] ] } } }, - { - "id": "mounted_scar_l", - "copy-from": "turret", - "type": "vehicle_part", - "name": { "str": "mounted FN SCAR-L" }, - "item": "scar_l", - "breaks_into": [ { "item": "scar_l", "prob": 50 } ], - "requirements": { "install": { "skills": [ [ "mechanics", 3 ] ] }, "removal": { "skills": [ [ "mechanics", 1 ] ] } } - }, { "id": "mounted_shotgun_d", "copy-from": "turret", diff --git a/data/mods/Fuji_Mil_Prof/prof/itemgroups_prof.json b/data/mods/Fuji_Mil_Prof/prof/itemgroups_prof.json index 4e705e6bf5c0c..3c237c4f6d6eb 100644 --- a/data/mods/Fuji_Mil_Prof/prof/itemgroups_prof.json +++ b/data/mods/Fuji_Mil_Prof/prof/itemgroups_prof.json @@ -3,7 +3,7 @@ "type": "item_group", "subtype": "collection", "id": "holster_supp_MEU", - "entries": [ { "item": "m1911_MEU", "ammo-item": "45_acp", "charges": 7, "contents-item": [ "suppressor" ] } ] + "entries": [ { "item": "m1911", "variant": "m1911_MEU", "ammo-item": "45_acp", "charges": 7, "contents-item": [ "suppressor" ] } ] }, { "type": "item_group", diff --git a/data/mods/Generic_Guns/firearms/gg_firearms_migration.json b/data/mods/Generic_Guns/firearms/gg_firearms_migration.json index 76fa0bad19c1a..428c44560049f 100644 --- a/data/mods/Generic_Guns/firearms/gg_firearms_migration.json +++ b/data/mods/Generic_Guns/firearms/gg_firearms_migration.json @@ -86,7 +86,6 @@ "sig_40", "hptjcp", "m1911", - "m1911_MEU", "walther_ppq_45", "hptjhp", "tokarev", @@ -111,7 +110,6 @@ "walther_ppq_40", "tommygun", "usp_45", - "mk23", "fn57", "glock_17", "kpf9", @@ -201,18 +199,12 @@ }, { "id": [ - "h&k416a5", "m1918", "acr_300blk", "hk417_13", - "acr", - "m4a1", - "m16a3", "m16a4", - "m38dmr", - "m4_cqbr", + "nato_assault_rifle", "m231pfw", - "scar_l", "scar_h", "sig_mcx_rattler_sbr", "rm51_assault_rifle", @@ -238,7 +230,7 @@ "replace": "rifle_huge_hmg" }, { - "id": [ "m134", "m249", "m27iar", "m240", "m60", "rm614_lmg", "rm298" ], + "id": [ "m134", "m249", "m240", "m60", "rm614_lmg", "rm298" ], "type": "MIGRATION", "replace": "rifle_lmg" }, diff --git a/data/mods/National_Guard_Camp/item_groups.json b/data/mods/National_Guard_Camp/item_groups.json index 71b4f9af03aa9..0ee98e5838696 100644 --- a/data/mods/National_Guard_Camp/item_groups.json +++ b/data/mods/National_Guard_Camp/item_groups.json @@ -152,7 +152,13 @@ { "group": "robots", "prob": 100 }, { "item": "storage_battery", "prob": 40, "charges-min": 200, "charges-max": 1000 }, { "item": "223", "prob": 20, "charges-min": 10, "charges-max": 30 }, - { "item": "scar_l", "prob": 20, "damage": [ 1, 2 ], "contents-item": [ "stanag30" ] } + { + "item": "nato_assault_rifle", + "variant": "scar_l", + "prob": 20, + "damage": [ 1, 2 ], + "contents-item": [ "stanag30" ] + } ] } ] diff --git a/data/mods/package_bionic_professions/bionic_professions.json b/data/mods/package_bionic_professions/bionic_professions.json index ce95cdd416dd0..e1b6671f659df 100644 --- a/data/mods/package_bionic_professions/bionic_professions.json +++ b/data/mods/package_bionic_professions/bionic_professions.json @@ -483,7 +483,8 @@ { "item": "ear_plugs", "custom-flags": [ "no_auto_equip" ] }, { "item": "sheath", "contents-item": "knife_combat" }, { - "item": "h&k416a5", + "item": "nato_assault_rifle", + "variant": "h&k416a5", "ammo-item": "556", "charges": 30, "contents-item": [ "shoulder_strap", "acog_scope" ] diff --git a/doc/ITEM_SPAWN.md b/doc/ITEM_SPAWN.md index 53817e324d1f8..2e7463624ba2e 100644 --- a/doc/ITEM_SPAWN.md +++ b/doc/ITEM_SPAWN.md @@ -93,6 +93,7 @@ Each entry can have more values (shown above as `...`). They allow further prop "ammo-group": "", "container-group": "", "sealed": +"variant": "artifact": ``` @@ -104,6 +105,8 @@ Each entry can have more values (shown above as `...`). They allow further prop `sealed`: If true, a container will be sealed when the item spawns. Default is `true`. +`variant`: A valid gun variant id for this item. + `artifact`: This object determines that the item or group that is spawned by this entry will become an artifact. Here is an example: ```json "artifact": { "procgen_id": "cult", "rules": { "power_level": 1000, "max_attributes": 5, "max_negative_power": -2000 } } diff --git a/doc/JSON_INFO.md b/doc/JSON_INFO.md index 62854253daf15..7fbe547bcb01a 100644 --- a/doc/JSON_INFO.md +++ b/doc/JSON_INFO.md @@ -2684,6 +2684,15 @@ Guns can be defined like this: "blackpowder_tolerance": 8,// One in X chance to get clogged up (per shot) when firing blackpowder ammunition (higher is better). Optional, default is 8. "min_cycle_recoil": 0, // Minimum ammo recoil for gun to be able to fire more than once per attack. "burst": 5, // Number of shots fired in burst mode +"variants": [ // Cosmetic variants this gun can have + { + "id": "varianta", // id used in spawning to spawn this variant specifically + "name": { "str": "Variant A pistol" }, // The name used instead of the default name when this variant is selected + "description": "A fancy variant A pistol", // The description used instead of the default when this variant is selected + "ascii_picture": "valid_ascii_art_id", // An ASCII art picture used when this variant is selected. If there is none, the default (if it exists) is used. + "weight": 2 // The relative chance of this variant being selected over other variants when this item is spawned with no explicit variant. Defaults to 0. If it is 0, this variant will not be selected + } +], "clip_size": 100, // Maximum amount of ammo that can be loaded "ups_charges": 0, // Additionally to the normal ammo (if any), a gun can require some charges from an UPS. This also works on mods. Attaching a mod with ups_charges will add/increase ups drain on the weapon. "ammo_to_fire" 1, // Amount of ammo used diff --git a/doc/MAPGEN.md b/doc/MAPGEN.md index 2e765138c9f9b..0724a929dc7f0 100644 --- a/doc/MAPGEN.md +++ b/doc/MAPGEN.md @@ -928,6 +928,7 @@ matching magazine and ammo for guns. | chance | (optional, integer) x in 100 chance of item(s) spawning. Defaults to 100. | ammo | (optional, integer) x in 100 chance of item(s) spawning with the default amount of ammo. Defaults to 0. | magazine | (optional, integer) x in 100 chance of item(s) spawning with the default magazine. Defaults to 0. +| variant | (optional, string), gun variant id for the spawned item ### Plant seeds in a planter with "sealed_item" diff --git a/doc/VEHICLES_JSON.md b/doc/VEHICLES_JSON.md index 0cd720d0c9187..403bfeb9ef866 100644 --- a/doc/VEHICLES_JSON.md +++ b/doc/VEHICLES_JSON.md @@ -70,4 +70,6 @@ TYPE and DATA may be one of: ``` the optional keyword "chance" provides an X in 100 chance that a particular item definition will spawn. +If a single item is specified through `"items"`, a gun variant for it can be specified through `"variant"`. + Multiple lines of items may share the same X and Y values. diff --git a/lang/extract_json_strings.py b/lang/extract_json_strings.py index 6a21764f8b64d..67658db0b56b0 100755 --- a/lang/extract_json_strings.py +++ b/lang/extract_json_strings.py @@ -153,7 +153,6 @@ def warning_supressed(filename): "json_flag", "keybinding", "LOOT_ZONE", - "MAGAZINE", "map_extra", "MOD_INFO", "MONSTER", @@ -476,6 +475,12 @@ def extract_gun(item): if "description" in item: description = item.get("description") writestr(outfile, description) + if "variants" in item: + for variant in item.get("variants"): + vname = variant.get("name") + writestr(outfile, vname, pl_fmt=True) + vdesc = variant.get("description") + writestr(outfile, vdesc) if "modes" in item: modes = item.get("modes") for fire_mode in modes: @@ -490,6 +495,25 @@ def extract_gun(item): if "reload_noise" in item: item_reload_noise = item.get("reload_noise") writestr(outfile, item_reload_noise) + + +def extract_magazine(item): + outfile = get_outfile("magazine") + if "name" in item: + item_name = item.get("name") + if item["type"] in needs_plural: + writestr(outfile, item_name, pl_fmt=True) + else: + writestr(outfile, item_name) + if "description" in item: + description = item.get("description") + writestr(outfile, description) + if "variants" in item: + for variant in item.get("variants"): + vname = variant.get("name") + writestr(outfile, vname, pl_fmt=True) + vdesc = variant.get("description") + writestr(outfile, vdesc) if "use_action" in item: use_action = item.get("use_action") item_name = item.get("name") @@ -976,6 +1000,7 @@ def extract_vehicle_part_category(item): "GUN": extract_gun, "GUNMOD": extract_gunmod, "harvest": extract_harvest, + "MAGAZINE": extract_magazine, "mapgen": extract_mapgen, "martial_art": extract_martial_art, "material": extract_material, diff --git a/src/cata_io.h b/src/cata_io.h index 19f3aeea81bba..93c2ed4d36348 100644 --- a/src/cata_io.h +++ b/src/cata_io.h @@ -292,6 +292,26 @@ class JsonObjectInputArchive : public JsonObject load( ident ); return true; } + /** + * The 'I-give-up' template for gun variant data + */ + template + bool io( const std::string &name, T &pointer, + const LoadFunc &load, + const SaveFunc &save, bool required = false ) { + // Only used by the matching function in the output archive classes. + ( void ) save; + std::string ident; + if( !io( name, ident ) ) { + if( required ) { + JsonObject::throw_error( std::string( "required member is missing: " ) + name ); + } + pointer = nullptr; + return false; + } + load( ident ); + return true; + } template bool io( const std::string &name, T *&pointer, const std::function &load, @@ -421,6 +441,21 @@ class JsonObjectOutputArchive } return io( name, save( *pointer ) ); } + /** + * The I-give-up load function for gun variants + */ + template + bool io( const std::string &name, const T &pointer, + const LoadFunc &, + const SaveFunc &save, bool required = false ) { + if( pointer == nullptr ) { + if( required ) { + throw JsonError( "a required member is null: " + name ); + } + return false; + } + return io( name, save( pointer ) ); + } template bool io( const std::string &name, const T *pointer, const std::function &load, diff --git a/src/item.cpp b/src/item.cpp index ffefcfaa8c2a8..a93cdcc2f9bb5 100644 --- a/src/item.cpp +++ b/src/item.cpp @@ -265,6 +265,7 @@ item::item() : bday( calendar::start_of_cataclysm ) type = nullitem(); charges = 0; contents = item_contents( type->pockets ); + select_gun_variant(); } item::item( const itype *type, time_point turn, int qty ) : type( type ), bday( turn ) @@ -290,6 +291,7 @@ item::item( const itype *type, time_point turn, int qty ) : type( type ), bday( set_var( "NANOFAB_ITEM_ID", nanofab_recipe.str() ); } + select_gun_variant(); if( type->gun ) { for( const itype_id &mod : type->gun->built_in_mods ) { item it( mod, turn, qty ); @@ -1014,6 +1016,11 @@ bool item::stacks_with( const item &rhs, bool check_components, bool combine_liq if( is_relic() && rhs.is_relic() && !( *relic_data == *rhs.relic_data ) ) { return false; } + if( has_gun_variant() != rhs.has_gun_variant() || + ( has_gun_variant() && rhs.has_gun_variant() && + gun_variant().id != rhs.gun_variant().id ) ) { + return false; + } if( charges != 0 && rhs.charges != 0 && is_money() ) { // Dealing with nonempty cash cards return true; @@ -1679,6 +1686,8 @@ void item::basic_info( std::vector &info, const iteminfo_query *parts, info.push_back( iteminfo( "DESCRIPTION", snippet.value().translated() ) ); } else if( idescription != item_vars.end() ) { info.push_back( iteminfo( "DESCRIPTION", idescription->second ) ); + } else if( has_gun_variant() ) { + info.push_back( iteminfo( "DESCRIPTION", gun_variant().alt_description.translated() ) ); } else { if( has_flag( flag_MAGIC_FOCUS ) ) { info.push_back( iteminfo( "DESCRIPTION", @@ -4191,7 +4200,10 @@ void item::final_info( std::vector &info, const iteminfo_query *parts, contents_info( info, parts, batch, debug ); if( get_option( "ENABLE_ASCII_ART" ) ) { - const ascii_art_id art = type->picture_id; + ascii_art_id art = type->picture_id; + if( has_gun_variant() && gun_variant().art.is_valid() ) { + art = gun_variant().art; + } if( art.is_valid() ) { for( const std::string &line : art->picture ) { info.push_back( iteminfo( "DESCRIPTION", line ) ); @@ -6785,6 +6797,74 @@ bool item::is_gun() const return !!type->gun; } +void item::select_gun_variant() +{ + weighted_int_list variants; + if( is_gun() ) { + for( const gun_variant_data &gv : type->gun->variants ) { + variants.add( gv.id, gv.weight ); + } + } else if( !!type->magazine ) { + for( const gun_variant_data &gv : type->magazine->variants ) { + variants.add( gv.id, gv.weight ); + } + } else { + return; + } + + const std::string *selected = variants.pick(); + if( !selected ) { + // No variants exist + return; + } + + set_gun_variant( *selected ); +} + +bool item::has_gun_variant( bool check_option ) const +{ + return _gun_variant != nullptr && + ( !check_option || get_option( "SHOW_GUN_VARIANTS" ) ); +} + +const gun_variant_data &item::gun_variant() const +{ + return *_gun_variant; +} + +void item::set_gun_variant( const std::string &variant ) +{ + if( variant.empty() || ( is_gun() && type->gun->variants.empty() ) || ( !!type->magazine && + type->magazine->variants.empty() ) ) { + return; + } + + if( is_gun() ) { + for( const gun_variant_data &option : type->gun->variants ) { + if( option.id == variant ) { + _gun_variant = &option; + return; + } + } + } else if( !!type->magazine ) { + for( const gun_variant_data &option : type->magazine->variants ) { + if( option.id == variant ) { + _gun_variant = &option; + return; + } + } + } else { + return; + } + + debugmsg( "Gun %s has no variant %s!", typeId().str(), variant ); +} + +void item::clear_gun_variant() +{ + _gun_variant = nullptr; +} + bool item::is_firearm() const { return is_gun() && !has_flag( flag_PRIMITIVE_RANGED_WEAPON ); @@ -10463,6 +10543,8 @@ std::string item::type_name( unsigned int quantity ) const } } else if( iter != item_vars.end() ) { return iter->second; + } else if( has_gun_variant() ) { + ret_name = gun_variant().brand_name.translated(); } else { ret_name = type->nname( quantity ); } diff --git a/src/item.h b/src/item.h index f62a7a438f94d..9569cade94e2c 100644 --- a/src/item.h +++ b/src/item.h @@ -51,6 +51,7 @@ class player; class recipe; class relic; struct armor_portion_data; +struct gun_variant_data; struct islot_comestible; struct itype; struct mtype; @@ -1803,6 +1804,27 @@ class item : public visitable */ bool is_gun() const; + /** + * Does this item have a gun variant associated with it + * If check_option, the return of this is dependent on the SHOW_GUN_VARIANTS option + */ + bool has_gun_variant( bool check_option = true ) const; + + /** + * The gun variant associated with this item + */ + const gun_variant_data &gun_variant() const; + + /** + * Set the gun variant of this item + */ + void set_gun_variant( const std::string &variant ); + + /** + * For debug use only + */ + void clear_gun_variant(); + /** Quantity of energy currently loaded in tool or battery */ units::energy energy_remaining() const; @@ -2306,6 +2328,13 @@ class item : public visitable std::string corpse_name; // Name of the late lamented std::set techniques; // item specific techniques + // Select a random variant from the possibilities + // Intended to be called when no explicit variant is set + void select_gun_variant(); + + // If the item has a gun variant, this points to it + const gun_variant_data *_gun_variant = nullptr; + /** * Data for items that represent in-progress crafts. */ diff --git a/src/item_factory.cpp b/src/item_factory.cpp index 8e7c3c998c205..e974b0e910d99 100644 --- a/src/item_factory.cpp +++ b/src/item_factory.cpp @@ -1767,6 +1767,20 @@ void Item_factory::load_wheel( const JsonObject &jo, const std::string &src ) } } +void gun_variant_data::deserialize( JsonIn &jsin ) +{ + load( jsin.get_object() ); +} + +void gun_variant_data::load( const JsonObject &jo ) +{ + mandatory( jo, false, "id", id ); + mandatory( jo, false, "name", brand_name ); + mandatory( jo, false, "description", alt_description ); + optional( jo, false, "ascii_picture", art ); + optional( jo, false, "weight", weight ); +} + void Item_factory::load( islot_gun &slot, const JsonObject &jo, const std::string &src ) { bool strict = src == "dda"; @@ -1801,6 +1815,8 @@ void Item_factory::load( islot_gun &slot, const JsonObject &jo, const std::strin assign( jo, "ammo_effects", slot.ammo_effects, strict ); assign( jo, "ammo_to_fire", slot.ammo_to_fire, strict, 1 ); + optional( jo, false, "variants", slot.variants ); + if( jo.has_array( "valid_mod_locations" ) ) { slot.valid_mod_locations.clear(); for( JsonArray curr : jo.get_array( "valid_mod_locations" ) ) { @@ -2420,6 +2436,8 @@ void Item_factory::load( islot_magazine &slot, const JsonObject &jo, const std:: assign( jo, "default_ammo", slot.default_ammo, strict ); assign( jo, "reload_time", slot.reload_time, strict, 0 ); assign( jo, "linkage", slot.linkage, strict ); + + optional( jo, false, "variants", slot.variants ); } void Item_factory::load_magazine( const JsonObject &jo, const std::string &src ) @@ -3137,6 +3155,7 @@ void Item_factory::load_migration( const JsonObject &jo ) { migration m; assign( jo, "replace", m.replace ); + assign( jo, "variant", m.variant ); assign( jo, "flags", m.flags ); assign( jo, "charges", m.charges ); assign( jo, "contents", m.contents ); @@ -3186,6 +3205,8 @@ void Item_factory::migrate_item( const itype_id &id, item &obj ) obj.charges = iter->second.charges; } + obj.set_gun_variant( iter->second.variant ); + for( const migration::content &it : iter->second.contents ) { int count = it.count; item content( it.id, obj.birthday(), 1 ); @@ -3487,6 +3508,10 @@ void Item_factory::add_entry( Item_group &ig, const JsonObject &obj, const std:: for( const auto &cf : custom_flags ) { modifier.custom_flags.emplace_back( cf ); } + if( obj.has_member( "variant" ) ) { + modifier.variant = obj.get_string( "variant" ); + use_modifier = true; + } if( use_modifier ) { sptr->modifier.emplace( std::move( modifier ) ); diff --git a/src/item_factory.h b/src/item_factory.h index 63d9847e94976..e63ec6784d73e 100644 --- a/src/item_factory.h +++ b/src/item_factory.h @@ -44,6 +44,7 @@ class migration { public: itype_id id; + std::string variant; itype_id replace; std::set flags; int charges = 0; diff --git a/src/item_group.cpp b/src/item_group.cpp index b0cfef5f57ef5..b7bc98a8c8ae4 100644 --- a/src/item_group.cpp +++ b/src/item_group.cpp @@ -391,6 +391,8 @@ void Item_modifier::modify( item &new_item, const std::string &context ) const } } + new_item.set_gun_variant( variant ); + // create container here from modifier or from default to get max charges later item cont; if( container != nullptr ) { @@ -610,11 +612,17 @@ Item_group::Item_group( Type t, int probability, int ammo_chance, int magazine_c } } -void Item_group::add_item_entry( const itype_id &itemid, int probability ) +void Item_group::add_item_entry( const itype_id &itemid, int probability, + const std::string &variant ) { std::string entry_context = "item " + itemid.str() + " within " + context(); - add_entry( std::make_unique( - itemid.str(), Single_item_creator::S_ITEM, probability, entry_context ) ); + std::unique_ptr added = std::make_unique( + itemid.str(), Single_item_creator::S_ITEM, probability, entry_context ); + if( !variant.empty() ) { + added->modifier.emplace(); + added->modifier->variant = variant; + } + add_entry( std::move( added ) ); } void Item_group::add_group_entry( const item_group_id &groupid, int probability ) diff --git a/src/item_group.h b/src/item_group.h index d6c9eae7db489..9987d7f75495f 100644 --- a/src/item_group.h +++ b/src/item_group.h @@ -250,6 +250,11 @@ class Item_modifier */ std::vector custom_flags; + /** + * gun variant id, for guns with variants + */ + std::string variant; + /** * Custom sub set of snippets to be randomly chosen from and then applied to the item. */ @@ -344,7 +349,8 @@ class Item_group : public Item_spawn_data */ using prop_list = std::vector >; - void add_item_entry( const itype_id &itemid, int probability ); + void add_item_entry( const itype_id &itemid, int probability, + const std::string &variant = "" ); void add_group_entry( const item_group_id &groupid, int probability ); /** * Once the relevant data has been read from JSON, this function is always called (either from diff --git a/src/itype.h b/src/itype.h index 471013f573dc6..05c6de659d557 100644 --- a/src/itype.h +++ b/src/itype.h @@ -458,8 +458,21 @@ struct islot_wheel { void deserialize( JsonIn &jsin ); }; +struct gun_variant_data { + std::string id; + translation brand_name; + translation alt_description; + ascii_art_id art; + + int weight = 0; + + void deserialize( JsonIn &jsin ); + void load( const JsonObject &jo ); +}; + // TODO: this shares a lot with the ammo item type, merge into a separate slot type? struct islot_gun : common_ranged_data { + std::vector variants; /** * What skill this gun uses. */ @@ -646,6 +659,7 @@ struct islot_gunmod : common_ranged_data { }; struct islot_magazine { + std::vector variants; /** What type of ammo this magazine can be loaded with */ std::set type; diff --git a/src/map.cpp b/src/map.cpp index 3ad76f462f746..6549a3c0a099b 100644 --- a/src/map.cpp +++ b/src/map.cpp @@ -4283,9 +4283,9 @@ void map::spawn_artifact( const tripoint &p, const relic_procgen_id &id ) add_item_or_charges( p, id->create_item( rules ) ); } -void map::spawn_item( const tripoint &p, const itype_id &type_id, - const unsigned quantity, const int charges, - const time_point &birthday, const int damlevel, const std::set &flags ) +void map::spawn_item( const tripoint &p, const itype_id &type_id, const unsigned quantity, + const int charges, const time_point &birthday, const int damlevel, const std::set &flags, + const std::string &variant ) { if( type_id.is_null() ) { return; @@ -4300,6 +4300,7 @@ void map::spawn_item( const tripoint &p, const itype_id &type_id, } // spawn the item item new_item( type_id, birthday ); + new_item.set_gun_variant( variant ); if( one_in( 3 ) && new_item.has_flag( flag_VARSIZE ) ) { new_item.set_flag( flag_FIT ); } diff --git a/src/map.h b/src/map.h index 11a3728a1cd5d..c18cdbf887812 100644 --- a/src/map.h +++ b/src/map.h @@ -1091,12 +1091,13 @@ class map void spawn_item( const tripoint &p, const itype_id &type_id, unsigned quantity = 1, int charges = 0, const time_point &birthday = calendar::start_of_cataclysm, int damlevel = 0, - const std::set &flags = {} ); + const std::set &flags = {}, const std::string &variant = "" ); void spawn_item( const point &p, const itype_id &type_id, unsigned quantity = 1, int charges = 0, const time_point &birthday = calendar::start_of_cataclysm, int damlevel = 0, - const std::set &flags = {} ) { - spawn_item( tripoint( p, abs_sub.z ), type_id, quantity, charges, birthday, damlevel, flags ); + const std::set &flags = {}, const std::string &variant = "" ) { + spawn_item( tripoint( p, abs_sub.z ), type_id, quantity, charges, birthday, damlevel, flags, + variant ); } // FIXME: remove these overloads and require spawn_item to take an @@ -1104,14 +1105,15 @@ class map void spawn_item( const tripoint &p, const std::string &type_id, unsigned quantity = 1, int charges = 0, const time_point &birthday = calendar::start_of_cataclysm, int damlevel = 0, - const std::set &flags = {} ) { - spawn_item( p, itype_id( type_id ), quantity, charges, birthday, damlevel, flags ); + const std::set &flags = {}, const std::string &variant = "" ) { + spawn_item( p, itype_id( type_id ), quantity, charges, birthday, damlevel, flags, variant ); } void spawn_item( const point &p, const std::string &type_id, unsigned quantity = 1, int charges = 0, const time_point &birthday = calendar::start_of_cataclysm, int damlevel = 0, - const std::set &flags = {} ) { - spawn_item( tripoint( p, abs_sub.z ), type_id, quantity, charges, birthday, damlevel, flags ); + const std::set &flags = {}, const std::string &variant = "" ) { + spawn_item( tripoint( p, abs_sub.z ), type_id, quantity, charges, birthday, damlevel, flags, + variant ); } units::volume max_volume( const tripoint &p ); units::volume free_volume( const tripoint &p ); diff --git a/src/mapgen.cpp b/src/mapgen.cpp index 1517e3a0e57a0..03646c4ae5e30 100644 --- a/src/mapgen.cpp +++ b/src/mapgen.cpp @@ -1198,7 +1198,11 @@ class jmapgen_loot : public jmapgen_piece if( group.is_empty() ) { // Migrations are applied to item *groups* on load, but single item spawns must be // migrated individually - result_group.add_item_entry( item_controller->migrate_id( ity ), 100 ); + std::string variant; + if( jsi.has_string( "variant" ) ) { + variant = jsi.get_string( "variant" ); + } + result_group.add_item_entry( item_controller->migrate_id( ity ), 100, variant ); } else { result_group.add_group_entry( group, 100 ); } @@ -1424,6 +1428,7 @@ class jmapgen_spawn_item : public jmapgen_piece { public: itype_id type; + std::string variant; jmapgen_int amount; jmapgen_int chance; std::set flags; @@ -1432,6 +1437,9 @@ class jmapgen_spawn_item : public jmapgen_piece , amount( jsi, "amount", 1, 1 ) , chance( jsi, "chance", 100, 100 ) , flags( jsi.get_tags( "custom-flags" ) ) { + if( jsi.has_string( "variant" ) ) { + variant = jsi.get_string( "variant" ); + } // Itemgroups apply migrations when being loaded, but we need to migrate // individual items here. type = item_controller->migrate_id( type ); @@ -1449,7 +1457,7 @@ class jmapgen_spawn_item : public jmapgen_piece int spawn_count = ( c == 100 ) ? 1 : roll_remainder( c * spawn_rate / 100.0f ); for( int i = 0; i < spawn_count; i++ ) { dat.m.spawn_item( point( x.get(), y.get() ), type, amount.get(), - 0, calendar::start_of_cataclysm, 0, flags ); + 0, calendar::start_of_cataclysm, 0, flags, variant ); } } }; diff --git a/src/options.cpp b/src/options.cpp index 4abcbb2278f9a..9e25c2fd6cf20 100644 --- a/src/options.cpp +++ b/src/options.cpp @@ -1399,6 +1399,16 @@ void options_manager::add_options_interface() add_empty_line(); + add( "SHOW_GUN_VARIANTS", "interface", to_translation( "Show gun brand names" ), + to_translation( "Show brand names for guns, intead of generic functional names - 'm4a1' or 'h&k416a5' instead of 'NATO assault rifle'." ), + false ); + add( "AMMO_IN_NAMES", "interface", to_translation( "Add ammo to weapon/magazine names" ), + to_translation( "If true, the default ammo is added to weapon and magazine names. For example \"Mosin-Nagant M44 (4/5)\" becomes \"Mosin-Nagant M44 (4/5 7.62x54mm)\"." ), + true + ); + + add_empty_line(); + add( "SDL_KEYBOARD_MODE", "interface", to_translation( "Use key code input mode" ), to_translation( "Use key code or symbol input on SDL. " "Symbol is recommended for non-qwerty layouts since currently " @@ -1651,10 +1661,6 @@ void options_manager::add_options_interface() to_translation( "If true, show item symbols in inventory and pick up menu." ), false ); - add( "AMMO_IN_NAMES", "interface", to_translation( "Add ammo to weapon/magazine names" ), - to_translation( "If true, the default ammo is added to weapon and magazine names. For example \"Mosin-Nagant M44 (4/5)\" becomes \"Mosin-Nagant M44 (4/5 7.62x54mm)\"." ), - true - ); add_empty_line(); diff --git a/src/savegame_json.cpp b/src/savegame_json.cpp index 3f6e79ff311e9..0230396e9c70a 100644 --- a/src/savegame_json.cpp +++ b/src/savegame_json.cpp @@ -2470,6 +2470,13 @@ void item::io( Archive &archive ) return i.id.str(); } ); archive.io( "craft_data", craft_data_, decltype( craft_data_ )() ); + const auto gvload = [this]( const std::string & variant ) { + set_gun_variant( variant ); + }; + const auto gvsave = []( const gun_variant_data * gv ) { + return gv->id; + }; + archive.io( "variant", _gun_variant, gvload, gvsave, false ); archive.io( "light", light.luminance, nolight.luminance ); archive.io( "light_width", light.width, nolight.width ); archive.io( "light_dir", light.direction, nolight.direction ); diff --git a/src/veh_type.cpp b/src/veh_type.cpp index 006935b9c11a8..1af5c6fe09cca 100644 --- a/src/veh_type.cpp +++ b/src/veh_type.cpp @@ -1162,7 +1162,13 @@ void vehicle_prototype::load( const JsonObject &jo ) spawn_info.read( "items", next_spawn.item_ids, true ); } else if( spawn_info.has_string( "items" ) ) { //Treat single item as array - next_spawn.item_ids.push_back( itype_id( spawn_info.get_string( "items" ) ) ); + // And read the gun variant (if it exists) + if( spawn_info.has_string( "variant" ) ) { + const std::string variant = spawn_info.get_string( "variant" ); + next_spawn.variant_ids.emplace_back( itype_id( spawn_info.get_string( "items" ) ), variant ); + } else { + next_spawn.item_ids.push_back( itype_id( spawn_info.get_string( "items" ) ) ); + } } if( spawn_info.has_array( "item_groups" ) ) { //Pick from a group of items, just like map::place_items diff --git a/src/veh_type.h b/src/veh_type.h index 475bd7b5cc5b9..923a3d2677d24 100644 --- a/src/veh_type.h +++ b/src/veh_type.h @@ -474,6 +474,8 @@ struct vehicle_item_spawn { /** Chance [0-100%] for items to spawn with their default magazine (if any) */ int with_magazine = 0; std::vector item_ids; + // item_ids, but for items with variants specified + std::vector> variant_ids; std::vector item_groups; }; diff --git a/src/vehicle.cpp b/src/vehicle.cpp index 0063764704479..bacabf0432ed8 100644 --- a/src/vehicle.cpp +++ b/src/vehicle.cpp @@ -5473,7 +5473,7 @@ void vehicle::place_spawn_items() } const float spawn_rate = get_option( "ITEM_SPAWNRATE" ); - for( const vehicle_item_spawn &spawn : type.obj().item_spawns ) { + for( const vehicle_item_spawn &spawn : type->item_spawns ) { int part = part_with_feature( spawn.pos, "CARGO", false ); if( part < 0 ) { debugmsg( "No CARGO parts at (%d, %d) of %s!", spawn.pos.x, spawn.pos.y, name ); @@ -5493,6 +5493,13 @@ void vehicle::place_spawn_items() created.emplace_back( item( e ).in_its_container() ); } } + for( const std::pair &e : spawn.variant_ids ) { + if( rng_float( 0, 1 ) < spawn_rate ) { + item added = item( e.first ).in_its_container(); + added.set_gun_variant( e.second ); + created.push_back( added ); + } + } for( const item_group_id &e : spawn.item_groups ) { item_group::ItemList group_items = item_group::items_from( e, calendar::start_of_cataclysm, spawn_flags::use_spawn_rate ); diff --git a/src/wish.cpp b/src/wish.cpp index 0ca3fbe0cfd89..cc288a1922e9a 100644 --- a/src/wish.cpp +++ b/src/wish.cpp @@ -601,7 +601,10 @@ void debug_menu::wishitem( player *p, const tripoint &pos ) } std::vector> opts; for( const itype *i : item_controller->all() ) { - opts.emplace_back( item( i, calendar::turn_zero ).tname( 1, false ), i ); + item option( i, calendar::turn_zero ); + // Only display the generic name if it has variants + option.clear_gun_variant(); + opts.emplace_back( option.tname( 1, false ), i ); } std::sort( opts.begin(), opts.end(), localized_compare ); std::vector itypes; diff --git a/tests/pocket_test.cpp b/tests/pocket_test.cpp index 490134c2426ce..aa9e60002b537 100644 --- a/tests/pocket_test.cpp +++ b/tests/pocket_test.cpp @@ -1335,7 +1335,7 @@ TEST_CASE( "character best pocket", "[pocket][character][best]" ) TEST_CASE( "guns and gunmods", "[pocket][gunmod]" ) { - item m4a1( "m4a1" ); + item m4a1( "nato_assault_rifle" ); item strap( "shoulder_strap" ); // Guns cannot "contain" gunmods, but gunmods can be inserted into guns CHECK_FALSE( m4a1.contents.can_contain( strap ).success() ); diff --git a/tests/reload_magazine_test.cpp b/tests/reload_magazine_test.cpp index c9bd8ce63a3cf..a598812d2397f 100644 --- a/tests/reload_magazine_test.cpp +++ b/tests/reload_magazine_test.cpp @@ -19,7 +19,7 @@ struct itype; TEST_CASE( "reload_magazine", "[magazine] [visitable] [item] [item_location]" ) { - const itype_id gun_id( "m4a1" ); + const itype_id gun_id( "nato_assault_rifle" ); const ammotype gun_ammo( "223" ); const itype_id ammo_id( "556" ); // any type of compatible ammo const itype_id alt_ammo( "223" ); // any alternative type of compatible ammo From 2a93dc69b61d7e7fd0b9463d9fa0ea2d1977fa3a Mon Sep 17 00:00:00 2001 From: Bella Date: Sat, 27 Feb 2021 11:19:18 -0600 Subject: [PATCH 314/453] Turbine CBM Obsoletion (#47774) --- data/mods/Aftershock/itemgroups/bionics_groups.json | 6 ++---- data/mods/Aftershock/items/cbms.json | 9 --------- data/mods/Aftershock/items/obsolete.json | 9 +++++++++ data/mods/Aftershock/player/bionics.json | 11 ----------- data/mods/Aftershock/player/obsolete.json | 11 +++++++++++ 5 files changed, 22 insertions(+), 24 deletions(-) diff --git a/data/mods/Aftershock/itemgroups/bionics_groups.json b/data/mods/Aftershock/itemgroups/bionics_groups.json index f5fd0cd54948a..d264c170db869 100644 --- a/data/mods/Aftershock/itemgroups/bionics_groups.json +++ b/data/mods/Aftershock/itemgroups/bionics_groups.json @@ -4,7 +4,6 @@ "type": "item_group", "items": [ [ "bn_bio_solar", 10 ], - [ "afs_bio_wind_turbine", 5 ], [ "afs_bio_missiles", 10 ], [ "afs_bio_linguistic_coprocessor", 10 ], [ "afs_bio_dopamine_stimulators", 10 ], @@ -16,7 +15,7 @@ { "id": "bionics_common", "type": "item_group", - "items": [ [ "bn_bio_solar", 10 ], [ "afs_bio_wind_turbine", 5 ], [ "afs_bio_linguistic_coprocessor", 8 ] ] + "items": [ [ "bn_bio_solar", 10 ], [ "afs_bio_linguistic_coprocessor", 8 ] ] }, { "id": "bionics_mil", @@ -32,14 +31,13 @@ { "id": "bionics_sci", "type": "item_group", - "items": [ [ "bn_bio_solar", 5 ], [ "afs_bio_wind_turbine", 2 ] ] + "items": [ [ "bn_bio_solar", 5 ] ] }, { "id": "bionics_op", "type": "item_group", "items": [ [ "bn_bio_solar", 15 ], - [ "afs_bio_wind_turbine", 10 ], [ "afs_bio_missiles", 10 ], [ "afs_bio_melee_counteraction", 10 ], [ "afs_bio_melee_optimization_unit", 10 ], diff --git a/data/mods/Aftershock/items/cbms.json b/data/mods/Aftershock/items/cbms.json index 627339be2c031..77695b5adf4eb 100644 --- a/data/mods/Aftershock/items/cbms.json +++ b/data/mods/Aftershock/items/cbms.json @@ -8,15 +8,6 @@ "price": 350000, "difficulty": 4 }, - { - "id": "afs_bio_wind_turbine", - "copy-from": "bionic_general", - "type": "BIONIC_ITEM", - "name": { "str": "Wind Turbine CBM" }, - "description": "Installed on your body is a set of small retractable wind turbines. When activated, they will deploy and slowly harvest wind power to recharge your power level.", - "price": 350000, - "difficulty": 4 - }, { "id": "afs_bio_missiles", "copy-from": "bionic_general", diff --git a/data/mods/Aftershock/items/obsolete.json b/data/mods/Aftershock/items/obsolete.json index a2193f7e28f8c..4a8398257ceae 100644 --- a/data/mods/Aftershock/items/obsolete.json +++ b/data/mods/Aftershock/items/obsolete.json @@ -621,6 +621,15 @@ "intelligence": 5, "time": "18 m" }, + { + "id": "afs_bio_wind_turbine", + "copy-from": "bionic_general", + "type": "BIONIC_ITEM", + "name": { "str": "Wind Turbine CBM" }, + "description": "Installed on your body is a set of small retractable wind turbines. When activated, they will deploy and slowly harvest wind power to recharge your power level.", + "price": 350000, + "difficulty": 4 + }, { "id": "afs_brigandine_crafted", "type": "ARMOR", diff --git a/data/mods/Aftershock/player/bionics.json b/data/mods/Aftershock/player/bionics.json index 3b97dcc2f612b..13ba381a399e8 100644 --- a/data/mods/Aftershock/player/bionics.json +++ b/data/mods/Aftershock/player/bionics.json @@ -10,17 +10,6 @@ "time": 1, "flags": [ "BIONIC_POWER_SOURCE", "BIONIC_TOGGLED" ] }, - { - "id": "afs_bio_wind_turbine", - "type": "bionic", - "name": { "str": "Wind Turbines" }, - "description": "Installed on your body is a set of small retractable wind turbines. When activated, they will deploy and slowly harvest wind power to recharge your power level.", - "occupied_bodyparts": [ [ "torso", 10 ] ], - "fuel_options": [ "wind" ], - "fuel_efficiency": 0.25, - "time": 1, - "flags": [ "BIONIC_POWER_SOURCE", "BIONIC_TOGGLED" ] - }, { "id": "afs_bio_missiles", "type": "bionic", diff --git a/data/mods/Aftershock/player/obsolete.json b/data/mods/Aftershock/player/obsolete.json index 2343e05286a9b..e99c10a9aba5d 100644 --- a/data/mods/Aftershock/player/obsolete.json +++ b/data/mods/Aftershock/player/obsolete.json @@ -6,5 +6,16 @@ "description": "Your hands have been outfitted with precise soldering tools, wire cutters, and cable spools. They're too small to use in most crafting, but in the absence of proper machinery, they're essential for creating bionics without better tools.", "occupied_bodyparts": [ [ "hand_l", 1 ], [ "hand_r", 1 ] ], "fake_item": "afs_solderers_item" + }, + { + "id": "afs_bio_wind_turbine", + "type": "bionic", + "name": { "str": "Wind Turbines" }, + "description": "Installed on your body is a set of small retractable wind turbines. When activated, they will deploy and slowly harvest wind power to recharge your power level.", + "occupied_bodyparts": [ [ "torso", 10 ] ], + "fuel_options": [ "wind" ], + "fuel_efficiency": 0.25, + "time": 1, + "flags": [ "BIONIC_POWER_SOURCE", "BIONIC_TOGGLED" ] } ] From 93228d620138a0d704e853cdfa8355a63fd5dbf2 Mon Sep 17 00:00:00 2001 From: LordMadness <45457447+LordMadness@users.noreply.github.com> Date: Thu, 25 Mar 2021 04:28:14 -0300 Subject: [PATCH 315/453] NPC Interaction Tweak (#47819) --- data/json/npcs/TALK_COMMON_ALLY.json | 107 ++++++++++++++++----------- 1 file changed, 62 insertions(+), 45 deletions(-) diff --git a/data/json/npcs/TALK_COMMON_ALLY.json b/data/json/npcs/TALK_COMMON_ALLY.json index 9c94ae2484536..35f7ea07a2ff6 100644 --- a/data/json/npcs/TALK_COMMON_ALLY.json +++ b/data/json/npcs/TALK_COMMON_ALLY.json @@ -163,12 +163,6 @@ "topic": "TALK_FRIEND_GUARD", "effect": "assign_guard" }, - { - "text": "I want to assign you to work at this camp.", - "condition": { "npc_at_om_location": "FACTION_CAMP_ANY" }, - "topic": "TALK_FRIEND_GUARD", - "effect": "assign_camp" - }, { "text": "Find a horse and mount up!", "condition": { "not": "npc_is_riding" }, @@ -181,46 +175,8 @@ "topic": "TALK_DONE", "effect": "dismount" }, - { - "text": "Please go to this location.", - "topic": "TALK_GOTO_LOCATION", - "condition": { "or": [ "is_by_radio", "u_has_camp" ] }, - "effect": "goto_location" - }, - { - "text": "I want you to build a camp here.", - "topic": "TALK_HALLU_CAMP", - "condition": { "npc_has_trait": "HALLUCINATION" }, - "switch": true - }, - { - "text": "I want you to build a camp here.", - "topic": "TALK_DONE", - "effect": "start_camp", - "condition": { "npc_at_om_location": "FACTION_CAMP_START" }, - "switch": true, - "default": true - }, - { - "text": "Since we can't build a camp here, I want you to tell me where can we build a camp?", - "topic": "TALK_CAMP_SITES", - "condition": { "not": { "npc_at_om_location": "FACTION_CAMP_START" } }, - "switch": true, - "default": true - }, - { - "text": "We need to abandon this camp.", - "condition": { "npc_at_om_location": "FACTION_CAMP_ANY" }, - "topic": "TALK_DONE", - "effect": "abandon_camp" - }, - { - "text": "Show me what needs to be done at the camp.", - "topic": "TALK_DONE", - "effect": "basecamp_mission", - "condition": { "npc_at_om_location": "FACTION_CAMP_ANY" } - }, { "text": "Let's talk about your current activity.", "topic": "TALK_ACTIVITIES" }, + { "text": "Let's talk about the camp.", "topic": "TALK_CAMP" }, { "text": "Let's go.", "topic": "TALK_DONE" } ] }, @@ -931,5 +887,66 @@ "type": "talk_topic", "dynamic_line": "", "responses": [ { "text": "Fair enough.", "topic": "TALK_NONE" } ] + }, + { + "id": "TALK_CAMP", + "type": "talk_topic", + "dynamic_line": "What about the camp?", + "responses": [ + { + "text": "I want to assign you to work at this camp.", + "condition": { "npc_at_om_location": "FACTION_CAMP_ANY" }, + "topic": "TALK_FRIEND_GUARD", + "effect": "assign_camp" + }, + { + "text": "Please go to this location.", + "topic": "TALK_GOTO_LOCATION", + "condition": { "or": [ "is_by_radio", "u_has_camp" ] }, + "effect": "goto_location" + }, + { + "text": "I want you to build a camp here.", + "topic": "TALK_HALLU_CAMP", + "condition": { "npc_has_trait": "HALLUCINATION" }, + "switch": true + }, + { + "text": "I want you to build a camp here.", + "topic": "TALK_DONE", + "effect": "start_camp", + "condition": { "npc_at_om_location": "FACTION_CAMP_START" }, + "switch": true, + "default": true + }, + { + "text": "Since we can't build a camp here, I want you to tell me where can we build a camp?", + "topic": "TALK_CAMP_SITES", + "condition": { "not": { "npc_at_om_location": "FACTION_CAMP_START" } }, + "switch": true, + "default": true + }, + { + "text": "We need to abandon this camp.", + "condition": { "npc_at_om_location": "FACTION_CAMP_ANY" }, + "topic": "TALK_ABANDON" + }, + { + "text": "Show me what needs to be done at the camp.", + "topic": "TALK_DONE", + "effect": "basecamp_mission", + "condition": { "npc_at_om_location": "FACTION_CAMP_ANY" } + }, + { "text": "Never mind.", "topic": "TALK_NONE" } + ] + }, + { + "id": "TALK_ABANDON", + "type": "talk_topic", + "dynamic_line": "Are you sure?", + "responses": [ + { "text": "Yes, I'm sure.", "topic": "TALK_DONE", "effect": "abandon_camp" }, + { "text": "Actually, never mind.", "topic": "TALK_NONE" } + ] } ] From 9b52ae08bb9238dff51c581f004e99f2eacc6bd0 Mon Sep 17 00:00:00 2001 From: Jamuro-g Date: Mon, 1 Mar 2021 21:11:49 +0100 Subject: [PATCH 316/453] Added warning when removing gunmods (#47816) --- src/iuse_actor.cpp | 10 +++++++--- 1 file changed, 7 insertions(+), 3 deletions(-) diff --git a/src/iuse_actor.cpp b/src/iuse_actor.cpp index e92e185e78781..a405503e41496 100644 --- a/src/iuse_actor.cpp +++ b/src/iuse_actor.cpp @@ -3925,9 +3925,13 @@ cata::optional detach_gunmods_actor::use( player &p, item &it, bool, const if( prompt.ret >= 0 ) { gun_copy.remove_item( *mods_copy[prompt.ret] ); - if( game_menus::inv::compare_items( it, gun_copy, _( "Remove modification?" ) ) ) { - p.gunmod_remove( it, *mods[ prompt.ret ] ); - return 0; + if( p.meets_requirements( *mods[prompt.ret], gun_copy ) || + query_yn( _( "Are you sure? You may be lacking the skills needed to reattach this modification." ) ) ) { + + if( game_menus::inv::compare_items( it, gun_copy, _( "Remove modification?" ) ) ) { + p.gunmod_remove( it, *mods[prompt.ret] ); + return 0; + } } } From d7827de54dd73cd7c604256120cdf54a56755bf7 Mon Sep 17 00:00:00 2001 From: Jamuro-g <76928284+Jamuro-g@users.noreply.github.com> Date: Thu, 25 Mar 2021 08:29:39 +0100 Subject: [PATCH 317/453] Added vehicle racking activity (#47557) --- data/json/player_activities.json | 22 +++++++++ src/activity_actor.cpp | 85 ++++++++++++++++++++++++++++++++ src/activity_actor_definitions.h | 57 +++++++++++++++++++++ src/vehicle.cpp | 9 +++- src/vehicle.h | 4 +- src/vehicle_use.cpp | 37 +++++++------- 6 files changed, 194 insertions(+), 20 deletions(-) diff --git a/data/json/player_activities.json b/data/json/player_activities.json index c5558ddf87138..3ced2d6de6b7b 100644 --- a/data/json/player_activities.json +++ b/data/json/player_activities.json @@ -74,6 +74,28 @@ "no_resume": true, "multi_activity": true }, + { + "id": "ACT_BIKERACK_RACKING", + "type": "activity_type", + "activity_level": "MODERATE_EXERCISE", + "verb": "mounting a vehicle onto rack", + "rooted": true, + "based_on": "time", + "no_resume": true, + "refuel_fires": false, + "auto_needs": false + }, + { + "id": "ACT_BIKERACK_UNRACKING", + "type": "activity_type", + "activity_level": "MODERATE_EXERCISE", + "verb": "taking a vehicle from rack", + "rooted": true, + "based_on": "time", + "no_resume": true, + "refuel_fires": false, + "auto_needs": false + }, { "id": "ACT_MULTIPLE_CHOP_PLANKS", "type": "activity_type", diff --git a/src/activity_actor.cpp b/src/activity_actor.cpp index 9bd47f22f659e..11f77a499526f 100644 --- a/src/activity_actor.cpp +++ b/src/activity_actor.cpp @@ -938,6 +938,89 @@ std::unique_ptr hotwire_car_activity_actor::deserialize( JsonIn return actor.clone(); } +void bikerack_racking_activity_actor::start( player_activity &act, Character & ) +{ + act.moves_total = moves_total; + act.moves_left = moves_total; +} + +void bikerack_racking_activity_actor::finish( player_activity &act, Character & ) +{ + if( parent_vehicle.try_to_rack_nearby_vehicle( parts ) ) { + map &here = get_map(); + here.invalidate_map_cache( here.get_abs_sub().z ); + here.rebuild_vehicle_level_caches(); + } else { + debugmsg( "Racking task failed. Parent-Vehicle:" + parent_vehicle.name + + "; Found parts size:" + std::to_string( parts[0].size() ) ); + } + act.set_to_null(); +} + +void bikerack_racking_activity_actor::serialize( JsonOut &jsout ) const +{ + jsout.start_object(); + jsout.member( "moves_total", moves_total ); + jsout.member( "parent_vehicle", parent_vehicle ); + jsout.member( "parts", parts ); + jsout.end_object(); +} + +std::unique_ptr bikerack_racking_activity_actor::deserialize( JsonIn &jsin ) +{ + vehicle veh; + bikerack_racking_activity_actor actor( 0, veh, std::vector>() ); + JsonObject data = jsin.get_object(); + data.read( "moves_total", actor.moves_total ); + data.read( "parent_vehicle", actor.parent_vehicle ); + data.read( "parts", actor.parts ); + + return actor.clone(); +} + +void bikerack_unracking_activity_actor::start( player_activity &act, Character & ) +{ + act.moves_total = moves_total; + act.moves_left = moves_total; +} + +void bikerack_unracking_activity_actor::finish( player_activity &act, Character & ) +{ + if( parent_vehicle.remove_carried_vehicle( parts ) ) { + parent_vehicle.clear_bike_racks( racks ); + map &here = get_map(); + here.invalidate_map_cache( here.get_abs_sub().z ); + here.rebuild_vehicle_level_caches(); + } else { + debugmsg( "Unracking task failed. Parent-Vehicle:" + parent_vehicle.name + + "; Found parts size:" + std::to_string( parts.size() ) ); + } + act.set_to_null(); +} + +void bikerack_unracking_activity_actor::serialize( JsonOut &jsout ) const +{ + jsout.start_object(); + jsout.member( "moves_total", moves_total ); + jsout.member( "parent_vehicle", parent_vehicle ); + jsout.member( "parts", parts ); + jsout.member( "racks", racks ); + jsout.end_object(); +} + +std::unique_ptr bikerack_unracking_activity_actor::deserialize( JsonIn &jsin ) +{ + vehicle veh; + bikerack_unracking_activity_actor actor( 0, veh, std::vector(), std::vector() ); + JsonObject data = jsin.get_object(); + data.read( "moves_total", actor.moves_total ); + data.read( "parent_vehicle", actor.parent_vehicle ); + data.read( "parts", actor.parts ); + data.read( "racks", actor.racks ); + + return actor.clone(); +} + void move_items_activity_actor::do_turn( player_activity &act, Character &who ) { const tripoint dest = relative_destination + who.pos(); @@ -2789,6 +2872,8 @@ const std::unordered_map( * )( Json deserialize_functions = { { activity_id( "ACT_AIM" ), &aim_activity_actor::deserialize }, { activity_id( "ACT_AUTODRIVE" ), &autodrive_activity_actor::deserialize }, + { activity_id( "ACT_BIKERACK_RACKING" ), &bikerack_racking_activity_actor::deserialize }, + { activity_id( "ACT_BIKERACK_UNRACKING" ), &bikerack_unracking_activity_actor::deserialize }, { activity_id( "ACT_CONSUME" ), &consume_activity_actor::deserialize }, { activity_id( "ACT_CRAFT" ), &craft_activity_actor::deserialize }, { activity_id( "ACT_DIG" ), &dig_activity_actor::deserialize }, diff --git a/src/activity_actor_definitions.h b/src/activity_actor_definitions.h index 654363d84cbb9..e2a814625a99b 100644 --- a/src/activity_actor_definitions.h +++ b/src/activity_actor_definitions.h @@ -22,6 +22,7 @@ #include "type_id.h" #include "units.h" #include "units_fwd.h" +#include "vehicle.h" #include "activity_actor.h" @@ -341,6 +342,62 @@ class hotwire_car_activity_actor : public activity_actor static std::unique_ptr deserialize( JsonIn &jsin ); }; +class bikerack_racking_activity_actor : public activity_actor +{ + private: + int moves_total; + vehicle &parent_vehicle; + std::vector> parts; + public: + bikerack_racking_activity_actor( int moves_total, vehicle &parent_vehicle, + std::vector> parts ): moves_total( moves_total ), + parent_vehicle( parent_vehicle ), parts( parts ) {} + + activity_id get_type() const override { + return activity_id( "ACT_BIKERACK_RACKING" ); + } + + void start( player_activity &act, Character & ) override; + void do_turn( player_activity &, Character & ) override {} + void finish( player_activity &act, Character & ) override; + + std::unique_ptr clone() const override { + return std::make_unique( *this ); + } + + void serialize( JsonOut &jsout ) const override; + static std::unique_ptr deserialize( JsonIn &jsin ); +}; + +class bikerack_unracking_activity_actor : public activity_actor +{ + private: + int moves_total; + vehicle &parent_vehicle; + std::vector parts; + std::vector racks; + + public: + bikerack_unracking_activity_actor( int moves_total, vehicle &parent_vehicle, + std::vector parts, std::vector racks ) : moves_total( moves_total ), + parent_vehicle( parent_vehicle ), parts( parts ), racks( racks ) {} + + activity_id get_type() const override { + return activity_id( "ACT_BIKERACK_UNRACKING" ); + } + + void start( player_activity &act, Character & ) override; + void do_turn( player_activity &, Character & ) override {} + void finish( player_activity &act, Character & ) override; + + std::unique_ptr clone() const override { + return std::make_unique( *this ); + } + + void serialize( JsonOut &jsout ) const override; + static std::unique_ptr deserialize( JsonIn &jsin ); +}; + class move_items_activity_actor : public activity_actor { private: diff --git a/src/vehicle.cpp b/src/vehicle.cpp index bacabf0432ed8..bab24e12ea761 100644 --- a/src/vehicle.cpp +++ b/src/vehicle.cpp @@ -1654,7 +1654,8 @@ int vehicle::install_part( const point &dp, const vehicle_part &new_part ) return parts.size() - 1; } -bool vehicle::try_to_rack_nearby_vehicle( std::vector> &list_of_racks ) +bool vehicle::try_to_rack_nearby_vehicle( std::vector> &list_of_racks, + bool do_not_rack ) { map &here = get_map(); for( std::vector &this_bike_rack : list_of_racks ) { @@ -1685,7 +1686,11 @@ bool vehicle::try_to_rack_nearby_vehicle( std::vector> &list_of } partial_matches[ i ].insert( search_pos ); if( partial_matches[ i ] == test_veh->get_points() ) { - return merge_rackable_vehicle( test_veh, this_bike_rack ); + if( do_not_rack ) { + return true; + } else { + return merge_rackable_vehicle( test_veh, this_bike_rack ); + } } ++i; } diff --git a/src/vehicle.h b/src/vehicle.h index 5c22c5a847039..a96e8fc8fcf2b 100644 --- a/src/vehicle.h +++ b/src/vehicle.h @@ -910,7 +910,8 @@ class vehicle const std::string &variant = "", bool force = false ); // find a single tile wide vehicle adjacent to a list of part indices - bool try_to_rack_nearby_vehicle( std::vector> &list_of_racks ); + bool try_to_rack_nearby_vehicle( std::vector> &list_of_racks, + bool do_not_rack = false ); // merge a previously found single tile vehicle into this vehicle bool merge_rackable_vehicle( vehicle *carry_veh, const std::vector &rack_parts ); @@ -1783,6 +1784,7 @@ class vehicle void use_dishwasher( int p ); void use_monster_capture( int part, const tripoint &pos ); void use_bike_rack( int part ); + void clear_bike_racks( std::vector &racks ); void use_harness( int part, const tripoint &pos ); void interact_with( const vpart_position &vp ); diff --git a/src/vehicle_use.cpp b/src/vehicle_use.cpp index d8db2d2b6137f..ad7a282830213 100644 --- a/src/vehicle_use.cpp +++ b/src/vehicle_use.cpp @@ -1940,14 +1940,14 @@ void vehicle::use_bike_rack( int part ) full_rack &= carry_size == rack_parts.size(); } int unload_carried = full_rack ? 0 : -1; - bool success = false; - + bool found_rackable_vehicle = try_to_rack_nearby_vehicle( racks_parts, true ); validate_carried_vehicles( carried_vehicles ); validate_carried_vehicles( carrying_racks ); - if( found_vehicle && !full_rack ) { uilist rack_menu; - rack_menu.addentry( 0, true, '0', _( "Load a vehicle on the rack" ) ); + if( found_rackable_vehicle ) { + rack_menu.addentry( 0, true, '0', _( "Load a vehicle on the rack" ) ); + } for( size_t i = 0; i < carried_vehicles.size(); i++ ) { rack_menu.addentry( i + 1, true, '1' + i, string_format( _( "Remove the %s from the rack" ), @@ -1956,21 +1956,24 @@ void vehicle::use_bike_rack( int part ) rack_menu.query(); unload_carried = rack_menu.ret - 1; } + + player_activity new_act; if( unload_carried > -1 ) { - success = remove_carried_vehicle( carried_vehicles[unload_carried] ); - if( success ) { - for( const int &rack_part : carrying_racks[unload_carried] ) { - parts[ rack_part ].remove_flag( vehicle_part::carrying_flag ); - parts[rack_part].remove_flag( vehicle_part::tracked_flag ); - } - } - } else { - success = try_to_rack_nearby_vehicle( racks_parts ); + new_act = player_activity( bikerack_unracking_activity_actor( to_moves( 5_minutes ), *this, + carried_vehicles[unload_carried], carrying_racks[unload_carried] ) ); + get_player_character().assign_activity( new_act, false ); + } else if( found_rackable_vehicle ) { + new_act = player_activity( bikerack_racking_activity_actor( to_moves( 5_minutes ), *this, + racks_parts ) ); + get_player_character().assign_activity( new_act, false ); } - if( success ) { - map &here = get_map(); - here.invalidate_map_cache( here.get_abs_sub().z ); - here.rebuild_vehicle_level_caches(); +} + +void vehicle::clear_bike_racks( std::vector &racks ) +{ + for( const int &rack_part : racks ) { + parts[rack_part].remove_flag( vehicle_part::carrying_flag ); + parts[rack_part].remove_flag( vehicle_part::tracked_flag ); } } From d10f0818bbb836498757f6676327e680565a93ac Mon Sep 17 00:00:00 2001 From: Eric <52087122+Ramza13@users.noreply.github.com> Date: Thu, 25 Mar 2021 03:33:41 -0400 Subject: [PATCH 318/453] Get bionic tools to use power as charges (#47694) --- data/json/bionics.json | 6 ++- data/json/items/fake.json | 4 +- src/activity_actor.cpp | 42 +++---------------- src/activity_actor_definitions.h | 6 --- src/character.cpp | 69 +++++++++++++++++--------------- src/character.h | 2 +- src/iexamine.cpp | 36 ++--------------- src/visitable.cpp | 9 ++--- 8 files changed, 56 insertions(+), 118 deletions(-) diff --git a/data/json/bionics.json b/data/json/bionics.json index 662161a12015b..64a94138ad13e 100644 --- a/data/json/bionics.json +++ b/data/json/bionics.json @@ -481,7 +481,9 @@ "type": "bionic", "name": { "str": "Fingerhack" }, "description": "One of your fingers has an electrohack surgically embedded in it; an all-purpose hacking unit used to override control panels and the like (but not computers). Skill in computers is important, and a failed use may damage your circuits.", - "occupied_bodyparts": [ [ "hand_r", 2 ] ] + "occupied_bodyparts": [ [ "hand_r", 2 ] ], + "fake_item": "electrohack", + "flags": [ "BIONIC_TOGGLED" ] }, { "id": "bio_flashbang", @@ -664,7 +666,7 @@ "description": "The index fingers of both hands have powerful fire starters which extend from the tip.", "occupied_bodyparts": [ [ "hand_l", 1 ], [ "hand_r", 1 ] ], "fake_item": "fake_firestarter", - "act_cost": "3 kJ" + "act_cost": "5 kJ" }, { "id": "bio_lockpick", diff --git a/data/json/items/fake.json b/data/json/items/fake.json index b33dba7bbfa12..977925c2b1325 100644 --- a/data/json/items/fake.json +++ b/data/json/items/fake.json @@ -29,7 +29,7 @@ "copy-from": "fake_item", "type": "TOOL", "name": { "str": "integrated toolset" }, - "flags": [ "TRADER_AVOID" ], + "flags": [ "TRADER_AVOID", "FIRESTARTER", "USES_BIONIC_POWER" ], "max_charges": 10000, "use_action": [ "HAMMER", "CROWBAR" ], "qualities": [ @@ -143,7 +143,7 @@ "copy-from": "fake_item", "type": "TOOL", "name": { "str": "bionic firestarter" }, - "flags": [ "FIRESTARTER" ] + "flags": [ "FIRESTARTER", "USES_BIONIC_POWER" ] }, { "id": "migo_bio_gun", diff --git a/src/activity_actor.cpp b/src/activity_actor.cpp index 11f77a499526f..ac699fb7b888d 100644 --- a/src/activity_actor.cpp +++ b/src/activity_actor.cpp @@ -721,7 +721,7 @@ static int hack_level( const Character &who ) return who.get_skill_level( skill_computer ) + who.int_cur / 2 - 8; } -static hack_result hack_attempt( Character &who, const bool using_bionic ) +static hack_result hack_attempt( Character &who ) { // TODO: Remove this once player -> Character migration is complete { @@ -735,21 +735,10 @@ static hack_result hack_attempt( Character &who, const bool using_bionic ) int success = std::ceil( normal_roll( hack_level( who ), hack_stddev ) ); if( success < 0 ) { who.add_msg_if_player( _( "You cause a short circuit!" ) ); - if( using_bionic ) { - who.mod_power_level( -25_kJ ); - } else { - who.use_charges( itype_electrohack, 25 ); - } + who.use_charges( itype_electrohack, 25 ); if( success <= -5 ) { - if( !using_bionic ) { - who.add_msg_if_player( m_bad, _( "Your electrohack is ruined!" ) ); - who.use_amount( itype_electrohack, 1 ); - } else { - who.add_msg_if_player( m_bad, _( "Your power is drained!" ) ); - who.mod_power_level( units::from_kilojoule( -rng( 25, - units::to_kilojoule( who.get_power_level() ) ) ) ); - } + who.use_charges( itype_electrohack, 50 ); } return hack_result::FAIL; } else if( success < 6 ) { @@ -777,16 +766,11 @@ static hack_type get_hack_type( const tripoint &examp ) return type; } -hacking_activity_actor::hacking_activity_actor( use_bionic ) - : using_bionic( true ) -{ -} - void hacking_activity_actor::finish( player_activity &act, Character &who ) { tripoint examp = act.placement; hack_type type = get_hack_type( examp ); - switch( hack_attempt( who, using_bionic ) ) { + switch( hack_attempt( who ) ) { case hack_result::UNABLE: who.add_msg_if_player( _( "You cannot hack this." ) ); break; @@ -842,25 +826,11 @@ void hacking_activity_actor::finish( player_activity &act, Character &who ) act.set_to_null(); } -void hacking_activity_actor::serialize( JsonOut &jsout ) const -{ - jsout.start_object(); - jsout.member( "using_bionic", using_bionic ); - jsout.end_object(); -} +void hacking_activity_actor::serialize( JsonOut & ) const {} -std::unique_ptr hacking_activity_actor::deserialize( JsonIn &jsin ) +std::unique_ptr hacking_activity_actor::deserialize( JsonIn & ) { hacking_activity_actor actor; - if( jsin.test_null() ) { - // Old saves might contain a null instead of an object. - // Since we do not know whether a bionic or an item was chosen we assume - // it was an item. - actor.using_bionic = false; - } else { - JsonObject jsobj = jsin.get_object(); - jsobj.read( "using_bionic", actor.using_bionic ); - } return actor.clone(); } diff --git a/src/activity_actor_definitions.h b/src/activity_actor_definitions.h index e2a814625a99b..ddb9d78c65fb5 100644 --- a/src/activity_actor_definitions.h +++ b/src/activity_actor_definitions.h @@ -278,14 +278,8 @@ class gunmod_remove_activity_actor : public activity_actor class hacking_activity_actor : public activity_actor { - private: - bool using_bionic = false; - public: - struct use_bionic {}; - hacking_activity_actor() = default; - explicit hacking_activity_actor( use_bionic ); activity_id get_type() const override { return activity_id( "ACT_HACKING" ); diff --git a/src/character.cpp b/src/character.cpp index c608f9aae1406..cae189a0dd74d 100644 --- a/src/character.cpp +++ b/src/character.cpp @@ -224,7 +224,6 @@ static const itype_id itype_rm13_armor_on( "rm13_armor_on" ); static const itype_id itype_rope_6( "rope_6" ); static const itype_id itype_snare_trigger( "snare_trigger" ); static const itype_id itype_string_36( "string_36" ); -static const itype_id itype_toolset( "toolset" ); static const itype_id itype_UPS( "UPS" ); static const itype_id itype_UPS_off( "UPS_off" ); @@ -282,15 +281,12 @@ static const bionic_id bio_gills( "bio_gills" ); static const bionic_id bio_ground_sonar( "bio_ground_sonar" ); static const bionic_id bio_hydraulics( "bio_hydraulics" ); static const bionic_id bio_jointservo( "bio_jointservo" ); -static const bionic_id bio_laser( "bio_laser" ); static const bionic_id bio_leukocyte( "bio_leukocyte" ); -static const bionic_id bio_lighter( "bio_lighter" ); static const bionic_id bio_memory( "bio_memory" ); static const bionic_id bio_railgun( "bio_railgun" ); static const bionic_id bio_recycler( "bio_recycler" ); static const bionic_id bio_shock_absorber( "bio_shock_absorber" ); static const bionic_id bio_tattoo_led( "bio_tattoo_led" ); -static const bionic_id bio_tools( "bio_tools" ); static const bionic_id bio_ups( "bio_ups" ); // Aftershock stuff! static const bionic_id afs_bio_linguistic_coprocessor( "afs_bio_linguistic_coprocessor" ); @@ -381,6 +377,7 @@ static const json_character_flag json_flag_ALARMCLOCK( "ALARMCLOCK" ); static const json_character_flag json_flag_ACID_IMMUNE( "ACID_IMMUNE" ); static const json_character_flag json_flag_BASH_IMMUNE( "BASH_IMMUNE" ); static const json_character_flag json_flag_BIO_IMMUNE( "BIO_IMMUNE" ); +static const json_character_flag json_flag_BIONIC_TOGGLED( "BIONIC_TOGGLED" ); static const json_character_flag json_flag_BLIND( "BLIND" ); static const json_character_flag json_flag_BULLET_IMMUNE( "BULLET_IMMUNE" ); static const json_character_flag json_flag_CLAIRVOYANCE( "CLAIRVOYANCE" ); @@ -11268,12 +11265,16 @@ std::list Character::use_charges( const itype_id &what, int qty, const int if( qty <= 0 ) { return res; + } + for( const auto &bio : *this->my_bionics ) { + const bionic_data &bid = bio.info(); + if( bid.fake_item == what && ( !bid.activated || bio.powered ) ) { + mod_power_level( units::from_kilojoule( -qty ) ); + return res; + } + } - } else if( what == itype_toolset ) { - mod_power_level( units::from_kilojoule( -qty ) ); - return res; - - } else if( what == itype_fire ) { + if( what == itype_fire ) { use_fire( qty ); return res; @@ -11349,21 +11350,30 @@ std::list Character::use_charges( const itype_id &what, int qty, return use_charges( what, qty, -1, filter ); } -const item *Character::find_firestarter_with_charges( const int quantity ) const +item Character::find_firestarter_with_charges( const int quantity ) const { for( const item *i : all_items_with_flag( flag_FIRESTARTER ) ) { if( !i->typeId()->can_have_charges() ) { const use_function *usef = i->type->get_use( "firestarter" ); const firestarter_actor *actor = dynamic_cast( usef->get_actor_ptr() ); if( actor->can_use( *this->as_character(), *i, false, tripoint_zero ).success() ) { - return i; + return *i; } } else if( has_charges( i->typeId(), quantity ) ) { - return i; + return *i; } } - - return nullptr; + for( const auto &bio : *this->my_bionics ) { + const bionic_data &bid = bio.info(); + if( bid.fake_item.is_valid() && ( !bid.has_flag( json_flag_BIONIC_TOGGLED ) || ( !bid.activated || + bio.powered ) ) && get_power_level() > quantity * 5_kJ ) { + item fake( bid.fake_item ); + if( !fake.is_null() && bid.fake_item->has_flag( flag_FIRESTARTER ) ) { + return fake; + } + } + } + return item(); } bool Character::has_fire( const int quantity ) const @@ -11374,13 +11384,7 @@ bool Character::has_fire( const int quantity ) const return true; } else if( has_item_with_flag( flag_FIRE ) ) { return true; - } else if( find_firestarter_with_charges( quantity ) ) { - return true; - } else if( has_active_bionic( bio_tools ) && get_power_level() > quantity * 5_kJ ) { - return true; - } else if( has_bionic( bio_lighter ) && get_power_level() > quantity * 5_kJ ) { - return true; - } else if( has_bionic( bio_laser ) && get_power_level() > quantity * 5_kJ ) { + } else if( !find_firestarter_with_charges( quantity ).is_null() ) { return true; } else if( is_npc() ) { // HACK: A hack to make NPCs use their Molotovs @@ -11429,20 +11433,19 @@ void Character::use_fire( const int quantity ) return; } else if( has_item_with_flag( flag_FIRE ) ) { return; - } else if( const item *firestarter = find_firestarter_with_charges( quantity ) ) { - if( firestarter->typeId()->can_have_charges() ) { - use_charges( firestarter->typeId(), quantity ); + } else { + const item firestarter = find_firestarter_with_charges( quantity ); + if( firestarter.is_null() ) { + return; + } + if( firestarter.type->has_flag( flag_USES_BIONIC_POWER ) ) { + mod_power_level( -quantity * 5_kJ ); + return; + } + if( firestarter.typeId()->can_have_charges() ) { + use_charges( firestarter.typeId(), quantity ); return; } - } else if( has_active_bionic( bio_tools ) && get_power_level() > quantity * 5_kJ ) { - mod_power_level( -quantity * 5_kJ ); - return; - } else if( has_bionic( bio_lighter ) && get_power_level() > quantity * 5_kJ ) { - mod_power_level( -quantity * 5_kJ ); - return; - } else if( has_bionic( bio_laser ) && get_power_level() > quantity * 5_kJ ) { - mod_power_level( -quantity * 5_kJ ); - return; } } diff --git a/src/character.h b/src/character.h index 0df50d945dc29..dca5ede190e09 100644 --- a/src/character.h +++ b/src/character.h @@ -2072,7 +2072,7 @@ class Character : public Creature, public visitable std::list use_charges( const itype_id &what, int qty, int radius, const std::function &filter = return_true ); - const item *find_firestarter_with_charges( int quantity ) const; + item find_firestarter_with_charges( int quantity ) const; bool has_fire( int quantity ) const; void use_fire( int quantity ); void assign_stashed_activity(); diff --git a/src/iexamine.cpp b/src/iexamine.cpp index 8c62a54cfef80..69c551ae367c2 100644 --- a/src/iexamine.cpp +++ b/src/iexamine.cpp @@ -207,7 +207,6 @@ static const mtype_id mon_spider_cellar_giant_s( "mon_spider_cellar_giant_s" ); static const mtype_id mon_spider_web_s( "mon_spider_web_s" ); static const mtype_id mon_spider_widow_giant_s( "mon_spider_widow_giant_s" ); -static const bionic_id bio_fingerhack( "bio_fingerhack" ); static const bionic_id bio_lighter( "bio_lighter" ); static const bionic_id bio_lockpick( "bio_lockpick" ); static const bionic_id bio_painkiller( "bio_painkiller" ); @@ -1057,37 +1056,12 @@ bool iexamine::try_start_hacking( player &p, const tripoint &examp ) return false; } const bool has_item = p.has_charges( itype_electrohack, 25 ); - const bool has_bionic = p.has_bionic( bio_fingerhack ) && p.get_power_level() >= 25_kJ; - if( !has_item && !has_bionic ) { + if( !has_item ) { add_msg( _( "You don't have a hacking tool with enough charges!" ) ); return false; } - bool use_bionic = has_bionic; - if( has_item && has_bionic ) { - uilist menu; - menu.settext( _( "Use which hacking tool?" ) ); - menu.addentry( 0, true, MENU_AUTOASSIGN, "%s", itype_electrohack->nname( 1 ) ); - menu.addentry( 1, true, MENU_AUTOASSIGN, "%s", bio_fingerhack->name ); - menu.query(); - switch( menu.ret ) { - case 0: - use_bionic = false; - break; - case 1: - use_bionic = true; - break; - default: - return false; - } - } - if( use_bionic ) { - p.mod_power_level( -25_kJ ); - p.assign_activity( player_activity( hacking_activity_actor( - hacking_activity_actor::use_bionic {} ) ) ); - } else { - p.use_charges( itype_electrohack, 25 ); - p.assign_activity( player_activity( hacking_activity_actor() ) ); - } + p.use_charges( itype_electrohack, 25 ); + p.assign_activity( player_activity( hacking_activity_actor() ) ); p.activity.placement = examp; return true; } @@ -4310,9 +4284,7 @@ void iexamine::pay_gas( player &p, const tripoint &examp ) int pricePerUnit = getGasPricePerLiter( discount ); - bool can_hack = ( !p.has_trait( trait_ILLITERATE ) && - ( ( p.has_charges( itype_electrohack, 25 ) ) || - ( p.has_bionic( bio_fingerhack ) && p.get_power_level() > 24_kJ ) ) ); + bool can_hack = ( !p.has_trait( trait_ILLITERATE ) && p.has_charges( itype_electrohack, 25 ) ); uilist amenu; amenu.selected = 1; diff --git a/src/visitable.cpp b/src/visitable.cpp index 5079bb5aa7c26..e0933fc7398a2 100644 --- a/src/visitable.cpp +++ b/src/visitable.cpp @@ -39,13 +39,11 @@ static const itype_id itype_apparatus( "apparatus" ); static const itype_id itype_adv_UPS_off( "adv_UPS_off" ); -static const itype_id itype_toolset( "toolset" ); static const itype_id itype_UPS( "UPS" ); static const itype_id itype_UPS_off( "UPS_off" ); static const quality_id qual_BUTCHER( "BUTCHER" ); -static const bionic_id bio_tools( "bio_tools" ); static const bionic_id bio_ups( "bio_ups" ); static const json_character_flag json_flag_BIONIC_TOGGLED( "BIONIC_TOGGLED" ); @@ -828,11 +826,10 @@ int Character::charges_of( const itype_id &what, int limit, { const player *p = dynamic_cast( this ); - if( what == itype_toolset ) { - if( p && p->has_active_bionic( bio_tools ) ) { + for( const auto &bio : *this->my_bionics ) { + const bionic_data &bid = bio.info(); + if( bid.fake_item == what && ( !bid.activated || bio.powered ) ) { return std::min( units::to_kilojoule( p->get_power_level() ), limit ); - } else { - return 0; } } From 383712f569584412ad057bb15f6a508473bbe66d Mon Sep 17 00:00:00 2001 From: "Matthew S. Klosak" Date: Thu, 25 Mar 2021 00:34:17 -0700 Subject: [PATCH 319/453] Migrate some activities to activity actor system (#47913) --- src/activity_actor.cpp | 107 +++++++++++++++++++++++++++++++ src/activity_actor_definitions.h | 84 ++++++++++++++++++++++++ src/activity_handlers.cpp | 37 ----------- src/activity_handlers.h | 4 -- src/iuse.cpp | 12 +--- src/monexamine.cpp | 5 +- 6 files changed, 195 insertions(+), 54 deletions(-) diff --git a/src/activity_actor.cpp b/src/activity_actor.cpp index ac699fb7b888d..70bf09da9dc69 100644 --- a/src/activity_actor.cpp +++ b/src/activity_actor.cpp @@ -2834,6 +2834,109 @@ std::unique_ptr disassemble_activity_actor::deserialize( JsonIn return actor.clone(); } +void meditate_activity_actor::start( player_activity &act, Character & ) +{ + act.moves_total = to_moves( 20_minutes ); + act.moves_left = act.moves_total; +} + +void meditate_activity_actor::finish( player_activity &act, Character &who ) +{ + who.add_msg_if_player( m_good, _( "You pause to engage in spiritual contemplation." ) ); + who.add_morale( MORALE_FEELING_GOOD, 5, 10 ); + act.set_to_null(); +} + +void meditate_activity_actor::serialize( JsonOut &jsout ) const +{ + jsout.write_null(); +} + +std::unique_ptr meditate_activity_actor::deserialize( JsonIn & ) +{ + return meditate_activity_actor().clone(); +} + +void play_with_pet_activity_actor::start( player_activity &act, Character & ) +{ + act.moves_total = rng( 50, 125 ) * 100; + act.moves_left = act.moves_total; +} + +void play_with_pet_activity_actor::finish( player_activity &act, Character &who ) +{ + who.add_morale( MORALE_PLAY_WITH_PET, rng( 3, 10 ), 10, 5_hours, 25_minutes ); + who.add_msg_if_player( m_good, _( "Playing with your %s has lifted your spirits a bit." ), + pet_name ); + act.set_to_null(); +} + +void play_with_pet_activity_actor::serialize( JsonOut &jsout ) const +{ + jsout.start_object(); + + jsout.member( "pet_name", pet_name ); + + jsout.end_object(); +} + +std::unique_ptr play_with_pet_activity_actor::deserialize( JsonIn &jsin ) +{ + play_with_pet_activity_actor actor = play_with_pet_activity_actor(); + + JsonObject data = jsin.get_object(); + + data.read( "pet_name", actor.pet_name ); + + return actor.clone(); +} + +void shave_activity_actor::start( player_activity &act, Character & ) +{ + act.moves_total = to_moves( 5_minutes ); + act.moves_left = act.moves_total; +} + +void shave_activity_actor::finish( player_activity &act, Character &who ) +{ + who.add_msg_if_player( _( "You open up your kit and shave." ) ); + who.add_morale( MORALE_SHAVE, 8, 8, 240_minutes, 3_minutes ); + act.set_to_null(); +} + +void shave_activity_actor::serialize( JsonOut &jsout ) const +{ + jsout.write_null(); +} + +std::unique_ptr shave_activity_actor::deserialize( JsonIn & ) +{ + return shave_activity_actor().clone(); +} + +void haircut_activity_actor::start( player_activity &act, Character & ) +{ + act.moves_total = to_moves( 30_minutes ); + act.moves_left = act.moves_total; +} + +void haircut_activity_actor::finish( player_activity &act, Character &who ) +{ + who.add_msg_if_player( _( "You give your hair a trim." ) ); + who.add_morale( MORALE_HAIRCUT, 3, 3, 480_minutes, 3_minutes ); + act.set_to_null(); +} + +void haircut_activity_actor::serialize( JsonOut &jsout ) const +{ + jsout.write_null(); +} + +std::unique_ptr haircut_activity_actor::deserialize( JsonIn & ) +{ + return haircut_activity_actor().clone(); +} + namespace activity_actors { @@ -2852,15 +2955,19 @@ deserialize_functions = { { activity_id( "ACT_DROP" ), &drop_activity_actor::deserialize }, { activity_id( "ACT_GUNMOD_REMOVE" ), &gunmod_remove_activity_actor::deserialize }, { activity_id( "ACT_HACKING" ), &hacking_activity_actor::deserialize }, + { activity_id( "ACT_HAIRCUT" ), &haircut_activity_actor::deserialize }, { activity_id( "ACT_HOTWIRE_CAR" ), &hotwire_car_activity_actor::deserialize }, { activity_id( "ACT_INSERT_ITEM" ), &insert_item_activity_actor::deserialize }, { activity_id( "ACT_LOCKPICK" ), &lockpick_activity_actor::deserialize }, + { activity_id( "ACT_MEDITATE" ), &meditate_activity_actor::deserialize }, { activity_id( "ACT_MIGRATION_CANCEL" ), &migration_cancel_activity_actor::deserialize }, { activity_id( "ACT_MILK" ), &milk_activity_actor::deserialize }, { activity_id( "ACT_MOVE_ITEMS" ), &move_items_activity_actor::deserialize }, { activity_id( "ACT_OPEN_GATE" ), &open_gate_activity_actor::deserialize }, { activity_id( "ACT_PICKUP" ), &pickup_activity_actor::deserialize }, + { activity_id( "ACT_PLAY_WITH_PET" ), &play_with_pet_activity_actor::deserialize }, { activity_id( "ACT_RELOAD" ), &reload_activity_actor::deserialize }, + { activity_id( "ACT_SHAVE" ), &shave_activity_actor::deserialize }, { activity_id( "ACT_STASH" ), &stash_activity_actor::deserialize }, { activity_id( "ACT_TRY_SLEEP" ), &try_sleep_activity_actor::deserialize }, { activity_id( "ACT_UNLOAD" ), &unload_activity_actor::deserialize }, diff --git a/src/activity_actor_definitions.h b/src/activity_actor_definitions.h index ddb9d78c65fb5..b3fd236b518b2 100644 --- a/src/activity_actor_definitions.h +++ b/src/activity_actor_definitions.h @@ -1007,4 +1007,88 @@ class insert_item_activity_actor : public activity_actor static std::unique_ptr deserialize( JsonIn &jsin ); }; +class meditate_activity_actor : public activity_actor +{ + public: + meditate_activity_actor() = default; + activity_id get_type() const override { + return activity_id( "ACT_MEDITATE" ); + } + + void start( player_activity &act, Character & ) override; + void do_turn( player_activity &, Character & ) override {} + void finish( player_activity &act, Character &who ) override; + + std::unique_ptr clone() const override { + return std::make_unique( *this ); + } + + void serialize( JsonOut & ) const override; + static std::unique_ptr deserialize( JsonIn & ); +}; + +class play_with_pet_activity_actor : public activity_actor +{ + private: + std::string pet_name; + public: + play_with_pet_activity_actor() = default; + explicit play_with_pet_activity_actor( const std::string &pet_name ) : + pet_name( pet_name ) {} + activity_id get_type() const override { + return activity_id( "ACT_PLAY_WITH_PET" ); + } + + void start( player_activity &act, Character & ) override; + void do_turn( player_activity &, Character & ) override {} + void finish( player_activity &act, Character &who ) override; + + std::unique_ptr clone() const override { + return std::make_unique( *this ); + } + + void serialize( JsonOut &jsout ) const override; + static std::unique_ptr deserialize( JsonIn &jsin ); +}; + +class shave_activity_actor : public activity_actor +{ + public: + shave_activity_actor() = default; + activity_id get_type() const override { + return activity_id( "ACT_SHAVE" ); + } + + void start( player_activity &act, Character & ) override; + void do_turn( player_activity &, Character & ) override {} + void finish( player_activity &act, Character &who ) override; + + std::unique_ptr clone() const override { + return std::make_unique( *this ); + } + + void serialize( JsonOut & ) const override; + static std::unique_ptr deserialize( JsonIn & ); +}; + +class haircut_activity_actor : public activity_actor +{ + public: + haircut_activity_actor() = default; + activity_id get_type() const override { + return activity_id( "ACT_HAIRCUT" ); + } + + void start( player_activity &act, Character & ) override; + void do_turn( player_activity &, Character & ) override {} + void finish( player_activity &act, Character &who ) override; + + std::unique_ptr clone() const override { + return std::make_unique( *this ); + } + + void serialize( JsonOut & ) const override; + static std::unique_ptr deserialize( JsonIn & ); +}; + #endif // CATA_SRC_ACTIVITY_ACTOR_DEFINITIONS_H diff --git a/src/activity_handlers.cpp b/src/activity_handlers.cpp index 507458cc82f55..87b98c5d350a9 100644 --- a/src/activity_handlers.cpp +++ b/src/activity_handlers.cpp @@ -136,12 +136,10 @@ static const activity_id ACT_GAME( "ACT_GAME" ); static const activity_id ACT_GENERIC_GAME( "ACT_GENERIC_GAME" ); static const activity_id ACT_GUNMOD_ADD( "ACT_GUNMOD_ADD" ); static const activity_id ACT_HACKSAW( "ACT_HACKSAW" ); -static const activity_id ACT_HAIRCUT( "ACT_HAIRCUT" ); static const activity_id ACT_HAND_CRANK( "ACT_HAND_CRANK" ); static const activity_id ACT_HEATING( "ACT_HEATING" ); static const activity_id ACT_JACKHAMMER( "ACT_JACKHAMMER" ); static const activity_id ACT_LONGSALVAGE( "ACT_LONGSALVAGE" ); -static const activity_id ACT_MEDITATE( "ACT_MEDITATE" ); static const activity_id ACT_MEND_ITEM( "ACT_MEND_ITEM" ); static const activity_id ACT_MIND_SPLICER( "ACT_MIND_SPLICER" ); static const activity_id ACT_MOVE_LOOT( "ACT_MOVE_LOOT" ); @@ -156,14 +154,12 @@ static const activity_id ACT_OPERATION( "ACT_OPERATION" ); static const activity_id ACT_OXYTORCH( "ACT_OXYTORCH" ); static const activity_id ACT_PICKAXE( "ACT_PICKAXE" ); static const activity_id ACT_PLANT_SEED( "ACT_PLANT_SEED" ); -static const activity_id ACT_PLAY_WITH_PET( "ACT_PLAY_WITH_PET" ); static const activity_id ACT_PRY_NAILS( "ACT_PRY_NAILS" ); static const activity_id ACT_PULP( "ACT_PULP" ); static const activity_id ACT_QUARTER( "ACT_QUARTER" ); static const activity_id ACT_READ( "ACT_READ" ); static const activity_id ACT_REPAIR_ITEM( "ACT_REPAIR_ITEM" ); static const activity_id ACT_ROBOT_CONTROL( "ACT_ROBOT_CONTROL" ); -static const activity_id ACT_SHAVE( "ACT_SHAVE" ); static const activity_id ACT_SKIN( "ACT_SKIN" ); static const activity_id ACT_SOCIALIZE( "ACT_SOCIALIZE" ); static const activity_id ACT_SPELLCASTING( "ACT_SPELLCASTING" ); @@ -343,7 +339,6 @@ activity_handlers::finish_functions = { { ACT_GUNMOD_ADD, gunmod_add_finish }, { ACT_TOOLMOD_ADD, toolmod_add_finish }, { ACT_CLEAR_RUBBLE, clear_rubble_finish }, - { ACT_MEDITATE, meditate_finish }, { ACT_READ, read_finish }, { ACT_WAIT, wait_finish }, { ACT_WAIT_WEATHER, wait_weather_finish }, @@ -366,9 +361,6 @@ activity_handlers::finish_functions = { { ACT_CHOP_PLANKS, chop_planks_finish }, { ACT_JACKHAMMER, jackhammer_finish }, { ACT_FILL_PIT, fill_pit_finish }, - { ACT_PLAY_WITH_PET, play_with_pet_finish }, - { ACT_SHAVE, shaving_finish }, - { ACT_HAIRCUT, haircut_finish }, { ACT_ROBOT_CONTROL, robot_control_finish }, { ACT_MIND_SPLICER, mind_splicer_finish }, { ACT_SPELLCASTING, spellcasting_finish }, @@ -2841,13 +2833,6 @@ void activity_handlers::clear_rubble_finish( player_activity *act, player *p ) here.maybe_trigger_trap( pos, *p, true ); } -void activity_handlers::meditate_finish( player_activity *act, player *p ) -{ - p->add_msg_if_player( m_good, _( "You pause to engage in spiritual contemplation." ) ); - p->add_morale( MORALE_FEELING_GOOD, 5, 10 ); - act->set_to_null(); -} - void activity_handlers::wear_do_turn( player_activity *act, player *p ) { activity_on_turn_wear( *act, *p ); @@ -3879,28 +3864,6 @@ void activity_handlers::fill_pit_finish( player_activity *act, player *p ) act->set_to_null(); } -void activity_handlers::play_with_pet_finish( player_activity *act, player *p ) -{ - p->add_morale( MORALE_PLAY_WITH_PET, rng( 3, 10 ), 10, 5_hours, 25_minutes ); - p->add_msg_if_player( m_good, _( "Playing with your %s has lifted your spirits a bit." ), - act->str_values[0] ); - act->set_to_null(); -} - -void activity_handlers::shaving_finish( player_activity *act, player *p ) -{ - p->add_msg_if_player( _( "You open up your kit and shave." ) ); - p->add_morale( MORALE_SHAVE, 8, 8, 240_minutes, 3_minutes ); - act->set_to_null(); -} - -void activity_handlers::haircut_finish( player_activity *act, player *p ) -{ - p->add_msg_if_player( _( "You give your hair a trim." ) ); - p->add_morale( MORALE_HAIRCUT, 3, 3, 480_minutes, 3_minutes ); - act->set_to_null(); -} - std::vector get_sorted_tiles_by_distance( const tripoint &abspos, const std::unordered_set &tiles ) { diff --git a/src/activity_handlers.h b/src/activity_handlers.h index 185258f1a009d..bfb9ff44bd3af 100644 --- a/src/activity_handlers.h +++ b/src/activity_handlers.h @@ -211,7 +211,6 @@ void gunmod_add_finish( player_activity *act, player *p ); void toolmod_add_finish( player_activity *act, player *p ); void clear_rubble_finish( player_activity *act, player *p ); void heat_item_finish( player_activity *act, player *p ); -void meditate_finish( player_activity *act, player *p ); void read_finish( player_activity *act, player *p ); void wait_finish( player_activity *act, player *p ); void wait_weather_finish( player_activity *act, player *p ); @@ -231,9 +230,6 @@ void chop_logs_finish( player_activity *act, player *p ); void chop_planks_finish( player_activity *act, player *p ); void jackhammer_finish( player_activity *act, player *p ); void fill_pit_finish( player_activity *act, player *p ); -void play_with_pet_finish( player_activity *act, player *p ); -void shaving_finish( player_activity *act, player *p ); -void haircut_finish( player_activity *act, player *p ); void robot_control_finish( player_activity *act, player *p ); void mind_splicer_finish( player_activity *act, player *p ); void spellcasting_finish( player_activity *act, player *p ); diff --git a/src/iuse.cpp b/src/iuse.cpp index 6d9bee87a8ee8..d0f8bcefb765b 100644 --- a/src/iuse.cpp +++ b/src/iuse.cpp @@ -126,17 +126,14 @@ static const activity_id ACT_FISH( "ACT_FISH" ); static const activity_id ACT_GAME( "ACT_GAME" ); static const activity_id ACT_GENERIC_GAME( "ACT_GENERIC_GAME" ); static const activity_id ACT_HACKSAW( "ACT_HACKSAW" ); -static const activity_id ACT_HAIRCUT( "ACT_HAIRCUT" ); static const activity_id ACT_HAND_CRANK( "ACT_HAND_CRANK" ); static const activity_id ACT_HEATING( "ACT_HEATING" ); static const activity_id ACT_JACKHAMMER( "ACT_JACKHAMMER" ); -static const activity_id ACT_MEDITATE( "ACT_MEDITATE" ); static const activity_id ACT_MIND_SPLICER( "ACT_MIND_SPLICER" ); static const activity_id ACT_OXYTORCH( "ACT_OXYTORCH" ); static const activity_id ACT_PICKAXE( "ACT_PICKAXE" ); static const activity_id ACT_PRY_NAILS( "ACT_PRY_NAILS" ); static const activity_id ACT_ROBOT_CONTROL( "ACT_ROBOT_CONTROL" ); -static const activity_id ACT_SHAVE( "ACT_SHAVE" ); static const activity_id ACT_VIBE( "ACT_VIBE" ); static const activity_id ACT_WASH( "ACT_WASH" ); @@ -960,8 +957,7 @@ cata::optional iuse::meditate( player *p, item *it, bool t, const tripoint return cata::nullopt; } if( p->has_trait( trait_SPIRITUAL ) ) { - const int moves = to_moves( 20_minutes ); - p->assign_activity( ACT_MEDITATE, moves ); + p->assign_activity( player_activity( meditate_activity_actor() ) ); } else { p->add_msg_if_player( _( "This %s probably meant a lot to someone at one time." ), it->tname() ); @@ -9131,8 +9127,7 @@ cata::optional iuse::shavekit( player *p, item *it, bool, const tripoint & if( !it->ammo_sufficient() ) { p->add_msg_if_player( _( "You need soap to use this." ) ); } else { - const int moves = to_moves( 5_minutes ); - p->assign_activity( ACT_SHAVE, moves ); + p->assign_activity( player_activity( shave_activity_actor() ) ); } return it->type->charges_to_use(); } @@ -9143,8 +9138,7 @@ cata::optional iuse::hairkit( player *p, item *it, bool, const tripoint & ) p->add_msg_if_player( m_info, _( "You can't do that while mounted." ) ); return cata::nullopt; } - const int moves = to_moves( 30_minutes ); - p->assign_activity( ACT_HAIRCUT, moves ); + p->assign_activity( player_activity( haircut_activity_actor() ) ); return it->type->charges_to_use(); } diff --git a/src/monexamine.cpp b/src/monexamine.cpp index 90168ad4cde80..3d23556174d14 100644 --- a/src/monexamine.cpp +++ b/src/monexamine.cpp @@ -44,8 +44,6 @@ static const quality_id qual_SHEAR( "SHEAR" ); static const efftype_id effect_sheared( "sheared" ); -static const activity_id ACT_PLAY_WITH_PET( "ACT_PLAY_WITH_PET" ); - static const efftype_id effect_controlled( "controlled" ); static const efftype_id effect_harnessed( "harnessed" ); static const efftype_id effect_has_bag( "has_bag" ); @@ -747,8 +745,7 @@ void monexamine::play_with( monster &z ) { std::string pet_name = z.get_name(); Character &player_character = get_player_character(); - player_character.assign_activity( ACT_PLAY_WITH_PET, rng( 50, 125 ) * 100 ); - player_character.activity.str_values.push_back( pet_name ); + player_character.assign_activity( player_activity( play_with_pet_activity_actor( pet_name ) ) ); } void monexamine::tie_or_untie( monster &z ) From 3acc54b5591102dd504194794f9d4ef60306ef5c Mon Sep 17 00:00:00 2001 From: chrispikula Date: Thu, 25 Mar 2021 01:38:10 -0600 Subject: [PATCH 320/453] Moved Scourge and Lobotomizer to weapon category in inventory (#47893) --- data/json/items/melee/misc.json | 10 ++++++---- 1 file changed, 6 insertions(+), 4 deletions(-) diff --git a/data/json/items/melee/misc.json b/data/json/items/melee/misc.json index ff891a10e4a30..9824040db4f42 100644 --- a/data/json/items/melee/misc.json +++ b/data/json/items/melee/misc.json @@ -18,8 +18,9 @@ { "id": "bullwhip_razor", "name": { "str": "scourge" }, - "type": "TOOL", - "description": "The \"cat 'o nine tails\", a handle with nine short leather whips each sporting a razor-sharp metal tip. This ancient instrument of torture causes massive bleeding but is an ineffecient weapon by design.", + "type": "GENERIC", + "category": "weapons", + "description": "The \"cat 'o nine tails\", a handle with nine short leather whips, each sporting a razor-sharp metal tip. This ancient instrument of torture causes massive bleeding, but by design is inefficient as a weapon.", "symbol": "/", "color": "brown", "weight": "3496 g", @@ -34,9 +35,10 @@ }, { "id": "lobotomizer", - "type": "TOOL", + "type": "GENERIC", + "category": "weapons", "name": { "str": "lobotomizer" }, - "description": "This is a hand-forged collapsible tool that has two axe heads and sharp shovel-like tip on one end. It can be used as a shovel, or you could chop some zombies with it instead.", + "description": "This is a hand-forged collapsible tool that has two axe heads and a sharp shovel-like tip on one end. It can be used as a shovel, or you could chop some zombies with it instead.", "weight": "2722 g", "volume": "1750 ml", "price": 25000, From 5711ac07a18919dfa11b6491e56973fe8c53e926 Mon Sep 17 00:00:00 2001 From: adamkad1 Date: Thu, 25 Mar 2021 08:38:57 +0100 Subject: [PATCH 321/453] Deluxe scrambled eggs from human meats (#47866) --- data/json/items/comestibles/meat_dishes.json | 6 +++++- data/json/recipes/recipe_food.json | 4 ++++ 2 files changed, 9 insertions(+), 1 deletion(-) diff --git a/data/json/items/comestibles/meat_dishes.json b/data/json/items/comestibles/meat_dishes.json index 13d6eb6577bd1..a6f27f6b5170f 100644 --- a/data/json/items/comestibles/meat_dishes.json +++ b/data/json/items/comestibles/meat_dishes.json @@ -951,7 +951,11 @@ "type": "COMESTIBLE", "id": "deluxe_eggs", "name": { "str_sp": "deluxe scrambled eggs" }, - "conditional_names": [ { "type": "COMPONENT_ID", "condition": "mutant", "name": { "str_sp": "\"deluxe\" scrambled eggs" } } ], + "conditional_names": [ + { "type": "FLAG", "condition": "CANNIBALISM", "name": { "str_sp": "deluxe scrambled eggheads" } }, + { "type": "FLAG", "condition": "STRICT_HUMANITARIANISM", "name": { "str_sp": "birdman's scrambled eggs" } }, + { "type": "COMPONENT_ID", "condition": "mutant", "name": { "str_sp": "\"deluxe\" scrambled eggs" } } + ], "weight": "198 g", "color": "yellow", "spoils_in": "2 days", diff --git a/data/json/recipes/recipe_food.json b/data/json/recipes/recipe_food.json index c3ab7e4257802..aa40e1a7ed67b 100644 --- a/data/json/recipes/recipe_food.json +++ b/data/json/recipes/recipe_food.json @@ -3708,6 +3708,8 @@ [ [ "bacon", 2 ], [ "meat_cooked", 1 ], + [ "human_cooked", 1 ], + [ "demihuman_cooked", 1 ], [ "mutant_meat_cooked", 1 ], [ "meat_smoked", 1 ], [ "dry_meat", 1 ], @@ -3750,6 +3752,8 @@ [ [ "bacon", 2 ], [ "meat_cooked", 1 ], + [ "human_cooked", 1 ], + [ "demihuman_cooked", 1 ], [ "mutant_meat_cooked", 1 ], [ "meat_smoked", 1 ], [ "dry_meat", 1 ], From c0671aee97a69a8f2a1ce09cd82afe70c45ed181 Mon Sep 17 00:00:00 2001 From: Saicchi <47158232+Saicchi@users.noreply.github.com> Date: Thu, 25 Mar 2021 04:39:53 -0300 Subject: [PATCH 322/453] Improve naming of uilist single letter parameters (#47722) --- src/ui.cpp | 110 ++++++++++++++++----------------- src/ui.h | 174 ++++++++++++++++++++++++++++++++++++++++++++--------- 2 files changed, 203 insertions(+), 81 deletions(-) diff --git a/src/ui.cpp b/src/ui.cpp index d99d07439716f..0165ca5a21570 100644 --- a/src/ui.cpp +++ b/src/ui.cpp @@ -62,74 +62,74 @@ static cata::optional hotkey_from_char( const int ch ) return input_event(); } -uilist_entry::uilist_entry( const std::string &T ) - : retval( -1 ), enabled( true ), hotkey( cata::nullopt ), txt( T ), +uilist_entry::uilist_entry( const std::string &txt ) + : retval( -1 ), enabled( true ), hotkey( cata::nullopt ), txt( txt ), text_color( c_red_red ) { } -uilist_entry::uilist_entry( const std::string &T, const std::string &D ) - : retval( -1 ), enabled( true ), hotkey( cata::nullopt ), txt( T ), - desc( D ), text_color( c_red_red ) +uilist_entry::uilist_entry( const std::string &txt, const std::string &desc ) + : retval( -1 ), enabled( true ), hotkey( cata::nullopt ), txt( txt ), + desc( desc ), text_color( c_red_red ) { } -uilist_entry::uilist_entry( const std::string &T, const int K ) - : retval( -1 ), enabled( true ), hotkey( hotkey_from_char( K ) ), txt( T ), +uilist_entry::uilist_entry( const std::string &txt, const int key ) + : retval( -1 ), enabled( true ), hotkey( hotkey_from_char( key ) ), txt( txt ), text_color( c_red_red ) { } -uilist_entry::uilist_entry( const std::string &T, const cata::optional &K ) - : retval( -1 ), enabled( true ), hotkey( K ), txt( T ), +uilist_entry::uilist_entry( const std::string &txt, const cata::optional &key ) + : retval( -1 ), enabled( true ), hotkey( key ), txt( txt ), text_color( c_red_red ) { } -uilist_entry::uilist_entry( const int R, const bool E, const int K, - const std::string &T ) - : retval( R ), enabled( E ), hotkey( hotkey_from_char( K ) ), txt( T ), +uilist_entry::uilist_entry( const int retval, const bool enabled, const int key, + const std::string &txt ) + : retval( retval ), enabled( enabled ), hotkey( hotkey_from_char( key ) ), txt( txt ), text_color( c_red_red ) { } -uilist_entry::uilist_entry( const int R, const bool E, - const cata::optional &K, - const std::string &T ) - : retval( R ), enabled( E ), hotkey( K ), txt( T ), +uilist_entry::uilist_entry( const int retval, const bool enabled, + const cata::optional &key, + const std::string &txt ) + : retval( retval ), enabled( enabled ), hotkey( key ), txt( txt ), text_color( c_red_red ) { } -uilist_entry::uilist_entry( const int R, const bool E, const int K, - const std::string &T, const std::string &D ) - : retval( R ), enabled( E ), hotkey( hotkey_from_char( K ) ), txt( T ), - desc( D ), text_color( c_red_red ) +uilist_entry::uilist_entry( const int retval, const bool enabled, const int key, + const std::string &txt, const std::string &desc ) + : retval( retval ), enabled( enabled ), hotkey( hotkey_from_char( key ) ), txt( txt ), + desc( desc ), text_color( c_red_red ) { } -uilist_entry::uilist_entry( const int R, const bool E, const int K, - const std::string &T, const std::string &D, - const std::string &C ) - : retval( R ), enabled( E ), hotkey( hotkey_from_char( K ) ), txt( T ), - desc( D ), ctxt( C ), text_color( c_red_red ) +uilist_entry::uilist_entry( const int retval, const bool enabled, const int key, + const std::string &txt, const std::string &desc, + const std::string &column ) + : retval( retval ), enabled( enabled ), hotkey( hotkey_from_char( key ) ), txt( txt ), + desc( desc ), ctxt( column ), text_color( c_red_red ) { } -uilist_entry::uilist_entry( const int R, const bool E, - const cata::optional &K, - const std::string &T, const std::string &D, - const std::string &C ) - : retval( R ), enabled( E ), hotkey( K ), txt( T ), - desc( D ), ctxt( C ), text_color( c_red_red ) +uilist_entry::uilist_entry( const int retval, const bool enabled, + const cata::optional &key, + const std::string &txt, const std::string &desc, + const std::string &column ) + : retval( retval ), enabled( enabled ), hotkey( key ), txt( txt ), + desc( desc ), ctxt( column ), text_color( c_red_red ) { } -uilist_entry::uilist_entry( const int R, const bool E, const int K, - const std::string &T, - const nc_color &H, const nc_color &C ) - : retval( R ), enabled( E ), hotkey( hotkey_from_char( K ) ), txt( T ), - hotkey_color( H ), text_color( C ) +uilist_entry::uilist_entry( const int retval, const bool enabled, const int key, + const std::string &txt, + const nc_color &keycolor, const nc_color &txtcolor ) + : retval( retval ), enabled( enabled ), hotkey( hotkey_from_char( key ) ), txt( txt ), + hotkey_color( keycolor ), text_color( txtcolor ) { } @@ -997,45 +997,47 @@ void uilist::reset() init(); } -void uilist::addentry( const std::string &str ) +void uilist::addentry( const std::string &txt ) { - entries.emplace_back( str ); + entries.emplace_back( txt ); } -void uilist::addentry( int r, bool e, int k, const std::string &str ) +void uilist::addentry( int retval, bool enabled, int key, const std::string &txt ) { - entries.emplace_back( r, e, k, str ); + entries.emplace_back( retval, enabled, key, txt ); } -void uilist::addentry( const int r, const bool e, - const cata::optional &k, - const std::string &str ) +void uilist::addentry( const int retval, const bool enabled, + const cata::optional &key, + const std::string &txt ) { - entries.emplace_back( r, e, k, str ); + entries.emplace_back( retval, enabled, key, txt ); } -void uilist::addentry_desc( const std::string &str, const std::string &desc ) +void uilist::addentry_desc( const std::string &txt, const std::string &desc ) { - entries.emplace_back( str, desc ); + entries.emplace_back( txt, desc ); } -void uilist::addentry_desc( int r, bool e, int k, const std::string &str, const std::string &desc ) +void uilist::addentry_desc( int retval, bool enabled, int key, const std::string &txt, + const std::string &desc ) { - entries.emplace_back( r, e, k, str, desc ); + entries.emplace_back( retval, enabled, key, txt, desc ); } -void uilist::addentry_col( int r, bool e, int k, const std::string &str, const std::string &column, +void uilist::addentry_col( int retval, bool enabled, int key, const std::string &txt, + const std::string &column, const std::string &desc ) { - entries.emplace_back( r, e, k, str, desc, column ); + entries.emplace_back( retval, enabled, key, txt, desc, column ); } -void uilist::addentry_col( const int r, const bool e, - const cata::optional &k, - const std::string &str, const std::string &column, +void uilist::addentry_col( const int retval, const bool enabled, + const cata::optional &key, + const std::string &txt, const std::string &column, const std::string &desc ) { - entries.emplace_back( r, e, k, str, desc, column ); + entries.emplace_back( retval, enabled, key, txt, desc, column ); } void uilist::settext( const std::string &str ) diff --git a/src/ui.h b/src/ui.h index 4677604374f79..8129a0d9e4ccc 100644 --- a/src/ui.h +++ b/src/ui.h @@ -70,24 +70,87 @@ struct uilist_entry { nc_color text_color; mvwzstr extratxt; - // In the following constructors, int K only support letters (a-z, A-Z) and + // In the following constructors, int key only support letters (a-z, A-Z) and // digits (0-9), MENU_AUTOASSIGN, and 0 or ' ' (disable hotkey). Other // values may not work under keycode mode. - explicit uilist_entry( const std::string &T ); - uilist_entry( const std::string &T, const std::string &D ); - uilist_entry( const std::string &T, int K ); - uilist_entry( const std::string &T, const cata::optional &K ); - uilist_entry( int R, bool E, int K, const std::string &T ); - uilist_entry( int R, bool E, const cata::optional &K, - const std::string &T ); - uilist_entry( int R, bool E, int K, const std::string &T, const std::string &D ); - uilist_entry( int R, bool E, int K, const std::string &T, const std::string &D, - const std::string &C ); - uilist_entry( int R, bool E, const cata::optional &K, - const std::string &T, const std::string &D, - const std::string &C ); - uilist_entry( int R, bool E, int K, const std::string &T, - const nc_color &H, const nc_color &C ); + + /** + * @param txt string that will be displayed on the entry first column + */ + explicit uilist_entry( const std::string &txt ); + /** + * @param txt string that will be displayed on the entry first column + * @param desc entry description if menu desc_enabled is true + * @see uilist::desc_enabled + */ + uilist_entry( const std::string &txt, const std::string &desc ); + /** + * @param txt string that will be displayed on the entry first column + * @param key hotkey character that when pressed will return this entry return value + */ + uilist_entry( const std::string &txt, int key ); + /** + * @param txt string that will be displayed on the entry first column + * @param key hotkey character that when pressed will return this entry return value + */ + uilist_entry( const std::string &txt, const cata::optional &key ); + /** + * @param retval return value of this option when selected during menu query + * @param enable is entry enabled. disabled entries will be grayed out and won't be selectable + * @param key hotkey character that when pressed will return this entry return value + * @param txt string that will be displayed on the entry first column + */ + uilist_entry( int retval, bool enabled, int key, const std::string &txt ); + /** + * @param retval return value of this option when selected during menu query + * @param enable is entry enabled. disabled entries will be grayed out and won't be selectable + * @param key hotkey character that when pressed will return this entry return value + * @param txt string that will be displayed on the entry first column + */ + uilist_entry( int retval, bool enabled, const cata::optional &key, + const std::string &txt ); + /** + * @param retval return value of this option when selected during menu query + * @param enable is entry enabled. disabled entries will be grayed out and won't be selectable + * @param key hotkey character that when pressed will return this entry return value + * @param txt string that will be displayed on the entry first column + * @param desc entry description if menu desc_enabled is true + * @see uilist::desc_enabled + */ + uilist_entry( int retval, bool enabled, int key, const std::string &txt, const std::string &desc ); + /** + * @param retval return value of this option when selected during menu query + * @param enable is entry enabled. disabled entries will be grayed out and won't be selectable + * @param key hotkey character that when pressed will return this entry return value + * @param txt string that will be displayed on the entry first column + * @param desc entry description if menu desc_enabled is true + * @param column string that will be displayed on the entry second column + * @see uilist::desc_enabled + */ + uilist_entry( int retval, bool enabled, int key, const std::string &txt, const std::string &desc, + const std::string &column ); + /** + * @param retval return value of this option when selected during menu query + * @param enable is entry enabled. disabled entries will be grayed out and won't be selectable + * @param key hotkey character that when pressed will return this entry return value + * @param txt string that will be displayed on the entry first column + * @param desc entry description if menu desc_enabled is true + * @param column string that will be displayed on the entry second column + * @see uilist::desc_enabled + */ + uilist_entry( int retval, bool enabled, const cata::optional &key, + const std::string &txt, const std::string &desc, + const std::string &column ); + /** + * @param retval return value of this option when selected during menu query + * @param enable is entry enabled. disabled entries will be grayed out and won't be selectable + * @param key hotkey character that when pressed will return this entry return value + * @param txt string that will be displayed on the entry first column + * @param keycolor color of the hotkey character + * @param txtcolor entry text string color + */ + uilist_entry( int retval, bool enabled, int key, const std::string &txt, + const nc_color &keycolor, const nc_color &txtcolor ); template::value>> explicit uilist_entry( Enum e, Args && ... args ) : @@ -214,21 +277,78 @@ class uilist // NOLINT(cata-xy) // In add_entry/add_entry_desc/add_entry_col, int k only support letters // (a-z, A-Z) and digits (0-9), MENU_AUTOASSIGN, and 0 or ' ' (disable // hotkey). Other values may not work under keycode mode. - void addentry( const std::string &str ); - void addentry( int r, bool e, int k, const std::string &str ); - void addentry( int r, bool e, const cata::optional &k, - const std::string &str ); + + /** + * @param txt string that will be displayed on the entry first column + */ + void addentry( const std::string &txt ); + /** + * @param retval return value of this option when selected during menu query + * @param enable is entry enabled. disabled entries will be grayed out and won't be selectable + * @param key hotkey character that when pressed will return this entry return value + * @param txt string that will be displayed on the entry first column + */ + void addentry( int retval, bool enabled, int key, const std::string &txt ); + /** + * @param retval return value of this option when selected during menu query + * @param enable is entry enabled. disabled entries will be grayed out and won't be selectable + * @param key hotkey character that when pressed will return this entry return value + * @param txt string that will be displayed on the entry first column + */ + void addentry( int retval, bool enabled, const cata::optional &key, + const std::string &txt ); + /** + * @param retval return value of this option when selected during menu query + * @param enable is entry enabled. disabled entries will be grayed out and won't be selectable + * @param key hotkey character that when pressed will return this entry return value + * @param txt string that will be displayed on the entry first column + * @param args list of parameters for string_format to format txt + */ template - void addentry( const int r, const bool e, K &&k, const char *const format, Args &&... args ) { - return addentry( r, e, std::forward( k ), + void addentry( const int retval, const bool enabled, K &&key, const char *const format, + Args &&... args ) { + return addentry( retval, enabled, std::forward( key ), string_format( format, std::forward( args )... ) ); } - void addentry_desc( const std::string &str, const std::string &desc ); - void addentry_desc( int r, bool e, int k, const std::string &str, const std::string &desc ); - void addentry_col( int r, bool e, int k, const std::string &str, const std::string &column, + /** + * @param txt string that will be displayed on the entry first column + * @param desc entry description if menu desc_enabled is true + * @see uilist::desc_enabled + */ + void addentry_desc( const std::string &txt, const std::string &desc ); + /** + * @param retval return value of this option when selected during menu query + * @param enable is entry enabled. disabled entries will be grayed out and won't be selectable + * @param key hotkey character that when pressed will return this entry return value + * @param txt string that will be displayed on the entry first column + * @param desc entry description if menu desc_enabled is true + * @see uilist::desc_enabled + */ + void addentry_desc( int retval, bool enabled, int key, const std::string &txt, + const std::string &desc ); + /** + * @param retval return value of this option when selected during menu query + * @param enable is entry enabled. disabled entries will be grayed out and won't be selectable + * @param key hotkey character that when pressed will return this entry return value + * @param txt string that will be displayed on the entry first column + * @param column string that will be displayed on the entry second column + * @param desc entry description if menu desc_enabled is true + * @see uilist::desc_enabled + */ + void addentry_col( int retval, bool enabled, int key, const std::string &txt, + const std::string &column, const std::string &desc = "" ); - void addentry_col( int r, bool e, const cata::optional &k, - const std::string &str, const std::string &column, + /** + * @param retval return value of this option when selected during menu query + * @param enable is entry enabled. disabled entries will be grayed out and won't be selectable + * @param key hotkey character that when pressed will return this entry return value + * @param txt string that will be displayed on the entry first column + * @param column string that will be displayed on the entry second column + * @param desc entry description if menu desc_enabled is true + * @see uilist::desc_enabled + */ + void addentry_col( int retval, bool enabled, const cata::optional &key, + const std::string &txt, const std::string &column, const std::string &desc = std::string() ); void settext( const std::string &str ); From f31212faea61ae0a2ccce4fa0e0f25bfc36dc2f8 Mon Sep 17 00:00:00 2001 From: Eric <52087122+Ramza13@users.noreply.github.com> Date: Thu, 25 Mar 2021 03:41:54 -0400 Subject: [PATCH 323/453] Adds effect_on_condition, allowing json scriptable events to happen at any time. (#48042) Co-authored-by: actual-nh <74678550+actual-nh@users.noreply.github.com> --- doc/EFFECT_ON_CONDITION.md | 33 ++++++ src/bionics.cpp | 2 + src/character.cpp | 2 + src/debug_menu.cpp | 8 ++ src/debug_menu.h | 1 + src/dialogue.h | 4 +- src/effect_on_condition.cpp | 228 ++++++++++++++++++++++++++++++++++++ src/effect_on_condition.h | 79 +++++++++++++ src/game.cpp | 5 +- src/game.h | 5 + src/init.cpp | 5 + src/mission_util.cpp | 2 +- src/npctalk.cpp | 15 ++- src/savegame.cpp | 38 ++++++ src/type_id.h | 3 + 15 files changed, 418 insertions(+), 12 deletions(-) create mode 100644 doc/EFFECT_ON_CONDITION.md create mode 100644 src/effect_on_condition.cpp create mode 100644 src/effect_on_condition.h diff --git a/doc/EFFECT_ON_CONDITION.md b/doc/EFFECT_ON_CONDITION.md new file mode 100644 index 0000000000000..2d764de4002cc --- /dev/null +++ b/doc/EFFECT_ON_CONDITION.md @@ -0,0 +1,33 @@ +### effect_on_condition +An effect_on_condition is an object allowing the combination of dialog conditions and effects with their usage outside of a dialog. When invoked, they will test their condition; on a pass, they will cause their effect. They can be activated automatically with any given frequency. (Note: effect_on_conditions use the npc dialog conditions and effects syntax, which allows checking related to, or targeting an effect at, an npc (for example: `npc_has_trait`). Using these commands in an effect_on_condition is not supported.) + +## Fields + +|Identifier|Type|Description| +|-|-|-| +| `recurrence_min`| int | The effect_on_condition is automatically invoked (activated) with at least this many seconds in-between. +| `recurrence_max`| int | The effect_on_condition is automatically invoked (activated) at least once this many seconds. +| `condition`| condition | The condition(s) under which this effect_on_condition, upon activation, will cause its effect. See the "Dialogue conditions" section of [NPCs](NPCs.md) for the full syntax. +| `deactivate_condition`| condition | *optional* When an effect_on_condition is automatically activated (invoked) and fails its condition(s), `deactivate_condition` will be tested if it exists and there is no `false_effect` entry. If it returns true, this effect_on_condition will no longer be invoked automatically every `recurrence_max` seconds. Whenever the player gains/loses a trait or bionic all deactivated effect_on_conditions will have `deactivate_condition` run; on a return of false, the effect_on_condition will start being run again. This is to allow adding effect_on_conditions for specific traits or bionics that don't waste time running when you don't have the target bionic/trait. See the "Dialogue conditions" section of [NPCs](NPCs.md) for the full syntax. +| `effect`| effect | The effect(s) caused if `condition` returns true upon activation. See the "Dialogue Effects" section of [NPCs](NPCs.md) for the full syntax. +| `false_effect`| effect | The effect(s) caused if `condition` returns false upon activation. See the "Dialogue Effects" section of [NPCs](NPCs.md) for the full syntax. + +## Examples: +```JSON + { + "type": "effect_on_condition", + "id": "test_deactivate", + "recurrence_min": 1, + "recurrence_max": 1, + "condition": { "u_has_trait": "SPIRITUAL" }, + "deactivate_condition": {"not":{ "u_has_trait": "SPIRITUAL" } }, + "effect": { "u_add_effect": "infection", "duration": 1 } + }, + { + "type": "effect_on_condition", + "id": "test_stats", + "recurrence_min": 1, + "recurrence_max": 10, + "condition": { "not": { "u_has_strength": 7 } }, + "effect": { "u_add_effect": "infection", "duration": 1 } + } diff --git a/src/bionics.cpp b/src/bionics.cpp index 72706762976de..2562f37684f43 100644 --- a/src/bionics.cpp +++ b/src/bionics.cpp @@ -2759,6 +2759,7 @@ void Character::add_bionic( const bionic_id &b ) if( !b->enchantments.empty() ) { recalculate_enchantment_cache(); } + effect_on_conditions::process_reactivate(); } void Character::remove_bionic( const bionic_id &b ) @@ -2800,6 +2801,7 @@ void Character::remove_bionic( const bionic_id &b ) if( !b->enchantments.empty() ) { recalculate_enchantment_cache(); } + effect_on_conditions::process_reactivate(); } int Character::num_bionics() const diff --git a/src/character.cpp b/src/character.cpp index cae189a0dd74d..9813694d1d924 100644 --- a/src/character.cpp +++ b/src/character.cpp @@ -11612,6 +11612,7 @@ void Character::on_mutation_gain( const trait_id &mid ) magic->on_mutation_gain( mid, *this ); update_type_of_scent( mid ); recalculate_enchantment_cache(); // mutations can have enchantments + effect_on_conditions::process_reactivate(); } void Character::on_mutation_loss( const trait_id &mid ) @@ -11620,6 +11621,7 @@ void Character::on_mutation_loss( const trait_id &mid ) magic->on_mutation_loss( mid ); update_type_of_scent( mid, false ); recalculate_enchantment_cache(); // mutations can have enchantments + effect_on_conditions::process_reactivate(); } void Character::on_stat_change( const std::string &stat, int value ) diff --git a/src/debug_menu.cpp b/src/debug_menu.cpp index d211f0d5a99d3..a7fbc2d575454 100644 --- a/src/debug_menu.cpp +++ b/src/debug_menu.cpp @@ -177,6 +177,7 @@ std::string enum_to_string( debug_menu::debug_menu case debug_menu::debug_menu_index::PRINT_NPC_MAGIC: return "PRINT_NPC_MAGIC"; case debug_menu::debug_menu_index::QUIT_NOSAVE: return "QUIT_NOSAVE"; case debug_menu::debug_menu_index::TEST_WEATHER: return "TEST_WEATHER"; + case debug_menu::debug_menu_index::WRITE_EOCS: return "WRITE_EOCS"; case debug_menu::debug_menu_index::SAVE_SCREENSHOT: return "SAVE_SCREENSHOT"; case debug_menu::debug_menu_index::GAME_REPORT: return "GAME_REPORT"; case debug_menu::debug_menu_index::DISPLAY_SCENTS_LOCAL: return "DISPLAY_SCENTS_LOCAL"; @@ -274,6 +275,7 @@ static int info_uilist( bool display_all_entries = true ) { uilist_entry( debug_menu_index::PRINT_FACTION_INFO, true, 'f', _( "Print faction info to console" ) ) }, { uilist_entry( debug_menu_index::PRINT_NPC_MAGIC, true, 'M', _( "Print NPC magic info to console" ) ) }, { uilist_entry( debug_menu_index::TEST_WEATHER, true, 'W', _( "Test weather" ) ) }, + { uilist_entry( debug_menu_index::WRITE_EOCS, true, 'C', _( "Write effect_on_condition(s) to eocs.output" ) ) }, { uilist_entry( debug_menu_index::TEST_MAP_EXTRA_DISTRIBUTION, true, 'e', _( "Test map extra list" ) ) }, { uilist_entry( debug_menu_index::GENERATE_EFFECT_LIST, true, 'L', _( "Generate effect list" ) ) }, }; @@ -2666,6 +2668,12 @@ void debug() } break; + case debug_menu_index::WRITE_EOCS: { + effect_on_conditions::write_eocs_to_file(); + popup( _( "effect_on_condition list written to eocs.output" ) ); + } + break; + case debug_menu_index::SAVE_SCREENSHOT: { #if defined(TILES) // check that the current '/screenshots' directory exists diff --git a/src/debug_menu.h b/src/debug_menu.h index c40f657c9f327..66498bbd88328 100644 --- a/src/debug_menu.h +++ b/src/debug_menu.h @@ -69,6 +69,7 @@ enum class debug_menu_index : int { PRINT_NPC_MAGIC, QUIT_NOSAVE, TEST_WEATHER, + WRITE_EOCS, SAVE_SCREENSHOT, GAME_REPORT, DISPLAY_SCENTS_LOCAL, diff --git a/src/dialogue.h b/src/dialogue.h index ab4a5e1fd95f1..24ab167dfa820 100644 --- a/src/dialogue.h +++ b/src/dialogue.h @@ -172,12 +172,12 @@ struct talk_effect_t { void set_effect_consequence( const talk_effect_fun_t &fun, dialogue_consequence con ); void set_effect_consequence( const std::function &ptr, dialogue_consequence con ); - void load_effect( const JsonObject &jo ); + void load_effect( const JsonObject &jo, const std::string &member_name ); void parse_sub_effect( const JsonObject &jo ); void parse_string_effect( const std::string &effect_id, const JsonObject &jo ); talk_effect_t() = default; - explicit talk_effect_t( const JsonObject & ); + explicit talk_effect_t( const JsonObject &, const std::string & ); /** * Functions that are called when the response is chosen. diff --git a/src/effect_on_condition.cpp b/src/effect_on_condition.cpp new file mode 100644 index 0000000000000..ebdb5d39a9dc2 --- /dev/null +++ b/src/effect_on_condition.cpp @@ -0,0 +1,228 @@ +#include "effect_on_condition.h" + +#include "avatar.h" +#include "cata_utility.h" +#include "character.h" +#include "condition.h" +#include "game.h" +#include "generic_factory.h" +#include "talker.h" +#include "type_id.h" + +namespace +{ +generic_factory +effect_on_condition_factory( "effect_on_condition" ); +} // namespace + +template<> +const effect_on_condition &effect_on_condition_id::obj() const +{ + return effect_on_condition_factory.obj( *this ); +} + +/** @relates string_id */ +template<> +bool string_id::is_valid() const +{ + return effect_on_condition_factory.is_valid( *this ); +} + +void effect_on_conditions::check_consistency() +{ +} + +void effect_on_condition::load( const JsonObject &jo, const std::string & ) +{ + activate_only = true; + if( jo.has_member( "recurrence_min" ) || jo.has_member( "recurrence_max" ) ) { + activate_only = false; + mandatory( jo, was_loaded, "recurrence_min", recurrence_min ); + mandatory( jo, was_loaded, "recurrence_max", recurrence_max ); + if( recurrence_max < recurrence_min ) { + jo.throw_error( "recurrence_max cannot be smaller than recurrence_min." ); + } + } + if( jo.has_member( "deactivate_condition" ) ) { + read_condition( jo, "deactivate_condition", deactivate_condition, false ); + has_deactivate_condition = true; + } + if( jo.has_member( "condition" ) ) { + read_condition( jo, "condition", condition, false ); + has_condition = true; + } + true_effect.load_effect( jo, "effect" ); + + if( jo.has_member( "false_effect" ) ) { + false_effect.load_effect( jo, "false_effect" ); + has_false_effect = true; + } +} + +static time_duration next_recurrence( const effect_on_condition_id &eoc ) +{ + return rng( eoc->recurrence_min, eoc->recurrence_max ); +} + +void effect_on_conditions::load_new_character() +{ + for( const effect_on_condition &eoc : effect_on_conditions::get_all() ) { + if( !eoc.activate_only ) { + queued_eoc new_eoc = queued_eoc{ eoc.id, true, calendar::turn + next_recurrence( eoc.id ) }; + g->queued_effect_on_conditions.push( new_eoc ); + } + } +} + +void effect_on_conditions::queue_effect_on_condition( time_duration duration, + effect_on_condition_id eoc ) +{ + queued_eoc new_eoc = queued_eoc{ eoc, false, calendar::turn + duration }; + g->queued_effect_on_conditions.push( new_eoc ); +} + +void effect_on_conditions::process_effect_on_conditions() +{ + dialogue d; + standard_npc default_npc( "Default" ); + d.alpha = get_talker_for( get_avatar() ); + d.beta = get_talker_for( default_npc ); + std::vector eocs_to_queue; + while( !g->queued_effect_on_conditions.empty() && + g->queued_effect_on_conditions.top().time <= calendar::turn ) { + queued_eoc top = g->queued_effect_on_conditions.top(); + bool activated = top.eoc->activate( d ); + if( top.recurring ) { + if( activated ) { // It worked so add it back + queued_eoc new_eoc = queued_eoc{ top.eoc, true, calendar::turn + next_recurrence( top.eoc ) }; + eocs_to_queue.push_back( new_eoc ); + } else { + if( !top.eoc->check_deactivate() ) { // It failed but shouldn't be deactivated so add it back + queued_eoc new_eoc = queued_eoc{ top.eoc, true, calendar::turn + next_recurrence( top.eoc ) }; + eocs_to_queue.push_back( new_eoc ); + } else { // It failed and should be deactivated for now + g->inactive_effect_on_condition_vector.push_back( top.eoc ); + } + } + } + g->queued_effect_on_conditions.pop(); + } + for( const queued_eoc &q_eoc : eocs_to_queue ) { + g->queued_effect_on_conditions.push( q_eoc ); + } +} + +void effect_on_conditions::process_reactivate() +{ + dialogue d; + standard_npc default_npc( "Default" ); + d.alpha = get_talker_for( get_avatar() ); + d.beta = get_talker_for( default_npc ); + + std::vector ids_to_reactivate; + for( const effect_on_condition_id &eoc : g->inactive_effect_on_condition_vector ) { + if( !eoc->check_deactivate() ) { + ids_to_reactivate.push_back( eoc ); + } + } + for( const effect_on_condition_id &eoc : ids_to_reactivate ) { + g->queued_effect_on_conditions.push( queued_eoc{ eoc, true, calendar::turn + next_recurrence( eoc ) } ); + g->inactive_effect_on_condition_vector.erase( std::remove( + g->inactive_effect_on_condition_vector.begin(), g->inactive_effect_on_condition_vector.end(), eoc ), + g->inactive_effect_on_condition_vector.end() ); + } +} + +bool effect_on_condition::activate( dialogue &d ) const +{ + if( !has_condition || condition( d ) ) { + true_effect.apply( d ); + return true; + } + + if( has_false_effect ) { + false_effect.apply( d ); + } + return false; +} + +bool effect_on_condition::check_deactivate() const +{ + if( !has_deactivate_condition || has_false_effect ) { + return false; + } + dialogue d; + standard_npc default_npc( "Default" ); + d.alpha = get_talker_for( get_avatar() ); + d.beta = get_talker_for( default_npc ); + return deactivate_condition( d ); +} + +void effect_on_conditions::clear() +{ + while( !g->queued_effect_on_conditions.empty() ) { + g->queued_effect_on_conditions.pop(); + } + g->inactive_effect_on_condition_vector.clear(); +} + +void effect_on_conditions::write_eocs_to_file() +{ + write_to_file( "eocs.output", [&]( std::ostream & testfile ) { + testfile << "id;timepoint;recurring" << std::endl; + + testfile << "queued eocs:" << std::endl; + std::vector temp_queue; + while( !g->queued_effect_on_conditions.empty() ) { + temp_queue.push_back( g->queued_effect_on_conditions.top() ); + g->queued_effect_on_conditions.pop(); + } + + for( const auto &queue_entry : temp_queue ) { + time_duration temp = queue_entry.time - calendar::turn; + testfile << queue_entry.eoc.c_str() << ";" << to_string( temp ) << ";" << + ( queue_entry.recurring ? "recur" : "non" ) << std::endl ; + } + + for( const auto &queued : temp_queue ) { + g->queued_effect_on_conditions.push( queued ); + } + + testfile << "inactive eocs:" << std::endl; + for( const effect_on_condition_id &eoc : g->inactive_effect_on_condition_vector ) { + testfile << eoc.c_str() << std::endl; + } + + }, "eocs test file" ); +} + +void effect_on_condition::finalize() +{ +} + +void effect_on_conditions::finalize_all() +{ + effect_on_condition_factory.finalize(); + for( const effect_on_condition &eoc : effect_on_condition_factory.get_all() ) { + const_cast( eoc ).finalize(); + } +} + +void effect_on_condition::check() const +{ +} + +const std::vector &effect_on_conditions::get_all() +{ + return effect_on_condition_factory.get_all(); +} + +void effect_on_conditions::reset() +{ + effect_on_condition_factory.reset(); +} + +void effect_on_conditions::load( const JsonObject &jo, const std::string &src ) +{ + effect_on_condition_factory.load( jo, src ); +} diff --git a/src/effect_on_condition.h b/src/effect_on_condition.h new file mode 100644 index 0000000000000..0d4ffae657845 --- /dev/null +++ b/src/effect_on_condition.h @@ -0,0 +1,79 @@ +#pragma once +#ifndef CATA_SRC_EFFECT_ON_CONDITION_H +#define CATA_SRC_EFFECT_ON_CONDITION_H + +#include +#include + +#include "calendar.h" +#include "dialogue.h" +#include "json.h" +#include "type_id.h" + +template +class generic_factory; + +struct queued_eoc { + public: + effect_on_condition_id eoc; + bool recurring = false; + time_point time; +}; + +struct eoc_compare { + bool operator()( const queued_eoc &lhs, const queued_eoc &rhs ) const { + return lhs.time > rhs.time; + } +}; + +struct effect_on_condition { + public: + friend class generic_factory; + bool was_loaded = false; + effect_on_condition_id id; + + std::function condition; + std::function deactivate_condition; + talk_effect_t true_effect; + talk_effect_t false_effect; + bool has_deactivate_condition = false; + bool has_condition = false; + bool has_false_effect = false; + bool activate_only = true; + + time_duration recurrence_min = 1_seconds; + time_duration recurrence_max = 1_seconds; + bool activate( dialogue &d ) const; + bool check_deactivate() const; + void load( const JsonObject &jo, const std::string &src ); + void finalize(); + void check() const; + effect_on_condition() = default; +}; +namespace effect_on_conditions +{ +/** Get all currently loaded effect_on_conditions */ +const std::vector &get_all(); +/** Finalize all loaded effect_on_conditions */ +void finalize_all(); +/** Clear all loaded effects on condition (invalidating any pointers) */ +void reset(); +/** Load effect on condition from JSON definition */ +void load( const JsonObject &jo, const std::string &src ); +/** Checks all loaded from JSON are valid */ +void check_consistency(); +/** Sets up the initial queue for a new character */ +void load_new_character(); +/** queue an eoc to happen in the future */ +void queue_effect_on_condition( time_duration duration, effect_on_condition_id eoc ); +/** called every turn to process the queued eocs */ +void process_effect_on_conditions(); +/** called after certain events to test whether to reactivate eocs */ +void process_reactivate(); +/** clear all queued and inactive eocs */ +void clear(); +/** write out all queued eocs and inactive eocs to a file for testing */ +void write_eocs_to_file(); +} // namespace effect_on_conditions + +#endif // CATA_SRC_EFFECT_ON_CONDITION_H diff --git a/src/game.cpp b/src/game.cpp index fec01e90318dd..54890c3ddc798 100644 --- a/src/game.cpp +++ b/src/game.cpp @@ -644,7 +644,7 @@ void game::setup() // reset follower list follower_ids.clear(); scent.reset(); - + effect_on_conditions::clear(); remoteveh_cache_time = calendar::before_time_starts; remoteveh_cache = nullptr; // back to menu for save loading, new game etc @@ -848,6 +848,8 @@ bool game::start_game() tripoint_abs_omt abs_omt = u.global_omt_location(); const oter_id &cur_ter = overmap_buffer.ter( abs_omt ); get_event_bus().send( abs_omt.raw(), cur_ter ); + + effect_on_conditions::load_new_character(); return true; } @@ -1610,6 +1612,7 @@ bool game::do_turn() ui_manager::redraw(); refresh_display(); } + effect_on_conditions::process_effect_on_conditions(); if( levz >= 0 && !u.is_underwater() ) { handle_weather_effects( weather.weather_id ); diff --git a/src/game.h b/src/game.h index ed032374b833f..3499b90f980d2 100644 --- a/src/game.h +++ b/src/game.h @@ -9,6 +9,7 @@ #include #include #include +#include #include #include #include @@ -20,6 +21,7 @@ #include "coordinates.h" #include "creature.h" #include "cursesdef.h" +#include "effect_on_condition.h" #include "enums.h" #include "game_constants.h" #include "item_location.h" @@ -1043,6 +1045,9 @@ class game weather_manager weather; + std::vector inactive_effect_on_condition_vector; + std::priority_queue, eoc_compare> queued_effect_on_conditions; + int mostseen = 0; // # of mons seen last turn; if this increases, set safe_mode to SAFE_MODE_STOP private: shared_ptr_fast u_shared_ptr; diff --git a/src/init.cpp b/src/init.cpp index 0f031898eabc0..5c3c94860f1be 100644 --- a/src/init.cpp +++ b/src/init.cpp @@ -31,6 +31,7 @@ #include "dialogue.h" #include "disease.h" #include "effect.h" +#include "effect_on_condition.h" #include "emit.h" #include "event_statistics.h" #include "faction.h" @@ -242,6 +243,7 @@ void DynamicDataLoader::initialize() add( "json_flag", &json_flag::load_all ); add( "fault", &fault::load_fault ); add( "relic_procgen_data", &relic_procgen_data::load_relic_procgen_data ); + add( "effect_on_condition", &effect_on_conditions::load ); add( "field_type", &field_types::load ); add( "weather_type", &weather_types::load ); add( "ammo_effect", &ammo_effects::load ); @@ -529,6 +531,7 @@ void DynamicDataLoader::unload_data() dreams.clear(); emit::reset(); event_statistic::reset(); + effect_on_conditions::reset(); event_transformation::reset(); faction_template::reset(); fault::reset(); @@ -619,6 +622,7 @@ void DynamicDataLoader::finalize_loaded_data( loading_ui &ui ) { _( "Flags" ), &json_flag::finalize_all }, { _( "Body parts" ), &body_part_type::finalize_all }, { _( "Weather types" ), &weather_types::finalize_all }, + { _( "Effect on conditions" ), &effect_on_conditions::finalize_all }, { _( "Field types" ), &field_types::finalize_all }, { _( "Ammo effects" ), &ammo_effects::finalize_all }, { _( "Emissions" ), &emit::finalize }, @@ -703,6 +707,7 @@ void DynamicDataLoader::check_consistency( loading_ui &ui ) }, { _( "Vitamins" ), &vitamin::check_consistency }, { _( "Weather types" ), &weather_types::check_consistency }, + { _( "Effect on conditions" ), &effect_on_conditions::check_consistency }, { _( "Field types" ), &field_types::check_consistency }, { _( "Ammo effects" ), &ammo_effects::check_consistency }, { _( "Emissions" ), &emit::check_consistency }, diff --git a/src/mission_util.cpp b/src/mission_util.cpp index b3fa1e641feea..2458745988feb 100644 --- a/src/mission_util.cpp +++ b/src/mission_util.cpp @@ -529,7 +529,7 @@ bool mission_type::parse_funcs( const JsonObject &jo, std::functionfind_npc( miss->get_npc_id() ); diff --git a/src/npctalk.cpp b/src/npctalk.cpp index facc2caad6eff..7945b7cb96a19 100644 --- a/src/npctalk.cpp +++ b/src/npctalk.cpp @@ -2134,9 +2134,9 @@ talk_topic talk_effect_t::apply( dialogue &d ) const return next_topic; } -talk_effect_t::talk_effect_t( const JsonObject &jo ) +talk_effect_t::talk_effect_t( const JsonObject &jo, const std::string &member_name ) { - load_effect( jo ); + load_effect( jo, member_name ); if( jo.has_object( "topic" ) ) { next_topic = load_inline_topic( jo.get_object( "topic" ) ); } else if( jo.has_string( "topic" ) ) { @@ -2414,7 +2414,7 @@ void talk_effect_t::parse_string_effect( const std::string &effect_id, const Jso jo.throw_error( "unknown effect string", effect_id ); } -void talk_effect_t::load_effect( const JsonObject &jo ) +void talk_effect_t::load_effect( const JsonObject &jo, const std::string &member_name ) { if( jo.has_member( "opinion" ) ) { JsonIn *ji = jo.get_raw( "opinion" ); @@ -2426,7 +2426,6 @@ void talk_effect_t::load_effect( const JsonObject &jo ) // Same format as when saving a game (-: mission_opinion.deserialize( *ji ); } - static const std::string member_name( "effect" ); if( !jo.has_member( member_name ) ) { return; } else if( jo.has_string( member_name ) ) { @@ -2487,11 +2486,11 @@ talk_response::talk_response( const JsonObject &jo ) } if( jo.has_member( "success" ) ) { JsonObject success_obj = jo.get_object( "success" ); - success = talk_effect_t( success_obj ); + success = talk_effect_t( success_obj, "effect" ); } else if( jo.has_string( "topic" ) ) { // This is for simple topic switching without a possible failure success.next_topic = talk_topic( jo.get_string( "topic" ) ); - success.load_effect( jo ); + success.load_effect( jo, "effect" ); } else if( jo.has_object( "topic" ) ) { success.next_topic = load_inline_topic( jo.get_object( "topic" ) ); } @@ -2500,7 +2499,7 @@ talk_response::talk_response( const JsonObject &jo ) } if( jo.has_member( "failure" ) ) { JsonObject failure_obj = jo.get_object( "failure" ); - failure = talk_effect_t( failure_obj ); + failure = talk_effect_t( failure_obj, "effect" ); } // TODO: mission_selected @@ -2767,7 +2766,7 @@ json_dynamic_line_effect::json_dynamic_line_effect( const JsonObject &jo, { std::function tmp_condition; read_condition( jo, "condition", tmp_condition, true ); - talk_effect_t tmp_effect = talk_effect_t( jo ); + talk_effect_t tmp_effect = talk_effect_t( jo, "effect" ); // if the topic has a sentinel, it means implicitly add a check for the sentinel value // and do not run the effects if it is set. if it is not set, run the effects and // set the sentinel diff --git a/src/savegame.cpp b/src/savegame.cpp index 96a1b941acfd4..ce41928e5472c 100644 --- a/src/savegame.cpp +++ b/src/savegame.cpp @@ -101,6 +101,26 @@ void game::serialize( std::ostream &fout ) json.member( "stats_tracker", *stats_tracker_ptr ); json.member( "achievements_tracker", *achievements_tracker_ptr ); + //save queued effect_on_conditions + std::vector temp_queue; + while( !g->queued_effect_on_conditions.empty() ) { + temp_queue.push_back( g->queued_effect_on_conditions.top() ); + g->queued_effect_on_conditions.pop(); + } + json.member( "queued_effect_on_conditions" ); + json.start_array(); + + for( const auto &queued : temp_queue ) { + g->queued_effect_on_conditions.push( queued ); + json.start_object(); + json.member( "time", queued.time ); + json.member( "eoc", queued.eoc ); + json.member( "recurring", queued.recurring ); + json.end_object(); + } + json.end_array(); + json.member( "inactive_eocs", inactive_effect_on_condition_vector ); + json.member( "player", u ); Messages::serialize( json ); @@ -232,6 +252,24 @@ void game::unserialize( std::istream &fin ) data.read( "player", u ); data.read( "stats_tracker", *stats_tracker_ptr ); data.read( "achievements_tracker", *achievements_tracker_ptr ); + + //load queued_eocs + for( JsonObject elem : data.get_array( "queued_effect_on_conditions" ) ) { + queued_eoc temp; + temp.time = time_point( elem.get_int( "time" ) ); + temp.eoc = effect_on_condition_id( elem.get_string( "eoc" ) ); + temp.recurring = elem.get_bool( "recurring" ); + g->queued_effect_on_conditions.push( temp ); + } + //load inactive queued_eocs + for( JsonObject elem : data.get_array( "inactive_effect_on_conditions" ) ) { + queued_eoc temp; + temp.time = time_point( elem.get_int( "time" ) ); + temp.eoc = effect_on_condition_id( elem.get_string( "eoc" ) ); + temp.recurring = elem.get_bool( "recurring" ); + g->queued_effect_on_conditions.push( temp ); + } + data.read( "inactive_eocs", inactive_effect_on_condition_vector ); Messages::deserialize( data ); } catch( const JsonError &jsonerr ) { diff --git a/src/type_id.h b/src/type_id.h index b1f9ee6b4b2c7..363f8ae8bb117 100644 --- a/src/type_id.h +++ b/src/type_id.h @@ -36,6 +36,9 @@ using construction_group_str_id = string_id; struct clothing_mod; using clothing_mod_id = string_id; +struct effect_on_condition; +using effect_on_condition_id = string_id; + class effect_type; using efftype_id = string_id; From a1e64da23a6de317eababb3a3ccd98d96abfa885 Mon Sep 17 00:00:00 2001 From: Salty Panda Date: Thu, 25 Mar 2021 20:30:22 +0100 Subject: [PATCH 324/453] [Magiclysm] Add spellcraft skillbook (#47431) * add spellcraft skillbook * Spawning too * Change spawns --- .../mods/Magiclysm/itemgroups/itemgroups.json | 24 +++++++++--- data/mods/Magiclysm/items/books.json | 39 +++++++++++++++++++ 2 files changed, 58 insertions(+), 5 deletions(-) create mode 100644 data/mods/Magiclysm/items/books.json diff --git a/data/mods/Magiclysm/itemgroups/itemgroups.json b/data/mods/Magiclysm/itemgroups/itemgroups.json index 54f1baa86964e..98a036a4cba1d 100644 --- a/data/mods/Magiclysm/itemgroups/itemgroups.json +++ b/data/mods/Magiclysm/itemgroups/itemgroups.json @@ -32,7 +32,8 @@ { "group": "spellbook_loot_1", "prob": 3 }, { "group": "magic_recipe_basic", "prob": 3 }, { "group": "magic_recipe_advanced", "prob": 1 }, - { "group": "dragon_books", "prob": 3 } + { "group": "dragon_books", "prob": 3 }, + { "item": "spellcraft_theory", "prob": 2 } ] }, { @@ -42,13 +43,23 @@ { "group": "spellbook_loot_0", "prob": 6 }, { "group": "magic_recipe_basic", "prob": 6 }, { "group": "magic_recipe_advanced", "prob": 2 }, - { "group": "dragon_books", "prob": 5 } + { "group": "dragon_books", "prob": 5 }, + { "group": "spellcraft_books", "prob": 4 } ] }, { "type": "item_group", "id": "exotic_books", - "items": [ { "group": "spellbook_loot_1", "prob": 3 }, { "group": "dragon_books", "prob": 2 } ] + "items": [ + { "group": "spellbook_loot_1", "prob": 3 }, + { "group": "dragon_books", "prob": 2 }, + { "group": "spellcraft_books", "prob": 1 } + ] + }, + { + "type": "item_group", + "id": "spellcraft_books", + "items": [ { "item": "spellcraft_theory_basic", "prob": 70 }, { "item": "spellcraft_theory", "prob": 30 } ] }, { "type": "item_group", @@ -131,7 +142,8 @@ { "group": "spell_scroll_tier_1", "prob": 60 }, { "group": "spell_scroll_tier_2", "prob": 30 }, { "group": "magic_recipe_basic", "prob": 50 }, - { "group": "magic_recipe_advanced", "prob": 16 } + { "group": "magic_recipe_advanced", "prob": 16 }, + { "group": "spellcraft_books", "prob": 40 } ] }, { @@ -142,7 +154,8 @@ { "group": "spellbook_tier_0", "prob": 100 }, { "group": "spellbook_tier_0", "prob": 80 }, { "group": "spellbook_tier_0", "prob": 60 }, - { "group": "spellbook_tier_0", "prob": 20 } + { "group": "spellbook_tier_0", "prob": 20 }, + { "item": "spellcraft_theory_basic", "prob": 10 } ] }, { @@ -1014,6 +1027,7 @@ { "group": "enchanted_tokens_tool", "prob": 15 }, { "group": "enchanted_tokens_weapon", "prob": 5 }, { "group": "potions_common", "prob": 35 }, + { "group": "spellcraft_books", "prob": 10 }, { "distribution": [ { "group": "enchanted_wands_lesser", "prob": 15 }, diff --git a/data/mods/Magiclysm/items/books.json b/data/mods/Magiclysm/items/books.json new file mode 100644 index 0000000000000..ba3642e57161e --- /dev/null +++ b/data/mods/Magiclysm/items/books.json @@ -0,0 +1,39 @@ +[ + { + "id": "spellcraft_theory", + "type": "BOOK", + "name": { "str": "Spellcraft Theory", "str_pl": "copies of Spellcraft Theory" }, + "description": "A intermediate textbook on magical theories.", + "weight": "1587 g", + "volume": "1750 ml", + "longest_side": "22 cm", + "price": 8200, + "price_postapoc": 750, + "bashing": 5, + "material": [ "paper" ], + "symbol": "?", + "color": "blue", + "skill": "spellcraft", + "required_level": 2, + "max_level": 4, + "intelligence": 12, + "time": "60 m", + "fun": -1 + }, + { + "id": "spellcraft_theory_basic", + "type": "BOOK", + "copy-from": "spellcraft_theory", + "name": { "str": "Basic Spellcraft Theory", "str_pl": "copies of Basic Spellcraft Theory" }, + "description": "A beginner textbook on magical theories.", + "weight": "1087 g", + "volume": "1450 ml", + "price": 5200, + "price_postapoc": 550, + "required_level": 0, + "max_level": 2, + "intelligence": 9, + "time": "45 m", + "fun": 0 + } +] From fdeeb88825997bfe4ee07db3528b040992384e96 Mon Sep 17 00:00:00 2001 From: OromisElf Date: Thu, 25 Mar 2021 20:39:35 +0100 Subject: [PATCH 325/453] added golem core, summon golem spell and ways to find golem core (#47500) * added golem core, summon golem spell and ways to find golem core golemancer can summon a clay golem with a golem core as a focus; golem cores aren't crafteable YET * linted attunements forgot to do that >.> * added a recipe for golem core and a basic golemancy proficiency --- .../Spells/attunements/Golemancer.json | 52 +++++++++++++++++++ .../mods/Magiclysm/itemgroups/itemgroups.json | 4 ++ data/mods/Magiclysm/items/constructs.json | 15 ++++++ data/mods/Magiclysm/proficiencies.json | 10 ++++ .../mods/Magiclysm/recipes/blacksmithing.json | 25 +++++++++ data/mods/Magiclysm/traits/attunements.json | 2 +- 6 files changed, 107 insertions(+), 1 deletion(-) diff --git a/data/mods/Magiclysm/Spells/attunements/Golemancer.json b/data/mods/Magiclysm/Spells/attunements/Golemancer.json index 5656a3651d3b9..eda42f5345646 100644 --- a/data/mods/Magiclysm/Spells/attunements/Golemancer.json +++ b/data/mods/Magiclysm/Spells/attunements/Golemancer.json @@ -1,4 +1,56 @@ [ + { + "id": "summon_golem", + "type": "requirement", + "components": [ [ [ "golemcore", 1 ] ] ] + }, + { + "id": "summon_golem_clay", + "type": "SPELL", + "spell_class": "GOLEMANCER", + "name": "Summon Claygolem", + "description": "Use a golem core as a focus to shape clay into a roughly humanoid shape and animate it for some time.", + "valid_targets": [ "ground" ], + "effect": "summon", + "effect_str": "mon_claygolem", + "shape": "blast", + "base_casting_time": 3500, + "casting_time_increment": -100, + "final_casting_time": 2000, + "base_energy_cost": 500, + "energy_source": "MANA", + "difficulty": 6, + "max_level": 35, + "min_damage": 1, + "max_damage": 1, + "min_duration": 30000, + "max_duration": 90000, + "duration_increment": 1715, + "min_range": 3, + "max_range": 3, + "components": "summon_golem", + "extra_effects": [ { "id": "summon_golem_focus" } ], + "flags": [ "SOMATIC", "VERBAL", "CONCENTRATE" ] + }, + { + "id": "summon_golem_focus", + "type": "SPELL", + "spell_class": "NONE", + "name": "Give back core", + "description": "Gives back a golem's core. You should not see this spell", + "valid_targets": [ "self" ], + "effect": "spawn_item", + "effect_str": "golemcore", + "shape": "blast", + "base_casting_time": 100, + "base_energy_cost": 1000, + "energy_source": "MANA", + "difficulty": 1, + "min_damage": 1, + "max_damage": 1, + "duration_increment": 1, + "flags": [ "PERMANENT", "NO_LEGS", "CONCENTRATE" ] + }, { "type": "SPELL", "id": "golem_push", diff --git a/data/mods/Magiclysm/itemgroups/itemgroups.json b/data/mods/Magiclysm/itemgroups/itemgroups.json index 98a036a4cba1d..4be9b3778fff3 100644 --- a/data/mods/Magiclysm/itemgroups/itemgroups.json +++ b/data/mods/Magiclysm/itemgroups/itemgroups.json @@ -344,6 +344,7 @@ "type": "item_group", "//": "all enchanted miscellanious items", "items": [ + { "item": "golemcore", "prob": 10 }, { "item": "heat_cube", "prob": 100 }, { "item": "mkey_opening", "prob": 100 }, { "item": "mtorch_everburning", "prob": 100 }, @@ -818,6 +819,7 @@ }, { "distribution": [ + { "item": "golemcore", "prob": 20 }, { "item": "animist_doll_skeleton", "prob": 10 }, { "item": "animist_doll_zombie", "prob": 20 }, { "item": "animist_doll_decayed_pouncer", "prob": 3 } @@ -936,6 +938,7 @@ }, { "distribution": [ + { "item": "golemcore", "prob": 10 }, { "item": "recovery_spellbook", "prob": 5 }, { "item": "eshaper_spellbook", "prob": 10 }, { "item": "spell_scroll_recover_stamina", "prob": 50 }, @@ -1058,6 +1061,7 @@ }, { "distribution": [ + { "item": "golemcore", "prob": 3 }, { "item": "light_manipulation_spellbook", "prob": 5 }, { "item": "translocate_spellbook", "prob": 2 }, { "item": "spell_scroll_obfuscated_body", "prob": 50 } diff --git a/data/mods/Magiclysm/items/constructs.json b/data/mods/Magiclysm/items/constructs.json index e1288be2576b5..5b534b18d5aa4 100644 --- a/data/mods/Magiclysm/items/constructs.json +++ b/data/mods/Magiclysm/items/constructs.json @@ -1,4 +1,19 @@ [ + { + "type": "GENERIC", + "id": "golemcore", + "symbol": ".", + "color": "red", + "name": "golem core", + "description": "The \"heart\" of a golem. Makes a soft humming noise when you hold it close to your ear.", + "price": 10000, + "price_postapoc": 5000, + "material": [ "orichalcum_metal" ], + "weight": "5 kg", + "volume": "1 L", + "bashing": 6, + "flags": [ "NO_REPAIR", "FRAGILE_MELEE" ] + }, { "type": "GENERIC", "id": "broken_claygolem", diff --git a/data/mods/Magiclysm/proficiencies.json b/data/mods/Magiclysm/proficiencies.json index 2eaf25d02e2c8..6d13fc27d1d33 100644 --- a/data/mods/Magiclysm/proficiencies.json +++ b/data/mods/Magiclysm/proficiencies.json @@ -19,5 +19,15 @@ "default_time_multiplier": 2, "default_fail_multiplier": 2, "required_proficiencies": [ "prof_alchemy" ] + }, + { + "type": "proficiency", + "id": "prof_golemancy_basic", + "name": { "str": "Basic Golemancy" }, + "description": "Infusing shaped material with your will and the ability to move is hard but you're starting to get it.", + "can_learn": true, + "time_to_learn": "4 h", + "default_time_multiplier": 1.5, + "default_fail_multiplier": 2 } ] diff --git a/data/mods/Magiclysm/recipes/blacksmithing.json b/data/mods/Magiclysm/recipes/blacksmithing.json index 95a4f7c4e0736..5033df4212c0b 100644 --- a/data/mods/Magiclysm/recipes/blacksmithing.json +++ b/data/mods/Magiclysm/recipes/blacksmithing.json @@ -70,5 +70,30 @@ "proficiencies": [ { "proficiency": "prof_alchemy", "required": false, "time_multiplier": 1.5, "fail_multiplier": 5 } ], "tools": [ [ [ "surface_heat", 10, "LIST" ] ] ], "components": [ [ [ "charcoal", 50 ] ], [ [ "crystallized_mana", 10 ] ], [ [ "denat_alcohol", 10 ] ] ] + }, + { + "type": "recipe", + "activity_level": "MODERATE_EXERCISE", + "result": "golemcore", + "category": "CC_ENCHANTED", + "subcategory": "CSC_ENCHANTED_OTHER", + "skill_used": "fabrication", + "skills_required": [ "spellcraft", 6 ], + "difficulty": 5, + "time": "150 m", + "book_learn": [ [ "metal_legends", 6 ] ], + "qualities": [ + { "id": "CHISEL", "level": 2 }, + { "id": "MANA_INFUSE", "level": 2 }, + { "id": "HAMMER_FINE", "level": 1 }, + { "id": "FILE", "level": 2 }, + { "id": "ANVIL", "level": 1 } + ], + "tools": [ [ [ "demon_forge", 30 ] ], [ [ "tongs", -1 ] ] ], + "proficiencies": [ + { "proficiency": "prof_almetallurgy", "required": true }, + { "proficiency": "prof_golemancy_basic", "required": false, "time_multiplier": 1.5, "fail_multiplier": 2 } + ], + "components": [ [ [ "orichalcum_ingot", 4 ] ], [ [ "mercury", 4 ] ], [ [ "crystallized_mana", 100 ] ] ] } ] diff --git a/data/mods/Magiclysm/traits/attunements.json b/data/mods/Magiclysm/traits/attunements.json index 87066d1ac2589..639f6d11c3b8c 100644 --- a/data/mods/Magiclysm/traits/attunements.json +++ b/data/mods/Magiclysm/traits/attunements.json @@ -503,7 +503,7 @@ "valid": false, "description": "The Golemancer is the ancient myth of the clay golem, made reality from constant use of Animist summons and Earthshaper self-strengthening spells. Takes some traits from the golems they create, such as immunity to slowing effects.", "prereqs": [ "ANIMIST", "EARTHSHAPER" ], - "spells_learned": [ [ "golem_push", 5 ] ], + "spells_learned": [ [ "golem_push", 5 ], [ "summon_golem_clay", 5 ] ], "cancels": [ "ARTIFICER", "AURA_MAGE", From fab02fa0b478dfd9d8244fc838812319a7bf9aca Mon Sep 17 00:00:00 2001 From: OromisElf Date: Thu, 25 Mar 2021 20:43:48 +0100 Subject: [PATCH 326/453] new druid spell: seed of growth (#47912) * new druid spell: seed of growth * added comment for future json workers --- data/mods/Magiclysm/Spells/druid.json | 23 +++++++++++++++++++ .../mods/Magiclysm/itemgroups/itemgroups.json | 3 ++- .../mods/Magiclysm/itemgroups/spellbooks.json | 1 + data/mods/Magiclysm/items/ethereal_items.json | 18 +++++++++++++++ data/mods/Magiclysm/items/spell_scrolls.json | 9 ++++++++ 5 files changed, 53 insertions(+), 1 deletion(-) diff --git a/data/mods/Magiclysm/Spells/druid.json b/data/mods/Magiclysm/Spells/druid.json index 5acc79f74e387..dbe29be9b020b 100644 --- a/data/mods/Magiclysm/Spells/druid.json +++ b/data/mods/Magiclysm/Spells/druid.json @@ -398,5 +398,28 @@ "shape": "blast", "effect": "summon", "effect_str": "mon_wolf" + }, + { + "id": "druid_growth", + "type": "SPELL", + "spell_class": "DRUID", + "name": "Seed of Growth", + "description": "Offer some of your life in a ritual to get tokens of growth in return.", + "valid_targets": [ "self" ], + "effect": "spawn_item", + "effect_str": "druid_fertilizer", + "shape": "blast", + "base_casting_time": 360000, + "final_casting_time": 90000, + "casting_time_increment": -15000, + "base_energy_cost": 5, + "energy_source": "HP", + "difficulty": 4, + "max_level": 20, + "min_damage": 5, + "max_damage": 80, + "damage_increment": 4, + "//": "The spell can only be permanent without being at maximum level because of how items with charges work", + "flags": [ "SOMATIC", "NO_LEGS", "PERMANENT" ] } ] diff --git a/data/mods/Magiclysm/itemgroups/itemgroups.json b/data/mods/Magiclysm/itemgroups/itemgroups.json index 4be9b3778fff3..d6eea28c00f7c 100644 --- a/data/mods/Magiclysm/itemgroups/itemgroups.json +++ b/data/mods/Magiclysm/itemgroups/itemgroups.json @@ -996,7 +996,8 @@ { "item": "spell_scroll_druid_woodshaft", "prob": 30 }, { "item": "summon_scroll_smudged", "prob": 2 }, { "item": "spell_scroll_tornskin", "prob": 2 }, - { "item": "spell_scroll_summon_cats", "prob": 50 } + { "item": "spell_scroll_summon_cats", "prob": 50 }, + { "item": "spell_scroll_seed_of_growth", "prob": 15 } ], "prob": 45 }, diff --git a/data/mods/Magiclysm/itemgroups/spellbooks.json b/data/mods/Magiclysm/itemgroups/spellbooks.json index 2d538d1a7aab4..ee790246a596f 100644 --- a/data/mods/Magiclysm/itemgroups/spellbooks.json +++ b/data/mods/Magiclysm/itemgroups/spellbooks.json @@ -13,6 +13,7 @@ [ "spell_scroll_blinding_flash", 50 ], [ "spell_scroll_ethereal_grasp", 50 ], [ "spell_scroll_druid_woodshaft", 50 ], + [ "spell_scroll_seed_of_growth", 35 ], [ "spell_scroll_summon_cats", 65 ], [ "spell_scroll_stonefist", 20 ], [ "spell_scroll_eshaper_piercing_bolt", 40 ], diff --git a/data/mods/Magiclysm/items/ethereal_items.json b/data/mods/Magiclysm/items/ethereal_items.json index fca6f63e3b456..4f96dda1d4d77 100644 --- a/data/mods/Magiclysm/items/ethereal_items.json +++ b/data/mods/Magiclysm/items/ethereal_items.json @@ -378,6 +378,24 @@ "max_charges": 15, "use_action": [ "WATER_PURIFIER" ] }, + { + "type": "COMESTIBLE", + "id": "druid_fertilizer", + "name": { "str": "seed of growth", "str_pl": "seeds of growth" }, + "weight": "27 g", + "color": "white", + "flags": [ "TRADER_AVOID", "FERTILIZER" ], + "comestible_type": "FOOD", + "symbol": "°", + "quench": -10, + "healthy": -2, + "description": "A magical powder that can be scattered on growing crops and make them grow faster.", + "material": [ "powder" ], + "volume": "2 L", + "charges": 60, + "category": "chems", + "fun": -15 + }, { "id": "obfuscating_aura", "type": "ARMOR", diff --git a/data/mods/Magiclysm/items/spell_scrolls.json b/data/mods/Magiclysm/items/spell_scrolls.json index abbf141e0de31..196bd38f10a72 100644 --- a/data/mods/Magiclysm/items/spell_scrolls.json +++ b/data/mods/Magiclysm/items/spell_scrolls.json @@ -1035,5 +1035,14 @@ "name": { "str": "Scroll of freezing touch", "str_pl": "Scrolls of freezing touch" }, "description": "Your hands freeze anything they touch at temperatures so cold it slows down your foes.", "use_action": { "type": "learn_spell", "spells": [ "freezing_touch" ] } + }, + { + "type": "BOOK", + "copy-from": "spell_scroll", + "id": "spell_scroll_seed_of_growth", + "//": "Druid spell", + "name": { "str": "Scroll of seed of growth", "str_pl": "Scrolls of seed of growth" }, + "description": "Offer some of your life in a ritual to get tokens of growth in return.", + "use_action": { "type": "learn_spell", "spells": [ "druid_growth" ] } } ] From b82478e83aa7f3c6d1c9488b4e6d5d84026e571c Mon Sep 17 00:00:00 2001 From: Salty Panda Date: Thu, 25 Mar 2021 22:28:14 +0100 Subject: [PATCH 327/453] [Magiclysm] Overhaul and balance dragon items (#47499) * Overhaul dragon items * Fixes * Small balance fixes after testing, make crafting costs more linear * Update data/mods/Magiclysm/items/black_dragon_items.json Co-authored-by: actual-nh <74678550+actual-nh@users.noreply.github.com> * Update data/mods/Magiclysm/items/black_dragon_items.json Co-authored-by: actual-nh <74678550+actual-nh@users.noreply.github.com> * Make xl visor the same thickness as normal one to avoid error, specify in description that dragon hide/scale is very durable, fix gloves description mentioning Kevlar, add XL backpack * lint * fix xl backpack * Update data/mods/Magiclysm/items/black_dragon_items.json Co-authored-by: actual-nh <74678550+actual-nh@users.noreply.github.com> Co-authored-by: Curtis Merrill --- .../Magiclysm/items/black_dragon_items.json | 216 ++++++++++------- data/mods/Magiclysm/items/tools.json | 4 +- data/mods/Magiclysm/materials.json | 46 +++- data/mods/Magiclysm/proficiencies.json | 22 ++ data/mods/Magiclysm/recipes/alchemy.json | 26 +++ data/mods/Magiclysm/recipes/dragon_black.json | 221 +++++++++++++----- data/mods/Magiclysm/tool_qualities.json | 5 + doc/JSON_INFO.md | 4 +- 8 files changed, 383 insertions(+), 161 deletions(-) diff --git a/data/mods/Magiclysm/items/black_dragon_items.json b/data/mods/Magiclysm/items/black_dragon_items.json index 64cda2534e678..10f2bc1a42cc0 100644 --- a/data/mods/Magiclysm/items/black_dragon_items.json +++ b/data/mods/Magiclysm/items/black_dragon_items.json @@ -7,7 +7,7 @@ "color": "black_white", "name": "black dragon scale", "price": 2500, - "material": [ "black_dragon_hide" ], + "material": [ "black_dragon_scales" ], "weight": "380 g", "volume": "75 ml", "bashing": 0, @@ -95,20 +95,20 @@ "type": "ARMOR", "category": "armor", "name": { "str": "pair of black dragonscale boots", "str_pl": "pairs of black dragonscale boots" }, - "description": "Boots made of black dragonscale. Very protective, and surprisingly light.", + "description": "Boots made of black incredibly durable dragonscale. Very protective, and surprisingly light.", "weight": "945 g", "volume": "3250 ml", "price": 75000, "to_hit": -2, "bashing": 7, - "material": [ "black_dragon_hide" ], + "material": [ "black_dragon_hide", "black_dragon_scales" ], "symbol": "[", "color": "black_white", "covers": [ "foot_l", "foot_r" ], "coverage": 100, "encumbrance": 30, - "warmth": 20, - "material_thickness": 4, + "warmth": 25, + "material_thickness": 5, "environmental_protection": 3, "flags": [ "VARSIZE", "WATERPROOF", "STURDY" ] }, @@ -117,7 +117,7 @@ "type": "ARMOR", "category": "armor", "name": { "str": "pair of black dragonhide boots", "str_pl": "pairs of black dragonhide boots" }, - "description": "Boots made of black dragonhide. Very protective, and surprisingly light.", + "description": "Boots made of very durable black dragonhide. Very protective, and surprisingly light.", "weight": "655 g", "volume": "3250 ml", "price": 50000, @@ -128,9 +128,9 @@ "color": "black_white", "covers": [ "foot_l", "foot_r" ], "coverage": 100, - "encumbrance": 18, + "encumbrance": 20, "warmth": 20, - "material_thickness": 2, + "material_thickness": 3, "environmental_protection": 3, "flags": [ "VARSIZE", "WATERPROOF", "STURDY" ] }, @@ -139,32 +139,47 @@ "type": "ARMOR", "category": "armor", "name": "black dragonscale helmet", - "description": "A helmet made from black dragonscale, held together with black dragonhide. It comes equipped with a full face visor.", + "description": "A helmet made from black incredibly durable dragonscale, held together with black dragonhide. It comes equipped with a full face visor with only a thin slit to see out of. Activate to raise the visor.", + "use_action": { "type": "transform", "target": "helmet_black_dragon_scale_raised", "msg": "You raise your visor." }, "weight": "856 g", "volume": "2500 ml", "price": 58000, "to_hit": -1, "bashing": 10, - "material": [ "black_dragon_hide" ], + "material": [ "black_dragon_hide", "black_dragon_scales" ], "symbol": "[", "color": "black_white", - "covers": [ "head", "eyes", "mouth" ], - "coverage": 100, - "encumbrance": 32, - "warmth": 15, - "material_thickness": 6, + "armor_portion_data": [ + { "covers": [ "head" ], "coverage": 100, "encumbrance": 32 }, + { "covers": [ "eyes", "mouth" ], "coverage": 100, "encumbrance": 20 } + ], + "warmth": 25, + "material_thickness": 5, "environmental_protection": 3, "techniques": [ "WBLOCK_1" ], - "flags": [ "VARSIZE", "WATERPROOF", "STURDY" ] + "qualities": [ [ "GLARE", 1 ] ], + "flags": [ "VARSIZE", "WATERPROOF", "STURDY", "SUN_GLASSES" ] + }, + { + "id": "helmet_black_dragon_scale_raised", + "type": "ARMOR", + "category": "armor", + "copy-from": "helmet_black_dragon_scale", + "name": { "str": "black dragonscale helmet (raised visor)", "str_pl": "black dragonscale helmets (raised visor)" }, + "description": "A helmet made from incredibly durable black dragonscale, held together with black dragonhide. The visor is raised.", + "use_action": { "type": "transform", "target": "helmet_black_dragon_scale", "msg": "You put down your visor." }, + "symbol": "[", + "armor_portion_data": [ { "covers": [ "head" ], "coverage": 100, "encumbrance": 32 } ], + "delete": { "qualities": [ [ "GLARE", 1 ] ], "flags": [ "SUN_GLASSES" ] } }, { "id": "helmet_black_dragon_hide", "type": "ARMOR", "category": "armor", "name": "black dragonhide helmet", - "description": "A helmet made from black dragonhide. It protects your head well, and doesn't cover your face.", + "description": "A helmet made from very durable black dragonhide. It protects your head well, but doesn't cover your face.", "weight": "585 g", - "volume": "2500 ml", + "volume": "2 L", "price": 58000, "to_hit": -1, "bashing": 10, @@ -173,9 +188,9 @@ "color": "black_white", "covers": [ "head" ], "coverage": 100, - "encumbrance": 32, + "encumbrance": 20, "warmth": 15, - "material_thickness": 2, + "material_thickness": 3, "environmental_protection": 1, "techniques": [ "WBLOCK_1" ], "flags": [ "VARSIZE", "WATERPROOF", "STURDY" ] @@ -185,21 +200,21 @@ "type": "ARMOR", "category": "armor", "name": "black dragonscale armor", - "description": "A full suit of black dragon scale mail. It comes with all the accoutrements that cover your torso, legs, and arms, with the benefit of being very light and flexible.", + "description": "A full suit of incredibly durable black dragon scale mail. It comes with all the accoutrements that cover your torso, legs, and arms, with the benefit of being very light and flexible.", "weight": "4250 g", "volume": "12 L", "price": 2000000, "to_hit": -3, "bashing": 6, - "material": [ "black_dragon_hide" ], + "material": [ "black_dragon_hide", "black_dragon_scales" ], "symbol": "[", "color": "black_white", "covers": [ "leg_l", "leg_r", "torso", "arm_l", "arm_r" ], "coverage": 100, "encumbrance": 25, - "warmth": 15, - "material_thickness": 4, - "environmental_protection": 2, + "warmth": 25, + "material_thickness": 5, + "environmental_protection": 3, "flags": [ "VARSIZE", "WATERPROOF", "RAINPROOF", "STURDY" ] }, { @@ -207,9 +222,9 @@ "type": "ARMOR", "category": "armor", "name": "black dragonhide armor", - "description": "A full suit of black dragonhide armor. It comes with all the accoutrements that cover your torso, legs, and arms, with the benefit of being very light and flexible.", + "description": "A full suit of very durable black dragonhide armor. It comes with all the accoutrements that cover your torso, legs, and arms, with the benefit of being very light and flexible.", "weight": "3 kg", - "volume": "12 L", + "volume": "11 L", "price": 2000000, "to_hit": -3, "bashing": 6, @@ -220,8 +235,8 @@ "coverage": 100, "encumbrance": 18, "warmth": 15, - "material_thickness": 4, - "environmental_protection": 1, + "material_thickness": 3, + "environmental_protection": 2, "flags": [ "VARSIZE", "WATERPROOF", "RAINPROOF", "STURDY" ] }, { @@ -229,19 +244,19 @@ "type": "ARMOR", "category": "armor", "name": { "str": "pair of black dragonscale gauntlets", "str_pl": "pairs of black dragonscale gauntlets" }, - "description": "A pair of heavy-duty gauntlets made of black dragonscale that covers your hands.", + "description": "A pair of heavy-duty gauntlets made of incredibly durable black dragonscale that covers your hands.", "weight": "380 g", "volume": "1 L", "price": 180000, "to_hit": 2, - "material": [ "black_dragon_hide" ], + "material": [ "black_dragon_hide", "black_dragon_scales" ], "symbol": "[", "color": "black_white", "covers": [ "hand_l", "hand_r" ], "coverage": 100, "encumbrance": 20, - "warmth": 15, - "material_thickness": 3, + "warmth": 20, + "material_thickness": 4, "environmental_protection": 3, "flags": [ "VARSIZE", "WATERPROOF", "STURDY" ] }, @@ -250,7 +265,7 @@ "type": "ARMOR", "category": "armor", "name": { "str": "pair of black dragonhide gloves", "str_pl": "pairs of black dragonhide gloves" }, - "description": "A pair of customized, Kevlar armored leather gloves, modified to be easy to wear while providing maximum protection under extreme conditions.", + "description": "A pair of gloves made of very durable black dragonhide, modified to be easy to wear while providing maximum protection under extreme conditions.", "weight": "230 g", "volume": "750 ml", "price": 180000, @@ -261,7 +276,7 @@ "covers": [ "hand_l", "hand_r" ], "coverage": 100, "encumbrance": 8, - "warmth": 15, + "warmth": 13, "material_thickness": 2, "environmental_protection": 1, "flags": [ "VARSIZE", "WATERPROOF", "STURDY" ] @@ -271,7 +286,7 @@ "copy-from": "boots_black_dragon_scale", "type": "ARMOR", "name": { "str": "pair of XL black dragonscale boots", "str_pl": "pairs of XL black dragonscale boots" }, - "description": "Massive boots made of black dragonscale, modified to fit even the strangest of bodies. Very protective, and surprisingly light.", + "description": "Massive boots made of incredibly durable black dragonscale, modified to fit even the strangest of bodies. Very protective, and surprisingly light.", "weight": "1545 g", "volume": "6250 ml", "encumbrance": 40, @@ -282,10 +297,10 @@ "copy-from": "boots_black_dragon_hide", "type": "ARMOR", "name": { "str": "pair of XL black dragonhide boots", "str_pl": "pairs of XL black dragonhide boots" }, - "description": "Massive boots made of black dragonhide, modified to fit even the strangest of bodies. Very protective, and surprisingly light.", + "description": "Massive boots made of very durable black dragonhide, modified to fit even the strangest of bodies. Very protective, and surprisingly light.", "weight": "955 g", "volume": "6250 ml", - "encumbrance": 28, + "encumbrance": 25, "flags": [ "OVERSIZE", "VARSIZE", "WATERPROOF", "STURDY" ] }, { @@ -293,7 +308,7 @@ "copy-from": "gauntlets_black_dragon_scale", "type": "ARMOR", "name": { "str": "pair of XL black dragonscale gauntlets", "str_pl": "pairs of XL black dragonscale gauntlets" }, - "description": "A pair of heavy-duty gauntlets made of black dragonscale that covers your hands, or whatever you use as hands.", + "description": "A pair of heavy-duty gauntlets made of incredibly durable black dragonscale that covers your hands, or whatever you use as hands.", "weight": "680 g", "volume": "2 L", "encumbrance": 30, @@ -304,65 +319,34 @@ "copy-from": "gloves_black_dragon_hide", "type": "ARMOR", "name": { "str": "pair of XL black dragonhide gloves", "str_pl": "pairs of XL black dragonhide gloves" }, - "description": "A pair of customized, Kevlar armored leather gloves, modified to be easy to wear while providing maximum protection under extreme conditions. Sized to fit even the strangest of anatomy.", + "description": "A pair of gloves made of very durable black dragonhide, modified to be easy to wear while providing maximum protection under extreme conditions. Sized to fit even the strangest of anatomy.", "weight": "430 g", "volume": "1500 ml", "encumbrance": 18, "flags": [ "OVERSIZE", "VARSIZE", "WATERPROOF", "STURDY" ] }, - { - "id": "boots_xlblack_dragon_scale", - "copy-from": "boots_black_dragon_scale", - "type": "ARMOR", - "name": { "str": "pair of XL black dragonscale boots", "str_pl": "pairs of XL black dragonscale boots" }, - "description": "Massive boots made of black dragonscale, modified to fit even the strangest of bodies. Very protective, and surprisingly light.", - "weight": "1545 g", - "volume": "6250 ml", - "encumbrance": 40, - "flags": [ "OVERSIZE", "VARSIZE", "WATERPROOF", "STURDY" ] - }, - { - "id": "boots_xlblack_dragon_hide", - "copy-from": "boots_black_dragon_hide", - "type": "ARMOR", - "name": { "str": "pair of XL black dragonhide boots", "str_pl": "pairs of XL black dragonhide boots" }, - "description": "Massive boots made of black dragonhide, modified to fit even the strangest of bodies. Very protective, and surprisingly light.", - "weight": "955 g", - "volume": "6250 ml", - "encumbrance": 28, - "flags": [ "OVERSIZE", "VARSIZE", "WATERPROOF", "STURDY" ] - }, { "id": "helmet_xlblack_dragon_scale", "copy-from": "helmet_black_dragon_scale", "type": "ARMOR", "name": { "str": "XL black dragonscale helmet" }, - "description": "A massive helmet made from black dragonscale, held together with black dragonhide. It comes equipped with a full face visor and is large enough to fit even the strangest of heads.", + "description": "A massive helmet made from incredibly durable black dragonscale, held together with black dragonhide. It comes equipped with a full face visor you can raise and is large enough to fit even the strangest of heads.", + "use_action": { "type": "transform", "target": "helmet_xlblack_dragon_scale_raised", "msg": "You raise your visor." }, "weight": "1256 g", "volume": "4500 ml", - "encumbrance": 42, - "flags": [ "OVERSIZE", "VARSIZE", "WATERPROOF", "STURDY" ] + "armor_portion_data": [ { "covers": [ "head" ], "coverage": 100, "encumbrance": 42 } ], + "flags": [ "OVERSIZE", "VARSIZE", "WATERPROOF", "STURDY", "SUN_GLASSES" ] }, { - "id": "helmet_xlblack_dragon_hide", - "copy-from": "helmet_black_dragon_hide", + "id": "helmet_xlblack_dragon_scale_raised", + "copy-from": "helmet_black_dragon_scale_raised", "type": "ARMOR", - "name": { "str": "XL black dragonhide helmet" }, - "description": "A massive helmet made from black dragonhide. It protects your head well, and doesn't cover your face, but is large enough to fit even the strangest of heads.", - "weight": "815 g", - "volume": "4500 ml", - "encumbrance": 42, - "flags": [ "OVERSIZE", "VARSIZE", "WATERPROOF", "STURDY" ] - }, - { - "id": "helmet_xlblack_dragon_scale", - "copy-from": "helmet_black_dragon_scale", - "type": "ARMOR", - "name": { "str": "XL black dragonscale helmet" }, - "description": "A massive helmet made from black dragonscale, held together with black dragonhide. It comes equipped with a full face visor and is large enough to fit even the strangest of heads.", + "name": { "str": "XL black dragonscale helmet (raised visor)", "str_pl": "XL black dragonscale helmets (raised visor)" }, + "description": "A massive helmet made from incredibly durable black dragonscale, held together with black dragonhide. It is large enough to fit even the strangest of heads. The visor is raised", + "use_action": { "type": "transform", "target": "helmet_xlblack_dragon_scale", "msg": "You put down your visor." }, + "armor_portion_data": [ { "covers": [ "head" ], "coverage": 100, "encumbrance": 42 } ], "weight": "1256 g", "volume": "4500 ml", - "encumbrance": 42, "flags": [ "OVERSIZE", "VARSIZE", "WATERPROOF", "STURDY" ] }, { @@ -370,10 +354,10 @@ "copy-from": "helmet_black_dragon_hide", "type": "ARMOR", "name": { "str": "XL black dragonhide helmet" }, - "description": "A massive helmet made from black dragonhide. It protects your head well, and doesn't cover your face, but is large enough to fit even the strangest of heads.", + "description": "A massive helmet made from very durable black dragonhide. It protects your head well, and doesn't cover your face, but is large enough to fit even the strangest of heads.", "weight": "815 g", "volume": "4500 ml", - "encumbrance": 42, + "encumbrance": 26, "flags": [ "OVERSIZE", "VARSIZE", "WATERPROOF", "STURDY" ] }, { @@ -381,7 +365,7 @@ "copy-from": "suit_black_dragon_scale", "type": "ARMOR", "name": { "str": "XL black dragonscale armor" }, - "description": "A massive full suit of black dragon scale mail. It comes with all the accoutrements that cover your torso, legs, and arms; sized to fit even the strangest of bodies.", + "description": "A massive full suit of incredibly durable black dragon scale mail. It comes with all the accoutrements that cover your torso, legs, and arms; sized to fit even the strangest of bodies.", "weight": "6250 g", "volume": "18 L", "encumbrance": 35, @@ -392,10 +376,70 @@ "copy-from": "suit_black_dragon_hide", "type": "ARMOR", "name": { "str": "XL black dragonhide armor" }, - "description": "A massive full suit of black dragonhide armor. It comes with all the accoutrements that cover your torso, legs, and arms; sized to fit even the strangest of bodies.", + "description": "A massive full suit of very durable black dragonhide armor. It comes with all the accoutrements that cover your torso, legs, and arms; sized to fit even the strangest of bodies.", "weight": "5500 g", "volume": "18 L", - "encumbrance": 28, + "encumbrance": 26, "flags": [ "OVERSIZE", "VARSIZE", "WATERPROOF", "RAINPROOF", "STURDY" ] + }, + { + "id": "backpack_black_dragon_hide", + "//": "After adding more dragons, maybe make it more generic", + "type": "ARMOR", + "name": { "str": "dragonhide backpack" }, + "description": "A custom-built backpack. Made of very durable dragon leather and carefully crafted to hold as much stuff as possible.", + "weight": "900 g", + "volume": "5250 ml", + "price": 240000, + "price_postapoc": 3250, + "material": [ "black_dragon_hide" ], + "symbol": "[", + "looks_like": "backpack", + "color": "black", + "covers": [ "torso" ], + "coverage": 40, + "encumbrance": 5, + "max_encumbrance": 30, + "pocket_data": [ + { + "pocket_type": "CONTAINER", + "max_contains_volume": "29 L", + "max_contains_weight": "45 kg", + "max_item_length": "48 cm", + "magazine_well": "5 L", + "moves": 300 + } + ], + "warmth": 8, + "material_thickness": 3, + "environmental_protection": 3, + "flags": [ "WATER_FRIENDLY", "STURDY", "BELTED", "WATERPROOF" ] + }, + { + "id": "backpack_xl_black_dragon_hide", + "copy-from": "backpack_black_dragon_hide", + "type": "ARMOR", + "name": { "str": "XL dragonhide backpack" }, + "weight": "1200 g", + "volume": "6250 ml", + "price": 280000, + "price_postapoc": 3450, + "symbol": "[", + "encumbrance": 8, + "max_encumbrance": 40, + "pocket_data": [ + { + "pocket_type": "CONTAINER", + "max_contains_volume": "38 L", + "max_contains_weight": "52 kg", + "max_item_length": "58 cm", + "magazine_well": "5 L", + "moves": 330 + } + ], + "warmth": 9, + "material_thickness": 4, + "environmental_protection": 3, + "extend": { "flags": [ "OVERSIZE" ] } } ] diff --git a/data/mods/Magiclysm/items/tools.json b/data/mods/Magiclysm/items/tools.json index 7bd18d0a18579..a2fa1a59c78d2 100644 --- a/data/mods/Magiclysm/items/tools.json +++ b/data/mods/Magiclysm/items/tools.json @@ -16,7 +16,7 @@ "color": "red", "pocket_data": [ { "open_container": true, "watertight": true, "max_contains_volume": "16 L", "max_contains_weight": "50 kg" } ], "//": "I went ahead and gave this a level of 2 for when magical mutagens become a thing as I figured dragonblood for instance should need different tools than making alpha mutagen.", - "qualities": [ [ "COOK", 3 ], [ "BOIL", 2 ], [ "CONTAIN", 1 ], [ "MAGIC_MUTAGEN", 2 ] ], + "qualities": [ [ "COOK", 3 ], [ "BOIL", 2 ], [ "CONTAIN", 1 ], [ "MAGIC_MUTAGEN", 2 ], [ "MAGIC_CAULDRON", 1 ] ], "use_action": [ "HEAT_FOOD" ] }, { @@ -34,7 +34,7 @@ "symbol": "U", "color": "yellow", "pocket_data": [ { "open_container": true, "watertight": true, "max_contains_volume": "16 L", "max_contains_weight": "50 kg" } ], - "qualities": [ [ "COOK", 3 ], [ "BOIL", 2 ], [ "CONTAIN", 1 ], [ "MAGIC_MUTAGEN", 1 ] ], + "qualities": [ [ "COOK", 3 ], [ "BOIL", 2 ], [ "CONTAIN", 1 ], [ "MAGIC_MUTAGEN", 1 ], [ "MAGIC_CAULDRON", 2 ] ], "use_action": [ "HEAT_FOOD" ] }, { diff --git a/data/mods/Magiclysm/materials.json b/data/mods/Magiclysm/materials.json index 9e3e6522fe219..00e4b1d76d3bc 100644 --- a/data/mods/Magiclysm/materials.json +++ b/data/mods/Magiclysm/materials.json @@ -24,22 +24,50 @@ "type": "material", "id": "black_dragon_hide", "name": "Black Dragon Hide", - "density": 20, - "specific_heat_liquid": 4.186, - "specific_heat_solid": 2.108, + "density": 9, "latent_heat": 333, - "bash_resist": 5, - "cut_resist": 8, + "bash_resist": 3, + "cut_resist": 7, "bullet_resist": 6, "acid_resist": 40, "fire_resist": 1, - "elec_resist": 1, - "chip_resist": 30, + "elec_resist": 2, + "chip_resist": 20, + "reinforces": true, + "soft": true, + "repaired_with": "black_dragon_tanned_hide", + "dmg_adj": [ "scratched", "cut", "ripped", "shredded" ], + "bash_dmg_verb": "ripped", + "cut_dmg_verb": "scratched", + "burn_data": [ + { "fuel": 0, "smoke": 0, "burn": 0 }, + { "fuel": 1, "smoke": 1, "burn": 1, "volume_per_turn": "100 ml" }, + { "fuel": 2, "smoke": 4, "burn": 2 } + ] + }, + { + "type": "material", + "id": "black_dragon_scales", + "name": "Black Dragon Scale", + "density": 15, + "latent_heat": 533, + "bash_resist": 8, + "cut_resist": 9, + "bullet_resist": 8, + "acid_resist": 40, + "fire_resist": 4, + "elec_resist": 3, + "chip_resist": 35, "reinforces": true, "repaired_with": "dragon_black_scale", - "dmg_adj": [ "scratched", "cut", "cracked", "shattered" ], + "dmg_adj": [ "scratched", "marked", "cracked", "shattered" ], "bash_dmg_verb": "cracked", - "cut_dmg_verb": "chipped" + "cut_dmg_verb": "chipped", + "burn_data": [ + { "fuel": 0, "smoke": 0, "burn": 0 }, + { "fuel": 0, "smoke": 0, "burn": 0 }, + { "fuel": 1, "smoke": 1, "burn": 1, "volume_per_turn": "100 ml" } + ] }, { "type": "material", diff --git a/data/mods/Magiclysm/proficiencies.json b/data/mods/Magiclysm/proficiencies.json index 6d13fc27d1d33..f57b91947089e 100644 --- a/data/mods/Magiclysm/proficiencies.json +++ b/data/mods/Magiclysm/proficiencies.json @@ -20,6 +20,28 @@ "default_fail_multiplier": 2, "required_proficiencies": [ "prof_alchemy" ] }, + { + "type": "proficiency", + "id": "prof_leatherworking_dragon", + "name": { "str": "Dragon leather working" }, + "description": "Working with dragon leather requires a specific set of skills and tools… a set you are familiar with.", + "can_learn": true, + "default_time_multiplier": 1.5, + "default_fail_multiplier": 2, + "time_to_learn": "6 h", + "required_proficiencies": [ "prof_leatherworking" ] + }, + { + "type": "proficiency", + "id": "prof_scaleworking_dragon", + "name": { "str": "Dragon scale working" }, + "description": "Working with dragon scales requires a specific set of skills and tools… a set you are familiar with.", + "can_learn": true, + "default_time_multiplier": 2, + "default_fail_multiplier": 3, + "time_to_learn": "12 h", + "required_proficiencies": [ "prof_leatherworking_dragon" ] + }, { "type": "proficiency", "id": "prof_golemancy_basic", diff --git a/data/mods/Magiclysm/recipes/alchemy.json b/data/mods/Magiclysm/recipes/alchemy.json index 3825e8ab6ab3c..5d695526e2b97 100644 --- a/data/mods/Magiclysm/recipes/alchemy.json +++ b/data/mods/Magiclysm/recipes/alchemy.json @@ -21,6 +21,32 @@ "category": "CC_ENCHANTED", "subcategory": "CSC_ENCHANTED_OTHER" }, + { + "type": "recipe", + "activity_level": "fake", + "result": "dragon_essence", + "id_suffix": "with_blood", + "charges": 2, + "batch_time_factors": [ 40, 3 ], + "qualities": [ + { "id": "CONCENTRATE", "level": 1 }, + { "id": "FINE_DISTILL", "level": 1 }, + { "id": "SEPARATE", "level": 1 }, + { "id": "CONTAIN", "level": 1 }, + { "id": "MANA_FOCUS", "level": 1 }, + { "id": "MAGIC_CAULDRON", "level": 1 } + ], + "tools": [ [ [ "surface_heat", 20, "LIST" ] ] ], + "components": [ [ [ "dragon_scale", 6, "LIST" ], [ "meat_dragon", 60 ] ], [ [ "dragon_blood", 500 ] ] ], + "proficiencies": [ { "proficiency": "prof_alchemy", "required": true } ], + "time": "2 h", + "skill_used": "chemistry", + "difficulty": 5, + "skills_required": [ "spellcraft", 6 ], + "book_learn": [ [ "black_dragons", 5 ] ], + "category": "CC_ENCHANTED", + "subcategory": "CSC_ENCHANTED_OTHER" + }, { "type": "recipe", "activity_level": "fake", diff --git a/data/mods/Magiclysm/recipes/dragon_black.json b/data/mods/Magiclysm/recipes/dragon_black.json index a39e48973c49d..e38b36bcaaf30 100644 --- a/data/mods/Magiclysm/recipes/dragon_black.json +++ b/data/mods/Magiclysm/recipes/dragon_black.json @@ -19,7 +19,12 @@ { "id": "MANA_INFUSE", "level": 1 } ], "tools": [ [ [ "surface_heat", 20, "LIST" ] ] ], - "proficiencies": [ { "proficiency": "prof_leatherworking_basic" } ], + "proficiencies": [ + { "proficiency": "prof_leatherworking_basic" }, + { "proficiency": "prof_leatherworking" }, + { "proficiency": "prof_leatherworking_dragon" }, + { "proficiency": "prof_alchemy" } + ], "book_learn": [ [ "black_dragons", 2 ] ], "components": [ [ [ "dragon_essence", 1 ] ], [ [ "black_dragon_hide_raw", 1 ] ] ] }, @@ -54,7 +59,7 @@ { "result": "suit_black_dragon_hide", "type": "recipe", - "activity_level": "fake", + "activity_level": "LIGHT_EXERCISE", "category": "CC_ENCHANTED", "subcategory": "CSC_ENCHANTED_ARMOR", "skill_used": "tailor", @@ -62,51 +67,61 @@ "skills_required": [ "spellcraft", 3 ], "time": "70 h", "book_learn": [ [ "black_dragons", 5 ] ], - "qualities": [ { "id": "MANA_INFUSE", "level": 1 }, { "id": "CHISEL", "level": 3 } ], + "qualities": [ { "id": "MANA_INFUSE", "level": 1 }, { "id": "CHISEL", "level": 1 } ], "using": [ [ "sewing_standard", 250 ] ], - "proficiencies": [ { "proficiency": "prof_leatherworking_basic" }, { "proficiency": "prof_leatherworking" } ], - "components": [ [ [ "black_dragon_tanned_hide", 40 ] ], [ [ "dragon_black_scale", 150 ] ], [ [ "dragon_essence", 15 ] ] ] + "proficiencies": [ + { "proficiency": "prof_leatherworking_basic" }, + { "proficiency": "prof_leatherworking" }, + { "proficiency": "prof_leatherworking_dragon" } + ], + "components": [ [ [ "black_dragon_tanned_hide", 22 ] ], [ [ "dragon_essence", 11 ] ] ] }, { "result": "suit_black_dragon_scale", "type": "recipe", - "activity_level": "fake", + "activity_level": "LIGHT_EXERCISE", "category": "CC_ENCHANTED", "subcategory": "CSC_ENCHANTED_ARMOR", "skill_used": "fabrication", "difficulty": 7, "skills_required": [ "spellcraft", 5 ], - "time": "340 h", + "time": "290 h", "book_learn": [ [ "black_dragons", 6 ] ], "qualities": [ { "id": "MANA_INFUSE", "level": 2 }, { "id": "CHISEL", "level": 3 } ], - "proficiencies": [ { "proficiency": "prof_leatherworking_basic" }, { "proficiency": "prof_leatherworking" } ], + "proficiencies": [ + { "proficiency": "prof_leatherworking_basic" }, + { "proficiency": "prof_leatherworking" }, + { "proficiency": "prof_leatherworking_dragon" }, + { "proficiency": "prof_scaleworking_dragon" } + ], "using": [ [ "sewing_standard", 250 ], [ "welding_standard", 50 ] ], - "components": [ [ [ "black_dragon_tanned_hide", 40 ] ], [ [ "dragon_black_scale", 1500 ] ], [ [ "dragon_essence", 15 ] ] ] + "components": [ [ [ "black_dragon_tanned_hide", 22 ] ], [ [ "dragon_black_scale", 1100 ] ], [ [ "dragon_essence", 11 ] ] ] }, { "result": "boots_black_dragon_hide", "type": "recipe", - "activity_level": "fake", + "activity_level": "LIGHT_EXERCISE", "category": "CC_ENCHANTED", "subcategory": "CSC_ENCHANTED_ARMOR", "skill_used": "tailor", "difficulty": 5, "skills_required": [ "spellcraft", 3 ], - "time": "30 h", + "time": "25 h", "book_learn": [ [ "black_dragons", 5 ] ], - "qualities": [ { "id": "MANA_INFUSE", "level": 1 }, { "id": "CHISEL", "level": 3 } ], + "qualities": [ { "id": "MANA_INFUSE", "level": 1 }, { "id": "CHISEL", "level": 1 } ], "using": [ [ "sewing_standard", 100 ] ], "proficiencies": [ { "proficiency": "prof_leatherworking_basic" }, { "proficiency": "prof_cobbling" }, - { "proficiency": "prof_leatherworking" } + { "proficiency": "prof_leatherworking" }, + { "proficiency": "prof_leatherworking_dragon" } ], - "components": [ [ [ "black_dragon_tanned_hide", 4 ] ], [ [ "dragon_black_scale", 15 ] ], [ [ "dragon_essence", 2 ] ] ] + "components": [ [ [ "black_dragon_tanned_hide", 4 ] ], [ [ "dragon_essence", 2 ] ] ] }, { "result": "boots_black_dragon_scale", "type": "recipe", - "activity_level": "fake", + "activity_level": "LIGHT_EXERCISE", "category": "CC_ENCHANTED", "subcategory": "CSC_ENCHANTED_ARMOR", "skill_used": "fabrication", @@ -119,30 +134,36 @@ "proficiencies": [ { "proficiency": "prof_leatherworking_basic" }, { "proficiency": "prof_cobbling" }, - { "proficiency": "prof_leatherworking" } + { "proficiency": "prof_leatherworking" }, + { "proficiency": "prof_leatherworking_dragon" }, + { "proficiency": "prof_scaleworking_dragon" } ], "components": [ [ [ "black_dragon_tanned_hide", 6 ] ], [ [ "dragon_black_scale", 75 ] ], [ [ "dragon_essence", 4 ] ] ] }, { "result": "helmet_black_dragon_hide", "type": "recipe", - "activity_level": "fake", + "activity_level": "LIGHT_EXERCISE", "category": "CC_ENCHANTED", "subcategory": "CSC_ENCHANTED_ARMOR", "skill_used": "tailor", "difficulty": 5, "skills_required": [ "spellcraft", 3 ], - "time": "30 h", + "time": "25 h", "book_learn": [ [ "black_dragons", 5 ] ], - "qualities": [ { "id": "MANA_INFUSE", "level": 1 }, { "id": "CHISEL", "level": 3 } ], + "qualities": [ { "id": "MANA_INFUSE", "level": 1 }, { "id": "CHISEL", "level": 1 } ], "using": [ [ "sewing_standard", 100 ] ], - "proficiencies": [ { "proficiency": "prof_leatherworking_basic" }, { "proficiency": "prof_leatherworking" } ], - "components": [ [ [ "black_dragon_tanned_hide", 3 ] ], [ [ "dragon_black_scale", 8 ] ], [ [ "dragon_essence", 2 ] ] ] + "proficiencies": [ + { "proficiency": "prof_leatherworking_basic" }, + { "proficiency": "prof_leatherworking" }, + { "proficiency": "prof_leatherworking_dragon" } + ], + "components": [ [ [ "black_dragon_tanned_hide", 3 ] ], [ [ "dragon_essence", 2 ] ] ] }, { "result": "helmet_black_dragon_scale", "type": "recipe", - "activity_level": "fake", + "activity_level": "LIGHT_EXERCISE", "category": "CC_ENCHANTED", "subcategory": "CSC_ENCHANTED_ARMOR", "skill_used": "fabrication", @@ -152,13 +173,18 @@ "book_learn": [ [ "black_dragons", 6 ] ], "qualities": [ { "id": "MANA_INFUSE", "level": 2 }, { "id": "CHISEL", "level": 3 } ], "using": [ [ "sewing_standard", 100 ], [ "welding_standard", 10 ] ], - "proficiencies": [ { "proficiency": "prof_leatherworking_basic" }, { "proficiency": "prof_leatherworking" } ], + "proficiencies": [ + { "proficiency": "prof_leatherworking_basic" }, + { "proficiency": "prof_leatherworking" }, + { "proficiency": "prof_leatherworking_dragon" }, + { "proficiency": "prof_scaleworking_dragon" } + ], "components": [ [ [ "black_dragon_tanned_hide", 1 ] ], [ [ "dragon_black_scale", 90 ] ], [ [ "dragon_essence", 4 ] ] ] }, { "result": "gloves_black_dragon_hide", "type": "recipe", - "activity_level": "fake", + "activity_level": "LIGHT_EXERCISE", "category": "CC_ENCHANTED", "subcategory": "CSC_ENCHANTED_ARMOR", "skill_used": "tailor", @@ -166,55 +192,62 @@ "skills_required": [ "spellcraft", 3 ], "time": "30 h", "book_learn": [ [ "black_dragons", 5 ] ], - "qualities": [ { "id": "MANA_INFUSE", "level": 1 }, { "id": "CHISEL", "level": 3 } ], + "qualities": [ { "id": "MANA_INFUSE", "level": 1 }, { "id": "CHISEL", "level": 1 } ], "using": [ [ "sewing_standard", 100 ] ], "proficiencies": [ { "proficiency": "prof_leatherworking_basic" }, { "proficiency": "prof_articulation", "required": false, "time_multiplier": 2 }, - { "proficiency": "prof_leatherworking" } + { "proficiency": "prof_leatherworking" }, + { "proficiency": "prof_leatherworking_dragon" } ], - "components": [ [ [ "black_dragon_tanned_hide", 3 ] ], [ [ "dragon_black_scale", 10 ] ], [ [ "dragon_essence", 3 ] ] ] + "components": [ [ [ "black_dragon_tanned_hide", 3 ] ], [ [ "dragon_essence", 3 ] ] ] }, { "result": "gauntlets_black_dragon_scale", "type": "recipe", - "activity_level": "fake", + "activity_level": "LIGHT_EXERCISE", "category": "CC_ENCHANTED", "subcategory": "CSC_ENCHANTED_ARMOR", "skill_used": "fabrication", "difficulty": 7, "skills_required": [ "spellcraft", 5 ], - "time": "30 h", + "time": "40 h", "book_learn": [ [ "black_dragons", 6 ] ], "qualities": [ { "id": "MANA_INFUSE", "level": 2 }, { "id": "CHISEL", "level": 3 } ], "using": [ [ "sewing_standard", 100 ], [ "welding_standard", 10 ] ], "proficiencies": [ { "proficiency": "prof_leatherworking_basic" }, { "proficiency": "prof_articulation", "required": false, "time_multiplier": 2 }, - { "proficiency": "prof_leatherworking" } + { "proficiency": "prof_leatherworking" }, + { "proficiency": "prof_leatherworking_dragon" }, + { "proficiency": "prof_scaleworking_dragon" } ], "components": [ [ [ "black_dragon_tanned_hide", 4 ] ], [ [ "dragon_black_scale", 50 ] ], [ [ "dragon_essence", 5 ] ] ] }, { "result": "suit_xlblack_dragon_hide", "type": "recipe", - "activity_level": "fake", + "activity_level": "LIGHT_EXERCISE", "category": "CC_ENCHANTED", "subcategory": "CSC_ENCHANTED_ARMOR", "skill_used": "tailor", "difficulty": 6, "skills_required": [ "spellcraft", 4 ], - "time": "70 h", + "time": "60 h", "book_learn": [ [ "black_dragons", 5 ] ], - "qualities": [ { "id": "MANA_INFUSE", "level": 1 }, { "id": "CHISEL", "level": 3 } ], + "qualities": [ { "id": "MANA_INFUSE", "level": 1 }, { "id": "CHISEL", "level": 1 } ], "using": [ [ "sewing_standard", 350 ] ], - "proficiencies": [ { "proficiency": "prof_leatherworking_basic" }, { "proficiency": "prof_leatherworking" } ], - "components": [ [ [ "black_dragon_tanned_hide", 60 ] ], [ [ "dragon_black_scale", 250 ] ], [ [ "dragon_essence", 20 ] ] ] + "proficiencies": [ + { "proficiency": "prof_leatherworking_basic" }, + { "proficiency": "prof_leatherworking" }, + { "proficiency": "prof_leatherworking_dragon" } + ], + "components": [ [ [ "black_dragon_tanned_hide", 35 ] ], [ [ "dragon_essence", 18 ] ] ] }, { "result": "suit_xlblack_dragon_scale", "type": "recipe", - "activity_level": "fake", + "activity_level": "LIGHT_EXERCISE", "category": "CC_ENCHANTED", "subcategory": "CSC_ENCHANTED_ARMOR", "skill_used": "fabrication", @@ -224,118 +257,138 @@ "book_learn": [ [ "black_dragons", 6 ] ], "qualities": [ { "id": "MANA_INFUSE", "level": 2 }, { "id": "CHISEL", "level": 3 } ], "using": [ [ "sewing_standard", 350 ], [ "welding_standard", 100 ] ], - "proficiencies": [ { "proficiency": "prof_leatherworking_basic" }, { "proficiency": "prof_leatherworking" } ], - "components": [ [ [ "black_dragon_tanned_hide", 60 ] ], [ [ "dragon_black_scale", 2250 ] ], [ [ "dragon_essence", 25 ] ] ] + "proficiencies": [ + { "proficiency": "prof_leatherworking_basic" }, + { "proficiency": "prof_leatherworking" }, + { "proficiency": "prof_leatherworking_dragon" }, + { "proficiency": "prof_scaleworking_dragon" } + ], + "components": [ [ [ "black_dragon_tanned_hide", 35 ] ], [ [ "dragon_black_scale", 1800 ] ], [ [ "dragon_essence", 20 ] ] ] }, { "result": "boots_xlblack_dragon_hide", "type": "recipe", - "activity_level": "fake", + "activity_level": "LIGHT_EXERCISE", "category": "CC_ENCHANTED", "subcategory": "CSC_ENCHANTED_ARMOR", "skill_used": "tailor", "difficulty": 6, "skills_required": [ "spellcraft", 4 ], - "time": "30 h", + "time": "32 h", "book_learn": [ [ "black_dragons", 5 ] ], - "qualities": [ { "id": "MANA_INFUSE", "level": 1 }, { "id": "CHISEL", "level": 3 } ], + "qualities": [ { "id": "MANA_INFUSE", "level": 1 }, { "id": "CHISEL", "level": 1 } ], "using": [ [ "sewing_standard", 150 ] ], "proficiencies": [ { "proficiency": "prof_leatherworking_basic" }, { "proficiency": "prof_cobbling" }, - { "proficiency": "prof_leatherworking" } + { "proficiency": "prof_leatherworking" }, + { "proficiency": "prof_leatherworking_dragon" } ], - "components": [ [ [ "black_dragon_tanned_hide", 6 ] ], [ [ "dragon_black_scale", 20 ] ], [ [ "dragon_essence", 3 ] ] ] + "components": [ [ [ "black_dragon_tanned_hide", 6 ] ], [ [ "dragon_essence", 3 ] ] ] }, { "result": "boots_xlblack_dragon_scale", "type": "recipe", - "activity_level": "fake", + "activity_level": "LIGHT_EXERCISE", "category": "CC_ENCHANTED", "subcategory": "CSC_ENCHANTED_ARMOR", "skill_used": "fabrication", "difficulty": 8, "skills_required": [ "spellcraft", 6 ], - "time": "30 h", + "time": "40 h", "book_learn": [ [ "black_dragons", 6 ] ], "qualities": [ { "id": "MANA_INFUSE", "level": 2 }, { "id": "CHISEL", "level": 3 } ], "using": [ [ "sewing_standard", 150 ], [ "welding_standard", 20 ] ], "proficiencies": [ { "proficiency": "prof_leatherworking_basic" }, { "proficiency": "prof_cobbling" }, - { "proficiency": "prof_leatherworking" } + { "proficiency": "prof_leatherworking" }, + { "proficiency": "prof_leatherworking_dragon" }, + { "proficiency": "prof_scaleworking_dragon" } ], "components": [ [ [ "black_dragon_tanned_hide", 8 ] ], [ [ "dragon_black_scale", 125 ] ], [ [ "dragon_essence", 6 ] ] ] }, { "result": "helmet_xlblack_dragon_hide", "type": "recipe", - "activity_level": "fake", + "activity_level": "LIGHT_EXERCISE", "category": "CC_ENCHANTED", "subcategory": "CSC_ENCHANTED_ARMOR", "skill_used": "tailor", "difficulty": 6, "skills_required": [ "spellcraft", 4 ], - "time": "30 h", + "time": "32 h", "book_learn": [ [ "black_dragons", 5 ] ], - "qualities": [ { "id": "MANA_INFUSE", "level": 1 }, { "id": "CHISEL", "level": 3 } ], + "qualities": [ { "id": "MANA_INFUSE", "level": 1 }, { "id": "CHISEL", "level": 1 } ], "using": [ [ "sewing_standard", 150 ] ], - "proficiencies": [ { "proficiency": "prof_leatherworking_basic" }, { "proficiency": "prof_leatherworking" } ], - "components": [ [ [ "black_dragon_tanned_hide", 4 ] ], [ [ "dragon_black_scale", 12 ] ], [ [ "dragon_essence", 3 ] ] ] + "proficiencies": [ + { "proficiency": "prof_leatherworking_basic" }, + { "proficiency": "prof_leatherworking" }, + { "proficiency": "prof_leatherworking_dragon" } + ], + "components": [ [ [ "black_dragon_tanned_hide", 4 ] ], [ [ "dragon_essence", 3 ] ] ] }, { "result": "helmet_xlblack_dragon_scale", "type": "recipe", - "activity_level": "fake", + "activity_level": "LIGHT_EXERCISE", "category": "CC_ENCHANTED", "subcategory": "CSC_ENCHANTED_ARMOR", "skill_used": "fabrication", "difficulty": 8, "skills_required": [ "spellcraft", 6 ], - "time": "30 h", + "time": "40 h", "book_learn": [ [ "black_dragons", 6 ] ], "qualities": [ { "id": "MANA_INFUSE", "level": 2 }, { "id": "CHISEL", "level": 3 } ], "using": [ [ "sewing_standard", 150 ], [ "welding_standard", 20 ] ], - "proficiencies": [ { "proficiency": "prof_leatherworking_basic" }, { "proficiency": "prof_leatherworking" } ], + "proficiencies": [ + { "proficiency": "prof_leatherworking_basic" }, + { "proficiency": "prof_leatherworking" }, + { "proficiency": "prof_leatherworking_dragon" }, + { "proficiency": "prof_scaleworking_dragon" } + ], "components": [ [ [ "black_dragon_tanned_hide", 2 ] ], [ [ "dragon_black_scale", 140 ] ], [ [ "dragon_essence", 6 ] ] ] }, { "result": "gloves_xlblack_dragon_hide", "type": "recipe", - "activity_level": "fake", + "activity_level": "LIGHT_EXERCISE", "category": "CC_ENCHANTED", "subcategory": "CSC_ENCHANTED_ARMOR", "skill_used": "tailor", "difficulty": 6, "skills_required": [ "spellcraft", 4 ], - "time": "30 h", + "time": "40 h", "book_learn": [ [ "black_dragons", 5 ] ], - "qualities": [ { "id": "MANA_INFUSE", "level": 1 }, { "id": "CHISEL", "level": 3 } ], + "qualities": [ { "id": "MANA_INFUSE", "level": 1 }, { "id": "CHISEL", "level": 1 } ], "using": [ [ "sewing_standard", 150 ] ], "proficiencies": [ { "proficiency": "prof_leatherworking_basic" }, { "proficiency": "prof_articulation", "required": false, "time_multiplier": 2 }, - { "proficiency": "prof_leatherworking" } + { "proficiency": "prof_leatherworking" }, + { "proficiency": "prof_leatherworking_dragon" } ], - "components": [ [ [ "black_dragon_tanned_hide", 4 ] ], [ [ "dragon_black_scale", 15 ] ], [ [ "dragon_essence", 4 ] ] ] + "components": [ [ [ "black_dragon_tanned_hide", 4 ] ], [ [ "dragon_essence", 4 ] ] ] }, { "result": "gauntlets_xlblack_dragon_scale", "type": "recipe", - "activity_level": "fake", + "activity_level": "LIGHT_EXERCISE", "category": "CC_ENCHANTED", "subcategory": "CSC_ENCHANTED_ARMOR", "skill_used": "fabrication", "difficulty": 8, "skills_required": [ "spellcraft", 6 ], - "time": "30 h", + "time": "50 h", "book_learn": [ [ "black_dragons", 6 ] ], "qualities": [ { "id": "MANA_INFUSE", "level": 2 }, { "id": "CHISEL", "level": 3 } ], "using": [ [ "sewing_standard", 150 ], [ "welding_standard", 20 ] ], "proficiencies": [ { "proficiency": "prof_leatherworking_basic" }, { "proficiency": "prof_articulation", "required": false, "time_multiplier": 2 }, - { "proficiency": "prof_leatherworking" } + { "proficiency": "prof_leatherworking" }, + { "proficiency": "prof_leatherworking_dragon" }, + { "proficiency": "prof_scaleworking_dragon" } ], "components": [ [ [ "black_dragon_tanned_hide", 6 ] ], [ [ "dragon_black_scale", 75 ] ], [ [ "dragon_essence", 7 ] ] ] }, @@ -368,5 +421,49 @@ "qualities": [ { "id": "CHEM", "level": 1 }, { "id": "CONCENTRATE", "level": 1 }, { "id": "MANA_INFUSE", "level": 1 } ], "components": [ [ [ "dragon_essence", 5 ] ], [ [ "mutagen_black_dragon", 1 ] ], [ [ "manatouched_serum", 1 ] ] ], "flags": [ "SECRET" ] + }, + { + "result": "backpack_black_dragon_hide", + "type": "recipe", + "activity_level": "LIGHT_EXERCISE", + "category": "CC_ENCHANTED", + "subcategory": "CSC_ENCHANTED_ARMOR", + "skill_used": "tailor", + "difficulty": 5, + "skills_required": [ [ "spellcraft", 2 ], [ "fabrication", 3 ] ], + "time": "10 h", + "book_learn": [ [ "black_dragons", 4 ] ], + "qualities": [ { "id": "MANA_INFUSE", "level": 1 }, { "id": "CHISEL", "level": 1 } ], + "using": [ [ "sewing_standard", 120 ], [ "fastener_large", 2 ] ], + "proficiencies": [ + { "proficiency": "prof_leatherworking_basic" }, + { "proficiency": "prof_leatherworking" }, + { "proficiency": "prof_leatherworking_dragon" }, + { "proficiency": "prof_closures" }, + { "proficiency": "prof_closures_waterproofing" } + ], + "components": [ [ [ "black_dragon_tanned_hide", 10 ] ], [ [ "dragon_essence", 3 ] ], [ [ "plastic_sheet", 1 ] ] ] + }, + { + "result": "backpack_xl_black_dragon_hide", + "type": "recipe", + "activity_level": "LIGHT_EXERCISE", + "category": "CC_ENCHANTED", + "subcategory": "CSC_ENCHANTED_ARMOR", + "skill_used": "tailor", + "difficulty": 5, + "skills_required": [ [ "spellcraft", 2 ], [ "fabrication", 3 ] ], + "time": "13 h", + "book_learn": [ [ "black_dragons", 4 ] ], + "qualities": [ { "id": "MANA_INFUSE", "level": 1 }, { "id": "CHISEL", "level": 1 } ], + "using": [ [ "sewing_standard", 130 ], [ "fastener_large", 2 ] ], + "proficiencies": [ + { "proficiency": "prof_leatherworking_basic" }, + { "proficiency": "prof_leatherworking" }, + { "proficiency": "prof_leatherworking_dragon" }, + { "proficiency": "prof_closures" }, + { "proficiency": "prof_closures_waterproofing" } + ], + "components": [ [ [ "black_dragon_tanned_hide", 14 ] ], [ [ "dragon_essence", 4 ] ], [ [ "plastic_sheet", 1 ] ] ] } ] diff --git a/data/mods/Magiclysm/tool_qualities.json b/data/mods/Magiclysm/tool_qualities.json index 1c48775418cd3..c20c78040f9a5 100644 --- a/data/mods/Magiclysm/tool_qualities.json +++ b/data/mods/Magiclysm/tool_qualities.json @@ -3,5 +3,10 @@ "type": "tool_quality", "id": "MAGIC_MUTAGEN", "name": "magic mutagen mixer" + }, + { + "type": "tool_quality", + "id": "MAGIC_CAULDRON", + "name": "alchemical cauldron" } ] diff --git a/doc/JSON_INFO.md b/doc/JSON_INFO.md index 7fbe547bcb01a..d35def589a768 100644 --- a/doc/JSON_INFO.md +++ b/doc/JSON_INFO.md @@ -828,8 +828,8 @@ When you sort your inventory by category, these are the categories that are disp | `dmg_adj` | Adjectives used to describe damage states of a material. | `density` | Affects vehicle collision damage, with denser parts having the advantage over less-dense parts. | `vitamins` | Vitamins in a material. Usually overridden by item specific values. An integer percentage of ideal daily value. -| `specific_heat_liquid` | Specific heat of a material when not frozen (J/(g K)). Default 4.186. -| `specific_heat_solid` | Specific heat of a material when frozen (J/(g K)). Default 2.108. +| `specific_heat_liquid` | Specific heat of a material when not frozen (J/(g K)). Default 4.186 - water. +| `specific_heat_solid` | Specific heat of a material when frozen (J/(g K)). Default 2.108 - water. | `latent_heat` | Latent heat of fusion for a material (J/g). Default 334. | `freezing_point` | Freezing point of this material (C). Default 0 C ( 32 F ). | `edible` | Optional boolean. Default is false. From 793cda82ecf6d4ad14166de81e46b47686459793 Mon Sep 17 00:00:00 2001 From: Light-Wave <66904273+Light-Wave@users.noreply.github.com> Date: Thu, 25 Mar 2021 22:38:11 +0100 Subject: [PATCH 328/453] [Magiclysm] New spell: Jar of Force (#47952) * Adds Jar of Force spell for magus Adds Jar of Force, a magus spell that summons a jar of force that acts as a 3l jar. It can store liquids and be used to boil things in. * Update data/mods/Magiclysm/Spells/magus.json Co-authored-by: actual-nh <74678550+actual-nh@users.noreply.github.com> Co-authored-by: actual-nh <74678550+actual-nh@users.noreply.github.com> --- data/mods/Magiclysm/Spells/magus.json | 22 +++++++++++++ .../mods/Magiclysm/itemgroups/spellbooks.json | 1 + data/mods/Magiclysm/items/ethereal_items.json | 32 +++++++++++++++++++ data/mods/Magiclysm/items/spell_scrolls.json | 8 +++++ data/mods/Magiclysm/items/spellbooks.json | 7 ++-- 5 files changed, 68 insertions(+), 2 deletions(-) diff --git a/data/mods/Magiclysm/Spells/magus.json b/data/mods/Magiclysm/Spells/magus.json index 627c45e8df2c5..fb33365d86a29 100644 --- a/data/mods/Magiclysm/Spells/magus.json +++ b/data/mods/Magiclysm/Spells/magus.json @@ -339,6 +339,28 @@ "effect": "attack", "effect_str": "foxs_cunning" }, + { + "id": "magus_force_jar", + "type": "SPELL", + "name": { "str": "Jar of Force" }, + "description": "Summon a jar of force in which you can store liquids.", + "effect": "spawn_item", + "effect_str": "jar_3l_force", + "shape": "blast", + "valid_targets": [ "self" ], + "flags": [ "SOMATIC", "CONCENTRATE", "VERBAL" ], + "max_level": 15, + "min_damage": 1, + "max_damage": 1, + "min_duration": 8640000, + "max_duration": 129600000, + "duration_increment": 8640000, + "spell_class": "MAGUS", + "base_casting_time": 400, + "base_energy_cost": 350, + "energy_source": "MANA", + "difficulty": 3 + }, { "id": "magus_summon_impact_sling", "type": "SPELL", diff --git a/data/mods/Magiclysm/itemgroups/spellbooks.json b/data/mods/Magiclysm/itemgroups/spellbooks.json index ee790246a596f..5fadcf918fdfd 100644 --- a/data/mods/Magiclysm/itemgroups/spellbooks.json +++ b/data/mods/Magiclysm/itemgroups/spellbooks.json @@ -80,6 +80,7 @@ [ "spell_scroll_impactsling", 20 ], [ "spell_scroll_boneclub", 20 ], [ "spell_scroll_flamesword", 35 ], + [ "spell_scroll_force_jar", 30 ], [ "spell_scroll_flamebreath", 30 ] ] }, diff --git a/data/mods/Magiclysm/items/ethereal_items.json b/data/mods/Magiclysm/items/ethereal_items.json index 4f96dda1d4d77..32df41e0a69c7 100644 --- a/data/mods/Magiclysm/items/ethereal_items.json +++ b/data/mods/Magiclysm/items/ethereal_items.json @@ -776,6 +776,38 @@ "passive_effects": [ { "has": "WIELD", "condition": "ALWAYS", "values": [ { "value": "ITEM_DAMAGE_COLD", "add": 6 } ] } ] } }, + { + "id": "jar_3l_force", + "type": "GENERIC", + "category": "container", + "name": { "str": "jar of force", "str_pl": "jars of force" }, + "looks_like": "jar_glass_sealed", + "description": "A three-liter container made out of transparent force. Can be used to store liquids.", + "weight": "1 g", + "volume": "3050 ml", + "longest_side": "298 mm", + "price": 0, + "price_postapoc": 0, + "to_hit": -1, + "bashing": 1, + "material": [ ], + "symbol": ")", + "color": "light_cyan", + "pocket_data": [ + { + "pocket_type": "CONTAINER", + "rigid": true, + "watertight": true, + "max_contains_volume": "3 L", + "max_contains_weight": "6 kg" + } + ], + "flags": [ "UNBREAKABLE_MELEE", "NONCONDUCTIVE", "NO_REPAIR", "NO_SALVAGE", "MAGIC_FOCUS", "TRADER_AVOID" ], + "qualities": [ [ "CONTAIN", 1 ], [ "BOIL", 1 ] ], + "relic_data": { + "passive_effects": [ { "has": "WIELD", "condition": "ALWAYS", "values": [ { "value": "ITEM_DAMAGE_PURE", "add": 3 } ] } ] + } + }, { "id": "longsword_holy", "type": "GENERIC", diff --git a/data/mods/Magiclysm/items/spell_scrolls.json b/data/mods/Magiclysm/items/spell_scrolls.json index 196bd38f10a72..e4b7a4e43075a 100644 --- a/data/mods/Magiclysm/items/spell_scrolls.json +++ b/data/mods/Magiclysm/items/spell_scrolls.json @@ -1027,6 +1027,14 @@ "description": "Causes an intense heat at the location, greatly damaging the target.", "use_action": { "type": "learn_spell", "spells": [ "nova_flare" ] } }, + { + "type": "BOOK", + "copy-from": "spell_scroll", + "id": "spell_scroll_force_jar", + "name": { "str": "Scroll of Jar of Force", "str_pl": "Scrolls of Jar of Force" }, + "description": "Summon a jar of force you can use to store liquids in.", + "use_action": { "type": "learn_spell", "spells": [ "magus_force_jar" ] } + }, { "type": "BOOK", "copy-from": "spell_scroll", diff --git a/data/mods/Magiclysm/items/spellbooks.json b/data/mods/Magiclysm/items/spellbooks.json index 3c371e6ef75c8..09b134fcbafae 100644 --- a/data/mods/Magiclysm/items/spellbooks.json +++ b/data/mods/Magiclysm/items/spellbooks.json @@ -59,7 +59,7 @@ "id": "wizard_utility", "type": "BOOK", "name": { "str": "Wizarding Guide to Backpacking", "str_pl": "copies of Wizarding Guide to Backpacking" }, - "//": "1 Magus, 1 Biomancer, 1, Kelvinist, 1 classless spell", + "//": "2 Magus, 1 Biomancer, 1, Kelvinist, 1 classless spell", "description": "This appears to be the spell version of a guide for what things to take with you when backpacking. It's a little bulky, but will certainly prove useful.", "weight": "1 kg", "volume": "1250 ml", @@ -67,7 +67,10 @@ "material": [ "paper" ], "symbol": "?", "color": "red", - "use_action": { "type": "learn_spell", "spells": [ "phase_door", "create_lighter", "pain_split", "protection_aura" ] } + "use_action": { + "type": "learn_spell", + "spells": [ "phase_door", "create_lighter", "pain_split", "protection_aura", "magus_force_jar" ] + } }, { "id": "pyro", From b76f9816bf899717e31a83c3cef26a4db3586696 Mon Sep 17 00:00:00 2001 From: John Bytheway Date: Thu, 25 Mar 2021 21:37:14 -0400 Subject: [PATCH 329/453] Detect duplicate values in json definitions of sets (#48225) --- data/json/items/gun/460.json | 2 +- data/json/items/gun/monster_gun.json | 12 +-------- data/json/items/ranged/slings.json | 25 +++---------------- data/mods/Aftershock/items/gun/5x50.json | 2 +- data/mods/CRT_EXPANSION/items/crt_gun.json | 2 +- .../CRT_EXPANSION/items/crt_toolarmor.json | 1 - data/mods/Magiclysm/items/ethereal_items.json | 3 +-- src/json.h | 14 ++++++++--- 8 files changed, 20 insertions(+), 41 deletions(-) diff --git a/data/json/items/gun/460.json b/data/json/items/gun/460.json index d3954498777c3..f93b32285e16c 100644 --- a/data/json/items/gun/460.json +++ b/data/json/items/gun/460.json @@ -18,7 +18,7 @@ "holster": true, "max_contains_volume": "20 L", "max_contains_weight": "20 kg", - "item_restriction": [ "m1911mag", "m1911bigmag", "m1911mag", "m1911bigmag" ] + "item_restriction": [ "m1911mag", "m1911bigmag" ] } ] } diff --git a/data/json/items/gun/monster_gun.json b/data/json/items/gun/monster_gun.json index dd0dc0fd09421..54423b2743f47 100644 --- a/data/json/items/gun/monster_gun.json +++ b/data/json/items/gun/monster_gun.json @@ -63,17 +63,7 @@ "name": { "str": "hurled rubble" }, "description": "Stone at the ready to crush that which isn't part of the blob.", "material": [ "stone" ], - "flags": [ - "PRIMITIVE_RANGED_WEAPON", - "NEVER_JAMS", - "NONCONDUCTIVE", - "NO_REPAIR", - "WATERPROOF_GUN", - "NO_SALVAGE", - "NO_UNLOAD", - "WATERPROOF_GUN", - "NEVER_JAMS" - ], + "flags": [ "PRIMITIVE_RANGED_WEAPON", "NEVER_JAMS", "NONCONDUCTIVE", "NO_REPAIR", "WATERPROOF_GUN", "NO_SALVAGE", "NO_UNLOAD" ], "skill": "throw", "ammo": [ "rock" ], "ammo_effects": [ "NO_PENETRATE_OBSTACLES", "NEVER_MISFIRES" ], diff --git a/data/json/items/ranged/slings.json b/data/json/items/ranged/slings.json index c3a36f8be5e4a..64c185dbb10e3 100644 --- a/data/json/items/ranged/slings.json +++ b/data/json/items/ranged/slings.json @@ -10,7 +10,7 @@ "price": 150, "//": "It's little more than a piece of slightly shaped leather", "material": [ "leather" ], - "flags": [ "RELOAD_AND_SHOOT", "NEVER_JAMS", "PRIMITIVE_RANGED_WEAPON", "BELT_CLIP", "WATERPROOF_GUN", "NEVER_JAMS" ], + "flags": [ "RELOAD_AND_SHOOT", "NEVER_JAMS", "PRIMITIVE_RANGED_WEAPON", "BELT_CLIP", "WATERPROOF_GUN" ], "ammo_effects": [ "NEVER_MISFIRES", "NO_PENETRATE_OBSTACLES" ], "skill": "throw", "ammo": [ "rock" ], @@ -35,15 +35,7 @@ "description": "A forked piece of wood with an elastic band stretched between two of its tips. Can launch tiny pebbles and similar things at high speeds.", "price": 500, "material": [ "wood" ], - "flags": [ - "FIRE_TWOHAND", - "RELOAD_AND_SHOOT", - "NEVER_JAMS", - "PRIMITIVE_RANGED_WEAPON", - "BELT_CLIP", - "WATERPROOF_GUN", - "NEVER_JAMS" - ], + "flags": [ "FIRE_TWOHAND", "RELOAD_AND_SHOOT", "NEVER_JAMS", "PRIMITIVE_RANGED_WEAPON", "BELT_CLIP", "WATERPROOF_GUN" ], "ammo_effects": [ "NEVER_MISFIRES", "NO_PENETRATE_OBSTACLES" ], "skill": "archery", "ammo": [ "pebble" ], @@ -79,8 +71,7 @@ "NONCONDUCTIVE", "SHEATH_SPEAR", "ALWAYS_TWOHAND", - "WATERPROOF_GUN", - "NEVER_JAMS" + "WATERPROOF_GUN" ], "ammo_effects": [ "NEVER_MISFIRES", "NO_PENETRATE_OBSTACLES" ], "techniques": [ "WBLOCK_2", "RAPID", "SWEEP" ], @@ -109,15 +100,7 @@ "description": "A modern slingshot with a wrist brace, allowing it to fire tiny objects slightly more forcefully than a simple wooden slingshot.", "price": 3000, "material": [ "steel", "plastic" ], - "flags": [ - "FIRE_TWOHAND", - "RELOAD_AND_SHOOT", - "NEVER_JAMS", - "PRIMITIVE_RANGED_WEAPON", - "BELT_CLIP", - "WATERPROOF_GUN", - "NEVER_JAMS" - ], + "flags": [ "FIRE_TWOHAND", "RELOAD_AND_SHOOT", "NEVER_JAMS", "PRIMITIVE_RANGED_WEAPON", "BELT_CLIP", "WATERPROOF_GUN" ], "ammo_effects": [ "NEVER_MISFIRES", "NO_PENETRATE_OBSTACLES" ], "skill": "archery", "ammo": [ "pebble" ], diff --git a/data/mods/Aftershock/items/gun/5x50.json b/data/mods/Aftershock/items/gun/5x50.json index 503efee079558..b71d8d237ec53 100644 --- a/data/mods/Aftershock/items/gun/5x50.json +++ b/data/mods/Aftershock/items/gun/5x50.json @@ -11,7 +11,7 @@ "valid_mod_locations": [ [ "accessories", 2 ] ], "modes": [ [ "DEFAULT", "single", 1 ], [ "MULTI", "4 rd.", 4 ] ], "clip_size": 4, - "flags": [ "NEVER_JAMS", "RELOAD_ONE", "NEVER_JAMS", "RELOAD_EJECT" ], + "flags": [ "NEVER_JAMS", "RELOAD_ONE", "RELOAD_EJECT" ], "pocket_data": [ { "pocket_type": "MAGAZINE", "ammo_restriction": { "5x50": 4 } } ] } ] diff --git a/data/mods/CRT_EXPANSION/items/crt_gun.json b/data/mods/CRT_EXPANSION/items/crt_gun.json index b645c14f8f931..b20bac85e98a9 100644 --- a/data/mods/CRT_EXPANSION/items/crt_gun.json +++ b/data/mods/CRT_EXPANSION/items/crt_gun.json @@ -202,7 +202,7 @@ "price": 9900, "//": "You can get a decent Ruger .177 at walmart for $99", "material": [ "steel", "plastic" ], - "flags": [ "STR_RELOAD", "NON_FOULING", "NON_FOULING" ], + "flags": [ "STR_RELOAD", "NON_FOULING" ], "skill": "rifle", "ammo": [ "pellets" ], "weight": "5023 g", diff --git a/data/mods/CRT_EXPANSION/items/crt_toolarmor.json b/data/mods/CRT_EXPANSION/items/crt_toolarmor.json index 228154a7b7f4c..551b49fd24be8 100644 --- a/data/mods/CRT_EXPANSION/items/crt_toolarmor.json +++ b/data/mods/CRT_EXPANSION/items/crt_toolarmor.json @@ -214,7 +214,6 @@ "OUTER", "LIGHT_35", "CHARGEDIM", - "NO_UNLOAD", "TRADER_AVOID" ], "material_thickness": 3, diff --git a/data/mods/Magiclysm/items/ethereal_items.json b/data/mods/Magiclysm/items/ethereal_items.json index 32df41e0a69c7..a4ac0b348f05d 100644 --- a/data/mods/Magiclysm/items/ethereal_items.json +++ b/data/mods/Magiclysm/items/ethereal_items.json @@ -637,8 +637,7 @@ "TRADER_AVOID", "NO_UNLOAD", "NO_REPAIR", - "WATERPROOF_GUN", - "NEVER_JAMS" + "WATERPROOF_GUN" ], "ammo_effects": [ "NEVER_MISFIRES" ], "weight": "86 g", diff --git a/src/json.h b/src/json.h index 550b12086d25f..f9bbb5dba5ae7 100644 --- a/src/json.h +++ b/src/json.h @@ -466,7 +466,11 @@ class JsonIn while( !end_array() ) { typename T::value_type element; if( read( element, throw_on_error ) ) { - v.insert( std::move( element ) ); + if( !v.insert( std::move( element ) ).second ) { + return error_or_false( + throw_on_error, + "Duplicate entry in set defined by json array" ); + } } else { skip_value(); } @@ -1441,7 +1445,9 @@ Res JsonArray::get_tags( const size_t index ) const } for( const std::string line : jsin->get_array() ) { - res.insert( T( line ) ); + if( !res.insert( T( line ) ).second ) { + jsin->error( "duplicate item in set defined by json array" ); + } } return res; @@ -1466,7 +1472,9 @@ Res JsonObject::get_tags( const std::string &name ) const // otherwise assume it's an array and error if it isn't. for( const std::string line : jsin->get_array() ) { - res.insert( T( line ) ); + if( !res.insert( T( line ) ).second ) { + jsin->error( "duplicate item in set defined by json array" ); + } } return res; From d79752af60a284853dacff3097afb27d978c9e41 Mon Sep 17 00:00:00 2001 From: Eric <52087122+Ramza13@users.noreply.github.com> Date: Fri, 26 Mar 2021 22:34:11 -0400 Subject: [PATCH 330/453] Change weather to use effect_on_conditions (#48178) * Move weather into effect_on_conditions * Update effect_on_condition.json * LGTM issue --- data/json/effect_on_condition.json | 78 +++++++++++++++ data/json/weather_type.json | 82 ++++------------ doc/NPCs.md | 22 ++++- doc/WEATHER_TYPE.md | 76 ++------------- src/condition.cpp | 132 ++++++++++++++++++++++++-- src/condition.h | 20 +++- src/debug_menu.cpp | 3 +- src/dialogue.h | 4 + src/npctalk.cpp | 124 ++++++++++++++++++++++++ src/npctalk.h | 1 + src/npctalk_funcs.cpp | 7 ++ src/overmap_ui.cpp | 3 +- src/talker.h | 10 ++ src/talker_character.cpp | 20 ++++ src/talker_character.h | 6 ++ src/weather.cpp | 147 ++++------------------------- src/weather.h | 8 +- src/weather_gen.cpp | 77 +++++---------- src/weather_gen.h | 9 +- src/weather_type.cpp | 141 ++------------------------- src/weather_type.h | 79 +--------------- tests/weather_test.cpp | 4 +- 22 files changed, 504 insertions(+), 549 deletions(-) create mode 100644 data/json/effect_on_condition.json diff --git a/data/json/effect_on_condition.json b/data/json/effect_on_condition.json new file mode 100644 index 0000000000000..dc0db08616435 --- /dev/null +++ b/data/json/effect_on_condition.json @@ -0,0 +1,78 @@ +[ + { + "type": "effect_on_condition", + "id": "thunder", + "recurrence_min": 1, + "recurrence_max": 1, + "condition": { + "and": [ + { "or": [ { "is_weather": "thunder" }, { "is_weather": "lightning" } ] }, + { "one_in_chance": 50 }, + { "u_is_height": 0 } + ] + }, + "deactivate_condition": { "not": { "or": [ { "is_weather": "thunder" }, { "is_weather": "lightning" } ] } }, + "effect": [ + { "message": "You hear a distant rumble of thunder.", "sound": true }, + { "sound_effect": "thunder_far", "outdoor_event": true } + ] + }, + { + "type": "effect_on_condition", + "id": "lightning", + "recurrence_min": 1, + "recurrence_max": 1, + "condition": { "and": [ { "is_weather": "lightning" }, { "one_in_chance": 600 }, { "u_is_height": 0 } ] }, + "deactivate_condition": { "not": { "is_weather": "lightning" } }, + "effect": [ + { "message": "A flash of lightning illuminates your surroundings!" }, + { "sound_effect": "thunder_near" }, + "lightning" + ] + }, + { + "type": "effect_on_condition", + "id": "acid_drizzle", + "recurrence_min": 1, + "recurrence_max": 1, + "condition": { "and": [ { "is_weather": "acid_drizzle" }, "u_is_outside", { "not": { "u_has_pain": 30 } } ] }, + "deactivate_condition": { "not": { "is_weather": "acid_drizzle" } }, + "effect": [ { "message": "The acid rain stings, but is mostly harmless for now…" }, { "u_mod_pain": 1 } ] + }, + { + "type": "effect_on_condition", + "id": "acid_rain", + "recurrence_min": 1, + "recurrence_max": 1, + "condition": { + "and": [ + { "is_weather": "acid_rain" }, + "u_is_outside", + { "not": { "u_has_pain": 100 } }, + { + "not": { "or": [ { "u_has_wielded_with_flag": "RAIN_PROTECT" }, { "u_has_worn_with_flag": "RAINPROOF" } ] } + } + ] + }, + "deactivate_condition": { "not": { "is_weather": "acid_rain" } }, + "effect": [ { "message": "The acid rain burns!" }, { "u_mod_pain": 3 } ] + }, + { + "type": "effect_on_condition", + "id": "snow", + "recurrence_min": 6, + "recurrence_max": 6, + "condition": { "and": [ { "is_weather": "snowing" }, "u_is_outside" ] }, + "deactivate_condition": { "not": { "is_weather": "snowing" } }, + "effect": [ { "u_add_wet": 10 } ] + }, + { + "type": "effect_on_condition", + "id": "snowstorm", + "recurrence_min": 6, + "recurrence_max": 6, + "condition": { "and": [ { "is_weather": "snowstorm" }, "u_is_outside" ] }, + "deactivate_condition": { "not": { "is_weather": "snowstorm" } }, + "effect": [ { "u_add_wet": 40 } ] + } +] diff --git a/data/json/weather_type.json b/data/json/weather_type.json index 77fb5a5955120..62e2bebee943c 100644 --- a/data/json/weather_type.json +++ b/data/json/weather_type.json @@ -15,7 +15,7 @@ "rains": false, "acidic": false, "sun_intensity": "high", - "requirements": { "pressure_min": 1020, "humidity_max": 70, "time": "day" } + "condition": { "and": [ "is_day", { "is_pressure": 1020 }, { "not": { "is_humidity": 70 } } ] } }, { "id": "cloudy", @@ -33,7 +33,7 @@ "rains": false, "acidic": false, "sun_intensity": "light", - "requirements": { "pressure_max": 1010, "humidity_min": 40 } + "condition": { "and": [ { "is_humidity": 40 }, { "not": { "is_pressure": 1010 } } ] } }, { "id": "light_drizzle", @@ -54,7 +54,8 @@ "weather_animation": { "factor": 0.01, "color": "light_blue", "sym": "," }, "sound_category": "drizzle", "sun_intensity": "light", - "requirements": { "pressure_max": 1003, "humidity_min": 96, "humidity_and_pressure": false, "required_weathers": [ "cloudy" ] } + "required_weathers": [ "cloudy" ], + "condition": { "or": [ { "is_humidity": 96 }, { "not": { "is_pressure": 1003 } } ] } }, { "id": "drizzle", @@ -75,7 +76,8 @@ "weather_animation": { "factor": 0.01, "color": "light_blue", "sym": "." }, "sound_category": "drizzle", "sun_intensity": "light", - "requirements": { "pressure_max": 1000, "humidity_min": 97, "humidity_and_pressure": false, "required_weathers": [ "light_drizzle" ] } + "required_weathers": [ "light_drizzle" ], + "condition": { "or": [ { "is_humidity": 97 }, { "not": { "is_pressure": 1000 } } ] } }, { "id": "rain", @@ -96,12 +98,8 @@ "weather_animation": { "factor": 0.02, "color": "light_blue", "sym": "," }, "sound_category": "rainy", "sun_intensity": "light", - "requirements": { - "pressure_max": 993, - "humidity_min": 98, - "humidity_and_pressure": false, - "required_weathers": [ "light_drizzle", "drizzle" ] - } + "required_weathers": [ "light_drizzle", "drizzle" ], + "condition": { "or": [ { "is_humidity": 98 }, { "not": { "is_pressure": 993 } } ] } }, { "id": "thunder", @@ -118,19 +116,12 @@ "precip": "heavy", "rains": true, "acidic": false, - "effects": [ - { - "one_in_chance": 50, - "must_be_outside": false, - "sound_message": "You hear a distant rumble of thunder.", - "sound_effect": "thunder_far" - } - ], "tiles_animation": "weather_rain_drop", "weather_animation": { "factor": 0.02, "color": "light_blue", "sym": "." }, "sound_category": "thunder", "sun_intensity": "none", - "requirements": { "pressure_max": 996, "required_weathers": [ "rain" ] } + "required_weathers": [ "rain" ], + "condition": { "not": { "is_pressure": 996 } } }, { "id": "lightning", @@ -147,26 +138,12 @@ "precip": "heavy", "rains": true, "acidic": false, - "effects": [ - { - "one_in_chance": 50, - "must_be_outside": false, - "sound_message": "You hear a distant rumble of thunder.", - "sound_effect": "thunder_far" - }, - { - "one_in_chance": 600, - "must_be_outside": false, - "message": "A flash of lightning illuminates your surroundings!.", - "sound_effect": "thunder_near", - "lightning": true - } - ], "tiles_animation": "weather_rain_drop", "weather_animation": { "factor": 0.04, "color": "light_blue", "sym": "," }, "sound_category": "thunder", "sun_intensity": "none", - "requirements": { "pressure_max": 990, "required_weathers": [ "thunder" ] } + "required_weathers": [ "thunder" ], + "condition": { "not": { "is_pressure": 990 } } }, { "id": "acid_drizzle", @@ -183,21 +160,11 @@ "precip": "light", "rains": true, "acidic": true, - "effects": [ - { - "time_between": "3 minutes", - "must_be_outside": true, - "message": "The acid rain stings, but is mostly harmless for now…", - "rain_proof": true, - "pain_max": 10, - "pain": 1 - } - ], "tiles_animation": "weather_acid_drop", "weather_animation": { "factor": 0.01, "color": "light_green", "sym": "." }, "sound_category": "drizzle", "sun_intensity": "normal", - "requirements": { "required_weathers": [ "drizzle" ] } + "required_weathers": [ "drizzle" ] }, { "id": "acid_rain", @@ -214,21 +181,11 @@ "precip": "heavy", "rains": true, "acidic": true, - "effects": [ - { - "time_between": "2 seconds", - "must_be_outside": true, - "message": "The acid rain burns!", - "rain_proof": true, - "pain_max": 100, - "pain": 3 - } - ], "tiles_animation": "weather_acid_drop", "weather_animation": { "factor": 0.02, "color": "light_green", "sym": "," }, "sound_category": "rainy", "sun_intensity": "none", - "requirements": { "required_weathers": [ "rain" ] } + "required_weathers": [ "rain" ] }, { "id": "flurries", @@ -249,7 +206,8 @@ "weather_animation": { "factor": 0.01, "color": "white", "sym": "." }, "sound_category": "flurries", "sun_intensity": "light", - "requirements": { "temperature_max": 33, "required_weathers": [ "drizzle" ] } + "required_weathers": [ "flurries" ], + "condition": { "not": { "is_temperature": 33 } } }, { "id": "snowing", @@ -266,12 +224,12 @@ "precip": "heavy", "rains": false, "acidic": false, - "effects": [ { "must_be_outside": true, "wet": 10 } ], "tiles_animation": "weather_snowflake", "weather_animation": { "factor": 0.02, "color": "white", "sym": "," }, "sound_category": "snow", "sun_intensity": "light", - "requirements": { "temperature_max": 33, "required_weathers": [ "rain", "thunder", "lightning" ] } + "required_weathers": [ "rain", "thunder", "lightning" ], + "condition": { "not": { "is_temperature": 33 } } }, { "id": "snowstorm", @@ -288,11 +246,11 @@ "precip": "heavy", "rains": false, "acidic": false, - "effects": [ { "must_be_outside": true, "wet": 40 } ], "tiles_animation": "weather_snowflake", "weather_animation": { "factor": 0.04, "color": "white", "sym": "*" }, "sound_category": "snowstorm", "sun_intensity": "none", - "requirements": { "temperature_max": 33, "windpower_min": 15, "required_weathers": [ "thunder", "lightning" ] } + "required_weathers": [ "thunder", "lightning" ], + "condition": { "and": [ { "is_windpower": 15 }, { "not": { "is_temperature": 33 } } ] } } ] diff --git a/doc/NPCs.md b/doc/NPCs.md index 28c9fc1fd9601..5f9e5f18d9a80 100644 --- a/doc/NPCs.md +++ b/doc/NPCs.md @@ -486,6 +486,8 @@ Effect | Description `barber_beard` | Opens a menu allowing the player to choose a new beard style. `u_learn_recipe: recipe_string` | Your character will learn and memorize the recipe `recipe_string`. `npc_first_topic: talk_topic_string` | Changes the initial talk_topic of the NPC in all future dialogues. +`u_mod_pain: pain_int`
`npc_mod_pain: pain_int` | Your character or the NPC will have `pain_int` added or subtracted from its pain. +`u_add_wet: wet_int`
`npc_add_wet: wet_int` | Your character or the NPC will be wet `wet_int` as if they were in the rain. #### Trade / Items @@ -549,6 +551,13 @@ Effect | Description #### Map Updates `mapgen_update: mapgen_update_id_string`
`mapgen_update:` *list of `mapgen_update_id_string`s*, (optional `assign_mission_target` parameters) | With no other parameters, updates the overmap tile at the player's current location with the changes described in `mapgen_update_id` (or for each `mapgen_update_id` in the list). The `assign_mission_target` parameters can be used to change the location of the overmap tile that gets updated. See [the missions docs](MISSIONS_JSON.md) for `assign_mission_target` parameters and [the mapgen docs](MAPGEN.md) for `mapgen_update`. +`lightning` | Lights up the map as if its day time. + +#### General +Effect | Description +---|--- +`message: message_string`, (*optional* `sound: sound_bool`),(*optional* `outdoor_only: outdoor_only_bool`),(*optional* `snippet: snippet_bool`),(*optional* `type: type_string`),(*optional* `popup: popup_bool`) | Displays a message to the player of `message_string`. If `snippet_bool` is true(defaults to false) it will instead display a random snippet from `message_string` category. If `sound` is true(defaults to false) it will only display the message if the player is not deaf. `outdoor_only`(defaults to false) only matters when `sound` is true and will make the message less likely to be heard if the player is underground. Message will display as type of `type_string`. Type affects the color of message and can be any of the following values: good, neutral, bad, mixed, warning, info, debug, headshot, critical, grazing. enums.h has more info on each types use. If `popup_bool` is true the message will be in a modal popup the user has to dismiss to continue. +`sound_effect: sound_effect_id_string`, *optional* `outdoor_event: outdoor_event` | Will play a sound effect of type `sound_effect_id_string`. If `outdoor_event`(defaults to false) is true this will be less likely to play if the player is underground. #### Deprecated @@ -623,6 +632,10 @@ Condition | Type | Description `"u_driving"`
`"npc_driving"` | simple string | `true` if the player character or NPC is operating a vehicle. Note NPCs cannot currently operate vehicles. `"u_has_skill"`
`"npc_has_skill"` | dictionary | `u_has_skill` or `npc_has_skill` must be a dictionary with a `skill` string and a `level` int.
`true` if the player character or NPC has at least the value of `level` in `skill`. `"u_know_recipe"` | string | `true` if the player character knows the recipe specified in `u_know_recipe`. It only counts as known if it is actually memorized--holding a book with the recipe in it will not count. +`"u_has_pain"`
`"npc_has_pain"` | int | `true` if the player character's or NPC's pain is at least the value of `u_has_pain` or `npc_has_pain`. +`"u_is_height"`
`"npc_is_height"` | int | `true` if the player character's or NPC's elevation is at least the value of `u_is_height` or `npc_is_height`. +`"u_has_worn_with_flag"`
`"npc_has_worn_with_flag"` | string | `true` if the player character or NPC is wearing something with the `u_has_worn_with_flag` or `npc_has_worn_with_flag` flag. +`"u_has_wielded_with_flag"`
`"npc_has_wielded_with_flag"` | string | `true` if the player character or NPC is wielding something with the `u_has_wielded_with_flag` or `npc_has_wielded_with_flag` flag. #### Player Only conditions @@ -678,8 +691,13 @@ Condition | Type | Description `"days_since_cataclysm"` | int | `true` if at least `days_since_cataclysm` days have passed since the Cataclysm. `"is_season"` | string | `true` if the current season matches `is_season`, which must be one of "`spring"`, `"summer"`, `"autumn"`, or `"winter"`. `"is_day"` | simple string | `true` if it is currently daytime. -`"is_outside"` | simple string | `true` if the NPC is on a tile without a roof. - +`"u_is_outside"`
`"npc_is_outside"` | simple string | `true` if you or the NPC is on a tile without a roof. +`"one_in_chance"` | int | `true` if a one in `one_in_chance` random chance occurs. +`"is_temperature"` | int | `true` if it is currently at least `"is_temperature"` degrees fahrenheit. +`"is_windpower"` | int | `true` if current windpower is at least `"is_windpower"`. +`"is_humidity"` | int | `true` if current humidity is at least `"is_humidity"`. +`"is_pressure"` | int | `true` if current pressure is at least `"is_pressure"`. +`"is_weather"` | int | `true` if current weather is `"is_weather"`. #### Sample responses with conditions and effects ```json diff --git a/doc/WEATHER_TYPE.md b/doc/WEATHER_TYPE.md index 01612bb348467..b572553cd35c5 100644 --- a/doc/WEATHER_TYPE.md +++ b/doc/WEATHER_TYPE.md @@ -1,6 +1,6 @@ # WEATHER TYPES -Each weather type is a type of weather that occurs, its effects and what causes it. The only required entries are null and clear. +Each weather type is a type of weather that occurs, and what causes it. The only required entries are null and clear. ## `weather_type` properties @@ -26,8 +26,8 @@ Each weather type is a type of weather that occurs, its effects and what causes | `time_between_min` | Optional: the lower bound on the amount of time that will be guaranteed to pass before this weather happens again. Defaults to 0. | | `time_between_max` | Optional: the upper bound on the amount of time that will be guaranteed to pass before this weather happens again. Defaults to 0. | | `weather_animation` | Optional, Information controlling weather animations. Members: factor, color and glyph | -| `effects` | Array for the effects the weather has. Descibed in detail below -| `requirements` | Optional, is what determines what weather it is. All members are optional. When determining current weather, it loops through the entries in order and uses the last one to pass all the requirements. | +| `required_weathers` | a string array of possible weathers it is at this point in the loop. i.e. rain can only happen if the conditions for clouds light drizzle or drizzle are present | +| `condition` | A dialog condition to determine if this weather is happening. See Dialogue conditions section of [NPCs](NPCs.md) #### `weather_type` example @@ -37,9 +37,9 @@ Each weather type is a type of weather that occurs, its effects and what causes "id": "lightning", "type": "weather_type", "name": "Lightning Storm", - "color": "yellow", + "color": "c_yellow", "map_color": "h_yellow", - "sym": "%", + "glyph": "%", "ranged_penalty": 4, "sight_penalty": 1.25, "light_modifier": -45, @@ -48,27 +48,9 @@ Each weather type is a type of weather that occurs, its effects and what causes "precip": "heavy", "rains": true, "acidic": false, - "effects": [ - { - "one_in_chance": 50, - "must_be_outside": false, - "sound_message": "You hear a distant rumble of thunder.", - "sound_effect": "thunder_far" - }, - { - "one_in_chance": 600, - "must_be_outside": false, - "message": "A flash of lightning illuminates your surroundings!.", - "sound_effect": "thunder_near", - "lightning": true - } - ], - "tiles_animation": "weather_rain_drop", - "weather_animation": { "factor": 0.04, "color": "light_blue", "sym": "," }, - "sound_category": "thunder", - "sun_intensity": "none", - "requirements": { "pressure_max": 990, "required_weathers": [ "thunder" ] } - }, + "required_weathers": [ "thunder" ], + "condition": { "not": { "is_pressure": 990 } } + } ] ``` @@ -128,45 +110,3 @@ Each weather type is a type of weather that occurs, its effects and what causes }] } ``` - -### `requirements` properties - -| Identifier | Description | -| ------------------------------ | --------------------------------------------------------------------- | -| `pressure_min` | These are all minimum and maximum values for which the weather will occur. I.e., it will only rain if it is sufficiently humid. | -| `pressure_max` | | -| `humidity_min` | | -| `humidity_max` | | -| `temperature_min` | | -| `temperature_max` | | -| `windpower_min` | | -| `windpower_max` | | -| `humidity_and_pressure` | should logical AND be used for pressure and humidity requirements when they are both defined | -| `acidic` | does this require acidic precipitation | -| `time` | Valid values are: "day", "night", and "both". | -| `required_weathers` | a string array of possible prior weathers; i.e., rain can only happen if the conditions for clouds, light drizzle, or drizzle are present | -| `time_passed_min` | Optional: Time after the Cataclysm when this weather can start appearing; | -| `time_passed_max` | Optional: Time after the Cataclysm when this weather can no longer appear. | -| `one_in_chance` | Optional: This has a 1 in this value chance of happening. This will usually be called every 5 minutes| - - -### `spawns` properties - -| Identifier | Description | -| ------------------------------ | --------------------------------------------------------------------- | -| `max_radius` | Optional: The furthest away a spawn will happen. | -| `min_radius` | Optional: The closest a spawn will happen. | -| `hallucination_count` | Optional: Number of hallucinations of the target to spawn. | -| `real_count` | Optional: Number of real copies to spawn. | -| `target` | Optional: Monster id of target to spawn. If left blank a nearby monster will be used. | -| `target_range` | Optional: If target is left blank how far away to look for something to copy. | - -### `fields` properties - -| Identifier | Description | -| ------------------------------ | --------------------------------------------------------------------- | -| `type` | The string id of the field. | -| `intensity` | Intensity of the field. | -| `age` | Age of the field. | -| `outdoor_only` | Optional: Defaults to true. If true field will only spawn outdoors. | -| `radius` | Optional: Radius around player the effect will spread, defaults to everywhere. | diff --git a/src/condition.cpp b/src/condition.cpp index e5933505c5997..10aae878264d7 100644 --- a/src/condition.cpp +++ b/src/condition.cpp @@ -746,15 +746,75 @@ void conditional_t::set_is_day() } template -void conditional_t::set_is_outside() +void conditional_t::set_is_outside( bool is_npc ) { - condition = []( const T & d ) { - const map &here = get_map(); - const tripoint &pos = here.getabs( d.beta->pos() ); - return !here.has_flag( TFLAG_INDOORS, pos ); + condition = [is_npc]( const T & d ) { + return is_creature_outside( *d.actor( is_npc )->get_character() ); + }; +} + +template +void conditional_t::set_one_in_chance( const JsonObject &jo, const std::string &member ) +{ + const int one_in_chance = jo.get_int( member ); + condition = [one_in_chance]( const T & ) { + return one_in( one_in_chance ); + }; +} + +template +void conditional_t::set_is_temperature( const JsonObject &jo, const std::string &member ) +{ + const int temp_min = jo.get_int( member ); + condition = [temp_min]( const T & ) { + return get_weather().weather_precise->temperature >= temp_min; + }; +} + +template +void conditional_t::set_is_height( const JsonObject &jo, const std::string &member, bool is_npc ) +{ + const int height_min = jo.get_int( member ); + condition = [height_min, is_npc]( const T & d ) { + return d.actor( is_npc )->posz() >= height_min; + }; +} + +template +void conditional_t::set_is_windpower( const JsonObject &jo, const std::string &member ) +{ + const int windpower_min = jo.get_int( member ); + condition = [windpower_min]( const T & ) { + return get_weather().weather_precise->windpower >= windpower_min; + }; +} + +template +void conditional_t::set_is_humidity( const JsonObject &jo, const std::string &member ) +{ + const int humidity_min = jo.get_int( member ); + condition = [humidity_min]( const T & ) { + return get_weather().weather_precise->humidity >= humidity_min; }; } +template +void conditional_t::set_is_pressure( const JsonObject &jo, const std::string &member ) +{ + const int pressure_min = jo.get_int( member ); + condition = [pressure_min]( const T & ) { + return get_weather().weather_precise->pressure >= pressure_min; + }; +} + +template +void conditional_t::set_is_weather( const JsonObject &jo ) +{ + weather_type_id weather = weather_type_id( jo.get_string( "is_weather" ) ); + condition = [weather]( const T & ) { + return get_weather().weather_id == weather; + }; +} template void conditional_t::set_u_has_camp() { @@ -828,6 +888,36 @@ void conditional_t::set_mission_has_generic_rewards() }; } +template +void conditional_t::set_has_worn_with_flag( const JsonObject &jo, const std::string &member, + bool is_npc ) +{ + const std::string flag( jo.get_string( member ) ); + condition = [flag, is_npc]( const T & d ) { + return d.actor( is_npc )->worn_with_flag( flag_id( flag ) ); + }; +} + +template +void conditional_t::set_has_wielded_with_flag( const JsonObject &jo, const std::string &member, + bool is_npc ) +{ + const std::string flag( jo.get_string( member ) ); + condition = [flag, is_npc]( const T & d ) { + return d.actor( is_npc )->wielded_with_flag( flag_id( flag ) ); + }; +} + +template +void conditional_t::set_has_pain( const JsonObject &jo, const std::string &member, + bool is_npc ) +{ + const int min_pain = jo.get_int( member ); + condition = [min_pain, is_npc]( const T & d ) { + return d.actor( is_npc )->pain_cur() >= min_pain; + }; +} + template conditional_t::conditional_t( const JsonObject &jo ) { @@ -1006,6 +1096,34 @@ conditional_t::conditional_t( const JsonObject &jo ) set_has_skill( jo, "npc_has_skill", is_npc ); } else if( jo.has_member( "u_know_recipe" ) ) { set_u_know_recipe( jo, "u_know_recipe" ); + } else if( jo.has_int( "one_in_chance" ) ) { + set_one_in_chance( jo, "one_in_chance" ); + } else if( jo.has_int( "is_temperature" ) ) { + set_is_temperature( jo, "is_temperature" ); + } else if( jo.has_int( "is_windpower" ) ) { + set_is_windpower( jo, "is_windpower" ); + } else if( jo.has_int( "is_humidity" ) ) { + set_is_humidity( jo, "is_humidity" ); + } else if( jo.has_member( "is_pressure" ) ) { + set_is_pressure( jo, "is_pressure" ); + } else if( jo.has_int( "u_is_height" ) ) { + set_is_height( jo, "u_is_height" ); + } else if( jo.has_int( "npc_is_height" ) ) { + set_is_height( jo, "npc_is_height", is_npc ); + } else if( jo.has_string( "u_has_worn_with_flag" ) ) { + set_has_worn_with_flag( jo, "u_has_worn_with_flag" ); + } else if( jo.has_string( "npc_has_worn_with_flag" ) ) { + set_has_worn_with_flag( jo, "npc_has_worn_with_flag", is_npc ); + } else if( jo.has_string( "u_has_wielded_with_flag" ) ) { + set_has_wielded_with_flag( jo, "u_has_wielded_with_flag" ); + } else if( jo.has_string( "npc_has_wielded_with_flag" ) ) { + set_has_wielded_with_flag( jo, "npc_has_wielded_with_flag", is_npc ); + } else if( jo.has_member( "u_has_pain" ) ) { + set_has_pain( jo, "u_has_pain" ); + } else if( jo.has_int( "npc_has_pain" ) ) { + set_has_pain( jo, "npc_has_pain", is_npc ); + } else if( jo.has_string( "is_weather" ) ) { + set_is_weather( jo ); } else { for( const std::string &sub_member : dialogue_data::simple_string_conds ) { if( jo.has_string( sub_member ) ) { @@ -1087,8 +1205,10 @@ conditional_t::conditional_t( const std::string &type ) set_is_day(); } else if( type == "u_has_stolen_item" ) { set_has_stolen_item( is_npc ); - } else if( type == "is_outside" ) { + } else if( type == "u_is_outside" ) { set_is_outside(); + } else if( type == "is_outside" || type == "npc_is_outside" ) { + set_is_outside( is_npc ); } else if( type == "u_has_camp" ) { set_u_has_camp(); } else if( type == "has_pickup_list" ) { diff --git a/src/condition.h b/src/condition.h index ea9fd856de8bd..25af633754c12 100644 --- a/src/condition.h +++ b/src/condition.h @@ -23,7 +23,7 @@ const std::unordered_set simple_string_conds = { { "mission_complete", "mission_incomplete", "mission_has_generic_rewards", "npc_available", "npc_following", "npc_friend", "npc_hostile", "npc_train_skills", "npc_train_styles", "npc_train_spells", - "at_safe_space", "is_day", "npc_has_activity", "is_outside", "u_has_camp", + "at_safe_space", "is_day", "npc_has_activity", "is_outside", "u_is_outside", "npc_is_outside", "u_has_camp", "u_can_stow_weapon", "npc_can_stow_weapon", "u_has_weapon", "npc_has_weapon", "u_driving", "npc_driving", "has_pickup_list", "is_by_radio", "has_reason" @@ -43,7 +43,10 @@ const std::unordered_set complex_conds = { { "npc_cbm_reserve_rule", "npc_cbm_recharge_rule", "days_since_cataclysm", "is_season", "mission_goal", "u_has_var", "npc_has_var", "u_has_skill", "npc_has_skill", "u_know_recipe", "u_compare_var", "npc_compare_var", - "u_compare_time_since_var", "npc_compare_time_since_var" + "u_compare_time_since_var", "npc_compare_time_since_var", "is_weather", "one_in_chance", + "is_temperature", "is_windpower", "is_humidity", "is_pressure", "u_is_height", "npc_is_height", + "u_has_worn_with_flag", "npc_has_worn_with_flag", "u_has_wielded_with_flag", "npc_has_wielded_with_flag", + "u_has_pain", "npc_has_pain" } }; } // namespace dialogue_data @@ -88,6 +91,16 @@ struct conditional_t { void set_has_dexterity( const JsonObject &jo, const std::string &member, bool is_npc = false ); void set_has_intelligence( const JsonObject &jo, const std::string &member, bool is_npc = false ); void set_has_perception( const JsonObject &jo, const std::string &member, bool is_npc = false ); + void set_has_pain( const JsonObject &jo, const std::string &member, bool is_npc = false ); + void set_one_in_chance( const JsonObject &jo, const std::string &member ); + void set_is_temperature( const JsonObject &jo, const std::string &member ); + void set_is_height( const JsonObject &jo, const std::string &member, bool is_npc = false ); + void set_is_windpower( const JsonObject &jo, const std::string &member ); + void set_has_worn_with_flag( const JsonObject &jo, const std::string &member, bool is_npc = false ); + void set_is_humidity( const JsonObject &jo, const std::string &member ); + void set_is_pressure( const JsonObject &jo, const std::string &member ); + void set_has_wielded_with_flag( const JsonObject &jo, const std::string &member, + bool is_npc = false ); void set_is_wearing( const JsonObject &jo, const std::string &member, bool is_npc = false ); void set_has_item( const JsonObject &jo, const std::string &member, bool is_npc = false ); void set_has_items( const JsonObject &jo, const std::string &member, bool is_npc = false ); @@ -108,6 +121,7 @@ struct conditional_t { void set_npc_override( const JsonObject &jo ); void set_days_since( const JsonObject &jo ); void set_is_season( const JsonObject &jo ); + void set_is_weather( const JsonObject &jo ); void set_mission_goal( const JsonObject &jo ); void set_no_assigned_mission(); void set_has_assigned_mission(); @@ -130,7 +144,7 @@ struct conditional_t { void set_is_driving( bool is_npc = false ); void set_is_day(); void set_has_stolen_item( bool is_npc = false ); - void set_is_outside(); + void set_is_outside( bool is_npc = false ); void set_is_by_radio(); void set_u_has_camp(); void set_has_pickup_list(); diff --git a/src/debug_menu.cpp b/src/debug_menu.cpp index a7fbc2d575454..6ad998654ff89 100644 --- a/src/debug_menu.cpp +++ b/src/debug_menu.cpp @@ -2663,8 +2663,7 @@ void debug() } break; case debug_menu_index::TEST_WEATHER: { - get_weather().get_cur_weather_gen().test_weather( g->get_seed(), - get_weather().next_instance_allowed ); + get_weather().get_cur_weather_gen().test_weather( g->get_seed() ); } break; diff --git a/src/dialogue.h b/src/dialogue.h index 24ab167dfa820..c707b594a7b63 100644 --- a/src/dialogue.h +++ b/src/dialogue.h @@ -99,6 +99,10 @@ struct talk_effect_fun_t { void set_remove_effect( const JsonObject &jo, const std::string &member, bool is_npc = false ); void set_add_trait( const JsonObject &jo, const std::string &member, bool is_npc = false ); void set_remove_trait( const JsonObject &jo, const std::string &member, bool is_npc = false ); + void set_message( const JsonObject &jo, const std::string &member ); + void set_mod_pain( const JsonObject &jo, const std::string &member, bool is_npc ); + void set_add_wet( const JsonObject &jo, const std::string &member, bool is_npc ); + void set_sound_effect( const JsonObject &jo, const std::string &member ); void set_add_var( const JsonObject &jo, const std::string &member, bool is_npc = false ); void set_remove_var( const JsonObject &jo, const std::string &member, bool is_npc = false ); void set_adjust_var( const JsonObject &jo, const std::string &member, bool is_npc = false ); diff --git a/src/npctalk.cpp b/src/npctalk.cpp index 7945b7cb96a19..a5f09105e21b6 100644 --- a/src/npctalk.cpp +++ b/src/npctalk.cpp @@ -80,6 +80,7 @@ static const activity_id ACT_WAIT_NPC( "ACT_WAIT_NPC" ); static const efftype_id effect_narcosis( "narcosis" ); static const efftype_id effect_riding( "riding" ); +static const efftype_id effect_sleep( "sleep" ); static const efftype_id effect_under_operation( "under_operation" ); static const itype_id fuel_type_animal( "animal" ); @@ -2061,6 +2062,116 @@ void talk_effect_fun_t::set_npc_first_topic( const std::string &chat_topic ) }; } +void talk_effect_fun_t::set_message( const JsonObject &jo, const std::string &member ) +{ + std::string message = jo.get_string( member ); + const bool snippet = jo.get_bool( "snippet", false ); + const bool outdoor_only = jo.get_bool( "outdoor_only", false ); + const bool sound = jo.get_bool( "sound", false ); + const bool popup_msg = jo.get_bool( "popup", false ); + game_message_type type = m_neutral; + std::string type_string = jo.get_string( "type", "neutral" ); + if( type_string == "good" ) { + type = m_good; + } else if( type_string == "neutral" ) { + type = m_neutral; + } else if( type_string == "bad" ) { + type = m_bad; + } else if( type_string == "mixed" ) { + type = m_mixed; + } else if( type_string == "warning" ) { + type = m_warning; + } else if( type_string == "info" ) { + type = m_info; + } else if( type_string == "debug" ) { + type = m_debug; + } else if( type_string == "headshot" ) { + type = m_headshot; + } else if( type_string == "critical" ) { + type = m_critical; + } else if( type_string == "grazing" ) { + type = m_grazing; + } else { + jo.throw_error( "Invalid message type." ); + } + + function = [message, outdoor_only, sound, snippet, type, popup_msg]( const dialogue & d ) { + std::string translated_message; + if( snippet ) { + translated_message = SNIPPET.random_from_category( message ).value_or( translation() ).translated(); + } else { + translated_message = _( message ); + } + Character *target = d.alpha->get_character(); + if( !target ) { + return; + } + if( sound ) { + bool display = false; + map &here = get_map(); + if( !target->has_effect( effect_sleep ) && !target->is_deaf() ) { + if( !outdoor_only || here.get_abs_sub().z >= 0 ) { + display = true; + } else if( one_in( std::max( roll_remainder( 2.0f * here.get_abs_sub().z / + target->mutation_value( "hearing_modifier" ) ), 1 ) ) ) { + display = true; + } + } + if( !display ) { + return; + } + } + if( popup_msg ) { + popup( translated_message, PF_NONE ); + } else { + target->add_msg_if_player( type, translated_message ); + } + + }; +} + + +void talk_effect_fun_t::set_mod_pain( const JsonObject &jo, const std::string &member, + bool is_npc ) +{ + int amount = jo.get_int( member ); + function = [is_npc, amount]( const dialogue & d ) { + d.actor( is_npc )->mod_pain( amount ); + }; +} + +void talk_effect_fun_t::set_add_wet( const JsonObject &jo, const std::string &member, + bool is_npc ) +{ + int amount = jo.get_int( member ); + function = [is_npc, amount]( const dialogue & d ) { + Character *target = d.actor( is_npc )->get_character(); + if( target ) { + wet_character( *target, amount ); + } + }; +} + +void talk_effect_fun_t::set_sound_effect( const JsonObject &jo, const std::string &member ) +{ + std::string sound_effect = jo.get_string( member ); + const bool outdoor_event = jo.get_bool( "outdoor_event", false ); + function = [sound_effect, outdoor_event]( const dialogue & d ) { + map &here = get_map(); + + Character *target = d.alpha->get_character(); + if( target && !target->has_effect( effect_sleep ) && !target->is_deaf() ) { + if( !outdoor_event || here.get_abs_sub().z >= 0 ) { + sfx::play_variant_sound( "environment", sound_effect, 80, random_direction() ); + } else if( one_in( std::max( roll_remainder( 2.0f * here.get_abs_sub().z / + target->mutation_value( "hearing_modifier" ) ), 1 ) ) ) { + sfx::play_variant_sound( "environment", sound_effect, + ( 80 * target->mutation_value( "hearing_modifier" ) ), random_direction() ); + } + } + }; +} + void talk_effect_t::set_effect_consequence( const talk_effect_fun_t &fun, dialogue_consequence con ) { @@ -2298,6 +2409,18 @@ void talk_effect_t::parse_sub_effect( const JsonObject &jo ) } else if( jo.has_string( "npc_first_topic" ) ) { const std::string chat_topic = jo.get_string( "npc_first_topic" ); subeffect_fun.set_npc_first_topic( chat_topic ); + } else if( jo.has_string( "sound_effect" ) ) { + subeffect_fun.set_sound_effect( jo, "sound_effect" ); + } else if( jo.has_string( "message" ) ) { + subeffect_fun.set_message( jo, "message" ); + } else if( jo.has_int( "u_mod_pain" ) ) { + subeffect_fun.set_mod_pain( jo, "u_mod_pain", false ); + } else if( jo.has_int( "npc_mod_pain" ) ) { + subeffect_fun.set_mod_pain( jo, "npc_mod_pain", false ); + } else if( jo.has_int( "u_add_wet" ) ) { + subeffect_fun.set_add_wet( jo, "u_add_wet", false ); + } else if( jo.has_int( "npc_add_wet" ) ) { + subeffect_fun.set_add_wet( jo, "npc_add_wet", true ); } else { jo.throw_error( "invalid sub effect syntax: " + jo.str() ); } @@ -2384,6 +2507,7 @@ void talk_effect_t::parse_string_effect( const std::string &effect_id, const Jso WRAP( npc_die ), WRAP( npc_thankful ), WRAP( clear_overrides ), + WRAP( lightning ), WRAP( nothing ) #undef WRAP } diff --git a/src/npctalk.h b/src/npctalk.h index 4f02b0b3dee73..09746e814def4 100644 --- a/src/npctalk.h +++ b/src/npctalk.h @@ -68,6 +68,7 @@ void deny_train( npc & ); // p gets "asked_to_train" void deny_personal_info( npc & ); // p gets "asked_personal_info" void hostile( npc & ); // p turns hostile to u void flee( npc & ); +void lightning( npc &p ); void leave( npc & ); // p becomes indifferent void stop_following( npc & ); void stranger_neutral( npc & ); // p is now neutral towards you diff --git a/src/npctalk_funcs.cpp b/src/npctalk_funcs.cpp index ed10341c7511e..45f092e1610e9 100644 --- a/src/npctalk_funcs.cpp +++ b/src/npctalk_funcs.cpp @@ -801,6 +801,13 @@ void talk_function::flee( npc &p ) p.set_attitude( NPCATT_FLEE ); } +void talk_function::lightning( npc & ) +{ + if( get_player_character().posz() >= 0 ) { + get_weather().lightning_active = true; + } +} + void talk_function::leave( npc &p ) { add_msg( _( "%s leaves." ), p.name ); diff --git a/src/overmap_ui.cpp b/src/overmap_ui.cpp index 79c97b7e89cd6..7f294b6c5102d 100644 --- a/src/overmap_ui.cpp +++ b/src/overmap_ui.cpp @@ -220,8 +220,7 @@ static weather_type_id get_weather_at_point( const tripoint_abs_omt &pos ) // TODO: fix point types const tripoint abs_ms_pos = project_to( pos ).raw(); const auto &wgen = overmap_buffer.get_settings( pos ).weather; - const auto weather = wgen.get_weather_conditions( abs_ms_pos, calendar::turn, g->get_seed(), - g->weather.next_instance_allowed ); + const auto weather = wgen.get_weather_conditions( abs_ms_pos, calendar::turn, g->get_seed() ); iter = weather_cache.insert( std::make_pair( pos, weather ) ).first; } return iter->second; diff --git a/src/talker.h b/src/talker.h index 6d9baaab14cf0..c7f1655461fb9 100644 --- a/src/talker.h +++ b/src/talker.h @@ -314,5 +314,15 @@ class talker virtual bool is_safe() const { return true; } + virtual void mod_pain( int ) {} + virtual int pain_cur() const { + return 0; + } + virtual bool worn_with_flag( const flag_id & ) const { + return false; + } + virtual bool wielded_with_flag( const flag_id & ) const { + return false; + } }; #endif // CATA_SRC_TALKER_H diff --git a/src/talker_character.cpp b/src/talker_character.cpp index 449e405a8c1ab..ab6f12029ed57 100644 --- a/src/talker_character.cpp +++ b/src/talker_character.cpp @@ -292,3 +292,23 @@ void talker_character::shout( const std::string &speech, bool order ) { me_chr->shout( speech, order ); } +\ +int talker_character::pain_cur() const +{ + return me_chr->get_pain(); +} + +void talker_character::mod_pain( int amount ) +{ + me_chr->mod_pain( amount ); +} + +bool talker_character::worn_with_flag( const flag_id &flag ) const +{ + return me_chr->worn_with_flag( flag ); +} + +bool talker_character::wielded_with_flag( const flag_id &flag ) const +{ + return me_chr->weapon.has_flag( flag ); +} diff --git a/src/talker_character.h b/src/talker_character.h index 6364f02329648..bc0fb7f38a914 100644 --- a/src/talker_character.h +++ b/src/talker_character.h @@ -55,6 +55,7 @@ class talker_character: public talker int dex_cur() const override; int int_cur() const override; int per_cur() const override; + int pain_cur() const override; bool has_trait( const trait_id &trait_to_check ) const override; void set_mutation( const trait_id &new_trait ) override; void unset_mutation( const trait_id &old_trait ) override; @@ -108,6 +109,11 @@ class talker_character: public talker // speaking void shout( const std::string &speech = "", bool order = false ) override; + bool worn_with_flag( const flag_id &flag ) const override; + bool wielded_with_flag( const flag_id &flag ) const override; + + void mod_pain( int amount ) override; + protected: talker_character() = default; player *me_chr; diff --git a/src/weather.cpp b/src/weather.cpp index a4348ca4b75b6..ff04584a1674a 100644 --- a/src/weather.cpp +++ b/src/weather.cpp @@ -67,7 +67,7 @@ static const flag_id json_flag_SUN_GLASSES( "SUN_GLASSES" ); * @{ */ -static bool is_creature_outside( const Creature &target ) +bool is_creature_outside( const Creature &target ) { map &here = get_map(); return here.is_outside( point( target.posx(), target.posy() ) ) && here.get_abs_sub().z >= 0; @@ -169,7 +169,7 @@ weather_type_id current_weather( const tripoint &location, const time_point &t ) if( g->weather.weather_override != WEATHER_NULL ) { return g->weather.weather_override; } - return wgen.get_weather_conditions( location, t, g->get_seed(), g->weather.next_instance_allowed ); + return wgen.get_weather_conditions( location, t, g->get_seed() ); } ////// Funnels. @@ -401,10 +401,9 @@ static void fill_water_collectors( int mmPerHour, bool acid ) * @see map::decay_fields_and_scent * @see player::drench */ -void wet( Character &target, int amount ) +void wet_character( Character &target, int amount ) { - if( !is_creature_outside( target ) || - amount <= 0 || + if( amount <= 0 || target.has_trait( trait_FEATHERS ) || target.weapon.has_flag( json_flag_RAIN_PROTECT ) || ( !one_in( 50 ) && target.worn_with_flag( json_flag_RAINPROOF ) ) ) { @@ -469,7 +468,7 @@ void handle_weather_effects( const weather_type_id &w ) { //Possible TODO, make npc/monsters affected map &here = get_map(); - Character &player_character = get_player_character(); + Character &target = get_player_character(); if( w->rains && w->precip != precip_class::none ) { fill_water_collectors( precip_mm_per_hour( w->precip ), w->acidic ); @@ -486,129 +485,13 @@ void handle_weather_effects( const weather_type_id &w ) wetness = 60; } here.decay_fields_and_scent( decay_time ); - wet( player_character, wetness ); + // Coarse correction to get us back to previously intended soaking rate. + if( calendar::once_every( 6_seconds ) && is_creature_outside( target ) ) { + wet_character( target, wetness ); + } } glare( w ); g->weather.lightning_active = false; - - for( const weather_effect ¤t_effect : w->effects ) { - if( current_effect.must_be_outside && !is_creature_outside( player_character ) ) { - continue; - } - if( current_effect.time_between > 0_seconds && - !calendar::once_every( current_effect.time_between ) ) { - continue; - } - if( !one_in( current_effect.one_in_chance ) ) { - continue; - } - if( current_effect.lightning && here.get_abs_sub().z >= 0 ) { - g->weather.lightning_active = true; - } - if( current_effect.rain_proof ) { - int chance = 0; - if( w->precip <= precip_class::light ) { - chance = 2; - } else if( w->precip >= precip_class::heavy ) { - chance = 4; - } - if( player_character.weapon.has_flag( json_flag_RAIN_PROTECT ) && one_in( chance ) ) { - add_msg( _( "Your %s protects you from the weather." ), player_character.weapon.tname() ); - continue; - } else { - if( player_character.worn_with_flag( json_flag_RAINPROOF ) && one_in( chance * 2 ) ) { - add_msg( _( "Your clothing protects you from the weather." ) ); - continue; - } else { - bool has_helmet = false; - if( player_character.is_wearing_power_armor( &has_helmet ) && ( has_helmet || - one_in( chance * 2 ) ) ) { - add_msg( _( "Your power armor protects you from the weather." ) ); - continue; - } - } - } - } - if( player_character.get_pain() >= current_effect.pain_max ) { - continue; - } - - bool spawned = current_effect.spawns.empty(); - for( const spawn_type &spawn : current_effect.spawns ) { - monster target_monster; - if( spawn.target.is_empty() ) { - //grab a random nearby hostile creature to create a hallucination or copy of - Creature *copy = g->get_creature_if( [&spawn]( const Creature & critter ) -> bool { - bool not_self = get_player_character().pos() != critter.pos(); - bool in_range = std::round( rl_dist_exact( get_player_character().pos(), critter.pos() ) ) <= spawn.target_range; - bool valid_target = get_player_character().attitude_to( critter ) == Creature::Attitude::HOSTILE; - return not_self && in_range && valid_target; - } ); - if( copy == nullptr ) { - continue; - } - target_monster = *dynamic_cast( copy ); - } else { - target_monster = monster( spawn.target ); - } - - for( int i = 0; i < spawn.hallucination_count; i++ ) { - tripoint point; - if( g->find_nearby_spawn_point( player_character, target_monster.type->id, spawn.min_radius, - spawn.max_radius, point ) ) { - g->spawn_hallucination( point, target_monster.type->id ); - spawned = true; - } - } - for( int i = 0; i < spawn.real_count; i++ ) { - tripoint point; - if( g->find_nearby_spawn_point( player_character, target_monster.type->id, spawn.min_radius, - spawn.max_radius, point ) ) { - g->place_critter_at( target_monster.type->id, point ); - spawned = true; - } - } - } - if( !spawned ) { - continue; - } - for( const weather_field &field : current_effect.fields ) { - for( const tripoint &dest : get_map().points_in_radius( player_character.pos(), field.radius ) ) { - if( !field.outdoor_only || get_map().is_outside( dest ) ) { - get_map().add_field( dest, field.type, field.intensity, field.age ); - } - } - } - if( current_effect.effect_id.is_valid() ) { - if( current_effect.target_part.is_valid() ) { - player_character.add_effect( current_effect.effect_id, current_effect.effect_duration, - current_effect.target_part ); - } else { - player_character.add_effect( current_effect.effect_id, current_effect.effect_duration ); - } - } - if( current_effect.trait_id_to_add.is_valid() ) { - player_character.set_mutation( current_effect.trait_id_to_add ); - } - if( current_effect.trait_id_to_remove.is_valid() ) { - player_character.unset_mutation( current_effect.trait_id_to_remove ); - } - if( current_effect.damage.has_value() ) { - if( current_effect.target_part.is_valid() ) { - player_character.deal_damage( nullptr, current_effect.target_part, current_effect.damage.value() ); - } else { - for( const bodypart_id &bp : player_character.get_all_body_parts() ) { - player_character.deal_damage( nullptr, bp, current_effect.damage.value() ); - } - } - } - player_character.mod_healthy( current_effect.healthy ); - player_character.mod_rad( current_effect.radiation ); - wet( player_character, current_effect.wet ); - player_character.mod_pain( current_effect.pain ); - weather_sound( current_effect.sound_message, current_effect.sound_effect ); - player_character.add_msg_if_player( current_effect.message ); - } } static std::string to_string( const weekdays &d ) @@ -696,6 +579,7 @@ std::string weather_forecast( const point_abs_sm &abs_sm_pos ) // TODO: fix point types const tripoint abs_ms_pos = tripoint( project_to( abs_sm_pos ).raw(), 0 ); + w_point weatherPoint = *g->weather.weather_precise; // TODO: wind direction and speed const time_point last_hour = calendar::turn - ( calendar::turn - calendar::turn_zero ) % 1_hours; @@ -704,7 +588,8 @@ std::string weather_forecast( const point_abs_sm &abs_sm_pos ) const weather_generator wgen = get_weather().get_cur_weather_gen(); for( time_point i = last_hour + d * 12_hours; i < last_hour + ( d + 1 ) * 12_hours; i += 1_hours ) { w_point w = wgen.get_weather( abs_ms_pos, i, g->get_seed() ); - forecast = std::max( forecast, wgen.get_weather_conditions( w, g->weather.next_instance_allowed ) ); + *g->weather.weather_precise = w; + forecast = std::max( forecast, wgen.get_weather_conditions( w ) ); high = std::max( high, w.temperature ); low = std::min( low, w.temperature ); } @@ -729,6 +614,7 @@ std::string weather_forecast( const point_abs_sm &abs_sm_pos ) print_temperature( high ), print_temperature( low ) ); } + *g->weather.weather_precise = weatherPoint; return weather_report; } @@ -1058,13 +944,11 @@ void weather_manager::update_weather() g->get_seed() ); weather_type_id old_weather = weather_id; weather_id = weather_override == WEATHER_NULL ? - weather_gen.get_weather_conditions( w, next_instance_allowed ) + weather_gen.get_weather_conditions( w ) : weather_override; sfx::do_ambient(); temperature = w.temperature; lightning_active = false; - next_instance_allowed[weather_id] = calendar::turn + rng( weather_id->time_between_min, - weather_id->time_between_max ); nextweather = calendar::turn + rng( weather_id->duration_min, weather_id->duration_max ); map &here = get_map(); if( weather_id != old_weather && weather_id->dangerous && @@ -1084,6 +968,9 @@ void weather_manager::update_weather() } here.set_seen_cache_dirty( tripoint_zero ); } + if( weather_id != old_weather ) { + effect_on_conditions::process_reactivate(); + } } } diff --git a/src/weather.h b/src/weather.h index d63dc2e9cdf63..4e3a4c1803c8f 100644 --- a/src/weather.h +++ b/src/weather.h @@ -50,6 +50,7 @@ static constexpr int BODYTEMP_SCORCHING = 9500; #include class Character; +class Creature; class item; struct rl_vec2d; struct trap; @@ -82,7 +83,8 @@ struct weather_sum { float sunlight = 0.0f; int wind_amount = 0; }; - +bool is_creature_outside( const Creature &target ); +void wet_character( Character &target, int amount ); weather_type_id get_bad_weather(); std::string get_shortdirstring( int angle ); @@ -157,7 +159,6 @@ int incident_sunlight( const weather_type_id &wtype, const time_point &t = calendar::turn ); void weather_sound( const translation &sound_message, const std::string &sound_effect ); -void wet( Character &target, int amount ); class weather_manager { @@ -178,7 +179,6 @@ class weather_manager cata::optional wind_direction_override; cata::optional windspeed_override; weather_type_id weather_override; - std::map next_instance_allowed; // not only sets nextweather, but updates weather as well void set_nextweather( time_point t ); // The time at which weather will shift next. @@ -190,8 +190,6 @@ class weather_manager // Returns outdoor or indoor temperature of given location int get_temperature( const tripoint_abs_omt &location ); void clear_temp_cache(); - void on_load(); - static void serialize_all( JsonOut &json ); static void unserialize_all( JsonIn &jsin ); }; diff --git a/src/weather_gen.cpp b/src/weather_gen.cpp index 337ea17b9fe9a..bf2798df042f6 100644 --- a/src/weather_gen.cpp +++ b/src/weather_gen.cpp @@ -8,7 +8,11 @@ #include #include +#include "avatar.h" #include "cata_utility.h" +#include "condition.h" +#include "dialogue.h" +#include "game.h" #include "game_constants.h" #include "json.h" #include "math_defines.h" @@ -168,70 +172,37 @@ w_point weather_generator::get_weather( const tripoint &location, const time_poi } weather_type_id weather_generator::get_weather_conditions( const tripoint &location, - const time_point &t, unsigned seed, - std::map &next_instance_allowed ) const + const time_point &t, unsigned seed ) const { w_point w( get_weather( location, t, seed ) ); - weather_type_id wt = get_weather_conditions( w, next_instance_allowed ); + weather_type_id wt = get_weather_conditions( w ); return wt; } -weather_type_id weather_generator::get_weather_conditions( const w_point &w, - std::map &next_instance_allowed ) const +weather_type_id weather_generator::get_weather_conditions( const w_point & ) const { weather_type_id current_conditions = WEATHER_CLEAR; + dialogue d; + standard_npc default_npc( "Default" ); + d.alpha = get_talker_for( get_avatar() ); + d.beta = get_talker_for( default_npc ); for( const std::string &weather_type : weather_types ) { weather_type_id type = weather_type_id( weather_type ); - const weather_requirements &requires = type->requirements; - if( ( w.time < ( calendar::start_of_cataclysm + requires.time_passed_min ) ) || - ( requires.time_passed_max != 0_seconds && - ( w.time > ( calendar::start_of_cataclysm + requires.time_passed_max ) ) ) ) { - continue; - } - std::map::iterator instance = next_instance_allowed.find( type ); - if( instance != next_instance_allowed.end() && instance->second > calendar::turn ) { - continue; - } - - bool test_pressure = - requires.pressure_max > w.pressure && - requires.pressure_min < w.pressure; - bool test_humidity = - requires.humidity_max > w.humidity && - requires.humidity_min < w.humidity; - if( ( requires.humidity_and_pressure && !( test_pressure && test_humidity ) ) || - ( !requires.humidity_and_pressure && !( test_pressure || test_humidity ) ) ) { - continue; - } - - bool test_temperature = - requires.temperature_max > w.temperature && - requires.temperature_min < w.temperature; - bool test_windspeed = - requires.windpower_max > w.windpower && - requires.windpower_min < w.windpower; - if( !( test_temperature && test_windspeed ) ) { - continue; - } - - if( !requires.required_weathers.empty() ) { - if( std::find( requires.required_weathers.begin(), requires.required_weathers.end(), - current_conditions ) == requires.required_weathers.end() ) { - continue; + bool required_weather = type->required_weathers.empty(); + if( !required_weather ) { + for( const weather_type_id &weather : type->required_weathers ) { + if( weather == current_conditions ) { + required_weather = true; + break; + } } } - if( !( requires.time == weather_time_requirement_type::both || - ( requires.time == weather_time_requirement_type::day && is_day( calendar::turn ) ) || - ( requires.time == weather_time_requirement_type::night && !is_day( calendar::turn ) ) ) ) { + if( required_weather && type->condition( d ) ) { + current_conditions = type; continue; } - if( requires.one_in_chance != 0 && !one_in( requires.one_in_chance ) ) { - continue; - } - - current_conditions = type; } return current_conditions; } @@ -293,13 +264,13 @@ int weather_generator::get_water_temperature() const return water_temperature; } -void weather_generator::test_weather( unsigned seed, - std::map &next_instance_allowed ) const +void weather_generator::test_weather( unsigned seed ) const { // Outputs a Cata year's worth of weather data to a CSV file. // Usage: // weather_generator WEATHERGEN; // Instantiate the class. // WEATHERGEN.test_weather(); // Runs this test. + w_point weatherPoint = *g->weather.weather_precise; write_to_file( "weather.output", [&]( std::ostream & testfile ) { testfile << "|;year;season;day;hour;minute;temperature(F);humidity(%);pressure(mB);weatherdesc;windspeed(mph);winddirection" @@ -309,7 +280,8 @@ void weather_generator::test_weather( unsigned seed, const time_point end = begin + 2 * calendar::year_length(); for( time_point i = begin; i < end; i += 20_minutes ) { w_point w = get_weather( tripoint_zero, i, seed ); - weather_type_id conditions = get_weather_conditions( w, next_instance_allowed ); + weather_type_id conditions = get_weather_conditions( w ); + *g->weather.weather_precise = w; int year = to_turns( i - calendar::turn_zero ) / to_turns ( calendar::year_length() ) + 1; @@ -328,6 +300,7 @@ void weather_generator::test_weather( unsigned seed, } }, "weather test file" ); + *g->weather.weather_precise = weatherPoint; } weather_generator weather_generator::load( const JsonObject &jo ) diff --git a/src/weather_gen.h b/src/weather_gen.h index 972404d9da016..3f7baca8be077 100644 --- a/src/weather_gen.h +++ b/src/weather_gen.h @@ -55,15 +55,12 @@ class weather_generator * relative position (relative to the map you called getabs on). */ w_point get_weather( const tripoint &, const time_point &, unsigned ) const; - weather_type_id get_weather_conditions( const tripoint &, const time_point &, - unsigned seed, std::map &next_instance_allowed ) const; - weather_type_id get_weather_conditions( const w_point &, - std::map &next_instance_allowed ) const; + weather_type_id get_weather_conditions( const tripoint &, const time_point &, unsigned seed ) const; + weather_type_id get_weather_conditions( const w_point & ) const; int get_wind_direction( season_type ) const; int convert_winddir( int ) const; int get_water_temperature() const; - void test_weather( unsigned seed, - std::map &next_instance_allowed ) const; + void test_weather( unsigned seed ) const; double get_weather_temperature( const tripoint &, const time_point &, unsigned ) const; diff --git a/src/weather_type.cpp b/src/weather_type.cpp index 48a76f726e262..e48d9134024a5 100644 --- a/src/weather_type.cpp +++ b/src/weather_type.cpp @@ -4,6 +4,7 @@ #include #include "assign.h" +#include "condition.h" #include "debug.h" #include "generic_factory.h" #include "json.h" @@ -53,23 +54,6 @@ std::string enum_to_string( sun_intensity_type data ) abort(); } -template<> -std::string enum_to_string( weather_time_requirement_type data ) -{ - switch( data ) { - case weather_time_requirement_type::day: - return "day"; - case weather_time_requirement_type::night: - return "night"; - case weather_time_requirement_type::both: - return "both"; - case weather_time_requirement_type::last: - break; - } - debugmsg( "Invalid time_requirement_type" ); - abort(); -} - template<> std::string enum_to_string( weather_sound_category data ) { @@ -91,7 +75,7 @@ std::string enum_to_string( weather_sound_category data case weather_sound_category::last: break; } - debugmsg( "Invalid time_requirement_type" ); + debugmsg( "Invalid weather sound category." ); abort(); } @@ -117,42 +101,12 @@ void weather_type::finalize() void weather_type::check() const { - for( const weather_type_id &required : requirements.required_weathers ) { - if( !required.is_valid() ) { - debugmsg( "Required weather type %s does not exist.", required.c_str() ); + for( const auto &type : required_weathers ) { + if( !type.is_valid() ) { + debugmsg( "Weather type %s does not exist.", type.c_str() ); abort(); } } - for( const weather_effect &effect : effects ) { - if( !effect.effect_id.is_empty() && !effect.effect_id.is_valid() ) { - debugmsg( "Effect type %s does not exist.", effect.effect_id.c_str() ); - abort(); - } - if( !effect.trait_id_to_add.is_empty() && !effect.trait_id_to_add.is_valid() ) { - debugmsg( "Trait %s does not exist.", effect.trait_id_to_add.c_str() ); - abort(); - } - if( !effect.trait_id_to_remove.is_empty() && !effect.trait_id_to_remove.is_valid() ) { - debugmsg( "Trait %s does not exist.", effect.trait_id_to_remove.c_str() ); - abort(); - } - if( !effect.target_part.is_empty() && !effect.target_part.is_valid() ) { - debugmsg( "Target part %s does not exist.", effect.target_part.c_str() ); - abort(); - } - for( const spawn_type &spawn : effect.spawns ) { - if( !spawn.target.is_empty() && !spawn.target.is_valid() ) { - debugmsg( "Spawn target %s does not exist.", spawn.target.c_str() ); - abort(); - } - } - for( const weather_field &field : effect.fields ) { - if( !field.type.is_valid() ) { - debugmsg( "field type %s does not exist.", field.type.c_str() ); - abort(); - } - } - } } void weather_type::load( const JsonObject &jo, const std::string & ) @@ -182,61 +136,7 @@ void weather_type::load( const JsonObject &jo, const std::string & ) if( duration_min > duration_max ) { jo.throw_error( "duration_min must be less than or equal to duration_max" ); } - optional( jo, was_loaded, "time_between_min", time_between_min, 0_seconds ); - optional( jo, was_loaded, "time_between_max", time_between_max, 0_seconds ); - if( time_between_min > time_between_max ) { - jo.throw_error( "time_between_min must be less than or equal to time_between_max" ); - } - for( const JsonObject weather_effect_jo : jo.get_array( "effects" ) ) { - weather_effect effect; - - optional( weather_effect_jo, was_loaded, "message", effect.message ); - optional( weather_effect_jo, was_loaded, "sound_message", effect.sound_message ); - optional( weather_effect_jo, was_loaded, "sound_effect", effect.sound_effect, "" ); - mandatory( weather_effect_jo, was_loaded, "must_be_outside", effect.must_be_outside ); - optional( weather_effect_jo, was_loaded, "one_in_chance", effect.one_in_chance, -1 ); - optional( weather_effect_jo, was_loaded, "time_between", effect.time_between ); - optional( weather_effect_jo, was_loaded, "lightning", effect.lightning, false ); - optional( weather_effect_jo, was_loaded, "rain_proof", effect.rain_proof, false ); - optional( weather_effect_jo, was_loaded, "pain_max", effect.pain_max, INT_MAX ); - optional( weather_effect_jo, was_loaded, "pain", effect.pain, 0 ); - optional( weather_effect_jo, was_loaded, "wet", effect.wet, 0 ); - optional( weather_effect_jo, was_loaded, "radiation", effect.radiation, 0 ); - optional( weather_effect_jo, was_loaded, "healthy", effect.healthy, 0 ); - optional( weather_effect_jo, was_loaded, "effect_id", effect.effect_id ); - optional( weather_effect_jo, was_loaded, "effect_duration", effect.effect_duration ); - optional( weather_effect_jo, was_loaded, "trait_id_to_add", effect.trait_id_to_add ); - optional( weather_effect_jo, was_loaded, "trait_id_to_remove", effect.trait_id_to_remove ); - optional( weather_effect_jo, was_loaded, "target_part", effect.target_part ); - assign( weather_effect_jo, "damage", effect.damage ); - - for( const JsonObject field_jo : weather_effect_jo.get_array( "fields" ) ) { - weather_field new_field; - mandatory( field_jo, was_loaded, "type", new_field.type ); - mandatory( field_jo, was_loaded, "intensity", new_field.intensity ); - mandatory( field_jo, was_loaded, "age", new_field.age ); - optional( field_jo, was_loaded, "outdoor_only", new_field.outdoor_only, true ); - optional( field_jo, was_loaded, "radius", new_field.radius, 10000000 ); - - effect.fields.emplace_back( new_field ); - } - for( const JsonObject spawn_jo : weather_effect_jo.get_array( "spawns" ) ) { - spawn_type spawn; - mandatory( spawn_jo, was_loaded, "max_radius", spawn.max_radius ); - mandatory( spawn_jo, was_loaded, "min_radius", spawn.min_radius ); - if( spawn.min_radius > spawn.max_radius ) { - spawn_jo.throw_error( "min_radius must be less than or equal to max_radius" ); - } - optional( spawn_jo, was_loaded, "hallucination_count", spawn.hallucination_count, 0 ); - optional( spawn_jo, was_loaded, "real_count", spawn.real_count, 0 ); - optional( spawn_jo, was_loaded, "target", spawn.target ); - optional( spawn_jo, was_loaded, "target_range", spawn.target_range, 30 ); - - effect.spawns.emplace_back( spawn ); - } - effects.emplace_back( effect ); - } if( jo.has_member( "weather_animation" ) ) { JsonObject weather_animation_jo = jo.get_object( "weather_animation" ); mandatory( weather_animation_jo, was_loaded, "factor", weather_animation.factor ); @@ -246,35 +146,8 @@ void weather_type::load( const JsonObject &jo, const std::string & ) mandatory( weather_animation_jo, was_loaded, "sym", weather_animation.symbol, unicode_codepoint_from_symbol_reader ); } - - requirements = {}; - if( jo.has_member( "requirements" ) ) { - JsonObject weather_requires = jo.get_object( "requirements" ); - weather_requirements new_requires; - - optional( weather_requires, was_loaded, "pressure_min", new_requires.pressure_min, INT_MIN ); - optional( weather_requires, was_loaded, "pressure_max", new_requires.pressure_max, INT_MAX ); - optional( weather_requires, was_loaded, "humidity_min", new_requires.humidity_min, INT_MIN ); - optional( weather_requires, was_loaded, "humidity_max", new_requires.humidity_max, INT_MAX ); - optional( weather_requires, was_loaded, "temperature_min", new_requires.temperature_min, INT_MIN ); - optional( weather_requires, was_loaded, "temperature_max", new_requires.temperature_max, INT_MAX ); - optional( weather_requires, was_loaded, "windpower_min", new_requires.windpower_min, INT_MIN ); - optional( weather_requires, was_loaded, "windpower_max", new_requires.windpower_max, INT_MAX ); - optional( weather_requires, was_loaded, "humidity_and_pressure", new_requires.humidity_and_pressure, - true ); - optional( weather_requires, was_loaded, "time", new_requires.time, - weather_time_requirement_type::both ); - for( const std::string &required_weather : - weather_requires.get_string_array( "required_weathers" ) ) { - new_requires.required_weathers.push_back( weather_type_id( required_weather ) ); - } - optional( weather_requires, was_loaded, "time_passed_min", new_requires.time_passed_min, - 0_seconds ); - optional( weather_requires, was_loaded, "time_passed_max", new_requires.time_passed_max, - 0_seconds ); - optional( weather_requires, was_loaded, "one_in_chance", new_requires.one_in_chance, 0 ); - requirements = new_requires; - } + optional( jo, was_loaded, "required_weathers", required_weathers ); + read_condition( jo, "condition", condition, true ); } void weather_types::reset() diff --git a/src/weather_type.h b/src/weather_type.h index 0ca6d3de4fd83..d6658cf5e2a9e 100644 --- a/src/weather_type.h +++ b/src/weather_type.h @@ -13,6 +13,7 @@ #include "catacharset.h" #include "color.h" #include "damage.h" +#include "dialogue.h" #include "optional.h" #include "translations.h" #include "type_id.h" @@ -49,18 +50,7 @@ struct enum_traits { static constexpr sun_intensity_type last = sun_intensity_type::last; }; -enum class weather_time_requirement_type : int { - day, - night, - both, - last -}; -template<> -struct enum_traits { - static constexpr weather_time_requirement_type last = weather_time_requirement_type::last; -}; - -enum class weather_sound_category : int { +enum weather_sound_category : int { silent, drizzle, rainy, @@ -88,64 +78,6 @@ struct weather_animation_t { } }; -struct weather_requirements { - int windpower_min = INT_MIN; - int windpower_max = INT_MAX; - int temperature_min = INT_MIN; - int temperature_max = INT_MAX; - int pressure_min = INT_MIN; - int pressure_max = INT_MAX; - int humidity_min = INT_MIN; - int humidity_max = INT_MAX; - bool humidity_and_pressure = true; - weather_time_requirement_type time = weather_time_requirement_type::both; - std::vector required_weathers{}; - time_duration time_passed_min = 0_turns; - time_duration time_passed_max = 0_turns; - int one_in_chance = 0; -}; - -struct weather_field { - field_type_str_id type; - int intensity = 0; - time_duration age = 0_turns; - int radius = 0; - bool outdoor_only = false; -}; - -struct spawn_type { - mtype_id target; - int target_range = 0; - int hallucination_count = 0; - int real_count = 0; - int min_radius = 0; - int max_radius = 0; -}; - -struct weather_effect { - int one_in_chance = 0; - time_duration time_between = 0_turns; - translation message; - bool must_be_outside = false; - translation sound_message; - std::string sound_effect; - bool lightning = false; - bool rain_proof = false; - int pain = 0; - int pain_max = 0; - int wet = 0; - int radiation = 0; - int healthy = 0; - efftype_id effect_id; - time_duration effect_duration = 0_turns; - trait_id trait_id_to_add; - trait_id trait_id_to_remove; - bodypart_str_id target_part; - cata::optional damage; - std::vector spawns; - std::vector fields; -}; - struct weather_type { public: friend class generic_factory; @@ -175,8 +107,6 @@ struct weather_type { bool rains = false; // Whether said precipitation is acidic. bool acidic = false; - // vector for weather effects. - std::vector effects{}; // string for tiles animation std::string tiles_animation; // Information for weather animations @@ -186,11 +116,10 @@ struct weather_type { // strength of the sun sun_intensity_type sun_intensity = sun_intensity_type::none; // when this weather should happen - weather_requirements requirements; + std::function condition; + std::vector required_weathers; time_duration duration_min = 0_turns; time_duration duration_max = 0_turns; - time_duration time_between_min = 0_turns; - time_duration time_between_max = 0_turns; void load( const JsonObject &jo, const std::string &src ); void finalize(); void check() const; diff --git a/tests/weather_test.cpp b/tests/weather_test.cpp index 3b2b4bc3d28dd..30ab91c53bbbe 100644 --- a/tests/weather_test.cpp +++ b/tests/weather_test.cpp @@ -72,10 +72,10 @@ TEST_CASE( "weather realism" ) int minute = to_minutes( time_past_midnight( i ) ); temperature[day][minute] = w.temperature; int hour = to_hours( time_past_new_year( i ) ); - std::map next_instance_allowed; + *get_weather().weather_precise = w; hourly_precip[hour] += precip_mm_per_hour( - wgen.get_weather_conditions( w, next_instance_allowed )->precip ) + wgen.get_weather_conditions( w )->precip ) / 60; } From 07635f0547a1d7fafa48d2741cf8bd38390175e0 Mon Sep 17 00:00:00 2001 From: Dekker3D Date: Tue, 23 Mar 2021 12:43:58 +0100 Subject: [PATCH 331/453] Material volume fixes (#48194) --- data/json/items/resources/plastic.json | 12 ++++-- data/json/items/resources/tailoring.json | 49 ++++++++++++++++-------- 2 files changed, 41 insertions(+), 20 deletions(-) diff --git a/data/json/items/resources/plastic.json b/data/json/items/resources/plastic.json index c1f69d6d06372..d1cc9c7d0da83 100644 --- a/data/json/items/resources/plastic.json +++ b/data/json/items/resources/plastic.json @@ -6,7 +6,8 @@ "name": { "str": "plastic chunk" }, "description": "This is a piece of plastic. It could be used to fabricate, repair, or reinforce plastic items.", "weight": "50 g", - "volume": "250 ml", + "volume": "95 ml", + "//": "Based on a density around 1.05 grams/mL, like PLA and ABS, + 100% for being rigid and probably oddly-shaped.", "price": 0, "price_postapoc": 10, "material": [ "plastic" ], @@ -21,7 +22,8 @@ "name": { "str_sp": "synthetic fabric" }, "description": "This is small bolt of synthetic fabric. Unlike you and other natural materials, it won't degrade much with age. Maybe that's less of a bad thing now.", "weight": "55 g", - "volume": "250 ml", + "volume": "50 ml", + "//": "Density of 1.15 grams per mL", "price": 0, "price_postapoc": 10, "material": [ "nylon" ], @@ -36,7 +38,8 @@ "name": { "str": "Lycra patch", "str_pl": "Lycra patches" }, "description": "This is a small bolt of a synthetic fabric blended with stretchy Lycra fibers. It could be used to make flexible yet strong clothing. Stylish, but bad for the environment; at least you're recycling it.", "weight": "87 g", - "volume": "250 ml", + "volume": "70 ml", + "//": "Density of 1.21-1.35 grams per mL, using 1.28", "price": 0, "price_postapoc": 10, "material": [ "lycra" ], @@ -51,7 +54,8 @@ "name": { "str": "plastic sheet" }, "description": "This is a large sheet of heavy flexible plastic, the sort that might have been used for commercial wrapping or for weather-sealing a home.", "weight": "1000 g", - "volume": "2 L", + "volume": "950 ml", + "//": "Based on a density around 1.05 grams/mL, like PLA and ABS", "price": 0, "price_postapoc": 25, "material": [ "plastic" ], diff --git a/data/json/items/resources/tailoring.json b/data/json/items/resources/tailoring.json index dbc468911f73c..a86c2a7508193 100644 --- a/data/json/items/resources/tailoring.json +++ b/data/json/items/resources/tailoring.json @@ -116,7 +116,8 @@ "name": { "str": "cotton sheet" }, "description": "A sheet of cotton fabric, suitable for making clothing.", "weight": "5 g", - "volume": "300 ml", + "volume": "3 ml", + "//": "Density of 1.55 grams per mL", "price": 1000, "price_postapoc": 100, "material": [ "cotton" ], @@ -132,7 +133,8 @@ "name": { "str_sp": "patchwork cotton clothing parts" }, "description": "A selection of various clothing parts, sewn together from cotton patches in a patchwork fashion. Suitable for making most clothing, though it's much less time-efficient than if using proper material sheets.", "weight": "100 g", - "volume": "60 ml", + "volume": "65 ml", + "//": "Density of 1.55 grams per mL", "price": 200, "price_postapoc": 50, "count": 1 @@ -144,7 +146,8 @@ "name": { "str": "faux fur sheet" }, "description": "A sheet of fake synthetic colorful fur, suitable for making clothing.", "weight": "10 g", - "volume": "4500 ml", + "volume": "25 ml", + "//": "Guesstimated density of 0.44 grams per mL based on felt", "price": 5000, "price_postapoc": 100, "material": [ "faux_fur" ], @@ -160,7 +163,8 @@ "name": { "str_sp": "patchwork faux fur clothing parts" }, "description": "A selection of various clothing parts, sewn together from faux fur patches in a patchwork fashion. Suitable for making most clothing, though it's much less time-efficient than if using proper material sheets.", "weight": "200 g", - "volume": "900 ml", + "volume": "450 ml", + "//": "Guesstimated density of 0.44 grams per mL based on felt", "price": 1000, "price_postapoc": 50, "count": 1 @@ -172,7 +176,8 @@ "name": { "str": "felt sheet" }, "description": "A sheet of felt, suitable for making clothing.", "weight": "8 g", - "volume": "1800 ml", + "volume": "20 ml", + "//": "Density of 0.44 grams per mL", "price": 2500, "price_postapoc": 250, "material": [ "wool" ], @@ -189,6 +194,7 @@ "description": "A selection of various clothing parts, sewn together from felt patches in a patchwork fashion. Suitable for making most clothing, though it's much less time-efficient than if using proper material sheets.", "weight": "160 g", "volume": "360 ml", + "//": "Density of 0.44 grams per mL", "price": 500, "price_postapoc": 100, "count": 1 @@ -200,7 +206,8 @@ "name": { "str": "Kevlar sheet" }, "description": "A sheet of Kevlar synthetic fabric, suitable for making cut-resistant, durable clothing. In this form, unlike rigid plates, it can be stitched.", "weight": "5 g", - "volume": "300 ml", + "volume": "4 ml", + "//": "Density of 1.4 grams per mL", "price": 900, "price_postapoc": 500, "material": [ "kevlar" ], @@ -216,7 +223,8 @@ "name": { "str": "Lycra sheet" }, "description": "A sheet of synthetic fabric blended with stretchy Lycra fibers, suitable for making flexible yet strong clothing.", "weight": "3 g", - "volume": "300 ml", + "volume": "2 ml", + "//": "Density of 1.21-1.35 grams per mL, using 1.28", "price": 5000, "price_postapoc": 100, "material": [ "lycra" ], @@ -232,7 +240,8 @@ "name": { "str": "layered kevlar panel" }, "description": "This is a small 16-layer thick Kevlar panel. It could be used to repair armor made of Kevlar.", "weight": "80 g", - "volume": "600 ml", + "volume": "65 ml", + "//": "Density of 1.4 grams per mL; volume increased ~5% to account for some rigidity", "price": 15000, "material": [ "kevlar_layered" ], "flags": [ "NO_SALVAGE" ], @@ -246,7 +255,8 @@ "name": { "str": "rigid kevlar plate" }, "description": "This is a compressed panel of Kevlar treated with epoxy or other adhesive. It could be used to repair items made of Kevlar.", "weight": "300 g", - "volume": "250 ml", + "volume": "235 ml", + "//": "Density of 1.4 grams per mL + 10% for being rigid and possibly oddly-shaped", "price": 1000, "material": [ "kevlar_rigid" ], "flags": [ "NO_SALVAGE" ], @@ -260,7 +270,8 @@ "name": { "str_sp": "patchwork Lycra clothing parts" }, "description": "A selection of various clothing parts, sewn together from Lycra patches in a patchwork fashion. Suitable for making most clothing, though it's much less time-efficient than if using proper material sheets.", "weight": "60 g", - "volume": "60 ml", + "volume": "45 ml", + "//": "Density of 1.21-1.35 grams per mL, using 1.28", "price": 1000, "price_postapoc": 50, "count": 1 @@ -272,7 +283,8 @@ "name": { "str": "neoprene sheet" }, "description": "A sheet of neoprene, a synthetic rubber, suitable for making underwater gear.", "weight": "6 g", - "volume": "300 ml", + "volume": "5 ml", + "//": "Density of 1.23 grams per mL", "price": 5000, "price_postapoc": 100, "material": [ "neoprene" ], @@ -288,7 +300,8 @@ "name": { "str_sp": "patchwork neoprene clothing parts" }, "description": "A selection of various clothing parts, sewn together from neoprene patches in a patchwork fashion, with waterproofed seams. Suitable for making most clothing, though it's much less time-efficient than if using proper material sheets.", "weight": "120 g", - "volume": "60 ml", + "volume": "100 ml", + "//": "Density of 1.23 grams per mL", "price": 1000, "price_postapoc": 50, "count": 1 @@ -300,7 +313,8 @@ "name": { "str": "Nomex sheet" }, "description": "A sheet of Nomex synthetic fabric, suitable for making heat-resistant clothing.", "weight": "5 g", - "volume": "300 ml", + "volume": "7 ml", + "//": "Density of 0.72-1.1 grams per mL, using ~0.72 to account for possible unwieldiness", "price": 15000, "price_postapoc": 250, "material": [ "nomex" ], @@ -316,7 +330,8 @@ "name": { "str_sp": "patchwork Nomex clothing parts" }, "description": "A selection of various clothing parts, sewn together with Nomex thread from Nomex patches in a patchwork fashion. Suitable for making most clothing, though it's much less time-efficient than if using proper material sheets.", "weight": "100 g", - "volume": "60 ml", + "volume": "110 ml", + "//": "Density of 0.72-1.1 grams per mL, using 0.91", "price": 3000, "price_postapoc": 50, "count": 1 @@ -328,7 +343,8 @@ "name": { "str": "synthetic fabric sheet" }, "description": "A sheet of synthetic fabric, suitable for making clothing.", "weight": "3 g", - "volume": "300 ml", + "volume": "3 ml", + "//": "Density of 1.15 grams per mL", "price": 5000, "price_postapoc": 100, "material": [ "nylon" ], @@ -344,7 +360,8 @@ "name": { "str_sp": "patchwork synthetic fabric clothing parts" }, "description": "A selection of various clothing parts, sewn together from synthetic fabric patches in a patchwork fashion. Suitable for making most clothing, though it's much less time-efficient than if using proper material sheets.", "weight": "60 g", - "volume": "60 ml", + "volume": "50 ml", + "//": "Density of 1.15 grams per mL", "price": 1000, "price_postapoc": 50, "count": 1 From 26fd55bcbe6bd54796f6b111ddf401fdc2a17f9e Mon Sep 17 00:00:00 2001 From: Saint-of-Grey <42332565+Saint-of-Grey@users.noreply.github.com> Date: Sun, 28 Mar 2021 00:47:10 -0700 Subject: [PATCH 332/453] Update description of LEAVES mutation line (#48215) --- data/json/mutations/mutations.json | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/data/json/mutations/mutations.json b/data/json/mutations/mutations.json index d1ed05dbb5ee6..10b1ad3e70c90 100644 --- a/data/json/mutations/mutations.json +++ b/data/json/mutations/mutations.json @@ -2526,7 +2526,7 @@ "points": 3, "visibility": 8, "ugliness": 3, - "description": "All the hair on your body has turned to long, grass-like leaves. Apart from being physically striking, these provide you with a minor amount of nutrition while in sunlight when your head is uncovered. Slightly reduces wet effects.", + "description": "All the hair on your body has turned to long, grass-like leaves. Apart from being physically striking, these provide you with a minor amount of nutrients while in sunlight when your head is uncovered. Slightly reduces wet effects.", "prereqs": [ "PLANTSKIN", "BARK" ], "changes_to": [ "LEAVES2" ], "category": [ "PLANT", "ELFA" ], @@ -2539,7 +2539,7 @@ "points": 6, "visibility": 10, "ugliness": 5, - "description": "Your leaves have grown in size and prominence, with additional leaves sprouting along your arms. While your arms and head are uncovered, you will photosynthesize additional nutrients while in sunlight. Reduces wet effects.", + "description": "Your leaves have grown in size and prominence, with additional leaves sprouting along your arms. While your arms and head are uncovered, you will photosynthesize nutrients while in sunlight. Reduces wet effects.", "prereqs": [ "LEAVES" ], "prereqs2": [ "TRANSPIRATION" ], "threshreq": [ "THRESH_PLANT" ], @@ -2555,7 +2555,7 @@ "points": 9, "visibility": 12, "ugliness": 6, - "description": "Your leaves are vibrant, large, and green, and have become a major source of nutrition for your body. Whenever your arms and head are uncovered you will gain a large amount of nutrition by standing in the sunlight. Reduces wet effects.", + "description": "Your leaves are vibrant, large, and green, and have become a major source of nutrients for your body. Whenever your arms and head are uncovered you will gain a large amount of nutrients by standing in the sunlight. Reduces wet effects.", "prereqs": [ "LEAVES2" ], "prereqs2": [ "TRANSPIRATION" ], "threshreq": [ "THRESH_PLANT" ], @@ -3165,7 +3165,7 @@ "points": -3, "visibility": 5, "ugliness": 9, - "description": "You prefer to sustain yourself using your roots and direct nutrient extraction/synthesis. You can still consume 'food', though, if you have to: you merely prefer it aged a little.", + "description": "You prefer to sustain your nutritional needs using your roots and direct nutrient extraction/synthesis. Your human parts still need the raw caloric bulk of 'food' to keep them going, though, and you handle it a lot easier if it's had time to… age a little.", "prereqs": [ "ROOTS2" ], "prereqs2": [ "LEAVES" ], "threshreq": [ "THRESH_PLANT" ], From 974900393de8de8bd88314a0c0a64f1c83df2980 Mon Sep 17 00:00:00 2001 From: Mark Langsdorf Date: Wed, 31 Mar 2021 02:09:51 -0500 Subject: [PATCH 333/453] monsters: Monsters on patrol (#48155) * mapgen: clean up jmapgen_monster formatting Add some whitespace and relocate some single line comments so the jmapgen_monster class looks nice on a 100 character wide screen. * monsters: pass a patrol route to a monster Add the ability to define a patrol route when placing a monster. The patrol route is defined as a series of relative mapsquare points to the original overmap terrain tile's (0,0) mapsquare and is part of the "spawn_data" structure. Patrol routes and progress along the route are saved as part of the monster's data structure. Monsters on a patrol route move on the patrol if they have nothing better to do: patrol movement takes precedence over wandering and stabling, but any valid target overrides the patrol. Monsters on a patrol will move to the next patrol point in the list. As a work-around for impassible destination points, patrol points are considered reached when the monster gets within 2 tiles of them. * monsters: document spawn_data and add patrol in mapgen.doc Document the existing spawn_data field and its ammo subfield, and add the new patrol subfield. patrol is a list of points that the monster will move between, when it would otherwise move idly. --- doc/MAPGEN.md | 26 ++++++++++++++++++++++++++ src/map.cpp | 3 +++ src/mapgen.cpp | 23 ++++++++++++++++++----- src/mapgen.h | 1 + src/monmove.cpp | 15 +++++++++++++-- src/monster.cpp | 10 ++++++++++ src/monster.h | 5 +++++ src/savegame_json.cpp | 8 ++++++++ 8 files changed, 84 insertions(+), 7 deletions(-) diff --git a/doc/MAPGEN.md b/doc/MAPGEN.md index 0724a929dc7f0..bb44511583410 100644 --- a/doc/MAPGEN.md +++ b/doc/MAPGEN.md @@ -543,6 +543,7 @@ Value: `[ array of {objects} ]: [ { "monster": ... } ]` | friendly | Set true to make the monster friendly. Default false. | name | Extra name to display on the monster. | target | Set to true to make this into mission target. Only works when the monster is spawned from a mission. +| spawn_data | An optional object that contains additional details for spawning the monster. Note that high spawn density game setting can cause extra monsters to spawn when `monster` is used. When `group` is used only one monster will spawn. @@ -572,6 +573,31 @@ Example: This places "mon_secubot" at random coordinate (7-18, 7-18). The monster is placed with 30% probability. The placement is repeated by random number of times `[1-3]`. The monster will spawn with 20-30 5.56x45mm rounds. +### "spawn_data" for monsters +This optional object can have two fields: +| Field | Description +| --- | --- +| ammo | A list of objects, each of which has an `"ammo_id"` field and a `"qty"` list of two integers. The monster will spawn with items of "ammo_id", with at least the first number in the "qty" and no more than the second. +| patrol | A list of objects, each of which has an `"x"` field and a `"y"` field. Either value can be a range or a single number. The x,y co-ordinates define a patrol point as an relative mapsquare point offset from the (0, 0) local mapsquare of the overmap terrain tile that the monster spawns in. Patrol points are converted to absolute mapqaure tripoints inside the monster generator. + +Monsters with a patrol point list will move to each patrol point, in order, whenever they have no more pressing action to take on their turn. Upon reaching the last point in the patrol point list, the monster will continue on to the first point in the list. + +Example: +```json +"place_monster": [ + { "monster": "mon_zombie", "x": 12, "y": 12, "spawn_data": { "patrol": [ { "x": 12, "y": 12 } ] } } +] +``` + +This places a "mon_zombie" at (12, 12). The zombie can move freely to chase after enemies, but will always return to the (12, 12) position if it has nothing else to do. + +Example 2: +```json +"place_monster": [ + { "monster": "mon_secubot", "x": 12, "y": 12, "spawn_data": { "ammo": [ { "ammo_id": "556", "qty": [ 20, 30 ] } ], "patrol": [ { "x": -23, "y": -23 }, { "x": 47, "y": -23 }, { "x": 47, "y": 47 }, { "x": 47, "y": -23 } ] } } +] +``` +This places a "mon_secubot" at (12,12). It will patrol the four outmost concerns of the diagonally adjacent overmap terrain tiles in a box pattern. ## Spawn specific items with a "place_item" array **optional** A list of *specific* things to add. WIP: Monsters and vehicles will be here too diff --git a/src/map.cpp b/src/map.cpp index 6549a3c0a099b..e8d4e594c8264 100644 --- a/src/map.cpp +++ b/src/map.cpp @@ -7598,6 +7598,9 @@ void map::spawn_monsters_submap( const tripoint &gp, bool ignore_sight ) const auto place_it = [&]( const tripoint & p ) { monster *const placed = g->place_critter_at( make_shared_fast( tmp ), p ); + if( !i.data.patrol_points_rel_ms.empty() ) { + placed->set_patrol_route( i.data.patrol_points_rel_ms ); + } if( placed ) { placed->on_load(); } diff --git a/src/mapgen.cpp b/src/mapgen.cpp index 03646c4ae5e30..664aada2e175b 100644 --- a/src/mapgen.cpp +++ b/src/mapgen.cpp @@ -1278,7 +1278,8 @@ class jmapgen_monster : public jmapgen_piece chance( jsi, "chance", 100, 100 ) , pack_size( jsi, "pack_size", 1, 1 ) , one_or_none( jsi.get_bool( "one_or_none", - !( jsi.has_member( "repeat" ) || jsi.has_member( "pack_size" ) ) ) ) + !( jsi.has_member( "repeat" ) || + jsi.has_member( "pack_size" ) ) ) ) , friendly( jsi.get_bool( "friendly", false ) ) , name( jsi.get_string( "name", "NONE" ) ) , target( jsi.get_bool( "target", false ) ) { @@ -1319,7 +1320,16 @@ class jmapgen_monster : public jmapgen_piece if( sd.has_array( "ammo" ) ) { const JsonArray &ammos = sd.get_array( "ammo" ); for( const JsonObject adata : ammos ) { - data.ammo.emplace( itype_id( adata.get_string( "ammo_id" ) ), jmapgen_int( adata, "qty" ) ); + data.ammo.emplace( itype_id( adata.get_string( "ammo_id" ) ), + jmapgen_int( adata, "qty" ) ); + } + } + if( sd.has_array( "patrol" ) ) { + const JsonArray &patrol_pts = sd.get_array( "patrol" ); + for( const JsonObject p_pt : patrol_pts ) { + jmapgen_int ptx = jmapgen_int( p_pt, "x" ); + jmapgen_int pty = jmapgen_int( p_pt, "y" ); + data.patrol_points_rel_ms.push_back( point( ptx.get(), pty.get() ) ); } } } @@ -1329,7 +1339,8 @@ class jmapgen_monster : public jmapgen_piece int raw_odds = chance.get(); - // Handle spawn density: Increase odds, but don't let the odds of absence go below half the odds at density 1. + // Handle spawn density: Increase odds, but don't let the odds of absence go below + // half the odds at density 1. // Instead, apply a multiplier to the number of monsters for really high densities. // For example, a 50% chance at spawn density 4 becomes a 75% chance of ~2.7 monsters. int odds_after_density = raw_odds * get_option( "SPAWN_DENSITY" ); @@ -1347,10 +1358,12 @@ class jmapgen_monster : public jmapgen_piece int spawn_count = roll_remainder( density_multiplier ); - if( one_or_none ) { // don't let high spawn density alone cause more than 1 to spawn. + // don't let high spawn density alone cause more than 1 to spawn. + if( one_or_none ) { spawn_count = std::min( spawn_count, 1 ); } - if( raw_odds == 100 ) { // don't spawn less than 1 if odds were 100%, even with low spawn density. + // don't spawn less than 1 if odds were 100%, even with low spawn density. + if( raw_odds == 100 ) { spawn_count = std::max( spawn_count, 1 ); } else { if( !x_in_y( odds_after_density, 100 ) ) { diff --git a/src/mapgen.h b/src/mapgen.h index 7767c4ddc683a..6a1b0b4cbcb70 100644 --- a/src/mapgen.h +++ b/src/mapgen.h @@ -130,6 +130,7 @@ struct jmapgen_setmap { struct spawn_data { std::map ammo; + std::vector patrol_points_rel_ms; }; /** diff --git a/src/monmove.cpp b/src/monmove.cpp index f6e9f57d51bdc..21644a2101bb8 100644 --- a/src/monmove.cpp +++ b/src/monmove.cpp @@ -77,7 +77,7 @@ static constexpr int MONSTER_FOLLOW_DIST = 8; bool monster::wander() { - return ( goal == pos() ); + return ( goal == pos() && patrol_route_abs_ms.empty() ); } bool monster::is_immune_field( const field_type_id &fid ) const @@ -619,6 +619,17 @@ void monster::plan() anger += 10 - static_cast( hp_per / 10 ); } } + } else if( !patrol_route_abs_ms.empty() ) { + // If we have a patrol route and no target, find the current step on the route + tripoint next_stop_loc_ms = here.getlocal( patrol_route_abs_ms.at( next_patrol_point ) ); + + // if there is more than one patrol point, advance to the next one if we're almost there + // this handles impassable obstancles but patrollers can still get stuck + if( ( patrol_route_abs_ms.size() > 1 ) && rl_dist( next_stop_loc_ms, pos() ) < 2 ) { + next_patrol_point = ( next_patrol_point + 1 ) % patrol_route_abs_ms.size(); + next_stop_loc_ms = here.getlocal( patrol_route_abs_ms.at( next_patrol_point ) ); + } + set_dest( next_stop_loc_ms ); } else if( friendly > 0 && one_in( 3 ) ) { // Grow restless with no targets friendly--; @@ -841,7 +852,7 @@ void monster::move() } } - if( current_attitude == MATT_IGNORE || + if( ( current_attitude == MATT_IGNORE && patrol_route_abs_ms.empty() ) || ( current_attitude == MATT_FOLLOW && rl_dist( pos(), goal ) <= MONSTER_FOLLOW_DIST ) ) { moves = 0; stumble(); diff --git a/src/monster.cpp b/src/monster.cpp index edca5c9df481b..991485db63c6b 100644 --- a/src/monster.cpp +++ b/src/monster.cpp @@ -1076,6 +1076,16 @@ void monster::set_goal( const tripoint &p ) goal = p; } +void monster::set_patrol_route( const std::vector &patrol_pts_rel_ms ) +{ + map &here = get_map(); + tripoint base_abs_ms( real_coords( here.getabs( pos().xy() ) ).begin_om_pos(), posz() ); + for( const point &patrol_pt : patrol_pts_rel_ms ) { + patrol_route_abs_ms.push_back( base_abs_ms + patrol_pt ); + } + next_patrol_point = 0; +} + void monster::shift( const point &sm_shift ) { const point ms_shift = sm_to_ms_copy( sm_shift ); diff --git a/src/monster.h b/src/monster.h index 07450a8c51438..0297d4b3e4322 100644 --- a/src/monster.h +++ b/src/monster.h @@ -178,6 +178,7 @@ class monster : public Creature // Movement void shift( const point &sm_shift ); // Shifts the monster to the appropriate submap void set_goal( const tripoint &p ); + void set_patrol_route( const std::vector &patrol_pts_rel_ms ); // Updates current pos AND our plans bool wander(); // Returns true if we have no plans @@ -572,6 +573,10 @@ class monster : public Creature monster_horde_attraction horde_attraction = MHA_NULL; /** Found path. Note: Not used by monsters that don't pathfind! **/ std::vector path; + /** patrol points for monsters that can pathfind and have a patrol route! **/ + std::vector patrol_route_abs_ms; + int next_patrol_point = -1; + std::bitset effect_cache; cata::optional summon_time_limit = cata::nullopt; int turns_since_target = 0; diff --git a/src/savegame_json.cpp b/src/savegame_json.cpp index 0230396e9c70a..fa9df07486e89 100644 --- a/src/savegame_json.cpp +++ b/src/savegame_json.cpp @@ -2100,6 +2100,10 @@ void monster::load( const JsonObject &data ) if( data.read( "wandz", wander_pos.z ) ) { wander_pos.z = position.z; } + if( data.has_int( "next_patrol_point" ) ) { + data.read( "next_patrol_point", next_patrol_point ); + data.read( "patrol_route", patrol_route_abs_ms ); + } if( data.has_object( "tied_item" ) ) { JsonIn *tied_item_json = data.get_raw( "tied_item" ); item newitem; @@ -2251,6 +2255,10 @@ void monster::store( JsonOut &json ) const json.member( "wandy", wander_pos.y ); json.member( "wandz", wander_pos.z ); json.member( "wandf", wandf ); + if( !patrol_route_abs_ms.empty() ) { + json.member( "patrol_route", patrol_route_abs_ms ); + json.member( "next_patrol_point", next_patrol_point ); + } json.member( "hp", hp ); json.member( "special_attacks", special_attacks ); json.member( "friendly", friendly ); From 18a05ed90e0d303668c6532b27cf303b74bad59b Mon Sep 17 00:00:00 2001 From: zeropol Date: Wed, 31 Mar 2021 09:51:56 +0200 Subject: [PATCH 334/453] Make gym furniture constructible (#48271) --- data/json/construction.json | 45 +++++++++++++++++++++++++++++++ data/json/construction_group.json | 15 +++++++++++ 2 files changed, 60 insertions(+) diff --git a/data/json/construction.json b/data/json/construction.json index 2241de455e644..947fc9a81384b 100644 --- a/data/json/construction.json +++ b/data/json/construction.json @@ -4276,6 +4276,51 @@ "pre_terrain": "t_railroad_rubble", "post_terrain": "t_dirt" }, + { + "type": "construction", + "id": "constr_exercise_machine", + "group": "build_exercise_machine", + "category": "FURN", + "required_skills": [ [ "fabrication", 3 ] ], + "time": "180 m", + "qualities": [ [ { "id": "HAMMER", "level": 2 } ], [ { "id": "SCREW", "level": 1 } ] ], + "components": [ [ [ "pipe", 1 ] ], [ [ "steel_chunk", 1 ] ], [ [ "scrap", 6 ] ], [ [ "lead", 2000 ] ] ], + "pre_special": "check_empty", + "post_terrain": "f_exercise" + }, + { + "type": "construction", + "id": "constr_ergometer_mechanical", + "group": "build_ergometer_mechanical", + "category": "FURN", + "required_skills": [ [ "fabrication", 4 ] ], + "time": "240 m", + "qualities": [ [ { "id": "HAMMER", "level": 2 } ], [ { "id": "SCREW", "level": 1 } ], [ { "id": "WRENCH", "level": 1 } ] ], + "components": [ + [ [ "foot_crank", 1 ] ], + [ [ "plastic_chunk", 10 ] ], + [ [ "scrap", 4 ] ], + [ [ "chain", 1 ] ], + [ [ "pipe", 5 ] ], + [ [ "saddle", 1 ] ], + [ [ "wheel_small", 1 ] ], + [ [ "nail", 8 ] ] + ], + "pre_special": "check_empty", + "post_terrain": "f_ergometer_mechanical" + }, + { + "type": "construction", + "id": "constr_treadmill_mechanical", + "group": "build_treadmill_mechanical", + "category": "FURN", + "required_skills": [ [ "fabrication", 4 ] ], + "time": "240 m", + "qualities": [ [ { "id": "HAMMER", "level": 2 } ], [ { "id": "SCREW", "level": 1 } ], [ { "id": "WRENCH", "level": 1 } ] ], + "components": [ [ [ "plastic_chunk", 14 ] ], [ [ "scrap", 10 ] ], [ [ "pipe", 6 ] ], [ [ "nail", 8 ] ] ], + "pre_special": "check_empty", + "post_terrain": "f_treadmill_mechanical" + }, { "type": "construction", "id": "constr_glass_wall", diff --git a/data/json/construction_group.json b/data/json/construction_group.json index 5495ebfb62d93..e70f44cdf54a2 100644 --- a/data/json/construction_group.json +++ b/data/json/construction_group.json @@ -259,6 +259,11 @@ "id": "build_entertainment_center", "name": "Build Entertainment Center" }, + { + "type": "construction_group", + "id": "build_exercise_machine", + "name": "Build Exercise Machine" + }, { "type": "construction_group", "id": "build_fence", @@ -284,6 +289,11 @@ "id": "build_fire_ring", "name": "Build Fire Ring" }, + { + "type": "construction_group", + "id": "build_treadmill_mechanical", + "name": "Build Gravity Treadmill" + }, { "type": "construction_group", "id": "build_glass_door", @@ -359,6 +369,11 @@ "id": "build_makeshift_door", "name": "Build Makeshift Door" }, + { + "type": "construction_group", + "id": "build_ergometer_mechanical", + "name": "Build Mechanical Ergometer" + }, { "type": "construction_group", "id": "build_metal_bars", From cca16218d394fcd93549833535d5786f27090b80 Mon Sep 17 00:00:00 2001 From: Maleclypse <54345792+Maleclypse@users.noreply.github.com> Date: Wed, 31 Mar 2021 02:52:44 -0500 Subject: [PATCH 335/453] Add Red Concrete (#48242) Co-authored-by: Binrui Dong --- .../furniture_and_terrain/terrain-floors-indoor.json | 12 ++++++++++++ 1 file changed, 12 insertions(+) diff --git a/data/json/furniture_and_terrain/terrain-floors-indoor.json b/data/json/furniture_and_terrain/terrain-floors-indoor.json index a28bdf373e96f..8af1e8d7a55ea 100644 --- a/data/json/furniture_and_terrain/terrain-floors-indoor.json +++ b/data/json/furniture_and_terrain/terrain-floors-indoor.json @@ -46,6 +46,18 @@ ] } }, + { + "type": "terrain", + "id": "t_thconc_r", + "name": "concrete floor", + "description": "A bare and cold concrete floor with a streak of red paint, could still insulate from the outdoors but roof collapse is possible if supporting walls are broken down.", + "symbol": ".", + "color": "red", + "looks_like": "t_floor_red", + "move_cost": 2, + "roof": "t_flat_roof", + "copy-from": "t_thconc_floor" + }, { "type": "terrain", "id": "t_thconc_floor_olight", From 3e2e54956873a6ca6e71abf7c8e9eb17c795601a Mon Sep 17 00:00:00 2001 From: Alexey Mostovoy <1931904+AMurkin@users.noreply.github.com> Date: Wed, 31 Mar 2021 13:25:24 +0300 Subject: [PATCH 336/453] Fix typo --- doc/MAPGEN.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/doc/MAPGEN.md b/doc/MAPGEN.md index bb44511583410..84567b35cb1aa 100644 --- a/doc/MAPGEN.md +++ b/doc/MAPGEN.md @@ -578,7 +578,7 @@ This optional object can have two fields: | Field | Description | --- | --- | ammo | A list of objects, each of which has an `"ammo_id"` field and a `"qty"` list of two integers. The monster will spawn with items of "ammo_id", with at least the first number in the "qty" and no more than the second. -| patrol | A list of objects, each of which has an `"x"` field and a `"y"` field. Either value can be a range or a single number. The x,y co-ordinates define a patrol point as an relative mapsquare point offset from the (0, 0) local mapsquare of the overmap terrain tile that the monster spawns in. Patrol points are converted to absolute mapqaure tripoints inside the monster generator. +| patrol | A list of objects, each of which has an `"x"` field and a `"y"` field. Either value can be a range or a single number. The x,y co-ordinates define a patrol point as an relative mapsquare point offset from the (0, 0) local mapsquare of the overmap terrain tile that the monster spawns in. Patrol points are converted to absolute mapsquare tripoints inside the monster generator. Monsters with a patrol point list will move to each patrol point, in order, whenever they have no more pressing action to take on their turn. Upon reaching the last point in the patrol point list, the monster will continue on to the first point in the list. From 3735bce383e535b496acb58ca709c02af451fe24 Mon Sep 17 00:00:00 2001 From: zeropol Date: Thu, 1 Apr 2021 03:58:53 +0200 Subject: [PATCH 337/453] Filter items by book skill ( V, e, / ), fixes #47530 (#48275) * Add a filter to search books by skills they teach * Hide books not skimmed when filtering items The player was able to know which skill a book tech without first skim it. * Fix typographic error * Check non-skill by ID name() is i18n-dependent and it may return something other than "nothing" in different languages. Co-authored-by: Binrui Dong --- src/item.cpp | 10 ++++++++++ src/item.h | 2 ++ src/item_search.cpp | 10 ++++++++++ src/output.cpp | 5 +++-- 4 files changed, 25 insertions(+), 2 deletions(-) diff --git a/src/item.cpp b/src/item.cpp index a93cdcc2f9bb5..cdf9494d421f7 100644 --- a/src/item.cpp +++ b/src/item.cpp @@ -7099,6 +7099,16 @@ bool item::is_book() const return !!type->book; } +std::string item::get_book_skill() const +{ + if( is_book() ) { + if( type->book->skill->ident() != skill_id::NULL_ID() ) { + return type->book->skill->name(); + } + } + return ""; +} + bool item::is_map() const { return get_category_shallow().get_id() == item_category_maps; diff --git a/src/item.h b/src/item.h index 9569cade94e2c..75ccd1f5c0602 100644 --- a/src/item.h +++ b/src/item.h @@ -1243,6 +1243,8 @@ class item : public visitable /** Returns true if the item is A: is SOLID and if it B: is of type LIQUID */ bool is_frozen_liquid() const; + /** Returns empty string if the book teach no skill */ + std::string get_book_skill() const; float get_specific_heat_liquid() const; float get_specific_heat_solid() const; float get_latent_heat() const; diff --git a/src/item_search.cpp b/src/item_search.cpp index fd6b92bd44d22..04ff020e4a3e0 100644 --- a/src/item_search.cpp +++ b/src/item_search.cpp @@ -3,7 +3,9 @@ #include #include +#include "avatar.h" #include "cata_utility.h" +#include "game.h" #include "item.h" #include "item_category.h" #include "material.h" @@ -68,6 +70,14 @@ std::function basic_item_filter( std::string filter ) const std::string note = i.get_var( "item_note" ); return !note.empty() && lcmatch( note, filter ); }; + // by book skill + case 's': + return [filter]( const item & i ) { + if( get_avatar().has_identified( i.typeId() ) ) { + return lcmatch( i.get_book_skill(), filter ); + } + return false; + }; // by name default: return [filter]( const item & a ) { diff --git a/src/output.cpp b/src/output.cpp index cdd163a12ce1f..545cbf00c5e07 100644 --- a/src/output.cpp +++ b/src/output.cpp @@ -870,11 +870,12 @@ void draw_item_filter_rules( const catacurses::window &win, int starty, int heig starty += fold_and_print( win, point( 1, starty ), len, c_white, _( "Search [c]ategory, [m]aterial, " - "[q]uality, [n]otes or " + "[q]uality, [n]otes, " + "[s]skill taught by books or " "[d]isassembled components." ) ); fold_and_print( win, point( 1, starty ), len, c_white, //~ An example of how to filter items based on category or material. - _( "Examples: c:food,m:iron,q:hammering,n:toolshelf,d:pipe" ) ); + _( "Examples: c:food,m:iron,q:hammering,n:toolshelf,d:pipe,s:devices" ) ); wnoutrefresh( win ); } From ead9a13b9e662e7dca19350acc6edaf1ec9bb641 Mon Sep 17 00:00:00 2001 From: MarlossCDDA <78324429+MarlossCDDA@users.noreply.github.com> Date: Wed, 31 Mar 2021 22:30:27 -0400 Subject: [PATCH 338/453] Replace "two-by-four" with "plank" in user-facing strings (#47709) * s/two by four/plank there are still some translations that refer to "two by" "four" across two lines, leaving those alone for now because I'm lazy * fix id in doc/VEHICLES_JSON.md, revert translation changes --- .../furniture_and_terrain/terrain-doors.json | 36 +++++++++---------- .../furniture_and_terrain/terrain-traps.json | 6 ++-- .../furniture_and_terrain/terrain-walls.json | 4 +-- .../terrain-windows.json | 6 ++-- data/json/items/armor/arms_armor.json | 2 +- data/json/items/armor/legs_armor.json | 2 +- data/json/items/melee/swords_and_blades.json | 2 +- data/json/items/tool/workshop.json | 2 +- data/json/items/vehicle/plating.json | 2 +- data/json/npcs/Backgrounds/evacuee_5.json | 2 +- data/json/npcs/Backgrounds/no_past_4.json | 2 +- data/json/npcs/hints.json | 2 +- doc/GAME_BALANCE.md | 2 +- doc/VEHICLES_JSON.md | 2 +- src/crafting_gui.cpp | 2 +- src/map.cpp | 2 +- tests/melee_test.cpp | 4 +-- 17 files changed, 40 insertions(+), 40 deletions(-) diff --git a/data/json/furniture_and_terrain/terrain-doors.json b/data/json/furniture_and_terrain/terrain-doors.json index eac05445ffa89..d017cb560107d 100644 --- a/data/json/furniture_and_terrain/terrain-doors.json +++ b/data/json/furniture_and_terrain/terrain-doors.json @@ -578,7 +578,7 @@ "type": "terrain", "id": "t_door_white_b", "name": "damaged wood door", - "description": "A trashed wooden door, that is more of an obstacle than a door. Also, you can see right through it. It could be boarded up with a few two by fours.", + "description": "A trashed wooden door, that is more of an obstacle than a door. Also, you can see right through it. It could be boarded up with a few planks.", "symbol": "&", "looks_like": "t_door_b", "color": "brown", @@ -614,7 +614,7 @@ "type": "terrain", "id": "t_door_gray_b", "name": "damaged wood door", - "description": "A trashed wooden door, that is more of an obstacle than a door. Also, you can see right through it. It could be boarded up with a few two by fours.", + "description": "A trashed wooden door, that is more of an obstacle than a door. Also, you can see right through it. It could be boarded up with a few planks.", "symbol": "&", "looks_like": "t_door_b", "color": "brown", @@ -650,7 +650,7 @@ "type": "terrain", "id": "t_door_red_b", "name": "damaged wood door", - "description": "A trashed wooden door, that is more of an obstacle than a door. Also, you can see right through it. It could be boarded up with a few two by fours.", + "description": "A trashed wooden door, that is more of an obstacle than a door. Also, you can see right through it. It could be boarded up with a few planks.", "symbol": "&", "looks_like": "t_door_b", "color": "brown", @@ -686,7 +686,7 @@ "type": "terrain", "id": "t_door_green_b", "name": "damaged wood door", - "description": "A trashed wooden door, that is more of an obstacle than a door. Also, you can see right through it. It could be boarded up with a few two by fours.", + "description": "A trashed wooden door, that is more of an obstacle than a door. Also, you can see right through it. It could be boarded up with a few planks.", "symbol": "&", "looks_like": "t_door_b", "color": "brown", @@ -722,7 +722,7 @@ "type": "terrain", "id": "t_door_white_frame", "name": "empty door frame", - "description": "An empty door frame made from two by fours and nails. A variety of doors could be constructed here.", + "description": "An empty door frame made from planks and nails. A variety of doors could be constructed here.", "symbol": ".", "looks_like": "t_door_frame", "color": "brown", @@ -747,7 +747,7 @@ "type": "terrain", "id": "t_door_gray_frame", "name": "empty door frame", - "description": "An empty door frame made from two by fours and nails. A variety of doors could be constructed here.", + "description": "An empty door frame made from planks and nails. A variety of doors could be constructed here.", "symbol": ".", "looks_like": "t_door_frame", "color": "brown", @@ -772,7 +772,7 @@ "type": "terrain", "id": "t_door_red_frame", "name": "empty door frame", - "description": "An empty door frame made from two by fours and nails. A variety of doors could be constructed here.", + "description": "An empty door frame made from planks and nails. A variety of doors could be constructed here.", "symbol": ".", "looks_like": "t_door_frame", "color": "brown", @@ -797,7 +797,7 @@ "type": "terrain", "id": "t_door_green_frame", "name": "empty door frame", - "description": "An empty door frame made from two by fours and nails. A variety of doors could be constructed here.", + "description": "An empty door frame made from planks and nails. A variety of doors could be constructed here.", "symbol": ".", "looks_like": "t_door_frame", "color": "brown", @@ -1053,7 +1053,7 @@ "type": "terrain", "id": "t_door_b", "name": "damaged wood door", - "description": "A trashed wooden door, that is more of an obstacle than a door. Also, you can see right through it. It could be boarded up with a few two by fours.", + "description": "A trashed wooden door, that is more of an obstacle than a door. Also, you can see right through it. It could be boarded up with a few planks.", "symbol": "&", "looks_like": "t_door_c", "color": "brown", @@ -1089,7 +1089,7 @@ "type": "terrain", "id": "t_door_lab_b", "name": "damaged wood door", - "description": "A trashed wooden door, that is more of an obstacle than a door. Also, you can see right through it. It could be boarded up with a few two by fours.", + "description": "A trashed wooden door, that is more of an obstacle than a door. Also, you can see right through it. It could be boarded up with a few planks.", "symbol": "&", "looks_like": "t_door_b", "color": "brown", @@ -1274,7 +1274,7 @@ "type": "terrain", "id": "t_rdoor_c", "name": "closed reinforced wood door", - "description": "Just like other wooden doors, except this one has layers of nailed in two by fours and additional hinge for reinforcement. It might be barricaded, but still susceptible to fire.", + "description": "Just like other wooden doors, except this one has layers of nailed in planks and additional hinge for reinforcement. It might be barricaded, but still susceptible to fire.", "symbol": "+", "looks_like": "t_door_c", "color": "red", @@ -1347,7 +1347,7 @@ "type": "terrain", "id": "t_rdoor_o", "name": "open reinforced wood door", - "description": "Just like other wooden doors, except this one has layers of nailed in two by fours for reinforcement. It might be fortified, but still susceptible to fire. It's open so it's not stopping anything right now.", + "description": "Just like other wooden doors, except this one has layers of nailed in planks for reinforcement. It might be fortified, but still susceptible to fire. It's open so it's not stopping anything right now.", "symbol": "'", "looks_like": "t_door_o", "color": "red", @@ -1574,7 +1574,7 @@ "type": "terrain", "id": "t_door_makeshift_c", "name": "closed makeshift door", - "description": "A makeshift screen consisting of two by fours bound together with vertical rope hanging from the top of the doorway. Could be easily taken down and re-purposed.", + "description": "A makeshift screen consisting of planks bound together with vertical rope hanging from the top of the doorway. Could be easily taken down and re-purposed.", "symbol": "+", "looks_like": "t_door_c", "color": "brown", @@ -1636,7 +1636,7 @@ "type": "terrain", "id": "t_door_makeshift_o", "name": "open makeshift door", - "description": "A makeshift screen consisting of two by fours bound together with rope hanging from the top of the doorway. Could be easily taken down and re-purposed. The planks have been rolled up and attached to the top of the doorway, allowing free movement through.", + "description": "A makeshift screen consisting of planks bound together with rope hanging from the top of the doorway. Could be easily taken down and re-purposed. The planks have been rolled up and attached to the top of the doorway, allowing free movement through.", "symbol": "'", "looks_like": "t_door_o", "color": "brown", @@ -1665,7 +1665,7 @@ "type": "terrain", "id": "t_door_frame", "name": "empty door frame", - "description": "An empty door frame made from two by fours and nails. A variety of doors could be constructed here.", + "description": "An empty door frame made from planks and nails. A variety of doors could be constructed here.", "symbol": ".", "looks_like": "t_floor", "color": "brown", @@ -1690,7 +1690,7 @@ "type": "terrain", "id": "t_door_lab_frame", "name": "empty door frame", - "description": "An empty door frame made from two by fours and nails. A variety of doors could be constructed here.", + "description": "An empty door frame made from planks and nails. A variety of doors could be constructed here.", "symbol": ".", "looks_like": "t_door_frame", "color": "brown", @@ -1859,7 +1859,7 @@ "type": "terrain", "id": "t_rdoor_boarded", "name": "boarded up reinforced door", - "description": "An additionally reinforced door of layered two by fours that has been boarded up with more wood to prevent it from opening. Still susceptible to fire.", + "description": "An additionally reinforced door of layered planks that has been boarded up with more wood to prevent it from opening. Still susceptible to fire.", "symbol": "#", "looks_like": "t_door_boarded", "color": "brown", @@ -1887,7 +1887,7 @@ "type": "terrain", "id": "t_rdoor_boarded_damaged", "name": "boarded up damaged reinforced door", - "description": "A battered and torn reinforced door with planks bursting from the joints. The boarded up two by fours are fragmented and in pieces, this doesn't look like an easy repair.", + "description": "A battered and torn reinforced door with planks bursting from the joints. The boarded up planks are fragmented and in pieces, this doesn't look like an easy repair.", "symbol": "#", "looks_like": "t_door_b", "color": "brown", diff --git a/data/json/furniture_and_terrain/terrain-traps.json b/data/json/furniture_and_terrain/terrain-traps.json index 6d6d564d03819..698951e420b17 100644 --- a/data/json/furniture_and_terrain/terrain-traps.json +++ b/data/json/furniture_and_terrain/terrain-traps.json @@ -50,7 +50,7 @@ "type": "terrain", "id": "t_pit_covered", "name": "covered pit", - "description": "A deep pit with a two by four placed across it, looks sturdy enough to cross safely or the plank could be removed to turn it back into trap fall.", + "description": "A deep pit with a plank placed across it, looks sturdy enough to cross safely or the plank could be removed to turn it back into trap fall.", "symbol": "#", "color": "light_red", "move_cost": 2, @@ -75,7 +75,7 @@ "type": "terrain", "id": "t_pit_spiked_covered", "name": "covered spiked pit", - "description": "Menacing with sharp spears along the bottom, this pit has a plank across it to allow someone or something to cross safely. The two by four could be removed to revert it back into a trap.", + "description": "Menacing with sharp spears along the bottom, this pit has a plank across it to allow someone or something to cross safely. The plank could be removed to revert it back into a trap.", "symbol": "#", "color": "light_red", "move_cost": 2, @@ -100,7 +100,7 @@ "type": "terrain", "id": "t_pit_glass_covered", "name": "covered glass pit", - "description": "A two by four has been placed carefully to allow traversal over this ditch full of large glass shards. The wooden board could be removed so it couldn't be safely crossed.", + "description": "A plank has been placed carefully to allow traversal over this ditch full of large glass shards. The wooden board could be removed so it couldn't be safely crossed.", "symbol": "#", "color": "light_cyan", "move_cost": 2, diff --git a/data/json/furniture_and_terrain/terrain-walls.json b/data/json/furniture_and_terrain/terrain-walls.json index f88f870d7d403..488e38d1d221d 100644 --- a/data/json/furniture_and_terrain/terrain-walls.json +++ b/data/json/furniture_and_terrain/terrain-walls.json @@ -40,7 +40,7 @@ "id": "t_wall_half", "name": "half-built wall", "looks_like": "t_wall", - "description": "An incomplete wall of refined wood, dotted with carefully placed nails to provide proper support. It requires some more two by fours and nails before it'd be considered a suitable wall.", + "description": "An incomplete wall of refined wood, dotted with carefully placed nails to provide proper support. It requires some more planks and nails before it'd be considered a suitable wall.", "symbol": "#", "color": "light_red", "move_cost": 4, @@ -649,7 +649,7 @@ "id": "t_wall_wood_chipped", "name": "chipped wood wall", "looks_like": "t_wall_wood", - "description": "A wall of aligned two by fours that's starting to crack and break open. Some cut wood and a number of nails could patch this up quick.", + "description": "A wall of aligned planks that's starting to crack and break open. Some cut wood and a number of nails could patch this up quick.", "symbol": "LINE_OXOX", "color": "light_red", "move_cost": 0, diff --git a/data/json/furniture_and_terrain/terrain-windows.json b/data/json/furniture_and_terrain/terrain-windows.json index dc3b36b82e4c1..0c05005733ea8 100644 --- a/data/json/furniture_and_terrain/terrain-windows.json +++ b/data/json/furniture_and_terrain/terrain-windows.json @@ -377,7 +377,7 @@ "id": "t_window_empty", "name": "empty window", "roof": "t_flat_roof", - "description": "An empty window frame consisting of two by fours and nails. You could install a sheet of glass, or even board it up for protection. You could also convert it into a wall if you took the time to construct it.", + "description": "An empty window frame consisting of planks and nails. You could install a sheet of glass, or even board it up for protection. You could also convert it into a wall if you took the time to construct it.", "symbol": "0", "color": "yellow", "move_cost": 4, @@ -432,7 +432,7 @@ "type": "terrain", "id": "t_window_boarded", "name": "boarded up window", - "description": "A glass window that has been covered with nailed down planks, blocking sunlight and visibility. It's not much stronger, but it could be further reinforced with strategically placed two by fours.", + "description": "A glass window that has been covered with nailed down planks, blocking sunlight and visibility. It's not much stronger, but it could be further reinforced with strategically placed planks.", "symbol": "#", "color": "brown", "move_cost": 0, @@ -459,7 +459,7 @@ "id": "t_window_boarded_noglass", "name": "boarded up window", "looks_like": "t_window_boarded", - "description": "An empty window frame that has been covered with nailed down planks, blocking sunlight and visibility. It's not much stronger, but it could be further reinforced with strategically placed two by fours.", + "description": "An empty window frame that has been covered with nailed down planks, blocking sunlight and visibility. It's not much stronger, but it could be further reinforced with strategically placed planks.", "symbol": "#", "color": "brown", "move_cost": 0, diff --git a/data/json/items/armor/arms_armor.json b/data/json/items/armor/arms_armor.json index 4bee254520558..19abbbf64451e 100644 --- a/data/json/items/armor/arms_armor.json +++ b/data/json/items/armor/arms_armor.json @@ -4,7 +4,7 @@ "type": "ARMOR", "category": "armor", "name": { "str": "pair of 2-by-arm guards", "str_pl": "pairs of 2-by-arm guards" }, - "description": "A pair of improvised arm guards made from broken pieces of a two by four that are tied to your arms with rags and string. They offer good protection, but are really uncomfortable to wear.", + "description": "A pair of improvised arm guards made from broken pieces of a plank that are tied to your arms with rags and string. They offer good protection, but are really uncomfortable to wear.", "weight": "300 g", "volume": "1500 ml", "price": 500, diff --git a/data/json/items/armor/legs_armor.json b/data/json/items/armor/legs_armor.json index 3befa36a1ca9e..045001ad7fd5e 100644 --- a/data/json/items/armor/legs_armor.json +++ b/data/json/items/armor/legs_armor.json @@ -4,7 +4,7 @@ "type": "ARMOR", "category": "armor", "name": { "str": "pair of 2-by-shin guards", "str_pl": "pairs of 2-by-shin guards" }, - "description": "A pair of improvised shin guards made from broken pieces of a two by four that are tied to your shins with rags and string. They offer good protection, but are really hard to run with.", + "description": "A pair of improvised shin guards made from broken pieces of a plank that are tied to your shins with rags and string. They offer good protection, but are really hard to run with.", "weight": "300 g", "volume": "1500 ml", "price": 500, diff --git a/data/json/items/melee/swords_and_blades.json b/data/json/items/melee/swords_and_blades.json index d6a5d81e52af2..c577cc76d3ac3 100644 --- a/data/json/items/melee/swords_and_blades.json +++ b/data/json/items/melee/swords_and_blades.json @@ -5,7 +5,7 @@ "symbol": "!", "color": "brown", "name": { "str": "2-by-sword" }, - "description": "A two by four with a crossguard and whittled-down point; not much for slashing, but much better than your bare hands.", + "description": "A plank with a crossguard and whittled-down point; not much for slashing, but much better than your bare hands.", "material": [ "wood" ], "volume": "1250 ml", "weight": "1000 g", diff --git a/data/json/items/tool/workshop.json b/data/json/items/tool/workshop.json index 40987eae92595..5e67c927ca8ad 100644 --- a/data/json/items/tool/workshop.json +++ b/data/json/items/tool/workshop.json @@ -309,7 +309,7 @@ "id": "hammer", "type": "TOOL", "name": { "str": "hammer" }, - "description": "This is a demagnetized steel claw hammer with a wooden grip. With a hammer, nails, and two by fours in your inventory, you could board up adjacent doors and windows. It has myriad other uses as well.", + "description": "This is a demagnetized steel claw hammer with a wooden grip. With a hammer, nails, and planks in your inventory, you could board up adjacent doors and windows. It has myriad other uses as well.", "ascii_picture": "hammer", "longest_side": "25 cm", "weight": "566 g", diff --git a/data/json/items/vehicle/plating.json b/data/json/items/vehicle/plating.json index c7de99d163048..7b9e1b6f01cac 100644 --- a/data/json/items/vehicle/plating.json +++ b/data/json/items/vehicle/plating.json @@ -37,7 +37,7 @@ "type": "GENERIC", "id": "wood_plate", "name": { "str": "wooden armor kit" }, - "description": "A bundle of two-by-fours prepared to be used as vehicle armor.", + "description": "A bundle of planks prepared to be used as vehicle armor.", "weight": "5600 g", "to_hit": -8, "color": "brown", diff --git a/data/json/npcs/Backgrounds/evacuee_5.json b/data/json/npcs/Backgrounds/evacuee_5.json index 054226d4c8b73..bfd88f16a16f2 100644 --- a/data/json/npcs/Backgrounds/evacuee_5.json +++ b/data/json/npcs/Backgrounds/evacuee_5.json @@ -2,7 +2,7 @@ { "id": "BGSS_EVACUEE_5_STORY1", "type": "talk_topic", - "dynamic_line": "My Evac shelter got swarmed by some of those bees, the ones the size of dogs. I took out a few with a two-by-four, but pretty quick I realized it was either head for the hills or get stuck like a pig. The rest is history.", + "dynamic_line": "My Evac shelter got swarmed by some of those bees, the ones the size of dogs. I took out a few with a plank, but pretty quick I realized it was either head for the hills or get stuck like a pig. The rest is history.", "//": "TK: In a future iteration, this evacuee might give you directions to a hive.", "responses": [ { "text": "Giant bees? Tell me more.", "topic": "BGSS_EVACUEE_5_BEES" }, diff --git a/data/json/npcs/Backgrounds/no_past_4.json b/data/json/npcs/Backgrounds/no_past_4.json index d4194568a047a..1770b06b359d7 100644 --- a/data/json/npcs/Backgrounds/no_past_4.json +++ b/data/json/npcs/Backgrounds/no_past_4.json @@ -17,7 +17,7 @@ { "id": "BGSS_NO_PAST_4_STORY2", "type": "talk_topic", - "dynamic_line": "I went on, running when I had to and fighting when I could, like the rest of us. Started learning who I am now. Lost the bat in a fight against some crazy electric lightning shooting zombie. It was arcing electricity through my bat so I dropped it and used a nearby two-by-four, but I wound up having to run and leave the ol' slugger behind. I nearly died that day.", + "dynamic_line": "I went on, running when I had to and fighting when I could, like the rest of us. Started learning who I am now. Lost the bat in a fight against some crazy electric lightning shooting zombie. It was arcing electricity through my bat so I dropped it and used a nearby plank, but I wound up having to run and leave the ol' slugger behind. I nearly died that day.", "responses": [ { "text": "It can't be healthy to abandon your past like that…", diff --git a/data/json/npcs/hints.json b/data/json/npcs/hints.json index d25e659098279..e337a28c28e1c 100644 --- a/data/json/npcs/hints.json +++ b/data/json/npcs/hints.json @@ -44,7 +44,7 @@ "For a good melee weapon, you can't beat a machete. I've seen a guy take down a zombie brute with one! Of course, if you can find a katana, that might be even better…", "A knife spear makes a good weapon in a pinch, but a spike strapped to a stick isn't the sturdiest construction. At least you can strap the spike back on when it comes off.", "You know, a glass bottle can make a good weapon in a pinch. If you break it over someone's head, the shattering glass will hurt them extra. Of course, it might hurt your hands, too…", - "You know what makes a nice weapon? Take a two by four, or a baseball bat or something, and stick a bunch of nails through the end!", + "You know what makes a nice weapon? Take a plank, or a baseball bat or something, and stick a bunch of nails through the end!", "BB guns may seem like a joke, but they've got their uses. They're good for hunting small game, or getting to know the basics of rifles.", "Crossbows are a great weapon for long term use. Most of the time, you can retrieve the bolt after shooting it, so running out of ammo is less of a concern.", "Consider going Robin Hood, if you have the strength to pull the string of a bow. Those larger ones need significant muscle power, but they hit hard, and are silent.", diff --git a/doc/GAME_BALANCE.md b/doc/GAME_BALANCE.md index d5ec2bb898ff6..19f0ce7395460 100644 --- a/doc/GAME_BALANCE.md +++ b/doc/GAME_BALANCE.md @@ -126,7 +126,7 @@ Relative value should put the weapon into one of those categories: <2 - Not weapons. Those items may be pressed into service, but are unlikely to be better than fists. Plastic bottles, rocks, boots. -2-5 - Tools not meant to strike and improvised weapons. Two-by-fours, pointy sticks, pipes, hammers. +2-5 - Tools not meant to strike and improvised weapons. Planks, pointy sticks, pipes, hammers. 6-11 - Dangerous tools or crude dedicated weapons. Golf clubs, two-by-swords, wooden spears, knife spears, hatchets, switchblades, tonfas, quarterstaves. diff --git a/doc/VEHICLES_JSON.md b/doc/VEHICLES_JSON.md index 403bfeb9ef866..4e090f9942544 100644 --- a/doc/VEHICLES_JSON.md +++ b/doc/VEHICLES_JSON.md @@ -30,7 +30,7 @@ Vehicle prototypes do not currently accept copy-from "items": [ // Item spawn list { "x": 0, "y": 0, "items": "helmet_army" }, // individual item { "x": 0, "y": 0, "item_groups": "army_uniform" }, // item or items from an item_group - { "x": 0, "y": 1, "items": [ "matchbook", "two_by_four" ] }, // all items in the list spawn + { "x": 0, "y": 1, "items": [ "matchbook", "2x4" ] }, // all items in the list spawn { "x": 0, "y": 0, "item_groups": [ "army_uniform", "rare_guns" ] } all item_groups are processed ] ``` diff --git a/src/crafting_gui.cpp b/src/crafting_gui.cpp index 4e67f4a334029..ec9a7fc52f1f5 100644 --- a/src/crafting_gui.cpp +++ b/src/crafting_gui.cpp @@ -934,7 +934,7 @@ const recipe *select_crafting_recipe( int &batch_size_out ) //~ Example result description search term { 'q', _( "metal sawing" ), _( "quality of resulting item" ) }, { 'd', _( "reach attack" ), _( "full description of resulting item (slow)" ) }, - { 'c', _( "two by four" ), _( "component required to craft" ) }, + { 'c', _( "plank" ), _( "component required to craft" ) }, { 'p', _( "tailoring" ), _( "primary skill used to craft" ) }, { 's', _( "cooking" ), _( "any skill used to craft" ) }, { 'Q', _( "fine bolt turning" ), _( "quality required to craft" ) }, diff --git a/src/map.cpp b/src/map.cpp index e8d4e594c8264..0f7c755afe4b3 100644 --- a/src/map.cpp +++ b/src/map.cpp @@ -3030,7 +3030,7 @@ void map::smash_items( const tripoint &p, const int power, const std::string &ca const float volume_factor = std::max( 40, i->volume() / units::legacy_volume_factor ); float damage_chance = 10.0f * power / volume_factor; // Example: - // Power 40 (just below C4 epicenter) vs two-by-four + // Power 40 (just below C4 epicenter) vs plank // damage_chance = 10 * 40 / 40 = 10, material_factor = 8 // Will deal 1 damage, then 20% chance for another point // Power 20 (grenade minus shrapnel) vs glass bottle diff --git a/tests/melee_test.cpp b/tests/melee_test.cpp index 23ba262880001..f40e68d9c5bd9 100644 --- a/tests/melee_test.cpp +++ b/tests/melee_test.cpp @@ -85,7 +85,7 @@ TEST_CASE( "Character attacking a zombie", "[.melee]" ) check_near( prob, 0.6f, 0.1f ); } - SECTION( "8/8/8/8, 3 all skills, two-by-four" ) { + SECTION( "8/8/8/8, 3 all skills, plank" ) { standard_npc dude( "TestCharacter", dude_pos, {}, 3, 8, 8, 8, 8 ); dude.weapon = item( "2x4" ); const float prob = brute_probability( dude, zed, num_iters ); @@ -114,7 +114,7 @@ TEST_CASE( "Character attacking a manhack", "[.melee]" ) check_near( prob, 0.2f, 0.05f ); } - SECTION( "8/8/8/8, 3 all skills, two-by-four" ) { + SECTION( "8/8/8/8, 3 all skills, plank" ) { standard_npc dude( "TestCharacter", dude_pos, {}, 3, 8, 8, 8, 8 ); dude.weapon = item( "2x4" ); const float prob = brute_probability( dude, manhack, num_iters ); From 056737c06158bb047d61f7cdd07890644f4e614b Mon Sep 17 00:00:00 2001 From: Jamuro-g <76928284+Jamuro-g@users.noreply.github.com> Date: Thu, 1 Apr 2021 04:51:53 +0200 Subject: [PATCH 339/453] Added warning to excessive long attack times (#47835) MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit * added warning to excessive long attack times * restore code * astyle fix * removed unused code * Update src/melee.cpp Co-authored-by: Jianxiang Wang (王健翔) * Update src/melee.cpp Co-authored-by: Jianxiang Wang (王健翔) * switch message block Co-authored-by: Jianxiang Wang (王健翔) --- src/character.h | 1 + src/melee.cpp | 24 +++++++++++++++++++++++- 2 files changed, 24 insertions(+), 1 deletion(-) diff --git a/src/character.h b/src/character.h index dca5ede190e09..eedd8b4dadb43 100644 --- a/src/character.h +++ b/src/character.h @@ -2948,6 +2948,7 @@ class Character : public Creature, public visitable tripoint cached_position; pimpl cached_crafting_inventory; + time_point melee_warning_turn = calendar::turn_zero; protected: /** Subset of learned recipes. Needs to be mutable for lazy initialization. */ mutable pimpl learned_recipes; diff --git a/src/melee.cpp b/src/melee.cpp index eb9fb2b6facb4..856aa4f645486 100644 --- a/src/melee.cpp +++ b/src/melee.cpp @@ -55,6 +55,7 @@ #include "pimpl.h" #include "player.h" #include "point.h" +#include "popup.h" #include "projectile.h" #include "rng.h" #include "sounds.h" @@ -540,9 +541,30 @@ bool Character::melee_attack_abstract( Creature &t, bool allow_special, add_msg( m_bad, _( "This weapon is too unwieldy to attack with!" ) ); return false; } - int move_cost = attack_speed( *cur_weapon ); + if( is_avatar() && move_cost > 1000 && calendar::turn > melee_warning_turn ) { + const auto &action = query_popup() + .context( "CANCEL_ACTIVITY_OR_IGNORE_QUERY" ) + .message( _( "Attacking with your %1$s will take a long time. " + "Are you sure you want to continue?" ), + cur_weapon->display_name() ) + .option( "YES" ) + .option( "NO" ) + .option( "IGNORE" ) + .query() + .action; + + if( action == "NO" ) { + return false; + } + if( action == "IGNORE" ) { + if( melee_warning_turn == calendar::turn_zero || melee_warning_turn <= calendar::turn ) { + melee_warning_turn = calendar::turn + 50_turns; + } + } + } + const bool hits = hit_spread >= 0; if( monster *m = t.as_monster() ) { From 79812264f1ae218ad34746c8fc647f47cbb1c72e Mon Sep 17 00:00:00 2001 From: Mark Ponti Date: Wed, 31 Mar 2021 21:11:09 -0700 Subject: [PATCH 340/453] meatballs (#48124) * Update meat_dishes.json * Update meat_dishes.json * Update meat_dishes.json * Update meat_dishes.json * Update recipe_food.json * Update recipe_food.json * Update recipe_food.json * Update recipe_food.json * Update recipe_food.json * Update data/json/recipes/recipe_food.json Co-authored-by: Binrui Dong Co-authored-by: Binrui Dong --- data/json/items/comestibles/meat_dishes.json | 43 ++++++++++++++++++++ data/json/recipes/recipe_food.json | 41 +++++++++++++++++++ 2 files changed, 84 insertions(+) diff --git a/data/json/items/comestibles/meat_dishes.json b/data/json/items/comestibles/meat_dishes.json index a6f27f6b5170f..a9a28f0a6ed53 100644 --- a/data/json/items/comestibles/meat_dishes.json +++ b/data/json/items/comestibles/meat_dishes.json @@ -1389,5 +1389,48 @@ "flags": [ "EATEN_HOT" ], "fun": 7, "vitamins": [ [ "vitC", 3 ], [ "calcium", 19 ], [ "iron", 12 ] ] + }, + { + "type": "COMESTIBLE", + "id": "meatball_raw", + "name": { "str": "raw meatball" }, + "conditional_names": [ + { "type": "FLAG", "condition": "CANNIBALISM", "name": "raw manball" }, + { "type": "FLAG", "condition": "STRICT_HUMANITARIANISM", "name": "raw murderball" }, + { "type": "COMPONENT_ID", "condition": "mutant", "name": { "str_sp": "sinister %s" } } + ], + "weight": "85g", + "color": "pink", + "spoils_in": "1 day", + "comestible_type": "FOOD", + "symbol": "%", + "calories": 230, + "healthy": -1, + "parasites": 32, + "description": "A round, seasoned lump of meat, ready to fry.", + "price": 800, + "price_postapoc": 200, + "material": [ "flesh" ], + "volume": "85 ml", + "vitamins": [ [ "vitA", 2 ], [ "vitC", 2 ], [ "calcium", 8 ], [ "iron", 4 ] ], + "fun": -10 + }, + { + "type": "COMESTIBLE", + "id": "meatball", + "name": { "str": "meatball" }, + "conditional_names": [ + { "type": "FLAG", "condition": "CANNIBALISM", "name": "manball" }, + { "type": "FLAG", "condition": "STRICT_HUMANITARIANISM", "name": "murderball" }, + { "type": "COMPONENT_ID", "condition": "mutant", "name": { "str_sp": "sinister %s" } } + ], + "copy-from": "meatball_raw", + "parasites": 0, + "healthy": 0, + "spoils_in": "4 days", + "price_postapoc": 300, + "description": "A seasoned, fried, round lump of meat. Just like mom used to make!", + "flags": [ "EATEN_HOT" ], + "fun": 6 } ] diff --git a/data/json/recipes/recipe_food.json b/data/json/recipes/recipe_food.json index aa40e1a7ed67b..2b92975413284 100644 --- a/data/json/recipes/recipe_food.json +++ b/data/json/recipes/recipe_food.json @@ -7684,5 +7684,46 @@ [ [ "sugar", 1 ], [ "artificial_sweetener", 1 ] ], [ [ "salt", 1 ], [ "seasoning_salt", 1 ] ] ] + }, + { + "type": "recipe", + "activity_level": "LIGHT_EXERCISE", + "result": "meatball_raw", + "category": "CC_FOOD", + "subcategory": "CSC_FOOD_MEAT", + "skill_used": "cooking", + "difficulty": 4, + "time": "10 m", + "charges": 6, + "book_learn": [ [ "family_cookbook", 2 ], [ "cookbook_italian", 2 ] ], + "batch_time_factors": [ 50, 3 ], + "qualities": [ { "id": "CUT", "level": 1 }, { "id": "COOK", "level": 1 } ], + "components": [ + [ [ "meat_red", 2, "LIST" ] ], + [ [ "bread", 1 ] ], + [ + [ "salt", 2 ], + [ "soysauce", 2 ], + [ "seasoning_italian", 2 ], + [ "wild_herbs", 2 ], + [ "seasoning_salt", 2 ], + [ "pepper", 2 ] + ] + ] + }, + { + "type": "recipe", + "activity_level": "LIGHT_EXERCISE", + "result": "meatball", + "category": "CC_FOOD", + "subcategory": "CSC_FOOD_MEAT", + "skill_used": "cooking", + "time": "15 m", + "autolearn": true, + "batch_time_factors": [ 67, 5 ], + "qualities": [ { "id": "COOK", "level": 1 } ], + "tools": [ [ [ "surface_heat", 2, "LIST" ] ] ], + "charges": 1, + "components": [ [ [ "meatball_raw", 1 ] ] ] } ] From 1a1d44d8935d2b217e3ae5baeb274cf6546489ca Mon Sep 17 00:00:00 2001 From: Anton Burmistrov Date: Mon, 5 Apr 2021 23:15:13 +0400 Subject: [PATCH 341/453] Jsonify drug dealer map extra (#48327) * Added json-version of drug dealers map extra * Made game use json-version instead of hardcoded one * Updated item group to contain drugs Also increased damage level of corpses to pulped state so they don't revive * Removed hardcoded generation --- .../Locations_MapExtras/map_extras.json | 11 +- data/json/mapgen/map_extras/drug_dealers.json | 51 +++++++ data/json/overmap/map_extras.json | 2 +- src/map_extras.cpp | 128 ------------------ 4 files changed, 62 insertions(+), 130 deletions(-) create mode 100644 data/json/mapgen/map_extras/drug_dealers.json diff --git a/data/json/itemgroups/Locations_MapExtras/map_extras.json b/data/json/itemgroups/Locations_MapExtras/map_extras.json index 7b21d2695145b..1620384f0e575 100644 --- a/data/json/itemgroups/Locations_MapExtras/map_extras.json +++ b/data/json/itemgroups/Locations_MapExtras/map_extras.json @@ -71,12 +71,21 @@ "id": "map_extra_drugdeal", "entries": [ { "group": "drugdealer", "prob": 75 }, + { + "distribution": [ + { "item": "weed", "container-item": "bag_zipper", "charges-min": 20, "charges-max": 30, "prob": 10 }, + { "item": "coke", "container-item": "bag_zipper", "charges-min": 10, "charges-max": 20, "prob": 40 }, + { "item": "meth", "container-item": "bag_zipper", "charges-min": 8, "charges-max": 14, "prob": 30 }, + { "item": "heroin", "container-item": "bag_zipper", "charges-min": 6, "charges-max": 12, "prob": 20 } + ], + "prob": 50 + }, { "item": "pants_cargo", "damage-min": 1, "damage-max": 4 }, { "group": "lab_shoes", "damage-min": 1, "damage-max": 4, "prob": 50 }, { "group": "shirts", "damage-min": 1, "damage-max": 4, "prob": 50 }, { "group": "jackets", "damage-min": 1, "damage-max": 4, "prob": 30 }, { "group": "underwear", "damage-min": 1, "damage-max": 3 }, - { "item": "corpse", "damage": 3 } + { "item": "corpse", "damage": 4 } ] }, { diff --git a/data/json/mapgen/map_extras/drug_dealers.json b/data/json/mapgen/map_extras/drug_dealers.json new file mode 100644 index 0000000000000..5d34b27fa1976 --- /dev/null +++ b/data/json/mapgen/map_extras/drug_dealers.json @@ -0,0 +1,51 @@ +[ + { + "type": "mapgen", + "method": "json", + "nested_mapgen_id": "corpse_blood_gibs_drugs_3x3", + "object": { + "mapgensize": [ 3, 3 ], + "place_items": [ { "item": "map_extra_drugdeal", "x": [ 0, 2 ], "y": [ 0, 2 ], "chance": 100 } ], + "place_fields": [ { "field": "fd_blood", "x": [ 0, 2 ], "y": [ 0, 2 ] }, { "field": "fd_gibs_flesh", "x": [ 0, 2 ], "y": [ 0, 2 ] } ] + } + }, + { + "type": "mapgen", + "method": "json", + "update_mapgen_id": "mx_drugdeal", + "object": { + "rows": [ + " ", + " ", + " ", + " ", + " ", + " ", + " ", + " ", + " ", + " ", + " ", + " 1 ", + " ", + " ", + " ", + " ", + " ", + " ", + " ", + " ", + " ", + " ", + " ", + " " + ], + "terrain": { " ": [ [ "t_region_groundcover_urban", 50 ], [ "t_region_groundcover_barren", 20 ] ] }, + "monsters": { " ": { "monster": "GROUP_NETHER_CAPTURED", "chance": 1, "density": 0.0001 } }, + "nested": { + " ": { "chunks": [ [ "corpse_blood_gibs_drugs_3x3", 1 ], [ "null", 150 ] ] }, + "1": { "chunks": [ "corpse_blood_gibs_drugs_3x3" ] } + } + } + } +] diff --git a/data/json/overmap/map_extras.json b/data/json/overmap/map_extras.json index bb8a7cf44a558..a7d4846738189 100644 --- a/data/json/overmap/map_extras.json +++ b/data/json/overmap/map_extras.json @@ -24,7 +24,7 @@ "type": "map_extra", "name": { "str": "Drug Deal" }, "description": "Several corpses of drug dealers are here.", - "generator": { "generator_method": "map_extra_function", "generator_id": "mx_drugdeal" }, + "generator": { "generator_method": "update_mapgen", "generator_id": "mx_drugdeal" }, "sym": "d", "color": "light_red", "autonote": true diff --git a/src/map_extras.cpp b/src/map_extras.cpp index 948625df39251..5834d5cb92673 100644 --- a/src/map_extras.cpp +++ b/src/map_extras.cpp @@ -916,133 +916,6 @@ static bool mx_bandits_block( map &m, const tripoint &abs_sub ) return false; } -static bool mx_drugdeal( map &m, const tripoint &abs_sub ) -{ - // Decide on a drug type - int num_drugs = 0; - itype_id drugtype; - switch( rng( 1, 10 ) ) { - case 1: - // Weed - num_drugs = rng( 20, 30 ); - drugtype = itype_weed; - break; - case 2: - case 3: - case 4: - case 5: - // Cocaine - num_drugs = rng( 10, 20 ); - drugtype = itype_coke; - break; - case 6: - case 7: - case 8: - // Meth - num_drugs = rng( 8, 14 ); - drugtype = itype_meth; - break; - case 9: - case 10: - // Heroin - num_drugs = rng( 6, 12 ); - drugtype = itype_heroin; - break; - } - int num_bodies_a = dice( 3, 3 ); - int num_bodies_b = dice( 3, 3 ); - bool north_south = one_in( 2 ); - bool a_has_drugs = one_in( 2 ); - - for( int i = 0; i < num_bodies_a; i++ ) { - point p; - point offset; - int tries = 0; - do { // Loop until we find a valid spot to dump a body, or we give up - if( north_south ) { - p.x = rng( 0, SEEX * 2 - 1 ); - p.y = rng( 0, SEEY - 4 ); - offset.x = 0; - offset.y = -1; - } else { - p.x = rng( 0, SEEX - 4 ); - p.y = rng( 0, SEEY * 2 - 1 ); - offset.x = -1; - offset.y = 0; - } - tries++; - } while( tries < 10 && m.impassable( p ) ); - - if( tries < 10 ) { // We found a valid spot! - if( a_has_drugs && num_drugs > 0 ) { - int drugs_placed = rng( 2, 6 ); - if( drugs_placed > num_drugs ) { - drugs_placed = num_drugs; - num_drugs = 0; - } - m.spawn_item( p, drugtype, 0, drugs_placed ); - } - if( one_in( 10 ) ) { - m.add_spawn( mon_zombie_spitter, 1, { p, abs_sub.z } ); - } else { - m.place_items( item_group_id( "map_extra_drugdeal" ), 100, p, p, true, - calendar::start_of_cataclysm ); - int splatter_range = rng( 1, 3 ); - for( int j = 0; j <= splatter_range; j++ ) { - m.add_field( p + tripoint( j * offset.x, j * offset.y, abs_sub.z ), fd_blood, 1, 0_turns ); - } - } - } - } - for( int i = 0; i < num_bodies_b; i++ ) { - point p2; - point offset2; - int tries = 0; - do { // Loop until we find a valid spot to dump a body, or we give up - if( north_south ) { - p2.x = rng( 0, SEEX * 2 - 1 ); - p2.y = rng( SEEY + 3, SEEY * 2 - 1 ); - offset2.x = 0; - offset2.y = 1; - } else { - p2.x = rng( SEEX + 3, SEEX * 2 - 1 ); - p2.y = rng( 0, SEEY * 2 - 1 ); - offset2.x = 1; - offset2.y = 0; - } - tries++; - } while( tries < 10 && m.impassable( p2 ) ); - - if( tries < 10 ) { // We found a valid spot! - if( one_in( 20 ) ) { - m.add_spawn( mon_zombie_smoker, 1, { p2, abs_sub.z } ); - } else { - m.place_items( item_group_id( "map_extra_drugdeal" ), 100, p2, p2, true, - calendar::start_of_cataclysm ); - int splatter_range = rng( 1, 3 ); - for( int j = 0; j <= splatter_range; j++ ) { - m.add_field( p2 + tripoint( j * offset2.x, j * offset2.y, abs_sub.z ), fd_blood, 1, 0_turns ); - } - if( !a_has_drugs && num_drugs > 0 ) { - int drugs_placed = rng( 2, 6 ); - if( drugs_placed > num_drugs ) { - drugs_placed = num_drugs; - num_drugs = 0; - } - m.spawn_item( p2, drugtype, 0, drugs_placed ); - } - } - } - } - int num_monsters = rng( 0, 3 ); - for( int i = 0; i < num_monsters; i++ ) { - point m2( rng( 1, SEEX * 2 - 2 ), rng( 1, SEEY * 2 - 2 ) ); - m.place_spawns( GROUP_NETHER_CAPTURED, 1, m2, m2, 1, true ); - } - - return true; -} - static bool mx_supplydrop( map &m, const tripoint &/*abs_sub*/ ) { const bool intact = x_in_y( 40, @@ -3122,7 +2995,6 @@ FunctionMap builtin_functions = { { "mx_null", mx_null }, { "mx_crater", mx_crater }, { "mx_collegekids", mx_collegekids }, - { "mx_drugdeal", mx_drugdeal }, { "mx_roadworks", mx_roadworks }, { "mx_mayhem", mx_mayhem }, { "mx_roadblock", mx_roadblock }, From c83c70a61e1b8b531ad941c1f257ff4c8344db43 Mon Sep 17 00:00:00 2001 From: Eric <52087122+Ramza13@users.noreply.github.com> Date: Tue, 6 Apr 2021 00:14:27 -0400 Subject: [PATCH 342/453] Allows defining enchantments inline in bionics/mutations (#48151) --- data/json/bionics.json | 12 ++++-- data/json/enchantments.json | 39 ------------------- .../json/mutations/mutation_enchantments.json | 15 ------- data/json/mutations/mutations.json | 20 ++++++++-- doc/JSON_INFO.md | 4 +- src/bionics.cpp | 7 +++- src/magic_enchantment.cpp | 28 ++++++++++++- src/magic_enchantment.h | 8 +++- src/mutation_data.cpp | 7 +++- 9 files changed, 72 insertions(+), 68 deletions(-) delete mode 100644 data/json/enchantments.json delete mode 100644 data/json/mutations/mutation_enchantments.json diff --git a/data/json/bionics.json b/data/json/bionics.json index 64a94138ad13e..68895c5982d83 100644 --- a/data/json/bionics.json +++ b/data/json/bionics.json @@ -281,7 +281,7 @@ "act_cost": "30 kJ", "react_cost": "30 kJ", "time": 1, - "enchantments": [ "ENCH_INVISIBILITY" ], + "enchantments": [ { "condition": "ACTIVE", "ench_effects": [ { "effect": "invisibility", "intensity": 1 } ] } ], "flags": [ "BIONIC_TOGGLED" ] }, { @@ -740,7 +740,13 @@ "description": "When active, this bionic eliminates all light within a 2 tile radius through destructive interference.", "occupied_bodyparts": [ [ "torso", 16 ] ], "flags": [ "BIONIC_TOGGLED" ], - "enchantments": [ "ENCH_SHADOW_CLOUD" ], + "enchantments": [ + { + "condition": "ACTIVE", + "ench_effects": [ { "effect": "invisibility", "intensity": 1 } ], + "emitter": "emit_shadow_field" + } + ], "act_cost": "9 kJ", "react_cost": "9 kJ", "time": 1 @@ -1228,6 +1234,6 @@ "description": "An electrode has been implanted into your brain's ventrolateral preoptic nucleus. It turns on whenever you're trying to fall asleep, creating an artificial but effective sensation of fatigue.", "occupied_bodyparts": [ [ "head", 1 ] ], "flags": [ "BIONIC_TOGGLED" ], - "enchantments": [ "ENCH_BIO_SOPORIFIC" ] + "enchantments": [ { "condition": "ACTIVE", "values": [ { "value": "SLEEPY", "add": 30 } ] } ] } ] diff --git a/data/json/enchantments.json b/data/json/enchantments.json deleted file mode 100644 index 85852553944b5..0000000000000 --- a/data/json/enchantments.json +++ /dev/null @@ -1,39 +0,0 @@ -[ - { - "type": "enchantment", - "id": "ENCH_INVISIBILITY", - "condition": "ACTIVE", - "ench_effects": [ { "effect": "invisibility", "intensity": 1 } ] - }, - { - "type": "enchantment", - "id": "ENCH_SHADOW_CLOUD", - "condition": "ACTIVE", - "ench_effects": [ { "effect": "invisibility", "intensity": 1 } ], - "emitter": "emit_shadow_field" - }, - { - "type": "enchantment", - "id": "ENCH_TRAIT_INSOMNIA", - "condition": "ALWAYS", - "values": [ { "value": "SLEEPY", "add": -12 } ] - }, - { - "type": "enchantment", - "id": "ENCH_TRAIT_EASYSLEEPER", - "condition": "ALWAYS", - "values": [ { "value": "SLEEPY", "add": 24 } ] - }, - { - "type": "enchantment", - "id": "ENCH_TRAIT_EASYSLEEPER2", - "condition": "ALWAYS", - "values": [ { "value": "SLEEPY", "add": 40 } ] - }, - { - "type": "enchantment", - "id": "ENCH_BIO_SOPORIFIC", - "condition": "ACTIVE", - "values": [ { "value": "SLEEPY", "add": 30 } ] - } -] diff --git a/data/json/mutations/mutation_enchantments.json b/data/json/mutations/mutation_enchantments.json deleted file mode 100644 index 8421a76188920..0000000000000 --- a/data/json/mutations/mutation_enchantments.json +++ /dev/null @@ -1,15 +0,0 @@ -[ - { - "type": "enchantment", - "id": "MEP_INK_GLAND_SPRAY", - "hit_me_effect": [ - { - "id": "generic_blinding_spray_1", - "hit_self": false, - "once_in": 15, - "message": "Your ink glands spray some ink into %2$s's eyes.", - "npc_message": "%1$s's ink glands spray some ink into %2$s's eyes." - } - ] - } -] diff --git a/data/json/mutations/mutations.json b/data/json/mutations/mutations.json index 10b1ad3e70c90..01460e1e17bef 100644 --- a/data/json/mutations/mutations.json +++ b/data/json/mutations/mutations.json @@ -305,7 +305,7 @@ "valid": false, "cancels": [ "INSOMNIA" ], "category": [ "MOUSE", "INSECT" ], - "enchantments": [ "ENCH_TRAIT_EASYSLEEPER" ] + "enchantments": [ { "condition": "ALWAYS", "values": [ { "value": "SLEEPY", "add": 24 } ] } ] }, { "type": "mutation", @@ -317,7 +317,7 @@ "cancels": [ "INSOMNIA" ], "threshreq": [ "THRESH_MOUSE" ], "category": [ "MOUSE" ], - "enchantments": [ "ENCH_TRAIT_EASYSLEEPER2" ] + "enchantments": [ { "condition": "ALWAYS", "values": [ { "value": "SLEEPY", "add": 40 } ] } ] }, { "type": "mutation", @@ -1062,7 +1062,7 @@ "starting_trait": true, "valid": false, "category": [ "MEDICAL" ], - "enchantments": [ "ENCH_TRAIT_INSOMNIA" ], + "enchantments": [ { "condition": "ALWAYS", "values": [ { "value": "SLEEPY", "add": -12 } ] } ], "cancels": [ "EASYSLEEPER" ] }, { @@ -2815,7 +2815,19 @@ "visibility": 1, "ugliness": 1, "description": "Several ink glands have grown onto your torso. They can be used to spray defensive ink and blind an attacker in an emergency, as long as the torso isn't covered.", - "enchantments": [ "MEP_INK_GLAND_SPRAY" ], + "enchantments": [ + { + "hit_me_effect": [ + { + "id": "generic_blinding_spray_1", + "hit_self": false, + "once_in": 15, + "message": "Your ink glands spray some ink into %2$s's eyes.", + "npc_message": "%1$s's ink glands spray some ink into %2$s's eyes." + } + ] + } + ], "category": [ "CEPHALOPOD" ] }, { diff --git a/doc/JSON_INFO.md b/doc/JSON_INFO.md index d35def589a768..38b3db1821dd4 100644 --- a/doc/JSON_INFO.md +++ b/doc/JSON_INFO.md @@ -673,7 +673,7 @@ For information about tools with option to export ASCII art in format ready to b | coverage_power_gen_penalty | (_optional_) Fraction of coverage diminishing fuel_efficiency. Float between 0.0 and 1.0. (default: `nullopt`) | power_gen_emission | (_optional_) `emit_id` of the field emitted by this bionic when it produces energy. Emit_ids are defined in `emit.json`. | stat_bonus | (_optional_) List of passive stat bonus. Stat are designated as follow: "DEX", "INT", "STR", "PER". -| enchantments | (_optional_) List of enchantments applied by this CBM (see MAGIC.md for instructions on enchantment. NB: enchantments are not necessarily magic.) +| enchantments | (_optional_) List of enchantments applied by this CBM (see MAGIC.md for instructions on enchantment. NB: enchantments are not necessarily magic.) Values can either be the enchantments's id or an inline definition of the enchantment. | learned_spells | (_optional_) Map of {spell:level} you gain when installing this CBM, and lose when you uninstall this CBM. Spell classes are automatically gained. | learned_proficiencies | (_optional_) Array of proficiency ids you gain when installing this CBM, and lose when uninstalling | installation_requirement | (_optional_) Requirement id pointing to a requirement defining the tools and components necessary to install this CBM. @@ -1940,7 +1940,7 @@ it is present to help catch errors. } ] ], -"enchantments": [ "ench_id_1" ], // List of IDs of enchantments granted by this mutation +"enchantments": [ "ench_id_1" ], // List of enchantments granted by this mutation, can be either string ids of the enchantment or an inline definition of the enchantment "temperature_speed_modifier": 0.5, // If nonzero, become slower when cold, and faster when hot // 1.0 gives +/-1% speed for each degree above or below 65F "mana_modifier": 100 // Positive or negative change to total mana pool diff --git a/src/bionics.cpp b/src/bionics.cpp index 2562f37684f43..e80aaff137285 100644 --- a/src/bionics.cpp +++ b/src/bionics.cpp @@ -306,7 +306,6 @@ void bionic_data::load( const JsonObject &jsobj, const std::string & ) optional( jsobj, was_loaded, "fake_item", fake_item, itype_id() ); - optional( jsobj, was_loaded, "enchantments", enchantments ); optional( jsobj, was_loaded, "spell_on_activation", spell_on_activate ); optional( jsobj, was_loaded, "weight_capacity_modifier", weight_capacity_modifier, 1.0f ); @@ -331,6 +330,12 @@ void bionic_data::load( const JsonObject &jsobj, const std::string & ) optional( jsobj, was_loaded, "vitamin_absorb_mod", vitamin_absorb_mod, 1.0f ); + int enchant_num = 0; + for( JsonValue jv : jsobj.get_array( "enchantments" ) ) { + std::string enchant_name = "INLINE_ENCH_" + name + "_" + std::to_string( enchant_num++ ); + enchantments.push_back( enchantment::load_inline_enchantment( jv, "", enchant_name ) ); + } + if( jsobj.has_array( "stat_bonus" ) ) { // clear data first so that copy-from can override it stat_bonus.clear(); diff --git a/src/magic_enchantment.cpp b/src/magic_enchantment.cpp index cfbd928183c2f..390b78594862e 100644 --- a/src/magic_enchantment.cpp +++ b/src/magic_enchantment.cpp @@ -147,6 +147,29 @@ void enchantment::load_enchantment( const JsonObject &jo, const std::string &src spell_factory.load( jo, src ); } +enchantment_id enchantment::load_inline_enchantment( const JsonValue &jv, const std::string &src, + std::string &inline_id ) +{ + if( jv.test_string() ) { + return enchantment_id( jv.get_string() ); + } else if( jv.test_object() ) { + if( inline_id.empty() ) { + jv.throw_error( "Inline enchantment cannot be created without an id." ); + } + if( spell_factory.is_valid( enchantment_id( inline_id ) ) ) { + jv.throw_error( "Inline enchantment " + inline_id + + " cannot be created as an enchantment already has this id." ); + } + + enchantment inline_enchant; + inline_enchant.load( jv.get_object(), src, inline_id ); + spell_factory.insert( inline_enchant ); + return enchantment_id( inline_id ); + } else { + jv.throw_error( "Enchantment needs to be either string or enchantment object." ); + } +} + bool enchantment::is_active( const Character &guy, const item &parent ) const { if( !guy.has_item( parent ) ) { @@ -197,9 +220,10 @@ void enchantment::add_activation( const time_duration &dur, const fake_spell &fa intermittent_activation[dur].emplace_back( fake ); } -void enchantment::load( const JsonObject &jo, const std::string & ) +void enchantment::load( const JsonObject &jo, const std::string &, + const cata::optional &inline_id ) { - optional( jo, was_loaded, "id", id, enchantment_id( "" ) ); + optional( jo, was_loaded, "id", id, enchantment_id( inline_id.value_or( "" ) ) ); jo.read( "hit_you_effect", hit_you_effect ); jo.read( "hit_me_effect", hit_me_effect ); diff --git a/src/magic_enchantment.h b/src/magic_enchantment.h index 442d56b50b45f..de76442562094 100644 --- a/src/magic_enchantment.h +++ b/src/magic_enchantment.h @@ -120,7 +120,13 @@ class enchantment }; static void load_enchantment( const JsonObject &jo, const std::string &src ); - void load( const JsonObject &jo, const std::string &src = "" ); + void load( const JsonObject &jo, const std::string &src = "", + const cata::optional &inline_id = cata::nullopt ); + + // Takes in a JsonValue which can be either a string or an enchantment object and returns the id of the enchantment the caller will use. + // If the input is a string return it as an enchantment_id otherwise create an enchantment with id inline_id and return inline_id as an enchantment id + static enchantment_id load_inline_enchantment( const JsonValue &jv, const std::string &src, + std::string &inline_id ); // attempts to add two like enchantments together. // if their conditions don't match, return false. else true. diff --git a/src/mutation_data.cpp b/src/mutation_data.cpp index bf16334165fda..2600d3de911a1 100644 --- a/src/mutation_data.cpp +++ b/src/mutation_data.cpp @@ -504,7 +504,12 @@ void mutation_branch::load( const JsonObject &jo, const std::string & ) optional( jo, was_loaded, "active_flags", active_flags, flag_reader{} ); optional( jo, was_loaded, "inactive_flags", inactive_flags, flag_reader{} ); optional( jo, was_loaded, "types", types, string_reader{} ); - optional( jo, was_loaded, "enchantments", enchantments ); + + int enchant_num = 0; + for( JsonValue jv : jo.get_array( "enchantments" ) ) { + std::string enchant_name = "INLINE_ENCH_" + raw_name + "_" + std::to_string( enchant_num++ ); + enchantments.push_back( enchantment::load_inline_enchantment( jv, "", enchant_name ) ); + } for( const std::string s : jo.get_array( "no_cbm_on_bp" ) ) { no_cbm_on_bp.emplace( bodypart_str_id( s ) ); From 9ea89412b98c7ba26723b5a136e7b9b16aa3e91e Mon Sep 17 00:00:00 2001 From: Eric <52087122+Ramza13@users.noreply.github.com> Date: Tue, 6 Apr 2021 01:19:34 -0400 Subject: [PATCH 343/453] Unhardcode bio_drain bionic faults (#48295) --- data/json/effect_on_condition.json | 17 ++++++++++++-- doc/NPCs.md | 4 +++- src/condition.cpp | 17 +++++++++++++- src/condition.h | 3 ++- src/dialogue.h | 1 + src/npctalk.cpp | 36 +++++++++++++++++++++++++----- src/suffer.cpp | 6 ----- src/talker.h | 3 +++ src/talker_character.cpp | 8 ++++++- src/talker_character.h | 1 + 10 files changed, 78 insertions(+), 18 deletions(-) diff --git a/data/json/effect_on_condition.json b/data/json/effect_on_condition.json index dc0db08616435..ce8a99fc4ff9d 100644 --- a/data/json/effect_on_condition.json +++ b/data/json/effect_on_condition.json @@ -14,7 +14,7 @@ "deactivate_condition": { "not": { "or": [ { "is_weather": "thunder" }, { "is_weather": "lightning" } ] } }, "effect": [ { "message": "You hear a distant rumble of thunder.", "sound": true }, - { "sound_effect": "thunder_far", "outdoor_event": true } + { "sound_effect": "thunder_far", "outdoor_event": true, "id": "environment" } ] }, { @@ -26,7 +26,7 @@ "deactivate_condition": { "not": { "is_weather": "lightning" } }, "effect": [ { "message": "A flash of lightning illuminates your surroundings!" }, - { "sound_effect": "thunder_near" }, + { "sound_effect": "thunder_near", "id": "environment" }, "lightning" ] }, @@ -74,5 +74,18 @@ "condition": { "and": [ { "is_weather": "snowstorm" }, "u_is_outside" ] }, "deactivate_condition": { "not": { "is_weather": "snowstorm" } }, "effect": [ { "u_add_wet": 40 } ] + }, + { + "type": "effect_on_condition", + "id": "bio_drain", + "recurrence_min": "30 minutes", + "recurrence_max": "1 hours 30 minutes", + "condition": { "and": [ { "u_has_bionics": "bio_drain" }, { "u_has_power": "24 kJ" } ] }, + "deactivate_condition": { "not": { "u_has_bionics": "bio_drain" } }, + "effect": [ + { "message": "Your batteries discharge slightly.", "type": "bad" }, + { "sound_effect": "elec_crackle_low", "id": "bionics", "volume": 100 }, + { "u_add_power": "-25kJ" } + ] } ] diff --git a/doc/NPCs.md b/doc/NPCs.md index 5f9e5f18d9a80..0062c4628488a 100644 --- a/doc/NPCs.md +++ b/doc/NPCs.md @@ -488,6 +488,7 @@ Effect | Description `npc_first_topic: talk_topic_string` | Changes the initial talk_topic of the NPC in all future dialogues. `u_mod_pain: pain_int`
`npc_mod_pain: pain_int` | Your character or the NPC will have `pain_int` added or subtracted from its pain. `u_add_wet: wet_int`
`npc_add_wet: wet_int` | Your character or the NPC will be wet `wet_int` as if they were in the rain. +`u_add_power: power_energy`
`npc_add_power: power_energy` | Your character or the NPC will have `power_energy` added or subtracted from its bionic power. #### Trade / Items @@ -557,7 +558,7 @@ Effect | Description Effect | Description ---|--- `message: message_string`, (*optional* `sound: sound_bool`),(*optional* `outdoor_only: outdoor_only_bool`),(*optional* `snippet: snippet_bool`),(*optional* `type: type_string`),(*optional* `popup: popup_bool`) | Displays a message to the player of `message_string`. If `snippet_bool` is true(defaults to false) it will instead display a random snippet from `message_string` category. If `sound` is true(defaults to false) it will only display the message if the player is not deaf. `outdoor_only`(defaults to false) only matters when `sound` is true and will make the message less likely to be heard if the player is underground. Message will display as type of `type_string`. Type affects the color of message and can be any of the following values: good, neutral, bad, mixed, warning, info, debug, headshot, critical, grazing. enums.h has more info on each types use. If `popup_bool` is true the message will be in a modal popup the user has to dismiss to continue. -`sound_effect: sound_effect_id_string`, *optional* `outdoor_event: outdoor_event` | Will play a sound effect of type `sound_effect_id_string`. If `outdoor_event`(defaults to false) is true this will be less likely to play if the player is underground. +`sound_effect: sound_effect_id_string`, *optional* `sound_effect_variant: variant_string`, *optional* `outdoor_event: outdoor_event`,*optional* `volume: volume_int` | Will play a sound effect of id `sound_effect_id_string` and variant `variant_string`. If `volume_int` is defined it will be used otherwise 80 is the default. If `outdoor_event`(defaults to false) is true this will be less likely to play if the player is underground. #### Deprecated @@ -636,6 +637,7 @@ Condition | Type | Description `"u_is_height"`
`"npc_is_height"` | int | `true` if the player character's or NPC's elevation is at least the value of `u_is_height` or `npc_is_height`. `"u_has_worn_with_flag"`
`"npc_has_worn_with_flag"` | string | `true` if the player character or NPC is wearing something with the `u_has_worn_with_flag` or `npc_has_worn_with_flag` flag. `"u_has_wielded_with_flag"`
`"npc_has_wielded_with_flag"` | string | `true` if the player character or NPC is wielding something with the `u_has_wielded_with_flag` or `npc_has_wielded_with_flag` flag. +`"u_has_power"`
`"npc_has_power"` | int | `true` if the player character's or NPC's bionic power is at least the value of `u_has_power` or `npc_has_power`. #### Player Only conditions diff --git a/src/condition.cpp b/src/condition.cpp index 10aae878264d7..e454446372227 100644 --- a/src/condition.cpp +++ b/src/condition.cpp @@ -918,6 +918,17 @@ void conditional_t::set_has_pain( const JsonObject &jo, const std::string &me }; } +template +void conditional_t::set_has_power( const JsonObject &jo, const std::string &member, + bool is_npc ) +{ + units::energy min_power; + assign( jo, member, min_power, false, 0_kJ ); + condition = [min_power, is_npc]( const T & d ) { + return d.actor( is_npc )->power_cur() >= min_power; + }; +} + template conditional_t::conditional_t( const JsonObject &jo ) { @@ -1120,8 +1131,12 @@ conditional_t::conditional_t( const JsonObject &jo ) set_has_wielded_with_flag( jo, "npc_has_wielded_with_flag", is_npc ); } else if( jo.has_member( "u_has_pain" ) ) { set_has_pain( jo, "u_has_pain" ); - } else if( jo.has_int( "npc_has_pain" ) ) { + } else if( jo.has_member( "npc_has_pain" ) ) { set_has_pain( jo, "npc_has_pain", is_npc ); + } else if( jo.has_member( "u_has_power" ) ) { + set_has_power( jo, "u_has_power" ); + } else if( jo.has_member( "npc_has_power" ) ) { + set_has_power( jo, "npc_has_power", is_npc ); } else if( jo.has_string( "is_weather" ) ) { set_is_weather( jo ); } else { diff --git a/src/condition.h b/src/condition.h index 25af633754c12..6c72715de9b9c 100644 --- a/src/condition.h +++ b/src/condition.h @@ -46,7 +46,7 @@ const std::unordered_set complex_conds = { { "u_compare_time_since_var", "npc_compare_time_since_var", "is_weather", "one_in_chance", "is_temperature", "is_windpower", "is_humidity", "is_pressure", "u_is_height", "npc_is_height", "u_has_worn_with_flag", "npc_has_worn_with_flag", "u_has_wielded_with_flag", "npc_has_wielded_with_flag", - "u_has_pain", "npc_has_pain" + "u_has_pain", "npc_has_pain", "u_has_power", "npc_has_power" } }; } // namespace dialogue_data @@ -92,6 +92,7 @@ struct conditional_t { void set_has_intelligence( const JsonObject &jo, const std::string &member, bool is_npc = false ); void set_has_perception( const JsonObject &jo, const std::string &member, bool is_npc = false ); void set_has_pain( const JsonObject &jo, const std::string &member, bool is_npc = false ); + void set_has_power( const JsonObject &jo, const std::string &member, bool is_npc = false ); void set_one_in_chance( const JsonObject &jo, const std::string &member ); void set_is_temperature( const JsonObject &jo, const std::string &member ); void set_is_height( const JsonObject &jo, const std::string &member, bool is_npc = false ); diff --git a/src/dialogue.h b/src/dialogue.h index c707b594a7b63..0ea3acb49d395 100644 --- a/src/dialogue.h +++ b/src/dialogue.h @@ -102,6 +102,7 @@ struct talk_effect_fun_t { void set_message( const JsonObject &jo, const std::string &member ); void set_mod_pain( const JsonObject &jo, const std::string &member, bool is_npc ); void set_add_wet( const JsonObject &jo, const std::string &member, bool is_npc ); + void set_add_power( const JsonObject &jo, const std::string &member, bool is_npc ); void set_sound_effect( const JsonObject &jo, const std::string &member ); void set_add_var( const JsonObject &jo, const std::string &member, bool is_npc = false ); void set_remove_var( const JsonObject &jo, const std::string &member, bool is_npc = false ); diff --git a/src/npctalk.cpp b/src/npctalk.cpp index a5f09105e21b6..9c1807edd5e80 100644 --- a/src/npctalk.cpp +++ b/src/npctalk.cpp @@ -2154,24 +2154,44 @@ void talk_effect_fun_t::set_add_wet( const JsonObject &jo, const std::string &me void talk_effect_fun_t::set_sound_effect( const JsonObject &jo, const std::string &member ) { - std::string sound_effect = jo.get_string( member ); + std::string variant = jo.get_string( member ); + std::string id = jo.get_string( "id" ); const bool outdoor_event = jo.get_bool( "outdoor_event", false ); - function = [sound_effect, outdoor_event]( const dialogue & d ) { + const int volume = jo.get_int( "volume", -1 ); + function = [variant, id, outdoor_event, volume]( const dialogue & d ) { map &here = get_map(); - + int local_volume = volume; Character *target = d.alpha->get_character(); if( target && !target->has_effect( effect_sleep ) && !target->is_deaf() ) { if( !outdoor_event || here.get_abs_sub().z >= 0 ) { - sfx::play_variant_sound( "environment", sound_effect, 80, random_direction() ); + if( local_volume == -1 ) { + local_volume = 80; + } + sfx::play_variant_sound( id, variant, local_volume, random_direction() ); } else if( one_in( std::max( roll_remainder( 2.0f * here.get_abs_sub().z / target->mutation_value( "hearing_modifier" ) ), 1 ) ) ) { - sfx::play_variant_sound( "environment", sound_effect, - ( 80 * target->mutation_value( "hearing_modifier" ) ), random_direction() ); + if( local_volume == -1 ) { + local_volume = 80 * target->mutation_value( "hearing_modifier" ); + } + sfx::play_variant_sound( id, variant, local_volume, random_direction() ); } } }; } +void talk_effect_fun_t::set_add_power( const JsonObject &jo, const std::string &member, + bool is_npc ) +{ + units::energy amount; + assign( jo, member, amount, false ); + function = [is_npc, amount]( const dialogue & d ) { + Character *target = d.actor( is_npc )->get_character(); + if( target ) { + target->mod_power_level( amount ); + } + }; +} + void talk_effect_t::set_effect_consequence( const talk_effect_fun_t &fun, dialogue_consequence con ) { @@ -2421,6 +2441,10 @@ void talk_effect_t::parse_sub_effect( const JsonObject &jo ) subeffect_fun.set_add_wet( jo, "u_add_wet", false ); } else if( jo.has_int( "npc_add_wet" ) ) { subeffect_fun.set_add_wet( jo, "npc_add_wet", true ); + } else if( jo.has_member( "u_add_power" ) ) { + subeffect_fun.set_add_power( jo, "u_add_power", false ); + } else if( jo.has_member( "npc_add_power" ) ) { + subeffect_fun.set_add_power( jo, "npc_add_power", true ); } else { jo.throw_error( "invalid sub effect syntax: " + jo.str() ); } diff --git a/src/suffer.cpp b/src/suffer.cpp index 6af3cbb4763ce..a4bb582b0ca5c 100644 --- a/src/suffer.cpp +++ b/src/suffer.cpp @@ -62,7 +62,6 @@ static const bionic_id bio_dis_acid( "bio_dis_acid" ); static const bionic_id bio_dis_shock( "bio_dis_shock" ); -static const bionic_id bio_drain( "bio_drain" ); static const bionic_id bio_geiger( "bio_geiger" ); static const bionic_id bio_gills( "bio_gills" ); static const bionic_id bio_glowy( "bio_glowy" ); @@ -1183,11 +1182,6 @@ void Character::suffer_from_bad_bionics() sfx::play_variant_sound( "bionics", "acid_discharge", 100 ); sfx::do_player_death_hurt( get_player_character(), false ); } - if( has_bionic( bio_drain ) && get_power_level() > 24_kJ && one_turn_in( 1_hours ) ) { - add_msg_if_player( m_bad, _( "Your batteries discharge slightly." ) ); - mod_power_level( -25_kJ ); - sfx::play_variant_sound( "bionics", "elec_crackle_low", 100 ); - } if( has_bionic( bio_noise ) && one_turn_in( 50_minutes ) && !has_effect( effect_narcosis ) ) { // TODO: NPCs with said bionic diff --git a/src/talker.h b/src/talker.h index c7f1655461fb9..a548cc95274d7 100644 --- a/src/talker.h +++ b/src/talker.h @@ -324,5 +324,8 @@ class talker virtual bool wielded_with_flag( const flag_id & ) const { return false; } + virtual units::energy power_cur() const { + return 0_kJ; + } }; #endif // CATA_SRC_TALKER_H diff --git a/src/talker_character.cpp b/src/talker_character.cpp index ab6f12029ed57..b233df97b98a0 100644 --- a/src/talker_character.cpp +++ b/src/talker_character.cpp @@ -292,7 +292,7 @@ void talker_character::shout( const std::string &speech, bool order ) { me_chr->shout( speech, order ); } -\ + int talker_character::pain_cur() const { return me_chr->get_pain(); @@ -312,3 +312,9 @@ bool talker_character::wielded_with_flag( const flag_id &flag ) const { return me_chr->weapon.has_flag( flag ); } + +units::energy talker_character::power_cur() const +{ + return me_chr->get_power_level(); +} + diff --git a/src/talker_character.h b/src/talker_character.h index bc0fb7f38a914..782c0ca41483b 100644 --- a/src/talker_character.h +++ b/src/talker_character.h @@ -56,6 +56,7 @@ class talker_character: public talker int int_cur() const override; int per_cur() const override; int pain_cur() const override; + units::energy power_cur() const override; bool has_trait( const trait_id &trait_to_check ) const override; void set_mutation( const trait_id &new_trait ) override; void unset_mutation( const trait_id &old_trait ) override; From 8a04ce8c53864171933fd404c062144900ffc632 Mon Sep 17 00:00:00 2001 From: LaVeyanFiend <51099123+LaVeyanFiend@users.noreply.github.com> Date: Tue, 6 Apr 2021 09:09:00 -0400 Subject: [PATCH 344/453] Mutations + Bionics: The Cancelling (#47117) --- data/json/bionics.json | 300 ++++++++++++++++++++++++++++++++++++++++- 1 file changed, 293 insertions(+), 7 deletions(-) diff --git a/data/json/bionics.json b/data/json/bionics.json index 68895c5982d83..bfd725cf142fb 100644 --- a/data/json/bionics.json +++ b/data/json/bionics.json @@ -46,7 +46,78 @@ "bash_protec": [ [ "arm_l", 3 ], [ "arm_r", 3 ] ], "cut_protec": [ [ "arm_l", 3 ], [ "arm_r", 3 ] ], "bullet_protec": [ [ "arm_l", 3 ], [ "arm_r", 3 ] ], - "flags": [ "BIONIC_NPC_USABLE", "BIONIC_SHOCKPROOF" ] + "flags": [ "BIONIC_NPC_USABLE", "BIONIC_SHOCKPROOF" ], + "mutation_conflicts": [ + "THICKSKIN", + "THINSKIN", + "ALBINO", + "SKIN_ROUGH", + "M_SKIN", + "M_SKIN2", + "M_SKIN3", + "SCALES", + "THICK_SCALES", + "SLEEK_SCALES", + "FEATHERS", + "DOWN", + "LIGHTFUR", + "FUR", + "URSINE_FUR", + "LUPINE_FUR", + "FELINE_FUR", + "LYNX_FUR", + "CHITIN", + "CHITIN2", + "CHITIN3", + "CHITIN_FUR", + "CHITIN_FUR2", + "CHITIN_FUR3", + "CF_HAIR", + "SPINES", + "QUILLS", + "BARBS", + "PLANTSKIN", + "BARK", + "THORNS", + "LEAVES", + "LEAVES2", + "LEAVES3", + "SLIMY", + "VISCOUS", + "AMORPHOUS", + "BENDY1", + "BENDY2", + "BENDY3", + "WINGS_BIRD", + "WINGS_INSECT", + "LARGE", + "LARGE_OK", + "HUGE", + "HUGE_OK", + "SMALL", + "SMALL2", + "SMALL_OK", + "WINGS_STUB", + "WINGS_BAT", + "WINGS_BUTTERFLY", + "PALE", + "SPOTS", + "SUNBURN", + "SORES", + "CHLOROMORPH", + "ARM_FEATHERS", + "INSECT_ARMS", + "INSECT_ARMS_OK", + "ARACHNID_ARMS", + "ARACHNID_ARMS_OK", + "ARM_TENTACLES", + "ARM_TENTACLES_4", + "ARM_TENTACLES_8", + "CLAWS_TENTACLES", + "ACIDPROOF", + "TOXICFLESH", + "FRESHWATEROSMOSIS" + ] }, { "id": "bio_armor_eyes", @@ -58,7 +129,7 @@ "bash_protec": [ [ "eyes", 3 ] ], "cut_protec": [ [ "eyes", 3 ] ], "bullet_protec": [ [ "eyes", 3 ] ], - "flags": [ "BIONIC_NPC_USABLE", "BIONIC_SHOCKPROOF" ], + "mutation_conflicts": [ "COMPOUND_EYES", "CEPH_VISION", "CEPH_EYES", "EYEBULGE" ], "social_modifiers": { "intimidate": 10 } }, { @@ -70,7 +141,85 @@ "bash_protec": [ [ "head", 3 ] ], "cut_protec": [ [ "head", 3 ] ], "bullet_protec": [ [ "head", 3 ] ], - "flags": [ "BIONIC_NPC_USABLE", "BIONIC_SHOCKPROOF" ] + "flags": [ "BIONIC_NPC_USABLE", "BIONIC_SHOCKPROOF" ], + "mutation_conflicts": [ + "THICKSKIN", + "THINSKIN", + "ALBINO", + "SKIN_ROUGH", + "M_SKIN", + "M_SKIN2", + "M_SKIN3", + "SCALES", + "THICK_SCALES", + "SLEEK_SCALES", + "FEATHERS", + "DOWN", + "LIGHTFUR", + "FUR", + "URSINE_FUR", + "LUPINE_FUR", + "FELINE_FUR", + "LYNX_FUR", + "CHITIN", + "CHITIN2", + "CHITIN3", + "CHITIN_FUR", + "CHITIN_FUR2", + "CHITIN_FUR3", + "CF_HAIR", + "SPINES", + "QUILLS", + "BARBS", + "PLANTSKIN", + "BARK", + "THORNS", + "LEAVES", + "LEAVES2", + "LEAVES3", + "SLIMY", + "VISCOUS", + "AMORPHOUS", + "LARGE", + "LARGE_OK", + "HUGE", + "HUGE_OK", + "SMALL", + "SMALL2", + "SMALL_OK", + "PALE", + "SPOTS", + "SUNBURN", + "SORES", + "CHLOROMORPH", + "ACIDPROOF", + "TOXICFLESH", + "FRESHWATEROSMOSIS", + "BIOLUM0", + "BIOLUM0_active", + "BIOLUM1", + "BIOLUM1_active", + "BIOLUM2", + "BIOLUM2_active", + "GILLS", + "GILLS_CEPH", + "FLOWERS", + "ROSEBUDS", + "HORNS", + "HORNS_CURLED", + "HORNS_POINTED", + "ANTLERS", + "ANTENNAE", + "HEADBUMPS", + "HAIRROOTS", + "SNOUT", + "MINOTAUR", + "MUZZLE", + "MUZZLE_BEAR", + "MUZZLE_RAT", + "MUZZLE_LONG", + "PROBISCIS" + ] }, { "id": "bio_armor_legs", @@ -81,7 +230,76 @@ "bash_protec": [ [ "leg_l", 3 ], [ "leg_r", 3 ] ], "cut_protec": [ [ "leg_l", 3 ], [ "leg_r", 3 ] ], "bullet_protec": [ [ "leg_l", 3 ], [ "leg_r", 3 ] ], - "flags": [ "BIONIC_NPC_USABLE", "BIONIC_SHOCKPROOF" ] + "flags": [ "BIONIC_NPC_USABLE", "BIONIC_SHOCKPROOF" ], + "mutation_conflicts": [ + "THICKSKIN", + "THINSKIN", + "ALBINO", + "SKIN_ROUGH", + "M_SKIN", + "M_SKIN2", + "M_SKIN3", + "SCALES", + "THICK_SCALES", + "SLEEK_SCALES", + "FEATHERS", + "DOWN", + "LIGHTFUR", + "FUR", + "URSINE_FUR", + "LUPINE_FUR", + "FELINE_FUR", + "LYNX_FUR", + "CHITIN", + "CHITIN2", + "CHITIN3", + "CHITIN_FUR", + "CHITIN_FUR2", + "CHITIN_FUR3", + "CF_HAIR", + "SPINES", + "QUILLS", + "BARBS", + "PLANTSKIN", + "BARK", + "THORNS", + "LEAVES", + "LEAVES2", + "LEAVES3", + "SLIMY", + "VISCOUS", + "AMORPHOUS", + "BENDY1", + "BENDY2", + "BENDY3", + "LARGE", + "LARGE_OK", + "HUGE", + "HUGE_OK", + "SMALL", + "SMALL2", + "SMALL_OK", + "PALE", + "SPOTS", + "SUNBURN", + "SORES", + "CHLOROMORPH", + "ACIDPROOF", + "TOXICFLESH", + "FRESHWATEROSMOSIS", + "TAIL_STUB", + "TAIL_FIN", + "TAIL_LONG", + "TAIL_CATTLE", + "TAIL_RAT", + "TAIL_THICK", + "TAIL_RAPTOR", + "TAIL_FLUFFY", + "TAIL_STING", + "TAIL_CLUB", + "LEG_TENTACLES", + "LEG_TENT_BRACE" + ] }, { "id": "bio_armor_torso", @@ -92,7 +310,73 @@ "bash_protec": [ [ "torso", 3 ] ], "cut_protec": [ [ "torso", 3 ] ], "bullet_protec": [ [ "torso", 3 ] ], - "flags": [ "BIONIC_NPC_USABLE", "BIONIC_SHOCKPROOF" ] + "flags": [ "BIONIC_NPC_USABLE", "BIONIC_SHOCKPROOF" ], + "canceled_mutations": [ "VINES1", "VINES2", "VINES3" ], + "mutation_conflicts": [ + "THICKSKIN", + "THINSKIN", + "ALBINO", + "SKIN_ROUGH", + "M_SKIN", + "M_SKIN2", + "M_SKIN3", + "SCALES", + "THICK_SCALES", + "SLEEK_SCALES", + "FEATHERS", + "DOWN", + "LIGHTFUR", + "FUR", + "URSINE_FUR", + "LUPINE_FUR", + "FELINE_FUR", + "LYNX_FUR", + "CHITIN", + "CHITIN2", + "CHITIN3", + "CHITIN_FUR", + "CHITIN_FUR2", + "CHITIN_FUR3", + "CF_HAIR", + "SPINES", + "QUILLS", + "BARBS", + "PLANTSKIN", + "BARK", + "THORNS", + "LEAVES", + "LEAVES2", + "LEAVES3", + "SLIMY", + "VISCOUS", + "AMORPHOUS", + "BENDY1", + "BENDY2", + "BENDY3", + "LARGE", + "LARGE_OK", + "HUGE", + "HUGE_OK", + "SMALL", + "SMALL2", + "SMALL_OK", + "PALE", + "SPOTS", + "SUNBURN", + "SORES", + "CHLOROMORPH", + "ACIDPROOF", + "TOXICFLESH", + "FRESHWATEROSMOSIS", + "INK_GLANDS", + "INSECT_ARMS", + "INSECT_ARMS_OK", + "ARACHNID_ARMS", + "ARACHNID_ARMS_OK", + "CLAWS_TENTACLES", + "SHELL", + "SHELL2" + ] }, { "id": "bio_batteries", @@ -1134,7 +1418,8 @@ "name": { "str": "Joint Servo" }, "description": "Your leg joints have been equipped with servomotors that provide power-assisted movement. They are optimized for running, but walking also requires less effort when this bionic is online. However, when it's offline it will hamper your movement, as you struggle against its moving parts.", "occupied_bodyparts": [ [ "leg_l", 12 ], [ "leg_r", 12 ] ], - "flags": [ "BIONIC_TOGGLED" ] + "flags": [ "BIONIC_TOGGLED" ], + "mutation_conflicts": [ "LEG_TENTACLES", "LEG_TENT_BRACE" ] }, { "id": "bio_trip", @@ -1170,7 +1455,8 @@ "description": "You will likely spend the rest of your days serving as a walking testament to why you don't opt for the Autodoc's 'Cyborg Identity Package'. A remodulator unit jammed down your throat has given you a creepy robot voice.", "occupied_bodyparts": [ [ "torso", 2 ], [ "mouth", 1 ] ], "flags": [ "BIONIC_FAULTY" ], - "social_modifiers": { "persuade": -20, "lie": 10, "intimidate": 20 } + "social_modifiers": { "persuade": -20, "lie": 10, "intimidate": 20 }, + "canceled_mutations": [ "GROWL", "SNARL", "HISS" ] }, { "id": "bio_watch", From e10feb35ab9bcbde5d151578bd0823e79c1f95e7 Mon Sep 17 00:00:00 2001 From: Shadestyle <35916758+Shadestyle@users.noreply.github.com> Date: Tue, 6 Apr 2021 13:00:54 -0500 Subject: [PATCH 345/453] Add Underground Pit Digging (#47943) --- data/json/construction.json | 12 +++ data/json/construction_group.json | 5 ++ .../recipe_modular_canteen_common.json | 12 +-- .../recipe_modular_field_common.json | 8 +- .../recipe_modular_field_defenses.json | 80 +++++++++++++------ .../basecamps/recipe_primitive_field.json | 40 +++++++--- 6 files changed, 111 insertions(+), 46 deletions(-) diff --git a/data/json/construction.json b/data/json/construction.json index 947fc9a81384b..5875ed28a0102 100644 --- a/data/json/construction.json +++ b/data/json/construction.json @@ -59,6 +59,18 @@ "pre_terrain": "t_pit", "post_terrain": "t_pit_glass" }, + { + "type": "construction", + "id": "constr_pit_underground", + "group": "underground_pit", + "category": "DIG", + "qualities": [ [ { "id": "DIG", "level": 2 } ] ], + "required_skills": [ [ "survival", 3 ] ], + "time": "300 m", + "tools": [ [ [ "pickaxe", -1 ], [ "jackhammer", 140 ], [ "elec_jackhammer", 7000 ] ] ], + "pre_terrain": "t_rock_floor", + "post_terrain": "t_pit" + }, { "type": "construction", "id": "constr_chop_trunk", diff --git a/data/json/construction_group.json b/data/json/construction_group.json index e70f44cdf54a2..919aad6e06529 100644 --- a/data/json/construction_group.json +++ b/data/json/construction_group.json @@ -844,6 +844,11 @@ "id": "dig_a_deep_pit", "name": "Dig a Deep Pit" }, + { + "type": "construction_group", + "id": "underground_pit", + "name": "Dig a Deep Pit Underground" + }, { "type": "construction_group", "id": "dig_a_shallow_pit", diff --git a/data/json/recipes/basecamps/recipe_modular_canteen/recipe_modular_canteen_common.json b/data/json/recipes/basecamps/recipe_modular_canteen/recipe_modular_canteen_common.json index 9b0bf13067490..295a53a00ce0f 100644 --- a/data/json/recipes/basecamps/recipe_modular_canteen/recipe_modular_canteen_common.json +++ b/data/json/recipes/basecamps/recipe_modular_canteen/recipe_modular_canteen_common.json @@ -175,19 +175,19 @@ "blueprint_provides": [ { "id": "fbmk_pantry_furniture" }, { "id": "pantry" } ], "blueprint_excludes": [ { "id": "fbmk_pantry_furniture" } ], "blueprint_needs": { - "time": "1 d 4 h 20 m", - "skills": [ [ "cooking", 3 ], [ "fabrication", 4 ], [ "survival", 4 ] ], + "time": "1 d 9 h 20 m", + "skills": [ [ "survival", 4 ], [ "fabrication", 4 ], [ "cooking", 3 ] ], "inline": { - "tools": [ ], + "tools": [ [ [ "elec_jackhammer", 14000 ], [ "jackhammer", 280 ], [ "pickaxe", -1 ] ] ], "qualities": [ [ { "id": "DIG", "level": 2 } ], [ { "id": "HAMMER", "level": 2 } ], [ { "id": "SAW_W" } ] ], "components": [ [ [ "2x4", 112 ] ], - [ [ "wood_sheet", 24 ], [ "wood_panel", 48 ] ], + [ [ "brick", 80 ], [ "rock", 80 ] ], [ [ "nail", 504 ] ], [ [ "sheet_metal_small", 24 ] ], + [ [ "straw_pile", 24 ], [ "withered", 24 ] ], [ [ "water_faucet", 2 ] ], - [ [ "rock", 80 ], [ "brick", 80 ] ], - [ [ "withered", 24 ], [ "straw_pile", 24 ] ] + [ [ "wood_panel", 48 ], [ "wood_sheet", 24 ] ] ] } } diff --git a/data/json/recipes/basecamps/recipe_modular_field_common.json b/data/json/recipes/basecamps/recipe_modular_field_common.json index 83877967fef30..97a42204ed3f1 100644 --- a/data/json/recipes/basecamps/recipe_modular_field_common.json +++ b/data/json/recipes/basecamps/recipe_modular_field_common.json @@ -897,12 +897,12 @@ "blueprint_provides": [ { "id": "pantry" } ], "blueprint_requires": [ { "id": "fbmh_northeast", "amount": 4 }, { "id": "fbmh_fire_northeast" }, { "id": "fbmh_bed2_northeast" } ], "blueprint_needs": { - "time": "4 h 40 m", - "skills": [ [ "fabrication", 4 ], [ "survival", 4 ] ], + "time": "7 h 10 m", + "skills": [ [ "survival", 4 ], [ "fabrication", 4 ] ], "inline": { - "tools": [ ], + "tools": [ [ [ "elec_jackhammer", 7000 ], [ "jackhammer", 140 ], [ "pickaxe", -1 ] ] ], "qualities": [ [ { "id": "DIG", "level": 2 } ], [ { "id": "HAMMER", "level": 2 } ] ], - "components": [ [ [ "rock", 40 ], [ "brick", 40 ] ], [ [ "2x4", 6 ], [ "stick", 6 ] ], [ [ "withered", 12 ], [ "straw_pile", 12 ] ] ] + "components": [ [ [ "2x4", 6 ], [ "stick", 6 ] ], [ [ "brick", 40 ], [ "rock", 40 ] ], [ [ "straw_pile", 12 ], [ "withered", 12 ] ] ] } } }, diff --git a/data/json/recipes/basecamps/recipe_modular_field_defenses.json b/data/json/recipes/basecamps/recipe_modular_field_defenses.json index 20af1b5d800d4..b1df09f3d343b 100644 --- a/data/json/recipes/basecamps/recipe_modular_field_defenses.json +++ b/data/json/recipes/basecamps/recipe_modular_field_defenses.json @@ -14,9 +14,13 @@ "blueprint_requires": [ { "id": "fbmh_northeast", "amount": 4 }, { "id": "fbmh_fire_northeast" }, { "id": "fbmh_bed2_northeast" } ], "blueprint_excludes": [ { "id": "fbm_no_dig" } ], "blueprint_needs": { - "time": "1 d 21 h", - "skills": [ [ "survival", 1 ] ], - "inline": { "tools": [ ], "qualities": [ [ { "id": "DIG", "level": 2 } ] ], "components": [ ] } + "time": "3 d 18 h", + "skills": [ [ "survival", 3 ] ], + "inline": { + "tools": [ [ [ "elec_jackhammer", 126000 ], [ "jackhammer", 2520 ], [ "pickaxe", -1 ] ] ], + "qualities": [ [ { "id": "DIG", "level": 2 } ] ], + "components": [ ] + } } }, { @@ -34,9 +38,13 @@ "blueprint_requires": [ { "id": "fbmh_northeast", "amount": 4 }, { "id": "fbmh_fire_northeast" }, { "id": "fbmh_bed2_northeast" } ], "blueprint_excludes": [ { "id": "fbm_no_dig" } ], "blueprint_needs": { - "time": "1 d 21 h", - "skills": [ [ "survival", 1 ] ], - "inline": { "tools": [ ], "qualities": [ [ { "id": "DIG", "level": 2 } ] ], "components": [ ] } + "time": "3 d 18 h", + "skills": [ [ "survival", 3 ] ], + "inline": { + "tools": [ [ [ "elec_jackhammer", 126000 ], [ "jackhammer", 2520 ], [ "pickaxe", -1 ] ] ], + "qualities": [ [ { "id": "DIG", "level": 2 } ] ], + "components": [ ] + } } }, { @@ -54,9 +62,13 @@ "blueprint_requires": [ { "id": "fbmh_northeast", "amount": 4 }, { "id": "fbmh_fire_northeast" }, { "id": "fbmh_bed2_northeast" } ], "blueprint_excludes": [ { "id": "fbm_no_dig" }, { "id": "fbmh_trench_northeast" }, { "id": "fbmh_trench_east" } ], "blueprint_needs": { - "time": "12 h 30 m", - "skills": [ [ "survival", 1 ] ], - "inline": { "tools": [ ], "qualities": [ [ { "id": "DIG", "level": 2 } ] ], "components": [ ] } + "time": "1 d 1 h", + "skills": [ [ "survival", 3 ] ], + "inline": { + "tools": [ [ [ "elec_jackhammer", 35000 ], [ "jackhammer", 700 ], [ "pickaxe", -1 ] ] ], + "qualities": [ [ { "id": "DIG", "level": 2 } ] ], + "components": [ ] + } } }, { @@ -74,9 +86,13 @@ "blueprint_requires": [ { "id": "fbmh_northeast", "amount": 4 }, { "id": "fbmh_fire_northeast" }, { "id": "fbmh_bed2_northeast" } ], "blueprint_excludes": [ { "id": "fbm_no_dig" }, { "id": "fbmh_trench_northwest" }, { "id": "fbmh_trench_west" } ], "blueprint_needs": { - "time": "12 h 30 m", - "skills": [ [ "survival", 1 ] ], - "inline": { "tools": [ ], "qualities": [ [ { "id": "DIG", "level": 2 } ] ], "components": [ ] } + "time": "1 d 1 h", + "skills": [ [ "survival", 3 ] ], + "inline": { + "tools": [ [ [ "elec_jackhammer", 35000 ], [ "jackhammer", 700 ], [ "pickaxe", -1 ] ] ], + "qualities": [ [ { "id": "DIG", "level": 2 } ] ], + "components": [ ] + } } }, { @@ -94,9 +110,13 @@ "blueprint_requires": [ { "id": "fbmh_northeast", "amount": 4 }, { "id": "fbmh_fire_northeast" }, { "id": "fbmh_bed2_northeast" } ], "blueprint_excludes": [ { "id": "fbm_no_dig" }, { "id": "fbmh_trench_southeast" }, { "id": "fbmh_trench_east" } ], "blueprint_needs": { - "time": "12 h 30 m", - "skills": [ [ "survival", 1 ] ], - "inline": { "tools": [ ], "qualities": [ [ { "id": "DIG", "level": 2 } ] ], "components": [ ] } + "time": "1 d 1 h", + "skills": [ [ "survival", 3 ] ], + "inline": { + "tools": [ [ [ "elec_jackhammer", 35000 ], [ "jackhammer", 700 ], [ "pickaxe", -1 ] ] ], + "qualities": [ [ { "id": "DIG", "level": 2 } ] ], + "components": [ ] + } } }, { @@ -114,9 +134,13 @@ "blueprint_requires": [ { "id": "fbmh_northeast", "amount": 4 }, { "id": "fbmh_fire_northeast" }, { "id": "fbmh_bed2_northeast" } ], "blueprint_excludes": [ { "id": "fbm_no_dig" }, { "id": "fbmh_trench_southwest" }, { "id": "fbmh_trench_west" } ], "blueprint_needs": { - "time": "12 h 30 m", - "skills": [ [ "survival", 1 ] ], - "inline": { "tools": [ ], "qualities": [ [ { "id": "DIG", "level": 2 } ] ], "components": [ ] } + "time": "1 d 1 h", + "skills": [ [ "survival", 3 ] ], + "inline": { + "tools": [ [ [ "elec_jackhammer", 35000 ], [ "jackhammer", 700 ], [ "pickaxe", -1 ] ] ], + "qualities": [ [ { "id": "DIG", "level": 2 } ] ], + "components": [ ] + } } }, { @@ -134,9 +158,13 @@ "blueprint_requires": [ { "id": "fbmh_northeast", "amount": 4 }, { "id": "fbmh_fire_northeast" }, { "id": "fbmh_bed2_northeast" } ], "blueprint_excludes": [ { "id": "fbm_no_dig" }, { "id": "fbmh_trench_southeast" }, { "id": "fbmh_trench_northeast" } ], "blueprint_needs": { - "time": "2 d 22 h", - "skills": [ [ "survival", 1 ] ], - "inline": { "tools": [ ], "qualities": [ [ { "id": "DIG", "level": 2 } ] ], "components": [ ] } + "time": "5 d 20 h", + "skills": [ [ "survival", 3 ] ], + "inline": { + "tools": [ [ [ "elec_jackhammer", 196000 ], [ "jackhammer", 3920 ], [ "pickaxe", -1 ] ] ], + "qualities": [ [ { "id": "DIG", "level": 2 } ] ], + "components": [ ] + } } }, { @@ -154,9 +182,13 @@ "blueprint_requires": [ { "id": "fbmh_northeast", "amount": 4 }, { "id": "fbmh_fire_northeast" }, { "id": "fbmh_bed2_northeast" } ], "blueprint_excludes": [ { "id": "fbm_no_dig" }, { "id": "fbmh_trench_southwest" }, { "id": "fbmh_trench_northwest" } ], "blueprint_needs": { - "time": "2 d 22 h", - "skills": [ [ "survival", 1 ] ], - "inline": { "tools": [ ], "qualities": [ [ { "id": "DIG", "level": 2 } ] ], "components": [ ] } + "time": "5 d 20 h", + "skills": [ [ "survival", 3 ] ], + "inline": { + "tools": [ [ [ "elec_jackhammer", 196000 ], [ "jackhammer", 3920 ], [ "pickaxe", -1 ] ] ], + "qualities": [ [ { "id": "DIG", "level": 2 } ] ], + "components": [ ] + } } } ] diff --git a/data/json/recipes/basecamps/recipe_primitive_field.json b/data/json/recipes/basecamps/recipe_primitive_field.json index 28900960bfc0f..f0f3fe4b20c45 100644 --- a/data/json/recipes/basecamps/recipe_primitive_field.json +++ b/data/json/recipes/basecamps/recipe_primitive_field.json @@ -508,9 +508,13 @@ "time": "180 m", "blueprint_requires": [ { "id": "not_an_upgrade" } ], "blueprint_needs": { - "time": "5 h", - "skills": [ [ "survival", 1 ] ], - "inline": { "tools": [ ], "qualities": [ [ { "id": "DIG", "level": 2 } ] ], "components": [ ] } + "time": "10 h", + "skills": [ [ "survival", 3 ] ], + "inline": { + "tools": [ [ [ "elec_jackhammer", 14000 ], [ "jackhammer", 280 ], [ "pickaxe", -1 ] ] ], + "qualities": [ [ { "id": "DIG", "level": 2 } ] ], + "components": [ ] + } } }, { @@ -604,9 +608,13 @@ "time": "180 m", "blueprint_requires": [ { "id": "not_an_upgrade" } ], "blueprint_needs": { - "time": "15 h", - "skills": [ [ "survival", 1 ] ], - "inline": { "tools": [ ], "qualities": [ [ { "id": "DIG", "level": 2 } ] ], "components": [ ] } + "time": "1 d 6 h", + "skills": [ [ "survival", 3 ] ], + "inline": { + "tools": [ [ [ "elec_jackhammer", 42000 ], [ "jackhammer", 840 ], [ "pickaxe", -1 ] ] ], + "qualities": [ [ { "id": "DIG", "level": 2 } ] ], + "components": [ ] + } } }, { @@ -764,9 +772,13 @@ "time": "180 m", "blueprint_requires": [ { "id": "not_an_upgrade" } ], "blueprint_needs": { - "time": "12 h 30 m", - "skills": [ [ "survival", 1 ] ], - "inline": { "tools": [ ], "qualities": [ [ { "id": "DIG", "level": 2 } ] ], "components": [ ] } + "time": "1 d 1 h", + "skills": [ [ "survival", 3 ] ], + "inline": { + "tools": [ [ [ "elec_jackhammer", 35000 ], [ "jackhammer", 700 ], [ "pickaxe", -1 ] ] ], + "qualities": [ [ { "id": "DIG", "level": 2 } ] ], + "components": [ ] + } } }, { @@ -1023,9 +1035,13 @@ "blueprint_requires": [ { "id": "not_an_upgrade" } ], "time": "180 m", "blueprint_needs": { - "time": "15 h", - "skills": [ [ "survival", 1 ] ], - "inline": { "tools": [ ], "qualities": [ [ { "id": "DIG", "level": 2 } ] ], "components": [ ] } + "time": "1 d 6 h", + "skills": [ [ "survival", 3 ] ], + "inline": { + "tools": [ [ [ "elec_jackhammer", 42000 ], [ "jackhammer", 840 ], [ "pickaxe", -1 ] ] ], + "qualities": [ [ { "id": "DIG", "level": 2 } ] ], + "components": [ ] + } } }, { From 246b50d9e99d1da2f55a46ecb5b139f3c323e39c Mon Sep 17 00:00:00 2001 From: casswedson <58050969+casswedson@users.noreply.github.com> Date: Wed, 7 Apr 2021 03:34:10 -0500 Subject: [PATCH 346/453] Misc typographical fixes (#48346) * misc typographical fixes Co-authored-by: actual-nh <74678550+actual-nh@users.noreply.github.com> --- .../furniture-appliances.json | 2 +- .../furniture-recreation.json | 4 ++-- .../furniture_and_terrain/furniture-roof.json | 2 +- .../furniture-storage.json | 2 +- .../terrain-liquids.json | 4 ++-- .../terrain-windows.json | 20 +++++++++---------- data/json/items/armor/helmets.json | 2 +- data/json/items/armor/legs_armor.json | 6 +++--- data/json/items/armor/torso_armor.json | 4 ++-- data/json/items/armor/torso_clothes.json | 2 +- data/json/items/battery.json | 8 ++++---- data/json/items/gun/flintlock.json | 2 +- data/json/items/gun/shot.json | 4 ++-- data/json/items/tool/cooking.json | 2 +- data/json/monsters/jabberwock.json | 2 +- data/json/monsters/zed_acid.json | 2 +- data/json/monsters/zed_misc.json | 2 +- data/json/proficiencies/tailoring.json | 2 +- 18 files changed, 36 insertions(+), 36 deletions(-) diff --git a/data/json/furniture_and_terrain/furniture-appliances.json b/data/json/furniture_and_terrain/furniture-appliances.json index 905cfba830472..4c225a9d544e4 100644 --- a/data/json/furniture_and_terrain/furniture-appliances.json +++ b/data/json/furniture_and_terrain/furniture-appliances.json @@ -546,7 +546,7 @@ "id": "f_satellite", "name": "large satellite dish", "looks_like": "t_radio_tower", - "description": "A large concave metal panel with simple electronics used to receive signals from sattelites. While the hundreds of expensive machines orbitting the planet will likely continue to function indefinately, their various purposes have all been lost.", + "description": "A large, concave metal panel with simple electronics used to receive signals from satellites. While the hundreds of expensive machines orbiting the planet will likely continue to function indefinitely, their various purposes have all been lost.", "symbol": ")", "color": "white_green", "move_cost_mod": -1, diff --git a/data/json/furniture_and_terrain/furniture-recreation.json b/data/json/furniture_and_terrain/furniture-recreation.json index 7176dd4498e48..52759263e3958 100644 --- a/data/json/furniture_and_terrain/furniture-recreation.json +++ b/data/json/furniture_and_terrain/furniture-recreation.json @@ -123,7 +123,7 @@ "type": "furniture", "id": "f_arcade_machine", "name": "arcade machine", - "description": "A bulky upright arcade cabinet, brightly painted and slightyly worn with age. Useless for its intended purpose, it's bound to have valuable parts.", + "description": "A bulky upright arcade cabinet, brightly painted and slightly worn with age. Useless for its intended purpose, it's bound to have valuable parts.", "symbol": "6", "color": "red", "move_cost_mod": -1, @@ -211,7 +211,7 @@ "type": "furniture", "id": "f_ergometer", "name": "ergometer", - "description": "An exercise machine with a set of handles and plates meant to emulate rowing a boat. Without power it can't be operated, but it might have useful parts to be scavanged.", + "description": "An exercise machine with a set of handles and plates meant to emulate rowing a boat. Without power it can't be operated, but it might have useful parts to be scavenged.", "symbol": "5", "color": "dark_gray", "move_cost_mod": 2, diff --git a/data/json/furniture_and_terrain/furniture-roof.json b/data/json/furniture_and_terrain/furniture-roof.json index 372a2787c682d..e58575b943e9a 100644 --- a/data/json/furniture_and_terrain/furniture-roof.json +++ b/data/json/furniture_and_terrain/furniture-roof.json @@ -123,7 +123,7 @@ "type": "furniture", "id": "f_roof_turbine_vent", "name": "roof turbine vent", - "description": "A rotary wind turbine that will catch the wind and pull out air from inside. It is most commonly used for improving air cicrulation, particularly in poorly-ventilated areas like attics.", + "description": "A rotary wind turbine that will catch the wind and pull out air from inside. It is most commonly used for improving air circulation, particularly in poorly-ventilated areas like attics.", "symbol": "&", "color": "light_gray", "move_cost_mod": 2, diff --git a/data/json/furniture_and_terrain/furniture-storage.json b/data/json/furniture_and_terrain/furniture-storage.json index 65502b26f0ab0..f0949f3ed1c35 100644 --- a/data/json/furniture_and_terrain/furniture-storage.json +++ b/data/json/furniture_and_terrain/furniture-storage.json @@ -1128,7 +1128,7 @@ "type": "furniture", "id": "f_foot_locker", "name": "metal foot locker", - "description": "An metal stoarge box, capable of holding any number of things. The lid has has a small lock.", + "description": "A metal storage box, capable of holding any number of things. The lid has a small lock.", "symbol": "O", "color": "white", "move_cost_mod": -1, diff --git a/data/json/furniture_and_terrain/terrain-liquids.json b/data/json/furniture_and_terrain/terrain-liquids.json index fb3e646b576d1..30ffa1ce5953a 100644 --- a/data/json/furniture_and_terrain/terrain-liquids.json +++ b/data/json/furniture_and_terrain/terrain-liquids.json @@ -377,7 +377,7 @@ "id": "t_lake_bed_concrete_yellow", "//": "for eventual use with water z levels. Currently non-functional. Cement on the lake floor.", "name": "submerged concrete", - "description": "You are standing at the bottom of a body of fresh water on a pad of concrete with yelllow paint. With a watertight container, you could gather fresh water from here. Not safe to drink as is.", + "description": "You are standing at the bottom of a body of fresh water on a pad of yellow-painted concrete. With a watertight container, you could gather fresh water from here. Not safe to drink as is.", "symbol": "#", "looks_like": "t_pavement_y", "color": "yellow", @@ -397,7 +397,7 @@ "type": "terrain", "id": "t_water_hot", "name": "hot spring water", - "description": "Scalding hot water, not particulary safe for swimming. With a watertight container, you could gather fresh water from here. Not safe to drink as is.", + "description": "Scalding hot water, not particularly safe for swimming. With a watertight container, you could gather fresh water from here. Not safe to drink as is.", "symbol": "~", "color": "light_blue", "move_cost": 5, diff --git a/data/json/furniture_and_terrain/terrain-windows.json b/data/json/furniture_and_terrain/terrain-windows.json index 0c05005733ea8..89122004585c2 100644 --- a/data/json/furniture_and_terrain/terrain-windows.json +++ b/data/json/furniture_and_terrain/terrain-windows.json @@ -1724,7 +1724,7 @@ "type": "terrain", "id": "t_reinforced_double_pane_glass", "name": "Reinforced double glazed glass window", - "description": "A reinfoced double glazed window inserted into a frame. The outer layer comprises a pane of reinforced glass for extra security.", + "description": "A reinforced, double-glazed window inserted into a frame. For extra security, the outer layer is reinforced glass.", "looks_like": "t_window_no_curtains", "symbol": "\"", "color": "light_cyan", @@ -2984,7 +2984,7 @@ "type": "terrain", "id": "t_plastic_window_with_curtain", "name": "Plastic window with a curtain", - "description": "A makeshift window with a closed curtain. comprising a sheet of translucent, rigid plastic secured in a wooden frame. There are sheets drawn across it to block the light. It'll do in a pinch.", + "description": "A makeshift window with a closed curtain. It's a sheet of translucent, rigid plastic secured in a wooden frame. There are sheets drawn across it to block the light. It'll do in a pinch.", "looks_like": "t_curtains", "symbol": "|", "color": "light_blue", @@ -3022,7 +3022,7 @@ "type": "terrain", "id": "t_plastic_window_with_curtain_open_window_closed", "name": "Plastic window with a curtain", - "description": "A makeshift window with a opened curtain. comprising a sheet of translucent, rigid plastic secured in a wooden frame, with sheets strung about it to block the light as required. It'll do in a pinch.", + "description": "A makeshift window with a opened curtain. It's a sheet of translucent, rigid plastic secured in a wooden frame, with sheets strung about it to block the light as required. It'll do in a pinch.", "looks_like": "t_window_domestic", "symbol": "|", "color": "light_blue", @@ -3069,8 +3069,8 @@ { "type": "terrain", "id": "t_plastic_window_with_curtain_open", - "name": "Plastic window With a curtain", - "description": "An opened makeshift window with a opened curtain. comprising a sheet of translucent, rigid plastic secured in a wooden frame, with sheets strung about it to block the light as required. It'll do in a pinch.", + "name": "Plastic window with open curtains", + "description": "An open makeshift window with open curtains. It's a sheet of translucent, rigid plastic secured in a wooden frame, with sheets strung about it to block the light as required. It'll do in a pinch.", "looks_like": "t_window_open", "symbol": "|", "color": "light_blue", @@ -3213,7 +3213,7 @@ "type": "terrain", "id": "t_reinforced_plastic_window_with_curtain", "name": "Reinforced plastic window with a curtain", - "description": "A makeshift window with a closed curtain. comprising three sheets of translucent, rigid plastic secured in a wooden frame. It'll do in a pinch.", + "description": "A makeshift reinforced window with a closed curtain. It's three sheets of translucent, rigid plastic secured in a wooden frame. There are sheets drawn across it to block the light. It'll do in a pinch.", "looks_like": "t_curtains", "symbol": "|", "color": "light_blue", @@ -3263,8 +3263,8 @@ { "type": "terrain", "id": "t_reinforced_plastic_window_with_curtain_open_window_closed", - "name": "Reinforced plastic window with a curtain", - "description": "A makeshift window with a opened curtain. comprising three sheets of translucent, rigid plastic secured in a wooden frame. It'll do in a pinch.", + "name": "Reinforced plastic window with an open curtain", + "description": "A makeshift reinforced window with a opened curtain. It's three sheets of translucent, rigid plastic secured in a wooden frame, with sheets strung about it to block the light as required. It'll do in a pinch.", "looks_like": "t_window_domestic", "symbol": "|", "color": "light_blue", @@ -3316,8 +3316,8 @@ { "type": "terrain", "id": "t_reinforced_plastic_window_with_curtain_open", - "name": "Reinforced plastic window With a curtain", - "description": "An open makeshift window with a opened curtain. comprising three sheets of translucent, rigid plastic secured in a wooden frame. It'll do in a pinch.", + "name": "Reinforced plastic window with an open curtain", + "description": "An open makeshift reinforced window with a opened curtain. It's three sheets of translucent, rigid plastic secured in a wooden frame, with sheets strung about it to block the light as required. It'll do in a pinch.", "looks_like": "t_window_open", "symbol": "|", "color": "light_blue", diff --git a/data/json/items/armor/helmets.json b/data/json/items/armor/helmets.json index 3fd0ac7760cbb..82532ac251d44 100644 --- a/data/json/items/armor/helmets.json +++ b/data/json/items/armor/helmets.json @@ -441,7 +441,7 @@ "id": "helmet_skull", "type": "ARMOR", "name": { "str": "large wolf skull" }, - "description": "The top part of an unusually large wolf skull equiped with leather straps to secure it on your head. Every inch of it has been carved with a maze of fine intertwined symbols that make your eyes water.", + "description": "The top part of an unusually large wolf skull equipped with leather straps to secure it on your head. Every inch of it has been carved with a maze of fine intertwined symbols that make your eyes water.", "weight": "1 kg", "volume": "3 L", "price": 1400, diff --git a/data/json/items/armor/legs_armor.json b/data/json/items/armor/legs_armor.json index 045001ad7fd5e..0efcba5f75190 100644 --- a/data/json/items/armor/legs_armor.json +++ b/data/json/items/armor/legs_armor.json @@ -145,7 +145,7 @@ "id": "chaps_cut_resistant", "type": "ARMOR", "name": { "str_sp": "chainsaw chaps" }, - "description": "A pair of tough chaps made of kevlar. Chainsaw kickbacks are potentially fatal; personal protective equipment like these chaps help protect your femoral arteries. The layered kevlar is designed to fray on contact with the chain and bind up the tool.", + "description": "A pair of tough chaps made of Kevlar. Chainsaw kickbacks are potentially fatal; personal protective equipment like these chaps help protect your femoral arteries. The layered Kevlar is designed to fray on contact with the chain and bind up the tool.", "weight": "1519 g", "copy-from": "chaps_leather", "price": 7800, @@ -479,7 +479,7 @@ "type": "ARMOR", "category": "armor", "name": { "str_sp": "EOD trousers" }, - "description": "Thick armored trousers constructed from kevlar and nomex for explosive ordnance disposal. It is designed to protect against overpressure, fragmentation, impact and heat.", + "description": "Thick armored trousers constructed from Kevlar and Nomex for explosive ordnance disposal. They are designed to protect against overpressure, fragmentation, impact, and heat.", "weight": "6400 g", "volume": "12 L", "price": 200000, @@ -499,7 +499,7 @@ "type": "ARMOR", "category": "armor", "name": { "str_sp": "light EOD trousers" }, - "description": "Armored trousers constructed from kevlar and nomex designed to protect against overpressure, fragmentation, impact and heat in hostile environments. It is lighter than normal EOD armor to provide more maneuverability.", + "description": "Armored trousers constructed from Kevlar and Nomex, designed to protect against overpressure, fragmentation, impact, and heat in hostile environments. They are lighter than normal EOD armor to provide more maneuverability.", "weight": "3000 g", "volume": "12 L", "price": 200000, diff --git a/data/json/items/armor/torso_armor.json b/data/json/items/armor/torso_armor.json index b5f148f4ffa85..77e2660c19f8a 100644 --- a/data/json/items/armor/torso_armor.json +++ b/data/json/items/armor/torso_armor.json @@ -512,7 +512,7 @@ "type": "TOOL_ARMOR", "category": "armor", "name": { "str": "EOD jacket" }, - "description": "A thick armored jacket constructed from kevlar and nomex for explosive ordnance disposal. It is designed to protect against overpressure, fragmentation, impact and heat.", + "description": "A thick armored jacket constructed from Kevlar and Nomex for explosive ordnance disposal. It is designed to protect against overpressure, fragmentation, impact, and heat.", "weight": "16300 g", "volume": "15 L", "price": 200000, @@ -533,7 +533,7 @@ "type": "TOOL_ARMOR", "category": "armor", "name": { "str": "light EOD jacket" }, - "description": "An armored jacket constructed from kevlar and nomex designed to protect against overpressure, fragmentation, impact and heat in hostile environments. It is lighter than normal EOD armor to provide more maneuverability and can be worn over ballistic armor.", + "description": "An armored jacket constructed from Kevlar and Nomex, designed to protect against overpressure, fragmentation, impact, and heat in hostile environments. It is lighter than normal EOD armor to provide more maneuverability and can be worn over ballistic armor.", "weight": "7000 g", "volume": "15 L", "price": 200000, diff --git a/data/json/items/armor/torso_clothes.json b/data/json/items/armor/torso_clothes.json index 64d7524d89155..ba59311006616 100644 --- a/data/json/items/armor/torso_clothes.json +++ b/data/json/items/armor/torso_clothes.json @@ -31,7 +31,7 @@ "repairs_like": "apron_leather", "type": "ARMOR", "name": { "str": "cut-resistant apron" }, - "description": "An apron made of kevlar fabric which provides excellent protection from cuts.", + "description": "An apron made of Kevlar fabric which provides excellent protection from cuts.", "copy-from": "apron_leather", "price": 3800, "material": [ "kevlar" ] diff --git a/data/json/items/battery.json b/data/json/items/battery.json index bae1ef4a5f256..a3810b2ce5544 100644 --- a/data/json/items/battery.json +++ b/data/json/items/battery.json @@ -41,7 +41,7 @@ "type": "MAGAZINE", "category": "spare_parts", "name": { "str": "ultra-light plutonium fuel battery", "str_pl": "ultra-light plutonium fuel batteries" }, - "description": "This battery uses a thin plutonium-244 rod to stablize an exotic nanocompound. It is universally compatible with small devices. Although it stores a huge amount of power, it cannot be recharged.", + "description": "This battery uses a thin plutonium-244 rod to stabilize an exotic nanocompound. It is universally compatible with small devices. Although it stores a huge amount of power, it cannot be recharged.", "ascii_picture": "ultra_light_battery_plut", "weight": "80 g", "volume": "1 ml", @@ -201,7 +201,7 @@ "type": "MAGAZINE", "category": "spare_parts", "name": { "str": "medium plutonium fuel battery", "str_pl": "medium plutonium fuel batteries" }, - "description": "This battery uses a thin plutonium-244 rod to stablize an exotic nanocompound. It is universally compatible with all kinds of appliances and power tools. Although it stores a huge amount of power, it cannot be recharged.", + "description": "This battery uses a thin plutonium-244 rod to stabilize an exotic nanocompound. It is universally compatible with all kinds of appliances and power tools. Although it stores a huge amount of power, it cannot be recharged.", "ascii_picture": "medium_battery_plut", "weight": "1000 g", "volume": "525ml", @@ -281,7 +281,7 @@ "type": "MAGAZINE", "category": "spare_parts", "name": { "str": "heavy plutonium fuel battery", "str_pl": "heavy plutonium fuel batteries" }, - "description": "This battery uses a thin plutonium-244 rod to stablize an exotic nanocompound. It is universally compatible with all kinds of industrial-grade equipment and large tools. Although it stores a huge amount of power, it cannot be recharged.", + "description": "This battery uses a thin plutonium-244 rod to stabilize an exotic nanocompound. It is universally compatible with all kinds of industrial-grade equipment and large tools. Although it stores a huge amount of power, it cannot be recharged.", "ascii_picture": "heavy_battery_plut", "weight": "1600 g", "volume": "1500ml", @@ -302,7 +302,7 @@ "type": "MAGAZINE", "category": "spare_parts", "name": { "str": "military plutonium fuel cell" }, - "description": "This battery uses a huge plutonium-244 rod to stablize an exotic nanocompound. It was used in military mech-suits, was highly experimental, and had no civilian applications. Although it stores a stupendous amount of power, it cannot be recharged.", + "description": "This battery uses a huge plutonium-244 rod to stabilize an exotic nanocompound. It was used in military mech-suits, was highly experimental, and had no civilian applications. Although it stores a stupendous amount of power, it cannot be recharged.", "weight": "64000 g", "volume": "30 L", "price": 100000, diff --git a/data/json/items/gun/flintlock.json b/data/json/items/gun/flintlock.json index 9dd5c71b5b305..c971757fd9515 100644 --- a/data/json/items/gun/flintlock.json +++ b/data/json/items/gun/flintlock.json @@ -118,7 +118,7 @@ "copy-from": "rifle_flintlock", "type": "GUN", "name": { "str": "flintlock rifle" }, - "description": "Also called a Pennsylvania rifle, this long barreled rifled flintlock gun has signficantly increased accuracy at the cost of taking even longer to reload.", + "description": "Also called a Pennsylvania rifle, this long-barreled rifled flintlock gun has significantly increased accuracy at the cost of taking even longer to reload.", "weight": "3700 g", "volume": "1700 ml", "longest_side": "1278 mm", diff --git a/data/json/items/gun/shot.json b/data/json/items/gun/shot.json index 9cce99d93b790..a0c1f6dde9f75 100644 --- a/data/json/items/gun/shot.json +++ b/data/json/items/gun/shot.json @@ -74,7 +74,7 @@ "looks_like": "remington_870", "type": "GUN", "name": { "str": "handmade lever shotgun" }, - "description": "A short homemade lever-action shotgun with a small internal tube magazine. While still a primitive pipe and 2x4 design, it is a formiddable shotgun in its own right with room for improvement.", + "description": "A short, homemade lever-action shotgun with a small internal tube magazine. While still a primitive design - made from a pipe and a plank - it is a formidable shotgun in its own right with room for improvement.", "weight": "2311 g", "volume": "2 L", "longest_side": "85 cm", @@ -802,7 +802,7 @@ "copy-from": "shotgun_base", "type": "GUN", "name": { "str": "M1897 Trench Gun" }, - "description": "The Winchester 1897 was one of the first commercially successful pump action shotguns. In its 'trench' configuraton it has become a heavily romanticized American icon of World War 1. With its barrel shroud, bayonet lug and 17 inch bayonet, this shotgun is undeniably fearsome in appearance. There aren't any more trenches to clear, so the next zombie infested town will have to suffice.", + "description": "The Winchester 1897 was one of the first commercially-successful pump-action shotguns. In its 'trench' configuration it has become a heavily-romanticized American icon of World War 1. With its barrel shroud, bayonet lug, and 17 inch bayonet, this shotgun is undeniably fearsome in appearance. There aren't any more trenches to clear, so the next zombie-infested town will have to suffice.", "weight": "3629 g", "volume": "2564 ml", "longest_side": "989 mm", diff --git a/data/json/items/tool/cooking.json b/data/json/items/tool/cooking.json index f5665c1d37823..1113ef3e9c028 100644 --- a/data/json/items/tool/cooking.json +++ b/data/json/items/tool/cooking.json @@ -873,7 +873,7 @@ "type": "GENERIC", "category": "tools", "name": { "str": "sieve" }, - "description": "This is no mere strainer for noodles; it's a sieve used to separate particles of certain sizes. You could use this to do a really good job sifting flour, remove dust and soil from grain, or perhaps conduct gradiation tests for any civil engineers you might know. This one has been constructed from steel mesh.", + "description": "This is no mere strainer for noodles; it's a sieve used to separate particles of certain sizes. You could use this to do a really good job sifting flour, remove dust and soil from grain, or perhaps conduct gradation tests for any civil engineers you might know. This one has been constructed from steel mesh.", "volume": "500 ml", "weight": "318 g", "price": 700, diff --git a/data/json/monsters/jabberwock.json b/data/json/monsters/jabberwock.json index 68c50183c508f..8e49506b21980 100644 --- a/data/json/monsters/jabberwock.json +++ b/data/json/monsters/jabberwock.json @@ -3,7 +3,7 @@ "id": "mon_fleshy_shambler", "type": "MONSTER", "name": { "str": "fleshy shambler" }, - "description": "An amalgamation of throbbing organs from various creatures have fused together into this lurching, vaguely humanoid shape. Its myriad roughly formed mouths sussurate in a chorus of sibilant groans and whispers.", + "description": "An amalgamation of throbbing organs from various creatures have fused together into this lurching, vaguely-humanoid shape. Its myriad roughly-formed mouths susurrate in a chorus of sibilant groans and whispers.", "default_faction": "jabberwock", "species": [ "ABERRATION" ], "volume": "80000 ml", diff --git a/data/json/monsters/zed_acid.json b/data/json/monsters/zed_acid.json index a7c46a911faf7..328abbac67496 100644 --- a/data/json/monsters/zed_acid.json +++ b/data/json/monsters/zed_acid.json @@ -260,7 +260,7 @@ "type": "MONSTER", "copy-from": "mon_zombie_dog_acidic", "name": { "str": "blistered horror" }, - "description": "A huge canine with multiple large foul looking blisters covering its body. A corrosive liquid spills from its menancing-looking mouth.", + "description": "A huge canine with multiple large, foul-looking blisters covering its body. A corrosive liquid spills from its menacing-looking mouth.", "color": "yellow_white", "upgrades": false, "relative": { diff --git a/data/json/monsters/zed_misc.json b/data/json/monsters/zed_misc.json index 9a8810708c313..090d952eb07f3 100644 --- a/data/json/monsters/zed_misc.json +++ b/data/json/monsters/zed_misc.json @@ -1131,7 +1131,7 @@ "id": "mon_smoker_brute", "type": "MONSTER", "name": { "str": "ashen brawler" }, - "description": "A gigantic, twisted human frame with a menancing stance and rapid movements. Thick clouds of smoke pour from violent-looking eviscerations spread across its muscular-looking body, and its arms appear to have elongated massively.", + "description": "A gigantic, twisted human frame with a menacing stance and rapid movements. Thick clouds of smoke pour from violent-looking eviscerations spread across its muscular-looking body, and its arms appear to have elongated massively.", "default_faction": "zombie", "bodytype": "human", "species": [ "ZOMBIE", "HUMAN" ], diff --git a/data/json/proficiencies/tailoring.json b/data/json/proficiencies/tailoring.json index 17f08e47ba40c..9568cf3e3ff1e 100644 --- a/data/json/proficiencies/tailoring.json +++ b/data/json/proficiencies/tailoring.json @@ -162,7 +162,7 @@ "type": "proficiency", "id": "prof_polymerworking", "name": { "str": "Advanced polymer sewing" }, - "description": "You know the tricks for working with kevlar, nomex, and other advanced polymer cloth.", + "description": "You know the tricks for working with Kevlar, Nomex, and other advanced polymer cloth.", "can_learn": true, "default_time_multiplier": 2, "default_fail_multiplier": 2.5, From 4399e252cd3bc124c6927e60df817d803d20f05a Mon Sep 17 00:00:00 2001 From: actual-nh <74678550+actual-nh@users.noreply.github.com> Date: Wed, 7 Apr 2021 04:43:54 -0400 Subject: [PATCH 347/453] [Magiclysm] Fix orc archer not spawning with ammo (#46780) --- data/mods/Magiclysm/monsters/Orcs.json | 16 ++++++++++++---- 1 file changed, 12 insertions(+), 4 deletions(-) diff --git a/data/mods/Magiclysm/monsters/Orcs.json b/data/mods/Magiclysm/monsters/Orcs.json index 71c797abfe79a..d01baf6a96df9 100644 --- a/data/mods/Magiclysm/monsters/Orcs.json +++ b/data/mods/Magiclysm/monsters/Orcs.json @@ -1,4 +1,10 @@ [ + { + "type": "item_group", + "subtype": "collection", + "id": "quiver_orc_archer", + "entries": [ { "item": "arrow_wood_heavy", "count": [ 1, 6 ], "charges": [ 1, 10 ] } ] + }, { "id": "mon_orc_warrior", "type": "MONSTER", @@ -57,10 +63,11 @@ { "item": "armguard_scrap", "prob": 40 }, { "item": "cuirass_scrap", "prob": 40 }, { "item": "longbow", "prob": 100 }, - { "item": "sheath", "contents-item": "knife_combat", "prob": 50 } + { "item": "sheath", "contents-item": "knife_combat", "prob": 50 }, + { "item": "quiver_large", "contents-group": "quiver_orc_archer", "prob": 100 } ] }, - "starting_ammo": { "arrow_wood_heavy": 75 }, + "starting_ammo": { "arrow_wood_heavy": 60 }, "extend": { "special_attacks": [ { @@ -69,7 +76,7 @@ "move_cost": 93, "gun_type": "longbow", "ammo_type": "arrow_wood_heavy", - "fake_skills": [ [ "gun", 6 ], [ "rifle", 7 ] ], + "fake_skills": [ [ "gun", 6 ], [ "archery", 7 ] ], "fake_dex": 9, "fake_per": 5, "require_targeting_player": false, @@ -77,7 +84,8 @@ "ranges": [ [ 3, 13, "DEFAULT" ] ], "no_ammo_sound": "grunting" } - ] + ], + "flags": [ "DROPS_AMMO" ] } }, { From d21ebda69b44e1e72c6ec60153dd06497db3e2bd Mon Sep 17 00:00:00 2001 From: Xenomorph-III Date: Mon, 5 Apr 2021 11:21:45 +1200 Subject: [PATCH 348/453] Reword student description --- data/json/professions.json | 5 ++--- 1 file changed, 2 insertions(+), 3 deletions(-) diff --git a/data/json/professions.json b/data/json/professions.json index b40032f09b937..e8c285cae3f41 100644 --- a/data/json/professions.json +++ b/data/json/professions.json @@ -1897,7 +1897,7 @@ "type": "profession", "id": "student", "name": "Student", - "description": "Just an average high school student, you find yourself facing a test you never studied for, and the stakes are a bit higher than geometry. Maybe there'll be something useful in one of these books you've been lugging around all year.", + "description": "Just an average student, you find yourself facing a test you never studied for, and the stakes are a bit higher than geometry. Maybe there'll be something useful in one of these books you've been lugging around all year.", "points": 1, "items": { "both": { @@ -1911,8 +1911,7 @@ "wristwatch", "textbook_speech", "story_book", - "howto_computer", - "novel_coa" + "howto_computer" ], "entries": [ { "group": "charged_cell_phone" } ] }, From 381f6db0ba3fac323d26d06c90f3c8f0964a778c Mon Sep 17 00:00:00 2001 From: souricelle <67675144+souricelle@users.noreply.github.com> Date: Wed, 7 Apr 2021 02:01:53 -0700 Subject: [PATCH 349/453] Add feral scientists and lab security (#47996) --- data/json/harvest.json | 19 ++++ data/json/monsterdrops/feral_humans.json | 66 +++++++++++++ data/json/monstergroups/lab.json | 15 +++ data/json/monsters/feral_humans.json | 121 +++++++++++++++++++++++ data/json/snippets/lab.json | 4 +- 5 files changed, 224 insertions(+), 1 deletion(-) diff --git a/data/json/harvest.json b/data/json/harvest.json index f8658ec5c88fd..0c04a110e268a 100644 --- a/data/json/harvest.json +++ b/data/json/harvest.json @@ -1294,6 +1294,25 @@ { "drop": "bone_tainted", "type": "bone", "mass_ratio": 0.1 } ] }, + { + "id": "CBM_SCI_FERAL", + "type": "harvest", + "entries": [ + { + "drop": "bionics_sci", + "type": "bionic_group", + "flags": [ "NO_STERILE", "NO_PACKED" ], + "faults": [ "fault_bionic_salvaged" ] + }, + { "drop": "human_flesh", "type": "flesh", "mass_ratio": 0.2 }, + { "drop": "hstomach", "scale_num": [ 1, 1 ], "max": 1, "type": "offal" }, + { "drop": "human_fat", "type": "flesh", "mass_ratio": 0.1 }, + { "drop": "blood", "type": "blood", "mass_ratio": 0.1 }, + { "drop": "bone_human", "type": "bone", "mass_ratio": 0.12 }, + { "drop": "sinew", "type": "bone", "mass_ratio": 0.001 }, + { "drop": "raw_hleather", "type": "skin", "mass_ratio": 0.01 } + ] + }, { "id": "CBM_TECH", "type": "harvest", diff --git a/data/json/monsterdrops/feral_humans.json b/data/json/monsterdrops/feral_humans.json index 03e30f201d6c0..df787a4720216 100644 --- a/data/json/monsterdrops/feral_humans.json +++ b/data/json/monsterdrops/feral_humans.json @@ -16,5 +16,71 @@ "subtype": "collection", "id": "feral_humans_death_drops_crowbar", "entries": [ { "item": "crowbar", "prob": 100, "damage": [ 1, 3 ] }, { "group": "default_zombie_clothes", "prob": 100 } ] + }, + { + "type": "item_group", + "subtype": "collection", + "id": "feral_scientists_death_drops_scalpel", + "entries": [ + { "item": "scalpel", "prob": 100, "damage": [ 1, 3 ] }, + { "group": "lab_shoes", "damage": [ 1, 4 ] }, + { "group": "lab_torso", "damage": [ 1, 4 ] }, + { "group": "lab_pants", "damage": [ 1, 4 ] }, + { "group": "underwear", "damage": [ 1, 4 ] }, + { + "collection": [ + { "group": "harddrugs", "prob": 25 }, + { "group": "chem_lab", "prob": 60 }, + { "group": "teleport", "prob": 6 }, + { "group": "goo", "prob": 20 }, + { "group": "cloning_vat", "prob": 1 }, + { "group": "dissection", "prob": 50 }, + { "group": "electronics", "prob": 40 }, + { "group": "bionics", "prob": 10 }, + { "group": "radio", "prob": 15 }, + { "group": "textbooks", "prob": 25 }, + { "group": "autodoc_installation_programs", "prob": 5 } + ] + }, + { "group": "wallets_science", "damage": [ 1, 4 ], "prob": 5 } + ] + }, + { + "id": "feral_security_death_drops_9mm", + "type": "item_group", + "subtype": "collection", + "magazine": 100, + "ammo": 20, + "entries": [ + { "item": "m9", "prob": 100, "damage": [ 2, 4 ] }, + { "group": "cop_gear", "prob": 50, "damage": [ 0, 2 ] }, + { "group": "cop_gloves", "prob": 30, "damage": [ 1, 4 ] }, + { "group": "security_pants", "damage": [ 1, 4 ] }, + { "group": "security_shoes", "prob": 70, "damage": [ 1, 4 ] }, + { "group": "security_torso", "prob": 70, "damage": [ 1, 4 ] }, + { "group": "underwear", "damage": [ 1, 4 ] }, + { "group": "clothing_glasses", "prob": 5 }, + { "group": "clothing_watch", "prob": 5 }, + { "group": "wallets", "damage": [ 1, 4 ] } + ] + }, + { + "id": "feral_security_death_drops_flashlight", + "type": "item_group", + "subtype": "collection", + "magazine": 100, + "ammo": 20, + "entries": [ + { "item": "heavy_flashlight", "prob": 100, "damage": [ 2, 4 ] }, + { "item": "tazer", "prob": 100, "damage": [ 2, 4 ] }, + { "group": "cop_gloves", "prob": 30, "damage": [ 1, 4 ] }, + { "group": "security_pants", "damage": [ 1, 4 ] }, + { "group": "security_shoes", "prob": 70, "damage": [ 1, 4 ] }, + { "group": "security_torso", "prob": 70, "damage": [ 1, 4 ] }, + { "group": "underwear", "damage": [ 1, 4 ] }, + { "group": "clothing_glasses", "prob": 5 }, + { "group": "clothing_watch", "prob": 5 }, + { "group": "wallets", "damage": [ 1, 4 ] } + ] } ] diff --git a/data/json/monstergroups/lab.json b/data/json/monstergroups/lab.json index ad71a5a8e059b..b67cd2eb03c8d 100644 --- a/data/json/monstergroups/lab.json +++ b/data/json/monstergroups/lab.json @@ -5,6 +5,7 @@ "default": "mon_zombie_scientist", "monsters": [ { "monster": "mon_zombie_soldier", "freq": 25, "cost_multiplier": 0, "pack_size": [ 1, 4 ] }, + { "monster": "mon_feral_scientist_scalpel", "freq": 20, "cost_multiplier": 0 }, { "monster": "mon_manhack", "freq": 200, "cost_multiplier": 0 }, { "monster": "mon_manhack", "freq": 45, "cost_multiplier": 0, "pack_size": [ 2, 3 ] }, { "monster": "mon_skitterbot", "freq": 100, "cost_multiplier": 0 }, @@ -28,6 +29,9 @@ "default": "mon_zombie_scientist", "monsters": [ { "monster": "mon_blob_small", "freq": 25, "cost_multiplier": 0, "pack_size": [ 1, 4 ] }, + { "monster": "mon_feral_labsecurity_9mm", "freq": 18, "cost_multiplier": 8 }, + { "monster": "mon_feral_labsecurity_flashlight", "freq": 18, "cost_multiplier": 2 }, + { "monster": "mon_feral_scientist_scalpel", "freq": 20, "cost_multiplier": 0 }, { "monster": "mon_zombie", "freq": 200, "cost_multiplier": 0, "pack_size": [ 1, 3 ] }, { "monster": "mon_zombie_fat", "freq": 100, "cost_multiplier": 0, "pack_size": [ 1, 3 ] }, { "monster": "mon_zombie_tough", "freq": 100, "cost_multiplier": 2, "pack_size": [ 1, 3 ] }, @@ -61,6 +65,9 @@ "name": "GROUP_LAB_SURFACE", "default": "mon_zombie_scientist", "monsters": [ + { "monster": "mon_feral_labsecurity_9mm", "freq": 18, "cost_multiplier": 8 }, + { "monster": "mon_feral_labsecurity_flashlight", "freq": 18, "cost_multiplier": 2 }, + { "monster": "mon_feral_scientist_scalpel", "freq": 20, "cost_multiplier": 0 }, { "monster": "mon_zombie_labsecurity", "freq": 400, "cost_multiplier": 2, "pack_size": [ 1, 3 ] }, { "monster": "mon_zombie_scientist", "freq": 600, "cost_multiplier": 1 }, { "monster": "mon_zombie_scientist", "freq": 400, "cost_multiplier": 1, "pack_size": [ 1, 5 ] }, @@ -94,6 +101,8 @@ "name": "GROUP_LAB_SECURITY", "default": "mon_zombie_labsecurity", "monsters": [ + { "monster": "mon_feral_labsecurity_9mm", "freq": 22, "cost_multiplier": 8 }, + { "monster": "mon_feral_labsecurity_flashlight", "freq": 22, "cost_multiplier": 2 }, { "monster": "mon_zombie_labsecurity", "freq": 700, "cost_multiplier": 2 }, { "monster": "mon_science_bot", "freq": 50, "cost_multiplier": 4 }, { "monster": "mon_manhack", "freq": 200, "cost_multiplier": 0 }, @@ -119,6 +128,9 @@ "default": "mon_zombie_scientist", "//": "Mostly scientists, lab personnel and regular zombies.", "monsters": [ + { "monster": "mon_feral_labsecurity_9mm", "freq": 18, "cost_multiplier": 8 }, + { "monster": "mon_feral_labsecurity_flashlight", "freq": 18, "cost_multiplier": 2 }, + { "monster": "mon_feral_scientist_scalpel", "freq": 20, "cost_multiplier": 8 }, { "monster": "mon_zombie", "freq": 75, "cost_multiplier": 0 }, { "monster": "mon_zombie_fat", "freq": 75, "cost_multiplier": 0 }, { "monster": "mon_zombie_tough", "freq": 75, "cost_multiplier": 2 }, @@ -144,6 +156,9 @@ "default": "mon_zombie_scientist", "monsters": [ { "monster": "mon_blob_small", "freq": 40, "cost_multiplier": 0, "pack_size": [ 3, 6 ] }, + { "monster": "mon_feral_labsecurity_9mm", "freq": 18, "cost_multiplier": 8 }, + { "monster": "mon_feral_labsecurity_flashlight", "freq": 18, "cost_multiplier": 2 }, + { "monster": "mon_feral_scientist_scalpel", "freq": 20, "cost_multiplier": 0 }, { "monster": "mon_zombie_scientist", "freq": 40, "cost_multiplier": 0, "pack_size": [ 1, 5 ] }, { "monster": "mon_science_bot", "freq": 40, "cost_multiplier": 2 }, { "monster": "mon_zombie_labsecurity", "freq": 40, "cost_multiplier": 0, "pack_size": [ 2, 3 ] }, diff --git a/data/json/monsters/feral_humans.json b/data/json/monsters/feral_humans.json index 355a9d25b7ce3..3d3829915f477 100644 --- a/data/json/monsters/feral_humans.json +++ b/data/json/monsters/feral_humans.json @@ -78,5 +78,126 @@ "melee_dice_sides": 7, "melee_cut": 9, "death_drops": "feral_humans_death_drops_axe" + }, + { + "id": "mon_feral_scientist_scalpel", + "type": "MONSTER", + "name": { "str": "mad scientist" }, + "description": "A researcher who has stared too long into the abyss, and now shambles about muttering nonsense under their breath. For some reason, the zombies don't seem to mind that this person is obviously still alive. They're clutching a tiny but razor-sharp blade in one shaky hand.", + "default_faction": "science", + "looks_like": "chud", + "bodytype": "human", + "species": [ "HUMAN" ], + "volume": "62500 ml", + "weight": "81500 g", + "hp": 80, + "speed": 100, + "material": [ "flesh" ], + "symbol": "@", + "color": "magenta", + "aggression": 30, + "morale": 100, + "melee_skill": 4, + "melee_dice": 1, + "melee_dice_sides": 3, + "melee_cut": 2, + "dodge": 1, + "harvest": "CBM_SCI_FERAL", + "path_settings": { "max_dist": 10 }, + "vision_day": 50, + "vision_night": 3, + "death_drops": "feral_scientists_death_drops_scalpel", + "death_function": [ "NORMAL" ], + "zombify_into": "mon_zombie_scientist", + "anger_triggers": [ "FRIEND_DIED", "FRIEND_ATTACKED", "HURT", "PLAYER_CLOSE" ], + "flags": [ + "SEES", + "HEARS", + "SMELLS", + "WARM", + "BASHES", + "GROUP_BASH", + "HUMAN", + "CAN_OPEN_DOORS", + "PATH_AVOID_DANGER_2", + "DROPS_AMMO", + "CBM_SCI" + ] + }, + { + "id": "mon_feral_labsecurity_9mm", + "type": "MONSTER", + "name": { "str": "feral security guard" }, + "description": "This security guard still breathes, but has been lost to some terrible madness. They move among the undead, handgun at the ready and saucer pupils scanning for threats in a mockery of their former duty.", + "default_faction": "science", + "looks_like": "chud", + "bodytype": "human", + "species": [ "HUMAN" ], + "volume": "62500 ml", + "weight": "81500 g", + "hp": 80, + "speed": 100, + "material": [ "flesh" ], + "symbol": "@", + "color": "magenta", + "aggression": 30, + "morale": 100, + "melee_skill": 6, + "melee_dice": 2, + "melee_dice_sides": 3, + "armor_bash": 4, + "armor_cut": 6, + "armor_bullet": 4, + "armor_stab": 4, + "dodge": 1, + "harvest": "human", + "vision_day": 50, + "vision_night": 4, + "path_settings": { "max_dist": 10 }, + "diff": 5, + "starting_ammo": { "9mm": 5 }, + "special_attacks": [ + { + "type": "gun", + "cooldown": 10, + "move_cost": 150, + "gun_type": "m9", + "ammo_type": "9mm", + "fake_skills": [ [ "gun", 1 ], [ "handgun", 2 ] ], + "fake_dex": 8, + "fake_per": 10, + "ranges": [ [ 0, 14, "DEFAULT" ] ], + "require_targeting_player": false, + "description": "The feral security guard fires their Beretta M9A1!" + } + ], + "death_drops": "feral_security_death_drops_9mm", + "death_function": [ "NORMAL" ], + "zombify_into": "mon_zombie_labsecurity", + "anger_triggers": [ "FRIEND_DIED", "FRIEND_ATTACKED", "HURT", "PLAYER_WEAK" ], + "flags": [ + "SEES", + "HEARS", + "SMELLS", + "WARM", + "BASHES", + "GROUP_BASH", + "HUMAN", + "CAN_OPEN_DOORS", + "CLIMBS", + "PUSH_MON", + "PATH_AVOID_DANGER_2", + "DROPS_AMMO" + ] + }, + { + "id": "mon_feral_labsecurity_flashlight", + "type": "MONSTER", + "copy-from": "mon_feral_labsecurity_9mm", + "description": "At first glance, this disheveled figure could almost pass for a survivor, but the bloodshot eyes give them away as one of the humans who have gone feral and joined the undead without dying. Their uniform suggests that this was at some point a security guard, and they still carry a stun gun and a heavy-duty flashlight that looks like it could easily double as a club.", + "melee_dice_sides": 6, + "special_attacks": [ [ "TAZER", 10 ] ], + "luminance": 500, + "death_drops": "feral_security_death_drops_flashlight" } ] diff --git a/data/json/snippets/lab.json b/data/json/snippets/lab.json index 05eb5d8b55c9b..7b1deb77238c3 100644 --- a/data/json/snippets/lab.json +++ b/data/json/snippets/lab.json @@ -122,7 +122,9 @@ "Jakobson was killed today by one of S37ZBE's subjects; ironic considering how hard he fought to keep the project active. Alarmingly, his corpse revivified immediately. This suggests that XE037 may have contaminated the lab at large. Even more alarmingly, we received an alert from Dr. Dionne in XEDRA-12 that they have detected similar signs of cross-contamination with XE037. How can this have happened? Even during the breach last week, we managed to keep containment protocols active!", "Termination of a subject which was never a part of S37ZBE has confirmed my fears. XE037 has contaminated most, if not all of the laboratory. We're in communication with XEDRA-12 over their own outbreak, and both labs have been quarantined. While they backtrace the leak, we will start research into a process to destroy XE037 within the human body.", "Dr. Takatoshi sent us interesting news: her lab serendipitously discovered that sufficient rapid teleports in a short span of time can strip out XE037 somehow, without harming the subject. This has the unfortunate issues of needing an absolutely insane amount of electricity, and drawing the attention of what Dr. Takatoshi calls \"subplanar creatures\" and the rest of us call \"horrifying alien monstrosities\". Still, it's a start.", - "Dr. Sidhu figured out a way to track what happens to XE037 when it's stripped out during teleportation, using a high-affinity biotracer and a probe that follows immediately behind the test subject. XE037 migrates out of the body in small but significant quantities with every teleport. We're attributing way too much intelligence to it here, but we can't help but feel this is some kind of intentional 'stowaway' effect, like it's shedding off the body to try to colonize a new dimension. At the meeting, Dr. Sidhu told us to stop anthropomorphizing it. He thinks it's no more a sign of intelligence than a cold virus coming out with a sneeze." + "Dr. Sidhu figured out a way to track what happens to XE037 when it's stripped out during teleportation, using a high-affinity biotracer and a probe that follows immediately behind the test subject. XE037 migrates out of the body in small but significant quantities with every teleport. We're attributing way too much intelligence to it here, but we can't help but feel this is some kind of intentional 'stowaway' effect, like it's shedding off the body to try to colonize a new dimension. At the meeting, Dr. Sidhu told us to stop anthropomorphizing it. He thinks it's no more a sign of intelligence than a cold virus coming out with a sneeze.", + "I've put Dr. Welch and Dr. Bondi on supervised leave following the incident discussed in my previous message. Obviously neither has a history of this kind of behavior or they wouldn't be here, and it's deeply concerning that they both suddenly began acting this way following Wednesday's demonstration. For now we'll keep them on-site until (hopefully) they recover enough to get back to work, but I'd like to formally ask that we start looking at possible replacements.", + "At approximately 11:15 today, I saw Dr. Greene enter the break area from the primary corridor. He is always so rude so I drew my service pistol and fired three shots into his body. Then I shot Dr. Summers and Officer Clark because they were being loud. I am sorry, but I do not know how many times I shot them. I think Hollis tazed me but I was so mad by that point that I could not keep track of what was going on. Then you restrained me and brought me here, so I guess that's my whole report." ] } ] From 020ba21656a485a9f5b48f3ea423ffdb9529e324 Mon Sep 17 00:00:00 2001 From: John Bytheway Date: Tue, 30 Mar 2021 21:07:41 -0400 Subject: [PATCH 350/453] Split debug_menu function Extract three cases from the giant switch statement into new, separate, functions. --- src/debug_menu.cpp | 393 ++++++++++++++++++++++++--------------------- 1 file changed, 206 insertions(+), 187 deletions(-) diff --git a/src/debug_menu.cpp b/src/debug_menu.cpp index 6ad998654ff89..1ef8722b50c4a 100644 --- a/src/debug_menu.cpp +++ b/src/debug_menu.cpp @@ -1949,6 +1949,205 @@ void draw_benchmark( const int max_difference ) difference / 1000.0, 1000.0 * draw_counter / static_cast( difference ) ); } +static void debug_menu_game_state() +{ + avatar &player_character = get_avatar(); + map &here = get_map(); + tripoint abs_sub = here.get_abs_sub(); + std::string mfus; + std::vector> sorted; + for( int f = 0; f < m_flag::MF_MAX; f++ ) { + sorted.push_back( {static_cast( f ), MonsterGenerator::generator().m_flag_usage_stats[f]} ); + } + std::sort( sorted.begin(), sorted.end(), []( std::pair a, std::pair b ) { + return a.second != b.second ? a.second > b.second : a.first < b.first; + } ); + popup( player_character.total_daily_calories_string() ); + for( auto &m_flag_stat : sorted ) { + mfus += string_format( "%s;%d\n", io::enum_to_string( m_flag_stat.first ), + m_flag_stat.second ); + } + DebugLog( D_INFO, DC_ALL ) << "Monster flag usage statistics:\nFLAG;COUNT\n" << mfus; + std::fill( MonsterGenerator::generator().m_flag_usage_stats.begin(), + MonsterGenerator::generator().m_flag_usage_stats.end(), 0 ); + popup_top( "Monster flag usage statistics were dumped to debug.log and cleared." ); + + std::string s = _( "Location %d:%d in %d:%d, %s\n" ); + s += _( "Current turn: %d.\n" ); + s += ngettext( "%d creature exists.\n", "%d creatures exist.\n", g->num_creatures() ); + + std::unordered_map creature_counts; + for( Creature &critter : g->all_creatures() ) { + std::string this_name = critter.get_name(); + creature_counts[this_name]++; + } + + if( !creature_counts.empty() ) { + std::vector> creature_names_sorted; + for( const std::pair &it : creature_counts ) { + creature_names_sorted.emplace_back( it ); + } + + std::stable_sort( creature_names_sorted.begin(), creature_names_sorted.end(), []( auto a, auto b ) { + return a.second > b.second; + } ); + + s += _( "\nSpecific creature type list:\n" ); + for( const std::pair &crit_name : creature_names_sorted ) { + s += string_format( "%i %s\n", crit_name.second, crit_name.first ); + } + } + + popup_top( + s.c_str(), + player_character.posx(), player_character.posy(), abs_sub.x, abs_sub.y, + overmap_buffer.ter( player_character.global_omt_location() )->get_name(), + to_turns( calendar::turn - calendar::turn_zero ), + g->num_creatures() ); + for( const npc &guy : g->all_npcs() ) { + tripoint t = guy.global_sm_location(); + add_msg( m_info, _( "%s: map ( %d:%d ) pos ( %d:%d )" ), guy.name, t.x, + t.y, guy.posx(), guy.posy() ); + } + + add_msg( m_info, _( "(you: %d:%d)" ), player_character.posx(), player_character.posy() ); + std::string stom = + _( "Stomach Contents: %d ml / %d ml kCal: %d, Water: %d ml" ); + add_msg( m_info, stom.c_str(), units::to_milliliter( player_character.stomach.contains() ), + units::to_milliliter( player_character.stomach.capacity( player_character ) ), + player_character.stomach.get_calories(), + units::to_milliliter( player_character.stomach.get_water() ), player_character.get_hunger() ); + stom = _( "Guts Contents: %d ml / %d ml kCal: %d, Water: %d ml\nHunger: %d, Thirst: %d, kCal: %d / %d" ); + add_msg( m_info, stom.c_str(), units::to_milliliter( player_character.guts.contains() ), + units::to_milliliter( player_character.guts.capacity( player_character ) ), + player_character.guts.get_calories(), units::to_milliliter( player_character.guts.get_water() ), + player_character.get_hunger(), player_character.get_thirst(), player_character.get_stored_kcal(), + player_character.get_healthy_kcal() ); + add_msg( m_info, _( "Body Mass Index: %.0f\nBasal Metabolic Rate: %i" ), player_character.get_bmi(), + player_character.get_bmr() ); + add_msg( m_info, _( "Player activity level: %s" ), player_character.activity_level_str() ); + if( get_option( "STATS_THROUGH_KILLS" ) ) { + add_msg( m_info, _( "Kill xp: %d" ), player_character.kill_xp() ); + } + g->invalidate_main_ui_adaptor(); + g->disp_NPCs(); +} + +static void debug_menu_spawn_vehicle() +{ + avatar &player_character = get_avatar(); + map &here = get_map(); + if( here.veh_at( player_character.pos() ) ) { + dbg( D_ERROR ) << "game:load: There's already vehicle here"; + debugmsg( "There's already vehicle here" ); + } else { + // Vector of name, id so that we can sort by name + std::vector> veh_strings; + for( auto &elem : vehicle_prototype::get_all() ) { + if( elem == vproto_id( "custom" ) ) { + continue; + } + veh_strings.emplace_back( elem->name.translated(), elem ); + } + std::sort( veh_strings.begin(), veh_strings.end(), localized_compare ); + uilist veh_menu; + veh_menu.text = _( "Choose vehicle to spawn" ); + int menu_ind = 0; + for( auto &elem : veh_strings ) { + //~ Menu entry in vehicle wish menu: 1st string: displayed name, 2nd string: internal name of vehicle + veh_menu.addentry( menu_ind, true, MENU_AUTOASSIGN, _( "%1$s (%2$s)" ), + elem.first, elem.second.c_str() ); + ++menu_ind; + } + veh_menu.query(); + if( veh_menu.ret >= 0 && veh_menu.ret < static_cast( veh_strings.size() ) ) { + // Didn't cancel + const vproto_id &selected_opt = veh_strings[veh_menu.ret].second; + tripoint dest = player_character.pos(); + uilist veh_cond_menu; + veh_cond_menu.text = _( "Vehicle condition" ); + veh_cond_menu.addentry( 0, true, MENU_AUTOASSIGN, _( "Light damage" ) ); + veh_cond_menu.addentry( 1, true, MENU_AUTOASSIGN, _( "Undamaged" ) ); + veh_cond_menu.addentry( 2, true, MENU_AUTOASSIGN, _( "Disabled (tires or engine)" ) ); + veh_cond_menu.query(); + + if( veh_cond_menu.ret >= 0 && veh_cond_menu.ret < 3 ) { + // TODO: Allow picking this when add_vehicle has 3d argument + vehicle *veh = here.add_vehicle( + selected_opt, dest, -90_degrees, 100, veh_cond_menu.ret - 1 ); + if( veh != nullptr ) { + here.board_vehicle( dest, &player_character ); + } + } + } + } +} + +static void debug_menu_change_time() +{ + auto set_turn = [&]( const int initial, const time_duration & factor, const char *const msg ) { + const auto text = string_input_popup() + .title( msg ) + .width( 20 ) + .text( std::to_string( initial ) ) + .only_digits( true ) + .query_string(); + if( text.empty() ) { + return; + } + const int new_value = std::atoi( text.c_str() ); + const time_duration offset = ( new_value - initial ) * factor; + // Arbitrary maximal value. + const time_point max = calendar::turn_zero + time_duration::from_turns( + std::numeric_limits::max() / 2 ); + calendar::turn = std::max( std::min( max, calendar::turn + offset ), calendar::turn_zero ); + }; + + uilist smenu; + static const auto years = []( const time_point & p ) { + return static_cast( ( p - calendar::turn_zero ) / calendar::year_length() ); + }; + do { + const int iSel = smenu.ret; + smenu.reset(); + smenu.addentry( 0, true, 'y', "%s: %d", _( "year" ), years( calendar::turn ) ); + smenu.addentry( 1, !calendar::eternal_season(), 's', "%s: %d", + _( "season" ), static_cast( season_of_year( calendar::turn ) ) ); + smenu.addentry( 2, true, 'd', "%s: %d", _( "day" ), day_of_season( calendar::turn ) ); + smenu.addentry( 3, true, 'h', "%s: %d", _( "hour" ), hour_of_day( calendar::turn ) ); + smenu.addentry( 4, true, 'm', "%s: %d", _( "minute" ), minute_of_hour( calendar::turn ) ); + smenu.addentry( 5, true, 't', "%s: %d", _( "turn" ), + to_turns( calendar::turn - calendar::turn_zero ) ); + smenu.selected = iSel; + smenu.query(); + + switch( smenu.ret ) { + case 0: + set_turn( years( calendar::turn ), calendar::year_length(), _( "Set year to?" ) ); + break; + case 1: + set_turn( static_cast( season_of_year( calendar::turn ) ), calendar::season_length(), + _( "Set season to? (0 = spring)" ) ); + break; + case 2: + set_turn( day_of_season( calendar::turn ), 1_days, _( "Set days to?" ) ); + break; + case 3: + set_turn( hour_of_day( calendar::turn ), 1_hours, _( "Set hour to?" ) ); + break; + case 4: + set_turn( minute_of_hour( calendar::turn ), 1_minutes, _( "Set minute to?" ) ); + break; + case 5: + set_turn( to_turns( calendar::turn - calendar::turn_zero ), 1_turns, + string_format( _( "Set turn to? (One day is %i turns)" ), to_turns( 1_days ) ).c_str() ); + break; + default: + break; + } + } while( smenu.ret != UILIST_CANCEL ); +} + void debug() { bool debug_menu_has_hotkey = hotkey_for_action( ACTION_DEBUG, @@ -2036,86 +2235,10 @@ void debug() debug_menu::wishmonster( cata::nullopt ); break; - case debug_menu_index::GAME_STATE: { - std::string mfus; - std::vector> sorted; - for( int f = 0; f < m_flag::MF_MAX; f++ ) { - sorted.push_back( {static_cast( f ), MonsterGenerator::generator().m_flag_usage_stats[f]} ); - } - std::sort( sorted.begin(), sorted.end(), []( std::pair a, std::pair b ) { - return a.second != b.second ? a.second > b.second : a.first < b.first; - } ); - popup( player_character.total_daily_calories_string() ); - for( auto &m_flag_stat : sorted ) { - mfus += string_format( "%s;%d\n", io::enum_to_string( m_flag_stat.first ), - m_flag_stat.second ); - } - DebugLog( D_INFO, DC_ALL ) << "Monster flag usage statistics:\nFLAG;COUNT\n" << mfus; - std::fill( MonsterGenerator::generator().m_flag_usage_stats.begin(), - MonsterGenerator::generator().m_flag_usage_stats.end(), 0 ); - popup_top( "Monster flag usage statistics were dumped to debug.log and cleared." ); - - std::string s = _( "Location %d:%d in %d:%d, %s\n" ); - s += _( "Current turn: %d.\n" ); - s += ngettext( "%d creature exists.\n", "%d creatures exist.\n", g->num_creatures() ); - - std::unordered_map creature_counts; - for( Creature &critter : g->all_creatures() ) { - std::string this_name = critter.get_name(); - creature_counts[this_name]++; - } - - if( !creature_counts.empty() ) { - std::vector> creature_names_sorted; - for( const std::pair &it : creature_counts ) { - creature_names_sorted.emplace_back( it ); - } - - std::stable_sort( creature_names_sorted.begin(), creature_names_sorted.end(), []( auto a, auto b ) { - return a.second > b.second; - } ); - - s += _( "\nSpecific creature type list:\n" ); - for( const std::pair &crit_name : creature_names_sorted ) { - s += string_format( "%i %s\n", crit_name.second, crit_name.first ); - } - } - - popup_top( - s.c_str(), - player_character.posx(), player_character.posy(), abs_sub.x, abs_sub.y, - overmap_buffer.ter( player_character.global_omt_location() )->get_name(), - to_turns( calendar::turn - calendar::turn_zero ), - g->num_creatures() ); - for( const npc &guy : g->all_npcs() ) { - tripoint t = guy.global_sm_location(); - add_msg( m_info, _( "%s: map ( %d:%d ) pos ( %d:%d )" ), guy.name, t.x, - t.y, guy.posx(), guy.posy() ); - } - - add_msg( m_info, _( "(you: %d:%d)" ), player_character.posx(), player_character.posy() ); - std::string stom = - _( "Stomach Contents: %d ml / %d ml kCal: %d, Water: %d ml" ); - add_msg( m_info, stom.c_str(), units::to_milliliter( player_character.stomach.contains() ), - units::to_milliliter( player_character.stomach.capacity( player_character ) ), - player_character.stomach.get_calories(), - units::to_milliliter( player_character.stomach.get_water() ), player_character.get_hunger() ); - stom = _( "Guts Contents: %d ml / %d ml kCal: %d, Water: %d ml\nHunger: %d, Thirst: %d, kCal: %d / %d" ); - add_msg( m_info, stom.c_str(), units::to_milliliter( player_character.guts.contains() ), - units::to_milliliter( player_character.guts.capacity( player_character ) ), - player_character.guts.get_calories(), units::to_milliliter( player_character.guts.get_water() ), - player_character.get_hunger(), player_character.get_thirst(), player_character.get_stored_kcal(), - player_character.get_healthy_kcal() ); - add_msg( m_info, _( "Body Mass Index: %.0f\nBasal Metabolic Rate: %i" ), player_character.get_bmi(), - player_character.get_bmr() ); - add_msg( m_info, _( "Player activity level: %s" ), player_character.activity_level_str() ); - if( get_option( "STATS_THROUGH_KILLS" ) ) { - add_msg( m_info, _( "Kill xp: %d" ), player_character.kill_xp() ); - } - g->invalidate_main_ui_adaptor(); - g->disp_NPCs(); + case debug_menu_index::GAME_STATE: + debug_menu_game_state(); break; - } + case debug_menu_index::KILL_NPCS: for( npc &guy : g->all_npcs() ) { add_msg( _( "%s's head implodes!" ), guy.name ); @@ -2128,50 +2251,7 @@ void debug() break; case debug_menu_index::SPAWN_VEHICLE: - if( here.veh_at( player_character.pos() ) ) { - dbg( D_ERROR ) << "game:load: There's already vehicle here"; - debugmsg( "There's already vehicle here" ); - } else { - // Vector of name, id so that we can sort by name - std::vector> veh_strings; - for( auto &elem : vehicle_prototype::get_all() ) { - if( elem == vproto_id( "custom" ) ) { - continue; - } - veh_strings.emplace_back( elem->name.translated(), elem ); - } - std::sort( veh_strings.begin(), veh_strings.end(), localized_compare ); - uilist veh_menu; - veh_menu.text = _( "Choose vehicle to spawn" ); - int menu_ind = 0; - for( auto &elem : veh_strings ) { - //~ Menu entry in vehicle wish menu: 1st string: displayed name, 2nd string: internal name of vehicle - veh_menu.addentry( menu_ind, true, MENU_AUTOASSIGN, _( "%1$s (%2$s)" ), - elem.first, elem.second.c_str() ); - ++menu_ind; - } - veh_menu.query(); - if( veh_menu.ret >= 0 && veh_menu.ret < static_cast( veh_strings.size() ) ) { - // Didn't cancel - const vproto_id &selected_opt = veh_strings[veh_menu.ret].second; - tripoint dest = player_character.pos(); - uilist veh_cond_menu; - veh_cond_menu.text = _( "Vehicle condition" ); - veh_cond_menu.addentry( 0, true, MENU_AUTOASSIGN, _( "Light damage" ) ); - veh_cond_menu.addentry( 1, true, MENU_AUTOASSIGN, _( "Undamaged" ) ); - veh_cond_menu.addentry( 2, true, MENU_AUTOASSIGN, _( "Disabled (tires or engine)" ) ); - veh_cond_menu.query(); - - if( veh_cond_menu.ret >= 0 && veh_cond_menu.ret < 3 ) { - // TODO: Allow picking this when add_vehicle has 3d argument - vehicle *veh = here.add_vehicle( - selected_opt, dest, -90_degrees, 100, veh_cond_menu.ret - 1 ); - if( veh != nullptr ) { - here.board_vehicle( dest, &player_character ); - } - } - } - } + debug_menu_spawn_vehicle(); break; case debug_menu_index::CHANGE_SKILLS: { @@ -2471,70 +2551,9 @@ void debug() case debug_menu_index::HOUR_TIMER: g->toggle_debug_hour_timer(); break; - case debug_menu_index::CHANGE_TIME: { - auto set_turn = [&]( const int initial, const time_duration & factor, const char *const msg ) { - const auto text = string_input_popup() - .title( msg ) - .width( 20 ) - .text( std::to_string( initial ) ) - .only_digits( true ) - .query_string(); - if( text.empty() ) { - return; - } - const int new_value = std::atoi( text.c_str() ); - const time_duration offset = ( new_value - initial ) * factor; - // Arbitrary maximal value. - const time_point max = calendar::turn_zero + time_duration::from_turns( - std::numeric_limits::max() / 2 ); - calendar::turn = std::max( std::min( max, calendar::turn + offset ), calendar::turn_zero ); - }; - - uilist smenu; - static const auto years = []( const time_point & p ) { - return static_cast( ( p - calendar::turn_zero ) / calendar::year_length() ); - }; - do { - const int iSel = smenu.ret; - smenu.reset(); - smenu.addentry( 0, true, 'y', "%s: %d", _( "year" ), years( calendar::turn ) ); - smenu.addentry( 1, !calendar::eternal_season(), 's', "%s: %d", - _( "season" ), static_cast( season_of_year( calendar::turn ) ) ); - smenu.addentry( 2, true, 'd', "%s: %d", _( "day" ), day_of_season( calendar::turn ) ); - smenu.addentry( 3, true, 'h', "%s: %d", _( "hour" ), hour_of_day( calendar::turn ) ); - smenu.addentry( 4, true, 'm', "%s: %d", _( "minute" ), minute_of_hour( calendar::turn ) ); - smenu.addentry( 5, true, 't', "%s: %d", _( "turn" ), - to_turns( calendar::turn - calendar::turn_zero ) ); - smenu.selected = iSel; - smenu.query(); - - switch( smenu.ret ) { - case 0: - set_turn( years( calendar::turn ), calendar::year_length(), _( "Set year to?" ) ); - break; - case 1: - set_turn( static_cast( season_of_year( calendar::turn ) ), calendar::season_length(), - _( "Set season to? (0 = spring)" ) ); - break; - case 2: - set_turn( day_of_season( calendar::turn ), 1_days, _( "Set days to?" ) ); - break; - case 3: - set_turn( hour_of_day( calendar::turn ), 1_hours, _( "Set hour to?" ) ); - break; - case 4: - set_turn( minute_of_hour( calendar::turn ), 1_minutes, _( "Set minute to?" ) ); - break; - case 5: - set_turn( to_turns( calendar::turn - calendar::turn_zero ), 1_turns, - string_format( _( "Set turn to? (One day is %i turns)" ), to_turns( 1_days ) ).c_str() ); - break; - default: - break; - } - } while( smenu.ret != UILIST_CANCEL ); - } - break; + case debug_menu_index::CHANGE_TIME: + debug_menu_change_time(); + break; case debug_menu_index::SET_AUTOMOVE: { const cata::optional dest = g->look_around(); if( !dest || *dest == player_character.pos() ) { From 6c0d03155a02ddd728f1677eb0c97eee4d4932e9 Mon Sep 17 00:00:00 2001 From: John Bytheway Date: Fri, 2 Apr 2021 20:22:28 -0400 Subject: [PATCH 351/453] Split game::handle_action Make this large function smaller by factoring out two parts of it into new functions. --- src/game.h | 2 + src/handle_action.cpp | 1828 +++++++++++++++++++++-------------------- 2 files changed, 931 insertions(+), 899 deletions(-) diff --git a/src/game.h b/src/game.h index 3499b90f980d2..41f62321b594f 100644 --- a/src/game.h +++ b/src/game.h @@ -885,6 +885,8 @@ class game void process_activity(); // Processes and enacts the player's activity void handle_key_blocking_activity(); // Abort reading etc. void open_consume_item_menu(); // Custom menu for consuming specific group of items + bool do_regular_action( action_id &act, avatar &player_character, + const cata::optional &mouse_target ); bool handle_action(); bool try_get_right_click_action( action_id &act, const tripoint &mouse_target ); bool try_get_left_click_action( action_id &act, const tripoint &mouse_target ); diff --git a/src/handle_action.cpp b/src/handle_action.cpp index 2f7582e9290c5..fce8b3d44c4f9 100644 --- a/src/handle_action.cpp +++ b/src/handle_action.cpp @@ -1679,1050 +1679,1080 @@ static void handle_debug_mode() } while( dbmenu.ret != UILIST_CANCEL ); } -bool game::handle_action() +static bool has_vehicle_control( avatar &player_character ) { - std::string action; - input_context ctxt; - action_id act = ACTION_NULL; - user_turn current_turn; - avatar &player_character = get_avatar(); - // Check if we have an auto-move destination - if( player_character.has_destination() ) { - act = player_character.get_next_auto_move_direction(); - if( act == ACTION_NULL ) { - add_msg( m_info, _( "Auto-move canceled" ) ); - player_character.clear_destination(); - return false; - } - } else if( player_character.has_destination_activity() ) { - // starts destination activity after the player successfully reached his destination - player_character.start_destination_activity(); + if( player_character.is_dead_state() ) { return false; - } else { - // No auto-move, ask player for input - ctxt = get_player_input( action ); } + const optional_vpart_position vp = get_map().veh_at( player_character.pos() ); + if( vp && vp->vehicle().player_in_control( player_character ) ) { + return true; + } + return g->remoteveh() != nullptr; +} - const optional_vpart_position vp = m.veh_at( player_character.pos() ); - bool veh_ctrl = !player_character.is_dead_state() && - ( ( vp && vp->vehicle().player_in_control( player_character ) ) || remoteveh() != nullptr ); - - // If performing an action with right mouse button, co-ordinates - // of location clicked. - cata::optional mouse_target; +static void do_deathcam_action( const action_id &act, avatar &player_character ) +{ + switch( act ) { + case ACTION_TOGGLE_MAP_MEMORY: + player_character.toggle_map_memory(); + break; - if( uquit == QUIT_WATCH && action == "QUIT" ) { - uquit = QUIT_DIED; - return false; - } + case ACTION_CENTER: + player_character.view_offset.x = g->driving_view_offset.x; + player_character.view_offset.y = g->driving_view_offset.y; + break; - if( act == ACTION_NULL ) { - act = look_up_action( action ); + case ACTION_SHIFT_N: + case ACTION_SHIFT_NE: + case ACTION_SHIFT_E: + case ACTION_SHIFT_SE: + case ACTION_SHIFT_S: + case ACTION_SHIFT_SW: + case ACTION_SHIFT_W: + case ACTION_SHIFT_NW: { + static const std::map> shift_delta = { + { ACTION_SHIFT_N, { point_north, point_north_east } }, + { ACTION_SHIFT_NE, { point_north_east, point_east } }, + { ACTION_SHIFT_E, { point_east, point_south_east } }, + { ACTION_SHIFT_SE, { point_south_east, point_south } }, + { ACTION_SHIFT_S, { point_south, point_south_west } }, + { ACTION_SHIFT_SW, { point_south_west, point_west } }, + { ACTION_SHIFT_W, { point_west, point_north_west } }, + { ACTION_SHIFT_NW, { point_north_west, point_north } }, + }; + int soffset = get_option( "MOVE_VIEW_OFFSET" ); + player_character.view_offset += use_tiles && tile_iso ? + shift_delta.at( act ).second * soffset : shift_delta.at( act ).first * soffset; + } + break; + + case ACTION_LOOK: + g->look_around(); + break; - if( act == ACTION_KEYBINDINGS ) { + case ACTION_KEYBINDINGS: // already handled by input context - return false; - } + break; - if( act == ACTION_MAIN_MENU ) { - if( uquit == QUIT_WATCH ) { - return false; - } - // No auto-move actions have or can be set at this point. - player_character.clear_destination(); - destination_preview.clear(); - act = handle_main_menu(); - if( act == ACTION_NULL ) { - return false; - } - } + default: + break; + } +} - if( act == ACTION_ACTIONMENU ) { - if( uquit == QUIT_WATCH ) { - return false; - } - // No auto-move actions have or can be set at this point. - player_character.clear_destination(); - destination_preview.clear(); - act = handle_action_menu(); - if( act == ACTION_NULL ) { - return false; - } -#if defined(__ANDROID__) - if( get_option( "ANDROID_ACTIONMENU_AUTOADD" ) && ctxt.get_category() == "DEFAULTMODE" ) { - add_best_key_for_action_to_quick_shortcuts( act, ctxt.get_category(), false ); +bool game::do_regular_action( action_id &act, avatar &player_character, + const cata::optional &mouse_target ) +{ + switch( act ) { + case ACTION_NULL: + case NUM_ACTIONS: + break; // dummy entries + case ACTION_ACTIONMENU: + case ACTION_MAIN_MENU: + case ACTION_KEYBINDINGS: + break; // handled above + + case ACTION_TIMEOUT: + if( check_safe_mode_allowed( false ) ) { + player_character.pause(); } -#endif - } + break; - if( act == ACTION_KEYBINDINGS ) { - player_character.clear_destination(); - destination_preview.clear(); - act = ctxt.display_menu( true ); - if( act == ACTION_NULL ) { - return false; + case ACTION_PAUSE: + if( check_safe_mode_allowed() ) { + player_character.pause(); } - } + break; - if( can_action_change_worldstate( act ) ) { - user_action_counter += 1; - } + case ACTION_CYCLE_MOVE: + player_character.cycle_move_mode(); + break; - if( act == ACTION_SELECT || act == ACTION_SEC_SELECT ) { - // Mouse button click - if( veh_ctrl ) { - // No mouse use in vehicle - return false; - } + case ACTION_RESET_MOVE: + player_character.reset_move_mode(); + break; - if( player_character.is_dead_state() ) { - // do not allow mouse actions while dead - return false; - } + case ACTION_TOGGLE_RUN: + player_character.toggle_run_mode(); + break; - const cata::optional mouse_pos = ctxt.get_coordinates( w_terrain ); - if( !mouse_pos ) { - return false; - } else if( !player_character.sees( *mouse_pos ) ) { - // Not clicked in visible terrain - return false; + case ACTION_TOGGLE_CROUCH: + player_character.toggle_crouch_mode(); + break; + + case ACTION_OPEN_MOVEMENT: + open_movement_mode_menu(); + break; + + case ACTION_MOVE_FORTH: + case ACTION_MOVE_FORTH_RIGHT: + case ACTION_MOVE_RIGHT: + case ACTION_MOVE_BACK_RIGHT: + case ACTION_MOVE_BACK: + case ACTION_MOVE_BACK_LEFT: + case ACTION_MOVE_LEFT: + case ACTION_MOVE_FORTH_LEFT: + if( !player_character.get_value( "remote_controlling" ).empty() && + ( player_character.has_active_item( itype_radiocontrol ) || + player_character.has_active_bionic( bio_remote ) ) ) { + rcdrive( get_delta_from_movement_action( act, iso_rotate::yes ) ); + } else if( has_vehicle_control( player_character ) ) { + // vehicle control uses x for steering and y for ac/deceleration, + // so no rotation needed + pldrive( get_delta_from_movement_action( act, iso_rotate::no ) ); + } else { + point dest_delta = get_delta_from_movement_action( act, iso_rotate::yes ); + if( auto_travel_mode && !player_character.is_auto_moving() ) { + for( int i = 0; i < SEEX; i++ ) { + tripoint auto_travel_destination( player_character.posx() + dest_delta.x * ( SEEX - i ), + player_character.posy() + dest_delta.y * ( SEEX - i ), + player_character.posz() ); + destination_preview = m.route( player_character.pos(), + auto_travel_destination, + player_character.get_pathfinding_settings(), + player_character.get_path_avoid() ); + if( !destination_preview.empty() ) { + destination_preview.erase( destination_preview.begin() + 1, destination_preview.end() ); + player_character.set_destination( destination_preview ); + break; + } + } + act = player_character.get_next_auto_move_direction(); + const point dest_next = get_delta_from_movement_action( act, iso_rotate::yes ); + if( dest_next == point_zero ) { + player_character.clear_destination(); + } + dest_delta = dest_next; + } + if( !avatar_action::move( player_character, m, dest_delta ) ) { + // auto-move should be canceled due to a failed move or obstacle + player_character.clear_destination(); + } } - mouse_target = mouse_pos; + break; + case ACTION_MOVE_DOWN: + if( player_character.is_mounted() ) { + auto *mon = player_character.mounted_creature.get(); + if( !mon->has_flag( MF_RIDEABLE_MECH ) ) { + add_msg( m_info, _( "You can't go down stairs while you're riding." ) ); + break; + } + } + if( !player_character.in_vehicle ) { + vertical_move( -1, false ); + } else if( has_vehicle_control( player_character ) ) { + const optional_vpart_position vp = get_map().veh_at( player_character.pos() ); + if( vp->vehicle().is_rotorcraft() ) { + pldrive( tripoint_below ); + } + } + break; - if( act == ACTION_SELECT ) { - // Note: The following has the potential side effect of - // setting auto-move destination state in addition to setting - // act. - if( !try_get_left_click_action( act, *mouse_target ) ) { - return false; + case ACTION_MOVE_UP: + if( player_character.is_mounted() ) { + auto *mon = player_character.mounted_creature.get(); + if( !mon->has_flag( MF_RIDEABLE_MECH ) ) { + add_msg( m_info, _( "You can't go up stairs while you're riding." ) ); + break; } - } else if( act == ACTION_SEC_SELECT ) { - if( !try_get_right_click_action( act, *mouse_target ) ) { - return false; + } + if( !player_character.in_vehicle ) { + vertical_move( 1, false ); + } else if( has_vehicle_control( player_character ) ) { + const optional_vpart_position vp = get_map().veh_at( player_character.pos() ); + if( vp->vehicle().is_rotorcraft() ) { + pldrive( tripoint_above ); } } - } else if( act != ACTION_TIMEOUT ) { - // act has not been set for an auto-move, so clearing possible - // auto-move destinations. Since initializing an auto-move with - // the mouse may span across multiple actions, we do not clear the - // auto-move destination if the action is only a timeout, as this - // would require the user to double click quicker than the - // timeout delay. - player_character.clear_destination(); - destination_preview.clear(); - } - } + break; - if( act == ACTION_NULL ) { - const input_event &&evt = ctxt.get_raw_input(); - if( !evt.sequence.empty() ) { - const int ch = evt.get_first_input(); - if( !get_option( "NO_UNKNOWN_COMMAND_MSG" ) ) { - add_msg( m_info, _( "Unknown command: \"%s\" (%ld)" ), evt.long_description(), ch ); - if( const cata::optional hint = - press_x_if_bound( ACTION_KEYBINDINGS ) ) { - add_msg( m_info, _( "%s at any time to see and edit keybindings relevant to " - "the current context." ), - *hint ); + case ACTION_OPEN: + if( player_character.has_active_mutation( trait_SHELL2 ) ) { + add_msg( m_info, _( "You can't open things while you're in your shell." ) ); + } else if( player_character.is_mounted() ) { + add_msg( m_info, _( "You can't open things while you're riding." ) ); + } else if( u.has_effect( effect_incorporeal ) ) { + add_msg( m_info, _( "You lack the substance to affect anything." ) ); + } else { + open(); + } + break; + + case ACTION_CLOSE: + if( player_character.has_active_mutation( trait_SHELL2 ) ) { + add_msg( m_info, _( "You can't close things while you're in your shell." ) ); + } else if( player_character.has_effect( effect_incorporeal ) ) { + add_msg( m_info, _( "You lack the substance to affect anything." ) ); + } else if( player_character.is_mounted() ) { + auto *mon = player_character.mounted_creature.get(); + if( !mon->has_flag( MF_RIDEABLE_MECH ) ) { + add_msg( m_info, _( "You can't close things while you're riding." ) ); } + } else if( mouse_target ) { + doors::close_door( m, player_character, *mouse_target ); + } else { + close(); } - } - return false; - } + break; - // This has no action unless we're in a special game mode. - gamemode->pre_action( act ); + case ACTION_SMASH: + if( has_vehicle_control( player_character ) ) { + handbrake(); + } else if( player_character.has_active_mutation( trait_SHELL2 ) ) { + add_msg( m_info, _( "You can't smash things while you're in your shell." ) ); + } else if( u.has_effect( effect_incorporeal ) ) { + add_msg( m_info, _( "You lack the substance to affect anything." ) ); + } else { + smash(); + } + break; - int soffset = get_option( "MOVE_VIEW_OFFSET" ); + case ACTION_EXAMINE: + if( player_character.has_active_mutation( trait_SHELL2 ) ) { + add_msg( m_info, _( "You can't examine your surroundings while you're in your shell." ) ); + } else if( mouse_target ) { + examine( *mouse_target ); + } else { + examine(); + } + break; - int before_action_moves = player_character.moves; + case ACTION_ADVANCEDINV: + if( player_character.has_active_mutation( trait_SHELL2 ) ) { + add_msg( m_info, _( "You can't move mass quantities while you're in your shell." ) ); + } else if( player_character.is_mounted() ) { + add_msg( m_info, _( "You can't move mass quantities while you're riding." ) ); + } else if( u.has_effect( effect_incorporeal ) ) { + add_msg( m_info, _( "You lack the substance to affect anything." ) ); + } else { + create_advanced_inv(); + } + break; - // These actions are allowed while deathcam is active. Registered in game::get_player_input - if( uquit == QUIT_WATCH || !player_character.is_dead_state() ) { - switch( act ) { - case ACTION_TOGGLE_MAP_MEMORY: - player_character.toggle_map_memory(); - break; + case ACTION_PICKUP: + if( player_character.has_active_mutation( trait_SHELL2 ) ) { + add_msg( m_info, _( "You can't pick anything up while you're in your shell." ) ); + } else if( player_character.is_mounted() ) { + add_msg( m_info, _( "You can't pick anything up while you're riding." ) ); + } else if( u.has_effect( effect_incorporeal ) ) { + add_msg( m_info, _( "You lack the substance to affect anything." ) ); + } else if( mouse_target ) { + pickup( *mouse_target ); + } else { + pickup(); + } + break; - case ACTION_CENTER: - player_character.view_offset.x = driving_view_offset.x; - player_character.view_offset.y = driving_view_offset.y; - break; + case ACTION_PICKUP_FEET: + if( player_character.has_active_mutation( trait_SHELL2 ) ) { + add_msg( m_info, _( "You can't pick anything up while you're in your shell." ) ); + } else if( u.has_effect( effect_incorporeal ) ) { + add_msg( m_info, _( "You lack the substance to affect anything." ) ); + } else { + pickup_feet(); + } + break; - case ACTION_SHIFT_N: - case ACTION_SHIFT_NE: - case ACTION_SHIFT_E: - case ACTION_SHIFT_SE: - case ACTION_SHIFT_S: - case ACTION_SHIFT_SW: - case ACTION_SHIFT_W: - case ACTION_SHIFT_NW: { - static const std::map> shift_delta = { - { ACTION_SHIFT_N, { point_north, point_north_east } }, - { ACTION_SHIFT_NE, { point_north_east, point_east } }, - { ACTION_SHIFT_E, { point_east, point_south_east } }, - { ACTION_SHIFT_SE, { point_south_east, point_south } }, - { ACTION_SHIFT_S, { point_south, point_south_west } }, - { ACTION_SHIFT_SW, { point_south_west, point_west } }, - { ACTION_SHIFT_W, { point_west, point_north_west } }, - { ACTION_SHIFT_NW, { point_north_west, point_north } }, - }; - player_character.view_offset += use_tiles && tile_iso ? - shift_delta.at( act ).second * soffset : shift_delta.at( act ).first * soffset; - } - break; - - case ACTION_LOOK: - look_around(); - break; + case ACTION_GRAB: + if( player_character.has_active_mutation( trait_SHELL2 ) ) { + add_msg( m_info, _( "You can't grab things while you're in your shell." ) ); + } else if( player_character.is_mounted() ) { + add_msg( m_info, _( "You can't grab things while you're riding." ) ); + } else if( u.has_effect( effect_incorporeal ) ) { + add_msg( m_info, _( "You lack the substance to affect anything." ) ); + } else { + grab(); + } + break; - case ACTION_KEYBINDINGS: - // already handled by input context - break; + case ACTION_HAUL: + if( player_character.has_active_mutation( trait_SHELL2 ) ) { + add_msg( m_info, _( "You can't haul things while you're in your shell." ) ); + } else if( player_character.is_mounted() ) { + add_msg( m_info, _( "You can't haul things while you're riding." ) ); + } else if( u.has_effect( effect_incorporeal ) ) { + add_msg( m_info, _( "You lack the substance to affect anything." ) ); + } else { + haul(); + } + break; - default: - break; - } - } + case ACTION_BUTCHER: + if( player_character.has_active_mutation( trait_SHELL2 ) ) { + add_msg( m_info, _( "You can't butcher while you're in your shell." ) ); + } else if( player_character.is_mounted() ) { + add_msg( m_info, _( "You can't butcher while you're riding." ) ); + } else if( u.has_effect( effect_incorporeal ) ) { + add_msg( m_info, _( "You lack the substance to affect anything." ) ); + } else { + butcher(); + } + break; - // actions allowed only while alive - if( !player_character.is_dead_state() ) { - switch( act ) { - case ACTION_NULL: - case NUM_ACTIONS: - break; // dummy entries - case ACTION_ACTIONMENU: - case ACTION_MAIN_MENU: - case ACTION_KEYBINDINGS: - break; // handled above - - case ACTION_TIMEOUT: - if( check_safe_mode_allowed( false ) ) { - player_character.pause(); - } - break; + case ACTION_CHAT: + chat(); + break; - case ACTION_PAUSE: - if( check_safe_mode_allowed() ) { - player_character.pause(); - } - break; + case ACTION_PEEK: + if( player_character.has_active_mutation( trait_SHELL2 ) ) { + add_msg( m_info, _( "You can't peek around corners while you're in your shell." ) ); + } else if( player_character.is_mounted() ) { + add_msg( m_info, _( "You can't peek around corners while you're riding." ) ); + } else { + peek(); + } + break; - case ACTION_CYCLE_MOVE: - player_character.cycle_move_mode(); - break; + case ACTION_LIST_ITEMS: + list_items_monsters(); + break; - case ACTION_RESET_MOVE: - player_character.reset_move_mode(); - break; + case ACTION_ZONES: + zones_manager(); + break; - case ACTION_TOGGLE_RUN: - player_character.toggle_run_mode(); - break; + case ACTION_LOOT: + loot(); + break; - case ACTION_TOGGLE_CROUCH: - player_character.toggle_crouch_mode(); - break; + case ACTION_INVENTORY: + game_menus::inv::common( player_character ); + break; - case ACTION_OPEN_MOVEMENT: - open_movement_mode_menu(); - break; + case ACTION_COMPARE: + game_menus::inv::compare( player_character, cata::nullopt ); + break; - case ACTION_MOVE_FORTH: - case ACTION_MOVE_FORTH_RIGHT: - case ACTION_MOVE_RIGHT: - case ACTION_MOVE_BACK_RIGHT: - case ACTION_MOVE_BACK: - case ACTION_MOVE_BACK_LEFT: - case ACTION_MOVE_LEFT: - case ACTION_MOVE_FORTH_LEFT: - if( !player_character.get_value( "remote_controlling" ).empty() && - ( player_character.has_active_item( itype_radiocontrol ) || - player_character.has_active_bionic( bio_remote ) ) ) { - rcdrive( get_delta_from_movement_action( act, iso_rotate::yes ) ); - } else if( veh_ctrl ) { - // vehicle control uses x for steering and y for ac/deceleration, - // so no rotation needed - pldrive( get_delta_from_movement_action( act, iso_rotate::no ) ); - } else { - point dest_delta = get_delta_from_movement_action( act, iso_rotate::yes ); - if( auto_travel_mode && !player_character.is_auto_moving() ) { - for( int i = 0; i < SEEX; i++ ) { - tripoint auto_travel_destination( player_character.posx() + dest_delta.x * ( SEEX - i ), - player_character.posy() + dest_delta.y * ( SEEX - i ), - player_character.posz() ); - destination_preview = m.route( player_character.pos(), - auto_travel_destination, - player_character.get_pathfinding_settings(), - player_character.get_path_avoid() ); - if( !destination_preview.empty() ) { - destination_preview.erase( destination_preview.begin() + 1, destination_preview.end() ); - player_character.set_destination( destination_preview ); - break; - } - } - act = player_character.get_next_auto_move_direction(); - const point dest_next = get_delta_from_movement_action( act, iso_rotate::yes ); - if( dest_next == point_zero ) { - player_character.clear_destination(); - } - dest_delta = dest_next; - } - if( !avatar_action::move( player_character, m, dest_delta ) ) { - // auto-move should be canceled due to a failed move or obstacle - player_character.clear_destination(); - } - } - break; - case ACTION_MOVE_DOWN: - if( player_character.is_mounted() ) { - auto *mon = player_character.mounted_creature.get(); - if( !mon->has_flag( MF_RIDEABLE_MECH ) ) { - add_msg( m_info, _( "You can't go down stairs while you're riding." ) ); - break; - } - } - if( !player_character.in_vehicle ) { - vertical_move( -1, false ); - } else if( veh_ctrl && vp->vehicle().is_rotorcraft() ) { - pldrive( tripoint_below ); - } - break; + case ACTION_ORGANIZE: + game_menus::inv::swap_letters( player_character ); + break; - case ACTION_MOVE_UP: - if( player_character.is_mounted() ) { - auto *mon = player_character.mounted_creature.get(); - if( !mon->has_flag( MF_RIDEABLE_MECH ) ) { - add_msg( m_info, _( "You can't go up stairs while you're riding." ) ); - break; - } - } - if( !player_character.in_vehicle ) { - vertical_move( 1, false ); - } else if( veh_ctrl && vp->vehicle().is_rotorcraft() ) { - pldrive( tripoint_above ); - } - break; + case ACTION_USE: + // Shell-users are presumed to be able to mess with their inventories, etc + // while in the shell. Eating, gear-changing, and item use are OK. + avatar_action::use_item( player_character ); + break; - case ACTION_OPEN: - if( player_character.has_active_mutation( trait_SHELL2 ) ) { - add_msg( m_info, _( "You can't open things while you're in your shell." ) ); - } else if( player_character.is_mounted() ) { - add_msg( m_info, _( "You can't open things while you're riding." ) ); - } else if( u.has_effect( effect_incorporeal ) ) { - add_msg( m_info, _( "You lack the substance to affect anything." ) ); - } else { - open(); - } - break; + case ACTION_USE_WIELDED: + player_character.use_wielded(); + break; - case ACTION_CLOSE: - if( player_character.has_active_mutation( trait_SHELL2 ) ) { - add_msg( m_info, _( "You can't close things while you're in your shell." ) ); - } else if( player_character.has_effect( effect_incorporeal ) ) { - add_msg( m_info, _( "You lack the substance to affect anything." ) ); - } else if( player_character.is_mounted() ) { - auto *mon = player_character.mounted_creature.get(); - if( !mon->has_flag( MF_RIDEABLE_MECH ) ) { - add_msg( m_info, _( "You can't close things while you're riding." ) ); - } - } else if( mouse_target ) { - doors::close_door( m, player_character, *mouse_target ); - } else { - close(); - } - break; + case ACTION_WEAR: + wear(); + break; - case ACTION_SMASH: - if( veh_ctrl ) { - handbrake(); - } else if( player_character.has_active_mutation( trait_SHELL2 ) ) { - add_msg( m_info, _( "You can't smash things while you're in your shell." ) ); - } else if( u.has_effect( effect_incorporeal ) ) { - add_msg( m_info, _( "You lack the substance to affect anything." ) ); - } else { - smash(); - } - break; + case ACTION_TAKE_OFF: + takeoff(); + break; - case ACTION_EXAMINE: - if( player_character.has_active_mutation( trait_SHELL2 ) ) { - add_msg( m_info, _( "You can't examine your surroundings while you're in your shell." ) ); - } else if( mouse_target ) { - examine( *mouse_target ); - } else { - examine(); - } - break; + case ACTION_EAT: + if( !avatar_action::eat_here( player_character ) ) { + avatar_action::eat( player_character, game_menus::inv::consume( player_character ) ); + } + break; - case ACTION_ADVANCEDINV: - if( player_character.has_active_mutation( trait_SHELL2 ) ) { - add_msg( m_info, _( "You can't move mass quantities while you're in your shell." ) ); - } else if( player_character.is_mounted() ) { - add_msg( m_info, _( "You can't move mass quantities while you're riding." ) ); - } else if( u.has_effect( effect_incorporeal ) ) { - add_msg( m_info, _( "You lack the substance to affect anything." ) ); - } else { - create_advanced_inv(); - } - break; + case ACTION_OPEN_CONSUME: + if( !avatar_action::eat_here( player_character ) ) { + open_consume_item_menu(); + } + break; - case ACTION_PICKUP: - if( player_character.has_active_mutation( trait_SHELL2 ) ) { - add_msg( m_info, _( "You can't pick anything up while you're in your shell." ) ); - } else if( player_character.is_mounted() ) { - add_msg( m_info, _( "You can't pick anything up while you're riding." ) ); - } else if( u.has_effect( effect_incorporeal ) ) { - add_msg( m_info, _( "You lack the substance to affect anything." ) ); - } else if( mouse_target ) { - pickup( *mouse_target ); - } else { - pickup(); - } - break; + case ACTION_READ: + // Shell-users are presumed to have the book just at an opening and read it that way + read(); + break; - case ACTION_PICKUP_FEET: - if( player_character.has_active_mutation( trait_SHELL2 ) ) { - add_msg( m_info, _( "You can't pick anything up while you're in your shell." ) ); - } else if( u.has_effect( effect_incorporeal ) ) { - add_msg( m_info, _( "You lack the substance to affect anything." ) ); - } else { - pickup_feet(); - } - break; + case ACTION_WIELD: + wield(); + break; - case ACTION_GRAB: - if( player_character.has_active_mutation( trait_SHELL2 ) ) { - add_msg( m_info, _( "You can't grab things while you're in your shell." ) ); - } else if( player_character.is_mounted() ) { - add_msg( m_info, _( "You can't grab things while you're riding." ) ); - } else if( u.has_effect( effect_incorporeal ) ) { - add_msg( m_info, _( "You lack the substance to affect anything." ) ); - } else { - grab(); - } - break; + case ACTION_PICK_STYLE: + player_character.martial_arts_data->pick_style( player_character ); + break; - case ACTION_HAUL: - if( player_character.has_active_mutation( trait_SHELL2 ) ) { - add_msg( m_info, _( "You can't haul things while you're in your shell." ) ); - } else if( player_character.is_mounted() ) { - add_msg( m_info, _( "You can't haul things while you're riding." ) ); - } else if( u.has_effect( effect_incorporeal ) ) { - add_msg( m_info, _( "You lack the substance to affect anything." ) ); - } else { - haul(); - } - break; + case ACTION_RELOAD_ITEM: + reload_item(); + break; - case ACTION_BUTCHER: - if( player_character.has_active_mutation( trait_SHELL2 ) ) { - add_msg( m_info, _( "You can't butcher while you're in your shell." ) ); - } else if( player_character.is_mounted() ) { - add_msg( m_info, _( "You can't butcher while you're riding." ) ); - } else if( u.has_effect( effect_incorporeal ) ) { - add_msg( m_info, _( "You lack the substance to affect anything." ) ); - } else { - butcher(); - } - break; + case ACTION_RELOAD_WEAPON: + reload_weapon(); + break; - case ACTION_CHAT: - chat(); - break; + case ACTION_RELOAD_WIELDED: + reload_wielded(); + break; - case ACTION_PEEK: - if( player_character.has_active_mutation( trait_SHELL2 ) ) { - add_msg( m_info, _( "You can't peek around corners while you're in your shell." ) ); - } else if( player_character.is_mounted() ) { - add_msg( m_info, _( "You can't peek around corners while you're riding." ) ); - } else { - peek(); - } - break; + case ACTION_UNLOAD: + avatar_action::unload( player_character ); + break; - case ACTION_LIST_ITEMS: - list_items_monsters(); - break; + case ACTION_MEND: + avatar_action::mend( player_character, item_location() ); + break; - case ACTION_ZONES: - zones_manager(); - break; + case ACTION_THROW: { + item_location loc; + avatar_action::plthrow( player_character, loc ); + break; + } - case ACTION_LOOT: - loot(); - break; + case ACTION_FIRE: + fire(); + break; - case ACTION_INVENTORY: - game_menus::inv::common( player_character ); - break; + case ACTION_CAST_SPELL: + cast_spell(); + break; - case ACTION_COMPARE: - game_menus::inv::compare( player_character, cata::nullopt ); - break; + case ACTION_FIRE_BURST: { + gun_mode_id original_mode = player_character.weapon.gun_get_mode_id(); + if( player_character.weapon.gun_set_mode( gun_mode_id( "AUTO" ) ) ) { + avatar_action::fire_wielded_weapon( player_character ); + player_character.weapon.gun_set_mode( original_mode ); + } + break; + } - case ACTION_ORGANIZE: - game_menus::inv::swap_letters( player_character ); - break; + case ACTION_SELECT_FIRE_MODE: + if( player_character.is_armed() ) { + if( player_character.weapon.is_gun() && !player_character.weapon.is_gunmod() && + player_character.weapon.gun_all_modes().size() > 1 ) { + player_character.weapon.gun_cycle_mode(); + } else if( player_character.weapon.has_flag( flag_RELOAD_ONE ) || + player_character.weapon.has_flag( flag_RELOAD_AND_SHOOT ) ) { + item::reload_option opt = player_character.select_ammo( player_character.weapon, false ); + if( !opt ) { + break; + } else if( player_character.ammo_location && opt.ammo == player_character.ammo_location ) { + player_character.ammo_location = item_location(); + } else { + player_character.ammo_location = opt.ammo; + } + } + } + break; - case ACTION_USE: - // Shell-users are presumed to be able to mess with their inventories, etc - // while in the shell. Eating, gear-changing, and item use are OK. - avatar_action::use_item( player_character ); - break; + case ACTION_DROP: + // You CAN drop things to your own tile while in the shell. + drop(); + break; - case ACTION_USE_WIELDED: - player_character.use_wielded(); - break; + case ACTION_DIR_DROP: + if( player_character.has_active_mutation( trait_SHELL2 ) ) { + add_msg( m_info, _( "You can't drop things to another tile while you're in your shell." ) ); + } else { + drop_in_direction(); + } + break; + case ACTION_BIONICS: + player_character.power_bionics(); + break; + case ACTION_MUTATIONS: + player_character.power_mutations(); + break; - case ACTION_WEAR: - wear(); - break; + case ACTION_SORT_ARMOR: + player_character.sort_armor(); + break; - case ACTION_TAKE_OFF: - takeoff(); - break; + case ACTION_WAIT: + wait(); + break; - case ACTION_EAT: - if( !avatar_action::eat_here( player_character ) ) { - avatar_action::eat( player_character, game_menus::inv::consume( player_character ) ); - } - break; + case ACTION_CRAFT: + if( player_character.has_active_mutation( trait_SHELL2 ) ) { + add_msg( m_info, _( "You can't craft while you're in your shell." ) ); + } else if( player_character.has_effect( effect_incorporeal ) ) { + add_msg( m_info, _( "You lack the substance to affect anything." ) ); + } else if( player_character.is_mounted() ) { + add_msg( m_info, _( "You can't craft while you're riding." ) ); + } else { + player_character.craft(); + } + break; - case ACTION_OPEN_CONSUME: - if( !avatar_action::eat_here( player_character ) ) { - open_consume_item_menu(); - } - break; + case ACTION_RECRAFT: + if( player_character.has_active_mutation( trait_SHELL2 ) ) { + add_msg( m_info, _( "You can't craft while you're in your shell." ) ); + } else if( player_character.has_effect( effect_incorporeal ) ) { + add_msg( m_info, _( "You lack the substance to affect anything." ) ); + } else if( player_character.is_mounted() ) { + add_msg( m_info, _( "You can't craft while you're riding." ) ); + } else { + player_character.recraft(); + } + break; - case ACTION_READ: - // Shell-users are presumed to have the book just at an opening and read it that way - read(); - break; + case ACTION_LONGCRAFT: + if( player_character.has_active_mutation( trait_SHELL2 ) ) { + add_msg( m_info, _( "You can't craft while you're in your shell." ) ); + } else if( player_character.is_mounted() ) { + add_msg( m_info, _( "You can't craft while you're riding." ) ); + } else if( u.has_effect( effect_incorporeal ) ) { + add_msg( m_info, _( "You lack the substance to affect anything." ) ); + } else { + player_character.long_craft(); + } + break; - case ACTION_WIELD: - wield(); - break; + case ACTION_DISASSEMBLE: + if( player_character.controlling_vehicle ) { + add_msg( m_info, _( "You can't disassemble items while driving." ) ); + } else if( player_character.is_mounted() ) { + add_msg( m_info, _( "You can't disassemble items while you're riding." ) ); + } else if( u.has_effect( effect_incorporeal ) ) { + add_msg( m_info, _( "You lack the substance to affect anything." ) ); + } else { + player_character.disassemble(); + } + break; - case ACTION_PICK_STYLE: - player_character.martial_arts_data->pick_style( player_character ); - break; + case ACTION_CONSTRUCT: + if( player_character.in_vehicle ) { + add_msg( m_info, _( "You can't construct while in a vehicle." ) ); + } else if( player_character.has_active_mutation( trait_SHELL2 ) ) { + add_msg( m_info, _( "You can't construct while you're in your shell." ) ); + } else if( player_character.is_mounted() ) { + add_msg( m_info, _( "You can't construct while you're riding." ) ); + } else if( u.has_effect( effect_incorporeal ) ) { + add_msg( m_info, _( "You lack the substance to affect anything." ) ); + } else { + construction_menu( false ); + } + break; - case ACTION_RELOAD_ITEM: - reload_item(); - break; + case ACTION_SLEEP: + if( has_vehicle_control( player_character ) ) { + add_msg( m_info, _( "Vehicle control has moved, %s" ), + press_x( ACTION_CONTROL_VEHICLE, _( "new binding is " ), + _( "new default binding is '^'." ) ) ); + } else { + sleep(); + } + break; - case ACTION_RELOAD_WEAPON: - reload_weapon(); - break; + case ACTION_CONTROL_VEHICLE: + if( player_character.has_active_mutation( trait_SHELL2 ) ) { + add_msg( m_info, _( "You can't operate a vehicle while you're in your shell." ) ); + } else if( player_character.is_mounted() ) { + player_character.dismount(); + } else if( player_character.has_trait( trait_WAYFARER ) ) { + add_msg( m_info, _( "You refuse to take control of this vehicle." ) ); + } else if( u.has_effect( effect_incorporeal ) ) { + add_msg( m_info, _( "You lack the substance to affect anything." ) ); + } else { + control_vehicle(); + } + break; - case ACTION_RELOAD_WIELDED: - reload_wielded(); - break; + case ACTION_TOGGLE_AUTO_TRAVEL_MODE: + auto_travel_mode = !auto_travel_mode; + add_msg( m_info, auto_travel_mode ? _( "Auto travel mode ON!" ) : _( "Auto travel mode OFF!" ) ); + break; - case ACTION_UNLOAD: - avatar_action::unload( player_character ); - break; + case ACTION_TOGGLE_SAFEMODE: + if( safe_mode == SAFE_MODE_OFF ) { + set_safe_mode( SAFE_MODE_ON ); + mostseen = 0; + add_msg( m_info, _( "Safe mode ON!" ) ); + } else { + turnssincelastmon = 0_turns; + set_safe_mode( SAFE_MODE_OFF ); + add_msg( m_info, get_option( "AUTOSAFEMODE" ) + ? _( "Safe mode OFF! (Auto safe mode still enabled!)" ) : _( "Safe mode OFF!" ) ); + } + if( player_character.has_effect( effect_laserlocked ) ) { + player_character.remove_effect( effect_laserlocked ); + safe_mode_warning_logged = false; + } + break; - case ACTION_MEND: - avatar_action::mend( player_character, item_location() ); - break; + case ACTION_TOGGLE_AUTOSAFE: { + auto &autosafemode_option = get_options().get_option( "AUTOSAFEMODE" ); + add_msg( m_info, autosafemode_option.value_as() + ? _( "Auto safe mode OFF!" ) : _( "Auto safe mode ON!" ) ); + autosafemode_option.setNext(); + break; + } - case ACTION_THROW: { - item_location loc; - avatar_action::plthrow( player_character, loc ); - break; + case ACTION_IGNORE_ENEMY: + if( safe_mode == SAFE_MODE_STOP ) { + add_msg( m_info, _( "Ignoring enemy!" ) ); + for( auto &elem : player_character.get_mon_visible().new_seen_mon ) { + monster &critter = *elem; + critter.ignoring = rl_dist( player_character.pos(), critter.pos() ); + } + set_safe_mode( SAFE_MODE_ON ); + } else if( player_character.has_effect( effect_laserlocked ) ) { + if( player_character.has_trait( trait_PROF_CHURL ) ) { + add_msg( m_warning, _( "You make the sign of the cross." ) ); + } else { + add_msg( m_info, _( "Ignoring laser targeting!" ) ); + } + player_character.remove_effect( effect_laserlocked ); + safe_mode_warning_logged = false; } + break; - case ACTION_FIRE: - fire(); - break; + case ACTION_WHITELIST_ENEMY: + if( safe_mode == SAFE_MODE_STOP && !get_safemode().empty() ) { + get_safemode().add_rule( get_safemode().lastmon_whitelist, Creature::Attitude::ANY, 0, + rule_state::WHITELISTED ); + add_msg( m_info, _( "Creature whitelisted: %s" ), get_safemode().lastmon_whitelist ); + set_safe_mode( SAFE_MODE_ON ); + mostseen = 0; + } else { + get_safemode().show(); + } + break; - case ACTION_CAST_SPELL: - cast_spell(); - break; + case ACTION_WORKOUT: + if( query_yn( _( "Start workout?" ) ) ) { + player_character.assign_activity( player_activity( workout_activity_actor( + player_character.pos() ) ) ); + } + break; - case ACTION_FIRE_BURST: { - gun_mode_id original_mode = player_character.weapon.gun_get_mode_id(); - if( player_character.weapon.gun_set_mode( gun_mode_id( "AUTO" ) ) ) { - avatar_action::fire_wielded_weapon( player_character ); - player_character.weapon.gun_set_mode( original_mode ); + case ACTION_SUICIDE: + if( query_yn( _( "Commit suicide?" ) ) ) { + if( query_yn( _( "REALLY commit suicide?" ) ) ) { + player_character.moves = 0; + player_character.place_corpse(); + uquit = QUIT_SUICIDE; } - break; } + break; - case ACTION_SELECT_FIRE_MODE: - if( player_character.is_armed() ) { - if( player_character.weapon.is_gun() && !player_character.weapon.is_gunmod() && - player_character.weapon.gun_all_modes().size() > 1 ) { - player_character.weapon.gun_cycle_mode(); - } else if( player_character.weapon.has_flag( flag_RELOAD_ONE ) || - player_character.weapon.has_flag( flag_RELOAD_AND_SHOOT ) ) { - item::reload_option opt = player_character.select_ammo( player_character.weapon, false ); - if( !opt ) { - break; - } else if( player_character.ammo_location && opt.ammo == player_character.ammo_location ) { - player_character.ammo_location = item_location(); - } else { - player_character.ammo_location = opt.ammo; - } - } + case ACTION_SAVE: + if( query_yn( _( "Save and quit?" ) ) ) { + if( save() ) { + player_character.moves = 0; + uquit = QUIT_SAVED; } - break; + } + break; - case ACTION_DROP: - // You CAN drop things to your own tile while in the shell. - drop(); - break; + case ACTION_QUICKSAVE: + quicksave(); + return false; - case ACTION_DIR_DROP: - if( player_character.has_active_mutation( trait_SHELL2 ) ) { - add_msg( m_info, _( "You can't drop things to another tile while you're in your shell." ) ); - } else { - drop_in_direction(); - } - break; - case ACTION_BIONICS: - player_character.power_bionics(); - break; - case ACTION_MUTATIONS: - player_character.power_mutations(); - break; + case ACTION_QUICKLOAD: + quickload(); + return false; - case ACTION_SORT_ARMOR: - player_character.sort_armor(); - break; + case ACTION_PL_INFO: + player_character.disp_info(); + break; - case ACTION_WAIT: - wait(); - break; + case ACTION_MAP: + ui::omap::display(); + break; - case ACTION_CRAFT: - if( player_character.has_active_mutation( trait_SHELL2 ) ) { - add_msg( m_info, _( "You can't craft while you're in your shell." ) ); - } else if( player_character.has_effect( effect_incorporeal ) ) { - add_msg( m_info, _( "You lack the substance to affect anything." ) ); - } else if( player_character.is_mounted() ) { - add_msg( m_info, _( "You can't craft while you're riding." ) ); - } else { - player_character.craft(); - } - break; + case ACTION_SKY: + if( m.is_outside( player_character.pos() ) ) { + ui::omap::display_visible_weather(); + } else { + add_msg( m_info, _( "You can't see the sky from here." ) ); + } + break; - case ACTION_RECRAFT: - if( player_character.has_active_mutation( trait_SHELL2 ) ) { - add_msg( m_info, _( "You can't craft while you're in your shell." ) ); - } else if( player_character.has_effect( effect_incorporeal ) ) { - add_msg( m_info, _( "You lack the substance to affect anything." ) ); - } else if( player_character.is_mounted() ) { - add_msg( m_info, _( "You can't craft while you're riding." ) ); - } else { - player_character.recraft(); - } - break; + case ACTION_MISSIONS: + list_missions(); + break; - case ACTION_LONGCRAFT: - if( player_character.has_active_mutation( trait_SHELL2 ) ) { - add_msg( m_info, _( "You can't craft while you're in your shell." ) ); - } else if( player_character.is_mounted() ) { - add_msg( m_info, _( "You can't craft while you're riding." ) ); - } else if( u.has_effect( effect_incorporeal ) ) { - add_msg( m_info, _( "You lack the substance to affect anything." ) ); - } else { - player_character.long_craft(); - } - break; + case ACTION_SCORES: + show_scores_ui( *achievements_tracker_ptr, stats(), get_kill_tracker() ); + break; - case ACTION_DISASSEMBLE: - if( player_character.controlling_vehicle ) { - add_msg( m_info, _( "You can't disassemble items while driving." ) ); - } else if( player_character.is_mounted() ) { - add_msg( m_info, _( "You can't disassemble items while you're riding." ) ); - } else if( u.has_effect( effect_incorporeal ) ) { - add_msg( m_info, _( "You lack the substance to affect anything." ) ); - } else { - player_character.disassemble(); - } - break; + case ACTION_FACTIONS: + faction_manager_ptr->display(); + break; - case ACTION_CONSTRUCT: - if( player_character.in_vehicle ) { - add_msg( m_info, _( "You can't construct while in a vehicle." ) ); - } else if( player_character.has_active_mutation( trait_SHELL2 ) ) { - add_msg( m_info, _( "You can't construct while you're in your shell." ) ); - } else if( player_character.is_mounted() ) { - add_msg( m_info, _( "You can't construct while you're riding." ) ); - } else if( u.has_effect( effect_incorporeal ) ) { - add_msg( m_info, _( "You lack the substance to affect anything." ) ); - } else { - construction_menu( false ); - } - break; + case ACTION_MORALE: + player_character.disp_morale(); + break; - case ACTION_SLEEP: - if( veh_ctrl ) { - add_msg( m_info, _( "Vehicle control has moved, %s" ), - press_x( ACTION_CONTROL_VEHICLE, _( "new binding is " ), - _( "new default binding is '^'." ) ) ); - } else { - sleep(); - } - break; + case ACTION_MESSAGES: + Messages::display_messages(); + break; - case ACTION_CONTROL_VEHICLE: - if( player_character.has_active_mutation( trait_SHELL2 ) ) { - add_msg( m_info, _( "You can't operate a vehicle while you're in your shell." ) ); - } else if( player_character.is_mounted() ) { - player_character.dismount(); - } else if( player_character.has_trait( trait_WAYFARER ) ) { - add_msg( m_info, _( "You refuse to take control of this vehicle." ) ); - } else if( u.has_effect( effect_incorporeal ) ) { - add_msg( m_info, _( "You lack the substance to affect anything." ) ); - } else { - control_vehicle(); - } - break; + case ACTION_HELP: + get_help().display_help(); + break; - case ACTION_TOGGLE_AUTO_TRAVEL_MODE: - auto_travel_mode = !auto_travel_mode; - add_msg( m_info, auto_travel_mode ? _( "Auto travel mode ON!" ) : _( "Auto travel mode OFF!" ) ); - break; + case ACTION_OPTIONS: + get_options().show( true ); + break; - case ACTION_TOGGLE_SAFEMODE: - if( safe_mode == SAFE_MODE_OFF ) { - set_safe_mode( SAFE_MODE_ON ); - mostseen = 0; - add_msg( m_info, _( "Safe mode ON!" ) ); - } else { - turnssincelastmon = 0_turns; - set_safe_mode( SAFE_MODE_OFF ); - add_msg( m_info, get_option( "AUTOSAFEMODE" ) - ? _( "Safe mode OFF! (Auto safe mode still enabled!)" ) : _( "Safe mode OFF!" ) ); - } - if( player_character.has_effect( effect_laserlocked ) ) { - player_character.remove_effect( effect_laserlocked ); - safe_mode_warning_logged = false; - } - break; + case ACTION_AUTOPICKUP: + get_auto_pickup().show(); + break; - case ACTION_TOGGLE_AUTOSAFE: { - auto &autosafemode_option = get_options().get_option( "AUTOSAFEMODE" ); - add_msg( m_info, autosafemode_option.value_as() - ? _( "Auto safe mode OFF!" ) : _( "Auto safe mode ON!" ) ); - autosafemode_option.setNext(); - break; - } + case ACTION_AUTONOTES: + get_auto_notes_settings().show_gui(); + break; - case ACTION_IGNORE_ENEMY: - if( safe_mode == SAFE_MODE_STOP ) { - add_msg( m_info, _( "Ignoring enemy!" ) ); - for( auto &elem : player_character.get_mon_visible().new_seen_mon ) { - monster &critter = *elem; - critter.ignoring = rl_dist( player_character.pos(), critter.pos() ); - } - set_safe_mode( SAFE_MODE_ON ); - } else if( player_character.has_effect( effect_laserlocked ) ) { - if( player_character.has_trait( trait_PROF_CHURL ) ) { - add_msg( m_warning, _( "You make the sign of the cross." ) ); - } else { - add_msg( m_info, _( "Ignoring laser targeting!" ) ); - } - player_character.remove_effect( effect_laserlocked ); - safe_mode_warning_logged = false; - } - break; + case ACTION_SAFEMODE: + get_safemode().show(); + break; + + case ACTION_COLOR: + all_colors.show_gui(); + break; - case ACTION_WHITELIST_ENEMY: - if( safe_mode == SAFE_MODE_STOP && !get_safemode().empty() ) { - get_safemode().add_rule( get_safemode().lastmon_whitelist, Creature::Attitude::ANY, 0, - rule_state::WHITELISTED ); - add_msg( m_info, _( "Creature whitelisted: %s" ), get_safemode().lastmon_whitelist ); - set_safe_mode( SAFE_MODE_ON ); - mostseen = 0; - } else { - get_safemode().show(); - } - break; + case ACTION_WORLD_MODS: + world_generator->show_active_world_mods( world_generator->active_world->active_mod_order ); + break; - case ACTION_WORKOUT: - if( query_yn( _( "Start workout?" ) ) ) { - player_character.assign_activity( player_activity( workout_activity_actor( - player_character.pos() ) ) ); - } - break; + case ACTION_DEBUG: + if( MAP_SHARING::isCompetitive() && !MAP_SHARING::isDebugger() ) { + break; //don't do anything when sharing and not debugger + } + debug_menu::debug(); + break; - case ACTION_SUICIDE: - if( query_yn( _( "Commit suicide?" ) ) ) { - if( query_yn( _( "REALLY commit suicide?" ) ) ) { - player_character.moves = 0; - player_character.place_corpse(); - uquit = QUIT_SUICIDE; - } - } - break; + case ACTION_TOGGLE_FULLSCREEN: + toggle_fullscreen(); + break; - case ACTION_SAVE: - if( query_yn( _( "Save and quit?" ) ) ) { - if( save() ) { - player_character.moves = 0; - uquit = QUIT_SAVED; - } - } - break; + case ACTION_TOGGLE_PIXEL_MINIMAP: + toggle_pixel_minimap(); + break; - case ACTION_QUICKSAVE: - quicksave(); - return false; + case ACTION_TOGGLE_PANEL_ADM: + panel_manager::get_manager().show_adm(); + break; - case ACTION_QUICKLOAD: - quickload(); - return false; + case ACTION_RELOAD_TILESET: + reload_tileset(); + break; - case ACTION_PL_INFO: - player_character.disp_info(); - break; + case ACTION_TOGGLE_AUTO_FEATURES: + get_options().get_option( "AUTO_FEATURES" ).setNext(); + get_options().save(); + //~ Auto Features are now ON/OFF + add_msg( _( "%s are now %s." ), + get_options().get_option( "AUTO_FEATURES" ).getMenuText(), + get_option( "AUTO_FEATURES" ) ? _( "ON" ) : _( "OFF" ) ); + break; - case ACTION_MAP: - ui::omap::display(); - break; + case ACTION_TOGGLE_AUTO_PULP_BUTCHER: + get_options().get_option( "AUTO_PULP_BUTCHER" ).setNext(); + get_options().save(); + //~ Auto Pulp/Pulp Adjacent/Butcher is now set to x + add_msg( _( "%s is now set to %s." ), + get_options().get_option( "AUTO_PULP_BUTCHER" ).getMenuText(), + get_options().get_option( "AUTO_PULP_BUTCHER" ).getValueName() ); + break; - case ACTION_SKY: - if( m.is_outside( player_character.pos() ) ) { - ui::omap::display_visible_weather(); - } else { - add_msg( m_info, _( "You can't see the sky from here." ) ); - } - break; + case ACTION_TOGGLE_AUTO_MINING: + get_options().get_option( "AUTO_MINING" ).setNext(); + get_options().save(); + //~ Auto Mining is now ON/OFF + add_msg( _( "%s is now %s." ), + get_options().get_option( "AUTO_MINING" ).getMenuText(), + get_option( "AUTO_MINING" ) ? _( "ON" ) : _( "OFF" ) ); + break; - case ACTION_MISSIONS: - list_missions(); - break; + case ACTION_TOGGLE_THIEF_MODE: + if( player_character.get_value( "THIEF_MODE" ) == "THIEF_ASK" ) { + player_character.set_value( "THIEF_MODE", "THIEF_HONEST" ); + player_character.set_value( "THIEF_MODE_KEEP", "YES" ); + //~ Thief mode cycled between THIEF_ASK/THIEF_HONEST/THIEF_STEAL + add_msg( _( "You will not pick up other peoples belongings." ) ); + } else if( player_character.get_value( "THIEF_MODE" ) == "THIEF_HONEST" ) { + player_character.set_value( "THIEF_MODE", "THIEF_STEAL" ); + player_character.set_value( "THIEF_MODE_KEEP", "YES" ); + //~ Thief mode cycled between THIEF_ASK/THIEF_HONEST/THIEF_STEAL + add_msg( _( "You will pick up also those things that belong to others!" ) ); + } else if( player_character.get_value( "THIEF_MODE" ) == "THIEF_STEAL" ) { + player_character.set_value( "THIEF_MODE", "THIEF_ASK" ); + player_character.set_value( "THIEF_MODE_KEEP", "NO" ); + //~ Thief mode cycled between THIEF_ASK/THIEF_HONEST/THIEF_STEAL + add_msg( _( "You will be reminded not to steal." ) ); + } else { + // ERROR + add_msg( _( "THIEF_MODE CONTAINED BAD VALUE [ %s ]!" ), + player_character.get_value( "THIEF_MODE" ) ); + } + break; - case ACTION_SCORES: - show_scores_ui( *achievements_tracker_ptr, stats(), get_kill_tracker() ); - break; + case ACTION_TOGGLE_AUTO_FORAGING: + get_options().get_option( "AUTO_FORAGING" ).setNext(); + get_options().save(); + //~ Auto Foraging is now set to x + add_msg( _( "%s is now set to %s." ), + get_options().get_option( "AUTO_FORAGING" ).getMenuText(), + get_options().get_option( "AUTO_FORAGING" ).getValueName() ); + break; - case ACTION_FACTIONS: - faction_manager_ptr->display(); - break; + case ACTION_TOGGLE_AUTO_PICKUP: + get_options().get_option( "AUTO_PICKUP" ).setNext(); + get_options().save(); + //~ Auto pickup is now set to x + add_msg( _( "%s is now set to %s." ), + get_options().get_option( "AUTO_PICKUP" ).getMenuText(), + get_options().get_option( "AUTO_PICKUP" ).getValueName() ); + break; - case ACTION_MORALE: - player_character.disp_morale(); - break; + case ACTION_DISPLAY_SCENT: + if( MAP_SHARING::isCompetitive() && !MAP_SHARING::isDebugger() ) { + break; //don't do anything when sharing and not debugger + } + display_scent(); + break; - case ACTION_MESSAGES: - Messages::display_messages(); - break; + case ACTION_DISPLAY_SCENT_TYPE: + if( MAP_SHARING::isCompetitive() && !MAP_SHARING::isDebugger() ) { + break; //don't do anything when sharing and not debugger + } + display_scent(); + break; - case ACTION_HELP: - get_help().display_help(); - break; + case ACTION_DISPLAY_TEMPERATURE: + if( MAP_SHARING::isCompetitive() && !MAP_SHARING::isDebugger() ) { + break; //don't do anything when sharing and not debugger + } + display_temperature(); + break; + case ACTION_DISPLAY_VEHICLE_AI: + if( MAP_SHARING::isCompetitive() && !MAP_SHARING::isDebugger() ) { + break; //don't do anything when sharing and not debugger + } + display_vehicle_ai(); + break; + case ACTION_DISPLAY_VISIBILITY: + if( MAP_SHARING::isCompetitive() && !MAP_SHARING::isDebugger() ) { + break; //don't do anything when sharing and not debugger + } + display_visibility(); + break; - case ACTION_OPTIONS: - get_options().show( true ); - break; + case ACTION_DISPLAY_LIGHTING: + if( MAP_SHARING::isCompetitive() && !MAP_SHARING::isDebugger() ) { + break; //don't do anything when sharing and not debugger + } + display_lighting(); + break; - case ACTION_AUTOPICKUP: - get_auto_pickup().show(); - break; + case ACTION_DISPLAY_RADIATION: + if( MAP_SHARING::isCompetitive() && !MAP_SHARING::isDebugger() ) { + break; //don't do anything when sharing and not debugger + } + display_radiation(); + break; - case ACTION_AUTONOTES: - get_auto_notes_settings().show_gui(); - break; + case ACTION_TOGGLE_HOUR_TIMER: + toggle_debug_hour_timer(); + break; - case ACTION_SAFEMODE: - get_safemode().show(); - break; + case ACTION_DISPLAY_TRANSPARENCY: + if( MAP_SHARING::isCompetitive() && !MAP_SHARING::isDebugger() ) { + break; //don't do anything when sharing and not debugger + } + display_transparency(); + break; - case ACTION_COLOR: - all_colors.show_gui(); - break; + case ACTION_DISPLAY_REACHABILITY_ZONES: + if( MAP_SHARING::isCompetitive() && !MAP_SHARING::isDebugger() ) { + break; //don't do anything when sharing and not debugger + } + display_reachability_zones(); + break; - case ACTION_WORLD_MODS: - world_generator->show_active_world_mods( world_generator->active_world->active_mod_order ); - break; + case ACTION_TOGGLE_DEBUG_MODE: + if( MAP_SHARING::isCompetitive() && !MAP_SHARING::isDebugger() ) { + break; //don't do anything when sharing and not debugger + } + handle_debug_mode(); + break; - case ACTION_DEBUG: - if( MAP_SHARING::isCompetitive() && !MAP_SHARING::isDebugger() ) { - break; //don't do anything when sharing and not debugger - } - debug_menu::debug(); - break; + case ACTION_ZOOM_IN: + zoom_in(); + break; - case ACTION_TOGGLE_FULLSCREEN: - toggle_fullscreen(); - break; + case ACTION_ZOOM_OUT: + zoom_out(); + break; - case ACTION_TOGGLE_PIXEL_MINIMAP: - toggle_pixel_minimap(); - break; + case ACTION_ITEMACTION: + item_action_menu(); + break; - case ACTION_TOGGLE_PANEL_ADM: - panel_manager::get_manager().show_adm(); - break; + case ACTION_AUTOATTACK: + avatar_action::autoattack( player_character, m ); + break; - case ACTION_RELOAD_TILESET: - reload_tileset(); - break; + default: + break; + } - case ACTION_TOGGLE_AUTO_FEATURES: - get_options().get_option( "AUTO_FEATURES" ).setNext(); - get_options().save(); - //~ Auto Features are now ON/OFF - add_msg( _( "%s are now %s." ), - get_options().get_option( "AUTO_FEATURES" ).getMenuText(), - get_option( "AUTO_FEATURES" ) ? _( "ON" ) : _( "OFF" ) ); - break; + return true; +} - case ACTION_TOGGLE_AUTO_PULP_BUTCHER: - get_options().get_option( "AUTO_PULP_BUTCHER" ).setNext(); - get_options().save(); - //~ Auto Pulp/Pulp Adjacent/Butcher is now set to x - add_msg( _( "%s is now set to %s." ), - get_options().get_option( "AUTO_PULP_BUTCHER" ).getMenuText(), - get_options().get_option( "AUTO_PULP_BUTCHER" ).getValueName() ); - break; +bool game::handle_action() +{ + std::string action; + input_context ctxt; + action_id act = ACTION_NULL; + user_turn current_turn; + avatar &player_character = get_avatar(); + // Check if we have an auto-move destination + if( player_character.has_destination() ) { + act = player_character.get_next_auto_move_direction(); + if( act == ACTION_NULL ) { + add_msg( m_info, _( "Auto-move canceled" ) ); + player_character.clear_destination(); + return false; + } + } else if( player_character.has_destination_activity() ) { + // starts destination activity after the player successfully reached his destination + player_character.start_destination_activity(); + return false; + } else { + // No auto-move, ask player for input + ctxt = get_player_input( action ); + } - case ACTION_TOGGLE_AUTO_MINING: - get_options().get_option( "AUTO_MINING" ).setNext(); - get_options().save(); - //~ Auto Mining is now ON/OFF - add_msg( _( "%s is now %s." ), - get_options().get_option( "AUTO_MINING" ).getMenuText(), - get_option( "AUTO_MINING" ) ? _( "ON" ) : _( "OFF" ) ); - break; + bool veh_ctrl = has_vehicle_control( player_character ); - case ACTION_TOGGLE_THIEF_MODE: - if( player_character.get_value( "THIEF_MODE" ) == "THIEF_ASK" ) { - player_character.set_value( "THIEF_MODE", "THIEF_HONEST" ); - player_character.set_value( "THIEF_MODE_KEEP", "YES" ); - //~ Thief mode cycled between THIEF_ASK/THIEF_HONEST/THIEF_STEAL - add_msg( _( "You will not pick up other peoples belongings." ) ); - } else if( player_character.get_value( "THIEF_MODE" ) == "THIEF_HONEST" ) { - player_character.set_value( "THIEF_MODE", "THIEF_STEAL" ); - player_character.set_value( "THIEF_MODE_KEEP", "YES" ); - //~ Thief mode cycled between THIEF_ASK/THIEF_HONEST/THIEF_STEAL - add_msg( _( "You will pick up also those things that belong to others!" ) ); - } else if( player_character.get_value( "THIEF_MODE" ) == "THIEF_STEAL" ) { - player_character.set_value( "THIEF_MODE", "THIEF_ASK" ); - player_character.set_value( "THIEF_MODE_KEEP", "NO" ); - //~ Thief mode cycled between THIEF_ASK/THIEF_HONEST/THIEF_STEAL - add_msg( _( "You will be reminded not to steal." ) ); - } else { - // ERROR - add_msg( _( "THIEF_MODE CONTAINED BAD VALUE [ %s ]!" ), - player_character.get_value( "THIEF_MODE" ) ); - } - break; + // If performing an action with right mouse button, co-ordinates + // of location clicked. + cata::optional mouse_target; - case ACTION_TOGGLE_AUTO_FORAGING: - get_options().get_option( "AUTO_FORAGING" ).setNext(); - get_options().save(); - //~ Auto Foraging is now set to x - add_msg( _( "%s is now set to %s." ), - get_options().get_option( "AUTO_FORAGING" ).getMenuText(), - get_options().get_option( "AUTO_FORAGING" ).getValueName() ); - break; + if( uquit == QUIT_WATCH && action == "QUIT" ) { + uquit = QUIT_DIED; + return false; + } - case ACTION_TOGGLE_AUTO_PICKUP: - get_options().get_option( "AUTO_PICKUP" ).setNext(); - get_options().save(); - //~ Auto pickup is now set to x - add_msg( _( "%s is now set to %s." ), - get_options().get_option( "AUTO_PICKUP" ).getMenuText(), - get_options().get_option( "AUTO_PICKUP" ).getValueName() ); - break; + if( act == ACTION_NULL ) { + act = look_up_action( action ); - case ACTION_DISPLAY_SCENT: - if( MAP_SHARING::isCompetitive() && !MAP_SHARING::isDebugger() ) { - break; //don't do anything when sharing and not debugger - } - display_scent(); - break; + if( act == ACTION_KEYBINDINGS ) { + // already handled by input context + return false; + } - case ACTION_DISPLAY_SCENT_TYPE: - if( MAP_SHARING::isCompetitive() && !MAP_SHARING::isDebugger() ) { - break; //don't do anything when sharing and not debugger - } - display_scent(); - break; + if( act == ACTION_MAIN_MENU ) { + if( uquit == QUIT_WATCH ) { + return false; + } + // No auto-move actions have or can be set at this point. + player_character.clear_destination(); + destination_preview.clear(); + act = handle_main_menu(); + if( act == ACTION_NULL ) { + return false; + } + } - case ACTION_DISPLAY_TEMPERATURE: - if( MAP_SHARING::isCompetitive() && !MAP_SHARING::isDebugger() ) { - break; //don't do anything when sharing and not debugger - } - display_temperature(); - break; - case ACTION_DISPLAY_VEHICLE_AI: - if( MAP_SHARING::isCompetitive() && !MAP_SHARING::isDebugger() ) { - break; //don't do anything when sharing and not debugger - } - display_vehicle_ai(); - break; - case ACTION_DISPLAY_VISIBILITY: - if( MAP_SHARING::isCompetitive() && !MAP_SHARING::isDebugger() ) { - break; //don't do anything when sharing and not debugger - } - display_visibility(); - break; + if( act == ACTION_ACTIONMENU ) { + if( uquit == QUIT_WATCH ) { + return false; + } + // No auto-move actions have or can be set at this point. + player_character.clear_destination(); + destination_preview.clear(); + act = handle_action_menu(); + if( act == ACTION_NULL ) { + return false; + } +#if defined(__ANDROID__) + if( get_option( "ANDROID_ACTIONMENU_AUTOADD" ) && ctxt.get_category() == "DEFAULTMODE" ) { + add_best_key_for_action_to_quick_shortcuts( act, ctxt.get_category(), false ); + } +#endif + } - case ACTION_DISPLAY_LIGHTING: - if( MAP_SHARING::isCompetitive() && !MAP_SHARING::isDebugger() ) { - break; //don't do anything when sharing and not debugger - } - display_lighting(); - break; + if( act == ACTION_KEYBINDINGS ) { + player_character.clear_destination(); + destination_preview.clear(); + act = ctxt.display_menu( true ); + if( act == ACTION_NULL ) { + return false; + } + } - case ACTION_DISPLAY_RADIATION: - if( MAP_SHARING::isCompetitive() && !MAP_SHARING::isDebugger() ) { - break; //don't do anything when sharing and not debugger - } - display_radiation(); - break; + if( can_action_change_worldstate( act ) ) { + user_action_counter += 1; + } - case ACTION_TOGGLE_HOUR_TIMER: - toggle_debug_hour_timer(); - break; + if( act == ACTION_SELECT || act == ACTION_SEC_SELECT ) { + // Mouse button click + if( veh_ctrl ) { + // No mouse use in vehicle + return false; + } - case ACTION_DISPLAY_TRANSPARENCY: - if( MAP_SHARING::isCompetitive() && !MAP_SHARING::isDebugger() ) { - break; //don't do anything when sharing and not debugger - } - display_transparency(); - break; + if( player_character.is_dead_state() ) { + // do not allow mouse actions while dead + return false; + } - case ACTION_DISPLAY_REACHABILITY_ZONES: - if( MAP_SHARING::isCompetitive() && !MAP_SHARING::isDebugger() ) { - break; //don't do anything when sharing and not debugger - } - display_reachability_zones(); - break; + const cata::optional mouse_pos = ctxt.get_coordinates( w_terrain ); + if( !mouse_pos ) { + return false; + } else if( !player_character.sees( *mouse_pos ) ) { + // Not clicked in visible terrain + return false; + } + mouse_target = mouse_pos; - case ACTION_TOGGLE_DEBUG_MODE: - if( MAP_SHARING::isCompetitive() && !MAP_SHARING::isDebugger() ) { - break; //don't do anything when sharing and not debugger + if( act == ACTION_SELECT ) { + // Note: The following has the potential side effect of + // setting auto-move destination state in addition to setting + // act. + if( !try_get_left_click_action( act, *mouse_target ) ) { + return false; } - handle_debug_mode(); - break; + } else if( act == ACTION_SEC_SELECT ) { + if( !try_get_right_click_action( act, *mouse_target ) ) { + return false; + } + } + } else if( act != ACTION_TIMEOUT ) { + // act has not been set for an auto-move, so clearing possible + // auto-move destinations. Since initializing an auto-move with + // the mouse may span across multiple actions, we do not clear the + // auto-move destination if the action is only a timeout, as this + // would require the user to double click quicker than the + // timeout delay. + player_character.clear_destination(); + destination_preview.clear(); + } + } - case ACTION_ZOOM_IN: - zoom_in(); - break; + if( act == ACTION_NULL ) { + const input_event &&evt = ctxt.get_raw_input(); + if( !evt.sequence.empty() ) { + const int ch = evt.get_first_input(); + if( !get_option( "NO_UNKNOWN_COMMAND_MSG" ) ) { + add_msg( m_info, _( "Unknown command: \"%s\" (%ld)" ), evt.long_description(), ch ); + if( const cata::optional hint = + press_x_if_bound( ACTION_KEYBINDINGS ) ) { + add_msg( m_info, _( "%s at any time to see and edit keybindings relevant to " + "the current context." ), + *hint ); + } + } + } + return false; + } - case ACTION_ZOOM_OUT: - zoom_out(); - break; + // This has no action unless we're in a special game mode. + gamemode->pre_action( act ); - case ACTION_ITEMACTION: - item_action_menu(); - break; + int before_action_moves = player_character.moves; - case ACTION_AUTOATTACK: - avatar_action::autoattack( player_character, m ); - break; + // These actions are allowed while deathcam is active. Registered in game::get_player_input + if( uquit == QUIT_WATCH || !player_character.is_dead_state() ) { + do_deathcam_action( act, player_character ); + } - default: - break; + // actions allowed only while alive + if( !player_character.is_dead_state() ) { + if( !do_regular_action( act, player_character, mouse_target ) ) { + return false; } } if( act != ACTION_TIMEOUT ) { From 1bcc1f695ba7d54e446b8e09d0026d598f05ccae Mon Sep 17 00:00:00 2001 From: John Bytheway Date: Sat, 3 Apr 2021 07:22:14 -0400 Subject: [PATCH 352/453] Refactor Character::hardcoded_effects Split some more effects out into their own specific functions to reduce the size of this very large function. --- src/player_hardcoded_effects.cpp | 1263 +++++++++++++++--------------- 1 file changed, 648 insertions(+), 615 deletions(-) diff --git a/src/player_hardcoded_effects.cpp b/src/player_hardcoded_effects.cpp index 9ae508df29920..cc46a9a53e9ac 100644 --- a/src/player_hardcoded_effects.cpp +++ b/src/player_hardcoded_effects.cpp @@ -491,6 +491,649 @@ static void eff_fun_frostbite( Character &u, effect &it ) } } +static void eff_fun_teleglow( Character &u, effect &it ) +{ + // Default we get around 300 duration points per teleport (possibly more + // depending on the source). + // TODO: Include a chance to teleport to the nether realm. + // TODO: This with regards to NPCS + if( !u.is_player() ) { + // NO, no teleporting around the player because an NPC has teleglow! + return; + } + const time_duration dur = it.get_duration(); + Character &player_character = get_player_character(); + map &here = get_map(); + if( dur > 10_hours ) { + // 20 teleports (no decay; in practice at least 21) + if( one_in( 6000 - ( ( dur - 600_minutes ) / 1_minutes ) ) ) { + if( !u.is_npc() ) { + add_msg( _( "Glowing lights surround you, and you teleport." ) ); + } + teleport::teleport( u ); + get_event_bus().send( u.getID() ); + if( one_in( 10 ) ) { + // Set ourselves up for removal + it.set_duration( 0_turns ); + } + } + } + if( one_in( 7200 - ( dur - 360_minutes ) / 4_turns ) ) { + //Spawn a tindalos rift via effect_tindrift rather than it being hard-coded to teleglow + u.add_effect( effect_tindrift, 5_turns ); + + if( one_in( 2 ) ) { + // Set ourselves up for removal + it.set_duration( 0_turns ); + } + } + if( one_in( 7200 - ( ( dur - 600_minutes ) / 30_seconds ) ) && one_in( 20 ) ) { + u.add_msg_if_player( m_bad, _( "You pass out." ) ); + u.fall_asleep( 2_hours ); + if( one_in( 6 ) ) { + // Set ourselves up for removal + it.set_duration( 0_turns ); + } + } + if( dur > 6_hours ) { + // 12 teleports + if( one_in( 24000 - ( dur - 360_minutes ) / 4_turns ) ) { + tripoint dest( 0, 0, u.posz() ); + int &x = dest.x; + int &y = dest.y; + int tries = 0; + do { + x = u.posx() + rng( -4, 4 ); + y = u.posy() + rng( -4, 4 ); + tries++; + if( tries >= 10 ) { + break; + } + } while( g->critter_at( dest ) ); + if( tries < 10 ) { + if( here.impassable( dest ) ) { + here.make_rubble( dest, f_rubble_rock, true ); + } + MonsterGroupResult spawn_details = MonsterGroupManager::GetResultFromGroup( + GROUP_NETHER ); + g->place_critter_at( spawn_details.name, dest ); + if( player_character.sees( dest ) ) { + g->cancel_activity_or_ignore_query( distraction_type::hostile_spotted_far, + _( "A monster appears nearby!" ) ); + add_msg( m_warning, _( "A portal opens nearby, and a monster crawls through!" ) ); + } + if( one_in( 2 ) ) { + // Set ourselves up for removal + it.set_duration( 0_turns ); + } + } + } + if( one_in( 21000 - ( dur - 360_minutes ) / 4_turns ) ) { + u.add_msg_if_player( m_bad, _( "You shudder suddenly." ) ); + u.mutate(); + if( one_in( 4 ) ) { + // Set ourselves up for removal + it.set_duration( 0_turns ); + } + } + } + if( dur > 4_hours ) { + // 8 teleports + if( one_turn_in( 1000_minutes - dur ) && !u.has_effect( effect_valium ) ) { + u.add_effect( effect_shakes, rng( 4_minutes, 8_minutes ) ); + } + if( one_turn_in( 1200_minutes - dur ) ) { + u.add_msg_if_player( m_bad, _( "Your vision is filled with bright lights…" ) ); + u.add_effect( effect_blind, rng( 1_minutes, 2_minutes ) ); + if( one_in( 8 ) ) { + // Set ourselves up for removal + it.set_duration( 0_turns ); + } + } + if( one_in( 5000 ) && !u.has_effect( effect_hallu ) ) { + u.add_effect( effect_hallu, 6_hours ); + if( one_in( 5 ) ) { + // Set ourselves up for removal + it.set_duration( 0_turns ); + } + } + } + if( one_in( 4000 ) ) { + u.add_msg_if_player( m_bad, _( "You're suddenly covered in ectoplasm." ) ); + u.add_effect( effect_boomered, 10_minutes ); + if( one_in( 4 ) ) { + // Set ourselves up for removal + it.set_duration( 0_turns ); + } + } + if( one_in( 10000 ) ) { + if( !u.has_trait( trait_M_IMMUNE ) ) { + u.add_effect( effect_fungus, 1_turns, true ); + } else { + u.add_msg_if_player( m_info, _( "We have many colonists awaiting passage." ) ); + } + // Set ourselves up for removal + it.set_duration( 0_turns ); + } +} + +static void eff_fun_datura( Character &u, effect &it ) +{ + const time_duration dur = it.get_duration(); + if( dur > 100_minutes && u.get_focus() >= 1 && one_in( 24 ) ) { + u.mod_focus( -1 ); + } + if( dur > 200_minutes && one_in( 48 ) && u.get_stim() < 20 ) { + u.mod_stim( 1 ); + } + if( dur > 300_minutes && u.get_focus() >= 1 && one_in( 12 ) ) { + u.mod_focus( -1 ); + } + if( dur > 400_minutes && one_in( 384 ) ) { + u.mod_pain( rng( -1, -8 ) ); + } + if( ( !u.has_effect( effect_hallu ) ) && ( dur > 500_minutes && one_in( 24 ) ) ) { + u.add_effect( effect_hallu, 6_hours ); + } + if( dur > 600_minutes && one_in( 768 ) ) { + u.mod_pain( rng( -3, -24 ) ); + if( dur > 800_minutes && one_in( 16 ) ) { + u.add_msg_if_player( m_bad, + _( "You're experiencing loss of basic motor skills and blurred vision. Your mind recoils in horror, unable to communicate with your spinal column." ) ); + u.add_msg_if_player( m_bad, _( "You stagger and fall!" ) ); + u.add_effect( effect_downed, rng( 1_turns, 4_turns ), false, 0, true ); + if( one_in( 8 ) || x_in_y( u.vomit_mod(), 10 ) ) { + u.vomit(); + } + } + } + if( dur > 700_minutes && u.get_focus() >= 1 ) { + u.mod_focus( -1 ); + } + if( dur > 800_minutes && one_in( 1536 ) ) { + u.add_effect( effect_visuals, rng( 4_minutes, 20_minutes ) ); + u.mod_pain( rng( -8, -40 ) ); + } + if( dur > 1200_minutes && one_in( 1536 ) ) { + u.add_msg_if_player( m_bad, _( "There's some kind of big machine in the sky." ) ); + u.add_effect( effect_visuals, rng( 8_minutes, 40_minutes ) ); + if( one_in( 32 ) ) { + u.add_msg_if_player( m_bad, _( "It's some kind of electric snake, coming right at you!" ) ); + u.mod_pain( rng( 4, 40 ) ); + u.vomit(); + } + } + if( dur > 1400_minutes && one_in( 768 ) ) { + u.add_msg_if_player( m_bad, + _( "Order us some golf shoes, otherwise we'll never get out of this place alive." ) ); + u.add_effect( effect_visuals, rng( 40_minutes, 200_minutes ) ); + if( one_in( 8 ) ) { + u.add_msg_if_player( m_bad, + _( "The possibility of physical and mental collapse is now very real." ) ); + if( one_in( 2 ) || x_in_y( u.vomit_mod(), 10 ) ) { + u.add_msg_if_player( m_bad, _( "No one should be asked to handle this trip." ) ); + u.vomit(); + u.mod_pain( rng( 8, 40 ) ); + } + } + } + + if( dur > 1800_minutes && one_in( 300 * 512 ) ) { + if( !u.has_trait( trait_NOPAIN ) ) { + u.add_msg_if_player( m_bad, + _( "Your heart spasms painfully and stops, dragging you back to reality as you die." ) ); + } else { + u.add_msg_if_player( + _( "You dissolve into beautiful paroxysms of energy. Life fades from your nebulae and you are no more." ) ); + } + get_event_bus().send( u.getID(), it.get_id() ); + u.set_part_hp_cur( bodypart_id( "torso" ), 0 ); + } +} + +static void eff_fun_hypovolemia( Character &u, effect &it ) +{ + // hypovolemia and dehydration are closely related so it will pull water + // from your system to replenish blood quantity + int intense = it.get_intensity(); + + if( calendar::once_every( -u.vitamin_rate( vitamin_blood ) ) && one_in( 5 ) && + u.get_thirst() <= 240 ) { + u.mod_thirst( rng( 0, intense ) ); + } + // bleed out lambda + auto bleed_out = [&] { + if( u.has_effect( effect_bleed ) ) + { + u.add_msg_player_or_npc( m_bad, + _( "You bleed to death!" ), + _( " bleeds to death!" ) ); + get_event_bus().send( u.getID() ); + } else + { + u.add_msg_player_or_npc( m_bad, + _( "Your heart can't keep up the pace and fails!" ), + _( " has a sudden heart attack!" ) ); + get_event_bus().send( u.getID() ); + } + u.set_part_hp_cur( bodypart_id( "torso" ), 0 ); + }; + // this goes first because beyond minimum threshold you just die without delay, + // while stage 4 is on a timer check with an rng grace period + + if( u.vitamin_get( vitamin_blood ) == vitamin_blood->min() ) { + bleed_out(); + } + + // Hypovolemic shock + // stage 1 - early symptoms include headache, fatigue, weakness, thirst, and dizziness. + // stage 2 - person may begin sweating and feeling more anxious and restless. + // stage 3 - heart rate will increase to over 120 bpm; rapid breathing + // mental distress, including anxiety and agitation; skin is pale and cold + cyanosis, sweating + // stage 4 is a life threatening condition; extremely rapid heart rate, breathing very fast and difficult + // drifting in and out of consciousness, sweating heavily, feeling cool to the touch, looking extremely pale + + if( one_in( 1200 / intense ) && !u.in_sleep_state() ) { + std::string warning; + + if( one_in( 5 ) ) { + // no-effect message block + if( intense == 1 ) { + warning = _( "Your skin looks pale and you feel anxious and thirsty. Blood loss?" ); + } else if( intense == 2 ) { + warning = _( "Your pale skin is sweating, your heart is beating fast, and you feel restless. Maybe you lost too much blood?" ); + } else if( intense == 3 ) { + warning = _( "You're unsettlingly white, but your fingertips are bluish. You are agitated and your heart is racing. Your blood loss must be serious." ); + } else { //intense == 4 + warning = _( "You are pale as a ghost, dripping wet from the sweat, and sluggish - despite your heart racing like a train. You are on the brink of collapse from the effects of blood loss." ); + } + u.add_msg_if_player( m_bad, warning ); + } else { + // effect dice, with progression of effects, 3 possible effects per tier + int dice_roll = rng( 0, 2 ) + intense; + switch( dice_roll ) { + case 1: + warning = _( "You feel dizzy and lightheaded." ); + u.add_effect( effect_stunned, rng( 5_seconds * intense, 2_minutes * intense ) ); + break; + case 2: + warning = _( "You feel tired and you breathe heavily." ); + u.mod_fatigue( 3 * intense ); + break; + case 3: + warning = _( "You are anxious and cannot collect your thoughts." ); + u.mod_focus( -rng( 1, u.get_focus() * intense / it.get_max_intensity() ) ); + break; + case 4: + warning = _( "You are sweating profusely, but you feel cold." ); + u.mod_part_temp_conv( bodypart_id( "hand_l" ), - 1000 * intense ); + u.mod_part_temp_conv( bodypart_id( "hand_r" ), -1000 * intense ); + u.mod_part_temp_conv( bodypart_id( "foot_l" ), -1000 * intense ); + u.mod_part_temp_conv( bodypart_id( "foot_r" ), -1000 * intense ); + break; + case 5: + warning = _( "You huff and puff. Your breath is rapid and shallow." ); + u.mod_stamina( -500 * intense ); + break; + case 6: + if( one_in( 2 ) ) { + warning = _( "You drop to the ground, fighting to keep yourself conscious." ); + u.add_effect( effect_downed, rng( 1_minutes, 2_minutes ) ); + break; + } else { + warning = _( "Your mind slips away." ); + u.fall_asleep( rng( 2_minutes, 5_minutes ) ); + break; + } + } + u.add_msg_if_player( m_bad, warning ); + } + } + // this goes last because we don't want in_sleep_state to prevent you from dying + if( intense == 4 && one_in( 900 ) && + rng( 1, -vitamin_blood->min() * 3 / 5 ) > ( -vitamin_blood->min() + u.vitamin_get( + vitamin_blood ) ) ) { + bleed_out(); + } +} + +static void eff_fun_redcells_anemia( Character &u, effect &it ) +{ + // Lack of iron impairs production of hemoglobin and therefore ability to carry + // oxygen by red blood cells. Alternatively hemorrhage causes physical loss of red blood cells. + // This triggers variety of symptoms, focusing on weakness, + // fatigue, cold limbs, later in dizziness, soreness, breathlessness, + // and severe malaise and lethargy. + // Base anemia symptoms: fatigue, loss of stamina, loss of strength, impact on health + // are placed in effect JSON + + int intense = it.get_intensity(); + + // you can only lose as much red blood cells before your body fails to function + if( u.vitamin_get( vitamin_redcells ) <= vitamin_redcells->min() + 5 ) { + u.add_msg_player_or_npc( m_bad, + _( "You cannot breathe and your body gives out!" ), + _( " gasps for air and dies!" ) ); + get_event_bus().send( u.getID() ); + u.set_part_hp_cur( bodypart_id( "torso" ), 0 ); + } + if( one_in( 900 / intense ) && !u.in_sleep_state() ) { + // level 1 symptoms are cold limbs, pale skin, and weakness + switch( dice( 1, 9 ) ) { + case 1: + u.add_msg_if_player( m_bad, _( "Your hands feel unusually cold." ) ); + u.mod_part_temp_conv( bodypart_id( "hand_l" ), -2000 ); + u.mod_part_temp_conv( bodypart_id( "hand_r" ), -2000 ); + break; + case 2: + u.add_msg_if_player( m_bad, _( "Your feet feel unusually cold." ) ); + u.mod_part_temp_conv( bodypart_id( "foot_l" ), -2000 ); + u.mod_part_temp_conv( bodypart_id( "foot_r" ), -2000 ); + break; + case 3: + u.add_msg_if_player( m_bad, _( "Your skin looks very pale." ) ); + break; + case 4: + u.add_msg_if_player( m_bad, _( "You feel weak. Where has your strength gone?" ) ); + break; + case 5: + u.add_msg_if_player( m_bad, _( "You feel feeble. A gust of wind could make you stumble." ) ); + break; + case 6: + u.add_msg_if_player( m_bad, _( "There is an overwhelming aura of tiredness inside of you." ) ); + u.mod_fatigue( intense * 3 ); + break; + case 7: // 7-9 empty for variability, as messages stack on higher intensity + break; + case 8: + break; + case 9: + break; + } + // level 2 anemia introduces dizziness, shakes, headaches, cravings for non-comestibles, + // mouth and tongue soreness + if( intense > 1 ) { + switch( dice( 1, 9 ) ) { + case 1: + u.add_msg_if_player( m_bad, _( "Rest is what you want. Rest is what you need." ) ); + break; + case 2: + u.add_msg_if_player( m_bad, _( "You feel dizzy and can't coordinate the movement of your feet." ) ); + u.add_effect( effect_stunned, rng( 1_minutes, 2_minutes ) ); + break; + case 3: + u.add_msg_if_player( m_bad, _( "Your muscles are quivering." ) ); + u.add_effect( effect_shakes, rng( 4_minutes, 8_minutes ) ); + break; + case 4: + u.add_msg_if_player( m_bad, _( "You crave for ice. The dirt under your feet looks tasty too." ) ); + break; + case 5: + u.add_msg_if_player( m_bad, _( "Your whole mouth is sore, and your tongue is swollen." ) ); + break; + case 6: + u.add_msg_if_player( m_bad, _( "You feel lightheaded. A migraine follows." ) ); + u.mod_pain( intense * 9 ); + break; + case 7: // 7-9 empty for variability, as messages stack on higher intensity + break; + case 8: + break; + case 9: + break; + } + } + // level 3 anemia introduces restless legs, severe tiredness, breathlessness + if( intense > 2 ) { + switch( dice( 1, 9 ) ) { + case 1: + u.add_msg_if_player( m_bad, _( "Your legs are restless. The urge to move them is so strong." ) ); + break; + case 2: + u.add_msg_if_player( m_bad, _( "You feel like you could sleep on a rock." ) ); + u.mod_fatigue( intense * 3 ); + break; + case 3: + u.add_msg_if_player( m_bad, _( "You gasp for air!" ) ); + u.set_stamina( 0 ); + u.add_effect( effect_winded, rng( 30_seconds, 3_minutes ) ); + break; + case 4: + u.add_msg_if_player( m_bad, _( "Can't breathe. Must rest." ) ); + u.set_stamina( 0 ); + break; + case 5: + u.add_msg_if_player( m_bad, + _( "You can't take it any more. Rest first; everything else later." ) ); + u.add_effect( effect_lying_down, rng( 2_minutes, 5_minutes ) ); + break; + case 6: + u.add_msg_if_player( m_bad, _( "You must sit down for a moment. Just a moment." ) ); + u.add_effect( effect_downed, rng( 1_minutes, 2_minutes ) ); + break; + case 7: // 7-9 empty for variability, as messages stack on higher intensity + break; + case 8: + break; + case 9: + break; + } + } + } +} + +static void eff_fun_sleep( Character &u, effect &it ) +{ + int intense = it.get_intensity(); + map &here = get_map(); + + u.set_moves( 0 ); +#if defined(TILES) + if( u.is_player() ) { + SDL_PumpEvents(); + } +#endif // TILES + + if( intense < 1 ) { + it.set_intensity( 1 ); + } else if( intense < 24 ) { + it.mod_intensity( 1 ); + } + + if( u.has_effect( effect_narcosis ) && u.get_fatigue() <= 25 ) { + u.set_fatigue( 25 ); //Prevent us from waking up naturally while under anesthesia + } + + if( u.get_fatigue() < -25 && it.get_duration() > 3_minutes && !u.has_effect( effect_narcosis ) ) { + it.set_duration( 1_turns * dice( 3, 10 ) ); + } + + if( u.get_fatigue() <= 0 && u.get_fatigue() > -20 && !u.has_effect( effect_narcosis ) ) { + u.mod_fatigue( -25 ); + if( u.get_sleep_deprivation() < SLEEP_DEPRIVATION_HARMLESS ) { + u.add_msg_if_player( m_good, _( "You feel well rested." ) ); + } else { + u.add_msg_if_player( m_warning, + _( "You feel physically rested, but you haven't been able to catch up on your missed sleep yet." ) ); + } + it.set_duration( 1_turns * dice( 3, 100 ) ); + } + + // TODO: Move this to update_needs when NPCs can mutate + if( calendar::once_every( 10_minutes ) && ( u.has_trait( trait_CHLOROMORPH ) || + u.has_trait( trait_M_SKIN3 ) || u.has_trait( trait_WATERSLEEP ) ) && + here.is_outside( u.pos() ) ) { + if( u.has_trait( trait_CHLOROMORPH ) ) { + // Hunger and thirst fall before your Chloromorphic physiology! + if( g->natural_light_level( u.posz() ) >= 12 && + get_weather().weather_id->sun_intensity >= sun_intensity_type::light ) { + if( u.get_hunger() >= -30 ) { + u.mod_hunger( -5 ); + // photosynthesis warrants absorbing kcal directly + u.mod_stored_nutr( -5 ); + } + if( u.get_thirst() >= -30 ) { + u.mod_thirst( -5 ); + } + } + } + if( u.has_trait( trait_M_SKIN3 ) ) { + // Spores happen! + if( here.has_flag_ter_or_furn( "FUNGUS", u.pos() ) ) { + if( u.get_fatigue() >= 0 ) { + u.mod_fatigue( -5 ); // Local guides need less sleep on fungal soil + } + if( calendar::once_every( 1_hours ) ) { + u.spores(); // spawn some P O O F Y B O I S + } + } + } + if( u.has_trait( trait_WATERSLEEP ) ) { + u.mod_fatigue( -3 ); // Fish sleep less in water + } + } + + // Check mutation category strengths to see if we're mutated enough to get a dream + mutation_category_id highcat = u.get_highest_category(); + int highest = u.mutation_category_level[highcat]; + + // Determine the strength of effects or dreams based upon category strength + int strength = 0; // Category too weak for any effect or dream + if( u.crossed_threshold() ) { + strength = 4; // Post-human. + } else if( highest >= 20 && highest < 35 ) { + strength = 1; // Low strength + } else if( highest >= 35 && highest < 50 ) { + strength = 2; // Medium strength + } else if( highest >= 50 ) { + strength = 3; // High strength + } + + // Get a dream if category strength is high enough. + if( strength != 0 ) { + //Once every 6 / 3 / 2 hours, with a bit of randomness + if( calendar::once_every( 6_hours / strength ) && one_in( 3 ) ) { + // Select a dream + std::string dream = u.get_category_dream( highcat, strength ); + if( !dream.empty() ) { + u.add_msg_if_player( dream ); + } + // Mycus folks upgrade in their sleep. + if( u.has_trait( trait_THRESH_MYCUS ) ) { + if( one_in( 8 ) ) { + u.mutate_category( mutation_category_id( "MYCUS" ) ); + u.mod_stored_nutr( 10 ); + u.mod_thirst( 10 ); + u.mod_fatigue( 5 ); + } + } + } + } + + bool woke_up = false; + int tirednessVal = rng( 5, 200 ) + rng( 0, std::abs( u.get_fatigue() * 2 * 5 ) ); + if( !u.is_blind() && !u.has_effect( effect_narcosis ) ) { + // People who can see while sleeping are acclimated to the light. + if( !u.has_trait( trait_SEESLEEP ) ) { + if( u.has_trait( trait_HEAVYSLEEPER2 ) && !u.has_trait( trait_HIBERNATE ) ) { + // So you can too sleep through noon + if( ( tirednessVal * 1.25 ) < here.ambient_light_at( u.pos() ) && ( u.get_fatigue() < 10 || + one_in( u.get_fatigue() / 2 ) ) ) { + u.add_msg_if_player( _( "It's too bright to sleep." ) ); + // Set ourselves up for removal + it.set_duration( 0_turns ); + woke_up = true; + } + // Ursine hibernators would likely do so indoors. Plants, though, might be in the sun. + } else if( u.has_trait( trait_HIBERNATE ) ) { + if( ( tirednessVal * 5 ) < here.ambient_light_at( u.pos() ) && ( u.get_fatigue() < 10 || + one_in( u.get_fatigue() / 2 ) ) ) { + u.add_msg_if_player( _( "It's too bright to sleep." ) ); + // Set ourselves up for removal + it.set_duration( 0_turns ); + woke_up = true; + } + } else if( tirednessVal < here.ambient_light_at( u.pos() ) && ( u.get_fatigue() < 10 || + one_in( u.get_fatigue() / 2 ) ) ) { + u.add_msg_if_player( _( "It's too bright to sleep." ) ); + // Set ourselves up for removal + it.set_duration( 0_turns ); + woke_up = true; + } + } else if( u.has_active_mutation( trait_SEESLEEP ) ) { + Creature *hostile_critter = g->is_hostile_very_close(); + if( hostile_critter != nullptr ) { + u.add_msg_if_player( _( "You see %s approaching!" ), + hostile_critter->disp_name() ); + it.set_duration( 0_turns ); + woke_up = true; + } + } + } + + // Have we already woken up? + if( !woke_up && !u.has_effect( effect_narcosis ) ) { + // Cold or heat may wake you up. + // Player will sleep through cold or heat if fatigued enough + for( const bodypart_id &bp : u.get_all_body_parts() ) { + const int curr_temp = u.get_part_temp_cur( bp ); + if( curr_temp < BODYTEMP_VERY_COLD - u.get_fatigue() / 2 ) { + if( one_in( 30000 ) ) { + u.add_msg_if_player( _( "You toss and turn trying to keep warm." ) ); + } + if( curr_temp < BODYTEMP_FREEZING - u.get_fatigue() / 2 || + one_in( curr_temp * 6 + 30000 ) ) { + u.add_msg_if_player( m_bad, _( "It's too cold to sleep." ) ); + // Set ourselves up for removal + it.set_duration( 0_turns ); + woke_up = true; + break; + } + } else if( curr_temp > BODYTEMP_VERY_HOT + u.get_fatigue() / 2 ) { + if( one_in( 30000 ) ) { + u.add_msg_if_player( _( "You toss and turn in the heat." ) ); + } + if( curr_temp > BODYTEMP_SCORCHING + u.get_fatigue() / 2 || + one_in( 90000 - curr_temp ) ) { + u.add_msg_if_player( m_bad, _( "It's too hot to sleep." ) ); + // Set ourselves up for removal + it.set_duration( 0_turns ); + woke_up = true; + break; + } + } + } + if( u.has_trait( trait_SCHIZOPHRENIC ) && one_in( 43200 ) && u.is_player() ) { + if( one_in( 2 ) ) { + u.sound_hallu(); + } else { + int max_count = rng( 1, 3 ); + int count = 0; + for( const tripoint &mp : here.points_in_radius( u.pos(), 1 ) ) { + if( mp == u.pos() ) { + continue; + } + if( here.has_flag( "FLAT", mp ) && + here.pl_sees( mp, 2 ) ) { + g->spawn_hallucination( mp ); + if( ++count > max_count ) { + break; + } + } + } + } + it.set_duration( 0_turns ); + woke_up = true; + } + } + + // A bit of a hack: check if we are about to wake up for any reason, including regular + // timing out of sleep + if( it.get_duration() == 1_turns || woke_up ) { + u.wake_up(); + } +} + void Character::hardcoded_effects( effect &it ) { if( const ma_buff *buff = ma_buff::from_effect( it ) ) { @@ -513,6 +1156,11 @@ void Character::hardcoded_effects( effect &it ) { effect_cold, eff_fun_cold }, { effect_hot, eff_fun_hot }, { effect_frostbite, eff_fun_frostbite }, + { effect_teleglow, eff_fun_teleglow }, + { effect_datura, eff_fun_datura }, + { effect_hypovolemia, eff_fun_hypovolemia }, + { effect_redcells_anemia, eff_fun_redcells_anemia }, + { effect_sleep, eff_fun_sleep }, } }; const efftype_id &id = it.get_id(); @@ -651,126 +1299,6 @@ void Character::hardcoded_effects( effect &it ) remove_effect( effect_tindrift ); } } - } else if( id == effect_teleglow ) { - // Default we get around 300 duration points per teleport (possibly more - // depending on the source). - // TODO: Include a chance to teleport to the nether realm. - // TODO: This with regards to NPCS - if( !is_player() ) { - // NO, no teleporting around the player because an NPC has teleglow! - return; - } - if( dur > 10_hours ) { - // 20 teleports (no decay; in practice at least 21) - if( one_in( 6000 - ( ( dur - 600_minutes ) / 1_minutes ) ) ) { - if( !is_npc() ) { - add_msg( _( "Glowing lights surround you, and you teleport." ) ); - } - teleport::teleport( *this ); - get_event_bus().send( getID() ); - if( one_in( 10 ) ) { - // Set ourselves up for removal - it.set_duration( 0_turns ); - } - } - } - if( one_in( 7200 - ( dur - 360_minutes ) / 4_turns ) ) { - //Spawn a tindalos rift via effect_tindrift rather than it being hard-coded to teleglow - add_effect( effect_tindrift, 5_turns ); - - if( one_in( 2 ) ) { - // Set ourselves up for removal - it.set_duration( 0_turns ); - } - } - if( one_in( 7200 - ( ( dur - 600_minutes ) / 30_seconds ) ) && one_in( 20 ) ) { - add_msg_if_player( m_bad, _( "You pass out." ) ); - fall_asleep( 2_hours ); - if( one_in( 6 ) ) { - // Set ourselves up for removal - it.set_duration( 0_turns ); - } - } - if( dur > 6_hours ) { - // 12 teleports - if( one_in( 24000 - ( dur - 360_minutes ) / 4_turns ) ) { - tripoint dest( 0, 0, posz() ); - int &x = dest.x; - int &y = dest.y; - int tries = 0; - do { - x = posx() + rng( -4, 4 ); - y = posy() + rng( -4, 4 ); - tries++; - if( tries >= 10 ) { - break; - } - } while( g->critter_at( dest ) ); - if( tries < 10 ) { - if( here.impassable( dest ) ) { - here.make_rubble( dest, f_rubble_rock, true ); - } - MonsterGroupResult spawn_details = MonsterGroupManager::GetResultFromGroup( - GROUP_NETHER ); - g->place_critter_at( spawn_details.name, dest ); - if( player_character.sees( dest ) ) { - g->cancel_activity_or_ignore_query( distraction_type::hostile_spotted_far, - _( "A monster appears nearby!" ) ); - add_msg( m_warning, _( "A portal opens nearby, and a monster crawls through!" ) ); - } - if( one_in( 2 ) ) { - // Set ourselves up for removal - it.set_duration( 0_turns ); - } - } - } - if( one_in( 21000 - ( dur - 360_minutes ) / 4_turns ) ) { - add_msg_if_player( m_bad, _( "You shudder suddenly." ) ); - mutate(); - if( one_in( 4 ) ) { - // Set ourselves up for removal - it.set_duration( 0_turns ); - } - } - } - if( dur > 4_hours ) { - // 8 teleports - if( one_turn_in( 1000_minutes - dur ) && !has_effect( effect_valium ) ) { - add_effect( effect_shakes, rng( 4_minutes, 8_minutes ) ); - } - if( one_turn_in( 1200_minutes - dur ) ) { - add_msg_if_player( m_bad, _( "Your vision is filled with bright lights…" ) ); - add_effect( effect_blind, rng( 1_minutes, 2_minutes ) ); - if( one_in( 8 ) ) { - // Set ourselves up for removal - it.set_duration( 0_turns ); - } - } - if( one_in( 5000 ) && !has_effect( effect_hallu ) ) { - add_effect( effect_hallu, 6_hours ); - if( one_in( 5 ) ) { - // Set ourselves up for removal - it.set_duration( 0_turns ); - } - } - } - if( one_in( 4000 ) ) { - add_msg_if_player( m_bad, _( "You're suddenly covered in ectoplasm." ) ); - add_effect( effect_boomered, 10_minutes ); - if( one_in( 4 ) ) { - // Set ourselves up for removal - it.set_duration( 0_turns ); - } - } - if( one_in( 10000 ) ) { - if( !has_trait( trait_M_IMMUNE ) ) { - add_effect( effect_fungus, 1_turns, true ); - } else { - add_msg_if_player( m_info, _( "We have many colonists awaiting passage." ) ); - } - // Set ourselves up for removal - it.set_duration( 0_turns ); - } } else if( id == effect_asthma ) { if( has_effect( effect_adrenaline ) || has_effect( effect_datura ) ) { add_msg_if_player( m_good, _( "Your asthma attack stops." ) ); @@ -831,300 +1359,11 @@ void Character::hardcoded_effects( effect &it ) } } } - } else if( id == effect_datura ) { - if( dur > 100_minutes && get_focus() >= 1 && one_in( 24 ) ) { - mod_focus( -1 ); - } - if( dur > 200_minutes && one_in( 48 ) && get_stim() < 20 ) { - mod_stim( 1 ); - } - if( dur > 300_minutes && get_focus() >= 1 && one_in( 12 ) ) { - mod_focus( -1 ); - } - if( dur > 400_minutes && one_in( 384 ) ) { - mod_pain( rng( -1, -8 ) ); - } - if( ( !has_effect( effect_hallu ) ) && ( dur > 500_minutes && one_in( 24 ) ) ) { - add_effect( effect_hallu, 6_hours ); - } - if( dur > 600_minutes && one_in( 768 ) ) { - mod_pain( rng( -3, -24 ) ); - if( dur > 800_minutes && one_in( 16 ) ) { - add_msg_if_player( m_bad, - _( "You're experiencing loss of basic motor skills and blurred vision. Your mind recoils in horror, unable to communicate with your spinal column." ) ); - add_msg_if_player( m_bad, _( "You stagger and fall!" ) ); - add_effect( effect_downed, rng( 1_turns, 4_turns ), false, 0, true ); - if( one_in( 8 ) || x_in_y( vomit_mod(), 10 ) ) { - vomit(); - } - } - } - if( dur > 700_minutes && get_focus() >= 1 ) { - mod_focus( -1 ); - } - if( dur > 800_minutes && one_in( 1536 ) ) { - add_effect( effect_visuals, rng( 4_minutes, 20_minutes ) ); - mod_pain( rng( -8, -40 ) ); - } - if( dur > 1200_minutes && one_in( 1536 ) ) { - add_msg_if_player( m_bad, _( "There's some kind of big machine in the sky." ) ); - add_effect( effect_visuals, rng( 8_minutes, 40_minutes ) ); - if( one_in( 32 ) ) { - add_msg_if_player( m_bad, _( "It's some kind of electric snake, coming right at you!" ) ); - mod_pain( rng( 4, 40 ) ); - vomit(); - } - } - if( dur > 1400_minutes && one_in( 768 ) ) { - add_msg_if_player( m_bad, - _( "Order us some golf shoes, otherwise we'll never get out of this place alive." ) ); - add_effect( effect_visuals, rng( 40_minutes, 200_minutes ) ); - if( one_in( 8 ) ) { - add_msg_if_player( m_bad, - _( "The possibility of physical and mental collapse is now very real." ) ); - if( one_in( 2 ) || x_in_y( vomit_mod(), 10 ) ) { - add_msg_if_player( m_bad, _( "No one should be asked to handle this trip." ) ); - vomit(); - mod_pain( rng( 8, 40 ) ); - } - } - } - - if( dur > 1800_minutes && one_in( 300 * 512 ) ) { - if( !has_trait( trait_NOPAIN ) ) { - add_msg_if_player( m_bad, - _( "Your heart spasms painfully and stops, dragging you back to reality as you die." ) ); - } else { - add_msg_if_player( - _( "You dissolve into beautiful paroxysms of energy. Life fades from your nebulae and you are no more." ) ); - } - get_event_bus().send( getID(), id ); - set_part_hp_cur( bodypart_id( "torso" ), 0 ); - } - } else if( id == effect_hypovolemia ) { - // hypovolemia and dehydration are closely related so it will pull water - // from your system to replenish blood quantity - if( calendar::once_every( -vitamin_rate( vitamin_blood ) ) && one_in( 5 ) && get_thirst() <= 240 ) { - mod_thirst( rng( 0, intense ) ); - } - // bleed out lambda - auto bleed_out = [&] { - if( has_effect( effect_bleed ) ) - { - add_msg_player_or_npc( m_bad, - _( "You bleed to death!" ), - _( " bleeds to death!" ) ); - get_event_bus().send( getID() ); - } else - { - add_msg_player_or_npc( m_bad, - _( "Your heart can't keep up the pace and fails!" ), - _( " has a sudden heart attack!" ) ); - get_event_bus().send( getID() ); - } - set_part_hp_cur( bodypart_id( "torso" ), 0 ); - }; - // this goes first because beyond minimum threshold you just die without delay, - // while stage 4 is on a timer check with an rng grace period - - if( vitamin_get( vitamin_blood ) == vitamin_blood->min() ) { - bleed_out(); - } - - // Hypovolemic shock - // stage 1 - early symptoms include headache, fatigue, weakness, thirst, and dizziness. - // stage 2 - person may begin sweating and feeling more anxious and restless. - // stage 3 - heart rate will increase to over 120 bpm; rapid breathing - // mental distress, including anxiety and agitation; skin is pale and cold + cyanosis, sweating - // stage 4 is a life threatening condition; extremely rapid heart rate, breathing very fast and difficult - // drifting in and out of consciousness, sweating heavily, feeling cool to the touch, looking extremely pale - - if( one_in( 1200 / intense ) && !in_sleep_state() ) { - std::string warning; - - if( one_in( 5 ) ) { - // no-effect message block - if( intense == 1 ) { - warning = _( "Your skin looks pale and you feel anxious and thirsty. Blood loss?" ); - } else if( intense == 2 ) { - warning = _( "Your pale skin is sweating, your heart is beating fast, and you feel restless. Maybe you lost too much blood?" ); - } else if( intense == 3 ) { - warning = _( "You're unsettlingly white, but your fingertips are bluish. You are agitated and your heart is racing. Your blood loss must be serious." ); - } else { //intense == 4 - warning = _( "You are pale as a ghost, dripping wet from the sweat, and sluggish - despite your heart racing like a train. You are on the brink of collapse from the effects of blood loss." ); - } - add_msg_if_player( m_bad, warning ); - } else { - // effect dice, with progression of effects, 3 possible effects per tier - int dice_roll = rng( 0, 2 ) + intense; - switch( dice_roll ) { - case 1: - warning = _( "You feel dizzy and lightheaded." ); - add_effect( effect_stunned, rng( 5_seconds * intense, 2_minutes * intense ) ); - break; - case 2: - warning = _( "You feel tired and you breathe heavily." ); - mod_fatigue( 3 * intense ); - break; - case 3: - warning = _( "You are anxious and cannot collect your thoughts." ); - mod_focus( -rng( 1, get_focus() * intense / it.get_max_intensity() ) ); - break; - case 4: - warning = _( "You are sweating profusely, but you feel cold." ); - mod_part_temp_conv( bodypart_id( "hand_l" ), - 1000 * intense ); - mod_part_temp_conv( bodypart_id( "hand_r" ), -1000 * intense ); - mod_part_temp_conv( bodypart_id( "foot_l" ), -1000 * intense ); - mod_part_temp_conv( bodypart_id( "foot_r" ), -1000 * intense ); - break; - case 5: - warning = _( "You huff and puff. Your breath is rapid and shallow." ); - mod_stamina( -500 * intense ); - break; - case 6: - if( one_in( 2 ) ) { - warning = _( "You drop to the ground, fighting to keep yourself conscious." ); - add_effect( effect_downed, rng( 1_minutes, 2_minutes ) ); - break; - } else { - warning = _( "Your mind slips away." ); - fall_asleep( rng( 2_minutes, 5_minutes ) ); - break; - } - } - add_msg_if_player( m_bad, warning ); - } - } - // this goes last because we don't want in_sleep_state to prevent you from dying - if( intense == 4 && one_in( 900 ) && - rng( 1, -vitamin_blood->min() * 3 / 5 ) > ( -vitamin_blood->min() + vitamin_get( - vitamin_blood ) ) ) { - bleed_out(); - } } else if( id == effect_anemia ) { // effects: reduces effective redcells regen and depletes redcells at high intensity if( calendar::once_every( vitamin_rate( vitamin_redcells ) ) ) { vitamin_mod( vitamin_redcells, -rng( 0, intense ) ); } - } else if( id == effect_redcells_anemia ) { - // Lack of iron impairs production of hemoglobin and therefore ability to carry - // oxygen by red blood cells. Alternatively hemorrhage causes physical loss of red blood cells. - // This triggers variety of symptoms, focusing on weakness, - // fatigue, cold limbs, later in dizziness, soreness, breathlessness, - // and severe malaise and lethargy. - // Base anemia symptoms: fatigue, loss of stamina, loss of strength, impact on health - // are placed in effect JSON - - // you can only lose as much red blood cells before your body fails to function - if( vitamin_get( vitamin_redcells ) <= vitamin_redcells->min() + 5 ) { - add_msg_player_or_npc( m_bad, - _( "You cannot breathe and your body gives out!" ), - _( " gasps for air and dies!" ) ); - get_event_bus().send( getID() ); - set_part_hp_cur( bodypart_id( "torso" ), 0 ); - } - if( one_in( 900 / intense ) && !in_sleep_state() ) { - // level 1 symptoms are cold limbs, pale skin, and weakness - switch( dice( 1, 9 ) ) { - case 1: - add_msg_if_player( m_bad, _( "Your hands feel unusually cold." ) ); - mod_part_temp_conv( bodypart_id( "hand_l" ), -2000 ); - mod_part_temp_conv( bodypart_id( "hand_r" ), -2000 ); - break; - case 2: - add_msg_if_player( m_bad, _( "Your feet feel unusually cold." ) ); - mod_part_temp_conv( bodypart_id( "foot_l" ), -2000 ); - mod_part_temp_conv( bodypart_id( "foot_r" ), -2000 ); - break; - case 3: - add_msg_if_player( m_bad, _( "Your skin looks very pale." ) ); - break; - case 4: - add_msg_if_player( m_bad, _( "You feel weak. Where has your strength gone?" ) ); - break; - case 5: - add_msg_if_player( m_bad, _( "You feel feeble. A gust of wind could make you stumble." ) ); - break; - case 6: - add_msg_if_player( m_bad, _( "There is an overwhelming aura of tiredness inside of you." ) ); - mod_fatigue( intense * 3 ); - break; - case 7: // 7-9 empty for variability, as messages stack on higher intensity - break; - case 8: - break; - case 9: - break; - } - // level 2 anemia introduces dizziness, shakes, headaches, cravings for non-comestibles, - // mouth and tongue soreness - if( intense > 1 ) { - switch( dice( 1, 9 ) ) { - case 1: - add_msg_if_player( m_bad, _( "Rest is what you want. Rest is what you need." ) ); - break; - case 2: - add_msg_if_player( m_bad, _( "You feel dizzy and can't coordinate the movement of your feet." ) ); - add_effect( effect_stunned, rng( 1_minutes, 2_minutes ) ); - break; - case 3: - add_msg_if_player( m_bad, _( "Your muscles are quivering." ) ); - add_effect( effect_shakes, rng( 4_minutes, 8_minutes ) ); - break; - case 4: - add_msg_if_player( m_bad, _( "You crave for ice. The dirt under your feet looks tasty too." ) ); - break; - case 5: - add_msg_if_player( m_bad, _( "Your whole mouth is sore, and your tongue is swollen." ) ); - break; - case 6: - add_msg_if_player( m_bad, _( "You feel lightheaded. A migraine follows." ) ); - mod_pain( intense * 9 ); - break; - case 7: // 7-9 empty for variability, as messages stack on higher intensity - break; - case 8: - break; - case 9: - break; - } - } - // level 3 anemia introduces restless legs, severe tiredness, breathlessness - if( intense > 2 ) { - switch( dice( 1, 9 ) ) { - case 1: - add_msg_if_player( m_bad, _( "Your legs are restless. The urge to move them is so strong." ) ); - break; - case 2: - add_msg_if_player( m_bad, _( "You feel like you could sleep on a rock." ) ); - mod_fatigue( intense * 3 ); - break; - case 3: - add_msg_if_player( m_bad, _( "You gasp for air!" ) ); - set_stamina( 0 ); - add_effect( effect_winded, rng( 30_seconds, 3_minutes ) ); - break; - case 4: - add_msg_if_player( m_bad, _( "Can't breathe. Must rest." ) ); - set_stamina( 0 ); - break; - case 5: - add_msg_if_player( m_bad, _( "You can't take it any more. Rest first; everything else later." ) ); - add_effect( effect_lying_down, rng( 2_minutes, 5_minutes ) ); - break; - case 6: - add_msg_if_player( m_bad, _( "You must sit down for a moment. Just a moment." ) ); - add_effect( effect_downed, rng( 1_minutes, 2_minutes ) ); - break; - case 7: // 7-9 empty for variability, as messages stack on higher intensity - break; - case 8: - break; - case 9: - break; - } - } - } } else if( id == effect_grabbed ) { set_num_blocks_bonus( get_num_blocks_bonus() - 1 ); int zed_number = 0; @@ -1274,212 +1513,6 @@ void Character::hardcoded_effects( effect &it ) if( dur == 1_turns && !sleeping ) { add_msg_if_player( _( "You try to sleep, but can't…" ) ); } - } else if( id == effect_sleep ) { - set_moves( 0 ); -#if defined(TILES) - if( is_player() ) { - SDL_PumpEvents(); - } -#endif // TILES - - if( intense < 1 ) { - it.set_intensity( 1 ); - } else if( intense < 24 ) { - it.mod_intensity( 1 ); - } - - if( has_effect( effect_narcosis ) && get_fatigue() <= 25 ) { - set_fatigue( 25 ); //Prevent us from waking up naturally while under anesthesia - } - - if( get_fatigue() < -25 && it.get_duration() > 3_minutes && !has_effect( effect_narcosis ) ) { - it.set_duration( 1_turns * dice( 3, 10 ) ); - } - - if( get_fatigue() <= 0 && get_fatigue() > -20 && !has_effect( effect_narcosis ) ) { - mod_fatigue( -25 ); - if( get_sleep_deprivation() < SLEEP_DEPRIVATION_HARMLESS ) { - add_msg_if_player( m_good, _( "You feel well rested." ) ); - } else { - add_msg_if_player( m_warning, - _( "You feel physically rested, but you haven't been able to catch up on your missed sleep yet." ) ); - } - it.set_duration( 1_turns * dice( 3, 100 ) ); - } - - // TODO: Move this to update_needs when NPCs can mutate - if( calendar::once_every( 10_minutes ) && ( has_trait( trait_CHLOROMORPH ) || - has_trait( trait_M_SKIN3 ) || has_trait( trait_WATERSLEEP ) ) && - here.is_outside( pos() ) ) { - if( has_trait( trait_CHLOROMORPH ) ) { - // Hunger and thirst fall before your Chloromorphic physiology! - if( g->natural_light_level( posz() ) >= 12 && - get_weather().weather_id->sun_intensity >= sun_intensity_type::light ) { - if( get_hunger() >= -30 ) { - mod_hunger( -5 ); - // photosynthesis warrants absorbing kcal directly - mod_stored_nutr( -5 ); - } - if( get_thirst() >= -30 ) { - mod_thirst( -5 ); - } - } - } - if( has_trait( trait_M_SKIN3 ) ) { - // Spores happen! - if( here.has_flag_ter_or_furn( "FUNGUS", pos() ) ) { - if( get_fatigue() >= 0 ) { - mod_fatigue( -5 ); // Local guides need less sleep on fungal soil - } - if( calendar::once_every( 1_hours ) ) { - spores(); // spawn some P O O F Y B O I S - } - } - } - if( has_trait( trait_WATERSLEEP ) ) { - mod_fatigue( -3 ); // Fish sleep less in water - } - } - - // Check mutation category strengths to see if we're mutated enough to get a dream - mutation_category_id highcat = get_highest_category(); - int highest = mutation_category_level[highcat]; - - // Determine the strength of effects or dreams based upon category strength - int strength = 0; // Category too weak for any effect or dream - if( crossed_threshold() ) { - strength = 4; // Post-human. - } else if( highest >= 20 && highest < 35 ) { - strength = 1; // Low strength - } else if( highest >= 35 && highest < 50 ) { - strength = 2; // Medium strength - } else if( highest >= 50 ) { - strength = 3; // High strength - } - - // Get a dream if category strength is high enough. - if( strength != 0 ) { - //Once every 6 / 3 / 2 hours, with a bit of randomness - if( calendar::once_every( 6_hours / strength ) && one_in( 3 ) ) { - // Select a dream - std::string dream = get_category_dream( highcat, strength ); - if( !dream.empty() ) { - add_msg_if_player( dream ); - } - // Mycus folks upgrade in their sleep. - if( has_trait( trait_THRESH_MYCUS ) ) { - if( one_in( 8 ) ) { - mutate_category( mutation_category_id( "MYCUS" ) ); - mod_stored_nutr( 10 ); - mod_thirst( 10 ); - mod_fatigue( 5 ); - } - } - } - } - - bool woke_up = false; - int tirednessVal = rng( 5, 200 ) + rng( 0, std::abs( get_fatigue() * 2 * 5 ) ); - if( !is_blind() && !has_effect( effect_narcosis ) ) { - if( !has_trait( - trait_SEESLEEP ) ) { // People who can see while sleeping are acclimated to the light. - if( has_trait( trait_HEAVYSLEEPER2 ) && !has_trait( trait_HIBERNATE ) ) { - // So you can too sleep through noon - if( ( tirednessVal * 1.25 ) < here.ambient_light_at( pos() ) && ( get_fatigue() < 10 || - one_in( get_fatigue() / 2 ) ) ) { - add_msg_if_player( _( "It's too bright to sleep." ) ); - // Set ourselves up for removal - it.set_duration( 0_turns ); - woke_up = true; - } - // Ursine hibernators would likely do so indoors. Plants, though, might be in the sun. - } else if( has_trait( trait_HIBERNATE ) ) { - if( ( tirednessVal * 5 ) < here.ambient_light_at( pos() ) && ( get_fatigue() < 10 || - one_in( get_fatigue() / 2 ) ) ) { - add_msg_if_player( _( "It's too bright to sleep." ) ); - // Set ourselves up for removal - it.set_duration( 0_turns ); - woke_up = true; - } - } else if( tirednessVal < here.ambient_light_at( pos() ) && ( get_fatigue() < 10 || - one_in( get_fatigue() / 2 ) ) ) { - add_msg_if_player( _( "It's too bright to sleep." ) ); - // Set ourselves up for removal - it.set_duration( 0_turns ); - woke_up = true; - } - } else if( has_active_mutation( trait_SEESLEEP ) ) { - Creature *hostile_critter = g->is_hostile_very_close(); - if( hostile_critter != nullptr ) { - add_msg_if_player( _( "You see %s approaching!" ), - hostile_critter->disp_name() ); - it.set_duration( 0_turns ); - woke_up = true; - } - } - } - - // Have we already woken up? - if( !woke_up && !has_effect( effect_narcosis ) ) { - // Cold or heat may wake you up. - // Player will sleep through cold or heat if fatigued enough - for( const bodypart_id &bp : get_all_body_parts() ) { - const int curr_temp = get_part_temp_cur( bp ); - if( curr_temp < BODYTEMP_VERY_COLD - get_fatigue() / 2 ) { - if( one_in( 30000 ) ) { - add_msg_if_player( _( "You toss and turn trying to keep warm." ) ); - } - if( curr_temp < BODYTEMP_FREEZING - get_fatigue() / 2 || - one_in( curr_temp * 6 + 30000 ) ) { - add_msg_if_player( m_bad, _( "It's too cold to sleep." ) ); - // Set ourselves up for removal - it.set_duration( 0_turns ); - woke_up = true; - break; - } - } else if( curr_temp > BODYTEMP_VERY_HOT + get_fatigue() / 2 ) { - if( one_in( 30000 ) ) { - add_msg_if_player( _( "You toss and turn in the heat." ) ); - } - if( curr_temp > BODYTEMP_SCORCHING + get_fatigue() / 2 || - one_in( 90000 - curr_temp ) ) { - add_msg_if_player( m_bad, _( "It's too hot to sleep." ) ); - // Set ourselves up for removal - it.set_duration( 0_turns ); - woke_up = true; - break; - } - } - } - if( has_trait( trait_SCHIZOPHRENIC ) && one_in( 43200 ) && is_player() ) { - if( one_in( 2 ) ) { - sound_hallu(); - } else { - int max_count = rng( 1, 3 ); - int count = 0; - for( const tripoint &mp : here.points_in_radius( pos(), 1 ) ) { - if( mp == pos() ) { - continue; - } - if( here.has_flag( "FLAT", mp ) && - here.pl_sees( mp, 2 ) ) { - g->spawn_hallucination( mp ); - if( ++count > max_count ) { - break; - } - } - } - } - it.set_duration( 0_turns ); - woke_up = true; - } - } - - // A bit of a hack: check if we are about to wake up for any reason, including regular - // timing out of sleep - if( dur == 1_turns || woke_up ) { - wake_up(); - } } else if( id == effect_alarm_clock ) { if( in_sleep_state() ) { const bool asleep = has_effect( effect_sleep ); From 11c55d66314855594435dcd1c77b9c2a009b45b2 Mon Sep 17 00:00:00 2001 From: John Bytheway Date: Sat, 3 Apr 2021 07:27:33 -0400 Subject: [PATCH 353/453] Split ammo_set_test function Split this large function to reduce its size. --- tests/ammo_set_test.cpp | 660 ++++++++++++++++++++-------------------- 1 file changed, 334 insertions(+), 326 deletions(-) diff --git a/tests/ammo_set_test.cpp b/tests/ammo_set_test.cpp index e258ade67054c..b7958c2712706 100644 --- a/tests/ammo_set_test.cpp +++ b/tests/ammo_set_test.cpp @@ -13,378 +13,386 @@ #include "type_id.h" #include "value_ptr.h" -TEST_CASE( "ammo_set", "[ammo_set][magazine][ammo]" ) +TEST_CASE( "ammo_set items with MAGAZINE pockets", "[ammo_set][magazine][ammo]" ) { - SECTION( "ammo_set items with MAGAZINE pockets" ) { - GIVEN( "empty 9mm CZ 75 20-round magazine" ) { - item cz75mag_20rd( "cz75mag_20rd" ); - REQUIRE( cz75mag_20rd.is_magazine() ); - REQUIRE( cz75mag_20rd.ammo_remaining() == 0 ); - REQUIRE( cz75mag_20rd.ammo_default() ); - itype_id ammo_default_id = cz75mag_20rd.ammo_default(); - itype_id ammo9mm_id( "9mm" ); - REQUIRE( ammo_default_id.str() == ammo9mm_id.str() ); - const ammotype &amtype = ammo9mm_id->ammo->type; - REQUIRE( cz75mag_20rd.ammo_capacity( amtype ) == 20 ); - WHEN( "set 9mm ammo in the magazine w/o quantity" ) { - cz75mag_20rd.ammo_set( ammo9mm_id ); - THEN( "magazine has 20 rounds of 9mm" ) { - CHECK( cz75mag_20rd.ammo_remaining() == 20 ); - CHECK( cz75mag_20rd.ammo_current().str() == ammo9mm_id.str() ); - } + GIVEN( "empty 9mm CZ 75 20-round magazine" ) { + item cz75mag_20rd( "cz75mag_20rd" ); + REQUIRE( cz75mag_20rd.is_magazine() ); + REQUIRE( cz75mag_20rd.ammo_remaining() == 0 ); + REQUIRE( cz75mag_20rd.ammo_default() ); + itype_id ammo_default_id = cz75mag_20rd.ammo_default(); + itype_id ammo9mm_id( "9mm" ); + REQUIRE( ammo_default_id.str() == ammo9mm_id.str() ); + const ammotype &amtype = ammo9mm_id->ammo->type; + REQUIRE( cz75mag_20rd.ammo_capacity( amtype ) == 20 ); + WHEN( "set 9mm ammo in the magazine w/o quantity" ) { + cz75mag_20rd.ammo_set( ammo9mm_id ); + THEN( "magazine has 20 rounds of 9mm" ) { + CHECK( cz75mag_20rd.ammo_remaining() == 20 ); + CHECK( cz75mag_20rd.ammo_current().str() == ammo9mm_id.str() ); } - WHEN( "set 9mm ammo in the magazine -1 quantity" ) { - cz75mag_20rd.ammo_set( ammo9mm_id, -1 ); - THEN( "magazine has 20 rounds of 9mm" ) { - CHECK( cz75mag_20rd.ammo_remaining() == 20 ); - CHECK( cz75mag_20rd.ammo_current().str() == ammo9mm_id.str() ); - } + } + WHEN( "set 9mm ammo in the magazine -1 quantity" ) { + cz75mag_20rd.ammo_set( ammo9mm_id, -1 ); + THEN( "magazine has 20 rounds of 9mm" ) { + CHECK( cz75mag_20rd.ammo_remaining() == 20 ); + CHECK( cz75mag_20rd.ammo_current().str() == ammo9mm_id.str() ); } - WHEN( "set 9mm ammo in the magazine 21 quantity" ) { - cz75mag_20rd.ammo_set( ammo9mm_id, 21 ); - THEN( "magazine has 20 rounds of 9mm" ) { - CHECK( cz75mag_20rd.ammo_remaining() == 20 ); - CHECK( cz75mag_20rd.ammo_current().str() == ammo9mm_id.str() ); - } + } + WHEN( "set 9mm ammo in the magazine 21 quantity" ) { + cz75mag_20rd.ammo_set( ammo9mm_id, 21 ); + THEN( "magazine has 20 rounds of 9mm" ) { + CHECK( cz75mag_20rd.ammo_remaining() == 20 ); + CHECK( cz75mag_20rd.ammo_current().str() == ammo9mm_id.str() ); } - WHEN( "set 9mm ammo in the magazine 20 quantity" ) { - cz75mag_20rd.ammo_set( ammo9mm_id, 20 ); - THEN( "magazine has 20 rounds of 9mm" ) { - CHECK( cz75mag_20rd.ammo_remaining() == 20 ); - CHECK( cz75mag_20rd.ammo_current().str() == ammo9mm_id.str() ); - } + } + WHEN( "set 9mm ammo in the magazine 20 quantity" ) { + cz75mag_20rd.ammo_set( ammo9mm_id, 20 ); + THEN( "magazine has 20 rounds of 9mm" ) { + CHECK( cz75mag_20rd.ammo_remaining() == 20 ); + CHECK( cz75mag_20rd.ammo_current().str() == ammo9mm_id.str() ); } - WHEN( "set 9mm ammo in the magazine 12 quantity" ) { - cz75mag_20rd.ammo_set( ammo9mm_id, 12 ); - THEN( "magazine has 12 rounds of 9mm" ) { - CHECK( cz75mag_20rd.ammo_remaining() == 12 ); - CHECK( cz75mag_20rd.ammo_current().str() == ammo9mm_id.str() ); - } + } + WHEN( "set 9mm ammo in the magazine 12 quantity" ) { + cz75mag_20rd.ammo_set( ammo9mm_id, 12 ); + THEN( "magazine has 12 rounds of 9mm" ) { + CHECK( cz75mag_20rd.ammo_remaining() == 12 ); + CHECK( cz75mag_20rd.ammo_current().str() == ammo9mm_id.str() ); } - WHEN( "set 9mm ammo in the magazine 1 quantity" ) { - cz75mag_20rd.ammo_set( ammo9mm_id, 1 ); - THEN( "magazine has 1 round of 9mm" ) { - CHECK( cz75mag_20rd.ammo_remaining() == 1 ); - CHECK( cz75mag_20rd.ammo_current().str() == ammo9mm_id.str() ); - } + } + WHEN( "set 9mm ammo in the magazine 1 quantity" ) { + cz75mag_20rd.ammo_set( ammo9mm_id, 1 ); + THEN( "magazine has 1 round of 9mm" ) { + CHECK( cz75mag_20rd.ammo_remaining() == 1 ); + CHECK( cz75mag_20rd.ammo_current().str() == ammo9mm_id.str() ); + } + } + WHEN( "set 9mm ammo in the magazine 0 quantity" ) { + cz75mag_20rd.ammo_set( ammo9mm_id, 0 ); + THEN( "magazine has 0 round of null" ) { + CHECK( cz75mag_20rd.ammo_remaining() == 0 ); + CHECK( cz75mag_20rd.ammo_current().is_null() ); + } + } + WHEN( "set 9mm FMJ ammo in the magazine 15 quantity" ) { + itype_id ammo9mmfmj_id( "9mmfmj" ); + cz75mag_20rd.ammo_set( ammo9mmfmj_id, 15 ); + THEN( "magazine has 15 round of 9mm FMJ" ) { + CHECK( cz75mag_20rd.ammo_remaining() == 15 ); + CHECK( cz75mag_20rd.ammo_current().str() == ammo9mmfmj_id.str() ); } - WHEN( "set 9mm ammo in the magazine 0 quantity" ) { - cz75mag_20rd.ammo_set( ammo9mm_id, 0 ); - THEN( "magazine has 0 round of null" ) { + } + WHEN( "set 308 ammo in the 9mm magazine" ) { + itype_id ammo308_id( "308" ); + std::string dmsg = capture_debugmsg_during( [&cz75mag_20rd, &ammo308_id]() { + cz75mag_20rd.ammo_set( ammo308_id, 15 ); + } ); + THEN( "get debugmsg with \"Tried to set invalid ammo of 308 for cz75mag_20rd\"" ) { + CHECK_THAT( dmsg, Catch::EndsWith( "Tried to set invalid ammo of 308 for cz75mag_20rd" ) ); + AND_THEN( "magazine has 0 round of null" ) { CHECK( cz75mag_20rd.ammo_remaining() == 0 ); CHECK( cz75mag_20rd.ammo_current().is_null() ); } } - WHEN( "set 9mm FMJ ammo in the magazine 15 quantity" ) { - itype_id ammo9mmfmj_id( "9mmfmj" ); - cz75mag_20rd.ammo_set( ammo9mmfmj_id, 15 ); - THEN( "magazine has 15 round of 9mm FMJ" ) { - CHECK( cz75mag_20rd.ammo_remaining() == 15 ); - CHECK( cz75mag_20rd.ammo_current().str() == ammo9mmfmj_id.str() ); - } + } + } + GIVEN( "empty M24 gun with capacity of 5 .308 rounds" ) { + item m24( "M24" ); + REQUIRE( m24.is_gun() ); + REQUIRE( m24.is_magazine() ); + REQUIRE( m24.ammo_remaining() == 0 ); + REQUIRE( m24.ammo_default() ); + itype_id ammo_default_id = m24.ammo_default(); + itype_id ammo308_id( "308" ); + itype_id ammo762_51_id( "762_51" ); + REQUIRE( ammo_default_id.str() == ammo762_51_id.str() ); + const ammotype &amtype = ammo308_id->ammo->type; + REQUIRE( m24.ammo_capacity( amtype ) == 5 ); + WHEN( "set 308 ammo in the gun with internal magazine w/o quantity" ) { + m24.ammo_set( ammo308_id ); + THEN( "gun has 5 rounds of 308" ) { + CHECK( m24.ammo_remaining() == 5 ); + CHECK( m24.ammo_current().str() == ammo308_id.str() ); } - WHEN( "set 308 ammo in the 9mm magazine" ) { - itype_id ammo308_id( "308" ); - std::string dmsg = capture_debugmsg_during( [&cz75mag_20rd, &ammo308_id]() { - cz75mag_20rd.ammo_set( ammo308_id, 15 ); - } ); - THEN( "get debugmsg with \"Tried to set invalid ammo of 308 for cz75mag_20rd\"" ) { - CHECK_THAT( dmsg, Catch::EndsWith( "Tried to set invalid ammo of 308 for cz75mag_20rd" ) ); - AND_THEN( "magazine has 0 round of null" ) { - CHECK( cz75mag_20rd.ammo_remaining() == 0 ); - CHECK( cz75mag_20rd.ammo_current().is_null() ); - } - } + } + WHEN( "set 308 ammo in the gun with internal magazine -1 quantity" ) { + m24.ammo_set( ammo308_id, -1 ); + THEN( "gun has 5 rounds of 308" ) { + CHECK( m24.ammo_remaining() == 5 ); + CHECK( m24.ammo_current().str() == ammo308_id.str() ); } } - GIVEN( "empty M24 gun with capacity of 5 .308 rounds" ) { - item m24( "M24" ); - REQUIRE( m24.is_gun() ); - REQUIRE( m24.is_magazine() ); - REQUIRE( m24.ammo_remaining() == 0 ); - REQUIRE( m24.ammo_default() ); - itype_id ammo_default_id = m24.ammo_default(); - itype_id ammo308_id( "308" ); - itype_id ammo762_51_id( "762_51" ); - REQUIRE( ammo_default_id.str() == ammo762_51_id.str() ); - const ammotype &amtype = ammo308_id->ammo->type; - REQUIRE( m24.ammo_capacity( amtype ) == 5 ); - WHEN( "set 308 ammo in the gun with internal magazine w/o quantity" ) { - m24.ammo_set( ammo308_id ); - THEN( "gun has 5 rounds of 308" ) { - CHECK( m24.ammo_remaining() == 5 ); - CHECK( m24.ammo_current().str() == ammo308_id.str() ); - } + WHEN( "set 308 ammo in the gun with internal magazine 500 quantity" ) { + m24.ammo_set( ammo308_id, 500 ); + THEN( "gun has 5 rounds of 308" ) { + CHECK( m24.ammo_remaining() == 5 ); + CHECK( m24.ammo_current().str() == ammo308_id.str() ); } - WHEN( "set 308 ammo in the gun with internal magazine -1 quantity" ) { - m24.ammo_set( ammo308_id, -1 ); - THEN( "gun has 5 rounds of 308" ) { - CHECK( m24.ammo_remaining() == 5 ); - CHECK( m24.ammo_current().str() == ammo308_id.str() ); - } + } + WHEN( "set 308 ammo in the gun with internal magazine 5 quantity" ) { + m24.ammo_set( ammo308_id, 5 ); + THEN( "gun has 5 rounds of 308" ) { + CHECK( m24.ammo_remaining() == 5 ); + CHECK( m24.ammo_current().str() == ammo308_id.str() ); } - WHEN( "set 308 ammo in the gun with internal magazine 500 quantity" ) { - m24.ammo_set( ammo308_id, 500 ); - THEN( "gun has 5 rounds of 308" ) { - CHECK( m24.ammo_remaining() == 5 ); - CHECK( m24.ammo_current().str() == ammo308_id.str() ); - } + } + WHEN( "set 308 ammo in the gun with internal magazine 4 quantity" ) { + m24.ammo_set( ammo308_id, 4 ); + THEN( "gun has 4 rounds of 308" ) { + CHECK( m24.ammo_remaining() == 4 ); + CHECK( m24.ammo_current().str() == ammo308_id.str() ); } - WHEN( "set 308 ammo in the gun with internal magazine 5 quantity" ) { - m24.ammo_set( ammo308_id, 5 ); - THEN( "gun has 5 rounds of 308" ) { - CHECK( m24.ammo_remaining() == 5 ); - CHECK( m24.ammo_current().str() == ammo308_id.str() ); - } + } + WHEN( "set 308 ammo in the gun with internal magazine 1 quantity" ) { + m24.ammo_set( ammo308_id, 1 ); + THEN( "gun has 41rounds of 308" ) { + CHECK( m24.ammo_remaining() == 1 ); + CHECK( m24.ammo_current().str() == ammo308_id.str() ); } - WHEN( "set 308 ammo in the gun with internal magazine 4 quantity" ) { - m24.ammo_set( ammo308_id, 4 ); - THEN( "gun has 4 rounds of 308" ) { - CHECK( m24.ammo_remaining() == 4 ); - CHECK( m24.ammo_current().str() == ammo308_id.str() ); - } + } + WHEN( "set 308 ammo in the gun with internal magazine 0 quantity" ) { + m24.ammo_set( ammo308_id, 0 ); + THEN( "gun has 0 rounds of null" ) { + CHECK( m24.ammo_remaining() == 0 ); + CHECK( m24.ammo_current().is_null() ); } - WHEN( "set 308 ammo in the gun with internal magazine 1 quantity" ) { - m24.ammo_set( ammo308_id, 1 ); - THEN( "gun has 41rounds of 308" ) { - CHECK( m24.ammo_remaining() == 1 ); - CHECK( m24.ammo_current().str() == ammo308_id.str() ); - } + } + WHEN( "set 762_51 ammo in the gun with internal magazine 2 quantity" ) { + m24.ammo_set( ammo762_51_id, 2 ); + THEN( "gun has 2 rounds of 762_51" ) { + CHECK( m24.ammo_remaining() == 2 ); + CHECK( m24.ammo_current().str() == ammo762_51_id.str() ); } - WHEN( "set 308 ammo in the gun with internal magazine 0 quantity" ) { - m24.ammo_set( ammo308_id, 0 ); - THEN( "gun has 0 rounds of null" ) { + } + WHEN( "set 9mm ammo in ammo in the .308 gun" ) { + itype_id ammo9mm_id( "9mm" ); + std::string dmsg = capture_debugmsg_during( [&m24, &ammo9mm_id]() { + m24.ammo_set( ammo9mm_id, 2 ); + } ); + THEN( "get debugmsg with \"Tried to set invalid ammo of 9mm for M24\"" ) { + CHECK_THAT( dmsg, Catch::EndsWith( "Tried to set invalid ammo of 9mm for M24" ) ); + AND_THEN( "gun has 0 round of null" ) { CHECK( m24.ammo_remaining() == 0 ); CHECK( m24.ammo_current().is_null() ); } } - WHEN( "set 762_51 ammo in the gun with internal magazine 2 quantity" ) { - m24.ammo_set( ammo762_51_id, 2 ); - THEN( "gun has 2 rounds of 762_51" ) { - CHECK( m24.ammo_remaining() == 2 ); - CHECK( m24.ammo_current().str() == ammo762_51_id.str() ); - } + } + } +} + +TEST_CASE( "ammo_set items with MAGAZINE_WELL pockets with magazine", + "[ammo_set][magazine][ammo]" ) +{ + GIVEN( "CZ 75 B 9mm gun with empty 9mm CZ 75 20-round magazine" ) { + item cz75( "cz75" ); + item cz75mag_20rd( "cz75mag_20rd" ); + REQUIRE( cz75.is_gun() ); + REQUIRE_FALSE( cz75.is_magazine() ); + REQUIRE( cz75.magazine_current() == nullptr ); + REQUIRE( cz75.magazine_compatible().count( cz75mag_20rd.typeId() ) == 1 ); + REQUIRE( cz75mag_20rd.is_magazine() ); + REQUIRE( cz75mag_20rd.ammo_remaining() == 0 ); + REQUIRE( cz75mag_20rd.ammo_default() ); + itype_id ammo_default_id = cz75mag_20rd.ammo_default(); + itype_id ammo9mm_id( "9mm" ); + REQUIRE( ammo_default_id.str() == ammo9mm_id.str() ); + const ammotype &amtype = ammo9mm_id->ammo->type; + REQUIRE( cz75mag_20rd.ammo_capacity( amtype ) == 20 ); + cz75.put_in( cz75mag_20rd, item_pocket::pocket_type::MAGAZINE_WELL ); + REQUIRE( cz75.magazine_current()->typeId().str() == cz75mag_20rd.typeId().str() ); + REQUIRE( cz75.ammo_capacity( amtype ) == 20 ); + WHEN( "set 9mm ammo in the gun with magazine w/o quantity" ) { + cz75.ammo_set( ammo9mm_id ); + THEN( "gun and current magazine has 20 rounds of 9mm" ) { + CHECK( cz75.ammo_remaining() == 20 ); + CHECK( cz75.ammo_current().str() == ammo9mm_id.str() ); + CHECK( cz75.magazine_current()->ammo_remaining() == 20 ); + CHECK( cz75.magazine_current()->ammo_current().str() == ammo9mm_id.str() ); } - WHEN( "set 9mm ammo in ammo in the .308 gun" ) { - itype_id ammo9mm_id( "9mm" ); - std::string dmsg = capture_debugmsg_during( [&m24, &ammo9mm_id]() { - m24.ammo_set( ammo9mm_id, 2 ); - } ); - THEN( "get debugmsg with \"Tried to set invalid ammo of 9mm for M24\"" ) { - CHECK_THAT( dmsg, Catch::EndsWith( "Tried to set invalid ammo of 9mm for M24" ) ); - AND_THEN( "gun has 0 round of null" ) { - CHECK( m24.ammo_remaining() == 0 ); - CHECK( m24.ammo_current().is_null() ); - } - } + } + WHEN( "set 9mm ammo in the gun with magazine -1 quantity" ) { + cz75.ammo_set( ammo9mm_id, -1 ); + THEN( "gun and current magazine has 20 rounds of 9mm" ) { + CHECK( cz75.ammo_remaining() == 20 ); + CHECK( cz75.ammo_current().str() == ammo9mm_id.str() ); + CHECK( cz75.magazine_current()->ammo_remaining() == 20 ); + CHECK( cz75.magazine_current()->ammo_current().str() == ammo9mm_id.str() ); } } - } - SECTION( "ammo_set items with MAGAZINE_WELL pockets" ) { - GIVEN( "CZ 75 B 9mm gun with empty 9mm CZ 75 20-round magazine" ) { - item cz75( "cz75" ); - item cz75mag_20rd( "cz75mag_20rd" ); - REQUIRE( cz75.is_gun() ); - REQUIRE_FALSE( cz75.is_magazine() ); - REQUIRE( cz75.magazine_current() == nullptr ); - REQUIRE( cz75.magazine_compatible().count( cz75mag_20rd.typeId() ) == 1 ); - REQUIRE( cz75mag_20rd.is_magazine() ); - REQUIRE( cz75mag_20rd.ammo_remaining() == 0 ); - REQUIRE( cz75mag_20rd.ammo_default() ); - itype_id ammo_default_id = cz75mag_20rd.ammo_default(); - itype_id ammo9mm_id( "9mm" ); - REQUIRE( ammo_default_id.str() == ammo9mm_id.str() ); - const ammotype &amtype = ammo9mm_id->ammo->type; - REQUIRE( cz75mag_20rd.ammo_capacity( amtype ) == 20 ); - cz75.put_in( cz75mag_20rd, item_pocket::pocket_type::MAGAZINE_WELL ); - REQUIRE( cz75.magazine_current()->typeId().str() == cz75mag_20rd.typeId().str() ); - REQUIRE( cz75.ammo_capacity( amtype ) == 20 ); - WHEN( "set 9mm ammo in the gun with magazine w/o quantity" ) { - cz75.ammo_set( ammo9mm_id ); - THEN( "gun and current magazine has 20 rounds of 9mm" ) { - CHECK( cz75.ammo_remaining() == 20 ); - CHECK( cz75.ammo_current().str() == ammo9mm_id.str() ); - CHECK( cz75.magazine_current()->ammo_remaining() == 20 ); - CHECK( cz75.magazine_current()->ammo_current().str() == ammo9mm_id.str() ); - } + WHEN( "set 9mm ammo in the gun with magazine 21 quantity" ) { + cz75.ammo_set( ammo9mm_id, 21 ); + THEN( "gun and current magazine has 20 rounds of 9mm" ) { + CHECK( cz75.ammo_remaining() == 20 ); + CHECK( cz75.ammo_current().str() == ammo9mm_id.str() ); + CHECK( cz75.magazine_current()->ammo_remaining() == 20 ); + CHECK( cz75.magazine_current()->ammo_current().str() == ammo9mm_id.str() ); } - WHEN( "set 9mm ammo in the gun with magazine -1 quantity" ) { - cz75.ammo_set( ammo9mm_id, -1 ); - THEN( "gun and current magazine has 20 rounds of 9mm" ) { - CHECK( cz75.ammo_remaining() == 20 ); - CHECK( cz75.ammo_current().str() == ammo9mm_id.str() ); - CHECK( cz75.magazine_current()->ammo_remaining() == 20 ); - CHECK( cz75.magazine_current()->ammo_current().str() == ammo9mm_id.str() ); - } + } + WHEN( "set 9mm ammo in the gun with magazine 20 quantity" ) { + cz75.ammo_set( ammo9mm_id, 20 ); + THEN( "gun and current magazine has 20 rounds of 9mm" ) { + CHECK( cz75.ammo_remaining() == 20 ); + CHECK( cz75.ammo_current().str() == ammo9mm_id.str() ); + CHECK( cz75.magazine_current()->ammo_remaining() == 20 ); + CHECK( cz75.magazine_current()->ammo_current().str() == ammo9mm_id.str() ); } - WHEN( "set 9mm ammo in the gun with magazine 21 quantity" ) { - cz75.ammo_set( ammo9mm_id, 21 ); - THEN( "gun and current magazine has 20 rounds of 9mm" ) { - CHECK( cz75.ammo_remaining() == 20 ); - CHECK( cz75.ammo_current().str() == ammo9mm_id.str() ); - CHECK( cz75.magazine_current()->ammo_remaining() == 20 ); - CHECK( cz75.magazine_current()->ammo_current().str() == ammo9mm_id.str() ); - } + } + WHEN( "set 9mm ammo in the gun with magazine 12 quantity" ) { + cz75.ammo_set( ammo9mm_id, 12 ); + THEN( "gun and current magazine has 12 rounds of 9mm" ) { + CHECK( cz75.ammo_remaining() == 12 ); + CHECK( cz75.ammo_current().str() == ammo9mm_id.str() ); + CHECK( cz75.magazine_current()->ammo_remaining() == 12 ); + CHECK( cz75.magazine_current()->ammo_current().str() == ammo9mm_id.str() ); } - WHEN( "set 9mm ammo in the gun with magazine 20 quantity" ) { - cz75.ammo_set( ammo9mm_id, 20 ); - THEN( "gun and current magazine has 20 rounds of 9mm" ) { - CHECK( cz75.ammo_remaining() == 20 ); - CHECK( cz75.ammo_current().str() == ammo9mm_id.str() ); - CHECK( cz75.magazine_current()->ammo_remaining() == 20 ); - CHECK( cz75.magazine_current()->ammo_current().str() == ammo9mm_id.str() ); - } + } + WHEN( "set 9mm ammo in the current magazine of a gun 1 quantity" ) { + cz75.magazine_current()->ammo_set( ammo9mm_id, 1 ); + THEN( "gun and current magazine has 1 round of 9mm" ) { + CHECK( cz75.ammo_remaining() == 1 ); + CHECK( cz75.ammo_current().str() == ammo9mm_id.str() ); + CHECK( cz75.magazine_current()->ammo_remaining() == 1 ); + CHECK( cz75.magazine_current()->ammo_current().str() == ammo9mm_id.str() ); } - WHEN( "set 9mm ammo in the gun with magazine 12 quantity" ) { - cz75.ammo_set( ammo9mm_id, 12 ); - THEN( "gun and current magazine has 12 rounds of 9mm" ) { - CHECK( cz75.ammo_remaining() == 12 ); - CHECK( cz75.ammo_current().str() == ammo9mm_id.str() ); - CHECK( cz75.magazine_current()->ammo_remaining() == 12 ); - CHECK( cz75.magazine_current()->ammo_current().str() == ammo9mm_id.str() ); - } + } + WHEN( "set 9mm ammo in the gun with magazine 0 quantity" ) { + cz75.ammo_set( ammo9mm_id, 0 ); + THEN( "gun and current magazine has 0 rounds of null" ) { + CHECK( cz75.ammo_remaining() == 0 ); + CHECK( cz75.ammo_current().is_null() ); + CHECK( cz75.magazine_current()->ammo_remaining() == 0 ); + CHECK( cz75.magazine_current()->ammo_current().is_null() ); } - WHEN( "set 9mm ammo in the current magazine of a gun 1 quantity" ) { - cz75.magazine_current()->ammo_set( ammo9mm_id, 1 ); - THEN( "gun and current magazine has 1 round of 9mm" ) { - CHECK( cz75.ammo_remaining() == 1 ); - CHECK( cz75.ammo_current().str() == ammo9mm_id.str() ); - CHECK( cz75.magazine_current()->ammo_remaining() == 1 ); - CHECK( cz75.magazine_current()->ammo_current().str() == ammo9mm_id.str() ); - } + } + WHEN( "set 9mm FMJ ammo in the gun with magazine 10 quantity" ) { + itype_id ammo9mmfmj_id( "9mmfmj" ); + cz75.ammo_set( ammo9mmfmj_id, 10 ); + THEN( "gun and current magazine has 10 rounds of 9mm FMJ" ) { + CHECK( cz75.ammo_remaining() == 10 ); + CHECK( cz75.ammo_current().str() == ammo9mmfmj_id.str() ); + CHECK( cz75.magazine_current()->ammo_remaining() == 10 ); + CHECK( cz75.magazine_current()->ammo_current().str() == ammo9mmfmj_id.str() ); } - WHEN( "set 9mm ammo in the gun with magazine 0 quantity" ) { - cz75.ammo_set( ammo9mm_id, 0 ); - THEN( "gun and current magazine has 0 rounds of null" ) { + } + WHEN( "set 308 ammo in the 9mm gun with magazine" ) { + itype_id ammo308_id( "308" ); + std::string dmsg = capture_debugmsg_during( [&cz75, &ammo308_id]() { + cz75.ammo_set( ammo308_id, 15 ); + } ); + THEN( "get debugmsg with \"Tried to set invalid ammo of 308 for cz75\"" ) { + CHECK_THAT( dmsg, Catch::EndsWith( "Tried to set invalid ammo of 308 for cz75" ) ); + AND_THEN( "gun has 0 round of null" ) { CHECK( cz75.ammo_remaining() == 0 ); CHECK( cz75.ammo_current().is_null() ); - CHECK( cz75.magazine_current()->ammo_remaining() == 0 ); - CHECK( cz75.magazine_current()->ammo_current().is_null() ); - } - } - WHEN( "set 9mm FMJ ammo in the gun with magazine 10 quantity" ) { - itype_id ammo9mmfmj_id( "9mmfmj" ); - cz75.ammo_set( ammo9mmfmj_id, 10 ); - THEN( "gun and current magazine has 10 rounds of 9mm FMJ" ) { - CHECK( cz75.ammo_remaining() == 10 ); - CHECK( cz75.ammo_current().str() == ammo9mmfmj_id.str() ); - CHECK( cz75.magazine_current()->ammo_remaining() == 10 ); - CHECK( cz75.magazine_current()->ammo_current().str() == ammo9mmfmj_id.str() ); - } - } - WHEN( "set 308 ammo in the 9mm gun with magazine" ) { - itype_id ammo308_id( "308" ); - std::string dmsg = capture_debugmsg_during( [&cz75, &ammo308_id]() { - cz75.ammo_set( ammo308_id, 15 ); - } ); - THEN( "get debugmsg with \"Tried to set invalid ammo of 308 for cz75\"" ) { - CHECK_THAT( dmsg, Catch::EndsWith( "Tried to set invalid ammo of 308 for cz75" ) ); - AND_THEN( "gun has 0 round of null" ) { - CHECK( cz75.ammo_remaining() == 0 ); - CHECK( cz75.ammo_current().is_null() ); - } } } } - GIVEN( "CZ 75 B 9mm gun w/o magazine" ) { - item cz75( "cz75" ); - itype_id cz75mag_12rd_id( "cz75mag_12rd" ); - itype_id cz75mag_20rd_id( "cz75mag_20rd" ); - itype_id cz75mag_26rd_id( "cz75mag_26rd" ); - itype_id ammo9mm_id( "9mm" ); - REQUIRE( cz75.is_gun() ); - REQUIRE_FALSE( cz75.is_magazine() ); - REQUIRE( cz75.magazine_current() == nullptr ); - REQUIRE( cz75.magazine_compatible().size() == 3 ); - REQUIRE( cz75.magazine_compatible().count( cz75mag_12rd_id ) == 1 ); - REQUIRE( cz75.magazine_compatible().count( cz75mag_20rd_id ) == 1 ); - REQUIRE( cz75.magazine_compatible().count( cz75mag_26rd_id ) == 1 ); - REQUIRE( cz75.magazine_default().str() == cz75mag_12rd_id.str() ); - const ammotype &amtype = ammo9mm_id->ammo->type; - REQUIRE( cz75.ammo_capacity( amtype ) == 0 ); - REQUIRE( !cz75.ammo_default().is_null() ); - REQUIRE( cz75.magazine_default()->magazine->default_ammo.str() == ammo9mm_id.str() ); - WHEN( "set 9mm ammo in the gun w/o magazine w/o quantity" ) { - cz75.ammo_set( ammo9mm_id ); - THEN( "gun with new cz75mag_12rd magazine has 12 rounds of 9mm" ) { - CHECK( cz75.ammo_remaining() == 12 ); - CHECK( cz75.ammo_current().str() == ammo9mm_id.str() ); - REQUIRE( cz75.magazine_current() != nullptr ); - CHECK( cz75.magazine_current()->typeId().str() == cz75mag_12rd_id.str() ); - CHECK( cz75.magazine_current()->ammo_remaining() == 12 ); - CHECK( cz75.magazine_current()->ammo_current().str() == ammo9mm_id.str() ); - } + } +} + +TEST_CASE( "ammo_set items with MAGAZINE_WELL pockets without magazine", + "[ammo_set][magazine][ammo]" ) +{ + GIVEN( "CZ 75 B 9mm gun w/o magazine" ) { + item cz75( "cz75" ); + itype_id cz75mag_12rd_id( "cz75mag_12rd" ); + itype_id cz75mag_20rd_id( "cz75mag_20rd" ); + itype_id cz75mag_26rd_id( "cz75mag_26rd" ); + itype_id ammo9mm_id( "9mm" ); + REQUIRE( cz75.is_gun() ); + REQUIRE_FALSE( cz75.is_magazine() ); + REQUIRE( cz75.magazine_current() == nullptr ); + REQUIRE( cz75.magazine_compatible().size() == 3 ); + REQUIRE( cz75.magazine_compatible().count( cz75mag_12rd_id ) == 1 ); + REQUIRE( cz75.magazine_compatible().count( cz75mag_20rd_id ) == 1 ); + REQUIRE( cz75.magazine_compatible().count( cz75mag_26rd_id ) == 1 ); + REQUIRE( cz75.magazine_default().str() == cz75mag_12rd_id.str() ); + const ammotype &amtype = ammo9mm_id->ammo->type; + REQUIRE( cz75.ammo_capacity( amtype ) == 0 ); + REQUIRE( !cz75.ammo_default().is_null() ); + REQUIRE( cz75.magazine_default()->magazine->default_ammo.str() == ammo9mm_id.str() ); + WHEN( "set 9mm ammo in the gun w/o magazine w/o quantity" ) { + cz75.ammo_set( ammo9mm_id ); + THEN( "gun with new cz75mag_12rd magazine has 12 rounds of 9mm" ) { + CHECK( cz75.ammo_remaining() == 12 ); + CHECK( cz75.ammo_current().str() == ammo9mm_id.str() ); + REQUIRE( cz75.magazine_current() != nullptr ); + CHECK( cz75.magazine_current()->typeId().str() == cz75mag_12rd_id.str() ); + CHECK( cz75.magazine_current()->ammo_remaining() == 12 ); + CHECK( cz75.magazine_current()->ammo_current().str() == ammo9mm_id.str() ); } - WHEN( "set 9mm ammo in the gun w/o magazine 19 quantity" ) { - cz75.ammo_set( ammo9mm_id, 19 ); - THEN( "gun with new cz75mag_20rd magazine has 19 rounds of 9mm" ) { - CHECK( cz75.ammo_remaining() == 19 ); - CHECK( cz75.ammo_current().str() == ammo9mm_id.str() ); - REQUIRE( cz75.magazine_current() != nullptr ); - CHECK( cz75.magazine_current()->typeId().str() == cz75mag_20rd_id.str() ); - CHECK( cz75.magazine_current()->ammo_remaining() == 19 ); - CHECK( cz75.magazine_current()->ammo_current().str() == ammo9mm_id.str() ); - } + } + WHEN( "set 9mm ammo in the gun w/o magazine 19 quantity" ) { + cz75.ammo_set( ammo9mm_id, 19 ); + THEN( "gun with new cz75mag_20rd magazine has 19 rounds of 9mm" ) { + CHECK( cz75.ammo_remaining() == 19 ); + CHECK( cz75.ammo_current().str() == ammo9mm_id.str() ); + REQUIRE( cz75.magazine_current() != nullptr ); + CHECK( cz75.magazine_current()->typeId().str() == cz75mag_20rd_id.str() ); + CHECK( cz75.magazine_current()->ammo_remaining() == 19 ); + CHECK( cz75.magazine_current()->ammo_current().str() == ammo9mm_id.str() ); } - WHEN( "set 9mm ammo in the gun w/o magazine 21 quantity" ) { - cz75.ammo_set( ammo9mm_id, 21 ); - THEN( "gun with new cz75mag_26rd magazine has 21 rounds of 9mm" ) { - CHECK( cz75.ammo_remaining() == 21 ); - CHECK( cz75.ammo_current().str() == ammo9mm_id.str() ); - REQUIRE( cz75.magazine_current() != nullptr ); - CHECK( cz75.magazine_current()->typeId().str() == cz75mag_26rd_id.str() ); - CHECK( cz75.magazine_current()->ammo_remaining() == 21 ); - CHECK( cz75.magazine_current()->ammo_current().str() == ammo9mm_id.str() ); - } + } + WHEN( "set 9mm ammo in the gun w/o magazine 21 quantity" ) { + cz75.ammo_set( ammo9mm_id, 21 ); + THEN( "gun with new cz75mag_26rd magazine has 21 rounds of 9mm" ) { + CHECK( cz75.ammo_remaining() == 21 ); + CHECK( cz75.ammo_current().str() == ammo9mm_id.str() ); + REQUIRE( cz75.magazine_current() != nullptr ); + CHECK( cz75.magazine_current()->typeId().str() == cz75mag_26rd_id.str() ); + CHECK( cz75.magazine_current()->ammo_remaining() == 21 ); + CHECK( cz75.magazine_current()->ammo_current().str() == ammo9mm_id.str() ); } - WHEN( "set 9mm ammo in the gun w/o magazine 9000 quantity" ) { - cz75.ammo_set( ammo9mm_id, 9000 ); - THEN( "gun with new cz75mag_26rd magazine has 26 rounds of 9mm" ) { - CHECK( cz75.ammo_remaining() == 26 ); - CHECK( cz75.ammo_current().str() == ammo9mm_id.str() ); - REQUIRE( cz75.magazine_current() != nullptr ); - CHECK( cz75.magazine_current()->typeId().str() == cz75mag_26rd_id.str() ); - CHECK( cz75.magazine_current()->ammo_remaining() == 26 ); - CHECK( cz75.magazine_current()->ammo_current().str() == ammo9mm_id.str() ); - } + } + WHEN( "set 9mm ammo in the gun w/o magazine 9000 quantity" ) { + cz75.ammo_set( ammo9mm_id, 9000 ); + THEN( "gun with new cz75mag_26rd magazine has 26 rounds of 9mm" ) { + CHECK( cz75.ammo_remaining() == 26 ); + CHECK( cz75.ammo_current().str() == ammo9mm_id.str() ); + REQUIRE( cz75.magazine_current() != nullptr ); + CHECK( cz75.magazine_current()->typeId().str() == cz75mag_26rd_id.str() ); + CHECK( cz75.magazine_current()->ammo_remaining() == 26 ); + CHECK( cz75.magazine_current()->ammo_current().str() == ammo9mm_id.str() ); } - WHEN( "set 308 ammo in the 9mm gun w/o magazine 2 quantity" ) { - itype_id ammo308_id( "308" ); - std::string dmsg = capture_debugmsg_during( [&cz75, &ammo308_id]() { - cz75.ammo_set( ammo308_id, 2 ); - } ); - THEN( "get debugmsg with \"Tried to set invalid ammo of 308 for cz75\"" ) { - REQUIRE( !dmsg.empty() ); - CHECK_THAT( dmsg, Catch::EndsWith( "Tried to set invalid ammo of 308 for cz75" ) ); - AND_THEN( "gun w/o magazine has 0 round of null" ) { - CHECK( cz75.ammo_remaining() == 0 ); - CHECK( cz75.ammo_current().is_null() ); - CHECK( cz75.magazine_current() == nullptr ); - } + } + WHEN( "set 308 ammo in the 9mm gun w/o magazine 2 quantity" ) { + itype_id ammo308_id( "308" ); + std::string dmsg = capture_debugmsg_during( [&cz75, &ammo308_id]() { + cz75.ammo_set( ammo308_id, 2 ); + } ); + THEN( "get debugmsg with \"Tried to set invalid ammo of 308 for cz75\"" ) { + REQUIRE( !dmsg.empty() ); + CHECK_THAT( dmsg, Catch::EndsWith( "Tried to set invalid ammo of 308 for cz75" ) ); + AND_THEN( "gun w/o magazine has 0 round of null" ) { + CHECK( cz75.ammo_remaining() == 0 ); + CHECK( cz75.ammo_current().is_null() ); + CHECK( cz75.magazine_current() == nullptr ); } } } } - SECTION( "ammo_set items with CONTAINER pockets" ) { - GIVEN( "small box" ) { - item box( "box_small" ); - REQUIRE_FALSE( box.is_gun() ); - REQUIRE_FALSE( box.is_magazine() ); - REQUIRE( box.is_container_empty() ); - REQUIRE( box.magazine_current() == nullptr ); - REQUIRE( box.magazine_compatible().empty() ); - itype_id ammo9mm_id( "9mm" ); - WHEN( "set 9mm ammo in the small box" ) { - std::string dmsg = capture_debugmsg_during( [&box, &ammo9mm_id]() { - box.ammo_set( ammo9mm_id, 10 ); - } ); - THEN( "get debugmsg with \"Tried to set invalid ammo of 9mm for box_small\"" ) { - CHECK_THAT( dmsg, Catch::EndsWith( "Tried to set invalid ammo of 9mm for box_small" ) ); - AND_THEN( "small box still empty" ) { - REQUIRE_FALSE( box.is_gun() ); - REQUIRE_FALSE( box.is_magazine() ); - CHECK( box.is_container_empty() ); - } +} + +TEST_CASE( "ammo_set items with CONTAINER pockets", "[ammo_set][magazine][ammo]" ) +{ + GIVEN( "small box" ) { + item box( "box_small" ); + REQUIRE_FALSE( box.is_gun() ); + REQUIRE_FALSE( box.is_magazine() ); + REQUIRE( box.is_container_empty() ); + REQUIRE( box.magazine_current() == nullptr ); + REQUIRE( box.magazine_compatible().empty() ); + itype_id ammo9mm_id( "9mm" ); + WHEN( "set 9mm ammo in the small box" ) { + std::string dmsg = capture_debugmsg_during( [&box, &ammo9mm_id]() { + box.ammo_set( ammo9mm_id, 10 ); + } ); + THEN( "get debugmsg with \"Tried to set invalid ammo of 9mm for box_small\"" ) { + CHECK_THAT( dmsg, Catch::EndsWith( "Tried to set invalid ammo of 9mm for box_small" ) ); + AND_THEN( "small box still empty" ) { + REQUIRE_FALSE( box.is_gun() ); + REQUIRE_FALSE( box.is_magazine() ); + CHECK( box.is_container_empty() ); } } } From 427c71fe6c99026a4b41658716f8065d2f127fbb Mon Sep 17 00:00:00 2001 From: John Bytheway Date: Sat, 3 Apr 2021 08:57:42 -0400 Subject: [PATCH 354/453] Refactor iteminfo_test coverage and encumbrance Pull out a bunch of repeated REQUIRES commands into two new helper functions. This dramatically reduces the number of statements in the function, allowing it to pass the clang-tidy check for function size, and I think it also improves readability. --- tests/iteminfo_test.cpp | 447 ++++++++++++++++++++++------------------ 1 file changed, 241 insertions(+), 206 deletions(-) diff --git a/tests/iteminfo_test.cpp b/tests/iteminfo_test.cpp index 9c56537dc2b6d..aee453d83abb3 100644 --- a/tests/iteminfo_test.cpp +++ b/tests/iteminfo_test.cpp @@ -20,6 +20,7 @@ #include "player_helpers.h" #include "recipe.h" #include "recipe_dictionary.h" +#include "stringmaker.h" // IWYU pragma: keep #include "type_id.h" #include "units.h" #include "value_ptr.h" @@ -638,6 +639,44 @@ TEST_CASE( "techniques when wielded", "[iteminfo][weapon][techniques]" ) " Medium blocking ability\n" ); } +static std::vector bodyparts_to_check() +{ + return { + bodypart_id( "torso" ), + bodypart_id( "arm_l" ), + bodypart_id( "arm_r" ), + bodypart_id( "leg_l" ), + bodypart_id( "leg_r" ), + bodypart_id( "hand_l" ), + bodypart_id( "hand_r" ), + bodypart_id( "head" ), + bodypart_id( "mouth" ), + bodypart_id( "foot_l" ), + bodypart_id( "foot_r" ), + }; +} + +static void verify_item_coverage( const item &i, const std::map &expected ) +{ + CAPTURE( i.typeId().str() ); + REQUIRE( i.get_covered_body_parts().any() ); + for( const bodypart_id &bp : bodyparts_to_check() ) { + CAPTURE( bp.id().str() ); + REQUIRE( i.get_coverage( bp ) == expected.at( bp ) ); + } +} + +static void verify_item_encumbrance( const item &i, item::encumber_flags flags, int average, + const std::map &expected ) +{ + CAPTURE( i.typeId().str() ); + REQUIRE( i.get_avg_encumber( get_player_character(), flags ) == average ); + for( const bodypart_id &bp : bodyparts_to_check() ) { + CAPTURE( bp.id().str() ); + REQUIRE( i.get_encumber( get_player_character(), bp, flags ) == expected.at( bp ) ); + } +} + // Related JSON fields: // "covers" // "coverage" @@ -653,18 +692,21 @@ TEST_CASE( "armor coverage, warmth, and encumbrance", "[iteminfo][armor][coverag SECTION( "armor with coverage shows covered body parts, warmth, encumbrance, and protection values" ) { // Long-sleeved shirt covering torso and arms item longshirt( "test_longshirt" ); - REQUIRE( longshirt.get_covered_body_parts().any() ); - REQUIRE( longshirt.get_coverage( bodypart_id( "torso" ) ) == 90 ); - REQUIRE( longshirt.get_coverage( bodypart_id( "arm_l" ) ) == 90 ); - REQUIRE( longshirt.get_coverage( bodypart_id( "arm_r" ) ) == 90 ); - REQUIRE( longshirt.get_coverage( bodypart_id( "leg_l" ) ) == 0 ); - REQUIRE( longshirt.get_coverage( bodypart_id( "leg_r" ) ) == 0 ); - REQUIRE( longshirt.get_coverage( bodypart_id( "hand_l" ) ) == 0 ); - REQUIRE( longshirt.get_coverage( bodypart_id( "hand_r" ) ) == 0 ); - REQUIRE( longshirt.get_coverage( bodypart_id( "head" ) ) == 0 ); - REQUIRE( longshirt.get_coverage( bodypart_id( "mouth" ) ) == 0 ); - REQUIRE( longshirt.get_coverage( bodypart_id( "foot_l" ) ) == 0 ); - REQUIRE( longshirt.get_coverage( bodypart_id( "foot_r" ) ) == 0 ); + verify_item_coverage( + longshirt, { + { bodypart_id( "torso" ), 90 }, + { bodypart_id( "arm_l" ), 90 }, + { bodypart_id( "arm_r" ), 90 }, + { bodypart_id( "leg_l" ), 0 }, + { bodypart_id( "leg_r" ), 0 }, + { bodypart_id( "hand_l" ), 0 }, + { bodypart_id( "hand_r" ), 0 }, + { bodypart_id( "head" ), 0 }, + { bodypart_id( "mouth" ), 0 }, + { bodypart_id( "foot_l" ), 0 }, + { bodypart_id( "foot_r" ), 0 }, + } + ); CHECK( item_info_str( longshirt, { iteminfo_parts::ARMOR_BODYPARTS } ) == "--\n" @@ -677,7 +719,9 @@ TEST_CASE( "armor coverage, warmth, and encumbrance", "[iteminfo][armor][coverag "Layer: Normal.\n" ); // Coverage and warmth are displayed together on a single line - std::vector cov_warm_shirt = { iteminfo_parts::ARMOR_COVERAGE, iteminfo_parts::ARMOR_WARMTH }; + std::vector cov_warm_shirt = { + iteminfo_parts::ARMOR_COVERAGE, iteminfo_parts::ARMOR_WARMTH + }; REQUIRE( longshirt.get_avg_coverage() == 90 ); REQUIRE( longshirt.get_warmth() == 5 ); CHECK( item_info_str( longshirt, cov_warm_shirt ) @@ -685,43 +729,37 @@ TEST_CASE( "armor coverage, warmth, and encumbrance", "[iteminfo][armor][coverag "--\n" "Average Coverage: 90% Warmth: 5\n" ); - REQUIRE( longshirt.get_avg_encumber( get_player_character() ) == 3 ); - REQUIRE( longshirt.get_encumber( get_player_character(), bodypart_id( "torso" ) ) == 3 ); - REQUIRE( longshirt.get_encumber( get_player_character(), bodypart_id( "arm_l" ) ) == 3 ); - REQUIRE( longshirt.get_encumber( get_player_character(), bodypart_id( "arm_r" ) ) == 3 ); - REQUIRE( longshirt.get_encumber( get_player_character(), bodypart_id( "leg_l" ) ) == 0 ); - REQUIRE( longshirt.get_encumber( get_player_character(), bodypart_id( "leg_r" ) ) == 0 ); - REQUIRE( longshirt.get_encumber( get_player_character(), bodypart_id( "hand_l" ) ) == 0 ); - REQUIRE( longshirt.get_encumber( get_player_character(), bodypart_id( "hand_r" ) ) == 0 ); - REQUIRE( longshirt.get_encumber( get_player_character(), bodypart_id( "head" ) ) == 0 ); - REQUIRE( longshirt.get_encumber( get_player_character(), bodypart_id( "mouth" ) ) == 0 ); - REQUIRE( longshirt.get_encumber( get_player_character(), bodypart_id( "foot_l" ) ) == 0 ); - REQUIRE( longshirt.get_encumber( get_player_character(), bodypart_id( "foot_r" ) ) == 0 ); - - REQUIRE( longshirt.get_avg_encumber( get_player_character(), - item::encumber_flags::assume_full ) == 3 ); - REQUIRE( longshirt.get_encumber( get_player_character(), bodypart_id( "torso" ), - item::encumber_flags::assume_full ) == 3 ); - REQUIRE( longshirt.get_encumber( get_player_character(), bodypart_id( "arm_l" ), - item::encumber_flags::assume_full ) == 3 ); - REQUIRE( longshirt.get_encumber( get_player_character(), bodypart_id( "arm_r" ), - item::encumber_flags::assume_full ) == 3 ); - REQUIRE( longshirt.get_encumber( get_player_character(), bodypart_id( "leg_l" ), - item::encumber_flags::assume_full ) == 0 ); - REQUIRE( longshirt.get_encumber( get_player_character(), bodypart_id( "leg_r" ), - item::encumber_flags::assume_full ) == 0 ); - REQUIRE( longshirt.get_encumber( get_player_character(), bodypart_id( "hand_l" ), - item::encumber_flags::assume_full ) == 0 ); - REQUIRE( longshirt.get_encumber( get_player_character(), bodypart_id( "hand_r" ), - item::encumber_flags::assume_full ) == 0 ); - REQUIRE( longshirt.get_encumber( get_player_character(), bodypart_id( "head" ), - item::encumber_flags::assume_full ) == 0 ); - REQUIRE( longshirt.get_encumber( get_player_character(), bodypart_id( "mouth" ), - item::encumber_flags::assume_full ) == 0 ); - REQUIRE( longshirt.get_encumber( get_player_character(), bodypart_id( "foot_l" ), - item::encumber_flags::assume_full ) == 0 ); - REQUIRE( longshirt.get_encumber( get_player_character(), bodypart_id( "foot_r" ), - item::encumber_flags::assume_full ) == 0 ); + verify_item_encumbrance( + longshirt, item::encumber_flags::none, 3, { + { bodypart_id( "torso" ), 3 }, + { bodypart_id( "arm_l" ), 3 }, + { bodypart_id( "arm_r" ), 3 }, + { bodypart_id( "leg_l" ), 0 }, + { bodypart_id( "leg_r" ), 0 }, + { bodypart_id( "hand_l" ), 0 }, + { bodypart_id( "hand_r" ), 0 }, + { bodypart_id( "head" ), 0 }, + { bodypart_id( "mouth" ), 0 }, + { bodypart_id( "foot_l" ), 0 }, + { bodypart_id( "foot_r" ), 0 }, + } + ); + + verify_item_encumbrance( + longshirt, item::encumber_flags::assume_full, 3, { + { bodypart_id( "torso" ), 3 }, + { bodypart_id( "arm_l" ), 3 }, + { bodypart_id( "arm_r" ), 3 }, + { bodypart_id( "leg_l" ), 0 }, + { bodypart_id( "leg_r" ), 0 }, + { bodypart_id( "hand_l" ), 0 }, + { bodypart_id( "hand_r" ), 0 }, + { bodypart_id( "head" ), 0 }, + { bodypart_id( "mouth" ), 0 }, + { bodypart_id( "foot_l" ), 0 }, + { bodypart_id( "foot_r" ), 0 }, + } + ); CHECK( item_info_str( longshirt, { iteminfo_parts::ARMOR_ENCUMBRANCE } ) == "--\n" @@ -753,59 +791,56 @@ TEST_CASE( "armor coverage, warmth, and encumbrance", "[iteminfo][armor][coverag "--\n" "Average Coverage: 95% Warmth: 35\n" ); - REQUIRE( swat_armor.get_coverage( bodypart_id( "torso" ) ) == 95 ); - REQUIRE( swat_armor.get_coverage( bodypart_id( "leg_l" ) ) == 95 ); - REQUIRE( swat_armor.get_coverage( bodypart_id( "leg_r" ) ) == 95 ); - REQUIRE( swat_armor.get_coverage( bodypart_id( "arm_l" ) ) == 95 ); - REQUIRE( swat_armor.get_coverage( bodypart_id( "arm_r" ) ) == 95 ); - REQUIRE( swat_armor.get_coverage( bodypart_id( "head" ) ) == 0 ); - REQUIRE( swat_armor.get_coverage( bodypart_id( "foot_l" ) ) == 0 ); - REQUIRE( swat_armor.get_coverage( bodypart_id( "foot_r" ) ) == 0 ); - REQUIRE( swat_armor.get_coverage( bodypart_id( "eyes" ) ) == 0 ); - REQUIRE( swat_armor.get_coverage( bodypart_id( "mouth" ) ) == 0 ); - REQUIRE( swat_armor.get_coverage( bodypart_id( "hand_r" ) ) == 0 ); - REQUIRE( swat_armor.get_coverage( bodypart_id( "hand_l" ) ) == 0 ); - - REQUIRE( swat_armor.get_avg_encumber( get_player_character() ) == 12 ); - REQUIRE( swat_armor.get_encumber( get_player_character(), bodypart_id( "torso" ) ) == 12 ); - REQUIRE( swat_armor.get_encumber( get_player_character(), bodypart_id( "leg_l" ) ) == 12 ); - REQUIRE( swat_armor.get_encumber( get_player_character(), bodypart_id( "leg_r" ) ) == 12 ); - REQUIRE( swat_armor.get_encumber( get_player_character(), bodypart_id( "arm_l" ) ) == 12 ); - REQUIRE( swat_armor.get_encumber( get_player_character(), bodypart_id( "arm_r" ) ) == 12 ); - REQUIRE( swat_armor.get_encumber( get_player_character(), bodypart_id( "head" ) ) == 0 ); - REQUIRE( swat_armor.get_encumber( get_player_character(), bodypart_id( "foot_l" ) ) == 0 ); - REQUIRE( swat_armor.get_encumber( get_player_character(), bodypart_id( "foot_r" ) ) == 0 ); - REQUIRE( swat_armor.get_encumber( get_player_character(), bodypart_id( "eyes" ) ) == 0 ); - REQUIRE( swat_armor.get_encumber( get_player_character(), bodypart_id( "mouth" ) ) == 0 ); - REQUIRE( swat_armor.get_encumber( get_player_character(), bodypart_id( "hand_l" ) ) == 0 ); - REQUIRE( swat_armor.get_encumber( get_player_character(), bodypart_id( "hand_r" ) ) == 0 ); - - REQUIRE( swat_armor.get_avg_encumber( get_player_character(), - item::encumber_flags::assume_full ) == 25 ); - REQUIRE( swat_armor.get_encumber( get_player_character(), bodypart_id( "torso" ), - item::encumber_flags::assume_full ) == 25 ); - REQUIRE( swat_armor.get_encumber( get_player_character(), bodypart_id( "leg_l" ), - item::encumber_flags::assume_full ) == 25 ); - REQUIRE( swat_armor.get_encumber( get_player_character(), bodypart_id( "leg_r" ), - item::encumber_flags::assume_full ) == 25 ); - REQUIRE( swat_armor.get_encumber( get_player_character(), bodypart_id( "arm_l" ), - item::encumber_flags::assume_full ) == 25 ); - REQUIRE( swat_armor.get_encumber( get_player_character(), bodypart_id( "arm_r" ), - item::encumber_flags::assume_full ) == 25 ); - REQUIRE( swat_armor.get_encumber( get_player_character(), bodypart_id( "foot_l" ), - item::encumber_flags::assume_full ) == 0 ); - REQUIRE( swat_armor.get_encumber( get_player_character(), bodypart_id( "foot_r" ), - item::encumber_flags::assume_full ) == 0 ); - REQUIRE( swat_armor.get_encumber( get_player_character(), bodypart_id( "head" ), - item::encumber_flags::assume_full ) == 0 ); - REQUIRE( swat_armor.get_encumber( get_player_character(), bodypart_id( "eyes" ), - item::encumber_flags::assume_full ) == 0 ); - REQUIRE( swat_armor.get_encumber( get_player_character(), bodypart_id( "mouth" ), - item::encumber_flags::assume_full ) == 0 ); - REQUIRE( swat_armor.get_encumber( get_player_character(), bodypart_id( "hand_l" ), - item::encumber_flags::assume_full ) == 0 ); - REQUIRE( swat_armor.get_encumber( get_player_character(), bodypart_id( "hand_r" ), - item::encumber_flags::assume_full ) == 0 ); + verify_item_coverage( + swat_armor, { + { bodypart_id( "torso" ), 95 }, + { bodypart_id( "leg_l" ), 95 }, + { bodypart_id( "leg_r" ), 95 }, + { bodypart_id( "arm_l" ), 95 }, + { bodypart_id( "arm_r" ), 95 }, + { bodypart_id( "head" ), 0 }, + { bodypart_id( "foot_l" ), 0 }, + { bodypart_id( "foot_r" ), 0 }, + { bodypart_id( "eyes" ), 0 }, + { bodypart_id( "mouth" ), 0 }, + { bodypart_id( "hand_r" ), 0 }, + { bodypart_id( "hand_l" ), 0 }, + } + ); + + verify_item_encumbrance( + swat_armor, item::encumber_flags::none, 12, { + { bodypart_id( "torso" ), 12 }, + { bodypart_id( "leg_l" ), 12 }, + { bodypart_id( "leg_r" ), 12 }, + { bodypart_id( "arm_l" ), 12 }, + { bodypart_id( "arm_r" ), 12 }, + { bodypart_id( "head" ), 0 }, + { bodypart_id( "foot_l" ), 0 }, + { bodypart_id( "foot_r" ), 0 }, + { bodypart_id( "eyes" ), 0 }, + { bodypart_id( "mouth" ), 0 }, + { bodypart_id( "hand_l" ), 0 }, + { bodypart_id( "hand_r" ), 0 }, + } + ); + + verify_item_encumbrance( + swat_armor, item::encumber_flags::assume_full, 25, { + { bodypart_id( "torso" ), 25 }, + { bodypart_id( "leg_l" ), 25 }, + { bodypart_id( "leg_r" ), 25 }, + { bodypart_id( "arm_l" ), 25 }, + { bodypart_id( "arm_r" ), 25 }, + { bodypart_id( "foot_l" ), 0 }, + { bodypart_id( "foot_r" ), 0 }, + { bodypart_id( "head" ), 0 }, + { bodypart_id( "eyes" ), 0 }, + { bodypart_id( "mouth" ), 0 }, + { bodypart_id( "hand_l" ), 0 }, + { bodypart_id( "hand_r" ), 0 }, + } + ); CHECK( item_info_str( swat_armor, { iteminfo_parts::ARMOR_ENCUMBRANCE } ) == "--\n" @@ -842,55 +877,56 @@ TEST_CASE( "armor coverage, warmth, and encumbrance", "[iteminfo][armor][coverag "Average Coverage: 95% Warmth: 70\n" ); REQUIRE( faux_fur_pants.get_avg_coverage() == 95 ); - REQUIRE( faux_fur_pants.get_coverage( bodypart_id( "leg_l" ) ) == 95 ); - REQUIRE( faux_fur_pants.get_coverage( bodypart_id( "leg_r" ) ) == 95 ); - REQUIRE( faux_fur_pants.get_coverage( bodypart_id( "arm_l" ) ) == 0 ); - REQUIRE( faux_fur_pants.get_coverage( bodypart_id( "arm_r" ) ) == 0 ); - REQUIRE( faux_fur_pants.get_coverage( bodypart_id( "foot_r" ) ) == 0 ); - REQUIRE( faux_fur_pants.get_coverage( bodypart_id( "foot_l" ) ) == 0 ); - REQUIRE( faux_fur_pants.get_coverage( bodypart_id( "head" ) ) == 0 ); - REQUIRE( faux_fur_pants.get_coverage( bodypart_id( "eyes" ) ) == 0 ); - REQUIRE( faux_fur_pants.get_coverage( bodypart_id( "mouth" ) ) == 0 ); - REQUIRE( faux_fur_pants.get_coverage( bodypart_id( "hand_l" ) ) == 0 ); - REQUIRE( faux_fur_pants.get_coverage( bodypart_id( "hand_r" ) ) == 0 ); - - REQUIRE( faux_fur_pants.get_avg_encumber( get_player_character() ) == 16 ); - REQUIRE( faux_fur_pants.get_encumber( get_player_character(), bodypart_id( "leg_l" ) ) == 16 ); - REQUIRE( faux_fur_pants.get_encumber( get_player_character(), bodypart_id( "leg_r" ) ) == 16 ); - REQUIRE( faux_fur_pants.get_encumber( get_player_character(), bodypart_id( "arm_l" ) ) == 0 ); - REQUIRE( faux_fur_pants.get_encumber( get_player_character(), bodypart_id( "arm_r" ) ) == 0 ); - REQUIRE( faux_fur_pants.get_encumber( get_player_character(), bodypart_id( "foot_r" ) ) == 0 ); - REQUIRE( faux_fur_pants.get_encumber( get_player_character(), bodypart_id( "foot_l" ) ) == 0 ); - REQUIRE( faux_fur_pants.get_encumber( get_player_character(), bodypart_id( "head" ) ) == 0 ); - REQUIRE( faux_fur_pants.get_encumber( get_player_character(), bodypart_id( "eyes" ) ) == 0 ); - REQUIRE( faux_fur_pants.get_encumber( get_player_character(), bodypart_id( "mouth" ) ) == 0 ); - REQUIRE( faux_fur_pants.get_encumber( get_player_character(), bodypart_id( "hand_l" ) ) == 0 ); - REQUIRE( faux_fur_pants.get_encumber( get_player_character(), bodypart_id( "hand_r" ) ) == 0 ); - - REQUIRE( faux_fur_pants.get_avg_encumber( get_player_character(), - item::encumber_flags::assume_full ) == 20 ); - REQUIRE( faux_fur_pants.get_encumber( get_player_character(), bodypart_id( "leg_l" ), - item::encumber_flags::assume_full ) == 20 ); - REQUIRE( faux_fur_pants.get_encumber( get_player_character(), bodypart_id( "leg_r" ), - item::encumber_flags::assume_full ) == 20 ); - REQUIRE( faux_fur_pants.get_encumber( get_player_character(), bodypart_id( "arm_l" ), - item::encumber_flags::assume_full ) == 0 ); - REQUIRE( faux_fur_pants.get_encumber( get_player_character(), bodypart_id( "arm_r" ), - item::encumber_flags::assume_full ) == 0 ); - REQUIRE( faux_fur_pants.get_encumber( get_player_character(), bodypart_id( "foot_r" ), - item::encumber_flags::assume_full ) == 0 ); - REQUIRE( faux_fur_pants.get_encumber( get_player_character(), bodypart_id( "foot_l" ), - item::encumber_flags::assume_full ) == 0 ); - REQUIRE( faux_fur_pants.get_encumber( get_player_character(), bodypart_id( "head" ), - item::encumber_flags::assume_full ) == 0 ); - REQUIRE( faux_fur_pants.get_encumber( get_player_character(), bodypart_id( "eyes" ), - item::encumber_flags::assume_full ) == 0 ); - REQUIRE( faux_fur_pants.get_encumber( get_player_character(), bodypart_id( "mouth" ), - item::encumber_flags::assume_full ) == 0 ); - REQUIRE( faux_fur_pants.get_encumber( get_player_character(), bodypart_id( "hand_l" ), - item::encumber_flags::assume_full ) == 0 ); - REQUIRE( faux_fur_pants.get_encumber( get_player_character(), bodypart_id( "hand_r" ), - item::encumber_flags::assume_full ) == 0 ); + verify_item_coverage( + faux_fur_pants, { + { bodypart_id( "torso" ), 0 }, + { bodypart_id( "leg_l" ), 95 }, + { bodypart_id( "leg_r" ), 95 }, + { bodypart_id( "arm_l" ), 0 }, + { bodypart_id( "arm_r" ), 0 }, + { bodypart_id( "foot_r" ), 0 }, + { bodypart_id( "foot_l" ), 0 }, + { bodypart_id( "head" ), 0 }, + { bodypart_id( "eyes" ), 0 }, + { bodypart_id( "mouth" ), 0 }, + { bodypart_id( "hand_l" ), 0 }, + { bodypart_id( "hand_r" ), 0 }, + } + ); + + verify_item_encumbrance( + faux_fur_pants, item::encumber_flags::none, 16, { + { bodypart_id( "torso" ), 0 }, + { bodypart_id( "leg_l" ), 16 }, + { bodypart_id( "leg_r" ), 16 }, + { bodypart_id( "arm_l" ), 0 }, + { bodypart_id( "arm_r" ), 0 }, + { bodypart_id( "foot_r" ), 0 }, + { bodypart_id( "foot_l" ), 0 }, + { bodypart_id( "head" ), 0 }, + { bodypart_id( "eyes" ), 0 }, + { bodypart_id( "mouth" ), 0 }, + { bodypart_id( "hand_l" ), 0 }, + { bodypart_id( "hand_r" ), 0 }, + } + ); + + verify_item_encumbrance( + faux_fur_pants, item::encumber_flags::assume_full, 20, { + { bodypart_id( "torso" ), 0 }, + { bodypart_id( "leg_l" ), 20 }, + { bodypart_id( "leg_r" ), 20 }, + { bodypart_id( "arm_l" ), 0 }, + { bodypart_id( "arm_r" ), 0 }, + { bodypart_id( "foot_r" ), 0 }, + { bodypart_id( "foot_l" ), 0 }, + { bodypart_id( "head" ), 0 }, + { bodypart_id( "eyes" ), 0 }, + { bodypart_id( "mouth" ), 0 }, + { bodypart_id( "hand_l" ), 0 }, + { bodypart_id( "hand_r" ), 0 }, + } + ); item faux_fur_suit( "test_portion_faux_fur_pants_suit" ); REQUIRE( faux_fur_suit.get_covered_body_parts().any() ); @@ -907,7 +943,9 @@ TEST_CASE( "armor coverage, warmth, and encumbrance", "[iteminfo][armor][coverag "--\n" "Layer: Normal.\n" ); - std::vector cov_warm_suit = { iteminfo_parts::ARMOR_COVERAGE, iteminfo_parts::ARMOR_WARMTH }; + std::vector cov_warm_suit = { + iteminfo_parts::ARMOR_COVERAGE, iteminfo_parts::ARMOR_WARMTH + }; REQUIRE( faux_fur_suit.get_avg_coverage() == 75 ); REQUIRE( faux_fur_suit.get_warmth() == 5 ); CHECK( item_info_str( faux_fur_suit, cov_warm_suit ) @@ -916,59 +954,56 @@ TEST_CASE( "armor coverage, warmth, and encumbrance", "[iteminfo][armor][coverag "Average Coverage: 75% Warmth: 5\n" ); REQUIRE( faux_fur_suit.get_avg_coverage() == 75 ); - REQUIRE( faux_fur_suit.get_coverage( bodypart_id( "torso" ) ) == 100 ); - REQUIRE( faux_fur_suit.get_coverage( bodypart_id( "leg_l" ) ) == 50 ); - REQUIRE( faux_fur_suit.get_coverage( bodypart_id( "leg_r" ) ) == 100 ); - REQUIRE( faux_fur_suit.get_coverage( bodypart_id( "arm_l" ) ) == 50 ); - REQUIRE( faux_fur_suit.get_coverage( bodypart_id( "arm_r" ) ) == 100 ); - REQUIRE( faux_fur_suit.get_coverage( bodypart_id( "head" ) ) == 50 ); - REQUIRE( faux_fur_suit.get_coverage( bodypart_id( "eyes" ) ) == 0 ); - REQUIRE( faux_fur_suit.get_coverage( bodypart_id( "mouth" ) ) == 0 ); - REQUIRE( faux_fur_suit.get_coverage( bodypart_id( "hand_l" ) ) == 0 ); - REQUIRE( faux_fur_suit.get_coverage( bodypart_id( "hand_r" ) ) == 0 ); - REQUIRE( faux_fur_suit.get_coverage( bodypart_id( "foot_l" ) ) == 0 ); - REQUIRE( faux_fur_suit.get_coverage( bodypart_id( "foot_r" ) ) == 0 ); - - REQUIRE( faux_fur_suit.get_avg_encumber( get_player_character() ) == 7 ); - REQUIRE( faux_fur_suit.get_encumber( get_player_character(), bodypart_id( "torso" ) ) == 10 ); - REQUIRE( faux_fur_suit.get_encumber( get_player_character(), bodypart_id( "leg_l" ) ) == 5 ); - REQUIRE( faux_fur_suit.get_encumber( get_player_character(), bodypart_id( "leg_r" ) ) == 10 ); - REQUIRE( faux_fur_suit.get_encumber( get_player_character(), bodypart_id( "arm_l" ) ) == 5 ); - REQUIRE( faux_fur_suit.get_encumber( get_player_character(), bodypart_id( "arm_r" ) ) == 10 ); - REQUIRE( faux_fur_suit.get_encumber( get_player_character(), bodypart_id( "head" ) ) == 5 ); - REQUIRE( faux_fur_suit.get_encumber( get_player_character(), bodypart_id( "eyes" ) ) == 0 ); - REQUIRE( faux_fur_suit.get_encumber( get_player_character(), bodypart_id( "mouth" ) ) == 0 ); - REQUIRE( faux_fur_suit.get_encumber( get_player_character(), bodypart_id( "foot_l" ) ) == 0 ); - REQUIRE( faux_fur_suit.get_encumber( get_player_character(), bodypart_id( "foot_r" ) ) == 0 ); - REQUIRE( faux_fur_suit.get_encumber( get_player_character(), bodypart_id( "hand_r" ) ) == 0 ); - REQUIRE( faux_fur_suit.get_encumber( get_player_character(), bodypart_id( "hand_r" ) ) == 0 ); - - REQUIRE( faux_fur_suit.get_avg_encumber( get_player_character(), - item::encumber_flags::assume_full ) == 17 ); - REQUIRE( faux_fur_suit.get_encumber( get_player_character(), bodypart_id( "torso" ), - item::encumber_flags::assume_full ) == 25 ); - REQUIRE( faux_fur_suit.get_encumber( get_player_character(), bodypart_id( "leg_l" ), - item::encumber_flags::assume_full ) == 9 ); - REQUIRE( faux_fur_suit.get_encumber( get_player_character(), bodypart_id( "leg_r" ), - item::encumber_flags::assume_full ) == 25 ); - REQUIRE( faux_fur_suit.get_encumber( get_player_character(), bodypart_id( "arm_l" ), - item::encumber_flags::assume_full ) == 9 ); - REQUIRE( faux_fur_suit.get_encumber( get_player_character(), bodypart_id( "arm_r" ), - item::encumber_flags::assume_full ) == 25 ); - REQUIRE( faux_fur_suit.get_encumber( get_player_character(), bodypart_id( "head" ), - item::encumber_flags::assume_full ) == 9 ); - REQUIRE( faux_fur_suit.get_encumber( get_player_character(), bodypart_id( "eyes" ), - item::encumber_flags::assume_full ) == 0 ); - REQUIRE( faux_fur_suit.get_encumber( get_player_character(), bodypart_id( "mouth" ), - item::encumber_flags::assume_full ) == 0 ); - REQUIRE( faux_fur_suit.get_encumber( get_player_character(), bodypart_id( "hand_l" ), - item::encumber_flags::assume_full ) == 0 ); - REQUIRE( faux_fur_suit.get_encumber( get_player_character(), bodypart_id( "hand_r" ), - item::encumber_flags::assume_full ) == 0 ); - REQUIRE( faux_fur_suit.get_encumber( get_player_character(), bodypart_id( "foot_l" ), - item::encumber_flags::assume_full ) == 0 ); - REQUIRE( faux_fur_suit.get_encumber( get_player_character(), bodypart_id( "foot_r" ), - item::encumber_flags::assume_full ) == 0 ); + verify_item_coverage( + faux_fur_suit, { + { bodypart_id( "torso" ), 100 }, + { bodypart_id( "leg_l" ), 50 }, + { bodypart_id( "leg_r" ), 100 }, + { bodypart_id( "arm_l" ), 50 }, + { bodypart_id( "arm_r" ), 100 }, + { bodypart_id( "head" ), 50 }, + { bodypart_id( "eyes" ), 0 }, + { bodypart_id( "mouth" ), 0 }, + { bodypart_id( "hand_l" ), 0 }, + { bodypart_id( "hand_r" ), 0 }, + { bodypart_id( "foot_l" ), 0 }, + { bodypart_id( "foot_r" ), 0 }, + } + ); + + verify_item_encumbrance( + faux_fur_suit, item::encumber_flags::none, 7, { + { bodypart_id( "torso" ), 10 }, + { bodypart_id( "leg_l" ), 5 }, + { bodypart_id( "leg_r" ), 10 }, + { bodypart_id( "arm_l" ), 5 }, + { bodypart_id( "arm_r" ), 10 }, + { bodypart_id( "head" ), 5 }, + { bodypart_id( "eyes" ), 0 }, + { bodypart_id( "mouth" ), 0 }, + { bodypart_id( "foot_l" ), 0 }, + { bodypart_id( "foot_r" ), 0 }, + { bodypart_id( "hand_l" ), 0 }, + { bodypart_id( "hand_r" ), 0 }, + } + ); + + verify_item_encumbrance( + faux_fur_suit, item::encumber_flags::assume_full, 17, { + { bodypart_id( "torso" ), 25 }, + { bodypart_id( "leg_l" ), 9 }, + { bodypart_id( "leg_r" ), 25 }, + { bodypart_id( "arm_l" ), 9 }, + { bodypart_id( "arm_r" ), 25 }, + { bodypart_id( "head" ), 9 }, + { bodypart_id( "eyes" ), 0 }, + { bodypart_id( "mouth" ), 0 }, + { bodypart_id( "hand_l" ), 0 }, + { bodypart_id( "hand_r" ), 0 }, + { bodypart_id( "foot_l" ), 0 }, + { bodypart_id( "foot_r" ), 0 }, + } + ); CHECK( item_info_str( faux_fur_suit, { iteminfo_parts::ARMOR_ENCUMBRANCE } ) == "--\n" From 2ed6e0b406d7707f3459b6aa52a58d86e956b34d Mon Sep 17 00:00:00 2001 From: John Bytheway Date: Thu, 8 Apr 2021 11:06:26 -0400 Subject: [PATCH 355/453] Fix compilation of magic.cpp (#48430) This got broken by #47946 because exp_for_level was made a member function but one call to it was not updated. Fix that. --- src/magic.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/magic.cpp b/src/magic.cpp index 0e12bcef19813..8f5344a1b16a1 100644 --- a/src/magic.cpp +++ b/src/magic.cpp @@ -2388,7 +2388,7 @@ spell fake_spell::get_spell( int min_level_override ) const debugmsg( "ERROR: fake spell %s has higher min_level than max_level", id.c_str() ); return sp; } - sp.set_exp( exp_for_level( level_of_spell ) ); + sp.set_exp( sp.exp_for_level( level_of_spell ) ); return sp; } From 4021a808fba1fc7728b8cd1a8920188b3332ed78 Mon Sep 17 00:00:00 2001 From: John Bytheway Date: Fri, 9 Apr 2021 18:08:21 -0400 Subject: [PATCH 356/453] Enable clang-tidy readability-function-size (#48407) * Enable readability-function-size Suppress the remaining cases for functions I don't care to refactor. * Typo in iteminfo_test --- .clang-tidy | 1 - src/mapgen.cpp | 1 + tests/iteminfo_test.cpp | 2 +- tests/line_test.cpp | 2 +- tests/reload_magazine_test.cpp | 1 + tests/visitable_remove_test.cpp | 1 + 6 files changed, 5 insertions(+), 3 deletions(-) diff --git a/.clang-tidy b/.clang-tidy index 5aad02e467092..2b0d987887aec 100644 --- a/.clang-tidy +++ b/.clang-tidy @@ -44,7 +44,6 @@ readability-*,\ -performance-unnecessary-value-param,\ -readability-braces-around-statements,\ -readability-else-after-return,\ --readability-function-size,\ -readability-implicit-bool-conversion,\ -readability-isolate-declaration,\ -readability-magic-numbers,\ diff --git a/src/mapgen.cpp b/src/mapgen.cpp index 664aada2e175b..dc0d5a664d435 100644 --- a/src/mapgen.cpp +++ b/src/mapgen.cpp @@ -3016,6 +3016,7 @@ void map::draw_map( mapgendata &dat ) static const int SOUTH_EDGE = 2 * SEEY - 1; static const int EAST_EDGE = 2 * SEEX - 1; +// NOLINTNEXTLINE(readability-function-size) void map::draw_lab( mapgendata &dat ) { const oter_id &terrain_type = dat.terrain_type(); diff --git a/tests/iteminfo_test.cpp b/tests/iteminfo_test.cpp index aee453d83abb3..133c2d123dcbb 100644 --- a/tests/iteminfo_test.cpp +++ b/tests/iteminfo_test.cpp @@ -2695,7 +2695,7 @@ TEST_CASE( "item debug info", "[iteminfo][debug][!mayfail][.]" ) nuts.debug_info( info_vec, &debug_query, 1, true ); // FIXME: "last rot" and "last temp" are expected to be 0, but may have values (ex. 43200) - // Neex to figure out what processing to do before this check to make them predictable + // Need to figure out what processing to do before this check to make them predictable CHECK( format_item_info( info_vec, {} ) == "age (hours): 8\n" "charges: 4\n" diff --git a/tests/line_test.cpp b/tests/line_test.cpp index 742eee7936458..c4a34d5fb8822 100644 --- a/tests/line_test.cpp +++ b/tests/line_test.cpp @@ -131,9 +131,9 @@ TEST_CASE( "test_normalized_angle", "[line]" ) CHECK( get_normalized_angle( point_zero, {-10, -10} ) == Approx( 1.0 ) ); } +// NOLINTNEXTLINE(readability-function-size) TEST_CASE( "Test bounds for mapping x/y/z/ offsets to direction enum", "[line]" ) { - // Test the unit cube, which are the only values this function is valid for. REQUIRE( make_xyz_unit( tripoint( -1, -1, 1 ) ) == direction::ABOVENORTHWEST ); REQUIRE( make_xyz_unit( tripoint_north_west ) == direction::NORTHWEST ); diff --git a/tests/reload_magazine_test.cpp b/tests/reload_magazine_test.cpp index a598812d2397f..fa929364d170a 100644 --- a/tests/reload_magazine_test.cpp +++ b/tests/reload_magazine_test.cpp @@ -17,6 +17,7 @@ struct itype; +// NOLINTNEXTLINE(readability-function-size) TEST_CASE( "reload_magazine", "[magazine] [visitable] [item] [item_location]" ) { const itype_id gun_id( "nato_assault_rifle" ); diff --git a/tests/visitable_remove_test.cpp b/tests/visitable_remove_test.cpp index b8eae0f871eda..94ae2875ba185 100644 --- a/tests/visitable_remove_test.cpp +++ b/tests/visitable_remove_test.cpp @@ -37,6 +37,7 @@ static int count_items( const T &src, const itype_id &id ) return n; } +// NOLINTNEXTLINE(readability-function-size) TEST_CASE( "visitable_remove", "[visitable]" ) { const itype_id liquid_id( "water" ); From c3130fb0c1924d696c4f5b20de7628c061ce5e2f Mon Sep 17 00:00:00 2001 From: John Candlebury Date: Fri, 9 Apr 2021 16:09:33 -0600 Subject: [PATCH 357/453] Aftershock: Cold Suits (#48428) --- .../itemgroups/clothing/winter_outfits.json | 37 +++++ .../Aftershock/items/armor/winter_masks.json | 127 ++++++++++++++++++ .../Aftershock/items/armor/winter_suits.json | 126 +++++++++++++++++ .../maps/mapgen/astrobiology_lab.json | 6 +- .../formless_ruins_dynamic.json | 7 + data/mods/Aftershock/suit_operating_time.md | 106 +++++++++++++++ 6 files changed, 408 insertions(+), 1 deletion(-) create mode 100644 data/mods/Aftershock/itemgroups/clothing/winter_outfits.json create mode 100644 data/mods/Aftershock/items/armor/winter_masks.json create mode 100644 data/mods/Aftershock/items/armor/winter_suits.json create mode 100644 data/mods/Aftershock/suit_operating_time.md diff --git a/data/mods/Aftershock/itemgroups/clothing/winter_outfits.json b/data/mods/Aftershock/itemgroups/clothing/winter_outfits.json new file mode 100644 index 0000000000000..14dd3ca958376 --- /dev/null +++ b/data/mods/Aftershock/itemgroups/clothing/winter_outfits.json @@ -0,0 +1,37 @@ +[ + { + "//": "A group for any advanced civilian piece of clothing", + "id": "afs_wintersuit_civilian_advanced", + "type": "item_group", + "subtype": "distribution", + "items": [ { "group": "afs_wintersuit_science_advanced", "prob": 2 }, { "group": "afs_wintersuit_generic_advanced", "prob": 2 } ] + }, + { + "//": "A group for any generic-flavour advanced civilian piece of clothing", + "id": "afs_wintersuit_generic_advanced", + "type": "item_group", + "subtype": "distribution", + "items": [ { "group": "afs_frontier_cryo_g", "prob": 2 } ] + }, + { + "//": "A group for any science-flavour advanced civilian piece of clothing", + "id": "afs_wintersuit_science_advanced", + "type": "item_group", + "subtype": "distribution", + "items": [ { "group": "afs_magellan_g", "prob": 2 } ] + }, + { + "id": "afs_frontier_cryo_g", + "type": "item_group", + "//": "The matching frontier-cryosuit set. Includes suit, mask and possible future accessories", + "subtype": "collection", + "entries": [ { "item": "afs_frontier_cryo" }, { "item": "afs_frontier_cryomask", "prob": 90 } ] + }, + { + "id": "afs_magellan_g", + "type": "item_group", + "//": "The matching Magellan Exosuit set. Includes suit, mask and possible future accessories", + "subtype": "collection", + "entries": [ { "item": "afs_magellan_suit" }, { "item": "afs_magellan_suit_helmet", "prob": 90 } ] + } +] diff --git a/data/mods/Aftershock/items/armor/winter_masks.json b/data/mods/Aftershock/items/armor/winter_masks.json new file mode 100644 index 0000000000000..a10b724f8639f --- /dev/null +++ b/data/mods/Aftershock/items/armor/winter_masks.json @@ -0,0 +1,127 @@ +[ + { + "id": "afs_magellan_suit_helmet", + "repairs_like": "afs_magellan_suit", + "type": "TOOL_ARMOR", + "category": "armor", + "looks_like": "helmet_motor", + "name": { "str": "Magellan helmet CA." }, + "description": "The high quality helmet of a Magellan exosuit, adapted to handle the freezing but breathable air of Salus IV. In addition to its life support functionality, it features a minor augmented reality UI overlay and a retractable gold-plated visor to protect against glare and UV light. Although not armored as such, it's strong enough to handle minor blunt impacts.", + "weight": "2500 g", + "volume": "2250 ml", + "price": "750 USD", + "to_hit": -1, + "bashing": 7, + "material": [ "plastic", "nomex" ], + "symbol": "[", + "color": "dark_gray", + "ammo": "battery", + "charges_per_use": 1, + "use_action": { + "type": "transform", + "msg": "You activate your %s.", + "target": "afs_magellan_suit_helmet_on", + "active": true, + "need_charges": 1, + "need_charges_msg": "The %s's batteries are dead." + }, + "armor_portion_data": [ + { "covers": [ "head" ], "coverage": 100, "encumbrance": 25 }, + { "covers": [ "eyes" ], "coverage": 100, "encumbrance": 5 }, + { "covers": [ "mouth" ], "coverage": 100, "encumbrance": 15 } + ], + "pocket_data": [ { "pocket_type": "MAGAZINE", "rigid": true, "ammo_restriction": { "battery": 1000 } } ], + "warmth": 10, + "material_thickness": 6, + "environmental_protection": 1, + "flags": [ + "VARSIZE", + "WATERPROOF", + "RAINPROOF", + "STURDY", + "SUN_GLASSES", + "RAD_RESIST", + "OUTER", + "SWIM_GOGGLES", + "RECHARGE", + "NO_RELOAD", + "NO_UNLOAD" + ] + }, + { + "id": "afs_magellan_suit_helmet_on", + "copy-from": "afs_magellan_suit_helmet", + "repairs_like": "afs_magellan_suit", + "type": "TOOL_ARMOR", + "name": { "str": "Magellan helmet CA. (on)", "str_pl": "Magellan helmets CA. (on)" }, + "looks_like": "helmet_motor", + "description": "The temperature control units and augmented reality overlays of this high-tech garment are currently active, and continuously draining battery power. Use it to turn them off.", + "power_draw": 8170, + "warmth": 150, + "revert_to": "afs_magellan_suit_helmet", + "use_action": { "type": "transform", "menu_text": "Turn off", "msg": "Your %s deactivates.", "target": "afs_magellan_suit_helmet" }, + "extend": { + "flags": [ "CLIMATE_CONTROL", "GAS_PROOF", "WATCH", "ALARMCLOCK", "THERMOMETER", "HYGROMETER", "PARTIAL_DEAF", "TRADER_AVOID" ] + }, + "environmental_protection": 15 + }, + { + "id": "afs_frontier_cryomask", + "repairs_like": "nomex_hood", + "type": "TOOL_ARMOR", + "category": "armor", + "looks_like": "helmet_motor", + "name": { "str": "frontier cryomask" }, + "description": "A common, industrially printed respirator cleverly retrofitted into a wearable air heater. While it adequately protects against the cold, most of its original functions have been discarded and it offers no noticeable protection against noxious fumes or other environmental hazards.", + "weight": "2500 g", + "volume": "2250 ml", + "price": "750 USD", + "to_hit": -1, + "bashing": 7, + "material": [ "plastic", "nomex" ], + "symbol": "[", + "color": "dark_gray", + "charges_per_use": 1, + "ammo": "battery", + "use_action": { + "type": "transform", + "msg": "You activate your %s.", + "target": "afs_frontier_cryomask_on", + "active": true, + "need_charges": 1, + "need_charges_msg": "The %s's batteries are dead." + }, + "armor_portion_data": [ + { "covers": [ "eyes" ], "coverage": 100, "encumbrance": 15 }, + { "covers": [ "mouth" ], "coverage": 100, "encumbrance": 20 } + ], + "pocket_data": [ + { + "pocket_type": "MAGAZINE_WELL", + "holster": true, + "rigid": true, + "max_contains_volume": "20 L", + "max_contains_weight": "20 kg", + "item_restriction": [ "medium_battery_cell", "medium_plus_battery_cell", "medium_atomic_battery_cell", "medium_disposable_cell" ] + } + ], + "warmth": 5, + "material_thickness": 2, + "environmental_protection": 2, + "flags": [ "VARSIZE", "WATERPROOF", "RAINPROOF", "STURDY", "SUN_GLASSES", "OUTER" ] + }, + { + "id": "afs_frontier_cryomask_on", + "copy-from": "afs_frontier_cryomask", + "repairs_like": "afs_frontier_cryomask", + "type": "TOOL_ARMOR", + "name": { "str": "frontier cryomask (on)", "str_pl": "frontier cryomasks (on)" }, + "looks_like": "helmet_motor", + "description": "The heater of this high-tech garment is currently active, and continuously draining battery power. Use it to turn the heat off.", + "power_draw": 6944, + "warmth": 150, + "revert_to": "afs_frontier_cryomask", + "use_action": { "type": "transform", "menu_text": "Turn off", "msg": "Your %s deactivates.", "target": "afs_frontier_cryomask" }, + "extend": { "flags": [ "CLIMATE_CONTROL" ] } + } +] diff --git a/data/mods/Aftershock/items/armor/winter_suits.json b/data/mods/Aftershock/items/armor/winter_suits.json new file mode 100644 index 0000000000000..d8a607ba579dc --- /dev/null +++ b/data/mods/Aftershock/items/armor/winter_suits.json @@ -0,0 +1,126 @@ +[ + { + "id": "afs_magellan_suit", + "type": "TOOL_ARMOR", + "category": "armor", + "name": { "str": "Magellan exosuit" }, + "description": "A high-quality, civilian grade EVA suit often employed by well-established frontier research and exploration associations. Designed to support the exploration of challenging terrain, it offers respectable protection against common environmental hazards like extreme temperatures, inhospitable atmospheres, and light radiation. It leaves arms and hands relatively unencumbered to aid the manipulation of scientific instruments.\n\nAn integral battery allows the suit to operate for up to 34 hours, but complicates field recharging.", + "weight": "7800 g", + "volume": "14 L", + "price": "4 kUSD", + "material": [ "nomex", "steel" ], + "symbol": "[", + "looks_like": "robofac_enviro_suit", + "color": "light_gray", + "ammo": "battery", + "charges_per_use": 1, + "use_action": { + "type": "transform", + "msg": "You activate your %s.", + "target": "afs_magellan_suit_on", + "active": true, + "need_charges": 1, + "need_charges_msg": "The %s's batteries are dead." + }, + "armor_portion_data": [ + { "covers": [ "torso" ], "coverage": 100, "encumbrance": 25 }, + { "covers": [ "leg_l", "leg_r" ], "coverage": 100, "encumbrance": 25 }, + { "covers": [ "arm_l", "arm_r" ], "coverage": 100, "encumbrance": 15 }, + { "covers": [ "hand_l", "hand_r" ], "coverage": 100, "encumbrance": 10 }, + { "covers": [ "foot_l", "foot_r" ], "coverage": 100, "encumbrance": 15 } + ], + "pocket_data": [ { "pocket_type": "MAGAZINE", "rigid": true, "ammo_restriction": { "battery": 1000 } } ], + "warmth": 20, + "material_thickness": 2, + "valid_mods": [ "steel_padded" ], + "environmental_protection": 15, + "flags": [ + "VARSIZE", + "WATERPROOF", + "GAS_PROOF", + "POCKETS", + "RAINPROOF", + "STURDY", + "RAD_RESIST", + "RECHARGE", + "OUTER", + "NO_RELOAD", + "NO_UNLOAD" + ] + }, + { + "id": "afs_magellan_suit_on", + "copy-from": "afs_magellan_suit", + "repairs_like": "afs_magellan_suit", + "type": "TOOL_ARMOR", + "name": { "str": "Magellan exosuit (on)", "str_pl": "Magellan exosuits (on)" }, + "looks_like": "afs_cryopod_bodyglove", + "description": "The temperature control units of this high-tech garment are currently active, and continuously draining battery power. Use it to turn them off.", + "power_draw": 8170, + "warmth": 150, + "revert_to": "afs_magellan_suit", + "use_action": { "type": "transform", "menu_text": "Turn off", "msg": "Your %s deactivates.", "target": "afs_magellan_suit" }, + "extend": { "flags": [ "CLIMATE_CONTROL" ] } + }, + { + "id": "afs_frontier_cryo", + "type": "TOOL_ARMOR", + "category": "armor", + "name": { "str": "frontier cryo suit" }, + "description": "A sturdy suit meant to protect against the freezing cold, made from a pair of jumpsuits that have been woven around a heavy insulation layer and crisscrossed with the thermal tubing of a heat regulation unit. The thick insulation allows the suit to function with unrivaled efficiency, but also makes all types of movement difficult.", + "weight": "7800 g", + "volume": "14 L", + "price": "75 USD", + "material": [ "cotton", "plastic" ], + "symbol": "[", + "looks_like": "robofac_enviro_suit", + "color": "cyan", + "ammo": "battery", + "charges_per_use": 1, + "use_action": { + "type": "transform", + "msg": "You activate your %s.", + "target": "afs_frontier_cryo_on", + "active": true, + "need_charges": 1, + "need_charges_msg": "The %s's batteries are dead." + }, + "armor_portion_data": [ + { "covers": [ "head" ], "coverage": 100, "encumbrance": 5 }, + { "covers": [ "torso" ], "coverage": 100, "encumbrance": 35 }, + { "covers": [ "leg_l", "leg_r" ], "coverage": 100, "encumbrance": 25 }, + { "covers": [ "arm_l", "arm_r" ], "coverage": 100, "encumbrance": 25 }, + { "covers": [ "hand_l", "hand_r" ], "coverage": 100, "encumbrance": 25 }, + { "covers": [ "foot_l", "foot_r" ], "coverage": 100, "encumbrance": 15 } + ], + "pocket_data": [ + { + "pocket_type": "MAGAZINE_WELL", + "holster": true, + "rigid": true, + "max_contains_volume": "20 L", + "max_contains_weight": "20 kg", + "item_restriction": [ "medium_battery_cell", "medium_plus_battery_cell", "medium_atomic_battery_cell", "medium_disposable_cell" ] + } + ], + "warmth": 20, + "material_thickness": 4, + "valid_mods": [ "steel_padded" ], + "environmental_protection": 2, + "flags": [ "VARSIZE", "WATERPROOF", "POCKETS", "HELMET_COMPAT", "RAINPROOF", "STURDY", "OUTER" ] + }, + { + "id": "afs_frontier_cryo_on", + "copy-from": "afs_frontier_cryo", + "repairs_like": "afs_frontier_cryo", + "type": "TOOL_ARMOR", + "name": { "str": "frontier cryo suit (on)", "str_pl": "frontier cryo suits (on)" }, + "looks_like": "afs_cryopod_bodyglove", + "description": "The temperature control units of this high-tech garment are currently active, and continuously draining battery power. Use it to turn them off.", + "power_draw": 6944, + "warmth": 150, + "revert_to": "afs_frontier_cryo", + "use_action": { "type": "transform", "menu_text": "Turn off", "msg": "Your %s deactivates.", "target": "afs_frontier_cryo" }, + "extend": { "flags": [ "CLIMATE_CONTROL" ] } + } +] diff --git a/data/mods/Aftershock/maps/mapgen/astrobiology_lab.json b/data/mods/Aftershock/maps/mapgen/astrobiology_lab.json index 67d82df8cbc75..9beaf91e7e9fb 100644 --- a/data/mods/Aftershock/maps/mapgen/astrobiology_lab.json +++ b/data/mods/Aftershock/maps/mapgen/astrobiology_lab.json @@ -63,7 +63,11 @@ { "item": "supplies_reagents_lab", "chance": 70, "repeat": [ 2, 5 ] }, { "item": "supplies_xenoreagents_lab", "chance": 70, "repeat": [ 2, 5 ] } ], - "R": [ { "item": "decontamination_room", "chance": 60 }, { "item": "clothing_work_set", "chance": 30 } ], + "R": [ + { "item": "decontamination_room", "chance": 60 }, + { "item": "clothing_work_set", "chance": 30 }, + { "item": "afs_wintersuit_science_advanced", "chance": 30 } + ], "t": [ { "item": "office_paper", "chance": 60 }, { "item": "tools_science", "chance": 10, "repeat": [ 1, 2 ] } ] }, "item": { "c": { "item": "recipe_lichenlog", "chance": 6 } }, diff --git a/data/mods/Aftershock/maps/mapgen/formless_ruins/formless_ruins_dynamic.json b/data/mods/Aftershock/maps/mapgen/formless_ruins/formless_ruins_dynamic.json index 97449fe566d9a..7f6327ca83929 100644 --- a/data/mods/Aftershock/maps/mapgen/formless_ruins/formless_ruins_dynamic.json +++ b/data/mods/Aftershock/maps/mapgen/formless_ruins/formless_ruins_dynamic.json @@ -8,6 +8,12 @@ { "group": "afs_basic_material_scrapgroup", "prob": 20 } ] }, + { + "id": "afs_formless_ruins_random_suit", + "type": "item_group", + "subtype": "distribution", + "entries": [ { "group": "afs_wintersuit_civilian_advanced", "prob": 50 } ] + }, { "type": "mapgen", "method": "json", @@ -724,6 +730,7 @@ "///.. // " ], "terrain": { "C": "t_metal_floor", "s": "t_metal_floor" }, + "items": { "P": [ { "item": "afs_formless_ruins_random_suit", "chance": 80, "repeat": [ 1, 2 ] } ] }, "furniture": { "P": "f_sleep_pod", "s": "f_sink" }, "place_monsters": [ { "monster": "AFS_GROUP_MOXIE_LOW_RISK", "x": [ 0, 11 ], "y": [ 0, 11 ], "density": 0.1 } ], "palettes": [ "afs_formless_ruins" ] diff --git a/data/mods/Aftershock/suit_operating_time.md b/data/mods/Aftershock/suit_operating_time.md new file mode 100644 index 0000000000000..4a346e910efef --- /dev/null +++ b/data/mods/Aftershock/suit_operating_time.md @@ -0,0 +1,106 @@ +# Powered Armor Balance + +These are guidelines for designing all sorts of Aftershock power armor. + +## Operating time + +We define `operating time` as the amount of time the suit/gear-piece takes to consume 1000 charges of batteries. The following factors, totaled, determine how long the suit should work between battery swaps. + + +#### Additional factors + | Extra Hours | Condition | + |-----------------------|-------------------------------------------------------------------------| + | 4 hours | Base operating time. All suits work for at least 4 hours per full charge | + |-----------------------|-------------------------------------------------------------------------| + | 1hour per every 5 enc | Count only the most encumbered part | + | 1 hours | Less than 40 armor against all hazards | + | 1 hours | Less than 20 armor against all hazards | + | 6 hours | Less than 10 armor against all hazards | + | 2 hours | Has the fragile tag or is made from a very fragile material (ex: glass) | + | 4 hours | Less than 90% coverage of the most encumbered part | + | 4 hours | No protection against gases | + | 12 hours | No protection against the cold | + | 2 hours | No protection against other environmental factors (ex: acid, electricity, radiation) | + | 4 hours | Gear doesn't give passive bonuses to physical attributes (ex: dex or str) or skills (ex: athletics) and won't grant physical-based proficiencies| + | 4 hours | Doesn't grant any combat/movement related spells or enchantments | + | 4 hours | Gear doesn't give passive bonuses to mental attributes (per or int) or skills (ex: applied science) and won't grant knowledge based proficiencies | + | 1 hours | Doesn't grant any mental/knowledge related spells or enchantments | + | 2 hours | Has a non-swappable integral battery. | + | 2 hours | Won't grant night/heat-vision or clairvoyance effects. | + +Once you have determined the operating time using the table above, simply divide the number 277777.78 by the indicated number of hours to obtain your new suit's `power_draw` json value. + +For player convenience, the power draw and battery capacity of all clothing pieces that comprise a single matching outfit (e.g., the Magellan exosuit and its helmet) should be the same. + +#### Example Calculation + +Consider the Magellan exosuit, which has the following definition: +``` + { + "id": "afs_magellan_suit", + "type": "TOOL_ARMOR", + "category": "armor", + "name": { "str": "Magellan exosuit" }, + "description": "A high-quality, civilian grade EVA suit often employed by well-established frontier research and exploration associations. Designed to support the exploration of challenging terrain, it offers respectable protection against common environmental hazards like extreme temperatures, inhospitable atmospheres, and light radiation. It leaves arms and hands relatively unencumbered to aid the manipulation of scientific instruments.\n\nAn integral battery allows the suit to operate for up to 34 hours, but complicates field recharging.", + "weight": "7800 g", + "volume": "14 L", + "price": "4 kUSD", + "material": [ "nomex", "steel" ], + "symbol": "[", + "looks_like": "robofac_enviro_suit", + "color": "light_gray", + "ammo": "battery", + "charges_per_use": 1, + "use_action": { + "type": "transform", + "msg": "You activate your %s.", + "target": "afs_magellan_suit_on", + "active": true, + "need_charges": 1, + "need_charges_msg": "The %s's batteries are dead." + }, + "armor_portion_data": [ + { "covers": [ "torso" ], "coverage": 100, "encumbrance": 25 }, + { "covers": [ "leg_l", "leg_r" ], "coverage": 100, "encumbrance": 25 }, + { "covers": [ "arm_l", "arm_r" ], "coverage": 100, "encumbrance": 15 }, + { "covers": [ "hand_l", "hand_r" ], "coverage": 100, "encumbrance": 10 }, + { "covers": [ "foot_l", "foot_r" ], "coverage": 100, "encumbrance": 15 } + ], + "pocket_data": [ + { "pocket_type": "MAGAZINE", "rigid": true, "ammo_restriction": { "battery": 1000 } } + ], + "warmth": 20, + "material_thickness": 2, + "valid_mods": [ "steel_padded" ], + "environmental_protection": 15, + "flags": [ "VARSIZE", "WATERPROOF", "GAS_PROOF", "POCKETS", "RAINPROOF", "STURDY", "RAD_RESIST", "RECHARGE", "OUTER", "NO_RELOAD", "NO_UNLOAD" ] + }, + +``` +The active version provides no additional bonuses except for cold protection. + +Evaluating the performance time using the table above, the result should be: + +| Suit Qualifies | Extra Hours | Condition | +|----------------|-----------------------|-------------------------------------------------------------------------| +| yes | 4 hours | Base operating time. All suits work for at least 4 hours per full charge | +|----------------|-----------------------|-------------------------------------------------------------------------| +| yes | 5 hours | Count only the most encumbered part | +| yes | 1 hours | Less than 40 armor against all hazards | +| yes | 1 hours | Less than 20 armor against all hazards | +| yes | 6 hours | Less than 10 armor against all hazards | +| no | 2 hours | Has the fragile tag or is made from a very fragile material (ex: glass) | +| no | 4 hours | Less than 90% coverage of the most encumbered part | +| no | 4 hours | No protection against gases | +| no | 12 hours | No protection against the cold | +| no | 2 hours | No protection against other environmental factors (ex: acid, electricity, radiation) | +| yes | 4 hours |Gear doesn't give passive bonuses to physical attributes (ex: dex or str) or skills (ex: athletics) and won't grant physical-based proficiencies| +| yes | 4 hours | Doesn't grant any combat/movement related spells or enchantments | +| yes | 4 hours | Gear doesn't give passive bonuses to mental attributes (per or int) or skills (ex: applied science) and won't grant knowledge based proficiencies | +| yes | 1 hours | Doesn't grant any mental/knowledge related spells or enchantments | +| yes | 2 hours | Has a non-swappable integral battery. | +| yes | 2 hours | Won't grant night/heat-vision or clairvoyance effects, | +|----------------|-----------------------|-------------------------------------------------------------------------| +| Total hours | 34 hours | | + +Due to the fulfilled conditions, the suit should operate for 34 hours when connected to a 1000 charge battery. To calculate its final `power_draw` value, we divide 277777.78 by 34 to obtain a `power_draw` of 8170. \ No newline at end of file From 81c04e370a9b375976d0a621e0a35a63905c20ce Mon Sep 17 00:00:00 2001 From: slitherrr Date: Thu, 8 Apr 2021 23:01:13 +0000 Subject: [PATCH 358/453] Fix some dialog in refugee trees Add an escape for the Jenny Forcette training tree to prevent an unescapable loop when the avatar is too skilled, and also add a bit of prologue to Boris's ask for the Ash's Laptop quest. --- .../surface_refugees/NPC_Boris_Borichenko.json | 2 +- .../refugee_center/surface_refugees/NPC_Jenny_Forcette.json | 5 ++++- 2 files changed, 5 insertions(+), 2 deletions(-) diff --git a/data/json/npcs/refugee_center/surface_refugees/NPC_Boris_Borichenko.json b/data/json/npcs/refugee_center/surface_refugees/NPC_Boris_Borichenko.json index c0b5d6d9fe7fe..c6a8eeb3109ca 100644 --- a/data/json/npcs/refugee_center/surface_refugees/NPC_Boris_Borichenko.json +++ b/data/json/npcs/refugee_center/surface_refugees/NPC_Boris_Borichenko.json @@ -480,7 +480,7 @@ }, "dialogue": { "describe": "Find Boris' son's laptop.", - "offer": "If you can find it, it would mean so much to me. I will give you directions to the shelter where he left it. It was barely a shelter, broken and torn apart. It should just be on the floor where it was dropped.", + "offer": "My son, Ash, had a laptop on which he kept his writing. If you can find it, it would mean so much to me. I will give you directions to the shelter where he left it. It was barely a shelter, broken and torn apart. It should just be on the floor where it was dropped.", "accepted": "You are a kind soul.", "rejected": "Ah well. I can ask around myself, perhaps.", "advice": "You can tell it is his because he covered it in stickers.", diff --git a/data/json/npcs/refugee_center/surface_refugees/NPC_Jenny_Forcette.json b/data/json/npcs/refugee_center/surface_refugees/NPC_Jenny_Forcette.json index a842d449da979..92126eb22009f 100644 --- a/data/json/npcs/refugee_center/surface_refugees/NPC_Jenny_Forcette.json +++ b/data/json/npcs/refugee_center/surface_refugees/NPC_Jenny_Forcette.json @@ -255,7 +255,10 @@ "id": "TALK_REFUGEE_JENNY_Teach2", "dynamic_line": "All right, fine. Grab some tools and do as I tell you.", "speaker_effect": { "effect": { "npc_add_var": "Jenny_teach", "type": "timer", "context": "flag", "time": true } }, - "responses": [ { "text": "Just say the word, teach.", "topic": "TALK_TRAIN" } ] + "responses": [ + { "text": "Just say the word, teach.", "topic": "TALK_TRAIN" }, + { "text": "Actually, I'd better get going. Let's do this later.", "topic": "TALK_DONE" } + ] }, { "type": "talk_topic", From 395b8d4cad4e82fd6523026d087a760dae04c329 Mon Sep 17 00:00:00 2001 From: MitztheKat Date: Fri, 9 Apr 2021 18:15:42 -0400 Subject: [PATCH 359/453] Clarify Wood Saw's log-to-plank ability in its description (#48444) --- data/json/items/tool/woodworking.json | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/data/json/items/tool/woodworking.json b/data/json/items/tool/woodworking.json index 2409520ec0195..6343db479c51c 100644 --- a/data/json/items/tool/woodworking.json +++ b/data/json/items/tool/woodworking.json @@ -262,7 +262,7 @@ "id": "saw", "type": "TOOL", "name": { "str": "wood saw" }, - "description": "This is a thin saw, useful for cutting through wood objects.", + "description": "This is a thin saw, useful for cutting through wood objects. Can turn pre-cut logs into planks by activation.", "weight": "283 g", "volume": "1 L", "longest_side": "46 cm", From 10414a9297f77c36c944c885439e10c6caa10b7d Mon Sep 17 00:00:00 2001 From: ephemeralstoryteller Date: Sat, 10 Apr 2021 03:20:07 -0400 Subject: [PATCH 360/453] [Dark Skies] Lore and JSON Cleanup, Blacklists Mutant Wildlife (#48448) --- data/mods/Dark-Skies-Above/mondrops.json | 90 ------- .../Dark-Skies-Above/overrides/monsters.json | 113 +++++--- .../overrides/professions.json | 247 ++++++++++++++++++ .../Dark-Skies-Above/overrides/scenarios.json | 2 +- .../speech/neworder_speech.json | 24 -- 5 files changed, 330 insertions(+), 146 deletions(-) delete mode 100644 data/mods/Dark-Skies-Above/mondrops.json create mode 100644 data/mods/Dark-Skies-Above/overrides/professions.json diff --git a/data/mods/Dark-Skies-Above/mondrops.json b/data/mods/Dark-Skies-Above/mondrops.json deleted file mode 100644 index c1a8683142ee4..0000000000000 --- a/data/mods/Dark-Skies-Above/mondrops.json +++ /dev/null @@ -1,90 +0,0 @@ -[ - { - "id": "dks_mon_neworder_scout", - "type": "item_group", - "subtype": "collection", - "magazine": 100, - "ammo": 40, - "entries": [ - { "group": "underwear", "damage": [ 0, 1 ] }, - { "item": "dks_neworder_armor_salvaged", "damage": [ 1, 3 ] }, - { "item": "machete" }, - { "group": "clothing_watch", "prob": 20 }, - { "item": "knife_combat", "container-item": "sheath", "prob": 40 }, - { "item": "cash_card", "prob": 20, "charges-min": 0, "charges-max": 50000 }, - { "group": "dks_scout_extras", "prob": 60 } - ] - }, - { - "id": "dks_mon_neworder_cop", - "type": "item_group", - "subtype": "collection", - "magazine": 100, - "ammo": 40, - "entries": [ - { "group": "underwear", "damage": [ 0, 1 ] }, - { "item": "dks_neworder_armor_salvaged", "damage": [ 1, 3 ] }, - { "item": "shocktonfa_off", "charges-min": 10, "charges-max": 1198 }, - { "group": "clothing_watch", "prob": 20 }, - { "item": "dks_riotshield" }, - { "item": "cash_card", "prob": 20, "charges-min": 0, "charges-max": 50000 }, - { "group": "dks_cop_extras", "prob": 60, "count": [ 0, 2 ] } - ] - }, - { - "id": "dks_mon_neworder_pyro", - "type": "item_group", - "subtype": "collection", - "magazine": 100, - "ammo": 40, - "entries": [ - { "group": "underwear", "damage": [ 0, 1 ] }, - { "item": "dks_neworder_armor_salvaged", "damage": [ 1, 3 ] }, - { "group": "clothing_watch", "prob": 20 }, - { "item": "dks_flamesword_salvaged" }, - { "item": "cash_card", "prob": 20, "charges": [ 0, 50000 ] }, - { "group": "dks_knight_extras", "prob": 50, "count": [ 0, 2 ] } - ] - }, - { - "id": "dks_mon_neworder_knight", - "type": "item_group", - "subtype": "collection", - "magazine": 100, - "ammo": 40, - "entries": [ - { "group": "underwear", "damage": [ 0, 1 ] }, - { "item": "dks_neworder_armor_salvaged", "damage": [ 1, 3 ] }, - { "group": "clothing_watch", "prob": 20 }, - { "item": "dks_knightsword_salvaged" }, - { "item": "dks_battleshield" }, - { "item": "cash_card", "prob": 20, "charges": [ 0, 50000 ] }, - { "group": "dks_knight_extras", "prob": 50, "count": [ 0, 2 ] } - ] - }, - { - "id": "dks_cop_extras", - "type": "item_group", - "items": [ - { "group": "full_1st_aid", "prob": 25 }, - { "item": "legrig", "prob": 10 }, - { "item": "dump_pouch", "prob": 10 }, - { "item": "medium_disposable_cell", "prob": 30 } - ] - }, - { - "id": "dks_scout_extras", - "type": "item_group", - "items": [ - { "group": "full_1st_aid", "prob": 25 }, - { "item": "legrig", "prob": 10 }, - { "item": "dump_pouch", "prob": 10 }, - { "item": "binoculars", "prob": 30 } - ] - }, - { - "id": "dks_knight_extras", - "type": "item_group", - "items": [ { "item": "1st_aid", "prob": 25 }, { "item": "legrig", "prob": 10 }, { "item": "dump_pouch", "prob": 10 } ] - } -] diff --git a/data/mods/Dark-Skies-Above/overrides/monsters.json b/data/mods/Dark-Skies-Above/overrides/monsters.json index ea7a618811662..b0278f7d84b82 100644 --- a/data/mods/Dark-Skies-Above/overrides/monsters.json +++ b/data/mods/Dark-Skies-Above/overrides/monsters.json @@ -1,56 +1,107 @@ [ { - "id": "mon_c4_hack", - "copy-from": "mon_c4_hack", + "id": "mon_rattlesnake_giant", + "copy-from": "mon_rattlesnake_giant", "type": "MONSTER", - "name": { "str": "C-4 hack" }, - "extend": { "categories": [ "ALIEN" ] }, - "description": "An automated kamikaze drone, this small flying robot appears to have some C-4 inside." + "name": "giant rattlesnake", + "delete": { "categories": [ "WILDLIFE" ] } }, { - "id": "mon_flashbang_hack", - "copy-from": "mon_flashbang_hack", + "id": "mon_nakedmolerat_giant", + "copy-from": "mon_nakedmolerat_giant", "type": "MONSTER", - "name": { "str": "flashbang hack" }, - "extend": { "categories": [ "ALIEN" ] }, - "description": "An automated kamikaze drone, this small flying robot appears to have a flashbang inside." + "name": "gigantic naked mole-rat", + "delete": { "categories": [ "WILDLIFE" ] } }, { - "id": "mon_gasbomb_hack", - "copy-from": "mon_gasbomb_hack", + "id": "mon_crow_mutant_small", + "copy-from": "mon_crow_mutant_small", "type": "MONSTER", - "name": { "str": "tear gas hack" }, - "extend": { "categories": [ "ALIEN" ] }, - "description": "An automated kamikaze drone, this small flying robot appears to have a tear gas canister inside." + "name": { "str": "oversized crow" }, + "delete": { "categories": [ "WILDLIFE" ] } }, { - "id": "mon_grenade_hack", - "copy-from": "mon_grenade_hack", + "id": "mon_cockatrice", + "copy-from": "mon_cockatrice", "type": "MONSTER", - "name": { "str": "grenade hack" }, - "extend": { "categories": [ "ALIEN" ] }, - "description": "An automated kamikaze drone, this small flying robot appears to have a grenade inside." + "name": { "str": "cockatrice" }, + "delete": { "categories": [ "WILDLIFE" ] } }, { - "id": "mon_manhack", - "copy-from": "mon_manhack", + "id": "mon_bear_mutant_3headed", "type": "MONSTER", - "name": { "str": "manhack" }, - "extend": { "categories": [ "ALIEN" ] }, - "description": "An automated anti-personnel drone, a small flying robot surrounded by whirring blades." + "name": { "str": "Cerbearus", "str_pl": "Cerberuses" }, + "copy-from": "mon_bear_mutant_3headed", + "delete": { "categories": [ "WILDLIFE" ] } }, { - "id": "mon_rattlesnake_giant", - "copy-from": "mon_rattlesnake_giant", + "id": "mon_beaver_mutant_huge", "type": "MONSTER", - "name": "giant rattlesnake", + "name": { "str": "dambreaker" }, + "copy-from": "mon_beaver_mutant_huge", "delete": { "categories": [ "WILDLIFE" ] } }, { - "id": "mon_nakedmolerat_giant", - "copy-from": "mon_nakedmolerat_giant", + "id": "mon_beaver_mutant_avian", "type": "MONSTER", - "name": "gigantic naked mole-rat", + "name": { "str": "feaver" }, + "copy-from": "mon_beaver_mutant_avian", + "delete": { "categories": [ "WILDLIFE" ] } + }, + { + "id": "mon_cat_mutant_prism", + "type": "MONSTER", + "name": { "str": "iridescent cat" }, + "copy-from": "mon_cat_mutant_prism", + "delete": { "categories": [ "WILDLIFE" ] } + }, + { + "id": "mon_cat_mutant_kitten_prism", + "type": "MONSTER", + "name": { "str": "iridescent kitten" }, + "copy-from": "mon_cat_mutant_kitten_prism", + "delete": { "categories": [ "WILDLIFE" ] } + }, + { + "id": "mon_coyote_mutant_shark", + "type": "MONSTER", + "name": { "str": "grinning coyote" }, + "copy-from": "mon_coyote_mutant_shark", + "delete": { "categories": [ "WILDLIFE" ] } + }, + { + "id": "mon_coyote_mutant_venom", + "type": "MONSTER", + "name": { "str": "slavering coyote" }, + "copy-from": "mon_coyote_mutant_venom", + "delete": { "categories": [ "WILDLIFE" ] } + }, + { + "id": "mon_wolf_mutant_huge", + "type": "MONSTER", + "name": { "str": "dire wolf" }, + "copy-from": "mon_wolf_mutant_huge", + "delete": { "categories": [ "WILDLIFE" ] } + }, + { + "id": "mon_deer_mutant_spider", + "type": "MONSTER", + "name": { "str": "spideer" }, + "copy-from": "mon_deer_mutant_spider", + "delete": { "categories": [ "WILDLIFE" ] } + }, + { + "id": "mon_deer_mutant_spider_fawn", + "type": "MONSTER", + "name": { "str": "spideer fawn" }, + "copy-from": "mon_deer_mutant_spider_fawn", + "delete": { "categories": [ "WILDLIFE" ] } + }, + { + "id": "mon_dog_mutant_mongrel", + "type": "MONSTER", + "name": { "str": "mongrel" }, + "copy-from": "mon_dog_mutant_mongrel", "delete": { "categories": [ "WILDLIFE" ] } } ] diff --git a/data/mods/Dark-Skies-Above/overrides/professions.json b/data/mods/Dark-Skies-Above/overrides/professions.json new file mode 100644 index 0000000000000..69bc3430511fa --- /dev/null +++ b/data/mods/Dark-Skies-Above/overrides/professions.json @@ -0,0 +1,247 @@ +[ + { + "type": "profession", + "id": "heroin_addict", + "copy-from": "heroin_addict", + "name": "Heroin Addict", + "description": "The last thing you remember was meeting God behind the local Foodplace. Then the skies opened up and fire rained forth. This doesn't feel like a fever dream." + }, + { + "type": "profession", + "id": "pillhead", + "copy-from": "pillhead", + "name": "Heroin Addict", + "description": "After an accident in your youth, you got addicted to the opiates treating your pain. With the pharmacies shut down and your dealers started growing crystals, satisfying those cravings just got a lot more difficult." + }, + { + "type": "profession", + "id": "naked", + "copy-from": "naked", + "name": "Naked and Afraid", + "description": "You were out filming a reality TV show, naked in the woods. The cast and crew fled when the aliens came, which is pretty bad timing for you. Looks like it's for real this time…" + }, + { + "type": "profession", + "id": "lumberjack", + "copy-from": "lumberjack", + "name": "Lumberjack", + "description": "You're a lumberjack, and you're okay. You felled trees before the world ended, but suspect those crystal ghouls aren't nearly as tough." + }, + { + "type": "profession", + "id": "dancer", + "copy-from": "dancer", + "name": "Ballroom Dancer", + "description": "Things got a little weird on your way to your weekly dance class. Aliens don't seem to know how to dance, but you're not about to let them step on your toes." + }, + { + "type": "profession", + "id": "skaboy", + "copy-from": "skaboy", + "name": { "male": "Rude Boy", "female": "Rude Girl" }, + "description": "Your ska band broke up after the drummer got vaporized. Now you're alone in the Cataclysm with some cigarettes and your mp3 player." + }, + { + "type": "profession", + "id": "imam", + "copy-from": "imam", + "name": { "male": "Imam", "female": "Mourchida" }, + "description": "You spent much of your time prior to the apocalypse at the local mosque, studying the words of the Prophet and the Quran and guiding your community in prayer. Back then they came from far and wide to listen to you; now they come to tear you apart." + }, + { + "type": "profession", + "id": "teacher", + "copy-from": "teacher", + "name": "Teacher", + "description": "You've been teaching kids all your life, experiencing the joy and aggravation of imparting knowledge to young minds. If aliens have any interest in education, they're not showing it." + }, + { + "type": "profession", + "id": "groundskeeper", + "copy-from": "groundskeeper", + "name": "Landscaper", + "description": "You used to mow lawns and trim hedges for the wealthy. Contract work was getting scarce even before the aliens came, but now you've got nothing left except your tools and expertise." + }, + { + "type": "profession", + "id": "homemaker", + "copy-from": "homemaker", + "name": "Nursing Assistant", + "description": "You went on providing in-home care for the elderly even as the whole world fell apart around you. You can only pray that you don't see your former clients among those crystal things…" + }, + { + "type": "profession", + "id": "cosplay", + "copy-from": "cosplay", + "name": "Otaku", + "description": "After many late nights with friends watching anime and eating snacks, you decided to make the trip to the premier anime convention in the Northeast. Now aliens are killing everyone, and even worse, the convention is cancelled! At least you were ready in case your costume tore." + }, + { + "type": "profession", + "id": "lawyer", + "copy-from": "lawyer", + "name": "Lawyer", + "description": "The jury were in the palm of your hand, but after the aliens started invading, you were forced to flee the courtroom in disgrace. Now nobody seems to care about your objections." + }, + { + "type": "profession", + "id": "pizzaboy", + "copy-from": "pizzaboy", + "name": { "male": "Pizza Delivery Boy", "female": "Pizza Delivery Girl" }, + "description": "You were delivering the last pizza of the night to the local cryogenics lab when hungry aliens attempted to make a meal out of you. Fleeing for safety, you find yourself with only your wits and some leftover pizza. And they didn't even leave a tip!" + }, + { + "type": "profession", + "id": "relief_volunteer", + "copy-from": "relief_volunteer", + "name": "Relief Volunteer", + "description": "You were a member of a non-profit organization dedicated to helping out where help was needed. When the storms picked up and the first bombs dropped, you were eager to lend a hand. But you had to cut your plans short when the aliens arrived: they seem less interested in handouts, and more interested in eating you." + }, + { + "type": "profession", + "id": "guru", + "copy-from": "guru", + "name": "Guru", + "description": "You spent many years traveling through the world, becoming wise and learned. Normally, you can answer any question, but even you are not quite sure what to do about the ravenous aliens." + }, + { + "type": "profession", + "id": "preacher", + "copy-from": "preacher", + "name": "Preacher", + "description": "You devoted your life to spreading the good word, always on the road, traveling from town to town. Now everything has gone to hell, you can't host your daily podcast, and the aliens don't seem particularly moved by your sermons." + }, + { + "type": "profession", + "id": "rollerderby", + "copy-from": "rollerderby", + "name": "Roller Derby Player", + "description": "You were hell on wheels. Now the rest of your team is dead, and you probably wouldn't have lived this long if not for your penchant for high-speed violence. Things are looking grim; how long can you race laps around the aliens before you get blocked for good?" + }, + { + "type": "profession", + "id": "game_master", + "copy-from": "game_master", + "name": "Game Master", + "description": "Trying to herd cats into meeting up every week has taught you something: it's usually better to cut your losses and trust your gut. For that reason, when you had two no-shows and the other two got eaten, you ditched. Maybe you can find some new players in the ruins of the world." + }, + { + "type": "profession", + "id": "frat", + "copy-from": "frat", + "name": { "male": "Frat Boy", "female": "Sorority Girl" }, + "description": "You were living the high life, spending your parents' money without a care in the world. At one of your usual crazy parties, a bomb landed right in the hot tub, but you still have a chance to use the last symbol of your luxurious life - your sports car - and get far away." + }, + { + "type": "profession", + "id": "labtech", + "copy-from": "labtech", + "name": "Lab Technician", + "description": "Thanks to years of study and hard work in the lab, you're familiar with the basics of scientific inquiry. Only one question remains: can you avoid getting experimented on in return?" + }, + { + "type": "profession", + "id": "paperboy", + "copy-from": "paperboy", + "name": { "male": "Paperboy", "female": "Papergirl" }, + "description": "You set out this morning to deliver the news of the apocalypse. The aliens don't seem to value the latest news, but at least your trusty bicycle is still in working order." + }, + { + "type": "profession", + "id": "labtech", + "copy-from": "labtech", + "name": "Lab Technician", + "description": "Thanks to years of study and hard work in the lab, you're familiar with the basics of scientific inquiry. Only one question remains: can you avoid getting experimented on in return?" + }, + { + "type": "profession", + "id": "national_guard", + "copy-from": "national_guard", + "name": "National Guard", + "description": "The government activated your National Guard unit to deal with the growing storms and the following bombings. Despite your best efforts, you were unable to form up before all communications ceased and you found yourself alone amongst the enemy." + }, + { + "type": "profession", + "id": "gym_teacher", + "copy-from": "gym_teacher", + "name": "Gym Teacher", + "description": "It was hard enough getting kids to run laps without having to worry about doing it in a warzone. Aliens won't even line up when you blow your whistle." + }, + { + "type": "profession", + "id": "major-general", + "copy-from": "major-general", + "name": "Major General", + "description": "You worked your way up through the ranks, from a no-name private, to a big shot Major General. Now however, it is years since you last fired a weapon in anger, and you've somehow ended up deep behind enemy lines." + }, + { + "type": "profession", + "id": "recruit", + "copy-from": "recruit", + "name": "Military Recruit", + "description": "Joining the military has been your dream for years. You finally got in, just in time for your training to get interrupted by some sort of national emergency. After a hot deployment, as far as you can tell you're one of the last active personnel in this hellhole." + }, + { + "type": "profession", + "id": "combat-mechanic", + "copy-from": "combat-mechanic", + "name": "Combat Mechanic", + "description": "You failed out of high school, and joined the army. You were soon hand picked for extra training in the mechanics trade, keeping the armour running. It's been years since you last touched a rifle, and now the sky is falling…" + }, + { + "type": "profession", + "id": "riot_police", + "copy-from": "riot_police", + "name": "Riot Control Officer", + "description": "You were keeping the peace at a local climate change protest when the bombs started dropping and aliens started appearing in the streets. It was only by luck that you manage to survive the crowd in one piece, and the worst is yet to come." + }, + { + "type": "profession", + "id": "trucker", + "copy-from": "trucker", + "name": "Trucker", + "description": "You once ruled the road in your big rig. When the bombs hit, you hopped in and drove it to safety. Now it's just you and your truck against the world." + }, + { + "type": "profession", + "id": "fencer", + "copy-from": "fencer", + "name": "Competitive Fencer", + "description": "Years of training prepared you for the competitive fencing circuit, but your latest tournament was cut short when aliens invaded the piste. The referee was blown away, so you're not sure if the rules are still in play." + }, + { + "type": "profession", + "id": "politician", + "copy-from": "politician", + "name": "Career Politician", + "description": "You've spent your life appealing to the people, persuading many and promising much throughout your time in office. Now that your voting base is dead or worse and hostile forces are in America's heartland, winning hearts and minds just got that much harder." + }, + { + "type": "profession", + "id": "hazmat_unit", + "copy-from": "hazmat_unit", + "name": "Hazmat Unit", + "description": "You were deployed to autopsy one of the aliens after it was put down. When their friends showed up in force, you knew this was out of your job description." + }, + { + "type": "profession", + "id": "mili_burner", + "copy-from": "mili_burner", + "name": "Military Flamethrower Operator", + "description": "In response to the outbreak, you were dispatched to contain alien invasive species through judicious use of fire. After getting separated from your squad, your priorities have shifted to basic survival." + }, + { + "type": "profession", + "id": "nco", + "copy-from": "nco", + "name": "Non Commissioned Officer", + "description": "You're a veteran of several peace keeping missions. You lead your squad as a sort of parental figure, offering helpful advice on how not to die. Now they've been blasted to pieces by the alien and you're on your own." + }, + { + "type": "profession", + "id": "specops", + "copy-from": "specops", + "name": "Special Operator", + "description": "You were the best of the best, the military's finest. That's why you're still alive, even after all your comrades fell to the aliens. As far as you can tell, you're one of the last active operators in this hellhole." + } +] diff --git a/data/mods/Dark-Skies-Above/overrides/scenarios.json b/data/mods/Dark-Skies-Above/overrides/scenarios.json index 423e9a3fa875a..eb1ae0331df40 100644 --- a/data/mods/Dark-Skies-Above/overrides/scenarios.json +++ b/data/mods/Dark-Skies-Above/overrides/scenarios.json @@ -5,7 +5,7 @@ "copy-from": "evacuee", "allowed_locs": [ "sloc_dks_shelter" ], "name": "Evacuee", - "description": "You have survived the initial wave of panic and managed to avoid being taken to the Designated Living Zones. You begin in the (relative) safety in one of the many government evac shelters.", + "description": "You have survived the initial wave of panic and managed to escape to (relative) safety in one of the many government evac shelters.", "blacklist_professions": true, "professions": [ "churl" ] }, diff --git a/data/mods/Dark-Skies-Above/speech/neworder_speech.json b/data/mods/Dark-Skies-Above/speech/neworder_speech.json index 09bfd1ac33562..3e9d576765f43 100644 --- a/data/mods/Dark-Skies-Above/speech/neworder_speech.json +++ b/data/mods/Dark-Skies-Above/speech/neworder_speech.json @@ -1,28 +1,4 @@ [ - { - "type": "speech", - "speaker": [ "dks_neworder_scout", "dks_neworder_pyro", "dks_neworder_cop", "dks_neworder_knight" ], - "sound": "unintelligble radio chatter.", - "volume": 20 - }, - { - "type": "speech", - "speaker": [ "dks_neworder_scout", "dks_neworder_pyro", "dks_neworder_cop", "dks_neworder_knight" ], - "sound": "unintelligble radio chatter.", - "volume": 20 - }, - { - "type": "speech", - "speaker": [ "dks_neworder_scout", "dks_neworder_pyro", "dks_neworder_cop", "dks_neworder_knight" ], - "sound": "unintelligble radio chatter, followed by a response.", - "volume": 25 - }, - { - "type": "speech", - "speaker": [ "dks_neworder_scout", "dks_neworder_pyro", "dks_neworder_cop", "dks_neworder_knight" ], - "sound": "unintelligble radio chatter.", - "volume": 20 - }, { "type": "speech", "speaker": [ "mon_dks_emissary", "mon_dks_emissary_war", "mon_dks_emissary_flame" ], From 020938a86375cef1837e66e0190a59640248f756 Mon Sep 17 00:00:00 2001 From: ephemeralstoryteller Date: Sat, 10 Apr 2021 03:21:35 -0400 Subject: [PATCH 361/453] [Dark Skies] Adds ballistic armor to aliens (#48446) --- .../Dark-Skies-Above/monsters/alien_cyborgs.json | 12 ++++++++---- .../mods/Dark-Skies-Above/monsters/alien_robots.json | 6 ++++-- 2 files changed, 12 insertions(+), 6 deletions(-) diff --git a/data/mods/Dark-Skies-Above/monsters/alien_cyborgs.json b/data/mods/Dark-Skies-Above/monsters/alien_cyborgs.json index 6305f45b6b940..c4c5f5c7f78c1 100644 --- a/data/mods/Dark-Skies-Above/monsters/alien_cyborgs.json +++ b/data/mods/Dark-Skies-Above/monsters/alien_cyborgs.json @@ -24,6 +24,7 @@ "melee_cut": 2, "armor_bash": 90, "armor_cut": 90, + "armor_bullet": 100, "armor_acid": 10, "path_settings": { "max_dist": 30 }, "death_drops": { "groups": [ [ "robots", 4 ], [ "eyebot", 1 ], [ "turret_searchlight", 1 ] ] }, @@ -93,6 +94,7 @@ "melee_cut": 2, "armor_bash": 90, "armor_cut": 90, + "armor_bullet": 100, "armor_acid": 10, "path_settings": { "max_dist": 30 }, "emit_fields": [ { "emit_id": "emit_toxic_leak", "delay": "1 s" } ], @@ -161,6 +163,7 @@ "melee_cut": 2, "armor_bash": 90, "armor_cut": 90, + "armor_bullet": 100, "armor_acid": 10, "path_settings": { "max_dist": 30 }, "death_drops": { "groups": [ [ "robots", 4 ], [ "eyebot", 1 ], [ "turret_searchlight", 1 ] ] }, @@ -207,7 +210,7 @@ "id": "dks_mon_lurker_rectified", "type": "MONSTER", "name": { "str": "recycler" }, - "description": "A sleek mass of hairy tentacles originate from a metallic core that looks like a mix between a garbage disposal and a clamp, golden pinpoints of dim light dotting its chassis. It seems adept at collecting small pieces of junk and debris and mulching them in its mouth for unknown purposes - you included.", + "description": "A sleek mass of hairy tentacles originate from a metallic core that looks like a mix between a garbage disposal and a clamp, golden pinpoints of dim light dotting its chassis. It seems adept at collecting small pieces of junk and debris to mulch them into their bae parts - you included.", "default_faction": "invader_alien", "bodytype": "spider", "categories": [ "ALIEN" ], @@ -248,7 +251,7 @@ "id": "dks_mon_bileworm_rectified", "type": "MONSTER", "name": { "str": "tunneler" }, - "description": "A huge creature, encased in metal plating and covered in small golden \"eyes\". Stocky robotic appendages covering its body allow it to smash through rock and propel itself forward with efficiency. Its interior seems to have been replaced by some sort of whirring processing equipment that would be highly unpleasant to be caught up in. Fortunately it doesn't seem very hostile.", + "description": "A huge creature, encased in metal plating and covered in small golden \"eyes\". Stocky robotic appendages covering its body allow it to smash through rock and propel itself forward with efficiency. Its interior seems to have been replaced by some sort of whirring processing equipment that would be highly unpleasant to be caught up in. Fortunately it doesn't seem immediately interested in you.", "looks_like": "mon_worm", "default_faction": "invader_alien", "bodytype": "snake", @@ -266,8 +269,9 @@ "melee_skill": 4, "melee_dice": 4, "melee_dice_sides": 6, - "armor_bash": 4, - "armor_cut": 2, + "armor_bash": 12, + "armor_cut": 6, + "armor_bullet": 6, "vision_night": 15, "harvest": "mutant_meatslug", "special_attacks": [ diff --git a/data/mods/Dark-Skies-Above/monsters/alien_robots.json b/data/mods/Dark-Skies-Above/monsters/alien_robots.json index 7dab18c2aebfc..625d40bb98338 100644 --- a/data/mods/Dark-Skies-Above/monsters/alien_robots.json +++ b/data/mods/Dark-Skies-Above/monsters/alien_robots.json @@ -3,7 +3,7 @@ "id": "mon_dks_glowdrone", "type": "MONSTER", "name": { "str": "alien surveillance drone" }, - "description": "A small, sleek, white-plated robot bearing a golden insignia. Capable of limited flight, it hovers about the ruins of the former world, on-board cameras and spotlights impartial witness to the chaos around it. Who knows what might be watching on the other side…", + "description": "A small, sleek, white-plated robot bearing a golden insignia that is capable of limited flight. It hovers about the ruins of the former world, onboard cameras and spotlights impartial witness to the chaos around it. Who knows might be watching on the other side…", "default_faction": "invader_alien", "looks_like": "mon_eyebot", "categories": [ "ALIEN" ], @@ -18,6 +18,7 @@ "dodge": 3, "armor_bash": 8, "armor_cut": 10, + "armor_bullet": 6, "luminance": 5, "special_attacks": [ [ "SEARCHLIGHT", 1 ] ], "path_settings": { "max_dist": 5 }, @@ -29,7 +30,7 @@ "id": "mon_dks_scidrone", "type": "MONSTER", "name": { "str": "alien seeker drone" }, - "description": "A small, sleek, white-plated robot bearing a golden insignia. Capable of limited flight, it hovers about the ruins of the former world, using a suite of rather sharp looking retractable tools, a bright camera flash, and integrated 'arms' to manipulate the world around it with surprising dexterity and procure samples. It seems to watch you closely once it catches sight of you…", + "description": "A small, sleek, white-plated robot bearing a golden insignia that is capable of limited flight. It hovers about the ruins of the former world, using a suite of sharp retractable tools, a bright camera flash, and integrated 'arms' to manipulate the world around it. It seems to watch its subjects closely…", "default_faction": "invader_alien", "looks_like": "mon_eyebot", "categories": [ "ALIEN" ], @@ -46,6 +47,7 @@ "dodge": 3, "armor_bash": 10, "armor_cut": 12, + "armor_bullet": 8, "luminance": 10, "vision_night": 5, "special_attacks": [ From a249b7f495f40cf62ce1fa604c8ebc2a5893d78d Mon Sep 17 00:00:00 2001 From: ANickelN <52714184+ANickelN@users.noreply.github.com> Date: Sat, 10 Apr 2021 00:26:43 -0700 Subject: [PATCH 362/453] Audit Pocket Length/Volume/Weight Clothing (#48420) --- data/json/items/armor/coats.json | 966 +++++++++++++++++--- data/json/items/armor/legs_armor.json | 160 +++- data/json/items/armor/legs_clothes.json | 606 ++++++++++-- data/json/items/armor/suits_protection.json | 123 ++- data/json/items/armor/swimming.json | 36 +- data/json/items/armor/torso_clothes.json | 143 ++- 6 files changed, 1756 insertions(+), 278 deletions(-) diff --git a/data/json/items/armor/coats.json b/data/json/items/armor/coats.json index 40ce1171431ee..692429dd8785e 100644 --- a/data/json/items/armor/coats.json +++ b/data/json/items/armor/coats.json @@ -20,9 +20,27 @@ { "covers": [ "arm_l", "arm_r" ], "coverage": 100, "encumbrance": [ 22, 22 ] } ], "pocket_data": [ - { "pocket_type": "CONTAINER", "max_contains_volume": "1 L", "max_contains_weight": "3 kg", "moves": 80 }, - { "pocket_type": "CONTAINER", "max_contains_volume": "500 ml", "max_contains_weight": "2 kg", "moves": 80 }, - { "pocket_type": "CONTAINER", "max_contains_volume": "500 ml", "max_contains_weight": "2 kg", "moves": 80 } + { + "pocket_type": "CONTAINER", + "max_contains_volume": "900 ml", + "max_contains_weight": "3 kg", + "max_item_length": "24 cm", + "moves": 80 + }, + { + "pocket_type": "CONTAINER", + "max_contains_volume": "3250 ml", + "max_contains_weight": "5 kg", + "max_item_length": "30 cm", + "moves": 80 + }, + { + "pocket_type": "CONTAINER", + "max_contains_volume": "3250 ml", + "max_contains_weight": "5 kg", + "max_item_length": "30 cm", + "moves": 80 + } ], "warmth": 30, "material_thickness": 2, @@ -71,8 +89,20 @@ { "covers": [ "arm_l", "arm_r" ], "coverage": 95, "encumbrance": [ 26, 26 ] } ], "pocket_data": [ - { "pocket_type": "CONTAINER", "max_contains_volume": "500 ml", "max_contains_weight": "2 kg", "moves": 80 }, - { "pocket_type": "CONTAINER", "max_contains_volume": "500 ml", "max_contains_weight": "2 kg", "moves": 80 } + { + "pocket_type": "CONTAINER", + "max_contains_volume": "500 ml", + "max_contains_weight": "2 kg", + "max_item_length": "16 cm", + "moves": 80 + }, + { + "pocket_type": "CONTAINER", + "max_contains_volume": "500 ml", + "max_contains_weight": "2 kg", + "max_item_length": "16 cm", + "moves": 80 + } ], "warmth": 80, "material_thickness": 2, @@ -128,8 +158,20 @@ { "covers": [ "arm_l", "arm_r" ], "coverage": 95, "encumbrance": [ 30, 30 ] } ], "pocket_data": [ - { "pocket_type": "CONTAINER", "max_contains_volume": "700 ml", "max_contains_weight": "3 kg", "moves": 80 }, - { "pocket_type": "CONTAINER", "max_contains_volume": "700 ml", "max_contains_weight": "3 kg", "moves": 80 } + { + "pocket_type": "CONTAINER", + "max_contains_volume": "700 ml", + "max_contains_weight": "3 kg", + "max_item_length": "16 cm", + "moves": 80 + }, + { + "pocket_type": "CONTAINER", + "max_contains_volume": "700 ml", + "max_contains_weight": "3 kg", + "max_item_length": "16 cm", + "moves": 80 + } ], "warmth": 90, "material_thickness": 2, @@ -157,9 +199,27 @@ { "covers": [ "arm_l", "arm_r" ], "coverage": 90, "encumbrance": [ 2, 2 ] } ], "pocket_data": [ - { "pocket_type": "CONTAINER", "max_contains_volume": "1500 ml", "max_contains_weight": "3 kg", "moves": 80 }, - { "pocket_type": "CONTAINER", "max_contains_volume": "1500 ml", "max_contains_weight": "3 kg", "moves": 80 }, - { "pocket_type": "CONTAINER", "max_contains_volume": "500 ml", "max_contains_weight": "1 kg", "moves": 80 } + { + "pocket_type": "CONTAINER", + "max_contains_volume": "1600 ml", + "max_contains_weight": "3 kg", + "max_item_length": "21 cm", + "moves": 80 + }, + { + "pocket_type": "CONTAINER", + "max_contains_volume": "1600 ml", + "max_contains_weight": "3 kg", + "max_item_length": "21 cm", + "moves": 80 + }, + { + "pocket_type": "CONTAINER", + "max_contains_volume": "900 ml", + "max_contains_weight": "1 kg", + "max_item_length": "13 cm", + "moves": 80 + } ], "warmth": 15, "material_thickness": 0.25, @@ -183,8 +243,20 @@ { "covers": [ "arm_l", "arm_r" ], "coverage": 95, "encumbrance": [ 7, 7 ] } ], "pocket_data": [ - { "pocket_type": "CONTAINER", "max_contains_volume": "1500 ml", "max_contains_weight": "4 kg", "moves": 80 }, - { "pocket_type": "CONTAINER", "max_contains_volume": "1500 ml", "max_contains_weight": "4 kg", "moves": 120 } + { + "pocket_type": "CONTAINER", + "max_contains_volume": "1500 ml", + "max_contains_weight": "4 kg", + "max_item_length": "21 cm", + "moves": 80 + }, + { + "pocket_type": "CONTAINER", + "max_contains_volume": "1500 ml", + "max_contains_weight": "4 kg", + "max_item_length": "21 cm", + "moves": 80 + } ], "warmth": 10, "material_thickness": 0.2, @@ -254,10 +326,34 @@ { "covers": [ "arm_l", "arm_r" ], "coverage": 95, "encumbrance": [ 18, 21 ] } ], "pocket_data": [ - { "pocket_type": "CONTAINER", "max_contains_volume": "1250 ml", "max_contains_weight": "3kg", "moves": 80 }, - { "pocket_type": "CONTAINER", "max_contains_volume": "1250 ml", "max_contains_weight": "3 kg", "moves": 80 }, - { "pocket_type": "CONTAINER", "max_contains_volume": "350 ml", "max_contains_weight": "1 kg", "moves": 120 }, - { "pocket_type": "CONTAINER", "max_contains_volume": "350 ml", "max_contains_weight": "1 kg", "moves": 120 } + { + "pocket_type": "CONTAINER", + "max_contains_volume": "1250 ml", + "max_contains_weight": "3 kg", + "max_item_length": "21 cm", + "moves": 80 + }, + { + "pocket_type": "CONTAINER", + "max_contains_volume": "1250 ml", + "max_contains_weight": "3 kg", + "max_item_length": "21 cm", + "moves": 80 + }, + { + "pocket_type": "CONTAINER", + "max_contains_volume": "900 ml", + "max_contains_weight": "1 kg", + "max_item_length": "13 cm", + "moves": 120 + }, + { + "pocket_type": "CONTAINER", + "max_contains_volume": "900 ml", + "max_contains_weight": "1 kg", + "max_item_length": "13 cm", + "moves": 120 + } ], "warmth": 70, "material_thickness": 2, @@ -285,12 +381,48 @@ { "covers": [ "arm_l", "arm_r" ], "coverage": 90, "encumbrance": [ 7, 7 ] } ], "pocket_data": [ - { "pocket_type": "CONTAINER", "max_contains_volume": "1500 ml", "max_contains_weight": "4 kg", "moves": 80 }, - { "pocket_type": "CONTAINER", "max_contains_volume": "1500 ml", "max_contains_weight": "4 kg", "moves": 80 }, - { "pocket_type": "CONTAINER", "max_contains_volume": "1 L", "max_contains_weight": "2 kg", "moves": 80 }, - { "pocket_type": "CONTAINER", "max_contains_volume": "1 L", "max_contains_weight": "2 kg", "moves": 80 }, - { "pocket_type": "CONTAINER", "max_contains_volume": "500 ml", "max_contains_weight": "1 kg", "moves": 120 }, - { "pocket_type": "CONTAINER", "max_contains_volume": "500 ml", "max_contains_weight": "1 kg", "moves": 120 } + { + "pocket_type": "CONTAINER", + "max_contains_volume": "1500 ml", + "max_contains_weight": "4 kg", + "max_item_length": "24 cm", + "moves": 80 + }, + { + "pocket_type": "CONTAINER", + "max_contains_volume": "1500 ml", + "max_contains_weight": "4 kg", + "max_item_length": "24 cm", + "moves": 80 + }, + { + "pocket_type": "CONTAINER", + "max_contains_volume": "1 L", + "max_contains_weight": "2 kg", + "max_item_length": "21 cm", + "moves": 80 + }, + { + "pocket_type": "CONTAINER", + "max_contains_volume": "1 L", + "max_contains_weight": "2 kg", + "max_item_length": "21 cm", + "moves": 80 + }, + { + "pocket_type": "CONTAINER", + "max_contains_volume": "800 ml", + "max_contains_weight": "1 kg", + "max_item_length": "13 cm", + "moves": 120 + }, + { + "pocket_type": "CONTAINER", + "max_contains_volume": "800 ml", + "max_contains_weight": "1 kg", + "max_item_length": "13 cm", + "moves": 120 + } ], "warmth": 15, "material_thickness": 0.3, @@ -317,12 +449,48 @@ { "covers": [ "arm_l", "arm_r" ], "coverage": 90, "encumbrance": [ 9, 9 ] } ], "pocket_data": [ - { "pocket_type": "CONTAINER", "max_contains_volume": "1500 ml", "max_contains_weight": "4 kg", "moves": 80 }, - { "pocket_type": "CONTAINER", "max_contains_volume": "1500 ml", "max_contains_weight": "4 kg", "moves": 80 }, - { "pocket_type": "CONTAINER", "max_contains_volume": "1 L", "max_contains_weight": "2 kg", "moves": 80 }, - { "pocket_type": "CONTAINER", "max_contains_volume": "1 L", "max_contains_weight": "2 kg", "moves": 80 }, - { "pocket_type": "CONTAINER", "max_contains_volume": "500 ml", "max_contains_weight": "1 kg", "moves": 120 }, - { "pocket_type": "CONTAINER", "max_contains_volume": "500 ml", "max_contains_weight": "1 kg", "moves": 120 } + { + "pocket_type": "CONTAINER", + "max_contains_volume": "1500 ml", + "max_contains_weight": "4 kg", + "max_item_length": "24 cm", + "moves": 80 + }, + { + "pocket_type": "CONTAINER", + "max_contains_volume": "1500 ml", + "max_contains_weight": "4 kg", + "max_item_length": "24 cm", + "moves": 80 + }, + { + "pocket_type": "CONTAINER", + "max_contains_volume": "1 L", + "max_contains_weight": "2 kg", + "max_item_length": "21 cm", + "moves": 80 + }, + { + "pocket_type": "CONTAINER", + "max_contains_volume": "1 L", + "max_contains_weight": "2 kg", + "max_item_length": "21 cm", + "moves": 80 + }, + { + "pocket_type": "CONTAINER", + "max_contains_volume": "800 ml", + "max_contains_weight": "1 kg", + "max_item_length": "13 cm", + "moves": 120 + }, + { + "pocket_type": "CONTAINER", + "max_contains_volume": "800 ml", + "max_contains_weight": "1 kg", + "max_item_length": "13 cm", + "moves": 120 + } ], "warmth": 50, "material_thickness": 3, @@ -385,12 +553,48 @@ { "covers": [ "arm_l", "arm_r" ], "coverage": 90, "encumbrance": [ 8, 8 ] } ], "pocket_data": [ - { "pocket_type": "CONTAINER", "max_contains_volume": "1500 ml", "max_contains_weight": "4 kg", "moves": 80 }, - { "pocket_type": "CONTAINER", "max_contains_volume": "1500 ml", "max_contains_weight": "4 kg", "moves": 80 }, - { "pocket_type": "CONTAINER", "max_contains_volume": "1 L", "max_contains_weight": "2 kg", "moves": 80 }, - { "pocket_type": "CONTAINER", "max_contains_volume": "1 L", "max_contains_weight": "2 kg", "moves": 80 }, - { "pocket_type": "CONTAINER", "max_contains_volume": "500 ml", "max_contains_weight": "1 kg", "moves": 120 }, - { "pocket_type": "CONTAINER", "max_contains_volume": "500 ml", "max_contains_weight": "1 kg", "moves": 120 } + { + "pocket_type": "CONTAINER", + "max_contains_volume": "1500 ml", + "max_contains_weight": "4 kg", + "max_item_length": "24 cm", + "moves": 80 + }, + { + "pocket_type": "CONTAINER", + "max_contains_volume": "1500 ml", + "max_contains_weight": "4 kg", + "max_item_length": "24 cm", + "moves": 80 + }, + { + "pocket_type": "CONTAINER", + "max_contains_volume": "1 L", + "max_contains_weight": "2 kg", + "max_item_length": "21 cm", + "moves": 80 + }, + { + "pocket_type": "CONTAINER", + "max_contains_volume": "1 L", + "max_contains_weight": "2 kg", + "max_item_length": "21 cm", + "moves": 80 + }, + { + "pocket_type": "CONTAINER", + "max_contains_volume": "800 ml", + "max_contains_weight": "1 kg", + "max_item_length": "13 cm", + "moves": 120 + }, + { + "pocket_type": "CONTAINER", + "max_contains_volume": "800 ml", + "max_contains_weight": "1 kg", + "max_item_length": "13 cm", + "moves": 120 + } ], "warmth": 30, "material_thickness": 1.5, @@ -427,12 +631,48 @@ { "covers": [ "arm_l", "arm_r" ], "coverage": 85, "encumbrance": [ 7, 7 ] } ], "pocket_data": [ - { "pocket_type": "CONTAINER", "max_contains_volume": "3 L", "max_contains_weight": "6 kg", "moves": 80 }, - { "pocket_type": "CONTAINER", "max_contains_volume": "3 L", "max_contains_weight": "6 kg", "moves": 80 }, - { "pocket_type": "CONTAINER", "max_contains_volume": "1 L", "max_contains_weight": "2 kg", "moves": 80 }, - { "pocket_type": "CONTAINER", "max_contains_volume": "1 L", "max_contains_weight": "2 kg", "moves": 80 }, - { "pocket_type": "CONTAINER", "max_contains_volume": "500 ml", "max_contains_weight": "1 kg", "moves": 120 }, - { "pocket_type": "CONTAINER", "max_contains_volume": "500 ml", "max_contains_weight": "1 kg", "moves": 120 } + { + "pocket_type": "CONTAINER", + "max_contains_volume": "3 L", + "max_contains_weight": "6 kg", + "max_item_length": "31 cm", + "moves": 80 + }, + { + "pocket_type": "CONTAINER", + "max_contains_volume": "3 L", + "max_contains_weight": "6 kg", + "max_item_length": "31 cm", + "moves": 80 + }, + { + "pocket_type": "CONTAINER", + "max_contains_volume": "1 L", + "max_contains_weight": "2 kg", + "max_item_length": "25 cm", + "moves": 80 + }, + { + "pocket_type": "CONTAINER", + "max_contains_volume": "1 L", + "max_contains_weight": "2 kg", + "max_item_length": "25 cm", + "moves": 80 + }, + { + "pocket_type": "CONTAINER", + "max_contains_volume": "800 ml", + "max_contains_weight": "1 kg", + "max_item_length": "13 cm", + "moves": 120 + }, + { + "pocket_type": "CONTAINER", + "max_contains_volume": "800 ml", + "max_contains_weight": "1 kg", + "max_item_length": "13 cm", + "moves": 120 + } ], "warmth": 10, "material_thickness": 3, @@ -468,10 +708,34 @@ { "covers": [ "arm_l", "arm_r" ], "coverage": 95, "encumbrance": [ 11, 11 ] } ], "pocket_data": [ - { "pocket_type": "CONTAINER", "max_contains_volume": "1750 ml", "max_contains_weight": "4 kg", "moves": 80 }, - { "pocket_type": "CONTAINER", "max_contains_volume": "1750 ml", "max_contains_weight": "4 kg", "moves": 80 }, - { "pocket_type": "CONTAINER", "max_contains_volume": "750 ml", "max_contains_weight": "2 kg", "moves": 120 }, - { "pocket_type": "CONTAINER", "max_contains_volume": "750 ml", "max_contains_weight": "2 kg", "moves": 120 } + { + "pocket_type": "CONTAINER", + "max_contains_volume": "1750 ml", + "max_contains_weight": "4 kg", + "max_item_length": "24 cm", + "moves": 80 + }, + { + "pocket_type": "CONTAINER", + "max_contains_volume": "1750 ml", + "max_contains_weight": "4 kg", + "max_item_length": "24 cm", + "moves": 80 + }, + { + "pocket_type": "CONTAINER", + "max_contains_volume": "900 ml", + "max_contains_weight": "2 kg", + "max_item_length": "13 cm", + "moves": 120 + }, + { + "pocket_type": "CONTAINER", + "max_contains_volume": "900 ml", + "max_contains_weight": "2 kg", + "max_item_length": "13 cm", + "moves": 120 + } ], "warmth": 50, "material_thickness": 4, @@ -540,8 +804,20 @@ { "covers": [ "arm_l", "arm_r" ], "coverage": 85, "encumbrance": [ 5, 5 ] } ], "pocket_data": [ - { "pocket_type": "CONTAINER", "max_contains_volume": "750 ml", "max_contains_weight": "2 kg", "moves": 80 }, - { "pocket_type": "CONTAINER", "max_contains_volume": "750 ml", "max_contains_weight": "2 kg", "moves": 80 } + { + "pocket_type": "CONTAINER", + "max_contains_volume": "750 ml", + "max_contains_weight": "2 kg", + "max_item_length": "13 cm", + "moves": 80 + }, + { + "pocket_type": "CONTAINER", + "max_contains_volume": "750 ml", + "max_contains_weight": "2 kg", + "max_item_length": "13 cm", + "moves": 80 + } ], "warmth": 20, "material_thickness": 2, @@ -567,12 +843,48 @@ { "covers": [ "arm_l", "arm_r" ], "coverage": 95, "encumbrance": [ 7, 9 ] } ], "pocket_data": [ - { "pocket_type": "CONTAINER", "max_contains_volume": "1 L", "max_contains_weight": "2 kg", "moves": 80 }, - { "pocket_type": "CONTAINER", "max_contains_volume": "1 L", "max_contains_weight": "2 kg", "moves": 80 }, - { "pocket_type": "CONTAINER", "max_contains_volume": "750 ml", "max_contains_weight": "2 kg", "moves": 80 }, - { "pocket_type": "CONTAINER", "max_contains_volume": "750 ml", "max_contains_weight": "2 kg", "moves": 80 }, - { "pocket_type": "CONTAINER", "max_contains_volume": "500 ml", "max_contains_weight": "1 kg", "moves": 120 }, - { "pocket_type": "CONTAINER", "max_contains_volume": "500 ml", "max_contains_weight": "1 kg", "moves": 120 } + { + "pocket_type": "CONTAINER", + "max_contains_volume": "1 L", + "max_contains_weight": "2 kg", + "max_item_length": "15 cm", + "moves": 80 + }, + { + "pocket_type": "CONTAINER", + "max_contains_volume": "1 L", + "max_contains_weight": "2 kg", + "max_item_length": "15 cm", + "moves": 80 + }, + { + "pocket_type": "CONTAINER", + "max_contains_volume": "900 ml", + "max_contains_weight": "2 kg", + "max_item_length": "15 cm", + "moves": 80 + }, + { + "pocket_type": "CONTAINER", + "max_contains_volume": "900 ml", + "max_contains_weight": "2 kg", + "max_item_length": "15 cm", + "moves": 80 + }, + { + "pocket_type": "CONTAINER", + "max_contains_volume": "500 ml", + "max_contains_weight": "1 kg", + "max_item_length": "13 cm", + "moves": 120 + }, + { + "pocket_type": "CONTAINER", + "max_contains_volume": "500 ml", + "max_contains_weight": "1 kg", + "max_item_length": "13 cm", + "moves": 120 + } ], "warmth": 20, "material_thickness": 0.3, @@ -597,7 +909,15 @@ { "covers": [ "torso" ], "coverage": 95, "encumbrance": [ 8, 13 ] }, { "covers": [ "arm_l", "arm_r" ], "coverage": 95, "encumbrance": [ 8, 8 ] } ], - "pocket_data": [ { "pocket_type": "CONTAINER", "max_contains_volume": "1250 ml", "max_contains_weight": "2 kg", "moves": 80 } ], + "pocket_data": [ + { + "pocket_type": "CONTAINER", + "max_contains_volume": "1250 ml", + "max_contains_weight": "2 kg", + "max_item_length": "13 cm", + "moves": 80 + } + ], "warmth": 25, "material_thickness": 0.4, "flags": [ "OUTER", "VARSIZE" ] @@ -621,8 +941,20 @@ { "covers": [ "arm_l", "arm_r" ], "coverage": 90, "encumbrance": [ 13, 13 ] } ], "pocket_data": [ - { "pocket_type": "CONTAINER", "max_contains_volume": "350 ml", "max_contains_weight": "1 kg", "moves": 80 }, - { "pocket_type": "CONTAINER", "max_contains_volume": "350 ml", "max_contains_weight": "1 kg", "moves": 80 } + { + "pocket_type": "CONTAINER", + "max_contains_volume": "800 ml", + "max_contains_weight": "1 kg", + "max_item_length": "13 cm", + "moves": 80 + }, + { + "pocket_type": "CONTAINER", + "max_contains_volume": "800 ml", + "max_contains_weight": "1 kg", + "max_item_length": "13 cm", + "moves": 80 + } ], "warmth": 25, "material_thickness": 0.15, @@ -647,8 +979,20 @@ { "covers": [ "arm_l", "arm_r" ], "coverage": 90, "encumbrance": [ 9, 9 ] } ], "pocket_data": [ - { "pocket_type": "CONTAINER", "max_contains_volume": "500 ml", "max_contains_weight": "2 kg", "moves": 80 }, - { "pocket_type": "CONTAINER", "max_contains_volume": "500 ml", "max_contains_weight": "2 kg", "moves": 80 } + { + "pocket_type": "CONTAINER", + "max_contains_volume": "800 ml", + "max_contains_weight": "2 kg", + "max_item_length": "13 cm", + "moves": 80 + }, + { + "pocket_type": "CONTAINER", + "max_contains_volume": "800 ml", + "max_contains_weight": "2 kg", + "max_item_length": "13 cm", + "moves": 80 + } ], "warmth": 35, "material_thickness": 0.2, @@ -673,8 +1017,20 @@ { "covers": [ "arm_l", "arm_r" ], "coverage": 90, "encumbrance": [ 9, 9 ] } ], "pocket_data": [ - { "pocket_type": "CONTAINER", "max_contains_volume": "350 ml", "max_contains_weight": "1 kg", "moves": 80 }, - { "pocket_type": "CONTAINER", "max_contains_volume": "350 ml", "max_contains_weight": "1 kg", "moves": 80 } + { + "pocket_type": "CONTAINER", + "max_contains_volume": "800 ml", + "max_contains_weight": "1 kg", + "max_item_length": "13 cm", + "moves": 80 + }, + { + "pocket_type": "CONTAINER", + "max_contains_volume": "800 ml", + "max_contains_weight": "1 kg", + "max_item_length": "13 cm", + "moves": 80 + } ], "warmth": 30, "material_thickness": 0.2, @@ -705,8 +1061,20 @@ { "covers": [ "arm_l", "arm_r" ], "coverage": 90, "encumbrance": [ 10, 10 ] } ], "pocket_data": [ - { "pocket_type": "CONTAINER", "max_contains_volume": "700 ml", "max_contains_weight": "3 kg", "moves": 80 }, - { "pocket_type": "CONTAINER", "max_contains_volume": "700 ml", "max_contains_weight": "3 kg", "moves": 80 } + { + "pocket_type": "CONTAINER", + "max_contains_volume": "800 ml", + "max_item_length": "13 cm", + "max_contains_weight": "3 kg", + "moves": 80 + }, + { + "pocket_type": "CONTAINER", + "max_contains_volume": "800 ml", + "max_item_length": "13 cm", + "max_contains_weight": "3 kg", + "moves": 80 + } ], "warmth": 30, "material_thickness": 1.5, @@ -734,8 +1102,20 @@ { "covers": [ "arm_l", "arm_r" ], "coverage": 90, "encumbrance": [ 15, 15 ] } ], "pocket_data": [ - { "pocket_type": "CONTAINER", "max_contains_volume": "700 ml", "max_contains_weight": "3 kg", "moves": 80 }, - { "pocket_type": "CONTAINER", "max_contains_volume": "700 ml", "max_contains_weight": "3 kg", "moves": 80 } + { + "pocket_type": "CONTAINER", + "max_contains_volume": "800 ml", + "max_contains_weight": "3 kg", + "max_item_length": "13 cm", + "moves": 80 + }, + { + "pocket_type": "CONTAINER", + "max_contains_volume": "800 ml", + "max_contains_weight": "3 kg", + "max_item_length": "13 cm", + "moves": 80 + } ], "warmth": 30, "material_thickness": 1.0, @@ -762,8 +1142,20 @@ { "covers": [ "arm_l", "arm_r" ], "coverage": 90, "encumbrance": [ 4, 4 ] } ], "pocket_data": [ - { "pocket_type": "CONTAINER", "max_contains_volume": "700 ml", "max_contains_weight": "3 kg", "moves": 80 }, - { "pocket_type": "CONTAINER", "max_contains_volume": "700 ml", "max_contains_weight": "3 kg", "moves": 80 } + { + "pocket_type": "CONTAINER", + "max_contains_volume": "700 ml", + "max_contains_weight": "3 kg", + "max_item_length": "14 cm", + "moves": 80 + }, + { + "pocket_type": "CONTAINER", + "max_contains_volume": "700 ml", + "max_contains_weight": "3 kg", + "max_item_length": "14 cm", + "moves": 80 + } ], "warmth": 15, "material_thickness": 0.5, @@ -788,9 +1180,27 @@ { "covers": [ "arm_l", "arm_r" ], "coverage": 90, "encumbrance": [ 6, 7 ] } ], "pocket_data": [ - { "pocket_type": "CONTAINER", "max_contains_volume": "1 L", "max_contains_weight": "3 kg", "moves": 80 }, - { "pocket_type": "CONTAINER", "max_contains_volume": "350 ml", "max_contains_weight": "3 kg", "moves": 80 }, - { "pocket_type": "CONTAINER", "max_contains_volume": "350 ml", "max_contains_weight": "3 kg", "moves": 80 } + { + "pocket_type": "CONTAINER", + "max_contains_volume": "1300 ml", + "max_contains_weight": "3 kg", + "max_item_length": "21 cm", + "moves": 80 + }, + { + "pocket_type": "CONTAINER", + "max_contains_volume": "800 ml", + "max_contains_weight": "3 kg", + "max_item_length": "13 cm", + "moves": 80 + }, + { + "pocket_type": "CONTAINER", + "max_contains_volume": "800 ml", + "max_contains_weight": "3 kg", + "max_item_length": "13 cm", + "moves": 80 + } ], "warmth": 25, "material_thickness": 0.3, @@ -922,8 +1332,13 @@ { "covers": [ "arm_l", "arm_r" ], "coverage": 90, "encumbrance": [ 2, 2 ] } ], "pocket_data": [ - { "pocket_type": "CONTAINER", "max_contains_volume": "500 ml", "max_contains_weight": "3 kg", "moves": 80 }, - { "pocket_type": "CONTAINER", "max_contains_volume": "500 ml", "max_contains_weight": "3 kg", "moves": 80 } + { + "pocket_type": "CONTAINER", + "max_contains_volume": "500 ml", + "max_contains_weight": "1 kg", + "max_item_length": "13 cm", + "moves": 80 + } ], "warmth": 20, "material_thickness": 0.2, @@ -949,8 +1364,13 @@ { "covers": [ "arm_l", "arm_r" ], "coverage": 80, "encumbrance": [ 1, 1 ] } ], "pocket_data": [ - { "pocket_type": "CONTAINER", "max_contains_volume": "500 ml", "max_contains_weight": "3 kg", "moves": 80 }, - { "pocket_type": "CONTAINER", "max_contains_volume": "500 ml", "max_contains_weight": "3 kg", "moves": 80 } + { + "pocket_type": "CONTAINER", + "max_contains_volume": "500 ml", + "max_contains_weight": "1 kg", + "max_item_length": "13 cm", + "moves": 80 + } ], "warmth": 5, "material_thickness": 0.15, @@ -1018,10 +1438,34 @@ { "covers": [ "arm_l", "arm_r" ], "coverage": 85, "encumbrance": [ 10, 10 ] } ], "pocket_data": [ - { "pocket_type": "CONTAINER", "max_contains_volume": "1500 ml", "max_contains_weight": "2 kg", "moves": 80 }, - { "pocket_type": "CONTAINER", "max_contains_volume": "1500 ml", "max_contains_weight": "2 kg", "moves": 80 }, - { "pocket_type": "CONTAINER", "max_contains_volume": "250 ml", "max_contains_weight": "1 kg", "moves": 120 }, - { "pocket_type": "CONTAINER", "max_contains_volume": "250 ml", "max_contains_weight": "1 kg", "moves": 120 } + { + "pocket_type": "CONTAINER", + "max_contains_volume": "1500 ml", + "max_contains_weight": "2 kg", + "max_item_length": "24 cm", + "moves": 80 + }, + { + "pocket_type": "CONTAINER", + "max_contains_volume": "1500 ml", + "max_contains_weight": "2 kg", + "max_item_length": "24 cm", + "moves": 80 + }, + { + "pocket_type": "CONTAINER", + "max_contains_volume": "800 ml", + "max_contains_weight": "1 kg", + "max_item_length": "13 cm", + "moves": 120 + }, + { + "pocket_type": "CONTAINER", + "max_contains_volume": "800 ml", + "max_contains_weight": "1 kg", + "max_item_length": "13 cm", + "moves": 120 + } ], "warmth": 50, "material_thickness": 1.0, @@ -1049,12 +1493,48 @@ { "covers": [ "arm_l", "arm_r" ], "coverage": 80, "encumbrance": [ 8, 8 ] } ], "pocket_data": [ - { "pocket_type": "CONTAINER", "max_contains_volume": "500 ml", "max_contains_weight": "2 kg", "moves": 120 }, - { "pocket_type": "CONTAINER", "max_contains_volume": "500 ml", "max_contains_weight": "2 kg", "moves": 120 }, - { "pocket_type": "CONTAINER", "max_contains_volume": "500 ml", "max_contains_weight": "2 kg", "moves": 120 }, - { "pocket_type": "CONTAINER", "max_contains_volume": "500 ml", "max_contains_weight": "2 kg", "moves": 120 }, - { "pocket_type": "CONTAINER", "max_contains_volume": "500 ml", "max_contains_weight": "2 kg", "moves": 120 }, - { "pocket_type": "CONTAINER", "max_contains_volume": "500 ml", "max_contains_weight": "1 kg", "moves": 120 } + { + "pocket_type": "CONTAINER", + "max_contains_volume": "800 ml", + "max_contains_weight": "2 kg", + "max_item_length": "13 cm", + "moves": 120 + }, + { + "pocket_type": "CONTAINER", + "max_contains_volume": "800 ml", + "max_contains_weight": "2 kg", + "max_item_length": "13 cm", + "moves": 120 + }, + { + "pocket_type": "CONTAINER", + "max_contains_volume": "800 ml", + "max_contains_weight": "2 kg", + "max_item_length": "13 cm", + "moves": 120 + }, + { + "pocket_type": "CONTAINER", + "max_contains_volume": "800 ml", + "max_contains_weight": "2 kg", + "max_item_length": "13 cm", + "moves": 120 + }, + { + "pocket_type": "CONTAINER", + "max_contains_volume": "800 ml", + "max_contains_weight": "2 kg", + "max_item_length": "13 cm", + "moves": 120 + }, + { + "pocket_type": "CONTAINER", + "max_contains_volume": "800 ml", + "max_contains_weight": "1 kg", + "max_item_length": "13 cm", + "moves": 120 + } ], "warmth": 20, "material_thickness": 2, @@ -1101,10 +1581,34 @@ { "covers": [ "arm_l", "arm_r" ], "coverage": 95, "encumbrance": [ 15, 15 ] } ], "pocket_data": [ - { "pocket_type": "CONTAINER", "max_contains_volume": "700 ml", "max_contains_weight": "2 kg", "moves": 80 }, - { "pocket_type": "CONTAINER", "max_contains_volume": "700 ml", "max_contains_weight": "2 kg", "moves": 80 }, - { "pocket_type": "CONTAINER", "max_contains_volume": "250 ml", "max_contains_weight": "1 kg", "moves": 120 }, - { "pocket_type": "CONTAINER", "max_contains_volume": "250 ml", "max_contains_weight": "1 kg", "moves": 120 } + { + "pocket_type": "CONTAINER", + "max_contains_volume": "1000 ml", + "max_contains_weight": "2 kg", + "max_item_length": "15 cm", + "moves": 80 + }, + { + "pocket_type": "CONTAINER", + "max_contains_volume": "1000 ml", + "max_contains_weight": "2 kg", + "max_item_length": "15 cm", + "moves": 80 + }, + { + "pocket_type": "CONTAINER", + "max_contains_volume": "800 ml", + "max_contains_weight": "1 kg", + "max_item_length": "13 cm", + "moves": 120 + }, + { + "pocket_type": "CONTAINER", + "max_contains_volume": "800 ml", + "max_contains_weight": "1 kg", + "max_item_length": "13 cm", + "moves": 120 + } ], "warmth": 80, "material_thickness": 2, @@ -1132,12 +1636,48 @@ { "covers": [ "leg_l", "leg_r" ], "coverage": 90, "encumbrance": [ 7, 10 ] } ], "pocket_data": [ - { "pocket_type": "CONTAINER", "max_contains_volume": "1500 ml", "max_contains_weight": "4 kg", "moves": 80 }, - { "pocket_type": "CONTAINER", "max_contains_volume": "1500 ml", "max_contains_weight": "4 kg", "moves": 80 }, - { "pocket_type": "CONTAINER", "max_contains_volume": "1 L", "max_contains_weight": "2 kg", "moves": 80 }, - { "pocket_type": "CONTAINER", "max_contains_volume": "1 L", "max_contains_weight": "2 kg", "moves": 80 }, - { "pocket_type": "CONTAINER", "max_contains_volume": "500 ml", "max_contains_weight": "1 kg", "moves": 120 }, - { "pocket_type": "CONTAINER", "max_contains_volume": "500 ml", "max_contains_weight": "1 kg", "moves": 120 } + { + "pocket_type": "CONTAINER", + "max_contains_volume": "1500 ml", + "max_contains_weight": "4 kg", + "max_item_length": "24 cm", + "moves": 80 + }, + { + "pocket_type": "CONTAINER", + "max_contains_volume": "1500 ml", + "max_contains_weight": "4 kg", + "max_item_length": "24 cm", + "moves": 80 + }, + { + "pocket_type": "CONTAINER", + "max_contains_volume": "1 L", + "max_contains_weight": "2 kg", + "max_item_length": "21 cm", + "moves": 80 + }, + { + "pocket_type": "CONTAINER", + "max_contains_volume": "1 L", + "max_contains_weight": "2 kg", + "max_item_length": "21 cm", + "moves": 80 + }, + { + "pocket_type": "CONTAINER", + "max_contains_volume": "800 ml", + "max_contains_weight": "1 kg", + "max_item_length": "13 cm", + "moves": 120 + }, + { + "pocket_type": "CONTAINER", + "max_contains_volume": "800 ml", + "max_contains_weight": "1 kg", + "max_item_length": "13 cm", + "moves": 120 + } ], "warmth": 15, "material_thickness": 0.3, @@ -1164,12 +1704,48 @@ { "covers": [ "leg_l", "leg_r" ], "coverage": 90, "encumbrance": [ 9, 11 ] } ], "pocket_data": [ - { "pocket_type": "CONTAINER", "max_contains_volume": "1500 ml", "max_contains_weight": "4 kg", "moves": 80 }, - { "pocket_type": "CONTAINER", "max_contains_volume": "1500 ml", "max_contains_weight": "4 kg", "moves": 80 }, - { "pocket_type": "CONTAINER", "max_contains_volume": "1 L", "max_contains_weight": "2 kg", "moves": 80 }, - { "pocket_type": "CONTAINER", "max_contains_volume": "1 L", "max_contains_weight": "2 kg", "moves": 80 }, - { "pocket_type": "CONTAINER", "max_contains_volume": "500 ml", "max_contains_weight": "1 kg", "moves": 120 }, - { "pocket_type": "CONTAINER", "max_contains_volume": "500 ml", "max_contains_weight": "1 kg", "moves": 120 } + { + "pocket_type": "CONTAINER", + "max_contains_volume": "1500 ml", + "max_contains_weight": "4 kg", + "max_item_length": "24 cm", + "moves": 80 + }, + { + "pocket_type": "CONTAINER", + "max_contains_volume": "1500 ml", + "max_contains_weight": "4 kg", + "max_item_length": "24 cm", + "moves": 80 + }, + { + "pocket_type": "CONTAINER", + "max_contains_volume": "1 L", + "max_contains_weight": "2 kg", + "max_item_length": "21 cm", + "moves": 80 + }, + { + "pocket_type": "CONTAINER", + "max_contains_volume": "1 L", + "max_contains_weight": "2 kg", + "max_item_length": "21 cm", + "moves": 80 + }, + { + "pocket_type": "CONTAINER", + "max_contains_volume": "800 ml", + "max_contains_weight": "1 kg", + "max_item_length": "13 cm", + "moves": 120 + }, + { + "pocket_type": "CONTAINER", + "max_contains_volume": "800 ml", + "max_contains_weight": "1 kg", + "max_item_length": "13 cm", + "moves": 120 + } ], "warmth": 50, "material_thickness": 0.5, @@ -1207,12 +1783,48 @@ { "covers": [ "leg_l", "leg_r" ], "coverage": 90, "encumbrance": [ 8, 10 ] } ], "pocket_data": [ - { "pocket_type": "CONTAINER", "max_contains_volume": "1500 ml", "max_contains_weight": "4 kg", "moves": 80 }, - { "pocket_type": "CONTAINER", "max_contains_volume": "1500 ml", "max_contains_weight": "4 kg", "moves": 80 }, - { "pocket_type": "CONTAINER", "max_contains_volume": "1 L", "max_contains_weight": "2 kg", "moves": 80 }, - { "pocket_type": "CONTAINER", "max_contains_volume": "1 L", "max_contains_weight": "2 kg", "moves": 80 }, - { "pocket_type": "CONTAINER", "max_contains_volume": "500 ml", "max_contains_weight": "1 kg", "moves": 120 }, - { "pocket_type": "CONTAINER", "max_contains_volume": "500 ml", "max_contains_weight": "1 kg", "moves": 120 } + { + "pocket_type": "CONTAINER", + "max_contains_volume": "1500 ml", + "max_contains_weight": "4 kg", + "max_item_length": "24 cm", + "moves": 80 + }, + { + "pocket_type": "CONTAINER", + "max_contains_volume": "1500 ml", + "max_contains_weight": "4 kg", + "max_item_length": "24 cm", + "moves": 80 + }, + { + "pocket_type": "CONTAINER", + "max_contains_volume": "1 L", + "max_contains_weight": "2 kg", + "max_item_length": "21 cm", + "moves": 80 + }, + { + "pocket_type": "CONTAINER", + "max_contains_volume": "1 L", + "max_contains_weight": "2 kg", + "max_item_length": "21 cm", + "moves": 80 + }, + { + "pocket_type": "CONTAINER", + "max_contains_volume": "800 ml", + "max_contains_weight": "1 kg", + "max_item_length": "13 cm", + "moves": 120 + }, + { + "pocket_type": "CONTAINER", + "max_contains_volume": "800 ml", + "max_contains_weight": "1 kg", + "max_item_length": "13 cm", + "moves": 120 + } ], "warmth": 30, "material_thickness": 1.5, @@ -1564,12 +2176,48 @@ { "covers": [ "arm_l", "arm_r" ], "coverage": 85, "encumbrance": [ 7, 7 ] } ], "pocket_data": [ - { "pocket_type": "CONTAINER", "max_contains_volume": "3 L", "max_contains_weight": "6 kg", "moves": 80 }, - { "pocket_type": "CONTAINER", "max_contains_volume": "3 L", "max_contains_weight": "6 kg", "moves": 80 }, - { "pocket_type": "CONTAINER", "max_contains_volume": "1 L", "max_contains_weight": "2 kg", "moves": 80 }, - { "pocket_type": "CONTAINER", "max_contains_volume": "1 L", "max_contains_weight": "2 kg", "moves": 80 }, - { "pocket_type": "CONTAINER", "max_contains_volume": "500 ml", "max_contains_weight": "1 kg", "moves": 120 }, - { "pocket_type": "CONTAINER", "max_contains_volume": "500 ml", "max_contains_weight": "1 kg", "moves": 120 } + { + "pocket_type": "CONTAINER", + "max_contains_volume": "3 L", + "max_contains_weight": "6 kg", + "max_item_length": "31 cm", + "moves": 80 + }, + { + "pocket_type": "CONTAINER", + "max_contains_volume": "3 L", + "max_contains_weight": "6 kg", + "max_item_length": "31 cm", + "moves": 80 + }, + { + "pocket_type": "CONTAINER", + "max_contains_volume": "1 L", + "max_contains_weight": "2 kg", + "max_item_length": "25 cm", + "moves": 80 + }, + { + "pocket_type": "CONTAINER", + "max_contains_volume": "1 L", + "max_contains_weight": "2 kg", + "max_item_length": "25 cm", + "moves": 80 + }, + { + "pocket_type": "CONTAINER", + "max_contains_volume": "800 ml", + "max_contains_weight": "1 kg", + "max_item_length": "13 cm", + "moves": 120 + }, + { + "pocket_type": "CONTAINER", + "max_contains_volume": "800 ml", + "max_contains_weight": "1 kg", + "max_item_length": "13 cm", + "moves": 120 + } ], "warmth": 10, "material_thickness": 3, @@ -1639,10 +2287,27 @@ { "covers": [ "arm_l", "arm_r" ], "coverage": 95, "encumbrance": [ 13, 13 ] } ], "pocket_data": [ - { "pocket_type": "CONTAINER", "max_contains_volume": "350 ml", "max_contains_weight": "2 kg", "moves": 80 }, - { "pocket_type": "CONTAINER", "max_contains_volume": "350 ml", "max_contains_weight": "2 kg", "moves": 80 }, - { "pocket_type": "CONTAINER", "max_contains_volume": "250 ml", "max_contains_weight": "1 kg", "moves": 120 }, - { "pocket_type": "CONTAINER", "max_contains_volume": "250 ml", "max_contains_weight": "1 kg", "moves": 120 } + { + "pocket_type": "CONTAINER", + "max_contains_volume": "800 ml", + "max_contains_weight": "2 kg", + "max_item_length": "16 cm", + "moves": 80 + }, + { + "pocket_type": "CONTAINER", + "max_contains_volume": "800 ml", + "max_contains_weight": "2 kg", + "max_item_length": "16 cm", + "moves": 80 + }, + { + "pocket_type": "CONTAINER", + "max_contains_volume": "600 ml", + "max_contains_weight": "1 kg", + "max_item_length": "13 cm", + "moves": 120 + } ], "warmth": 30, "material_thickness": 0.5, @@ -1667,10 +2332,27 @@ "encumbrance": 2, "max_encumbrance": 5, "pocket_data": [ - { "pocket_type": "CONTAINER", "max_contains_volume": "500 ml", "max_contains_weight": "2 kg", "moves": 80 }, - { "pocket_type": "CONTAINER", "max_contains_volume": "500 ml", "max_contains_weight": "2 kg", "moves": 80 }, - { "pocket_type": "CONTAINER", "max_contains_volume": "250 ml", "max_contains_weight": "1 kg", "moves": 120 }, - { "pocket_type": "CONTAINER", "max_contains_volume": "250 ml", "max_contains_weight": "1 kg", "moves": 120 } + { + "pocket_type": "CONTAINER", + "max_contains_volume": "800 ml", + "max_contains_weight": "2 kg", + "max_item_length": "16 cm", + "moves": 80 + }, + { + "pocket_type": "CONTAINER", + "max_contains_volume": "800 ml", + "max_contains_weight": "2 kg", + "max_item_length": "16 cm", + "moves": 80 + }, + { + "pocket_type": "CONTAINER", + "max_contains_volume": "600 ml", + "max_contains_weight": "1 kg", + "max_item_length": "13 cm", + "moves": 120 + } ], "warmth": 5, "material_thickness": 0.5, @@ -1695,12 +2377,48 @@ { "covers": [ "arm_l", "arm_r" ], "coverage": 95, "encumbrance": [ 10, 10 ] } ], "pocket_data": [ - { "pocket_type": "CONTAINER", "max_contains_volume": "1 L", "max_contains_weight": "3 kg", "moves": 80 }, - { "pocket_type": "CONTAINER", "max_contains_volume": "1 L", "max_contains_weight": "3 kg", "moves": 80 }, - { "pocket_type": "CONTAINER", "max_contains_volume": "1 L", "max_contains_weight": "3 kg", "moves": 80 }, - { "pocket_type": "CONTAINER", "max_contains_volume": "1 L", "max_contains_weight": "3 kg", "moves": 80 }, - { "pocket_type": "CONTAINER", "max_contains_volume": "500 ml", "max_contains_weight": "1 kg", "moves": 120 }, - { "pocket_type": "CONTAINER", "max_contains_volume": "500 ml", "max_contains_weight": "1 kg", "moves": 120 } + { + "pocket_type": "CONTAINER", + "max_contains_volume": "1 L", + "max_contains_weight": "2 kg", + "max_item_length": "15 cm", + "moves": 80 + }, + { + "pocket_type": "CONTAINER", + "max_contains_volume": "1 L", + "max_contains_weight": "2 kg", + "max_item_length": "15 cm", + "moves": 80 + }, + { + "pocket_type": "CONTAINER", + "max_contains_volume": "900 ml", + "max_contains_weight": "2 kg", + "max_item_length": "15 cm", + "moves": 80 + }, + { + "pocket_type": "CONTAINER", + "max_contains_volume": "900 ml", + "max_contains_weight": "2 kg", + "max_item_length": "15 cm", + "moves": 80 + }, + { + "pocket_type": "CONTAINER", + "max_contains_volume": "500 ml", + "max_contains_weight": "1 kg", + "max_item_length": "13 cm", + "moves": 120 + }, + { + "pocket_type": "CONTAINER", + "max_contains_volume": "500 ml", + "max_contains_weight": "1 kg", + "max_item_length": "13 cm", + "moves": 120 + } ], "warmth": 50, "material_thickness": 1, diff --git a/data/json/items/armor/legs_armor.json b/data/json/items/armor/legs_armor.json index 0efcba5f75190..60502c2801cd6 100644 --- a/data/json/items/armor/legs_armor.json +++ b/data/json/items/armor/legs_armor.json @@ -79,10 +79,34 @@ "encumbrance": 24, "max_encumbrance": 30, "pocket_data": [ - { "pocket_type": "CONTAINER", "max_contains_volume": "500 ml", "max_contains_weight": "1 kg", "moves": 80 }, - { "pocket_type": "CONTAINER", "max_contains_volume": "500 ml", "max_contains_weight": "1 kg", "moves": 80 }, - { "pocket_type": "CONTAINER", "max_contains_volume": "250 ml", "max_contains_weight": "1 kg", "moves": 100 }, - { "pocket_type": "CONTAINER", "max_contains_volume": "250 ml", "max_contains_weight": "1 kg", "moves": 100 } + { + "pocket_type": "CONTAINER", + "max_contains_volume": "3250 ml", + "max_contains_weight": "4 kg", + "max_item_length": "30 cm", + "moves": 80 + }, + { + "pocket_type": "CONTAINER", + "max_contains_volume": "3250 ml", + "max_contains_weight": "4 kg", + "max_item_length": "30 cm", + "moves": 80 + }, + { + "pocket_type": "CONTAINER", + "max_contains_volume": "800 ml", + "max_contains_weight": "2 kg", + "max_item_length": "16 cm", + "moves": 100 + }, + { + "pocket_type": "CONTAINER", + "max_contains_volume": "800 ml", + "max_contains_weight": "2 kg", + "max_item_length": "16 cm", + "moves": 100 + } ], "warmth": 30, "material_thickness": 2, @@ -171,8 +195,20 @@ "encumbrance": 13, "max_encumbrance": 15, "pocket_data": [ - { "pocket_type": "CONTAINER", "max_contains_volume": "250 ml", "max_contains_weight": "1 kg", "moves": 100 }, - { "pocket_type": "CONTAINER", "max_contains_volume": "250 ml", "max_contains_weight": "1 kg", "moves": 100 } + { + "pocket_type": "CONTAINER", + "max_contains_volume": "800 ml", + "max_contains_weight": "1 kg", + "max_item_length": "13 cm", + "moves": 100 + }, + { + "pocket_type": "CONTAINER", + "max_contains_volume": "800 ml", + "max_contains_weight": "1 kg", + "max_item_length": "13 cm", + "moves": 100 + } ], "warmth": 20, "material_thickness": 2, @@ -388,12 +424,48 @@ "encumbrance": 8, "max_encumbrance": 16, "pocket_data": [ - { "pocket_type": "CONTAINER", "max_contains_volume": "700 ml", "max_contains_weight": "2 kg", "moves": 80 }, - { "pocket_type": "CONTAINER", "max_contains_volume": "700 ml", "max_contains_weight": "2 kg", "moves": 80 }, - { "pocket_type": "CONTAINER", "max_contains_volume": "500 ml", "max_contains_weight": "1 kg", "moves": 100 }, - { "pocket_type": "CONTAINER", "max_contains_volume": "500 ml", "max_contains_weight": "1 kg", "moves": 100 }, - { "pocket_type": "CONTAINER", "max_contains_volume": "250 ml", "max_contains_weight": "1 kg", "moves": 100 }, - { "pocket_type": "CONTAINER", "max_contains_volume": "250 ml", "max_contains_weight": "1 kg", "moves": 100 } + { + "pocket_type": "CONTAINER", + "max_contains_volume": "1000 ml", + "max_contains_weight": "2 kg", + "max_item_length": "21 cm", + "moves": 80 + }, + { + "pocket_type": "CONTAINER", + "max_contains_volume": "1000 ml", + "max_contains_weight": "2 kg", + "max_item_length": "21 cm", + "moves": 80 + }, + { + "pocket_type": "CONTAINER", + "max_contains_volume": "800 ml", + "max_contains_weight": "1 kg", + "max_item_length": "15 cm", + "moves": 100 + }, + { + "pocket_type": "CONTAINER", + "max_contains_volume": "800 ml", + "max_contains_weight": "1 kg", + "max_item_length": "15 cm", + "moves": 100 + }, + { + "pocket_type": "CONTAINER", + "max_contains_volume": "500 ml", + "max_contains_weight": "1 kg", + "max_item_length": "13 cm", + "moves": 100 + }, + { + "pocket_type": "CONTAINER", + "max_contains_volume": "500 ml", + "max_contains_weight": "1 kg", + "max_item_length": "13 cm", + "moves": 100 + } ], "warmth": 12, "material_thickness": 3, @@ -450,14 +522,62 @@ "encumbrance": 10, "max_encumbrance": 20, "pocket_data": [ - { "pocket_type": "CONTAINER", "max_contains_volume": "1 L", "max_contains_weight": "3 kg", "moves": 80 }, - { "pocket_type": "CONTAINER", "max_contains_volume": "1 L", "max_contains_weight": "3 kg", "moves": 80 }, - { "pocket_type": "CONTAINER", "max_contains_volume": "500 ml", "max_contains_weight": "2 kg", "moves": 80 }, - { "pocket_type": "CONTAINER", "max_contains_volume": "500 ml", "max_contains_weight": "2 kg", "moves": 80 }, - { "pocket_type": "CONTAINER", "max_contains_volume": "500 ml", "max_contains_weight": "2 kg", "moves": 80 }, - { "pocket_type": "CONTAINER", "max_contains_volume": "500 ml", "max_contains_weight": "2 kg", "moves": 80 }, - { "pocket_type": "CONTAINER", "max_contains_volume": "250 ml", "max_contains_weight": "1 kg", "moves": 100 }, - { "pocket_type": "CONTAINER", "max_contains_volume": "250 ml", "max_contains_weight": "1 kg", "moves": 100 } + { + "pocket_type": "CONTAINER", + "max_contains_volume": "1250 ml", + "max_contains_weight": "3 kg", + "max_item_length": "21 cm", + "moves": 80 + }, + { + "pocket_type": "CONTAINER", + "max_contains_volume": "1250 ml", + "max_contains_weight": "3 kg", + "max_item_length": "21 cm", + "moves": 80 + }, + { + "pocket_type": "CONTAINER", + "max_contains_volume": "800 ml", + "max_contains_weight": "2 kg", + "max_item_length": "15 cm", + "moves": 80 + }, + { + "pocket_type": "CONTAINER", + "max_contains_volume": "800 ml", + "max_contains_weight": "2 kg", + "max_item_length": "15 cm", + "moves": 80 + }, + { + "pocket_type": "CONTAINER", + "max_contains_volume": "800 ml", + "max_contains_weight": "2 kg", + "max_item_length": "15 cm", + "moves": 80 + }, + { + "pocket_type": "CONTAINER", + "max_contains_volume": "800 ml", + "max_contains_weight": "2 kg", + "max_item_length": "15 cm", + "moves": 80 + }, + { + "pocket_type": "CONTAINER", + "max_contains_volume": "500 ml", + "max_contains_weight": "1 kg", + "max_item_length": "13 cm", + "moves": 100 + }, + { + "pocket_type": "CONTAINER", + "max_contains_volume": "500 ml", + "max_contains_weight": "1 kg", + "max_item_length": "13 cm", + "moves": 100 + } ], "warmth": 15, "material_thickness": 4, diff --git a/data/json/items/armor/legs_clothes.json b/data/json/items/armor/legs_clothes.json index 9f84fca637a46..c12b2be167269 100644 --- a/data/json/items/armor/legs_clothes.json +++ b/data/json/items/armor/legs_clothes.json @@ -18,10 +18,13 @@ "encumbrance": 7, "max_encumbrance": 11, "pocket_data": [ - { "pocket_type": "CONTAINER", "max_contains_volume": "350 ml", "max_contains_weight": "1 kg", "moves": 80 }, - { "pocket_type": "CONTAINER", "max_contains_volume": "350 ml", "max_contains_weight": "1 kg", "moves": 80 }, - { "pocket_type": "CONTAINER", "max_contains_volume": "250 ml", "max_contains_weight": "1 kg", "moves": 100 }, - { "pocket_type": "CONTAINER", "max_contains_volume": "250 ml", "max_contains_weight": "1 kg", "moves": 100 } + { + "pocket_type": "CONTAINER", + "max_contains_volume": "500 ml", + "max_contains_weight": "1 kg", + "max_item_length": "165 mm", + "moves": 400 + } ], "warmth": 8, "material_thickness": 0.3, @@ -45,8 +48,20 @@ "covers": [ "leg_l", "leg_r" ], "coverage": 50, "pocket_data": [ - { "pocket_type": "CONTAINER", "max_contains_volume": "500 ml", "max_contains_weight": "1 kg", "moves": 80 }, - { "pocket_type": "CONTAINER", "max_contains_volume": "500 ml", "max_contains_weight": "1 kg", "moves": 80 } + { + "pocket_type": "CONTAINER", + "max_contains_volume": "1000 ml", + "max_contains_weight": "3 kg", + "max_item_length": "17 cm", + "moves": 80 + }, + { + "pocket_type": "CONTAINER", + "max_contains_volume": "1000 ml", + "max_contains_weight": "3 kg", + "max_item_length": "17 cm", + "moves": 80 + } ], "warmth": 5, "material_thickness": 0.1, @@ -93,10 +108,13 @@ { "covers": [ "foot_l", "foot_r" ], "coverage": 100, "encumbrance": [ 19, 19 ] } ], "pocket_data": [ - { "pocket_type": "CONTAINER", "max_contains_volume": "500 ml", "max_contains_weight": "1 kg", "moves": 80 }, - { "pocket_type": "CONTAINER", "max_contains_volume": "500 ml", "max_contains_weight": "1 kg", "moves": 80 }, - { "pocket_type": "CONTAINER", "max_contains_volume": "250 ml", "max_contains_weight": "1 kg", "moves": 100 }, - { "pocket_type": "CONTAINER", "max_contains_volume": "250 ml", "max_contains_weight": "1 kg", "moves": 100 } + { + "pocket_type": "CONTAINER", + "max_contains_volume": "1600 ml", + "max_contains_weight": "4 kg", + "max_item_length": "18 cm", + "moves": 80 + } ], "warmth": 5, "material_thickness": 2, @@ -178,10 +196,34 @@ "encumbrance": 12, "max_encumbrance": 16, "pocket_data": [ - { "pocket_type": "CONTAINER", "max_contains_volume": "350 ml", "max_contains_weight": "1 kg", "moves": 80 }, - { "pocket_type": "CONTAINER", "max_contains_volume": "350 ml", "max_contains_weight": "1 kg", "moves": 80 }, - { "pocket_type": "CONTAINER", "max_contains_volume": "250 ml", "max_contains_weight": "1 kg", "moves": 100 }, - { "pocket_type": "CONTAINER", "max_contains_volume": "250 ml", "max_contains_weight": "1 kg", "moves": 100 } + { + "pocket_type": "CONTAINER", + "max_contains_volume": "1250 ml", + "max_contains_weight": "4 kg", + "max_item_length": "19 cm", + "moves": 80 + }, + { + "pocket_type": "CONTAINER", + "max_contains_volume": "1250 ml", + "max_contains_weight": "4 kg", + "max_item_length": "19 cm", + "moves": 80 + }, + { + "pocket_type": "CONTAINER", + "max_contains_volume": "1080 ml", + "max_contains_weight": "4 kg", + "max_item_length": "165 mm", + "moves": 100 + }, + { + "pocket_type": "CONTAINER", + "max_contains_volume": "1080 ml", + "max_contains_weight": "4 kg", + "max_item_length": "165 mm", + "moves": 100 + } ], "warmth": 10, "material_thickness": 0.25, @@ -207,10 +249,34 @@ "encumbrance": 12, "max_encumbrance": 16, "pocket_data": [ - { "pocket_type": "CONTAINER", "max_contains_volume": "350 ml", "max_contains_weight": "1 kg", "moves": 80 }, - { "pocket_type": "CONTAINER", "max_contains_volume": "350 ml", "max_contains_weight": "1 kg", "moves": 80 }, - { "pocket_type": "CONTAINER", "max_contains_volume": "250 ml", "max_contains_weight": "1 kg", "moves": 100 }, - { "pocket_type": "CONTAINER", "max_contains_volume": "250 ml", "max_contains_weight": "1 kg", "moves": 100 } + { + "pocket_type": "CONTAINER", + "max_contains_volume": "1250 ml", + "max_contains_weight": "4 kg", + "max_item_length": "19 cm", + "moves": 80 + }, + { + "pocket_type": "CONTAINER", + "max_contains_volume": "1250 ml", + "max_contains_weight": "4 kg", + "max_item_length": "19 cm", + "moves": 80 + }, + { + "pocket_type": "CONTAINER", + "max_contains_volume": "1080 ml", + "max_contains_weight": "4 kg", + "max_item_length": "165 mm", + "moves": 100 + }, + { + "pocket_type": "CONTAINER", + "max_contains_volume": "1080 ml", + "max_contains_weight": "4 kg", + "max_item_length": "165 mm", + "moves": 100 + } ], "warmth": 10, "material_thickness": 0.25, @@ -231,7 +297,15 @@ "color": "dark_gray", "covers": [ "leg_l", "leg_r" ], "coverage": 50, - "pocket_data": [ { "pocket_type": "CONTAINER", "max_contains_volume": "250 ml", "max_contains_weight": "1 kg", "moves": 80 } ], + "pocket_data": [ + { + "pocket_type": "CONTAINER", + "max_contains_volume": "1000 ml", + "max_contains_weight": "3 kg", + "max_item_length": "19 cm", + "moves": 80 + } + ], "warmth": 20, "material_thickness": 0.3, "flags": [ "VARSIZE" ] @@ -251,7 +325,15 @@ "color": "dark_gray", "covers": [ "leg_l", "leg_r" ], "coverage": 50, - "pocket_data": [ { "pocket_type": "CONTAINER", "max_contains_volume": "250 ml", "max_contains_weight": "1 kg", "moves": 80 } ], + "pocket_data": [ + { + "pocket_type": "CONTAINER", + "max_contains_volume": "1000 ml", + "max_contains_weight": "3 kg", + "max_item_length": "19 cm", + "moves": 80 + } + ], "warmth": 10, "material_thickness": 1.5, "flags": [ "VARSIZE" ] @@ -388,10 +470,34 @@ "encumbrance": 7, "max_encumbrance": 11, "pocket_data": [ - { "pocket_type": "CONTAINER", "max_contains_volume": "350 ml", "max_contains_weight": "1 kg", "moves": 80 }, - { "pocket_type": "CONTAINER", "max_contains_volume": "350 ml", "max_contains_weight": "1 kg", "moves": 80 }, - { "pocket_type": "CONTAINER", "max_contains_volume": "250 ml", "max_contains_weight": "1 kg", "moves": 100 }, - { "pocket_type": "CONTAINER", "max_contains_volume": "250 ml", "max_contains_weight": "1 kg", "moves": 100 } + { + "pocket_type": "CONTAINER", + "max_contains_volume": "1250 ml", + "max_contains_weight": "4 kg", + "max_item_length": "19 cm", + "moves": 80 + }, + { + "pocket_type": "CONTAINER", + "max_contains_volume": "1250 ml", + "max_contains_weight": "4 kg", + "max_item_length": "19 cm", + "moves": 80 + }, + { + "pocket_type": "CONTAINER", + "max_contains_volume": "1080 ml", + "max_contains_weight": "4 kg", + "max_item_length": "165 mm", + "moves": 100 + }, + { + "pocket_type": "CONTAINER", + "max_contains_volume": "1080 ml", + "max_contains_weight": "4 kg", + "max_item_length": "165 mm", + "moves": 100 + } ], "warmth": 15, "material_thickness": 0.2, @@ -416,12 +522,48 @@ "encumbrance": 9, "max_encumbrance": 18, "pocket_data": [ - { "pocket_type": "CONTAINER", "max_contains_volume": "700 ml", "max_contains_weight": "3 kg", "moves": 80 }, - { "pocket_type": "CONTAINER", "max_contains_volume": "700 ml", "max_contains_weight": "3 kg", "moves": 80 }, - { "pocket_type": "CONTAINER", "max_contains_volume": "500 ml", "max_contains_weight": "2 kg", "moves": 100 }, - { "pocket_type": "CONTAINER", "max_contains_volume": "500 ml", "max_contains_weight": "2 kg", "moves": 100 }, - { "pocket_type": "CONTAINER", "max_contains_volume": "500 ml", "max_contains_weight": "3 kg", "moves": 120 }, - { "pocket_type": "CONTAINER", "max_contains_volume": "500 ml", "max_contains_weight": "3 kg", "moves": 120 } + { + "pocket_type": "CONTAINER", + "max_contains_volume": "1250 ml", + "max_contains_weight": "4 kg", + "max_item_length": "19 cm", + "moves": 80 + }, + { + "pocket_type": "CONTAINER", + "max_contains_volume": "1250 ml", + "max_contains_weight": "4 kg", + "max_item_length": "19 cm", + "moves": 80 + }, + { + "pocket_type": "CONTAINER", + "max_contains_volume": "1250 ml", + "max_contains_weight": "4 kg", + "max_item_length": "19 cm", + "moves": 80 + }, + { + "pocket_type": "CONTAINER", + "max_contains_volume": "1250 ml", + "max_contains_weight": "4 kg", + "max_item_length": "19 cm", + "moves": 80 + }, + { + "pocket_type": "CONTAINER", + "max_contains_volume": "1080 ml", + "max_contains_weight": "4 kg", + "max_item_length": "165 mm", + "moves": 100 + }, + { + "pocket_type": "CONTAINER", + "max_contains_volume": "1080 ml", + "max_contains_weight": "4 kg", + "max_item_length": "165 mm", + "moves": 100 + } ], "warmth": 20, "material_thickness": 0.25, @@ -445,14 +587,48 @@ "encumbrance": 8, "max_encumbrance": 16, "pocket_data": [ - { "pocket_type": "CONTAINER", "max_contains_volume": "700 ml", "max_contains_weight": "3 kg", "moves": 80 }, - { "pocket_type": "CONTAINER", "max_contains_volume": "700 ml", "max_contains_weight": "3 kg", "moves": 80 }, - { "pocket_type": "CONTAINER", "max_contains_volume": "500 ml", "max_contains_weight": "2 kg", "moves": 100 }, - { "pocket_type": "CONTAINER", "max_contains_volume": "500 ml", "max_contains_weight": "2 kg", "moves": 100 }, - { "pocket_type": "CONTAINER", "max_contains_volume": "500 ml", "max_contains_weight": "2 kg", "moves": 100 }, - { "pocket_type": "CONTAINER", "max_contains_volume": "500 ml", "max_contains_weight": "2 kg", "moves": 100 }, - { "pocket_type": "CONTAINER", "max_contains_volume": "500 ml", "max_contains_weight": "3 kg", "moves": 120 }, - { "pocket_type": "CONTAINER", "max_contains_volume": "500 ml", "max_contains_weight": "3 kg", "moves": 120 } + { + "pocket_type": "CONTAINER", + "max_contains_volume": "1250 ml", + "max_contains_weight": "4 kg", + "max_item_length": "19 cm", + "moves": 80 + }, + { + "pocket_type": "CONTAINER", + "max_contains_volume": "1250 ml", + "max_contains_weight": "4 kg", + "max_item_length": "19 cm", + "moves": 80 + }, + { + "pocket_type": "CONTAINER", + "max_contains_volume": "1250 ml", + "max_contains_weight": "4 kg", + "max_item_length": "19 cm", + "moves": 80 + }, + { + "pocket_type": "CONTAINER", + "max_contains_volume": "1250 ml", + "max_contains_weight": "4 kg", + "max_item_length": "19 cm", + "moves": 80 + }, + { + "pocket_type": "CONTAINER", + "max_contains_volume": "1080 ml", + "max_contains_weight": "4 kg", + "max_item_length": "165 mm", + "moves": 100 + }, + { + "pocket_type": "CONTAINER", + "max_contains_volume": "1080 ml", + "max_contains_weight": "4 kg", + "max_item_length": "165 mm", + "moves": 100 + } ], "warmth": 15, "material_thickness": 0.25, @@ -477,10 +653,34 @@ "encumbrance": 2, "max_encumbrance": 5, "pocket_data": [ - { "pocket_type": "CONTAINER", "max_contains_volume": "350 ml", "max_contains_weight": "1 kg", "moves": 80 }, - { "pocket_type": "CONTAINER", "max_contains_volume": "350 ml", "max_contains_weight": "1 kg", "moves": 80 }, - { "pocket_type": "CONTAINER", "max_contains_volume": "250 ml", "max_contains_weight": "1 kg", "moves": 100 }, - { "pocket_type": "CONTAINER", "max_contains_volume": "250 ml", "max_contains_weight": "1 kg", "moves": 100 } + { + "pocket_type": "CONTAINER", + "max_contains_volume": "1250 ml", + "max_contains_weight": "4 kg", + "max_item_length": "19 cm", + "moves": 80 + }, + { + "pocket_type": "CONTAINER", + "max_contains_volume": "1250 ml", + "max_contains_weight": "4 kg", + "max_item_length": "19 cm", + "moves": 80 + }, + { + "pocket_type": "CONTAINER", + "max_contains_volume": "1080 ml", + "max_contains_weight": "4 kg", + "max_item_length": "165 mm", + "moves": 100 + }, + { + "pocket_type": "CONTAINER", + "max_contains_volume": "1080 ml", + "max_contains_weight": "4 kg", + "max_item_length": "165 mm", + "moves": 100 + } ], "warmth": 15, "material_thickness": 0.2, @@ -505,10 +705,34 @@ "encumbrance": 16, "max_encumbrance": 20, "pocket_data": [ - { "pocket_type": "CONTAINER", "max_contains_volume": "350 ml", "max_contains_weight": "1 kg", "moves": 80 }, - { "pocket_type": "CONTAINER", "max_contains_volume": "350 ml", "max_contains_weight": "1 kg", "moves": 80 }, - { "pocket_type": "CONTAINER", "max_contains_volume": "250 ml", "max_contains_weight": "1 kg", "moves": 100 }, - { "pocket_type": "CONTAINER", "max_contains_volume": "250 ml", "max_contains_weight": "1 kg", "moves": 100 } + { + "pocket_type": "CONTAINER", + "max_contains_volume": "1250 ml", + "max_contains_weight": "4 kg", + "max_item_length": "19 cm", + "moves": 80 + }, + { + "pocket_type": "CONTAINER", + "max_contains_volume": "1250 ml", + "max_contains_weight": "4 kg", + "max_item_length": "19 cm", + "moves": 80 + }, + { + "pocket_type": "CONTAINER", + "max_contains_volume": "1080 ml", + "max_contains_weight": "4 kg", + "max_item_length": "165 mm", + "moves": 100 + }, + { + "pocket_type": "CONTAINER", + "max_contains_volume": "1080 ml", + "max_contains_weight": "4 kg", + "max_item_length": "165 mm", + "moves": 100 + } ], "warmth": 80, "material_thickness": 1, @@ -545,8 +769,20 @@ "encumbrance": 15, "max_encumbrance": 17, "pocket_data": [ - { "pocket_type": "CONTAINER", "max_contains_volume": "350 ml", "max_contains_weight": "1 kg", "moves": 80 }, - { "pocket_type": "CONTAINER", "max_contains_volume": "350 ml", "max_contains_weight": "1 kg", "moves": 80 } + { + "pocket_type": "CONTAINER", + "max_contains_volume": "800 ml", + "max_contains_weight": "1 kg", + "max_item_length": "19 cm", + "moves": 80 + }, + { + "pocket_type": "CONTAINER", + "max_contains_volume": "800 ml", + "max_contains_weight": "1 kg", + "max_item_length": "19 cm", + "moves": 80 + } ], "warmth": 25, "material_thickness": 0.75, @@ -572,10 +808,34 @@ "encumbrance": 6, "max_encumbrance": 10, "pocket_data": [ - { "pocket_type": "CONTAINER", "max_contains_volume": "350 ml", "max_contains_weight": "1 kg", "moves": 80 }, - { "pocket_type": "CONTAINER", "max_contains_volume": "350 ml", "max_contains_weight": "1 kg", "moves": 80 }, - { "pocket_type": "CONTAINER", "max_contains_volume": "250 ml", "max_contains_weight": "1 kg", "moves": 100 }, - { "pocket_type": "CONTAINER", "max_contains_volume": "250 ml", "max_contains_weight": "1 kg", "moves": 100 } + { + "pocket_type": "CONTAINER", + "max_contains_volume": "1250 ml", + "max_contains_weight": "4 kg", + "max_item_length": "19 cm", + "moves": 80 + }, + { + "pocket_type": "CONTAINER", + "max_contains_volume": "1250 ml", + "max_contains_weight": "4 kg", + "max_item_length": "19 cm", + "moves": 80 + }, + { + "pocket_type": "CONTAINER", + "max_contains_volume": "1080 ml", + "max_contains_weight": "4 kg", + "max_item_length": "165 mm", + "moves": 100 + }, + { + "pocket_type": "CONTAINER", + "max_contains_volume": "1080 ml", + "max_contains_weight": "4 kg", + "max_item_length": "165 mm", + "moves": 100 + } ], "warmth": 70, "material_thickness": 1, @@ -600,10 +860,34 @@ "covers": [ "leg_l", "leg_r" ], "coverage": 40, "pocket_data": [ - { "pocket_type": "CONTAINER", "max_contains_volume": "500 ml", "max_contains_weight": "1 kg", "moves": 80 }, - { "pocket_type": "CONTAINER", "max_contains_volume": "500 ml", "max_contains_weight": "1 kg", "moves": 80 }, - { "pocket_type": "CONTAINER", "max_contains_volume": "250 ml", "max_contains_weight": "1 kg", "moves": 100 }, - { "pocket_type": "CONTAINER", "max_contains_volume": "250 ml", "max_contains_weight": "1 kg", "moves": 100 } + { + "pocket_type": "CONTAINER", + "max_contains_volume": "1250 ml", + "max_contains_weight": "4 kg", + "max_item_length": "19 cm", + "moves": 80 + }, + { + "pocket_type": "CONTAINER", + "max_contains_volume": "1250 ml", + "max_contains_weight": "4 kg", + "max_item_length": "19 cm", + "moves": 80 + }, + { + "pocket_type": "CONTAINER", + "max_contains_volume": "1080 ml", + "max_contains_weight": "4 kg", + "max_item_length": "165 mm", + "moves": 100 + }, + { + "pocket_type": "CONTAINER", + "max_contains_volume": "1080 ml", + "max_contains_weight": "4 kg", + "max_item_length": "165 mm", + "moves": 100 + } ], "warmth": 5, "material_thickness": 0.2, @@ -628,10 +912,34 @@ "encumbrance": 2, "max_encumbrance": 5, "pocket_data": [ - { "pocket_type": "CONTAINER", "max_contains_volume": "350 ml", "max_contains_weight": "1 kg", "moves": 80 }, - { "pocket_type": "CONTAINER", "max_contains_volume": "350 ml", "max_contains_weight": "1 kg", "moves": 80 }, - { "pocket_type": "CONTAINER", "max_contains_volume": "250 ml", "max_contains_weight": "1 kg", "moves": 100 }, - { "pocket_type": "CONTAINER", "max_contains_volume": "250 ml", "max_contains_weight": "1 kg", "moves": 100 } + { + "pocket_type": "CONTAINER", + "max_contains_volume": "1250 ml", + "max_contains_weight": "4 kg", + "max_item_length": "19 cm", + "moves": 80 + }, + { + "pocket_type": "CONTAINER", + "max_contains_volume": "1250 ml", + "max_contains_weight": "4 kg", + "max_item_length": "19 cm", + "moves": 80 + }, + { + "pocket_type": "CONTAINER", + "max_contains_volume": "1080 ml", + "max_contains_weight": "4 kg", + "max_item_length": "165 mm", + "moves": 100 + }, + { + "pocket_type": "CONTAINER", + "max_contains_volume": "1080 ml", + "max_contains_weight": "4 kg", + "max_item_length": "165 mm", + "moves": 100 + } ], "warmth": 5, "material_thickness": 0.2, @@ -656,12 +964,48 @@ "encumbrance": 2, "max_encumbrance": 5, "pocket_data": [ - { "pocket_type": "CONTAINER", "max_contains_volume": "500 ml", "max_contains_weight": "1 kg", "moves": 80 }, - { "pocket_type": "CONTAINER", "max_contains_volume": "500 ml", "max_contains_weight": "1 kg", "moves": 80 }, - { "pocket_type": "CONTAINER", "max_contains_volume": "500 ml", "max_contains_weight": "1 kg", "moves": 80 }, - { "pocket_type": "CONTAINER", "max_contains_volume": "500 ml", "max_contains_weight": "1 kg", "moves": 80 }, - { "pocket_type": "CONTAINER", "max_contains_volume": "250 ml", "max_contains_weight": "1 kg", "moves": 100 }, - { "pocket_type": "CONTAINER", "max_contains_volume": "250 ml", "max_contains_weight": "1 kg", "moves": 100 } + { + "pocket_type": "CONTAINER", + "max_contains_volume": "1250 ml", + "max_contains_weight": "4 kg", + "max_item_length": "19 cm", + "moves": 80 + }, + { + "pocket_type": "CONTAINER", + "max_contains_volume": "1250 ml", + "max_contains_weight": "4 kg", + "max_item_length": "19 cm", + "moves": 80 + }, + { + "pocket_type": "CONTAINER", + "max_contains_volume": "1250 ml", + "max_contains_weight": "4 kg", + "max_item_length": "19 cm", + "moves": 80 + }, + { + "pocket_type": "CONTAINER", + "max_contains_volume": "1250 ml", + "max_contains_weight": "4 kg", + "max_item_length": "19 cm", + "moves": 80 + }, + { + "pocket_type": "CONTAINER", + "max_contains_volume": "1080 ml", + "max_contains_weight": "4 kg", + "max_item_length": "165 mm", + "moves": 100 + }, + { + "pocket_type": "CONTAINER", + "max_contains_volume": "1080 ml", + "max_contains_weight": "4 kg", + "max_item_length": "165 mm", + "moves": 100 + } ], "warmth": 5, "material_thickness": 0.2, @@ -686,8 +1030,20 @@ "encumbrance": 1, "max_encumbrance": 2, "pocket_data": [ - { "pocket_type": "CONTAINER", "max_contains_volume": "350 ml", "max_contains_weight": "1 kg", "moves": 80 }, - { "pocket_type": "CONTAINER", "max_contains_volume": "350 ml", "max_contains_weight": "1 kg", "moves": 80 } + { + "pocket_type": "CONTAINER", + "max_contains_volume": "1080 ml", + "max_contains_weight": "4 kg", + "max_item_length": "165 mm", + "moves": 100 + }, + { + "pocket_type": "CONTAINER", + "max_contains_volume": "1080 ml", + "max_contains_weight": "4 kg", + "max_item_length": "165 mm", + "moves": 100 + } ], "warmth": 5, "material_thickness": 0.25, @@ -773,10 +1129,34 @@ "encumbrance": 2, "max_encumbrance": 5, "pocket_data": [ - { "pocket_type": "CONTAINER", "max_contains_volume": "350 ml", "max_contains_weight": "1 kg", "moves": 80 }, - { "pocket_type": "CONTAINER", "max_contains_volume": "350 ml", "max_contains_weight": "1 kg", "moves": 80 }, - { "pocket_type": "CONTAINER", "max_contains_volume": "250 ml", "max_contains_weight": "1 kg", "moves": 100 }, - { "pocket_type": "CONTAINER", "max_contains_volume": "250 ml", "max_contains_weight": "1 kg", "moves": 100 } + { + "pocket_type": "CONTAINER", + "max_contains_volume": "1250 ml", + "max_contains_weight": "4 kg", + "max_item_length": "19 cm", + "moves": 80 + }, + { + "pocket_type": "CONTAINER", + "max_contains_volume": "1250 ml", + "max_contains_weight": "4 kg", + "max_item_length": "19 cm", + "moves": 80 + }, + { + "pocket_type": "CONTAINER", + "max_contains_volume": "1080 ml", + "max_contains_weight": "4 kg", + "max_item_length": "165 mm", + "moves": 100 + }, + { + "pocket_type": "CONTAINER", + "max_contains_volume": "1080 ml", + "max_contains_weight": "4 kg", + "max_item_length": "165 mm", + "moves": 100 + } ], "warmth": 15, "material_thickness": 0.2, @@ -802,10 +1182,34 @@ "encumbrance": 2, "max_encumbrance": 5, "pocket_data": [ - { "pocket_type": "CONTAINER", "max_contains_volume": "700 ml", "max_contains_weight": "3 kg", "moves": 80 }, - { "pocket_type": "CONTAINER", "max_contains_volume": "700 ml", "max_contains_weight": "3 kg", "moves": 80 }, - { "pocket_type": "CONTAINER", "max_contains_volume": "250 ml", "max_contains_weight": "1 kg", "moves": 100 }, - { "pocket_type": "CONTAINER", "max_contains_volume": "250 ml", "max_contains_weight": "1 kg", "moves": 100 } + { + "pocket_type": "CONTAINER", + "max_contains_volume": "1250 ml", + "max_contains_weight": "4 kg", + "max_item_length": "19 cm", + "moves": 80 + }, + { + "pocket_type": "CONTAINER", + "max_contains_volume": "1250 ml", + "max_contains_weight": "4 kg", + "max_item_length": "19 cm", + "moves": 80 + }, + { + "pocket_type": "CONTAINER", + "max_contains_volume": "1080 ml", + "max_contains_weight": "4 kg", + "max_item_length": "165 mm", + "moves": 100 + }, + { + "pocket_type": "CONTAINER", + "max_contains_volume": "1080 ml", + "max_contains_weight": "4 kg", + "max_item_length": "165 mm", + "moves": 100 + } ], "warmth": 15, "material_thickness": 0.3, @@ -835,14 +1239,48 @@ "encumbrance": 11, "max_encumbrance": 22, "pocket_data": [ - { "pocket_type": "CONTAINER", "max_contains_volume": "350 ml", "max_contains_weight": "1 kg", "moves": 80 }, - { "pocket_type": "CONTAINER", "max_contains_volume": "350 ml", "max_contains_weight": "1 kg", "moves": 80 }, - { "pocket_type": "CONTAINER", "max_contains_volume": "500 ml", "max_contains_weight": "2 kg", "moves": 100 }, - { "pocket_type": "CONTAINER", "max_contains_volume": "500 ml", "max_contains_weight": "2 kg", "moves": 100 }, - { "pocket_type": "CONTAINER", "max_contains_volume": "500 ml", "max_contains_weight": "2 kg", "moves": 100 }, - { "pocket_type": "CONTAINER", "max_contains_volume": "500 ml", "max_contains_weight": "2 kg", "moves": 100 }, - { "pocket_type": "CONTAINER", "max_contains_volume": "500 ml", "max_contains_weight": "2 kg", "moves": 120 }, - { "pocket_type": "CONTAINER", "max_contains_volume": "500 ml", "max_contains_weight": "2 kg", "moves": 120 } + { + "pocket_type": "CONTAINER", + "max_contains_volume": "1250 ml", + "max_contains_weight": "4 kg", + "max_item_length": "19 cm", + "moves": 80 + }, + { + "pocket_type": "CONTAINER", + "max_contains_volume": "1250 ml", + "max_contains_weight": "4 kg", + "max_item_length": "19 cm", + "moves": 80 + }, + { + "pocket_type": "CONTAINER", + "max_contains_volume": "1250 ml", + "max_contains_weight": "4 kg", + "max_item_length": "19 cm", + "moves": 80 + }, + { + "pocket_type": "CONTAINER", + "max_contains_volume": "1250 ml", + "max_contains_weight": "4 kg", + "max_item_length": "19 cm", + "moves": 80 + }, + { + "pocket_type": "CONTAINER", + "max_contains_volume": "1080 ml", + "max_contains_weight": "4 kg", + "max_item_length": "165 mm", + "moves": 100 + }, + { + "pocket_type": "CONTAINER", + "max_contains_volume": "1080 ml", + "max_contains_weight": "4 kg", + "max_item_length": "165 mm", + "moves": 100 + } ], "warmth": 50, "material_thickness": 0.5, diff --git a/data/json/items/armor/suits_protection.json b/data/json/items/armor/suits_protection.json index d0c6c03f1bae3..b99ed35c402b9 100644 --- a/data/json/items/armor/suits_protection.json +++ b/data/json/items/armor/suits_protection.json @@ -19,10 +19,34 @@ { "covers": [ "arm_l", "arm_r" ], "coverage": 100, "encumbrance": [ 10, 10 ] } ], "pocket_data": [ - { "pocket_type": "CONTAINER", "max_contains_volume": "1 L", "max_contains_weight": "3 kg", "moves": 80 }, - { "pocket_type": "CONTAINER", "max_contains_volume": "1 L", "max_contains_weight": "3 kg", "moves": 80 }, - { "pocket_type": "CONTAINER", "max_contains_volume": "1 L", "max_contains_weight": "3 kg", "moves": 80 }, - { "pocket_type": "CONTAINER", "max_contains_volume": "1 L", "max_contains_weight": "3 kg", "moves": 80 } + { + "pocket_type": "CONTAINER", + "max_contains_volume": "1 L", + "max_contains_weight": "3 kg", + "max_item_length": "18 cm", + "moves": 80 + }, + { + "pocket_type": "CONTAINER", + "max_contains_volume": "1 L", + "max_contains_weight": "3 kg", + "max_item_length": "18 cm", + "moves": 80 + }, + { + "pocket_type": "CONTAINER", + "max_contains_volume": "1 L", + "max_contains_weight": "3 kg", + "max_item_length": "18 cm", + "moves": 80 + }, + { + "pocket_type": "CONTAINER", + "max_contains_volume": "1 L", + "max_contains_weight": "3 kg", + "max_item_length": "18 cm", + "moves": 80 + } ], "warmth": 35, "material_thickness": 7, @@ -73,8 +97,20 @@ { "covers": [ "arm_l", "arm_r" ], "coverage": 90, "encumbrance": [ 18, 18 ] } ], "pocket_data": [ - { "pocket_type": "CONTAINER", "max_contains_volume": "500 ml", "max_contains_weight": "2 kg", "moves": 80 }, - { "pocket_type": "CONTAINER", "max_contains_volume": "500 ml", "max_contains_weight": "2 kg", "moves": 80 } + { + "pocket_type": "CONTAINER", + "max_contains_volume": "500 ml", + "max_contains_weight": "3 kg", + "max_item_length": "165 mm", + "moves": 80 + }, + { + "pocket_type": "CONTAINER", + "max_contains_volume": "500 ml", + "max_contains_weight": "3 kg", + "max_item_length": "165 mm", + "moves": 80 + } ], "warmth": 20, "material_thickness": 5, @@ -156,8 +192,20 @@ { "covers": [ "arm_l", "arm_r" ], "coverage": 90, "encumbrance": [ 21, 21 ] } ], "pocket_data": [ - { "pocket_type": "CONTAINER", "max_contains_volume": "500 ml", "max_contains_weight": "1 kg", "moves": 80 }, - { "pocket_type": "CONTAINER", "max_contains_volume": "500 ml", "max_contains_weight": "2 kg", "moves": 80 } + { + "pocket_type": "CONTAINER", + "max_contains_volume": "500 ml", + "max_contains_weight": "3 kg", + "max_item_length": "165 mm", + "moves": 80 + }, + { + "pocket_type": "CONTAINER", + "max_contains_volume": "500 ml", + "max_contains_weight": "3 kg", + "max_item_length": "165 mm", + "moves": 80 + } ], "warmth": 60, "material_thickness": 4, @@ -193,8 +241,20 @@ { "covers": [ "leg_l", "leg_r" ], "coverage": 90, "encumbrance": [ 12, 12 ] } ], "pocket_data": [ - { "pocket_type": "CONTAINER", "max_contains_volume": "1 L", "max_contains_weight": "3 kg", "moves": 80 }, - { "pocket_type": "CONTAINER", "max_contains_volume": "1 L", "max_contains_weight": "3 kg", "moves": 80 } + { + "pocket_type": "CONTAINER", + "max_contains_volume": "800 ml", + "max_contains_weight": "3 kg", + "max_item_length": "165 mm", + "moves": 80 + }, + { + "pocket_type": "CONTAINER", + "max_contains_volume": "800 ml", + "max_contains_weight": "3 kg", + "max_item_length": "165 mm", + "moves": 80 + } ], "warmth": 25, "material_thickness": 4, @@ -337,10 +397,34 @@ { "covers": [ "arm_l", "arm_r" ], "coverage": 90, "encumbrance": [ 17, 17 ] } ], "pocket_data": [ - { "pocket_type": "CONTAINER", "max_contains_volume": "700 ml", "max_contains_weight": "2 kg", "moves": 80 }, - { "pocket_type": "CONTAINER", "max_contains_volume": "700 ml", "max_contains_weight": "2 kg", "moves": 80 }, - { "pocket_type": "CONTAINER", "max_contains_volume": "250 ml", "max_contains_weight": "1 kg", "moves": 120 }, - { "pocket_type": "CONTAINER", "max_contains_volume": "250 ml", "max_contains_weight": "1 kg", "moves": 120 } + { + "pocket_type": "CONTAINER", + "max_contains_volume": "800 ml", + "max_contains_weight": "3 kg", + "max_item_length": "165 mm", + "moves": 80 + }, + { + "pocket_type": "CONTAINER", + "max_contains_volume": "800 ml", + "max_contains_weight": "3 kg", + "max_item_length": "165 mm", + "moves": 80 + }, + { + "pocket_type": "CONTAINER", + "max_contains_volume": "500 ml", + "max_contains_weight": "3 kg", + "max_item_length": "145 mm", + "moves": 120 + }, + { + "pocket_type": "CONTAINER", + "max_contains_volume": "500 ml", + "max_contains_weight": "3 kg", + "max_item_length": "145 mm", + "moves": 120 + } ], "warmth": 25, "material_thickness": 4, @@ -510,10 +594,13 @@ { "covers": [ "arm_l", "arm_r" ], "coverage": 100, "encumbrance": [ 10, 10 ] } ], "pocket_data": [ - { "pocket_type": "CONTAINER", "max_contains_volume": "700 ml", "max_contains_weight": "2 kg", "moves": 120 }, - { "pocket_type": "CONTAINER", "max_contains_volume": "700 ml", "max_contains_weight": "2 kg", "moves": 120 }, - { "pocket_type": "CONTAINER", "max_contains_volume": "250 ml", "max_contains_weight": "1 kg", "moves": 150 }, - { "pocket_type": "CONTAINER", "max_contains_volume": "250 ml", "max_contains_weight": "1 kg", "moves": 150 } + { + "pocket_type": "CONTAINER", + "max_contains_volume": "1600 ml", + "max_contains_weight": "3 kg", + "max_item_length": "18 cm", + "moves": 120 + } ], "warmth": 25, "material_thickness": 2, diff --git a/data/json/items/armor/swimming.json b/data/json/items/armor/swimming.json index b4af0dfd40176..448ea1349da71 100644 --- a/data/json/items/armor/swimming.json +++ b/data/json/items/armor/swimming.json @@ -58,10 +58,20 @@ { "covers": [ "arm_l", "arm_r" ], "coverage": 100, "encumbrance": [ 11, 11 ] } ], "pocket_data": [ - { "pocket_type": "CONTAINER", "max_contains_volume": "350 ml", "max_contains_weight": "1 kg", "moves": 80 }, - { "pocket_type": "CONTAINER", "max_contains_volume": "350 ml", "max_contains_weight": "1 kg", "moves": 80 }, - { "pocket_type": "CONTAINER", "max_contains_volume": "250 ml", "max_contains_weight": "1 kg", "moves": 100 }, - { "pocket_type": "CONTAINER", "max_contains_volume": "250 ml", "max_contains_weight": "1 kg", "moves": 100 } + { + "pocket_type": "CONTAINER", + "max_contains_volume": "500 ml", + "max_contains_weight": "2 kg", + "max_item_length": "11 cm", + "moves": 130 + }, + { + "pocket_type": "CONTAINER", + "max_contains_volume": "500 ml", + "max_contains_weight": "2 kg", + "max_item_length": "11 cm", + "moves": 130 + } ], "warmth": 50, "material_thickness": 3, @@ -188,10 +198,20 @@ { "covers": [ "arm_l", "arm_r" ], "coverage": 90, "encumbrance": [ 2, 4 ] } ], "pocket_data": [ - { "pocket_type": "CONTAINER", "max_contains_volume": "350 ml", "max_contains_weight": "1 kg", "moves": 80 }, - { "pocket_type": "CONTAINER", "max_contains_volume": "350 ml", "max_contains_weight": "1 kg", "moves": 80 }, - { "pocket_type": "CONTAINER", "max_contains_volume": "250 ml", "max_contains_weight": "1 kg", "moves": 100 }, - { "pocket_type": "CONTAINER", "max_contains_volume": "250 ml", "max_contains_weight": "1 kg", "moves": 100 } + { + "pocket_type": "CONTAINER", + "max_contains_volume": "500 ml", + "max_contains_weight": "2 kg", + "max_item_length": "11 cm", + "moves": 130 + }, + { + "pocket_type": "CONTAINER", + "max_contains_volume": "500 ml", + "max_contains_weight": "2 kg", + "max_item_length": "11 cm", + "moves": 130 + } ], "warmth": 30, "material_thickness": 2, diff --git a/data/json/items/armor/torso_clothes.json b/data/json/items/armor/torso_clothes.json index ba59311006616..50e3773b1c12d 100644 --- a/data/json/items/armor/torso_clothes.json +++ b/data/json/items/armor/torso_clothes.json @@ -18,8 +18,20 @@ { "covers": [ "leg_l", "leg_r" ], "coverage": 70, "encumbrance": [ 2, 2 ] } ], "pocket_data": [ - { "pocket_type": "CONTAINER", "max_contains_volume": "1 L", "max_contains_weight": "3 kg", "moves": 80 }, - { "pocket_type": "CONTAINER", "max_contains_volume": "1 L", "max_contains_weight": "3 kg", "moves": 80 } + { + "pocket_type": "CONTAINER", + "max_contains_volume": "1 L", + "max_contains_weight": "3 kg", + "max_item_length": "21 cm", + "moves": 80 + }, + { + "pocket_type": "CONTAINER", + "max_contains_volume": "1 L", + "max_contains_weight": "3 kg", + "max_item_length": "21 cm", + "moves": 80 + } ], "warmth": 15, "material_thickness": 2, @@ -54,10 +66,27 @@ { "covers": [ "arm_l", "arm_r" ], "coverage": 85, "encumbrance": [ 16, 16 ] } ], "pocket_data": [ - { "pocket_type": "CONTAINER", "max_contains_volume": "250 ml", "max_contains_weight": "2 kg", "moves": 80 }, - { "pocket_type": "CONTAINER", "max_contains_volume": "250 ml", "max_contains_weight": "2 kg", "moves": 80 }, - { "pocket_type": "CONTAINER", "max_contains_volume": "250 ml", "max_contains_weight": "2 kg", "moves": 120 }, - { "pocket_type": "CONTAINER", "max_contains_volume": "250 ml", "max_contains_weight": "2 kg", "moves": 120 } + { + "pocket_type": "CONTAINER", + "max_contains_volume": "750 ml", + "max_contains_weight": "3 kg", + "max_item_length": "11 cm", + "moves": 80 + }, + { + "pocket_type": "CONTAINER", + "max_contains_volume": "750 ml", + "max_contains_weight": "3 kg", + "max_item_length": "11 cm", + "moves": 80 + }, + { + "pocket_type": "CONTAINER", + "max_contains_volume": "350 ml", + "max_contains_weight": "2 kg", + "max_item_length": "9 cm", + "moves": 100 + } ], "warmth": 20, "material_thickness": 1.5, @@ -104,7 +133,15 @@ { "covers": [ "torso" ], "coverage": 90, "encumbrance": [ 4, 5 ] }, { "covers": [ "arm_l", "arm_r" ], "coverage": 90, "encumbrance": [ 4, 4 ] } ], - "pocket_data": [ { "pocket_type": "CONTAINER", "max_contains_volume": "250 ml", "max_contains_weight": "1 kg", "moves": 80 } ], + "pocket_data": [ + { + "pocket_type": "CONTAINER", + "max_contains_volume": "350 ml", + "max_contains_weight": "2 kg", + "max_item_length": "9 cm", + "moves": 80 + } + ], "warmth": 10, "material_thickness": 0.1, "flags": [ "VARSIZE", "FANCY" ] @@ -256,9 +293,13 @@ { "covers": [ "arm_l", "arm_r" ], "coverage": 95, "encumbrance": [ 6, 6 ] } ], "pocket_data": [ - { "pocket_type": "CONTAINER", "max_contains_volume": "2 L", "max_contains_weight": "4 kg", "moves": 80 }, - { "pocket_type": "CONTAINER", "max_contains_volume": "250 ml", "max_contains_weight": "1 kg", "moves": 80 }, - { "pocket_type": "CONTAINER", "max_contains_volume": "250 ml", "max_contains_weight": "1 kg", "moves": 80 } + { + "pocket_type": "CONTAINER", + "max_contains_volume": "3 L", + "max_contains_weight": "4 kg", + "max_item_length": "36 cm", + "moves": 80 + } ], "warmth": 30, "material_thickness": 1, @@ -445,8 +486,13 @@ { "covers": [ "arm_l", "arm_r" ], "coverage": 75, "encumbrance": [ 5, 5 ] } ], "pocket_data": [ - { "pocket_type": "CONTAINER", "max_contains_volume": "250 ml", "max_contains_weight": "1 kg", "moves": 120 }, - { "pocket_type": "CONTAINER", "max_contains_volume": "250 ml", "max_contains_weight": "1 kg", "moves": 120 } + { + "pocket_type": "CONTAINER", + "max_contains_volume": "500 ml", + "max_contains_weight": "3 kg", + "max_item_length": "10 cm", + "moves": 80 + } ], "warmth": 5, "material_thickness": 0.1, @@ -490,8 +536,20 @@ "covers": [ "torso" ], "coverage": 90, "pocket_data": [ - { "pocket_type": "CONTAINER", "max_contains_volume": "500 ml", "max_contains_weight": "1 kg", "moves": 80 }, - { "pocket_type": "CONTAINER", "max_contains_volume": "500 ml", "max_contains_weight": "1 kg", "moves": 80 } + { + "pocket_type": "CONTAINER", + "max_contains_volume": "800 ml", + "max_contains_weight": "3 kg", + "max_item_length": "15 cm", + "moves": 80 + }, + { + "pocket_type": "CONTAINER", + "max_contains_volume": "800 ml", + "max_contains_weight": "3 kg", + "max_item_length": "15 cm", + "moves": 80 + } ], "warmth": 5, "material_thickness": 0.1, @@ -515,7 +573,15 @@ { "covers": [ "torso" ], "coverage": 90, "encumbrance": [ 3, 5 ] }, { "covers": [ "arm_l", "arm_r" ], "coverage": 90, "encumbrance": [ 3, 3 ] } ], - "pocket_data": [ { "pocket_type": "CONTAINER", "max_contains_volume": "500 ml", "max_contains_weight": "1 kg", "moves": 80 } ], + "pocket_data": [ + { + "pocket_type": "CONTAINER", + "max_contains_volume": "650 ml", + "max_contains_weight": "3 kg", + "max_item_length": "15 cm", + "moves": 80 + } + ], "warmth": 15, "material_thickness": 0.2, "flags": [ "VARSIZE" ] @@ -642,7 +708,15 @@ "coverage": 40, "encumbrance": 4, "max_encumbrance": 5, - "pocket_data": [ { "pocket_type": "CONTAINER", "max_contains_volume": "250 ml", "max_contains_weight": "1 kg", "moves": 80 } ], + "pocket_data": [ + { + "pocket_type": "CONTAINER", + "max_contains_volume": "650 ml", + "max_contains_weight": "1 kg", + "max_item_length": "15 cm", + "moves": 80 + } + ], "warmth": 8, "material_thickness": 0.2, "snippet_category": [ @@ -761,7 +835,7 @@ "coverage": 50, "encumbrance": 4, "max_encumbrance": 5, - "pocket_data": [ { "pocket_type": "CONTAINER", "max_contains_volume": "250 ml", "max_contains_weight": "1 kg", "moves": 80 } ], + "pocket_data": [ { "pocket_type": "CONTAINER", "max_contains_volume": "250 ml", "max_contains_weight": "1 kg", "moves": 400 } ], "warmth": 5, "material_thickness": 0.4, "flags": [ "VARSIZE", "FANCY" ] @@ -785,10 +859,27 @@ "encumbrance": 4, "max_encumbrance": 8, "pocket_data": [ - { "pocket_type": "CONTAINER", "max_contains_volume": "350 ml", "max_contains_weight": "1 kg", "moves": 80 }, - { "pocket_type": "CONTAINER", "max_contains_volume": "350 ml", "max_contains_weight": "1 kg", "moves": 80 }, - { "pocket_type": "CONTAINER", "max_contains_volume": "250 ml", "max_contains_weight": "1 kg", "moves": 120 }, - { "pocket_type": "CONTAINER", "max_contains_volume": "250 ml", "max_contains_weight": "1 kg", "moves": 120 } + { + "pocket_type": "CONTAINER", + "max_contains_volume": "650 ml", + "max_contains_weight": "3 kg", + "max_item_length": "15 cm", + "moves": 80 + }, + { + "pocket_type": "CONTAINER", + "max_contains_volume": "800 ml", + "max_contains_weight": "3 kg", + "max_item_length": "15 cm", + "moves": 120 + }, + { + "pocket_type": "CONTAINER", + "max_contains_volume": "800 ml", + "max_contains_weight": "3 kg", + "max_item_length": "15 cm", + "moves": 120 + } ], "warmth": 20, "material_thickness": 1.5, @@ -814,9 +905,13 @@ { "covers": [ "arm_l", "arm_r" ], "coverage": 95, "encumbrance": [ 6, 6 ] } ], "pocket_data": [ - { "pocket_type": "CONTAINER", "max_contains_volume": "2 L", "max_contains_weight": "4 kg", "moves": 80 }, - { "pocket_type": "CONTAINER", "max_contains_volume": "250 ml", "max_contains_weight": "1 kg", "moves": 80 }, - { "pocket_type": "CONTAINER", "max_contains_volume": "250 ml", "max_contains_weight": "1 kg", "moves": 80 } + { + "pocket_type": "CONTAINER", + "max_contains_volume": "3 L", + "max_contains_weight": "4 kg", + "max_item_length": "36 cm", + "moves": 80 + } ], "warmth": 45, "material_thickness": 1, From d7067d41a4afbaade77fa9b5b67313caef28f940 Mon Sep 17 00:00:00 2001 From: ANickelN <52714184+ANickelN@users.noreply.github.com> Date: Sat, 10 Apr 2021 00:27:14 -0700 Subject: [PATCH 363/453] Fix glass weights, lengths and volumes (#48449) --- data/json/items/resources/glass.json | 26 ++++++----- data/json/materials.json | 26 +++++++++++ tests/vehicle_drag_test.cpp | 66 ++++++++++++++-------------- tests/vehicle_efficiency_test.cpp | 50 ++++++++++----------- 4 files changed, 99 insertions(+), 69 deletions(-) diff --git a/data/json/items/resources/glass.json b/data/json/items/resources/glass.json index 1e9b16ffda269..4db237c921cac 100644 --- a/data/json/items/resources/glass.json +++ b/data/json/items/resources/glass.json @@ -27,13 +27,14 @@ "symbol": "]", "color": "light_cyan", "name": { "str": "sheet of glass", "str_pl": "sheets of glass" }, - "description": "A large sheet of glass. Easily shattered. Useful for repairing windows.", + "description": "A large sheet of glass, around three by four feet. Easily shattered. Useful for repairing windows.", "category": "spare_parts", "price": 5000, "price_postapoc": 100, "material": [ "glass" ], - "weight": "31250 g", - "volume": "12500 ml", + "weight": "6577 g", + "volume": "2655 ml", + "longest_side": "122 cm", "bashing": 4, "to_hit": -5, "use_action": { @@ -50,13 +51,14 @@ "symbol": "]", "color": "light_blue", "name": { "str": "sheet of reinforced glass", "str_pl": "sheets of reinforced glass" }, - "description": "A large sheet of glass strengthened with steel wiring.", + "description": "A large sheet of bulletproof glass, it looks to a little over two inches thick.", "category": "spare_parts", "price": 10000, "price_postapoc": 250, "material": [ "glass", "steel" ], - "weight": "40123 g", - "volume": "12500 ml", + "weight": "137710 g", + "volume": "63713 ml", + "longest_side": "122 cm", "bashing": 6, "to_hit": -6 }, @@ -66,13 +68,14 @@ "symbol": "]", "color": "light_blue", "name": { "str": "pane of reinforced glass", "str_pl": "panes of reinforced glass" }, - "description": "A small pane of glass strengthened with steel wiring.", + "description": "A small pane of bulletproof glass, it looks to be a little over two inches thick.", "category": "spare_parts", "price": 5000, "price_postapoc": 100, "material": [ "glass", "steel" ], - "weight": "10040 g", - "volume": "3 L", + "weight": "11475 g", + "volume": "5300 ml", + "longest_side": "305 mm", "bashing": 4, "to_hit": -2 }, @@ -87,8 +90,9 @@ "price": 10000, "price_postapoc": 100, "material": [ "glass" ], - "weight": "22700 g", - "volume": "22700 ml", + "weight": "17514 g", + "volume": "7070 ml", + "longest_side": "122 cm", "bashing": 6, "to_hit": -5 } diff --git a/data/json/materials.json b/data/json/materials.json index 6ecef26451a54..a62c2a95edb50 100644 --- a/data/json/materials.json +++ b/data/json/materials.json @@ -607,6 +607,32 @@ { "fuel": 1, "smoke": 5, "burn": 5 } ] }, + { + "type": "material", + "id": "lvl4ballisticglass", + "name": "Ballistic Glass", + "//": "Values are based on thickness being a quarter of an inch.", + "density": 30, + "specific_heat_liquid": 0.2, + "specific_heat_solid": 0.2, + "latent_heat": 100, + "bash_resist": 5, + "cut_resist": 10, + "bullet_resist": 9, + "acid_resist": 10, + "fire_resist": 3, + "elec_resist": 4, + "chip_resist": 0, + "dmg_adj": [ "scratched", "cut", "cracked", "shattered" ], + "bash_dmg_verb": "cracked", + "cut_dmg_verb": "scratched", + "burn_data": [ + { "fuel": 0, "smoke": 0, "burn": 0 }, + { "fuel": 0, "smoke": 0, "burn": 0 }, + { "fuel": 0, "smoke": 0, "burn": 1000, "volume_per_turn": "5000 ml", "//": "More like shattering than melting" } + ], + "burn_products": [ [ "glass_shard", 1 ] ] + }, { "type": "material", "id": "glass", diff --git a/tests/vehicle_drag_test.cpp b/tests/vehicle_drag_test.cpp index 6920713743150..af5f69c38b203 100644 --- a/tests/vehicle_drag_test.cpp +++ b/tests/vehicle_drag_test.cpp @@ -239,28 +239,28 @@ TEST_CASE( "vehicle_drag", "[vehicle] [engine]" ) test_vehicle_drag( "superbike", 0.609525, 0.846042, 378.257812, 9912, 11797 ); test_vehicle_drag( "tandem", 0.609525, 0.010590, 19.990625, 1430, 1870 ); test_vehicle_drag( "unicycle", 0.690795, 0.002493, 25.100000, 1377, 1798 ); - test_vehicle_drag( "beetle", 0.785610, 1.802151, 1275.732812, 8969, 10710 ); - test_vehicle_drag( "bubble_car", 0.823988, 1.764712, 1189.742560, 9304, 9651 ); - test_vehicle_drag( "car", 0.294604, 2.473484, 1167.310417, 11916, 14350 ); - test_vehicle_drag( "car_mini", 0.294604, 1.817781, 1286.796875, 12157, 14580 ); - test_vehicle_drag( "car_sports", 0.294604, 2.549405, 1443.767500, 20848, 24904 ); - test_vehicle_drag( "car_sports_atomic", 0.294604, 3.788275, 1787.798958, 23696, 24593 ); - test_vehicle_drag( "car_sports_electric", 0.294604, 3.119641, 1766.701250, 23901, 24797 ); - test_vehicle_drag( "electric_car", 0.304763, 2.311289, 1090.765625, 16266, 16882 ); - test_vehicle_drag( "rara_x", 0.679185, 1.952527, 1092.094907, 9114, 9459 ); - test_vehicle_drag( "suv", 0.294604, 2.914201, 1178.826786, 13988, 16827 ); - test_vehicle_drag( "suv_electric", 0.304763, 2.461925, 995.875893, 16216, 16833 ); + test_vehicle_drag( "beetle", 0.785610, 1.584313, 1121.526562, 9005, 10744 ); + test_vehicle_drag( "bubble_car", 0.823988, 1.002279, 675.721726, 9424, 9769 ); + test_vehicle_drag( "car", 0.294604, 2.255646, 1064.506250, 11995, 14426 ); + test_vehicle_drag( "car_mini", 0.294604, 1.599943, 1132.590625, 12238, 14657 ); + test_vehicle_drag( "car_sports", 0.294604, 2.331567, 1320.402500, 20918, 24972 ); + test_vehicle_drag( "car_sports_atomic", 0.294604, 3.461518, 1633.592708, 23795, 24693 ); + test_vehicle_drag( "car_sports_electric", 0.294604, 2.901803, 1643.336250, 23968, 24864 ); + test_vehicle_drag( "electric_car", 0.304763, 2.093451, 987.961458, 16337, 16954 ); + test_vehicle_drag( "rara_x", 0.679185, 1.544080, 863.641204, 9191, 9535 ); + test_vehicle_drag( "suv", 0.294604, 2.696363, 1090.708929, 14063, 16899 ); + test_vehicle_drag( "suv_electric", 0.304763, 2.244087, 907.758036, 16288, 16904 ); test_vehicle_drag( "golf_cart", 0.943313, 1.472114, 926.312500, 7039, 7303 ); test_vehicle_drag( "golf_cart_4seat", 0.943313, 1.439476, 905.775000, 7044, 7308 ); - test_vehicle_drag( "hearse", 0.355556, 3.216780, 1301.223214, 11046, 13340 ); - test_vehicle_drag( "pickup_technical", 0.838097, 2.958591, 1196.783036, 10176, 12173 ); - test_vehicle_drag( "ambulance", 1.049323, 2.348252, 1927.320833, 11306, 13472 ); - test_vehicle_drag( "car_fbi", 0.457144, 2.743431, 1294.706250, 14625, 17490 ); + test_vehicle_drag( "hearse", 0.355556, 2.672185, 1080.928571, 11212, 13499 ); + test_vehicle_drag( "pickup_technical", 0.838097, 2.631835, 1064.606250, 10223, 12217 ); + test_vehicle_drag( "ambulance", 1.049323, 2.191681, 1798.815625, 11324, 13488 ); + test_vehicle_drag( "car_fbi", 0.457144, 2.525593, 1191.902083, 14675, 17538 ); test_vehicle_drag( "fire_engine", 2.305875, 3.544531, 2327.331250, 8697, 10364 ); test_vehicle_drag( "fire_truck", 1.056510, 8.175862, 5419.870313, 10648, 12841 ); - test_vehicle_drag( "policecar", 0.629843, 2.744534, 1295.227083, 13235, 15807 ); - test_vehicle_drag( "policesuv", 0.629843, 3.096796, 1252.688393, 13173, 15749 ); - test_vehicle_drag( "truck_swat", 0.808830, 7.607580, 6243.900000, 9929, 11682 ); + test_vehicle_drag( "policecar", 0.629843, 2.526697, 1192.422917, 13273, 15844 ); + test_vehicle_drag( "policesuv", 0.629843, 2.878958, 1164.570536, 13211, 15785 ); + test_vehicle_drag( "truck_swat", 0.808830, 8.226852, 6752.165625, 9846, 11602 ); test_vehicle_drag( "oldtractor", 0.537285, 0.893482, 1319.981250, 12446, 14408 ); test_vehicle_drag( "autotractor", 1.425450, 2.044321, 2013.445000, 7779, 8068 ); test_vehicle_drag( "tractor_plow", 0.609525, 0.918444, 1739.562500, 11941, 13822 ); @@ -268,34 +268,34 @@ TEST_CASE( "vehicle_drag", "[vehicle] [engine]" ) test_vehicle_drag( "tractor_seed", 0.609525, 0.804219, 1523.216346, 11963, 13843 ); test_vehicle_drag( "aapc-mg", 1.625400, 8.660271, 4378.969494, 8038, 9427 ); test_vehicle_drag( "apc", 1.625400, 8.538354, 4317.323661, 8047, 9436 ); - test_vehicle_drag( "humvee", 0.616297, 7.288356, 4913.700893, 12935, 15175 ); - test_vehicle_drag( "military_cargo_truck", 0.840757, 9.507160, 4387.005556, 11554, 13581 ); + test_vehicle_drag( "humvee", 0.616298, 7.938499, 5352.017857, 12830, 15073 ); + test_vehicle_drag( "military_cargo_truck", 0.840758, 10.682064, 4929.155556, 11411, 13443 ); test_vehicle_drag( "flatbed_truck", 0.776902, 4.556718, 2039.952841, 10177, 12239 ); - test_vehicle_drag( "pickup", 0.589208, 3.264179, 1320.396429, 11288, 13539 ); + test_vehicle_drag( "pickup", 0.589208, 2.852032, 1153.678571, 11367, 13615 ); test_vehicle_drag( "semi_truck", 0.792020, 10.185646, 5885.327500, 11661, 13732 ); test_vehicle_drag( "truck_trailer", 1.196475, 13.127154, 5818.000000, 0, 0 ); test_vehicle_drag( "tatra_truck", 0.968467, 8.434611, 4507.793605, 14050, 16400 ); - test_vehicle_drag( "animalctrl", 0.396191, 2.829350, 1144.503571, 12832, 15400 ); + test_vehicle_drag( "animalctrl", 0.396191, 2.611512, 1056.385714, 12891, 15457 ); test_vehicle_drag( "autosweeper", 0.986850, 1.844396, 1305.637500, 6884, 7144 ); - test_vehicle_drag( "excavator", 0.659728, 1.793523, 1269.625000, 13204, 15305 ); + test_vehicle_drag( "excavator", 0.659728, 2.439720, 1727.064062, 13095, 15200 ); test_vehicle_drag( "road_roller", 1.823738, 2.768224, 9197.104167, 9430, 10928 ); test_vehicle_drag( "forklift", 0.565988, 1.510686, 712.937500, 8258, 8572 ); - test_vehicle_drag( "trencher", 0.520838, 1.173965, 1334.115865, 8559, 8881 ); - test_vehicle_drag( "armored_car", 0.844628, 7.034173, 4742.334821, 11846, 13860 ); + test_vehicle_drag( "trencher", 0.520838, 1.545528, 1756.367308, 8466, 8788 ); + test_vehicle_drag( "armored_car", 0.844627, 7.682788, 5179.621429, 11764, 13781 ); test_vehicle_drag( "cube_van", 0.518580, 2.707603, 2222.257292, 11852, 14196 ); test_vehicle_drag( "cube_van_cheap", 0.512775, 2.643764, 1905.244207, 10060, 12081 ); - test_vehicle_drag( "hippie_van", 0.375874, 2.698624, 1091.623214, 11022, 13267 ); - test_vehicle_drag( "icecream_truck", 0.681673, 3.271602, 2225.536486, 10796, 12939 ); - test_vehicle_drag( "lux_rv", 1.630929, 4.101402, 2315.010526, 8390, 9759 ); + test_vehicle_drag( "hippie_van", 0.375874, 2.480786, 1003.505357, 11086, 13328 ); + test_vehicle_drag( "icecream_truck", 0.681673, 2.971394, 2021.317399, 10847, 12988 ); + test_vehicle_drag( "lux_rv", 1.630929, 3.669265, 2071.093531, 8426, 9792 ); test_vehicle_drag( "meth_lab", 0.499230, 4.185080, 2538.355452, 11668, 14057 ); - test_vehicle_drag( "rv", 0.541800, 3.107252, 2127.031915, 11611, 13925 ); - test_vehicle_drag( "schoolbus", 0.445050, 4.727095, 2140.748136, 12301, 14426 ); - test_vehicle_drag( "security_van", 0.541800, 8.004081, 6569.327083, 11003, 13010 ); - test_vehicle_drag( "wienermobile", 1.281891, 2.613527, 2145.044792, 10576, 12602 ); + test_vehicle_drag( "rv", 0.541800, 2.939497, 2012.197473, 11645, 13958 ); + test_vehicle_drag( "schoolbus", 0.445050, 3.727552, 1688.087610, 12535, 14652 ); + test_vehicle_drag( "security_van", 0.541800, 8.623353, 7077.592708, 10891, 12901 ); + test_vehicle_drag( "wienermobile", 1.281891, 2.237757, 1836.632292, 10612, 12636 ); test_vehicle_drag( "canoe", 0.609525, 7.741047, 2.191938, 298, 628 ); test_vehicle_drag( "kayak", 0.609525, 2.935863, 1.108417, 710, 1314 ); test_vehicle_drag( "kayak_racing", 0.609525, 2.604776, 0.983417, 779, 1406 ); - test_vehicle_drag( "DUKW", 0.776902, 3.850773, 83.288765, 10283, 12339 ); + test_vehicle_drag( "DUKW", 0.776903, 3.602238, 77.913176, 10321, 12374 ); test_vehicle_drag( "raft", 0.997815, 9.743243, 5.517750, 239, 508 ); test_vehicle_drag( "inflatable_boat", 0.469560, 3.616690, 2.048188, 602, 1173 ); } diff --git a/tests/vehicle_efficiency_test.cpp b/tests/vehicle_efficiency_test.cpp index 4eec7efb70e6f..4d8c1211df14f 100644 --- a/tests/vehicle_efficiency_test.cpp +++ b/tests/vehicle_efficiency_test.cpp @@ -433,41 +433,41 @@ TEST_CASE( "make_vehicle_efficiency_case", "[.]" ) // Fix test for electric vehicles TEST_CASE( "vehicle_efficiency", "[vehicle] [engine]" ) { - test_vehicle( "beetle", 816469, 431300, 338700, 95610, 68060 ); - test_vehicle( "car", 1120618, 617500, 388600, 52730, 25170 ); - test_vehicle( "car_sports", 1155014, 352600, 267600, 36820, 22360 ); - test_vehicle( "electric_car", 1047135, 355300, 201600, 22400, 10780 ); - test_vehicle( "suv", 1320286, 1163000, 630000, 85540, 31840 ); + test_vehicle( "beetle", 717777, 444000, 386700, 111500, 91570 ); + test_vehicle( "car", 1021926, 644100, 436900, 59860, 30240 ); + test_vehicle( "car_sports", 1056322, 354700, 288200, 39690, 27210 ); + test_vehicle( "electric_car", 948443, 372500, 231100, 25020, 14280 ); + test_vehicle( "suv", 1221594, 1210000, 695900, 93430, 37220 ); test_vehicle( "motorcycle", 162585, 120300, 100900, 63320, 51130 ); test_vehicle( "quad_bike", 264845, 116100, 116100, 46770, 46770 ); test_vehicle( "scooter", 55441, 235900, 235900, 174700, 174700 ); - test_vehicle( "superbike", 241585, 109800, 65300, 41990, 24140 ); - test_vehicle( "ambulance", 1850228, 623000, 511100, 77700, 57910 ); - test_vehicle( "fire_engine", 2606611, 1895000, 1585000, 337800, 261900 ); - test_vehicle( "fire_truck", 6441903, 420800, 80000, 19080, 4063 ); - test_vehicle( "truck_swat", 5994144, 682900, 130200, 29610, 7604 ); + test_vehicle( "superbike", 241585, 109800, 65300, 42000, 24140 ); + test_vehicle( "ambulance", 1726863, 623000, 538800, 83190, 69710 ); + test_vehicle( "fire_engine", 2483246, 1912000, 1665000, 355000, 295200 ); + test_vehicle( "fire_truck", 6195173, 428300, 92250, 19710, 4700 ); + test_vehicle( "truck_swat", 6482079, 649500, 97380, 28180, 6083 ); test_vehicle( "tractor_plow", 723658, 681200, 681200, 132700, 132700 ); - test_vehicle( "apc", 5802483, 1626000, 1119000, 130800, 85590 ); - test_vehicle( "humvee", 5503345, 767900, 306900, 25620, 9171 ); - test_vehicle( "road_roller", 8831620, 602500, 147100, 22760, 6925 ); + test_vehicle( "apc", 5900070, 1607000, 1086000, 125600, 80390 ); + test_vehicle( "humvee", 5991280, 739500, 296600, 23790, 7337 ); + test_vehicle( "road_roller", 8658909, 584800, 156400, 22760, 6925 ); test_vehicle( "golf_cart", 444630, 96000, 69390, 35490, 14200 ); // in reverse - test_vehicle( "beetle", 816469, 58970, 58870, 44560, 43060, 0, 0, true ); - test_vehicle( "car", 1120618, 76060, 76060, 44230, 24920, 0, 0, true ); - test_vehicle( "car_sports", 1155014, 353200, 268000, 35220, 19540, 0, 0, true ); - test_vehicle( "electric_car", 1047135, 356400, 202300, 22450, 10810, 0, 0, true ); - test_vehicle( "suv", 1320286, 112000, 111700, 66880, 31640, 0, 0, true ); + test_vehicle( "beetle", 717777, 58800, 58800, 45900, 44560, 0, 0, true ); + test_vehicle( "car", 1021926, 76390, 76260, 48330, 30270, 0, 0, true ); + test_vehicle( "car_sports", 1056322, 355300, 288600, 38670, 24580, 0, 0, true ); + test_vehicle( "electric_car", 948443, 373700, 231800, 25070, 14310, 0, 0, true ); + test_vehicle( "suv", 1221594, 114900, 112400, 70400, 35200, 0, 0, true ); test_vehicle( "motorcycle", 162585, 20070, 19030, 15490, 14890, 0, 0, true ); test_vehicle( "quad_bike", 264845, 19650, 19650, 15440, 15440, 0, 0, true ); test_vehicle( "scooter", 55441, 58790, 58790, 46320, 46320, 0, 0, true ); test_vehicle( "superbike", 241585, 18380, 10570, 13100, 8497, 0, 0, true ); - test_vehicle( "ambulance", 1850228, 58460, 57740, 42480, 39100, 0, 0, true ); - test_vehicle( "fire_engine", 2606611, 258000, 257800, 185600, 179400, 0, 0, true ); - test_vehicle( "fire_truck", 6441903, 58760, 59170, 18580, 3447, 0, 0, true ); - test_vehicle( "truck_swat", 5994144, 129300, 130100, 29350, 7668, 0, 0, true ); + test_vehicle( "ambulance", 1726863, 58600, 57910, 42480, 40260, 0, 0, true ); + test_vehicle( "fire_engine", 2483246, 257400, 257100, 185600, 179400, 0, 0, true ); + test_vehicle( "fire_truck", 6195173, 58700, 58860, 19630, 4471, 0, 0, true ); + test_vehicle( "truck_swat", 6482079, 129900, 130900, 26920, 5308, 0, 0, true ); test_vehicle( "tractor_plow", 723658, 72490, 72490, 53700, 53700, 0, 0, true ); - test_vehicle( "apc", 5802483, 381500, 382100, 123600, 82000, 0, 0, true ); - test_vehicle( "humvee", 5503345, 89940, 89940, 25780, 9086, 0, 0, true ); - test_vehicle( "road_roller", 8831620, 97490, 97690, 22880, 6606, 0, 0, true ); + test_vehicle( "apc", 5900070, 382000, 382600, 123100, 82750, 0, 0, true ); + test_vehicle( "humvee", 5991280, 89490, 89490, 24180, 7595, 0, 0, true ); + test_vehicle( "road_roller", 8658909, 97090, 97190, 22880, 6545, 0, 0, true ); test_vehicle( "golf_cart", 444630, 96150, 28800, 35560, 11150, 0, 0, true ); } From fe3189aad1e0235cc871d6d31d8ba309fe56cf2b Mon Sep 17 00:00:00 2001 From: Mark Langsdorf Date: Sat, 10 Apr 2021 02:30:34 -0500 Subject: [PATCH 364/453] Dark Skies Above: Surveillance drone scan and reinforcements (#48228) --- .../mapgen/map_extras/patrols.json | 25 ++++++ data/mods/Dark-Skies-Above/monattack.json | 26 ++++++ data/mods/Dark-Skies-Above/monspell.json | 15 ++++ .../monsters/alien_cyborgs.json | 34 +++++++ .../monsters/alien_robots.json | 28 +++++- src/monattack.cpp | 89 +++++++++++++++++++ src/monattack.h | 1 + src/monstergenerator.cpp | 1 + src/timed_event.cpp | 23 +++++ src/timed_event.h | 1 + 10 files changed, 242 insertions(+), 1 deletion(-) create mode 100644 data/mods/Dark-Skies-Above/mapgen/map_extras/patrols.json diff --git a/data/mods/Dark-Skies-Above/mapgen/map_extras/patrols.json b/data/mods/Dark-Skies-Above/mapgen/map_extras/patrols.json new file mode 100644 index 0000000000000..2476303940849 --- /dev/null +++ b/data/mods/Dark-Skies-Above/mapgen/map_extras/patrols.json @@ -0,0 +1,25 @@ +[ + { + "type": "mapgen", + "method": "json", + "update_mapgen_id": "mx_dsa_alrp", + "object": { + "place_monster": [ + { + "monster": "dks_mon_skirmsoldier", + "x": 12, + "y": 12, + "repeat": [ 3, 4 ], + "spawn_data": { "patrol": [ { "x": -10, "y": -10 }, { "x": 33, "y": -10 }, { "x": 33, "y": 33 }, { "x": 33, "y": -10 } ] } + } + ] + } + }, + { + "id": "mx_dsa_alrp", + "type": "map_extra", + "name": { "str": "DSA ALRP" }, + "description": "Alien light reconnaissance patrol.", + "generator": { "generator_method": "update_mapgen", "generator_id": "mx_dsa_alrp" } + } +] diff --git a/data/mods/Dark-Skies-Above/monattack.json b/data/mods/Dark-Skies-Above/monattack.json index c7e85ffcb9a47..ae924ef9cf4dc 100644 --- a/data/mods/Dark-Skies-Above/monattack.json +++ b/data/mods/Dark-Skies-Above/monattack.json @@ -42,5 +42,31 @@ "hit_dmg_npc": "The %1$s slashes !", "no_dmg_msg_u": "The %1$s attempts to cut you, but fails to penetrate your armor.", "no_dmg_msg_npc": "The %1$s tries to cut , but fails to penetrate their armor." + }, + { + "type": "monster_attack", + "attack_type": "melee", + "id": "melee_shock", + "cooldown": 20, + "move_cost": 150, + "damage_max_instance": [ { "damage_type": "electric", "amount": 8 }, { "damage_type": "stab", "amount": 6 } ], + "body_parts": [ + [ "foot_l", 2 ], + [ "foot_r", 2 ], + [ "leg_l", 3 ], + [ "leg_r", 3 ], + [ "hand_l", 2 ], + [ "hand_r", 2 ], + [ "head", 3 ], + [ "eyes", 2 ], + [ "mouth", 1 ], + [ "arm_l", 3 ], + [ "arm_r", 3 ], + [ "torso", 4 ] + ], + "hit_dmg_u": "The %1$s lances electricity into you!", + "hit_dmg_npc": "The %1$s lances with electricity!", + "no_dmg_msg_u": "The %1$s attempts to electrify you, but fails to penetrate your armor.", + "no_dmg_msg_npc": "The %1$s tries to electrify , but fails to penetrate their armor." } ] diff --git a/data/mods/Dark-Skies-Above/monspell.json b/data/mods/Dark-Skies-Above/monspell.json index a57b28498426e..5460cc86ac210 100644 --- a/data/mods/Dark-Skies-Above/monspell.json +++ b/data/mods/Dark-Skies-Above/monspell.json @@ -14,5 +14,20 @@ "min_duration": 425, "max_duration": 425, "flags": [ "SILENT", "NO_PROJECTILE" ] + }, + { + "type": "SPELL", + "id": "dks_summon_alrp", + "name": { "str": "Spawn ALRP" }, + "description": "Summons a squad of 3-4 skirmishers.", + "flags": [ "HOSTILE_SUMMON", "RANDOM_DAMAGE", "PERMANENT" ], + "valid_targets": [ "ground", "self" ], + "min_damage": 3, + "max_damage": 4, + "min_aoe": 2, + "max_aoe": 2, + "shape": "blast", + "effect": "summon", + "effect_str": "dks_mon_skirmsoldier" } ] diff --git a/data/mods/Dark-Skies-Above/monsters/alien_cyborgs.json b/data/mods/Dark-Skies-Above/monsters/alien_cyborgs.json index c4c5f5c7f78c1..7a26fb3c5dfbc 100644 --- a/data/mods/Dark-Skies-Above/monsters/alien_cyborgs.json +++ b/data/mods/Dark-Skies-Above/monsters/alien_cyborgs.json @@ -290,5 +290,39 @@ "anger_triggers": [ "FRIEND_ATTACKED", "HURT" ], "death_function": [ "NORMAL" ], "flags": [ "SEES", "HEARS", "SMELLS", "BASHES", "DESTROYS", "ACIDPROOF", "CAN_DIG", "ARTHROPOD_BLOOD" ] + }, + { + "id": "dks_mon_skirmsoldier", + "type": "MONSTER", + "name": { "str": "alien skirmisher" }, + "description": "A slouched bipedal figure, slightly smaller than an average adult human. Beneath woven full-body combat armor and a full suite of cybernetic modifications are glimpses of rubbery, abscessed flesh. It is capable of short, boosted jumps using a device on its back, closing gaps to cause havoc with its wicked integrated melee weapons. Severed organic parts dangle from its equipment, morbid trophies from past battles.", + "default_faction": "invader_alien", + "bodytype": "human", + "categories": [ "ALIEN" ], + "species": [ "ROBOT" ], + "volume": "52500 ml", + "weight": "71500 g", + "hp": 45, + "speed": 90, + "material": [ "steel" ], + "symbol": "$", + "aggression": 100, + "morale": 100, + "color": "light_gray", + "dodge": 1, + "melee_skill": 5, + "melee_dice": 4, + "melee_dice_sides": 3, + "armor_bash": 15, + "armor_stab": 25, + "armor_cut": 6, + "armor_fire": 15, + "armor_bullet": 35, + "vision_night": 5, + "special_attacks": [ { "type": "leap", "cooldown": 10, "max_range": 5 }, { "id": "melee_shock" } ], + "path_settings": { "max_dist": 5 }, + "death_function": [ "NORMAL" ], + "harvest": "dks_alien_cyborg", + "flags": [ "SEES", "HEARS", "SMELLS", "SWARMS", "WARM", "BASHES", "GROUP_BASH", "PRIORITIZE_TARGETS", "PATH_AVOID_DANGER_2" ] } ] diff --git a/data/mods/Dark-Skies-Above/monsters/alien_robots.json b/data/mods/Dark-Skies-Above/monsters/alien_robots.json index 625d40bb98338..e2267a8587ea3 100644 --- a/data/mods/Dark-Skies-Above/monsters/alien_robots.json +++ b/data/mods/Dark-Skies-Above/monsters/alien_robots.json @@ -1,4 +1,29 @@ [ + { + "id": "mon_dsa_alien_dispatch", + "type": "MONSTER", + "name": { "str": "alien dispatch system" }, + "description": "A monstrous intelligence, capable of teleporting drones and skirmishers to the planet, or dispatching larger aliens in drop pods.", + "default_faction": "invader_alien", + "looks_like": "mon_eyebot", + "categories": [ "ALIEN" ], + "species": [ "ROBOT" ], + "volume": "30000 ml", + "weight": "40750 g", + "hp": 400, + "speed": 100, + "material": [ "steel" ], + "symbol": "D", + "color": "red", + "dodge": 3, + "armor_bash": 8, + "armor_cut": 10, + "luminance": 5, + "path_settings": { "max_dist": 5 }, + "death_drops": { "groups": [ [ "robots", 4 ] ] }, + "death_function": [ "MELT" ], + "flags": [ "SEES", "FLIES", "ELECTRONIC", "COLDPROOF", "NO_BREATHE", "NOHEAD", "PRIORITIZE_TARGETS" ] + }, { "id": "mon_dks_glowdrone", "type": "MONSTER", @@ -20,7 +45,7 @@ "armor_cut": 10, "armor_bullet": 6, "luminance": 5, - "special_attacks": [ [ "SEARCHLIGHT", 1 ] ], + "special_attacks": [ [ "SEARCHLIGHT", 1 ], [ "DSA_DRONE_SCAN", 2 ] ], "path_settings": { "max_dist": 5 }, "death_drops": { "groups": [ [ "robots", 4 ], [ "eyebot", 1 ], [ "turret_searchlight", 1 ] ] }, "death_function": [ "BROKEN" ], @@ -52,6 +77,7 @@ "vision_night": 5, "special_attacks": [ [ "TAZER", 12 ], + [ "DSA_DRONE_SCAN", 5 ], { "id": "tool_slash" }, { "type": "spell", diff --git a/src/monattack.cpp b/src/monattack.cpp index ceaf9593c1517..5215543897c9a 100644 --- a/src/monattack.cpp +++ b/src/monattack.cpp @@ -5817,3 +5817,92 @@ bool mattack::speaker( monster *z ) SNIPPET.random_from_category( "speaker_warning" ).value_or( translation() ) ); return true; } + +bool mattack::dsa_drone_scan( monster *z ) +{ + z->moves -= 100; + constexpr int scan_range = 30; + // Select a target: the avatar or a nearby NPC. Must be visible and within scan range + Character *target = &get_player_character(); + Character &you = get_player_character(); + bool avatar_in_range = z->posz() == target->posz() && z->sees( target->pos() ) && + rl_dist( z->pos(), target->pos() ) <= scan_range; + const std::vector available = g->get_npcs_if( [&]( const npc & guy ) { + // TODO: Get rid of the z-level check when z-level vision gets "better" + return z->posz() == guy.posz() && z->sees( guy.pos() ) && + rl_dist( z->pos(), guy.pos() ) <= scan_range; + } ); + if( !avatar_in_range && available.empty() ) { + return true; + } + if( !available.empty() ) { + if( !avatar_in_range || + ( avatar_in_range && x_in_y( available.size(), available.size() + 1 ) ) ) { + target = random_entry( available ); + } + } + const std::string timestamp_str = "dsa_drone_scan_timestamp"; + const std::string weapons_str = "dsa_drone_scan_weapons_count"; + + // only check for weapons once every 10 seconds by timestap variable + int weapons_count = 0; + bool summon_reinforcements = false; + if( !target->get_value( weapons_str ).empty() ) { + weapons_count = std::stoi( target->get_value( weapons_str ) ); + } + + if( !target->get_value( timestamp_str ).empty() ) { + time_point last_check( std::stoi( target->get_value( timestamp_str ) ) ); + if( ( last_check + 10_seconds ) > calendar::turn ) { + return true; + } + // reset the weapons count if it has been more than an hour + if( ( last_check + 1_hours ) < calendar::turn ) { + weapons_count = 0; + } + } + target->set_value( timestamp_str, string_format( "%d", to_turn( calendar::turn ) ) ); + if( weapons_count < 3 ) { + if( target->weapon.is_gun() ) { + const gun_type_type &guntype = target->weapon.gun_type(); + if( guntype == gun_type_type( "rifle" ) || + guntype == gun_type_type( "shotgun" ) || + guntype == gun_type_type( "launcher" ) ) { + weapons_count += 2; + } else { + weapons_count += 1; + } + } else { + for( const item &worn_item : target->worn ) { + if( worn_item.is_gun() ) { + weapons_count += 1; + break; + } + } + } + summon_reinforcements = weapons_count >= 3; + } + target->set_value( weapons_str, string_format( "%d", weapons_count ) ); + + if( you.sees( z->pos() ) ) { + target->add_msg_player_or_npc( _( "The %s shines its light at you." ), + _( "The %s shines its light at ." ), + z->name() ); + } + std::string warning_signal = _( "a dull beep" ); + if( weapons_count == 1 ) { + warning_signal = _( "an ominous hum" ); + } else if( weapons_count == 2 ) { + warning_signal = _( "a threatening whirr" ); + } else if( weapons_count >= 3 ) { + warning_signal = _( "a high-pitched shriek" ); + } + warning_signal = string_format( _( "%s from the %s." ), warning_signal, z->name() ); + sounds::sound( z->pos(), 15 + 10 * weapons_count, sounds::sound_t::alarm, warning_signal ); + if( summon_reinforcements ) { + get_timed_events().add( timed_event_type::DSA_ALRP_SUMMON, + calendar::turn + rng( 5_turns, 10_turns ), + 0, target->global_sm_location() ); + } + return true; +} diff --git a/src/monattack.h b/src/monattack.h index 3f9e344d9ed80..3f976245600f6 100644 --- a/src/monattack.h +++ b/src/monattack.h @@ -107,6 +107,7 @@ bool grenadier( monster *z ); bool grenadier_elite( monster *z ); bool doot( monster *z ); bool zombie_fuse( monster *z ); +bool dsa_drone_scan( monster *z ); void taze( monster *z, Creature *target ); void rifle( monster *z, Creature *target ); // Automated M4 diff --git a/src/monstergenerator.cpp b/src/monstergenerator.cpp index 18dc7e8886a52..31bc369de1767 100644 --- a/src/monstergenerator.cpp +++ b/src/monstergenerator.cpp @@ -652,6 +652,7 @@ void MonsterGenerator::init_attack() add_hardcoded_attack( "GRAB", mattack::grab ); add_hardcoded_attack( "GRAB_DRAG", mattack::grab_drag ); add_hardcoded_attack( "DOOT", mattack::doot ); + add_hardcoded_attack( "DSA_DRONE_SCAN", mattack::dsa_drone_scan ); add_hardcoded_attack( "ZOMBIE_FUSE", mattack::zombie_fuse ); } diff --git a/src/timed_event.cpp b/src/timed_event.cpp index 983f521d77bd9..cc3536bdd20ae 100644 --- a/src/timed_event.cpp +++ b/src/timed_event.cpp @@ -8,6 +8,8 @@ #include "avatar.h" #include "avatar_action.h" #include "character.h" +#include "coordinate_conversions.h" +#include "coordinates.h" #include "debug.h" #include "enums.h" #include "event.h" @@ -15,7 +17,9 @@ #include "game.h" #include "game_constants.h" #include "line.h" +#include "magic.h" #include "map.h" +#include "map_extras.h" #include "map_iterator.h" #include "mapdata.h" #include "memorial_logger.h" @@ -35,6 +39,7 @@ static const mtype_id mon_amigara_horror( "mon_amigara_horror" ); static const mtype_id mon_copbot( "mon_copbot" ); static const mtype_id mon_dark_wyrm( "mon_dark_wyrm" ); static const mtype_id mon_dermatik( "mon_dermatik" ); +static const mtype_id mon_dsa_alien_dispatch( "mon_dsa_alien_dispatch" ); static const mtype_id mon_eyebot( "mon_eyebot" ); static const mtype_id mon_riotbot( "mon_riotbot" ); static const mtype_id mon_sewer_snake( "mon_sewer_snake" ); @@ -241,6 +246,24 @@ void timed_event::actualize() } break; + case timed_event_type::DSA_ALRP_SUMMON: { + const tripoint u_pos = player_character.global_sm_location(); + if( rl_dist( u_pos, map_point ) <= 4 ) { + const tripoint spot = here.getlocal( sm_to_ms_copy( map_point ) ); + monster dispatcher( mon_dsa_alien_dispatch ); + fake_spell summoning( spell_id( "dks_summon_alrp" ), true, 12 ); + summoning.get_spell().cast_all_effects( dispatcher, spot ); + } else { + tinymap mx_map; + tripoint_abs_sm map_pt( map_point ); + mx_map.load( map_pt, false ); + MapExtras::apply_function( "mx_dsa_alrp", mx_map, map_point ); + g->load_npcs(); + here.invalidate_map_cache( map_point.z ); + } + } + break; + default: // Nothing happens for other events break; diff --git a/src/timed_event.h b/src/timed_event.h index d408fa06477c2..bbf04553d576e 100644 --- a/src/timed_event.h +++ b/src/timed_event.h @@ -20,6 +20,7 @@ enum class timed_event_type : int { TEMPLE_SPAWN, DIM, ARTIFACT_LIGHT, + DSA_ALRP_SUMMON, NUM_TIMED_EVENT_TYPES }; From cf4b6eae2505483475792d237a8c8921c5f72914 Mon Sep 17 00:00:00 2001 From: Brian-Otten <47374323+Brian-Otten@users.noreply.github.com> Date: Sat, 10 Apr 2021 09:44:36 +0200 Subject: [PATCH 365/453] simple makeshift glaive (#48386) --- .../json/items/melee/spears_and_polearms.json | 31 +++++++++++++++++++ data/json/items/tool/misc.json | 21 ------------- data/json/martialarts.json | 3 ++ data/json/recipes/weapon/cutting.json | 27 +++++++++++++++- data/json/recipes/weapon/piercing.json | 6 ---- 5 files changed, 60 insertions(+), 28 deletions(-) diff --git a/data/json/items/melee/spears_and_polearms.json b/data/json/items/melee/spears_and_polearms.json index 94ca953eb09c0..442d787531328 100644 --- a/data/json/items/melee/spears_and_polearms.json +++ b/data/json/items/melee/spears_and_polearms.json @@ -79,6 +79,37 @@ "qualities": [ [ "CUT", 1 ], [ "BUTCHER", -22 ] ], "flags": [ "FRAGILE_MELEE", "NONCONDUCTIVE", "POLEARM", "SHEATH_SPEAR", "REACH_ATTACK", "ALWAYS_TWOHAND" ] }, + { + "id": "makeshift_halberd", + "type": "GENERIC", + "name": { "str": "simple makeshift glaive" }, + "//": "Name changed to simple makeshift glaive, but changing the id would break e.g. tilesets.", + "description": "This is a large blade attached to a stout section of tree branch. It could do a considerable amount of damage.", + "weight": "1800 g", + "volume": "3 L", + "longest_side": "180 cm", + "price": 5000, + "price_postapoc": 250, + "to_hit": -1, + "bashing": 13, + "cutting": 31, + "material": [ "steel", "wood" ], + "symbol": "/", + "color": "light_gray", + "techniques": [ "WBLOCK_1" ], + "qualities": [ [ "CUT", 1 ], [ "BUTCHER", -42 ] ], + "flags": [ "REACH_ATTACK", "POLEARM", "NONCONDUCTIVE", "SHEATH_SPEAR", "FRAGILE_MELEE" ] + }, + { + "id": "makeshift_glaive", + "type": "GENERIC", + "copy-from": "makeshift_halberd", + "name": { "str": "makeshift glaive" }, + "description": "A stout tree branch that has been carefully split and reinforced. At the split point, a sharp blade has been bolted into place and reinforced with layers of sturdy wrapped bindings.", + "price_postapoc": 400, + "qualities": [ [ "CUT", 1 ], [ "BUTCHER", -28 ] ], + "delete": { "flags": [ "FRAGILE_MELEE" ] } + }, { "id": "spear_spike", "type": "TOOL", diff --git a/data/json/items/tool/misc.json b/data/json/items/tool/misc.json index cb2947fa5a920..c6f851e5ba728 100644 --- a/data/json/items/tool/misc.json +++ b/data/json/items/tool/misc.json @@ -432,27 +432,6 @@ "charges_per_use": 1, "use_action": [ "WATER_PURIFIER" ] }, - { - "id": "makeshift_halberd", - "type": "GENERIC", - "name": { "str": "makeshift glaive" }, - "//": "Name changed to glaive, but changing the id would break e.g. tilesets.", - "description": "This is a large blade attached to a stout section of tree branch. It could do a considerable amount of damage.", - "weight": "1800 g", - "volume": "3 L", - "longest_side": "180 cm", - "price": 5000, - "price_postapoc": 250, - "to_hit": -1, - "bashing": 13, - "cutting": 31, - "material": [ "steel", "wood" ], - "symbol": "/", - "color": "light_gray", - "techniques": [ "WBLOCK_1" ], - "qualities": [ [ "CUT", 1 ], [ "BUTCHER", -42 ] ], - "flags": [ "REACH_ATTACK", "POLEARM", "NONCONDUCTIVE", "SHEATH_SPEAR", "FRAGILE_MELEE" ] - }, { "type": "GENERIC", "id": "mind_splicer", diff --git a/data/json/martialarts.json b/data/json/martialarts.json index 025e18de40ff9..077a1485acf3b 100644 --- a/data/json/martialarts.json +++ b/data/json/martialarts.json @@ -520,6 +520,7 @@ "lucern_hammer", "lucern_hammerfake", "makeshift_halberd", + "makeshift_glaive", "pickaxe", "poleaxe", "primitive_axe" @@ -1187,6 +1188,7 @@ "machete", "machete_gimmick", "makeshift_halberd", + "makeshift_glaive", "makeshift_knife", "makeshift_machete", "naginata", @@ -1318,6 +1320,7 @@ "naginata_fake", "long_pole", "makeshift_halberd", + "makeshift_glaive", "pike", "pike_inferior", "pike_fake", diff --git a/data/json/recipes/weapon/cutting.json b/data/json/recipes/weapon/cutting.json index 2e403db2c9bd0..a7b30c2414ba6 100644 --- a/data/json/recipes/weapon/cutting.json +++ b/data/json/recipes/weapon/cutting.json @@ -132,6 +132,7 @@ "type": "recipe", "activity_level": "LIGHT_EXERCISE", "result": "makeshift_halberd", + "//": "this makes the simple makeshift glaive, but changing the id would break e.g. tilesets.", "category": "CC_WEAPON", "subcategory": "CSC_WEAPON_CUTTING", "skill_used": "fabrication", @@ -139,7 +140,31 @@ "reversible": true, "autolearn": true, "proficiencies": [ { "proficiency": "prof_carving", "time_multiplier": 1.5, "fail_multiplier": 1 } ], - "components": [ [ [ "duct_tape", 100 ] ], [ [ "blade", 1 ] ], [ [ "stick_long", 1 ] ] ] + "components": [ + [ [ "duct_tape", 100 ] ], + [ [ "blade", 1 ], [ "knife_meat_cleaver", 1 ], [ "knife_vegetable_cleaver", 1 ] ], + [ [ "stick_long", 1 ] ] + ] + }, + { + "type": "recipe", + "activity_level": "MODERATE_EXERCISE", + "result": "makeshift_glaive", + "category": "CC_WEAPON", + "subcategory": "CSC_WEAPON_PIERCING", + "skill_used": "fabrication", + "difficulty": 1, + "time": "45 m", + "reversible": true, + "autolearn": true, + "qualities": [ { "id": "CUT", "level": 1 }, { "id": "HAMMER", "level": 1 }, { "id": "DRILL", "level": 1 } ], + "proficiencies": [ { "proficiency": "prof_carving", "time_multiplier": 1.5, "fail_multiplier": 1.5 } ], + "components": [ + [ [ "duct_tape", 100 ] ], + [ [ "blade", 1 ], [ "knife_meat_cleaver", 1 ], [ "knife_vegetable_cleaver", 1 ] ], + [ [ "stick_long", 1 ] ], + [ [ "cordage", 2, "LIST" ] ] + ] }, { "type": "recipe", diff --git a/data/json/recipes/weapon/piercing.json b/data/json/recipes/weapon/piercing.json index 87e21aa990d2b..0177d47a17d13 100644 --- a/data/json/recipes/weapon/piercing.json +++ b/data/json/recipes/weapon/piercing.json @@ -615,9 +615,6 @@ [ "knife_butcher", 1 ], [ "knife_chef", 1 ], [ "knife_carving", 1 ], - [ "knife_vegetable_cleaver", 1 ], - [ "knife_meat_cleaver", 1 ], - [ "blade", 1 ], [ "knife_combat", 1 ], [ "knife_combat_mod", 1 ], [ "knife_hunting", 1 ], @@ -650,9 +647,6 @@ [ "knife_butcher", 1 ], [ "knife_chef", 1 ], [ "knife_carving", 1 ], - [ "knife_vegetable_cleaver", 1 ], - [ "knife_meat_cleaver", 1 ], - [ "blade", 1 ], [ "knife_combat", 1 ], [ "knife_combat_mod", 1 ], [ "knife_hunting", 1 ], From c4a4e34af53cc880c6a02880fec503378fd01886 Mon Sep 17 00:00:00 2001 From: Alexey Mostovoy <1931904+AMurkin@users.noreply.github.com> Date: Sat, 10 Apr 2021 12:41:13 +0300 Subject: [PATCH 366/453] Mark string for translation --- src/iexamine.cpp | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-) diff --git a/src/iexamine.cpp b/src/iexamine.cpp index 69c551ae367c2..960a14c74ae90 100644 --- a/src/iexamine.cpp +++ b/src/iexamine.cpp @@ -4760,8 +4760,9 @@ void iexamine::autodoc( player &p, const tripoint &examp ) } autodoc_header += - string_format( "\n\nInternal supplies:\n Arm splints: %d\n Leg splints: %d", - arm_splints.size(), leg_splints.size() ); + string_format( + _( "\n\nInternal supplies:\n Arm splints: %d\n Leg splints: %d" ), + arm_splints.size(), leg_splints.size() ); uilist amenu; amenu.text = autodoc_header; From aae4907cb67d4491c34b5962ad6142752c32eff0 Mon Sep 17 00:00:00 2001 From: John Bytheway Date: Sun, 11 Apr 2021 05:18:31 -0400 Subject: [PATCH 367/453] Enable clang-tidy check for noexcept move constructors (#48467) * Mark many things noexcept Mark all our move constructors and move assignment operators noexcept. * Enable performance-noexcept-move-constructors This clang-tidy check looks for mone constructors which were are not noexcept, which can cause poor performance when those classes are e.g. used in a std::vector. --- .clang-tidy | 1 - src/character.cpp | 4 ++-- src/character.h | 4 ++-- src/clone_ptr.h | 4 ++-- src/creature.cpp | 5 +++++ src/creature.h | 8 ++++---- src/item.cpp | 4 ++-- src/item.h | 4 ++-- src/monster.cpp | 4 ++-- src/monster.h | 4 ++-- src/npc.cpp | 4 ++-- src/npc.h | 4 ++-- src/player.cpp | 4 ++-- src/player.h | 4 ++-- src/player_activity.h | 2 +- src/projectile.cpp | 2 +- src/projectile.h | 2 +- src/safe_reference.cpp | 16 ++++++++++++++++ src/safe_reference.h | 2 ++ src/submap.cpp | 4 ++-- src/submap.h | 4 ++-- src/value_ptr.h | 4 ++-- src/veh_type.cpp | 4 ++-- src/veh_type.h | 4 ++-- src/weighted_list.h | 6 ++++++ 25 files changed, 68 insertions(+), 40 deletions(-) diff --git a/.clang-tidy b/.clang-tidy index 2b0d987887aec..e4b6c9c5467d6 100644 --- a/.clang-tidy +++ b/.clang-tidy @@ -37,7 +37,6 @@ readability-*,\ -modernize-use-default-member-init,\ -modernize-use-emplace,\ -performance-inefficient-vector-operation,\ --performance-noexcept-move-constructor,\ -performance-implicit-conversion-in-loop,\ -performance-inefficient-string-concatenation,\ -performance-type-promotion-in-math-fn,\ diff --git a/src/character.cpp b/src/character.cpp index 9813694d1d924..1aba11b701be3 100644 --- a/src/character.cpp +++ b/src/character.cpp @@ -488,8 +488,8 @@ Character::Character() : // *INDENT-ON* Character::~Character() = default; -Character::Character( Character && ) = default; -Character &Character::operator=( Character && ) = default; +Character::Character( Character && ) noexcept = default; +Character &Character::operator=( Character && ) noexcept = default; void Character::setID( character_id i, bool force ) { diff --git a/src/character.h b/src/character.h index eedd8b4dadb43..600a9b78f5db6 100644 --- a/src/character.h +++ b/src/character.h @@ -2747,8 +2747,8 @@ class Character : public Creature, public visitable protected: Character(); - Character( Character && ); - Character &operator=( Character && ); + Character( Character && ) noexcept; + Character &operator=( Character && ) noexcept; struct trait_data { /** Whether the mutation is activated. */ bool powered = false; diff --git a/src/clone_ptr.h b/src/clone_ptr.h index 28859daff3f63..0001a8dc2efe2 100644 --- a/src/clone_ptr.h +++ b/src/clone_ptr.h @@ -14,12 +14,12 @@ class clone_ptr // NOLINTNEXTLINE(google-explicit-constructor) clone_ptr( std::nullptr_t ) {} clone_ptr( const clone_ptr &other ) : p_( other.p_ ? other.p_->clone() : nullptr ) {} - clone_ptr( clone_ptr && ) = default; + clone_ptr( clone_ptr && ) noexcept = default; clone_ptr &operator=( const clone_ptr &other ) { p_ = other.p_ ? other.p_->clone() : nullptr; return *this; } - clone_ptr &operator=( clone_ptr && ) = default; + clone_ptr &operator=( clone_ptr && ) noexcept = default; // implicit conversion from unique_ptr template diff --git a/src/creature.cpp b/src/creature.cpp index 60d39652bfe13..6d8a4f4651fc0 100644 --- a/src/creature.cpp +++ b/src/creature.cpp @@ -114,6 +114,11 @@ Creature::Creature() fake = false; } +Creature::Creature( const Creature & ) = default; +Creature::Creature( Creature && ) noexcept = default; +Creature &Creature::operator=( const Creature & ) = default; +Creature &Creature::operator=( Creature && ) noexcept = default; + Creature::~Creature() = default; std::vector Creature::get_grammatical_genders() const diff --git a/src/creature.h b/src/creature.h index 799826d71e785..3915e0912f098 100644 --- a/src/creature.h +++ b/src/creature.h @@ -1172,10 +1172,10 @@ class Creature : public location, public viewer bool fake = false; Creature(); - Creature( const Creature & ) = default; - Creature( Creature && ) = default; - Creature &operator=( const Creature & ) = default; - Creature &operator=( Creature && ) = default; + Creature( const Creature & ); + Creature( Creature && ) noexcept; + Creature &operator=( const Creature & ); + Creature &operator=( Creature && ) noexcept; protected: virtual void on_stat_change( const std::string &, int ) {} diff --git a/src/item.cpp b/src/item.cpp index cdf9494d421f7..b19d3270a1280 100644 --- a/src/item.cpp +++ b/src/item.cpp @@ -437,10 +437,10 @@ item::item( const recipe *rec, item &component ) } item::item( const item & ) = default; -item::item( item && ) = default; +item::item( item && ) noexcept = default; item::~item() = default; item &item::operator=( const item & ) = default; -item &item::operator=( item && ) = default; +item &item::operator=( item && ) noexcept = default; item item::make_corpse( const mtype_id &mt, time_point turn, const std::string &name, const int upgrade_time ) diff --git a/src/item.h b/src/item.h index 75ccd1f5c0602..ad11c22a00657 100644 --- a/src/item.h +++ b/src/item.h @@ -180,9 +180,9 @@ class item : public visitable item(); - item( item && ); + item( item && ) noexcept; item( const item & ); - item &operator=( item && ); + item &operator=( item && ) noexcept; item &operator=( const item & ); explicit item( const itype_id &id, time_point turn = calendar::turn, int qty = -1 ); diff --git a/src/monster.cpp b/src/monster.cpp index 991485db63c6b..9b92c0e91c600 100644 --- a/src/monster.cpp +++ b/src/monster.cpp @@ -269,10 +269,10 @@ monster::monster( const mtype_id &id, const tripoint &p ) : monster( id ) } monster::monster( const monster & ) = default; -monster::monster( monster && ) = default; +monster::monster( monster && ) noexcept = default; monster::~monster() = default; monster &monster::operator=( const monster & ) = default; -monster &monster::operator=( monster && ) = default; +monster &monster::operator=( monster && ) noexcept = default; void monster::setpos( const tripoint &p ) { diff --git a/src/monster.h b/src/monster.h index 0297d4b3e4322..4ab96e8b615c5 100644 --- a/src/monster.h +++ b/src/monster.h @@ -90,10 +90,10 @@ class monster : public Creature explicit monster( const mtype_id &id ); monster( const mtype_id &id, const tripoint &pos ); monster( const monster & ); - monster( monster && ); + monster( monster && ) noexcept; ~monster() override; monster &operator=( const monster & ); - monster &operator=( monster && ); + monster &operator=( monster && ) noexcept; bool is_monster() const override { return true; diff --git a/src/npc.cpp b/src/npc.cpp index 1586fd686b8cd..7a69b21c4f04e 100644 --- a/src/npc.cpp +++ b/src/npc.cpp @@ -204,8 +204,8 @@ standard_npc::standard_npc( const std::string &name, const tripoint &pos, } } -npc::npc( npc && ) = default; -npc &npc::operator=( npc && ) = default; +npc::npc( npc && ) noexcept = default; +npc &npc::operator=( npc && ) noexcept = default; static std::map, npc_template> npc_templates; diff --git a/src/npc.h b/src/npc.h index 7554cb98fb431..3e380f7cafd61 100644 --- a/src/npc.h +++ b/src/npc.h @@ -761,9 +761,9 @@ class npc : public player npc(); npc( const npc & ) = delete; - npc( npc && ); + npc( npc && ) noexcept; npc &operator=( const npc & ) = delete; - npc &operator=( npc && ); + npc &operator=( npc && ) noexcept; ~npc() override; bool is_player() const override { diff --git a/src/player.cpp b/src/player.cpp index 2fb5b0e81c8b8..4d606de86667e 100644 --- a/src/player.cpp +++ b/src/player.cpp @@ -226,8 +226,8 @@ player::player() } player::~player() = default; -player::player( player && ) = default; -player &player::operator=( player && ) = default; +player::player( player && ) noexcept = default; +player &player::operator=( player && ) noexcept = default; void player::normalize() { diff --git a/src/player.h b/src/player.h index eb8a12fac4d7b..c683d4ee8bc7d 100644 --- a/src/player.h +++ b/src/player.h @@ -79,10 +79,10 @@ class player : public Character public: player(); player( const player & ) = delete; - player( player && ); + player( player && ) noexcept; ~player() override; player &operator=( const player & ) = delete; - player &operator=( player && ); + player &operator=( player && ) noexcept; /** Calls Character::normalize() * normalizes HP and body temperature diff --git a/src/player_activity.h b/src/player_activity.h index 82b2e5d9d21f9..d9811ef6d3dda 100644 --- a/src/player_activity.h +++ b/src/player_activity.h @@ -87,7 +87,7 @@ class player_activity player_activity( player_activity && ) noexcept = default; player_activity( const player_activity & ) = default; - player_activity &operator=( player_activity && ) = default; + player_activity &operator=( player_activity && ) noexcept = default; player_activity &operator=( const player_activity & ) = default; explicit operator bool() const { diff --git a/src/projectile.cpp b/src/projectile.cpp index 25a0df1616f51..1a3ed96063911 100644 --- a/src/projectile.cpp +++ b/src/projectile.cpp @@ -25,7 +25,7 @@ projectile::projectile() : projectile::~projectile() = default; -projectile::projectile( projectile && ) = default; +projectile::projectile( projectile && ) noexcept = default; projectile::projectile( const projectile &other ) { diff --git a/src/projectile.h b/src/projectile.h index 09cd211cd5d12..7d246c5812b02 100644 --- a/src/projectile.h +++ b/src/projectile.h @@ -46,7 +46,7 @@ struct projectile { projectile(); projectile( const projectile & ); - projectile( projectile && ); + projectile( projectile && ) noexcept; projectile &operator=( const projectile & ); ~projectile(); diff --git a/src/safe_reference.cpp b/src/safe_reference.cpp index d52082f7a93ee..6dd4c6e6ee924 100644 --- a/src/safe_reference.cpp +++ b/src/safe_reference.cpp @@ -1,5 +1,8 @@ #include "safe_reference.h" +static_assert( std::is_nothrow_move_constructible::value, "" ); +static_assert( std::is_nothrow_move_assignable::value, "" ); + safe_reference_anchor::safe_reference_anchor() { impl = std::make_shared(); @@ -9,8 +12,21 @@ safe_reference_anchor::safe_reference_anchor( const safe_reference_anchor & ) : safe_reference_anchor() {} +// Technically the move constructor and move assignment can throw bad_alloc, +// but we have no way to recover from that so mark it noexcept anyway; will +// cause terminate on out-of-memory. +safe_reference_anchor::safe_reference_anchor( safe_reference_anchor && ) noexcept : + safe_reference_anchor() +{} + safe_reference_anchor &safe_reference_anchor::operator=( const safe_reference_anchor & ) { impl = std::make_shared(); return *this; } + +safe_reference_anchor &safe_reference_anchor::operator=( safe_reference_anchor && ) noexcept +{ + impl = std::make_shared(); + return *this; +} diff --git a/src/safe_reference.h b/src/safe_reference.h index 2c660630e46f0..cdb1488ea1950 100644 --- a/src/safe_reference.h +++ b/src/safe_reference.h @@ -58,7 +58,9 @@ class safe_reference_anchor public: safe_reference_anchor(); safe_reference_anchor( const safe_reference_anchor & ); + safe_reference_anchor( safe_reference_anchor && ) noexcept; safe_reference_anchor &operator=( const safe_reference_anchor & ); + safe_reference_anchor &operator=( safe_reference_anchor && ) noexcept; template safe_reference reference_to( T *object ) { diff --git a/src/submap.cpp b/src/submap.cpp index 07cbedf62a7c8..cc424848e9a11 100644 --- a/src/submap.cpp +++ b/src/submap.cpp @@ -36,10 +36,10 @@ submap::submap() is_uniform = false; } -submap::submap( submap && ) = default; +submap::submap( submap && ) noexcept = default; submap::~submap() = default; -submap &submap::operator=( submap && ) = default; +submap &submap::operator=( submap && ) noexcept = default; static const std::string COSMETICS_GRAFFITI( "GRAFFITI" ); static const std::string COSMETICS_SIGNAGE( "SIGNAGE" ); diff --git a/src/submap.h b/src/submap.h index 5f0d8cfa71316..a08a681b9d32c 100644 --- a/src/submap.h +++ b/src/submap.h @@ -65,10 +65,10 @@ class submap : maptile_soa { public: submap(); - submap( submap && ); + submap( submap && ) noexcept; ~submap(); - submap &operator=( submap && ); + submap &operator=( submap && ) noexcept; trap_id get_trap( const point &p ) const { return trp[p.x][p.y]; diff --git a/src/value_ptr.h b/src/value_ptr.h index 5ade27a90c547..1266c7c7c619a 100644 --- a/src/value_ptr.h +++ b/src/value_ptr.h @@ -19,13 +19,13 @@ class value_ptr : public std::unique_ptr { public: value_ptr() = default; - value_ptr( value_ptr && ) = default; + value_ptr( value_ptr && ) noexcept = default; // NOLINTNEXTLINE(google-explicit-constructor) value_ptr( std::nullptr_t ) {} explicit value_ptr( T *value ) : std::unique_ptr( value ) {} value_ptr( const value_ptr &other ) : std::unique_ptr( other ? new T( *other ) : nullptr ) {} - value_ptr &operator=( value_ptr other ) { + value_ptr &operator=( value_ptr other ) noexcept { std::unique_ptr::operator=( std::move( other ) ); return *this; } diff --git a/src/veh_type.cpp b/src/veh_type.cpp index 1af5c6fe09cca..115dd218f96d5 100644 --- a/src/veh_type.cpp +++ b/src/veh_type.cpp @@ -1069,10 +1069,10 @@ bool string_id::is_valid() const } vehicle_prototype::vehicle_prototype() = default; -vehicle_prototype::vehicle_prototype( vehicle_prototype && ) = default; +vehicle_prototype::vehicle_prototype( vehicle_prototype && ) noexcept = default; vehicle_prototype::~vehicle_prototype() = default; -vehicle_prototype &vehicle_prototype::operator=( vehicle_prototype && ) = default; +vehicle_prototype &vehicle_prototype::operator=( vehicle_prototype && ) noexcept = default; /** *Caches a vehicle definition from a JsonObject to be loaded after itypes is initialized. diff --git a/src/veh_type.h b/src/veh_type.h index 923a3d2677d24..0e7febb173abf 100644 --- a/src/veh_type.h +++ b/src/veh_type.h @@ -495,10 +495,10 @@ struct vehicle_prototype { }; vehicle_prototype(); - vehicle_prototype( vehicle_prototype && ); + vehicle_prototype( vehicle_prototype && ) noexcept; ~vehicle_prototype(); - vehicle_prototype &operator=( vehicle_prototype && ); + vehicle_prototype &operator=( vehicle_prototype && ) noexcept; translation name; std::vector parts; diff --git a/src/weighted_list.h b/src/weighted_list.h index 065986e498b8e..57919982ef016 100644 --- a/src/weighted_list.h +++ b/src/weighted_list.h @@ -19,6 +19,10 @@ template struct weighted_object { template struct weighted_list { weighted_list() : total_weight( 0 ) { } + weighted_list( const weighted_list & ) = default; + weighted_list( weighted_list && ) noexcept = default; + weighted_list &operator=( const weighted_list & ) = default; + weighted_list &operator=( weighted_list && ) noexcept = default; virtual ~weighted_list() = default; /** @@ -224,6 +228,8 @@ template struct weighted_int_list : public weighted_list { std::vector precalc_array; }; +static_assert( std::is_nothrow_move_constructible>::value, "" ); + template struct weighted_float_list : public weighted_list { // TODO: precalc using alias method From eb92fd5e4111460b606c58f3c5db3aaa64b51253 Mon Sep 17 00:00:00 2001 From: Maleclypse <54345792+Maleclypse@users.noreply.github.com> Date: Sun, 11 Apr 2021 04:21:27 -0500 Subject: [PATCH 368/453] Retractable security gates (#48336) --- .../terrain-fences-gates.json | 76 +++++++++++++++++++ data/json/mapgen/mall/mall_ground.json | 10 ++- src/activity_actor.cpp | 3 + src/activity_handlers.cpp | 9 +++ src/iuse.cpp | 6 ++ src/mapdata.cpp | 4 + src/mapdata.h | 1 + 7 files changed, 105 insertions(+), 4 deletions(-) diff --git a/data/json/furniture_and_terrain/terrain-fences-gates.json b/data/json/furniture_and_terrain/terrain-fences-gates.json index 61412734e2956..56281da8f0a36 100644 --- a/data/json/furniture_and_terrain/terrain-fences-gates.json +++ b/data/json/furniture_and_terrain/terrain-fences-gates.json @@ -128,6 +128,82 @@ ] } }, + { + "type": "terrain", + "id": "t_retractable_gate_l", + "name": "locked retractable gate", + "description": "A retractable security gate. The latch on this one is locked. With the right tools, you could cut the metal fence or disable the lock.", + "symbol": "+", + "color": "cyan", + "move_cost": 0, + "flags": [ "TRANSPARENT", "PERMEABLE", "LOCKED", "PICKABLE", "THIN_OBSTACLE" ], + "connects_to": "WALL", + "examine_action": "locked_object_pickable", + "bash": { + "str_min": 17, + "str_max": 175, + "str_min_blocked": 15, + "str_max_blocked": 175, + "sound": "metal screeching!", + "sound_fail": "clang!", + "ter_set": "t_null", + "items": [ + { "item": "wire", "count": [ 8, 20 ] }, + { "item": "chain", "count": [ 1, 2 ] }, + { "item": "scrap", "count": [ 0, 12 ] } + ] + } + }, + { + "type": "terrain", + "id": "t_retractable_gate_c", + "name": "closed retractable gate", + "description": "A retractable security gate with a latch system to stay closed.", + "symbol": "+", + "color": "cyan", + "move_cost": 0, + "flags": [ "TRANSPARENT", "DOOR", "PERMEABLE", "THIN_OBSTACLE" ], + "connects_to": "WALL", + "open": "t_retractable_gate_o", + "bash": { + "str_min": 17, + "str_max": 175, + "str_min_blocked": 20, + "str_max_blocked": 100, + "sound": "metal screeching!", + "sound_fail": "clang!", + "ter_set": "t_null", + "items": [ + { "item": "wire", "count": [ 6, 15 ] }, + { "item": "chain", "count": [ 1, 2 ] }, + { "item": "scrap", "count": [ 0, 12 ] } + ] + } + }, + { + "type": "terrain", + "id": "t_retractable_gate_o", + "name": "open retractable gate", + "description": "A retractable security gate with a latch system to stay closed. The latch is undone, so the gate has retracted up.", + "symbol": ".", + "color": "cyan", + "move_cost": 2, + "flags": [ "TRANSPARENT", "FLAT", "ROAD" ], + "connects_to": "WALL", + "close": "t_retractable_gate_c", + "bash": { + "str_min": 5, + "str_max": 150, + "sound": "metal screeching!", + "sound_fail": "clang!", + "ter_set": "t_null", + "items": [ + { "item": "wire", "count": [ 6, 15 ] }, + { "item": "pipe", "count": [ 6, 15 ] }, + { "item": "scrap", "count": [ 0, 12 ] } + ] + } + }, { "type": "terrain", "id": "t_fencegate_c", diff --git a/data/json/mapgen/mall/mall_ground.json b/data/json/mapgen/mall/mall_ground.json index 2f1b5032f5244..c42e0f1e7ef94 100644 --- a/data/json/mapgen/mall/mall_ground.json +++ b/data/json/mapgen/mall/mall_ground.json @@ -1434,7 +1434,7 @@ "ւГ˽˽˽˽˽˽˽˽˽˽˽˽˽˽˽˽˽˽˽˽˽˽˽˽˽˽ГГГɱɱ||||||^^99@@@99^9ɅɅɅ9Ʌ9^M^^M^^MMM^MM^H%,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,", "ւГɔɔɔɔɔɔɔ˽˽˽˽˽˽˽˽˽˽˽˽ɔɔɔɔɔɔɔГГɱЯɱHd|T^^^^9999999^9Ʌ999Ʌ9^^^^^^^^^^^^^dH.,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,", "ւГ˽˽˽˽˽˽˽˽˽˽˽˽˽˽˽˽˽˽˽˽˽˽˽˽˽˽ГГɱϻɱHy|T^^M^99ǝǝǝ99^9Ʌ9ɅɅɅ9^^^^^^777777^^H..FFF...,,.....FFF................,,,,,,.........", - "ւГ˽˽˽˽˽˽˽˽˽˽˽˽˽˽˽˽˽˽˽˽˽˽˽˽˽˽ГГɱЯɱHd|T^^M^9999999^9999999^^^^^^7))))7^Ŧ||||||||.,,.||HHH||HHH|^^^|HHH||||.,....,.||||HHH|", + "ւГ˽˽˽˽˽˽˽˽˽˽˽˽˽˽˽˽˽˽˽˽˽˽˽˽˽˽ГГɱЯɱHd|T^^M^9999999^9999999^^^^^^7))))7^Ŧ||||||||.,,.||HHH||HHH|óóó|HHH||||.,....,.||||HHH|", "ւГ˽˽˽˽˽˽˽˽˽˽˽˽˽˽˽˽˽˽˽˽˽˽˽˽˽˽ГГɱЯɱ|θ|T^^M^99@@@99^^^^^^^^^^^^^^7))))7^Ŧ|t_|t|t|.,,.|y:::yc:::y^^^^:::^Cy|.,,³³,,.Hd|Ħ^^^^", "ւГ˽˽˽˽˽˽˽˽˽˽˽˽˽˽˽˽˽˽˽˽˽˽˽˽˽˽ГГɱϻɱ|b^^^^^^9999999^^ĦĦĦ^^HHHH|y^777777^Ŧ|__|_|_|.,,.|b666666666666666666:H.,.°°.,.Hy|Ħ^3KK", "ւГ˽˽˽˽˽˽˽˽˽˽˽˽˽˽˽˽˽˽˽˽˽˽˽˽˽˽ГГɱЯɱ|Ħ^^KK^^^^^^^^^^^^^^^^^^^^|b^^^^^^^^b||=|=|=|.,,F|:664446644446466466:H.,,³³,,.Hd|Ħ^^^^", @@ -1442,7 +1442,7 @@ "ւГɔɔɔɔɔɔɔ˽˽˽˽˽˽˽˽˽˽˽˽ɔɔɔɔɔɔɔГГɱϻɱ|Ħ^^^^^^Ħ^^Δ^;^^K^K^^b|<^^^^^7((((7^Ŧ|______|.,,F|b66666664664646^b::yH.,,³³,,.|ydy=^^?", "ւГ˽˽˽˽˽˽˽˽˽˽˽˽˽˽˽˽˽˽˽˽˽˽˽˽˽˽ГГɱЯɱ|Ħ^^KK^^Ħ^^Δ^;^^K^K^^y|HHHH^^777777^Ŧ|______=.,,.|:66444664666646C|HHH|.,....,.|HHH|JƃJ", "ւГ˽˽˽˽˽˽˽˽˽˽˽˽˽˽˽˽˽˽˽˽˽˽˽˽˽˽ГГɱЯɱ|b^^KK^^Ħ^^Δ^;^^^^^^^^^^^^^^^7((((7^b|j0j0j0|.,,%|:66444664444666b|.....,,,,,,.....|Ħ^^", - "ւГ˽˽˽˽˽˽˽˽˽˽˽˽˽˽˽˽˽˽˽˽˽˽˽˽˽˽ГГɱϻɱ|Ħ^^^^^^Ħ^^^^^^^K^K^^^^^^^^^^777777^Ŧ||||||||.,,u|^66666666666666^^.,,,,,,,,,,,,,,.||||" + "ւГ˽˽˽˽˽˽˽˽˽˽˽˽˽˽˽˽˽˽˽˽˽˽˽˽˽˽ГГɱϻɱ|Ħ^^^^^^Ħ^^^^^^^K^K^^^^^^^^^^777777^Ŧ||||||||.,,u|^66666666666666^ó.,,,,,,,,,,,,,,.||||" ], "palettes": [ "mall_palette_2" ], "terrain": { @@ -1460,6 +1460,7 @@ "*": "t_linoleum_gray", "%": "t_linoleum_gray", "u": "t_linoleum_gray", + "ó": "t_retractable_gate_l", "@": "t_carpet_concrete_yellow", "ǝ": "t_carpet_concrete_yellow", "Ʌ": "t_carpet_concrete_yellow", @@ -1725,8 +1726,8 @@ "object": { "fill_ter": "t_floor", "rows": [ - "ւГ˽˽˽˽˽˽˽˽˽˽˽˽˽˽˽˽˽˽˽˽˽˽˽˽˽˽ГГɱЯɱ|^^^^d^^^^^d^^^^K^K^^d^^^^^^^^^^^^^^T|j0j0j0|.,,u|ƃJJJJ?JJJJJJJ^^^^.,,,,......,,,,.|_@@", - "ւГ˽˽˽˽˽˽˽˽˽˽˽˽˽˽˽˽˽˽˽˽˽˽˽˽˽˽ГГɱЯɱ|C^^^^^^^^^^^3^^^^^^^^^999999^^T|^||||______=.,,*|^^^^A^^^^^^^ƃ^^^^.,,,..1111..,,,.H_@ǝ", + "ւГ˽˽˽˽˽˽˽˽˽˽˽˽˽˽˽˽˽˽˽˽˽˽˽˽˽˽ГГɱЯɱ|^^^^d^^^^^d^^^^K^K^^d^^^^^^^^^^^^^^T|j0j0j0|.,,u|ƃJJJJ?JJJJJJJ^^^ó.,,,,......,,,,.|_@@", + "ւГ˽˽˽˽˽˽˽˽˽˽˽˽˽˽˽˽˽˽˽˽˽˽˽˽˽˽ГГɱЯɱ|C^^^^^^^^^^^3^^^^^^^^^999999^^T|^||||______=.,,*|^^^^A^^^^^^^ƃ^^^ó.,,,..1111..,,,.H_@ǝ", "ւГ˽˽˽˽˽˽˽˽˽˽˽˽˽˽˽˽˽˽˽˽˽˽˽˽˽˽ГГɱЯɱ|b^^KK^^Ħ^^d^3^999999^^9ɅɅɅɅ9^^T|^|bb|______|.,,.|y^Y~~~~^^:::J^::|.,,,.F1³³1F.,,,.H_@9", "ւГɔɔɔɔɔɔɔ˽˽˽˽˽˽˽˽˽˽˽˽ɔɔɔɔɔɔɔГГɱЯɱ|Ħ^^KK^^Ħ^^^^3^9@99@9^^9ɅɅɅɅ9^^T|^=^^|______|F,,.||θ|||||θ|HHH|||||.,,,.F1³³1F.,,,.|_99", "ւГ˽˽˽˽˽˽˽˽˽˽˽˽˽˽˽˽˽˽˽˽˽˽˽˽˽˽ГГɱЯɱ|Ħ^^^^^^Ħ^^d^3^9@99@9^^999999^^T|^|||||=|=|=|F,,.|w_0|P____NNNa|FF|.,,,.F1³³1F.,,,.__99", @@ -1771,6 +1772,7 @@ "*": "t_linoleum_gray", "%": "t_linoleum_gray", "u": "t_linoleum_gray", + "ó": "t_retractable_gate_l", "@": "t_carpet_concrete_yellow", "ǝ": "t_carpet_concrete_yellow", "Ʌ": "t_carpet_concrete_yellow", diff --git a/src/activity_actor.cpp b/src/activity_actor.cpp index 70bf09da9dc69..20a0595d93aa5 100644 --- a/src/activity_actor.cpp +++ b/src/activity_actor.cpp @@ -1217,6 +1217,9 @@ void lockpick_activity_actor::finish( player_activity &act, Character &who ) } else if( ter_type == t_door_locked_peep ) { new_ter_type = t_door_c_peep; open_message = _( "With a satisfying click, the lock on the door opens." ); + } else if( ter_type == t_retractable_gate_l ) { + new_ter_type = t_retractable_gate_c; + open_message = _( "With a satisfying click, the lock on the gate opens." ); } else if( ter_type == t_door_metal_pickable ) { new_ter_type = t_door_metal_c; open_message = _( "With a satisfying click, the lock on the door opens." ); diff --git a/src/activity_handlers.cpp b/src/activity_handlers.cpp index 87b98c5d350a9..b4a45eef7f360 100644 --- a/src/activity_handlers.cpp +++ b/src/activity_handlers.cpp @@ -209,6 +209,7 @@ static const itype_id itype_steel_chunk( "steel_chunk" ); static const itype_id itype_steel_plate( "steel_plate" ); static const itype_id itype_UPS( "UPS" ); static const itype_id itype_wire( "wire" ); +static const itype_id itype_chain( "chain" ); static const itype_id itype_wool_staple( "wool_staple" ); static const zone_type_id zone_type_FARM_PLOT( "FARM_PLOT" ); @@ -2305,6 +2306,10 @@ void activity_handlers::oxytorch_finish( player_activity *act, player *p ) here.ter_set( pos, t_pit ); here.spawn_item( pos, itype_spike, rng( 1, 19 ) ); here.spawn_item( pos, itype_scrap, rng( 1, 8 ) ); + } else if( ter == t_retractable_gate_c || ter == t_retractable_gate_l ) { + here.ter_set( pos, t_strconc_floor ); + here.spawn_item( pos, itype_chain, rng( 1, 2 ) ); + here.spawn_item( pos, itype_wire, rng( 8, 22 ) ); } else if( ter == t_bars ) { if( here.ter( pos + point_east ) == t_sewage || here.ter( pos + point_south ) == t_sewage || @@ -3584,6 +3589,10 @@ void activity_handlers::hacksaw_finish( player_activity *act, player *p ) here.ter_set( pos, t_pit ); here.spawn_item( p->pos(), itype_spike, 19 ); here.spawn_item( p->pos(), itype_scrap, 8 ); + } else if( ter == t_retractable_gate_c || ter == t_retractable_gate_l ) { + here.ter_set( pos, t_strconc_floor ); + here.spawn_item( pos, itype_chain, rng( 1, 2 ) ); + here.spawn_item( pos, itype_wire, rng( 8, 22 ) ); } else if( ter == t_bars ) { if( here.ter( pos + point_east ) == t_sewage || here.ter( pos + point_south ) == t_sewage || diff --git a/src/iuse.cpp b/src/iuse.cpp index d0f8bcefb765b..3f0ca0adce021 100644 --- a/src/iuse.cpp +++ b/src/iuse.cpp @@ -4995,6 +4995,8 @@ cata::optional iuse::oxytorch( player *p, item *it, bool, const tripoint & t_chainfence, t_chaingate_c, t_chaingate_l, + t_retractable_gate_l, + t_retractable_gate_c, t_bars, t_window_bars_alarm, t_window_bars, @@ -5059,6 +5061,7 @@ cata::optional iuse::oxytorch( player *p, item *it, bool, const tripoint & } else if( ter == t_window_enhanced || ter == t_window_enhanced_noglass ) { turns = to_turns( 5_seconds ); } else if( ter == t_chainfence || ter == t_chaingate_c || + ter == t_retractable_gate_c || ter == t_retractable_gate_l || ter == t_chaingate_l || ter == t_bars || ter == t_window_bars_alarm || ter == t_window_bars || ter == t_window_bars_curtains || ter == t_window_domestic || ter == t_reb_cage || ter == t_metal_grate_window || ter == t_metal_grate_window_with_curtain || @@ -5109,6 +5112,8 @@ cata::optional iuse::hacksaw( player *p, item *it, bool t, const tripoint & t_chainfence, t_chaingate_c, t_chaingate_l, + t_retractable_gate_l, + t_retractable_gate_c, t_window_bars_alarm, t_window_bars, t_window_bars_curtains, @@ -5164,6 +5169,7 @@ cata::optional iuse::hacksaw( player *p, item *it, bool t, const tripoint & } else if( ter == t_window_enhanced || ter == t_window_enhanced_noglass ) { moves = to_moves( 5_minutes ); } else if( ter == t_chainfence || ter == t_chaingate_c || ter == t_chaingate_l || + ter == t_retractable_gate_c || ter == t_retractable_gate_l || ter == t_window_bars_alarm || ter == t_window_bars || ter == t_window_bars_curtains || ter == t_window_bars_domestic || ter == t_reb_cage || ter == t_metal_grate_window || ter == t_metal_grate_window_with_curtain || ter == t_metal_grate_window_with_curtain_open || diff --git a/src/mapdata.cpp b/src/mapdata.cpp index 7b53b9bc9a32d..1fc7f671b1cc4 100644 --- a/src/mapdata.cpp +++ b/src/mapdata.cpp @@ -574,6 +574,7 @@ ter_id t_null, t_rdoor_o, t_door_locked_interior, t_door_locked, t_door_locked_peep, t_door_locked_alarm, t_door_frame, t_chaingate_l, t_fencegate_c, t_fencegate_o, t_chaingate_c, t_chaingate_o, + t_retractable_gate_c, t_retractable_gate_l, t_retractable_gate_o, t_door_boarded, t_door_boarded_damaged, t_door_boarded_peep, t_rdoor_boarded, t_rdoor_boarded_damaged, t_door_boarded_damaged_peep, t_door_metal_c, t_door_metal_o, t_door_metal_locked, t_door_metal_pickable, t_mdoor_frame, @@ -757,6 +758,9 @@ void set_ter_ids() t_fencegate_o = ter_id( "t_fencegate_o" ); t_chaingate_c = ter_id( "t_chaingate_c" ); t_chaingate_o = ter_id( "t_chaingate_o" ); + t_retractable_gate_l = ter_id( "t_retractable_gate_l" ); + t_retractable_gate_c = ter_id( "t_retractable_gate_c" ); + t_retractable_gate_o = ter_id( "t_retractable_gate_o" ); t_door_boarded = ter_id( "t_door_boarded" ); t_door_boarded_damaged = ter_id( "t_door_boarded_damaged" ); t_door_boarded_peep = ter_id( "t_door_boarded_peep" ); diff --git a/src/mapdata.h b/src/mapdata.h index 65d6e89bb29f5..6a20fc6f02f2c 100644 --- a/src/mapdata.h +++ b/src/mapdata.h @@ -485,6 +485,7 @@ extern ter_id t_null, t_door_c, t_door_c_peep, t_door_b, t_door_b_peep, t_door_o, t_door_o_peep, t_door_locked_interior, t_door_locked, t_door_locked_peep, t_door_locked_alarm, t_door_frame, t_chaingate_l, t_fencegate_c, t_fencegate_o, t_chaingate_c, t_chaingate_o, + t_retractable_gate_l, t_retractable_gate_c, t_retractable_gate_o, t_door_boarded, t_door_boarded_damaged, t_door_boarded_peep, t_rdoor_boarded, t_rdoor_boarded_damaged, t_door_boarded_damaged_peep, t_door_metal_c, t_door_metal_o, t_door_metal_locked, t_door_metal_pickable, From 347e1e5b151a6ba599583f11ccbc78d99b62d71b Mon Sep 17 00:00:00 2001 From: John Bytheway Date: Sun, 11 Apr 2021 08:27:11 -0400 Subject: [PATCH 369/453] Fix missing harvest entry introduced in #48228 --- data/mods/Dark-Skies-Above/monsters/alien_cyborgs.json | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/data/mods/Dark-Skies-Above/monsters/alien_cyborgs.json b/data/mods/Dark-Skies-Above/monsters/alien_cyborgs.json index 7a26fb3c5dfbc..6eea495a4ba5c 100644 --- a/data/mods/Dark-Skies-Above/monsters/alien_cyborgs.json +++ b/data/mods/Dark-Skies-Above/monsters/alien_cyborgs.json @@ -322,7 +322,7 @@ "special_attacks": [ { "type": "leap", "cooldown": 10, "max_range": 5 }, { "id": "melee_shock" } ], "path_settings": { "max_dist": 5 }, "death_function": [ "NORMAL" ], - "harvest": "dks_alien_cyborg", + "harvest": "dks_alien_hcyborg", "flags": [ "SEES", "HEARS", "SMELLS", "SWARMS", "WARM", "BASHES", "GROUP_BASH", "PRIORITIZE_TARGETS", "PATH_AVOID_DANGER_2" ] } ] From 1c1758a63dcf01a2733ae9be35f1b002ceedec6b Mon Sep 17 00:00:00 2001 From: John Bytheway Date: Mon, 12 Apr 2021 21:37:17 -0400 Subject: [PATCH 370/453] Work around issues with STL move assignments (#48482) --- src/character.cpp | 2 +- src/character.h | 3 ++- src/compatibility.h | 16 ++++++++++++++++ src/item.cpp | 2 +- src/item.h | 3 ++- src/monster.cpp | 2 +- src/monster.h | 3 ++- src/npc.cpp | 2 +- src/npc.h | 2 +- src/player.cpp | 2 +- src/player.h | 2 +- src/veh_type.cpp | 3 ++- src/veh_type.h | 3 ++- 13 files changed, 33 insertions(+), 12 deletions(-) create mode 100644 src/compatibility.h diff --git a/src/character.cpp b/src/character.cpp index 1aba11b701be3..069edd8dcdf43 100644 --- a/src/character.cpp +++ b/src/character.cpp @@ -489,7 +489,7 @@ Character::Character() : Character::~Character() = default; Character::Character( Character && ) noexcept = default; -Character &Character::operator=( Character && ) noexcept = default; +Character &Character::operator=( Character && ) noexcept( list_is_noexcept ) = default; void Character::setID( character_id i, bool force ) { diff --git a/src/character.h b/src/character.h index 600a9b78f5db6..9b1db26a0a918 100644 --- a/src/character.h +++ b/src/character.h @@ -2748,7 +2748,8 @@ class Character : public Creature, public visitable protected: Character(); Character( Character && ) noexcept; - Character &operator=( Character && ) noexcept; + Character &operator=( Character && ) noexcept( list_is_noexcept ); + public: struct trait_data { /** Whether the mutation is activated. */ bool powered = false; diff --git a/src/compatibility.h b/src/compatibility.h new file mode 100644 index 0000000000000..528f2eaaff0bf --- /dev/null +++ b/src/compatibility.h @@ -0,0 +1,16 @@ +#ifndef CATA_SRC_COMPATIBILITY_H +#define CATA_SRC_COMPATIBILITY_H + +#include +#include + +// Some older standard libraries don't have all their classes +// nothrow-move-assignable when you might expect them to be. +// Some of our classes can't be in that case, so we need to know when we're in +// that situation. Can probably get rid of this once we're on C++17. +// std::list is a problem on clang-3.8 on Travis CI Ubuntu Xenial. +constexpr bool list_is_noexcept = std::is_nothrow_move_assignable>::value; +// std::string is a problem on gcc-5.3 on Travis CI Ubuntu Xenial. +constexpr bool string_is_noexcept = std::is_nothrow_move_assignable::value; + +#endif // CATA_SRC_COMPATIBILITY_H diff --git a/src/item.cpp b/src/item.cpp index b19d3270a1280..e81419c5df16e 100644 --- a/src/item.cpp +++ b/src/item.cpp @@ -440,7 +440,7 @@ item::item( const item & ) = default; item::item( item && ) noexcept = default; item::~item() = default; item &item::operator=( const item & ) = default; -item &item::operator=( item && ) noexcept = default; +item &item::operator=( item && ) noexcept( list_is_noexcept ) = default; item item::make_corpse( const mtype_id &mt, time_point turn, const std::string &name, const int upgrade_time ) diff --git a/src/item.h b/src/item.h index ad11c22a00657..7d2785a6ed39f 100644 --- a/src/item.h +++ b/src/item.h @@ -17,6 +17,7 @@ #include "calendar.h" #include "cata_utility.h" +#include "compatibility.h" #include "craft_command.h" #include "enums.h" #include "gun_mode.h" @@ -182,7 +183,7 @@ class item : public visitable item( item && ) noexcept; item( const item & ); - item &operator=( item && ) noexcept; + item &operator=( item && ) noexcept( list_is_noexcept ); item &operator=( const item & ); explicit item( const itype_id &id, time_point turn = calendar::turn, int qty = -1 ); diff --git a/src/monster.cpp b/src/monster.cpp index 9b92c0e91c600..78a3a7f2c3804 100644 --- a/src/monster.cpp +++ b/src/monster.cpp @@ -272,7 +272,7 @@ monster::monster( const monster & ) = default; monster::monster( monster && ) noexcept = default; monster::~monster() = default; monster &monster::operator=( const monster & ) = default; -monster &monster::operator=( monster && ) noexcept = default; +monster &monster::operator=( monster && ) noexcept( string_is_noexcept ) = default; void monster::setpos( const tripoint &p ) { diff --git a/src/monster.h b/src/monster.h index 4ab96e8b615c5..e3c4bf2d3d484 100644 --- a/src/monster.h +++ b/src/monster.h @@ -16,6 +16,7 @@ #include "calendar.h" #include "character_id.h" #include "color.h" +#include "compatibility.h" #include "creature.h" #include "damage.h" #include "enums.h" @@ -93,7 +94,7 @@ class monster : public Creature monster( monster && ) noexcept; ~monster() override; monster &operator=( const monster & ); - monster &operator=( monster && ) noexcept; + monster &operator=( monster && ) noexcept( string_is_noexcept ); bool is_monster() const override { return true; diff --git a/src/npc.cpp b/src/npc.cpp index 7a69b21c4f04e..c62db79f96901 100644 --- a/src/npc.cpp +++ b/src/npc.cpp @@ -205,7 +205,7 @@ standard_npc::standard_npc( const std::string &name, const tripoint &pos, } npc::npc( npc && ) noexcept = default; -npc &npc::operator=( npc && ) noexcept = default; +npc &npc::operator=( npc && ) noexcept( list_is_noexcept ) = default; static std::map, npc_template> npc_templates; diff --git a/src/npc.h b/src/npc.h index 3e380f7cafd61..c931086cb9cc4 100644 --- a/src/npc.h +++ b/src/npc.h @@ -763,7 +763,7 @@ class npc : public player npc( const npc & ) = delete; npc( npc && ) noexcept; npc &operator=( const npc & ) = delete; - npc &operator=( npc && ) noexcept; + npc &operator=( npc && ) noexcept( list_is_noexcept ); ~npc() override; bool is_player() const override { diff --git a/src/player.cpp b/src/player.cpp index 4d606de86667e..a78429aad4264 100644 --- a/src/player.cpp +++ b/src/player.cpp @@ -227,7 +227,7 @@ player::player() player::~player() = default; player::player( player && ) noexcept = default; -player &player::operator=( player && ) noexcept = default; +player &player::operator=( player && ) noexcept( list_is_noexcept ) = default; void player::normalize() { diff --git a/src/player.h b/src/player.h index c683d4ee8bc7d..cb6f60c6fa213 100644 --- a/src/player.h +++ b/src/player.h @@ -82,7 +82,7 @@ class player : public Character player( player && ) noexcept; ~player() override; player &operator=( const player & ) = delete; - player &operator=( player && ) noexcept; + player &operator=( player && ) noexcept( list_is_noexcept ); /** Calls Character::normalize() * normalizes HP and body temperature diff --git a/src/veh_type.cpp b/src/veh_type.cpp index 115dd218f96d5..8b4bbb98565ae 100644 --- a/src/veh_type.cpp +++ b/src/veh_type.cpp @@ -1072,7 +1072,8 @@ vehicle_prototype::vehicle_prototype() = default; vehicle_prototype::vehicle_prototype( vehicle_prototype && ) noexcept = default; vehicle_prototype::~vehicle_prototype() = default; -vehicle_prototype &vehicle_prototype::operator=( vehicle_prototype && ) noexcept = default; +vehicle_prototype &vehicle_prototype::operator=( vehicle_prototype && + ) noexcept( string_is_noexcept ) = default; /** *Caches a vehicle definition from a JsonObject to be loaded after itypes is initialized. diff --git a/src/veh_type.h b/src/veh_type.h index 0e7febb173abf..1319c7c21e815 100644 --- a/src/veh_type.h +++ b/src/veh_type.h @@ -16,6 +16,7 @@ #include "calendar.h" #include "color.h" +#include "compatibility.h" #include "damage.h" #include "optional.h" #include "point.h" @@ -498,7 +499,7 @@ struct vehicle_prototype { vehicle_prototype( vehicle_prototype && ) noexcept; ~vehicle_prototype(); - vehicle_prototype &operator=( vehicle_prototype && ) noexcept; + vehicle_prototype &operator=( vehicle_prototype && ) noexcept( string_is_noexcept ); translation name; std::vector parts; From 0c89512854e94294b5a9e994ed86fd6252af1bfd Mon Sep 17 00:00:00 2001 From: John Bytheway Date: Tue, 13 Apr 2021 17:37:14 -0400 Subject: [PATCH 371/453] Enable performance-inefficient-vector-operation (#48480) * Add a collection of `vector::reserve` calls. All changes done automatically by clang-tidy. * Enable performance-inefficient-vector-operation --- .clang-tidy | 1 - src/activity_item_handling.cpp | 1 + src/cata_tiles.cpp | 1 + src/debug_menu.cpp | 2 ++ src/faction_camp.cpp | 1 + src/inventory.cpp | 1 + src/item_contents.cpp | 1 + src/magic_spell_effect.cpp | 1 + src/mission_companion.cpp | 1 + src/newcharacter.cpp | 1 + src/npc.h | 1 + src/requirements.cpp | 1 + tests/encumbrance_test.cpp | 1 + tests/generic_factory_test.cpp | 1 + tests/ranged_balance_test.cpp | 1 + tests/string_ids_test.cpp | 3 +++ 16 files changed, 18 insertions(+), 1 deletion(-) diff --git a/.clang-tidy b/.clang-tidy index e4b6c9c5467d6..9b1f40408b7db 100644 --- a/.clang-tidy +++ b/.clang-tidy @@ -36,7 +36,6 @@ readability-*,\ -modernize-return-braced-init-list,\ -modernize-use-default-member-init,\ -modernize-use-emplace,\ --performance-inefficient-vector-operation,\ -performance-implicit-conversion-in-loop,\ -performance-inefficient-string-concatenation,\ -performance-type-promotion-in-math-fn,\ diff --git a/src/activity_item_handling.cpp b/src/activity_item_handling.cpp index 935ae8acbf1c2..2bb06f1a65d59 100644 --- a/src/activity_item_handling.cpp +++ b/src/activity_item_handling.cpp @@ -2526,6 +2526,7 @@ static requirement_check_result generic_multi_activity_check_requirement( player // come back here after successfully fetching your stuff if( act_prev.coords.empty() ) { std::vector local_src_set; + local_src_set.reserve( src_set.size() ); for( const tripoint &elem : src_set ) { local_src_set.push_back( here.getlocal( elem ) ); } diff --git a/src/cata_tiles.cpp b/src/cata_tiles.cpp index 9b13ffba2d925..e276392fe44aa 100644 --- a/src/cata_tiles.cpp +++ b/src/cata_tiles.cpp @@ -3928,6 +3928,7 @@ std::vector cata_tiles::build_display_list() }; int numdisplays = SDL_GetNumVideoDisplays(); + display_names.reserve( numdisplays ); for( int i = 0 ; i < numdisplays ; i++ ) { display_names.emplace_back( std::to_string( i ), no_translation( SDL_GetDisplayName( i ) ) ); } diff --git a/src/debug_menu.cpp b/src/debug_menu.cpp index 1ef8722b50c4a..8233d04ddc03d 100644 --- a/src/debug_menu.cpp +++ b/src/debug_menu.cpp @@ -1956,6 +1956,7 @@ static void debug_menu_game_state() tripoint abs_sub = here.get_abs_sub(); std::string mfus; std::vector> sorted; + sorted.reserve( m_flag::MF_MAX ); for( int f = 0; f < m_flag::MF_MAX; f++ ) { sorted.push_back( {static_cast( f ), MonsterGenerator::generator().m_flag_usage_stats[f]} ); } @@ -1984,6 +1985,7 @@ static void debug_menu_game_state() if( !creature_counts.empty() ) { std::vector> creature_names_sorted; + creature_names_sorted.reserve( creature_counts.size() ); for( const std::pair &it : creature_counts ) { creature_names_sorted.emplace_back( it ); } diff --git a/src/faction_camp.cpp b/src/faction_camp.cpp index c139c8616ebab..99f2d76bab7cf 100644 --- a/src/faction_camp.cpp +++ b/src/faction_camp.cpp @@ -532,6 +532,7 @@ recipe_id base_camps::select_camp_option( const std::map std::vector pos_names; int choice = 0; + pos_names.reserve( pos_options.size() ); for( const auto &it : pos_options ) { pos_names.push_back( it.second.translated() ); } diff --git a/src/inventory.cpp b/src/inventory.cpp index bb0ae2be85daa..38e1b09796cf2 100644 --- a/src/inventory.cpp +++ b/src/inventory.cpp @@ -451,6 +451,7 @@ void inventory::form_from_zone( map &m, std::unordered_set &zone_pts, bool assign_invlet ) { std::vector pts; + pts.reserve( zone_pts.size() ); for( const tripoint &elem : zone_pts ) { pts.push_back( m.getlocal( elem ) ); } diff --git a/src/item_contents.cpp b/src/item_contents.cpp index 23cd9a86aac0c..2c055e1cdef65 100644 --- a/src/item_contents.cpp +++ b/src/item_contents.cpp @@ -149,6 +149,7 @@ bool pocket_favorite_callback::key( const input_context &, const input_event &ev } std::vector itype_initializer; + itype_initializer.reserve( nearby_itypes.size() ); for( const std::pair &name : nearby_itypes ) { itype_initializer.emplace_back( name.first ); } diff --git a/src/magic_spell_effect.cpp b/src/magic_spell_effect.cpp index 43978f1c511db..20da42d70dd54 100644 --- a/src/magic_spell_effect.cpp +++ b/src/magic_spell_effect.cpp @@ -1229,6 +1229,7 @@ void spell_effect::dash( const spell &sp, Creature &caster, const tripoint &targ ::map &here = get_map(); // uses abs() coordinates std::vector trajectory; + trajectory.reserve( trajectory_local.size() ); for( const tripoint &local_point : trajectory_local ) { trajectory.push_back( here.getabs( local_point ) ); } diff --git a/src/mission_companion.cpp b/src/mission_companion.cpp index 030cc39ea8667..a74d805de20c2 100644 --- a/src/mission_companion.cpp +++ b/src/mission_companion.cpp @@ -2054,6 +2054,7 @@ npc_ptr talk_function::companion_choose_return( const tripoint_abs_omt &omt_pos, } std::vector npcs; + npcs.reserve( available.size() ); for( auto &elem : available ) { npcs.push_back( ( elem )->name ); } diff --git a/src/newcharacter.cpp b/src/newcharacter.cpp index bbfe516e17030..ce53b30ac77b9 100644 --- a/src/newcharacter.cpp +++ b/src/newcharacter.cpp @@ -1447,6 +1447,7 @@ tab_direction set_traits( avatar &u, points_left &points ) // Grab a list of the names of the bionics that block this trait // So that the player know what is preventing them from taking it std::vector conflict_names; + conflict_names.reserve( cbms_blocking_trait.size() ); for( const bionic_id &conflict : cbms_blocking_trait ) { conflict_names.emplace_back( conflict->name.translated() ); } diff --git a/src/npc.h b/src/npc.h index c931086cb9cc4..15f17794716a3 100644 --- a/src/npc.h +++ b/src/npc.h @@ -177,6 +177,7 @@ class job_data const std::pair &b ) { return a.second > b.second; } ); + ret.reserve( pairs.size() ); for( const std::pair &elem : pairs ) { ret.push_back( elem.first ); } diff --git a/src/requirements.cpp b/src/requirements.cpp index ba5f4a0e712fa..8d769b7e2e798 100644 --- a/src/requirements.cpp +++ b/src/requirements.cpp @@ -72,6 +72,7 @@ const requirement_data &string_id::obj() const std::vector requirement_data::get_all() { std::vector ret; + ret.reserve( requirements_all.size() ); for( const std::pair &pair : requirements_all ) { ret.push_back( pair.second ); } diff --git a/tests/encumbrance_test.cpp b/tests/encumbrance_test.cpp index bb495a9eb030b..61eec9fbab457 100644 --- a/tests/encumbrance_test.cpp +++ b/tests/encumbrance_test.cpp @@ -61,6 +61,7 @@ static void test_encumbrance( { CAPTURE( clothing_types ); std::vector clothing; + clothing.reserve( clothing_types.size() ); for( const std::string &type : clothing_types ) { clothing.push_back( item( type ) ); } diff --git a/tests/generic_factory_test.cpp b/tests/generic_factory_test.cpp index 0da6ab03c8d6b..711668efe3f6d 100644 --- a/tests/generic_factory_test.cpp +++ b/tests/generic_factory_test.cpp @@ -380,6 +380,7 @@ TEST_CASE( "string_and_int_ids_benchmark", "[.][generic_factory][int_id][string_ } const int test_flags_size = test_flags.size(); std::vector test_dyn_str_ids; + test_dyn_str_ids.reserve( test_flags.size() ); for( const auto &f : test_flags ) { test_dyn_str_ids.push_back( dyn_str_id( f.str() ) ); } diff --git a/tests/ranged_balance_test.cpp b/tests/ranged_balance_test.cpp index 40997377ae042..7d7b8b9bf838a 100644 --- a/tests/ranged_balance_test.cpp +++ b/tests/ranged_balance_test.cpp @@ -117,6 +117,7 @@ static std::vector firing_test( const dispersion_sources &dis const int range, const std::vector< Threshold > &thresholds ) { std::vector firing_stats; + firing_stats.reserve( thresholds.size() ); for( const Threshold &pear : thresholds ) { firing_stats.push_back( firing_test( dispersion, range, pear ) ); } diff --git a/tests/string_ids_test.cpp b/tests/string_ids_test.cpp index 24d06dfbd0e46..c3e7957968273 100644 --- a/tests/string_ids_test.cpp +++ b/tests/string_ids_test.cpp @@ -37,6 +37,7 @@ TEST_CASE( "string_ids_intern_test", "[string_id]" ) struct test_obj {}; std::vector> ids; // lots of ids to make sure that "interning" map gets expanded + ids.reserve( num_ids ); for( int i = 0; i < num_ids; ++i ) { ids.push_back( string_id( "test_id" + std::to_string( i ) ) ); } @@ -119,6 +120,7 @@ TEST_CASE( "string_id_sorting_test", "[string_id]" ) SECTION( "vector ids sorting" ) { std::vector vec; + vec.reserve( 10 ); for( int i = 0; i < 10; ++i ) { vec.push_back( id( "id" + std::to_string( i ) ) ); } @@ -150,6 +152,7 @@ TEST_CASE( "string_id_creation_benchmark", "[.][string_id][benchmark]" ) { static constexpr int num_test_strings = 30; std::vector test_strings; + test_strings.reserve( num_test_strings ); for( int i = 0; i < num_test_strings; ++i ) { test_strings.push_back( "some_test_string_" + std::to_string( i ) ); } From ff73bc7a7d481b0d15cecb260083cfcb508088d8 Mon Sep 17 00:00:00 2001 From: John Bytheway Date: Wed, 12 Aug 2020 12:24:09 -0400 Subject: [PATCH 372/453] Simplify mapgen logic Previously there were separate dedicated components for terrain and furniture mapgen. But these are also supported in the more general format_placings so it simplifies the code to get rid of the special cases for terrain and furniture. (There's some performance cost here, but I don't think it's significant). --- src/mapgen.cpp | 165 ++++++++++++------------------------------------- src/mapgen.h | 11 ++-- 2 files changed, 45 insertions(+), 131 deletions(-) diff --git a/src/mapgen.cpp b/src/mapgen.cpp index dc0d5a664d435..6e9e446e29654 100644 --- a/src/mapgen.cpp +++ b/src/mapgen.cpp @@ -591,7 +591,6 @@ mapgen_function_json_base::mapgen_function_json_base( const json_source_location &jsrcloc, const std::string &context ) : jsrcloc( jsrcloc ) , context_( context ) - , do_format( false ) , is_ready( false ) , mapgensize( SEEX * 2, SEEY * 2 ) , objects( m_offset, mapgensize ) @@ -1538,6 +1537,11 @@ class jmapgen_terrain : public jmapgen_piece jmapgen_terrain( const JsonObject &jsi, const std::string &/*context*/ ) : jmapgen_terrain( jsi.get_string( "ter" ) ) {} explicit jmapgen_terrain( const std::string &tid ) : id( ter_id( tid ) ) {} + + bool is_nop() const override { + return id.id().is_null(); + } + void apply( const mapgendata &dat, const jmapgen_int &x, const jmapgen_int &y ) const override { dat.m.ter_set( point( x.get(), y.get() ), id ); @@ -2200,12 +2204,6 @@ void mapgen_palette::load_place_mapings( const JsonObject &jo, const std::string if( !jo.has_object( member_name ) ) { return; } - /* This is kind of a hack. Loading furniture/terrain from `jo` is already done in - * mapgen_palette::load_temp, continuing here would load it again and cause trouble. - */ - if( member_name == "terrain" || member_name == "furniture" ) { - return; - } for( const JsonMember member : jo.get_object( member_name ) ) { const map_key key( member ); auto &vect = format_placings[ key ]; @@ -2216,29 +2214,9 @@ void mapgen_palette::load_place_mapings( const JsonObject &jo, const std::string static std::map palettes; -static bool check_furn( const furn_id &id, const std::string &context ) -{ - const furn_t &furn = id.obj(); - if( furn.has_flag( "PLANT" ) ) { - debugmsg( "json mapgen for %s specifies furniture %s, which has flag " - "PLANT. Such furniture must be specified in a \"sealed_item\" special.", - context, furn.id.str() ); - // Only report once per mapgen object, otherwise the reports are - // very repetitive - return true; - } - return false; -} - void mapgen_palette::check() { std::string context = "palette " + id; - for( const std::pair &p : format_furniture ) { - if( check_furn( p.second, context ) ) { - return; - } - } - for( const std::pair>> &p : format_placings ) { for( const shared_ptr_fast &j : p.second ) { @@ -2296,11 +2274,8 @@ void mapgen_palette::add( const mapgen_palette &rh ) for( const auto &placing : rh.format_placings ) { format_placings[ placing.first ] = placing.second; } - for( const auto &placing : rh.format_terrain ) { - format_terrain[ placing.first ] = placing.second; - } - for( const auto &placing : rh.format_furniture ) { - format_furniture[ placing.first ] = placing.second; + for( const auto &placing : rh.keys_with_terrain ) { + keys_with_terrain.insert( placing ); } } @@ -2309,8 +2284,7 @@ mapgen_palette mapgen_palette::load_internal( const JsonObject &jo, const std::s { mapgen_palette new_pal; auto &format_placings = new_pal.format_placings; - auto &format_terrain = new_pal.format_terrain; - auto &format_furniture = new_pal.format_furniture; + auto &keys_with_terrain = new_pal.keys_with_terrain; if( require_id ) { new_pal.id = jo.get_string( "id" ); } @@ -2327,39 +2301,17 @@ mapgen_palette mapgen_palette::load_internal( const JsonObject &jo, const std::s } // mandatory: every character in rows must have matching entry, unless fill_ter is set - // "terrain": { "a": "t_grass", "b": "t_lava" } + // "terrain": { "a": "t_grass", "b": "t_lava" }. To help enforce this we + // keep track of everything in the "terrain" object if( jo.has_member( "terrain" ) ) { for( const JsonMember member : jo.get_object( "terrain" ) ) { - const map_key key( member ); - if( member.test_string() ) { - format_terrain[key] = ter_id( member.get_string() ); - } else { - auto &vect = format_placings[ key ]; - ::load_place_mapings( - member, vect, "terrain " + member.name() + " in palette " + new_pal.id ); - if( !vect.empty() ) { - // Dummy entry to signal that this terrain is actually defined, because - // the code below checks that each square on the map has a valid terrain - // defined somehow. - format_terrain[key] = t_null; - } - } + keys_with_terrain.insert( map_key( member ) ); } } - if( jo.has_object( "furniture" ) ) { - for( const JsonMember member : jo.get_object( "furniture" ) ) { - const map_key key( member ); - if( member.test_string() ) { - format_furniture[key] = furn_id( member.get_string() ); - } else { - auto &vect = format_placings[ key ]; - ::load_place_mapings( - member, vect, "furniture " + member.name() + " in palette " + new_pal.id ); - } - } - } std::string c = "palette " + new_pal.id; + new_pal.load_place_mapings( jo, "terrain", format_placings, c ); + new_pal.load_place_mapings( jo, "furniture", format_placings, c ); new_pal.load_place_mapings( jo, "fields", format_placings, c ); new_pal.load_place_mapings( jo, "npcs", format_placings, c ); new_pal.load_place_mapings( jo, "signs", format_placings, c ); @@ -2387,6 +2339,15 @@ mapgen_palette mapgen_palette::load_internal( const JsonObject &jo, const std::s new_pal.load_place_mapings( jo, "ter_furn_transforms", format_placings, c ); new_pal.load_place_mapings( jo, "faction_owner_character", format_placings, c ); + + for( mapgen_palette::placing_map::value_type &p : format_placings ) { + p.second.erase( + std::remove_if( + p.second.begin(), p.second.end(), + []( const shared_ptr_fast &placing ) { + return placing->is_nop(); + } ), p.second.end() ); + } return new_pal; } @@ -2486,15 +2447,13 @@ bool mapgen_function_json_base::setup_common( const JsonObject &jo ) JsonArray sparray; JsonObject pjo; - format.resize( static_cast( mapgensize.x * mapgensize.y ) ); // just like mapf::basic_bind("stuff",blargle("foo", etc) ), only json input and faster when applying if( jo.has_array( "rows" ) ) { mapgen_palette palette = mapgen_palette::load_temp( jo, "dda" ); - auto &format_terrain = palette.format_terrain; - auto &format_furniture = palette.format_furniture; + auto &keys_with_terrain = palette.keys_with_terrain; auto &format_placings = palette.format_placings; - if( format_terrain.empty() ) { + if( palette.keys_with_terrain.empty() ) { return false; } @@ -2524,12 +2483,10 @@ bool mapgen_function_json_base::setup_common( const JsonObject &jo ) for( int i = m_offset.x; i < expected_dim.x; i++ ) { const point p = point( i, c ) - m_offset; const map_key key = row_keys[i]; - const auto iter_ter = format_terrain.find( key ); - const auto iter_furn = format_furniture.find( key ); + const auto iter_ter = keys_with_terrain.find( key ); const auto fpi = format_placings.find( key ); - const bool has_terrain = iter_ter != format_terrain.end(); - const bool has_furn = iter_furn != format_furniture.end(); + const bool has_terrain = iter_ter != keys_with_terrain.end(); const bool has_placing = fpi != format_placings.end(); if( !has_terrain && !fallback_terrain_exists ) { @@ -2538,8 +2495,7 @@ bool mapgen_function_json_base::setup_common( const JsonObject &jo ) "'%s' is not in 'terrain', and no 'fill_ter' is set!", c + 1, i + 1, key.str ), c, i + 1 ); } - if( !has_terrain && !has_furn && !has_placing && - key.str != " " && key.str != "." ) { + if( !has_terrain && !has_placing && key.str != " " && key.str != "." ) { try { parray.string_error( string_format( "format: rows: row %d column %d: " @@ -2549,12 +2505,6 @@ bool mapgen_function_json_base::setup_common( const JsonObject &jo ) debugmsg( "(json-error)\n%s", e.what() ); } } - if( has_terrain ) { - format[ calc_index( p ) ].ter = iter_ter->second; - } - if( has_furn ) { - format[ calc_index( p ) ].furn = iter_furn->second; - } if( has_placing ) { jmapgen_place where( p ); for( auto &what : fpi->second ) { @@ -2564,7 +2514,6 @@ bool mapgen_function_json_base::setup_common( const JsonObject &jo ) } } fallback_terrain_exists = true; - do_format = true; } // No fill_ter? No format? GTFO. @@ -2622,14 +2571,22 @@ void mapgen_function_json_nested::check() const check_common(); } -void mapgen_function_json_base::check_common() const +static bool check_furn( const furn_id &id, const std::string &context ) { - for( const ter_furn_id &id : format ) { - if( check_furn( id.furn, context_ ) ) { - return; - } + const furn_t &furn = id.obj(); + if( furn.has_flag( "PLANT" ) ) { + debugmsg( "json mapgen for %s specifies furniture %s, which has flag " + "PLANT. Such furniture must be specified in a \"sealed_item\" special.", + context, furn.id.str() ); + // Only report once per mapgen object, otherwise the reports are + // very repetitive + return true; } + return false; +} +void mapgen_function_json_base::check_common() const +{ for( const jmapgen_setmap &setmap : setmap_points ) { if( setmap.op != JMAPGEN_SETMAP_FURN && setmap.op != JMAPGEN_SETMAP_LINE_FURN && @@ -2810,44 +2767,9 @@ bool jmapgen_setmap::has_vehicle_collision( const mapgendata &dat, const point & return false; } -void mapgen_function_json_base::formatted_set_incredibly_simple( map &m, const point &offset ) const -{ - for( int y = 0; y < mapgensize.y; y++ ) { - for( int x = 0; x < mapgensize.x; x++ ) { - point p( x, y ); - const size_t index = calc_index( p ); - const ter_furn_id &tdata = format[index]; - const point map_pos = p + offset; - if( tdata.furn != f_null ) { - if( tdata.ter != t_null ) { - m.set( map_pos, tdata.ter, tdata.furn ); - } else { - m.furn_set( map_pos, tdata.furn ); - } - } else if( tdata.ter != t_null ) { - m.ter_set( map_pos, tdata.ter ); - } - } - } -} - bool mapgen_function_json_base::has_vehicle_collision( const mapgendata &dat, const point &offset ) const { - if( do_format ) { - for( int y = 0; y < mapgensize.y; y++ ) { - for( int x = 0; x < mapgensize.x; x++ ) { - const point p( x, y ); - const ter_furn_id &tdata = format[calc_index( p )]; - const point map_pos = p + offset; - if( ( tdata.furn != f_null || tdata.ter != t_null ) && - dat.m.veh_at( tripoint( map_pos, dat.zlevel() ) ).has_value() ) { - return true; - } - } - } - } - for( const jmapgen_setmap &elem : setmap_points ) { if( elem.has_vehicle_collision( dat, offset ) ) { return true; @@ -2884,9 +2806,6 @@ void mapgen_function_json::generate( mapgendata &md ) m->rotate( ( -static_cast( md.terrain_type()->get_dir() ) + 4 ) % 4 ); } } - if( do_format ) { - formatted_set_incredibly_simple( *m, point_zero ); - } for( auto &elem : setmap_points ) { elem.apply( md, point_zero ); } @@ -2907,10 +2826,6 @@ void mapgen_function_json_nested::nest( const mapgendata &dat, const point &offs // TODO: Make rotation work for submaps, then pass this value into elem & objects apply. //int chosen_rotation = rotation.get() % 4; - if( do_format ) { - formatted_set_incredibly_simple( dat.m, offset ); - } - for( const jmapgen_setmap &elem : setmap_points ) { elem.apply( dat, offset ); } diff --git a/src/mapgen.h b/src/mapgen.h index 6a1b0b4cbcb70..34616459af352 100644 --- a/src/mapgen.h +++ b/src/mapgen.h @@ -8,6 +8,7 @@ #include #include #include +#include #include #include @@ -159,6 +160,9 @@ class jmapgen_piece protected: jmapgen_piece() : repeat( 1, 1 ) { } public: + virtual bool is_nop() const { + return false; + } /** Sanity-check this piece */ virtual void check( const std::string &/*context*/ ) const { } /** Place something on the map from mapgendata &dat, at (x,y). */ @@ -226,8 +230,7 @@ class mapgen_palette using placing_map = std::unordered_map>>; - std::unordered_map format_terrain; - std::unordered_map format_furniture; + std::unordered_set keys_with_terrain; placing_map format_placings; template @@ -338,14 +341,10 @@ class mapgen_function_json_base void check_common() const; - void formatted_set_incredibly_simple( map &m, const point &offset ) const; - - bool do_format; bool is_ready; point mapgensize; point m_offset; - std::vector format; std::vector setmap_points; jmapgen_objects objects; From a00aa28b806bb59120fc9376b86670ff27ba1e27 Mon Sep 17 00:00:00 2001 From: casswedson <58050969+casswedson@users.noreply.github.com> Date: Tue, 13 Apr 2021 23:38:25 -0500 Subject: [PATCH 373/453] fix typo (#48505) --- data/mods/Magiclysm/items/armor.json | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/data/mods/Magiclysm/items/armor.json b/data/mods/Magiclysm/items/armor.json index 1d6a47e552eda..ceb110b3009c4 100644 --- a/data/mods/Magiclysm/items/armor.json +++ b/data/mods/Magiclysm/items/armor.json @@ -72,7 +72,7 @@ "copy-from": "boots_chitin", "type": "ARMOR", "name": { "str": "pair of demon chitin boots", "str_pl": "pairs of demon chitin boots" }, - "description": "Boots crafted from carefully cleaned and pruned pruned red exoskeletons of demon spiders. Fire-resistant and very durable.", + "description": "Boots crafted from carefully cleaned and pruned red exoskeletons of demon spiders. Fire-resistant and very durable.", "material": [ "demon_chitin" ], "proportional": { "weight": 0.9, "encumbrance": 0.9, "price": 10, "warmth": 2 }, "environmental_protection": 8 From b81a6f480f49a504a73130e45970a137e59b507c Mon Sep 17 00:00:00 2001 From: John Bytheway Date: Tue, 13 Apr 2021 15:31:33 -0400 Subject: [PATCH 374/453] Move HashCombine to clang-tidy-plugin/Utils.h Expecting this to be needed in multiple places now, so move to shared code. --- .../TestsMustRestoreGlobalStateCheck.h | 8 ++------ tools/clang-tidy-plugin/Utils.h | 11 +++++++++++ 2 files changed, 13 insertions(+), 6 deletions(-) diff --git a/tools/clang-tidy-plugin/TestsMustRestoreGlobalStateCheck.h b/tools/clang-tidy-plugin/TestsMustRestoreGlobalStateCheck.h index 92bbea8016388..0b80f96e8a378 100644 --- a/tools/clang-tidy-plugin/TestsMustRestoreGlobalStateCheck.h +++ b/tools/clang-tidy-plugin/TestsMustRestoreGlobalStateCheck.h @@ -6,6 +6,7 @@ #include #include "ClangTidy.h" +#include "Utils.h" namespace clang { @@ -36,12 +37,7 @@ namespace std template<> struct hash { std::size_t operator()( const clang::tidy::cata::RestoredDecl &r ) const noexcept { - hash function_hash; - hash decl_hash; - size_t result = function_hash( r.function ); - result ^= 0x9e3779b9 + ( result << 6 ) + ( result >> 2 ); - result ^= decl_hash( r.variable ); - return result; + return clang::tidy::cata::HashCombine( r.function, r.variable ); } }; } // namespace std diff --git a/tools/clang-tidy-plugin/Utils.h b/tools/clang-tidy-plugin/Utils.h index 5a39a1c45d8b2..df7a355ca45c1 100644 --- a/tools/clang-tidy-plugin/Utils.h +++ b/tools/clang-tidy-plugin/Utils.h @@ -206,6 +206,17 @@ class NameConvention bool valid = true; }; +template +inline size_t HashCombine( const T &t, const U &u ) +{ + std::hash t_hash; + std::hash u_hash; + size_t result = t_hash( t ); + result ^= 0x9e3779b9 + ( result << 6 ) + ( result >> 2 ); + result ^= u_hash( u ); + return result; +} + } // namespace cata } // namespace tidy } // namespace clang From 6dd4cdf55e72a3b63e5f012058785728f71eae77 Mon Sep 17 00:00:00 2001 From: John Bytheway Date: Tue, 13 Apr 2021 15:32:36 -0400 Subject: [PATCH 375/453] Add initial UnsequencedCallsCheck This check is intended to look for cases where code is calling multiple member functions of the same object, at least one of which is non-const, without an intervening sequence point. This has been the source of some bugs, primarily in JSON parsing, where objects might be extracted from JSON in an unexpected order. --- tools/clang-tidy-plugin/CMakeLists.txt | 1 + tools/clang-tidy-plugin/CataTidyModule.cpp | 2 + .../UnsequencedCallsCheck.cpp | 104 ++++++++++++++++++ .../clang-tidy-plugin/UnsequencedCallsCheck.h | 67 +++++++++++ .../test/unsequenced-calls.cpp | 23 ++++ 5 files changed, 197 insertions(+) create mode 100644 tools/clang-tidy-plugin/UnsequencedCallsCheck.cpp create mode 100644 tools/clang-tidy-plugin/UnsequencedCallsCheck.h create mode 100644 tools/clang-tidy-plugin/test/unsequenced-calls.cpp diff --git a/tools/clang-tidy-plugin/CMakeLists.txt b/tools/clang-tidy-plugin/CMakeLists.txt index 4b493eeab6c5c..54064951c5d67 100644 --- a/tools/clang-tidy-plugin/CMakeLists.txt +++ b/tools/clang-tidy-plugin/CMakeLists.txt @@ -23,6 +23,7 @@ add_library(CataAnalyzerPlugin MODULE TestsMustRestoreGlobalStateCheck.cpp TextStyleCheck.cpp TranslatorCommentsCheck.cpp + UnsequencedCallsCheck.cpp UseLocalizedSortingCheck.cpp UseNamedPointConstantsCheck.cpp UsePointApisCheck.cpp diff --git a/tools/clang-tidy-plugin/CataTidyModule.cpp b/tools/clang-tidy-plugin/CataTidyModule.cpp index 716aa0b509023..b8442e9344f3b 100644 --- a/tools/clang-tidy-plugin/CataTidyModule.cpp +++ b/tools/clang-tidy-plugin/CataTidyModule.cpp @@ -18,6 +18,7 @@ #include "TestsMustRestoreGlobalStateCheck.h" #include "TextStyleCheck.h" #include "TranslatorCommentsCheck.h" +#include "UnsequencedCallsCheck.h" #include "UseLocalizedSortingCheck.h" #include "UseNamedPointConstantsCheck.h" #include "UsePointApisCheck.h" @@ -55,6 +56,7 @@ class CataModule : public ClangTidyModule "cata-tests-must-restore-global-state" ); CheckFactories.registerCheck( "cata-text-style" ); CheckFactories.registerCheck( "cata-translator-comments" ); + CheckFactories.registerCheck( "cata-unsequenced-calls" ); CheckFactories.registerCheck( "cata-use-localized-sorting" ); CheckFactories.registerCheck( "cata-use-named-point-constants" ); diff --git a/tools/clang-tidy-plugin/UnsequencedCallsCheck.cpp b/tools/clang-tidy-plugin/UnsequencedCallsCheck.cpp new file mode 100644 index 0000000000000..c79bde41383ff --- /dev/null +++ b/tools/clang-tidy-plugin/UnsequencedCallsCheck.cpp @@ -0,0 +1,104 @@ +#include "UnsequencedCallsCheck.h" + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#include "Utils.h" + +using namespace clang::ast_matchers; + +namespace clang +{ +namespace tidy +{ +namespace cata +{ + +void UnsequencedCallsCheck::registerMatchers( MatchFinder *Finder ) +{ + Finder->addMatcher( + cxxMemberCallExpr( + on( declRefExpr( to( namedDecl().bind( "on" ) ) ) ) + ).bind( "memberCall" ), + this + ); +} + +// Keep walking up the AST so long as the nodes are expressions. When we reach +// a non-expression, return the previous expression. +// This is a vague approximation to finding the AST node which represents +// everything between two sequence points. +static const Expr *getContainingStatement( + const ast_matchers::MatchFinder::MatchResult &Result, const Expr *Node ) +{ + for( const ast_type_traits::DynTypedNode &parent : Result.Context->getParents( *Node ) ) { + if( const Expr *Candidate = parent.get() ) { + return getContainingStatement( Result, Candidate ); + } + } + + return Node; +} + +void UnsequencedCallsCheck::CheckCall( const MatchFinder::MatchResult &Result ) +{ + const CXXMemberCallExpr *MemberCall = + Result.Nodes.getNodeAs( "memberCall" ); + const NamedDecl *On = + Result.Nodes.getNodeAs( "on" ); + if( !MemberCall || !On ) { + return; + } + + const Expr *ContainingStatement = getContainingStatement( Result, MemberCall ); + + CallContext context{ ContainingStatement, On }; + calls_[context].push_back( MemberCall ); +} + +void UnsequencedCallsCheck::onEndOfTranslationUnit() +{ + for( const std::pair> &p : calls_ ) { + const CallContext &context = p.first; + const std::vector &calls = p.second; + + if( calls.size() < 2 ) { + continue; + } + bool any_non_const = false; + for( const CXXMemberCallExpr *member_call : calls ) { + const CXXMethodDecl *method = member_call->getMethodDecl(); + if( !method->isConst() ) { + any_non_const = true; + break; + } + } + + if( any_non_const ) { + diag( + context.stmt->getBeginLoc(), + "Unsequenced calls to member functions of %0, at least one of which is non-const." + ) << context.on; + } + } +} + +void UnsequencedCallsCheck::check( const MatchFinder::MatchResult &Result ) +{ + CheckCall( Result ); +} + +} // namespace cata +} // namespace tidy +} // namespace clang diff --git a/tools/clang-tidy-plugin/UnsequencedCallsCheck.h b/tools/clang-tidy-plugin/UnsequencedCallsCheck.h new file mode 100644 index 0000000000000..132a139f1798b --- /dev/null +++ b/tools/clang-tidy-plugin/UnsequencedCallsCheck.h @@ -0,0 +1,67 @@ +#ifndef CATA_TOOLS_CLANG_TIDY_PLUGIN_UNSEQUENCEDCALLSCHECK_H +#define CATA_TOOLS_CLANG_TIDY_PLUGIN_UNSEQUENCEDCALLSCHECK_H + +#include +#include + +#include "ClangTidy.h" +#include "Utils.h" + +namespace clang +{ + +namespace tidy +{ +class ClangTidyContext; + +namespace cata +{ + +struct CallContext { + const Expr *stmt; + const NamedDecl *on; + + bool operator==( const CallContext &other ) const { + return stmt == other.stmt && on == other.on; + } +}; + +} // namespace cata +} // namespace tidy +} // namespace clang + +namespace std +{ +template<> +struct hash { + std::size_t operator()( const clang::tidy::cata::CallContext &c ) const noexcept { + return clang::tidy::cata::HashCombine( c.stmt, c.on ); + } +}; +} // namespace std + +namespace clang +{ +namespace tidy +{ +namespace cata +{ + +class UnsequencedCallsCheck : public ClangTidyCheck +{ + public: + UnsequencedCallsCheck( StringRef Name, ClangTidyContext *Context ) + : ClangTidyCheck( Name, Context ) {} + void registerMatchers( ast_matchers::MatchFinder *Finder ) override; + void check( const ast_matchers::MatchFinder::MatchResult &Result ) override; + void onEndOfTranslationUnit() override; + private: + void CheckCall( const ast_matchers::MatchFinder::MatchResult & ); + std::unordered_map> calls_; +}; + +} // namespace cata +} // namespace tidy +} // namespace clang + +#endif // CATA_TOOLS_CLANG_TIDY_PLUGIN_UNSEQUENCEDCALLSCHECK_H diff --git a/tools/clang-tidy-plugin/test/unsequenced-calls.cpp b/tools/clang-tidy-plugin/test/unsequenced-calls.cpp new file mode 100644 index 0000000000000..600208298a494 --- /dev/null +++ b/tools/clang-tidy-plugin/test/unsequenced-calls.cpp @@ -0,0 +1,23 @@ +// RUN: %check_clang_tidy %s cata-unsequenced-calls %t -- -plugins=%cata_plugin -- + +struct A { + // Define a const and a non-const member function + int const_mf() const; + int nonconst_mf(); +}; + +void g( int, int ); + +void f0() +{ + A a; + // Two calls to const functions are fine + g( a.const_mf(), a.const_mf() ); + // But if at least one is non-const, raise a warning + g( a.nonconst_mf(), a.const_mf() ); + // CHECK-MESSAGES: [[@LINE-1]]:5: warning: Unsequenced calls to member functions of 'a', at least one of which is non-const. [cata-unsequenced-calls] + g( a.const_mf(), a.nonconst_mf() ); + // CHECK-MESSAGES: [[@LINE-1]]:5: warning: Unsequenced calls to member functions of 'a', at least one of which is non-const. [cata-unsequenced-calls] + g( a.nonconst_mf(), a.nonconst_mf() ); + // CHECK-MESSAGES: [[@LINE-1]]:5: warning: Unsequenced calls to member functions of 'a', at least one of which is non-const. [cata-unsequenced-calls] +} From 75661317a798ace042f8cf41195654fb6a8315c8 Mon Sep 17 00:00:00 2001 From: John Bytheway Date: Tue, 13 Apr 2021 19:32:54 -0400 Subject: [PATCH 376/453] Exempt more things from unsequenced calls check Treat member functions called begin, end, find as special and effectively const. Treat the ternary operator as sequencing its args. --- .../UnsequencedCallsCheck.cpp | 42 +++++++++++++++---- .../test/unsequenced-calls.cpp | 8 +++- 2 files changed, 42 insertions(+), 8 deletions(-) diff --git a/tools/clang-tidy-plugin/UnsequencedCallsCheck.cpp b/tools/clang-tidy-plugin/UnsequencedCallsCheck.cpp index c79bde41383ff..582062342bc1e 100644 --- a/tools/clang-tidy-plugin/UnsequencedCallsCheck.cpp +++ b/tools/clang-tidy-plugin/UnsequencedCallsCheck.cpp @@ -39,12 +39,15 @@ void UnsequencedCallsCheck::registerMatchers( MatchFinder *Finder ) // a non-expression, return the previous expression. // This is a vague approximation to finding the AST node which represents // everything between two sequence points. -static const Expr *getContainingStatement( +static const Expr *getContainingSequenceStatement( const ast_matchers::MatchFinder::MatchResult &Result, const Expr *Node ) { for( const ast_type_traits::DynTypedNode &parent : Result.Context->getParents( *Node ) ) { + if( parent.get() ) { + return Node; + } if( const Expr *Candidate = parent.get() ) { - return getContainingStatement( Result, Candidate ); + return getContainingSequenceStatement( Result, Candidate ); } } @@ -61,25 +64,39 @@ void UnsequencedCallsCheck::CheckCall( const MatchFinder::MatchResult &Result ) return; } - const Expr *ContainingStatement = getContainingStatement( Result, MemberCall ); + const Expr *ContainingStatement = getContainingSequenceStatement( Result, MemberCall ); CallContext context{ ContainingStatement, On }; calls_[context].push_back( MemberCall ); } +static bool IsEffectivelyConstCall( const CXXMemberCallExpr *Call ) +{ + const CXXMethodDecl *method = Call->getMethodDecl(); + if( method->isConst() ) { + return true; + } + StringRef Name = method->getName(); + if( Name == "begin" || Name == "end" || Name == "find" ) { + return true; + } + return false; +} + void UnsequencedCallsCheck::onEndOfTranslationUnit() { - for( const std::pair> &p : calls_ ) { + for( std::pair> &p : calls_ ) { const CallContext &context = p.first; - const std::vector &calls = p.second; + std::vector &calls = p.second; + std::sort( calls.begin(), calls.end() ); + calls.erase( std::unique( calls.begin(), calls.end() ), calls.end() ); if( calls.size() < 2 ) { continue; } bool any_non_const = false; for( const CXXMemberCallExpr *member_call : calls ) { - const CXXMethodDecl *method = member_call->getMethodDecl(); - if( !method->isConst() ) { + if( !IsEffectivelyConstCall( member_call ) ) { any_non_const = true; break; } @@ -90,6 +107,17 @@ void UnsequencedCallsCheck::onEndOfTranslationUnit() context.stmt->getBeginLoc(), "Unsequenced calls to member functions of %0, at least one of which is non-const." ) << context.on; + + for( const CXXMemberCallExpr *member_call : calls ) { + const CXXMethodDecl *method = member_call->getMethodDecl(); + if( IsEffectivelyConstCall( member_call ) ) { + diag( member_call->getBeginLoc(), "Call to const member function %0", + DiagnosticIDs::Note ) << method; + } else { + diag( member_call->getBeginLoc(), "Call to non-const member function %0", + DiagnosticIDs::Note ) << method; + } + } } } } diff --git a/tools/clang-tidy-plugin/test/unsequenced-calls.cpp b/tools/clang-tidy-plugin/test/unsequenced-calls.cpp index 600208298a494..c42bb5be9a2c9 100644 --- a/tools/clang-tidy-plugin/test/unsequenced-calls.cpp +++ b/tools/clang-tidy-plugin/test/unsequenced-calls.cpp @@ -4,6 +4,8 @@ struct A { // Define a const and a non-const member function int const_mf() const; int nonconst_mf(); + int begin(); + int end(); }; void g( int, int ); @@ -13,7 +15,11 @@ void f0() A a; // Two calls to const functions are fine g( a.const_mf(), a.const_mf() ); - // But if at least one is non-const, raise a warning + // Calls to begin/end are also fine + g( a.begin(), a.end() ); + // Calls in a ternary expression are fine + int n = a.nonconst_mf() ? a.nonconst_mf() : a.const_mf(); + // But otherwise, if at least one is non-const, raise a warning g( a.nonconst_mf(), a.const_mf() ); // CHECK-MESSAGES: [[@LINE-1]]:5: warning: Unsequenced calls to member functions of 'a', at least one of which is non-const. [cata-unsequenced-calls] g( a.const_mf(), a.nonconst_mf() ); From da1873bead08fb55c6d1a00777e34185a39bc787 Mon Sep 17 00:00:00 2001 From: John Bytheway Date: Tue, 13 Apr 2021 20:20:51 -0400 Subject: [PATCH 377/453] Treat nested calls as sequenced Previously the UnsequencedCallsCheck was giving false positives for calls where one was nested within the other; prevent that. --- .../UnsequencedCallsCheck.cpp | 105 +++++++++++++----- .../clang-tidy-plugin/UnsequencedCallsCheck.h | 17 ++- .../test/unsequenced-calls.cpp | 6 +- 3 files changed, 99 insertions(+), 29 deletions(-) diff --git a/tools/clang-tidy-plugin/UnsequencedCallsCheck.cpp b/tools/clang-tidy-plugin/UnsequencedCallsCheck.cpp index 582062342bc1e..17e517062f462 100644 --- a/tools/clang-tidy-plugin/UnsequencedCallsCheck.cpp +++ b/tools/clang-tidy-plugin/UnsequencedCallsCheck.cpp @@ -13,6 +13,7 @@ #include #include #include +#include #include "Utils.h" @@ -39,21 +40,45 @@ void UnsequencedCallsCheck::registerMatchers( MatchFinder *Finder ) // a non-expression, return the previous expression. // This is a vague approximation to finding the AST node which represents // everything between two sequence points. -static const Expr *getContainingSequenceStatement( - const ast_matchers::MatchFinder::MatchResult &Result, const Expr *Node ) +static const Expr *GetContainingSequenceStatement( ASTContext *Context, const Expr *Node ) { - for( const ast_type_traits::DynTypedNode &parent : Result.Context->getParents( *Node ) ) { + for( const ast_type_traits::DynTypedNode &parent : Context->getParents( *Node ) ) { if( parent.get() ) { return Node; } if( const Expr *Candidate = parent.get() ) { - return getContainingSequenceStatement( Result, Candidate ); + return GetContainingSequenceStatement( Context, Candidate ); } } return Node; } +// Keep walking up the AST so long as the nodes are expressions. When we reach +// a non-expression, return the previous expression. +// This is a vague approximation to finding the AST node which represents +// everything between two sequence points. +static std::vector GetAncestorExpressions( ASTContext *Context, const Expr *Node ) +{ + const Expr *stop = GetContainingSequenceStatement( Context, Node ); + std::vector result; + const Expr *next; + do { + next = nullptr; + for( const ast_type_traits::DynTypedNode &parent : Context->getParents( *Node ) ) { + if( const Expr *candidate = parent.get() ) { + next = candidate; + break; + } + } + if( next ) { + result.push_back( next ); + } + } while( next && next != stop ); + + return result; +} + void UnsequencedCallsCheck::CheckCall( const MatchFinder::MatchResult &Result ) { const CXXMemberCallExpr *MemberCall = @@ -64,10 +89,10 @@ void UnsequencedCallsCheck::CheckCall( const MatchFinder::MatchResult &Result ) return; } - const Expr *ContainingStatement = getContainingSequenceStatement( Result, MemberCall ); + const Expr *ContainingStatement = GetContainingSequenceStatement( Result.Context, MemberCall ); CallContext context{ ContainingStatement, On }; - calls_[context].push_back( MemberCall ); + calls_[context].push_back( { MemberCall, Result.Context } ); } static bool IsEffectivelyConstCall( const CXXMemberCallExpr *Call ) @@ -85,40 +110,68 @@ static bool IsEffectivelyConstCall( const CXXMemberCallExpr *Call ) void UnsequencedCallsCheck::onEndOfTranslationUnit() { - for( std::pair> &p : calls_ ) { + for( std::pair> &p : calls_ ) { const CallContext &context = p.first; - std::vector &calls = p.second; + std::vector &calls = p.second; std::sort( calls.begin(), calls.end() ); calls.erase( std::unique( calls.begin(), calls.end() ), calls.end() ); if( calls.size() < 2 ) { continue; } - bool any_non_const = false; - for( const CXXMemberCallExpr *member_call : calls ) { - if( !IsEffectivelyConstCall( member_call ) ) { - any_non_const = true; - break; + std::unordered_set non_const_calls; + for( const CallWithASTContext &member_call : calls ) { + if( !IsEffectivelyConstCall( member_call.call ) ) { + non_const_calls.insert( member_call.call ); } } - if( any_non_const ) { - diag( - context.stmt->getBeginLoc(), - "Unsequenced calls to member functions of %0, at least one of which is non-const." - ) << context.on; - - for( const CXXMemberCallExpr *member_call : calls ) { - const CXXMethodDecl *method = member_call->getMethodDecl(); - if( IsEffectivelyConstCall( member_call ) ) { - diag( member_call->getBeginLoc(), "Call to const member function %0", - DiagnosticIDs::Note ) << method; + if( non_const_calls.empty() ) { + continue; + } + + // If some of the calls are an ancestor of other of the calls then we + // might not need to report it. + std::vector to_delete; + for( const CallWithASTContext &member_call : calls ) { + for( const Expr *ancestor : + GetAncestorExpressions( member_call.context, member_call.call ) ) { + auto in_set = std::find( calls.begin(), calls.end(), ancestor ); + if( in_set == calls.end() ) { + continue; + } + // We have found a pair with an ancestor relationship. Delete + // the most const one. + if( non_const_calls.count( in_set->call ) ) { + to_delete.push_back( member_call ); } else { - diag( member_call->getBeginLoc(), "Call to non-const member function %0", - DiagnosticIDs::Note ) << method; + to_delete.push_back( *in_set ); } } } + std::sort( to_delete.begin(), to_delete.end() ); + auto new_end = std::set_difference( + calls.begin(), calls.end(), to_delete.begin(), to_delete.end(), calls.begin() ); + calls.erase( new_end, calls.end() ); + if( calls.size() < 2 ) { + continue; + } + + diag( + context.stmt->getBeginLoc(), + "Unsequenced calls to member functions of %0, at least one of which is non-const." + ) << context.on; + + for( const CallWithASTContext &member_call : calls ) { + const CXXMethodDecl *method = member_call.call->getMethodDecl(); + if( IsEffectivelyConstCall( member_call.call ) ) { + diag( member_call.call->getBeginLoc(), "Call to const member function %0", + DiagnosticIDs::Note ) << method; + } else { + diag( member_call.call->getBeginLoc(), "Call to non-const member function %0", + DiagnosticIDs::Note ) << method; + } + } } } diff --git a/tools/clang-tidy-plugin/UnsequencedCallsCheck.h b/tools/clang-tidy-plugin/UnsequencedCallsCheck.h index 132a139f1798b..9d4dec47b85f0 100644 --- a/tools/clang-tidy-plugin/UnsequencedCallsCheck.h +++ b/tools/clang-tidy-plugin/UnsequencedCallsCheck.h @@ -26,6 +26,21 @@ struct CallContext { } }; +struct CallWithASTContext { + const CXXMemberCallExpr *call; + ASTContext *context; + + bool operator==( const CallWithASTContext &other ) const { + return call == other.call; + } + bool operator==( const Expr *other ) const { + return call == other; + } + bool operator<( const CallWithASTContext &other ) const { + return std::less<> {}( call, other.call ); + } +}; + } // namespace cata } // namespace tidy } // namespace clang @@ -57,7 +72,7 @@ class UnsequencedCallsCheck : public ClangTidyCheck void onEndOfTranslationUnit() override; private: void CheckCall( const ast_matchers::MatchFinder::MatchResult & ); - std::unordered_map> calls_; + std::unordered_map> calls_; }; } // namespace cata diff --git a/tools/clang-tidy-plugin/test/unsequenced-calls.cpp b/tools/clang-tidy-plugin/test/unsequenced-calls.cpp index c42bb5be9a2c9..15eee1cf2721f 100644 --- a/tools/clang-tidy-plugin/test/unsequenced-calls.cpp +++ b/tools/clang-tidy-plugin/test/unsequenced-calls.cpp @@ -2,8 +2,8 @@ struct A { // Define a const and a non-const member function - int const_mf() const; - int nonconst_mf(); + int const_mf( int = 0 ) const; + int nonconst_mf( int = 0 ); int begin(); int end(); }; @@ -19,6 +19,8 @@ void f0() g( a.begin(), a.end() ); // Calls in a ternary expression are fine int n = a.nonconst_mf() ? a.nonconst_mf() : a.const_mf(); + // Nested calls are OK + a.nonconst_mf( a.const_mf() ); // But otherwise, if at least one is non-const, raise a warning g( a.nonconst_mf(), a.const_mf() ); // CHECK-MESSAGES: [[@LINE-1]]:5: warning: Unsequenced calls to member functions of 'a', at least one of which is non-const. [cata-unsequenced-calls] From 12d691108ba2b93933705bb6c4496f6ae9dad923 Mon Sep 17 00:00:00 2001 From: John Bytheway Date: Tue, 13 Apr 2021 20:34:38 -0400 Subject: [PATCH 378/453] Treat logical operators as sequencing Most false-positives for UnsequencedCallsCheck were related to logical operators. Handle those properly. --- tools/clang-tidy-plugin/UnsequencedCallsCheck.cpp | 6 ++++++ tools/clang-tidy-plugin/test/unsequenced-calls.cpp | 7 ++++++- 2 files changed, 12 insertions(+), 1 deletion(-) diff --git a/tools/clang-tidy-plugin/UnsequencedCallsCheck.cpp b/tools/clang-tidy-plugin/UnsequencedCallsCheck.cpp index 17e517062f462..65a706f968f0c 100644 --- a/tools/clang-tidy-plugin/UnsequencedCallsCheck.cpp +++ b/tools/clang-tidy-plugin/UnsequencedCallsCheck.cpp @@ -46,6 +46,11 @@ static const Expr *GetContainingSequenceStatement( ASTContext *Context, const Ex if( parent.get() ) { return Node; } + if( const BinaryOperator *op = parent.get() ) { + if( op->isLogicalOp() ) { + return Node; + } + } if( const Expr *Candidate = parent.get() ) { return GetContainingSequenceStatement( Context, Candidate ); } @@ -73,6 +78,7 @@ static std::vector GetAncestorExpressions( ASTContext *Context, co } if( next ) { result.push_back( next ); + Node = next; } } while( next && next != stop ); diff --git a/tools/clang-tidy-plugin/test/unsequenced-calls.cpp b/tools/clang-tidy-plugin/test/unsequenced-calls.cpp index 15eee1cf2721f..08a0a2783ce7a 100644 --- a/tools/clang-tidy-plugin/test/unsequenced-calls.cpp +++ b/tools/clang-tidy-plugin/test/unsequenced-calls.cpp @@ -18,7 +18,10 @@ void f0() // Calls to begin/end are also fine g( a.begin(), a.end() ); // Calls in a ternary expression are fine - int n = a.nonconst_mf() ? a.nonconst_mf() : a.const_mf(); + int n0 = a.nonconst_mf() ? a.nonconst_mf() : a.const_mf(); + // Or by short-circuiting boolean expressions + int n1 = a.nonconst_mf() && a.nonconst_mf(); + int n2 = a.nonconst_mf() || a.nonconst_mf(); // Nested calls are OK a.nonconst_mf( a.const_mf() ); // But otherwise, if at least one is non-const, raise a warning @@ -28,4 +31,6 @@ void f0() // CHECK-MESSAGES: [[@LINE-1]]:5: warning: Unsequenced calls to member functions of 'a', at least one of which is non-const. [cata-unsequenced-calls] g( a.nonconst_mf(), a.nonconst_mf() ); // CHECK-MESSAGES: [[@LINE-1]]:5: warning: Unsequenced calls to member functions of 'a', at least one of which is non-const. [cata-unsequenced-calls] + int n3 = a.nonconst_mf() | a.nonconst_mf(); + // CHECK-MESSAGES: [[@LINE-1]]:14: warning: Unsequenced calls to member functions of 'a', at least one of which is non-const. [cata-unsequenced-calls] } From 2109f72519bdb51b18105284e24772434e3f9e13 Mon Sep 17 00:00:00 2001 From: John Bytheway Date: Tue, 13 Apr 2021 20:49:48 -0400 Subject: [PATCH 379/453] Better identification of effectively const methods Any method with an overload which is const can be treated as effectively const for the purposes of this check (ideally we'd also see whether the resulting use was const, but that's probably more complication than necessary). --- tools/clang-tidy-plugin/UnsequencedCallsCheck.cpp | 11 ++++++++--- tools/clang-tidy-plugin/test/unsequenced-calls.cpp | 2 ++ 2 files changed, 10 insertions(+), 3 deletions(-) diff --git a/tools/clang-tidy-plugin/UnsequencedCallsCheck.cpp b/tools/clang-tidy-plugin/UnsequencedCallsCheck.cpp index 65a706f968f0c..bf5480fd3183b 100644 --- a/tools/clang-tidy-plugin/UnsequencedCallsCheck.cpp +++ b/tools/clang-tidy-plugin/UnsequencedCallsCheck.cpp @@ -107,9 +107,14 @@ static bool IsEffectivelyConstCall( const CXXMemberCallExpr *Call ) if( method->isConst() ) { return true; } - StringRef Name = method->getName(); - if( Name == "begin" || Name == "end" || Name == "find" ) { - return true; + DeclarationName name = method->getDeclName(); + DeclContextLookupResult similar_functions = method->getParent()->lookup( name ); + for( const NamedDecl *similar : similar_functions ) { + if( const CXXMethodDecl *similar_function = dyn_cast( similar ) ) { + if( similar_function->isConst() ) { + return true; + } + } } return false; } diff --git a/tools/clang-tidy-plugin/test/unsequenced-calls.cpp b/tools/clang-tidy-plugin/test/unsequenced-calls.cpp index 08a0a2783ce7a..8846a9dcf6cbc 100644 --- a/tools/clang-tidy-plugin/test/unsequenced-calls.cpp +++ b/tools/clang-tidy-plugin/test/unsequenced-calls.cpp @@ -6,6 +6,8 @@ struct A { int nonconst_mf( int = 0 ); int begin(); int end(); + int begin() const; + int end() const; }; void g( int, int ); From bfed6a2490a63261b688ac8290576131d0d1226e Mon Sep 17 00:00:00 2001 From: John Bytheway Date: Wed, 14 Apr 2021 07:09:07 -0400 Subject: [PATCH 380/453] Provide class name in UnsequencedCallsCheck It's useful for the warning message to also provide the type name of the thing on which the member function calls are being made. --- tools/clang-tidy-plugin/UnsequencedCallsCheck.cpp | 7 +++++-- tools/clang-tidy-plugin/test/unsequenced-calls.cpp | 8 ++++---- 2 files changed, 9 insertions(+), 6 deletions(-) diff --git a/tools/clang-tidy-plugin/UnsequencedCallsCheck.cpp b/tools/clang-tidy-plugin/UnsequencedCallsCheck.cpp index bf5480fd3183b..fe9729214855b 100644 --- a/tools/clang-tidy-plugin/UnsequencedCallsCheck.cpp +++ b/tools/clang-tidy-plugin/UnsequencedCallsCheck.cpp @@ -168,10 +168,13 @@ void UnsequencedCallsCheck::onEndOfTranslationUnit() continue; } + const CXXRecordDecl *class_type = calls[0].call->getRecordDecl(); + diag( context.stmt->getBeginLoc(), - "Unsequenced calls to member functions of %0, at least one of which is non-const." - ) << context.on; + "Unsequenced calls to member functions of %0 (of type %1), at least one of which is " + "non-const." + ) << context.on << class_type; for( const CallWithASTContext &member_call : calls ) { const CXXMethodDecl *method = member_call.call->getMethodDecl(); diff --git a/tools/clang-tidy-plugin/test/unsequenced-calls.cpp b/tools/clang-tidy-plugin/test/unsequenced-calls.cpp index 8846a9dcf6cbc..cd73eef2341fc 100644 --- a/tools/clang-tidy-plugin/test/unsequenced-calls.cpp +++ b/tools/clang-tidy-plugin/test/unsequenced-calls.cpp @@ -28,11 +28,11 @@ void f0() a.nonconst_mf( a.const_mf() ); // But otherwise, if at least one is non-const, raise a warning g( a.nonconst_mf(), a.const_mf() ); - // CHECK-MESSAGES: [[@LINE-1]]:5: warning: Unsequenced calls to member functions of 'a', at least one of which is non-const. [cata-unsequenced-calls] + // CHECK-MESSAGES: [[@LINE-1]]:5: warning: Unsequenced calls to member functions of 'a' (of type 'A'), at least one of which is non-const. [cata-unsequenced-calls] g( a.const_mf(), a.nonconst_mf() ); - // CHECK-MESSAGES: [[@LINE-1]]:5: warning: Unsequenced calls to member functions of 'a', at least one of which is non-const. [cata-unsequenced-calls] + // CHECK-MESSAGES: [[@LINE-1]]:5: warning: Unsequenced calls to member functions of 'a' (of type 'A'), at least one of which is non-const. [cata-unsequenced-calls] g( a.nonconst_mf(), a.nonconst_mf() ); - // CHECK-MESSAGES: [[@LINE-1]]:5: warning: Unsequenced calls to member functions of 'a', at least one of which is non-const. [cata-unsequenced-calls] + // CHECK-MESSAGES: [[@LINE-1]]:5: warning: Unsequenced calls to member functions of 'a' (of type 'A'), at least one of which is non-const. [cata-unsequenced-calls] int n3 = a.nonconst_mf() | a.nonconst_mf(); - // CHECK-MESSAGES: [[@LINE-1]]:14: warning: Unsequenced calls to member functions of 'a', at least one of which is non-const. [cata-unsequenced-calls] + // CHECK-MESSAGES: [[@LINE-1]]:14: warning: Unsequenced calls to member functions of 'a' (of type 'A'), at least one of which is non-const. [cata-unsequenced-calls] } From b3878d5d3a59720e681495ee0abafdef226418b3 Mon Sep 17 00:00:00 2001 From: John Bytheway Date: Wed, 14 Apr 2021 08:21:01 -0400 Subject: [PATCH 381/453] Know that list initialization is sequenced To avoid one more class of false positives in UnsequencedCallsCheck, note that the subexpressions of a list initialization are sequenced. --- .../clang-tidy-plugin/UnsequencedCallsCheck.cpp | 8 +++++++- .../test/unsequenced-calls.cpp | 17 +++++++++++++++++ 2 files changed, 24 insertions(+), 1 deletion(-) diff --git a/tools/clang-tidy-plugin/UnsequencedCallsCheck.cpp b/tools/clang-tidy-plugin/UnsequencedCallsCheck.cpp index fe9729214855b..5c20feb2afe1e 100644 --- a/tools/clang-tidy-plugin/UnsequencedCallsCheck.cpp +++ b/tools/clang-tidy-plugin/UnsequencedCallsCheck.cpp @@ -37,7 +37,8 @@ void UnsequencedCallsCheck::registerMatchers( MatchFinder *Finder ) } // Keep walking up the AST so long as the nodes are expressions. When we reach -// a non-expression, return the previous expression. +// a non-expression or an expressions whose subexpressions we know to be +// sequenced (like a short-circuiting logical operator), return the previous expression. // This is a vague approximation to finding the AST node which represents // everything between two sequence points. static const Expr *GetContainingSequenceStatement( ASTContext *Context, const Expr *Node ) @@ -51,6 +52,11 @@ static const Expr *GetContainingSequenceStatement( ASTContext *Context, const Ex return Node; } } + if( const CXXConstructExpr *construct = parent.get() ) { + if( construct->isListInitialization() ) { + return Node; + } + } if( const Expr *Candidate = parent.get() ) { return GetContainingSequenceStatement( Context, Candidate ); } diff --git a/tools/clang-tidy-plugin/test/unsequenced-calls.cpp b/tools/clang-tidy-plugin/test/unsequenced-calls.cpp index cd73eef2341fc..4da9839a0b289 100644 --- a/tools/clang-tidy-plugin/test/unsequenced-calls.cpp +++ b/tools/clang-tidy-plugin/test/unsequenced-calls.cpp @@ -12,6 +12,10 @@ struct A { void g( int, int ); +struct B { + B( int, int ); +}; + void f0() { A a; @@ -36,3 +40,16 @@ void f0() int n3 = a.nonconst_mf() | a.nonconst_mf(); // CHECK-MESSAGES: [[@LINE-1]]:14: warning: Unsequenced calls to member functions of 'a' (of type 'A'), at least one of which is non-const. [cata-unsequenced-calls] } + +void f1() +{ + A a; + // Calls in args to a 'regular' constructor are dangerous + B b0( a.nonconst_mf(), a.nonconst_mf() ); + // CHECK-MESSAGES: [[@LINE-1]]:7: warning: Unsequenced calls to member functions of 'a' (of type 'A'), at least one of which is non-const. [cata-unsequenced-calls] + + // ...but using an initializer-list style is OK, because those are + // sequenced. + B b1{ a.nonconst_mf(), a.nonconst_mf() }; + B b2 = { a.nonconst_mf(), a.nonconst_mf() }; +} From 563aa5a991cec98826749e09358f25251d6ef0c2 Mon Sep 17 00:00:00 2001 From: John Bytheway Date: Wed, 14 Apr 2021 08:22:28 -0400 Subject: [PATCH 382/453] Fix warnings discovered by UnsequencesCallsCheck These are mostly just member functions which should have been const but weren't. There were a few places where I chose to refactor the code and one place got a suppression. I don't think any of these were actual bugs, but in some cases they could have become bugs in the right corner cases. --- src/construction.cpp | 2 +- src/iexamine.cpp | 3 ++- src/item.cpp | 5 +---- src/item.h | 2 +- src/iuse.cpp | 3 ++- src/mapgendata.cpp | 1 + src/melee.cpp | 3 ++- src/mission.cpp | 4 ++-- src/mission.h | 4 ++-- src/monster.cpp | 6 +++--- src/monster.h | 6 +++--- src/npctalk_funcs.cpp | 6 ++++-- src/overmap.h | 6 ++++++ src/pathfinding.cpp | 2 +- src/ranged.cpp | 6 ++++-- src/vehicle.cpp | 2 +- src/vehicle.h | 3 +-- src/vehicle_move.cpp | 2 +- src/visitable.cpp | 8 ++++---- tests/crafting_test.cpp | 3 ++- 20 files changed, 44 insertions(+), 33 deletions(-) diff --git a/src/construction.cpp b/src/construction.cpp index 37bff408b3a50..9b6ebf9726bc2 100644 --- a/src/construction.cpp +++ b/src/construction.cpp @@ -1195,7 +1195,7 @@ void construct::done_grave( const tripoint &p ) Character &player_character = get_player_character(); map &here = get_map(); map_stack its = here.i_at( p ); - for( item it : its ) { + for( const item &it : its ) { if( it.is_corpse() ) { if( it.get_corpse_name().empty() ) { if( it.get_mtype()->has_flag( MF_HUMAN ) ) { diff --git a/src/iexamine.cpp b/src/iexamine.cpp index 960a14c74ae90..a112f5a39d19a 100644 --- a/src/iexamine.cpp +++ b/src/iexamine.cpp @@ -6087,7 +6087,8 @@ void iexamine::workbench_internal( player &p, const tripoint &examp, break; } const recipe &rec = selected_craft->get_making(); - if( p.has_recipe( &rec, p.crafting_inventory(), p.get_crafting_helpers() ) == -1 ) { + const inventory &inv = p.crafting_inventory(); + if( p.has_recipe( &rec, inv, p.get_crafting_helpers() ) == -1 ) { p.add_msg_player_or_npc( _( "You don't know the recipe for the %s and can't continue crafting." ), _( " doesn't know the recipe for the %s and can't continue crafting." ), diff --git a/src/item.cpp b/src/item.cpp index e81419c5df16e..d37d66cb1172e 100644 --- a/src/item.cpp +++ b/src/item.cpp @@ -10604,11 +10604,8 @@ std::string item::type_name( unsigned int quantity ) const return ret_name; } -std::string item::get_corpse_name() +std::string item::get_corpse_name() const { - if( corpse_name.empty() ) { - return std::string(); - } return corpse_name; } diff --git a/src/item.h b/src/item.h index 7d2785a6ed39f..bd3b4971b1312 100644 --- a/src/item.h +++ b/src/item.h @@ -2087,7 +2087,7 @@ class item : public visitable /** * Returns name of deceased being if it had any or empty string if not **/ - std::string get_corpse_name(); + std::string get_corpse_name() const; /** * Returns the translated item name for the item with given id. * The name is in the proper plural form as specified by the diff --git a/src/iuse.cpp b/src/iuse.cpp index 3f0ca0adce021..de7d7363e7bd0 100644 --- a/src/iuse.cpp +++ b/src/iuse.cpp @@ -9671,7 +9671,8 @@ cata::optional iuse::craft( player *p, item *it, bool, const tripoint & ) return cata::nullopt; } const recipe &rec = it->get_making(); - if( p->has_recipe( &rec, p->crafting_inventory(), p->get_crafting_helpers() ) == -1 ) { + const inventory &inv = p->crafting_inventory(); + if( p->has_recipe( &rec, inv, p->get_crafting_helpers() ) == -1 ) { p->add_msg_player_or_npc( _( "You don't know the recipe for the %s and can't continue crafting." ), _( " doesn't know the recipe for the %s and can't continue crafting." ), diff --git a/src/mapgendata.cpp b/src/mapgendata.cpp index af83b99ceffb3..461111506954a 100644 --- a/src/mapgendata.cpp +++ b/src/mapgendata.cpp @@ -25,6 +25,7 @@ mapgendata::mapgendata( oter_id north, oter_id east, oter_id south, oter_id west mapgendata::mapgendata( const tripoint_abs_omt &over, map &m, const float density, const time_point &when, ::mission *const miss ) +// NOLINTNEXTLINE( cata-unsequenced-calls ) : mapgendata( overmap_buffer.ter( over + tripoint_north ), overmap_buffer.ter( over + tripoint_east ), overmap_buffer.ter( over + tripoint_south ), diff --git a/src/melee.cpp b/src/melee.cpp index 856aa4f645486..2466c12332a46 100644 --- a/src/melee.cpp +++ b/src/melee.cpp @@ -1698,7 +1698,8 @@ void Character::perform_technique( const ma_technique &technique, Creature &t, d } if( technique.disarms && p != nullptr && p->is_armed() ) { - here.add_item_or_charges( p->pos(), p->remove_weapon() ); + item weap = p->remove_weapon(); + here.add_item_or_charges( p->pos(), weap ); if( p->is_player() ) { add_msg_if_npc( _( " disarms you!" ) ); } else { diff --git a/src/mission.cpp b/src/mission.cpp index b68858bf33cf3..64848fb2f96ed 100644 --- a/src/mission.cpp +++ b/src/mission.cpp @@ -733,7 +733,7 @@ character_id mission::get_assigned_player_id() const return player_id; } -std::string mission::name() +std::string mission::name() const { if( type == nullptr ) { return "NULL"; @@ -741,7 +741,7 @@ std::string mission::name() return type->tname(); } -mission_type_id mission::mission_id() +mission_type_id mission::mission_id() const { if( type == nullptr ) { return mission_type_id( "NULL" ); diff --git a/src/mission.h b/src/mission.h index 0792b5ad2c0f0..0e37a2d3f5917 100644 --- a/src/mission.h +++ b/src/mission.h @@ -352,8 +352,8 @@ class mission character_id player_id; public: - std::string name(); - mission_type_id mission_id(); + std::string name() const; + mission_type_id mission_id() const; void serialize( JsonOut &json ) const; void deserialize( JsonIn &jsin ); diff --git a/src/monster.cpp b/src/monster.cpp index 78a3a7f2c3804..69e3ca2beb55a 100644 --- a/src/monster.cpp +++ b/src/monster.cpp @@ -1096,7 +1096,7 @@ void monster::shift( const point &sm_shift ) } } -tripoint monster::move_target() +tripoint monster::move_target() const { return goal; } @@ -2846,7 +2846,7 @@ void monster::add_msg_debug_player_or_npc( debugmode::debug_filter type, add_msg_debug_if_player_sees( *this, type, replace_with_npc_name( npc_msg ) ); } -units::mass monster::get_carried_weight() +units::mass monster::get_carried_weight() const { units::mass total_weight = 0_gram; if( tack_item ) { @@ -2864,7 +2864,7 @@ units::mass monster::get_carried_weight() return total_weight; } -units::volume monster::get_carried_volume() +units::volume monster::get_carried_volume() const { units::volume total_volume = 0_ml; for( const item &it : inv ) { diff --git a/src/monster.h b/src/monster.h index e3c4bf2d3d484..b509c01df8974 100644 --- a/src/monster.h +++ b/src/monster.h @@ -173,7 +173,7 @@ class monster : public Creature void serialize( JsonOut &json ) const; void deserialize( JsonIn &jsin ); - tripoint move_target(); // Returns point at the end of the monster's current plans + tripoint move_target() const; // Returns point at the end of the monster's current plans Creature *attack_target(); // Returns the creature at the end of plans (if hostile) // Movement @@ -467,8 +467,8 @@ class monster : public Creature cata::value_ptr armor_item; // item of armor the monster may be wearing cata::value_ptr storage_item; // storage item for monster carrying items cata::value_ptr battery_item; // item to power mechs - units::mass get_carried_weight(); - units::volume get_carried_volume(); + units::mass get_carried_weight() const; + units::volume get_carried_volume() const; void move_special_item_to_inv( cata::value_ptr &it ); // DEFINING VALUES diff --git a/src/npctalk_funcs.cpp b/src/npctalk_funcs.cpp index 45f092e1610e9..fe2ab3eb640f4 100644 --- a/src/npctalk_funcs.cpp +++ b/src/npctalk_funcs.cpp @@ -918,7 +918,8 @@ void talk_function::drop_weapon( npc &p ) if( p.is_hallucination() ) { return; } - get_map().add_item_or_charges( p.pos(), p.remove_weapon() ); + item weap = p.remove_weapon(); + get_map().add_item_or_charges( p.pos(), weap ); } void talk_function::player_weapon_away( npc &/*p*/ ) @@ -930,7 +931,8 @@ void talk_function::player_weapon_away( npc &/*p*/ ) void talk_function::player_weapon_drop( npc &/*p*/ ) { Character &player_character = get_player_character(); - get_map().add_item_or_charges( player_character.pos(), player_character.remove_weapon() ); + item weap = player_character.remove_weapon(); + get_map().add_item_or_charges( player_character.pos(), weap ); } void talk_function::lead_to_safety( npc &p ) diff --git a/src/overmap.h b/src/overmap.h index 65261344dc234..e1b64da5cfb50 100644 --- a/src/overmap.h +++ b/src/overmap.h @@ -137,9 +137,15 @@ class overmap_special_batch std::vector::iterator begin() { return placements.begin(); } + std::vector::const_iterator begin() const { + return placements.begin(); + } std::vector::iterator end() { return placements.end(); } + std::vector::const_iterator end() const { + return placements.end(); + } std::vector::iterator erase( std::vector::iterator pos ) { return placements.erase( pos ); diff --git a/src/pathfinding.cpp b/src/pathfinding.cpp index e9a6d0b8f58c7..d02963f7c00a8 100644 --- a/src/pathfinding.cpp +++ b/src/pathfinding.cpp @@ -351,7 +351,7 @@ std::vector map::route( const tripoint &f, const tripoint &t, } else if( part >= 0 && bash > 0 ) { // Car obstacle that isn't a door // TODO: Account for armor - int hp = veh->cpart( part ).hp(); + int hp = veh->part( part ).hp(); if( hp / 20 > bash ) { // Threshold damage thing means we just can't bash this down layer.state[index] = ASL_CLOSED; diff --git a/src/ranged.cpp b/src/ranged.cpp index 65204f8f22ca2..6a738950b32bc 100644 --- a/src/ranged.cpp +++ b/src/ranged.cpp @@ -702,7 +702,8 @@ void npc::pretend_fire( npc *source, int shots, item &gun ) add_msg_if_player_sees( *source, m_info, _( "%s shoots something." ), source->disp_name() ); } while( curshot != shots ) { - if( gun.ammo_consume( gun.ammo_required(), pos() ) != gun.ammo_required() ) { + const int required = gun.ammo_required(); + if( gun.ammo_consume( required, pos() ) != required ) { debugmsg( "Unexpected shortage of ammo whilst firing %s", gun.tname().c_str() ); break; } @@ -808,7 +809,8 @@ int player::fire_gun( const tripoint &target, int shots, item &gun ) } } - if( gun.ammo_consume( gun.ammo_required(), pos() ) != gun.ammo_required() ) { + const int required = gun.ammo_required(); + if( gun.ammo_consume( required, pos() ) != required ) { debugmsg( "Unexpected shortage of ammo whilst firing %s", gun.tname() ); break; } diff --git a/src/vehicle.cpp b/src/vehicle.cpp index bab24e12ea761..39e0ab0c4485c 100644 --- a/src/vehicle.cpp +++ b/src/vehicle.cpp @@ -7212,7 +7212,7 @@ vehicle_part &vehicle::part( int part_num ) return parts[part_num]; } -const vehicle_part &vehicle::cpart( int part_num ) const +const vehicle_part &vehicle::part( int part_num ) const { return const_cast( parts[part_num] ); } diff --git a/src/vehicle.h b/src/vehicle.h index a96e8fc8fcf2b..673db9febd9bf 100644 --- a/src/vehicle.h +++ b/src/vehicle.h @@ -1834,8 +1834,7 @@ class vehicle int part_count() const; // Returns the vehicle_part with the given part number vehicle_part &part( int part_num ); - // Same as vehicle::part() except with const binding - const vehicle_part &cpart( int part_num ) const; + const vehicle_part &part( int part_num ) const; // Determines whether the given part_num is valid for this vehicle bool valid_part( int part_num ) const; // Forcibly removes a part from this vehicle. Only exists to support faction_camp.cpp diff --git a/src/vehicle_move.cpp b/src/vehicle_move.cpp index 2db0620d7e6bc..2ee74d0c56937 100644 --- a/src/vehicle_move.cpp +++ b/src/vehicle_move.cpp @@ -2020,7 +2020,7 @@ float map::vehicle_wheel_traction( const vehicle &veh, float traction_wheel_area = 0.0f; for( int p : wheel_indices ) { const tripoint &pp = veh.global_part_pos3( p ); - const int wheel_area = veh.cpart( p ).wheel_area(); + const int wheel_area = veh.part( p ).wheel_area(); const auto &tr = ter( pp ).obj(); // Deep water and air diff --git a/src/visitable.cpp b/src/visitable.cpp index e0933fc7398a2..f797bd3c6bef1 100644 --- a/src/visitable.cpp +++ b/src/visitable.cpp @@ -130,11 +130,11 @@ static int has_quality_from_vpart( const vehicle &veh, int part, const quality_i { int qty = 0; - point pos = veh.cpart( part ).mount; + point pos = veh.part( part ).mount; for( const auto &n : veh.parts_at_relative( pos, true ) ) { // only unbroken parts can provide tool qualities - if( !veh.cpart( n ).is_broken() ) { + if( !veh.part( n ).is_broken() ) { auto tq = veh.part_info( n ).qualities; auto iter = tq.find( qual ); @@ -239,11 +239,11 @@ static int max_quality_from_vpart( const vehicle &veh, int part, const quality_i { int res = INT_MIN; - point pos = veh.cpart( part ).mount; + point pos = veh.part( part ).mount; for( const auto &n : veh.parts_at_relative( pos, true ) ) { // only unbroken parts can provide tool qualities - if( !veh.cpart( n ).is_broken() ) { + if( !veh.part( n ).is_broken() ) { auto tq = veh.part_info( n ).qualities; auto iter = tq.find( qual ); diff --git a/tests/crafting_test.cpp b/tests/crafting_test.cpp index 492c4c802dbf6..6e99dfcb60459 100644 --- a/tests/crafting_test.cpp +++ b/tests/crafting_test.cpp @@ -371,7 +371,8 @@ static int actually_test_craft( const recipe_id &rid, int interrupt_after_turns, // This really shouldn't be needed, but for some reason the tests fail for mingw builds without it player_character.learn_recipe( &rec ); - REQUIRE( player_character.has_recipe( &rec, player_character.crafting_inventory(), + const inventory &inv = player_character.crafting_inventory(); + REQUIRE( player_character.has_recipe( &rec, inv, player_character.get_crafting_helpers() ) != -1 ); player_character.remove_weapon(); REQUIRE( !player_character.is_armed() ); From 6de5f93e91a97bfefbc9c9ea2160e81f0e380160 Mon Sep 17 00:00:00 2001 From: John Bytheway Date: Mon, 5 Apr 2021 13:28:43 -0400 Subject: [PATCH 383/453] Add new try_parse_integer API All the existing ways to parse strings to integers are pretty terrible for one reason or another. They offer poor error handling, are verbose, and/or don't make it obvious whether they are influenced by the current locale. Introduce a new API to attempt to simplify the conversion of strings to ints, using a ret_val for error handling, and with explicit control over locale. Also add unit tests. --- src/try_parse_integer.cpp | 36 ++++++++++ src/try_parse_integer.h | 23 +++++++ tests/test_try_parse_integer.cpp | 109 +++++++++++++++++++++++++++++++ 3 files changed, 168 insertions(+) create mode 100644 src/try_parse_integer.cpp create mode 100644 src/try_parse_integer.h create mode 100644 tests/test_try_parse_integer.cpp diff --git a/src/try_parse_integer.cpp b/src/try_parse_integer.cpp new file mode 100644 index 0000000000000..6a0e74921dca8 --- /dev/null +++ b/src/try_parse_integer.cpp @@ -0,0 +1,36 @@ +#include "try_parse_integer.h" + +#include + +#include "translations.h" + +template +ret_val try_parse_integer( const std::string &s, bool use_locale ) +{ + // Using stringstream-based parsing because that's the only one in the + // standard library for which it's possible to turn off the + // locale-dependency. Once we're using C++17 we could use a combination of + // std::from_chars and std::strto* functions, but this should be fine so + // long as the code is not performance-critical. + std::istringstream buffer( s ); + if( !use_locale ) { + buffer.imbue( std::locale::classic() ); + } + T result; + buffer >> result; + if( !buffer ) { + return ret_val::make_failure( + 0, string_format( _( "Could not convert '%s' to an integer" ), s ) ); + } + char c; + buffer >> c; + if( buffer ) { + return ret_val::make_failure( + 0, string_format( _( "Stray characters after integer in '%s'" ), s ) ); + } + return ret_val::make_success( result ); +} + +template ret_val try_parse_integer( const std::string &, bool use_locale ); +template ret_val try_parse_integer( const std::string &, bool use_locale ); +template ret_val try_parse_integer( const std::string &, bool use_locale ); diff --git a/src/try_parse_integer.h b/src/try_parse_integer.h new file mode 100644 index 0000000000000..64d3bfe516108 --- /dev/null +++ b/src/try_parse_integer.h @@ -0,0 +1,23 @@ +#pragma once +#ifndef CATA_SRC_TRY_PARSE_INTEGER_H +#define CATA_SRC_TRY_PARSE_INTEGER_H + +#include "ret_val.h" + +/** + * Convert a string to an integer or provide an error message indicating what + * went wrong in trying to do so. + * + * @param use_locale Whether to use a number-parsing function that might permit + * formats specific to the user's locale. Generally would be true for + * player-input values, and false for values from e.g. game data files. + */ +template +ret_val try_parse_integer( const std::string &, bool use_locale ); + +extern template ret_val try_parse_integer( const std::string &, bool use_locale ); +extern template ret_val try_parse_integer( const std::string &, bool use_locale ); +extern template ret_val try_parse_integer( + const std::string &, bool use_locale ); + +#endif // CATA_SRC_TRY_PARSE_INTEGER_H diff --git a/tests/test_try_parse_integer.cpp b/tests/test_try_parse_integer.cpp new file mode 100644 index 0000000000000..e8464383cdbae --- /dev/null +++ b/tests/test_try_parse_integer.cpp @@ -0,0 +1,109 @@ +#include "catch/catch.hpp" +#include "try_parse_integer.h" + +TEMPLATE_TEST_CASE( "try_parse_int_simple_parsing", "[try_parse_integer]", int, long, long long ) +{ + try { + std::locale::global( std::locale( "en_US.UTF-8" ) ); + } catch( std::runtime_error & ) { + // On platforms where we can't set the locale, the test should still + // pass + } + CAPTURE( setlocale( LC_ALL, nullptr ) ); + CAPTURE( std::locale().name() ); + + bool use_locale = GENERATE( false, true ); + CAPTURE( use_locale ); + + SECTION( "successes" ) { + { + ret_val result = try_parse_integer( "1234", use_locale ); + CAPTURE( result.str() ); + CHECK( result.success() ); + CHECK( result.value() == 1234 ); + } + { + ret_val result = try_parse_integer( "-1234", use_locale ); + CAPTURE( result.str() ); + CHECK( result.success() ); + CHECK( result.value() == -1234 ); + } + { + ret_val result = try_parse_integer( "+1234", use_locale ); + CAPTURE( result.str() ); + CHECK( result.success() ); + CHECK( result.value() == +1234 ); + } + { + ret_val result = try_parse_integer( " 1234", use_locale ); + CAPTURE( result.str() ); + CHECK( result.success() ); + CHECK( result.value() == 1234 ); + } + } + + SECTION( "errors" ) { + { + ret_val result = try_parse_integer( "", use_locale ); + CHECK( !result.success() ); + CHECK( result.str() == "Could not convert '' to an integer" ); + } + { + ret_val result = try_parse_integer( "a", use_locale ); + CHECK( !result.success() ); + CHECK( result.str() == "Could not convert 'a' to an integer" ); + } + { + // Verify that we detect overflow + ret_val result = + try_parse_integer( "999999999999999999999", use_locale ); + CHECK( !result.success() ); + CHECK( result.str() == "Could not convert '999999999999999999999' to an integer" ); + } + } +} + +TEMPLATE_TEST_CASE( "try_parse_int_locale_parsing", "[try_parse_integer]", int, long, long long ) +{ + SECTION( "de_DE" ) { + try { + std::locale::global( std::locale( "de_DE.UTF-8" ) ); + } catch( std::runtime_error & ) { + // On platforms where we can't set the locale, ignore this test + return; + } + CAPTURE( setlocale( LC_ALL, nullptr ) ); + CAPTURE( std::locale().name() ); + { + ret_val result = try_parse_integer( "1.234", true ); + CHECK( result.success() ); + CHECK( result.value() == 1234 ); + } + { + ret_val result = try_parse_integer( "1.234", false ); + CHECK( !result.success() ); + CHECK( result.str() == "Stray characters after integer in '1.234'" ); + } + } + + SECTION( "en_US" ) { + try { + std::locale::global( std::locale( "en_US.UTF-8" ) ); + } catch( std::runtime_error & ) { + // On platforms where we can't set the locale, ignore this test + return; + } + CAPTURE( setlocale( LC_ALL, nullptr ) ); + CAPTURE( std::locale().name() ); + { + ret_val result = try_parse_integer( "1,234", true ); + CHECK( result.success() ); + CHECK( result.value() == 1234 ); + } + { + ret_val result = try_parse_integer( "1,234", false ); + CHECK( !result.success() ); + CHECK( result.str() == "Stray characters after integer in '1,234'" ); + } + } +} From bdbcebdd9c62abe341da40d684b5f4cab526e601 Mon Sep 17 00:00:00 2001 From: John Bytheway Date: Mon, 5 Apr 2021 14:13:37 -0400 Subject: [PATCH 384/453] Port string_input_popup to try_parse_integer Stop using atoi in favour of the new API. --- src/string_input_popup.cpp | 56 ++++++++++++++++++++++++++++---------- 1 file changed, 42 insertions(+), 14 deletions(-) diff --git a/src/string_input_popup.cpp b/src/string_input_popup.cpp index 3a1fdc8b7e817..0c034f98c982b 100644 --- a/src/string_input_popup.cpp +++ b/src/string_input_popup.cpp @@ -7,6 +7,7 @@ #include "output.h" #include "point.h" #include "translations.h" +#include "try_parse_integer.h" #include "ui.h" #include "ui_manager.h" #include "uistate.h" @@ -283,14 +284,31 @@ void string_input_popup::query( const bool loop, const bool draw_only ) query_string( loop, draw_only ); } +template +T query_int_impl( string_input_popup &p, const bool loop, const bool draw_only ) +{ + do { + ret_val result = try_parse_integer( p.query_string( loop, draw_only ), true ); + if( p.canceled() ) { + return 0; + } + if( result.success() ) { + return result.value(); + } + popup( result.str() ); + } while( loop ); + + return 0; +} + int string_input_popup::query_int( const bool loop, const bool draw_only ) { - return std::atoi( query_string( loop, draw_only ).c_str() ); + return query_int_impl( *this, loop, draw_only ); } int64_t string_input_popup::query_int64_t( const bool loop, const bool draw_only ) { - return std::atoll( query_string( loop, draw_only ).c_str() ); + return query_int_impl( *this, loop, draw_only ); } const std::string &string_input_popup::query_string( const bool loop, const bool draw_only ) @@ -535,25 +553,35 @@ void string_input_popup::edit( std::string &value ) } } +template +static void edit_integer( string_input_popup &p, T &value ) +{ + p.only_digits( true ); + while( true ) { + p.text( std::to_string( value ) ); + p.query(); + if( p.canceled() ) { + break; + } + ret_val parsed_val = try_parse_integer( p.text(), true ); + if( parsed_val.success() ) { + value = parsed_val.value(); + break; + } else { + popup( parsed_val.str() ); + } + } +} + // NOLINTNEXTLINE(cata-no-long) void string_input_popup::edit( long &value ) { - only_digits( true ); - text( std::to_string( value ) ); - query(); - if( !canceled() ) { - value = std::atol( text().c_str() ); - } + edit_integer( *this, value ); } void string_input_popup::edit( int &value ) { - only_digits( true ); - text( std::to_string( value ) ); - query(); - if( !canceled() ) { - value = std::atoi( text().c_str() ); - } + edit_integer( *this, value ); } string_input_popup &string_input_popup::text( const std::string &value ) From 9f0f7d8a31d60a83bc3b76388fb262f6fb27becf Mon Sep 17 00:00:00 2001 From: John Bytheway Date: Mon, 5 Apr 2021 15:21:21 -0400 Subject: [PATCH 385/453] Improve cata-no-long check We need to suppress warnings nested arbitrarily deep in template specializations; previously we were only suppressing warnings where the immediate context was a template specialization. --- tools/clang-tidy-plugin/NoLongCheck.cpp | 48 +++++++++++++++++------- tools/clang-tidy-plugin/test/no-long.cpp | 17 +++++++++ 2 files changed, 52 insertions(+), 13 deletions(-) diff --git a/tools/clang-tidy-plugin/NoLongCheck.cpp b/tools/clang-tidy-plugin/NoLongCheck.cpp index e9d1282d00401..866a236dc1553 100644 --- a/tools/clang-tidy-plugin/NoLongCheck.cpp +++ b/tools/clang-tidy-plugin/NoLongCheck.cpp @@ -87,6 +87,36 @@ static std::string AlternativesFor( QualType Type ) } } +static bool AnyDeclContextIsSpecialization( const Decl *D ) +{ + Decl::Kind contextKind = D->getDeclContext()->getDeclKind(); + TemplateSpecializationKind tsk = TSK_Undeclared; + const Decl *ContextDecl = nullptr; + if( contextKind == Decl::Function || contextKind == Decl::CXXMethod || + contextKind == Decl::CXXConstructor || contextKind == Decl::CXXConversion || + contextKind == Decl::CXXDestructor || contextKind == Decl::CXXDeductionGuide ) { + const FunctionDecl *C = static_cast( D->getDeclContext() ); + ContextDecl = C; + tsk = C->getTemplateSpecializationKind(); + } + if( contextKind == Decl::CXXRecord || contextKind == Decl::ClassTemplateSpecialization || + contextKind == Decl::ClassTemplatePartialSpecialization ) { + const CXXRecordDecl *C = static_cast( D->getDeclContext() ); + ContextDecl = C; + tsk = C->getTemplateSpecializationKind(); + } + if( !ContextDecl ) { + return false; + } + if( tsk != TSK_Undeclared ) { + // This happens for e.g. a parameter 'T a' to an instantiated + // template function where T is long. We don't want to report such + // cases. + return true; + } + return AnyDeclContextIsSpecialization( ContextDecl ); +} + static void CheckDecl( NoLongCheck &Check, const MatchFinder::MatchResult &Result ) { const ValueDecl *MatchedDecl = Result.Nodes.getNodeAs( "decl" ); @@ -103,19 +133,11 @@ static void CheckDecl( NoLongCheck &Check, const MatchFinder::MatchResult &Resul // generated function return; } - Decl::Kind contextKind = MatchedDecl->getDeclContext()->getDeclKind(); - if( contextKind == Decl::Function || contextKind == Decl::CXXMethod || - contextKind == Decl::CXXConstructor || contextKind == Decl::CXXConversion || - contextKind == Decl::CXXDestructor || contextKind == Decl::CXXDeductionGuide ) { - TemplateSpecializationKind tsk = - static_cast( - MatchedDecl->getDeclContext() )->getTemplateSpecializationKind(); - if( tsk == TSK_ImplicitInstantiation ) { - // This happens for e.g. a parameter 'T a' to an instantiated - // template function where T is long. We don't want to report such - // cases. - return; - } + if( AnyDeclContextIsSpecialization( MatchedDecl ) ) { + // This happens for e.g. a parameter 'T a' to an instantiated + // template function where T is long. We don't want to report such + // cases. + return; } Check.diag( MatchedDecl->getLocation(), "Variable %0 declared as %1. %2." ) << diff --git a/tools/clang-tidy-plugin/test/no-long.cpp b/tools/clang-tidy-plugin/test/no-long.cpp index a0a7f1b8d87e6..4f6672c5785a8 100644 --- a/tools/clang-tidy-plugin/test/no-long.cpp +++ b/tools/clang-tidy-plugin/test/no-long.cpp @@ -105,3 +105,20 @@ void Bf() template long g1( T g1p0 ); // CHECK-MESSAGES: warning: Function 'g1' declared as returning 'long'. Prefer int or int64_t to long. [cata-no-long] + +template +struct A1 { + void f( T a1a ) { + } + T a1b; +}; + +template +A1 f5() +{ + return {}; +} + +// Would be nice to get warnings here but haven't found a way to do so. +extern template A1 f5(); +template A1 f5(); From d775d1d81db29924c5ef6ea670d7d72b26edc30e Mon Sep 17 00:00:00 2001 From: John Bytheway Date: Mon, 5 Apr 2021 19:55:48 -0400 Subject: [PATCH 386/453] Stop using atoi in safemode_ui It was only being used to convert an option value, and that functionality is already built into options. --- src/safemode_ui.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/safemode_ui.cpp b/src/safemode_ui.cpp index 82a19efc45126..24b9b5620b22d 100644 --- a/src/safemode_ui.cpp +++ b/src/safemode_ui.cpp @@ -439,7 +439,7 @@ void safemode::show( const std::string &custom_name_in, bool is_safemode_in ) //Let the options class handle the validity of the new value options_manager::cOpt temp_option = get_options().get_option( "SAFEMODEPROXIMITY" ); temp_option.setValue( text ); - current_tab[line].proximity = atoi( temp_option.getValue().c_str() ); + current_tab[line].proximity = temp_option.value_as(); } } } else if( action == "ENABLE_RULE" && !current_tab.empty() ) { From 0120c54832ae6ff97488910632d7605a53b84589 Mon Sep 17 00:00:00 2001 From: John Bytheway Date: Mon, 5 Apr 2021 20:31:03 -0400 Subject: [PATCH 387/453] Stop using atoi in output.cpp This was using it to convert the result of a string_input_popup, but that functionality is already built in to that class, so just use it. --- src/output.cpp | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/src/output.cpp b/src/output.cpp index 545cbf00c5e07..e8c22e2f1ee70 100644 --- a/src/output.cpp +++ b/src/output.cpp @@ -719,11 +719,11 @@ bool query_int( int &result, const std::string &text ) string_input_popup popup; popup.title( text ); popup.text( "" ).only_digits( true ); - popup.query(); + int temp = popup.query_int(); if( popup.canceled() ) { return false; } - result = atoi( popup.text().c_str() ); + result = temp; return true; } From 788d186ca22764dfba24fe3e3351cf98e05cc548 Mon Sep 17 00:00:00 2001 From: John Bytheway Date: Mon, 5 Apr 2021 20:50:35 -0400 Subject: [PATCH 388/453] Stop using atoi in debug_menu.cpp Port one use to string_input_popup::query_int, the others to try_parse_integer. --- src/debug_menu.cpp | 41 +++++++++++++++++++++++++++++------------ 1 file changed, 29 insertions(+), 12 deletions(-) diff --git a/src/debug_menu.cpp b/src/debug_menu.cpp index 8233d04ddc03d..f50b9a6978440 100644 --- a/src/debug_menu.cpp +++ b/src/debug_menu.cpp @@ -95,6 +95,7 @@ #include "string_input_popup.h" #include "trait_group.h" #include "translations.h" +#include "try_parse_integer.h" #include "type_id.h" #include "ui.h" #include "ui_manager.h" @@ -1040,17 +1041,33 @@ void teleport_overmap( bool specific_coordinates ) tripoint_abs_omt where; if( specific_coordinates ) { const std::string text = string_input_popup() - .title( "Teleport where?" ) + .title( _( "Teleport where?" ) ) .width( 20 ) .query_string(); if( text.empty() ) { return; } const std::vector coord_strings = string_split( text, ',' ); + if( coord_strings.size() < 2 || coord_strings.size() > 3 ) { + popup( _( "Error interpreting teleport target: " + "expected two or three comma-separated values; got %zu" ), + coord_strings.size() ); + return; + } + std::vector coord_ints; + for( const std::string &coord_string : coord_strings ) { + ret_val parsed_coord = try_parse_integer( coord_string, true ); + if( !parsed_coord.success() ) { + popup( _( "Error interpreting teleport target: %s" ), parsed_coord.str() ); + return; + } + coord_ints.push_back( parsed_coord.value() ); + } + cata_assert( coord_ints.size() >= 2 ); tripoint coord; - coord.x = !coord_strings.empty() ? std::atoi( coord_strings[0].c_str() ) : 0; - coord.y = coord_strings.size() >= 2 ? std::atoi( coord_strings[1].c_str() ) : 0; - coord.z = coord_strings.size() >= 3 ? std::atoi( coord_strings[2].c_str() ) : 0; + coord.x = coord_ints[0]; + coord.y = coord_ints[1]; + coord.z = coord_ints.size() >= 3 ? coord_ints[2] : 0; where = tripoint_abs_omt( OMAPX * coord.x, OMAPY * coord.y, coord.z ); } else { const cata::optional dir_ = choose_direction( _( "Where is the desired overmap?" ) ); @@ -2088,16 +2105,16 @@ static void debug_menu_spawn_vehicle() static void debug_menu_change_time() { auto set_turn = [&]( const int initial, const time_duration & factor, const char *const msg ) { - const auto text = string_input_popup() - .title( msg ) - .width( 20 ) - .text( std::to_string( initial ) ) - .only_digits( true ) - .query_string(); - if( text.empty() ) { + string_input_popup pop; + const int new_value = pop + .title( msg ) + .width( 20 ) + .text( std::to_string( initial ) ) + .only_digits( true ) + .query_int(); + if( pop.canceled() ) { return; } - const int new_value = std::atoi( text.c_str() ); const time_duration offset = ( new_value - initial ) * factor; // Arbitrary maximal value. const time_point max = calendar::turn_zero + time_duration::from_turns( From bf4f21e03903ee64c306c26f096d4e6c2229df30 Mon Sep 17 00:00:00 2001 From: John Bytheway Date: Mon, 5 Apr 2021 20:59:43 -0400 Subject: [PATCH 389/453] Stop using sscanf in ranged.cpp Port to new try_parse_integer API. --- src/ranged.cpp | 12 ++++++++++-- 1 file changed, 10 insertions(+), 2 deletions(-) diff --git a/src/ranged.cpp b/src/ranged.cpp index 6a738950b32bc..9ee9d44b09a10 100644 --- a/src/ranged.cpp +++ b/src/ranged.cpp @@ -66,6 +66,7 @@ #include "string_formatter.h" #include "translations.h" #include "trap.h" +#include "try_parse_integer.h" #include "type_id.h" #include "ui.h" #include "ui_manager.h" @@ -1593,8 +1594,15 @@ static projectile make_gun_projectile( const item &gun ) if( gun.ammo_data() ) { // Some projectiles have a chance of being recoverable bool recover = std::any_of( fx.begin(), fx.end(), []( const std::string & e ) { - int n; - return sscanf( e.c_str(), "RECOVER_%i", &n ) == 1 && !one_in( n ); + if( !string_starts_with( e, "RECOVER_" ) ) { + return false; + } + ret_val n = try_parse_integer( e.substr( 8 ), false ); + if( !n.success() ) { + debugmsg( "Error parsing ammo RECOVER_ denominator: %s", n.str() ); + return false; + } + return !one_in( n.value() ); } ); if( recover && !fx.count( "IGNITE" ) && !fx.count( "EXPLOSIVE" ) ) { From 7b787b6fcc74523128cbb397e5d41f59625feadb Mon Sep 17 00:00:00 2001 From: John Bytheway Date: Mon, 5 Apr 2021 21:15:16 -0400 Subject: [PATCH 390/453] Stop using atoi in options.cpp Port to new try_parse_integer API. --- src/options.cpp | 30 +++++++++++++++++++++++++----- 1 file changed, 25 insertions(+), 5 deletions(-) diff --git a/src/options.cpp b/src/options.cpp index 9e25c2fd6cf20..cbdc264e0a354 100644 --- a/src/options.cpp +++ b/src/options.cpp @@ -33,6 +33,7 @@ #include "string_formatter.h" #include "string_input_popup.h" #include "translations.h" +#include "try_parse_integer.h" #include "ui_manager.h" #include "worldfactory.h" @@ -852,17 +853,36 @@ void options_manager::cOpt::setValue( const std::string &sSetIn ) bSet = sSetIn == "True" || sSetIn == "true" || sSetIn == "T" || sSetIn == "t"; } else if( sType == "int" ) { - iSet = atoi( sSetIn.c_str() ); + // Some integer values are stored with a '%', e.g. "100%". + std::string without_percent = sSetIn; + if( string_ends_with( without_percent, "%" ) ) { + without_percent.erase( without_percent.end() - 1 ); + } + ret_val val = try_parse_integer( without_percent, false ); + + if( val.success() ) { + iSet = val.value(); - if( iSet < iMin || iSet > iMax ) { + if( iSet < iMin || iSet > iMax ) { + iSet = iDefault; + } + } else { + debugmsg( "Error parsing option as integer: %s", val.str() ); iSet = iDefault; } } else if( sType == "int_map" ) { - iSet = atoi( sSetIn.c_str() ); + ret_val val = try_parse_integer( sSetIn, false ); - auto item = findInt( iSet ); - if( !item ) { + if( val.success() ) { + iSet = val.value(); + + auto item = findInt( iSet ); + if( !item ) { + iSet = iDefault; + } + } else { + debugmsg( "Error parsing option as integer: %s", val.str() ); iSet = iDefault; } From c4ae7dd60173ddb5a438c39954b14a5d1950c5c5 Mon Sep 17 00:00:00 2001 From: John Bytheway Date: Tue, 6 Apr 2021 06:42:56 -0400 Subject: [PATCH 391/453] Stop using sscanf in iexamine.cpp Port to new try_parse_integer API. --- src/iexamine.cpp | 12 +++++++++--- 1 file changed, 9 insertions(+), 3 deletions(-) diff --git a/src/iexamine.cpp b/src/iexamine.cpp index a112f5a39d19a..ea509725eafa1 100644 --- a/src/iexamine.cpp +++ b/src/iexamine.cpp @@ -90,6 +90,7 @@ #include "timed_event.h" #include "translations.h" #include "trap.h" +#include "try_parse_integer.h" #include "ui.h" #include "ui_manager.h" #include "uistate.h" @@ -4084,9 +4085,14 @@ cata::optional iexamine::getNearFilledGasTank( const tripoint ¢er, static int getGasDiscountCardQuality( const item &it ) { for( const flag_id &tag : it.type->get_flags() ) { - int discount_value; - if( sscanf( tag->id.c_str(), "DISCOUNT_VALUE_%i", &discount_value ) == 1 ) { - return discount_value; + if( string_starts_with( tag->id.str(), "DISCOUNT_VALUE_" ) ) { + ret_val discount_value = + try_parse_integer( tag->id.str().substr( 15 ), false ); + if( discount_value.success() ) { + return discount_value.value(); + } else { + debugmsg( "Error parsing ammo DISCOUNT_VALUE_ suffix: %s", discount_value.str() ); + } } } return 0; From 73f91234c0aff31ff98ff35e3562e0236061df43 Mon Sep 17 00:00:00 2001 From: John Bytheway Date: Tue, 6 Apr 2021 07:08:11 -0400 Subject: [PATCH 392/453] Stop using atoi in iuse.cpp Port to new try_parse_integer API, via a new helper function. --- src/iuse.cpp | 41 +++++++++++++++++++++++++++-------------- 1 file changed, 27 insertions(+), 14 deletions(-) diff --git a/src/iuse.cpp b/src/iuse.cpp index de7d7363e7bd0..41eea1facc843 100644 --- a/src/iuse.cpp +++ b/src/iuse.cpp @@ -99,6 +99,7 @@ #include "timed_event.h" #include "translations.h" #include "trap.h" +#include "try_parse_integer.h" #include "type_id.h" #include "ui.h" #include "units.h" @@ -6131,6 +6132,17 @@ static void init_memory_card_with_random_stuff( item &it ) } } +static int get_quality_from_string( const std::string &s ) +{ + const ret_val try_quality = try_parse_integer( s, false ); + if( try_quality.success() ) { + return try_quality.value(); + } else { + debugmsg( "Error parsing photo quality: %s", try_quality.str() ); + return 0; + } +} + static bool einkpc_download_memory_card( player &p, item &eink, item &mc ) { bool something_downloaded = false; @@ -6247,22 +6259,22 @@ static bool einkpc_download_memory_card( player &p, item &eink, item &mc ) const std::string mtype = s; getline( f, s, ',' ); - char *chq = &s[0]; - const int quality = atoi( chq ); + const int quality = get_quality_from_string( s ); const size_t eink_strpos = photos.find( "," + mtype + "," ); if( eink_strpos == std::string::npos ) { photos += mtype + "," + string_format( "%d", quality ) + ","; } else { - const size_t strqpos = eink_strpos + mtype.size() + 2; - char *chq = &photos[strqpos]; - const int old_quality = atoi( chq ); + const size_t next_comma = photos.find( ',', strqpos ); + const int old_quality = + get_quality_from_string( photos.substr( strqpos, next_comma ) ); if( quality > old_quality ) { - chq = &string_format( "%d", quality )[0]; - photos[strqpos] = *chq; + const std::string quality_s = string_format( "%d", quality ); + cata_assert( quality_s.size() == 1 ); + photos[strqpos] = quality_s.front(); } } @@ -6516,8 +6528,7 @@ cata::optional iuse::einktabletpc( player *p, item *it, bool t, const tripo const monster dummy( monster_photos.back() ); menu_str = dummy.name(); getline( f, s, ',' ); - char *chq = &s[0]; - const int quality = atoi( chq ); + const int quality = get_quality_from_string( s ); menu_str += " [" + photo_quality_name( quality ) + "]"; pmenu.addentry( k++, true, -1, menu_str.c_str() ); } @@ -7328,11 +7339,14 @@ static void item_save_monsters( player &p, item &it, const std::vector old_quality ) { - monster_photos[ quality_num_pos ] = string_format( "%d", photo_quality )[ 0 ]; + const std::string quality_s = string_format( "%d", photo_quality ); + cata_assert( quality_s.size() == 1 ); + monster_photos[quality_num_pos] = quality_s.front(); } if( !p.is_blind() ) { if( photo_quality > old_quality ) { @@ -7645,8 +7659,7 @@ cata::optional iuse::camera( player *p, item *it, bool, const tripoint & ) descriptions.push_back( dummy.type->get_description() ); getline( f_mon, s, ',' ); - char *chq = &s[0]; - const int quality = atoi( chq ); + const int quality = get_quality_from_string( s ); menu_str += " [" + photo_quality_name( quality ) + "]"; From 6597211e1ee03d219a1c365f17198e92117066b0 Mon Sep 17 00:00:00 2001 From: John Bytheway Date: Tue, 6 Apr 2021 07:17:56 -0400 Subject: [PATCH 393/453] Stop using sscanf in item_factory.cpp Port to try_parse_integer.cpp --- src/item_factory.cpp | 17 ++++++++++++++--- 1 file changed, 14 insertions(+), 3 deletions(-) diff --git a/src/item_factory.cpp b/src/item_factory.cpp index e974b0e910d99..9b4ce667f0f4b 100644 --- a/src/item_factory.cpp +++ b/src/item_factory.cpp @@ -51,6 +51,7 @@ #include "string_formatter.h" #include "text_snippets.h" #include "translations.h" +#include "try_parse_integer.h" #include "ui.h" #include "units.h" #include "value_ptr.h" @@ -215,9 +216,19 @@ void Item_factory::finalize_pre( itype &obj ) // set light_emission based on LIGHT_[X] flag for( const auto &f : obj.item_tags ) { - int ll; - if( sscanf( f.c_str(), "LIGHT_%i", &ll ) == 1 && ll > 0 ) { - obj.light_emission = ll; + if( string_starts_with( f.str(), "LIGHT_" ) ) { + ret_val ll = try_parse_integer( f.str().substr( 6 ), false ); + if( ll.success() ) { + if( ll.value() > 0 ) { + obj.light_emission = ll.value(); + } else { + debugmsg( "item %s specifies light emission of zero, which is redundant", + obj.id.str() ); + } + } else { + debugmsg( "error parsing integer light emission suffic for item %s: %s", + obj.id.str(), ll.str() ); + } } } // remove LIGHT_[X] flags From ef86d79abe704ad0e5d098025e7302292aefa040 Mon Sep 17 00:00:00 2001 From: John Bytheway Date: Tue, 6 Apr 2021 07:48:52 -0400 Subject: [PATCH 394/453] Stop using atoi/atof in item.cpp Port to try_parse_integer and strtod. --- src/item.cpp | 43 ++++++++++++++++++++++++++++++++++++------- tests/item_test.cpp | 11 +++++++++++ 2 files changed, 47 insertions(+), 7 deletions(-) diff --git a/src/item.cpp b/src/item.cpp index d37d66cb1172e..292806369507e 100644 --- a/src/item.cpp +++ b/src/item.cpp @@ -95,6 +95,7 @@ #include "string_id_utils.h" #include "text_snippets.h" #include "translations.h" +#include "try_parse_integer.h" #include "units.h" #include "units_fwd.h" #include "units_utility.h" @@ -1185,7 +1186,19 @@ double item::get_var( const std::string &name, const double default_value ) cons if( it == item_vars.end() ) { return default_value; } - return atof( it->second.c_str() ); + const std::string &val = it->second; + char *end; + errno = 0; + double result = strtod( &val[0], &end ); + if( errno != 0 ) { + debugmsg( "Error parsing floating point value from %s in item::get_var: %s", + val, strerror( errno ) ); + return default_value; + } + if( end != &val[0] + val.size() ) { + debugmsg( "Stray characters at end of floating point value %s in item::get_var", val ); + } + return result; } void item::set_var( const std::string &name, const tripoint &value ) @@ -1200,9 +1213,19 @@ tripoint item::get_var( const std::string &name, const tripoint &default_value ) return default_value; } std::vector values = string_split( it->second, ',' ); - return tripoint( atoi( values[0].c_str() ), - atoi( values[1].c_str() ), - atoi( values[2].c_str() ) ); + cata_assert( values.size() == 3 ); + auto convert_or_error = []( const std::string & s ) { + ret_val result = try_parse_integer( s, false ); + if( result.success() ) { + return result.value(); + } else { + debugmsg( "Error parsing tripoint coordinate in item::get_var: %s", result.str() ); + return 0; + } + }; + return tripoint( convert_or_error( values[0] ), + convert_or_error( values[1] ), + convert_or_error( values[2] ) ); } void item::set_var( const std::string &name, const std::string &value ) @@ -2148,9 +2171,15 @@ void item::ammo_info( std::vector &info, const iteminfo_query *parts, } if( parts->test( iteminfo_parts::AMMO_FX_RECOVER ) ) { for( const std::string &effect : ammo.ammo_effects ) { - if( effect.compare( 0, 8, "RECOVER_" ) == 0 ) { - int recover_chance; - sscanf( effect.c_str(), "RECOVER_%i", &recover_chance ); + if( string_starts_with( effect, "RECOVER_" ) ) { + ret_val try_recover_chance = + try_parse_integer( effect.substr( 8 ), false ); + if( !try_recover_chance.success() ) { + debugmsg( "Error parsing ammo RECOVER_ denominator: %s", + try_recover_chance.str() ); + break; + } + int recover_chance = try_recover_chance.value(); if( recover_chance <= 5 ) { fx.emplace_back( _( "Stands a very low chance of remaining intact once fired." ) ); } else if( recover_chance <= 10 ) { diff --git a/tests/item_test.cpp b/tests/item_test.cpp index ddf729b01c893..33d820e3fc765 100644 --- a/tests/item_test.cpp +++ b/tests/item_test.cpp @@ -286,3 +286,14 @@ TEST_CASE( "items spawn in their default containers", "[item]" ) check_spawning_in_container( "chem_black_powder" ); check_spawning_in_container( "software_useless" ); } + +TEST_CASE( "item variables round-trip accurately", "[item]" ) +{ + item i( "water" ); + i.set_var( "A", 17 ); + CHECK( i.get_var( "A", 0 ) == 17 ); + i.set_var( "B", 0.125 ); + CHECK( i.get_var( "B", 0.0 ) == 0.125 ); + i.set_var( "C", tripoint( 2, 3, 4 ) ); + CHECK( i.get_var( "C", tripoint() ) == tripoint( 2, 3, 4 ) ); +} From 09563089be26b0a53f0c971a9e0635cf990c5539 Mon Sep 17 00:00:00 2001 From: John Bytheway Date: Sat, 10 Apr 2021 13:24:08 -0400 Subject: [PATCH 395/453] Disable some tests on Apple platforms It looks like the Mac OS tests show that it doesn't support localized integer parsing. Just disable those tests there; the feature is not super important. --- ...est_try_parse_integer.cpp => try_parse_integer_test.cpp} | 6 ++++++ 1 file changed, 6 insertions(+) rename tests/{test_try_parse_integer.cpp => try_parse_integer_test.cpp} (96%) diff --git a/tests/test_try_parse_integer.cpp b/tests/try_parse_integer_test.cpp similarity index 96% rename from tests/test_try_parse_integer.cpp rename to tests/try_parse_integer_test.cpp index e8464383cdbae..5136e2541bcd6 100644 --- a/tests/test_try_parse_integer.cpp +++ b/tests/try_parse_integer_test.cpp @@ -74,11 +74,15 @@ TEMPLATE_TEST_CASE( "try_parse_int_locale_parsing", "[try_parse_integer]", int, } CAPTURE( setlocale( LC_ALL, nullptr ) ); CAPTURE( std::locale().name() ); + // Disabling on Apple; seems like their C library doesn't do localized integer + // parsing. +#ifndef __APPLE__ { ret_val result = try_parse_integer( "1.234", true ); CHECK( result.success() ); CHECK( result.value() == 1234 ); } +#endif { ret_val result = try_parse_integer( "1.234", false ); CHECK( !result.success() ); @@ -95,11 +99,13 @@ TEMPLATE_TEST_CASE( "try_parse_int_locale_parsing", "[try_parse_integer]", int, } CAPTURE( setlocale( LC_ALL, nullptr ) ); CAPTURE( std::locale().name() ); +#ifndef __APPLE__ { ret_val result = try_parse_integer( "1,234", true ); CHECK( result.success() ); CHECK( result.value() == 1234 ); } +#endif { ret_val result = try_parse_integer( "1,234", false ); CHECK( !result.success() ); From 9fca9ad2465016fc020d02e59fe8b4292e9f11c9 Mon Sep 17 00:00:00 2001 From: John Bytheway Date: Sun, 13 Sep 2020 14:51:23 -0400 Subject: [PATCH 396/453] Enable cert-err34-c --- .clang-tidy | 1 - 1 file changed, 1 deletion(-) diff --git a/.clang-tidy b/.clang-tidy index 9b1f40408b7db..c986d1a99bac9 100644 --- a/.clang-tidy +++ b/.clang-tidy @@ -24,7 +24,6 @@ readability-*,\ -bugprone-misplaced-widening-cast,\ -bugprone-narrowing-conversions,\ -bugprone-unused-return-value,\ --cert-err34-c,\ -cert-flp30-c,\ -cert-msc30-c,\ -cert-msc32-c,\ From 3642ef96d8236fe0448c1cd5e0d1740f16cc501c Mon Sep 17 00:00:00 2001 From: John Bytheway Date: Wed, 14 Apr 2021 20:09:19 -0400 Subject: [PATCH 397/453] Work around Mac OS parsing issues Simply always set the classic locale on those platforms. --- src/try_parse_integer.cpp | 9 +++++++++ 1 file changed, 9 insertions(+) diff --git a/src/try_parse_integer.cpp b/src/try_parse_integer.cpp index 6a0e74921dca8..a4187920fa72b 100644 --- a/src/try_parse_integer.cpp +++ b/src/try_parse_integer.cpp @@ -13,9 +13,18 @@ ret_val try_parse_integer( const std::string &s, bool use_locale ) // std::from_chars and std::strto* functions, but this should be fine so // long as the code is not performance-critical. std::istringstream buffer( s ); +#ifdef __APPLE__ + // On Apple platforms we always use the classic locale, because the other + // locales seem to behave strangely. See + // https://github.com/CleverRaven/Cataclysm-DDA/pull/48431 for more + // discussion. + static_cast( use_locale ); + buffer.imbue( std::locale::classic() ); +#else if( !use_locale ) { buffer.imbue( std::locale::classic() ); } +#endif T result; buffer >> result; if( !buffer ) { From c81981712b042262812795c0416fa29502e6bc62 Mon Sep 17 00:00:00 2001 From: John Bytheway Date: Fri, 16 Apr 2021 08:15:40 -0400 Subject: [PATCH 398/453] Enable clang-tidy cert-msc{30,32,50,51}-cpp These all relate to pseudorandom number generators. --- .clang-tidy | 4 ---- 1 file changed, 4 deletions(-) diff --git a/.clang-tidy b/.clang-tidy index c986d1a99bac9..86d26ffc3eb03 100644 --- a/.clang-tidy +++ b/.clang-tidy @@ -25,10 +25,6 @@ readability-*,\ -bugprone-narrowing-conversions,\ -bugprone-unused-return-value,\ -cert-flp30-c,\ --cert-msc30-c,\ --cert-msc32-c,\ --cert-msc50-cpp,\ --cert-msc51-cpp,\ -misc-non-private-member-variables-in-classes,\ -modernize-avoid-c-arrays,\ -modernize-pass-by-value,\ From c704386ccb09145b1eefcd346c0c8aecea7f81f4 Mon Sep 17 00:00:00 2001 From: John Bytheway Date: Fri, 16 Apr 2021 10:22:36 -0400 Subject: [PATCH 399/453] Enable performance-implicit-conversion-in-loop --- .clang-tidy | 1 - 1 file changed, 1 deletion(-) diff --git a/.clang-tidy b/.clang-tidy index 86d26ffc3eb03..242dacf57f694 100644 --- a/.clang-tidy +++ b/.clang-tidy @@ -31,7 +31,6 @@ readability-*,\ -modernize-return-braced-init-list,\ -modernize-use-default-member-init,\ -modernize-use-emplace,\ --performance-implicit-conversion-in-loop,\ -performance-inefficient-string-concatenation,\ -performance-type-promotion-in-math-fn,\ -performance-unnecessary-value-param,\ From 05a9945260ee4b03bcbdaba1aaa4fef45e78946f Mon Sep 17 00:00:00 2001 From: John Candlebury Date: Wed, 14 Apr 2021 18:50:17 -0600 Subject: [PATCH 400/453] Add cold resistance gear to escape pod --- data/mods/Aftershock/itemgroups/spaceship_groups.json | 1 + data/mods/Aftershock/items/ethereal.json | 7 ++++--- 2 files changed, 5 insertions(+), 3 deletions(-) diff --git a/data/mods/Aftershock/itemgroups/spaceship_groups.json b/data/mods/Aftershock/itemgroups/spaceship_groups.json index 2e664bacb8d8e..98bd8743490a3 100644 --- a/data/mods/Aftershock/itemgroups/spaceship_groups.json +++ b/data/mods/Aftershock/itemgroups/spaceship_groups.json @@ -12,6 +12,7 @@ { "item": "whistle_multitool" }, { "item": "water_clean", "container-item": "bottle_twoliter", "count": 3 }, { "item": "afs_escapepod_ration", "count": 3 }, + { "item": "cold_res_cream", "count": 3 }, { "item": "light_plus_battery_cell", "charges": 150, "container-item": "flashlight" }, { "item": "light_plus_battery_cell", "charges": 150, "container-item": "water_purifier" }, { "item": "medium_plus_battery_cell", "ammo-item": "battery", "charges": 600, "container-item": "mil_mess_kit" }, diff --git a/data/mods/Aftershock/items/ethereal.json b/data/mods/Aftershock/items/ethereal.json index bdcdd089fdaa1..3ae15d5addf67 100644 --- a/data/mods/Aftershock/items/ethereal.json +++ b/data/mods/Aftershock/items/ethereal.json @@ -8,10 +8,10 @@ "volume": "1ml", "price": 3646, "symbol": "o", + "warmth": 150, "color": "green", "covers": [ "leg_l", "leg_r", "torso", "arm_l", "arm_r", "hand_l", "hand_r", "head", "foot_l", "foot_r", "mouth", "eyes" ], - "flags": [ "AURA", "SEMITANGIBLE", "OVERSIZE", "ONLY_ONE", "TRADER_AVOID", "NO_TAKEOFF", "NONCONDUCTIVE" ], - "relic_data": { "passive_effects": [ { "has": "WORN", "condition": "ALWAYS", "mutations": [ "AFS_CRYOADAPTATION" ] } ] } + "flags": [ "AURA", "SEMITANGIBLE", "OVERSIZE", "ONLY_ONE", "TRADER_AVOID", "NO_TAKEOFF", "CLIMATE_CONTROL", "NONCONDUCTIVE" ] }, { "id": "cold_res_cream_greater", @@ -22,9 +22,10 @@ "volume": "1ml", "price": 3646, "symbol": "o", + "warmth": 150, "color": "green", "covers": [ "leg_l", "leg_r", "torso", "arm_l", "arm_r", "hand_l", "hand_r", "head", "foot_l", "foot_r", "mouth", "eyes" ], - "flags": [ "AURA", "SEMITANGIBLE", "OVERSIZE", "ONLY_ONE", "TRADER_AVOID", "NO_TAKEOFF", "NONCONDUCTIVE" ], + "flags": [ "AURA", "SEMITANGIBLE", "OVERSIZE", "ONLY_ONE", "TRADER_AVOID", "NO_TAKEOFF", "CLIMATE_CONTROL", "NONCONDUCTIVE" ], "relic_data": { "passive_effects": [ { "has": "WORN", "condition": "ALWAYS", "values": [ { "value": "ARMOR_COLD", "multiply": -0.25 } ] } ] } From 4c9870429cc5ae7dc1bf52a90bf37e2bf9a5e378 Mon Sep 17 00:00:00 2001 From: John Bytheway Date: Mon, 19 Apr 2021 10:25:06 -0400 Subject: [PATCH 401/453] Move Mingw CI build to GitHub actions (#48572) * Move Mingw CI build to GitHub actions The Mingw cross-compile on Travis has been consistently exceeding the 50 minute time limit for jobs, and causing all PRs to have failed checks. This is not helpful. Try to recreate an equivalent job on GitHub actions in the general build matrix, and disable the Travis version on PRs (leaving it enabled for master). * Fetch key before adding mxe repo * Convey some variables from requirements to build GitHub doesn't retain environment by default between steps. We need to explicitly save the variables we want transferred from requirements.sh to build.sh. * Install wine for Mingw build Looks like wine was installed by default on Travis, but not GitHub, so we explicitly install it in requirements.sh. * Pre-run wine in requirements.sh I think there might be race conditions associated with launching three wine processes simultaneously. Try to avoid that by running one in advance. --- .github/workflows/matrix.yml | 11 ++++++++++ .travis.yml | 3 ++- build-scripts/requirements.sh | 40 +++++++++++++++++++++++++++++++---- 3 files changed, 49 insertions(+), 5 deletions(-) diff --git a/.github/workflows/matrix.yml b/.github/workflows/matrix.yml index 5510159801530..6be2c78235b75 100644 --- a/.github/workflows/matrix.yml +++ b/.github/workflows/matrix.yml @@ -73,16 +73,27 @@ jobs: tiles: 1 native: osx title: Clang 12, macOS 10.15, Tiles + - compiler: g++ + os: ubuntu-latest + cmake: 0 + tiles: 1 + title: GCC, Ubuntu cross-compile to MinGW-Win64, Tiles + ldflags: -static-libgcc -static-libstdc++ + mxe_target: i686-w64-mingw32.static + wine: wine name: ${{ matrix.title }} runs-on: ${{ matrix.os }} env: CMAKE: ${{ matrix.cmake }} COMPILER: ${{ matrix.compiler }} + MXE_TARGET: ${{ matrix.mxe_target }} + WINE: ${{ matrix.wine }} OS: ${{ matrix.os }} TILES: ${{ matrix.tiles }} SOUND: ${{ matrix.tiles }} SANITIZE: ${{ matrix.sanitize }} TEST_STAGE: ${{ matrix.test-stage }} + LDFLAGS: ${{ matrix.ldflags }} EXTRA_TEST_OPTS: --error-format=github-action NATIVE: ${{ matrix.native }} GOLD: ${{ matrix.gold }} diff --git a/.travis.yml b/.travis.yml index 13e4b8e6293d3..169aab5e5aca3 100644 --- a/.travis.yml +++ b/.travis.yml @@ -99,7 +99,8 @@ jobs: - stage: "Platforms and Tidy" # MXE variant using alternate repository http://mirror.mxe.cc/repos/apt env: COMPILER=g++ LDFLAGS="-static-libgcc -static-libstdc++" MXE_TARGET="i686-w64-mingw32.static" WINE="wine" TILES=1 SOUND=1 - name: "Mingw-w64 Make cross-compile to Windows with Tiles and Sound" + name: "MinGW-Win64 Make cross-compile to Windows with Tiles and Sound" + if: type != pull_request compiler: gcc addons: &gcc apt: diff --git a/build-scripts/requirements.sh b/build-scripts/requirements.sh index bb17283fa3ca9..15fbf384ecbd6 100644 --- a/build-scripts/requirements.sh +++ b/build-scripts/requirements.sh @@ -54,8 +54,9 @@ fi # Influenced by https://github.com/zer0main/battleship/blob/master/build/windows/requirements.sh if [ -n "${MXE_TARGET}" ]; then - sudo add-apt-repository 'deb [arch=amd64] https://mirror.mxe.cc/repos/apt xenial main' - $travis_retry sudo apt-key adv --keyserver keyserver.ubuntu.com --recv-keys 84C7C89FC632241A6999ED0A580873F586B72ED9 + $travis_retry sudo apt-key adv --keyserver keyserver.ubuntu.com --recv-keys 84C7C89FC632241A6999ED0A580873F586B72ED9 + sudo add-apt-repository 'deb [arch=amd64] https://mirror.mxe.cc/repos/apt xenial main' + sudo dpkg --add-architecture i386 # We need to treat apt-get update warnings as errors for which the exit code # is not sufficient. The following workaround inspired by # https://unix.stackexchange.com/questions/175146/apt-get-update-exit-status/ @@ -66,9 +67,18 @@ if [ -n "${MXE_TARGET}" ]; then MXE2_TARGET=$(echo "$MXE_TARGET" | sed 's/_/-/g') export MXE_DIR=/usr/lib/mxe/usr/bin - $travis_retry sudo apt-get --yes install mxe-${MXE2_TARGET}-gcc mxe-${MXE2_TARGET}-gettext mxe-${MXE2_TARGET}-glib mxe-${MXE2_TARGET}-sdl2 mxe-${MXE2_TARGET}-sdl2-ttf mxe-${MXE2_TARGET}-sdl2-image mxe-${MXE2_TARGET}-sdl2-mixer + $travis_retry sudo apt-get --yes install \ + mxe-${MXE2_TARGET}-gcc \ + mxe-${MXE2_TARGET}-gettext \ + mxe-${MXE2_TARGET}-glib \ + mxe-${MXE2_TARGET}-sdl2 \ + mxe-${MXE2_TARGET}-sdl2-ttf \ + mxe-${MXE2_TARGET}-sdl2-image \ + mxe-${MXE2_TARGET}-sdl2-mixer \ + wine \ + wine32 export PLATFORM='i686-w64-mingw32.static' - export CROSS_COMPILATION='${MXE_DIR}/${PLATFORM}-' + export CROSS_COMPILATION="${MXE_DIR}/${PLATFORM}-" # Need to overwrite CXX to make the Makefile $CROSS logic work right. export CXX="$COMPILER" export CCACHE=1 @@ -97,4 +107,26 @@ if [[ "$NATIVE" == "android" ]]; then yes | sdkmanager "ndk-bundle" fi +if [ -n "$WINE" ] +then + # The build script will try to run things under wine in parallel, and I + # think there are race conditions that can cause that to break. So, run + # something benign under wine in advance to trigger it to configure all the + # one-time init stuff + wine hostname +fi + +# On GitHub actions environment variables are not saved between steps by +# default, so we need to explicitly save the ones that we care about +if [ -n "$GITHUB_ENV" ] +then + for v in CROSS_COMPILATION CXX + do + if [ -n "${!v}" ] + then + printf "%s='%s'\n" "$v" "${!v}" >> "$GITHUB_ENV" + fi + done +fi + set +x From b80f3ff44707d4fe5c511e5c3a27e931b7bc41f1 Mon Sep 17 00:00:00 2001 From: Binrui Dong Date: Tue, 20 Apr 2021 02:34:48 -0400 Subject: [PATCH 402/453] Enable ClangBuildAnalyzer on PRs to 0.F-dev (#48586) --- .github/workflows/CBA.yml | 2 ++ 1 file changed, 2 insertions(+) diff --git a/.github/workflows/CBA.yml b/.github/workflows/CBA.yml index a8adfaef29ad9..b9325b39f07c7 100644 --- a/.github/workflows/CBA.yml +++ b/.github/workflows/CBA.yml @@ -4,6 +4,7 @@ on: push: branches: - master + - 0.F-dev paths: - '**.cpp' - '**.h' @@ -16,6 +17,7 @@ on: pull_request: branches: - master + - 0.F-dev paths: - '**.cpp' - '**.h' From a490a1de175de1383182c54e21cde154ead6e3e7 Mon Sep 17 00:00:00 2001 From: John Bytheway Date: Tue, 20 Apr 2021 02:36:09 -0400 Subject: [PATCH 403/453] More robust sunburn tests; better burn feedback. (#48527) * Translator notes on sunburn suffer strings These strings were wrong; they had punctuation that they shouldn't have. Remove that punctuation and add translator note to clarify why it shouldn't have been there in the first place. * Remove redundant escapes These '%' should not have been escaped. Un-escape them. * List all burned bodyparts in message Previously only the most exposed bodypart would be listed in the message regarding sunburn / irritation. Instead, list all parts. * Switch sunburn test to IsBinomialObservation This test relied on some arbitrary constants, so it was difficult to know how reasonable failures were. Switch it to a more statistically well-founded approach. * Make IsBinomialObservation more lenient by default This was calibrated to a false positive rate of one in ten thousand. That's too high for the rate at which we run tests. Default to one in one hundred thousand instead. * Improve translatability of sunburn messaging The "%s your %s" string was surely basically impossible to translate. Incorporate the first part into the string to make that easier, and provide the number of bodyparts for languages where that matters. --- src/suffer.cpp | 88 ++++++++++++++++++++++---------------- tests/char_suffer_test.cpp | 18 +++++--- tests/test_statistics.h | 2 +- 3 files changed, 64 insertions(+), 44 deletions(-) diff --git a/src/suffer.cpp b/src/suffer.cpp index a4bb582b0ca5c..10a7d2b3466ed 100644 --- a/src/suffer.cpp +++ b/src/suffer.cpp @@ -43,6 +43,7 @@ #include "npc.h" #include "optional.h" #include "options.h" +#include "output.h" #include "overmapbuffer.h" #include "pimpl.h" #include "player_activity.h" @@ -806,26 +807,23 @@ void Character::suffer_from_sunburn() return; } - std::string sunlight_effect; if( has_trait( trait_ALBINO ) || has_effect( effect_datura ) ) { // Albinism and datura have the same effects, once per minute on average if( !one_turn_in( 1_minutes ) ) { return; } - sunlight_effect = _( "The sunlight is really irritating." ); } else if( has_trait( trait_SUNBURN ) ) { // Sunburn effects occur about 3 times per minute if( !one_turn_in( 20_seconds ) ) { return; } - sunlight_effect = _( "The sunlight burns!" ); } // Sunglasses can keep the sun off the eyes. if( !has_flag( json_flag_GLARE_RESIST ) && !( wearing_something_on( bodypart_id( "eyes" ) ) && ( worn_with_flag( flag_SUN_GLASSES ) || worn_with_flag( flag_BLIND ) ) ) ) { - add_msg_if_player( m_bad, _( "%s your eyes." ), sunlight_effect ); + add_msg_if_player( m_bad, _( "The sunlight is really irritating your eyes." ) ); // Pain (1/60) or loss of focus (59/60) if( one_turn_in( 1_minutes ) ) { mod_pain( 1 ); @@ -842,12 +840,8 @@ void Character::suffer_from_sunburn() // Minimum exposure threshold for pain const float MIN_EXPOSURE = 0.01f; - // Count how many body parts are above the threshold - int count_affected_bp = 0; - // Get the most exposed body part, and how exposed it is. This is to tell the player what body - // part is most irritated by sun, so they know what needs to be covered up better. - bodypart_id most_exposed_bp; - float max_exposure = 0.0f; + // Track body parts above the threshold + std::vector> affected_bodyparts; // Check each bodypart with exposure above the minimum for( const std::pair &bp_exp : bp_exposure ) { const float exposure = bp_exp.second; @@ -855,40 +849,60 @@ void Character::suffer_from_sunburn() if( exposure <= MIN_EXPOSURE || bp_exp.first == bodypart_id( "eyes" ) ) { continue; } - ++count_affected_bp; - if( exposure > max_exposure ) { - max_exposure = exposure; - most_exposed_bp = bp_exp.first; - } + affected_bodyparts.emplace_back( exposure, bp_exp.first ); } // If all body parts are protected, there is no suffering - if( count_affected_bp == 0 || most_exposed_bp == bodypart_str_id::NULL_ID() ) { + if( affected_bodyparts.empty() ) { return; } - // Check if both arms/legs are affected - int count_limbs = 1; - const bodypart_id &other_bp = most_exposed_bp->opposite_part; - const bodypart_id &other_bp_rev = other_bp->opposite_part; - // If these are different, we have a left/right part like a leg or arm. - // If same, it's a central body part with no opposite, like head or torso. - // Only used to generate a simpler message when both arms or both legs are affected. - if( other_bp != other_bp_rev ) { - const auto found = bp_exposure.find( other_bp ); - // Is opposite part exposed? - if( found != bp_exposure.end() && found->second > MIN_EXPOSURE ) { - ++count_limbs; - } - } - // Get singular or plural body part name; append "and other body parts" if appropriate - std::string bp_name = body_part_name( most_exposed_bp, count_limbs ); - if( count_affected_bp == count_limbs ) { - add_msg_if_player( m_bad, _( "%s your %s." ), sunlight_effect, bp_name ); - } else { - add_msg_if_player( m_bad, _( "%s your %s and other body parts." ), sunlight_effect, - bp_name ); + // Sort most affected bodyparts to the front + std::sort( affected_bodyparts.begin(), affected_bodyparts.end(), std::greater<> {} ); + + std::vector affected_part_names; + std::unordered_set excluded_other_parts; + + for( const std::pair &exp_bp : affected_bodyparts ) { + const bodypart_id &bp = exp_bp.second; + if( excluded_other_parts.count( bp ) ) { + continue; + } + const bodypart_id &opposite_bp = bp->opposite_part; + // If these are different, we have a left/right part like a leg or arm. + // If same, it's a central body part with no opposite, like head or torso. + // Used to generate a simpler message when both arms or both legs are affected. + int count_limbs = 1; + if( bp != opposite_bp ) { + const auto found = bp_exposure.find( opposite_bp ); + // Is opposite part exposed? + if( found != bp_exposure.end() && found->second > MIN_EXPOSURE ) { + ++count_limbs; + excluded_other_parts.insert( opposite_bp ); + } + } + // Get singular or plural body part name; append "and other body parts" if appropriate + std::string bp_name = body_part_name( bp, count_limbs ); + affected_part_names.push_back( bp_name ); + } + + std::string all_parts_list = enumerate_as_string( affected_part_names ); + + std::string message; + if( has_trait( trait_ALBINO ) || has_effect( effect_datura ) ) { + //~ %s is a list of body parts. The plurality integer is the total + //~ number of body parts + message = ngettext( "The sunlight is really irritating your %s.", + "The sunlight is really irritating your %s.", + affected_bodyparts.size() ); + } else if( has_trait( trait_SUNBURN ) ) { + //~ %s is a list of body parts. The plurality integer is the total + //~ number of body parts + message = ngettext( "The sunlight burns your %s.", + "The sunlight burns your %s.", + affected_bodyparts.size() ); } + add_msg_if_player( m_bad, message, all_parts_list ); // Wake up from skin irritation/burning if( has_effect( effect_sleep ) ) { diff --git a/tests/char_suffer_test.cpp b/tests/char_suffer_test.cpp index 1261d45fac566..57bdadb2053e3 100644 --- a/tests/char_suffer_test.cpp +++ b/tests/char_suffer_test.cpp @@ -15,6 +15,7 @@ #include "item.h" #include "map_helpers.h" #include "player_helpers.h" +#include "test_statistics.h" #include "type_id.h" // Tests for Character suffering @@ -273,25 +274,30 @@ TEST_CASE( "suffering from sunburn", "[char][suffer][sunburn]" ) } - WHEN( "torso and arms are 90%% covered" ) { + WHEN( "torso and arms are 90% covered" ) { dummy.worn.clear(); dummy.wear_item( longshirt, false ); - THEN( "damage to torso is 90%% less than other parts" ) { - bp_hp_lost = test_suffer_bodypart_hp_lost( dummy, 10_minutes ); + THEN( "damage to torso is 90% less than other parts" ) { + time_duration t = 10_minutes; + int num_turns = t / 1_turns; + + bp_hp_lost = test_suffer_bodypart_hp_lost( dummy, t ); for( const bodypart_id &bp : body_parts_with_hp ) { CAPTURE( bp.id().str() ); if( bp.id().str() == "torso" ) { // Torso has only 10% chance losing 2 HP, 3x per minute - CHECK( bp_hp_lost[bp] == Approx( 6 ).margin( 12 ) ); + CHECK_THAT( bp_hp_lost[bp] / 2, + IsBinomialObservation( num_turns, 1.0 / 200 ) ); } else if( bp.id().str() == "arm_l" || bp.id().str() == "arm_r" ) { // Arms have 10% chance of losing 1 HP, 3x per minute (6 in 10m) // But hands are exposed, and still lose 1 HP, 3x per minute (30 in 10m) - CHECK( bp_hp_lost[bp] == Approx( 36 ).margin( 30 ) ); + CHECK_THAT( bp_hp_lost[bp], + IsBinomialObservation( num_turns, 1.0 / 200 + 1.0 / 20 ) ); } else { // All other parts lose 1 HP, 3x per minute (30 in 10m) // but legs+feet combine, and head+mouth combine (60 in 10m) - CHECK( bp_hp_lost[bp] == Approx( 60 ).margin( 40 ) ); + CHECK_THAT( bp_hp_lost[bp], IsBinomialObservation( num_turns, 2.0 / 20 ) ); } } } diff --git a/tests/test_statistics.h b/tests/test_statistics.h index 3cbb2fe779643..03d59f0224040 100644 --- a/tests/test_statistics.h +++ b/tests/test_statistics.h @@ -223,7 +223,7 @@ class BinomialMatcher : public Catch::MatcherBase // distribution. Uses a normal approximation to the binomial, and permits a // deviation up to max_deviation (measured in standard deviations). inline BinomialMatcher IsBinomialObservation( - const int num_samples, const double p, const double max_deviation = Z99_99 ) + const int num_samples, const double p, const double max_deviation = Z99_999 ) { return BinomialMatcher( num_samples, p, max_deviation ); } From 7bfbb2f54e3e15a611a75717442d21d7f3d5189f Mon Sep 17 00:00:00 2001 From: John Bytheway Date: Tue, 20 Apr 2021 02:36:36 -0400 Subject: [PATCH 404/453] Enable clang-tidy check bugprone-unused-return-value (#48546) * Fix bugprone-unused-return-value Biggest change here was to mapbuffer, which now stores submaps via unique_ptr rather than raw pointers, simplifying the destructor. Unfortunately, we have to retain the strange pointer-based API for mapbuffer, because the submap ownership logic in map is so convoluted. That can be fixed another day. Also, renamed mapbuffer::reset() to clear(), for consistency. In trait_group, removed a couple of calls to reset() that this warning was highlighting. They didn't do anything anyway. * Enable clang-tidy bugprone-unused-return-value --- .clang-tidy | 1 - src/game.cpp | 8 ++++---- src/main_menu.cpp | 8 ++++---- src/mapbuffer.cpp | 37 ++++++++++++++++--------------------- src/mapbuffer.h | 8 ++++---- src/trait_group.cpp | 2 -- 6 files changed, 28 insertions(+), 36 deletions(-) diff --git a/.clang-tidy b/.clang-tidy index 242dacf57f694..534a499defb7f 100644 --- a/.clang-tidy +++ b/.clang-tidy @@ -23,7 +23,6 @@ performance-*,\ readability-*,\ -bugprone-misplaced-widening-cast,\ -bugprone-narrowing-conversions,\ --bugprone-unused-return-value,\ -cert-flp30-c,\ -misc-non-private-member-variables-in-classes,\ -modernize-avoid-c-arrays,\ diff --git a/src/game.cpp b/src/game.cpp index 54890c3ddc798..c9d9a2abf93ec 100644 --- a/src/game.cpp +++ b/src/game.cpp @@ -415,7 +415,7 @@ bool game::check_mod_data( const std::vector &opts, loading_ui &ui ) std::string world_name = world_generator->active_world->world_name; world_generator->delete_world( world_name, true ); - MAPBUFFER.reset(); + MAPBUFFER.clear(); overmap_buffer.clear(); } @@ -459,7 +459,7 @@ bool game::check_mod_data( const std::vector &opts, loading_ui &ui ) std::string world_name = world_generator->active_world->world_name; world_generator->delete_world( world_name, true ); - MAPBUFFER.reset(); + MAPBUFFER.clear(); overmap_buffer.clear(); } return true; @@ -1284,7 +1284,7 @@ bool game::cleanup_at_end() sfx::fade_audio_group( sfx::group::context_themes, 300 ); sfx::fade_audio_group( sfx::group::fatigue, 300 ); - MAPBUFFER.reset(); + MAPBUFFER.clear(); overmap_buffer.clear(); #if defined(__ANDROID__) @@ -12240,7 +12240,7 @@ void game::quickload() if( active_world->save_exists( save_t::from_player_name( u.name ) ) ) { if( moves_since_last_save != 0 ) { // See if we need to reload anything - MAPBUFFER.reset(); + MAPBUFFER.clear(); overmap_buffer.clear(); try { setup(); diff --git a/src/main_menu.cpp b/src/main_menu.cpp index 2ec0ff896802f..01e583dad960d 100644 --- a/src/main_menu.cpp +++ b/src/main_menu.cpp @@ -882,7 +882,7 @@ bool main_menu::new_character_tab() } if( !player_character.create( play_type ) ) { load_char_templates(); - MAPBUFFER.reset(); + MAPBUFFER.clear(); overmap_buffer.clear(); continue; } @@ -954,7 +954,7 @@ bool main_menu::new_character_tab() } if( !player_character.create( character_type::TEMPLATE, templates[sel3] ) ) { load_char_templates(); - MAPBUFFER.reset(); + MAPBUFFER.clear(); overmap_buffer.clear(); continue; } @@ -1247,7 +1247,7 @@ void main_menu::world_tab() player_character.save_template( player_character.name, points ); player_character = avatar(); - MAPBUFFER.reset(); + MAPBUFFER.clear(); overmap_buffer.clear(); load_char_templates(); @@ -1323,7 +1323,7 @@ void main_menu::world_tab() world_generator->delete_world( all_worldnames[sel2 - 1], do_delete ); savegames.clear(); - MAPBUFFER.reset(); + MAPBUFFER.clear(); overmap_buffer.clear(); if( do_delete ) { diff --git a/src/mapbuffer.cpp b/src/mapbuffer.cpp index 3b212578c3526..19dc38e18fec5 100644 --- a/src/mapbuffer.cpp +++ b/src/mapbuffer.cpp @@ -43,36 +43,32 @@ static std::string find_dirname( const tripoint &om_addr ) mapbuffer MAPBUFFER; mapbuffer::mapbuffer() = default; +mapbuffer::~mapbuffer() = default; -mapbuffer::~mapbuffer() +void mapbuffer::clear() { - reset(); -} - -void mapbuffer::reset() -{ - for( auto &elem : submaps ) { - delete elem.second; - } submaps.clear(); } -bool mapbuffer::add_submap( const tripoint &p, submap *sm ) +bool mapbuffer::add_submap( const tripoint &p, std::unique_ptr &sm ) { - if( submaps.count( p ) != 0 ) { + if( submaps.count( p ) ) { return false; } - submaps[p] = sm; + submaps[p] = std::move( sm ); return true; } -bool mapbuffer::add_submap( const tripoint &p, std::unique_ptr &sm ) +bool mapbuffer::add_submap( const tripoint &p, submap *sm ) { - const bool result = add_submap( p, sm.get() ); - if( result ) { - sm.release(); + // FIXME: get rid of this overload and make submap ownership semantics sane. + std::unique_ptr temp( sm ); + bool result = add_submap( p, temp ); + if( !result ) { + // NOLINTNEXTLINE( bugprone-unused-return-value ) + temp.release(); } return result; } @@ -84,7 +80,6 @@ void mapbuffer::remove_submap( tripoint addr ) debugmsg( "Tried to remove non-existing submap %d,%d,%d", addr.x, addr.y, addr.z ); return; } - delete m_target->second; submaps.erase( m_target ); } @@ -102,7 +97,7 @@ submap *mapbuffer::lookup_submap( const tripoint &p ) return nullptr; } - return iter->second; + return iter->second.get(); } void mapbuffer::save( bool delete_after_save ) @@ -182,7 +177,7 @@ void mapbuffer::save_quad( const std::string &dirname, const std::string &filena submap_addr.x += offsets_offset.x; submap_addr.y += offsets_offset.y; submap_addrs.push_back( submap_addr ); - submap *sm = submaps[submap_addr]; + submap *sm = submaps[submap_addr].get(); if( sm != nullptr && !sm->is_uniform ) { all_uniform = false; } @@ -211,7 +206,7 @@ void mapbuffer::save_quad( const std::string &dirname, const std::string &filena continue; } - submap *sm = submaps[submap_addr]; + submap *sm = submaps[submap_addr].get(); if( sm == nullptr ) { continue; @@ -272,7 +267,7 @@ submap *mapbuffer::unserialize_submaps( const tripoint &p ) quad_path, p.x, p.y, p.z ); return nullptr; } - return submaps[ p ]; + return submaps[ p ].get(); } void mapbuffer::deserialize( JsonIn &jsin ) diff --git a/src/mapbuffer.h b/src/mapbuffer.h index c90bb587f681e..f2cd10cdbcdbf 100644 --- a/src/mapbuffer.h +++ b/src/mapbuffer.h @@ -28,7 +28,7 @@ class mapbuffer void save( bool delete_after_save = false ); /** Delete all buffered submaps. **/ - void reset(); + void clear(); /** Add a new submap to the buffer. * @@ -38,10 +38,10 @@ class mapbuffer * is released (set to NULL). * @return true if the submap has been stored here. False if there * is already a submap with the specified coordinates. The submap - * is not stored than and the caller must take of the submap object - * on their own (and properly delete it). + * is not stored and the given unique_ptr retains ownsership. */ bool add_submap( const tripoint &p, std::unique_ptr &sm ); + // Old overload that we should stop using, but it's complicated bool add_submap( const tripoint &p, submap *sm ); /** Get a submap stored in this buffer. @@ -55,7 +55,7 @@ class mapbuffer submap *lookup_submap( const tripoint &p ); private: - using submap_map_t = std::map; + using submap_map_t = std::map>; public: inline submap_map_t::iterator begin() { diff --git a/src/trait_group.cpp b/src/trait_group.cpp index 4100a4f21e7f4..386914d0b6616 100644 --- a/src/trait_group.cpp +++ b/src/trait_group.cpp @@ -276,7 +276,6 @@ void Trait_group_collection::add_entry( std::unique_ptr ptr ptr->probability = std::min( 100, ptr->probability ); creators.push_back( std::move( ptr ) ); - ptr.release(); } void Trait_group_distribution::add_entry( std::unique_ptr ptr ) @@ -289,7 +288,6 @@ void Trait_group_distribution::add_entry( std::unique_ptr p sum_prob += ptr->probability; creators.push_back( std::move( ptr ) ); - ptr.release(); } Trait_list Trait_group_distribution::create( RecursionList &rec ) const From 18dff1eea738e85cd76b301e6b349ab471b467a0 Mon Sep 17 00:00:00 2001 From: LyleSY Date: Tue, 20 Apr 2021 03:06:02 -0400 Subject: [PATCH 405/453] [DinoMod] Dinosaur Jr. bugfix (#48585) --- data/mods/DinoMod/monsters/juvenile.json | 12 ++++++------ 1 file changed, 6 insertions(+), 6 deletions(-) diff --git a/data/mods/DinoMod/monsters/juvenile.json b/data/mods/DinoMod/monsters/juvenile.json index 326cc24fb279c..0dc549715a0e6 100644 --- a/data/mods/DinoMod/monsters/juvenile.json +++ b/data/mods/DinoMod/monsters/juvenile.json @@ -186,7 +186,7 @@ "id": "mon_apatosaurus_juvenile", "type": "MONSTER", "name": "brown and magenta four-legged juvenile", - "description": "A small four-legged plant-eating dinosaur juvenile with huge shiny eyes, it could be from a number of different species.", + "description": "A huge four-legged plant-eating juvenile sauropod with a long neck and tail, it could be from a number of different species.", "copy-from": "mon_gallimimus_juvenile", "default_faction": "herbivore_dino", "color": "brown_magenta", @@ -214,7 +214,7 @@ "id": "mon_brontosaurus_juvenile", "type": "MONSTER", "name": "brown and magenta four-legged juvenile", - "description": "A small four-legged plant-eating dinosaur juvenile with huge shiny eyes, it could be from a number of different species.", + "description": "A huge four-legged plant-eating juvenile sauropod with a long neck and tail, it could be from a number of different species.", "copy-from": "mon_gallimimus_juvenile", "default_faction": "herbivore_dino", "color": "brown_magenta", @@ -242,7 +242,7 @@ "id": "mon_diplodocus_juvenile", "type": "MONSTER", "name": "brown and magenta four-legged juvenile", - "description": "A small four-legged plant-eating dinosaur juvenile with huge shiny eyes, it could be from a number of different species.", + "description": "A huge four-legged plant-eating juvenile sauropod with a long neck and tail, it could be from a number of different species.", "copy-from": "mon_gallimimus_juvenile", "default_faction": "herbivore_dino", "color": "brown_magenta", @@ -270,7 +270,7 @@ "id": "mon_camarasaurus_juvenile", "type": "MONSTER", "name": "brown and magenta four-legged juvenile", - "description": "A small four-legged plant-eating dinosaur juvenile with huge shiny eyes, it could be from a number of different species.", + "description": "A huge four-legged plant-eating juvenile sauropod with a long neck and tail, it could be from a number of different species.", "copy-from": "mon_gallimimus_juvenile", "default_faction": "herbivore_dino", "color": "brown_magenta", @@ -298,7 +298,7 @@ "id": "mon_brachiosaurus_juvenile", "type": "MONSTER", "name": "brown and magenta four-legged juvenile", - "description": "A small four-legged plant-eating dinosaur juvenile with huge shiny eyes, it could be from a number of different species.", + "description": "A huge four-legged plant-eating juvenile sauropod with a long neck and tail, it could be from a number of different species.", "copy-from": "mon_gallimimus_juvenile", "default_faction": "herbivore_dino", "color": "brown_magenta", @@ -326,7 +326,7 @@ "id": "mon_alamosaurus_juvenile", "type": "MONSTER", "name": "brown and magenta four-legged juvenile", - "description": "A small four-legged plant-eating dinosaur juvenile with huge shiny eyes, it could be from a number of different species.", + "description": "A huge four-legged plant-eating juvenile sauropod with a long neck and tail, it could be from a number of different species.", "copy-from": "mon_gallimimus_juvenile", "default_faction": "herbivore_dino", "color": "brown_magenta", From 5e45cc23dec4d3fa0a339a64619f2bce05a85ffc Mon Sep 17 00:00:00 2001 From: Maleclypse <54345792+Maleclypse@users.noreply.github.com> Date: Tue, 20 Apr 2021 02:23:32 -0500 Subject: [PATCH 406/453] CRT filenames, fixes and Lore Background (#48506) --- .../advanced_gear.json} | 0 data/mods/CRT_EXPANSION/monsters/crt_monster.json | 14 +++++++------- .../CRT_EXPANSION/monsters/crt_monstergroups.json | 2 +- data/mods/CRT_EXPANSION/readme/README.md | 4 ++-- 4 files changed, 10 insertions(+), 10 deletions(-) rename data/mods/CRT_EXPANSION/{deadspace/deadspaceitems.json => crt_gear/advanced_gear.json} (100%) diff --git a/data/mods/CRT_EXPANSION/deadspace/deadspaceitems.json b/data/mods/CRT_EXPANSION/crt_gear/advanced_gear.json similarity index 100% rename from data/mods/CRT_EXPANSION/deadspace/deadspaceitems.json rename to data/mods/CRT_EXPANSION/crt_gear/advanced_gear.json diff --git a/data/mods/CRT_EXPANSION/monsters/crt_monster.json b/data/mods/CRT_EXPANSION/monsters/crt_monster.json index 0f78397d0cda6..8717d5a9c1754 100644 --- a/data/mods/CRT_EXPANSION/monsters/crt_monster.json +++ b/data/mods/CRT_EXPANSION/monsters/crt_monster.json @@ -2,7 +2,7 @@ { "id": "mon_slasher", "type": "MONSTER", - "name": "Slasher Necromorph", + "name": "Slasher Bio-Recombinant", "description": "A horrifically twisted human body. Two massive, bladed appendages have burst through its shoulders where they are poised above its head as it stalks about with terrifying purpose.", "default_faction": "zombie", "categories": [ "CLASSIC" ], @@ -48,7 +48,7 @@ { "id": "mon_slasher_weak", "type": "MONSTER", - "name": "Weak Slasher Necromorph", + "name": "Weak Slasher Bio-Recombinant", "description": "A horrifically mutilated human body. Two scrawny blades have freshly bursted through its hand to deal with prey and the haunting visage of a jawless maw and a gaping wound in its forehead sends chills down your spine. The awkward steps it takes slows it down greatly.", "default_faction": "zombie", "categories": [ "CLASSIC" ], @@ -94,7 +94,7 @@ { "id": "mon_waster", "type": "MONSTER", - "name": "Waster Necromorph", + "name": "Waster Bio-Recombinant", "description": "Clad in heavy assault gear, an eerie light green glows beneath its helmet from sunken eye sockets and a gaping mouth. Strange blade like points have burst out of it's forearms making it a formidable force to be reckoned with.", "default_faction": "zombie", "species": [ "ZOMBIE", "HUMAN" ], @@ -128,7 +128,7 @@ { "id": "mon_leaper", "type": "MONSTER", - "name": "Leaper Necromorph", + "name": "Leaper Bio-Recombinant", "description": "This once-human body is barely recognizable, scrambling about on its abdomen as it leaps forward with immense arm strength. With elongated fangs that can easily mutilate your flesh, the grotesque face roars incessantly. The lower body has fused together into one giant tail with a barbed spike.", "default_faction": "zombie", "species": [ "ZOMBIE", "HUMAN" ], @@ -169,7 +169,7 @@ { "id": "mon_twitcher", "type": "MONSTER", - "name": "Twitcher Necromorph", + "name": "Twitcher Bio-Recombinant", "description": "With narrow blades coming out of its hands, this corpse spasmically dashes to-and-fro with surprising speed. It carries itself quite steadily when idle, further observation shows that the person before this husk was a C.R.I.T S-I G.E.A.R operator.", "default_faction": "zombie", "species": [ "ZOMBIE", "HUMAN" ], @@ -218,7 +218,7 @@ { "id": "mon_pack", "type": "MONSTER", - "name": "Pack Necromorph", + "name": "Pack Bio-Recombinant", "description": "A shrieking mutated child zombie. The face is is mainly blank with eyes swollen shut and a torn-open mouth with flaps of flesh hanging to the side. A pair of seemingly purposeless appendages sprout from its shoulders before ending in its arms. Its small hands end in sharp claws.", "default_faction": "zombie", "species": [ "ZOMBIE" ], @@ -253,7 +253,7 @@ { "id": "mon_puker", "type": "MONSTER", - "name": "Puker Necromorph", + "name": "Puker Bio-Recombinant", "description": "A rather mutilated corpse covered in gaping sores. Hanging arms with hands that have long corroded away reveal jagged edges that could easily pierce into your flesh. A sticky, frothing yellow sludge flows from its exposed internal organs to its unhinged jaw where it drips, hissing as it eats through material.", "default_faction": "zombie", "species": [ "ZOMBIE", "HUMAN" ], diff --git a/data/mods/CRT_EXPANSION/monsters/crt_monstergroups.json b/data/mods/CRT_EXPANSION/monsters/crt_monstergroups.json index 8686d5986acf5..43b96f6ac0fe5 100644 --- a/data/mods/CRT_EXPANSION/monsters/crt_monstergroups.json +++ b/data/mods/CRT_EXPANSION/monsters/crt_monstergroups.json @@ -1,7 +1,7 @@ [ { "type": "monstergroup", - "name": "GROUP_NECROMORPH", + "name": "GROUP_BIORECOMBINANT", "default": "mon_slasher_weak", "monsters": [ { "monster": "mon_slasher_weak", "freq": 300, "cost_multiplier": 0, "pack_size": [ 2, 4 ] }, diff --git a/data/mods/CRT_EXPANSION/readme/README.md b/data/mods/CRT_EXPANSION/readme/README.md index 16d67176f6697..c21f0c3b2b4f7 100644 --- a/data/mods/CRT_EXPANSION/readme/README.md +++ b/data/mods/CRT_EXPANSION/readme/README.md @@ -24,7 +24,7 @@ More techniques, more play styles. Tries to open up melee and offer more than "d I tried to keep the damage balanced and also added scaling damage and movecosts to make it so certain attacks or weapons carry different risks. -# Dead Space -Yeah, the suit is the R.I.G and many other things come from these games. Awesome series! Some Necromorphs will spawn in labs as well, so beware. +# Lore +The logic behind the C.R.T Expansion is that in this version of the Cataclysm is that there was a much longer build up of the dead rising and random portals appearing before the final Cataclysmic Portal Storm erupted. Governments used this time to create special response forces similar to the Fringe universe. Despite the extra time that the world had to prepare, the Cataclysm still mostly went off as basic DDA. Eventually there will be more special locations showing off some of these preparations and the failures they experienced. Anyways, have fun and report any bugs you find. From 93cba035b4bb4207da497060a716fbe092ed21ce Mon Sep 17 00:00:00 2001 From: Maleclypse <54345792+Maleclypse@users.noreply.github.com> Date: Tue, 20 Apr 2021 02:36:47 -0500 Subject: [PATCH 407/453] [Aftershock] Greeting Card snippets (#48209) --- .../Aftershock/itemgroups/item_groups.json | 5 +++ data/mods/Aftershock/items/lore_items.json | 17 ++++++++++ .../Aftershock/snippets/personal_cards.json | 32 +++++++++++++++++++ .../Aftershock/{ => snippets}/snippets.json | 0 4 files changed, 54 insertions(+) create mode 100644 data/mods/Aftershock/items/lore_items.json create mode 100644 data/mods/Aftershock/snippets/personal_cards.json rename data/mods/Aftershock/{ => snippets}/snippets.json (100%) diff --git a/data/mods/Aftershock/itemgroups/item_groups.json b/data/mods/Aftershock/itemgroups/item_groups.json index ee3f72098ce77..2fb7809900440 100644 --- a/data/mods/Aftershock/itemgroups/item_groups.json +++ b/data/mods/Aftershock/itemgroups/item_groups.json @@ -77,6 +77,11 @@ "type": "item_group", "items": [ [ "afs_atompot", 3 ] ] }, + { + "id": "newspaper", + "type": "item_group", + "items": [ [ "afs_personal_card", 2 ] ] + }, { "id": "livingroom", "type": "item_group", diff --git a/data/mods/Aftershock/items/lore_items.json b/data/mods/Aftershock/items/lore_items.json new file mode 100644 index 0000000000000..3f7869e9aa7a6 --- /dev/null +++ b/data/mods/Aftershock/items/lore_items.json @@ -0,0 +1,17 @@ +[ + { + "type": "GENERIC", + "id": "afs_personal_card", + "category": "books", + "symbol": ",", + "color": "red", + "name": { "str": "personal message card" }, + "snippet_category": "afs_personal_card", + "description": "A creased card with images and a personal message.", + "price": 0, + "price_postapoc": 0, + "material": [ "paper" ], + "weight": "3 g", + "volume": "5 ml" + } +] diff --git a/data/mods/Aftershock/snippets/personal_cards.json b/data/mods/Aftershock/snippets/personal_cards.json new file mode 100644 index 0000000000000..a3a0b6390a7a3 --- /dev/null +++ b/data/mods/Aftershock/snippets/personal_cards.json @@ -0,0 +1,32 @@ +[ + { + "type": "snippet", + "category": "afs_personal_card", + "text": [ + { + "id": "afs_card_1", + "text": "There is a picture of a shuttle taking off with happy people waving from the viewports. \"Salus is cold.\n\n Our love is true\n\n I hope to see you\n\n On Croatan 2\n\n My dearest, please join me. I don't believe there are many shuttles left before people will be stuck here forever.\"" + }, + { + "id": "afs_card_2", + "text": "A person wrapped up in bandages in a hospital bed is pictured on the front of this card. \"Get well soon!!!\n\n Torrance, I'm sorry you feel ill but many new colonists forget to process any foodstuffs from Salus IV to remove the macronutrient.\"" + }, + { + "id": "afs_card_3", + "text": "A picture of a bloody steak. This card appears particularly old. \"Gauchos Steaks. Deliveries made monthly from Brazil to Salus IV. Sign up today!\"" + }, + { + "id": "afs_card_4", + "text": "A glossy image of flowers and funeral statuary. \"I'm sorry for your loss. Ebby was an excellent grandparent and we hate for you that he was infected with the Moxphoria and wandered into the wastes.\"" + }, + { + "id": "afs_card_5", + "text": "An orbital view of Salus IV. \"Happy Colonization Day!\n\n Leonid,\n\n This place is cold as Hell but we've made a life out here in the last ten years.\"" + }, + { + "id": "afs_card_6", + "text": "An old style movie theater. \"Showing the vintage film Aelita!\n\n Tovarishch,\n\n Come with me to the movies. My grandfather says that this movie is one of the classics.\"" + } + ] + } +] diff --git a/data/mods/Aftershock/snippets.json b/data/mods/Aftershock/snippets/snippets.json similarity index 100% rename from data/mods/Aftershock/snippets.json rename to data/mods/Aftershock/snippets/snippets.json From d7eeb81d49f64bb0d7b46a3e0a647475c41064e9 Mon Sep 17 00:00:00 2001 From: Eric <52087122+Ramza13@users.noreply.github.com> Date: Tue, 20 Apr 2021 03:39:35 -0400 Subject: [PATCH 408/453] Unhardcode bio recycler, add hunger enchantment (#47637) --- data/json/bionics.json | 12 +++++++++++- doc/MAGIC.md | 1 + src/character.cpp | 10 +--------- src/magic_enchantment.cpp | 1 + src/magic_enchantment.h | 1 + 5 files changed, 15 insertions(+), 10 deletions(-) diff --git a/data/json/bionics.json b/data/json/bionics.json index bfd725cf142fb..085ac4fc83069 100644 --- a/data/json/bionics.json +++ b/data/json/bionics.json @@ -1191,7 +1191,17 @@ "name": { "str": "Recycler Unit" }, "description": "Your digestive system has been outfitted with a series of filters and processors, allowing you to reclaim waste liquid and, to a lesser degree, nutrients. The net effect is a greatly reduced need to eat and drink.", "occupied_bodyparts": [ [ "torso", 15 ] ], - "flags": [ "BIONIC_NPC_USABLE" ] + "flags": [ "BIONIC_NPC_USABLE" ], + "enchantments": [ + { + "condition": "ALWAYS", + "values": [ + { "value": "HUNGER", "multiply": -0.5 }, + { "value": "THIRST", "multiply": -0.5 }, + { "value": "METABOLISM", "multiply": -0.5 } + ] + } + ] }, { "id": "bio_remote", diff --git a/doc/MAGIC.md b/doc/MAGIC.md index adb40c129e92e..d444fd769b22a 100644 --- a/doc/MAGIC.md +++ b/doc/MAGIC.md @@ -477,6 +477,7 @@ Effects for the character that has the enchantment: * REGEN_STAMINA * MAX_HP * REGEN_HP +* HUNGER * THIRST * FATIGUE * PAIN diff --git a/src/character.cpp b/src/character.cpp index 069edd8dcdf43..0b82505d8d84f 100644 --- a/src/character.cpp +++ b/src/character.cpp @@ -284,7 +284,6 @@ static const bionic_id bio_jointservo( "bio_jointservo" ); static const bionic_id bio_leukocyte( "bio_leukocyte" ); static const bionic_id bio_memory( "bio_memory" ); static const bionic_id bio_railgun( "bio_railgun" ); -static const bionic_id bio_recycler( "bio_recycler" ); static const bionic_id bio_shock_absorber( "bio_shock_absorber" ); static const bionic_id bio_tattoo_led( "bio_tattoo_led" ); static const bionic_id bio_ups( "bio_ups" ); @@ -5981,7 +5980,6 @@ void Character::update_needs( int rate_multiplier ) needs_rates Character::calc_needs_rates() const { const effect &sleep = get_effect( effect_sleep ); - const bool has_recycler = has_bionic( bio_recycler ); const bool asleep = !sleep.is_null(); needs_rates rates; @@ -6004,13 +6002,6 @@ needs_rates Character::calc_needs_rates() const static const std::string fatigue_modifier( "fatigue_modifier" ); rates.fatigue *= 1.0f + mutation_value( fatigue_modifier ); - // Note: intentionally not in metabolic rate - if( has_recycler ) { - // Recycler won't help much with mutant metabolism - it is intended for human one - rates.hunger = std::min( rates.hunger, std::max( 0.5f, rates.hunger - 0.5f ) ); - rates.thirst = std::min( rates.thirst, std::max( 0.5f, rates.thirst - 0.5f ) ); - } - if( asleep ) { static const std::string fatigue_regen_modifier( "fatigue_regen_modifier" ); rates.recovery = 1.0f + mutation_value( fatigue_regen_modifier ); @@ -6055,6 +6046,7 @@ needs_rates Character::calc_needs_rates() const rates.thirst *= 0.25f; } + rates.hunger = enchantment_cache->modify_value( enchant_vals::mod::HUNGER, rates.hunger ); rates.fatigue = enchantment_cache->modify_value( enchant_vals::mod::FATIGUE, rates.fatigue ); rates.thirst = enchantment_cache->modify_value( enchant_vals::mod::THIRST, rates.thirst ); diff --git a/src/magic_enchantment.cpp b/src/magic_enchantment.cpp index 390b78594862e..9d03db6ce1472 100644 --- a/src/magic_enchantment.cpp +++ b/src/magic_enchantment.cpp @@ -67,6 +67,7 @@ namespace io case enchant_vals::mod::REGEN_STAMINA: return "REGEN_STAMINA"; case enchant_vals::mod::MAX_HP: return "MAX_HP"; case enchant_vals::mod::REGEN_HP: return "REGEN_HP"; + case enchant_vals::mod::HUNGER: return "HUNGER"; case enchant_vals::mod::THIRST: return "THIRST"; case enchant_vals::mod::FATIGUE: return "FATIGUE"; case enchant_vals::mod::PAIN: return "PAIN"; diff --git a/src/magic_enchantment.h b/src/magic_enchantment.h index de76442562094..8eb15161b5555 100644 --- a/src/magic_enchantment.h +++ b/src/magic_enchantment.h @@ -43,6 +43,7 @@ enum class mod : int { REGEN_STAMINA, MAX_HP, // for all limbs! use with caution REGEN_HP, + HUNGER, // hunger rate THIRST, // thirst rate FATIGUE, // fatigue rate PAIN, // cost or regen over time From edd16a7d07bfd99f9d43947976b620e4fdae9461 Mon Sep 17 00:00:00 2001 From: John Bytheway Date: Sat, 17 Apr 2021 11:55:07 -0400 Subject: [PATCH 409/453] Improve UnsequencedCallsCheck Previously this check triggered false warnings on expressions in different elements of an initializer list expression. Prevent that, and add some test cases. --- tools/clang-tidy-plugin/UnsequencedCallsCheck.cpp | 3 +++ tools/clang-tidy-plugin/test/unsequenced-calls.cpp | 14 ++++++++++++++ 2 files changed, 17 insertions(+) diff --git a/tools/clang-tidy-plugin/UnsequencedCallsCheck.cpp b/tools/clang-tidy-plugin/UnsequencedCallsCheck.cpp index 5c20feb2afe1e..2182b38aa73a8 100644 --- a/tools/clang-tidy-plugin/UnsequencedCallsCheck.cpp +++ b/tools/clang-tidy-plugin/UnsequencedCallsCheck.cpp @@ -47,6 +47,9 @@ static const Expr *GetContainingSequenceStatement( ASTContext *Context, const Ex if( parent.get() ) { return Node; } + if( parent.get() ) { + return Node; + } if( const BinaryOperator *op = parent.get() ) { if( op->isLogicalOp() ) { return Node; diff --git a/tools/clang-tidy-plugin/test/unsequenced-calls.cpp b/tools/clang-tidy-plugin/test/unsequenced-calls.cpp index 4da9839a0b289..58e8f6478bccb 100644 --- a/tools/clang-tidy-plugin/test/unsequenced-calls.cpp +++ b/tools/clang-tidy-plugin/test/unsequenced-calls.cpp @@ -53,3 +53,17 @@ void f1() B b1{ a.nonconst_mf(), a.nonconst_mf() }; B b2 = { a.nonconst_mf(), a.nonconst_mf() }; } + +struct B2 { + int a; + int b; +}; + +void f2() +{ + A a; + // Aggregate initialization is also OK. + B2 b1{ a.nonconst_mf(), a.nonconst_mf() }; + B2 b2 = { a.nonconst_mf(), a.nonconst_mf() }; + B2{ a.nonconst_mf(), a.nonconst_mf() }; +} From 981048a3715641c098868ad0cbceb3e3989744ac Mon Sep 17 00:00:00 2001 From: John Bytheway Date: Sun, 18 Apr 2021 07:06:36 -0400 Subject: [PATCH 410/453] Fix inefficient string concatenations Fix all the warnings triggered by the clang-tidy check performance-inefficient-string-concatenation. This highlights two things: concatenation of a bunch of strings using operator+, and appending to a string using 'a = a + b' rather than 'a += b'. In both cases it only highlights the issue in a loop. Some of these cases were pretty benign, some looked more serious. Even the more serious cases were not, as far as I could tell, in performance-critical code, but some were probably changing O(n) loops into O(n^2) loops, so they are good to fix. To help remediate these issues, added two new helped functions: str_cat and str_append, inspired by Abseil's StrCat and StrAppend. --- src/basecamp.cpp | 2 +- src/cata_tiles.cpp | 9 +++-- src/cata_utility.h | 30 ++++++++++++++ src/chkjson/chkjson.cpp | 5 ++- src/debug.cpp | 3 +- src/faction_camp.cpp | 20 +++++----- src/game.cpp | 4 +- src/help.cpp | 10 +++-- src/item.cpp | 6 ++- src/iuse.cpp | 14 ++++--- src/mapgen.cpp | 9 +++-- src/mission_companion.cpp | 42 ++++++++++---------- src/mod_manager.cpp | 3 +- src/newcharacter.cpp | 2 +- src/npctrade.cpp | 2 +- src/options.cpp | 3 +- src/veh_interact.cpp | 10 ++--- src/worldfactory.cpp | 7 ++-- tests/string_test.cpp | 23 +++++++++++ tools/clang-tidy-plugin/HeaderGuardCheck.cpp | 9 +++-- tools/clang-tidy-plugin/Utils.h | 10 +++++ 21 files changed, 152 insertions(+), 71 deletions(-) diff --git a/src/basecamp.cpp b/src/basecamp.cpp index f727c4f0d8a8c..11fe7a3f52e8e 100644 --- a/src/basecamp.cpp +++ b/src/basecamp.cpp @@ -219,7 +219,7 @@ std::string basecamp::om_upgrade_description( const std::string &bldg, bool trun std::string comp; for( auto &elem : component_print_buffer ) { - comp = comp + elem + "\n"; + str_append( comp, elem, "\n" ); } comp = string_format( _( "Notes:\n%s\n\nSkills used: %s\n%s\n" ), making.description, making.required_all_skills_string(), comp ); diff --git a/src/cata_tiles.cpp b/src/cata_tiles.cpp index e276392fe44aa..1355bec28a05d 100644 --- a/src/cata_tiles.cpp +++ b/src/cata_tiles.cpp @@ -926,7 +926,7 @@ void tileset_loader::load_tilejson_from_file( const JsonObject &config ) // fetch additional tiles for( const JsonObject subentry : entry.get_array( "additional_tiles" ) ) { const std::string s_id = subentry.get_string( "id" ); - const std::string m_id = t_id + "_" + s_id; + const std::string m_id = str_cat( t_id, "_", s_id ); tile_type &curr_subtile = load_tile( subentry, m_id ); curr_subtile.offset = sprite_offset; curr_subtile.rotates = true; @@ -1679,12 +1679,15 @@ bool cata_tiles::find_overlay_looks_like( const bool male, const std::string &ov } for( int cnt = 0; cnt < 10 && !looks_like.empty(); cnt++ ) { - draw_id = ( male ? "overlay_male_" : "overlay_female_" ) + over_type + looks_like; + draw_id.clear(); + str_append( draw_id, + ( male ? "overlay_male_" : "overlay_female_" ), over_type, looks_like ); if( tileset_ptr->find_tile_type( draw_id ) ) { exists = true; break; } - draw_id = "overlay_" + over_type + looks_like; + draw_id.clear(); + str_append( draw_id, "overlay_", over_type, looks_like ); if( tileset_ptr->find_tile_type( draw_id ) ) { exists = true; break; diff --git a/src/cata_utility.h b/src/cata_utility.h index 7ca37e414ded5..490967d3f71a6 100644 --- a/src/cata_utility.h +++ b/src/cata_utility.h @@ -442,6 +442,36 @@ bool return_true( const T & ) */ std::string join( const std::vector &strings, const std::string &joiner ); +/** + * Append all arguments after the first to the first. + * + * This provides a way to append several strings to a single root string + * in a single line without an expression like 'a += b + c' which can cause an + * unnecessary allocation in the 'b + c' expression. + */ +template +std::string &str_append( std::string &root, T &&...a ) +{ + // Using initializer list as a poor man's fold expression until C++17. + static_cast( + std::array { { + ( root.append( std::forward( a ) ), false )... + } + } ); + return root; +} + +/** + * Concatenates a bunch of strings with append, to minimze unnecessary + * allocations + */ +template +std::string str_cat( T0 &&a0, T &&...a ) +{ + std::string result( std::forward( a0 ) ); + return str_append( result, std::forward( a )... ); +} + /** * Erases elements from a set that match given predicate function. * Will work on vector, albeit not optimally performance-wise. diff --git a/src/chkjson/chkjson.cpp b/src/chkjson/chkjson.cpp index 07b24e7a5fb3b..278be0c4521f5 100644 --- a/src/chkjson/chkjson.cpp +++ b/src/chkjson/chkjson.cpp @@ -38,6 +38,7 @@ static std::vector get_files_from_path( std::string extension, std: while( !directories.empty() ) { path = directories.top(); + std::string path_with_slash = path + "/"; directories.pop(); DIR *root = opendir( path.c_str() ); @@ -52,7 +53,7 @@ static std::vector get_files_from_path( std::string extension, std: if( stat( root_file->d_name, &_buff ) != 0x4 ) { // ignore '.' and '..' folder names, which are current and parent folder relative paths if( ( strcmp( root_file->d_name, "." ) != 0 ) && ( strcmp( root_file->d_name, ".." ) != 0 ) ) { - std::string subpath = path + "/" + root_file->d_name; + std::string subpath = path_with_slash + root_file->d_name; if( recursive_search ) { subdir = opendir( subpath.c_str() ); @@ -66,7 +67,7 @@ static std::vector get_files_from_path( std::string extension, std: // check to see if it is a file with the appropriate extension std::string tmp = root_file->d_name; if( tmp.find( c_extension, match_extension ? tmp.size() - extsz : 0 ) != std::string::npos ) { - std::string fullpath = path + "/" + tmp; + std::string fullpath = path_with_slash + tmp; files.push_back( fullpath ); } } diff --git a/src/debug.cpp b/src/debug.cpp index 4243f727b281e..8fa5335dd5434 100644 --- a/src/debug.cpp +++ b/src/debug.cpp @@ -684,11 +684,12 @@ static std::string debug_resolve_binary( const std::string &binary, std::ostream return binary; } + std::string suffix = "/" + binary; for( const std::string &path_elem : string_split( path, ':' ) ) { if( path_elem.empty() ) { continue; } - std::string candidate = path_elem + "/" + binary; + std::string candidate = path_elem + suffix; if( 0 == access( candidate.c_str(), X_OK ) ) { return candidate; } diff --git a/src/faction_camp.cpp b/src/faction_camp.cpp index 99f2d76bab7cf..30593e04732d9 100644 --- a/src/faction_camp.cpp +++ b/src/faction_camp.cpp @@ -477,16 +477,16 @@ static bool update_time_left( std::string &entry, const comp_list &npc_list ) Character &player_character = get_player_character(); for( const auto &comp : npc_list ) { if( comp->companion_mission_time_ret < calendar::turn ) { - entry = entry + _( " [DONE]\n" ); + entry += _( " [DONE]\n" ); avail = true; } else { - entry = entry + " [" + - to_string( comp->companion_mission_time_ret - calendar::turn ) + - _( " left]\n" ); + entry += " [" + + to_string( comp->companion_mission_time_ret - calendar::turn ) + + _( " left]\n" ); avail = player_character.has_trait( trait_DEBUG_HS ); } } - entry = entry + _( "\n\nDo you wish to bring your allies back into your party?" ); + entry += _( "\n\nDo you wish to bring your allies back into your party?" ); return avail; } @@ -496,11 +496,11 @@ static bool update_time_fixed( std::string &entry, const comp_list &npc_list, bool avail = false; for( const auto &comp : npc_list ) { time_duration elapsed = calendar::turn - comp->companion_mission_time; - entry = entry + " " + comp->name + " [" + to_string( elapsed ) + "/" + - to_string( duration ) + "]\n"; + entry += " " + comp->name + " [" + to_string( elapsed ) + "/" + + to_string( duration ) + "]\n"; avail |= elapsed >= duration; } - entry = entry + _( "\n\nDo you wish to bring your allies back into your party?" ); + entry += _( "\n\nDo you wish to bring your allies back into your party?" ); return avail; } @@ -3596,7 +3596,7 @@ std::string basecamp::craft_description( const recipe_id &itm ) std::string comp; for( auto &elem : component_print_buffer ) { - comp = comp + elem + "\n"; + str_append( comp, elem, "\n" ); } comp = string_format( _( "Skill used: %s\nDifficulty: %d\n%s\nTime: %s\n" ), making.skill_used.obj().name(), making.difficulty, comp, @@ -3706,7 +3706,7 @@ std::string basecamp::gathering_description( const std::string &bldg ) itemnames2.insert( std::pair( e.second, e.first ) ); } for( const auto &e : itemnames2 ) { - output = output + "> " + e.second + "\n"; + str_append( output, "> ", e.second, "\n" ); } return output; } diff --git a/src/game.cpp b/src/game.cpp index c9d9a2abf93ec..fa30668c1bb5b 100644 --- a/src/game.cpp +++ b/src/game.cpp @@ -3320,8 +3320,8 @@ void game::display_faction_epilogues() }; scrollable_text( new_win, elem.second.name, std::accumulate( epilogue.begin() + 1, epilogue.end(), epilogue.front(), - []( const std::string & lhs, const std::string & rhs ) -> std::string { - return lhs + "\n" + rhs; + []( std::string lhs, const std::string & rhs ) -> std::string { + return std::move( lhs ) + "\n" + rhs; } ) ); } } diff --git a/src/help.cpp b/src/help.cpp index 8cb5986d5ccba..210c2887a9e0b 100644 --- a/src/help.cpp +++ b/src/help.cpp @@ -196,12 +196,14 @@ void help::display_help() const size_t pos2 = line_proc.find( ">", pos, 1 ); std::string action = line_proc.substr( pos + 7, pos2 - pos - 7 ); - auto replace = "" + press_x( look_up_action( action ), "", "" ) + ""; + std::string replace = "" + + press_x( look_up_action( action ), "", "" ) + ""; if( replace.empty() ) { debugmsg( "Help json: Unknown action: %s", action ); } else { - line_proc = string_replace( line_proc, "", replace ); + line_proc = string_replace( + line_proc, "", replace ); } pos = line_proc.find( " &info, int reduce_encum } } } + const std::string when_full_message = space + _( "When full:" ) + space; + const std::string coverage_message = space + _( "Coverage:" ) + space; for( auto &piece : to_display_data ) { if( t->sided ) { const bodypart_str_id &covering_id = piece.first; @@ -2776,12 +2778,12 @@ void item::armor_encumbrance_info( std::vector &info, int reduce_encum piece.second.portion.encumber ) ); if( piece.second.portion.encumber != piece.second.portion.max_encumber ) { - info.push_back( iteminfo( "ARMOR", space + _( "When full:" ) + space, "", + info.push_back( iteminfo( "ARMOR", when_full_message, "", iteminfo::no_newline | iteminfo::lower_is_better, piece.second.portion.max_encumber ) ); } - info.push_back( iteminfo( "ARMOR", space + _( "Coverage:" ) + space, "", + info.push_back( iteminfo( "ARMOR", coverage_message, "", iteminfo::no_flags, piece.second.portion.coverage ) ); } diff --git a/src/iuse.cpp b/src/iuse.cpp index 41eea1facc843..95e184bdb225a 100644 --- a/src/iuse.cpp +++ b/src/iuse.cpp @@ -6952,8 +6952,12 @@ static object_names_collection enumerate_objects_around_point( const tripoint &p const std::string trap_name = colorized_trap_name_at( point_around_figure ); const std::string field_desc = colorized_field_description_at( point_around_figure ); + auto augment_description = [&]( std::string & desc ) { + desc = str_cat( trap_name, desc, field_desc ); + }; + if( !furn_desc.empty() ) { - furn_desc = trap_name + furn_desc + field_desc; + augment_description( furn_desc ); if( point == point_around_figure && create_figure_desc ) { description_furniture_on_figure = furn_desc; } else { @@ -6986,7 +6990,7 @@ static object_names_collection enumerate_objects_around_point( const tripoint &p local_vehicles_recorded.insert( veh_hash ); } else if( !item.is_null() ) { std::string item_name = colorized_item_name( item ); - item_name = trap_name + item_name + field_desc; + augment_description( item_name ); if( point == point_around_figure && create_figure_desc ) { //~ %1$s: terrain description, %2$s: item name description_terrain_on_figure = string_format( pgettext( "terrain and item", "%1$s with a %2$s" ), @@ -6995,21 +6999,21 @@ static object_names_collection enumerate_objects_around_point( const tripoint &p ret_obj.items[ item_name ] ++; } } else if( !unusual_ter_desc.empty() ) { - unusual_ter_desc = trap_name + unusual_ter_desc + field_desc; + augment_description( unusual_ter_desc ); if( point == point_around_figure && create_figure_desc ) { description_furniture_on_figure = unusual_ter_desc; } else { ret_obj.furniture[ unusual_ter_desc ] ++; } } else if( !ter_desc.empty() && ( !field_desc.empty() || !trap_name.empty() ) ) { - ter_desc = trap_name + ter_desc + field_desc; + augment_description( ter_desc ); if( point == point_around_figure && create_figure_desc ) { description_terrain_on_figure = ter_desc; } else { ret_obj.terrain[ ter_desc ] ++; } } else { - ter_desc = trap_name + ter_desc + field_desc; + augment_description( ter_desc ); if( point == point_around_figure && create_figure_desc ) { description_terrain_on_figure = ter_desc; } diff --git a/src/mapgen.cpp b/src/mapgen.cpp index 6e9e446e29654..12bf05145f44e 100644 --- a/src/mapgen.cpp +++ b/src/mapgen.cpp @@ -2197,8 +2197,8 @@ void mapgen_palette::load_place_mapings( const JsonObject &jo, const std::string continue; } auto &vect = format_placings[ key ]; - ::load_place_mapings( sub.get_member( member_name ), vect, - member_name + " in mapping in " + context ); + std::string this_context = string_format( "%s in mapping in %s", member_name, context ); + ::load_place_mapings( sub.get_member( member_name ), vect, this_context ); } } if( !jo.has_object( member_name ) ) { @@ -2207,8 +2207,9 @@ void mapgen_palette::load_place_mapings( const JsonObject &jo, const std::string for( const JsonMember member : jo.get_object( member_name ) ) { const map_key key( member ); auto &vect = format_placings[ key ]; - ::load_place_mapings( - member, vect, member_name + " " + member.name() + " in " + context ); + std::string this_context = + string_format( "%s %s in %s", member_name, member.name(), context ); + ::load_place_mapings( member, vect, this_context ); } } diff --git a/src/mission_companion.cpp b/src/mission_companion.cpp index a74d805de20c2..9b158d9695340 100644 --- a/src/mission_companion.cpp +++ b/src/mission_companion.cpp @@ -154,10 +154,10 @@ void talk_function::scavenger_patrol( mission_data &mission_key, npc &p ) if( !npc_list.empty() ) { entry = _( "Profit: $25-$500\nDanger: Low\nTime: 10 hour missions\n\nPatrol Roster:\n" ); for( auto &elem : npc_list ) { - entry = entry + " " + elem->name + " [" + std::to_string( to_hours( calendar::turn - - elem->companion_mission_time ) ) + _( " hours]\n" ); + entry += " " + elem->name + " [" + std::to_string( to_hours( calendar::turn - + elem->companion_mission_time ) ) + _( " hours]\n" ); } - entry = entry + _( "\n\nDo you wish to bring your allies back into your party?" ); + entry += _( "\n\nDo you wish to bring your allies back into your party?" ); mission_key.add( "Retrieve Scavenging Patrol", _( "Retrieve Scavenging Patrol" ), entry ); } } @@ -176,10 +176,10 @@ void talk_function::scavenger_raid( mission_data &mission_key, npc &p ) entry = _( "Profit: $200-$1000\nDanger: Medium\nTime: 10 hour missions\n\n" "Raid Roster:\n" ); for( auto &elem : npc_list ) { - entry = entry + " " + elem->name + " [" + std::to_string( to_hours( calendar::turn - - elem->companion_mission_time ) ) + _( " hours]\n" ); + entry += " " + elem->name + " [" + std::to_string( to_hours( calendar::turn - + elem->companion_mission_time ) ) + _( " hours]\n" ); } - entry = entry + _( "\n\nDo you wish to bring your allies back into your party?" ); + entry += _( "\n\nDo you wish to bring your allies back into your party?" ); mission_key.add( "Retrieve Scavenging Raid", _( "Retrieve Scavenging Raid" ), entry ); } } @@ -194,10 +194,10 @@ void talk_function::commune_menial( mission_data &mission_key, npc &p ) "them basic skills and build reputation with the outpost. Don't expect " "much of a reward though.\n\nLabor Roster:\n" ); for( auto &elem : npc_list ) { - entry = entry + " " + elem->name + " [" + std::to_string( to_hours( calendar::turn - - elem->companion_mission_time ) ) + _( " hours]\n" ); + entry += " " + elem->name + " [" + std::to_string( to_hours( calendar::turn - + elem->companion_mission_time ) ) + _( " hours]\n" ); } - entry = entry + _( "\n\nDo you wish to bring your allies back into your party?" ); + entry += _( "\n\nDo you wish to bring your allies back into your party?" ); mission_key.add( "Recover Ally from Menial Labor", _( "Recover Ally from Menial Labor" ), entry ); } @@ -214,10 +214,10 @@ void talk_function::commune_carpentry( mission_data &mission_key, npc &p ) if( !npc_list.empty() ) { entry = _( "Profit: $12/hour\nDanger: Minimal\nTime: 1 hour minimum\n\nLabor Roster:\n" ); for( auto &elem : npc_list ) { - entry = entry + " " + elem->name + " [" + std::to_string( to_hours( calendar::turn - - elem->companion_mission_time ) ) + _( " hours]\n" ); + entry += " " + elem->name + " [" + std::to_string( to_hours( calendar::turn - + elem->companion_mission_time ) ) + _( " hours]\n" ); } - entry = entry + _( "\n\nDo you wish to bring your allies back into your party?" ); + entry += _( "\n\nDo you wish to bring your allies back into your party?" ); mission_key.add( "Recover Ally from Carpentry Work", _( "Recover Ally from Carpentry Work" ), entry ); } @@ -306,10 +306,10 @@ void talk_function::commune_forage( mission_data &mission_key, npc &p ) if( !npc_list.empty() ) { entry = _( "Profit: $10/hour\nDanger: Low\nTime: 4 hour minimum\n\nLabor Roster:\n" ); for( auto &elem : npc_list ) { - entry = entry + " " + elem->name + " [" + std::to_string( to_hours( calendar::turn - - elem->companion_mission_time ) ) + _( " hours]\n" ); + entry += " " + elem->name + " [" + std::to_string( to_hours( calendar::turn - + elem->companion_mission_time ) ) + _( " hours]\n" ); } - entry = entry + _( "\n\nDo you wish to bring your allies back into your party?" ); + entry += _( "\n\nDo you wish to bring your allies back into your party?" ); mission_key.add( "Recover Ally from Foraging", _( "Recover Ally from Foraging" ), entry ); } } @@ -333,13 +333,13 @@ void talk_function::commune_refuge_caravan( mission_data &mission_key, npc &p ) "\nRoster:\n" ); for( auto &elem : npc_list ) { if( elem->companion_mission_time == calendar::before_time_starts ) { - entry = entry + " " + elem->name + _( " [READY]\n" ); + entry += " " + elem->name + _( " [READY]\n" ); npc_list_aux.push_back( elem ); } else if( calendar::turn >= elem->companion_mission_time ) { - entry = entry + " " + elem->name + _( " [COMPLETE]\n" ); + entry += " " + elem->name + _( " [COMPLETE]\n" ); } else { - entry = entry + " " + elem->name + " [" + std::to_string( std::abs( to_hours - ( calendar::turn - elem->companion_mission_time ) ) ) + _( " Hours]\n" ); + entry += " " + elem->name + " [" + std::to_string( std::abs( to_hours + ( calendar::turn - elem->companion_mission_time ) ) ) + _( " Hours]\n" ); } } if( !npc_list_aux.empty() ) { @@ -348,7 +348,7 @@ void talk_function::commune_refuge_caravan( mission_data &mission_key, npc &p ) const std::string entry_suffix = _( " [READY]\n" ); for( auto &elem : npc_list_aux ) { if( elem->companion_mission_time == calendar::before_time_starts ) { - entry_aux = entry_aux + " " + elem->name + entry_suffix; + entry_aux += " " + elem->name + entry_suffix; } } entry_aux = entry_aux + _( "\n\n" @@ -357,7 +357,7 @@ void talk_function::commune_refuge_caravan( mission_data &mission_key, npc &p ) mission_key.add( "Begin Commune-Refugee Center Run", _( "Begin Commune-Refugee Center Run" ), entry ); } - entry = entry + _( "\n\nDo you wish to bring your allies back into your party?" ); + entry += _( "\n\nDo you wish to bring your allies back into your party?" ); mission_key.add( "Recover Commune-Refugee Center", _( "Recover Commune-Refugee Center" ), entry ); } diff --git a/src/mod_manager.cpp b/src/mod_manager.cpp index 7f3fcbbf21a1a..414d1607fa646 100644 --- a/src/mod_manager.cpp +++ b/src/mod_manager.cpp @@ -341,8 +341,7 @@ bool mod_manager::copy_mod_contents( const t_mod_list &mods_to_copy, // trim file paths from full length down to just /data forward for( auto &input_file : input_files ) { - std::string output_path = input_file; - output_path = cur_mod_dir + output_path.substr( start_index ); + std::string output_path = cur_mod_dir + input_file.substr( start_index ); copy_file( input_file, output_path ); } } diff --git a/src/newcharacter.cpp b/src/newcharacter.cpp index ce53b30ac77b9..b87e83453c0f2 100644 --- a/src/newcharacter.cpp +++ b/src/newcharacter.cpp @@ -2081,7 +2081,7 @@ tab_direction set_skills( avatar &u, points_left &points ) } ); if( elem.first == currentSkill->name() ) { - rec_disp = "\n\n" + colorize( rec_temp, c_brown ) + rec_disp; + rec_disp = "\n\n" + colorize( rec_temp, c_brown ) + std::move( rec_disp ); } else { rec_disp += "\n\n" + colorize( "[" + elem.first + "]\n" + rec_temp, c_light_gray ); } diff --git a/src/npctrade.cpp b/src/npctrade.cpp index e124282a06056..ee35e356637db 100644 --- a/src/npctrade.cpp +++ b/src/npctrade.cpp @@ -378,7 +378,7 @@ void trading_window::update_win( npc &np, const std::string &deal ) std::string itname = it->display_name(); if( np.will_exchange_items_freely() && ip.loc.where() != item_location::type::character ) { - itname = itname + " (" + ip.loc.describe( &player_character ) + ")"; + itname += " (" + ip.loc.describe( &player_character ) + ")"; color = c_light_blue; } diff --git a/src/options.cpp b/src/options.cpp index cbdc264e0a354..ea6641a0f6fb3 100644 --- a/src/options.cpp +++ b/src/options.cpp @@ -913,9 +913,10 @@ static std::vector build_resource_list( resource_option.clear(); const auto resource_dirs = get_directories_with( filename, dirname, true ); + const std::string slash_filename = "/" + filename; for( const std::string &resource_dir : resource_dirs ) { - read_from_file( resource_dir + "/" + filename, [&]( std::istream & fin ) { + read_from_file( resource_dir + slash_filename, [&]( std::istream & fin ) { std::string resource_name; std::string view_name; // should only have 2 values inside it, otherwise is going to only load the last 2 values diff --git a/src/veh_interact.cpp b/src/veh_interact.cpp index f834e953dfda0..39bf2ac840f51 100644 --- a/src/veh_interact.cpp +++ b/src/veh_interact.cpp @@ -1459,7 +1459,7 @@ void veh_interact::calc_overview() int offset = 1; std::string fmtstring = "%s %s %5.1fL"; if( pt.is_leaking() ) { - fmtstring = "%s %s " + leak_marker + "%5.1fL" + leak_marker; + fmtstring = str_cat( "%s %s ", leak_marker, "%5.1fL", leak_marker ); offset = 0; } right_print( w, y, offset, pt_ammo_cur->color, @@ -1467,7 +1467,7 @@ void veh_interact::calc_overview() round_up( units::to_liter( it.volume() ), 1 ) ) ); } else { if( pt.is_leaking() ) { - std::string outputstr = leak_marker + " " + leak_marker; + std::string outputstr = str_cat( leak_marker, " ", leak_marker ); right_print( w, y, 0, c_light_gray, outputstr ); } } @@ -1480,7 +1480,7 @@ void veh_interact::calc_overview() int offset = 1; std::string fmtstring = "%s %5.1fL"; if( pt.is_leaking() ) { - fmtstring = "%s " + leak_marker + "%5.1fL" + leak_marker; + fmtstring = str_cat( "%s ", leak_marker, "%5.1fL", leak_marker ); offset = 0; } right_print( w, y, offset, pt_ammo_cur->color, @@ -1507,7 +1507,7 @@ void veh_interact::calc_overview() int offset = 1; std::string fmtstring = "%i %3i%%"; if( pt.is_leaking() ) { - fmtstring = "%i " + leak_marker + "%3i%%" + leak_marker; + fmtstring = str_cat( "%i ", leak_marker, "%3i%%", leak_marker ); offset = 0; } right_print( w, y, offset, item::find_type( pt.ammo_current() )->color, @@ -1522,7 +1522,7 @@ void veh_interact::calc_overview() int offset = 1; std::string fmtstring = "%s %5i"; if( pt.is_leaking() ) { - fmtstring = "%s " + leak_marker + "%5i" + leak_marker; + fmtstring = str_cat( "%s ", leak_marker, "%5i", leak_marker ); offset = 0; } right_print( w, y, offset, item::find_type( pt.ammo_current() )->color, diff --git a/src/worldfactory.cpp b/src/worldfactory.cpp index 51e94d63ca1cb..7408d067f4074 100644 --- a/src/worldfactory.cpp +++ b/src/worldfactory.cpp @@ -741,19 +741,20 @@ void worldfactory::draw_mod_list( const catacurses::window &w, int &start, size_ } const mod_id &mod_entry_id = *iter; - std::string mod_entry_name = string_format( _( " [%s]" ), mod_entry_id.str() ); + std::string mod_entry_name; nc_color mod_entry_color = c_white; if( mod_entry_id.is_valid() ) { const MOD_INFORMATION &mod = *mod_entry_id; - mod_entry_name = mod.name() + mod_entry_name; + mod_entry_name = mod.name(); if( mod.obsolete ) { mod_entry_color = c_dark_gray; } } else { mod_entry_color = c_light_red; - mod_entry_name = _( "N/A" ) + mod_entry_name; + mod_entry_name = _( "N/A" ); } + mod_entry_name += string_format( _( " [%s]" ), mod_entry_id.str() ); trim_and_print( w, point( 4, iNum - start ), wwidth, mod_entry_color, mod_entry_name ); if( w_shift ) { diff --git a/tests/string_test.cpp b/tests/string_test.cpp index 4293374abc27e..b998ada26c14c 100644 --- a/tests/string_test.cpp +++ b/tests/string_test.cpp @@ -38,3 +38,26 @@ TEST_CASE( "trim_by_length" ) CHECK( trim_by_length( "MRE 主菜(鸡肉意大利香蒜沙司通心粉)(新鲜)", 36 ) == "MRE 主菜(鸡肉意大利香蒜沙司通心粉…" ); } + +TEST_CASE( "str_cat" ) +{ + CHECK( str_cat( " " ) == " " ); + CHECK( str_cat( "a", "b", "c" ) == "abc" ); + CHECK( str_cat( "a", std::string( "b" ), "c" ) == "abc" ); + std::string a( "a" ); + std::string b( "b" ); + std::string result = str_cat( a, std::move( b ), a ); + CHECK( result == "aba" ); +} + +TEST_CASE( "str_append" ) +{ + std::string root( "a" ); + CHECK( str_append( root, " " ) == "a " ); + CHECK( str_append( root, "b", "c" ) == "a bc" ); + CHECK( str_append( root, std::string( "b" ), "c" ) == "a bcbc" ); + std::string a( "a" ); + std::string b( "b" ); + str_append( root, a, std::move( b ), a ); + CHECK( root == "a bcbcaba" ); +} diff --git a/tools/clang-tidy-plugin/HeaderGuardCheck.cpp b/tools/clang-tidy-plugin/HeaderGuardCheck.cpp index e51841b191fbe..16894eaddd4fd 100644 --- a/tools/clang-tidy-plugin/HeaderGuardCheck.cpp +++ b/tools/clang-tidy-plugin/HeaderGuardCheck.cpp @@ -9,6 +9,8 @@ #include #endif +#include "Utils.h" + namespace clang { namespace tidy @@ -360,12 +362,13 @@ class HeaderGuardPPCallbacks : public PPCallbacks Newlines = "\n"; } + std::string ToInsertHeader = StrCat( + "#ifndef ", CPPVar, "\n#define ", CPPVar, Newlines ); Check->diag( InsertLoc, "Header is missing header guard." ) - << FixItHint::CreateInsertion( - InsertLoc, "#ifndef " + CPPVar + "\n#define " + CPPVar + Newlines ) + << FixItHint::CreateInsertion( InsertLoc, ToInsertHeader ) << FixItHint::CreateInsertion( SM.getLocForEndOfFile( FID ), - "\n#" + formatEndIf( CPPVar ) + "\n" ); + StrCat( "\n#", formatEndIf( CPPVar ), "\n" ) ); } } private: diff --git a/tools/clang-tidy-plugin/Utils.h b/tools/clang-tidy-plugin/Utils.h index df7a355ca45c1..c84f1c0ddb9d4 100644 --- a/tools/clang-tidy-plugin/Utils.h +++ b/tools/clang-tidy-plugin/Utils.h @@ -217,6 +217,16 @@ inline size_t HashCombine( const T &t, const U &u ) return result; } +template +std::string StrCat( T0 &&a0, T &&...a ) +{ + std::string result( std::forward( a0 ) ); + // Using initializer list as a poor man's fold expression until C++17. + static_cast( + std::array { ( result.append( std::forward( a ) ), false )... } ); + return result; +} + } // namespace cata } // namespace tidy } // namespace clang From ab5431cc8ff72571dbf8b187985226932d6d060a Mon Sep 17 00:00:00 2001 From: John Bytheway Date: Fri, 16 Apr 2021 15:22:05 -0400 Subject: [PATCH 411/453] Enable performance-inefficient-string-concatenation --- .clang-tidy | 1 - 1 file changed, 1 deletion(-) diff --git a/.clang-tidy b/.clang-tidy index 534a499defb7f..6b5239d0b8b2f 100644 --- a/.clang-tidy +++ b/.clang-tidy @@ -30,7 +30,6 @@ readability-*,\ -modernize-return-braced-init-list,\ -modernize-use-default-member-init,\ -modernize-use-emplace,\ --performance-inefficient-string-concatenation,\ -performance-type-promotion-in-math-fn,\ -performance-unnecessary-value-param,\ -readability-braces-around-statements,\ From 731ab1fc21c963e68341913b4687233bc1142b96 Mon Sep 17 00:00:00 2001 From: John Bytheway Date: Tue, 20 Apr 2021 13:23:47 -0400 Subject: [PATCH 412/453] Enable clang-tidy check cert-flp30-c This is just an alias for clang-analyzer-security.FloatLoopCounter which we're already running, so it just required suppressions in the same places. --- .clang-tidy | 1 - tests/rng_test.cpp | 4 ++-- 2 files changed, 2 insertions(+), 3 deletions(-) diff --git a/.clang-tidy b/.clang-tidy index 6b5239d0b8b2f..a53ca3ca5bc02 100644 --- a/.clang-tidy +++ b/.clang-tidy @@ -23,7 +23,6 @@ performance-*,\ readability-*,\ -bugprone-misplaced-widening-cast,\ -bugprone-narrowing-conversions,\ --cert-flp30-c,\ -misc-non-private-member-variables-in-classes,\ -modernize-avoid-c-arrays,\ -modernize-pass-by-value,\ diff --git a/tests/rng_test.cpp b/tests/rng_test.cpp index d1ba612048fd9..ff2fcafc7a734 100644 --- a/tests/rng_test.cpp +++ b/tests/rng_test.cpp @@ -54,11 +54,11 @@ static void check_x_in_y( double x, double y ) TEST_CASE( "x_in_y_distribution" ) { float y_increment = 0.01f; - // NOLINTNEXTLINE(clang-analyzer-security.FloatLoopCounter) + // NOLINTNEXTLINE(clang-analyzer-security.FloatLoopCounter,cert-flp30-c) for( float y = 0.1f; y < 500.0f; y += y_increment ) { y_increment *= 1.1f; float x_increment = 0.1f; - // NOLINTNEXTLINE(clang-analyzer-security.FloatLoopCounter) + // NOLINTNEXTLINE(clang-analyzer-security.FloatLoopCounter,cert-flp30-c) for( float x = 0.1f; x < y; x += x_increment ) { check_x_in_y( x, y ); x_increment *= 1.1f; From 584cdbcbaddca4e42f2a5809c458bcd6f514e38d Mon Sep 17 00:00:00 2001 From: John Bytheway Date: Wed, 21 Apr 2021 11:01:55 -0400 Subject: [PATCH 413/453] Improve error message for JSON files with a BOM (#48595) * Improve error message for JSON files with a BOM Previously, JSON files starting with a BOM would have a strange and unhelpful error message that could easily confuse new contributors who had edited a file in Notepad. Add a check for this case and try to provide a more helpful error. Also, expand on this issue in CONTRIBUTING.md, and add some more links to the wiki guide for first time contributors. Co-authored-by: Binrui Dong --- .github/CONTRIBUTING.md | 20 ++++++++++++++++++-- doc/MODDING.md | 5 +++++ src/json.cpp | 27 +++++++++++++++++++++++++++ src/json.h | 11 ++++------- 4 files changed, 54 insertions(+), 9 deletions(-) diff --git a/.github/CONTRIBUTING.md b/.github/CONTRIBUTING.md index fc2f76faaa571..bd959ede62aea 100644 --- a/.github/CONTRIBUTING.md +++ b/.github/CONTRIBUTING.md @@ -2,12 +2,28 @@ **Opening a new issue?** Please read [ISSUES.md](../ISSUES.md) first. -Contributing to Cataclysm: Dark Days Ahead is easy — simply fork the repository here on GitHub, make your changes, and then send us a pull request. +**Want an introductory guide for creating game content?** You might want to +read the [Guide to adding new content to CDDA for first time +contributors](https://github.com/CleverRaven/Cataclysm-DDA/wiki/Guide-to-adding-new-content-to-CDDA-for-first-time-contributors) +on the CDDA wiki. Cataclysm:Dark Days Ahead is released under the Creative Commons Attribution ShareAlike 3.0 license. The code and content of the game is free to use, modify, and redistribute for any purpose whatsoever. See http://creativecommons.org/licenses/by-sa/3.0/ for details. This means any contribution you make to the project will also be covered by the same license, and this license is irrevocable. -## Guidelines +## Using a good text editor + +Most of the Cataclysm: Dark Days Ahead game data is defined in JSON files. +These files are intended to be easy for you to edit, but there are some +pitfalls. Using Windows Notepad can get you into trouble, because it likes to +insert a special character called a BOM at the start of the file, which CDDA +does not want. + +If you're going to be editing JSON files consider getting a more fully-featured +editor such as [Notepad++](https://notepad-plus-plus.org/). + +## Contributing to GitHub + +Contributing to Cataclysm: Dark Days Ahead is easy — simply fork the repository here on GitHub, make your changes, and then send us a pull request. There are a couple of guidelines we suggest sticking to: diff --git a/doc/MODDING.md b/doc/MODDING.md index 6b6d2fa638421..1db912b8cff7d 100644 --- a/doc/MODDING.md +++ b/doc/MODDING.md @@ -4,6 +4,11 @@ Certain features of the game can be modified without rebuilding the game from so The majority of modding is done by editing JSON files. An in-depth review of all json files and their appropriate fields is available in [JSON_INFO.md](JSON_INFO.md). +## Other guides + +You might want to read the [Guide to adding new content to CDDA for first time +contributors](https://github.com/CleverRaven/Cataclysm-DDA/wiki/Guide-to-adding-new-content-to-CDDA-for-first-time-contributors) on the CDDA wiki. + ## The basics ### Creating a barebones mod diff --git a/src/json.cpp b/src/json.cpp index 0f2df3195ee3b..b6657d2301cc6 100644 --- a/src/json.cpp +++ b/src/json.cpp @@ -747,6 +747,33 @@ void add_array_to_set( std::set &s, const JsonObject &json, const s } } +JsonIn::JsonIn( std::istream &s ) : stream( &s ) +{ + sanity_check_stream(); +} + +JsonIn::JsonIn( std::istream &s, const std::string &path ) + : stream( &s ) + , path( make_shared_fast( path ) ) +{ + sanity_check_stream(); +} + +JsonIn::JsonIn( std::istream &s, const json_source_location &loc ) + : stream( &s ), path( loc.path ) +{ + seek( loc.offset ); + sanity_check_stream(); +} + +void JsonIn::sanity_check_stream() +{ + char c = stream->peek(); + if( c == '\xef' ) { + error( _( "This JSON file looks like it starts with a Byte Order Mark (BOM) or is otherwise corrupted. This can happen if you edit files in Windows Notepad. See doc/CONTRIBUTING.md for more advice." ) ); + } +} + int JsonIn::tell() { return stream->tellg(); diff --git a/src/json.h b/src/json.h index f9bbb5dba5ae7..f192a81828c87 100644 --- a/src/json.h +++ b/src/json.h @@ -189,18 +189,15 @@ class JsonIn shared_ptr_fast path; bool ate_separator = false; + void sanity_check_stream(); void skip_separator(); void skip_pair_separator(); void end_value(); public: - explicit JsonIn( std::istream &s ) : stream( &s ) {} - JsonIn( std::istream &s, const std::string &path ) - : stream( &s ), path( make_shared_fast( path ) ) {} - JsonIn( std::istream &s, const json_source_location &loc ) - : stream( &s ), path( loc.path ) { - seek( loc.offset ); - } + explicit JsonIn( std::istream &s ); + JsonIn( std::istream &s, const std::string &path ); + JsonIn( std::istream &s, const json_source_location &loc ); JsonIn( const JsonIn & ) = delete; JsonIn &operator=( const JsonIn & ) = delete; From 875d1154459d0a65c2f09d4ef4e1bb658e9b17df Mon Sep 17 00:00:00 2001 From: John Bytheway Date: Thu, 22 Apr 2021 20:59:16 -0400 Subject: [PATCH 414/453] Improve tripoint formatting in debug messages (#48611) --- src/debug_menu.cpp | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/src/debug_menu.cpp b/src/debug_menu.cpp index f50b9a6978440..bd4646ff5a065 100644 --- a/src/debug_menu.cpp +++ b/src/debug_menu.cpp @@ -1022,7 +1022,7 @@ void teleport_short() } g->place_player( *where ); const tripoint new_pos( player_location.pos() ); - add_msg( _( "You teleport to point (%d,%d,%d)." ), new_pos.x, new_pos.y, new_pos.z ); + add_msg( _( "You teleport to point %s." ), new_pos.to_string() ); } void teleport_long() @@ -1032,7 +1032,7 @@ void teleport_long() return; } g->place_player_overmap( where ); - add_msg( _( "You teleport to submap (%s)." ), where.to_string() ); + add_msg( _( "You teleport to submap %s." ), where.to_string() ); } void teleport_overmap( bool specific_coordinates ) From 06252cfbbeca3dec3cd2f1f97bebd5ba9e3b3133 Mon Sep 17 00:00:00 2001 From: John Bytheway Date: Tue, 20 Apr 2021 21:34:09 -0400 Subject: [PATCH 415/453] Improve messages for some JSON errors Several of the top-level save files were not providing filenames with their JSON error messages, because the filename was never passed to the JsonIn constructor. Arrange for it to be so passed, to improve those errors and assist with debugging. --- src/game.cpp | 13 ++++++++----- src/game.h | 4 ++-- src/memorial_logger.cpp | 4 ++-- src/memorial_logger.h | 2 +- src/savegame.cpp | 8 ++++---- tests/memorial_test.cpp | 6 +++--- 6 files changed, 20 insertions(+), 17 deletions(-) diff --git a/src/game.cpp b/src/game.cpp index fa30668c1bb5b..67515c5555069 100644 --- a/src/game.cpp +++ b/src/game.cpp @@ -2931,7 +2931,8 @@ bool game::load( const save_t &name ) u.name = name.player_name(); // This should be initialized more globally (in player/Character constructor) u.weapon = item(); - if( !read_from_file( playerpath + SAVE_EXTENSION, std::bind( &game::unserialize, this, _1 ) ) ) { + const std::string save_filename = playerpath + SAVE_EXTENSION; + if( !read_from_file( save_filename, std::bind( &game::unserialize, this, _1, save_filename ) ) ) { return false; } @@ -2939,12 +2940,14 @@ bool game::load( const save_t &name ) u.deserialize_map_memory( jsin ); } ); - read_from_file_optional( worldpath + name.base_path() + SAVE_EXTENSION_LOG, - std::bind( &memorial_logger::load, &memorial(), _1 ) ); + const std::string log_filename = worldpath + name.base_path() + SAVE_EXTENSION_LOG; + read_from_file_optional( log_filename, + std::bind( &memorial_logger::load, &memorial(), _1, log_filename ) ); #if defined(__ANDROID__) - read_from_file_optional( worldpath + name.base_path() + SAVE_EXTENSION_SHORTCUTS, - std::bind( &game::load_shortcuts, this, _1 ) ); + const std::string shortcuts_filename = worldpath + name.base_path() + SAVE_EXTENSION_SHORTCUTS; + read_from_file_optional( shortcuts_filename, + std::bind( &game::load_shortcuts, this, _1, shortcuts_filename ) ); #endif // Now that the player's worn items are updated, their sight limits need to be diff --git a/src/game.h b/src/game.h index 41f62321b594f..477886cb11110 100644 --- a/src/game.h +++ b/src/game.h @@ -208,7 +208,7 @@ class game void setup(); /** Saving and loading functions. */ void serialize( std::ostream &fout ); // for save - void unserialize( std::istream &fin ); // for load + void unserialize( std::istream &fin, const std::string &path ); // for load void unserialize_master( std::istream &fin ); // for load /** write statistics to stdout and @return true if successful */ @@ -750,7 +750,7 @@ class game bool load( const save_t &name ); // Load a player-specific save file void load_master(); // Load the master data file, with factions &c #if defined(__ANDROID__) - void load_shortcuts( std::istream &fin ); + void load_shortcuts( std::istream &fin, const std::string &path ); #endif bool start_game(); // Starts a new game in the active world diff --git a/src/memorial_logger.cpp b/src/memorial_logger.cpp index 9de81018cf371..c5982bb223d8f 100644 --- a/src/memorial_logger.cpp +++ b/src/memorial_logger.cpp @@ -140,7 +140,7 @@ void memorial_logger::add( const std::string &male_msg, * In new format the entries are stored as json. * @param fin The stream to read the memorial entries from. */ -void memorial_logger::load( std::istream &fin ) +void memorial_logger::load( std::istream &fin, const std::string &path ) { log.clear(); if( fin.peek() == '|' ) { @@ -155,7 +155,7 @@ void memorial_logger::load( std::istream &fin ) log.emplace_back( entry ); } } else { - JsonIn jsin( fin ); + JsonIn jsin( fin, path ); if( !jsin.read( log ) ) { debugmsg( "Error reading JSON memorial log" ); } diff --git a/src/memorial_logger.h b/src/memorial_logger.h index c4f426f32d4b4..250ec0a8a7d4f 100644 --- a/src/memorial_logger.h +++ b/src/memorial_logger.h @@ -63,7 +63,7 @@ class memorial_logger : public event_subscriber } // Loads the memorial log from a file - void load( std::istream & ); + void load( std::istream &, const std::string &path ); void save( std::ostream & ) const; // Dumps all memorial events into a single newline-delimited string // (this is the content of the temporary file used to preserve the log diff --git a/src/savegame.cpp b/src/savegame.cpp index ce41928e5472c..86d99ff82e023 100644 --- a/src/savegame.cpp +++ b/src/savegame.cpp @@ -175,7 +175,7 @@ static void chkversion( std::istream &fin ) /* * Parse an open .sav file. */ -void game::unserialize( std::istream &fin ) +void game::unserialize( std::istream &fin, const std::string &path ) { chkversion( fin ); int tmpturn = 0; @@ -183,7 +183,7 @@ void game::unserialize( std::istream &fin ) int tmprun = 0; tripoint_om_sm lev; point_abs_om com; - JsonIn jsin( fin ); + JsonIn jsin( fin, path ); try { JsonObject data = jsin.get_object(); @@ -303,9 +303,9 @@ void scent_map::deserialize( const std::string &data, bool is_type ) #if defined(__ANDROID__) ///// quick shortcuts -void game::load_shortcuts( std::istream &fin ) +void game::load_shortcuts( std::istream &fin, const std::string &path ) { - JsonIn jsin( fin ); + JsonIn jsin( fin, path ); try { JsonObject data = jsin.get_object(); diff --git a/tests/memorial_test.cpp b/tests/memorial_test.cpp index 41b976094de5b..01c0727fa17dd 100644 --- a/tests/memorial_test.cpp +++ b/tests/memorial_test.cpp @@ -294,7 +294,7 @@ TEST_CASE( "convert_legacy_memorial_log", "[memorial]" ) memorial_logger logger; { std::istringstream is( input ); - logger.load( is ); + logger.load( is, "" ); std::ostringstream os; logger.save( os ); CHECK( os.str() == json_value ); @@ -303,7 +303,7 @@ TEST_CASE( "convert_legacy_memorial_log", "[memorial]" ) // Then verify that the new format is unchanged { std::istringstream is( json_value ); - logger.load( is ); + logger.load( is, "" ); std::ostringstream os; logger.save( os ); CHECK( os.str() == json_value ); @@ -328,6 +328,6 @@ TEST_CASE( "memorial_log_dumping", "[memorial]" ) memorial_logger logger; std::istringstream is( json_value ); - logger.load( is ); + logger.load( is, "" ); CHECK( logger.dump() == expected_output ); } From 499a805668bd590737dbf90e676261f4652b0e0f Mon Sep 17 00:00:00 2001 From: John Bytheway Date: Fri, 23 Apr 2021 17:06:12 -0400 Subject: [PATCH 416/453] Omit tests that are failing on Mingw (#48622) * Omit tests that are failing on Mingw These string_formatter tests fail on Mingw and it looks like it's simply a bug in the standard library there. I don't know that we can reasonably fix them (short of implementing printf ourselves) and they're showing up in the GitHub UI for every PR, which is potentially confusing for contributors. * Remove !mayfail marking on string_formatter test This should no longer be expected to fail, with the troublesome tests excised. --- tests/string_formatter_test.cpp | 9 +++++++-- 1 file changed, 7 insertions(+), 2 deletions(-) diff --git a/tests/string_formatter_test.cpp b/tests/string_formatter_test.cpp index 18e4d50bb0fc5..18f2fae922e4a 100644 --- a/tests/string_formatter_test.cpp +++ b/tests/string_formatter_test.cpp @@ -101,8 +101,7 @@ void mingw_test( const char *const old_pattern, const char *const new_pattern, c CHECK( original_result == new_result ); } -// Marking mayfail due to failure in MXE's MinGW on Travis on Ubuntu Xenial. -TEST_CASE( "string_formatter", "[!mayfail]" ) +TEST_CASE( "string_formatter" ) { test_typed_printf( "%hhi", "%i" ); test_typed_printf( "%hhu", "%u" ); @@ -221,7 +220,10 @@ TEST_CASE( "string_formatter", "[!mayfail]" ) importet_test( 38, "42 ", "%0-15d", 42 ); importet_test( 39, "-42 ", "%0-15d", -42 ); importet_test( 43, "42.90", "%.2f", 42.8952 ); +#if !(defined(__MINGW32__) || defined(__MINGW64__)) + // Omit this one that fails on Mingw importet_test( 44, "42.90", "%.2F", 42.8952 ); +#endif importet_test( 45, "42.8952000000", "%.10f", 42.8952 ); importet_test( 46, "42.90", "%1.2f", 42.8952 ); importet_test( 47, " 42.90", "%6.2f", 42.8952 ); @@ -515,6 +517,8 @@ TEST_CASE( "string_formatter", "[!mayfail]" ) importet_test( 365, " 00edcb5433", "%20.10x", 3989525555U ); importet_test( 366, " 1234ABCD", "%20.5X", 305441741 ); importet_test( 367, " 00EDCB5433", "%20.10X", 3989525555U ); +#if !(defined(__MINGW32__) || defined(__MINGW64__)) + // Omit these ones that fail on Mingw importet_test( 369, " 01024", "%020.5d", 1024 ); importet_test( 370, " -01024", "%020.5d", -1024 ); importet_test( 371, " 01024", "%020.5i", 1024 ); @@ -527,6 +531,7 @@ TEST_CASE( "string_formatter", "[!mayfail]" ) importet_test( 378, " 00edcb5433", "%020.10x", 3989525555U ); importet_test( 379, " 1234ABCD", "%020.5X", 305441741 ); importet_test( 380, " 00EDCB5433", "%020.10X", 3989525555U ); +#endif importet_test( 381, "", "%.0s", "Hallo heimur" ); importet_test( 382, " ", "%20.0s", "Hallo heimur" ); importet_test( 383, "", "%.s", "Hallo heimur" ); From 249c3c6d63af70518b00d3228b1b7f7d7d43570b Mon Sep 17 00:00:00 2001 From: John Bytheway Date: Mon, 26 Apr 2021 21:26:25 -0400 Subject: [PATCH 417/453] Triage clang-tidy readability-braces-around-statements (#48653) * Triage readability-braces-around-statements I tried running this clang-tidy check. It caught only one debatably useful case and had two false-positives due to a bug. This is mostly because this situation is already covered by astyle. I decided to take the opportunity to add comments for each of the disabled checks where we've decided we don't want to enable them. This one could be enabled once we're using a newer version of clang-tidy. Co-authored-by: actual-nh <74678550+actual-nh@users.noreply.github.com> Co-authored-by: Kevin Granade --- .clang-tidy | 26 +++++++++++++++++++++++++- 1 file changed, 25 insertions(+), 1 deletion(-) diff --git a/.clang-tidy b/.clang-tidy index a53ca3ca5bc02..1a30c0a992e36 100644 --- a/.clang-tidy +++ b/.clang-tidy @@ -4,6 +4,30 @@ # this codebase and we do not intend to fix. The disabled checks appearing # thereafter in a separate alphabetical list have yet to be triaged. We may # fix their errors or recategorise them as checks we don't care about. +# +# Comments on the checks we have decided are not worthwhile: +# +# * cert-dcl21-cpp (postfix operator++ and operator-- should return const objects) +# This is an unconventional code style, and conflicts with +# readability-const-return-type. +# +# * cert-env33-c (calls to system, popen) +# Unlikely to catch bugs, and using system is convenient for portability. +# +# * cert-err58-cpp (exceptions from static variable declarations) +# We have lots of memory allocations in static variable declarations, and +# that's fine. +# +# * modernize-use-auto +# We prefer an almost-always-avoid-auto style. +# +# * modernize-use-trailing-return-type +# An arbitrary style convention we haven't adopted. +# +# * readability-braces-around-statements +# Covered by astyle and buggy in clang-tidy 8. Can enable once we have a newer +# clang-tidy. + Checks: "\ bugprone-*,\ cata-*,\ @@ -21,6 +45,7 @@ modernize-*,\ -modernize-use-trailing-return-type,\ performance-*,\ readability-*,\ +-readability-braces-around-statements,\ -bugprone-misplaced-widening-cast,\ -bugprone-narrowing-conversions,\ -misc-non-private-member-variables-in-classes,\ @@ -31,7 +56,6 @@ readability-*,\ -modernize-use-emplace,\ -performance-type-promotion-in-math-fn,\ -performance-unnecessary-value-param,\ --readability-braces-around-statements,\ -readability-else-after-return,\ -readability-implicit-bool-conversion,\ -readability-isolate-declaration,\ From fc54563df1575f7b8da4890b5d4cb8ee396bda9a Mon Sep 17 00:00:00 2001 From: actual-nh <74678550+actual-nh@users.noreply.github.com> Date: Thu, 29 Apr 2021 15:15:28 -0400 Subject: [PATCH 418/453] Correct description of epidemiologist in newspaper (#48684) He's not a correspondent unless he's a reporter. --- data/json/snippets/newspapers.json | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/data/json/snippets/newspapers.json b/data/json/snippets/newspapers.json index 51269f1dfd27c..c059b05a82094 100644 --- a/data/json/snippets/newspapers.json +++ b/data/json/snippets/newspapers.json @@ -348,7 +348,7 @@ }, { "id": "weeks_old_news_12", - "text": "PSYCHIC EMANATIONS? A seemingly far-fetched theory about ongoing riots sweeping the nation has been gaining traction after a leaked document about experiments in magnetic control of brain-waves. \"Two weeks ago, I'd have told you this is ridiculous,\" said Dr. Andrew Morton, an epidemiologist and our leading correspondent for the medical basis for the riots. \"Now? I'll consider anything. With the caveat that I don't think any of this is possible, magnetic weaponry altering our brain waves and making people into crazy violent psychopaths is more plausible than a lot of the theories running around. I certainly prefer this one to that 'zombies' suggestion from a few days ago.\"" + "text": "PSYCHIC EMANATIONS? A seemingly far-fetched theory about ongoing riots sweeping the nation has been gaining traction after a leaked document about experiments in magnetic control of brain-waves. \"Two weeks ago, I'd have told you this is ridiculous,\" said Dr. Andrew Morton, an epidemiologist and our leading expert on the medical basis for the riots. \"Now? I'll consider anything. With the caveat that I don't think any of this is possible, magnetic weaponry altering our brain waves and making people into crazy violent psychopaths is more plausible than a lot of the theories running around. I certainly prefer this one to that 'zombies' suggestion from a few days ago.\"" }, { "id": "weeks_old_news_13", From 8a8974826c7b35e894c244bbc5f2d3a566da259b Mon Sep 17 00:00:00 2001 From: John Bytheway Date: Fri, 30 Apr 2021 07:52:41 -0400 Subject: [PATCH 419/453] Enable performance-type-promotion-in-math-fn Enable this clang-tidy check that has no associated warnings. --- .clang-tidy | 1 - 1 file changed, 1 deletion(-) diff --git a/.clang-tidy b/.clang-tidy index 1a30c0a992e36..9f3a11e18bec3 100644 --- a/.clang-tidy +++ b/.clang-tidy @@ -54,7 +54,6 @@ readability-*,\ -modernize-return-braced-init-list,\ -modernize-use-default-member-init,\ -modernize-use-emplace,\ --performance-type-promotion-in-math-fn,\ -performance-unnecessary-value-param,\ -readability-else-after-return,\ -readability-implicit-bool-conversion,\ From 6fa4248e8fffa8d70bdec6c9292abc5ff7e6c7f6 Mon Sep 17 00:00:00 2001 From: John Bytheway Date: Fri, 30 Apr 2021 15:46:53 -0400 Subject: [PATCH 420/453] Remove unused global statics --- src/character.cpp | 2 -- src/debug_menu.cpp | 1 - src/game_inventory.cpp | 2 -- src/item.cpp | 1 - src/iuse.cpp | 8 -------- src/map_extras.cpp | 6 ------ src/melee.cpp | 2 -- src/suffer.cpp | 3 --- src/visitable.cpp | 2 -- tests/clzones_test.cpp | 1 - tests/vehicle_part_test.cpp | 4 ++-- tools/clang-tidy-plugin/CataTidyModule.cpp | 1 + 12 files changed, 3 insertions(+), 30 deletions(-) diff --git a/src/character.cpp b/src/character.cpp index 0b82505d8d84f..1d59aeee1a82e 100644 --- a/src/character.cpp +++ b/src/character.cpp @@ -252,8 +252,6 @@ static const trait_id trait_CHITIN_FUR3( "CHITIN_FUR3" ); static const trait_id trait_CLUMSY( "CLUMSY" ); static const trait_id trait_DEBUG_NODMG( "DEBUG_NODMG" ); static const trait_id trait_DEFT( "DEFT" ); -static const trait_id trait_EASYSLEEPER( "EASYSLEEPER" ); -static const trait_id trait_EASYSLEEPER2( "EASYSLEEPER2" ); static const trait_id trait_EATHEALTH( "EATHEALTH" ); static const trait_id trait_FAT( "FAT" ); static const trait_id trait_FELINE_FUR( "FELINE_FUR" ); diff --git a/src/debug_menu.cpp b/src/debug_menu.cpp index bd4646ff5a065..850b391a78caf 100644 --- a/src/debug_menu.cpp +++ b/src/debug_menu.cpp @@ -111,7 +111,6 @@ #include "weighted_list.h" static const efftype_id effect_asthma( "asthma" ); -static const efftype_id effect_flu( "flu" ); static const mtype_id mon_generator( "mon_generator" ); diff --git a/src/game_inventory.cpp b/src/game_inventory.cpp index 1fb79e7692c1b..e2bd48c46f4ff 100644 --- a/src/game_inventory.cpp +++ b/src/game_inventory.cpp @@ -63,8 +63,6 @@ static const activity_id ACT_CONSUME_FOOD_MENU( "ACT_CONSUME_FOOD_MENU" ); static const activity_id ACT_CONSUME_DRINK_MENU( "ACT_CONSUME_DRINK_MENU" ); static const activity_id ACT_CONSUME_MEDS_MENU( "ACT_CONSUME_MEDS_MENU" ); -static const fault_id fault_bionic_salvaged( "fault_bionic_salvaged" ); - static const quality_id qual_ANESTHESIA( "ANESTHESIA" ); static const bionic_id bio_painkiller( "bio_painkiller" ); diff --git a/src/item.cpp b/src/item.cpp index b036d23277812..437450f384ad4 100644 --- a/src/item.cpp +++ b/src/item.cpp @@ -162,7 +162,6 @@ static const bionic_id bio_digestion( "bio_digestion" ); static const trait_id trait_CARNIVORE( "CARNIVORE" ); static const trait_id trait_JITTERY( "JITTERY" ); static const trait_id trait_LIGHTWEIGHT( "LIGHTWEIGHT" ); -static const trait_id trait_SAPROVORE( "SAPROVORE" ); static const trait_id trait_TOLERANCE( "TOLERANCE" ); static const trait_id trait_WOOLALLERGY( "WOOLALLERGY" ); diff --git a/src/iuse.cpp b/src/iuse.cpp index 95e184bdb225a..0cee62f9f03b2 100644 --- a/src/iuse.cpp +++ b/src/iuse.cpp @@ -121,7 +121,6 @@ static const activity_id ACT_CHOP_PLANKS( "ACT_CHOP_PLANKS" ); static const activity_id ACT_CHOP_TREE( "ACT_CHOP_TREE" ); static const activity_id ACT_CHURN( "ACT_CHURN" ); static const activity_id ACT_CLEAR_RUBBLE( "ACT_CLEAR_RUBBLE" ); -static const activity_id ACT_CRAFT( "ACT_CRAFT" ); static const activity_id ACT_FILL_PIT( "ACT_FILL_PIT" ); static const activity_id ACT_FISH( "ACT_FISH" ); static const activity_id ACT_GAME( "ACT_GAME" ); @@ -143,7 +142,6 @@ static const efftype_id effect_antibiotic( "antibiotic" ); static const efftype_id effect_antibiotic_visible( "antibiotic_visible" ); static const efftype_id effect_antifungal( "antifungal" ); static const efftype_id effect_asthma( "asthma" ); -static const efftype_id effect_attention( "attention" ); static const efftype_id effect_beartrap( "beartrap" ); static const efftype_id effect_bite( "bite" ); static const efftype_id effect_bleed( "bleed" ); @@ -206,7 +204,6 @@ static const efftype_id effect_strong_antibiotic_visible( "strong_antibiotic_vis static const efftype_id effect_stunned( "stunned" ); static const efftype_id effect_tapeworm( "tapeworm" ); static const efftype_id effect_teargas( "teargas" ); -static const efftype_id effect_teleglow( "teleglow" ); static const efftype_id effect_tetanus( "tetanus" ); static const efftype_id effect_tied( "tied" ); static const efftype_id effect_took_antiasthmatic( "took_antiasthmatic" ); @@ -350,23 +347,18 @@ static const species_id species_FUNGUS( "FUNGUS" ); static const species_id species_HALLUCINATION( "HALLUCINATION" ); static const species_id species_INSECT( "INSECT" ); static const species_id species_ROBOT( "ROBOT" ); -static const species_id species_ZOMBIE( "ZOMBIE" ); static const vitamin_id vitamin_blood( "blood" ); static const vitamin_id vitamin_redcells( "redcells" ); static const mongroup_id GROUP_FISH( "GROUP_FISH" ); -static const mtype_id mon_bee( "mon_bee" ); static const mtype_id mon_blob( "mon_blob" ); static const mtype_id mon_dog_thing( "mon_dog_thing" ); -static const mtype_id mon_fly( "mon_fly" ); static const mtype_id mon_hallu_multicooker( "mon_hallu_multicooker" ); static const mtype_id mon_hologram( "mon_hologram" ); -static const mtype_id mon_shadow( "mon_shadow" ); static const mtype_id mon_spore( "mon_spore" ); static const mtype_id mon_vortex( "mon_vortex" ); -static const mtype_id mon_wasp( "mon_wasp" ); static const bionic_id bio_shock( "bio_shock" ); static const bionic_id bio_tools( "bio_tools" ); diff --git a/src/map_extras.cpp b/src/map_extras.cpp index 5834d5cb92673..c55ddea0ee287 100644 --- a/src/map_extras.cpp +++ b/src/map_extras.cpp @@ -84,12 +84,10 @@ static const itype_id itype_bag_canvas( "bag_canvas" ); static const itype_id itype_bottle_glass( "bottle_glass" ); static const itype_id itype_bullwhip( "bullwhip" ); static const itype_id itype_chunk_sulfur( "chunk_sulfur" ); -static const itype_id itype_coke( "coke" ); static const itype_id itype_crowbar( "crowbar" ); static const itype_id itype_fedora( "fedora" ); static const itype_id itype_glasses_eye( "glasses_eye" ); static const itype_id itype_hatchet( "hatchet" ); -static const itype_id itype_heroin( "heroin" ); static const itype_id itype_holybook_bible1( "holybook_bible1" ); static const itype_id itype_indoor_volleyball( "indoor_volleyball" ); static const itype_id itype_jacket_leather( "jacket_leather" ); @@ -98,7 +96,6 @@ static const itype_id itype_landmine( "landmine" ); static const itype_id itype_machete( "machete" ); static const itype_id itype_material_sand( "material_sand" ); static const itype_id itype_material_soil( "material_soil" ); -static const itype_id itype_meth( "meth" ); static const itype_id itype_rag_bloody( "rag_bloody" ); static const itype_id itype_remington_870_breacher( "remington_870_breacher" ); static const itype_id itype_shot_hull( "shot_hull" ); @@ -113,7 +110,6 @@ static const itype_id itype_tux( "tux" ); static const itype_id itype_umbrella( "umbrella" ); static const itype_id itype_usp_45( "usp_45" ); static const itype_id itype_vodka( "vodka" ); -static const itype_id itype_weed( "weed" ); static const itype_id itype_wheel( "wheel" ); static const itype_id itype_withered( "withered" ); static const itype_id itype_wrench( "wrench" ); @@ -154,9 +150,7 @@ static const mtype_id mon_wolf( "mon_wolf" ); static const mtype_id mon_zombie_bio_op( "mon_zombie_bio_op" ); static const mtype_id mon_zombie_military_pilot( "mon_zombie_military_pilot" ); static const mtype_id mon_zombie_scientist( "mon_zombie_scientist" ); -static const mtype_id mon_zombie_smoker( "mon_zombie_smoker" ); static const mtype_id mon_zombie_soldier( "mon_zombie_soldier" ); -static const mtype_id mon_zombie_spitter( "mon_zombie_spitter" ); static const mtype_id mon_zombie_tough( "mon_zombie_tough" ); class npc_template; diff --git a/src/melee.cpp b/src/melee.cpp index 2466c12332a46..e09e46acdeb7f 100644 --- a/src/melee.cpp +++ b/src/melee.cpp @@ -85,7 +85,6 @@ static const skill_id skill_unarmed( "unarmed" ); static const skill_id skill_bashing( "bashing" ); static const skill_id skill_melee( "melee" ); -static const efftype_id effect_badpoison( "badpoison" ); static const efftype_id effect_beartrap( "beartrap" ); static const efftype_id effect_bouldering( "bouldering" ); static const efftype_id effect_contacts( "contacts" ); @@ -98,7 +97,6 @@ static const efftype_id effect_hit_by_player( "hit_by_player" ); static const efftype_id effect_incorporeal( "incorporeal" ); static const efftype_id effect_lightsnare( "lightsnare" ); static const efftype_id effect_narcosis( "narcosis" ); -static const efftype_id effect_poison( "poison" ); static const efftype_id effect_stunned( "stunned" ); static const efftype_id effect_venom_dmg( "venom_dmg" ); static const efftype_id effect_venom_weaken( "venom_weaken" ); diff --git a/src/suffer.cpp b/src/suffer.cpp index 10a7d2b3466ed..dcb0721b49e80 100644 --- a/src/suffer.cpp +++ b/src/suffer.cpp @@ -138,7 +138,6 @@ static const trait_id trait_RADIOACTIVE2( "RADIOACTIVE2" ); static const trait_id trait_RADIOACTIVE3( "RADIOACTIVE3" ); static const trait_id trait_RADIOGENIC( "RADIOGENIC" ); static const trait_id trait_REGEN_LIZ( "REGEN_LIZ" ); -static const trait_id trait_ROOTS3( "ROOTS3" ); static const trait_id trait_SCHIZOPHRENIC( "SCHIZOPHRENIC" ); static const trait_id trait_SHARKTEETH( "SHARKTEETH" ); static const trait_id trait_SHELL2( "SHELL2" ); @@ -162,8 +161,6 @@ static const mtype_id mon_zombie_fat( "mon_zombie_fat" ); static const mtype_id mon_zombie_fireman( "mon_zombie_fireman" ); static const mtype_id mon_zombie_soldier( "mon_zombie_soldier" ); -static const std::string flag_PLOWABLE( "PLOWABLE" ); - static const json_character_flag json_flag_GLARE_RESIST( "GLARE_RESIST" ); static float addiction_scaling( float at_min, float at_max, float add_lvl ) diff --git a/src/visitable.cpp b/src/visitable.cpp index f797bd3c6bef1..c4969073b901f 100644 --- a/src/visitable.cpp +++ b/src/visitable.cpp @@ -46,8 +46,6 @@ static const quality_id qual_BUTCHER( "BUTCHER" ); static const bionic_id bio_ups( "bio_ups" ); -static const json_character_flag json_flag_BIONIC_TOGGLED( "BIONIC_TOGGLED" ); - /** @relates visitable */ item *read_only_visitable::find_parent( const item &it ) const { diff --git a/tests/clzones_test.cpp b/tests/clzones_test.cpp index 9e8fd6cd9ba02..d88f26996784f 100644 --- a/tests/clzones_test.cpp +++ b/tests/clzones_test.cpp @@ -12,7 +12,6 @@ #include "ret_val.h" #include "type_id.h" -static const zone_type_id zone_type_LOOT_UNSORTED( "LOOT_UNSORTED" ); static const zone_type_id zone_type_LOOT_FOOD( "LOOT_FOOD" ); static const zone_type_id zone_type_LOOT_PFOOD( "LOOT_PFOOD" ); static const zone_type_id zone_type_LOOT_DRINK( "LOOT_DRINK" ); diff --git a/tests/vehicle_part_test.cpp b/tests/vehicle_part_test.cpp index 1cc0113dcd578..3c861c2c52d57 100644 --- a/tests/vehicle_part_test.cpp +++ b/tests/vehicle_part_test.cpp @@ -31,8 +31,8 @@ #include "vpart_position.h" #include "vpart_range.h" -static time_point midnight = calendar::turn_zero + 0_hours; -static time_point midday = calendar::turn_zero + 12_hours; +static time_point midnight = calendar::turn_zero; +static time_point midday = midnight + 12_hours; static void set_time( const time_point &time ) { diff --git a/tools/clang-tidy-plugin/CataTidyModule.cpp b/tools/clang-tidy-plugin/CataTidyModule.cpp index b8442e9344f3b..e72f158a7ec41 100644 --- a/tools/clang-tidy-plugin/CataTidyModule.cpp +++ b/tools/clang-tidy-plugin/CataTidyModule.cpp @@ -69,6 +69,7 @@ class CataModule : public ClangTidyModule } // namespace cata // Register the MiscTidyModule using this statically initialized variable. +// NOLINTNEXTLINE(cata-unused-statics) static ClangTidyModuleRegistry::Add X( "cata-module", "Adds Cataclysm-DDA checks." ); From 2ddee88f3fdb44339b140cb9a61145bc9c9f5dac Mon Sep 17 00:00:00 2001 From: John Bytheway Date: Fri, 30 Apr 2021 13:38:31 -0400 Subject: [PATCH 421/453] Check for unused static variables We have a lot of global static string_ids. We want to be able to detect when they are no longer used. This check tries to do this. --- tools/clang-tidy-plugin/CMakeLists.txt | 1 + tools/clang-tidy-plugin/CataTidyModule.cpp | 2 + .../clang-tidy-plugin/UnusedStaticsCheck.cpp | 82 +++++++++++++++++++ tools/clang-tidy-plugin/UnusedStaticsCheck.h | 36 ++++++++ .../clang-tidy-plugin/test/unused-statics.cpp | 31 +++++++ 5 files changed, 152 insertions(+) create mode 100644 tools/clang-tidy-plugin/UnusedStaticsCheck.cpp create mode 100644 tools/clang-tidy-plugin/UnusedStaticsCheck.h create mode 100644 tools/clang-tidy-plugin/test/unused-statics.cpp diff --git a/tools/clang-tidy-plugin/CMakeLists.txt b/tools/clang-tidy-plugin/CMakeLists.txt index 54064951c5d67..f7e804152cf0e 100644 --- a/tools/clang-tidy-plugin/CMakeLists.txt +++ b/tools/clang-tidy-plugin/CMakeLists.txt @@ -24,6 +24,7 @@ add_library(CataAnalyzerPlugin MODULE TextStyleCheck.cpp TranslatorCommentsCheck.cpp UnsequencedCallsCheck.cpp + UnusedStaticsCheck.cpp UseLocalizedSortingCheck.cpp UseNamedPointConstantsCheck.cpp UsePointApisCheck.cpp diff --git a/tools/clang-tidy-plugin/CataTidyModule.cpp b/tools/clang-tidy-plugin/CataTidyModule.cpp index e72f158a7ec41..8a28b0713e206 100644 --- a/tools/clang-tidy-plugin/CataTidyModule.cpp +++ b/tools/clang-tidy-plugin/CataTidyModule.cpp @@ -19,6 +19,7 @@ #include "TextStyleCheck.h" #include "TranslatorCommentsCheck.h" #include "UnsequencedCallsCheck.h" +#include "UnusedStaticsCheck.h" #include "UseLocalizedSortingCheck.h" #include "UseNamedPointConstantsCheck.h" #include "UsePointApisCheck.h" @@ -57,6 +58,7 @@ class CataModule : public ClangTidyModule CheckFactories.registerCheck( "cata-text-style" ); CheckFactories.registerCheck( "cata-translator-comments" ); CheckFactories.registerCheck( "cata-unsequenced-calls" ); + CheckFactories.registerCheck( "cata-unused-statics" ); CheckFactories.registerCheck( "cata-use-localized-sorting" ); CheckFactories.registerCheck( "cata-use-named-point-constants" ); diff --git a/tools/clang-tidy-plugin/UnusedStaticsCheck.cpp b/tools/clang-tidy-plugin/UnusedStaticsCheck.cpp new file mode 100644 index 0000000000000..c69b60ddf2ff2 --- /dev/null +++ b/tools/clang-tidy-plugin/UnusedStaticsCheck.cpp @@ -0,0 +1,82 @@ +#include "UnusedStaticsCheck.h" +#include "Utils.h" +#include + +using namespace clang::ast_matchers; + +namespace clang +{ +namespace tidy +{ +namespace cata +{ + +void UnusedStaticsCheck::registerMatchers( MatchFinder *Finder ) +{ + Finder->addMatcher( + varDecl( + anyOf( hasParent( namespaceDecl() ), hasParent( translationUnitDecl() ) ), + hasStaticStorageDuration() + ).bind( "decl" ), + this + ); + Finder->addMatcher( + declRefExpr( to( varDecl().bind( "decl" ) ) ).bind( "ref" ), + this + ); +} + +void UnusedStaticsCheck::check( const MatchFinder::MatchResult &Result ) +{ + const VarDecl *ThisDecl = Result.Nodes.getNodeAs( "decl" ); + if( !ThisDecl ) { + return; + } + + const DeclRefExpr *Ref = Result.Nodes.getNodeAs( "ref" ); + if( Ref ) { + used_decls_.insert( ThisDecl ); + } + + const SourceManager &SM = *Result.SourceManager; + + // Ignore cases in header files + if( !SM.isInMainFile( ThisDecl->getBeginLoc() ) ) { + return; + } + + // Ignore cases that are not the first declaration + if( ThisDecl->getPreviousDecl() ) { + return; + } + + // Ignore cases that are not static linkage + Linkage Lnk = ThisDecl->getFormalLinkage(); + if( Lnk != InternalLinkage && Lnk != UniqueExternalLinkage ) { + return; + } + + SourceLocation DeclLoc = ThisDecl->getBeginLoc(); + SourceLocation ExpansionLoc = SM.getFileLoc( DeclLoc ); + if( DeclLoc != ExpansionLoc ) { + // We are inside a macro expansion + return; + } + + decls_.push_back( ThisDecl ); +} + +void UnusedStaticsCheck::onEndOfTranslationUnit() +{ + for( const VarDecl *V : decls_ ) { + if( used_decls_.count( V ) ) { + continue; + } + + diag( V->getBeginLoc(), "Variable %0 declared but not used." ) << V; + } +} + +} // namespace cata +} // namespace tidy +} // namespace clang diff --git a/tools/clang-tidy-plugin/UnusedStaticsCheck.h b/tools/clang-tidy-plugin/UnusedStaticsCheck.h new file mode 100644 index 0000000000000..0711759ca9bea --- /dev/null +++ b/tools/clang-tidy-plugin/UnusedStaticsCheck.h @@ -0,0 +1,36 @@ +#ifndef CATA_TOOLS_CLANG_TIDY_PLUGIN_UNUSEDSTATICSCHECK_H +#define CATA_TOOLS_CLANG_TIDY_PLUGIN_UNUSEDSTATICSCHECK_H + +#include +#include + +#include "ClangTidy.h" + +namespace clang +{ + +namespace tidy +{ +class ClangTidyContext; + +namespace cata +{ + +class UnusedStaticsCheck : public ClangTidyCheck +{ + public: + UnusedStaticsCheck( StringRef Name, ClangTidyContext *Context ) + : ClangTidyCheck( Name, Context ) {} + void registerMatchers( ast_matchers::MatchFinder *Finder ) override; + void check( const ast_matchers::MatchFinder::MatchResult &Result ) override; + void onEndOfTranslationUnit() override; + private: + std::unordered_set used_decls_; + std::vector decls_; +}; + +} // namespace cata +} // namespace tidy +} // namespace clang + +#endif // CATA_TOOLS_CLANG_TIDY_PLUGIN_UNUSEDSTATICSCHECK_H diff --git a/tools/clang-tidy-plugin/test/unused-statics.cpp b/tools/clang-tidy-plugin/test/unused-statics.cpp new file mode 100644 index 0000000000000..e10370b7479c6 --- /dev/null +++ b/tools/clang-tidy-plugin/test/unused-statics.cpp @@ -0,0 +1,31 @@ +// RUN: %check_clang_tidy %s cata-unused-statics %t -- -plugins=%cata_plugin -- + +class A0 {}; + +static A0 a0; +// CHECK-MESSAGES: warning: Variable 'a0' declared but not used. [cata-unused-statics] + +namespace cata +{ + +class A1 {}; + +static A1 a1; +// CHECK-MESSAGES: warning: Variable 'a1' declared but not used. [cata-unused-statics] + +} + +namespace +{ + +class A2 {}; + +A2 a2; +// CHECK-MESSAGES: warning: Variable 'a2' declared but not used. [cata-unused-statics] + +} + +// No warnings inside macros +class A3 {}; +#define M3 static A3 a3; +M3 From e479617b75b67cbd88e95fad645cfa5737e63268 Mon Sep 17 00:00:00 2001 From: John Bytheway Date: Mon, 3 May 2021 07:41:49 -0400 Subject: [PATCH 422/453] Enable clang-tidy readability-isolate-declaration (#48629) * Enable clang-tidy readability-isolate-declaration Enable this clang-tidy check and apply the changes it suggests. Perform some minor refactoring on the result to move some declarations to first use. * Refactor some point code These changes were suggested by clang-tidy as a result of the earlier tweaks to isolate declarations. --- .clang-tidy | 1 - src/activity_item_handling.cpp | 6 ++-- src/advanced_inv.cpp | 6 ++-- src/armor_layers.cpp | 3 +- src/cata_tiles.cpp | 4 ++- src/character.cpp | 3 +- src/chkjson/chkjson.cpp | 3 +- src/colony.h | 3 +- src/computer_session.cpp | 4 +-- src/crafting_gui.cpp | 3 +- src/explosion.cpp | 6 ++-- src/iuse.cpp | 10 +++++-- src/lightmap.cpp | 3 +- src/list.h | 28 ++++++++++-------- src/main_menu.cpp | 6 ++-- src/map.h | 3 +- src/map_extras.cpp | 53 +++++++++++++++++++--------------- src/mapgen.cpp | 12 +++++--- src/mapgen_functions.cpp | 3 +- src/messages.cpp | 3 +- src/mission_ui.cpp | 3 +- src/mod_manager.cpp | 3 +- src/newcharacter.cpp | 14 ++++----- src/npcmove.cpp | 4 ++- src/ranged.cpp | 6 ++-- src/reachability_cache.cpp | 4 ++- src/savegame_json.cpp | 3 +- src/sdltiles.cpp | 3 +- src/simplexnoise.cpp | 44 +++++++++++++++++++++++----- src/veh_interact.cpp | 4 ++- src/vehicle.cpp | 6 ++-- src/vehicle_move.cpp | 15 ++++++---- src/worldfactory.cpp | 3 +- tests/colony_test.cpp | 12 ++++++-- tests/invlet_test.cpp | 4 +-- 35 files changed, 190 insertions(+), 101 deletions(-) diff --git a/.clang-tidy b/.clang-tidy index 9f3a11e18bec3..4f11f89b67c59 100644 --- a/.clang-tidy +++ b/.clang-tidy @@ -57,7 +57,6 @@ readability-*,\ -performance-unnecessary-value-param,\ -readability-else-after-return,\ -readability-implicit-bool-conversion,\ --readability-isolate-declaration,\ -readability-magic-numbers,\ -readability-named-parameter,\ " diff --git a/src/activity_item_handling.cpp b/src/activity_item_handling.cpp index 2bb06f1a65d59..c01a5269f0f46 100644 --- a/src/activity_item_handling.cpp +++ b/src/activity_item_handling.cpp @@ -1989,8 +1989,10 @@ void activity_on_turn_move_loot( player_activity &act, player &p ) // the boolean in this pair being true indicates the item is from a vehicle storage space auto items = std::vector>(); - vehicle *src_veh, *dest_veh; - int src_part, dest_part; + vehicle *src_veh; + vehicle *dest_veh; + int src_part; + int dest_part; //Check source for cargo part //map_stack and vehicle_stack are different types but inherit from item_stack diff --git a/src/advanced_inv.cpp b/src/advanced_inv.cpp index 559ec885ea010..13a3c66e58278 100644 --- a/src/advanced_inv.cpp +++ b/src/advanced_inv.cpp @@ -939,7 +939,8 @@ bool advanced_inventory::move_all_items() std::vector target_items; std::vector target_items_favorites; std::vector quantities; - item_stack::iterator stack_begin, stack_end; + item_stack::iterator stack_begin; + item_stack::iterator stack_end; if( panes[src].in_vehicle() ) { vehicle_stack targets = sarea.veh->get_items( sarea.vstor ); stack_begin = targets.begin(); @@ -1015,7 +1016,8 @@ bool advanced_inventory::move_all_items() std::vector quantities; - item_stack::iterator stack_begin, stack_end; + item_stack::iterator stack_begin; + item_stack::iterator stack_end; if( panes[src].in_vehicle() ) { vehicle_stack targets = sarea.veh->get_items( sarea.vstor ); stack_begin = targets.begin(); diff --git a/src/armor_layers.cpp b/src/armor_layers.cpp index 18a8611f5fa57..7883df1a5f18b 100644 --- a/src/armor_layers.cpp +++ b/src/armor_layers.cpp @@ -667,7 +667,8 @@ void player::sort_armor() } else if( rightListOffset + rightListLines > rightListSize ) { rightListOffset = rightListSize - rightListLines; } - int pos = 1, curr = 0; + int pos = 1; + int curr = 0; for( const bodypart_id &cover : rl ) { if( cover == bodypart_id( "bp_null" ) ) { continue; diff --git a/src/cata_tiles.cpp b/src/cata_tiles.cpp index 1355bec28a05d..5033e910bfda4 100644 --- a/src/cata_tiles.cpp +++ b/src/cata_tiles.cpp @@ -2010,7 +2010,9 @@ bool cata_tiles::draw_from_id_string( const std::string &id, TILE_CATEGORY categ }; // use a fair mix function to turn the "random" seed into a random int // taken from public domain code at http://burtleburtle.net/bob/c/lookup3.c 2015/12/11 - unsigned int a = seed, b = -seed, c = seed * seed; + unsigned int a = seed; + unsigned int b = -seed; + unsigned int c = seed * seed; c ^= b; c -= rot32( b, 14 ); a ^= c; diff --git a/src/character.cpp b/src/character.cpp index 1d59aeee1a82e..fee731b93ed91 100644 --- a/src/character.cpp +++ b/src/character.cpp @@ -10650,7 +10650,8 @@ void Character::apply_persistent_morale() } // Characters with higher tiers of Nomad suffer worse morale penalties, faster. int max_unhappiness; - float min_time, max_time; + float min_time; + float max_time; if( has_trait( trait_NOMAD ) ) { max_unhappiness = 20; min_time = to_moves( 12_hours ); diff --git a/src/chkjson/chkjson.cpp b/src/chkjson/chkjson.cpp index 278be0c4521f5..22639af3afe4c 100644 --- a/src/chkjson/chkjson.cpp +++ b/src/chkjson/chkjson.cpp @@ -32,7 +32,8 @@ static std::vector get_files_from_path( std::string extension, std: root_path = "."; } - std::stack directories, tempstack; + std::stack directories; + std::stack tempstack; directories.push( root_path ); std::string path; diff --git a/src/colony.h b/src/colony.h index 2717614e8efe2..f6dc265d7bfdc 100644 --- a/src/colony.h +++ b/src/colony.h @@ -3029,7 +3029,8 @@ class colony : private element_allocator_type using diff_type = typename iterator_type::difference_type; diff_type distance = 0; - iterator_type iterator1 = first, iterator2 = last; + iterator_type iterator1 = first; + iterator_type iterator2 = last; const bool swap = first > last; if( swap ) { // Less common case diff --git a/src/computer_session.cpp b/src/computer_session.cpp index 0aaf5995ed18d..0f0ddc253463d 100644 --- a/src/computer_session.cpp +++ b/src/computer_session.cpp @@ -780,8 +780,8 @@ void computer_session::action_repeater_mod() avatar &player_character = get_avatar(); if( player_character.has_amount( itype_radio_repeater_mod, 1 ) ) { for( mission *miss : player_character.get_active_missions() ) { - static const mission_type_id commo_3 = mission_type_id( "MISSION_OLD_GUARD_NEC_COMMO_3" ), - commo_4 = mission_type_id( "MISSION_OLD_GUARD_NEC_COMMO_4" ); + static const mission_type_id commo_3 = mission_type_id( "MISSION_OLD_GUARD_NEC_COMMO_3" ); + static const mission_type_id commo_4 = mission_type_id( "MISSION_OLD_GUARD_NEC_COMMO_4" ); if( miss->mission_id() == commo_3 || miss->mission_id() == commo_4 ) { miss->step_complete( 1 ); print_error( _( "Repeater mod installed…" ) ); diff --git a/src/crafting_gui.cpp b/src/crafting_gui.cpp index ec9a7fc52f1f5..a5629e5723052 100644 --- a/src/crafting_gui.cpp +++ b/src/crafting_gui.cpp @@ -535,7 +535,8 @@ const recipe *select_crafting_recipe( int &batch_size_out ) const int max_recipe_name_width = 27; cata::optional cursor_pos; - int recmin = 0, recmax = current.size(); + int recmin = 0; + int recmax = current.size(); if( recmax > dataLines ) { if( line <= recmin + dataHalfLines ) { for( int i = recmin; i < recmin + dataLines; ++i ) { diff --git a/src/explosion.cpp b/src/explosion.cpp index 1dd5b68ac9428..384d0553afca6 100644 --- a/src/explosion.cpp +++ b/src/explosion.cpp @@ -799,8 +799,10 @@ void resonance_cascade( const tripoint &p ) player_character.pos() ) ) ); player_character.add_effect( effect_teleglow, rng( minglow, maxglow ) * 100 ); } - int startx = ( p.x < 8 ? 0 : p.x - 8 ), endx = ( p.x + 8 >= SEEX * 3 ? SEEX * 3 - 1 : p.x + 8 ); - int starty = ( p.y < 8 ? 0 : p.y - 8 ), endy = ( p.y + 8 >= SEEY * 3 ? SEEY * 3 - 1 : p.y + 8 ); + int startx = ( p.x < 8 ? 0 : p.x - 8 ); + int endx = ( p.x + 8 >= SEEX * 3 ? SEEX * 3 - 1 : p.x + 8 ); + int starty = ( p.y < 8 ? 0 : p.y - 8 ); + int endy = ( p.y + 8 >= SEEY * 3 ? SEEY * 3 - 1 : p.y + 8 ); tripoint dest( startx, starty, p.z ); map &here = get_map(); for( int &i = dest.x; i <= endx; i++ ) { diff --git a/src/iuse.cpp b/src/iuse.cpp index 0cee62f9f03b2..465c9004b9ad8 100644 --- a/src/iuse.cpp +++ b/src/iuse.cpp @@ -7095,7 +7095,11 @@ static extended_photo_def photo_def_for_camera_point( const tripoint &aim_point, } if( guy || mon ) { - std::string figure_appearance, figure_name, pose, pronoun_sex, figure_effects; + std::string figure_appearance; + std::string figure_name; + std::string pose; + std::string pronoun_sex; + std::string figure_effects; Creature *creature; if( mon && mon->has_effect( effect_ridden ) ) { // only player can ride, see monexamine::mount_pet @@ -7168,8 +7172,8 @@ static extended_photo_def photo_def_for_camera_point( const tripoint &aim_point, std::string ter_name = colorized_ter_name_flags_at( aim_point, {}, {} ); const std::string field_desc = colorized_field_description_at( aim_point ); - bool found_vehicle_aim_point = here.veh_at( aim_point ).has_value(), - found_furniture_aim_point = !furn_desc.empty(); + bool found_vehicle_aim_point = here.veh_at( aim_point ).has_value(); + bool found_furniture_aim_point = !furn_desc.empty(); // colorized_feature_description_at do not update flag if no furniture found, so need to check again if( !found_furniture_aim_point ) { found_item_aim_point = !item.is_null(); diff --git a/src/lightmap.cpp b/src/lightmap.cpp index 13a73f439db0a..9c0de7c0b5aff 100644 --- a/src/lightmap.cpp +++ b/src/lightmap.cpp @@ -155,7 +155,8 @@ bool map::build_transparency_cache( const int zlev ) }; if( cur_submap->is_uniform ) { - float value, dummy; + float value; + float dummy; std::tie( value, dummy ) = calc_transp( sm_offset ); // if rebuild_all==true all values were already set to LIGHT_TRANSPARENCY_OPEN_AIR if( !rebuild_all || value != LIGHT_TRANSPARENCY_OPEN_AIR ) { diff --git a/src/list.h b/src/list.h index 4a8a5bdc690a1..8126a026c68b6 100644 --- a/src/list.h +++ b/src/list.h @@ -495,8 +495,9 @@ template = block_pointer ); @@ -510,8 +511,9 @@ template free_list_head == nullptr ) ? nullptr : - last_searched_group, closest_freelist_right = ( last_searched_group->free_list_head == nullptr ) ? - nullptr : last_searched_group; + last_searched_group; + group_pointer_type closest_freelist_right = ( last_searched_group->free_list_head == nullptr ) ? + nullptr : last_searched_group; while( true ) { if( right_not_beyond_back ) { @@ -653,10 +655,12 @@ template ( this ), static_cast( &source ), sizeof( group_vector ) ); std::memcpy( static_cast( &source ), static_cast( &temp ), sizeof( group_vector ) ); } else { - const group_pointer_type swap_last_endpoint_group = last_endpoint_group, - swap_block_pointer = block_pointer, swap_last_searched_group = last_searched_group; - const size_type swap_size = size, swap_element_capacity = element_allocator_pair.capacity, - swap_capacity = group_allocator_pair.capacity; + const group_pointer_type swap_last_endpoint_group = last_endpoint_group; + const group_pointer_type swap_block_pointer = block_pointer; + const group_pointer_type swap_last_searched_group = last_searched_group; + const size_type swap_size = size; + const size_type swap_element_capacity = element_allocator_pair.capacity; + const size_type swap_capacity = group_allocator_pair.capacity; last_endpoint_group = source.last_endpoint_group; block_pointer = source.block_pointer; @@ -2201,11 +2205,11 @@ template next, - current2 = source.begin_iterator.node_pointer->next; + node_pointer_type current1 = begin_iterator.node_pointer->next; + node_pointer_type current2 = source.begin_iterator.node_pointer->next; node_pointer_type previous = source.begin_iterator.node_pointer; - const node_pointer_type source_end = source.end_iterator.node_pointer, - this_end = end_iterator.node_pointer; + const node_pointer_type source_end = source.end_iterator.node_pointer; + const node_pointer_type this_end = end_iterator.node_pointer; begin_iterator.node_pointer->next = source.begin_iterator.node_pointer; source.begin_iterator.node_pointer->previous = begin_iterator.node_pointer; diff --git a/src/main_menu.cpp b/src/main_menu.cpp index 01e583dad960d..79a464c2eb188 100644 --- a/src/main_menu.cpp +++ b/src/main_menu.cpp @@ -1022,7 +1022,8 @@ bool main_menu::load_character_tab( bool transfer ) int line = menu_offset.y - 2 - i; std::string world_name = all_worldnames[i]; int savegames_count = world_generator->get_world( world_name )->world_saves.size(); - nc_color color1, color2; + nc_color color1; + nc_color color2; if( world_name == "TUTORIAL" || world_name == "DEFENSE" ) { color1 = c_light_cyan; color2 = h_light_cyan; @@ -1209,7 +1210,8 @@ void main_menu::world_tab() for( auto it = all_worldnames.begin(); it != all_worldnames.end(); ++it, i++ ) { int savegames_count = world_generator->get_world( *it )->world_saves.size(); int line = menu_offset.y - 2 - i; - nc_color color1, color2; + nc_color color1; + nc_color color2; if( *it == "TUTORIAL" || *it == "DEFENSE" ) { color1 = c_light_cyan; color2 = h_light_cyan; diff --git a/src/map.h b/src/map.h index c18cdbf887812..953bf435a1b17 100644 --- a/src/map.h +++ b/src/map.h @@ -328,7 +328,8 @@ class map return cache.r_hor_cache->has_potential_los( from.xy(), to.xy(), cache ) && cache.r_hor_cache->has_potential_los( to.xy(), from.xy(), cache ) ; } - tripoint upper, lower; + tripoint upper; + tripoint lower; std::tie( upper, lower ) = from.z > to.z ? std::make_pair( from, to ) : std::make_pair( to, from ); // z-bounds depend on the invariant that both points are inbounds and their z are different return get_cache( lower.z ).r_up_cache->has_potential_los( diff --git a/src/map_extras.cpp b/src/map_extras.cpp index c55ddea0ee287..4ba83bd8f6529 100644 --- a/src/map_extras.cpp +++ b/src/map_extras.cpp @@ -1048,7 +1048,6 @@ static bool mx_minefield( map &, const tripoint &abs_sub ) const int num_mines = rng( 6, 20 ); const std::string text = _( "DANGER! MINEFIELD!" ); - int x, y, x1, y1 = 0; bool did_something = false; @@ -1121,23 +1120,23 @@ static bool mx_minefield( map &, const tripoint &abs_sub ) //Spawn 6-20 mines in the lower submap. //Spawn ordinary mine on asphalt, otherwise spawn buried mine for( int i = 0; i < num_mines; i++ ) { - const int x = rng( 3, SEEX * 2 - 4 ), y = rng( SEEY, SEEY * 2 - 2 ); - if( m.has_flag( flag_DIGGABLE, point( x, y ) ) ) { - place_trap_if_clear( m, point( x, y ), tr_landmine_buried ); + const point p( rng( 3, SEEX * 2 - 4 ), rng( SEEY, SEEY * 2 - 2 ) ); + if( m.has_flag( flag_DIGGABLE, p ) ) { + place_trap_if_clear( m, p, tr_landmine_buried ); } else { - place_trap_if_clear( m, point( x, y ), tr_landmine ); + place_trap_if_clear( m, p, tr_landmine ); } } //Spawn 6-20 puddles of blood on tiles without mines for( int i = 0; i < num_mines; i++ ) { - const int x = rng( 3, SEEX * 2 - 4 ), y = rng( SEEY, SEEY * 2 - 2 ); - if( m.tr_at( { x, y, abs_sub.z } ).is_null() ) { - m.add_field( { x, y, abs_sub.z }, fd_blood, rng( 1, 3 ) ); + const point p2( rng( 3, SEEX * 2 - 4 ), rng( SEEY, SEEY * 2 - 2 ) ); + if( m.tr_at( { p2, abs_sub.z } ).is_null() ) { + m.add_field( { p2, abs_sub.z }, fd_blood, rng( 1, 3 ) ); //10% chance to spawn a corpse of dead people/zombie on a tile with blood if( one_in( 10 ) ) { - m.add_corpse( { x, y, abs_sub.z } ); - for( const auto &loc : m.points_in_radius( { x, y, abs_sub.z }, 1 ) ) { + m.add_corpse( { p2, abs_sub.z } ); + for( const auto &loc : m.points_in_radius( { p2, abs_sub.z }, 1 ) ) { //50% chance to spawn gibs in every tile around corpse in 1-tile radius if( one_in( 2 ) ) { m.add_field( { loc.xy(), abs_sub.z }, fd_gibs_flesh, rng( 1, 3 ) ); @@ -1148,8 +1147,8 @@ static bool mx_minefield( map &, const tripoint &abs_sub ) } //Set two warning signs on the last horizontal line of the submap - x = rng( 3, SEEX ); - x1 = rng( SEEX + 1, SEEX * 2 - 4 ); + const int x = rng( 3, SEEX ); + const int x1 = rng( SEEX + 1, SEEX * 2 - 4 ); m.furn_set( point( x, SEEY * 2 - 1 ), furn_str_id( "f_sign_warning" ) ); m.set_signage( tripoint( x, SEEY * 2 - 1, abs_sub.z ), text ); m.furn_set( point( x1, SEEY * 2 - 1 ), furn_str_id( "f_sign_warning" ) ); @@ -1224,7 +1223,8 @@ static bool mx_minefield( map &, const tripoint &abs_sub ) //Spawn 6-20 mines in the upper submap. //Spawn ordinary mine on asphalt, otherwise spawn buried mine for( int i = 0; i < num_mines; i++ ) { - const int x = rng( 3, SEEX * 2 - 4 ), y = rng( 1, SEEY ); + const int x = rng( 3, SEEX * 2 - 4 ); + const int y = rng( 1, SEEY ); if( m.has_flag( flag_DIGGABLE, point( x, y ) ) ) { place_trap_if_clear( m, point( x, y ), tr_landmine_buried ); } else { @@ -1234,7 +1234,8 @@ static bool mx_minefield( map &, const tripoint &abs_sub ) //Spawn 6-20 puddles of blood on tiles without mines for( int i = 0; i < num_mines; i++ ) { - const int x = rng( 3, SEEX * 2 - 4 ), y = rng( 1, SEEY ); + const int x = rng( 3, SEEX * 2 - 4 ); + const int y = rng( 1, SEEY ); if( m.tr_at( { x, y, abs_sub.z } ).is_null() ) { m.add_field( { x, y, abs_sub.z }, fd_blood, rng( 1, 3 ) ); //10% chance to spawn a corpse of dead people/zombie on a tile with blood @@ -1251,8 +1252,8 @@ static bool mx_minefield( map &, const tripoint &abs_sub ) } //Set two warning signs on the first horizontal line of the submap - x = rng( 3, SEEX ); - x1 = rng( SEEX + 1, SEEX * 2 - 4 ); + const int x = rng( 3, SEEX ); + const int x1 = rng( SEEX + 1, SEEX * 2 - 4 ); m.furn_set( point( x, 0 ), furn_str_id( "f_sign_warning" ) ); m.set_signage( tripoint( x, 0, abs_sub.z ), text ); m.furn_set( point( x1, 0 ), furn_str_id( "f_sign_warning" ) ); @@ -1371,7 +1372,8 @@ static bool mx_minefield( map &, const tripoint &abs_sub ) //Spawn 6-20 mines in the rightmost submap. //Spawn ordinary mine on asphalt, otherwise spawn buried mine for( int i = 0; i < num_mines; i++ ) { - const int x = rng( SEEX + 1, SEEX * 2 - 2 ), y = rng( 3, SEEY * 2 - 4 ); + const int x = rng( SEEX + 1, SEEX * 2 - 2 ); + const int y = rng( 3, SEEY * 2 - 4 ); if( m.has_flag( flag_DIGGABLE, point( x, y ) ) ) { place_trap_if_clear( m, point( x, y ), tr_landmine_buried ); } else { @@ -1381,7 +1383,8 @@ static bool mx_minefield( map &, const tripoint &abs_sub ) //Spawn 6-20 puddles of blood on tiles without mines for( int i = 0; i < num_mines; i++ ) { - const int x = rng( SEEX + 1, SEEX * 2 - 2 ), y = rng( 3, SEEY * 2 - 4 ); + const int x = rng( SEEX + 1, SEEX * 2 - 2 ); + const int y = rng( 3, SEEY * 2 - 4 ); if( m.tr_at( { x, y, abs_sub.z } ).is_null() ) { m.add_field( { x, y, abs_sub.z }, fd_blood, rng( 1, 3 ) ); //10% chance to spawn a corpse of dead people/zombie on a tile with blood @@ -1398,8 +1401,8 @@ static bool mx_minefield( map &, const tripoint &abs_sub ) } //Set two warning signs on the last vertical line of the submap - y = rng( 3, SEEY ); - y1 = rng( SEEY + 1, SEEY * 2 - 4 ); + const int y = rng( 3, SEEY ); + const int y1 = rng( SEEY + 1, SEEY * 2 - 4 ); m.furn_set( point( SEEX * 2 - 1, y ), furn_str_id( "f_sign_warning" ) ); m.set_signage( tripoint( SEEX * 2 - 1, y, abs_sub.z ), text ); m.furn_set( point( SEEX * 2 - 1, y1 ), furn_str_id( "f_sign_warning" ) ); @@ -1510,7 +1513,8 @@ static bool mx_minefield( map &, const tripoint &abs_sub ) //Spawn 6-20 mines in the leftmost submap. //Spawn ordinary mine on asphalt, otherwise spawn buried mine for( int i = 0; i < num_mines; i++ ) { - const int x = rng( 1, SEEX ), y = rng( 3, SEEY * 2 - 4 ); + const int x = rng( 1, SEEX ); + const int y = rng( 3, SEEY * 2 - 4 ); if( m.has_flag( flag_DIGGABLE, point( x, y ) ) ) { place_trap_if_clear( m, point( x, y ), tr_landmine_buried ); } else { @@ -1520,7 +1524,8 @@ static bool mx_minefield( map &, const tripoint &abs_sub ) //Spawn 6-20 puddles of blood on tiles without mines for( int i = 0; i < num_mines; i++ ) { - const int x = rng( 1, SEEX ), y = rng( 3, SEEY * 2 - 4 ); + const int x = rng( 1, SEEX ); + const int y = rng( 3, SEEY * 2 - 4 ); if( m.tr_at( { x, y, abs_sub.z } ).is_null() ) { m.add_field( { x, y, abs_sub.z }, fd_blood, rng( 1, 3 ) ); //10% chance to spawn a corpse of dead people/zombie on a tile with blood @@ -1537,8 +1542,8 @@ static bool mx_minefield( map &, const tripoint &abs_sub ) } //Set two warning signs on the first vertical line of the submap - y = rng( 3, SEEY ); - y1 = rng( SEEY + 1, SEEY * 2 - 4 ); + const int y = rng( 3, SEEY ); + const int y1 = rng( SEEY + 1, SEEY * 2 - 4 ); m.furn_set( point( 0, y ), furn_str_id( "f_sign_warning" ) ); m.set_signage( tripoint( 0, y, abs_sub.z ), text ); m.furn_set( point( 0, y1 ), furn_str_id( "f_sign_warning" ) ); diff --git a/src/mapgen.cpp b/src/mapgen.cpp index 12bf05145f44e..d6ebf48bb3446 100644 --- a/src/mapgen.cpp +++ b/src/mapgen.cpp @@ -4091,7 +4091,8 @@ void map::draw_temple( const mapgendata &dat ) square( this, t_rock, point( SEEX + 2, 0 ), point( EAST_EDGE, 1 ) ); square( this, t_rock, point( SEEX + 2, SEEY * 2 - 2 ), point( EAST_EDGE, SOUTH_EDGE ) ); square( this, t_rock, point( SEEX + 5, 2 ), point( EAST_EDGE, SEEY * 2 - 3 ) ); - int x = rng( SEEX - 1, SEEX + 2 ), y = 2; + int x = rng( SEEX - 1, SEEX + 2 ); + int y = 2; std::vector path; // Path, from end to start while( x < SEEX - 1 || x > SEEX + 2 || y < SEEY * 2 - 2 ) { static const std::vector terrains = { @@ -4239,8 +4240,10 @@ void map::draw_mine( mapgendata &dat ) point end_location( rng( SEEX + 1, SEEX * 2 - 7 ), rng( SEEY + 1, SEEY * 2 - 7 ) ); const int num = rng( 2, 4 ); for( int i = 0; i < num; i++ ) { - int lx1 = start_location.x + rng( -1, 1 ), lx2 = end_location.x + rng( -1, 1 ), - ly1 = start_location.y + rng( -1, 1 ), ly2 = end_location.y + rng( -1, 1 ); + int lx1 = start_location.x + rng( -1, 1 ); + int lx2 = end_location.x + rng( -1, 1 ); + int ly1 = start_location.y + rng( -1, 1 ); + int ly2 = end_location.y + rng( -1, 1 ); line( this, t_lava, point( lx1, ly1 ), point( lx2, ly2 ) ); } } @@ -4490,7 +4493,8 @@ void map::draw_mine( mapgendata &dat ) computer *tmpcomp = nullptr; switch( rn ) { case 1: { // Wyrms - const int x = rng( SEEX, SEEX + 1 ), y = rng( SEEY, SEEY + 1 ); + const int x = rng( SEEX, SEEX + 1 ); + const int y = rng( SEEY, SEEY + 1 ); ter_set( point( x, y ), t_pedestal_wyrm ); spawn_item( point( x, y ), "petrified_eye" ); } diff --git a/src/mapgen_functions.cpp b/src/mapgen_functions.cpp index c9e85d53f6142..b7034c9cd4c58 100644 --- a/src/mapgen_functions.cpp +++ b/src/mapgen_functions.cpp @@ -802,7 +802,8 @@ void mapgen_road( mapgendata &dat ) if( curvedir_nesw[dir] != 0 ) { for( int x = 1; x < 4; x++ ) { for( int y = 0; y < x; y++ ) { - int ty = y, tx = ( curvedir_nesw[dir] == -1 ? x : SEEX * 2 - 1 - x ); + int ty = y; + int tx = ( curvedir_nesw[dir] == -1 ? x : SEEX * 2 - 1 - x ); coord_rotate_cw( tx, ty, dir ); m->ter_set( point( tx, ty ), t_pavement ); } diff --git a/src/messages.cpp b/src/messages.cpp index b804c29fa2a27..848dacb0fefe0 100644 --- a/src/messages.cpp +++ b/src/messages.cpp @@ -572,7 +572,8 @@ void Messages::dialog::show() .apply( w ); // Range of window lines to print - size_t line_from = 0, line_to; + size_t line_from = 0; + size_t line_to; if( offset < folded_filtered.size() ) { line_to = std::min( max_lines, folded_filtered.size() - offset ); } else { diff --git a/src/mission_ui.cpp b/src/mission_ui.cpp index 908f52e52e3d3..e2729e8dd187e 100644 --- a/src/mission_ui.cpp +++ b/src/mission_ui.cpp @@ -70,7 +70,8 @@ void game::list_missions() }; draw_tabs( w_missions, tabs, tab ); draw_border_below_tabs( w_missions ); - int x1 = 2, x2 = 2; + int x1 = 2; + int x2 = 2; for( const std::pair &t : tabs ) { x2 = x1 + utf8_width( t.second ) + 1; if( t.first == tab ) { diff --git a/src/mod_manager.cpp b/src/mod_manager.cpp index 414d1607fa646..bfc3361287005 100644 --- a/src/mod_manager.cpp +++ b/src/mod_manager.cpp @@ -440,7 +440,8 @@ static inline bool compare_mod_by_name_and_category( const MOD_INFORMATION *cons void mod_manager::set_usable_mods() { - std::vector available_cores, available_supplementals; + std::vector available_cores; + std::vector available_supplementals; std::vector ordered_mods; std::vector mods; diff --git a/src/newcharacter.cpp b/src/newcharacter.cpp index b87e83453c0f2..5b96fdd1d3a19 100644 --- a/src/newcharacter.cpp +++ b/src/newcharacter.cpp @@ -1230,7 +1230,11 @@ tab_direction set_traits( avatar &u, points_left &points ) } for( int iCurrentPage = 0; iCurrentPage < 3; iCurrentPage++ ) { - nc_color col_on_act, col_off_act, col_on_pas, col_off_pas, hi_on, hi_off, col_tr; + nc_color col_on_act; + nc_color col_off_act; + nc_color col_on_pas; + nc_color col_off_pas; + nc_color col_tr; switch( iCurrentPage ) { case 0: col_on_act = COL_TR_GOOD_ON_ACT; @@ -1238,8 +1242,6 @@ tab_direction set_traits( avatar &u, points_left &points ) col_on_pas = COL_TR_GOOD_ON_PAS; col_off_pas = COL_TR_GOOD_OFF_PAS; col_tr = COL_TR_GOOD; - hi_on = hilite( col_on_act ); - hi_off = hilite( col_off_act ); break; case 1: col_on_act = COL_TR_BAD_ON_ACT; @@ -1247,8 +1249,6 @@ tab_direction set_traits( avatar &u, points_left &points ) col_on_pas = COL_TR_BAD_ON_PAS; col_off_pas = COL_TR_BAD_OFF_PAS; col_tr = COL_TR_BAD; - hi_on = hilite( col_on_act ); - hi_off = hilite( col_off_act ); break; default: col_on_act = COL_TR_NEUT_ON_ACT; @@ -1256,10 +1256,10 @@ tab_direction set_traits( avatar &u, points_left &points ) col_on_pas = COL_TR_NEUT_ON_PAS; col_off_pas = COL_TR_NEUT_OFF_PAS; col_tr = COL_TR_NEUT; - hi_on = hilite( col_on_act ); - hi_off = hilite( col_off_act ); break; } + nc_color hi_on = hilite( col_on_act ); + nc_color hi_off = hilite( col_off_act ); int &start = iStartPos[iCurrentPage]; int current = iCurrentLine[iCurrentPage]; diff --git a/src/npcmove.cpp b/src/npcmove.cpp index 03ea28a6a9eb2..a27cd05da9531 100644 --- a/src/npcmove.cpp +++ b/src/npcmove.cpp @@ -3123,7 +3123,9 @@ void npc::drop_items( const units::mass &drop_weight, const units::volume &drop_ units::mass weight_dropped = units::from_gram( 0 ); units::volume volume_dropped = units::from_liter( 0 ); - std::vector rWgt, rVol; // Weight/Volume to value ratios + // Weight/Volume to value ratios + std::vector rWgt; + std::vector rVol; // First fill our ratio vectors, so we know which things to drop first invslice slice = inv->slice(); diff --git a/src/ranged.cpp b/src/ranged.cpp index 9ee9d44b09a10..a3d9eaae8a7ba 100644 --- a/src/ranged.cpp +++ b/src/ranged.cpp @@ -1287,8 +1287,10 @@ static int print_ranged_chance( const player &p, const catacurses::window &w, in } std::string label_m = _( "Moves" ); - std::vector t_aims( 4 ), t_confidence( 20 ); - int aim_iter = 0, conf_iter = 0; + std::vector t_aims( 4 ); + std::vector t_confidence( 20 ); + int aim_iter = 0; + int conf_iter = 0; nc_color col = c_dark_gray; diff --git a/src/reachability_cache.cpp b/src/reachability_cache.cpp index adfdc1562ee03..db2d84aa165eb 100644 --- a/src/reachability_cache.cpp +++ b/src/reachability_cache.cpp @@ -60,7 +60,9 @@ void reachability_cache::rebuild( Q q, static_assert( MAPSIZE_X == SEEX * MAPSIZE, "reachability cache uses outdated map dimensions" ); // start is inclusive, end is exclusive (1 step outside of the range) - point dir, start, end; + point dir; + point start; + point end; if( q == Q::SW || q == Q::NW ) { std::tie( dir.x, start.x, end.x ) = std::make_tuple( 1, 0, MAPSIZE_X ); diff --git a/src/savegame_json.cpp b/src/savegame_json.cpp index fa9df07486e89..cb9e3871edfef 100644 --- a/src/savegame_json.cpp +++ b/src/savegame_json.cpp @@ -4288,7 +4288,8 @@ void submap::load( JsonIn &jsin, const std::string &member_name, int version ) int i = jsin.get_int(); int j = jsin.get_int(); const point p( i, j ); - std::string type, str; + std::string type; + std::string str; // Try to read as current format if( jsin.test_string() ) { type = jsin.get_string(); diff --git a/src/sdltiles.cpp b/src/sdltiles.cpp index e2139fce49573..6e57ba056dd8e 100644 --- a/src/sdltiles.cpp +++ b/src/sdltiles.cpp @@ -2904,7 +2904,8 @@ static void init_term_size_and_scaling_factor() if( scaling_factor > 1 ) { - int max_width, max_height; + int max_width; + int max_height; int current_display_id = std::stoi( get_option( "DISPLAY" ) ); SDL_DisplayMode current_display; diff --git a/src/simplexnoise.cpp b/src/simplexnoise.cpp index 0d3f05763f050..b0530f7df3d03 100644 --- a/src/simplexnoise.cpp +++ b/src/simplexnoise.cpp @@ -204,7 +204,10 @@ float raw_noise_2d( const float x, const float y ) // For the 2D case, the simplex shape is an equilateral triangle. // Determine which simplex we are in. - int i1, j1; // Offsets for second (middle) corner of simplex in (i,j) coordinates + + // Offsets for second (middle) corner of simplex in (i,j) coordinates + int i1; + int j1; if( x0 > y0 ) { i1 = 1; // lower triangle, XY order: (0,0)->(1,0)->(1,1) j1 = 0; @@ -261,7 +264,11 @@ float raw_noise_2d( const float x, const float y ) // 3D raw Simplex noise float raw_noise_3d( const float x, const float y, const float z ) { - float n0, n1, n2, n3; // Noise contributions from the four corners + // Noise contributions from the four corners + float n0; + float n1; + float n2; + float n3; // Skew the input space to determine which simplex cell we're in float F3 = 1.0f / 3.0f; @@ -281,8 +288,12 @@ float raw_noise_3d( const float x, const float y, const float z ) // For the 3D case, the simplex shape is a slightly irregular tetrahedron. // Determine which simplex we are in. - int i1, j1, k1; // Offsets for second corner of simplex in (i,j,k) coordinates - int i2, j2, k2; // Offsets for third corner of simplex in (i,j,k) coordinates + int i1; // Offsets for second corner of simplex in (i,j,k) coordinates + int j1; + int k1; + int i2; // Offsets for third corner of simplex in (i,j,k) coordinates + int j2; + int k2; if( x0 >= y0 ) { if( y0 >= z0 ) { @@ -399,7 +410,12 @@ float raw_noise_4d( const float x, const float y, const float z, const float w ) // The skewing and unskewing factors are hairy again for the 4D case static const float F4 = ( std::sqrt( 5.0f ) - 1.0f ) / 4.0f; static const float G4 = ( 5.0f - std::sqrt( 5.0f ) ) / 20.0f; - float n0, n1, n2, n3, n4; // Noise contributions from the five corners + // Noise contributions from the five corners + float n0; + float n1; + float n2; + float n3; + float n4; // Skew the (x,y,z,w) space to determine which cell of 24 simplices we're in float s = ( x + y + z + w ) * F4; // Factor for 4D skewing @@ -434,9 +450,21 @@ float raw_noise_4d( const float x, const float y, const float z, const float w ) int c6 = ( z0 > w0 ) ? 1 : 0; int c = c1 + c2 + c3 + c4 + c5 + c6; - int i1, j1, k1, l1; // The integer offsets for the second simplex corner - int i2, j2, k2, l2; // The integer offsets for the third simplex corner - int i3, j3, k3, l3; // The integer offsets for the fourth simplex corner + // The integer offsets for the second simplex corner + int i1; + int j1; + int k1; + int l1; + // The integer offsets for the third simplex corner + int i2; + int j2; + int k2; + int l2; + // The integer offsets for the fourth simplex corner + int i3; + int j3; + int k3; + int l3; // simplex[c] is a 4-vector with the numbers 0, 1, 2 and 3 in some order. // Many values of c will never occur, since e.g. x>y>z>w makes x vehicle::use_charges( const vpart_position &vp, const itype_id & const cata::optional cargo_vp = vp.part_with_feature( "CARGO", true ); const auto tool_wants_battery = []( const itype_id & type ) { - item tool( type, calendar::turn_zero ), mag( tool.magazine_default() ); + item tool( type, calendar::turn_zero ); + item mag( tool.magazine_default() ); mag.contents.clear_items(); return tool.contents.insert_item( mag, item_pocket::pocket_type::MAGAZINE_WELL ).success() && diff --git a/src/vehicle_move.cpp b/src/vehicle_move.cpp index 2ee74d0c56937..a1f8216389252 100644 --- a/src/vehicle_move.cpp +++ b/src/vehicle_move.cpp @@ -169,7 +169,8 @@ void vehicle::smart_controller_handle_turn( bool thrusting, return; } - int cur_battery_level, max_battery_level; + int cur_battery_level; + int max_battery_level; std::tie( cur_battery_level, max_battery_level ) = battery_power_level(); int battery_level_percent = max_battery_level == 0 ? 0 : cur_battery_level * 100 / max_battery_level; @@ -1640,7 +1641,8 @@ bool vehicle::allow_manual_turn_on_rails( units::angle &corrected_turn_dir ) con if( turn_dir != face.dir() ) { corrected_turn_dir = get_corrected_turn_dir( turn_dir, face.dir() ); - int wheels_on_rail, turning_wheels_that_are_one_axis; + int wheels_on_rail; + int turning_wheels_that_are_one_axis; precalculate_vehicle_turning( corrected_turn_dir, true, TFLAG_RAIL, wheels_on_rail, turning_wheels_that_are_one_axis ); if( is_wheel_state_correct_to_turn_on_rails( wheels_on_rail, rail_wheelcache.size(), @@ -1657,19 +1659,22 @@ bool vehicle::allow_auto_turn_on_rails( units::angle &corrected_turn_dir ) const // check if autoturn is possible if( turn_dir == face.dir() ) { // precalculate wheels for every direction - int straight_wheels_on_rail, straight_turning_wheels_that_are_one_axis; + int straight_wheels_on_rail; + int straight_turning_wheels_that_are_one_axis; precalculate_vehicle_turning( face.dir(), true, TFLAG_RAIL, straight_wheels_on_rail, straight_turning_wheels_that_are_one_axis ); units::angle left_turn_dir = get_corrected_turn_dir( face.dir() - 45_degrees, face.dir() ); - int leftturn_wheels_on_rail, leftturn_turning_wheels_that_are_one_axis; + int leftturn_wheels_on_rail; + int leftturn_turning_wheels_that_are_one_axis; precalculate_vehicle_turning( left_turn_dir, true, TFLAG_RAIL, leftturn_wheels_on_rail, leftturn_turning_wheels_that_are_one_axis ); units::angle right_turn_dir = get_corrected_turn_dir( face.dir() + 45_degrees, face.dir() ); - int rightturn_wheels_on_rail, rightturn_turning_wheels_that_are_one_axis; + int rightturn_wheels_on_rail; + int rightturn_turning_wheels_that_are_one_axis; precalculate_vehicle_turning( right_turn_dir, true, TFLAG_RAIL, rightturn_wheels_on_rail, rightturn_turning_wheels_that_are_one_axis ); diff --git a/src/worldfactory.cpp b/src/worldfactory.cpp index 7408d067f4074..d71f563488fca 100644 --- a/src/worldfactory.cpp +++ b/src/worldfactory.cpp @@ -415,7 +415,8 @@ WORLDPTR worldfactory::pick_world( bool show_prompt ) mapLines[3] = true; std::map > world_pages; - size_t sel = 0, selpage = 0; + size_t sel = 0; + size_t selpage = 0; catacurses::window w_worlds_border; catacurses::window w_worlds_tooltip; diff --git a/tests/colony_test.cpp b/tests/colony_test.cpp index f210cd7e1f36a..e88199b335765 100644 --- a/tests/colony_test.cpp +++ b/tests/colony_test.cpp @@ -638,7 +638,11 @@ TEST_CASE( "colony range erase", "[colony]" ) CHECK( count == 400 ); CHECK( test_colony.size() == 400 ); - unsigned int size, range1, range2, loop_count, internal_loop_count; + unsigned int size; + unsigned int range1; + unsigned int range2; + unsigned int loop_count; + unsigned int internal_loop_count; for( loop_count = 0; loop_count < 50; ++loop_count ) { test_colony.clear(); @@ -887,7 +891,8 @@ TEST_CASE( "colony perfect forwarding", "[colony]" ) TEST_CASE( "colony emplace", "[colony]" ) { cata::colony test_colony; - int sum1 = 0, sum2 = 0; + int sum1 = 0; + int sum2 = 0; for( int i = 0; i < 100; ++i ) { test_colony.emplace( i ); @@ -949,7 +954,8 @@ TEST_CASE( "colony group size and capacity", "[colony]" ) TEST_CASE( "colony splice", "[colony]" ) { - cata::colony test_colony_1, test_colony_2; + cata::colony test_colony_1; + cata::colony test_colony_2; SECTION( "small splice 1" ) { int i = 0; diff --git a/tests/invlet_test.cpp b/tests/invlet_test.cpp index be0fb49138c11..6b1eb49b3c1d8 100644 --- a/tests/invlet_test.cpp +++ b/tests/invlet_test.cpp @@ -513,8 +513,8 @@ static void invlet_test( player &dummy, const inventory_location from, const inv break; } - invlet_state final_first_invlet_state = check_invlet( dummy, *final_first, invlet ), - final_second_invlet_state = check_invlet( dummy, *final_second, invlet ); + invlet_state final_first_invlet_state = check_invlet( dummy, *final_first, invlet ); + invlet_state final_second_invlet_state = check_invlet( dummy, *final_second, invlet ); INFO( test_action_desc( action, from, to, first_invlet_state, second_invlet_state, expected_first_invlet_state, expected_second_invlet_state, final_first_invlet_state, From 4386c694779ffc8ef55ed51bfcc77f5bc766cb31 Mon Sep 17 00:00:00 2001 From: John Bytheway Date: Mon, 3 May 2021 07:42:57 -0400 Subject: [PATCH 423/453] New clang-tidy check for static int_ids (#48688) * Initial check for static int_ids int_ids with static storage duration are dangerous because they can start to refer to the wrong thing when game data reloads. This has caused problems in the past. Add a check for such variables, and some tests. * Remove some static int_ids Fix issues detected by new check by replacing some static int_ids with their respective string_ids. Some were just unused, so got deleted instead. Some cases suppressed, including the furniture and terrain ids, since they were the most numerous and widely used, so that seemed the riskiest change. --- src/editmap.cpp | 1 + src/field_type.h | 1 + src/map.cpp | 4 +- src/mapdata.cpp | 21 ----- src/mapdata.h | 2 + src/overmap.cpp | 19 ++-- tests/submap_load_test.cpp | 24 ++--- tools/clang-tidy-plugin/CMakeLists.txt | 1 + tools/clang-tidy-plugin/CataTidyModule.cpp | 3 + .../StaticIntIdConstantsCheck.cpp | 87 +++++++++++++++++++ .../StaticIntIdConstantsCheck.h | 32 +++++++ .../StaticStringIdConstantsCheck.cpp | 1 + .../test/static-int_id-constants.cpp | 50 +++++++++++ 13 files changed, 197 insertions(+), 49 deletions(-) create mode 100644 tools/clang-tidy-plugin/StaticIntIdConstantsCheck.cpp create mode 100644 tools/clang-tidy-plugin/StaticIntIdConstantsCheck.h create mode 100644 tools/clang-tidy-plugin/test/static-int_id-constants.cpp diff --git a/src/editmap.cpp b/src/editmap.cpp index 0c680f0513925..eeed0847399bc 100644 --- a/src/editmap.cpp +++ b/src/editmap.cpp @@ -62,6 +62,7 @@ static constexpr tripoint editmap_boundary_max( MAPSIZE_X, MAPSIZE_Y, OVERMAP_HE static constexpr half_open_cuboid editmap_boundaries( editmap_boundary_min, editmap_boundary_max ); +// NOLINTNEXTLINE(cata-static-int_id-constants) static const ter_id undefined_ter_id( -1 ); static std::vector fld_string( const std::string &str, int width ) diff --git a/src/field_type.h b/src/field_type.h index f0b82656dc2d9..4099cd26fe513 100644 --- a/src/field_type.h +++ b/src/field_type.h @@ -111,6 +111,7 @@ struct field_intensity_level { std::vector field_effects; }; +// NOLINTNEXTLINE(cata-static-int_id-constants) const field_type_id INVALID_FIELD_TYPE_ID = field_type_id( -1 ); extern const field_type_str_id fd_null; extern const field_type_str_id fd_fire; diff --git a/src/map.cpp b/src/map.cpp index 0f7c755afe4b3..dbc0a112b5fe1 100644 --- a/src/map.cpp +++ b/src/map.cpp @@ -6884,8 +6884,8 @@ static void generate_uniform( const tripoint &p, const ter_id &terrain_type ) void map::loadn( const tripoint &grid, const bool update_vehicles, bool _actualize ) { // Cache empty overmap types - static const oter_id rock( "empty_rock" ); - static const oter_id air( "open_air" ); + static const oter_str_id rock( "empty_rock" ); + static const oter_str_id air( "open_air" ); dbg( D_INFO ) << "map::loadn(game[" << g.get() << "], worldx[" << abs_sub.x << "], worldy[" << abs_sub.y << "], grid " << grid << ")"; diff --git a/src/mapdata.cpp b/src/mapdata.cpp index 1fc7f671b1cc4..5cbf6cb2731d0 100644 --- a/src/mapdata.cpp +++ b/src/mapdata.cpp @@ -656,8 +656,6 @@ ter_id t_null, t_railroad_track_on_tie, t_railroad_track_h_on_tie, t_railroad_track_v_on_tie, t_railroad_track_d_on_tie; -static ter_id t_nanofab, t_nanofab_body, t_wall_b, t_wall_g, t_wall_p, t_wall_r, t_wall_w; - // TODO: Put this crap into an inclusion, which should be generated automatically using JSON data void set_ter_ids() @@ -733,11 +731,6 @@ void set_ter_ids() t_reinforced_door_glass_o = ter_id( "t_reinforced_door_glass_o" ); t_bars = ter_id( "t_bars" ); t_reb_cage = ter_id( "t_reb_cage" ); - t_wall_b = ter_id( "t_wall_b" ); - t_wall_g = ter_id( "t_wall_g" ); - t_wall_p = ter_id( "t_wall_p" ); - t_wall_r = ter_id( "t_wall_r" ); - t_wall_w = ter_id( "t_wall_w" ); t_door_c = ter_id( "t_door_c" ); t_door_c_peep = ter_id( "t_door_c_peep" ); t_door_b = ter_id( "t_door_b" ); @@ -904,8 +897,6 @@ void set_ter_ids() t_rootcellar = ter_id( "t_rootcellar" ); t_cvdbody = ter_id( "t_cvdbody" ); t_cvdmachine = ter_id( "t_cvdmachine" ); - t_nanofab = ter_id( "t_nanofab" ); - t_nanofab_body = ter_id( "t_nanofab_body" ); t_stairs_down = ter_id( "t_stairs_down" ); t_stairs_up = ter_id( "t_stairs_up" ); t_manhole = ter_id( "t_manhole" ); @@ -1030,9 +1021,6 @@ furn_id f_null, f_sign, f_street_light, f_traffic_light; -static furn_id f_ball_mach, f_bluebell, f_dahlia, f_dandelion, f_datura, f_floor_canvas, - f_indoor_plant_y, f_lane, f_statue; - void set_furn_ids() { f_null = furn_id( "f_null" ); @@ -1046,7 +1034,6 @@ void set_furn_ids() f_sandbag_wall = furn_id( "f_sandbag_wall" ); f_bulletin = furn_id( "f_bulletin" ); f_indoor_plant = furn_id( "f_indoor_plant" ); - f_indoor_plant_y = furn_id( "f_indoor_plant_y" ); f_bed = furn_id( "f_bed" ); f_toilet = furn_id( "f_toilet" ); f_makeshift_bed = furn_id( "f_makeshift_bed" ); @@ -1063,9 +1050,7 @@ void set_furn_ids() f_trashcan = furn_id( "f_trashcan" ); f_desk = furn_id( "f_desk" ); f_exercise = furn_id( "f_exercise" ); - f_ball_mach = furn_id( "f_ball_mach" ); f_bench = furn_id( "f_bench" ); - f_lane = furn_id( "f_lane" ); f_table = furn_id( "f_table" ); f_pool_table = furn_id( "f_pool_table" ); f_counter = furn_id( "f_counter" ); @@ -1104,10 +1089,6 @@ void set_furn_ids() f_fungal_mass = furn_id( "f_fungal_mass" ); f_fungal_clump = furn_id( "f_fungal_clump" ); f_flower_fungal = furn_id( "f_flower_fungal" ); - f_bluebell = furn_id( "f_bluebell" ); - f_dahlia = furn_id( "f_dahlia" ); - f_datura = furn_id( "f_datura" ); - f_dandelion = furn_id( "f_dandelion" ); f_cattails = furn_id( "f_cattails" ); f_lilypad = furn_id( "f_lilypad" ); f_lotus = furn_id( "f_lotus" ); @@ -1122,13 +1103,11 @@ void set_furn_ids() f_fvat_full = furn_id( "f_fvat_full" ); f_wood_keg = furn_id( "f_wood_keg" ); f_standing_tank = furn_id( "f_standing_tank" ); - f_statue = furn_id( "f_statue" ); f_egg_sackbw = furn_id( "f_egg_sackbw" ); f_egg_sackcs = furn_id( "f_egg_sackcs" ); f_egg_sackws = furn_id( "f_egg_sackws" ); f_egg_sacke = furn_id( "f_egg_sacke" ); f_flower_marloss = furn_id( "f_flower_marloss" ); - f_floor_canvas = furn_id( "f_floor_canvas" ); f_kiln_empty = furn_id( "f_kiln_empty" ); f_kiln_full = furn_id( "f_kiln_full" ); f_kiln_metal_empty = furn_id( "f_kiln_metal_empty" ); diff --git a/src/mapdata.h b/src/mapdata.h index 6a20fc6f02f2c..5403eb2e69262 100644 --- a/src/mapdata.h +++ b/src/mapdata.h @@ -448,6 +448,7 @@ provided for terrains added by mods. A string equivalent is always present, i.e. t_basalt "t_basalt" */ +// NOLINTNEXTLINE(cata-static-int_id-constants) extern ter_id t_null, t_hole, // Real nothingness; makes you fall a z-level // Ground @@ -574,6 +575,7 @@ runtime index: furn_id furn_id refers to a position in the furnlist[] where the furn_t struct is stored. See note about ter_id above. */ +// NOLINTNEXTLINE(cata-static-int_id-constants) extern furn_id f_null, f_hay, f_cattails, f_lotus, f_lilypad, f_rubble, f_rubble_rock, f_wreckage, f_ash, diff --git a/src/overmap.cpp b/src/overmap.cpp index 4719edfc7f780..15e2d46006c5e 100644 --- a/src/overmap.cpp +++ b/src/overmap.cpp @@ -77,13 +77,11 @@ using oter_type_id = int_id; using oter_type_str_id = string_id; //////////////// -static oter_id ot_null, - ot_crater, - ot_field, - ot_forest, - ot_forest_thick, - ot_forest_water, - ot_river_center; +static oter_id ot_null; +static const oter_str_id ot_forest( "ot_forest" ); +static const oter_str_id ot_forest_thick( "ot_forest_thick" ); +static const oter_str_id ot_forest_water( "ot_forest_water" ); +static const oter_str_id ot_river_center( "ot_river_center" ); const oter_type_t oter_type_t::null_type{}; @@ -327,13 +325,6 @@ bool operator!=( const int_id &lhs, const char *rhs ) static void set_oter_ids() // FIXME: constify { ot_null = oter_str_id::NULL_ID(); - // NOT required. - ot_crater = oter_id( "crater" ); - ot_field = oter_id( "field" ); - ot_forest = oter_id( "forest" ); - ot_forest_thick = oter_id( "forest_thick" ); - ot_forest_water = oter_id( "forest_water" ); - ot_river_center = oter_id( "river_center" ); } std::string overmap_land_use_code::get_symbol() const diff --git a/tests/submap_load_test.cpp b/tests/submap_load_test.cpp index 5493f52efba1e..fd2f238484ee8 100644 --- a/tests/submap_load_test.cpp +++ b/tests/submap_load_test.cpp @@ -926,7 +926,7 @@ TEST_CASE( "submap_furniture_load", "[submap][load]" ) REQUIRE( furn_ne == f_bookcase ); REQUIRE( furn_sw == f_dresser ); REQUIRE( furn_se == f_crate_o ); - REQUIRE( furn_ra == STATIC( furn_id( "f_gas_tank" ) ) ); + REQUIRE( furn_ra == STATIC( furn_str_id( "f_gas_tank" ) ) ); // Also, check we have no other furniture for( int x = 0; x < SEEX; ++x ) { @@ -963,11 +963,11 @@ TEST_CASE( "submap_trap_load", "[submap][load]" ) INFO( string_format( "se: %s", trap_se.id().str() ) ); INFO( string_format( "ra: %s", trap_ra.id().str() ) ); // Require to prevent the lower CHECK from being spammy - REQUIRE( trap_nw == STATIC( trap_id( "tr_rollmat" ) ) ); - REQUIRE( trap_ne == STATIC( trap_id( "tr_bubblewrap" ) ) ); - REQUIRE( trap_sw == STATIC( trap_id( "tr_beartrap" ) ) ); - REQUIRE( trap_se == STATIC( trap_id( "tr_funnel" ) ) ); - REQUIRE( trap_ra == STATIC( trap_id( "tr_landmine" ) ) ); + REQUIRE( trap_nw == STATIC( trap_str_id( "tr_rollmat" ) ) ); + REQUIRE( trap_ne == STATIC( trap_str_id( "tr_bubblewrap" ) ) ); + REQUIRE( trap_sw == STATIC( trap_str_id( "tr_beartrap" ) ) ); + REQUIRE( trap_se == STATIC( trap_str_id( "tr_funnel" ) ) ); + REQUIRE( trap_ra == STATIC( trap_str_id( "tr_landmine" ) ) ); // Also, check we have no other traps for( int x = 0; x < SEEX; ++x ) { @@ -1113,12 +1113,12 @@ TEST_CASE( "submap_field_load", "[submap][load]" ) const field &field_sw = sm.get_field( corner_sw ); const field &field_se = sm.get_field( corner_se ); const field &field_ra = sm.get_field( random_pt ); - const field_entry *fd_nw = field_nw.find_field( STATIC( field_type_id( "fd_web" ) ) ); - const field_entry *fd_ne = field_ne.find_field( STATIC( field_type_id( "fd_laser" ) ) ); - const field_entry *fd_sw = field_sw.find_field( STATIC( field_type_id( "fd_electricity" ) ) ); - const field_entry *fd_se = field_se.find_field( STATIC( field_type_id( "fd_acid" ) ) ); - const field_entry *fd_ra = field_ra.find_field( STATIC( field_type_id( "fd_nuke_gas" ) ) ); - const field_entry *fd_ow = field_nw.find_field( STATIC( field_type_id( "fd_smoke" ) ) ); + const field_entry *fd_nw = field_nw.find_field( STATIC( field_type_str_id( "fd_web" ) ) ); + const field_entry *fd_ne = field_ne.find_field( STATIC( field_type_str_id( "fd_laser" ) ) ); + const field_entry *fd_sw = field_sw.find_field( STATIC( field_type_str_id( "fd_electricity" ) ) ); + const field_entry *fd_se = field_se.find_field( STATIC( field_type_str_id( "fd_acid" ) ) ); + const field_entry *fd_ra = field_ra.find_field( STATIC( field_type_str_id( "fd_nuke_gas" ) ) ); + const field_entry *fd_ow = field_nw.find_field( STATIC( field_type_str_id( "fd_smoke" ) ) ); // No nullptrs for me REQUIRE( fd_nw != nullptr ); REQUIRE( fd_ow != nullptr ); diff --git a/tools/clang-tidy-plugin/CMakeLists.txt b/tools/clang-tidy-plugin/CMakeLists.txt index f7e804152cf0e..cf0c237645db7 100644 --- a/tools/clang-tidy-plugin/CMakeLists.txt +++ b/tools/clang-tidy-plugin/CMakeLists.txt @@ -17,6 +17,7 @@ add_library(CataAnalyzerPlugin MODULE PointInitializationCheck.cpp SimplifyPointConstructorsCheck.cpp StaticDeclarationsCheck.cpp + StaticIntIdConstantsCheck.cpp StaticStringIdConstantsCheck.cpp StringLiteralIterator.cpp TestFilenameCheck.cpp diff --git a/tools/clang-tidy-plugin/CataTidyModule.cpp b/tools/clang-tidy-plugin/CataTidyModule.cpp index 8a28b0713e206..b7cb4df22c32c 100644 --- a/tools/clang-tidy-plugin/CataTidyModule.cpp +++ b/tools/clang-tidy-plugin/CataTidyModule.cpp @@ -13,6 +13,7 @@ #include "PointInitializationCheck.h" #include "SimplifyPointConstructorsCheck.h" #include "StaticDeclarationsCheck.h" +#include "StaticIntIdConstantsCheck.h" #include "StaticStringIdConstantsCheck.h" #include "TestFilenameCheck.h" #include "TestsMustRestoreGlobalStateCheck.h" @@ -50,6 +51,8 @@ class CataModule : public ClangTidyModule CheckFactories.registerCheck( "cata-simplify-point-constructors" ); CheckFactories.registerCheck( "cata-static-declarations" ); + CheckFactories.registerCheck( + "cata-static-int_id-constants" ); CheckFactories.registerCheck( "cata-static-string_id-constants" ); CheckFactories.registerCheck( "cata-test-filename" ); diff --git a/tools/clang-tidy-plugin/StaticIntIdConstantsCheck.cpp b/tools/clang-tidy-plugin/StaticIntIdConstantsCheck.cpp new file mode 100644 index 0000000000000..c7e54a18e1b57 --- /dev/null +++ b/tools/clang-tidy-plugin/StaticIntIdConstantsCheck.cpp @@ -0,0 +1,87 @@ +#include "StaticIntIdConstantsCheck.h" +#include "Utils.h" +#include + +using namespace clang::ast_matchers; + +namespace clang +{ +namespace tidy +{ +namespace cata +{ + +void StaticIntIdConstantsCheck::registerMatchers( MatchFinder *Finder ) +{ + Finder->addMatcher( + varDecl( + hasType( + namedDecl( + anyOf( + hasName( "int_id" ), + typedefNameDecl( + hasType( + hasCanonicalType( + hasDeclaration( namedDecl( hasName( "int_id" ) ) ) + ) + ) + ) + ) + ).bind( "typeDecl" ) + ) + ).bind( "varDecl" ), + this + ); +} + +static void CheckConstructor( StaticIntIdConstantsCheck &Check, + const MatchFinder::MatchResult &Result ) +{ + const VarDecl *IntIdVarDecl = Result.Nodes.getNodeAs( "varDecl" ); + const TypeDecl *IntIdTypeDecl = Result.Nodes.getNodeAs( "typeDecl" ); + if( !IntIdVarDecl || !IntIdTypeDecl ) { + return; + } + + StringRef VarName = IntIdVarDecl->getName(); + if( VarName.endswith( "null" ) || VarName.endswith( "NULL" ) ) { + // Null constants are OK because they probably don't vary + return; + } + + const VarDecl *PreviousDecl = dyn_cast_or_null( IntIdVarDecl->getPreviousDecl() ); + + if( PreviousDecl ) { + // Only complain about each variable once + return; + } + + std::string Adjective; + + if( IntIdVarDecl->hasGlobalStorage() ) { + Adjective = "Global"; + } + + if( IntIdVarDecl->isStaticDataMember() || IntIdVarDecl->isStaticLocal() ) { + Adjective = "Static"; + } + + if( Adjective.empty() ) { + return; + } + + Check.diag( + IntIdVarDecl->getBeginLoc(), + "%2 declaration of %0 is dangerous because %1 is a specialization of int_id and it " + "will not update automatically when game data changes. Consider switching to a string_id." + ) << IntIdVarDecl << IntIdTypeDecl << Adjective; +} + +void StaticIntIdConstantsCheck::check( const MatchFinder::MatchResult &Result ) +{ + CheckConstructor( *this, Result ); +} + +} // namespace cata +} // namespace tidy +} // namespace clang diff --git a/tools/clang-tidy-plugin/StaticIntIdConstantsCheck.h b/tools/clang-tidy-plugin/StaticIntIdConstantsCheck.h new file mode 100644 index 0000000000000..0a9ec7ad42ac4 --- /dev/null +++ b/tools/clang-tidy-plugin/StaticIntIdConstantsCheck.h @@ -0,0 +1,32 @@ +#ifndef CATA_TOOLS_CLANG_TIDY_PLUGIN_STATICINTIDCONSTANTSCHECK_H +#define CATA_TOOLS_CLANG_TIDY_PLUGIN_STATICINTIDCONSTANTSCHECK_H + +#include +#include + +#include "ClangTidy.h" + +namespace clang +{ + +namespace tidy +{ +class ClangTidyContext; + +namespace cata +{ + +class StaticIntIdConstantsCheck : public ClangTidyCheck +{ + public: + StaticIntIdConstantsCheck( StringRef Name, ClangTidyContext *Context ) + : ClangTidyCheck( Name, Context ) {} + void registerMatchers( ast_matchers::MatchFinder *Finder ) override; + void check( const ast_matchers::MatchFinder::MatchResult &Result ) override; +}; + +} // namespace cata +} // namespace tidy +} // namespace clang + +#endif // CATA_TOOLS_CLANG_TIDY_PLUGIN_STATICINTIDCONSTANTSCHECK_H diff --git a/tools/clang-tidy-plugin/StaticStringIdConstantsCheck.cpp b/tools/clang-tidy-plugin/StaticStringIdConstantsCheck.cpp index 7249cb0ac137b..a57bb6c145b68 100644 --- a/tools/clang-tidy-plugin/StaticStringIdConstantsCheck.cpp +++ b/tools/clang-tidy-plugin/StaticStringIdConstantsCheck.cpp @@ -68,6 +68,7 @@ static std::string GetPrefixFor( const CXXRecordDecl *Type ) { "mutation_branch", "trait_" }, { "mutation_category_trait", "mutation_category_" }, { "npc_class", "" }, + { "oter_t", "" }, { "quality", "qual_" }, { "Skill", "skill_" }, { "ter_t", "ter_" }, diff --git a/tools/clang-tidy-plugin/test/static-int_id-constants.cpp b/tools/clang-tidy-plugin/test/static-int_id-constants.cpp new file mode 100644 index 0000000000000..b6fc5530e313b --- /dev/null +++ b/tools/clang-tidy-plugin/test/static-int_id-constants.cpp @@ -0,0 +1,50 @@ +// RUN: %check_clang_tidy %s cata-static-int_id-constants %t -- -plugins=%cata_plugin -- -isystem %cata_include + +template +class int_id +{ + public: + int_id(); + explicit int_id( int ); +}; + +struct furn_t; +using furn_id = int_id; + +extern furn_id f_hay; +// CHECK-MESSAGES: warning: Global declaration of 'f_hay' is dangerous because 'furn_id' is a specialization of int_id and it will not update automatically when game data changes. Consider switching to a string_id. [cata-static-int_id-constants] + +// No warning for second decl os same variable. +furn_id f_hay; + +static int_id f_ball_mach; +// CHECK-MESSAGES: warning: Global declaration of 'f_ball_mach' is dangerous because 'int_id' is a specialization of int_id and it will not update automatically when game data changes. Consider switching to a string_id. [cata-static-int_id-constants] + +namespace foo +{ + +const furn_id f_dahlia; +// CHECK-MESSAGES: warning: Global declaration of 'f_dahlia' is dangerous because 'furn_id' is a specialization of int_id and it will not update automatically when game data changes. Consider switching to a string_id. [cata-static-int_id-constants] + +} // namespace foo + +class A +{ + static furn_id f_bluebell; + // CHECK-MESSAGES: warning: Static declaration of 'f_bluebell' is dangerous because 'furn_id' is a specialization of int_id and it will not update automatically when game data changes. Consider switching to a string_id. [cata-static-int_id-constants] + + // No warning for regular class data members + furn_id my_furn; +}; + +void f() +{ + static furn_id f_floor_canvas; + // CHECK-MESSAGES: warning: Static declaration of 'f_floor_canvas' is dangerous because 'furn_id' is a specialization of int_id and it will not update automatically when game data changes. Consider switching to a string_id. [cata-static-int_id-constants] + + // No warning for regular local variables + furn_id f; + + // No warning for other types + static int i; +} From 516b150841ee236ea36665f68194abf9ee41777a Mon Sep 17 00:00:00 2001 From: John Bytheway Date: Wed, 28 Apr 2021 08:53:32 -0400 Subject: [PATCH 424/453] Fix StringMaker ODR violations in tests Catch2 provides a customization point for converting our types to strings by specializing the StringMaker template. We have some specializations in stringmaker.h, but this feature was only working intermittently. I finally figured out that was due to an ODR violation. The test files that didn't include stringmaker.h were compiling a different specialization than the ones that did. Re-jig the test includes so that any file including catch.hpp also includes stringmaker.h, thereby ensuring that the custom specializations are used everywhere and there is no ODR violation. I achieved this by adding a new cata_catch.h header and making all existing headers include catch.hpp via the new header. --- tests/active_item_cache_test.cpp | 2 +- tests/active_item_test.cpp | 2 +- tests/activity_tracker_test.cpp | 2 +- tests/algo_test.cpp | 2 +- tests/ammo_set_test.cpp | 2 +- tests/ammo_test.cpp | 2 +- tests/archery_damage_test.cpp | 2 +- tests/assertion_helpers.h | 2 +- tests/battery_mod_test.cpp | 2 +- tests/behavior_test.cpp | 2 +- tests/bionics_test.cpp | 2 +- tests/calendar_test.cpp | 2 +- tests/cata_catch.h | 15 +++++++++++++++ tests/cata_generators.h | 2 +- tests/cata_utility_test.cpp | 2 +- tests/cata_variant_test.cpp | 2 +- tests/catacharset_test.cpp | 2 +- tests/char_biometrics_test.cpp | 2 +- tests/char_edible_rating_test.cpp | 2 +- tests/char_exposure_test.cpp | 2 +- tests/char_healing_test.cpp | 2 +- tests/char_sight_test.cpp | 2 +- tests/char_stamina_test.cpp | 2 +- tests/char_suffer_test.cpp | 2 +- tests/char_validity_check_test.cpp | 2 +- tests/clzones_test.cpp | 2 +- tests/colony_test.cpp | 2 +- tests/comestible_test.cpp | 2 +- tests/coordinate_test.cpp | 2 +- tests/crafting_test.cpp | 2 +- tests/creature_effect_test.cpp | 2 +- tests/creature_in_field_test.cpp | 2 +- tests/creature_test.cpp | 2 +- tests/effect_test.cpp | 2 +- tests/effective_dps_test.cpp | 2 +- tests/enchantments_test.cpp | 2 +- tests/encumbrance_test.cpp | 2 +- tests/event_test.cpp | 2 +- tests/explosion_balance_test.cpp | 2 +- tests/field_test.cpp | 2 +- tests/flat_set_test.cpp | 2 +- tests/focus_test.cpp | 2 +- tests/fold_string_test.cpp | 2 +- tests/food_fun_for_test.cpp | 2 +- tests/generic_factory_test.cpp | 2 +- tests/ground_destroy_test.cpp | 2 +- tests/hash_test.cpp | 2 +- tests/health_test.cpp | 2 +- tests/iexamine_test.cpp | 2 +- tests/invlet_test.cpp | 2 +- tests/item_contents_test.cpp | 2 +- tests/item_group_test.cpp | 2 +- tests/item_location_test.cpp | 2 +- tests/item_stackable_test.cpp | 2 +- tests/item_test.cpp | 2 +- tests/item_tname_test.cpp | 2 +- tests/item_type_name_test.cpp | 2 +- tests/iteminfo_test.cpp | 11 +++++------ tests/itemname_test.cpp | 2 +- tests/iuse_actor_test.cpp | 2 +- tests/iuse_test.cpp | 2 +- tests/json_test.cpp | 2 +- tests/line_test.cpp | 2 +- tests/list_test.cpp | 2 +- tests/magic_spell_effect_test.cpp | 2 +- tests/magic_spell_test.cpp | 2 +- tests/make_static_test.cpp | 2 +- tests/map_extra_test.cpp | 2 +- tests/map_iterator_test.cpp | 2 +- tests/map_memory_test.cpp | 2 +- tests/map_test.cpp | 2 +- tests/map_test_case.h | 2 +- tests/mapgen_function_test.cpp | 2 +- tests/math_functions_test.cpp | 2 +- tests/melee_dodge_hit_test.cpp | 2 +- tests/melee_test.cpp | 2 +- tests/memorial_test.cpp | 2 +- tests/modify_morale_test.cpp | 2 +- tests/mondefense_test.cpp | 2 +- tests/monfactions_test.cpp | 2 +- tests/monster_attack_test.cpp | 2 +- tests/monster_test.cpp | 2 +- tests/monster_vision_test.cpp | 2 +- tests/moon_test.cpp | 2 +- tests/morale_test.cpp | 2 +- tests/mutation_test.cpp | 2 +- tests/name_test.cpp | 2 +- tests/new_character_test.cpp | 3 +-- tests/npc_talk_test.cpp | 2 +- tests/npc_test.cpp | 2 +- tests/optional_test.cpp | 2 +- tests/overmap_noise_test.cpp | 2 +- tests/overmap_test.cpp | 2 +- tests/player_helpers.cpp | 2 +- tests/player_test.cpp | 2 +- tests/pocket_test.cpp | 2 +- tests/point_test.cpp | 2 +- tests/projectile_test.cpp | 2 +- tests/ranged_balance_test.cpp | 2 +- tests/reachability_cache_test.cpp | 2 +- tests/reading_test.cpp | 2 +- tests/recipe_test.cpp | 2 +- tests/reload_magazine_test.cpp | 2 +- tests/reload_option_test.cpp | 2 +- tests/reloading_test.cpp | 2 +- tests/requirements_test.cpp | 2 +- tests/rewrite_vsnprintf_test.cpp | 2 +- tests/rng_test.cpp | 2 +- tests/rot_test.cpp | 2 +- tests/safe_reference_test.cpp | 2 +- tests/shadowcasting_test.cpp | 2 +- tests/simple_pathfinding_test.cpp | 2 +- tests/stats_tracker_test.cpp | 2 +- tests/stomach_contents_test.cpp | 2 +- tests/string_formatter_test.cpp | 2 +- tests/string_ids_test.cpp | 2 +- tests/string_test.cpp | 2 +- tests/stringmaker.h | 2 +- tests/submap_load_test.cpp | 2 +- tests/submap_test.cpp | 2 +- tests/sun_test.cpp | 2 +- tests/temp_crafting_inv_test.cpp | 2 +- tests/temperature_test.cpp | 2 +- tests/test_main.cpp | 2 +- tests/test_statistics.h | 2 +- tests/text_snippets_test.cpp | 2 +- tests/throwing_test.cpp | 2 +- tests/translations_test.cpp | 2 +- tests/try_parse_integer_test.cpp | 2 +- tests/units_test.cpp | 2 +- tests/unseal_and_spill_test.cpp | 2 +- tests/value_ptr_test.cpp | 2 +- tests/vehicle_drag_test.cpp | 2 +- tests/vehicle_efficiency_test.cpp | 2 +- tests/vehicle_interact_test.cpp | 2 +- tests/vehicle_part_test.cpp | 2 +- tests/vehicle_power_test.cpp | 2 +- tests/vehicle_ramp_test.cpp | 2 +- tests/vehicle_split_test.cpp | 2 +- tests/vehicle_test.cpp | 2 +- tests/vehicle_turrets_test.cpp | 2 +- tests/vision_test.cpp | 2 +- tests/visitable_remove_test.cpp | 2 +- tests/visitable_test.cpp | 2 +- tests/weary_test.cpp | 2 +- tests/weather_test.cpp | 2 +- tests/wield_times_test.cpp | 2 +- 147 files changed, 165 insertions(+), 152 deletions(-) create mode 100644 tests/cata_catch.h diff --git a/tests/active_item_cache_test.cpp b/tests/active_item_cache_test.cpp index 8307cd1bc0d1f..a92816bc935dd 100644 --- a/tests/active_item_cache_test.cpp +++ b/tests/active_item_cache_test.cpp @@ -1,7 +1,7 @@ #include #include "calendar.h" -#include "catch/catch.hpp" +#include "cata_catch.h" #include "game_constants.h" #include "item.h" #include "map.h" diff --git a/tests/active_item_test.cpp b/tests/active_item_test.cpp index 5676d0f94d683..2a89e295f5097 100644 --- a/tests/active_item_test.cpp +++ b/tests/active_item_test.cpp @@ -3,7 +3,7 @@ #include "avatar.h" #include "calendar.h" -#include "catch/catch.hpp" +#include "cata_catch.h" #include "item.h" #include "map.h" #include "map_helpers.h" diff --git a/tests/activity_tracker_test.cpp b/tests/activity_tracker_test.cpp index e22e3a725daa5..3aeaf38ad981e 100644 --- a/tests/activity_tracker_test.cpp +++ b/tests/activity_tracker_test.cpp @@ -1,4 +1,4 @@ -#include "catch/catch.hpp" +#include "cata_catch.h" #include "activity_tracker.h" #include "calendar.h" diff --git a/tests/algo_test.cpp b/tests/algo_test.cpp index 73a7d42919d30..529955f1cb81b 100644 --- a/tests/algo_test.cpp +++ b/tests/algo_test.cpp @@ -1,6 +1,6 @@ #pragma GCC diagnostic ignored "-Wunused-macros" #define CATCH_CONFIG_ENABLE_PAIR_STRINGMAKER -#include "catch/catch.hpp" +#include "cata_catch.h" #include #include diff --git a/tests/ammo_set_test.cpp b/tests/ammo_set_test.cpp index b7958c2712706..84ce9572866ad 100644 --- a/tests/ammo_set_test.cpp +++ b/tests/ammo_set_test.cpp @@ -4,7 +4,7 @@ #include #include -#include "catch/catch.hpp" +#include "cata_catch.h" #include "debug.h" #include "item.h" #include "item_pocket.h" diff --git a/tests/ammo_test.cpp b/tests/ammo_test.cpp index d33472650edce..ba7544744dfb8 100644 --- a/tests/ammo_test.cpp +++ b/tests/ammo_test.cpp @@ -1,4 +1,4 @@ -#include "catch/catch.hpp" +#include "cata_catch.h" #include diff --git a/tests/archery_damage_test.cpp b/tests/archery_damage_test.cpp index 78f8a1d0cd2cf..34ee5ceeec6ba 100644 --- a/tests/archery_damage_test.cpp +++ b/tests/archery_damage_test.cpp @@ -16,7 +16,7 @@ #include #include -#include "catch/catch.hpp" +#include "cata_catch.h" #include "damage.h" #include "game_constants.h" #include "item.h" diff --git a/tests/assertion_helpers.h b/tests/assertion_helpers.h index b35d54f1bf433..f8cc5358a8187 100644 --- a/tests/assertion_helpers.h +++ b/tests/assertion_helpers.h @@ -2,7 +2,7 @@ #ifndef CATA_TESTS_ASSERTION_HELPERS_H #define CATA_TESTS_ASSERTION_HELPERS_H -#include "catch/catch.hpp" +#include "cata_catch.h" #include diff --git a/tests/battery_mod_test.cpp b/tests/battery_mod_test.cpp index 19c6f0d93eef6..62054945f75d6 100644 --- a/tests/battery_mod_test.cpp +++ b/tests/battery_mod_test.cpp @@ -7,7 +7,7 @@ #include #include "avatar.h" -#include "catch/catch.hpp" +#include "cata_catch.h" #include "debug.h" #include "item.h" #include "item_contents.h" diff --git a/tests/behavior_test.cpp b/tests/behavior_test.cpp index 145abed552152..b458c5ceb8385 100644 --- a/tests/behavior_test.cpp +++ b/tests/behavior_test.cpp @@ -6,7 +6,7 @@ #include "behavior.h" #include "behavior_strategy.h" -#include "catch/catch.hpp" +#include "cata_catch.h" #include "character_oracle.h" #include "item.h" #include "item_location.h" diff --git a/tests/bionics_test.cpp b/tests/bionics_test.cpp index 3474dd778715c..28f12d95e495b 100644 --- a/tests/bionics_test.cpp +++ b/tests/bionics_test.cpp @@ -7,7 +7,7 @@ #include "avatar.h" #include "bionics.h" #include "calendar.h" -#include "catch/catch.hpp" +#include "cata_catch.h" #include "item.h" #include "item_pocket.h" #include "npc.h" diff --git a/tests/calendar_test.cpp b/tests/calendar_test.cpp index 7ca3c60cbbb9d..925b3fe123c4a 100644 --- a/tests/calendar_test.cpp +++ b/tests/calendar_test.cpp @@ -2,7 +2,7 @@ #include #include "calendar.h" -#include "catch/catch.hpp" +#include "cata_catch.h" TEST_CASE( "time_duration_to_string", "[calendar]" ) { diff --git a/tests/cata_catch.h b/tests/cata_catch.h new file mode 100644 index 0000000000000..f03278aead309 --- /dev/null +++ b/tests/cata_catch.h @@ -0,0 +1,15 @@ +#pragma once +#ifndef CATA_TESTS_CATA_CATCH_H +#define CATA_TESTS_CATA_CATCH_H + +// To avoid ODR violations, it's important that whenever a file includes +// catch.hpp it also includes stringmaker.h, so that all specializations of +// StringMaker match. Therefore, all test code should include catch.hpp via +// this file. + +// IWYU pragma: begin_exports +#include "catch/catch.hpp" +#include "stringmaker.h" +// IWYU pragma: end_exports + +#endif // CATA_TESTS_CATA_CATCH_H diff --git a/tests/cata_generators.h b/tests/cata_generators.h index 85dbc1c6a0e9f..e6009f863ab90 100644 --- a/tests/cata_generators.h +++ b/tests/cata_generators.h @@ -4,7 +4,7 @@ // Some Catch2 Generators for generating our data types -#include "catch/catch.hpp" +#include "cata_catch.h" #include "game_constants.h" struct point; diff --git a/tests/cata_utility_test.cpp b/tests/cata_utility_test.cpp index bccb6b4c2bad0..50a32cb6fa466 100644 --- a/tests/cata_utility_test.cpp +++ b/tests/cata_utility_test.cpp @@ -9,7 +9,7 @@ #include "assertion_helpers.h" #include "cata_utility.h" -#include "catch/catch.hpp" +#include "cata_catch.h" #include "debug_menu.h" #include "units.h" #include "units_utility.h" diff --git a/tests/cata_variant_test.cpp b/tests/cata_variant_test.cpp index cf7ec3673d9d9..dc2637d3cdae5 100644 --- a/tests/cata_variant_test.cpp +++ b/tests/cata_variant_test.cpp @@ -3,7 +3,7 @@ #include #include "cata_variant.h" -#include "catch/catch.hpp" +#include "cata_catch.h" #include "character_id.h" #include "debug_menu.h" #include "enum_conversions.h" diff --git a/tests/catacharset_test.cpp b/tests/catacharset_test.cpp index 76c10fe23fba3..77545b40a581f 100644 --- a/tests/catacharset_test.cpp +++ b/tests/catacharset_test.cpp @@ -8,7 +8,7 @@ #include #include "catacharset.h" -#include "catch/catch.hpp" +#include "cata_catch.h" #include "translations.h" TEST_CASE( "utf8_width", "[catacharset]" ) diff --git a/tests/char_biometrics_test.cpp b/tests/char_biometrics_test.cpp index 5e9a395d91658..80625e3740036 100644 --- a/tests/char_biometrics_test.cpp +++ b/tests/char_biometrics_test.cpp @@ -4,7 +4,7 @@ #include "avatar.h" #include "calendar.h" -#include "catch/catch.hpp" +#include "cata_catch.h" #include "creature.h" #include "game_constants.h" #include "options.h" diff --git a/tests/char_edible_rating_test.cpp b/tests/char_edible_rating_test.cpp index 37cb87cea01f9..93d9e6594b0bb 100644 --- a/tests/char_edible_rating_test.cpp +++ b/tests/char_edible_rating_test.cpp @@ -4,7 +4,7 @@ #include "avatar.h" #include "calendar.h" -#include "catch/catch.hpp" +#include "cata_catch.h" #include "character.h" #include "flag.h" #include "item.h" diff --git a/tests/char_exposure_test.cpp b/tests/char_exposure_test.cpp index ce631de3dc86c..7e41c320379c2 100644 --- a/tests/char_exposure_test.cpp +++ b/tests/char_exposure_test.cpp @@ -2,7 +2,7 @@ #include #include -#include "catch/catch.hpp" +#include "cata_catch.h" #include "character.h" #include "item.h" #include "player_helpers.h" diff --git a/tests/char_healing_test.cpp b/tests/char_healing_test.cpp index d48aa99681517..98be7bd3b2f5d 100644 --- a/tests/char_healing_test.cpp +++ b/tests/char_healing_test.cpp @@ -2,7 +2,7 @@ #include "avatar.h" #include "calendar.h" -#include "catch/catch.hpp" +#include "cata_catch.h" #include "character.h" #include "options.h" #include "player.h" diff --git a/tests/char_sight_test.cpp b/tests/char_sight_test.cpp index 9f1e80477fa82..fe788b1bec57e 100644 --- a/tests/char_sight_test.cpp +++ b/tests/char_sight_test.cpp @@ -2,7 +2,7 @@ #include #include "calendar.h" -#include "catch/catch.hpp" +#include "cata_catch.h" #include "character.h" #include "flag.h" #include "game.h" diff --git a/tests/char_stamina_test.cpp b/tests/char_stamina_test.cpp index 62be669f530dc..b561e14d4f6a1 100644 --- a/tests/char_stamina_test.cpp +++ b/tests/char_stamina_test.cpp @@ -1,4 +1,4 @@ -#include "catch/catch.hpp" +#include "cata_catch.h" #include "calendar.h" #include "character.h" diff --git a/tests/char_suffer_test.cpp b/tests/char_suffer_test.cpp index 57bdadb2053e3..ceba9cc43c70d 100644 --- a/tests/char_suffer_test.cpp +++ b/tests/char_suffer_test.cpp @@ -7,7 +7,7 @@ #include "avatar.h" #include "calendar.h" -#include "catch/catch.hpp" +#include "cata_catch.h" #include "character.h" #include "creature.h" #include "flag.h" diff --git a/tests/char_validity_check_test.cpp b/tests/char_validity_check_test.cpp index e8b63149ffe1f..77425e53ab188 100644 --- a/tests/char_validity_check_test.cpp +++ b/tests/char_validity_check_test.cpp @@ -1,4 +1,4 @@ -#include "catch/catch.hpp" +#include "cata_catch.h" #include "char_validity_check.h" TEST_CASE( "char_validity_check" ) diff --git a/tests/clzones_test.cpp b/tests/clzones_test.cpp index d88f26996784f..ba98117dace0d 100644 --- a/tests/clzones_test.cpp +++ b/tests/clzones_test.cpp @@ -1,7 +1,7 @@ #include #include -#include "catch/catch.hpp" +#include "cata_catch.h" #include "clzones.h" #include "item.h" #include "item_category.h" diff --git a/tests/colony_test.cpp b/tests/colony_test.cpp index e88199b335765..c859a81cfbc86 100644 --- a/tests/colony_test.cpp +++ b/tests/colony_test.cpp @@ -4,7 +4,7 @@ #include #include // range-insert testing -#include "catch/catch.hpp" +#include "cata_catch.h" #include "colony.h" #include "colony_list_test_helpers.h" diff --git a/tests/comestible_test.cpp b/tests/comestible_test.cpp index c00c217ba7f4c..1975c0e40b3a8 100644 --- a/tests/comestible_test.cpp +++ b/tests/comestible_test.cpp @@ -8,7 +8,7 @@ #include #include -#include "catch/catch.hpp" +#include "cata_catch.h" #include "character.h" #include "item.h" #include "item_contents.h" diff --git a/tests/coordinate_test.cpp b/tests/coordinate_test.cpp index 80f1f1220579c..774fb7db8076f 100644 --- a/tests/coordinate_test.cpp +++ b/tests/coordinate_test.cpp @@ -4,7 +4,7 @@ #include #include "cata_generators.h" -#include "catch/catch.hpp" +#include "cata_catch.h" #include "coordinate_conversions.h" #include "coordinates.h" #include "point.h" diff --git a/tests/crafting_test.cpp b/tests/crafting_test.cpp index 6e99dfcb60459..01eebfe24c53f 100644 --- a/tests/crafting_test.cpp +++ b/tests/crafting_test.cpp @@ -14,7 +14,7 @@ #include "avatar.h" #include "calendar.h" #include "cata_utility.h" -#include "catch/catch.hpp" +#include "cata_catch.h" #include "character.h" #include "game.h" #include "inventory.h" diff --git a/tests/creature_effect_test.cpp b/tests/creature_effect_test.cpp index 7b148b626e6d5..fa15b090bec9f 100644 --- a/tests/creature_effect_test.cpp +++ b/tests/creature_effect_test.cpp @@ -1,6 +1,6 @@ #include "avatar.h" #include "calendar.h" -#include "catch/catch.hpp" +#include "cata_catch.h" #include "monster.h" #include "mtype.h" #include "type_id.h" diff --git a/tests/creature_in_field_test.cpp b/tests/creature_in_field_test.cpp index 9838043d8d7a1..8bec189edfdee 100644 --- a/tests/creature_in_field_test.cpp +++ b/tests/creature_in_field_test.cpp @@ -1,4 +1,4 @@ -#include "catch/catch.hpp" +#include "cata_catch.h" #include "map.h" #include "map_helpers.h" #include "monster.h" diff --git a/tests/creature_test.cpp b/tests/creature_test.cpp index 8e37b9d108077..f8a7ffb2765da 100644 --- a/tests/creature_test.cpp +++ b/tests/creature_test.cpp @@ -3,7 +3,7 @@ #include #include "bodypart.h" -#include "catch/catch.hpp" +#include "cata_catch.h" #include "character.h" #include "creature.h" #include "enum_traits.h" diff --git a/tests/effect_test.cpp b/tests/effect_test.cpp index d0f691b89cc93..56f448e0a5990 100644 --- a/tests/effect_test.cpp +++ b/tests/effect_test.cpp @@ -4,7 +4,7 @@ #include #include "calendar.h" -#include "catch/catch.hpp" +#include "cata_catch.h" #include "character.h" #include "character_id.h" #include "damage.h" diff --git a/tests/effective_dps_test.cpp b/tests/effective_dps_test.cpp index 7c263f5bbf4e2..b1de9b8d8bf54 100644 --- a/tests/effective_dps_test.cpp +++ b/tests/effective_dps_test.cpp @@ -3,7 +3,7 @@ #include #include "avatar.h" -#include "catch/catch.hpp" +#include "cata_catch.h" #include "item.h" #include "melee.h" #include "monster.h" diff --git a/tests/enchantments_test.cpp b/tests/enchantments_test.cpp index e25833385fda0..e1e983347f6f0 100644 --- a/tests/enchantments_test.cpp +++ b/tests/enchantments_test.cpp @@ -1,5 +1,5 @@ #include "avatar.h" -#include "catch/catch.hpp" +#include "cata_catch.h" #include "field.h" #include "item.h" #include "item_location.h" diff --git a/tests/encumbrance_test.cpp b/tests/encumbrance_test.cpp index 61eec9fbab457..97d4c74d7b74e 100644 --- a/tests/encumbrance_test.cpp +++ b/tests/encumbrance_test.cpp @@ -5,7 +5,7 @@ #include #include "bodypart.h" -#include "catch/catch.hpp" +#include "cata_catch.h" #include "character.h" #include "item.h" #include "npc.h" diff --git a/tests/event_test.cpp b/tests/event_test.cpp index bc96b9f9057aa..2480ea3536b23 100644 --- a/tests/event_test.cpp +++ b/tests/event_test.cpp @@ -3,7 +3,7 @@ #include "calendar.h" #include "cata_variant.h" -#include "catch/catch.hpp" +#include "cata_catch.h" #include "character_id.h" #include "event.h" #include "event_bus.h" diff --git a/tests/explosion_balance_test.cpp b/tests/explosion_balance_test.cpp index a95c167f7f21e..d57cfd1ac3972 100644 --- a/tests/explosion_balance_test.cpp +++ b/tests/explosion_balance_test.cpp @@ -5,7 +5,7 @@ #include #include "avatar.h" -#include "catch/catch.hpp" +#include "cata_catch.h" #include "creature.h" #include "explosion.h" #include "game.h" diff --git a/tests/field_test.cpp b/tests/field_test.cpp index 61f5ee0ab0d04..f2050c4781796 100644 --- a/tests/field_test.cpp +++ b/tests/field_test.cpp @@ -3,7 +3,7 @@ #include "avatar.h" #include "calendar.h" -#include "catch/catch.hpp" +#include "cata_catch.h" #include "field.h" #include "field_type.h" #include "item.h" diff --git a/tests/flat_set_test.cpp b/tests/flat_set_test.cpp index d1c05285f11c0..e5fd16cebda3f 100644 --- a/tests/flat_set_test.cpp +++ b/tests/flat_set_test.cpp @@ -5,7 +5,7 @@ #include #include "assertion_helpers.h" -#include "catch/catch.hpp" +#include "cata_catch.h" #include "flat_set.h" #if 0 diff --git a/tests/focus_test.cpp b/tests/focus_test.cpp index 1f8d76e9d979b..d1f50cacca873 100644 --- a/tests/focus_test.cpp +++ b/tests/focus_test.cpp @@ -1,7 +1,7 @@ #include #include "avatar.h" -#include "catch/catch.hpp" +#include "cata_catch.h" #include "player_helpers.h" #include "skill.h" #include "type_id.h" diff --git a/tests/fold_string_test.cpp b/tests/fold_string_test.cpp index 3ec6dedceb897..35cd74cca7b48 100644 --- a/tests/fold_string_test.cpp +++ b/tests/fold_string_test.cpp @@ -1,4 +1,4 @@ -#include "catch/catch.hpp" +#include "cata_catch.h" #include #include diff --git a/tests/food_fun_for_test.cpp b/tests/food_fun_for_test.cpp index 9a8b861cb8926..740163f4dc7cb 100644 --- a/tests/food_fun_for_test.cpp +++ b/tests/food_fun_for_test.cpp @@ -4,7 +4,7 @@ #include "avatar.h" #include "calendar.h" -#include "catch/catch.hpp" +#include "cata_catch.h" #include "flag.h" #include "item.h" #include "itype.h" diff --git a/tests/generic_factory_test.cpp b/tests/generic_factory_test.cpp index 711668efe3f6d..321d3f2285f74 100644 --- a/tests/generic_factory_test.cpp +++ b/tests/generic_factory_test.cpp @@ -6,7 +6,7 @@ #include #include -#include "catch/catch.hpp" +#include "cata_catch.h" #include "colony_list_test_helpers.h" #include "flat_set.h" #include "generic_factory.h" diff --git a/tests/ground_destroy_test.cpp b/tests/ground_destroy_test.cpp index d00b0b88af5f8..52d922eba3236 100644 --- a/tests/ground_destroy_test.cpp +++ b/tests/ground_destroy_test.cpp @@ -2,7 +2,7 @@ #include #include "avatar.h" -#include "catch/catch.hpp" +#include "cata_catch.h" #include "item.h" #include "itype.h" #include "map.h" diff --git a/tests/hash_test.cpp b/tests/hash_test.cpp index 6fd981a276119..c912d82007a58 100644 --- a/tests/hash_test.cpp +++ b/tests/hash_test.cpp @@ -4,7 +4,7 @@ #include #include -#include "catch/catch.hpp" +#include "cata_catch.h" #include "point.h" // A larger number for this would be GREAT, but the test isn't efficient enough to make it larger. diff --git a/tests/health_test.cpp b/tests/health_test.cpp index ee314c2e32fbd..9ee73fea642f2 100644 --- a/tests/health_test.cpp +++ b/tests/health_test.cpp @@ -1,4 +1,4 @@ -#include "catch/catch.hpp" +#include "cata_catch.h" #include #include diff --git a/tests/iexamine_test.cpp b/tests/iexamine_test.cpp index a0f53f5be620b..9438eb5ae18bc 100644 --- a/tests/iexamine_test.cpp +++ b/tests/iexamine_test.cpp @@ -1,4 +1,4 @@ -#include "catch/catch.hpp" +#include "cata_catch.h" #include "iexamine.h" #include "mapdata.h" diff --git a/tests/invlet_test.cpp b/tests/invlet_test.cpp index 6b1eb49b3c1d8..0d3b8c7c0005b 100644 --- a/tests/invlet_test.cpp +++ b/tests/invlet_test.cpp @@ -10,7 +10,7 @@ #include "activity_actor_definitions.h" #include "avatar.h" -#include "catch/catch.hpp" +#include "cata_catch.h" #include "inventory.h" #include "item.h" #include "item_location.h" diff --git a/tests/item_contents_test.cpp b/tests/item_contents_test.cpp index 72da9133a96e3..17cf135c4a004 100644 --- a/tests/item_contents_test.cpp +++ b/tests/item_contents_test.cpp @@ -1,6 +1,6 @@ #include -#include "catch/catch.hpp" +#include "cata_catch.h" #include "item.h" #include "item_contents.h" #include "item_pocket.h" diff --git a/tests/item_group_test.cpp b/tests/item_group_test.cpp index 50fb442229de6..9ffa89d7d6704 100644 --- a/tests/item_group_test.cpp +++ b/tests/item_group_test.cpp @@ -6,7 +6,7 @@ #include #include -#include "catch/catch.hpp" +#include "cata_catch.h" #include "flag.h" #include "item.h" #include "item_contents.h" diff --git a/tests/item_location_test.cpp b/tests/item_location_test.cpp index 16c1fc0121187..814aa8dd72cda 100644 --- a/tests/item_location_test.cpp +++ b/tests/item_location_test.cpp @@ -2,7 +2,7 @@ #include #include -#include "catch/catch.hpp" +#include "cata_catch.h" #include "character.h" #include "item.h" #include "item_contents.h" diff --git a/tests/item_stackable_test.cpp b/tests/item_stackable_test.cpp index 098d56eeba4f3..c410e31bcd249 100644 --- a/tests/item_stackable_test.cpp +++ b/tests/item_stackable_test.cpp @@ -2,7 +2,7 @@ #include #include -#include "catch/catch.hpp" +#include "cata_catch.h" #include "item_factory.h" #include "itype.h" #include "type_id.h" diff --git a/tests/item_test.cpp b/tests/item_test.cpp index 33d820e3fc765..0c7614ebf5308 100644 --- a/tests/item_test.cpp +++ b/tests/item_test.cpp @@ -1,4 +1,4 @@ -#include "catch/catch.hpp" +#include "cata_catch.h" #include "item.h" #include diff --git a/tests/item_tname_test.cpp b/tests/item_tname_test.cpp index 0bd11764836e1..85428439d247c 100644 --- a/tests/item_tname_test.cpp +++ b/tests/item_tname_test.cpp @@ -4,7 +4,7 @@ #include #include "calendar.h" -#include "catch/catch.hpp" +#include "cata_catch.h" #include "character.h" #include "flag.h" #include "item.h" diff --git a/tests/item_type_name_test.cpp b/tests/item_type_name_test.cpp index be6bd8468821e..d1aece474e16f 100644 --- a/tests/item_type_name_test.cpp +++ b/tests/item_type_name_test.cpp @@ -2,7 +2,7 @@ #include #include "calendar.h" -#include "catch/catch.hpp" +#include "cata_catch.h" #include "item.h" #include "type_id.h" diff --git a/tests/iteminfo_test.cpp b/tests/iteminfo_test.cpp index 133c2d123dcbb..7c3a238772d75 100644 --- a/tests/iteminfo_test.cpp +++ b/tests/iteminfo_test.cpp @@ -8,7 +8,7 @@ #include "avatar.h" #include "bodypart.h" #include "calendar.h" -#include "catch/catch.hpp" +#include "cata_catch.h" #include "character.h" #include "flag.h" #include "item.h" @@ -20,7 +20,6 @@ #include "player_helpers.h" #include "recipe.h" #include "recipe_dictionary.h" -#include "stringmaker.h" // IWYU pragma: keep #include "type_id.h" #include "units.h" #include "value_ptr.h" @@ -658,10 +657,10 @@ static std::vector bodyparts_to_check() static void verify_item_coverage( const item &i, const std::map &expected ) { - CAPTURE( i.typeId().str() ); + CAPTURE( i.typeId() ); REQUIRE( i.get_covered_body_parts().any() ); for( const bodypart_id &bp : bodyparts_to_check() ) { - CAPTURE( bp.id().str() ); + CAPTURE( bp.id() ); REQUIRE( i.get_coverage( bp ) == expected.at( bp ) ); } } @@ -669,10 +668,10 @@ static void verify_item_coverage( const item &i, const std::map &expected ) { - CAPTURE( i.typeId().str() ); + CAPTURE( i.typeId() ); REQUIRE( i.get_avg_encumber( get_player_character(), flags ) == average ); for( const bodypart_id &bp : bodyparts_to_check() ) { - CAPTURE( bp.id().str() ); + CAPTURE( bp.id() ); REQUIRE( i.get_encumber( get_player_character(), bp, flags ) == expected.at( bp ) ); } } diff --git a/tests/itemname_test.cpp b/tests/itemname_test.cpp index 3ebd49c418019..d080e29ecaa60 100644 --- a/tests/itemname_test.cpp +++ b/tests/itemname_test.cpp @@ -3,7 +3,7 @@ #include #include "calendar.h" -#include "catch/catch.hpp" +#include "cata_catch.h" #include "character.h" #include "flag.h" #include "item.h" diff --git a/tests/iuse_actor_test.cpp b/tests/iuse_actor_test.cpp index f65e19a4edf61..0c86943101502 100644 --- a/tests/iuse_actor_test.cpp +++ b/tests/iuse_actor_test.cpp @@ -8,7 +8,7 @@ #include "avatar.h" #include "calendar.h" -#include "catch/catch.hpp" +#include "cata_catch.h" #include "colony.h" #include "game.h" #include "item.h" diff --git a/tests/iuse_test.cpp b/tests/iuse_test.cpp index 43f49654d56bb..00e66b1a820dd 100644 --- a/tests/iuse_test.cpp +++ b/tests/iuse_test.cpp @@ -5,7 +5,7 @@ #include "avatar.h" #include "calendar.h" -#include "catch/catch.hpp" +#include "cata_catch.h" #include "flag.h" #include "item.h" #include "itype.h" diff --git a/tests/json_test.cpp b/tests/json_test.cpp index 99985e66e6aec..1f31ca0671f41 100644 --- a/tests/json_test.cpp +++ b/tests/json_test.cpp @@ -13,7 +13,7 @@ #include "bodypart.h" #include "cached_options.h" #include "cata_utility.h" -#include "catch/catch.hpp" +#include "cata_catch.h" #include "colony.h" #include "damage.h" #include "debug.h" diff --git a/tests/line_test.cpp b/tests/line_test.cpp index c4a34d5fb8822..0efa68e05ad52 100644 --- a/tests/line_test.cpp +++ b/tests/line_test.cpp @@ -9,7 +9,7 @@ #include #include "cata_generators.h" -#include "catch/catch.hpp" +#include "cata_catch.h" #include "coordinates.h" #include "line.h" #include "point.h" diff --git a/tests/list_test.cpp b/tests/list_test.cpp index 258b9d2ce1546..8c9327ef21a43 100644 --- a/tests/list_test.cpp +++ b/tests/list_test.cpp @@ -6,7 +6,7 @@ #include #include // range-insert testing -#include "catch/catch.hpp" +#include "cata_catch.h" #include "colony_list_test_helpers.h" #include "list.h" diff --git a/tests/magic_spell_effect_test.cpp b/tests/magic_spell_effect_test.cpp index db5ce789c30fe..842953eafddc0 100644 --- a/tests/magic_spell_effect_test.cpp +++ b/tests/magic_spell_effect_test.cpp @@ -1,7 +1,7 @@ #include #include -#include "catch/catch.hpp" +#include "cata_catch.h" #include "json.h" #include "magic.h" #include "magic_spell_effect_helpers.h" diff --git a/tests/magic_spell_test.cpp b/tests/magic_spell_test.cpp index 5654f69369bb3..cc2835ffcf6c6 100644 --- a/tests/magic_spell_test.cpp +++ b/tests/magic_spell_test.cpp @@ -3,7 +3,7 @@ #include #include "avatar.h" -#include "catch/catch.hpp" +#include "cata_catch.h" #include "game.h" #include "magic.h" #include "map_helpers.h" diff --git a/tests/make_static_test.cpp b/tests/make_static_test.cpp index a8f9fbf2590c7..7409f412b85c9 100644 --- a/tests/make_static_test.cpp +++ b/tests/make_static_test.cpp @@ -2,7 +2,7 @@ #include #include -#include "catch/catch.hpp" +#include "cata_catch.h" #include "make_static.h" #include "string_id.h" diff --git a/tests/map_extra_test.cpp b/tests/map_extra_test.cpp index 263acc80c8c2b..79cedaa631f94 100644 --- a/tests/map_extra_test.cpp +++ b/tests/map_extra_test.cpp @@ -4,7 +4,7 @@ #include #include -#include "catch/catch.hpp" +#include "cata_catch.h" #include "coordinates.h" #include "enums.h" #include "map.h" diff --git a/tests/map_iterator_test.cpp b/tests/map_iterator_test.cpp index 7b1706e0eb3c0..4d701f3d0a928 100644 --- a/tests/map_iterator_test.cpp +++ b/tests/map_iterator_test.cpp @@ -1,4 +1,4 @@ -#include "catch/catch.hpp" +#include "cata_catch.h" #include #include diff --git a/tests/map_memory_test.cpp b/tests/map_memory_test.cpp index 993fdb1995964..fcc28128043ea 100644 --- a/tests/map_memory_test.cpp +++ b/tests/map_memory_test.cpp @@ -3,7 +3,7 @@ #include #include -#include "catch/catch.hpp" +#include "cata_catch.h" #include "game_constants.h" #include "json.h" #include "lru_cache.h" diff --git a/tests/map_test.cpp b/tests/map_test.cpp index 38c0ab96bc28f..57300e9dda09c 100644 --- a/tests/map_test.cpp +++ b/tests/map_test.cpp @@ -1,4 +1,4 @@ -#include "catch/catch.hpp" +#include "cata_catch.h" #include "map.h" #include diff --git a/tests/map_test_case.h b/tests/map_test_case.h index 3f31cbc71fff7..7bbf8f4937d99 100644 --- a/tests/map_test_case.h +++ b/tests/map_test_case.h @@ -7,7 +7,7 @@ #include #include -#include "catch/catch.hpp" +#include "cata_catch.h" #include "map.h" #include "mapdata.h" #include "optional.h" diff --git a/tests/mapgen_function_test.cpp b/tests/mapgen_function_test.cpp index 0334b2a92a364..943d87116b3a3 100644 --- a/tests/mapgen_function_test.cpp +++ b/tests/mapgen_function_test.cpp @@ -1,4 +1,4 @@ -#include "catch/catch.hpp" +#include "cata_catch.h" #include "mapgen.h" #include "type_id.h" diff --git a/tests/math_functions_test.cpp b/tests/math_functions_test.cpp index 7cbeb9b8bf757..69422d33e0e36 100644 --- a/tests/math_functions_test.cpp +++ b/tests/math_functions_test.cpp @@ -1,4 +1,4 @@ -#include "catch/catch.hpp" +#include "cata_catch.h" #include #include diff --git a/tests/melee_dodge_hit_test.cpp b/tests/melee_dodge_hit_test.cpp index eb683648d3e84..fa100edb8a735 100644 --- a/tests/melee_dodge_hit_test.cpp +++ b/tests/melee_dodge_hit_test.cpp @@ -4,7 +4,7 @@ #include "avatar.h" #include "calendar.h" -#include "catch/catch.hpp" +#include "cata_catch.h" #include "creature.h" #include "flag.h" #include "game.h" diff --git a/tests/melee_test.cpp b/tests/melee_test.cpp index f40e68d9c5bd9..d9da5a05602b9 100644 --- a/tests/melee_test.cpp +++ b/tests/melee_test.cpp @@ -3,7 +3,7 @@ #include #include "calendar.h" -#include "catch/catch.hpp" +#include "cata_catch.h" #include "creature.h" #include "game_constants.h" #include "item.h" diff --git a/tests/memorial_test.cpp b/tests/memorial_test.cpp index 01c0727fa17dd..eb8d06f3cc1ec 100644 --- a/tests/memorial_test.cpp +++ b/tests/memorial_test.cpp @@ -9,7 +9,7 @@ #include "achievement.h" #include "avatar.h" #include "bodypart.h" -#include "catch/catch.hpp" +#include "cata_catch.h" #include "character_id.h" #include "debug_menu.h" #include "event.h" diff --git a/tests/modify_morale_test.cpp b/tests/modify_morale_test.cpp index 1651644d9f35f..a60d643e03f00 100644 --- a/tests/modify_morale_test.cpp +++ b/tests/modify_morale_test.cpp @@ -6,7 +6,7 @@ #include #include "avatar.h" -#include "catch/catch.hpp" +#include "cata_catch.h" #include "flag.h" #include "item.h" #include "item_contents.h" diff --git a/tests/mondefense_test.cpp b/tests/mondefense_test.cpp index 26363f0587aca..fcc2691daf582 100644 --- a/tests/mondefense_test.cpp +++ b/tests/mondefense_test.cpp @@ -1,4 +1,4 @@ -#include "catch/catch.hpp" +#include "cata_catch.h" #include "creature.h" #include "item.h" diff --git a/tests/monfactions_test.cpp b/tests/monfactions_test.cpp index cff04907e751d..1204cbeb775e5 100644 --- a/tests/monfactions_test.cpp +++ b/tests/monfactions_test.cpp @@ -1,7 +1,7 @@ #include #include -#include "catch/catch.hpp" +#include "cata_catch.h" #include "monfaction.h" #include "type_id.h" diff --git a/tests/monster_attack_test.cpp b/tests/monster_attack_test.cpp index 7e9159d0d5463..6c1bb9051d833 100644 --- a/tests/monster_attack_test.cpp +++ b/tests/monster_attack_test.cpp @@ -3,7 +3,7 @@ #include "cached_options.h" #include "calendar.h" -#include "catch/catch.hpp" +#include "cata_catch.h" #include "character.h" #include "game.h" #include "line.h" diff --git a/tests/monster_test.cpp b/tests/monster_test.cpp index 3e391a9e27f01..68983eeb63016 100644 --- a/tests/monster_test.cpp +++ b/tests/monster_test.cpp @@ -10,7 +10,7 @@ #include #include "cata_utility.h" -#include "catch/catch.hpp" +#include "cata_catch.h" #include "character.h" #include "game.h" #include "game_constants.h" diff --git a/tests/monster_vision_test.cpp b/tests/monster_vision_test.cpp index 6785a193bdf53..6fb433b48b7a3 100644 --- a/tests/monster_vision_test.cpp +++ b/tests/monster_vision_test.cpp @@ -1,6 +1,6 @@ #include "cached_options.h" #include "calendar.h" -#include "catch/catch.hpp" +#include "cata_catch.h" #include "map.h" #include "map_helpers.h" #include "mapdata.h" diff --git a/tests/moon_test.cpp b/tests/moon_test.cpp index 65d7c14aae968..55ef7e7bd8f3a 100644 --- a/tests/moon_test.cpp +++ b/tests/moon_test.cpp @@ -2,7 +2,7 @@ #include #include "calendar.h" -#include "catch/catch.hpp" +#include "cata_catch.h" #include "enum_conversions.h" // MOON TESTS diff --git a/tests/morale_test.cpp b/tests/morale_test.cpp index a43425f496253..2e59f0189d245 100644 --- a/tests/morale_test.cpp +++ b/tests/morale_test.cpp @@ -1,4 +1,4 @@ -#include "catch/catch.hpp" +#include "cata_catch.h" #include "bodypart.h" #include "item.h" diff --git a/tests/mutation_test.cpp b/tests/mutation_test.cpp index 96cec2e7de7fb..8997db26b78a5 100644 --- a/tests/mutation_test.cpp +++ b/tests/mutation_test.cpp @@ -4,7 +4,7 @@ #include #include -#include "catch/catch.hpp" +#include "cata_catch.h" #include "character.h" #include "mutation.h" #include "npc.h" diff --git a/tests/name_test.cpp b/tests/name_test.cpp index 1f525c93384c9..a6c7c6168b671 100644 --- a/tests/name_test.cpp +++ b/tests/name_test.cpp @@ -2,7 +2,7 @@ #include #include -#include "catch/catch.hpp" +#include "cata_catch.h" #include "enum_traits.h" #include "name.h" diff --git a/tests/new_character_test.cpp b/tests/new_character_test.cpp index 6a1ac5e14cf5d..579699eb3c47d 100644 --- a/tests/new_character_test.cpp +++ b/tests/new_character_test.cpp @@ -10,14 +10,13 @@ #include #include "avatar.h" -#include "catch/catch.hpp" +#include "cata_catch.h" #include "inventory.h" #include "item.h" #include "pimpl.h" #include "profession.h" #include "scenario.h" #include "string_formatter.h" -#include "stringmaker.h" // IWYU pragma: keep #include "type_id.h" #include "visitable.h" diff --git a/tests/npc_talk_test.cpp b/tests/npc_talk_test.cpp index 8da6c8e8a311c..5a5a9ef7d5d34 100644 --- a/tests/npc_talk_test.cpp +++ b/tests/npc_talk_test.cpp @@ -8,7 +8,7 @@ #include "avatar.h" #include "calendar.h" -#include "catch/catch.hpp" +#include "cata_catch.h" #include "character.h" #include "character_id.h" #include "coordinate_conversions.h" diff --git a/tests/npc_test.cpp b/tests/npc_test.cpp index 178747affd4fd..9ddd6e13526a0 100644 --- a/tests/npc_test.cpp +++ b/tests/npc_test.cpp @@ -7,7 +7,7 @@ #include #include "calendar.h" -#include "catch/catch.hpp" +#include "cata_catch.h" #include "character.h" #include "common_types.h" #include "faction.h" diff --git a/tests/optional_test.cpp b/tests/optional_test.cpp index ce0d6b575925b..3e72261b5d85e 100644 --- a/tests/optional_test.cpp +++ b/tests/optional_test.cpp @@ -1,7 +1,7 @@ #include #include -#include "catch/catch.hpp" +#include "cata_catch.h" #include "optional.h" TEST_CASE( "optional_assignment_works", "[optional]" ) diff --git a/tests/overmap_noise_test.cpp b/tests/overmap_noise_test.cpp index 979340ddd7ef4..7df43907f4295 100644 --- a/tests/overmap_noise_test.cpp +++ b/tests/overmap_noise_test.cpp @@ -1,6 +1,6 @@ #include -#include "catch/catch.hpp" +#include "cata_catch.h" #include "coordinates.h" #include "game_constants.h" #include "overmap_noise.h" diff --git a/tests/overmap_test.cpp b/tests/overmap_test.cpp index 9435dab132c36..ce609cbb1e69c 100644 --- a/tests/overmap_test.cpp +++ b/tests/overmap_test.cpp @@ -2,7 +2,7 @@ #include #include "calendar.h" -#include "catch/catch.hpp" +#include "cata_catch.h" #include "common_types.h" #include "coordinates.h" #include "enums.h" diff --git a/tests/player_helpers.cpp b/tests/player_helpers.cpp index 58dc5de7b4914..2442d881cca55 100644 --- a/tests/player_helpers.cpp +++ b/tests/player_helpers.cpp @@ -7,7 +7,7 @@ #include "avatar.h" #include "bionics.h" -#include "catch/catch.hpp" +#include "cata_catch.h" #include "character.h" #include "character_id.h" #include "character_martial_arts.h" diff --git a/tests/player_test.cpp b/tests/player_test.cpp index 584e7b54febe6..612a8a5b9e11f 100644 --- a/tests/player_test.cpp +++ b/tests/player_test.cpp @@ -3,7 +3,7 @@ #include #include "calendar.h" -#include "catch/catch.hpp" +#include "cata_catch.h" #include "character.h" #include "item.h" #include "type_id.h" diff --git a/tests/pocket_test.cpp b/tests/pocket_test.cpp index aa9e60002b537..e97efc2e7b938 100644 --- a/tests/pocket_test.cpp +++ b/tests/pocket_test.cpp @@ -8,7 +8,7 @@ #include #include "calendar.h" -#include "catch/catch.hpp" +#include "cata_catch.h" #include "debug.h" #include "enums.h" #include "flag.h" diff --git a/tests/point_test.cpp b/tests/point_test.cpp index 59bee2c3bed23..355e0cfa3adf4 100644 --- a/tests/point_test.cpp +++ b/tests/point_test.cpp @@ -2,7 +2,7 @@ #include #include -#include "catch/catch.hpp" +#include "cata_catch.h" #include "coordinates.h" #include "cuboid_rectangle.h" #include "point.h" diff --git a/tests/projectile_test.cpp b/tests/projectile_test.cpp index 9d7793498d95f..7e3efc0fcc83c 100644 --- a/tests/projectile_test.cpp +++ b/tests/projectile_test.cpp @@ -5,7 +5,7 @@ #include #include "ballistics.h" -#include "catch/catch.hpp" +#include "cata_catch.h" #include "character.h" #include "damage.h" #include "dispersion.h" diff --git a/tests/ranged_balance_test.cpp b/tests/ranged_balance_test.cpp index 7d7b8b9bf838a..b4623a4b9ccec 100644 --- a/tests/ranged_balance_test.cpp +++ b/tests/ranged_balance_test.cpp @@ -11,7 +11,7 @@ #include "bodypart.h" #include "calendar.h" #include "cata_utility.h" -#include "catch/catch.hpp" +#include "cata_catch.h" #include "creature.h" #include "dispersion.h" #include "game_constants.h" diff --git a/tests/reachability_cache_test.cpp b/tests/reachability_cache_test.cpp index f6defcb9747ee..c5ec897f7d30f 100644 --- a/tests/reachability_cache_test.cpp +++ b/tests/reachability_cache_test.cpp @@ -4,7 +4,7 @@ #include #include "cached_options.h" -#include "catch/catch.hpp" +#include "cata_catch.h" #include "map.h" #include "map_helpers.h" #include "map_iterator.h" diff --git a/tests/reading_test.cpp b/tests/reading_test.cpp index b2f6c48e20af6..8f6a45c8c219d 100644 --- a/tests/reading_test.cpp +++ b/tests/reading_test.cpp @@ -6,7 +6,7 @@ #include "avatar.h" #include "calendar.h" -#include "catch/catch.hpp" +#include "cata_catch.h" #include "character.h" #include "item.h" #include "itype.h" diff --git a/tests/recipe_test.cpp b/tests/recipe_test.cpp index 4cc53a1996901..49e3e1907329a 100644 --- a/tests/recipe_test.cpp +++ b/tests/recipe_test.cpp @@ -2,7 +2,7 @@ #include #include "calendar.h" -#include "catch/catch.hpp" +#include "cata_catch.h" #include "character.h" #include "json.h" #include "recipe.h" diff --git a/tests/reload_magazine_test.cpp b/tests/reload_magazine_test.cpp index fa929364d170a..76fb218827abd 100644 --- a/tests/reload_magazine_test.cpp +++ b/tests/reload_magazine_test.cpp @@ -6,7 +6,7 @@ #include "avatar.h" #include "calendar.h" -#include "catch/catch.hpp" +#include "cata_catch.h" #include "character.h" #include "inventory.h" #include "item.h" diff --git a/tests/reload_option_test.cpp b/tests/reload_option_test.cpp index cd894ee6cc95d..6778426537b93 100644 --- a/tests/reload_option_test.cpp +++ b/tests/reload_option_test.cpp @@ -3,7 +3,7 @@ #include "avatar.h" #include "calendar.h" -#include "catch/catch.hpp" +#include "cata_catch.h" #include "item.h" #include "item_location.h" #include "item_pocket.h" diff --git a/tests/reloading_test.cpp b/tests/reloading_test.cpp index 29ab9e5895add..f75d39fbcf676 100644 --- a/tests/reloading_test.cpp +++ b/tests/reloading_test.cpp @@ -6,7 +6,7 @@ #include "avatar.h" #include "calendar.h" -#include "catch/catch.hpp" +#include "cata_catch.h" #include "game.h" #include "item.h" #include "item_contents.h" diff --git a/tests/requirements_test.cpp b/tests/requirements_test.cpp index 367d97cf893f4..eb73a620fa326 100644 --- a/tests/requirements_test.cpp +++ b/tests/requirements_test.cpp @@ -3,7 +3,7 @@ #include #include -#include "catch/catch.hpp" +#include "cata_catch.h" #include "requirements.h" #include "type_id.h" diff --git a/tests/rewrite_vsnprintf_test.cpp b/tests/rewrite_vsnprintf_test.cpp index 69a83f49b5fe1..f1e17ae8cc29e 100644 --- a/tests/rewrite_vsnprintf_test.cpp +++ b/tests/rewrite_vsnprintf_test.cpp @@ -3,7 +3,7 @@ #include // the rewrite_vsnprintf function is explicitly defined for non-MS compilers in output.cpp -#include "catch/catch.hpp" +#include "cata_catch.h" #include "output.h" TEST_CASE( "Test vsnprintf_rewrite" ) diff --git a/tests/rng_test.cpp b/tests/rng_test.cpp index ff2fcafc7a734..c19277b1ad77e 100644 --- a/tests/rng_test.cpp +++ b/tests/rng_test.cpp @@ -1,7 +1,7 @@ #include #include -#include "catch/catch.hpp" +#include "cata_catch.h" #include "optional.h" #include "rng.h" #include "test_statistics.h" diff --git a/tests/rot_test.cpp b/tests/rot_test.cpp index 4a9bd41abf721..3eb05e471575b 100644 --- a/tests/rot_test.cpp +++ b/tests/rot_test.cpp @@ -1,5 +1,5 @@ #include "calendar.h" -#include "catch/catch.hpp" +#include "cata_catch.h" #include "enums.h" #include "item.h" #include "point.h" diff --git a/tests/safe_reference_test.cpp b/tests/safe_reference_test.cpp index a0b7681a8793e..2b0589073509f 100644 --- a/tests/safe_reference_test.cpp +++ b/tests/safe_reference_test.cpp @@ -1,4 +1,4 @@ -#include "catch/catch.hpp" +#include "cata_catch.h" #include diff --git a/tests/shadowcasting_test.cpp b/tests/shadowcasting_test.cpp index a5813893e3cd4..c5c04c1368789 100644 --- a/tests/shadowcasting_test.cpp +++ b/tests/shadowcasting_test.cpp @@ -7,7 +7,7 @@ #include #include -#include "catch/catch.hpp" +#include "cata_catch.h" #include "cuboid_rectangle.h" #include "game_constants.h" #include "level_cache.h" diff --git a/tests/simple_pathfinding_test.cpp b/tests/simple_pathfinding_test.cpp index 617ed3a8121e5..621d756ed6c1c 100644 --- a/tests/simple_pathfinding_test.cpp +++ b/tests/simple_pathfinding_test.cpp @@ -1,4 +1,4 @@ -#include "catch/catch.hpp" +#include "cata_catch.h" #include "simple_pathfinding.h" #include "coordinates.h" diff --git a/tests/stats_tracker_test.cpp b/tests/stats_tracker_test.cpp index 3519444cb965a..3f1289b6a46f1 100644 --- a/tests/stats_tracker_test.cpp +++ b/tests/stats_tracker_test.cpp @@ -1,4 +1,4 @@ -#include "catch/catch.hpp" +#include "cata_catch.h" #include "stats_tracker.h" #include diff --git a/tests/stomach_contents_test.cpp b/tests/stomach_contents_test.cpp index f28cb10819775..90680b265b9bc 100644 --- a/tests/stomach_contents_test.cpp +++ b/tests/stomach_contents_test.cpp @@ -4,7 +4,7 @@ #include "avatar.h" #include "calendar.h" -#include "catch/catch.hpp" +#include "cata_catch.h" #include "character.h" #include "item.h" #include "player.h" diff --git a/tests/string_formatter_test.cpp b/tests/string_formatter_test.cpp index 18f2fae922e4a..badd7eed5d87f 100644 --- a/tests/string_formatter_test.cpp +++ b/tests/string_formatter_test.cpp @@ -4,7 +4,7 @@ #include #include -#include "catch/catch.hpp" +#include "cata_catch.h" #include "string_formatter.h" // Same as @ref string_format, but does not swallow errors and throws them instead. diff --git a/tests/string_ids_test.cpp b/tests/string_ids_test.cpp index c3e7957968273..5cc963592b0f4 100644 --- a/tests/string_ids_test.cpp +++ b/tests/string_ids_test.cpp @@ -6,7 +6,7 @@ #include #include -#include "catch/catch.hpp" +#include "cata_catch.h" #include "field_type.h" #include "string_id_utils.h" #include "type_id.h" diff --git a/tests/string_test.cpp b/tests/string_test.cpp index b998ada26c14c..7dab191d90caa 100644 --- a/tests/string_test.cpp +++ b/tests/string_test.cpp @@ -1,7 +1,7 @@ #include #include -#include "catch/catch.hpp" +#include "cata_catch.h" #include "output.h" static void test_remove_color_tags( const std::string &original, const std::string &expected ) diff --git a/tests/stringmaker.h b/tests/stringmaker.h index d5c6938869512..d0eac3c374539 100644 --- a/tests/stringmaker.h +++ b/tests/stringmaker.h @@ -3,7 +3,7 @@ #define CATA_TESTS_STRINGMAKER_H #include "cuboid_rectangle.h" -#include "catch/catch.hpp" +#include "cata_catch.h" #include "cata_variant.h" #include "dialogue.h" #include "item.h" diff --git a/tests/submap_load_test.cpp b/tests/submap_load_test.cpp index fd2f238484ee8..38260a285c6b0 100644 --- a/tests/submap_load_test.cpp +++ b/tests/submap_load_test.cpp @@ -7,7 +7,7 @@ #include #include "calendar.h" -#include "catch/catch.hpp" +#include "cata_catch.h" #include "colony.h" #include "construction.h" #include "field.h" diff --git a/tests/submap_test.cpp b/tests/submap_test.cpp index 2d63ec3b1120b..e38f81d375d88 100644 --- a/tests/submap_test.cpp +++ b/tests/submap_test.cpp @@ -1,4 +1,4 @@ -#include "catch/catch.hpp" +#include "cata_catch.h" #include "submap.h" #include "game_constants.h" diff --git a/tests/sun_test.cpp b/tests/sun_test.cpp index 7c067532b3464..5ffbe45abb807 100644 --- a/tests/sun_test.cpp +++ b/tests/sun_test.cpp @@ -1,4 +1,4 @@ -#include "catch/catch.hpp" +#include "cata_catch.h" #include "calendar.h" // IWYU pragma: associated #include diff --git a/tests/temp_crafting_inv_test.cpp b/tests/temp_crafting_inv_test.cpp index 7e91aeca5145a..0d9da91e815b7 100644 --- a/tests/temp_crafting_inv_test.cpp +++ b/tests/temp_crafting_inv_test.cpp @@ -1,6 +1,6 @@ #include "../src/temp_crafting_inventory.h" #include "calendar.h" -#include "catch/catch.hpp" +#include "cata_catch.h" #include "item.h" #include "type_id.h" diff --git a/tests/temperature_test.cpp b/tests/temperature_test.cpp index 24d1677b61e6f..c18262d9c49cf 100644 --- a/tests/temperature_test.cpp +++ b/tests/temperature_test.cpp @@ -1,6 +1,6 @@ #include "calendar.h" #include "cata_utility.h" -#include "catch/catch.hpp" +#include "cata_catch.h" #include "enums.h" #include "flag.h" #include "game_constants.h" diff --git a/tests/test_main.cpp b/tests/test_main.cpp index a53e34208d546..f8c37bdbc2a29 100644 --- a/tests/test_main.cpp +++ b/tests/test_main.cpp @@ -17,7 +17,7 @@ #include #include "calendar.h" -#include "catch/catch.hpp" +#include "cata_catch.h" #include "coordinates.h" #ifndef _WIN32 #include diff --git a/tests/test_statistics.h b/tests/test_statistics.h index 03d59f0224040..9d5f99b18ad1c 100644 --- a/tests/test_statistics.h +++ b/tests/test_statistics.h @@ -9,7 +9,7 @@ #include #include -#include "catch/catch.hpp" +#include "cata_catch.h" // Z-value for confidence interval constexpr double Z95 = 1.96; diff --git a/tests/text_snippets_test.cpp b/tests/text_snippets_test.cpp index 8c6a6f50921ec..b5b98d70f580e 100644 --- a/tests/text_snippets_test.cpp +++ b/tests/text_snippets_test.cpp @@ -1,6 +1,6 @@ #include -#include "catch/catch.hpp" +#include "cata_catch.h" #include "optional.h" #include "text_snippets.h" #include "translations.h" diff --git a/tests/throwing_test.cpp b/tests/throwing_test.cpp index 4072d08fced58..3d947e1d66eec 100644 --- a/tests/throwing_test.cpp +++ b/tests/throwing_test.cpp @@ -5,7 +5,7 @@ #include "avatar.h" #include "calendar.h" -#include "catch/catch.hpp" +#include "cata_catch.h" #include "damage.h" #include "game.h" #include "game_constants.h" diff --git a/tests/translations_test.cpp b/tests/translations_test.cpp index 5293be188d3b4..c8516298de3e9 100644 --- a/tests/translations_test.cpp +++ b/tests/translations_test.cpp @@ -2,7 +2,7 @@ #include #include -#include "catch/catch.hpp" +#include "cata_catch.h" #include "translations.h" // wrapping in another macro to prevent collection of the test string for translation diff --git a/tests/try_parse_integer_test.cpp b/tests/try_parse_integer_test.cpp index 5136e2541bcd6..a40e9f48428b9 100644 --- a/tests/try_parse_integer_test.cpp +++ b/tests/try_parse_integer_test.cpp @@ -1,4 +1,4 @@ -#include "catch/catch.hpp" +#include "cata_catch.h" #include "try_parse_integer.h" TEMPLATE_TEST_CASE( "try_parse_int_simple_parsing", "[try_parse_integer]", int, long, long long ) diff --git a/tests/units_test.cpp b/tests/units_test.cpp index 0af40be98d23e..b849df756939a 100644 --- a/tests/units_test.cpp +++ b/tests/units_test.cpp @@ -4,7 +4,7 @@ #include "calendar.h" #include "cata_utility.h" -#include "catch/catch.hpp" +#include "cata_catch.h" #include "json.h" #include "math_defines.h" #include "options_helpers.h" diff --git a/tests/unseal_and_spill_test.cpp b/tests/unseal_and_spill_test.cpp index 6fdcacdde764f..a3cd35838942c 100644 --- a/tests/unseal_and_spill_test.cpp +++ b/tests/unseal_and_spill_test.cpp @@ -9,7 +9,7 @@ #include "avatar.h" #include "cached_options.h" -#include "catch/catch.hpp" +#include "cata_catch.h" #include "character.h" #include "colony.h" #include "item.h" diff --git a/tests/value_ptr_test.cpp b/tests/value_ptr_test.cpp index 407507f1dfb75..187f2de2bba4d 100644 --- a/tests/value_ptr_test.cpp +++ b/tests/value_ptr_test.cpp @@ -1,6 +1,6 @@ #include -#include "catch/catch.hpp" +#include "cata_catch.h" #include "value_ptr.h" TEST_CASE( "value_ptr copy constructor", "[value_ptr]" ) diff --git a/tests/vehicle_drag_test.cpp b/tests/vehicle_drag_test.cpp index af5f69c38b203..8ddb70e5b0313 100644 --- a/tests/vehicle_drag_test.cpp +++ b/tests/vehicle_drag_test.cpp @@ -4,7 +4,7 @@ #include #include "calendar.h" -#include "catch/catch.hpp" +#include "cata_catch.h" #include "character.h" #include "map.h" #include "map_helpers.h" diff --git a/tests/vehicle_efficiency_test.cpp b/tests/vehicle_efficiency_test.cpp index 4d8c1211df14f..10943a343f4d2 100644 --- a/tests/vehicle_efficiency_test.cpp +++ b/tests/vehicle_efficiency_test.cpp @@ -11,7 +11,7 @@ #include #include "calendar.h" -#include "catch/catch.hpp" +#include "cata_catch.h" #include "character.h" #include "enums.h" #include "item.h" diff --git a/tests/vehicle_interact_test.cpp b/tests/vehicle_interact_test.cpp index 8e831385e3b6c..9830483ad66cd 100644 --- a/tests/vehicle_interact_test.cpp +++ b/tests/vehicle_interact_test.cpp @@ -4,7 +4,7 @@ #include #include "calendar.h" -#include "catch/catch.hpp" +#include "cata_catch.h" #include "character.h" #include "inventory.h" #include "item.h" diff --git a/tests/vehicle_part_test.cpp b/tests/vehicle_part_test.cpp index 3c861c2c52d57..d69bca02778da 100644 --- a/tests/vehicle_part_test.cpp +++ b/tests/vehicle_part_test.cpp @@ -9,7 +9,7 @@ #include "activity_type.h" #include "calendar.h" -#include "catch/catch.hpp" +#include "cata_catch.h" #include "character.h" #include "damage.h" #include "game.h" diff --git a/tests/vehicle_power_test.cpp b/tests/vehicle_power_test.cpp index 33b9aa9f0ade5..027ec23060543 100644 --- a/tests/vehicle_power_test.cpp +++ b/tests/vehicle_power_test.cpp @@ -2,7 +2,7 @@ #include #include "calendar.h" -#include "catch/catch.hpp" +#include "cata_catch.h" #include "character.h" #include "map.h" #include "map_helpers.h" diff --git a/tests/vehicle_ramp_test.cpp b/tests/vehicle_ramp_test.cpp index b359e184444e1..b34a5983627a8 100644 --- a/tests/vehicle_ramp_test.cpp +++ b/tests/vehicle_ramp_test.cpp @@ -7,7 +7,7 @@ #include #include "calendar.h" -#include "catch/catch.hpp" +#include "cata_catch.h" #include "character.h" #include "game.h" #include "game_constants.h" diff --git a/tests/vehicle_split_test.cpp b/tests/vehicle_split_test.cpp index b890ec7565ddf..d9a343c70aeff 100644 --- a/tests/vehicle_split_test.cpp +++ b/tests/vehicle_split_test.cpp @@ -1,7 +1,7 @@ #include #include -#include "catch/catch.hpp" +#include "cata_catch.h" #include "character.h" #include "map.h" #include "point.h" diff --git a/tests/vehicle_test.cpp b/tests/vehicle_test.cpp index 57f530b009712..44c41cfc2b5a9 100644 --- a/tests/vehicle_test.cpp +++ b/tests/vehicle_test.cpp @@ -1,7 +1,7 @@ #include #include "avatar.h" -#include "catch/catch.hpp" +#include "cata_catch.h" #include "character.h" #include "damage.h" #include "enums.h" diff --git a/tests/vehicle_turrets_test.cpp b/tests/vehicle_turrets_test.cpp index 37a42c74b6abc..5c9d76b5527e1 100644 --- a/tests/vehicle_turrets_test.cpp +++ b/tests/vehicle_turrets_test.cpp @@ -1,4 +1,4 @@ -#include "catch/catch.hpp" +#include "cata_catch.h" #include #include diff --git a/tests/vision_test.cpp b/tests/vision_test.cpp index 94c7bff2a11a2..4557c9864a6e6 100644 --- a/tests/vision_test.cpp +++ b/tests/vision_test.cpp @@ -8,7 +8,7 @@ #include "cached_options.h" #include "calendar.h" -#include "catch/catch.hpp" +#include "cata_catch.h" #include "character.h" #include "game.h" #include "item.h" diff --git a/tests/visitable_remove_test.cpp b/tests/visitable_remove_test.cpp index 94ae2875ba185..b31263c8a9c3e 100644 --- a/tests/visitable_remove_test.cpp +++ b/tests/visitable_remove_test.cpp @@ -7,7 +7,7 @@ #include "calendar.h" #include "cata_utility.h" -#include "catch/catch.hpp" +#include "cata_catch.h" #include "character.h" #include "inventory.h" #include "item.h" diff --git a/tests/visitable_test.cpp b/tests/visitable_test.cpp index 0bcfd78eee6d0..f69aa2f742f4f 100644 --- a/tests/visitable_test.cpp +++ b/tests/visitable_test.cpp @@ -1,4 +1,4 @@ -#include "catch/catch.hpp" +#include "cata_catch.h" #include "calendar.h" #include "inventory.h" diff --git a/tests/weary_test.cpp b/tests/weary_test.cpp index 29824ccaad7ae..f804b5bd540c6 100644 --- a/tests/weary_test.cpp +++ b/tests/weary_test.cpp @@ -2,7 +2,7 @@ #include "activity_scheduling_helper.h" #include "avatar.h" #include "calendar.h" -#include "catch/catch.hpp" +#include "cata_catch.h" #include "player_helpers.h" #include "point.h" #include "type_id.h" diff --git a/tests/weather_test.cpp b/tests/weather_test.cpp index 30ab91c53bbbe..2f6148594aaea 100644 --- a/tests/weather_test.cpp +++ b/tests/weather_test.cpp @@ -4,7 +4,7 @@ #include #include "calendar.h" -#include "catch/catch.hpp" +#include "cata_catch.h" #include "options_helpers.h" #include "point.h" #include "type_id.h" diff --git a/tests/wield_times_test.cpp b/tests/wield_times_test.cpp index b304f25afe798..77f8ef8586743 100644 --- a/tests/wield_times_test.cpp +++ b/tests/wield_times_test.cpp @@ -1,4 +1,4 @@ -#include "catch/catch.hpp" +#include "cata_catch.h" #include From 0d8ad0661c43d6ebde14dba5078fd3c58fc675b3 Mon Sep 17 00:00:00 2001 From: Qrox Date: Wed, 5 May 2021 22:42:20 +0800 Subject: [PATCH 425/453] Fix json formatter build and string extraction script --- lang/extract_json_strings.py | 10 ++++++++++ src/translations.h | 8 ++++++++ 2 files changed, 18 insertions(+) diff --git a/lang/extract_json_strings.py b/lang/extract_json_strings.py index 67658db0b56b0..be9989e712627 100755 --- a/lang/extract_json_strings.py +++ b/lang/extract_json_strings.py @@ -267,6 +267,13 @@ def extract_construction(item): writestr(outfile, item["pre_note"]) +def extract_effect_on_condition(item): + outfile = get_outfile("effect_on_condition") + extract_talk_effects(item["effect"], outfile) + if "false_effect" in item: + extract_talk_effects(item["false_effect"], outfile) + + def extract_harvest(item): outfile = get_outfile("harvest") if "message" in item: @@ -716,6 +723,8 @@ def extract_talk_effects(effects, outfile): comment = "Nickname for creature '{}'".format( eff["u_buy_monster"]) writestr(outfile, eff["name"], comment=comment) + if "message" in eff: + writestr(outfile, eff["message"]) def extract_talk_response(response, outfile): @@ -995,6 +1004,7 @@ def extract_vehicle_part_category(item): "clothing_mod": extract_clothing_mod, "conduct": extract_achievement, "construction": extract_construction, + "effect_on_condition": extract_effect_on_condition, "effect_type": extract_effect_type, "fault": extract_fault, "GUN": extract_gun, diff --git a/src/translations.h b/src/translations.h index 63061314389c0..6f63bbe0df496 100644 --- a/src/translations.h +++ b/src/translations.h @@ -92,12 +92,16 @@ class local_translation_cache std::string cached_translation; public: const std::string &operator()( const std::string &arg ) { +#ifndef CATA_IN_TOOL if( cached_lang_version != get_current_language_version() || cached_arg != arg ) { cached_lang_version = get_current_language_version(); cached_arg = arg; cached_translation = _translate_internal( arg ); } return cached_translation; +#else + return arg; +#endif } }; @@ -111,6 +115,7 @@ class local_translation_cache const char *cached_translation = nullptr; public: const char *operator()( const char *arg ) { +#ifndef CATA_IN_TOOL if( cached_lang_version != get_current_language_version() || cached_arg != arg ) { cached_lang_version = get_current_language_version(); cached_translation = _translate_internal( arg ); @@ -120,6 +125,9 @@ class local_translation_cache // mimic gettext() behavior: return `arg` if no translation is found // `same_as_arg` is needed to ensure that the current `arg` is returned (not a cached one) return same_as_arg ? arg : cached_translation; +#else + return arg; +#endif } }; From 68a5d63492e5acf028b2fb812c754dc823077282 Mon Sep 17 00:00:00 2001 From: John Bytheway Date: Fri, 14 May 2021 14:45:12 -0400 Subject: [PATCH 426/453] clang-tidy modernize-use-emplace (#48661) * Port code to emplace_back This is clang-tidy making automated changes to convert push_back into emplace_back whenever the argument to push_back is either a constructor call for the type in question of an expression of a type implicitly convertible to the type in question. This should eliminate one move-construction of the inserted object for each call. * Enable clang-tidy modernize-use-emplace --- .clang-tidy | 1 - src/activity_handlers.cpp | 4 +- src/activity_item_handling.cpp | 36 +- src/armor_layers.cpp | 24 +- src/avatar.cpp | 4 +- src/bionics.cpp | 16 +- src/bionics_ui.cpp | 4 +- src/character.cpp | 2 +- src/clzones.cpp | 2 +- src/construction.cpp | 4 +- src/crafting.cpp | 2 +- src/crafting_gui.cpp | 6 +- src/creature.cpp | 8 +- src/debug_menu.cpp | 3 +- src/dialogue_win.cpp | 2 +- src/editmap.cpp | 4 +- src/effect.cpp | 46 +- src/event_field_transformations.cpp | 2 +- src/faction_camp.cpp | 18 +- src/game.cpp | 16 +- src/handle_liquid.cpp | 2 +- src/iexamine.cpp | 24 +- src/inventory_ui.cpp | 4 +- src/item.cpp | 911 ++++++++++++++-------------- src/item_contents.cpp | 8 +- src/item_factory.cpp | 6 +- src/item_pocket.cpp | 32 +- src/iuse.cpp | 28 +- src/iuse_actor.cpp | 12 +- src/iuse_software_lightson.cpp | 6 +- src/iuse_software_minesweeper.cpp | 6 +- src/iuse_software_snake.cpp | 54 +- src/iuse_software_sokoban.cpp | 14 +- src/lightmap.cpp | 2 +- src/line.cpp | 12 +- src/main_menu.cpp | 59 +- src/map.cpp | 6 +- src/map_field.cpp | 20 +- src/map_item_stack.cpp | 2 +- src/mapgen.cpp | 54 +- src/mattack_actors.cpp | 2 +- src/memorial_logger.cpp | 2 +- src/mission.cpp | 8 +- src/mod_manager.cpp | 2 +- src/monattack.cpp | 2 +- src/monexamine.cpp | 8 +- src/mongroup.cpp | 8 +- src/monmove.cpp | 6 +- src/newcharacter.cpp | 8 +- src/npcmove.cpp | 8 +- src/npctalk.cpp | 4 +- src/output.cpp | 4 +- src/overmap.cpp | 36 +- src/overmap_ui.cpp | 2 +- src/panels.cpp | 28 +- src/past_games_info.cpp | 2 +- src/pixel_minimap.cpp | 2 +- src/player.cpp | 4 +- src/player_activity.cpp | 6 +- src/player_display.cpp | 32 +- src/profession.cpp | 2 +- src/proficiency.cpp | 6 +- src/ranged.cpp | 2 +- src/recipe.cpp | 2 +- src/safemode_ui.cpp | 23 +- src/talker_avatar.cpp | 2 +- src/talker_npc.cpp | 28 +- src/translations.cpp | 2 +- src/veh_interact.cpp | 6 +- src/veh_type.cpp | 9 +- src/vehicle_use.cpp | 46 +- src/wish.cpp | 2 +- src/worldfactory.cpp | 10 +- tests/behavior_test.cpp | 2 +- tests/crafting_test.cpp | 6 +- tests/encumbrance_test.cpp | 2 +- tests/generic_factory_test.cpp | 4 +- tests/invlet_test.cpp | 6 +- tests/iteminfo_test.cpp | 2 +- tests/modify_morale_test.cpp | 18 +- tests/npc_talk_test.cpp | 2 +- tests/player_helpers.cpp | 2 +- tests/ranged_balance_test.cpp | 2 +- tests/reading_test.cpp | 12 +- tests/reload_option_test.cpp | 8 +- tests/reloading_test.cpp | 2 +- tests/string_ids_test.cpp | 6 +- tests/vehicle_part_test.cpp | 6 +- tests/visitable_remove_test.cpp | 2 +- 89 files changed, 929 insertions(+), 933 deletions(-) diff --git a/.clang-tidy b/.clang-tidy index 4f11f89b67c59..1e041e5b16011 100644 --- a/.clang-tidy +++ b/.clang-tidy @@ -53,7 +53,6 @@ readability-*,\ -modernize-pass-by-value,\ -modernize-return-braced-init-list,\ -modernize-use-default-member-init,\ --modernize-use-emplace,\ -performance-unnecessary-value-param,\ -readability-else-after-return,\ -readability-implicit-bool-conversion,\ diff --git a/src/activity_handlers.cpp b/src/activity_handlers.cpp index b4a45eef7f360..355fd41ad6f99 100644 --- a/src/activity_handlers.cpp +++ b/src/activity_handlers.cpp @@ -1555,7 +1555,7 @@ void activity_handlers::fill_liquid_do_turn( player_activity *act, player *p ) act_ref.set_to_null(); } else { if( act_ref.str_values.empty() ) { - act_ref.str_values.push_back( std::string() ); + act_ref.str_values.emplace_back( ); } act_ref.str_values.at( 0 ) = serialize( liquid ); } @@ -3951,7 +3951,7 @@ void activity_handlers::fertilize_plot_do_turn( player_activity *act, player *p auto check_fertilizer = [&]( bool ask_user = true ) -> void { if( act->str_values.empty() ) { - act->str_values.push_back( "" ); + act->str_values.emplace_back( "" ); } fertilizer = itype_id( act->str_values[0] ); diff --git a/src/activity_item_handling.cpp b/src/activity_item_handling.cpp index c01a5269f0f46..651c6bfd93fd7 100644 --- a/src/activity_item_handling.cpp +++ b/src/activity_item_handling.cpp @@ -513,13 +513,13 @@ void activity_handlers::washing_finish( player_activity *act, player *p ) } std::vector comps; - comps.push_back( item_comp( itype_water, required.water ) ); - comps.push_back( item_comp( itype_water_clean, required.water ) ); + comps.emplace_back( itype_water, required.water ); + comps.emplace_back( itype_water_clean, required.water ); p->consume_items( comps, 1, is_liquid_crafting_component ); std::vector comps1; - comps1.push_back( item_comp( itype_soap, required.cleanser ) ); - comps1.push_back( item_comp( itype_detergent, required.cleanser ) ); + comps1.emplace_back( itype_soap, required.cleanser ); + comps1.emplace_back( itype_detergent, required.cleanser ); p->consume_items( comps1 ); p->add_msg_if_player( m_good, _( "You washed your items." ) ); @@ -1469,7 +1469,7 @@ static std::vector> requirements_map( player continue; } } - requirement_map.push_back( std::make_tuple( point_elem, map_elem.first, map_elem.second ) ); + requirement_map.emplace_back( point_elem, map_elem.first, map_elem.second ); } } // Ok we now have a list of all the items that match the requirements, their points, and a quantity for each one. @@ -1493,8 +1493,8 @@ static std::vector> requirements_map( player } if( item_quantity >= quantity_required ) { // it's just this spot that can fulfil the requirement on its own - final_map.push_back( std::make_tuple( pos_here, item_here, std::min( quantity_here, - quantity_required ) ) ); + final_map.emplace_back( pos_here, item_here, std::min( quantity_here, + quantity_required ) ); if( quantity_here >= quantity_required ) { line_found = true; break; @@ -1520,10 +1520,10 @@ static std::vector> requirements_map( player int quantity_here2 = std::get<2>( *it ); if( comp_elem.type == item_here2 ) { if( quantity_here2 >= remainder ) { - final_map.push_back( std::make_tuple( pos_here2, item_here2, remainder ) ); + final_map.emplace_back( pos_here2, item_here2, remainder ); line_found = true; } else { - final_map.push_back( std::make_tuple( pos_here2, item_here2, remainder ) ); + final_map.emplace_back( pos_here2, item_here2, remainder ); remainder -= quantity_here2; } } @@ -1551,8 +1551,8 @@ static std::vector> requirements_map( player } if( item_quantity >= quantity_required ) { // it's just this spot that can fulfil the requirement on its own - final_map.push_back( std::make_tuple( pos_here, item_here, std::min( quantity_here, - quantity_required ) ) ); + final_map.emplace_back( pos_here, item_here, std::min( quantity_here, + quantity_required ) ); if( quantity_here >= quantity_required ) { line_found = true; break; @@ -1578,10 +1578,10 @@ static std::vector> requirements_map( player int quantity_here2 = std::get<2>( *it ); if( comp_elem.type == item_here2 ) { if( quantity_here2 >= remainder ) { - final_map.push_back( std::make_tuple( pos_here2, item_here2, remainder ) ); + final_map.emplace_back( pos_here2, item_here2, remainder ); line_found = true; } else { - final_map.push_back( std::make_tuple( pos_here2, item_here2, remainder ) ); + final_map.emplace_back( pos_here2, item_here2, remainder ); remainder -= quantity_here2; } } @@ -1604,7 +1604,7 @@ static std::vector> requirements_map( player item test_item = item( item_here, calendar::turn_zero ); if( test_item.has_quality( tool_qual, qual_level ) ) { // it's just this spot that can fulfil the requirement on its own - final_map.push_back( std::make_tuple( pos_here, item_here, 1 ) ); + final_map.emplace_back( pos_here, item_here, 1 ); line_found = true; break; } @@ -2002,14 +2002,14 @@ void activity_on_turn_move_loot( player_activity &act, player &p ) src_veh = &vp->vehicle(); src_part = vp->part_index(); for( auto &it : src_veh->get_items( src_part ) ) { - items.push_back( std::make_pair( &it, true ) ); + items.emplace_back( &it, true ); } } else { src_veh = nullptr; src_part = -1; } for( item &it : here.i_at( src_loc ) ) { - items.push_back( std::make_pair( &it, false ) ); + items.emplace_back( &it, false ); } //Skip items that have already been processed @@ -2158,7 +2158,7 @@ static bool mine_activity( player &p, const tripoint &src_loc ) moves /= 2; } p.assign_activity( powered ? ACT_JACKHAMMER : ACT_PICKAXE, moves ); - p.activity.targets.push_back( item_location( p, chosen_item ) ); + p.activity.targets.emplace_back( p, chosen_item ); p.activity.placement = here.getabs( src_loc ); return true; @@ -2648,7 +2648,7 @@ static bool generic_multi_activity_do( player &p, const activity_id &act_id, item *best_rod = p.best_quality_item( qual_FISHING ); p.assign_activity( ACT_FISH, to_moves( 5_hours ), 0, 0, best_rod->tname() ); - p.activity.targets.push_back( item_location( p, best_rod ) ); + p.activity.targets.emplace_back( p, best_rod ); p.activity.coord_set = g->get_fishable_locations( ACTIVITY_SEARCH_DISTANCE, src_loc ); return false; } else if( reason == do_activity_reason::NEEDS_MINING ) { diff --git a/src/armor_layers.cpp b/src/armor_layers.cpp index 7883df1a5f18b..65583dffff262 100644 --- a/src/armor_layers.cpp +++ b/src/armor_layers.cpp @@ -330,40 +330,40 @@ std::vector clothing_flags_description( const item &worn_item ) std::vector description_stack; if( worn_item.has_flag( flag_FIT ) ) { - description_stack.push_back( _( "It fits you well." ) ); + description_stack.emplace_back( _( "It fits you well." ) ); } else if( worn_item.has_flag( flag_VARSIZE ) ) { - description_stack.push_back( _( "It could be refitted." ) ); + description_stack.emplace_back( _( "It could be refitted." ) ); } if( worn_item.has_flag( flag_HOOD ) ) { - description_stack.push_back( _( "It has a hood." ) ); + description_stack.emplace_back( _( "It has a hood." ) ); } if( worn_item.has_flag( flag_POCKETS ) ) { - description_stack.push_back( _( "It has pockets." ) ); + description_stack.emplace_back( _( "It has pockets." ) ); } if( worn_item.has_flag( flag_WATERPROOF ) ) { - description_stack.push_back( _( "It is waterproof." ) ); + description_stack.emplace_back( _( "It is waterproof." ) ); } if( worn_item.has_flag( flag_WATER_FRIENDLY ) ) { - description_stack.push_back( _( "It is water friendly." ) ); + description_stack.emplace_back( _( "It is water friendly." ) ); } if( worn_item.has_flag( flag_FANCY ) ) { - description_stack.push_back( _( "It looks fancy." ) ); + description_stack.emplace_back( _( "It looks fancy." ) ); } if( worn_item.has_flag( flag_SUPER_FANCY ) ) { - description_stack.push_back( _( "It looks really fancy." ) ); + description_stack.emplace_back( _( "It looks really fancy." ) ); } if( worn_item.has_flag( flag_FLOTATION ) ) { - description_stack.push_back( _( "You will not drown today." ) ); + description_stack.emplace_back( _( "You will not drown today." ) ); } if( worn_item.has_flag( flag_OVERSIZE ) ) { - description_stack.push_back( _( "It is very bulky." ) ); + description_stack.emplace_back( _( "It is very bulky." ) ); } if( worn_item.has_flag( flag_SWIM_GOGGLES ) ) { - description_stack.push_back( _( "It helps you to see clearly underwater." ) ); + description_stack.emplace_back( _( "It helps you to see clearly underwater." ) ); } if( worn_item.has_flag( flag_SEMITANGIBLE ) ) { - description_stack.push_back( _( "It can occupy the same space as other things." ) ); + description_stack.emplace_back( _( "It can occupy the same space as other things." ) ); } return description_stack; diff --git a/src/avatar.cpp b/src/avatar.cpp index a71170d7a4be0..21fb23ce969ed 100644 --- a/src/avatar.cpp +++ b/src/avatar.cpp @@ -745,11 +745,11 @@ void avatar::do_read( item &book ) player *n = g->find_npc( character_id( activity.values[i] ) ); if( n != nullptr ) { const std::string &s = activity.get_str_value( i, "1" ); - learners.push_back( { n, strtod( s.c_str(), nullptr ) } ); + learners.emplace_back( n, strtod( s.c_str(), nullptr ) ); } // Otherwise they must have died/teleported or something } - learners.push_back( { this, 1.0 } ); + learners.emplace_back( this, 1.0 ); //whether to continue reading or not bool continuous = false; // NPCs who learned a little about the skill diff --git a/src/bionics.cpp b/src/bionics.cpp index e80aaff137285..a064a5ce3877e 100644 --- a/src/bionics.cpp +++ b/src/bionics.cpp @@ -2199,13 +2199,13 @@ bool Character::uninstall_bionic( const bionic_id &b_id, player &installer, bool activity.values.push_back( success ); activity.values.push_back( units::to_kilojoule( b_id->capacity ) ); activity.values.push_back( pl_skill ); - activity.str_values.push_back( "uninstall" ); + activity.str_values.emplace_back( "uninstall" ); activity.str_values.push_back( b_id.str() ); - activity.str_values.push_back( "" ); // installer_name is unused for uninstall + activity.str_values.emplace_back( "" ); // installer_name is unused for uninstall if( autodoc ) { - activity.str_values.push_back( "true" ); + activity.str_values.emplace_back( "true" ); } else { - activity.str_values.push_back( "false" ); + activity.str_values.emplace_back( "false" ); } for( const std::pair &elem : b_id->occupied_bodyparts ) { add_effect( effect_under_operation, difficulty * 20_minutes, elem.first.id(), true, difficulty ); @@ -2486,18 +2486,18 @@ bool Character::install_bionics( const itype &type, player &installer, bool auto activity.values.push_back( success ); activity.values.push_back( units::to_millijoule( bioid->capacity ) ); activity.values.push_back( pl_skill ); - activity.str_values.push_back( "install" ); + activity.str_values.emplace_back( "install" ); activity.str_values.push_back( bioid.str() ); if( installer.has_trait( trait_PROF_MED ) || installer.has_trait( trait_PROF_AUTODOC ) ) { activity.str_values.push_back( installer.disp_name( true ) ); } else { - activity.str_values.push_back( "NOT_MED" ); + activity.str_values.emplace_back( "NOT_MED" ); } if( autodoc ) { - activity.str_values.push_back( "true" ); + activity.str_values.emplace_back( "true" ); } else { - activity.str_values.push_back( "false" ); + activity.str_values.emplace_back( "false" ); } for( const std::pair &elem : bioid->occupied_bodyparts ) { add_effect( effect_under_operation, difficulty * 20_minutes, elem.first.id(), true, difficulty ); diff --git a/src/bionics_ui.cpp b/src/bionics_ui.cpp index f02653a929e2a..96c6b08f17428 100644 --- a/src/bionics_ui.cpp +++ b/src/bionics_ui.cpp @@ -314,10 +314,10 @@ static std::string build_bionic_poweronly_string( const bionic &bio ) bio_data.charge_time ) ); } if( bio_data.has_flag( STATIC( json_character_flag( "BIONIC_TOGGLED" ) ) ) ) { - properties.push_back( bio.powered ? _( "ON" ) : _( "OFF" ) ); + properties.emplace_back( bio.powered ? _( "ON" ) : _( "OFF" ) ); } if( bio.incapacitated_time > 0_turns ) { - properties.push_back( _( "(incapacitated)" ) ); + properties.emplace_back( _( "(incapacitated)" ) ); } if( bio.get_safe_fuel_thresh() > 0 && ( !bio.info().fuel_opts.empty() || bio.info().is_remote_fueled ) ) { diff --git a/src/character.cpp b/src/character.cpp index fee731b93ed91..7760f9e5c955e 100644 --- a/src/character.cpp +++ b/src/character.cpp @@ -3496,7 +3496,7 @@ std::vector Character::find_reloadables() node->remaining_ammo_capacity() > 0; } if( reloadable ) { - reloadables.push_back( item_location( *this, node ) ); + reloadables.emplace_back( *this, node ); } return VisitResponse::NEXT; } ); diff --git a/src/clzones.cpp b/src/clzones.cpp index 177fc14c0bd1c..1e4c5319441cb 100644 --- a/src/clzones.cpp +++ b/src/clzones.cpp @@ -1240,7 +1240,7 @@ void zone_manager::zone_edited( zone_data &zone ) } } //Add it to the list of changed zones - changed_vzones.push_back( std::make_pair( zone_data( zone ), &zone ) ); + changed_vzones.emplace_back( zone_data( zone ), &zone ); } } diff --git a/src/construction.cpp b/src/construction.cpp index 9b6ebf9726bc2..d083073c34a9d 100644 --- a/src/construction.cpp +++ b/src/construction.cpp @@ -519,7 +519,7 @@ construction_id construction_menu( const bool blueprint ) } current_buffer_location += construct_buffers[i].size(); if( i < construct_buffers.size() - 1 ) { - full_construct_buffer.push_back( std::string() ); + full_construct_buffer.emplace_back( ); current_buffer_location++; } } @@ -1781,7 +1781,7 @@ void finalize_constructions() if( !vp.has_flag( flag_INITIAL_PART ) ) { continue; } - frame_items.push_back( item_comp( vp.base_item, 1 ) ); + frame_items.emplace_back( vp.base_item, 1 ); } if( frame_items.empty() ) { diff --git a/src/crafting.cpp b/src/crafting.cpp index c50a5c541994d..6b2c8ff1c2f47 100644 --- a/src/crafting.cpp +++ b/src/crafting.cpp @@ -2317,7 +2317,7 @@ void Character::disassemble_all( bool one_pass ) bool found_any = false; std::vector to_disassemble; for( item &it : get_map().i_at( pos() ) ) { - to_disassemble.push_back( item_location( map_cursor( pos() ), &it ) ); + to_disassemble.emplace_back( map_cursor( pos() ), &it ); } for( item_location &it_loc : to_disassemble ) { // Prevent disassembling an in process disassembly because it could have been created by a previous iteration of this loop diff --git a/src/crafting_gui.cpp b/src/crafting_gui.cpp index a5629e5723052..dc8ea31b791f0 100644 --- a/src/crafting_gui.cpp +++ b/src/crafting_gui.cpp @@ -680,7 +680,7 @@ const recipe *select_crafting_recipe( int &batch_size_out ) current.clear(); for( int i = 1; i <= 50; i++ ) { current.push_back( chosen ); - available.push_back( availability( chosen, i ) ); + available.emplace_back( chosen, i ); } } else { static_popup popup; @@ -1091,7 +1091,7 @@ std::string peek_related_recipe( const recipe *current, const recipe_subset &ava const requirement_data &req = current->simple_requirements(); for( const std::vector &comp_list : req.get_components() ) { for( const item_comp &a : comp_list ) { - related_components.push_back( { a.type, item::nname( a.type, 1 ) } ); + related_components.emplace_back( a.type, item::nname( a.type, 1 ) ); } } std::sort( related_components.begin(), related_components.end(), compare_second ); @@ -1104,7 +1104,7 @@ std::string peek_related_recipe( const recipe *current, const recipe_subset &ava get_player_character().get_learned_recipes().of_component( tid ); for( const auto &b : known_recipes ) { if( available.contains( b ) ) { - related_results.push_back( { b->result(), b->result_name() } ); + related_results.emplace_back( b->result(), b->result_name() ); } } std::stable_sort( related_results.begin(), related_results.end(), compare_second ); diff --git a/src/creature.cpp b/src/creature.cpp index 6d8a4f4651fc0..583b9ec6ceb60 100644 --- a/src/creature.cpp +++ b/src/creature.cpp @@ -1427,7 +1427,7 @@ void Creature::process_effects() // Add any effects that others remove to the removal list for( const auto &removed_effect : _it.second.get_removes_effects() ) { rem_ids.push_back( removed_effect ); - rem_bps.push_back( bodypart_str_id::NULL_ID() ); + rem_bps.emplace_back( bodypart_str_id::NULL_ID() ); } effect &e = _it.second; const int prev_int = e.get_intensity(); @@ -2115,7 +2115,7 @@ std::vector Creature::get_all_body_parts( get_body_part_flags flags if( only_main && elem.first->main_part != elem.first ) { continue; } - all_bps.push_back( elem.first ); + all_bps.emplace_back( elem.first ); } if( flags & get_body_part_flags::sorted ) { @@ -2596,11 +2596,11 @@ void Creature::describe_infrared( std::vector &buf ) const size_str = "invalid"; break; } - buf.push_back( _( "You see a figure radiating heat." ) ); + buf.emplace_back( _( "You see a figure radiating heat." ) ); buf.push_back( string_format( _( "It is %s in size." ), size_str ) ); } void Creature::describe_specials( std::vector &buf ) const { - buf.push_back( _( "You sense a creature here." ) ); + buf.emplace_back( _( "You sense a creature here." ) ); } diff --git a/src/debug_menu.cpp b/src/debug_menu.cpp index 850b391a78caf..ff26a6bef399e 100644 --- a/src/debug_menu.cpp +++ b/src/debug_menu.cpp @@ -1974,7 +1974,8 @@ static void debug_menu_game_state() std::vector> sorted; sorted.reserve( m_flag::MF_MAX ); for( int f = 0; f < m_flag::MF_MAX; f++ ) { - sorted.push_back( {static_cast( f ), MonsterGenerator::generator().m_flag_usage_stats[f]} ); + sorted.emplace_back( static_cast( f ), + MonsterGenerator::generator().m_flag_usage_stats[f] ); } std::sort( sorted.begin(), sorted.end(), []( std::pair a, std::pair b ) { return a.second != b.second ? a.second > b.second : a.first < b.first; diff --git a/src/dialogue_win.cpp b/src/dialogue_win.cpp index 7a8f6a3c331c6..2d7681d3fb623 100644 --- a/src/dialogue_win.cpp +++ b/src/dialogue_win.cpp @@ -71,7 +71,7 @@ size_t dialogue_window::add_to_history( const std::string &text ) // Empty line between lines of dialogue void dialogue_window::add_history_separator() { - history.push_back( "" ); + history.emplace_back( "" ); } void dialogue_window::print_history( const size_t hilight_lines ) diff --git a/src/editmap.cpp b/src/editmap.cpp index eeed0847399bc..e658635e93d46 100644 --- a/src/editmap.cpp +++ b/src/editmap.cpp @@ -2095,7 +2095,7 @@ void editmap::mapgen_retarget() for( int y = target.y - SEEY + 1; y < target.y + SEEY + 1; y++ ) { if( x == target.x - SEEX + 1 || x == target.x + SEEX || y == target.y - SEEY + 1 || y == target.y + SEEY ) { - target_list.push_back( tripoint( x, y, target.z ) ); + target_list.emplace_back( x, y, target.z ); } } } @@ -2161,7 +2161,7 @@ void editmap::edit_mapgen() for( int y = target.y - SEEY + 1; y < target.y + SEEY + 1; y++ ) { if( x == target.x - SEEX + 1 || x == target.x + SEEX || y == target.y - SEEY + 1 || y == target.y + SEEY ) { - target_list.push_back( tripoint( x, y, target.z ) ); + target_list.emplace_back( x, y, target.z ); } } } diff --git a/src/effect.cpp b/src/effect.cpp index fad0aae5fc147..e5d4b91774938 100644 --- a/src/effect.cpp +++ b/src/effect.cpp @@ -517,7 +517,7 @@ bool effect_type::load_decay_msgs( const JsonObject &jo, const std::string &memb } else { rate = m_neutral; } - decay_msgs.push_back( std::make_pair( msg, rate ) ); + decay_msgs.emplace_back( msg, rate ); } return true; } @@ -627,32 +627,32 @@ std::string effect::disp_desc( bool reduced ) const // place to add them. int val = 0; val = get_avg_mod( "PAIN", reduced ); - values.push_back( desc_freq( get_percentage( "PAIN", val, reduced ), val, _( "pain" ), - _( "pain" ) ) ); + values.emplace_back( get_percentage( "PAIN", val, reduced ), val, _( "pain" ), + _( "pain" ) ); val = get_avg_mod( "HURT", reduced ); - values.push_back( desc_freq( get_percentage( "HURT", val, reduced ), val, _( "damage" ), - _( "damage" ) ) ); + values.emplace_back( get_percentage( "HURT", val, reduced ), val, _( "damage" ), + _( "damage" ) ); val = get_avg_mod( "STAMINA", reduced ); - values.push_back( desc_freq( get_percentage( "STAMINA", val, reduced ), val, - _( "stamina recovery" ), _( "fatigue" ) ) ); + values.emplace_back( get_percentage( "STAMINA", val, reduced ), val, + _( "stamina recovery" ), _( "fatigue" ) ); val = get_avg_mod( "THIRST", reduced ); - values.push_back( desc_freq( get_percentage( "THIRST", val, reduced ), val, _( "thirst" ), - _( "quench" ) ) ); + values.emplace_back( get_percentage( "THIRST", val, reduced ), val, _( "thirst" ), + _( "quench" ) ); val = get_avg_mod( "HUNGER", reduced ); - values.push_back( desc_freq( get_percentage( "HUNGER", val, reduced ), val, _( "hunger" ), - _( "sate" ) ) ); + values.emplace_back( get_percentage( "HUNGER", val, reduced ), val, _( "hunger" ), + _( "sate" ) ); val = get_avg_mod( "FATIGUE", reduced ); - values.push_back( desc_freq( get_percentage( "FATIGUE", val, reduced ), val, _( "sleepiness" ), - _( "rest" ) ) ); + values.emplace_back( get_percentage( "FATIGUE", val, reduced ), val, _( "sleepiness" ), + _( "rest" ) ); val = get_avg_mod( "COUGH", reduced ); - values.push_back( desc_freq( get_percentage( "COUGH", val, reduced ), val, _( "coughing" ), - _( "coughing" ) ) ); + values.emplace_back( get_percentage( "COUGH", val, reduced ), val, _( "coughing" ), + _( "coughing" ) ); val = get_avg_mod( "VOMIT", reduced ); - values.push_back( desc_freq( get_percentage( "VOMIT", val, reduced ), val, _( "vomiting" ), - _( "vomiting" ) ) ); + values.emplace_back( get_percentage( "VOMIT", val, reduced ), val, _( "vomiting" ), + _( "vomiting" ) ); val = get_avg_mod( "SLEEP", reduced ); - values.push_back( desc_freq( get_percentage( "SLEEP", val, reduced ), val, _( "blackouts" ), - _( "blackouts" ) ) ); + values.emplace_back( get_percentage( "SLEEP", val, reduced ), val, _( "blackouts" ), + _( "blackouts" ) ); for( auto &i : values ) { if( i.val > 0 ) { @@ -1312,16 +1312,16 @@ void load_effect_type( const JsonObject &jo ) jo.read( "blood_analysis_description", new_etype.blood_analysis_description ); for( auto &&f : jo.get_string_array( "resist_traits" ) ) { // *NOPAD* - new_etype.resist_traits.push_back( trait_id( f ) ); + new_etype.resist_traits.emplace_back( f ); } for( auto &&f : jo.get_string_array( "resist_effects" ) ) { // *NOPAD* - new_etype.resist_effects.push_back( efftype_id( f ) ); + new_etype.resist_effects.emplace_back( f ); } for( auto &&f : jo.get_string_array( "removes_effects" ) ) { // *NOPAD* - new_etype.removes_effects.push_back( efftype_id( f ) ); + new_etype.removes_effects.emplace_back( f ); } for( auto &&f : jo.get_string_array( "blocks_effects" ) ) { // *NOPAD* - new_etype.blocks_effects.push_back( efftype_id( f ) ); + new_etype.blocks_effects.emplace_back( f ); } if( jo.has_string( "max_duration" ) ) { diff --git a/src/event_field_transformations.cpp b/src/event_field_transformations.cpp index 0dc6badbd3030..4699b19ac8a4e 100644 --- a/src/event_field_transformations.cpp +++ b/src/event_field_transformations.cpp @@ -60,7 +60,7 @@ static std::vector species_of_monster( const cata_variant &v ) std::vector result; result.reserve( species.size() ); for( const species_id &s : species ) { - result.push_back( cata_variant( s ) ); + result.emplace_back( s ); } return result; } diff --git a/src/faction_camp.cpp b/src/faction_camp.cpp index 30593e04732d9..06122ffd7d1a1 100644 --- a/src/faction_camp.cpp +++ b/src/faction_camp.cpp @@ -2783,10 +2783,10 @@ void basecamp::recruit_return( const std::string &task, int score ) description += _( "Select an option:" ); std::vector rec_options; - rec_options.push_back( _( "Increase Food" ) ); - rec_options.push_back( _( "Decrease Food" ) ); - rec_options.push_back( _( "Make Offer" ) ); - rec_options.push_back( _( "Not Interested" ) ); + rec_options.emplace_back( _( "Increase Food" ) ); + rec_options.emplace_back( _( "Decrease Food" ) ); + rec_options.emplace_back( _( "Make Offer" ) ); + rec_options.emplace_back( _( "Not Interested" ) ); rec_m = uilist( description, rec_options ); if( rec_m < 0 || rec_m == 3 || static_cast( rec_m ) >= rec_options.size() ) { @@ -3297,19 +3297,19 @@ void om_range_mark( const tripoint_abs_omt &origin, int range, bool add_notes, std::vector note_pts; //North Limit for( int x = origin.x() - range; x < origin.x() + range + 1; x++ ) { - note_pts.push_back( tripoint_abs_omt( x, origin.y() - range, origin.z() ) ); + note_pts.emplace_back( x, origin.y() - range, origin.z() ); } //South for( int x = origin.x() - range; x < origin.x() + range + 1; x++ ) { - note_pts.push_back( tripoint_abs_omt( x, origin.y() + range, origin.z() ) ); + note_pts.emplace_back( x, origin.y() + range, origin.z() ); } //West for( int y = origin.y() - range; y < origin.y() + range + 1; y++ ) { - note_pts.push_back( tripoint_abs_omt( origin.x() - range, y, origin.z() ) ); + note_pts.emplace_back( origin.x() - range, y, origin.z() ); } //East for( int y = origin.y() - range; y < origin.y() + range + 1; y++ ) { - note_pts.push_back( tripoint_abs_omt( origin.x() + range, y, origin.z() ) ); + note_pts.emplace_back( origin.x() + range, y, origin.z() ); } for( auto pt : note_pts ) { @@ -3541,7 +3541,7 @@ std::vector> talk_function::om_building std::string om_rnear_id = omt_rnear.id().c_str(); if( !purge || ( om_rnear_id.find( "faction_base_" ) != std::string::npos && om_rnear_id.find( "faction_base_camp" ) == std::string::npos ) ) { - om_camp_region.push_back( std::make_pair( om_rnear_id, omt_near_pos ) ); + om_camp_region.emplace_back( om_rnear_id, omt_near_pos ); } } return om_camp_region; diff --git a/src/game.cpp b/src/game.cpp index 67515c5555069..ecf9b621914f7 100644 --- a/src/game.cpp +++ b/src/game.cpp @@ -861,15 +861,15 @@ vehicle *game::place_vehicle_nearby( if( search_types.empty() ) { vehicle veh( id ); if( veh.max_ground_velocity() > 0 ) { - search_types.push_back( "road" ); - search_types.push_back( "field" ); + search_types.emplace_back( "road" ); + search_types.emplace_back( "field" ); } else if( veh.can_float() ) { - search_types.push_back( "river" ); - search_types.push_back( "lake" ); + search_types.emplace_back( "river" ); + search_types.emplace_back( "lake" ); } else { // some default locations - search_types.push_back( "road" ); - search_types.push_back( "field" ); + search_types.emplace_back( "road" ); + search_types.emplace_back( "field" ); } } for( const std::string &search_type : search_types ) { @@ -10130,7 +10130,7 @@ point game::place_player( const tripoint &dest_loc ) u.assign_activity( activity_id( "ACT_PULP" ), calendar::INDEFINITELY_LONG, 0 ); u.activity.placement = m.getabs( pos ); u.activity.auto_resume = true; - u.activity.str_values.push_back( "auto_pulp_no_acid" ); + u.activity.str_values.emplace_back( "auto_pulp_no_acid" ); return; } } @@ -12379,7 +12379,7 @@ game::Creature_range::Creature_range( game &game_ref ) : u( &game_ref.u, []( pla const auto &monsters = game_ref.critter_tracker->get_monsters_list(); items.insert( items.end(), monsters.begin(), monsters.end() ); items.insert( items.end(), game_ref.active_npc.begin(), game_ref.active_npc.end() ); - items.push_back( u ); + items.emplace_back( u ); } game::npc_range::npc_range( game &game_ref ) diff --git a/src/handle_liquid.cpp b/src/handle_liquid.cpp index dac6d78424828..cea3863606784 100644 --- a/src/handle_liquid.cpp +++ b/src/handle_liquid.cpp @@ -86,7 +86,7 @@ static void serialize_liquid_target( player_activity &act, const item_location & act.values.push_back( static_cast( liquid_target_type::CONTAINER ) ); act.values.push_back( 0 ); // dummy act.targets.push_back( container_item ); - act.coords.push_back( tripoint() ); // dummy + act.coords.emplace_back( ); // dummy } static void serialize_liquid_target( player_activity &act, const tripoint &pos ) diff --git a/src/iexamine.cpp b/src/iexamine.cpp index ea509725eafa1..473efc94fa581 100644 --- a/src/iexamine.cpp +++ b/src/iexamine.cpp @@ -748,7 +748,7 @@ class atm_menu // the next turn. Putting this here makes sure there will be something to be // done next turn. u.assign_activity( ACT_ATM, 0, transfer_all_money ); - u.activity.targets.push_back( item_location( u, dst ) ); + u.activity.targets.emplace_back( u, dst ); break; } // should we check for max capacity here? @@ -1341,7 +1341,7 @@ void iexamine::pit( player &p, const tripoint &examp ) return; } std::vector planks; - planks.push_back( item_comp( itype_2x4, 1 ) ); + planks.emplace_back( itype_2x4, 1 ); map &here = get_map(); if( query_yn( _( "Place a plank over the pit?" ) ) ) { @@ -3522,7 +3522,7 @@ void iexamine::tree_maple( player &p, const tripoint &examp ) } std::vector comps; - comps.push_back( item_comp( itype_tree_spile, 1 ) ); + comps.emplace_back( itype_tree_spile, 1 ); p.consume_items( comps, 1, is_crafting_component ); p.mod_moves( -to_moves( 20_seconds ) ); @@ -3989,7 +3989,7 @@ void iexamine::sign( player &p, const tripoint &examp ) } ); tools.reserve( filter.size() ); for( const item *writing_item : filter ) { - tools.push_back( tool_comp( writing_item->typeId(), 1 ) ); + tools.emplace_back( writing_item->typeId(), 1 ); } if( !tools.empty() ) { @@ -4714,9 +4714,9 @@ void iexamine::autodoc( player &p, const tripoint &examp ) } case 2: { std::vector choice_names; - choice_names.push_back( _( "Personality_Override" ) ); + choice_names.emplace_back( _( "Personality_Override" ) ); for( size_t i = 0; i < 6; i++ ) { - choice_names.push_back( _( "C0RR#PTED?D#TA" ) ); + choice_names.emplace_back( _( "C0RR#PTED?D#TA" ) ); } int choice_index = uilist( _( "Choose bionic to uninstall" ), choice_names ); if( choice_index == 0 ) { @@ -4795,7 +4795,7 @@ void iexamine::autodoc( player &p, const tripoint &examp ) } ); for( const item *anesthesia_item : a_filter ) { if( anesthesia_item->ammo_remaining() >= 1 ) { - anesth_kit.push_back( tool_comp( anesthesia_item->typeId(), 1 ) ); + anesth_kit.emplace_back( anesthesia_item->typeId(), 1 ); drug_count += anesthesia_item->ammo_remaining(); } } @@ -4825,7 +4825,7 @@ void iexamine::autodoc( player &p, const tripoint &examp ) if( !install_programs.empty() ) { has_install_program = true; - progs.push_back( item_comp( install_programs[0]->typeId(), 1 ) ); + progs.emplace_back( install_programs[0]->typeId(), 1 ); } const int weight = units::to_kilogram( patient.bodyweight() ) / 10; @@ -5385,7 +5385,7 @@ static void smoker_load_food( player &p, const tripoint &examp, entries.push_back( smokable_item ); } names.push_back( item::nname( smokable_item->typeId(), 1 ) ); - comps.push_back( item_comp( smokable_item->typeId(), count ) ); + comps.emplace_back( smokable_item->typeId(), count ); } } @@ -5434,7 +5434,7 @@ static void smoker_load_food( player &p, const tripoint &examp, // reload comps with chosen items and quantity comps.clear(); - comps.push_back( item_comp( what->typeId(), amount ) ); + comps.emplace_back( what->typeId(), amount ); Character &player_character = get_player_character(); // select from where to get the items from and place them @@ -5494,7 +5494,7 @@ static void mill_load_food( player &p, const tripoint &examp, entries.push_back( millable_item ); } names.push_back( item::nname( millable_item->typeId(), 1 ) ); - comps.push_back( item_comp( millable_item->typeId(), count ) ); + comps.emplace_back( millable_item->typeId(), count ); } } @@ -5543,7 +5543,7 @@ static void mill_load_food( player &p, const tripoint &examp, // reload comps with chosen items and quantity comps.clear(); - comps.push_back( item_comp( what->typeId(), amount ) ); + comps.emplace_back( what->typeId(), amount ); Character &player_character = get_player_character(); // select from where to get the items from and place them diff --git a/src/inventory_ui.cpp b/src/inventory_ui.cpp index 1f712504b272b..a0de6ee2ca11b 100644 --- a/src/inventory_ui.cpp +++ b/src/inventory_ui.cpp @@ -1044,8 +1044,8 @@ void inventory_column::draw( const catacurses::window &win, const point &p, const int hx_max = p.x + get_width() + contained_offset; inclusive_rectangle rect = inclusive_rectangle( point( x1, yy ), point( hx_max - 1, yy ) ); - rect_entry_map.push_back( std::pair, inventory_entry *>( rect, - &entry ) ); + rect_entry_map.emplace_back( rect, + &entry ); if( selected && visible_cells() > 1 ) { for( int hx = x1; hx < hx_max; ++hx ) { diff --git a/src/item.cpp b/src/item.cpp index 437450f384ad4..af31100f3a17d 100644 --- a/src/item.cpp +++ b/src/item.cpp @@ -1506,7 +1506,7 @@ void item::validate_ownership() const static void insert_separation_line( std::vector &info ) { if( info.empty() || info.back().sName != "--" ) { - info.push_back( iteminfo( "DESCRIPTION", "--" ) ); + info.emplace_back( "DESCRIPTION", "--" ); } } @@ -1673,7 +1673,7 @@ void item::basic_info( std::vector &info, const iteminfo_query *parts, []( const material_type * material ) { return string_format( "%s", material->name() ); }, enumeration_conjunction::none ); - info.push_back( iteminfo( "BASE", string_format( _( "Material: %s" ), material_list ) ) ); + info.emplace_back( "BASE", string_format( _( "Material: %s" ), material_list ) ); } } if( parts->test( iteminfo_parts::BASE_VOLUME ) ) { @@ -1684,18 +1684,18 @@ void item::basic_info( std::vector &info, const iteminfo_query *parts, info.back().bNewLine = true; } if( parts->test( iteminfo_parts::BASE_LENGTH ) && length() > 0_mm ) { - info.push_back( iteminfo( "BASE", _( "Length: " ), - string_format( " %s", length_units( length() ) ), - iteminfo::lower_is_better, - convert_length( length() ) ) ); + info.emplace_back( "BASE", _( "Length: " ), + string_format( " %s", length_units( length() ) ), + iteminfo::lower_is_better, + convert_length( length() ) ); } if( parts->test( iteminfo_parts::BASE_OWNER ) && !owner.is_null() ) { - info.push_back( iteminfo( "BASE", string_format( _( "Owner: %s" ), - _( get_owner_name() ) ) ) ); + info.emplace_back( "BASE", string_format( _( "Owner: %s" ), + _( get_owner_name() ) ) ); } if( parts->test( iteminfo_parts::BASE_CATEGORY ) ) { - info.push_back( iteminfo( "BASE", _( "Category: " ), - "
" + get_category_shallow().name() + "
" ) ); + info.emplace_back( "BASE", _( "Category: " ), + "
" + get_category_shallow().name() + "
" ); } if( parts->test( iteminfo_parts::DESCRIPTION ) ) { @@ -1705,16 +1705,16 @@ void item::basic_info( std::vector &info, const iteminfo_query *parts, const cata::optional snippet = SNIPPET.get_snippet_by_id( snip_id ); if( snippet.has_value() ) { // Just use the dynamic description - info.push_back( iteminfo( "DESCRIPTION", snippet.value().translated() ) ); + info.emplace_back( "DESCRIPTION", snippet.value().translated() ); } else if( idescription != item_vars.end() ) { - info.push_back( iteminfo( "DESCRIPTION", idescription->second ) ); + info.emplace_back( "DESCRIPTION", idescription->second ); } else if( has_gun_variant() ) { - info.push_back( iteminfo( "DESCRIPTION", gun_variant().alt_description.translated() ) ); + info.emplace_back( "DESCRIPTION", gun_variant().alt_description.translated() ); } else { if( has_flag( flag_MAGIC_FOCUS ) ) { - info.push_back( iteminfo( "DESCRIPTION", - _( "This item is a magical focus. " - "You can cast spells with it in your hand." ) ) ); + info.emplace_back( "DESCRIPTION", + _( "This item is a magical focus. " + "You can cast spells with it in your hand." ) ); } if( is_craft() ) { const std::string desc = ( typeId() == itype_disassembly ) ? @@ -1722,11 +1722,11 @@ void item::basic_info( std::vector &info, const iteminfo_query *parts, "It is %d percent complete." ) : _( "This is an in progress %s. " "It is %d percent complete." ); const int percent_progress = item_counter / 100000; - info.push_back( iteminfo( "DESCRIPTION", string_format( desc, - craft_data_->making->result_name(), - percent_progress ) ) ); + info.emplace_back( "DESCRIPTION", string_format( desc, + craft_data_->making->result_name(), + percent_progress ) ); } else { - info.push_back( iteminfo( "DESCRIPTION", type->description.translated() ) ); + info.emplace_back( "DESCRIPTION", type->description.translated() ); } } insert_separation_line( info ); @@ -1760,13 +1760,13 @@ void item::basic_info( std::vector &info, const iteminfo_query *parts, } if( has_var( "contained_name" ) && parts->test( iteminfo_parts::BASE_CONTENTS ) ) { - info.push_back( iteminfo( "BASE", string_format( _( "Contains: %s" ), - get_var( "contained_name" ) ) ) ); + info.emplace_back( "BASE", string_format( _( "Contains: %s" ), + get_var( "contained_name" ) ) ); } if( count_by_charges() && !is_food() && !is_medication() && parts->test( iteminfo_parts::BASE_AMOUNT ) ) { - info.push_back( iteminfo( "BASE", _( "Amount: " ), "", iteminfo::no_flags, - charges * batch ) ); + info.emplace_back( "BASE", _( "Amount: " ), "", iteminfo::no_flags, + charges * batch ); } } @@ -1775,66 +1775,66 @@ void item::debug_info( std::vector &info, const iteminfo_query *parts, { if( debug && parts->test( iteminfo_parts::BASE_DEBUG ) ) { if( g != nullptr ) { - info.push_back( iteminfo( "BASE", string_format( "itype_id: %s", - typeId().str() ) ) ); + info.emplace_back( "BASE", string_format( "itype_id: %s", + typeId().str() ) ); if( !old_owner.is_null() ) { - info.push_back( iteminfo( "BASE", string_format( _( "Old owner: %s" ), - _( get_old_owner_name() ) ) ) ); - } - info.push_back( iteminfo( "BASE", _( "age (hours): " ), "", iteminfo::lower_is_better, - to_hours( age() ) ) ); - info.push_back( iteminfo( "BASE", _( "charges: " ), "", iteminfo::lower_is_better, - charges ) ); - info.push_back( iteminfo( "BASE", _( "damage: " ), "", iteminfo::lower_is_better, - damage_ ) ); - info.push_back( iteminfo( "BASE", _( "active: " ), "", iteminfo::lower_is_better, - active ) ); - info.push_back( iteminfo( "BASE", _( "burn: " ), "", iteminfo::lower_is_better, - burnt ) ); + info.emplace_back( "BASE", string_format( _( "Old owner: %s" ), + _( get_old_owner_name() ) ) ); + } + info.emplace_back( "BASE", _( "age (hours): " ), "", iteminfo::lower_is_better, + to_hours( age() ) ); + info.emplace_back( "BASE", _( "charges: " ), "", iteminfo::lower_is_better, + charges ); + info.emplace_back( "BASE", _( "damage: " ), "", iteminfo::lower_is_better, + damage_ ); + info.emplace_back( "BASE", _( "active: " ), "", iteminfo::lower_is_better, + active ); + info.emplace_back( "BASE", _( "burn: " ), "", iteminfo::lower_is_better, + burnt ); const std::string tags_listed = enumerate_as_string( item_tags, []( const flag_id & f ) { return f.str(); }, enumeration_conjunction::none ); - info.push_back( iteminfo( "BASE", string_format( _( "tags: %s" ), tags_listed ) ) ); + info.emplace_back( "BASE", string_format( _( "tags: %s" ), tags_listed ) ); for( auto const &imap : item_vars ) { - info.push_back( iteminfo( "BASE", - string_format( _( "item var: %s, %s" ), imap.first, - imap.second ) ) ); + info.emplace_back( "BASE", + string_format( _( "item var: %s, %s" ), imap.first, + imap.second ) ); } const std::string space = " "; if( goes_bad() ) { - info.push_back( iteminfo( "BASE", _( "age (turns): " ), - "", iteminfo::lower_is_better, - to_turns( age() ) ) ); - info.push_back( iteminfo( "BASE", _( "rot (turns): " ), - "", iteminfo::lower_is_better, - to_turns( rot ) ) ); - info.push_back( iteminfo( "BASE", space + _( "max rot (turns): " ), - "", iteminfo::lower_is_better, - to_turns( get_shelf_life() ) ) ); + info.emplace_back( "BASE", _( "age (turns): " ), + "", iteminfo::lower_is_better, + to_turns( age() ) ); + info.emplace_back( "BASE", _( "rot (turns): " ), + "", iteminfo::lower_is_better, + to_turns( rot ) ); + info.emplace_back( "BASE", space + _( "max rot (turns): " ), + "", iteminfo::lower_is_better, + to_turns( get_shelf_life() ) ); } if( has_temperature() ) { - info.push_back( iteminfo( "BASE", _( "last temp: " ), - "", iteminfo::lower_is_better, - to_turn( last_temp_check ) ) ); - info.push_back( iteminfo( "BASE", _( "Temp: " ), "", iteminfo::lower_is_better, - temperature ) ); - info.push_back( iteminfo( "BASE", _( "Spec ener: " ), "", - iteminfo::lower_is_better, - specific_energy ) ); - info.push_back( iteminfo( "BASE", _( "Spec heat lq: " ), "", - iteminfo::lower_is_better | iteminfo::is_decimal, - get_specific_heat_liquid() ) ); - info.push_back( iteminfo( "BASE", _( "Spec heat sld: " ), "", - iteminfo::lower_is_better | iteminfo::is_decimal, - get_specific_heat_solid() ) ); - info.push_back( iteminfo( "BASE", _( "latent heat: " ), "", - iteminfo::lower_is_better, - get_latent_heat() ) ); - info.push_back( iteminfo( "BASE", _( "Freeze point: " ), "", - iteminfo::lower_is_better | iteminfo::is_decimal, - get_freeze_point() ) ); + info.emplace_back( "BASE", _( "last temp: " ), + "", iteminfo::lower_is_better, + to_turn( last_temp_check ) ); + info.emplace_back( "BASE", _( "Temp: " ), "", iteminfo::lower_is_better, + temperature ); + info.emplace_back( "BASE", _( "Spec ener: " ), "", + iteminfo::lower_is_better, + specific_energy ); + info.emplace_back( "BASE", _( "Spec heat lq: " ), "", + iteminfo::lower_is_better | iteminfo::is_decimal, + get_specific_heat_liquid() ); + info.emplace_back( "BASE", _( "Spec heat sld: " ), "", + iteminfo::lower_is_better | iteminfo::is_decimal, + get_specific_heat_solid() ); + info.emplace_back( "BASE", _( "latent heat: " ), "", + iteminfo::lower_is_better, + get_latent_heat() ); + info.emplace_back( "BASE", _( "Freeze point: " ), "", + iteminfo::lower_is_better | iteminfo::is_decimal, + get_freeze_point() ); } } } @@ -1845,29 +1845,29 @@ void item::med_info( const item *med_item, std::vector &info, const it { const cata::value_ptr &med_com = med_item->get_comestible(); if( med_com->quench != 0 && parts->test( iteminfo_parts::MED_QUENCH ) ) { - info.push_back( iteminfo( "MED", _( "Quench: " ), med_com->quench ) ); + info.emplace_back( "MED", _( "Quench: " ), med_com->quench ); } Character &player_character = get_player_character(); if( med_item->get_comestible_fun() != 0 && parts->test( iteminfo_parts::MED_JOY ) ) { - info.push_back( iteminfo( "MED", _( "Enjoyability: " ), - player_character.fun_for( *med_item ).first ) ); + info.emplace_back( "MED", _( "Enjoyability: " ), + player_character.fun_for( *med_item ).first ); } if( med_com->stim != 0 && parts->test( iteminfo_parts::MED_STIMULATION ) ) { std::string name = string_format( "%s %s", _( "Stimulation:" ), med_com->stim > 0 ? _( "Upper" ) : _( "Downer" ) ); - info.push_back( iteminfo( "MED", name ) ); + info.emplace_back( "MED", name ); } if( parts->test( iteminfo_parts::MED_PORTIONS ) ) { - info.push_back( iteminfo( "MED", _( "Portions: " ), - std::abs( static_cast( med_item->charges ) * batch ) ) ); + info.emplace_back( "MED", _( "Portions: " ), + std::abs( static_cast( med_item->charges ) * batch ) ); } if( parts->test( iteminfo_parts::MED_CONSUME_TIME ) ) { - info.push_back( iteminfo( "MED", _( "Consume time: " ), - to_string( player_character.get_consume_time( *med_item ) ) ) ); + info.emplace_back( "MED", _( "Consume time: " ), + to_string( player_character.get_consume_time( *med_item ) ) ); } if( med_com->addict && parts->test( iteminfo_parts::DESCRIPTION_MED_ADDICTING ) ) { @@ -1904,51 +1904,51 @@ void item::food_info( const item *food_item, std::vector &info, 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, min_nutr.kcal() ) ); + info.emplace_back( "FOOD", _( "Calories (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() ) ); + info.emplace_back( "FOOD", _( "-" ), + "", iteminfo::no_newline, max_nutr.kcal() ); } } if( parts->test( iteminfo_parts::FOOD_QUENCH ) ) { const std::string space = " "; - info.push_back( iteminfo( "FOOD", space + _( "Quench: " ), - food_item->get_comestible()->quench ) ); + info.emplace_back( "FOOD", space + _( "Quench: " ), + food_item->get_comestible()->quench ); } if( parts->test( iteminfo_parts::FOOD_SATIATION ) ) { if( max_nutr.kcal() == min_nutr.kcal() ) { - info.push_back( iteminfo( "FOOD", _( "Satiety: " ), - satiety_bar( player_character.compute_calories_per_effective_volume( *food_item ) ) ) ); + info.emplace_back( "FOOD", _( "Satiety: " ), + satiety_bar( player_character.compute_calories_per_effective_volume( *food_item ) ) ); } else { - info.push_back( iteminfo( "FOOD", _( "Satiety: " ), - satiety_bar( player_character.compute_calories_per_effective_volume( *food_item, &min_nutr ) ), - iteminfo::no_newline - ) ); - info.push_back( iteminfo( "FOOD", _( " - " ), - satiety_bar( player_character.compute_calories_per_effective_volume( *food_item, &max_nutr ) ) ) ); + info.emplace_back( "FOOD", _( "Satiety: " ), + satiety_bar( player_character.compute_calories_per_effective_volume( *food_item, &min_nutr ) ), + iteminfo::no_newline + ); + info.emplace_back( "FOOD", _( " - " ), + satiety_bar( player_character.compute_calories_per_effective_volume( *food_item, &max_nutr ) ) ); } } } const std::pair fun_for_food_item = player_character.fun_for( *food_item ); if( fun_for_food_item.first != 0 && parts->test( iteminfo_parts::FOOD_JOY ) ) { - info.push_back( iteminfo( "FOOD", _( "Enjoyability: " ), fun_for_food_item.first ) ); + info.emplace_back( "FOOD", _( "Enjoyability: " ), fun_for_food_item.first ); } if( parts->test( iteminfo_parts::FOOD_PORTIONS ) ) { - info.push_back( iteminfo( "FOOD", _( "Portions: " ), - std::abs( static_cast( food_item->charges ) * batch ) ) ); + info.emplace_back( "FOOD", _( "Portions: " ), + std::abs( static_cast( food_item->charges ) * batch ) ); } if( food_item->corpse != nullptr && parts->test( iteminfo_parts::FOOD_SMELL ) && ( debug || ( g != nullptr && player_character.has_trait( trait_CARNIVORE ) ) ) ) { - info.push_back( iteminfo( "FOOD", _( "Smells like: " ) + food_item->corpse->nname() ) ); + info.emplace_back( "FOOD", _( "Smells like: " ) + food_item->corpse->nname() ); } if( parts->test( iteminfo_parts::FOOD_CONSUME_TIME ) ) { - info.push_back( iteminfo( "FOOD", _( "Consume time: " ), - to_string( player_character.get_consume_time( *food_item ) ) ) ); + info.emplace_back( "FOOD", _( "Consume time: " ), + to_string( player_character.get_consume_time( *food_item ) ) ); } auto format_vitamin = [&]( const std::pair &v, bool display_vitamins ) { @@ -2062,19 +2062,19 @@ void item::food_info( const item *food_item, std::vector &info, } if( food_item->rotten() ) { if( player_character.has_bionic( bio_digestion ) ) { - info.push_back( iteminfo( "DESCRIPTION", - _( "This food has started to rot, " - "but your bionic digestion can tolerate " - "it." ) ) ); + info.emplace_back( "DESCRIPTION", + _( "This food has started to rot, " + "but your bionic digestion can tolerate " + "it." ) ); } else if( player_character.has_flag( json_flag_IMMUNE_SPOIL ) ) { - info.push_back( iteminfo( "DESCRIPTION", - _( "This food has started to rot, " - "but you can tolerate it." ) ) ); + info.emplace_back( "DESCRIPTION", + _( "This food has started to rot, " + "but you can tolerate it." ) ); } else { - info.push_back( iteminfo( "DESCRIPTION", - _( "This food has started to rot. " - "Eating it would be a very bad " - "idea." ) ) ); + info.emplace_back( "DESCRIPTION", + _( "This food has started to rot. " + "Eating it would be a very bad " + "idea." ) ); } } } @@ -2267,8 +2267,8 @@ void item::gun_info( const item *mod, std::vector &info, const iteminf if( parts->test( iteminfo_parts::GUN_DAMAGE ) ) { insert_separation_line( info ); - info.push_back( iteminfo( "GUN", _( "Ranged damage: " ), "", iteminfo::no_newline, - mod->gun_damage( false ).total_damage() ) ); + info.emplace_back( "GUN", _( "Ranged damage: " ), "", iteminfo::no_newline, + mod->gun_damage( false ).total_damage() ); } if( mod->ammo_required() ) { @@ -2279,36 +2279,36 @@ void item::gun_info( const item *mod, std::vector &info, const iteminf } if( dmg_mult != 1.0f ) { if( parts->test( iteminfo_parts::GUN_DAMAGE_AMMOPROP ) ) { - info.push_back( iteminfo( "GUN", "ammo_mult", "*", - iteminfo::no_newline | iteminfo::no_name | iteminfo::is_decimal, dmg_mult ) ); + info.emplace_back( "GUN", "ammo_mult", "*", + iteminfo::no_newline | iteminfo::no_name | iteminfo::is_decimal, dmg_mult ); } } else { if( parts->test( iteminfo_parts::GUN_DAMAGE_LOADEDAMMO ) ) { damage_instance ammo_dam = curammo->ammo->damage; - info.push_back( iteminfo( "GUN", "ammo_damage", "", - iteminfo::no_newline | iteminfo::no_name | - iteminfo::show_plus, ammo_dam.total_damage() ) ); + info.emplace_back( "GUN", "ammo_damage", "", + iteminfo::no_newline | iteminfo::no_name | + iteminfo::show_plus, ammo_dam.total_damage() ); } } if( damage_level() > 0 ) { int dmg_penalty = damage_level() * -2; - info.push_back( iteminfo( "GUN", "damaged_weapon_penalty", "", - iteminfo::no_newline | iteminfo::no_name, dmg_penalty ) ); + info.emplace_back( "GUN", "damaged_weapon_penalty", "", + iteminfo::no_newline | iteminfo::no_name, dmg_penalty ); } if( parts->test( iteminfo_parts::GUN_DAMAGE_TOTAL ) ) { - info.push_back( iteminfo( "GUN", "sum_of_damage", _( " = " ), - iteminfo::no_newline | iteminfo::no_name, - loaded_mod->gun_damage( true ).total_damage() ) ); + info.emplace_back( "GUN", "sum_of_damage", _( " = " ), + iteminfo::no_newline | iteminfo::no_name, + loaded_mod->gun_damage( true ).total_damage() ); } } info.back().bNewLine = true; if( mod->ammo_required() && curammo->ammo->critical_multiplier != 1.0 ) { if( parts->test( iteminfo_parts::AMMO_DAMAGE_CRIT_MULTIPLIER ) ) { - info.push_back( iteminfo( "GUN", _( "Critical multiplier: " ), "", - iteminfo::no_flags, curammo->ammo->critical_multiplier ) ); + info.emplace_back( "GUN", _( "Critical multiplier: " ), "", + iteminfo::no_flags, curammo->ammo->critical_multiplier ); } } @@ -2322,43 +2322,43 @@ void item::gun_info( const item *mod, std::vector &info, const iteminf // TODO: This doesn't cover multiple damage types if( parts->test( iteminfo_parts::GUN_ARMORPIERCE ) ) { - info.push_back( iteminfo( "GUN", _( "Armor-pierce: " ), "", - iteminfo::no_newline, get_ranged_pierce( gun ) ) ); + info.emplace_back( "GUN", _( "Armor-pierce: " ), "", + iteminfo::no_newline, get_ranged_pierce( gun ) ); } if( mod->ammo_required() ) { int ammo_pierce = get_ranged_pierce( *curammo->ammo ); // ammo_armor_pierce and sum_of_armor_pierce don't need to translate. if( parts->test( iteminfo_parts::GUN_ARMORPIERCE_LOADEDAMMO ) ) { - info.push_back( iteminfo( "GUN", "ammo_armor_pierce", "", - iteminfo::no_newline | iteminfo::no_name | - iteminfo::show_plus, ammo_pierce ) ); + info.emplace_back( "GUN", "ammo_armor_pierce", "", + iteminfo::no_newline | iteminfo::no_name | + iteminfo::show_plus, ammo_pierce ); } if( parts->test( iteminfo_parts::GUN_ARMORPIERCE_TOTAL ) ) { - info.push_back( iteminfo( "GUN", "sum_of_armor_pierce", _( " = " ), - iteminfo::no_name, - get_ranged_pierce( gun ) + ammo_pierce ) ); + info.emplace_back( "GUN", "sum_of_armor_pierce", _( " = " ), + iteminfo::no_name, + get_ranged_pierce( gun ) + ammo_pierce ); } } info.back().bNewLine = true; if( parts->test( iteminfo_parts::GUN_DISPERSION ) ) { - info.push_back( iteminfo( "GUN", _( "Dispersion: " ), "", - iteminfo::no_newline | iteminfo::lower_is_better, - mod->gun_dispersion( false, false ) ) ); + info.emplace_back( "GUN", _( "Dispersion: " ), "", + iteminfo::no_newline | iteminfo::lower_is_better, + mod->gun_dispersion( false, false ) ); } if( mod->ammo_required() ) { int ammo_dispersion = curammo->ammo->dispersion; // ammo_dispersion and sum_of_dispersion don't need to translate. if( parts->test( iteminfo_parts::GUN_DISPERSION_LOADEDAMMO ) ) { - info.push_back( iteminfo( "GUN", "ammo_dispersion", "", - iteminfo::no_newline | iteminfo::lower_is_better | - iteminfo::no_name | iteminfo::show_plus, - ammo_dispersion ) ); + info.emplace_back( "GUN", "ammo_dispersion", "", + iteminfo::no_newline | iteminfo::lower_is_better | + iteminfo::no_name | iteminfo::show_plus, + ammo_dispersion ); } if( parts->test( iteminfo_parts::GUN_DISPERSION_TOTAL ) ) { - info.push_back( iteminfo( "GUN", "sum_of_dispersion", _( " = " ), - iteminfo::lower_is_better | iteminfo::no_name, - loaded_mod->gun_dispersion( true, false ) ) ); + info.emplace_back( "GUN", "sum_of_dispersion", _( " = " ), + iteminfo::lower_is_better | iteminfo::no_name, + loaded_mod->gun_dispersion( true, false ) ); } } info.back().bNewLine = true; @@ -2369,17 +2369,17 @@ void item::gun_info( const item *mod, std::vector &info, const iteminf int adj_disp = eff_disp - act_disp; if( parts->test( iteminfo_parts::GUN_DISPERSION_SIGHT ) ) { - info.push_back( iteminfo( "GUN", _( "Sight dispersion: " ), "", - iteminfo::no_newline | iteminfo::lower_is_better, - act_disp ) ); + info.emplace_back( "GUN", _( "Sight dispersion: " ), "", + iteminfo::no_newline | iteminfo::lower_is_better, + act_disp ); if( adj_disp ) { - info.push_back( iteminfo( "GUN", "sight_adj_disp", "", - iteminfo::no_newline | iteminfo::lower_is_better | - iteminfo::no_name | iteminfo::show_plus, adj_disp ) ); - info.push_back( iteminfo( "GUN", "sight_eff_disp", _( " = " ), - iteminfo::lower_is_better | iteminfo::no_name, - eff_disp ) ); + info.emplace_back( "GUN", "sight_adj_disp", "", + iteminfo::no_newline | iteminfo::lower_is_better | + iteminfo::no_name | iteminfo::show_plus, adj_disp ); + info.emplace_back( "GUN", "sight_eff_disp", _( " = " ), + iteminfo::lower_is_better | iteminfo::no_name, + eff_disp ); } } @@ -2416,8 +2416,8 @@ void item::gun_info( const item *mod, std::vector &info, const iteminf } if( parts->test( iteminfo_parts::GUN_USEDSKILL ) ) { - info.push_back( iteminfo( "GUN", _( "Skill used: " ), - "" + skill.name() + "" ) ); + info.emplace_back( "GUN", _( "Skill used: " ), + "" + skill.name() + "" ); } if( mod->magazine_integral() || mod->magazine_current() ) { @@ -2542,7 +2542,7 @@ void item::gun_info( const item *mod, std::vector &info, const iteminf iternum++; } mod_str += "."; - info.push_back( iteminfo( "DESCRIPTION", mod_str ) ); + info.emplace_back( "DESCRIPTION", mod_str ); } if( mod->casings_count() && parts->test( iteminfo_parts::DESCRIPTION_GUN_CASINGS ) ) { @@ -2554,8 +2554,8 @@ void item::gun_info( const item *mod, std::vector &info, const iteminf if( is_gun() && has_flag( flag_FIRE_TWOHAND ) && parts->test( iteminfo_parts::DESCRIPTION_TWOHANDED ) ) { - info.push_back( iteminfo( "DESCRIPTION", - _( "This weapon needs two free hands to fire." ) ) ); + info.emplace_back( "DESCRIPTION", + _( "This weapon needs two free hands to fire." ) ); } } @@ -2568,52 +2568,52 @@ void item::gunmod_info( std::vector &info, const iteminfo_query *parts const islot_gunmod &mod = *type->gunmod; if( is_gun() && parts->test( iteminfo_parts::DESCRIPTION_GUNMOD ) ) { - info.push_back( iteminfo( "DESCRIPTION", - _( "This mod must be attached to a gun, " - "it can not be fired separately." ) ) ); + info.emplace_back( "DESCRIPTION", + _( "This mod must be attached to a gun, " + "it can not be fired separately." ) ); } if( has_flag( flag_REACH_ATTACK ) && parts->test( iteminfo_parts::DESCRIPTION_GUNMOD_REACH ) ) { - info.push_back( iteminfo( "DESCRIPTION", - _( "When attached to a gun, allows making " - "reach melee attacks with it." ) ) ); + info.emplace_back( "DESCRIPTION", + _( "When attached to a gun, allows making " + "reach melee attacks with it." ) ); } if( is_gunmod() && has_flag( flag_DISABLE_SIGHTS ) && parts->test( iteminfo_parts::DESCRIPTION_GUNMOD_DISABLESSIGHTS ) ) { - info.push_back( iteminfo( "DESCRIPTION", - _( "This mod obscures sights of the " - "base weapon." ) ) ); + info.emplace_back( "DESCRIPTION", + _( "This mod obscures sights of the " + "base weapon." ) ); } if( is_gunmod() && has_flag( flag_CONSUMABLE ) && parts->test( iteminfo_parts::DESCRIPTION_GUNMOD_CONSUMABLE ) ) { - info.push_back( iteminfo( "DESCRIPTION", - _( "This mod might suffer wear when firing " - "the base weapon." ) ) ); + info.emplace_back( "DESCRIPTION", + _( "This mod might suffer wear when firing " + "the base weapon." ) ); } if( mod.dispersion != 0 && parts->test( iteminfo_parts::GUNMOD_DISPERSION ) ) { - info.push_back( iteminfo( "GUNMOD", _( "Dispersion modifier: " ), "", - iteminfo::lower_is_better | iteminfo::show_plus, - mod.dispersion ) ); + info.emplace_back( "GUNMOD", _( "Dispersion modifier: " ), "", + iteminfo::lower_is_better | iteminfo::show_plus, + mod.dispersion ); } if( mod.sight_dispersion != -1 && parts->test( iteminfo_parts::GUNMOD_DISPERSION_SIGHT ) ) { - info.push_back( iteminfo( "GUNMOD", _( "Sight dispersion: " ), "", - iteminfo::lower_is_better, mod.sight_dispersion ) ); + info.emplace_back( "GUNMOD", _( "Sight dispersion: " ), "", + iteminfo::lower_is_better, mod.sight_dispersion ); } if( mod.aim_speed >= 0 && parts->test( iteminfo_parts::GUNMOD_AIMSPEED ) ) { - info.push_back( iteminfo( "GUNMOD", _( "Aim speed: " ), "", - iteminfo::no_flags, mod.aim_speed ) ); + info.emplace_back( "GUNMOD", _( "Aim speed: " ), "", + iteminfo::lower_is_better, mod.aim_speed ); } int total_damage = static_cast( mod.damage.total_damage() ); if( total_damage != 0 && parts->test( iteminfo_parts::GUNMOD_DAMAGE ) ) { - info.push_back( iteminfo( "GUNMOD", _( "Damage: " ), "", iteminfo::show_plus, - total_damage ) ); + info.emplace_back( "GUNMOD", _( "Damage: " ), "", iteminfo::show_plus, + total_damage ); } int pierce = get_ranged_pierce( mod ); if( get_ranged_pierce( mod ) != 0 && parts->test( iteminfo_parts::GUNMOD_ARMORPIERCE ) ) { - info.push_back( iteminfo( "GUNMOD", _( "Armor-pierce: " ), "", iteminfo::show_plus, - pierce ) ); + info.emplace_back( "GUNMOD", _( "Armor-pierce: " ), "", iteminfo::show_plus, + pierce ); } if( mod.handling != 0 && parts->test( iteminfo_parts::GUNMOD_HANDLING ) ) { info.emplace_back( "GUNMOD", _( "Handling modifier: " ), "", @@ -2621,8 +2621,8 @@ void item::gunmod_info( std::vector &info, const iteminfo_query *parts } if( !type->mod->ammo_modifier.empty() && parts->test( iteminfo_parts::GUNMOD_AMMO ) ) { for( const ammotype &at : type->mod->ammo_modifier ) { - info.push_back( iteminfo( "GUNMOD", string_format( _( "Ammo: %s" ), - at->name() ) ) ); + info.emplace_back( "GUNMOD", string_format( _( "Ammo: %s" ), + at->name() ) ); } } if( mod.reload_modifier != 0 && parts->test( iteminfo_parts::GUNMOD_RELOAD ) ) { @@ -2630,8 +2630,8 @@ void item::gunmod_info( std::vector &info, const iteminfo_query *parts iteminfo::lower_is_better, mod.reload_modifier ); } if( mod.min_str_required_mod > 0 && parts->test( iteminfo_parts::GUNMOD_STRENGTH ) ) { - info.push_back( iteminfo( "GUNMOD", _( "Minimum strength required modifier: " ), - mod.min_str_required_mod ) ); + info.emplace_back( "GUNMOD", _( "Minimum strength required modifier: " ), + mod.min_str_required_mod ); } if( !mod.add_mod.empty() && parts->test( iteminfo_parts::GUNMOD_ADD_MOD ) ) { insert_separation_line( info ); @@ -2649,7 +2649,7 @@ void item::gunmod_info( std::vector &info, const iteminfo_query *parts iternum++; } mod_loc_str += "."; - info.push_back( iteminfo( "GUNMOD", mod_loc_str ) ); + info.emplace_back( "GUNMOD", mod_loc_str ); } insert_separation_line( info ); @@ -2659,12 +2659,12 @@ void item::gunmod_info( std::vector &info, const iteminfo_query *parts enumerate_as_string( mod.usable.begin(), mod.usable.end(), []( const gun_type_type & used_on ) { return string_format( "%s", used_on.name() ); } ); - info.push_back( iteminfo( "GUNMOD", used_on_str ) ); + info.emplace_back( "GUNMOD", used_on_str ); } if( parts->test( iteminfo_parts::GUNMOD_LOCATION ) ) { - info.push_back( iteminfo( "GUNMOD", string_format( _( "Location: %s" ), - mod.location.name() ) ) ); + info.emplace_back( "GUNMOD", string_format( _( "Location: %s" ), + mod.location.name() ) ); } if( !mod.blacklist_mod.empty() && parts->test( iteminfo_parts::GUNMOD_BLACKLIST_MOD ) ) { @@ -2679,7 +2679,7 @@ void item::gunmod_info( std::vector &info, const iteminfo_query *parts iternum++; } mod_black_str += "."; - info.push_back( iteminfo( "GUNMOD", mod_black_str ) ); + info.emplace_back( "GUNMOD", mod_black_str ); } } @@ -2710,7 +2710,7 @@ void item::armor_encumbrance_info( std::vector &info, int reduce_encum } } - info.push_back( iteminfo( "ARMOR", _( "Encumbrance:" ) + format ) ); + info.emplace_back( "ARMOR", _( "Encumbrance:" ) + format ); if( const islot_armor *t = find_armor_data() ) { if( !t->data.empty() ) { @@ -2771,30 +2771,30 @@ void item::armor_encumbrance_info( std::vector &info, int reduce_encum } } if( piece.second.active ) { - info.push_back( iteminfo( "ARMOR", - string_format( _( "%s:" ), piece.second.to_display.translated() ) + space, "", - iteminfo::no_newline | iteminfo::lower_is_better, - piece.second.portion.encumber ) ); + info.emplace_back( "ARMOR", + string_format( _( "%s:" ), piece.second.to_display.translated() ) + space, "", + iteminfo::no_newline | iteminfo::lower_is_better, + piece.second.portion.encumber ); if( piece.second.portion.encumber != piece.second.portion.max_encumber ) { - info.push_back( iteminfo( "ARMOR", when_full_message, "", - iteminfo::no_newline | iteminfo::lower_is_better, - piece.second.portion.max_encumber ) ); + info.emplace_back( "ARMOR", when_full_message, "", + iteminfo::no_newline | iteminfo::lower_is_better, + piece.second.portion.max_encumber ); } - info.push_back( iteminfo( "ARMOR", coverage_message, "", - iteminfo::no_flags, - piece.second.portion.coverage ) ); + info.emplace_back( "ARMOR", coverage_message, "", + iteminfo::no_flags, + piece.second.portion.coverage ); } } } } else if( is_gun() && has_flag( flag_IS_ARMOR ) ) { //right now all eligible gunmods (shoulder_strap, belt_clip) have the is_armor flag and use the torso - info.push_back( iteminfo( "ARMOR", _( "Torso:" ) + space, "", - iteminfo::no_newline | iteminfo::lower_is_better, get_avg_encumber( get_avatar() ) ) ); + info.emplace_back( "ARMOR", _( "Torso:" ) + space, "", + iteminfo::no_newline | iteminfo::lower_is_better, get_avg_encumber( get_avatar() ) ); - info.push_back( iteminfo( "ARMOR", space + _( "Coverage:" ) + space, "", - iteminfo::no_flags, get_coverage( body_part_torso.id() ) ) ); + info.emplace_back( "ARMOR", space + _( "Coverage:" ) + space, "", + iteminfo::no_flags, get_coverage( body_part_torso.id() ) ); } } @@ -2808,36 +2808,36 @@ void item::armor_protection_info( std::vector &info, const iteminfo_qu if( parts->test( iteminfo_parts::ARMOR_PROTECTION ) ) { const std::string space = " "; - info.push_back( iteminfo( "ARMOR", _( "Protection: Bash: " ), "", - iteminfo::no_newline | iteminfo::is_decimal, bash_resist() ) ); - info.push_back( iteminfo( "ARMOR", space + _( "Cut: " ), "", - iteminfo::no_newline | iteminfo::is_decimal, cut_resist() ) ); - info.push_back( iteminfo( "ARMOR", space + _( "Ballistic: " ), "", iteminfo::is_decimal, - bullet_resist() ) ); - info.push_back( iteminfo( "ARMOR", space + _( "Acid: " ), "", - iteminfo::no_newline | iteminfo::is_decimal, acid_resist() ) ); - info.push_back( iteminfo( "ARMOR", space + _( "Fire: " ), "", - iteminfo::no_newline | iteminfo::is_decimal, fire_resist() ) ); - info.push_back( iteminfo( "ARMOR", space + _( "Environmental: " ), - get_base_env_resist( *this ) ) ); + info.emplace_back( "ARMOR", _( "Protection: Bash: " ), "", + iteminfo::no_newline | iteminfo::is_decimal, bash_resist() ); + info.emplace_back( "ARMOR", space + _( "Cut: " ), "", + iteminfo::no_newline | iteminfo::is_decimal, cut_resist() ); + info.emplace_back( "ARMOR", space + _( "Ballistic: " ), "", iteminfo::is_decimal, + bullet_resist() ); + info.emplace_back( "ARMOR", space + _( "Acid: " ), "", + iteminfo::no_newline | iteminfo::is_decimal, acid_resist() ); + info.emplace_back( "ARMOR", space + _( "Fire: " ), "", + iteminfo::no_newline | iteminfo::is_decimal, fire_resist() ); + info.emplace_back( "ARMOR", space + _( "Environmental: " ), + get_base_env_resist( *this ) ); if( type->can_use( "GASMASK" ) || type->can_use( "DIVE_TANK" ) ) { - info.push_back( iteminfo( "ARMOR", - _( "Protection when active: " ) ) ); - info.push_back( iteminfo( "ARMOR", space + _( "Acid: " ), "", - iteminfo::no_newline | iteminfo::is_decimal, - acid_resist( false, get_base_env_resist_w_filter() ) ) ); - info.push_back( iteminfo( "ARMOR", space + _( "Fire: " ), "", - iteminfo::no_newline | iteminfo::is_decimal, - fire_resist( false, get_base_env_resist_w_filter() ) ) ); - info.push_back( iteminfo( "ARMOR", space + _( "Environmental: " ), - get_env_resist( get_base_env_resist_w_filter() ) ) ); + info.emplace_back( "ARMOR", + _( "Protection when active: " ) ); + info.emplace_back( "ARMOR", space + _( "Acid: " ), "", + iteminfo::no_newline | iteminfo::is_decimal, + acid_resist( false, get_base_env_resist_w_filter() ) ); + info.emplace_back( "ARMOR", space + _( "Fire: " ), "", + iteminfo::no_newline | iteminfo::is_decimal, + fire_resist( false, get_base_env_resist_w_filter() ) ); + info.emplace_back( "ARMOR", space + _( "Environmental: " ), + get_env_resist( get_base_env_resist_w_filter() ) ); } if( damage() > 0 ) { - info.push_back( iteminfo( "ARMOR", - _( "Protection values are reduced by damage and " - "you may be able to improve them by repairing this " - "item." ) ) ); + info.emplace_back( "ARMOR", + _( "Protection values are reduced by damage and " + "you may be able to improve them by repairing this " + "item." ) ); } } } @@ -2913,7 +2913,7 @@ void item::armor_info( std::vector &info, const iteminfo_query *parts, coverage += _( " Nothing." ); } - info.push_back( iteminfo( "ARMOR", coverage ) ); + info.emplace_back( "ARMOR", coverage ); } if( parts->test( iteminfo_parts::ARMOR_LAYER ) && covers_anything ) { @@ -2934,15 +2934,15 @@ void item::armor_info( std::vector &info, const iteminfo_query *parts, layering += _( " Normal." ); } - info.push_back( iteminfo( "ARMOR", layering ) ); + info.emplace_back( "ARMOR", layering ); } if( parts->test( iteminfo_parts::ARMOR_COVERAGE ) && covers_anything ) { - info.push_back( iteminfo( "ARMOR", _( "Average Coverage: " ), "%", - iteminfo::no_newline, get_avg_coverage() ) ); + info.emplace_back( "ARMOR", _( "Average Coverage: " ), "%", + iteminfo::no_newline, get_avg_coverage() ); } if( parts->test( iteminfo_parts::ARMOR_WARMTH ) && covers_anything ) { - info.push_back( iteminfo( "ARMOR", space + _( "Warmth: " ), get_warmth() ) ); + info.emplace_back( "ARMOR", space + _( "Warmth: " ), get_warmth() ); } insert_separation_line( info ); @@ -2962,7 +2962,7 @@ void item::armor_info( std::vector &info, const iteminfo_query *parts, tmp.armor_protection_info( info, parts, batch, debug ); insert_separation_line( info ); - info.push_back( iteminfo( "ARMOR", _( "When active:" ) ) ); + info.emplace_back( "ARMOR", _( "When active:" ) ); tmp = tmp.convert( itype_id( tmp.typeId().str() + "_on" ) ); } @@ -2994,9 +2994,9 @@ void item::armor_info( std::vector &info, const iteminfo_query *parts, } else { modifier = "x"; } - info.push_back( iteminfo( "ARMOR", - _( "Weight capacity modifier: " ), modifier, - iteminfo::no_newline | iteminfo::is_decimal, weight_modif ) ); + info.emplace_back( "ARMOR", + _( "Weight capacity modifier: " ), modifier, + iteminfo::no_newline | iteminfo::is_decimal, weight_modif ); } if( weight_bonus != 0_gram ) { std::string bonus; @@ -3005,9 +3005,9 @@ void item::armor_info( std::vector &info, const iteminfo_query *parts, } else { bonus = string_format( " %s", weight_units() ); } - info.push_back( iteminfo( "ARMOR", _( "Weight capacity bonus: " ), bonus, - iteminfo::no_newline | iteminfo::is_decimal, - convert_weight( weight_bonus ) ) ); + info.emplace_back( "ARMOR", _( "Weight capacity bonus: " ), bonus, + iteminfo::no_newline | iteminfo::is_decimal, + convert_weight( weight_bonus ) ); } } @@ -3032,9 +3032,9 @@ void item::armor_fit_info( std::vector &info, const iteminfo_query *pa if( has_flag( flag_HELMET_COMPAT ) && parts->test( iteminfo_parts::DESCRIPTION_FLAGS_HELMETCOMPAT ) ) { - info.push_back( iteminfo( "DESCRIPTION", - _( "* This item can be worn with a " - "helmet." ) ) ); + info.emplace_back( "DESCRIPTION", + _( "* This item can be worn with a " + "helmet." ) ); } if( parts->test( iteminfo_parts::DESCRIPTION_FLAGS_FITS ) ) { @@ -3118,7 +3118,7 @@ void item::armor_fit_info( std::vector &info, const iteminfo_query *pa } if( !resize_str.empty() ) { std::string info_str = string_format( _( "* This clothing %s." ), resize_str ); - info.push_back( iteminfo( "DESCRIPTION", info_str ) ); + info.emplace_back( "DESCRIPTION", info_str ); } } else { switch( sizing_level ) { @@ -3141,7 +3141,7 @@ void item::armor_fit_info( std::vector &info, const iteminfo_query *pa } std::string info_str = string_format( _( "* This clothing can be " "refitted%s." ), resize_str ); - info.push_back( iteminfo( "DESCRIPTION", info_str ) ); + info.emplace_back( "DESCRIPTION", info_str ); } } else { info.emplace_back( "DESCRIPTION", _( "* This clothing can not be refitted, " @@ -3150,32 +3150,32 @@ void item::armor_fit_info( std::vector &info, const iteminfo_query *pa } if( is_sided() && parts->test( iteminfo_parts::DESCRIPTION_FLAGS_SIDED ) ) { - info.push_back( iteminfo( "DESCRIPTION", - _( "* This item can be worn on either side of " - "the body." ) ) ); + info.emplace_back( "DESCRIPTION", + _( "* This item can be worn on either side of " + "the body." ) ); } if( is_power_armor() && parts->test( iteminfo_parts::DESCRIPTION_FLAGS_POWERARMOR ) ) { - info.push_back( iteminfo( "DESCRIPTION", - _( "* This gear is a part of power armor." ) ) ); + info.emplace_back( "DESCRIPTION", + _( "* This gear is a part of power armor." ) ); if( parts->test( iteminfo_parts::DESCRIPTION_FLAGS_POWERARMOR_RADIATIONHINT ) ) { if( covers( bodypart_id( "head" ) ) ) { - info.push_back( iteminfo( "DESCRIPTION", - _( "* When worn with a power armor suit, it will " - "fully protect you from " - "radiation." ) ) ); + info.emplace_back( "DESCRIPTION", + _( "* When worn with a power armor suit, it will " + "fully protect you from " + "radiation." ) ); } else { - info.push_back( iteminfo( "DESCRIPTION", - _( "* When worn with a power armor helmet, it will " - "fully protect you from " - "radiation." ) ) ); + info.emplace_back( "DESCRIPTION", + _( "* When worn with a power armor helmet, it will " + "fully protect you from " + "radiation." ) ); } } } if( typeId() == itype_rad_badge && parts->test( iteminfo_parts::DESCRIPTION_IRRADIATION ) ) { - info.push_back( iteminfo( "DESCRIPTION", - string_format( _( "* The film strip on the badge is %s." ), - rad_badge_color( irradiation ) ) ) ); + info.emplace_back( "DESCRIPTION", + string_format( _( "* The film strip on the badge is %s." ), + rad_badge_color( irradiation ) ) ); } } @@ -3190,31 +3190,31 @@ void item::book_info( std::vector &info, const iteminfo_query *parts, const islot_book &book = *type->book; // Some things about a book you CAN tell by it's cover. if( !book.skill && !type->can_use( "MA_MANUAL" ) && parts->test( iteminfo_parts::BOOK_SUMMARY ) ) { - info.push_back( iteminfo( "BOOK", _( "Just for fun." ) ) ); + info.emplace_back( "BOOK", _( "Just for fun." ) ); } avatar &player_character = get_avatar(); if( type->can_use( "MA_MANUAL" ) && parts->test( iteminfo_parts::BOOK_SUMMARY ) ) { - info.push_back( iteminfo( "BOOK", - _( "Some sort of martial arts training " - "manual." ) ) ); + info.emplace_back( "BOOK", + _( "Some sort of martial arts training " + "manual." ) ); if( player_character.has_identified( typeId() ) ) { const matype_id style_to_learn = martial_art_learned_from( *type ); - info.push_back( iteminfo( "BOOK", - string_format( _( "You can learn %s style " - "from it." ), style_to_learn->name ) ) ); - info.push_back( iteminfo( "BOOK", - string_format( _( "This fighting style is %s " - "to learn." ), - martialart_difficulty( style_to_learn ) ) ) ); - info.push_back( iteminfo( "BOOK", - string_format( _( "It'd be easier to master if you'd have " - "skill expertise in %s." ), - style_to_learn->primary_skill->name() ) ) ); + info.emplace_back( "BOOK", + string_format( _( "You can learn %s style " + "from it." ), style_to_learn->name ) ); + info.emplace_back( "BOOK", + string_format( _( "This fighting style is %s " + "to learn." ), + martialart_difficulty( style_to_learn ) ) ); + info.emplace_back( "BOOK", + string_format( _( "It'd be easier to master if you'd have " + "skill expertise in %s." ), + style_to_learn->primary_skill->name() ) ); } } if( book.req == 0 && parts->test( iteminfo_parts::BOOK_REQUIREMENTS_BEGINNER ) ) { - info.push_back( iteminfo( "BOOK", _( "It can be understood by " - "beginners." ) ) ); + info.emplace_back( "BOOK", _( "It can be understood by " + "beginners." ) ); } if( player_character.has_identified( typeId() ) ) { if( book.skill ) { @@ -3223,31 +3223,31 @@ void item::book_info( std::vector &info, const iteminfo_query *parts, const std::string skill_name = book.skill->name(); std::string fmt = string_format( _( "Can bring your %s skill to " "." ), skill_name ); - info.push_back( iteminfo( "BOOK", "", fmt, iteminfo::no_flags, book.level ) ); + info.emplace_back( "BOOK", "", fmt, iteminfo::no_flags, book.level ); fmt = string_format( _( "Your current %s skill is ." ), skill_name ); - info.push_back( iteminfo( "BOOK", "", fmt, iteminfo::no_flags, skill.level() ) ); + info.emplace_back( "BOOK", "", fmt, iteminfo::no_flags, skill.level() ); } if( book.req != 0 && parts->test( iteminfo_parts::BOOK_SKILLRANGE_MIN ) ) { const std::string fmt = string_format( _( "Requires %s level to " "understand." ), book.skill.obj().name() ); - info.push_back( iteminfo( "BOOK", "", fmt, - iteminfo::lower_is_better, book.req ) ); + info.emplace_back( "BOOK", "", fmt, + iteminfo::lower_is_better, book.req ); } } if( book.intel != 0 && parts->test( iteminfo_parts::BOOK_REQUIREMENTS_INT ) ) { - info.push_back( iteminfo( "BOOK", "", - _( "Requires intelligence of to easily " - "read." ), iteminfo::lower_is_better, book.intel ) ); + info.emplace_back( "BOOK", "", + _( "Requires intelligence of to easily " + "read." ), iteminfo::lower_is_better, book.intel ); } if( player_character.book_fun_for( *this, player_character ) != 0 && parts->test( iteminfo_parts::BOOK_MORALECHANGE ) ) { - info.push_back( iteminfo( "BOOK", "", - _( "Reading this book affects your morale by " ), - iteminfo::show_plus, player_character.book_fun_for( *this, player_character ) ) ); + info.emplace_back( "BOOK", "", + _( "Reading this book affects your morale by " ), + iteminfo::show_plus, player_character.book_fun_for( *this, player_character ) ); } if( parts->test( iteminfo_parts::BOOK_TIMEPERCHAPTER ) ) { std::string fmt = ngettext( @@ -3262,8 +3262,8 @@ void item::book_info( std::vector &info, const iteminfo_query *parts, "A training session with this book takes " " minutes.", book.time ); } - info.push_back( iteminfo( "BOOK", "", fmt, - iteminfo::lower_is_better, book.time ) ); + info.emplace_back( "BOOK", "", fmt, + iteminfo::lower_is_better, book.time ); } if( book.chapters > 0 && parts->test( iteminfo_parts::BOOK_NUMUNREADCHAPTERS ) ) { @@ -3271,7 +3271,7 @@ void item::book_info( std::vector &info, const iteminfo_query *parts, std::string fmt = ngettext( "This book has unread chapter.", "This book has unread chapters.", unread ); - info.push_back( iteminfo( "BOOK", "", fmt, iteminfo::no_flags, unread ) ); + info.emplace_back( "BOOK", "", fmt, iteminfo::no_flags, unread ); } if( !book.proficiencies.empty() ) { @@ -3284,7 +3284,7 @@ void item::book_info( std::vector &info, const iteminfo_query *parts, book.proficiencies.begin(), book.proficiencies.end(), enumerate_profs ) ); - info.push_back( iteminfo( "BOOK", profs ) ); + info.emplace_back( "BOOK", profs ); } if( parts->test( iteminfo_parts::BOOK_INCLUDED_RECIPES ) ) { @@ -3317,22 +3317,22 @@ void item::book_info( std::vector &info, const iteminfo_query *parts, recipe_list.size(), enumerate_as_string( recipe_list ) ); insert_separation_line( info ); - info.push_back( iteminfo( "DESCRIPTION", recipe_line ) ); + info.emplace_back( "DESCRIPTION", recipe_line ); } if( recipe_list.size() != book.recipes.size() && parts->test( iteminfo_parts::DESCRIPTION_BOOK_ADDITIONAL_RECIPES ) ) { - info.push_back( iteminfo( "DESCRIPTION", - _( "It might help you figuring out some more " - "recipes." ) ) ); + info.emplace_back( "DESCRIPTION", + _( "It might help you figuring out some more " + "recipes." ) ); } } } else { if( parts->test( iteminfo_parts::BOOK_UNREAD ) ) { - info.push_back( iteminfo( "BOOK", - _( "You need to read this book to see its " - "contents." ) ) ); + info.emplace_back( "BOOK", + _( "You need to read this book to see its " + "contents." ) ); } } } @@ -3406,24 +3406,24 @@ void item::tool_info( std::vector &info, const iteminfo_query *parts, // UPS, rechargeable power cells, and bionic power if( has_flag( flag_USE_UPS ) && parts->test( iteminfo_parts::DESCRIPTION_RECHARGE_UPSMODDED ) ) { - info.push_back( iteminfo( "DESCRIPTION", - _( "* This tool has been modified to use a universal " - "power supply and is not compatible" - " with standard batteries." ) ) ); + info.emplace_back( "DESCRIPTION", + _( "* This tool has been modified to use a universal " + "power supply and is not compatible" + " with standard batteries." ) ); } else if( has_flag( flag_RECHARGE ) && has_flag( flag_NO_RELOAD ) && parts->test( iteminfo_parts::DESCRIPTION_RECHARGE_NORELOAD ) ) { - info.push_back( iteminfo( "DESCRIPTION", - _( "* This tool has a rechargeable power cell " - "and is not compatible with " - "standard batteries." ) ) ); + info.emplace_back( "DESCRIPTION", + _( "* This tool has a rechargeable power cell " + "and is not compatible with " + "standard batteries." ) ); } else if( has_flag( flag_RECHARGE ) && parts->test( iteminfo_parts::DESCRIPTION_RECHARGE_UPSCAPABLE ) ) { - info.push_back( iteminfo( "DESCRIPTION", - _( "* This tool has a rechargeable power cell " - "and can be recharged in any UPS-compatible " - "recharging station. You could charge it with " - "standard batteries, but unloading it is " - "impossible." ) ) ); + info.emplace_back( "DESCRIPTION", + _( "* This tool has a rechargeable power cell " + "and can be recharged in any UPS-compatible " + "recharging station. You could charge it with " + "standard batteries, but unloading it is " + "impossible." ) ); } else if( has_flag( flag_USES_BIONIC_POWER ) ) { info.emplace_back( "DESCRIPTION", _( "* This tool runs on bionic power." ) ); @@ -3444,7 +3444,7 @@ void item::tool_info( std::vector &info, const iteminfo_query *parts, feedback = _( "Almost completely burned out." ); } feedback = _( "Fuel: " ) + feedback; - info.push_back( iteminfo( "DESCRIPTION", feedback ) ); + info.emplace_back( "DESCRIPTION", feedback ); } } @@ -3455,11 +3455,11 @@ void item::component_info( std::vector &info, const iteminfo_query *pa return; } if( is_craft() ) { - info.push_back( iteminfo( "DESCRIPTION", string_format( _( "Using: %s" ), - components_to_string() ) ) ); + info.emplace_back( "DESCRIPTION", string_format( _( "Using: %s" ), + components_to_string() ) ); } else { - info.push_back( iteminfo( "DESCRIPTION", string_format( _( "Made from: %s" ), - components_to_string() ) ) ); + info.emplace_back( "DESCRIPTION", string_format( _( "Made from: %s" ), + components_to_string() ) ); } } @@ -3536,7 +3536,7 @@ void item::disassembly_info( std::vector &info, const iteminfo_query * } insert_separation_line( info ); - info.push_back( iteminfo( "DESCRIPTION", descr ) ); + info.emplace_back( "DESCRIPTION", descr ); } } @@ -3597,15 +3597,15 @@ void item::bionic_info( std::vector &info, const iteminfo_query *parts // TODO: Unhide when enforcing limits if( get_option < bool >( "CBM_SLOTS_ENABLED" ) && parts->test( iteminfo_parts::DESCRIPTION_CBM_SLOTS ) ) { - info.push_back( iteminfo( "DESCRIPTION", list_occupied_bps( type->bionic->id, - _( "This bionic is installed in the following body " - "part(s):" ) ) ) ); + info.emplace_back( "DESCRIPTION", list_occupied_bps( type->bionic->id, + _( "This bionic is installed in the following body " + "part(s):" ) ) ); } insert_separation_line( info ); if( is_bionic() && has_flag( flag_NO_STERILE ) ) { - info.push_back( iteminfo( "DESCRIPTION", - _( "* This bionic is not sterile, use an autoclave and an autoclave pouch to sterilize it. " ) ) ); + info.emplace_back( "DESCRIPTION", + _( "* This bionic is not sterile, use an autoclave and an autoclave pouch to sterilize it. " ) ); } insert_separation_line( info ); @@ -3614,79 +3614,78 @@ void item::bionic_info( std::vector &info, const iteminfo_query *parts if( !fuels.empty() ) { const int &fuel_numb = fuels.size(); - info.push_back( iteminfo( "DESCRIPTION", - ngettext( "* This bionic can produce power from the following fuel: ", - "* This bionic can produce power from the following fuels: ", - fuel_numb ) + enumerate_as_string( fuels.begin(), - fuels.end(), []( const material_id & id ) -> std::string { return "" + id->name() + ""; } ) ) ); + info.emplace_back( "DESCRIPTION", + ngettext( "* This bionic can produce power from the following fuel: ", + "* This bionic can produce power from the following fuels: ", + fuel_numb ) + enumerate_as_string( fuels.begin(), + fuels.end(), []( const material_id & id ) -> std::string { return "" + id->name() + ""; } ) ); } insert_separation_line( info ); if( bid->capacity > 0_mJ ) { - info.push_back( iteminfo( "CBM", _( "Power Capacity:" ), _( " mJ" ), - iteminfo::no_newline, - units::to_millijoule( bid->capacity ) ) ); + info.emplace_back( "CBM", _( "Power Capacity:" ), _( " mJ" ), + iteminfo::no_newline, + units::to_millijoule( bid->capacity ) ); } insert_separation_line( info ); // TODO refactor these almost identical blocks if( !bid->encumbrance.empty() ) { - info.push_back( iteminfo( "DESCRIPTION", _( "Encumbrance:" ), - iteminfo::no_newline ) ); + info.emplace_back( "DESCRIPTION", _( "Encumbrance:" ), + iteminfo::no_newline ); for( const std::pair &element : sorted_lex( bid->encumbrance ) ) { - info.push_back( - iteminfo( "CBM", " " + body_part_name_as_heading( element.first.id(), 1 ), - " ", iteminfo::no_newline, element.second ) ); + info.emplace_back( "CBM", " " + body_part_name_as_heading( element.first.id(), 1 ), + " ", iteminfo::no_newline, element.second ); } } if( !bid->env_protec.empty() ) { - info.push_back( iteminfo( "DESCRIPTION", - _( "Environmental Protection:" ), - iteminfo::no_newline ) ); + info.emplace_back( "DESCRIPTION", + _( "Environmental Protection:" ), + iteminfo::no_newline ); for( const std::pair< bodypart_str_id, size_t > &element : sorted_lex( bid->env_protec ) ) { - info.push_back( iteminfo( "CBM", " " + body_part_name_as_heading( element.first, 1 ), - " ", iteminfo::no_newline, element.second ) ); + info.emplace_back( "CBM", " " + body_part_name_as_heading( element.first, 1 ), + " ", iteminfo::no_newline, element.second ); } } if( !bid->bash_protec.empty() ) { - info.push_back( iteminfo( "DESCRIPTION", - _( "Bash Protection:" ), - iteminfo::no_newline ) ); + info.emplace_back( "DESCRIPTION", + _( "Bash Protection:" ), + iteminfo::no_newline ); for( const std::pair< bodypart_str_id, size_t > &element : sorted_lex( bid->bash_protec ) ) { - info.push_back( iteminfo( "CBM", " " + body_part_name_as_heading( element.first, 1 ), - " ", iteminfo::no_newline, element.second ) ); + info.emplace_back( "CBM", " " + body_part_name_as_heading( element.first, 1 ), + " ", iteminfo::no_newline, element.second ); } } if( !bid->cut_protec.empty() ) { - info.push_back( iteminfo( "DESCRIPTION", - _( "Cut Protection:" ), - iteminfo::no_newline ) ); + info.emplace_back( "DESCRIPTION", + _( "Cut Protection:" ), + iteminfo::no_newline ); for( const std::pair< bodypart_str_id, size_t > &element : sorted_lex( bid->cut_protec ) ) { - info.push_back( iteminfo( "CBM", " " + body_part_name_as_heading( element.first, 1 ), - " ", iteminfo::no_newline, element.second ) ); + info.emplace_back( "CBM", " " + body_part_name_as_heading( element.first, 1 ), + " ", iteminfo::no_newline, element.second ); } } if( !bid->bullet_protec.empty() ) { - info.push_back( iteminfo( "DESCRIPTION", _( "Ballistic Protection:" ), - iteminfo::no_newline ) ); + info.emplace_back( "DESCRIPTION", _( "Ballistic Protection:" ), + iteminfo::no_newline ); for( const std::pair< bodypart_str_id, size_t > &element : sorted_lex( bid->bullet_protec ) ) { - info.push_back( iteminfo( "CBM", " " + body_part_name_as_heading( element.first, 1 ), - " ", iteminfo::no_newline, element.second ) ); + info.emplace_back( "CBM", " " + body_part_name_as_heading( element.first, 1 ), + " ", iteminfo::no_newline, element.second ); } } if( !bid->stat_bonus.empty() ) { - info.push_back( iteminfo( "DESCRIPTION", _( "Stat Bonus:" ), - iteminfo::no_newline ) ); + info.emplace_back( "DESCRIPTION", _( "Stat Bonus:" ), + iteminfo::no_newline ); for( const auto &element : bid->stat_bonus ) { - info.push_back( iteminfo( "CBM", " " + get_stat_name( element.first ), " ", - iteminfo::no_newline, element.second ) ); + info.emplace_back( "CBM", " " + get_stat_name( element.first ), " ", + iteminfo::no_newline, element.second ); } } @@ -3699,10 +3698,10 @@ void item::bionic_info( std::vector &info, const iteminfo_query *parts } else { modifier = "x"; } - info.push_back( iteminfo( "CBM", - _( "Weight capacity modifier: " ), modifier, - iteminfo::no_newline | iteminfo::is_decimal, - weight_modif ) ); + info.emplace_back( "CBM", + _( "Weight capacity modifier: " ), modifier, + iteminfo::no_newline | iteminfo::is_decimal, + weight_modif ); } if( weight_bonus != 0_gram ) { std::string bonus; @@ -3711,9 +3710,9 @@ void item::bionic_info( std::vector &info, const iteminfo_query *parts } else { bonus = string_format( " %s", weight_units() ); } - info.push_back( iteminfo( "CBM", _( "Weight capacity bonus: " ), bonus, - iteminfo::no_newline | iteminfo::is_decimal, - convert_weight( weight_bonus ) ) ); + info.emplace_back( "CBM", _( "Weight capacity bonus: " ), bonus, + iteminfo::no_newline | iteminfo::is_decimal, + convert_weight( weight_bonus ) ); } } @@ -3729,30 +3728,30 @@ void item::combat_info( std::vector &info, const iteminfo_query *parts insert_separation_line( info ); std::string sep; if( dmg_bash || dmg_cut || dmg_stab ) { - info.push_back( iteminfo( "BASE", _( "Melee damage: " ), "", iteminfo::no_newline ) ); + info.emplace_back( "BASE", _( "Melee damage: " ), "", iteminfo::no_newline ); } if( dmg_bash ) { - info.push_back( iteminfo( "BASE", _( "Bash: " ), "", iteminfo::no_newline, dmg_bash ) ); + info.emplace_back( "BASE", _( "Bash: " ), "", iteminfo::no_newline, dmg_bash ); sep = space; } if( dmg_cut ) { - info.push_back( iteminfo( "BASE", sep + _( "Cut: " ), "", iteminfo::no_newline, dmg_cut ) ); + info.emplace_back( "BASE", sep + _( "Cut: " ), "", iteminfo::no_newline, dmg_cut ); sep = space; } if( dmg_stab ) { - info.push_back( iteminfo( "BASE", sep + _( "Pierce: " ), "", iteminfo::no_newline, dmg_stab ) ); + info.emplace_back( "BASE", sep + _( "Pierce: " ), "", iteminfo::no_newline, dmg_stab ); } } if( dmg_bash || dmg_cut || dmg_stab ) { if( parts->test( iteminfo_parts::BASE_TOHIT ) ) { - info.push_back( iteminfo( "BASE", space + _( "To-hit bonus: " ), "", - iteminfo::show_plus, type->m_to_hit ) ); + info.emplace_back( "BASE", space + _( "To-hit bonus: " ), "", + iteminfo::show_plus, type->m_to_hit ); } if( parts->test( iteminfo_parts::BASE_MOVES ) ) { - info.push_back( iteminfo( "BASE", _( "Moves per attack: " ), "", - iteminfo::lower_is_better, attack_time() ) ); + info.emplace_back( "BASE", _( "Moves per attack: " ), "", + iteminfo::lower_is_better, attack_time() ); } @@ -3777,11 +3776,11 @@ void item::combat_info( std::vector &info, const iteminfo_query *parts if( !all_techniques.empty() ) { const std::vector all_tec_sorted = sorted_lex( all_techniques ); insert_separation_line( info ); - info.push_back( iteminfo( "DESCRIPTION", _( "Techniques when wielded: " ) + + info.emplace_back( "DESCRIPTION", _( "Techniques when wielded: " ) + enumerate_as_string( all_tec_sorted.begin(), all_tec_sorted.end(), []( const matec_id & tid ) { return string_format( "%s: %s", tid.obj().name, tid.obj().description ); - } ) ) ); + } ) ); } } @@ -3792,9 +3791,9 @@ void item::combat_info( std::vector &info, const iteminfo_query *parts typeId() ); if( !valid_styles.empty() ) { insert_separation_line( info ); - info.push_back( iteminfo( "DESCRIPTION", - _( "You know how to use this with these martial arts " - "styles: " ) + valid_styles ) ); + info.emplace_back( "DESCRIPTION", + _( "You know how to use this with these martial arts " + "styles: " ) + valid_styles ); } } @@ -3802,13 +3801,13 @@ void item::combat_info( std::vector &info, const iteminfo_query *parts parts->test( iteminfo_parts::DESCRIPTION_GUNMOD_ADDREACHATTACK ) ) { insert_separation_line( info ); if( has_flag( flag_REACH3 ) ) { - info.push_back( iteminfo( "DESCRIPTION", - _( "* This item can be used to make long reach " - "attacks." ) ) ); + info.emplace_back( "DESCRIPTION", + _( "* This item can be used to make long reach " + "attacks." ) ); } else { - info.push_back( iteminfo( "DESCRIPTION", - _( "* This item can be used to make reach " - "attacks." ) ) ); + info.emplace_back( "DESCRIPTION", + _( "* This item can be used to make reach " + "attacks." ) ); } } @@ -3822,50 +3821,50 @@ void item::combat_info( std::vector &info, const iteminfo_query *parts int attack_cost = player_character.attack_speed( *this ); insert_separation_line( info ); if( parts->test( iteminfo_parts::DESCRIPTION_MELEEDMG ) ) { - info.push_back( iteminfo( "DESCRIPTION", _( "Average melee damage:" ) ) ); + info.emplace_back( "DESCRIPTION", _( "Average melee damage:" ) ); } // Chance of critical hit if( parts->test( iteminfo_parts::DESCRIPTION_MELEEDMG_CRIT ) ) { - info.push_back( iteminfo( "DESCRIPTION", - string_format( _( "Critical hit chance %d%% - %d%%" ), + info.emplace_back( "DESCRIPTION", + string_format( _( "Critical hit chance %d%% - %d%%" ), static_cast( player_character.crit_chance( 0, 100, *this ) * 100 ), static_cast( player_character.crit_chance( 100, 0, *this ) * - 100 ) ) ) ); + 100 ) ) ); } // Bash damage if( parts->test( iteminfo_parts::DESCRIPTION_MELEEDMG_BASH ) ) { // NOTE: Using "BASE" instead of "DESCRIPTION", so numerical formatting will work // (output.cpp:format_item_info does not interpolate for DESCRIPTION info) - info.push_back( iteminfo( "BASE", _( "Bashing: " ), "", iteminfo::no_newline, - non_crit.type_damage( damage_type::BASH ) ) ); - info.push_back( iteminfo( "BASE", space + _( "Critical bash: " ), "", iteminfo::no_flags, - crit.type_damage( damage_type::BASH ) ) ); + info.emplace_back( "BASE", _( "Bashing: " ), "", iteminfo::no_newline, + non_crit.type_damage( damage_type::BASH ) ); + info.emplace_back( "BASE", space + _( "Critical bash: " ), "", iteminfo::no_flags, + crit.type_damage( damage_type::BASH ) ); } // Cut damage if( ( non_crit.type_damage( damage_type::CUT ) > 0.0f || crit.type_damage( damage_type::CUT ) > 0.0f ) && parts->test( iteminfo_parts::DESCRIPTION_MELEEDMG_CUT ) ) { - info.push_back( iteminfo( "BASE", _( "Cutting: " ), "", iteminfo::no_newline, - non_crit.type_damage( damage_type::CUT ) ) ); - info.push_back( iteminfo( "BASE", space + _( "Critical cut: " ), "", iteminfo::no_flags, - crit.type_damage( damage_type::CUT ) ) ); + info.emplace_back( "BASE", _( "Cutting: " ), "", iteminfo::no_newline, + non_crit.type_damage( damage_type::CUT ) ); + info.emplace_back( "BASE", space + _( "Critical cut: " ), "", iteminfo::no_flags, + crit.type_damage( damage_type::CUT ) ); } // Pierce/stab damage if( ( non_crit.type_damage( damage_type::STAB ) > 0.0f || crit.type_damage( damage_type::STAB ) > 0.0f ) && parts->test( iteminfo_parts::DESCRIPTION_MELEEDMG_PIERCE ) ) { - info.push_back( iteminfo( "BASE", _( "Piercing: " ), "", iteminfo::no_newline, - non_crit.type_damage( damage_type::STAB ) ) ); - info.push_back( iteminfo( "BASE", space + _( "Critical pierce: " ), "", iteminfo::no_flags, - crit.type_damage( damage_type::STAB ) ) ); + info.emplace_back( "BASE", _( "Piercing: " ), "", iteminfo::no_newline, + non_crit.type_damage( damage_type::STAB ) ); + info.emplace_back( "BASE", space + _( "Critical pierce: " ), "", iteminfo::no_flags, + crit.type_damage( damage_type::STAB ) ); } // Moves if( parts->test( iteminfo_parts::DESCRIPTION_MELEEDMG_MOVES ) ) { - info.push_back( iteminfo( "BASE", _( "Moves per attack: " ), "", - iteminfo::lower_is_better, attack_cost ) ); + info.emplace_back( "BASE", _( "Moves per attack: " ), "", + iteminfo::lower_is_better, attack_cost ); } insert_separation_line( info ); } @@ -3951,14 +3950,14 @@ void item::final_info( std::vector &info, const iteminfo_query *parts, if( parts->test( iteminfo_parts::DESCRIPTION_CONDUCTIVITY ) ) { if( !conductive() ) { - info.push_back( iteminfo( "BASE", _( "* This item does not " - "conduct electricity." ) ) ); + info.emplace_back( "BASE", _( "* This item does not " + "conduct electricity." ) ); } else if( has_flag( flag_CONDUCTIVE ) ) { - info.push_back( iteminfo( "BASE", - _( "* This item effectively conducts " - "electricity, as it has no guard." ) ) ); + info.emplace_back( "BASE", + _( "* This item effectively conducts " + "electricity, as it has no guard." ) ); } else { - info.push_back( iteminfo( "BASE", _( "* This item conducts electricity." ) ) ); + info.emplace_back( "BASE", _( "* This item conducts electricity." ) ); } } @@ -4024,16 +4023,16 @@ void item::final_info( std::vector &info, const iteminfo_query *parts, if( has_flag( flag_LEAK_DAM ) && has_flag( flag_RADIOACTIVE ) && damage() > 0 && parts->test( iteminfo_parts::DESCRIPTION_RADIOACTIVITY_DAMAGED ) ) { - info.push_back( iteminfo( "DESCRIPTION", - _( "* The casing of this item has cracked, " - "revealing an ominous green glow." ) ) ); + info.emplace_back( "DESCRIPTION", + _( "* The casing of this item has cracked, " + "revealing an ominous green glow." ) ); } if( has_flag( flag_LEAK_ALWAYS ) && has_flag( flag_RADIOACTIVE ) && parts->test( iteminfo_parts::DESCRIPTION_RADIOACTIVITY_ALWAYS ) ) { - info.push_back( iteminfo( "DESCRIPTION", - _( "* This object is surrounded by a " - "sickly green glow." ) ) ); + info.emplace_back( "DESCRIPTION", + _( "* This object is surrounded by a " + "sickly green glow." ) ); } if( is_brewable() ) { @@ -4043,25 +4042,25 @@ void item::final_info( std::vector &info, const iteminfo_query *parts, int btime_i = to_days( btime ); if( btime <= 2_days ) { btime_i = to_hours( btime ); - info.push_back( iteminfo( "DESCRIPTION", - string_format( ngettext( "* Once set in a vat, this " + info.emplace_back( "DESCRIPTION", + string_format( ngettext( "* Once set in a vat, this " "will ferment in around %d hour.", "* Once set in a vat, this will ferment in " - "around %d hours.", btime_i ), btime_i ) ) ); + "around %d hours.", btime_i ), btime_i ) ); } else { - info.push_back( iteminfo( "DESCRIPTION", - string_format( ngettext( "* Once set in a vat, this " + info.emplace_back( "DESCRIPTION", + string_format( ngettext( "* Once set in a vat, this " "will ferment in around %d day.", "* Once set in a vat, this will ferment in " - "around %d days.", btime_i ), btime_i ) ) ); + "around %d days.", btime_i ), btime_i ) ); } } if( parts->test( iteminfo_parts::DESCRIPTION_BREWABLE_PRODUCTS ) ) { for( const itype_id &res : brewed.brewing_results() ) { - info.push_back( iteminfo( "DESCRIPTION", - string_format( _( "* Fermenting this will produce " - "%s." ), - nname( res, brewed.charges ) ) ) ); + info.emplace_back( "DESCRIPTION", + string_format( _( "* Fermenting this will produce " + "%s." ), + nname( res, brewed.charges ) ) ); } } } @@ -4105,13 +4104,13 @@ void item::final_info( std::vector &info, const iteminfo_query *parts, } const int time_to_do = tt->time_to_do( *this ); if( time_to_do <= 0 ) { - info.push_back( iteminfo( "DESCRIPTION", - _( "It's done and can be activated." ) ) ); + info.emplace_back( "DESCRIPTION", + _( "It's done and can be activated." ) ); } else { const std::string time = to_string_clipped( time_duration::from_turns( time_to_do ) ); - info.push_back( iteminfo( "DESCRIPTION", - string_format( _( "It will be done in %s." ), - time.c_str() ) ) ); + info.emplace_back( "DESCRIPTION", + string_format( _( "It will be done in %s." ), + time.c_str() ) ); } } } @@ -4138,7 +4137,7 @@ void item::final_info( std::vector &info, const iteminfo_query *parts, //~ %1$s: inscription text ntext = string_format( pgettext( "carving", "Note: %1$s" ), item_note->second ); } - info.push_back( iteminfo( "DESCRIPTION", ntext ) ); + info.emplace_back( "DESCRIPTION", ntext ); } if( parts->test( iteminfo_parts::DESCRIPTION_DIE ) && this->get_var( "die_num_sides", 0 ) != 0 ) { @@ -4154,15 +4153,15 @@ void item::final_info( std::vector &info, const iteminfo_query *parts, const int price_postapoc = price( true ) * batch; if( parts->test( iteminfo_parts::BASE_PRICE ) ) { insert_separation_line( info ); - info.push_back( iteminfo( "BASE", _( "Price: " ), _( "$" ), - iteminfo::is_decimal | iteminfo::lower_is_better | iteminfo::no_newline, - static_cast( price_preapoc ) / 100 ) ); + info.emplace_back( "BASE", _( "Price: " ), _( "$" ), + iteminfo::is_decimal | iteminfo::lower_is_better | iteminfo::no_newline, + static_cast( price_preapoc ) / 100 ); } if( price_preapoc != price_postapoc && parts->test( iteminfo_parts::BASE_BARTER ) ) { const std::string space = " "; - info.push_back( iteminfo( "BASE", space + _( "Barter value: " ), _( "$" ), - iteminfo::is_decimal | iteminfo::lower_is_better, - static_cast( price_postapoc ) / 100 ) ); + info.emplace_back( "BASE", space + _( "Barter value: " ), _( "$" ), + iteminfo::is_decimal | iteminfo::lower_is_better, + static_cast( price_postapoc ) / 100 ); } // Recipes using this item as an ingredient @@ -4176,17 +4175,17 @@ void item::final_info( std::vector &info, const iteminfo_query *parts, if( item_recipes.empty() ) { insert_separation_line( info ); - info.push_back( iteminfo( "DESCRIPTION", - _( "You know of nothing you could craft with it." ) ) ); + info.emplace_back( "DESCRIPTION", + _( "You know of nothing you could craft with it." ) ); } else { if( item_recipes.size() > 24 ) { insert_separation_line( info ); - info.push_back( iteminfo( "DESCRIPTION", - _( "You know dozens of things you could craft with it." ) ) ); + info.emplace_back( "DESCRIPTION", + _( "You know dozens of things you could craft with it." ) ); } else if( item_recipes.size() > 12 ) { insert_separation_line( info ); - info.push_back( iteminfo( "DESCRIPTION", - _( "You could use it to craft various other things." ) ) ); + info.emplace_back( "DESCRIPTION", + _( "You could use it to craft various other things." ) ); } else { // Extract item names from recipes and sort them std::vector> result_names; @@ -4209,9 +4208,9 @@ void item::final_info( std::vector &info, const iteminfo_query *parts, } } ); insert_separation_line( info ); - info.push_back( iteminfo( "DESCRIPTION", - string_format( _( "You could use it to craft: %s" ), - recipes ) ) ); + info.emplace_back( "DESCRIPTION", + string_format( _( "You could use it to craft: %s" ), + recipes ) ); } } } @@ -4220,9 +4219,9 @@ void item::final_info( std::vector &info, const iteminfo_query *parts, const ret_val can_wear = player_character.can_wear( *this, true ); if( ! can_wear.success() ) { insert_separation_line( info ); - info.push_back( iteminfo( "DESCRIPTION", - // can_wear returns a translated string - string_format( "%s", can_wear.str() ) ) ); + info.emplace_back( "DESCRIPTION", + // can_wear returns a translated string + string_format( "%s", can_wear.str() ) ); } } @@ -4236,7 +4235,7 @@ void item::final_info( std::vector &info, const iteminfo_query *parts, } if( art.is_valid() ) { for( const std::string &line : art->picture ) { - info.push_back( iteminfo( "DESCRIPTION", line ) ); + info.emplace_back( "DESCRIPTION", line ); } } } @@ -7567,7 +7566,7 @@ std::vector> item::get_available_recipes( const C for( const islot_book::recipe_with_description_t &elem : type->book->recipes ) { if( u.get_skill_level( elem.recipe->skill_used ) >= elem.skill_level ) { - recipe_entries.push_back( std::make_pair( elem.recipe, elem.skill_level ) ); + recipe_entries.emplace_back( elem.recipe, elem.skill_level ); } } } else if( has_var( "EIPC_RECIPES" ) ) { @@ -7584,7 +7583,7 @@ std::vector> item::get_available_recipes( const C next_string_index - first_string_index ); const recipe *r = &recipe_id( new_recipe ).obj(); if( u.get_skill_level( r->skill_used ) >= r->difficulty ) { - recipe_entries.push_back( std::make_pair( r, r->difficulty ) ); + recipe_entries.emplace_back( r, r->difficulty ); } first_string_index = next_string_index + 1; } @@ -10796,7 +10795,7 @@ std::vector item::get_uncraft_components() const if( iter != ret.end() ) { iter->count += component.count(); } else { - ret.push_back( item_comp( component.typeId(), component.count() ) ); + ret.emplace_back( component.typeId(), component.count() ); } } } diff --git a/src/item_contents.cpp b/src/item_contents.cpp index 2c055e1cdef65..911b5274ced9c 100644 --- a/src/item_contents.cpp +++ b/src/item_contents.cpp @@ -201,7 +201,7 @@ item_contents::item_contents( const std::vector &pockets ) { for( const pocket_data &data : pockets ) { - contents.push_back( item_pocket( &data ) ); + contents.emplace_back( &data ); } } @@ -1252,7 +1252,7 @@ void item_contents::update_modified_pockets( // in case the debugmsg wasn't clear, this should never happen debugmsg( "Oops! deleted some items when updating pockets that were added via toolmods" ); } - contents.push_back( item_pocket( *mag_or_mag_well ) ); + contents.emplace_back( *mag_or_mag_well ); pocket_iter = contents.erase( pocket_iter ); } else { ++pocket_iter; @@ -1268,7 +1268,7 @@ void item_contents::update_modified_pockets( // we've deleted all of the superfluous copies already, so time to add the new pockets for( const pocket_data *container_pocket : container_pockets ) { - contents.push_back( item_pocket( container_pocket ) ); + contents.emplace_back( container_pocket ); } } @@ -1549,7 +1549,7 @@ int item_contents::best_quality( const quality_id &id ) const static void insert_separation_line( std::vector &info ) { if( info.empty() || info.back().sName != "--" ) { - info.push_back( iteminfo( "DESCRIPTION", "--" ) ); + info.emplace_back( "DESCRIPTION", "--" ); } } diff --git a/src/item_factory.cpp b/src/item_factory.cpp index 9b4ce667f0f4b..c7f736d1e3eef 100644 --- a/src/item_factory.cpp +++ b/src/item_factory.cpp @@ -2575,7 +2575,7 @@ void hflesh_to_flesh( itype &item_template ) // Only add "flesh" material if not already present if( old_size != mats.size() && std::find( mats.begin(), mats.end(), material_id( "flesh" ) ) == mats.end() ) { - mats.push_back( material_id( "flesh" ) ); + mats.emplace_back( "flesh" ); } } @@ -3402,10 +3402,10 @@ bool Item_factory::load_sub_ref( std::unique_ptr &ptr, const Js iname, gname ) ); } if( obj.has_string( iname ) ) { - entries.push_back( std::make_pair( obj.get_string( iname ), false ) ); + entries.emplace_back( obj.get_string( iname ), false ); } if( obj.has_string( gname ) ) { - entries.push_back( std::make_pair( obj.get_string( gname ), true ) ); + entries.emplace_back( obj.get_string( gname ), true ); } const std::string subcontext = name + " of " + parent.context(); diff --git a/src/item_pocket.cpp b/src/item_pocket.cpp index e24dcdf436702..77528f33c5b26 100644 --- a/src/item_pocket.cpp +++ b/src/item_pocket.cpp @@ -822,7 +822,7 @@ void item_pocket::set_item_defaults() static void insert_separation_line( std::vector &info ) { if( info.empty() || info.back().sName != "--" ) { - info.push_back( iteminfo( "DESCRIPTION", "--" ) ); + info.emplace_back( "DESCRIPTION", "--" ); } } @@ -851,10 +851,10 @@ void item_pocket::general_info( std::vector &info, int pocket_number, if( data->max_item_length != 0_mm ) { info.back().bNewLine = true; - info.push_back( iteminfo( "BASE", _( "Maximum item length: " ), - string_format( " %s", length_units( data->max_item_length ) ), - iteminfo::no_flags, - convert_length( data->max_item_length ) ) ); + info.emplace_back( "BASE", _( "Maximum item length: " ), + string_format( " %s", length_units( data->max_item_length ) ), + iteminfo::no_flags, + convert_length( data->max_item_length ) ); } if( data->min_item_volume > 0_ml ) { @@ -1677,19 +1677,19 @@ std::string enumerate( cata::flat_set container ) void item_pocket::favorite_settings::info( std::vector &info ) const { - info.push_back( iteminfo( "BASE", string_format( "%s %d", _( "Priority:" ), priority_rating ) ) ); - info.push_back( iteminfo( "BASE", string_format( _( "Item Whitelist: %s" ), - item_whitelist.empty() ? _( "(empty)" ) : + info.emplace_back( "BASE", string_format( "%s %d", _( "Priority:" ), priority_rating ) ); + info.emplace_back( "BASE", string_format( _( "Item Whitelist: %s" ), + item_whitelist.empty() ? _( "(empty)" ) : enumerate_as_string( item_whitelist.begin(), item_whitelist.end(), []( const itype_id & id ) { return id->nname( 1 ); - } ) ) ) ); - info.push_back( iteminfo( "BASE", string_format( _( "Item Blacklist: %s" ), - item_blacklist.empty() ? _( "(empty)" ) : + } ) ) ); + info.emplace_back( "BASE", string_format( _( "Item Blacklist: %s" ), + item_blacklist.empty() ? _( "(empty)" ) : enumerate_as_string( item_blacklist.begin(), item_blacklist.end(), []( const itype_id & id ) { return id->nname( 1 ); - } ) ) ) ); - info.push_back( iteminfo( "BASE", string_format( _( "Category Whitelist: %s" ), - category_whitelist.empty() ? _( "(empty)" ) : enumerate( category_whitelist ) ) ) ); - info.push_back( iteminfo( "BASE", string_format( _( "Category Blacklist: %s" ), - category_blacklist.empty() ? _( "(empty)" ) : enumerate( category_blacklist ) ) ) ); + } ) ) ); + info.emplace_back( "BASE", string_format( _( "Category Whitelist: %s" ), + category_whitelist.empty() ? _( "(empty)" ) : enumerate( category_whitelist ) ) ); + info.emplace_back( "BASE", string_format( _( "Category Blacklist: %s" ), + category_blacklist.empty() ? _( "(empty)" ) : enumerate( category_blacklist ) ) ); } diff --git a/src/iuse.cpp b/src/iuse.cpp index 465c9004b9ad8..e29ef74089286 100644 --- a/src/iuse.cpp +++ b/src/iuse.cpp @@ -1856,7 +1856,7 @@ cata::optional iuse::fishing_rod( player *p, item *it, bool, const tripoint } p->add_msg_if_player( _( "You cast your line and wait to hook something…" ) ); p->assign_activity( ACT_FISH, to_moves( 5_hours ), 0, 0, it->tname() ); - p->activity.targets.push_back( item_location( *p, it ) ); + p->activity.targets.emplace_back( *p, it ); p->activity.coord_set = g->get_fishable_locations( 60, *found ); return 0; } @@ -2128,7 +2128,7 @@ cata::optional iuse::pack_cbm( player *p, item *it, bool, const tripoint & } std::vector comps; - comps.push_back( item_comp( it->typeId(), 1 ) ); + comps.emplace_back( it->typeId(), 1 ); p->consume_items( comps, 1, is_crafting_component ); return 0; @@ -3378,7 +3378,7 @@ cata::optional iuse::jackhammer( player *p, item *it, bool, const tripoint } p->assign_activity( ACT_JACKHAMMER, moves ); - p->activity.targets.push_back( item_location( *p, it ) ); + p->activity.targets.emplace_back( *p, it ); p->activity.placement = here.getabs( pnt ); // You can mine either furniture or terrain, and furniture goes first, @@ -3490,7 +3490,7 @@ cata::optional iuse::pickaxe( player *p, item *it, bool, const tripoint &po } p->assign_activity( ACT_PICKAXE, moves, -1 ); - p->activity.targets.push_back( item_location( *p, it ) ); + p->activity.targets.emplace_back( *p, it ); p->activity.placement = here.getabs( pnt ); // You can mine either furniture or terrain, and furniture goes first, @@ -4497,11 +4497,11 @@ cata::optional iuse::portable_game( player *p, item *it, bool active, const if( loaded_software == "null" ) { p->assign_activity( ACT_GENERIC_GAME, to_moves( 1_hours ), -1, p->get_item_position( it ), "gaming" ); - p->activity.targets.push_back( item_location( *p, it ) ); + p->activity.targets.emplace_back( *p, it ); return 0; } p->assign_activity( ACT_GAME, moves, -1, 0, "gaming" ); - p->activity.targets.push_back( item_location( *p, it ) ); + p->activity.targets.emplace_back( *p, it ); std::map game_data; game_data.clear(); int game_score = 0; @@ -4588,7 +4588,7 @@ cata::optional iuse::hand_crank( player *p, item *it, bool, const tripoint p->add_msg_if_player( _( "You start cranking the %s to charge its %s." ), it->tname(), it->magazine_current()->tname() ); p->assign_activity( ACT_HAND_CRANK, moves, -1, 0, "hand-cranking" ); - p->activity.targets.push_back( item_location( *p, it ) ); + p->activity.targets.emplace_back( *p, it ); } else { p->add_msg_if_player( _( "You could use the %s to charge its %s, but it's already charged." ), it->tname(), magazine->tname() ); @@ -4634,7 +4634,7 @@ cata::optional iuse::vibe( player *p, item *it, bool, const tripoint & ) it->tname() ); } p->assign_activity( ACT_VIBE, moves, -1, 0, "de-stressing" ); - p->activity.targets.push_back( item_location( *p, it ) ); + p->activity.targets.emplace_back( *p, it ); } return it->type->charges_to_use(); } @@ -4806,7 +4806,7 @@ cata::optional iuse::mind_splicer( player *p, item *it, bool, const tripoin skill_firstaid ) - 1 ) - 10_minutes * ( p->get_dex() - 8 ), 30_minutes ); player_activity act( ACT_MIND_SPLICER, to_moves( time ) ); - act.targets.push_back( item_location( *p, &data_card ) ); + act.targets.emplace_back( *p, &data_card ); p->assign_activity( act ); return it->type->charges_to_use(); } @@ -5081,7 +5081,7 @@ cata::optional iuse::oxytorch( player *p, item *it, bool, const tripoint & // placing ter here makes resuming tasks work better p->assign_activity( ACT_OXYTORCH, moves, static_cast( ter ) ); - p->activity.targets.push_back( item_location( *p, it ) ); + p->activity.targets.emplace_back( *p, it ); p->activity.placement = pnt; p->activity.values.push_back( charges ); @@ -5397,7 +5397,7 @@ static bool heat_item( player &p ) } p.add_msg_if_player( m_info, _( "You start heating up the food." ) ); p.assign_activity( ACT_HEATING, duration ); - p.activity.targets.push_back( item_location( p, target ) ); + p.activity.targets.emplace_back( p, target ); return true; } @@ -6515,7 +6515,7 @@ cata::optional iuse::einktabletpc( player *p, item *it, bool t, const tripo if( s.empty() ) { continue; } - monster_photos.push_back( mtype_id( s ) ); + monster_photos.emplace_back( s ); std::string menu_str; const monster dummy( monster_photos.back() ); menu_str = dummy.name(); @@ -7650,7 +7650,7 @@ cata::optional iuse::camera( player *p, item *it, bool, const tripoint & ) continue; } - monster_photos.push_back( mtype_id( s ) ); + monster_photos.emplace_back( s ); std::string menu_str; @@ -9609,7 +9609,7 @@ cata::optional iuse::break_stick( player *p, item *it, bool, const tripoint return 0; } std::vector comps; - comps.push_back( item_comp( it->typeId(), 1 ) ); + comps.emplace_back( it->typeId(), 1 ); p->consume_items( comps, 1, is_crafting_component ); int chance = rng( 0, 100 ); map &here = get_map(); diff --git a/src/iuse_actor.cpp b/src/iuse_actor.cpp index a405503e41496..df8f9da629c46 100644 --- a/src/iuse_actor.cpp +++ b/src/iuse_actor.cpp @@ -1116,7 +1116,7 @@ void reveal_map_actor::load( const JsonObject &obj ) ter_match_type = jo.get_enum_value( "om_terrain_match_type", ot_match_type::contains ); } - omt_types.push_back( std::make_pair( ter, ter_match_type ) ); + omt_types.emplace_back( ter, ter_match_type ); } } @@ -1319,7 +1319,7 @@ cata::optional firestarter_actor::use( player &p, item &it, bool t, moves_modifier + moves_cost_fast / 100.0 + 2; p.assign_activity( ACT_START_FIRE, moves, potential_skill_gain, 0, it.tname() ); - p.activity.targets.push_back( item_location( p, &it ) ); + p.activity.targets.emplace_back( p, &it ); p.activity.values.push_back( g->natural_light_level( pos.z ) ); p.activity.placement = pos; // charges to use are handled by the activity @@ -3176,8 +3176,8 @@ cata::optional heal_actor::use( player &p, item &it, bool, const tripoint & // Assign first aid long action. /** @EFFECT_FIRSTAID speeds up firstaid activity */ p.assign_activity( ACT_FIRSTAID, cost, 0, 0, it.tname() ); - p.activity.targets.push_back( item_location( p, &it ) ); - p.activity.str_values.push_back( hpp.c_str() ); + p.activity.targets.emplace_back( p, &it ); + p.activity.str_values.emplace_back( hpp.c_str() ); p.moves = 0; return 0; } @@ -4242,7 +4242,7 @@ void sew_advanced_actor::load( const JsonObject &obj ) materials.emplace( line ); } for( const std::string line : obj.get_array( "clothing_mods" ) ) { - clothing_mods.push_back( clothing_mod_id( line ) ); + clothing_mods.emplace_back( line ); } // TODO: Make skill non-mandatory while still erroring on invalid skill @@ -4426,7 +4426,7 @@ cata::optional sew_advanced_actor::use( player &p, item &it, bool, const tr const auto &repair_item = clothing_mods[choice].obj().item_string; std::vector comps; - comps.push_back( item_comp( repair_item, items_needed ) ); + comps.emplace_back( repair_item, items_needed ); p.moves -= to_moves( 30_seconds * p.fine_detail_vision_mod() ); p.practice( used_skill, items_needed * 3 + 3 ); /** @EFFECT_TAILOR randomly improves clothing modification efforts */ diff --git a/src/iuse_software_lightson.cpp b/src/iuse_software_lightson.cpp index c2d31d366fe64..5da853e453317 100644 --- a/src/iuse_software_lightson.cpp +++ b/src/iuse_software_lightson.cpp @@ -154,9 +154,9 @@ int lightson_game::start_game() ui.on_redraw( [&]( const ui_adaptor & ) { std::vector shortcuts; - shortcuts.push_back( _( " toggle lights" ) ); - shortcuts.push_back( _( "eset" ) ); - shortcuts.push_back( _( "uit" ) ); + shortcuts.emplace_back( _( " toggle lights" ) ); + shortcuts.emplace_back( _( "eset" ) ); + shortcuts.emplace_back( _( "uit" ) ); int iWidth = 0; for( auto &shortcut : shortcuts ) { diff --git a/src/iuse_software_minesweeper.cpp b/src/iuse_software_minesweeper.cpp index 3b48b64ed08c1..ef59e867203c3 100644 --- a/src/iuse_software_minesweeper.cpp +++ b/src/iuse_software_minesweeper.cpp @@ -183,9 +183,9 @@ int minesweeper_game::start_game() draw_border( w_minesweeper_border ); std::vector shortcuts; - shortcuts.push_back( _( "ew level" ) ); - shortcuts.push_back( _( "lag" ) ); - shortcuts.push_back( _( "uit" ) ); + shortcuts.emplace_back( _( "ew level" ) ); + shortcuts.emplace_back( _( "lag" ) ); + shortcuts.emplace_back( _( "uit" ) ); int iWidth = 0; for( auto &shortcut : shortcuts ) { diff --git a/src/iuse_software_snake.cpp b/src/iuse_software_snake.cpp index a5baba6558447..0ae65f9f414c2 100644 --- a/src/iuse_software_snake.cpp +++ b/src/iuse_software_snake.cpp @@ -61,18 +61,18 @@ void snake_game::snake_over( const catacurses::window &w_snake, int iScore ) mvwputch( w_snake, point( 71, body_length + 2 ), c_green, 'v' ); std::vector game_over_text; - game_over_text.push_back( R"( ________ _____ _____ ___________)" ); - game_over_text.push_back( R"( / _____/ / _ \ / \ \_ _____/)" ); - game_over_text.push_back( R"(/ \ ___ / /_\ \ / \ / \ | __)_ )" ); - game_over_text.push_back( R"(\ \_\ \/ | \/ Y \ | \)" ); - game_over_text.push_back( R"( \______ /\____|__ /\____|__ //_______ /)" ); - game_over_text.push_back( R"( \/ \/ \/ \/ )" ); - game_over_text.push_back( R"( ________ ____ _________________________ )" ); - game_over_text.push_back( R"( \_____ \\ \ / /\_ _____/\______ \ )" ); - game_over_text.push_back( R"( / | \\ Y / | __)_ | _/ )" ); - game_over_text.push_back( R"( / | \\ / | \ | | \ )" ); - game_over_text.push_back( R"( \_______ / \___/ /_______ / |____|_ / )" ); - game_over_text.push_back( R"( \/ \/ \/ )" ); + game_over_text.emplace_back( R"( ________ _____ _____ ___________)" ); + game_over_text.emplace_back( R"( / _____/ / _ \ / \ \_ _____/)" ); + game_over_text.emplace_back( R"(/ \ ___ / /_\ \ / \ / \ | __)_ )" ); + game_over_text.emplace_back( R"(\ \_\ \/ | \/ Y \ | \)" ); + game_over_text.emplace_back( R"( \______ /\____|__ /\____|__ //_______ /)" ); + game_over_text.emplace_back( R"( \/ \/ \/ \/ )" ); + game_over_text.emplace_back( R"( ________ ____ _________________________ )" ); + game_over_text.emplace_back( R"( \_____ \\ \ / /\_ _____/\______ \ )" ); + game_over_text.emplace_back( R"( / | \\ Y / | __)_ | _/ )" ); + game_over_text.emplace_back( R"( / | \\ / | \ | | \ )" ); + game_over_text.emplace_back( R"( \_______ / \___/ /_______ / |____|_ / )" ); + game_over_text.emplace_back( R"( \/ \/ \/ )" ); for( size_t i = 0; i < game_over_text.size(); i++ ) { mvwprintz( w_snake, point( 17, i + 3 ), c_light_red, game_over_text[i] ); @@ -103,7 +103,7 @@ int snake_game::start_game() ui.mark_resize(); //Snake start position - vSnakeBody.push_back( std::make_pair( FULL_SCREEN_HEIGHT / 2, FULL_SCREEN_WIDTH / 2 ) ); + vSnakeBody.emplace_back( FULL_SCREEN_HEIGHT / 2, FULL_SCREEN_WIDTH / 2 ); mSnakeBody[FULL_SCREEN_HEIGHT / 2][FULL_SCREEN_WIDTH / 2] = true; //Snake start direction @@ -144,28 +144,28 @@ int snake_game::start_game() do { //Check if we hit a border if( vSnakeBody[vSnakeBody.size() - 1].first + iDirY == 0 ) { - vSnakeBody.push_back( std::make_pair( vSnakeBody[vSnakeBody.size() - 1].first + - iDirY + FULL_SCREEN_HEIGHT - 2, - vSnakeBody[vSnakeBody.size() - 1].second + iDirX ) ); + vSnakeBody.emplace_back( vSnakeBody[vSnakeBody.size() - 1].first + + iDirY + FULL_SCREEN_HEIGHT - 2, + vSnakeBody[vSnakeBody.size() - 1].second + iDirX ); } else if( vSnakeBody[vSnakeBody.size() - 1].first + iDirY == FULL_SCREEN_HEIGHT - 1 ) { - vSnakeBody.push_back( std::make_pair( vSnakeBody[vSnakeBody.size() - 1].first + - iDirY - FULL_SCREEN_HEIGHT + 2, - vSnakeBody[vSnakeBody.size() - 1].second + iDirX ) ); + vSnakeBody.emplace_back( vSnakeBody[vSnakeBody.size() - 1].first + + iDirY - FULL_SCREEN_HEIGHT + 2, + vSnakeBody[vSnakeBody.size() - 1].second + iDirX ); } else if( vSnakeBody[vSnakeBody.size() - 1].second + iDirX == 0 ) { - vSnakeBody.push_back( std::make_pair( vSnakeBody[vSnakeBody.size() - 1].first + iDirY, - vSnakeBody[vSnakeBody.size() - 1].second + - iDirX + FULL_SCREEN_WIDTH - 2 ) ); + vSnakeBody.emplace_back( vSnakeBody[vSnakeBody.size() - 1].first + iDirY, + vSnakeBody[vSnakeBody.size() - 1].second + + iDirX + FULL_SCREEN_WIDTH - 2 ); } else if( vSnakeBody[vSnakeBody.size() - 1].second + iDirX == FULL_SCREEN_WIDTH - 1 ) { - vSnakeBody.push_back( std::make_pair( vSnakeBody[vSnakeBody.size() - 1].first + iDirY, - vSnakeBody[vSnakeBody.size() - 1].second + - iDirX - FULL_SCREEN_WIDTH + 2 ) ); + vSnakeBody.emplace_back( vSnakeBody[vSnakeBody.size() - 1].first + iDirY, + vSnakeBody[vSnakeBody.size() - 1].second + + iDirX - FULL_SCREEN_WIDTH + 2 ); } else { - vSnakeBody.push_back( std::make_pair( vSnakeBody[vSnakeBody.size() - 1].first + iDirY, - vSnakeBody[vSnakeBody.size() - 1].second + iDirX ) ); + vSnakeBody.emplace_back( vSnakeBody[vSnakeBody.size() - 1].first + iDirY, + vSnakeBody[vSnakeBody.size() - 1].second + iDirX ); } //Check if we hit ourselves diff --git a/src/iuse_software_sokoban.cpp b/src/iuse_software_sokoban.cpp index d321c0b39baec..bd46d21555229 100644 --- a/src/iuse_software_sokoban.cpp +++ b/src/iuse_software_sokoban.cpp @@ -248,11 +248,11 @@ int sokoban_game::start_game() draw_border( w_sokoban, BORDER_COLOR, _( "Sokoban" ), hilite( c_white ) ); std::vector shortcuts; - shortcuts.push_back( _( "<+> next" ) ); // '+': next - shortcuts.push_back( _( "<-> prev" ) ); // '-': prev - shortcuts.push_back( _( "eset" ) ); // 'r': reset - shortcuts.push_back( _( "uit" ) ); // 'q': quit - shortcuts.push_back( _( "ndo move" ) ); // 'u': undo move + shortcuts.emplace_back( _( "<+> next" ) ); // '+': next + shortcuts.emplace_back( _( "<-> prev" ) ); // '-': prev + shortcuts.emplace_back( _( "eset" ) ); // 'r': reset + shortcuts.emplace_back( _( "uit" ) ); // 'q': quit + shortcuts.emplace_back( _( "ndo move" ) ); // 'u': undo move int indent = 10; for( auto &shortcut : shortcuts ) { @@ -378,7 +378,7 @@ int sokoban_game::start_game() bMovePlayer = true; mLevel[iPlayerY + iDirY * 2][iPlayerX + iDirX * 2] = sMovePackTo == "." ? "*" : "$"; - vUndo.push_back( cUndo( point( iDirX, iDirY ), sMoveTo ) ); + vUndo.emplace_back( point( iDirX, iDirY ), sMoveTo ); iMoves--; } @@ -388,7 +388,7 @@ int sokoban_game::start_game() if( bMovePlayer ) { //move player - vUndo.push_back( cUndo( point( iPlayerX, iPlayerY ), mLevel[iPlayerY][iPlayerX] ) ); + vUndo.emplace_back( point( iPlayerX, iPlayerY ), mLevel[iPlayerY][iPlayerX] ); mLevel[iPlayerY][iPlayerX] = mLevel[iPlayerY][iPlayerX] == "+" ? "." : " "; mLevel[iPlayerY + iDirY][iPlayerX + iDirX] = sMoveTo == "." || sMoveTo == "*" ? "+" : "@"; diff --git a/src/lightmap.cpp b/src/lightmap.cpp index 9c0de7c0b5aff..e82fb2c985608 100644 --- a/src/lightmap.cpp +++ b/src/lightmap.cpp @@ -493,7 +493,7 @@ void map::generate_lightmap( const int zlev ) } const float light_override = cur->get_intensity_level().local_light_override; if( light_override >= 0.0f ) { - lm_override.push_back( std::pair( p, light_override ) ); + lm_override.emplace_back( p, light_override ); } } } diff --git a/src/line.cpp b/src/line.cpp index 98bf894853642..4c3959731b03f 100644 --- a/src/line.cpp +++ b/src/line.cpp @@ -548,16 +548,16 @@ std::vector squares_in_direction( const point &p1, const point &p2 ) adjacent_squares.push_back( center_square ); if( p1.x == center_square.x ) { // Horizontally adjacent. - adjacent_squares.push_back( point( p1.x + 1, center_square.y ) ); - adjacent_squares.push_back( point( p1.x - 1, center_square.y ) ); + adjacent_squares.emplace_back( p1.x + 1, center_square.y ); + adjacent_squares.emplace_back( p1.x - 1, center_square.y ); } else if( p1.y == center_square.y ) { // Vertically adjacent. - adjacent_squares.push_back( point( center_square.x, p1.y + 1 ) ); - adjacent_squares.push_back( point( center_square.x, p1.y - 1 ) ); + adjacent_squares.emplace_back( center_square.x, p1.y + 1 ); + adjacent_squares.emplace_back( center_square.x, p1.y - 1 ); } else { // Diagonally adjacent. - adjacent_squares.push_back( point( p1.x, center_square.y ) ); - adjacent_squares.push_back( point( center_square.x, p1.y ) ); + adjacent_squares.emplace_back( p1.x, center_square.y ); + adjacent_squares.emplace_back( center_square.x, p1.y ); } return adjacent_squares; } diff --git a/src/main_menu.cpp b/src/main_menu.cpp index 79a464c2eb188..45ea33525edeb 100644 --- a/src/main_menu.cpp +++ b/src/main_menu.cpp @@ -351,15 +351,15 @@ void main_menu::init_strings() // fill menu with translated menu items vMenuItems.clear(); - vMenuItems.push_back( pgettext( "Main Menu", "OTD" ) ); - vMenuItems.push_back( pgettext( "Main Menu", "ew Game" ) ); - vMenuItems.push_back( pgettext( "Main Menu", "Lod" ) ); - vMenuItems.push_back( pgettext( "Main Menu", "orld" ) ); - vMenuItems.push_back( pgettext( "Main Menu", "pecial" ) ); - vMenuItems.push_back( pgettext( "Main Menu", "Setings" ) ); - vMenuItems.push_back( pgettext( "Main Menu", "Hlp" ) ); - vMenuItems.push_back( pgettext( "Main Menu", "redits" ) ); - vMenuItems.push_back( pgettext( "Main Menu", "uit" ) ); + vMenuItems.emplace_back( pgettext( "Main Menu", "OTD" ) ); + vMenuItems.emplace_back( pgettext( "Main Menu", "ew Game" ) ); + vMenuItems.emplace_back( pgettext( "Main Menu", "Lod" ) ); + vMenuItems.emplace_back( pgettext( "Main Menu", "orld" ) ); + vMenuItems.emplace_back( pgettext( "Main Menu", "pecial" ) ); + vMenuItems.emplace_back( pgettext( "Main Menu", "Setings" ) ); + vMenuItems.emplace_back( pgettext( "Main Menu", "Hlp" ) ); + vMenuItems.emplace_back( pgettext( "Main Menu", "redits" ) ); + vMenuItems.emplace_back( pgettext( "Main Menu", "uit" ) ); // determine hotkeys from translated menu item text vMenuHotkeys.clear(); @@ -368,11 +368,11 @@ void main_menu::init_strings() } vWorldSubItems.clear(); - vWorldSubItems.push_back( pgettext( "Main Menu|World", "elete World" ) ); - vWorldSubItems.push_back( pgettext( "Main Menu|World", "eset World" ) ); - vWorldSubItems.push_back( pgettext( "Main Menu|World", "how World Mods" ) ); - vWorldSubItems.push_back( pgettext( "Main Menu|World", "opy World Settings" ) ); - vWorldSubItems.push_back( pgettext( "Main Menu|World", "Character to emplate" ) ); + vWorldSubItems.emplace_back( pgettext( "Main Menu|World", "elete World" ) ); + vWorldSubItems.emplace_back( pgettext( "Main Menu|World", "eset World" ) ); + vWorldSubItems.emplace_back( pgettext( "Main Menu|World", "how World Mods" ) ); + vWorldSubItems.emplace_back( pgettext( "Main Menu|World", "opy World Settings" ) ); + vWorldSubItems.emplace_back( pgettext( "Main Menu|World", "Character to emplate" ) ); vWorldHotkeys.clear(); for( const std::string &item : vWorldSubItems ) { @@ -380,11 +380,11 @@ void main_menu::init_strings() } vSettingsSubItems.clear(); - vSettingsSubItems.push_back( pgettext( "Main Menu|Settings", "ptions" ) ); - vSettingsSubItems.push_back( pgettext( "Main Menu|Settings", "Kybindings" ) ); - vSettingsSubItems.push_back( pgettext( "Main Menu|Settings", "utopickup" ) ); - vSettingsSubItems.push_back( pgettext( "Main Menu|Settings", "afemode" ) ); - vSettingsSubItems.push_back( pgettext( "Main Menu|Settings", "olors" ) ); + vSettingsSubItems.emplace_back( pgettext( "Main Menu|Settings", "ptions" ) ); + vSettingsSubItems.emplace_back( pgettext( "Main Menu|Settings", "Kybindings" ) ); + vSettingsSubItems.emplace_back( pgettext( "Main Menu|Settings", "utopickup" ) ); + vSettingsSubItems.emplace_back( pgettext( "Main Menu|Settings", "afemode" ) ); + vSettingsSubItems.emplace_back( pgettext( "Main Menu|Settings", "olors" ) ); vSettingsHotkeys.clear(); for( const std::string &item : vSettingsSubItems ) { @@ -747,23 +747,22 @@ bool main_menu::opening_screen() bool main_menu::new_character_tab() { std::vector vSubItems; - vSubItems.push_back( pgettext( "Main Menu|New Game", "ustom Character" ) ); - vSubItems.push_back( pgettext( "Main Menu|New Game", "reset Character" ) ); - vSubItems.push_back( pgettext( "Main Menu|New Game", "andom Character" ) ); + vSubItems.emplace_back( pgettext( "Main Menu|New Game", "ustom Character" ) ); + vSubItems.emplace_back( pgettext( "Main Menu|New Game", "reset Character" ) ); + vSubItems.emplace_back( pgettext( "Main Menu|New Game", "andom Character" ) ); if( !MAP_SHARING::isSharing() ) { // "Play Now" function doesn't play well together with shared maps - vSubItems.push_back( pgettext( "Main Menu|New Game", "Play Now! (ixed Scenario)" ) ); - vSubItems.push_back( pgettext( "Main Menu|New Game", "Play ow!" ) ); + vSubItems.emplace_back( pgettext( "Main Menu|New Game", "Play Now! (ixed Scenario)" ) ); + vSubItems.emplace_back( pgettext( "Main Menu|New Game", "Play ow!" ) ); } std::vector hints; - hints.push_back( + hints.emplace_back( _( "Allows you to fully customize points pool, scenario, and character's profession, stats, traits, skills and other parameters." ) ); - hints.push_back( - _( "Select from one of previously created character templates." ) ); - hints.push_back( + hints.emplace_back( _( "Select from one of previously created character templates." ) ); + hints.emplace_back( _( "Creates random character, but lets you preview the generated character and the scenario and change character and/or scenario if needed." ) ); - hints.push_back( + hints.emplace_back( _( "Puts you right in the game, randomly choosing character's traits, profession, skills and other parameters. Scenario is fixed to Evacuee." ) ); - hints.push_back( + hints.emplace_back( _( "Puts you right in the game, randomly choosing scenario and character's traits, profession, skills and other parameters." ) ); std::vector> vNewGameHotkeys; diff --git a/src/map.cpp b/src/map.cpp index dbc0a112b5fe1..1f40aaf68e2a9 100644 --- a/src/map.cpp +++ b/src/map.cpp @@ -3078,7 +3078,7 @@ void map::smash_items( const tripoint &p, const int power, const std::string &ca // But save the contents, except for irremovable gunmods for( item *elem : i->contents.all_items_top() ) { if( !elem->is_irremovable() ) { - contents.push_back( item( *elem ) ); + contents.emplace_back( *elem ); } } @@ -3491,7 +3491,7 @@ void map::bash_items( const tripoint &p, bash_params ¶ms ) params.did_bash = true; smashed_glass = true; for( const item *bashed_content : bashed_item->contents.all_items_top() ) { - smashed_contents.push_back( item( *bashed_content ) ); + smashed_contents.emplace_back( *bashed_content ); } bashed_item = bashed_items.erase( bashed_item ); } else { @@ -5149,7 +5149,7 @@ std::list > map::get_rc_items( const tripoint &p ) map_stack items = i_at( pos ); for( auto &elem : items ) { if( elem.has_flag( flag_RADIO_ACTIVATION ) || elem.has_flag( flag_RADIO_CONTAINER ) ) { - rc_pairs.push_back( std::make_pair( pos, &elem ) ); + rc_pairs.emplace_back( pos, &elem ); } } } diff --git a/src/map_field.cpp b/src/map_field.cpp index dfa2eacfc8623..59d7b0e00f42e 100644 --- a/src/map_field.cpp +++ b/src/map_field.cpp @@ -979,7 +979,7 @@ void field_processor_fd_fire( const tripoint &p, field_entry &cur, field_proc_da const std::list content_list = fuel->contents.all_items_top(); for( item *it : content_list ) { if( !it->is_irremovable() ) { - new_content.push_back( item( *it ) ); + new_content.emplace_back( *it ); } } fuel = items_here.erase( fuel ); @@ -1516,19 +1516,19 @@ void map::player_in_field( player &u ) if( !u.is_on_ground() ) { switch( adjusted_intensity ) { case 3: - parts_burned.push_back( bodypart_id( "hand_l" ) ); - parts_burned.push_back( bodypart_id( "hand_r" ) ); - parts_burned.push_back( bodypart_id( "arm_l" ) ); - parts_burned.push_back( bodypart_id( "arm_r" ) ); + parts_burned.emplace_back( "hand_l" ); + parts_burned.emplace_back( "hand_r" ); + parts_burned.emplace_back( "arm_l" ); + parts_burned.emplace_back( "arm_r" ); /* fallthrough */ case 2: - parts_burned.push_back( bodypart_id( "torso" ) ); + parts_burned.emplace_back( "torso" ); /* fallthrough */ case 1: - parts_burned.push_back( bodypart_id( "foot_l" ) ); - parts_burned.push_back( bodypart_id( "foot_r" ) ); - parts_burned.push_back( bodypart_id( "leg_l" ) ); - parts_burned.push_back( bodypart_id( "leg_r" ) ); + parts_burned.emplace_back( "foot_l" ); + parts_burned.emplace_back( "foot_r" ); + parts_burned.emplace_back( "leg_l" ); + parts_burned.emplace_back( "leg_r" ); } } else { // Lying in the fire is BAAAD news, hits every body part. diff --git a/src/map_item_stack.cpp b/src/map_item_stack.cpp index 362ee16528200..4d18fb414bdd9 100644 --- a/src/map_item_stack.cpp +++ b/src/map_item_stack.cpp @@ -21,7 +21,7 @@ map_item_stack::item_group::item_group( const tripoint &p, const int arg_count, map_item_stack::map_item_stack() : example( nullptr ), totalcount( 0 ) { - vIG.push_back( item_group() ); + vIG.emplace_back( ); } map_item_stack::map_item_stack( const item *const it, const tripoint &pos ) : example( it ), diff --git a/src/mapgen.cpp b/src/mapgen.cpp index d6ebf48bb3446..763673c2bcca1 100644 --- a/src/mapgen.cpp +++ b/src/mapgen.cpp @@ -1328,7 +1328,7 @@ class jmapgen_monster : public jmapgen_piece for( const JsonObject p_pt : patrol_pts ) { jmapgen_int ptx = jmapgen_int( p_pt, "x" ); jmapgen_int pty = jmapgen_int( p_pt, "y" ); - data.patrol_points_rel_ms.push_back( point( ptx.get(), pty.get() ) ); + data.patrol_points_rel_ms.emplace_back( ptx.get(), pty.get() ); } } } @@ -3224,37 +3224,37 @@ void map::draw_lab( mapgendata &dat ) if( is_ot_match( "stairs", terrain_type, ot_match_type::contains ) ) { // Stairs going down std::vector stair_points; if( tw != 0 ) { - stair_points.push_back( point( SEEX - 1, 2 ) ); - stair_points.push_back( point( SEEX - 1, 2 ) ); - stair_points.push_back( point( SEEX, 2 ) ); - stair_points.push_back( point( SEEX, 2 ) ); + stair_points.emplace_back( SEEX - 1, 2 ); + stair_points.emplace_back( SEEX - 1, 2 ); + stair_points.emplace_back( SEEX, 2 ); + stair_points.emplace_back( SEEX, 2 ); } if( rw != 1 ) { - stair_points.push_back( point( SEEX * 2 - 3, SEEY - 1 ) ); - stair_points.push_back( point( SEEX * 2 - 3, SEEY - 1 ) ); - stair_points.push_back( point( SEEX * 2 - 3, SEEY ) ); - stair_points.push_back( point( SEEX * 2 - 3, SEEY ) ); + stair_points.emplace_back( SEEX * 2 - 3, SEEY - 1 ); + stair_points.emplace_back( SEEX * 2 - 3, SEEY - 1 ); + stair_points.emplace_back( SEEX * 2 - 3, SEEY ); + stair_points.emplace_back( SEEX * 2 - 3, SEEY ); } if( bw != 1 ) { - stair_points.push_back( point( SEEX - 1, SEEY * 2 - 3 ) ); - stair_points.push_back( point( SEEX - 1, SEEY * 2 - 3 ) ); - stair_points.push_back( point( SEEX, SEEY * 2 - 3 ) ); - stair_points.push_back( point( SEEX, SEEY * 2 - 3 ) ); + stair_points.emplace_back( SEEX - 1, SEEY * 2 - 3 ); + stair_points.emplace_back( SEEX - 1, SEEY * 2 - 3 ); + stair_points.emplace_back( SEEX, SEEY * 2 - 3 ); + stair_points.emplace_back( SEEX, SEEY * 2 - 3 ); } if( lw != 0 ) { - stair_points.push_back( point( 2, SEEY - 1 ) ); - stair_points.push_back( point( 2, SEEY - 1 ) ); - stair_points.push_back( point( 2, SEEY ) ); - stair_points.push_back( point( 2, SEEY ) ); + stair_points.emplace_back( 2, SEEY - 1 ); + stair_points.emplace_back( 2, SEEY - 1 ); + stair_points.emplace_back( 2, SEEY ); + stair_points.emplace_back( 2, SEEY ); } - stair_points.push_back( point( static_cast( SEEX / 2 ), SEEY ) ); - stair_points.push_back( point( static_cast( SEEX / 2 ), SEEY - 1 ) ); - stair_points.push_back( point( static_cast( SEEX / 2 ) + SEEX, SEEY ) ); - stair_points.push_back( point( static_cast( SEEX / 2 ) + SEEX, SEEY - 1 ) ); - stair_points.push_back( point( SEEX, static_cast( SEEY / 2 ) ) ); - stair_points.push_back( point( SEEX + 2, static_cast( SEEY / 2 ) ) ); - stair_points.push_back( point( SEEX, static_cast( SEEY / 2 ) + SEEY ) ); - stair_points.push_back( point( SEEX + 2, static_cast( SEEY / 2 ) + SEEY ) ); + stair_points.emplace_back( static_cast( SEEX / 2 ), SEEY ); + stair_points.emplace_back( static_cast( SEEX / 2 ), SEEY - 1 ); + stair_points.emplace_back( static_cast( SEEX / 2 ) + SEEX, SEEY ); + stair_points.emplace_back( static_cast( SEEX / 2 ) + SEEX, SEEY - 1 ); + stair_points.emplace_back( SEEX, static_cast( SEEY / 2 ) ); + stair_points.emplace_back( SEEX + 2, static_cast( SEEY / 2 ) ); + stair_points.emplace_back( SEEX, static_cast( SEEY / 2 ) + SEEY ); + stair_points.emplace_back( SEEX + 2, static_cast( SEEY / 2 ) + SEEY ); const point p = random_entry( stair_points ); ter_set( p, t_stairs_down ); } @@ -4098,7 +4098,7 @@ void map::draw_temple( const mapgendata &dat ) static const std::vector terrains = { t_floor_red, t_floor_green, t_floor_blue, }; - path.push_back( point( x, y ) ); + path.emplace_back( x, y ); ter_set( point( x, y ), random_entry( terrains ) ); if( y == SEEY * 2 - 2 ) { if( x < SEEX - 1 ) { @@ -4111,7 +4111,7 @@ void map::draw_temple( const mapgendata &dat ) for( int nx = x - 1; nx <= x + 1; nx++ ) { for( int ny = y; ny <= y + 1; ny++ ) { if( ter( point( nx, ny ) ) == t_rock_floor ) { - next.push_back( point( nx, ny ) ); + next.emplace_back( nx, ny ); } } } diff --git a/src/mattack_actors.cpp b/src/mattack_actors.cpp index 77069b8f8e3e4..a54ebc7400933 100644 --- a/src/mattack_actors.cpp +++ b/src/mattack_actors.cpp @@ -548,7 +548,7 @@ void gun_actor::shoot( monster &z, Creature &target, const gun_mode_id &mode ) c standard_npc tmp( _( "The " ) + z.name(), z.pos(), {}, 8, fake_str, fake_dex, fake_int, fake_per ); - tmp.worn.push_back( item( "backpack" ) ); + tmp.worn.emplace_back( "backpack" ); tmp.set_fake( true ); tmp.set_attitude( z.friendly ? NPCATT_FOLLOW : NPCATT_KILL ); tmp.recoil = 0; // no need to aim diff --git a/src/memorial_logger.cpp b/src/memorial_logger.cpp index c5982bb223d8f..2475bb41d5c07 100644 --- a/src/memorial_logger.cpp +++ b/src/memorial_logger.cpp @@ -130,7 +130,7 @@ void memorial_logger::add( const std::string &male_msg, const oter_type_str_id cur_oter_type = cur_ter->get_type_id(); const std::string &oter_name = cur_ter->get_name(); - log.push_back( { calendar::turn, cur_oter_type, oter_name, msg } ); + log.emplace_back( calendar::turn, cur_oter_type, oter_name, msg ); } /** diff --git a/src/mission.cpp b/src/mission.cpp index 64848fb2f96ed..5df75c4ecfa90 100644 --- a/src/mission.cpp +++ b/src/mission.cpp @@ -358,7 +358,7 @@ void mission::wrap_up() container, itype_id( "null" ), specific_container_required ); for( std::pair &cnt : matches ) { - comps.push_back( item_comp( cnt.first, cnt.second ) ); + comps.emplace_back( cnt.first, cnt.second ); } @@ -367,10 +367,10 @@ void mission::wrap_up() if( remove_container ) { std::vector container_comp = std::vector(); if( !empty_container.is_null() ) { - container_comp.push_back( item_comp( empty_container, type->item_count ) ); + container_comp.emplace_back( empty_container, type->item_count ); player_character.consume_items( container_comp ); } else { - container_comp.push_back( item_comp( container, type->item_count ) ); + container_comp.emplace_back( container, type->item_count ); player_character.consume_items( container_comp ); } } @@ -390,7 +390,7 @@ void mission::wrap_up() } } } else { - comps.push_back( item_comp( type->item_id, item_count ) ); + comps.emplace_back( type->item_id, item_count ); player_character.consume_items( comps ); } } diff --git a/src/mod_manager.cpp b/src/mod_manager.cpp index bfc3361287005..12fd9c587479b 100644 --- a/src/mod_manager.cpp +++ b/src/mod_manager.cpp @@ -290,7 +290,7 @@ bool mod_manager::copy_mod_contents( const t_mod_list &mods_to_copy, return true; } std::vector search_extensions; - search_extensions.push_back( ".json" ); + search_extensions.emplace_back( ".json" ); DebugLog( D_INFO, DC_ALL ) << "Copying mod contents into directory: " << output_base_path; diff --git a/src/monattack.cpp b/src/monattack.cpp index 5215543897c9a..4f6924e7156c9 100644 --- a/src/monattack.cpp +++ b/src/monattack.cpp @@ -985,7 +985,7 @@ bool mattack::resurrect( monster *z ) int raise_score = ( i.damage_level() + 1 ) * mt->hp + i.burnt; lowest_raise_score = std::min( lowest_raise_score, raise_score ); if( raise_score <= raising_level ) { - corpses.push_back( std::make_pair( p, &i ) ); + corpses.emplace_back( p, &i ); } } } diff --git a/src/monexamine.cpp b/src/monexamine.cpp index 3d23556174d14..29aa3a909ef21 100644 --- a/src/monexamine.cpp +++ b/src/monexamine.cpp @@ -302,10 +302,10 @@ void monexamine::shear_animal( monster &z ) // pin the sheep in place if it isn't already if( !z.has_effect( effect_tied ) ) { z.add_effect( effect_tied, 1_turns, true ); - player_character.activity.str_values.push_back( "temp_tie" ); + player_character.activity.str_values.emplace_back( "temp_tie" ); } - player_character.activity.targets.push_back( item_location( player_character, - player_character.best_quality_item( qual_SHEAR ) ) ); + player_character.activity.targets.emplace_back( player_character, + player_character.best_quality_item( qual_SHEAR ) ); add_msg( _( "You start shearing the %s." ), z.get_name() ); } @@ -805,7 +805,7 @@ void monexamine::milk_source( monster &source_mon ) bool temp_tie = !source_mon.has_effect( effect_tied ); if( temp_tie ) { source_mon.add_effect( effect_tied, 1_turns, true ); - str_values.push_back( "temp_tie" ); + str_values.emplace_back( "temp_tie" ); } player_character.assign_activity( player_activity( milk_activity_actor( moves, coords, str_values ) ) ); diff --git a/src/mongroup.cpp b/src/mongroup.cpp index 599a33a4650d6..7c4ffcdaf57e7 100644 --- a/src/mongroup.cpp +++ b/src/mongroup.cpp @@ -128,13 +128,13 @@ MonsterGroupResult MonsterGroupManager::GetResultFromGroup( //Collect valid time of day ranges if( elem == "DAY" || elem == "NIGHT" || elem == "DUSK" || elem == "DAWN" ) { if( elem == "DAY" ) { - valid_times_of_day.push_back( std::make_pair( sunrise, sunset ) ); + valid_times_of_day.emplace_back( sunrise, sunset ); } else if( elem == "NIGHT" ) { - valid_times_of_day.push_back( std::make_pair( sunset, sunrise ) ); + valid_times_of_day.emplace_back( sunset, sunrise ); } else if( elem == "DUSK" ) { - valid_times_of_day.push_back( std::make_pair( sunset - 1_hours, sunset + 1_hours ) ); + valid_times_of_day.emplace_back( sunset - 1_hours, sunset + 1_hours ); } else if( elem == "DAWN" ) { - valid_times_of_day.push_back( std::make_pair( sunrise - 1_hours, sunrise + 1_hours ) ); + valid_times_of_day.emplace_back( sunrise - 1_hours, sunrise + 1_hours ); } } diff --git a/src/monmove.cpp b/src/monmove.cpp index 21644a2101bb8..1687bc7cb05b3 100644 --- a/src/monmove.cpp +++ b/src/monmove.cpp @@ -1401,7 +1401,7 @@ static std::vector get_bashing_zone( const tripoint &bashee, const tri for( const tripoint &p : path ) { std::vector swath = squares_in_direction( previous.xy(), p.xy() ); for( const point &q : swath ) { - zone.push_back( tripoint( q, bashee.z ) ); + zone.emplace_back( q, bashee.z ); } previous = p; @@ -1928,9 +1928,9 @@ void monster::stumble() for( const tripoint &dest : here.points_in_radius( pos(), 1 ) ) { if( dest != pos() ) { if( here.has_flag( TFLAG_RAMP_DOWN, dest ) ) { - valid_stumbles.push_back( tripoint( dest.xy(), dest.z - 1 ) ); + valid_stumbles.emplace_back( dest.xy(), dest.z - 1 ); } else if( here.has_flag( TFLAG_RAMP_UP, dest ) ) { - valid_stumbles.push_back( tripoint( dest.xy(), dest.z + 1 ) ); + valid_stumbles.emplace_back( dest.xy(), dest.z + 1 ); } else { valid_stumbles.push_back( dest ); } diff --git a/src/newcharacter.cpp b/src/newcharacter.cpp index 5b96fdd1d3a19..7a04272a385c8 100644 --- a/src/newcharacter.cpp +++ b/src/newcharacter.cpp @@ -2862,10 +2862,10 @@ tab_direction set_description( avatar &you, const bool allow_reroll, std::vector vStatNames; mvwprintz( w_stats, point_zero, COL_HEADER, _( "Stats:" ) ); - vStatNames.push_back( _( "Strength:" ) ); - vStatNames.push_back( _( "Dexterity:" ) ); - vStatNames.push_back( _( "Intelligence:" ) ); - vStatNames.push_back( _( "Perception:" ) ); + vStatNames.emplace_back( _( "Strength:" ) ); + vStatNames.emplace_back( _( "Dexterity:" ) ); + vStatNames.emplace_back( _( "Intelligence:" ) ); + vStatNames.emplace_back( _( "Perception:" ) ); int pos = 0; for( size_t i = 0; i < vStatNames.size(); i++ ) { pos = ( utf8_width( vStatNames[i] ) > pos ? diff --git a/src/npcmove.cpp b/src/npcmove.cpp index a27cd05da9531..2f3aa940d2244 100644 --- a/src/npcmove.cpp +++ b/src/npcmove.cpp @@ -1267,7 +1267,7 @@ void npc::execute_action( npc_action action ) my_spot = priority; } - seats.push_back( std::make_pair( priority, static_cast( vp.part_index() ) ) ); + seats.emplace_back( priority, static_cast( vp.part_index() ) ); } if( my_spot >= 3 ) { @@ -1406,7 +1406,7 @@ npc_action npc::method_of_attack() std::vector> modes; if( rules.has_flag( ally_rule::use_guns ) || !is_player_ally() ) { for( const auto &e : weapon.gun_all_modes() ) { - modes.push_back( e ); + modes.emplace_back( e ); } modes.erase( std::remove_if( modes.begin(), modes.end(), @@ -3149,7 +3149,7 @@ void npc::drop_items( const units::mass &drop_weight, const units::volume &drop_ } } if( !added_wgt ) { - rWgt.push_back( ratio_index( wgt_ratio, i ) ); + rWgt.emplace_back( wgt_ratio, i ); } for( size_t j = 0; j < rVol.size() && !added_vol; j++ ) { if( vol_ratio > rVol[j].ratio ) { @@ -3158,7 +3158,7 @@ void npc::drop_items( const units::mass &drop_weight, const units::volume &drop_ } } if( !added_vol ) { - rVol.push_back( ratio_index( vol_ratio, i ) ); + rVol.emplace_back( vol_ratio, i ); } } diff --git a/src/npctalk.cpp b/src/npctalk.cpp index 9c1807edd5e80..7a7b671266463 100644 --- a/src/npctalk.cpp +++ b/src/npctalk.cpp @@ -1343,7 +1343,7 @@ void parse_tags( std::string &phrase, const Character &u, const Character &me, void dialogue::add_topic( const std::string &topic_id ) { - topic_stack.push_back( talk_topic( topic_id ) ); + topic_stack.emplace_back( topic_id ); } void dialogue::add_topic( const talk_topic &topic ) @@ -1767,7 +1767,7 @@ void talk_effect_fun_t::set_u_buy_item( const itype_id &item_name, int cost, int // Update structure used by mission descriptions. if( cost <= 0 ) { - likely_rewards.push_back( std::pair( count, item_name ) ); + likely_rewards.emplace_back( count, item_name ); } } diff --git a/src/output.cpp b/src/output.cpp index e8c22e2f1ee70..4d9f402a0d509 100644 --- a/src/output.cpp +++ b/src/output.cpp @@ -2116,7 +2116,7 @@ void scrollingcombattext::add( const point &pos, direction p_oDir, iter->advanceStepOffset(); } } - vSCT.push_back( cSCT( pos, p_oDir, p_sText, p_gmt, p_sText2, p_gmt2, p_sType ) ); + vSCT.emplace_back( pos, p_oDir, p_sText, p_gmt, p_sText2, p_gmt2, p_sType ); } } @@ -2354,7 +2354,7 @@ std::vector string_split( const std::string &text_in, char delim_in } if( text_in.back() == delim_in ) { - elems.push_back( "" ); + elems.emplace_back( "" ); } return elems; diff --git a/src/overmap.cpp b/src/overmap.cpp index 15e2d46006c5e..8121614556da7 100644 --- a/src/overmap.cpp +++ b/src/overmap.cpp @@ -1545,35 +1545,35 @@ bool overmap::generate_sub( const int z ) sewer_points.emplace_back( i, j ); } else if( oter_above == "anthill" || oter_above == "acid_anthill" ) { const int size = rng( MIN_ANT_SIZE, MAX_ANT_SIZE ); - ant_points.push_back( city( p.xy(), size ) ); + ant_points.emplace_back( p.xy(), size ); } else if( oter_above == "slimepit_down" ) { const int size = rng( MIN_GOO_SIZE, MAX_GOO_SIZE ); - goo_points.push_back( city( p.xy(), size ) ); + goo_points.emplace_back( p.xy(), size ); } else if( oter_above == "forest_water" ) { ter_set( p, oter_id( "cavern" ) ); chip_rock( p ); } else if( oter_above == "lab_core" || ( z == -1 && oter_above == "lab_stairs" ) ) { - lab_points.push_back( city( p.xy(), rng( 1, 5 + z ) ) ); + lab_points.emplace_back( p.xy(), rng( 1, 5 + z ) ); } else if( oter_above == "lab_stairs" ) { ter_set( p, oter_id( "lab" ) ); } else if( oter_above == "ice_lab_core" || ( z == -1 && oter_above == "ice_lab_stairs" ) ) { - ice_lab_points.push_back( city( p.xy(), rng( 1, 5 + z ) ) ); + ice_lab_points.emplace_back( p.xy(), rng( 1, 5 + z ) ); } else if( oter_above == "ice_lab_stairs" ) { ter_set( p, oter_id( "ice_lab" ) ); } else if( oter_above == "central_lab_core" ) { - central_lab_points.push_back( city( p.xy(), rng( std::max( 1, 7 + z ), 9 + z ) ) ); + central_lab_points.emplace_back( p.xy(), rng( std::max( 1, 7 + z ), 9 + z ) ); } else if( oter_above == "central_lab_stairs" ) { ter_set( p, oter_id( "central_lab" ) ); } else if( is_ot_match( "hidden_lab_stairs", oter_above, ot_match_type::contains ) ) { - lab_points.push_back( city( p.xy(), rng( 1, 5 + z ) ) ); + lab_points.emplace_back( p.xy(), rng( 1, 5 + z ) ); } else if( is_ot_match( "mine_entrance", oter_ground, ot_match_type::prefix ) && z == -2 ) { - mine_points.push_back( city( ( p + tripoint_west ).xy(), rng( 6 + z, 10 + z ) ) ); + mine_points.emplace_back( ( p + tripoint_west ).xy(), rng( 6 + z, 10 + z ) ); requires_sub = true; } else if( oter_above == "mine_down" ) { ter_set( p, oter_id( "mine" ) ); - mine_points.push_back( city( p.xy(), rng( 6 + z, 10 + z ) ) ); + mine_points.emplace_back( p.xy(), rng( 6 + z, 10 + z ) ); // technically not all finales need a sub level, // but at this point we don't know requires_sub = true; @@ -2604,10 +2604,10 @@ void overmap::place_rivers( const overmap *north, const overmap *east, const ove while( river_start.empty() || river_start.size() + 1 < river_end.size() ) { new_rivers.clear(); if( north == nullptr && one_in( river_chance ) ) { - new_rivers.push_back( point_om_omt( rng( 10, OMAPX - 11 ), 0 ) ); + new_rivers.emplace_back( rng( 10, OMAPX - 11 ), 0 ); } if( west == nullptr && one_in( river_chance ) ) { - new_rivers.push_back( point_om_omt( 0, rng( 10, OMAPY - 11 ) ) ); + new_rivers.emplace_back( 0, rng( 10, OMAPY - 11 ) ); } river_start.push_back( random_entry( new_rivers ) ); } @@ -2616,10 +2616,10 @@ void overmap::place_rivers( const overmap *north, const overmap *east, const ove while( river_end.empty() || river_end.size() + 1 < river_start.size() ) { new_rivers.clear(); if( south == nullptr && one_in( river_chance ) ) { - new_rivers.push_back( point_om_omt( rng( 10, OMAPX - 11 ), OMAPY - 1 ) ); + new_rivers.emplace_back( rng( 10, OMAPX - 11 ), OMAPY - 1 ); } if( east == nullptr && one_in( river_chance ) ) { - new_rivers.push_back( point_om_omt( OMAPX - 1, rng( 10, OMAPY - 11 ) ) ); + new_rivers.emplace_back( OMAPX - 1, rng( 10, OMAPY - 11 ) ); } river_end.push_back( random_entry( new_rivers ) ); } @@ -2650,8 +2650,8 @@ void overmap::place_rivers( const overmap *north, const overmap *east, const ove } } else if( !river_end.empty() ) { if( river_start.size() != river_end.size() ) { - river_start.push_back( point_om_omt( rng( OMAPX / 4, ( OMAPX * 3 ) / 4 ), - rng( OMAPY / 4, ( OMAPY * 3 ) / 4 ) ) ); + river_start.emplace_back( rng( OMAPX / 4, ( OMAPX * 3 ) / 4 ), + rng( OMAPY / 4, ( OMAPY * 3 ) / 4 ) ); } for( size_t i = 0; i < river_start.size(); i++ ) { place_river( river_start[i], river_end[i] ); @@ -4421,21 +4421,21 @@ void overmap::place_radios() // Since location have id such as "radio_tower_1_north", we must check the beginning of the id if( is_ot_match( "radio_tower", ter( pos_omt ), ot_match_type::prefix ) ) { if( one_in( 3 ) ) { - radios.push_back( radio_tower( pos_sm, strength(), "", radio_type::WEATHER_RADIO ) ); + radios.emplace_back( pos_sm, strength(), "", radio_type::WEATHER_RADIO ); } else { message = SNIPPET.expand( SNIPPET.random_from_category( "radio_archive" ).value_or( translation() ).translated() ); - radios.push_back( radio_tower( pos_sm, strength(), message ) ); + radios.emplace_back( pos_sm, strength(), message ); } } else if( is_ot_match( "lmoe", ter( pos_omt ), ot_match_type::prefix ) ) { message = string_format( _( "This is automated emergency shelter beacon %d%d." " Supplies, amenities and shelter are stocked." ), i, j ); - radios.push_back( radio_tower( pos_sm, strength() / 2, message ) ); + radios.emplace_back( pos_sm, strength() / 2, message ); } else if( is_ot_match( "fema_entrance", ter( pos_omt ), ot_match_type::prefix ) ) { message = string_format( _( "This is FEMA camp %d%d." " Supplies are limited, please bring supplemental food, water, and bedding." " This is FEMA camp %d%d. A designated long-term emergency shelter." ), i, j, i, j ); - radios.push_back( radio_tower( pos_sm, strength(), message ) ); + radios.emplace_back( pos_sm, strength(), message ); } } } diff --git a/src/overmap_ui.cpp b/src/overmap_ui.cpp index 7f294b6c5102d..7af7a90245283 100644 --- a/src/overmap_ui.cpp +++ b/src/overmap_ui.cpp @@ -654,7 +654,7 @@ void draw( npc *npc_to_add = elem.get(); if( npc_to_add->mission == NPC_MISSION_TRAVELLING && !npc_to_add->omt_path.empty() ) { for( auto &elem : npc_to_add->omt_path ) { - path_route.push_back( tripoint_abs_omt( elem.xy(), npc_to_add->posz() ) ); + path_route.emplace_back( elem.xy(), npc_to_add->posz() ); } } } diff --git a/src/panels.cpp b/src/panels.cpp index 9132293f7551d..4425efc018454 100644 --- a/src/panels.cpp +++ b/src/panels.cpp @@ -1112,20 +1112,20 @@ static void draw_stealth( avatar &u, const catacurses::window &w ) static void draw_time_graphic( const catacurses::window &w ) { std::vector > vGlyphs; - vGlyphs.push_back( std::make_pair( '_', c_red ) ); - vGlyphs.push_back( std::make_pair( '_', c_cyan ) ); - vGlyphs.push_back( std::make_pair( '.', c_brown ) ); - vGlyphs.push_back( std::make_pair( ',', c_blue ) ); - vGlyphs.push_back( std::make_pair( '+', c_yellow ) ); - vGlyphs.push_back( std::make_pair( 'c', c_light_blue ) ); - vGlyphs.push_back( std::make_pair( '*', c_yellow ) ); - vGlyphs.push_back( std::make_pair( 'C', c_white ) ); - vGlyphs.push_back( std::make_pair( '+', c_yellow ) ); - vGlyphs.push_back( std::make_pair( 'c', c_light_blue ) ); - vGlyphs.push_back( std::make_pair( '.', c_brown ) ); - vGlyphs.push_back( std::make_pair( ',', c_blue ) ); - vGlyphs.push_back( std::make_pair( '_', c_red ) ); - vGlyphs.push_back( std::make_pair( '_', c_cyan ) ); + vGlyphs.emplace_back( '_', c_red ); + vGlyphs.emplace_back( '_', c_cyan ); + vGlyphs.emplace_back( '.', c_brown ); + vGlyphs.emplace_back( ',', c_blue ); + vGlyphs.emplace_back( '+', c_yellow ); + vGlyphs.emplace_back( 'c', c_light_blue ); + vGlyphs.emplace_back( '*', c_yellow ); + vGlyphs.emplace_back( 'C', c_white ); + vGlyphs.emplace_back( '+', c_yellow ); + vGlyphs.emplace_back( 'c', c_light_blue ); + vGlyphs.emplace_back( '.', c_brown ); + vGlyphs.emplace_back( ',', c_blue ); + vGlyphs.emplace_back( '_', c_red ); + vGlyphs.emplace_back( '_', c_cyan ); const int iHour = hour_of_day( calendar::turn ); wprintz( w, c_white, "[" ); diff --git a/src/past_games_info.cpp b/src/past_games_info.cpp index d34c2bd08a09a..fa35621131500 100644 --- a/src/past_games_info.cpp +++ b/src/past_games_info.cpp @@ -116,7 +116,7 @@ void past_games_info::ensure_loaded() std::istringstream iss( read_entire_file( filename ) ); try { JsonIn jsin( iss ); - info_.push_back( past_game_info( jsin ) ); + info_.emplace_back( jsin ); } catch( const JsonError &err ) { debugmsg( "Error reading memorial file %s: %s", filename, err.what() ); } catch( const too_old_memorial_file_error & ) { diff --git a/src/pixel_minimap.cpp b/src/pixel_minimap.cpp index 1bd963238bff2..e9acb49a43de2 100644 --- a/src/pixel_minimap.cpp +++ b/src/pixel_minimap.cpp @@ -334,7 +334,7 @@ void pixel_minimap::update_cache_at( const tripoint &sm_pos ) if( current_color != color ) { current_color = color; - cache_item.update_list.push_back( { x, y } ); + cache_item.update_list.emplace_back( x, y ); } } } diff --git a/src/player.cpp b/src/player.cpp index a78429aad4264..5704cb9e133fa 100644 --- a/src/player.cpp +++ b/src/player.cpp @@ -2238,8 +2238,8 @@ void player::gunmod_add( item &gun, item &mod ) const int moves = !has_trait( trait_DEBUG_HS ) ? mod.type->gunmod->install_time : 0; assign_activity( activity_id( "ACT_GUNMOD_ADD" ), moves, -1, 0, tool ); - activity.targets.push_back( item_location( *this, &gun ) ); - activity.targets.push_back( item_location( *this, &mod ) ); + activity.targets.emplace_back( *this, &gun ); + activity.targets.emplace_back( *this, &mod ); activity.values.push_back( 0 ); // dummy value activity.values.push_back( roll ); // chance of success (%) activity.values.push_back( risk ); // chance of damage (%) diff --git a/src/player_activity.cpp b/src/player_activity.cpp index f0417d4e5250f..e7e4a877c8b76 100644 --- a/src/player_activity.cpp +++ b/src/player_activity.cpp @@ -64,11 +64,11 @@ void player_activity::migrate_item_position( Character &guy ) type == ACT_ATM; if( simple_action_replace ) { - targets.push_back( item_location( guy, &guy.i_at( position ) ) ); + targets.emplace_back( guy, &guy.i_at( position ) ); } else if( type == ACT_GUNMOD_ADD ) { // this activity has two indices; "position" = gun and "values[0]" = mod - targets.push_back( item_location( guy, &guy.i_at( position ) ) ); - targets.push_back( item_location( guy, &guy.i_at( values[0] ) ) ); + targets.emplace_back( guy, &guy.i_at( position ) ); + targets.emplace_back( guy, &guy.i_at( values[0] ) ); } } diff --git a/src/player_display.cpp b/src/player_display.cpp index 835f085759dd7..cc403e8e0c21b 100644 --- a/src/player_display.cpp +++ b/src/player_display.cpp @@ -1192,7 +1192,7 @@ void player::disp_info() if( tmp.empty() ) { continue; } - effect_name_and_text.push_back( { tmp, _effect_it.second.disp_desc() } ); + effect_name_and_text.emplace_back( tmp, _effect_it.second.disp_desc() ); } } if( get_perceived_pain() > 0 ) { @@ -1208,7 +1208,7 @@ void player::disp_info() add_if( ppen.intelligence, _( "Intelligence -%d" ) ); add_if( ppen.perception, _( "Perception -%d" ) ); add_if( ppen.speed, _( "Speed -%d %%" ) ); - effect_name_and_text.push_back( { _( "Pain" ), pain_text } ); + effect_name_and_text.emplace_back( _( "Pain" ), pain_text ); } const float bmi = get_bmi(); @@ -1237,30 +1237,30 @@ void player::disp_info() str_penalty * 50.0f ); } - effect_name_and_text.push_back( { starvation_name, starvation_text } ); + effect_name_and_text.emplace_back( starvation_name, starvation_text ); } if( has_trait( trait_id( "TROGLO" ) ) && g->is_in_sunlight( pos() ) && get_weather().weather_id->sun_intensity >= sun_intensity_type::high ) { - effect_name_and_text.push_back( { _( "In Sunlight" ), - _( "The sunlight irritates you.\n" - "Strength - 1; Dexterity - 1; Intelligence - 1; Perception - 1" ) - } ); + effect_name_and_text.emplace_back( _( "In Sunlight" ), + _( "The sunlight irritates you.\n" + "Strength - 1; Dexterity - 1; Intelligence - 1; Perception - 1" ) + ); } else if( has_trait( trait_id( "TROGLO2" ) ) && g->is_in_sunlight( pos() ) ) { - effect_name_and_text.push_back( { _( "In Sunlight" ), - _( "The sunlight irritates you badly.\n" - "Strength - 2; Dexterity - 2; Intelligence - 2; Perception - 2" ) - } ); + effect_name_and_text.emplace_back( _( "In Sunlight" ), + _( "The sunlight irritates you badly.\n" + "Strength - 2; Dexterity - 2; Intelligence - 2; Perception - 2" ) + ); } else if( has_trait( trait_id( "TROGLO3" ) ) && g->is_in_sunlight( pos() ) ) { - effect_name_and_text.push_back( { _( "In Sunlight" ), - _( "The sunlight irritates you terribly.\n" - "Strength - 4; Dexterity - 4; Intelligence - 4; Perception - 4" ) - } ); + effect_name_and_text.emplace_back( _( "In Sunlight" ), + _( "The sunlight irritates you terribly.\n" + "Strength - 4; Dexterity - 4; Intelligence - 4; Perception - 4" ) + ); } for( auto &elem : addictions ) { if( elem.sated < 0_turns && elem.intensity >= MIN_ADDICTION_LEVEL ) { - effect_name_and_text.push_back( { addiction_name( elem ), addiction_text( elem ) } ); + effect_name_and_text.emplace_back( addiction_name( elem ), addiction_text( elem ) ); } } diff --git a/src/profession.cpp b/src/profession.cpp index 7349369fa0551..92f84f13f2139 100644 --- a/src/profession.cpp +++ b/src/profession.cpp @@ -608,7 +608,7 @@ void json_item_substitution::load( const JsonObject &jo ) if( check_duplicate_item( old_it ) ) { sub.throw_error( "Duplicate definition of item" ); } - s.trait_reqs.present.push_back( trait_id( jo.get_string( "trait" ) ) ); + s.trait_reqs.present.emplace_back( jo.get_string( "trait" ) ); for( const JsonValue info : sub.get_array( "new" ) ) { s.infos.emplace_back( info ); } diff --git a/src/proficiency.cpp b/src/proficiency.cpp index 593d244ad9588..9da433d251633 100644 --- a/src/proficiency.cpp +++ b/src/proficiency.cpp @@ -120,11 +120,11 @@ std::vector proficiency_set::display() const std::vector> sorted_learning; for( const proficiency_id &cur : known ) { - sorted_known.push_back( { cur->name(), cur } ); + sorted_known.emplace_back( cur->name(), cur ); } for( const learning_proficiency &cur : learning ) { - sorted_learning.push_back( { cur.id->name(), cur.id } ); + sorted_learning.emplace_back( cur.id->name(), cur.id ); } std::sort( sorted_known.begin(), sorted_known.end(), localized_compare ); @@ -170,7 +170,7 @@ bool proficiency_set::practice( const proficiency_id &practicing, const time_dur return false; } if( !has_practiced( practicing ) ) { - learning.push_back( learning_proficiency( practicing, 0_seconds ) ); + learning.emplace_back( practicing, 0_seconds ); } learning_proficiency ¤t = fetch_learning( practicing ); diff --git a/src/ranged.cpp b/src/ranged.cpp index a3d9eaae8a7ba..7966a97f9e30f 100644 --- a/src/ranged.cpp +++ b/src/ranged.cpp @@ -2670,7 +2670,7 @@ std::vector> target_ui::list_friendlies_in_lof() ( cr->is_npc() && a != Creature::Attitude::HOSTILE ) || ( !cr->is_npc() && a == Creature::Attitude::FRIENDLY ) ) { - ret.push_back( g->shared_from( *cr ) ); + ret.emplace_back( g->shared_from( *cr ) ); } } } diff --git a/src/recipe.cpp b/src/recipe.cpp index 43ca504e20504..2679182ce9ae9 100644 --- a/src/recipe.cpp +++ b/src/recipe.cpp @@ -814,7 +814,7 @@ std::string recipe::primary_skill_string( const Character *c, bool print_skill_l std::vector< std::pair > skillList; if( !skill_used.is_null() ) { - skillList.push_back( std::pair( skill_used, difficulty ) ); + skillList.emplace_back( skill_used, difficulty ); } return required_skills_as_string( skillList.begin(), skillList.end(), c, print_skill_level ); diff --git a/src/safemode_ui.cpp b/src/safemode_ui.cpp index 24b9b5620b22d..1b51dc0b2f6fc 100644 --- a/src/safemode_ui.cpp +++ b/src/safemode_ui.cpp @@ -303,16 +303,16 @@ void safemode::show( const std::string &custom_name_in, bool is_safemode_in ) } } else if( action == "ADD_DEFAULT_RULESET" ) { changes_made = true; - current_tab.push_back( rules_class( "*", true, false, Creature::Attitude::HOSTILE, - get_option( "SAFEMODEPROXIMITY" ) - , Categories::HOSTILE_SPOTTED ) ); - current_tab.push_back( rules_class( "*", true, true, Creature::Attitude::HOSTILE, 5, - Categories::SOUND ) ); + current_tab.emplace_back( "*", true, false, Creature::Attitude::HOSTILE, + get_option( "SAFEMODEPROXIMITY" ) + , Categories::HOSTILE_SPOTTED ); + current_tab.emplace_back( "*", true, true, Creature::Attitude::HOSTILE, 5, + Categories::SOUND ); line = current_tab.size() - 1; } else if( action == "ADD_RULE" ) { changes_made = true; - current_tab.push_back( rules_class( "", true, false, Creature::Attitude::HOSTILE, - get_option( "SAFEMODEPROXIMITY" ), Categories::HOSTILE_SPOTTED ) ); + current_tab.emplace_back( "", true, false, Creature::Attitude::HOSTILE, + get_option( "SAFEMODEPROXIMITY" ), Categories::HOSTILE_SPOTTED ); line = current_tab.size() - 1; } else if( action == "REMOVE_RULE" && !current_tab.empty() ) { changes_made = true; @@ -640,8 +640,8 @@ void safemode::add_rule( const std::string &rule_in, const Creature::Attitude at const int proximity_in, const rule_state state_in ) { - character_rules.push_back( rules_class( rule_in, true, ( state_in == rule_state::WHITELISTED ), - attitude_in, proximity_in, Categories::HOSTILE_SPOTTED ) ); + character_rules.emplace_back( rule_in, true, ( state_in == rule_state::WHITELISTED ), + attitude_in, proximity_in, Categories::HOSTILE_SPOTTED ); create_rules(); if( !get_option( "SAFEMODE" ) && @@ -891,8 +891,7 @@ void safemode::deserialize( JsonIn &jsin ) const Categories cat = jo.has_member( "category" ) ? static_cast ( jo.get_int( "category" ) ) : Categories::HOSTILE_SPOTTED; - temp_rules.push_back( - rules_class( rule, active, whitelist, attitude, proximity, cat ) - ); + temp_rules.emplace_back( rule, active, whitelist, attitude, proximity, cat + ); } } diff --git a/src/talker_avatar.cpp b/src/talker_avatar.cpp index e43ca0e9c7e3c..75d303e70627f 100644 --- a/src/talker_avatar.cpp +++ b/src/talker_avatar.cpp @@ -31,7 +31,7 @@ std::vector talker_avatar::get_topics( bool ) std::vector add_topics; if( has_trait( trait_PROF_FOODP ) && !( is_wearing( itype_id( "foodperson_mask" ) ) || is_wearing( itype_id( "foodperson_mask_on" ) ) ) ) { - add_topics.push_back( "TALK_NOFACE" ); + add_topics.emplace_back( "TALK_NOFACE" ); } return add_topics; } diff --git a/src/talker_npc.cpp b/src/talker_npc.cpp index 0e065a909b4c2..ac51ee3df2fcd 100644 --- a/src/talker_npc.cpp +++ b/src/talker_npc.cpp @@ -108,19 +108,19 @@ std::vector talker_npc::get_topics( bool radio_contact ) add_topics.push_back( me_npc->chatbin.first_topic ); if( radio_contact ) { - add_topics.push_back( "TALK_RADIO" ); + add_topics.emplace_back( "TALK_RADIO" ); } else if( me_npc->is_leader() ) { - add_topics.push_back( "TALK_LEADER" ); + add_topics.emplace_back( "TALK_LEADER" ); } else if( me_npc->is_player_ally() && ( me_npc->is_walking_with() || me_npc->has_activity() ) ) { - add_topics.push_back( "TALK_FRIEND" ); + add_topics.emplace_back( "TALK_FRIEND" ); } else if( me_npc->get_attitude() == NPCATT_RECOVER_GOODS ) { - add_topics.push_back( "TALK_STOLE_ITEM" ); + add_topics.emplace_back( "TALK_STOLE_ITEM" ); } int most_difficult_mission = 0; for( auto &mission : me_npc->chatbin.missions ) { const auto &type = mission->get_type(); if( type.urgent && type.difficulty > most_difficult_mission ) { - add_topics.push_back( "TALK_MISSION_DESCRIBE_URGENT" ); + add_topics.emplace_back( "TALK_MISSION_DESCRIBE_URGENT" ); me_npc->chatbin.mission_selected = mission; most_difficult_mission = type.difficulty; } @@ -136,7 +136,7 @@ std::vector talker_npc::get_topics( bool radio_contact ) if( ( type.urgent && !chosen_urgent ) || ( type.difficulty > most_difficult_mission && ( type.urgent || !chosen_urgent ) ) ) { chosen_urgent = type.urgent; - add_topics.push_back( "TALK_MISSION_INQUIRE" ); + add_topics.emplace_back( "TALK_MISSION_INQUIRE" ); me_npc->chatbin.mission_selected = mission; most_difficult_mission = type.difficulty; } @@ -144,13 +144,13 @@ std::vector talker_npc::get_topics( bool radio_contact ) // Needs if( me_npc->has_effect( effect_npc_suspend ) ) { - add_topics.push_back( "TALK_REBOOT" ); + add_topics.emplace_back( "TALK_REBOOT" ); } if( me_npc->has_effect( effect_sleep ) || me_npc->has_effect( effect_lying_down ) ) { if( me_npc->has_effect( effect_narcosis ) ) { - add_topics.push_back( "TALK_SEDATED" ); + add_topics.emplace_back( "TALK_SEDATED" ); } else { - add_topics.push_back( "TALK_WAKE_UP" ); + add_topics.emplace_back( "TALK_WAKE_UP" ); } } @@ -163,25 +163,25 @@ std::vector talker_npc::get_topics( bool radio_contact ) if( add_topics.back() == "TALK_MUG" || add_topics.back() == "TALK_STRANGER_AGGRESSIVE" ) { me_npc->make_angry(); - add_topics.push_back( "TALK_DEAF_ANGRY" ); + add_topics.emplace_back( "TALK_DEAF_ANGRY" ); } else { - add_topics.push_back( "TALK_DEAF" ); + add_topics.emplace_back( "TALK_DEAF" ); } } if( player_character.is_mute() ) { if( add_topics.back() == "TALK_MUG" || add_topics.back() == "TALK_STRANGER_AGGRESSIVE" ) { me_npc->make_angry(); - add_topics.push_back( "TALK_MUTE_ANGRY" ); + add_topics.emplace_back( "TALK_MUTE_ANGRY" ); } else { - add_topics.push_back( "TALK_MUTE" ); + add_topics.emplace_back( "TALK_MUTE" ); } } if( me_npc->has_trait( trait_PROF_FOODP ) && !( me_npc->is_wearing( itype_id( "foodperson_mask_on" ) ) || me_npc->is_wearing( itype_id( "foodperson_mask" ) ) ) ) { - add_topics.push_back( "TALK_NPC_NOFACE" ); + add_topics.emplace_back( "TALK_NPC_NOFACE" ); } me_npc->decide_needs(); diff --git a/src/translations.cpp b/src/translations.cpp index fa0ee479b2c93..645e1fc59ae43 100644 --- a/src/translations.cpp +++ b/src/translations.cpp @@ -434,7 +434,7 @@ std::string gettext_gendered( const GenderMap &genders, const std::string &msg ) sanity_check_genders( language_genders ); if( language_genders.empty() ) { - language_genders.push_back( "n" ); + language_genders.emplace_back( "n" ); } std::vector chosen_genders; diff --git a/src/veh_interact.cpp b/src/veh_interact.cpp index 97fd98fa40858..8c207deaf0172 100644 --- a/src/veh_interact.cpp +++ b/src/veh_interact.cpp @@ -912,15 +912,15 @@ void veh_interact::do_install() for( const vpart_category &cat : vpart_category::all() ) { tab_list.push_back( cat ); if( cat.get_id() == "_all" ) { - tab_filters.push_back( []( const vpart_info * ) { + tab_filters.emplace_back( []( const vpart_info * ) { return true; } ); } else if( cat.get_id() == "_filter" ) { - tab_filters.push_back( [&filter]( const vpart_info * p ) { + tab_filters.emplace_back( [&filter]( const vpart_info * p ) { return lcmatch( p->name(), filter ); } ); } else { - tab_filters.push_back( [ &, cat = cat.get_id()]( const vpart_info * p ) { + tab_filters.emplace_back( [ &, cat = cat.get_id()]( const vpart_info * p ) { return p->has_category( cat ); } ); } diff --git a/src/veh_type.cpp b/src/veh_type.cpp index 8b4bbb98565ae..4f6fef9421c9b 100644 --- a/src/veh_type.cpp +++ b/src/veh_type.cpp @@ -267,7 +267,7 @@ void vpart_info::load_engine( cata::optional &eptr, const JsonObj if( !fuel_opts.empty() ) { e_info.fuel_opts.clear(); for( const std::string line : fuel_opts ) { - e_info.fuel_opts.push_back( itype_id( line ) ); + e_info.fuel_opts.emplace_back( line ); } } else if( e_info.fuel_opts.empty() && fuel_type != itype_id( "null" ) ) { e_info.fuel_opts.push_back( fuel_type ); @@ -1168,17 +1168,16 @@ void vehicle_prototype::load( const JsonObject &jo ) const std::string variant = spawn_info.get_string( "variant" ); next_spawn.variant_ids.emplace_back( itype_id( spawn_info.get_string( "items" ) ), variant ); } else { - next_spawn.item_ids.push_back( itype_id( spawn_info.get_string( "items" ) ) ); + next_spawn.item_ids.emplace_back( spawn_info.get_string( "items" ) ); } } if( spawn_info.has_array( "item_groups" ) ) { //Pick from a group of items, just like map::place_items for( const std::string line : spawn_info.get_array( "item_groups" ) ) { - next_spawn.item_groups.push_back( item_group_id( line ) ); + next_spawn.item_groups.emplace_back( line ); } } else if( spawn_info.has_string( "item_groups" ) ) { - next_spawn.item_groups.push_back( - item_group_id( spawn_info.get_string( "item_groups" ) ) ); + next_spawn.item_groups.emplace_back( spawn_info.get_string( "item_groups" ) ); } vproto.item_spawns.push_back( std::move( next_spawn ) ); } diff --git a/src/vehicle_use.cpp b/src/vehicle_use.cpp index ad7a282830213..9dbe7ce27cfeb 100644 --- a/src/vehicle_use.cpp +++ b/src/vehicle_use.cpp @@ -136,7 +136,7 @@ void vehicle::add_toggle_to_opts( std::vector &options, name ); options.emplace_back( -1, allow, key, msg ); - actions.push_back( [ = ] { + actions.emplace_back( [ = ] { for( const vpart_reference &vp : found ) { vehicle_part &e = vp.part(); @@ -324,14 +324,14 @@ void vehicle::set_electronics_menu_options( std::vector &options, if( has_part( "DOOR_MOTOR" ) ) { options.emplace_back( _( "Toggle doors" ), keybind( "TOGGLE_DOORS" ) ); - actions.push_back( [&] { control_doors(); refresh(); } ); + actions.emplace_back( [&] { control_doors(); refresh(); } ); } if( camera_on || ( has_part( "CAMERA" ) && has_part( "CAMERA_CONTROL" ) ) ) { options.emplace_back( camera_on ? colorize( _( "Turn off camera system" ), c_pink ) : _( "Turn on camera system" ), keybind( "TOGGLE_CAMERA" ) ); - actions.push_back( [&] { + actions.emplace_back( [&] { if( camera_on ) { camera_on = false; @@ -626,7 +626,7 @@ void vehicle::use_controls( const tripoint &pos ) if( remote ) { options.emplace_back( _( "Stop controlling" ), keybind( "RELEASE_CONTROLS" ) ); - actions.push_back( [&] { + actions.emplace_back( [&] { player_character.controlling_vehicle = false; g->setremoteveh( nullptr ); add_msg( _( "You stop controlling the vehicle." ) ); @@ -638,7 +638,7 @@ void vehicle::use_controls( const tripoint &pos ) } else if( veh_pointer_or_null( get_map().veh_at( pos ) ) == this ) { if( player_character.controlling_vehicle ) { options.emplace_back( _( "Let go of controls" ), keybind( "RELEASE_CONTROLS" ) ); - actions.push_back( [&] { + actions.emplace_back( [&] { player_character.controlling_vehicle = false; add_msg( _( "You let go of the controls." ) ); refresh(); @@ -661,7 +661,7 @@ void vehicle::use_controls( const tripoint &pos ) if( has_part( "ENGINE" ) ) { if( player_character.controlling_vehicle || ( remote && engine_on ) ) { options.emplace_back( _( "Stop driving" ), keybind( "TOGGLE_ENGINE" ) ); - actions.push_back( [&] { + actions.emplace_back( [&] { if( engine_on && has_engine_type_not( fuel_type_muscle, true ) ) { add_msg( _( "You turn the engine off and let go of the controls." ) ); @@ -704,7 +704,7 @@ void vehicle::use_controls( const tripoint &pos ) } else if( has_engine_type_not( fuel_type_muscle, true ) ) { options.emplace_back( engine_on ? _( "Turn off the engine" ) : _( "Turn on the engine" ), keybind( "TOGGLE_ENGINE" ) ); - actions.push_back( [&] { + actions.emplace_back( [&] { if( engine_on ) { engine_on = false; @@ -722,13 +722,13 @@ void vehicle::use_controls( const tripoint &pos ) if( has_part( "HORN" ) ) { options.emplace_back( _( "Honk horn" ), keybind( "SOUND_HORN" ) ); - actions.push_back( [&] { honk_horn(); refresh(); } ); + actions.emplace_back( [&] { honk_horn(); refresh(); } ); } if( has_part( "AUTOPILOT" ) && ( has_part( "CTRL_ELECTRONIC" ) || has_part( "REMOTE_CONTROLS" ) ) ) { options.emplace_back( _( "Control autopilot" ), keybind( "CONTROL_AUTOPILOT" ) ); - actions.push_back( [&] { toggle_autopilot(); refresh(); } ); + actions.emplace_back( [&] { toggle_autopilot(); refresh(); } ); } options.emplace_back( cruise_on ? _( "Disable cruise control" ) : _( "Enable cruise control" ), @@ -742,28 +742,28 @@ void vehicle::use_controls( const tripoint &pos ) if( has_electronic_controls ) { set_electronics_menu_options( options, actions ); options.emplace_back( _( "Control multiple electronics" ), keybind( "CONTROL_MANY_ELECTRONICS" ) ); - actions.push_back( [&] { control_electronics(); refresh(); } ); + actions.emplace_back( [&] { control_electronics(); refresh(); } ); } options.emplace_back( tracking_on ? _( "Forget vehicle position" ) : _( "Remember vehicle position" ), keybind( "TOGGLE_TRACKING" ) ); - actions.push_back( [&] { toggle_tracking(); } ); + actions.emplace_back( [&] { toggle_tracking(); } ); if( ( is_foldable() || tags.count( "convertible" ) ) && !remote ) { options.emplace_back( string_format( _( "Fold %s" ), name ), keybind( "FOLD_VEHICLE" ) ); - actions.push_back( [&] { fold_up(); } ); + actions.emplace_back( [&] { fold_up(); } ); } if( has_part( "ENGINE" ) ) { options.emplace_back( _( "Control individual engines" ), keybind( "CONTROL_ENGINES" ) ); - actions.push_back( [&] { control_engines(); refresh(); } ); + actions.emplace_back( [&] { control_engines(); refresh(); } ); } if( has_part( "SMART_ENGINE_CONTROLLER" ) ) { options.emplace_back( _( "Smart controller settings" ), keybind( "TOGGLE_SMART_ENGINE_CONTROLLER" ) ); - actions.push_back( [&] { + actions.emplace_back( [&] { if( !smart_controller_cfg ) { smart_controller_cfg = smart_controller_config(); @@ -783,11 +783,11 @@ void vehicle::use_controls( const tripoint &pos ) if( is_alarm_on ) { if( velocity == 0 && !remote ) { options.emplace_back( _( "Try to disarm alarm" ), keybind( "TOGGLE_ALARM" ) ); - actions.push_back( [&] { smash_security_system(); refresh(); } ); + actions.emplace_back( [&] { smash_security_system(); refresh(); } ); } else if( has_electronic_controls && has_part( "SECURITY" ) ) { options.emplace_back( _( "Trigger alarm" ), keybind( "TOGGLE_ALARM" ) ); - actions.push_back( [&] { + actions.emplace_back( [&] { is_alarm_on = true; add_msg( _( "You trigger the alarm" ) ); refresh(); @@ -797,21 +797,21 @@ void vehicle::use_controls( const tripoint &pos ) if( has_part( "TURRET" ) ) { options.emplace_back( _( "Set turret targeting modes" ), keybind( "TURRET_TARGET_MODE" ) ); - actions.push_back( [&] { turrets_set_targeting(); refresh(); } ); + actions.emplace_back( [&] { turrets_set_targeting(); refresh(); } ); options.emplace_back( _( "Set turret firing modes" ), keybind( "TURRET_FIRE_MODE" ) ); - actions.push_back( [&] { turrets_set_mode(); refresh(); } ); + actions.emplace_back( [&] { turrets_set_mode(); refresh(); } ); // We can also fire manual turrets with ACTION_FIRE while standing at the controls. options.emplace_back( _( "Aim turrets manually" ), keybind( "TURRET_MANUAL_AIM" ) ); - actions.push_back( [&] { turrets_aim_and_fire_all_manual( true ); refresh(); } ); + actions.emplace_back( [&] { turrets_aim_and_fire_all_manual( true ); refresh(); } ); // This lets us manually override and set the target for the automatic turrets instead. options.emplace_back( _( "Aim automatic turrets" ), keybind( "TURRET_MANUAL_OVERRIDE" ) ); - actions.push_back( [&] { turrets_override_automatic_aim(); refresh(); } ); + actions.emplace_back( [&] { turrets_override_automatic_aim(); refresh(); } ); options.emplace_back( _( "Aim individual turret" ), keybind( "TURRET_SINGLE_FIRE" ) ); - actions.push_back( [&] { turrets_aim_and_fire_single(); refresh(); } ); + actions.emplace_back( [&] { turrets_aim_and_fire_single(); refresh(); } ); } uilist menu; @@ -1732,7 +1732,7 @@ void vehicle::use_washing_machine( int p ) } std::vector detergent; - detergent.push_back( item_comp( det_types[chosen_detergent], 5 ) ); + detergent.emplace_back( det_types[chosen_detergent], 5 ); player_character.consume_items( detergent, 1, is_crafting_component ); add_msg( m_good, @@ -1789,7 +1789,7 @@ void vehicle::use_dishwasher( int p ) } std::vector detergent; - detergent.push_back( item_comp( itype_detergent, 5 ) ); + detergent.emplace_back( itype_detergent, 5 ); player_character.consume_items( detergent, 1, is_crafting_component ); add_msg( m_good, diff --git a/src/wish.cpp b/src/wish.cpp index cc288a1922e9a..a6be648885d9d 100644 --- a/src/wish.cpp +++ b/src/wish.cpp @@ -845,7 +845,7 @@ void debug_menu::wishproficiency( player *p ) know_all = player_know; } - sorted_profs.push_back( { cur.prof_id(), player_know } ); + sorted_profs.emplace_back( cur.prof_id(), player_know ); } std::sort( sorted_profs.begin(), sorted_profs.end(), localized_compare ); diff --git a/src/worldfactory.cpp b/src/worldfactory.cpp index d71f563488fca..532b99a6b871e 100644 --- a/src/worldfactory.cpp +++ b/src/worldfactory.cpp @@ -117,9 +117,9 @@ worldfactory::worldfactory() , mman_ui( *mman ) { // prepare tab display order - tabs.push_back( std::bind( &worldfactory::show_worldgen_tab_modselection, this, _1, _2, _3 ) ); - tabs.push_back( std::bind( &worldfactory::show_worldgen_tab_options, this, _1, _2, _3 ) ); - tabs.push_back( std::bind( &worldfactory::show_worldgen_tab_confirm, this, _1, _2, _3 ) ); + tabs.emplace_back( std::bind( &worldfactory::show_worldgen_tab_modselection, this, _1, _2, _3 ) ); + tabs.emplace_back( std::bind( &worldfactory::show_worldgen_tab_options, this, _1, _2, _3 ) ); + tabs.emplace_back( std::bind( &worldfactory::show_worldgen_tab_confirm, this, _1, _2, _3 ) ); } worldfactory::~worldfactory() = default; @@ -968,8 +968,8 @@ int worldfactory::show_worldgen_tab_modselection( const catacurses::window &win, ui.on_screen_resize( init_windows ); std::vector headers; - headers.push_back( _( "Mod List" ) ); - headers.push_back( _( "Mod Load Order" ) ); + headers.emplace_back( _( "Mod List" ) ); + headers.emplace_back( _( "Mod Load Order" ) ); size_t active_header = 0; int startsel[2] = {0, 0}; diff --git a/tests/behavior_test.cpp b/tests/behavior_test.cpp index b458c5ceb8385..c54ada29b7539 100644 --- a/tests/behavior_test.cpp +++ b/tests/behavior_test.cpp @@ -160,7 +160,7 @@ TEST_CASE( "check_npc_behavior_tree", "[npc][behavior]" ) test_npc.update_bodytemp(); REQUIRE( oracle.needs_warmth_badly( "" ) == behavior::status_t::running ); CHECK( npc_needs.tick( &oracle ) == "idle" ); - test_npc.worn.push_back( item( "backpack" ) ); + test_npc.worn.emplace_back( "backpack" ); item &sweater = test_npc.i_add( item( itype_id( "sweater" ) ) ); CHECK( oracle.can_wear_warmer_clothes( "" ) == behavior::status_t::running ); CHECK( npc_needs.tick( &oracle ) == "wear_warmer_clothes" ); diff --git a/tests/crafting_test.cpp b/tests/crafting_test.cpp index 01eebfe24c53f..d61d4c1b1a8a0 100644 --- a/tests/crafting_test.cpp +++ b/tests/crafting_test.cpp @@ -165,7 +165,7 @@ TEST_CASE( "available_recipes", "[recipes]" ) } GIVEN( "an appropriate book" ) { - dummy.worn.push_back( item( "backpack" ) ); + dummy.worn.emplace_back( "backpack" ); item &craftbook = dummy.i_add( item( "manual_electronics" ) ); REQUIRE( craftbook.is_book() ); REQUIRE_FALSE( craftbook.type->book->recipes.empty() ); @@ -209,7 +209,7 @@ TEST_CASE( "available_recipes", "[recipes]" ) GIVEN( "an eink pc with a sushi recipe" ) { const recipe *r2 = &recipe_id( "sushi_rice" ).obj(); - dummy.worn.push_back( item( "backpack" ) ); + dummy.worn.emplace_back( "backpack" ); item &eink = dummy.i_add( item( "eink_tablet_pc" ) ); eink.set_var( "EIPC_RECIPES", ",sushi_rice," ); REQUIRE_FALSE( dummy.knows_recipe( r2 ) ); @@ -399,7 +399,7 @@ TEST_CASE( "UPS shows as a crafting component", "[crafting][ups]" ) { avatar dummy; clear_character( dummy ); - dummy.worn.push_back( item( "backpack" ) ); + dummy.worn.emplace_back( "backpack" ); item &ups = dummy.i_add( item( "UPS_off", calendar::turn_zero, 500 ) ); REQUIRE( dummy.has_item( ups ) ); REQUIRE( ups.charges == 500 ); diff --git a/tests/encumbrance_test.cpp b/tests/encumbrance_test.cpp index 97d4c74d7b74e..11de147f86488 100644 --- a/tests/encumbrance_test.cpp +++ b/tests/encumbrance_test.cpp @@ -63,7 +63,7 @@ static void test_encumbrance( std::vector clothing; clothing.reserve( clothing_types.size() ); for( const std::string &type : clothing_types ) { - clothing.push_back( item( type ) ); + clothing.emplace_back( type ); } test_encumbrance_items( clothing, body_part, expected_encumbrance ); } diff --git a/tests/generic_factory_test.cpp b/tests/generic_factory_test.cpp index 321d3f2285f74..bd48552245b48 100644 --- a/tests/generic_factory_test.cpp +++ b/tests/generic_factory_test.cpp @@ -347,7 +347,7 @@ TEST_CASE( "string_and_int_ids_benchmark", "[.][generic_factory][int_id][string_ std_uo_set_int_ids.emplace( int_id ); // do not add duplicates if( std_uo_set_int_ids.size() > vector_int_ids.size() ) { - vector_int_ids.push_back( flag ); + vector_int_ids.emplace_back( flag ); } } } item; @@ -382,7 +382,7 @@ TEST_CASE( "string_and_int_ids_benchmark", "[.][generic_factory][int_id][string_ std::vector test_dyn_str_ids; test_dyn_str_ids.reserve( test_flags.size() ); for( const auto &f : test_flags ) { - test_dyn_str_ids.push_back( dyn_str_id( f.str() ) ); + test_dyn_str_ids.emplace_back( f.str() ); } DYNAMIC_SECTION( "number_ids_in_collection: " << flags_in_item << "; only_hits: " << hits ) { diff --git a/tests/invlet_test.cpp b/tests/invlet_test.cpp index 0d3b8c7c0005b..bb8aaf0db7dde 100644 --- a/tests/invlet_test.cpp +++ b/tests/invlet_test.cpp @@ -464,7 +464,7 @@ static void invlet_test( player &dummy, const inventory_location from, const inv dummy.worn.clear(); dummy.remove_weapon(); get_map().i_clear( dummy.pos() ); - dummy.worn.push_back( item( "backpack" ) ); + dummy.worn.emplace_back( "backpack" ); // some two items that can be wielded, worn, and picked up item tshirt( "tshirt" ); @@ -546,7 +546,7 @@ static void stack_invlet_test( player &dummy, inventory_location from, inventory dummy.worn.clear(); dummy.remove_weapon(); get_map().i_clear( dummy.pos() ); - dummy.worn.push_back( item( "backpack" ) ); + dummy.worn.emplace_back( "backpack" ); // some stackable item that can be wielded and worn item tshirt1( "tshirt" ); @@ -682,7 +682,7 @@ static void merge_invlet_test( player &dummy, inventory_location from ) dummy.worn.clear(); dummy.remove_weapon(); get_map().i_clear( dummy.pos() ); - dummy.worn.push_back( item( "backpack" ) ); + dummy.worn.emplace_back( "backpack" ); // some stackable item item tshirt1( "tshirt" ); diff --git a/tests/iteminfo_test.cpp b/tests/iteminfo_test.cpp index 7c3a238772d75..422b8f86e8c17 100644 --- a/tests/iteminfo_test.cpp +++ b/tests/iteminfo_test.cpp @@ -2347,7 +2347,7 @@ TEST_CASE( "show available recipes with item as an ingredient", "[iteminfo][reci std::vector crafting = { iteminfo_parts::DESCRIPTION_APPLICABLE_RECIPES }; GIVEN( "character has a potassium iodide tablet and no skill" ) { - player_character.worn.push_back( item( "backpack" ) ); + player_character.worn.emplace_back( "backpack" ); item &iodine = player_character.i_add( item( "iodine" ) ); player_character.empty_skills(); REQUIRE( !player_character.knows_recipe( purtab ) ); diff --git a/tests/modify_morale_test.cpp b/tests/modify_morale_test.cpp index a60d643e03f00..cf5c4ea204837 100644 --- a/tests/modify_morale_test.cpp +++ b/tests/modify_morale_test.cpp @@ -46,7 +46,7 @@ static const trait_id trait_VEGETARIAN( "VEGETARIAN" ); TEST_CASE( "food enjoyability", "[food][modify_morale][fun]" ) { avatar dummy; - dummy.worn.push_back( item( "backpack" ) ); + dummy.worn.emplace_back( "backpack" ); std::pair fun; GIVEN( "food with positive fun" ) { @@ -80,7 +80,7 @@ TEST_CASE( "dining with table and chair", "[food][modify_morale][table][chair]" dummy.set_body(); const tripoint avatar_pos( 60, 60, 0 ); dummy.setpos( avatar_pos ); - dummy.worn.push_back( item( "backpack" ) ); + dummy.worn.emplace_back( "backpack" ); // Morale bonus only applies to unspoiled food that is not junk item &bread = dummy.i_add( item( "sourdough_bread" ) ); @@ -194,7 +194,7 @@ TEST_CASE( "dining with table and chair", "[food][modify_morale][table][chair]" TEST_CASE( "eating hot food", "[food][modify_morale][hot]" ) { avatar dummy; - dummy.worn.push_back( item( "backpack" ) ); + dummy.worn.emplace_back( "backpack" ); GIVEN( "some food that tastes better when hot" ) { item &bread = dummy.i_add( item( "sourdough_bread" ) ); @@ -268,7 +268,7 @@ TEST_CASE( "cannibalism", "[food][modify_morale][cannibal]" ) { avatar dummy; dummy.set_body(); - dummy.worn.push_back( item( "backpack" ) ); + dummy.worn.emplace_back( "backpack" ); item &human = dummy.i_add( item( "bone_human" ) ); REQUIRE( human.has_flag( flag_CANNIBALISM ) ); @@ -344,7 +344,7 @@ TEST_CASE( "sweet junk food", "[food][modify_morale][junk][sweet]" ) { avatar dummy; dummy.set_body(); - dummy.worn.push_back( item( "backpack" ) ); + dummy.worn.emplace_back( "backpack" ); GIVEN( "some sweet junk food" ) { item &necco = dummy.i_add( item( "neccowafers" ) ); @@ -398,7 +398,7 @@ TEST_CASE( "junk food that is not ingested", "[modify_morale][junk][no_ingest]" { avatar dummy; dummy.set_body(); - dummy.worn.push_back( item( "backpack" ) ); + dummy.worn.emplace_back( "backpack" ); item &caff_gum = dummy.i_add( item( "caff_gum" ) ); @@ -464,7 +464,7 @@ TEST_CASE( "food allergies and intolerances", "[food][modify_morale][allergy]" ) { avatar dummy; dummy.set_body(); - dummy.worn.push_back( item( "backpack" ) ); + dummy.worn.emplace_back( "backpack" ); int penalty = -75; GIVEN( "character is vegetarian" ) { @@ -551,7 +551,7 @@ TEST_CASE( "saprophage character", "[food][modify_morale][saprophage]" ) { avatar dummy; dummy.set_body(); - dummy.worn.push_back( item( "backpack" ) ); + dummy.worn.emplace_back( "backpack" ); GIVEN( "character is a saprophage, preferring rotted food" ) { dummy.clear_morale(); @@ -588,7 +588,7 @@ TEST_CASE( "ursine honey", "[food][modify_morale][ursine][honey]" ) { avatar dummy; dummy.set_body(); - dummy.worn.push_back( item( "backpack" ) ); + dummy.worn.emplace_back( "backpack" ); item &honeycomb = dummy.i_add( item( "honeycomb" ) ); REQUIRE( honeycomb.has_flag( flag_URSINE_HONEY ) ); diff --git a/tests/npc_talk_test.cpp b/tests/npc_talk_test.cpp index 5a5a9ef7d5d34..1b5f9937793ba 100644 --- a/tests/npc_talk_test.cpp +++ b/tests/npc_talk_test.cpp @@ -616,7 +616,7 @@ TEST_CASE( "npc_talk_items", "[npc_talk]" ) }; player_character.cash = 1000; player_character.int_cur = 8; - player_character.worn.push_back( item( "backpack" ) ); + player_character.worn.emplace_back( "backpack" ); d.add_topic( "TALK_TEST_EFFECTS" ); gen_response_lines( d, 19 ); // add and remove effect diff --git a/tests/player_helpers.cpp b/tests/player_helpers.cpp index 2442d881cca55..7907569b12b1e 100644 --- a/tests/player_helpers.cpp +++ b/tests/player_helpers.cpp @@ -123,7 +123,7 @@ void arm_shooter( npc &shooter, const std::string &gun_type, shooter.remove_weapon(); // XL so arrows can fit. if( !shooter.is_wearing( itype_id( "debug_backpack" ) ) ) { - shooter.worn.push_back( item( "debug_backpack" ) ); + shooter.worn.emplace_back( "debug_backpack" ); } const itype_id &gun_id{ itype_id( gun_type ) }; diff --git a/tests/ranged_balance_test.cpp b/tests/ranged_balance_test.cpp index b4623a4b9ccec..bc27c11728a90 100644 --- a/tests/ranged_balance_test.cpp +++ b/tests/ranged_balance_test.cpp @@ -227,7 +227,7 @@ TEST_CASE( "unskilled_shooter_accuracy", "[ranged] [balance] [slow]" ) clear_map(); standard_npc shooter( "Shooter", shooter_pos, {}, 0, 8, 8, 8, 7 ); shooter.set_body(); - shooter.worn.push_back( item( "backpack" ) ); + shooter.worn.emplace_back( "backpack" ); equip_shooter( shooter, { "bastsandals", "armguard_chitin", "armor_chitin", "beekeeping_gloves", "mask_guy_fawkes", "cowboy_hat" } ); assert_encumbrance( shooter, 10 ); diff --git a/tests/reading_test.cpp b/tests/reading_test.cpp index 8f6a45c8c219d..a362594c8fb65 100644 --- a/tests/reading_test.cpp +++ b/tests/reading_test.cpp @@ -44,7 +44,7 @@ TEST_CASE( "identifying unread books", "[reading][book][identify]" ) { clear_avatar(); Character &dummy = get_avatar(); - dummy.worn.push_back( item( "backpack" ) ); + dummy.worn.emplace_back( "backpack" ); GIVEN( "character has some unidentified books" ) { item &book1 = dummy.i_add( item( "novel_western" ) ); @@ -70,7 +70,7 @@ TEST_CASE( "reading a book for fun", "[reading][book][fun]" ) clear_avatar(); Character &dummy = get_avatar(); dummy.set_body(); - dummy.worn.push_back( item( "backpack" ) ); + dummy.worn.emplace_back( "backpack" ); GIVEN( "a fun book" ) { item &book = dummy.i_add( item( "novel_western" ) ); @@ -141,7 +141,7 @@ TEST_CASE( "character reading speed", "[reading][character][speed]" ) { clear_avatar(); Character &dummy = get_avatar(); - dummy.worn.push_back( item( "backpack" ) ); + dummy.worn.emplace_back( "backpack" ); // Note: read_speed() returns number of moves; // 6000 == 60 seconds @@ -186,7 +186,7 @@ TEST_CASE( "character reading speed", "[reading][character][speed]" ) TEST_CASE( "estimated reading time for a book", "[reading][book][time]" ) { avatar dummy; - dummy.worn.push_back( item( "backpack" ) ); + dummy.worn.emplace_back( "backpack" ); // Easy, medium, and hard books item &child = dummy.i_add( item( "child_book" ) ); @@ -274,7 +274,7 @@ TEST_CASE( "reasons for not being able to read", "[reading][reasons]" ) { avatar dummy; dummy.set_body(); - dummy.worn.push_back( item( "backpack" ) ); + dummy.worn.emplace_back( "backpack" ); std::vector reasons; std::vector expect_reasons; @@ -369,7 +369,7 @@ TEST_CASE( "determining book mastery", "[reading][book][mastery]" ) avatar dummy; dummy.set_body(); - dummy.worn.push_back( item( "backpack" ) ); + dummy.worn.emplace_back( "backpack" ); item &child = dummy.i_add( item( "child_book" ) ); item &alpha = dummy.i_add( item( "recipe_alpha" ) ); diff --git a/tests/reload_option_test.cpp b/tests/reload_option_test.cpp index 6778426537b93..416649bbe26be 100644 --- a/tests/reload_option_test.cpp +++ b/tests/reload_option_test.cpp @@ -15,7 +15,7 @@ TEST_CASE( "revolver_reload_option", "[reload],[reload_option],[gun]" ) { avatar dummy; - dummy.worn.push_back( item( "backpack" ) ); + dummy.worn.emplace_back( "backpack" ); item &gun = dummy.i_add( item( "sw_619", calendar::turn_zero, 0 ) ); const ammotype &gun_ammo_type = item::find_type( gun.ammo_default() )->ammo->type; @@ -46,7 +46,7 @@ TEST_CASE( "revolver_reload_option", "[reload],[reload_option],[gun]" ) TEST_CASE( "magazine_reload_option", "[reload],[reload_option],[gun]" ) { avatar dummy; - dummy.worn.push_back( item( "backpack" ) ); + dummy.worn.emplace_back( "backpack" ); item &magazine = dummy.i_add( item( "glockmag", calendar::turn_zero, 0 ) ); const ammotype &mag_ammo_type = item::find_type( magazine.ammo_default() )->ammo->type; @@ -69,7 +69,7 @@ TEST_CASE( "belt_reload_option", "[reload],[reload_option],[gun]" ) { avatar dummy; dummy.set_body(); - dummy.worn.push_back( item( "backpack" ) ); + dummy.worn.emplace_back( "backpack" ); item &belt = dummy.i_add( item( "belt308", calendar::turn_zero, 0 ) ); const ammotype &belt_ammo_type = item::find_type( belt.ammo_default() )->ammo->type; @@ -96,7 +96,7 @@ TEST_CASE( "belt_reload_option", "[reload],[reload_option],[gun]" ) TEST_CASE( "canteen_reload_option", "[reload],[reload_option],[liquid]" ) { avatar dummy; - dummy.worn.push_back( item( "backpack" ) ); + dummy.worn.emplace_back( "backpack" ); item &bottle = dummy.i_add( item( "bottle_plastic" ) ); item water( "water_clean", calendar::turn_zero, 2 ); diff --git a/tests/reloading_test.cpp b/tests/reloading_test.cpp index f75d39fbcf676..56b7b5d929c3a 100644 --- a/tests/reloading_test.cpp +++ b/tests/reloading_test.cpp @@ -211,7 +211,7 @@ TEST_CASE( "automatic_reloading_action", "[reload],[gun]" ) GIVEN( "a player wielding an unloaded gun, carrying an unloaded magazine, and carrying ammo for the magazine" ) { dummy.worn.clear(); - dummy.worn.push_back( item( "backpack" ) ); + dummy.worn.emplace_back( "backpack" ); item &ammo = dummy.i_add( item( "9mm", calendar::turn_zero, 50 ) ); const cata::value_ptr &ammo_type = ammo.type->ammo; REQUIRE( ammo_type ); diff --git a/tests/string_ids_test.cpp b/tests/string_ids_test.cpp index 5cc963592b0f4..f8479470721a2 100644 --- a/tests/string_ids_test.cpp +++ b/tests/string_ids_test.cpp @@ -39,7 +39,7 @@ TEST_CASE( "string_ids_intern_test", "[string_id]" ) // lots of ids to make sure that "interning" map gets expanded ids.reserve( num_ids ); for( int i = 0; i < num_ids; ++i ) { - ids.push_back( string_id( "test_id" + std::to_string( i ) ) ); + ids.emplace_back( "test_id" + std::to_string( i ) ); } // check that interning works @@ -107,7 +107,7 @@ TEST_CASE( "string_id_sorting_test", "[string_id]" ) SECTION( "vector of pairs sorting" ) { std::vector> vec; for( int i = 9; i >= 0; i-- ) { - vec.push_back( {id( "id" + std::to_string( i ) ), i} ); + vec.emplace_back( id( "id" + std::to_string( i ) ), i ); } int i = 0; @@ -122,7 +122,7 @@ TEST_CASE( "string_id_sorting_test", "[string_id]" ) std::vector vec; vec.reserve( 10 ); for( int i = 0; i < 10; ++i ) { - vec.push_back( id( "id" + std::to_string( i ) ) ); + vec.emplace_back( "id" + std::to_string( i ) ); } int i = 0; diff --git a/tests/vehicle_part_test.cpp b/tests/vehicle_part_test.cpp index d69bca02778da..4f8a4b8964982 100644 --- a/tests/vehicle_part_test.cpp +++ b/tests/vehicle_part_test.cpp @@ -196,19 +196,19 @@ TEST_CASE( "craft_available_via_vehicle_rig", "[vehicle][vehicle_craft]" ) } SECTION( "cook oatmeal without battery" ) { std::vector items; - items.push_back( item( itype_id( "oatmeal" ) ) ); + items.emplace_back( itype_id( "oatmeal" ) ); test_craft_via_rig( items, 0, 0, 1, 1, recipe_id( "oatmeal_cooked" ).obj(), false ); } SECTION( "cook oatmeal without water" ) { std::vector items; - items.push_back( item( itype_id( "oatmeal" ) ) ); + items.emplace_back( itype_id( "oatmeal" ) ); test_craft_via_rig( items, 2, 2, 0, 0, recipe_id( "oatmeal_cooked" ).obj(), false ); } SECTION( "cook oatmeal successfully" ) { std::vector items; - items.push_back( item( itype_id( "oatmeal" ) ) ); + items.emplace_back( itype_id( "oatmeal" ) ); test_craft_via_rig( items, 2, 0, 1, 0, recipe_id( "oatmeal_cooked" ).obj(), true ); } diff --git a/tests/visitable_remove_test.cpp b/tests/visitable_remove_test.cpp index b31263c8a9c3e..15544be8a2c4f 100644 --- a/tests/visitable_remove_test.cpp +++ b/tests/visitable_remove_test.cpp @@ -50,7 +50,7 @@ TEST_CASE( "visitable_remove", "[visitable]" ) Character &p = get_player_character(); p.worn.clear(); - p.worn.push_back( item( "backpack" ) ); + p.worn.emplace_back( "backpack" ); p.inv->clear(); p.remove_weapon(); p.wear_item( item( "backpack" ) ); // so we don't drop anything From f3687194741b0c7db348ef32750d222f4b82bcb7 Mon Sep 17 00:00:00 2001 From: Zeropol Date: Fri, 28 May 2021 12:07:46 +0200 Subject: [PATCH 427/453] Add a few epitaphs (#48752) We had only 13 epitaphs, this commit adds 16. Most are from https://stoneletters.com and I created a few. I let the reviewer(s) decide which one are OK. --- data/json/snippets/grave_labels.json | 18 +++++++++++++++++- 1 file changed, 17 insertions(+), 1 deletion(-) diff --git a/data/json/snippets/grave_labels.json b/data/json/snippets/grave_labels.json index 90f824cb5bc48..ae3c7bfff0d72 100644 --- a/data/json/snippets/grave_labels.json +++ b/data/json/snippets/grave_labels.json @@ -15,7 +15,23 @@ "We will always remember you", "This was all my fault", "This was all our fault", - "I hope you feel better up there" + "I hope you feel better up there", + "You won't suffer no more", + "You were the best of us", + "And when the earth shall claim your limbs, then shall you truly dance", + "The song is ended but the melody lingers on", + "Step softly, a dream lies buried here", + "Miss you Mom", + "Miss you Dad", + "May you never walk again, may I not kill you again", + "Vita mutatur non tollitur", + "Let your hunger calm down", + "The child is the father of the man", + "Now we learned that death is a gift", + "I held you your whole life", + "So small, so sweet, so soon", + "Ours for a little while", + "You died for us, we'll live for you" ] } ] From d11dfe7d4e7c7d36a6f058d268a5593d802679c8 Mon Sep 17 00:00:00 2001 From: Fris0uman <41293484+Fris0uman@users.noreply.github.com> Date: Fri, 28 May 2021 12:08:26 +0200 Subject: [PATCH 428/453] [MSC] Make sugar comestible to sugarkin (#48967) --- data/mods/My_Sweet_Cataclysm/sweet_items.json | 10 ++++++++++ 1 file changed, 10 insertions(+) diff --git a/data/mods/My_Sweet_Cataclysm/sweet_items.json b/data/mods/My_Sweet_Cataclysm/sweet_items.json index 6c83a070228ae..78a9f83bee3df 100644 --- a/data/mods/My_Sweet_Cataclysm/sweet_items.json +++ b/data/mods/My_Sweet_Cataclysm/sweet_items.json @@ -59,5 +59,15 @@ "symbol": ",", "color": "light_gray", "flags": [ "NO_SALVAGE" ] + }, + { + "type": "COMESTIBLE", + "id": "sugar", + "name": { "str_sp": "sugar" }, + "copy-from": "sugar", + "color": "white", + "symbol": "%", + "description": "Sweet, sweet sugar. Bad for your teeth and surprisingly not very tasty on its own.", + "material": [ "junk" ] } ] From a9441a5b4d64bb1f9e8da57c8c318a3faa26cfd7 Mon Sep 17 00:00:00 2001 From: Fris0uman <41293484+Fris0uman@users.noreply.github.com> Date: Fri, 28 May 2021 12:10:44 +0200 Subject: [PATCH 429/453] Remove "burst" from the code for good (#48856) --- data/json/items/gun/shot.json | 2 +- doc/JSON_INFO.md | 3 +-- src/item_factory.cpp | 12 ------------ src/itype.h | 3 --- 4 files changed, 2 insertions(+), 18 deletions(-) diff --git a/data/json/items/gun/shot.json b/data/json/items/gun/shot.json index a0c1f6dde9f75..662fbbcbf64b9 100644 --- a/data/json/items/gun/shot.json +++ b/data/json/items/gun/shot.json @@ -53,7 +53,7 @@ "material": [ "steel" ], "dispersion": 855, "durability": 8, - "burst": 6, + "modes": [ [ "DEFAULT", "burst", 6 ] ], "ups_charges": 1, "reload": 200, "valid_mod_locations": [ [ "accessories", 4 ], [ "sights", 1 ], [ "rail mount", 1 ] ], diff --git a/doc/JSON_INFO.md b/doc/JSON_INFO.md index 38b3db1821dd4..230b3c69b9da6 100644 --- a/doc/JSON_INFO.md +++ b/doc/JSON_INFO.md @@ -2683,7 +2683,6 @@ Guns can be defined like this: "durability": 8, // Resistance to damage/rusting, also determines misfire chance "blackpowder_tolerance": 8,// One in X chance to get clogged up (per shot) when firing blackpowder ammunition (higher is better). Optional, default is 8. "min_cycle_recoil": 0, // Minimum ammo recoil for gun to be able to fire more than once per attack. -"burst": 5, // Number of shots fired in burst mode "variants": [ // Cosmetic variants this gun can have { "id": "varianta", // id used in spawning to spawn this variant specifically @@ -2696,6 +2695,7 @@ Guns can be defined like this: "clip_size": 100, // Maximum amount of ammo that can be loaded "ups_charges": 0, // Additionally to the normal ammo (if any), a gun can require some charges from an UPS. This also works on mods. Attaching a mod with ups_charges will add/increase ups drain on the weapon. "ammo_to_fire" 1, // Amount of ammo used +"modes": [ [ "DEFAULT", "semi-auto", 1 ], [ "AUTO", "auto", 4 ] ], // Firing modes on this gun, DEFAULT,AUTO, or MELEE followed by the name of the mode displayed in game, and finaly the number of shots of the mod. "reload": 450, // Amount of time to reload, 100 = 1 second = 1 "turn" "built_in_mods": ["m203"], //An array of mods that will be integrated in the weapon using the IRREMOVABLE tag. "default_mods": ["m203"] //An array of mods that will be added to a weapon on spawn. @@ -2728,7 +2728,6 @@ Gun mods can be defined like this: "acceptable_ammo": [ "9mm" ], // Optional filter restricting mod to guns with those base (before modifiers) ammo types "ammo_modifier": [ "57" ], // Optional field which if specified modifies parent gun to use these ammo types "magazine_adaptor": [ [ "223", [ "stanag30" ] ] ], // Optional field which changes the types of magazines the parent gun accepts -"burst_modifier": 3, // Optional field increasing or decreasing base gun burst size "damage_modifier": -1, // Optional field increasing or decreasing base gun damage "dispersion_modifier": 15, // Optional field increasing or decreasing base gun dispersion "loudness_modifier": 4, // Optional field increasing or decreasing base guns loudness diff --git a/src/item_factory.cpp b/src/item_factory.cpp index c7f736d1e3eef..dd7ecebfc358a 100644 --- a/src/item_factory.cpp +++ b/src/item_factory.cpp @@ -418,12 +418,6 @@ void Item_factory::finalize_pre( itype &obj ) gun_modifier_data( to_translation( "melee" ), 1, { "MELEE" } ) ); } - if( obj.gun->burst > 1 ) { - // handle legacy JSON format - obj.gun->modes.emplace( gun_mode_id( "AUTO" ), - gun_modifier_data( to_translation( "auto" ), obj.gun->burst, - std::set() ) ); - } if( obj.gun->handling < 0 ) { // TODO: specify in JSON via classes @@ -1795,11 +1789,6 @@ void gun_variant_data::load( const JsonObject &jo ) void Item_factory::load( islot_gun &slot, const JsonObject &jo, const std::string &src ) { bool strict = src == "dda"; - - if( jo.has_member( "burst" ) && jo.has_member( "modes" ) ) { - jo.throw_error( "cannot specify both burst and modes", "burst" ); - } - assign( jo, "skill", slot.skill_used, strict ); assign( jo, "ammo", slot.ammo, strict ); assign( jo, "range", slot.range, strict ); @@ -1811,7 +1800,6 @@ void Item_factory::load( islot_gun &slot, const JsonObject &jo, const std::strin assign( jo, "recoil", slot.recoil, strict, 0 ); assign( jo, "handling", slot.handling, strict ); assign( jo, "durability", slot.durability, strict, 0, 10 ); - assign( jo, "burst", slot.burst, strict, 1 ); assign( jo, "loudness", slot.loudness, strict ); assign( jo, "clip_size", slot.clip, strict, 0 ); assign( jo, "reload", slot.reload_time, strict, 0 ); diff --git a/src/itype.h b/src/itype.h index 05c6de659d557..35c5f3e1ba2c1 100644 --- a/src/itype.h +++ b/src/itype.h @@ -546,9 +546,6 @@ struct islot_gun : common_ranged_data { /** Firing modes are supported by the gun. Always contains at least DEFAULT mode */ std::map modes; - /** Burst size for AUTO mode (legacy field for items not migrated to specify modes ) */ - int burst = 0; - /** How easy is control of recoil? If unset value automatically derived from weapon type */ int handling = -1; From 2a34032cf022749291aef052c59c3fc226f03800 Mon Sep 17 00:00:00 2001 From: Fris0uman <41293484+Fris0uman@users.noreply.github.com> Date: Fri, 28 May 2021 12:11:19 +0200 Subject: [PATCH 430/453] Add Eye colors cosmetic traits (#48726) * Add the 6 main eye colors * Make some approximate trait groups * Randomize eye color for random character at chargen --- data/json/mutations/mutation_appearance.json | 72 ++++++++++++++++++++ data/json/mutations/mutation_type.json | 4 ++ data/json/npcs/appearance_trait_groups.json | 41 ++++++++--- src/newcharacter.cpp | 2 + 4 files changed, 111 insertions(+), 8 deletions(-) diff --git a/data/json/mutations/mutation_appearance.json b/data/json/mutations/mutation_appearance.json index 79d025513ed1b..6b8aebf137567 100644 --- a/data/json/mutations/mutation_appearance.json +++ b/data/json/mutations/mutation_appearance.json @@ -479,6 +479,78 @@ "player_display": false, "types": [ "hair_style" ] }, + { + "id": "eye_blue", + "type": "mutation", + "name": { "str": "Eye color: blue" }, + "description": "You have blue eyes.", + "points": 0, + "starting_trait": true, + "valid": false, + "purifiable": false, + "player_display": false, + "types": [ "eye_color" ] + }, + { + "id": "eye_brown", + "type": "mutation", + "name": { "str": "Eye color: brown" }, + "description": "You have brown eyes.", + "points": 0, + "starting_trait": true, + "valid": false, + "purifiable": false, + "player_display": false, + "types": [ "eye_color" ] + }, + { + "id": "eye_hazel", + "type": "mutation", + "name": { "str": "Eye color: hazel" }, + "description": "You have hazel eyes.", + "points": 0, + "starting_trait": true, + "valid": false, + "purifiable": false, + "player_display": false, + "types": [ "eye_color" ] + }, + { + "id": "eye_amber", + "type": "mutation", + "name": { "str": "Eye color: amber" }, + "description": "You have amber eyes.", + "points": 0, + "starting_trait": true, + "valid": false, + "purifiable": false, + "player_display": false, + "types": [ "eye_color" ] + }, + { + "id": "eye_gray", + "type": "mutation", + "name": { "str": "Eye color: gray" }, + "description": "You have gray eyes.", + "points": 0, + "starting_trait": true, + "valid": false, + "purifiable": false, + "player_display": false, + "types": [ "eye_color" ] + }, + { + "id": "eye_green", + "type": "mutation", + "name": { "str": "Eye color: green" }, + "description": "You have green eyes.", + "points": 0, + "starting_trait": true, + "valid": false, + "purifiable": false, + "player_display": false, + "types": [ "eye_color" ] + }, { "id": "SKIN_DARK", "type": "mutation", diff --git a/data/json/mutations/mutation_type.json b/data/json/mutations/mutation_type.json index 56e4f91bff305..97807fedc1330 100644 --- a/data/json/mutations/mutation_type.json +++ b/data/json/mutations/mutation_type.json @@ -71,6 +71,10 @@ "type": "mutation_type", "id": "skin_tone" }, + { + "type": "mutation_type", + "id": "eye_color" + }, { "type": "mutation_type", "id": "hair_style" diff --git a/data/json/npcs/appearance_trait_groups.json b/data/json/npcs/appearance_trait_groups.json index c4c7a36542022..e70abf1547bf3 100644 --- a/data/json/npcs/appearance_trait_groups.json +++ b/data/json/npcs/appearance_trait_groups.json @@ -19,49 +19,49 @@ "type": "trait_group", "id": "Appearance_Irish", "subtype": "collection", - "traits": [ { "group": "Hair_Irish", "prob": 100 }, { "group": "Skin_Fair", "prob": 100 } ] + "traits": [ { "group": "Hair_Irish", "prob": 100 }, { "group": "Skin_Fair", "prob": 100 }, { "group": "Eye_light", "prob": 100 } ] }, { "type": "trait_group", "id": "Appearance_Caucasian", "subtype": "collection", - "traits": [ { "group": "Hair_Any", "prob": 100 }, { "group": "Skin_White", "prob": 100 } ] + "traits": [ { "group": "Hair_Any", "prob": 100 }, { "group": "Skin_White", "prob": 100 }, { "group": "Eye_any", "prob": 100 } ] }, { "type": "trait_group", "id": "Appearance_Germanic", "subtype": "collection", - "traits": [ { "group": "Hair_Fair", "prob": 100 }, { "group": "Skin_Fair", "prob": 100 } ] + "traits": [ { "group": "Hair_Fair", "prob": 100 }, { "group": "Skin_Fair", "prob": 100 }, { "group": "Eye_light", "prob": 100 } ] }, { "type": "trait_group", "id": "Appearance_Latin", "subtype": "collection", - "traits": [ { "group": "Hair_Dark", "prob": 100 }, { "group": "Skin_Medium", "prob": 100 } ] + "traits": [ { "group": "Hair_Dark", "prob": 100 }, { "group": "Skin_Medium", "prob": 100 }, { "group": "Eye_dark", "prob": 100 } ] }, { "type": "trait_group", "id": "Appearance_African", "subtype": "collection", - "traits": [ { "group": "Hair_Dark", "prob": 100 }, { "group": "Skin_Dark", "prob": 100 } ] + "traits": [ { "group": "Hair_Dark", "prob": 100 }, { "group": "Skin_Dark", "prob": 100 }, { "group": "Eye_dark", "prob": 100 } ] }, { "type": "trait_group", "id": "Appearance_EastAsian", "subtype": "collection", - "traits": [ { "group": "Hair_Dark", "prob": 100 }, { "trait": "SKIN_TAN", "prob": 100 } ] + "traits": [ { "group": "Hair_Dark", "prob": 100 }, { "trait": "SKIN_TAN", "prob": 100 }, { "group": "Eye_dark", "prob": 100 } ] }, { "type": "trait_group", "id": "Appearance_SouthAsian", "subtype": "collection", - "traits": [ { "group": "Hair_Dark", "prob": 100 }, { "trait": "SKIN_TAN", "prob": 100 } ] + "traits": [ { "group": "Hair_Dark", "prob": 100 }, { "trait": "SKIN_TAN", "prob": 100 }, { "group": "Eye_dark", "prob": 100 } ] }, { "type": "trait_group", "id": "Appearance_Mixed", "subtype": "collection", - "traits": [ { "group": "Hair_Any", "prob": 100 }, { "group": "Skin_Any", "prob": 100 } ] + "traits": [ { "group": "Hair_Any", "prob": 100 }, { "group": "Skin_Any", "prob": 100 }, { "group": "Eye_any", "prob": 100 } ] }, { "type": "trait_group", @@ -153,6 +153,31 @@ "subtype": "distribution", "traits": [ { "trait": "SKIN_DARK", "prob": 50 }, { "trait": "SKIN_MEDIUM", "prob": 5 }, { "trait": "SKIN_TAN", "prob": 25 } ] }, + { + "type": "trait_group", + "id": "Eye_light", + "subtype": "distribution", + "traits": [ { "trait": "eye_blue", "prob": 55 }, { "trait": "eye_gray", "prob": 25 }, { "trait": "eye_green", "prob": 15 } ] + }, + { + "type": "trait_group", + "id": "Eye_dark", + "subtype": "distribution", + "traits": [ { "trait": "eye_brown", "prob": 60 }, { "trait": "eye_hazel", "prob": 20 }, { "trait": "eye_amber", "prob": 20 } ] + }, + { + "type": "trait_group", + "id": "Eye_any", + "subtype": "distribution", + "traits": [ + { "trait": "eye_brown", "prob": 70 }, + { "trait": "eye_hazel", "prob": 9 }, + { "trait": "eye_amber", "prob": 8 }, + { "trait": "eye_blue", "prob": 8 }, + { "trait": "eye_gray", "prob": 3 }, + { "trait": "eye_green", "prob": 2 } + ] + }, { "type": "trait_group", "id": "Hair_Black", diff --git a/src/newcharacter.cpp b/src/newcharacter.cpp index 7a04272a385c8..2e1d0b637866f 100644 --- a/src/newcharacter.cpp +++ b/src/newcharacter.cpp @@ -69,6 +69,7 @@ static const std::string flag_SECRET( "SECRET" ); static const std::string type_hair_style( "hair_style" ); static const std::string type_skin_tone( "skin_tone" ); static const std::string type_facial_hair( "facial_hair" ); +static const std::string type_eye_color( "eye_color" ); static const flag_id json_flag_no_auto_equip( "no_auto_equip" ); static const flag_id json_flag_auto_wield( "auto_wield" ); @@ -382,6 +383,7 @@ void avatar::randomize( const bool random_scenario, points_left &points, bool pl randomize_cosmetic_trait( type_hair_style ); randomize_cosmetic_trait( type_skin_tone ); + randomize_cosmetic_trait( type_eye_color ); //arbitrary 50% chance to add beard to male characters if( male && one_in( 2 ) ) { randomize_cosmetic_trait( type_facial_hair ); From ea5a9a9b98752406ccb5a36541bb080e3be97b9d Mon Sep 17 00:00:00 2001 From: Fris0uman <41293484+Fris0uman@users.noreply.github.com> Date: Fri, 28 May 2021 12:12:58 +0200 Subject: [PATCH 431/453] Jsonize fungalization (#48479) --- data/json/monsters/insect_spider.json | 9 ++ data/json/monsters/triffid.json | 3 + data/json/monsters/zed-classic.json | 9 ++ data/json/monsters/zed_children.json | 7 ++ data/json/monsters/zed_explosive.json | 3 + data/json/monsters/zed_misc.json | 12 +++ data/json/monsters/zed_soldiers.json | 2 + data/json/monsters/zed_survivor.json | 1 + doc/JSON_FLAGS.md | 1 + doc/MONSTERS.md | 2 + src/monster.cpp | 125 ++------------------------ src/monster.h | 1 + src/monstergenerator.cpp | 7 ++ src/mtype.h | 2 + 14 files changed, 65 insertions(+), 119 deletions(-) diff --git a/data/json/monsters/insect_spider.json b/data/json/monsters/insect_spider.json index cb3837f4b7602..e8ae956ea583e 100644 --- a/data/json/monsters/insect_spider.json +++ b/data/json/monsters/insect_spider.json @@ -862,6 +862,7 @@ "harvest": "arachnid", "anger_triggers": [ "STALK", "PLAYER_WEAK", "PLAYER_CLOSE" ], "death_function": [ "NORMAL" ], + "fungalize_into": "mon_spider_fungus", "upgrades": { "half_life": 21, "into": "mon_spider_cellar_mega" }, "flags": [ "SEES", "SMELLS", "HEARS", "VENOM", "WEBWALK", "CLIMBS", "HARDTOSHOOT", "PUSH_MON", "PATH_AVOID_FIRE" ], "//": "No, they are not in fact the most venomous spider in the world." @@ -958,6 +959,7 @@ "special_attacks": [ { "type": "leap", "cooldown": 2, "max_range": 5, "allow_no_target": true } ], "anger_triggers": [ "PLAYER_CLOSE" ], "death_function": [ "NORMAL" ], + "fungalize_into": "mon_spider_fungus", "upgrades": { "half_life": 21, "into": "mon_spider_jumping_mega" }, "flags": [ "SEES", "SMELLS", "HEARS", "HIT_AND_RUN", "CLIMBS", "PATH_AVOID_DANGER_1" ] }, @@ -1015,6 +1017,7 @@ "vision_night": 5, "harvest": "arachnid", "death_function": [ "NORMAL" ], + "fungalize_into": "mon_spider_fungus", "upgrades": { "half_life": 21, "into": "mon_spider_trapdoor_mega" }, "flags": [ "SEES", "SMELLS", "HEARS", "VENOM", "GRABS", "CAN_DIG", "WEBWALK", "CLIMBS", "PATH_AVOID_FIRE" ] }, @@ -1074,6 +1077,7 @@ "vision_night": 5, "harvest": "arachnid", "death_function": [ "NORMAL" ], + "fungalize_into": "mon_spider_fungus", "upgrades": { "half_life": 21, "into": "mon_spider_web_mega" }, "flags": [ "SEES", "SMELLS", "HEARS", "WEBWALK", "CLIMBS", "PATH_AVOID_FIRE", "PATH_AVOID_FALL" ] }, @@ -1164,6 +1168,7 @@ "harvest": "arachnid", "anger_triggers": [ "PLAYER_WEAK", "PLAYER_CLOSE" ], "death_function": [ "NORMAL" ], + "fungalize_into": "mon_spider_fungus", "upgrades": { "half_life": 21, "into": "mon_spider_widow_mega" }, "flags": [ "SEES", "SMELLS", "HEARS", "BADVENOM", "WEBWALK", "CLIMBS", "PATH_AVOID_FIRE" ] }, @@ -1258,6 +1263,7 @@ "harvest": "arachnid", "anger_triggers": [ "STALK", "PLAYER_WEAK", "HURT", "PLAYER_CLOSE" ], "death_function": [ "NORMAL" ], + "fungalize_into": "mon_spider_fungus", "upgrades": { "half_life": 21, "into": "mon_spider_wolf_mega" }, "flags": [ "SEES", "SMELLS", "HEARS", "CLIMBS", "PATH_AVOID_FIRE", "PATH_AVOID_FALL" ] }, @@ -1528,6 +1534,7 @@ "anger_triggers": [ "FRIEND_ATTACKED", "FRIEND_DIED", "HURT", "PLAYER_WEAK" ], "death_function": [ "NORMAL" ], "special_attacks": [ [ "EAT_FOOD", 30 ] ], + "fungalize_into": "mon_ant_fungus", "flags": [ "SEES", "HEARS", "SMELLS", "CLIMBS", "PATH_AVOID_FIRE", "PATH_AVOID_FALL" ] }, { @@ -1721,6 +1728,7 @@ "special_attacks": [ [ "ANTQUEEN", 1 ] ], "anger_triggers": [ "FRIEND_ATTACKED", "FRIEND_DIED", "HURT" ], "death_function": [ "NORMAL" ], + "fungalize_into": "mon_ant_fungus", "flags": [ "SMELLS", "QUEEN", "CLIMBS", "PATH_AVOID_FIRE", "PATH_AVOID_FALL" ] }, { @@ -1753,6 +1761,7 @@ "harvest": "arachnid", "anger_triggers": [ "FRIEND_ATTACKED", "FRIEND_DIED", "HURT", "PLAYER_CLOSE" ], "death_function": [ "NORMAL" ], + "fungalize_into": "mon_ant_fungus", "upgrades": { "half_life": 21, "into": "mon_ant_soldier_mega" }, "flags": [ "SEES", "HEARS", "SMELLS", "CLIMBS", "PATH_AVOID_FIRE", "PATH_AVOID_FALL" ] }, diff --git a/data/json/monsters/triffid.json b/data/json/monsters/triffid.json index 24541393ac309..e92824b27659f 100644 --- a/data/json/monsters/triffid.json +++ b/data/json/monsters/triffid.json @@ -143,6 +143,7 @@ "upgrades": { "age_grow": 14, "into": "mon_triffid" }, "special_attacks": [ [ "TRIFFID_GROWTH", 28800 ] ], "death_function": [ "NORMAL" ], + "fungalize_into": "mon_fungaloid", "flags": [ "HEARS", "SMELLS", "NOHEAD", "PARALYZEVENOM" ] }, { @@ -170,6 +171,7 @@ "armor_bullet": 3, "harvest": "triffid_paralytic", "death_function": [ "NORMAL" ], + "fungalize_into": "mon_fungaloid", "flags": [ "SEES", "SMELLS", "BASHES", "GROUP_BASH", "NOHEAD", "PARALYZEVENOM" ] }, { @@ -198,6 +200,7 @@ "harvest": "triffid_queen", "special_attacks": [ [ "GROWPLANTS", 20 ] ], "death_function": [ "NORMAL" ], + "fungalize_into": "mon_fungaloid", "flags": [ "HEARS", "SMELLS", "BASHES", "NOHEAD", "PARALYZEVENOM" ] }, { diff --git a/data/json/monsters/zed-classic.json b/data/json/monsters/zed-classic.json index 2a20a86ea6950..a11db87639196 100644 --- a/data/json/monsters/zed-classic.json +++ b/data/json/monsters/zed-classic.json @@ -43,6 +43,7 @@ "NO_BREATHE", "REVIVES", "PUSH_MON", + "NO_FUNG_DMG", "FILTHY" ] }, @@ -74,6 +75,7 @@ "death_drops": "default_zombie_death_drops", "death_function": [ "NORMAL" ], "burn_into": "mon_zombie_scorched", + "fungalize_into": "mon_zombie_fungus", "upgrades": { "half_life": 14, "into_group": "GROUP_ZOMBIE_UPGRADE" }, "flags": [ "SEES", @@ -123,6 +125,7 @@ "death_drops": "mon_zombie_cop_death_drops", "death_function": [ "NORMAL" ], "burn_into": "mon_zombie_scorched", + "fungalize_into": "mon_zombie_fungus", "flags": [ "SEES", "HEARS", @@ -198,6 +201,7 @@ "harvest": "zombie_leather", "special_attacks": [ [ "DANCE", 30 ] ], "death_drops": "mon_zombie_hulk_death_drops", + "fungalize_into": "mon_zombie_fungus", "death_function": [ "NORMAL" ], "regenerates": 50, "flags": [ "WARM", "BASHES", "DESTROYS", "NO_BREATHE", "POISON", "FILTHY" ] @@ -233,6 +237,7 @@ "death_drops": "default_zombie_death_drops", "death_function": [ "NORMAL" ], "burn_into": "mon_zombie_scorched", + "fungalize_into": "mon_zombie_fungus", "upgrades": { "half_life": 12, "into_group": "GROUP_ZOMBIE_FAT" }, "flags": [ "SEES", @@ -294,6 +299,7 @@ "NO_BREATHE", "REVIVES", "PUSH_MON", + "NO_FUNG_DMG", "FILTHY" ] }, @@ -340,6 +346,7 @@ "NO_BREATHE", "REVIVES", "PUSH_MON", + "NO_FUNG_DMG", "FILTHY" ] }, @@ -371,6 +378,7 @@ "death_drops": "default_zombie_death_drops", "death_function": [ "NORMAL" ], "burn_into": "mon_zombie_scorched", + "fungalize_into": "mon_zombie_fungus", "upgrades": { "half_life": 23, "into": "mon_devourer" }, "flags": [ "SEES", @@ -467,6 +475,7 @@ "death_drops": "default_zombie_death_drops", "death_function": [ "NORMAL" ], "burn_into": "mon_zombie_scorched", + "fungalize_into": "mon_zombie_fungus", "upgrades": { "half_life": 14, "into_group": "GROUP_ZOMBIE_UPGRADE" }, "flags": [ "SEES", diff --git a/data/json/monsters/zed_children.json b/data/json/monsters/zed_children.json index 0fa1c8af14176..6512ba1615ce2 100644 --- a/data/json/monsters/zed_children.json +++ b/data/json/monsters/zed_children.json @@ -28,6 +28,7 @@ "death_drops": { "subtype": "collection", "groups": [ [ "default_zombie_clothes", 100 ], [ "child_items", 65 ] ] }, "death_function": [ "NORMAL" ], "burn_into": "mon_zombie_child_scorched", + "zombify_into": "mon_zombie_child_fungus", "flags": [ "SEES", "HEARS", "SMELLS", "STUMBLES", "WARM", "BASHES", "POISON", "NO_BREATHE", "REVIVES", "FILTHY" ], "//": "no GUILT because it no longer looks enough like a child to evoke pity" }, @@ -65,6 +66,7 @@ }, "death_function": [ "NORMAL" ], "burn_into": "mon_zombie_child_scorched", + "zombify_into": "mon_zombie_child_fungus", "upgrades": { "half_life": 14, "into_group": "GROUP_CHILD_ZOMBIE_UPGRADE" }, "flags": [ "SEES", "HEARS", "SMELLS", "STUMBLES", "WARM", "BASHES", "POISON", "GUILT", "NO_BREATHE", "REVIVES", "FILTHY" ] }, @@ -97,6 +99,7 @@ "death_drops": { "subtype": "collection", "groups": [ [ "default_zombie_clothes", 100 ], [ "child_items", 65 ] ] }, "death_function": [ "NORMAL" ], "burn_into": "mon_zombie_child_scorched", + "zombify_into": "mon_zombie_child_fungus", "flags": [ "SEES", "HEARS", "SMELLS", "STUMBLES", "WARM", "BASHES", "POISON", "NO_BREATHE", "REVIVES", "CLIMBS", "FILTHY" ], "//": "no GUILT because it no longer looks enough like a child to evoke pity" }, @@ -130,6 +133,7 @@ "death_drops": { "subtype": "collection", "groups": [ [ "default_zombie_clothes", 100 ], [ "child_items", 65 ] ] }, "death_function": [ "NORMAL" ], "burn_into": "mon_zombie_child_scorched", + "zombify_into": "mon_zombie_child_fungus", "flags": [ "SEES", "HEARS", "SMELLS", "STUMBLES", "WARM", "GUILT", "BASHES", "POISON", "NO_BREATHE", "REVIVES", "FILTHY" ], "//": "GUILT because it still looks enough like a child to evoke pity" }, @@ -163,6 +167,7 @@ "death_drops": { "subtype": "collection", "groups": [ [ "default_zombie_clothes", 100 ], [ "child_items", 65 ] ] }, "death_function": [ "BOOMER" ], "burn_into": "mon_zombie_child_scorched", + "zombify_into": "mon_zombie_child_fungus", "flags": [ "SEES", "HEARS", "STUMBLES", "WARM", "GUILT", "POISON", "NO_BREATHE", "REVIVES", "FILTHY" ], "//": "GUILT because it still looks enough like a child to evoke pity" }, @@ -195,6 +200,7 @@ "death_drops": { "subtype": "collection", "groups": [ [ "default_zombie_clothes", 100 ], [ "child_items", 65 ] ] }, "death_function": [ "NORMAL" ], "burn_into": "mon_zombie_child_scorched", + "zombify_into": "mon_zombie_child_fungus", "flags": [ "SEES", "HEARS", "SMELLS", "STUMBLES", "WARM", "BASHES", "POISON", "NO_BREATHE", "REVIVES", "CLIMBS", "FILTHY" ], "//": "no GUILT because it no longer looks enough like a child to evoke pity" }, @@ -230,6 +236,7 @@ "death_drops": { "subtype": "collection", "groups": [ [ "default_zombie_clothes", 100 ], [ "child_items", 65 ] ] }, "death_function": [ "NORMAL" ], "burn_into": "mon_zombie_child_scorched", + "zombify_into": "mon_zombie_child_fungus", "flags": [ "SEES", "HEARS", "SMELLS", "STUMBLES", "WARM", "GUILT", "POISON", "NO_BREATHE", "REVIVES", "HARDTOSHOOT", "FILTHY" ], "//": "GUILT because it still looks enough like a child to evoke pity" } diff --git a/data/json/monsters/zed_explosive.json b/data/json/monsters/zed_explosive.json index d0df9c8e8cdcd..47f11eda5b05e 100644 --- a/data/json/monsters/zed_explosive.json +++ b/data/json/monsters/zed_explosive.json @@ -27,6 +27,7 @@ "death_drops": "default_zombie_items", "death_function": [ "BOOMER" ], "upgrades": { "half_life": 14, "into": "mon_boomer_huge" }, + "fungalize_into": "mon_boomer_fungus", "flags": [ "SEES", "HEARS", @@ -71,6 +72,7 @@ "armor_bullet": 4, "vision_night": 3, "harvest": "zombie", + "fungalize_into": "mon_boomer_fungus", "special_attacks": [ [ "BOOMER_GLOW", 20 ], [ "scratch", 20 ] ], "death_drops": "default_zombie_items", "death_function": [ "BOOMER_GLOW" ], @@ -162,6 +164,7 @@ "special_attacks": [ [ "SUICIDE", 20 ], [ "scratch", 15 ] ], "death_drops": "default_zombie_items", "death_function": [ "GAS" ], + "fungalize_into": "mon_zombie_gasbag_fungus", "flags": [ "SEES", "HEARS", "SMELLS", "STUMBLES", "WARM", "POISON", "NO_BREATHE", "REVIVES", "FILTHY" ] } ] diff --git a/data/json/monsters/zed_misc.json b/data/json/monsters/zed_misc.json index 090d952eb07f3..5f479006945d9 100644 --- a/data/json/monsters/zed_misc.json +++ b/data/json/monsters/zed_misc.json @@ -222,6 +222,7 @@ "death_function": [ "NORMAL" ], "burn_into": "mon_zombie_fiend", "upgrades": { "half_life": 21, "into_group": "GROUP_ZOMBIE_BRUTE" }, + "fungalize_into": "mon_zombie_fungus", "flags": [ "SEES", "HEARS", @@ -415,6 +416,7 @@ "death_function": [ "NORMAL" ], "burn_into": "mon_zombie_scorched", "upgrades": { "half_life": 14, "into_group": "GROUP_ZOMBIE_GRAB" }, + "fungalize_into": "mon_zombie_fungus", "flags": [ "SEES", "HEARS", @@ -460,6 +462,7 @@ "death_drops": "default_zombie_death_drops", "death_function": [ "NORMAL" ], "burn_into": "mon_zombie_scorched", + "fungalize_into": "mon_zombie_fungus", "flags": [ "SEES", "HEARS", @@ -540,6 +543,7 @@ "special_attacks": [ [ "SMASH", 20 ] ], "death_drops": "mon_zombie_hulk_death_drops", "death_function": [ "NORMAL" ], + "fungalize_into": "mon_zombie_fungus", "flags": [ "SEES", "HEARS", @@ -594,6 +598,7 @@ "death_function": [ "NORMAL" ], "burn_into": "mon_zombie_scorched", "upgrades": { "half_life": 28, "into": "mon_zombie_predator" }, + "fungalize_into": "mon_zombie_fungus", "flags": [ "SEES", "HEARS", "SMELLS", "WARM", "BASHES", "POISON", "NO_BREATHE", "REVIVES", "CLIMBS", "PUSH_MON", "FILTHY" ] }, { @@ -736,6 +741,7 @@ "REVIVES", "CAN_OPEN_DOORS", "PRIORITIZE_TARGETS", + "NO_FUNG_DMG", "FILTHY", "PATH_AVOID_DANGER_1" ] @@ -785,6 +791,7 @@ "PATH_AVOID_DANGER_1", "CAN_OPEN_DOORS", "PRIORITIZE_TARGETS", + "NO_FUNG_DMG", "FILTHY" ] }, @@ -1018,6 +1025,7 @@ "death_drops": "default_zombie_death_drops", "death_function": [ "NORMAL" ], "burn_into": "mon_zombie_scorched", + "fungalize_into": "mon_zombie_fungus", "upgrades": { "half_life": 10, "into": "mon_zombie_screecher" }, "flags": [ "SEES", @@ -1111,6 +1119,7 @@ "emit_fields": [ { "emit_id": "emit_smoke_stream", "delay": "1 s" } ], "special_attacks": [ { "type": "bite", "cooldown": 5 }, [ "scratch", 15 ] ], "death_function": [ "SMOKEBURST" ], + "fungalize_into": "mon_zombie_smoker_fungus", "upgrades": { "half_life": 28, "into": "mon_smoker_brute" }, "flags": [ "SEES", @@ -1205,6 +1214,7 @@ "death_drops": "mon_zombie_swimmer_death_drops", "death_function": [ "NORMAL" ], "burn_into": "mon_zombie_scorched", + "fungalize_into": "mon_zombie_fungus", "upgrades": { "half_life": 14, "into": "mon_zombie_swimmer" }, "categories": [ "CLASSIC" ], "flags": [ @@ -1250,6 +1260,7 @@ "death_drops": "mon_zombie_swimmer_death_drops", "death_function": [ "NORMAL" ], "burn_into": "mon_zombie_scorched", + "fungalize_into": "mon_zombie_fungus", "upgrades": { "half_life": 28, "into": "mon_zombie_mancroc" }, "flags": [ "SEES", @@ -1296,6 +1307,7 @@ "vision_day": 15, "vision_night": 2, "harvest": "CBM_TECH", + "fungalize_into": "mon_zombie_fungus", "special_attacks": [ [ "PULL_METAL_WEAPON", 25 ], { "type": "bite", "cooldown": 20 } ], "death_drops": "mon_zombie_technician_death_drops", "death_function": [ "NORMAL" ], diff --git a/data/json/monsters/zed_soldiers.json b/data/json/monsters/zed_soldiers.json index 67d44f111c2ec..8dfb1774795e6 100644 --- a/data/json/monsters/zed_soldiers.json +++ b/data/json/monsters/zed_soldiers.json @@ -33,6 +33,7 @@ "death_function": [ "NORMAL" ], "upgrades": { "half_life": 28, "into_group": "GROUP_SOLDIER_UPGRADE" }, "burn_into": "mon_zombie_scorched", + "fungalize_into": "mon_zombie_fungus", "flags": [ "SEES", "HEARS", "SMELLS", "WARM", "BASHES", "GROUP_BASH", "POISON", "NO_BREATHE", "REVIVES", "PUSH_MON", "FILTHY" ] }, { @@ -405,6 +406,7 @@ "special_when_hit": [ "ZAPBACK", 75 ], "death_drops": "mon_zombie_bio_op_death_drops", "death_function": [ "NORMAL" ], + "fungalize_into": "mon_zombie_fungus", "flags": [ "SEES", "HEARS", diff --git a/data/json/monsters/zed_survivor.json b/data/json/monsters/zed_survivor.json index f07140b5ddddc..e6b3913ff5ea2 100644 --- a/data/json/monsters/zed_survivor.json +++ b/data/json/monsters/zed_survivor.json @@ -38,6 +38,7 @@ "death_drops": "mon_zombie_survivor_death_drops", "death_function": [ "NORMAL" ], "burn_into": "mon_zombie_scorched", + "fungalize_into": "mon_zombie_fungus", "flags": [ "SEES", "HEARS", "SMELLS", "WARM", "BASHES", "GROUP_BASH", "POISON", "NO_BREATHE", "REVIVES", "PUSH_MON", "FILTHY" ] }, { diff --git a/doc/JSON_FLAGS.md b/doc/JSON_FLAGS.md index b8847cfd14c48..036e6a3919e63 100644 --- a/doc/JSON_FLAGS.md +++ b/doc/JSON_FLAGS.md @@ -983,6 +983,7 @@ Other monster flags. - ```NOHEAD``` Headshots not allowed! - ```NO_BREATHE``` Creature can't drown and is unharmed by gas, smoke or poison. - ```NO_BREED``` Creature doesn't reproduce even though it has reproduction data - useful when using copy-from to make child versions of adult creatures +- ```NO_FUNG_DMG``` This monster can't be damaged by fungal spores and can't be fungalized either. - ```PAY_BOT``` Creature can be turned into a pet for a limited time in exchange of e-money. - ```PET_MOUNTABLE``` Creature can be ridden or attached to an harness. - ```PET_HARNESSABLE```Creature can be attached to an harness. diff --git a/doc/MONSTERS.md b/doc/MONSTERS.md index 6e16aea25d22d..ad1f898c68274 100644 --- a/doc/MONSTERS.md +++ b/doc/MONSTERS.md @@ -87,6 +87,8 @@ Monsters may also have any of these optional properties: | `path_settings` | (object) How monster may find a path, open doors, avoid traps, or bash obstacles | `biosignature` | (object) Droppings or feces left by the animal or monster | `harvest` | (string) ID of a "harvest" type describing what can be harvested from the corpse +| `zombify_into` | (string) mtype_id this monster zombifies into after it's death +| `fungalize_into` | (string) mtype_id this monster turns into when fungalized by spores Properties in the above tables are explained in more detail in the sections below. diff --git a/src/monster.cpp b/src/monster.cpp index 69e3ca2beb55a..1ba933611a821 100644 --- a/src/monster.cpp +++ b/src/monster.cpp @@ -126,59 +126,6 @@ static const trait_id trait_PHEROMONE_MAMMAL( "PHEROMONE_MAMMAL" ); static const trait_id trait_TERRIFYING( "TERRIFYING" ); static const trait_id trait_THRESH_MYCUS( "THRESH_MYCUS" ); -static const mtype_id mon_ant( "mon_ant" ); -static const mtype_id mon_ant_fungus( "mon_ant_fungus" ); -static const mtype_id mon_ant_queen( "mon_ant_queen" ); -static const mtype_id mon_ant_soldier( "mon_ant_soldier" ); -static const mtype_id mon_beekeeper( "mon_beekeeper" ); -static const mtype_id mon_boomer( "mon_boomer" ); -static const mtype_id mon_boomer_fungus( "mon_boomer_fungus" ); -static const mtype_id mon_boomer_huge( "mon_boomer_huge" ); -static const mtype_id mon_fungaloid( "mon_fungaloid" ); -static const mtype_id mon_skeleton_brute( "mon_skeleton_brute" ); -static const mtype_id mon_skeleton_hulk( "mon_skeleton_hulk" ); -static const mtype_id mon_skeleton_hulk_fungus( "mon_skeleton_hulk_fungus" ); -static const mtype_id mon_spider_fungus( "mon_spider_fungus" ); -static const mtype_id mon_triffid( "mon_triffid" ); -static const mtype_id mon_triffid_queen( "mon_triffid_queen" ); -static const mtype_id mon_triffid_young( "mon_triffid_young" ); -static const mtype_id mon_zombie( "mon_zombie" ); -static const mtype_id mon_zombie_anklebiter( "mon_zombie_anklebiter" ); -static const mtype_id mon_zombie_bio_op( "mon_zombie_bio_op" ); -static const mtype_id mon_zombie_brute( "mon_zombie_brute" ); -static const mtype_id mon_zombie_brute_shocker( "mon_zombie_brute_shocker" ); -static const mtype_id mon_zombie_child( "mon_zombie_child" ); -static const mtype_id mon_zombie_child_fungus( "mon_zombie_child_fungus" ); -static const mtype_id mon_zombie_cop( "mon_zombie_cop" ); -static const mtype_id mon_zombie_creepy( "mon_zombie_creepy" ); -static const mtype_id mon_zombie_electric( "mon_zombie_electric" ); -static const mtype_id mon_zombie_fat( "mon_zombie_fat" ); -static const mtype_id mon_zombie_fireman( "mon_zombie_fireman" ); -static const mtype_id mon_zombie_fungus( "mon_zombie_fungus" ); -static const mtype_id mon_zombie_gasbag( "mon_zombie_gasbag" ); -static const mtype_id mon_zombie_gasbag_fungus( "mon_zombie_gasbag_fungus" ); -static const mtype_id mon_zombie_grabber( "mon_zombie_grabber" ); -static const mtype_id mon_zombie_hazmat( "mon_zombie_hazmat" ); -static const mtype_id mon_zombie_hulk( "mon_zombie_hulk" ); -static const mtype_id mon_zombie_hunter( "mon_zombie_hunter" ); -static const mtype_id mon_zombie_master( "mon_zombie_master" ); -static const mtype_id mon_zombie_necro( "mon_zombie_necro" ); -static const mtype_id mon_zombie_rot( "mon_zombie_rot" ); -static const mtype_id mon_zombie_scientist( "mon_zombie_scientist" ); -static const mtype_id mon_zombie_shrieker( "mon_zombie_shrieker" ); -static const mtype_id mon_zombie_shriekling( "mon_zombie_shriekling" ); -static const mtype_id mon_zombie_smoker( "mon_zombie_smoker" ); -static const mtype_id mon_zombie_smoker_fungus( "mon_zombie_smoker_fungus" ); -static const mtype_id mon_zombie_snotgobbler( "mon_zombie_snotgobbler" ); -static const mtype_id mon_zombie_soldier( "mon_zombie_soldier" ); -static const mtype_id mon_zombie_spitter( "mon_zombie_spitter" ); -static const mtype_id mon_zombie_sproglodyte( "mon_zombie_sproglodyte" ); -static const mtype_id mon_zombie_survivor( "mon_zombie_survivor" ); -static const mtype_id mon_zombie_swimmer( "mon_zombie_swimmer" ); -static const mtype_id mon_zombie_technician( "mon_zombie_technician" ); -static const mtype_id mon_zombie_tough( "mon_zombie_tough" ); -static const mtype_id mon_zombie_waif( "mon_zombie_waif" ); - struct pathfinding_settings; // Limit the number of iterations for next upgrade_time calculations. @@ -2670,8 +2617,6 @@ bool monster::make_fungus() if( is_hallucination() ) { return true; } - char polypick = 0; - const mtype_id &tid = type->id; if( type->in_species( species_FUNGUS ) ) { // No friendly-fungalizing ;-) return true; } @@ -2681,73 +2626,15 @@ bool monster::make_fungus() // No fungalizing robots or weird stuff (mi-gos are technically fungi, blobs are goo) return true; } - if( tid == mon_ant || tid == mon_ant_soldier || tid == mon_ant_queen ) { - polypick = 1; - } else if( tid == mon_zombie || tid == mon_zombie_shrieker || tid == mon_zombie_electric || - tid == mon_zombie_spitter || tid == mon_zombie_brute || - tid == mon_zombie_hulk || tid == mon_zombie_soldier || tid == mon_zombie_tough || - tid == mon_zombie_scientist || tid == mon_zombie_hunter || tid == mon_skeleton_brute || - tid == mon_zombie_bio_op || tid == mon_zombie_survivor || tid == mon_zombie_fireman || - tid == mon_zombie_cop || tid == mon_zombie_fat || tid == mon_zombie_rot || - tid == mon_zombie_swimmer || tid == mon_zombie_grabber || tid == mon_zombie_technician || - tid == mon_zombie_brute_shocker ) { - polypick = 2; - } else if( tid == mon_zombie_necro || tid == mon_zombie_master || tid == mon_zombie_fireman || - tid == mon_zombie_hazmat || tid == mon_beekeeper ) { - // Necro and Master have enough Goo to resist conversion. - // Firefighter, hazmat, and scarred/beekeeper have the PPG on. - return true; - } else if( tid == mon_boomer || tid == mon_boomer_huge ) { - polypick = 3; - } else if( tid == mon_triffid || tid == mon_triffid_young || tid == mon_triffid_queen ) { - polypick = 4; - } else if( tid == mon_zombie_anklebiter || tid == mon_zombie_child || tid == mon_zombie_creepy || - tid == mon_zombie_shriekling || tid == mon_zombie_snotgobbler || tid == mon_zombie_sproglodyte || - tid == mon_zombie_waif ) { - polypick = 5; - } else if( tid == mon_skeleton_hulk ) { - polypick = 6; - } else if( tid == mon_zombie_smoker ) { - polypick = 7; - } else if( tid == mon_zombie_gasbag ) { - polypick = 8; - } else if( type->in_species( species_SPIDER ) && get_size() > creature_size::tiny ) { - polypick = 9; + if( type->has_flag( MF_NO_FUNG_DMG ) ) { + return true; // Retrun true when monster is immune to fungal damage. + } + if( type->fungalize_into.is_empty() ) { + return false; } const std::string old_name = name(); - switch( polypick ) { - case 1: - poly( mon_ant_fungus ); - break; - case 2: - // zombies, non-boomer - poly( mon_zombie_fungus ); - break; - case 3: - poly( mon_boomer_fungus ); - break; - case 4: - poly( mon_fungaloid ); - break; - case 5: - poly( mon_zombie_child_fungus ); - break; - case 6: - poly( mon_skeleton_hulk_fungus ); - break; - case 7: - poly( mon_zombie_smoker_fungus ); - break; - case 8: - poly( mon_zombie_gasbag_fungus ); - break; - case 9: - poly( mon_spider_fungus ); - break; - default: - return false; - } + poly( type->fungalize_into ); add_msg_if_player_sees( pos(), m_info, _( "The spores transform %1$s into a %2$s!" ), old_name, name() ); diff --git a/src/monster.h b/src/monster.h index b509c01df8974..827bf221df85f 100644 --- a/src/monster.h +++ b/src/monster.h @@ -416,6 +416,7 @@ class monster : public Creature /** * Makes this monster into a fungus version * Returns false if no such monster exists + * Returns true if monster is immune or if it got fungalized */ bool make_fungus(); void make_friendly(); diff --git a/src/monstergenerator.cpp b/src/monstergenerator.cpp index 31bc369de1767..e6ede6b24a3eb 100644 --- a/src/monstergenerator.cpp +++ b/src/monstergenerator.cpp @@ -176,6 +176,7 @@ std::string enum_to_string( m_flag data ) case MF_MILKABLE: return "MILKABLE"; case MF_SHEARABLE: return "SHEARABLE"; case MF_NO_BREED: return "NO_BREED"; + case MF_NO_FUNG_DMG: return "NO_FUNG_DMG"; case MF_PET_WONT_FOLLOW: return "PET_WONT_FOLLOW"; case MF_DRIPS_NAPALM: return "DRIPS_NAPALM"; case MF_DRIPS_GASOLINE: return "DRIPS_GASOLINE"; @@ -789,6 +790,8 @@ void mtype::load( const JsonObject &jo, const std::string &src ) optional( jo, was_loaded, "zombify_into", zombify_into, auto_flags_reader {}, mtype_id() ); + optional( jo, was_loaded, "fungalize_into", fungalize_into, auto_flags_reader {}, + mtype_id() ); // TODO: make this work with `was_loaded` if( jo.has_array( "melee_damage" ) ) { @@ -1221,6 +1224,10 @@ void MonsterGenerator::check_monster_definitions() const debugmsg( "monster %s has unknown zombify_into: %s", mon.id.c_str(), mon.zombify_into.c_str() ); } + if( !mon.fungalize_into.is_empty() && !mon.fungalize_into.is_valid() ) { + debugmsg( "monster %s has unknown fungalize_into: %s", mon.id.c_str(), + mon.fungalize_into.c_str() ); + } if( !mon.picture_id.is_empty() && !mon.picture_id.is_valid() ) { debugmsg( "monster %s has unknown ascii_picture: %s", mon.id.c_str(), mon.picture_id.c_str() ); diff --git a/src/mtype.h b/src/mtype.h index 229fb8beb7697..96392f9002e52 100644 --- a/src/mtype.h +++ b/src/mtype.h @@ -165,6 +165,7 @@ enum m_flag : int { MF_MILKABLE, // This monster is milkable. MF_SHEARABLE, // This monster is shearable. MF_NO_BREED, // This monster doesn't breed, even though it has breed data + MF_NO_FUNG_DMG, // This monster can't be damaged by fungal spores and can't be fungalized either. MF_PET_WONT_FOLLOW, // This monster won't follow the player automatically when tamed. MF_DRIPS_NAPALM, // This monster occasionally drips napalm on move MF_DRIPS_GASOLINE, // This monster occasionally drips gasoline on move @@ -312,6 +313,7 @@ struct mtype { mtype_id burn_into; mtype_id zombify_into; // mtype_id this monster zombifies into + mtype_id fungalize_into; // mtype_id this monster fungalize into // Monster reproduction variables cata::optional baby_timer; From bbd97d7ec4a69a8cf07f5663eb7466ebab914ab3 Mon Sep 17 00:00:00 2001 From: John Candlebury Date: Fri, 28 May 2021 04:17:41 -0600 Subject: [PATCH 432/453] Bases for the first four Hub01 basement npcs (#48719) --- data/json/mutations/mutations.json | 12 +++ .../NPC_Andrea_Dzvonko.json | 80 ++++++++++++++++++ .../NPC_Darla_Novak.json | 82 ++++++++++++++++++ .../NPC_Jonathan_Farrier.json | 83 +++++++++++++++++++ .../NPC_Sunil_Narayana.json | 81 ++++++++++++++++++ 5 files changed, 338 insertions(+) create mode 100644 data/json/npcs/robofac/robofac_basement_npcs/NPC_Andrea_Dzvonko.json create mode 100644 data/json/npcs/robofac/robofac_basement_npcs/NPC_Darla_Novak.json create mode 100644 data/json/npcs/robofac/robofac_basement_npcs/NPC_Jonathan_Farrier.json create mode 100644 data/json/npcs/robofac/robofac_basement_npcs/NPC_Sunil_Narayana.json diff --git a/data/json/mutations/mutations.json b/data/json/mutations/mutations.json index 01460e1e17bef..3785849830bde 100644 --- a/data/json/mutations/mutations.json +++ b/data/json/mutations/mutations.json @@ -6501,6 +6501,18 @@ "name": { "str": "US Marshal" }, "points": 0, "description": "You are a duly sworn Federal marshal, with nationwide jurisdiction and the authority of the United States of America.", + "cancels": [ "PROF_HUB01_ANCILLIARY" ], + "valid": false, + "purifiable": false, + "profession": true + }, + { + "type": "mutation", + "id": "PROF_HUB01_ANCILLIARY", + "name": { "str": "Hub 01 Ancilliary" }, + "points": 0, + "description": "You are known to be a capable and resourceful mercenary at the employ of Hub 01.", + "cancels": [ "PROF_FED" ], "valid": false, "purifiable": false, "profession": true diff --git a/data/json/npcs/robofac/robofac_basement_npcs/NPC_Andrea_Dzvonko.json b/data/json/npcs/robofac/robofac_basement_npcs/NPC_Andrea_Dzvonko.json new file mode 100644 index 0000000000000..88cb804016e21 --- /dev/null +++ b/data/json/npcs/robofac/robofac_basement_npcs/NPC_Andrea_Dzvonko.json @@ -0,0 +1,80 @@ +[ + { + "type": "npc", + "id": "HUB01_ADzvonko", + "name_unique": "Andrea Dzvonko", + "gender": "female", + "name_suffix": "software engineer", + "class": "NC_HUB01_ADzvonko", + "attitude": 0, + "mission": 7, + "chat": "HUB01_ADzvonko_Intro", + "faction": "robofac" + }, + { + "type": "npc_class", + "id": "NC_HUB01_ADzvonko", + "name": { "str": "Hub 01 Software Engineer" }, + "job_description": "I work for Hub 01 as a software engineer.", + "common": false, + "//": "Andrea Dzvonko is a software engineer with a limited understanding of how melchior actually functions.", + "bonus_str": { "rng": [ -2, 2 ] }, + "bonus_dex": { "rng": [ -2, 2 ] }, + "bonus_int": { "rng": [ 0, 4 ] }, + "bonus_per": { "rng": [ -2, 2 ] }, + "worn_override": "HUB01_ADzvonko_worn", + "carry_override": "HUB01_ADzvonko_carried", + "weapon_override": "HUB01_ADzvonko_wield", + "traits": [ { "trait": "FASTLEARNER" }, { "group": "Appearance_Caucasian" } ], + "skills": [ + { "skill": "ALL", "level": { "mul": [ { "one_in": 3 }, { "sum": [ { "dice": [ 2, 2 ] }, { "rng": [ 0, -4 ] } ] } ] } }, + { "skill": "computer", "bonus": { "rng": [ 4, 6 ] } } + ] + }, + { + "type": "item_group", + "id": "HUB01_ADzvonko_worn", + "subtype": "collection", + "entries": [ + { "item": "bra" }, + { "item": "panties" }, + { "item": "socks" }, + { "item": "robofac_jumpsuit" }, + { "item": "sneakers" }, + { "item": "sweater" } + ] + }, + { + "type": "item_group", + "id": "HUB01_ADzvonko_carried", + "subtype": "collection", + "entries": [ { "group": "wallets_science" } ] + }, + { + "type": "item_group", + "id": "HUB01_ADzvonko_wield" + }, + { + "type": "talk_topic", + "id": "HUB01_ADzvonko_Intro", + "dynamic_line": { + "u_has_trait": "PROF_HUB01_ANCILLIARY", + "yes": "Woah, you must be that new person they told us about. I can't really believe you're here. I'm Andrea. Dr. Dzvonko in the old days, but that seems silly now.", + "no": "Who the fuck are you? How did you get down here? Security!" + }, + "responses": [ + { + "text": "Hold on, hold on. I'm not here to hurt anyone, and there aren't enough of us left to just start fighting.", + "topic": "TALK_DONE", + "condition": { "not": { "u_has_trait": "PROF_HUB01_ANCILLIARY" } }, + "effect": "flee" + }, + { + "text": "Nice to meet you too.", + "topic": "TALK_DONE", + "effect": { "u_add_var": "u_met_ADzvonko", "type": "general", "context": "meeting", "value": "yes" }, + "condition": { "u_has_trait": "PROF_HUB01_ANCILLIARY" } + } + ] + } +] diff --git a/data/json/npcs/robofac/robofac_basement_npcs/NPC_Darla_Novak.json b/data/json/npcs/robofac/robofac_basement_npcs/NPC_Darla_Novak.json new file mode 100644 index 0000000000000..7c4d307114056 --- /dev/null +++ b/data/json/npcs/robofac/robofac_basement_npcs/NPC_Darla_Novak.json @@ -0,0 +1,82 @@ +[ + { + "type": "npc", + "id": "HUB01_DNovak", + "name_unique": "Darla Novak", + "gender": "female", + "name_suffix": "building maintenance", + "class": "NC_HUB01_DNovak", + "attitude": 0, + "mission": 7, + "chat": "HUB01_DNovak_Intro", + "faction": "robofac" + }, + { + "type": "npc_class", + "id": "NC_HUB01_DNovak", + "name": { "str": "Hub 01 HVAC maintenance" }, + "job_description": "I'm part of Hub 01's maintenance crew.", + "common": false, + "//": "HVAC maintenance. Keeps melchior from boiling to death and you from choking on stale bunker air.", + "bonus_str": { "rng": [ -1, 2 ] }, + "bonus_dex": { "rng": [ -1, 2 ] }, + "bonus_int": { "rng": [ -2, 2 ] }, + "bonus_per": { "rng": [ -1, 2 ] }, + "worn_override": "HUB01_DNovak_worn", + "carry_override": "HUB01_DNovak_carried", + "weapon_override": "HUB01_DNovak_wield", + "traits": [ { "group": "Appearance_demographics" } ], + "skills": [ + { "skill": "ALL", "level": { "mul": [ { "one_in": 3 }, { "sum": [ { "dice": [ 2, 2 ] }, { "rng": [ 0, -4 ] } ] } ] } }, + { "skill": "fabrication", "bonus": { "rng": [ 0, 3 ] } }, + { "skill": "mechanics", "bonus": { "rng": [ 4, 5 ] } } + ] + }, + { + "type": "item_group", + "id": "HUB01_DNovak_worn", + "subtype": "collection", + "entries": [ + { "item": "bra" }, + { "item": "panties" }, + { "item": "socks" }, + { "item": "robofac_jumpsuit" }, + { "item": "boots_steel" }, + { "item": "vest" }, + { "item": "gloves_work" } + ] + }, + { + "type": "item_group", + "id": "HUB01_DNovak_carried", + "subtype": "collection", + "entries": [ { "group": "wallet_full" }, { "item": "flashlight" }, { "item": "screwdriver_set" } ] + }, + { + "type": "item_group", + "id": "HUB01_DNovak_wield" + }, + { + "type": "talk_topic", + "id": "HUB01_DNovak_Intro", + "dynamic_line": { + "u_has_trait": "PROF_HUB01_ANCILLIARY", + "yes": "Oh, hey. The rumors were true, there really is someone new around. Nice to meet you, call me Darla.", + "no": "Who the fuck are you? How did you get down here? Security!" + }, + "responses": [ + { + "text": "Hold on, hold on. I'm not here to hurt anyone, and there aren't enough of us left to just start fighting.", + "condition": { "not": { "u_has_trait": "PROF_HUB01_ANCILLIARY" } }, + "topic": "TALK_DONE", + "effect": "flee" + }, + { + "text": "Nice to meet you too.", + "topic": "TALK_DONE", + "effect": { "u_add_var": "u_met_DNovak", "type": "general", "context": "meeting", "value": "yes" }, + "condition": { "u_has_trait": "PROF_HUB01_ANCILLIARY" } + } + ] + } +] diff --git a/data/json/npcs/robofac/robofac_basement_npcs/NPC_Jonathan_Farrier.json b/data/json/npcs/robofac/robofac_basement_npcs/NPC_Jonathan_Farrier.json new file mode 100644 index 0000000000000..e2144bc693f19 --- /dev/null +++ b/data/json/npcs/robofac/robofac_basement_npcs/NPC_Jonathan_Farrier.json @@ -0,0 +1,83 @@ +[ + { + "type": "npc", + "id": "HUB01_JFarrier", + "name_unique": "Jonathan Farrier", + "gender": "male", + "name_suffix": "assistant", + "class": "NC_HUB01_JFarrier", + "attitude": 0, + "mission": 7, + "chat": "HUB01_JFarrier_Intro", + "faction": "robofac" + }, + { + "type": "npc_class", + "id": "NC_HUB01_JFarrier", + "name": { "str": "Hub 01 Assistant" }, + "job_description": "I do miscellaneous jobs within Hub 01.", + "common": false, + "//": "Trucker and now general handyman. Used to work as a cargo driver for a company supplying Hub 01, is only inside the lab by chance.", + "bonus_str": { "rng": [ -1, 2 ] }, + "bonus_dex": { "rng": [ -2, 2 ] }, + "bonus_int": { "rng": [ -2, 2 ] }, + "bonus_per": { "rng": [ -2, 2 ] }, + "worn_override": "HUB01_JFarrier_worn", + "carry_override": "HUB01_JFarrier_carried", + "weapon_override": "HUB01_JFarrier_wield", + "traits": [ { "group": "Appearance_demographics" } ], + "skills": [ + { "skill": "ALL", "level": { "mul": [ { "one_in": 3 }, { "sum": [ { "dice": [ 2, 2 ] }, { "rng": [ 0, -4 ] } ] } ] } }, + { "skill": "driving", "bonus": { "rng": [ 4, 6 ] } }, + { "skill": "fabrication", "bonus": { "rng": [ 0, 1 ] } }, + { "skill": "mechanics", "bonus": { "rng": [ 1, 2 ] } } + ] + }, + { + "type": "item_group", + "id": "HUB01_JFarrier_worn", + "subtype": "collection", + "entries": [ + { "item": "briefs" }, + { "item": "socks" }, + { "item": "robofac_jumpsuit" }, + { "item": "bandana" }, + { "item": "boots_steel" }, + { "item": "tool_belt" }, + { "item": "gloves_work" } + ] + }, + { + "type": "item_group", + "id": "HUB01_JFarrier_carried", + "subtype": "collection", + "entries": [ { "group": "wallet_full" }, { "item": "multitool" }, { "item": "screwdriver_set" }, { "item": "hammer" } ] + }, + { + "type": "item_group", + "id": "HUB01_JFarrier_wield" + }, + { + "type": "talk_topic", + "id": "HUB01_JFarrier_Intro", + "dynamic_line": { + "u_has_trait": "PROF_HUB01_ANCILLIARY", + "yes": "Aw, hey, you must be that new blood runnin' jobs up top. So, they finally let you down, eh? My name's Jon, Jon Farrier. Nice to meet you, real nice.", + "no": "Who the fuck are you? How did you get down here? Security!" + }, + "responses": [ + { + "text": "Hold on, hold on. I'm not here to hurt anyone, and there aren't enough of us left to just start fighting.", + "condition": { "not": { "u_has_trait": "PROF_HUB01_ANCILLIARY" } }, + "topic": "TALK_DONE", + "effect": "flee" + }, + { + "text": "Nice to meet you too.", + "topic": "TALK_DONE", + "effect": { "u_add_var": "u_met_JFarrier", "type": "general", "context": "meeting", "value": "yes" }, + "condition": { "u_has_trait": "PROF_HUB01_ANCILLIARY" } + } + ] + } +] diff --git a/data/json/npcs/robofac/robofac_basement_npcs/NPC_Sunil_Narayana.json b/data/json/npcs/robofac/robofac_basement_npcs/NPC_Sunil_Narayana.json new file mode 100644 index 0000000000000..ebf75b47aff42 --- /dev/null +++ b/data/json/npcs/robofac/robofac_basement_npcs/NPC_Sunil_Narayana.json @@ -0,0 +1,81 @@ +[ + { + "type": "npc", + "id": "HUB01_SNarayana", + "name_unique": "Sunil Narayana", + "gender": "male", + "name_suffix": "server maintenance", + "class": "NC_HUB01_SNarayana", + "attitude": 0, + "mission": 7, + "chat": "HUB01_SNarayana_Intro", + "faction": "robofac" + }, + { + "type": "npc_class", + "id": "NC_HUB01_SNarayana", + "name": { "str": "Hub 01 Server Maintenance" }, + "job_description": "I'm part of Hub 01's maintenance crew.", + "common": false, + "//": "HVAC maintenance. Resident dungeon master.", + "bonus_str": { "rng": [ -2, 2 ] }, + "bonus_dex": { "rng": [ 0, 2 ] }, + "bonus_int": { "rng": [ 0, 2 ] }, + "bonus_per": { "rng": [ -1, 1 ] }, + "worn_override": "HUB01_SNarayana_worn", + "carry_override": "HUB01_SNarayana_carried", + "weapon_override": "HUB01_SNarayana_wield", + "traits": [ { "trait": "PROF_DICEMASTER" }, { "group": "Appearance_demographics" } ], + "skills": [ + { "skill": "ALL", "level": { "mul": [ { "one_in": 3 }, { "sum": [ { "dice": [ 2, 2 ] }, { "rng": [ 0, -4 ] } ] } ] } }, + { "skill": "speech", "bonus": { "rng": [ 0, 1 ] } }, + { "skill": "electronics", "bonus": { "rng": [ 4, 5 ] } } + ] + }, + { + "type": "item_group", + "id": "HUB01_SNarayana_worn", + "subtype": "collection", + "entries": [ + { "item": "boxer_briefs" }, + { "item": "socks" }, + { "item": "robofac_jumpsuit" }, + { "item": "boots" }, + { "item": "hat_ball" }, + { "item": "gloves_work" } + ] + }, + { + "type": "item_group", + "id": "HUB01_SNarayana_carried", + "subtype": "collection", + "entries": [ { "group": "wallet_full" } ] + }, + { + "type": "item_group", + "id": "HUB01_SNarayana_wield" + }, + { + "type": "talk_topic", + "id": "HUB01_SNarayana_Intro", + "dynamic_line": { + "u_has_trait": "PROF_HUB01_ANCILLIARY", + "yes": "Oooh, the NEW person. So, you're not just some rumour they cooked up as a team building exercise. I'm Sunil, welcome to the underground.", + "no": "Who the fuck are you? How did you get down here? Security!" + }, + "responses": [ + { + "text": "Hold on, hold on. I'm not here to hurt anyone, and there aren't enough of us left to just start fighting.", + "condition": { "not": { "u_has_trait": "PROF_HUB01_ANCILLIARY" } }, + "topic": "TALK_DONE", + "effect": "flee" + }, + { + "text": "Nice to meet you too.", + "topic": "TALK_DONE", + "effect": { "u_add_var": "u_met_SNarayana", "type": "general", "context": "meeting", "value": "yes" }, + "condition": { "u_has_trait": "PROF_HUB01_ANCILLIARY" } + } + ] + } +] From dec84b185652474bac6d64b885ad80f4a7443523 Mon Sep 17 00:00:00 2001 From: John Candlebury Date: Fri, 28 May 2021 04:20:57 -0600 Subject: [PATCH 433/453] Aftershock: Basic Exoplanet Region (#48206) --- .../Aftershock/maps/overmap_specials.json | 6 +- .../Map/overmap_terrain/ice_fields.json | 52 +++++ .../aftershock_exoplanet/game_balance.json | 16 ++ data/mods/aftershock_exoplanet/modinfo.json | 12 + .../aftershock_exoplanet/region_settings.json | 207 ++++++++++++++++++ data/mods/aftershock_exoplanet/scenarios.json | 13 ++ .../location_blacklist.json | 89 ++++++++ .../setting_blacklists/mon_blacklist.json | 9 + .../scenario_blacklist.json | 7 + .../aftershock_exoplanet/weather_type.json | 130 +++++++++++ 10 files changed, 537 insertions(+), 4 deletions(-) create mode 100644 data/mods/aftershock_exoplanet/Map/overmap_terrain/ice_fields.json create mode 100644 data/mods/aftershock_exoplanet/game_balance.json create mode 100644 data/mods/aftershock_exoplanet/modinfo.json create mode 100644 data/mods/aftershock_exoplanet/region_settings.json create mode 100644 data/mods/aftershock_exoplanet/scenarios.json create mode 100644 data/mods/aftershock_exoplanet/setting_blacklists/location_blacklist.json create mode 100644 data/mods/aftershock_exoplanet/setting_blacklists/mon_blacklist.json create mode 100644 data/mods/aftershock_exoplanet/setting_blacklists/scenario_blacklist.json create mode 100644 data/mods/aftershock_exoplanet/weather_type.json diff --git a/data/mods/Aftershock/maps/overmap_specials.json b/data/mods/Aftershock/maps/overmap_specials.json index 440fb168d2728..3063859b1d991 100644 --- a/data/mods/Aftershock/maps/overmap_specials.json +++ b/data/mods/Aftershock/maps/overmap_specials.json @@ -7,8 +7,7 @@ "locations": [ "land" ], "city_distance": [ 5, -1 ], "city_sizes": [ 2, -1 ], - "occurrences": [ 0, 1 ], - "flags": [ "CLASSIC" ] + "occurrences": [ 0, 1 ] }, { "type": "overmap_special", @@ -91,8 +90,7 @@ "locations": [ "land" ], "city_distance": [ 5, -1 ], "city_sizes": [ 2, -1 ], - "occurrences": [ 0, 1 ], - "flags": [ "CLASSIC" ] + "occurrences": [ 0, 1 ] }, { "type": "overmap_special", diff --git a/data/mods/aftershock_exoplanet/Map/overmap_terrain/ice_fields.json b/data/mods/aftershock_exoplanet/Map/overmap_terrain/ice_fields.json new file mode 100644 index 0000000000000..f470565670d0a --- /dev/null +++ b/data/mods/aftershock_exoplanet/Map/overmap_terrain/ice_fields.json @@ -0,0 +1,52 @@ +[ + { + "type": "overmap_terrain", + "id": "field", + "copy-from": "generic_open_land", + "name": "Ice Fields", + "sym": ".", + "color": "light_gray", + "see_cost": 2, + "extras": "field", + "mapgen": [ { "method": "builtin", "name": "field" } ], + "flags": [ "NO_ROTATE" ] + }, + { + "type": "overmap_terrain", + "id": "forest", + "copy-from": "generic_forest", + "name": "hydrothermal flats", + "sym": "%", + "color": "light_red", + "see_cost": 3, + "extras": "forest", + "spawns": { "group": "GROUP_FOREST", "population": [ 0, 3 ], "chance": 13 }, + "flags": [ "NO_ROTATE", "SOURCE_FORAGE" ] + }, + { + "type": "overmap_terrain", + "id": "forest_thick", + "copy-from": "generic_forest", + "name": "hydrothermal flats", + "sym": "%", + "color": "light_red", + "see_cost": 4, + "extras": "forest_thick", + "spawns": { "group": "GROUP_FOREST", "population": [ 0, 6 ], "chance": 15 }, + "mapgen": [ { "method": "builtin", "name": "forest" } ], + "flags": [ "NO_ROTATE", "SOURCE_FORAGE" ] + }, + { + "type": "overmap_terrain", + "id": "forest_water", + "copy-from": "generic_wetland_forest", + "name": "hydrothermal flats", + "sym": "%", + "color": "cyan", + "see_cost": 4, + "extras": "forest_water", + "spawns": { "group": "GROUP_SWAMP", "population": [ 1, 4 ], "chance": 16 }, + "mapgen": [ { "method": "builtin", "name": "forest" } ], + "flags": [ "NO_ROTATE", "SOURCE_FORAGE", "RISK_HIGH" ] + } +] diff --git a/data/mods/aftershock_exoplanet/game_balance.json b/data/mods/aftershock_exoplanet/game_balance.json new file mode 100644 index 0000000000000..f36efb1980153 --- /dev/null +++ b/data/mods/aftershock_exoplanet/game_balance.json @@ -0,0 +1,16 @@ +[ + { + "type": "EXTERNAL_OPTION", + "name": "GENERIC_PROFESSION_ID", + "info": "The profession selected by default in the character creator menu.", + "stype": "string_input", + "value": "afs_rating" + }, + { + "type": "EXTERNAL_OPTION", + "name": "GENERIC_SCENARIO_ID", + "info": "The scenario selected by default in the character creator menu.", + "stype": "string_input", + "value": "escape_pod" + } +] diff --git a/data/mods/aftershock_exoplanet/modinfo.json b/data/mods/aftershock_exoplanet/modinfo.json new file mode 100644 index 0000000000000..343b808c968e6 --- /dev/null +++ b/data/mods/aftershock_exoplanet/modinfo.json @@ -0,0 +1,12 @@ +[ + { + "type": "MOD_INFO", + "id": "aftershock_exoplanet", + "name": "Aftershock: Exoplanet", + "authors": [ "Maleclypse", "Candlebury", "Mom_Bun" ], + "maintainers": [ "Maleclypse", "Candlebury", "Mom_Bun" ], + "description": "An experimental implementation of Aftershock's exoplanet region, not recommended for actual playthroughs. Adds no new content by itself, and requires the main mod to function correctly.", + "category": "content", + "dependencies": [ "dda", "aftershock" ] + } +] diff --git a/data/mods/aftershock_exoplanet/region_settings.json b/data/mods/aftershock_exoplanet/region_settings.json new file mode 100644 index 0000000000000..615b3cd483879 --- /dev/null +++ b/data/mods/aftershock_exoplanet/region_settings.json @@ -0,0 +1,207 @@ +[ + { + "type": "region_settings", + "id": "default", + "overmap_feature_flag_settings": { + "clear_blacklist": false, + "blacklist": [ "BLOB", "BEE", "ANT", "FUNGAL", "SLIME", "TRIFFID", "MI-GO", "LAB", "CLASSIC" ], + "clear_whitelist": false, + "whitelist": [ ] + }, + "default_oter": "field", + "default_groundcover": [ [ "t_region_groundcover", 1 ] ], + "river_scale": 0, + "city": { + "shop_radius": 30, + "shop_sigma": 80, + "park_radius": 20, + "park_sigma": 80, + "houses": { "afs_city_ruinfield": 400, "afs_formless_ruins_dynamic": 600 }, + "parks": { "afs_city_ruinfield": 100 }, + "shops": { "afs_augmentation_clinic_1": 400, "afs_astrobiology_lab": 400 } + }, + "weather": { + "base_temperature": -50.0, + "base_humidity": 80.0, + "base_pressure": 1015.0, + "base_wind": 9.0, + "base_wind_distrib_peaks": 80, + "base_wind_season_variation": 50, + "weather_types": [ "clear", "sunny", "cloudy", "afs_whiteout", "afs_thunder", "afs_lightning", "afs_flurries", "afs_snowing" ] + }, + "region_terrain_and_furniture": { + "terrain": { + "t_region_groundcover": { "t_snow": 32, "t_ice": 2, "t_deaddirt": 5 }, + "t_region_groundcover_urban": { "t_snow": 20, "t_ice": 3 }, + "t_region_groundcover_forest": { "t_snow": 410, "t_lichen": 300, "t_lichendirt": 300, "t_fuma_ice": 1 }, + "t_region_groundcover_swamp": { "t_snow": 410, "t_lichen": 300, "t_lichendirt": 300, "t_fuma_ice": 1 }, + "t_region_groundcover_barren": { "t_snow": 20, "t_ice": 3 }, + "t_region_grass": { "t_lichen": 1 }, + "t_region_soil": { "t_deaddirt": 1 }, + "t_region_shrub": { "t_lichen": 30 }, + "t_region_shrub_fruit": { "t_lichenyum": 30 }, + "t_region_shrub_decorative": { "t_lichenyum": 3, "t_lichendirt": 1 }, + "t_region_tree": { "t_tree_worm": 30, "t_tree_lichen": 15, "t_tree_xenoinfested": 10 }, + "t_region_tree_fruit": { "t_lichenyum": 30 }, + "t_region_tree_nut": { "t_tree_worm": 30, "t_tree_xenoinfested": 15 }, + "t_region_tree_evergreen": { "t_tree_xenoinfested": 32, "t_tree_xeno": 16 } + }, + "furniture": { + "f_region_flower": { "f_shrub_moss": 1 }, + "f_region_flower_decorative": { + "f_lily": 4, + "f_flower_tulip": 4, + "f_black_eyed_susan": 3, + "f_dahlia": 2, + "f_bluebell": 2, + "f_flower_spurge": 1, + "f_chicory": 1, + "f_sunflower": 1 + }, + "f_region_weed": { "f_shrub_moss": 1 }, + "f_region_water_plant": { "f_shrub_moss": 15 } + } + }, + "field_coverage": { + "percent_coverage": 0.02, + "default_ter": "t_lichen", + "other": { + "t_region_tree": 1, + "t_region_shrub": 3, + "f_region_weed": 49, + "f_region_flower": 37, + "f_boulder_small": 5, + "f_boulder_medium": 4, + "f_boulder_large": 1 + }, + "boost_chance": 0.03, + "boosted_percent_coverage": 2.5, + "boosted_other": { "t_lichen": 0.2, "t_lichendirt": 0.1 }, + "boosted_other_percent": 50.0 + }, + "overmap_lake_settings": { + "noise_threshold_lake": 10.0, + "lake_size_min": 20, + "lake_depth": -5, + "shore_extendable_overmap_terrain": [ "forest", "forest_thick", "forest_water", "field" ], + "shore_extendable_overmap_terrain_aliases": [ + { "om_terrain": "island_forest", "om_terrain_match_type": "TYPE", "alias": "forest" }, + { "om_terrain": "island_forest_thick", "om_terrain_match_type": "TYPE", "alias": "forest_thick" }, + { "om_terrain": "island_forest_water", "om_terrain_match_type": "TYPE", "alias": "forest_water" }, + { "om_terrain": "island_field", "om_terrain_match_type": "TYPE", "alias": "field" } + ] + }, + "overmap_ravine_settings": { "num_ravines": 15, "ravine_width": 3, "ravine_range": 45, "ravine_depth": -3 }, + "overmap_forest_settings": { + "noise_threshold_forest": 0.5, + "noise_threshold_forest_thick": 0.55, + "noise_threshold_swamp_adjacent_water": 0.3, + "noise_threshold_swamp_isolated": 0.6, + "river_floodplain_buffer_distance_min": 3, + "river_floodplain_buffer_distance_max": 15 + }, + "forest_mapgen_settings": { + "forest": { + "sparseness_adjacency_factor": 9, + "item_group": "forest", + "item_group_chance": 60, + "item_spawn_iterations": 1, + "clear_groundcover": false, + "groundcover": { "t_region_groundcover_forest": 1 }, + "clear_components": false, + "components": { + "trees": { "sequence": 0, "chance": 12, "clear_types": false, "types": { "t_region_tree": 128 } }, + "shrubs_and_flowers": { "sequence": 1, "chance": 10, "clear_types": false, "types": { "t_region_shrub": 100, "f_region_weed": 20 } }, + "clutter": { + "sequence": 2, + "chance": 80, + "clear_types": false, + "types": { + "f_geo_vent": 128, + "t_dirtmound": 128, + "f_boulder_small": 128, + "f_rubble_rock": 32, + "f_boulder_medium": 8, + "f_boulder_large": 1, + "t_pit": 1, + "t_pit_shallow": 1 + } + }, + "water": { "sequence": 3, "chance": 512, "clear_types": false, "types": { "t_water_sh": 1 } } + }, + "clear_terrain_furniture": false, + "terrain_furniture": { } + }, + "forest_thick": { + "sparseness_adjacency_factor": 4, + "item_group": "forest", + "item_group_chance": 60, + "item_spawn_iterations": 1, + "clear_groundcover": false, + "groundcover": { "t_region_groundcover_forest": 1 }, + "clear_components": false, + "components": { + "trees": { "sequence": 0, "chance": 5, "clear_types": false, "types": { "t_region_tree": 100 } }, + "shrubs_and_flowers": { "sequence": 1, "chance": 5, "clear_types": false, "types": { "t_region_shrub": 100, "f_region_weed": 20 } }, + "clutter": { + "sequence": 2, + "chance": 64, + "clear_types": false, + "types": { + "f_geo_vent": 14, + "t_dirtmound": 24, + "f_boulder_small": 32, + "f_rubble_rock": 32, + "f_boulder_medium": 16, + "f_boulder_large": 4, + "t_pit": 1, + "t_pit_shallow": 1 + } + }, + "water": { "sequence": 3, "chance": 512, "clear_types": false, "types": { "t_water_sh": 1 } } + }, + "clear_terrain_furniture": false, + "terrain_furniture": { } + }, + "forest_water": { + "sparseness_adjacency_factor": 2, + "item_group": "forest", + "item_group_chance": 60, + "item_spawn_iterations": 1, + "clear_groundcover": false, + "groundcover": { "t_region_groundcover_swamp": 1 }, + "clear_components": false, + "components": { + "trees": { "sequence": 1, "chance": 45, "clear_types": false, "types": { "f_geo_vent": 40 } }, + "shrubs_and_flowers": { "sequence": 1, "chance": 15, "clear_types": false, "types": { "t_region_shrub": 80, "f_region_weed": 30 } }, + "clutter": { + "sequence": 2, + "chance": 75, + "clear_types": false, + "types": { "t_trunk": 1, "f_boulder_small": 2, "f_boulder_medium": 1 } + }, + "water": { "sequence": 3, "chance": 2, "clear_types": false, "types": { "t_water_hot": 12 } } + }, + "clear_terrain_furniture": false, + "terrain_furniture": { "t_water_hot": { "chance": 2, "clear_furniture": false, "furniture": { "f_region_water_plant": 1 } } } + } + }, + "forest_trail_settings": { + "chance": 2, + "border_point_chance": 2, + "minimum_forest_size": 100, + "random_point_min": 4, + "random_point_max": 50, + "random_point_size_scalar": 100, + "trailhead_chance": 1, + "trailhead_road_distance": 6, + "trail_center_variance": 3, + "trail_width_offset_min": 1, + "trail_width_offset_max": 3, + "clear_trail_terrain": false, + "trail_terrain": { "t_deaddirt": 1 }, + "trailheads": { "trailhead_basic": 1, "trailhead_outhouse": 1, "trailhead_shack": 1 } + }, + "map_extras": { } + } +] diff --git a/data/mods/aftershock_exoplanet/scenarios.json b/data/mods/aftershock_exoplanet/scenarios.json new file mode 100644 index 0000000000000..f78814a1fb57d --- /dev/null +++ b/data/mods/aftershock_exoplanet/scenarios.json @@ -0,0 +1,13 @@ +[ + { + "type": "scenario", + "id": "evacuee", + "name": "Stranded Spacer", + "points": 1, + "description": "What was to be a routine cargo transfer ended in tragedy when, in a brief moment of chaos, your space ship was intercepted and destroyed by a StO missile. As soon as the MAW alarm flared to life, you scrambled to the nearest escape pod and barely managed reach the uncertain safety of the planet below.", + "allowed_locs": [ "sloc_escape_pod" ], + "professions": [ "afs_espatier", "afs_rating" ], + "flags": [ "LONE_START" ], + "start_name": "Escape Pod" + } +] diff --git a/data/mods/aftershock_exoplanet/setting_blacklists/location_blacklist.json b/data/mods/aftershock_exoplanet/setting_blacklists/location_blacklist.json new file mode 100644 index 0000000000000..80201b69af785 --- /dev/null +++ b/data/mods/aftershock_exoplanet/setting_blacklists/location_blacklist.json @@ -0,0 +1,89 @@ +[ + { + "//": "mostly removes areas with their own storylines, static NPCs, and the like. some will be readded with time", + "type": "overmap_special", + "id": "Necropolis", + "overmaps": [ ], + "occurrences": [ 0, 0 ] + }, + { + "type": "overmap_special", + "id": "St_Johns_farm", + "overmaps": [ ], + "occurrences": [ 0, 0 ] + }, + { + "type": "overmap_special", + "id": "Strangle Temple", + "overmaps": [ ], + "occurrences": [ 0, 0 ] + }, + { + "type": "overmap_special", + "id": "evac_center", + "overmaps": [ ], + "occurrences": [ 0, 0 ] + }, + { + "type": "overmap_special", + "id": "hub_01", + "overmaps": [ ], + "occurrences": [ 0, 0 ] + }, + { + "type": "overmap_special", + "id": "Hazardous Waste Sarcophagus", + "overmaps": [ ], + "occurrences": [ 0, 0 ] + }, + { + "type": "overmap_special", + "id": "Isherwood Farms", + "overmaps": [ ], + "occurrences": [ 0, 0 ] + }, + { + "//": "sorry Mr. Lapin ;w;. temporary until I work on NPCs", + "type": "overmap_special", + "id": "Cabin_Lapin", + "overmaps": [ ], + "occurrences": [ 0, 0 ] + }, + { + "type": "overmap_special", + "id": "Strange Cabin", + "overmaps": [ ], + "occurrences": [ 0, 0 ] + }, + { + "//": "there will be 'FEMA camps' in the future, but almost even more sinister", + "type": "overmap_special", + "id": "FEMA Camp", + "overmaps": [ ], + "occurrences": [ 0, 0 ] + }, + { + "type": "overmap_special", + "id": "FEMA_camp", + "overmaps": [ ], + "occurrences": [ 0, 0 ] + }, + { + "type": "overmap_special", + "id": "lab_surface_big", + "overmaps": [ ], + "occurrences": [ 0, 0 ] + }, + { + "type": "overmap_special", + "id": "Mass Grave", + "overmaps": [ ], + "occurrences": [ 0, 0 ] + }, + { + "type": "overmap_special", + "id": "Mine Entrance", + "overmaps": [ ], + "occurrences": [ 0, 0 ] + } +] diff --git a/data/mods/aftershock_exoplanet/setting_blacklists/mon_blacklist.json b/data/mods/aftershock_exoplanet/setting_blacklists/mon_blacklist.json new file mode 100644 index 0000000000000..9779163f0ecd7 --- /dev/null +++ b/data/mods/aftershock_exoplanet/setting_blacklists/mon_blacklist.json @@ -0,0 +1,9 @@ +[ + { + "//": "edited from no_wildlife", + "type": "MONSTER_WHITELIST", + "mode": "EXCLUSIVE", + "categories": [ "WILDLIFE", "MUTANT" ], + "species": [ "MOXIE", "ROBOT" ] + } +] diff --git a/data/mods/aftershock_exoplanet/setting_blacklists/scenario_blacklist.json b/data/mods/aftershock_exoplanet/setting_blacklists/scenario_blacklist.json new file mode 100644 index 0000000000000..b1ffc6dd09a24 --- /dev/null +++ b/data/mods/aftershock_exoplanet/setting_blacklists/scenario_blacklist.json @@ -0,0 +1,7 @@ +[ + { + "type": "SCENARIO_BLACKLIST", + "subtype": "whitelist", + "scenarios": [ "escape_pod" ] + } +] diff --git a/data/mods/aftershock_exoplanet/weather_type.json b/data/mods/aftershock_exoplanet/weather_type.json new file mode 100644 index 0000000000000..113a3eee20750 --- /dev/null +++ b/data/mods/aftershock_exoplanet/weather_type.json @@ -0,0 +1,130 @@ +[ + { + "id": "afs_flurries", + "type": "weather_type", + "name": "Flurries", + "color": "white", + "map_color": "h_white", + "sym": ".", + "ranged_penalty": 1, + "sight_penalty": 1.03, + "light_modifier": -20, + "sound_attn": 1, + "dangerous": false, + "precip": "light", + "rains": true, + "acidic": false, + "tiles_animation": "weather_snow_drop", + "weather_animation": { "factor": 0.01, "color": "white", "sym": "." }, + "sound_category": "drizzle", + "sun_intensity": "light", + "requirements": { "pressure_max": 1000, "humidity_min": 97, "humidity_and_pressure": false, "required_weathers": [ "cloudy" ] } + }, + { + "id": "afs_whiteout", + "type": "weather_type", + "name": "Whiteout", + "color": "i_black", + "map_color": "i_black", + "sym": "o", + "ranged_penalty": 1, + "sight_penalty": 1.03, + "light_modifier": -40, + "sound_attn": 1, + "dangerous": false, + "precip": "light", + "rains": false, + "acidic": false, + "tiles_animation": "weather_snow_drop", + "weather_animation": { "factor": 0.01, "color": "white", "sym": "*" }, + "sound_category": "drizzle", + "sun_intensity": "light", + "requirements": { "time": "day", "windpower_min": 20, "humidity_min": 97, "required_weathers": [ "cloudy", "afs_flurries" ] } + }, + { + "id": "afs_snowing", + "type": "weather_type", + "name": "Snowing", + "color": "blue", + "map_color": "h_blue", + "sym": "o", + "ranged_penalty": 3, + "sight_penalty": 1.1, + "light_modifier": -30, + "sound_attn": 4, + "dangerous": false, + "precip": "heavy", + "rains": true, + "acidic": false, + "tiles_animation": "weather_snow_drop", + "weather_animation": { "factor": 0.02, "color": "white", "sym": "*" }, + "sound_category": "rainy", + "sun_intensity": "light", + "requirements": { "pressure_max": 993, "humidity_min": 98, "humidity_and_pressure": false, "required_weathers": [ "afs_flurries", "afs_whiteout" ] } + }, + { + "id": "afs_thunder", + "type": "weather_type", + "name": "Thunder Storm", + "color": "dark_gray", + "map_color": "i_blue", + "sym": "%", + "ranged_penalty": 4, + "sight_penalty": 1.2, + "light_modifier": -40, + "sound_attn": 8, + "dangerous": false, + "precip": "heavy", + "rains": true, + "acidic": false, + "effects": [ + { + "one_in_chance": 50, + "must_be_outside": false, + "sound_message": "You hear a distant rumble of thunder.", + "sound_effect": "thunder_far" + } + ], + "tiles_animation": "weather_snow_drop", + "weather_animation": { "factor": 0.02, "color": "white", "sym": "*" }, + "sound_category": "thunder", + "sun_intensity": "none", + "requirements": { "pressure_max": 950, "required_weathers": [ "afs_snowing" ] } + }, + { + "id": "afs_lightning", + "type": "weather_type", + "name": "Lightning Storm", + "color": "yellow", + "map_color": "h_yellow", + "sym": "%", + "ranged_penalty": 4, + "sight_penalty": 1.25, + "light_modifier": -45, + "sound_attn": 8, + "dangerous": false, + "precip": "heavy", + "rains": true, + "acidic": false, + "effects": [ + { + "one_in_chance": 50, + "must_be_outside": false, + "sound_message": "You hear a distant rumble of thunder.", + "sound_effect": "thunder_far" + }, + { + "one_in_chance": 600, + "must_be_outside": false, + "message": "A flash of lightning illuminates your surroundings!", + "sound_effect": "thunder_near", + "lightning": true + } + ], + "tiles_animation": "weather_snow_drop", + "weather_animation": { "factor": 0.04, "color": "white", "sym": "*" }, + "sound_category": "thunder", + "sun_intensity": "none", + "requirements": { "pressure_max": 940, "required_weathers": [ "afs_thunder" ] } + } +] From 238f040dd004dd715666918c0580a1f8c09ea1c7 Mon Sep 17 00:00:00 2001 From: ToxiClay Date: Fri, 28 May 2021 06:24:18 -0400 Subject: [PATCH 434/453] Adding lard to hallula recipe (#48728) --- data/json/recipes/food/bread.json | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/data/json/recipes/food/bread.json b/data/json/recipes/food/bread.json index d8ae2930a9b1a..d1c8b5256bd79 100644 --- a/data/json/recipes/food/bread.json +++ b/data/json/recipes/food/bread.json @@ -71,7 +71,7 @@ [ [ "sugar", 1 ] ], [ [ "salt", 1 ] ], [ [ "water", 1 ] ], - [ [ "any_butter_or_oil", 2, "LIST" ] ] + [ [ "any_butter_or_oil", 2, "LIST" ], [ "edible_lard", 1, "LIST" ] ] ], "//": "I'm not sure whether this should also be rewritten to use a portion of charges, or scaled up so that the smallest component in the recipe becomes a single charge.", "//2": "Since milk is only used sparingly in the creation of hallula, to give it a glazed appearance, Cataclysm practicality suggests omitting it." From 7c432ac4db4289f5171fbacdfa55f50e9af90ef4 Mon Sep 17 00:00:00 2001 From: Venera3 <72006894+Venera3@users.noreply.github.com> Date: Fri, 28 May 2021 12:26:47 +0200 Subject: [PATCH 435/453] Redesigning Arthropods Part 3: Wasps! (#47960) --- data/json/harvest.json | 45 ++- data/json/items/comestibles/egg.json | 30 +- data/json/mapgen/map_extras/nest_wasp.json | 8 +- .../monster_attacks.json | 16 ++ data/json/monstergroups/bugs.json | 164 ++++++++++- data/json/monstergroups/eggs.json | 6 + data/json/monstergroups/misc.json | 4 +- data/json/monstergroups/obsolete.json | 9 + data/json/monstergroups/wilderness.json | 149 ++++------ data/json/monsters/insect_spider.json | 271 ++++++++++++++---- .../overmap_terrain_agricultural.json | 5 + .../overmap_terrain_commercial.json | 4 + .../overmap_terrain_industrial.json | 2 + data/json/regional_map_settings.json | 4 +- .../json/requirements/cooking_components.json | 3 +- data/json/snippets/mutant_anatomy.json | 64 ++++- data/json/snippets/snippets.json | 5 + data/json/species.json | 2 +- src/map_extras.cpp | 12 +- 19 files changed, 595 insertions(+), 208 deletions(-) diff --git a/data/json/harvest.json b/data/json/harvest.json index 0c04a110e268a..ec4704e512648 100644 --- a/data/json/harvest.json +++ b/data/json/harvest.json @@ -998,14 +998,14 @@ "type": "harvest", "message": "", "entries": [ - { "drop": "mutant_meat", "type": "flesh", "mass_ratio": 0.1 }, + { "drop": "mutant_meat", "type": "flesh", "mass_ratio": 0.3 }, { "drop": "mutant_blood", "type": "blood", "mass_ratio": 0.1 }, - { "drop": "sinew", "type": "bone", "mass_ratio": 0.01 }, + { "drop": "sinew", "type": "bone", "mass_ratio": 0.003 }, { "drop": "endochitin", "type": "bone", "mass_ratio": 0.01 }, - { "drop": "mutant_bug_hydrogen_sacs", "type": "flesh", "mass_ratio": 0.2 }, - { "drop": "mutant_bug_lungs", "type": "flesh", "mass_ratio": 0.0035 }, - { "drop": "mutant_bug_organs", "type": "offal", "mass_ratio": 0.015 }, - { "drop": "chitin_piece", "type": "bone", "mass_ratio": 0.01 } + { "drop": "mutant_bug_hydrogen_sacs", "type": "flesh", "mass_ratio": 0.1 }, + { "drop": "mutant_bug_lungs", "type": "flesh", "mass_ratio": 0.01 }, + { "drop": "mutant_bug_organs", "type": "offal", "mass_ratio": 0.03 }, + { "drop": "chitin_piece", "type": "bone", "mass_ratio": 0.1 } ] }, { @@ -1073,17 +1073,36 @@ { "id": "arachnid_wasp", "type": "harvest", - "message": "There's a faintly hairy, skin-like membrane, covered in blood vessels, beneath the chitin of this creature. Inside it is a bundle of bubble-like tissue sacs that appear to be floating, which doesn't fit with what you know about pre-Cataclysm wasps.", + "message": "", "entries": [ - { "drop": "mutant_meat", "type": "flesh", "mass_ratio": 0.33 }, - { "drop": "sinew", "type": "bone", "mass_ratio": 0.01 }, - { "drop": "endochitin", "type": "bone", "mass_ratio": 0.1 }, + { "drop": "mutant_meat", "type": "flesh", "mass_ratio": 0.3 }, + { "drop": "mutant_blood", "type": "blood", "mass_ratio": 0.1 }, + { "drop": "sinew", "type": "bone", "mass_ratio": 0.003 }, + { "drop": "endochitin", "type": "bone", "mass_ratio": 0.01 }, { "drop": "mutant_bug_hydrogen_sacs", "type": "flesh", "mass_ratio": 0.1 }, - { "drop": "mutant_bug_lungs", "type": "flesh", "mass_ratio": 0.0035 }, - { "drop": "mutant_bug_organs", "type": "offal", "mass_ratio": 0.015 }, + { "drop": "mutant_bug_lungs", "type": "flesh", "mass_ratio": 0.01 }, + { "drop": "mutant_bug_organs", "type": "offal", "mass_ratio": 0.03 }, + { "drop": "wasp_sting", "base_num": [ 0, 1 ], "type": "bone" }, + { "drop": "chitin_piece", "type": "bone", "mass_ratio": 0.1 }, + { "drop": "venom_wasp", "type": "offal", "base_num": [ 0, 3 ], "scale_num": [ 0, 2 ] } + ] + }, + { + "id": "arachnid_wasp_queen", + "type": "harvest", + "message": "", + "entries": [ + { "drop": "mutant_meat", "type": "flesh", "mass_ratio": 0.2 }, + { "drop": "mutant_blood", "type": "blood", "mass_ratio": 0.1 }, + { "drop": "sinew", "type": "bone", "mass_ratio": 0.003 }, + { "drop": "endochitin", "type": "bone", "mass_ratio": 0.01 }, + { "drop": "mutant_bug_hydrogen_sacs", "type": "flesh", "mass_ratio": 0.1 }, + { "drop": "mutant_bug_lungs", "type": "flesh", "mass_ratio": 0.01 }, + { "drop": "mutant_bug_organs", "type": "offal", "mass_ratio": 0.03 }, { "drop": "wasp_sting", "base_num": [ 0, 1 ], "type": "bone" }, { "drop": "chitin_piece", "type": "bone", "mass_ratio": 0.1 }, - { "drop": "venom_wasp", "type": "offal", "mass_ratio": 0.005 } + { "drop": "egg_wasp", "type": "offal", "base_num": [ 10, 30 ], "scale_num": [ 5, 5 ] }, + { "drop": "venom_wasp", "type": "offal", "base_num": [ 5, 25 ], "scale_num": [ 5, 2 ] } ] }, { diff --git a/data/json/items/comestibles/egg.json b/data/json/items/comestibles/egg.json index d06956948c024..6780c71206c90 100644 --- a/data/json/items/comestibles/egg.json +++ b/data/json/items/comestibles/egg.json @@ -129,7 +129,7 @@ "comestible_type": "FOOD", "name": { "str": "Insect Egg" }, "abstract": "egg_insect", - "//": "5x the weight and 3x the nutrition of real chicken eggs, toxins equal 296g mutant meat", + "//": "5x the weight and 3x the nutrition of real chicken eggs, toxins equal to 296g mutant meat", "color": "white", "symbol": "%", "material": [ "egg" ], @@ -141,6 +141,7 @@ "fun": -20, "price": 0, "price_postapoc": 100, + "spoils_in": "5 days", "flags": [ "FREEZERBURN", "RAW" ], "vitamins": [ [ "vitA", 19 ], [ "calcium", 7 ], [ "iron", 18 ], [ "vitB", 66 ], [ "mutant_toxin", 25 ] ] }, @@ -149,15 +150,12 @@ "id": "ant_egg", "name": { "str": "ant egg" }, "copy-from": "egg_insect", - "color": "white", - "symbol": "%", "description": "A large, heavy ant egg, the size of a softball. Extremely nutritious, but incredibly gross.", "price": 175, "price_postapoc": 500, "material": [ "egg" ], - "volume": "600 ml", - "proportional": { "weight": 3, "calories": 3 }, - "vitamins": [ [ "vitA", 108 ], [ "calcium", 36 ], [ "iron", 48 ], [ "vitB", 252 ] ], + "proportional": { "weight": 4, "calories": 4, "volume": 4 }, + "vitamins": [ [ "vitA", 76 ], [ "calcium", 28 ], [ "iron", 72 ], [ "vitB", 264 ], [ "mutant_toxin", 100 ] ], "rot_spawn": "GROUP_EGG_ANT", "rot_spawn_chance": 60 }, @@ -213,7 +211,6 @@ "copy-from": "egg_insect", "color": "light_green", "symbol": "o", - "spoils_in": "2 days", "rot_spawn": "GROUP_EGG_DRAGONFLY", "rot_spawn_chance": 50 }, @@ -224,7 +221,6 @@ "copy-from": "egg_insect", "color": "yellow", "symbol": "o", - "spoils_in": "1 day", "description": "The fist-sized egg of a mutant firefly. Glows faintly in the dark.", "rot_spawn": "GROUP_EGG_FIREFLY", "rot_spawn_chance": 100 @@ -233,14 +229,26 @@ "type": "COMESTIBLE", "id": "egg_centipede", "name": { "str": "centipede egg" }, + "description": "A large, soft egg you got from butchering a mutant centipede. Inside, you can already see a bundle of spindly legs, twitching in anticipation.", "copy-from": "egg_insect", "color": "light_green", - "symbol": "o", - "spoils_in": "10 days", - "description": "A large, soft egg you got from butchering a mutant centipede. Inside, you can already see a bundle of spindly legs, twitching in anticipation.", + "proportional": { "weight": 2, "calories": 2, "volume": 2 }, + "vitamins": [ [ "vitA", 38 ], [ "calcium", 14 ], [ "iron", 36 ], [ "vitB", 132 ], [ "mutant_toxin", 50 ] ], "rot_spawn": "GROUP_EGG_CENTIPEDE", "rot_spawn_chance": 50 }, + { + "type": "COMESTIBLE", + "id": "egg_wasp", + "name": { "str": "wasp egg" }, + "copy-from": "egg_insect", + "color": "white", + "symbol": "o", + "spoils_in": "2 days", + "description": "A white, flexible wasp egg. It looks like a pristine grain of rice, grown to the size of your palm.", + "rot_spawn": "GROUP_EGG_WASP", + "rot_spawn_chance": 100 + }, { "type": "COMESTIBLE", "id": "razorclaw_roe", diff --git a/data/json/mapgen/map_extras/nest_wasp.json b/data/json/mapgen/map_extras/nest_wasp.json index f3ffb4b03f4f6..54155a869bc06 100644 --- a/data/json/mapgen/map_extras/nest_wasp.json +++ b/data/json/mapgen/map_extras/nest_wasp.json @@ -17,7 +17,7 @@ " ---.---.,---.- ", " t-.--.,--...-.-- ", " --...-.--.--. ", - " -..-,-..-,-..-t t ", + " -..-,-.8-,-..-t t ", " t --....-.-..--- ", " t---.,.-.---..- ", " -.---.---..--- ", @@ -34,9 +34,11 @@ "t": [ "t_region_tree", "t_region_groundcover_swamp" ], ",": [ "t_region_tree" ], "-": [ "t_paper" ], - ".": [ "t_floor_paper" ] + ".": [ "t_floor_paper" ], + "8": [ "t_floor_paper" ] }, - "place_monsters": [ { "monster": "GROUP_WASP", "x": [ 0, 23 ], "y": [ 0, 23 ], "repeat": [ 0, 3 ], "density": 0.1 } ] + "monster": { "8": { "group": "GROUP_WASP_QUEEN" } }, + "place_monster": [ { "group": "GROUP_WASP_NEST", "x": [ 0, 23 ], "y": [ 0, 23 ], "repeat": [ 5, 15 ] } ] } } ] diff --git a/data/json/monster_special_attacks/monster_attacks.json b/data/json/monster_special_attacks/monster_attacks.json index e905c34d74979..567c4a8ffd608 100644 --- a/data/json/monster_special_attacks/monster_attacks.json +++ b/data/json/monster_special_attacks/monster_attacks.json @@ -65,6 +65,22 @@ "no_dmg_msg_u": "The %1$s tries to slam into you, but stumbles aside.", "no_dmg_msg_npc": "The %1$s tries to slam into , but fails to." }, + { + "type": "monster_attack", + "attack_type": "melee", + "id": "sting", + "cooldown": 20, + "move_cost": 260, + "damage_max_instance": [ { "damage_type": "stab", "amount": 10 } ], + "body_parts": [ [ "leg_l", 2 ], [ "leg_r", 2 ], [ "head", 1 ], [ "arm_l", 2 ], [ "arm_r", 2 ], [ "torso", 3 ] ], + "effects": [ { "id": "venom_weaken", "duration": 400, "chance": 50 } ], + "hit_dmg_u": "The %1$s stings your %2$s!", + "hit_dmg_npc": "The %1$s stings 's %2$s!", + "miss_msg_u": "The %1$s tries to sting you, but you dodge!", + "miss_msg_npc": "The %1$s tries to sting , but they dodge!", + "no_dmg_msg_u": "The %1$s tries to sting your %2$s, but it fails to penetrate your armor.", + "no_dmg_msg_npc": "The %1$s tries to sting 's %2$s, but it fails to penetrate their armor." + }, { "id": "acid_spray", "type": "GUN", diff --git a/data/json/monstergroups/bugs.json b/data/json/monstergroups/bugs.json index b679a8772e566..8b1225781b6f5 100644 --- a/data/json/monstergroups/bugs.json +++ b/data/json/monstergroups/bugs.json @@ -60,18 +60,170 @@ "monsters": [ ] }, { - "name": "GROUP_WASP", + "name": "GROUP_WASP_NEST", "type": "monstergroup", - "default": "mon_wasp_small", - "monsters": [ { "monster": "mon_wasp_small", "freq": 100, "cost_multiplier": 1, "conditions": [ "SPRING", "SUMMER", "AUTUMN" ] } ] + "default": "mon_null", + "monsters": [ + { + "monster": "mon_wasp_small", + "freq": 500, + "cost_multiplier": 1, + "ends": 180, + "conditions": [ "SPRING", "SUMMER", "AUTUMN" ] + }, + { + "monster": "mon_wasp_small", + "freq": 500, + "cost_multiplier": 1, + "starts": 180, + "ends": 540, + "pack_size": [ 2, 4 ], + "conditions": [ "SPRING", "SUMMER", "AUTUMN" ] + }, + { + "monster": "mon_wasp_small_guard", + "freq": 500, + "cost_multiplier": 1, + "ends": 180, + "conditions": [ "SPRING", "SUMMER", "AUTUMN" ] + }, + { + "monster": "mon_wasp_small_guard", + "freq": 500, + "cost_multiplier": 1, + "starts": 180, + "ends": 540, + "pack_size": [ 2, 4 ], + "conditions": [ "SPRING", "SUMMER", "AUTUMN" ] + }, + { + "monster": "mon_wasp", + "freq": 500, + "cost_multiplier": 1, + "starts": 180, + "ends": 540, + "conditions": [ "SPRING", "SUMMER", "AUTUMN" ] + }, + { + "monster": "mon_wasp", + "freq": 500, + "cost_multiplier": 1, + "starts": 540, + "pack_size": [ 2, 4 ], + "conditions": [ "SPRING", "SUMMER", "AUTUMN" ] + }, + { + "monster": "mon_wasp_guard", + "freq": 500, + "cost_multiplier": 1, + "starts": 180, + "ends": 540, + "conditions": [ "SPRING", "SUMMER", "AUTUMN" ] + }, + { + "monster": "mon_wasp_guard", + "freq": 500, + "cost_multiplier": 1, + "starts": 540, + "pack_size": [ 2, 4 ], + "conditions": [ "SPRING", "SUMMER", "AUTUMN" ] + } + ] + }, + { + "name": "GROUP_WASP_FORAGER", + "type": "monstergroup", + "default": "mon_null", + "monsters": [ + { + "monster": "mon_wasp_small", + "freq": 1000, + "cost_multiplier": 1, + "ends": 180, + "conditions": [ "SPRING", "SUMMER", "AUTUMN" ] + }, + { + "monster": "mon_wasp_small", + "freq": 500, + "cost_multiplier": 1, + "starts": 180, + "ends": 540, + "pack_size": [ 2, 4 ], + "conditions": [ "SPRING", "SUMMER", "AUTUMN" ] + }, + { + "monster": "mon_wasp", + "freq": 1000, + "cost_multiplier": 1, + "starts": 360, + "ends": 720, + "conditions": [ "SPRING", "SUMMER", "AUTUMN" ] + }, + { + "monster": "mon_wasp", + "freq": 1000, + "cost_multiplier": 1, + "starts": 720, + "pack_size": [ 2, 4 ], + "conditions": [ "SPRING", "SUMMER", "AUTUMN" ] + } + ] + }, + { + "name": "GROUP_WASP_GUARD", + "type": "monstergroup", + "default": "mon_null", + "monsters": [ + { + "monster": "mon_wasp_small_guard", + "freq": 1000, + "cost_multiplier": 1, + "ends": 180, + "conditions": [ "SPRING", "SUMMER", "AUTUMN" ] + }, + { + "monster": "mon_wasp_small_guard", + "freq": 500, + "cost_multiplier": 1, + "starts": 180, + "ends": 540, + "pack_size": [ 2, 4 ], + "conditions": [ "SPRING", "SUMMER", "AUTUMN" ] + }, + { + "monster": "mon_wasp_guard", + "freq": 500, + "cost_multiplier": 1, + "starts": 180, + "ends": 540, + "conditions": [ "SPRING", "SUMMER", "AUTUMN" ] + }, + { + "monster": "mon_wasp_guard", + "freq": 500, + "cost_multiplier": 1, + "starts": 540, + "pack_size": [ 2, 4 ], + "conditions": [ "SPRING", "SUMMER", "AUTUMN" ] + } + ] + }, + { + "name": "GROUP_WASP_QUEEN", + "type": "monstergroup", + "default": "mon_null", + "monsters": [ + { "monster": "mon_wasp_queen", "freq": 1000, "cost_multiplier": 50, "ends": 720 }, + { "monster": "mon_wasp_mega", "freq": 1000, "cost_multiplier": 50, "starts": 360 } + ] }, { - "name": "WASP_UPGRADE", + "name": "GROUP_WASP_PUPA", "type": "monstergroup", "default": "mon_wasp", "monsters": [ - { "monster": "mon_wasp", "freq": 200, "cost_multiplier": 1 }, - { "monster": "mon_dermatik", "freq": 100, "cost_multiplier": 1 } + { "monster": "mon_dermatik", "freq": 50, "cost_multiplier": 1 }, + { "monster": "mon_wasp_guard", "freq": 500, "cost_multiplier": 1 } ] }, { diff --git a/data/json/monstergroups/eggs.json b/data/json/monstergroups/eggs.json index 6a0e75b2774e3..e24ac955d81de 100644 --- a/data/json/monstergroups/eggs.json +++ b/data/json/monstergroups/eggs.json @@ -103,6 +103,12 @@ "default": "mon_centipede_small", "monsters": [ { "monster": "mon_centipede_small", "freq": 1000, "cost_multiplier": 1 } ] }, + { + "name": "GROUP_EGG_WASP", + "type": "monstergroup", + "default": "mon_wasp_larva", + "monsters": [ { "monster": "mon_wasp_larva", "freq": 1000, "cost_multiplier": 1, "conditions": [ "SPRING", "SUMMER", "AUTUMN" ] } ] + }, { "name": "GROUP_EGG_DRAGONFLY", "type": "monstergroup", diff --git a/data/json/monstergroups/misc.json b/data/json/monstergroups/misc.json index f7dcb784e3f2c..1bd7a3f098902 100644 --- a/data/json/monstergroups/misc.json +++ b/data/json/monstergroups/misc.json @@ -132,7 +132,7 @@ { "monster": "mon_rattlesnake", "freq": 10, "cost_multiplier": 1 }, { "monster": "mon_rattlesnake_giant", "freq": 5, "cost_multiplier": 2 }, { "monster": "mon_worm", "freq": 20, "cost_multiplier": 1 }, - { "monster": "mon_wasp", "freq": 10, "cost_multiplier": 1 } + { "monster": "mon_wasp_small", "freq": 10, "cost_multiplier": 1 } ] }, { @@ -151,7 +151,7 @@ { "monster": "mon_spider_widow_giant", "freq": 30, "cost_multiplier": 1, "pack_size": [ 2, 4 ] }, { "monster": "mon_giant_cockroach", "freq": 50, "cost_multiplier": 1, "pack_size": [ 3, 6 ] }, { "monster": "mon_black_rat", "freq": 30, "cost_multiplier": 1, "pack_size": [ 4, 8 ] }, - { "monster": "mon_wasp", "freq": 50, "cost_multiplier": 1, "pack_size": [ 3, 6 ] }, + { "monster": "mon_wasp_small", "freq": 50, "cost_multiplier": 1, "pack_size": [ 2, 4 ] }, { "monster": "mon_zombie_child", "freq": 20, "cost_multiplier": 1, "pack_size": [ 2, 6 ] }, { "monster": "mon_zombie", "freq": 20, "cost_multiplier": 1, "pack_size": [ 2, 6 ] }, { "monster": "mon_zombie_rot", "freq": 10, "cost_multiplier": 1, "pack_size": [ 1, 5 ] }, diff --git a/data/json/monstergroups/obsolete.json b/data/json/monstergroups/obsolete.json index d559e82543a62..d389e490c2fe5 100644 --- a/data/json/monstergroups/obsolete.json +++ b/data/json/monstergroups/obsolete.json @@ -60,5 +60,14 @@ "type": "monstergroup", "default": "mon_null", "monsters": [ { "monster": "mon_zombie_spitter", "freq": 65, "cost_multiplier": 5 } ] + }, + { + "name": "WASP_UPGRADE", + "type": "monstergroup", + "default": "mon_wasp", + "monsters": [ + { "monster": "mon_wasp", "freq": 200, "cost_multiplier": 1 }, + { "monster": "mon_dermatik", "freq": 100, "cost_multiplier": 1 } + ] } ] diff --git a/data/json/monstergroups/wilderness.json b/data/json/monstergroups/wilderness.json index f8e86a648656c..77b8b0009adc0 100644 --- a/data/json/monstergroups/wilderness.json +++ b/data/json/monstergroups/wilderness.json @@ -1731,114 +1731,52 @@ { "monster": "mon_zpider_mass", "freq": 1, "cost_multiplier": 10, "starts": 2160 }, { "monster": "mon_wasp_small", - "freq": 3, - "cost_multiplier": 0, - "conditions": [ "DAY", "SPRING", "SUMMER", "AUTUMN" ] - }, - { - "monster": "mon_wasp_small", - "freq": 2, - "cost_multiplier": 0, - "starts": 24, - "conditions": [ "DAY", "SPRING", "SUMMER", "AUTUMN" ] - }, - { - "monster": "mon_wasp_small", - "freq": 3, - "cost_multiplier": 0, - "starts": 72, - "conditions": [ "DAY", "SPRING", "SUMMER", "AUTUMN" ] - }, - { - "monster": "mon_wasp_small", - "freq": 2, - "cost_multiplier": 0, - "starts": 120, - "conditions": [ "DAY", "SPRING", "SUMMER", "AUTUMN" ] + "freq": 20, + "cost_multiplier": 2, + "conditions": [ "SPRING", "SUMMER", "AUTUMN" ], + "ends": 168 }, { "monster": "mon_wasp_small", - "freq": 3, - "cost_multiplier": 0, + "freq": 25, + "cost_multiplier": 2, "starts": 168, - "conditions": [ "DAY", "SPRING", "SUMMER", "AUTUMN" ] - }, - { - "monster": "mon_wasp_small", - "freq": 2, - "cost_multiplier": 0, - "starts": 216, - "conditions": [ "DAY", "SPRING", "SUMMER", "AUTUMN" ] - }, - { - "monster": "mon_wasp_small", - "freq": 3, - "cost_multiplier": 0, - "starts": 288, - "conditions": [ "DAY", "SPRING", "SUMMER", "AUTUMN" ] + "ends": 336, + "conditions": [ "SPRING", "SUMMER", "AUTUMN" ] }, { "monster": "mon_wasp_small", - "freq": 2, - "cost_multiplier": 0, + "freq": 25, + "cost_multiplier": 2, + "pack_size": [ 1, 2 ], "starts": 336, - "conditions": [ "DAY", "SPRING", "SUMMER", "AUTUMN" ] - }, - { - "monster": "mon_wasp_small", - "freq": 3, - "cost_multiplier": 0, - "starts": 384, - "conditions": [ "DAY", "SPRING", "SUMMER", "AUTUMN" ] - }, - { - "monster": "mon_wasp_small", - "freq": 2, - "cost_multiplier": 0, - "starts": 456, - "conditions": [ "DAY", "SPRING", "SUMMER", "AUTUMN" ] - }, - { - "monster": "mon_wasp_small", - "freq": 3, - "cost_multiplier": 0, - "starts": 504, - "conditions": [ "DAY", "SPRING", "SUMMER", "AUTUMN" ] - }, - { - "monster": "mon_wasp_small", - "freq": 2, - "cost_multiplier": 0, - "starts": 552, - "conditions": [ "DAY", "SPRING", "SUMMER", "AUTUMN" ] - }, - { - "monster": "mon_wasp_small", - "freq": 3, - "cost_multiplier": 0, - "starts": 624, - "conditions": [ "DAY", "SPRING", "SUMMER", "AUTUMN" ] + "ends": 720, + "conditions": [ "SPRING", "SUMMER", "AUTUMN" ] }, { - "monster": "mon_wasp_small", - "freq": 2, - "cost_multiplier": 0, - "starts": 672, - "conditions": [ "DAY", "SPRING", "SUMMER", "AUTUMN" ] + "monster": "mon_wasp", + "freq": 30, + "cost_multiplier": 2, + "starts": 720, + "ends": 1440, + "conditions": [ "SPRING", "SUMMER", "AUTUMN" ] }, { - "monster": "mon_wasp_small", - "freq": 3, - "cost_multiplier": 0, - "starts": 720, - "conditions": [ "DAY", "SPRING", "SUMMER", "AUTUMN" ] + "monster": "mon_wasp", + "freq": 30, + "cost_multiplier": 2, + "pack_size": [ 1, 2 ], + "starts": 1440, + "ends": 2160, + "conditions": [ "SPRING", "SUMMER", "AUTUMN" ] }, { - "monster": "mon_wasp_small", - "freq": 2, - "cost_multiplier": 0, - "starts": 792, - "conditions": [ "DAY", "SPRING", "SUMMER", "AUTUMN" ] + "monster": "mon_wasp", + "freq": 30, + "cost_multiplier": 2, + "pack_size": [ 1, 3 ], + "starts": 2160, + "conditions": [ "SPRING", "SUMMER", "AUTUMN" ] }, { "monster": "mon_worm_small", "freq": 1, "cost_multiplier": 0, "conditions": [ "SPRING", "SUMMER", "AUTUMN" ] }, { @@ -2664,9 +2602,18 @@ "monster": "mon_wasp_small", "freq": 25, "cost_multiplier": 2, - "pack_size": [ 1, 3 ], - "starts": 84, - "ends": 180, + "pack_size": [ 1, 2 ], + "starts": 336, + "ends": 720, + "conditions": [ "SPRING", "SUMMER", "AUTUMN" ] + }, + { + "monster": "mon_wasp", + "freq": 30, + "cost_multiplier": 2, + "pack_size": [ 1, 2 ], + "starts": 720, + "ends": 1440, "conditions": [ "SPRING", "SUMMER", "AUTUMN" ] }, { @@ -2674,16 +2621,16 @@ "freq": 30, "cost_multiplier": 2, "pack_size": [ 1, 3 ], - "starts": 180, - "ends": 360, + "starts": 1440, + "ends": 2160, "conditions": [ "SPRING", "SUMMER", "AUTUMN" ] }, { "monster": "mon_wasp", "freq": 30, "cost_multiplier": 2, - "pack_size": [ 2, 4 ], - "starts": 360, + "pack_size": [ 2, 5 ], + "starts": 2160, "conditions": [ "SPRING", "SUMMER", "AUTUMN" ] }, { diff --git a/data/json/monsters/insect_spider.json b/data/json/monsters/insect_spider.json index e8ae956ea583e..8a21bad7e797f 100644 --- a/data/json/monsters/insect_spider.json +++ b/data/json/monsters/insect_spider.json @@ -380,9 +380,10 @@ "vision_night": 5, "harvest": "arachnid_bee", "anger_triggers": [ "HURT", "FRIEND_DIED", "PLAYER_CLOSE" ], + "fear_triggers": [ "FIRE" ], "death_function": [ "NORMAL" ], "upgrades": { "half_life": 21, "into": "mon_bee_mega" }, - "flags": [ "SEES", "SMELLS", "FLIES", "STUMBLES", "SWARMS", "GROUP_MORALE", "CANPLAY", "PATH_AVOID_FIRE", "LOUDMOVES" ] + "flags": [ "SEES", "SMELLS", "FLIES", "STUMBLES", "SWARMS", "GROUP_MORALE", "CANPLAY", "PATH_AVOID_FIRE" ] }, { "id": "mon_bee_mega", @@ -474,9 +475,9 @@ "//": "10-20 dmg, 4 hits to max intensity, 5 hits to max duration", "dodge": 2, "armor_bash": 10, - "armor_cut": 15, - "armor_bullet": 8, - "armor_stab": 10, + "armor_cut": 25, + "armor_bullet": 12, + "armor_stab": 14, "vision_day": 9, "vision_night": 6, "anger_triggers": [ "STALK", "PLAYER_CLOSE" ], @@ -604,7 +605,7 @@ "fear_triggers": [ "HURT" ], "death_function": [ "NORMAL" ], "flags": [ "AQUATIC", "SEES" ], - "upgrades": { "age_grow": 24, "into": "mon_dragonfly_giant" } + "upgrades": { "age_grow": 21, "into": "mon_dragonfly_giant" } }, { "id": "mon_dragonfly_giant", @@ -618,6 +619,7 @@ "weight": "40750 g", "hp": 50, "speed": 150, + "attack_cost": 150, "material": [ "iflesh" ], "symbol": "y", "color": "light_green", @@ -634,7 +636,9 @@ "cooldown": 6, "accuracy": 5, "move_cost": 300, - "damage_max_instance": [ { "damage_type": "cut", "amount": 6, "armor_penetration": 20 } ] + "damage_max_instance": [ { "damage_type": "cut", "amount": 6, "armor_penetration": 20 } ], + "min_mul": 1, + "max_mul": 2 } ], "dodge": 2, @@ -642,10 +646,10 @@ "vision_night": 5, "harvest": "arachnid_flying", "anger_triggers": [ "PLAYER_WEAK", "STALK" ], - "fear_triggers": [ "HURT" ], + "fear_triggers": [ "HURT", "FIRE" ], "death_function": [ "NORMAL" ], "upgrades": { "age_grow": 40, "into": "mon_dragonfly_mega" }, - "flags": [ "SWARMS", "HEARS", "SEES", "FLIES", "PATH_AVOID_FIRE", "LOUDMOVES" ] + "flags": [ "SWARMS", "HEARS", "SEES", "FLIES", "PATH_AVOID_FIRE" ] }, { "id": "mon_dragonfly_mega", @@ -690,7 +694,7 @@ "name": { "str": "firefly", "str_pl": "fireflies" }, "description": "A mutated firefly grown to the size of a large housecat, brightly glowing abdomen bobbing up and down as it tries to impress its unseen mate. It looks strangely uninterested in you and everything else.", "bodytype": "flying insect", - "species": [ "INSECT" ], + "species": [ "INSECT_FLYING" ], "default_faction": "insect", "material": [ "iflesh" ], "symbol": "y", @@ -705,7 +709,7 @@ "harvest": "arachnid_firefly", "reproduction": { "baby_egg": "egg_firefly", "baby_count": 1, "baby_timer": 15 }, "baby_flags": [ "SPRING", "SUMMER" ], - "fear_triggers": [ "HURT" ], + "fear_triggers": [ "HURT", "FIRE" ], "flags": [ "SEES", "HEARS", "FLIES", "STUMBLES" ] }, { @@ -744,10 +748,10 @@ "vision_day": 5, "vision_night": 5, "harvest": "arachnid_flying", - "fear_triggers": [ "PLAYER_CLOSE" ], + "fear_triggers": [ "PLAYER_CLOSE", "HURT", "FIRE" ], "death_function": [ "NORMAL" ], "upgrades": { "half_life": 21, "into": "mon_fly_mega" }, - "flags": [ "SEES", "SMELLS", "FLIES", "STUMBLES", "HIT_AND_RUN", "CANPLAY", "PATH_AVOID_FIRE", "LOUDMOVES" ] + "flags": [ "SEES", "SMELLS", "FLIES", "STUMBLES", "HIT_AND_RUN", "CANPLAY", "PATH_AVOID_FIRE" ] }, { "id": "mon_fly_mega", @@ -801,9 +805,10 @@ "vision_day": 5, "vision_night": 5, "harvest": "arachnid_flying", + "fear_triggers": [ "HURT", "FIRE" ], "death_function": [ "NORMAL" ], "upgrades": { "half_life": 21, "into": "mon_mosquito_mega" }, - "flags": [ "SEES", "SMELLS", "HEARS", "STUMBLES", "VENOM", "FLIES", "HIT_AND_RUN", "PATH_AVOID_FIRE", "LOUDMOVES" ] + "flags": [ "SEES", "SMELLS", "HEARS", "STUMBLES", "VENOM", "FLIES", "HIT_AND_RUN", "PATH_AVOID_FIRE" ] }, { "id": "mon_mosquito_mega", @@ -1280,89 +1285,228 @@ "special_attacks": [ [ "HOWL", 10 ] ], "extend": { "flags": [ "DESTROYS", "PUSH_MON", "PUSH_VEH" ] } }, + { + "id": "mon_wasp_larva", + "type": "MONSTER", + "name": { "str": "wasp larva", "str_pl": "wasp larvae" }, + "description": "A dog-sized white grub, featureless apart from a vestigal mouthpart. It hangs upside-down in its cell, and regurgitates sweet-smelling fluid in return for the scraps of viscera fed to it by the workers below.", + "symbol": "a", + "color": "white", + "looks_like": "mon_dermatik_larva", + "default_faction": "wasp", + "bodytype": "snake", + "material": [ "iflesh" ], + "species": [ "INSECT" ], + "volume": "30 L", + "weight": "35 kg", + "hp": 35, + "upgrades": { "age_grow": 16, "into": "mon_wasp_pupa" }, + "//": "30 days of development from egg to adult.", + "flags": [ "IMMOBILE" ] + }, + { + "id": "mon_wasp_pupa", + "type": "MONSTER", + "name": { "str": "wasp pupa", "str_pl": "wasp pupae" }, + "description": "A wasp larva undergoing metamorphosis into a full-grown giant wasp. It looks like a strangely immobile adult coated in a thin white membrane, its legs and wings packed tightly into its cell.", + "symbol": "8", + "color": "light_gray", + "default_faction": "wasp", + "bodytype": "blob", + "material": [ "iflesh" ], + "species": [ "INSECT" ], + "volume": "85 L", + "weight": "90 kg", + "hp": 100, + "upgrades": { "age_grow": 10, "into_group": "GROUP_WASP_PUPA" }, + "flags": [ "IMMOBILE" ] + }, { "id": "mon_wasp_small", "type": "MONSTER", - "name": { "str": "huge wasp" }, - "description": "A huge black and yellow mutant yellowjacket wasp the size of a ferret with a long, evil-looking stinger.", + "name": { "str": "wasp" }, + "description": "A huge wasp the size of a large cat with bright yellow markings on her jet-black carapace and a threatening stinger. It flies around erratically, searching for smaller prey.", "default_faction": "wasp", "bodytype": "flying insect", "species": [ "INSECT_FLYING" ], "diff": 2, - "volume": "750 ml", - "weight": "1 kg", + "volume": "9 L", + "weight": "9 kg", "hp": 20, - "speed": 165, + "speed": 130, + "attack_cost": 130, "material": [ "iflesh" ], "symbol": "a", "color": "dark_gray", - "aggression": 10, - "morale": 30, + "aggression": -10, "melee_skill": 5, "melee_dice": 2, - "melee_dice_sides": 4, - "melee_cut": 8, - "attack_effs": [ { "id": "venom_weaken", "duration": 100 } ], - "dodge": 4, - "armor_bash": 4, - "armor_cut": 8, - "armor_bullet": 6, - "vision_day": 10, + "melee_dice_sides": 3, + "special_attacks": [ + { + "id": "sting", + "cooldown": 8, + "min_mul": 0.3, + "max_mul": 0.5, + "effects": [ { "id": "venom_weaken", "duration": 100, "chance": 50 } ] + }, + { + "type": "bite", + "cooldown": 4, + "move_cost": 130, + "damage_max_instance": [ { "damage_type": "cut", "amount": 10 } ], + "min_mul": 0.2, + "max_mul": 0.5 + } + ], + "//": "sting 3-5 dmg, 40 hits to max intensity, 50 to max duration", + "dodge": 8, + "armor_bash": 1, + "armor_cut": 6, + "armor_stab": 4, + "vision_day": 15, "vision_night": 5, "harvest": "arachnid_wasp", - "anger_triggers": [ "HURT", "FRIEND_DIED", "PLAYER_CLOSE", "PLAYER_WEAK", "STALK" ], + "anger_triggers": [ "FRIEND_ATTACKED", "PLAYER_CLOSE", "PLAYER_WEAK", "HOSTILE_SEEN" ], + "fear_triggers": [ "HURT", "FIRE" ], "death_function": [ "NORMAL" ], - "upgrades": { "half_life": 14, "into_group": "WASP_UPGRADE" }, - "flags": [ "SEES", "SMELLS", "FLIES", "SWARMS", "GROUP_MORALE", "CANPLAY", "PATH_AVOID_FIRE" ] + "upgrades": { "half_life": 30, "into": "mon_wasp" }, + "flags": [ "SEES", "SMELLS", "HEARS", "FLIES", "SWARMS", "GROUP_MORALE", "CANPLAY", "PATH_AVOID_FIRE", "HARDTOSHOOT" ] + }, + { + "id": "mon_wasp_small_guard", + "type": "MONSTER", + "name": { "str": "wasp guard" }, + "description": "A mutated wasp worker, buzzing around their nest. While their foraging sisters are relatively content to leave you be, this one won't hesitate to attack anything it considers a threat to the nest. Don't linger.", + "copy-from": "mon_wasp_small", + "aggression": 0, + "morale": 100, + "melee_skill": 6, + "extend": { "anger_triggers": [ "HURT", "FIRE", "STALK" ] }, + "delete": { "fear_triggers": [ "HURT", "FIRE" ] }, + "upgrades": { "half_life": 30, "into": "mon_wasp_guard" } + }, + { + "id": "mon_wasp_queen", + "type": "MONSTER", + "name": { "str": "wasp queen" }, + "description": "A mutated wasp queen grown to the size of a person, laying a single white egg in each empty cell it comes across while scurrying around on the paper walls of their home. It struggles to fit into some of them, but the newer cells seem to be getting larger…", + "copy-from": "mon_wasp_guard", + "harvest": "arachnid_wasp_queen", + "reproduction": { "baby_egg": "egg_wasp", "baby_count": 2, "baby_timer": 5 }, + "upgrades": { "half_life": 30, "into": "mon_wasp_mega" } }, { "id": "mon_wasp", "type": "MONSTER", "name": { "str": "giant wasp" }, - "description": "A gigantic slender-bodied wasp with an evil-looking stinger protruding from its abdomen. Its exoskeleton glowers with ominous red markings.", + "description": "A gigantic wasp worker, scouring the landscape for an easy meal to feed the next generation. Its abdomen glowers with ominous yellow stripes and ends in a half-hidden stinger the size of a kitchen knife.", "default_faction": "wasp", "bodytype": "flying insect", "species": [ "INSECT_FLYING" ], - "diff": 2, "volume": "62500 ml", "weight": "81500 g", - "hp": 40, + "hp": 100, "speed": 150, + "attack_cost": 150, "material": [ "iflesh" ], "symbol": "a", "color": "dark_gray", - "aggression": 10, - "morale": 40, - "melee_skill": 5, + "aggression": -5, + "morale": 15, + "melee_skill": 7, "melee_dice": 2, - "melee_dice_sides": 6, - "melee_cut": 8, - "attack_effs": [ { "id": "venom_weaken", "duration": 200 } ], - "//": "15 hits to max intensity, 18 hits to max duration", - "dodge": 4, - "armor_bash": 4, - "armor_cut": 8, - "armor_bullet": 6, - "vision_day": 10, - "vision_night": 5, + "melee_dice_sides": 7, + "special_attacks": [ + { + "id": "sting", + "move_cost": 300, + "cooldown": 5, + "damage_max_instance": [ { "damage_type": "stab", "amount": 10, "armor_penetration": 25 } ], + "min_mul": 0.5, + "max_mul": 2 + }, + { + "type": "bite", + "cooldown": 5, + "move_cost": 130, + "damage_max_instance": [ { "damage_type": "cut", "amount": 10, "armor_penetration": 20 } ], + "body_parts": [ [ "leg_l", 2 ], [ "leg_r", 2 ], [ "head", 1 ], [ "arm_l", 2 ], [ "arm_r", 2 ], [ "torso", 4 ] ], + "min_mul": 0.5, + "max_mul": 1.5 + } + ], + "//": "sting 5-15 damage, 8 hits to max intensity, 9 to max duration", + "dodge": 7, + "armor_bash": 5, + "armor_cut": 14, + "armor_stab": 12, + "armor_bullet": 12, + "vision_day": 17, + "vision_night": 7, "harvest": "arachnid_wasp", - "anger_triggers": [ "HURT", "FRIEND_DIED", "PLAYER_CLOSE", "PLAYER_WEAK", "STALK" ], + "anger_triggers": [ "FRIEND_ATTACKED", "PLAYER_CLOSE", "PLAYER_WEAK", "HOSTILE_SEEN" ], + "fear_triggers": [ "HURT", "FIRE" ], "death_function": [ "NORMAL" ], - "upgrades": { "half_life": 21, "into": "mon_wasp_mega" }, - "flags": [ "SEES", "SMELLS", "FLIES", "SWARMS", "GROUP_MORALE", "CANPLAY", "PATH_AVOID_FIRE" ] + "flags": [ "SEES", "SMELLS", "HEARS", "FLIES", "SWARMS", "GROUP_MORALE", "CANPLAY", "HARDTOSHOOT", "PATH_AVOID_FIRE" ] }, { - "id": "mon_wasp_mega", + "id": "mon_wasp_guard", "type": "MONSTER", - "name": { "str": "whale wasp" }, - "description": "An enormous slender-bodied wasp with an evil-looking stinger protruding from its abdomen. Its exoskeleton glowers with ominous red markings.", + "name": { "str": "giant wasp guard" }, + "description": "A wasp worker grown to the size of a person, buzzing around their home. While their foraging sisters are relatively content to live and let live, this one won't hesitate to attack anything it considers a threat to the nest. Don't linger.", "copy-from": "mon_wasp", - "proportional": { "hp": 10, "speed": 0.25, "dodge": 0.25, "vision_day": 2 }, - "volume": "625 L", - "weight": "815 kg", - "melee_dice": 3, - "special_attacks": [ { "id": "impale" } ], - "extend": { "flags": [ "DESTROYS", "PUSH_MON", "PUSH_VEH" ] } + "aggression": 4, + "morale": 100, + "melee_skill": 9, + "extend": { "anger_triggers": [ "HURT", "FIRE" ], "flags": [ "BASHES" ] }, + "delete": { "fear_triggers": [ "HURT", "FIRE" ] } + }, + { + "id": "mon_wasp_mega", + "type": "MONSTER", + "name": { "str": "giant wasp queen" }, + "description": "A yellowjacket queen grown to the size of a horse, towering over their daughters. Even with their abdomen swollen with eggs and wings long unused it still poses a threat to interlopers, should their children have failed at subduing them.", + "copy-from": "mon_wasp_guard", + "looks_like": "mon_wasp_mega", + "diff": 4, + "proportional": { "hp": 4, "volume": 5, "weight": 5 }, + "speed": 100, + "attack_cost": 100, + "melee_skill": 8, + "melee_dice": 4, + "melee_dice_sides": 5, + "special_attacks": [ + { + "id": "sting", + "cooldown": 5, + "move_cost": 200, + "damage_max_instance": [ { "damage_type": "stab", "amount": 15, "armor_penetration": 60 } ], + "min_mul": 1, + "max_mul": 3, + "effects": [ { "id": "venom_weaken", "duration": 600 }, { "id": "downed", "duration": 1, "chance": 50 } ] + }, + { + "type": "bite", + "cooldown": 3, + "move_cost": 100, + "damage_max_instance": [ { "damage_type": "cut", "amount": 10, "armor_penetration": 30 } ], + "min_mul": 1, + "max_mul": 3, + "body_parts": [ [ "leg_l", 2 ], [ "leg_r", 2 ], [ "head", 1 ], [ "arm_l", 2 ], [ "arm_r", 2 ], [ "torso", 4 ] ] + } + ], + "//": "sting 15-45 damage, 6 hits to max intensity, 8 to max duration; bite 10-30", + "dodge": 3, + "vision_night": 15, + "armor_bash": 8, + "armor_cut": 30, + "armor_stab": 18, + "armor_bullet": 22, + "harvest": "arachnid_wasp_queen", + "reproduction": { "baby_egg": "egg_wasp", "baby_count": 4, "baby_timer": 5 }, + "extend": { "flags": [ "PUSH_MON" ] }, + "delete": { "flags": [ "HARDTOSHOOT" ] } }, { "id": "mon_dermatik_larva", @@ -1404,7 +1548,7 @@ "volume": "12 L", "weight": "15 kg", "hp": 60, - "speed": 110, + "speed": 130, "material": [ "iflesh" ], "symbol": "a", "color": "red", @@ -1423,13 +1567,14 @@ "anger_triggers": [ "FRIEND_ATTACKED", "PLAYER_WEAK" ], "fear_triggers": [ "HURT", "FIRE" ], "death_function": [ "NORMAL" ], - "flags": [ "SEES", "HEARS", "SMELLS", "FLIES", "PATH_AVOID_FIRE", "LOUDMOVES" ] + "flags": [ "SEES", "HEARS", "SMELLS", "FLIES", "PATH_AVOID_FIRE", "CANPLAY" ] }, { "id": "mon_dermatik_midwife", "type": "MONSTER", "name": { "str": "dermatik midwife", "str_pl": "dermatik midwives" }, "description": "A dermatik grown even larger, its wings and ovipositor chewed off by her sisters. It now stands watch in the nest, tending to the unfortunate hosts dragged home and ensuring they don't perish before their purpose is fulfilled.", + "species": [ "INSECT" ], "copy-from": "mon_dermatik", "volume": "17 L", "weight": "25 kg", @@ -1437,7 +1582,7 @@ "speed": 100, "melee_cut": 10, "vision_night": 8, - "delete": { "flags": [ "FLIES", "LOUDMOVES" ], "special_attacks": [ "DERMATIK" ] } + "delete": { "flags": [ "FLIES" ], "special_attacks": [ "DERMATIK" ] } }, { "id": "mon_dermatik_incubator_deer", @@ -1820,6 +1965,7 @@ "baby_flags": [ "AUTUMN" ], "biosignature": { "biosig_item": "feces_roach", "biosig_timer": 3 }, "anger_triggers": [ "FRIEND_ATTACKED" ], + "fear_triggers": [ "HURT", "FIRE" ], "death_function": [ "NORMAL" ], "upgrades": { "half_life": 21, "into": "mon_locust_mega" }, "special_attacks": [ { "type": "leap", "cooldown": 2, "max_range": 8, "allow_no_target": true }, [ "EAT_CROP", 60 ] ], @@ -1865,6 +2011,7 @@ "upgrades": { "age_grow": 10, "into": "mon_locust" }, "death_function": [ "NORMAL" ], "special_attacks": [ { "type": "leap", "cooldown": 4, "max_range": 4, "allow_no_target": true }, [ "EAT_CROP", 120 ] ], + "fear_triggers": [ "HURT", "FIRE" ], "flags": [ "SEES", "HEARS", "SMELLS", "CLIMBS", "LARVA", "STUMBLES", "PATH_AVOID_FIRE" ] } ] diff --git a/data/json/overmap/overmap_terrain/overmap_terrain_agricultural.json b/data/json/overmap/overmap_terrain/overmap_terrain_agricultural.json index 693e377cface8..5a2e2ccef9845 100644 --- a/data/json/overmap/overmap_terrain/overmap_terrain_agricultural.json +++ b/data/json/overmap/overmap_terrain/overmap_terrain_agricultural.json @@ -123,6 +123,7 @@ "id": "sugar_house", "copy-from": "generic_rural_building", "name": "sugar house", + "spawns": { "group": "GROUP_WASP_FORAGER", "population": [ 1, 4 ], "chance": 20 }, "sym": "S" }, { @@ -270,6 +271,7 @@ "type": "overmap_terrain", "id": [ "farm_stills_4", "farm_stills_8", "farm_stills_12" ], "copy-from": "generic_rural_building", + "spawns": { "group": "GROUP_WASP_FORAGER", "population": [ 1, 4 ], "chance": 10 }, "name": "grape farm" }, { @@ -284,6 +286,7 @@ "id": "farm_stills_11", "copy-from": "generic_rural_building", "name": "orchard", + "spawns": { "group": "GROUP_WASP_FORAGER", "population": [ 1, 4 ], "chance": 10 }, "color": "brown" }, { @@ -293,6 +296,7 @@ "name": "apple orchard", "sym": "T", "color": "light_green", + "spawns": { "group": "GROUP_WASP_FORAGER", "population": [ 1, 4 ], "chance": 5 }, "mondensity": 3 }, { @@ -502,6 +506,7 @@ "copy-from": "generic_rural_building", "name": "tree farm", "sym": "T", + "spawns": { "group": "GROUP_WASP_FORAGER", "population": [ 1, 2 ], "chance": 20 }, "color": "i_green" }, { diff --git a/data/json/overmap/overmap_terrain/overmap_terrain_commercial.json b/data/json/overmap/overmap_terrain/overmap_terrain_commercial.json index f66a217205760..dfba53e9ffe20 100644 --- a/data/json/overmap/overmap_terrain/overmap_terrain_commercial.json +++ b/data/json/overmap/overmap_terrain/overmap_terrain_commercial.json @@ -417,6 +417,7 @@ "copy-from": "generic_city_building", "name": "butcher shop", "color": "i_red", + "spawns": { "group": "GROUP_WASP_FORAGER", "population": [ 2, 6 ], "chance": 20 }, "extend": { "flags": [ "SOURCE_FOOD", "SOURCE_COOKING" ] } }, { @@ -853,6 +854,7 @@ "copy-from": "generic_city_building", "name": "candy shop", "color": "red_white", + "spawns": { "group": "GROUP_WASP_FORAGER", "population": [ 2, 6 ], "chance": 20 }, "extend": { "flags": [ "SOURCE_LUXURY", "SOURCE_FOOD" ] } }, { @@ -868,6 +870,7 @@ "name": "bakery", "copy-from": "generic_city_building", "color": "yellow_white", + "spawns": { "group": "GROUP_WASP_FORAGER", "population": [ 2, 6 ], "chance": 20 }, "extend": { "flags": [ "SOURCE_LUXURY", "SOURCE_FOOD" ] } }, { @@ -890,6 +893,7 @@ "name": "icecream shop", "copy-from": "generic_city_building", "color": "blue_white", + "spawns": { "group": "GROUP_WASP_FORAGER", "population": [ 3, 6 ], "chance": 20 }, "extend": { "flags": [ "SOURCE_LUXURY", "SOURCE_FOOD" ] } }, { diff --git a/data/json/overmap/overmap_terrain/overmap_terrain_industrial.json b/data/json/overmap/overmap_terrain/overmap_terrain_industrial.json index 69511469ecc81..c57c4e7367a21 100644 --- a/data/json/overmap/overmap_terrain/overmap_terrain_industrial.json +++ b/data/json/overmap/overmap_terrain/overmap_terrain_industrial.json @@ -116,6 +116,7 @@ "name": "lumberyard", "sym": "L", "color": "i_green", + "spawns": { "group": "GROUP_WASP_FORAGER", "population": [ 1, 3 ], "chance": 10 }, "extend": { "flags": [ "SOURCE_CONSTRUCTION", "SOURCE_FABRICATION" ] } }, { @@ -133,6 +134,7 @@ "name": "lumbermill", "sym": "L", "color": "i_green", + "spawns": { "group": "GROUP_WASP_FORAGER", "population": [ 1, 3 ], "chance": 10 }, "extend": { "flags": [ "SOURCE_CONSTRUCTION", "SOURCE_FABRICATION" ] } }, { diff --git a/data/json/regional_map_settings.json b/data/json/regional_map_settings.json index 399068e0aabf0..6433a28fa34b2 100644 --- a/data/json/regional_map_settings.json +++ b/data/json/regional_map_settings.json @@ -391,6 +391,7 @@ "mx_grass": 20, "mx_fallen_shed": 30, "mx_spider": 200, + "mx_nest_wasp": 100, "mx_grove": 500, "mx_shrubbery": 500, "mx_clearcut": 125, @@ -419,6 +420,7 @@ "mx_fallen_shed": 20, "mx_shia": 1, "mx_spider": 200, + "mx_nest_wasp": 100, "mx_jabberwock": 1, "mx_grove": 500, "mx_shrubbery": 500, @@ -474,7 +476,7 @@ "mx_point_burned_ground": 50, "mx_casings": 20, "mx_corpses": 3, - "mx_nest_wasp": 2, + "mx_nest_wasp": 5, "mx_mass_grave": 5, "mx_grave": 5 } diff --git a/data/json/requirements/cooking_components.json b/data/json/requirements/cooking_components.json index 5b2913d707145..940f82dbb78f6 100644 --- a/data/json/requirements/cooking_components.json +++ b/data/json/requirements/cooking_components.json @@ -72,7 +72,8 @@ [ "egg_locust", 4 ], [ "egg_dragonfly", 4 ], [ "egg_firefly", 4 ], - [ "egg_centipede", 2 ] + [ "egg_centipede", 2 ], + [ "egg_wasp", 4 ] ] ] }, diff --git a/data/json/snippets/mutant_anatomy.json b/data/json/snippets/mutant_anatomy.json index d914d42482a9c..efccd0450330c 100644 --- a/data/json/snippets/mutant_anatomy.json +++ b/data/json/snippets/mutant_anatomy.json @@ -142,7 +142,8 @@ "Inside is a complex, still-squirming mess of strange appendages and organs that bear only a passing resemblance to any natural creature", "Beneath the chitin, the meat is covered in thick, bristly hair hiding a chaotic bramble of half-formed, mutated organs", "Inside is a tangled mess of organs and tissues that do not appear entirely natural", - "Inside the creature you find lungs, hearts, and intestines more like a mammal than a giant bug" + "Inside the creature you find lungs, hearts, and intestines more like a mammal than a giant bug", + "Despite the apparent death of the whole, some organs still pump, beat, and churn on undisturbed" ] }, { @@ -157,7 +158,9 @@ "You follow what you think are superflous veins into the deep, finding a gorged, tick-like creature at their convergence", "Every cut reveals an organ you can't quite recognize, and you start to wonder what your insides look like by now", "You are dizzied by the rainbow coloration of the creature's muscles, clashing with the bloody mess in its guts", - "As you cut into its flesh you are disturbed by its sickly-sweet smell, like fermenting fruit" + "As you cut into its flesh you are disturbed by its sickly-sweet smell, like fermenting fruit", + "There are fist-sized globs of nervous tissue dotted about its insides, sending the corpse into a spasm every time you touch one", + "The muscles grow stiff, and begin leaking a dark gray liquid that pools around your feet" ] }, { @@ -243,6 +246,42 @@ "This one's very flesh is glowing with a blinding intensity, lighting up your gruesome work" ] }, + { + "type": "snippet", + "category": "", + "text": [ + "", + "", + "Its chitin is sturdier than usual for the flying insects, and marked by the struggles of its previous victims", + "The stripes on the back of its abdomen are warped into a nauseating spiral you can't tear your eyes away from", + "Upon closer inspection, the uniform black stripes reveal themselves to be rows upon rows of glistening eyes", + "With each cut, the stinger springs from its sheath, tip bending ever so slightly towards your leg", + "The stripes -so uniform at a distance- reveal themselves to be jagged, strangely familiar patterns, like the cursive of an unknown language" + ] + }, + { + "type": "snippet", + "category": "", + "text": [ + "", + "", + "The chaotic bundle of organs in its torso look much like those of other mutated insects, but as you near the abdomen there's order to the madness: comparatively neat rows of venom-filled glands, each feeding into a reservoir at the base of the stinger", + "You open a stomach, releasing a gush of sweet-smelling grey fluid", + "For its apparent hunger for meat, its intestines seem almost atrophied", + "Your knife reaches the retracted stinger and slips on its smooth surface, opening half a dozen venom glands in the process. You haven't cut yourself, have you?", + "You find a handful of dead grubs underneath its chitin, near a chewed-open venom gland" + ] + }, + { + "type": "snippet", + "category": "", + "text": [ + "Deep, deep within the dead queen you find a smooth, brightly colored plaque the size of your fingernail, reading ", + "Some of the now-familiar venom glands also contain dozens of shiny white eggs, undisturbed by their deadly surroundings", + "As you cut into its abdomen you disturb a handful of normal-sized, wingless wasps clinging to a strange, tubular organ. They crawl a few steps before falling lifelessly to the ground", + "Some of the egg clusters are ransacked by fat, white worms tunneling blindly through its flesh" + ] + }, { "type": "snippet", "category": "", @@ -320,7 +359,26 @@ "text": [ ".", ". .", - ". . " + ". . ." + ] + }, + { + "type": "snippet", + "category": "", + "text": [ + " .", + ".", + ". . ", + ". . ." + ] + }, + { + "type": "snippet", + "category": "", + "text": [ + ". .", + ". .", + ". . ." ] }, { diff --git a/data/json/snippets/snippets.json b/data/json/snippets/snippets.json index 58dc06c5979e6..fc9c96cbe8c6d 100644 --- a/data/json/snippets/snippets.json +++ b/data/json/snippets/snippets.json @@ -1,4 +1,9 @@ [ + { + "type": "snippet", + "category": "", + "text": [ "0", "1", "2", "3", "4", "5", "6", "7", "8", "9" ] + }, { "type": "snippet", "category": "necropolis_intro", diff --git a/data/json/species.json b/data/json/species.json index f58ed34aca5e8..156a16b6890f1 100644 --- a/data/json/species.json +++ b/data/json/species.json @@ -93,7 +93,7 @@ "description": "a flying insect", "footsteps": "BZZZZZZZZZZZZZZZZZ", "anger_triggers": [ "FRIEND_DIED" ], - "fear_triggers": [ "HURT", "FIRE" ], + "flags": [ "LOUDMOVES" ], "bleeds": "fd_blood_insect" }, { diff --git a/src/map_extras.cpp b/src/map_extras.cpp index 4ba83bd8f6529..224d96bfd1b93 100644 --- a/src/map_extras.cpp +++ b/src/map_extras.cpp @@ -131,8 +131,11 @@ static const mongroup_id GROUP_NETHER_CAPTURED( "GROUP_NETHER_CAPTURED" ); static const mongroup_id GROUP_NETHER_PORTAL( "GROUP_NETHER_PORTAL" ); static const mongroup_id GROUP_PETS( "GROUP_PETS" ); static const mongroup_id GROUP_STRAY_DOGS( "GROUP_STRAY_DOGS" ); +static const mongroup_id GROUP_WASP_GUARD( "GROUP_WASP_GUARD" ); +static const mongroup_id GROUP_WASP_QUEEN( "GROUP_WASP_QUEEN" ); static const mtype_id mon_dispatch( "mon_dispatch" ); +static const mtype_id mon_dermatik( "mon_dermatik" ); static const mtype_id mon_jabberwock( "mon_jabberwock" ); static const mtype_id mon_marloss_zealot_f( "mon_marloss_zealot_f" ); static const mtype_id mon_marloss_zealot_m( "mon_marloss_zealot_m" ); @@ -145,7 +148,6 @@ static const mtype_id mon_turret_searchlight( "mon_turret_searchlight" ); 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_turret_speaker( "mon_turret_speaker" ); -static const mtype_id mon_wasp( "mon_wasp" ); static const mtype_id mon_wolf( "mon_wolf" ); static const mtype_id mon_zombie_bio_op( "mon_zombie_bio_op" ); static const mtype_id mon_zombie_military_pilot( "mon_zombie_military_pilot" ); @@ -287,10 +289,12 @@ static bool mx_house_wasp( map &m, const tripoint &loc ) } } } - m.add_spawn( mon_wasp, 1, tripoint( pod, loc.z ) ); + m.place_spawns( GROUP_WASP_GUARD, 1, pod, pod, 1, true ); + } + m.place_spawns( GROUP_WASP_QUEEN, 1, point_zero, point( SEEX, SEEY ), 1, true ); + if( one_in( 5 ) ) { + m.add_spawn( mon_dermatik, rng( 1, 3 ), tripoint( point( SEEX * 2 - 1, SEEY * 2 - 1 ), loc.z ) ); } - m.place_items( item_group_id( "rare" ), 70, point_zero, point( SEEX * 2 - 1, SEEY * 2 - 1 ), - false, calendar::start_of_cataclysm ); return true; } From d46dcab8c769e44726abd52f4a3f2663f436396a Mon Sep 17 00:00:00 2001 From: ToxiClay Date: Thu, 13 May 2021 22:22:31 -0400 Subject: [PATCH 436/453] Replace comma with semicolon --- data/json/items/comestibles/carnivore.json | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/data/json/items/comestibles/carnivore.json b/data/json/items/comestibles/carnivore.json index 294cc6b837ddf..2338ef2278536 100644 --- a/data/json/items/comestibles/carnivore.json +++ b/data/json/items/comestibles/carnivore.json @@ -209,7 +209,7 @@ "flags": [ ], "use_action": { "target": "raw_cured_fatty_meat", - "msg": "You pat off a bit of extra brine from the slice, this piece of meat is now fully cured.", + "msg": "You pat off a bit of extra brine from the slice; this piece of meat is now fully cured.", "moves": 150, "type": "delayed_transform", "transform_age": 4800, From 91c5f991787d6c54b873d6ec39959a6718ac56ae Mon Sep 17 00:00:00 2001 From: Clay Caviness Date: Thu, 22 Apr 2021 23:08:48 -0400 Subject: [PATCH 437/453] Fix found->find typo --- .../npcs/refugee_center/surface_staff/NPC_old_guard_doctor.json | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/data/json/npcs/refugee_center/surface_staff/NPC_old_guard_doctor.json b/data/json/npcs/refugee_center/surface_staff/NPC_old_guard_doctor.json index dd4421cb5b79e..09a336dac48f3 100644 --- a/data/json/npcs/refugee_center/surface_staff/NPC_old_guard_doctor.json +++ b/data/json/npcs/refugee_center/surface_staff/NPC_old_guard_doctor.json @@ -145,7 +145,7 @@ "followup": "MISSION_SCIENCE_REP_5", "dialogue": { "describe": "We need help…", - "offer": "So there looks to be months, maybe years of experiments, and that data set must be huge. Database servers massive enough to house it would overheat running on emergency power. But I did found communications from a lab that had some kind of freezing portal open during the Cataclysm, sending everything to subzero temperatures. I bet the archives inside that lab are still working.", + "offer": "So there looks to be months, maybe years of experiments, and that data set must be huge. Database servers massive enough to house it would overheat running on emergency power. But I did find communications from a lab that had some kind of freezing portal open during the Cataclysm, sending everything to subzero temperatures. I bet the archives inside that lab are still working.", "accepted": "Great! I've mapped out a route. Bundle up, it gets colder the deeper you go and it looks like the archives were on the fourth basement level.", "rejected": "Can't blame you, but come back if you change your mind.", "advice": "That lab is going to start freezing and just get colder the deeper you go. You'll really need special equipment to survive that far down. Bring back anything you find on a USB drive.", From 91fa5d659cb385411165a863193351402f6a373e Mon Sep 17 00:00:00 2001 From: FayFlightee <71143790+FayFlightee@users.noreply.github.com> Date: Fri, 28 May 2021 17:30:09 +0700 Subject: [PATCH 438/453] adding steel knuckles (#48535) --- .../Locations_MapExtras/locations.json | 3 ++- .../locations_commercial.json | 3 ++- .../locations_mapextras.json | 3 ++- data/json/itemgroups/food_service.json | 6 ++++- data/json/itemgroups/military.json | 3 ++- data/json/items/melee/unarmed_weapons.json | 17 ++++++++++++++ data/json/martialarts.json | 4 ++-- data/json/npcs/island_prison/prisoners.json | 3 ++- data/json/recipes/weapon/bashing.json | 22 +++++++++++++++++++ 9 files changed, 56 insertions(+), 8 deletions(-) diff --git a/data/json/itemgroups/Locations_MapExtras/locations.json b/data/json/itemgroups/Locations_MapExtras/locations.json index a3670f5a8f9ca..b255b6fa67157 100644 --- a/data/json/itemgroups/Locations_MapExtras/locations.json +++ b/data/json/itemgroups/Locations_MapExtras/locations.json @@ -1534,7 +1534,8 @@ { "item": "chain", "prob": 10 }, { "item": "glass_shiv", "prob": 30 }, { "item": "bottle_glass", "prob": 5 }, - { "item": "knuckle_brass", "prob": 10 }, + { "item": "knuckle_brass", "prob": 7 }, + { "item": "knuckle_steel_forged", "prob": 3 }, { "item": "switchblade", "prob": 4 }, { "item": "throwing_knife", "prob": 5 }, { "item": "tazer", "prob": 1, "charges": [ 0, 100 ] }, diff --git a/data/json/itemgroups/Locations_MapExtras/locations_commercial.json b/data/json/itemgroups/Locations_MapExtras/locations_commercial.json index 898c9df2cbba2..bdd84cd4cfcdf 100644 --- a/data/json/itemgroups/Locations_MapExtras/locations_commercial.json +++ b/data/json/itemgroups/Locations_MapExtras/locations_commercial.json @@ -226,7 +226,8 @@ [ "multi_cooker", 1 ], [ "pastaextruder", 8 ], { "item": "can_sealer", "prob": 5, "charges": [ 0, 500 ] }, - [ "knuckle_brass", 15 ], + [ "knuckle_brass", 10 ], + [ "knuckle_steel_forged", 5 ], [ "platinum_small", 10 ], { "item": "foodperson_mask", "prob": 1, "charges": [ 0, 500 ] }, [ "gold_small", 10 ], diff --git a/data/json/itemgroups/Locations_MapExtras/locations_mapextras.json b/data/json/itemgroups/Locations_MapExtras/locations_mapextras.json index a36e51c4436ae..a3ed07ff4d2a5 100644 --- a/data/json/itemgroups/Locations_MapExtras/locations_mapextras.json +++ b/data/json/itemgroups/Locations_MapExtras/locations_mapextras.json @@ -8,7 +8,8 @@ [ "daypack", 20 ], [ "energy_drink", 55 ], [ "energy_drink_atomic", 8 ], - [ "knuckle_brass", 30 ], + [ "knuckle_brass", 20 ], + [ "knuckle_steel_forged", 10 ], [ "sports_drink", 35 ], [ "colamdew", 60 ], [ "purple_drink", 15 ], diff --git a/data/json/itemgroups/food_service.json b/data/json/itemgroups/food_service.json index 97a77205dea06..253f81eba17a6 100644 --- a/data/json/itemgroups/food_service.json +++ b/data/json/itemgroups/food_service.json @@ -74,7 +74,11 @@ "id": "corner_weapon", "type": "item_group", "subtype": "distribution", - "entries": [ { "item": "tazer", "prob": 70, "charges": [ 0, 500 ] }, { "item": "knuckle_brass", "prob": 70 } ] + "entries": [ + { "item": "tazer", "prob": 70, "charges": [ 0, 500 ] }, + { "item": "knuckle_brass", "prob": 50 }, + { "item": "knuckle_steel_forged", "prob": 20 } + ] }, { "id": "displays", diff --git a/data/json/itemgroups/military.json b/data/json/itemgroups/military.json index fff33a56cdce2..ef8cf03b9927d 100644 --- a/data/json/itemgroups/military.json +++ b/data/json/itemgroups/military.json @@ -126,7 +126,8 @@ { "item": "small_repairkit", "prob": 10 }, { "item": "50_incendiary", "prob": 2 }, { "item": "water_clean", "prob": 90 }, - { "item": "knuckle_brass", "prob": 15 }, + { "item": "knuckle_brass", "prob": 10 }, + { "item": "knuckle_steel_forged", "prob": 5 }, { "item": "battery_ups", "prob": 10 }, { "item": "bandages", "prob": 30 }, { "item": "adhesive_bandages", "prob": 20 }, diff --git a/data/json/items/melee/unarmed_weapons.json b/data/json/items/melee/unarmed_weapons.json index 0ba543f49c29e..c6f7d653b4f1e 100644 --- a/data/json/items/melee/unarmed_weapons.json +++ b/data/json/items/melee/unarmed_weapons.json @@ -98,6 +98,23 @@ "qualities": [ [ "HAMMER", 1 ] ], "flags": [ "UNARMED_WEAPON" ] }, + { + "type": "GENERIC", + "id": "knuckle_steel_forged", + "symbol": "3", + "color": "light_gray", + "name": { "str": "pair of steel knuckles", "str_pl": "pairs of steel knuckles" }, + "looks_like": "knuckle_brass", + "description": "A pair of knuckles forged from steel, designed to be gripped in the palm and cause punches to do more damage. A good, quick weapon - but you have to get within punching range to use it.", + "category": "weapons", + "material": [ "steel" ], + "volume": "250 ml", + "weight": "240 g", + "bashing": 4, + "price_postapoc": 180, + "qualities": [ [ "HAMMER", 1 ] ], + "flags": [ "UNARMED_WEAPON", "DURABLE_MELEE" ] + }, { "type": "GENERIC", "id": "punch_dagger", diff --git a/data/json/martialarts.json b/data/json/martialarts.json index 077a1485acf3b..8a49e33a015b5 100644 --- a/data/json/martialarts.json +++ b/data/json/martialarts.json @@ -68,7 +68,7 @@ "tec_aikido_dodgethrow", "tec_aikido_blockthrow" ], - "weapons": [ "bagh_nakha", "bio_claws_weapon", "cestus", "knuckle_brass", "knuckle_nail", "knuckle_steel" ] + "weapons": [ "bagh_nakha", "bio_claws_weapon", "cestus", "knuckle_brass", "knuckle_nail", "knuckle_steel", "knuckle_steel_forged" ] }, { "type": "martial_art", @@ -545,7 +545,7 @@ } ], "techniques": [ "tec_judo_backthrow", "tec_judo_counter", "tec_judo_disarm", "tec_judo_break", "tec_judo_throw" ], - "weapons": [ "bagh_nakha", "bio_claws_weapon", "cestus", "knuckle_brass", "knuckle_nail", "knuckle_steel" ] + "weapons": [ "bagh_nakha", "bio_claws_weapon", "cestus", "knuckle_brass", "knuckle_nail", "knuckle_steel", "knuckle_steel_forged" ] }, { "type": "martial_art", diff --git a/data/json/npcs/island_prison/prisoners.json b/data/json/npcs/island_prison/prisoners.json index 7e2e37815686f..8128c191aba72 100644 --- a/data/json/npcs/island_prison/prisoners.json +++ b/data/json/npcs/island_prison/prisoners.json @@ -104,7 +104,8 @@ [ "scissors", 5 ], [ "screwdriver", 5 ], [ "knife_steak", 5 ], - [ "knuckle_brass", 5 ], + [ "knuckle_brass", 3 ], + [ "knuckle_steel_forged", 2 ], [ "switchblade", 5 ], [ "throwing_knife", 5 ], { diff --git a/data/json/recipes/weapon/bashing.json b/data/json/recipes/weapon/bashing.json index 0bc9867ca1f9f..160288864fb4f 100644 --- a/data/json/recipes/weapon/bashing.json +++ b/data/json/recipes/weapon/bashing.json @@ -258,6 +258,28 @@ "qualities": [ { "id": "HAMMER", "level": 1 }, { "id": "SAW_M", "level": 1 } ], "components": [ [ [ "rag", 4 ] ], [ [ "scrap", 4 ] ] ] }, + { + "type": "recipe", + "activity_level": "BRISK_EXERCISE", + "result": "knuckle_steel_forged", + "category": "CC_WEAPON", + "subcategory": "CSC_WEAPON_BASHING", + "skill_used": "fabrication", + "skills_required": [ "bashing", 1 ], + "proficiencies": [ + { "proficiency": "prof_metalworking" }, + { "proficiency": "prof_blacksmithing" }, + { "proficiency": "prof_toolsmithing" } + ], + "difficulty": 3, + "time": "1 h", + "autolearn": true, + "book_learn": [ [ "recipe_melee", 2 ] ], + "using": [ [ "blacksmithing_standard", 4 ] ], + "qualities": [ { "id": "CHISEL", "level": 3 } ], + "tools": [ [ [ "swage", -1 ] ] ], + "components": [ [ [ "steel_chunk", 1 ], [ "scrap", 5 ] ] ] + }, { "type": "recipe", "activity_level": "LIGHT_EXERCISE", From 8a265588c6af99dbe7b504d53dc03c7e47701f4c Mon Sep 17 00:00:00 2001 From: Nbane522 <82512002+Nbane522@users.noreply.github.com> Date: Fri, 28 May 2021 11:31:15 +0100 Subject: [PATCH 439/453] Update wood.json (#48515) --- data/json/items/resources/wood.json | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/data/json/items/resources/wood.json b/data/json/items/resources/wood.json index afd9e89cacc64..9f0d412197594 100644 --- a/data/json/items/resources/wood.json +++ b/data/json/items/resources/wood.json @@ -39,8 +39,8 @@ "id": "stick", "symbol": "/", "color": "brown", - "name": { "str": "stout branch", "str_pl": "stout branches" }, - "description": "A respectable length of tree branch, just big enough to wrap your hand around. Makes a decent melee weapon.", + "name": { "str": "stick" }, + "description": "A respectable length of wood, just big enough to wrap your hand around. Makes a decent melee weapon.", "material": [ "wood" ], "techniques": [ "WBLOCK_1" ], "flags": [ "TRADER_AVOID", "FIREWOOD" ], @@ -56,8 +56,8 @@ "id": "stick_long", "symbol": "/", "color": "brown", - "name": { "str": "long stout branch", "str_pl": "long stout branches" }, - "description": "A straight section of wood from a tree branch, about eight feet long and a couple of inches in diameter. Makes a decent melee weapon, and can be broken into shorter pieces for crafting.", + "name": { "str": "long stick" }, + "description": "A straight section of wood, about eight feet long and a couple of inches in diameter. Makes a decent melee weapon, and can be broken into shorter pieces for crafting.", "material": [ "wood" ], "techniques": [ "WBLOCK_1" ], "flags": [ "TRADER_AVOID", "FIREWOOD" ], From fa9081cf777d1b80d196904f10d0cfa38303593b Mon Sep 17 00:00:00 2001 From: Albert Islamov Date: Mon, 12 Apr 2021 16:31:27 +0000 Subject: [PATCH 440/453] separate woods soup by meat and egg --- data/json/items/comestibles/soup.json | 27 ++++++++++++++- data/json/recipes/recipe_food.json | 16 +++++++++ .../json/requirements/cooking_components.json | 33 ++++++++++++++++--- 3 files changed, 71 insertions(+), 5 deletions(-) diff --git a/data/json/items/comestibles/soup.json b/data/json/items/comestibles/soup.json index a486da82e0a87..92dec742732cf 100644 --- a/data/json/items/comestibles/soup.json +++ b/data/json/items/comestibles/soup.json @@ -179,7 +179,7 @@ { "type": "COMESTIBLE", "id": "soup_woods", - "name": { "str": "woods soup" }, + "name": { "str": "woods meat soup" }, "conditional_names": [ { "type": "COMPONENT_ID", "condition": "mutant", "name": "Mirkwood soup" } ], "weight": "250 g", "color": "red", @@ -201,6 +201,31 @@ "vitamins": [ [ "vitA", 20 ], [ "vitC", 9 ], [ "iron", 3 ], [ "vitB", 5 ] ], "fun": 1 }, + { + "type": "COMESTIBLE", + "id": "soup_woods_egg", + "name": { "str": "woods egg soup" }, + "conditional_names": [ { "type": "COMPONENT_ID", "condition": "mutant", "name": "Mirkwood soup" } ], + "weight": "250 g", + "color": "red", + "spoils_in": "5 days", + "container": "can_medium", + "comestible_type": "DRINK", + "symbol": "~", + "quench": 8, + "healthy": 1, + "calories": 304, + "description": "A nutritious and delicious soup, made of gifts of nature.", + "price": 350, + "price_postapoc": 100, + "material": [ "egg", "veggy" ], + "volume": "500 ml", + "charges": 2, + "phase": "liquid", + "flags": [ "EATEN_HOT", "USE_EAT_VERB" ], + "vitamins": [ [ "vitA", 20 ], [ "vitC", 9 ], [ "iron", 3 ], [ "vitB", 5 ] ], + "fun": 1 + }, { "type": "COMESTIBLE", "id": "soup_chicken", diff --git a/data/json/recipes/recipe_food.json b/data/json/recipes/recipe_food.json index 2b92975413284..61c03bc3e3764 100644 --- a/data/json/recipes/recipe_food.json +++ b/data/json/recipes/recipe_food.json @@ -2585,6 +2585,22 @@ "tools": [ [ [ "surface_heat", 5, "LIST" ] ] ], "using": [ [ "woods_soup_ingredients", 1 ] ] }, + { + "type": "recipe", + "activity_level": "LIGHT_EXERCISE", + "result": "soup_woods_egg", + "charges": 2, + "category": "CC_FOOD", + "subcategory": "CSC_FOOD_VEGGI", + "skill_used": "cooking", + "difficulty": 3, + "time": "20 m", + "autolearn": true, + "batch_time_factors": [ 80, 4 ], + "qualities": [ { "id": "COOK", "level": 3 } ], + "tools": [ [ [ "surface_heat", 5, "LIST" ] ] ], + "using": [ [ "woods_soup_ingredients_veggy", 1 ] ] + }, { "type": "recipe", "activity_level": "LIGHT_EXERCISE", diff --git a/data/json/requirements/cooking_components.json b/data/json/requirements/cooking_components.json index 940f82dbb78f6..c44780dba54b2 100644 --- a/data/json/requirements/cooking_components.json +++ b/data/json/requirements/cooking_components.json @@ -443,10 +443,7 @@ [ "can_tuna", 1 ], [ "sausage", 1 ], [ "sausage_cooked", 1 ], - [ "bratwurst_sausage", 1 ], - [ "powder_eggs", 2 ], - [ "eggs_bird", 2, "LIST" ], - [ "egg_reptile", 2 ] + [ "bratwurst_sausage", 1 ] ], [ [ "veggy_wild", 2 ], @@ -473,6 +470,34 @@ ] ] }, + { + "id": "woods_soup_ingredients_veggy", + "type": "requirement", + "components": [ + [ [ "broth", 2 ], [ "broth_bone", 2 ], [ "pine_tea", 2 ] ], + [ [ "powder_eggs", 2 ], [ "eggs_bird", 2, "LIST" ], [ "egg_reptile", 2 ] ], + [ + [ "veggy_wild", 2 ], + [ "veggy", 2 ], + [ "rehydrated_veggy", 2 ], + [ "dry_veggy", 2 ], + [ "dry_beans", 2 ], + [ "can_beans", 2 ], + [ "raw_beans", 2 ], + [ "beans_cooked", 2 ], + [ "dry_lentils", 2 ], + [ "raw_lentils", 2 ], + [ "dry_rice", 2 ], + [ "dandelion_cooked", 2 ], + [ "burdock_cooked", 2 ], + [ "mushroom", 2 ], + [ "dry_mushroom", 2 ], + [ "mushroom_cooked", 2 ], + [ "morel_cooked", 2 ], + [ "acorns_cooked", 2 ] + ] + ] + }, { "id": "any_fat", "type": "requirement", From 7b71c0568b8d8077cb95ef9b07f7ee11ed9132dc Mon Sep 17 00:00:00 2001 From: stubkan <34361592+stubkan@users.noreply.github.com> Date: Fri, 28 May 2021 11:33:35 +0100 Subject: [PATCH 441/453] Placing specials around cities now scales with city size (#48628) --- doc/OVERMAP.md | 7 +++---- src/overmap.cpp | 2 +- 2 files changed, 4 insertions(+), 5 deletions(-) diff --git a/doc/OVERMAP.md b/doc/OVERMAP.md index 5d855355c3691..fd1767152238d 100644 --- a/doc/OVERMAP.md +++ b/doc/OVERMAP.md @@ -327,8 +327,7 @@ level value and then only specify it for individual entries that differ. During generation of a new overmap, cities and their connecting roads will be generated before specials are placed. Each city gets assigned a size at generation and will begin its life as a single intersection. The city distance field specifies the minimum and maximum distance the special can be -placed from _this_ intersection, *not* from the edge of the city, meaning a special with a low minimum -distance and a high or unbounded maximum city size may be placed on the outer border of a larger city. +placed from the edge of the urban radius of a city, and not from the center of the city. Both city size and city distance requirements are only checked for the "nearest" city, measured from the original intersection. @@ -342,7 +341,7 @@ original intersection. | `overmaps` | List of overmap terrains and their relative `[ x, y, z ]` location within the special. | | `connections` | List of overmap connections and their relative `[ x, y, z ]` location within the special. | | `locations` | List of `overmap_location` ids that the special may be placed on. | -| `city_distance` | Min/max distance from a city that the special may be placed. Use -1 for unbounded. | +| `city_distance` | Min/max distance from a city edge that the special may be placed. Use -1 for unbounded. | | `city_sizes` | Min/max city size for a city that the special may be placed near. Use -1 for unbounded. | | `occurrences` | Min/max number of occurrences when placing the special. If UNIQUE flag is set, becomes X of Y chance. | | `flags` | See `Overmap specials` in [JSON_FLAGS.md](JSON_FLAGS.md). | @@ -388,7 +387,7 @@ original intersection. | `terrain` | Will go away in favor of `connection` eventually. Use `road`, `subway`, `sewer`, etc. | | `connection` | Id of the `overmap_connection` to build. Optional for now, but you should specify it explicitly. | | `from` | Optional point `[ x, y, z]` within the special to treat as the origin of the connection. | -| `existing` | Boolean, default false. If the special requires a preexisting terrain to spawn. | +| `existing` | Boolean, default false. If the special requires a preexisting terrain to spawn. | ## City Building diff --git a/src/overmap.cpp b/src/overmap.cpp index 8121614556da7..8021dfd3883a4 100644 --- a/src/overmap.cpp +++ b/src/overmap.cpp @@ -852,7 +852,7 @@ bool overmap_special::can_belong_to_city( const tripoint_om_omt &p, const city & if( !cit || !city_size.contains( cit.size ) ) { return false; } - return city_distance.contains( cit.get_distance_from( p ) ); + return city_distance.contains( cit.get_distance_from( p ) - ( cit.size ) ); } void overmap_special::load( const JsonObject &jo, const std::string &src ) From e5a72e514d99c9062b54c3ceb71c04a51e8e8364 Mon Sep 17 00:00:00 2001 From: Maleclypse <54345792+Maleclypse@users.noreply.github.com> Date: Fri, 28 May 2021 05:35:57 -0500 Subject: [PATCH 442/453] [Magiclysm] Forge Floor and Wall improvements (#48234) --- data/mods/Magiclysm/terrain.json | 49 ++++++++++++++++++- .../Magiclysm/worldgen/forge_of_wonders.json | 26 +++++----- 2 files changed, 60 insertions(+), 15 deletions(-) diff --git a/data/mods/Magiclysm/terrain.json b/data/mods/Magiclysm/terrain.json index bdeb5e28bc143..9440798c062d0 100644 --- a/data/mods/Magiclysm/terrain.json +++ b/data/mods/Magiclysm/terrain.json @@ -102,10 +102,55 @@ "sound_fail": "whack!", "sound_vol": 16, "sound_fail_vol": 10, - "ter_set": "t_thconc_floor", + "ter_set": "t_magiconc_floor", "items": [ { "item": "glass_shard", "count": [ 8, 16 ] } ] } }, + { + "type": "terrain", + "id": "t_magiconc_wall", + "name": "magically reinforced concrete wall", + "looks_like": "t_concrete_wall", + "description": "An extremely resilient wall, filled with concrete and rebar and esoteric ingredients. Best suited for supporting multi-level buildings, only serious explosives and high-speed impacts would be capable of damaging this wall.", + "symbol": "LINE_OXOX", + "color": "light_gray", + "move_cost": 0, + "coverage": 100, + "roof": "t_flat_roof", + "flags": [ "NOITEM", "SUPPORTS_ROOF", "WALL", "NO_SCENT", "AUTO_WALL_SYMBOL", "BLOCK_WIND" ], + "connects_to": "WALL", + "bash": { + "str_min": 240, + "str_max": 560, + "sound": "scrrrash!", + "sound_fail": "whump!", + "ter_set": "t_reb_cage", + "items": [ { "item": "rock", "count": [ 10, 22 ] } ] + } + }, + { + "type": "terrain", + "id": "t_magiconc_floor", + "name": "magically reinforced concrete floor", + "description": "Extremely resilient floor made from carefully placed rebar and poured alchemical concrete, capable of providing protection from the elements. As for the matching roof, it still requires supporting walls, otherwise it may very well cave in.", + "symbol": ".", + "color": "cyan", + "move_cost": 2, + "roof": "t_flat_roof", + "flags": [ "TRANSPARENT", "SUPPORTS_ROOF", "COLLAPSES", "INDOORS", "FLAT", "ROAD" ], + "bash": { + "sound": "SMASH!", + "ter_set": "t_null", + "str_min": 350, + "str_max": 600, + "str_min_supported": 200, + "items": [ + { "item": "rock", "count": [ 10, 22 ] }, + { "item": "scrap", "count": [ 10, 12 ] }, + { "item": "rebar", "count": [ 0, 4 ] } + ] + } + }, { "type": "terrain", "id": "t_vault_vent", @@ -119,7 +164,7 @@ "flags": [ "TRANSPARENT", "SUPPORTS_ROOF", "COLLAPSES", "INDOORS", "FLAT", "ROAD" ], "bash": { "sound": "SMASH!", - "ter_set": "t_null", + "ter_set": "t_magiconc_floor", "str_min": 150, "str_max": 400, "str_min_supported": 200, diff --git a/data/mods/Magiclysm/worldgen/forge_of_wonders.json b/data/mods/Magiclysm/worldgen/forge_of_wonders.json index cf7833a7587e7..0d71c7c715736 100644 --- a/data/mods/Magiclysm/worldgen/forge_of_wonders.json +++ b/data/mods/Magiclysm/worldgen/forge_of_wonders.json @@ -90,7 +90,7 @@ "terrain": { "w": "t_water_sh", "l": "t_lava", - "#": "t_strconc_wall", + "#": "t_magiconc_wall", "t": "t_ov_reb_cage", "W": "t_water_dp", "3": "t_water_moving_sh_underground", @@ -99,19 +99,19 @@ "&": "t_ballistic_door_glass_c", "|": "t_window_stained_green", "X": "t_wall_glassteel_alarm", - ".": "t_strconc_floor", - "h": "t_strconc_floor", - "!": "t_strconc_floor", - "~": "t_strconc_floor", - "1": "t_strconc_floor", - "z": "t_strconc_floor", - "Z": "t_strconc_floor", - "$": [ "t_strconc_floor", "t_vault_vent" ], - "f": "t_strconc_floor", - "F": "t_strconc_floor", - "8": "t_strconc_floor", + ".": "t_magiconc_floor", + "h": "t_magiconc_floor", + "!": "t_magiconc_floor", + "~": "t_magiconc_floor", + "1": "t_magiconc_floor", + "z": "t_magiconc_floor", + "Z": "t_magiconc_floor", + "$": [ "t_magiconc_floor", "t_vault_vent" ], + "f": "t_magiconc_floor", + "F": "t_magiconc_floor", + "8": "t_magiconc_floor", "9": "t_vault_vent", - "2": "t_strconc_floor", + "2": "t_magiconc_floor", "4": "t_thconc_floor_echandelier", "+": "t_railroad_rubble", "5": "t_bollard" From ef26f4d704df2c0a124493476fb0116643f1350c Mon Sep 17 00:00:00 2001 From: Maleclypse <54345792+Maleclypse@users.noreply.github.com> Date: Fri, 28 May 2021 05:36:23 -0500 Subject: [PATCH 443/453] Faux Fur survivor gear and recipes (#47424) --- data/json/items/armor/boots.json | 24 ++++ data/json/items/armor/gloves.json | 23 ++++ data/json/items/armor/hoods.json | 24 ++++ data/json/items/armor/suits_protection.json | 24 ++++ data/json/items/tool_armor.json | 24 ++++ data/json/recipes/armor/feet.json | 37 ++++++ data/json/recipes/armor/hands.json | 48 ++++++++ data/json/recipes/armor/head.json | 42 +++++++ data/json/recipes/armor/suit.json | 121 ++++++++++++++++++++ 9 files changed, 367 insertions(+) diff --git a/data/json/items/armor/boots.json b/data/json/items/armor/boots.json index 27ab9f419a516..6e12a9e296a71 100644 --- a/data/json/items/armor/boots.json +++ b/data/json/items/armor/boots.json @@ -274,6 +274,30 @@ "proportional": { "weight": 1.15, "volume": 1.15 }, "flags": [ "VARSIZE", "WATERPROOF", "OVERSIZE" ] }, + { + "id": "boots_wsurvivor_nofur", + "type": "ARMOR", + "name": { "str": "pair of faux fur winter survivor boots", "str_pl": "pairs of faux fur winter survivor boots" }, + "description": "A pair of customized, Kevlar armored faux fur boots, modified to provide maximum protection from harm and the elements, even when knee-deep in the dead. While not quite as warm as real fur it's pretty good.", + "copy-from": "boots_wsurvivor", + "material": [ "kevlar", "faux_fur" ], + "symbol": "[", + "warmth": 50, + "looks_like": "boots_fur", + "color": "pink" + }, + { + "id": "xl_boots_wsurvivor_nofur", + "type": "ARMOR", + "name": { "str": "pair of XL faux fur winter survivor boots", "str_pl": "pairs of XL faux fur winter survivor boots" }, + "copy-from": "boots_wsurvivor", + "material": [ "kevlar", "faux_fur" ], + "description": "A pair of customized and oversized, Kevlar armored faux fur boots, modified to provide maximum protection from harm and the elements, even when knee-deep in the dead. While not quite as warm as real fur it's pretty good.", + "color": "pink", + "warmth": 50, + "proportional": { "weight": 1.3, "volume": 1.3 }, + "flags": [ "VARSIZE", "WATERPROOF", "OVERSIZE", "STURDY" ] + }, { "id": "boots_h20survivor", "type": "ARMOR", diff --git a/data/json/items/armor/gloves.json b/data/json/items/armor/gloves.json index 8572ff3ca4a57..4422500ac804f 100644 --- a/data/json/items/armor/gloves.json +++ b/data/json/items/armor/gloves.json @@ -346,6 +346,29 @@ "proportional": { "weight": 1.6, "volume": 1.6 }, "flags": [ "WATERPROOF" ] }, + { + "id": "gloves_wsurvivor_nofur", + "type": "ARMOR", + "name": { "str": "pair of faux fur winter survivor gloves", "str_pl": "pairs of faux fur winter survivor gloves" }, + "description": "A pair of customized, Kevlar armored faux fur gloves, modified to be easy to wear while providing maximum protection under extreme conditions. While not quite as warm as real fur it's pretty good.", + "copy-from": "gloves_wsurvivor", + "material": [ "kevlar_layered", "faux_fur" ], + "symbol": "[", + "looks_like": "gloves_winter", + "color": "pink", + "warmth": 60 + }, + { + "id": "xl_gloves_wsurvivor_nofur", + "type": "ARMOR", + "name": { "str": "pair of XL faux fur winter survivor gloves", "str_pl": "pairs of XL faux fur winter survivor gloves" }, + "copy-from": "gloves_wsurvivor_nofur", + "material": [ "kevlar_layered", "faux_fur" ], + "description": "A pair of customized and oversized Kevlar armored faux fur gloves, modified to be easy to wear while providing maximum protection under extreme conditions. While not quite as warm as real fur it's pretty good.", + "color": "pink", + "proportional": { "weight": 1.5, "volume": 1.5 }, + "flags": [ "VARSIZE", "WATERPROOF", "STURDY", "OVERSIZE" ] + }, { "id": "gloves_hsurvivor", "type": "ARMOR", diff --git a/data/json/items/armor/hoods.json b/data/json/items/armor/hoods.json index 04f53e1fc10bb..4e3649c008d37 100644 --- a/data/json/items/armor/hoods.json +++ b/data/json/items/armor/hoods.json @@ -118,6 +118,30 @@ "proportional": { "weight": 1.25, "volume": 1.3, "price": 1.25 }, "flags": [ "VARSIZE", "STURDY", "OVERSIZE", "HELMET_COMPAT", "OUTER", "WATERPROOF" ] }, + { + "id": "hood_wsurvivor_nofur", + "type": "ARMOR", + "name": { "str": "winter faux fur survivor hood" }, + "description": "A customized armored faux fur and Kevlar hood, warm and durable. If not quite as warm as real fur.", + "copy-from": "hood_wsurvivor", + "material": [ "kevlar_layered", "faux_fur" ], + "symbol": "[", + "warmth": 65, + "looks_like": "hood_survivor", + "color": "pink" + }, + { + "id": "xl_hood_wsurvivor_nofur", + "type": "ARMOR", + "copy-from": "hood_wsurvivor", + "material": [ "kevlar_layered", "faux_fur" ], + "color": "pink", + "warmth": 65, + "name": { "str": "XL faux fur winter survivor hood" }, + "description": "A customized and oversized armored faux fur and Kevlar hood, warm and durable. If not quite as warm as real fur.", + "proportional": { "weight": 1.25, "volume": 1.3, "price": 1.25 }, + "flags": [ "VARSIZE", "STURDY", "OVERSIZE", "HELMET_COMPAT", "OUTER", "WATERPROOF" ] + }, { "id": "hood_rain", "type": "ARMOR", diff --git a/data/json/items/armor/suits_protection.json b/data/json/items/armor/suits_protection.json index b99ed35c402b9..c18e8ba4286bf 100644 --- a/data/json/items/armor/suits_protection.json +++ b/data/json/items/armor/suits_protection.json @@ -781,6 +781,30 @@ "proportional": { "weight": 1.125, "volume": 1.13, "price": 1.25 }, "flags": [ "VARSIZE", "WATERPROOF", "RAINPROOF", "POCKETS", "STURDY", "OVERSIZE" ] }, + { + "id": "wsurvivor_suit_nofur", + "type": "ARMOR", + "name": { "str": "winter survivor suit" }, + "description": "A warm and heavy hand-built combination armor made from a reinforced bulletproof vest and a faux fur insulated leather jumpsuit. Protects from the elements as well as from harm.", + "copy-from": "wsurvivor_suit", + "material": [ "kevlar_layered", "faux_fur" ], + "symbol": "[", + "warmth": 65, + "looks_like": "survivor_suit", + "color": "pink" + }, + { + "id": "xl_wsurvivor_suit_nofur", + "type": "ARMOR", + "name": { "str": "XL winter survivor suit" }, + "copy-from": "wsurvivor_suit", + "material": [ "kevlar_layered", "faux_fur" ], + "description": "A warm, heavy and oversized hand-built combination armor made from a reinforced bulletproof vest and a faux fur insulated leather jumpsuit. Protects from the elements as well as from harm.", + "color": "pink", + "warmth": 65, + "proportional": { "weight": 1.125, "volume": 1.13, "price": 1.25 }, + "flags": [ "VARSIZE", "WATERPROOF", "POCKETS", "HOOD", "RAINPROOF", "STURDY", "OVERSIZE" ] + }, { "id": "gambeson", "type": "ARMOR", diff --git a/data/json/items/tool_armor.json b/data/json/items/tool_armor.json index afe219e96dfbf..a5dafc099ab96 100644 --- a/data/json/items/tool_armor.json +++ b/data/json/items/tool_armor.json @@ -1560,6 +1560,30 @@ "qualities": [ [ "GLARE", 1 ] ], "flags": [ "VARSIZE", "STURDY", "OVERSIZE", "SUN_GLASSES", "SLEEP_IGNORE" ] }, + { + "id": "mask_wsurvivor_nofur", + "type": "TOOL_ARMOR", + "name": { "str": "faux fur winter survivor mask" }, + "description": "A custom-built, faux fur-trimmed gas mask that covers the face and eyes. It provides excellent protection from smoke, teargas, and shrapnel and while not quite as warm as real fur it's pretty good. It must be prepared before use.", + "copy-from": "mask_wsurvivor", + "material": [ "kevlar_layered", "faux_fur" ], + "symbol": "[", + "warmth": 65, + "looks_like": "mask_wsurvivor", + "color": "pink" + }, + { + "id": "mask_wsurvivorxl_nofur", + "type": "TOOL_ARMOR", + "name": { "str": "XL faux fur winter survivor mask" }, + "description": "A custom-built, faux fur-trimmed gas mask that covers the face and eyes regardless of your state of mutation. It still provides excellent protection from smoke, teargas, and shrapnel and while not quite as warm as real fur it's pretty good. It must be prepared before use.", + "copy-from": "mask_wsurvivorxl", + "material": [ "kevlar_layered", "faux_fur" ], + "symbol": "[", + "warmth": 65, + "looks_like": "mask_wsurvivorxl", + "color": "pink" + }, { "id": "mask_wsurvivor", "type": "TOOL_ARMOR", diff --git a/data/json/recipes/armor/feet.json b/data/json/recipes/armor/feet.json index 7ec67854577b0..3d0e20cc753c4 100644 --- a/data/json/recipes/armor/feet.json +++ b/data/json/recipes/armor/feet.json @@ -154,6 +154,43 @@ "using": [ [ "sewing_standard", 16 ], [ "tailoring_leather_small", 8 ], [ "tailoring_fur_small", 8 ], [ "fastener_small", 2 ] ], "time": "15 h" }, + { + "result": "boots_wsurvivor_nofur", + "type": "recipe", + "activity_level": "LIGHT_EXERCISE", + "category": "CC_ARMOR", + "subcategory": "CSC_ARMOR_FEET", + "skill_used": "tailor", + "difficulty": 7, + "skills_required": [ "fabrication", 5 ], + "time": "24 h", + "autolearn": true, + "using": [ [ "tailoring_kevlar_fabric", 4 ], [ "fastener_small", 2 ] ], + "proficiencies": [ + { "proficiency": "prof_cobbling" }, + { "proficiency": "prof_leatherworking_basic" }, + { "proficiency": "prof_closures_waterproofing" }, + { "proficiency": "prof_polymerworking" } + ], + "components": [ + [ [ "faux_fur", 12 ] ], + [ [ "duct_tape", 100 ] ], + [ [ "boots_combat", 1 ], [ "boots_steel", 1 ], [ "boots_hiking", 1 ], [ "boots_bunker", 1 ], [ "boots", 1 ] ] + ] + }, + { + "result": "xl_boots_wsurvivor_nofur", + "type": "recipe", + "activity_level": "LIGHT_EXERCISE", + "copy-from": "boots_wsurvivor_nofur", + "using": [ [ "tailoring_kevlar_fabric", 6 ], [ "fastener_small", 2 ] ], + "components": [ + [ [ "faux_fur", 16 ] ], + [ [ "duct_tape", 150 ] ], + [ [ "boots_combat", 1 ], [ "boots_steel", 1 ], [ "boots_hiking", 1 ], [ "boots_bunker", 1 ], [ "boots", 1 ] ] + ], + "time": "32 h" + }, { "result": "boots_h20survivor", "type": "recipe", diff --git a/data/json/recipes/armor/hands.json b/data/json/recipes/armor/hands.json index c1c174ade6e36..046fe41cce8ea 100644 --- a/data/json/recipes/armor/hands.json +++ b/data/json/recipes/armor/hands.json @@ -186,6 +186,54 @@ "time": "13 h", "using": [ [ "tailoring_fur_small", 5 ] ] }, + { + "result": "gloves_wsurvivor_nofur", + "type": "recipe", + "activity_level": "LIGHT_EXERCISE", + "category": "CC_ARMOR", + "subcategory": "CSC_ARMOR_HANDS", + "skill_used": "tailor", + "difficulty": 7, + "skills_required": [ "fabrication", 5 ], + "time": "20 h", + "autolearn": true, + "using": [ [ "sewing_standard", 50 ], [ "tailoring_kevlar_fabric", 1 ] ], + "proficiencies": [ + { "proficiency": "prof_closures_waterproofing" }, + { "proficiency": "prof_polymerworking" }, + { "proficiency": "prof_leatherworking_basic" }, + { "proficiency": "prof_articulation" } + ], + "components": [ + [ [ "duct_tape", 80 ] ], + [ [ "faux_fur", 4 ] ], + [ + [ "gloves_leather", 1 ], + [ "gloves_light", 1 ], + [ "gloves_liner", 1 ], + [ "wetsuit_gloves", 1 ], + [ "fire_gauntlets", 1 ] + ] + ] + }, + { + "result": "xl_gloves_wsurvivor_nofur", + "type": "recipe", + "copy-from": "gloves_wsurvivor_nofur", + "time": "26 h", + "using": [ [ "sewing_standard", 75 ], [ "tailoring_kevlar_fabric", 2 ] ], + "components": [ + [ [ "duct_tape", 120 ] ], + [ [ "faux_fur", 5 ] ], + [ + [ "gloves_leather", 1 ], + [ "gloves_light", 1 ], + [ "gloves_liner", 1 ], + [ "wetsuit_gloves", 1 ], + [ "fire_gauntlets", 1 ] + ] + ] + }, { "result": "gloves_h20survivor", "type": "recipe", diff --git a/data/json/recipes/armor/head.json b/data/json/recipes/armor/head.json index 6fcd875e6fd29..b6b332aa6ad0c 100644 --- a/data/json/recipes/armor/head.json +++ b/data/json/recipes/armor/head.json @@ -886,6 +886,48 @@ [ [ "duct_tape", 150 ] ] ] }, + { + "result": "hood_wsurvivor_nofur", + "type": "recipe", + "activity_level": "LIGHT_EXERCISE", + "category": "CC_ARMOR", + "subcategory": "CSC_ARMOR_HEAD", + "skill_used": "tailor", + "difficulty": 7, + "skills_required": [ "fabrication", 5 ], + "time": "6 h", + "autolearn": true, + "using": [ [ "sewing_standard", 40 ] ], + "tools": [ [ [ "welder", 21 ], [ "welder_crude", 32 ], [ "soldering_iron", 32 ], [ "toolset", 32 ] ] ], + "components": [ + [ [ "faux_fur", 8 ] ], + [ [ "rag", 2 ] ], + [ [ "sheet_kevlar_layered", 4 ] ], + [ [ "hood_rain", 1 ], [ "bag_plastic", 2 ], [ "hood_gut", 1 ] ], + [ [ "duct_tape", 100 ] ] + ], + "proficiencies": [ + { "proficiency": "prof_millinery" }, + { "proficiency": "prof_leatherworking_basic" }, + { "proficiency": "prof_plasticworking" }, + { "proficiency": "prof_polymerworking" } + ] + }, + { + "result": "xl_hood_wsurvivor_nofur", + "type": "recipe", + "copy-from": "hood_wsurvivor_nofur", + "time": "8 h", + "using": [ [ "sewing_standard", 60 ] ], + "tools": [ [ [ "welder", 28 ], [ "welder_crude", 43 ], [ "soldering_iron", 43 ], [ "toolset", 43 ] ] ], + "components": [ + [ [ "faux_fur", 10 ] ], + [ [ "rag", 4 ] ], + [ [ "sheet_kevlar_layered", 6 ] ], + [ [ "hood_rain", 1 ], [ "bag_plastic", 2 ], [ "hood_gut", 1 ] ], + [ [ "duct_tape", 150 ] ] + ] + }, { "result": "hood_rain", "type": "recipe", diff --git a/data/json/recipes/armor/suit.json b/data/json/recipes/armor/suit.json index 3f4b119ffc8f2..3aa0e2aee9cf6 100644 --- a/data/json/recipes/armor/suit.json +++ b/data/json/recipes/armor/suit.json @@ -785,6 +785,127 @@ [ [ "kevlar", 2 ], [ "ballistic_vest_empty", 2 ], [ "swat_armor", 2 ], [ "sheet_kevlar_layered", 48 ] ] ] }, + { + "result": "wsurvivor_suit_nofur", + "type": "recipe", + "activity_level": "LIGHT_EXERCISE", + "category": "CC_ARMOR", + "subcategory": "CSC_ARMOR_SUIT", + "skill_used": "tailor", + "difficulty": 6, + "skills_required": [ "fabrication", 6 ], + "time": "12 h", + "autolearn": true, + "using": [ [ "sewing_standard", 200 ] ], + "qualities": [ { "id": "LEATHER_AWL", "level": 1 } ], + "proficiencies": [ + { "proficiency": "prof_leatherworking_basic" }, + { "proficiency": "prof_leatherworking" }, + { "proficiency": "prof_closures" }, + { "proficiency": "prof_closures_waterproofing" }, + { "proficiency": "prof_polymerworking" } + ], + "tools": [ [ [ "welder", 28 ], [ "welder_crude", 42 ], [ "soldering_iron", 42 ], [ "toolset", 42 ] ] ], + "components": [ + [ [ "rag", 10 ] ], + [ [ "leather", 20 ], [ "tanned_hide", 4 ] ], + [ [ "faux_fur", 20 ] ], + [ [ "coat_rain", 1 ], [ "jacket_windbreaker", 1 ], [ "jacket_evac", 1 ], [ "coat_gut", 1 ] ], + [ + [ "tacvest", 1 ], + [ "legrig", 1 ], + [ "vest", 1 ], + [ "tool_belt", 1 ], + [ "ragpouch", 6 ], + [ "leather_pouch", 4 ], + [ "dump_pouch", 1 ], + [ "purse", 2 ], + [ "fanny", 2 ] + ], + [ [ "duct_tape", 300 ] ], + [ [ "kevlar", 1 ], [ "ballistic_vest_empty", 1 ], [ "swat_armor", 1 ], [ "sheet_kevlar_layered", 24 ] ] + ] + }, + { + "result": "xl_wsurvivor_suit_nofur", + "copy-from": "wsurvivor_suit_nofur", + "time": "18 h", + "type": "recipe", + "using": [ [ "sewing_standard", 300 ] ], + "qualities": [ { "id": "LEATHER_AWL", "level": 1 } ], + "tools": [ [ [ "welder", 56 ], [ "welder_crude", 104 ], [ "soldering_iron", 104 ], [ "toolset", 104 ] ] ], + "components": [ + [ [ "rag", 20 ] ], + [ [ "leather", 30 ], [ "tanned_hide", 6 ] ], + [ [ "faux_fur", 30 ] ], + [ [ "coat_rain", 2 ], [ "jacket_windbreaker", 2 ], [ "jacket_evac", 2 ], [ "coat_gut", 2 ] ], + [ + [ "tacvest", 1 ], + [ "legrig", 1 ], + [ "vest", 1 ], + [ "tool_belt", 1 ], + [ "ragpouch", 6 ], + [ "leather_pouch", 4 ], + [ "dump_pouch", 1 ], + [ "purse", 2 ], + [ "fanny", 2 ] + ], + [ [ "duct_tape", 400 ] ], + [ [ "kevlar", 2 ], [ "ballistic_vest_empty", 2 ], [ "swat_armor", 2 ], [ "sheet_kevlar_layered", 48 ] ] + ] + }, + { + "result": "mask_wsurvivor_nofur", + "type": "recipe", + "activity_level": "LIGHT_EXERCISE", + "category": "CC_ARMOR", + "subcategory": "CSC_ARMOR_HEAD", + "skill_used": "fabrication", + "difficulty": 7, + "skills_required": [ "tailor", 7 ], + "time": "4 h", + "autolearn": true, + "using": [ [ "adhesive", 1 ], [ "sewing_standard", 10 ] ], + "tools": [ [ [ "welder", 56 ], [ "welder_crude", 84 ], [ "soldering_iron", 84 ], [ "toolset", 84 ] ] ], + "components": [ + [ [ "mask_filter", 2 ], [ "mask_gas", 1 ], [ "mask_bunker", 1 ] ], + [ [ "glasses_safety", 2 ], [ "glasses_bal", 1 ] ], + [ [ "mask_bal", 1 ], [ "sheet_kevlar_layered", 4 ] ], + [ [ "faux_fur", 6 ], [ "tanned_pelt", 1 ] ] + ], + "proficiencies": [ + { "proficiency": "prof_plasticworking" }, + { "proficiency": "prof_leatherworking_basic" }, + { "proficiency": "prof_closures_waterproofing" }, + { "proficiency": "prof_polymerworking" } + ] + }, + { + "result": "mask_wsurvivorxl_nofur", + "type": "recipe", + "activity_level": "LIGHT_EXERCISE", + "category": "CC_ARMOR", + "subcategory": "CSC_ARMOR_HEAD", + "skill_used": "fabrication", + "difficulty": 7, + "skills_required": [ "tailor", 7 ], + "time": "4 h", + "autolearn": true, + "using": [ [ "adhesive", 1 ], [ "sewing_standard", 20 ] ], + "tools": [ [ [ "welder", 56 ], [ "welder_crude", 84 ], [ "soldering_iron", 84 ], [ "toolset", 84 ] ] ], + "components": [ + [ [ "mask_filter", 2 ], [ "mask_gas", 1 ], [ "mask_bunker", 1 ] ], + [ [ "glasses_safety", 2 ], [ "glasses_bal", 1 ] ], + [ [ "mask_bal", 1 ], [ "sheet_kevlar_layered", 4 ] ], + [ [ "faux_fur", 12 ], [ "tanned_pelt", 2 ] ] + ], + "proficiencies": [ + { "proficiency": "prof_plasticworking" }, + { "proficiency": "prof_leatherworking_basic" }, + { "proficiency": "prof_closures_waterproofing" }, + { "proficiency": "prof_polymerworking" } + ] + }, { "result": "gambeson", "type": "recipe", From 96d2a20927aab5ae784989c4b9404b6b9dc46e90 Mon Sep 17 00:00:00 2001 From: Anton Burmistrov Date: Fri, 28 May 2021 14:37:28 +0400 Subject: [PATCH 444/453] Avgas fuel pump (#48458) --- .../terrain-manufactured.json | 48 +++++++++++++++++++ data/json/mapgen/regional_airport.json | 2 +- data/json/materials.json | 1 + src/mapgen.cpp | 2 +- 4 files changed, 51 insertions(+), 2 deletions(-) diff --git a/data/json/furniture_and_terrain/terrain-manufactured.json b/data/json/furniture_and_terrain/terrain-manufactured.json index 405f93674385c..ff8dbb0e067de 100644 --- a/data/json/furniture_and_terrain/terrain-manufactured.json +++ b/data/json/furniture_and_terrain/terrain-manufactured.json @@ -203,6 +203,54 @@ ] } }, + { + "type": "terrain", + "id": "t_avgas_pump", + "name": "avgas pump", + "looks_like": "t_gas_pump", + "description": "This pump is filled with avgas. If this gas dispenser doesn't give up the goods for free, you may have to pay at a nearby terminal.", + "symbol": "&", + "color": "red", + "move_cost": 0, + "coverage": 65, + "flags": [ "TRANSPARENT", "FLAMMABLE", "NOITEM", "SEALED", "CONTAINER", "REDUCE_SCENT", "PERMEABLE", "LIQUIDCONT" ], + "examine_action": "gaspump", + "bash": { + "str_min": 8, + "str_max": 150, + "sound": "crunch!", + "sound_fail": "clang!", + "ter_set": "t_avgas_pump_smashed", + "items": [ { "item": "scrap", "count": 1 } ] + } + }, + { + "type": "terrain", + "id": "t_avgas_pump_smashed", + "name": "smashed avgas pump", + "description": "You're not getting any avgas out of this pump any time soon. Some barbarian decided to take their frustration out on it.", + "symbol": "&", + "color": "light_green", + "looks_like": "t_gas_pump_smashed", + "move_cost": 0, + "coverage": 55, + "flags": [ "TRANSPARENT", "NOITEM", "REDUCE_SCENT", "PERMEABLE" ], + "bash": { + "str_min": 20, + "str_max": 150, + "explosive": 40, + "sound": "metal screeching!", + "sound_fail": "clang!", + "ter_set": "t_pavement", + "items": [ + { "item": "steel_lump", "prob": 50 }, + { "item": "steel_chunk", "count": [ 1, 4 ] }, + { "item": "pipe_fittings", "count": [ 2, 6 ] }, + { "item": "pipe", "count": [ 4, 8 ] }, + { "item": "scrap", "count": [ 3, 7 ] } + ] + } + }, { "type": "terrain", "id": "t_atm", diff --git a/data/json/mapgen/regional_airport.json b/data/json/mapgen/regional_airport.json index 3d8e211848626..479e7ee48224b 100644 --- a/data/json/mapgen/regional_airport.json +++ b/data/json/mapgen/regional_airport.json @@ -250,7 +250,7 @@ "palettes": [ "airport_palette" ], "place_furniture": [ { "furn": "f_gas_tank", "x": 13, "y": 4 } ], "place_liquids": [ { "liquid": "avgas", "x": 13, "y": 4, "repeat": [ 100, 500 ] } ], - "gaspumps": { "J": { } }, + "gaspumps": { "J": { "fuel": "avgas" } }, "place_monsters": [ { "monster": "GROUP_SMALL_STATION", "x": [ 4, 23 ], "y": [ 5, 23 ], "density": 0.05 } ], "place_loot": [ { "group": "supplies_electronics", "x": [ 19, 22 ], "y": 20, "chance": 60, "repeat": [ 1, 3 ] }, diff --git a/data/json/materials.json b/data/json/materials.json index a62c2a95edb50..b804a2b0367ec 100644 --- a/data/json/materials.json +++ b/data/json/materials.json @@ -803,6 +803,7 @@ "copy-from": "hydrocarbons", "fuel_data": { "energy": 45.8, + "pump_terrain": "t_avgas_pump", "explosion_data": { "chance_hot": 20, "chance_cold": 1000, "factor": 0.2, "fiery": false, "size_factor": 0.1 } } }, diff --git a/src/mapgen.cpp b/src/mapgen.cpp index 763673c2bcca1..8ddba4ba4748c 100644 --- a/src/mapgen.cpp +++ b/src/mapgen.cpp @@ -1085,7 +1085,7 @@ class jmapgen_gaspump : public jmapgen_piece fuel = jsi.get_string( "fuel" ); // may want to not force this, if we want to support other fuels for some reason - if( fuel != "gasoline" && fuel != "diesel" && fuel != "jp8" ) { + if( fuel != "gasoline" && fuel != "diesel" && fuel != "jp8" && fuel != "avgas" ) { jsi.throw_error( "invalid fuel", "fuel" ); } } From b44595b018e05317f54c2838233830c403e2483b Mon Sep 17 00:00:00 2001 From: Anton Burmistrov Date: Fri, 28 May 2021 14:37:58 +0400 Subject: [PATCH 445/453] New "Bordered" scenario (#48514) --- data/json/mapgen/rock_border.json | 36 + .../overmap_special/bordered_world.json | 727 ++++++++++++++++++ .../overmap_terrain/overmap_terrain.json | 8 + data/json/scenarios.json | 10 + doc/JSON_FLAGS.md | 1 + src/game.cpp | 8 + src/newcharacter.cpp | 4 + 7 files changed, 794 insertions(+) create mode 100644 data/json/mapgen/rock_border.json create mode 100644 data/json/overmap/overmap_special/bordered_world.json diff --git a/data/json/mapgen/rock_border.json b/data/json/mapgen/rock_border.json new file mode 100644 index 0000000000000..3377ea4d15324 --- /dev/null +++ b/data/json/mapgen/rock_border.json @@ -0,0 +1,36 @@ +[ + { + "type": "mapgen", + "method": "json", + "om_terrain": [ "rock_border" ], + "object": { + "rows": [ + " ", + " ", + " ", + " ", + " ", + " ", + " ", + " ", + " ", + " ", + " ", + " ", + " ", + " ", + " ", + " ", + " ", + " ", + " ", + " ", + " ", + " ", + " ", + " " + ], + "terrain": { " ": "t_rock" } + } + } +] diff --git a/data/json/overmap/overmap_special/bordered_world.json b/data/json/overmap/overmap_special/bordered_world.json new file mode 100644 index 0000000000000..fb561af4f7a45 --- /dev/null +++ b/data/json/overmap/overmap_special/bordered_world.json @@ -0,0 +1,727 @@ +[ + { + "type": "overmap_special", + "id": "world", + "overmaps": [ + { "point": [ 0, 0, 0 ], "overmap": "rock_border" }, + { "point": [ 1, 0, 0 ], "overmap": "rock_border" }, + { "point": [ 2, 0, 0 ], "overmap": "rock_border" }, + { "point": [ 3, 0, 0 ], "overmap": "rock_border" }, + { "point": [ 4, 0, 0 ], "overmap": "rock_border" }, + { "point": [ 5, 0, 0 ], "overmap": "rock_border" }, + { "point": [ 6, 0, 0 ], "overmap": "rock_border" }, + { "point": [ 7, 0, 0 ], "overmap": "rock_border" }, + { "point": [ 8, 0, 0 ], "overmap": "rock_border" }, + { "point": [ 9, 0, 0 ], "overmap": "rock_border" }, + { "point": [ 10, 0, 0 ], "overmap": "rock_border" }, + { "point": [ 11, 0, 0 ], "overmap": "rock_border" }, + { "point": [ 12, 0, 0 ], "overmap": "rock_border" }, + { "point": [ 13, 0, 0 ], "overmap": "rock_border" }, + { "point": [ 14, 0, 0 ], "overmap": "rock_border" }, + { "point": [ 15, 0, 0 ], "overmap": "rock_border" }, + { "point": [ 16, 0, 0 ], "overmap": "rock_border" }, + { "point": [ 17, 0, 0 ], "overmap": "rock_border" }, + { "point": [ 18, 0, 0 ], "overmap": "rock_border" }, + { "point": [ 19, 0, 0 ], "overmap": "rock_border" }, + { "point": [ 20, 0, 0 ], "overmap": "rock_border" }, + { "point": [ 21, 0, 0 ], "overmap": "rock_border" }, + { "point": [ 22, 0, 0 ], "overmap": "rock_border" }, + { "point": [ 23, 0, 0 ], "overmap": "rock_border" }, + { "point": [ 24, 0, 0 ], "overmap": "rock_border" }, + { "point": [ 25, 0, 0 ], "overmap": "rock_border" }, + { "point": [ 26, 0, 0 ], "overmap": "rock_border" }, + { "point": [ 27, 0, 0 ], "overmap": "rock_border" }, + { "point": [ 28, 0, 0 ], "overmap": "rock_border" }, + { "point": [ 29, 0, 0 ], "overmap": "rock_border" }, + { "point": [ 30, 0, 0 ], "overmap": "rock_border" }, + { "point": [ 31, 0, 0 ], "overmap": "rock_border" }, + { "point": [ 32, 0, 0 ], "overmap": "rock_border" }, + { "point": [ 33, 0, 0 ], "overmap": "rock_border" }, + { "point": [ 34, 0, 0 ], "overmap": "rock_border" }, + { "point": [ 35, 0, 0 ], "overmap": "rock_border" }, + { "point": [ 36, 0, 0 ], "overmap": "rock_border" }, + { "point": [ 37, 0, 0 ], "overmap": "rock_border" }, + { "point": [ 38, 0, 0 ], "overmap": "rock_border" }, + { "point": [ 39, 0, 0 ], "overmap": "rock_border" }, + { "point": [ 40, 0, 0 ], "overmap": "rock_border" }, + { "point": [ 41, 0, 0 ], "overmap": "rock_border" }, + { "point": [ 42, 0, 0 ], "overmap": "rock_border" }, + { "point": [ 43, 0, 0 ], "overmap": "rock_border" }, + { "point": [ 44, 0, 0 ], "overmap": "rock_border" }, + { "point": [ 45, 0, 0 ], "overmap": "rock_border" }, + { "point": [ 46, 0, 0 ], "overmap": "rock_border" }, + { "point": [ 47, 0, 0 ], "overmap": "rock_border" }, + { "point": [ 48, 0, 0 ], "overmap": "rock_border" }, + { "point": [ 49, 0, 0 ], "overmap": "rock_border" }, + { "point": [ 50, 0, 0 ], "overmap": "rock_border" }, + { "point": [ 51, 0, 0 ], "overmap": "rock_border" }, + { "point": [ 52, 0, 0 ], "overmap": "rock_border" }, + { "point": [ 53, 0, 0 ], "overmap": "rock_border" }, + { "point": [ 54, 0, 0 ], "overmap": "rock_border" }, + { "point": [ 55, 0, 0 ], "overmap": "rock_border" }, + { "point": [ 56, 0, 0 ], "overmap": "rock_border" }, + { "point": [ 57, 0, 0 ], "overmap": "rock_border" }, + { "point": [ 58, 0, 0 ], "overmap": "rock_border" }, + { "point": [ 59, 0, 0 ], "overmap": "rock_border" }, + { "point": [ 60, 0, 0 ], "overmap": "rock_border" }, + { "point": [ 61, 0, 0 ], "overmap": "rock_border" }, + { "point": [ 62, 0, 0 ], "overmap": "rock_border" }, + { "point": [ 63, 0, 0 ], "overmap": "rock_border" }, + { "point": [ 64, 0, 0 ], "overmap": "rock_border" }, + { "point": [ 65, 0, 0 ], "overmap": "rock_border" }, + { "point": [ 66, 0, 0 ], "overmap": "rock_border" }, + { "point": [ 67, 0, 0 ], "overmap": "rock_border" }, + { "point": [ 68, 0, 0 ], "overmap": "rock_border" }, + { "point": [ 69, 0, 0 ], "overmap": "rock_border" }, + { "point": [ 70, 0, 0 ], "overmap": "rock_border" }, + { "point": [ 71, 0, 0 ], "overmap": "rock_border" }, + { "point": [ 72, 0, 0 ], "overmap": "rock_border" }, + { "point": [ 73, 0, 0 ], "overmap": "rock_border" }, + { "point": [ 74, 0, 0 ], "overmap": "rock_border" }, + { "point": [ 75, 0, 0 ], "overmap": "rock_border" }, + { "point": [ 76, 0, 0 ], "overmap": "rock_border" }, + { "point": [ 77, 0, 0 ], "overmap": "rock_border" }, + { "point": [ 78, 0, 0 ], "overmap": "rock_border" }, + { "point": [ 79, 0, 0 ], "overmap": "rock_border" }, + { "point": [ 80, 0, 0 ], "overmap": "rock_border" }, + { "point": [ 81, 0, 0 ], "overmap": "rock_border" }, + { "point": [ 82, 0, 0 ], "overmap": "rock_border" }, + { "point": [ 83, 0, 0 ], "overmap": "rock_border" }, + { "point": [ 84, 0, 0 ], "overmap": "rock_border" }, + { "point": [ 85, 0, 0 ], "overmap": "rock_border" }, + { "point": [ 86, 0, 0 ], "overmap": "rock_border" }, + { "point": [ 87, 0, 0 ], "overmap": "rock_border" }, + { "point": [ 88, 0, 0 ], "overmap": "rock_border" }, + { "point": [ 89, 0, 0 ], "overmap": "rock_border" }, + { "point": [ 90, 0, 0 ], "overmap": "rock_border" }, + { "point": [ 91, 0, 0 ], "overmap": "rock_border" }, + { "point": [ 92, 0, 0 ], "overmap": "rock_border" }, + { "point": [ 93, 0, 0 ], "overmap": "rock_border" }, + { "point": [ 94, 0, 0 ], "overmap": "rock_border" }, + { "point": [ 95, 0, 0 ], "overmap": "rock_border" }, + { "point": [ 96, 0, 0 ], "overmap": "rock_border" }, + { "point": [ 97, 0, 0 ], "overmap": "rock_border" }, + { "point": [ 98, 0, 0 ], "overmap": "rock_border" }, + { "point": [ 99, 0, 0 ], "overmap": "rock_border" }, + { "point": [ 100, 0, 0 ], "overmap": "rock_border" }, + { "point": [ 101, 0, 0 ], "overmap": "rock_border" }, + { "point": [ 102, 0, 0 ], "overmap": "rock_border" }, + { "point": [ 103, 0, 0 ], "overmap": "rock_border" }, + { "point": [ 104, 0, 0 ], "overmap": "rock_border" }, + { "point": [ 105, 0, 0 ], "overmap": "rock_border" }, + { "point": [ 106, 0, 0 ], "overmap": "rock_border" }, + { "point": [ 107, 0, 0 ], "overmap": "rock_border" }, + { "point": [ 108, 0, 0 ], "overmap": "rock_border" }, + { "point": [ 109, 0, 0 ], "overmap": "rock_border" }, + { "point": [ 110, 0, 0 ], "overmap": "rock_border" }, + { "point": [ 111, 0, 0 ], "overmap": "rock_border" }, + { "point": [ 112, 0, 0 ], "overmap": "rock_border" }, + { "point": [ 113, 0, 0 ], "overmap": "rock_border" }, + { "point": [ 114, 0, 0 ], "overmap": "rock_border" }, + { "point": [ 115, 0, 0 ], "overmap": "rock_border" }, + { "point": [ 116, 0, 0 ], "overmap": "rock_border" }, + { "point": [ 117, 0, 0 ], "overmap": "rock_border" }, + { "point": [ 118, 0, 0 ], "overmap": "rock_border" }, + { "point": [ 119, 0, 0 ], "overmap": "rock_border" }, + { "point": [ 120, 0, 0 ], "overmap": "rock_border" }, + { "point": [ 121, 0, 0 ], "overmap": "rock_border" }, + { "point": [ 122, 0, 0 ], "overmap": "rock_border" }, + { "point": [ 123, 0, 0 ], "overmap": "rock_border" }, + { "point": [ 124, 0, 0 ], "overmap": "rock_border" }, + { "point": [ 125, 0, 0 ], "overmap": "rock_border" }, + { "point": [ 126, 0, 0 ], "overmap": "rock_border" }, + { "point": [ 127, 0, 0 ], "overmap": "rock_border" }, + { "point": [ 128, 0, 0 ], "overmap": "rock_border" }, + { "point": [ 129, 0, 0 ], "overmap": "rock_border" }, + { "point": [ 130, 0, 0 ], "overmap": "rock_border" }, + { "point": [ 131, 0, 0 ], "overmap": "rock_border" }, + { "point": [ 132, 0, 0 ], "overmap": "rock_border" }, + { "point": [ 133, 0, 0 ], "overmap": "rock_border" }, + { "point": [ 134, 0, 0 ], "overmap": "rock_border" }, + { "point": [ 135, 0, 0 ], "overmap": "rock_border" }, + { "point": [ 136, 0, 0 ], "overmap": "rock_border" }, + { "point": [ 137, 0, 0 ], "overmap": "rock_border" }, + { "point": [ 138, 0, 0 ], "overmap": "rock_border" }, + { "point": [ 139, 0, 0 ], "overmap": "rock_border" }, + { "point": [ 140, 0, 0 ], "overmap": "rock_border" }, + { "point": [ 141, 0, 0 ], "overmap": "rock_border" }, + { "point": [ 142, 0, 0 ], "overmap": "rock_border" }, + { "point": [ 143, 0, 0 ], "overmap": "rock_border" }, + { "point": [ 144, 0, 0 ], "overmap": "rock_border" }, + { "point": [ 145, 0, 0 ], "overmap": "rock_border" }, + { "point": [ 146, 0, 0 ], "overmap": "rock_border" }, + { "point": [ 147, 0, 0 ], "overmap": "rock_border" }, + { "point": [ 148, 0, 0 ], "overmap": "rock_border" }, + { "point": [ 149, 0, 0 ], "overmap": "rock_border" }, + { "point": [ 150, 0, 0 ], "overmap": "rock_border" }, + { "point": [ 151, 0, 0 ], "overmap": "rock_border" }, + { "point": [ 152, 0, 0 ], "overmap": "rock_border" }, + { "point": [ 153, 0, 0 ], "overmap": "rock_border" }, + { "point": [ 154, 0, 0 ], "overmap": "rock_border" }, + { "point": [ 155, 0, 0 ], "overmap": "rock_border" }, + { "point": [ 156, 0, 0 ], "overmap": "rock_border" }, + { "point": [ 157, 0, 0 ], "overmap": "rock_border" }, + { "point": [ 158, 0, 0 ], "overmap": "rock_border" }, + { "point": [ 159, 0, 0 ], "overmap": "rock_border" }, + { "point": [ 160, 0, 0 ], "overmap": "rock_border" }, + { "point": [ 161, 0, 0 ], "overmap": "rock_border" }, + { "point": [ 162, 0, 0 ], "overmap": "rock_border" }, + { "point": [ 163, 0, 0 ], "overmap": "rock_border" }, + { "point": [ 164, 0, 0 ], "overmap": "rock_border" }, + { "point": [ 165, 0, 0 ], "overmap": "rock_border" }, + { "point": [ 166, 0, 0 ], "overmap": "rock_border" }, + { "point": [ 167, 0, 0 ], "overmap": "rock_border" }, + { "point": [ 168, 0, 0 ], "overmap": "rock_border" }, + { "point": [ 169, 0, 0 ], "overmap": "rock_border" }, + { "point": [ 170, 0, 0 ], "overmap": "rock_border" }, + { "point": [ 171, 0, 0 ], "overmap": "rock_border" }, + { "point": [ 172, 0, 0 ], "overmap": "rock_border" }, + { "point": [ 173, 0, 0 ], "overmap": "rock_border" }, + { "point": [ 174, 0, 0 ], "overmap": "rock_border" }, + { "point": [ 175, 0, 0 ], "overmap": "rock_border" }, + { "point": [ 176, 0, 0 ], "overmap": "rock_border" }, + { "point": [ 177, 0, 0 ], "overmap": "rock_border" }, + { "point": [ 178, 0, 0 ], "overmap": "rock_border" }, + { "point": [ 179, 0, 0 ], "overmap": "rock_border" }, + { "point": [ 1, 179, 0 ], "overmap": "rock_border" }, + { "point": [ 2, 179, 0 ], "overmap": "rock_border" }, + { "point": [ 3, 179, 0 ], "overmap": "rock_border" }, + { "point": [ 4, 179, 0 ], "overmap": "rock_border" }, + { "point": [ 5, 179, 0 ], "overmap": "rock_border" }, + { "point": [ 6, 179, 0 ], "overmap": "rock_border" }, + { "point": [ 7, 179, 0 ], "overmap": "rock_border" }, + { "point": [ 8, 179, 0 ], "overmap": "rock_border" }, + { "point": [ 9, 179, 0 ], "overmap": "rock_border" }, + { "point": [ 10, 179, 0 ], "overmap": "rock_border" }, + { "point": [ 11, 179, 0 ], "overmap": "rock_border" }, + { "point": [ 12, 179, 0 ], "overmap": "rock_border" }, + { "point": [ 13, 179, 0 ], "overmap": "rock_border" }, + { "point": [ 14, 179, 0 ], "overmap": "rock_border" }, + { "point": [ 15, 179, 0 ], "overmap": "rock_border" }, + { "point": [ 16, 179, 0 ], "overmap": "rock_border" }, + { "point": [ 17, 179, 0 ], "overmap": "rock_border" }, + { "point": [ 18, 179, 0 ], "overmap": "rock_border" }, + { "point": [ 19, 179, 0 ], "overmap": "rock_border" }, + { "point": [ 20, 179, 0 ], "overmap": "rock_border" }, + { "point": [ 21, 179, 0 ], "overmap": "rock_border" }, + { "point": [ 22, 179, 0 ], "overmap": "rock_border" }, + { "point": [ 23, 179, 0 ], "overmap": "rock_border" }, + { "point": [ 24, 179, 0 ], "overmap": "rock_border" }, + { "point": [ 25, 179, 0 ], "overmap": "rock_border" }, + { "point": [ 26, 179, 0 ], "overmap": "rock_border" }, + { "point": [ 27, 179, 0 ], "overmap": "rock_border" }, + { "point": [ 28, 179, 0 ], "overmap": "rock_border" }, + { "point": [ 29, 179, 0 ], "overmap": "rock_border" }, + { "point": [ 30, 179, 0 ], "overmap": "rock_border" }, + { "point": [ 31, 179, 0 ], "overmap": "rock_border" }, + { "point": [ 32, 179, 0 ], "overmap": "rock_border" }, + { "point": [ 33, 179, 0 ], "overmap": "rock_border" }, + { "point": [ 34, 179, 0 ], "overmap": "rock_border" }, + { "point": [ 35, 179, 0 ], "overmap": "rock_border" }, + { "point": [ 36, 179, 0 ], "overmap": "rock_border" }, + { "point": [ 37, 179, 0 ], "overmap": "rock_border" }, + { "point": [ 38, 179, 0 ], "overmap": "rock_border" }, + { "point": [ 39, 179, 0 ], "overmap": "rock_border" }, + { "point": [ 40, 179, 0 ], "overmap": "rock_border" }, + { "point": [ 41, 179, 0 ], "overmap": "rock_border" }, + { "point": [ 42, 179, 0 ], "overmap": "rock_border" }, + { "point": [ 43, 179, 0 ], "overmap": "rock_border" }, + { "point": [ 44, 179, 0 ], "overmap": "rock_border" }, + { "point": [ 45, 179, 0 ], "overmap": "rock_border" }, + { "point": [ 46, 179, 0 ], "overmap": "rock_border" }, + { "point": [ 47, 179, 0 ], "overmap": "rock_border" }, + { "point": [ 48, 179, 0 ], "overmap": "rock_border" }, + { "point": [ 49, 179, 0 ], "overmap": "rock_border" }, + { "point": [ 50, 179, 0 ], "overmap": "rock_border" }, + { "point": [ 51, 179, 0 ], "overmap": "rock_border" }, + { "point": [ 52, 179, 0 ], "overmap": "rock_border" }, + { "point": [ 53, 179, 0 ], "overmap": "rock_border" }, + { "point": [ 54, 179, 0 ], "overmap": "rock_border" }, + { "point": [ 55, 179, 0 ], "overmap": "rock_border" }, + { "point": [ 56, 179, 0 ], "overmap": "rock_border" }, + { "point": [ 57, 179, 0 ], "overmap": "rock_border" }, + { "point": [ 58, 179, 0 ], "overmap": "rock_border" }, + { "point": [ 59, 179, 0 ], "overmap": "rock_border" }, + { "point": [ 60, 179, 0 ], "overmap": "rock_border" }, + { "point": [ 61, 179, 0 ], "overmap": "rock_border" }, + { "point": [ 62, 179, 0 ], "overmap": "rock_border" }, + { "point": [ 63, 179, 0 ], "overmap": "rock_border" }, + { "point": [ 64, 179, 0 ], "overmap": "rock_border" }, + { "point": [ 65, 179, 0 ], "overmap": "rock_border" }, + { "point": [ 66, 179, 0 ], "overmap": "rock_border" }, + { "point": [ 67, 179, 0 ], "overmap": "rock_border" }, + { "point": [ 68, 179, 0 ], "overmap": "rock_border" }, + { "point": [ 69, 179, 0 ], "overmap": "rock_border" }, + { "point": [ 70, 179, 0 ], "overmap": "rock_border" }, + { "point": [ 71, 179, 0 ], "overmap": "rock_border" }, + { "point": [ 72, 179, 0 ], "overmap": "rock_border" }, + { "point": [ 73, 179, 0 ], "overmap": "rock_border" }, + { "point": [ 74, 179, 0 ], "overmap": "rock_border" }, + { "point": [ 75, 179, 0 ], "overmap": "rock_border" }, + { "point": [ 76, 179, 0 ], "overmap": "rock_border" }, + { "point": [ 77, 179, 0 ], "overmap": "rock_border" }, + { "point": [ 78, 179, 0 ], "overmap": "rock_border" }, + { "point": [ 79, 179, 0 ], "overmap": "rock_border" }, + { "point": [ 80, 179, 0 ], "overmap": "rock_border" }, + { "point": [ 81, 179, 0 ], "overmap": "rock_border" }, + { "point": [ 82, 179, 0 ], "overmap": "rock_border" }, + { "point": [ 83, 179, 0 ], "overmap": "rock_border" }, + { "point": [ 84, 179, 0 ], "overmap": "rock_border" }, + { "point": [ 85, 179, 0 ], "overmap": "rock_border" }, + { "point": [ 86, 179, 0 ], "overmap": "rock_border" }, + { "point": [ 87, 179, 0 ], "overmap": "rock_border" }, + { "point": [ 88, 179, 0 ], "overmap": "rock_border" }, + { "point": [ 89, 179, 0 ], "overmap": "rock_border" }, + { "point": [ 90, 179, 0 ], "overmap": "rock_border" }, + { "point": [ 91, 179, 0 ], "overmap": "rock_border" }, + { "point": [ 92, 179, 0 ], "overmap": "rock_border" }, + { "point": [ 93, 179, 0 ], "overmap": "rock_border" }, + { "point": [ 94, 179, 0 ], "overmap": "rock_border" }, + { "point": [ 95, 179, 0 ], "overmap": "rock_border" }, + { "point": [ 96, 179, 0 ], "overmap": "rock_border" }, + { "point": [ 97, 179, 0 ], "overmap": "rock_border" }, + { "point": [ 98, 179, 0 ], "overmap": "rock_border" }, + { "point": [ 99, 179, 0 ], "overmap": "rock_border" }, + { "point": [ 100, 179, 0 ], "overmap": "rock_border" }, + { "point": [ 101, 179, 0 ], "overmap": "rock_border" }, + { "point": [ 102, 179, 0 ], "overmap": "rock_border" }, + { "point": [ 103, 179, 0 ], "overmap": "rock_border" }, + { "point": [ 104, 179, 0 ], "overmap": "rock_border" }, + { "point": [ 105, 179, 0 ], "overmap": "rock_border" }, + { "point": [ 106, 179, 0 ], "overmap": "rock_border" }, + { "point": [ 107, 179, 0 ], "overmap": "rock_border" }, + { "point": [ 108, 179, 0 ], "overmap": "rock_border" }, + { "point": [ 109, 179, 0 ], "overmap": "rock_border" }, + { "point": [ 110, 179, 0 ], "overmap": "rock_border" }, + { "point": [ 111, 179, 0 ], "overmap": "rock_border" }, + { "point": [ 112, 179, 0 ], "overmap": "rock_border" }, + { "point": [ 113, 179, 0 ], "overmap": "rock_border" }, + { "point": [ 114, 179, 0 ], "overmap": "rock_border" }, + { "point": [ 115, 179, 0 ], "overmap": "rock_border" }, + { "point": [ 116, 179, 0 ], "overmap": "rock_border" }, + { "point": [ 117, 179, 0 ], "overmap": "rock_border" }, + { "point": [ 118, 179, 0 ], "overmap": "rock_border" }, + { "point": [ 119, 179, 0 ], "overmap": "rock_border" }, + { "point": [ 120, 179, 0 ], "overmap": "rock_border" }, + { "point": [ 121, 179, 0 ], "overmap": "rock_border" }, + { "point": [ 122, 179, 0 ], "overmap": "rock_border" }, + { "point": [ 123, 179, 0 ], "overmap": "rock_border" }, + { "point": [ 124, 179, 0 ], "overmap": "rock_border" }, + { "point": [ 125, 179, 0 ], "overmap": "rock_border" }, + { "point": [ 126, 179, 0 ], "overmap": "rock_border" }, + { "point": [ 127, 179, 0 ], "overmap": "rock_border" }, + { "point": [ 128, 179, 0 ], "overmap": "rock_border" }, + { "point": [ 129, 179, 0 ], "overmap": "rock_border" }, + { "point": [ 130, 179, 0 ], "overmap": "rock_border" }, + { "point": [ 131, 179, 0 ], "overmap": "rock_border" }, + { "point": [ 132, 179, 0 ], "overmap": "rock_border" }, + { "point": [ 133, 179, 0 ], "overmap": "rock_border" }, + { "point": [ 134, 179, 0 ], "overmap": "rock_border" }, + { "point": [ 135, 179, 0 ], "overmap": "rock_border" }, + { "point": [ 136, 179, 0 ], "overmap": "rock_border" }, + { "point": [ 137, 179, 0 ], "overmap": "rock_border" }, + { "point": [ 138, 179, 0 ], "overmap": "rock_border" }, + { "point": [ 139, 179, 0 ], "overmap": "rock_border" }, + { "point": [ 140, 179, 0 ], "overmap": "rock_border" }, + { "point": [ 141, 179, 0 ], "overmap": "rock_border" }, + { "point": [ 142, 179, 0 ], "overmap": "rock_border" }, + { "point": [ 143, 179, 0 ], "overmap": "rock_border" }, + { "point": [ 144, 179, 0 ], "overmap": "rock_border" }, + { "point": [ 145, 179, 0 ], "overmap": "rock_border" }, + { "point": [ 146, 179, 0 ], "overmap": "rock_border" }, + { "point": [ 147, 179, 0 ], "overmap": "rock_border" }, + { "point": [ 148, 179, 0 ], "overmap": "rock_border" }, + { "point": [ 149, 179, 0 ], "overmap": "rock_border" }, + { "point": [ 150, 179, 0 ], "overmap": "rock_border" }, + { "point": [ 151, 179, 0 ], "overmap": "rock_border" }, + { "point": [ 152, 179, 0 ], "overmap": "rock_border" }, + { "point": [ 153, 179, 0 ], "overmap": "rock_border" }, + { "point": [ 154, 179, 0 ], "overmap": "rock_border" }, + { "point": [ 155, 179, 0 ], "overmap": "rock_border" }, + { "point": [ 156, 179, 0 ], "overmap": "rock_border" }, + { "point": [ 157, 179, 0 ], "overmap": "rock_border" }, + { "point": [ 158, 179, 0 ], "overmap": "rock_border" }, + { "point": [ 159, 179, 0 ], "overmap": "rock_border" }, + { "point": [ 160, 179, 0 ], "overmap": "rock_border" }, + { "point": [ 161, 179, 0 ], "overmap": "rock_border" }, + { "point": [ 162, 179, 0 ], "overmap": "rock_border" }, + { "point": [ 163, 179, 0 ], "overmap": "rock_border" }, + { "point": [ 164, 179, 0 ], "overmap": "rock_border" }, + { "point": [ 165, 179, 0 ], "overmap": "rock_border" }, + { "point": [ 166, 179, 0 ], "overmap": "rock_border" }, + { "point": [ 167, 179, 0 ], "overmap": "rock_border" }, + { "point": [ 168, 179, 0 ], "overmap": "rock_border" }, + { "point": [ 169, 179, 0 ], "overmap": "rock_border" }, + { "point": [ 170, 179, 0 ], "overmap": "rock_border" }, + { "point": [ 171, 179, 0 ], "overmap": "rock_border" }, + { "point": [ 172, 179, 0 ], "overmap": "rock_border" }, + { "point": [ 173, 179, 0 ], "overmap": "rock_border" }, + { "point": [ 174, 179, 0 ], "overmap": "rock_border" }, + { "point": [ 175, 179, 0 ], "overmap": "rock_border" }, + { "point": [ 176, 179, 0 ], "overmap": "rock_border" }, + { "point": [ 177, 179, 0 ], "overmap": "rock_border" }, + { "point": [ 178, 179, 0 ], "overmap": "rock_border" }, + { "point": [ 179, 179, 0 ], "overmap": "rock_border" }, + { "point": [ 0, 1, 0 ], "overmap": "rock_border" }, + { "point": [ 0, 2, 0 ], "overmap": "rock_border" }, + { "point": [ 0, 3, 0 ], "overmap": "rock_border" }, + { "point": [ 0, 4, 0 ], "overmap": "rock_border" }, + { "point": [ 0, 5, 0 ], "overmap": "rock_border" }, + { "point": [ 0, 6, 0 ], "overmap": "rock_border" }, + { "point": [ 0, 7, 0 ], "overmap": "rock_border" }, + { "point": [ 0, 8, 0 ], "overmap": "rock_border" }, + { "point": [ 0, 9, 0 ], "overmap": "rock_border" }, + { "point": [ 0, 10, 0 ], "overmap": "rock_border" }, + { "point": [ 0, 11, 0 ], "overmap": "rock_border" }, + { "point": [ 0, 12, 0 ], "overmap": "rock_border" }, + { "point": [ 0, 13, 0 ], "overmap": "rock_border" }, + { "point": [ 0, 14, 0 ], "overmap": "rock_border" }, + { "point": [ 0, 15, 0 ], "overmap": "rock_border" }, + { "point": [ 0, 16, 0 ], "overmap": "rock_border" }, + { "point": [ 0, 17, 0 ], "overmap": "rock_border" }, + { "point": [ 0, 18, 0 ], "overmap": "rock_border" }, + { "point": [ 0, 19, 0 ], "overmap": "rock_border" }, + { "point": [ 0, 20, 0 ], "overmap": "rock_border" }, + { "point": [ 0, 21, 0 ], "overmap": "rock_border" }, + { "point": [ 0, 22, 0 ], "overmap": "rock_border" }, + { "point": [ 0, 23, 0 ], "overmap": "rock_border" }, + { "point": [ 0, 24, 0 ], "overmap": "rock_border" }, + { "point": [ 0, 25, 0 ], "overmap": "rock_border" }, + { "point": [ 0, 26, 0 ], "overmap": "rock_border" }, + { "point": [ 0, 27, 0 ], "overmap": "rock_border" }, + { "point": [ 0, 28, 0 ], "overmap": "rock_border" }, + { "point": [ 0, 29, 0 ], "overmap": "rock_border" }, + { "point": [ 0, 30, 0 ], "overmap": "rock_border" }, + { "point": [ 0, 31, 0 ], "overmap": "rock_border" }, + { "point": [ 0, 32, 0 ], "overmap": "rock_border" }, + { "point": [ 0, 33, 0 ], "overmap": "rock_border" }, + { "point": [ 0, 34, 0 ], "overmap": "rock_border" }, + { "point": [ 0, 35, 0 ], "overmap": "rock_border" }, + { "point": [ 0, 36, 0 ], "overmap": "rock_border" }, + { "point": [ 0, 37, 0 ], "overmap": "rock_border" }, + { "point": [ 0, 38, 0 ], "overmap": "rock_border" }, + { "point": [ 0, 39, 0 ], "overmap": "rock_border" }, + { "point": [ 0, 40, 0 ], "overmap": "rock_border" }, + { "point": [ 0, 41, 0 ], "overmap": "rock_border" }, + { "point": [ 0, 42, 0 ], "overmap": "rock_border" }, + { "point": [ 0, 43, 0 ], "overmap": "rock_border" }, + { "point": [ 0, 44, 0 ], "overmap": "rock_border" }, + { "point": [ 0, 45, 0 ], "overmap": "rock_border" }, + { "point": [ 0, 46, 0 ], "overmap": "rock_border" }, + { "point": [ 0, 47, 0 ], "overmap": "rock_border" }, + { "point": [ 0, 48, 0 ], "overmap": "rock_border" }, + { "point": [ 0, 49, 0 ], "overmap": "rock_border" }, + { "point": [ 0, 50, 0 ], "overmap": "rock_border" }, + { "point": [ 0, 51, 0 ], "overmap": "rock_border" }, + { "point": [ 0, 52, 0 ], "overmap": "rock_border" }, + { "point": [ 0, 53, 0 ], "overmap": "rock_border" }, + { "point": [ 0, 54, 0 ], "overmap": "rock_border" }, + { "point": [ 0, 55, 0 ], "overmap": "rock_border" }, + { "point": [ 0, 56, 0 ], "overmap": "rock_border" }, + { "point": [ 0, 57, 0 ], "overmap": "rock_border" }, + { "point": [ 0, 58, 0 ], "overmap": "rock_border" }, + { "point": [ 0, 59, 0 ], "overmap": "rock_border" }, + { "point": [ 0, 60, 0 ], "overmap": "rock_border" }, + { "point": [ 0, 61, 0 ], "overmap": "rock_border" }, + { "point": [ 0, 62, 0 ], "overmap": "rock_border" }, + { "point": [ 0, 63, 0 ], "overmap": "rock_border" }, + { "point": [ 0, 64, 0 ], "overmap": "rock_border" }, + { "point": [ 0, 65, 0 ], "overmap": "rock_border" }, + { "point": [ 0, 66, 0 ], "overmap": "rock_border" }, + { "point": [ 0, 67, 0 ], "overmap": "rock_border" }, + { "point": [ 0, 68, 0 ], "overmap": "rock_border" }, + { "point": [ 0, 69, 0 ], "overmap": "rock_border" }, + { "point": [ 0, 70, 0 ], "overmap": "rock_border" }, + { "point": [ 0, 71, 0 ], "overmap": "rock_border" }, + { "point": [ 0, 72, 0 ], "overmap": "rock_border" }, + { "point": [ 0, 73, 0 ], "overmap": "rock_border" }, + { "point": [ 0, 74, 0 ], "overmap": "rock_border" }, + { "point": [ 0, 75, 0 ], "overmap": "rock_border" }, + { "point": [ 0, 76, 0 ], "overmap": "rock_border" }, + { "point": [ 0, 77, 0 ], "overmap": "rock_border" }, + { "point": [ 0, 78, 0 ], "overmap": "rock_border" }, + { "point": [ 0, 79, 0 ], "overmap": "rock_border" }, + { "point": [ 0, 80, 0 ], "overmap": "rock_border" }, + { "point": [ 0, 81, 0 ], "overmap": "rock_border" }, + { "point": [ 0, 82, 0 ], "overmap": "rock_border" }, + { "point": [ 0, 83, 0 ], "overmap": "rock_border" }, + { "point": [ 0, 84, 0 ], "overmap": "rock_border" }, + { "point": [ 0, 85, 0 ], "overmap": "rock_border" }, + { "point": [ 0, 86, 0 ], "overmap": "rock_border" }, + { "point": [ 0, 87, 0 ], "overmap": "rock_border" }, + { "point": [ 0, 88, 0 ], "overmap": "rock_border" }, + { "point": [ 0, 89, 0 ], "overmap": "rock_border" }, + { "point": [ 0, 90, 0 ], "overmap": "rock_border" }, + { "point": [ 0, 91, 0 ], "overmap": "rock_border" }, + { "point": [ 0, 92, 0 ], "overmap": "rock_border" }, + { "point": [ 0, 93, 0 ], "overmap": "rock_border" }, + { "point": [ 0, 94, 0 ], "overmap": "rock_border" }, + { "point": [ 0, 95, 0 ], "overmap": "rock_border" }, + { "point": [ 0, 96, 0 ], "overmap": "rock_border" }, + { "point": [ 0, 97, 0 ], "overmap": "rock_border" }, + { "point": [ 0, 98, 0 ], "overmap": "rock_border" }, + { "point": [ 0, 99, 0 ], "overmap": "rock_border" }, + { "point": [ 0, 100, 0 ], "overmap": "rock_border" }, + { "point": [ 0, 101, 0 ], "overmap": "rock_border" }, + { "point": [ 0, 102, 0 ], "overmap": "rock_border" }, + { "point": [ 0, 103, 0 ], "overmap": "rock_border" }, + { "point": [ 0, 104, 0 ], "overmap": "rock_border" }, + { "point": [ 0, 105, 0 ], "overmap": "rock_border" }, + { "point": [ 0, 106, 0 ], "overmap": "rock_border" }, + { "point": [ 0, 107, 0 ], "overmap": "rock_border" }, + { "point": [ 0, 108, 0 ], "overmap": "rock_border" }, + { "point": [ 0, 109, 0 ], "overmap": "rock_border" }, + { "point": [ 0, 110, 0 ], "overmap": "rock_border" }, + { "point": [ 0, 111, 0 ], "overmap": "rock_border" }, + { "point": [ 0, 112, 0 ], "overmap": "rock_border" }, + { "point": [ 0, 113, 0 ], "overmap": "rock_border" }, + { "point": [ 0, 114, 0 ], "overmap": "rock_border" }, + { "point": [ 0, 115, 0 ], "overmap": "rock_border" }, + { "point": [ 0, 116, 0 ], "overmap": "rock_border" }, + { "point": [ 0, 117, 0 ], "overmap": "rock_border" }, + { "point": [ 0, 118, 0 ], "overmap": "rock_border" }, + { "point": [ 0, 119, 0 ], "overmap": "rock_border" }, + { "point": [ 0, 120, 0 ], "overmap": "rock_border" }, + { "point": [ 0, 121, 0 ], "overmap": "rock_border" }, + { "point": [ 0, 122, 0 ], "overmap": "rock_border" }, + { "point": [ 0, 123, 0 ], "overmap": "rock_border" }, + { "point": [ 0, 124, 0 ], "overmap": "rock_border" }, + { "point": [ 0, 125, 0 ], "overmap": "rock_border" }, + { "point": [ 0, 126, 0 ], "overmap": "rock_border" }, + { "point": [ 0, 127, 0 ], "overmap": "rock_border" }, + { "point": [ 0, 128, 0 ], "overmap": "rock_border" }, + { "point": [ 0, 129, 0 ], "overmap": "rock_border" }, + { "point": [ 0, 130, 0 ], "overmap": "rock_border" }, + { "point": [ 0, 131, 0 ], "overmap": "rock_border" }, + { "point": [ 0, 132, 0 ], "overmap": "rock_border" }, + { "point": [ 0, 133, 0 ], "overmap": "rock_border" }, + { "point": [ 0, 134, 0 ], "overmap": "rock_border" }, + { "point": [ 0, 135, 0 ], "overmap": "rock_border" }, + { "point": [ 0, 136, 0 ], "overmap": "rock_border" }, + { "point": [ 0, 137, 0 ], "overmap": "rock_border" }, + { "point": [ 0, 138, 0 ], "overmap": "rock_border" }, + { "point": [ 0, 139, 0 ], "overmap": "rock_border" }, + { "point": [ 0, 140, 0 ], "overmap": "rock_border" }, + { "point": [ 0, 141, 0 ], "overmap": "rock_border" }, + { "point": [ 0, 142, 0 ], "overmap": "rock_border" }, + { "point": [ 0, 143, 0 ], "overmap": "rock_border" }, + { "point": [ 0, 144, 0 ], "overmap": "rock_border" }, + { "point": [ 0, 145, 0 ], "overmap": "rock_border" }, + { "point": [ 0, 146, 0 ], "overmap": "rock_border" }, + { "point": [ 0, 147, 0 ], "overmap": "rock_border" }, + { "point": [ 0, 148, 0 ], "overmap": "rock_border" }, + { "point": [ 0, 149, 0 ], "overmap": "rock_border" }, + { "point": [ 0, 150, 0 ], "overmap": "rock_border" }, + { "point": [ 0, 151, 0 ], "overmap": "rock_border" }, + { "point": [ 0, 152, 0 ], "overmap": "rock_border" }, + { "point": [ 0, 153, 0 ], "overmap": "rock_border" }, + { "point": [ 0, 154, 0 ], "overmap": "rock_border" }, + { "point": [ 0, 155, 0 ], "overmap": "rock_border" }, + { "point": [ 0, 156, 0 ], "overmap": "rock_border" }, + { "point": [ 0, 157, 0 ], "overmap": "rock_border" }, + { "point": [ 0, 158, 0 ], "overmap": "rock_border" }, + { "point": [ 0, 159, 0 ], "overmap": "rock_border" }, + { "point": [ 0, 160, 0 ], "overmap": "rock_border" }, + { "point": [ 0, 161, 0 ], "overmap": "rock_border" }, + { "point": [ 0, 162, 0 ], "overmap": "rock_border" }, + { "point": [ 0, 163, 0 ], "overmap": "rock_border" }, + { "point": [ 0, 164, 0 ], "overmap": "rock_border" }, + { "point": [ 0, 165, 0 ], "overmap": "rock_border" }, + { "point": [ 0, 166, 0 ], "overmap": "rock_border" }, + { "point": [ 0, 167, 0 ], "overmap": "rock_border" }, + { "point": [ 0, 168, 0 ], "overmap": "rock_border" }, + { "point": [ 0, 169, 0 ], "overmap": "rock_border" }, + { "point": [ 0, 170, 0 ], "overmap": "rock_border" }, + { "point": [ 0, 171, 0 ], "overmap": "rock_border" }, + { "point": [ 0, 172, 0 ], "overmap": "rock_border" }, + { "point": [ 0, 173, 0 ], "overmap": "rock_border" }, + { "point": [ 0, 174, 0 ], "overmap": "rock_border" }, + { "point": [ 0, 175, 0 ], "overmap": "rock_border" }, + { "point": [ 0, 176, 0 ], "overmap": "rock_border" }, + { "point": [ 0, 177, 0 ], "overmap": "rock_border" }, + { "point": [ 0, 178, 0 ], "overmap": "rock_border" }, + { "point": [ 0, 179, 0 ], "overmap": "rock_border" }, + { "point": [ 179, 1, 0 ], "overmap": "rock_border" }, + { "point": [ 179, 2, 0 ], "overmap": "rock_border" }, + { "point": [ 179, 3, 0 ], "overmap": "rock_border" }, + { "point": [ 179, 4, 0 ], "overmap": "rock_border" }, + { "point": [ 179, 5, 0 ], "overmap": "rock_border" }, + { "point": [ 179, 6, 0 ], "overmap": "rock_border" }, + { "point": [ 179, 7, 0 ], "overmap": "rock_border" }, + { "point": [ 179, 8, 0 ], "overmap": "rock_border" }, + { "point": [ 179, 9, 0 ], "overmap": "rock_border" }, + { "point": [ 179, 10, 0 ], "overmap": "rock_border" }, + { "point": [ 179, 11, 0 ], "overmap": "rock_border" }, + { "point": [ 179, 12, 0 ], "overmap": "rock_border" }, + { "point": [ 179, 13, 0 ], "overmap": "rock_border" }, + { "point": [ 179, 14, 0 ], "overmap": "rock_border" }, + { "point": [ 179, 15, 0 ], "overmap": "rock_border" }, + { "point": [ 179, 16, 0 ], "overmap": "rock_border" }, + { "point": [ 179, 17, 0 ], "overmap": "rock_border" }, + { "point": [ 179, 18, 0 ], "overmap": "rock_border" }, + { "point": [ 179, 19, 0 ], "overmap": "rock_border" }, + { "point": [ 179, 20, 0 ], "overmap": "rock_border" }, + { "point": [ 179, 21, 0 ], "overmap": "rock_border" }, + { "point": [ 179, 22, 0 ], "overmap": "rock_border" }, + { "point": [ 179, 23, 0 ], "overmap": "rock_border" }, + { "point": [ 179, 24, 0 ], "overmap": "rock_border" }, + { "point": [ 179, 25, 0 ], "overmap": "rock_border" }, + { "point": [ 179, 26, 0 ], "overmap": "rock_border" }, + { "point": [ 179, 27, 0 ], "overmap": "rock_border" }, + { "point": [ 179, 28, 0 ], "overmap": "rock_border" }, + { "point": [ 179, 29, 0 ], "overmap": "rock_border" }, + { "point": [ 179, 30, 0 ], "overmap": "rock_border" }, + { "point": [ 179, 31, 0 ], "overmap": "rock_border" }, + { "point": [ 179, 32, 0 ], "overmap": "rock_border" }, + { "point": [ 179, 33, 0 ], "overmap": "rock_border" }, + { "point": [ 179, 34, 0 ], "overmap": "rock_border" }, + { "point": [ 179, 35, 0 ], "overmap": "rock_border" }, + { "point": [ 179, 36, 0 ], "overmap": "rock_border" }, + { "point": [ 179, 37, 0 ], "overmap": "rock_border" }, + { "point": [ 179, 38, 0 ], "overmap": "rock_border" }, + { "point": [ 179, 39, 0 ], "overmap": "rock_border" }, + { "point": [ 179, 40, 0 ], "overmap": "rock_border" }, + { "point": [ 179, 41, 0 ], "overmap": "rock_border" }, + { "point": [ 179, 42, 0 ], "overmap": "rock_border" }, + { "point": [ 179, 43, 0 ], "overmap": "rock_border" }, + { "point": [ 179, 44, 0 ], "overmap": "rock_border" }, + { "point": [ 179, 45, 0 ], "overmap": "rock_border" }, + { "point": [ 179, 46, 0 ], "overmap": "rock_border" }, + { "point": [ 179, 47, 0 ], "overmap": "rock_border" }, + { "point": [ 179, 48, 0 ], "overmap": "rock_border" }, + { "point": [ 179, 49, 0 ], "overmap": "rock_border" }, + { "point": [ 179, 50, 0 ], "overmap": "rock_border" }, + { "point": [ 179, 51, 0 ], "overmap": "rock_border" }, + { "point": [ 179, 52, 0 ], "overmap": "rock_border" }, + { "point": [ 179, 53, 0 ], "overmap": "rock_border" }, + { "point": [ 179, 54, 0 ], "overmap": "rock_border" }, + { "point": [ 179, 55, 0 ], "overmap": "rock_border" }, + { "point": [ 179, 56, 0 ], "overmap": "rock_border" }, + { "point": [ 179, 57, 0 ], "overmap": "rock_border" }, + { "point": [ 179, 58, 0 ], "overmap": "rock_border" }, + { "point": [ 179, 59, 0 ], "overmap": "rock_border" }, + { "point": [ 179, 60, 0 ], "overmap": "rock_border" }, + { "point": [ 179, 61, 0 ], "overmap": "rock_border" }, + { "point": [ 179, 62, 0 ], "overmap": "rock_border" }, + { "point": [ 179, 63, 0 ], "overmap": "rock_border" }, + { "point": [ 179, 64, 0 ], "overmap": "rock_border" }, + { "point": [ 179, 65, 0 ], "overmap": "rock_border" }, + { "point": [ 179, 66, 0 ], "overmap": "rock_border" }, + { "point": [ 179, 67, 0 ], "overmap": "rock_border" }, + { "point": [ 179, 68, 0 ], "overmap": "rock_border" }, + { "point": [ 179, 69, 0 ], "overmap": "rock_border" }, + { "point": [ 179, 70, 0 ], "overmap": "rock_border" }, + { "point": [ 179, 71, 0 ], "overmap": "rock_border" }, + { "point": [ 179, 72, 0 ], "overmap": "rock_border" }, + { "point": [ 179, 73, 0 ], "overmap": "rock_border" }, + { "point": [ 179, 74, 0 ], "overmap": "rock_border" }, + { "point": [ 179, 75, 0 ], "overmap": "rock_border" }, + { "point": [ 179, 76, 0 ], "overmap": "rock_border" }, + { "point": [ 179, 77, 0 ], "overmap": "rock_border" }, + { "point": [ 179, 78, 0 ], "overmap": "rock_border" }, + { "point": [ 179, 79, 0 ], "overmap": "rock_border" }, + { "point": [ 179, 80, 0 ], "overmap": "rock_border" }, + { "point": [ 179, 81, 0 ], "overmap": "rock_border" }, + { "point": [ 179, 82, 0 ], "overmap": "rock_border" }, + { "point": [ 179, 83, 0 ], "overmap": "rock_border" }, + { "point": [ 179, 84, 0 ], "overmap": "rock_border" }, + { "point": [ 179, 85, 0 ], "overmap": "rock_border" }, + { "point": [ 179, 86, 0 ], "overmap": "rock_border" }, + { "point": [ 179, 87, 0 ], "overmap": "rock_border" }, + { "point": [ 179, 88, 0 ], "overmap": "rock_border" }, + { "point": [ 179, 89, 0 ], "overmap": "rock_border" }, + { "point": [ 179, 90, 0 ], "overmap": "rock_border" }, + { "point": [ 179, 91, 0 ], "overmap": "rock_border" }, + { "point": [ 179, 92, 0 ], "overmap": "rock_border" }, + { "point": [ 179, 93, 0 ], "overmap": "rock_border" }, + { "point": [ 179, 94, 0 ], "overmap": "rock_border" }, + { "point": [ 179, 95, 0 ], "overmap": "rock_border" }, + { "point": [ 179, 96, 0 ], "overmap": "rock_border" }, + { "point": [ 179, 97, 0 ], "overmap": "rock_border" }, + { "point": [ 179, 98, 0 ], "overmap": "rock_border" }, + { "point": [ 179, 99, 0 ], "overmap": "rock_border" }, + { "point": [ 179, 100, 0 ], "overmap": "rock_border" }, + { "point": [ 179, 101, 0 ], "overmap": "rock_border" }, + { "point": [ 179, 102, 0 ], "overmap": "rock_border" }, + { "point": [ 179, 103, 0 ], "overmap": "rock_border" }, + { "point": [ 179, 104, 0 ], "overmap": "rock_border" }, + { "point": [ 179, 105, 0 ], "overmap": "rock_border" }, + { "point": [ 179, 106, 0 ], "overmap": "rock_border" }, + { "point": [ 179, 107, 0 ], "overmap": "rock_border" }, + { "point": [ 179, 108, 0 ], "overmap": "rock_border" }, + { "point": [ 179, 109, 0 ], "overmap": "rock_border" }, + { "point": [ 179, 110, 0 ], "overmap": "rock_border" }, + { "point": [ 179, 111, 0 ], "overmap": "rock_border" }, + { "point": [ 179, 112, 0 ], "overmap": "rock_border" }, + { "point": [ 179, 113, 0 ], "overmap": "rock_border" }, + { "point": [ 179, 114, 0 ], "overmap": "rock_border" }, + { "point": [ 179, 115, 0 ], "overmap": "rock_border" }, + { "point": [ 179, 116, 0 ], "overmap": "rock_border" }, + { "point": [ 179, 117, 0 ], "overmap": "rock_border" }, + { "point": [ 179, 118, 0 ], "overmap": "rock_border" }, + { "point": [ 179, 119, 0 ], "overmap": "rock_border" }, + { "point": [ 179, 120, 0 ], "overmap": "rock_border" }, + { "point": [ 179, 121, 0 ], "overmap": "rock_border" }, + { "point": [ 179, 122, 0 ], "overmap": "rock_border" }, + { "point": [ 179, 123, 0 ], "overmap": "rock_border" }, + { "point": [ 179, 124, 0 ], "overmap": "rock_border" }, + { "point": [ 179, 125, 0 ], "overmap": "rock_border" }, + { "point": [ 179, 126, 0 ], "overmap": "rock_border" }, + { "point": [ 179, 127, 0 ], "overmap": "rock_border" }, + { "point": [ 179, 128, 0 ], "overmap": "rock_border" }, + { "point": [ 179, 129, 0 ], "overmap": "rock_border" }, + { "point": [ 179, 130, 0 ], "overmap": "rock_border" }, + { "point": [ 179, 131, 0 ], "overmap": "rock_border" }, + { "point": [ 179, 132, 0 ], "overmap": "rock_border" }, + { "point": [ 179, 133, 0 ], "overmap": "rock_border" }, + { "point": [ 179, 134, 0 ], "overmap": "rock_border" }, + { "point": [ 179, 135, 0 ], "overmap": "rock_border" }, + { "point": [ 179, 136, 0 ], "overmap": "rock_border" }, + { "point": [ 179, 137, 0 ], "overmap": "rock_border" }, + { "point": [ 179, 138, 0 ], "overmap": "rock_border" }, + { "point": [ 179, 139, 0 ], "overmap": "rock_border" }, + { "point": [ 179, 140, 0 ], "overmap": "rock_border" }, + { "point": [ 179, 141, 0 ], "overmap": "rock_border" }, + { "point": [ 179, 142, 0 ], "overmap": "rock_border" }, + { "point": [ 179, 143, 0 ], "overmap": "rock_border" }, + { "point": [ 179, 144, 0 ], "overmap": "rock_border" }, + { "point": [ 179, 145, 0 ], "overmap": "rock_border" }, + { "point": [ 179, 146, 0 ], "overmap": "rock_border" }, + { "point": [ 179, 147, 0 ], "overmap": "rock_border" }, + { "point": [ 179, 148, 0 ], "overmap": "rock_border" }, + { "point": [ 179, 149, 0 ], "overmap": "rock_border" }, + { "point": [ 179, 150, 0 ], "overmap": "rock_border" }, + { "point": [ 179, 151, 0 ], "overmap": "rock_border" }, + { "point": [ 179, 152, 0 ], "overmap": "rock_border" }, + { "point": [ 179, 153, 0 ], "overmap": "rock_border" }, + { "point": [ 179, 154, 0 ], "overmap": "rock_border" }, + { "point": [ 179, 155, 0 ], "overmap": "rock_border" }, + { "point": [ 179, 156, 0 ], "overmap": "rock_border" }, + { "point": [ 179, 157, 0 ], "overmap": "rock_border" }, + { "point": [ 179, 158, 0 ], "overmap": "rock_border" }, + { "point": [ 179, 159, 0 ], "overmap": "rock_border" }, + { "point": [ 179, 160, 0 ], "overmap": "rock_border" }, + { "point": [ 179, 161, 0 ], "overmap": "rock_border" }, + { "point": [ 179, 162, 0 ], "overmap": "rock_border" }, + { "point": [ 179, 163, 0 ], "overmap": "rock_border" }, + { "point": [ 179, 164, 0 ], "overmap": "rock_border" }, + { "point": [ 179, 165, 0 ], "overmap": "rock_border" }, + { "point": [ 179, 166, 0 ], "overmap": "rock_border" }, + { "point": [ 179, 167, 0 ], "overmap": "rock_border" }, + { "point": [ 179, 168, 0 ], "overmap": "rock_border" }, + { "point": [ 179, 169, 0 ], "overmap": "rock_border" }, + { "point": [ 179, 170, 0 ], "overmap": "rock_border" }, + { "point": [ 179, 171, 0 ], "overmap": "rock_border" }, + { "point": [ 179, 172, 0 ], "overmap": "rock_border" }, + { "point": [ 179, 173, 0 ], "overmap": "rock_border" }, + { "point": [ 179, 174, 0 ], "overmap": "rock_border" }, + { "point": [ 179, 175, 0 ], "overmap": "rock_border" }, + { "point": [ 179, 176, 0 ], "overmap": "rock_border" }, + { "point": [ 179, 177, 0 ], "overmap": "rock_border" }, + { "point": [ 179, 178, 0 ], "overmap": "rock_border" } + ], + "locations": [ "land" ], + "//": "This location should never spawn naturally, only on top of existing locations when playing the scenarios with BORDERED flag.", + "occurrences": [ 0, 0 ] + } +] diff --git a/data/json/overmap/overmap_terrain/overmap_terrain.json b/data/json/overmap/overmap_terrain/overmap_terrain.json index 171b70dada0cf..c1f37fd273478 100644 --- a/data/json/overmap/overmap_terrain/overmap_terrain.json +++ b/data/json/overmap/overmap_terrain/overmap_terrain.json @@ -711,5 +711,13 @@ "sym": "O", "color": "brown", "see_cost": 2 + }, + { + "type": "overmap_terrain", + "id": "rock_border", + "name": "rock border", + "sym": "#", + "color": "white", + "flags": [ "NO_ROTATE" ] } ] diff --git a/data/json/scenarios.json b/data/json/scenarios.json index 634bcf79b105f..02c6451c1cbf0 100644 --- a/data/json/scenarios.json +++ b/data/json/scenarios.json @@ -284,6 +284,16 @@ "allowed_locs": [ "sloc_lab_random", "sloc_lab_escape_cells", "sloc_lab_finale", "sloc_ice_lab_stairs", "sloc_ice_lab_finale" ], "flags": [ "CHALLENGE", "CITY_START", "LONE_START" ] }, + { + "type": "scenario", + "id": "bordered", + "name": "Challenge - Bordered", + "points": -2, + "description": "You have survived the initial wave of panic, and have achieved (relative) safety in one of the many government evac shelters. The only thing that really bothers you is a mysterious sky-high wall seen in the distance.", + "allowed_locs": [ "sloc_shelter_a", "sloc_shelter_b", "sloc_shelter_c" ], + "start_name": "Evac Shelter", + "flags": [ "CHALLENGE", "CITY_START", "BORDERED" ] + }, { "type": "scenario", "id": "ambushed", diff --git a/doc/JSON_FLAGS.md b/doc/JSON_FLAGS.md index 036e6a3919e63..060d4be3f3f06 100644 --- a/doc/JSON_FLAGS.md +++ b/doc/JSON_FLAGS.md @@ -1253,6 +1253,7 @@ These branches are also the valid entries for the categories of `dreams` in `dre ### Flags - ```BAD_DAY``` Player starts the game drunk, depressed and sick with the flu. +- ```BORDERED``` Initial start location is bordered by an enormous wall of solid rock. - ```CHALLENGE``` Game won't choose this scenario in random game types. - ```CITY_START``` Scenario is available only when city size value in world options is more than 0. - ```FIRE_START``` Player starts the game with fire nearby. diff --git a/src/game.cpp b/src/game.cpp index ecf9b621914f7..05b90607081be 100644 --- a/src/game.cpp +++ b/src/game.cpp @@ -816,6 +816,14 @@ bool game::start_game() } } } + if( scen->has_flag( "BORDERED" ) ) { + overmap &starting_om = get_cur_om(); + for( int z = -OVERMAP_DEPTH; z <= OVERMAP_HEIGHT; z++ ) { + starting_om.place_special_forced( overmap_special_id( "world" ), { 0, 0, z }, + om_direction::type::north ); + } + + } for( auto &e : u.inv_dump() ) { e->set_owner( get_player_character() ); } diff --git a/src/newcharacter.cpp b/src/newcharacter.cpp index 2e1d0b637866f..17face50e0330 100644 --- a/src/newcharacter.cpp +++ b/src/newcharacter.cpp @@ -2509,6 +2509,10 @@ tab_direction set_scenario( avatar &u, points_left &points, wprintz( w_flags, c_light_gray, _( "No starting NPC" ) ); wprintz( w_flags, c_light_gray, ( "\n" ) ); } + if( sorted_scens[cur_id]->has_flag( "BORDERED" ) ) { + wprintz( w_flags, c_light_gray, _( "Starting location is bordered by an immense wall" ) ); + wprintz( w_flags, c_light_gray, ( "\n" ) ); + } } draw_scrollbar( w, cur_id, iContentHeight, scens_length, point( 0, 5 ) ); From 89eb9f32cea78fad6fff91ad3fa5748ecead8c26 Mon Sep 17 00:00:00 2001 From: Venera3 <72006894+Venera3@users.noreply.github.com> Date: Fri, 28 May 2021 12:39:00 +0200 Subject: [PATCH 446/453] Add proper wasp nests (#48161) --- .../terrain-floors-indoor.json | 77 +++- .../furniture_and_terrain/terrain-roofs.json | 22 ++ .../furniture_and_terrain/terrain-walls.json | 39 +- .../monster_drops_lairs.json | 79 ++++ data/json/mapgen/bugs/wasp_tower.json | 360 ++++++++++++++++++ data/json/mapgen/radio_tower.json | 20 +- data/json/mapgen_palettes/wasp_palette.json | 144 +++++++ .../overmap/overmap_special/specials.json | 44 ++- .../overmap_terrain/overmap_terrain.json | 21 +- 9 files changed, 800 insertions(+), 6 deletions(-) create mode 100644 data/json/mapgen/bugs/wasp_tower.json create mode 100644 data/json/mapgen_palettes/wasp_palette.json diff --git a/data/json/furniture_and_terrain/terrain-floors-indoor.json b/data/json/furniture_and_terrain/terrain-floors-indoor.json index 8af1e8d7a55ea..28f171cfee5db 100644 --- a/data/json/furniture_and_terrain/terrain-floors-indoor.json +++ b/data/json/furniture_and_terrain/terrain-floors-indoor.json @@ -877,7 +877,82 @@ "sound_fail": "slap!", "sound_vol": 8, "sound_fail_vol": 4, - "ter_set": "t_dirt" + "ter_set": "t_null" } + }, + { + "type": "terrain", + "id": "t_floor_paper_noroof", + "name": "paper floor", + "description": "Floor made of pulpy mass, covered in sticky wasp saliva.", + "symbol": ".", + "looks_like": "t_dirt", + "color": "white", + "move_cost": 2, + "flags": [ "TRANSPARENT", "FLAMMABLE_ASH", "INDOORS", "FLAT", "ROAD" ], + "bash": { + "str_min": 1, + "str_max": 6, + "sound": "rrrrip!", + "sound_fail": "slap!", + "sound_vol": 8, + "sound_fail_vol": 4, + "ter_set": "t_open_air" + } + }, + { + "type": "terrain", + "id": "t_floor_paper_hard", + "name": "hard paper floor", + "description": "Hardened cardboard floor made of chewed up trees and resin mixed with wasp saliva.", + "symbol": ".", + "looks_like": "t_floor_paper", + "color": "light_gray", + "move_cost": 2, + "flags": [ "TRANSPARENT", "FLAMMABLE_HARD", "INDOORS", "FLAT" ], + "bash": { + "str_min": 15, + "str_max": 150, + "str_min_supported": 30, + "sound": "rrrrip!", + "sound_fail": "slap!", + "sound_vol": 10, + "sound_fail_vol": 6, + "ter_set": "t_open_air" + } + }, + { + "type": "terrain", + "id": "t_floor_brood_wasp", + "name": "paper brood cap", + "description": "A thin paper floor, protecting the pupatig wasp larva until it's ready to emerge.", + "looks_like": "t_floor_paper", + "symbol": ".", + "color": "white", + "move_cost": 2, + "flags": [ "TRANSPARENT", "FLAMMABLE_ASH", "INDOORS", "NO_FLOOR" ], + "bash": { + "str_min": 1, + "str_max": 6, + "sound": "rrrrip!", + "sound_fail": "slap!", + "sound_vol": 8, + "sound_fail_vol": 4, + "ter_set": "t_open_air" + } + }, + { + "type": "terrain", + "id": "t_floor_brood_fake", + "name": "open air", + "description": "This is open air.", + "//": "Actually, this is a thin membrane of bullshit to keep wasp eggs levitating.", + "symbol": " ", + "looks_like": "t_open_air", + "color": "i_cyan", + "move_cost": 2, + "trap": "tr_ledge", + "flags": [ "TRANSPARENT" ], + "examine_action": "ledge" } ] diff --git a/data/json/furniture_and_terrain/terrain-roofs.json b/data/json/furniture_and_terrain/terrain-roofs.json index 9557141b6151e..877a7fe5416cf 100644 --- a/data/json/furniture_and_terrain/terrain-roofs.json +++ b/data/json/furniture_and_terrain/terrain-roofs.json @@ -354,5 +354,27 @@ "ter_set": "t_open_air", "bash_below": true } + }, + { + "type": "terrain", + "id": "t_roof_paper_hard", + "name": "flat roof", + "description": "A flat surface made of hardened pulpy mass, covered in sticky wasp saliva.", + "symbol": ".", + "looks_like": "t_paper", + "color": "white", + "move_cost": 2, + "flags": [ "TRANSPARENT", "FLAMMABLE_HARD", "FLAT" ], + "bash": { + "str_min": 25, + "str_max": 150, + "str_min_supported": 40, + "sound": "rrrrip!", + "sound_fail": "slap!", + "sound_vol": 15, + "sound_fail_vol": 10, + "ter_set": "t_open_air", + "bash_below": true + } } ] diff --git a/data/json/furniture_and_terrain/terrain-walls.json b/data/json/furniture_and_terrain/terrain-walls.json index 488e38d1d221d..bdbc377be1f88 100644 --- a/data/json/furniture_and_terrain/terrain-walls.json +++ b/data/json/furniture_and_terrain/terrain-walls.json @@ -1160,7 +1160,44 @@ "sound_fail": "slap!", "sound_vol": 8, "sound_fail_vol": 4, - "ter_set": "t_null" + "ter_set": "t_floor_paper" + } + }, + { + "type": "terrain", + "id": "t_paper_brood", + "copy-from": "t_paper", + "symbol": "#", + "color": "white", + "flags": [ "FLAMMABLE_ASH", "NOITEM", "WALL", "NO_SCENT" ], + "bash": { + "str_min": 1, + "str_max": 6, + "sound": "rrrrip!", + "sound_fail": "slap!", + "sound_vol": 8, + "sound_fail_vol": 4, + "ter_set": "t_floor_paper_noroof" + } + }, + { + "type": "terrain", + "id": "t_paper_hard", + "name": "layered paper wall", + "description": "A thick wall of layered tree pulp and wasp saliva, hardened to withstand the elements. You could break through this, but it won't be easy.", + "symbol": "#", + "color": "dark_gray", + "move_cost": 0, + "coverage": 100, + "flags": [ "FLAMMABLE_HARD", "NOITEM", "MINEABLE", "WALL", "NO_SCENT" ], + "bash": { + "str_min": 30, + "str_max": 150, + "sound": "rrrrip!", + "sound_fail": "slap!", + "sound_vol": 20, + "sound_fail_vol": 10, + "ter_set": "t_floor_paper_hard" } }, { diff --git a/data/json/itemgroups/Monsters_Animals_Lairs/monster_drops_lairs.json b/data/json/itemgroups/Monsters_Animals_Lairs/monster_drops_lairs.json index 51ffb7422cfda..65683bdea1a6e 100644 --- a/data/json/itemgroups/Monsters_Animals_Lairs/monster_drops_lairs.json +++ b/data/json/itemgroups/Monsters_Animals_Lairs/monster_drops_lairs.json @@ -290,6 +290,85 @@ { "item": "beekeeping_gloves", "prob": 5 } ] }, + { + "type": "item_group", + "id": "bug_parts", + "//": "Bug butchery remains", + "subtype": "distribution", + "entries": [ + { "item": "chitin_piece", "prob": 70 }, + { "item": "acidchitin_piece", "prob": 30 }, + { "item": "endochitin", "prob": 70 }, + { "item": "mutant_bug_hydrogen_sacs", "prob": 30 }, + { "item": "mutant_bug_lungs", "prob": 10 }, + { "item": "mutant_bug_organs", "prob": 10 }, + { "item": "sinew", "prob": 10 }, + { "item": "bee_sting", "prob": 10 } + ] + }, + { + "type": "item_group", + "id": "vertebrate_parts", + "//": "Normal/mutated animal remains", + "subtype": "distribution", + "entries": [ + { "item": "bone", "prob": 80 }, + { "item": "feather", "prob": 80 }, + { "item": "raw_leather", "prob": 30 }, + { "item": "raw_fur", "prob": 30 }, + { "item": "wool_staple", "prob": 30 }, + { "item": "sinew", "prob": 5 }, + { "item": "brain", "prob": 5 }, + { "item": "lung", "prob": 5 }, + { "item": "liver", "prob": 5 }, + { "item": "sweetbread", "prob": 5 }, + { "item": "stomach", "prob": 5 }, + { "item": "stomach_large", "prob": 5 }, + { "item": "kidney", "prob": 5 }, + { "item": "jabberwock_heart", "prob": 1 } + ] + }, + { + "type": "item_group", + "id": "human_parts", + "//": "(demi)human remains", + "subtype": "distribution", + "entries": [ + { "item": "bone_human", "prob": 80 }, + { "item": "raw_hleather", "prob": 30 }, + { "item": "raw_demihumanleather", "prob": 5 }, + { "item": "raw_hfur", "prob": 1 }, + { "item": "sinew", "prob": 5 }, + { "item": "hstomach", "prob": 5 }, + { "item": "demihuman_stomach", "prob": 1 }, + { "item": "hstomach_large", "prob": 5 }, + { "item": "demihuman_stomach_large", "prob": 1 } + ] + }, + { + "type": "item_group", + "id": "wasp_lair", + "//": "Damaged generic/military/science drops, nothing fancy", + "subtype": "distribution", + "ammo": 10, + "entries": [ + { "group": "allclothes", "damage": [ 2, 4 ], "prob": 150 }, + { "group": "clothing_outdoor_set", "damage": [ 2, 4 ], "prob": 10 }, + { "group": "clothing_hunting", "damage": [ 2, 4 ], "prob": 10 }, + { "group": "clothing_work_set", "damage": [ 2, 4 ], "prob": 10 }, + { "group": "everyday_gear", "damage": [ 2, 4 ], "prob": 50 }, + { "group": "gear_homeless", "damage": [ 2, 4 ], "prob": 30 }, + { "group": "child_items", "damage": [ 2, 4 ], "prob": 30 }, + { "group": "traveler", "damage": [ 2, 4 ], "prob": 10 }, + { "group": "default_zombie_clothes", "damage": [ 2, 4 ], "prob": 30 }, + { "group": "default_zombie_items_bags", "damage": [ 2, 4 ], "prob": 30 }, + { "group": "default_zombie_items_pockets", "damage": [ 2, 4 ], "prob": 30 }, + { "group": "mon_zombie_scientist_death_drops", "damage": [ 2, 4 ], "prob": 5 }, + { "group": "mon_zombie_labsecurity_death_drops", "damage": [ 2, 4 ], "prob": 5 }, + { "group": "mon_zombie_kevlar_death_drops", "damage": [ 2, 4 ], "prob": 15 }, + { "group": "mon_zombie_military_pilot_death_drops", "damage": [ 2, 4 ], "prob": 5 } + ] + }, { "type": "item_group", "id": "radio", diff --git a/data/json/mapgen/bugs/wasp_tower.json b/data/json/mapgen/bugs/wasp_tower.json new file mode 100644 index 0000000000000..6f1ba77ff6d9c --- /dev/null +++ b/data/json/mapgen/bugs/wasp_tower.json @@ -0,0 +1,360 @@ +[ + { + "type": "mapgen", + "method": "json", + "om_terrain": [ "wasp_tower" ], + "weight": 250, + "object": { + "fill_ter": "t_floor", + "rows": [ + " ---------------------- ", + " | | ", + " | | ", + " | R____R | ", + " |_______ ______ | ", + " |_______ ______ | ", + " |_______ ______ | ", + " |_______ _<____ | ", + " |_______ R____R | ", + " |_______ 6 | ", + " |_______ | ", + " ------22-------------- ", + " ", + " ", + " ", + " ", + " ", + " ", + " ", + " ", + " ", + " ", + " ", + " " + ], + "terrain": { + " ": [ "t_region_groundcover" ], + "#": "t_concrete_wall", + "R": "t_radio_tower", + "2": "t_chaingate_c", + "-": "t_chainfence_h", + "|": "t_chainfence_v", + "6": "t_radio_controls", + "_": "t_pavement", + "<": "t_stairs_up" + }, + "nested": { + " ": { "chunks": [ [ "null", 50 ], [ "wasp_gibs", 10 ] ] }, + "_": { "chunks": [ [ "null", 50 ], [ "wasp_gibs", 10 ] ] } + } + } + }, + { + "type": "mapgen", + "method": "json", + "om_terrain": [ "wasp_tower_1" ], + "weight": 250, + "object": { + "fill_ter": "t_floor", + "rows": [ + " -2222222-------------- ", + " |_______ | ", + " |_______ | ", + " |_______ R____R | ", + " |_______ ______ | ", + " |_______ ______ | ", + " |_______ ______ | ", + " |_______ _<____ | ", + " |_______ R____R | ", + " |___________ | ", + " |___________ | ", + " --------##+########--- ", + " #..ll#rrrC#4 ", + " w....+..h6# ", + " ##+#w#...C# ", + " |R wCCCCw ", + " |----##ww## ", + " ", + " ", + " ", + " ", + " ", + " ", + " " + ], + "terrain": { + " ": [ "t_region_groundcover" ], + "#": "t_concrete_wall", + "R": "t_radio_tower", + "2": "t_chaingate_c", + "-": "t_chainfence_h", + "|": "t_chainfence_v", + "6": "t_radio_controls", + "_": "t_pavement", + "+": [ "t_door_c", [ "t_door_b", 3 ], [ "t_door_frame", 3 ] ], + "4": "t_gutter_downspout", + "<": "t_stairs_up", + "w": [ "t_window", [ "t_window_frame", 3 ], [ "t_window_empty", 3 ] ] + }, + "furniture": { "C": "f_counter", "r": "f_rack", "h": "f_chair", "l": "f_locker" }, + "items": { + "C": { "item": "radio", "chance": 80, "repeat": [ 1, 2 ] }, + "r": { "item": "recycle_electronic", "chance": 80, "repeat": [ 1, 2 ] }, + "l": { "item": "clothing_work_set", "chance": 80 } + }, + "nested": { + " ": { "chunks": [ [ "null", 50 ], [ "wasp_gibs", 10 ] ] }, + "_": { "chunks": [ [ "null", 50 ], [ "wasp_gibs", 10 ] ] } + } + } + }, + { + "type": "mapgen", + "method": "json", + "om_terrain": "wasp_tower_roof_1", + "object": { + "fill_ter": "t_metal_floor_no_roof", + "rows": [ + " ", + " ", + " ", + " R,,,,R ", + " , , ", + " , , ", + " aaaa , ", + " a>": "t_stairs_down" } + } + }, + { + "type": "mapgen", + "method": "json", + "om_terrain": "wasp_tower_even_1", + "object": { + "fill_ter": "t_open_air", + "rows": [ + " ", + " :: ", + " aaaaaaaa ", + " aR,,,,Ra ", + " :a,,,,,,a# ", + " X a,,::,,a ", + " XXXXXa,,::,,a ", + " XX_XXX,<>,XXaX ", + " X___XXR,,,XRXXXX ", + " XX____XXXXXX___XX ", + " XX______________XX ", + " X_______________XX ", + " X_______________XX ", + " X_______________XX ", + " XX______________XX ", + " XX_____________XX ", + " X____________XXX ", + " X___________XXX ", + " XXX________XXX ", + " XXXX____XXXX ", + " XX__XXXXX ", + " X__XX ", + " ", + " " + ], + "palettes": [ "wasp_palette" ], + "nested": { "_": { "chunks": [ "null", "wasp_gibs" ] } } + } + }, + { + "type": "mapgen", + "method": "json", + "om_terrain": "wasp_tower_even_2", + "object": { + "fill_ter": "t_open_air", + "rows": [ + " ", + " :: ", + " aaaaaaaa ", + " aR,,,,Ra ", + " XX,,,,,,X# ", + " XXXX,::XXXXX ", + " XXXX_aXXXXXXaXX ", + " X_ a,<>,,,a XX ", + " X ..aR,,,,Ra X ", + " XX xxxxxxxxxxx. XX ", + " XX xOxOxOxOxOx. X ", + " XX xxxxxxxxxxxxx X ", + " XX xOxOxOxOxOxOx X ", + " XX xxxxxxxxxxxxxx X ", + " XX xOxOxOxOxOxOx X ", + " XX xxxxxxxxxxxxx X ", + " XXX xOxOxOxOx.. X ", + " XXX xxxxxxxxx. XX ", + " XX xOxOxOx. XX ", + " XX xxxxxxx XX ", + " XXX _XX ", + " XXXXXXXXXXX ", + " XXXXX ", + " " + ], + "palettes": [ "wasp_palette" ] + } + }, + { + "type": "mapgen", + "method": "json", + "om_terrain": "wasp_tower_odd_1", + "object": { + "fill_ter": "t_open_air", + "rows": [ + " ", + " ", + " ", + " :R,,,,R ", + " , , ", + " XXX, , ", + " XXXXXXXXXa XXXX ", + " XXX X>,,,xOx. X ", + " XX xxxxxxxxxxxxx. XX ", + " X xOxOxOxOxOxOx. X ", + " XX xxxxxxxxxxxxxxx. X ", + " X xOxOxOxOxOxOxOx. X ", + " X xxxxxxxxxxxxxxxxx X ", + " X xOxOxOxOxOxOxOxOx X ", + " X xxxxxxxxxxxxxxxxx X ", + " X .xOxOxOxOxOxOxOx. X ", + " X xxxxxxxxxxxxxxx. X ", + " XX xOxOxOxOxOxOx. X ", + " XX xxxxxxxxxxxxx XX ", + " X ...xOxOxOx.. XX ", + " X .xxxxxxx. XX ", + " XXX ... XX ", + " XXXX XXXX ", + " XXXXXXX " + ], + "palettes": [ "wasp_palette" ] + } + }, + { + "type": "mapgen", + "method": "json", + "om_terrain": "wasp_tower_roof", + "object": { + "fill_ter": "t_open_air", + "rows": [ + " ", + " ", + " ********* ", + " *********** ", + " ************** ", + " ***************** ", + " ****************** ", + " ******************* ", + " ******************** ", + " ******************** ", + " ********************* ", + " ********************* ", + " ********************* ", + " ********************* ", + " ********************* ", + " ********************* ", + " ********************* ", + " ********************* ", + " ******************** ", + " ****************** ", + " ***************** ", + " **************** ", + " ************* ", + " ******* " + ], + "palettes": [ "wasp_palette" ] + } + } +] diff --git a/data/json/mapgen/radio_tower.json b/data/json/mapgen/radio_tower.json index e53e0595966e8..6915653dcaddf 100644 --- a/data/json/mapgen/radio_tower.json +++ b/data/json/mapgen/radio_tower.json @@ -280,7 +280,13 @@ "terrain": { "R": "t_radio_tower", "a": "t_railing", ",": "t_metal_floor_no_roof", ">": "t_stairs_down" }, "place_nested": [ { - "chunks": [ [ "null", 40 ], [ "radio_tower_2x2_map", 40 ], [ "radio_tower_2x2_holdout", 10 ], [ "radio_tower_2x2_sniper", 10 ] ], + "chunks": [ + [ "null", 40 ], + [ "radio_tower_2x2_map", 40 ], + [ "radio_tower_2x2_holdout", 10 ], + [ "radio_tower_2x2_sniper", 10 ], + [ "radio_tower_wasp", 5 ] + ], "x": 10, "y": 5 } @@ -321,6 +327,18 @@ ] } }, + { + "type": "mapgen", + "method": "json", + "nested_mapgen_id": "radio_tower_wasp", + "object": { + "mapgensize": [ 5, 5 ], + "place_furniture": [ { "furn": "f_camp_chair", "x": 1, "y": 0 }, { "furn": "f_makeshift_bed", "x": 1, "y": 1 } ], + "place_loot": [ { "group": "wasp_lair", "x": 1, "y": 1, "repeat": [ 0, 2 ] }, { "group": "human_parts", "x": 1, "y": 1 } ], + "place_monster": [ { "group": "GROUP_WASP_QUEEN", "x": [ 0, 5 ], "y": [ 0, 5 ] } ], + "place_nested": [ { "chunks": [ "wasp_gibs" ], "x": [ 0, 2 ], "y": [ 0, 2 ], "repeat": [ 5, 7 ] } ] + } + }, { "type": "mapgen", "method": "json", diff --git a/data/json/mapgen_palettes/wasp_palette.json b/data/json/mapgen_palettes/wasp_palette.json new file mode 100644 index 0000000000000..e342148865d91 --- /dev/null +++ b/data/json/mapgen_palettes/wasp_palette.json @@ -0,0 +1,144 @@ +[ + { + "type": "palette", + "id": "wasp_palette", + "terrain": { + "x": "t_paper_brood", + "X": "t_paper_hard", + "_": "t_floor_paper_hard", + "*": "t_roof_paper_hard", + ".": "t_floor_paper_noroof", + "8": "t_floor_paper_noroof", + "R": "t_radio_tower", + "a": "t_railing", + ",": "t_metal_floor_no_roof", + "<": "t_stairs_up", + ">": "t_stairs_down", + ":": "t_null", + "#": "t_metal_floor_no_roof" + }, + "monster": { "8": { "group": "GROUP_WASP_QUEEN" } }, + "furniture": { ":": "f_cellphone_booster", "#": "f_small_satelitte_dish" }, + "nested": { "O": { "chunks": [ "wasp_brood" ] } } + }, + { + "type": "mapgen", + "method": "json", + "nested_mapgen_id": "wasp_brood", + "//": "Empty cell", + "weight": 100, + "object": { "mapgensize": [ 1, 1 ], "rows": [ "0" ], "terrain": { "0": "t_open_air" } } + }, + { + "type": "mapgen", + "method": "json", + "nested_mapgen_id": "wasp_brood", + "//": "Egg cell.", + "weight": 200, + "object": { + "mapgensize": [ 1, 1 ], + "rows": [ "0" ], + "terrain": { "0": "t_floor_brood_fake" }, + "item": { "0": { "item": "egg_wasp" } } + } + }, + { + "type": "mapgen", + "method": "json", + "nested_mapgen_id": "wasp_brood", + "//": "Hatched larva, unsealed", + "weight": 300, + "object": { + "mapgensize": [ 1, 1 ], + "rows": [ "0" ], + "terrain": { "0": "t_open_air" }, + "monster": { "0": { "monster": "mon_wasp_larva" } } + } + }, + { + "type": "mapgen", + "method": "json", + "nested_mapgen_id": "wasp_brood", + "//": "Sealed brood with a pupating wasp.", + "weight": 300, + "object": { + "mapgensize": [ 1, 1 ], + "rows": [ "0" ], + "terrain": { "0": "t_floor_brood_wasp" }, + "monster": { "0": { "monster": "mon_wasp_pupa" } } + } + }, + { + "type": "mapgen", + "method": "json", + "nested_mapgen_id": "wasp_brood", + "//": "Just in time for the adult. Lucky you.", + "weight": 100, + "object": { + "mapgensize": [ 1, 1 ], + "rows": [ "0" ], + "terrain": { "0": "t_open_air" }, + "monster": { "0": { "group": "GROUP_WASP_NEST" } } + } + }, + { + "type": "mapgen", + "method": "json", + "nested_mapgen_id": "wasp_gibs", + "weight": 100, + "object": { + "mapgensize": [ 1, 1 ], + "place_fields": [ { "field": "fd_blood", "x": 0, "y": 0, "intensity": 1, "repeat": [ 0, 3 ] } ] + } + }, + { + "type": "mapgen", + "method": "json", + "nested_mapgen_id": "wasp_gibs", + "weight": 100, + "object": { + "mapgensize": [ 1, 1 ], + "place_fields": [ { "field": "fd_blood_insect", "x": 0, "y": 0, "intensity": 1, "repeat": [ 0, 3 ] } ] + } + }, + { + "type": "mapgen", + "method": "json", + "nested_mapgen_id": "wasp_gibs", + "weight": 100, + "object": { + "mapgensize": [ 1, 1 ], + "place_fields": [ { "field": "fd_blood_invertebrate", "x": 0, "y": 0, "intensity": 1, "repeat": [ 0, 3 ] } ] + } + }, + { + "type": "mapgen", + "method": "json", + "nested_mapgen_id": "wasp_gibs", + "weight": 80, + "object": { "mapgensize": [ 1, 1 ], "place_loot": [ { "group": "bug_parts", "x": 0, "y": 0, "repeat": [ 0, 3 ], "chance": 50 } ] } + }, + { + "type": "mapgen", + "method": "json", + "nested_mapgen_id": "wasp_gibs", + "weight": 80, + "object": { + "mapgensize": [ 1, 1 ], + "place_loot": [ { "group": "vertebrate_parts", "x": 0, "y": 0, "repeat": [ 0, 3 ], "chance": 50 } ] + } + }, + { + "type": "mapgen", + "method": "json", + "nested_mapgen_id": "wasp_gibs", + "weight": 80, + "object": { + "mapgensize": [ 1, 1 ], + "place_loot": [ + { "group": "human_parts", "x": 0, "y": 0, "repeat": [ 0, 3 ], "chance": 50 }, + { "group": "wasp_lair", "x": 0, "y": 0, "repeat": [ 0, 1 ], "chance": 25 } + ] + } + } +] diff --git a/data/json/overmap/overmap_special/specials.json b/data/json/overmap/overmap_special/specials.json index 326b01007d486..89b9df5942bc7 100644 --- a/data/json/overmap/overmap_special/specials.json +++ b/data/json/overmap/overmap_special/specials.json @@ -867,7 +867,7 @@ "connections": [ { "point": [ 0, -1, 0 ], "terrain": "road", "connection": "local_road", "from": [ 0, 0, 0 ] } ], "locations": [ "land" ], "city_distance": [ 0, 20 ], - "occurrences": [ 0, 5 ], + "occurrences": [ 0, 4 ], "flags": [ "CLASSIC", "WILDERNESS" ] }, { @@ -885,9 +885,49 @@ "connections": [ { "point": [ 0, -1, 0 ], "terrain": "road", "connection": "local_road", "from": [ 0, 0, 0 ] } ], "locations": [ "land" ], "city_distance": [ 0, 20 ], - "occurrences": [ 0, 5 ], + "occurrences": [ 0, 4 ], "flags": [ "CLASSIC", "WILDERNESS" ] }, + { + "type": "overmap_special", + "id": "Wasp Tower", + "overmaps": [ + { "point": [ 0, 0, 0 ], "overmap": "wasp_tower_north" }, + { "point": [ 0, 0, 1 ], "overmap": "radio_tower_odd_north" }, + { "point": [ 0, 0, 2 ], "overmap": "wasp_tower_even_1_north" }, + { "point": [ 0, 0, 3 ], "overmap": "wasp_tower_odd_1_north" }, + { "point": [ 0, 0, 4 ], "overmap": "wasp_tower_even_2_north" }, + { "point": [ 0, 0, 5 ], "overmap": "wasp_tower_odd_2_north" }, + { "point": [ 0, 0, 6 ], "overmap": "wasp_tower_top_north" }, + { "point": [ 0, 0, 7 ], "overmap": "wasp_tower_roof_north" } + ], + "connections": [ { "point": [ 0, -1, 0 ], "terrain": "road", "connection": "local_road", "from": [ 0, 0, 0 ] } ], + "locations": [ "land" ], + "city_distance": [ 5, 25 ], + "occurrences": [ 80, 100 ], + "spawns": { "group": "GROUP_WASP_FORAGER", "population": [ 50, 80 ], "radius": [ 6, 20 ] }, + "flags": [ "WILDERNESS", "UNIQUE" ] + }, + { + "type": "overmap_special", + "id": "Wasp Tower 1", + "overmaps": [ + { "point": [ 0, 0, 0 ], "overmap": "wasp_tower_1_north" }, + { "point": [ 0, 0, 1 ], "overmap": "wasp_tower_roof_1_north" }, + { "point": [ 0, 0, 2 ], "overmap": "wasp_tower_even_1_north" }, + { "point": [ 0, 0, 3 ], "overmap": "wasp_tower_odd_1_north" }, + { "point": [ 0, 0, 4 ], "overmap": "wasp_tower_even_2_north" }, + { "point": [ 0, 0, 5 ], "overmap": "wasp_tower_odd_2_north" }, + { "point": [ 0, 0, 6 ], "overmap": "wasp_tower_top_north" }, + { "point": [ 0, 0, 7 ], "overmap": "wasp_tower_roof_north" } + ], + "connections": [ { "point": [ 0, -1, 0 ], "terrain": "road", "connection": "local_road", "from": [ 0, 0, 0 ] } ], + "locations": [ "land" ], + "city_distance": [ 5, 25 ], + "occurrences": [ 80, 100 ], + "spawns": { "group": "GROUP_WASP_FORAGER", "population": [ 50, 100 ], "radius": [ 6, 20 ] }, + "flags": [ "WILDERNESS", "UNIQUE" ] + }, { "type": "overmap_special", "id": "Prison", diff --git a/data/json/overmap/overmap_terrain/overmap_terrain.json b/data/json/overmap/overmap_terrain/overmap_terrain.json index c1f37fd273478..6338ba751a437 100644 --- a/data/json/overmap/overmap_terrain/overmap_terrain.json +++ b/data/json/overmap/overmap_terrain/overmap_terrain.json @@ -313,6 +313,25 @@ "color": "light_gray", "see_cost": 2 }, + { + "type": "overmap_terrain", + "id": [ + "wasp_tower", + "wasp_tower_1", + "wasp_tower_roof_1", + "wasp_tower_odd_1", + "wasp_tower_odd_2", + "wasp_tower_even_1", + "wasp_tower_even_2", + "wasp_tower_top" + ], + "name": "radio tower", + "sym": "X", + "color": "light_gray", + "see_cost": 2, + "mondensity": 2, + "spawns": { "group": "GROUP_WASP_GUARD", "population": [ 3, 8 ], "chance": 100 } + }, { "type": "overmap_terrain", "id": [ "bandit_camp_1", "bandit_camp_2", "bandit_camp_3", "bandit_camp_4" ], @@ -608,7 +627,7 @@ }, { "type": "overmap_terrain", - "id": [ "airliner_2a_1", "airliner_2c_1" ], + "id": [ "airliner_2a_1", "airliner_2c_1", "wasp_tower_roof" ], "name": "open air", "sym": ".", "color": "blue", From daa7cb996cf19ba9eaf5af088a7f94e2c332f37f Mon Sep 17 00:00:00 2001 From: Curtis Merrill Date: Fri, 28 May 2021 06:41:36 -0400 Subject: [PATCH 447/453] [Magiclysm] Fix ring stacking by adding ONE_PER_LAYER flag (#47518) --- data/json/flags.json | 6 +++ .../mods/Magiclysm/items/enchanted_rings.json | 8 ++-- src/character.cpp | 41 ++++++++++++++++++- src/item.cpp | 32 +++++++++++++++ src/item.h | 2 + src/player.cpp | 14 +++++++ 6 files changed, 98 insertions(+), 5 deletions(-) diff --git a/data/json/flags.json b/data/json/flags.json index f1e549ad6edba..2fa6a3112c900 100644 --- a/data/json/flags.json +++ b/data/json/flags.json @@ -258,6 +258,12 @@ "context": [ "ARMOR", "TOOL_ARMOR" ], "info": "You can wear only one." }, + { + "id": "ONE_PER_LAYER", + "type": "json_flag", + "context": [ "ARMOR", "TOOL_ARMOR" ], + "info": "Only one item can be worn on this clothing layer." + }, { "id": "FANCY", "type": "json_flag", diff --git a/data/mods/Magiclysm/items/enchanted_rings.json b/data/mods/Magiclysm/items/enchanted_rings.json index 52ea3568c77fb..cd0bd583d432b 100644 --- a/data/mods/Magiclysm/items/enchanted_rings.json +++ b/data/mods/Magiclysm/items/enchanted_rings.json @@ -15,7 +15,7 @@ "sided": true, "coverage": 0, "warmth": 0, - "flags": [ "WATER_FRIENDLY", "ALLOWS_NATURAL_ATTACKS", "FANCY", "ONLY_ONE", "SKINTIGHT" ] + "flags": [ "WATER_FRIENDLY", "ALLOWS_NATURAL_ATTACKS", "FANCY", "ONE_PER_LAYER", "SKINTIGHT" ] }, { "abstract": "mring_silver", @@ -33,7 +33,7 @@ "sided": true, "coverage": 0, "warmth": 0, - "flags": [ "WATER_FRIENDLY", "ALLOWS_NATURAL_ATTACKS", "FANCY", "ONLY_ONE", "SKINTIGHT" ] + "flags": [ "WATER_FRIENDLY", "ALLOWS_NATURAL_ATTACKS", "FANCY", "ONE_PER_LAYER", "SKINTIGHT" ] }, { "abstract": "mring_gold", @@ -51,7 +51,7 @@ "sided": true, "coverage": 0, "warmth": 0, - "flags": [ "WATER_FRIENDLY", "ALLOWS_NATURAL_ATTACKS", "FANCY", "ONLY_ONE", "SKINTIGHT" ] + "flags": [ "WATER_FRIENDLY", "ALLOWS_NATURAL_ATTACKS", "FANCY", "ONE_PER_LAYER", "SKINTIGHT" ] }, { "abstract": "mring_platinum", @@ -69,7 +69,7 @@ "sided": true, "coverage": 0, "warmth": 0, - "flags": [ "WATER_FRIENDLY", "ALLOWS_NATURAL_ATTACKS", "FANCY", "ONLY_ONE", "SKINTIGHT" ] + "flags": [ "WATER_FRIENDLY", "ALLOWS_NATURAL_ATTACKS", "FANCY", "ONE_PER_LAYER", "SKINTIGHT" ] }, { "copy-from": "mring_copper", diff --git a/src/character.cpp b/src/character.cpp index 7760f9e5c955e..a45778d4f736b 100644 --- a/src/character.cpp +++ b/src/character.cpp @@ -3879,14 +3879,36 @@ ret_val Character::can_wear( const item &it, bool with_equip_change ) cons : string_format( _( "%s doesn't have a hand free to wear that." ), name ) ) ); } + const bool this_restricts_only_one = it.has_flag( flag_id( "ONE_PER_LAYER" ) ); + std::map sidedness; + sidedness[side::BOTH] = false; + sidedness[side::LEFT] = false; + sidedness[side::RIGHT] = false; + const auto sidedness_conflicts = [&sidedness]( side s ) -> bool { + const bool ret = sidedness[s]; + sidedness[s] = true; + if( sidedness[side::LEFT] && sidedness[side::RIGHT] ) + { + sidedness[side::BOTH] = true; + return true; + } + return ret; + }; for( const item &i : worn ) { if( i.has_flag( flag_ONLY_ONE ) && i.typeId() == it.typeId() ) { return ret_val::make_failure( _( "Can't wear more than one %s!" ), it.tname() ); } + + if( this_restricts_only_one || i.has_flag( flag_id( "ONE_PER_LAYER" ) ) ) { + cata::optional overlaps = it.covers_overlaps( i ); + if( overlaps && sidedness_conflicts( *overlaps ) ) { + return ret_val::make_failure( _( "%1$s conflicts with %2$s!" ), it.tname(), i.tname() ); + } + } } if( amount_worn( it.typeId() ) >= MAX_WORN_PER_TYPE ) { - return ret_val::make_failure( _( "Can't wear %i or more %s at once." ), + return ret_val::make_failure( _( "Can't wear %1$i or more %2$s at once." ), MAX_WORN_PER_TYPE + 1, it.tname( MAX_WORN_PER_TYPE + 1 ) ); } @@ -4437,6 +4459,23 @@ bool Character::change_side( item &it, bool interactive ) return false; } + const bool item_one_per_layer = it.has_flag( flag_id( "ONE_PER_LAYER" ) ); + for( const item &worn_item : worn ) { + if( item_one_per_layer && worn_item.has_flag( flag_id( "ONE_PER_LAYER" ) ) ) { + const cata::optional sidedness_conflict = it.covers_overlaps( worn_item ); + if( sidedness_conflict ) { + const std::string player_msg = string_format( + _( "Your %s conflicts with %s, so you cannot swap its side." ), + it.tname(), worn_item.tname() ); + const std::string npc_msg = string_format( + _( "'s %s conflicts with %s so they cannot swap its side." ), + it.tname(), worn_item.tname() ); + add_msg_player_or_npc( m_info, player_msg, npc_msg ); + return false; + } + } + } + if( interactive ) { add_msg_player_or_npc( m_info, _( "You swap the side on which your %s is worn." ), _( " swaps the side on which their %s is worn." ), diff --git a/src/item.cpp b/src/item.cpp index af31100f3a17d..b1a058f7f499f 100644 --- a/src/item.cpp +++ b/src/item.cpp @@ -736,6 +736,38 @@ bool item::covers( const bodypart_id &bp ) const return does_cover; } +cata::optional item::covers_overlaps( const item &rhs ) const +{ + if( get_layer() != rhs.get_layer() ) { + return cata::nullopt; + } + const islot_armor *armor = find_armor_data(); + if( armor == nullptr ) { + return cata::nullopt; + } + const islot_armor *rhs_armor = rhs.find_armor_data(); + if( rhs_armor == nullptr ) { + return cata::nullopt; + } + body_part_set this_covers; + for( const armor_portion_data &data : armor->data ) { + if( data.covers.has_value() ) { + this_covers.unify_set( *data.covers ); + } + } + body_part_set rhs_covers; + for( const armor_portion_data &data : rhs_armor->data ) { + if( data.covers.has_value() ) { + rhs_covers.unify_set( *data.covers ); + } + } + if( this_covers.intersect_set( rhs_covers ).any() ) { + return rhs.get_side(); + } else { + return cata::nullopt; + } +} + body_part_set item::get_covered_body_parts() const { return get_covered_body_parts( get_side() ); diff --git a/src/item.h b/src/item.h index bd3b4971b1312..31dad75edaf7f 100644 --- a/src/item.h +++ b/src/item.h @@ -1589,6 +1589,8 @@ class item : public visitable * Whether this item (when worn) covers the given body part. */ bool covers( const bodypart_id &bp ) const; + // do both items overlap a bodypart at all? returns the side that conflicts via rhs + cata::optional covers_overlaps( const item &rhs ) const; /** * Bitset of all covered body parts. * diff --git a/src/player.cpp b/src/player.cpp index 5704cb9e133fa..e9f638c485053 100644 --- a/src/player.cpp +++ b/src/player.cpp @@ -1882,6 +1882,20 @@ player::wear( item_location item_wear, bool interactive ) was_weapon = false; } + const bool item_one_per_layer = to_wear_copy.has_flag( flag_id( "ONE_PER_LAYER" ) ); + for( const item &worn_item : worn ) { + const cata::optional sidedness_conflict = to_wear_copy.covers_overlaps( worn_item ); + if( sidedness_conflict && ( item_one_per_layer || + worn_item.has_flag( flag_id( "ONE_PER_LAYER" ) ) ) ) { + // we can assume both isn't an option because it'll be caught in can_wear + if( *sidedness_conflict == side::LEFT ) { + to_wear_copy.set_side( side::RIGHT ); + } else { + to_wear_copy.set_side( side::LEFT ); + } + } + } + auto result = wear_item( to_wear_copy, interactive ); if( !result ) { if( was_weapon ) { From 7078dd352b6a391f0a79778015d6577f9597a91d Mon Sep 17 00:00:00 2001 From: SenpaiSlime <83998268+SenpaiSlime@users.noreply.github.com> Date: Fri, 28 May 2021 03:44:14 -0700 Subject: [PATCH 448/453] Addition of Gravel Material and according recipes, stone fixes (#49043) --- data/json/construction.json | 30 +++++++++-- data/json/construction_group.json | 5 ++ .../furniture-barriers.json | 54 +++++++++++++++++++ .../terrain-railroads.json | 4 +- data/json/itemgroups/supplies.json | 1 + data/json/items/ammo.json | 7 ++- data/json/items/chemicals_and_resources.json | 32 +++++++++++ data/json/recipes/other/materials.json | 16 +++++- data/json/recipes/recipe_others.json | 2 +- data/json/recipes/tools/tool.json | 2 +- data/json/recipes/tools/tools_primitive.json | 8 +-- 11 files changed, 145 insertions(+), 16 deletions(-) diff --git a/data/json/construction.json b/data/json/construction.json index 5875ed28a0102..4fea1b8c48567 100644 --- a/data/json/construction.json +++ b/data/json/construction.json @@ -855,6 +855,30 @@ "pre_terrain": "f_sandbag_half", "post_terrain": "f_sandbag_wall" }, + { + "type": "construction", + "id": "constr_gravelbag_half", + "group": "build_gravelbag_wall", + "category": "CONSTRUCT", + "required_skills": [ [ "fabrication", 0 ] ], + "time": "16 m", + "components": [ [ [ "gravelbag", 16 ] ] ], + "pre_note": "Can be deconstructed without tools.", + "pre_special": "check_empty", + "post_terrain": "f_gravelbag_half" + }, + { + "type": "construction", + "id": "constr_gravelbag_wall", + "group": "build_gravelbag_wall", + "category": "CONSTRUCT", + "required_skills": [ [ "fabrication", 0 ] ], + "time": "20 m", + "components": [ [ [ "gravelbag", 20 ] ] ], + "pre_note": "Can be deconstructed without tools.", + "pre_terrain": "f_gravelbag_half", + "post_terrain": "f_gravelbag_wall" + }, { "type": "construction", "id": "constr_earthbag_half", @@ -978,11 +1002,11 @@ "type": "construction", "id": "constr_railroad_rubble", "group": "make_gravel_floor", - "//": "Covers the floor with pebbles. Used for constructing railroads.", + "//": "Covers the floor with gravel. Used for constructing railroads.", "category": "CONSTRUCT", "required_skills": [ [ "fabrication", 1 ] ], "time": "40 m", - "components": [ [ [ "pebble", 100 ] ] ], + "components": [ [ [ "material_gravel", 500 ] ] ], "pre_special": "check_empty", "post_terrain": "t_railroad_rubble" }, @@ -4284,7 +4308,7 @@ "required_skills": [ [ "survival", 0 ] ], "time": "60 m", "qualities": [ [ { "id": "DIG", "level": 1 } ] ], - "byproducts": [ { "item": "pebble", "count": [ 70, 100 ] } ], + "byproducts": [ { "item": "material_gravel", "count": [ 350, 500 ] } ], "pre_terrain": "t_railroad_rubble", "post_terrain": "t_dirt" }, diff --git a/data/json/construction_group.json b/data/json/construction_group.json index 919aad6e06529..648e05ac97d02 100644 --- a/data/json/construction_group.json +++ b/data/json/construction_group.json @@ -249,6 +249,11 @@ "id": "build_dumpster", "name": "Build Dumpster" }, + { + "type": "construction_group", + "id": "build_gravelbag_wall", + "name": "Build Gravelbag Wall" + }, { "type": "construction_group", "id": "build_earthbag_wall", diff --git a/data/json/furniture_and_terrain/furniture-barriers.json b/data/json/furniture_and_terrain/furniture-barriers.json index a0e4260978b67..218553bf485ef 100644 --- a/data/json/furniture_and_terrain/furniture-barriers.json +++ b/data/json/furniture_and_terrain/furniture-barriers.json @@ -20,6 +20,60 @@ "items": [ { "item": "2x4", "count": [ 2, 6 ] }, { "item": "nail", "charges": [ 4, 8 ] }, { "item": "splinter", "count": 1 } ] } }, + { + "type": "furniture", + "id": "f_gravelbag_half", + "name": "gravelbag barricade", + "symbol": "#", + "looks_like": "f_sandbag_half", + "bgcolor": "brown", + "description": "A low wall made of stacked gravelbags, uncommonly used to catch bullets and block flooding.", + "move_cost_mod": -1, + "coverage": 60, + "required_str": -1, + "flags": [ + "CLIMB_SIMPLE", + "TRANSPARENT", + "MOUNTABLE", + "BLOCKSDOOR", + "SHORT", + "EASY_DECONSTRUCT", + "THIN_OBSTACLE", + "CLIMBABLE", + "PERMEABLE" + ], + "examine_action": "chainfence", + "deconstruct": { "items": [ { "item": "gravelbag", "count": 16 } ] }, + "bash": { + "str_min": 12, + "str_max": 60, + "sound": "rrrip!", + "sound_fail": "whump.", + "items": [ { "item": "bag_canvas", "count": [ 10, 16 ] }, { "item": "material_gravel", "charges": [ 40, 48 ] } ] + } + }, + { + "type": "furniture", + "id": "f_gravelbag_wall", + "name": "gravelbag wall", + "symbol": "#", + "looks_like": "f_sandbag_wall", + "bgcolor": "brown", + "move_cost_mod": -1, + "coverage": 95, + "description": "A wall of stacked gravelbags, a bit taller than an average adult.", + "required_str": -1, + "flags": [ "NOITEM", "BLOCKSDOOR", "EASY_DECONSTRUCT", "MINEABLE", "BLOCK_WIND" ], + "deconstruct": { "items": [ { "item": "gravelbag", "count": 20 } ], "furn_set": "f_gravelbag_half" }, + "bash": { + "str_min": 24, + "str_max": 80, + "sound": "rrrip!", + "sound_fail": "whump.", + "furn_set": "f_gravelbag_half", + "items": [ { "item": "bag_canvas", "count": [ 15, 20 ] }, { "item": "material_gravel", "charges": [ 50, 60 ] } ] + } + }, { "type": "furniture", "id": "f_earthbag_half", diff --git a/data/json/furniture_and_terrain/terrain-railroads.json b/data/json/furniture_and_terrain/terrain-railroads.json index 27f6c4e97dcb4..7a0441806cb88 100644 --- a/data/json/furniture_and_terrain/terrain-railroads.json +++ b/data/json/furniture_and_terrain/terrain-railroads.json @@ -13,12 +13,12 @@ "ter_set": "t_null", "sound": "crunch!", "sound_fail": "whump!", - "items": [ { "item": "pebble", "count": [ 1, 3 ] }, { "item": "sharp_rock", "count": [ 0, 1 ] } ] + "items": [ { "item": "material_gravel", "count": [ 5, 15 ] }, { "item": "sharp_rock", "count": [ 0, 1 ] } ] }, "deconstruct": { "ter_set": "t_pit_shallow", "items": [ - { "item": "pebble", "count": [ 75, 100 ] }, + { "item": "material_gravel", "count": [ 350, 500 ] }, { "item": "sharp_rock", "count": [ 0, 2 ] }, { "item": "rock", "count": [ 4, 12 ] } ] diff --git a/data/json/itemgroups/supplies.json b/data/json/itemgroups/supplies.json index 18ec8fc1ff434..4b08ce7d840a5 100644 --- a/data/json/itemgroups/supplies.json +++ b/data/json/itemgroups/supplies.json @@ -74,6 +74,7 @@ { "item": "coal_lump", "prob": 20, "count": [ 1, 10 ] }, { "item": "material_cement", "prob": 100, "charges": 500, "container-item": "bag_canvas" }, { "item": "material_sand", "prob": 100, "charges": 500, "container-item": "bag_canvas" }, + { "item": "material_gravel", "prob": 100, "charges": 500, "container-item": "bag_canvas" }, [ "material_shrd_limestone", 70 ], [ "fertilizer_commercial", 100 ], [ "material_quicklime", 70 ], diff --git a/data/json/items/ammo.json b/data/json/items/ammo.json index b2333a280868b..4a29bca1d172a 100644 --- a/data/json/items/ammo.json +++ b/data/json/items/ammo.json @@ -382,16 +382,15 @@ { "type": "AMMO", "id": "pebble", - "price": 100, - "price_postapoc": 10, "name": { "str": "pebble" }, "symbol": "=", "color": "light_gray", - "description": "A handful of pebbles, useful as ammunition for slingshots.", + "description": "A small rock, useful as ammunition for slingshots.", "material": [ "stone" ], "volume": "250 ml", - "weight": "5 g", + "weight": "66 g", "ammo_type": "pebble", + "flags": [ "TRADER_AVOID" ], "damage": { "damage_type": "bullet", "amount": 2 }, "range": 10, "dispersion": 14, diff --git a/data/json/items/chemicals_and_resources.json b/data/json/items/chemicals_and_resources.json index 5608d816e56a5..acacbd54957c4 100644 --- a/data/json/items/chemicals_and_resources.json +++ b/data/json/items/chemicals_and_resources.json @@ -71,6 +71,23 @@ "ammo_type": "components", "count": 50 }, + { + "type": "AMMO", + "id": "material_gravel", + "category": "spare_parts", + "price": 0, + "price_postapoc": 0, + "name": { "str_sp": "gravel" }, + "symbol": "=", + "color": "dark_gray", + "description": "A handful of gravel, smaller than pebbles but larger than sand.", + "material": [ "stone" ], + "volume": "250 ml", + "weight": "6 g", + "bashing": 1, + "ammo_type": "components", + "count": 50 + }, { "type": "AMMO", "id": "material_limestone", @@ -1458,6 +1475,21 @@ "color": "brown", "looks_like": "bag_canvas" }, + { + "id": "gravelbag", + "type": "GENERIC", + "category": "other", + "name": { "str": "gravelbag" }, + "description": "This is a canvas sack filled with gravel. It can be used to construct simple barricades.", + "weight": "19200 g", + "volume": "16L", + "price": 0, + "price_postapoc": 10, + "material": [ "cotton", "powder" ], + "symbol": ")", + "color": "brown", + "looks_like": "bag_canvas" + }, { "id": "earthbag", "type": "GENERIC", diff --git a/data/json/recipes/other/materials.json b/data/json/recipes/other/materials.json index 26302aa2a51da..8bf6a845a7a67 100644 --- a/data/json/recipes/other/materials.json +++ b/data/json/recipes/other/materials.json @@ -29,7 +29,21 @@ "book_learn": [ [ "concrete_book", 4 ] ], "batch_time_factors": [ 75, 3 ], "tools": [ [ [ "crucible", -1 ], [ "crucible_clay", -1 ] ], [ [ "forge", 250 ], [ "oxy_torch", 50 ] ] ], - "components": [ [ [ "material_quicklime", 50 ] ], [ [ "material_sand", 50 ] ] ] + "components": [ [ [ "material_quicklime", 50 ] ], [ [ "material_sand", 50 ], [ "material_gravel", 50 ] ] ] + }, + { + "type": "recipe", + "activity_level": "LIGHT_EXERCISE", + "result": "material_gravel", + "category": "CC_OTHER", + "subcategory": "CSC_OTHER_MATERIALS", + "skill_used": "survival", + "skills_required": [ "survival", 1 ], + "difficulty": 1, + "time": "10m", + "autolearn": true, + "qualities": [ { "id": "HAMMER", "level": 1 }, { "id": "ANVIL", "level": 1 } ], + "components": [ [ [ "pebble", 10 ] ] ] }, { "type": "recipe", diff --git a/data/json/recipes/recipe_others.json b/data/json/recipes/recipe_others.json index 4886c50cb5789..e2d1cba16f7a6 100644 --- a/data/json/recipes/recipe_others.json +++ b/data/json/recipes/recipe_others.json @@ -11,7 +11,7 @@ "autolearn": false, "book_learn": [ [ "concrete_book", 4 ] ], "tools": [ [ [ "con_mix", 50 ] ] ], - "components": [ [ [ "material_cement", 50 ] ], [ [ "material_sand", 25 ] ], [ [ "pebble", 20 ] ] ] + "components": [ [ [ "material_cement", 50 ] ], [ [ "material_sand", 25 ] ], [ [ "pebble", 20 ], [ "material_gravel", 100 ] ] ] }, { "type": "recipe", diff --git a/data/json/recipes/tools/tool.json b/data/json/recipes/tools/tool.json index a4d33cd87e7c0..019a339eca64d 100644 --- a/data/json/recipes/tools/tool.json +++ b/data/json/recipes/tools/tool.json @@ -548,7 +548,7 @@ "components": [ [ [ "rock", 2 ] ], [ [ "water", 1 ], [ "water_clean", 1 ], [ "water_sewage", 1 ], [ "salt_water", 1 ], [ "saline", 5 ] ], - [ [ "material_sand", 1 ] ] + [ [ "material_sand", 1 ], [ "material_gravel", 1 ] ] ] }, { diff --git a/data/json/recipes/tools/tools_primitive.json b/data/json/recipes/tools/tools_primitive.json index d3bf2cbebbe77..c1774b7b84c37 100644 --- a/data/json/recipes/tools/tools_primitive.json +++ b/data/json/recipes/tools/tools_primitive.json @@ -15,7 +15,7 @@ [ [ "stick", 1 ], [ "2x4", 1 ] ], [ [ "rock", 1 ] ], [ [ "water", 1 ], [ "water_clean", 1 ], [ "water_sewage", 1 ], [ "salt_water", 1 ], [ "saline", 5 ] ], - [ [ "material_sand", 1 ] ], + [ [ "material_sand", 1 ], [ "material_gravel", 1 ] ], [ [ "cordage_short", 1, "LIST" ], [ "filament", 50, "LIST" ] ] ] }, @@ -135,7 +135,7 @@ [ [ "stick", 1 ], [ "2x4", 1 ] ], [ [ "rock", 1 ] ], [ [ "water", 1 ], [ "water_clean", 1 ], [ "water_sewage", 1 ], [ "salt_water", 1 ], [ "saline", 5 ] ], - [ [ "material_sand", 1 ] ] + [ [ "material_sand", 1 ], [ "material_gravel", 1 ] ] ] }, { @@ -180,7 +180,7 @@ [ [ "stick", 1 ], [ "2x4", 1 ] ], [ [ "rock_large", 2 ] ], [ [ "water", 1 ], [ "water_clean", 1 ], [ "water_sewage", 1 ], [ "salt_water", 1 ], [ "saline", 5 ] ], - [ [ "material_sand", 1 ] ] + [ [ "material_sand", 1 ], [ "material_gravel", 1 ] ] ] }, { @@ -279,7 +279,7 @@ "components": [ [ [ "rock", 1 ] ], [ [ "water", 1 ], [ "water_clean", 1 ], [ "water_sewage", 1 ], [ "salt_water", 1 ], [ "saline", 5 ] ], - [ [ "material_sand", 1 ] ] + [ [ "material_sand", 1 ], [ "material_gravel", 1 ] ] ] }, { From 0ab52e71ee9fbb0ad96932fd84eaab0cf8d06d78 Mon Sep 17 00:00:00 2001 From: OromisElf Date: Fri, 28 May 2021 12:48:03 +0200 Subject: [PATCH 449/453] added mechanical winch and metal gate to construction menu (#47919) --- data/json/construction.json | 32 +++++++++++++++++++++++++++++++ data/json/construction_group.json | 10 ++++++++++ 2 files changed, 42 insertions(+) diff --git a/data/json/construction.json b/data/json/construction.json index 4fea1b8c48567..6d173f3604e9f 100644 --- a/data/json/construction.json +++ b/data/json/construction.json @@ -4312,6 +4312,38 @@ "pre_terrain": "t_railroad_rubble", "post_terrain": "t_dirt" }, + { + "type": "construction", + "id": "constr_mechanical_winch", + "group": "build_mechanical_winch", + "category": "CONSTRUCT", + "required_skills": [ [ "fabrication", 5 ], [ "mechanics", 6 ] ], + "time": "60 m", + "tools": [ [ [ "oxy_torch", 4 ], [ "welder", 20 ], [ "welder_crude", 30 ], [ "toolset", 30 ] ] ], + "qualities": [ [ { "id": "SAW_M", "level": 1 } ], [ { "id": "GLARE", "level": 2 } ] ], + "components": [ [ [ "chain", 16 ] ], [ [ "wheel_metal", 2 ] ], [ [ "pipe", 4 ] ] ], + "pre_note": "Must be adjacent to a reinforced concrete wall that is itself adjacent to a metal gate in order to open said gate.", + "pre_special": "check_empty", + "post_terrain": "t_gates_mech_control_lab" + }, + { + "type": "construction", + "id": "constr_metal_gate", + "group": "build_metal_gate", + "category": "CONSTRUCT", + "required_skills": [ [ "fabrication", 4 ], [ "mechanics", 4 ] ], + "time": "120 m", + "tools": [ [ [ "oxy_torch", 10 ], [ "welder", 50 ], [ "welder_crude", 75 ], [ "toolset", 75 ] ] ], + "qualities": [ [ { "id": "SAW_M", "level": 2 } ], [ { "id": "GLARE", "level": 2 } ] ], + "components": [ + [ [ "steel_lump", 8 ], [ "steel_chunk", 24 ], [ "scrap", 72 ] ], + [ [ "sheet_metal", 16 ] ], + [ [ "frame", 4 ], [ "spike", 24 ] ] + ], + "pre_note": "Must be between reinforced concrete walls to function, and at least one wall must have an adjacent mechanical winch.", + "pre_special": "check_empty", + "post_terrain": "t_door_metal_locked" + }, { "type": "construction", "id": "constr_exercise_machine", diff --git a/data/json/construction_group.json b/data/json/construction_group.json index 648e05ac97d02..c66778037d128 100644 --- a/data/json/construction_group.json +++ b/data/json/construction_group.json @@ -374,6 +374,11 @@ "id": "build_makeshift_door", "name": "Build Makeshift Door" }, + { + "type": "construction_group", + "id": "build_mechanical_winch", + "name": "Build Mechanical Winch" + }, { "type": "construction_group", "id": "build_ergometer_mechanical", @@ -394,6 +399,11 @@ "id": "build_metal_door", "name": "Build Metal Door" }, + { + "type": "construction_group", + "id": "build_metal_gate", + "name": "Build Metal Gate" + }, { "type": "construction_group", "id": "build_metal_grate_over_a_window", From d80906bd38981598ef9b7aaad96c66c973639571 Mon Sep 17 00:00:00 2001 From: RelMayers <74023387+RelMayers@users.noreply.github.com> Date: Fri, 28 May 2021 12:55:38 +0200 Subject: [PATCH 450/453] Update soy milk and almond milk to fix carnivores having no problems with them. (#48918) --- data/json/items/comestibles/drink.json | 4 ++-- data/json/requirements/cooking_components.json | 2 ++ 2 files changed, 4 insertions(+), 2 deletions(-) diff --git a/data/json/items/comestibles/drink.json b/data/json/items/comestibles/drink.json index 0a0bc595b8a42..8b18bd6444b2c 100644 --- a/data/json/items/comestibles/drink.json +++ b/data/json/items/comestibles/drink.json @@ -39,7 +39,7 @@ "description": "Milk some almonds? Not quite, but blend them with water, yes! A dairy-free alternative strong in calcium! Rival to soy milk.", "price": 40, "price_postapoc": 50, - "material": [ "water" ], + "material": [ "water", "nut" ], "volume": "250 ml", "phase": "liquid", "vitamins": [ [ "vitA", 2 ], [ "calcium", 11 ] ], @@ -62,7 +62,7 @@ "description": "Milk some soybeans? Not quite, but blend them with water, yes! A dairy-free alternative strong in protein! Rival to almond milk.", "price": 40, "price_postapoc": 50, - "material": [ "water" ], + "material": [ "water", "veggy" ], "volume": "250 ml", "phase": "liquid", "vitamins": [ [ "vitA", 2 ], [ "iron", 1 ], [ "calcium", 7 ] ], diff --git a/data/json/requirements/cooking_components.json b/data/json/requirements/cooking_components.json index c44780dba54b2..1e314b25eca32 100644 --- a/data/json/requirements/cooking_components.json +++ b/data/json/requirements/cooking_components.json @@ -480,7 +480,9 @@ [ "veggy_wild", 2 ], [ "veggy", 2 ], [ "rehydrated_veggy", 2 ], + [ "rehydrated_corn_kernels", 2 ], [ "dry_veggy", 2 ], + [ "dry_corn", 2 ], [ "dry_beans", 2 ], [ "can_beans", 2 ], [ "raw_beans", 2 ], From 40b329693f504ec4297e1b207e1b7a6c1ca5114a Mon Sep 17 00:00:00 2001 From: Zhilkin Serg Date: Fri, 28 May 2021 15:01:03 +0300 Subject: [PATCH 451/453] Apply suggestions from code review --- data/json/monstergroups/zanimal_upgrades.json | 11 ----------- 1 file changed, 11 deletions(-) diff --git a/data/json/monstergroups/zanimal_upgrades.json b/data/json/monstergroups/zanimal_upgrades.json index 082432758ac64..d6910ccb8e695 100644 --- a/data/json/monstergroups/zanimal_upgrades.json +++ b/data/json/monstergroups/zanimal_upgrades.json @@ -21,17 +21,6 @@ { "monster": "mon_zombie_pig_gas", "freq": 45, "cost_multiplier": 2 } ] }, - { - "type": "monstergroup", - "name": "GROUP_ZOMBIE_PIG_UPGRADE", - "default": "mon_zombie_pig", - "//": "No bionics or fungal", - "monsters": [ - { "monster": "mon_zombie_pig", "freq": 45, "cost_multiplier": 5 }, - { "monster": "mon_zpig_brute", "freq": 45, "cost_multiplier": 2 }, - { "monster": "mon_zombie_pig_gas", "freq": 45, "cost_multiplier": 2 } - ] - }, { "type": "monstergroup", "name": "GROUP_ZOLF_UPGRADE", From ff11d21c4eb4157ef013b6bead50605f67f2c3a1 Mon Sep 17 00:00:00 2001 From: Zhilkin Serg Date: Fri, 28 May 2021 15:01:22 +0300 Subject: [PATCH 452/453] Apply suggestions from code review --- src/worldfactory.cpp | 1 - 1 file changed, 1 deletion(-) diff --git a/src/worldfactory.cpp b/src/worldfactory.cpp index 32338e80174c6..532b99a6b871e 100644 --- a/src/worldfactory.cpp +++ b/src/worldfactory.cpp @@ -31,7 +31,6 @@ #include "string_formatter.h" #include "string_input_popup.h" #include "translations.h" -#include "try_parse_integer.h" #include "ui_manager.h" using namespace std::placeholders; From 3cc24a84de3b34ca27218ac072976f0ff599ae1a Mon Sep 17 00:00:00 2001 From: Zhilkin Serg Date: Wed, 2 Jun 2021 12:11:50 +0300 Subject: [PATCH 453/453] Apply suggestions from code review --- tools/clang-tidy-plugin/UnsequencedCallsCheck.h | 1 - 1 file changed, 1 deletion(-) diff --git a/tools/clang-tidy-plugin/UnsequencedCallsCheck.h b/tools/clang-tidy-plugin/UnsequencedCallsCheck.h index a73672c87a045..6baeb6e9484a7 100644 --- a/tools/clang-tidy-plugin/UnsequencedCallsCheck.h +++ b/tools/clang-tidy-plugin/UnsequencedCallsCheck.h @@ -3,7 +3,6 @@ #include #include - #include #include "ClangTidy.h"