Skip to content

Commit

Permalink
feat: spawn active items on mapgen (#4283)
Browse files Browse the repository at this point in the history
* Documentation

* Give `place_item` an `active` argument.

Now you can spawn grenades active in houses, or you know, atomic lights

* `item_groups` can spawn `active` items

* revert active grenades on roof

* fix: msvc does not like auto return types

* fix: move pointer explicitly

Co-authored-by: joveeater <joveasarus@gmail.com>

* style(autofix.ci): automated formatting

* docs(mapgen): class fields

Co-authored-by: Coolthulhu <Coolthulhu@gmail.com>

* docs(item_spawn): be more explicit, add examples

Co-authored-by: Coolthulhu <Coolthulhu@gmail.com>

---------

Co-authored-by: KheirFerrum <102964889+KheirFerrum@users.noreply.github.com>
Co-authored-by: joveeater <joveasarus@gmail.com>
Co-authored-by: autofix-ci[bot] <114827586+autofix-ci[bot]@users.noreply.github.com>
Co-authored-by: Coolthulhu <Coolthulhu@gmail.com>
  • Loading branch information
5 people committed Mar 7, 2024
1 parent e8ceea9 commit 4e22dfd
Show file tree
Hide file tree
Showing 6 changed files with 85 additions and 15 deletions.
28 changes: 28 additions & 0 deletions doc/src/content/docs/en/mod/json/reference/items/item_spawn.md
Original file line number Diff line number Diff line change
Expand Up @@ -94,6 +94,7 @@ item(s):
"charges": <number>|<array>,
"charges-min": <number>,
"charges-max": <number>,
"active": "<bool>"
"contents-item": "<item-id>" (can be a string or an array of strings),
"contents-group": "<group-id>" (can be a string or an array of strings),
"ammo-item": "<ammo-item-id>",
Expand All @@ -111,6 +112,33 @@ item. This allows water, that contains a book, that contains a steel frame, that
or ammo/magazine capacity. Setting max too high will decrease it to maximum capacity. Not setting
min will set it to 0 when max is set.

`active`: If true, activates the item on spawn. Note that this _does not work_ for itemgroups, only
individual items _within_ itemgroups.

#### `active` Usage example

```json
[
{
"id": "test_grenade",
"type": "item_group",
"subtype": "collection",
"items": [{ "item": "grenade_act", "prob": 100, "active": true }]
},
{
"type": "mapgen",
"method": "json",
"om_terrain": "shelter_roof",
"weight": 100,
"object": {
// ...
"place_items": [{ "item": "test_grenade", "x": 12, "y": 12, "chance": 100, "repeat": 1 }],
"place_item": [{ "item": "grenade_act", "x": 15, "y": 15, "chance": 100, "active": true }]
}
}
]
```

```json
"damage-min": 0,
"damage-max": 3,
Expand Down
17 changes: 17 additions & 0 deletions src/item_factory.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -3121,6 +3121,22 @@ bool Item_factory::load_string( std::vector<std::string> &vec, const JsonObject
return result;
}

namespace
{
auto load_active( std::vector<ItemFn> &xs, const JsonObject &obj ) -> bool
{
const bool result = obj.has_bool( "active" ) && obj.get_bool( "active" );
if( result ) {
xs.emplace_back( []( detached_ptr<item> &&it ) {
it->activate();
return std::move( it );
} );
}
return result;
}

} // namespace

void Item_factory::add_entry( Item_group &ig, const JsonObject &obj )
{
std::unique_ptr<Item_group> gptr;
Expand Down Expand Up @@ -3164,6 +3180,7 @@ void Item_factory::add_entry( Item_group &ig, const JsonObject &obj )
use_modifier |= load_sub_ref( modifier.ammo, obj, "ammo", ig );
use_modifier |= load_sub_ref( modifier.container, obj, "container", ig );
use_modifier |= load_sub_ref( modifier.contents, obj, "contents", ig );
use_modifier |= load_active( modifier.postprocess_fns, obj );

std::vector<std::string> custom_flags;
use_modifier |= load_string( custom_flags, obj, "custom-flags" );
Expand Down
4 changes: 4 additions & 0 deletions src/item_group.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -374,6 +374,10 @@ detached_ptr<item> Item_modifier::modify( detached_ptr<item> &&new_item ) const
for( const flag_id &flag : custom_flags ) {
new_item->set_flag( flag );
}

for( const auto &fn : postprocess_fns ) {
new_item = fn( std::move( new_item ) );
}
return std::move( new_item );
}

Expand Down
8 changes: 8 additions & 0 deletions src/item_group.h
Original file line number Diff line number Diff line change
Expand Up @@ -144,6 +144,9 @@ class Item_spawn_data
/** probability, used by the parent object. */
int probability;
};

using ItemFn = std::function < detached_ptr<item> ( detached_ptr<item> &&it ) >;

/**
* Creates a single item, but can change various aspects
* of the created item.
Expand Down Expand Up @@ -186,6 +189,11 @@ class Item_modifier
*/
std::vector<flag_id> custom_flags;

/**
* Custom functions to be applied to the item after its creation.
*/
std::vector<ItemFn> postprocess_fns;

Item_modifier();
Item_modifier( Item_modifier && ) = default;

Expand Down
7 changes: 4 additions & 3 deletions src/map.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -4303,6 +4303,10 @@ std::vector<detached_ptr<item>> map::i_clear( const tripoint &p )
detached_ptr<item> map::spawn_an_item( const tripoint &p, detached_ptr<item> &&new_item,
const int charges, const int damlevel )
{
if( one_in( 3 ) && new_item->has_flag( flag_VARSIZE ) ) {
new_item->set_flag( flag_FIT );
}

if( charges && new_item->charges > 0 ) {
//let's fail silently if we specify charges for an item that doesn't support it
new_item->charges = charges;
Expand Down Expand Up @@ -4364,9 +4368,6 @@ void map::spawn_item( const tripoint &p, const itype_id &type_id,
for( size_t i = 0; i < quantity; i++ ) {
// spawn the item
detached_ptr<item> new_item = item::spawn( type_id, birthday );
if( one_in( 3 ) && new_item->has_flag( flag_VARSIZE ) ) {
new_item->set_flag( flag_FIT );
}

spawn_an_item( p, std::move( new_item ), charges, damlevel );
}
Expand Down
36 changes: 24 additions & 12 deletions src/mapgen.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -2164,24 +2164,21 @@ class jmapgen_vehicle : public jmapgen_piece
type.check( oter_name, parameters );
}
};
/**
* Place a specific item.
* "item": id of item type to spawn.
* "chance": chance of spawning it (1 = always, otherwise one_in(chance)).
* "amount": amount of items to spawn.
* "repeat": number of times to apply this piece
*/

/// Place a specific item.
class jmapgen_spawn_item : public jmapgen_piece
{
public:
mapgen_value<itype_id> type;
jmapgen_int amount;
jmapgen_int chance;
mapgen_value<itype_id> type; //< id of item type to spawn.
jmapgen_int amount; //< amount of items to spawn.
jmapgen_int chance; //< chance of spawning it (1 = always, otherwise one_in(chance)).
bool activate_on_spawn; //< whether to activate the item on spawn.
jmapgen_spawn_item( const JsonObject &jsi ) :
type( jsi.get_member( "item" ) )
, amount( jsi, "amount", 1, 1 )
, chance( jsi, "chance", 100, 100 ) {
repeat = jmapgen_int( jsi, "repeat", 1, 1 );
activate_on_spawn = jsi.get_bool( "active", false );
}
void apply( const mapgendata &dat, const jmapgen_int &x, const jmapgen_int &y
) const override {
Expand All @@ -2193,13 +2190,28 @@ class jmapgen_spawn_item : public jmapgen_piece
// individual items here.
chosen_id = item_controller->migrate_id( chosen_id );

if( item_is_blacklisted( chosen_id ) ) {
return;
}

const int c = chance.get();

// 100% chance = exactly 1 item, otherwise scale by item spawn rate.
const float spawn_rate = get_option<float>( "ITEM_SPAWNRATE" );
int spawn_count = ( c == 100 ) ? 1 : roll_remainder( c * spawn_rate / 100.0f );
const int spawn_count = ( c == 100 ) ? 1 : roll_remainder( c * spawn_rate / 100.0f );
const int quantity = amount.get();

const point p = { x.get(), y.get() };

for( int i = 0; i < spawn_count; i++ ) {
dat.m.spawn_item( point( x.get(), y.get() ), chosen_id, amount.get() );
for( int j = 0; j < quantity; j++ ) {
detached_ptr<item> new_item = item::spawn( chosen_id, calendar::start_of_cataclysm );
if( activate_on_spawn ) {
new_item->activate();
}

dat.m.spawn_an_item( p, std::move( new_item ), 0, 0 );
}
}
}

Expand Down

0 comments on commit 4e22dfd

Please sign in to comment.