From 56dd3fc1fb7ac30e46e6482ce0611bf7d901792e Mon Sep 17 00:00:00 2001 From: Anton Simakov <67688115+GuardianDll@users.noreply.github.com> Date: Mon, 19 Aug 2024 00:35:41 +0200 Subject: [PATCH] Monster vision enchantment and evaluation (#75753) * Add enchantment to affect monster vision * improve vision_range_eval() to evaluate monster sight range also --- doc/MAGIC.md | 1 + doc/NPCs.md | 2 +- src/magic_enchantment.cpp | 3 +++ src/magic_enchantment.h | 1 + src/math_parser_diag.cpp | 4 ++++ src/monster.cpp | 6 ++++-- 6 files changed, 14 insertions(+), 3 deletions(-) diff --git a/doc/MAGIC.md b/doc/MAGIC.md index 2e693724c9259..e7486a851b94c 100644 --- a/doc/MAGIC.md +++ b/doc/MAGIC.md @@ -956,6 +956,7 @@ Character status value | Description `ARMOR_HEAT` | `ARMOR_STAB` | `REGEN_HP` | Affects the rate the monster recovers hp. +`VISION_RANGE` | Affects monster vision range, both day and night one. `SPEED` | Affects the base speed of the monster. `LUMINATION` | Affects monster luminance diff --git a/doc/NPCs.md b/doc/NPCs.md index 5300a3454f3e7..409d35221216b 100644 --- a/doc/NPCs.md +++ b/doc/NPCs.md @@ -1383,7 +1383,7 @@ _some functions support array arguments or kwargs, denoted with square brackets | npc_value() | ✅ | ✅ | u, n | Return NPC value toward opposite talker.

Example:
`{ "math": [ "n_npc_value()", "+=", "2" ] }`| | vitamin(`s`/`v`) | ✅ | ✅ | u, n | Return or set the characters vitamin level.
Argument is vitamin ID.

Example:
`{ "math": [ "u_vitamin('mutagen')", "=", "0" ] }`| | warmth(`s`/`v`) | ✅ | ❌ | u, n | Return the characters warmth on a body part.
Argument is bodypart ID.

Example:
The value displayed in-game is calculated as follows.
`"{ "math": [ "u_warmth_in_game", "=", "(u_warmth('torso') / 100) * 2 - 100"] }`| -| vision_range() | ✅ | ❌ | u, n | Return the character's visual range, adjusted by their mutations, effects, and other issues.

Example:
`"{ "math": [ "u_vision_range", "<", "30"] }`| +| vision_range() | ✅ | ❌ | u, n | Return the character's or monsters visual range, adjusted by their mutations, effects, and other issues.

Example:
`"{ "math": [ "n_vision_range()", "<", "30"] }`| | weather(`s`) | ✅ | ✅ | N/A
(global) | Return or set a weather aspect

Aspect must be one of:
`temperature` (in Kelvin),
`humidity` (as percentage),
`pressure` (in millibar),
`windpower` (in mph).
`precipitation` (in mm / h) either 0.5 (very_light ), 1.5 (light), or 3 (heavy). Read only.

Temperature conversion functions are available: `celsius()`, `fahrenheit()`, `from_celsius()`, and `from_fahrenheit()`.

Examples:
`{ "math": [ "weather('temperature')", "<", "from_fahrenheit( 33 )" ] }`
`{ "math": [ "fahrenheit( weather('temperature') )", "==", "21" ] }`| | damage_level() | ✅ | ❌ | u, n | Return the damage level of the talker, which must be an item.

Example:
`"condition": { "math": [ "n_damage_level()", "<", "1" ] }`| | climate_control_str_heat() | ✅ | ❌ | u, n | return amount of heat climate control that character currently has (character feels better in warm places with it), in warmth points; default 0, affected by CLIMATE_CONTROL_HEAT enchantment.

Example:
`"condition": { "math": [ "u_climate_control_str_heat()", "<", "0" ] }`| diff --git a/src/magic_enchantment.cpp b/src/magic_enchantment.cpp index dd9c0d90f63b6..5baf8e186c28f 100644 --- a/src/magic_enchantment.cpp +++ b/src/magic_enchantment.cpp @@ -95,6 +95,7 @@ namespace io case enchant_vals::mod::ATTACK_NOISE: return "ATTACK_NOISE"; case enchant_vals::mod::SHOUT_NOISE: return "SHOUT_NOISE"; case enchant_vals::mod::FOOTSTEP_NOISE: return "FOOTSTEP_NOISE"; + case enchant_vals::mod::VISION_RANGE: return "VISION_RANGE"; case enchant_vals::mod::SIGHT_RANGE_ELECTRIC: return "SIGHT_RANGE_ELECTRIC"; case enchant_vals::mod::MOTION_VISION_RANGE: return "MOTION_VISION_RANGE"; case enchant_vals::mod::SIGHT_RANGE_FAE: return "SIGHT_RANGE_FAE"; @@ -324,6 +325,7 @@ bool enchantment::is_monster_relevant() const pair_values.first == enchant_vals::mod::ARMOR_HEAT || pair_values.first == enchant_vals::mod::ARMOR_STAB || pair_values.first == enchant_vals::mod::REGEN_HP || + pair_values.first == enchant_vals::mod::VISION_RANGE || pair_values.first == enchant_vals::mod::SPEED || pair_values.first == enchant_vals::mod::LUMINATION ) { return true; @@ -344,6 +346,7 @@ bool enchantment::is_monster_relevant() const pair_values.first == enchant_vals::mod::ARMOR_HEAT || pair_values.first == enchant_vals::mod::ARMOR_STAB || pair_values.first == enchant_vals::mod::REGEN_HP || + pair_values.first == enchant_vals::mod::VISION_RANGE || pair_values.first == enchant_vals::mod::SPEED || pair_values.first == enchant_vals::mod::LUMINATION ) { return true; diff --git a/src/magic_enchantment.h b/src/magic_enchantment.h index 40bbb2aab53b8..bf6bd747e3dda 100644 --- a/src/magic_enchantment.h +++ b/src/magic_enchantment.h @@ -71,6 +71,7 @@ enum class mod : int { ATTACK_NOISE, SHOUT_NOISE, FOOTSTEP_NOISE, + VISION_RANGE, SIGHT_RANGE_ELECTRIC, MOTION_VISION_RANGE, SIGHT_RANGE_FAE, diff --git a/src/math_parser_diag.cpp b/src/math_parser_diag.cpp index bbf429c58058c..24e85a6b734e7 100644 --- a/src/math_parser_diag.cpp +++ b/src/math_parser_diag.cpp @@ -1478,6 +1478,10 @@ std::function vision_range_eval( char scope, talker const *const actor = d.actor( beta ); if( Character const *const chr = actor->get_character(); chr != nullptr ) { return chr->unimpaired_range(); + } else if( monster const *const mon = actor->get_monster(); mon != nullptr ) { + map &here = get_map(); + tripoint_bub_ms tripoint = get_map().bub_from_abs( mon->get_location() ); + return mon->sight_range( here.ambient_light_at( tripoint ) ); } debugmsg( "Tried to access vision range of a non-Character talker" ); return 0; diff --git a/src/monster.cpp b/src/monster.cpp index 1ae2e6f78e4b7..8ade126638dbb 100644 --- a/src/monster.cpp +++ b/src/monster.cpp @@ -1385,13 +1385,15 @@ int monster::sight_range( const float light_level ) const } static const float default_daylight = default_daylight_level(); if( light_level == 0 ) { - return type->vision_night; + return calculate_by_enchantment( type->vision_night, enchant_vals::mod::VISION_RANGE, true ); } else if( light_level >= default_daylight ) { - return type->vision_day; + return calculate_by_enchantment( type->vision_day, enchant_vals::mod::VISION_RANGE, true ); } int range = ( light_level * type->vision_day + ( default_daylight - light_level ) * type->vision_night ) / default_daylight; + range = calculate_by_enchantment( range, enchant_vals::mod::VISION_RANGE, true ); + return range; }