diff --git a/data/json/construction.json b/data/json/construction.json index 4b2cc066f68f6..6ef30bb35aec8 100644 --- a/data/json/construction.json +++ b/data/json/construction.json @@ -2712,5 +2712,29 @@ "pre_note": "Can be deconstructed without tools.", "pre_flags": [ "DIGGABLE", "FLAT" ], "post_terrain": "t_tarptent" + }, + { + "type": "construction", + "skill": "survival", + "description": "Dig a Shallow Pit", + "category": "CONSTRUCT", + "difficulty": 1, + "time": "30m", + "on_display": false, + "qualities": [ { "id": "DIG", "level": 1 } ], + "pre_flags": [ "DIGGABLE", "FLAT" ], + "post_terrain": "t_pit_shallow" + }, + { + "type": "construction", + "skill": "survival", + "description": "Dig a Deep Pit", + "category": "CONSTRUCT", + "difficulty": 1, + "time": "150m", + "on_display": false, + "qualities": [ { "id": "DIG", "level": 2 } ], + "pre_flags": [ "DIGGABLE", "FLAT" ], + "post_terrain": "t_pit" } ] diff --git a/data/json/item_actions.json b/data/json/item_actions.json index 143375a22a173..5f54c2c42de55 100644 --- a/data/json/item_actions.json +++ b/data/json/item_actions.json @@ -634,6 +634,11 @@ "id": "MP3_ON", "name": "Turn off music" }, + { + "type": "item_action", + "id": "RPGDIE", + "name": "Roll die" + }, { "type": "item_action", "id": "GASMASK", diff --git a/data/json/item_groups.json b/data/json/item_groups.json index 36087a856abc6..313072dd440e4 100644 --- a/data/json/item_groups.json +++ b/data/json/item_groups.json @@ -61,6 +61,8 @@ [ "slingshot", 10 ], [ "frisbee", 10 ], [ "dnd_handbook", 1 ], + [ "RPG_die", 1 ], + [ "metal_RPG_die", 1 ], [ "milkshake_fastfood", 3 ] ] }, diff --git a/data/json/itemgroups/SUS_specific_use_storage_items.json b/data/json/itemgroups/SUS_specific_use_storage_items.json index 5c932cac68f27..1ce899ca86c60 100644 --- a/data/json/itemgroups/SUS_specific_use_storage_items.json +++ b/data/json/itemgroups/SUS_specific_use_storage_items.json @@ -102,6 +102,8 @@ { "item": "corkscrew", "prob": 60 }, { "item": "bottle_opener", "prob": 75 }, { "item": "candle", "prob": 75 }, + { "item": "RPG_die", "prob": 10 }, + { "item": "metal_RPG_die", "prob": 1 }, { "distribution": [ { "item": "matches" }, { "item": "lighter" } ], "prob": 90 } ] }, diff --git a/data/json/itemgroups/mall_item_groups.json b/data/json/itemgroups/mall_item_groups.json index 90ce066f31814..4c26c86aec0b4 100644 --- a/data/json/itemgroups/mall_item_groups.json +++ b/data/json/itemgroups/mall_item_groups.json @@ -118,7 +118,9 @@ [ "jedi_cloak", 5 ], [ "clown_suit", 5 ], [ "clownshoes", 5 ], - [ "radio_car_box", 10 ] + [ "radio_car_box", 10 ], + [ "RPG_die", 5 ], + [ "metal_RPG_die", 1 ] ] }, { diff --git a/data/json/itemgroups/misc.json b/data/json/itemgroups/misc.json index 34d059c11d2f7..714b7279c725f 100644 --- a/data/json/itemgroups/misc.json +++ b/data/json/itemgroups/misc.json @@ -83,6 +83,8 @@ { "item": "family_photo", "prob": 5 }, { "item": "coin_quarter", "prob": 5 }, { "item": "mobile_memory_card_used", "count": [ 1, 4 ], "prob": 15 }, + { "item": "RPG_die", "prob": 5 }, + { "item": "metal_RPG_die", "prob": 1 }, { "item": "mobile_memory_card_encrypted", "count": [ 1, 2 ], "prob": 15 } ] }, diff --git a/data/json/itemgroups/supplies.json b/data/json/itemgroups/supplies.json index 4a6f8dc9fccf3..2081f4a9e0005 100644 --- a/data/json/itemgroups/supplies.json +++ b/data/json/itemgroups/supplies.json @@ -56,8 +56,9 @@ "//": "large quantities of common building supplies.", "items": [ { "item": "2x4", "prob": 100, "count": [ 5, 20 ] }, - { "item": "wood_sheet", "prob": 50, "count": [ 1, 2 ] }, - { "item": "wood_panel", "prob": 60, "count": [ 1, 4 ] }, + { "item": "wood_beam", "prob": 50, "count": [ 1, 5 ] }, + { "item": "wood_sheet", "prob": 50, "count": [ 1, 4 ] }, + { "item": "wood_panel", "prob": 60, "count": [ 1, 8 ] }, { "item": "rock", "prob": 70, "count": [ 10, 20 ] }, { "item": "coal_lump", "prob": 20, "count": [ 1, 10 ] }, { "item": "material_cement", "prob": 100, "charges": 500, "container-item": "bag_canvas" }, @@ -136,6 +137,7 @@ { "distribution": [ { "item": "2x4", "prob": 500, "count": [ 20, 50 ] }, + { "item": "wood_beam", "prob": 50, "count": [ 5, 20 ] }, { "item": "wood_sheet", "prob": 400, "count": [ 10, 30 ] }, { "item": "wood_panel", "prob": 300, "count": [ 15, 40 ] }, { "item": "log", "prob": 200, "count": [ 5, 10 ] }, diff --git a/data/json/items/ammo.json b/data/json/items/ammo.json index 7413aa192e092..08555e019e66c 100644 --- a/data/json/items/ammo.json +++ b/data/json/items/ammo.json @@ -1328,5 +1328,49 @@ "count": 50, "ammo_type": "tinder", "effects": [ "NEVER_MISFIRES" ] + }, + { + "type": "AMMO", + "id": "RPG_die", + "price": 10, + "name": "RPG die", + "name_plural": "RPG dice", + "symbol": "=", + "color": "light_gray", + "looks_like": "marble", + "description": "A die used to play various role-playing games.", + "material": "plastic", + "volume": 1, + "weight": 1, + "ammo_type": "pebble", + "damage": 1, + "range": 20, + "dispersion": 15, + "loudness": 0, + "count": 7, + "effects": [ "NEVER_MISFIRES" ], + "use_action": "RPGDIE" + }, + { + "type": "AMMO", + "id": "metal_RPG_die", + "price": 50, + "name": "metal RPG die", + "name_plural": "metal RPG dice", + "symbol": "=", + "color": "light_gray", + "looks_like": "marble", + "description": "A metal die used to play various role-playing games", + "material": "zinc", + "volume": 1, + "weight": 1, + "ammo_type": "pebble", + "damage": 3, + "range": 15, + "dispersion": 10, + "loudness": 0, + "count": 7, + "effects": [ "NEVER_MISFIRES" ], + "use_action": "RPGDIE" } ] diff --git a/data/json/items/ammo/shotcanister.json b/data/json/items/ammo/shotcanister.json new file mode 100644 index 0000000000000..45b1972e466a7 --- /dev/null +++ b/data/json/items/ammo/shotcanister.json @@ -0,0 +1,89 @@ +[ + { + "type": "AMMO", + "id": "shotcanister_scrap", + "price": 1000, + "name": "scrap shotcanister", + "symbol": "=", + "color": "green", + "description": "This small paper canister resembling a crude shotshell is filled to the brim with assorted pieces of scrap metal.", + "material": [ "steel" ], + "volume": 1, + "weight": 55, + "bashing": 2, + "cutting": 1, + "ammo_type": "shotcanister", + "looks_like": "shot_scrap", + "range": 1, + "damage": 10, + "dispersion": 250, + "loudness": 0, + "count": 10 + }, + { + "type": "AMMO", + "id": "shotcanister_pebble", + "price": 1000, + "name": "pebble shotcanister", + "symbol": "=", + "color": "green", + "description": "This small paper canister resembling a crude shotshell is filled to the brim with tiny pebbles. Damage is pathetic but flight is much more stable than scrap", + "material": [ "steel" ], + "volume": 1, + "weight": 55, + "bashing": 2, + "cutting": 1, + "ammo_type": "shotcanister", + "looks_like": "shot_scrap", + "range": 2, + "pierce": 1, + "damage": 7, + "dispersion": 80, + "loudness": 0, + "count": 10 + }, + { + "type": "AMMO", + "id": "shotcanister_flechette", + "price": 1000, + "name": "flechette shotcanister", + "symbol": "=", + "color": "green", + "description": "This small paper canister resembling a crude shotshell is filled to the brim with handmade flechettes, giving it some armor piercing capabilities.", + "material": [ "steel" ], + "volume": 1, + "weight": 55, + "bashing": 2, + "cutting": 1, + "ammo_type": "shotcanister", + "looks_like": "shot_scrap", + "range": 3, + "damage": 13, + "pierce": 7, + "dispersion": 50, + "loudness": 0, + "count": 10 + }, + { + "type": "AMMO", + "id": "shotcanister_bearing", + "price": 1000, + "name": "bearing shotcanister", + "symbol": "=", + "color": "green", + "description": "This small paper canister resembling a crude shotshell is filled to the brim with handmade bearings, stabilizing it's flight pattern a tiny bit.", + "material": [ "steel" ], + "volume": 1, + "weight": 55, + "bashing": 2, + "cutting": 1, + "ammo_type": "shotcanister", + "looks_like": "shot_scrap", + "range": 2, + "damage": 12, + "pierce": 2, + "dispersion": 100, + "loudness": 0, + "count": 10 + } +] diff --git a/data/json/items/ammo_types.json b/data/json/items/ammo_types.json index 25f9e8dcb8df7..59e167428431c 100644 --- a/data/json/items/ammo_types.json +++ b/data/json/items/ammo_types.json @@ -53,6 +53,12 @@ "name": "pebbles", "default": "pebble" }, + { + "type": "ammunition_type", + "id": "shotcanister", + "name": "shotcanisters", + "default": "shotcanister_scrap" + }, { "type": "ammunition_type", "id": "shot", diff --git a/data/json/items/comestibles/other.json b/data/json/items/comestibles/other.json index 748974345eeee..2663fc4f2bcea 100644 --- a/data/json/items/comestibles/other.json +++ b/data/json/items/comestibles/other.json @@ -366,7 +366,8 @@ { "type": "COMESTIBLE", "id": "soybean", - "name": "soybean", + "name": "soybeans", + "name_plural": "soybeans", "copy-from": "seed", "weight": 160, "symbol": ".", @@ -374,7 +375,7 @@ "healthy": -5, "spoils_in": "364 days", "calories": 56, - "description": "A light brown bean, has many uses, mildly toxic and not recommended, but you could eat them raw.", + "description": "Light brown beans, they have many uses, mildly toxic and not recommended, but you could eat them raw.", "price": 90, "fun": -5, "vitamins": [ [ "iron", 25 ], [ "vitC", 1 ], [ "calcium", 3 ] ] diff --git a/data/json/items/comestibles/seed.json b/data/json/items/comestibles/seed.json index 4e2b38d190c59..24295860c1f31 100644 --- a/data/json/items/comestibles/seed.json +++ b/data/json/items/comestibles/seed.json @@ -54,7 +54,7 @@ "type": "COMESTIBLE", "name": "blackberry seeds", "name_plural": "blackberry seeds", - "description": "Some blackberry seeds.", + "description": "Some blackberry seeds. You could probably plant these.", "seed_data": { "plant_name": "blackberry", "fruit": "blackberries", "byproducts": [ "withered" ], "grow": "91 days" } }, { @@ -63,7 +63,7 @@ "type": "COMESTIBLE", "name": "blueberry seeds", "name_plural": "blueberry seeds", - "description": "Some blueberry seeds.", + "description": "Some blueberry seeds. You could probably plant these.", "seed_data": { "plant_name": "blueberry", "fruit": "blueberries", "byproducts": [ "withered" ], "grow": "91 days" } }, { @@ -72,7 +72,7 @@ "type": "COMESTIBLE", "name": "cranberry seeds", "name_plural": "cranberry seeds", - "description": "Some cranberry seeds.", + "description": "Some cranberry seeds. You could probably plant these.", "seed_data": { "plant_name": "cranberry", "fruit": "cranberries", "byproducts": [ "withered" ], "grow": "91 days" } }, { @@ -81,7 +81,7 @@ "type": "COMESTIBLE", "name": "huckleberry seeds", "name_plural": "huckleberry seeds", - "description": "Some huckleberry seeds.", + "description": "Some huckleberry seeds. You could probably plant these.", "seed_data": { "plant_name": "huckleberry", "fruit": "huckleberries", "byproducts": [ "withered" ], "grow": "91 days" } }, { @@ -90,7 +90,7 @@ "type": "COMESTIBLE", "name": "mulberry seeds", "name_plural": "mulberry seeds", - "description": "Some mulberry seeds.", + "description": "Some mulberry seeds. You could probably plant these.", "seed_data": { "plant_name": "mulberry", "fruit": "mulberries", "byproducts": [ "withered" ], "grow": "91 days" } }, { @@ -99,7 +99,7 @@ "type": "COMESTIBLE", "name": "elderberry seeds", "name_plural": "elderberry seeds", - "description": "Some elderberry seeds.", + "description": "Some elderberry seeds. You could probably plant these.", "seed_data": { "plant_name": "elderberry", "fruit": "elderberries", "byproducts": [ "withered" ], "grow": "91 days" } }, { @@ -108,7 +108,7 @@ "type": "COMESTIBLE", "name": "raspberry seeds", "name_plural": "raspberry seeds", - "description": "Some raspberry seeds.", + "description": "Some raspberry seeds. You could probably plant these.", "seed_data": { "plant_name": "raspberry", "fruit": "raspberries", "byproducts": [ "withered" ], "grow": "91 days" } }, { @@ -117,7 +117,7 @@ "type": "COMESTIBLE", "name": "strawberry seeds", "name_plural": "strawberry seeds", - "description": "Some strawberry seeds.", + "description": "Some strawberry seeds. You could probably plant these.", "seed_data": { "plant_name": "strawberry", "fruit": "strawberries", "byproducts": [ "withered" ], "grow": "91 days" } }, { @@ -126,7 +126,7 @@ "type": "COMESTIBLE", "name": "grape seeds", "name_plural": "grape seeds", - "description": "Some grape seeds.", + "description": "Some grape seeds. You could probably plant these.", "seed_data": { "plant_name": "grape", "fruit": "grapes", "byproducts": [ "withered" ], "grow": "91 days" } }, { @@ -135,7 +135,7 @@ "type": "COMESTIBLE", "name": "rose seeds", "name_plural": "rose seeds", - "description": "Some rose seeds.", + "description": "Some rose seeds. You could probably plant these.", "seed_data": { "plant_name": "rose", "fruit": "rose_hips", "byproducts": [ "withered" ], "grow": "91 days" } }, { @@ -144,7 +144,7 @@ "copy-from": "seed", "name": "tobacco seeds", "name_plural": "tobacco seeds", - "description": "Some tobacco seeds.", + "description": "Some tobacco seeds. You could probably plant these.", "seed_data": { "plant_name": "tobacco", "fruit": "tobacco_raw", "grow": "91 days" } }, { @@ -154,7 +154,7 @@ "price": 160, "name": "barley seeds", "name_plural": "barley seeds", - "description": "Some barley seeds.", + "description": "Some barley seeds. You could probably plant these.", "weight": 5, "charges": 2, "stack_size": 40, @@ -167,7 +167,7 @@ "price": 120, "name": "sugar beet seeds", "name_plural": "sugar beet seeds", - "description": "Some sugar beet seeds.", + "description": "Some sugar beet seeds. You could probably plant these.", "volume": 0, "weight": 5, "stack_size": 40, @@ -180,7 +180,7 @@ "price": 50, "name": "lettuce seeds", "name_plural": "lettuce seeds", - "description": "Some lettuce seeds.", + "description": "Some lettuce seeds. You could probably plant these.", "seed_data": { "plant_name": "lettuce", "fruit": "lettuce", "byproducts": [ "withered" ], "grow": "85 days" } }, { @@ -191,7 +191,7 @@ "name": "cabbage seeds", "name_plural": "cabbage seeds", "color": "light_gray", - "description": "Some white cabbage seeds.", + "description": "Some white cabbage seeds. You could probably plant these.", "seed_data": { "plant_name": "cabbage", "fruit": "cabbage", "byproducts": [ "withered" ], "grow": "85 days" } }, { @@ -201,7 +201,7 @@ "price": 50, "name": "tomato seeds", "name_plural": "tomato seeds", - "description": "Some tomato seeds.", + "description": "Some tomato seeds. You could probably plant these.", "seed_data": { "plant_name": "tomato", "fruit": "tomato", "byproducts": [ "withered" ], "grow": "65 days" } }, { @@ -211,7 +211,7 @@ "price": 50, "name": "cotton seeds", "name_plural": "cotton seeds", - "description": "Some cotton seeds. Can be processed to produce an edible oil.", + "description": "Some cotton seeds. Can be processed to produce an edible oil, or can be planted.", "weight": 5, "charges": 8, "stack_size": 40, @@ -224,7 +224,7 @@ "price": 50, "name": "broccoli seeds", "name_plural": "broccoli seeds", - "description": "Some broccoli seeds.", + "description": "Some broccoli seeds. You could probably plant these.", "seed_data": { "plant_name": "broccoli", "fruit": "broccoli", "byproducts": [ "withered" ], "grow": "75 days" } }, { @@ -234,7 +234,7 @@ "price": 50, "name": "zucchini seeds", "name_plural": "zucchini seeds", - "description": "Some zucchini seeds.", + "description": "Some zucchini seeds. You could probably plant these.", "seed_data": { "plant_name": "zucchini", "fruit": "zucchini", "byproducts": [ "withered" ], "grow": "47 days" } }, { @@ -244,7 +244,7 @@ "price": 50, "name": "onion seeds", "name_plural": "onion seeds", - "description": "Some onion seeds.", + "description": "Some onion seeds. You could probably plant these.", "seed_data": { "plant_name": "onion", "fruit": "onion", "byproducts": [ "withered" ], "grow": "65 days" } }, { @@ -254,7 +254,7 @@ "price": 50, "name": "garlic seeds", "name_plural": "garlic seeds", - "description": "Some garlic seeds.", + "description": "Some garlic seeds. You could probably plant these.", "seed_data": { "plant_name": "garlic", "fruit": "garlic", "byproducts": [ "withered" ], "grow": "65 days" } }, { @@ -326,7 +326,7 @@ "price": 50, "name": "carrot seeds", "name_plural": "carrot seeds", - "description": "Some carrot seeds.", + "description": "Some carrot seeds. You could probably plant these.", "seed_data": { "plant_name": "carrot", "fruit": "carrot", "byproducts": [ "withered" ], "grow": "65 days" } }, { @@ -336,7 +336,7 @@ "price": 50, "name": "corn seeds", "name_plural": "corn seeds", - "description": "Some corn seeds.", + "description": "Some corn seeds. You could probably plant these.", "seed_data": { "plant_name": "corn", "fruit": "corn", "byproducts": [ "withered" ], "grow": "80 days" } }, { @@ -347,7 +347,7 @@ "name": "chili pepper seeds", "name_plural": "chili pepper seeds", "color": "white", - "description": "Some chili pepper seeds.", + "description": "Some chili pepper seeds. You could probably plant these.", "seed_data": { "plant_name": "chili pepper", "fruit": "chili_pepper", "byproducts": [ "withered" ], "grow": "65 days" } }, { @@ -357,7 +357,7 @@ "price": 50, "name": "cucumber seeds", "name_plural": "cucumber seeds", - "description": "Some cucumber seeds.", + "description": "Some cucumber seeds. You could probably plant these.", "seed_data": { "plant_name": "cucumber", "fruit": "cucumber", "byproducts": [ "withered" ], "grow": "60 days" } }, { @@ -383,7 +383,7 @@ "quench": -1, "healthy": 1, "calories": 17, - "description": "Seeds of the cannabis plant. Filled with vitamins, they can be roasted or eaten raw.", + "description": "Seeds of the cannabis plant. Filled with vitamins, they can be roasted or eaten raw, or can be planted.", "price": 100, "weight": 2, "charges": 2, @@ -397,7 +397,7 @@ "name": "fungal seeds", "name_plural": "fungal seeds", "color": "dark_gray", - "description": "Some fungal seeds.", + "description": "Some fungal seeds. You could probably plant these.", "ammo_type": "NULL", "stack_size": 8, "seed_data": { "fruit": "null", "//": "dummy entry, results are hardcoded", "plant_name": "fungal flower", "grow": "91 days" } @@ -418,7 +418,7 @@ "healthy": -10, "addiction_potential": 5, "calories": 174, - "description": "This looks like a sunflower seed the size of your palm. It has a strong but delicious aroma, but is clearly either mutated or of alien origin.", + "description": "This looks like a sunflower seed the size of your palm. It has a strong but delicious aroma, but is clearly either mutated or of alien origin. You could probably plant it.", "price": 0, "material": "fruit", "primary_material": "dried_vegetable", @@ -444,7 +444,8 @@ "type": "COMESTIBLE", "id": "soybean_seed", "copy-from": "seed", - "name": "soybean seed", + "name": "soybean seeds", + "name_plural": "soybean seeds", "weight": 160, "symbol": ".", "color": "yellow", @@ -513,7 +514,7 @@ "color": "green", "use_action": "SEED", "calories": 17, - "description": "Some raw sunflower seeds. Could be pressed into oil.", + "description": "Some raw sunflower seeds. Could be pressed into oil or planted.", "price": 100, "charges": 2, "seed_data": { "plant_name": "sunflower", "fruit": "seed_sunflower", "byproducts": [ "withered" ], "grow": "91 days" } @@ -646,7 +647,7 @@ "price": 50, "name": "celery seeds", "name_plural": "celery seeds", - "description": "Some celery seeds.", + "description": "Some celery seeds. You could probably plant these.", "seed_data": { "plant_name": "celery", "fruit": "celery", "byproducts": [ "withered" ], "grow": "130 days" } }, { @@ -656,7 +657,7 @@ "price": 50, "name": "oat seeds", "name_plural": "oat seeds", - "description": "Some oat seeds.", + "description": "Some oat seeds. You could probably plant these.", "material": "wheat", "primary_material": "dried_vegetable", "weight": 5, @@ -669,7 +670,7 @@ "type": "COMESTIBLE", "name": "wheat seeds", "name_plural": "wheat seeds", - "description": "Some wheat seeds.", + "description": "Some wheat seeds. You could probably plant these.", "weight": 5, "price": 50, "stack_size": 40, @@ -764,7 +765,7 @@ "looks_like": "seed_raw_dandelion", "name": "chamomile seeds", "name_plural": "chamomile seeds", - "description": "Some chamomile seeds.", + "description": "Some chamomile seeds. You could probably plant these.", "seed_data": { "plant_name": "chamomile", "fruit": "chamomile", "byproducts": [ "withered" ], "grow": "91 days" } } ] diff --git a/data/json/items/generic.json b/data/json/items/generic.json index d701d1445c60d..ca5d572548e61 100644 --- a/data/json/items/generic.json +++ b/data/json/items/generic.json @@ -608,40 +608,6 @@ "volume": 4, "bashing": 4 }, - { - "type": "GENERIC", - "id": "log", - "symbol": "/", - "color": "brown", - "name": "log", - "description": "A large log, cut from a tree. (a)ctivate a wood axe or wood saw to cut it into planks.", - "category": "other", - "price": 10000, - "price_postapoc": 100, - "material": "wood", - "weight": 9071, - "volume": 40, - "bashing": 10, - "to_hit": -10, - "qualities": [ [ "HAMMER", 1 ] ], - "flags": [ "FIREWOOD" ] - }, - { - "type": "GENERIC", - "id": "splinter", - "symbol": "/", - "color": "brown", - "name": "splintered wood", - "description": "A splintered piece of wood, could be used as a skewer or for kindling.", - "category": "other", - "material": "wood", - "weight": 453, - "volume": 1, - "bashing": 4, - "to_hit": 1, - "qualities": [ [ "COOK", 1 ] ], - "flags": [ "NO_SALVAGE", "TRADER_AVOID", "FIREWOOD" ] - }, { "type": "GENERIC", "id": "skewer_bone", diff --git a/data/json/items/ranged.json b/data/json/items/ranged.json index b47849d09c020..10e780eede30f 100644 --- a/data/json/items/ranged.json +++ b/data/json/items/ranged.json @@ -318,6 +318,34 @@ "loudness": 22, "valid_mod_locations": [ [ "accessories", 4 ], [ "grip", 1 ], [ "mechanism", 4 ], [ "sights", 1 ], [ "sling", 1 ], [ "stock", 1 ] ] }, + { + "id": "pneumatic_shotgun", + "type": "GUN", + "reload_noise_volume": 10, + "symbol": "(", + "color": "dark_gray", + "looks_like": "pipe_double_shotgun", + "name": "pneumatic shotgun", + "description": "A double-barreled pneumatic air shotgun handcrafted from scrap. Though it's firepower is lacking compared to more conventional shotguns, this thing can still pack quite a punch. That is, if your target is directly in front of you.", + "price": 220000, + "material": [ "steel", "wood" ], + "flags": [ "RELOAD_ONE", "STR_RELOAD" ], + "skill": "shotgun", + "ammo": "shotcanister", + "weight": 3410, + "volume": 10, + "bashing": 8, + "to_hit": -1, + "ranged_damage": 15, + "range": 3, + "dispersion": 350, + "durability": 7, + "modes": [ [ "DEFAULT", "single", 1 ], [ "DOUBLE", "double", 2 ] ], + "clip_size": 2, + "reload": 1000, + "loudness": 22, + "valid_mod_locations": [ [ "accessories", 4 ], [ "grip", 1 ], [ "mechanism", 4 ], [ "sights", 1 ], [ "sling", 1 ], [ "stock", 1 ] ] + }, { "id": "mininuke_launcher", "type": "GUN", diff --git a/data/json/items/resources/wood.json b/data/json/items/resources/wood.json index 1f9002ac7848c..be56705362db1 100644 --- a/data/json/items/resources/wood.json +++ b/data/json/items/resources/wood.json @@ -1,4 +1,37 @@ [ + { + "type": "GENERIC", + "id": "log", + "symbol": "/", + "color": "brown", + "name": "log", + "description": "A large chunk of log, cut from a tree. (a)ctivate a wood axe or wood saw to cut it into planks.", + "category": "other", + "price": 10000, + "price_postapoc": 100, + "material": "wood", + "weight": 9071, + "volume": 40, + "bashing": 10, + "to_hit": -10, + "flags": [ "FIREWOOD" ] + }, + { + "type": "GENERIC", + "id": "splinter", + "symbol": "/", + "color": "brown", + "name": "splintered wood", + "description": "A splintered piece of wood, could be used as a skewer or for kindling.", + "category": "other", + "material": "wood", + "weight": 453, + "volume": 1, + "bashing": 4, + "to_hit": 1, + "qualities": [ [ "COOK", 1 ] ], + "flags": [ "NO_SALVAGE", "TRADER_AVOID", "FIREWOOD" ] + }, { "type": "GENERIC", "id": "stick", @@ -35,8 +68,8 @@ { "type": "GENERIC", "id": "2x4", - "name": "two by four", - "description": "A plank of wood. Makes a decent melee weapon, and can be used to board up doors and windows if you have a hammer and nails.", + "name": "plank", + "description": "A narrow, thick plank of wood, like a 2 by 4 or similar piece of dimensional lumber. Makes a decent melee weapon, and can be used for all kinds construction.", "category": "spare_parts", "weight": 1391, "to_hit": 1, @@ -50,6 +83,24 @@ "price_postapoc": 0, "flags": [ "FIREWOOD" ] }, + { + "type": "GENERIC", + "id": "wood_beam", + "name": "heavy wooden beam", + "description": "An enormous beam of solid wood, very heavy and hard to lug around, but also very sturdy for construction. You could saw or chop it into smaller pieces, like planks or panels.", + "category": "spare_parts", + "weight": 36000, + "volume": "60000 ml", + "//": "weight for a roughly 6x6x8 wooden beam. Probably a bit small tbh.", + "to_hit": -2, + "color": "brown", + "symbol": "/", + "material": [ "wood" ], + "bashing": 16, + "price": 40000, + "price_postapoc": 0, + "flags": [ "FIREWOOD" ] + }, { "type": "GENERIC", "id": "wood_panel", @@ -65,7 +116,7 @@ "techniques": [ "WBLOCK_1" ], "volume": 12, "bashing": 8, - "price": 2000, + "price": 8000, "price_postapoc": 0, "flags": [ "FIREWOOD" ] }, @@ -84,7 +135,7 @@ "techniques": [ "WBLOCK_1" ], "volume": 25, "bashing": 8, - "price": 2000, + "price": 20000, "price_postapoc": 0, "flags": [ "FIREWOOD" ] } diff --git a/data/json/mapgen/Glassblower.json b/data/json/mapgen/Glassblower.json index 72ee5f95a23dc..32e8ced2b2f48 100644 --- a/data/json/mapgen/Glassblower.json +++ b/data/json/mapgen/Glassblower.json @@ -11,24 +11,24 @@ "________ss4 2 5 4 ", "_______ss5 52 445 ", "_______s%%--%rr%--%-%% ", - "_______s#...........E% ", + "_______s%...........E% ", "_______sG.n.n.n.n.P%%%5 ", "______s5w.n.n.n.n.B%S% ", "______ss=.n.n.n.n..=.%55", "______s5w.........R%t%1 ", "______s4GEEcccC...P%v%4 ", "______s %....T....E% 4 5", - "______s4%BBB....PEE% ", + "______s4%BBB....PEE%6 ", "______s4%%%%%=%%xx%% 4 ", "______s 5 551 11 55 1 5", "_____s42 41 1 4 2 5 ", "_____s4||||||=|||x|| 4 ", "_____s4|L??%'''qNmY| ", "_____ss='''='''''#'| 2 ", - "______ |fLm%''qqq''| ", + "______ |fLm%''qqq''|6 ", "______4|||v|Q'''''m| 2 ", "______ 2 5|Q'Qqq'Q| 54 ", - "_______ u H|Q'Q''qQ|2 ", + "_______ u H|<'Q''qQ|2 ", "________ H||r|G|w||1 4 ", "______UU5 5 5 " ], @@ -56,22 +56,24 @@ "v": "t_window_domestic", "c": "t_floor", "C": "t_console_broken", - "L": "t_rock_floor", - "'": "t_rock_floor", - "Q": "t_rock_floor", - "Y": "t_rock_floor", - "A": "t_rock_floor", - "q": "t_rock_floor", - "E": "t_rock_floor", - "h": "t_rock_floor", - "z": "t_rock_floor", - "d": "t_rock_floor", - "@": "t_rock_floor", - "f": "t_rock_floor", - "?": "t_rock_floor", - "m": "t_rock_floor", - "N": "t_rock_floor", - "#": "t_rock_floor" + "L": "t_concrete", + "'": "t_concrete", + "Q": "t_concrete", + "Y": "t_concrete", + "A": "t_concrete", + "q": "t_concrete", + "E": "t_concrete", + "h": "t_concrete", + "z": "t_concrete", + "d": "t_concrete", + "@": "t_concrete", + "f": "t_concrete", + "?": "t_concrete", + "m": "t_concrete", + "N": "t_concrete", + "#": "t_concrete", + "6": "t_gutter_downspout", + "<": "t_stairs_up" }, "furniture": { "H": "f_bench", @@ -116,7 +118,7 @@ { "item": "trash", "x": [ 18, 18 ], "y": [ 8, 8 ], "chance": 70, "repeat": [ 2, 10 ] }, { "item": "cleaning", "x": [ 9, 9 ], "y": [ 18, 18 ], "chance": 50, "repeat": [ 2, 10 ] }, { "item": "glass_workroom", "x": [ 14, 16 ], "y": [ 18, 18 ], "chance": 80, "repeat": [ 2, 5 ] }, - { "item": "glass_shop", "x": [ 12, 12 ], "y": [ 20, 21 ], "chance": 50, "repeat": [ 2, 10 ] }, + { "item": "glass_shop", "x": 12, "y": 20, "chance": 50, "repeat": [ 2, 10 ] }, { "item": "glass_shop", "x": [ 14, 14 ], "y": [ 20, 21 ], "chance": 50, "repeat": [ 2, 10 ] }, { "item": "glass_shop", "x": [ 18, 18 ], "y": [ 21, 21 ], "chance": 50, "repeat": [ 2, 10 ] }, { "item": "glass_workroom", "x": [ 17, 17 ], "y": [ 21, 21 ], "chance": 50, "repeat": [ 2, 10 ] }, @@ -132,5 +134,97 @@ ], "place_monsters": [ { "monster": "GROUP_ZOMBIE", "x": [ 2, 21 ], "y": [ 2, 21 ], "chance": 2 } ] } + }, + { + "type": "mapgen", + "method": "json", + "om_terrain": "craft_shop_roof", + "object": { + "fill_ter": "t_floor", + "rows": [ + " ", + " ", + " ", + " |2222222222223 ", + " |............3 ", + " |.........A..3 ", + " |............3 ", + " |...........=3 ", + " |............3 ", + " |..........3-3 ", + " |....&.....3 ", + " |..........5 ", + " |----------3 ", + " ", + " ", + " ****%%v%%v%%% ", + " *y_h%ssscY_Fv ", + " *y__+__scY_ev4 ", + " *yh_%______Sv ", + " ****%_wwwKww% ", + " %_+_w__@% ", + " %>wTwDt@% ", + " %%%%vv%%% ", + " " + ], + "palettes": [ "roof_palette" ], + "terrain": { + "^": "t_floor", + "%": "t_rock_wall", + "w": "t_wall_wood", + "+": "t_door_glass_c", + "v": "t_window_domestic", + "*": "t_rock_wall_half", + "=": "t_flat_roof", + "&": "t_flat_roof", + "A": "t_flat_roof", + ">": "t_stairs_down" + }, + "furniture": { "@": "f_bed", "K": "f_beaded_door", "h": "f_camp_chair", "D": "f_dresser" }, + "items": { + "F": { "item": "fridge", "chance": 40, "repeat": [ 2, 4 ] }, + "e": { "item": "oven", "chance": 50 }, + "S": { "item": "kitchen", "chance": 20, "repeat": [ 2, 4 ] }, + "c": { "item": "kitchen", "chance": 20, "repeat": [ 2, 4 ] }, + "@": { "item": "bed", "chance": 30, "repeat": [ 1, 2 ] }, + "D": { "item": "allclothes", "chance": 60, "repeat": [ 2, 4 ] } + } + } + }, + { + "type": "mapgen", + "method": "json", + "om_terrain": "craft_shop_upper_roof", + "object": { + "fill_ter": "t_flat_roof", + "rows": [ + " ", + " ", + " ", + " ", + " ", + " ", + " ", + " ", + " ", + " ", + " ", + " ", + " ", + " ", + " ", + " |22222223 ", + " BBB|.......3 ", + " BBB|..:....5 ", + " BBB|.......3 ", + " |....&..3 ", + " |.......3 ", + " |.......3 ", + " |-------3 ", + " " + ], + "palettes": [ "roof_palette" ], + "terrain": { "B": "t_open_air_rooved" } + } } ] diff --git a/data/json/mapgen/Metalworker.json b/data/json/mapgen/Metalworker.json index dec4341b09915..3c21c9f55c07c 100644 --- a/data/json/mapgen/Metalworker.json +++ b/data/json/mapgen/Metalworker.json @@ -2,7 +2,7 @@ { "type": "mapgen", "method": "json", - "om_terrain": [ "craft_shop" ], + "om_terrain": [ "craft_shop_1" ], "weight": 200, "object": { "fill_ter": "t_strconc_floor", @@ -12,11 +12,11 @@ "__________8_|--||--||_8_", "_8888^^^^^8_-P.k...P|_8_", "_8__________+..kh..N|_8_", - "_8__________-..kk.||||8_", - "_8________s_|.....|.t|8_", + "_8__________-b.kk.||||8_", + "_8________s_|b....|.t|8_", "_8__|=====%||N....+.S|8_", "_8__|.....sLLR...|||||8_", - "_8__|..............q|_8_", + "_8__|..............q|<8_", "_8__|..........Q...Y|_8_", "_8__|........Q.Q...Y|_8_", "_8__|q.......Q.Q.#.m|_8_", @@ -24,7 +24,7 @@ "_8__|q.............P|_8_", "_8_U|........?||+-|||_8_", "_8_U|R....sRm?|...HHP_8_", - "_8__|=====%|--|......_8_", + "_8_4|=====%|--|......_8_", "_8________s___________8_", "_8_v1__________v3v____8_", "_8_vv________vvvvv___28_", @@ -42,13 +42,15 @@ "v": "t_junk_wall", "^": "t_chaingate_l", "+": "t_door_glass_c", - "_": "t_rock_floor_no_roof", - "U": "t_rock_floor_no_roof", - "2": "t_rock_floor_no_roof", + "_": "t_pavement", + "U": "t_pavement", + "2": "t_pavement", ".": "t_strconc_floor", "3": "t_machinery_heavy", "1": "t_machinery_old", - "#": "t_strconc_floor" + "#": "t_strconc_floor", + "<": "t_ladder_up", + "4": "t_gutter_downspout" }, "furniture": { "H": "f_bench", @@ -66,7 +68,8 @@ "q": "f_crate_c", "U": "f_dumpster", "2": "f_standing_tank", - "?": "f_sofa" + "?": "f_sofa", + "b": "f_bench" }, "toilets": { "t": { } }, "place_items": [ @@ -96,5 +99,70 @@ "place_vehicles": [ { "vehicle": "workshop_vehicles", "x": [ 6, 11 ], "y": [ 9, 15 ], "chance": 50, "fuel": 20, "status": 0 } ], "place_monsters": [ { "monster": "GROUP_ZOMBIE", "x": [ 2, 21 ], "y": [ 2, 21 ], "chance": 4 } ] } + }, + { + "type": "mapgen", + "method": "json", + "om_terrain": "craft_shop_roof_1", + "object": { + "fill_ter": "t_flat_roof", + "rows": [ + " ", + " ", + " |22222223 ", + " |.......3 ", + " |.......3 ", + " |.......33 ", + " |........3 ", + " |2222222|........3 ", + " |...............### ", + " |...............#># ", + " |..............H### ", + " |..............H3 ", + " |...............3 ", + " |...............3 ", + " |...............3 ", + " |...............3 ", + " |...............3 ", + " 5---------------3 ", + " ", + " ", + " ", + " ", + " ", + " " + ], + "palettes": [ "roof_palette" ], + "terrain": { ">": "t_ladder_down" }, + "furniture": { "H": "f_chimney" }, + "place_nested": [ + { + "chunks": [ + [ "null", 20 ], + [ "roof_2x2_utilities_b", 15 ], + [ "roof_2x2_utilities_c", 5 ], + [ "roof_2x2_utilities_d", 40 ], + [ "roof_2x2_utilities", 50 ], + [ "roof_2x2_golf", 20 ], + [ "roof_3x3_wine", 30 ] + ], + "x": 14, + "y": 4 + }, + { + "chunks": [ + [ "null", 20 ], + [ "roof_4x4_party", 15 ], + [ "roof_4x4_holdout", 5 ], + [ "roof_4x4_utility", 40 ], + [ "roof_4x4_utility_1", 30 ], + [ "roof_6x6_survivor", 20 ], + [ "roof_6x6_utility", 20 ] + ], + "x": [ 6, 13 ], + "y": [ 9, 10 ] + } + ] + } } ] diff --git a/data/json/mapgen/Pottery_Sewing_Shops.json b/data/json/mapgen/Pottery_Sewing_Shops.json index 1ec27bd8d2700..3691f3f517911 100644 --- a/data/json/mapgen/Pottery_Sewing_Shops.json +++ b/data/json/mapgen/Pottery_Sewing_Shops.json @@ -2,7 +2,7 @@ { "type": "mapgen", "method": "json", - "om_terrain": [ "craft_shop" ], + "om_terrain": [ "craft_shop_2" ], "weight": 200, "object": { "fill_ter": "t_floor", @@ -12,11 +12,11 @@ "____,____,____,____,____", "____,____,____,____,____", "____,____,____,____,____", - "ssssssssssssssssssssssss", - "ssssusssssssssssssusssss", - "s51|---+-|H;3H|-+---|15s", - "s11|.c..P-52;5-P..c.|11s", - "s4||TC..B|4554|n..CT||4s", + "sssssssssss55sssssssssss", + "ssssussssssb3sssssusssss", + "s51|---+-|s55s|-+---|15s", + "s11|.c..P-ssss-P..c.|11s", + "s4||TC..B||<<||n..CT||4s", "s;|R.c..B||||||n..c.R|;s", "s;|B....B|t|SS|n....B|;s", "s;|B.nn..=wwww=..nn.n|4s", @@ -27,9 +27,9 @@ "s4|**nh*nh*|Q*****|=||;s", "s;|**nh*nh*|Q*******q|;s", "s;|E******q|Q*qY*Y**q|;s", - "s4|||||||=|||=||||||||4s", - "s;__UU_____4_____UU___;s", - "s;_________4__________4s", + "s4|||||||=||||||+|||||4s", + "s;__UU_____4|g_|_UU___;s", + "s;_________2__________4s", "s;_________4__________;s" ], "terrain": { @@ -41,6 +41,7 @@ ",": "t_pavement_y", ";": "t_grass", "H": "t_grass", + "b": "t_grass", "1": "t_shrub_hydrangea", "2": "t_tree_walnut", "3": "t_tree_apple", @@ -60,7 +61,9 @@ "A": "t_thconc_floor", "q": "t_thconc_floor", "E": "t_thconc_floor", - "h": "t_thconc_floor" + "h": "t_thconc_floor", + "g": "t_ladder_up", + "<": "t_stairs_up" }, "furniture": { "H": "f_bench", @@ -75,6 +78,7 @@ "R": "f_trashcan", "Y": "f_clay_kiln", "Q": "f_rack", + "b": "f_birdbath", "q": "f_crate_c", "E": "f_mannequin", "U": "f_dumpster", @@ -110,5 +114,155 @@ ], "place_monsters": [ { "monster": "GROUP_ZOMBIE", "x": [ 2, 21 ], "y": [ 2, 21 ], "chance": 2 } ] } + }, + { + "type": "mapgen", + "method": "json", + "om_terrain": "craft_shop_2ndfloor_2", + "object": { + "fill_ter": "t_floor", + "rows": [ + " ", + " ", + " ", + " ", + " ", + " ", + " ", + " |--|--| |--|--| ", + " |Cttty- -U.C.t| ", + " ||.....||>>||U...t|| ", + " |B.UUU.t|..|yU..CyB| ", + " 0B......|++|......B0 ", + " |.a..a..|..|...a.a.| ", + " 0ccccc..+..+..ccccc0 ", + " |.......||||.......| ", + " |fcoSc.y|&.+..fcoSc| ", + " ||||||+||S9||+|||||| ", + " |y.....A||||B...t@@| ", + " |.@@..h.+.&|B.h..@@| ", + " |t@@.yII|9S|yIIy..A| ", + " ||0|||0||||||0|||0|| ", + " ##2##1## ", + " ", + " " + ], + "terrain": { + ".": "t_floor", + "|": "t_brick_wall", + "+": "t_door_locked", + "-": "t_wall_glass", + "0": "t_window_domestic", + "#": "t_grate", + "1": "t_ladder_down", + "2": "t_ladder_up", + " ": "t_open_air", + ">": "t_stairs_down" + }, + "toilets": { "&": { } }, + "furniture": { + "@": "f_bed", + "o": "f_oven", + "f": "f_fridge", + "S": "f_sink", + "U": "f_sofa", + "t": "f_table", + "c": "f_counter", + "h": "f_chair", + "I": "f_desk", + "C": "f_armchair", + "A": "f_wardrobe", + "a": "f_stool", + "9": "f_shower", + "B": "f_bookcase", + "y": [ "f_indoor_plant_y", "f_indoor_plant" ] + }, + "items": { + "@": { "item": "bed", "chance": 40, "repeat": [ 1, 2 ] }, + "y": { "item": "trash", "chance": 5 }, + "o": { "item": "oven", "chance": 50, "repeat": [ 1, 2 ] }, + "c": { "item": "kitchen", "chance": 40 }, + "f": { "item": "fridge", "chance": 50, "repeat": [ 2, 4 ] }, + "I": { "item": "office", "chance": 30 }, + "A": { "item": "allclothes", "chance": 60, "repeat": [ 2, 4 ] }, + "9": { "item": "softdrugs", "chance": 60, "repeat": [ 1, 2 ] }, + "S": { "item": "shower", "chance": 60, "repeat": [ 1, 2 ] }, + "B": { "item": "homebooks", "chance": 60, "repeat": [ 1, 2 ] } + } + } + }, + { + "type": "mapgen", + "method": "json", + "om_terrain": "craft_shop_roof_2", + "object": { + "fill_ter": "t_tile_flat_roof", + "rows": [ + " ", + " ", + " ", + " ", + " ", + " ", + " ", + " %%%%%%% %%%%%%% ", + " %.....% %.....% ", + " %%.J...%%oo%%.J...%% ", + " %.......%oo%.......% ", + " %.......%%%%.......% ", + " %..................% ", + " %.U......bb.Z......% ", + " %........bb........% ", + " %........bb........% ", + " %..................% ", + " %........bb........% ", + " %........bb........% ", + " %..................% ", + " %%%%%%########%%%%%% ", + " ##1##### ", + " ", + " " + ], + "palettes": [ "roof_palette" ], + "terrain": { + ".": "t_tile_flat_roof", + "U": "t_tile_flat_roof", + "Z": "t_tile_flat_roof", + "J": "t_tile_flat_roof", + "%": "t_glass_railing", + "1": "t_ladder_down" + }, + "nested": { + "U": { + "chunks": [ + [ "roof_6x6_greenhouse_1", 20 ], + [ "roof_6x6_greenhouse_2", 20 ], + [ "roof_6x6_garden_3", 20 ], + [ "roof_6x6_garden_1", 20 ], + [ "roof_6x6_garden_2", 20 ] + ] + }, + "Z": { + "chunks": [ + [ "roof_5x5_coop", 20 ], + [ "roof_6x6_survivor", 20 ], + [ "roof_4x4_utility_1", 20 ], + [ "roof_4x4_holdout", 20 ], + [ "roof_6x6_garden_3", 20 ] + ] + }, + "J": { + "chunks": [ + [ "null", 20 ], + [ "roof_2x2_utilities_b", 15 ], + [ "roof_2x2_utilities_c", 5 ], + [ "roof_2x2_utilities_d", 40 ], + [ "roof_2x2_utilities", 50 ], + [ "roof_2x2_golf", 20 ], + [ "roof_3x3_wine", 30 ] + ] + } + } + } } ] diff --git a/data/json/mapgen/basement/basement_game.json b/data/json/mapgen/basement/basement_game.json index 8da0abb51f3ff..6aa07dc267e19 100644 --- a/data/json/mapgen/basement/basement_game.json +++ b/data/json/mapgen/basement/basement_game.json @@ -239,7 +239,9 @@ "place_loot": [ { "item": "dnd_handbook", "x": 18, "y": 8, "chance": 100 }, { "item": "novel_fantasy", "x": [ 17, 19 ], "y": [ 8, 10 ], "chance": 60, "repeat": [ 0, 4 ] }, - { "item": "character_sheet", "x": [ 17, 19 ], "y": [ 9, 10 ], "chance": 80, "repeat": [ 1, 5 ] } + { "item": "character_sheet", "x": [ 17, 19 ], "y": [ 9, 10 ], "chance": 80, "repeat": [ 1, 5 ] }, + { "item": "metal_RPG_die", "x": 18, "y": 8, "chance": 10 }, + { "item": "RPG_die", "x": [ 17, 19 ], "y": [ 8, 10 ], "chance": 90, "repeat": [ 1, 4 ] } ], "mapping": { "F": { "items": [ { "item": "fridgesnacks", "chance": 80, "repeat": [ 1, 3 ] } ] }, diff --git a/data/json/mapgen/garage_gas.json b/data/json/mapgen/garage_gas.json index faca5fb28b19e..1c2d826e09f44 100644 --- a/data/json/mapgen/garage_gas.json +++ b/data/json/mapgen/garage_gas.json @@ -2,216 +2,155 @@ { "type": "mapgen", "method": "json", - "om_terrain": [ "garage_gas_1" ], + "om_terrain": [ [ "garage_gas_1", "garage_gas_2", "garage_gas_3" ] ], "weight": 250, "object": { - "fill_ter": "t_floor", + "fill_ter": "t_concrete", "rows": [ - "ss______________________", - "ss______________________", - "ss______________________", - "ss______________________", - "ss______________________", - "ss__________________ssss", - "ss________I________sssss", - "ss________&________sss|-", - "ss________I________ssswr", - "ss________s________sssw ", - "ss________s________ssD|r", - "ss________s________sss[ ", - "ss________I________sss[ ", - "ss________&________ssD|r", - "_s________I________sssw ", - "___________________sssw ", - "___________________sss| ", - "___________________sssw ", - "___________________sssw ", - "___________________sss|[", - "___________________sss|r", - "____________________ss| ", - "___________________...|-", - "_s......................" - ], - "set": [ { "point": "terrain", "id": "t_dirt", "x": [ 2, 23 ], "y": 23, "repeat": [ 4, 7 ] } ], - "terrain": { - "&": "t_sidewalk", - "-": "t_wall", - ".": "t_grass", - "D": "t_sidewalk", - "I": "t_column", - "[": "t_door_glass_c", - "_": "t_pavement", - "r": "t_floor", - "s": "t_sidewalk", - "w": "t_window", - "|": "t_wall" - }, - "furniture": { "D": "f_trashcan", "r": "f_rack" }, - "gaspumps": { "&": { } }, - "place_loot": [ - { "group": "magazines", "x": [ 23, 23 ], "y": [ 10, 10 ], "chance": 80, "repeat": [ 1, 2 ] }, - { "group": "magazines", "x": [ 23, 23 ], "y": [ 13, 13 ], "chance": 80, "repeat": [ 1, 2 ] }, - { "group": "floor_trash", "x": [ 21, 21 ], "y": [ 10, 10 ], "chance": 90, "repeat": [ 1, 4 ] }, - { "group": "floor_trash", "x": [ 21, 21 ], "y": [ 13, 13 ], "chance": 90, "repeat": [ 1, 4 ] }, - { "group": "alcohol", "x": [ 23, 23 ], "y": [ 20, 20 ], "chance": 20 }, - { "group": "snacks", "x": [ 23, 23 ], "y": [ 8, 8 ], "chance": 20 } - ], - "place_monsters": [ { "monster": "GROUP_ZOMBIE", "x": [ 0, 23 ], "y": [ 0, 21 ], "chance": 5 } ] - } - }, - { - "type": "mapgen", - "method": "json", - "om_terrain": [ "garage_gas_2" ], - "weight": 250, - "object": { - "fill_ter": "t_floor", - "rows": [ - "________________________", - "________________________", - "________________________", - "________________________", - "________________________", - "ssssssssss__________s___", - "sssssssllss________sss__", - "www-www-|--========---==", - "rrr rrrr| e ", - " [ I ", - " cc [ ", - " cc | ", - " 6 |r ", - " c |r I ", - " c r|r ", - "rrr c r|r ", - "rrr |+-| ", - " | + I ", - " | z|-www-+-| ", - "[[[[[| z| kkk P|rrcccrr", - "rrrrr| z| h |--www--", - " + | ooo|.......", - "--------|-------|.......", - "........................" + "ss_____________________x_______________________x_________s..............", + "ss_______________________________________________________s..............", + "ss_______________________________________________________s..............", + "ss_______________________________________________________s..............", + "ss______________________________________________________ss..............", + "ss__________________ssssssssssssss__________s__________sss..............", + "ss________I________ssssssssssssllse________sss________esssss............", + "ss________&________sss|-www-www-|--========---========---|sssss.........", + "ss________I________ssswrrrr rrrr| e e |ssssss........", + "ss________s________sssw [ I r|---|ss........", + "ss________s________ssD|r cc [ r|t S|ss........", + "ss________s________sss[ cc | r|R +ss........", + "ss________I________sss[ 6 |r c|---|ss........", + "ss________&________ssD|r c |r I c|t +ss........", + "_s________I________sssw c r|r r|S R|s.........", + "___________________sssw rrr c r|r r|---|s.........", + "___________________sss| rrr |+-| +sssss.........", + "___________________sssw | + I w..............", + "___________________sssw | z|-www-+-| w..............", + "___________________sss|[[[[[[| z| kkk P|rrcccrrrrcccrrrr|..............", + "___________________sss|rrrrrr| z| h |--www----www----|..............", + "____________________ss| + | ooo|4..............................", + "___________________...|---------|-------|...............................", + "_s......................................................................" ], "set": [ - { "point": "terrain", "id": "t_dirt", "x": [ 0, 23 ], "y": [ 23, 23 ], "repeat": [ 4, 8 ] }, - { "point": "terrain", "id": "t_dirt", "x": [ 17, 23 ], "y": [ 21, 22 ], "repeat": [ 1, 4 ] } + { "point": "terrain", "id": "t_shrub", "x": [ 64, 71 ], "y": [ 0, 23 ], "repeat": [ 0, 2 ] }, + { "point": "furniture", "id": "f_dandelion", "x": [ 64, 71 ], "y": [ 0, 23 ], "repeat": [ 0, 1 ] }, + { "point": "furniture", "id": "f_bluebell", "x": [ 64, 71 ], "y": [ 0, 23 ], "repeat": [ 0, 1 ] }, + { "point": "furniture", "id": "f_mutpoppy", "x": [ 64, 71 ], "y": [ 0, 23 ], "repeat": [ 0, 1 ] } ], "terrain": { "+": "t_door_c", - "-": "t_wall", - ".": "t_grass", + "-": "t_wall_w", + "|": "t_wall_w", + ".": [ [ "t_grass", 3 ], [ "t_dirt", 3 ], "t_grass_long" ], + " ": "t_concrete", "6": "t_console_broken", "=": "t_door_metal_locked", "I": "t_column", - "P": "t_floor", "[": "t_door_glass_c", "_": "t_pavement", - "c": "t_floor", "e": "t_gates_mech_control", - "h": "t_floor", - "k": "t_floor", "l": "t_sidewalk", - "o": "t_floor", - "r": "t_floor", "s": "t_sidewalk", - "w": "t_window", - "z": "t_floor", - "|": "t_wall" + "&": "t_sidewalk", + "D": "t_sidewalk", + "4": "t_gutter_downspout", + "w": "t_window" }, "furniture": { "P": "f_indoor_plant", + "D": "f_trashcan", + "R": "f_trashcan", "c": "f_counter", "h": "f_chair", "k": "f_desk", "l": "f_vending_c", "o": "f_bookcase", "r": "f_rack", - "z": "f_crate_c" + "z": "f_crate_c", + "S": "f_sink" }, - "place_vendingmachines": [ { "item_group": "vending_food", "x": 7, "y": 6 }, { "item_group": "vending_drink", "x": 8, "y": 6 } ], + "gaspumps": { "&": { } }, + "toilets": { "t": { } }, + "place_vendingmachines": [ { "item_group": "vending_food", "x": 31, "y": 6 }, { "item_group": "vending_drink", "x": 32, "y": 6 } ], "place_loot": [ - { "group": "alcohol", "x": [ 0, 4 ], "y": [ 20, 20 ], "chance": 75, "repeat": [ 1, 2 ] }, - { "group": "snacks", "x": [ 0, 2 ], "y": [ 8, 8 ], "chance": 70, "repeat": [ 1, 2 ] }, - { "group": "mechanics", "x": [ 4, 7 ], "y": [ 8, 8 ], "chance": 65, "repeat": [ 1, 2 ] }, - { "group": "snacks", "x": [ 0, 2 ], "y": [ 15, 16 ], "chance": 80, "repeat": [ 1, 3 ] }, - { "group": "snacks", "x": [ 7, 7 ], "y": [ 18, 20 ], "chance": 50, "repeat": [ 1, 4 ] }, - { "group": "smoke_shop", "x": [ 7, 7 ], "y": [ 14, 15 ], "chance": 70, "repeat": [ 1, 2 ] }, - { "group": "office", "x": [ 10, 12 ], "y": [ 19, 19 ], "chance": 75, "repeat": [ 1, 2 ] }, - { "group": "manuals", "x": [ 13, 15 ], "y": [ 21, 21 ], "chance": 60, "repeat": [ 1, 2 ] }, - { "group": "mechanics", "x": [ 9, 9 ], "y": [ 12, 15 ], "chance": 65, "repeat": [ 1, 2 ] }, - { "group": "mechanics", "x": [ 17, 23 ], "y": [ 19, 19 ], "chance": 75, "repeat": [ 1, 3 ] } + { "group": "magazines", "x": [ 23, 23 ], "y": [ 10, 10 ], "chance": 80, "repeat": [ 1, 2 ] }, + { "group": "magazines", "x": [ 23, 23 ], "y": [ 13, 13 ], "chance": 80, "repeat": [ 1, 2 ] }, + { "group": "floor_trash", "x": [ 21, 21 ], "y": [ 10, 10 ], "chance": 90, "repeat": [ 1, 4 ] }, + { "group": "floor_trash", "x": [ 21, 21 ], "y": [ 13, 13 ], "chance": 90, "repeat": [ 1, 4 ] }, + { "group": "alcohol", "x": [ 23, 23 ], "y": [ 20, 20 ], "chance": 20 }, + { "group": "snacks", "x": [ 23, 23 ], "y": [ 8, 8 ], "chance": 20 }, + { "group": "alcohol", "x": [ 24, 28 ], "y": 20, "chance": 75, "repeat": [ 1, 2 ] }, + { "group": "snacks", "x": [ 24, 26 ], "y": 8, "chance": 70, "repeat": [ 1, 2 ] }, + { "group": "mechanics", "x": [ 28, 31 ], "y": 8, "chance": 65, "repeat": [ 1, 2 ] }, + { "group": "snacks", "x": [ 24, 26 ], "y": [ 15, 16 ], "chance": 80, "repeat": [ 1, 3 ] }, + { "group": "snacks", "x": 31, "y": [ 18, 20 ], "chance": 50, "repeat": [ 1, 4 ] }, + { "group": "smoke_shop", "x": 31, "y": [ 14, 15 ], "chance": 70, "repeat": [ 1, 2 ] }, + { "group": "office", "x": [ 34, 36 ], "y": 19, "chance": 75, "repeat": [ 1, 2 ] }, + { "group": "manuals", "x": [ 37, 39 ], "y": 21, "chance": 60, "repeat": [ 1, 2 ] }, + { "group": "mechanics", "x": 33, "y": [ 12, 15 ], "chance": 65, "repeat": [ 1, 2 ] }, + { "group": "mechanics", "x": [ 41, 47 ], "y": 19, "chance": 75, "repeat": [ 1, 3 ] }, + { "group": "mechanics", "x": 56, "y": [ 9, 15 ], "chance": 70, "repeat": [ 1, 2 ] }, + { "group": "mechanics", "x": [ 48, 56 ], "y": [ 19, 19 ], "chance": 75, "repeat": [ 1, 3 ] }, + { "group": "field", "x": [ 63, 70 ], "y": [ 2, 23 ], "chance": 90, "repeat": [ 0, 2 ] } + ], + "place_monsters": [ + { "monster": "GROUP_ZOMBIE", "x": [ 0, 23 ], "y": [ 0, 21 ], "chance": 5 }, + { "monster": "GROUP_ZOMBIE", "x": [ 24, 47 ], "y": [ 0, 21 ], "chance": 5 }, + { "monster": "GROUP_ZOMBIE", "x": [ 48, 71 ], "y": [ 0, 19 ], "chance": 5 } ], - "place_monsters": [ { "monster": "GROUP_ZOMBIE", "x": [ 0, 23 ], "y": [ 0, 21 ], "chance": 5 } ], - "place_vehicles": [ { "vehicle": "garage", "x": [ 14, 15 ], "y": [ 12, 13 ], "chance": 20, "rotation": 270 } ] + "place_vehicles": [ + { "vehicle": "garage", "x": [ 38, 39 ], "y": [ 12, 13 ], "chance": 20, "rotation": 270 }, + { "vehicle": "garage", "x": [ 49, 50 ], "y": [ 12, 13 ], "chance": 20, "rotation": 270 } + ] } }, { "type": "mapgen", "method": "json", - "om_terrain": [ "garage_gas_3" ], - "weight": 250, + "om_terrain": [ [ "garage_gas_roof_1", "garage_gas_roof_2", "garage_gas_roof_3" ] ], "object": { - "fill_ter": "t_floor", + "fill_ter": "t_flat_roof", "rows": [ - "_________s..............", - "_________s..............", - "_________s..............", - "_________s..............", - "________ss..............", - "_______sss..............", - "______ssssss............", - "======---|sssss.........", - " e |ssssss........", - " r|---|ss........", - " r| S|ss........", - " r|t +ss........", - " c|---|ss........", - " c|t +ss........", - " r| S|s.........", - " r|---|s.........", - " +sssss.........", - " w..............", - " w..............", - "rrcccrrrr|..............", - "--www----|..............", - "........................", - "........................", - "........................" - ], - "set": [ - { "point": "terrain", "id": "t_dirt", "x": [ 16, 23 ], "y": [ 0, 23 ], "repeat": [ 32, 64 ] }, - { "point": "terrain", "id": "t_dirt", "x": [ 10, 15 ], "y": [ 0, 5 ], "repeat": [ 6, 12 ] }, - { "point": "terrain", "id": "t_dirt", "x": [ 10, 15 ], "y": [ 17, 23 ], "repeat": [ 7, 14 ] }, - { "point": "terrain", "id": "t_dirt", "x": [ 0, 9 ], "y": [ 21, 23 ], "repeat": [ 5, 10 ] }, - { "point": "terrain", "id": "t_shrub", "x": [ 16, 23 ], "y": [ 0, 23 ], "repeat": [ 0, 2 ] }, - { "point": "furniture", "id": "f_dandelion", "x": [ 16, 23 ], "y": [ 0, 23 ], "repeat": [ 0, 1 ] }, - { "point": "furniture", "id": "f_bluebell", "x": [ 16, 23 ], "y": [ 0, 23 ], "repeat": [ 0, 1 ] }, - { "point": "furniture", "id": "f_mutpoppy", "x": [ 16, 23 ], "y": [ 0, 23 ], "repeat": [ 0, 1 ] } - ], - "terrain": { - "+": "t_door_c", - "-": "t_wall", - ".": "t_grass", - "=": "t_door_metal_locked", - "S": "t_floor", - "_": "t_pavement", - "c": "t_floor", - "e": "t_gates_mech_control", - "r": "t_floor", - "s": "t_sidewalk", - "t": "t_floor", - "w": "t_window", - "|": "t_wall" - }, - "furniture": { "S": "f_sink", "c": "f_counter", "r": "f_rack" }, - "toilets": { "t": { } }, - "place_loot": [ - { "group": "mechanics", "x": [ 8, 8 ], "y": [ 9, 15 ], "chance": 70, "repeat": [ 1, 2 ] }, - { "group": "mechanics", "x": [ 0, 8 ], "y": [ 19, 19 ], "chance": 75, "repeat": [ 1, 3 ] }, - { "group": "field", "x": [ 15, 23 ], "y": [ 2, 23 ], "chance": 90, "repeat": [ 0, 2 ] } + " x x ", + " ", + " ", + " ", + " ", + " ", + " ", + " ... |22222222222222222222222222222222223 ", + " ... |..................................3 ", + " ... |...:..............................32223 ", + " ... |......................................3 ", + " ... |....................................=.3 ", + " ... |......................................3 ", + " ... |....................................=.3 ", + " ... |......................................3 ", + " |..................................3---3 ", + " |..................................3 ", + " |..................................3 ", + " |...........................&......3 ", + " |..................................3 ", + " |.................5----------------3 ", + " |.................3 ", + " |-----------------3 ", + " " ], - "place_monsters": [ { "monster": "GROUP_ZOMBIE", "x": [ 0, 12 ], "y": [ 0, 19 ], "chance": 5 } ], - "place_vehicles": [ { "vehicle": "garage", "x": [ 1, 2 ], "y": [ 12, 13 ], "chance": 20, "rotation": 270 } ] + "palettes": [ "roof_palette" ], + "place_nested": [ + { + "chunks": [ + [ "null", 20 ], + [ "roof_2x2_utilities_b", 15 ], + [ "roof_2x2_utilities_c", 5 ], + [ "roof_2x2_utilities_d", 10 ], + [ "roof_2x2_utilities", 10 ] + ], + "x": [ 24, 46 ], + "y": [ 10, 15 ] + } + ] } } ] diff --git a/data/json/mapgen/garden_botanical.json b/data/json/mapgen/garden_botanical.json index b075e2e1120e7..b9b25cf3bdef7 100644 --- a/data/json/mapgen/garden_botanical.json +++ b/data/json/mapgen/garden_botanical.json @@ -1,89 +1,89 @@ [ { "method": "json", + "om_terrain": [ [ "BotanicalGarden_1a", "BotanicalGarden_1b" ] ], + "type": "mapgen", + "weight": 100, "object": { - "furniture": { - "#": "f_null", - "+": "f_null", - ".": "f_null", - "4": "f_null", - "7": "f_null", - "B": "f_bench", - "D": [ "f_dandelion", "f_null", "f_null" ], - "F": [ "f_mutcactus_test", "f_null", "f_null" ], - "P": "f_sign", - "S": "f_null", - "T": "f_null", - "_": "f_null", - "a": "f_null", - "b": "f_bench", - "c": "f_null", - "d": "f_null", - "e": "f_null", - "Z": "f_trashcan", - "f": [ "f_chamomile", "f_null", "f_null" ], - "G": [ "f_bluebell", "f_null", "f_null" ], - "h": "f_null", - "I": [ "f_dahlia", "f_null", "f_null" ], - "m": [ "f_mutpoppy", "f_null", "f_null" ], - "s": "f_sign", - "t": "f_null", - "|": "f_null" - }, - "place_items": [ { "chance": 20, "repeat": [ 1, 3 ], "item": "trash", "x": 10, "y": 12 } ], + "fill_ter": "t_grass", "rows": [ - "cccccccccccccccccccccccc", - "cccccccccccccccccccccccc", - "...#.#.#.#...#...7...P__", - "..._____.....4...P.#.___", - ".#.______..#.P......____", - "..__.#..__......._____..", - "#.__....___....______...", - "..__.TP.._________.___..", - "..__#...._______..._____", - "..___#.._____..#.P..____", - ".#________#......a......", - "....______....#....#..#.", - "#.#..#.__.Z|||||||||||||", - "..eP...__.b|fffftFFFFtGG", - "....______b|ffsftFFsFtGG", - "..#________|fffftFFFFtGG", - "#..___..___+tttttttttttt", - "..__....___+tttttttttttt", - ".#__.hP.___|mmmmtDDDDtII", - "..__....__b|mmsmtDDsDtII", - ".#________b|mmmmtDDDDtII", - "...______..|||||||||||||", - "....#.........#......#..", - "#..#...#...#.......#...." + "cccccccccccccccccccccccccccccccccccccccccccccccc", + "cccccccccccccccccccccccccccccccccccccccccccccccc", + "...#.#.#.#...#...X...P____P...7..#........#.....", + "..._____.....4...P.#.______.#.P...T..#..._____#.", + ".#.______..#.P......________......P.....______..", + "..__.#..__......._____...._____........__..#.__.", + "#.__....___....______...j..______...#.___....__.", + "..__.KP.._________.___..P.___._________#.Pa..__#", + "..__#...._______...__________..._______......__.", + "..___#.._____..#.P..________..P.._______..#.___.", + ".#________#......3............9.#....._________.", + "....______....#....#..#..#..#......#.._______...", + "#.#..#.__.Z||||||||||||||||||||||||||&.__.#...#.", + "..6P...__.b|fffftFFFFtGGGGtiiiitSSSS|b.__...Pe..", + "....______b|ffsftFFsFtGGsGtisiitSsSS|b______....", + "..#________|fffftFFFFtGGGGtiiiitSSSS|________#..", + "#..___..___+tttttttttttttttttttttttt+___.#___...", + "..__....___+tttttttttttttttttttttttt+___....__.#", + ".#__.hP.___|mmmmtDDDDtIIIIt****tBBBB|___.Pg.__..", + "..__....__b|mmsmtDDsDtIIsIt*s**tBsBB|b__....__..", + ".#________b|mmmmtDDDDtIIIIt****tBBBB|b________#.", + "...______..||||||||||||||||||||||||||..______...", + "....#.........#......#.......#........#......#..", + "#..#...#...#.......#....#....#....#......#......" ], "terrain": { "#": "t_underbrush", "+": "t_reinforced_door_glass_c", ".": [ "t_grass", "t_grass", "t_grass", "t_grass", "t_dirt" ], + "B": [ "t_shrub_blueberry", "t_dirtfloor", "t_dirtfloor" ], + "S": [ "t_shrub_strawberry", "t_dirtfloor", "t_dirtfloor" ], "4": "t_tree_willow", - "7": "t_tree", - "B": "t_underbrush", - "D": "t_dirtfloor", - "F": "t_dirtfloor", + "K": "t_tree_pine", + "6": "t_tree_hickory", + "3": "t_tree_maple", + "h": "t_tree_birch", + "7": "t_tree_pear", + "T": "t_tree_cherry", + "a": "t_tree_peach", + "9": "t_tree_apple", + "e": "t_tree_apricot", + "g": "t_tree_plum", + "j": "t_tree_coffee", + "X": "t_tree", "P": "t_grass", - "T": "t_tree_pine", - "_": "t_concrete", - "a": "t_tree_maple", + "&": "t_grass", "b": "t_grass", "Z": "t_grass", - "c": "t_sidewalk", "d": "t_dirtfloor", - "e": "t_tree_hickory", "f": "t_dirtfloor", "G": "t_dirtfloor", - "h": "t_tree_birch", "I": "t_dirtfloor", "m": "t_dirtfloor", "s": "t_dirtfloor", + "*": "t_dirtfloor", + "D": "t_dirtfloor", + "F": "t_dirtfloor", + "i": "t_dirtfloor", + "_": "t_concrete", + "c": "t_sidewalk", "t": "t_thconc_floor", "|": "t_wall_glass" }, + "furniture": { + "b": "f_bench", + "Z": "f_trashcan", + "s": "f_sign", + "P": "f_sign", + "D": [ "f_dandelion", "f_null", "f_null" ], + "*": [ "f_datura", "f_null", "f_null" ], + "i": [ "f_cattails", "f_null", "f_null" ], + "I": [ "f_dahlia", "f_null", "f_null" ], + "f": [ "f_chamomile", "f_null", "f_null" ], + "F": [ "f_mutcactus_test", "f_null", "f_null" ], + "G": [ "f_bluebell", "f_null", "f_null" ], + "m": [ "f_mutpoppy", "f_null", "f_null" ] + }, "place_signs": [ { "signage": "Welcome to Botanical Garden! Please stay on the path!", "x": 21, "y": 2 }, { "signage": "WILLOW", "x": 13, "y": 4 }, @@ -95,114 +95,61 @@ { "signage": "CHAMOMILE", "x": 14, "y": 14 }, { "signage": "POPPY", "x": 14, "y": 19 }, { "signage": "CACTUS", "x": 19, "y": 14 }, - { "signage": "DANDELION", "x": 19, "y": 19 } + { "signage": "DANDELION", "x": 19, "y": 19 }, + { "signage": "Welcome to Botanical Garden! Please stay on the path!", "x": 26, "y": 2 }, + { "signage": "KENTUCKY COFFEE", "x": 24, "y": 7 }, + { "signage": "PEAR", "x": 30, "y": 3 }, + { "signage": "CHERRY", "x": 34, "y": 4 }, + { "signage": "APPLE", "x": 30, "y": 9 }, + { "signage": "PEACH", "x": 41, "y": 7 }, + { "signage": "APRICOT", "x": 44, "y": 13 }, + { "signage": "PLUM", "x": 41, "y": 18 }, + { "signage": "BLUEBELL", "x": 24, "y": 14 }, + { "signage": "DAHLIA", "x": 24, "y": 19 }, + { "signage": "CATTAIL", "x": 28, "y": 14 }, + { "signage": "DATURA", "x": 28, "y": 19 }, + { "signage": "STRAWBERRY", "x": 33, "y": 14 }, + { "signage": "BLUEBERRY", "x": 33, "y": 19 } + ], + "place_items": [ + { "chance": 20, "repeat": [ 1, 3 ], "item": "trash", "x": 10, "y": 12 }, + { "chance": 20, "repeat": [ 1, 3 ], "item": "trash", "x": 37, "y": 12 } ] - }, - "om_terrain": "BotanicalGarden_1a", - "type": "mapgen", - "weight": 100 + } }, { + "type": "mapgen", "method": "json", + "om_terrain": [ [ "BotanicalGarden_1a_roof", "BotanicalGarden_1b_roof" ] ], "object": { - "furniture": { - "#": "f_null", - "&": "f_trashcan", - "*": [ "f_datura", "f_null", "f_null" ], - "+": "f_null", - ".": "f_null", - "7": "f_null", - "P": "f_sign", - "S": "f_null", - "T": "f_null", - "_": "f_null", - "a": "f_null", - "b": "f_bench", - "c": "f_null", - "d": "f_null", - "e": "f_null", - "g": "f_null", - "G": [ "f_bluebell", "f_null", "f_null" ], - "i": [ "f_cattails", "f_null", "f_null" ], - "I": [ "f_dahlia", "f_null", "f_null" ], - "s": "f_sign", - "t": "f_null", - "|": "f_null" - }, - "place_items": [ { "chance": 20, "repeat": [ 1, 3 ], "item": "trash", "x": 13, "y": 12 } ], + "fill_ter": "t_glass_roof", "rows": [ - "________________________", - "________________________", - "__P...7..#........#.....", - "___.#.P...T..#..._____#.", - "____......P.....______..", - ".._____........__..#.__.", - "j..______...#.___....__.", - "P.___._________#.Pa..__#", - "_____..._______......__.", - "____..P.._______..#.___.", - "......c.#....._________.", - ".#..#......#.._______...", - "|||||||||||||&.__.#...#.", - "GGtiiiitSSSS|b.__...Pe..", - "sGtisiitSsSS|b______....", - "GGtiiiitSSSS|________#..", - "tttttttttttt+___.#___...", - "tttttttttttt+___....__.#", - "IIt****tBBBB|___.Pg.__..", - "sIt*s**tBsBB|b__....__..", - "IIt****tBBBB|b________#.", - "|||||||||||||..______...", - ".....#........#......#..", - ".#....#....#......#....." + " ", + " ", + " ", + " ", + " ", + " ", + " ", + " ", + " ", + " ", + " ", + " ", + " oooooooooooooooooooooooooo ", + " oooooooooooooooooooooooooo ", + " oooooooooooooooooooooooooo ", + " oooooooooooooooooooooooooo ", + " oooooooooooooooooooooooooo ", + " oooooooooooooooooooooooooo ", + " oooooooooooooooooooooooooo ", + " oooooooooooooooooooooooooo ", + " oooooooooooooooooooooooooo ", + " oooooooooooooooooooooooooo ", + " ", + " " ], - "terrain": { - "#": "t_underbrush", - "&": "t_grass", - "*": "t_dirtfloor", - "+": "t_reinforced_door_glass_c", - ".": [ "t_grass", "t_grass", "t_grass", "t_grass", "t_dirt" ], - "7": "t_tree_pear", - "P": "t_grass", - "B": [ "t_shrub_blueberry", "t_dirtfloor", "t_dirtfloor" ], - "S": [ "t_shrub_strawberry", "t_dirtfloor", "t_dirtfloor" ], - "T": "t_tree_cherry", - "_": "t_concrete", - "a": "t_tree_peach", - "b": "t_grass", - "c": "t_tree_apple", - "d": "t_dirtfloor", - "e": "t_tree_apricot", - "f": "t_dirtfloor", - "g": "t_tree_plum", - "i": "t_dirtfloor", - "I": "t_dirtfloor", - "G": "t_dirtfloor", - "m": "t_dirtfloor", - "s": "t_dirtfloor", - "t": "t_thconc_floor", - "j": "t_tree_coffee", - "|": "t_wall_glass" - }, - "place_signs": [ - { "signage": "Welcome to Botanical Garden! Please stay on the path!", "x": 2, "y": 2 }, - { "signage": "KENTUCKY COFFEE", "x": 0, "y": 7 }, - { "signage": "PEAR", "x": 6, "y": 3 }, - { "signage": "CHERRY", "x": 10, "y": 4 }, - { "signage": "APPLE", "x": 6, "y": 9 }, - { "signage": "PEACH", "x": 17, "y": 7 }, - { "signage": "APRICOT", "x": 20, "y": 13 }, - { "signage": "PLUM", "x": 17, "y": 18 }, - { "signage": "BLUEBELL", "x": 0, "y": 14 }, - { "signage": "DAHLIA", "x": 0, "y": 19 }, - { "signage": "CATTAIL", "x": 4, "y": 14 }, - { "signage": "DATURA", "x": 4, "y": 19 }, - { "signage": "STRAWBERRY", "x": 9, "y": 14 }, - { "signage": "BLUEBERRY", "x": 9, "y": 19 } - ] - }, - "om_terrain": "BotanicalGarden_1b", - "type": "mapgen", - "weight": 100 + "palettes": [ "roof_palette" ] + } } ] diff --git a/data/json/mapgen/parking_lot.json b/data/json/mapgen/parking_lot.json new file mode 100644 index 0000000000000..1fde804f6d9e6 --- /dev/null +++ b/data/json/mapgen/parking_lot.json @@ -0,0 +1,135 @@ +[ + { + "type": "mapgen", + "method": "json", + "om_terrain": [ [ "parking_2x1_0", "parking_2x1_1" ] ], + "weight": 250, + "object": { + "fill_ter": "t_floor", + "rows": [ + "................................................", + "....____-____-____-____-____-____-____-____-....", + "...-____-____-____-____-____-____-____-____-_...", + ".._-____-____-____-____-____-____-____-____-__..", + ".__-____-____-____-____-____-____-____-____-___.", + ".__-____-____-____-____-____-____-____-____-___.", + ".__-____-____-____-____-____-____-____-____-___.", + ".______________________________________________.", + ".______________________________________________.", + ".______________________________________________.", + ".______________________________________________.", + ".______________________________________________.", + ".______________________________________________.", + ".______________________________________________.", + ".______________________________________________.", + ".______________________________________________.", + ".______________________________________________.", + ".__-___-____-____-____-____-___________________.", + ".__-___-____-____-____-____-___________________.", + ".__-___-____-____-____-____-___________________.", + ".._-___-____-____-____-____-__________________..", + "...-___-____-____-____-____-_________________...", + "....___-____-____-____-____-________________....", + "............................_______--_______...." + ], + "terrain": { ".": [ [ "t_grass", 6 ], [ "t_dirt", 5 ] ], "_": "t_pavement", "-": "t_pavement_y" } + } + }, + { + "type": "mapgen", + "method": "json", + "om_terrain": [ [ "parking_3x1_0", "parking_3x1_1", "parking_3x1_2" ] ], + "weight": 250, + "object": { + "fill_ter": "t_floor", + "rows": [ + "........................................................................", + "....___-____-____-____-____-____-____-____-____-____-____-____-____-....", + "...____-____-____-____-____-____-____-____-____-____-____-____-____-_...", + ".._____-____-____-____-____-____-____-____-____-____-____-____-____-__..", + ".______-____-____-____-____-____-____-____-____-____-____-____-____-___.", + ".______-____-____-____-____-____-____-____-____-____-____-____-____-___.", + ".______-____-____-____-____-____-____-____-____-____-____-____-____-___.", + ".______________________________________________________________________.", + ".______________________________________________________________________.", + ".______________________________________________________________________.", + ".______________________________________________________________________.", + ".______________________________________________________________________.", + ".______________________________________________________________________.", + ".______________________________________________________________________.", + ".______________________________________________________________________.", + ".______________________________________________________________________.", + ".______________________________________________________________________.", + "._____-____-____-____-____-____-____-____-____-____-___________________.", + "._____-____-____-____-____-____-____-____-____-____-___________________.", + "._____-____-____-____-____-____-____-____-____-____-___________________.", + "..____-____-____-____-____-____-____-____-____-____-__________________..", + "...___-____-____-____-____-____-____-____-____-____-_________________...", + "....__-____-____-____-____-____-____-____-____-____-________________....", + "...................................................._______--_______...." + ], + "terrain": { ".": [ [ "t_grass", 6 ], [ "t_dirt", 5 ] ], "_": "t_pavement", "-": "t_pavement_y" } + } + }, + { + "type": "mapgen", + "method": "json", + "om_terrain": [ [ "parking_2x2_0_0", "parking_2x2_1_0" ], [ "parking_2x2_0_1", "parking_2x2_1_1" ] ], + "weight": 250, + "object": { + "fill_ter": "t_floor", + "rows": [ + "................................................", + "....__-____-____-____-____-_________________....", + "...___-____-____-____-____-__________________...", + "..____-____-____-____-____-___________________..", + "._____-____-____-____-____-____________________.", + "._____-____-____-____-____-____________________.", + "._____-____-____-____-____-____________________.", + ".______________________________________________.", + ".______________________________________________.", + ".______________________________________________.", + ".______________________________________________.", + ".______________________________________________.", + ".______________________________________________.", + ".______________________________________________.", + ".______________________________________________.", + ".______________________________________________.", + ".______________________________________________.", + "._____-____-____-____-____-____________________.", + "._____-____-____-____-____-____________________.", + "._____-____-____-____-____-____________________.", + "._____-____-____-____-____-____________________.", + "._____-____-____-____-____-____________________.", + "._____-____-____-____-____-____________________.", + ".,,,,,,,,,,,,,,,,,,,,,,,,,,____________________.", + "..........................,____________________.", + ".,,,,,,,,,,,,,,,,,,,,,,,,,,____________________.", + "._____-____-____-____-____-____________________.", + "._____-____-____-____-____-____________________.", + "._____-____-____-____-____-____________________.", + "._____-____-____-____-____-____________________.", + "._____-____-____-____-____-____________________.", + "._____-____-____-____-____-____________________.", + ".______________________________________________.", + ".______________________________________________.", + ".______________________________________________.", + ".______________________________________________.", + ".______________________________________________.", + ".______________________________________________.", + ".______________________________________________.", + ".______________________________________________.", + ".______________________________________________.", + ".______________________________________________.", + "._____-____-____-____-____-____________________.", + "._____-____-____-____-____-____________________.", + "._____-____-____-____-____-____________________.", + "..____-____-____-____-____-___________________..", + "...___-____-____-____-____-__________________...", + "....__-____-____-____-____-_________________....", + "..........................._______--_______....." + ], + "terrain": { ".": [ [ "t_grass", 6 ], [ "t_dirt", 5 ] ], "_": "t_pavement", "-": "t_pavement_y", ",": "t_concrete" } + } + } +] diff --git a/data/json/mapgen/prison_1.json b/data/json/mapgen/prison_1.json index ee9c2685c6317..9f6747c03c386 100644 --- a/data/json/mapgen/prison_1.json +++ b/data/json/mapgen/prison_1.json @@ -286,11 +286,11 @@ "```~~~~~~~~ *** ^^^ F____(_(______(_(____F $o,,,,h$11111$o,,dh$ *$I,,,+,,,+,,,C$C,,,+,,,+,,,I$ ***^^^)~~~``", "```~~~~~~~~~ ** ^^^ F___(__(______(__(___F $1,,,dd$,,,,,$o,,d,$ wC,hd$,,,$dh,I$I,hd$,,,$dh,Cw **^^^)~~~``", "```~~~~~~~~~~ * ^^^ F___(__(______(__(___F g1,,,,,$$$?$$$Y,,,,g $$$$$$,,,$$$$$$$$$$$,,,$$$$$$ **^^^)~~~```", - "````~~~~~~~~~ ** ^^^ F___(__((((((((__(___F $Y,,,,,?,,,,,?,,111$ $I,,,+,,,$A,,t,,,,o$,,,$0000$ **^^^)~~~````", - "```~~~~~~~~~~ ***** ^^^^ F___(__(______(__(___F $$$$$$$$,,,,,$$$$$$$ wC,hd$,,,$A,,t,,,,o$,,,$,,,0$**^^^)~~~~````", - "``~~~~~~~~~~ ********^^^ F___(__(______(__(___F $o,,,,1$,,,,,$S,=,T$ $$$$$$,,,$A,,,,,,,J$,,,+,,,0$*^^^)~~~~~````", - "```~~~~~~~~~ **********^^^F____(_(______(_(____F gdd,,,,?,,,,,$,,$$$$ $I,,,+,,,$$$$$+$$$$$,,,$,,,0$*^^^)~~~~~````", - "````~~~~~~~~~ ** ****^^^F_____(________(_____F $h,,,,Y$,,,,,=,,=,T$ wC,hd$,,,,,,,,,,,,,,,,,$0000$*^^^)~~~~~````", + "````~~~~~~~~~ ** ^^^ F___(__((((((((__(___F $Y,,,,,?,,,,,?,,111$ $I,,,+,,,$A,,t,,,,o$,,,$$000$ **^^^)~~~````", + "```~~~~~~~~~~ ***** ^^^^ F___(__(______(__(___F $$$$$$$$,,,,,$$$$$$$ wC,hd$,,,$A,,t,,,,o$,,,$$,,0$**^^^)~~~~````", + "``~~~~~~~~~~ ********^^^ F___(__(______(__(___F $o,,,,1$,,,,,$S,=,T$ $$$$$$,,,$A,,,,,,,J$,,,+G,,0$*^^^)~~~~~````", + "```~~~~~~~~~ **********^^^F____(_(______(_(____F gdd,,,,?,,,,,$,,$$$$ $I,,,+,,,$$$$$+$$$$$,,,$$,,0$*^^^)~~~~~````", + "````~~~~~~~~~ ** ****^^^F_____(________(_____F $h,,,,Y$,,,,,=,,=,T$ wC,hd$,,,,,,,,,,,,,,,,,$$000$*^^^)~~~~~````", "```~~~~~~~~~~ * ****** ^^^F______((((((((______F $$$$$$$$$$+$$$$$$$$$ $$$$$$$$$$$$$$+$$$$$$$$$$$$$$**^^)~~~~~~```", "```~~~~~~~~ *** ^^^FffffffffffHfffffffffF^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^*^^)~~~~~~```", "```~~~~~~~~ **|-----|^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^|-----|^*^^)~~~~~~~``", @@ -314,9 +314,9 @@ "````~~~~~ *** **** %'F g,,,,,,,,,,,,,,,,,,,,B,,B,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,g F'% ~~~~````", "`````~~~~ ** %'F g,,,,,,,,,,,,,,,,,,,,G,,G,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,g F'% ~~~~`````", "`````~~~~~ ** %'F |--BBGBB--|BG|-BBGBB-|BG|----|BBGBB|----|----|BBGBB|----|----|BBGBB|----| F'% ~~~~`````", - "````~~~~~~~ ** %'F |Y,,,,,,,3|,,|Y,,,,,l|,,|T,,,B,,,,,B,,,T|T,,,B,,,,,B,,,T|T,,,B,,,,,B,,,T| F'% ~~~~`````", - "```~~~~~~~~~ ** %'F |Y,,333,,3|,,|Y,,,,,l|,,|bb,,G,,,,,G,,bb|bb,,G,,,,,G,,bb|bb,,G,,,,,G,,bb| F'% ~~~~~~````", - "``~~~~~~~~~~ ** %'F |Y,,,,,,,3|,,|Y,,,,,l|,,|----|,,,,,|----|----|,,,,,|----|----|,,,,,|----| F'% ~~~~~`````", + "````~~~~~~~ ** %'F |X,,,,,,,3|,,|X,,,,,l|,,|T,,,B,,,,,B,,,T|T,,,B,,,,,B,,,T|T,,,B,,,,,B,,,T| F'% ~~~~`````", + "```~~~~~~~~~ ** %'F |X,,333,,3|,,|X,,,,,l|,,|bb,,G,,,,,G,,bb|bb,,G,,,,,G,,bb|bb,,G,,,,,G,,bb| F'% ~~~~~~````", + "``~~~~~~~~~~ ** %'F |X,,,,,,,3|,,|X,,,,,l|,,|----|,,,,,|----|----|,,,,,|----|----|,,,,,|----| F'% ~~~~~`````", "`~~~~~~~~~~~~ *** V'V |----+----|,,|---+---|,,|T,,,B,,,,,B,,,T|T,,,B,,,,,B,,,T|T,,,B,,,,,B,,,T| V'V ~~~~~```", "````~~~~~~~~~~ ** %'F |6,,,,,,,6|,,|L,,,,,P|,,|bb,,G,,,,,G,,bb|bb,,G,,,,,G,,bb|bb,,G,,,,,G,,bb| F'% ~~~````", "`````~~~~~~~~~ * %'F |6,,,6,,,6|,,|,,,,,,P|,,|----|-----|----|----|,,,,,|----|----|,,,,,|----| F'% ~~~~```", @@ -390,6 +390,7 @@ "R": [ "t_floor" ], "U": [ "t_concrete" ], "V": [ "t_column" ], + "X": [ "t_floor" ], "Y": [ "t_floor" ], "`": [ [ "t_water_dp", 20 ], "t_water_sh" ] }, @@ -409,10 +410,11 @@ "Q": [ "f_cupboard" ], "R": [ "f_locker" ], "U": [ "f_fiber_mat" ], + "X": [ "f_rack_coat" ], + "Y": [ "f_rack_coat" ], "#": [ [ "f_null", 30 ], "f_boulder_small" ], "*": [ [ "f_boulder_large", 20 ], "f_boulder_medium" ], "1": [ "f_filing_cabinet" ], - "Y": [ "f_rack_coat" ], "2": [ "f_cupboard" ], "4": [ "f_glass_fridge" ], "5": [ "f_safe_l" ], @@ -426,17 +428,21 @@ "0": [ { "item": "prison_weapons", "chance": 50 }, { "item": "prison_armor", "chance": 50 } ], "I": [ { "item": "cop_torso", "chance": 33 }, { "item": "cop_pants", "chance": 33 }, { "item": "cop_shoes", "chance": 33 } ], "N": [ { "item": "hand_tools", "chance": 50 }, { "item": "tools_carpentry", "chance": 50 } ], + "l": [ { "item": "hand_tools", "chance": 50 }, { "item": "tools_carpentry", "chance": 50 } ], "C": { "item": "bed", "chance": 70 }, "Q": { "item": "prison_canine_food", "chance": 70, "repeat": [ 3, 5 ] }, "R": [ - { "item": "animalshelter_softdrug", "chance": 70, "repeat": [ 2, 3 ] }, + { "item": "animalshelter_softdrug", "chance": 70, "repeat": [ 1, 2 ] }, { "item": "animalshelter_hardrug", "chance": 30, "repeat": [ 1, 2 ] } ], "U": { "item": "prison_canine_bowl", "chance": 70 }, + "Y": { "item": "clothing_outdoor_torso", "chance": 60 }, "q": { "item": "trash_cart", "chance": 50, "repeat": [ 2, 3 ] }, "n": { "item": "oven", "chance": 70 }, + "r": { "item": "cleaning", "chance": 50 }, ":": { "item": "animalshelter_toys", "chance": 5 }, - "1": { "item": "office_paper", "chance": 70, "repeat": [ 2, 3 ] }, + "1": { "item": "office_paper", "chance": 50 }, + "4": [ { "item": "softdrugs", "chance": 50 }, { "item": "harddrugs", "chance": 50 } ], "5": { "item": "alcohol_bottled_canned", "chance": 95, "repeat": [ 1, 3 ] }, "2": [ { "item": "cannedfood", "chance": 70, "repeat": [ 1, 3 ] }, { "item": "pasta", "chance": 70, "repeat": [ 1, 3 ] } ] }, diff --git a/data/json/materials.json b/data/json/materials.json index c67b3d63d6712..2663ef3a02f6b 100644 --- a/data/json/materials.json +++ b/data/json/materials.json @@ -1387,5 +1387,23 @@ "dmg_adj": [ "lightly damaged", "damaged", "very damaged", "thoroughly damaged" ], "bash_dmg_verb": "damaged", "cut_dmg_verb": "damaged" + }, + { + "type": "material", + "ident": "zinc", + "name": "Zinc", + "density": 10, + "specific_heat_liquid": 1.18, + "specific_heat_solid": 0.91, + "latent_heat": 260, + "bash_resist": 4, + "cut_resist": 3, + "acid_resist": 4, + "fire_resist": 1, + "elec_resist": 0, + "chip_resist": 10, + "dmg_adj": [ "dented", "bent", "smashed", "shattered" ], + "bash_dmg_verb": "dented", + "cut_dmg_verb": "scratched" } ] diff --git a/data/json/monster_drops.json b/data/json/monster_drops.json index add0145b60163..0644159630e8d 100644 --- a/data/json/monster_drops.json +++ b/data/json/monster_drops.json @@ -98,6 +98,10 @@ ], "prob": 5 }, + { + "distribution": [ { "item": "RPG_die", "prob": 70 }, { "item": "dnd_handbook", "prob": 30 }, { "item": "metal_RPG_die", "prob": 10 } ], + "prob": 1 + }, { "distribution": [ { "item": "cig", "prob": 65, "charges-min": 0, "charges-max": 20 }, diff --git a/data/json/npcs/TALK_COMMON_ALLY.json b/data/json/npcs/TALK_COMMON_ALLY.json index 892f5f92a1b84..7a3f2af0705db 100644 --- a/data/json/npcs/TALK_COMMON_ALLY.json +++ b/data/json/npcs/TALK_COMMON_ALLY.json @@ -163,6 +163,16 @@ } ] }, + { + "and": [ + { "npc_override": "follow_distance_2", "yes": " OVERRIDE: ", "no": " " }, + { + "npc_rule": "follow_distance_2", + "yes": "", + "no": "" + } + ] + }, { "and": [ { "npc_override": "use_guns", "yes": " OVERRIDE: ", "no": " " }, @@ -237,6 +247,15 @@ "topic": "TALK_COMBAT_COMMANDS", "effect": { "toggle_npc_rule": "follow_close" } }, + { + "truefalsetext": { + "condition": { "npc_rule": "follow_distance_2" }, + "true": "", + "false": "" + }, + "topic": "TALK_COMBAT_COMMANDS", + "effect": { "toggle_npc_rule": "follow_distance_2" } + }, { "truefalsetext": { "condition": { "npc_rule": "use_guns" }, diff --git a/data/json/npcs/talk_tags.json b/data/json/npcs/talk_tags.json index 9eccbe9bb7886..ecb8ac3326ab3 100644 --- a/data/json/npcs/talk_tags.json +++ b/data/json/npcs/talk_tags.json @@ -1165,6 +1165,16 @@ "category": "", "text": " will move freely as needed." }, + { + "type": "snippet", + "category": "", + "text": " will follow you at about two paces." + }, + { + "type": "snippet", + "category": "", + "text": " will follow you at about four paces." + }, { "type": "snippet", "category": "", diff --git a/data/json/overmap/multitile_city_buildings.json b/data/json/overmap/multitile_city_buildings.json index e1c9b6bbcc2d5..dd5fecfdca7cf 100644 --- a/data/json/overmap/multitile_city_buildings.json +++ b/data/json/overmap/multitile_city_buildings.json @@ -315,8 +315,11 @@ "locations": [ "land" ], "overmaps": [ { "point": [ 0, 0, 0 ], "overmap": "garage_gas_1_north" }, + { "point": [ 0, 0, 1 ], "overmap": "garage_gas_roof_1_north" }, { "point": [ 1, 0, 0 ], "overmap": "garage_gas_2_north" }, - { "point": [ 2, 0, 0 ], "overmap": "garage_gas_3_north" } + { "point": [ 1, 0, 1 ], "overmap": "garage_gas_roof_2_north" }, + { "point": [ 2, 0, 0 ], "overmap": "garage_gas_3_north" }, + { "point": [ 2, 0, 1 ], "overmap": "garage_gas_roof_3_north" } ] }, { @@ -975,7 +978,9 @@ "locations": [ "land" ], "overmaps": [ { "point": [ 0, 0, 0 ], "overmap": "BotanicalGarden_1a_north" }, - { "point": [ 1, 0, 0 ], "overmap": "BotanicalGarden_1b_north" } + { "point": [ 0, 0, 1 ], "overmap": "BotanicalGarden_1a_roof_north" }, + { "point": [ 1, 0, 0 ], "overmap": "BotanicalGarden_1b_north" }, + { "point": [ 1, 0, 1 ], "overmap": "BotanicalGarden_1b_roof_north" } ] }, { @@ -1662,6 +1667,35 @@ { "point": [ 0, 1, 3 ], "overmap": "homeless_1_0_roof_north" } ] }, + { + "type": "city_building", + "id": "craft_shop", + "locations": [ "land" ], + "overmaps": [ + { "point": [ 0, 0, 0 ], "overmap": "craft_shop_north" }, + { "point": [ 0, 0, 1 ], "overmap": "craft_shop_roof_north" }, + { "point": [ 0, 0, 2 ], "overmap": "craft_shop_upper_roof_north" } + ] + }, + { + "type": "city_building", + "id": "craft_shop_1", + "locations": [ "land" ], + "overmaps": [ + { "point": [ 0, 0, 0 ], "overmap": "craft_shop_1_north" }, + { "point": [ 0, 0, 1 ], "overmap": "craft_shop_roof_1_north" } + ] + }, + { + "type": "city_building", + "id": "craft_shop_2", + "locations": [ "land" ], + "overmaps": [ + { "point": [ 0, 0, 0 ], "overmap": "craft_shop_2_north" }, + { "point": [ 0, 0, 1 ], "overmap": "craft_shop_2ndfloor_2_north" }, + { "point": [ 0, 0, 2 ], "overmap": "craft_shop_roof_2_north" } + ] + }, { "type": "city_building", "id": "pool", diff --git a/data/json/overmap/specials.json b/data/json/overmap/specials.json index 345356fcba1de..30fdfd9b2e5db 100644 --- a/data/json/overmap/specials.json +++ b/data/json/overmap/specials.json @@ -1609,8 +1609,11 @@ "id": "garage_gas", "overmaps": [ { "point": [ 0, 0, 0 ], "overmap": "garage_gas_1_north" }, + { "point": [ 0, 0, 1 ], "overmap": "garage_gas_roof_1_north" }, { "point": [ 1, 0, 0 ], "overmap": "garage_gas_2_north" }, - { "point": [ 2, 0, 0 ], "overmap": "garage_gas_3_north" } + { "point": [ 1, 0, 1 ], "overmap": "garage_gas_roof_2_north" }, + { "point": [ 2, 0, 0 ], "overmap": "garage_gas_3_north" }, + { "point": [ 2, 0, 1 ], "overmap": "garage_gas_roof_3_north" } ], "connections": [ { "point": [ 0, -1, 0 ], "terrain": "road", "existing": true }, diff --git a/data/json/overmap_terrain.json b/data/json/overmap_terrain.json index 2192a79e3e221..f722e063a6e30 100644 --- a/data/json/overmap_terrain.json +++ b/data/json/overmap_terrain.json @@ -566,6 +566,54 @@ "name": "public space", "color": "i_white" }, + { + "type": "overmap_terrain", + "id": "parking_2x1_0", + "name": "parking lot", + "sym": "O", + "color": "dark_gray", + "see_cost": 2 + }, + { + "type": "overmap_terrain", + "id": "parking_2x1_1", + "copy-from": "parking_2x1_0" + }, + { + "type": "overmap_terrain", + "id": "parking_3x1_0", + "copy-from": "parking_2x1_0" + }, + { + "type": "overmap_terrain", + "id": "parking_3x1_1", + "copy-from": "parking_2x1_0" + }, + { + "type": "overmap_terrain", + "id": "parking_3x1_2", + "copy-from": "parking_2x1_0" + }, + { + "type": "overmap_terrain", + "id": "parking_2x2_0_0", + "copy-from": "parking_2x1_0" + }, + { + "type": "overmap_terrain", + "id": "parking_2x2_0_1", + "copy-from": "parking_2x1_0" + }, + { + "type": "overmap_terrain", + "id": "parking_2x2_1_0", + "copy-from": "parking_2x1_0" + }, + { + "type": "overmap_terrain", + "id": "parking_2x2_1_1", + "copy-from": "parking_2x1_0" + }, { "type": "overmap_terrain", "id": "irradiator_1_1", diff --git a/data/json/overmap_terrain_commercial.json b/data/json/overmap_terrain_commercial.json index 11ca79a6342f9..a8de2c94acdd0 100644 --- a/data/json/overmap_terrain_commercial.json +++ b/data/json/overmap_terrain_commercial.json @@ -1218,6 +1218,13 @@ "copy-from": "generic_city_building", "color": "light_blue" }, + { + "type": "overmap_terrain", + "id": "garage_gas_roof_1", + "name": "garage - gas station roof", + "copy-from": "generic_city_building", + "color": "light_blue" + }, { "type": "overmap_terrain", "id": "garage_gas_2", @@ -1226,6 +1233,14 @@ "sym": "O", "color": "white" }, + { + "type": "overmap_terrain", + "id": "garage_gas_roof_2", + "copy-from": "generic_city_building", + "name": "garage roof", + "sym": "O", + "color": "white" + }, { "type": "overmap_terrain", "id": "garage_gas_3", @@ -1234,6 +1249,14 @@ "sym": "O", "color": "white" }, + { + "type": "overmap_terrain", + "id": "garage_gas_roof_3", + "copy-from": "generic_city_building", + "name": "garage roof", + "sym": "O", + "color": "white" + }, { "id": "dispensary", "type": "overmap_terrain", @@ -1814,6 +1837,62 @@ "sym": "s", "color": "cyan" }, + { + "type": "overmap_terrain", + "id": "craft_shop_roof", + "name": "craft shop roof", + "copy-from": "generic_city_building", + "sym": "s", + "color": "cyan" + }, + { + "type": "overmap_terrain", + "id": "craft_shop_upper_roof", + "name": "craft shop upper roof", + "copy-from": "generic_city_building", + "sym": "s", + "color": "cyan" + }, + { + "type": "overmap_terrain", + "id": "craft_shop_1", + "name": "craft shop", + "copy-from": "generic_city_building", + "sym": "s", + "color": "cyan" + }, + { + "type": "overmap_terrain", + "id": "craft_shop_roof_1", + "name": "craft shop roof", + "copy-from": "generic_city_building", + "sym": "s", + "color": "cyan" + }, + { + "type": "overmap_terrain", + "id": "craft_shop_2", + "name": "craft shop", + "copy-from": "generic_city_building", + "sym": "s", + "color": "cyan" + }, + { + "type": "overmap_terrain", + "id": "craft_shop_2ndfloor_2", + "name": "craft shop 2nd floor", + "copy-from": "generic_city_building", + "sym": "s", + "color": "cyan" + }, + { + "type": "overmap_terrain", + "id": "craft_shop_roof_2", + "name": "craft shop roof", + "copy-from": "generic_city_building", + "sym": "s", + "color": "cyan" + }, { "type": "overmap_terrain", "id": "cs_market_small", diff --git a/data/json/overmap_terrain_recreational.json b/data/json/overmap_terrain_recreational.json index 1de11add07a71..080525d84f188 100644 --- a/data/json/overmap_terrain_recreational.json +++ b/data/json/overmap_terrain_recreational.json @@ -416,6 +416,16 @@ "mondensity": 2, "flags": [ "SIDEWALK" ] }, + { + "type": "overmap_terrain", + "id": "BotanicalGarden_1a_roof", + "name": "botanical garden", + "sym": "g", + "color": "i_green", + "see_cost": 5, + "extras": "field", + "mondensity": 2 + }, { "type": "overmap_terrain", "id": "BotanicalGarden_1b", @@ -427,6 +437,16 @@ "mondensity": 2, "flags": [ "SIDEWALK" ] }, + { + "type": "overmap_terrain", + "id": "BotanicalGarden_1b_roof", + "name": "botanical garden", + "sym": "g", + "color": "i_green", + "see_cost": 5, + "extras": "field", + "mondensity": 2 + }, { "type": "overmap_terrain", "id": "TreeFarm_1a", diff --git a/data/json/professions.json b/data/json/professions.json index 879f8b903d7be..e97d6a03ef5f5 100644 --- a/data/json/professions.json +++ b/data/json/professions.json @@ -2164,7 +2164,11 @@ "description": "The cataclysm gave you a chance to escape, but freedom comes with a steep price.", "points": 0, "skills": [ { "level": 1, "name": "melee" } ], - "items": { "both": [ "striped_shirt", "striped_pants", "glass_shiv" ], "male": [ "briefs" ], "female": [ "bra", "panties" ] } + "items": { + "both": [ "striped_shirt", "striped_pants", "sneakers", "socks", "glass_shiv" ], + "male": [ "briefs" ], + "female": [ "bra", "panties" ] + } }, { "type": "profession", @@ -2174,7 +2178,11 @@ "points": 0, "skills": [ { "level": 1, "name": "melee" } ], "traits": [ "KILLER" ], - "items": { "both": [ "striped_shirt", "striped_pants", "glass_shiv" ], "male": [ "briefs" ], "female": [ "bra", "panties" ] } + "items": { + "both": [ "striped_shirt", "striped_pants", "sneakers", "socks", "glass_shiv" ], + "male": [ "briefs" ], + "female": [ "bra", "panties" ] + } }, { "type": "profession", @@ -3579,7 +3587,7 @@ "skills": [ { "level": 2, "name": "speech" }, { "level": 1, "name": "survival" } ], "items": { "both": { - "items": [ "jeans", "tshirt", "socks", "sneakers", "mbag", "pizza_cheese", "cola", "dnd_handbook", "wristwatch" ], + "items": [ "jeans", "tshirt", "socks", "sneakers", "mbag", "pizza_cheese", "cola", "dnd_handbook", "wristwatch", "RPG_die" ], "entries": [ { "group": "charged_cell_phone" } ] }, "male": [ "briefs" ], @@ -3709,5 +3717,31 @@ }, "female": [ "chestwrap" ] } + }, + { + "type": "profession", + "ident": "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 wants to eat you alive, winning hearts and minds just got that much harder.", + "points": 4, + "skills": [ { "level": 4, "name": "barter" }, { "level": 6, "name": "speech" } ], + "traits": [ "LIAR" ], + "items": { + "both": [ + "suit", + "tieclip", + "socks_wool", + "dress_shoes", + "smart_phone", + "gold_watch", + "briefcase", + "skinny_tie", + "file", + "ref_lighter", + "cigar" + ], + "male": [ "boxer_shorts" ], + "female": [ "bra", "panties" ] + } } ] diff --git a/data/json/recipes/other/containers.json b/data/json/recipes/other/containers.json index 1649a1d7dbc3a..80e08f4778629 100644 --- a/data/json/recipes/other/containers.json +++ b/data/json/recipes/other/containers.json @@ -9,8 +9,7 @@ "difficulty": 2, "time": "20 m", "autolearn": true, - "using": [ [ "cordage_short", 1 ], [ "glazing", 1 ] ], - "tools": [ [ [ "brick_kiln", 40 ], [ "kiln", 40 ] ] ], + "using": [ [ "cordage_short", 1 ], [ "glazing", 1 ], [ "earthenware_firing", 40 ] ], "components": [ [ [ "water", 1 ], [ "water_clean", 1 ] ], [ [ "clay_lump", 4 ] ], [ [ "leather", 2 ], [ "fur", 2 ] ] ] }, { @@ -23,8 +22,7 @@ "difficulty": 2, "time": "30 m", "autolearn": true, - "using": [ [ "cordage_short", 1 ], [ "glazing", 1 ] ], - "tools": [ [ [ "brick_kiln", 60 ], [ "kiln", 60 ] ] ], + "using": [ [ "cordage_short", 1 ], [ "glazing", 1 ], [ "earthenware_firing", 60 ] ], "components": [ [ [ "water", 1 ], [ "water_clean", 1 ] ], [ [ "clay_lump", 2 ] ], [ [ "leather", 2 ], [ "fur", 2 ] ] ] }, { @@ -37,8 +35,7 @@ "difficulty": 2, "time": "45 m", "autolearn": true, - "using": [ [ "cordage_short", 2 ], [ "glazing", 2 ] ], - "tools": [ [ [ "brick_kiln", 120 ], [ "kiln", 120 ] ] ], + "using": [ [ "cordage_short", 2 ], [ "glazing", 2 ], [ "earthenware_firing", 120 ] ], "components": [ [ [ "water", 2 ], [ "water_clean", 2 ] ], [ [ "clay_lump", 10 ] ], [ [ "leather", 3 ], [ "fur", 3 ] ] ] }, { @@ -51,8 +48,7 @@ "difficulty": 2, "time": "80 m", "autolearn": true, - "using": [ [ "cordage_short", 2 ], [ "glazing", 3 ] ], - "tools": [ [ [ "brick_kiln", 160 ], [ "kiln", 160 ] ] ], + "using": [ [ "cordage_short", 2 ], [ "glazing", 3 ], [ "earthenware_firing", 160 ] ], "components": [ [ [ "water", 3 ], [ "water_clean", 3 ] ], [ [ "clay_lump", 20 ] ], [ [ "leather", 3 ], [ "fur", 3 ] ] ] }, { @@ -65,8 +61,7 @@ "difficulty": 2, "time": "25 m", "autolearn": true, - "using": [ [ "cordage_short", 2 ], [ "glazing", 1 ] ], - "tools": [ [ [ "brick_kiln", 50 ], [ "kiln", 50 ] ] ], + "using": [ [ "cordage_short", 2 ], [ "glazing", 1 ], [ "earthenware_firing", 50 ] ], "components": [ [ [ "water", 1 ], [ "water_clean", 1 ] ], [ [ "clay_lump", 6 ] ], [ [ "leather", 3 ], [ "fur", 3 ] ] ] }, { diff --git a/data/json/recipes/recipe_ammo.json b/data/json/recipes/recipe_ammo.json index ef97a3405acfc..a44aff5a457bb 100644 --- a/data/json/recipes/recipe_ammo.json +++ b/data/json/recipes/recipe_ammo.json @@ -619,6 +619,60 @@ "using": [ [ "surface_heat", 2 ] ], "components": [ [ [ "gunpowder", 16 ], [ "chem_black_powder", 16 ] ], [ [ "glass_shard", 1 ], [ "nail", 8 ], [ "combatnail", 8 ] ] ] }, + { + "type": "recipe", + "result": "shotcanister_scrap", + "category": "CC_AMMO", + "subcategory": "CSC_AMMO_SHOT", + "skill_used": "fabrication", + "skills_required": [ "gun", 1 ], + "difficulty": 3, + "time": "1 m", + "autolearn": true, + "book_learn": [ [ "recipe_bullets", 2 ], [ "manual_shotgun", 2 ] ], + "components": [ [ [ "scrap", 1 ] ], [ [ "paper", 2 ] ] ] + }, + { + "type": "recipe", + "result": "shotcanister_flechette", + "category": "CC_AMMO", + "subcategory": "CSC_AMMO_SHOT", + "skill_used": "fabrication", + "skills_required": [ "gun", 1 ], + "difficulty": 3, + "time": "1 m", + "autolearn": true, + "book_learn": [ [ "recipe_bullets", 2 ], [ "manual_shotgun", 2 ] ], + "components": [ [ [ "combatnail", 10 ] ], [ [ "paper", 2 ] ] ] + }, + { + "type": "recipe", + "result": "shotcanister_bearing", + "category": "CC_AMMO", + "subcategory": "CSC_AMMO_SHOT", + "skill_used": "fabrication", + "skills_required": [ "gun", 1 ], + "difficulty": 3, + "time": "1 m", + "autolearn": true, + "book_learn": [ [ "recipe_bullets", 2 ], [ "manual_shotgun", 2 ] ], + "components": [ [ [ "bearing", 10 ] ], [ [ "paper", 2 ] ] ] + }, + { + "type": "recipe", + "result": "shotcanister_pebble", + "category": "CC_AMMO", + "subcategory": "CSC_AMMO_SHOT", + "skill_used": "fabrication", + "skills_required": [ "gun", 1 ], + "difficulty": 3, + "time": "1 m", + "autolearn": true, + "book_learn": [ [ "recipe_bullets", 2 ], [ "manual_shotgun", 2 ] ], + "qualities": [ ], + "using": [ ], + "components": [ [ [ "pebble", 10 ] ], [ [ "paper", 2 ] ] ] + }, { "type": "recipe", "result": "smpistol_primer", diff --git a/data/json/recipes/recipe_others.json b/data/json/recipes/recipe_others.json index 18b224acd9f92..4e02b5b3c327c 100644 --- a/data/json/recipes/recipe_others.json +++ b/data/json/recipes/recipe_others.json @@ -74,17 +74,70 @@ "using": [ [ "sewing_standard", 12 ] ], "components": [ [ [ "rag", 4 ] ], [ [ "cotton_ball", 8 ] ] ] }, + { + "type": "recipe", + "result": "wood_beam", + "id_suffix": "from logs", + "category": "CC_OTHER", + "skill_used": "fabrication", + "difficulty": 1, + "time": "1 h", + "autolearn": true, + "byproducts": [ [ "splinter", 20 ] ], + "qualities": [ { "id": "AXE", "level": 2 } ], + "//": "Eventually, smoothing tools should also be required, or we should distinguish between rough-hewn and finished beams", + "components": [ [ [ "log", 6 ] ] ], + "//2": "This is a terrible stand-in for the fact that logs are only 10kg chunks and not big enough to hew into an 8' or longer wooden beam." + }, + { + "type": "recipe", + "result": "wood_panel", + "id_suffix": "from wooden beams", + "category": "CC_OTHER", + "skill_used": "fabrication", + "time": "2 h", + "autolearn": true, + "byproducts": [ [ "splinter", 7 ], [ "wood_panel", 3 ] ], + "qualities": [ { "id": "SAW_W", "level": 2 } ], + "components": [ [ [ "wood_beam", 1 ] ] ], + "//": "I am assuming here that you actually get more than 4 smaller-than-represented wood panels, but any application that requires panels means you'll be putting these side by side to get the effect of a single panel." + }, { "type": "recipe", "result": "wood_panel", + "id_suffix": "from wooden sheets", "category": "CC_OTHER", "skill_used": "fabrication", - "time": 1000, + "time": "10 m", "autolearn": true, "byproducts": [ [ "wood_panel", 1 ] ], "qualities": [ { "id": "SAW_W", "level": 2 } ], "components": [ [ [ "wood_sheet", 1 ] ] ] }, + { + "type": "recipe", + "result": "wood_panel", + "id_suffix": "from nailed planks", + "category": "CC_OTHER", + "skill_used": "fabrication", + "time": "10 m", + "autolearn": true, + "qualities": [ { "id": "SAW_W", "level": 2 }, { "id": "HAMMER", "level": 2 } ], + "components": [ [ [ "2x4", 8 ] ], [ [ "nail", 36 ] ] ] + }, + { + "type": "recipe", + "result": "2x4", + "id_suffix": "from wooden beams", + "category": "CC_OTHER", + "skill_used": "fabrication", + "time": "2 h", + "autolearn": true, + "byproducts": [ [ "splinter", 4 ], [ "2x4", 8 ] ], + "qualities": [ { "id": "SAW_W", "level": 2 } ], + "//": "This should eventually require planing tools once implemented, and should replace the ability to turn a small chunk of log into a long wooden plank.", + "components": [ [ [ "wood_beam", 1 ] ] ] + }, { "type": "recipe", "result": "wind_mill", @@ -2197,7 +2250,7 @@ "difficulty": 2, "time": "45 m", "autolearn": true, - "tools": [ [ [ "brick_kiln", 90 ], [ "kiln", 90 ] ] ], + "using": [ [ "earthenware_firing", 90 ] ], "components": [ [ [ "water", 1 ], [ "water_clean", 1 ] ], [ [ "clay_lump", 5 ] ] ] }, { @@ -3777,7 +3830,7 @@ "difficulty": 2, "time": "45 m", "autolearn": true, - "tools": [ [ [ "brick_kiln", 90 ], [ "kiln", 90 ] ] ], + "using": [ [ "earthenware_firing", 90 ] ], "components": [ [ [ "water", 1 ], [ "water_clean", 1 ] ], [ [ "clay_lump", 5 ] ] ] }, { @@ -3790,7 +3843,7 @@ "difficulty": 2, "time": "35 m", "autolearn": true, - "tools": [ [ [ "brick_kiln", 75 ], [ "kiln", 75 ] ] ], + "using": [ [ "earthenware_firing", 75 ] ], "components": [ [ [ "water", 1 ], [ "water_clean", 1 ] ], [ [ "clay_lump", 4 ] ] ] }, { @@ -3803,7 +3856,7 @@ "difficulty": 2, "time": "50 m", "autolearn": true, - "tools": [ [ [ "brick_kiln", 100 ], [ "kiln", 100 ] ] ], + "using": [ [ "earthenware_firing", 100 ] ], "components": [ [ [ "water", 1 ], [ "water_clean", 1 ] ], [ [ "clay_lump", 8 ] ] ] }, { @@ -3816,7 +3869,7 @@ "difficulty": 2, "time": "20 m", "autolearn": true, - "tools": [ [ [ "brick_kiln", 40 ], [ "kiln", 40 ] ] ], + "using": [ [ "earthenware_firing", 40 ] ], "components": [ [ [ "water", 1 ], [ "water_clean", 1 ] ], [ [ "clay_lump", 3 ] ] ] }, { @@ -3829,7 +3882,7 @@ "time": "40 m", "autolearn": true, "batch_time_factors": [ 75, 4 ], - "tools": [ [ [ "brick_kiln", 60 ], [ "kiln", 60 ] ] ], + "using": [ [ "earthenware_firing", 60 ] ], "components": [ [ [ "clay_lump", 1 ] ], [ [ "water", 1 ], [ "water_clean", 1 ] ] ] }, { diff --git a/data/json/recipes/recipe_weapon.json b/data/json/recipes/recipe_weapon.json index 3d8663e435ce0..fdc69e275b6f9 100644 --- a/data/json/recipes/recipe_weapon.json +++ b/data/json/recipes/recipe_weapon.json @@ -1777,6 +1777,26 @@ [ [ "steel_chunk", 3 ], [ "scrap", 9 ] ] ] }, + { + "type": "recipe", + "result": "pneumatic_shotgun", + "category": "CC_WEAPON", + "subcategory": "CSC_WEAPON_RANGED", + "skill_used": "mechanics", + "skills_required": [ "gun", 3 ], + "difficulty": 7, + "time": "180 m", + "autolearn": true, + "using": [ [ "welding_standard", 30 ] ], + "qualities": [ { "id": "SAW_M_FINE", "level": 1 }, { "id": "SCREW_FINE", "level": 1 }, { "id": "WRENCH_FINE", "level": 1 } ], + "components": [ + [ [ "pipe", 3 ] ], + [ [ "duct_tape", 100 ], [ "superglue", 1 ] ], + [ [ "2x4", 1 ], [ "stick", 1 ] ], + [ [ "metal_tank_little", 1 ] ], + [ [ "steel_chunk", 4 ], [ "scrap", 12 ] ] + ] + }, { "type": "recipe", "result": "mininuke_launcher", diff --git a/data/json/regional_map_settings.json b/data/json/regional_map_settings.json index 4b027742b5461..d1e84627943c2 100644 --- a/data/json/regional_map_settings.json +++ b/data/json/regional_map_settings.json @@ -603,7 +603,9 @@ "shops": { "bus_station": 200, "town_hall": 150, - "craft_shop": 100, + "craft_shop": 200, + "craft_shop_1": 200, + "craft_shop_2": 200, "s_gas": 500, "s_pharm": 300, "s_pharm_1": 300, diff --git a/data/json/requirements/toolsets.json b/data/json/requirements/toolsets.json index d721d942007e4..3013619b57147 100644 --- a/data/json/requirements/toolsets.json +++ b/data/json/requirements/toolsets.json @@ -5,6 +5,12 @@ "//": "Forming of bullets from raw materials", "tools": [ [ [ "press", -1 ] ], [ [ "fire", -1 ], [ "hotplate", 2 ], [ "toolset", 2 ] ] ] }, + { + "id": "earthenware_firing", + "type": "requirement", + "//": "Firing various clay shapes to make earthenware", + "tools": [ [ [ "brick_kiln", -1 ], [ "kiln", -1 ] ], [ [ "fire", -1 ], [ "brick_kiln", 1 ], [ "kiln", 1 ] ] ] + }, { "id": "forging_standard", "type": "requirement", diff --git a/doc/JSON_INFO.md b/doc/JSON_INFO.md index ab53ba16bdd1f..e21b25601b118 100644 --- a/doc/JSON_INFO.md +++ b/doc/JSON_INFO.md @@ -562,6 +562,7 @@ Mods can modify this via `add:traits` and `remove:traits`. "ANOTHERFLAG" ], "construction_blueprint": "camp", // an optional string containing an update_mapgen_id. Used by faction camps to upgrade their buildings +"on_display": false, // this is a hidden construction item, used by faction camps to calculate construction times but not available to the player "qualities": [ // Generic qualities of tools needed to craft {"id":"CUT","level":1,"amount":1} ], diff --git a/src/activity_handlers.cpp b/src/activity_handlers.cpp index 51a129e803d81..c7ec8870049ed 100644 --- a/src/activity_handlers.cpp +++ b/src/activity_handlers.cpp @@ -2050,6 +2050,7 @@ void activity_handlers::start_engines_finish( player_activity *act, player *p ) int non_muscle_attempted = 0; int started = 0; int non_muscle_started = 0; + int non_combustion_started = 0; const bool take_control = act->values[0]; for( size_t e = 0; e < veh->engines.size(); ++e ) { @@ -2062,6 +2063,8 @@ void activity_handlers::start_engines_finish( player_activity *act, player *p ) started++; if( !veh->is_engine_type( e, "muscle" ) && !veh->is_engine_type( e, "animal" ) ) { non_muscle_started++; + } else { + non_combustion_started++; } } } @@ -2084,6 +2087,9 @@ void activity_handlers::start_engines_finish( player_activity *act, player *p ) //Only some of the non-muscle engines started add_msg( ngettext( "One of the %s's engines start up.", "Some of the %s's engines start up.", non_muscle_started ), veh->name ); + } else if( non_combustion_started > 0 ) { + //Non-combustions "engines" started + add_msg( "The %s is ready for movement.", veh->name ); } else { //All of the non-muscle engines failed add_msg( m_bad, ngettext( "The %s's engine fails to start.", diff --git a/src/construction.cpp b/src/construction.cpp index a595b3026f263..36b309a2c213d 100644 --- a/src/construction.cpp +++ b/src/construction.cpp @@ -134,7 +134,7 @@ static void load_available_constructions( std::vector &available, cat_available.clear(); available.clear(); for( auto &it : constructions ) { - if( !hide_unconstructable || can_construct( it ) ) { + if( it.on_display && ( !hide_unconstructable || can_construct( it ) ) ) { bool already_have_it = false; for( auto &avail_it : available ) { if( avail_it == it.description ) { @@ -1398,6 +1398,8 @@ void load_construction( JsonObject &jo ) assign_or_debugmsg( con.explain_failure, jo.get_string( "explain_failure", "" ), explain_fail_map ); con.vehicle_start = jo.get_bool( "vehicle_start", false ); + con.on_display = jo.get_bool( "on_display", true ); + constructions.push_back( con ); } @@ -1531,3 +1533,81 @@ void finalize_constructions() constructions[ i ].id = i; } } + +void get_build_reqs_for_furn_ter_ids( const std::pair, + std::map> &changed_ids, + build_reqs &total_reqs ) +{ + std::map total_builds; + + // iteratively recurse through the pre-terrains until the pre-terrain is empty, adding + // the constructions to the total_builds map + const auto add_builds = [&total_builds]( const construction & build, int count ) { + if( total_builds.find( build.id ) == total_builds.end() ) { + total_builds[build.id] = 0; + } + total_builds[build.id] += count; + std::string build_pre_ter = build.pre_terrain; + while( !build_pre_ter.empty() ) { + for( const construction &pre_build : constructions ) { + if( pre_build.category == "REPAIR" ) { + continue; + } + if( pre_build.post_terrain == build_pre_ter ) { + if( total_builds.find( pre_build.id ) == total_builds.end() ) { + total_builds[pre_build.id] = 0; + } + total_builds[pre_build.id] += count; + build_pre_ter = pre_build.pre_terrain; + break; + } + } + break; + } + }; + + // go through the list of terrains and add their constructions and any pre-constructions + // to the map of total builds + for( const auto &ter_data : changed_ids.first ) { + for( const construction &build : constructions ) { + if( build.post_terrain.empty() || build.post_is_furniture || + build.category == "REPAIR" ) { + continue; + } + if( ter_id( build.post_terrain ) == ter_data.first ) { + add_builds( build, ter_data.second ); + break; + } + } + } + // same, but for furniture + for( const auto &furn_data : changed_ids.second ) { + for( const construction &build : constructions ) { + if( build.post_terrain.empty() || !build.post_is_furniture || + build.category == "REPAIR" ) { + continue; + } + if( furn_id( build.post_terrain ) == furn_data.first ) { + add_builds( build, furn_data.second ); + break; + } + } + } + + for( const auto &build_data : total_builds ) { + const construction &build = constructions[build_data.first]; + const int count = build_data.second; + total_reqs.time += build.time * count; + if( total_reqs.reqs.find( build.requirements ) == total_reqs.reqs.end() ) { + total_reqs.reqs[build.requirements] = 0; + } + total_reqs.reqs[build.requirements] += count; + for( const auto &req_skill : build.required_skills ) { + if( total_reqs.skills.find( req_skill.first ) == total_reqs.skills.end() ) { + total_reqs.skills[req_skill.first] = req_skill.second; + } else if( total_reqs.skills[req_skill.first] < req_skill.second ) { + total_reqs.skills[req_skill.first] = req_skill.second; + } + } + } +} diff --git a/src/construction.h b/src/construction.h index b239534a69992..ca9b210ed3a50 100644 --- a/src/construction.h +++ b/src/construction.h @@ -29,6 +29,12 @@ struct partial_con { size_t id = 0; }; +struct build_reqs { + std::map skills; + std::map reqs; + int time = 0; +}; + struct construction { // Construction type category std::string category; @@ -78,6 +84,9 @@ struct construction { std::vector get_folded_time_string( int width ) const; // Result of construction scaling option float time_scale() const; + + // make the construction available for selection + bool on_display = true; private: std::string get_time_string() const; }; @@ -94,4 +103,7 @@ void complete_construction( player *p ); void check_constructions(); void finalize_constructions(); +void get_build_reqs_for_furn_ter_ids( const std::pair, + std::map> &changed_ids, + build_reqs &total_reqs ); #endif diff --git a/src/crafting.cpp b/src/crafting.cpp index 255e1759aafac..30f56fcabeaa4 100644 --- a/src/crafting.cpp +++ b/src/crafting.cpp @@ -1165,15 +1165,6 @@ bool player::can_continue_craft( item &craft ) } const recipe &rec = craft.get_making(); - if( has_recipe( &rec, crafting_inventory(), get_crafting_helpers() ) == -1 ) { - add_msg_player_or_npc( - string_format( _( "You don't know the recipe for the %s and can't continue crafting." ), - rec.result_name() ), - string_format( _( " doesn't know the recipe for the %s and can't continue crafting." ), - rec.result_name() ) - ); - return false; - } const requirement_data continue_reqs = craft.get_continue_reqs(); diff --git a/src/debug_menu.cpp b/src/debug_menu.cpp index c26988cd2fdac..4150124e2caa0 100644 --- a/src/debug_menu.cpp +++ b/src/debug_menu.cpp @@ -1127,7 +1127,7 @@ void debug() _( "Keep normal weather patterns" ) : _( "Disable weather forcing" ) ); for( int weather_id = 1; weather_id < NUM_WEATHER_TYPES; weather_id++ ) { weather_menu.addentry( weather_id, true, MENU_AUTOASSIGN, - weather_data( static_cast( weather_id ) ).name ); + weather::name( static_cast( weather_id ) ) ); } weather_menu.query(); diff --git a/src/game.cpp b/src/game.cpp index d84559e8cd650..6618bbd7d7dfc 100644 --- a/src/game.cpp +++ b/src/game.cpp @@ -1516,7 +1516,7 @@ bool game::do_turn() u.process_active_items(); if( get_levz() >= 0 && !u.is_underwater() ) { - weather_data( weather.weather ).effect(); + weather::effect( weather.weather )(); } const bool player_is_sleeping = u.has_effect( effect_sleep ); @@ -3604,7 +3604,7 @@ float game::natural_light_level( const int zlev ) const ret = DAYLIGHT_LEVEL; } - ret += weather_data( weather.weather ).light_modifier; + ret += weather::light_modifier( weather.weather ); // Artifact light level changes here. Even though some of these only have an effect // aboveground it is cheaper performance wise to simply iterate through the entire @@ -7265,7 +7265,6 @@ game::vmenu_ret game::list_items( const std::vector &item_list ) } reset_item_list_state( w_items_border, iInfoHeight, sort_radius ); - iScrollPos = 0; if( action == "HELP_KEYBINDINGS" ) { draw_ter(); diff --git a/src/iexamine.cpp b/src/iexamine.cpp index 8f93e7cdd3c8c..09dd9e4ec1f44 100644 --- a/src/iexamine.cpp +++ b/src/iexamine.cpp @@ -53,6 +53,7 @@ #include "overmapbuffer.h" #include "pickup.h" #include "player.h" +#include "recipe.h" #include "requirements.h" #include "rng.h" #include "sounds.h" @@ -5243,7 +5244,16 @@ void iexamine::workbench_internal( player &p, const tripoint &examp, if( !p.can_continue_craft( *selected_craft ) ) { break; } - + const recipe &rec = selected_craft->get_making(); + if( p.has_recipe( &rec, p.crafting_inventory(), p.get_crafting_helpers() ) == -1 ) { + p.add_msg_player_or_npc( + string_format( _( "You don't know the recipe for the %s and can't continue crafting." ), + rec.result_name() ), + string_format( _( " doesn't know the recipe for the %s and can't continue crafting." ), + rec.result_name() ) + ); + break; + } p.add_msg_player_or_npc( string_format( pgettext( "in progress craft", "You start working on the %s." ), selected_craft->tname() ), diff --git a/src/item.cpp b/src/item.cpp index 53d0cb5b8bbf8..a2e71604dd11e 100644 --- a/src/item.cpp +++ b/src/item.cpp @@ -2692,6 +2692,11 @@ std::string item::info( std::vector &info, const iteminfo_query *parts } } } + if( this->get_var( "die_num_sides", 0 ) != 0 ) { + info.emplace_back( "DESCRIPTION", + string_format( _( "* This item can be used as a die, and has %d sides." ), + static_cast( this->get_var( "die_num_sides", 0 ) ) ) ); + } // list recipes you could use it in itype_id tid; @@ -2792,8 +2797,19 @@ nc_color item::color_in_inventory() const // Only item not otherwise colored gets colored as favorite nc_color ret = is_favorite ? c_white : c_light_gray; - - if( has_flag( "WET" ) ) { + if( type->can_use( "learn_spell" ) ) { + const use_function *iuse = get_use( "learn_spell" ); + const learn_spell_actor *actor_ptr = static_cast( iuse->get_actor_ptr() ); + for( const std::string spell_id_str : actor_ptr->spells ) { + const spell_id sp_id( spell_id_str ); + if( u.magic.knows_spell( sp_id ) && !u.magic.get_spell( sp_id ).is_max_level() ) { + ret = c_yellow; + } + if( !u.magic.knows_spell( sp_id ) && u.magic.can_learn_spell( u, sp_id ) ) { + return c_light_blue; + } + } + } else if( has_flag( "WET" ) ) { ret = c_cyan; } else if( has_flag( "LITCIG" ) ) { ret = c_red; diff --git a/src/item_factory.cpp b/src/item_factory.cpp index f0aaf85a65269..ad1fc44451fdd 100644 --- a/src/item_factory.cpp +++ b/src/item_factory.cpp @@ -604,6 +604,7 @@ void Item_factory::init() add_iuse( "CHAINSAW_OFF", &iuse::chainsaw_off ); add_iuse( "CHAINSAW_ON", &iuse::chainsaw_on ); add_iuse( "CHEW", &iuse::chew ); + add_iuse( "RPGDIE", &iuse::rpgdie ); add_iuse( "BIRDFOOD", &iuse::feedbird ); add_iuse( "BURROW", &iuse::burrow ); add_iuse( "CHOP_TREE", &iuse::chop_tree ); diff --git a/src/iuse.cpp b/src/iuse.cpp index cd9e1a3db6779..a7def13f9d52a 100644 --- a/src/iuse.cpp +++ b/src/iuse.cpp @@ -4051,6 +4051,23 @@ int iuse::mp3_on( player *p, item *it, bool t, const tripoint &pos ) return it->type->charges_to_use(); } +int iuse::rpgdie( player *you, item *die, bool, const tripoint & ) +{ + const std::vector sides_options = { 4, 6, 8, 10, 12, 20, 50 }; + int num_sides = die->get_var( "die_num_sides", 0 ); + if( num_sides == 0 ) { + const int sides = sides_options[ rng( 0, sides_options.size() - 1 ) ]; + num_sides = sides; + die->set_var( "die_num_sides", sides ); + } + const int roll = rng( 1, num_sides ); + you->add_msg_if_player( _( "You roll a %d on your %d sided %s" ), roll, num_sides, die->tname() ); + if( roll == num_sides ) { + add_msg( m_good, _( "Critical!" ) ); + } + return roll; +} + int iuse::dive_tank( player *p, item *it, bool t, const tripoint & ) { if( t ) { // Normal use @@ -8304,7 +8321,16 @@ int iuse::craft( player *p, item *it, bool, const tripoint & ) if( !p->can_continue_craft( p->weapon ) ) { return 0; } - + const recipe &rec = it->get_making(); + if( p->has_recipe( &rec, p->crafting_inventory(), p->get_crafting_helpers() ) == -1 ) { + p->add_msg_player_or_npc( + string_format( _( "You don't know the recipe for the %s and can't continue crafting." ), + rec.result_name() ), + string_format( _( " doesn't know the recipe for the %s and can't continue crafting." ), + rec.result_name() ) + ); + return 0; + } p->add_msg_player_or_npc( string_format( pgettext( "in progress craft", "You start working on the %s." ), craft_name ), string_format( pgettext( "in progress craft", " starts working on the %s." ), diff --git a/src/iuse.h b/src/iuse.h index 3565a888d6915..b8891500c58e3 100644 --- a/src/iuse.h +++ b/src/iuse.h @@ -133,6 +133,7 @@ class iuse int shocktonfa_on( player *, item *, bool, const tripoint & ); int mp3( player *, item *, bool, const tripoint & ); int mp3_on( player *, item *, bool, const tripoint & ); + int rpgdie( player *, item *, bool, const tripoint & ); int dive_tank( player *, item *, bool, const tripoint & ); int gasmask( player *, item *, bool, const tripoint & ); int portable_game( player *, item *, bool, const tripoint & ); diff --git a/src/lightmap.cpp b/src/lightmap.cpp index 35ccde7e71676..9c7b9ee99da2d 100644 --- a/src/lightmap.cpp +++ b/src/lightmap.cpp @@ -95,7 +95,7 @@ void map::build_transparency_cache( const int zlev ) &transparency_cache[0][0], MAPSIZE_X * MAPSIZE_Y, static_cast( LIGHT_TRANSPARENCY_OPEN_AIR ) ); - const float sight_penalty = weather_data( g->weather.weather ).sight_penalty; + const float sight_penalty = weather::sight_penalty( g->weather.weather ); // Traverse the submaps in order for( int smx = 0; smx < my_MAPSIZE; ++smx ) { @@ -233,7 +233,7 @@ void map::build_sunlight_cache( int zlev ) const auto &prev_transparency_cache = prev_map_cache.transparency_cache; const auto &prev_floor_cache = prev_map_cache.floor_cache; const auto &outside_cache = map_cache.outside_cache; - const float sight_penalty = weather_data( g->weather.weather ).sight_penalty; + const float sight_penalty = weather::sight_penalty( g->weather.weather ); for( int x = 0, prev_x = offset.x; x < MAPSIZE_X; x++, prev_x++ ) { bool x_inbounds = true; if( prev_x < 0 || prev_x >= MAPSIZE_X ) { diff --git a/src/map.cpp b/src/map.cpp index 62551958fdf65..22f252dbc8ae6 100644 --- a/src/map.cpp +++ b/src/map.cpp @@ -360,26 +360,23 @@ void map::on_vehicle_moved( const int smz ) void map::vehmove() { // give vehicles movement points - { - VehicleList vehs = get_vehicles(); - for( auto &vehs_v : vehs ) { - vehicle *veh = vehs_v.v; - veh->gain_moves(); - veh->slow_leak(); - } + VehicleList vehicle_list = get_vehicles(); + for( auto &vehs_v : vehicle_list ) { + vehicle *veh = vehs_v.v; + veh->gain_moves(); + veh->slow_leak(); } // 15 equals 3 >50mph vehicles, or up to 15 slow (1 square move) ones // But 15 is too low for V12 death-bikes, let's put 100 here for( int count = 0; count < 100; count++ ) { - if( !vehproceed() ) { + if( !vehproceed( vehicle_list ) ) { break; } } // Process item removal on the vehicles that were modified this turn. // Use a copy because part_removal_cleanup can modify the container. auto temp = dirty_vehicle_list; - VehicleList vehicle_list = get_vehicles(); for( const auto &elem : temp ) { auto same_ptr = [ elem ]( const struct wrapped_vehicle & tgt ) { return elem == tgt.v; @@ -392,25 +389,23 @@ void map::vehmove() dirty_vehicle_list.clear(); } -bool map::vehproceed() +bool map::vehproceed( VehicleList &vehs ) { - VehicleList vehs = get_vehicles(); - vehicle *cur_veh = nullptr; + wrapped_vehicle *cur_veh = nullptr; float max_of_turn = 0; // First horizontal movement - for( auto &vehs_v : vehs ) { + for( wrapped_vehicle &vehs_v : vehs ) { if( vehs_v.v->of_turn > max_of_turn ) { - cur_veh = vehs_v.v; - max_of_turn = cur_veh->of_turn; + cur_veh = &vehs_v; + max_of_turn = cur_veh->v->of_turn; } } // Then vertical-only movement if( cur_veh == nullptr ) { - for( auto &vehs_v : vehs ) { - vehicle &cveh = *vehs_v.v; - if( cveh.is_falling ) { - cur_veh = vehs_v.v; + for( wrapped_vehicle &vehs_v : vehs ) { + if( vehs_v.v->is_falling ) { + cur_veh = &vehs_v; break; } } @@ -420,7 +415,8 @@ bool map::vehproceed() return false; } - return cur_veh->act_on_map(); + cur_veh->v = cur_veh->v->act_on_map(); + return true; } static bool sees_veh( const Creature &c, vehicle &veh, bool force_recalc ) @@ -431,18 +427,18 @@ static bool sees_veh( const Creature &c, vehicle &veh, bool force_recalc ) } ); } -void map::move_vehicle( vehicle &veh, const tripoint &dp, const tileray &facing ) +vehicle *map::move_vehicle( vehicle &veh, const tripoint &dp, const tileray &facing ) { const bool vertical = dp.z != 0; if( ( dp.x == 0 && dp.y == 0 && dp.z == 0 ) || ( abs( dp.x ) > 1 || abs( dp.y ) > 1 || abs( dp.z ) > 1 ) || ( vertical && ( dp.x != 0 || dp.y != 0 ) ) ) { debugmsg( "move_vehicle called with %d,%d,%d displacement vector", dp.x, dp.y, dp.z ); - return; + return &veh; } if( dp.z + veh.smz < -OVERMAP_DEPTH || dp.z + veh.smz > OVERMAP_HEIGHT ) { - return; + return &veh; } veh.precalc_mounts( 1, veh.skidding ? veh.turn_dir : facing.dir(), veh.pivot_point() ); @@ -462,7 +458,7 @@ void map::move_vehicle( vehicle &veh, const tripoint &dp, const tileray &facing if( velocity_before == 0 ) { debugmsg( "%s tried to move %s with no velocity", veh.name, vertical ? "vertically" : "horizontally" ); - return; + return &veh; } bool veh_veh_coll_flag = false; @@ -527,7 +523,7 @@ void map::move_vehicle( vehicle &veh, const tripoint &dp, const tileray &facing if( veh_veh_coll_flag ) { // Break here to let the hit vehicle move away - return; + return &veh; } // If not enough wheels, mess up the ground a bit. @@ -574,6 +570,7 @@ void map::move_vehicle( vehicle &veh, const tripoint &dp, const tileray &facing const bool seen = sees_veh( g->u, veh, false ); + vehicle *new_vehicle = &veh; if( can_move ) { // Accept new direction if( veh.skidding ) { @@ -590,7 +587,7 @@ void map::move_vehicle( vehicle &veh, const tripoint &dp, const tileray &facing veh.on_move(); // Actually change position tripoint pt = veh.global_pos3(); // displace_vehicle needs a non-const reference - displace_vehicle( pt, dp1 ); + new_vehicle = displace_vehicle( pt, dp1 ); } else if( !vertical ) { veh.stop(); } @@ -609,6 +606,7 @@ void map::move_vehicle( vehicle &veh, const tripoint &dp, const tileray &facing g->draw(); refresh_display(); } + return new_vehicle; } float map::vehicle_vehicle_collision( vehicle &veh, vehicle &veh2, diff --git a/src/map.h b/src/map.h index 82411fb0944e2..cbb3c5927cc96 100644 --- a/src/map.h +++ b/src/map.h @@ -533,7 +533,7 @@ class map // Vehicle movement void vehmove(); // Selects a vehicle to move, returns false if no moving vehicles - bool vehproceed(); + bool vehproceed( VehicleList &vehs ); // 3D vehicles VehicleList get_vehicles( const tripoint &start, const tripoint &end ); @@ -574,7 +574,7 @@ class map // Actually moves the vehicle // Unlike displace_vehicle, this one handles collisions - void move_vehicle( vehicle &veh, const tripoint &dp, const tileray &facing ); + vehicle *move_vehicle( vehicle &veh, const tripoint &dp, const tileray &facing ); // Furniture: 2D overloads void set( const int x, const int y, const ter_id &new_terrain, const furn_id &new_furniture ); diff --git a/src/mapgen.cpp b/src/mapgen.cpp index e161126f25a9a..a8d7d6691053e 100644 --- a/src/mapgen.cpp +++ b/src/mapgen.cpp @@ -8342,10 +8342,10 @@ bool update_mapgen_function_json::setup_internal( JsonObject &/*jo*/ ) bool update_mapgen_function_json::update_map( const tripoint &omt_pos, int offset_x, int offset_y, mission *miss, bool verify ) const { - tinymap update_map; + tinymap update_tmap; const regional_settings &rsettings = overmap_buffer.get_settings( omt_pos.x, omt_pos.y, omt_pos.z ); - update_map.load( omt_pos.x * 2, omt_pos.y * 2, omt_pos.z, false ); + update_tmap.load( omt_pos.x * 2, omt_pos.y * 2, omt_pos.z, false ); const std::string map_id = overmap_buffer.ter( omt_pos ).id().c_str(); oter_id north = overmap_buffer.ter( omt_pos + tripoint( 0, -1, 0 ) ); oter_id south = overmap_buffer.ter( omt_pos + tripoint( 0, 1, 0 ) ); @@ -8359,7 +8359,7 @@ bool update_mapgen_function_json::update_map( const tripoint &omt_pos, int offse oter_id below = overmap_buffer.ter( omt_pos + tripoint( 0, 0, -1 ) ); mapgendata md( north, south, east, west, northeast, southeast, northwest, southwest, - above, below, omt_pos.z, rsettings, update_map ); + above, below, omt_pos.z, rsettings, update_tmap ); int rotation = 0; if( map_id.size() > 7 ) { @@ -8374,7 +8374,19 @@ bool update_mapgen_function_json::update_map( const tripoint &omt_pos, int offse md.m.rotate( rotation ); } } + if( update_map( md, offset_x, offset_y, miss, verify, rotation ) ) { + md.m.save(); + g->load_npcs(); + g->m.invalidate_map_cache( md.zlevel ); + g->refresh_all(); + return true; + } + return false; +} +bool update_mapgen_function_json::update_map( mapgendata &md, int offset_x, int offset_y, + mission *miss, bool verify, int rotation ) const +{ for( auto &elem : setmap_points ) { if( verify && elem.has_vehicle_collision( md, offset_x, offset_y ) ) { return false; @@ -8391,10 +8403,6 @@ bool update_mapgen_function_json::update_map( const tripoint &omt_pos, int offse md.m.rotate( 4 - rotation ); } - update_map.save(); - g->load_npcs(); - g->m.invalidate_map_cache( omt_pos.z ); - g->refresh_all(); return true; } @@ -8435,6 +8443,58 @@ bool run_mapgen_update_func( const std::string &update_mapgen_id, const tripoint return update_function->second[0]->update_map( omt_pos, 0, 0, miss, cancel_on_collision ); } +std::pair, std::map> get_changed_ids_from_update( + const std::string &update_mapgen_id ) +{ + std::map terrains; + std::map furnitures; + + const auto update_function = update_mapgen.find( update_mapgen_id ); + + if( update_function == update_mapgen.end() || update_function->second.empty() ) { + return std::make_pair( terrains, furnitures ); + } + + const tripoint omt_pos = tripoint( 0, 0, 0 ); + + tinymap fake_map; + fake_map.load( 0, 0, 0, false ); + for( const tripoint &pos : fake_map.points_in_rectangle( omt_pos, + tripoint( MAPSIZE * SEEX, MAPSIZE * SEEY, 0 ) ) ) { + fake_map.furn_set( pos, f_null ); + fake_map.ter_set( pos, t_dirt ); + fake_map.trap_set( pos, tr_null ); + } + + const regional_settings &rsettings = overmap_buffer.get_settings( omt_pos.x, omt_pos.y, + omt_pos.z ); + oter_id any = oter_id( "field" ); + + mapgendata fake_md( any, any, any, any, any, any, any, any, + any, any, omt_pos.z, rsettings, fake_map ); + + if( update_function->second[0]->update_map( fake_md ) ) { + for( const tripoint &pos : fake_map.points_in_rectangle( { 0, 0, 0 }, { 23, 23, 0 } ) ) { + ter_id ter_at_pos = fake_map.ter( pos ); + if( ter_at_pos != t_dirt ) { + if( terrains.find( ter_at_pos ) == terrains.end() ) { + terrains[ter_at_pos] = 0; + } + terrains[ter_at_pos] += 1; + } + if( fake_map.has_furn( pos ) ) { + furn_id furn_at_pos = fake_map.furn( pos ); + if( furnitures.find( furn_at_pos ) == furnitures.end() ) { + furnitures[furn_at_pos] = 0; + } + furnitures[furn_at_pos] += 1; + } + } + } + return std::make_pair( terrains, furnitures ); +} + + bool run_mapgen_func( const std::string &mapgen_id, map *m, oter_id terrain_type, mapgendata dat, const time_point &turn, float density ) { diff --git a/src/mapgen.h b/src/mapgen.h index 58389d76059f4..85e1a4564dc95 100644 --- a/src/mapgen.h +++ b/src/mapgen.h @@ -349,6 +349,9 @@ class update_mapgen_function_json : public mapgen_function_json_base void check( const std::string &oter_name ) const; bool update_map( const tripoint &omt_pos, int offset_x, int offset_y, mission *miss, bool verify = false ) const; + bool update_map( mapgendata &md, int offset_x = 0, int offset_y = 0, + mission *miss = nullptr, bool verify = false, int rotation = 0 ) const; + protected: bool setup_internal( JsonObject &/*jo*/ ) override; ter_id fill_ter; diff --git a/src/mapgen_functions.h b/src/mapgen_functions.h index c181ab5af3cbd..a2c1fea2404c9 100644 --- a/src/mapgen_functions.h +++ b/src/mapgen_functions.h @@ -2,6 +2,7 @@ #ifndef MAPGEN_FUNCTIONS_H #define MAPGEN_FUNCTIONS_H +#include #include #include @@ -215,7 +216,8 @@ void place_stairs( map *m, oter_id terrain_type, mapgendata dat ); mapgen_update_func add_mapgen_update_func( JsonObject &jo, bool &defer ); bool run_mapgen_update_func( const std::string &update_mapgen_id, const tripoint &omt_pos, mission *miss = nullptr, bool cancel_on_collision = true ); - bool run_mapgen_func( const std::string &mapgen_id, map *m, oter_id terrain_type, mapgendata dat, const time_point &turn, float density ); +std::pair, std::map> get_changed_ids_from_update( + const std::string &update_mapgen_id ); #endif diff --git a/src/npc.cpp b/src/npc.cpp index af62705613309..391296f544a31 100644 --- a/src/npc.cpp +++ b/src/npc.cpp @@ -1764,7 +1764,14 @@ int npc::follow_distance() const g->m.has_flag( TFLAG_GOES_UP, g->u.pos() ) ) ) { return 1; } - // TODO: Allow player to set that + // Uses ally_rule follow_distance_2 to determine if should follow by 2 or 4 tiles + if( rules.has_flag( ally_rule::follow_distance_2 ) ) { + return 2; + } + // If NPC doesn't see player, change follow distance to 2 + if( !sees( g->u ) ) { + return 2; + } return 4; } @@ -2681,6 +2688,7 @@ npc_follower_rules::npc_follower_rules() clear_flag( ally_rule::hold_the_line ); clear_flag( ally_rule::ignore_noise ); clear_flag( ally_rule::forbid_engage ); + set_flag( ally_rule::follow_distance_2 ); } bool npc_follower_rules::has_flag( ally_rule test, bool check_override ) const diff --git a/src/npc.h b/src/npc.h index 7b7319f35d73b..f267e9533acec 100644 --- a/src/npc.h +++ b/src/npc.h @@ -282,7 +282,8 @@ enum class ally_rule { avoid_doors = 2048, hold_the_line = 4096, ignore_noise = 8192, - forbid_engage = 16384 + forbid_engage = 16384, + follow_distance_2 = 32768 }; struct ally_rule_data { @@ -396,6 +397,13 @@ const std::unordered_map ally_rule_strs = { { "", "" } + }, + { + "follow_distance_2", { + ally_rule::follow_distance_2, + "", + "" + } } } }; diff --git a/src/npctalk.cpp b/src/npctalk.cpp index dda8338c03a61..fa4ef95c7db32 100644 --- a/src/npctalk.cpp +++ b/src/npctalk.cpp @@ -1084,11 +1084,13 @@ void dialogue::gen_responses( const talk_topic &the_topic ) } for( auto &trained : trainable ) { const int cost = calc_skill_training_cost( *p, trained ); - const int cur_level = g->u.get_skill_level( trained ); - //~Skill name: current level -> next level (cost in dollars) - std::string text = string_format( cost > 0 ? _( "%s: %d -> %d (cost $%d)" ) : - _( "%s: %d -> %d" ), - trained.obj().name(), cur_level, cur_level + 1, + const SkillLevel skill_level_obj = g->u.get_skill_level_object( trained ); + const int cur_level = skill_level_obj.level(); + const int cur_level_exercise = skill_level_obj.exercise(); + //~Skill name: current level (exercise) -> next level (cost in dollars) + std::string text = string_format( cost > 0 ? _( "%s: %d (%d%%) -> %d (cost $%d)" ) : + _( "%s: %d (%d%%) -> %d" ), + trained.obj().name(), cur_level, cur_level_exercise, cur_level + 1, cost / 100 ); add_response( text, "TALK_TRAIN_START", trained ); } diff --git a/src/overmap_ui.cpp b/src/overmap_ui.cpp index 53afb10112681..72d178113f004 100644 --- a/src/overmap_ui.cpp +++ b/src/overmap_ui.cpp @@ -607,9 +607,9 @@ void draw( const catacurses::window &w, const catacurses::window &wbar, const tr ter_color = g->u.symbol_color(); ter_sym = "@"; } else if( viewing_weather && ( data.debug_weather || los_sky ) ) { - weather_datum weather = weather_data( get_weather_at_point( tripoint( omx, omy, z ) ) ); - ter_color = weather.map_color; - ter_sym = weather.glyph; + const weather_type type = get_weather_at_point( tripoint( omx, omy, z ) ); + ter_color = weather::map_color( type ); + ter_sym = weather::glyph( type ); } else if( data.debug_scent && get_scent_glyph( cur_pos, ter_color, ter_sym ) ) { } else if( blink && has_target && omx == target.x && omy == target.y ) { // Mission target, display always, player should know where it is anyway. diff --git a/src/panels.cpp b/src/panels.cpp index 19bdb3e2386cd..1a2abdac8ca90 100644 --- a/src/panels.cpp +++ b/src/panels.cpp @@ -1211,8 +1211,8 @@ static void draw_env1( const avatar &u, const catacurses::window &w ) mvwprintz( w, 1, 1, c_light_gray, _( "Sky : Underground" ) ); } else { mvwprintz( w, 1, 1, c_light_gray, _( "Sky :" ) ); - wprintz( w, weather_data( g->weather.weather ).color, " %s", - weather_data( g->weather.weather ).name ); + const weather_datum wdata = weather_data( g->weather.weather ); + wprintz( w, wdata.color, " %s", wdata.name ); } // display lighting const auto ll = get_light_level( g->u.fine_detail_vision_mod() ); @@ -1293,8 +1293,8 @@ static void draw_env_compact( avatar &u, const catacurses::window &w ) if( g->get_levz() < 0 ) { mvwprintz( w, 3, 8, c_light_gray, _( "Underground" ) ); } else { - mvwprintz( w, 3, 8, weather_data( g->weather.weather ).color, - weather_data( g->weather.weather ).name ); + const weather_datum wdata = weather_data( g->weather.weather ); + mvwprintz( w, 3, 8, wdata.color, wdata.name ); } // display lighting const auto ll = get_light_level( g->u.fine_detail_vision_mod() ); @@ -1602,9 +1602,9 @@ static void draw_weather_classic( avatar &, const catacurses::window &w ) if( g->get_levz() < 0 ) { mvwprintz( w, 0, 0, c_light_gray, _( "Underground" ) ); } else { + const weather_datum wdata = weather_data( g->weather.weather ); mvwprintz( w, 0, 0, c_light_gray, _( "Weather :" ) ); - mvwprintz( w, 0, 10, weather_data( g->weather.weather ).color, - weather_data( g->weather.weather ).name ); + mvwprintz( w, 0, 10, wdata.color, wdata.name ); } mvwprintz( w, 0, 31, c_light_gray, _( "Moon :" ) ); nc_color clr = c_white; diff --git a/src/player.cpp b/src/player.cpp index 8a16a52132232..e38dbf700c977 100644 --- a/src/player.cpp +++ b/src/player.cpp @@ -1164,6 +1164,7 @@ void player::update_bodytemp() // Difference between high and low is the "safe" heat - one we only apply if it's beneficial const int mutation_heat_bonus = mutation_heat_high - mutation_heat_low; + const int h_radiation = get_heat_radiation( pos(), false ); // Current temperature and converging temperature calculations for( const body_part bp : all_body_parts ) { // Skip eyes @@ -1218,7 +1219,6 @@ void player::update_bodytemp() // Bark : lowers blister count to -5; harder to get blisters int blister_count = ( has_bark ? -5 : 0 ); // If the counter is high, your skin starts to burn - const int h_radiation = get_heat_radiation( pos(), false ); if( frostbite_timer[bp] > 0 ) { frostbite_timer[bp] -= std::max( 5, h_radiation ); } @@ -3952,8 +3952,8 @@ void player::update_body( const time_point &from, const time_point &to ) { update_stamina( to_turns( to - from ) ); update_stomach( from, to ); - if( ticks_between( from, to, 10_turns ) > 0 ) { - magic.update_mana( *this, to_turns( 10_turns ) ); + if( ticks_between( from, to, 3_minutes ) > 0 ) { + magic.update_mana( *this, to_turns( 3_minutes ) ); } const int five_mins = ticks_between( from, to, 5_minutes ); if( five_mins > 0 ) { @@ -5001,14 +5001,14 @@ void player::process_one_effect( effect &it, bool is_new ) } else { add_msg_if_player( _( "Your %s hurts!" ), body_part_name_accusative( bp_torso ) ); } - apply_damage( nullptr, bp_torso, val ); + apply_damage( nullptr, bp_torso, val, true ); } else { if( val > 5 ) { add_msg_if_player( _( "Your %s HURTS!" ), body_part_name_accusative( bp ) ); } else { add_msg_if_player( _( "Your %s hurts!" ), body_part_name_accusative( bp ) ); } - apply_damage( nullptr, bp, val ); + apply_damage( nullptr, bp, val, true ); } } } @@ -5245,13 +5245,13 @@ void player::suffer() } } - if( x_in_y( root_vitamins, 96 ) ) { + if( x_in_y( root_vitamins, 576 ) ) { vitamin_mod( vitamin_id( "iron" ), 1, true ); vitamin_mod( vitamin_id( "calcium" ), 1, true ); mod_healthy_mod( 5, 50 ); } - if( x_in_y( root_water, 425 ) ) { + if( x_in_y( root_water, 2550 ) ) { // Plants draw some crazy amounts of water from the ground in real life, // so these numbers try to reflect that uncertain but large amount // this should take 12 hours to meet your daily needs with ROOTS2, and 8 with ROOTS3 @@ -5753,12 +5753,12 @@ void player::suffer() } } - if( x_in_y( sunlight_nutrition, 3000 ) ) { + if( x_in_y( sunlight_nutrition, 18000 ) ) { vitamin_mod( vitamin_id( "vitA" ), 1, true ); vitamin_mod( vitamin_id( "vitC" ), 1, true ); } - if( x_in_y( sunlight_nutrition, 2000 ) ) { + if( x_in_y( sunlight_nutrition, 12000 ) ) { mod_hunger( -1 ); // photosynthesis absorbs kcal directly mod_stored_nutr( -1 ); @@ -11488,7 +11488,7 @@ bool player::can_hear( const tripoint &source, const int volume ) const } const int dist = rl_dist( source, pos() ); const float volume_multiplier = hearing_ability(); - return ( volume - weather_data( g->weather.weather ).sound_attn ) * volume_multiplier >= dist; + return ( volume - weather::sound_attn( g->weather.weather ) ) * volume_multiplier >= dist; } float player::hearing_ability() const diff --git a/src/player_display.cpp b/src/player_display.cpp index 4ee6fb15cff8e..357726f2ec3b5 100644 --- a/src/player_display.cpp +++ b/src/player_display.cpp @@ -5,6 +5,7 @@ #include #include "addiction.h" +#include "avatar.h" #include "bionics.h" #include "effect.h" #include "game.h" @@ -23,6 +24,14 @@ const skill_id skill_swimming( "swimming" ); +static const std::string title_STATS = _( "STATS" ); +static const std::string title_ENCUMB = _( "ENCUMBRANCE AND WARMTH" ); +static const std::string title_EFFECTS = _( "EFFECTS" ); +static const std::string title_SPEED = _( "SPEED" ); +static const std::string title_SKILLS = _( "SKILLS" ); +static const std::string title_BIONICS = _( "BIONICS" ); +static const std::string title_TRAITS = _( "TRAITS" ); + // use this instead of having to type out 26 spaces like before static const std::string header_spaces( 26, ' ' ); @@ -237,163 +246,512 @@ static bool is_cqb_skill( const skill_id &id ) return std::find( cqb_skills.begin(), cqb_skills.end(), id ) != cqb_skills.end(); } -void player::disp_info() +static void draw_stats_tab( const catacurses::window &w_stats, const catacurses::window &w_info, + player &you, unsigned int &line, int &curtab, input_context &ctxt, bool &done, + std::string &action ) { - unsigned line; - std::vector effect_name; - std::vector effect_text; - for( auto &elem : *effects ) { - for( auto &_effect_it : elem.second ) { - const std::string tmp = _effect_it.second.disp_name(); - if( !tmp.empty() ) { - effect_name.push_back( tmp ); - effect_text.push_back( _effect_it.second.disp_desc() ); + + mvwprintz( w_stats, 0, 0, h_light_gray, header_spaces ); + center_print( w_stats, 0, h_light_gray, title_STATS ); + + // Clear bonus/penalty menu. + mvwprintz( w_stats, 7, 0, c_light_gray, "%26s", "" ); + mvwprintz( w_stats, 8, 0, c_light_gray, "%26s", "" ); + + if( line == 0 ) { + // Display information on player strength in appropriate window + mvwprintz( w_stats, 2, 1, h_light_gray, _( "Strength:" ) ); + fold_and_print( w_info, 0, 1, FULL_SCREEN_WIDTH - 2, c_magenta, + _( "Strength affects your melee damage, the amount of weight you can carry, your total HP, " + "your resistance to many diseases, and the effectiveness of actions which require brute force." ) ); + mvwprintz( w_info, 3, 1, c_magenta, _( "Base HP:" ) ); + mvwprintz( w_info, 3, 22, c_magenta, "%3d", you.hp_max[1] ); + if( get_option( "USE_METRIC_WEIGHTS" ) == "kg" ) { + mvwprintz( w_info, 4, 1, c_magenta, _( "Carry weight(kg):" ) ); + } else { + mvwprintz( w_info, 4, 1, c_magenta, _( "Carry weight(lbs):" ) ); + } + mvwprintz( w_info, 4, 21, c_magenta, "%4.1f", convert_weight( you.weight_capacity() ) ); + mvwprintz( w_info, 5, 1, c_magenta, _( "Melee damage:" ) ); + mvwprintz( w_info, 5, 22, c_magenta, "%3.1f", you.bonus_damage( false ) ); + + } else if( line == 1 ) { + // Display information on player dexterity in appropriate window + mvwprintz( w_stats, 3, 1, h_light_gray, _( "Dexterity:" ) ); + fold_and_print( w_info, 0, 1, FULL_SCREEN_WIDTH - 2, c_magenta, + _( "Dexterity affects your chance to hit in melee combat, helps you steady your " + "gun for ranged combat, and enhances many actions that require finesse." ) ); + mvwprintz( w_info, 3, 1, c_magenta, _( "Melee to-hit bonus:" ) ); + mvwprintz( w_info, 3, 38, c_magenta, "%+.1lf", you.get_hit_base() ); + mvwprintz( w_info, 4, 1, c_magenta, _( "Ranged penalty:" ) ); + mvwprintz( w_info, 4, 38, c_magenta, "%+3d", -( abs( you.ranged_dex_mod() ) ) ); + mvwprintz( w_info, 5, 1, c_magenta, _( "Throwing penalty per target's dodge:" ) ); + mvwprintz( w_info, 5, 38, c_magenta, "%+3d", you.throw_dispersion_per_dodge( false ) ); + } else if( line == 2 ) { + // Display information on player intelligence in appropriate window + mvwprintz( w_stats, 4, 1, h_light_gray, _( "Intelligence:" ) ); + fold_and_print( w_info, 0, 1, FULL_SCREEN_WIDTH - 2, c_magenta, + _( "Intelligence is less important in most situations, but it is vital for more complex tasks like " + "electronics crafting. It also affects how much skill you can pick up from reading a book." ) ); + mvwprintz( w_info, 3, 1, c_magenta, _( "Read times:" ) ); + mvwprintz( w_info, 3, 21, c_magenta, "%3d%%", you.read_speed( false ) ); + mvwprintz( w_info, 4, 1, c_magenta, _( "Skill rust:" ) ); + mvwprintz( w_info, 4, 22, c_magenta, "%2d%%", you.rust_rate( false ) ); + mvwprintz( w_info, 5, 1, c_magenta, _( "Crafting bonus:" ) ); + mvwprintz( w_info, 5, 22, c_magenta, "%2d%%", you.get_int() ); + } else if( line == 3 ) { + // Display information on player perception in appropriate window + mvwprintz( w_stats, 5, 1, h_light_gray, _( "Perception:" ) ); + fold_and_print( w_info, 0, 1, FULL_SCREEN_WIDTH - 2, c_magenta, + _( "Perception is the most important stat for ranged combat. It's also used for " + "detecting traps and other things of interest." ) ); + mvwprintz( w_info, 4, 1, c_magenta, _( "Trap detection level:" ) ); + mvwprintz( w_info, 4, 23, c_magenta, "%2d", you.get_per() ); + if( you.ranged_per_mod() > 0 ) { + mvwprintz( w_info, 5, 1, c_magenta, _( "Aiming penalty:" ) ); + mvwprintz( w_info, 5, 21, c_magenta, "%+4d", -you.ranged_per_mod() ); + } + } else if( line == 4 ) { + mvwprintz( w_stats, 6, 1, h_light_gray, _( "Weight:" ) ); + mvwprintz( w_stats, 6, 25 - you.get_weight_string().size(), h_light_gray, you.get_weight_string() ); + const int lines = fold_and_print( w_info, 0, 1, FULL_SCREEN_WIDTH - 2, c_magenta, + _( "Your weight is a general indicator of how much fat your body has stored up," + " which in turn shows how prepared you are to survive for a time without food." + "Having too much, or too little, can be unhealthy." ) ); + fold_and_print( w_info, 1 + lines, 1, FULL_SCREEN_WIDTH - 2, c_magenta, + you.get_weight_description() ); + } + wrefresh( w_stats ); + wrefresh( w_info ); + + action = ctxt.handle_input(); + if( action == "DOWN" ) { + line++; + if( line == 5 ) { + line = 0; + } + } else if( action == "UP" ) { + if( line == 0 ) { + line = 4; + } else { + line--; + } + } else if( action == "NEXT_TAB" || action == "PREV_TAB" ) { + mvwprintz( w_stats, 0, 0, c_light_gray, header_spaces ); + center_print( w_stats, 0, c_light_gray, title_STATS ); + wrefresh( w_stats ); + line = 0; + curtab = action == "NEXT_TAB" ? curtab + 1 : 6; + } else if( action == "QUIT" ) { + done = true; + } + mvwprintz( w_stats, 2, 1, c_light_gray, _( "Strength:" ) ); + mvwprintz( w_stats, 3, 1, c_light_gray, _( "Dexterity:" ) ); + mvwprintz( w_stats, 4, 1, c_light_gray, _( "Intelligence:" ) ); + mvwprintz( w_stats, 5, 1, c_light_gray, _( "Perception:" ) ); + mvwprintz( w_stats, 6, 1, c_light_gray, _( "Weight:" ) ); + mvwprintz( w_stats, 6, 25 - you.get_weight_string().size(), c_light_gray, you.get_weight_string() ); + wrefresh( w_stats ); +} + +static void draw_encumbrance_tab( const catacurses::window &w_encumb, + const catacurses::window &w_info, player &you, unsigned int &line, int &curtab, input_context &ctxt, + bool &done, std::string &action ) +{ + werase( w_encumb ); + center_print( w_encumb, 0, h_light_gray, title_ENCUMB ); + you.print_encumbrance( w_encumb, line ); + wrefresh( w_encumb ); + + werase( w_info ); + std::string s; + + body_part bp = line <= 11 ? all_body_parts[line] : num_bp; + bool combined_here = ( bp_aiOther[line] == line + 1 || + bp_aiOther[line] == line - 1 ) && // first of a pair + should_combine_bps( you, line, bp_aiOther[line] ); + s += get_encumbrance_description( you, bp, combined_here ); + fold_and_print( w_info, 0, 1, FULL_SCREEN_WIDTH - 2, c_magenta, s ); + wrefresh( w_info ); + + action = ctxt.handle_input(); + if( action == "DOWN" ) { + if( line < num_bp - 1 ) { + if( combined_here ) { + line += ( line < num_bp - 2 ) ? 2 : 0; // skip a line if we aren't at the last pair + } else { + line++; // unpaired or unequal + } + } + } else if( action == "UP" ) { + if( line > 0 ) { + if( bp_aiOther[line] == line - 1 && // second of a pair + should_combine_bps( you, line, bp_aiOther[line] ) ) { + line -= ( line > 1 ) ? 2 : 0; // skip a line if we aren't at the first pair + } else { + line--; // unpaired or unequal } } + } else if( action == "NEXT_TAB" || action == "PREV_TAB" ) { + mvwprintz( w_encumb, 0, 0, c_light_gray, header_spaces ); + center_print( w_encumb, 0, c_light_gray, title_ENCUMB ); + wrefresh( w_encumb ); + line = 0; + curtab = action == "NEXT_TAB" ? curtab + 1 : curtab - 1; + } else if( action == "QUIT" ) { + done = true; } - if( get_perceived_pain() > 0 ) { - effect_name.push_back( _( "Pain" ) ); - const auto ppen = get_pain_penalty(); - std::stringstream pain_text; - if( ppen.strength > 0 ) { - pain_text << _( "Strength" ) << " -" << ppen.strength << " "; +} + +static void draw_traits_tab( const catacurses::window &w_traits, const catacurses::window &w_info, + unsigned int &line, int &curtab, input_context &ctxt, bool &done, + std::string &action, std::vector &traitslist, + size_t &min, size_t &max ) +{ + werase( w_traits ); + mvwprintz( w_traits, 0, 0, h_light_gray, header_spaces ); + center_print( w_traits, 0, h_light_gray, title_TRAITS ); + const unsigned int trait_win_size_y = 1 + static_cast( traitslist.size() ); + if( line <= ( trait_win_size_y - 1 ) / 2 ) { + min = 0; + max = trait_win_size_y; + if( traitslist.size() < max ) { + max = traitslist.size(); } - if( ppen.dexterity > 0 ) { - pain_text << _( "Dexterity" ) << " -" << ppen.dexterity << " "; + } else if( line >= traitslist.size() - ( trait_win_size_y + 1 ) / 2 ) { + min = ( traitslist.size() < trait_win_size_y ? 0 : traitslist.size() - trait_win_size_y ); + max = traitslist.size(); + } else { + min = line - ( trait_win_size_y - 1 ) / 2; + max = line + trait_win_size_y / 2 + 1; + if( traitslist.size() < max ) { + max = traitslist.size(); } - if( ppen.intelligence > 0 ) { - pain_text << _( "Intelligence" ) << " -" << ppen.intelligence << " "; + } + + for( size_t i = min; i < max; i++ ) { + const auto &mdata = traitslist[i].obj(); + const auto color = mdata.get_display_color(); + trim_and_print( w_traits, static_cast( 1 + i - min ), 1, getmaxx( w_traits ) - 1, + i == line ? hilite( color ) : color, mdata.name() ); + } + if( line < traitslist.size() ) { + const auto &mdata = traitslist[line].obj(); + fold_and_print( w_info, 0, 1, FULL_SCREEN_WIDTH - 2, c_magenta, string_format( + "%s: %s", string_from_color( mdata.get_display_color() ), + mdata.name(), traitslist[line]->desc() ) ); + } + wrefresh( w_traits ); + wrefresh( w_info ); + + action = ctxt.handle_input(); + if( action == "DOWN" ) { + if( line < traitslist.size() - 1 ) { + line++; } - if( ppen.perception > 0 ) { - pain_text << _( "Perception" ) << " -" << ppen.perception << " "; + return; + } else if( action == "UP" ) { + if( line > 0 ) { + line--; } - if( ppen.speed > 0 ) { - pain_text << _( "Speed" ) << " -" << ppen.speed << "% "; + } else if( action == "NEXT_TAB" || action == "PREV_TAB" ) { + mvwprintz( w_traits, 0, 0, c_light_gray, header_spaces ); + center_print( w_traits, 0, c_light_gray, title_TRAITS ); + for( size_t i = 0; i < traitslist.size() && i < trait_win_size_y; i++ ) { + const auto &mdata = traitslist[i].obj(); + mvwprintz( w_traits, static_cast( i + 1 ), 1, c_black, " " ); + const auto color = mdata.get_display_color(); + trim_and_print( w_traits, static_cast( i + 1 ), 1, getmaxx( w_traits ) - 1, + color, mdata.name() ); } - effect_text.push_back( pain_text.str() ); + wrefresh( w_traits ); + line = 0; + curtab = action == "NEXT_TAB" ? curtab + 1 : curtab - 1; + } else if( action == "QUIT" ) { + done = true; } +} - int starvation_base_penalty = get_starvation() + 300; +static void draw_bionics_tab( const catacurses::window &w_bionics, const catacurses::window &w_info, + player &you, unsigned int &line, int &curtab, input_context &ctxt, bool &done, + std::string &action, std::vector &bionicslist, + size_t &min, size_t &max, const size_t bionics_useful_size_y, const size_t bionics_win_size_y ) +{ + werase( w_bionics ); + mvwprintz( w_bionics, 0, 0, h_light_gray, header_spaces ); + center_print( w_bionics, 0, h_light_gray, title_BIONICS ); + trim_and_print( w_bionics, 1, 1, getmaxx( w_bionics ) - 1, c_white, + string_format( _( "Bionic Power: %1$d" ), you.max_power_level ) ); + + if( line <= ( ( bionics_useful_size_y - 1 ) / 2 ) ) { + min = 0; + max = std::min( bionicslist.size(), bionics_useful_size_y ); + } else if( line >= ( bionicslist.size() - ( bionics_useful_size_y + 1 ) / 2 ) ) { + min = ( bionicslist.size() < bionics_useful_size_y ? 0 : bionicslist.size() - bionics_useful_size_y + + 1 ); + max = bionicslist.size(); + } else { + min = line - ( bionics_useful_size_y - 1 ) / 2; + max = std::min( bionicslist.size(), static_cast( 1 + line + bionics_useful_size_y / 2 ) ); + } - if( starvation_base_penalty > 300 ) { - std::stringstream starvation_text; + for( size_t i = min; i < max; i++ ) { + trim_and_print( w_bionics, static_cast( 2 + i - min ), 1, getmaxx( w_bionics ) - 1, + i == line ? hilite( c_white ) : c_white, bionicslist[i].info().name ); + } + if( line < bionicslist.size() ) { + fold_and_print( w_info, 0, 1, FULL_SCREEN_WIDTH - 2, c_white, + bionicslist[line].info().description ); + } + wrefresh( w_bionics ); + wrefresh( w_info ); - if( starvation_base_penalty > 1400 ) { - effect_name.push_back( _( "Severely Malnourished" ) ); - starvation_text << - _( "Your body is severely weakened by starvation. You might die if you don't start eating regular meals!\n \n" ); - } else { - effect_name.push_back( _( "Malnourished" ) ); - starvation_text << - _( "Your body is weakened by starvation. Only time and regular meals will help you recover.\n \n" ); + action = ctxt.handle_input(); + if( action == "DOWN" ) { + if( line < bionicslist.size() - 1 ) { + line++; + } + return; + } else if( action == "UP" ) { + if( line > 0 ) { + line--; } + } else if( action == "NEXT_TAB" || action == "PREV_TAB" ) { + mvwprintz( w_bionics, 0, 0, c_light_gray, header_spaces ); + center_print( w_bionics, 0, c_light_gray, title_BIONICS ); + trim_and_print( w_bionics, 1, 1, getmaxx( w_bionics ) - 1, c_white, + string_format( _( "Bionic Power: %1$d" ), you.max_power_level ) ); + for( size_t i = 0; i < bionicslist.size() && i < bionics_win_size_y; i++ ) { + mvwprintz( w_bionics, static_cast( i + 2 ), 1, c_black, " " ); + trim_and_print( w_bionics, static_cast( i + 2 ), 1, getmaxx( w_bionics ) - 1, + c_white, bionicslist[i].info().name ); + } + wrefresh( w_bionics ); + line = 0; + curtab = action == "NEXT_TAB" ? curtab + 1 : curtab - 1; + } else if( action == "QUIT" ) { + done = true; + } +} - if( starvation_base_penalty > 500 ) { - starvation_text << _( "Strength" ) << " -" << static_cast( starvation_base_penalty / 500 ) << - " "; - if( starvation_base_penalty > 1000 ) { - starvation_text << _( "Dexterity" ) << " -" << static_cast( starvation_base_penalty / 1000 ) << - " "; - starvation_text << _( "Intelligence" ) << " -" << static_cast( starvation_base_penalty / 1000 ) - << " "; - } +static void draw_effects_tab( const catacurses::window &w_effects, const catacurses::window &w_info, + unsigned int &line, int &curtab, input_context &ctxt, bool &done, + std::string &action, std::vector &effect_name, + size_t &min, size_t &max, const size_t effect_win_size_y, + const std::vector &effect_text, size_t &half_y ) +{ + mvwprintz( w_effects, 0, 0, h_light_gray, header_spaces ); + center_print( w_effects, 0, h_light_gray, title_EFFECTS ); + half_y = effect_win_size_y / 2; + if( line <= half_y ) { + min = 0; + max = effect_win_size_y; + if( effect_name.size() < max ) { + max = effect_name.size(); + } + } else if( line >= effect_name.size() - half_y ) { + min = ( effect_name.size() < effect_win_size_y ? 0 : effect_name.size() - effect_win_size_y ); + max = effect_name.size(); + } else { + min = line - half_y; + max = line - half_y + effect_win_size_y; + if( effect_name.size() < max ) { + max = effect_name.size(); } + } - effect_text.push_back( starvation_text.str() ); + for( size_t i = min; i < max; i++ ) { + trim_and_print( w_effects, static_cast( 1 + i - min ), 0, getmaxx( w_effects ) - 1, + i == line ? h_light_gray : c_light_gray, effect_name[i] ); } + if( line < effect_text.size() ) { + fold_and_print( w_info, 0, 1, FULL_SCREEN_WIDTH - 2, c_magenta, effect_text[line] ); + } + wrefresh( w_effects ); + wrefresh( w_info ); - if( ( has_trait( trait_id( "TROGLO" ) ) && g->is_in_sunlight( pos() ) && - g->weather.weather == WEATHER_SUNNY ) || - ( has_trait( trait_id( "TROGLO2" ) ) && g->is_in_sunlight( pos() ) && - g->weather.weather != WEATHER_SUNNY ) ) { - effect_name.push_back( _( "In Sunlight" ) ); - effect_text.push_back( _( "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.push_back( _( "In Sunlight" ) ); - effect_text.push_back( _( "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.push_back( _( "In Sunlight" ) ); - effect_text.push_back( _( "The sunlight irritates you terribly.\n\ -Strength - 4; Dexterity - 4; Intelligence - 4; Perception - 4" ) ); + action = ctxt.handle_input(); + if( action == "DOWN" ) { + if( line < effect_name.size() - 1 ) { + line++; + } + return; + } else if( action == "UP" ) { + if( line > 0 ) { + line--; + } + } else if( action == "NEXT_TAB" || action == "PREV_TAB" ) { + mvwprintz( w_effects, 0, 0, c_light_gray, header_spaces ); + center_print( w_effects, 0, c_light_gray, title_EFFECTS ); + for( size_t i = 0; i < effect_name.size() && i < 7; i++ ) { + trim_and_print( w_effects, static_cast( i ) + 1, 0, getmaxx( w_effects ) - 1, c_light_gray, + effect_name[i] ); + } + wrefresh( w_effects ); + line = 0; + curtab = action == "NEXT_TAB" ? 1 : curtab - 1; + } else if( action == "QUIT" ) { + done = true; } +} - for( auto &elem : addictions ) { - if( elem.sated < 0_turns && elem.intensity >= MIN_ADDICTION_LEVEL ) { - effect_name.push_back( addiction_name( elem ) ); - effect_text.push_back( addiction_text( elem ) ); +static void draw_skills_tab( const catacurses::window &w_skills, const catacurses::window &w_info, + player &you, unsigned int &line, int &curtab, input_context &ctxt, bool &done, + std::string &action, const std::vector &skillslist, + size_t &min, size_t &max, const size_t skill_win_size_y, size_t &half_y ) +{ + assert( line >= min && line <= max ); + mvwprintz( w_skills, 0, 0, h_light_gray, header_spaces ); + center_print( w_skills, 0, h_light_gray, title_SKILLS ); + half_y = skill_win_size_y / 2; + if( line <= half_y ) { + min = 0; + max = skill_win_size_y; + if( skillslist.size() < max ) { + max = skillslist.size(); + } + } else if( line >= skillslist.size() - half_y ) { + min = ( skillslist.size() < static_cast( skill_win_size_y ) ? 0 : skillslist.size() - + skill_win_size_y ); + max = skillslist.size(); + } else { + min = line - half_y; + max = line - half_y + skill_win_size_y; + if( skillslist.size() < max ) { + max = skillslist.size(); } } - unsigned maxy = static_cast( TERMY ); + const Skill *selectedSkill = nullptr; - unsigned effect_win_size_y = 1 + static_cast( effect_name.size() ); + for( size_t i = min; i < max; i++ ) { + const Skill *aSkill = skillslist[i]; + const SkillLevel &level = you.get_skill_level_object( aSkill->ident() ); - std::vector traitslist = get_mutations( false ); - unsigned trait_win_size_y = 1 + static_cast( traitslist.size() ); + const bool can_train = level.can_train(); + const bool training = level.isTraining(); + const bool rusting = level.isRusting(); + int exercise = level.exercise(); + int level_num = level.level(); + bool locked = false; + if( you.has_active_bionic( bionic_id( "bio_cqb" ) ) && is_cqb_skill( aSkill->ident() ) ) { + level_num = 5; + exercise = 0; + locked = true; + } + nc_color cstatus; + if( i == line ) { + selectedSkill = aSkill; + if( locked ) { + cstatus = h_yellow; + } else if( !can_train ) { + cstatus = rusting ? h_light_red : h_white; + } else if( exercise >= 100 ) { + cstatus = training ? h_pink : h_magenta; + } else if( rusting ) { + cstatus = training ? h_light_red : h_red; + } else { + cstatus = training ? h_light_blue : h_blue; + } + } else { + if( locked ) { + cstatus = c_yellow; + } else if( rusting ) { + cstatus = training ? c_light_red : c_red; + } else if( !can_train ) { + cstatus = c_white; + } else { + cstatus = training ? c_light_blue : c_blue; + } + } + mvwprintz( w_skills, static_cast( 1 + i - min ), 1, c_light_gray, + " " ); + mvwprintz( w_skills, static_cast( 1 + i - min ), 1, cstatus, "%s:", aSkill->name() ); - std::vector bionicslist = *my_bionics; - unsigned bionics_win_size_y = 2 + bionicslist.size(); + if( aSkill->ident() == skill_id( "dodge" ) ) { + mvwprintz( w_skills, static_cast( 1 + i - min ), 14, cstatus, "%4.1f/%-2d(%2d%%)", + you.get_dodge(), level_num, exercise < 0 ? 0 : exercise ); + } else { + mvwprintz( w_skills, static_cast( 1 + i - min ), 19, cstatus, "%-2d(%2d%%)", level_num, + ( exercise < 0 ? 0 : exercise ) ); + } + } - const auto skillslist = Skill::get_skills_sorted_by( [&]( const Skill & a, const Skill & b ) { - const int level_a = get_skill_level_object( a.ident() ).exercised_level(); - const int level_b = get_skill_level_object( b.ident() ).exercised_level(); - return level_a > level_b || ( level_a == level_b && a.name() < b.name() ); - } ); - unsigned skill_win_size_y = 1 + skillslist.size(); - unsigned info_win_size_y = 6; + draw_scrollbar( w_skills, line, skill_win_size_y, static_cast( skillslist.size() ), 1 ); + wrefresh( w_skills ); - unsigned infooffsetytop = 11; - unsigned infooffsetybottom = infooffsetytop + 1 + info_win_size_y; + werase( w_info ); - if( ( bionics_win_size_y + trait_win_size_y + infooffsetybottom ) > maxy ) { - // maximum space for either window if they're both the same size - unsigned max_shared_y = ( maxy - infooffsetybottom ) / 2; - // both are larger than the shared size - if( std::min( bionics_win_size_y, trait_win_size_y ) > max_shared_y ) { - bionics_win_size_y = max_shared_y; - // trait window is less than the shared size, so give space to bionics - } else if( trait_win_size_y <= max_shared_y ) { - bionics_win_size_y = maxy - infooffsetybottom - trait_win_size_y; - } - // fall through if bionics is smaller - trait_win_size_y = maxy - infooffsetybottom - bionics_win_size_y; + if( line < skillslist.size() ) { + fold_and_print( w_info, 0, 1, FULL_SCREEN_WIDTH - 2, c_magenta, selectedSkill->description() ); } + wrefresh( w_info ); - if( skill_win_size_y + infooffsetybottom > maxy ) { - skill_win_size_y = maxy - infooffsetybottom; - } + action = ctxt.handle_input(); + if( action == "DOWN" ) { + if( static_cast( line ) < skillslist.size() - 1 ) { + line++; + } + } else if( action == "UP" ) { + if( line > 0 ) { + line--; + } + } else if( action == "NEXT_TAB" || action == "PREV_TAB" ) { + werase( w_skills ); + mvwprintz( w_skills, 0, 0, c_light_gray, header_spaces ); + center_print( w_skills, 0, c_light_gray, title_SKILLS ); + for( size_t i = 0; i < skillslist.size() && i < static_cast( skill_win_size_y ); i++ ) { + const Skill *thisSkill = skillslist[i]; + const SkillLevel &level = you.get_skill_level_object( thisSkill->ident() ); + bool can_train = level.can_train(); + bool isLearning = level.isTraining(); + bool rusting = level.isRusting(); + int level_num = level.level(); + int exercise = level.exercise(); + bool locked = false; + if( you.has_active_bionic( bionic_id( "bio_cqb" ) ) && is_cqb_skill( thisSkill->ident() ) ) { + level_num = 5; + exercise = 0; + locked = true; + } + nc_color cstatus; + if( locked ) { + cstatus = c_yellow; + } else if( rusting ) { + cstatus = isLearning ? c_light_red : c_red; + } else if( !can_train ) { + cstatus = c_white; + } else { + cstatus = isLearning ? c_light_blue : c_blue; + } - catacurses::window w_grid_top = catacurses::newwin( infooffsetybottom, FULL_SCREEN_WIDTH + 1, - VIEW_OFFSET_Y, VIEW_OFFSET_X ); - catacurses::window w_grid_skill = catacurses::newwin( skill_win_size_y + 1, 27, - infooffsetybottom + VIEW_OFFSET_Y, 0 + VIEW_OFFSET_X ); - catacurses::window w_grid_trait = catacurses::newwin( trait_win_size_y + 1, 27, - infooffsetybottom + VIEW_OFFSET_Y, 27 + VIEW_OFFSET_X ); - catacurses::window w_grid_bionics = catacurses::newwin( bionics_win_size_y + 1, 27, - infooffsetybottom + VIEW_OFFSET_Y + trait_win_size_y + 1, - 27 + VIEW_OFFSET_X ); - catacurses::window w_grid_effect = catacurses::newwin( effect_win_size_y + 1, 28, - infooffsetybottom + VIEW_OFFSET_Y, 53 + VIEW_OFFSET_X ); + mvwprintz( w_skills, i + 1, 1, cstatus, "%s:", thisSkill->name() ); - catacurses::window w_tip = catacurses::newwin( 1, FULL_SCREEN_WIDTH, VIEW_OFFSET_Y, - 0 + VIEW_OFFSET_X ); - catacurses::window w_stats = catacurses::newwin( 9, 26, 1 + VIEW_OFFSET_Y, 0 + VIEW_OFFSET_X ); - catacurses::window w_traits = catacurses::newwin( trait_win_size_y, 26, - infooffsetybottom + VIEW_OFFSET_Y, 27 + VIEW_OFFSET_X ); - catacurses::window w_bionics = catacurses::newwin( bionics_win_size_y, 26, - infooffsetybottom + VIEW_OFFSET_Y + trait_win_size_y + 1, - 27 + VIEW_OFFSET_X ); - catacurses::window w_encumb = catacurses::newwin( 9, 26, 1 + VIEW_OFFSET_Y, 27 + VIEW_OFFSET_X ); - catacurses::window w_effects = catacurses::newwin( effect_win_size_y, 26, - infooffsetybottom + VIEW_OFFSET_Y, 54 + VIEW_OFFSET_X ); - catacurses::window w_speed = catacurses::newwin( 9, 26, 1 + VIEW_OFFSET_Y, 54 + VIEW_OFFSET_X ); - catacurses::window w_skills = catacurses::newwin( skill_win_size_y, 26, - infooffsetybottom + VIEW_OFFSET_Y, 0 + VIEW_OFFSET_X ); - catacurses::window w_info = catacurses::newwin( info_win_size_y, FULL_SCREEN_WIDTH, - infooffsetytop + VIEW_OFFSET_Y, 0 + VIEW_OFFSET_X ); + if( thisSkill->ident() == skill_id( "dodge" ) ) { + mvwprintz( w_skills, i + 1, 14, cstatus, "%4.1f/%-2d(%2d%%)", + you.get_dodge(), level_num, exercise < 0 ? 0 : exercise ); + } else { + mvwprintz( w_skills, i + 1, 19, cstatus, "%-2d(%2d%%)", level_num, + ( exercise < 0 ? 0 : exercise ) ); + } + } + wrefresh( w_skills ); + line = 0; + curtab = action == "NEXT_TAB" ? curtab + 1 : curtab - 1; + } else if( action == "CONFIRM" ) { + you.get_skill_level_object( selectedSkill->ident() ).toggleTraining(); + } else if( action == "QUIT" ) { + done = true; + } +} +static void draw_grid_borders( const catacurses::window &w_grid_top, + const catacurses::window &w_grid_skill, const catacurses::window &w_grid_trait, + const catacurses::window &w_grid_bionics, const catacurses::window &w_grid_effect, + const unsigned int &info_win_size_y, const unsigned int &infooffsetybottom, + const unsigned int &skill_win_size_y, const unsigned int &trait_win_size_y, + const unsigned int &bionics_win_size_y, const unsigned int &effect_win_size_y ) +{ unsigned upper_info_border = 10; unsigned lower_info_border = 1 + upper_info_border + info_win_size_y; for( unsigned i = 0; i < static_cast( FULL_SCREEN_WIDTH + 1 ); i++ ) { @@ -495,51 +853,18 @@ Strength - 4; Dexterity - 4; Intelligence - 4; Perception - 4" ) ); wrefresh( w_grid_trait ); wrefresh( w_grid_bionics ); - //-1 for header - trait_win_size_y--; - bionics_win_size_y--; - skill_win_size_y--; - effect_win_size_y--; - - // Print name and header - // Post-humanity trumps your pre-Cataclysm life. - if( crossed_threshold() ) { - std::string race; - for( auto &mut : my_mutations ) { - const auto &mdata = mut.first.obj(); - if( mdata.threshold ) { - race = mdata.name(); - break; - } - } - //~ player info window: 1s - name, 2s - gender, 3s - Prof or Mutation name - mvwprintw( w_tip, 0, 0, _( "%1$s | %2$s | %3$s" ), name, male ? _( "Male" ) : _( "Female" ), race ); - } else if( prof == nullptr || prof == prof->generic() ) { - // Regular person. Nothing interesting. - //~ player info window: 1s - name, 2s - gender, '|' - field separator. - mvwprintw( w_tip, 0, 0, _( "%1$s | %2$s" ), name, male ? _( "Male" ) : _( "Female" ) ); - } else { - mvwprintw( w_tip, 0, 0, _( "%1$s | %2$s | %3$s" ), name, - male ? _( "Male" ) : _( "Female" ), prof->gender_appropriate_name( male ) ); - } - - input_context ctxt( "PLAYER_INFO" ); - ctxt.register_updown(); - ctxt.register_action( "NEXT_TAB", _( "Cycle to next category" ) ); - ctxt.register_action( "PREV_TAB", _( "Cycle to previous category" ) ); - ctxt.register_action( "QUIT" ); - ctxt.register_action( "CONFIRM", _( "Toggle skill training" ) ); - ctxt.register_action( "HELP_KEYBINDINGS" ); - std::string action; - - std::string help_msg = string_format( _( "Press %s for help." ), - ctxt.get_desc( "HELP_KEYBINDINGS" ) ); - mvwprintz( w_tip, 0, FULL_SCREEN_WIDTH - utf8_width( help_msg ), c_light_red, help_msg ); - help_msg.clear(); - wrefresh( w_tip ); +} +static void draw_initial_windows( const catacurses::window &w_stats, + const catacurses::window &w_encumb, const catacurses::window &w_traits, + const catacurses::window &w_bionics, const catacurses::window &w_effects, + const catacurses::window &w_skills, const catacurses::window &w_speed, player &you, + unsigned int &line, std::vector &traitslist, std::vector &bionicslist, + std::vector &effect_name, const std::vector &skillslist, + const size_t bionics_win_size_y, const size_t effect_win_size_y, const size_t trait_win_size_y, + const size_t skill_win_size_y ) +{ // First! Default STATS screen. - const std::string title_STATS = _( "STATS" ); center_print( w_stats, 0, c_light_gray, title_STATS ); // Stats @@ -564,23 +889,21 @@ Strength - 4; Dexterity - 4; Intelligence - 4; Perception - 4" ) ); mvwprintz( w_stats, line_n, 21, c_light_gray, "(%2d)", max ); }; - display_stat( _( "Strength:" ), str_cur, str_max, 2 ); - display_stat( _( "Dexterity:" ), dex_cur, dex_max, 3 ); - display_stat( _( "Intelligence:" ), int_cur, int_max, 4 ); - display_stat( _( "Perception:" ), per_cur, per_max, 5 ); + display_stat( _( "Strength:" ), you.str_cur, you.str_max, 2 ); + display_stat( _( "Dexterity:" ), you.dex_cur, you.dex_max, 3 ); + display_stat( _( "Intelligence:" ), you.int_cur, you.int_max, 4 ); + display_stat( _( "Perception:" ), you.per_cur, you.per_max, 5 ); mvwprintz( w_stats, 6, 1, c_light_gray, _( "Weight:" ) ); - mvwprintz( w_stats, 6, 25 - get_weight_string().size(), c_light_gray, get_weight_string() ); + mvwprintz( w_stats, 6, 25 - you.get_weight_string().size(), c_light_gray, you.get_weight_string() ); wrefresh( w_stats ); // Next, draw encumbrance. - const std::string title_ENCUMB = _( "ENCUMBRANCE AND WARMTH" ); center_print( w_encumb, 0, c_light_gray, title_ENCUMB ); - print_encumbrance( w_encumb ); + you.print_encumbrance( w_encumb ); wrefresh( w_encumb ); // Next, draw traits. - const std::string title_TRAITS = _( "TRAITS" ); center_print( w_traits, 0, c_light_gray, title_TRAITS ); std::sort( traitslist.begin(), traitslist.end(), trait_display_sort ); for( size_t i = 0; i < traitslist.size() && i < trait_win_size_y; i++ ) { @@ -592,11 +915,10 @@ Strength - 4; Dexterity - 4; Intelligence - 4; Perception - 4" ) ); wrefresh( w_traits ); // Next, draw bionics - const std::string title_BIONICS = _( "BIONICS" ); center_print( w_bionics, 0, c_light_gray, title_BIONICS ); trim_and_print( w_bionics, 1, 1, getmaxx( w_bionics ) - 1, c_white, string_format( _( "Bionic Power: %1$d / %2$d" ), - power_level, max_power_level ) ); + you.power_level, you.max_power_level ) ); for( size_t i = 0; i < bionicslist.size() && i < bionics_win_size_y; i++ ) { trim_and_print( w_bionics, static_cast( i ) + 2, 1, getmaxx( w_bionics ) - 1, c_white, bionicslist[i].info().name ); @@ -604,7 +926,6 @@ Strength - 4; Dexterity - 4; Intelligence - 4; Perception - 4" ) ); wrefresh( w_bionics ); // Next, draw effects. - const std::string title_EFFECTS = _( "EFFECTS" ); center_print( w_effects, 0, c_light_gray, title_EFFECTS ); for( size_t i = 0; i < effect_name.size() && i < effect_win_size_y; i++ ) { trim_and_print( w_effects, static_cast( i ) + 1, 0, getmaxx( w_effects ) - 1, c_light_gray, @@ -615,11 +936,10 @@ Strength - 4; Dexterity - 4; Intelligence - 4; Perception - 4" ) ); // Next, draw skills. line = 1; - const std::string title_SKILLS = _( "SKILLS" ); center_print( w_skills, 0, c_light_gray, title_SKILLS ); for( auto &elem : skillslist ) { - const SkillLevel &level = get_skill_level_object( elem->ident() ); + const SkillLevel &level = you.get_skill_level_object( elem->ident() ); // Default to not training and not rusting nc_color text_color = c_blue; @@ -640,7 +960,7 @@ Strength - 4; Dexterity - 4; Intelligence - 4; Perception - 4" ) ); int level_num = level.level(); int exercise = level.exercise(); - if( has_active_bionic( bionic_id( "bio_cqb" ) ) && is_cqb_skill( elem->ident() ) ) { + if( you.has_active_bionic( bionic_id( "bio_cqb" ) ) && is_cqb_skill( elem->ident() ) ) { level_num = 5; exercise = 0; text_color = c_yellow; @@ -651,10 +971,10 @@ Strength - 4; Dexterity - 4; Intelligence - 4; Perception - 4" ) ); if( ( elem )->ident() == skill_id( "dodge" ) ) { mvwprintz( w_skills, line, 14, text_color, "%4.1f/%-2d(%2d%%)", - get_dodge(), level_num, exercise < 0 ? 0 : exercise ); + you.get_dodge(), level_num, exercise < 0 ? 0 : exercise ); } else { mvwprintz( w_skills, line, 19, text_color, "%-2d(%2d%%)", level_num, - ( exercise < 0 ? 0 : exercise ) ); + ( exercise < 0 ? 0 : exercise ) ); } line++; @@ -663,57 +983,56 @@ Strength - 4; Dexterity - 4; Intelligence - 4; Perception - 4" ) ); wrefresh( w_skills ); // Finally, draw speed. - const std::string title_SPEED = _( "SPEED" ); center_print( w_speed, 0, c_light_gray, title_SPEED ); - mvwprintz( w_speed, 1, 1, c_light_gray, _( "Base Move Cost:" ) ); - mvwprintz( w_speed, 2, 1, c_light_gray, _( "Current Speed:" ) ); - int newmoves = get_speed(); + mvwprintz( w_speed, 1, 1, c_light_gray, _( "Base Move Cost:" ) ); + mvwprintz( w_speed, 2, 1, c_light_gray, _( "Current Speed:" ) ); + int newmoves = you.get_speed(); int pen = 0; line = 3; - if( weight_carried() > weight_capacity() ) { - pen = 25 * ( weight_carried() - weight_capacity() ) / ( weight_capacity() ); + if( you.weight_carried() > you.weight_capacity() ) { + pen = 25 * ( you.weight_carried() - you.weight_capacity() ) / ( you.weight_capacity() ); mvwprintz( w_speed, line, 1, c_red, _( "Overburdened -%s%d%%" ), ( pen < 10 ? " " : "" ), pen ); line++; } - pen = get_pain_penalty().speed; + pen = you.get_pain_penalty().speed; if( pen >= 1 ) { mvwprintz( w_speed, line, 1, c_red, _( "Pain -%s%d%%" ), ( pen < 10 ? " " : "" ), pen ); line++; } - if( get_thirst() > 40 ) { - pen = abs( thirst_speed_penalty( get_thirst() ) ); + if( you.get_thirst() > 40 ) { + pen = abs( you.thirst_speed_penalty( you.get_thirst() ) ); mvwprintz( w_speed, line, 1, c_red, _( "Thirst -%s%d%%" ), ( pen < 10 ? " " : "" ), pen ); line++; } - if( kcal_speed_penalty() < 0 ) { - pen = abs( kcal_speed_penalty() ); + if( you.kcal_speed_penalty() < 0 ) { + pen = abs( you.kcal_speed_penalty() ); mvwprintz( w_speed, line, 1, c_red, _( "Starving -%s%d%%" ), ( pen < 10 ? " " : "" ), pen ); line++; } - if( has_trait( trait_id( "SUNLIGHT_DEPENDENT" ) ) && !g->is_in_sunlight( pos() ) ) { - pen = ( g->light_level( posz() ) >= 12 ? 5 : 10 ); + if( you.has_trait( trait_id( "SUNLIGHT_DEPENDENT" ) ) && !g->is_in_sunlight( you.pos() ) ) { + pen = ( g->light_level( you.posz() ) >= 12 ? 5 : 10 ); mvwprintz( w_speed, line, 1, c_red, _( "Out of Sunlight -%s%d%%" ), ( pen < 10 ? " " : "" ), pen ); line++; } /* Cache result of calculation, possibly used multiple times later. */ - const auto player_local_temp = g->weather.get_temperature( pos() ); - if( has_trait( trait_id( "COLDBLOOD4" ) ) && player_local_temp > 65 ) { + const auto player_local_temp = g->weather.get_temperature( you.pos() ); + if( you.has_trait( trait_id( "COLDBLOOD4" ) ) && player_local_temp > 65 ) { pen = ( player_local_temp - 65 ) / 2; mvwprintz( w_speed, line, 1, c_green, _( "Cold-Blooded +%s%d%%" ), ( pen < 10 ? " " : "" ), pen ); line++; } - if( ( has_trait( trait_id( "COLDBLOOD" ) ) || has_trait( trait_id( "COLDBLOOD2" ) ) || - has_trait( trait_id( "COLDBLOOD3" ) ) || has_trait( trait_id( "COLDBLOOD4" ) ) ) && + if( ( you.has_trait( trait_id( "COLDBLOOD" ) ) || you.has_trait( trait_id( "COLDBLOOD2" ) ) || + you.has_trait( trait_id( "COLDBLOOD3" ) ) || you.has_trait( trait_id( "COLDBLOOD4" ) ) ) && player_local_temp < 65 ) { - if( has_trait( trait_id( "COLDBLOOD3" ) ) || has_trait( trait_id( "COLDBLOOD4" ) ) ) { + if( you.has_trait( trait_id( "COLDBLOOD3" ) ) || you.has_trait( trait_id( "COLDBLOOD4" ) ) ) { pen = ( 65 - player_local_temp ) / 2; - } else if( has_trait( trait_id( "COLDBLOOD2" ) ) ) { + } else if( you.has_trait( trait_id( "COLDBLOOD2" ) ) ) { pen = ( 65 - player_local_temp ) / 3; } else { pen = ( 65 - player_local_temp ) / 5; @@ -723,52 +1042,261 @@ Strength - 4; Dexterity - 4; Intelligence - 4; Perception - 4" ) ); line++; } - std::map speed_effects; - for( auto &elem : *effects ) { - for( auto &_effect_it : elem.second ) { - auto &it = _effect_it.second; - bool reduced = resists_effect( it ); - int move_adjust = it.get_mod( "SPEED", reduced ); - if( move_adjust != 0 ) { - const std::string dis_text = it.get_speed_name(); - speed_effects[dis_text] += move_adjust; - } - } - } - - for( auto &speed_effect : speed_effects ) { - nc_color col = ( speed_effect.second > 0 ? c_green : c_red ); - mvwprintz( w_speed, line, 1, col, "%s", speed_effect.first ); - mvwprintz( w_speed, line, 21, col, ( speed_effect.second > 0 ? "+" : "-" ) ); - mvwprintz( w_speed, line, ( abs( speed_effect.second ) >= 10 ? 22 : 23 ), col, "%d%%", - abs( speed_effect.second ) ); - line++; - } - int quick_bonus = static_cast( newmoves - ( newmoves / 1.1 ) ); int bio_speed_bonus = quick_bonus; - if( has_trait( trait_id( "QUICK" ) ) && has_bionic( bionic_id( "bio_speed" ) ) ) { + if( you.has_trait( trait_id( "QUICK" ) ) && you.has_bionic( bionic_id( "bio_speed" ) ) ) { bio_speed_bonus = static_cast( newmoves / 1.1 - ( newmoves / 1.1 / 1.1 ) ); std::swap( quick_bonus, bio_speed_bonus ); } - if( has_trait( trait_id( "QUICK" ) ) ) { + if( you.has_trait( trait_id( "QUICK" ) ) ) { mvwprintz( w_speed, line, 1, c_green, _( "Quick +%s%d%%" ), ( quick_bonus < 10 ? " " : "" ), quick_bonus ); line++; } - if( has_bionic( bionic_id( "bio_speed" ) ) ) { + if( you.has_bionic( bionic_id( "bio_speed" ) ) ) { mvwprintz( w_speed, line, 1, c_green, _( "Bionic Speed +%s%d%%" ), ( bio_speed_bonus < 10 ? " " : "" ), bio_speed_bonus ); } - int runcost = run_cost( 100 ); + int runcost = you.run_cost( 100 ); nc_color col = ( runcost <= 100 ? c_green : c_red ); - mvwprintz( w_speed, 1, ( runcost >= 100 ? 21 : ( runcost < 10 ? 23 : 22 ) ), col, + mvwprintz( w_speed, 1, ( runcost >= 100 ? 21 : ( runcost < 10 ? 23 : 22 ) ), col, "%d", runcost ); col = ( newmoves >= 100 ? c_green : c_red ); mvwprintz( w_speed, 2, ( newmoves >= 100 ? 21 : ( newmoves < 10 ? 23 : 22 ) ), col, "%d", newmoves ); wrefresh( w_speed ); +} + +void player::disp_info() +{ + unsigned int line = 0; + std::vector effect_name; + std::vector effect_text; + for( auto &elem : *effects ) { + for( auto &_effect_it : elem.second ) { + const std::string tmp = _effect_it.second.disp_name(); + if( !tmp.empty() ) { + effect_name.push_back( tmp ); + effect_text.push_back( _effect_it.second.disp_desc() ); + } + } + } + if( get_perceived_pain() > 0 ) { + effect_name.push_back( _( "Pain" ) ); + const auto ppen = get_pain_penalty(); + std::stringstream pain_text; + if( ppen.strength > 0 ) { + pain_text << _( "Strength" ) << " -" << ppen.strength << " "; + } + if( ppen.dexterity > 0 ) { + pain_text << _( "Dexterity" ) << " -" << ppen.dexterity << " "; + } + if( ppen.intelligence > 0 ) { + pain_text << _( "Intelligence" ) << " -" << ppen.intelligence << " "; + } + if( ppen.perception > 0 ) { + pain_text << _( "Perception" ) << " -" << ppen.perception << " "; + } + if( ppen.speed > 0 ) { + pain_text << _( "Speed" ) << " -" << ppen.speed << "% "; + } + effect_text.push_back( pain_text.str() ); + } + + int starvation_base_penalty = get_starvation() + 300; + + if( starvation_base_penalty > 300 ) { + std::stringstream starvation_text; + + if( starvation_base_penalty > 1400 ) { + effect_name.push_back( _( "Severely Malnourished" ) ); + starvation_text << + _( "Your body is severely weakened by starvation. You might die if you don't start eating regular meals!\n \n" ); + } else { + effect_name.push_back( _( "Malnourished" ) ); + starvation_text << + _( "Your body is weakened by starvation. Only time and regular meals will help you recover.\n \n" ); + } + + if( starvation_base_penalty > 500 ) { + starvation_text << _( "Strength" ) << " -" << static_cast( starvation_base_penalty / 500 ) << + " "; + if( starvation_base_penalty > 1000 ) { + starvation_text << _( "Dexterity" ) << " -" << static_cast( starvation_base_penalty / 1000 ) << + " "; + starvation_text << _( "Intelligence" ) << " -" << static_cast( starvation_base_penalty / 1000 ) + << " "; + } + } + + effect_text.push_back( starvation_text.str() ); + } + + if( ( has_trait( trait_id( "TROGLO" ) ) && g->is_in_sunlight( pos() ) && + g->weather.weather == WEATHER_SUNNY ) || + ( has_trait( trait_id( "TROGLO2" ) ) && g->is_in_sunlight( pos() ) && + g->weather.weather != WEATHER_SUNNY ) ) { + effect_name.push_back( _( "In Sunlight" ) ); + effect_text.push_back( _( "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.push_back( _( "In Sunlight" ) ); + effect_text.push_back( _( "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.push_back( _( "In Sunlight" ) ); + effect_text.push_back( _( "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.push_back( addiction_name( elem ) ); + effect_text.push_back( addiction_text( elem ) ); + } + } + + unsigned int maxy = static_cast( TERMY ); + + unsigned int effect_win_size_y = 1 + static_cast( effect_name.size() ); + + std::vector traitslist = get_mutations( false ); + unsigned int trait_win_size_y = 1 + static_cast( traitslist.size() ); + + std::vector bionicslist = *my_bionics; + unsigned int bionics_win_size_y = 2 + bionicslist.size(); + + const std::vector skillslist = Skill::get_skills_sorted_by( [&]( const Skill & a, + const Skill & b ) { + const int level_a = get_skill_level_object( a.ident() ).exercised_level(); + const int level_b = get_skill_level_object( b.ident() ).exercised_level(); + return level_a > level_b || ( level_a == level_b && a.name() < b.name() ); + } ); + unsigned int skill_win_size_y = 1 + skillslist.size(); + unsigned int info_win_size_y = 6; + + unsigned int infooffsetytop = 11; + unsigned int infooffsetybottom = infooffsetytop + 1 + info_win_size_y; + + if( ( bionics_win_size_y + trait_win_size_y + infooffsetybottom ) > maxy ) { + // maximum space for either window if they're both the same size + unsigned max_shared_y = ( maxy - infooffsetybottom ) / 2; + // both are larger than the shared size + if( std::min( bionics_win_size_y, trait_win_size_y ) > max_shared_y ) { + bionics_win_size_y = max_shared_y; + // trait window is less than the shared size, so give space to bionics + } else if( trait_win_size_y <= max_shared_y ) { + bionics_win_size_y = maxy - infooffsetybottom - trait_win_size_y; + } + // fall through if bionics is smaller + trait_win_size_y = maxy - infooffsetybottom - bionics_win_size_y; + } + + if( skill_win_size_y + infooffsetybottom > maxy ) { + skill_win_size_y = maxy - infooffsetybottom; + } + + catacurses::window w_grid_top = catacurses::newwin( infooffsetybottom, FULL_SCREEN_WIDTH + 1, + VIEW_OFFSET_Y, VIEW_OFFSET_X ); + catacurses::window w_grid_skill = catacurses::newwin( skill_win_size_y + 1, 27, + infooffsetybottom + VIEW_OFFSET_Y, 0 + VIEW_OFFSET_X ); + catacurses::window w_grid_trait = catacurses::newwin( trait_win_size_y + 1, 27, + infooffsetybottom + VIEW_OFFSET_Y, 27 + VIEW_OFFSET_X ); + catacurses::window w_grid_bionics = catacurses::newwin( bionics_win_size_y + 1, 27, + infooffsetybottom + VIEW_OFFSET_Y + trait_win_size_y + 1, + 27 + VIEW_OFFSET_X ); + catacurses::window w_grid_effect = catacurses::newwin( effect_win_size_y + 1, 28, + infooffsetybottom + VIEW_OFFSET_Y, 53 + VIEW_OFFSET_X ); + + catacurses::window w_tip = catacurses::newwin( 1, FULL_SCREEN_WIDTH, VIEW_OFFSET_Y, + 0 + VIEW_OFFSET_X ); + catacurses::window w_stats = catacurses::newwin( 9, 26, 1 + VIEW_OFFSET_Y, 0 + VIEW_OFFSET_X ); + catacurses::window w_traits = catacurses::newwin( trait_win_size_y, 26, + infooffsetybottom + VIEW_OFFSET_Y, 27 + VIEW_OFFSET_X ); + catacurses::window w_bionics = catacurses::newwin( bionics_win_size_y, 26, + infooffsetybottom + VIEW_OFFSET_Y + trait_win_size_y + 1, + 27 + VIEW_OFFSET_X ); + catacurses::window w_encumb = catacurses::newwin( 9, 26, 1 + VIEW_OFFSET_Y, 27 + VIEW_OFFSET_X ); + catacurses::window w_effects = catacurses::newwin( effect_win_size_y, 26, + infooffsetybottom + VIEW_OFFSET_Y, 54 + VIEW_OFFSET_X ); + catacurses::window w_speed = catacurses::newwin( 9, 26, 1 + VIEW_OFFSET_Y, 54 + VIEW_OFFSET_X ); + catacurses::window w_skills = catacurses::newwin( skill_win_size_y, 26, + infooffsetybottom + VIEW_OFFSET_Y, 0 + VIEW_OFFSET_X ); + catacurses::window w_info = catacurses::newwin( info_win_size_y, FULL_SCREEN_WIDTH, + infooffsetytop + VIEW_OFFSET_Y, 0 + VIEW_OFFSET_X ); + + draw_grid_borders( w_grid_top, w_grid_skill, w_grid_trait, w_grid_bionics, w_grid_effect, + info_win_size_y, infooffsetybottom, skill_win_size_y, trait_win_size_y, bionics_win_size_y, + effect_win_size_y ); + //-1 for header + trait_win_size_y--; + bionics_win_size_y--; + skill_win_size_y--; + effect_win_size_y--; + + // Print name and header + // Post-humanity trumps your pre-Cataclysm life. + if( crossed_threshold() ) { + std::string race; + for( auto &mut : my_mutations ) { + const auto &mdata = mut.first.obj(); + if( mdata.threshold ) { + race = mdata.name(); + break; + } + } + //~ player info window: 1s - name, 2s - gender, 3s - Prof or Mutation name + mvwprintw( w_tip, 0, 0, _( "%1$s | %2$s | %3$s" ), name, male ? _( "Male" ) : _( "Female" ), race ); + } else if( prof == nullptr || prof == prof->generic() ) { + // Regular person. Nothing interesting. + //~ player info window: 1s - name, 2s - gender, '|' - field separator. + mvwprintw( w_tip, 0, 0, _( "%1$s | %2$s" ), name, male ? _( "Male" ) : _( "Female" ) ); + } else { + mvwprintw( w_tip, 0, 0, _( "%1$s | %2$s | %3$s" ), name, + male ? _( "Male" ) : _( "Female" ), prof->gender_appropriate_name( male ) ); + } + + input_context ctxt( "PLAYER_INFO" ); + ctxt.register_updown(); + ctxt.register_action( "NEXT_TAB", _( "Cycle to next category" ) ); + ctxt.register_action( "PREV_TAB", _( "Cycle to previous category" ) ); + ctxt.register_action( "QUIT" ); + ctxt.register_action( "CONFIRM", _( "Toggle skill training" ) ); + ctxt.register_action( "HELP_KEYBINDINGS" ); + std::string action; + + std::string help_msg = string_format( _( "Press %s for help." ), + ctxt.get_desc( "HELP_KEYBINDINGS" ) ); + mvwprintz( w_tip, 0, FULL_SCREEN_WIDTH - utf8_width( help_msg ), c_light_red, help_msg ); + help_msg.clear(); + wrefresh( w_tip ); + + draw_initial_windows( w_stats, w_encumb, w_traits, w_bionics, w_effects, w_skills, w_speed, *this, + line, traitslist, bionicslist, effect_name, skillslist, bionics_win_size_y, effect_win_size_y, + trait_win_size_y, skill_win_size_y ); + + std::map speed_effects; + for( auto &elem : *effects ) { + for( std::pair &_effect_it : elem.second ) { + effect &it = _effect_it.second; + bool reduced = resists_effect( it ); + int move_adjust = it.get_mod( "SPEED", reduced ); + if( move_adjust != 0 ) { + const std::string dis_text = it.get_speed_name(); + speed_effects[dis_text] += move_adjust; + } + } + } + + for( std::pair &speed_effect : speed_effects ) { + nc_color col = ( speed_effect.second > 0 ? c_green : c_red ); + mvwprintz( w_speed, line, 1, col, "%s", speed_effect.first ); + mvwprintz( w_speed, line, 21, col, ( speed_effect.second > 0 ? "+" : "-" ) ); + mvwprintz( w_speed, line, ( abs( speed_effect.second ) >= 10 ? 22 : 23 ), col, "%d%%", + abs( speed_effect.second ) ); + line++; + } catacurses::refresh(); @@ -785,474 +1313,31 @@ Strength - 4; Dexterity - 4; Intelligence - 4; Perception - 4" ) ); werase( w_info ); switch( curtab ) { case 1: // Stats tab - mvwprintz( w_stats, 0, 0, h_light_gray, header_spaces ); - center_print( w_stats, 0, h_light_gray, title_STATS ); - - // Clear bonus/penalty menu. - mvwprintz( w_stats, 7, 0, c_light_gray, "%26s", "" ); - mvwprintz( w_stats, 8, 0, c_light_gray, "%26s", "" ); - - if( line == 0 ) { - // Display information on player strength in appropriate window - mvwprintz( w_stats, 2, 1, h_light_gray, _( "Strength:" ) ); - fold_and_print( w_info, 0, 1, FULL_SCREEN_WIDTH - 2, c_magenta, - _( "Strength affects your melee damage, the amount of weight you can carry, your total HP, " - "your resistance to many diseases, and the effectiveness of actions which require brute force." ) ); - mvwprintz( w_info, 3, 1, c_magenta, _( "Base HP:" ) ); - mvwprintz( w_info, 3, 22, c_magenta, "%3d", hp_max[1] ); - if( get_option( "USE_METRIC_WEIGHTS" ) == "kg" ) { - mvwprintz( w_info, 4, 1, c_magenta, _( "Carry weight(kg):" ) ); - } else { - mvwprintz( w_info, 4, 1, c_magenta, _( "Carry weight(lbs):" ) ); - } - mvwprintz( w_info, 4, 21, c_magenta, "%4.1f", convert_weight( weight_capacity() ) ); - mvwprintz( w_info, 5, 1, c_magenta, _( "Melee damage:" ) ); - mvwprintz( w_info, 5, 22, c_magenta, "%3.1f", bonus_damage( false ) ); - - } else if( line == 1 ) { - // Display information on player dexterity in appropriate window - mvwprintz( w_stats, 3, 1, h_light_gray, _( "Dexterity:" ) ); - fold_and_print( w_info, 0, 1, FULL_SCREEN_WIDTH - 2, c_magenta, - _( "Dexterity affects your chance to hit in melee combat, helps you steady your " - "gun for ranged combat, and enhances many actions that require finesse." ) ); - mvwprintz( w_info, 3, 1, c_magenta, _( "Melee to-hit bonus:" ) ); - mvwprintz( w_info, 3, 38, c_magenta, "%+.1lf", get_hit_base() ); - mvwprintz( w_info, 4, 1, c_magenta, _( "Ranged penalty:" ) ); - mvwprintz( w_info, 4, 38, c_magenta, "%+3d", -( abs( ranged_dex_mod() ) ) ); - mvwprintz( w_info, 5, 1, c_magenta, _( "Throwing penalty per target's dodge:" ) ); - mvwprintz( w_info, 5, 38, c_magenta, "%+3d", throw_dispersion_per_dodge( false ) ); - } else if( line == 2 ) { - // Display information on player intelligence in appropriate window - mvwprintz( w_stats, 4, 1, h_light_gray, _( "Intelligence:" ) ); - fold_and_print( w_info, 0, 1, FULL_SCREEN_WIDTH - 2, c_magenta, - _( "Intelligence is less important in most situations, but it is vital for more complex tasks like " - "electronics crafting. It also affects how much skill you can pick up from reading a book." ) ); - mvwprintz( w_info, 3, 1, c_magenta, _( "Read times:" ) ); - mvwprintz( w_info, 3, 21, c_magenta, "%3d%%", read_speed( false ) ); - mvwprintz( w_info, 4, 1, c_magenta, _( "Skill rust:" ) ); - mvwprintz( w_info, 4, 22, c_magenta, "%2d%%", rust_rate( false ) ); - mvwprintz( w_info, 5, 1, c_magenta, _( "Crafting bonus:" ) ); - mvwprintz( w_info, 5, 22, c_magenta, "%2d%%", get_int() ); - } else if( line == 3 ) { - // Display information on player perception in appropriate window - mvwprintz( w_stats, 5, 1, h_light_gray, _( "Perception:" ) ); - fold_and_print( w_info, 0, 1, FULL_SCREEN_WIDTH - 2, c_magenta, - _( "Perception is the most important stat for ranged combat. It's also used for " - "detecting traps and other things of interest." ) ); - mvwprintz( w_info, 4, 1, c_magenta, _( "Trap detection level:" ) ); - mvwprintz( w_info, 4, 23, c_magenta, "%2d", get_per() ); - if( ranged_per_mod() > 0 ) { - mvwprintz( w_info, 5, 1, c_magenta, _( "Aiming penalty:" ) ); - mvwprintz( w_info, 5, 21, c_magenta, "%+4d", -ranged_per_mod() ); - } - } else if( line == 4 ) { - mvwprintz( w_stats, 6, 1, h_light_gray, _( "Weight:" ) ); - mvwprintz( w_stats, 6, 25 - get_weight_string().size(), h_light_gray, get_weight_string() ); - const int lines = fold_and_print( w_info, 0, 1, FULL_SCREEN_WIDTH - 2, c_magenta, - _( "Your weight is a general indicator of how much fat your body has stored up," - " which in turn shows how prepared you are to survive for a time without food." - "Having too much, or too little, can be unhealthy." ) ); - fold_and_print( w_info, 1 + lines, 1, FULL_SCREEN_WIDTH - 2, c_magenta, get_weight_description() ); - } - wrefresh( w_stats ); - wrefresh( w_info ); - - action = ctxt.handle_input(); - if( action == "DOWN" ) { - line++; - if( line == 5 ) { - line = 0; - } - } else if( action == "UP" ) { - if( line == 0 ) { - line = 4; - } else { - line--; - } - } else if( action == "NEXT_TAB" || action == "PREV_TAB" ) { - mvwprintz( w_stats, 0, 0, c_light_gray, header_spaces ); - center_print( w_stats, 0, c_light_gray, title_STATS ); - wrefresh( w_stats ); - line = 0; - curtab = action == "NEXT_TAB" ? curtab + 1 : 6; - } else if( action == "QUIT" ) { - done = true; - } - mvwprintz( w_stats, 2, 1, c_light_gray, _( "Strength:" ) ); - mvwprintz( w_stats, 3, 1, c_light_gray, _( "Dexterity:" ) ); - mvwprintz( w_stats, 4, 1, c_light_gray, _( "Intelligence:" ) ); - mvwprintz( w_stats, 5, 1, c_light_gray, _( "Perception:" ) ); - mvwprintz( w_stats, 6, 1, c_light_gray, _( "Weight:" ) ); - mvwprintz( w_stats, 6, 25 - get_weight_string().size(), c_light_gray, get_weight_string() ); - wrefresh( w_stats ); + draw_stats_tab( w_stats, w_info, *this, line, curtab, ctxt, done, action ); break; case 2: { // Encumbrance tab - werase( w_encumb ); - center_print( w_encumb, 0, h_light_gray, title_ENCUMB ); - print_encumbrance( w_encumb, line ); - wrefresh( w_encumb ); - - werase( w_info ); - std::string s; - - body_part bp = line <= 11 ? all_body_parts[line] : num_bp; - bool combined_here = ( bp_aiOther[line] == line + 1 || - bp_aiOther[line] == line - 1 ) && // first of a pair - should_combine_bps( *this, line, bp_aiOther[line] ); - s += get_encumbrance_description( *this, bp, combined_here ); - fold_and_print( w_info, 0, 1, FULL_SCREEN_WIDTH - 2, c_magenta, s ); - wrefresh( w_info ); - - action = ctxt.handle_input(); - if( action == "DOWN" ) { - if( line < num_bp - 1 ) { - if( combined_here ) { - line += ( line < num_bp - 2 ) ? 2 : 0; // skip a line if we aren't at the last pair - } else { - line++; // unpaired or unequal - } - } - } else if( action == "UP" ) { - if( line > 0 ) { - if( bp_aiOther[line] == line - 1 && // second of a pair - should_combine_bps( *this, line, bp_aiOther[line] ) ) { - line -= ( line > 1 ) ? 2 : 0; // skip a line if we aren't at the first pair - } else { - line--; // unpaired or unequal - } - } - } else if( action == "NEXT_TAB" || action == "PREV_TAB" ) { - mvwprintz( w_encumb, 0, 0, c_light_gray, header_spaces ); - center_print( w_encumb, 0, c_light_gray, title_ENCUMB ); - wrefresh( w_encumb ); - line = 0; - curtab = action == "NEXT_TAB" ? curtab + 1 : curtab - 1; - } else if( action == "QUIT" ) { - done = true; - } + draw_encumbrance_tab( w_encumb, w_info, *this, line, curtab, ctxt, done, action ); break; } case 4: // Traits tab - werase( w_traits ); - mvwprintz( w_traits, 0, 0, h_light_gray, header_spaces ); - center_print( w_traits, 0, h_light_gray, title_TRAITS ); - if( line <= ( trait_win_size_y - 1 ) / 2 ) { - min = 0; - max = trait_win_size_y; - if( traitslist.size() < max ) { - max = traitslist.size(); - } - } else if( line >= traitslist.size() - ( trait_win_size_y + 1 ) / 2 ) { - min = ( traitslist.size() < trait_win_size_y ? 0 : traitslist.size() - trait_win_size_y ); - max = traitslist.size(); - } else { - min = line - ( trait_win_size_y - 1 ) / 2; - max = line + trait_win_size_y / 2 + 1; - if( traitslist.size() < max ) { - max = traitslist.size(); - } - } - - for( size_t i = min; i < max; i++ ) { - const auto &mdata = traitslist[i].obj(); - const auto color = mdata.get_display_color(); - trim_and_print( w_traits, static_cast( 1 + i - min ), 1, getmaxx( w_traits ) - 1, - i == line ? hilite( color ) : color, mdata.name() ); - } - if( line < traitslist.size() ) { - const auto &mdata = traitslist[line].obj(); - fold_and_print( w_info, 0, 1, FULL_SCREEN_WIDTH - 2, c_magenta, string_format( - "%s: %s", string_from_color( mdata.get_display_color() ), - mdata.name(), traitslist[line]->desc() ) ); - } - wrefresh( w_traits ); - wrefresh( w_info ); - - action = ctxt.handle_input(); - if( action == "DOWN" ) { - if( line < traitslist.size() - 1 ) { - line++; - } - break; - } else if( action == "UP" ) { - if( line > 0 ) { - line--; - } - } else if( action == "NEXT_TAB" || action == "PREV_TAB" ) { - mvwprintz( w_traits, 0, 0, c_light_gray, header_spaces ); - center_print( w_traits, 0, c_light_gray, title_TRAITS ); - for( size_t i = 0; i < traitslist.size() && i < trait_win_size_y; i++ ) { - const auto &mdata = traitslist[i].obj(); - mvwprintz( w_traits, static_cast( i + 1 ), 1, c_black, " " ); - const auto color = mdata.get_display_color(); - trim_and_print( w_traits, static_cast( i + 1 ), 1, getmaxx( w_traits ) - 1, - color, mdata.name() ); - } - wrefresh( w_traits ); - line = 0; - curtab = action == "NEXT_TAB" ? curtab + 1 : curtab - 1; - } else if( action == "QUIT" ) { - done = true; - } + draw_traits_tab( w_traits, w_info, line, curtab, ctxt, done, action, traitslist, + min, max ); break; case 5: // Bionics tab - werase( w_bionics ); - mvwprintz( w_bionics, 0, 0, h_light_gray, header_spaces ); - center_print( w_bionics, 0, h_light_gray, title_BIONICS ); - trim_and_print( w_bionics, 1, 1, getmaxx( w_bionics ) - 1, c_white, - string_format( _( "Bionic Power: %1$d" ), max_power_level ) ); - - if( line <= ( ( bionics_useful_size_y - 1 ) / 2 ) ) { - min = 0; - max = std::min( bionicslist.size(), bionics_useful_size_y ); - } else if( line >= ( bionicslist.size() - ( bionics_useful_size_y + 1 ) / 2 ) ) { - min = ( bionicslist.size() < bionics_useful_size_y ? 0 : bionicslist.size() - bionics_useful_size_y - + 1 ); - max = bionicslist.size(); - } else { - min = line - ( bionics_useful_size_y - 1 ) / 2; - max = std::min( bionicslist.size(), static_cast( 1 + line + bionics_useful_size_y / 2 ) ); - } - - for( size_t i = min; i < max; i++ ) { - trim_and_print( w_bionics, static_cast( 2 + i - min ), 1, getmaxx( w_bionics ) - 1, - i == line ? hilite( c_white ) : c_white, bionicslist[i].info().name ); - } - if( line < bionicslist.size() ) { - fold_and_print( w_info, 0, 1, FULL_SCREEN_WIDTH - 2, c_white, - bionicslist[line].info().description ); - } - wrefresh( w_bionics ); - wrefresh( w_info ); - - action = ctxt.handle_input(); - if( action == "DOWN" ) { - if( line < bionicslist.size() - 1 ) { - line++; - } - break; - } else if( action == "UP" ) { - if( line > 0 ) { - line--; - } - } else if( action == "NEXT_TAB" || action == "PREV_TAB" ) { - mvwprintz( w_bionics, 0, 0, c_light_gray, header_spaces ); - center_print( w_bionics, 0, c_light_gray, title_BIONICS ); - trim_and_print( w_bionics, 1, 1, getmaxx( w_bionics ) - 1, c_white, - string_format( _( "Bionic Power: %1$d" ), max_power_level ) ); - for( size_t i = 0; i < bionicslist.size() && i < bionics_win_size_y; i++ ) { - mvwprintz( w_bionics, static_cast( i + 2 ), 1, c_black, " " ); - trim_and_print( w_bionics, static_cast( i + 2 ), 1, getmaxx( w_bionics ) - 1, - c_white, bionicslist[i].info().name ); - } - wrefresh( w_bionics ); - line = 0; - curtab = action == "NEXT_TAB" ? curtab + 1 : curtab - 1; - } else if( action == "QUIT" ) { - done = true; - } + draw_bionics_tab( w_bionics, w_info, *this, line, curtab, ctxt, done, action, + bionicslist, min, max, bionics_useful_size_y, bionics_win_size_y ); break; case 6: // Effects tab - mvwprintz( w_effects, 0, 0, h_light_gray, header_spaces ); - center_print( w_effects, 0, h_light_gray, title_EFFECTS ); - half_y = effect_win_size_y / 2; - if( line <= half_y ) { - min = 0; - max = effect_win_size_y; - if( effect_name.size() < max ) { - max = effect_name.size(); - } - } else if( line >= effect_name.size() - half_y ) { - min = ( effect_name.size() < effect_win_size_y ? 0 : effect_name.size() - effect_win_size_y ); - max = effect_name.size(); - } else { - min = line - half_y; - max = line - half_y + effect_win_size_y; - if( effect_name.size() < max ) { - max = effect_name.size(); - } - } - - for( size_t i = min; i < max; i++ ) { - trim_and_print( w_effects, static_cast( 1 + i - min ), 0, getmaxx( w_effects ) - 1, - i == line ? h_light_gray : c_light_gray, effect_name[i] ); - } - if( line < effect_text.size() ) { - fold_and_print( w_info, 0, 1, FULL_SCREEN_WIDTH - 2, c_magenta, effect_text[line] ); - } - wrefresh( w_effects ); - wrefresh( w_info ); - - action = ctxt.handle_input(); - if( action == "DOWN" ) { - if( line < effect_name.size() - 1 ) { - line++; - } - break; - } else if( action == "UP" ) { - if( line > 0 ) { - line--; - } - } else if( action == "NEXT_TAB" || action == "PREV_TAB" ) { - mvwprintz( w_effects, 0, 0, c_light_gray, header_spaces ); - center_print( w_effects, 0, c_light_gray, title_EFFECTS ); - for( size_t i = 0; i < effect_name.size() && i < 7; i++ ) { - trim_and_print( w_effects, static_cast( i ) + 1, 0, getmaxx( w_effects ) - 1, c_light_gray, - effect_name[i] ); - } - wrefresh( w_effects ); - line = 0; - curtab = action == "NEXT_TAB" ? 1 : curtab - 1; - } else if( action == "QUIT" ) { - done = true; - } + draw_effects_tab( w_effects, w_info, line, curtab, ctxt, done, action, + effect_name, min, max, effect_win_size_y, effect_text, half_y ); break; case 3: // Skills tab - mvwprintz( w_skills, 0, 0, h_light_gray, header_spaces ); - center_print( w_skills, 0, h_light_gray, title_SKILLS ); - half_y = skill_win_size_y / 2; - if( line <= half_y ) { - min = 0; - max = skill_win_size_y; - if( skillslist.size() < max ) { - max = skillslist.size(); - } - } else if( line >= skillslist.size() - half_y ) { - min = ( skillslist.size() < static_cast( skill_win_size_y ) ? 0 : skillslist.size() - - skill_win_size_y ); - max = skillslist.size(); - } else { - min = line - half_y; - max = line - half_y + skill_win_size_y; - if( skillslist.size() < max ) { - max = skillslist.size(); - } - } - - const Skill *selectedSkill = nullptr; - - for( size_t i = min; i < max; i++ ) { - const Skill *aSkill = skillslist[i]; - const SkillLevel &level = get_skill_level_object( aSkill->ident() ); - - const bool can_train = level.can_train(); - const bool training = level.isTraining(); - const bool rusting = level.isRusting(); - int exercise = level.exercise(); - int level_num = level.level(); - bool locked = false; - if( has_active_bionic( bionic_id( "bio_cqb" ) ) && is_cqb_skill( aSkill->ident() ) ) { - level_num = 5; - exercise = 0; - locked = true; - } - nc_color cstatus; - if( i == line ) { - selectedSkill = aSkill; - if( locked ) { - cstatus = h_yellow; - } else if( !can_train ) { - cstatus = rusting ? h_light_red : h_white; - } else if( exercise >= 100 ) { - cstatus = training ? h_pink : h_magenta; - } else if( rusting ) { - cstatus = training ? h_light_red : h_red; - } else { - cstatus = training ? h_light_blue : h_blue; - } - } else { - if( locked ) { - cstatus = c_yellow; - } else if( rusting ) { - cstatus = training ? c_light_red : c_red; - } else if( !can_train ) { - cstatus = c_white; - } else { - cstatus = training ? c_light_blue : c_blue; - } - } - mvwprintz( w_skills, static_cast( 1 + i - min ), 1, c_light_gray, - " " ); - mvwprintz( w_skills, static_cast( 1 + i - min ), 1, cstatus, "%s:", aSkill->name() ); - - if( aSkill->ident() == skill_id( "dodge" ) ) { - mvwprintz( w_skills, static_cast( 1 + i - min ), 14, cstatus, "%4.1f/%-2d(%2d%%)", - get_dodge(), level_num, exercise < 0 ? 0 : exercise ); - } else { - mvwprintz( w_skills, static_cast( 1 + i - min ), 19, cstatus, "%-2d(%2d%%)", level_num, - ( exercise < 0 ? 0 : exercise ) ); - } - } - - draw_scrollbar( w_skills, line, skill_win_size_y, static_cast( skillslist.size() ), 1 ); - wrefresh( w_skills ); - - werase( w_info ); - - if( line < skillslist.size() ) { - fold_and_print( w_info, 0, 1, FULL_SCREEN_WIDTH - 2, c_magenta, selectedSkill->description() ); - } - wrefresh( w_info ); - - action = ctxt.handle_input(); - if( action == "DOWN" ) { - if( static_cast( line ) < skillslist.size() - 1 ) { - line++; - } - } else if( action == "UP" ) { - if( line > 0 ) { - line--; - } - } else if( action == "NEXT_TAB" || action == "PREV_TAB" ) { - werase( w_skills ); - mvwprintz( w_skills, 0, 0, c_light_gray, header_spaces ); - center_print( w_skills, 0, c_light_gray, title_SKILLS ); - for( size_t i = 0; i < skillslist.size() && i < static_cast( skill_win_size_y ); i++ ) { - const Skill *thisSkill = skillslist[i]; - const SkillLevel &level = get_skill_level_object( thisSkill->ident() ); - bool can_train = level.can_train(); - bool isLearning = level.isTraining(); - bool rusting = level.isRusting(); - int level_num = level.level(); - int exercise = level.exercise(); - bool locked = false; - if( has_active_bionic( bionic_id( "bio_cqb" ) ) && is_cqb_skill( thisSkill->ident() ) ) { - level_num = 5; - exercise = 0; - locked = true; - } - nc_color cstatus; - if( locked ) { - cstatus = c_yellow; - } else if( rusting ) { - cstatus = isLearning ? c_light_red : c_red; - } else if( !can_train ) { - cstatus = c_white; - } else { - cstatus = isLearning ? c_light_blue : c_blue; - } - - mvwprintz( w_skills, i + 1, 1, cstatus, "%s:", thisSkill->name() ); - - if( thisSkill->ident() == skill_id( "dodge" ) ) { - mvwprintz( w_skills, i + 1, 14, cstatus, "%4.1f/%-2d(%2d%%)", - get_dodge(), level_num, exercise < 0 ? 0 : exercise ); - } else { - mvwprintz( w_skills, i + 1, 19, cstatus, "%-2d(%2d%%)", level_num, - ( exercise < 0 ? 0 : exercise ) ); - } - } - wrefresh( w_skills ); - line = 0; - curtab = action == "NEXT_TAB" ? curtab + 1 : curtab - 1; - } else if( action == "CONFIRM" ) { - get_skill_level_object( selectedSkill->ident() ).toggleTraining(); - } else if( action == "QUIT" ) { - done = true; - } + draw_skills_tab( w_skills, w_info, *this, line, curtab, ctxt, done, action, + skillslist, min, max, skill_win_size_y, half_y ); + } } while( !done ); diff --git a/src/recipe.cpp b/src/recipe.cpp index 5ef561193f692..6065491069fc3 100644 --- a/src/recipe.cpp +++ b/src/recipe.cpp @@ -15,7 +15,9 @@ #include "assign.h" #include "cata_utility.h" #include "character.h" +#include "construction.h" #include "json.h" +#include "mapgen_functions.h" #include "optional.h" #include "player.h" #include "translations.h" @@ -255,6 +257,7 @@ void recipe::load( JsonObject &jo, const std::string &src ) bp_excludes.emplace_back( std::make_pair( exclude.get_string( "id" ), exclude.get_int( "amount", 1 ) ) ); } + assign( jo, "blueprint_autocalc", bp_autocalc ); } } else if( type == "uncraft" ) { reversible = true; @@ -270,6 +273,9 @@ void recipe::load( JsonObject &jo, const std::string &src ) void recipe::finalize() { + if( bp_autocalc ) { + add_bp_autocalc_requirements(); + } // concatenate both external and inline requirements add_requirements( reqs_external ); add_requirements( reqs_internal ); @@ -277,6 +283,10 @@ void recipe::finalize() reqs_external.clear(); reqs_internal.clear(); + if( bp_autocalc ) { + requirements_.consolidate(); + } + if( contained && container == "null" ) { container = item::find_type( result_ )->default_container.value_or( "null" ); } @@ -548,6 +558,24 @@ const std::vector> &recipe::blueprint_excludes() co return bp_excludes; } +void recipe::add_bp_autocalc_requirements() +{ + build_reqs total_reqs; + get_build_reqs_for_furn_ter_ids( get_changed_ids_from_update( blueprint ), total_reqs ); + time = total_reqs.time; + for( const auto &skill_data : total_reqs.skills ) { + if( required_skills.find( skill_data.first ) == required_skills.end() ) { + required_skills[skill_data.first] = skill_data.second; + } else { + required_skills[skill_data.first] = std::max( skill_data.second, + required_skills[skill_data.first] ); + } + } + for( const auto &req : total_reqs.reqs ) { + reqs_internal.emplace_back( std::make_pair( req.first, req.second ) ); + } +} + bool recipe::hot_result() const { // Check if the recipe tools make this food item hot upon making it. diff --git a/src/recipe.h b/src/recipe.h index 60c9192a39ede..0dea0a4e14f8f 100644 --- a/src/recipe.h +++ b/src/recipe.h @@ -127,6 +127,11 @@ class recipe const std::vector> &blueprint_provides() const; const std::vector> &blueprint_requires() const; const std::vector> &blueprint_excludes() const; + /** Retrieves a map of changed ter_id/furn_id to the number of tiles changed, then + * converts that to requirement_ids and counts. The requirements later need to be + * consolidated and duplicate tools/qualities eliminated. + */ + void add_bp_autocalc_requirements(); bool hot_result() const; @@ -176,6 +181,7 @@ class recipe std::vector> bp_provides; std::vector> bp_requires; std::vector> bp_excludes; + bool bp_autocalc = false; }; #endif // RECIPE_H diff --git a/src/requirements.cpp b/src/requirements.cpp index d9612cc89d650..8397cb114191d 100644 --- a/src/requirements.cpp +++ b/src/requirements.cpp @@ -1020,3 +1020,92 @@ requirement_data requirement_data::continue_requirements( const std::vector all_quals; + for( const std::vector &qual_vector : qualities ) { + for( const quality_requirement &qual_data : qual_vector ) { + if( all_quals.find( qual_data.type ) == all_quals.end() ) { + all_quals[qual_data.type] = qual_data; + } else { + all_quals[qual_data.type].count = std::max( all_quals[qual_data.type].count, + qual_data.count ); + all_quals[qual_data.type].level = std::max( all_quals[qual_data.type].level, + qual_data.level ); + } + } + } + qualities.clear(); + std::transform( all_quals.begin(), all_quals.end(), std::back_inserter( qualities ), + []( auto & qual_data ) { + return std::vector( { qual_data.second } ); + } ); + + // elegance? I've heard of it + std::vector> all_tools; + for( const std::vector &old_tool_vector : tools ) { + bool match = false; + for( std::vector &con_tool_vector : all_tools ) { + size_t need_matches = con_tool_vector.size(); + size_t has_matches = 0; + for( const tool_comp &old_tool : old_tool_vector ) { + for( const tool_comp &con_tool : con_tool_vector ) { + if( old_tool.type == con_tool.type ) { + has_matches += 1; + break; + } + } + } + if( has_matches == need_matches ) { + match = true; + for( const tool_comp &old_tool : old_tool_vector ) { + for( tool_comp &con_tool : con_tool_vector ) { + if( old_tool.type == con_tool.type ) { + con_tool.count += old_tool.count; + break; + } + } + } + break; + } + } + if( !match ) { + all_tools.emplace_back( old_tool_vector ); + } + } + tools = std::move( all_tools ); + + std::vector> all_comps; + for( const std::vector &old_item_vector : components ) { + bool match = false; + for( auto &con_item_vector : all_comps ) { + size_t need_matches = con_item_vector.size(); + size_t has_matches = 0; + for( const item_comp &old_item : old_item_vector ) { + for( const item_comp &con_item : con_item_vector ) { + if( old_item.type == con_item.type ) { + has_matches += 1; + break; + } + } + } + if( has_matches == need_matches ) { + match = true; + for( const item_comp &old_item : old_item_vector ) { + for( item_comp &con_item : con_item_vector ) { + if( old_item.type == con_item.type ) { + con_item.count += old_item.count; + break; + } + } + } + break; + } + } + if( !match ) { + all_comps.emplace_back( old_item_vector ); + } + } + components = std::move( all_comps ); +} diff --git a/src/requirements.h b/src/requirements.h index d913b42151223..916bfa6cb0d80 100644 --- a/src/requirements.h +++ b/src/requirements.h @@ -277,6 +277,11 @@ struct requirement_data { static requirement_data continue_requirements( const std::vector &required_comps, const std::list &remaining_comps ); + /** + * Removes duplicated qualities and tools + */ + void consolidate(); + private: requirement_id id_ = requirement_id::NULL_ID(); diff --git a/src/sounds.cpp b/src/sounds.cpp index 72ad0372ffb85..38060476b9680 100644 --- a/src/sounds.cpp +++ b/src/sounds.cpp @@ -211,7 +211,7 @@ static int get_signal_for_hordes( const centroid ¢r ) { //Volume in tiles. Signal for hordes in submaps //modify vol using weather vol.Weather can reduce monster hearing - const int vol = centr.volume - weather_data( g->weather.weather ).sound_attn; + const int vol = centr.volume - weather::sound_attn( g->weather.weather ); const int min_vol_cap = 60; //Hordes can't hear volume lower than this const int underground_div = 2; //Coefficient for volume reduction underground const int hordes_sig_div = SEEX; //Divider coefficient for hordes @@ -235,7 +235,7 @@ static int get_signal_for_hordes( const centroid ¢r ) void sounds::process_sounds() { std::vector sound_clusters = cluster_sounds( recent_sounds ); - const int weather_vol = weather_data( g->weather.weather ).sound_attn; + const int weather_vol = weather::sound_attn( g->weather.weather ); for( const auto &this_centroid : sound_clusters ) { // Since monsters don't go deaf ATM we can just use the weather modified volume // If they later get physical effects from loud noises we'll have to change this @@ -279,7 +279,7 @@ void sounds::process_sound_markers( player *p ) { bool is_deaf = p->is_deaf(); const float volume_multiplier = p->hearing_ability(); - const int weather_vol = weather_data( g->weather.weather ).sound_attn; + const int weather_vol = weather::sound_attn( g->weather.weather ); for( const auto &sound_event_pair : sounds_since_last_turn ) { const tripoint &pos = sound_event_pair.first; const sound_event &sound = sound_event_pair.second; diff --git a/src/vehicle.cpp b/src/vehicle.cpp index 68d18febdff95..8cf5b3eeda5dc 100644 --- a/src/vehicle.cpp +++ b/src/vehicle.cpp @@ -3348,7 +3348,9 @@ void vehicle::noise_and_smoke( int load, time_duration time ) } add_msg( m_debug, "VEH NOISE final: %d", static_cast( noise ) ); vehicle_noise = static_cast( noise ); - sounds::sound( global_pos3(), noise, sounds::sound_t::movement, sound_msgs[lvl], true ); + if( has_engine_type_not( fuel_type_muscle, true ) ) { + sounds::sound( global_pos3(), noise, sounds::sound_t::movement, sound_msgs[lvl], true ); + } } int vehicle::wheel_area() const diff --git a/src/vehicle.h b/src/vehicle.h index 034c6fd8af6d4..6d380aa44e574 100644 --- a/src/vehicle.h +++ b/src/vehicle.h @@ -1454,8 +1454,8 @@ class vehicle rl_vec2d dir_vec() const; // update vehicle parts as the vehicle moves void on_move(); - // move the vehicle on the map - bool act_on_map(); + // move the vehicle on the map. Returns updated pointer to self. + vehicle *act_on_map(); // check if the vehicle should be falling or is in water void check_falling_or_floating(); diff --git a/src/vehicle_move.cpp b/src/vehicle_move.cpp index ed953f2e7a749..f3bf9dc49c725 100644 --- a/src/vehicle_move.cpp +++ b/src/vehicle_move.cpp @@ -1247,7 +1247,7 @@ bool vehicle::is_wheel_state_correct_to_turn_on_rails( int wheels_on_rail, int w // allow turn for vehicles with wheel distance < 4 when moving backwards } -bool vehicle::act_on_map() +vehicle *vehicle::act_on_map() { const tripoint pt = global_pos3(); if( !g->m.inbounds( pt ) ) { @@ -1256,7 +1256,7 @@ bool vehicle::act_on_map() stop( false ); of_turn = 0; is_falling = false; - return true; + return this; } const bool pl_ctrl = player_in_control( g->u ); @@ -1273,7 +1273,7 @@ bool vehicle::act_on_map() g->m.on_vehicle_moved( smz ); // Destroy vehicle (sank to nowhere) g->m.destroy_vehicle( this ); - return true; + return this; } // It needs to fall when it has no support OR was falling before @@ -1301,7 +1301,7 @@ bool vehicle::act_on_map() if( !should_fall && abs( velocity ) < 20 ) { stop(); of_turn -= .321f; - return true; + return this; } const float wheel_traction_area = g->m.vehicle_wheel_traction( *this ); @@ -1315,7 +1315,7 @@ bool vehicle::act_on_map() } else { add_msg( m_info, _( "Your %s is beached." ), name ); } - return true; + return this; } } const float turn_cost = vehicles::vmiph_per_tile / std::max( 0.0001f, abs( velocity ) ); @@ -1327,7 +1327,7 @@ bool vehicle::act_on_map() if( !should_fall ) { of_turn_carry = of_turn; of_turn = 0; - return true; + return this; } falling_only = true; } @@ -1404,17 +1404,18 @@ bool vehicle::act_on_map() dp.z = -1; } + vehicle *new_pointer = this; // Split the movement into horizontal and vertical for easier processing if( dp.x != 0 || dp.y != 0 ) { - g->m.move_vehicle( *this, tripoint( dp.x, dp.y, 0 ), mdir ); + new_pointer = g->m.move_vehicle( *new_pointer, tripoint( dp.x, dp.y, 0 ), mdir ); } if( dp.z != 0 ) { - g->m.move_vehicle( *this, tripoint( 0, 0, dp.z ), mdir ); + new_pointer = g->m.move_vehicle( *new_pointer, tripoint( 0, 0, dp.z ), mdir ); is_falling = false; } - return true; + return new_pointer; } void vehicle::check_falling_or_floating() diff --git a/src/vehicle_use.cpp b/src/vehicle_use.cpp index 3bda6b282a409..1541a641a50aa 100644 --- a/src/vehicle_use.cpp +++ b/src/vehicle_use.cpp @@ -823,17 +823,17 @@ bool vehicle::start_engine( const int e ) if( einfo.has_flag( "MUSCLE_ARMS" ) && ( g->u.hp_cur[hp_arm_l] == 0 || g->u.hp_cur[hp_arm_r] == 0 ) ) { add_msg( _( "You cannot use %s with a broken arm." ), eng.name() ); + return false; } else if( einfo.has_flag( "MUSCLE_LEGS" ) && ( g->u.hp_cur[hp_leg_l] == 0 || g->u.hp_cur[hp_leg_r] == 0 ) ) { add_msg( _( "You cannot use %s with a broken leg." ), eng.name() ); - } else { - add_msg( _( "The %s's mechanism is out of reach!" ), name ); + return false; } } else { add_msg( _( "Looks like the %1$s is out of %2$s." ), eng.name(), item::nname( einfo.fuel_type ) ); + return false; } - return false; } const double dmg = parts[engines[e]].damage_percent(); diff --git a/src/weather.cpp b/src/weather.cpp index 1ec296fe4a9c5..8d3a1b86984e6 100644 --- a/src/weather.cpp +++ b/src/weather.cpp @@ -127,8 +127,8 @@ inline void proc_weather_sum( const weather_type wtype, weather_sum &data, } // TODO: Change this sunlight "sampling" here into a proper interpolation - const float tick_sunlight = calendar( to_turn( t ) ).sunlight() + weather_data( - wtype ).light_modifier; + const float tick_sunlight = calendar( to_turn( t ) ).sunlight() + weather::light_modifier( + wtype ); data.sunlight += std::max( 0.0f, to_turns( tick_size ) * tick_sunlight ); } @@ -596,7 +596,7 @@ std::string weather_forecast( const point &abs_sm_pos ) _( "The current time is %s Eastern Standard Time. At %s in %s, it was %s. The temperature was %s. " ), to_string_time_of_day( calendar::turn ), print_time_just_hour( calendar::turn ), city_name, - weather_data( g->weather.weather ).name, print_temperature( g->weather.temperature ) + weather::name( g->weather.weather ), print_temperature( g->weather.temperature ) ); //weather_report << ", the dewpoint ???, and the relative humidity ???. "; @@ -645,7 +645,7 @@ std::string weather_forecast( const point &abs_sm_pos ) } weather_report << string_format( _( "%s... %s. Highs of %s. Lows of %s. " ), - day, weather_data( forecast ).name, + day, weather::name( forecast ), print_temperature( high ), print_temperature( low ) ); } @@ -990,19 +990,20 @@ void weather_manager::update_weather() // Check weather every few turns, instead of every turn. // TODO: predict when the weather changes and use that time. nextweather = calendar::turn + 5_minutes; - if( weather != old_weather && weather_data( weather ).dangerous && + const weather_datum wdata = weather_data( weather ); + if( weather != old_weather && wdata.dangerous && g->get_levz() >= 0 && g->m.is_outside( g->u.pos() ) && !g->u.has_activity( activity_id( "ACT_WAIT_WEATHER" ) ) ) { g->cancel_activity_or_ignore_query( distraction_type::weather_change, - string_format( _( "The weather changed to %s!" ), weather_data( weather ).name ) ); + string_format( _( "The weather changed to %s!" ), wdata.name ) ); } if( weather != old_weather && g->u.has_activity( activity_id( "ACT_WAIT_WEATHER" ) ) ) { g->u.assign_activity( activity_id( "ACT_WAIT_WEATHER" ), 0, 0 ); } - if( weather_data( weather ).sight_penalty != - weather_data( old_weather ).sight_penalty ) { + if( wdata.sight_penalty != + weather::sight_penalty( old_weather ) ) { for( int i = -OVERMAP_DEPTH; i <= OVERMAP_HEIGHT; i++ ) { g->m.set_transparency_cache_dirty( i ); } diff --git a/src/weather.h b/src/weather.h index 9e058038271c3..48e62c8b316fa 100644 --- a/src/weather.h +++ b/src/weather.h @@ -111,17 +111,19 @@ void snow_glare(); void snowstorm(); } //namespace weather_effect +using weather_effect_fn = void ( * )(); + struct weather_datum { - std::string name; //!< UI name of weather type. - nc_color color; //!< UI color of weather type. - nc_color map_color; //!< Map color of weather type. - char glyph; //!< Map glyph of weather type. - int ranged_penalty; //!< Penalty to ranged attacks. - float sight_penalty; //!< Penalty to per-square visibility, applied in transparency map. - int light_modifier; //!< Modification to ambient light. - int sound_attn; //!< Sound attenuation of a given weather type. - bool dangerous; //!< If true, our activity gets interrupted. - void ( *effect )(); //!< Function pointer for weather effects. + std::string name; //!< UI name of weather type. + nc_color color; //!< UI color of weather type. + nc_color map_color; //!< Map color of weather type. + char glyph; //!< Map glyph of weather type. + int ranged_penalty; //!< Penalty to ranged attacks. + float sight_penalty; //!< Penalty to per-square visibility, applied in transparency map. + int light_modifier; //!< Modification to ambient light. + int sound_attn; //!< Sound attenuation of a given weather type. + bool dangerous; //!< If true, our activity gets interrupted. + weather_effect_fn effect; //!< Function pointer for weather effects. }; struct weather_sum { @@ -132,6 +134,19 @@ struct weather_sum { }; weather_datum const weather_data( weather_type const type ); +namespace weather +{ +std::string name( weather_type const type ); +nc_color color( weather_type const type ); +nc_color map_color( weather_type const type ); +char glyph( weather_type const type ); +int ranged_penalty( weather_type const type ); +float sight_penalty( weather_type const type ); +int light_modifier( weather_type const type ); +int sound_attn( weather_type const type ); +bool dangerous( weather_type const type ); +weather_effect_fn effect( weather_type const type ); +} std::string get_shortdirstring( int angle ); diff --git a/src/weather_data.cpp b/src/weather_data.cpp index e10a5ce19e19a..61759767e6b0b 100644 --- a/src/weather_data.cpp +++ b/src/weather_data.cpp @@ -37,8 +37,11 @@ weather_animation_t get_weather_animation( weather_type const type ) return {0.0f, c_white, '?'}; } - -weather_datum const weather_data( weather_type const type ) +struct weather_result { + weather_datum datum; + bool is_valid; +}; +static weather_result weather_data_internal( weather_type const type ) { /** * Weather types data definition. @@ -104,12 +107,68 @@ weather_datum const weather_data( weather_type const type ) const auto i = static_cast( type ); if( i < NUM_WEATHER_TYPES ) { - weather_datum localized = data[i]; - localized.name = _( localized.name ); - return localized; + return { data[i], i > 0 }; } - return data[0]; + return { data[0], false }; +} + +static weather_datum weather_data_interal_localized( weather_type const type ) +{ + weather_result res = weather_data_internal( type ); + if( res.is_valid ) { + res.datum.name = _( res.datum.name ); + } + return res.datum; +} + +weather_datum const weather_data( weather_type const type ) +{ + return weather_data_interal_localized( type ); +} + +namespace weather +{ +std::string name( weather_type const type ) +{ + return weather_data_interal_localized( type ).name; +} +nc_color color( weather_type const type ) +{ + return weather_data_internal( type ).datum.color; +} +nc_color map_color( weather_type const type ) +{ + return weather_data_internal( type ).datum.map_color; +} +char glyph( weather_type const type ) +{ + return weather_data_internal( type ).datum.glyph; +} +int ranged_penalty( weather_type const type ) +{ + return weather_data_internal( type ).datum.ranged_penalty; +} +float sight_penalty( weather_type const type ) +{ + return weather_data_internal( type ).datum.sight_penalty; +} +int light_modifier( weather_type const type ) +{ + return weather_data_internal( type ).datum.light_modifier; +} +int sound_attn( weather_type const type ) +{ + return weather_data_internal( type ).datum.sound_attn; +} +bool dangerous( weather_type const type ) +{ + return weather_data_internal( type ).datum.dangerous; +} +weather_effect_fn effect( weather_type const type ) +{ + return weather_data_internal( type ).datum.effect; +} } ///@} diff --git a/tests/npc_talk_test.cpp b/tests/npc_talk_test.cpp index 806faf655f885..ab01eadbb8fff 100644 --- a/tests/npc_talk_test.cpp +++ b/tests/npc_talk_test.cpp @@ -557,16 +557,17 @@ TEST_CASE( "npc_talk_test" ) CHECK( !has_item( g->u, "beer", 1 ) ); d.add_topic( "TALK_COMBAT_COMMANDS" ); - gen_response_lines( d, 9 ); + gen_response_lines( d, 10 ); CHECK( d.responses[0].text == "Change your engagement rules..." ); CHECK( d.responses[1].text == "Change your aiming rules..." ); CHECK( d.responses[2].text == "Stick close to me, no matter what." ); - CHECK( d.responses[3].text == "Don't use ranged weapons anymore." ); - CHECK( d.responses[4].text == "Use only silent weapons." ); - CHECK( d.responses[5].text == "Don't use grenades anymore." ); - CHECK( d.responses[6].text == "Don't worry about shooting an ally." ); - CHECK( d.responses[7].text == "Hold the line: don't move onto obstacles adjacent to me." ); - CHECK( d.responses[8].text == "Never mind." ); + CHECK( d.responses[3].text == "" ); + CHECK( d.responses[4].text == "Don't use ranged weapons anymore." ); + CHECK( d.responses[5].text == "Use only silent weapons." ); + CHECK( d.responses[6].text == "Don't use grenades anymore." ); + CHECK( d.responses[7].text == "Don't worry about shooting an ally." ); + CHECK( d.responses[8].text == "Hold the line: don't move onto obstacles adjacent to me." ); + CHECK( d.responses[9].text == "Never mind." ); d.add_topic( "TALK_TEST_VARS" ); gen_response_lines( d, 3 );