Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Allow placing vehicle zones at mapgen #56768

Merged
merged 3 commits into from
Apr 24, 2022
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
6 changes: 6 additions & 0 deletions data/json/vehicles/factional.json
Original file line number Diff line number Diff line change
Expand Up @@ -60,6 +60,12 @@
{ "x": -3, "y": 1, "chance": 20, "item_groups": [ "car_kit" ] },
{ "x": -3, "y": 0, "chance": 18, "item_groups": [ "fuel_gasoline" ] },
{ "x": -2, "y": 1, "chance": 13, "items": [ "ax" ] }
],
"zones": [
{ "type": "LOOT_UNSORTED", "x": -2, "y": 0 },
{ "type": "LOOT_UNSORTED", "x": -2, "y": 1 },
{ "type": "LOOT_AMMO", "x": -3, "y": 0 },
{ "type": "LOOT_GUNS", "x": -3, "y": 1 }
]
}
]
102 changes: 65 additions & 37 deletions src/clzones.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -684,10 +684,10 @@ void zone_manager::cache_avatar_location()
}
}

void zone_manager::cache_vzones()
void zone_manager::cache_vzones( map *pmap )
{
vzone_cache.clear();
map &here = get_map();
map &here = pmap == nullptr ? get_map() : *pmap;
auto vzones = here.get_vehicle_zones( here.get_abs_sub().z() );
for( zone_data *elem : vzones ) {
if( !elem->get_enabled() ) {
Expand Down Expand Up @@ -1076,38 +1076,40 @@ const zone_data *zone_manager::get_bottom_zone(
// If you are passing new_zone from a non-const iterator, be prepared for a move! This
// may break some iterators like map iterators if you are less specific!
void zone_manager::create_vehicle_loot_zone( vehicle &vehicle, const point &mount_point,
zone_data &new_zone )
zone_data &new_zone, map *pmap )
{
//create a vehicle loot zone
new_zone.set_is_vehicle( true );
auto nz = vehicle.loot_zones.emplace( mount_point, new_zone );
map &here = get_map();
map &here = pmap == nullptr ? get_map() : *pmap;
here.register_vehicle_zone( &vehicle, here.get_abs_sub().z() );
vehicle.zones_dirty = false;
added_vzones.push_back( &nz->second );
cache_vzones();
cache_vzones( pmap );
}

void zone_manager::add( const std::string &name, const zone_type_id &type, const faction_id &fac,
const bool invert, const bool enabled, const tripoint &start,
const tripoint &end, const shared_ptr_fast<zone_options> &options, const bool personal )
const tripoint &end, const shared_ptr_fast<zone_options> &options, const bool personal,
bool silent, map *pmap )
{
map &here = get_map();
map &here = pmap == nullptr ? get_map() : *pmap;
zone_data new_zone = zone_data( name, type, fac, invert, enabled, start, end, options, personal );
// only non personal zones can be vehicle zones
if( !personal ) {
//the start is a vehicle tile with cargo space
if( const cata::optional<vpart_reference> vp = here.veh_at( here.getlocal(
start ) ).part_with_feature( "CARGO", false ) ) {
optional_vpart_position const vp = here.veh_at( here.getlocal( start ) );
if( vp and vp->vehicle().get_owner() == fac and vp.part_with_feature( "CARGO", false ) ) {
// TODO:Allow for loot zones on vehicles to be larger than 1x1
if( start == end && query_yn( _( "Bind this zone to the cargo part here?" ) ) ) {
if( start == end &&
( silent || query_yn( _( "Bind this zone to the cargo part here?" ) ) ) ) {
// TODO: refactor zone options for proper validation code
if( type == zone_type_FARM_PLOT || type == zone_type_CONSTRUCTION_BLUEPRINT ) {
if( !silent &&
( type == zone_type_FARM_PLOT || type == zone_type_CONSTRUCTION_BLUEPRINT ) ) {
popup( _( "You cannot add that type of zone to a vehicle." ), PF_NONE );
return;
}

create_vehicle_loot_zone( vp->vehicle(), vp->mount(), new_zone );
create_vehicle_loot_zone( vp->vehicle(), vp->mount(), new_zone, pmap );
return;
}
}
Expand Down Expand Up @@ -1182,36 +1184,50 @@ void zone_manager::swap( zone_data &a, zone_data &b )
std::swap( a, b );
}

namespace
{
void _rotate_zone( map &target_map, zone_data &zone, int turns )
{
const point dim( SEEX * 2, SEEY * 2 );
const tripoint a_start( 0, 0, target_map.get_abs_sub().z() );
const tripoint a_end( SEEX * 2 - 1, SEEY * 2 - 1, a_start.z );
const tripoint z_start = target_map.getlocal( zone.get_start_point() );
const tripoint z_end = target_map.getlocal( zone.get_end_point() );
const inclusive_cuboid<tripoint> boundary( a_start, a_end );
if( boundary.contains( z_start ) and boundary.contains( z_end ) ) {
// don't rotate centered squares
if( z_start.x == z_start.y && z_end.x == z_end.y &&
z_start.x + z_end.x == a_end.x ) {
return;
}
point z_l_start = z_start.xy().rotate( turns, dim );
point z_l_end = z_end.xy().rotate( turns, dim );
tripoint_abs_ms first =
target_map.getglobal( tripoint( std::min( z_l_start.x, z_l_end.x ),
std::min( z_l_start.y, z_l_end.y ),
z_start.z ) );
tripoint_abs_ms second =
target_map.getglobal( tripoint( std::max( z_l_start.x, z_l_end.x ),
std::max( z_l_start.y, z_l_end.y ),
z_end.z ) );
zone.set_position( std::make_pair( first.raw(), second.raw() ), false );
}
}

} // namespace

void zone_manager::rotate_zones( map &target_map, const int turns )
{
if( turns == 0 ) {
return;
}
const point dim( SEEX * 2, SEEY * 2 );

for( zone_data &zone : zones ) {
const tripoint a_start( 0, 0, target_map.get_abs_sub().z() );
const tripoint a_end( SEEX * 2 - 1, SEEY * 2 - 1, a_start.z );
const tripoint z_start = target_map.getlocal( zone.get_start_point() );
const tripoint z_end = target_map.getlocal( zone.get_end_point() );
const inclusive_cuboid<tripoint> boundary( a_start, a_end );
if( boundary.contains( z_start ) and boundary.contains( z_end ) ) {
// don't rotate centered squares
if( z_start.x == z_start.y && z_end.x == z_end.y &&
z_start.x + z_end.x == a_end.x ) {
continue;
}
point z_l_start = z_start.xy().rotate( turns, dim );
point z_l_end = z_end.xy().rotate( turns, dim );
tripoint_abs_ms first =
target_map.getglobal( tripoint( std::min( z_l_start.x, z_l_end.x ),
std::min( z_l_start.y, z_l_end.y ),
z_start.z ) );
tripoint_abs_ms second =
target_map.getglobal( tripoint( std::max( z_l_start.x, z_l_end.x ),
std::max( z_l_start.y, z_l_end.y ),
z_end.z ) );
zone.set_position( std::make_pair( first.raw(), second.raw() ), false );
}
_rotate_zone( target_map, zone, turns );
}

for( zone_data *zone : target_map.get_vehicle_zones( target_map.get_abs_sub().z() ) ) {
_rotate_zone( target_map, *zone, turns );
}
}

Expand Down Expand Up @@ -1459,3 +1475,15 @@ void zone_manager::revert_vzones()
remove( *zone );
}
}

void mapgen_place_zone( tripoint const &start, tripoint const &end, zone_type_id const &type,
faction_id const &fac, std::string const &name, std::string const &filter,
map *pmap )
{
zone_manager &mgr = zone_manager::get_manager();
auto options = zone_options::create( type );
if( type == zone_type_LOOT_CUSTOM or type == zone_type_LOOT_ITEM_GROUP ) {
dynamic_cast<loot_options *>( &*options )->set_mark( filter );
}
mgr.add( name, type, fac, false, true, start, end, options, false, true, pmap );
}
11 changes: 8 additions & 3 deletions src/clzones.h
Original file line number Diff line number Diff line change
Expand Up @@ -432,10 +432,11 @@ class zone_manager
void add( const std::string &name, const zone_type_id &type, const faction_id &faction,
bool invert, bool enabled,
const tripoint &start, const tripoint &end,
const shared_ptr_fast<zone_options> &options = nullptr, const bool personal = false );
const shared_ptr_fast<zone_options> &options = nullptr, const bool personal = false,
bool silent = false, map *pmap = nullptr );
const zone_data *get_zone_at( const tripoint_abs_ms &where, const zone_type_id &type ) const;
void create_vehicle_loot_zone( class vehicle &vehicle, const point &mount_point,
zone_data &new_zone );
zone_data &new_zone, map *pmap = nullptr );

bool remove( zone_data &zone );

Expand All @@ -451,7 +452,7 @@ class zone_manager
void cache_data( bool update_avatar = true );
void reset_disabled();
void cache_avatar_location();
void cache_vzones();
void cache_vzones( map *pmap = nullptr );
bool has( const zone_type_id &type, const tripoint_abs_ms &where,
const faction_id &fac = your_fac ) const;
bool has_near( const zone_type_id &type, const tripoint_abs_ms &where,
Expand Down Expand Up @@ -500,4 +501,8 @@ class zone_manager
void deserialize( const JsonValue &jv );
};

void mapgen_place_zone( tripoint const &start, tripoint const &end, zone_type_id const &type,
faction_id const &fac = your_fac, std::string const &name = {},
std::string const &filter = {}, map *pmap = nullptr );

#endif // CATA_SRC_CLZONES_H
15 changes: 5 additions & 10 deletions src/mapgen.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -173,9 +173,6 @@ static const trait_id trait_NPC_STATIC_NPC( "NPC_STATIC_NPC" );

static const vproto_id vehicle_prototype_shopping_cart( "shopping_cart" );

static const zone_type_id zone_type_LOOT_CUSTOM( "LOOT_CUSTOM" );
static const zone_type_id zone_type_LOOT_ITEM_GROUP( "LOOT_ITEM_GROUP" );

#define dbg(x) DebugLog((x),D_MAP_GEN) << __FILE__ << ":" << __LINE__ << ": "

static constexpr int MON_RADIUS = 3;
Expand Down Expand Up @@ -2959,19 +2956,16 @@ class jmapgen_zone : public jmapgen_piece
filter = jsi.get_string( "filter" );
}
}
mapgen_phase phase() const override {
return mapgen_phase::zones;
}
void apply( const mapgendata &dat, const jmapgen_int &x, const jmapgen_int &y,
const std::string &/*context*/ ) const override {
zone_type_id chosen_zone_type = zone_type.get( dat );
faction_id chosen_faction = faction.get( dat );
zone_manager &mgr = zone_manager::get_manager();
const tripoint start = dat.m.getabs( tripoint( x.val, y.val, dat.m.get_abs_sub().z() ) );
const tripoint end = dat.m.getabs( tripoint( x.valmax, y.valmax, dat.m.get_abs_sub().z() ) );
auto options = zone_options::create( chosen_zone_type );
if( chosen_zone_type == zone_type_LOOT_CUSTOM or
chosen_zone_type == zone_type_LOOT_ITEM_GROUP ) {
dynamic_cast<loot_options *>( &*options )->set_mark( filter );
}
mgr.add( name, chosen_zone_type, chosen_faction, false, true, start, end, options );
mapgen_place_zone( start, end, chosen_zone_type, chosen_faction, name, filter, &dat.m );
}

