diff --git a/data/mods/Xedra_Evolved/effects/effects.json b/data/mods/Xedra_Evolved/effects/effects.json index ebcd36807bb7e..3d09c0b820777 100644 --- a/data/mods/Xedra_Evolved/effects/effects.json +++ b/data/mods/Xedra_Evolved/effects/effects.json @@ -2882,5 +2882,15 @@ "max_intensity": 1, "show_in_info": true, "enchantments": [ { "hit_you_effect": [ { "id": "xedra_eater_erosion_attack" } ] } ] + }, + { + "type": "effect_type", + "id": "effect_xedra_monster_erosion", + "name": [ "Eroding Time" ], + "desc": [ "This creature destabilizes time around it, eroding everything it touches." ], + "rating": "good", + "max_intensity": 1, + "show_in_info": true, + "enchantments": [ { "hit_you_effect": [ { "id": "xedra_monster_erosion_attack" } ] } ] } ] diff --git a/data/mods/Xedra_Evolved/flags.json b/data/mods/Xedra_Evolved/flags.json index ea8c7d3e5f519..bba8855bd074c 100644 --- a/data/mods/Xedra_Evolved/flags.json +++ b/data/mods/Xedra_Evolved/flags.json @@ -52,5 +52,9 @@ "id": "STABILIZED_TIMELINE", "type": "json_flag", "info": "You are immune to adverse affects on your timeline." + }, + { + "id": "STABILIZED_TIMELINE", + "type": "monster_flag" } ] diff --git a/data/mods/Xedra_Evolved/monsters/changeling.json b/data/mods/Xedra_Evolved/monsters/changeling.json index 39e2734b0b65b..0ba46ab89b3c3 100644 --- a/data/mods/Xedra_Evolved/monsters/changeling.json +++ b/data/mods/Xedra_Evolved/monsters/changeling.json @@ -496,7 +496,8 @@ "PET_MOUNTABLE", "PATH_AVOID_DANGER", "WARM", - "HIT_AND_RUN" + "HIT_AND_RUN", + "STABILIZED_TIMELINE" ], "armor": { "bash": 8, diff --git a/data/mods/Xedra_Evolved/monsters/monster_overrides.json b/data/mods/Xedra_Evolved/monsters/monster_overrides.json index 264daa76306db..d41278d7b455f 100644 --- a/data/mods/Xedra_Evolved/monsters/monster_overrides.json +++ b/data/mods/Xedra_Evolved/monsters/monster_overrides.json @@ -1,4 +1,22 @@ [ + { + "type": "MONSTER", + "id": "mon_tindalos", + "copy-from": "mon_tindalos", + "extend": { "flags": [ "STABILIZED_TIMELINE" ] } + }, + { + "type": "MONSTER", + "id": "mon_hound_tindalos", + "copy-from": "mon_hound_tindalos", + "extend": { "flags": [ "STABILIZED_TIMELINE" ] } + }, + { + "type": "MONSTER", + "id": "mon_lieutenant_shadow", + "copy-from": "mon_lieutenant_shadow", + "extend": { "flags": [ "STABILIZED_TIMELINE" ] } + }, { "id": "mon_bear_cub", "type": "MONSTER", diff --git a/data/mods/Xedra_Evolved/monsters/monsterattacks.json b/data/mods/Xedra_Evolved/monsters/monsterattacks.json index 7fc8813caa803..01b6620df0226 100644 --- a/data/mods/Xedra_Evolved/monsters/monsterattacks.json +++ b/data/mods/Xedra_Evolved/monsters/monsterattacks.json @@ -294,5 +294,54 @@ "flags": [ "SILENT", "RANDOM_DAMAGE", "RANDOM_AOE" ], "min_aoe": 7, "max_aoe": 10 + }, + { + "id": "zombie_monochrome_reset_hp", + "type": "SPELL", + "name": { "str": "Reset HP", "//~": "NO_I18N" }, + "description": { "str": "Heals 100% of health. Players should not have this spell.", "//~": "NO_I18N" }, + "message": "", + "effect": "attack", + "shape": "blast", + "valid_targets": [ "ally", "self" ], + "flags": [ "SILENT", "IGNORE_WALLS", "PERCENTAGE_DAMAGE", "NO_EXPLOSION_SFX" ], + "min_damage": -200, + "max_damage": -200, + "min_range": 0, + "max_range": 0, + "damage_type": "pure" + }, + { + "id": "xedra_monster_erosion_attack", + "type": "SPELL", + "name": { "str": "Monster Erosion - Attack", "//~": "NO_I18N" }, + "description": "This causes the dot when attacking targets with the erosion buff. Having the spell is a bug. Monster version", + "valid_targets": [ "hostile", "ground", "none" ], + "flags": [ "SILENT", "NO_PROJECTILE", "NO_EXPLOSION_SFX", "RANDOM_DAMAGE", "RANDOM_DURATION", "SPLIT_DAMAGE" ], + "message": "monster erosion attack", + "effect": "attack", + "shape": "blast", + "min_dot": 5, + "max_dot": 5, + "min_range": 10, + "max_range": 10, + "min_duration": 1000, + "max_duration": 1000, + "damage_type": "pure" + }, + { + "id": "xedra_monster_erosion_buff", + "type": "SPELL", + "name": { "str": "Monster Erosion - Buff", "//~": "NO_I18N" }, + "description": "This gives the monster the erosion buff. Having the spell is a bug. Monster version", + "valid_targets": [ "self" ], + "flags": [ "SILENT", "NO_PROJECTILE", "NO_EXPLOSION_SFX" ], + "effect": "attack", + "effect_str": "effect_xedra_monster_erosion", + "shape": "blast", + "min_duration": 100000, + "max_duration": 100000, + "min_range": 0, + "max_range": 0 } ] diff --git a/data/mods/Xedra_Evolved/monsters/monstergroup.json b/data/mods/Xedra_Evolved/monsters/monstergroup.json index ac0b5d0292709..06070ff1a7599 100644 --- a/data/mods/Xedra_Evolved/monsters/monstergroup.json +++ b/data/mods/Xedra_Evolved/monsters/monstergroup.json @@ -366,5 +366,20 @@ { "monster": "mon_samhain_ghost_axe", "weight": 333 }, { "monster": "mon_samhain_ghost_spear", "weight": 333 } ] + }, + { + "type": "monstergroup", + "name": "GROUP_ZOMBIE_UPGRADE", + "monsters": [ { "monster": "mon_zombie_monochrome", "weight": 30 } ] + }, + { + "type": "monstergroup", + "name": "GROUP_ZOMBIE_MONOCHROME_UPGRADE", + "default": "mon_zombie_monochrome", + "monsters": [ + { "monster": "mon_zombie_monochrome", "weight": 450 }, + { "monster": "mon_zombie_monochrome_2", "weight": 225 }, + { "monster": "mon_zombie_monochrome_3", "weight": 100 } + ] } ] diff --git a/data/mods/Xedra_Evolved/monsters/zombies.json b/data/mods/Xedra_Evolved/monsters/zombies.json new file mode 100644 index 0000000000000..26803e00e66f9 --- /dev/null +++ b/data/mods/Xedra_Evolved/monsters/zombies.json @@ -0,0 +1,83 @@ +[ + { + "id": "mon_zombie_monochrome", + "copy-from": "mon_zombie_base", + "type": "MONSTER", + "name": { "str": "monochrome zombie" }, + "description": "What stands in front of you is one of the healthiest zombies you've ever seen. If not for the black muck oozing from its orifices and shambling gait, you might even think it human. Every part of this zombie, even its clothes, is colored some shade of gray, and every couple of seconds it flickers.", + "symbol": "Z", + "color": "light_gray", + "special_attacks": [ + { "id": "grab", "cooldown": 1 }, + { "id": "bite_humanoid", "cooldown": 5 }, + { + "id": "zombie_monochrome_reset_hp_attack", + "type": "spell", + "condition": { "math": [ "u_hp('ALL') < u_hp_max('bp_null')" ] }, + "spell_data": { "id": "zombie_monochrome_reset_hp" }, + "allow_no_target": true, + "cooldown": 10, + "monster_message": "%1$s flickers and all of its injuries disappear!" + } + ], + "upgrades": { "half_life": 25, "into_group": "GROUP_ZOMBIE_MONOCHROME_UPGRADE" } + }, + { + "id": "mon_zombie_monochrome_2", + "copy-from": "mon_zombie_base", + "type": "MONSTER", + "name": { "str": "distorted zombie" }, + "description": "This zombie is partially obscured by the gray, distorted air around it. From what you can see it doesn't have a single wound on its body, and it moves much quicker than a zombie should. Every few seconds the distortions surge.", + "symbol": "Z", + "color": "light_gray", + "proportional": { "speed": 1.5, "hp": 1.5 }, + "special_attacks": [ + { "id": "grab", "cooldown": 1 }, + { "id": "bite_humanoid", "cooldown": 5 }, + { + "id": "zombie_monochrome_reset_hp_attack", + "type": "spell", + "condition": { "math": [ "u_hp('ALL') < u_hp_max('bp_null')" ] }, + "spell_data": { "id": "zombie_monochrome_reset_hp" }, + "allow_no_target": true, + "cooldown": 5, + "monster_message": "%1$s flickers and all of its injuries disappear!" + } + ], + "upgrades": { "half_life": 25, "into": "mon_zombie_monochrome_3" }, + "extend": { "flags": [ "STABILIZED_TIMELINE" ] } + }, + { + "id": "mon_zombie_monochrome_3", + "copy-from": "mon_zombie_base", + "type": "MONSTER", + "name": { "str": "zombie timewound" }, + "description": "Every bit of color around this zombie has been sapped a distorted gray. In contrast with its healthy appearance, the surrounding environment seems to slowly erode, even after it swiftly moves away. It sharply flickers every few seconds.", + "symbol": "Z", + "color": "dark_gray", + "proportional": { "speed": 2, "hp": 2 }, + "special_attacks": [ + { "id": "grab", "cooldown": 1 }, + { "id": "bite_humanoid", "cooldown": 5 }, + { + "id": "zombie_monochrome_reset_hp_special", + "type": "spell", + "condition": { "math": [ "u_hp('ALL') < u_hp_max('bp_null')" ] }, + "spell_data": { "id": "zombie_monochrome_reset_hp" }, + "allow_no_target": true, + "cooldown": 2, + "monster_message": "%1$s flickers and all of its injuries disappear!" + }, + { + "id": "xedra_monster_erosion_buff_special", + "type": "spell", + "condition": { "not": { "u_has_effect": "effect_xedra_monster_erosion" } }, + "spell_data": { "id": "xedra_monster_erosion_buff" }, + "allow_no_target": true, + "monster_message": "The ground around %1$s starts eroding into nothingness." + } + ], + "extend": { "flags": [ "STABILIZED_TIMELINE" ] }, + "upgrades": false + } +] diff --git a/src/character.cpp b/src/character.cpp index 1433a07b9d345..3114fa1b6fbcd 100644 --- a/src/character.cpp +++ b/src/character.cpp @@ -10585,7 +10585,7 @@ void Character::echo_pulse() } // It's not moving. Must be an obstacle if( critter->has_flag( mon_flag_IMMOBILE ) || - critter->has_effect_with_flag( json_flag_CANNOT_MOVE ) ) { + critter->has_flag( json_flag_CANNOT_MOVE ) ) { echo_string = _( "click." ); } sounds::sound( origin, echo_volume, sounds::sound_t::sensory, _( echo_string ), false, diff --git a/src/character.h b/src/character.h index cc62b58920ee0..e143007b7aff3 100644 --- a/src/character.h +++ b/src/character.h @@ -1397,7 +1397,7 @@ class Character : public Creature, public visitable /** This is to prevent clang complaining about overloading a virtual function, the creature version uses monster flags so confusion is unlikely. */ using Creature::has_flag; /** Returns true if player has a trait, bionic, effect, bodypart, or martial arts buff with a flag */ - bool has_flag( const json_character_flag &flag ) const; + bool has_flag( const json_character_flag &flag ) const override; /** Returns the count of traits, bionics, effects, bodyparts, and martial arts buffs with a flag */ int count_flag( const json_character_flag &flag ) const; diff --git a/src/creature.cpp b/src/creature.cpp index 404b13d79de58..15bca269f65ea 100644 --- a/src/creature.cpp +++ b/src/creature.cpp @@ -902,7 +902,7 @@ int Creature::deal_melee_attack( Creature *source, int hitroll ) add_msg_debug( debugmode::DF_CREATURE, "Dodge roll %.1f", dodge ); - if( has_flag( mon_flag_IMMOBILE ) || has_effect_with_flag( json_flag_CANNOT_MOVE ) ) { + if( has_flag( mon_flag_IMMOBILE ) || has_flag( json_flag_CANNOT_MOVE ) ) { // Under normal circumstances, even a clumsy person would // not miss a turret. It should, however, be possible to // miss a smaller target, especially when wielding a @@ -1366,7 +1366,7 @@ void Creature::deal_projectile_attack( Creature *source, dealt_projectile_attack dealt_damage_instance Creature::deal_damage( Creature *source, bodypart_id bp, const damage_instance &dam, const weakpoint_attack &attack ) { - if( is_dead_state() || has_effect_with_flag( json_flag_CANNOT_TAKE_DAMAGE ) ) { + if( is_dead_state() || has_flag( json_flag_CANNOT_TAKE_DAMAGE ) ) { return dealt_damage_instance(); } int total_damage = 0; @@ -2035,7 +2035,7 @@ void Creature::process_effects() for( auto &elem : *effects ) { for( auto &_it : elem.second ) { // Do not freeze the effect with the FREEZE_EFFECTS flag. - if( has_effect_with_flag( json_flag_FREEZE_EFFECTS ) && + if( has_flag( json_flag_FREEZE_EFFECTS ) && !_it.second.has_flag( json_flag_FREEZE_EFFECTS ) ) { continue; } diff --git a/src/creature.h b/src/creature.h index 1a346ec654be2..50fba973b1929 100644 --- a/src/creature.h +++ b/src/creature.h @@ -765,6 +765,9 @@ class Creature : public viewer virtual bool has_flag( const mon_flag_id & ) const { return false; } + virtual bool has_flag( const flag_id & ) const { + return false; + } virtual bool uncanny_dodge() { return false; } diff --git a/src/game.cpp b/src/game.cpp index 747c9b3c4f635..d501a03488e0c 100644 --- a/src/game.cpp +++ b/src/game.cpp @@ -11892,7 +11892,7 @@ bool game::fling_creature( Creature *c, const units::angle &dir, float flvel, bo return false; } - if( c->has_effect_with_flag( json_flag_CANNOT_MOVE ) ) { + if( c->has_flag( json_flag_CANNOT_MOVE ) ) { // cannot fling creatures that cannot move. return false; } diff --git a/src/magic_enchantment.cpp b/src/magic_enchantment.cpp index 03e9fc239bfdc..0f279dcb57265 100644 --- a/src/magic_enchantment.cpp +++ b/src/magic_enchantment.cpp @@ -352,6 +352,11 @@ bool enchantment::is_monster_relevant() const } } + // check for hit you / me effects + if( !hit_you_effect.empty() || !hit_me_effect.empty() ) { + return true; + } + if( !damage_values_add.empty() || !damage_values_multiply.empty() || !armor_values_add.empty() || !armor_values_multiply.empty() ) { return true; @@ -1384,6 +1389,20 @@ void enchant_cache::activate_passive( Character &guy ) const } } +void enchant_cache::cast_hit_you( Creature &caster, const Creature &target ) const +{ + for( const fake_spell &sp : hit_you_effect ) { + cast_enchantment_spell( caster, &target, sp ); + } +} + +void enchant_cache::cast_hit_me( Creature &caster, const Creature *target ) const +{ + for( const fake_spell &sp : hit_me_effect ) { + cast_enchantment_spell( caster, target, sp ); + } +} + void enchant_cache::cast_hit_you( Character &caster, const Creature &target ) const { for( const fake_spell &sp : hit_you_effect ) { @@ -1398,7 +1417,7 @@ void enchant_cache::cast_hit_me( Character &caster, const Creature *target ) con } } -void enchant_cache::cast_enchantment_spell( Character &caster, const Creature *target, +void enchant_cache::cast_enchantment_spell( Creature &caster, const Creature *target, const fake_spell &sp ) const { // check the chances diff --git a/src/magic_enchantment.h b/src/magic_enchantment.h index f91fd480e06df..d3871fd062ee6 100644 --- a/src/magic_enchantment.h +++ b/src/magic_enchantment.h @@ -326,15 +326,17 @@ class enchant_cache : public enchantment // checks if the enchantments have the same active_conditions bool stacks_with( const enchantment &rhs ) const; // performs cooldown and distance checks before casting enchantment spells - void cast_enchantment_spell( Character &caster, const Creature *target, + void cast_enchantment_spell( Creature &caster, const Creature *target, const fake_spell &sp ) const; //Clears all the maps and vectors in the cache. void clear(); // casts all the hit_you_effects on the target void cast_hit_you( Character &caster, const Creature &target ) const; + void cast_hit_you( Creature &caster, const Creature &target ) const; // casts all the hit_me_effects on self or a target depending on the enchantment definition void cast_hit_me( Character &caster, const Creature *target ) const; + void cast_hit_me( Creature &caster, const Creature *target ) const; void serialize( JsonOut &jsout ) const; void add_value_add( enchant_vals::mod value, int add_value ); diff --git a/src/mattack_actors.cpp b/src/mattack_actors.cpp index 56f1434d20381..f5afba2cf8ab3 100644 --- a/src/mattack_actors.cpp +++ b/src/mattack_actors.cpp @@ -884,7 +884,7 @@ bool melee_actor::call( monster &z ) const } } if( throw_strength > 0 && !( target->has_flag( mon_flag_IMMOBILE ) || - target->has_effect_with_flag( json_flag_CANNOT_MOVE ) ) ) { + target->has_flag( json_flag_CANNOT_MOVE ) ) ) { if( g->fling_creature( target, coord_to_angle( z.pos(), target->pos() ), throw_strength ) ) { target->add_msg_player_or_npc( msg_type, throw_msg_u, diff --git a/src/melee.cpp b/src/melee.cpp index 148b9ab7ff443..b9f6d8cabf327 100644 --- a/src/melee.cpp +++ b/src/melee.cpp @@ -697,8 +697,8 @@ bool Character::melee_attack_abstract( Creature &t, bool allow_special, // Practice melee and relevant weapon skill (if any) except when using CQB bionic, if the creature is a hallucination, or if the creature cannot move and take damage. if( !has_active_bionic( bio_cqb ) && !t.is_hallucination() && - !( t.has_effect_with_flag( json_flag_CANNOT_MOVE ) && - t.has_effect_with_flag( json_flag_CANNOT_TAKE_DAMAGE ) ) ) { + !( t.has_flag( json_flag_CANNOT_MOVE ) && + t.has_flag( json_flag_CANNOT_TAKE_DAMAGE ) ) ) { melee_train( *this, 2, std::min( 5, skill_training_cap ), cur_weap, attack_vector_vector_null ); } @@ -879,8 +879,8 @@ bool Character::melee_attack_abstract( Creature &t, bool allow_special, // Practice melee and relevant weapon skill (if any) except when using CQB bionic, if the creature is a hallucination, or if the creature cannot move and take damage. if( !has_active_bionic( bio_cqb ) && !t.is_hallucination() && - !( t.has_effect_with_flag( json_flag_CANNOT_MOVE ) && - t.has_effect_with_flag( json_flag_CANNOT_TAKE_DAMAGE ) ) ) { + !( t.has_flag( json_flag_CANNOT_MOVE ) && + t.has_flag( json_flag_CANNOT_TAKE_DAMAGE ) ) ) { melee_train( *this, 5, std::min( 10, skill_training_cap ), cur_weap, vector_id ); } @@ -1786,7 +1786,7 @@ void Character::perform_technique( const ma_technique &technique, Creature &t, } if( technique.side_switch && !( t.has_flag( mon_flag_IMMOBILE ) || - t.has_effect_with_flag( json_flag_CANNOT_MOVE ) ) ) { + t.has_flag( json_flag_CANNOT_MOVE ) ) ) { const tripoint b = t.pos(); point new_; @@ -1813,7 +1813,7 @@ void Character::perform_technique( const ma_technique &technique, Creature &t, } map &here = get_map(); if( technique.knockback_dist && !( t.has_flag( mon_flag_IMMOBILE ) || - t.has_effect_with_flag( json_flag_CANNOT_MOVE ) ) ) { + t.has_flag( json_flag_CANNOT_MOVE ) ) ) { const tripoint_bub_ms prev_pos = t.pos_bub(); // track target startpoint for knockback_follow const point kb_offset( rng( -technique.knockback_spread, technique.knockback_spread ), rng( -technique.knockback_spread, technique.knockback_spread ) ); diff --git a/src/monmove.cpp b/src/monmove.cpp index b5f58a05b36ec..2c07183398e98 100644 --- a/src/monmove.cpp +++ b/src/monmove.cpp @@ -127,6 +127,9 @@ bool monster::is_immune_field( const field_type_id &fid ) const if( ft.immune_mtypes.count( type->id ) > 0 ) { return true; } + if( check_immunity_data( ft.immunity_data ) ) { + return true; + } // No specific immunity was found, so fall upwards return Creature::is_immune_field( fid ); } @@ -139,7 +142,9 @@ static bool z_is_valid( int z ) bool monster::will_move_to( const tripoint &p ) const { map &here = get_map(); - if( here.impassable( p ) ) { + const std::vector impassable_field_ids = here.get_impassable_field_type_ids_at( p ); + if( !here.passable_skip_fields( p ) || ( !impassable_field_ids.empty() && + !is_immune_fields( impassable_field_ids ) ) ) { if( digging() ) { if( !here.has_flag( ter_furn_flag::TFLAG_BURROWABLE, p ) ) { return false; @@ -1520,13 +1525,13 @@ tripoint monster::scent_move() return random_entry( smoves, next ); } -int monster::calc_movecost( const tripoint &f, const tripoint &t ) const +int monster::calc_movecost( const tripoint &f, const tripoint &t, bool ignore_fields ) const { int movecost = 0; map &here = get_map(); - const int source_cost = here.move_cost( f ); - const int dest_cost = here.move_cost( t ); + const int source_cost = here.move_cost( f, nullptr, ignore_fields ); + const int dest_cost = here.move_cost( t, nullptr, ignore_fields ); // Digging and flying monsters ignore terrain cost if( flies() || ( digging() && here.has_flag( ter_furn_flag::TFLAG_DIGGABLE, t ) ) ) { movecost = 100; @@ -1535,36 +1540,36 @@ int monster::calc_movecost( const tripoint &f, const tripoint &t ) const if( here.has_flag( ter_furn_flag::TFLAG_SWIMMABLE, f ) ) { movecost += 25; } else { - movecost += 50 * here.move_cost( f ); + movecost += 50 * source_cost; } if( here.has_flag( ter_furn_flag::TFLAG_SWIMMABLE, t ) ) { movecost += 25; } else { - movecost += 50 * here.move_cost( t ); + movecost += 50 * dest_cost; } } else if( can_submerge() ) { // No-breathe monsters have to walk underwater slowly if( here.has_flag( ter_furn_flag::TFLAG_SWIMMABLE, f ) ) { movecost += 250; } else { - movecost += 50 * here.move_cost( f ); + movecost += 50 * source_cost; } if( here.has_flag( ter_furn_flag::TFLAG_SWIMMABLE, t ) ) { movecost += 250; } else { - movecost += 50 * here.move_cost( t ); + movecost += 50 * dest_cost; } movecost /= 2; } else if( climbs() ) { if( here.has_flag( ter_furn_flag::TFLAG_CLIMBABLE, f ) ) { movecost += 150; } else { - movecost += 50 * here.move_cost( f ); + movecost += 50 * source_cost; } if( here.has_flag( ter_furn_flag::TFLAG_CLIMBABLE, t ) ) { movecost += 150; } else { - movecost += 50 * here.move_cost( t ); + movecost += 50 * dest_cost; } movecost /= 2; } else { @@ -1825,8 +1830,11 @@ bool monster::move_to( const tripoint &p, bool force, bool step_on_critter, // Allows climbing monsters to move on terrain with movecost <= 0 Creature *critter = get_creature_tracker().creature_at( destination, is_hallucination() ); + const std::vector impassable_field_ids = here.get_impassable_field_type_ids_at( + destination ); if( here.has_flag( ter_furn_flag::TFLAG_CLIMBABLE, destination ) ) { - if( here.impassable( destination ) && critter == nullptr ) { + if( ( !here.passable_skip_fields( destination ) || ( !impassable_field_ids.empty() && + !is_immune_fields( impassable_field_ids ) ) ) && critter == nullptr ) { if( flies() ) { mod_moves( -get_speed() ); force = true; @@ -1865,7 +1873,8 @@ bool monster::move_to( const tripoint &p, bool force, bool step_on_critter, static_cast( climbs() && here.has_flag( ter_furn_flag::TFLAG_NO_FLOOR, p ) ? calc_climb_cost( pos_bub().raw(), destination.raw() ) : calc_movecost( pos_bub().raw(), - destination.raw() ) ); + destination.raw(), ( !impassable_field_ids.empty() && + is_immune_fields( impassable_field_ids ) ) ) ); if( cost > 0.0f ) { mod_moves( -static_cast( std::ceil( cost ) ) ); } else { diff --git a/src/monster.cpp b/src/monster.cpp index 5ed42536b0f8e..c203fa1bbe5f7 100644 --- a/src/monster.cpp +++ b/src/monster.cpp @@ -1326,7 +1326,7 @@ bool monster::has_flag( const mon_flag_id &f ) const return type->has_flag( f ); } -bool monster::has_flag( const flag_id f ) const +bool monster::has_flag( const flag_id &f ) const { mon_flag_str_id checked( f.c_str() ); add_msg_debug( debugmode::DF_MONSTER, @@ -1941,6 +1941,21 @@ bool monster::is_immune_effect( const efftype_id &effect ) const has_flag( mon_flag_FLIES ) || has_flag( mon_flag_IMMOBILE ) || has_flag( json_flag_CANNOT_MOVE ); } } + for( const flag_id &flag : effect->immune_flags ) { + if( has_flag( flag ) ) { + return true; + } + } + return false; +} + +bool monster::check_immunity_data( const field_immunity_data &ft ) const +{ + for( const flag_id &flag : ft.immunity_data_flags ) { + if( has_flag( flag ) ) { + return true; + } + } return false; } @@ -2181,6 +2196,10 @@ bool monster::melee_attack( Creature &target, float accuracy ) return true; } + if( hitspread >= 0 && !is_hallucination() ) { + enchantment_cache->cast_hit_you( *this, target ); + } + if( total_dealt <= 0 ) { return true; } @@ -2595,7 +2614,7 @@ float monster::stability_roll() const float monster::get_dodge() const { - if( has_effect( effect_downed ) || has_effect_with_flag( json_flag_CANNOT_MOVE ) ) { + if( has_effect( effect_downed ) || has_flag( json_flag_CANNOT_MOVE ) ) { return 0.0f; } @@ -3794,6 +3813,8 @@ void monster::on_hit( Creature *source, bodypart_id, } } + enchantment_cache->cast_hit_me( *this, source ); + check_dead_state(); // TODO: Faction relations } diff --git a/src/monster.h b/src/monster.h index fc1154b1bce11..c29b0a892d1fc 100644 --- a/src/monster.h +++ b/src/monster.h @@ -166,7 +166,8 @@ class monster : public Creature // // Returns true if f is set (see mtype.h) bool has_flag( const mon_flag_id &f ) const final; // Evaluates monster for both JSON and monster flags (converted to mon_flag_id) - bool has_flag( flag_id f ) const; + using Creature::has_flag; + bool has_flag( const flag_id &f ) const override; bool can_see() const; // MF_SEES and no MF_BLIND bool can_hear() const; // MF_HEARS and no MF_DEAF bool can_submerge() const; // MF_AQUATIC or swims() or MF_NO_BREATH, and not MF_ELECTRONIC @@ -268,10 +269,11 @@ class monster : public Creature bool die_if_drowning( const tripoint &at_pos, int chance = 1 ); tripoint scent_move(); - int calc_movecost( const tripoint &f, const tripoint &t ) const; + int calc_movecost( const tripoint &f, const tripoint &t, bool ignore_fields = false ) const; int calc_climb_cost( const tripoint &f, const tripoint &t ) const; bool is_immune_field( const field_type_id &fid ) const override; + bool check_immunity_data( const field_immunity_data &ft ) const override; /** * Attempt to move to p. diff --git a/src/ranged.cpp b/src/ranged.cpp index 0fa2e4b6f6c53..8567a5ac38ccb 100644 --- a/src/ranged.cpp +++ b/src/ranged.cpp @@ -1566,13 +1566,13 @@ dealt_projectile_attack Character::throw_item( const tripoint_bub_ms &target, co if( critter && dealt_attack.hit_critter != nullptr && missed_by <= 0.1 && !critter->has_flag( mon_flag_IMMOBILE ) && - !critter->has_effect_with_flag( json_flag_CANNOT_MOVE ) ) { + !critter->has_flag( json_flag_CANNOT_MOVE ) ) { practice( skill_throw, final_xp_mult, MAX_SKILL ); // TODO: Check target for existence of head get_event_bus().send( getID() ); } else if( critter && dealt_attack.hit_critter != nullptr && missed_by > 0.0f && !critter->has_flag( mon_flag_IMMOBILE ) && - !critter->has_effect_with_flag( json_flag_CANNOT_MOVE ) ) { + !critter->has_flag( json_flag_CANNOT_MOVE ) ) { practice( skill_throw, final_xp_mult / ( 1.0f + missed_by ), MAX_SKILL ); } else { // Pure grindy practice - cap gain at lvl 2 diff --git a/src/vehicle_move.cpp b/src/vehicle_move.cpp index 43436d5d2b1c8..ca57530d02113 100644 --- a/src/vehicle_move.cpp +++ b/src/vehicle_move.cpp @@ -1115,7 +1115,7 @@ veh_collision vehicle::part_collision( int part, const tripoint_bub_ms &p, critter->get_armor_type( damage_bash, bodypart_id( "torso" ) ); dam = std::max( 0, dam - armor ); critter->apply_damage( driver, bodypart_id( "torso" ), dam ); - if( !critter->has_effect_with_flag( json_flag_CANNOT_TAKE_DAMAGE ) ) { + if( !critter->has_flag( json_flag_CANNOT_TAKE_DAMAGE ) ) { if( vpi.has_flag( "SHARP" ) ) { critter->add_effect( effect_source( driver ), effect_bleed, 1_minutes * rng( 1, dam ), critter->get_random_body_part_of_type( body_part_type::type::torso ) );