From fddcf72f4f64bb75ca0f58c51687fd719b23bc23 Mon Sep 17 00:00:00 2001 From: Mark Langsdorf Date: Sat, 2 Nov 2019 17:57:55 -0500 Subject: [PATCH 1/9] NPCs: clamp thirst and hunger levels to 0 when rating food NPCs with negative amounts of hunger or thirst (which is valid) will do weird things when rating food, like refusing to eat despite being very hungry because they don't want to waste the negative quench of some foods. Clamp the amount of quench or nutrition required when rating food to the higher of the NPC's quench/hunger or 0. --- src/npcmove.cpp | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/src/npcmove.cpp b/src/npcmove.cpp index 836cae3ee9873..4e31910ee8eef 100644 --- a/src/npcmove.cpp +++ b/src/npcmove.cpp @@ -3690,8 +3690,8 @@ bool npc::consume_food() { float best_weight = 0.0f; int index = -1; - int want_hunger = get_hunger(); - int want_quench = get_thirst(); + int want_hunger = std::max( 0, get_hunger() ); + int want_quench = std::max( 0, get_thirst() ); invslice slice = inv.slice(); for( size_t i = 0; i < slice.size(); i++ ) { const item &it = slice[i]->front(); From 6193fdc07e03ede71863c0d802fa00bd73edb830 Mon Sep 17 00:00:00 2001 From: Henrik Bergvin Date: Sun, 3 Nov 2019 10:12:36 +0100 Subject: [PATCH 2/9] make charges optional --- src/recipe.cpp | 6 +++--- src/recipe.h | 2 +- 2 files changed, 4 insertions(+), 4 deletions(-) diff --git a/src/recipe.cpp b/src/recipe.cpp index 7c2de1668e91c..ec4cb798b4945 100644 --- a/src/recipe.cpp +++ b/src/recipe.cpp @@ -323,7 +323,7 @@ std::string recipe::get_consistency_error() const return "defines invalid result"; } - if( charges >= 0 && !item::count_by_charges( result_ ) ) { + if( charges && !item::count_by_charges( result_ ) ) { return "specifies charges but result is not counted by charges"; } @@ -366,8 +366,8 @@ std::string recipe::get_consistency_error() const item recipe::create_result() const { item newit( result_, calendar::turn, item::default_charges_tag{} ); - if( charges >= 0 ) { - newit.charges = charges; + if( charges ) { + newit.charges = *charges; } if( !newit.craft_has_charges() ) { diff --git a/src/recipe.h b/src/recipe.h index 9c83647e6eea4..13bb02b783106 100644 --- a/src/recipe.h +++ b/src/recipe.h @@ -169,7 +169,7 @@ class recipe std::set flags; /** If set (zero or positive) set charges of output result for items counted by charges */ - int charges = -1; + cata::optional charges; // maximum achievable time reduction, as percentage of the original time. // if zero then the recipe has no batch crafting time reduction. From b58eb8b6166c3285c6ceec50e4da2ce3883b1093 Mon Sep 17 00:00:00 2001 From: anothersimulacrum Date: Sun, 3 Nov 2019 16:35:15 +0000 Subject: [PATCH 3/9] Allow Large and Huge players to move on underbrush PR 35060 changed it so that large and huge creatures could not move through tight passages, using the THIN_OBSTACLE flag. This is incorrect, because the THIN_OBSTACLE flag is widely used on things such as underbrush, that large and huge creatures should be able to move on. --- .../terrain-windows.json | 35 ++++++++++++++++--- doc/JSON_FLAGS.md | 1 + src/game.cpp | 2 +- src/mapdata.cpp | 3 +- src/mapdata.h | 1 + src/monmove.cpp | 2 +- 6 files changed, 37 insertions(+), 7 deletions(-) diff --git a/data/json/furniture_and_terrain/terrain-windows.json b/data/json/furniture_and_terrain/terrain-windows.json index 5158db842bdd4..e3396f46b8c47 100644 --- a/data/json/furniture_and_terrain/terrain-windows.json +++ b/data/json/furniture_and_terrain/terrain-windows.json @@ -136,7 +136,16 @@ "move_cost": 4, "coverage": 60, "roof": "t_flat_roof", - "flags": [ "TRANSPARENT", "FLAMMABLE", "NOITEM", "OPENCLOSE_INSIDE", "MOUNTABLE", "CONNECT_TO_WALL", "THIN_OBSTACLE" ], + "flags": [ + "TRANSPARENT", + "FLAMMABLE", + "NOITEM", + "OPENCLOSE_INSIDE", + "MOUNTABLE", + "CONNECT_TO_WALL", + "THIN_OBSTACLE", + "SMALL_PASSAGE" + ], "close": "t_window_no_curtains", "bash": { "str_min": 3, @@ -211,7 +220,16 @@ "move_cost": 4, "coverage": 60, "roof": "t_flat_roof", - "flags": [ "TRANSPARENT", "FLAMMABLE", "NOITEM", "OPENCLOSE_INSIDE", "MOUNTABLE", "CONNECT_TO_WALL", "THIN_OBSTACLE" ], + "flags": [ + "TRANSPARENT", + "FLAMMABLE", + "NOITEM", + "OPENCLOSE_INSIDE", + "MOUNTABLE", + "CONNECT_TO_WALL", + "THIN_OBSTACLE", + "SMALL_PASSAGE" + ], "examine_action": "curtains", "close": "t_window_domestic", "bash": { @@ -337,7 +355,16 @@ "symbol": "0", "color": "yellow", "move_cost": 4, - "flags": [ "TRANSPARENT", "NOITEM", "FLAMMABLE", "SUPPORTS_ROOF", "MOUNTABLE", "CONNECT_TO_WALL", "THIN_OBSTACLE" ], + "flags": [ + "TRANSPARENT", + "NOITEM", + "FLAMMABLE", + "SUPPORTS_ROOF", + "MOUNTABLE", + "CONNECT_TO_WALL", + "THIN_OBSTACLE", + "SMALL_PASSAGE" + ], "bash": { "str_min": 10, "str_max": 70, @@ -371,7 +398,7 @@ "ter_set": "t_window_empty", "items": [ { "item": "glass_shard", "count": [ 6, 10 ] } ] }, - "flags": [ "TRANSPARENT", "SHARP", "FLAMMABLE", "NOITEM", "MOUNTABLE", "CONNECT_TO_WALL" ] + "flags": [ "TRANSPARENT", "SHARP", "FLAMMABLE", "NOITEM", "MOUNTABLE", "CONNECT_TO_WALL", "SMALL_PASSAGE" ] }, { "type": "terrain", diff --git a/doc/JSON_FLAGS.md b/doc/JSON_FLAGS.md index cf86d5145b23c..83e0f1a88cf7e 100644 --- a/doc/JSON_FLAGS.md +++ b/doc/JSON_FLAGS.md @@ -576,6 +576,7 @@ List of known flags, used in both `terrain.json` and `furniture.json`. - ```SHARP``` May do minor damage to players/monsters passing through it. - ```SHORT``` Feature too short to collide with vehicle protrusions. (mirrors, blades). - ```SIGN``` Show written message on examine. +- ```SMALL_PASSAGE``` This terrain or furniture is too small for large or huge creatures to pass through. - ```SUPPORTS_ROOF``` Used as a boundary for roof construction. - ```SUPPRESS_SMOKE``` Prevents smoke from fires; used by ventilated wood stoves, etc. - ```SWIMMABLE``` Player and monsters can swim through it. diff --git a/src/game.cpp b/src/game.cpp index a2f3100d0ea82..faa255d4d0a00 100644 --- a/src/game.cpp +++ b/src/game.cpp @@ -9045,7 +9045,7 @@ std::vector game::get_dangerous_tile( const tripoint &dest_loc ) co bool game::walk_move( const tripoint &dest_loc ) { - if( m.has_flag_ter( "THIN_OBSTACLE", dest_loc ) ) { + if( m.has_flag_ter( TFLAG_SMALL_PASSAGE, dest_loc ) ) { if( u.get_size() > MS_MEDIUM ) { add_msg( m_warning, _( "You can't fit there." ) ); return false; // character too large to fit through a tight passage diff --git a/src/mapdata.cpp b/src/mapdata.cpp index 779f14e50db5f..a914eebb2c4cb 100644 --- a/src/mapdata.cpp +++ b/src/mapdata.cpp @@ -166,7 +166,8 @@ static const std::unordered_map ter_bitflags_map = { { "FLAT", TFLAG_FLAT }, // This tile is flat. { "RAMP", TFLAG_RAMP }, // Can be used to move up a z-level { "RAIL", TFLAG_RAIL }, // Rail tile (used heavily) - { "THIN_OBSTACLE", TFLAG_THIN_OBSTACLE }, // A tight passage, not usable by large or huge critters + { "THIN_OBSTACLE", TFLAG_THIN_OBSTACLE }, // Passable by players and monsters. Vehicles destroy it. + { "SMALL_PASSAGE", TFLAG_SMALL_PASSAGE } // A small passage, that large or huge things cannot pass through } }; diff --git a/src/mapdata.h b/src/mapdata.h index cd500f0d8db15..f897dd0304428 100644 --- a/src/mapdata.h +++ b/src/mapdata.h @@ -194,6 +194,7 @@ enum ter_bitflags : int { TFLAG_FLAT, TFLAG_RAIL, TFLAG_THIN_OBSTACLE, + TFLAG_SMALL_PASSAGE, NUM_TERFLAGS }; diff --git a/src/monmove.cpp b/src/monmove.cpp index da6b58de44056..22de0ed8cea10 100644 --- a/src/monmove.cpp +++ b/src/monmove.cpp @@ -129,7 +129,7 @@ bool monster::can_move_to( const tripoint &p ) const return false; } - if( get_size() > MS_MEDIUM && g->m.has_flag_ter( TFLAG_THIN_OBSTACLE, p ) ) { + if( get_size() > MS_MEDIUM && g->m.has_flag_ter( TFLAG_SMALL_PASSAGE, p ) ) { return false; // if a large critter, can't move through tight passages } From b9e987e8e0ee35ed6e07e6faeccb32927aafa52b Mon Sep 17 00:00:00 2001 From: Henrik Bergvin Date: Sun, 3 Nov 2019 18:12:39 +0100 Subject: [PATCH 4/9] change disp_name to be able to return a capitalized name --- src/activity_item_handling.cpp | 2 +- src/character.cpp | 6 +++--- src/character.h | 7 +++++-- src/creature.h | 3 ++- src/monster.cpp | 6 +++--- src/monster.h | 2 +- 6 files changed, 15 insertions(+), 11 deletions(-) diff --git a/src/activity_item_handling.cpp b/src/activity_item_handling.cpp index de6041d4dd095..33b0bf58376da 100644 --- a/src/activity_item_handling.cpp +++ b/src/activity_item_handling.cpp @@ -2273,7 +2273,7 @@ void activity_on_turn_move_loot( player_activity &act, player &p ) } // If we got here without restarting the activity, it means we're done - add_msg( m_info, _( "%s sorted out every item possible." ), p.disp_name() ); + add_msg( m_info, _( "%s sorted out every item possible." ), p.disp_name( false, true ) ); if( p.is_npc() ) { npc *guy = dynamic_cast( &p ); guy->revert_after_activity(); diff --git a/src/character.cpp b/src/character.cpp index 60ade1cc56826..a0a1b11699bca 100644 --- a/src/character.cpp +++ b/src/character.cpp @@ -338,16 +338,16 @@ int Character::get_fat_to_hp() const return mut_fat_hp * ( get_bmi() - character_weight_category::normal ); } -std::string Character::disp_name( bool possessive ) const +std::string Character::disp_name( bool possessive, bool capitalize_first ) const { if( !possessive ) { if( is_player() ) { - return pgettext( "not possessive", "you" ); + return pgettext( "not possessive", capitalize_first ? "You" : "you" ); } return name; } else { if( is_player() ) { - return _( "your" ); + return capitalize_first ? _( "Your" ) : _( "your" ); } return string_format( _( "%s's" ), name ); } diff --git a/src/character.h b/src/character.h index f79a6db777ed7..b78d48e1e92b3 100644 --- a/src/character.h +++ b/src/character.h @@ -309,8 +309,11 @@ class Character : public Creature, public visitable /**Get bonus to max_hp from excess stored fat*/ int get_fat_to_hp() const; - /** Returns either "you" or the player's name */ - std::string disp_name( bool possessive = false ) const override; + /** Returns either "you" or the player's name. capitalize_first assumes + that the character's name is already upper case and uses it only for + possessive "your" and "you" + **/ + std::string disp_name( bool possessive = false, bool capitalize_first = false ) const override; /** Returns the name of the player's outer layer, e.g. "armor plates" */ std::string skin_name() const override; diff --git a/src/creature.h b/src/creature.h index f46f0e0e6be21..d704cee54f85d 100644 --- a/src/creature.h +++ b/src/creature.h @@ -72,7 +72,8 @@ class Creature // Like disp_name, but without any "the" virtual std::string get_name() const = 0; - virtual std::string disp_name( bool possessive = false ) const = 0; // displayname for Creature + virtual std::string disp_name( bool possessive = false, + bool capitalize_first = false ) const = 0; // displayname for Creature virtual std::string skin_name() const = 0; // name of outer layer, e.g. "armor plates" virtual std::vector get_grammatical_genders() const; diff --git a/src/monster.cpp b/src/monster.cpp index d091dc7533cc3..3e18acd9c4971 100644 --- a/src/monster.cpp +++ b/src/monster.cpp @@ -532,12 +532,12 @@ std::string monster::name_with_armor() const return ret; } -std::string monster::disp_name( bool possessive ) const +std::string monster::disp_name( bool possessive, bool capitalize_first ) const { if( !possessive ) { - return string_format( _( "the %s" ), name() ); + return string_format( capitalize_first ? _( "The %s" ) : _( "the %s" ), name() ); } else { - return string_format( _( "the %s's" ), name() ); + return string_format( capitalize_first ? _( "The %s's" ) : _( "the %s's" ), name() ); } } diff --git a/src/monster.h b/src/monster.h index 8dcb15704106a..43e456a1060b7 100644 --- a/src/monster.h +++ b/src/monster.h @@ -121,7 +121,7 @@ class monster : public Creature std::string name( unsigned int quantity = 1 ) const; // Returns the monster's formal name std::string name_with_armor() const; // Name, with whatever our armor is called // the creature-class versions of the above - std::string disp_name( bool possessive = false ) const override; + std::string disp_name( bool possessive = false, bool capitalize_first = false ) const override; std::string skin_name() const override; void get_HP_Bar( nc_color &color, std::string &text ) const; std::pair get_attitude() const; From ae0a09ef5114a7035254824291bb1a4eee72056e Mon Sep 17 00:00:00 2001 From: Curtis Merrill Date: Sun, 3 Nov 2019 18:37:16 -0500 Subject: [PATCH 5/9] [magiclysm] clairvoyance spells (#35247) * make spell field age modifiable * make clairvoyant field (seen always) * create clairvoyance spells --- data/mods/Magiclysm/Spells/earthshaper.json | 21 +++++++++++++++ data/mods/Magiclysm/Spells/technomancer.json | 27 +++++++++++++++++++ data/mods/Magiclysm/field.json | 15 +++++++++++ .../mods/Magiclysm/itemgroups/spellbooks.json | 2 ++ data/mods/Magiclysm/items/spell_scrolls.json | 16 +++++++++++ src/lightmap.cpp | 4 +++ src/magic.cpp | 2 +- 7 files changed, 86 insertions(+), 1 deletion(-) create mode 100644 data/mods/Magiclysm/field.json diff --git a/data/mods/Magiclysm/Spells/earthshaper.json b/data/mods/Magiclysm/Spells/earthshaper.json index febb4f466549c..3b1f2c549aa96 100644 --- a/data/mods/Magiclysm/Spells/earthshaper.json +++ b/data/mods/Magiclysm/Spells/earthshaper.json @@ -272,5 +272,26 @@ "energy_source": "MANA", "flags": [ "VERBAL", "SOMATIC", "LOUD" ], "extra_effects": [ { "id": "lava_bomb_shrapnel" }, { "id": "lava_bomb_heat" }, { "id": "lava_bomb_ter" } ] + }, + { + "id": "clairvoyance", + "type": "SPELL", + "name": "Clairvoyance", + "description": "You close your eyes and the earth surrenders its secrets to you.", + "effect": "target_attack", + "valid_targets": [ "ally", "hostile", "ground" ], + "flags": [ "SOMATIC", "VERBAL", "IGNORE_WALLS" ], + "max_level": 20, + "min_aoe": 4, + "max_aoe": 13, + "aoe_increment": 0.5, + "spell_class": "EARTHSHAPER", + "base_casting_time": 350, + "base_energy_cost": 750, + "energy_source": "MANA", + "difficulty": 4, + "field_id": "fd_clairvoyant", + "min_field_intensity": 1, + "max_field_intensity": 1 } ] diff --git a/data/mods/Magiclysm/Spells/technomancer.json b/data/mods/Magiclysm/Spells/technomancer.json index b2731db621439..a8e4091c56657 100644 --- a/data/mods/Magiclysm/Spells/technomancer.json +++ b/data/mods/Magiclysm/Spells/technomancer.json @@ -320,5 +320,32 @@ "min_duration": 3000, "max_duration": 6000, "duration_increment": 200 + }, + { + "type": "SPELL", + "name": "X-ray Vision", + "id": "x-ray", + "description": "You fire a cone of X-rays that magically allow you to see that area for a short time.", + "valid_targets": [ "hostile", "ground", "ally" ], + "flags": [ "CONCENTRATE", "IGNORE_WALLS" ], + "effect": "cone_attack", + "field_id": "fd_clairvoyant", + "min_field_intensity": 1, + "max_field_intensity": 1, + "difficulty": 6, + "min_range": 5, + "max_range": 20, + "range_increment": 0.75, + "max_level": 20, + "min_aoe": 15, + "max_aoe": 60, + "aoe_increment": 1.5, + "min_duration": 0, + "max_duration": 900, + "duration_increment": 45, + "base_casting_time": 175, + "base_energy_cost": 550, + "energy_source": "BIONIC", + "spell_class": "TECHNOMANCER" } ] diff --git a/data/mods/Magiclysm/field.json b/data/mods/Magiclysm/field.json new file mode 100644 index 0000000000000..2cd801043c44f --- /dev/null +++ b/data/mods/Magiclysm/field.json @@ -0,0 +1,15 @@ +[ + { + "id": "fd_clairvoyant", + "type": "field_type", + "intensity_levels": [ { "name": "clairvoyance", "sym": "8", "dangerous": false } ], + "decay_amount_factor": 5, + "gas_absorption_factor": 12, + "dirty_transparency_cache": true, + "outdoor_age_speedup": "0 turns", + "priority": 8, + "half_life": "1 seconds", + "phase": "solid", + "display_field": false + } +] diff --git a/data/mods/Magiclysm/itemgroups/spellbooks.json b/data/mods/Magiclysm/itemgroups/spellbooks.json index 74e0dc4d40062..481f973a214ff 100644 --- a/data/mods/Magiclysm/itemgroups/spellbooks.json +++ b/data/mods/Magiclysm/itemgroups/spellbooks.json @@ -24,6 +24,7 @@ [ "spell_scroll_taze", 25 ], [ "spell_scroll_laze", 25 ], [ "spell_scroll_lightning_blast", 20 ], + [ "spell_scroll_x-ray", 30 ], [ "spell_scroll_necrotic_gaze", 50 ] ] }, @@ -41,6 +42,7 @@ [ "spell_scroll_druid_naturebow1", 20 ], [ "spell_scroll_seismic_stomp", 20 ], [ "spell_scroll_eshaper_shardspray", 25 ], + [ "spell_scroll_clairvoyance", 30 ], [ "spell_scroll_point_flare", 50 ], [ "spell_scroll_ice_spike", 50 ], [ "spell_scroll_burning_hands", 50 ], diff --git a/data/mods/Magiclysm/items/spell_scrolls.json b/data/mods/Magiclysm/items/spell_scrolls.json index 7a37215b548e6..60f149842224f 100644 --- a/data/mods/Magiclysm/items/spell_scrolls.json +++ b/data/mods/Magiclysm/items/spell_scrolls.json @@ -618,6 +618,22 @@ "description": "You summon a gift of the earth which will purify water. Greater levels yield greater numbers of seeds.", "use_action": { "type": "learn_spell", "spells": [ "purify_seed" ] } }, + { + "type": "GENERIC", + "copy-from": "spell_scroll", + "id": "spell_scroll_x-ray", + "name": "Scroll of X-ray Vision", + "description": "You fire a cone of X-rays that magically allow you to see that area for a short time.", + "use_action": { "type": "learn_spell", "spells": [ "x-ray" ] } + }, + { + "type": "GENERIC", + "copy-from": "spell_scroll", + "id": "spell_scroll_clairvoyance", + "name": "Scroll of Clairvoyance", + "description": "You close your eyes and the earth surrenders its secrets to you.", + "use_action": { "type": "learn_spell", "spells": [ "clairvoyance" ] } + }, { "type": "GENERIC", "copy-from": "spell_scroll", diff --git a/src/lightmap.cpp b/src/lightmap.cpp index bb09c161ba37d..401f61eee600d 100644 --- a/src/lightmap.cpp +++ b/src/lightmap.cpp @@ -578,6 +578,10 @@ lit_level map::apparent_light_at( const tripoint &p, const visibility_variables if( cache.u_clairvoyance > 0 && dist <= cache.u_clairvoyance ) { return LL_BRIGHT; } + const field_type_str_id fd_clairvoyant( "fd_clairvoyant" ); + if( fd_clairvoyant.is_valid() && field_at( p ).find_field( fd_clairvoyant ) ) { + return LL_BRIGHT; + } const auto &map_cache = get_cache_ref( p.z ); const apparent_light_info a = apparent_light_helper( map_cache, p ); diff --git a/src/magic.cpp b/src/magic.cpp index 51523d5c993e3..336aab79f4bd6 100644 --- a/src/magic.cpp +++ b/src/magic.cpp @@ -851,7 +851,7 @@ void spell::create_field( const tripoint &at ) const if( field ) { field->set_field_intensity( field->get_field_intensity() + intensity ); } else { - g->m.add_field( at, *type->field, intensity ); + g->m.add_field( at, *type->field, intensity, -duration_turns() ); } } } From 3c4cd0141ed6378aea3e3f0030f9d37865f4d4fa Mon Sep 17 00:00:00 2001 From: snipercup <50166150+snipercup@users.noreply.github.com> Date: Mon, 4 Nov 2019 00:37:56 +0100 Subject: [PATCH 6/9] Balance copper tubing recipe (#35284) --- data/json/recipes/recipe_others.json | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/data/json/recipes/recipe_others.json b/data/json/recipes/recipe_others.json index 4ca23c61478da..8ad6bdbdfa985 100644 --- a/data/json/recipes/recipe_others.json +++ b/data/json/recipes/recipe_others.json @@ -3445,7 +3445,7 @@ "autolearn": true, "qualities": [ { "id": "ANVIL", "level": 3 }, { "id": "HAMMER", "level": 3 }, { "id": "CHISEL", "level": 3 } ], "tools": [ [ [ "tongs", -1 ] ], [ [ "swage", -1 ] ], [ [ "forge", 50 ], [ "oxy_torch", 10 ] ] ], - "components": [ [ [ "scrap_copper", 2 ], [ "copper", 200 ] ] ] + "components": [ [ [ "scrap_copper", 7 ], [ "copper", 175 ] ] ] }, { "type": "recipe", From 4b1bf2947ede7593444c90b95d7be18b8355b9d3 Mon Sep 17 00:00:00 2001 From: snipercup <50166150+snipercup@users.noreply.github.com> Date: Mon, 4 Nov 2019 00:38:16 +0100 Subject: [PATCH 7/9] add-bp_57mm-recipe (#35232) --- data/json/recipes/ammo/pistol.json | 16 ++++++++++++++++ data/json/requirements/ammo.json | 6 ++++++ 2 files changed, 22 insertions(+) diff --git a/data/json/recipes/ammo/pistol.json b/data/json/recipes/ammo/pistol.json index 36f73f9b34772..d4c9dee7dea06 100644 --- a/data/json/recipes/ammo/pistol.json +++ b/data/json/recipes/ammo/pistol.json @@ -287,6 +287,22 @@ "using": [ [ "bullet_forming", 2 ], [ "ammo_bullet", 2 ], [ "ammo_380", 1 ] ], "components": [ [ [ "chem_black_powder", 3 ] ], [ [ "copper", 1 ] ] ] }, + { + "result": "bp_57mm", + "type": "recipe", + "category": "CC_AMMO", + "subcategory": "CSC_AMMO_PISTOL", + "skill_used": "fabrication", + "difficulty": 3, + "skills_required": [ "gun", 1 ], + "time": "2 m", + "batch_time_factors": [ 60, 5 ], + "book_learn": [ [ "manual_pistol", 2 ], [ "manual_smg", 2 ], [ "recipe_bullets", 3 ] ], + "charges": 1, + "reversible": true, + "using": [ [ "bullet_forming", 2 ], [ "ammo_bullet", 2 ], [ "ammo_57", 1 ] ], + "components": [ [ [ "chem_black_powder", 3 ] ], [ [ "copper", 1 ] ] ] + }, { "result": "36navy", "type": "recipe", diff --git a/data/json/requirements/ammo.json b/data/json/requirements/ammo.json index 3afe2e157ee04..d0bb994e9bf3f 100644 --- a/data/json/requirements/ammo.json +++ b/data/json/requirements/ammo.json @@ -22,6 +22,12 @@ "//": "Components required for 380 ammo", "components": [ [ [ "380_casing", 1 ] ], [ [ "smpistol_primer", 1 ] ] ] }, + { + "id": "ammo_57", + "type": "requirement", + "//": "Components required for 57 ammo", + "components": [ [ [ "57mm_casing", 1 ] ], [ [ "smpistol_primer", 1 ] ] ] + }, { "id": "ammo_shot", "type": "requirement", From b79b9276c76e0421519d10ff6d2bc55dc9ac7823 Mon Sep 17 00:00:00 2001 From: Mark Langsdorf Date: Sun, 3 Nov 2019 17:41:05 -0600 Subject: [PATCH 8/9] NPCs: further buy, sell, and trade fixes (#35282) * NPCs: don't set charges when buying/selling items Don't set charges when creating items to trade with NPCs. This should prevent the errors on loading caused by items that do not have charges having charges. * NPCs: fix buying bionics installations and removals from TC doctor The TC doctor can theoretically install or remove CBMs for a huge amount of money, but he expects to be paid in e-cash which is ridiculous. Rework the logic so he takes barter goods like a normal person. --- src/game_inventory.cpp | 4 ---- src/npctalk.cpp | 4 ++-- src/npctalk_funcs.cpp | 10 ++++------ 3 files changed, 6 insertions(+), 12 deletions(-) diff --git a/src/game_inventory.cpp b/src/game_inventory.cpp index ed22347f1a8ed..62d869ab9ba79 100644 --- a/src/game_inventory.cpp +++ b/src/game_inventory.cpp @@ -1534,8 +1534,6 @@ static item_location autodoc_internal( player &u, player &patient, } } - } else { - hint = string_format( _( "Money available: %s" ), format_money( u.cash ) ); } if( uninstall ) { @@ -1748,8 +1746,6 @@ class bionic_install_surgeon_preset : public inventory_selector_preset return _( "Superior version installed." ); } else if( pa.is_npc() && !bid->npc_usable ) { return _( "CBM is not compatible with patient." ); - } else if( it->price( true ) * 2 > p.cash ) { - return format_money( it->price( true ) * 2 ); } return std::string(); diff --git a/src/npctalk.cpp b/src/npctalk.cpp index c83a3d914d933..4c402af5cc3b6 100644 --- a/src/npctalk.cpp +++ b/src/npctalk.cpp @@ -1957,7 +1957,7 @@ void talk_effect_fun_t::set_u_buy_item( const std::string &item_name, int cost, return; } if( container_name.empty() ) { - item new_item = item( item_name, calendar::turn, 1 ); + item new_item = item( item_name, calendar::turn ); if( new_item.count_by_charges() ) { new_item.mod_charges( count - 1 ); u.i_add( new_item ); @@ -1993,7 +1993,7 @@ void talk_effect_fun_t::set_u_sell_item( const std::string &item_name, int cost, function = [item_name, cost, count]( const dialogue & d ) { npc &p = *d.beta; player &u = *d.alpha; - item old_item = item( item_name, calendar::turn, 1 ); + item old_item = item( item_name, calendar::turn ); if( u.has_charges( item_name, count ) ) { u.use_charges( item_name, count ); } else if( u.has_amount( item_name, count ) ) { diff --git a/src/npctalk_funcs.cpp b/src/npctalk_funcs.cpp index 0e32d55db5e02..92bb26e80346e 100644 --- a/src/npctalk_funcs.cpp +++ b/src/npctalk_funcs.cpp @@ -450,11 +450,12 @@ void talk_function::bionic_install( npc &p ) const itype &it = *tmp->type; signed int price = tmp->price( true ) * 2; + if( !npc_trading::pay_npc( p, price ) ) { + return; + } //Makes the doctor awesome at installing but not perfect if( g->u.can_install_bionics( it, p, false, 20 ) ) { - g->u.cash -= price; - p.cash += price; bionic.remove_item(); g->u.install_bionics( it, p, false, 20 ); } @@ -499,15 +500,12 @@ void talk_function::bionic_remove( npc &p ) } else { price = 50000; } - if( price > g->u.cash ) { - popup( _( "You can't afford the procedure…" ) ); + if( !npc_trading::pay_npc( p, price ) ) { return; } //Makes the doctor awesome at installing but not perfect if( g->u.can_uninstall_bionic( bionic_id( bionic_types[bionic_index] ), p, false ) ) { - g->u.cash -= price; - p.cash += price; g->u.amount_of( bionic_types[bionic_index] ); // ??? this does nothing, it just queries the count g->u.uninstall_bionic( bionic_id( bionic_types[bionic_index] ), p, false ); } From 33fcb6ef1430040008edc910cc3b3029dbec1fa3 Mon Sep 17 00:00:00 2001 From: Curtis Merrill Date: Sun, 3 Nov 2019 18:44:11 -0500 Subject: [PATCH 9/9] jsonizes zones into item_category (#35176) * add zones to item categories * move zones from hardcode to JSON --- data/json/item_category.json | 20 +++++++++++++ src/clzones.cpp | 58 ++++-------------------------------- src/item_category.cpp | 6 ++++ src/item_category.h | 4 +++ 4 files changed, 36 insertions(+), 52 deletions(-) diff --git a/data/json/item_category.json b/data/json/item_category.json index 5b5a89b8bdd8c..4354b2c3efe9c 100644 --- a/data/json/item_category.json +++ b/data/json/item_category.json @@ -3,54 +3,63 @@ "id": "guns", "type": "ITEM_CATEGORY", "name": "GUNS", + "zone": "LOOT_GUNS", "sort_rank": -23 }, { "id": "magazines", "type": "ITEM_CATEGORY", "name": "MAGAZINES", + "zone": "LOOT_MAGAZINES", "sort_rank": -22 }, { "id": "ammo", "type": "ITEM_CATEGORY", "name": "AMMO", + "zone": "LOOT_AMMO", "sort_rank": -21 }, { "id": "weapons", "type": "ITEM_CATEGORY", "name": "WEAPONS", + "zone": "LOOT_WEAPONS", "sort_rank": -20 }, { "id": "tools", "type": "ITEM_CATEGORY", "name": "TOOLS", + "zone": "LOOT_TOOLS", "sort_rank": -19 }, { "id": "clothing", "type": "ITEM_CATEGORY", "name": "CLOTHING", + "//": "zone is hardcoded due to filthy clothing", "sort_rank": -18 }, { "id": "food", "type": "ITEM_CATEGORY", "name": "FOOD", + "//": "zone is hardcoded", "sort_rank": -17 }, { "id": "drugs", "type": "ITEM_CATEGORY", "name": "DRUGS", + "zone": "LOOT_DRUGS", "sort_rank": -16 }, { "id": "books", "type": "ITEM_CATEGORY", "name": "BOOKS", + "zone": "LOOT_BOOKS", "sort_rank": -15 }, { @@ -63,66 +72,77 @@ "id": "mods", "type": "ITEM_CATEGORY", "name": "MODS", + "zone": "LOOT_MODS", "sort_rank": -13 }, { "id": "mutagen", "type": "ITEM_CATEGORY", "name": "MUTAGENS", + "zone": "LOOT_MUTAGENS", "sort_rank": -12 }, { "id": "bionics", "type": "ITEM_CATEGORY", "name": "BIONICS", + "zone": "LOOT_BIONICS", "sort_rank": -12 }, { "id": "veh_parts", "type": "ITEM_CATEGORY", "name": "VEHICLE PARTS", + "zone": "LOOT_VEHICLE_PARTS", "sort_rank": -10 }, { "id": "other", "type": "ITEM_CATEGORY", "name": "OTHER", + "zone": "LOOT_OTHER", "sort_rank": -9 }, { "id": "fuel", "type": "ITEM_CATEGORY", "name": "FUEL", + "zone": "LOOT_FUEL", "sort_rank": -8 }, { "id": "seeds", "type": "ITEM_CATEGORY", "name": "SEEDS", + "zone": "LOOT_SEEDS", "sort_rank": -7 }, { "id": "chems", "type": "ITEM_CATEGORY", "name": "CHEMICAL STUFF", + "zone": "LOOT_CHEMICAL", "sort_rank": 5 }, { "id": "spare_parts", "type": "ITEM_CATEGORY", "name": "SPARE PARTS", + "zone": "LOOT_SPARE_PARTS", "sort_rank": 8 }, { "id": "artifacts", "type": "ITEM_CATEGORY", "name": "ARTIFACTS", + "zone": "LOOT_ARTIFACTS", "sort_rank": 10 }, { "id": "armor", "type": "ITEM_CATEGORY", "name": "ARMOR", + "//": "zone is hardcoded due to filthy clothing", "sort_rank": 20 }, { diff --git a/src/clzones.cpp b/src/clzones.cpp index 74e24a32df5a7..2bba218fe1f05 100644 --- a/src/clzones.cpp +++ b/src/clzones.cpp @@ -827,7 +827,8 @@ cata::optional zone_manager::get_nearest( const zone_type_id &type, co zone_type_id zone_manager::get_near_zone_type_for_item( const item &it, const tripoint &where, int range ) const { - auto cat = it.get_category(); + const item_category &cat = it.get_category(); + if( has_near( zone_type_id( "LOOT_CUSTOM" ), where, range ) ) { for( const auto elem : get_near( zone_type_id( "LOOT_CUSTOM" ), where, range, &it ) ) { ( void )elem; @@ -845,6 +846,10 @@ zone_type_id zone_manager::get_near_zone_type_for_item( const item &it, } } + if( cat.zone() ) { + return *cat.zone(); + } + if( cat.get_id() == "food" ) { const bool preserves = it.is_food_container() && it.type->container->preserves; const auto &it_food = it.is_food_container() ? it.contents.front() : it; @@ -865,63 +870,12 @@ zone_type_id zone_manager::get_near_zone_type_for_item( const item &it, return zone_type_id( "LOOT_FOOD" ); } - if( cat.get_id() == "guns" ) { - return zone_type_id( "LOOT_GUNS" ); - } - if( cat.get_id() == "magazines" ) { - return zone_type_id( "LOOT_MAGAZINES" ); - } - if( cat.get_id() == "ammo" ) { - return zone_type_id( "LOOT_AMMO" ); - } - if( cat.get_id() == "weapons" ) { - return zone_type_id( "LOOT_WEAPONS" ); - } - if( cat.get_id() == "tools" ) { - return zone_type_id( "LOOT_TOOLS" ); - } if( cat.get_id() == "clothing" ) { if( it.is_filthy() && has_near( zone_type_id( "LOOT_FCLOTHING" ), where, range ) ) { return zone_type_id( "LOOT_FCLOTHING" ); } return zone_type_id( "LOOT_CLOTHING" ); } - if( cat.get_id() == "drugs" ) { - return zone_type_id( "LOOT_DRUGS" ); - } - if( cat.get_id() == "books" ) { - return zone_type_id( "LOOT_BOOKS" ); - } - if( cat.get_id() == "mods" ) { - return zone_type_id( "LOOT_MODS" ); - } - if( cat.get_id() == "mutagen" ) { - return zone_type_id( "LOOT_MUTAGENS" ); - } - if( cat.get_id() == "bionics" ) { - return zone_type_id( "LOOT_BIONICS" ); - } - if( cat.get_id() == "veh_parts" ) { - return zone_type_id( "LOOT_VEHICLE_PARTS" ); - } - if( cat.get_id() == "other" ) { - return zone_type_id( "LOOT_OTHER" ); - } - if( cat.get_id() == "fuel" ) { - return zone_type_id( "LOOT_FUEL" ); - } - if( cat.get_id() == "seeds" ) { - return zone_type_id( "LOOT_SEEDS" ); - } - if( cat.get_id() == "chems" ) { - return zone_type_id( "LOOT_CHEMICAL" ); - } - if( cat.get_id() == "spare_parts" ) { - return zone_type_id( "LOOT_SPARE_PARTS" ); - } - if( cat.get_id() == "artifacts" ) { - return zone_type_id( "LOOT_ARTIFACTS" ); - } if( cat.get_id() == "armor" ) { if( it.is_filthy() && has_near( zone_type_id( "LOOT_FARMOR" ), where, range ) ) { return zone_type_id( "LOOT_FARMOR" ); diff --git a/src/item_category.cpp b/src/item_category.cpp index 6c43d182e18a1..64feac313b1e0 100644 --- a/src/item_category.cpp +++ b/src/item_category.cpp @@ -29,6 +29,7 @@ void item_category::load( JsonObject &jo, const std::string & ) mandatory( jo, was_loaded, "id", id ); mandatory( jo, was_loaded, "name", name_ ); mandatory( jo, was_loaded, "sort_rank", sort_rank_ ); + optional( jo, was_loaded, "zone", zone_, cata::nullopt ); } bool item_category::operator<( const item_category &rhs ) const @@ -62,6 +63,11 @@ item_category_id item_category::get_id() const return id; } +cata::optional item_category::zone() const +{ + return zone_; +} + int item_category::sort_rank() const { return sort_rank_; diff --git a/src/item_category.h b/src/item_category.h index c1bd27134ef0f..953312c3532b2 100644 --- a/src/item_category.h +++ b/src/item_category.h @@ -4,6 +4,7 @@ #include +#include "optional.h" #include "translations.h" #include "type_id.h" @@ -24,6 +25,8 @@ class item_category /** Used to sort categories when displaying. Lower values are shown first. */ int sort_rank_ = 0; + cata::optional zone_; + public: /** Unique ID of this category, used when loading from JSON. */ item_category_id id; @@ -41,6 +44,7 @@ class item_category std::string name() const; item_category_id get_id() const; + cata::optional zone() const; int sort_rank() const; /**