diff --git a/data/json/encounters/randenc_caravans.json b/data/json/encounters/randenc_caravans.json new file mode 100644 index 0000000000000..67f22712e35e1 --- /dev/null +++ b/data/json/encounters/randenc_caravans.json @@ -0,0 +1,61 @@ +[ + { + "type": "effect_on_condition", + "id": "EOC_RandEnc_Roadstop_add", + "recurrence": 6000, + "global": true, + "condition": { + "and": [ + { "u_near_om_location": "roadstop_a", "range": 2 }, + "is_day", + { "one_in_chance": 10 }, + { "days_since_cataclysm": 7 }, + { + "not": { "u_compare_time_since_var": "RandEnc", "type": "timer", "context": "caravan", "op": "<", "time": "1 d" } + }, + { "not": { "u_at_om_location": "roadstop_a" } }, + { "not": { "is_season": "winter" } } + ] + }, + "effect": [ + { "mapgen_update": "nest_RandEnc_roadstop_a_add", "om_terrain": "roadstop_a" }, + { "u_add_var": "RandEnc", "type": "timer", "context": "caravan", "time": true } + ] + }, + { + "type": "effect_on_condition", + "id": "EOC_RandEnc_Roadstop_remove", + "recurrence": 200, + "global": true, + "condition": { + "and": [ { "u_compare_time_since_var": "RandEnc", "type": "timer", "context": "caravan", "op": ">", "time": "1 h" } ] + }, + "effect": [ + { "mapgen_update": "nest_RandEnc_roadstop_a_remove", "om_terrain": "roadstop_a" }, + { "remove_npc": "FM_caravan_merchant_random" }, + { "remove_npc": "FM_caravan_guard_A" }, + { "remove_npc": "FM_caravan_guard_B" } + ] + }, + { + "type": "mapgen", + "method": "json", + "update_mapgen_id": "nest_RandEnc_roadstop_a_add", + "//": "Adds a random encounter at this roadstop", + "object": { + "place_npcs": [ + { "class": "FM_caravan_merchant_random", "x": 5, "y": 4 }, + { "class": "FM_caravan_guard_A", "x": 4, "y": 1 }, + { "class": "FM_caravan_guard_B", "x": 4, "y": 2 } + ], + "place_vehicles": [ { "vehicle": "FM_early_pickup", "chance": 100, "fuel": 50, "faction": "free_merchants", "x": [ 4 ], "y": [ 1 ] } ] + } + }, + { + "type": "mapgen", + "method": "json", + "update_mapgen_id": "nest_RandEnc_roadstop_a_remove", + "//": "removes a random encounter at this roadstop", + "object": { "remove_vehicles": [ { "vehicles": [ "FM_early_pickup" ], "x": [ 1, 15 ], "y": [ 1, 10 ] } ] } + } +] diff --git a/data/json/mapgen/roadstop.json b/data/json/mapgen/roadstop.json index 566cf78d1a093..e8558f33eb12b 100644 --- a/data/json/mapgen/roadstop.json +++ b/data/json/mapgen/roadstop.json @@ -35,12 +35,12 @@ "terrain": { " ": "t_floor", "#": "t_wall_log", - ".": "t_grass", - "2": "t_dirt", + ".": "t_region_groundcover", + "2": "t_region_groundcover_barren", "3": "t_door_c", "6": "t_floor", "7": "t_floor", - "8": "t_dirt", + "8": "t_region_groundcover_barren", "A": "t_floor", "S": "t_sidewalk" }, @@ -125,17 +125,17 @@ "terrain": { " ": "t_floor", "#": "t_wall_log", - ".": "t_grass", - "2": "t_dirt", + ".": "t_region_groundcover", + "2": "t_region_groundcover_barren", "3": "t_door_c", "6": "t_floor", "7": "t_floor", - "8": "t_dirt", + "8": "t_region_groundcover_barren", "A": "t_floor", "S": "t_sidewalk", - "i": "t_dirt", - "o": "t_dirt", - "t": "t_tree" + "i": "t_region_groundcover_barren", + "o": "t_region_groundcover_barren", + "t": "t_region_tree" }, "furniture": { "6": "f_table", "7": "f_toilet", "8": "f_trashcan", "A": "f_sink", "i": "f_sign", "o": "f_crate_c" }, "signs": { diff --git a/data/json/npcs/random_encounters/free_merchant_caravans.json b/data/json/npcs/random_encounters/free_merchant_caravans.json new file mode 100644 index 0000000000000..4e788437fb686 --- /dev/null +++ b/data/json/npcs/random_encounters/free_merchant_caravans.json @@ -0,0 +1,243 @@ +[ + { + "type": "npc", + "id": "FM_caravan_merchant_random", + "//": "Random NPC, non persistent, can direct you to the free merchants and sell you things.", + "name_suffix": "Caravan Merchant", + "class": "NC_TRADER", + "attitude": 0, + "mission": 3, + "chat": "TALK_CARAVAN_MERCHANT_1", + "faction": "free_merchants" + }, + { + "type": "npc", + "id": "FM_caravan_guard_A", + "//": "Random NPC, non persistent, tells you about being a guard and directs you to free merchants.", + "name_suffix": "Caravan Guard", + "class": "NC_BOUNTY_HUNTER", + "attitude": 0, + "mission": 8, + "chat": "TALK_CARAVAN_GUARD_A1", + "faction": "free_merchants" + }, + { + "type": "npc", + "id": "FM_caravan_guard_B", + "//": "Random NPC, non persistent, doesn't have much to say.", + "name_suffix": "Caravan Guard", + "class": "NC_BOUNTY_HUNTER", + "attitude": 0, + "mission": 7, + "chat": "TALK_CARAVAN_GUARD_B", + "faction": "free_merchants" + }, + { + "type": "talk_topic", + "id": "TALK_CARAVAN_MERCHANT_1", + "dynamic_line": "Well well, another traveler. Don't try anything, you're outnumbered here and we're well armed.", + "speaker_effect": { "effect": { "npc_first_topic": "TALK_CARAVAN_MERCHANT_2" } }, + "responses": [ + { "text": "Are you threatening me?", "topic": "TALK_CARAVAN_MERCHANT_Threatening" }, + { "text": "What's your deal here?", "topic": "TALK_CARAVAN_MERCHANT_Job" }, + { "text": "I won't try anything if you don't. Just passing through.", "topic": "TALK_DONE" } + ] + }, + { + "type": "talk_topic", + "id": "TALK_CARAVAN_MERCHANT_2", + "dynamic_line": "What can I do for you?", + "responses": [ + { "text": "Do you have anything to trade?", "topic": "TALK_CARAVAN_MERCHANT_Trade", "effect": "start_trade" }, + { "text": "What's your story?", "topic": "TALK_CARAVAN_MERCHANT_Story" }, + { "text": "Nothing much. Just passing through.", "topic": "TALK_DONE" } + ] + }, + { + "type": "talk_topic", + "id": "TALK_CARAVAN_MERCHANT_Threatening", + "dynamic_line": "No, not at all. Just being cautious. You know how it gets out here. We're not looking for trouble. In fact, if you've got anything worthwhile, maybe we could do a little trading.", + "responses": [ + { "text": "Sure, let's trade.", "topic": "TALK_CARAVAN_MERCHANT_Trade", "effect": "start_trade" }, + { "text": "What's your deal here?", "topic": "TALK_CARAVAN_MERCHANT_Job" }, + { "text": "That suits me fine. I'll be on my way.", "topic": "TALK_DONE" } + ] + }, + { + "type": "talk_topic", + "id": "TALK_CARAVAN_MERCHANT_Job", + "dynamic_line": "We're just travelers, making a pit stop. Might be willing to trade a bit, if you've got anything to share. We're not looking for trouble, there's plenty of that on the roads already.", + "responses": [ + { "text": "Sure, let's trade.", "topic": "TALK_CARAVAN_MERCHANT_Trade", "effect": "start_trade" }, + { "text": "That's it? What's your story?", "topic": "TALK_CARAVAN_MERCHANT_Story" }, + { "text": "That suits me fine. I'll be on my way.", "topic": "TALK_DONE" } + ] + }, + { + "type": "talk_topic", + "id": "TALK_CARAVAN_MERCHANT_Story", + "dynamic_line": "We're with a larger group of survivors, working out of one of the old FEMA bunkers. Folks have taken to calling us Free Merchants, although that sounds kinda on the nose to me. We know about a few survivor groups and we make regular trips around, sharing supplies back and forth and bringing them home. We're on the way back now.", + "responses": [ + { "text": "That's interesting. Well, let's trade.", "topic": "TALK_CARAVAN_MERCHANT_Trade", "effect": "start_trade" }, + { + "text": "Can you give me directions to any of these other survivor groups?", + "topic": "TALK_CARAVAN_MERCHANT_Others" + }, + { + "text": "Where is 'home'?", + "topic": "TALK_CARAVAN_MERCHANT_Home", + "condition": { + "and": [ + { "not": { "u_has_mission": "MISSION_REACH_REFUGEE_CENTER" } }, + { "not": { "u_has_var": "found_refugee_center", "value": "yes" } } + ] + } + }, + { "text": "Thanks for chatting. I'd better go.", "topic": "TALK_DONE" } + ] + }, + { + "type": "talk_topic", + "id": "TALK_CARAVAN_MERCHANT_Others", + "dynamic_line": "No offense, but my clients definitely would not like me giving strangers directions to their hideouts. You'll have to find them on their own terms.", + "responses": [ + { + "text": "I can understand that. Well, let's trade.", + "topic": "TALK_CARAVAN_MERCHANT_Trade", + "effect": "start_trade" + }, + { + "text": "Where is 'home'?", + "topic": "TALK_CARAVAN_MERCHANT_Home", + "condition": { + "and": [ + { "not": { "u_has_mission": "MISSION_REACH_REFUGEE_CENTER" } }, + { "not": { "u_has_var": "found_refugee_center", "value": "yes" } } + ] + } + }, + { "text": "Thanks for chatting. I'd better go.", "topic": "TALK_DONE" } + ] + }, + { + "type": "talk_topic", + "id": "TALK_CARAVAN_MERCHANT_Home", + "dynamic_line": "Here, I'll mark it on your map. Feel free to come by and trade, or if you're the type, we might have use for your services as a merc.", + "speaker_effect": { "effect": { "assign_mission": "MISSION_REACH_REFUGEE_CENTER" } }, + "responses": [ + { "text": "Hey, thanks. Well, let's trade.", "topic": "TALK_CARAVAN_MERCHANT_Trade", "effect": "start_trade" }, + { + "text": "Can you give me directions to any of these other survivor groups?", + "topic": "TALK_CARAVAN_MERCHANT_Others" + }, + { "text": "Thanks for that. I'd better go.", "topic": "TALK_DONE" } + ] + }, + { + "type": "talk_topic", + "id": "TALK_CARAVAN_MERCHANT_Trade", + "dynamic_line": "Always good to do a little trading.", + "responses": [ + { + "text": "Actually I had a little more to trade still.", + "topic": "TALK_CARAVAN_MERCHANT_Trade", + "effect": "start_trade" + }, + { "text": "Thanks. What were we talking about before?", "topic": "TALK_NONE" }, + { "text": "Thanks for that. I'd better go.", "topic": "TALK_DONE" } + ] + }, + { + "type": "talk_topic", + "id": "TALK_CARAVAN_GUARD_A1", + "dynamic_line": "Sup? Nice to see a survivor. If you're here for business, talk to the trader.", + "speaker_effect": { "effect": { "npc_first_topic": "TALK_CARAVAN_GUARD_A2" } }, + "responses": [ + { "text": "What are you doing here?", "topic": "TALK_CARAVAN_GUARD_A_Job" }, + { "text": "Thanks for the tip.", "topic": "TALK_DONE" } + ] + }, + { + "type": "talk_topic", + "id": "TALK_CARAVAN_GUARD_A2", + "dynamic_line": "Hi again. You want something?", + "responses": [ + { "text": "What are you doing here?", "topic": "TALK_CARAVAN_GUARD_A_Job" }, + { "text": "You looking for work? I might be hiring.", "topic": "TALK_CARAVAN_GUARD_A_Hire" }, + { "text": "Nope, just saying hi.", "topic": "TALK_DONE" } + ] + }, + { + "type": "talk_topic", + "id": "TALK_CARAVAN_GUARD_A_Job", + "dynamic_line": "I'm a caravan guard, working for the Free Merchants. I'm an independent contractor though. Seems like a good way to get safety in numbers and try to find a safe place to settle down.", + "responses": [ + { "text": "So you're working for these guys, but aren't one of them?", "topic": "TALK_CARAVAN_GUARD_A_Merc" }, + { "text": "You looking for work? I might be hiring.", "topic": "TALK_CARAVAN_GUARD_A_Hire" }, + { + "text": "The Free Merchants? Do they have some kind of trade outpost or anything like that?", + "topic": "TALK_CARAVAN_GUARD_A_Directions", + "condition": { + "and": [ + { "not": { "u_has_mission": "MISSION_REACH_REFUGEE_CENTER" } }, + { "not": { "u_has_var": "found_refugee_center", "value": "yes" } } + ] + } + }, + { "text": "It's a living, eh? I'd better get going.", "topic": "TALK_DONE" } + ] + }, + { + "type": "talk_topic", + "id": "TALK_CARAVAN_GUARD_A_Merc", + "dynamic_line": "Yeah, these guys snagged some kind of FEMA evacuation bunker during the early part of and hoard the space. They don't let anyone else join, but they need supplies, so they send out traders, and those traders need protection, so they send out guys like me.", + "responses": [ + { "text": "You looking for work? I might be hiring.", "topic": "TALK_CARAVAN_GUARD_A_Hire" }, + { + "text": "How do I get there?", + "topic": "TALK_CARAVAN_GUARD_A_Directions", + "condition": { + "and": [ + { "not": { "u_has_mission": "MISSION_REACH_REFUGEE_CENTER" } }, + { "not": { "u_has_var": "found_refugee_center", "value": "yes" } } + ] + } + }, + { "text": "It's a living, eh? I'd better get going.", "topic": "TALK_DONE" } + ] + }, + { + "type": "talk_topic", + "id": "TALK_CARAVAN_GUARD_A_Hire", + "dynamic_line": "I'm good for the moment, but you can usually find a merc or two waiting between jobs, back at the Free Merchant base.", + "responses": [ + { + "text": "How do I get there?", + "topic": "TALK_CARAVAN_GUARD_A_Directions", + "condition": { + "and": [ + { "not": { "u_has_mission": "MISSION_REACH_REFUGEE_CENTER" } }, + { "not": { "u_has_var": "found_refugee_center", "value": "yes" } } + ] + } + }, + { "text": "Thanks for the tip! I'll be on my way.", "topic": "TALK_DONE" } + ] + }, + { + "type": "talk_topic", + "id": "TALK_CARAVAN_GUARD_A_Directions", + "dynamic_line": "Sure, I can mark it on your map if you like. Here.", + "speaker_effect": { "effect": { "assign_mission": "MISSION_REACH_REFUGEE_CENTER" } }, + "responses": [ + { "text": "Thanks for the tip! What were you saying before?", "topic": "TALK_NONE" }, + { "text": "Thanks for the tip! I'll be on my way.", "topic": "TALK_DONE" } + ] + }, + { + "type": "talk_topic", + "id": "TALK_CARAVAN_GUARD_B", + "dynamic_line": "*tips their hat down from their eyes and looks at you blearily. \"Huh? Hey, I'm tryin'a sleep here. I was on night watch.", + "responses": [ { "text": "Oh, uh, sorry.", "topic": "TALK_DONE" } ] + } +] diff --git a/data/json/npcs/refugee_center/missiondef_free_merchants.json b/data/json/npcs/refugee_center/missiondef_free_merchants.json index 6163a185c1cca..ce9367c09b383 100644 --- a/data/json/npcs/refugee_center/missiondef_free_merchants.json +++ b/data/json/npcs/refugee_center/missiondef_free_merchants.json @@ -8,6 +8,7 @@ "value": 0, "start": "reveal_refugee_center", "origins": [ "ORIGIN_COMPUTER" ], - "destination": "evac_center_18" + "destination": "evac_center_18", + "end": { "effect": [ { "u_add_var": "found_refugee_center", "value": "yes" } ] } } ] diff --git a/data/json/npcs/refugee_center/surface_staff/NPC_free_merchant_shopkeep.json b/data/json/npcs/refugee_center/surface_staff/NPC_free_merchant_shopkeep.json index 2f68a61a95524..1d832b8f4835a 100644 --- a/data/json/npcs/refugee_center/surface_staff/NPC_free_merchant_shopkeep.json +++ b/data/json/npcs/refugee_center/surface_staff/NPC_free_merchant_shopkeep.json @@ -278,6 +278,7 @@ { "id": "TALK_EVAC_MERCHANT", "type": "talk_topic", + "speaker_effect": { "effect": [ { "u_add_var": "found_refugee_center", "value": "yes" } ] }, "dynamic_line": { "u_is_wearing": "badge_marshal", "yes": "Welcome marshal…", "no": "Welcome…" } }, { diff --git a/data/json/vehicles/factional.json b/data/json/vehicles/factional.json new file mode 100644 index 0000000000000..9f06d3eff86d5 --- /dev/null +++ b/data/json/vehicles/factional.json @@ -0,0 +1,65 @@ +[ + { + "id": "FM_early_pickup", + "type": "vehicle", + "name": "Caravaner's Pickup Truck", + "//": "Basically a pickup truck, but spawns some different items in the bed. Later versions could have a mounted gun, a ram, and some armour.", + "blueprint": [ + [ "-o--+o-" ], + [ "==='#'|" ], + [ "==='#'|" ], + [ "-o--+o-" ] + ], + "parts": [ + { "x": 0, "y": 0, "parts": [ "frame_cross", "seat_windshield", "seatbelt", "controls", "stereo" ] }, + { "x": 0, "y": 0, "parts": [ "dashboard", "vehicle_clock", "vehicle_alarm", "horn_car" ] }, + { "x": 0, "y": 0, "part": "roof" }, + { "x": 0, "y": -1, "parts": [ "frame_vertical_left", "door_nw" ] }, + { "x": 0, "y": 1, "parts": [ "frame_cross", "seat_windshield", "seatbelt", "roof" ] }, + { "x": 0, "y": 2, "parts": [ "frame_vertical_right", "door_ne" ] }, + { "x": 1, "y": -1, "parts": [ "frame_vertical_T_left", "windshield_wheel_left" ] }, + { "x": 1, "y": -1, "parts": [ "wheel_mount_medium_steerable", "wheel" ] }, + { "x": 1, "y": 0, "parts": [ "frame_horizontal_2", "windshield_cover_left" ] }, + { "x": 1, "y": 1, "parts": [ "frame_horizontal_2", "windshield_cover_right" ] }, + { "x": 1, "y": 2, "parts": [ "frame_vertical_T_right", "windshield_wheel_right" ] }, + { "x": 1, "y": 2, "parts": [ "wheel_mount_medium_steerable", "wheel" ] }, + { "x": 2, "y": -1, "parts": [ "frame_nw", "halfboard_nw", "headlight" ] }, + { "x": 2, "y": 0, "parts": [ "frame_horizontal_front", "halfboard_cover_left" ] }, + { "x": 2, "y": 0, "parts": [ "engine_v6", "alternator_truck", "battery_car" ] }, + { "x": 2, "y": 1, "parts": [ "frame_horizontal_front", "halfboard_cover_right" ] }, + { "x": 2, "y": 2, "parts": [ "frame_ne", "halfboard_ne", "headlight" ] }, + { "x": -1, "y": -1, "parts": [ "frame_vertical_left", "windshield_sw" ] }, + { "x": -1, "y": 0, "parts": [ "frame_cross", "windshield_horizontal_rear", "roof" ] }, + { "x": -1, "y": 1, "parts": [ "frame_cross", "windshield_horizontal_rear", "roof" ] }, + { "x": -1, "y": 2, "parts": [ "frame_vertical_right", "windshield_se" ] }, + { "x": -2, "y": -1, "parts": [ "frame_vertical_left", "halfboard_vertical_left" ] }, + { "x": -2, "y": -1, "part": "tank", "fuel": "gasoline" }, + { "x": -2, "y": 0, "parts": [ "frame_cross", "cargo_space", "muffler" ] }, + { "x": -2, "y": 1, "parts": [ "frame_cross", "cargo_space" ] }, + { "x": -2, "y": 2, "parts": [ "frame_vertical_right", "halfboard_vertical_right" ] }, + { "x": -3, "y": -1, "parts": [ "frame_vertical_left", "halfboard_wheel_left" ] }, + { "x": -3, "y": -1, "parts": [ "wheel_mount_medium", "wheel" ] }, + { "x": -3, "y": 0, "parts": [ "frame_cross", "trunk" ] }, + { "x": -3, "y": 1, "parts": [ "frame_cross", "trunk" ] }, + { "x": -3, "y": 2, "parts": [ "frame_vertical_right", "halfboard_wheel_right" ] }, + { "x": -3, "y": 2, "parts": [ "wheel_mount_medium", "wheel" ] }, + { "x": -4, "y": -1, "parts": [ "frame_sw", "halfboard_sw" ] }, + { "x": -4, "y": 0, "parts": [ "frame_horizontal_rear", "trunk" ] }, + { "x": -4, "y": 1, "parts": [ "frame_horizontal_rear", "trunk" ] }, + { "x": -4, "y": 2, "parts": [ "frame_se", "halfboard_se" ] } + ], + "items": [ + { "x": 0, "y": 0, "chance": 15, "item_groups": [ "car_misc" ] }, + { "x": 0, "y": 0, "chance": 10, "item_groups": [ "car_misc" ] }, + { "x": 0, "y": 1, "chance": 10, "item_groups": [ "car_misc" ] }, + { "x": 0, "y": 1, "chance": 5, "item_groups": [ "snacks" ] }, + { "x": 0, "y": 0, "chance": 5, "item_groups": [ "fast_food" ] }, + { "x": -2, "y": 0, "chance": 55, "item_groups": [ "farming_tools" ] }, + { "x": -2, "y": 1, "chance": 52, "item_groups": [ "mischw" ] }, + { "x": -2, "y": 1, "chance": 22, "items": [ "jack", "wheel" ] }, + { "x": -3, "y": 1, "chance": 20, "item_groups": [ "car_kit" ] }, + { "x": -3, "y": 0, "chance": 18, "item_groups": [ "fuel_gasoline" ] }, + { "x": -2, "y": 1, "chance": 13, "items": [ "ax" ] } + ] + } +] diff --git a/src/dialogue.h b/src/dialogue.h index c78f8ad0330c3..03223b61d1c06 100644 --- a/src/dialogue.h +++ b/src/dialogue.h @@ -147,6 +147,7 @@ struct talk_effect_fun_t { void set_transform_radius( const JsonObject &jo, const std::string &member, bool is_npc ); void set_place_override( const JsonObject &jo, const std::string &member ); void set_mapgen_update( const JsonObject &jo, const std::string &member ); + void set_remove_npc( const JsonObject &jo, const std::string &member ); void set_revert_location( const JsonObject &jo, const std::string &member ); void set_npc_goal( const JsonObject &jo, const std::string &member ); void set_bulk_trade_accept( bool is_trade, int quantity, bool is_npc = false ); diff --git a/src/npctalk.cpp b/src/npctalk.cpp index beffa3f008d28..ad708fefb1071 100644 --- a/src/npctalk.cpp +++ b/src/npctalk.cpp @@ -2523,6 +2523,20 @@ void talk_effect_fun_t::set_mapgen_update( const JsonObject &jo, const std::stri }; } +void talk_effect_fun_t::set_remove_npc( const JsonObject &jo, const std::string &member ) +{ + std::string npc_id; + mandatory( jo, false, member, npc_id ); + function = [npc_id]( const dialogue & ) { + std::vector npc_list = g->get_npcs_if( [npc_id]( const npc & npc ) -> bool { + return npc.idz == npc_id; + } ); + for( npc *npc : npc_list ) { + overmap_buffer.remove_npc( npc->getID() ); + } + }; +} + void talk_effect_fun_t::set_revert_location( const JsonObject &jo, const std::string &member ) { duration_or_var dov_time_in_future = get_duration_or_var( jo, "time_in_future", true ); @@ -4176,6 +4190,8 @@ void talk_effect_t::parse_sub_effect( const JsonObject &jo ) subeffect_fun.set_npc_goal( jo, "npc_set_goal" ); } else if( jo.has_member( "mapgen_update" ) ) { subeffect_fun.set_mapgen_update( jo, "mapgen_update" ); + } else if( jo.has_member( "remove_npc" ) ) { + subeffect_fun.set_mapgen_update( jo, "remove_npc" ); } else if( jo.has_member( "revert_location" ) ) { subeffect_fun.set_revert_location( jo, "revert_location" ); } else if( jo.has_member( "place_override" ) ) {