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..5be58a68d401c 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. 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 ] ] + }, + { + "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 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/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..72e88f07eb877 --- /dev/null +++ b/data/json/monsters/power_leech.json @@ -0,0 +1,198 @@ +[ + { + "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, + "diff": 30, + "material": [ "flesh" ], + "symbol": "K", + "color": "light_cyan", + "aggression": 100, + "morale": 100, + "armor_bash": 15, + "vision_day": 30, + "vision_night": 12, + "luminance": 200, + "special_attacks": [ + { + "type": "gun", + "cooldown": 5, + "gun_type": "emp_frond", + "fake_skills": [ [ "gun", 3 ], [ "pistol", 3 ] ], + "ranges": [ [ 0, 12, "DEFAULT" ] ], + "targeting_sound": "a faint buzz", + "description": "Lightning arcs from the leech blossom!" + }, + [ "LEECH_SPAWNER", 25 ], + [ "MON_LEECH_EVOLUTION", 40 ], + [ "PARROT", 40 ] + ], + "special_when_hit": [ "ZAPBACK", 100 ], + "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, + "diff": 20, + "material": [ "flesh" ], + "symbol": "y", + "color": "light_blue", + "aggression": 100, + "morale": 100, + "armor_bash": 15, + "vision_day": 30, + "vision_night": 8, + "luminance": 200, + "special_attacks": [ + { + "type": "gun", + "cooldown": 15, + "gun_type": "emp_frond", + "fake_skills": [ [ "gun", 2 ], [ "pistol", 2 ] ], + "ranges": [ [ 0, 12, "DEFAULT" ] ], + "targeting_sound": "a faint buzz", + "description": "Lightning arcs from the leech stalk!" + }, + [ "MON_LEECH_EVOLUTION", 30 ] + ], + "special_when_hit": [ "ZAPBACK", 100 ], + "death_drops": { }, + "death_function": [ "NORMAL" ], + "flags": [ "SEES", "NOHEAD", "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 within a cloudy substance.", + "default_faction": "nether", + "species": [ "LEECH_PLANT" ], + "volume": "30000 ml", + "weight": "60 kg", + "hp": 40, + "speed": 100, + "diff": 20, + "material": [ "flesh" ], + "symbol": "g", + "color": "white", + "aggression": 100, + "morale": 100, + "armor_bash": 15, + "luminance": 60, + "special_attacks": [ + { + "type": "gun", + "cooldown": 15, + "gun_type": "emp_frond", + "ranges": [ [ 0, 1, "DEFAULT" ] ], + "targeting_sound": "a faint buzz", + "description": "Lightning arcs from the pod cluster!" + }, + [ "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. 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", + "weight": "6 kg", + "hp": 40, + "speed": 120, + "diff": 20, + "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": 5, + "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 ], [ "pistol", 1 ] ], + "ranges": [ [ 0, 2, "DEFAULT" ] ], + "targeting_sound": "a faint buzz", + "description": "Sparks fly from the root runner!" + }, + [ "EVOLVE_KILL_STRIKE", 3 ] + ], + "special_when_hit": [ "ZAPBACK", 100 ], + "death_drops": { }, + "death_function": [ "NORMAL" ], + "flags": [ "SEES", "NOHEAD", "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": 5, + "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 ], [ "pistol", 1 ] ], + "ranges": [ [ 0, 2, "DEFAULT" ] ], + "targeting_sound": "a faint buzz", + "description": "Lightning arcs from the root pod!" + }, + [ "EVOLVE_KILL_STRIKE", 6 ] + ], + "death_drops": { }, + "death_function": [ "NORMAL" ], + "flags": [ "SEES", "NOHEAD", "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..914d39d991d2d 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,130 @@ 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; + 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!" ), + _( "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; + } + 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 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 ); + 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!" ), upgrade_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.in_species( LEECH_PLANT ) && !candidate.has_flag( MF_IMMOBILE ) ) { + allies.push_back( &candidate ); + } + } + if( allies.size() > 45 ) { + return true; + } + 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 ) ) { + 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->has_flag( MF_QUEEN ); + 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 ) { + 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() ); + } + } + } + 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..87b36dc00773b 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 );