void check( const std::string &oter_name, const mapgen_parameters &parameters,
Expand Down Expand Up @@ -6442,6 +6436,7 @@ vehicle *map::add_vehicle( const vproto_id &type, const tripoint &p, const units
add_vehicle_to_cache( placed_vehicle );

rebuild_vehicle_level_caches();
placed_vehicle->place_zones( *this );
//debugmsg ("grid[%d]->vehicles.size=%d veh.parts.size=%d", nonant, grid[nonant]->vehicles.size(),veh.parts.size());
}
return placed_vehicle;
Expand Down
1 change: 1 addition & 0 deletions src/mapgen.h
Original file line number Diff line number Diff line change
Expand Up @@ -102,6 +102,7 @@ enum class mapgen_phase {
nested_mapgen,
transform,
faction_ownership,
zones,
last
};

Expand Down
15 changes: 15 additions & 0 deletions src/veh_type.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -1193,6 +1193,21 @@ void vehicle_prototype::load( const JsonObject &jo )
}
vproto.item_spawns.push_back( std::move( next_spawn ) );
}

for( JsonObject jzi : jo.get_array( "zones" ) ) {
zone_type_id zone_type( jzi.get_member( "type" ).get_string() );
std::string name;
std::string filter;
point pt( jzi.get_member( "x" ).get_int(), jzi.get_member( "y" ).get_int() );

if( jzi.has_string( "name" ) ) {
name = jzi.get_string( "name" );
}
if( jzi.has_string( "filter" ) ) {
filter = jzi.get_string( "filter" );
}
vproto.zone_defs.emplace_back( zone_def{ zone_type, name, filter, pt } );
}
}

