diff --git a/doc/MONSTERS.md b/doc/MONSTERS.md index 72a1c22ade0b1..6cc1c105a2106 100644 --- a/doc/MONSTERS.md +++ b/doc/MONSTERS.md @@ -545,8 +545,9 @@ The monster's reproduction cycle, if any. Supports: Field | Description --- | --- -`baby_monster` | (string, optional) the id of the monster spawned on reproduction for monsters who give live births. You must declare either this or `baby_egg` for reproduction to work. -`baby_egg` | (string, optional) The id of the egg type to spawn for egg-laying monsters. You must declare either this or "baby_monster" for reproduction to work. (see [JSON_INFO.md](JSON_INFO.md#comestibles) `rot_spawn`) +`baby_monster` | (string, optional) the id of the monster spawned on reproduction for monsters who give live births. You must declare either this, `baby_monster_group` or `baby_egg` for reproduction to work. +`baby_monster_group` | (string, optional) the id of the monstergroup spawned on reproduction for monsters who give live births. You must declare either this, `baby_monster`, or `baby_egg` for reproduction to work. +`baby_egg` | (string, optional) The id of the egg type to spawn for egg-laying monsters. You must declare either this, `baby_monster_group` or `baby_monster` for reproduction to work. (see [JSON_INFO.md](JSON_INFO.md#comestibles) `rot_spawn`) `baby_count` | (int) Number of new creatures or eggs to spawn on reproduction. `baby_timer` | (int) Number of days between reproduction events. diff --git a/src/monmove.cpp b/src/monmove.cpp index a279b139762c7..e0925364d2a9d 100644 --- a/src/monmove.cpp +++ b/src/monmove.cpp @@ -34,6 +34,7 @@ #include "memory_fast.h" #include "messages.h" #include "monfaction.h" +#include "mongroup.h" #include "monster_oracle.h" #include "mtype.h" #include "npc.h" @@ -415,7 +416,8 @@ void monster::anger_cub_threatened( monster_plan &mon_plan ) } for( monster &tmp : g->all_monsters() ) { - if( type->baby_monster == tmp.type->id ) { + if( type->baby_monster == tmp.type->id || + MonsterGroupManager::IsMonsterInGroup( type->baby_monster_group, tmp.type->id ) ) { // baby nearby; is the player too close? mon_plan.dist = tmp.rate_target( *mon_plan.target, mon_plan.dist, mon_plan.smart_planning ); if( mon_plan.dist <= 3 ) { diff --git a/src/monster.cpp b/src/monster.cpp index 8ade126638dbb..5da1331f05f43 100644 --- a/src/monster.cpp +++ b/src/monster.cpp @@ -607,6 +607,13 @@ void monster::try_reproduce() int spawn_cnt = rng( 1, type->baby_count ); if( type->baby_monster ) { here.add_spawn( type->baby_monster, spawn_cnt, pos_bub(), friendly ); + } else if( type->baby_monster_group ) { + std::vector babies = MonsterGroupManager::GetResultFromGroup( + type->baby_monster_group, &spawn_cnt, + nullptr, false, nullptr, true ); + for( const MonsterGroupResult &mgr : babies ) { + here.add_spawn( mgr.name, spawn_cnt * mgr.pack_size, pos_bub(), friendly ); + } } else { const item egg( type->baby_egg, *baby_timer ); for( int i = 0; i < spawn_cnt; i++ ) { diff --git a/src/monstergenerator.cpp b/src/monstergenerator.cpp index 9eea7bebce6c8..1304e222d97c3 100644 --- a/src/monstergenerator.cpp +++ b/src/monstergenerator.cpp @@ -1190,6 +1190,7 @@ void mtype::load( const JsonObject &jo, const std::string &src ) } optional( repro, was_loaded, "baby_monster", baby_monster, string_id_reader<::mtype> {}, mtype_id::NULL_ID() ); + optional( repro, was_loaded, "baby_monster_group", baby_monster_group, mongroup_id::NULL_ID() ); optional( repro, was_loaded, "baby_egg", baby_egg, string_id_reader<::itype> {}, itype_id::NULL_ID() ); reproduces = true; @@ -1762,16 +1763,26 @@ void MonsterGenerator::check_monster_definitions() const debugmsg( "Number of children (%d) is invalid for %s", mon.baby_count, mon.id.c_str() ); } - if( !mon.baby_monster && mon.baby_egg.is_null() ) { - debugmsg( "No baby or egg defined for monster %s", mon.id.c_str() ); + if( !mon.baby_monster && mon.baby_egg.is_null() && !mon.baby_monster_group ) { + debugmsg( "No baby, baby group, or egg defined for monster %s", mon.id.c_str() ); } if( mon.baby_monster && !mon.baby_egg.is_null() ) { debugmsg( "Both an egg and a live birth baby are defined for %s", mon.id.c_str() ); } + if( mon.baby_monster_group && !mon.baby_egg.is_null() ) { + debugmsg( "Both an egg and a baby group are defined for %s", mon.id.c_str() ); + } + if( mon.baby_monster && mon.baby_monster_group ) { + debugmsg( "Both baby and a baby group are defined for %s", mon.id.c_str() ); + } if( !mon.baby_monster.is_valid() ) { debugmsg( "baby_monster %s of monster %s is not a valid monster id", mon.baby_monster.c_str(), mon.id.c_str() ); } + if( !mon.baby_monster_group.is_valid() ) { + debugmsg( "baby_monster_group %s of monster %s is not a valid monster group id", + mon.baby_monster.c_str(), mon.id.c_str() ); + } if( !item::type_is_defined( mon.baby_egg ) ) { debugmsg( "item_id %s of monster %s is not a valid item id", mon.baby_egg.c_str(), mon.id.c_str() ); diff --git a/src/mtype.cpp b/src/mtype.cpp index 13088f2acb1ac..3464bb37ccedb 100644 --- a/src/mtype.cpp +++ b/src/mtype.cpp @@ -308,6 +308,7 @@ mtype::mtype() reproduces = false; baby_count = -1; baby_monster = mtype_id::NULL_ID(); + baby_monster_group = mongroup_id::NULL_ID(); baby_egg = itype_id::NULL_ID(); biosignatures = false; diff --git a/src/mtype.h b/src/mtype.h index 6014204a7dda6..61bb9c1aa70e8 100644 --- a/src/mtype.h +++ b/src/mtype.h @@ -312,6 +312,7 @@ struct mtype { mtype_id fungalize_into; // mtype_id this monster fungalize into mtype_id baby_monster; + mongroup_id baby_monster_group; itype_id baby_egg; // Monster biosignature variables itype_id biosig_item;