diff --git a/Makefile b/Makefile index 496e8507b2305..eec8f528a41ce 100644 --- a/Makefile +++ b/Makefile @@ -586,15 +586,20 @@ else else NCURSES_PREFIX = ncurses endif + ifdef OSXCROSS + NCURSES_PREFIX = ncurses + endif # ONLY when not cross-compiling, check for pkg-config or ncurses5-config # When doing a cross-compile, we can't rely on the host machine's -configs ifeq ($(CROSS),) - ifneq ($(shell pkg-config --libs $(NCURSES_PREFIX) 2>/dev/null),) - HAVE_PKGCONFIG = 1 - endif - ifneq ($(shell which $(NCURSES_PREFIX)5-config 2>/dev/null),) - HAVE_NCURSES5CONFIG = 1 - endif + ifeq ($(OSXCROSS),) + ifneq ($(shell pkg-config --libs $(NCURSES_PREFIX) 2>/dev/null),) + HAVE_PKGCONFIG = 1 + endif + ifneq ($(shell which $(NCURSES_PREFIX)5-config 2>/dev/null),) + HAVE_NCURSES5CONFIG = 1 + endif + endif endif # Link to ncurses if we're using a non-tiles, Linux build @@ -611,8 +616,8 @@ else endif ifdef OSXCROSS - LDFLAGS += -L$(LIBSDIR)/ncurses/lib - CXXFLAGS += -I$(LIBSDIR)/ncurses/include + LDFLAGS += -L$(LIBSDIR)/$(NCURSES_PREFIX)/lib + CXXFLAGS += -I$(LIBSDIR)/$(NCURSES_PREFIX)/include endif # OSXCROSS endif # HAVE_NCURSES5CONFIG endif # HAVE_PKGCONFIG diff --git a/data/json/itemgroups/collections_domestic.json b/data/json/itemgroups/collections_domestic.json index eaf86cbfa6375..9629af4f5f328 100644 --- a/data/json/itemgroups/collections_domestic.json +++ b/data/json/itemgroups/collections_domestic.json @@ -35,6 +35,7 @@ [ "ceramic_bowl", 50 ], [ "ceramic_cup", 20 ], [ "ceramic_mug", 20 ], + [ "wine_glass", 20 ], [ "plastic_plate", 50 ], [ "tumbler_plastic", 50 ], [ "bowl_pewter", 25 ], diff --git a/data/json/itemgroups/misc.json b/data/json/itemgroups/misc.json index 9700e57ffd40a..09466e08d9874 100644 --- a/data/json/itemgroups/misc.json +++ b/data/json/itemgroups/misc.json @@ -51,6 +51,7 @@ [ "glass_plate", 20 ], [ "glass_bowl", 20 ], [ "ceramic_plate", 10 ], + [ "wine_glass", 10 ], [ "ceramic_bowl", 10 ], [ "ceramic_cup", 10 ] ] diff --git a/data/json/items/generic.json b/data/json/items/generic.json index 438dd84937493..4f34470e7e856 100644 --- a/data/json/items/generic.json +++ b/data/json/items/generic.json @@ -700,20 +700,6 @@ "weight": "3220 g", "volume": "750 ml" }, - { - "type": "GENERIC", - "id": "leaf_spring", - "symbol": ",", - "color": "light_gray", - "name": "leaf spring", - "category": "spare_parts", - "description": "A large, heavy-duty leaf spring. Probably from some car or truck, and looks an awful lot like a bow. You can barely bend it...", - "price": 5000, - "price_postapoc": 500, - "material": "steel", - "weight": "8440 g", - "volume": "5 L" - }, { "type": "GENERIC", "id": "lawnmower", @@ -1848,19 +1834,6 @@ "to_hit": -2, "flags": [ "TRADER_AVOID" ] }, - { - "type": "GENERIC", - "id": "poppy_flower", - "name": "poppy flower", - "description": "A poppy stalk with some petals.", - "weight": "40 g", - "to_hit": -3, - "color": "light_red", - "symbol": ",", - "material": [ "veggy" ], - "volume": "250 ml", - "price": 0 - }, { "type": "GENERIC", "id": "poppy_bud", @@ -1874,253 +1847,6 @@ "volume": 0, "price": 200 }, - { - "type": "GENERIC", - "id": "bluebell_bud", - "name": "bluebell bud", - "description": "A bluebell bud. Contains some substances commonly produced by a bluebell flower.", - "weight": "30 g", - "to_hit": -3, - "color": "blue", - "symbol": ",", - "material": [ "veggy" ], - "volume": "250 ml", - "price": 200 - }, - { - "type": "GENERIC", - "id": "dahlia_flower", - "name": "dahlia", - "description": "A dahlia stalk with some petals.", - "weight": "40 g", - "to_hit": -3, - "color": "magenta", - "symbol": ",", - "material": [ "veggy" ], - "volume": "250 ml", - "price": 0 - }, - { - "type": "GENERIC", - "id": "dahlia_bud", - "name": "dahlia bud", - "description": "A dahlia bud. Contains some substances commonly produced by a dahlia.", - "weight": "30 g", - "to_hit": -3, - "color": "magenta", - "symbol": ",", - "material": [ "veggy" ], - "volume": "250 ml", - "price": 200 - }, - { - "type": "GENERIC", - "id": "rose_flower", - "name": "rose", - "description": "A rose stalk with some petals.", - "weight": "40 g", - "to_hit": -3, - "color": "red", - "symbol": ",", - "material": [ "veggy" ], - "volume": "250 ml", - "price": 0 - }, - { - "type": "GENERIC", - "id": "rose_bud", - "name": "rose bud", - "description": "A rose bud. Contains some substances commonly produced by a rose flower.", - "weight": "30 g", - "to_hit": -3, - "color": "red", - "symbol": ",", - "material": [ "veggy" ], - "volume": "250 ml", - "price": 200 - }, - { - "type": "GENERIC", - "id": "hydrangea_flower", - "name": "hydrangea", - "description": "A hydrangea stalk with some petals.", - "weight": "40 g", - "to_hit": -3, - "color": "light_blue", - "symbol": ",", - "material": [ "veggy" ], - "volume": "250 ml", - "price": 0 - }, - { - "type": "GENERIC", - "id": "hydrangea_bud", - "name": "hydrangea bud", - "description": "A hydrangea bud. Contains some substances commonly produced by a hydrangea flower.", - "weight": "30 g", - "to_hit": -3, - "color": "light_blue", - "symbol": ",", - "material": [ "veggy" ], - "volume": "250 ml", - "price": 200 - }, - { - "type": "GENERIC", - "id": "tulip_flower", - "name": "tulip", - "description": "A tulip stalk with some petals.", - "weight": "40 g", - "to_hit": -3, - "color": "magenta", - "symbol": ",", - "material": [ "veggy" ], - "volume": "250 ml", - "price": 0 - }, - { - "type": "GENERIC", - "id": "tulip_bud", - "name": "tulip bud", - "description": "A tulip bud. Contains some substances commonly produced by a tulip flower.", - "weight": "30 g", - "to_hit": -3, - "color": "magenta", - "symbol": ",", - "material": [ "veggy" ], - "volume": "250 ml", - "price": 200 - }, - { - "type": "GENERIC", - "id": "spurge_flower", - "name": "spurge", - "description": "A spurge stalk with some petals.", - "weight": "40 g", - "to_hit": -3, - "color": "light_green", - "symbol": ",", - "material": [ "veggy" ], - "volume": "250 ml", - "price": 0 - }, - { - "type": "GENERIC", - "id": "spurge_bud", - "name": "spurge bud", - "description": "A spurge bud. Contains some substances commonly produced by a spurge flower.", - "weight": "30 g", - "to_hit": -3, - "color": "light_green", - "symbol": ",", - "material": [ "veggy" ], - "volume": "250 ml", - "price": 200 - }, - { - "type": "GENERIC", - "id": "black_eyed_susan_flower", - "name": "black eyed susan", - "description": "A black eyed susan stalk with some petals.", - "weight": "40 g", - "to_hit": -3, - "color": "yellow", - "symbol": ",", - "material": [ "veggy" ], - "volume": "250 ml", - "price": 0 - }, - { - "type": "GENERIC", - "id": "black_eyed_susan_bud", - "name": "black eyed susan bud", - "description": "A black eyed susan bud. Contains some substances commonly produced by a black eyed susan flower.", - "weight": "30 g", - "to_hit": -3, - "color": "yellow", - "symbol": ",", - "material": [ "veggy" ], - "volume": "250 ml", - "price": 200 - }, - { - "type": "GENERIC", - "id": "lily_flower", - "name": "lily", - "description": "A lily stalk with some petals.", - "weight": "40 g", - "to_hit": -3, - "color": "magenta", - "symbol": ",", - "material": [ "veggy" ], - "volume": "250 ml", - "price": 0 - }, - { - "type": "GENERIC", - "id": "lily_bud", - "name": "lily bud", - "description": "A lily bud. Contains some substances commonly produced by a lily flower.", - "weight": "30 g", - "to_hit": -3, - "color": "magenta", - "symbol": ",", - "material": [ "veggy" ], - "volume": "250 ml", - "price": 200 - }, - { - "type": "GENERIC", - "id": "lotus_flower", - "name": "lotus", - "description": "A lotus stalk with some petals.", - "weight": "40 g", - "to_hit": -3, - "color": "yellow", - "symbol": ",", - "material": [ "veggy" ], - "volume": "250 ml", - "price": 0 - }, - { - "type": "GENERIC", - "id": "lotus_bud", - "name": "lotus bud", - "description": "A lotus bud. Contains some substances commonly produced by a lotus flower.", - "weight": "30 g", - "to_hit": -3, - "color": "yellow", - "symbol": ",", - "material": [ "veggy" ], - "volume": "250 ml", - "price": 200 - }, - { - "type": "GENERIC", - "id": "lilac_flower", - "name": "lilac", - "description": "A lilac stalk with some petals.", - "weight": "40 g", - "to_hit": -3, - "color": "magenta", - "symbol": ",", - "material": [ "veggy" ], - "volume": "250 ml", - "price": 0 - }, - { - "type": "GENERIC", - "id": "lilac_bud", - "name": "lilac bud", - "description": "A lilac bud. Contains some substances commonly produced by a lilac flower.", - "weight": "30 g", - "to_hit": -3, - "color": "magenta", - "symbol": ",", - "material": [ "veggy" ], - "volume": "250 ml", - "price": 200 - }, { "type": "GENERIC", "id": "sunflower", diff --git a/data/json/items/obsolete.json b/data/json/items/obsolete.json index eb0d0bc578c20..a752625f026bf 100644 --- a/data/json/items/obsolete.json +++ b/data/json/items/obsolete.json @@ -16,6 +16,20 @@ "looks_like": "1st_aid", "flags": [ "ANESTHESIA" ] }, + { + "type": "GENERIC", + "id": "leaf_spring", + "symbol": ",", + "color": "light_gray", + "name": "leaf spring", + "category": "spare_parts", + "description": "A large, heavy-duty leaf spring. Probably from some car or truck, and looks an awful lot like a bow. You can barely bend it...", + "price": 5000, + "price_postapoc": 500, + "material": "steel", + "weight": "8440 g", + "volume": "5 L" + }, { "id": "barrel_big", "type": "GUNMOD", @@ -653,6 +667,227 @@ }, "flags": [ "BOMB", "TRADER_AVOID" ] }, + { + "type": "GENERIC", + "id": "hydrangea_flower", + "name": "hydrangea", + "description": "A hydrangea stalk with some petals.", + "weight": "40 g", + "to_hit": -3, + "color": "light_blue", + "symbol": ",", + "material": [ "veggy" ], + "volume": "250 ml", + "price": 0 + }, + { + "type": "GENERIC", + "id": "hydrangea_bud", + "name": "hydrangea bud", + "description": "A hydrangea bud. Contains some substances commonly produced by a hydrangea flower.", + "weight": "30 g", + "to_hit": -3, + "color": "light_blue", + "symbol": ",", + "material": [ "veggy" ], + "volume": "250 ml", + "price": 200 + }, + { + "type": "GENERIC", + "id": "tulip_flower", + "name": "tulip", + "description": "A tulip stalk with some petals.", + "weight": "40 g", + "to_hit": -3, + "color": "magenta", + "symbol": ",", + "material": [ "veggy" ], + "volume": "250 ml", + "price": 0 + }, + { + "type": "GENERIC", + "id": "tulip_bud", + "name": "tulip bud", + "description": "A tulip bud. Contains some substances commonly produced by a tulip flower.", + "weight": "30 g", + "to_hit": -3, + "color": "magenta", + "symbol": ",", + "material": [ "veggy" ], + "volume": "250 ml", + "price": 200 + }, + { + "type": "GENERIC", + "id": "spurge_flower", + "name": "spurge", + "description": "A spurge stalk with some petals.", + "weight": "40 g", + "to_hit": -3, + "color": "light_green", + "symbol": ",", + "material": [ "veggy" ], + "volume": "250 ml", + "price": 0 + }, + { + "type": "GENERIC", + "id": "spurge_bud", + "name": "spurge bud", + "description": "A spurge bud. Contains some substances commonly produced by a spurge flower.", + "weight": "30 g", + "to_hit": -3, + "color": "light_green", + "symbol": ",", + "material": [ "veggy" ], + "volume": "250 ml", + "price": 200 + }, + { + "type": "GENERIC", + "id": "black_eyed_susan_flower", + "name": "black eyed susan", + "description": "A black eyed susan stalk with some petals.", + "weight": "40 g", + "to_hit": -3, + "color": "yellow", + "symbol": ",", + "material": [ "veggy" ], + "volume": "250 ml", + "price": 0 + }, + { + "type": "GENERIC", + "id": "black_eyed_susan_bud", + "name": "black eyed susan bud", + "description": "A black eyed susan bud. Contains some substances commonly produced by a black eyed susan flower.", + "weight": "30 g", + "to_hit": -3, + "color": "yellow", + "symbol": ",", + "material": [ "veggy" ], + "volume": "250 ml", + "price": 200 + }, + { + "type": "GENERIC", + "id": "lily_flower", + "name": "lily", + "description": "A lily stalk with some petals.", + "weight": "40 g", + "to_hit": -3, + "color": "magenta", + "symbol": ",", + "material": [ "veggy" ], + "volume": "250 ml", + "price": 0 + }, + { + "type": "GENERIC", + "id": "lily_bud", + "name": "lily bud", + "description": "A lily bud. Contains some substances commonly produced by a lily flower.", + "weight": "30 g", + "to_hit": -3, + "color": "magenta", + "symbol": ",", + "material": [ "veggy" ], + "volume": "250 ml", + "price": 200 + }, + { + "type": "GENERIC", + "id": "lotus_flower", + "name": "lotus", + "description": "A lotus stalk with some petals.", + "weight": "40 g", + "to_hit": -3, + "color": "yellow", + "symbol": ",", + "material": [ "veggy" ], + "volume": "250 ml", + "price": 0 + }, + { + "type": "GENERIC", + "id": "lotus_bud", + "name": "lotus bud", + "description": "A lotus bud. Contains some substances commonly produced by a lotus flower.", + "weight": "30 g", + "to_hit": -3, + "color": "yellow", + "symbol": ",", + "material": [ "veggy" ], + "volume": "250 ml", + "price": 200 + }, + { + "type": "GENERIC", + "id": "lilac_flower", + "name": "lilac", + "description": "A lilac stalk with some petals.", + "weight": "40 g", + "to_hit": -3, + "color": "magenta", + "symbol": ",", + "material": [ "veggy" ], + "volume": "250 ml", + "price": 0 + }, + { + "type": "GENERIC", + "id": "lilac_bud", + "name": "lilac bud", + "description": "A lilac bud. Contains some substances commonly produced by a lilac flower.", + "weight": "30 g", + "to_hit": -3, + "color": "magenta", + "symbol": ",", + "material": [ "veggy" ], + "volume": "250 ml", + "price": 200 + }, + { + "type": "GENERIC", + "id": "rose_bud", + "name": "rose bud", + "description": "A rose bud. Contains some substances commonly produced by a rose flower.", + "weight": "30 g", + "to_hit": -3, + "color": "red", + "symbol": ",", + "material": [ "veggy" ], + "volume": "250 ml", + "price": 200 + }, + { + "type": "GENERIC", + "id": "dahlia_bud", + "name": "dahlia bud", + "description": "A dahlia bud. Contains some substances commonly produced by a dahlia.", + "weight": "30 g", + "to_hit": -3, + "color": "magenta", + "symbol": ",", + "material": [ "veggy" ], + "volume": "250 ml", + "price": 200 + }, + { + "type": "GENERIC", + "id": "rose_flower", + "name": "rose", + "description": "A rose stalk with some petals.", + "weight": "40 g", + "to_hit": -3, + "color": "red", + "symbol": ",", + "material": [ "veggy" ], + "volume": "250 ml", + "price": 0 + }, { "type": "GENERIC", "id": "bluebell_flower", @@ -665,5 +900,44 @@ "material": [ "veggy" ], "volume": "250 ml", "price": 0 + }, + { + "type": "GENERIC", + "id": "dahlia_flower", + "name": "dahlia", + "description": "A dahlia stalk with some petals.", + "weight": "40 g", + "to_hit": -3, + "color": "magenta", + "symbol": ",", + "material": [ "veggy" ], + "volume": "250 ml", + "price": 0 + }, + { + "type": "GENERIC", + "id": "poppy_flower", + "name": "poppy flower", + "description": "A poppy stalk with some petals.", + "weight": "40 g", + "to_hit": -3, + "color": "light_red", + "symbol": ",", + "material": [ "veggy" ], + "volume": "250 ml", + "price": 0 + }, + { + "type": "GENERIC", + "id": "bluebell_bud", + "name": "bluebell bud", + "description": "A bluebell bud. Contains some substances commonly produced by a bluebell flower.", + "weight": "30 g", + "to_hit": -3, + "color": "blue", + "symbol": ",", + "material": [ "veggy" ], + "volume": "250 ml", + "price": 200 } ] diff --git a/data/json/items/tools.json b/data/json/items/tools.json index 973ae56cb263f..db64ea5e41438 100644 --- a/data/json/items/tools.json +++ b/data/json/items/tools.json @@ -1009,7 +1009,7 @@ "power_draw": 500, "revert_to": "cell_phone", "use_action": { "target": "cell_phone", "msg": "You stop lighting up the screen.", "menu_text": "Turn off", "type": "transform" }, - "flags": [ "LIGHT_15", "CHARGEDIM", "TRADER_AVOID" ] + "flags": [ "WATCH", "LIGHT_15", "CHARGEDIM", "TRADER_AVOID" ] }, { "id": "smart_phone", @@ -1053,7 +1053,7 @@ "power_draw": 300, "revert_to": "smart_phone", "use_action": "MP3_ON", - "flags": [ "TRADER_AVOID" ], + "flags": [ "WATCH", "TRADER_AVOID" ], "magazine_well": 1 }, { @@ -1070,7 +1070,7 @@ "menu_text": "Turn off flashlight", "type": "transform" }, - "flags": [ "LIGHT_20", "CHARGEDIM", "TRADER_AVOID" ] + "flags": [ "WATCH", "LIGHT_20", "CHARGEDIM", "TRADER_AVOID" ] }, { "id": "chainsaw_off", diff --git a/data/json/mutations/mutations.json b/data/json/mutations/mutations.json index cc0d75e8eb007..9c833f5abf80a 100644 --- a/data/json/mutations/mutations.json +++ b/data/json/mutations/mutations.json @@ -6075,7 +6075,25 @@ "points": 0, "description": "You were shaping up to be a pretty decent student of the martial arts before the Cataclysm struck. Time to see just how good you really are.", "valid": false, - "initial_ma_styles": [ "style_karate", "style_judo", "style_muay_thai", "style_tai_chi", "style_taekwondo" ], + "initial_ma_styles": [ + "style_aikido", + "style_capoeira", + "style_crane", + "style_dragon", + "style_judo", + "style_karate", + "style_krav_maga", + "style_leopard", + "style_muay_thai", + "style_ninjutsu", + "style_pankration", + "style_snake", + "style_taekwondo", + "style_tai_chi", + "style_tiger", + "style_wingchun", + "style_zui_quan" + ], "purifiable": false, "profession": true }, @@ -6086,13 +6104,23 @@ "points": 0, "description": "You were competitive at national levels, and had considered teaching your art. Defending against the entire town may still be a challenge, though.", "initial_ma_styles": [ - "style_karate", - "style_judo", "style_aikido", - "style_tai_chi", + "style_capoeira", + "style_crane", + "style_dragon", + "style_judo", + "style_karate", + "style_krav_maga", + "style_leopard", + "style_muay_thai", + "style_ninjutsu", + "style_pankration", + "style_snake", "style_taekwondo", - "style_zui_quan", - "style_muay_thai" + "style_tai_chi", + "style_tiger", + "style_wingchun", + "style_zui_quan" ], "valid": false, "purifiable": false, diff --git a/data/json/npcs/NC_CITY_COP.json b/data/json/npcs/NC_CITY_COP.json index 364fecf22dabb..c8945093d3da3 100644 --- a/data/json/npcs/NC_CITY_COP.json +++ b/data/json/npcs/NC_CITY_COP.json @@ -137,7 +137,6 @@ [ "bondage_mask", 1 ], [ "thermos", 25 ], [ "antenna", 18 ], - [ "battery", 50 ], [ "screwdriver", 40 ], [ "RAM", 22 ], [ "mp3", 18 ], diff --git a/data/json/recipes/food/dry.json b/data/json/recipes/food/dry.json index 5e4f3252aa007..6db23c894df33 100644 --- a/data/json/recipes/food/dry.json +++ b/data/json/recipes/food/dry.json @@ -307,6 +307,7 @@ "difficulty": 2, "charges": 1, "time": "18 m", + "batch_time_factors": [ 67, 5 ], "autolearn": true, "tools": [ [ [ "dehydrator", 25 ], [ "char_smoker", 25 ] ] ], "components": [ [ [ "milk", 1 ] ] ] @@ -321,6 +322,7 @@ "difficulty": 2, "charges": 1, "time": "20 m", + "batch_time_factors": [ 67, 5 ], "autolearn": true, "tools": [ [ [ "dehydrator", 25 ], [ "char_smoker", 25 ] ], [ [ "surface_heat", 5, "LIST" ] ] ], "components": [ [ [ "milk", 1 ] ] ] diff --git a/data/json/recipes/recipe_deconstruction.json b/data/json/recipes/recipe_deconstruction.json index af562a87437aa..dc84eb41d4dc5 100644 --- a/data/json/recipes/recipe_deconstruction.json +++ b/data/json/recipes/recipe_deconstruction.json @@ -2763,13 +2763,6 @@ "components": [ [ [ "garlic_clove", 6 ] ] ], "flags": [ "BLIND_EASY" ] }, - { - "result": "leaf_spring", - "type": "uncraft", - "time": "3 m", - "qualities": [ { "id": "SAW_M", "level": 1 } ], - "components": [ [ [ "steel_lump", 4 ] ] ] - }, { "result": "styrofoam_cup", "type": "uncraft", diff --git a/data/json/recipes/recipe_others.json b/data/json/recipes/recipe_others.json index 771b25c4bc0c5..661b989aaa0b2 100644 --- a/data/json/recipes/recipe_others.json +++ b/data/json/recipes/recipe_others.json @@ -1658,6 +1658,21 @@ "tools": [ [ [ "welder", 100 ], [ "welder_crude", 150 ], [ "toolset", 150 ], [ "forge", 100 ], [ "oxy_torch", 20 ] ] ], "components": [ [ [ "steel_lump", 8 ] ] ] }, + { + "type": "recipe", + "result": "steel_armor", + "category": "CC_OTHER", + "subcategory": "CSC_OTHER_MATERIALS", + "skill_used": "fabrication", + "difficulty": 4, + "time": "12 m", + "reversible": true, + "//": "sawing it down doesn't teach anything useful", + "autolearn": true, + "qualities": [ { "id": "GLARE", "level": 2 } ], + "tools": [ [ [ "welder", 50 ], [ "welder_crude", 75 ], [ "toolset", 75 ], [ "forge", 50 ], [ "oxy_torch", 10 ] ] ], + "components": [ [ [ "steel_lump", 4 ] ] ] + }, { "type": "recipe", "result": "spiked_plate", diff --git a/data/json/techniques.json b/data/json/techniques.json index f099413d94f3a..a4660b965bf4e 100644 --- a/data/json/techniques.json +++ b/data/json/techniques.json @@ -1460,7 +1460,7 @@ "unarmed_allowed": true, "knockback_dist": 1, "knockback_spread": 1, - "knockback_follow": 1, + "knockback_follow": true, "mult_bonuses": [ [ "movecost", 0.5 ], [ "damage", "bash", 0.66 ], [ "damage", "cut", 0.66 ], [ "damage", "stab", 0.66 ] ], "messages": [ "You chain strike %s", " chain strikes %s" ], "description": "50% moves, 66% damage, knockback and follow" diff --git a/data/json/recipes/engines.json b/data/json/uncraft/vehicle/engines.json similarity index 96% rename from data/json/recipes/engines.json rename to data/json/uncraft/vehicle/engines.json index e2974bdeb2762..d3d357ab3aa25 100644 --- a/data/json/recipes/engines.json +++ b/data/json/uncraft/vehicle/engines.json @@ -1,10 +1,4 @@ [ - { - "abstract": "engine_disassembly", - "type": "uncraft", - "skill_used": "mechanics", - "qualities": [ { "id": "SCREW", "level": 1 }, { "id": "WRENCH", "level": 1 }, { "id": "WRENCH_FINE", "level": 1 } ] - }, { "type": "uncraft", "result": "1cyl_combustion", diff --git a/data/mods/Magiclysm/martialarts.json b/data/mods/Magiclysm/martialarts.json new file mode 100644 index 0000000000000..9af276df1b20d --- /dev/null +++ b/data/mods/Magiclysm/martialarts.json @@ -0,0 +1,287 @@ +[ + { + "id": "style_aikido", + "copy-from": "style_aikido", + "type": "martial_art", + "name": "Aikido", + "extend": { + "weapons": [ + "cestus_plus_one", + "cestus_plus_two", + "flaming_fist", + "flaming_fist_plus_one", + "flaming_fist_plus_one", + "gauntlet_pounding", + "stonefist", + "stormglove", + "rune_earthshaper_weapon" + ] + } + }, + { + "id": "style_eskrima", + "copy-from": "style_eskrima", + "type": "martial_art", + "name": "Eskrima", + "extend": { + "weapons": [ + "cudgel_plus_one", + "cudgel_plus_two", + "knife_combat_plus_one", + "knife_combat_plus_two", + "knife_hunting_plus_one", + "knife_hunting_plus_two", + "knife_rambo_plus_one", + "knife_rambo_plus_two", + "knife_trench_plus_one", + "knife_trench_plus_two", + "kukri_plus_one", + "kukri_plus_two", + "tanto_plus_one", + "tanto_plus_two", + "rune_animist_weapon" + ] + } + }, + { + "id": "style_fencing", + "copy-from": "style_fencing", + "type": "martial_art", + "name": "Fencing", + "extend": { + "weapons": [ + "cudgel_plus_one", + "cudgel_plus_two", + "rapier_plus_one", + "rapier_plus_two", + "cavalry_sabre_plus_one", + "cavalry_sabre_plus_two", + "broadsword_plus_one", + "broadsword_plus_two" + ] + } + }, + { + "id": "style_medievalpole", + "copy-from": "style_medievalpole", + "type": "martial_art", + "name": "Fior Di Battaglia", + "extend": { + "weapons": [ + "sledge_plus_one", + "sledge_plus_two", + "halberd_plus_one", + "halberd_plus_two", + "glaive_plus_one", + "glaive_plus_two", + "battleaxe_plus_one", + "battleaxe_plus_two", + "fire_ax_plus_one", + "fire_ax_plus_two", + "pickaxe_plus_one", + "pickaxe_plus_two", + "stormhammer", + "rune_stormshaper_weapon", + "rune_technomancer_weapon" + ] + } + }, + { + "id": "style_judo", + "copy-from": "style_judo", + "type": "martial_art", + "name": "Judo", + "extend": { + "weapons": [ + "cestus_plus_one", + "cestus_plus_two", + "flaming_fist", + "flaming_fist_plus_one", + "flaming_fist_plus_one", + "gauntlet_pounding", + "stonefist", + "stormglove", + "rune_earthshaper_weapon" + ] + } + }, + { + "id": "style_krav_maga", + "copy-from": "style_krav_maga", + "type": "martial_art", + "name": "Krav Maga", + "extend": { + "weapons": [ + "cudgel_plus_one", + "cudgel_plus_two", + "knife_combat_plus_one", + "knife_combat_plus_two", + "knife_hunting_plus_one", + "knife_hunting_plus_two", + "knife_rambo_plus_one", + "knife_rambo_plus_two", + "knife_trench_plus_one", + "knife_trench_plus_two", + "kukri_plus_one", + "kukri_plus_two", + "tanto_plus_one", + "tanto_plus_two", + "rune_animist_weapon" + ] + } + }, + { + "id": "style_swordsmanship", + "copy-from": "style_swordsmanship", + "type": "martial_art", + "name": "Medieval Swordsmanship", + "extend": { + "weapons": [ + "arming_sword_plus_one", + "arming_sword_plus_two", + "broadsword_plus_one", + "broadsword_plus_two", + "estoc_plus_one", + "estoc_plus_two", + "longsword_plus_one", + "longsword_plus_two", + "zweihander_plus_one", + "zweihander_plus_two", + "rune_kelvinist_weapon" + ] + } + }, + { + "id": "style_ninjutsu", + "copy-from": "style_ninjutsu", + "type": "martial_art", + "name": "Ninjutsu", + "extend": { + "weapons": [ + "arming_sword_plus_one", + "arming_sword_plus_two", + "broadsword_plus_one", + "broadsword_plus_two", + "cavalry_sabre_plus_one", + "cavalry_sabre_plus_two", + "cutlass_plus_one", + "cutlass_plus_two", + "dao_plus_one", + "dao_plus_two", + "i_staff_plus_one", + "i_staff_plus_two", + "q_staff_plus_one", + "q_staff_plus_two", + "jian_plus_one", + "jian_plus_two", + "katana_plus_one", + "katana_plus_two", + "khopesh_plus_one", + "khopesh_plus_two", + "kris_plus_one", + "kris_plus_two", + "kukri_plus_one", + "kukri_plus_two", + "knife_combat_plus_one", + "knife_combat_plus_two", + "knife_hunting_plus_one", + "knife_hunting_plus_two", + "knife_rambo_plus_one", + "knife_rambo_plus_two", + "knife_trench_plus_one", + "knife_trench_plus_two", + "longsword_plus_one", + "longsword_plus_two", + "nodachi_plus_one", + "nodachi_plus_two", + "scimitar_plus_one", + "scimitar_plus_two", + "sword_xiphos_plus_one", + "sword_xiphos_plus_two", + "tanto_plus_one", + "tanto_plus_two", + "wakizashi_plus_one", + "wakizashi_plus_two", + "rune_animist_weapon", + "rune_kelvinist_weapon", + "rune_magus_weapon" + ] + } + }, + { + "id": "style_niten", + "copy-from": "style_niten", + "type": "martial_art", + "name": "Niten Ichi-Ryu", + "extend": { + "weapons": [ + "katana_plus_one", + "katana_plus_two", + "nodachi_plus_one", + "nodachi_plus_two", + "wakizashi_plus_one", + "wakizashi_plus_two" + ] + } + }, + { + "id": "style_silat", + "copy-from": "style_silat", + "type": "martial_art", + "name": "Silat", + "extend": { + "weapons": [ + "cudgel_plus_one", + "cudgel_plus_two", + "glaive_plus_one", + "glaive_plus_two", + "i_staff_plus_one", + "i_staff_plus_two", + "q_staff_plus_one", + "q_staff_plus_two", + "kris_plus_one", + "kris_plus_two", + "knife_combat_plus_one", + "knife_combat_plus_two", + "knife_hunting_plus_one", + "knife_hunting_plus_two", + "knife_rambo_plus_one", + "knife_rambo_plus_two", + "knife_trench_plus_one", + "knife_trench_plus_two", + "naginata_plus_one", + "naginata_plus_two", + "scimitar_plus_one", + "scimitar_plus_two", + "tanto_plus_one", + "tanto_plus_two", + "rune_animist_weapon", + "rune_biomancer_weapon", + "rune_magus_weapon", + "bonespear" + ] + } + }, + { + "id": "style_sojutsu", + "copy-from": "style_sojutsu", + "type": "martial_art", + "name": "Sojutsu", + "extend": { + "weapons": [ + "glaive_plus_one", + "glaive_plus_two", + "halberd_plus_one", + "halberd_plus_two", + "naginata_plus_one", + "naginata_plus_two", + "pike_plus_one", + "pike_plus_two", + "qiang_plus_one", + "qiang_plus_two", + "rune_biomancer_weapon", + "bonespear" + ] + } + } +] diff --git a/src/activity_item_handling.cpp b/src/activity_item_handling.cpp index fbbc50579b79a..e411af9ec737b 100644 --- a/src/activity_item_handling.cpp +++ b/src/activity_item_handling.cpp @@ -668,6 +668,15 @@ void activity_on_turn_pickup() return; } + // If the player moves while picking up (ie: in a moving vehicle) cancel the activity, only populate coords when grabbing from the ground + if( g->u.activity.coords.size() > 0 && g->u.activity.coords.at( 0 ) != g->u.pos() ) { + g->u.cancel_activity(); + if( g->u.is_player() ) { + g->u.add_msg_if_player( _( "Moving cancelled auto-pickup." ) ); + } + return; + } + // Auto_resume implies autopickup. const bool autopickup = g->u.activity.auto_resume; diff --git a/src/advanced_inv.cpp b/src/advanced_inv.cpp index a5268b4724617..1e89097be0b4d 100644 --- a/src/advanced_inv.cpp +++ b/src/advanced_inv.cpp @@ -1354,6 +1354,7 @@ bool advanced_inventory::move_all_items( bool nested_call ) } else { if( dpane.get_area() == AIM_INVENTORY || dpane.get_area() == AIM_WORN ) { g->u.assign_activity( activity_id( "ACT_PICKUP" ) ); + g->u.activity.coords.push_back( g->u.pos() ); } else { // Vehicle and map destinations are handled the same. // Check first if the destination area still have enough room for moving all. @@ -1729,6 +1730,7 @@ void advanced_inventory::display() if( destarea == AIM_INVENTORY ) { g->u.assign_activity( activity_id( "ACT_PICKUP" ) ); + g->u.activity.coords.push_back( g->u.pos() ); } else if( destarea == AIM_WORN ) { g->u.assign_activity( activity_id( "ACT_WEAR" ) ); } else { // Vehicle and map destinations are handled similarly. diff --git a/src/basecamp.h b/src/basecamp.h index a1aae7e813559..28597471da9b6 100644 --- a/src/basecamp.h +++ b/src/basecamp.h @@ -283,11 +283,14 @@ class basecamp /// called with a companion @ref comp who is not the camp manager, finishes updating their /// skills, consuming food, and returning them to the base. void finish_return( npc &comp, bool fixed_time, const std::string &return_msg, - const std::string &skill, int difficulty ); + const std::string &skill, int difficulty, bool cancel = false ); /// a wrapper function for @ref companion_choose_return and @ref finish_return npc_ptr mission_return( const std::string &miss_id, time_duration min_duration, bool fixed_time, const std::string &return_msg, const std::string &skill, int difficulty ); + /// select a companion for any mission to return to base + npc_ptr emergency_recall(); + /// Called to close upgrade missions, @ref miss is the name of the mission id /// and @ref dir is the direction of the location to be upgraded bool upgrade_return( const point &dir, const std::string &miss ); diff --git a/src/character.cpp b/src/character.cpp index 1d674228d665a..f1f0d7232e645 100644 --- a/src/character.cpp +++ b/src/character.cpp @@ -22,9 +22,11 @@ #include "game.h" #include "game_constants.h" #include "itype.h" +#include "material.h" #include "map.h" #include "map_iterator.h" #include "map_selector.h" +#include "memorial_logger.h" #include "messages.h" #include "mission.h" #include "monster.h" @@ -51,6 +53,14 @@ #include "stomach.h" #include "ui.h" +static const bionic_id bio_ads( "bio_ads" ); +static const bionic_id bio_armor_arms( "bio_armor_arms" ); +static const bionic_id bio_armor_eyes( "bio_armor_eyes" ); +static const bionic_id bio_armor_head( "bio_armor_head" ); +static const bionic_id bio_armor_legs( "bio_armor_legs" ); +static const bionic_id bio_armor_torso( "bio_armor_torso" ); +static const bionic_id bio_carbon( "bio_carbon" ); + const efftype_id effect_alarm_clock( "alarm_clock" ); const efftype_id effect_bandaged( "bandaged" ); const efftype_id effect_beartrap( "beartrap" ); @@ -75,6 +85,7 @@ const efftype_id effect_lying_down( "lying_down" ); const efftype_id effect_narcosis( "narcosis" ); const efftype_id effect_nausea( "nausea" ); const efftype_id effect_no_sight( "no_sight" ); +const efftype_id effect_onfire( "onfire" ); const efftype_id effect_pkill1( "pkill1" ); const efftype_id effect_pkill2( "pkill2" ); const efftype_id effect_pkill3( "pkill3" ); @@ -99,6 +110,8 @@ static const trait_id trait_PROF_FOODP( "PROF_FOODP" ); static const trait_id trait_GILLS( "GILLS" ); static const trait_id trait_GILLS_CEPH( "GILLS_CEPH" ); static const trait_id trait_GLASSJAW( "GLASSJAW" ); +static const trait_id trait_HOLLOW_BONES( "HOLLOW_BONES" ); +static const trait_id trait_LIGHT_BONES( "LIGHT_BONES" ); static const trait_id trait_MEMBRANE( "MEMBRANE" ); static const trait_id trait_MYOPIC( "MYOPIC" ); static const trait_id trait_NIGHTVISION2( "NIGHTVISION2" ); @@ -4169,3 +4182,232 @@ double Character::calculate_by_enchantment( double modify, enchantment::mod valu } return modify; } + +void Character::passive_absorb_hit( body_part bp, damage_unit &du ) const +{ + // >0 check because some mutations provide negative armor + // Thin skin check goes before subdermal armor plates because SUBdermal + if( du.amount > 0.0f ) { + // Horrible hack warning! + // Get rid of this as soon as CUT and STAB are split + if( du.type == DT_STAB ) { + damage_unit du_copy = du; + du_copy.type = DT_CUT; + du.amount -= mutation_armor( bp, du_copy ); + } else { + du.amount -= mutation_armor( bp, du ); + } + } + du.amount -= bionic_armor_bonus( bp, du.type ); //Check for passive armor bionics + du.amount -= mabuff_armor_bonus( du.type ); + du.amount = std::max( 0.0f, du.amount ); +} + +static void destroyed_armor_msg( Character &who, const std::string &pre_damage_name ) +{ + if( who.is_avatar() ) { + g->memorial().add( + //~ %s is armor name + pgettext( "memorial_male", "Worn %s was completely destroyed." ), + pgettext( "memorial_female", "Worn %s was completely destroyed." ), + pre_damage_name ); + } + who.add_msg_player_or_npc( m_bad, _( "Your %s is completely destroyed!" ), + _( "'s %s is completely destroyed!" ), + pre_damage_name ); +} + +void Character::absorb_hit( body_part bp, damage_instance &dam ) +{ + std::list worn_remains; + bool armor_destroyed = false; + + for( damage_unit &elem : dam.damage_units ) { + if( elem.amount < 0 ) { + // Prevents 0 damage hits (like from hallucinations) from ripping armor + elem.amount = 0; + continue; + } + + // The bio_ads CBM absorbs damage before hitting armor + if( has_active_bionic( bio_ads ) ) { + if( elem.amount > 0 && get_power_level() > 24_kJ ) { + if( elem.type == DT_BASH ) { + elem.amount -= rng( 1, 8 ); + } else if( elem.type == DT_CUT ) { + elem.amount -= rng( 1, 4 ); + } else if( elem.type == DT_STAB ) { + elem.amount -= rng( 1, 2 ); + } + mod_power_level( -25_kJ ); + } + if( elem.amount < 0 ) { + elem.amount = 0; + } + } + + // Only the outermost armor can be set on fire + bool outermost = true; + // The worn vector has the innermost item first, so + // iterate reverse to damage the outermost (last in worn vector) first. + for( auto iter = worn.rbegin(); iter != worn.rend(); ) { + item &armor = *iter; + + if( !armor.covers( bp ) ) { + ++iter; + continue; + } + + const std::string pre_damage_name = armor.tname(); + bool destroy = false; + + // Heat damage can set armor on fire + // Even though it doesn't cause direct physical damage to it + if( outermost && elem.type == DT_HEAT && elem.amount >= 1.0f ) { + // TODO: Different fire intensity values based on damage + fire_data frd{ 2 }; + destroy = armor.burn( frd ); + int fuel = roll_remainder( frd.fuel_produced ); + if( fuel > 0 ) { + add_effect( effect_onfire, time_duration::from_turns( fuel + 1 ), bp, false, 0, false, true ); + } + } + + if( !destroy ) { + destroy = armor_absorb( elem, armor ); + } + + if( destroy ) { + if( g->u.sees( *this ) ) { + SCT.add( point( posx(), posy() ), NORTH, remove_color_tags( pre_damage_name ), + m_neutral, _( "destroyed" ), m_info ); + } + destroyed_armor_msg( *this, pre_damage_name ); + armor_destroyed = true; + armor.on_takeoff( *this ); + worn_remains.insert( worn_remains.end(), armor.contents.begin(), armor.contents.end() ); + // decltype is the type name of the iterator, note that reverse_iterator::base returns the + // iterator to the next element, not the one the revers_iterator points to. + // http://stackoverflow.com/questions/1830158/how-to-call-erase-with-a-reverse-iterator + iter = decltype( iter )( worn.erase( --( iter.base() ) ) ); + } else { + ++iter; + outermost = false; + } + } + + passive_absorb_hit( bp, elem ); + + if( elem.type == DT_BASH ) { + if( has_trait( trait_LIGHT_BONES ) ) { + elem.amount *= 1.4; + } + if( has_trait( trait_HOLLOW_BONES ) ) { + elem.amount *= 1.8; + } + } + + elem.amount = std::max( elem.amount, 0.0f ); + } + for( item &remain : worn_remains ) { + g->m.add_item_or_charges( pos(), remain ); + } + if( armor_destroyed ) { + drop_invalid_inventory(); + } +} + +bool Character::armor_absorb( damage_unit &du, item &armor ) +{ + if( rng( 1, 100 ) > armor.get_coverage() ) { + return false; + } + + // TODO: add some check for power armor + armor.mitigate_damage( du ); + + // We want armor's own resistance to this type, not the resistance it grants + const int armors_own_resist = armor.damage_resist( du.type, true ); + if( armors_own_resist > 1000 ) { + // This is some weird type that doesn't damage armors + return false; + } + + // Scale chance of article taking damage based on the number of parts it covers. + // This represents large articles being able to take more punishment + // before becoming ineffective or being destroyed. + const int num_parts_covered = armor.get_covered_body_parts().count(); + if( !one_in( num_parts_covered ) ) { + return false; + } + + // Don't damage armor as much when bypassed by armor piercing + // Most armor piercing damage comes from bypassing armor, not forcing through + const int raw_dmg = du.amount; + if( raw_dmg > armors_own_resist ) { + // If damage is above armor value, the chance to avoid armor damage is + // 50% + 50% * 1/dmg + if( one_in( raw_dmg ) || one_in( 2 ) ) { + return false; + } + } else { + // Sturdy items and power armors never take chip damage. + // Other armors have 0.5% of getting damaged from hits below their armor value. + if( armor.has_flag( "STURDY" ) || armor.is_power_armor() || !one_in( 200 ) ) { + return false; + } + } + + const material_type &material = armor.get_random_material(); + std::string damage_verb = ( du.type == DT_BASH ) ? material.bash_dmg_verb() : + material.cut_dmg_verb(); + + const std::string pre_damage_name = armor.tname(); + const std::string pre_damage_adj = armor.get_base_material().dmg_adj( armor.damage_level( 4 ) ); + + // add "further" if the damage adjective and verb are the same + std::string format_string = ( pre_damage_adj == damage_verb ) ? + _( "Your %1$s is %2$s further!" ) : _( "Your %1$s is %2$s!" ); + add_msg_if_player( m_bad, format_string, pre_damage_name, damage_verb ); + //item is damaged + if( is_player() ) { + SCT.add( point( posx(), posy() ), NORTH, remove_color_tags( pre_damage_name ), m_neutral, + damage_verb, + m_info ); + } + + return armor.mod_damage( armor.has_flag( "FRAGILE" ) ? + rng( 2 * itype::damage_scale, 3 * itype::damage_scale ) : itype::damage_scale, du.type ); +} + +float Character::bionic_armor_bonus( body_part bp, damage_type dt ) const +{ + float result = 0.0f; + // We only check the passive bionics + if( has_bionic( bio_carbon ) ) { + if( dt == DT_BASH ) { + result += 2; + } else if( dt == DT_CUT || dt == DT_STAB ) { + result += 4; + } + } + // All the other bionic armors reduce bash/cut/stab by 3 + // Map body parts to a set of bionics that protect it + // TODO: JSONize passive bionic armor instead of hardcoding it + static const std::map< body_part, bionic_id > armor_bionics = { + { bp_head, { bio_armor_head } }, + { bp_arm_l, { bio_armor_arms } }, + { bp_arm_r, { bio_armor_arms } }, + { bp_torso, { bio_armor_torso } }, + { bp_leg_l, { bio_armor_legs } }, + { bp_leg_r, { bio_armor_legs } }, + { bp_eyes, { bio_armor_eyes } } + }; + auto iter = armor_bionics.find( bp ); + if( iter != armor_bionics.end() && has_bionic( iter->second ) && + ( dt == DT_BASH || dt == DT_CUT || dt == DT_STAB ) ) { + result += 3; + } + return result; +} + diff --git a/src/character.h b/src/character.h index 62d63a34b135a..2713b1d8a5240 100644 --- a/src/character.h +++ b/src/character.h @@ -400,6 +400,29 @@ class Character : public Creature, public visitable * that encumbrance may have changed and require recalculating. */ void check_item_encumbrance_flag(); + + + /** + * Check for relevant passive, non-clothing that can absorb damage, and reduce by specified + * damage unit. Only flat bonuses are checked here. Multiplicative ones are checked in + * @ref player::absorb_hit. The damage amount will never be reduced to less than 0. + * This is called from @ref player::absorb_hit + */ + void passive_absorb_hit( body_part bp, damage_unit &du ) const; + /** Runs through all bionics and armor on a part and reduces damage through their armor_absorb */ + void absorb_hit( body_part bp, damage_instance &dam ) override; + /** + * Reduces and mutates du, prints messages about armor taking damage. + * @return true if the armor was completely destroyed (and the item must be deleted). + */ + bool armor_absorb( damage_unit &du, item &armor ); + /** + * Check for passive bionics that provide armor, and returns the armor bonus + * This is called from player::passive_absorb_hit + */ + float bionic_armor_bonus( body_part bp, damage_type dt ) const; + /** Returns the armor bonus against given type from martial arts buffs */ + int mabuff_armor_bonus( damage_type type ) const; // --------------- Mutation Stuff --------------- // In newcharacter.cpp /** Returns the id of a random starting trait that costs >= 0 points */ diff --git a/src/faction_camp.cpp b/src/faction_camp.cpp index 8ffd3404b02df..b76bddf4f603c 100644 --- a/src/faction_camp.cpp +++ b/src/faction_camp.cpp @@ -125,6 +125,13 @@ std::map miss_info = {{ "Recover Ally from Upgrading", to_translation( "Recover Ally from Upgrading" ) } }, + { + "_faction_camp_recall", { + "Emergency Recall", to_translation( "Emergency Recall" ), + to_translation( "Lost in the ether!\n" ), + "Emergency Recall", to_translation( "Emergency Recall" ) + } + }, { "_faction_camp_crafting_", { "Craft Item", to_translation( "Craft Item" ), @@ -1265,6 +1272,22 @@ void basecamp::get_available_missions( mission_data &mission_key, bool by_radio } } } + + if( !camp_workers.empty() ) { + const base_camps::miss_data &miss_info = base_camps::miss_info[ "_faction_camp_recall" ]; + entry = string_format( _( "Notes:\n" + "Cancel a current mission and force the immediate return of a " + "companion. No work will be done on the mission and all " + "resources used on the mission will be lost.\n\n" + "WARNING: All resources used on the mission will be lost and " + "no work will be done. Only use this mission to recover a " + "companion who cannot otherwise be recovered.\n\n" + "Companions must be on missions for at least 24 hours before " + "emergency recall becomes available." ) ); + bool avail = update_time_fixed( entry, camp_workers, 24_hours ); + mission_key.add_return( miss_info.ret_miss_id, miss_info.ret_desc.translated(), + cata::nullopt, entry, avail ); + } } bool basecamp::handle_mission( const std::string &miss_id, const cata::optional miss_dir, @@ -1480,6 +1503,10 @@ bool basecamp::handle_mission( const std::string &miss_id, const cata::optional< } } + if( miss_id == "Emergency Recall" ) { + emergency_recall(); + } + g->draw_ter(); wrefresh( g->w_terrain ); g->draw_panels( true ); @@ -2156,8 +2183,8 @@ npc_ptr basecamp::companion_choose_return( const std::string &miss_id, return talk_function::companion_choose_return( omt_pos, base_camps::id, miss_id, calendar::turn - min_duration ); } -void basecamp::finish_return( npc &comp, bool fixed_time, const std::string &return_msg, - const std::string &skill, int difficulty ) +void basecamp::finish_return( npc &comp, const bool fixed_time, const std::string &return_msg, + const std::string &skill, int difficulty, const bool cancel ) { popup( "%s %s", comp.name, return_msg ); // this is the time the mission was expected to take, or did take for fixed time missions @@ -2166,7 +2193,9 @@ void basecamp::finish_return( npc &comp, bool fixed_time, const std::string &ret if( !fixed_time ) { mission_time = calendar::turn - comp.companion_mission_time; } - talk_function::companion_skill_trainer( comp, skill, mission_time, difficulty ); + if( !cancel ) { + talk_function::companion_skill_trainer( comp, skill, mission_time, difficulty ); + } // companions subtracted food when they started the mission, but didn't mod their hunger for // that food. so add it back in. @@ -2181,10 +2210,12 @@ void basecamp::finish_return( npc &comp, bool fixed_time, const std::string &ret comp.companion_mission_time = calendar::before_time_starts; comp.companion_mission_time_ret = calendar::before_time_starts; bool by_radio = g->u.global_omt_location() != comp.global_omt_location(); - for( size_t i = 0; i < comp.companion_mission_inv.size(); i++ ) { - for( const auto &it : comp.companion_mission_inv.const_stack( i ) ) { - if( !it.count_by_charges() || it.charges > 0 ) { - place_results( it, by_radio ); + if( !cancel ) { + for( size_t i = 0; i < comp.companion_mission_inv.size(); i++ ) { + for( const auto &it : comp.companion_mission_inv.const_stack( i ) ) { + if( !it.count_by_charges() || it.charges > 0 ) { + place_results( it, by_radio ); + } } } } @@ -2215,6 +2246,18 @@ npc_ptr basecamp::mission_return( const std::string &miss_id, time_duration min_ return comp; } +npc_ptr basecamp::emergency_recall() +{ + npc_ptr comp = talk_function::companion_choose_return( omt_pos, base_camps::id, "", + calendar::turn - 24_hours, false ); + if( comp != nullptr ) { + const std::string return_msg = _( "responds to the emergency recall..." ); + finish_return( *comp, false, return_msg, "menial", 0, true ); + } + return comp; + +} + bool basecamp::upgrade_return( const point &dir, const std::string &miss ) { const std::string bldg = next_upgrade( dir, 1 ); diff --git a/src/game.cpp b/src/game.cpp index 75ccda09b5b84..7149b9fa98e3c 100644 --- a/src/game.cpp +++ b/src/game.cpp @@ -1567,11 +1567,7 @@ bool game::do_turn() catacurses::refresh(); refresh_display(); } - } - - player_was_sleeping = player_is_sleeping; - - if( calendar::once_every( 1_minutes ) ) { + } else if( calendar::once_every( 1_minutes ) ) { if( const cata::optional progress = u.activity.get_progress_message() ) { query_popup() .wait_message( "%s", *progress ) @@ -1580,6 +1576,8 @@ bool game::do_turn() } } + player_was_sleeping = player_is_sleeping; + u.update_bodytemp(); u.update_body_wetness( *weather.weather_precise ); u.apply_wetness_morale( weather.temperature ); @@ -8943,7 +8941,29 @@ bool game::disable_robot( const tripoint &p ) return false; } +bool game::is_dangerous_tile( const tripoint &dest_loc ) const +{ + return !( get_dangerous_tile( dest_loc ).empty() ); +} + bool game::prompt_dangerous_tile( const tripoint &dest_loc ) const +{ + std::vector harmful_stuff = get_dangerous_tile( dest_loc ); + + if( !harmful_stuff.empty() && + !query_yn( _( "Really step into %s?" ), enumerate_as_string( harmful_stuff ) ) ) { + return false; + } + if( !harmful_stuff.empty() && u.is_mounted() && + m.tr_at( dest_loc ).loadid == tr_ledge ) { + add_msg( m_warning, _( "Your %s refuses to move over that ledge!" ), + u.mounted_creature->get_name() ); + return false; + } + return true; +} + +std::vector game::get_dangerous_tile( const tripoint &dest_loc ) const { std::vector harmful_stuff; const auto fields_here = m.field_at( u.pos() ); @@ -8988,17 +9008,7 @@ bool game::prompt_dangerous_tile( const tripoint &dest_loc ) const } - if( !harmful_stuff.empty() && - !query_yn( _( "Really step into %s?" ), enumerate_as_string( harmful_stuff ) ) ) { - return false; - } - if( !harmful_stuff.empty() && u.is_mounted() && - m.tr_at( dest_loc ).loadid == tr_ledge ) { - add_msg( m_warning, _( "Your %s refuses to move over that ledge!" ), - u.mounted_creature->get_name() ); - return false; - } - return true; + return harmful_stuff; } bool game::walk_move( const tripoint &dest_loc ) diff --git a/src/game.h b/src/game.h index 141ae94cb363b..c2af5856f306f 100644 --- a/src/game.h +++ b/src/game.h @@ -795,6 +795,8 @@ class game void mon_info( const catacurses::window &, int hor_padding = 0 ); // Prints a list of nearby monsters void cleanup_dead(); // Delete any dead NPCs/monsters + bool is_dangerous_tile( const tripoint &dest_loc ) const; + std::vector get_dangerous_tile( const tripoint &dest_loc ) const; bool prompt_dangerous_tile( const tripoint &dest_loc ) const; private: void wield(); diff --git a/src/lightmap.cpp b/src/lightmap.cpp index 63a7358dc4d6d..c2dd277ceb8e0 100644 --- a/src/lightmap.cpp +++ b/src/lightmap.cpp @@ -192,7 +192,7 @@ void map::build_sunlight_cache( int zlev ) } // If uppermost level, just apply weather illumination since there's no opportunity // for light to be blocked. - if( zlev == map_cache.max_populated_zlev ) { + if( zlev == std::min( map_cache.max_populated_zlev + 1, OVERMAP_HEIGHT ) ) { for( auto &lm_col : lm ) { for( four_quadrants &lm_entry : lm_col ) { lm_entry.fill( outside_light_level ); diff --git a/src/martialarts.cpp b/src/martialarts.cpp index ba4680d83589d..1b434bc3448e4 100644 --- a/src/martialarts.cpp +++ b/src/martialarts.cpp @@ -130,7 +130,7 @@ void ma_technique::load( JsonObject &jo, const std::string &src ) optional( jo, was_loaded, "knockback_dist", knockback_dist, 0 ); optional( jo, was_loaded, "knockback_spread", knockback_spread, 0 ); optional( jo, was_loaded, "powerful_knockback", powerful_knockback, false ); - optional( jo, was_loaded, "knockback_follow", knockback_follow, 0 ); + optional( jo, was_loaded, "knockback_follow", knockback_follow, false ); optional( jo, was_loaded, "aoe", aoe, "" ); optional( jo, was_loaded, "flags", flags, auto_flags_reader<> {} ); @@ -512,7 +512,7 @@ ma_technique::ma_technique() knockback_dist = 0; knockback_spread = 0; // adding randomness to knockback, like tec_throw powerful_knockback = false; - knockback_follow = 0; // player follows the knocked-back party into their former tile + knockback_follow = false; // player follows the knocked-back party into their former tile // offensive disarms = false; // like tec_disarm @@ -593,9 +593,9 @@ int ma_buff::speed_bonus( const player &u ) const { return bonuses.get_flat( u, AFFECTED_SPEED ); } -int ma_buff::armor_bonus( const player &u, damage_type dt ) const +int ma_buff::armor_bonus( const Character &guy, damage_type dt ) const { - return bonuses.get_flat( u, AFFECTED_ARMOR, dt ); + return bonuses.get_flat( guy, AFFECTED_ARMOR, dt ); } float ma_buff::damage_bonus( const player &u, damage_type dt ) const { @@ -1058,7 +1058,7 @@ int player::mabuff_speed_bonus() const } ); return ret; } -int player::mabuff_armor_bonus( damage_type type ) const +int Character::mabuff_armor_bonus( damage_type type ) const { int ret = 0; accumulate_ma_buff_effects( *effects, [&ret, type, this]( const ma_buff & b, const effect & d ) { diff --git a/src/martialarts.h b/src/martialarts.h index 0c01d231a4ae2..43c04ab1c12dc 100644 --- a/src/martialarts.h +++ b/src/martialarts.h @@ -98,7 +98,7 @@ class ma_technique float knockback_spread; // adding randomness to knockback, like tec_throw bool powerful_knockback; std::string aoe; // corresponds to an aoe shape, defaults to just the target - int knockback_follow; // player follows the knocked-back party into their former tile + bool knockback_follow; // player follows the knocked-back party into their former tile // offensive bool disarms; // like tec_disarm @@ -148,7 +148,7 @@ class ma_buff int block_bonus( const player &u ) const; // returns the armor bonus for various armor stats (equivalent to armor) - int armor_bonus( const player &u, damage_type dt ) const; + int armor_bonus( const Character &guy, damage_type dt ) const; // returns the stat bonus for the various damage stats (for rolls) float damage_bonus( const player &u, damage_type dt ) const; diff --git a/src/melee.cpp b/src/melee.cpp index 6990546be674b..ce0ee2b7d128e 100644 --- a/src/melee.cpp +++ b/src/melee.cpp @@ -53,6 +53,9 @@ #include "material.h" #include "type_id.h" #include "point.h" +#include "vehicle.h" +#include "vpart_position.h" +#include "mapdata.h" static const bionic_id bio_cqb( "bio_cqb" ); static const bionic_id bio_memory( "bio_memory" ); @@ -102,6 +105,8 @@ static const trait_id trait_SLIME_HANDS( "SLIME_HANDS" ); static const trait_id trait_TALONS( "TALONS" ); static const trait_id trait_THORNS( "THORNS" ); +static const efftype_id effect_amigara( "amigara" ); + const species_id HUMAN( "HUMAN" ); void player_hit_message( player *attacker, const std::string &message, @@ -1317,28 +1322,34 @@ void player::perform_technique( const ma_technique &technique, Creature &t, dama t.add_effect( effect_stunned, rng( 1_turns, time_duration::from_turns( technique.stun_dur ) ) ); } - if( technique.knockback_dist > 0 ) { + if( technique.knockback_dist ) { const tripoint prev_pos = t.pos(); // track target startpoint for knockback_follow const int kb_offset_x = rng( -technique.knockback_spread, technique.knockback_spread ); const int kb_offset_y = rng( -technique.knockback_spread, technique.knockback_spread ); tripoint kb_point( posx() + kb_offset_x, posy() + kb_offset_y, posz() ); - - if( !technique.powerful_knockback ) { - for( int dist = rng( 1, technique.knockback_dist ); dist > 0; dist-- ) { - t.knock_back_from( kb_point ); - } - } else { - g->knockback( pos(), t.pos(), technique.knockback_dist, technique.stun_dur, 1 ); + for( int dist = rng( 1, technique.knockback_dist ); dist > 0; dist-- ) { + t.knock_back_from( kb_point ); } - // This technique makes the player follow into the tile the target was knocked from - if( technique.knockback_follow > 0 ) { - // Check if terrain there is safe then if a critter's still there - if clear, move player there - if( !g->prompt_dangerous_tile( prev_pos ) ) { - return; - } else { + if( technique.knockback_follow ) { + const optional_vpart_position vp0 = g->m.veh_at( pos() ); + vehicle *const veh0 = veh_pointer_or_null( vp0 ); + bool to_swimmable = g->m.has_flag( "SWIMMABLE", prev_pos ); + bool to_deepwater = g->m.has_flag( TFLAG_DEEP_WATER, prev_pos ); + + // Check if it's possible to move to the new tile + bool move_issue = + g->is_dangerous_tile( prev_pos ) || // Tile contains fire, etc + ( to_swimmable && to_deepwater ) || // Dive into deep water + is_mounted() || + ( veh0 != nullptr && abs( veh0->velocity ) > 100 ) || // Diving from moving vehicle + ( veh0 != nullptr && veh0->player_in_control( g->u ) ) || // Player is driving + has_effect( effect_amigara ); + + if( !move_issue ) { if( t.pos() != prev_pos ) { g->place_player( prev_pos ); + g->on_move_effects(); } } } diff --git a/src/mission_companion.cpp b/src/mission_companion.cpp index 411259d15ac96..9a3157ad67f3f 100644 --- a/src/mission_companion.cpp +++ b/src/mission_companion.cpp @@ -1998,13 +1998,14 @@ npc_ptr talk_function::companion_choose_return( const npc &p, const std::string npc_ptr talk_function::companion_choose_return( const tripoint &omt_pos, const std::string &role_id, const std::string &mission_id, - const time_point &deadline ) + const time_point &deadline, + const bool by_mission ) { std::vector available; for( npc_ptr &guy : overmap_buffer.get_companion_mission_npcs() ) { npc_companion_mission c_mission = guy->get_companion_mission(); if( c_mission.position != omt_pos || - c_mission.mission_id != mission_id || c_mission.role_id != role_id ) { + ( by_mission && c_mission.mission_id != mission_id ) || c_mission.role_id != role_id ) { continue; } if( g->u.has_trait( trait_id( "DEBUG_HS" ) ) ) { diff --git a/src/mission_companion.h b/src/mission_companion.h index 526007e4aa00b..3646e22a52068 100644 --- a/src/mission_companion.h +++ b/src/mission_companion.h @@ -140,7 +140,8 @@ npc_ptr companion_choose( const std::string &skill_tested = "", int skill_level npc_ptr companion_choose_return( const npc &p, const std::string &mission_id, const time_point &deadline ); npc_ptr companion_choose_return( const tripoint &omt_pos, const std::string &role_id, - const std::string &mission_id, const time_point &deadline ); + const std::string &mission_id, const time_point &deadline, + bool by_mission = true ); //Return NPC to your party void companion_return( npc &comp ); diff --git a/src/newcharacter.cpp b/src/newcharacter.cpp index fe101c4e2d04f..a13b7f84a7694 100644 --- a/src/newcharacter.cpp +++ b/src/newcharacter.cpp @@ -2179,20 +2179,19 @@ tab_direction set_description( const catacurses::window &w, avatar &you, const b catacurses::window w_gender = catacurses::newwin( 2, 33, point( getbegx( w ) + 46, getbegy( w ) + 5 ) ); catacurses::window w_location = - catacurses::newwin( 1, 76, point( getbegx( w ) + 2, getbegy( w ) + 7 ) ); + catacurses::newwin( 1, TERMX - 3, point( getbegx( w ) + 2, getbegy( w ) + 7 ) ); catacurses::window w_stats = catacurses::newwin( 6, 20, point( getbegx( w ) + 2, getbegy( w ) + 9 ) ); catacurses::window w_traits = - catacurses::newwin( 13, 24, point( getbegx( w ) + 22, getbegy( w ) + 9 ) ); + catacurses::newwin( 30, 24, point( getbegx( w ) + 22, getbegy( w ) + 9 ) ); catacurses::window w_scenario = - catacurses::newwin( 1, 33, point( getbegx( w ) + 46, getbegy( w ) + 9 ) ); + catacurses::newwin( 1, TERMX - 47, point( getbegx( w ) + 46, getbegy( w ) + 9 ) ); catacurses::window w_profession = catacurses::newwin( 1, 33, point( getbegx( w ) + 46, getbegy( w ) + 10 ) ); catacurses::window w_skills = - catacurses::newwin( 9, 33, point( getbegx( w ) + 46, getbegy( w ) + 11 ) ); + catacurses::newwin( 30, 33, point( getbegx( w ) + 46, getbegy( w ) + 11 ) ); catacurses::window w_guide = - catacurses::newwin( TERMY - getbegy( w ) - 19 - 1, TERMX - 3, - point( getbegx( w ) + 2, getbegy( w ) + 19 ) ); + catacurses::newwin( 4, TERMX - 3, point( getbegx( w ) + 2, TERMY - 5 ) ); draw_points( w, points ); @@ -2277,9 +2276,10 @@ tab_direction set_description( const catacurses::window &w, avatar &you, const b if( current_traits.empty() ) { wprintz( w_traits, c_light_red, _( "None!" ) ); } else { - for( auto ¤t_trait : current_traits ) { - wprintz( w_traits, c_light_gray, "\n" ); - wprintz( w_traits, current_trait->get_display_color(), current_trait->name() ); + for( size_t i = 0; i < current_traits.size(); i++ ) { + const auto current_trait = current_traits[i]; + trim_and_print( w_traits, point( 0, i + 1 ), getmaxx( w_traits ) - 1, + current_trait->get_display_color(), current_trait->name() ); } } wrefresh( w_traits ); @@ -2316,8 +2316,6 @@ tab_direction set_description( const catacurses::window &w, avatar &you, const b } if( !has_skills ) { mvwprintz( w_skills, point( utf8_width( _( "Skills:" ) ) + 1, 0 ), c_light_red, _( "None!" ) ); - } else if( line > 10 ) { - mvwprintz( w_skills, point( utf8_width( _( "Skills:" ) ) + 1, 0 ), c_light_gray, _( "(Top 8)" ) ); } wrefresh( w_skills ); diff --git a/src/pickup.cpp b/src/pickup.cpp index e93daba63854d..7f3f15ce0ef18 100644 --- a/src/pickup.cpp +++ b/src/pickup.cpp @@ -509,6 +509,7 @@ void Pickup::pick_up( const tripoint &p, int min, from_where get_items_from ) g->u.activity.targets.emplace_back( vehicle_cursor( *veh, cargo_part ), &*here.front() ); } else { g->u.activity.targets.emplace_back( map_cursor( p ), &*here.front() ); + g->u.activity.coords.push_back( g->u.pos() ); } // auto-pickup means pick up all. g->u.activity.values.push_back( 0 ); @@ -990,6 +991,7 @@ void Pickup::pick_up( const tripoint &p, int min, from_where get_items_from ) // At this point we've selected our items, register an activity to pick them up. g->u.assign_activity( activity_id( "ACT_PICKUP" ) ); + g->u.activity.coords.push_back( g->u.pos() ); if( min == -1 ) { // Auto pickup will need to auto resume since there can be several of them on the stack. g->u.activity.auto_resume = true; diff --git a/src/player.cpp b/src/player.cpp index 78f0a9ea02c01..f03be82d7d0f7 100644 --- a/src/player.cpp +++ b/src/player.cpp @@ -1916,6 +1916,12 @@ nc_color player::basic_symbol_color() const has_active_optcloak() || has_trait( trait_DEBUG_CLOAK ) ) { return c_dark_gray; } + if( move_mode == PMM_RUN ) { + return c_yellow; + } + if( move_mode == PMM_CROUCH ) { + return c_light_gray; + } return c_white; } @@ -5522,7 +5528,7 @@ void player::suffer() !has_morale( MORALE_PYROMANIA_STARTFIRE ); if( has_trait( trait_PYROMANIA ) && needs_fire && !in_sleep_state() && calendar::once_every( 2_hours ) ) { - add_morale( MORALE_PYROMANIA_NOFIRE, -1, -30, 24_hours, 24_hours ); + add_morale( MORALE_PYROMANIA_NOFIRE, -1, -30, 24_hours, 24_hours, true ); if( calendar::once_every( 4_hours ) ) { std::string smokin_hot_fiyah = SNIPPET.random_from_category( "pyromania_withdrawal" ); add_msg_if_player( m_bad, _( smokin_hot_fiyah ) ); @@ -9920,234 +9926,6 @@ int player::get_armor_fire( body_part bp ) const return get_armor_type( DT_HEAT, bp ); } -static void destroyed_armor_msg( Character &who, const std::string &pre_damage_name ) -{ - if( who.is_avatar() ) { - g->memorial().add( - //~ %s is armor name - pgettext( "memorial_male", "Worn %s was completely destroyed." ), - pgettext( "memorial_female", "Worn %s was completely destroyed." ), - pre_damage_name ); - } - who.add_msg_player_or_npc( m_bad, _( "Your %s is completely destroyed!" ), - _( "'s %s is completely destroyed!" ), - pre_damage_name ); -} - -bool player::armor_absorb( damage_unit &du, item &armor ) -{ - if( rng( 1, 100 ) > armor.get_coverage() ) { - return false; - } - - // TODO: add some check for power armor - armor.mitigate_damage( du ); - - // We want armor's own resistance to this type, not the resistance it grants - const int armors_own_resist = armor.damage_resist( du.type, true ); - if( armors_own_resist > 1000 ) { - // This is some weird type that doesn't damage armors - return false; - } - - // Scale chance of article taking damage based on the number of parts it covers. - // This represents large articles being able to take more punishment - // before becoming ineffective or being destroyed. - const int num_parts_covered = armor.get_covered_body_parts().count(); - if( !one_in( num_parts_covered ) ) { - return false; - } - - // Don't damage armor as much when bypassed by armor piercing - // Most armor piercing damage comes from bypassing armor, not forcing through - const int raw_dmg = du.amount; - if( raw_dmg > armors_own_resist ) { - // If damage is above armor value, the chance to avoid armor damage is - // 50% + 50% * 1/dmg - if( one_in( raw_dmg ) || one_in( 2 ) ) { - return false; - } - } else { - // Sturdy items and power armors never take chip damage. - // Other armors have 0.5% of getting damaged from hits below their armor value. - if( armor.has_flag( "STURDY" ) || armor.is_power_armor() || !one_in( 200 ) ) { - return false; - } - } - - auto &material = armor.get_random_material(); - std::string damage_verb = ( du.type == DT_BASH ) ? material.bash_dmg_verb() : - material.cut_dmg_verb(); - - const std::string pre_damage_name = armor.tname(); - const std::string pre_damage_adj = armor.get_base_material().dmg_adj( armor.damage_level( 4 ) ); - - // add "further" if the damage adjective and verb are the same - std::string format_string = ( pre_damage_adj == damage_verb ) ? - _( "Your %1$s is %2$s further!" ) : _( "Your %1$s is %2$s!" ); - add_msg_if_player( m_bad, format_string, pre_damage_name, damage_verb ); - //item is damaged - if( is_player() ) { - SCT.add( point( posx(), posy() ), NORTH, remove_color_tags( pre_damage_name ), m_neutral, - damage_verb, - m_info ); - } - - return armor.mod_damage( armor.has_flag( "FRAGILE" ) ? - rng( 2 * itype::damage_scale, 3 * itype::damage_scale ) : itype::damage_scale, du.type ); -} - -float player::bionic_armor_bonus( body_part bp, damage_type dt ) const -{ - float result = 0.0f; - // We only check the passive bionics - if( has_bionic( bio_carbon ) ) { - if( dt == DT_BASH ) { - result += 2; - } else if( dt == DT_CUT || dt == DT_STAB ) { - result += 4; - } - } - // All the other bionic armors reduce bash/cut/stab by 3 - // Map body parts to a set of bionics that protect it - // TODO: JSONize passive bionic armor instead of hardcoding it - static const std::map< body_part, bionic_id > armor_bionics = { - { bp_head, { bio_armor_head } }, - { bp_arm_l, { bio_armor_arms } }, - { bp_arm_r, { bio_armor_arms } }, - { bp_torso, { bio_armor_torso } }, - { bp_leg_l, { bio_armor_legs } }, - { bp_leg_r, { bio_armor_legs } }, - { bp_eyes, { bio_armor_eyes } } - }; - auto iter = armor_bionics.find( bp ); - if( iter != armor_bionics.end() && has_bionic( iter->second ) && - ( dt == DT_BASH || dt == DT_CUT || dt == DT_STAB ) ) { - result += 3; - } - return result; -} - -void player::passive_absorb_hit( body_part bp, damage_unit &du ) const -{ - // >0 check because some mutations provide negative armor - // Thin skin check goes before subdermal armor plates because SUBdermal - if( du.amount > 0.0f ) { - // Horrible hack warning! - // Get rid of this as soon as CUT and STAB are split - if( du.type == DT_STAB ) { - damage_unit du_copy = du; - du_copy.type = DT_CUT; - du.amount -= mutation_armor( bp, du_copy ); - } else { - du.amount -= mutation_armor( bp, du ); - } - } - du.amount -= bionic_armor_bonus( bp, du.type ); //Check for passive armor bionics - du.amount -= mabuff_armor_bonus( du.type ); - du.amount = std::max( 0.0f, du.amount ); -} - -void player::absorb_hit( body_part bp, damage_instance &dam ) -{ - std::list worn_remains; - bool armor_destroyed = false; - - for( auto &elem : dam.damage_units ) { - if( elem.amount < 0 ) { - // Prevents 0 damage hits (like from hallucinations) from ripping armor - elem.amount = 0; - continue; - } - - // The bio_ads CBM absorbs damage before hitting armor - if( has_active_bionic( bio_ads ) ) { - if( elem.amount > 0 && get_power_level() > 24_kJ ) { - if( elem.type == DT_BASH ) { - elem.amount -= rng( 1, 8 ); - } else if( elem.type == DT_CUT ) { - elem.amount -= rng( 1, 4 ); - } else if( elem.type == DT_STAB ) { - elem.amount -= rng( 1, 2 ); - } - mod_power_level( -25_kJ ); - } - if( elem.amount < 0 ) { - elem.amount = 0; - } - } - - // Only the outermost armor can be set on fire - bool outermost = true; - // The worn vector has the innermost item first, so - // iterate reverse to damage the outermost (last in worn vector) first. - for( auto iter = worn.rbegin(); iter != worn.rend(); ) { - item &armor = *iter; - - if( !armor.covers( bp ) ) { - ++iter; - continue; - } - - const std::string pre_damage_name = armor.tname(); - bool destroy = false; - - // Heat damage can set armor on fire - // Even though it doesn't cause direct physical damage to it - if( outermost && elem.type == DT_HEAT && elem.amount >= 1.0f ) { - // TODO: Different fire intensity values based on damage - fire_data frd{ 2 }; - destroy = armor.burn( frd ); - int fuel = roll_remainder( frd.fuel_produced ); - if( fuel > 0 ) { - add_effect( effect_onfire, time_duration::from_turns( fuel + 1 ), bp, false, 0, false, true ); - } - } - - if( !destroy ) { - destroy = armor_absorb( elem, armor ); - } - - if( destroy ) { - if( g->u.sees( *this ) ) { - SCT.add( point( posx(), posy() ), NORTH, remove_color_tags( pre_damage_name ), - m_neutral, _( "destroyed" ), m_info ); - } - destroyed_armor_msg( *this, pre_damage_name ); - armor_destroyed = true; - armor.on_takeoff( *this ); - worn_remains.insert( worn_remains.end(), armor.contents.begin(), armor.contents.end() ); - // decltype is the type name of the iterator, note that reverse_iterator::base returns the - // iterator to the next element, not the one the revers_iterator points to. - // http://stackoverflow.com/questions/1830158/how-to-call-erase-with-a-reverse-iterator - iter = decltype( iter )( worn.erase( --( iter.base() ) ) ); - } else { - ++iter; - outermost = false; - } - } - - passive_absorb_hit( bp, elem ); - - if( elem.type == DT_BASH ) { - if( has_trait( trait_LIGHT_BONES ) ) { - elem.amount *= 1.4; - } - if( has_trait( trait_HOLLOW_BONES ) ) { - elem.amount *= 1.8; - } - } - - elem.amount = std::max( elem.amount, 0.0f ); - } - for( item &remain : worn_remains ) { - g->m.add_item_or_charges( pos(), remain ); - } - if( armor_destroyed ) { - drop_invalid_inventory(); - } -} - int player::get_env_resist( body_part bp ) const { int ret = 0; diff --git a/src/player.h b/src/player.h index d77989d71063c..4dcb34262228c 100644 --- a/src/player.h +++ b/src/player.h @@ -497,8 +497,6 @@ class player : public Character int mabuff_block_bonus() const; /** Returns the speed bonus from martial arts buffs */ int mabuff_speed_bonus() const; - /** Returns the armor bonus against given type from martial arts buffs */ - int mabuff_armor_bonus( damage_type type ) const; /** Returns the damage multiplier to given type from martial arts buffs */ float mabuff_damage_mult( damage_type type ) const; /** Returns the flat damage bonus to given type from martial arts buffs, applied after the multiplier */ @@ -612,25 +610,6 @@ class player : public Character /** Checks for valid block abilities and reduces damage accordingly. Returns true if the player blocks */ bool block_hit( Creature *source, body_part &bp_hit, damage_instance &dam ) override; - /** - * Reduces and mutates du, prints messages about armor taking damage. - * @return true if the armor was completely destroyed (and the item must be deleted). - */ - bool armor_absorb( damage_unit &du, item &armor ); - /** - * Check for passive bionics that provide armor, and returns the armor bonus - * This is called from player::passive_absorb_hit - */ - float bionic_armor_bonus( body_part bp, damage_type dt ) const; - /** - * Check for relevant passive, non-clothing that can absorb damage, and reduce by specified - * damage unit. Only flat bonuses are checked here. Multiplicative ones are checked in - * @ref player::absorb_hit. The damage amount will never be reduced to less than 0. - * This is called from @ref player::absorb_hit - */ - void passive_absorb_hit( body_part bp, damage_unit &du ) const; - /** Runs through all bionics and armor on a part and reduces damage through their armor_absorb */ - void absorb_hit( body_part bp, damage_instance &dam ) override; /** Called after the player has successfully dodged an attack */ void on_dodge( Creature *source, float difficulty ) override; /** Handles special defenses from an attack that hit us (source can be null) */ diff --git a/src/player_activity.cpp b/src/player_activity.cpp index eb8d1a3a6e510..7cb848d5d7c3a 100644 --- a/src/player_activity.cpp +++ b/src/player_activity.cpp @@ -61,38 +61,37 @@ std::string player_activity::get_str_value( size_t index, const std::string &def cata::optional player_activity::get_progress_message() const { + if( type == activity_id( "ACT_NULL" ) || get_verb().empty() ) { + return cata::optional(); + } + + std::string extra_info; if( type == activity_id( "ACT_CRAFT" ) ) { if( const item *craft = targets.front().get_item() ) { - return string_format( _( "Crafting: %s" ), craft->tname() ); + extra_info = craft->tname(); } } else if( moves_total > 0 ) { const int percentage = ( ( moves_total - moves_left ) * 100 ) / moves_total; - if( type == activity_id( "ACT_BURROW" ) ) { - return string_format( _( "Burrowing: %d%%" ), percentage ); - } else if( type == activity_id( "ACT_HACKSAW" ) ) { - return string_format( _( "Sawing: %d%%" ), percentage ); - } else if( type == activity_id( "ACT_JACKHAMMER" ) ) { - return string_format( _( "Jackhammering: %d%%" ), percentage ); - } else if( type == activity_id( "ACT_PICKAXE" ) ) { - return string_format( _( "Digging: %d%%" ), percentage ); - } else if( type == activity_id( "ACT_DISASSEMBLE" ) ) { - return string_format( _( "Disassembling: %d%%" ), percentage ); - } else if( + if( type == activity_id( "ACT_BURROW" ) || + type == activity_id( "ACT_HACKSAW" ) || + type == activity_id( "ACT_JACKHAMMER" ) || + type == activity_id( "ACT_PICKAXE" ) || + type == activity_id( "ACT_DISASSEMBLE" ) || type == activity_id( "ACT_FILL_PIT" ) || type == activity_id( "ACT_DIG" ) || - type == activity_id( "ACT_DIG_CHANNEL" ) - ) { - return string_format( _( "Shoveling: %d%%" ), percentage ); - } else if( + type == activity_id( "ACT_DIG_CHANNEL" ) || type == activity_id( "ACT_CHOP_TREE" ) || type == activity_id( "ACT_CHOP_LOGS" ) || type == activity_id( "ACT_CHOP_PLANKS" ) - ) { - return string_format( _( "Chopping: %d%%" ), percentage ); + ) { + extra_info = string_format( "%d%%", percentage ); } } - return cata::optional(); + + return extra_info.empty() ? string_format( _( "%s…" ), + get_verb().translated() ) : string_format( _( "%s: %s" ), + get_verb().translated(), extra_info ); } void player_activity::do_turn( player &p ) diff --git a/src/wish.cpp b/src/wish.cpp index 287bc9092b0b1..aa4b31f7a0b58 100644 --- a/src/wish.cpp +++ b/src/wish.cpp @@ -502,7 +502,7 @@ void debug_menu::wishitem( player *p, int x, int y, int z ) uilist wmenu; wmenu.w_x = 0; wmenu.w_width = TERMX; - wmenu.pad_right = TERMX / 2 > 40 ? TERMX - 40 : TERMX / 2; + wmenu.pad_right = std::max( TERMX / 2, TERMX - 50 ); wmenu.selected = uistate.wishitem_selected; wish_item_callback cb( opts ); wmenu.callback = &cb; diff --git a/tools/format/format.cpp b/tools/format/format.cpp index 0319c4f9246ef..320c7f2aa3cae 100644 --- a/tools/format/format.cpp +++ b/tools/format/format.cpp @@ -204,6 +204,7 @@ int main( int argc, char *argv[] ) fout << out.str(); fout.close(); std::cout << filename << " needs to be linted" << std::endl; + std::cout << "Please read doc/JSON_STYLE.md" << std::endl; exit( EXIT_FAILURE ); } }