void vehicle_prototype::reset()
Expand Down
8 changes: 8 additions & 0 deletions src/veh_type.h
Original file line number Diff line number Diff line change
Expand Up @@ -504,6 +504,13 @@ struct vehicle_prototype {
itype_id fuel = itype_id::NULL_ID();
};

struct zone_def {
zone_type_id zone_type;
std::string name;
std::string filter;
point pt;
};

vehicle_prototype();
vehicle_prototype( vehicle_prototype && ) noexcept;
~vehicle_prototype();
Expand All @@ -513,6 +520,7 @@ struct vehicle_prototype {
translation name;
std::vector<part_def> parts;
std::vector<vehicle_item_spawn> item_spawns;
std::vector<zone_def> zone_defs;

std::unique_ptr<vehicle> blueprint;

Expand Down
11 changes: 11 additions & 0 deletions src/vehicle.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -5538,6 +5538,17 @@ void vehicle::place_spawn_items()
}
}

void vehicle::place_zones( map &pmap ) const
{
if( !type.is_valid() || !has_owner() ) {
return;
}
for( vehicle_prototype::zone_def const &d : type->zone_defs ) {
tripoint const pt = pmap.getabs( tripoint( pos + d.pt, pmap.get_abs_sub().z() ) );
mapgen_place_zone( pt, pt, d.zone_type, get_owner(), d.name, d.filter, &pmap );
}
}

void vehicle::gain_moves()
{
fuel_used_last_turn.clear();
Expand Down
2 changes: 2 additions & 0 deletions src/vehicle.h
Original file line number Diff line number Diff line change
Expand Up @@ -1572,6 +1572,8 @@ class vehicle
// Generates starting items in the car, should only be called when placed on the map
void place_spawn_items();

void place_zones( map &pmap ) const;

void gain_moves();

// if its a summoned vehicle - its gotta disappear at some point, return true if destroyed
Expand Down