From 46c9ac1c55d4acb8974359684327983b9db8afc2 Mon Sep 17 00:00:00 2001 From: John Candlebury Date: Fri, 6 Dec 2019 20:37:59 -0600 Subject: [PATCH 01/31] Leech-pod-monster family --- data/json/harvest.json | 17 ++ data/json/items/comestibles/carnivore.json | 46 +++++ data/json/items/gun/monster_gun.json | 31 +++ .../microlab/microlab_special_tiles.json | 43 ++++ data/json/monsters/power_leech.json | 188 ++++++++++++++++++ data/json/species.json | 5 + data/json/speech.json | 24 +++ src/monattack.cpp | 142 +++++++++++++ src/monattack.h | 3 + src/monster.cpp | 6 + src/monster.h | 1 + src/monstergenerator.cpp | 3 + 12 files changed, 509 insertions(+) create mode 100644 data/json/monsters/power_leech.json diff --git a/data/json/harvest.json b/data/json/harvest.json index 49512175917ee..82e6d2fc0b834 100644 --- a/data/json/harvest.json +++ b/data/json/harvest.json @@ -704,6 +704,23 @@ { "drop": "bone_tainted", "type": "bone", "mass_ratio": 0.1 } ] }, + { + "id": "flesh_plant", + "type": "harvest", + "entries": [ + { "drop": "meat_bark", "type": "flesh", "mass_ratio": 0.05 }, + { "drop": "meat_frond", "type": "flesh", "mass_ratio": 0.5 } + ] + }, + { + "id": "flesh_plant_bloom", + "type": "harvest", + "entries": [ + { "drop": "meat_bark", "type": "flesh", "mass_ratio": 0.05 }, + { "drop": "leech_flower", "type": "flesh", "mass_ratio": 0.25 }, + { "drop": "meat_frond", "type": "flesh", "mass_ratio": 0.5 } + ] + }, { "id": "biollante", "type": "harvest", diff --git a/data/json/items/comestibles/carnivore.json b/data/json/items/comestibles/carnivore.json index 46ff3c932d530..4122d49d150d8 100644 --- a/data/json/items/comestibles/carnivore.json +++ b/data/json/items/comestibles/carnivore.json @@ -932,5 +932,51 @@ "material": [ "flesh" ], "volume": "250 ml", "fun": -30 + }, + { + "id": "meat_frond", + "copy-from": "meat_tainted", + "type": "COMESTIBLE", + "name": "alien fronds", + "use_action": "POISON", + "description": "The fleshy fronds harvested from an alien plant. The tiny membranous leaves attached and rigid and gut-like stem are certainly poisonous, and yet they have a paradoxically pleasant and inviting sweet smell. Might be non-vegan.", + "fun": 15, + "stim": 3, + "vitamins": [ [ "vitA", 6 ], [ "vitC", 2 ], [ "calcium", 0 ], [ "iron", 8 ], [ "vitB", 6 ], [ "mutant_toxin", 8 ] ] + }, + { + "id": "leech_flower", + "type": "COMESTIBLE", + "comestible_type": "FOOD", + "name": "leech flower", + "color": "blue", + "weight": "10 g", + "volume": "250 ml", + "symbol": "%", + "spoils_in": "30 days", + "description": "The alien beauty of this indigo flower is betrayed by its disgustingly fleshy composition. What from afar appear to be petals are but layered membranes of transparent veiny flesh, given color by a covering of blue iridescent ichor. Even if it is certainly poisonous, it has a pleasant medicinal smell to it.", + "stim": 30, + "healthy": -10, + "fun": 15, + "use_action": { + "type": "consume_drug", + "activation_message": "Even a close smell of this alien flower feels deeply intoxicating.", + "effects": [ + { "id": "pkill3", "duration": 360 }, + { "id": "pkill2", "duration": 810 }, + { "id": "foodpoison", "duration": 810 }, + { "id": "badpoison", "duration": 3600 }, + { "id": "shakes", "duration": 810 } + ] + } + }, + { + "id": "meat_bark", + "copy-from": "meat_frond", + "type": "COMESTIBLE", + "name": "leech bark", + "name_plural": "scraps of leech bark", + "description": "Dry and though bark matter harvested from an alien plant. It is slightly translucent, and if placed against the light you can distinguish glistening blue veins running through it.", + "vitamins": [ [ "vitA", 6 ], [ "vitC", 0 ], [ "calcium", 2 ], [ "iron", 8 ], [ "vitB", 6 ], [ "mutant_toxin", 12 ] ] } ] diff --git a/data/json/items/gun/monster_gun.json b/data/json/items/gun/monster_gun.json index c8506e441fb22..02472fdf49bdf 100644 --- a/data/json/items/gun/monster_gun.json +++ b/data/json/items/gun/monster_gun.json @@ -29,5 +29,36 @@ "range": 12, "dispersion": 100, "durability": 8 + }, + { + "id": "emp_frond", + "type": "GUN", + "symbol": "%", + "color": "red", + "name": "electric alien frond", + "description": "Electricity unnaturally arcs from the tips of this alien frond.", + "material": [ "hflesh" ], + "flags": [ + "PRIMITIVE_RANGED_WEAPON", + "NEVER_JAMS", + "NONCONDUCTIVE", + "NO_REPAIR", + "WATERPROOF_GUN", + "NO_SALVAGE", + "NO_UNLOAD", + "NO_AMMO" + ], + "skill": "pistol", + "ammo_effects": [ "EMP", "LIGHTNING" ], + "ranged_damage": { "damage_type": "electric", "amount": 1 }, + "weight": "540 g", + "volume": "750ml", + "bashing": 2, + "to_hit": 1, + "reload_noise_volume": 2, + "loudness": 2, + "range": 12, + "dispersion": 150, + "durability": 8 } ] diff --git a/data/json/mapgen/microlab/microlab_special_tiles.json b/data/json/mapgen/microlab/microlab_special_tiles.json index f831fcbc02f42..67440f20304b5 100644 --- a/data/json/mapgen/microlab/microlab_special_tiles.json +++ b/data/json/mapgen/microlab/microlab_special_tiles.json @@ -117,6 +117,49 @@ "place_monsters": [ { "monster": "GROUP_LAB", "chance": 2, "x": [ 2, 21 ], "y": [ 2, 21 ], "repeat": [ 1, 5 ] } ] } }, + { + "type": "mapgen", + "om_terrain": [ [ "microlab_generic" ] ], + "method": "json", + "object": { + "fill_ter": "t_strconc_floor", + "rows": [ + " cc | c| |c c|r ", + " cc | c| u|c c|r c ", + " | h 6| k2 2u c ", + " dd |==||| ||||||6h ", + "uhd |tt|-- -----|6uku ", + "|||u ||||- uuu-||||||", + " c|ku|##|-DDd ku-|hd^= ", + " c|u ||||- k-| d = ", + " c| uku( u c-| ] ", + " uk u|-k A u-|=]== ", + "|||k |- ukuu -|kuk||", + " u TAu u ", + " kkuu k kuAc 2 ", + "||u|| uk|-uukuk -| |||", + " kk| Y|-kk Au ( u|r ", + "cc | (k uu ( uk|r ", + "cc |||||- ddd u-| |r ", + " 2 r|-ku h ku-| |r ", + "||2|||rr|-- u--((-| |||", + " ||||||uk|| || |c ", + " c 6|k k|c ", + " iccc 6| uk ", + " c 6| k||22||||| ", + " c c|c | | |cc " + ], + "palettes": [ "microlab" ], + "terrain": { "A": "t_plut_generator" }, + "item": { "u": { "item": "corpse" }, "k": { "item": "corpse" }, "T": { "item": "corpse" } }, + "monster": { + "T": { "monster": "mon_leech_blossom" }, + "k": { "monster": "mon_leech_pod_cluster" }, + "u": { "monster": "mon_leech_stalk" } + }, + "place_monsters": [ { "monster": "GROUP_LAB", "chance": 2, "x": [ 2, 21 ], "y": [ 2, 21 ], "repeat": [ 1, 5 ] } ] + } + }, { "type": "mapgen", "om_terrain": [ [ "microlab_generic" ] ], diff --git a/data/json/monsters/power_leech.json b/data/json/monsters/power_leech.json new file mode 100644 index 0000000000000..e8f79a5919e1a --- /dev/null +++ b/data/json/monsters/power_leech.json @@ -0,0 +1,188 @@ +[ + { + "id": "mon_leech_blossom", + "type": "MONSTER", + "name": "leech blossom", + "description": "A resplendent alien fern, crowned with flowers colored deep indigo. It appears to be the centerpiece of this otherworldly bloom.", + "default_faction": "nether", + "species": [ "LEECH_PLANT" ], + "volume": "92500 ml", + "weight": "40 kg", + "hp": 100, + "speed": 100, + "material": [ "flesh" ], + "symbol": "K", + "color": "light_cyan", + "aggression": 100, + "morale": 100, + "armor_bash": 15, + "vision_day": 30, + "vision_night": 30, + "luminance": 200, + "special_attacks": [ + { + "type": "gun", + "cooldown": 5, + "gun_type": "emp_frond", + "fake_skills": [ [ "gun", 3 ], [ "rifle", 3 ] ], + "ranges": [ [ 0, 12, "DEFAULT" ] ], + "description": "Lightning arcs towards you!" + }, + [ "LEECH_SPAWNER", 25 ], + [ "MON_LEECH_EVOLUTION", 40 ], + [ "PARROT", 40 ] + ], + "death_drops": { }, + "death_function": [ "NORMAL" ], + "flags": [ "SEES", "NOHEAD", "IMMOBILE", "NO_BREATHE", "QUEEN", "HARDTOSHOOT" ] + }, + { + "id": "mon_leech_stalk", + "type": "MONSTER", + "name": "leech stalk", + "description": "A resplendent and voluminous alien fern. A faint buzzing sound emanates from it, and the shadow cast by its canopy continuously glows with electric charge.", + "default_faction": "nether", + "species": [ "LEECH_PLANT" ], + "volume": "30000 ml", + "weight": "40 kg", + "hp": 40, + "speed": 100, + "material": [ "flesh" ], + "symbol": "y", + "color": "light_blue", + "aggression": 100, + "morale": 100, + "armor_bash": 15, + "vision_day": 30, + "vision_night": 30, + "luminance": 200, + "special_attacks": [ + { + "type": "gun", + "cooldown": 15, + "gun_type": "emp_frond", + "fake_skills": [ [ "gun", 2 ], [ "rifle", 2 ] ], + "ranges": [ [ 0, 12, "DEFAULT" ] ], + "description": "Lightning arcs towards you!" + }, + [ "MON_LEECH_EVOLUTION", 30 ], + [ "PARROT", 40 ] + ], + "death_drops": { }, + "death_function": [ "NORMAL" ], + "flags": [ "SEES", "NOHEAD", "ELECTRONIC", "IMMOBILE", "NO_BREATHE", "HARDTOSHOOT" ] + }, + { + "id": "mon_leech_pod_cluster", + "type": "MONSTER", + "name": "leech pod cluster", + "description": "The translucent egg pods of an alien plant, firmly attached by luminous rhizomes. You can barely distinguish a root drone floating withing a cloudy substance.", + "default_faction": "nether", + "species": [ "LEECH_PLANT" ], + "volume": "30000 ml", + "weight": "60 kg", + "hp": 40, + "speed": 100, + "material": [ "flesh" ], + "symbol": "g", + "color": "white", + "aggression": 100, + "morale": 100, + "armor_bash": 15, + "luminance": 60, + "starting_ammo": { "9mm": 100 }, + "special_attacks": [ + { + "type": "gun", + "cooldown": 15, + "gun_type": "emp_frond", + "ranges": [ [ 0, 1, "DEFAULT" ] ], + "description": "Lightning arcs towards you!" + }, + [ "LEECH_SPAWNER", 35 ] + ], + "death_drops": { }, + "death_function": [ "NORMAL" ], + "flags": [ "SEES", "NOHEAD", "IMMOBILE", "NO_BREATHE" ] + }, + { + "id": "mon_leech_root_runner", + "type": "MONSTER", + "name": "root runner", + "description": "This clump of woody vegetation hastily clambers around in a lizard-like fashion. Three translucent scale-leaves stand tall on the backside of the creature, and the thin ridges within them periodically glow through some unknown mean. Its seemingly a symbiote of the nearby alien ferns, and looks ready to defend them with its life.", + "default_faction": "nether",1 + "species": [ "LEECH_PLANT" ], + "volume": "4000 ml", + "weight": "6 kg", + "hp": 40, + "speed": 120, + "material": [ "flesh" ], + "symbol": "m", + "color": "blue", + "aggression": 100, + "morale": 100, + "melee_skill": 4, + "melee_dice": 1, + "melee_dice_sides": 2, + "armor_bash": 15, + "luminance": 60, + "vision_day": 30, + "vision_night": 10, + "melee_damage": [ { "damage_type": "electric", "amount": 4 } ], + "upgrades": { "half_life": 9999, "into": "mon_leech_stalk" }, + "special_attacks": [ + { + "type": "gun", + "cooldown": 15, + "gun_type": "emp_frond", + "fake_skills": [ [ "gun", 1 ], [ "rifle", 1 ] ], + "ranges": [ [ 0, 2, "DEFAULT" ] ], + "description": "Lightning arcs towards you!" + }, + [ "EVOLVE_KILL_STRIKE", 3 ] + ], + "death_drops": { }, + "death_function": [ "NORMAL" ], + "flags": [ "SEES", "NOHEAD", "ELECTRONIC", "NO_BREATHE", "HARDTOSHOOT" ] + }, + { + "id": "mon_leech_root_drone", + "type": "MONSTER", + "name": "root drone", + "description": "A small bulb with a beak like protuberance, skittishly roaming about under three tendril rhizomes. Dripping and glistening, it resembles a creature newly born rather than a sapling grown from seeds.", + "default_faction": "nether", + "species": [ "LEECH_PLANT" ], + "volume": "3000 ml", + "weight": "2 kg", + "hp": 40, + "speed": 80, + "material": [ "flesh" ], + "symbol": "p", + "color": "blue", + "aggression": 100, + "morale": 100, + "melee_skill": 2, + "melee_dice": 1, + "melee_dice_sides": 2, + "armor_bash": 15, + "luminance": 60, + "vision_day": 30, + "vision_night": 10, + "melee_damage": [ { "damage_type": "electric", "amount": 3 } ], + "upgrades": { "half_life": 999, "into": "mon_leech_pod_cluster" }, + "special_attacks": [ + { + "type": "gun", + "cooldown": 15, + "gun_type": "emp_frond", + "fake_skills": [ [ "gun", 1 ], [ "rifle", 1 ] ], + "ranges": [ [ 0, 2, "DEFAULT" ] ], + "description": "Lightning arcs towards you!" + }, + [ "EVOLVE_KILL_STRIKE", 6 ] + ], + "death_drops": { }, + "death_function": [ "NORMAL" ], + "flags": [ "SEES", "NOHEAD", "ELECTRONIC", "NO_BREATHE", "HARDTOSHOOT" ] + } +] diff --git a/data/json/species.json b/data/json/species.json index 7f083143a9cf0..d41a8656f33e1 100644 --- a/data/json/species.json +++ b/data/json/species.json @@ -44,6 +44,11 @@ "id": "FUNGUS", "fear_triggers": [ "HURT", "FIRE" ] }, + { + "type": "SPECIES", + "id": "LEECH_PLANT", + "fear_triggers": [ "HURT", "FIRE" ] + }, { "type": "SPECIES", "id": "INSECT", diff --git a/data/json/speech.json b/data/json/speech.json index 14f10dba4e212..fc802c9cbef10 100644 --- a/data/json/speech.json +++ b/data/json/speech.json @@ -2135,6 +2135,30 @@ "sound": "\"Police inbound. Stay where you are!\"", "volume": 15 }, + { + "type": "speech", + "speaker": "mon_leech_blossom", + "sound": "\"visceral chittering.\"", + "volume": 15 + }, + { + "type": "speech", + "speaker": "mon_leech_blossom", + "sound": "\"a clear high-pitched hum.\"", + "volume": 15 + }, + { + "type": "speech", + "speaker": "mon_leech_blossom", + "sound": "\"the hum of static electricity.\"", + "volume": 15 + }, + { + "type": "speech", + "speaker": "mon_leech_blossom", + "sound": "\"a low buzzing sound.\"", + "volume": 15 + }, { "type": "speech", "speaker": "foodperson_mask", diff --git a/src/monattack.cpp b/src/monattack.cpp index eb1cc5e891535..a9b9483701b7f 100644 --- a/src/monattack.cpp +++ b/src/monattack.cpp @@ -94,6 +94,11 @@ static const mtype_id mon_fungal_wall( "mon_fungal_wall" ); static const mtype_id mon_headless_dog_thing( "mon_headless_dog_thing" ); static const mtype_id mon_manhack( "mon_manhack" ); static const mtype_id mon_shadow( "mon_shadow" ); +static const mtype_id mon_leech_stalk( "mon_leech_stalk" ); +static const mtype_id mon_leech_blossom( "mon_leech_blossom" ); +static const mtype_id mon_leech_pod_cluster( "mon_leech_pod_cluster" ); +static const mtype_id mon_leech_root_runner( "mon_leech_root_runner" ); +static const mtype_id mon_leech_root_drone( "mon_leech_root_drone" ); static const mtype_id mon_hound_tindalos_afterimage( "mon_hound_tindalos_afterimage" ); static const mtype_id mon_triffid( "mon_triffid" ); static const mtype_id mon_zombie_gasbag_impaler( "mon_zombie_gasbag_impaler" ); @@ -111,6 +116,7 @@ static const skill_id skill_launcher( "launcher" ); static const species_id ZOMBIE( "ZOMBIE" ); static const species_id BLOB( "BLOB" ); +static const species_id LEECH_PLANT( "LEECH_PLANT" ); static const efftype_id effect_assisted( "assisted" ); static const efftype_id effect_bite( "bite" ); @@ -4720,6 +4726,142 @@ bool mattack::riotbot( monster *z ) return true; } +bool mattack::evolve_kill_strike( monster *z ) +{ + Creature *target = z->attack_target(); + if( target == nullptr || + !is_adjacent( z, target, false ) || + !z->sees( *target ) ) { + return false; + } + if( !z->can_act() ) { + return false; + } + + z->moves -= 100; + bool uncanny = target->uncanny_dodge(); + if( uncanny || dodge_check( z, target ) ) { + auto msg_type = target == &g->u ? m_warning : m_info; + target->add_msg_player_or_npc( msg_type, _( "The %s lunges at you, but you dodge!" ), + _( "The %s lunges at , but they dodge!" ), + z->name() ); + if( !uncanny ) { + target->on_dodge( z, z->type->melee_skill * 2 ); + target->add_msg_player_or_npc( msg_type, _( "The %s lunges at you, but you dodge!" ), + _( "The %s lunges at , but they dodge!" ), + z->name() ); + } + return true; + } + const std::string old_name = z->name(); + const bool could_see_z = g->u.sees( *z ); + tripoint const target_pos = target->pos(); + const std::string target_name = target->disp_name(); + damage_instance damage( z->type->melee_damage ); + damage.mult_damage( 1.33f ); + int damage_dealt = target->deal_damage( z, bp_torso, damage_instance( DT_STAB, rng( 10, 20 ), + rng( 5, 15 ) ) ).total_damage(); + if( damage_dealt > 0 ) { + auto msg_type = target == &g->u ? m_bad : m_warning; + target->add_msg_player_or_npc( msg_type, + _( "The %1$s impales yor chest for %2$d damage!" ), + _( "The %1$s impales 's chest for %2$d damage!" ), + z->name(), damage_dealt ); + } else { + target->add_msg_player_or_npc( + _( "The %1$s attempts to burrow itself into you, but is stopped by your armor!" ), + _( "The %1$s slashes at 's %2$s, but is stopped by its glances off armor!" ), + z->name() ); + return true; + } + if( target->is_dead_state() && g->is_empty( target_pos ) && + target->made_of_any( Creature::cmat_flesh ) ) { + z->allow_upgrade(); + z->try_upgrade( false ); + z->setpos( target_pos ); + const std::string upgrade_name = z->name(); + const bool can_see_z_upgrade = g->u.sees( *z ); + if( could_see_z && can_see_z_upgrade ) { + add_msg( m_warning, _( "The %1$s burrows within %2$s corpse and a %3$s emerges from the remains!" ), + old_name, + target_name, upgrade_name ); + } else if( could_see_z ) { + add_msg( m_warning, _( "The %1$s burrows within %2$s corpse!" ), old_name, target_name ); + } else if( can_see_z_upgrade ) { + add_msg( m_warning, _( "A %1$s emerges from %2$s corpse!" ), target->disp_name(), target_name ); + } + } + return true; +} + +bool mattack::leech_spawner( monster *z ) +{ + const bool u_see = g->u.sees( *z ); + std::list allies; + for( monster &candidate : g->all_monsters() ) { + if( candidate.type->in_species( LEECH_PLANT ) && !candidate.type->has_flag( MF_IMMOBILE ) ) { + allies.push_back( &candidate ); + } + } + if( allies.size() > 35 ) { + return true; + } + int monsters_spawned = rng( 1, 4 ); + const mtype_id monster_type = one_in( 3 ) ? mon_leech_root_runner : mon_leech_root_drone; + for( int i = 0; i < monsters_spawned; i++ ) { + if( monster *const new_mon = g->place_critter_around( monster_type, z->pos(), 1 ) ) { + if( u_see ) { + add_msg( m_warning, + _( "An egg pod ruptures and a %s crawls out from the remains!" ), new_mon->name() ); + } + } + } + if( one_in( 25 ) ) { + z->poly( mon_leech_stalk ); + if( u_see ) { + add_msg( m_warning, + _( "Resplendent fronds emerge from the still intact pods! " ) ); + } + } + return true; +} + +bool mattack::mon_leech_evolution( monster *z ) +{ + const bool u_see = g->u.sees( *z ); + const bool is_queen = z->type->has_flag( MF_QUEEN ); + std::list queens; + for( monster &candidate : g->all_monsters() ) { + if( candidate.type->in_species( LEECH_PLANT ) && candidate.type->has_flag( MF_QUEEN ) && + rl_dist( z->pos(), candidate.pos() ) ) { + queens.push_back( &candidate ); + } + } + if( !is_queen ) { + if( queens.empty() ) { + z->poly( mon_leech_blossom ); + z->set_hp( z->get_hp_max() ); + if( u_see ) { + add_msg( m_warning, + _( "The %s blooms into flowers!" ), z->name() ); + } + } + + } else { + if( !queens.empty() ) { + if( u_see ) { + add_msg( m_warning, + _( "The %s flowers whiter and fall!" ), z->name() ); + } + z->poly( mon_leech_stalk ); + g->m.spawn_item( z->pos(), "leech_flower", 5, 0, calendar::turn ); + + } + } + return true; +} + + bool mattack::tindalos_teleport( monster *z ) { Creature *target = z->attack_target(); diff --git a/src/monattack.h b/src/monattack.h index 2a261e58075b0..73d3735f14ae5 100644 --- a/src/monattack.h +++ b/src/monattack.h @@ -84,6 +84,9 @@ bool parrot( monster *z ); bool parrot_at_danger( monster *parrot ); bool darkman( monster *z ); bool slimespring( monster *z ); +bool evolve_kill_strike( monster *z ); +bool leech_spawner( monster *z ); +bool mon_leech_evolution( monster *z ); bool tindalos_teleport( monster *z ); bool flesh_tendril( monster *z ); bool bio_op_takedown( monster *z ); diff --git a/src/monster.cpp b/src/monster.cpp index 0c3e76417bc7f..dbb942b82e30c 100644 --- a/src/monster.cpp +++ b/src/monster.cpp @@ -317,6 +317,12 @@ int monster::get_upgrade_time() const return upgrade_time; } +// Sets time to upgrade to 0. +void monster:: allow_upgrade() +{ + upgrade_time = 0; +} + // This will disable upgrades in case max iters have been reached. // Checking for return value of -1 is necessary. int monster::next_upgrade_time() diff --git a/src/monster.h b/src/monster.h index f1e13b3ed9a17..33ca4f22c1ee8 100644 --- a/src/monster.h +++ b/src/monster.h @@ -102,6 +102,7 @@ class monster : public Creature bool can_upgrade(); void hasten_upgrade(); int get_upgrade_time() const; + void allow_upgrade(); void try_upgrade( bool pin_time ); void try_reproduce(); void try_biosignature(); diff --git a/src/monstergenerator.cpp b/src/monstergenerator.cpp index 6aebf2d8783ed..da36c4eafa5da 100644 --- a/src/monstergenerator.cpp +++ b/src/monstergenerator.cpp @@ -527,6 +527,9 @@ void MonsterGenerator::init_attack() add_hardcoded_attack( "PARROT_AT_DANGER", mattack::parrot_at_danger ); add_hardcoded_attack( "DARKMAN", mattack::darkman ); add_hardcoded_attack( "SLIMESPRING", mattack::slimespring ); + add_hardcoded_attack( "EVOLVE_KILL_STRIKE", mattack::evolve_kill_strike ); + add_hardcoded_attack( "LEECH_SPAWNER", mattack::leech_spawner ); + add_hardcoded_attack( "MON_LEECH_EVOLUTION", mattack::mon_leech_evolution ); add_hardcoded_attack( "TINDALOS_TELEPORT", mattack::tindalos_teleport ); add_hardcoded_attack( "FLESH_TENDRIL", mattack::flesh_tendril ); add_hardcoded_attack( "BIO_OP_TAKEDOWN", mattack::bio_op_takedown ); From 5fd024a03b1ff23ca926cce39920ca0be3671630 Mon Sep 17 00:00:00 2001 From: John Candlebury Date: Tue, 17 Dec 2019 22:39:08 -0600 Subject: [PATCH 02/31] Fix typo --- data/json/monsters/power_leech.json | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/data/json/monsters/power_leech.json b/data/json/monsters/power_leech.json index e8f79a5919e1a..b23b696cc390d 100644 --- a/data/json/monsters/power_leech.json +++ b/data/json/monsters/power_leech.json @@ -110,7 +110,7 @@ "type": "MONSTER", "name": "root runner", "description": "This clump of woody vegetation hastily clambers around in a lizard-like fashion. Three translucent scale-leaves stand tall on the backside of the creature, and the thin ridges within them periodically glow through some unknown mean. Its seemingly a symbiote of the nearby alien ferns, and looks ready to defend them with its life.", - "default_faction": "nether",1 + "default_faction": "nether", "species": [ "LEECH_PLANT" ], "volume": "4000 ml", "weight": "6 kg", From 86b3fa6d0cd82f9863aed3158618b01be4ce014b Mon Sep 17 00:00:00 2001 From: John Candlebury Date: Wed, 18 Dec 2019 16:59:41 -0600 Subject: [PATCH 03/31] Apply suggestions from code review Co-Authored-By: Anton Burmistrov Co-Authored-By: BevapDin --- data/json/items/comestibles/carnivore.json | 2 +- data/json/monsters/power_leech.json | 9 ++++----- src/monattack.cpp | 19 ++++++++----------- src/monster.cpp | 2 +- 4 files changed, 14 insertions(+), 18 deletions(-) diff --git a/data/json/items/comestibles/carnivore.json b/data/json/items/comestibles/carnivore.json index 4122d49d150d8..9b2cbdb8d541a 100644 --- a/data/json/items/comestibles/carnivore.json +++ b/data/json/items/comestibles/carnivore.json @@ -976,7 +976,7 @@ "type": "COMESTIBLE", "name": "leech bark", "name_plural": "scraps of leech bark", - "description": "Dry and though bark matter harvested from an alien plant. It is slightly translucent, and if placed against the light you can distinguish glistening blue veins running through it.", + "description": "Dry and tough bark matter harvested from an alien plant. It is slightly translucent, and if placed against the light you can distinguish glistening blue veins running through it.", "vitamins": [ [ "vitA", 6 ], [ "vitC", 0 ], [ "calcium", 2 ], [ "iron", 8 ], [ "vitB", 6 ], [ "mutant_toxin", 12 ] ] } ] diff --git a/data/json/monsters/power_leech.json b/data/json/monsters/power_leech.json index b23b696cc390d..7b8c80062ca80 100644 --- a/data/json/monsters/power_leech.json +++ b/data/json/monsters/power_leech.json @@ -40,7 +40,7 @@ "id": "mon_leech_stalk", "type": "MONSTER", "name": "leech stalk", - "description": "A resplendent and voluminous alien fern. A faint buzzing sound emanates from it, and the shadow cast by its canopy continuously glows with electric charge.", + "description": "A resplendent and voluminous alien fern. A faint buzzing sound emanates from it, and the shadow cast by its canopy continuously glows with electric charge.", "default_faction": "nether", "species": [ "LEECH_PLANT" ], "volume": "30000 ml", @@ -76,7 +76,7 @@ "id": "mon_leech_pod_cluster", "type": "MONSTER", "name": "leech pod cluster", - "description": "The translucent egg pods of an alien plant, firmly attached by luminous rhizomes. You can barely distinguish a root drone floating withing a cloudy substance.", + "description": "The translucent egg pods of an alien plant, firmly attached by luminous rhizomes. You can barely distinguish a root drone floating within a cloudy substance.", "default_faction": "nether", "species": [ "LEECH_PLANT" ], "volume": "30000 ml", @@ -90,7 +90,6 @@ "morale": 100, "armor_bash": 15, "luminance": 60, - "starting_ammo": { "9mm": 100 }, "special_attacks": [ { "type": "gun", @@ -109,7 +108,7 @@ "id": "mon_leech_root_runner", "type": "MONSTER", "name": "root runner", - "description": "This clump of woody vegetation hastily clambers around in a lizard-like fashion. Three translucent scale-leaves stand tall on the backside of the creature, and the thin ridges within them periodically glow through some unknown mean. Its seemingly a symbiote of the nearby alien ferns, and looks ready to defend them with its life.", + "description": "This clump of woody vegetation hastily clambers around in a lizard-like fashion. Three translucent scale-leaves stand tall on the backside of the creature, and the thin ridges within them periodically glow through some unknown mean. It's seemingly a symbiote of the nearby alien ferns, and looks ready to defend them with its life.", "default_faction": "nether", "species": [ "LEECH_PLANT" ], "volume": "4000 ml", @@ -149,7 +148,7 @@ "id": "mon_leech_root_drone", "type": "MONSTER", "name": "root drone", - "description": "A small bulb with a beak like protuberance, skittishly roaming about under three tendril rhizomes. Dripping and glistening, it resembles a creature newly born rather than a sapling grown from seeds.", + "description": "A small bulb with a beak-like protuberance, skittishly roaming about under three tendril rhizomes. Dripping and glistening, it resembles a creature newly born rather than a sapling grown from seeds.", "default_faction": "nether", "species": [ "LEECH_PLANT" ], "volume": "3000 ml", diff --git a/src/monattack.cpp b/src/monattack.cpp index a9b9483701b7f..4a4ba3cd2807b 100644 --- a/src/monattack.cpp +++ b/src/monattack.cpp @@ -4739,7 +4739,7 @@ bool mattack::evolve_kill_strike( monster *z ) } z->moves -= 100; - bool uncanny = target->uncanny_dodge(); + const bool uncanny = target->uncanny_dodge(); if( uncanny || dodge_check( z, target ) ) { auto msg_type = target == &g->u ? m_warning : m_info; target->add_msg_player_or_npc( msg_type, _( "The %s lunges at you, but you dodge!" ), @@ -4770,7 +4770,7 @@ bool mattack::evolve_kill_strike( monster *z ) } else { target->add_msg_player_or_npc( _( "The %1$s attempts to burrow itself into you, but is stopped by your armor!" ), - _( "The %1$s slashes at 's %2$s, but is stopped by its glances off armor!" ), + _( "The %1$s slashes at 's %2$s, but is stopped by their armor!" ), z->name() ); return true; } @@ -4788,7 +4788,7 @@ bool mattack::evolve_kill_strike( monster *z ) } else if( could_see_z ) { add_msg( m_warning, _( "The %1$s burrows within %2$s corpse!" ), old_name, target_name ); } else if( can_see_z_upgrade ) { - add_msg( m_warning, _( "A %1$s emerges from %2$s corpse!" ), target->disp_name(), target_name ); + add_msg( m_warning, _( "A %1$s emerges from %2$s corpse!" ), upgrade_name, target_name ); } } return true; @@ -4799,14 +4799,14 @@ bool mattack::leech_spawner( monster *z ) const bool u_see = g->u.sees( *z ); std::list allies; for( monster &candidate : g->all_monsters() ) { - if( candidate.type->in_species( LEECH_PLANT ) && !candidate.type->has_flag( MF_IMMOBILE ) ) { + if( candidate.in_species( LEECH_PLANT ) && !candidate.has_flag( MF_IMMOBILE ) ) { allies.push_back( &candidate ); } } if( allies.size() > 35 ) { return true; } - int monsters_spawned = rng( 1, 4 ); + const int monsters_spawned = rng( 1, 4 ); const mtype_id monster_type = one_in( 3 ) ? mon_leech_root_runner : mon_leech_root_drone; for( int i = 0; i < monsters_spawned; i++ ) { if( monster *const new_mon = g->place_critter_around( monster_type, z->pos(), 1 ) ) { @@ -4820,7 +4820,7 @@ bool mattack::leech_spawner( monster *z ) z->poly( mon_leech_stalk ); if( u_see ) { add_msg( m_warning, - _( "Resplendent fronds emerge from the still intact pods! " ) ); + _( "Resplendent fronds emerge from the still intact pods!" ) ); } } return true; @@ -4829,10 +4829,10 @@ bool mattack::leech_spawner( monster *z ) bool mattack::mon_leech_evolution( monster *z ) { const bool u_see = g->u.sees( *z ); - const bool is_queen = z->type->has_flag( MF_QUEEN ); + const bool is_queen = z->has_flag( MF_QUEEN ); std::list queens; for( monster &candidate : g->all_monsters() ) { - if( candidate.type->in_species( LEECH_PLANT ) && candidate.type->has_flag( MF_QUEEN ) && + if( candidate.in_species( LEECH_PLANT ) && candidate.has_flag( MF_QUEEN ) && rl_dist( z->pos(), candidate.pos() ) ) { queens.push_back( &candidate ); } @@ -4846,7 +4846,6 @@ bool mattack::mon_leech_evolution( monster *z ) _( "The %s blooms into flowers!" ), z->name() ); } } - } else { if( !queens.empty() ) { if( u_see ) { @@ -4855,13 +4854,11 @@ bool mattack::mon_leech_evolution( monster *z ) } z->poly( mon_leech_stalk ); g->m.spawn_item( z->pos(), "leech_flower", 5, 0, calendar::turn ); - } } return true; } - bool mattack::tindalos_teleport( monster *z ) { Creature *target = z->attack_target(); diff --git a/src/monster.cpp b/src/monster.cpp index dbb942b82e30c..87b36dc00773b 100644 --- a/src/monster.cpp +++ b/src/monster.cpp @@ -318,7 +318,7 @@ int monster::get_upgrade_time() const } // Sets time to upgrade to 0. -void monster:: allow_upgrade() +void monster::allow_upgrade() { upgrade_time = 0; } From ffb5507afa26d628901adce2e192f3516ba486d1 Mon Sep 17 00:00:00 2001 From: John Candlebury Date: Wed, 18 Dec 2019 18:40:56 -0600 Subject: [PATCH 04/31] Follow through suggestions --- data/json/monsters/power_leech.json | 28 +++++++++++++++------------- src/monattack.cpp | 10 +++++----- 2 files changed, 20 insertions(+), 18 deletions(-) diff --git a/data/json/monsters/power_leech.json b/data/json/monsters/power_leech.json index 7b8c80062ca80..fdac101921fdf 100644 --- a/data/json/monsters/power_leech.json +++ b/data/json/monsters/power_leech.json @@ -17,14 +17,14 @@ "morale": 100, "armor_bash": 15, "vision_day": 30, - "vision_night": 30, + "vision_night": 12, "luminance": 200, "special_attacks": [ { "type": "gun", "cooldown": 5, "gun_type": "emp_frond", - "fake_skills": [ [ "gun", 3 ], [ "rifle", 3 ] ], + "fake_skills": [ [ "gun", 3 ], [ "pistol", 3 ] ], "ranges": [ [ 0, 12, "DEFAULT" ] ], "description": "Lightning arcs towards you!" }, @@ -32,6 +32,7 @@ [ "MON_LEECH_EVOLUTION", 40 ], [ "PARROT", 40 ] ], + "special_when_hit": [ "ZAPBACK", 100 ], "death_drops": { }, "death_function": [ "NORMAL" ], "flags": [ "SEES", "NOHEAD", "IMMOBILE", "NO_BREATHE", "QUEEN", "HARDTOSHOOT" ] @@ -54,23 +55,23 @@ "morale": 100, "armor_bash": 15, "vision_day": 30, - "vision_night": 30, + "vision_night": 8, "luminance": 200, "special_attacks": [ { "type": "gun", "cooldown": 15, "gun_type": "emp_frond", - "fake_skills": [ [ "gun", 2 ], [ "rifle", 2 ] ], + "fake_skills": [ [ "gun", 2 ], [ "pistol", 2 ] ], "ranges": [ [ 0, 12, "DEFAULT" ] ], "description": "Lightning arcs towards you!" }, - [ "MON_LEECH_EVOLUTION", 30 ], - [ "PARROT", 40 ] + [ "MON_LEECH_EVOLUTION", 30 ] ], + "special_when_hit": [ "ZAPBACK", 100 ], "death_drops": { }, "death_function": [ "NORMAL" ], - "flags": [ "SEES", "NOHEAD", "ELECTRONIC", "IMMOBILE", "NO_BREATHE", "HARDTOSHOOT" ] + "flags": [ "SEES", "NOHEAD", "IMMOBILE", "NO_BREATHE", "HARDTOSHOOT" ] }, { "id": "mon_leech_pod_cluster", @@ -126,7 +127,7 @@ "armor_bash": 15, "luminance": 60, "vision_day": 30, - "vision_night": 10, + "vision_night": 5, "melee_damage": [ { "damage_type": "electric", "amount": 4 } ], "upgrades": { "half_life": 9999, "into": "mon_leech_stalk" }, "special_attacks": [ @@ -134,15 +135,16 @@ "type": "gun", "cooldown": 15, "gun_type": "emp_frond", - "fake_skills": [ [ "gun", 1 ], [ "rifle", 1 ] ], + "fake_skills": [ [ "gun", 1 ], [ "pistol", 1 ] ], "ranges": [ [ 0, 2, "DEFAULT" ] ], "description": "Lightning arcs towards you!" }, [ "EVOLVE_KILL_STRIKE", 3 ] ], + "special_when_hit": [ "ZAPBACK", 100 ], "death_drops": { }, "death_function": [ "NORMAL" ], - "flags": [ "SEES", "NOHEAD", "ELECTRONIC", "NO_BREATHE", "HARDTOSHOOT" ] + "flags": [ "SEES", "NOHEAD", "NO_BREATHE", "HARDTOSHOOT" ] }, { "id": "mon_leech_root_drone", @@ -166,7 +168,7 @@ "armor_bash": 15, "luminance": 60, "vision_day": 30, - "vision_night": 10, + "vision_night": 5, "melee_damage": [ { "damage_type": "electric", "amount": 3 } ], "upgrades": { "half_life": 999, "into": "mon_leech_pod_cluster" }, "special_attacks": [ @@ -174,7 +176,7 @@ "type": "gun", "cooldown": 15, "gun_type": "emp_frond", - "fake_skills": [ [ "gun", 1 ], [ "rifle", 1 ] ], + "fake_skills": [ [ "gun", 1 ], [ "pistol", 1 ] ], "ranges": [ [ 0, 2, "DEFAULT" ] ], "description": "Lightning arcs towards you!" }, @@ -182,6 +184,6 @@ ], "death_drops": { }, "death_function": [ "NORMAL" ], - "flags": [ "SEES", "NOHEAD", "ELECTRONIC", "NO_BREATHE", "HARDTOSHOOT" ] + "flags": [ "SEES", "NOHEAD", "NO_BREATHE", "HARDTOSHOOT" ] } ] diff --git a/src/monattack.cpp b/src/monattack.cpp index 4a4ba3cd2807b..8ab7d917debda 100644 --- a/src/monattack.cpp +++ b/src/monattack.cpp @@ -4753,8 +4753,6 @@ bool mattack::evolve_kill_strike( monster *z ) } return true; } - const std::string old_name = z->name(); - const bool could_see_z = g->u.sees( *z ); tripoint const target_pos = target->pos(); const std::string target_name = target->disp_name(); damage_instance damage( z->type->melee_damage ); @@ -4770,12 +4768,14 @@ bool mattack::evolve_kill_strike( monster *z ) } else { target->add_msg_player_or_npc( _( "The %1$s attempts to burrow itself into you, but is stopped by your armor!" ), - _( "The %1$s slashes at 's %2$s, but is stopped by their armor!" ), + _( "The %1$s slashes at 's torso, but is stopped by their armor!" ), z->name() ); return true; } if( target->is_dead_state() && g->is_empty( target_pos ) && target->made_of_any( Creature::cmat_flesh ) ) { + const std::string old_name = z->name(); + const bool could_see_z = g->u.sees( *z ); z->allow_upgrade(); z->try_upgrade( false ); z->setpos( target_pos ); @@ -4803,7 +4803,7 @@ bool mattack::leech_spawner( monster *z ) allies.push_back( &candidate ); } } - if( allies.size() > 35 ) { + if( allies.size() > 45 ) { return true; } const int monsters_spawned = rng( 1, 4 ); @@ -4833,7 +4833,7 @@ bool mattack::mon_leech_evolution( monster *z ) std::list queens; for( monster &candidate : g->all_monsters() ) { if( candidate.in_species( LEECH_PLANT ) && candidate.has_flag( MF_QUEEN ) && - rl_dist( z->pos(), candidate.pos() ) ) { + rl_dist( z->pos(), candidate.pos() ) > 35 ) { queens.push_back( &candidate ); } } From 3fcc65b2094b4ae4134bb5e91e5cea2a1a6e6ae5 Mon Sep 17 00:00:00 2001 From: John Candlebury Date: Wed, 18 Dec 2019 19:45:45 -0600 Subject: [PATCH 05/31] Reword alien frond description --- data/json/items/comestibles/carnivore.json | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/data/json/items/comestibles/carnivore.json b/data/json/items/comestibles/carnivore.json index 9b2cbdb8d541a..5be58a68d401c 100644 --- a/data/json/items/comestibles/carnivore.json +++ b/data/json/items/comestibles/carnivore.json @@ -939,7 +939,7 @@ "type": "COMESTIBLE", "name": "alien fronds", "use_action": "POISON", - "description": "The fleshy fronds harvested from an alien plant. The tiny membranous leaves attached and rigid and gut-like stem are certainly poisonous, and yet they have a paradoxically pleasant and inviting sweet smell. Might be non-vegan.", + "description": "The fleshy fronds harvested from an alien plant. Eating these membranous leaves and gut-like stems is likely a terrible idea, and yet they have a paradoxically pleasant and inviting sweet smell. Might be non-vegan.", "fun": 15, "stim": 3, "vitamins": [ [ "vitA", 6 ], [ "vitC", 2 ], [ "calcium", 0 ], [ "iron", 8 ], [ "vitB", 6 ], [ "mutant_toxin", 8 ] ] From adb9e666fc37ffb8e74e82d43a87883a8e10d557 Mon Sep 17 00:00:00 2001 From: John Candlebury Date: Thu, 19 Dec 2019 18:15:14 -0600 Subject: [PATCH 06/31] Correct monattack logic --- src/monattack.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/monattack.cpp b/src/monattack.cpp index 8ab7d917debda..ba9aa405ef6bd 100644 --- a/src/monattack.cpp +++ b/src/monattack.cpp @@ -4833,7 +4833,7 @@ bool mattack::mon_leech_evolution( monster *z ) std::list queens; for( monster &candidate : g->all_monsters() ) { if( candidate.in_species( LEECH_PLANT ) && candidate.has_flag( MF_QUEEN ) && - rl_dist( z->pos(), candidate.pos() ) > 35 ) { + rl_dist( z->pos(), candidate.pos() ) < 35 ) { queens.push_back( &candidate ); } } From df0f9bae21a3c915c8a81fd2d60007fc6f807c7b Mon Sep 17 00:00:00 2001 From: John Candlebury Date: Thu, 19 Dec 2019 19:48:50 -0600 Subject: [PATCH 07/31] Finalize leech pod monster family --- data/json/monsters/power_leech.json | 19 ++++++++++++++----- src/monattack.cpp | 23 +++++++---------------- 2 files changed, 21 insertions(+), 21 deletions(-) diff --git a/data/json/monsters/power_leech.json b/data/json/monsters/power_leech.json index fdac101921fdf..72e88f07eb877 100644 --- a/data/json/monsters/power_leech.json +++ b/data/json/monsters/power_leech.json @@ -10,6 +10,7 @@ "weight": "40 kg", "hp": 100, "speed": 100, + "diff": 30, "material": [ "flesh" ], "symbol": "K", "color": "light_cyan", @@ -26,7 +27,8 @@ "gun_type": "emp_frond", "fake_skills": [ [ "gun", 3 ], [ "pistol", 3 ] ], "ranges": [ [ 0, 12, "DEFAULT" ] ], - "description": "Lightning arcs towards you!" + "targeting_sound": "a faint buzz", + "description": "Lightning arcs from the leech blossom!" }, [ "LEECH_SPAWNER", 25 ], [ "MON_LEECH_EVOLUTION", 40 ], @@ -48,6 +50,7 @@ "weight": "40 kg", "hp": 40, "speed": 100, + "diff": 20, "material": [ "flesh" ], "symbol": "y", "color": "light_blue", @@ -64,7 +67,8 @@ "gun_type": "emp_frond", "fake_skills": [ [ "gun", 2 ], [ "pistol", 2 ] ], "ranges": [ [ 0, 12, "DEFAULT" ] ], - "description": "Lightning arcs towards you!" + "targeting_sound": "a faint buzz", + "description": "Lightning arcs from the leech stalk!" }, [ "MON_LEECH_EVOLUTION", 30 ] ], @@ -84,6 +88,7 @@ "weight": "60 kg", "hp": 40, "speed": 100, + "diff": 20, "material": [ "flesh" ], "symbol": "g", "color": "white", @@ -97,7 +102,8 @@ "cooldown": 15, "gun_type": "emp_frond", "ranges": [ [ 0, 1, "DEFAULT" ] ], - "description": "Lightning arcs towards you!" + "targeting_sound": "a faint buzz", + "description": "Lightning arcs from the pod cluster!" }, [ "LEECH_SPAWNER", 35 ] ], @@ -116,6 +122,7 @@ "weight": "6 kg", "hp": 40, "speed": 120, + "diff": 20, "material": [ "flesh" ], "symbol": "m", "color": "blue", @@ -137,7 +144,8 @@ "gun_type": "emp_frond", "fake_skills": [ [ "gun", 1 ], [ "pistol", 1 ] ], "ranges": [ [ 0, 2, "DEFAULT" ] ], - "description": "Lightning arcs towards you!" + "targeting_sound": "a faint buzz", + "description": "Sparks fly from the root runner!" }, [ "EVOLVE_KILL_STRIKE", 3 ] ], @@ -178,7 +186,8 @@ "gun_type": "emp_frond", "fake_skills": [ [ "gun", 1 ], [ "pistol", 1 ] ], "ranges": [ [ 0, 2, "DEFAULT" ] ], - "description": "Lightning arcs towards you!" + "targeting_sound": "a faint buzz", + "description": "Lightning arcs from the root pod!" }, [ "EVOLVE_KILL_STRIKE", 6 ] ], diff --git a/src/monattack.cpp b/src/monattack.cpp index ba9aa405ef6bd..914d39d991d2d 100644 --- a/src/monattack.cpp +++ b/src/monattack.cpp @@ -4814,13 +4814,13 @@ bool mattack::leech_spawner( monster *z ) add_msg( m_warning, _( "An egg pod ruptures and a %s crawls out from the remains!" ), new_mon->name() ); } - } - } - if( one_in( 25 ) ) { - z->poly( mon_leech_stalk ); - if( u_see ) { - add_msg( m_warning, - _( "Resplendent fronds emerge from the still intact pods!" ) ); + if( one_in( 25 ) ) { + z->poly( mon_leech_stalk ); + if( u_see ) { + add_msg( m_warning, + _( "Resplendent fronds emerge from the still intact pods!" ) ); + } + } } } return true; @@ -4846,15 +4846,6 @@ bool mattack::mon_leech_evolution( monster *z ) _( "The %s blooms into flowers!" ), z->name() ); } } - } else { - if( !queens.empty() ) { - if( u_see ) { - add_msg( m_warning, - _( "The %s flowers whiter and fall!" ), z->name() ); - } - z->poly( mon_leech_stalk ); - g->m.spawn_item( z->pos(), "leech_flower", 5, 0, calendar::turn ); - } } return true; } From 86a0823d8280dc05a6c2a7cf50a54d4217c40477 Mon Sep 17 00:00:00 2001 From: ymber Date: Tue, 31 Dec 2019 18:48:32 +0000 Subject: [PATCH 08/31] Allow folding turret mount --- data/json/vehicleparts/vehicle_parts.json | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/data/json/vehicleparts/vehicle_parts.json b/data/json/vehicleparts/vehicle_parts.json index da53bb6b6eea2..0f254e78fbc28 100644 --- a/data/json/vehicleparts/vehicle_parts.json +++ b/data/json/vehicleparts/vehicle_parts.json @@ -3550,13 +3550,14 @@ "damage_modifier": 80, "durability": 320, "description": "A rotating, universal mount for a weapon. If your hands are empty, you can stand next to a turret mount and 'f'ire the weapon by selecting the tile.", + "folded_volume": "2500 ml", "item": "turret_mount", "requirements": { "install": { "skills": [ [ "mechanics", 1 ] ], "time": "20 m", "using": [ [ "welding_standard", 10 ] ] }, "removal": { "skills": [ [ "mechanics", 1 ] ], "time": "10 m", "using": "vehicle_weld_removal" }, "repair": { "skills": [ [ "mechanics", 1 ] ], "time": "5 m", "using": [ [ "welding_standard", 5 ] ] } }, - "flags": [ "TURRET_MOUNT" ], + "flags": [ "TURRET_MOUNT", "FOLDABLE" ], "breaks_into": [ { "item": "scrap", "count": [ 1, 4 ] } ], "damage_reduction": { "all": 54 } }, From 514fedc92afaf166a630d56a65f02dc88f816250 Mon Sep 17 00:00:00 2001 From: John Bytheway Date: Sun, 29 Dec 2019 21:05:35 -0500 Subject: [PATCH 09/31] Use a slightly more accurate lunar month Previously the in-game lunar month was exactly one third of a season (30.333 days, by default). This meant that the lunar cycle matched perfectly with the seasons / years, unlike the real-world lunar cycle which is inconveniently mismatched with other calendar units. Switch it so that, for the default season length, the lunar cycle matches the real-world synodic month of about 29.5 days. Also tidy up the code so that it's clearer how this value is arrived at. --- src/calendar.cpp | 7 ++++--- 1 file changed, 4 insertions(+), 3 deletions(-) diff --git a/src/calendar.cpp b/src/calendar.cpp index 587f5bb6fa587..d61aa0d11f5b4 100644 --- a/src/calendar.cpp +++ b/src/calendar.cpp @@ -59,9 +59,10 @@ double default_daylight_level() moon_phase get_moon_phase( const time_point &p ) { - //One full phase every 1 rl months = 1/3 season length - const time_duration moon_phase_duration = calendar::season_length() / 3.0; - //Switch moon phase at noon so it stays the same all night + static constexpr time_duration synodic_month = 29.530588853 * 1_days; + const time_duration moon_phase_duration = + calendar::season_from_default_ratio() * synodic_month; + // Switch moon phase at noon so it stays the same all night const time_duration current_day = ( p - calendar::turn_zero ) + 1_days / 2; const double phase_change = current_day / moon_phase_duration; const int current_phase = static_cast( round( phase_change * MOON_PHASE_MAX ) ) % From 2569a210f6736ac2e0d3baaa11aa90815998ff70 Mon Sep 17 00:00:00 2001 From: John Bytheway Date: Sun, 29 Dec 2019 21:09:05 -0500 Subject: [PATCH 10/31] Factor out the real and default season lengths Pull these values out as global statics to make it clearer that the default season length is the real-world season length. --- src/calendar.cpp | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-) diff --git a/src/calendar.cpp b/src/calendar.cpp index d61aa0d11f5b4..e16a12b254b3c 100644 --- a/src/calendar.cpp +++ b/src/calendar.cpp @@ -449,15 +449,16 @@ void calendar::set_season_length( const int dur ) cur_season_length = dur; } +static constexpr int real_world_season_length = 91; +static constexpr int default_season_length = real_world_season_length; + float calendar::season_ratio() { - static const int real_world_season_length = 91; return to_days( season_length() ) / real_world_season_length; } float calendar::season_from_default_ratio() { - static const int default_season_length = 91; return to_days( season_length() ) / default_season_length; } From 4075247675761ac30ed48dacc5ab7f7b20bf3a5c Mon Sep 17 00:00:00 2001 From: John Bytheway Date: Sun, 29 Dec 2019 21:09:57 -0500 Subject: [PATCH 11/31] Simplify some arithmetic. --- tests/vision_test.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/tests/vision_test.cpp b/tests/vision_test.cpp index 41abaddd4cf26..df21a9eee6684 100644 --- a/tests/vision_test.cpp +++ b/tests/vision_test.cpp @@ -460,7 +460,7 @@ TEST_CASE( "vision_wall_can_be_lit_by_player", "[shadowcasting][vision]" ) TEST_CASE( "vision_see_wall_in_moonlight", "[shadowcasting][vision]" ) { - const time_point full_moon = calendar::turn_zero + calendar::season_length() / 3 / 2; + const time_point full_moon = calendar::turn_zero + calendar::season_length() / 6; // Verify that I've picked the full_moon time correctly. CHECK( get_moon_phase( full_moon ) == MOON_FULL ); From fd88a62e7f8c7aa75ca41e2ed6894a356340c40c Mon Sep 17 00:00:00 2001 From: John Bytheway Date: Sun, 29 Dec 2019 21:10:20 -0500 Subject: [PATCH 12/31] Add a test for the lunar cycle code. --- tests/calendar_test.cpp | 22 ++++++++++++++++++++++ 1 file changed, 22 insertions(+) create mode 100644 tests/calendar_test.cpp diff --git a/tests/calendar_test.cpp b/tests/calendar_test.cpp new file mode 100644 index 0000000000000..bb3e6c8872bf5 --- /dev/null +++ b/tests/calendar_test.cpp @@ -0,0 +1,22 @@ +#include "catch/catch.hpp" + +#include "calendar.h" +#include "rng.h" + +TEST_CASE( "moon_phases_take_28_days", "[calendar]" ) +{ + // This test only makes sense if the seasons are set to the default length + REQUIRE( calendar::season_from_default_ratio() == 1 ); + + const int num_days = GENERATE( take( 100, random( 0, 1000 ) ) ); + const time_point first_time = calendar::turn_zero + time_duration::from_days( num_days ); + const time_point later_14_days = first_time + 14_days; + const time_point later_29_days = first_time + 29_days; + const time_point later_30_days = first_time + 30_days; + + CAPTURE( num_days ); + CHECK( get_moon_phase( first_time ) != get_moon_phase( later_14_days ) ); + // Phase should match either 29 or 30 days later + CHECK( ( get_moon_phase( first_time ) == get_moon_phase( later_29_days ) || + get_moon_phase( first_time ) == get_moon_phase( later_30_days ) ) ); +} From 346a794d16fc7036f2f41d4a560b6fb610cb2f43 Mon Sep 17 00:00:00 2001 From: John Bytheway Date: Mon, 30 Dec 2019 22:04:25 -0500 Subject: [PATCH 13/31] Be more permissive in season length assertion This was failing on Mingw, probably due to -ffast-math optimizations. --- tests/calendar_test.cpp | 4 +++- tests/stringmaker.h | 7 +++++++ 2 files changed, 10 insertions(+), 1 deletion(-) diff --git a/tests/calendar_test.cpp b/tests/calendar_test.cpp index bb3e6c8872bf5..c84d1dae93a81 100644 --- a/tests/calendar_test.cpp +++ b/tests/calendar_test.cpp @@ -2,11 +2,13 @@ #include "calendar.h" #include "rng.h" +#include "stringmaker.h" TEST_CASE( "moon_phases_take_28_days", "[calendar]" ) { + CAPTURE( calendar::season_length() ); // This test only makes sense if the seasons are set to the default length - REQUIRE( calendar::season_from_default_ratio() == 1 ); + REQUIRE( calendar::season_from_default_ratio() == Approx( 1.0f ) ); const int num_days = GENERATE( take( 100, random( 0, 1000 ) ) ); const time_point first_time = calendar::turn_zero + time_duration::from_days( num_days ); diff --git a/tests/stringmaker.h b/tests/stringmaker.h index 6d25a70f874e9..e845176bc21eb 100644 --- a/tests/stringmaker.h +++ b/tests/stringmaker.h @@ -40,6 +40,13 @@ struct StringMaker { } }; +template<> +struct StringMaker { + static std::string convert( const time_duration &d ) { + return string_format( "time_duration( %d ) [%s]", to_turns( d ), to_string( d ) ); + } +}; + } // namespace Catch #endif // CATA_TESTS_STRINGMAKER_H From 31bae0ed483442855be028c5af235077a0486819 Mon Sep 17 00:00:00 2001 From: John Bytheway Date: Mon, 30 Dec 2019 22:05:11 -0500 Subject: [PATCH 14/31] Ensure moon phase doesn't change at night This was already theoretically implemented, but it didn't work. Fix it and add a test. --- src/calendar.cpp | 5 +++-- tests/calendar_test.cpp | 14 ++++++++++++++ 2 files changed, 17 insertions(+), 2 deletions(-) diff --git a/src/calendar.cpp b/src/calendar.cpp index e16a12b254b3c..0068fa18b93dd 100644 --- a/src/calendar.cpp +++ b/src/calendar.cpp @@ -63,8 +63,9 @@ moon_phase get_moon_phase( const time_point &p ) const time_duration moon_phase_duration = calendar::season_from_default_ratio() * synodic_month; // Switch moon phase at noon so it stays the same all night - const time_duration current_day = ( p - calendar::turn_zero ) + 1_days / 2; - const double phase_change = current_day / moon_phase_duration; + const int num_middays = to_days( p - calendar::turn_zero + 1_days / 2 ); + const time_duration nearest_midnight = num_middays * 1_days; + const double phase_change = nearest_midnight / moon_phase_duration; const int current_phase = static_cast( round( phase_change * MOON_PHASE_MAX ) ) % static_cast( MOON_PHASE_MAX ); return static_cast( current_phase ); diff --git a/tests/calendar_test.cpp b/tests/calendar_test.cpp index c84d1dae93a81..8b4a918d53f74 100644 --- a/tests/calendar_test.cpp +++ b/tests/calendar_test.cpp @@ -22,3 +22,17 @@ TEST_CASE( "moon_phases_take_28_days", "[calendar]" ) CHECK( ( get_moon_phase( first_time ) == get_moon_phase( later_29_days ) || get_moon_phase( first_time ) == get_moon_phase( later_30_days ) ) ); } + +TEST_CASE( "moon_phase_changes_at_noon", "[calendar]" ) +{ + // This test only makes sense if the seasons are set to the default length + REQUIRE( calendar::season_from_default_ratio() == Approx( 1.0f ) ); + + const int num_days = GENERATE( take( 100, random( 0, 1000 ) ) ); + const time_point midnight = calendar::turn_zero + time_duration::from_days( num_days ); + const time_point earlier_11_hours = midnight - 11_hours; + const time_point later_11_hours = midnight + 11_hours; + + CAPTURE( num_days ); + CHECK( get_moon_phase( earlier_11_hours ) == get_moon_phase( later_11_hours ) ); +} From 9080d341801e7ad7ab5a957345f3e2c0b9d59a37 Mon Sep 17 00:00:00 2001 From: John Bytheway Date: Tue, 31 Dec 2019 17:11:59 -0500 Subject: [PATCH 15/31] Suppress clang-tidy warning This one is in Catch2 internals and triggered by using generators. --- tests/catch/catch.hpp | 1 + 1 file changed, 1 insertion(+) diff --git a/tests/catch/catch.hpp b/tests/catch/catch.hpp index 91c8f92c17d1a..0665c29bea503 100644 --- a/tests/catch/catch.hpp +++ b/tests/catch/catch.hpp @@ -4238,6 +4238,7 @@ namespace Catch { { if( !IMutableContext::currentContext ) IMutableContext::createContext(); + // NOLINTNEXTLINE(clang-analyzer-core.uninitialized.UndefReturn) return *IMutableContext::currentContext; } From 66130a07c1d62f260f2d37a7deb5e2cf3f751aaf Mon Sep 17 00:00:00 2001 From: RarkGrames <50421549+RarkGrames@users.noreply.github.com> Date: Wed, 1 Jan 2020 20:15:02 +0100 Subject: [PATCH 16/31] Update tools.json --- data/json/itemgroups/tools.json | 1 - 1 file changed, 1 deletion(-) diff --git a/data/json/itemgroups/tools.json b/data/json/itemgroups/tools.json index 1fa7712c9e83a..f8944c0505ea3 100644 --- a/data/json/itemgroups/tools.json +++ b/data/json/itemgroups/tools.json @@ -81,7 +81,6 @@ [ "jumper_cable_heavy", 2 ], [ "jerrycan", 10 ], [ "jerrycan_big", 10 ], - [ "lawnmower", 10 ], [ "char_smoker", 5 ], [ "dehydrator", 5 ], [ "tongs", 1 ], From 142fdfe0ecfb8368663da0d83c3fbbabdb61a2d2 Mon Sep 17 00:00:00 2001 From: John Bytheway Date: Tue, 31 Dec 2019 22:23:11 -0500 Subject: [PATCH 17/31] Detect and warn about crafting with rotten food To deal with the long-standing issue of accidentally using rotting food in crafting (especially when crafting a large batch) and thus wasting time and materials. Allow a recipe filter to exclude rotten components. Use this new feature when selecting items for crafting to prefer non-rotten ones. When non-rotten ones do not suffice, warn the player of this fact before proceeding. In the crafting GUI, mark crafts in brown when they can only be crafted with rotten ingredients. If the result doesn't care about rottenness, as with e.g. lamp oil, then no warnings or marking of the recipes is done. This only catches the case where the ingredients are rotten when you start the craft. There is also the situation where things start non-rotten, but become rotten while you craft. This change does not attempt to handle that, but it could now be handled by a localized change in recipe::get_component_filter. --- src/craft_command.cpp | 22 ++++++++--- src/craft_command.h | 3 ++ src/crafting.cpp | 19 +++++++-- src/crafting_gui.cpp | 92 ++++++++++++++++++++++--------------------- src/player.h | 3 +- src/recipe.cpp | 9 ++++- src/recipe.h | 14 ++++++- 7 files changed, 105 insertions(+), 57 deletions(-) diff --git a/src/craft_command.cpp b/src/craft_command.cpp index 73018b9fdae28..0800bf519e065 100644 --- a/src/craft_command.cpp +++ b/src/craft_command.cpp @@ -122,7 +122,7 @@ void craft_command::execute( const tripoint &new_loc ) if( need_selections ) { if( !crafter->can_make( rec, batch_size ) ) { - if( crafter->can_start_craft( rec, batch_size ) ) { + if( crafter->can_start_craft( rec, recipe_filter_flags::none, batch_size ) ) { if( !query_yn( _( "You don't have enough charges to complete the %s.\n" "Start crafting anyway?" ), rec->result_name() ) ) { return; @@ -133,13 +133,23 @@ void craft_command::execute( const tripoint &new_loc ) } } + flags = recipe_filter_flags::no_rotten; + + if( !crafter->can_start_craft( rec, flags, batch_size ) ) { + if( !query_yn( _( "This craft will use rotten components.\n" + "Start crafting anyway?" ) ) ) { + return; + } + flags = recipe_filter_flags::none; + } + item_selections.clear(); const auto needs = rec->requirements(); - const auto filter = rec->get_component_filter(); + const auto filter = rec->get_component_filter( flags ); for( const auto &it : needs.get_components() ) { - comp_selection is = crafter->select_item_component( it, batch_size, map_inv, true, - filter ); + comp_selection is = + crafter->select_item_component( it, batch_size, map_inv, true, filter ); if( is.use_from == cancel ) { return; } @@ -228,7 +238,7 @@ item craft_command::create_in_progress_craft() return item(); } - const auto filter = rec->get_component_filter(); + const auto filter = rec->get_component_filter( flags ); for( const auto &it : item_selections ) { std::list tmp = crafter->consume_items( it, batch_size, filter ); @@ -273,7 +283,7 @@ std::vector> craft_command::check_item_components_miss { std::vector> missing; - const auto filter = rec->get_component_filter(); + const auto filter = rec->get_component_filter( flags ); for( const auto &item_sel : item_selections ) { itype_id type = item_sel.comp.type; diff --git a/src/craft_command.h b/src/craft_command.h index a0071e8e41634..ac38b16a9350e 100644 --- a/src/craft_command.h +++ b/src/craft_command.h @@ -6,6 +6,7 @@ #include #include "point.h" +#include "recipe.h" #include "requirements.h" class inventory; @@ -96,6 +97,8 @@ class craft_command // This is mainly here for maintainability reasons. player *crafter; + recipe_filter_flags flags = recipe_filter_flags::none; + // Location of the workbench to place the item on // zero_tripoint indicates crafting without a workbench tripoint loc = tripoint_zero; diff --git a/src/crafting.cpp b/src/crafting.cpp index 65e81f1b2aff0..e91141033871d 100644 --- a/src/crafting.cpp +++ b/src/crafting.cpp @@ -482,7 +482,7 @@ bool player::can_make( const recipe *r, int batch_size ) batch_size ); } -bool player::can_start_craft( const recipe *rec, int batch_size ) +bool player::can_start_craft( const recipe *rec, recipe_filter_flags flags, int batch_size ) { if( !rec ) { return false; @@ -525,7 +525,8 @@ bool player::can_start_craft( const recipe *rec, int batch_size ) rec->requirements().get_qualities(), adjusted_comp_reqs ); - return start_reqs.can_make_with_inventory( crafting_inventory(), rec->get_component_filter() ); + return start_reqs.can_make_with_inventory( crafting_inventory(), + rec->get_component_filter( flags ) ); } const inventory &player::crafting_inventory( bool clear_path ) @@ -1254,7 +1255,9 @@ bool player::can_continue_craft( item &craft ) // Avoid building an inventory from the map if we don't have to, as it is expensive if( !continue_reqs.is_empty() ) { - const std::function filter = rec.get_component_filter(); + std::function filter = rec.get_component_filter(); + const std::function no_rotten_filter = + rec.get_component_filter( recipe_filter_flags::no_rotten ); // continue_reqs are for all batches at once const int batch_size = 1; @@ -1273,6 +1276,16 @@ bool player::can_continue_craft( item &craft ) return false; } + if( continue_reqs.can_make_with_inventory( crafting_inventory(), no_rotten_filter, + batch_size ) ) { + filter = no_rotten_filter; + } else { + if( !query_yn( _( "Some components required to continue are rotten.\n" + "Continue crafting anyway?" ) ) ) { + return false; + } + } + inventory map_inv; map_inv.form_from_map( pos(), PICKUP_RANGE, this ); diff --git a/src/crafting_gui.cpp b/src/crafting_gui.cpp index 41c7f84b3ee10..d3b055b0704b9 100644 --- a/src/crafting_gui.cpp +++ b/src/crafting_gui.cpp @@ -192,7 +192,26 @@ const recipe *select_crafting_recipe( int &batch_size ) list_circularizer tab( craft_cat_list ); list_circularizer subtab( craft_subcat_list[tab.cur()] ); std::vector current; - std::vector available; + + struct availability { + availability( const recipe *r, int batch_size = 1 ) : + can_craft( g->u.can_start_craft( r, recipe_filter_flags::none, batch_size ) ), + can_craft_non_rotten( g->u.can_start_craft( r, recipe_filter_flags::no_rotten, + batch_size ) ) + {} + bool can_craft; + bool can_craft_non_rotten; + + nc_color selected_color() const { + return can_craft ? can_craft_non_rotten ? h_white : h_brown : h_dark_gray; + } + + nc_color color() const { + return can_craft ? can_craft_non_rotten ? c_white : c_brown : c_dark_gray; + } + }; + + std::vector available; const int componentPrintHeight = dataHeight - tailHeight - 1; //preserves component color printout between mode rotations nc_color rotated_color = c_white; @@ -237,7 +256,7 @@ const recipe *select_crafting_recipe( int &batch_size ) std::string filterstring; const auto &available_recipes = g->u.get_available_recipes( crafting_inv, &helpers ); - std::map availability_cache; + std::map availability_cache; do { if( redraw ) { @@ -264,7 +283,7 @@ const recipe *select_crafting_recipe( int &batch_size ) current.clear(); for( int i = 1; i <= 20; i++ ) { current.push_back( chosen ); - available.push_back( g->u.can_start_craft( chosen, i ) ); + available.push_back( availability( chosen, i ) ); } } else { std::vector picking; @@ -363,23 +382,26 @@ const recipe *select_crafting_recipe( int &batch_size ) // cache recipe availability on first display for( const auto e : current ) { if( !availability_cache.count( e ) ) { - availability_cache.emplace( e, g->u.can_start_craft( e ) ); + availability_cache.emplace( e, availability( e ) ); } } if( subtab.cur() != "CSC_*_RECENT" ) { - std::stable_sort( current.begin(), current.end(), []( const recipe * a, const recipe * b ) { + std::stable_sort( current.begin(), current.end(), + []( const recipe * a, const recipe * b ) { return b->difficulty < a->difficulty; } ); - std::stable_sort( current.begin(), current.end(), [&]( const recipe * a, const recipe * b ) { - return availability_cache[a] && !availability_cache[b]; + std::stable_sort( current.begin(), current.end(), + [&]( const recipe * a, const recipe * b ) { + return availability_cache.at( a ).can_craft && + !availability_cache.at( b ).can_craft; } ); } std::transform( current.begin(), current.end(), std::back_inserter( available ), [&]( const recipe * e ) { - return availability_cache[e]; + return availability_cache.at( e ); } ); } @@ -443,13 +465,8 @@ const recipe *select_crafting_recipe( int &batch_size ) tmp_name = string_format( _( "%2dx %s" ), i + 1, tmp_name ); } mvwprintz( w_data, point( 2, i - recmin ), c_dark_gray, "" ); // Clear the line - if( i == line ) { - mvwprintz( w_data, point( 2, i - recmin ), ( available[i] ? h_white : h_dark_gray ), - utf8_truncate( tmp_name, 28 ) ); - } else { - mvwprintz( w_data, point( 2, i - recmin ), ( available[i] ? c_white : c_dark_gray ), - utf8_truncate( tmp_name, 28 ) ); - } + nc_color col = i == line ? available[i].selected_color() : available[i].color(); + mvwprintz( w_data, point( 2, i - recmin ), col, utf8_truncate( tmp_name, 28 ) ); } } else if( line >= recmax - dataHalfLines ) { for( int i = recmax - dataLines; i < recmax; ++i ) { @@ -458,15 +475,9 @@ const recipe *select_crafting_recipe( int &batch_size ) tmp_name = string_format( _( "%2dx %s" ), i + 1, tmp_name ); } mvwprintz( w_data, point( 2, dataLines + i - recmax ), c_light_gray, "" ); // Clear the line - if( i == line ) { - mvwprintz( w_data, point( 2, dataLines + i - recmax ), - ( available[i] ? h_white : h_dark_gray ), - utf8_truncate( tmp_name, 28 ) ); - } else { - mvwprintz( w_data, point( 2, dataLines + i - recmax ), - ( available[i] ? c_white : c_dark_gray ), - utf8_truncate( tmp_name, 28 ) ); - } + nc_color col = i == line ? available[i].selected_color() : available[i].color(); + mvwprintz( w_data, point( 2, dataLines + i - recmax ), col, + utf8_truncate( tmp_name, 28 ) ); } } else { for( int i = line - dataHalfLines; i < line - dataHalfLines + dataLines; ++i ) { @@ -475,37 +486,26 @@ const recipe *select_crafting_recipe( int &batch_size ) tmp_name = string_format( _( "%2dx %s" ), i + 1, tmp_name ); } mvwprintz( w_data, point( 2, dataHalfLines + i - line ), c_light_gray, "" ); // Clear the line - if( i == line ) { - mvwprintz( w_data, point( 2, dataHalfLines + i - line ), - ( available[i] ? h_white : h_dark_gray ), - utf8_truncate( tmp_name, 28 ) ); - } else { - mvwprintz( w_data, point( 2, dataHalfLines + i - line ), - ( available[i] ? c_white : c_dark_gray ), - utf8_truncate( tmp_name, 28 ) ); - } + nc_color col = i == line ? available[i].selected_color() : available[i].color(); + mvwprintz( w_data, point( 2, dataHalfLines + i - line ), col, + utf8_truncate( tmp_name, 28 ) ); } } } else { - for( size_t i = 0; i < current.size() && i < static_cast( dataHeight ) + 1; ++i ) { + for( int i = 0; i < static_cast( current.size() ) && i < dataHeight + 1; ++i ) { std::string tmp_name = current[i]->result_name(); if( batch ) { - tmp_name = string_format( _( "%2dx %s" ), static_cast( i ) + 1, tmp_name ); - } - if( static_cast( i ) == line ) { - mvwprintz( w_data, point( 2, i ), ( available[i] ? h_white : h_dark_gray ), - utf8_truncate( tmp_name, 28 ) ); - } else { - mvwprintz( w_data, point( 2, i ), ( available[i] ? c_white : c_dark_gray ), - utf8_truncate( tmp_name, 28 ) ); + tmp_name = string_format( _( "%2dx %s" ), i + 1, tmp_name ); } + nc_color col = i == line ? available[i].selected_color() : available[i].color(); + mvwprintz( w_data, point( 2, i ), col, utf8_truncate( tmp_name, 28 ) ); } } if( !current.empty() ) { int pane = FULL_SCREEN_WIDTH - 30 - 1; int count = batch ? line + 1 : 1; // batch size - nc_color col = available[ line ] ? c_white : c_light_gray; + nc_color col = available[ line ].color(); const auto &req = current[ line ]->requirements(); @@ -599,6 +599,10 @@ const recipe *select_crafting_recipe( int &batch_size ) current[line]->has_flag( "BLIND_EASY" ) ? _( "Easy" ) : current[line]->has_flag( "BLIND_HARD" ) ? _( "Hard" ) : _( "Impossible" ) ) ); + if( available[line].can_craft && !available[line].can_craft_non_rotten ) { + ypos += fold_and_print( w_data, point( xpos, ypos ), pane, col, + _( "Will use rotten ingredients" ) ); + } ypos += print_items( *current[line], w_data, ypos, xpos, col, batch ? line + 1 : 1 ); } @@ -693,7 +697,7 @@ const recipe *select_crafting_recipe( int &batch_size ) } else if( action == "UP" ) { line--; } else if( action == "CONFIRM" ) { - if( available.empty() || !available[line] ) { + if( available.empty() || !available[line].can_craft ) { popup( _( "You can't do that!" ) ); } else if( !g->u.check_eligible_containers_for_crafting( *current[line], ( batch ) ? line + 1 : 1 ) ) { diff --git a/src/player.h b/src/player.h index b6f4a5d873257..469ebf77180a1 100644 --- a/src/player.h +++ b/src/player.h @@ -48,6 +48,7 @@ class map; class npc; struct pathfinding_settings; class recipe; +enum class recipe_filter_flags : int; struct islot_comestible; struct itype; class monster; @@ -1045,7 +1046,7 @@ class player : public Character * The player is not required to have enough tool charges to finish crafting, only to * complete the first step (total / 20 + total % 20 charges) */ - bool can_start_craft( const recipe *rec, int batch_size = 1 ); + bool can_start_craft( const recipe *rec, recipe_filter_flags, int batch_size = 1 ); bool making_would_work( const recipe_id &id_to_make, int batch_size ); /** diff --git a/src/recipe.cpp b/src/recipe.cpp index c17b6d77a9260..e0ac262b4ddc3 100644 --- a/src/recipe.cpp +++ b/src/recipe.cpp @@ -500,14 +500,19 @@ bool recipe::will_be_blacklisted() const return any_is_blacklisted( reqs_internal ) || any_is_blacklisted( reqs_external ); } -std::function recipe::get_component_filter() const +std::function recipe::get_component_filter( + const recipe_filter_flags flags ) const { const item result = create_result(); // Disallow crafting of non-perishables with rotten components // Make an exception for items with the ALLOW_ROTTEN flag such as seeds + const bool recipe_forbids_rotten = + result.is_food() && !result.goes_bad() && !has_flag( "ALLOW_ROTTEN" ); + const bool flags_forbid_rotten = + static_cast( flags & recipe_filter_flags::no_rotten ) && result.goes_bad(); std::function rotten_filter = return_true; - if( result.is_food() && !result.goes_bad() && !has_flag( "ALLOW_ROTTEN" ) ) { + if( recipe_forbids_rotten || flags_forbid_rotten ) { rotten_filter = []( const item & component ) { return !component.rotten(); }; diff --git a/src/recipe.h b/src/recipe.h index c5170b370e963..89374a519f572 100644 --- a/src/recipe.h +++ b/src/recipe.h @@ -21,6 +21,17 @@ class time_duration; using itype_id = std::string; // From itype.h class Character; +enum class recipe_filter_flags : int { + none = 0, + no_rotten = 1, +}; + +inline constexpr recipe_filter_flags operator&( recipe_filter_flags l, recipe_filter_flags r ) +{ + return static_cast( + static_cast( l ) & static_cast( r ) ); +} + class recipe { friend class recipe_dictionary; @@ -66,7 +77,8 @@ class recipe // recipe finalization happens bool will_be_blacklisted() const; - std::function get_component_filter() const; + std::function get_component_filter( + recipe_filter_flags = recipe_filter_flags::none ) const; /** Prevent this recipe from ever being added to the player's learned recipies ( used for special NPC crafting ) */ bool never_learn = false; From a85a02a25a1683bb708c154618d39c1b2954e3f2 Mon Sep 17 00:00:00 2001 From: Fris0uman <41293484+Fris0uman@users.noreply.github.com> Date: Thu, 2 Jan 2020 08:41:04 +0100 Subject: [PATCH 18/31] Jsonize autodoc couch (#36200) --- .../furniture-medical.json | 4 ++-- doc/JSON_FLAGS.md | 3 +++ src/activity_handlers.cpp | 17 ++++++++++------- src/iexamine.cpp | 8 ++++---- src/map.cpp | 6 +++--- src/map.h | 6 +++--- src/mapdata.cpp | 4 +--- src/mapdata.h | 3 +-- src/monattack.cpp | 6 ++++-- src/monmove.cpp | 8 +++++--- 10 files changed, 36 insertions(+), 29 deletions(-) diff --git a/data/json/furniture_and_terrain/furniture-medical.json b/data/json/furniture_and_terrain/furniture-medical.json index 47110a1cbbf37..94e8a09d4299b 100644 --- a/data/json/furniture_and_terrain/furniture-medical.json +++ b/data/json/furniture_and_terrain/furniture-medical.json @@ -10,7 +10,7 @@ "move_cost_mod": -1, "coverage": 35, "required_str": -1, - "flags": [ "TRANSPARENT" ], + "flags": [ "TRANSPARENT", "AUTODOC" ], "examine_action": "autodoc", "deconstruct": { "items": [ @@ -66,7 +66,7 @@ { "item": "cable", "charges": [ 1, 2 ], "prob": 50 } ] }, - "flags": [ "TRANSPARENT", "FLAMMABLE_ASH", "ORGANIC", "BLOCKSDOOR", "MOUNTABLE" ], + "flags": [ "TRANSPARENT", "FLAMMABLE_ASH", "ORGANIC", "BLOCKSDOOR", "MOUNTABLE", "AUTODOC_COUCH" ], "bash": { "str_min": 10, "str_max": 40, diff --git a/doc/JSON_FLAGS.md b/doc/JSON_FLAGS.md index 714af7fe74781..a86e1ba5f0257 100644 --- a/doc/JSON_FLAGS.md +++ b/doc/JSON_FLAGS.md @@ -598,6 +598,7 @@ List of known flags, used in both `terrain.json` and `furniture.json`. ### Examine Actions - ```aggie_plant``` Harvest plants. +- ```autodoc``` Brings the autodoc consoles menu. Needs the ```AUTODOC``` flag to function properly and an adjacent furniture with the ```AUTODOC_COUCH``` flag. - ```autoclave_empty``` Start the autoclave cycle if it contains filthy CBM, and the player has enough water. - ```autoclave_full``` Check on the progress of the cycle, and collect sterile CBM once cycle is completed. - ```bars``` Take advantage of AMORPHOUS and slip through the bars. @@ -640,6 +641,8 @@ List of known flags, used in both `terrain.json` and `furniture.json`. ### Furniture Only +- ```AUTODOC``` This furniture can be an autodoc console, it also needs the ```autodoc``` examine action. +- ```AUTODOC_COUCH``` This furniture can be a couch for a furniture with the ```autodoc``` examine action. - ```BLOCKSDOOR``` This will boost map terrain's resistance to bashing if `str_*_blocked` is set (see `map_bash_info`) diff --git a/src/activity_handlers.cpp b/src/activity_handlers.cpp index 23dfeef0e0d57..183cc2564e561 100644 --- a/src/activity_handlers.cpp +++ b/src/activity_handlers.cpp @@ -115,6 +115,9 @@ static const efftype_id effect_controlled( "controlled" ); static const trait_id trait_ILLITERATE( "ILLITERATE" ); +static const std::string flag_AUTODOC( "AUTODOC" ); +static const std::string flag_AUTODOC_COUCH( "AUTODOC_COUCH" ); + using namespace activity_handlers; const std::map< activity_id, std::function > @@ -3153,10 +3156,10 @@ void activity_handlers::operation_do_turn( player_activity *act, player *p ) time_duration time_left = time_duration::from_turns( act->moves_left / 100 ) ; if( autodoc && g->m.inbounds( p->pos() ) ) { - const std::list autodocs = g->m.find_furnitures_in_radius( p->pos(), 1, - furn_str_id( "f_autodoc" ) ); + const std::list autodocs = g->m.find_furnitures_with_flag_in_radius( p->pos(), 1, + flag_AUTODOC ); - if( g->m.furn( p->pos() ) != furn_str_id( "f_autodoc_couch" ) || autodocs.empty() ) { + if( !g->m.has_flag_furn( flag_AUTODOC_COUCH, p->pos() ) || autodocs.empty() ) { p->remove_effect( effect_under_op ); act->set_to_null(); @@ -3294,8 +3297,8 @@ void activity_handlers::operation_finish( player_activity *act, player *p ) if( act->values[1] > 0 ) { add_msg( m_good, _( "The Autodoc returns to its resting position after successfully performing the operation." ) ); - const std::list autodocs = g->m.find_furnitures_in_radius( p->pos(), 1, - furn_str_id( "f_autodoc" ) ); + const std::list autodocs = g->m.find_furnitures_with_flag_in_radius( p->pos(), 1, + flag_AUTODOC ); sounds::sound( autodocs.front(), 10, sounds::sound_t::music, _( "a short upbeat jingle: \"Operation successful\"" ), true, "Autodoc", @@ -3303,8 +3306,8 @@ void activity_handlers::operation_finish( player_activity *act, player *p ) } else { add_msg( m_bad, _( "The Autodoc jerks back to its resting position after failing the operation." ) ); - const std::list autodocs = g->m.find_furnitures_in_radius( p->pos(), 1, - furn_str_id( "f_autodoc" ) ); + const std::list autodocs = g->m.find_furnitures_with_flag_in_radius( p->pos(), 1, + flag_AUTODOC ); sounds::sound( autodocs.front(), 10, sounds::sound_t::music, _( "a sad beeping noise: \"Operation failed\"" ), true, "Autodoc", diff --git a/src/iexamine.cpp b/src/iexamine.cpp index 204d4a4ed327b..87c3bf084fea0 100644 --- a/src/iexamine.cpp +++ b/src/iexamine.cpp @@ -125,6 +125,8 @@ static const trait_id trait_THRESH_MARLOSS( "THRESH_MARLOSS" ); static const trait_id trait_THRESH_MYCUS( "THRESH_MYCUS" ); static const trap_str_id tr_unfinished_construction( "tr_unfinished_construction" ); +static const std::string flag_AUTODOC_COUCH( "AUTODOC_COUCH" ); + static void pick_plant( player &p, const tripoint &examp, const std::string &itemType, ter_id new_ter, bool seeds = false ); @@ -4285,8 +4287,7 @@ static player &player_on_couch( player &p, const tripoint &autodoc_loc, player & bool &adjacent_couch, tripoint &couch_pos ) { for( const auto &couch_loc : g->m.points_in_radius( autodoc_loc, 1 ) ) { - const furn_str_id couch( "f_autodoc_couch" ); - if( g->m.furn( couch_loc ) == couch ) { + if( g->m.has_flag_furn( flag_AUTODOC_COUCH, couch_loc ) ) { adjacent_couch = true; couch_pos = couch_loc; if( p.pos() == couch_loc ) { @@ -4306,8 +4307,7 @@ static Character &operator_present( Character &p, const tripoint &autodoc_loc, Character &null_patient ) { for( const auto &loc : g->m.points_in_radius( autodoc_loc, 1 ) ) { - const furn_str_id couch( "f_autodoc_couch" ); - if( g->m.furn( loc ) != couch ) { + if( !g->m.has_flag_furn( flag_AUTODOC_COUCH, loc ) ) { if( p.pos() == loc ) { return p; } diff --git a/src/map.cpp b/src/map.cpp index 1653f0ad162a7..0fc4fe6f20b3c 100644 --- a/src/map.cpp +++ b/src/map.cpp @@ -8180,13 +8180,13 @@ std::list map::get_active_items_in_radius( const tripoint ¢er return result; } -std::list map::find_furnitures_in_radius( const tripoint ¢er, size_t radius, - furn_id target, +std::list map::find_furnitures_with_flag_in_radius( const tripoint ¢er, size_t radius, + const std::string &flag, size_t radiusz ) { std::list furn_locs; for( const auto &furn_loc : points_in_radius( center, radius, radiusz ) ) { - if( furn( furn_loc ) == target ) { + if( has_flag_furn( flag, furn_loc ) ) { furn_locs.push_back( furn_loc ); } } diff --git a/src/map.h b/src/map.h index 904abbd913b51..e295c04501ccd 100644 --- a/src/map.h +++ b/src/map.h @@ -1807,9 +1807,9 @@ class map std::list get_active_items_in_radius( const tripoint ¢er, int radius, special_item_type type ) const; - /**returns positions of furnitures matching target in the specified radius*/ - std::list find_furnitures_in_radius( const tripoint ¢er, size_t radius, - furn_id target, + /**returns positions of furnitures with matching flag in the specified radius*/ + std::list find_furnitures_with_flag_in_radius( const tripoint ¢er, size_t radius, + const std::string &flag, size_t radiusz = 0 ); /**returns creatures in specified radius*/ std::list get_creatures_in_radius( const tripoint ¢er, size_t radius, diff --git a/src/mapdata.cpp b/src/mapdata.cpp index 6ac4e396e74cb..d9579265ff03f 100644 --- a/src/mapdata.cpp +++ b/src/mapdata.cpp @@ -952,8 +952,7 @@ furn_id f_null, f_brazier, f_firering, f_tourist_table, - f_camp_chair, - f_autodoc_couch; + f_camp_chair; void set_furn_ids() { @@ -1065,7 +1064,6 @@ void set_furn_ids() f_wind_mill_active = furn_id( "f_wind_mill_active" ); f_robotic_arm = furn_id( "f_robotic_arm" ); f_brazier = furn_id( "f_brazier" ); - f_autodoc_couch = furn_id( "f_autodoc_couch" ); f_firering = furn_id( "f_firering" ); f_tourist_table = furn_id( "f_tourist_table" ); f_camp_chair = furn_id( "f_camp_chair" ); diff --git a/src/mapdata.h b/src/mapdata.h index 2862e3ce9c1c5..864f5a17640e0 100644 --- a/src/mapdata.h +++ b/src/mapdata.h @@ -550,8 +550,7 @@ extern furn_id f_null, f_brazier, f_firering, f_tourist_table, - f_camp_chair, - f_autodoc_couch; + f_camp_chair; /////////////////////////////////////////////////////////////////////////////////////////////////////////////////// //// These are on their way OUT and only used in certain switch statements until they are rewritten. diff --git a/src/monattack.cpp b/src/monattack.cpp index 6ddb8041dc083..d4e182667ef3f 100644 --- a/src/monattack.cpp +++ b/src/monattack.cpp @@ -164,6 +164,8 @@ static const trait_id trait_TAIL_CATTLE( "TAIL_CATTLE" ); static const trait_id trait_THRESH_MARLOSS( "THRESH_MARLOSS" ); static const trait_id trait_THRESH_MYCUS( "THRESH_MYCUS" ); +static const std::string flag_AUTODOC_COUCH( "AUTODOC_COUCH" ); + // shared utility functions static bool within_visual_range( monster *z, int max_range ) { @@ -2951,8 +2953,8 @@ bool mattack::nurse_operate( monster *z ) z->friendly = 0; z->anger = 100; - std::list couch_pos = g->m.find_furnitures_in_radius( z->pos(), 10, - furn_id( "f_autodoc_couch" ) ) ; + std::list couch_pos = g->m.find_furnitures_with_flag_in_radius( z->pos(), 10, + flag_AUTODOC_COUCH ) ; if( couch_pos.empty() ) { add_msg( m_info, _( "The %s looks for something but doesn't seem to find it." ), z->name() ); diff --git a/src/monmove.cpp b/src/monmove.cpp index 16ba4eb4eb80e..7b239b3fa9b61 100644 --- a/src/monmove.cpp +++ b/src/monmove.cpp @@ -62,6 +62,8 @@ static const efftype_id effect_harnessed( "harnessed" ); static const species_id ZOMBIE( "ZOMBIE" ); +static const std::string flag_AUTODOC_COUCH( "AUTODOC_COUCH" ); + bool monster::wander() { return ( goal == pos() ); @@ -486,8 +488,8 @@ void monster::plan() bool found_path_to_couch = false; tripoint tmp( pos() + point( 12, 12 ) ); tripoint couch_loc; - for( const auto &couch_pos : g->m.find_furnitures_in_radius( pos(), 10, - furn_id( "f_autodoc_couch" ) ) ) { + for( const auto &couch_pos : g->m.find_furnitures_with_flag_in_radius( pos(), 10, + flag_AUTODOC_COUCH ) ) { if( g->m.clear_path( pos(), couch_pos, 10, 0, 100 ) ) { if( rl_dist( pos(), couch_pos ) < rl_dist( pos(), tmp ) ) { tmp = couch_pos; @@ -971,7 +973,7 @@ void monster::nursebot_operate( player *dragged_foe ) return; } - if( rl_dist( pos(), goal ) == 1 && g->m.furn( goal ) == furn_id( "f_autodoc_couch" ) && + if( rl_dist( pos(), goal ) == 1 && !g->m.has_flag_furn( flag_AUTODOC_COUCH, goal ) && !has_effect( effect_operating ) ) { if( dragged_foe->has_effect( effect_grabbed ) && !has_effect( effect_countdown ) && ( g->critter_at( goal ) == nullptr || g->critter_at( goal ) == dragged_foe ) ) { From efa31beac63fae312dc4ea6e6485afe182cf88ac Mon Sep 17 00:00:00 2001 From: Maleclypse <54345792+Maleclypse@users.noreply.github.com> Date: Thu, 2 Jan 2020 02:42:52 -0500 Subject: [PATCH 19/31] Aftershock errors to be fixed (#36425) --- data/mods/Aftershock/items/afs_bioparts.json | 14 +++++++----- data/mods/Aftershock/items/afs_tools.json | 19 ++++++++++++---- data/mods/Aftershock/items/ammo.json | 22 +++++++++++++++++++ data/mods/Aftershock/items/ammo_type.json | 8 +++++++ .../recipes/afs_deconstruction.json | 1 + 5 files changed, 54 insertions(+), 10 deletions(-) create mode 100644 data/mods/Aftershock/items/ammo.json create mode 100644 data/mods/Aftershock/items/ammo_type.json diff --git a/data/mods/Aftershock/items/afs_bioparts.json b/data/mods/Aftershock/items/afs_bioparts.json index 4a98739889e9d..ba2c72d0aa7c6 100644 --- a/data/mods/Aftershock/items/afs_bioparts.json +++ b/data/mods/Aftershock/items/afs_bioparts.json @@ -89,24 +89,26 @@ "looks_like": "ar15", "type": "GUN", "name": "vibrating bioblaster", - "name_plural": "bioblasters", - "description": "You ripped this from a mi-go abomination. You have no clue how or if it can be reloaded. ", + "name_plural": "vibrating bioblasters", + "description": "You ripped this from a mi-go abomination. You think you should wear gloves to reload it. ", "weight": "5140 g", "volume": "1500 ml", "price": 400000, + "ammo": "acidic_bore", "to_hit": -1, "bashing": 4, "material": [ "alien_resin" ], "symbol": "(", "color": "magenta", - "skill": "rifle", + "skill": "launcher", "range": 30, - "ranged_damage": 16, + "ranged_damage": 19, "pierce": 12, "dispersion": 90, "durability": 7, - "loudness": 8, - "ammo_effects": [ "LASER", "INCENDIARY" ], + "loudness": 4, + "clip_size": 80, + "ammo_effects": "ACID", "flags": [ "NO_UNLOAD", "NON-FOULING" ] } ] diff --git a/data/mods/Aftershock/items/afs_tools.json b/data/mods/Aftershock/items/afs_tools.json index 16a71330921f9..b712de69f5d4b 100644 --- a/data/mods/Aftershock/items/afs_tools.json +++ b/data/mods/Aftershock/items/afs_tools.json @@ -19,9 +19,21 @@ "active": true, "type": "transform" }, - "CAMERA" + "CAMERA", + "MP3" ], - "flags": [ "WATCH", "ALARMCLOCK" ] + "flags": [ "WATCH", "ALARMCLOCK", "NO_UNLOAD", "NO_RELOAD" ] + }, + { + "id": "afs_atomic_smartphone_music", + "copy-from": "afs_atomic_smartphone", + "type": "TOOL", + "name": "atomic smartphone - music", + "name_plural": "atomic smartphones - music", + "description": "This phone is playing music, steadily raising your morale. You can't hear anything else while you're listening.", + "revert_to": "afs_atomic_smartphone", + "use_action": "MP3_ON", + "flags": [ "WATCH", "TRADER_AVOID", "ALARMCLOCK", "NO_UNLOAD", "NO_RELOAD" ] }, { "id": "afs_atomic_smartphone_flashlight", @@ -36,8 +48,7 @@ "menu_text": "Turn off flashlight", "type": "transform" }, - "//": "since we cost no battery, no reason not to keep these", - "flags": [ "WATCH", "ALARMCLOCK", "LIGHT_25" ] + "flags": [ "WATCH", "LIGHT_25", "CHARGEDIM", "TRADER_AVOID", "ALARMCLOCK", "NO_UNLOAD", "NO_RELOAD" ] }, { "id": "afs_wraitheon_smartphone", diff --git a/data/mods/Aftershock/items/ammo.json b/data/mods/Aftershock/items/ammo.json new file mode 100644 index 0000000000000..6e73f36a4d428 --- /dev/null +++ b/data/mods/Aftershock/items/ammo.json @@ -0,0 +1,22 @@ +[ + { + "type": "AMMO", + "id": "acidic_bore", + "price": 10000, + "price_postapoc": 500, + "name": "acidic bore", + "symbol": "=", + "color": "red", + "description": "This wriggling nodule of resin and flesh appears to be secreting a pungent fluid. You'd probably best feed it into the bioblaster. ", + "material": "alien_resin", + "volume": "250 ml", + "weight": "1 g", + "ammo_type": "acidic_bore", + "damage": 5, + "dispersion": 100, + "count": 80, + "stack_size": 80, + "loudness": 9, + "effects": "NEVER_MISFIRES" + } +] diff --git a/data/mods/Aftershock/items/ammo_type.json b/data/mods/Aftershock/items/ammo_type.json new file mode 100644 index 0000000000000..6c70202a19ba2 --- /dev/null +++ b/data/mods/Aftershock/items/ammo_type.json @@ -0,0 +1,8 @@ +[ + { + "type": "ammunition_type", + "id": "acidic_bore", + "name": "acidic bore", + "default": "acidic_bore" + } +] diff --git a/data/mods/Aftershock/recipes/afs_deconstruction.json b/data/mods/Aftershock/recipes/afs_deconstruction.json index 9114be0f469b5..66ecf088bae9e 100644 --- a/data/mods/Aftershock/recipes/afs_deconstruction.json +++ b/data/mods/Aftershock/recipes/afs_deconstruction.json @@ -12,6 +12,7 @@ [ [ "brain", 4 ] ], [ [ "mutant_meat", 12 ] ], [ [ "vibrating_blaster", 1 ] ], + [ [ "acidic_bore", 60 ] ], [ [ "humming_heart", 1 ] ], [ [ "sensory_cluster", 1 ] ], [ [ "bioweapon_chassis", 1 ] ] From d2e8c2509eecccdd6c2732e021b7b2c5ee47a962 Mon Sep 17 00:00:00 2001 From: 8street Date: Thu, 2 Jan 2020 10:44:56 +0300 Subject: [PATCH 20/31] Fix extended pickup window (#36593) --- src/pickup.cpp | 9 ++++++--- 1 file changed, 6 insertions(+), 3 deletions(-) diff --git a/src/pickup.cpp b/src/pickup.cpp index 288ea626d3f7b..73d76bf4df594 100644 --- a/src/pickup.cpp +++ b/src/pickup.cpp @@ -622,6 +622,7 @@ void Pickup::pick_up( const tripoint &p, int min, from_where get_items_from ) int selected = 0; int iScrollPos = 0; + std::string clear_buffer( pickupW, ' ' ); std::string filter; std::string new_filter; // Indexes of items that match the filter @@ -636,10 +637,12 @@ void Pickup::pick_up( const tripoint &p, int min, from_where get_items_from ) const std::string pickup_chars = ctxt.get_available_single_char_hotkeys( "abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ:;" ); int idx = -1; - for( int i = 1; i < pickupH; i++ ) { - mvwprintw( w_pickup, point( 0, i ), - " " ); + + //clear all items names + for( int cur_row = 1; cur_row < pickupH; cur_row++ ) { + mvwprintw( w_pickup, point( 0, cur_row ), clear_buffer ); } + if( action == "ANY_INPUT" && raw_input_char >= '0' && raw_input_char <= '9' ) { int raw_input_char_value = static_cast( raw_input_char ) - '0'; From 3399e371fb72931c81a11ec8e310b58be9dac0cd Mon Sep 17 00:00:00 2001 From: Matthew Taylor Date: Thu, 2 Jan 2020 07:48:09 +0000 Subject: [PATCH 21/31] Add items, update military pilot drops (#36558) --- data/json/itemgroups/clothing.json | 31 +++++++++++++------ data/json/items/armor/ballistic_armor.json | 22 +++++++++++++ data/json/items/armor/belts.json | 16 ++++++++++ .../monsterdrops/zombie_military_pilot.json | 12 +++---- data/json/monsterdrops/zombie_soldier.json | 2 +- 5 files changed, 66 insertions(+), 17 deletions(-) create mode 100644 data/json/items/armor/ballistic_armor.json create mode 100644 data/json/items/armor/belts.json diff --git a/data/json/itemgroups/clothing.json b/data/json/itemgroups/clothing.json index 15d24bf031e2e..25efe933f40e8 100644 --- a/data/json/itemgroups/clothing.json +++ b/data/json/itemgroups/clothing.json @@ -96,19 +96,21 @@ { "item": "jacket_army" }, { "item": "elbow_pads", "prob": 10 }, { "item": "pants_army" }, + { "item": "webbing_belt" }, { "item": "knee_pads", "prob": 85 }, + { "distribution": [ { "item": "socks", "prob": 95 }, { "item": "socks_wool", "prob": 5 } ] }, { "item": "boots_combat" }, { "item": "helmet_army", "prob": 80 }, { "item": "gloves_tactical", "prob": 60 }, + { "item": "ballistic_vest", "prob": 90 }, + { "item": "molle_pack", "prob": 85 }, { "group": "clothing_tactical_leg", "prob": 15 }, - { "group": "clothing_tactical_torso", "prob": 15 }, { "distribution": [ { "collection": [ { "item": "sports_bra" }, { "item": "boy_shorts" } ] }, { "distribution": [ { "item": "briefs" }, { "item": "boxer_briefs" }, { "item": "boxer_shorts" } ] } ] }, - { "distribution": [ { "item": "socks", "prob": 95 }, { "item": "socks_wool", "prob": 5 } ] }, { "distribution": [ { "group": "clothing_glasses", "prob": 60 }, @@ -131,19 +133,21 @@ { "item": "winter_jacket_army" }, { "item": "elbow_pads", "prob": 10 }, { "item": "winter_pants_army" }, + { "item": "webbing_belt" }, { "item": "knee_pads", "prob": 85 }, + { "distribution": [ { "item": "socks", "prob": 10 }, { "item": "socks_wool", "prob": 90 } ] }, { "item": "boots_combat" }, { "collection": [ { "item": "helmet_army" }, { "item": "helmet_liner" } ], "prob": 80 }, - { "collection": [ { "item": "gloves_liner" }, { "item": "winter_gloves_army" } ], "prob": 80 }, + { "collection": [ { "item": "gloves_liner", "prob": 60 }, { "item": "winter_gloves_army" } ], "prob": 80 }, + { "item": "ballistic_vest", "prob": 90 }, + { "item": "molle_pack", "prob": 85 }, { "group": "clothing_tactical_leg", "prob": 15 }, - { "group": "clothing_tactical_torso", "prob": 15 }, { "distribution": [ { "collection": [ { "item": "sports_bra" }, { "item": "boy_shorts" } ] }, { "distribution": [ { "item": "briefs" }, { "item": "boxer_briefs" }, { "item": "boxer_shorts" } ] } ] }, - { "distribution": [ { "item": "socks", "prob": 10 }, { "item": "socks_wool", "prob": 90 } ] }, { "distribution": [ { "group": "clothing_glasses", "prob": 60 }, @@ -162,13 +166,20 @@ "subtype": "collection", "//": "Standard set of clothes worn by a military helicopter pilot.", "items": [ - { "distribution": [ { "item": "longshirt", "prob": 75 }, { "item": "tshirt", "prob": 25 } ] }, + { "group": "clothing_soldier_shirt" }, { "item": "jacket_army" }, { "item": "pants_army" }, + { "item": "webbing_belt" }, + { "distribution": [ { "item": "socks", "prob": 95 }, { "item": "socks_wool", "prob": 5 } ] }, { "item": "boots_combat" }, - { "collection": [ { "item": "helmet_army" }, { "item": "helmet_liner" } ] }, - { "group": "underwear" }, - { "distribution": [ { "item": "socks", "prob": 10 }, { "item": "socks_wool", "prob": 90 } ] }, + { "item": "helmet_army", "prob": 80 }, + { "item": "gloves_tactical", "prob": 60 }, + { + "distribution": [ + { "collection": [ { "item": "sports_bra" }, { "item": "boy_shorts" } ] }, + { "distribution": [ { "item": "briefs" }, { "item": "boxer_briefs" }, { "item": "boxer_shorts" } ] } + ] + }, { "distribution": [ { "item": "fancy_sunglasses", "prob": 95 }, { "item": "glasses_bal", "prob": 5 } ] }, { "group": "clothing_watch", "prob": 85 }, { "item": "goggles_ir", "prob": 10 } @@ -178,7 +189,7 @@ "id": "clothing_soldier_shirt", "type": "item_group", "subtype": "distribution", - "entries": [ { "item": "army_top", "prob": 50 }, { "item": "longshirt", "prob": 40 }, { "item": "tshirt", "prob": 20 } ] + "entries": [ { "item": "tshirt" } ] }, { "id": "clothing_outdoor_pants", diff --git a/data/json/items/armor/ballistic_armor.json b/data/json/items/armor/ballistic_armor.json new file mode 100644 index 0000000000000..6a7aa7f2a38d8 --- /dev/null +++ b/data/json/items/armor/ballistic_armor.json @@ -0,0 +1,22 @@ +[ + { + "id": "ballistic_vest", + "type": "ARMOR", + "category": "armor", + "//": "Based on US Army SPCS", + "name": { "str": "ballistic vest" }, + "description": "Ballistic armor with ESAPI ceramic armor plates.", + "weight": "9911 g", + "volume": "6 L", + "price": 280000, + "material": [ "nylon", "ceramic" ], + "symbol": "[", + "color": "light_gray", + "covers": [ "TORSO" ], + "coverage": 85, + "encumbrance": 10, + "warmth": 15, + "material_thickness": 20, + "flags": [ "STURDY", "OUTER", "WATER_FRIENDLY" ] + } +] diff --git a/data/json/items/armor/belts.json b/data/json/items/armor/belts.json new file mode 100644 index 0000000000000..415bf2611012b --- /dev/null +++ b/data/json/items/armor/belts.json @@ -0,0 +1,16 @@ +[ + { + "id": "webbing_belt", + "type": "ARMOR", + "name": "webbing belt", + "description": "A 2-inch nylon webbing belt commonly used by military forces.", + "weight": "210 g", + "volume": "500 ml", + "price": 1000, + "material": [ "nylon", "steel" ], + "symbol": "[", + "color": "yellow", + "covers": [ "TORSO" ], + "flags": [ "WAIST", "WATER_FRIENDLY" ] + } +] diff --git a/data/json/monsterdrops/zombie_military_pilot.json b/data/json/monsterdrops/zombie_military_pilot.json index 0df7e4cd0a742..3239bdf7e7d31 100644 --- a/data/json/monsterdrops/zombie_military_pilot.json +++ b/data/json/monsterdrops/zombie_military_pilot.json @@ -6,13 +6,13 @@ "magazine": 100, "ammo": 60, "entries": [ - { "group": "clothing_military_pilot", "prob": 65, "damage-min": 1, "damage-max": 4 }, - { "group": "gear_soldier_sidearm", "prob": 50, "damage-min": 1, "damage-max": 4 }, - { "item": "two_way_radio", "prob": 50, "damage-min": 1, "damage-max": 4 }, + { "group": "clothing_military_pilot", "damage": [ 1, 4 ] }, + { "item": "holster", "contents-group": "military_standard_pistols" }, + { "item": "two_way_radio", "prob": 90 }, { "item": "adderall", "prob": 40 }, - { "item": "id_military", "prob": 5 }, - { "item": "cash_card", "prob": 10, "charges-min": 0, "charges-max": 50000 }, - { "group": "mil_food", "prob": 15 }, + { "item": "id_military", "prob": 25 }, + { "group": "military_patrol_food", "prob": 30 }, + { "item": "cash_card", "prob": 10, "charges": [ 0, 50000 ] }, { "group": "misc_smoking", "prob": 30 } ] } diff --git a/data/json/monsterdrops/zombie_soldier.json b/data/json/monsterdrops/zombie_soldier.json index a3698aa977ff5..ab7b17f5c48f9 100644 --- a/data/json/monsterdrops/zombie_soldier.json +++ b/data/json/monsterdrops/zombie_soldier.json @@ -24,7 +24,7 @@ { "group": "military_standard_grenades", "count": [ 1, 3 ], "prob": 20 }, { "group": "military_patrol_food" }, { "distribution": [ { "group": "infantry_officer_gear" }, { "group": "infantry_medical_gear" } ], "prob": 25 }, - { "item": "cash_card", "prob": 10, "charges-min": 0, "charges-max": 50000 }, + { "item": "cash_card", "prob": 10, "charges": [ 0, 50000 ] }, { "group": "misc_smoking", "prob": 30 } ] }, From 89a7b1c0115453b20f38fb069b4337a0ae3ee2c3 Mon Sep 17 00:00:00 2001 From: BevapDin Date: Tue, 31 Dec 2019 16:45:22 +0100 Subject: [PATCH 22/31] Store crafting related item data in a separate object inside a value_ptr This reduces the overhead for non-craft items to a single pointer. --- src/crafting.cpp | 6 ++--- src/item.cpp | 43 +++++++++++++++++++-------------- src/item.h | 31 +++++++++++++++++------- src/savegame_json.cpp | 56 +++++++++++++++++++++++++++++++++---------- src/value_ptr.h | 21 ++++++++++++++++ 5 files changed, 115 insertions(+), 42 deletions(-) diff --git a/src/crafting.cpp b/src/crafting.cpp index 65e81f1b2aff0..530519df6a887 100644 --- a/src/crafting.cpp +++ b/src/crafting.cpp @@ -956,7 +956,7 @@ int item::get_next_failure_point() const debugmsg( "get_next_failure_point() called on non-craft '%s.' Aborting.", tname() ); return INT_MAX; } - return next_failure_point >= 0 ? next_failure_point : INT_MAX; + return craft_data_->next_failure_point >= 0 ? craft_data_->next_failure_point : INT_MAX; } void item::set_next_failure_point( const player &crafter ) @@ -969,7 +969,7 @@ void item::set_next_failure_point( const player &crafter ) const int percent_left = 10000000 - item_counter; const int failure_point_delta = crafter.crafting_success_roll( get_making() ) * percent_left; - next_failure_point = item_counter + failure_point_delta; + craft_data_->next_failure_point = item_counter + failure_point_delta; } static void destroy_random_component( item &craft, const player &crafter ) @@ -1036,7 +1036,7 @@ requirement_data item::get_continue_reqs() const debugmsg( "get_continue_reqs() called on non-craft '%s.' Aborting.", tname() ); return requirement_data(); } - return requirement_data::continue_requirements( comps_used, components ); + return requirement_data::continue_requirements( craft_data_->comps_used, components ); } void item::inherit_flags( const item &parent ) diff --git a/src/item.cpp b/src/item.cpp index 8a3e7a54bfd95..b2a0754892f2d 100644 --- a/src/item.cpp +++ b/src/item.cpp @@ -284,9 +284,10 @@ static const item *get_most_rotten_component( const item &craft ) item::item( const recipe *rec, int qty, std::list items, std::vector selections ) : item( "craft", calendar::turn, qty ) { - making = rec; + craft_data_ = cata::make_value(); + craft_data_->making = rec; components = items; - comps_used = selections; + craft_data_->comps_used = selections; if( is_food() ) { active = true; @@ -753,10 +754,10 @@ bool item::stacks_with( const item &rhs, bool check_components ) const if( corpse != nullptr && rhs.corpse != nullptr && corpse->id != rhs.corpse->id ) { return false; } - if( is_craft() && rhs.is_craft() ) { - if( get_making().ident() != rhs.get_making().ident() ) { - return false; - } + if( craft_data_ || rhs.craft_data_ ) { + // In-progress crafts are always distinct items. Easier to handle for the player, + // and there shouldn't be that many items of this type around anyway. + return false; } if( check_components || is_comestible() || is_craft() ) { //Only check if at least one item isn't using the default recipe or is comestible @@ -2560,7 +2561,7 @@ void item::final_info( std::vector &info, const iteminfo_query *parts, "It is %d percent complete." ); const int percent_progress = item_counter / 100000; info.push_back( iteminfo( "DESCRIPTION", string_format( desc, - making->result_name(), + craft_data_->making->result_name(), percent_progress ) ) ); } else { info.push_back( iteminfo( "DESCRIPTION", type->description.translated() ) ); @@ -3799,7 +3800,7 @@ std::string item::tname( unsigned int quantity, bool with_prefix, unsigned int t } else if( is_armor() && has_clothing_mod() ) { maintext = label( quantity ) + "+1"; } else if( is_craft() ) { - maintext = string_format( _( "in progress %s" ), making->result_name() ); + maintext = string_format( _( "in progress %s" ), craft_data_->making->result_name() ); if( charges > 1 ) { maintext += string_format( " (%d)", charges ); } @@ -5713,7 +5714,7 @@ bool item::is_brewable() const bool item::is_food_container() const { return ( !contents.empty() && contents.front().is_food() ) || ( is_craft() && - making->create_result().is_food_container() ); + craft_data_->making->create_result().is_food_container() ); } bool item::has_temperature() const @@ -6034,7 +6035,7 @@ bool item::is_salvageable() const bool item::is_craft() const { - return making != nullptr; + return craft_data_ != nullptr; } bool item::is_funnel_container( units::volume &bigger_than ) const @@ -9451,37 +9452,43 @@ void item::set_favorite( const bool favorite ) const recipe &item::get_making() const { - if( !making ) { + if( !craft_data_ ) { debugmsg( "'%s' is not a craft or has a null recipe", tname() ); - return recipe().ident().obj(); + static const recipe dummy{}; + return dummy; } - return *making; + assert( craft_data_->making ); + return *craft_data_->making; } void item::set_tools_to_continue( bool value ) { - tools_to_continue = value; + assert( craft_data_ ); + craft_data_->tools_to_continue = value; } bool item::has_tools_to_continue() const { - return tools_to_continue; + assert( craft_data_ ); + return craft_data_->tools_to_continue; } void item::set_cached_tool_selections( const std::vector> &selections ) { - cached_tool_selections = selections; + assert( craft_data_ ); + craft_data_->cached_tool_selections = selections; } const std::vector> &item::get_cached_tool_selections() const { - return cached_tool_selections; + assert( craft_data_ ); + return craft_data_->cached_tool_selections; } const cata::value_ptr &item::get_comestible() const { if( is_craft() ) { - return find_type( making->result() )->comestible; + return find_type( craft_data_->making->result() )->comestible; } else { return type->comestible; } diff --git a/src/item.h b/src/item.h index b1a5017b510bc..d54d521738b31 100644 --- a/src/item.h +++ b/src/item.h @@ -15,6 +15,7 @@ #include #include "calendar.h" +#include "value_ptr.h" #include "cata_utility.h" #include "craft_command.h" #include "debug.h" @@ -42,12 +43,11 @@ namespace cata { template class optional; -template -class value_ptr; } // namespace cata class nc_color; class JsonIn; class JsonOut; +class JsonObject; class iteminfo_query; template class ret_val; @@ -2113,13 +2113,26 @@ class item : public visitable std::string corpse_name; // Name of the late lamented std::set techniques; // item specific techniques - // Only for in-progress crafts - const recipe *making = nullptr; - int next_failure_point = -1; - std::vector comps_used; - // If the crafter has insufficient tools to continue to the next 5% progress step - bool tools_to_continue = false; - std::vector> cached_tool_selections; + /** + * Data for items that represent in-progress crafts. + */ + class craft_data + { + public: + const recipe *making = nullptr; + int next_failure_point = -1; + std::vector comps_used; + // If the crafter has insufficient tools to continue to the next 5% progress step + bool tools_to_continue = false; + std::vector> cached_tool_selections; + + void serialize( JsonOut &jsout ) const; + void deserialize( JsonIn &jsin ); + void deserialize( const JsonObject &obj ); + }; + + cata::value_ptr craft_data_; + // any relic data specific to this item cata::optional relic_data; public: diff --git a/src/savegame_json.cpp b/src/savegame_json.cpp index 3545b43368581..2003b37d29c76 100644 --- a/src/savegame_json.cpp +++ b/src/savegame_json.cpp @@ -2034,6 +2034,47 @@ void units::energy::deserialize( JsonIn &jsin ) static void migrate_toolmod( item &it ); +void item::craft_data::serialize( JsonOut &jsout ) const +{ + jsout.start_object(); + jsout.member( "making", making->ident().str() ); + jsout.member( "comps_used", comps_used ); + jsout.member( "next_failure_point", next_failure_point ); + jsout.member( "tools_to_continue", tools_to_continue ); + jsout.member( "cached_tool_selections", cached_tool_selections ); + jsout.end_object(); +} + +void item::craft_data::deserialize( JsonIn &jsin ) +{ + deserialize( jsin.get_object() ); +} + +void item::craft_data::deserialize( const JsonObject &obj ) +{ + making = &recipe_id( obj.get_string( "making" ) ).obj(); + obj.read( "comps_used", comps_used ); + next_failure_point = obj.get_int( "next_failure_point", -1 ); + tools_to_continue = obj.get_bool( "tools_to_continue", false ); + obj.read( "cached_tool_selections", cached_tool_selections ); +} + +// Template parameter because item::craft_data is private and I don't want to make it public. +template +static void load_legacy_craft_data( io::JsonObjectInputArchive &archive, T &value ) +{ + if( archive.has_member( "making" ) ) { + value = cata::make_value(); + value->deserialize( archive ); + } +} + +// Dummy function as we never load anything from an output archive. +template +static void load_legacy_craft_data( io::JsonObjectOutputArchive &, T & ) +{ +} + template void item::io( Archive &archive ) { @@ -2055,10 +2096,6 @@ void item::io( Archive &archive ) corpse = &mtype_id( id ).obj(); } }; - const auto load_making = [this]( const std::string & id ) { - making = &recipe_id( id ).obj(); - }; - archive.template io( "typeid", type, load_type, []( const itype & i ) { return i.get_id(); }, io::required_tag() ); @@ -2109,17 +2146,10 @@ void item::io( Archive &archive ) []( const mtype & i ) { return i.id.str(); } ); - archive.template io( "making", making, load_making, - []( const recipe & i ) { - return i.ident().str(); - } ); + archive.io( "craft_data", craft_data_, decltype( craft_data_ )() ); archive.io( "light", light.luminance, nolight.luminance ); archive.io( "light_width", light.width, nolight.width ); archive.io( "light_dir", light.direction, nolight.direction ); - archive.io( "comps_used", comps_used, io::empty_default_tag() ); - archive.io( "next_failure_point", next_failure_point, -1 ); - archive.io( "tools_to_continue", tools_to_continue, false ); - archive.io( "cached_tool_selections", cached_tool_selections, io::empty_default_tag() ); archive.io( "relic_data", relic_data ); @@ -2130,6 +2160,8 @@ void item::io( Archive &archive ) } /* Loading has finished, following code is to ensure consistency and fixes bugs in saves. */ + load_legacy_craft_data( archive, craft_data_ ); + double float_damage = 0; if( archive.read( "damage", float_damage ) ) { damage_ = std::min( std::max( min_damage(), diff --git a/src/value_ptr.h b/src/value_ptr.h index c9b8c98a8912e..a89c894a915e1 100644 --- a/src/value_ptr.h +++ b/src/value_ptr.h @@ -4,6 +4,9 @@ #include +class JsonIn; +class JsonOut; + namespace cata { @@ -24,6 +27,24 @@ class value_ptr : public std::unique_ptr std::unique_ptr::operator=( std::move( other ) ); return *this; } + + template + void serialize( Stream &jsout ) const { + if( this->get() ) { + this->get()->serialize( jsout ); + } else { + jsout.write_null(); + } + } + template + void deserialize( Stream &jsin ) { + if( jsin.test_null() ) { + this->reset(); + } else { + this->reset( new T() ); + this->get()->deserialize( jsin ); + } + } }; template From 304a9e87602025c20fdacde7c4136c0996dd18dc Mon Sep 17 00:00:00 2001 From: Ramza13 <52087122+Ramza13@users.noreply.github.com> Date: Tue, 31 Dec 2019 11:18:33 -0500 Subject: [PATCH 23/31] Fix description --- data/raw/keybindings.json | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/data/raw/keybindings.json b/data/raw/keybindings.json index fa035f60582b7..534461aba4e10 100644 --- a/data/raw/keybindings.json +++ b/data/raw/keybindings.json @@ -1682,7 +1682,7 @@ }, { "type": "keybinding", - "name": "Reload Wielded Item", + "name": "Reload Weapons", "category": "DEFAULTMODE", "id": "reload_weapon" }, From 9b466405335a71feabf2f243329195a72b3e5bd9 Mon Sep 17 00:00:00 2001 From: 8street Date: Thu, 2 Jan 2020 10:53:41 +0300 Subject: [PATCH 24/31] Colored title of the info window (#36612) --- src/pickup.cpp | 5 ++++- 1 file changed, 4 insertions(+), 1 deletion(-) diff --git a/src/pickup.cpp b/src/pickup.cpp index 73d76bf4df594..9a1cea86284f6 100644 --- a/src/pickup.cpp +++ b/src/pickup.cpp @@ -806,9 +806,12 @@ void Pickup::pick_up( const tripoint &p, int min, from_where get_items_from ) draw_item_info( w_item_info, dummy ); } draw_custom_border( w_item_info, 0 ); + + // print info window title: < item name > mvwprintw( w_item_info, point( 2, 0 ), "< " ); - trim_and_print( w_item_info, point( 4, 0 ), itemsW - 8, c_white, "%s >", + trim_and_print( w_item_info, point( 4, 0 ), itemsW - 8, selected_item.color_in_inventory(), selected_item.display_name() ); + wprintw( w_item_info, " >" ); wrefresh( w_item_info ); if( action == "SELECT_ALL" ) { From eab27aa984afdb682803d5362a193977c982232c Mon Sep 17 00:00:00 2001 From: ymber Date: Wed, 1 Jan 2020 14:01:20 +0000 Subject: [PATCH 25/31] Unconditionally use material thickness for armor --- src/item.cpp | 26 ++++++++++---------------- 1 file changed, 10 insertions(+), 16 deletions(-) diff --git a/src/item.cpp b/src/item.cpp index b2a0754892f2d..b83c0e9a511e6 100644 --- a/src/item.cpp +++ b/src/item.cpp @@ -5161,14 +5161,11 @@ int item::bash_resist( bool to_self ) const float mod = get_clothing_mod_val( clothing_mod_type_bash ); int eff_thickness = 1; - // Armor gets an additional multiplier. - if( is_armor() || is_pet_armor() ) { - // base resistance - // Don't give reinforced items +armor, just more resistance to ripping - const int dmg = damage_level( 4 ); - const int eff_damage = to_self ? std::min( dmg, 0 ) : std::max( dmg, 0 ); - eff_thickness = std::max( 1, get_thickness() - eff_damage ); - } + // base resistance + // Don't give reinforced items +armor, just more resistance to ripping + const int dmg = damage_level( 4 ); + const int eff_damage = to_self ? std::min( dmg, 0 ) : std::max( dmg, 0 ); + eff_thickness = std::max( 1, get_thickness() - eff_damage ); const std::vector mat_types = made_of_types(); if( !mat_types.empty() ) { @@ -5193,14 +5190,11 @@ int item::cut_resist( bool to_self ) const float mod = get_clothing_mod_val( clothing_mod_type_cut ); int eff_thickness = 1; - // Armor gets an additional multiplier. - if( is_armor() ) { - // base resistance - // Don't give reinforced items +armor, just more resistance to ripping - const int dmg = damage_level( 4 ); - const int eff_damage = to_self ? std::min( dmg, 0 ) : std::max( dmg, 0 ); - eff_thickness = std::max( 1, base_thickness - eff_damage ); - } + // base resistance + // Don't give reinforced items +armor, just more resistance to ripping + const int dmg = damage_level( 4 ); + const int eff_damage = to_self ? std::min( dmg, 0 ) : std::max( dmg, 0 ); + eff_thickness = std::max( 1, base_thickness - eff_damage ); const std::vector mat_types = made_of_types(); if( !mat_types.empty() ) { From 9b40e2ef5a232c76bd3844a1e5ab08abc38bd991 Mon Sep 17 00:00:00 2001 From: curstwist <39442864+curstwist@users.noreply.github.com> Date: Thu, 2 Jan 2020 02:55:10 -0500 Subject: [PATCH 26/31] move and rename sus bedroom item_groups (#36614) --- data/json/itemgroups/SUS/domestic.json | 100 ++++++++++++++++++ data/json/itemgroups/clothing.json | 100 ------------------ data/json/mapgen/farm_2side.json | 4 +- data/json/mapgen/nested/house_nested.json | 64 +++++------ data/json/mapgen_palettes/cabin.json | 4 +- .../mapgen_palettes/city_block_palette.json | 2 +- .../json/mapgen_palettes/house_w_palette.json | 2 +- 7 files changed, 138 insertions(+), 138 deletions(-) diff --git a/data/json/itemgroups/SUS/domestic.json b/data/json/itemgroups/SUS/domestic.json index 34b11cd597c70..949fea5d1a8f2 100644 --- a/data/json/itemgroups/SUS/domestic.json +++ b/data/json/itemgroups/SUS/domestic.json @@ -667,5 +667,105 @@ { "collection": [ { "item": "candle", "count": [ 1, 2 ] }, { "item": "matches" } ], "prob": 20 }, { "item": "toilet_paper", "prob": 80 } ] + }, + { + "id": "SUS_desks_bedroom_unisex", + "type": "item_group", + "//": "clothing and wearable items for domestic desks, tables, etc.", + "subtype": "collection", + "entries": [ + { "group": "accesories_personal_unisex", "prob": 70, "count": [ 1, 4 ] }, + { "group": "accesories_personal_womens", "prob": 50 }, + { "group": "accesories_personal_mens", "prob": 50 }, + { "group": "masks_unisex", "prob": 20 }, + { "group": "socks_unisex", "prob": 60 }, + { "group": "scarfs_unisex", "prob": 30 }, + { "group": "gloves_womens", "prob": 10 }, + { "group": "gloves_unisex", "prob": 30 }, + { "group": "hats_unisex", "prob": 50 } + ] + }, + { + "id": "SUS_wardrobe_mens", + "type": "item_group", + "//": "clothing found in a man's wardrobe", + "subtype": "collection", + "entries": [ + { "group": "shoes_unisex", "prob": 50 }, + { "item": "fishing_waders", "prob": 3 }, + { "item": "kilt", "prob": 10 }, + { "item": "football_armor", "prob": 10 }, + { "item": "sleeping_bag", "prob": 10 }, + { "item": "sleeping_bag_roll", "prob": 10 }, + { "item": "bscabbard", "prob": 5 }, + { "item": "kilt_leather", "prob": 5 }, + { "item": "chaps_leather", "prob": 5 }, + { "group": "coats_unisex", "prob": 50 }, + { "group": "suits_unisex", "prob": 30 }, + { "group": "suits_mens", "prob": 30 }, + { "group": "bags_unisex", "prob": 20 } + ] + }, + { + "id": "SUS_wardrobe_womens", + "type": "item_group", + "//": "clothing found in a woman's wardrobe", + "subtype": "collection", + "entries": [ + { "group": "shoes_unisex", "prob": 50 }, + { "group": "shoes_womens", "prob": 60 }, + { "item": "fishing_waders", "prob": 2 }, + { "item": "football_armor", "prob": 5 }, + { "item": "skirt", "prob": 20 }, + { "item": "skirt_leather", "prob": 10 }, + { "item": "bscabbard", "prob": 3 }, + { "item": "sleeping_bag", "prob": 10 }, + { "item": "sleeping_bag_roll", "prob": 10 }, + { "item": "chaps_leather", "prob": 5 }, + { "group": "coats_unisex", "prob": 50 }, + { "group": "suits_unisex", "prob": 30 }, + { "group": "suits_womens", "prob": 40 }, + { "group": "bags_unisex", "prob": 20 } + ] + }, + { + "id": "SUS_dresser_mens", + "type": "item_group", + "//": "clothing found in a man's dresser", + "subtype": "collection", + "entries": [ + { "group": "accesories_personal_unisex", "prob": 10 }, + { "group": "accesories_personal_mens", "prob": 10 }, + { "group": "masks_unisex", "prob": 5 }, + { "group": "socks_unisex", "prob": 70 }, + { "group": "scarfs_unisex", "prob": 20 }, + { "group": "shirts_unisex", "prob": 50 }, + { "group": "underwear_mens", "prob": 80 }, + { "group": "underwear_unisex", "prob": 80 }, + { "group": "pants_unisex", "prob": 50 }, + { "group": "pants_mens", "prob": 60 }, + { "group": "gloves_unisex", "prob": 20 } + ] + }, + { + "id": "SUS_dresser_womens", + "type": "item_group", + "//": "clothing found in a woman's dresser", + "subtype": "collection", + "entries": [ + { "group": "accesories_personal_unisex", "prob": 30 }, + { "group": "accesories_personal_womens", "prob": 5 }, + { "group": "masks_unisex", "prob": 5 }, + { "group": "socks_unisex", "prob": 70 }, + { "group": "scarfs_unisex", "prob": 10 }, + { "group": "shirts_womens", "prob": 60 }, + { "group": "shirts_unisex", "prob": 50 }, + { "group": "underwear_womens", "prob": 80 }, + { "group": "underwear_unisex", "prob": 80 }, + { "group": "pants_unisex", "prob": 50 }, + { "group": "pants_womens", "prob": 60 }, + { "group": "gloves_womens", "prob": 5 }, + { "group": "gloves_unisex", "prob": 30 } + ] } ] diff --git a/data/json/itemgroups/clothing.json b/data/json/itemgroups/clothing.json index 25efe933f40e8..904e54d2700f2 100644 --- a/data/json/itemgroups/clothing.json +++ b/data/json/itemgroups/clothing.json @@ -2576,106 +2576,6 @@ [ "hairpin", 15 ] ] }, - { - "id": "desks_bedroom_unisex", - "type": "item_group", - "//": "clothing and wearable items for domestic desks, tables, etc.", - "subtype": "collection", - "items": [ - { "group": "accesories_personal_unisex", "prob": 70, "count": [ 1, 4 ] }, - { "group": "accesories_personal_womens", "prob": 50 }, - { "group": "accesories_personal_mens", "prob": 50 }, - { "group": "masks_unisex", "prob": 20 }, - { "group": "socks_unisex", "prob": 60 }, - { "group": "scarfs_unisex", "prob": 30 }, - { "group": "gloves_womens", "prob": 10 }, - { "group": "gloves_unisex", "prob": 30 }, - { "group": "hats_unisex", "prob": 50 } - ] - }, - { - "id": "wardrobe_mens", - "type": "item_group", - "//": "clothing found in a man's wardrobe", - "subtype": "collection", - "items": [ - { "group": "shoes_unisex", "prob": 50 }, - { "item": "fishing_waders", "prob": 3 }, - { "item": "kilt", "prob": 10 }, - { "item": "football_armor", "prob": 10 }, - { "item": "sleeping_bag", "prob": 10 }, - { "item": "sleeping_bag_roll", "prob": 10 }, - { "item": "bscabbard", "prob": 5 }, - { "item": "kilt_leather", "prob": 5 }, - { "item": "chaps_leather", "prob": 5 }, - { "group": "coats_unisex", "prob": 50 }, - { "group": "suits_unisex", "prob": 30 }, - { "group": "suits_mens", "prob": 30 }, - { "group": "bags_unisex", "prob": 20 } - ] - }, - { - "id": "wardrobe_womens", - "type": "item_group", - "//": "clothing found in a woman's wardrobe", - "subtype": "collection", - "items": [ - { "group": "shoes_unisex", "prob": 50 }, - { "group": "shoes_womens", "prob": 60 }, - { "item": "fishing_waders", "prob": 2 }, - { "item": "football_armor", "prob": 5 }, - { "item": "skirt", "prob": 20 }, - { "item": "skirt_leather", "prob": 10 }, - { "item": "bscabbard", "prob": 3 }, - { "item": "sleeping_bag", "prob": 10 }, - { "item": "sleeping_bag_roll", "prob": 10 }, - { "item": "chaps_leather", "prob": 5 }, - { "group": "coats_unisex", "prob": 50 }, - { "group": "suits_unisex", "prob": 30 }, - { "group": "suits_womens", "prob": 40 }, - { "group": "bags_unisex", "prob": 20 } - ] - }, - { - "id": "dresser_mens", - "type": "item_group", - "//": "clothing found in a man's dresser", - "subtype": "collection", - "items": [ - { "group": "accesories_personal_unisex", "prob": 10 }, - { "group": "accesories_personal_mens", "prob": 10 }, - { "group": "masks_unisex", "prob": 5 }, - { "group": "socks_unisex", "prob": 70 }, - { "group": "scarfs_unisex", "prob": 20 }, - { "group": "shirts_unisex", "prob": 50 }, - { "group": "underwear_mens", "prob": 80 }, - { "group": "underwear_unisex", "prob": 80 }, - { "group": "pants_unisex", "prob": 50 }, - { "group": "pants_mens", "prob": 60 }, - { "group": "gloves_unisex", "prob": 20 } - ] - }, - { - "id": "dresser_womens", - "type": "item_group", - "//": "clothing found in a woman's dresser", - "subtype": "collection", - "items": [ - { "group": "accesories_personal_unisex", "prob": 30 }, - { "group": "accesories_personal_womens", "prob": 5 }, - { "group": "masks_unisex", "prob": 5 }, - { "group": "socks_unisex", "prob": 70 }, - { "group": "scarfs_unisex", "prob": 10 }, - { "group": "shirts_womens", "prob": 60 }, - { "group": "shirts_unisex", "prob": 50 }, - { "group": "underwear_womens", "prob": 80 }, - { "group": "underwear_unisex", "prob": 80 }, - { "group": "pants_unisex", "prob": 50 }, - { "group": "pants_womens", "prob": 60 }, - { "group": "gloves_womens", "prob": 5 }, - { "group": "gloves_unisex", "prob": 30 } - ] - }, { "id": "unisex_coat_rack", "type": "item_group", diff --git a/data/json/mapgen/farm_2side.json b/data/json/mapgen/farm_2side.json index 3a11dcaea843d..2fb85efc91d5f 100644 --- a/data/json/mapgen/farm_2side.json +++ b/data/json/mapgen/farm_2side.json @@ -185,9 +185,9 @@ "H": { "item": "trash", "chance": 65 }, "b": { "item": "softdrugs", "chance": 70 }, "d": [ - { "item": "dresser_mens", "chance": 50 }, + { "item": "SUS_dresser_mens", "chance": 50 }, { "item": "homeguns", "chance": 20 }, - { "item": "dresser_womens", "chance": 50, "repeat": [ 1, 2 ] } + { "item": "SUS_dresser_womens", "chance": 50, "repeat": [ 1, 2 ] } ], "e": { "item": "fridge", "chance": 65, "repeat": [ 1, 8 ] }, "n": { "item": "bedroom", "chance": 65 }, diff --git a/data/json/mapgen/nested/house_nested.json b/data/json/mapgen/nested/house_nested.json index 425fa09e0c10b..e80bbf44652bd 100644 --- a/data/json/mapgen/nested/house_nested.json +++ b/data/json/mapgen/nested/house_nested.json @@ -15,7 +15,7 @@ ], "palettes": [ "house_w_nest_palette" ], "items": { - "O": [ { "item": "dresser_mens", "chance": 50 }, { "item": "dresser_womens", "chance": 50, "repeat": [ 1, 2 ] } ], + "O": [ { "item": "SUS_dresser_mens", "chance": 50 }, { "item": "SUS_dresser_womens", "chance": 50, "repeat": [ 1, 2 ] } ], "E": { "item": "bed", "chance": 40, "repeat": [ 1, 2 ] }, "L": { "item": "bedroom", "chance": 20, "repeat": [ 1, 2 ] } } @@ -37,7 +37,7 @@ ], "palettes": [ "house_w_nest_palette" ], "items": { - "O": [ { "item": "dresser_mens", "chance": 50 }, { "item": "dresser_womens", "chance": 50, "repeat": [ 1, 2 ] } ], + "O": [ { "item": "SUS_dresser_mens", "chance": 50 }, { "item": "SUS_dresser_womens", "chance": 50, "repeat": [ 1, 2 ] } ], "E": { "item": "bed", "chance": 40, "repeat": [ 1, 2 ] }, "a": { "item": "unisex_coat_rack", "chance": 100, "repeat": [ 1, 2 ] }, "L": { "item": "bedroom", "chance": 20, "repeat": [ 1, 2 ] } @@ -60,7 +60,7 @@ ], "palettes": [ "house_w_nest_palette" ], "items": { - "O": [ { "item": "dresser_mens", "chance": 50 }, { "item": "dresser_womens", "chance": 50, "repeat": [ 1, 2 ] } ], + "O": [ { "item": "SUS_dresser_mens", "chance": 50 }, { "item": "SUS_dresser_womens", "chance": 50, "repeat": [ 1, 2 ] } ], "E": { "item": "bed", "chance": 40, "repeat": [ 1, 2 ] }, "L": { "item": "bedroom", "chance": 20, "repeat": [ 1, 2 ] } } @@ -82,7 +82,7 @@ ], "palettes": [ "house_w_nest_palette" ], "items": { - "O": [ { "item": "dresser_mens", "chance": 50 }, { "item": "dresser_womens", "chance": 50, "repeat": [ 1, 2 ] } ], + "O": [ { "item": "SUS_dresser_mens", "chance": 50 }, { "item": "SUS_dresser_womens", "chance": 50, "repeat": [ 1, 2 ] } ], "E": { "item": "bed", "chance": 30, "repeat": [ 1, 2 ] }, "a": { "item": "unisex_coat_rack", "chance": 100, "repeat": [ 1, 2 ] }, "L": { "item": "bedroom", "chance": 20, "repeat": [ 1, 2 ] } @@ -105,9 +105,9 @@ ], "palettes": [ "house_w_nest_palette" ], "items": { - "O": [ { "item": "dresser_mens", "chance": 50 }, { "item": "dresser_womens", "chance": 50, "repeat": [ 1, 2 ] } ], + "O": [ { "item": "SUS_dresser_mens", "chance": 50 }, { "item": "SUS_dresser_womens", "chance": 50, "repeat": [ 1, 2 ] } ], "E": { "item": "bed", "chance": 40, "repeat": [ 1, 2 ] }, - "I": { "item": "desks_bedroom_unisex", "chance": 40, "repeat": [ 1, 2 ] }, + "I": { "item": "SUS_desks_bedroom_unisex", "chance": 40, "repeat": [ 1, 2 ] }, "L": { "item": "bedroom", "chance": 20, "repeat": [ 1, 2 ] } } } @@ -128,9 +128,9 @@ ], "palettes": [ "house_w_nest_palette" ], "items": { - "O": [ { "item": "dresser_mens", "chance": 50 }, { "item": "dresser_womens", "chance": 50, "repeat": [ 1, 2 ] } ], + "O": [ { "item": "SUS_dresser_mens", "chance": 50 }, { "item": "SUS_dresser_womens", "chance": 50, "repeat": [ 1, 2 ] } ], "E": { "item": "bed", "chance": 40, "repeat": [ 1, 2 ] }, - "I": { "item": "desks_bedroom_unisex", "chance": 40, "repeat": [ 1, 2 ] }, + "I": { "item": "SUS_desks_bedroom_unisex", "chance": 40, "repeat": [ 1, 2 ] }, "a": { "item": "unisex_coat_rack", "chance": 100, "repeat": [ 1, 2 ] }, "L": { "item": "bedroom", "chance": 20, "repeat": [ 1, 2 ] } } @@ -152,9 +152,9 @@ ], "palettes": [ "house_w_nest_palette" ], "items": { - "O": [ { "item": "dresser_mens", "chance": 50 }, { "item": "dresser_womens", "chance": 50, "repeat": [ 1, 2 ] } ], + "O": [ { "item": "SUS_dresser_mens", "chance": 50 }, { "item": "SUS_dresser_womens", "chance": 50, "repeat": [ 1, 2 ] } ], "E": { "item": "bed", "chance": 40, "repeat": [ 1, 2 ] }, - "I": { "item": "desks_bedroom_unisex", "chance": 40, "repeat": [ 1, 2 ] }, + "I": { "item": "SUS_desks_bedroom_unisex", "chance": 40, "repeat": [ 1, 2 ] }, "L": { "item": "bedroom", "chance": 20, "repeat": [ 1, 2 ] } } } @@ -175,9 +175,9 @@ ], "palettes": [ "house_w_nest_palette" ], "items": { - "O": [ { "item": "dresser_mens", "chance": 50 }, { "item": "dresser_womens", "chance": 50, "repeat": [ 1, 2 ] } ], + "O": [ { "item": "SUS_dresser_mens", "chance": 50 }, { "item": "SUS_dresser_womens", "chance": 50, "repeat": [ 1, 2 ] } ], "E": { "item": "bed", "chance": 40, "repeat": [ 1, 2 ] }, - "I": { "item": "desks_bedroom_unisex", "chance": 40, "repeat": [ 1, 2 ] }, + "I": { "item": "SUS_desks_bedroom_unisex", "chance": 40, "repeat": [ 1, 2 ] }, "L": { "item": "homebooks", "chance": 10, "repeat": [ 1, 2 ] } } } @@ -198,7 +198,7 @@ ], "palettes": [ "house_w_nest_palette" ], "items": { - "O": [ { "item": "dresser_mens", "chance": 50 }, { "item": "dresser_womens", "chance": 50, "repeat": [ 1, 2 ] } ], + "O": [ { "item": "SUS_dresser_mens", "chance": 50 }, { "item": "SUS_dresser_womens", "chance": 50, "repeat": [ 1, 2 ] } ], "E": { "item": "bed", "chance": 40, "repeat": [ 1, 2 ] }, "R": { "item": "homebooks", "chance": 10, "repeat": [ 1, 2 ] } } @@ -220,7 +220,7 @@ ], "palettes": [ "house_w_nest_palette" ], "items": { - "O": [ { "item": "dresser_mens", "chance": 50 }, { "item": "dresser_womens", "chance": 50, "repeat": [ 1, 2 ] } ], + "O": [ { "item": "SUS_dresser_mens", "chance": 50 }, { "item": "SUS_dresser_womens", "chance": 50, "repeat": [ 1, 2 ] } ], "E": { "item": "bed", "chance": 40, "repeat": [ 1, 2 ] }, "R": { "item": "homebooks", "chance": 10, "repeat": [ 1, 2 ] } } @@ -242,7 +242,7 @@ ], "palettes": [ "house_w_nest_palette" ], "items": { - "O": [ { "item": "dresser_mens", "chance": 50 }, { "item": "dresser_womens", "chance": 50, "repeat": [ 1, 2 ] } ], + "O": [ { "item": "SUS_dresser_mens", "chance": 50 }, { "item": "SUS_dresser_womens", "chance": 50, "repeat": [ 1, 2 ] } ], "E": { "item": "bed", "chance": 40, "repeat": [ 1, 2 ] }, "R": { "item": "homebooks", "chance": 10, "repeat": [ 1, 2 ] } } @@ -264,7 +264,7 @@ ], "palettes": [ "house_w_nest_palette" ], "items": { - "O": [ { "item": "dresser_mens", "chance": 50 }, { "item": "dresser_womens", "chance": 50, "repeat": [ 1, 2 ] } ], + "O": [ { "item": "SUS_dresser_mens", "chance": 50 }, { "item": "SUS_dresser_womens", "chance": 50, "repeat": [ 1, 2 ] } ], "E": { "item": "bed", "chance": 40, "repeat": [ 1, 2 ] }, "R": { "item": "homebooks", "chance": 10, "repeat": [ 1, 2 ] } } @@ -287,9 +287,9 @@ ], "palettes": [ "house_w_nest_palette" ], "items": { - "O": [ { "item": "dresser_mens", "chance": 50 }, { "item": "dresser_womens", "chance": 50, "repeat": [ 1, 2 ] } ], + "O": [ { "item": "SUS_dresser_mens", "chance": 50 }, { "item": "SUS_dresser_womens", "chance": 50, "repeat": [ 1, 2 ] } ], "E": { "item": "bed", "chance": 40, "repeat": [ 1, 2 ] }, - "I": { "item": "desks_bedroom_unisex", "chance": 40, "repeat": [ 1, 2 ] }, + "I": { "item": "SUS_desks_bedroom_unisex", "chance": 40, "repeat": [ 1, 2 ] }, "L": { "item": "homebooks", "chance": 10, "repeat": [ 1, 2 ] } } } @@ -311,9 +311,9 @@ ], "palettes": [ "house_w_nest_palette" ], "items": { - "O": [ { "item": "dresser_mens", "chance": 50 }, { "item": "dresser_womens", "chance": 50, "repeat": [ 1, 2 ] } ], + "O": [ { "item": "SUS_dresser_mens", "chance": 50 }, { "item": "SUS_dresser_womens", "chance": 50, "repeat": [ 1, 2 ] } ], "E": { "item": "bed", "chance": 40, "repeat": [ 1, 2 ] }, - "I": { "item": "desks_bedroom_unisex", "chance": 40, "repeat": [ 1, 2 ] }, + "I": { "item": "SUS_desks_bedroom_unisex", "chance": 40, "repeat": [ 1, 2 ] }, "L": { "item": "homebooks", "chance": 10, "repeat": [ 1, 2 ] } } } @@ -335,9 +335,9 @@ ], "palettes": [ "house_w_nest_palette" ], "items": { - "O": [ { "item": "dresser_mens", "chance": 50 }, { "item": "dresser_womens", "chance": 50, "repeat": [ 1, 2 ] } ], + "O": [ { "item": "SUS_dresser_mens", "chance": 50 }, { "item": "SUS_dresser_womens", "chance": 50, "repeat": [ 1, 2 ] } ], "E": { "item": "bed", "chance": 40, "repeat": [ 1, 2 ] }, - "I": { "item": "desks_bedroom_unisex", "chance": 40, "repeat": [ 1, 2 ] }, + "I": { "item": "SUS_desks_bedroom_unisex", "chance": 40, "repeat": [ 1, 2 ] }, "L": { "item": "homebooks", "chance": 10, "repeat": [ 1, 2 ] } } } @@ -359,9 +359,9 @@ ], "palettes": [ "house_w_nest_palette" ], "items": { - "O": [ { "item": "dresser_mens", "chance": 50 }, { "item": "dresser_womens", "chance": 50, "repeat": [ 1, 2 ] } ], + "O": [ { "item": "SUS_dresser_mens", "chance": 50 }, { "item": "SUS_dresser_womens", "chance": 50, "repeat": [ 1, 2 ] } ], "E": { "item": "bed", "chance": 40, "repeat": [ 1, 2 ] }, - "I": { "item": "desks_bedroom_unisex", "chance": 40, "repeat": [ 1, 2 ] }, + "I": { "item": "SUS_desks_bedroom_unisex", "chance": 40, "repeat": [ 1, 2 ] }, "L": { "item": "homebooks", "chance": 10, "repeat": [ 1, 2 ] } } } @@ -383,9 +383,9 @@ ], "palettes": [ "house_w_nest_palette" ], "items": { - "O": [ { "item": "dresser_mens", "chance": 50 }, { "item": "dresser_womens", "chance": 50, "repeat": [ 1, 2 ] } ], + "O": [ { "item": "SUS_dresser_mens", "chance": 50 }, { "item": "SUS_dresser_womens", "chance": 50, "repeat": [ 1, 2 ] } ], "E": { "item": "bed", "chance": 40, "repeat": [ 1, 2 ] }, - "I": { "item": "desks_bedroom_unisex", "chance": 40, "repeat": [ 1, 2 ] }, + "I": { "item": "SUS_desks_bedroom_unisex", "chance": 40, "repeat": [ 1, 2 ] }, "a": { "item": "unisex_coat_rack", "chance": 100, "repeat": [ 1, 2 ] }, "L": { "item": "homebooks", "chance": 10, "repeat": [ 1, 2 ] } } @@ -408,9 +408,9 @@ ], "palettes": [ "house_w_nest_palette" ], "items": { - "O": [ { "item": "dresser_mens", "chance": 50 }, { "item": "dresser_womens", "chance": 50, "repeat": [ 1, 2 ] } ], + "O": [ { "item": "SUS_dresser_mens", "chance": 50 }, { "item": "SUS_dresser_womens", "chance": 50, "repeat": [ 1, 2 ] } ], "E": { "item": "bed", "chance": 40, "repeat": [ 1, 2 ] }, - "I": { "item": "desks_bedroom_unisex", "chance": 40, "repeat": [ 1, 2 ] }, + "I": { "item": "SUS_desks_bedroom_unisex", "chance": 40, "repeat": [ 1, 2 ] }, "a": { "item": "unisex_coat_rack", "chance": 100, "repeat": [ 1, 2 ] }, "L": { "item": "homebooks", "chance": 10, "repeat": [ 1, 2 ] } } @@ -433,9 +433,9 @@ ], "palettes": [ "house_w_nest_palette" ], "items": { - "O": [ { "item": "dresser_mens", "chance": 50 }, { "item": "dresser_womens", "chance": 50, "repeat": [ 1, 2 ] } ], + "O": [ { "item": "SUS_dresser_mens", "chance": 50 }, { "item": "SUS_dresser_womens", "chance": 50, "repeat": [ 1, 2 ] } ], "E": { "item": "bed", "chance": 40, "repeat": [ 1, 2 ] }, - "I": { "item": "desks_bedroom_unisex", "chance": 40, "repeat": [ 1, 2 ] }, + "I": { "item": "SUS_desks_bedroom_unisex", "chance": 40, "repeat": [ 1, 2 ] }, "L": { "item": "homebooks", "chance": 10, "repeat": [ 1, 2 ] }, "R": { "item": "homebooks", "chance": 30, "repeat": [ 1, 2 ] } } @@ -458,9 +458,9 @@ ], "palettes": [ "house_w_nest_palette" ], "items": { - "O": [ { "item": "dresser_mens", "chance": 50 }, { "item": "dresser_womens", "chance": 50, "repeat": [ 1, 2 ] } ], + "O": [ { "item": "SUS_dresser_mens", "chance": 50 }, { "item": "SUS_dresser_womens", "chance": 50, "repeat": [ 1, 2 ] } ], "E": { "item": "bed", "chance": 40, "repeat": [ 1, 2 ] }, - "I": { "item": "desks_bedroom_unisex", "chance": 40, "repeat": [ 1, 2 ] }, + "I": { "item": "SUS_desks_bedroom_unisex", "chance": 40, "repeat": [ 1, 2 ] }, "L": { "item": "homebooks", "chance": 10, "repeat": [ 1, 2 ] }, "a": { "item": "unisex_coat_rack", "chance": 100, "repeat": [ 1, 2 ] }, "R": { "item": "homebooks", "chance": 30, "repeat": [ 1, 2 ] } diff --git a/data/json/mapgen_palettes/cabin.json b/data/json/mapgen_palettes/cabin.json index 11fbc0124691a..e4e5a7e44d32a 100644 --- a/data/json/mapgen_palettes/cabin.json +++ b/data/json/mapgen_palettes/cabin.json @@ -63,8 +63,8 @@ "B": { "item": "bed", "chance": 60 }, "d": [ { "item": "livingroom", "chance": 40 }, { "item": "office", "chance": 40 } ], "D": [ - { "item": "dresser_mens", "chance": 50, "repeat": [ 1, 4 ] }, - { "item": "dresser_womens", "chance": 50, "repeat": [ 1, 4 ] } + { "item": "SUS_dresser_mens", "chance": 50, "repeat": [ 1, 4 ] }, + { "item": "SUS_dresser_womens", "chance": 50, "repeat": [ 1, 4 ] } ], "F": { "item": "fridge", "chance": 35, "repeat": [ 1, 14 ] }, "h": { "item": "shower", "chance": 20 }, diff --git a/data/json/mapgen_palettes/city_block_palette.json b/data/json/mapgen_palettes/city_block_palette.json index 11ff96b47b26a..1fc4a81ca3284 100644 --- a/data/json/mapgen_palettes/city_block_palette.json +++ b/data/json/mapgen_palettes/city_block_palette.json @@ -74,7 +74,7 @@ "toilets": { "t": { } }, "liquids": { "g": { "liquid": "water_clean", "amount": [ 0, 100 ] } }, "items": { - "O": [ { "item": "wardrobe_mens", "chance": 50 }, { "item": "wardrobe_womens", "chance": 50, "repeat": [ 1, 2 ] } ], + "O": [ { "item": "SUS_wardrobe_mens", "chance": 50 }, { "item": "SUS_wardrobe_womens", "chance": 50, "repeat": [ 1, 2 ] } ], "Q": [ { "item": "preserved_food", "chance": 20, "repeat": [ 1, 2 ] }, { "item": "dry_goods", "chance": 30, "repeat": [ 1, 2 ] }, diff --git a/data/json/mapgen_palettes/house_w_palette.json b/data/json/mapgen_palettes/house_w_palette.json index 098ff5af8f1a8..eb5f1c8245fea 100644 --- a/data/json/mapgen_palettes/house_w_palette.json +++ b/data/json/mapgen_palettes/house_w_palette.json @@ -150,7 +150,7 @@ "toilets": { "t": { } }, "liquids": { "g": { "liquid": "water_clean", "amount": [ 0, 100 ] } }, "items": { - "O": [ { "item": "wardrobe_mens", "chance": 50 }, { "item": "wardrobe_womens", "chance": 50, "repeat": [ 1, 2 ] } ], + "O": [ { "item": "SUS_wardrobe_mens", "chance": 50 }, { "item": "SUS_wardrobe_womens", "chance": 50, "repeat": [ 1, 2 ] } ], "Q": [ { "item": "preserved_food", "chance": 20, "repeat": [ 1, 2 ] }, { "item": "dry_goods", "chance": 30, "repeat": [ 1, 2 ] }, From 5bdcd0649c9d20065dac2e566267100106764834 Mon Sep 17 00:00:00 2001 From: LaVeyanFiend Date: Wed, 1 Jan 2020 11:59:25 -0500 Subject: [PATCH 27/31] Remove pit digging construction from CRIT --- .../constructions/crt_constructions.json | 20 ------------------- 1 file changed, 20 deletions(-) diff --git a/data/mods/CRT_EXPANSION/constructions/crt_constructions.json b/data/mods/CRT_EXPANSION/constructions/crt_constructions.json index dcf35d50ee5a6..40a2429acfdc8 100644 --- a/data/mods/CRT_EXPANSION/constructions/crt_constructions.json +++ b/data/mods/CRT_EXPANSION/constructions/crt_constructions.json @@ -98,26 +98,6 @@ "pre_terrain": "t_trunk", "post_terrain": "t_dirt" }, - { - "type": "construction", - "description": "Dig a Pit", - "category": "DIG", - "required_skills": [ [ "survival", 0 ] ], - "time": "20 m", - "qualities": [ [ { "id": "DIG", "level": 2 } ] ], - "pre_terrain": "t_dirt", - "post_terrain": "t_pit_shallow" - }, - { - "type": "construction", - "description": "Dig a Pit", - "category": "DIG", - "required_skills": [ [ "survival", 1 ] ], - "time": "15 m", - "qualities": [ [ { "id": "DIG", "level": 2 } ] ], - "pre_terrain": "t_pit_shallow", - "post_terrain": "t_pit" - }, { "type": "construction", "description": "Makeshift Wall", From f6eb74d8ee4a0decaa9d0f41b1ac7f745e282eb6 Mon Sep 17 00:00:00 2001 From: Lil Shining Man <56778776+LilShiningMan@users.noreply.github.com> Date: Wed, 1 Jan 2020 09:36:51 -0800 Subject: [PATCH 28/31] Alcohol Revamp Granularized main alcohol groups, eliminated redundant lists in various item groups. --- data/json/itemgroups/food.json | 120 +++++++++++---------- data/json/itemgroups/food_service.json | 77 ++----------- data/json/itemgroups/item_groups.json | 67 ++---------- data/json/itemgroups/locations.json | 22 +--- data/json/itemgroups/science_and_tech.json | 1 + 5 files changed, 84 insertions(+), 203 deletions(-) diff --git a/data/json/itemgroups/food.json b/data/json/itemgroups/food.json index fda23b0c4e6e1..ee72007a63973 100644 --- a/data/json/itemgroups/food.json +++ b/data/json/itemgroups/food.json @@ -759,28 +759,29 @@ { "type": "item_group", "id": "alcohol", + "//": "all comestible alcohol -- packaged, mixed and homemade", + "items": [ + { "group": "alcohol_bottled_canned", "prob": 376 }, + { "group": "mixed_alcoholic_drinks", "prob": 141 }, + [ "dandelion_wine", 8 ], + [ "hb_beer", 8 ], + [ "moonshine", 8 ] + ] + }, + { + "type": "item_group", + "id": "alcohol_bottled_canned", + "items": [ + { "group": "liquor_and_spirits", "prob": 108 }, + { "group": "wines_worthy", "prob": 39 }, + { "group": "beer", "prob": 141 }, + { "group": "misc_alcohol", "prob": 88 } + ] + }, + { + "type": "item_group", + "id": "beer", "items": [ - [ "whiskey", 16 ], - [ "vodka", 20 ], - [ "gin", 20 ], - [ "rum", 14 ], - [ "tequila", 12 ], - [ "chem_ethanol", 10 ], - [ "triple_sec", 12 ], - [ "bum_wine", 20 ], - [ "fruit_wine", 12 ], - [ "brandy", 12 ], - [ "drink_rumcola", 12 ], - [ "drink_screwdriver", 12 ], - [ "drink_wild_apple", 8 ], - [ "long_island", 6 ], - [ "wine_riesling", 6 ], - [ "wine_chardonnay", 10 ], - [ "wine_cabernet", 10 ], - [ "wine_marsala", 2 ], - [ "wine_vermouth", 9 ], - [ "wine_barley", 24 ], - [ "wine_noir", 2 ], [ "beer", 35 ], [ "european_pilsner", 25 ], [ "pale_ale", 25 ], @@ -788,13 +789,24 @@ [ "stout", 15 ], [ "belgian_ale", 10 ], [ "imperial_stout", 4 ], - [ "single_malt_whiskey", 2 ], - [ "survnote", 1 ] + [ "wine_barley", 2 ] ] }, { "type": "item_group", - "id": "alcohol_bottled_canned", + "id": "wines_worthy", + "items": [ + [ "wine_riesling", 20 ], + [ "wine_chardonnay", 30 ], + [ "wine_cabernet", 30 ], + [ "wine_noir", 20 ], + [ "wine_vermouth", 25 ], + [ "wine_marsala", 15 ] + ] + }, + { + "type": "item_group", + "id": "liquor_and_spirits", "items": [ [ "whiskey", 16 ], [ "vodka", 20 ], @@ -803,51 +815,41 @@ [ "tequila", 12 ], [ "triple_sec", 12 ], [ "brandy", 12 ], + [ "single_malt_whiskey", 2 ], + [ "single_pot_whiskey", 10 ], + [ "cheap_whiskey", 10 ], + [ "canadian_whiskey", 10 ] + ] + }, + { + "type": "item_group", + "id": "misc_alcohol", + "items": [ + [ "bum_wine", 20 ], + [ "pine_wine", 6 ], + [ "fruit_wine", 12 ], + [ "mead", 10 ], + [ "sherry", 10 ], + [ "bristol_sherry", 5 ], + [ "madeira", 5 ] + ] + }, + { + "type": "item_group", + "id": "mixed_alcoholic_drinks", + "items": [ [ "drink_rumcola", 12 ], [ "drink_screwdriver", 12 ], [ "drink_wild_apple", 8 ], + [ "long_island", 6 ], [ "drink_strawberry_surprise", 6 ], [ "drink_boozeberry", 6 ], [ "drink_hobo", 10 ], [ "drink_kalimotxo", 10 ], [ "drink_beeknees", 8 ], [ "drink_wsour", 8 ], - [ "wine_riesling", 6 ], - [ "wine_chardonnay", 10 ], - [ "wine_cabernet", 10 ], - [ "wine_noir", 5 ], - [ "dandelion_wine", 8 ], - [ "wine_marsala", 2 ], - [ "wine_vermouth", 9 ], - [ "wine_barley", 24 ], - [ "pine_wine", 6 ], - [ "bum_wine", 20 ], - [ "fruit_wine", 12 ], - [ "beer", 35 ], - [ "european_pilsner", 25 ], - [ "pale_ale", 25 ], - [ "india_pale_ale", 25 ], - [ "stout", 15 ], - [ "belgian_ale", 10 ], - [ "imperial_stout", 5 ], - [ "hb_beer", 8 ], - [ "long_island", 6 ], - [ "mead", 10 ], - [ "moonshine", 8 ], [ "eggnog_spiked", 5 ], - [ "chem_ethanol", 5 ] - ] - }, - { - "type": "item_group", - "id": "wines_worthy", - "items": [ - [ "wine_riesling", 20 ], - [ "wine_chardonnay", 30 ], - [ "wine_cabernet", 30 ], - [ "wine_noir", 20 ], - [ "wine_vermouth", 25 ], - [ "wine_marsala", 15 ] + [ "drink_martini", 10 ] ] } ] diff --git a/data/json/itemgroups/food_service.json b/data/json/itemgroups/food_service.json index b66b0d96989f8..76e2952322c37 100644 --- a/data/json/itemgroups/food_service.json +++ b/data/json/itemgroups/food_service.json @@ -75,38 +75,14 @@ "id": "bar_alcohol", "type": "item_group", "items": [ - [ "beer", 70 ], - [ "european_pilsner", 60 ], - [ "pale_ale", 60 ], - [ "india_pale_ale", 57 ], - [ "wine_barley", 55 ], - [ "stout", 56 ], - [ "belgian_ale", 50 ], - [ "imperial_stout", 45 ], - [ "whiskey", 20 ], - [ "vodka", 12 ], - [ "gin", 15 ], - [ "rum", 12 ], - [ "tequila", 17 ], - [ "triple_sec", 10 ], - [ "single_pot_whiskey", 10 ], - [ "cheap_whiskey", 10 ], - [ "canadian_whiskey", 10 ], + { "group": "beer", "prob": 453 }, + { "group": "wines_worthy", "prob": 100 }, + { "group": "liquor_and_spirits", "prob": 116 }, + { "group": "mixed_alcoholic_drinks", "prob": 202 }, + [ "fruit_wine", 5 ], [ "sherry", 10 ], [ "bristol_sherry", 5 ], - [ "madeira", 5 ], - [ "fruit_wine", 5 ], - [ "wine_riesling", 7 ], - [ "wine_chardonnay", 4 ], - [ "wine_vermouth", 5 ], - [ "wine_cabernet", 1 ], - [ "wine_noir", 1 ], - [ "brandy", 5 ], - [ "drink_rumcola", 50 ], - [ "drink_screwdriver", 45 ], - [ "drink_wild_apple", 20 ], - [ "long_island", 27 ], - [ "drink_martini", 60 ] + [ "madeira", 5 ] ] }, { @@ -236,17 +212,7 @@ { "id": "pizza_beer", "type": "item_group", - "items": [ - [ "imperial_stout", 15 ], - [ "belgian_ale", 10 ], - [ "stout", 20 ], - [ "india_pale_ale", 20 ], - [ "pale_ale", 15 ], - [ "european_pilsner", 17 ], - [ "wine_barley", 17 ], - [ "mead", 5 ], - [ "beer", 18 ] - ] + "items": [ { "group": "beer", "prob": 10 }, [ "wine_chardonnay", 1 ], [ "wine_cabernet", 1 ] ] }, { "id": "pizza_soda", @@ -712,16 +678,7 @@ [ "spork", 10 ], [ "foon", 10 ], [ "bottle_glass", 15 ], - [ "fruit_wine", 10 ], - [ "wine_vermouth", 8 ], - [ "wine_marsala", 6 ], - [ "wine_riesling", 7 ], - [ "wine_chardonnay", 8 ], - [ "wine_cabernet", 8 ], - [ "wine_noir", 6 ], - [ "sherry", 5 ], - [ "bristol_sherry", 5 ], - [ "madeira", 5 ], + { "group": "bar_alcohol", "prob": 68 }, [ "currywurst", 5 ], [ "macaroni_cooked", 5 ], [ "lasagne", 5 ], @@ -756,13 +713,7 @@ [ "irradiated_onion", 4 ], [ "irradiated_carrot", 4 ], [ "chili", 10 ], - [ "fruit_wine", 10 ], - [ "wine_riesling", 7 ], - [ "wine_chardonnay", 8 ], - [ "wine_cabernet", 8 ], - [ "wine_marsala", 6 ], - [ "wine_vermouth", 9 ], - [ "wine_noir", 6 ], + { "group": "wines_worthy", "prob": 54 }, [ "fish_fried", 7 ], [ "cheese", 10 ], [ "lemon", 15 ], @@ -858,16 +809,8 @@ [ "fork", 20 ], [ "spork", 5 ], [ "foon", 5 ], + { "group": "wines_worthy", "prob": 66 }, [ "fruit_wine", 20 ], - [ "wine_riesling", 10 ], - [ "wine_chardonnay", 13 ], - [ "wine_cabernet", 13 ], - [ "wine_marsala", 9 ], - [ "wine_vermouth", 15 ], - [ "wine_noir", 9 ], - [ "sherry", 10 ], - [ "bristol_sherry", 5 ], - [ "madeira", 5 ], [ "hat_chef", 30 ], [ "jacket_chef", 30 ], [ "pants_checkered", 28 ] diff --git a/data/json/itemgroups/item_groups.json b/data/json/itemgroups/item_groups.json index ec01d32cda91a..c0f4be4ef32d8 100644 --- a/data/json/itemgroups/item_groups.json +++ b/data/json/itemgroups/item_groups.json @@ -226,14 +226,7 @@ [ "game_watch", 2 ], [ "deck_of_cards", 2 ], [ "usb_drive", 5 ], - [ "beer", 35 ], - [ "european_pilsner", 25 ], - [ "pale_ale", 25 ], - [ "india_pale_ale", 25 ], - [ "stout", 15 ], - [ "belgian_ale", 10 ], - [ "wine_barley", 24 ], - [ "imperial_stout", 4 ], + { "group": "alcohol", "prob": 163 }, [ "cell_phone", 15 ], [ "smart_phone", 25 ], [ "wristwatch", 15 ], @@ -323,19 +316,7 @@ [ "popcan_stove", 5 ], [ "flashlight", 40 ], [ "extinguisher", 20 ], - [ "whiskey", 16 ], - [ "bum_wine", 10 ], - [ "drink_rumcola", 8 ], - [ "drink_screwdriver", 8 ], - [ "drink_wild_apple", 8 ], - [ "long_island", 2 ], - [ "drink_martini", 10 ], - [ "wine_riesling", 6 ], - [ "wine_chardonnay", 10 ], - [ "wine_cabernet", 10 ], - [ "wine_noir", 2 ], - [ "wine_marsala", 2 ], - [ "wine_vermouth", 9 ], + { "group": "alcohol", "prob": 101 }, [ "sweet_sausage", 2 ], [ "roasted_coffee_bean", 10 ], [ "bacon", 25 ], @@ -586,17 +567,9 @@ [ "fruit_wine", 7 ], [ "brandy", 5 ], [ "jihelucake", 1 ], - [ "beer", 35 ], - [ "european_pilsner", 25 ], - [ "pale_ale", 25 ], - [ "india_pale_ale", 25 ], - [ "stout", 15 ], - [ "belgian_ale", 10 ], - [ "imperial_stout", 4 ], - [ "wine_barley", 24 ], + { "group": "beer", "prob": 163 }, [ "cake2", 1 ], [ "cake3", 1 ], - [ "beer", 60 ], [ "pizza_meat", 8 ], [ "pizza_veggy", 8 ], [ "pizza_cheese", 8 ], @@ -2645,7 +2618,7 @@ [ "colamdew", 60 ], [ "purple_drink", 15 ], [ "mag_melee", 30 ], - [ "whiskey", 16 ], + { "group": "liquor_and_spirits", "prob": 16 }, [ "bum_wine", 10 ], [ "chem_ethanol", 12 ], { "group": "salty_snacks", "prob": 135 }, @@ -3486,8 +3459,8 @@ { "group": "salty_snacks", "prob": 130 }, [ "aspirin", 80 ], [ "inhaler", 30 ], + { "group": "beer", "prob": 80 }, [ "vodka", 60 ], - [ "beer", 80 ], [ "cig", 20 ], [ "crackpipe", 10 ], [ "weed", 10 ], @@ -3525,10 +3498,7 @@ [ "rollerskates", 10 ], [ "aspirin", 80 ], [ "inhaler", 30 ], - [ "beer", 80 ], - [ "pale_ale", 40 ], - [ "wine_barley", 20 ], - [ "stout", 40 ], + { "group": "beer", "prob": 180 }, [ "sports_drink", 80 ], [ "energy_drink", 30 ], [ "cig", 20 ], @@ -3781,7 +3751,6 @@ "magazine": 50, "items": [ [ "plastic_shopping_bag", 15 ], - [ "bum_wine", 15 ], [ "meth", 2 ], [ "heroin", 1 ], [ "string_6", 2 ], @@ -3822,29 +3791,7 @@ [ "disc_golf", 30 ], [ "lawn_dart", 30 ], [ "golf_ball", 20 ], - [ "whiskey", 16 ], - [ "vodka", 20 ], - [ "gin", 20 ], - [ "rum", 14 ], - [ "tequila", 12 ], - [ "triple_sec", 12 ], - [ "fruit_wine", 12 ], - [ "brandy", 12 ], - [ "drink_wild_apple", 8 ], - [ "wine_riesling", 6 ], - [ "wine_chardonnay", 10 ], - [ "wine_cabernet", 10 ], - [ "wine_noir", 2 ], - [ "wine_marsala", 2 ], - [ "wine_vermouth", 9 ], - [ "wine_barley", 24 ], - [ "beer", 35 ], - [ "european_pilsner", 25 ], - [ "pale_ale", 25 ], - [ "india_pale_ale", 25 ], - [ "stout", 15 ], - [ "belgian_ale", 10 ], - [ "imperial_stout", 4 ] + { "group": "alcohol_bottled_canned", "prob": 343 } ] }, { diff --git a/data/json/itemgroups/locations.json b/data/json/itemgroups/locations.json index 952b9578a2682..4e17ad87706a2 100644 --- a/data/json/itemgroups/locations.json +++ b/data/json/itemgroups/locations.json @@ -468,26 +468,14 @@ "id": "bowling_alcohol", "type": "item_group", "items": [ - [ "beer", 60 ], - [ "european_pilsner", 50 ], - [ "pale_ale", 50 ], - [ "wine_barley", 45 ], - [ "india_pale_ale", 47 ], - [ "stout", 46 ], - [ "belgian_ale", 40 ], - [ "imperial_stout", 35 ], - [ "whiskey", 10 ], - [ "vodka", 10 ], - [ "gin", 10 ], - [ "rum", 10 ], - [ "tequila", 10 ], - [ "triple_sec", 5 ], - [ "fruit_wine", 5 ], - [ "brandy", 5 ], + { "group": "beer", "prob": 373 }, + { "group": "liquor_and_spirits", "prob": 80 }, [ "drink_rumcola", 40 ], [ "drink_screwdriver", 35 ], [ "drink_wild_apple", 10 ], - [ "long_island", 17 ] + [ "long_island", 17 ], + [ "wine_chardonnay", 20 ], + [ "wine_cabernet", 20 ] ] }, { diff --git a/data/json/itemgroups/science_and_tech.json b/data/json/itemgroups/science_and_tech.json index 0d53fcb60660a..dab0587734ccc 100644 --- a/data/json/itemgroups/science_and_tech.json +++ b/data/json/itemgroups/science_and_tech.json @@ -18,6 +18,7 @@ [ "eyedrops", 20 ], [ "adderall", 10 ], [ "id_science", 2 ], + [ "chem_ethanol", 10 ], [ "badge_doctor", 2 ], [ "double_plutonium_core", 1 ], [ "cleansuit", 5 ], From 93c4c76c01832a1f1f2acb28a6f873bad7ba5c70 Mon Sep 17 00:00:00 2001 From: RarkGrames <50421549+RarkGrames@users.noreply.github.com> Date: Wed, 1 Jan 2020 21:09:30 +0100 Subject: [PATCH 29/31] Update arms.json --- data/json/recipes/armor/arms.json | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/data/json/recipes/armor/arms.json b/data/json/recipes/armor/arms.json index 6e271027a50d9..2ae8f343f2e50 100644 --- a/data/json/recipes/armor/arms.json +++ b/data/json/recipes/armor/arms.json @@ -109,7 +109,7 @@ "skill_used": "survival", "time": "5 m", "autolearn": true, - "components": [ [ [ "paper", 60 ] ], [ [ "duct_tape", 10 ] ] ], + "components": [ [ [ "paper", 60 ] ], [ [ "duct_tape", 10 ], [ "medical_tape", 10 ] ] ], "flags": [ "BLIND_HARD" ] }, { From b2c6779f435daf46c5789b67722abf9403cb4804 Mon Sep 17 00:00:00 2001 From: John Bytheway Date: Tue, 31 Dec 2019 19:25:13 -0500 Subject: [PATCH 30/31] Fix crash in item comparison when using filter Fixes #34046. Using the search filter causes all the inventory_entry objects to be recreated, so it's not safe to store a pointer to them. A previous attempt to solve this (#36139) stored copies of the inventory_entry objects, but that was also unsafe. This attempt instead stores just pointers to the underlying items. This seems to prevent the crashes. The behaviour of the window is still not always exactly correct, because using the filter will violate the invariant that the items in the compared vector correspond to the selected entries. I don't see a way to fix that in general -- sometimes the compared item is filtered out, and thus you can't possibly select the entry (because it doesn't exist). We might want to add something that does its best to select the right entries when the filter changes, but this is a sufficiently niche use case that I'm not sure it's worth the complexity. I've settled for just fixing the crash for now. --- src/inventory_ui.cpp | 20 ++++++++++++++------ src/inventory_ui.h | 2 +- 2 files changed, 15 insertions(+), 7 deletions(-) diff --git a/src/inventory_ui.cpp b/src/inventory_ui.cpp index fbc8c9f4f17c9..8b727c89fb3e3 100644 --- a/src/inventory_ui.cpp +++ b/src/inventory_ui.cpp @@ -1877,15 +1877,19 @@ std::pair inventory_compare_selector::execute() const inventory_input input = get_input(); + inventory_entry *just_selected = nullptr; + if( input.entry != nullptr ) { select( input.entry->any_item() ); toggle_entry( input.entry ); + just_selected = input.entry; } else if( input.action == "RIGHT" ) { const auto selection( get_active_column().get_all_selected() ); for( auto &elem : selection ) { if( elem->chosen_count == 0 || selection.size() == 1 ) { toggle_entry( elem ); + just_selected = elem; if( compared.size() == 2 ) { break; } @@ -1905,9 +1909,12 @@ std::pair inventory_compare_selector::execute() } if( compared.size() == 2 ) { - const auto res = std::make_pair( &*compared.back()->any_item(), - &*compared.front()->any_item() ); - toggle_entry( compared.back() ); + const auto res = std::make_pair( compared[0], compared[1] ); + // Clear second selected entry to prevent comparison reopening too + // soon + if( just_selected ) { + toggle_entry( just_selected ); + } return res; } } @@ -1915,12 +1922,13 @@ std::pair inventory_compare_selector::execute() void inventory_compare_selector::toggle_entry( inventory_entry *entry ) { - const auto iter = std::find( compared.begin(), compared.end(), entry ); + const item *it = &*entry->any_item(); + const auto iter = std::find( compared.begin(), compared.end(), it ); - entry->chosen_count = ( iter == compared.end() ) ? 1 : 0; + entry->chosen_count = iter == compared.end() ? 1 : 0; if( entry->chosen_count != 0 ) { - compared.push_back( entry ); + compared.push_back( it ); } else { compared.erase( iter ); } diff --git a/src/inventory_ui.h b/src/inventory_ui.h index b2829064fded7..104929bf6f003 100644 --- a/src/inventory_ui.h +++ b/src/inventory_ui.h @@ -652,7 +652,7 @@ class inventory_compare_selector : public inventory_multiselector std::pair execute(); protected: - std::vector compared; + std::vector compared; void toggle_entry( inventory_entry *entry ); }; From fe0e3ded3c0801632951bd63fafa6c2cb7111e6f Mon Sep 17 00:00:00 2001 From: 8street Date: Thu, 2 Jan 2020 11:29:10 +0300 Subject: [PATCH 31/31] Remove duplicate stealing code (#36596) --- src/pickup.cpp | 43 ++++++++++++------------------------------- 1 file changed, 12 insertions(+), 31 deletions(-) diff --git a/src/pickup.cpp b/src/pickup.cpp index 9a1cea86284f6..270a98e42f47d 100644 --- a/src/pickup.cpp +++ b/src/pickup.cpp @@ -864,12 +864,6 @@ void Pickup::pick_up( const tripoint &p, int min, from_where get_items_from ) wprintw( w_pickup, " - " ); } std::string item_name; - std::string stolen; - bool stealing = false; - if( !this_item.is_owned_by( g->u, true ) ) { - stolen = "!"; - stealing = true; - } if( stacked_here[true_it].front()->is_money() ) { //Count charges // TODO: transition to the item_location system used for the inventory @@ -888,38 +882,25 @@ void Pickup::pick_up( const tripoint &p, int min, from_where get_items_from ) it != stacked_here[true_it].end() && c > 0; ++it, --c ) { charges += ( *it )->charges; } - if( stealing ) { - item_name = string_format( "%s %s", stolen, - stacked_here[true_it].front()->display_money( getitem[true_it].count, charges_total, charges ) ); - } else { - item_name = stacked_here[true_it].front()->display_money( getitem[true_it].count, charges_total, - charges ); - } + item_name = stacked_here[true_it].front()->display_money( getitem[true_it].count, charges_total, + charges ); } } else { - if( stealing ) { - item_name = string_format( "%s %s", stolen, - this_item.display_name( stacked_here[true_it].size() ) ); - } else { - item_name = this_item.display_name( stacked_here[true_it].size() ); - } + item_name = this_item.display_name( stacked_here[true_it].size() ); } if( stacked_here[true_it].size() > 1 ) { - if( stealing ) { - item_name = string_format( "%s %d %s", stolen, stacked_here[true_it].size(), item_name ); - } else { - item_name = string_format( "%d %s", stacked_here[true_it].size(), item_name ); - } + item_name = string_format( "%d %s", stacked_here[true_it].size(), item_name ); } if( get_option( "ITEM_SYMBOLS" ) ) { - if( stealing ) { - item_name = string_format( "%s %s %s", stolen, this_item.symbol().c_str(), - item_name.c_str() ); - } else { - item_name = string_format( "%s %s", this_item.symbol().c_str(), - item_name ); - } + item_name = string_format( "%s %s", this_item.symbol().c_str(), + item_name ); + } + + // if the item does not belong to your fraction then add the stolen symbol + if( !this_item.is_owned_by( g->u, true ) ) { + item_name = string_format( "! %s", item_name ); } + trim_and_print( w_pickup, point( 6, 1 + ( cur_it % maxitems ) ), pickupW - 4, icolor, item_name ); }