diff --git a/doc/JSON_FLAGS.md b/doc/JSON_FLAGS.md index 9bf8162b1053b..809df2239c141 100644 --- a/doc/JSON_FLAGS.md +++ b/doc/JSON_FLAGS.md @@ -858,16 +858,19 @@ Flags used to describe monsters and define their properties and abilities. ### Anger, Fear and Placation Triggers -- ```FIRE``` There's a fire nearby. -- ```FRIEND_ATTACKED``` A monster of the same type was attacked. -- ```FRIEND_DIED``` A monster of the same type died. -- ```HURT``` The monster is hurt. +- ```FIRE``` Triggers if there's a fire within 3 tiles, the strength of the effect equals 5 * the field intensity of the fire. +- ```FRIEND_ATTACKED``` Triggers if the monster sees another monster of the same type being attacked; strength = 15. +- ```FRIEND_DIED``` Triggers if the monster sees another monster of the same type dying; strength = 15. +- ```HURT``` Triggers when the monster is hurt, strength equals 1 + (damage / 3 ). - ```MEAT``` Meat or a corpse is nearby. - Currently nonfunctional! - ```NULL``` Source use only? -- ```PLAYER_CLOSE``` The player gets within a few tiles distance. -- ```PLAYER_WEAK``` The player is hurt. -- ```SOUND``` Heard a sound. -- ```STALK``` Increases if already angry at the player. +- ```PLAYER_CLOSE``` Triggers when a potential enemy is within 5 tiles range - Anger/fear trigger only! +- ```PLAYER_WEAK``` Raises monster aggression by 10 - (percent of hp remaining / 10) if a potential enemy has less than 70% hp remaining - Anger trigger only! +- ```PLAYER_NEAR_BABY``` Increases monster aggression by 8 and morale by 4 if **the player** comes within 3 tiles of its offspring (defined by the baby_monster field in its reproduction data)- Anger trigger only! +- ```SOUND``` Not an actual trigger, monsters above 10 aggression and 0 morale will wander towards, monsters below 0 morale will wander away from the source of the sound for 1 turn (6, if they have the GOODHEARING flag). +- ```STALK``` Raises monster aggresssion by 1, triggers 20% of the time each turn if aggression > 5 - Anger trigger only! +- ```HOSTILE_SEEN``` Increases aggression/ decreases morale by a random amount between 0-2 for every potential enemy it can see, up to 20 aggression - Anger/fear trigger only! +- ```MATING_SEASON``` Increases aggression by 3 if a potential enemy is within 5 tiles range and the season is the same as the monster's mating season (defined by the baby_flags field in its reproduction data) - Anger trigger only! ### Categories diff --git a/doc/MONSTERS.md b/doc/MONSTERS.md index edae93eac052a..6e16aea25d22d 100644 --- a/doc/MONSTERS.md +++ b/doc/MONSTERS.md @@ -47,8 +47,8 @@ Monsters may also have any of these optional properties: | `phase` | (string) Monster's body matter state, ex. SOLID, LIQUID, GAS, PLASMA, NULL | `attack_cost` | (integer) Number of moves per regular attack (??) | `diff` | (integer) Additional monster difficulty for special and ranged attacks -| `aggression` | (integer) From totally passive `-99` to guaranteed hostile `100` -| `morale` | (integer) From lemming `-50` to bear `60` to most zombies and monsters `100` +| `aggression` | (integer) Starting aggression, the monster will become hostile when it reaches 10 +| `morale` | (integer) Starting morale, monster will flee when (current aggression + current morale) < 0 | `mountable_weight_ratio` | (float) For mounts, max ratio of mount to rider weight, ex. `0.2` for `<=20%` | `melee_skill` | (integer) Monster skill in melee combat, from `0-10`, with `4` being an average mob | `dodge` | (integer) Monster's skill at dodging attacks @@ -74,9 +74,9 @@ Monsters may also have any of these optional properties: | `regen_morale` | (bool) True if monster will stop fleeing at max HP to regenerate anger and morale | `special_attacks` | (array of objects) Special attacks the monster has | `flags` | (array of strings) Any number of attributes like SEES, HEARS, SMELLS, STUMBLES, REVIVES -| `fear_triggers` | (array of strings) What makes the monster afraid, ex. FIRE, HURT, PLAYER_CLOSE, SOUND -| `anger_triggers` | (array of strings) What makes the monster angry (same flags as fear) -| `placate_triggers` | (array of strings) What calms the monster (same flags as fear) +| `fear_triggers` | (array of strings) Triggers that lower monster morale (see JSON_FLAGS.md) +| `anger_triggers` | (array of strings) Triggers that raise monster aggression (same flags as fear) +| `placate_triggers` | (array of strings) Triggers that lower monster aggression (same flags as fear) | `revert_to_itype` | (string) Item monster can be converted to when friendly (ex. to deconstruct turrets) | `starting_ammo` | (object) Ammo that newly spawned monsters start with | `upgrades` | (boolean or object) False if monster does not upgrade, or an object do define an upgrade diff --git a/src/monmove.cpp b/src/monmove.cpp index c8e8c3421e605..f6e9f57d51bdc 100644 --- a/src/monmove.cpp +++ b/src/monmove.cpp @@ -326,9 +326,13 @@ void monster::plan() const bool angers_hostile_weak = type->has_anger_trigger( mon_trigger::HOSTILE_WEAK ); const int angers_hostile_near = type->has_anger_trigger( mon_trigger::HOSTILE_CLOSE ) ? 5 : 0; + const int angers_hostile_seen = type->has_anger_trigger( mon_trigger::HOSTILE_SEEN ) ? rng( 0, + 2 ) : 0; const int angers_mating_season = type->has_anger_trigger( mon_trigger::MATING_SEASON ) ? 3 : 0; const int angers_cub_threatened = type->has_anger_trigger( mon_trigger::PLAYER_NEAR_BABY ) ? 8 : 0; const int fears_hostile_near = type->has_fear_trigger( mon_trigger::HOSTILE_CLOSE ) ? 5 : 0; + const int fears_hostile_seen = type->has_fear_trigger( mon_trigger::HOSTILE_SEEN ) ? rng( 0, + 2 ) : 0; map &here = get_map(); std::bitset seen_levels = here.get_inter_level_visibility( pos().z ); @@ -342,6 +346,12 @@ void monster::plan() dist = rate_target( player_character, dist, smart_planning ); fleeing = fleeing || is_fleeing( player_character ); target = &player_character; + if( !fleeing && anger <= 20 ) { + anger += angers_hostile_seen; + } + if( !fleeing ) { + morale -= fears_hostile_seen; + } if( dist <= 5 ) { anger += angers_hostile_near; morale -= fears_hostile_near; @@ -407,7 +417,8 @@ void monster::plan() float rating = rate_target( who, dist, smart_planning ); bool fleeing_from = is_fleeing( who ); - if( rating == dist && ( fleeing || attitude( &who ) == MATT_ATTACK ) ) { + if( rating == dist && ( fleeing || attitude( &who ) == MATT_ATTACK || + attitude( &who ) == MATT_FOLLOW ) ) { ++valid_targets; if( one_in( valid_targets ) ) { target = &who; @@ -443,6 +454,12 @@ void monster::plan() } } } + if( !fleeing && anger <= 20 && valid_targets != 0 ) { + anger += angers_hostile_seen; + } + if( !fleeing && valid_targets != 0 ) { + morale -= fears_hostile_seen; + } } fleeing = fleeing || ( mood == MATT_FLEE ); @@ -486,6 +503,12 @@ void monster::plan() anger += angers_hostile_near; morale -= fears_hostile_near; } + if( !fleeing && anger <= 20 && valid_targets != 0 ) { + anger += angers_hostile_seen; + } + if( !fleeing && valid_targets != 0 ) { + morale -= fears_hostile_seen; + } } } } diff --git a/src/monstergenerator.cpp b/src/monstergenerator.cpp index 210f2baa711a2..46b85606d64ab 100644 --- a/src/monstergenerator.cpp +++ b/src/monstergenerator.cpp @@ -52,6 +52,7 @@ std::string enum_to_string( mon_trigger data ) case mon_trigger::MEAT: return "MEAT"; case mon_trigger::HOSTILE_WEAK: return "PLAYER_WEAK"; case mon_trigger::HOSTILE_CLOSE: return "PLAYER_CLOSE"; + case mon_trigger::HOSTILE_SEEN: return "HOSTILE_SEEN"; case mon_trigger::HURT: return "HURT"; case mon_trigger::FIRE: return "FIRE"; case mon_trigger::FRIEND_DIED: return "FRIEND_DIED"; diff --git a/src/mtype.h b/src/mtype.h index d5e09a9d623d7..229fb8beb7697 100644 --- a/src/mtype.h +++ b/src/mtype.h @@ -42,6 +42,7 @@ enum class mon_trigger : int { MEAT, // Meat or a corpse nearby HOSTILE_WEAK, // Hurt hostile player/npc/monster seen HOSTILE_CLOSE, // Hostile creature within a few tiles + HOSTILE_SEEN, // Hostile creature in visual range HURT, // We are hurt FIRE, // Fire nearby FRIEND_DIED, // A monster of the same type died