diff --git a/data/json/furniture_and_terrain/furniture-flora.json b/data/json/furniture_and_terrain/furniture-flora.json index 79991280b009a..48170072d2c1a 100644 --- a/data/json/furniture_and_terrain/furniture-flora.json +++ b/data/json/furniture_and_terrain/furniture-flora.json @@ -94,7 +94,7 @@ "seasons": [ "spring", "summer", "autumn" ], "entries": [ { "drop": "withered", "base_num": [ 1, 2 ] }, - { "drop": "seed_flower", "base_num": [ 1, 2 ] }, + { "drop": "seed_spurge", "base_num": [ 1, 2 ] }, { "drop": "spurge", "base_num": [ 1, 4 ] } ] } @@ -178,11 +178,7 @@ "harvest_by_season": [ { "seasons": [ "spring", "summer", "autumn" ], - "entries": [ - { "drop": "withered", "base_num": [ 1, 2 ] }, - { "drop": "seed_flower", "base_num": [ 1, 2 ] }, - { "drop": "lotus", "base_num": [ 1, 2 ] } - ] + "entries": [ { "drop": "withered", "base_num": [ 1, 2 ] }, { "drop": "lotus", "base_num": [ 1, 2 ] } ] } ], "//": "Add flower and bud spawns once useful.", diff --git a/data/json/itemgroups/Agriculture_Forage_Excavation/agriculture.json b/data/json/itemgroups/Agriculture_Forage_Excavation/agriculture.json index 202261ac3ee92..4d76f889b27cf 100644 --- a/data/json/itemgroups/Agriculture_Forage_Excavation/agriculture.json +++ b/data/json/itemgroups/Agriculture_Forage_Excavation/agriculture.json @@ -33,6 +33,7 @@ [ "seed_chili_pepper", 60 ], [ "seed_tomato", 60 ], [ "seed_horseradish", 10 ], + [ "seed_spurge", 10 ], [ "seed_popcorn", 10 ], [ "seed_mustard", 10 ] ] diff --git a/data/json/itemgroups/trash_and_debris.json b/data/json/itemgroups/trash_and_debris.json index 5c7063e4e07ac..3e3f2ec771f26 100644 --- a/data/json/itemgroups/trash_and_debris.json +++ b/data/json/itemgroups/trash_and_debris.json @@ -99,6 +99,7 @@ [ "seed_weed", 5 ], [ "seed_flower", 5 ], [ "seed_tobacco", 1 ], + [ "seed_spurge", 1 ], [ "joint_roach", 5 ], [ "pipe", 20 ], [ "bag_plastic", 10 ], diff --git a/data/json/items/armor/ballistic_armor.json b/data/json/items/armor/ballistic_armor.json index 1dfd1ffc8009d..af45b40580800 100644 --- a/data/json/items/armor/ballistic_armor.json +++ b/data/json/items/armor/ballistic_armor.json @@ -39,7 +39,7 @@ "coverage": 85, "encumbrance": 10, "warmth": 15, - "material_thickness": 20, + "material_thickness": 16, "flags": [ "STURDY", "OUTER", "WATER_FRIENDLY", "NO_REPAIR" ] }, { diff --git a/data/json/items/armor/coats.json b/data/json/items/armor/coats.json index 02c6eae13b234..872f2cf474efa 100644 --- a/data/json/items/armor/coats.json +++ b/data/json/items/armor/coats.json @@ -11,7 +11,7 @@ "price": 91000, "price_postapoc": 1500, "to_hit": -1, - "material": [ "nomex", "kevlar" ], + "material": [ "nomex", "kevlar", "lycra" ], "symbol": "[", "looks_like": "coat_winter", "color": "yellow", diff --git a/data/json/items/armor/legs_armor.json b/data/json/items/armor/legs_armor.json index ee9b7667d659a..99a11bff49b5a 100644 --- a/data/json/items/armor/legs_armor.json +++ b/data/json/items/armor/legs_armor.json @@ -35,7 +35,7 @@ "price": 81500, "price_postapoc": 500, "to_hit": -1, - "material": [ "nomex", "kevlar" ], + "material": [ "nomex", "kevlar", "lycra" ], "symbol": "[", "looks_like": "pants_cargo", "color": "dark_gray", diff --git a/data/json/items/armor/power_armor.json b/data/json/items/armor/power_armor.json index d247f0cf618fb..a7e8cba8d3a6a 100644 --- a/data/json/items/armor/power_armor.json +++ b/data/json/items/armor/power_armor.json @@ -62,7 +62,7 @@ "price_postapoc": 30000, "to_hit": 1, "bashing": 1, - "material": [ "hardsteel", "steel" ], + "material": [ "hardsteel", "ceramic", "kevlar_rigid" ], "symbol": "[", "looks_like": "depowered_armor", "color": "light_gray", @@ -72,7 +72,7 @@ "pocket_data": [ { "pocket_type": "CONTAINER", "max_contains_volume": "2500 ml", "max_contains_weight": "15 kg", "moves": 200 } ], "warmth": 90, "power_armor": true, - "material_thickness": 11, + "material_thickness": 14, "environmental_protection": 16, "use_action": { "type": "ups_based_armor", "activate_msg": "Your power armor engages." }, "flags": [ "WATERPROOF", "STURDY", "ELECTRIC_IMMUNE" ] @@ -113,7 +113,7 @@ "price_postapoc": 40000, "to_hit": 1, "bashing": 1, - "material": [ "hardsteel", "steel" ], + "material": [ "hardsteel", "ceramic", "kevlar_rigid" ], "symbol": "[", "looks_like": "power_armor_basic", "color": "dark_gray", @@ -123,7 +123,7 @@ "pocket_data": [ { "pocket_type": "CONTAINER", "max_contains_volume": "4 L", "max_contains_weight": "30 kg", "moves": 200 } ], "warmth": 60, "power_armor": true, - "material_thickness": 12, + "material_thickness": 16, "environmental_protection": 16, "use_action": { "type": "ups_based_armor", "activate_msg": "Your power armor engages." }, "flags": [ "WATERPROOF", "STURDY", "ELECTRIC_IMMUNE" ] @@ -140,7 +140,7 @@ "price_postapoc": 7500, "to_hit": 1, "bashing": 1, - "material": [ "hardsteel", "steel" ], + "material": [ "hardsteel", "ceramic", "kevlar_rigid" ], "symbol": "[", "looks_like": "depowered_helmet", "color": "light_gray", @@ -149,7 +149,7 @@ "encumbrance": 50, "warmth": 90, "power_armor": true, - "material_thickness": 11, + "material_thickness": 14, "environmental_protection": 16, "qualities": [ [ "GLARE", 2 ] ], "flags": [ "WATCH", "WATERPROOF", "STURDY", "PARTIAL_DEAF", "THERMOMETER", "SUN_GLASSES" ] @@ -166,7 +166,7 @@ "price_postapoc": 10000, "to_hit": 1, "bashing": 1, - "material": [ "hardsteel", "steel" ], + "material": [ "hardsteel", "ceramic", "kevlar_rigid" ], "symbol": "[", "looks_like": "power_armor_helmet_basic", "color": "dark_gray", @@ -175,7 +175,7 @@ "encumbrance": 60, "warmth": 60, "power_armor": true, - "material_thickness": 12, + "material_thickness": 16, "environmental_protection": 16, "qualities": [ [ "GLARE", 2 ] ], "flags": [ "WATCH", "WATERPROOF", "STURDY", "PARTIAL_DEAF", "THERMOMETER", "SUN_GLASSES" ] @@ -192,7 +192,7 @@ "price_postapoc": 10000, "to_hit": 1, "bashing": 1, - "material": [ "superalloy", "plastic" ], + "material": [ "hardsteel", "kevlar", "kevlar_rigid" ], "symbol": "[", "looks_like": "power_armor_helmet_basic", "color": "dark_gray", @@ -201,7 +201,7 @@ "encumbrance": 40, "warmth": 60, "power_armor": true, - "material_thickness": 9, + "material_thickness": 8, "environmental_protection": 16, "qualities": [ [ "GLARE", 1 ] ], "flags": [ "WATCH", "WATERPROOF", "STURDY", "THERMOMETER", "SUN_GLASSES" ] @@ -218,7 +218,7 @@ "price_postapoc": 40000, "to_hit": 1, "bashing": 1, - "material": [ "superalloy", "plastic" ], + "material": [ "hardsteel", "kevlar", "kevlar_rigid" ], "symbol": "[", "looks_like": "depowered_armor", "color": "dark_gray", @@ -228,7 +228,7 @@ "pocket_data": [ { "pocket_type": "CONTAINER", "max_contains_volume": "4 L", "max_contains_weight": "30 kg", "moves": 200 } ], "warmth": 60, "power_armor": true, - "material_thickness": 9, + "material_thickness": 8, "environmental_protection": 16, "use_action": { "type": "ups_based_armor", "activate_msg": "Your power armor engages." }, "flags": [ "WATERPROOF", "STURDY", "ELECTRIC_IMMUNE" ] diff --git a/data/json/items/armor/torso_armor.json b/data/json/items/armor/torso_armor.json index ee1b2c66bd264..1e92cd7d1163e 100644 --- a/data/json/items/armor/torso_armor.json +++ b/data/json/items/armor/torso_armor.json @@ -319,7 +319,7 @@ "coverage": 85, "encumbrance": 5, "warmth": 15, - "material_thickness": 4, + "material_thickness": 3, "flags": [ "STURDY", "SKINTIGHT" ] }, { diff --git a/data/json/items/comestibles/seed.json b/data/json/items/comestibles/seed.json index 18505e1cb9030..0bfc139d5d469 100644 --- a/data/json/items/comestibles/seed.json +++ b/data/json/items/comestibles/seed.json @@ -749,6 +749,15 @@ "description": "Some chamomile seeds.", "seed_data": { "plant_name": "chamomile", "fruit": "chamomile", "byproducts": [ "withered" ], "grow": "91 days" } }, + { + "type": "COMESTIBLE", + "id": "seed_spurge", + "copy-from": "seed", + "looks_like": "seed_raw_dandelion", + "name": { "str_sp": "spurge seeds" }, + "description": "Some spurge seeds.", + "seed_data": { "plant_name": "spurge", "fruit": "spurge", "byproducts": [ "withered" ], "grow": "91 days" } + }, { "type": "COMESTIBLE", "id": "seed_popcorn", diff --git a/data/json/items/comestibles/spice.json b/data/json/items/comestibles/spice.json index 3f08fcf47cca1..d574119e831b7 100644 --- a/data/json/items/comestibles/spice.json +++ b/data/json/items/comestibles/spice.json @@ -98,7 +98,7 @@ "symbol": "%", "quench": -1, "calories": 9, - "description": "A tasty collection of wild herbs including violet, sassafras, mint, clover, purslane, fireweed, and burdock.", + "description": "A tasty collection of wild herbs including violet, sassafras, mint, clover, purslane, and fireweed.", "price": 190, "price_postapoc": 50, "material": "veggy", diff --git a/data/json/mapgen/campus/buildings/admin_f0.json b/data/json/mapgen/campus/buildings/admin_f0.json index ea15f0396beb6..e6b8587a23db5 100644 --- a/data/json/mapgen/campus/buildings/admin_f0.json +++ b/data/json/mapgen/campus/buildings/admin_f0.json @@ -39,22 +39,22 @@ "__|,,,,,,,,,,,,|________", "__|,,,,,,,,,,,,|________", "__|,,,,,,,,,,,,|________", - "bb|,,,,,,,,,,,,||||||||||", - "..|,,,,,,,,,,,,,,,,,,,,,|", - "..|,,,,,,,,,,,,,,,,,,,,,|", - "..|,,,,,,,,,,,,,,,,,,,,,|", - "..|,,,,,,,,,,,,,,,,,,,,,|", - "..|,,,,,,,,,,,,,,,,,,,,,|", - "..|,,,,,,,,,,,,,,,,,,,,,|", - "..|,,,,,,,,,,,,,,,,,,,,,|", - "..|,,,,,,,,,,,,,,,,,,,,,|", - "..|,,,,,,,,,,,,,,,,,,,,,|", - "..|,,,,,,,,,,,,,,,,,,,,,|", - "..|,,,,,,,,,,,,,,,,,,,,,|", - "..|,,,,,,,,,,,,,,,,,,,,,|", - "..|,,,,,,,,,,,,,,,,,,,,,|", - "..|,,,,,,,,,,,,,,,,,,,,,|", - "..|,,,,,,,,,,,,,,||||||||", + "bb|,,,,,,,,,,,,|||||||||", + "..|,,,,,,,,,,,,,,,,,,,,|", + "..|,,,,,,,,,,,,,,,,,,,,|", + "..|,,,,,,,,,,,,,,,,,,,,|", + "..|,,,,,,,,,,,,,,,,,,,,|", + "..|,,,,,,,,,,,,,,,,,,,,|", + "..|,,,,,,,,,,,,,,,,,,,,|", + "..|,,,,,,,,,,,,,,,,,,,,|", + "..|,,,,,,,,,,,,,,,,,,,,|", + "..|,,,,,,,,,,,,,,,,,,,,|", + "..|,,,,,,,,,,,,,,,,,,,,|", + "..|,,,,,,,,,,,,,,,,,,,,|", + "..|,,,,,,,,,,,,,,,,,,,,|", + "..|,,,,,,,,,,,,,,,,,,,,|", + "..|,,,,,,,,,,,,,,,,,,,,|", + "..|,,,,,,,,,,,,,,|||||||", ".||,,,,,,,,,,,,,,|.....b", ".|,,,,,,,,,,,,,,,|.....b", ".|,,,,,,,,,,,,,,,|.....b", diff --git a/data/json/mapgen/campus/buildings/admin_f1.json b/data/json/mapgen/campus/buildings/admin_f1.json index 9091b93e802a9..457de096953ba 100644 --- a/data/json/mapgen/campus/buildings/admin_f1.json +++ b/data/json/mapgen/campus/buildings/admin_f1.json @@ -39,22 +39,22 @@ " |,,,,,,,,,,,,| ", " |,,,,,,,,,,,,| ", " |,,,,,,,,,,,,| ", - " |,,,,,,,,,,,,||||||||||", - " |,,,,,,,,,,,,,,,,,,,,,|", - " |,,,,,,,,,,,,,,,,,,,,,|", - " |,,,,,,,,,,,,,,,,,,,,,|", - " |,,,,,,,,,,,,,,,,,,,,,|", - " |,,,,,,,,,,,,,,,,,,,,,|", - " |,,,,,,,,,,,,,,,,,,,,,|", - " |,,,,,,,,,,,,,,,,,,,,,|", - " |,,,,,,,,,,,,,,,,,,,,,|", - " |,,,,,,,,,,,,,,,,,,,,,|", - " |,,,,,,,,,,,,,,,,,,,,,|", - " |,,,,,,,,,,,,,,,,,,,,,|", - " |,,,,,,,,,,,,,,,,,,,,,|", - " |,,,,,,,,,,,,,,,,,,,,,|", - " |,,,,,,,,,,,,,,,,,,,,,|", - " |,,,,,,,,,,,,,,||||||||", + " |,,,,,,,,,,,,|||||||||", + " |,,,,,,,,,,,,,,,,,,,,|", + " |,,,,,,,,,,,,,,,,,,,,|", + " |,,,,,,,,,,,,,,,,,,,,|", + " |,,,,,,,,,,,,,,,,,,,,|", + " |,,,,,,,,,,,,,,,,,,,,|", + " |,,,,,,,,,,,,,,,,,,,,|", + " |,,,,,,,,,,,,,,,,,,,,|", + " |,,,,,,,,,,,,,,,,,,,,|", + " |,,,,,,,,,,,,,,,,,,,,|", + " |,,,,,,,,,,,,,,,,,,,,|", + " |,,,,,,,,,,,,,,,,,,,,|", + " |,,,,,,,,,,,,,,,,,,,,|", + " |,,,,,,,,,,,,,,,,,,,,|", + " |,,,,,,,,,,,,,,,,,,,,|", + " |,,,,,,,,,,,,,,|||||||", " ||,,,,,,,,,,,,,,| ", " |,,,,,,,,,,,,,,,| ", " |,,,,,,,,,,,,,,,| ", diff --git a/data/json/mapgen/cs_gardening_allotment.json b/data/json/mapgen/cs_gardening_allotment.json index bcbfbd0fa859b..4b0027d8cbc66 100644 --- a/data/json/mapgen/cs_gardening_allotment.json +++ b/data/json/mapgen/cs_gardening_allotment.json @@ -11,6 +11,7 @@ [ "seed_carrot", 10 ], [ "seed_pumpkin", 10 ], [ "seed_broccoli", 10 ], + [ "seed_spurge", 10 ], [ "gloves_work", 10 ] ] }, diff --git a/data/json/mapgen/dumpsite.json b/data/json/mapgen/dumpsite.json index f9e4f79fc3e52..cb2cad498af7b 100644 --- a/data/json/mapgen/dumpsite.json +++ b/data/json/mapgen/dumpsite.json @@ -49,7 +49,7 @@ "........................", "........................", "..........^^^^.^........", - ".......q^^__^_^_qq.......", + ".......q^^__^_^_qq......", ".......q.________^q.....", ".....q^qq^______^^.q....", "....q^^qq_______^^q.....", diff --git a/data/json/mapgen/hotel_tower.json b/data/json/mapgen/hotel_tower.json index b8bd51c721150..43b1d7277c3e8 100644 --- a/data/json/mapgen/hotel_tower.json +++ b/data/json/mapgen/hotel_tower.json @@ -364,7 +364,7 @@ "******%c..BB|h..BB|o..BB|o..BB|c..BB|BB..h|BB..c|BB..c|BB..h|BB..c%*****", "******%....d|th..d|....d|....d|....d|d..ht|d....|dL...|d..ht|d....%*****", "******%%www%%%www%%%www%%%www%%%www%%%www%%%www%%%www%%%www%%%www%%*****", - "*************************************************************************" + "************************************************************************" ], "palettes": [ "hotel_tower_palette.json" ], "terrain": { "+": [ "t_door_c", "t_door_c", "t_door_o" ], "w": "t_window_domestic" }, diff --git a/data/json/mapgen/house/house05_ab.json b/data/json/mapgen/house/house05_ab.json index 20b3f55614621..d09e1156f095d 100644 --- a/data/json/mapgen/house/house05_ab.json +++ b/data/json/mapgen/house/house05_ab.json @@ -30,7 +30,7 @@ ".# | #.", ".# | #.", ".####oo#########oo#####.", - "............^............" + "............^..........." ], "set": [ { "point": "terrain", "id": "t_dirt", "x": [ 0, 0 ], "y": [ 0, 23 ], "repeat": [ 5, 10 ] }, diff --git a/data/json/mapgen/megastore.json b/data/json/mapgen/megastore.json index b698eedda7686..9bf37dfb18ade 100644 --- a/data/json/mapgen/megastore.json +++ b/data/json/mapgen/megastore.json @@ -2194,7 +2194,7 @@ "########################", "########################", "####----------------####", - "####| | ####", + "####| | ###", "####| -----", "####|I I ", "####| ", diff --git a/data/json/mapgen/steel_mill/steel_mill_z1.json b/data/json/mapgen/steel_mill/steel_mill_z1.json index 4a2d20dfae5eb..59d4da2d72f3d 100644 --- a/data/json/mapgen/steel_mill/steel_mill_z1.json +++ b/data/json/mapgen/steel_mill/steel_mill_z1.json @@ -13,7 +13,7 @@ "fill_ter": "t_thconc_floor", "rows": [ "vvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvv._______,,_______.vvvvvvvvvvvvvvvvvvvvvvvvvvv", - "v..................................................._______,,_______............................v", + "v..................................................._______,,_______...........................v", "v..................................................___________________________________,,,,,,,,.v", "v....]]]]]]]]]]]]**]]]**]]**]]**].................____________________________________________.v", "v....]ee]ee]<< #ch #ch #Sch S]-------------..._____________________________________________.v", diff --git a/data/json/mapgen/steel_mill/steel_mill_z2.json b/data/json/mapgen/steel_mill/steel_mill_z2.json index f4b994053c9af..ee62fd82b35b0 100644 --- a/data/json/mapgen/steel_mill/steel_mill_z2.json +++ b/data/json/mapgen/steel_mill/steel_mill_z2.json @@ -12,7 +12,7 @@ "object": { "fill_ter": "t_carpet_concrete", "rows": [ - ":::::::::::::::::::::::::::::::1:::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::", + ":::::::::::::::::::::::::::::::1::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::", "::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::", "::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::", ":::::]]]]]]]]]]]]**]]]**]]**]]**]:::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::", diff --git a/data/json/mapgen/trailhead.json b/data/json/mapgen/trailhead.json index 86b334b43a8e9..0cad3512d0986 100644 --- a/data/json/mapgen/trailhead.json +++ b/data/json/mapgen/trailhead.json @@ -101,7 +101,7 @@ ";;;...................;;", ";;;...................;;", ";;... ..;;;", - ";;... . . . .;;;;", + ";;... . . . .;;;", ";;;.. . ;;;;;", ";;;;. . . . ;;;;;", ";;;;; ;;;;;", diff --git a/data/json/materials.json b/data/json/materials.json index a122c7a7a9380..343a3408af23d 100644 --- a/data/json/materials.json +++ b/data/json/materials.json @@ -56,7 +56,7 @@ "latent_heat": 398, "bash_resist": 0, "cut_resist": 4, - "bullet_resist": 3, + "bullet_resist": 2, "acid_resist": 4, "fire_resist": 2, "elec_resist": 0, @@ -77,7 +77,7 @@ "latent_heat": 333, "bash_resist": 3, "cut_resist": 4, - "bullet_resist": 3, + "bullet_resist": 1, "acid_resist": 13, "fire_resist": 2, "elec_resist": 2, @@ -105,7 +105,7 @@ "rotting": true, "bash_resist": 2, "cut_resist": 3, - "bullet_resist": 2, + "bullet_resist": 1, "acid_resist": 7, "fire_resist": 1, "elec_resist": 2, @@ -132,7 +132,7 @@ "latent_heat": 205, "bash_resist": 3, "cut_resist": 4, - "bullet_resist": 3, + "bullet_resist": 2, "acid_resist": 16, "fire_resist": 2, "elec_resist": 0, @@ -148,7 +148,7 @@ "density": 58, "bash_resist": 4, "cut_resist": 5, - "bullet_resist": 4, + "bullet_resist": 2, "acid_resist": 1, "fire_resist": 2, "elec_resist": 0, @@ -170,7 +170,7 @@ "latent_heat": 273, "bash_resist": 6, "cut_resist": 6, - "bullet_resist": 5, + "bullet_resist": 2, "acid_resist": 7, "fire_resist": 3, "elec_resist": 0, @@ -212,8 +212,8 @@ "specific_heat_solid": 1, "latent_heat": 333, "bash_resist": 2, - "cut_resist": 6, - "bullet_resist": 5, + "cut_resist": 4, + "bullet_resist": 7, "acid_resist": 10, "fire_resist": 10, "elec_resist": 10, @@ -248,7 +248,7 @@ "latent_heat": 333, "bash_resist": 3, "cut_resist": 4, - "bullet_resist": 3, + "bullet_resist": 1, "acid_resist": 6, "fire_resist": 2, "elec_resist": 2, @@ -342,9 +342,9 @@ "specific_heat_liquid": 0.52, "specific_heat_solid": 0.52, "latent_heat": 5200, - "bash_resist": 14, - "cut_resist": 20, - "bullet_resist": 16, + "bash_resist": 5, + "cut_resist": 5, + "bullet_resist": 2, "acid_resist": 10, "fire_resist": 3, "elec_resist": 3, @@ -361,9 +361,9 @@ "specific_heat_liquid": 0.52, "specific_heat_solid": 0.52, "latent_heat": 5200, - "bash_resist": 14, - "cut_resist": 20, - "bullet_resist": 16, + "bash_resist": 5, + "cut_resist": 5, + "bullet_resist": 2, "acid_resist": 10, "fire_resist": 3, "elec_resist": 3, @@ -605,7 +605,7 @@ "latent_heat": 273, "bash_resist": 10, "cut_resist": 16, - "bullet_resist": 13, + "bullet_resist": 9, "acid_resist": 6, "fire_resist": 3, "elec_resist": 0, @@ -727,7 +727,7 @@ "latent_heat": 273, "bash_resist": 4, "cut_resist": 4, - "bullet_resist": 3, + "bullet_resist": 2, "acid_resist": 5, "fire_resist": 3, "elec_resist": 0, @@ -776,8 +776,8 @@ "latent_heat": 273, "soft": true, "bash_resist": 2, - "cut_resist": 4, - "bullet_resist": 3, + "cut_resist": 3, + "bullet_resist": 5, "acid_resist": 5, "fire_resist": 3, "elec_resist": 2, @@ -796,9 +796,9 @@ "specific_heat_liquid": 0.82, "specific_heat_solid": 0.45, "latent_heat": 273, - "bash_resist": 2, + "bash_resist": 3, "cut_resist": 4, - "bullet_resist": 3, + "bullet_resist": 5, "acid_resist": 5, "fire_resist": 3, "elec_resist": 2, @@ -1225,7 +1225,7 @@ "specific_heat_solid": 0.45, "latent_heat": 273, "cut_resist": 6, - "bullet_resist": 5, + "bullet_resist": 3, "acid_resist": 7, "fire_resist": 3, "elec_resist": 0, @@ -1248,7 +1248,7 @@ "latent_heat": 273, "bash_resist": 6, "cut_resist": 6, - "bullet_resist": 5, + "bullet_resist": 3, "acid_resist": 8, "fire_resist": 3, "elec_resist": 2, diff --git a/data/json/player_activities.json b/data/json/player_activities.json index 3be9f008c4200..02c1913c54a40 100644 --- a/data/json/player_activities.json +++ b/data/json/player_activities.json @@ -864,5 +864,12 @@ "suspendable": false, "based_on": "neither", "no_resume": true + }, + { + "id": "ACT_CONSUME", + "type": "activity_type", + "activity_level": "NO_EXERCISE", + "verb": "consuming", + "based_on": "time" } ] diff --git a/data/mods/Aftershock/items/armor.json b/data/mods/Aftershock/items/armor.json index 6aa3373f11b64..1206f12be4bbd 100644 --- a/data/mods/Aftershock/items/armor.json +++ b/data/mods/Aftershock/items/armor.json @@ -79,7 +79,7 @@ "weight": "900 g", "volume": "3 L", "copy-from": "jeans", - "storage": "750 ml", + "pocket_data": [ { "pocket_type": "CONTAINER", "rigid": true, "max_contains_volume": "750 ml", "max_contains_weight": "1 kg" } ], "material_thickness": 4, "flags": [ "VARSIZE", "POCKETS", "OVERSIZE" ] }, @@ -92,7 +92,7 @@ "copy-from": "technician_pants_gray", "weight": "770 g", "volume": "3 L", - "storage": "1700 ml", + "pocket_data": [ { "pocket_type": "CONTAINER", "rigid": true, "max_contains_volume": "1700 ml", "max_contains_weight": "2 kg" } ], "material_thickness": 2, "snippet_category": [ { "id": "xl_technician_pants_blue", "text": "A pair of XL blue work pants." }, diff --git a/data/mods/Magiclysm/worldgen/black_dragon_lair.json b/data/mods/Magiclysm/worldgen/black_dragon_lair.json index a81df2efa4031..c8cee2531505f 100644 --- a/data/mods/Magiclysm/worldgen/black_dragon_lair.json +++ b/data/mods/Magiclysm/worldgen/black_dragon_lair.json @@ -437,7 +437,7 @@ "X XXXXX XXX XXXXXX << XXXXXXX << XXXX", "X XXXXX XXX XXXXXXXXXXXXXX XX XXX << XXXX", "X XXXX XX XXX XXXXXXXXX XX XXXXX XXX", - "X XXX << XX XXX XXXXXX XXXX", + "X XXX << XX XXX XXXXXX XXX", "X XXX << XX XX XX XXXX XXX", "X XXX XXX XX XX XXX XXXXXXX XX", "X XXXX XXX X XXXX XXX XXXXXX XXX X", diff --git a/data/mods/mapspecials_demo/megastore/mega_2brc_01.json b/data/mods/mapspecials_demo/megastore/mega_2brc_01.json index 447ba1ee105af..d7a7085fab7de 100644 --- a/data/mods/mapspecials_demo/megastore/mega_2brc_01.json +++ b/data/mods/mapspecials_demo/megastore/mega_2brc_01.json @@ -11,7 +11,7 @@ "########################", "########################", "####----------------####", - "####| | ####", + "####| | ###", "####| -----", "####|I I ", "####| ", diff --git a/data/mods/mapspecials_demo/missile_silo/silo_utlca_01.json b/data/mods/mapspecials_demo/missile_silo/silo_utlca_01.json index 6fc9e88620bc1..bb8e3032805f7 100644 --- a/data/mods/mapspecials_demo/missile_silo/silo_utlca_01.json +++ b/data/mods/mapspecials_demo/missile_silo/silo_utlca_01.json @@ -22,7 +22,7 @@ "##............x.########", "##..............X##..###", "##.x.X..X............---", - "####...##................", + "####...##...............", "#############...........", "############.........~~~", "##-----#########...~~~~~", diff --git a/data/mods/mapspecials_demo/missile_silo/silo_utlca_02.json b/data/mods/mapspecials_demo/missile_silo/silo_utlca_02.json index 5728766b5f102..9a206572f9c75 100644 --- a/data/mods/mapspecials_demo/missile_silo/silo_utlca_02.json +++ b/data/mods/mapspecials_demo/missile_silo/silo_utlca_02.json @@ -13,7 +13,7 @@ "#################-------", "################-|....D.", "###############-|....c6.", - "###############|6..D...D.", + "###############|6..D..D.", "##---------####|4.c6....", "##|...|eee|####|6..D..D.", "##|.<.|eee|####-|....c6.", diff --git a/src/activity_actor.cpp b/src/activity_actor.cpp index d5f18c88ab69b..49ecf5668ddf2 100644 --- a/src/activity_actor.cpp +++ b/src/activity_actor.cpp @@ -22,6 +22,7 @@ #include "npc.h" #include "output.h" #include "pickup.h" +#include "player.h" #include "player_activity.h" #include "point.h" #include "timed_event.h" @@ -33,6 +34,8 @@ static const skill_id skill_computer( "computer" ); static const trait_id trait_ILLITERATE( "ILLITERATE" ); +static const std::string flag_USE_EAT_VERB( "USE_EAT_VERB" ); + void hacking_activity_actor::start( player_activity &act, Character & ) { act.moves_total = to_moves( 5_minutes ); @@ -409,12 +412,69 @@ std::unique_ptr open_gate_activity_actor::deserialize( JsonIn &j return actor.clone(); } +void consume_activity_actor::start( player_activity &act, Character & ) +{ + const int charges = std::max( loc->charges, 1 ); + int volume = units::to_milliliter( loc->volume() ) / charges; + time_duration time = 0_seconds; + const bool eat_verb = loc->has_flag( flag_USE_EAT_VERB ); + if( eat_verb || loc->get_comestible()->comesttype == "FOOD" ) { + time = time_duration::from_seconds( volume / 5 ); //Eat 5 mL (1 teaspoon) per second + } else if( !eat_verb && loc->get_comestible()->comesttype == "DRINK" ) { + time = time_duration::from_seconds( volume / 15 ); //Drink 15 mL (1 tablespoon) per second + } else if( loc->is_medication() ) { + time = time_duration::from_seconds( + 30 ); //Medicine/drugs takes 30 seconds this is pretty arbitrary and should probable be broken up more but seems ok for a start + } else { + debugmsg( "Consumed something that was not food, drink or medicine/drugs" ); + } + + act.moves_total = to_moves( time ); + act.moves_left = to_moves( time ); +} + +void consume_activity_actor::finish( player_activity &act, Character & ) +{ + if( loc.where() == item_location::type::character ) { + g->u.consume( loc ); + + } else if( g->u.consume_item( *loc ) ) { + loc.remove_item(); + } + if( g->u.get_value( "THIEF_MODE_KEEP" ) != "YES" ) { + g->u.set_value( "THIEF_MODE", "THIEF_ASK" ); + } + act.set_to_null(); +} + +void consume_activity_actor::serialize( JsonOut &jsout ) const +{ + jsout.start_object(); + + jsout.member( "loc", loc ); + + jsout.end_object(); +} + +std::unique_ptr consume_activity_actor::deserialize( JsonIn &jsin ) +{ + item_location null; + consume_activity_actor actor( null ); + + JsonObject data = jsin.get_object(); + + data.read( "loc", actor.loc ); + + return actor.clone(); +} + namespace activity_actors { // Please keep this alphabetically sorted const std::unordered_map( * )( JsonIn & )> deserialize_functions = { + { activity_id( "ACT_CONSUME" ), &consume_activity_actor::deserialize }, { activity_id( "ACT_HACKING" ), &hacking_activity_actor::deserialize }, { activity_id( "ACT_MIGRATION_CANCEL" ), &migration_cancel_activity_actor::deserialize }, { activity_id( "ACT_MOVE_ITEMS" ), &move_items_activity_actor::deserialize }, diff --git a/src/activity_actor.h b/src/activity_actor.h index d593551cc9f6c..86ed03c33b46a 100644 --- a/src/activity_actor.h +++ b/src/activity_actor.h @@ -202,6 +202,31 @@ class open_gate_activity_actor : public activity_actor static std::unique_ptr deserialize( JsonIn &jsin ); }; +class consume_activity_actor : public activity_actor +{ + private: + item_location loc; + + public: + consume_activity_actor( const item_location &loc ) : + loc( loc ) {} + + activity_id get_type() const override { + return activity_id( "ACT_CONSUME" ); + } + + void start( player_activity &act, Character & ) override; + void do_turn( player_activity &, Character & ) override {}; + void finish( player_activity &act, Character &who ) override; + + std::unique_ptr clone() const override { + return std::make_unique( *this ); + } + + void serialize( JsonOut &jsout ) const override; + static std::unique_ptr deserialize( JsonIn &jsin ); +}; + namespace activity_actors { diff --git a/src/avatar_action.cpp b/src/avatar_action.cpp index 537420dd4ea71..9cee402ba0190 100644 --- a/src/avatar_action.cpp +++ b/src/avatar_action.cpp @@ -1079,16 +1079,7 @@ void avatar_action::eat( avatar &you, item_location loc ) add_msg( _( "Never mind." ) ); return; } - item *it = loc.get_item(); - if( loc.where() == item_location::type::character ) { - you.consume( loc ); - - } else if( you.consume_item( *it ) ) { - loc.remove_item(); - } - if( g->u.get_value( "THIEF_MODE_KEEP" ) != "YES" ) { - g->u.set_value( "THIEF_MODE", "THIEF_ASK" ); - } + you.assign_activity( player_activity( consume_activity_actor( loc ) ) ); } void avatar_action::plthrow( avatar &you, item_location loc, diff --git a/src/game_inventory.cpp b/src/game_inventory.cpp index 1d3225ad3fbca..132ffdb8eb4c1 100644 --- a/src/game_inventory.cpp +++ b/src/game_inventory.cpp @@ -159,7 +159,6 @@ static item_location inv_internal( player &u, const inventory_selector_preset &p has_init_filter = true; } - bool need_refresh = true; do { u.inv.restack( u ); @@ -167,18 +166,14 @@ static item_location inv_internal( player &u, const inventory_selector_preset &p inv_s.add_character_items( u ); inv_s.add_nearby_items( radius ); - if( init_selection || has_init_filter ) { - inv_s.update( need_refresh ); - if( has_init_filter ) { - inv_s.set_filter( init_filter ); - has_init_filter = false; - inv_s.update( need_refresh ); - } - // Set position after filter to keep cursor at the right position - if( init_selection ) { - inv_s.select_position( init_pair ); - init_selection = false; - } + if( has_init_filter ) { + inv_s.set_filter( init_filter ); + has_init_filter = false; + } + // Set position after filter to keep cursor at the right position + if( init_selection ) { + inv_s.select_position( init_pair ); + init_selection = false; } if( inv_s.empty() ) { @@ -224,12 +219,10 @@ void game_menus::inv::common( avatar &you ) int res = 0; - bool need_refresh = true; do { you.inv.restack( you ); inv_s.clear_items(); inv_s.add_character_items( you ); - inv_s.update( need_refresh ); const item_location &location = inv_s.execute(); @@ -263,11 +256,9 @@ void game_menus::inv::common( item_location loc, avatar &you ) int res = 0; - bool need_refresh = true; do { inv_s.clear_items(); inv_s.add_contained_items( loc ); - inv_s.update( need_refresh ); const item_location &location = inv_s.execute(); @@ -528,26 +519,29 @@ class comestible_inventory_preset : public inventory_selector_preset public: comestible_inventory_preset( const player &p ) : p( p ) { - append_cell( [ &p, this ]( const item_location & loc ) { - const nutrients nutr = p.compute_effective_nutrients( get_consumable_item( loc ) ); + _indent_entries = false; + + append_cell( [&p]( const item_location & loc ) { + const nutrients nutr = p.compute_effective_nutrients( *loc ); return good_bad_none( nutr.kcal ); }, _( "CALORIES" ) ); - append_cell( [ this ]( const item_location & loc ) { - return good_bad_none( get_edible_comestible( loc ).quench ); + append_cell( []( const item_location & loc ) { + return good_bad_none( loc->is_comestible() ? loc->get_comestible()->quench : 0 ); }, _( "QUENCH" ) ); - append_cell( [ &p, this ]( const item_location & loc ) { - const item &it = get_consumable_item( loc ); + append_cell( [&p]( const item_location & loc ) { + const item &it = *loc; if( it.has_flag( flag_MUSHY ) ) { - return highlight_good_bad_none( p.fun_for( get_consumable_item( loc ) ).first ); + return highlight_good_bad_none( p.fun_for( *loc ).first ); } else { - return good_bad_none( p.fun_for( get_consumable_item( loc ) ).first ); + return good_bad_none( p.fun_for( *loc ).first ); } }, _( "JOY" ) ); - append_cell( [ this ]( const item_location & loc ) { - const time_duration spoils = get_edible_comestible( loc ).spoils; + append_cell( []( const item_location & loc ) { + const time_duration spoils = loc->is_comestible() ? loc->get_comestible()->spoils : + calendar::INDEFINITELY_LONG_DURATION; if( spoils > 0_turns ) { return to_string_clipped( spoils ); } @@ -555,8 +549,8 @@ class comestible_inventory_preset : public inventory_selector_preset return std::string( _( "indefinite" ) ); }, _( "SHELF LIFE" ) ); - append_cell( [ this ]( const item_location & loc ) { - const item &it = get_consumable_item( loc ); + append_cell( []( const item_location & loc ) { + const item &it = *loc; int converted_volume_scale = 0; const int charges = std::max( it.charges, 1 ); @@ -569,8 +563,7 @@ class comestible_inventory_preset : public inventory_selector_preset append_cell( [this]( const item_location & loc ) { if( g->u.can_estimate_rot() ) { - const islot_comestible item = get_edible_comestible( loc ); - if( item.spoils > 0_turns ) { + if( loc->is_comestible() && loc->get_comestible()->spoils > 0_turns ) { return get_freshness( loc ); } return std::string( "---" ); @@ -580,9 +573,8 @@ class comestible_inventory_preset : public inventory_selector_preset append_cell( [ this ]( const item_location & loc ) { if( g->u.can_estimate_rot() ) { - const islot_comestible item = get_edible_comestible( loc ); - if( item.spoils > 0_turns ) { - if( !get_consumable_item( loc ).rotten() ) { + if( loc->is_comestible() && loc->get_comestible()->spoils > 0_turns ) { + if( !loc->rotten() ) { return get_time_left_rounded( loc ); } } @@ -591,10 +583,10 @@ class comestible_inventory_preset : public inventory_selector_preset return std::string(); }, _( "SPOILS IN" ) ); - append_cell( [ this, &p ]( const item_location & loc ) { + append_cell( [&p]( const item_location & loc ) { std::string cbm_name; - switch( p.get_cbm_rechargeable_with( get_consumable_item( loc ) ) ) { + switch( p.get_cbm_rechargeable_with( *loc ) ) { case rechargeable_cbm::none: break; case rechargeable_cbm::reactor: @@ -604,7 +596,7 @@ class comestible_inventory_preset : public inventory_selector_preset cbm_name = _( "Furnace" ); break; case rechargeable_cbm::other: - std::vector bids = p.get_bionic_fueled_with( get_consumable_item( loc ) ); + std::vector bids = p.get_bionic_fueled_with( *loc ); if( !bids.empty() ) { bionic_id bid = p.get_most_efficient_bionic( bids ); cbm_name = bid->name.translated(); @@ -619,19 +611,19 @@ class comestible_inventory_preset : public inventory_selector_preset return std::string(); }, _( "CBM" ) ); - append_cell( [ this, &p ]( const item_location & loc ) { - return good_bad_none( p.get_acquirable_energy( get_consumable_item( loc ) ) ); + append_cell( [&p]( const item_location & loc ) { + return good_bad_none( p.get_acquirable_energy( *loc ) ); }, _( "ENERGY (kJ)" ) ); } bool is_shown( const item_location &loc ) const override { - return p.can_consume( *loc ); + return p.can_consume_as_is( *loc ); } std::string get_denial( const item_location &loc ) const override { const item &med = *loc; - if( loc->made_of_from_type( LIQUID ) && !g->m.has_flag( flag_LIQUIDCONT, loc.position() ) ) { + if( loc->made_of_from_type( LIQUID ) && loc.where() != item_location::type::container ) { return _( "Can't drink spilt liquids" ); } @@ -639,9 +631,9 @@ class comestible_inventory_preset : public inventory_selector_preset return _( "Your biology is not compatible with that item." ); } - const auto &it = get_consumable_item( loc ); - const auto res = p.can_eat( it ); - const auto cbm = p.get_cbm_rechargeable_with( it ); + const item &it = *loc; + const ret_val res = p.can_eat( it ); + const rechargeable_cbm cbm = p.get_cbm_rechargeable_with( it ); if( !res.success() && cbm == rechargeable_cbm::none ) { return res.str(); @@ -666,7 +658,7 @@ class comestible_inventory_preset : public inventory_selector_preset protected: int get_order( const item_location &loc, const time_duration &time ) const { - if( get_consumable_item( loc ).rotten() ) { + if( loc->rotten() ) { if( p.has_trait( trait_SAPROPHAGE ) || p.has_trait( trait_SAPROVORE ) ) { return 1; } else { @@ -679,16 +671,6 @@ class comestible_inventory_preset : public inventory_selector_preset } } - // WARNING: this can return consumables which are not necessarily possessing - // the comestible type. please dereference responsibly. - const item &get_consumable_item( const item_location &loc ) const { - return p.get_consumable_from( const_cast( *loc ) ); - } - - const islot_comestible &get_edible_comestible( const item_location &loc ) const { - return get_edible_comestible( get_consumable_item( loc ) ); - } - const islot_comestible &get_edible_comestible( const item &it ) const { if( it.is_comestible() && p.can_eat( it ).success() ) { // Ok since can_eat() returns false if is_craft() is true @@ -700,9 +682,10 @@ class comestible_inventory_preset : public inventory_selector_preset time_duration get_time_left( const item_location &loc ) const { time_duration time_left = 0_turns; - const time_duration shelf_life = get_edible_comestible( loc ).spoils; + const time_duration shelf_life = loc->is_comestible() ? loc->get_comestible()->spoils : + calendar::INDEFINITELY_LONG_DURATION; if( shelf_life > 0_turns ) { - const item &it = get_consumable_item( loc ); + const item &it = *loc; const double relative_rot = it.get_relative_rot(); time_left = shelf_life - shelf_life * relative_rot; @@ -717,7 +700,7 @@ class comestible_inventory_preset : public inventory_selector_preset } std::string get_time_left_rounded( const item_location &loc ) const { - const item &it = get_consumable_item( loc ); + const item &it = *loc; if( it.is_going_bad() ) { return _( "soon!" ); } @@ -727,7 +710,7 @@ class comestible_inventory_preset : public inventory_selector_preset } std::string get_freshness( const item_location &loc ) { - const item &it = get_consumable_item( loc ); + const item &it = *loc; const double rot_progress = it.get_relative_rot(); if( it.is_fresh() ) { return _( "fresh" ); @@ -787,7 +770,7 @@ class comestible_filtered_inventory_preset : public comestible_inventory_preset bool is_shown( const item_location &loc ) const override { return comestible_inventory_preset::is_shown( loc ) && - predicate( get_consumable_item( loc ) ); + predicate( *loc ); } private: @@ -1623,9 +1606,6 @@ static item_location autodoc_internal( player &u, player &patient, inv_s.set_hint( hint ); inv_s.set_display_stats( false ); - std::pair init_pair; - bool init_selection = false; - bool need_refresh = true; do { u.inv.restack( u ); @@ -1633,12 +1613,6 @@ static item_location autodoc_internal( player &u, player &patient, inv_s.add_character_items( u ); inv_s.add_nearby_items( radius ); - if( init_selection ) { - inv_s.update( need_refresh ); - inv_s.select_position( init_pair ); - init_selection = false; - } - if( inv_s.empty() ) { popup( _( "You don't have any bionics to install." ), PF_GET_KEY ); return item_location(); @@ -1998,9 +1972,6 @@ static item_location autoclave_internal( player &u, inv_s.set_hint( _( "Select one CBM to sterilize" ) ); inv_s.set_display_stats( false ); - std::pair init_pair; - bool init_selection = false; - bool need_refresh = true; do { u.inv.restack( u ); @@ -2008,12 +1979,6 @@ static item_location autoclave_internal( player &u, inv_s.add_character_items( u ); inv_s.add_nearby_items( radius ); - if( init_selection ) { - inv_s.update( need_refresh ); - inv_s.select_position( init_pair ); - init_selection = false; - } - if( inv_s.empty() ) { popup( _( "You don't have any CBM to sterilize." ), PF_GET_KEY ); return item_location(); diff --git a/src/inventory_ui.cpp b/src/inventory_ui.cpp index c919dea9a6bad..8c20715d3f063 100644 --- a/src/inventory_ui.cpp +++ b/src/inventory_ui.cpp @@ -473,9 +473,10 @@ const inventory_column::entry_cell_cache_t &inventory_column::get_entry_cell_cac return entries_cell_cache[index]; } -void inventory_column::set_width( const size_t new_width ) +void inventory_column::set_width( const size_t new_width, + const std::vector &all_columns ) { - reset_width(); + reset_width( all_columns ); int width_gap = get_width() - new_width; // Now adjust the width if we must while( width_gap != 0 ) { @@ -551,7 +552,7 @@ void inventory_column::expand_to_fit( const inventory_entry &entry ) } } -void inventory_column::reset_width() +void inventory_column::reset_width( const std::vector & ) { for( auto &elem : cells ) { elem = cell_t(); @@ -743,6 +744,7 @@ void inventory_column::prepare_paging( const std::string &filter ) return preset.get_filter( filter ); } ); + // FIXME: toggled status of multiselect menu resets when filtering the menu // First, remove all non-items const auto new_end = std::remove_if( entries.begin(), entries.end(), [&filter_fn]( const inventory_entry & entry ) { @@ -882,7 +884,7 @@ void inventory_column::draw( const catacurses::window &win, size_t x, size_t y ) } int contained_offset = 0; - if( entry.is_item() ) { + if( entry.is_item() && indent_entries() ) { // indent items that are contained contained_offset = num_parents( entry.locations.front() ); } @@ -995,6 +997,25 @@ selection_column::selection_column( const std::string &id, const std::string &na selection_column::~selection_column() = default; +void selection_column::reset_width( const std::vector &all_columns ) +{ + inventory_column::reset_width( all_columns ); + + const auto always_yes = []( const inventory_entry & ) { + return true; + }; + + for( const inventory_column *const col : all_columns ) { + if( col && !dynamic_cast( col ) ) { + for( const inventory_entry *const ent : col->get_entries( always_yes ) ) { + if( ent ) { + expand_to_fit( *ent ); + } + } + } + } +} + void selection_column::prepare_paging( const std::string &filter ) { inventory_column::prepare_paging( filter ); @@ -1137,9 +1158,11 @@ void inventory_selector::add_entry( inventory_column &target_column, preset.get_denial( locations.front() ).empty() ); target_column.add_entry( entry ); - on_entry_add( entry ); - layout_is_valid = false; + shared_ptr_fast current_ui = ui.lock(); + if( current_ui ) { + current_ui->mark_resize(); + } } void inventory_selector::add_item( inventory_column &target_column, @@ -1295,6 +1318,8 @@ inventory_entry *inventory_selector::find_entry_by_invlet( int invlet ) const return nullptr; } +// FIXME: if columns are merged due to low screen width, they will not be splitted +// once screen width becomes enough for the columns. void inventory_selector::rearrange_columns( size_t client_width ) { while( is_overflown( client_width ) ) { @@ -1313,6 +1338,7 @@ void inventory_selector::prepare_layout( size_t client_width, size_t client_heig // This block adds categories and should go before any width evaluations for( auto &elem : columns ) { elem->set_height( client_height ); + elem->reset_width( columns ); elem->prepare_paging( filter ); } // Handle screen overflow @@ -1321,7 +1347,7 @@ void inventory_selector::prepare_layout( size_t client_width, size_t client_heig // the available with -> expand it auto visible_columns = get_visible_columns(); if( visible_columns.size() == 1 && are_columns_centered( client_width ) ) { - visible_columns.front()->set_width( client_width ); + visible_columns.front()->set_width( client_width, columns ); } int custom_invlet = '0'; @@ -1335,14 +1361,6 @@ void inventory_selector::prepare_layout( size_t client_width, size_t client_heig void inventory_selector::prepare_layout() { - for( auto &elem : columns ) { - elem->prepare_paging(); - } - - if( layout_is_valid ) { - return; - } - const auto snap = []( size_t cur_dim, size_t max_dim ) { return cur_dim + 2 * max_win_snap_distance >= max_dim ? max_dim : cur_dim; }; @@ -1359,7 +1377,23 @@ void inventory_selector::prepare_layout() prepare_layout( win_width - nc_width, win_height - nc_height ); resize_window( win_width, win_height ); - layout_is_valid = true; +} + +shared_ptr_fast inventory_selector::create_or_get_ui_adaptor() +{ + shared_ptr_fast current_ui = ui.lock(); + if( !current_ui ) { + ui = current_ui = make_shared_fast(); + current_ui->on_screen_resize( [this]( ui_adaptor & ) { + prepare_layout(); + } ); + current_ui->mark_resize(); + + current_ui->on_redraw( [this]( const ui_adaptor & ) { + refresh_window(); + } ); + } + return current_ui; } size_t inventory_selector::get_layout_width() const @@ -1509,9 +1543,14 @@ std::vector inventory_selector::get_stats() const void inventory_selector::resize_window( int width, int height ) { - if( !w_inv || width != getmaxx( w_inv ) || height != getmaxy( w_inv ) ) { - w_inv = catacurses::newwin( height, width, - point( ( TERMX - width ) / 2, ( TERMY - height ) / 2 ) ); + w_inv = catacurses::newwin( height, width, + point( ( TERMX - width ) / 2, ( TERMY - height ) / 2 ) ); + if( spopup ) { + spopup->window( w_inv, point( 4, getmaxy( w_inv ) - 1 ), ( getmaxx( w_inv ) / 2 ) - 4 ); + } + shared_ptr_fast current_ui = ui.lock(); + if( current_ui ) { + current_ui->position_from_window( w_inv ); } } @@ -1531,41 +1570,46 @@ void inventory_selector::refresh_window() const void inventory_selector::set_filter() { - string_input_popup spopup; - spopup.window( w_inv, point( 4, getmaxy( w_inv ) - 1 ), ( getmaxx( w_inv ) / 2 ) - 4 ) - .max_length( 256 ) + spopup = std::make_unique(); + spopup->max_length( 256 ) .text( filter ); + shared_ptr_fast current_ui = ui.lock(); + if( current_ui ) { + current_ui->mark_resize(); + } + ime_sentry sentry; do { - mvwprintz( w_inv, point( 2, getmaxy( w_inv ) - 1 ), c_cyan, "< " ); - mvwprintz( w_inv, point( ( getmaxx( w_inv ) / 2 ) - 4, getmaxy( w_inv ) - 1 ), c_cyan, " >" ); + ui_manager::redraw(); + spopup->query_string( /*loop=*/false ); + } while( !spopup->confirmed() && !spopup->canceled() ); - std::string new_filter = spopup.query_string( false ); - if( spopup.context().get_raw_input().get_first_input() == KEY_ESCAPE ) { - filter.clear(); - } else { - filter = new_filter; + if( spopup->confirmed() ) { + filter = spopup->text(); + for( const auto elem : columns ) { + elem->set_filter( filter ); + } + if( current_ui ) { + current_ui->mark_resize(); } - - wrefresh( w_inv ); - } while( spopup.context().get_raw_input().get_first_input() != '\n' && - spopup.context().get_raw_input().get_first_input() != KEY_ESCAPE ); - - for( const auto elem : columns ) { - elem->set_filter( filter ); } - layout_is_valid = false; + + spopup.reset(); } void inventory_selector::set_filter( const std::string &str ) { + prepare_layout(); filter = str; for( const auto elem : columns ) { elem->set_filter( filter ); } - layout_is_valid = false; + shared_ptr_fast current_ui = ui.lock(); + if( current_ui ) { + current_ui->mark_resize(); + } } std::string inventory_selector::get_filter() const @@ -1573,18 +1617,6 @@ std::string inventory_selector::get_filter() const return filter; } -void inventory_selector::update( bool &need_refresh ) -{ - if( need_refresh ) { - g->draw_ter(); - wrefresh( g->w_terrain ); - g->draw_panels( true ); - need_refresh = false; - } - prepare_layout(); - refresh_window(); -} - void inventory_selector::draw_columns( const catacurses::window &w ) const { const auto columns = get_visible_columns(); @@ -1644,30 +1676,37 @@ std::pair inventory_selector::get_footer( navigation_mode void inventory_selector::draw_footer( const catacurses::window &w ) const { - int filter_offset = 0; - if( has_available_choices() || !filter.empty() ) { - std::string text = string_format( filter.empty() ? _( "[%s] Filter" ) : _( "[%s] Filter: " ), - ctxt.get_desc( "INVENTORY_FILTER" ) ); - filter_offset = utf8_width( text + filter ) + 6; + if( spopup ) { + mvwprintz( w_inv, point( 2, getmaxy( w_inv ) - 1 ), c_cyan, "< " ); + mvwprintz( w_inv, point( ( getmaxx( w_inv ) / 2 ) - 4, getmaxy( w_inv ) - 1 ), c_cyan, " >" ); - mvwprintz( w, point( 2, getmaxy( w ) - border ), c_light_gray, "< " ); - wprintz( w, c_light_gray, text ); - wprintz( w, c_white, filter ); - wprintz( w, c_light_gray, " >" ); - } + std::string new_filter = spopup->query_string( /*loop=*/false, /*draw_only=*/true ); + } else { + int filter_offset = 0; + if( has_available_choices() || !filter.empty() ) { + std::string text = string_format( filter.empty() ? _( "[%s] Filter" ) : _( "[%s] Filter: " ), + ctxt.get_desc( "INVENTORY_FILTER" ) ); + filter_offset = utf8_width( text + filter ) + 6; + + mvwprintz( w, point( 2, getmaxy( w ) - border ), c_light_gray, "< " ); + wprintz( w, c_light_gray, text ); + wprintz( w, c_white, filter ); + wprintz( w, c_light_gray, " >" ); + } - const auto footer = get_footer( mode ); - if( !footer.first.empty() ) { - const int string_width = utf8_width( footer.first ); - const int x1 = filter_offset + std::max( getmaxx( w ) - string_width - filter_offset, 0 ) / 2; - const int x2 = x1 + string_width - 1; - const int y = getmaxy( w ) - border; + const auto footer = get_footer( mode ); + if( !footer.first.empty() ) { + const int string_width = utf8_width( footer.first ); + const int x1 = filter_offset + std::max( getmaxx( w ) - string_width - filter_offset, 0 ) / 2; + const int x2 = x1 + string_width - 1; + const int y = getmaxy( w ) - border; - mvwprintz( w, point( x1, y ), footer.second, footer.first ); - mvwputch( w, point( x1 - 1, y ), c_light_gray, ' ' ); - mvwputch( w, point( x2 + 1, y ), c_light_gray, ' ' ); - mvwputch( w, point( x1 - 2, y ), c_light_gray, LINE_XOXX ); - mvwputch( w, point( x2 + 2, y ), c_light_gray, LINE_XXXO ); + mvwprintz( w, point( x1, y ), footer.second, footer.first ); + mvwputch( w, point( x1 - 1, y ), c_light_gray, ' ' ); + mvwputch( w, point( x2 + 1, y ), c_light_gray, ' ' ); + mvwputch( w, point( x1 - 2, y ), c_light_gray, LINE_XOXX ); + mvwputch( w, point( x2 + 2, y ), c_light_gray, LINE_XXXO ); + } } } @@ -1866,17 +1905,15 @@ const navigation_mode_data &inventory_selector::get_navigation_data( navigation_ item_location inventory_pick_selector::execute() { - // FIXME: temporarily disable redrawing of lower UIs before this UI is migrated to `ui_adaptor` - ui_adaptor ui( ui_adaptor::disable_uis_below {} ); - - bool need_refresh = true; + shared_ptr_fast ui = create_or_get_ui_adaptor(); while( true ) { - update( need_refresh ); + ui_manager::redraw(); + const inventory_input input = get_input(); if( input.entry != nullptr ) { if( select( input.entry->any_item() ) ) { - refresh_window(); + ui_manager::redraw(); } return input.entry->any_item(); } else if( input.action == "QUIT" ) { @@ -1895,10 +1932,6 @@ item_location inventory_pick_selector::execute() if( input.action == "TOGGLE_FAVORITE" ) { return item_location(); } - - if( input.action == "HELP_KEYBINDINGS" || input.action == "INVENTORY_FILTER" ) { - need_refresh = true; - } } } @@ -1924,24 +1957,14 @@ void inventory_multiselector::rearrange_columns( size_t client_width ) selection_col->set_visibility( !is_overflown( client_width ) ); } -void inventory_multiselector::on_entry_add( const inventory_entry &entry ) -{ - if( entry.is_item() ) { - dynamic_cast( selection_col.get() )->expand_to_fit( entry ); - } -} - inventory_compare_selector::inventory_compare_selector( player &p ) : inventory_multiselector( p, default_preset, _( "ITEMS TO COMPARE" ) ) {} std::pair inventory_compare_selector::execute() { - // FIXME: temporarily disable redrawing of lower UIs before this UI is migrated to `ui_adaptor` - ui_adaptor ui( ui_adaptor::disable_uis_below {} ); - - bool need_refresh = true; + shared_ptr_fast ui = create_or_get_ui_adaptor(); while( true ) { - update( need_refresh ); + ui_manager::redraw(); const inventory_input input = get_input(); @@ -2016,13 +2039,11 @@ inventory_iuse_selector::inventory_iuse_selector( {} drop_locations inventory_iuse_selector::execute() { - // FIXME: temporarily disable redrawing of lower UIs before this UI is migrated to `ui_adaptor` - ui_adaptor ui( ui_adaptor::disable_uis_below {} ); + shared_ptr_fast ui = create_or_get_ui_adaptor(); int count = 0; - bool need_refresh = true; while( true ) { - update( need_refresh ); + ui_manager::redraw(); const inventory_input input = get_input(); @@ -2182,13 +2203,11 @@ void inventory_drop_selector::deselect_contained_items() drop_locations inventory_drop_selector::execute() { - // FIXME: temporarily disable redrawing of lower UIs before this UI is migrated to `ui_adaptor` - ui_adaptor ui( ui_adaptor::disable_uis_below {} ); + shared_ptr_fast ui = create_or_get_ui_adaptor(); int count = 0; - bool need_refresh = true; while( true ) { - update( need_refresh ); + ui_manager::redraw(); const inventory_input input = get_input(); @@ -2260,7 +2279,6 @@ drop_locations inventory_drop_selector::execute() return drop_locations(); } else if( input.action == "INVENTORY_FILTER" ) { set_filter(); - need_refresh = true; } else if( input.action == "TOGGLE_FAVORITE" ) { // TODO: implement favoriting in multi selection menus while maintaining selection } else { diff --git a/src/inventory_ui.h b/src/inventory_ui.h index ed632404ba0b4..132091e590c81 100644 --- a/src/inventory_ui.h +++ b/src/inventory_ui.h @@ -19,6 +19,7 @@ #include "cursesdef.h" #include "input.h" #include "item_location.h" +#include "memory_fast.h" #include "pimpl.h" #include "units.h" #include "item_category.h" @@ -26,7 +27,9 @@ class Character; class item; class player; +class string_input_popup; struct tripoint; +class ui_adaptor; enum class navigation_mode : int { ITEM = 0, @@ -122,6 +125,9 @@ class inventory_entry private: const item_category *custom_category = nullptr; bool enabled = true; + protected: + // indents the entry if it is contained in an item + bool _indent = true; }; @@ -165,6 +171,10 @@ class inventory_selector_preset virtual std::function get_filter( const std::string &filter ) const; + bool indent_entries() const { + return _indent_entries; + } + protected: /** Text of the first column (default: item name) */ virtual std::string get_caption( const inventory_entry &entry ) const; @@ -182,6 +192,9 @@ class inventory_selector_preset const std::string &stub = std::string() ); bool check_components = false; + // whether to indent contained entries in the menu + bool _indent_entries = true; + private: class cell_t { @@ -288,14 +301,14 @@ class inventory_column this->visibility = visibility; } - void set_width( size_t new_width ); + void set_width( size_t new_width, const std::vector &all_columns ); void set_height( size_t new_height ); size_t get_width() const; size_t get_height() const; /** Expands the column to fit the new entry. */ void expand_to_fit( const inventory_entry &entry ); /** Resets width to original (unchanged). */ - void reset_width(); + virtual void reset_width( const std::vector &all_columns ); /** Returns next custom inventory letter. */ int reassign_custom_invlets( const player &p, int min_invlet, int max_invlet ); /** Reorder entries, repopulate titles, adjust to the new height. */ @@ -321,6 +334,11 @@ class inventory_column void set_filter( const std::string &filter ); + // whether or not to indent contained entries + bool indent_entries() const { + return preset.indent_entries(); + }; + protected: struct entry_cell_cache_t { bool assigned = false; @@ -409,6 +427,8 @@ class selection_column : public inventory_column return false; } + void reset_width( const std::vector &all_columns ) override; + void prepare_paging( const std::string &filter = "" ) override; void on_change( const inventory_entry &entry ) override; @@ -494,14 +514,11 @@ class inventory_selector /** Entry has been changed */ void on_change( const inventory_entry &entry ); - void prepare_layout( size_t client_width, size_t client_height ); - void prepare_layout(); + shared_ptr_fast create_or_get_ui_adaptor(); size_t get_layout_width() const; size_t get_layout_height() const; - void resize_window( int width, int height ); - void refresh_window() const; void set_filter(); /** Tackles screen overflow */ @@ -523,11 +540,6 @@ class inventory_selector size_t get_header_min_width() const; size_t get_footer_min_width() const; - void draw_header( const catacurses::window &w ) const; - void draw_footer( const catacurses::window &w ) const; - void draw_columns( const catacurses::window &w ) const; - void draw_frame( const catacurses::window &w ) const; - /** @return an entry from all entries by its invlet */ inventory_entry *find_entry_by_invlet( int invlet ) const; @@ -536,10 +548,21 @@ class inventory_selector } std::vector get_visible_columns() const; - public: + private: + // These functions are called from resizing/redraw callbacks of ui_adaptor + // and should not be made protected or public. + void prepare_layout( size_t client_width, size_t client_height ); + void prepare_layout(); - void update( bool &need_refresh ); + void resize_window( int width, int height ); + void refresh_window() const; + void draw_header( const catacurses::window &w ) const; + void draw_footer( const catacurses::window &w ) const; + void draw_columns( const catacurses::window &w ) const; + void draw_frame( const catacurses::window &w ) const; + + public: /** * Select a location * @param loc Location to select @@ -552,6 +575,7 @@ class inventory_selector } void select_position( std::pair position ) { + prepare_layout(); set_active_column( position.first ); get_active_column().select( position.second, scroll_direction::BACKWARD ); } @@ -598,14 +622,15 @@ class inventory_selector } void toggle_navigation_mode(); - /** Entry has been added */ - virtual void on_entry_add( const inventory_entry & ) {} - const navigation_mode_data &get_navigation_data( navigation_mode m ) const; private: catacurses::window w_inv; + weak_ptr_fast ui; + + std::unique_ptr spopup; + std::vector columns; std::string title; @@ -623,7 +648,6 @@ class inventory_selector bool is_empty = true; bool display_stats = true; - bool layout_is_valid = false; }; inventory_selector::stat display_stat( const std::string &caption, int cur_value, int max_value, @@ -646,7 +670,6 @@ class inventory_multiselector : public inventory_selector const std::string &selection_column_title = "" ); protected: void rearrange_columns( size_t client_width ) override; - void on_entry_add( const inventory_entry &entry ) override; private: std::unique_ptr selection_col; diff --git a/src/line.cpp b/src/line.cpp index 1087dd135ff75..36529a0e942e9 100644 --- a/src/line.cpp +++ b/src/line.cpp @@ -25,7 +25,7 @@ void bresenham( const point &p1, const point &p2, int t, const int sx = ( d.x == 0 ) ? 0 : sgn( d.x ); const int sy = ( d.y == 0 ) ? 0 : sgn( d.y ); // Absolute values of slopes x2 to avoid rounding errors. - const point a = abs( d ) * 2; + const point a = d.abs() * 2; point cur = p1; @@ -266,7 +266,7 @@ float rl_dist_exact( const tripoint &loc1, const tripoint &loc2 ) int manhattan_dist( const point &loc1, const point &loc2 ) { - const point d = abs( loc1 - loc2 ); + const point d = ( loc1 - loc2 ).abs(); return d.x + d.y; } diff --git a/src/line.h b/src/line.h index 88a12bc9bf7fb..5b7a2158509f5 100644 --- a/src/line.h +++ b/src/line.h @@ -163,12 +163,12 @@ inline float trig_dist( const point &loc1, const point &loc2 ) // Roguelike distance; maximum of dX and dY inline int square_dist( const tripoint &loc1, const tripoint &loc2 ) { - const tripoint d = abs( loc1 - loc2 ); + const tripoint d = ( loc1 - loc2 ).abs(); return std::max( { d.x, d.y, d.z } ); } inline int square_dist( const point &loc1, const point &loc2 ) { - const point d = abs( loc1 - loc2 ); + const point d = ( loc1 - loc2 ).abs(); return std::max( d.x, d.y ); } @@ -225,7 +225,7 @@ inline FastDistanceApproximation trig_dist_fast( const tripoint &loc1, const tri } inline FastDistanceApproximation square_dist_fast( const tripoint &loc1, const tripoint &loc2 ) { - const tripoint d = abs( loc1 - loc2 ); + const tripoint d = ( loc1 - loc2 ).abs(); return std::max( { d.x, d.y, d.z } ); } inline FastDistanceApproximation rl_dist_fast( const tripoint &loc1, const tripoint &loc2 ) diff --git a/src/magic_spell_effect.cpp b/src/magic_spell_effect.cpp index acf08815f6cac..1be6d84a4a423 100644 --- a/src/magic_spell_effect.cpp +++ b/src/magic_spell_effect.cpp @@ -233,7 +233,7 @@ std::set spell_effect::spell_effect_line( const spell &, const tripoin // Clockwise Perpendicular of Delta vector const point delta_perp( -delta.y, delta.x ); - const point abs_delta = abs( delta ); + const point abs_delta = delta.abs(); // Primary axis of delta vector const point axis_delta = abs_delta.x > abs_delta.y ? point( delta.x, 0 ) : point( 0, delta.y ); // Clockwise Perpendicular of axis vector diff --git a/src/point.h b/src/point.h index a724265687fc3..5bfaba1a153e2 100644 --- a/src/point.h +++ b/src/point.h @@ -72,6 +72,12 @@ struct point { return point( x / rhs, y / rhs ); } +#ifndef CATA_NO_STL + inline point abs() const { + return point( std::abs( x ), std::abs( y ) ); + } +#endif + /** * Rotate point clockwise @param turns times, 90 degrees per turn, * around the center of a rectangle with the dimensions specified @@ -178,6 +184,12 @@ struct tripoint { return *this; } +#ifndef CATA_NO_STL + inline tripoint abs() const { + return tripoint( std::abs( x ), std::abs( y ), std::abs( z ) ); + } +#endif + constexpr point xy() const { return point( x, y ); } @@ -311,16 +323,6 @@ std::vector closest_tripoints_first( const tripoint ¢er, int min_d std::vector closest_points_first( const point ¢er, int max_dist ); std::vector closest_points_first( const point ¢er, int min_dist, int max_dist ); -inline point abs( const point &p ) -{ - return point( std::abs( p.x ), std::abs( p.y ) ); -} - -inline tripoint abs( const tripoint &p ) -{ - return tripoint( std::abs( p.x ), std::abs( p.y ), std::abs( p.z ) ); -} - static constexpr tripoint tripoint_min { INT_MIN, INT_MIN, INT_MIN }; static constexpr tripoint tripoint_max{ INT_MAX, INT_MAX, INT_MAX }; diff --git a/src/tileray.cpp b/src/tileray.cpp index 3d595eadb7096..b5724b2656188 100644 --- a/src/tileray.cpp +++ b/src/tileray.cpp @@ -26,7 +26,7 @@ tileray::tileray( int adir ): direction( adir ) void tileray::init( const point &ad ) { delta = ad; - abs_d = abs( delta ); + abs_d = delta.abs(); if( delta == point_zero ) { direction = 0; } else { @@ -49,7 +49,7 @@ void tileray::init( int adir ) float direction_radians = static_cast( direction ) * M_PI / 180.0; rl_vec2d delta_f( std::cos( direction_radians ), std::sin( direction_radians ) ); delta = ( delta_f * 100 ).as_point(); - abs_d = abs( delta ); + abs_d = delta.abs(); steps = 0; infinite = true; } diff --git a/src/translations.cpp b/src/translations.cpp index f7eff7ad15d7c..432c8becccf32 100644 --- a/src/translations.cpp +++ b/src/translations.cpp @@ -703,7 +703,10 @@ bool localized_comparator::operator()( const std::string &l, const std::string & kCFStringEncodingUTF8, kCFAllocatorNull ); CFStringRef rr = CFStringCreateWithCStringNoCopy( kCFAllocatorDefault, r.c_str(), kCFStringEncodingUTF8, kCFAllocatorNull ); - return CFStringCompare( lr, rr, kCFCompareLocalized ) < 0; + bool result = CFStringCompare( lr, rr, kCFCompareLocalized ) < 0; + CFRelease( lr ); + CFRelease( rr ); + return result; #endif return std::locale()( l, r ); } diff --git a/tests/iteminfo_test.cpp b/tests/iteminfo_test.cpp index 1d7195ba2df5e..5e9c57890f9c4 100644 --- a/tests/iteminfo_test.cpp +++ b/tests/iteminfo_test.cpp @@ -11,6 +11,7 @@ #include "player_helpers.h" #include "options_helpers.h" #include "recipe.h" +#include "recipe_dictionary.h" #include "type_id.h" #include "value_ptr.h" @@ -530,11 +531,14 @@ TEST_CASE( "show available recipes with item as an ingredient", "[item][iteminfo iteminfo_query q = q_vec( { iteminfo_parts::DESCRIPTION_APPLICABLE_RECIPES } ); const recipe *purtab = &recipe_id( "pur_tablets" ).obj(); g->u.clear_mutations(); + recipe_subset &known_recipes = const_cast( g->u.get_learned_recipes() ); + known_recipes.clear(); GIVEN( "character has a potassium iodide tablet and no skill" ) { g->u.worn.push_back( item( "backpack" ) ); item &iodine = g->u.i_add( item( "iodine" ) ); g->u.empty_skills(); + REQUIRE( !g->u.knows_recipe( purtab ) ); THEN( "nothing is craftable from it" ) { test_info_equals( @@ -566,7 +570,11 @@ TEST_CASE( "show available recipes with item as an ingredient", "[item][iteminfo } WHEN( "they have the recipe in a book, but not memorized" ) { - g->u.i_add( item( "textbook_chemistry" ) ); + item &textbook = g->u.i_add( item( "textbook_chemistry" ) ); + g->u.do_read( textbook ); + REQUIRE( g->u.has_identified( "textbook_chemistry" ) ); + // update the crafting inventory cache + g->u.moves++; THEN( "they can use potassium iodide tablets to craft it" ) { test_info_equals(