From 482fdba55a926c66b7d5b1adadc7ddbaf2b5edba Mon Sep 17 00:00:00 2001 From: RenechCDDA <84619419+RenechCDDA@users.noreply.github.com> Date: Sun, 16 Jun 2024 13:48:55 -0400 Subject: [PATCH] Camp takeovers --- .../misc_effect_on_condition.json | 30 ++++++++ src/basecamp.cpp | 72 +++++++++++++++++++ src/basecamp.h | 4 ++ src/iexamine.cpp | 22 ++++++ 4 files changed, 128 insertions(+) diff --git a/data/json/effects_on_condition/misc_effect_on_condition.json b/data/json/effects_on_condition/misc_effect_on_condition.json index 3f28ae850db2a..a8c1e6d388734 100644 --- a/data/json/effects_on_condition/misc_effect_on_condition.json +++ b/data/json/effects_on_condition/misc_effect_on_condition.json @@ -162,5 +162,35 @@ "id": "morale_dislikes_sewer", "type": "morale_type", "text": "Dislikes being in sewer" + }, + { + "type": "effect_on_condition", + "id": "EOC_TOOK_OVER_CAMP_NOTICE", + "eoc_type": "EVENT", + "required_event": "camp_taken_over", + "condition": { "expects_vars": [ "old_owner", "new_owner", "camp_name", "was_violent" ] }, + "effect": [ + { + "if": { "compare_string": [ "your_followers", { "context_val": "new_owner" } ] }, + "then": { + "queue_eocs": { + "id": "EOC_camp_rumor_spread", + "effect": { "u_message": "Rumors of your takeover of have begun to spread…", "type": "mixed" } + }, + "time_in_future": [ "7 days", "14 days" ] + }, + "else": [ + { + "//": "Don't bother player unless they even have a camp.", + "if": "u_has_camp", + "then": { + "u_message": "While you've been out of contact with the powers of it's been taken over by its enemies.", + "popup": true, + "type": "bad" + } + } + ] + } + ] } ] diff --git a/src/basecamp.cpp b/src/basecamp.cpp index 62734492c8b94..a2006af0664fd 100644 --- a/src/basecamp.cpp +++ b/src/basecamp.cpp @@ -19,6 +19,7 @@ #include "clzones.h" #include "color.h" #include "debug.h" +#include "event_bus.h" #include "faction.h" #include "faction_camp.h" #include "game.h" @@ -28,6 +29,7 @@ #include "map.h" #include "map_iterator.h" #include "mapdata.h" +#include "messages.h" #include "npc.h" #include "output.h" #include "overmap.h" @@ -841,6 +843,76 @@ faction_id basecamp::get_owner() return owner; } +void basecamp::handle_takeover_by( faction_id new_owner, bool violent_takeover ) +{ + get_event_bus().send( get_owner(), new_owner, name, violent_takeover ); + + // If anyone was somehow assigned here, they aren't any longer. + assigned_npcs.clear(); + camp_workers.clear(); + + add_msg_debug( debugmode::DF_CAMPS, "Camp %s owned by %s is being taken over by %s!", + name, fac()->name, new_owner->name ); + + if( !violent_takeover ) { + set_owner( new_owner ); + return; + } + + // Since it was violent, the old owner is going to be upset. + // Currently only handles player faction, and very bluntly. + if( new_owner == get_player_character().get_faction()->id ) { + fac()->likes_u -= 100; + fac()->trusts_u -= 100; + } + + int num_of_owned_camps = 0; + // Go over all camps in existence and count the ones belonging to current owner + // TODO: Remove this when camps stop being stored on the player + for( tripoint_abs_omt camp_loc : get_player_character().camps ) { + std::optional bcp = overmap_buffer.find_camp( camp_loc.xy() ); + if( !bcp ) { + continue; + } + basecamp *checked_camp = *bcp; + // Note: Will count current basecamp object as well + if( checked_camp->get_owner() == get_owner() ) { + add_msg_debug( debugmode::DF_CAMPS, + "Camp %s at %s is owned by %s, adding it to plunder calculations.", + checked_camp->name, checked_camp->camp_omt_pos().to_string(), get_owner()->name ); + num_of_owned_camps++; + } + } + + if( num_of_owned_camps < 1 ) { + debugmsg( "Tried to take over a camp owned by %s, but they somehow own no camps! Is the owner's faction id no longer valid?", + get_owner().c_str() ); + // Also abort the rest + set_owner( new_owner ); + return; + } + + // The faction taking over also seizes resources proportional to the number of camps the previous owner had + // e.g. a single-camp faction has its entire stockpile plundered, a 10-camp faction has 10% transferred + nutrients captured_with_camp = fac()->food_supply / num_of_owned_camps; + nutrients taken_from_camp = -captured_with_camp; + camp_food_supply( taken_from_camp ); + add_msg_debug( debugmode::DF_CAMPS, + "Food supplies of %s plundered by %d kilocalories! Total food supply reduced to %d kilocalories after losing %.1f%% of their camps.", + fac()->name, captured_with_camp.kcal(), fac()->food_supply.kcal(), + 1.0 / static_cast( num_of_owned_camps ) * 100.0 ); + set_owner( new_owner ); + int previous_days_of_food = camp_food_supply_days( MODERATE_EXERCISE ); + camp_food_supply( captured_with_camp ); + add_msg_debug( debugmode::DF_CAMPS, + "Food supply of new owner %s has increased to %d kilocalories due to takeover of camp %s!", + fac()->name, new_owner->food_supply.kcal(), name ); + if( new_owner == get_player_character().get_faction()->id ) { + popup( _( "Through your looting of %s you found %d days worth of food and other resources." ), + name, camp_food_supply_days( MODERATE_EXERCISE ) - previous_days_of_food ); + } +} + void basecamp::form_crafting_inventory() { map &here = get_camp_map(); diff --git a/src/basecamp.h b/src/basecamp.h index cd9372615aa06..d58f8ffea2233 100644 --- a/src/basecamp.h +++ b/src/basecamp.h @@ -275,6 +275,10 @@ class basecamp int camp_morale( int change = 0 ) const; bool allowed_access_by( Character &guy, bool water_request = false ) const; + /* Transfers ownership of a camp and send an event signalling it. If violent_takeover, also applies relation + * maluses and transfers a proportional amount of the previous owner's food/resources to the new owner. + */ + void handle_takeover_by( faction_id new_owner, bool violent_takeover ); // recipes, gathering, and craft support functions // from a direction std::map recipe_deck( const point &dir ) const; diff --git a/src/iexamine.cpp b/src/iexamine.cpp index 94baa92523e20..24bfbef70c655 100644 --- a/src/iexamine.cpp +++ b/src/iexamine.cpp @@ -1984,6 +1984,28 @@ void iexamine::bulletin_board( Character &you, const tripoint &examp ) if( bcp ) { basecamp *temp_camp = *bcp; if( !temp_camp->allowed_access_by( you ) ) { + if( !you.is_avatar() ) { + return; // One day, NPCs may be able to use bulletin boards + } + // Checks the reality bubble for NPCs + std::vector> nearby_npcs = overmap_buffer.get_npcs_near_player( HALF_MAPSIZE ); + bool unoccupied_camp = true; + for( npc_ptr &some_guy : nearby_npcs ) { + if( !some_guy ) { + continue; + } else if( some_guy->get_faction()->id == temp_camp->get_owner() ) { + unoccupied_camp = false; + } + } + if( unoccupied_camp && + query_yn( _( "There's nobody here to protect %s. Do you want to claim ownership?" ), + temp_camp->camp_name() ) ) { + bool plunder = query_yn( + _( "Take whatever you can find from the stores? This may anger %s and their allies." ), + temp_camp->get_owner()->name ); + temp_camp->handle_takeover_by( you.get_faction()->id, plunder ); + return; + } you.add_msg_if_player( _( "You don't run this camp, the board is useless to you." ) ); return; }