Skip to content

Commit

Permalink
feat: extend add_spawn() to handle creating pets (#4309)
Browse files Browse the repository at this point in the history
feat: extend add_spawn() to handle creating pets

So far map::add_spawn() and the underlying spawn_point struct have been
operating on the binary notion that a spawn can be friendly or not. This
PR extends those APIs to also support generating monsters that are pets
of the player, while also honoring backwards compatibility with parts of
the codebase that still want to operate on the binary friendly notion,
such as the save/load system for submaps.
  • Loading branch information
ekaratzas authored Mar 7, 2024
1 parent 589ffa1 commit b86d593
Show file tree
Hide file tree
Showing 8 changed files with 63 additions and 14 deletions.
2 changes: 1 addition & 1 deletion src/editmap.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -663,7 +663,7 @@ void editmap::draw_main_ui_overlay()
const tripoint spawn_p = sm_origin + sp.pos;
const auto spawn_it = spawns.find( spawn_p );
if( spawn_it == spawns.end() ) {
const Attitude att = sp.friendly ? Attitude::A_FRIENDLY : Attitude::A_ANY;
const Attitude att = sp.is_friendly() ? Attitude::A_FRIENDLY : Attitude::A_ANY;
spawns.emplace( spawn_p, std::make_tuple( sp.type, sp.count, false, att ) );
} else {
std::get<2>( spawn_it->second ) = true;
Expand Down
9 changes: 7 additions & 2 deletions src/map.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -7321,7 +7321,9 @@ void map::rotten_item_spawn( const item &item, const tripoint &pnt )
get_option<float>( "CARRION_SPAWNRATE" ) );
if( rng( 0, 100 ) < chance ) {
MonsterGroupResult spawn_details = MonsterGroupManager::GetResultFromGroup( mgroup );
add_spawn( spawn_details.name, 1, pnt, item.has_own_flag( flag_SPAWN_FRIENDLY ) );
const spawn_disposition disposition = item.has_own_flag( flag_SPAWN_FRIENDLY ) ?
spawn_disposition::SpawnDisp_Pet : spawn_disposition::SpawnDisp_Default;
add_spawn( spawn_details.name, 1, pnt, disposition );
if( g->u.sees( pnt ) ) {
if( item.is_seed() ) {
add_msg( m_warning, _( "Something has crawled out of the %s plants!" ), item.get_plant_name() );
Expand Down Expand Up @@ -7889,7 +7891,7 @@ void map::spawn_monsters_submap( const tripoint &gp, bool ignore_sight )
if( i.name != "NONE" ) {
tmp.unique_name = i.name;
}
if( i.friendly ) {
if( i.is_friendly() ) {
tmp.friendly = -1;
}

Expand All @@ -7903,6 +7905,9 @@ void map::spawn_monsters_submap( const tripoint &gp, bool ignore_sight )
monster *const placed = g->place_critter_at( make_shared_fast<monster>( tmp ), p );
if( placed ) {
placed->on_load();
if( i.disposition == spawn_disposition::SpawnDisp_Pet ) {
placed->make_pet();
}
}
};

Expand Down
4 changes: 4 additions & 0 deletions src/map.h
Original file line number Diff line number Diff line change
Expand Up @@ -36,6 +36,7 @@
#include "type_id.h"
#include "units.h"

enum class spawn_disposition;
struct scent_block;
template <typename T> class string_id;

Expand Down Expand Up @@ -1560,6 +1561,9 @@ class map
void add_spawn( const mtype_id &type, int count, const tripoint &p,
bool friendly = false, int faction_id = -1, int mission_id = -1,
const std::string &name = "NONE" ) const;
void add_spawn( const mtype_id &type, int count, const tripoint &p,
spawn_disposition disposition, int faction_id = -1, int mission_id = -1,
const std::string &name = "NONE" ) const;
void do_vehicle_caching( int z );
// Note: in 3D mode, will actually build caches on ALL z-levels
void build_map_cache( int zlev, bool skip_lightmap = false );
Expand Down
10 changes: 9 additions & 1 deletion src/mapgen.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -6299,6 +6299,14 @@ std::vector<item *> map::put_items_from_loc( const item_group_id &loc, const tri

void map::add_spawn( const mtype_id &type, int count, const tripoint &p, bool friendly,
int faction_id, int mission_id, const std::string &name ) const
{
add_spawn( type, count, p, spawn_point::friendly_to_spawn_disposition( friendly ), faction_id,
mission_id, name );
}

void map::add_spawn( const mtype_id &type, int count, const tripoint &p,
spawn_disposition disposition,
int faction_id, int mission_id, const std::string &name ) const
{
if( p.x < 0 || p.x >= SEEX * my_MAPSIZE || p.y < 0 || p.y >= SEEY * my_MAPSIZE ) {
debugmsg( "Bad add_spawn(%s, %d, %d, %d)", type.c_str(), count, p.x, p.y );
Expand All @@ -6315,7 +6323,7 @@ void map::add_spawn( const mtype_id &type, int count, const tripoint &p, bool fr
if( MonsterGroupManager::monster_is_blacklisted( type ) ) {
return;
}
spawn_point tmp( type, count, offset, faction_id, mission_id, friendly, name );
spawn_point tmp( type, count, offset, faction_id, mission_id, disposition, name );
place_on_submap->spawns.push_back( tmp );
}

Expand Down
16 changes: 11 additions & 5 deletions src/monster.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -58,6 +58,7 @@
#include "string_formatter.h"
#include "string_id.h"
#include "string_utils.h"
#include "submap.h"
#include "text_snippets.h"
#include "translations.h"
#include "trap.h"
Expand Down Expand Up @@ -509,16 +510,16 @@ void monster::try_reproduce()

chance += 2;

// wildlife creatures that are friendly to the player will spawn friendly offspring
const bool friendly_parent = type->in_category( "WILDLIFE" ) &&
attitude_to( get_player_character() ) == Attitude::A_FRIENDLY;
// wildlife creatures that are pets of the player will spawn pet offspring
const spawn_disposition disposition = is_pet() ? spawn_disposition::SpawnDisp_Pet :
spawn_disposition::SpawnDisp_Default;
if( season_match && female && one_in( chance ) ) {
int spawn_cnt = rng( 1, type->baby_count );
if( type->baby_monster ) {
g->m.add_spawn( type->baby_monster, spawn_cnt, pos(), friendly_parent );
g->m.add_spawn( type->baby_monster, spawn_cnt, pos(), disposition );
} else {
detached_ptr<item> item_to_spawn = item::spawn( type->baby_egg, *baby_timer, spawn_cnt );
if( friendly_parent ) {
if( disposition == spawn_disposition::SpawnDisp_Pet ) {
item_to_spawn->set_flag( flag_SPAWN_FRIENDLY );
}
g->m.add_item_or_charges( pos(), std::move( item_to_spawn ), true );
Expand Down Expand Up @@ -2940,6 +2941,11 @@ void monster::make_pet()
add_effect( effect_pet, 1_turns, num_bp );
}

bool monster::is_pet() const
{
return ( friendly == -1 && has_effect( effect_pet ) );
}

bool monster::is_hallucination() const
{
return hallucination;
Expand Down
2 changes: 2 additions & 0 deletions src/monster.h
Original file line number Diff line number Diff line change
Expand Up @@ -433,6 +433,8 @@ class monster : public Creature, public location_visitable<monster>
void make_ally( const monster &z );
// makes this monster a pet of the player
void make_pet();
// check if this monster is a pet of the player
bool is_pet() const;
// Add an item to inventory
void add_item( detached_ptr<item> &&it );
// check mech power levels and modify it.
Expand Down
5 changes: 3 additions & 2 deletions src/savegame_json.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -3922,7 +3922,7 @@ void submap::store( JsonOut &jsout ) const
jsout.write( elem.pos.y );
jsout.write( elem.faction_id );
jsout.write( elem.mission_id );
jsout.write( elem.friendly );
jsout.write( elem.is_friendly() );
jsout.write( elem.name );
jsout.end_array();
}
Expand Down Expand Up @@ -4166,7 +4166,8 @@ void submap::load( JsonIn &jsin, const std::string &member_name, int version,
bool friendly = jsin.get_bool();
std::string name = jsin.get_string();
jsin.end_array();
spawn_point tmp( type, count, p, faction_id, mission_id, friendly, name );
spawn_point tmp( type, count, p, faction_id, mission_id,
spawn_point::friendly_to_spawn_disposition( friendly ), name );
spawns.push_back( tmp );
}
} else if( member_name == "vehicles" ) {
Expand Down
29 changes: 26 additions & 3 deletions src/submap.h
Original file line number Diff line number Diff line change
Expand Up @@ -19,6 +19,7 @@
#include "game_constants.h"
#include "item.h"
#include "type_id.h"
#include "monster.h"
#include "point.h"
#include "poly_serialized.h"

Expand All @@ -31,19 +32,41 @@ struct ter_t;
struct furn_t;
class vehicle;

// enum defines the initial disposition of the monster that is to be spawned
enum class spawn_disposition {
SpawnDisp_Default,
SpawnDisp_Friendly,
SpawnDisp_Pet,
};

struct spawn_point {
point pos;
int count;
mtype_id type;
int faction_id;
int mission_id;
bool friendly;
spawn_disposition disposition;
std::string name;
spawn_point( const mtype_id &T = mtype_id::NULL_ID(), int C = 0, point P = point_zero,
int FAC = -1, int MIS = -1, bool F = false,
int FAC = -1, int MIS = -1, spawn_disposition DISP = spawn_disposition::SpawnDisp_Default,
const std::string &N = "NONE" ) :
pos( P ), count( C ), type( T ), faction_id( FAC ),
mission_id( MIS ), friendly( F ), name( N ) {}
mission_id( MIS ), disposition( DISP ), name( N ) {}

// helper function to convert internal disposition into a binary bool value.
// This is required to preserve save game compatibility because submaps store/load
// their spawn_points using a boolean flag.
bool is_friendly( void ) const {
return disposition != spawn_disposition::SpawnDisp_Default;
}

// helper function to convert binary bool friendly value to internal disposition.
// This is required to preserve save game compatibility because submaps store/load
// their spawn_points using a boolean flag.
static spawn_disposition friendly_to_spawn_disposition( bool friendly ) {
return friendly ? spawn_disposition::SpawnDisp_Friendly
: spawn_disposition::SpawnDisp_Default;
}
};

template<int sx, int sy>
Expand Down

0 comments on commit b86d593

Please sign in to comment.