diff --git a/data/json/EraOfDecay/flags.json b/data/json/EraOfDecay/flags.json index b5bcc952350b3..8db4cf286717e 100644 --- a/data/json/EraOfDecay/flags.json +++ b/data/json/EraOfDecay/flags.json @@ -23,5 +23,10 @@ "id": "POWERARMOR_NOACTIVE", "type": "json_flag", "info": "This gear is an add-on for power armor, and is not affected by power armor being powered or not." + }, + { + "id": "HOLY_SYMBOL", + "type": "json_flag", + "info": "This gear improves morale of spiritual people if worn." } ] diff --git a/data/json/EraOfDecay/furniture/crafting.json b/data/json/EraOfDecay/furniture/crafting.json index 99a02ad33aa69..1d79007d764c2 100644 --- a/data/json/EraOfDecay/furniture/crafting.json +++ b/data/json/EraOfDecay/furniture/crafting.json @@ -51,5 +51,30 @@ "sound_fail": "whump!", "items": [ { "item": "fire_brick", "count": [ 6, 12 ] } ] } + }, + { + "type": "furniture", + "id": "f_milling_machine", + "name": "milling machine", + "looks_like": "f_machinery_light", + "description": "An industrial-grade machine tool which uses rotary cutters to remove material by advancing a cutter into a workpiece.", + "symbol": "4", + "color": "cyan_red", + "move_cost_mod": -1, + "coverage": 40, + "required_str": 16, + "flags": [ "BLOCKSDOOR" ], + "bash": { + "str_min": 40, + "str_max": 150, + "sound_fail": "clang!", + "items": [ + { "item": "cable", "charges": [ 0, 4 ] }, + { "item": "scrap", "count": [ 12, 20 ] }, + { "item": "steel_chunk", "count": [ 2, 4 ] }, + { "item": "steel_lump", "count": [ 1, 2 ] } + ] + }, + "deconstruct": { "items": [ { "item": "milling_machine", "count": 1 } ] } } ] diff --git a/data/json/EraOfDecay/items/fake.json b/data/json/EraOfDecay/items/fake.json new file mode 100644 index 0000000000000..f3b36476056dd --- /dev/null +++ b/data/json/EraOfDecay/items/fake.json @@ -0,0 +1,8 @@ +[ + { + "id": "milling_machine_tool", + "type": "TOOL", + "copy-from": "fake_appliance_tool", + "name": { "str": "milling machine" } + } +] diff --git a/data/json/EraOfDecay/items/generic/junk.json b/data/json/EraOfDecay/items/generic/junk.json new file mode 100644 index 0000000000000..5147bcd011ce5 --- /dev/null +++ b/data/json/EraOfDecay/items/generic/junk.json @@ -0,0 +1,17 @@ +[ + { + "id": "katana_plastic", + "copy-from": "katana", + "type": "GENERIC", + "name": { "str_sp": "toy katana" }, + "description": "A toy katana made from plastic. Worthless as a weapon.", + "proportional": { "melee_damage": { "bash": 0.6, "cut": 0 } }, + "delete": { "flags": [ "DURABLE_MELEE" ], "techniques": [ "WBLOCK_2" ] }, + "extend": { "flags": [ "FRAGILE_MELEE" ] }, + "material": [ "plastic" ], + "weight": "142 g", + "price": 100, + "price_postapoc": 0, + "qualities": [ ] + } +] diff --git a/data/json/EraOfDecay/items/tools/workshop.json b/data/json/EraOfDecay/items/tools/workshop.json new file mode 100644 index 0000000000000..ba6a9470faee9 --- /dev/null +++ b/data/json/EraOfDecay/items/tools/workshop.json @@ -0,0 +1,33 @@ +[ + { + "type": "GENERIC", + "id": "heavy_lathe", + "category": "tools", + "looks_like": "f_heavy_lathe", + "symbol": "7", + "description": "An industrial-grade lathe, for turning chunks of metal and other hard things into round chunks of metal and other hard things.", + "color": "black_red", + "name": { "str": "disconnected power lathe" }, + "material": [ "steel" ], + "//": "Based off Warco WM 280V Lathe.", + "longest_side": "135 cm", + "volume": "425 L", + "weight": "210 kg", + "price": "4100 USD" + }, + { + "type": "GENERIC", + "id": "milling_machine", + "looks_like": "f_milling_machine", + "symbol": "7", + "description": "An industrial-grade machine tool which uses rotary cutters to remove material by advancing a cutter into a workpiece.", + "color": "black_red", + "name": { "str": "disconnected milling machine" }, + "material": [ "steel" ], + "//": "Based off Warco WM 18B Belt Drive Mill. Volume reduced to account for the fact that this machine isn't a perfect cuboid with those dimensions.", + "longest_side": "126 cm", + "volume": "450 L", + "weight": "230 kg", + "price": "3000 USD" + } +] diff --git a/data/json/EraOfDecay/items/vehicle/rotor.json b/data/json/EraOfDecay/items/vehicle/rotor.json new file mode 100644 index 0000000000000..ea7c739a974a1 --- /dev/null +++ b/data/json/EraOfDecay/items/vehicle/rotor.json @@ -0,0 +1,18 @@ +[ + { + "id": "homebuilt_gyrocopter_rotor", + "type": "GENERIC", + "category": "veh_parts", + "name": { "str": "makeshift gyrocopter rotors", "str_pl": "sets of makeshift gyrocopter rotors" }, + "description": "A set of two-bladed wooden rotor and propeller, as well as a set of machined parts needed to control them, intended for lightweight vehicles put together by hobbyists.", + "price": "10 USD", + "price_postapoc": "2 USD", + "weight": "120 kg", + "volume": "120 L", + "longest_side": "609 cm", + "looks_like": "wind_turbine", + "material": [ "steel", "wood" ], + "symbol": "*", + "color": "brown" + } +] diff --git a/data/json/EraOfDecay/morale_types.json b/data/json/EraOfDecay/morale_types.json index cb1936507850d..507167f58f7ff 100644 --- a/data/json/EraOfDecay/morale_types.json +++ b/data/json/EraOfDecay/morale_types.json @@ -13,5 +13,10 @@ "id": "morale_perm_darkness", "type": "morale_type", "text": "In Dark" + }, + { + "id": "morale_spiritual", + "type": "morale_type", + "text": "Spiritual" } ] diff --git a/data/json/EraOfDecay/mutations/mutations.json b/data/json/EraOfDecay/mutations/mutations.json index a93ae4d90d4bb..d4144ca5a4395 100644 --- a/data/json/EraOfDecay/mutations/mutations.json +++ b/data/json/EraOfDecay/mutations/mutations.json @@ -18,5 +18,26 @@ "category": [ "HUMAN" ], "cancels": [ "RESISTWARM", "STRONGER_RESISTWARM" ], "description": "Your heat tolerance is more or less normal for a human." + }, + { + "type": "mutation", + "id": "PYROMANIA_GOOD", + "name": { "str": "Likes Fire" }, + "points": 1, + "description": "You enjoy lighting fires and standing near them, and gain a morale bonus for doing so.", + "starting_trait": true, + "valid": false + }, + { + "type": "mutation", + "id": "KILLER_GOOD", + "name": { "str": "Killer" }, + "points": 2, + "description": "You derive enjoyment from killing things. Putting end to life seem to spark some dark satisfaction and thrill, and you gain a morale bonus for doing so.", + "social_modifiers": { "intimidate": 10 }, + "cancels": [ "PACIFIST" ], + "flags": [ "CANNIBAL" ], + "starting_trait": true, + "valid": false } ] diff --git a/data/json/EraOfDecay/professions.json b/data/json/EraOfDecay/professions.json new file mode 100644 index 0000000000000..9f104e32dcaad --- /dev/null +++ b/data/json/EraOfDecay/professions.json @@ -0,0 +1,292 @@ +[ + { + "type": "item_group", + "subtype": "collection", + "id": "crossbow_hardened_survivor", + "entries": [ { "item": "crossbow", "ammo-item": "bolt_wood", "charges": 1 } ] + }, + { + "type": "item_group", + "subtype": "collection", + "id": "shotgun_d_roadwarrior", + "entries": [ { "item": "shotgun_d", "ammo-item": "shot_00", "charges": 2, "contents-item": [ "barrel_small", "stock_none" ] } ] + }, + { + "type": "item_group", + "subtype": "collection", + "id": "mags_waste_ranger", + "entries": [ { "item": "blrmag", "ammo-item": "3006", "charges": 4 }, { "item": "blrmag", "ammo-item": "3006", "charges": 4 } ] + }, + { + "type": "item_group", + "subtype": "collection", + "id": "quiver_hardened_survivor", + "entries": [ { "item": "bolt_wood", "charges": 29 } ] + }, + { + "type": "item_group", + "subtype": "collection", + "id": "quiver_player_bandit", + "entries": [ { "item": "bolt_wood", "charges": 19 } ] + }, + { + "type": "item_group", + "subtype": "collection", + "id": "bandolier_roadwarrior", + "entries": [ { "item": "shot_00", "charges": 18 } ] + }, + { + "type": "profession", + "ident": "neckbeard", + "name": "Basement Dweller", + "description": "In this moment, you are euphoric. Not because of any phony god's blessing. But because, it is in times of crisis like these that true gentlesirs and gentleladies are forged. This is it; you've watched your favorite anime over 300 times frame-by-frame. You shall emerge from the abyss a neckbeard of epic proportions.", + "points": 0, + "skills": [ { "level": 1, "name": "computer" } ], + "items": { + "both": { + "items": [ "socks", "trenchcoat_leather", "tshirt", "sunglasses", "fanny", "bodypillow", "nachos", "RPG_die", "cards_magic" ], + "entries": [ + { "group": "charged_cell_phone" }, + { "item": "katana_plastic", "custom-flags": [ "auto_wield" ] }, + { "item": "colamdew", "container-item": "bottle_plastic" }, + { + "item": "light_plus_battery_cell", + "ammo-item": "battery", + "charges": 150, + "container-item": "portable_game" + } + ] + }, + "male": { "items": [ "briefs", "leathersandals", "fedora", "gloves_fingerless", "shorts_cargo", "leather_belt" ] }, + "female": { "items": [ "boy_shorts", "slippers", "pants", "faux_fur_cat_ears", "bracelet_friendship" ] } + }, + "missions": [ "MISSION_OTAKU" ] + }, + { + "type": "profession", + "id": "gyro_pilot", + "name": "Gyrocopter Pilot", + "description": "You always loved tinkering with flying machines as a hobby. With your gyrocopter and what little flight gear you could scrounge up while the world was ending, the sky's the limit.", + "proficiencies": [ "prof_helicopter_pilot", "prof_aircraft_mechanic" ], + "vehicle": "helicopter_gyro", + "points": 4, + "skills": [ { "level": 4, "name": "driving" }, { "level": 3, "name": "fabrication" }, { "level": 3, "name": "mechanics" } ], + "items": { + "both": { + "items": [ + "socks", + "jumpsuit", + "boots_hiking", + "gloves_fingerless", + "helmet_larmor", + "glasses_safety", + "knit_scarf", + "tool_belt", + "wristwatch" + ], + "entries": [ { "group": "charged_smart_phone" }, { "item": "ear_plugs", "custom-flags": [ "no_auto_equip" ] } ] + }, + "male": [ "boxer_shorts" ], + "female": [ "bra", "boy_shorts" ] + } + }, + { + "type": "profession", + "id": "hardened_survivor", + "name": "Hardened Survivor", + "requirement": "achievement_survive_91_days", + "description": "One of the lucky few who escaped the Cataclysm, you made a life for yourself living off nature's bounties and what you could get outside the death traps of the large cities.", + "proficiencies": [ "prof_fibers", "prof_fibers_rope", "prof_knitting", "prof_closures" ], + "points": 6, + "skills": [ + { "level": 6, "name": "survival" }, + { "level": 6, "name": "fabrication" }, + { "level": 6, "name": "tailor" }, + { "level": 5, "name": "melee" }, + { "level": 3, "name": "gun" }, + { "level": 3, "name": "rifle" } + ], + "items": { + "both": { + "items": [ + "survivor_suit", + "socks", + "boots_survivor", + "hood_survivor", + "gloves_survivor", + "wristwatch", + "ref_lighter", + "hand_crank_charger", + "mess_kit" + ], + "entries": [ + { "item": "kukri", "container-item": "sheath" }, + { "item": "survivor_vest", "contents-group": "crossbow_hardened_survivor" }, + { "item": "quiver_large", "contents-group": "quiver_hardened_survivor" }, + { "item": "light_battery_cell", "charges": 100, "container-item": "wearable_light" } + ] + }, + "male": [ "boxer_shorts" ], + "female": [ "sports_bra", "panties" ] + } + }, + { + "type": "profession", + "id": "road_warrior", + "name": "Road Warrior", + "requirement": "achievement_survive_91_days", + "description": "You lived by your wheels at the beginning of the apocalypse, now you're running low on ammo and fuel, and your situation is dire. You've been reduced to a scavenger, living off the corpse of the old world.", + "points": 6, + "proficiencies": [ "prof_handloading", "prof_metalworking", "prof_welding_basic", "prof_closures" ], + "vehicle": "car_roadwarrior", + "skills": [ + { "level": 3, "name": "driving" }, + { "level": 3, "name": "fabrication" }, + { "level": 3, "name": "mechanics" }, + { "level": 3, "name": "tailor" }, + { "level": 2, "name": "survival" }, + { "level": 2, "name": "gun" }, + { "level": 1, "name": "shotgun" }, + { "level": 1, "name": "melee" }, + { "level": 1, "name": "stabbing" }, + { "level": 1, "name": "firstaid" } + ], + "items": { + "both": { + "items": [ + "tank_top", + "pants_leather", + "jacket_leather_mod", + "boots_steel", + "gloves_fingerless_mod", + "hat_cotton", + "long_patchwork_scarf", + "legrig", + "canteen", + "binoculars", + "ref_lighter", + "press_dowel", + "makeshift_hose", + "mess_kit" + ], + "entries": [ + { "item": "tool_belt", "contents-item": [ "knife_combat", "pliers", "wrench", "hacksaw" ] }, + { "item": "XL_holster", "contents-group": "shotgun_d_roadwarrior" }, + { "item": "bandolier_shotgun", "contents-group": "bandolier_roadwarrior" } + ] + }, + "male": [ "boxer_shorts" ], + "female": [ "sports_bra", "boy_shorts" ] + } + }, + { + "type": "profession", + "ident": "waste_ranger", + "name": "Wasteland Ranger", + "requirement": "achievement_survive_91_days", + "description": "If the human race is to survive, the threats facing its existence must be eliminated, no matter the cost. If it's hostile, you kill it.", + "proficiencies": [ "prof_handloading", "prof_closures" ], + "points": 6, + "skills": [ + { "level": 6, "name": "tailor" }, + { "level": 5, "name": "fabrication" }, + { "level": 3, "name": "survival" }, + { "level": 3, "name": "gun" }, + { "level": 2, "name": "cooking" }, + { "level": 2, "name": "rifle" }, + { "level": 1, "name": "dodge" }, + { "level": 1, "name": "melee" }, + { "level": 1, "name": "pistol" }, + { "level": 1, "name": "stabbing" } + ], + "items": { + "both": { + "ammo": 100, + "items": [ + "sheriffshirt", + "duster_survivor", + "pants_survivor", + "boots_lsurvivor", + "gloves_lsurvivor", + "mask_gas", + "helmet_army", + "badge_deputy", + "canteen", + "wristwatch", + "puller", + "press", + "ref_lighter", + "legpouch_large" + ], + "entries": [ + { "item": "knife_trench", "container-item": "sheath" }, + { "item": "browning_blr", "ammo-item": "3006", "charges": 4, "contents-item": "shoulder_strap" }, + { "item": "legpouch_large", "contents-group": "mags_waste_ranger" }, + { "item": "3006", "charges": 8 }, + { "item": "sw_619", "ammo-item": "357mag_jhp", "charges": 7, "container-item": "holster" }, + { "item": "38_speedloader", "ammo-item": "357mag_jhp", "charges": 7 }, + { "item": "38_speedloader", "ammo-item": "357mag_jhp", "charges": 7 }, + { "item": "357mag_jhp", "charges": 29 }, + { "item": "light_battery_cell", "charges": 100, "container-item": "wearable_light" }, + { "item": "survivor_mess_kit", "charges": 30 } + ] + }, + "male": [ "boxer_shorts" ], + "female": [ "sports_bra", "boy_shorts" ] + } + }, + { + "type": "profession", + "id": "player_bandit", + "name": "Veteran Bandit", + "requirement": "achievement_survive_91_days", + "description": "After the cities exploded there was a whirlwind of looting; a firestorm of fear. Men began to feed on men. On the roads it was a white line nightmare. Looting, killing, drug-running, one way or another you'll live and die on your bike.", + "points": 6, + "proficiencies": [ "prof_intro_chemistry", "prof_metalworking", "prof_welding_basic" ], + "vehicle": "motorcycle_methcart", + "skills": [ + { "level": 5, "name": "chemistry" }, + { "level": 3, "name": "mechanics" }, + { "level": 2, "name": "cooking" }, + { "level": 2, "name": "driving" }, + { "level": 2, "name": "gun" }, + { "level": 2, "name": "pistol" }, + { "level": 2, "name": "melee" }, + { "level": 2, "name": "bashing" }, + { "level": 2, "name": "dodge" }, + { "level": 2, "name": "tailor" }, + { "level": 1, "name": "fabrication" }, + { "level": 1, "name": "firstaid" }, + { "level": 1, "name": "survival" } + ], + "items": { + "both": { + "items": [ + "gold_ear", + "motorbike_armor", + "pants_leather", + "chaps_leather", + "motorbike_boots", + "vambrace_larmor", + "gauntlets_larmor", + "pickelhaube", + "mask_hockey", + "camelbak", + "dump_pouch", + "survivor_scope", + "ref_lighter", + "wristwatch" + ], + "entries": [ + { "item": "crossbow", "ammo-item": "bolt_wood", "charges": 1, "container-item": "single_sling" }, + { "item": "quiver", "contents-group": "quiver_player_bandit" }, + { "item": "makeshift_knife", "container-item": "bootsheath" }, + { "item": "bwirebat", "custom-flags": [ "auto_wield" ] }, + { "item": "light_battery_cell", "charges": 100, "container-item": "heavy_flashlight" } + ] + }, + "male": [ "boxer_shorts" ], + "female": [ "sports_bra", "boy_shorts" ] + } + } +] diff --git a/data/json/EraOfDecay/proficiencies/metalwork.json b/data/json/EraOfDecay/proficiencies/metalwork.json new file mode 100644 index 0000000000000..00c184e165f93 --- /dev/null +++ b/data/json/EraOfDecay/proficiencies/metalwork.json @@ -0,0 +1,26 @@ +[ + { + "type": "proficiency", + "id": "prof_machining", + "category": "prof_smithing", + "name": { "str": "Basic Machining" }, + "description": "You have a basic understanding of the different types of precision metalworking machinery and their purposes, including lathes, milling machines, presses, and some others.", + "can_learn": true, + "default_time_multiplier": 3, + "default_skill_penalty": 0.5, + "time_to_learn": "8 h", + "required_proficiencies": [ "prof_metalworking" ] + }, + { + "type": "proficiency", + "id": "prof_machining_skilled", + "category": "prof_smithing", + "name": { "str": "Skilled Machining" }, + "description": "You have a significant amount of experience with machine tools, and are unlikely to have any major difficulties in performing most machining operations, as long as you have all the suitable tools for them.", + "can_learn": true, + "default_time_multiplier": 2, + "default_skill_penalty": 0.25, + "time_to_learn": "20 h", + "required_proficiencies": [ "prof_machining" ] + } +] diff --git a/data/json/EraOfDecay/recipes/construction.json b/data/json/EraOfDecay/recipes/construction.json index d94017378ba12..300792b1c438c 100644 --- a/data/json/EraOfDecay/recipes/construction.json +++ b/data/json/EraOfDecay/recipes/construction.json @@ -67,5 +67,29 @@ "byproducts": [ { "item": "material_sand_black", "charges": [ 200, 400 ] } ], "pre_terrain": "t_sand_black", "post_special": "done_extract_maybe_revert_to_dirt" + }, + { + "type": "construction", + "id": "app_heavy_lathe", + "group": "place_heavy_lathe", + "category": "APPLIANCE", + "required_skills": [ [ "fabrication", 0 ] ], + "time": "5 m", + "components": [ [ [ "heavy_lathe", 1 ] ] ], + "pre_special": "check_empty", + "post_special": "done_appliance", + "activity_level": "BRISK_EXERCISE" + }, + { + "type": "construction", + "id": "app_milling_machine", + "group": "place_milling_machine", + "category": "APPLIANCE", + "required_skills": [ [ "fabrication", 0 ] ], + "time": "5 m", + "components": [ [ [ "milling_machine", 1 ] ] ], + "pre_special": "check_empty", + "post_special": "done_appliance", + "activity_level": "BRISK_EXERCISE" } ] diff --git a/data/json/EraOfDecay/recipes/construction_group.json b/data/json/EraOfDecay/recipes/construction_group.json index a08bbeaa03ded..5f4cb4c044ee2 100644 --- a/data/json/EraOfDecay/recipes/construction_group.json +++ b/data/json/EraOfDecay/recipes/construction_group.json @@ -28,5 +28,15 @@ "type": "construction_group", "id": "build_bloomery", "name": "Build Bloomery" + }, + { + "type": "construction_group", + "id": "place_heavy_lathe", + "name": "Place Heavy Lathe" + }, + { + "type": "construction_group", + "id": "place_milling_machine", + "name": "Place Milling Machine" } ] diff --git a/data/json/EraOfDecay/recipes/other/vehicle.json b/data/json/EraOfDecay/recipes/other/vehicle.json new file mode 100644 index 0000000000000..a6dab1fe8cb6f --- /dev/null +++ b/data/json/EraOfDecay/recipes/other/vehicle.json @@ -0,0 +1,51 @@ +[ + { + "type": "recipe", + "result": "homebuilt_gyrocopter_rotor", + "category": "CC_OTHER", + "subcategory": "CSC_OTHER_VEHICLE", + "skill_used": "fabrication", + "skills_required": [ "mechanics", 8 ], + "difficulty": 9, + "time": "4 d", + "book_learn": [ [ "textbook_fabrication", 8 ], [ "textbook_carpentry", 8 ], [ "textbook_mechanics", 8 ] ], + "proficiencies": [ + { "proficiency": "prof_carpentry_basic" }, + { "proficiency": "prof_metalworking" }, + { "proficiency": "prof_welding_basic" }, + { "proficiency": "prof_welding" }, + { "proficiency": "prof_blacksmithing" }, + { "proficiency": "prof_machining" }, + { "proficiency": "prof_machining_skilled" }, + { "proficiency": "prof_aircraft_mechanic", "required": true } + ], + "using": [ + [ "welding_standard", 10 ], + [ "blacksmithing_standard", 32 ], + [ "steel_standard", 12 ], + [ "tailoring_cotton_patchwork", 24 ] + ], + "qualities": [ + { "id": "SCREW", "level": 1 }, + { "id": "CUT", "level": 2 }, + { "id": "WRENCH", "level": 2 }, + { "id": "SAW_M", "level": 2 }, + { "id": "SAW_W", "level": 2 }, + { "id": "FILE", "level": 1 }, + { "id": "GRIND", "level": 2 } + ], + "tools": [ + [ [ "drill_press_tool", 400 ] ], + [ [ "heavy_lathe_tool", 400 ] ], + [ [ "hydraulic_press_tool", 400 ] ], + [ [ "milling_machine_tool", 400 ] ] + ], + "components": [ + [ [ "2x4", 30 ], [ "wood_panel", 6 ] ], + [ [ "sheet_metal_small", 10 ] ], + [ [ "nail", 20 ] ], + [ [ "nuts_bolts", 20 ] ], + [ [ "superglue", 16 ] ] + ] + } +] diff --git a/data/json/EraOfDecay/vehicleparts/appliance.json b/data/json/EraOfDecay/vehicleparts/appliance.json index 7454cc074ff86..e73b39cd27f68 100644 --- a/data/json/EraOfDecay/vehicleparts/appliance.json +++ b/data/json/EraOfDecay/vehicleparts/appliance.json @@ -74,5 +74,53 @@ { "count": [ 4, 6 ], "item": "steel_chunk" }, { "count": [ 4, 6 ], "item": "scrap" } ] + }, + { + "type": "vehicle_part", + "id": "ap_heavy_lathe", + "name": { "str": "power lathe" }, + "looks_like": "f_heavy_lathe", + "symbol": "7", + "color": "black_red", + "categories": [ "utility" ], + "description": "An industrial-grade lathe, for turning chunks of metal and other hard things into round chunks of metal and other hard things. Plugged in and ready to go.", + "damage_modifier": 10, + "damage_reduction": { "all": 30 }, + "durability": 80, + "flags": [ "OBSTACLE", "APPLIANCE" ], + "pseudo_tools": [ { "id": "heavy_lathe_tool" } ], + "epower": "0 W", + "item": "heavy_lathe", + "breaks_into": [ + { "item": "cable", "charges": [ 0, 4 ] }, + { "item": "scrap", "count": [ 8, 12 ] }, + { "item": "steel_chunk", "count": [ 2, 4 ] }, + { "item": "steel_lump", "count": [ 1, 2 ] }, + { "item": "steel_plate", "count": [ 1, 2 ] } + ] + }, + { + "type": "vehicle_part", + "id": "ap_milling_machine", + "name": { "str": "milling machine" }, + "looks_like": "f_milling_machine", + "symbol": "7", + "color": "black_red", + "categories": [ "utility" ], + "description": "An industrial-grade machine tool which uses rotary cutters to remove material by advancing a cutter into a workpiece. Plugged in and ready to go.", + "damage_modifier": 10, + "damage_reduction": { "all": 30 }, + "durability": 80, + "flags": [ "OBSTACLE", "APPLIANCE" ], + "pseudo_tools": [ { "id": "milling_machine_tool" } ], + "epower": "0 W", + "item": "milling_machine", + "breaks_into": [ + { "item": "cable", "charges": [ 0, 4 ] }, + { "item": "scrap", "count": [ 8, 12 ] }, + { "item": "steel_chunk", "count": [ 2, 4 ] }, + { "item": "steel_lump", "count": [ 1, 2 ] }, + { "item": "steel_plate", "count": [ 1, 2 ] } + ] } ] diff --git a/data/json/EraOfDecay/vehicleparts/rotor.json b/data/json/EraOfDecay/vehicleparts/rotor.json new file mode 100644 index 0000000000000..04d8786172dd7 --- /dev/null +++ b/data/json/EraOfDecay/vehicleparts/rotor.json @@ -0,0 +1,26 @@ +[ + { + "id": "gyrocopter_rotors", + "copy-from": "helicopter_rotors", + "type": "vehicle_part", + "name": "gyrocopter rotors", + "item": "homebuilt_gyrocopter_rotor", + "looks_like": "small_helicopter_rotor", + "rotor_diameter": 6, + "requirements": { + "install": { "skills": [ [ "mechanics", 5 ] ], "time": "1 h", "using": [ [ "vehicle_wrench_2", 1 ] ] }, + "removal": { "skills": [ [ "mechanics", 5 ] ], "time": "30 m", "using": [ [ "vehicle_wrench_2", 1 ] ] }, + "repair": { "skills": [ [ "mechanics", 6 ] ], "time": "1 h", "using": [ [ "repair_welding_standard", 10 ] ] } + }, + "durability": 50, + "description": "A pair of rotor blades powered by a propeller, for light vehicles.", + "damage_modifier": 80, + "breaks_into": [ + { "item": "scrap", "count": [ 4, 8 ] }, + { "item": "steel_chunk", "count": [ 1, 4 ] }, + { "item": "splinter", "count": [ 15, 30 ] } + ], + "damage_reduction": { "all": 10 }, + "extend": { "flags": [ "DIFFICULT_PART" ] } + } +] diff --git a/data/json/EraOfDecay/vehicles/custom_vehicles.json b/data/json/EraOfDecay/vehicles/custom_vehicles.json new file mode 100644 index 0000000000000..1bc7b9421630d --- /dev/null +++ b/data/json/EraOfDecay/vehicles/custom_vehicles.json @@ -0,0 +1,109 @@ +[ + { + "id": "car_roadwarrior", + "type": "vehicle", + "name": "Wasteland Interceptor", + "blueprint": [ + [ "o--+-o" ], + [ "_=##'|" ], + [ "_=#k'|" ], + [ "o--+-o" ] + ], + "parts": [ + { + "x": 0, + "y": 0, + "parts": [ "frame_vertical_2", "seat", "seatbelt", "controls", "dashboard", "vehicle_clock", "horn_car", "roof" ] + }, + { "x": 0, "y": 1, "parts": [ "frame_vertical_2", "animal_compartment", "roof" ] }, + { "x": 0, "y": -1, "parts": [ "frame_vertical", "door" ] }, + { "x": 0, "y": 2, "parts": [ "frame_vertical", "door" ] }, + { "x": -1, "y": 0, "parts": [ "frame_vertical_2", "seat", "seatbelt", "roof" ] }, + { "x": -1, "y": 1, "parts": [ "frame_vertical_2", "seat", "seatbelt", "roof" ] }, + { "x": -1, "y": -1, "parts": [ "frame_vertical", "halfboard_vertical" ] }, + { "x": -1, "y": 2, "parts": [ "frame_vertical", "halfboard_vertical" ] }, + { "x": 1, "y": 0, "parts": [ "frame_horizontal", "windshield" ] }, + { "x": 1, "y": 1, "parts": [ "frame_horizontal", "windshield" ] }, + { "x": 1, "y": -1, "parts": [ "frame_vertical", "windshield" ] }, + { "x": 1, "y": 2, "parts": [ "frame_vertical", "windshield" ] }, + { + "x": 2, + "y": 0, + "parts": [ "frame_horizontal", "engine_v8", "alternator_truck", "battery_car", "halfboard_horizontal" ] + }, + { "x": 2, "y": 1, "parts": [ "frame_horizontal", "halfboard_horizontal" ] }, + { + "x": 2, + "y": -1, + "parts": [ "frame_nw", "halfboard_nw", "wheel_mount_medium_steerable", "wheel", "headlight" ] + }, + { + "x": 2, + "y": 2, + "parts": [ "frame_ne", "halfboard_ne", "wheel_mount_medium_steerable", "wheel", "headlight" ] + }, + { + "x": -2, + "y": 0, + "parts": [ "frame_vertical", "trunk", "medium_storage_battery", "roof", "afs_small_roof_external_tank" ] + }, + { + "x": -2, + "y": 1, + "parts": [ "frame_vertical", "trunk", "battery_charger", "roof", "afs_small_roof_external_tank" ] + }, + { + "x": -2, + "y": -1, + "parts": [ "frame_vertical", "halfboard_vertical", { "part": "tank", "fuel": "gasoline" } ] + }, + { "x": -2, "y": 2, "parts": [ "frame_vertical", "halfboard_vertical", "muffler" ] }, + { "x": -3, "y": -1, "parts": [ "frame_horizontal", "halfboard_sw", "wheel_mount_medium", "wheel" ] }, + { "x": -3, "y": 0, "parts": [ "frame_horizontal", "door_trunk" ] }, + { "x": -3, "y": 1, "parts": [ "frame_horizontal", "door_trunk" ] }, + { "x": -3, "y": 2, "parts": [ "frame_horizontal", "halfboard_se", "wheel_mount_medium", "wheel" ] } + ], + "items": [ { "x": -2, "y": 1, "chance": 100, "items": [ "jerrycan" ] } ] + }, + { + "id": "motorcycle_methcart", + "type": "vehicle", + "name": "Meth Bike", + "blueprint": [ + [ "o#>o-" ], + [ " #>- " ] + ], + "parts": [ + { + "x": 0, + "y": 0, + "parts": [ + "frame_vertical_2", + "saddle_motor", + "controls", + "controls_electronic", + "vehicle_alarm", + "horn_car", + "engine_1cyl_large", + "alternator_motorbike" + ] + }, + { + "x": -1, + "y": 0, + "parts": [ "frame_vertical", "wheel_mount_light", "wheel_motorbike_rear", "muffler", "box" ] + }, + { "x": 1, "y": 0, "parts": [ "frame_handle", { "part": "tank", "fuel": "gasoline" }, "headlight" ] }, + { "x": 2, "y": 0, "parts": [ "frame_vertical", "wheel_mount_light_steerable", "wheel_motorbike" ] }, + { "x": 3, "y": 0, "parts": [ "ram_spiked" ] }, + { + "x": 0, + "y": 1, + "parts": [ "frame_cross", "wheel_mount_light", "wheel_motorbike", "veh_tools_kitchen", "medium_storage_battery" ] + }, + { "x": 1, "y": 1, "parts": [ "frame_handle", "box" ] }, + { "x": 2, "y": 1, "parts": [ "ram_spiked" ] } + ], + "items": [ { "x": 0, "y": 1, "chance": 50, "item_groups": [ "meth_ingredients", "meth_ingredients" ] } ] + } +] diff --git a/data/json/EraOfDecay/vehicles/helicopters.json b/data/json/EraOfDecay/vehicles/helicopters.json new file mode 100644 index 0000000000000..be20142f6cf5a --- /dev/null +++ b/data/json/EraOfDecay/vehicles/helicopters.json @@ -0,0 +1,39 @@ +[ + { + "id": "helicopter_gyro", + "type": "vehicle", + "name": "Gyrocopter", + "blueprint": [ [ "-X#" ] ], + "parts": [ + { + "x": 0, + "y": 0, + "parts": [ + "xlframe_cross", + "seat", + "seatbelt", + { "part": "tank", "fuel": "gasoline" }, + "controls", + "dashboard", + "wheel_mount_light_steerable", + "wheel_motorbike" + ] + }, + { + "x": -1, + "y": 0, + "parts": [ + "xlframe_vertical", + "stowboard_vertical", + "engine_inline4", + "alternator_car", + "battery_car", + "gyrocopter_rotors", + "wheel_mount_light", + "wheel_motorbike_rear" + ] + }, + { "x": -2, "y": 0, "parts": [ "xlframe_vertical" ] } + ] + } +] diff --git a/data/json/furniture_and_terrain/furniture-tools.json b/data/json/furniture_and_terrain/furniture-tools.json index 4c26137d05ab4..e419164cef9d8 100644 --- a/data/json/furniture_and_terrain/furniture-tools.json +++ b/data/json/furniture_and_terrain/furniture-tools.json @@ -1112,16 +1112,7 @@ { "item": "steel_lump", "count": [ 1, 2 ] } ] }, - "deconstruct": { - "items": [ - { "item": "cable", "charges": [ 4, 8 ] }, - { "item": "steel_chunk", "count": [ 4, 6 ] }, - { "item": "steel_lump", "count": [ 2, 4 ] }, - { "item": "scrap", "count": [ 12, 16 ] }, - { "item": "pipe", "count": [ 0, 4 ] }, - { "item": "motor_small", "count": 1 } - ] - } + "deconstruct": { "items": [ { "item": "heavy_lathe", "count": 1 } ] } }, { "type": "furniture", diff --git a/data/json/itemgroups/Locations_MapExtras/mall_item_groups.json b/data/json/itemgroups/Locations_MapExtras/mall_item_groups.json index 12303c77b8224..9e0dc2b6c0bb3 100644 --- a/data/json/itemgroups/Locations_MapExtras/mall_item_groups.json +++ b/data/json/itemgroups/Locations_MapExtras/mall_item_groups.json @@ -105,6 +105,7 @@ "ammo": 75, "magazine": 100, "items": [ + { "item": "katana_plastic", "prob": 10 }, [ "bat_nerf", 100 ], { "item": "portable_game", "prob": 60, "charges": 100 }, [ "bat", 60 ], diff --git a/data/json/itemgroups/Locations_MapExtras/mansion.json b/data/json/itemgroups/Locations_MapExtras/mansion.json index e4534caa1756a..ca3a4ecffa218 100644 --- a/data/json/itemgroups/Locations_MapExtras/mansion.json +++ b/data/json/itemgroups/Locations_MapExtras/mansion.json @@ -665,6 +665,7 @@ "magazine": 100, "subtype": "distribution", "items": [ + { "item": "katana_plastic", "prob": 10 }, [ "bat_nerf", 70 ], { "item": "marble", "prob": 50, "charges": [ 1, 20 ] }, [ "talking_doll", 50 ], diff --git a/data/json/itemgroups/collections_domestic.json b/data/json/itemgroups/collections_domestic.json index b1cae87270c38..237199a2257a5 100644 --- a/data/json/itemgroups/collections_domestic.json +++ b/data/json/itemgroups/collections_domestic.json @@ -1016,6 +1016,7 @@ "magazine": 100, "subtype": "distribution", "entries": [ + { "item": "katana_plastic", "prob": 2 }, { "item": "oxygen_mask", "prob": 3 }, { "item": "awl_steel", "prob": 5 }, { "item": "loom_frame", "prob": 1 }, diff --git a/data/json/itemgroups/stashes.json b/data/json/itemgroups/stashes.json index e7699827d557a..f0903e4abd564 100644 --- a/data/json/itemgroups/stashes.json +++ b/data/json/itemgroups/stashes.json @@ -358,6 +358,7 @@ "subtype": "distribution", "//": "this list is for toys that children may have wanted to take with themselves while preparing to run away for whatever reason.", "items": [ + { "item": "katana_plastic", "prob": 20 }, { "item": "talking_doll", "prob": 50 }, { "item": "teddy_bear", "prob": 52 }, { "item": "toy_figurine", "prob": 45 }, diff --git a/data/json/items/armor/jewelry.json b/data/json/items/armor/jewelry.json index 732850cd5b629..4df3eb4aecbb0 100644 --- a/data/json/items/armor/jewelry.json +++ b/data/json/items/armor/jewelry.json @@ -1095,7 +1095,7 @@ "symbol": "[", "color": "white", "use_action": [ "MEDITATE" ], - "flags": [ "NO_WEAR_EFFECT" ] + "flags": [ "NO_WEAR_EFFECT", "HOLY_SYMBOL" ] }, { "id": "holy_symbol", @@ -1110,7 +1110,7 @@ "symbol": ",", "color": "yellow", "use_action": [ "MEDITATE" ], - "flags": [ "NO_WEAR_EFFECT" ], + "flags": [ "NO_WEAR_EFFECT", "HOLY_SYMBOL" ], "variant_type": "generic", "variants": [ { @@ -1499,7 +1499,7 @@ "symbol": ",", "color": "brown", "use_action": [ "MEDITATE" ], - "flags": [ "NO_WEAR_EFFECT" ] + "flags": [ "NO_WEAR_EFFECT", "HOLY_SYMBOL" ] }, { "id": "jade_brooch", diff --git a/data/json/mapgen/abandoned_barn.json b/data/json/mapgen/abandoned_barn.json index d07ad501fed07..a7f892bdf6c5c 100644 --- a/data/json/mapgen/abandoned_barn.json +++ b/data/json/mapgen/abandoned_barn.json @@ -506,7 +506,7 @@ { "chance": 10, "item": "hardware_bulk", "x": 7, "y": 12 }, { "chance": 10, "item": "plumbing_bulk", "x": 8, "y": 12 } ], - "place_vehicles": [ { "chance": 100, "fuel": 0, "rotation": 180, "status": 1, "vehicle": "tractor_plow", "x": 10, "y": 9 } ], + "place_vehicles": [ { "chance": 100, "fuel": 0, "rotation": 180, "status": 1, "vehicle": "farm_vehicles", "x": 10, "y": 9 } ], "place_rubble": [ { "repeat": [ 0, 40 ], "x": [ 6, 18 ], "y": [ 5, 13 ] }, { "repeat": [ 0, 8 ], "x": [ 6, 9 ], "y": [ 17, 22 ] }, diff --git a/data/json/mapgen/gas_stations/gas_station_bunker.json b/data/json/mapgen/gas_stations/gas_station_bunker.json index e25bcd270d4ea..cae9b110f2578 100644 --- a/data/json/mapgen/gas_stations/gas_station_bunker.json +++ b/data/json/mapgen/gas_stations/gas_station_bunker.json @@ -291,7 +291,7 @@ "|.r.rxc...||||||||||||||", "|xx../|...q|K;K| ", "|||+|||...q|K.K|||||||||", - "|B.;.B|.;.|||e||!X!!!!!|", + "|B.;.B|.;.|||e||!X!!a!!|", "|B.C.B|...|xx;.c.....;!|", "|B.C.B|...d....d..!Ă..U|", "|B.C.B|...|Y..Yc.;....!|", @@ -374,6 +374,7 @@ "s": "f_chemical_mixer", "T": "f_arcfurnace_empty", "U": "f_heavy_lathe", + "a": "f_milling_machine", "X": "f_drill_press", "z": "f_arcfurnace_empty", "Ă": "f_drill_press", diff --git a/data/json/mapgen/s_lightindustry.json b/data/json/mapgen/s_lightindustry.json index 377087da42600..336f35cc5b839 100644 --- a/data/json/mapgen/s_lightindustry.json +++ b/data/json/mapgen/s_lightindustry.json @@ -14,7 +14,7 @@ "................................................", "#%%%%#%%%%#%%%%#%%#%%%%#%%%%#%%%%#%%%%#%%%%#....", "##::###::###::##::#######oo###oo###oo###oo##^%%#", - "#!{!v#rrrP#Prrr#HHHN#jk#U~~UUU~~U#~55~d~88~##o##", + "#!{!v#rrrP#Prrr#HHHN#jk#U~~UUU~~U#~55~d~08~##o##", "#!}}!: h h :!!!H#;;#U~~~~~~~U#~~~~d~~~~#ppp#", "#!!!!: :NN!H#M;#U~~~~~~~U#dd&dd~~~~:;q;o", "#L!!!:r hrh ) ##+##ddddd&d##~~~~~~K~~:;;;#", @@ -79,7 +79,7 @@ "#rh + #Y;j#Q~Q#~~~~~~~~~5##+# #B r#", "###+##P ####### +;;k#Q~Q#~52~~~~~~2#;;# # hr#", "#P B#P #mnlkn# #####Q~Q#~~~~~4K~~~#jk# # P#", - "orh u# +;;;;;+ +;;k#Q~Q#~52~~~~~~8####+##o##", + "orh u# +;;;;;+ +;;k#Q~Q#~52~~~~~~0####+##o##", "#r u#t #qpq;Y# #Y;j#Q~Q#~~~~~~~~~8#^sssss...", "###o###+####o########o###o####o####o###.sssss..." ], @@ -123,6 +123,7 @@ "3": "t_thconc_floor", "4": "t_thconc_floor", "9": "t_thconc_floor", + "0": "t_thconc_floor", "`": "t_metal_floor", ":": "t_wall_glass", ")": "t_door_glass_c", @@ -175,6 +176,7 @@ "3": "f_air_compressor", "4": "f_drill_press", "9": "f_heavy_lathe", + "0": "f_milling_machine", "K": "f_beverly_shear", "C": "f_crate_c" }, diff --git a/data/json/mapgen/s_lightindustry_scen.json b/data/json/mapgen/s_lightindustry_scen.json index 03e2d6c71d0a9..55523ada52c70 100644 --- a/data/json/mapgen/s_lightindustry_scen.json +++ b/data/json/mapgen/s_lightindustry_scen.json @@ -14,7 +14,7 @@ "................................................", "#%%%%#%%%%#%%%%#%%#%%%%#%%%%#%%%%#%%%%#%%%%#....", "##::###::###::##::#######oo###oo###oo###oo##^%%#", - "#!{!v#rrrP#Prrr#HHHN#jk#U~~UUU~~U#~55~d~88~##o##", + "#!{!v#rrrP#Prrr#HHHN#jk#U~~UUU~~U#~55~d~08~##o##", "#!}}!: h h :!!!H#;;#U~~~~~~~U#~~~~d~~~~#ppp#", "#!!!!: :NN!H#M;#U~~~~~~~U#dd&dd~~~~:;q;o", "#L!!!:r hrh ) ##+##ddddd&d##~~~~~~K~~:;;;#", @@ -79,7 +79,7 @@ "#rh + #Y;j#Q~Q#~~~~~~~~~5##+# #B r#", "###+##P ####### +;;k#Q~Q#~52~~~~~~2#;;# # hr#", "#P B#P #mnlkn# #####Q~Q#~~~~~4K~~~#jk# # P#", - "orh u# +;;;;;+ +;;k#Q~Q#~52~~~~~~8####+##o##", + "orh u# +;;;;;+ +;;k#Q~Q#~52~~~~~~0####+##o##", "#r u#t #qpq;Y# #Y;j#Q~Q#~~~~~~~~~8#^sssss...", "###o###+####o########o###o####o####o###.sssss..." ], @@ -123,6 +123,7 @@ "3": "t_thconc_floor", "4": "t_thconc_floor", "9": "t_thconc_floor", + "0": "t_thconc_floor", "`": "t_metal_floor", ":": "t_wall_glass", ")": "t_door_glass_c", @@ -175,6 +176,7 @@ "3": "f_air_compressor", "4": "f_drill_press", "9": "f_heavy_lathe", + "0": "f_milling_machine", "K": "f_beverly_shear", "C": "f_crate_c" }, diff --git a/data/json/mutations/mutations.json b/data/json/mutations/mutations.json index 519b811b058b7..f316506586424 100644 --- a/data/json/mutations/mutations.json +++ b/data/json/mutations/mutations.json @@ -1141,14 +1141,11 @@ "type": "mutation", "id": "KILLER", "name": { "str": "Killer Drive" }, - "points": 2, - "description": "You derive enjoyment from killing things. Putting end to life seem to spark some dark satisfaction and thrill, and you crave it every moment.", + "points": -1, + "description": "You are obsessed with killing things. Your morale suffers as long as you don't make regular kills.", "starting_trait": true, "valid": false, - "social_modifiers": { "intimidate": 10 }, - "types": [ "HUMAN_EMPATHY" ], - "prereqs": [ "PSYCHOPATH" ], - "flags": [ "CANNIBAL" ] + "cancels": [ "PACIFIST" ] }, { "type": "mutation", @@ -1792,7 +1789,8 @@ "starting_trait": true, "social_modifiers": { "intimidate": -10 }, "valid": false, - "types": [ "HUMAN_EMPATHY", "PREDATION" ] + "types": [ "HUMAN_EMPATHY", "PREDATION" ], + "cancels": [ "KILLER", "KILLER_GOOD" ] }, { "type": "mutation", @@ -7792,8 +7790,8 @@ "type": "mutation", "id": "PYROMANIA", "name": { "str": "Pyromaniac" }, - "points": -2, - "description": "You have an unhealthy obsession with fire, and you get anxious if you don't light them every now and then or stand near them often. However, you gain a mood bonus from doing so.", + "points": -3, + "description": "You have an unhealthy obsession with fire, and you get anxious if you don't light them every now and then or stand near them often.", "starting_trait": true }, { diff --git a/data/json/professions.json b/data/json/professions.json index 0f47d0b9d6446..21b778abe4923 100644 --- a/data/json/professions.json +++ b/data/json/professions.json @@ -611,7 +611,7 @@ "id": "sheltered_survivor", "name": "Sheltered Survivor", "requirement": "achievement_survive_28_days", - "description": "At the start of the Cataclysm, you hunkered down in a bomb shelter. You've spent the past months eating canned food, reading books, and tinkering. Now it is winter - time to face the world above.", + "description": "Just as the first troubles started, you hunkered down in a shelter. You've spent the past months eating canned food, reading books, and tinkering. Now it is time to face the new world.", "points": 4, "proficiencies": [ "prof_fibers", "prof_knitting", "prof_carving" ], "skills": [ @@ -635,15 +635,14 @@ }, "male": [ "boxer_shorts" ], "female": [ "bra", "panties" ] - }, - "flags": [ "SCEN_ONLY" ] + } }, { "type": "profession", "id": "sheltered_militia", "name": "Sheltered Militia", "requirement": "achievement_survive_28_days", - "description": "At the start of the Cataclysm, you hunkered down in a bomb shelter with your collection of guns. You've spent the past months eating canned food and practicing your aim. Now it is winter - time to face the world above.", + "description": "Just as the first troubles started, you hunkered down in a shelter with your collection of guns. You've spent the past months eating canned food and practicing your aim. Now it is time to face the new world.", "points": 4, "proficiencies": [ "prof_gunsmithing_basic", "prof_gunsmithing_improv" ], "skills": [ { "level": 2, "name": "gun" }, { "level": 1, "name": "rifle" }, { "level": 1, "name": "pistol" } ], @@ -674,8 +673,7 @@ }, "male": [ "boxer_shorts" ], "female": [ "sports_bra", "boy_shorts" ] - }, - "flags": [ "SCEN_ONLY" ] + } }, { "type": "profession", @@ -1050,7 +1048,7 @@ { "type": "profession", "id": "marine", - "name": { "male": "Marine Infantryman", "female": "Marine Infantrywoman" }, + "name": "Marine Infantry", "requirement": "achievement_reach_military_bunker", "description": "You are one of the few and the proud: a member of the US Marine Corps. Now that military command has collapsed in on itself as far as you can tell, you suppose that it falls to you to carry the memory of the Corps forward into the future. Semper fi.", "points": 6, @@ -1101,8 +1099,7 @@ }, "male": [ "boxer_shorts" ], "female": [ "sports_bra", "boxer_shorts" ] - }, - "flags": [ "SCEN_ONLY" ] + } }, { "type": "profession", @@ -1145,15 +1142,14 @@ }, "male": [ "boxer_shorts" ], "female": [ "sports_bra", "boxer_shorts" ] - }, - "flags": [ "SCEN_ONLY" ] + } }, { "type": "profession", "id": "diver_navy", "name": "Navy Diver", "requirement": "achievement_reach_aircraft_carrier", - "description": "You were a member of a Naval Special Warfare diving group, a skilled soldier adept at underwater infiltration and marine combat. You were suiting up for a practice dive when the aircraft carrier you were stationed on was somehow flung from the Yellow Sea to who knows where. You seem to be the only one who survived with your sanity intact, but it's not safe to stay here. At least you're already dressed to abandon ship.", + "description": "You were a member of a Naval Special Warfare diving group, a skilled soldier adept at underwater infiltration and marine combat. You were suiting up for a practice dive when the aircraft carrier you were stationed on was somehow flung from the Yellow Sea to who knows where. You seem to be the only one who survived with your sanity intact.", "points": 3, "proficiencies": [ "prof_spotting", "prof_gunsmithing_basic" ], "skills": [ @@ -1186,8 +1182,7 @@ }, "male": [ "rashguard", "wetsuit_shorts" ], "female": [ "bikini_top", "wetsuit_shorts" ] - }, - "flags": [ "SCEN_ONLY" ] + } }, { "type": "profession", @@ -1531,8 +1526,7 @@ }, "male": [ "boxer_shorts" ], "female": [ "sports_bra", "boxer_shorts" ] - }, - "flags": [ "SCEN_ONLY" ] + } }, { "type": "profession", @@ -3262,7 +3256,7 @@ "description": "You were a serial killer, ready to walk the green mile, but in a twist of fate you're one of the few still alive. True death comes only from your hands, so you're in for a job.", "points": 2, "skills": [ { "level": 1, "name": "melee" } ], - "traits": [ "KILLER" ], + "traits": [ "PSYCHOPATH", "KILLER", "KILLER_GOOD" ], "items": { "both": [ "striped_shirt", "striped_pants", "sneakers", "socks", "glass_shiv" ], "male": [ "briefs" ], @@ -3301,8 +3295,7 @@ "both": [ "striped_shirt", "striped_pants", "sneakers", "socks", "rock_sock" ], "male": [ "briefs" ], "female": [ "bra", "panties" ] - }, - "flags": [ "SCEN_ONLY" ] + } }, { "type": "profession", @@ -3318,8 +3311,7 @@ }, "male": [ "briefs" ], "female": [ "bra", "panties" ] - }, - "flags": [ "SCEN_ONLY" ] + } }, { "type": "profession", @@ -3335,8 +3327,7 @@ }, "male": [ "briefs" ], "female": [ "bra", "panties" ] - }, - "flags": [ "SCEN_ONLY" ] + } }, { "type": "profession", @@ -3346,13 +3337,12 @@ "points": 4, "skills": [ { "level": 1, "name": "speech" }, { "level": 1, "name": "survival" } ], "traits": [ "ANIMALEMPATH" ], - "pets": [ { "name": "mon_black_rat", "amount": 13 } ], + "pets": [ { "name": "mon_lab_rat", "amount": 13 } ], "items": { "both": [ "striped_shirt", "striped_pants", "sneakers", "socks", "fried_seeds" ], "male": [ "briefs" ], "female": [ "bra", "panties" ] - }, - "flags": [ "SCEN_ONLY" ] + } }, { "type": "profession", @@ -3737,7 +3727,7 @@ "id": "winter_scavenger", "name": "Hardened Scavenger", "requirement": "achievement_survive_91_days", - "description": "One of the lucky few who escaped the Cataclysm, you made a life for yourself amidst the ruins of civilization. Whether through force, guile, or luck, you've obtained the best gear you could find.", + "description": "One of the lucky few who escaped the Cataclysm, you have quickly made a life for yourself amidst the ruins of civilization. Whether through force, guile, or luck, you've obtained the best gear you could find.", "points": 8, "proficiencies": [ "prof_fibers", "prof_fibers_rope", "prof_knitting", "prof_closures" ], "skills": [ @@ -3769,8 +3759,7 @@ }, "male": [ "boxer_shorts" ], "female": [ "sports_bra", "panties" ] - }, - "flags": [ "SCEN_ONLY" ] + } }, { "type": "profession", @@ -3816,8 +3805,7 @@ }, "male": [ "boxer_shorts" ], "female": [ "sports_bra", "panties" ] - }, - "flags": [ "SCEN_ONLY" ] + } }, { "type": "profession", @@ -4973,7 +4961,6 @@ "male": [ "boxer_shorts" ], "female": [ "sports_bra", "boy_shorts" ] }, - "flags": [ "SCEN_ONLY" ], "missions": [ "MISSION_HELICOPTER_PILOT" ] }, { diff --git a/data/json/proficiencies/misc.json b/data/json/proficiencies/misc.json index 2460cea2baf62..b5ee8cc14f4aa 100644 --- a/data/json/proficiencies/misc.json +++ b/data/json/proficiencies/misc.json @@ -136,6 +136,8 @@ "category": "prof_mechanic", "name": { "str": "Airframe and Powerplant Mechanic" }, "description": "You're capable of properly repairing aircraft without compromising its flying capabilities.", + "default_time_multiplier": 3, + "default_skill_penalty": 0.5, "can_learn": false }, { diff --git a/data/json/scenarios.json b/data/json/scenarios.json index e884057e7dc65..10668236f7a40 100644 --- a/data/json/scenarios.json +++ b/data/json/scenarios.json @@ -517,7 +517,16 @@ "flags": [ "LONE_START" ], "custom_initial_date": { "season": "winter" }, "add_professions": true, - "professions": [ "sheltered_survivor", "sheltered_militia", "winter_scavenger", "winter_army" ], + "professions": [ + "sheltered_survivor", + "sheltered_militia", + "winter_scavenger", + "winter_army", + "hardened_survivor", + "road_warrior", + "waste_ranger", + "player_bandit" + ], "requirement": "achievement_survive_91_days" }, { @@ -542,7 +551,16 @@ "flags": [ "LONE_START" ], "custom_initial_date": { "season": "summer", "year": 2 }, "add_professions": true, - "professions": [ "sheltered_survivor", "sheltered_militia", "winter_scavenger", "winter_army" ], + "professions": [ + "sheltered_survivor", + "sheltered_militia", + "winter_scavenger", + "winter_army", + "hardened_survivor", + "road_warrior", + "waste_ranger", + "player_bandit" + ], "requirement": "achievement_survive_91_days" }, { diff --git a/data/json/vehicle_groups.json b/data/json/vehicle_groups.json index dbbbf4a24d864..ee271cb3e1b76 100644 --- a/data/json/vehicle_groups.json +++ b/data/json/vehicle_groups.json @@ -3,6 +3,7 @@ "type": "vehicle_group", "id": "city_vehicles", "vehicles": [ + [ "car_roadwarrior", 2 ], [ "car", 2000 ], [ "car_diesel", 1000 ], [ "car_anmlcmpt", 250 ], @@ -381,10 +382,11 @@ "type": "vehicle_group", "id": "farm_vehicles", "vehicles": [ + [ "helicopter_gyro", 100 ], [ "tractor_plow", 1000 ], [ "tractor_seed", 1000 ], [ "tractor_reaper", 1000 ], - [ "oldtractor", 100 ], + [ "oldtractor", 250 ], [ "autotractor", 1000 ], [ "excavator", 500 ], [ "wheelbarrow", 100 ] @@ -428,7 +430,7 @@ "id": "bandit_vehicles", "type": "vehicle_group", "//": "Vehicles used by Hell's Raiders for scouting and assaults", - "vehicles": [ [ "pickup_technical", 150 ], [ "quad_bike", 150 ], [ "motorcycle", 300 ] ] + "vehicles": [ [ "pickup_technical", 150 ], [ "quad_bike", 150 ], [ "motorcycle", 300 ], [ "motorcycle_methcart", 50 ] ] }, { "type": "vehicle_group", diff --git a/src/activity_actor.cpp b/src/activity_actor.cpp index ea57965b59842..bd950919b647a 100644 --- a/src/activity_actor.cpp +++ b/src/activity_actor.cpp @@ -5010,7 +5010,7 @@ void meditate_activity_actor::start( player_activity &act, Character & ) void meditate_activity_actor::finish( player_activity &act, Character &who ) { who.add_msg_if_player( m_good, _( "You pause to engage in spiritual contemplation." ) ); - who.add_morale( MORALE_FEELING_GOOD, 5, 10 ); + who.add_morale( MORALE_SPIRITUAL, 5, 10 ); act.set_to_null(); } diff --git a/src/bionics.cpp b/src/bionics.cpp index 186e4abda6084..72def6f923dc7 100644 --- a/src/bionics.cpp +++ b/src/bionics.cpp @@ -193,7 +193,7 @@ static const trait_id trait_MASOCHIST_MED( "MASOCHIST_MED" ); static const trait_id trait_NONE( "NONE" ); static const trait_id trait_PROF_AUTODOC( "PROF_AUTODOC" ); static const trait_id trait_PROF_MED( "PROF_MED" ); -static const trait_id trait_PYROMANIA( "PYROMANIA" ); +static const trait_id trait_PYROMANIA_GOOD( "PYROMANIA_GOOD" ); static const trait_id trait_THRESH_MEDICAL( "THRESH_MEDICAL" ); struct Character::bionic_fuels { @@ -941,9 +941,9 @@ bool Character::activate_bionic( bionic &bio, bool eff_only, bool *close_bionics if( pnt && here.is_flammable( *pnt ) ) { add_msg_activate(); here.add_field( *pnt, fd_fire, 1 ); - if( has_trait( trait_PYROMANIA ) ) { + rem_morale( MORALE_PYROMANIA_NOFIRE ); + if( has_trait( trait_PYROMANIA_GOOD ) ) { add_morale( MORALE_PYROMANIA_STARTFIRE, 5, 10, 3_hours, 2_hours ); - rem_morale( MORALE_PYROMANIA_NOFIRE ); add_msg_if_player( m_good, _( "You happily light a fire." ) ); } mod_moves( -100 ); diff --git a/src/character.h b/src/character.h index 1597dd44149d4..4af81ebe9969d 100644 --- a/src/character.h +++ b/src/character.h @@ -3068,6 +3068,8 @@ class Character : public Creature, public visitable void naked_morale_penalty(); // the morale penalty for nyctophobic character void in_dark_morale_penalty(); + // morale bonus from wearing holy symbol for spiritual characters + void spiritual_morale_bonus(); /** Used to apply morale modifications from food and medication **/ void modify_morale( item &food, int nutr = 0 ); // Modified by traits, &c diff --git a/src/character_body.cpp b/src/character_body.cpp index 18fd6a07c0f5a..7eec9e497219f 100644 --- a/src/character_body.cpp +++ b/src/character_body.cpp @@ -75,7 +75,7 @@ static const trait_id trait_FUR( "FUR" ); static const trait_id trait_LIGHTFUR( "LIGHTFUR" ); static const trait_id trait_LUPINE_FUR( "LUPINE_FUR" ); static const trait_id trait_M_DEPENDENT( "M_DEPENDENT" ); -static const trait_id trait_PYROMANIA( "PYROMANIA" ); +static const trait_id trait_PYROMANIA_GOOD( "PYROMANIA_GOOD" ); static const trait_id trait_SLIMY( "SLIMY" ); static const trait_id trait_URSINE_FUR( "URSINE_FUR" ); @@ -558,7 +558,7 @@ void Character::update_bodytemp() blister_count += h_radiation - 111 > 0 ? std::max( static_cast( std::sqrt( h_radiation - 111 ) ), 0 ) : 0; - const bool pyromania = has_trait( trait_PYROMANIA ); + const bool pyromania = has_trait( trait_PYROMANIA_GOOD ); // BLISTERS : Skin gets blisters from intense heat exposure. // Fire protection protects from blisters. // Heatsinks give near-immunity. @@ -570,15 +570,17 @@ void Character::update_bodytemp() } if( blister_count - fire_armor_per_bp[bp] > 0 ) { add_effect( effect_blisters, 1_turns, bp ); + rem_morale( MORALE_PYROMANIA_NOFIRE ); if( pyromania ) { add_morale( MORALE_PYROMANIA_NEARFIRE, 10, 10, 1_hours, 30_minutes ); // Proximity that's close enough to harm us gives us a bit of a thrill - rem_morale( MORALE_PYROMANIA_NOFIRE ); } - } else if( pyromania && best_fire >= 1 ) { // Only give us fire bonus if there's actually fire - add_morale( MORALE_PYROMANIA_NEARFIRE, 5, 5, 30_minutes, - 15_minutes ); // Gain a much smaller mood boost even if it doesn't hurt us + } else if( best_fire >= 1 ) { // Only give us fire bonus if there's actually fire rem_morale( MORALE_PYROMANIA_NOFIRE ); + if( pyromania ) { + add_morale( MORALE_PYROMANIA_NEARFIRE, 5, 5, 30_minutes, + 15_minutes ); // Gain a much smaller mood boost even if it doesn't hurt us + } } mod_part_temp_conv( bp, sunlight_warmth ); diff --git a/src/character_morale.cpp b/src/character_morale.cpp index 6c7599150d031..577e8b9b711f9 100644 --- a/src/character_morale.cpp +++ b/src/character_morale.cpp @@ -19,6 +19,7 @@ static const trait_id trait_NOMAD( "NOMAD" ); static const trait_id trait_NOMAD2( "NOMAD2" ); static const trait_id trait_NOMAD3( "NOMAD3" ); static const trait_id trait_PROF_FOODP( "PROF_FOODP" ); +static const trait_id trait_SPIRITUAL( "SPIRITUAL" ); static const json_character_flag json_flag_NYCTOPHOBIA( "NYCTOPHOBIA" ); static const json_character_flag json_flag_TOUGH_FEET( "TOUGH_FEET" ); @@ -86,6 +87,10 @@ void Character::apply_persistent_morale() if( has_flag( json_flag_NYCTOPHOBIA ) ) { in_dark_morale_penalty(); } + + if( has_trait( trait_SPIRITUAL ) ) { + spiritual_morale_bonus(); + } } } @@ -203,6 +208,15 @@ void Character::in_dark_morale_penalty() } } +void Character::spiritual_morale_bonus() +{ + if( worn_with_flag( flag_HOLY_SYMBOL ) ) { + add_morale( MORALE_SPIRITUAL, 10, 10, 1_minutes, 1_minutes, true ); + } else { + rem_morale( MORALE_SPIRITUAL ); + } +} + int Character::get_morale_level() const { return morale->get_level(); diff --git a/src/consumption.cpp b/src/consumption.cpp index b727f2adfe449..21ffe3a0388a9 100644 --- a/src/consumption.cpp +++ b/src/consumption.cpp @@ -1221,19 +1221,13 @@ void Character::modify_morale( item &food, const int nutr ) food.get_comestible()->comesttype != comesttype_DRINK ) { map &here = get_map(); if( here.has_nearby_chair( pos(), 1 ) && here.has_nearby_table( pos_bub(), 1 ) ) { - if( has_trait( trait_TABLEMANNERS ) ) { - rem_morale( MORALE_ATE_WITHOUT_TABLE ); - if( !food.rotten() ) { - add_morale( MORALE_ATE_WITH_TABLE, 3, 3, 3_hours, 2_hours, true ); - } - } else if( !food.rotten() ) { - add_morale( MORALE_ATE_WITH_TABLE, 1, 1, 3_hours, 2_hours, true ); - } - } else { - if( has_trait( trait_TABLEMANNERS ) ) { - rem_morale( MORALE_ATE_WITH_TABLE ); - add_morale( MORALE_ATE_WITHOUT_TABLE, -2, -4, 3_hours, 2_hours, true ); + if( !food.rotten() ) { + add_morale( MORALE_ATE_WITH_TABLE, 3, 3, 3_hours, 2_hours, true ); + add_msg_if_player( m_good, _( "You use nearby furniture to sit and eat at." ) ); } + } else if( has_trait( trait_TABLEMANNERS ) ) { + add_morale( MORALE_ATE_WITHOUT_TABLE, -2, -4, 3_hours, 2_hours, true ); + add_msg_if_player( m_bad, _( "Having to eat without proper furniture annoys you." ) ); } } diff --git a/src/creature.cpp b/src/creature.cpp index 4429ca617ffc9..104bc17c7ccbe 100644 --- a/src/creature.cpp +++ b/src/creature.cpp @@ -110,7 +110,7 @@ static const material_id material_wool( "wool" ); static const species_id species_ROBOT( "ROBOT" ); static const trait_id trait_GLASSJAW( "GLASSJAW" ); -static const trait_id trait_PYROMANIA( "PYROMANIA" ); +static const trait_id trait_PYROMANIA_GOOD( "PYROMANIA_GOOD" ); const std::map Creature::size_map = { {"TINY", creature_size::tiny}, @@ -823,6 +823,7 @@ void projectile::apply_effects_damage( Creature &target, Creature *source, } Character &player_character = get_player_character(); + bool set_on_fire = false; if( proj_effects.count( "INCENDIARY" ) ) { if( target.made_of( material_veggy ) || target.made_of_any( Creature::cmat_flammable ) ) { target.add_effect( effect_source( source ), effect_onfire, rng( 2_turns, 6_turns ), @@ -831,27 +832,27 @@ void projectile::apply_effects_damage( Creature &target, Creature *source, target.add_effect( effect_source( source ), effect_onfire, rng( 1_turns, 4_turns ), dealt_dam.bp_hit ); } - if( player_character.has_trait( trait_PYROMANIA ) && - !player_character.has_morale( MORALE_PYROMANIA_STARTFIRE ) && - player_character.sees( target ) ) { - player_character.add_msg_if_player( m_good, - _( "You feel a surge of euphoria as flame engulfs %s!" ), target.get_name() ); - player_character.add_morale( MORALE_PYROMANIA_STARTFIRE, 15, 15, 8_hours, 6_hours ); - player_character.rem_morale( MORALE_PYROMANIA_NOFIRE ); - } + set_on_fire = true; } else if( proj_effects.count( "IGNITE" ) ) { if( target.made_of( material_veggy ) || target.made_of_any( Creature::cmat_flammable ) ) { target.add_effect( effect_source( source ), effect_onfire, 6_turns, dealt_dam.bp_hit ); } else if( target.made_of_any( Creature::cmat_flesh ) ) { target.add_effect( effect_source( source ), effect_onfire, 10_turns, dealt_dam.bp_hit ); } - if( player_character.has_trait( trait_PYROMANIA ) && - !player_character.has_morale( MORALE_PYROMANIA_STARTFIRE ) && - player_character.sees( target ) ) { - player_character.add_msg_if_player( m_good, - _( "You feel a surge of euphoria as flame engulfs %s!" ), target.get_name() ); - player_character.add_morale( MORALE_PYROMANIA_STARTFIRE, 15, 15, 8_hours, 6_hours ); + set_on_fire = true; + } + + if( set_on_fire ) { + if( player_character.sees( target ) ) { player_character.rem_morale( MORALE_PYROMANIA_NOFIRE ); + if( player_character.has_trait( trait_PYROMANIA_GOOD ) ) { + if( !player_character.has_morale( MORALE_PYROMANIA_STARTFIRE ) ) { + // Check whether morale is already present to avoid spam if lighting a lot of monsters of fire. Bonus itself always applies, however. + player_character.add_msg_if_player( m_good, + _( "You feel a surge of euphoria as flame engulfs %s!" ), target.get_name() ); + } + } + player_character.add_morale( MORALE_PYROMANIA_STARTFIRE, 15, 15, 8_hours, 6_hours ); } } @@ -1227,12 +1228,16 @@ void Creature::deal_damage_handle_type( const effect_source &source, const damag add_effect( source, effect_onfire, rng( 1_turns, 3_turns ), bp ); Character &player_character = get_player_character(); - if( player_character.has_trait( trait_PYROMANIA ) && - !player_character.has_morale( MORALE_PYROMANIA_STARTFIRE ) && player_character.sees( *this ) ) { - player_character.add_msg_if_player( m_good, - _( "You feel a surge of euphoria as flame engulfs %s!" ), this->get_name() ); - player_character.add_morale( MORALE_PYROMANIA_STARTFIRE, 15, 15, 8_hours, 6_hours ); + if( player_character.sees( *this ) ) { player_character.rem_morale( MORALE_PYROMANIA_NOFIRE ); + if( player_character.has_trait( trait_PYROMANIA_GOOD ) ) { + if( !player_character.has_morale( MORALE_PYROMANIA_STARTFIRE ) ) { + // Check whether morale is already present to avoid spam if lighting a lot of monsters of fire. Bonus itself always applies, however. + player_character.add_msg_if_player( m_good, + _( "You feel a surge of euphoria as flame engulfs %s!" ), this->get_name() ); + } + player_character.add_morale( MORALE_PYROMANIA_STARTFIRE, 15, 15, 8_hours, 6_hours ); + } } } } else if( du.type == damage_electric ) { diff --git a/src/flag.cpp b/src/flag.cpp index 72ad5b2904643..2d1bdb9e5b67d 100644 --- a/src/flag.cpp +++ b/src/flag.cpp @@ -148,6 +148,7 @@ const flag_id flag_HARD( "HARD" ); const flag_id flag_HEAT_IMMUNE( "HEAT_IMMUNE" ); const flag_id flag_HIDDEN_HALLU( "HIDDEN_HALLU" ); const flag_id flag_HIDDEN_POISON( "HIDDEN_POISON" ); +const flag_id flag_HOLY_SYMBOL( "HOLY_SYMBOL" ); const flag_id flag_HOOD( "HOOD" ); const flag_id flag_HOT( "HOT" ); const flag_id flag_HURT_WHEN_WIELDED( "HURT_WHEN_WIELDED" ); diff --git a/src/flag.h b/src/flag.h index c1ab2ac665b25..f08d04f596c5a 100644 --- a/src/flag.h +++ b/src/flag.h @@ -157,6 +157,7 @@ extern const flag_id flag_HEAT_IMMUNE; extern const flag_id flag_HIDDEN_HALLU; extern const flag_id json_flag_HIDDEN_ITEM; extern const flag_id flag_HIDDEN_POISON; +extern const flag_id flag_HOLY_SYMBOL; extern const flag_id flag_HOOD; extern const flag_id flag_HOT; extern const flag_id flag_HURT_WHEN_WIELDED; diff --git a/src/iexamine.cpp b/src/iexamine.cpp index a5aeaf7d32235..6a994f3342a2a 100644 --- a/src/iexamine.cpp +++ b/src/iexamine.cpp @@ -239,7 +239,7 @@ static const trait_id trait_M_DEPENDENT( "M_DEPENDENT" ); static const trait_id trait_M_FERTILE( "M_FERTILE" ); static const trait_id trait_M_SPORES( "M_SPORES" ); static const trait_id trait_PROBOSCIS( "PROBOSCIS" ); -static const trait_id trait_PYROMANIA( "PYROMANIA" ); +static const trait_id trait_PYROMANIA_GOOD( "PYROMANIA_GOOD" ); static const trait_id trait_SHELL2( "SHELL2" ); static const trait_id trait_SHELL3( "SHELL3" ); static const trait_id trait_THRESH_MARLOSS( "THRESH_MARLOSS" ); @@ -2867,9 +2867,9 @@ void iexamine::kiln_empty( Character &you, const tripoint &examp ) result.charges = char_charges; here.add_item( examp, result ); - if( you.has_trait( trait_PYROMANIA ) ) { + you.rem_morale( MORALE_PYROMANIA_NOFIRE ); + if( you.has_trait( trait_PYROMANIA_GOOD ) ) { you.add_morale( MORALE_PYROMANIA_STARTFIRE, 5, 10, 3_hours, 2_hours ); - you.rem_morale( MORALE_PYROMANIA_NOFIRE ); you.add_msg_if_player( m_good, _( "You happily light a fire in the charcoal kiln." ) ); } else { add_msg( _( "You fire the charcoal kiln." ) ); @@ -5664,9 +5664,9 @@ static void smoker_activate( Character &you, const tripoint &examp ) result.activate(); here.add_item( examp, result ); - if( you.has_trait( trait_PYROMANIA ) ) { + you.rem_morale( MORALE_PYROMANIA_NOFIRE ); + if( you.has_trait( trait_PYROMANIA_GOOD ) ) { you.add_morale( MORALE_PYROMANIA_STARTFIRE, 5, 10, 3_hours, 2_hours ); - you.rem_morale( MORALE_PYROMANIA_NOFIRE ); you.add_msg_if_player( m_good, _( "You happily light a small fire under the rack and it starts to smoke." ) ); } else { diff --git a/src/item.cpp b/src/item.cpp index 03514ba8702ff..842aeafc23484 100644 --- a/src/item.cpp +++ b/src/item.cpp @@ -3569,7 +3569,7 @@ void item::armor_protection_info( std::vector &info, const iteminfo_qu for( const damage_info_order &dio : damage_info_order::get_all( damage_info_order::info_type::PROT ) ) { if( ( best_res.resist_vals.count( dio.dmg_type ) <= 0 || - best_res.type_resist( dio.dmg_type ) < 1.0f ) && !always_detailed ) { + best_res.type_resist( dio.dmg_type ) < 1.0f ) && !always_detailed ) { continue; } bool skipped_detailed = false; diff --git a/src/iuse.cpp b/src/iuse.cpp index bd5c1352c6f31..bde85d106795f 100644 --- a/src/iuse.cpp +++ b/src/iuse.cpp @@ -385,7 +385,7 @@ static const trait_id trait_MARLOSS_YELLOW( "MARLOSS_YELLOW" ); static const trait_id trait_M_DEPENDENT( "M_DEPENDENT" ); static const trait_id trait_NOPAIN( "NOPAIN" ); static const trait_id trait_PSYCHOPATH( "PSYCHOPATH" ); -static const trait_id trait_PYROMANIA( "PYROMANIA" ); +static const trait_id trait_PYROMANIA_GOOD( "PYROMANIA_GOOD" ); static const trait_id trait_SPIRITUAL( "SPIRITUAL" ); static const trait_id trait_THRESH_MARLOSS( "THRESH_MARLOSS" ); static const trait_id trait_THRESH_MYCUS( "THRESH_MYCUS" ); @@ -3854,9 +3854,9 @@ std::optional iuse::grenade_inc_act( Character *p, item *it, bool t, const here.add_field( dest, fd_incendiary, 3 ); } - if( p->has_trait( trait_PYROMANIA ) ) { + p->rem_morale( MORALE_PYROMANIA_NOFIRE ); + if( p->has_trait( trait_PYROMANIA_GOOD ) ) { p->add_morale( MORALE_PYROMANIA_STARTFIRE, 15, 15, 8_hours, 6_hours ); - p->rem_morale( MORALE_PYROMANIA_NOFIRE ); p->add_msg_if_player( m_good, _( "Fire… Good…" ) ); } } @@ -3876,9 +3876,9 @@ std::optional iuse::molotov_lit( Character *p, item *it, bool t, const trip const int intensity = 1 + one_in( 3 ) + one_in( 5 ); here.add_field( pt, fd_fire, intensity ); } - if( p->has_trait( trait_PYROMANIA ) ) { + p->rem_morale( MORALE_PYROMANIA_NOFIRE ); + if( p->has_trait( trait_PYROMANIA_GOOD ) ) { p->add_morale( MORALE_PYROMANIA_STARTFIRE, 15, 15, 8_hours, 6_hours ); - p->rem_morale( MORALE_PYROMANIA_NOFIRE ); p->add_msg_if_player( m_good, _( "Fire… Good…" ) ); } return 1; diff --git a/src/iuse_actor.cpp b/src/iuse_actor.cpp index b7e7657113d12..96dbdb63c4814 100644 --- a/src/iuse_actor.cpp +++ b/src/iuse_actor.cpp @@ -150,7 +150,7 @@ static const trait_id trait_DEBUG_BIONICS( "DEBUG_BIONICS" ); static const trait_id trait_ILLITERATE( "ILLITERATE" ); static const trait_id trait_LIGHTWEIGHT( "LIGHTWEIGHT" ); static const trait_id trait_NOPAIN( "NOPAIN" ); -static const trait_id trait_PYROMANIA( "PYROMANIA" ); +static const trait_id trait_PYROMANIA_GOOD( "PYROMANIA_GOOD" ); static const trait_id trait_TOLERANCE( "TOLERANCE" ); static const trap_str_id tr_firewood_source( "tr_firewood_source" ); @@ -289,14 +289,11 @@ std::optional iuse_transform::use( Character &p, item &it, bool t, const tr p.moves -= moves; } - if( possess && need_fire && p.has_trait( trait_PYROMANIA ) ) { - if( one_in( 2 ) ) { - p.add_msg_if_player( m_mixed, - _( "You light a fire, but it isn't enough. You need to light more." ) ); - } else { + if( possess && need_fire ) { + p.rem_morale( MORALE_PYROMANIA_NOFIRE ); + if( p.has_trait( trait_PYROMANIA_GOOD ) ) { p.add_msg_if_player( m_good, _( "You happily light a fire." ) ); p.add_morale( MORALE_PYROMANIA_STARTFIRE, 5, 10, 3_hours, 2_hours ); - p.rem_morale( MORALE_PYROMANIA_NOFIRE ); } } @@ -1272,17 +1269,12 @@ bool firestarter_actor::prep_firestarter_use( const Character &p, tripoint_bub_m void firestarter_actor::resolve_firestarter_use( Character &p, const tripoint_bub_ms &pos ) { if( get_map().add_field( pos, fd_fire, 1, 10_minutes ) ) { - if( !p.has_trait( trait_PYROMANIA ) ) { - p.add_msg_if_player( _( "You successfully light a fire." ) ); + p.rem_morale( MORALE_PYROMANIA_NOFIRE ); + if( p.has_trait( trait_PYROMANIA_GOOD ) ) { + p.add_msg_if_player( m_good, _( "You happily light a fire." ) ); + p.add_morale( MORALE_PYROMANIA_STARTFIRE, 5, 10, 6_hours, 4_hours ); } else { - if( one_in( 4 ) ) { - p.add_msg_if_player( m_mixed, - _( "You light a fire, but it isn't enough. You need to light more." ) ); - } else { - p.add_msg_if_player( m_good, _( "You happily light a fire." ) ); - p.add_morale( MORALE_PYROMANIA_STARTFIRE, 5, 10, 6_hours, 4_hours ); - p.rem_morale( MORALE_PYROMANIA_NOFIRE ); - } + p.add_msg_if_player( _( "You successfully light a fire." ) ); } } } diff --git a/src/magic_spell_effect.cpp b/src/magic_spell_effect.cpp index 0a1a2b07633bc..0a442bee284bc 100644 --- a/src/magic_spell_effect.cpp +++ b/src/magic_spell_effect.cpp @@ -88,7 +88,7 @@ static const species_id species_SLIME( "SLIME" ); static const trait_id trait_KILLER( "KILLER" ); static const trait_id trait_PACIFIST( "PACIFIST" ); static const trait_id trait_PSYCHOPATH( "PSYCHOPATH" ); -static const trait_id trait_PYROMANIA( "PYROMANIA" ); +static const trait_id trait_PYROMANIA_GOOD( "PYROMANIA_GOOD" ); namespace spell_detail { @@ -518,12 +518,13 @@ static void damage_targets( const spell &sp, Creature &caster, here.add_field( target, fd_fire, 1, 10_minutes ); Character &player_character = get_player_character(); - if( player_character.has_trait( trait_PYROMANIA ) && - !player_character.has_morale( MORALE_PYROMANIA_STARTFIRE ) ) { - player_character.add_msg_if_player( m_good, - _( "You feel a surge of euphoria as flames burst out!" ) ); + player_character.rem_morale( MORALE_PYROMANIA_NOFIRE ); + if( player_character.has_trait( trait_PYROMANIA_GOOD ) ) { + if( !player_character.has_morale( MORALE_PYROMANIA_STARTFIRE ) ) { + player_character.add_msg_if_player( m_good, + _( "You feel a surge of euphoria as flames burst out!" ) ); + } player_character.add_morale( MORALE_PYROMANIA_STARTFIRE, 15, 15, 8_hours, 6_hours ); - player_character.rem_morale( MORALE_PYROMANIA_NOFIRE ); } } Creature *const cr = creatures.creature_at( target ); @@ -1458,7 +1459,7 @@ void spell_effect::guilt( const spell &sp, Creature &caster, const tripoint &tar guilt_thresholds[25] = _( "You feel remorse for killing %s." ); Character &guy = *guilt_target; - if( guy.has_trait( trait_PSYCHOPATH ) || guy.has_trait( trait_KILLER ) || + if( guy.has_trait( trait_PSYCHOPATH ) || guy.has_flag( json_flag_PRED3 ) || guy.has_flag( json_flag_PRED4 ) ) { // specially immune. return; diff --git a/src/map.cpp b/src/map.cpp index 49d29aab0c829..cf3fc9eadb66b 100644 --- a/src/map.cpp +++ b/src/map.cpp @@ -141,6 +141,7 @@ static const oter_str_id oter_open_air( "open_air" ); static const oter_str_id oter_solid_earth( "solid_earth" ); static const species_id species_HUMAN( "HUMAN" ); +static const species_id species_ZOMBIE( "ZOMBIE" ); static const ter_str_id ter_t_dirt( "t_dirt" ); static const ter_str_id ter_t_soil( "t_soil" ); @@ -4235,7 +4236,7 @@ void map::shoot( const tripoint &p, projectile &proj, const bool hit_items ) float dam = initial_damage; const auto &ammo_effects = proj.proj_effects; - const bool incendiary = ammo_effects.count( "INCENDIARY" ); + const bool incendiary = ammo_effects.count( "INCENDIARY" ) || ammo_effects.count( "IGNITE" ); const bool laser = ammo_effects.count( "LASER" ); if( const optional_vpart_position vp = veh_at( p ) ) { @@ -8389,7 +8390,8 @@ void map::spawn_monsters_submap( const tripoint &gp, bool ignore_sight, bool spa for( int j = 0; j < i.count; j++ ) { monster tmp( i.type ); - if( tmp.type->in_species( species_HUMAN ) ) { + if( tmp.type->in_species( species_HUMAN ) && !tmp.type->in_species( species_ZOMBIE ) ) { + // Include non-undead humans for this check (i.e. ferals would be included). Cold and flu wouldn't survive on zombies. if( one_in( 100 ) ) { // Same chances and duration of flu vs. cold as for the player. if( one_in( 6 ) ) { diff --git a/src/monster.cpp b/src/monster.cpp index 43cde1bea8100..66a37d5954be1 100644 --- a/src/monster.cpp +++ b/src/monster.cpp @@ -165,7 +165,7 @@ static const trait_id trait_ANIMALEMPATH2( "ANIMALEMPATH2" ); static const trait_id trait_BEE( "BEE" ); static const trait_id trait_FLOWERS( "FLOWERS" ); static const trait_id trait_INATTENTIVE( "INATTENTIVE" ); -static const trait_id trait_KILLER( "KILLER" ); +static const trait_id trait_KILLER_GOOD( "KILLER_GOOD" ); static const trait_id trait_MYCUS_FRIEND( "MYCUS_FRIEND" ); static const trait_id trait_PHEROMONE_AMPHIBIAN( "PHEROMONE_AMPHIBIAN" ); static const trait_id trait_PHEROMONE_INSECT( "PHEROMONE_INSECT" ); @@ -2534,13 +2534,14 @@ void monster::die( Creature *nkiller ) Character *ch = get_killer()->as_character(); if( !is_hallucination() && ch != nullptr ) { get_event_bus().send( ch->getID(), type->id ); - if( ch->is_avatar() && ch->has_trait( trait_KILLER ) ) { + ch->rem_morale( MORALE_KILLER_NEED_TO_KILL ); + // TODO: Check if monster would cause guilt on killing; in this case, unless player character doesn't care about guilt, they don't get a bonus. + if( ch->is_avatar() && ch->has_trait( trait_KILLER_GOOD ) ) { if( one_in( 4 ) ) { const translation snip = SNIPPET.random_from_category( "killer_on_kill" ).value_or( translation() ); ch->add_msg_if_player( m_good, "%s", snip ); } ch->add_morale( MORALE_KILLER_HAS_KILLED, 5, 10, 6_hours, 4_hours ); - ch->rem_morale( MORALE_KILLER_NEED_TO_KILL ); } } } @@ -2934,7 +2935,8 @@ void monster::process_one_effect( effect &it, bool is_new ) } else if( id == effect_fake_common_cold ) { const tripoint &mon_pos = pos(); if( calendar::once_every( time_duration::from_seconds( rng( 30, 300 ) ) ) ) { - sounds::sound( mon_pos, 4, sounds::sound_t::speech, _( "a hacking cough." ), false, "misc", "cough" ); + sounds::sound( mon_pos, 4, sounds::sound_t::speech, _( "a hacking cough." ), false, "misc", + "cough" ); } avatar &you = get_avatar(); // No NPCs for now. @@ -2945,7 +2947,8 @@ void monster::process_one_effect( effect &it, bool is_new ) // Need to define the two separately because it's theoretically (and realistically) possible to have both flu and cold at once, both for players and mosters. const tripoint &mon_pos = pos(); if( calendar::once_every( time_duration::from_seconds( rng( 30, 300 ) ) ) ) { - sounds::sound( mon_pos, 4, sounds::sound_t::speech, _( "a hacking cough." ), false, "misc", "cough" ); + sounds::sound( mon_pos, 4, sounds::sound_t::speech, _( "a hacking cough." ), false, "misc", + "cough" ); } avatar &you = get_avatar(); // No NPCs for now. diff --git a/src/morale_types.cpp b/src/morale_types.cpp index fc025cb907bce..37a25fe639ee8 100644 --- a/src/morale_types.cpp +++ b/src/morale_types.cpp @@ -89,6 +89,7 @@ const morale_type MORALE_PYROMANIA_NOFIRE( "morale_pyromania_nofire" ); const morale_type MORALE_PYROMANIA_STARTFIRE( "morale_pyromania_startfire" ); const morale_type MORALE_SCREAM( "morale_scream" ); const morale_type MORALE_SHAVE( "morale_shave" ); +const morale_type MORALE_SPIRITUAL( "morale_spiritual" ); const morale_type MORALE_SUPPORT( "morale_support" ); const morale_type MORALE_SWEETTOOTH( "morale_sweettooth" ); const morale_type MORALE_TREE_COMMUNION( "morale_tree_communion" ); @@ -165,6 +166,7 @@ static const morale_type morale_pyromania_nofire( "morale_pyromania_nofire" ); static const morale_type morale_pyromania_startfire( "morale_pyromania_startfire" ); static const morale_type morale_scream( "morale_scream" ); static const morale_type morale_shave( "morale_shave" ); +static const morale_type morale_spiritual( "morale_spiritual" ); static const morale_type morale_support( "morale_support" ); static const morale_type morale_sweettooth( "morale_sweettooth" ); static const morale_type morale_vegetarian( "morale_vegetarian" ); diff --git a/src/morale_types.h b/src/morale_types.h index 61acccfd3c280..93789844f7bb9 100644 --- a/src/morale_types.h +++ b/src/morale_types.h @@ -107,6 +107,7 @@ extern const morale_type MORALE_PERM_RADIOPHILE; extern const morale_type MORALE_GAME_FOUND_KITTEN; extern const morale_type MORALE_HAIRCUT; extern const morale_type MORALE_SHAVE; +extern const morale_type MORALE_SPIRITUAL; extern const morale_type MORALE_CHAT; extern const morale_type MORALE_VOMITED; extern const morale_type MORALE_PLAY_WITH_PET; diff --git a/src/npc.cpp b/src/npc.cpp index c3d24a6efbf30..050f7ce8e135f 100644 --- a/src/npc.cpp +++ b/src/npc.cpp @@ -149,6 +149,7 @@ static const trait_id trait_CANNIBAL( "CANNIBAL" ); static const trait_id trait_DEBUG_MIND_CONTROL( "DEBUG_MIND_CONTROL" ); static const trait_id trait_HALLUCINATION( "HALLUCINATION" ); static const trait_id trait_ILLITERATE( "ILLITERATE" ); +static const trait_id trait_KILLER_GOOD( "KILLER_GOOD" ); static const trait_id trait_MUTE( "MUTE" ); static const trait_id trait_NO_BASH( "NO_BASH" ); static const trait_id trait_PROF_DICEMASTER( "PROF_DICEMASTER" ); @@ -3008,18 +3009,28 @@ void npc::die( Creature *nkiller ) } Character &player_character = get_player_character(); - if( killer == &player_character && ( !guaranteed_hostile() || hit_by_player ) ) { - bool cannibal = player_character.has_trait( trait_CANNIBAL ); - bool psycho = player_character.has_trait( trait_PSYCHOPATH ); - if( player_character.has_trait( trait_SAPIOVORE ) || psycho ) { - // No morale effect - } else if( cannibal ) { - player_character.add_morale( MORALE_KILLED_INNOCENT, -5, 0, 2_days, 3_hours ); - } else { - player_character.add_morale( MORALE_KILLED_INNOCENT, -100, 0, 2_days, 3_hours ); + // Remove no-kill morale + bool player_killed_innocent = false; + const bool psycho = player_character.has_trait( trait_PSYCHOPATH ); + if( killer == &player_character ) { + player_character.rem_morale( MORALE_KILLER_NEED_TO_KILL ); + if( ( !guaranteed_hostile() || hit_by_player ) ) { + player_killed_innocent = true; + const bool cannibal = player_character.has_trait( trait_CANNIBAL ); + if( player_character.has_trait( trait_SAPIOVORE ) || psycho ) { + // No morale effect + } else if( cannibal ) { + player_character.add_morale( MORALE_KILLED_INNOCENT, -5, 0, 2_days, 3_hours ); + } else { + player_character.add_morale( MORALE_KILLED_INNOCENT, -100, 0, 2_days, 3_hours ); + } } } + if( player_character.has_trait( trait_KILLER_GOOD ) && ( !player_killed_innocent || psycho ) ) { + player_character.add_morale( MORALE_KILLER_HAS_KILLED, 5, 10, 6_hours, 4_hours ); + } + place_corpse(); } diff --git a/src/projectile.cpp b/src/projectile.cpp index 28c715d14576b..77f3c78ec172e 100644 --- a/src/projectile.cpp +++ b/src/projectile.cpp @@ -28,6 +28,7 @@ static const ter_str_id ter_t_foamcrete_floor( "t_foamcrete_floor" ); static const ter_str_id ter_t_foamcrete_wall( "t_foamcrete_wall" ); static const trait_id trait_PYROMANIA( "PYROMANIA" ); +static const trait_id trait_PYROMANIA_GOOD( "PYROMANIA_GOOD" ); projectile::projectile() : critical_multiplier( 2.0 ), drop( nullptr ), custom_explosion( nullptr ) @@ -156,15 +157,19 @@ void apply_ammo_effects( const Creature *source, const tripoint &p, if( check_sees && check_passable ) { here.add_field( pt, ae.aoe_field_type, rng( ae.aoe_intensity_min, ae.aoe_intensity_max ) ); - if( player_character.has_trait( trait_PYROMANIA ) && - !player_character.has_morale( MORALE_PYROMANIA_STARTFIRE ) ) { + if( player_character.has_trait( trait_PYROMANIA_GOOD ) || + player_character.has_trait( trait_PYROMANIA ) ) { for( const auto &fd : here.field_at( pt ) ) { if( fd.first->has_fire ) { - player_character.add_msg_if_player( m_good, - _( "You feel a surge of euphoria as flames burst out!" ) ); - player_character.add_morale( MORALE_PYROMANIA_STARTFIRE, 15, 15, 8_hours, 6_hours ); player_character.rem_morale( MORALE_PYROMANIA_NOFIRE ); - break; + if( player_character.has_trait( trait_PYROMANIA_GOOD ) ) { + if( !player_character.has_morale( MORALE_PYROMANIA_STARTFIRE ) ) { + player_character.add_msg_if_player( m_good, + _( "You feel a surge of euphoria as flames burst out!" ) ); + } + player_character.add_morale( MORALE_PYROMANIA_STARTFIRE, 15, 15, 8_hours, 6_hours ); + break; + } } } } diff --git a/src/ranged.cpp b/src/ranged.cpp index c8bbdc48f892e..910a12af2959c 100644 --- a/src/ranged.cpp +++ b/src/ranged.cpp @@ -137,7 +137,7 @@ static const skill_id skill_swimming( "swimming" ); static const skill_id skill_throw( "throw" ); static const trait_id trait_BRAWLER( "BRAWLER" ); -static const trait_id trait_PYROMANIA( "PYROMANIA" ); +static const trait_id trait_PYROMANIA_GOOD( "PYROMANIA_GOOD" ); static const trap_str_id tr_practice_target( "tr_practice_target" ); @@ -914,20 +914,18 @@ int Character::fire_gun( const tripoint &target, int shots, item &gun ) ( qty * ( 1.0 - absorb ) ); const itype_id current_ammo = gun.ammo_current(); - - if( has_trait( trait_PYROMANIA ) && !has_morale( MORALE_PYROMANIA_STARTFIRE ) ) { - const std::set &at = gun.ammo_types(); - if( at.count( ammo_flammable ) ) { - add_msg_if_player( m_good, _( "You feel a surge of euphoria as flames roar out of the %s!" ), - gun.tname() ); - add_morale( MORALE_PYROMANIA_STARTFIRE, 15, 15, 8_hours, 6_hours ); - rem_morale( MORALE_PYROMANIA_NOFIRE ); - } else if( at.count( ammo_66mm ) || at.count( ammo_120mm ) || at.count( ammo_84x246mm ) || - at.count( ammo_m235 ) || at.count( ammo_atgm ) || at.count( ammo_RPG_7 ) || - at.count( ammo_homebrew_rocket ) ) { - add_msg_if_player( m_good, _( "You feel a surge of euphoria as flames burst out!" ) ); + const auto &curammo_effects = gun.ammo_effects(); + // TODO: Check if firing a gun actually started a fire + if( curammo_effects.count( "FLAME" ) || curammo_effects.count( "PYROPHORIC" ) || + curammo_effects.count( "INCENDIARY" ) || curammo_effects.count( "NAPALM" ) || + curammo_effects.count( "IGNITE" ) ) { + rem_morale( MORALE_PYROMANIA_NOFIRE ); + if( has_trait( trait_PYROMANIA_GOOD ) ) { + if( !has_morale( MORALE_PYROMANIA_STARTFIRE ) ) { + add_msg_if_player( m_good, _( "You feel a surge of euphoria as you fire the %s!" ), + gun.tname() ); + } add_morale( MORALE_PYROMANIA_STARTFIRE, 15, 15, 8_hours, 6_hours ); - rem_morale( MORALE_PYROMANIA_NOFIRE ); } }