From 1ccd2f3d41f110419b03796db7259a1bb6e63b6f Mon Sep 17 00:00:00 2001 From: andrei Date: Wed, 24 Jan 2024 08:23:42 +0200 Subject: [PATCH 1/3] eoc/math_parser: migrate all shimmed functions to native --- .../mutation_eocs/changing_eocs.json | 2 +- .../portal_storm_effect_on_condition.json | 4 +- data/json/monster_special_attacks/spells.json | 2 +- data/mods/Magiclysm/Spells/animist.json | 4 +- .../Magiclysm/enchantments/Basic_Classes.json | 4 +- .../Magiclysm/eoc_caster_level_boosts.json | 56 +-- data/mods/MindOverMatter/NewPowerGuide.md | 2 +- .../effectoncondition/eoc_items.json | 2 +- .../eoc_nether_attunement_events.json | 4 +- .../effects/effects_psionic.json | 2 +- .../mutations/psi_passives.json | 42 +- .../MindOverMatter/npcs/dialogue/Rubik.json | 2 +- .../npcs/dialogue/generic_dialogue.json | 4 +- .../npcs/dialogue/refugee_guards_traitor.json | 4 +- .../powers/biokinesis_concentration_eocs.json | 2 +- .../clairsentience_concentration_eocs.json | 4 +- .../MindOverMatter/powers/electrokinesis.json | 4 +- .../photokinesis_concentration_eoc.json | 4 +- .../mods/MindOverMatter/powers/telepathy.json | 16 +- .../MindOverMatter/powers/vitakinesis.json | 8 +- .../practice/electrokinesis_practice.json | 6 +- .../practice/pyrokinesis_practice.json | 4 +- data/mods/Sky_Island/EOCs.json | 8 +- .../effects/effect_on_condition.json | 2 +- .../mods/Xedra_Evolved/spells/spell_eocs.json | 2 +- doc/EFFECT_ON_CONDITION.md | 2 +- doc/NPCs.md | 16 +- src/condition.cpp | 359 ------------------ tests/math_parser_test.cpp | 6 - 29 files changed, 79 insertions(+), 498 deletions(-) diff --git a/data/json/effects_on_condition/mutation_eocs/changing_eocs.json b/data/json/effects_on_condition/mutation_eocs/changing_eocs.json index 0ff48e9d14653..1ded5e2e01172 100644 --- a/data/json/effects_on_condition/mutation_eocs/changing_eocs.json +++ b/data/json/effects_on_condition/mutation_eocs/changing_eocs.json @@ -8,7 +8,7 @@ "deactivate_condition": { "u_has_flag": "CHANGING" }, "effect": [ { - "weighted_list_eocs": [ [ "changing_failed", 2500 ], [ "changing_successful", { "u_val": "vitamin", "name": "mutagen" } ] ] + "weighted_list_eocs": [ [ "changing_failed", 2500 ], [ "changing_successful", { "math": [ "u_vitamin('mutagen')" ] } ] ] } ] }, diff --git a/data/json/effects_on_condition/nether_eocs/portal_storm_effect_on_condition.json b/data/json/effects_on_condition/nether_eocs/portal_storm_effect_on_condition.json index ca7b62aa9e8dc..544129008c428 100644 --- a/data/json/effects_on_condition/nether_eocs/portal_storm_effect_on_condition.json +++ b/data/json/effects_on_condition/nether_eocs/portal_storm_effect_on_condition.json @@ -38,7 +38,7 @@ }, "deactivate_condition": { "not": { "is_weather": "early_portal_storm" } }, "effect": { - "switch": { "distance": [ "u", { "global_val": "portal_storm_center" } ] }, + "switch": { "math": [ "distance('u', portal_storm_center)" ] }, "cases": [ { "case": 0, @@ -396,7 +396,7 @@ "//": "This displays messages depending on the storms strength.", "condition": { "and": [ "u_can_see", { "not": { "u_has_worn_with_flag": "PORTAL_PROOF" } } ] }, "effect": { - "switch": { "distance": [ "u", { "global_val": "portal_storm_center" } ] }, + "switch": { "math": [ "distance('u', portal_storm_center)" ] }, "cases": [ { "case": 0, diff --git a/data/json/monster_special_attacks/spells.json b/data/json/monster_special_attacks/spells.json index 749e7117a3c89..bd59e76b44c09 100644 --- a/data/json/monster_special_attacks/spells.json +++ b/data/json/monster_special_attacks/spells.json @@ -791,7 +791,7 @@ "type": "effect_on_condition", "id": "EOC_mon_reflection_attack", "effect": { - "switch": { "distance": [ "u", "npc" ] }, + "switch": { "math": [ "distance('u', 'npc')" ] }, "cases": [ { "case": 0, diff --git a/data/mods/Magiclysm/Spells/animist.json b/data/mods/Magiclysm/Spells/animist.json index b3808730c216d..2e96e9047203b 100644 --- a/data/mods/Magiclysm/Spells/animist.json +++ b/data/mods/Magiclysm/Spells/animist.json @@ -93,7 +93,7 @@ "type": "effect_on_condition", "id": "EOC_SUMMON_ZOMBIE", "effect": { - "switch": { "u_val": "spell_level", "spell": "summon_undead" }, + "switch": { "math": [ "u_spell_level('summon_undead')" ] }, "cases": [ { "case": 0, "effect": { "u_cast_spell": { "id": "summon_zombie" } } }, { "case": 7, "effect": { "u_cast_spell": { "id": "summon_tough_zombie" } } }, @@ -235,7 +235,7 @@ "type": "effect_on_condition", "id": "EOC_SUMMON_ZOMBIE_SWARM", "effect": { - "switch": { "u_val": "spell_level", "spell": "summon_undead" }, + "switch": { "math": [ "u_spell_level('summon_undead')" ] }, "cases": [ { "case": 0, "effect": { "u_cast_spell": { "id": "summon_zombie_dog" } } }, { "case": 5, "effect": { "u_cast_spell": { "id": "summon_dog_skeleton" } } }, diff --git a/data/mods/Magiclysm/enchantments/Basic_Classes.json b/data/mods/Magiclysm/enchantments/Basic_Classes.json index 8071e3d0894d8..cc99974721be6 100644 --- a/data/mods/Magiclysm/enchantments/Basic_Classes.json +++ b/data/mods/Magiclysm/enchantments/Basic_Classes.json @@ -2,11 +2,11 @@ { "type": "enchantment", "id": "KELVINIST", - "values": [ { "value": "ARMOR_HEAT", "add": { "math": [ "u_val('spell_level', 'school: KELVINIST') / -6" ] } } ] + "values": [ { "value": "ARMOR_HEAT", "add": { "math": [ "u_school_level('KELVINIST') / -6" ] } } ] }, { "type": "enchantment", "id": "STORMSHAPER", - "values": [ { "value": "ARMOR_ELEC", "add": { "math": [ "u_val('spell_level', 'school: STORMSHAPER') / -6" ] } } ] + "values": [ { "value": "ARMOR_ELEC", "add": { "math": [ "u_school_level('STORMSHAPER') / -6" ] } } ] } ] diff --git a/data/mods/Magiclysm/eoc_caster_level_boosts.json b/data/mods/Magiclysm/eoc_caster_level_boosts.json index 83fe3081011f5..194ae807a7395 100644 --- a/data/mods/Magiclysm/eoc_caster_level_boosts.json +++ b/data/mods/Magiclysm/eoc_caster_level_boosts.json @@ -14,18 +14,10 @@ "condition": { "u_has_trait": "MAGUS" }, "effect": [ { - "math": [ - "u_level_boost", - "=", - "u_val('item_count', 'item: magus_booster_1_active') + u_val('item_count', 'item: magus_booster_2_active') * 2" - ] + "math": [ "u_level_boost", "=", "u_item_count('magus_booster_1_active') + u_item_count('magus_booster_2_active') * 2" ] }, { - "math": [ - "u_val('spell_level_adjustment', 'school: MAGUS')", - "=", - "limit_caster_level_boost(u_level_boost, u_val('spell_level', 'school: MAGUS') )" - ] + "math": [ "u_school_level_adjustment('MAGUS')", "=", "limit_caster_level_boost(u_level_boost, u_school_level('MAGUS') )" ] } ] }, @@ -37,17 +29,13 @@ "condition": { "u_has_trait": "KELVINIST" }, "effect": [ { - "math": [ - "u_level_boost", - "=", - "u_val('item_count', 'item: kelvinist_booster_1_active') + u_val('item_count', 'item: kelvinist_booster_2_active') * 2" - ] + "math": [ "u_level_boost", "=", "u_item_count('kelvinist_booster_1_active') + u_item_count('kelvinist_booster_2_active') * 2" ] }, { "math": [ - "u_val('spell_level_adjustment', 'school: KELVINIST')", + "u_school_level_adjustment('KELVINIST')", "=", - "limit_caster_level_boost(u_level_boost, u_val('spell_level', 'school: KELVINIST') )" + "limit_caster_level_boost(u_level_boost, u_school_level('KELVINIST') )" ] } ] @@ -63,21 +51,21 @@ "math": [ "u_level_boost", "=", - "max( 0, u_effect_intensity('technomancer_cl_booster_effect') ) + u_val('charge_count', 'item: technomancer_booster_2_active') / 5" + "max( 0, u_effect_intensity('technomancer_cl_booster_effect') ) + u_charge_count('technomancer_booster_2_active') / 5" ] }, { "math": [ - "u_val('spell_level_adjustment', 'school: TECHNOMANCER')", + "u_school_level_adjustment('TECHNOMANCER')", "=", - "limit_caster_level_boost(u_level_boost, u_val('spell_level', 'school: TECHNOMANCER') )" + "limit_caster_level_boost(u_level_boost, u_school_level('TECHNOMANCER') )" ] }, { "math": [ "u_doodad_boost", "=", - "max( 0, limit_caster_level_boost(u_level_boost, u_val('spell_level', 'school: TECHNOMANCER') ) - max( 0, u_effect_intensity('technomancer_cl_booster_effect') ) )" + "max( 0, limit_caster_level_boost(u_level_boost, u_school_level('TECHNOMANCER') ) - max( 0, u_effect_intensity('technomancer_cl_booster_effect') ) )" ] } ] @@ -106,9 +94,9 @@ { "math": [ "u_level_boost", "=", "max( 0, u_effect_intensity('biomancer_cl_booster_effect') )" ] }, { "math": [ - "u_val('spell_level_adjustment', 'school: BIOMANCER')", + "u_school_level_adjustment('BIOMANCER')", "=", - "limit_caster_level_boost(u_level_boost, u_val('spell_level', 'school: BIOMANCER') )" + "limit_caster_level_boost(u_level_boost, u_school_level('BIOMANCER') )" ] } ] @@ -120,13 +108,9 @@ "required_event": "opens_spellbook", "condition": { "u_has_trait": "ANIMIST" }, "effect": [ - { "math": [ "u_level_boost", "=", "u_val('field_strength', 'field: fd_blood')" ] }, + { "math": [ "u_level_boost", "=", "u_field_strength('fd_blood')" ] }, { - "math": [ - "u_val('spell_level_adjustment', 'school: ANIMIST')", - "=", - "limit_caster_level_boost(u_level_boost, u_val('spell_level', 'school: ANIMIST') )" - ] + "math": [ "u_school_level_adjustment('ANIMIST')", "=", "limit_caster_level_boost(u_level_boost, u_school_level('ANIMIST') )" ] } ] }, @@ -140,9 +124,9 @@ { "math": [ "u_level_boost", "=", "weather('precipitation') * 2" ] }, { "math": [ - "u_val('spell_level_adjustment', 'school: STORMSHAPER')", + "u_school_level_adjustment('STORMSHAPER')", "=", - "limit_caster_level_boost(u_level_boost, u_val('spell_level', 'school: STORMSHAPER') )" + "limit_caster_level_boost(u_level_boost, u_school_level('STORMSHAPER') )" ] } ] @@ -198,9 +182,9 @@ }, { "math": [ - "u_val('spell_level_adjustment', 'school: EARTHSHAPER')", + "u_school_level_adjustment('EARTHSHAPER')", "=", - "limit_caster_level_boost(u_level_boost, u_val('spell_level', 'school: EARTHSHAPER') )" + "limit_caster_level_boost(u_level_boost, u_school_level('EARTHSHAPER') )" ] } ] @@ -266,11 +250,7 @@ ] }, { - "math": [ - "u_val('spell_level_adjustment', 'school: DRUID')", - "=", - "limit_caster_level_boost(u_level_boost, u_val('spell_level', 'school: DRUID') )" - ] + "math": [ "u_school_level_adjustment('DRUID')", "=", "limit_caster_level_boost(u_level_boost, u_school_level('DRUID') )" ] } ] } diff --git a/data/mods/MindOverMatter/NewPowerGuide.md b/data/mods/MindOverMatter/NewPowerGuide.md index ce50b85aef2f6..52d006147b6bc 100644 --- a/data/mods/MindOverMatter/NewPowerGuide.md +++ b/data/mods/MindOverMatter/NewPowerGuide.md @@ -4,7 +4,7 @@ When adding powers, keep the following in mind: 1) Choose a Difficulty, which is important for determining how much Nether Attunement the power causes. 2) Make sure to use the "extra_effects" field to apply drain -3) Make sure the power has some element of randomness--unlike magical spells, psionic powers are not completely predictable. The standard formula I've used is generally { "math": [ "( ( (u_val('spell_level', 'spell: [NAME]') * [LEVELED_VALUE]) + [BASE_VALUE]) * ( ( u_val('intelligence') + 10) / 20 ) )" ] }. This makes sure that the power scales appropriately with its level and also that its effects are modified by intelligence: +5% effectiveness for every point of intelligence above 10, -5% for every point below 10. Generally damage, duration, and range are all scaled this way, while maximum level is a simple 1.5 * intelligence. +3) Make sure the power has some element of randomness--unlike magical spells, psionic powers are not completely predictable. The standard formula I've used is generally { "math": [ "( ( (u_spell_level('[NAME]') * [LEVELED_VALUE]) + [BASE_VALUE]) * ( ( u_val('intelligence') + 10) / 20 ) )" ] }. This makes sure that the power scales appropriately with its level and also that its effects are modified by intelligence: +5% effectiveness for every point of intelligence above 10, -5% for every point below 10. Generally damage, duration, and range are all scaled this way, while maximum level is a simple 1.5 * intelligence. 4) Make sure the power has connections to other powers, either teaching them or being learned by them. 5) If the power is low-level enough that it should be a starting power, add it in to the EOC_Matrix_Awakening and EOC_Portal_Awakening EoCs to make sure that it's learned when awakening, as well as the appropriate professions. 6) Write a practice recipe for the power and add it to the appropriate EOC_learn_recipes EoC. Psionic practice recipes are found in recipes/practice. The numbers within are drawn from spellbook reading XP rates and teach Difficulty 1 2 3 and powers up to level 12, Difficulty 4 and 5 powers up to level 10, and Difficulty 6 and 7 powers up to level 7. diff --git a/data/mods/MindOverMatter/effectoncondition/eoc_items.json b/data/mods/MindOverMatter/effectoncondition/eoc_items.json index f57803a306612..438d05ac829be 100644 --- a/data/mods/MindOverMatter/effectoncondition/eoc_items.json +++ b/data/mods/MindOverMatter/effectoncondition/eoc_items.json @@ -2,7 +2,7 @@ { "type": "effect_on_condition", "id": "EOC_ZENER_DECK", - "condition": { "math": [ "u_val('spell_level', 'school: CLAIRSENTIENT')", ">=", "10" ] }, + "condition": { "math": [ "u_school_level('CLAIRSENTIENT')", ">=", "10" ] }, "effect": [ { "switch": { "rand": 4 }, diff --git a/data/mods/MindOverMatter/effectoncondition/eoc_nether_attunement_events.json b/data/mods/MindOverMatter/effectoncondition/eoc_nether_attunement_events.json index 3d7151651fb48..50fdfd407153d 100644 --- a/data/mods/MindOverMatter/effectoncondition/eoc_nether_attunement_events.json +++ b/data/mods/MindOverMatter/effectoncondition/eoc_nether_attunement_events.json @@ -6,7 +6,7 @@ "required_event": "opens_spellbook", "condition": { "not": { "u_has_effect": "effect_noetic_resilience" } }, "effect": { - "switch": { "u_val": "vitamin", "name": "vitamin_psionic_drain" }, + "switch": { "math": [ "u_vitamin('vitamin_psionic_drain')" ] }, "cases": [ { "case": 0, "effect": { "math": [ "u_nether_attunement_power_scaling", "=", "0.75" ] } }, { "case": 15, "effect": { "math": [ "u_nether_attunement_power_scaling", "=", "1" ] } }, @@ -64,7 +64,7 @@ "effect": [ { "math": [ "u_latest_channeled_power_difficulty", "=", "_difficulty" ] }, { - "switch": { "u_val": "vitamin", "name": "vitamin_psionic_drain" }, + "switch": { "math": [ "u_vitamin('vitamin_psionic_drain')" ] }, "cases": [ { "case": 15, diff --git a/data/mods/MindOverMatter/effects/effects_psionic.json b/data/mods/MindOverMatter/effects/effects_psionic.json index 442205e3ab139..aea6837492f18 100644 --- a/data/mods/MindOverMatter/effects/effects_psionic.json +++ b/data/mods/MindOverMatter/effects/effects_psionic.json @@ -506,7 +506,7 @@ "value": "SPEED", "add": { "math": [ - "min( ( ( ( ( u_val('spell_level', 'spell: biokin_hurricane_blows') * 75) + 400 ) * (scaling_factor(u_val('intelligence') ) ) ) * u_nether_attunement_power_scaling), 1800)" + "min( ( ( ( ( u_spell_level('biokin_hurricane_blows') * 75) + 400 ) * (scaling_factor(u_val('intelligence') ) ) ) * u_nether_attunement_power_scaling), 1800)" ] } } diff --git a/data/mods/MindOverMatter/mutations/psi_passives.json b/data/mods/MindOverMatter/mutations/psi_passives.json index a6e4c51543ae6..32a1efdefd1c4 100644 --- a/data/mods/MindOverMatter/mutations/psi_passives.json +++ b/data/mods/MindOverMatter/mutations/psi_passives.json @@ -32,15 +32,9 @@ "enchantments": [ { "values": [ - { "value": "HUNGER", "multiply": { "math": [ "(-0.03 - (0.015 * u_val('spell_level', 'school: BIOKINETIC')))" ] } }, - { - "value": "THIRST", - "multiply": { "math": [ "(-0.03 - (0.015 * u_val('spell_level', 'school: BIOKINETIC')))" ] } - }, - { - "value": "METABOLISM", - "multiply": { "math": [ "(-0.03 - (0.015 * u_val('spell_level', 'school: BIOKINETIC')))" ] } - } + { "value": "HUNGER", "multiply": { "math": [ "(-0.03 - (0.015 * u_school_level('BIOKINETIC')))" ] } }, + { "value": "THIRST", "multiply": { "math": [ "(-0.03 - (0.015 * u_school_level('BIOKINETIC')))" ] } }, + { "value": "METABOLISM", "multiply": { "math": [ "(-0.03 - (0.015 * u_school_level('BIOKINETIC')))" ] } } ] } ] @@ -58,9 +52,7 @@ "purifiable": false, "enchantments": [ { - "values": [ - { "value": "SIGHT_RANGE_NETHER", "add": { "math": [ "(2 + (1.5 * u_val('spell_level', 'school: CLAIRSENTIENT')))" ] } } - ] + "values": [ { "value": "SIGHT_RANGE_NETHER", "add": { "math": [ "(2 + (1.5 * u_school_level('CLAIRSENTIENT')))" ] } } ] } ] }, @@ -76,8 +68,8 @@ "enchantments": [ { "values": [ - { "value": "ARMOR_ELEC", "add": { "math": [ "u_val('spell_level', 'school: ELECTROKINETIC') / -4" ] } }, - { "value": "PAIN", "multiply": { "math": [ "u_val('spell_level', 'school: ELECTROKINETIC') * -0.007" ] } } + { "value": "ARMOR_ELEC", "add": { "math": [ "u_school_level('ELECTROKINETIC') / -4" ] } }, + { "value": "PAIN", "multiply": { "math": [ "u_school_level('ELECTROKINETIC') * -0.007" ] } } ] } ] @@ -459,12 +451,9 @@ "enchantments": [ { "values": [ - { "value": "SOCIAL_INTIMIDATE", "add": { "math": [ "(5 + (1.5 * u_val('spell_level', 'school: TELEPATHIC')))" ] } }, - { "value": "SOCIAL_LIE", "add": { "math": [ "(5 + (1.5 * u_val('spell_level', 'school: TELEPATHIC')))" ] } }, - { - "value": "SOCIAL_PERSUADE", - "add": { "math": [ "(5 + (1.5 * u_val('spell_level', 'school: TELEPATHIC')))" ] } - } + { "value": "SOCIAL_INTIMIDATE", "add": { "math": [ "(5 + (1.5 * u_school_level('TELEPATHIC')))" ] } }, + { "value": "SOCIAL_LIE", "add": { "math": [ "(5 + (1.5 * u_school_level('TELEPATHIC')))" ] } }, + { "value": "SOCIAL_PERSUADE", "add": { "math": [ "(5 + (1.5 * u_school_level('TELEPATHIC')))" ] } } ] } ] @@ -479,11 +468,7 @@ "valid": false, "player_display": true, "purifiable": false, - "enchantments": [ - { - "values": [ { "value": "EVASION", "add": { "math": [ "(0.01 + (0.005 * u_val('spell_level', 'school: TELEPORTER')))" ] } } ] - } - ] + "enchantments": [ { "values": [ { "value": "EVASION", "add": { "math": [ "(0.01 + (0.005 * u_school_level('TELEPORTER')))" ] } } ] } ] }, { "type": "mutation", @@ -499,11 +484,8 @@ "enchantments": [ { "values": [ - { "value": "REGEN_HP", "multiply": { "math": [ "(0.1 + (0.01 * u_val('spell_level', 'school: VITAKINETIC')))" ] } }, - { - "value": "MAX_HP", - "multiply": { "math": [ "(0.05 + (0.01 * u_val('spell_level', 'school: VITAKINETIC')))" ] } - } + { "value": "REGEN_HP", "multiply": { "math": [ "(0.1 + (0.01 * u_school_level('VITAKINETIC')))" ] } }, + { "value": "MAX_HP", "multiply": { "math": [ "(0.05 + (0.01 * u_school_level('VITAKINETIC')))" ] } } ] } ] diff --git a/data/mods/MindOverMatter/npcs/dialogue/Rubik.json b/data/mods/MindOverMatter/npcs/dialogue/Rubik.json index 90580be73d23f..efcd21165fa5b 100644 --- a/data/mods/MindOverMatter/npcs/dialogue/Rubik.json +++ b/data/mods/MindOverMatter/npcs/dialogue/Rubik.json @@ -43,7 +43,7 @@ { "text": "[Telepathy 10+] *Go deeper*.", "topic": "TALK_EXODII_MERCHANT_deep_scan", - "condition": { "math": [ "u_val('spell_level', 'school: TELEPATH')", ">=", "10" ] } + "condition": { "math": [ "u_school_level('TELEPATH')", ">=", "10" ] } } ] }, diff --git a/data/mods/MindOverMatter/npcs/dialogue/generic_dialogue.json b/data/mods/MindOverMatter/npcs/dialogue/generic_dialogue.json index b02dac1376eb5..c8e2a6d4f764a 100644 --- a/data/mods/MindOverMatter/npcs/dialogue/generic_dialogue.json +++ b/data/mods/MindOverMatter/npcs/dialogue/generic_dialogue.json @@ -12,7 +12,7 @@ "condition": { "and": [ { - "roll_contested": { "math": [ "u_val('spell_level', 'school: TELEPATH')" ] }, + "roll_contested": { "math": [ "u_school_level('TELEPATH')" ] }, "difficulty": { "math": [ "n_val('intelligence')" ] }, "die_size": 5 }, @@ -75,7 +75,7 @@ "trial": { "type": "CONDITION", "condition": { - "roll_contested": { "math": [ "u_val('spell_level', 'school: TELEKINETIC')" ] }, + "roll_contested": { "math": [ "u_school_level('TELEKINETIC')" ] }, "difficulty": { "math": [ "n_val('strength')" ] }, "die_size": 5 } diff --git a/data/mods/MindOverMatter/npcs/dialogue/refugee_guards_traitor.json b/data/mods/MindOverMatter/npcs/dialogue/refugee_guards_traitor.json index ce075f3350bbc..832151cd7afcc 100644 --- a/data/mods/MindOverMatter/npcs/dialogue/refugee_guards_traitor.json +++ b/data/mods/MindOverMatter/npcs/dialogue/refugee_guards_traitor.json @@ -39,7 +39,7 @@ { "text": "[Telepathy 8+] *Go deeper*.", "topic": "TALK_EVAC_GUARD3_deep_scan", - "condition": { "math": [ "u_val('spell_level', 'school: TELEPATH')", ">=", "8" ] } + "condition": { "math": [ "u_school_level('TELEPATH')", ">=", "8" ] } } ] }, @@ -103,7 +103,7 @@ "trial": { "type": "CONDITION", "condition": { - "roll_contested": { "math": [ "u_val('spell_level', 'school: TELEKINETIC')" ] }, + "roll_contested": { "math": [ "u_school_level('TELEKINETIC')" ] }, "difficulty": { "math": [ "n_val('strength')" ] }, "die_size": 5 } diff --git a/data/mods/MindOverMatter/powers/biokinesis_concentration_eocs.json b/data/mods/MindOverMatter/powers/biokinesis_concentration_eocs.json index c75d590dde4f1..7f880b1846133 100644 --- a/data/mods/MindOverMatter/powers/biokinesis_concentration_eocs.json +++ b/data/mods/MindOverMatter/powers/biokinesis_concentration_eocs.json @@ -30,7 +30,7 @@ "type": "effect_on_condition", "id": "EOC_BIOKIN_OVERCOME_PAIN_SWITCHER", "effect": { - "switch": { "u_val": "spell_level", "spell": "biokin_overcome_pain" }, + "switch": { "math": [ "u_spell_level('biokin_overcome_pain')" ] }, "cases": [ { "case": 0, "effect": { "u_add_effect": "effect_biokin_pkill_1", "duration": "PERMANENT" } }, { "case": 4, "effect": { "u_add_effect": "effect_biokin_pkill_2", "duration": "PERMANENT" } }, diff --git a/data/mods/MindOverMatter/powers/clairsentience_concentration_eocs.json b/data/mods/MindOverMatter/powers/clairsentience_concentration_eocs.json index 3ff6ea5fb866f..db1c1ba53e7bf 100644 --- a/data/mods/MindOverMatter/powers/clairsentience_concentration_eocs.json +++ b/data/mods/MindOverMatter/powers/clairsentience_concentration_eocs.json @@ -30,7 +30,7 @@ "type": "effect_on_condition", "id": "EOC_CLAIR_NIGHT_EYES_SWITCHER", "effect": { - "switch": { "u_val": "spell_level", "spell": "clair_night_vision" }, + "switch": { "math": [ "u_spell_level('clair_night_vision')" ] }, "cases": [ { "case": 0, "effect": { "u_add_effect": "effect_clair_night_eyes_1", "duration": "PERMANENT" } }, { "case": 3, "effect": { "u_add_effect": "effect_clair_night_eyes_2", "duration": "PERMANENT" } }, @@ -424,7 +424,7 @@ "type": "effect_on_condition", "id": "EOC_CLAIR_CRAFT_BONUS_SWITCHER", "effect": { - "switch": { "u_val": "spell_level", "spell": "clair_craft_bonus" }, + "switch": { "math": [ "u_spell_level('clair_craft_bonus')" ] }, "cases": [ { "case": 0, "effect": { "u_add_trait": "CLAIR_CRAFT_BONUS_01" } }, { "case": 4, "effect": { "u_add_trait": "CLAIR_CRAFT_BONUS_02" } }, diff --git a/data/mods/MindOverMatter/powers/electrokinesis.json b/data/mods/MindOverMatter/powers/electrokinesis.json index cb58cd57e21d3..d1be6f4e14b53 100644 --- a/data/mods/MindOverMatter/powers/electrokinesis.json +++ b/data/mods/MindOverMatter/powers/electrokinesis.json @@ -378,12 +378,12 @@ "shape": "blast", "min_damage": { "math": [ - "( (u_val('spell_level', 'spell: electrokinetic_recharge_vehicle') * 125) + 250) * (scaling_factor(u_val('intelligence') ) ) * u_nether_attunement_power_scaling" + "( (u_spell_level('electrokinetic_recharge_vehicle') * 125) + 250) * (scaling_factor(u_val('intelligence') ) ) * u_nether_attunement_power_scaling" ] }, "max_damage": { "math": [ - "( (u_val('spell_level', 'spell: electrokinetic_recharge_vehicle') * 250) + 500) * (scaling_factor(u_val('intelligence') ) ) * u_nether_attunement_power_scaling" + "( (u_spell_level('electrokinetic_recharge_vehicle') * 250) + 500) * (scaling_factor(u_val('intelligence') ) ) * u_nether_attunement_power_scaling" ] }, "min_range": 1, diff --git a/data/mods/MindOverMatter/powers/photokinesis_concentration_eoc.json b/data/mods/MindOverMatter/powers/photokinesis_concentration_eoc.json index f4d270e1cb10f..1babcae07668b 100644 --- a/data/mods/MindOverMatter/powers/photokinesis_concentration_eoc.json +++ b/data/mods/MindOverMatter/powers/photokinesis_concentration_eoc.json @@ -156,7 +156,7 @@ "id": "EOC_PHOTOKIN_CAMOUFLAGE_SWITCHER", "effect": [ { - "switch": { "u_val": "spell_level", "spell": "photokinetic_camouflage" }, + "switch": { "math": [ "u_spell_level('photokinetic_camouflage')" ] }, "cases": [ { "case": 0, "effect": { "u_add_trait": "PHOTOKINETIC_CAMOUFLAGE_1" } }, { "case": 4, "effect": { "u_add_trait": "PHOTOKINETIC_CAMOUFLAGE_2" } }, @@ -243,7 +243,7 @@ "type": "effect_on_condition", "id": "EOC_PHOTOKIN_HIDE_UGLY_SWITCHER", "effect": { - "switch": { "u_val": "spell_level", "spell": "photokinetic_hide_ugly" }, + "switch": { "math": [ "u_spell_level('photokinetic_hide_ugly')" ] }, "cases": [ { "case": 0, "effect": { "u_add_trait": "PHOTOKIN_HIDE_UGLY_01" } }, { "case": 4, "effect": { "u_add_trait": "PHOTOKIN_HIDE_UGLY_02" } }, diff --git a/data/mods/MindOverMatter/powers/telepathy.json b/data/mods/MindOverMatter/powers/telepathy.json index d90e069db4f90..26d9aef58a3f4 100644 --- a/data/mods/MindOverMatter/powers/telepathy.json +++ b/data/mods/MindOverMatter/powers/telepathy.json @@ -578,27 +578,27 @@ "shape": "blast", "min_damage": { "math": [ - "( (u_val('spell_level', 'spell: telepathic_beast_taming') * 15) + 200) * (scaling_factor(u_val('intelligence') ) ) * u_nether_attunement_power_scaling" + "( (u_spell_level('telepathic_beast_taming') * 15) + 200) * (scaling_factor(u_val('intelligence') ) ) * u_nether_attunement_power_scaling" ] }, "max_damage": { "math": [ - "( (u_val('spell_level', 'spell: telepathic_beast_taming') * 35) + 500) * (scaling_factor(u_val('intelligence') ) ) * u_nether_attunement_power_scaling" + "( (u_spell_level('telepathic_beast_taming') * 35) + 500) * (scaling_factor(u_val('intelligence') ) ) * u_nether_attunement_power_scaling" ] }, "min_duration": { "math": [ - "( (u_val('spell_level', 'spell: telepathic_beast_taming') * 8640000) + 241920000) * (scaling_factor(u_val('intelligence') ) ) * u_nether_attunement_power_scaling" + "( (u_spell_level('telepathic_beast_taming') * 8640000) + 241920000) * (scaling_factor(u_val('intelligence') ) ) * u_nether_attunement_power_scaling" ] }, "max_duration": { "math": [ - "( (u_val('spell_level', 'spell: telepathic_beast_taming') * 25920000) + 483840000) * (scaling_factor(u_val('intelligence') ) ) * u_nether_attunement_power_scaling" + "( (u_spell_level('telepathic_beast_taming') * 25920000) + 483840000) * (scaling_factor(u_val('intelligence') ) ) * u_nether_attunement_power_scaling" ] }, "min_range": { "math": [ - "min( (( (u_val('spell_level', 'spell: telepathic_beast_taming') * 1) + 3) * (scaling_factor(u_val('intelligence') ) ) * u_nether_attunement_power_scaling), 70)" + "min( (( (u_spell_level('telepathic_beast_taming') * 1) + 3) * (scaling_factor(u_val('intelligence') ) ) * u_nether_attunement_power_scaling), 70)" ] }, "max_range": 70, @@ -625,17 +625,17 @@ "shape": "blast", "min_duration": { "math": [ - "( (u_val('spell_level', 'spell: telepathic_beast_taming') * 8640000) + 241920000) * (scaling_factor(u_val('intelligence') ) ) * u_nether_attunement_power_scaling" + "( (u_spell_level('telepathic_beast_taming') * 8640000) + 241920000) * (scaling_factor(u_val('intelligence') ) ) * u_nether_attunement_power_scaling" ] }, "max_duration": { "math": [ - "( (u_val('spell_level', 'spell: telepathic_beast_taming') * 25920000) + 483840000) * (scaling_factor(u_val('intelligence') ) ) * u_nether_attunement_power_scaling" + "( (u_spell_level('telepathic_beast_taming') * 25920000) + 483840000) * (scaling_factor(u_val('intelligence') ) ) * u_nether_attunement_power_scaling" ] }, "min_range": { "math": [ - "min( (( (u_val('spell_level', 'spell: telepathic_beast_taming') * 1) + 3) * (scaling_factor(u_val('intelligence') ) ) * u_nether_attunement_power_scaling), 70)" + "min( (( (u_spell_level('telepathic_beast_taming') * 1) + 3) * (scaling_factor(u_val('intelligence') ) ) * u_nether_attunement_power_scaling), 70)" ] }, "max_range": 70, diff --git a/data/mods/MindOverMatter/powers/vitakinesis.json b/data/mods/MindOverMatter/powers/vitakinesis.json index 57505d25acd6d..6bf90e88b83ce 100644 --- a/data/mods/MindOverMatter/powers/vitakinesis.json +++ b/data/mods/MindOverMatter/powers/vitakinesis.json @@ -462,12 +462,12 @@ "damage_type": "biological", "min_damage": { "math": [ - "( (u_val('spell_level', 'spell: vita_attack_touch') * 2) + 12) * (scaling_factor(u_val('intelligence') ) ) * u_nether_attunement_power_scaling" + "( (u_spell_level('vita_attack_touch') * 2) + 12) * (scaling_factor(u_val('intelligence') ) ) * u_nether_attunement_power_scaling" ] }, "max_damage": { "math": [ - "( (u_val('spell_level', 'spell: vita_attack_touch') * 4) + 35) * (scaling_factor(u_val('intelligence') ) ) * u_nether_attunement_power_scaling" + "( (u_spell_level('vita_attack_touch') * 4) + 35) * (scaling_factor(u_val('intelligence') ) ) * u_nether_attunement_power_scaling" ] }, "min_dot": 1, @@ -475,12 +475,12 @@ "min_range": 1, "min_duration": { "math": [ - "( (u_val('spell_level', 'spell: vita_attack_touch') * 50) + 400) * (scaling_factor(u_val('intelligence') ) ) * u_nether_attunement_power_scaling" + "( (u_spell_level('vita_attack_touch') * 50) + 400) * (scaling_factor(u_val('intelligence') ) ) * u_nether_attunement_power_scaling" ] }, "max_duration": { "math": [ - "( (u_val('spell_level', 'spell: vita_attack_touch') * 100) + 800) * (scaling_factor(u_val('intelligence') ) ) * u_nether_attunement_power_scaling" + "( (u_spell_level('vita_attack_touch') * 100) + 800) * (scaling_factor(u_val('intelligence') ) ) * u_nether_attunement_power_scaling" ] }, "energy_source": "STAMINA", diff --git a/data/mods/MindOverMatter/recipes/practice/electrokinesis_practice.json b/data/mods/MindOverMatter/recipes/practice/electrokinesis_practice.json index 486e8b96b6b8f..a58495ab24310 100644 --- a/data/mods/MindOverMatter/recipes/practice/electrokinesis_practice.json +++ b/data/mods/MindOverMatter/recipes/practice/electrokinesis_practice.json @@ -750,12 +750,10 @@ "result_eocs": [ { "id": "EOC_PRACTICE_ELECTROKIN_RECHARGE_VEHICLE", - "condition": { "math": [ "u_val('spell_level', 'spell: electrokinetic_recharge_vehicle')", ">=", "1" ] }, + "condition": { "math": [ "u_spell_level('electrokinetic_recharge_vehicle')", ">=", "1" ] }, "effect": [ { "u_message": "You spend some time meditating and contemplating your powers and emerge with new knowledge." }, - { - "math": [ "u_val('spell_exp', 'spell: electrokinetic_recharge_vehicle')", "+=", "(contemplation_factor(1))" ] - }, + { "math": [ "u_spell_exp('electrokinetic_recharge_vehicle')", "+=", "(contemplation_factor(1))" ] }, { "math": [ "u_vitamin('vitamin_psionic_drain')", "+=", "rng( 1,10 )" ] }, { "math": [ "u_val('stored_kcal')", "-=", "psionics_contemplation_kcal_cost(5)" ] }, { "run_eocs": "EOC_PSI_PRACTICE_FOCUS_MOD" } diff --git a/data/mods/MindOverMatter/recipes/practice/pyrokinesis_practice.json b/data/mods/MindOverMatter/recipes/practice/pyrokinesis_practice.json index 61cd2862edfb3..bc296b16952c6 100644 --- a/data/mods/MindOverMatter/recipes/practice/pyrokinesis_practice.json +++ b/data/mods/MindOverMatter/recipes/practice/pyrokinesis_practice.json @@ -103,10 +103,10 @@ "result_eocs": [ { "id": "EOC_PRACTICE_PYROKIN_CAUTERIZE", - "condition": { "math": [ "u_val('spell_level', 'spell: pyrokinetic_cauterize')", ">=", "1" ] }, + "condition": { "math": [ "u_spell_level('pyrokinetic_cauterize')", ">=", "1" ] }, "effect": [ { "u_message": "You spend some time meditating and contemplating your powers and emerge with new knowledge." }, - { "math": [ "u_val('spell_exp', 'spell: pyrokinetic_cauterize')", "+=", "(contemplation_factor(1))" ] }, + { "math": [ "u_spell_exp('pyrokinetic_cauterize')", "+=", "(contemplation_factor(1))" ] }, { "math": [ "u_vitamin('vitamin_psionic_drain')", "+=", "rng( 1,10 )" ] }, { "math": [ "u_val('stored_kcal')", "-=", "psionics_contemplation_kcal_cost(2)" ] }, { "run_eocs": "EOC_PSI_PRACTICE_FOCUS_MOD" } diff --git a/data/mods/Sky_Island/EOCs.json b/data/mods/Sky_Island/EOCs.json index 79ace65a2e3e1..f8445a1a14f42 100644 --- a/data/mods/Sky_Island/EOCs.json +++ b/data/mods/Sky_Island/EOCs.json @@ -281,10 +281,10 @@ "effect": [ { "math": [ "u_val('stored_kcal')", "=", "max( u_val('stored_kcal'), 9000)" ] }, { "math": [ "u_val('thirst')", "=", "min( u_val('thirst'), 800)" ] }, - { "math": [ "u_val('vitamin', 'name: redcells')", "=", "0" ] }, - { "math": [ "u_val('vitamin', 'name: bad_food')", "=", "0" ] }, - { "math": [ "u_val('vitamin', 'name: blood')", "=", "0" ] }, - { "math": [ "u_val('vitamin', 'name: instability')", "=", "0" ] }, + { "math": [ "u_vitamin('redcells')", "=", "0" ] }, + { "math": [ "u_vitamin('bad_food')", "=", "0" ] }, + { "math": [ "u_vitamin('blood')", "=", "0" ] }, + { "math": [ "u_vitamin('instability')", "=", "0" ] }, { "math": [ "u_pain()", "=", "0" ] }, { "math": [ "u_val('rad')", "=", "0" ] }, { "u_add_effect": "cureall", "duration": "1 s", "intensity": 1 }, diff --git a/data/mods/Xedra_Evolved/effects/effect_on_condition.json b/data/mods/Xedra_Evolved/effects/effect_on_condition.json index c478b302401eb..25a1fb01e2a95 100644 --- a/data/mods/Xedra_Evolved/effects/effect_on_condition.json +++ b/data/mods/Xedra_Evolved/effects/effect_on_condition.json @@ -37,7 +37,7 @@ "id": "EOC_EATER_CHECK", "global": true, "recurrence": [ "12 hours", "72 hours" ], - "condition": { "math": [ "u_val('spell_count', 'school: EATER')", ">=", "6" ] }, + "condition": { "math": [ "u_spell_count('school': 'EATER')", ">=", "6" ] }, "deactivate_condition": { "u_has_trait": "EATER_SIXTH_SENSE" }, "effect": [ { diff --git a/data/mods/Xedra_Evolved/spells/spell_eocs.json b/data/mods/Xedra_Evolved/spells/spell_eocs.json index 40c78b960ce5b..093c32d99e8c3 100644 --- a/data/mods/Xedra_Evolved/spells/spell_eocs.json +++ b/data/mods/Xedra_Evolved/spells/spell_eocs.json @@ -17,7 +17,7 @@ "type": "effect_on_condition", "id": "EOC_DREAMER_ARTIFACT_FAIL_MESSAGE", "effect": { - "switch": { "u_val": "vitamin", "name": "dreamer_vit" }, + "switch": { "math": [ "u_vitamin('dreamer_vit')" ] }, "cases": [ { "case": 0, diff --git a/doc/EFFECT_ON_CONDITION.md b/doc/EFFECT_ON_CONDITION.md index 2675e763c2f8e..a6e09742118a1 100644 --- a/doc/EFFECT_ON_CONDITION.md +++ b/doc/EFFECT_ON_CONDITION.md @@ -1850,7 +1850,7 @@ Check the value, and, depending on it, pick the case that would be run Checks the level of `some_spell` spell, and, related to this, do something: for spell level 0 it casts another_spell, for spell level 3 it adds effect "drunk", and so on. ```json { - "switch": { "u_val": "spell_level", "spell": "some_spell" }, + "switch": { "math": [ "u_spell_level('some_spell')" ] }, "cases": [ { "case": 0, "effect": { "u_cast_spell": { "id": "another_spell" } } }, { "case": 3, "effect": { "u_add_effect": "drunk", "duration": "270 minutes" } }, diff --git a/doc/NPCs.md b/doc/NPCs.md index d414174826fa5..5649473bfbe8c 100644 --- a/doc/NPCs.md +++ b/doc/NPCs.md @@ -1239,8 +1239,6 @@ Example | Description `"u_val": "cash"` | Amount of money the character has. Only supported for the player character. Can be read but not written to. `"u_val": "owed"` | Owed money to the NPC you're talking to. `"u_val": "sold"` | Amount sold to the NPC you're talking to. -`"u_val": "warmth"` | Amount of warmth in a given bodypart. `bodypart` is the id of the part to use. -`"u_val": "effect_intensity"` | Intensity of an effect. `effect` is the id of the effect to test and `bodypart` is optionally the body part to look at. If the effect is not present a -1 is returned. `"u_val": "dodge"` | Current effective dodge of the character. `"u_val": "pos_x"` | Player character x coordinate. "pos_y" and "pos_z" also works as expected. `"u_val": "power"` | Bionic power in millijoule. @@ -1254,11 +1252,7 @@ Example | Description `"u_val": "instant_thirst"` | Current thirst minus water in the stomach that hasn't been absorbed by the body yet. `"u_val": "stored_kcal"` | Stored kcal in the character's body. 55'000 is considered healthy. `"u_val": "stored_kcal_percentage"` | a value of 100 represents 55'000 kcal, which is considered healthy. -`"u_val": "item_count"` | Number of a given item in the character's inventory. `"item"` must also be specified. Can be read but not written to. -`"u_val": "charge_count"` | Number of charges of a given item in the character's inventory. `"item"` must also be specified. Can be read but not written to. `"u_val": "exp"` | Total experience earned. -`"u_val": "addiction_intensity", "addiction": "caffeine"` | Current intensity of the given addiction. Allows for an optional field `"mod"` which accepts an integer to multiply against the current intensity. -`"u_val": "addiction_turns", "addiction": "caffeine"` | Current duration left (in turns) for the given addiction. `"u_val": "stim"` | Current stim level. `"u_val": "pkill"` | Current painkiller level. `"u_val": "rad"` | Current radiation level. @@ -1274,7 +1268,6 @@ Example | Description `"u_val": "npc_trust"` | Current trust the npc has for you. `"u_val": "npc_fear"` | Current fear of the npc. `"u_val": "npc_value"` | Current value npc places on you. -`"u_val": "vitamin"` | Current vitamin level. `name` must also be specified which is the vitamins id. `"u_val": "fine_detail_vision_mod"` | Returned values range from 1.0 (unimpeded vision) to 11.0 (totally blind). `"u_val": "age"` | Current age in years. `"u_val": "body_temp"` | Current body temperature. @@ -1283,15 +1276,8 @@ Example | Description `"u_val": "height"` | Current height in cm. When setting there is a range for your character size category. Setting it too high or low will use the limit instead. For tiny its 58, and 87. For small its 88 and 144. For medium its 145 and 200. For large its 201 and 250. For huge its 251 and 320. `"u_val": "size"` | Size category from 1 (tiny) to 5 (huge). Read-only. `"u_val": "grab_strength"` | Grab strength as defined in the monster definition. Read-only, returns false on characters. -`"u_val": "field_strength"` | Strength of a field on the tile the player or NPC is standing on. `field` must be specified. read only. -`"u_val": "spell_level"` | Level of a given spell. -1 means the spell is not known when read and that the spell should be forgotten if written. Optional params: `school` gives the highest level of spells known of that school (read only), `spell` reads or writes the level of the spell with matching spell id. If no parameter is provided, you will get the highest spell level of the spells you know (read only). -`"u_val": "spell_exp"` | Experience for a given spell. -1 means the spell is not known when read and that the spell should be forgotten if written. Required param: `spell` is the id of the spell in question. -`"u_val": "spell_level_adjustment"` | Temporary caster level adjustment. Only useable by EoCs that trigger on the event `opens_spellbook`. Old values will be reset to 0 before the event triggers. To avoid overwriting values from other EoCs, it is recommended to adjust the values here with `+=` or `-=` instead of setting it to an absolute value. When an NPC consider what spell to cast they will be considered the primary talker, so their values are manipulated with `u_val` the same way the player's values are. Optional params: `school` makes it only apply to a given school. `spell` makes it only apply to a given spell. -`"u_val": "spell_count"` | Number of spells that this character knows. Optional params: `school` returns only the number of spells of the specified spell class that the character knows. Read-only. -`"u_val": "proficiency"` | Deals with a proficiency. Required params: `proficiency_id` is the id of the proficiency dealt with. `format` determines how the proficiency will be interacted with. `"format": ` will read or write how much you have trained a proficiency out of . So for example, if you write a 5 to a proficiency using `"format": 10`, you will set the proficiency to be trained to 50%. `"format": "percent"` reads or writes how many percent done the learning is. `"format": "permille"` does likewise for permille. `"format": "total_time_required"` gives you total time required to train a given proficiency (read only). `"format": "time_spent"` deals with total time spent. `"format": "time_left"` sets the remaining time instead. For most formats possible, If the resulting time is set to equal or more than the time required to learn the proficiency, you learn it. If you read it and it gives back the total time required, it means it is learnt. Setting the total time practiced to a negative value completely removes the proficiency from your known and practiced proficiencies. If you try to read time spent on a proficiency that is not in your proficiency list, you will get back 0 seconds. `"u_val": "volume"` | Current volume in ml. read only. Cullently, doesn't work for characters, but for monsters and items. `"u_val": "weight"` | Current weight in mg. read only. -`"distance": []` | Distance between two targets. Valid targets are: "u","npc" and an object with a variable name.

