From c6e2180015fb07b81c29bbd5ce5321c615064b0c Mon Sep 17 00:00:00 2001 From: Chaosvolt Date: Wed, 31 May 2023 13:34:05 -0500 Subject: [PATCH] Scenario: The Lost And Damned (#2892) * Scenario: The Lost And Damned * Update professions.json * Nerf scenario cost, add a lil something * Apply suggestions from code review Co-authored-by: github-actions[bot] <41898282+github-actions[bot]@users.noreply.github.com> * Add the other complications * Update game.cpp * Some updates * Update data/json/effects.json Co-authored-by: github-actions[bot] <41898282+github-actions[bot]@users.noreply.github.com> --------- Co-authored-by: github-actions[bot] <41898282+github-actions[bot]@users.noreply.github.com> --- data/json/effects.json | 21 ++ data/json/mutations/mutations.json | 11 + data/json/professions.json | 374 +++++++++++++++++++++++++++++ data/json/scenarios.json | 42 ++++ src/character.h | 1 + src/game.cpp | 5 + src/monster.cpp | 38 ++- src/npc.cpp | 10 +- src/suffer.cpp | 91 ++++++- 9 files changed, 590 insertions(+), 3 deletions(-) diff --git a/data/json/effects.json b/data/json/effects.json index aab27d0a2868..3f90ab6b5aa2 100644 --- a/data/json/effects.json +++ b/data/json/effects.json @@ -737,6 +737,27 @@ "name": [ "Took Thorazine" ], "desc": [ "You took Thorazine some time ago and you might still be under its influence." ] }, + { + "type": "effect_type", + "id": "feral_killed_recently", + "max_duration": "200 d", + "name": [ "Lucidity" ], + "desc": [ + "You could always go for more bloodshed, but the voices in your head are staying quiet for now. You currently won't suffer the side effects of your deteriorating mind and body." + ], + "remove_message": "You can hear the whispering again. Need more meat.", + "rating": "good" + }, + { + "type": "effect_type", + "id": "feral_infighting_punishment", + "max_duration": "7 h", + "name": [ "Inner turmoil" ], + "desc": [ "You don't feel like you anymore. The others seem to regard you as prey." ], + "apply_message": "You feel like you shouldn't have done that…", + "remove_message": "You feel normal again.", + "rating": "bad" + }, { "type": "effect_type", "id": "no_sight", diff --git a/data/json/mutations/mutations.json b/data/json/mutations/mutations.json index 6004601f42db..f805398bc9b0 100644 --- a/data/json/mutations/mutations.json +++ b/data/json/mutations/mutations.json @@ -6455,5 +6455,16 @@ "valid": false, "purifiable": false, "profession": false + }, + { + "type": "mutation", + "id": "PROF_FERAL", + "name": { "str": "Lost To The Cataclysm" }, + "points": 0, + "description": "Something inside you snapped. Whether though wallowing in decay or by otherworldly influence, the living shun you while the undead mostly ignore you. Your mind and body will deteriorate if you don't keep killing the living and sane. Your fellow lost and damned will suffice too, but that might cause the others to mistake you for the living.", + "valid": false, + "purifiable": false, + "profession": true, + "scent_type": "sc_fetid" } ] diff --git a/data/json/professions.json b/data/json/professions.json index dda344bcd92d..45fbe825b57e 100644 --- a/data/json/professions.json +++ b/data/json/professions.json @@ -4523,5 +4523,379 @@ "vehicle": "helicopter_blackhawk_3a", "points": 7, "copy-from": "mili_pilot" + }, + { + "type": "profession", + "id": "prof_feral_unemployed", + "name": "Feral Survivor", + "description": "They used to say that there's nothing particularly notable about you. But you survived, and they didn't. You made sure of that.", + "points": 0, + "traits": [ "PROF_FERAL" ], + "items": { + "both": { + "items": [ "pockknife", "bottle_plastic", "wristwatch" ], + "entries": [ + { "item": "longshirt", "damage": [ 0, 3 ] }, + { "item": "jeans", "damage": [ 0, 3 ] }, + { "item": "socks", "damage": [ 0, 3 ] }, + { "item": "sneakers", "damage": [ 0, 3 ] }, + { "item": "mbag", "damage": [ 0, 3 ] }, + { "item": "wristwatch", "damage": [ 0, 3 ] }, + { "item": "makeshift_crowbar", "custom-flags": [ "auto_wield" ] } + ] + }, + "male": { "entries": [ { "item": "boxer_shorts", "damage": [ 0, 3 ] } ] }, + "female": { "entries": [ { "item": "bra", "damage": [ 0, 3 ] }, { "item": "panties", "damage": [ 0, 3 ] } ] } + }, + "flags": [ "SCEN_ONLY" ] + }, + { + "type": "profession", + "id": "prof_feral_scientist", + "copy-from": "prof_feral_unemployed", + "name": "Feral Scientist", + "description": "You learned quite a few things back in those old labs. You know now why the world ended. You just need a better equipment and you can prove to whoever's left you were right all along.", + "points": 3, + "skills": [ + { "level": 2, "name": "computer" }, + { "level": 2, "name": "cooking" }, + { "level": 2, "name": "electronics" }, + { "level": 2, "name": "mechanics" } + ], + "items": { + "both": { + "items": [ "pockknife", "bottle_plastic", "wristwatch" ], + "entries": [ + { "item": "dress_shirt", "damage": [ 0, 3 ] }, + { "item": "coat_lab", "damage": [ 0, 3 ] }, + { "item": "jeans", "damage": [ 0, 3 ] }, + { "item": "socks", "damage": [ 0, 3 ] }, + { "item": "boots", "damage": [ 0, 3 ] }, + { "item": "gloves_rubber", "damage": [ 0, 3 ] }, + { "item": "glasses_safety", "damage": [ 0, 3 ] }, + { + "item": "medium_battery_cell", + "ammo-item": "battery", + "charges": [ 1, 500 ], + "container-item": "chemistry_set" + }, + { "item": "scalpel", "custom-flags": [ "auto_wield" ] } + ] + }, + "male": { "entries": [ { "item": "briefs", "damage": [ 0, 3 ] } ] }, + "female": { "entries": [ { "item": "bra", "damage": [ 0, 3 ] }, { "item": "panties", "damage": [ 0, 3 ] } ] } + } + }, + { + "type": "profession", + "id": "prof_feral_cop", + "copy-from": "prof_feral_unemployed", + "name": "Feral Police Officer", + "//": "Contains a Judge Dredd reference.", + "description": "You were just a small-town deputy. You got caught up in the riots, and now you're the only law left in this town. The crime is life. The sentence is death.", + "points": 2, + "traits": [ "PROF_POLICE", "PROF_FERAL" ], + "items": { + "both": { + "items": [ "two_way_radio", "whistle", "wristwatch", "badge_deputy" ], + "entries": [ + { "item": "sheriffshirt", "damage": [ 0, 3 ] }, + { "item": "pants_army", "damage": [ 0, 3 ] }, + { "item": "socks", "damage": [ 0, 3 ] }, + { "item": "boots", "damage": [ 0, 3 ] }, + { "item": "police_belt", "damage": [ 0, 3 ] }, + { "item": "legpouch_large", "damage": [ 0, 3 ] }, + { "item": "m9", "ammo-item": "9mm", "charges": [ 1, 15 ], "container-item": "holster" }, + { + "item": "light_battery_cell", + "ammo-item": "battery", + "charges": [ 1, 100 ], + "container-item": "heavy_flashlight", + "custom-flags": [ "auto_wield" ] + } + ] + }, + "male": { "entries": [ { "item": "boxer_shorts", "damage": [ 0, 3 ] } ] }, + "female": { "entries": [ { "item": "bra", "damage": [ 0, 3 ] }, { "item": "boy_shorts", "damage": [ 0, 3 ] } ] } + } + }, + { + "type": "profession", + "id": "prof_feral_firefighter", + "copy-from": "prof_feral_unemployed", + "name": "Feral Firefighter", + "//": "Contains a Fahrenheit 451 reference.", + "description": "As a first responder you were direct witness to the gut-wrenching horrors of the apocalypse. You still feel the fire, burning the pit of your stomach. It was a pleasure to burn.", + "points": 3, + "skills": [ { "level": 2, "name": "melee" }, { "level": 1, "name": "firstaid" }, { "level": 1, "name": "swimming" } ], + "items": { + "both": { + "items": [ "pocketwatch" ], + "entries": [ + { "item": "bunker_coat", "damage": [ 0, 3 ] }, + { "item": "bunker_pants", "damage": [ 0, 3 ] }, + { "item": "nomex_socks", "damage": [ 0, 3 ] }, + { "item": "boots_bunker", "damage": [ 0, 3 ] }, + { "item": "fire_gauntlets", "damage": [ 0, 3 ] }, + { "item": "glasses_safety", "damage": [ 0, 3 ] }, + { "item": "fireman_belt", "damage": [ 0, 3 ] }, + { "item": "firehelmet", "damage": [ 0, 3 ] }, + { "item": "fire_ax", "custom-flags": [ "auto_wield" ] } + ] + }, + "male": { "entries": [ { "item": "boxer_shorts", "damage": [ 0, 3 ] } ] }, + "female": { "entries": [ { "item": "bra", "damage": [ 0, 3 ] }, { "item": "boxer_shorts", "damage": [ 0, 3 ] } ] } + } + }, + { + "type": "profession", + "id": "prof_feral_mechanic", + "copy-from": "prof_feral_unemployed", + "name": "Feral Mechanic", + "description": "You've always loved cars. Now you'll never be wanting for materials. The machine speaks to you, commanding you to build it.", + "points": 2, + "skills": [ { "level": 3, "name": "mechanics" } ], + "items": { + "both": { + "items": [ "wristwatch", "welder" ], + "entries": [ + { "item": "technician_shirt_gray", "damage": [ 0, 3 ] }, + { "item": "technician_pants_gray", "damage": [ 0, 3 ] }, + { "item": "socks", "damage": [ 0, 3 ] }, + { "item": "boots_steel", "damage": [ 0, 3 ] }, + { "item": "gloves_work", "damage": [ 0, 3 ] }, + { "item": "slingpack", "damage": [ 0, 3 ] }, + { "item": "tool_belt", "damage": [ 0, 3 ], "contents-item": "screwdriver" }, + { "item": "duct_tape", "charges": [ 1, 200 ] }, + { "item": "goggles_welding", "custom-flags": [ "no_auto_equip" ] }, + { "item": "wrench", "custom-flags": [ "auto_wield" ] } + ] + }, + "male": { "entries": [ { "item": "boxer_shorts", "damage": [ 0, 3 ] } ] }, + "female": { "entries": [ { "item": "bra", "damage": [ 0, 3 ] }, { "item": "boy_shorts", "damage": [ 0, 3 ] } ] } + } + }, + { + "type": "profession", + "id": "prof_feral_biker", + "copy-from": "prof_feral_unemployed", + "name": "Feral Biker", + "description": "You lived on the open road with your motorcycle club. They're dead and you're not. Any bastard that tries to touch your ride will join them.", + "//": "One point higher since starts with more gear.", + "points": 4, + "skills": [ { "level": 4, "name": "driving" }, { "level": 1, "name": "mechanics" } ], + "vehicle": "motorcycle", + "items": { + "both": { + "items": [ "wristwatch", "multitool" ], + "entries": [ + { "item": "tank_top", "damage": [ 0, 3 ] }, + { "item": "jacket_leather", "damage": [ 0, 3 ] }, + { "item": "jeans", "damage": [ 0, 3 ] }, + { "item": "chaps_leather", "damage": [ 0, 3 ] }, + { "item": "socks", "damage": [ 0, 3 ] }, + { "item": "boots", "damage": [ 0, 3 ] }, + { "item": "bandana", "damage": [ 0, 3 ] }, + { "item": "pickelhaube", "damage": [ 0, 3 ] }, + { "item": "sheath", "contents-item": "knife_trench" }, + { "item": "meth", "charges": [ 1, 3 ] }, + { + "item": "mossberg_500", + "ammo-item": "shot_00", + "charges": [ 1, 6 ], + "contents-item": "shoulder_strap", + "custom-flags": [ "auto_wield" ] + } + ] + }, + "male": { "entries": [ { "item": "boxer_shorts", "damage": [ 0, 3 ] } ] }, + "female": { "entries": [ { "item": "bra", "damage": [ 0, 3 ] }, { "item": "boy_shorts", "damage": [ 0, 3 ] } ] } + } + }, + { + "type": "profession", + "id": "prof_feral_survivalist", + "copy-from": "prof_feral_unemployed", + "name": "Feral Survivalist", + "description": "Your skills are quite likely to come in useful considering civilization is now full of monsters that want you dead. The feeling's mutual, you'll kill whoever or whatever poses a threat to you.", + "//": "One point higher since starts with extra gear.", + "points": 4, + "skills": [ + { "level": 4, "name": "survival" }, + { "level": 2, "name": "traps" }, + { "level": 2, "name": "fabrication" }, + { "level": 2, "name": "cooking" }, + { "level": 2, "name": "firstaid" }, + { "level": 2, "name": "swimming" } + ], + "items": { + "both": { + "items": [ "wristwatch", "canteen", "rope_30", "whistle", "lighter" ], + "entries": [ + { "item": "kevlar", "damage": [ 0, 3 ] }, + { "item": "tshirt", "damage": [ 0, 3 ] }, + { "item": "jacket_light", "damage": [ 0, 3 ] }, + { "item": "pants_cargo", "damage": [ 0, 3 ] }, + { "item": "socks", "damage": [ 0, 3 ] }, + { "item": "boots", "damage": [ 0, 3 ] }, + { "item": "hat_boonie", "damage": [ 0, 3 ] }, + { "item": "light_battery_cell", "charges": [ 1, 100 ], "container-item": "wearable_light" }, + { "item": "backpack", "damage": [ 0, 3 ] }, + { "item": "makeshift_machete", "container-item": "scabbard" }, + { + "item": "ruger_mini", + "ammo-item": "223", + "charges": [ 1, 20 ], + "contents-item": "shoulder_strap", + "custom-flags": [ "auto_wield" ] + } + ] + }, + "male": { "entries": [ { "item": "boxer_shorts", "damage": [ 0, 3 ] } ] }, + "female": { "entries": [ { "item": "bra", "damage": [ 0, 3 ] }, { "item": "boy_shorts", "damage": [ 0, 3 ] } ] } + } + }, + { + "type": "profession", + "id": "prof_feral_soldier", + "copy-from": "prof_feral_unemployed", + "name": "Feral Soldier", + "//": "Contains a Full Metal Jacket reference. One higher point cost due to added gear.", + "description": "As far as you can tell, command abandoned you to this hellhole. How can you take care of a bunch of panicked civilians in need of assistance with no backup? Easy, you just don't lead 'em so much.", + "points": 5, + "traits": [ "PROF_MILITARY", "PROF_FERAL" ], + "skills": [ + { "level": 2, "name": "gun" }, + { "level": 1, "name": "rifle" }, + { "level": 2, "name": "melee" }, + { "level": 1, "name": "stabbing" }, + { "level": 1, "name": "dodge" } + ], + "items": { + "both": { + "items": [ "wristwatch", "two_way_radio", "grenade" ], + "entries": [ + { "item": "undershirt", "damage": [ 0, 3 ] }, + { "item": "jacket_army", "damage": [ 0, 3 ] }, + { "item": "pants_army", "damage": [ 0, 3 ] }, + { "item": "modularvestceramic", "damage": [ 0, 3 ] }, + { "item": "socks", "damage": [ 0, 3 ] }, + { "item": "boots_combat", "damage": [ 0, 3 ] }, + { "item": "gloves_liner", "damage": [ 0, 3 ] }, + { "item": "gloves_tactical", "damage": [ 0, 3 ] }, + { "item": "mask_ski", "damage": [ 0, 3 ] }, + { "item": "helmet_army", "damage": [ 0, 3 ] }, + { "item": "mask_gas", "damage": [ 0, 3 ], "charges": [ 1, 100 ] }, + { "item": "molle_pack", "damage": [ 0, 3 ] }, + { "item": "webbing_belt", "damage": [ 0, 3 ], "contents-item": "e_tool" }, + { "item": "knife_combat", "container-item": "sheath" }, + { + "item": "m4a1", + "ammo-item": "556", + "charges": [ 1, 30 ], + "contents-item": [ "shoulder_strap", "holo_sight" ], + "custom-flags": [ "auto_wield" ] + } + ] + }, + "male": { "entries": [ { "item": "boxer_shorts", "damage": [ 0, 3 ] } ] }, + "female": { "entries": [ { "item": "sports_bra", "damage": [ 0, 3 ] }, { "item": "boxer_shorts", "damage": [ 0, 3 ] } ] } + } + }, + { + "type": "profession", + "id": "prof_feral_cyborg", + "copy-from": "prof_feral_unemployed", + "name": "Feral Cyborg", + "description": "Completely overtaken by bionic-induced psychosis, you are a deformed posthuman monster who had no place in society. Was that your excuse all along, was it the machine that drove you mad or were you always mad? Or did it all start when the world ended? You can't remember anymore.", + "//": "One higher point cost due to more powerful bionics.", + "points": 3, + "CBMs": [ + "bio_thumbs", + "bio_spasm", + "bio_shakes", + "bio_power_weakness", + "bio_sleepy", + "bio_drain", + "bio_nostril", + "bio_ankles", + "bio_trip", + "bio_stiff", + "bio_metabolics", + "bio_power_storage_mkII", + "bio_claws", + "bio_digestion", + "bio_hydraulics" + ], + "skills": [ + { "level": 3, "name": "melee" }, + { "level": 3, "name": "unarmed" }, + { "level": 3, "name": "dodge" }, + { "level": 2, "name": "survival" } + ], + "items": { + "both": { + "items": [ "wristwatch" ], + "entries": [ + { "item": "tank_top", "damage": [ 0, 3 ] }, + { "item": "shorts_cargo", "damage": [ 0, 3 ] }, + { "item": "footrags", "damage": [ 0, 3 ] }, + { "item": "gloves_wraps", "damage": [ 0, 3 ] }, + { "item": "hat_cotton", "damage": [ 0, 3 ] }, + { "item": "bandana", "damage": [ 0, 3 ] } + ] + }, + "male": { "entries": [ { "item": "briefs", "damage": [ 0, 3 ] } ] }, + "female": { "entries": [ { "item": "panties", "damage": [ 0, 3 ] } ] } + } + }, + { + "type": "profession", + "id": "prof_feral_socialite", + "copy-from": "prof_feral_unemployed", + "name": "Feral Socialite", + "description": "Elegant as always, the end of the world hardly fazed you at all. Your entourage is as lively as ever, just a bit peckish. Best to not keep them waiting, let the hunt begin.", + "points": 5, + "skills": [ + { "level": 3, "name": "dodge" }, + { "level": 3, "name": "melee" }, + { "level": 2, "name": "stabbing" }, + { "level": 2, "name": "gun" }, + { "level": 1, "name": "smg" } + ], + "items": { + "both": { + "items": [ "pocketwatch" ], + "entries": [ + { "item": "socks", "damage": [ 0, 3 ] }, + { "item": "dress_shoes", "damage": [ 0, 3 ] }, + { "item": "case_violin", "damage": [ 0, 3 ] }, + { "item": "rapier", "container-item": "scabbard" }, + { + "item": "thompson_drum", + "ammo-item": "45_acp", + "charges": [ 1, 50 ], + "container-item": "tommygun", + "custom-flags": [ "auto_wield" ] + } + ] + }, + "male": { + "entries": [ + { "item": "boxer_shorts", "damage": [ 0, 3 ] }, + { "item": "tux", "damage": [ 0, 3 ] }, + { "item": "bowhat", "damage": [ 0, 3 ] } + ] + }, + "female": { + "entries": [ + { "item": "bra", "damage": [ 0, 3 ] }, + { "item": "panties", "damage": [ 0, 3 ] }, + { "item": "gown", "damage": [ 0, 3 ] }, + { "item": "long_glove_white", "damage": [ 0, 3 ] }, + { "item": "purse", "damage": [ 0, 3 ] } + ] + } + } } ] diff --git a/data/json/scenarios.json b/data/json/scenarios.json index a59805014a82..d086e1c5e2e5 100644 --- a/data/json/scenarios.json +++ b/data/json/scenarios.json @@ -99,6 +99,7 @@ "points": -4, "start_name": "In Town", "allowed_locs": [ + "sloc_shelter_vandalized", "sloc_house", "sloc_house_boarded", "sloc_school", @@ -185,6 +186,47 @@ "forbidden_traits": [ "FASTREADER", "SLOWREADER" ], "flags": [ "CHALLENGE", "LONE_START" ] }, + { + "type": "scenario", + "id": "player_feral", + "name": "Challenge - The Lost And Damned", + "points": -5, + "description": "You spent the first few weeks of the cataclysm in a dull haze. The riots have died down and the summer sun has drawn out the stench of decay. You stagger out of your hiding place with a gnawing hunger, unsure if you're the only one left alive, or if this is what living death is like.", + "start_name": "In Town?", + "allowed_locs": [ + "sloc_shelter_vandalized", + "sloc_house", + "sloc_house_boarded", + "sloc_garage", + "sloc_pawn_shop", + "sloc_bank", + "sloc_furniture_store", + "sloc_church", + "sloc_cemetery", + "sloc_apartments_rooftop", + "sloc_hospital", + "sloc_fire_station", + "sloc_police", + "sloc_mansion", + "sloc_lmoe_empty" + ], + "professions": [ + "prof_feral_unemployed", + "prof_feral_scientist", + "prof_feral_cop", + "prof_feral_firefighter", + "prof_feral_mechanic", + "prof_feral_biker", + "prof_feral_survivalist", + "prof_feral_soldier", + "prof_feral_cyborg", + "prof_feral_socialite" + ], + "traits": [ "RADIOGENIC", "ROT2", "SAPROVORE", "SORES", "UNSTABLE" ], + "forced_traits": [ "KILLER", "SCHIZOPHRENIC", "CARNIVORE" ], + "forbidden_traits": [ "ANIMALEMPATH", "ANIMALDISCORD", "ANTIWHEAT", "ANTIFRUIT", "MEATARIAN", "SQUEAMISH" ], + "flags": [ "CHALLENGE", "LONE_START", "SUM_START", "CITY_START" ] + }, { "type": "scenario", "id": "lab_chal", diff --git a/src/character.h b/src/character.h index ab7b3c81212f..f033a227bc15 100644 --- a/src/character.h +++ b/src/character.h @@ -2222,6 +2222,7 @@ class Character : public Creature, public visitable void suffer_from_chemimbalance(); void suffer_from_schizophrenia(); void suffer_from_asthma( int current_stim ); + void suffer_feral_kill_withdrawl(); void suffer_in_sunlight(); void suffer_from_sunburn(); void suffer_from_other_mutations(); diff --git a/src/game.cpp b/src/game.cpp index 92fc9e21b041..eebb1752e492 100644 --- a/src/game.cpp +++ b/src/game.cpp @@ -226,6 +226,7 @@ static const efftype_id effect_docile( "docile" ); static const efftype_id effect_downed( "downed" ); static const efftype_id effect_drunk( "drunk" ); static const efftype_id effect_evil( "evil" ); +static const efftype_id effect_feral_killed_recently( "feral_killed_recently" ); static const efftype_id effect_flu( "flu" ); static const efftype_id effect_infected( "infected" ); static const efftype_id effect_laserlocked( "laserlocked" ); @@ -260,6 +261,7 @@ static const trait_id trait_ILLITERATE( "ILLITERATE" ); static const trait_id trait_LEG_TENT_BRACE( "LEG_TENT_BRACE" ); static const trait_id trait_M_IMMUNE( "M_IMMUNE" ); static const trait_id trait_PARKOUR( "PARKOUR" ); +static const trait_id trait_PROF_FERAL( "PROF_FERAL" ); static const trait_id trait_VINES2( "VINES2" ); static const trait_id trait_VINES3( "VINES3" ); static const trait_id trait_THICKSKIN( "THICKSKIN" ); @@ -627,6 +629,9 @@ bool game::start_game() get_option( "DISTANCE_INITIAL_VISIBILITY" ), 0 ); u.moves = 0; + if( u.has_trait( trait_PROF_FERAL ) ) { + u.add_effect( effect_feral_killed_recently, 3_days ); + } u.process_turn(); // process_turn adds the initial move points u.set_stamina( u.get_stamina_max() ); get_weather().temperature = SPRING_TEMPERATURE; diff --git a/src/monster.cpp b/src/monster.cpp index e00f4b4b750c..382ef0807e69 100644 --- a/src/monster.cpp +++ b/src/monster.cpp @@ -69,6 +69,8 @@ static const efftype_id effect_deaf( "deaf" ); static const efftype_id effect_docile( "docile" ); static const efftype_id effect_downed( "downed" ); static const efftype_id effect_emp( "emp" ); +static const efftype_id effect_feral_infighting_punishment( "feral_infighting_punishment" ); +static const efftype_id effect_feral_killed_recently( "feral_killed_recently" ); static const efftype_id effect_grabbed( "grabbed" ); static const efftype_id effect_grabbing( "grabbing" ); static const efftype_id effect_heavysnare( "heavysnare" ); @@ -111,6 +113,7 @@ static const trait_id trait_MYCUS_FRIEND( "MYCUS_FRIEND" ); static const trait_id trait_PACIFIST( "PACIFIST" ); static const trait_id trait_PHEROMONE_INSECT( "PHEROMONE_INSECT" ); static const trait_id trait_PHEROMONE_MAMMAL( "PHEROMONE_MAMMAL" ); +static const trait_id trait_PROF_FERAL( "PROF_FERAL" ); static const trait_id trait_TERRIFYING( "TERRIFYING" ); static const trait_id trait_THRESH_MYCUS( "THRESH_MYCUS" ); @@ -1124,6 +1127,13 @@ monster_attitude monster::attitude( const Character *u ) const } } + static const string_id faction_zombie( "zombie" ); + if( faction == faction_zombie || type->in_species( ZOMBIE ) ) { + if( u->has_trait( trait_PROF_FERAL ) && !u->has_effect( effect_feral_infighting_punishment ) ) { + return MATT_FRIEND; + } + } + if( type->in_species( FUNGUS ) && ( u->has_trait( trait_THRESH_MYCUS ) || u->has_trait( trait_MYCUS_FRIEND ) ) ) { return MATT_FRIEND; @@ -1140,7 +1150,15 @@ monster_attitude monster::attitude( const Character *u ) const } if( has_flag( MF_ANIMAL ) ) { - if( u->has_trait( trait_ANIMALEMPATH ) ) { + if( u->has_trait( trait_PROF_FERAL ) ) { + // We want wildlife to amp their normal fight-or-flight response up to eleven, so anger_relation won't cut it. + if( effective_anger >= -10 ) { + effective_anger += 25; + } + if( effective_anger < -10 ) { + effective_morale -= 100; + } + } else if( u->has_trait( trait_ANIMALEMPATH ) ) { effective_anger -= 10; if( effective_anger < 10 ) { effective_morale += 55; @@ -2308,6 +2326,24 @@ void monster::die( Creature *nkiller ) ch->add_morale( MORALE_KILLER_HAS_KILLED, 5, 10, 6_hours, 4_hours ); ch->rem_morale( MORALE_KILLER_NEED_TO_KILL ); } + static const string_id faction_zombie( "zombie" ); + // Feral survivors are motivated to kill anything human + if( ch->has_trait( trait_PROF_FERAL ) && has_flag( MF_HUMAN ) ) { + if( !ch->has_effect( effect_feral_killed_recently ) ) { + ch->add_msg_if_player( m_good, _( "The voices in your head quiet down a bit." ) ); + } + if( faction != faction_zombie && !type->in_species( ZOMBIE ) ) { + ch->add_effect( effect_feral_killed_recently, 3_days ); + } else { + // Killing fellow ferals works but is less efficient, and comes with risk of punishment. + ch->add_effect( effect_feral_killed_recently, 6_hours ); + if( one_in( 3 ) ) { + ch->add_msg_if_player( m_bad, + _( "The rush of blood seems to drive off the smell of decay for a moment." ) ); + ch->add_effect( effect_feral_infighting_punishment, 6_hours ); + } + } + } } // Drop items stored in optionals move_special_item_to_inv( tack_item ); diff --git a/src/npc.cpp b/src/npc.cpp index 9ff4f4c3171b..fa544d9c2073 100644 --- a/src/npc.cpp +++ b/src/npc.cpp @@ -81,6 +81,7 @@ static const efftype_id effect_ai_waiting( "ai_waiting" ); static const efftype_id effect_bouldering( "bouldering" ); static const efftype_id effect_contacts( "contacts" ); static const efftype_id effect_drunk( "drunk" ); +static const efftype_id effect_feral_killed_recently( "feral_killed_recently" ); static const efftype_id effect_infection( "infection" ); static const efftype_id effect_mending( "mending" ); static const efftype_id effect_npc_flee_player( "npc_flee_player" ); @@ -117,6 +118,7 @@ static const trait_id trait_ILLITERATE( "ILLITERATE" ); static const trait_id trait_KILLER( "KILLER" ); static const trait_id trait_MUTE( "MUTE" ); static const trait_id trait_PROF_DICEMASTER( "PROF_DICEMASTER" ); +static const trait_id trait_PROF_FERAL( "PROF_FERAL" ); static const trait_id trait_PSYCHOPATH( "PSYCHOPATH" ); static const trait_id trait_SAPIOVORE( "SAPIOVORE" ); static const trait_id trait_SCHIZOPHRENIC( "SCHIZOPHRENIC" ); @@ -2020,7 +2022,7 @@ bool npc::is_minion() const bool npc::guaranteed_hostile() const { - return is_enemy() || ( my_fac && my_fac->likes_u < -10 ); + return is_enemy() || ( my_fac && my_fac->likes_u < -10 ) || g->u.has_trait( trait_PROF_FERAL ); } bool npc::is_walking_with() const @@ -2538,6 +2540,12 @@ void npc::die( Creature *nkiller ) g->u.rem_morale( MORALE_KILLER_NEED_TO_KILL ); } + if( killer == &g->u && g->u.has_trait( trait_PROF_FERAL ) ) { + if( !g->u.has_effect( effect_feral_killed_recently ) ) { + g->u.add_msg_if_player( m_good, _( "The voices in your head quiet down a bit." ) ); + } + g->u.add_effect( effect_feral_killed_recently, 7_days ); + } place_corpse(); } diff --git a/src/suffer.cpp b/src/suffer.cpp index 55163bf580ba..22a623a14a97 100644 --- a/src/suffer.cpp +++ b/src/suffer.cpp @@ -88,6 +88,7 @@ static const efftype_id effect_deaf( "deaf" ); static const efftype_id effect_disabled( "disabled" ); static const efftype_id effect_downed( "downed" ); static const efftype_id effect_drunk( "drunk" ); +static const efftype_id effect_feral_killed_recently( "feral_killed_recently" ); static const efftype_id effect_formication( "formication" ); static const efftype_id effect_glowy_led( "glowy_led" ); static const efftype_id effect_hallu( "hallu" ); @@ -135,6 +136,7 @@ static const trait_id trait_NARCOLEPTIC( "NARCOLEPTIC" ); static const trait_id trait_NONADDICTIVE( "NONADDICTIVE" ); static const trait_id trait_NOPAIN( "NOPAIN" ); static const trait_id trait_PER_SLIME( "PER_SLIME" ); +static const trait_id trait_PROF_FERAL( "PROF_FERAL" ); static const trait_id trait_PYROMANIA( "PYROMANIA" ); static const trait_id trait_RADIOACTIVE1( "RADIOACTIVE1" ); static const trait_id trait_RADIOACTIVE2( "RADIOACTIVE2" ); @@ -312,7 +314,7 @@ void Character::suffer_while_awake( const int current_stim ) suffer_from_chemimbalance(); } if( ( has_trait( trait_SCHIZOPHRENIC ) || has_artifact_with( AEP_SCHIZO ) ) && - !has_effect( effect_took_thorazine ) ) { + !has_effect( effect_took_thorazine ) && !has_effect( effect_feral_killed_recently ) ) { suffer_from_schizophrenia(); } @@ -716,6 +718,90 @@ void Character::suffer_from_asthma( const int current_stim ) } } +void Character::suffer_feral_kill_withdrawl() +{ + // If we somehow triggered this while content with our bloodshed, cancel. + if( has_effect( effect_feral_killed_recently ) ) { + return; + } + // Once every 4 hours + if( calendar::once_every( 4_hours ) ) { + // Recent non-human kills reduce chance of it triggering but don't prevent entirely. + if( one_in( 2 ) && has_morale( MORALE_KILLER_HAS_KILLED ) ) { + return; + } + // Select a random side effect: + switch( dice( 1, 4 ) ) { + default: + case 1: + // Feel ill, overcome with nausea if awake. Additional chance of unexplained bleeding. + mod_healthy_mod( -50, -500 ); + if( !in_sleep_state() ) { + add_msg_if_player( m_bad, _( "You feel as if your insides are rotting away." ) ); + vomit(); + if( one_in( 3 ) ) { + add_msg_if_player( m_bad, _( "Blood starts leaking from your eyes and nose." ) ); + add_effect( effect_bleed, 10_minutes, bp_head ); + add_effect( effect_blind, rng( 1_seconds, 30_seconds ) ); + } + } else { + add_msg_if_player( m_bad, _( "You feel a bit queasy in your sleep." ) ); + if( one_in( 3 ) ) { + add_msg_if_player( m_bad, _( "You wake up bloody for some reason." ) ); + wake_up(); + add_effect( effect_bleed, 10_minutes, bp_head ); + add_effect( effect_blind, rng( 1_seconds, 30_seconds ) ); + } + } + break; + case 2: + // Empty stamina and inflict fatigue, pain if awake. + mod_fatigue( rng( 5, 10 ) ); + set_stamina( get_stamina() * 1 / ( rng( 3, 8 ) ) ); + if( !in_sleep_state() ) { + add_msg_if_player( m_bad, _( "Your head aches as a wave of exhaustion passes through you." ) ); + mod_pain( rng( 10, 25 ) ); + } else { + add_msg_if_player( m_bad, _( "You stir restlessly in your sleep." ) ); + } + break; + case 3: + // Adrenaline rush plus side effects from panic. Chance it will wake you up anyway. + if( !in_sleep_state() ) { + add_msg_if_player( m_bad, _( "A pang of terror stirs your fight-or-flight response!" ) ); + add_effect( effect_adrenaline, rng( 3_minutes, 5_minutes ) ); + mod_stim( rng( 5, 10 ) ); + add_morale( MORALE_FEELING_BAD, -5, -25, 10_minutes, 3_minutes, true ); + } else { + if( !one_in( 4 ) ) { + add_msg_if_player( m_bad, _( "You jolt awake in a panic attack!" ) ); + wake_up(); + add_effect( effect_adrenaline, rng( 3_minutes, 5_minutes ) ); + mod_stim( rng( 5, 10 ) ); + add_morale( MORALE_FEELING_BAD, -5, -25, 10_minutes, 3_minutes, true ); + } else { + add_msg_if_player( m_bad, _( "You have a vivid nightmare that almost wakes you up." ) ); + } + } + break; + case 4: + // The others are displeased with your lack of bloodshed, can sleep through the mental contact itself. + add_effect( effect_attention, rng( 3_hours, 6_hours ), num_bp, rng( 1, 4 ), false, true ); + if( !in_sleep_state() ) { + add_msg_if_player( m_bad, + _( "You feel like something is judging you from afar, leaving your head spinning." ) ); + add_effect( effect_shakes, 5_minutes ); + add_effect( effect_stunned, rng( 1_turns, 10_turns ) ); + } else { + add_msg_if_player( m_bad, + _( "You have a vivid nightmare about being deemed unworthy by a higher power." ) ); + } + break; + } + } + +} + void Character::suffer_in_sunlight() { double sleeve_factor = armwear_factor(); @@ -1478,6 +1564,9 @@ void Character::suffer() if( has_trait( trait_ASTHMA ) ) { suffer_from_asthma( current_stim ); } + if( has_trait( trait_PROF_FERAL ) && !has_effect( effect_feral_killed_recently ) ) { + suffer_feral_kill_withdrawl(); + } suffer_in_sunlight(); suffer_from_other_mutations();