Skip to content

Commit

Permalink
Allow black/whitelisting scenarios
Browse files Browse the repository at this point in the history
I-am-Erk wanted this for reworking 'Classic Zombies', and making it a
more refined experience.
  • Loading branch information
anothersimulacrum committed Jan 31, 2020
1 parent 7a0ad59 commit 9f8653d
Show file tree
Hide file tree
Showing 5 changed files with 105 additions and 0 deletions.
18 changes: 18 additions & 0 deletions doc/MODDING.md
Original file line number Diff line number Diff line change
Expand Up @@ -181,6 +181,24 @@ Finally, if you're trying to blacklist something that spawns inside of cities, y
}
]
````

### Disabling certain scenarios
The `SCENARIO_BLACKLIST` can be either a blacklist or a whitelist.
When it is a whitelist, it blacklists all scenarios but the ones specified.
No more than one blacklist can be specified at one time - this is in all json loaded for a particular game (all mods + base game), not just your specific mod.
The format is as follows
```json
[
{
"type": "SCENARIO_BLACKLIST",
"subtype": "whitelist",
"scenarios": [ "largebuilding" ]
}
]
```
Valid values for `subtype` are `whitelist` and `blacklist`.
Scenarios is an array of the scenario ids that you want to blacklist of whitelist.

## Important note on json files

The following characters: `[ { , } ] : "` are *very* important when adding or modifying JSON files. This means a single missing `,` or `[` or `}` can be the difference between a working file and a hanging game at startup.
Expand Down
1 change: 1 addition & 0 deletions src/init.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -213,6 +213,7 @@ void DynamicDataLoader::initialize()
add( "speech", &load_speech );
add( "ammunition_type", &ammunition_type::load_ammunition_type );
add( "scenario", &scenario::load_scenario );
add( "SCENARIO_BLACKLIST", &scen_blacklist::load_scen_blacklist );
add( "start_location", &start_location::load_location );
add( "skill_boost", &skill_boost::load_boost );
add( "enchantment", &enchantment::load_enchantment );
Expand Down
3 changes: 3 additions & 0 deletions src/newcharacter.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -1862,6 +1862,9 @@ tab_direction set_scenario( const catacurses::window &w, avatar &u, points_left
sorted_scens.clear();
auto &wopts = world_generator->active_world->WORLD_OPTIONS;
for( const auto &scen : scenario::get_all() ) {
if( scen.scen_is_blacklisted() ) {
continue;
}
if( !lcmatch( scen.gender_appropriate_name( u.male ), filterstring ) ) {
continue;
}
Expand Down
71 changes: 71 additions & 0 deletions src/scenario.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -33,6 +33,8 @@ bool string_id<scenario>::is_valid() const
return all_scenarios.is_valid( *this );
}

scen_blacklist sc_blacklist;

scenario::scenario()
: id( "" ), _name_male( no_translation( "null" ) ),
_name_female( no_translation( "null" ) ),
Expand Down Expand Up @@ -129,6 +131,7 @@ void scenario::check_definitions()
for( const auto &scen : all_scenarios.get_all() ) {
scen.check_definition();
}
sc_blacklist.finalize();
}

static void check_traits( const std::set<trait_id> &traits, const string_id<scenario> &ident )
Expand Down Expand Up @@ -221,6 +224,74 @@ start_location_id scenario::random_start_location() const
return random_entry( _allowed_locs );
}

bool scenario::scen_is_blacklisted() const
{
return sc_blacklist.scenarios.count( id ) != 0;
}

void scen_blacklist::load_scen_blacklist( const JsonObject &jo, const std::string &src )
{
sc_blacklist.load( jo, src );
}

void scen_blacklist::load( const JsonObject &jo, const std::string & )
{
if( !scenarios.empty() ) {
jo.throw_error( "Attempted to load scenario blacklist with an existing scenario blacklist" );
}

std::string bl_stype;
if( jo.has_string( "subtype" ) ) {
bl_stype = jo.get_string( "subtype" );
} else {
jo.throw_error( "Missing mandatory member subtype" );
}

if( bl_stype == "whitelist" ) {
whitelist = true;
} else if( bl_stype == "blacklist" ) {
whitelist = false;
} else {
jo.throw_error( "Blacklist subtype is not a valid subtype." );
}

if( !jo.has_array( "scenarios" ) ) {
jo.throw_error( "Missing mandatory member scenarios" );
}

for( const std::string &line : jo.get_array( "scenarios" ) ) {
scenarios.emplace( line );
}
}

void scen_blacklist::finalize()
{
std::vector<string_id<scenario>> all_scenarios;
for( const scenario &scen : scenario::get_all() ) {
all_scenarios.emplace_back( scen.ident() );
}
for( const string_id<scenario> &sc : sc_blacklist.scenarios ) {
if( std::find( all_scenarios.begin(), all_scenarios.end(), sc ) == all_scenarios.end() ) {
debugmsg( "Scenario blacklist contains invalid scenario" );
}
}

if( sc_blacklist.whitelist ) {
std::set<string_id<scenario>> listed_scenarios = sc_blacklist.scenarios;
sc_blacklist.scenarios.clear();
for( const scenario &scen : scenario::get_all() ) {
sc_blacklist.scenarios.insert( scen.ident() );
}
for( auto i = sc_blacklist.scenarios.begin(); i != sc_blacklist.scenarios.end(); ) {
if( listed_scenarios.count( *i ) != 0 ) {
i = sc_blacklist.scenarios.erase( i );
} else {
++i;
}
}
}
}

std::vector<string_id<profession>> scenario::permitted_professions() const
{
if( !cached_permitted_professions.empty() ) {
Expand Down
12 changes: 12 additions & 0 deletions src/scenario.h
Original file line number Diff line number Diff line change
Expand Up @@ -95,6 +95,9 @@ class scenario
*/
std::string prof_count_str() const;

// Is this scenario blacklisted?
bool scen_is_blacklisted() const;

/** Such as a seasonal start, fiery start, surrounded start, etc. */
bool has_flag( const std::string &flag ) const;

Expand All @@ -107,4 +110,13 @@ class scenario

};

struct scen_blacklist {
std::set<string_id<scenario>> scenarios;
bool whitelist = false;

static void load_scen_blacklist( const JsonObject &jo, const std::string &src );
void load( const JsonObject &jo, const std::string & );
void finalize();
};

#endif

0 comments on commit 9f8653d

Please sign in to comment.