Example:
"condition": { "compare_num": [
{ "distance": [ "u",{ "u_val": "stuck", "type": "ps", "context": "teleport" } ] },
">", { "const": 5 }
] }
`"mod_load_order"` | This should be a string with the name of the mod. It will return the order it was loaded in or -1 if its not loaded. `"arithmetic"` | An arithmetic expression with no result.

Example:
"real_count": { "arithmetic": [
{ "arithmetic": [ { "const":1 }, "+", { "const": 1 } ] },
"+", { "const": 1 }
] },
`"math"` | An array math object. @@ -1333,7 +1319,7 @@ Example: ``` If `operator` is `=`, `+=`, `-=`, `*=`, `/=`, or `%=` the operation is an assignment: ```JSON -"effect": { "math": [ "u_blorg", "=", "rng( 0, 2 ) + u_val('spell_level', 'spell: test_spell_pew') / 2" ] } +"effect": { "math": [ "u_blorg", "=", "rng( 0, 2 ) + u_spell_level('test_spell_pew') / 2" ] } ``` `lhs` must be an [assignment target](#assignment-target). `rhs` is evaluated and stored in the assignment target from `lhs`. diff --git a/src/condition.cpp b/src/condition.cpp index dbc2a19b011c8..600a540ea90a0 100644 --- a/src/condition.cpp +++ b/src/condition.cpp @@ -470,62 +470,6 @@ void finalize_conditions() } } -static std::string get_string_from_input( const JsonArray &objects, int index ) -{ - if( objects.has_string( index ) ) { - std::string type = objects.get_string( index ); - if( type == "u" || type == "npc" ) { - return type; - } - } - dbl_or_var empty; - JsonObject object = objects.get_object( index ); - if( object.has_string( "u_val" ) ) { - return "u_" + get_talk_varname( object, "u_val", false, empty ); - } else if( object.has_string( "npc_val" ) ) { - return "npc_" + get_talk_varname( object, "npc_val", false, empty ); - } else if( object.has_string( "global_val" ) ) { - return "global_" + get_talk_varname( object, "global_val", false, empty ); - } else if( object.has_string( "context_val" ) ) { - return "context_" + get_talk_varname( object, "context_val", false, empty ); - } else if( object.has_string( "faction_val" ) ) { - return "faction_" + get_talk_varname( object, "faction_val", false, empty ); - } else if( object.has_string( "party_val" ) ) { - return "party_" + get_talk_varname( object, "party_val", false, empty ); - } - object.throw_error( "Invalid input type." ); - return ""; -} - -static tripoint_abs_ms get_tripoint_from_string( const std::string &type, dialogue const &d ) -{ - if( type == "u" ) { - return d.actor( false )->global_pos(); - } else if( type == "npc" ) { - return d.actor( true )->global_pos(); - } else if( type.find( "u_" ) == 0 ) { - var_info var = var_info( var_type::u, type.substr( 2, type.size() - 2 ) ); - return get_tripoint_from_var( var, d ); - } else if( type.find( "npc_" ) == 0 ) { - var_info var = var_info( var_type::npc, type.substr( 4, type.size() - 4 ) ); - return get_tripoint_from_var( var, d ); - } else if( type.find( "global_" ) == 0 ) { - var_info var = var_info( var_type::global, type.substr( 7, type.size() - 7 ) ); - return get_tripoint_from_var( var, d ); - } else if( type.find( "faction_" ) == 0 ) { - var_info var = var_info( var_type::faction, type.substr( 8, type.size() - 8 ) ); - return get_tripoint_from_var( var, d ); - } else if( type.find( "party_" ) == 0 ) { - var_info var = var_info( var_type::party, type.substr( 6, type.size() - 6 ) ); - return get_tripoint_from_var( var, d ); - } else if( type.find( "context_" ) == 0 ) { - var_info var = var_info( var_type::context, type.substr( 8, type.size() - 8 ) ); - return get_tripoint_from_var( var, d ); - } - return tripoint_abs_ms(); -} - - namespace conditional_fun { namespace @@ -2118,30 +2062,10 @@ std::function conditional_t::get_get_dbl( J const &jo ) return [is_npc]( dialogue const & d ) { return d.actor( is_npc )->get_per_bonus(); }; - } else if( checked_value == "warmth" ) { - std::optional bp; - if constexpr( std::is_same_v ) { - optional( jo, false, "bodypart", bp ); - } - return [is_npc, bp]( dialogue const & d ) { - bodypart_id bid = bp.value_or( get_bp_from_str( d.reason ) ); - return units::to_legacy_bodypart_temp( d.actor( is_npc )->get_cur_part_temp( bid ) ); - }; } else if( checked_value == "dodge" ) { return [is_npc]( dialogue const & d ) { return d.actor( is_npc )->get_character()->get_dodge(); }; - } else if( checked_value == "effect_intensity" ) { - const std::string &effect_id = jo.get_string( "effect" ); - std::optional bp; - if constexpr( std::is_same_v ) { - optional( jo, false, "bodypart", bp ); - } - return [effect_id, bp, is_npc]( dialogue const & d ) { - bodypart_id bid = bp.value_or( get_bp_from_str( d.reason ) ); - effect target = d.actor( is_npc )->get_effect( efftype_id( effect_id ), bid ); - return target.is_null() ? -1 : target.get_intensity(); - }; } else if( checked_value == "var" ) { var_info info( {}, {} ); if constexpr( std::is_same_v ) { @@ -2273,42 +2197,10 @@ std::function conditional_t::get_get_dbl( J const &jo ) } return d.actor( is_npc )->get_stored_kcal() / divisor; }; - } else if( checked_value == "item_count" ) { - const itype_id item_id( jo.get_string( "item" ) ); - return [is_npc, item_id]( dialogue const & d ) { - return d.actor( is_npc )->get_amount( item_id ); - }; - } else if( checked_value == "charge_count" ) { - const itype_id item_id( jo.get_string( "item" ) ); - return [is_npc, item_id]( dialogue const & d ) { - return d.actor( is_npc )->charges_of( item_id ); - }; } else if( checked_value == "exp" ) { return [is_npc]( dialogue const & d ) { return d.actor( is_npc )->get_kill_xp(); }; - } else if( checked_value == "addiction_intensity" ) { - const addiction_id add_id( jo.get_string( "addiction" ) ); - if( jo.has_object( "mod" ) ) { - // final_value = (val / (val - step * intensity)) - 1 - JsonObject jobj = jo.get_object( "mod" ); - const int val = jobj.get_int( "val", 0 ); - const int step = jobj.get_int( "step", 0 ); - return [is_npc, add_id, val, step]( dialogue const & d ) { - int intens = d.actor( is_npc )->get_addiction_intensity( add_id ); - int denom = val - step * intens; - return denom == 0 ? 0 : ( val / std::max( 1, denom ) - 1 ); - }; - } - const int mod = jo.get_int( "mod", 1 ); - return [is_npc, add_id, mod]( dialogue const & d ) { - return d.actor( is_npc )->get_addiction_intensity( add_id ) * mod; - }; - } else if( checked_value == "addiction_turns" ) { - const addiction_id add_id( jo.get_string( "addiction" ) ); - return [is_npc, add_id]( dialogue const & d ) { - return d.actor( is_npc )->get_addiction_turns( add_id ); - }; } else if( checked_value == "stim" ) { return [is_npc]( dialogue const & d ) { return d.actor( is_npc )->get_stim(); @@ -2349,16 +2241,6 @@ std::function conditional_t::get_get_dbl( J const &jo ) return [is_npc]( dialogue const & d ) { return d.actor( is_npc )->get_friendly(); }; - } else if( checked_value == "vitamin" ) { - std::string vitamin_name = jo.get_string( "name" ); - return [is_npc, vitamin_name]( dialogue const & d ) { - Character const *you = static_cast( d.actor( is_npc ) )->get_character(); - if( you ) { - return you->vitamin_get( vitamin_id( vitamin_name ) ); - } else { - return 0; - } - }; } else if( checked_value == "age" ) { return [is_npc]( dialogue const & d ) { return d.actor( is_npc )->get_age(); @@ -2419,137 +2301,7 @@ std::function conditional_t::get_get_dbl( J const &jo ) return [is_npc]( dialogue const & d ) { return d.actor( is_npc )->get_npc_anger(); }; - } else if( checked_value == "field_strength" ) { - if( jo.has_member( "field" ) ) { - field_type_id ft = field_type_id( jo.get_string( "field" ) ); - return [is_npc, ft]( dialogue const & d ) { - map &here = get_map(); - for( const std::pair &f : here.field_at( d.actor( - is_npc )->pos() ) ) { - if( f.second.get_field_type() == ft ) { - return f.second.get_field_intensity(); - } - } - return 0; - }; - } - } else if( checked_value == "spell_level" ) { - if( jo.has_member( "school" ) ) { - const std::string school_name = jo.get_string( "school" ); - const trait_id spell_school( school_name ); - return [is_npc, spell_school]( dialogue & d ) { - return d.actor( is_npc )->get_spell_level( spell_school ); - }; - } else if( jo.has_member( "spell" ) ) { - const std::string spell_name = jo.get_string( "spell" ); - const spell_id this_spell_id( spell_name ); - return [is_npc, this_spell_id]( dialogue & d ) { - return d.actor( is_npc )->get_spell_level( this_spell_id ); - }; - } else { - return [is_npc]( dialogue & d ) { - return d.actor( is_npc )->get_highest_spell_level(); - }; - } - } else if( checked_value == "spell_level_adjustment" ) { - if( jo.has_member( "school" ) ) { - const std::string school_name = jo.get_string( "school" ); - const trait_id spell_school( school_name ); - return [is_npc, spell_school]( dialogue & d ) { - std::map::iterator it = - d.actor( is_npc )->get_character()->magic->caster_level_adjustment_by_school.find( spell_school ); - if( it != d.actor( is_npc )->get_character()->magic->caster_level_adjustment_by_school.end() ) { - return it->second; - } else { - return 0.0; - } - }; - } else if( jo.has_member( "spell" ) ) { - const std::string spell_name = jo.get_string( "spell" ); - const spell_id this_spell_id( spell_name ); - return [is_npc, this_spell_id]( dialogue & d ) { - std::map::iterator it = - d.actor( is_npc )->get_character()->magic->caster_level_adjustment_by_spell.find( this_spell_id ); - if( it != d.actor( is_npc )->get_character()->magic->caster_level_adjustment_by_spell.end() ) { - return it->second; - } else { - return 0.0; - } - }; - } else { - return [is_npc]( dialogue & d ) { - return d.actor( is_npc )->get_character()->magic->caster_level_adjustment; - }; - } - } else if( checked_value == "spell_exp" ) { - const std::string spell_name = jo.get_string( "spell" ); - const spell_id this_spell_id( spell_name ); - return [is_npc, this_spell_id]( dialogue & d ) { - return d.actor( is_npc )->get_spell_exp( this_spell_id ); - }; - } else if( checked_value == "spell_count" ) { - trait_id school = trait_id::NULL_ID(); - if( jo.has_member( "school" ) ) { - school = trait_id( jo.get_string( "school" ) ); - } - return [is_npc, school]( dialogue & d ) { - return d.actor( is_npc )->get_spell_count( school ); - }; - } else if( checked_value == "proficiency" ) { - const std::string proficiency_name = jo.get_string( "proficiency_id" ); - const proficiency_id the_proficiency_id( proficiency_name ); - if( jo.has_int( "format" ) ) { - const int format = jo.get_int( "format" ); - return [is_npc, format, the_proficiency_id]( dialogue & d ) { - return static_cast( ( d.actor( is_npc )->proficiency_practiced_time( - the_proficiency_id ) * format ) / - the_proficiency_id->time_to_learn() ); - }; - } else if( jo.has_member( "format" ) ) { - const std::string format = jo.get_string( "format" ); - if( format == "time_spent" ) { - return [is_npc, the_proficiency_id]( dialogue & d ) { - return to_turns( d.actor( is_npc )->proficiency_practiced_time( the_proficiency_id ) ); - }; - } else if( format == "percent" ) { - return [is_npc, the_proficiency_id]( dialogue & d ) { - return static_cast( ( d.actor( is_npc )->proficiency_practiced_time( - the_proficiency_id ) * 100 ) / - the_proficiency_id->time_to_learn() ); - }; - } else if( format == "permille" ) { - return [is_npc, the_proficiency_id]( dialogue & d ) { - return static_cast( ( d.actor( is_npc )->proficiency_practiced_time( - the_proficiency_id ) * 1000 ) / - the_proficiency_id->time_to_learn() ); - }; - } else if( format == "total_time_required" ) { - return [the_proficiency_id]( dialogue & d ) { - static_cast( d ); - return to_turns( the_proficiency_id->time_to_learn() ); - }; - } else if( format == "time_left" ) { - return [is_npc, the_proficiency_id]( dialogue & d ) { - return to_turns( the_proficiency_id->time_to_learn() - d.actor( - is_npc )->proficiency_practiced_time( the_proficiency_id ) ); - }; - } else { - jo.throw_error( "unrecognized format in " + jo.str() ); - } - } } - } else if( jo.has_array( "distance" ) ) { - JsonArray objects = jo.get_array( "distance" ); - if( objects.size() != 2 ) { - objects.throw_error( "distance requires an array with 2 elements." ); - } - std::string first = get_string_from_input( objects, 0 ); - std::string second = get_string_from_input( objects, 1 ); - return [first, second]( dialogue & d ) { - tripoint_abs_ms first_point = get_tripoint_from_string( first, d ); - tripoint_abs_ms second_point = get_tripoint_from_string( second, d ); - return rl_dist( first_point, second_point ); - }; } else if( jo.has_member( "mod_load_order" ) ) { const mod_id our_mod_id = mod_id( jo.get_string( "mod_load_order" ) ); return [our_mod_id]( dialogue const & ) { @@ -2627,10 +2379,6 @@ conditional_t::get_set_dbl( const J &jo, const std::optional &m write_var_value( var_type::global, "temp_var", d.actor( false ), &d, handle_min_max( d, input, min, max ) ); }; - } else if( jo.has_member( "const" ) ) { - jo.throw_error( "attempted to alter a constant value in " + jo.str() ); - } else if( jo.has_member( "rand" ) ) { - jo.throw_error( "can not alter the random number generator, silly! In " + jo.str() ); } else if( jo.has_member( "faction_trust" ) ) { str_or_var name = get_str_or_var( jo.get_member( "faction_trust" ), "faction_trust" ); return [name, min, max]( dialogue & d, double input ) { @@ -2722,13 +2470,6 @@ conditional_t::get_set_dbl( const J &jo, const std::optional &m write_var_value( type, var_name, d.actor( is_npc ), &d, handle_min_max( d, input, min, max ) ); }; - } else if( checked_value == "allies" ) { - // It would be possible to make this work by removing allies and spawning new ones as needed. - // But why would you ever want to do it this way? - jo.throw_error( "altering allies this way is currently not supported. In " + jo.str() ); - } else if( checked_value == "cash" ) { - // TODO: See if this can be handeled in a clever way. - jo.throw_error( "altering cash this way is currently not supported. In " + jo.str() ); } else if( checked_value == "owed" ) { if( is_npc ) { jo.throw_error( "owed amount not supported for NPCs. In " + jo.str() ); @@ -2767,8 +2508,6 @@ conditional_t::get_set_dbl( const J &jo, const std::optional &m // Energy in milijoule d.actor( is_npc )->set_power_cur( 1_mJ * handle_min_max( d, input, min, max ) ); }; - } else if( checked_value == "power_max" ) { - jo.throw_error( "altering max power this way is currently not supported. In " + jo.str() ); } else if( checked_value == "power_percentage" ) { return [is_npc, min, max]( dialogue & d, double input ) { // Energy in milijoule @@ -2785,15 +2524,11 @@ conditional_t::get_set_dbl( const J &jo, const std::optional &m return [is_npc, min, max]( dialogue & d, double input ) { d.actor( is_npc )->set_mana_cur( handle_min_max( d, input, min, max ) ); }; - } else if( checked_value == "mana_max" ) { - jo.throw_error( "altering max mana this way is currently not supported. In " + jo.str() ); } else if( checked_value == "mana_percentage" ) { return [is_npc, min, max]( dialogue & d, double input ) { d.actor( is_npc )->set_mana_cur( ( d.actor( is_npc )->mana_max() * handle_min_max( d, input, min, max ) ) / 100 ); }; - } else if( checked_value == "hunger" ) { - jo.throw_error( "altering hunger this way is currently not supported. In " + jo.str() ); } else if( checked_value == "thirst" ) { return [is_npc, min, max]( dialogue & d, double input ) { d.actor( is_npc )->set_thirst( handle_min_max( d, input, min, max ) ); @@ -2807,15 +2542,6 @@ conditional_t::get_set_dbl( const J &jo, const std::optional &m return [is_npc, min, max]( dialogue & d, double input ) { d.actor( is_npc )->set_stored_kcal( handle_min_max( d, input, min, max ) * 5500 ); }; - } else if( checked_value == "item_count" ) { - jo.throw_error( "altering items this way is currently not supported. In " + jo.str() ); - } else if( checked_value == "exp" ) { - jo.throw_error( "altering max exp this way is currently not supported. In " + jo.str() ); - } else if( checked_value == "addiction_turns" ) { - const addiction_id add_id( jo.get_string( "addiction" ) ); - return [is_npc, min, max, add_id]( dialogue & d, double input ) { - d.actor( is_npc )->set_addiction_turns( add_id, handle_min_max( d, input, min, max ) ); - }; } else if( checked_value == "stim" ) { return [is_npc, min, max]( dialogue & d, double input ) { d.actor( is_npc )->set_stim( handle_min_max( d, input, min, max ) ); @@ -2856,14 +2582,6 @@ conditional_t::get_set_dbl( const J &jo, const std::optional &m return [is_npc, min, max]( dialogue & d, double input ) { d.actor( is_npc )->set_kill_xp( handle_min_max( d, input, min, max ) ); }; - } else if( checked_value == "vitamin" ) { - std::string vitamin_name = jo.get_string( "name" ); - return [is_npc, min, max, vitamin_name]( dialogue & d, double input ) { - Character *you = d.actor( is_npc )->get_character(); - if( you ) { - you->vitamin_set( vitamin_id( vitamin_name ), handle_min_max( d, input, min, max ) ); - } - }; } else if( checked_value == "age" ) { return [is_npc, min, max]( dialogue & d, double input ) { d.actor( is_npc )->set_age( handle_min_max( d, input, min, max ) ); @@ -2888,83 +2606,6 @@ conditional_t::get_set_dbl( const J &jo, const std::optional &m return [is_npc, min, max]( dialogue & d, double input ) { d.actor( is_npc )->set_npc_anger( handle_min_max( d, input, min, max ) ); }; - } else if( checked_value == "spell_level" ) { - const std::string spell_name = jo.get_string( "spell" ); - const spell_id this_spell_id( spell_name ); - return [is_npc, min, max, this_spell_id]( dialogue & d, double input ) { - d.actor( is_npc )->set_spell_level( this_spell_id, handle_min_max( d, input, min, max ) ); - }; - } else if( checked_value == "spell_level_adjustment" ) { - if( jo.has_member( "school" ) ) { - const std::string school_name = jo.get_string( "school" ); - const trait_id spell_school( school_name ); - return [is_npc, min, max, spell_school]( dialogue & d, double input ) { - std::map::iterator it = - d.actor( is_npc )->get_character()->magic->caster_level_adjustment_by_school.find( spell_school ); - if( it != d.actor( is_npc )->get_character()->magic->caster_level_adjustment_by_school.end() ) { - it->second = handle_min_max( d, input, min, max ); - } else { - d.actor( is_npc )->get_character()->magic->caster_level_adjustment_by_school.insert( { spell_school, handle_min_max( d, input, min, max ) } ); - } - }; - } else if( jo.has_member( "spell" ) ) { - const std::string spell_name = jo.get_string( "spell" ); - const spell_id this_spell_id( spell_name ); - return [is_npc, min, max, this_spell_id]( dialogue & d, double input ) { - std::map::iterator it = - d.actor( is_npc )->get_character()->magic->caster_level_adjustment_by_spell.find( this_spell_id ); - if( it != d.actor( is_npc )->get_character()->magic->caster_level_adjustment_by_spell.end() ) { - it->second = handle_min_max( d, input, min, max ); - } else { - d.actor( is_npc )->get_character()->magic->caster_level_adjustment_by_spell.insert( { this_spell_id, handle_min_max( d, input, min, max ) } ); - } - }; - } else { - return [is_npc, min, max]( dialogue & d, double input ) { - d.actor( is_npc )->get_character()->magic->caster_level_adjustment = - handle_min_max( d, input, min, max ); - }; - } - } else if( checked_value == "spell_exp" ) { - const std::string spell_name = jo.get_string( "spell" ); - const spell_id this_spell_id( spell_name ); - return [is_npc, min, max, this_spell_id]( dialogue & d, double input ) { - d.actor( is_npc )->set_spell_exp( this_spell_id, handle_min_max( d, input, min, max ) ); - }; - } else if( checked_value == "proficiency" ) { - const std::string proficiency_name = jo.get_string( "proficiency_id" ); - const proficiency_id the_proficiency_id( proficiency_name ); - if( jo.has_int( "format" ) ) { - const int format = jo.get_int( "format" ); - return [is_npc, format, the_proficiency_id]( dialogue const & d, double input ) { - d.actor( is_npc )->set_proficiency_practiced_time( the_proficiency_id, - to_turns( the_proficiency_id->time_to_learn() * input ) / format ); - }; - } else if( jo.has_member( "format" ) ) { - const std::string format = jo.get_string( "format" ); - if( format == "time_spent" ) { - return [is_npc, the_proficiency_id]( dialogue const & d, double input ) { - d.actor( is_npc )->set_proficiency_practiced_time( the_proficiency_id, input ); - }; - } else if( format == "percent" ) { - return [is_npc, the_proficiency_id]( dialogue const & d, double input ) { - d.actor( is_npc )->set_proficiency_practiced_time( the_proficiency_id, - to_turns( the_proficiency_id->time_to_learn()* input ) / 100 ); - }; - } else if( format == "permille" ) { - return [is_npc, the_proficiency_id]( dialogue const & d, double input ) { - d.actor( is_npc )->set_proficiency_practiced_time( the_proficiency_id, - to_turns( the_proficiency_id->time_to_learn() * input ) / 1000 ); - }; - } else if( format == "time_left" ) { - return [is_npc, the_proficiency_id]( dialogue const & d, double input ) { - d.actor( is_npc )->set_proficiency_practiced_time( the_proficiency_id, - to_turns( the_proficiency_id->time_to_learn() ) - input ); - }; - } else { - jo.throw_error( "unrecognized format in " + jo.str() ); - } - } } } jo.throw_error( "error setting double destination in " + jo.str() ); diff --git a/tests/math_parser_test.cpp b/tests/math_parser_test.cpp index 1143d68a6a469..5f8e9fd38e69c 100644 --- a/tests/math_parser_test.cpp +++ b/tests/math_parser_test.cpp @@ -10,7 +10,6 @@ #include "math_parser_func.h" static const skill_id skill_survival( "survival" ); -static const spell_id spell_test_spell_pew( "test_spell_pew" ); // NOLINTNEXTLINE(readability-function-cognitive-complexity): false positive TEST_CASE( "math_parser_parsing", "[math_parser]" ) @@ -308,11 +307,6 @@ TEST_CASE( "math_parser_dialogue_integration", "[math_parser]" ) } ); CHECK( testexp.parse( "u_val('stamina')" ) ); CHECK( testexp.eval( d ) == get_avatar().get_stamina() ); - CHECK( testexp.parse( "u_val('spell_level', 'spell: test_spell_pew')" ) ); - get_avatar().magic->learn_spell( spell_test_spell_pew, get_avatar(), true ); - get_avatar().magic->set_spell_level( spell_test_spell_pew, 4, &get_avatar() ); - REQUIRE( d.actor( false )->get_spell_level( spell_test_spell_pew ) != 0 ); - CHECK( testexp.eval( d ) == d.actor( false )->get_spell_level( spell_test_spell_pew ) ); // units test CHECK( testexp.parse( "time('1 m')" ) ); From 33ae1be5adf5202aa686c4b88735f624503a7813 Mon Sep 17 00:00:00 2001 From: andrei Date: Wed, 24 Jan 2024 11:13:33 +0200 Subject: [PATCH 2/3] eoc/math: port faction_like/respect/trust to math --- .../npc_eocs/generic_npc_eocs.json | 12 ++-- .../eoc_premonition_instances.json | 12 ++-- doc/NPCs.md | 5 +- src/condition.cpp | 36 ----------- src/math_parser_diag.cpp | 60 +++++++++++++++++++ 5 files changed, 73 insertions(+), 52 deletions(-) diff --git a/data/json/effects_on_condition/npc_eocs/generic_npc_eocs.json b/data/json/effects_on_condition/npc_eocs/generic_npc_eocs.json index 2cab3d912cf64..101ff5404086c 100644 --- a/data/json/effects_on_condition/npc_eocs/generic_npc_eocs.json +++ b/data/json/effects_on_condition/npc_eocs/generic_npc_eocs.json @@ -235,8 +235,8 @@ "global": true, "condition": { "and": [ - { "math": [ "u_val('faction_like: hells_raiders')", "<", "-40" ] }, - { "math": [ "u_val('faction_like: hells_raiders')", ">", "-60" ] }, + { "math": [ "faction_like('hells_raiders')", "<", "-40" ] }, + { "math": [ "faction_like('hells_raiders')", ">", "-60" ] }, { "math": [ "u_bandit_assassins_sent", "<=", "10" ] }, { "math": [ "time_since('cataclysm', 'unit':'days') >= 9" ] }, { "not": { "is_weather": "portal_storm" } }, @@ -259,8 +259,8 @@ "global": true, "condition": { "and": [ - { "math": [ "u_val('faction_like: hells_raiders')", "<", "-60" ] }, - { "math": [ "u_val('faction_like: hells_raiders')", ">", "-90" ] }, + { "math": [ "faction_like('hells_raiders')", "<", "-60" ] }, + { "math": [ "faction_like('hells_raiders')", ">", "-90" ] }, { "math": [ "u_bandit_assassins_sent", "<=", "10" ] }, { "math": [ "time_since('cataclysm', 'unit':'days') >= 15" ] }, { "not": { "is_weather": "portal_storm" } }, @@ -283,7 +283,7 @@ "global": true, "condition": { "and": [ - { "math": [ "u_val('faction_like: hells_raiders')", "<", "-90" ] }, + { "math": [ "faction_like('hells_raiders')", "<", "-90" ] }, { "math": [ "u_bandit_assassins_sent", "<=", "10" ] }, { "math": [ "time_since('cataclysm', 'unit':'days') >= 21" ] }, { "not": { "is_weather": "portal_storm" } }, @@ -306,7 +306,7 @@ "global": true, "condition": { "and": [ - { "math": [ "u_val('faction_like: old_guard')", "<", "-45" ] }, + { "math": [ "faction_like('old_guard')", "<", "-45" ] }, { "math": [ "u_government_assassins_sent", "<=", "6" ] }, { "math": [ "time_since('cataclysm', 'unit':'days') >= 9" ] }, { "not": { "is_weather": "portal_storm" } }, diff --git a/data/mods/MindOverMatter/effectoncondition/eoc_premonition_instances.json b/data/mods/MindOverMatter/effectoncondition/eoc_premonition_instances.json index d39733c33a443..37ad4d653853f 100644 --- a/data/mods/MindOverMatter/effectoncondition/eoc_premonition_instances.json +++ b/data/mods/MindOverMatter/effectoncondition/eoc_premonition_instances.json @@ -110,8 +110,8 @@ "global": true, "condition": { "and": [ - { "math": [ "u_val('faction_like: hells_raiders')", "<", "-40" ] }, - { "math": [ "u_val('faction_like: hells_raiders')", ">", "-60" ] }, + { "math": [ "faction_like('hells_raiders')", "<", "-40" ] }, + { "math": [ "faction_like('hells_raiders')", ">", "-60" ] }, { "math": [ "u_bandit_assassins_sent", "<=", "10" ] }, { "math": [ "time_since('cataclysm', 'unit':'days') >= 9" ] }, { "not": { "is_weather": "portal_storm" } }, @@ -183,8 +183,8 @@ "global": true, "condition": { "and": [ - { "math": [ "u_val('faction_like: hells_raiders')", "<", "-60" ] }, - { "math": [ "u_val('faction_like: hells_raiders')", ">", "-90" ] }, + { "math": [ "faction_like('hells_raiders')", "<", "-60" ] }, + { "math": [ "faction_like('hells_raiders')", ">", "-90" ] }, { "math": [ "u_bandit_assassins_sent", "<=", "10" ] }, { "math": [ "time_since('cataclysm', 'unit':'days') >= 15" ] }, { "not": { "is_weather": "portal_storm" } }, @@ -258,7 +258,7 @@ "global": true, "condition": { "and": [ - { "math": [ "u_val('faction_like: hells_raiders')", "<", "-90" ] }, + { "math": [ "faction_like('hells_raiders')", "<", "-90" ] }, { "math": [ "u_bandit_assassins_sent", "<=", "10" ] }, { "math": [ "time_since('cataclysm', 'unit':'days') >= 21" ] }, { "not": { "is_weather": "portal_storm" } }, @@ -332,7 +332,7 @@ "global": true, "condition": { "and": [ - { "math": [ "u_val('faction_like: old_guard')", "<", "-45" ] }, + { "math": [ "faction_like('old_guard')", "<", "-45" ] }, { "math": [ "u_government_assassins_sent", "<=", "6" ] }, { "math": [ "time_since('cataclysm', 'unit':'days') >= 9" ] }, { "not": { "is_weather": "portal_storm" } }, diff --git a/doc/NPCs.md b/doc/NPCs.md index 5649473bfbe8c..0bfa908b8eb91 100644 --- a/doc/NPCs.md +++ b/doc/NPCs.md @@ -1226,11 +1226,7 @@ To get player character properties, use `"u_val"`. To get NPC properties, use sa Example | Description --- | --- `"const": 5` | A constant value, in this case 5. Can be read but not written to. -`"time": "5 days"` | A constant time value. Will be converted to turns. Can be read but not written to. `"rand": 20` | A random value between 0 and a given value, in this case 20. Can be read but not written to. -`"faction_trust": "free_merchants"` | The trust the faction has for the player (see [FACTIONS.md](FACTIONS.md)) for details. -`"faction_like": "free_merchants"` | How much the faction likes the player (see [FACTIONS.md](FACTIONS.md)) for details. -`"faction_respect": "free_merchants"` | How much the faction respects the player(see [FACTIONS.md](FACTIONS.md)) for details. `"u_val": "strength"` | Player character's strength. Can be read but not written to. Replace `"strength"` with `"dexterity"`, `"intelligence"`, or `"perception"` to get such values. `"u_val": "strength_base"` | Player character's strength. Replace `"strength_base"` with `"dexterity_base"`, `"intelligence_base"`, or `"perception_base"` to get such values. `"u_val": "strength_bonus"` | Player character's current strength bonus. Replace `"strength_bonus"` with `"dexterity_bonus"`, `"intelligence_bonus"`, or `"perception_bonus"` to get such values. @@ -1404,6 +1400,7 @@ _some functions support array arguments or kwargs, denoted with square brackets | effect_intensity(`s`/`v`) | ✅ | ❌ | u, n | Return the characters intensity of effect.
Argument is effect ID.

Optional kwargs:
`bodypart`: `s`/`v` - Specify the bodypart to get/set intensity of effect.

Example:
`"condition": { "math": [ "u_effect_intensity('bite', 'bodypart': 'torso')", ">", "1"] }`| | encumbrance(`s`/`v`) | ✅ | ❌ | u, n | Return the characters total encumbrance of a body part.
Argument is bodypart ID.
For items, returns typical encumbrance of the item.

Example:
`"condition": { "math": [ "u_encumbrance('torso')", ">", "0"] }`| | energy(`s`/`v`) | ✅ | ❌ | u, n | Return a numeric value (in millijoules) for an energy string (see [Units](JSON_INFO.md#units)).

Example:
`{ "math": [ "u_val('power')", "-=", "energy('25 kJ')" ] }`| +| faction_like(`s`/`v`)
faction_respect(`s`/`v`)
faction_trust(`s`/`v`) | ✅ | ❌ | N/A
(global) | Return the like/respect/trust value a faction has for the avatar.
Argument is faction ID.

Example:
`"condition": { "math": [ "faction_like('hells_raiders') < -60" ] }`| | field_strength(`s`/`v`) | ✅ | ❌ | u, n, global | Return the strength of a field on the tile.
Argument is field ID.

Optional kwargs:
`location`: `v` - center search on this location

The `location` kwarg is mandatory in the global scope.

Examples:
`"condition": { "math": [ "u_field_strength('fd_blood')", ">", "5" ] }`

`"condition": { "math": [ "field_strength('fd_blood_insect', 'location': u_search_loc)", ">", "5" ] }`| | has_trait(`s`/`v`) | ✅ | ❌ | u, n | Check whether the actor has a trait. Meant to be used as condition for ternaries. Arguemnt is trait ID.

Example:
`"condition": { "math": [ "u_blorg", "=", "u_has_trait('FEEBLE') ? 100 : 15" ] }`| | has_proficiency(`s`/`v`) | ✅ | ❌ | u, n | Check whether the actor has a proficiency. Meant to be used as condition for ternaries. Arguemnt is proficiency ID.

Example:
`"condition": { "math": [ "u_blorg", "=", "u_has_proficiency('prof_intro_biology') ? 100 : 15" ] }`| diff --git a/src/condition.cpp b/src/condition.cpp index 600a540ea90a0..237775b06f286 100644 --- a/src/condition.cpp +++ b/src/condition.cpp @@ -1988,24 +1988,6 @@ std::function conditional_t::get_get_dbl( J const &jo ) return [max_value]( dialogue const & ) { return rng( 0, max_value ); }; - } else if( jo.has_member( "faction_trust" ) ) { - str_or_var name = get_str_or_var( jo.get_member( "faction_trust" ), "faction_trust" ); - return [name]( dialogue const & d ) { - faction *fac = g->faction_manager_ptr->get( faction_id( name.evaluate( d ) ) ); - return fac->trusts_u; - }; - } else if( jo.has_member( "faction_like" ) ) { - str_or_var name = get_str_or_var( jo.get_member( "faction_like" ), "faction_like" ); - return [name]( dialogue const & d ) { - faction *fac = g->faction_manager_ptr->get( faction_id( name.evaluate( d ) ) ); - return fac->likes_u; - }; - } else if( jo.has_member( "faction_respect" ) ) { - str_or_var name = get_str_or_var( jo.get_member( "faction_respect" ), "faction_respect" ); - return [name]( dialogue const & d ) { - faction *fac = g->faction_manager_ptr->get( faction_id( name.evaluate( d ) ) ); - return fac->respects_u; - }; } else if( jo.has_member( "u_val" ) || jo.has_member( "npc_val" ) || jo.has_member( "global_val" ) || jo.has_member( "context_val" ) ) { const bool is_npc = jo.has_member( "npc_val" ); @@ -2379,24 +2361,6 @@ conditional_t::get_set_dbl( const J &jo, const std::optional &m write_var_value( var_type::global, "temp_var", d.actor( false ), &d, handle_min_max( d, input, min, max ) ); }; - } else if( jo.has_member( "faction_trust" ) ) { - str_or_var name = get_str_or_var( jo.get_member( "faction_trust" ), "faction_trust" ); - return [name, min, max]( dialogue & d, double input ) { - faction *fac = g->faction_manager_ptr->get( faction_id( name.evaluate( d ) ) ); - fac->trusts_u = handle_min_max( d, input, min, max ); - }; - } else if( jo.has_member( "faction_like" ) ) { - str_or_var name = get_str_or_var( jo.get_member( "faction_like" ), "faction_like" ); - return [name, min, max]( dialogue & d, double input ) { - faction *fac = g->faction_manager_ptr->get( faction_id( name.evaluate( d ) ) ); - fac->likes_u = handle_min_max( d, input, min, max ); - }; - } else if( jo.has_member( "faction_respect" ) ) { - str_or_var name = get_str_or_var( jo.get_member( "faction_respect" ), "faction_respect" ); - return [name, min, max]( dialogue & d, double input ) { - faction *fac = g->faction_manager_ptr->get( faction_id( name.evaluate( d ) ) ); - fac->respects_u = handle_min_max( d, input, min, max ); - }; } else if( jo.has_member( "u_val" ) || jo.has_member( "npc_val" ) || jo.has_member( "global_val" ) || jo.has_member( "faction_val" ) || jo.has_member( "party_val" ) || jo.has_member( "context_val" ) ) { diff --git a/src/math_parser_diag.cpp b/src/math_parser_diag.cpp index a159a6a44ac13..05d81f0eede9b 100644 --- a/src/math_parser_diag.cpp +++ b/src/math_parser_diag.cpp @@ -222,6 +222,60 @@ std::function encumbrance_eval( char scope, }; } +std::function faction_like_eval( char /* scope */, + std::vector const ¶ms, diag_kwargs const &/* kwargs */ ) +{ + return [fac_val = params[0]]( dialogue & d ) { + faction *fac = g->faction_manager_ptr->get( faction_id( fac_val.str( d ) ) ); + return fac->likes_u; + }; +} + +std::function faction_like_ass( char /* scope */, + std::vector const ¶ms, diag_kwargs const &/* kwargs */ ) +{ + return [fac_val = params[0]]( dialogue const & d, double val ) { + faction *fac = g->faction_manager_ptr->get( faction_id( fac_val.str( d ) ) ); + fac->likes_u = val; + }; +} + +std::function faction_respect_eval( char /* scope */, + std::vector const ¶ms, diag_kwargs const &/* kwargs */ ) +{ + return [fac_val = params[0]]( dialogue & d ) { + faction *fac = g->faction_manager_ptr->get( faction_id( fac_val.str( d ) ) ); + return fac->respects_u; + }; +} + +std::function faction_respect_ass( char /* scope */, + std::vector const ¶ms, diag_kwargs const &/* kwargs */ ) +{ + return [fac_val = params[0]]( dialogue const & d, double val ) { + faction *fac = g->faction_manager_ptr->get( faction_id( fac_val.str( d ) ) ); + fac->respects_u = val; + }; +} + +std::function faction_trust_eval( char /* scope */, + std::vector const ¶ms, diag_kwargs const &/* kwargs */ ) +{ + return [fac_val = params[0]]( dialogue & d ) { + faction *fac = g->faction_manager_ptr->get( faction_id( fac_val.str( d ) ) ); + return fac->trusts_u; + }; +} + +std::function faction_trust_ass( char /* scope */, + std::vector const ¶ms, diag_kwargs const &/* kwargs */ ) +{ + return [fac_val = params[0]]( dialogue const & d, double val ) { + faction *fac = g->faction_manager_ptr->get( faction_id( fac_val.str( d ) ) ); + fac->trusts_u = val; + }; +} + std::function field_strength_eval( char scope, std::vector const ¶ms, diag_kwargs const &kwargs ) { @@ -1181,6 +1235,9 @@ std::map const dialogue_eval_f{ { "effect_intensity", { "un", 1, effect_intensity_eval } }, { "encumbrance", { "un", 1, encumbrance_eval } }, { "energy", { "g", 1, energy_eval } }, + { "faction_like", { "g", 1, faction_like_eval } }, + { "faction_respect", { "g", 1, faction_respect_eval } }, + { "faction_trust", { "g", 1, faction_trust_eval } }, { "field_strength", { "ung", 1, field_strength_eval } }, { "gun_damage", { "un", 1, gun_damage_eval } }, { "game_option", { "g", 1, option_eval } }, @@ -1219,6 +1276,9 @@ std::map const dialogue_eval_f{ std::map const dialogue_assign_f{ { "addiction_turns", { "un", 1, addiction_turns_ass } }, + { "faction_like", { "g", 1, faction_like_ass } }, + { "faction_respect", { "g", 1, faction_respect_ass } }, + { "faction_trust", { "g", 1, faction_trust_ass } }, { "hp", { "un", 1, hp_ass } }, { "pain", { "un", 0, pain_ass } }, { "school_level_adjustment", { "un", 1, school_level_adjustment_ass } }, From 3d25d18b8896e9dfee6e7d318b51c98b7d57179c Mon Sep 17 00:00:00 2001 From: andrei Date: Wed, 24 Jan 2024 11:18:20 +0200 Subject: [PATCH 3/3] eoc/math_parser: port mod_load_order to math --- doc/NPCs.md | 2 +- src/condition.cpp | 12 ------------ src/math_parser_diag.cpp | 18 ++++++++++++++++++ 3 files changed, 19 insertions(+), 13 deletions(-) diff --git a/doc/NPCs.md b/doc/NPCs.md index 0bfa908b8eb91..73e4f0454093c 100644 --- a/doc/NPCs.md +++ b/doc/NPCs.md @@ -1274,7 +1274,6 @@ Example | Description `"u_val": "grab_strength"` | Grab strength as defined in the monster definition. Read-only, returns false on characters. `"u_val": "volume"` | Current volume in ml. read only. Cullently, doesn't work for characters, but for monsters and items. `"u_val": "weight"` | Current weight in mg. read only. -`"mod_load_order"` | This should be a string with the name of the mod. It will return the order it was loaded in or -1 if its not loaded. `"arithmetic"` | An arithmetic expression with no result.

Example:
"real_count": { "arithmetic": [
{ "arithmetic": [ { "const":1 }, "+", { "const": 1 } ] },
"+", { "const": 1 }
] },
`"math"` | An array math object. @@ -1413,6 +1412,7 @@ _some functions support array arguments or kwargs, denoted with square brackets | item_rad(`s`/`v`) | ✅ | ❌ | u, n | Return irradiation of worn items with the specified flag.
Argument is flag ID.

Optional kwargs:
`aggregate`: `s`/`v` - Specify the aggregation function to run, in case there's more than one item. Valid values are `min`/`max`/`sum`/`average`/`first`/`last`. Defaults to `min` if not specified.

Example:
`"condition": { "math": [ "u_item_rad('RAD_DETECT')", ">=", "1"] }`| | melee_damage(`s`/`v`) | ✅ | ❌ | u, n | Return the item's melee damage. Argument is damage type. For special value `ALL`, return sum for all damage types.

Actor must be an item.

Example:
`{ "math": [ "mymelee", "=", "n_melee_damage('ALL')" ] }`
See `EOC_test_weapon_damage` for a complete example| | monsters_nearby(`s`/`v`...) | ✅ | ❌ | u, n, global | Return the number of nearby monsters. Takes any number of `s`tring or `v`ariable positional parameters as monster IDs.

Optional kwargs:
`radius`: `d`/`v` - limit to radius (rl_dist)
`location`: `v` - center search on this location
`attitude`: `s`/`v` - attitude filter. Must be one of `hostile`, `friendly`, `both`. Assumes `hostile` if not specified

The `location` kwarg is mandatory in the global scope.

Examples:
`"condition": { "math": [ "u_monsters_nearby('radius': u_search_radius * 3)", ">", "5" ] }`

`"condition": { "math": [ "monsters_nearby('mon_void_maw', 'mon_void_limb', mon_fotm_var, 'radius': u_search_radius * 3, 'location': u_search_loc)", ">", "5" ] }`| +| mod_load_order(`s`/`v`) | ✅ | ❌ | N/A
(global) | Returns the load order of specified mod. Argument is mod id. Returns -1 is the mod is not loaded. | | mon_species_nearby(`s`/`v`...) | ✅ | ❌ | u, n, global | Same as `monsters_nearby()`, but arguments are monster species | | mon_groups_nearby(`s`/`v`...) | ✅ | ❌ | u, n, global | Same as `monsters_nearby()`, but arguments are monster groups | | moon_phase() | ✅ | ❌ | N/A
(global) | Returns current phase of the Moon.
MOON_NEW = 0,
WAXING_CRESCENT = 1,
HALF_MOON_WAXING = 2,
WAXING_GIBBOUS = 3,
FULL = 4,
WANING_GIBBOUS = 5,
HALF_MOON_WANING = 6,
WANING_CRESCENT = 7 | diff --git a/src/condition.cpp b/src/condition.cpp index 237775b06f286..efdcbc310d18f 100644 --- a/src/condition.cpp +++ b/src/condition.cpp @@ -2284,18 +2284,6 @@ std::function conditional_t::get_get_dbl( J const &jo ) return d.actor( is_npc )->get_npc_anger(); }; } - } else if( jo.has_member( "mod_load_order" ) ) { - const mod_id our_mod_id = mod_id( jo.get_string( "mod_load_order" ) ); - return [our_mod_id]( dialogue const & ) { - int count = 0; - for( const mod_id &mod : world_generator->active_world->active_mod_order ) { - if( our_mod_id == mod ) { - return count; - } - count++; - } - return -1; - }; } else if( jo.has_array( "arithmetic" ) ) { talk_effect_fun_t arith; if constexpr( std::is_same_v ) { diff --git a/src/math_parser_diag.cpp b/src/math_parser_diag.cpp index 05d81f0eede9b..f853b8cb5040f 100644 --- a/src/math_parser_diag.cpp +++ b/src/math_parser_diag.cpp @@ -18,6 +18,7 @@ #include "string_input_popup.h" #include "units.h" #include "weather.h" +#include "worldfactory.h" /* General guidelines for writing dialogue functions @@ -547,6 +548,22 @@ std::function melee_damage_eval( char scope, }; } +std::function mod_order_eval( char /* scope */, + std::vector const ¶ms, diag_kwargs const &/* kwargs */ ) +{ + return[mod_val = params[0]]( dialogue const & d ) { + int count = 0; + mod_id our_mod_id( mod_val.str( d ) ); + for( const mod_id &mod : world_generator->active_world->active_mod_order ) { + if( our_mod_id == mod ) { + return count; + } + count++; + } + return -1; + }; +} + template using f_monster_match = bool ( * )( Creature const &critter, ID const &id ); @@ -1249,6 +1266,7 @@ std::map const dialogue_eval_f{ { "item_count", { "un", 1, item_count_eval } }, { "item_rad", { "un", 1, item_rad_eval } }, { "melee_damage", { "un", 1, melee_damage_eval } }, + { "mod_load_order", { "g", 1, mod_order_eval } }, { "monsters_nearby", { "ung", -1, monsters_nearby_eval } }, { "mon_species_nearby", { "ung", -1, monster_species_nearby_eval } }, { "mon_groups_nearby", { "ung", -1, monster_groups_nearby_eval } },