From fa601c1efe32cfa049cc6f7dd3e4a6f718d3e8be Mon Sep 17 00:00:00 2001 From: b3brodie Date: Sat, 23 Nov 2024 21:31:42 -0800 Subject: [PATCH 01/48] Initial Commit: 1 Time power per class + related infrastructure --- data/json/flags.json | 14 +++ data/json/mutations/mutations.json | 1 + data/mods/Xedra_Evolved/effects/effects.json | 21 +++++ data/mods/Xedra_Evolved/eocs/dreamsmith.json | 3 +- data/mods/Xedra_Evolved/eocs/inventor.json | 2 +- .../eocs/spell_learning_eoc.json | 6 +- data/mods/Xedra_Evolved/field_type.json | 20 ++++ data/mods/Xedra_Evolved/flags.json | 5 + .../itemgroups/spell_artifacts/dreamer.json | 1 + .../itemgroups/spell_artifacts/eater.json | 3 +- .../Xedra_Evolved/items/inventor/misc.json | 33 +++++++ .../spell_learning_items_dreamer.json | 15 +++ .../spell_learning_items_eater.json | 15 +++ data/mods/Xedra_Evolved/items/tools.json | 21 +++++ .../mods/Xedra_Evolved/mutations/classes.json | 9 +- .../Xedra_Evolved/recipes/inventor/misc.json | 32 +++++++ .../Xedra_Evolved/spells/dreamer_spells.json | 36 ++++++++ .../Xedra_Evolved/spells/eater_spells.json | 26 ++++++ .../Xedra_Evolved/spells/item_spells.json | 91 +++++++++++++++++++ data/mods/Xedra_Evolved/traps.json | 17 ++++ doc/JSON_FLAGS.md | 3 + doc/JSON_INFO.md | 1 + src/avatar_action.cpp | 15 ++- src/character.cpp | 16 ++-- src/creature.cpp | 15 ++- src/creature.h | 3 + src/do_turn.cpp | 4 +- src/field.cpp | 19 +++- src/field.h | 3 + src/field_type.cpp | 1 + src/field_type.h | 1 + src/game.cpp | 11 ++- src/handle_action.cpp | 11 +++ src/magic.cpp | 4 + src/magic_spell_effect.cpp | 63 +++++++------ src/map.cpp | 70 ++++++++++++-- src/map.h | 20 +++- src/mattack_actors.cpp | 3 +- src/melee.cpp | 11 ++- src/monattack.cpp | 4 +- src/monmove.cpp | 16 ++-- src/monster.cpp | 14 +-- src/vehicle_move.cpp | 11 ++- 43 files changed, 607 insertions(+), 83 deletions(-) diff --git a/data/json/flags.json b/data/json/flags.json index d726d60ed2f83..d58d823019444 100644 --- a/data/json/flags.json +++ b/data/json/flags.json @@ -2613,5 +2613,19 @@ "id": "CRAFT_IN_DARKNESS", "type": "json_flag", "info": "You can craft at 100% speed in any level of light." + }, + { + "id": "CANNOT_ATTACK", + "type": "json_flag", + "//": "Creatures and players with this flag cannot attack (includes any spellcasting)." + }, + { + "id": "CANNOT_MOVE", + "type": "json_flag", + "//": "Creatures and players with this flag cannot naturally move." + }, + { + "id": "CANNOT_TAKE_DAMAGE", + "type": "json_flag" } ] diff --git a/data/json/mutations/mutations.json b/data/json/mutations/mutations.json index d74d0e0d32c34..ce70a665d6ef4 100644 --- a/data/json/mutations/mutations.json +++ b/data/json/mutations/mutations.json @@ -9674,6 +9674,7 @@ "points": 99, "valid": false, "description": "Bug-repellent forcefield.", + "flags": [ "CANNOT_TAKE_DAMAGE" ], "debug": true }, { diff --git a/data/mods/Xedra_Evolved/effects/effects.json b/data/mods/Xedra_Evolved/effects/effects.json index 1b16b2857d297..2d0abfc2c22ac 100644 --- a/data/mods/Xedra_Evolved/effects/effects.json +++ b/data/mods/Xedra_Evolved/effects/effects.json @@ -2692,5 +2692,26 @@ "values": [ { "value": "PHASE_DISTANCE", "add": 1 } ] } ] + }, + { + "type": "effect_type", + "id": "effect_xedra_time_freeze", + "name": [ "Frozen in Time" ], + "desc": [ "You are completely frozen in time." ], + "remove_message": "Everything is suddenly different.", + "rating": "neutral", + "immune_flags": [ "DIMENSIONAL_ANCHOR", "STABILIZED_TIMELINE" ], + "flags": [ "CANNOT_ATTACK", "CANNOT_MOVE", "CANNOT_TAKE_DAMAGE" ], + "show_in_info": true + }, + { + "type": "effect_type", + "id": "effect_xedra_eater_stabilize_reality", + "name": [ "Stabilized Reality" ], + "desc": [ "You are anchored in normal reality." ], + "remove_message": "You feel much more vulnerable.", + "rating": "good", + "flags": [ "DIMENSIONAL_ANCHOR", "STABILIZED_TIMELINE" ], + "show_in_info": true } ] diff --git a/data/mods/Xedra_Evolved/eocs/dreamsmith.json b/data/mods/Xedra_Evolved/eocs/dreamsmith.json index f9ca6c06fcf28..ebeb9ab8f4285 100644 --- a/data/mods/Xedra_Evolved/eocs/dreamsmith.json +++ b/data/mods/Xedra_Evolved/eocs/dreamsmith.json @@ -139,7 +139,8 @@ "dreamforged_tsurugi_speed", "dreamforged_q_staff_exp", "dreamforged_armguard_plate_gunslinger", - "dreamforged_bed_of_restful_repose" + "dreamforged_bed_of_restful_repose", + "xedra_dreamsmith_time_trap" ], "type": "recipe", "true_eocs": { diff --git a/data/mods/Xedra_Evolved/eocs/inventor.json b/data/mods/Xedra_Evolved/eocs/inventor.json index 9e6370342b2d5..2fc29b3fa730c 100644 --- a/data/mods/Xedra_Evolved/eocs/inventor.json +++ b/data/mods/Xedra_Evolved/eocs/inventor.json @@ -346,7 +346,7 @@ { "math": [ "dimension_difficulty_1", "+=", "5" ] }, { "run_eocs": "EOC_INVENTOR_PROCESS_SPARKS" }, { - "u_roll_remainder": [ "rip_ticket", "inventor_warp_grenade", "inventor_portal_closer", "teleporter_inventor" ], + "u_roll_remainder": [ "rip_ticket", "inventor_warp_grenade", "inventor_portal_closer", "teleporter_inventor", "xedra_inventor_time_pierce_tool" ], "type": "recipe", "true_eocs": [ "EOC_INVENTOR_MESSAGE_GOOD" ], "false_eocs": { diff --git a/data/mods/Xedra_Evolved/eocs/spell_learning_eoc.json b/data/mods/Xedra_Evolved/eocs/spell_learning_eoc.json index ea70bcba687d5..a5732177e5a77 100644 --- a/data/mods/Xedra_Evolved/eocs/spell_learning_eoc.json +++ b/data/mods/Xedra_Evolved/eocs/spell_learning_eoc.json @@ -97,7 +97,8 @@ "spell_speed_wonder", "spell_weak", "spell_unbreakable", - "point_blank" + "point_blank", + "xedra_eater_stabilize_reality" ], "target_var": { "var_val": "random_eater_spell" } } @@ -139,7 +140,8 @@ "spell_ethereal_wings", "spell_karma_arms", "spell_stalker_eyes", - "spell_devil_tail" + "spell_devil_tail", + "xedra_dreamer_time_bubble" ], "target_var": { "var_val": "random_dreamer_spell" } } diff --git a/data/mods/Xedra_Evolved/field_type.json b/data/mods/Xedra_Evolved/field_type.json index 375b64870e88c..f122a7cc2d1c7 100644 --- a/data/mods/Xedra_Evolved/field_type.json +++ b/data/mods/Xedra_Evolved/field_type.json @@ -253,5 +253,25 @@ "display_items": false, "display_field": true, "looks_like": "fd_smoke" + }, + { + "id": "fd_frozen_time", + "type": "field_type", + "intensity_levels": [ + { "name": "frozen time", "sym": "#", "color": "light_gray", "transparent": true, "move_cost": -1000 } + ], + "priority": 100, + "display_items": true, + "display_field": true, + "description_affix": "in", + "half_life": "1 seconds", + "linear_half_life": true, + "bash": { + "str_min": 10000, + "sound_vol": 0, + "sound_fail_vol": 0, + "msg_success": "Your strength is stronger than time itself!" + }, + "immunity_data": { "flags": [ "STABILIZED_TIMELINE" ] } } ] diff --git a/data/mods/Xedra_Evolved/flags.json b/data/mods/Xedra_Evolved/flags.json index 930e37b2c6709..ea8c7d3e5f519 100644 --- a/data/mods/Xedra_Evolved/flags.json +++ b/data/mods/Xedra_Evolved/flags.json @@ -47,5 +47,10 @@ { "id": "EVIL_EYE_IMMUNE_MONSTER", "type": "monster_flag" + }, + { + "id": "STABILIZED_TIMELINE", + "type": "json_flag", + "info": "You are immune to adverse affects on your timeline." } ] diff --git a/data/mods/Xedra_Evolved/itemgroups/spell_artifacts/dreamer.json b/data/mods/Xedra_Evolved/itemgroups/spell_artifacts/dreamer.json index 93af838c15a6e..0a00a4bf9d837 100644 --- a/data/mods/Xedra_Evolved/itemgroups/spell_artifacts/dreamer.json +++ b/data/mods/Xedra_Evolved/itemgroups/spell_artifacts/dreamer.json @@ -116,6 +116,7 @@ "subtype": "distribution", "entries": [ { "item": "mirror_artifact", "prob": 50 }, + { "item": "artifact_amber", "prob": 50 }, { "item": "artifact_sapient_light", "prob": 50 }, { "item": "artifact_bubble", "prob": 50 }, { "item": "artifact_ophanim", "prob": 50 }, diff --git a/data/mods/Xedra_Evolved/itemgroups/spell_artifacts/eater.json b/data/mods/Xedra_Evolved/itemgroups/spell_artifacts/eater.json index 898fe12bef3f4..9c376267df0e6 100644 --- a/data/mods/Xedra_Evolved/itemgroups/spell_artifacts/eater.json +++ b/data/mods/Xedra_Evolved/itemgroups/spell_artifacts/eater.json @@ -120,7 +120,8 @@ { "item": "artifact_skull", "prob": 100 }, { "item": "artifact_eye_left", "prob": 50 }, { "item": "eater_book_artifact", "prob": 50 }, - { "item": "artifact_muscle", "prob": 50 } + { "item": "artifact_muscle", "prob": 50 }, + { "item": "artifact_anchor", "prob": 50 } ] }, { diff --git a/data/mods/Xedra_Evolved/items/inventor/misc.json b/data/mods/Xedra_Evolved/items/inventor/misc.json index 1c8f25b45468a..53663f6e3e981 100644 --- a/data/mods/Xedra_Evolved/items/inventor/misc.json +++ b/data/mods/Xedra_Evolved/items/inventor/misc.json @@ -152,5 +152,38 @@ ], "use_action": [ { "type": "cast_spell", "spell_id": "inventor_portal_closer_spell", "no_fail": true, "level": 0 } ], "flags": [ "ELECTRONIC", "INVENTOR_CRAFTED" ] + }, + { + "id": "xedra_inventor_time_pierce_tool", + "type": "TOOL", + "name": { "str": "Time Piercing Device" }, + "description": "A small remote with a sharp spike at the end. You can activate this device while poking it into a zone of frozen time in order to unfreeze the area you're touching.", + "looks_like": "spike", + "weight": "300 g", + "volume": "400 ml", + "longest_side": "30 cm", + "material": [ "aluminum", "steel" ], + "symbol": ";", + "color": "white", + "flags": [ "ELECTRONIC", "INVENTOR_CRAFTED" ], + "ammo": [ "battery" ], + "charges_per_use": 150, + "use_action": { + "type": "cast_spell", + "spell_id": "xedra_inventor_time_pierce", + "no_fail": true, + "level": 1, + "need_wielding": true, + "mundane": true + }, + "pocket_data": [ + { + "pocket_type": "MAGAZINE_WELL", + "rigid": true, + "flag_restriction": [ "BATTERY_LIGHT", "BATTERY_MEDIUM" ], + "default_magazine": "medium_battery_cell" + } + ], + "melee_damage": { "stab": 10 } } ] diff --git a/data/mods/Xedra_Evolved/items/spell_learning_items/spell_learning_items_dreamer.json b/data/mods/Xedra_Evolved/items/spell_learning_items/spell_learning_items_dreamer.json index aa42daeca3c8c..09c4a3c25d894 100644 --- a/data/mods/Xedra_Evolved/items/spell_learning_items/spell_learning_items_dreamer.json +++ b/data/mods/Xedra_Evolved/items/spell_learning_items/spell_learning_items_dreamer.json @@ -167,6 +167,21 @@ "color": "white", "use_action": { "type": "learn_spell", "spells": [ "summon_duplicator" ] } }, + { + "id": "artifact_amber", + "type": "GENERIC", + "category": "artifacts", + "name": { "str": "shard of amber" }, + "description": "A small shard of amber. Looking carefully, you think you see some manner of creature trapped within.", + "weight": "1 g", + "volume": "150 ml", + "price": "20 USD", + "price_postapoc": "10 cent", + "material": [ "forged_dreamstuff" ], + "symbol": "0", + "color": "red", + "use_action": { "type": "learn_spell", "spells": [ "xedra_dreamer_time_bubble" ] } + }, { "id": "dreamer_coin_artifact", "repairs_like": "backpack", diff --git a/data/mods/Xedra_Evolved/items/spell_learning_items/spell_learning_items_eater.json b/data/mods/Xedra_Evolved/items/spell_learning_items/spell_learning_items_eater.json index 419c3f535f385..3add8a36a9347 100644 --- a/data/mods/Xedra_Evolved/items/spell_learning_items/spell_learning_items_eater.json +++ b/data/mods/Xedra_Evolved/items/spell_learning_items/spell_learning_items_eater.json @@ -307,5 +307,20 @@ "symbol": "0", "color": "dark_gray", "use_action": { "type": "learn_spell", "spells": [ "point_blank" ] } + }, + { + "id": "artifact_anchor", + "type": "GENERIC", + "category": "artifacts", + "name": { "str": "anchor" }, + "description": "A miniature anchor with an earthly sheen. You feel more stable looking at it.", + "weight": "560 g", + "volume": "280 ml", + "price": "10 USD", + "price_postapoc": "10 cent", + "material": [ "forged_dreamstuff" ], + "symbol": "0", + "color": "dark_gray", + "use_action": { "type": "learn_spell", "spells": [ "xedra_eater_stabilize_reality" ] } } ] diff --git a/data/mods/Xedra_Evolved/items/tools.json b/data/mods/Xedra_Evolved/items/tools.json index 9524b12eef097..907c989b48047 100644 --- a/data/mods/Xedra_Evolved/items/tools.json +++ b/data/mods/Xedra_Evolved/items/tools.json @@ -151,6 +151,27 @@ "symbol": ";", "color": "light_gray" }, + { + "id": "xedra_dreamsmith_time_trap", + "type": "TOOL", + "name": { "str": "dreamforged time trap" }, + "copy-from": "beartrap", + "description": "A dreamdross mesh that condenses within the center. Use it to set it on the ground, creating a trap that will freeze anything that steps on it for several hours.", + "proportional": { "weight": 0.5 }, + "price": "1000 USD", + "price_postapoc": "20 USD", + "material": [ "forged_dreamstuff" ], + "symbol": ";", + "color": "light_gray", + "use_action": { + "type": "place_trap", + "trap": "tr_xedra_dreamsmith_time_trap", + "moves": 200, + "practice": 4, + "done_message": "You set the time trap on the ground." + }, + "flags": [ "SINGLE_USE" ] + }, { "id": "dreamforged_ax", "type": "TOOL", diff --git a/data/mods/Xedra_Evolved/mutations/classes.json b/data/mods/Xedra_Evolved/mutations/classes.json index b0a4897f856b7..b5e4490163573 100644 --- a/data/mods/Xedra_Evolved/mutations/classes.json +++ b/data/mods/Xedra_Evolved/mutations/classes.json @@ -9,7 +9,6 @@ "purifiable": false, "valid": false, "enchantments": [ "BONUS_DREAMER" ], - "cancels": [ "EATER" ], "moncams": [ [ "mon_shifter", 100 ], [ "mon_duplicator", 100 ], @@ -31,7 +30,7 @@ "purifiable": false, "valid": false, "enchantments": [ "BONUS_EATER" ], - "cancels": [ "DREAMER" ], + "//": "removed for testing. remember to put cancels back", "spells_learned": [ [ "eat_dreamdross", 0 ] ] }, { @@ -43,8 +42,8 @@ "starting_trait": false, "purifiable": false, "valid": false, - "enchantments": [ "BONUS_DREAMSMITH" ], - "cancels": [ "INVENTOR" ] + "//": "removed for testing. remember to put cancels back", + "enchantments": [ "BONUS_DREAMSMITH" ] }, { "type": "mutation", @@ -56,7 +55,7 @@ "purifiable": false, "valid": false, "enchantments": [ "BONUS_INVENTOR" ], - "cancels": [ "DREAMSMITH" ], + "//": "removed for testing. remember to put cancels back", "vitamin_rates": [ [ "creative_spark", -64800 ] ] }, { diff --git a/data/mods/Xedra_Evolved/recipes/inventor/misc.json b/data/mods/Xedra_Evolved/recipes/inventor/misc.json index 38317b5d10196..078e70164e58e 100644 --- a/data/mods/Xedra_Evolved/recipes/inventor/misc.json +++ b/data/mods/Xedra_Evolved/recipes/inventor/misc.json @@ -270,6 +270,38 @@ "category": "CC_XEDRA", "subcategory": "CSC_XEDRA_TOOLS" }, + { + "result": "xedra_inventor_time_pierce_tool", + "id_suffix": "inventor", + "type": "recipe", + "activity_level": "NO_EXERCISE", + "time": "8 h", + "tools": [ [ [ "laptop", 200 ] ] ], + "qualities": [ { "id": "SCREW", "level": 1 }, { "id": "SAW_M", "level": 1 }, { "id": "AI_TOOL", "level": 1 } ], + "proficiencies": [ + { "proficiency": "prof_welding_basic", "time_multiplier": 3, "skill_penalty": 0 }, + { "proficiency": "prof_welding", "time_multiplier": 2, "skill_penalty": 0 } + ], + "using": [ [ "soldering_standard", 60 ], [ "welding_standard", 30 ] ], + "components": [ + [ [ "power_supply", 8 ] ], + [ [ "teleporter", 1 ] ], + [ [ "spike", 1 ] ], + [ [ "magnetron", 4 ] ], + [ [ "scrap", 20 ] ], + [ [ "cable", 80 ] ], + [ [ "scrap_aluminum", 10 ] ], + [ [ "processor", 1 ] ], + [ [ "lens_small", 4 ] ], + [ [ "amplifier", 1 ] ] + ], + "skill_used": "deduction", + "difficulty": 10, + "skills_required": [ [ "electronics", 6 ], [ "computer", 4 ] ], + "flags": [ "SECRET" ], + "category": "CC_XEDRA", + "subcategory": "CSC_XEDRA_TOOLS" + }, { "result": "inventor_portal_closer", "type": "recipe", diff --git a/data/mods/Xedra_Evolved/spells/dreamer_spells.json b/data/mods/Xedra_Evolved/spells/dreamer_spells.json index 59ca2e2e893ac..5618eea8ad759 100644 --- a/data/mods/Xedra_Evolved/spells/dreamer_spells.json +++ b/data/mods/Xedra_Evolved/spells/dreamer_spells.json @@ -441,6 +441,42 @@ "max_duration": { "math": [ "spell_time(time(' 3 h'))" ] }, "duration_increment": { "math": [ "spell_time(time(' 6 m'))" ] } }, + { + "id": "xedra_dreamer_time_bubble", + "type": "SPELL", + "name": "Summon Time Bubble", + "description": "Summon an impenetrable bubble of frozen time at your chosen location, freezing everything within.", + "message": "You create a bubble of frozen time!", + "teachable": false, + "valid_targets": [ "self", "ally", "ground", "hostile" ], + "skill": "deduction", + "flags": [ "SILENT", "NO_EXPLOSION_SFX", "IGNORE_WALLS" ], + "effect": "attack", + "effect_str": "effect_xedra_time_freeze", + "shape": "blast", + "min_aoe": 0, + "max_aoe": 3, + "aoe_increment": 0.15, + "field_id": "fd_frozen_time", + "field_chance": 1, + "min_field_intensity": 10, + "max_field_intensity": 10, + "min_range": 5, + "max_range": 20, + "range_increment": 0.75, + "max_level": { "math": [ "dreamer_level(1)" ] }, + "difficulty": 10, + "spell_class": "DREAMER", + "min_duration": { "math": [ "u_spell_level('xedra_dreamer_time_bubble')*60000" ] }, + "max_duration": { "math": [ "u_spell_level('xedra_dreamer_time_bubble')*60000" ] }, + "base_casting_time": 200, + "final_casting_time": 100, + "casting_time_increment": -5, + "energy_source": "MANA", + "base_energy_cost": 800, + "final_energy_cost": 200, + "energy_increment": -30 + }, { "id": "teleport_coin", "type": "SPELL", diff --git a/data/mods/Xedra_Evolved/spells/eater_spells.json b/data/mods/Xedra_Evolved/spells/eater_spells.json index 186dad2f43d5c..ab8be17f1c4df 100644 --- a/data/mods/Xedra_Evolved/spells/eater_spells.json +++ b/data/mods/Xedra_Evolved/spells/eater_spells.json @@ -535,6 +535,32 @@ "max_duration": { "math": [ "spell_time(time(' 2 h'))" ] }, "duration_increment": { "math": [ "spell_time(time(' 2 m'))" ] } }, + { + "id": "xedra_eater_stabilize_reality", + "type": "SPELL", + "name": "Stabilize in Reality", + "description": "Prevent hostile adjustments to your personal reality and timeline.", + "teachable": false, + "valid_targets": [ "self" ], + "effect": "attack", + "effect_str": "effect_xedra_eater_stabilize_reality", + "shape": "blast", + "flags": [ "NO_LEGS", "NO_HANDS", "SILENT", "NO_EXPLOSION_SFX" ], + "skill": "deduction", + "spell_class": "EATER", + "energy_source": "MANA", + "difficulty": 8, + "base_casting_time": 300, + "final_casting_time": 50, + "casting_time_increment": -9, + "base_energy_cost": 1000, + "final_energy_cost": 500, + "energy_increment": -14, + "max_level": { "math": [ "eater_level(1)" ] }, + "min_duration": { "math": [ "spell_time(time(' 10 m'))" ] }, + "max_duration": { "math": [ "spell_time(time(' 3 h'))" ] }, + "duration_increment": { "math": [ "spell_time(time(' 6 m'))" ] } + }, { "id": "point_blank", "type": "SPELL", diff --git a/data/mods/Xedra_Evolved/spells/item_spells.json b/data/mods/Xedra_Evolved/spells/item_spells.json index 10da408028423..05c6db5422cef 100644 --- a/data/mods/Xedra_Evolved/spells/item_spells.json +++ b/data/mods/Xedra_Evolved/spells/item_spells.json @@ -496,5 +496,96 @@ "id": "inventor_portal_closer_spell_furn_transform", "field": [ { "result": [ "fd_null" ], "valid_field": [ "fd_fatigue" ], "message": "The tear in reality smoothes out." } ], "trap": [ { "result": [ "tr_glass" ], "valid_trap": [ "tr_portal" ], "message": "The portal shatters into shards of glass!" } ] + }, + { + "id": "xedra_inventor_time_pierce", + "type": "SPELL", + "name": "Inventor Time Pierce", + "description": "Used by a time piercer to fix frozen time areas. Having this spell is a bug.", + "teachable": false, + "valid_targets": [ "self", "ally", "ground", "hostile" ], + "flags": [ "SILENT", "NO_LEGS", "NO_EXPLOSION_SFX", "NON_MAGICAL", "NO_FAIL" ], + "difficulty": 0, + "max_level": 1, + "effect": "ter_transform", + "effect_str": "xedra_inventor_time_pierce_furn_transform", + "extra_effects": [ { "id": "xedra_inventor_time_pierce_creature" } ], + "shape": "blast", + "min_range": 1, + "max_range": 1, + "energy_source": "NONE", + "base_energy_cost": 0, + "final_energy_cost": 0, + "energy_increment": 0, + "base_casting_time": 100 + }, + { + "id": "xedra_inventor_time_pierce_creature", + "type": "SPELL", + "name": "Inventor Time Pierce - Creature", + "description": "Used by a time piercer to fix time frozen creaures. Having this spell is a bug.", + "teachable": false, + "valid_targets": [ "self", "ally", "hostile" ], + "flags": [ "SILENT", "NO_LEGS", "NO_EXPLOSION_SFX", "NON_MAGICAL", "NO_FAIL" ], + "difficulty": 0, + "max_level": 1, + "effect": "remove_effect", + "effect_str": "effect_xedra_time_freeze", + "shape": "blast", + "min_range": 1, + "max_range": 1, + "energy_source": "NONE", + "base_energy_cost": 0, + "final_energy_cost": 0, + "energy_increment": 0, + "base_casting_time": 100 + }, + { + "type": "ter_furn_transform", + "id": "xedra_inventor_time_pierce_furn_transform", + "field": [ { "result": [ "fd_null" ], "valid_field": [ "fd_frozen_time" ], "message": "You unfreeze a zone of frozen time." } ] + }, + { + "id": "xedra_dreamsmith_time_trap_freeze", + "type": "SPELL", + "name": "Time Freeze", + "description": "Freezes the target in time. Having this spell is a bug.", + "teachable": false, + "valid_targets": [ "hostile", "ground", "ally" ], + "skill": "deduction", + "flags": [ "NO_FAIL", "SILENT", "NO_EXPLOSION_SFX", "NO_PROJECTILE" ], + "difficulty": 0, + "max_level": 1, + "effect": "attack", + "effect_str": "effect_xedra_time_freeze", + "extra_effects": [ { "id": "xedra_dreamsmith_time_trap_freeze_spawn_trap" } ], + "shape": "blast", + "min_range": 1, + "max_range": 1, + "min_duration": { "math": [ "spell_time(time(' 4 h'))" ] }, + "max_duration": { "math": [ "spell_time(time(' 4 h'))" ] }, + "energy_source": "NONE", + "base_energy_cost": 0, + "base_casting_time": 0 + }, + { + "id": "xedra_dreamsmith_time_trap_freeze_spawn_trap", + "type": "SPELL", + "name": "Time Freeze - Spawn Trap", + "description": "Spawns the trap after it is used. Having this spell is a bug.", + "teachable": false, + "valid_targets": [ "ground" ], + "skill": "deduction", + "flags": [ "NO_FAIL", "SILENT", "NO_EXPLOSION_SFX", "NO_PROJECTILE", "PERMANENT_ALL_LEVELS" ], + "difficulty": 0, + "max_level": 1, + "effect": "spawn_item", + "effect_str": "xedra_dreamsmith_time_trap", + "shape": "blast", + "min_range": 1, + "max_range": 1, + "energy_source": "NONE", + "base_energy_cost": 0, + "base_casting_time": 0 } ] diff --git a/data/mods/Xedra_Evolved/traps.json b/data/mods/Xedra_Evolved/traps.json index 7d516a76eec0e..7f0a8de9eced0 100644 --- a/data/mods/Xedra_Evolved/traps.json +++ b/data/mods/Xedra_Evolved/traps.json @@ -16,6 +16,23 @@ "flags": [ "UNDODGEABLE" ], "spell_data": { "id": "salamander_explosion_trap_spell_activated" } }, + { + "type": "trap", + "id": "tr_xedra_dreamsmith_time_trap", + "name": "time cage", + "color": "light_gray", + "symbol": "#", + "visibility": 2, + "avoidance": 10, + "difficulty": 5, + "trap_radius": 0, + "drops": [ "xedra_dreamsmith_time_trap" ], + "flags": [ "UNDODGEABLE" ], + "trigger_message_u": "You are frozen in time!", + "trigger_message_npc": " is frozen in time!", + "action": "spell", + "spell_data": { "id": "xedra_dreamsmith_time_trap_freeze" } + }, { "type": "trap", "id": "tr_species_snare", diff --git a/doc/JSON_FLAGS.md b/doc/JSON_FLAGS.md index 65069e0f801b9..33e94c334922d 100644 --- a/doc/JSON_FLAGS.md +++ b/doc/JSON_FLAGS.md @@ -346,6 +346,9 @@ Character flags can be `trait_id`, `json_flag_id` or `flag_id`. Some of these a - ```BLIND``` Makes you blind. - ```BULLET_IMMUNE``` You are immune to bullet damage. - ```CANNIBAL``` Butcher humans, eat foods with the `CANNIBALISM` and `STRICT_HUMANITARIANISM` flags without a morale penalty. +- ```CANNOT_ATTACK``` A creature with this flag cannot attack (includes spellcasting). +- ```CANNOT_MOVE``` A creature with this flag cannot move. +- ```CANNOT_TAKE_DAMAGE``` A creature with this flag cannot take any damage. - ```CBQ_LEARN_BONUS``` You learn CBQ from the bionic bio_cqb faster. - ```CHANGING```This flag is silently given to player to detect it can mutate. - ```CLAIRVOYANCE_PLUS``` Gives a clairvoyance effect, used for debug purposes. diff --git a/doc/JSON_INFO.md b/doc/JSON_INFO.md index 433763c0f2a05..11fb92878b59f 100644 --- a/doc/JSON_INFO.md +++ b/doc/JSON_INFO.md @@ -6234,6 +6234,7 @@ Fields can exist on top of terrain/furniture, and support different intensity le "decay_amount_factor": 2, // The field's rain decay amount is divided by this when processing the field, the rain decay is a function of the weather type's precipitation class: very_light = 5s, light = 15s, heavy = 45 s "half_life": "3 minutes", // If above 0 the field will disappear after two half-lifes on average "underwater_age_speedup": "25 minutes", // Increase the field's age by this time every tick if it's on a terrain with the SWIMMABLE flag + "linear_half_life": "true", // If true the half life decay is converted to a non-random, linear wait based on the defined half_life time. "outdoor_age_speedup": "20 minutes", // Increase the field's age by this duration if it's on an outdoor tile "accelerated_decay": true, // If the field should use a more simple decay calculation, used for cosmetic fields like gibs "percent_spread": 90, // The field must succeed on a `rng( 1, 100 - local windpower ) > percent_spread` roll to spread. The field must have a non-zero spread percent and the GAS phase to be eligible to spread in the first place diff --git a/src/avatar_action.cpp b/src/avatar_action.cpp index 976c6c692e99b..7791ab2605b4a 100644 --- a/src/avatar_action.cpp +++ b/src/avatar_action.cpp @@ -78,6 +78,8 @@ static const furn_str_id furn_f_safe_c( "f_safe_c" ); static const itype_id itype_swim_fins( "swim_fins" ); +static const json_character_flag json_flag_CANNOT_ATTACK( "CANNOT_ATTACK" ); +static const json_character_flag json_flag_CANNOT_MOVE( "CANNOT_MOVE" ); static const json_character_flag json_flag_ITEM_WATERPROOFING( "ITEM_WATERPROOFING" ); static const json_character_flag json_flag_WATERWALKING( "WATERWALKING" ); @@ -178,6 +180,10 @@ static bool check_water_affect_items( avatar &you ) bool avatar_action::move( avatar &you, map &m, const tripoint &d ) { + if( you.has_flag( json_flag_CANNOT_MOVE ) ) { + return false; + } + bool in_shell = you.has_active_mutation( trait_SHELL2 ) || you.has_active_mutation( trait_SHELL3 ); if( ( !g->check_safe_mode_allowed() ) || in_shell ) { @@ -394,7 +400,7 @@ bool avatar_action::move( avatar &you, map &m, const tripoint &d ) g->draw_hit_mon( dest_loc, critter, critter.is_dead() ); return false; } else if( critter.has_flag( mon_flag_IMMOBILE ) || critter.has_effect( effect_harnessed ) || - critter.has_effect( effect_ridden ) ) { + critter.has_effect( effect_ridden ) || critter.has_flag( json_flag_CANNOT_MOVE ) ) { add_msg( m_info, _( "You can't displace your %s." ), critter.name() ); return false; } @@ -675,6 +681,10 @@ static float rate_critter( const Creature &c ) void avatar_action::autoattack( avatar &you, map &m ) { + if( you.has_flag( json_flag_CANNOT_ATTACK ) ) { + add_msg( m_info, _("You are incapable of attacking!" ) ); + return; + } const item_location weapon = you.get_wielded_item(); int reach = weapon ? weapon->reach_range( you ) : 1; std::vector critters = you.get_targetable_creatures( reach, true ); @@ -951,6 +961,9 @@ void avatar_action::plthrow( avatar &you, item_location loc, } else if( you.has_effect( effect_incorporeal ) ) { add_msg( m_info, _( "You lack the substance to affect anything." ) ); return; + } else if( you.has_flag( json_flag_CANNOT_ATTACK ) ) { + add_msg( m_info, _( "You are incapable of throwing anything!" ) ); + return; } bool in_mech = false; diff --git a/src/character.cpp b/src/character.cpp index 1ffe55b71a15d..18403953fbb21 100644 --- a/src/character.cpp +++ b/src/character.cpp @@ -297,6 +297,8 @@ static const json_character_flag json_flag_ALARMCLOCK( "ALARMCLOCK" ); static const json_character_flag json_flag_ALWAYS_HEAL( "ALWAYS_HEAL" ); static const json_character_flag json_flag_BIONIC_LIMB( "BIONIC_LIMB" ); static const json_character_flag json_flag_BLIND( "BLIND" ); +static const json_character_flag json_flag_CANNOT_MOVE( "CANNOT_MOVE" ); +static const json_character_flag json_flag_CANNOT_TAKE_DAMAGE( "CANNOT_TAKE_DAMAGE" ); static const json_character_flag json_flag_CLAIRVOYANCE( "CLAIRVOYANCE" ); static const json_character_flag json_flag_CLAIRVOYANCE_PLUS( "CLAIRVOYANCE_PLUS" ); static const json_character_flag json_flag_DEAF( "DEAF" ); @@ -8131,7 +8133,7 @@ void Character::on_hit( Creature *source, bodypart_id bp_hit, void Character::apply_damage( Creature *source, bodypart_id hurt, int dam, const bool bypass_med ) { - if( is_dead_state() || has_trait( trait_DEBUG_NODMG ) || has_effect( effect_incorporeal ) ) { + if( is_dead_state() || has_effect( effect_incorporeal ) || has_flag( json_flag_CANNOT_TAKE_DAMAGE) ) { // don't do any more damage if we're already dead // Or if we're debugging and don't want to die // Or we are intangible @@ -8192,7 +8194,7 @@ void Character::apply_damage( Creature *source, bodypart_id hurt, int dam, dealt_damage_instance Character::deal_damage( Creature *source, bodypart_id bp, const damage_instance &d, const weakpoint_attack &attack ) { - if( has_trait( trait_DEBUG_NODMG ) || has_effect( effect_incorporeal ) ) { + if( has_effect( effect_incorporeal ) || has_flag( json_flag_CANNOT_TAKE_DAMAGE) ) { return dealt_damage_instance(); } @@ -8363,8 +8365,8 @@ void Character::healall( int dam ) void Character::hurtall( int dam, Creature *source, bool disturb /*= true*/ ) { - if( is_dead_state() || has_trait( trait_DEBUG_NODMG ) || has_effect( effect_incorporeal ) || - dam <= 0 ) { + if( is_dead_state() || has_effect( effect_incorporeal ) || + dam <= 0 || has_flag( json_flag_CANNOT_TAKE_DAMAGE) ) { return; } @@ -10617,7 +10619,7 @@ void Character::echo_pulse() } } // It's not moving. Must be an obstacle - if( critter->has_flag( mon_flag_IMMOBILE ) ) { + if( critter->has_flag( mon_flag_IMMOBILE ) || critter->has_effect_with_flag( json_flag_CANNOT_MOVE ) ) { echo_string = _( "click." ); } sounds::sound( origin, echo_volume, sounds::sound_t::sensory, _( echo_string ), false, @@ -12401,8 +12403,8 @@ int Character::get_lift_assist() const bool Character::immune_to( const bodypart_id &bp, damage_unit dam ) const { - if( has_trait( trait_DEBUG_NODMG ) || is_immune_damage( dam.type ) || - has_effect( effect_incorporeal ) ) { + if( is_immune_damage( dam.type ) || + has_effect( effect_incorporeal ) || has_flag( json_flag_CANNOT_TAKE_DAMAGE) ) { return true; } diff --git a/src/creature.cpp b/src/creature.cpp index 653a93c259f15..14b7e2441c27f 100644 --- a/src/creature.cpp +++ b/src/creature.cpp @@ -132,6 +132,8 @@ static const efftype_id effect_zapped( "zapped" ); static const field_type_str_id field_fd_last_known( "fd_last_known" ); +static const json_character_flag json_flag_CANNOT_MOVE( "CANNOT_MOVE" ); +static const json_character_flag json_flag_CANNOT_TAKE_DAMAGE( "CANNOT_TAKE_DAMAGE" ); static const json_character_flag json_flag_BIONIC_LIMB( "BIONIC_LIMB" ); static const json_character_flag json_flag_IGNORE_TEMP( "IGNORE_TEMP" ); static const json_character_flag json_flag_LIMB_LOWER( "LIMB_LOWER" ); @@ -446,6 +448,15 @@ bool Creature::is_dangerous_field( const field_entry &entry ) const return entry.is_dangerous() && !is_immune_field( entry.get_field_type() ); } +bool Creature::is_immune_fields( std::vector fields ) const { + for ( const field_type_id fi: fields) { + if (!is_immune_field(fi)) { + return false; + } + } + return true; +} + static bool majority_rule( const bool a_vote, const bool b_vote, const bool c_vote ) { // Helper function suggested on discord by jbtw @@ -889,7 +900,7 @@ int Creature::deal_melee_attack( Creature *source, int hitroll ) add_msg_debug( debugmode::DF_CREATURE, "Dodge roll %.1f", dodge ); - if( has_flag( mon_flag_IMMOBILE ) ) { + if( has_flag( mon_flag_IMMOBILE ) || has_effect_with_flag( json_flag_CANNOT_MOVE ) ) { // Under normal circumstances, even a clumsy person would // not miss a turret. It should, however, be possible to // miss a smaller target, especially when wielding a @@ -1353,7 +1364,7 @@ void Creature::deal_projectile_attack( Creature *source, dealt_projectile_attack dealt_damage_instance Creature::deal_damage( Creature *source, bodypart_id bp, const damage_instance &dam, const weakpoint_attack &attack ) { - if( is_dead_state() ) { + if( is_dead_state() || has_effect_with_flag( json_flag_CANNOT_TAKE_DAMAGE ) ) { return dealt_damage_instance(); } int total_damage = 0; diff --git a/src/creature.h b/src/creature.h index 11f32911ddd76..b376fe005859b 100644 --- a/src/creature.h +++ b/src/creature.h @@ -580,6 +580,9 @@ class Creature : public viewer return false; } + // Returns if the creature is immune to every given field type. + bool is_immune_fields( std::vector fields ) const; + // check if the creature is immune to the effect / field based on the immunity data virtual bool check_immunity_data( const field_immunity_data & ) const { return false; diff --git a/src/do_turn.cpp b/src/do_turn.cpp index 744ec116531b9..9f36084f57067 100644 --- a/src/do_turn.cpp +++ b/src/do_turn.cpp @@ -271,7 +271,7 @@ void monmove() for( monster &critter : g->all_monsters() ) { // Critters in impassable tiles get pushed away, unless it's not impassable for them - if( !critter.is_dead() && m.impassable( critter.pos_bub() ) && + if( !critter.is_dead() && (m.impassable( critter.pos_bub() ) && !m.get_impassable_field_at( critter.pos_bub() ).has_value() ) && !critter.can_move_to( critter.pos_bub() ) ) { dbg( D_ERROR ) << "game:monmove: " << critter.name() << " can't move to its location! (" << critter.posx() @@ -491,7 +491,7 @@ bool do_turn() u.gravity_check(); // If you're inside a wall or something and haven't been telefragged, let's get you out. - if( m.impassable( u.pos_bub() ) && !m.has_flag( ter_furn_flag::TFLAG_CLIMBABLE, u.pos_bub() ) ) { + if( (m.impassable( u.pos_bub() ) && !m.impassable_field_at( u.pos_bub() ) ) && !m.has_flag( ter_furn_flag::TFLAG_CLIMBABLE, u.pos_bub() ) ) { u.stagger(); } diff --git a/src/field.cpp b/src/field.cpp index 675f34b967965..1c3e6a66dcce1 100644 --- a/src/field.cpp +++ b/src/field.cpp @@ -80,10 +80,13 @@ time_duration field_entry::set_field_age( const time_duration &new_age ) void field_entry::initialize_decay() { - std::exponential_distribution<> d( 1.0f / ( M_LOG2E * to_turns + if( type.obj().linear_half_life ) { + decay_time = calendar::turn - age + type.obj().half_life; + } else { + std::exponential_distribution<> d( 1.0f / ( M_LOG2E * to_turns ( type.obj().half_life ) ) ); - const time_duration decay_delay = time_duration::from_turns( d( rng_get_engine() ) ); - decay_time = calendar::turn - age + decay_delay; + decay_time = calendar::turn - age + time_duration::from_turns( d( rng_get_engine() ) ); + } } void field_entry::do_decay() @@ -263,6 +266,16 @@ int field::total_move_cost() const return current_cost; } +bool field::any_negative_move_cost() const +{ + for( const auto &fld : *_field_type_list ) { + if(fld.second.get_intensity_level().move_cost < 0) { + return true; + } + } + return false; +} + std::vector field_entry::field_effects() const { return type->get_intensity_level( intensity - 1 ).field_effects; diff --git a/src/field.h b/src/field.h index f5755364384d9..cc0ad42bc6218 100644 --- a/src/field.h +++ b/src/field.h @@ -178,6 +178,9 @@ class field * Returns the total move cost from all fields. */ int total_move_cost() const; + + // Whether any individual field has a move cost below 0. + bool any_negative_move_cost() const; private: // A pointer lookup table of all field effects on the current tile. diff --git a/src/field_type.cpp b/src/field_type.cpp index ed4cb77957342..a36aac9cd0112 100644 --- a/src/field_type.cpp +++ b/src/field_type.cpp @@ -294,6 +294,7 @@ void field_type::load( const JsonObject &jo, const std::string_view ) optional( jo, was_loaded, "has_fume", has_fume, false ); optional( jo, was_loaded, "priority", priority, 0 ); optional( jo, was_loaded, "half_life", half_life, 0_turns ); + optional (jo, was_loaded, "linear_half_life", linear_half_life, false); const auto description_affix_reader = enum_flags_reader { "description affixes" }; optional( jo, was_loaded, "description_affix", desc_affix, description_affix_reader, description_affix::DESCRIPTION_AFFIX_IN ); diff --git a/src/field_type.h b/src/field_type.h index 0be98c145fa19..a5f3ba5803c36 100644 --- a/src/field_type.h +++ b/src/field_type.h @@ -222,6 +222,7 @@ struct field_type { bool display_items = true; bool display_field = false; bool legacy_make_rubble = false; + bool linear_half_life = false; field_type_str_id wandering_field; std::string looks_like; diff --git a/src/game.cpp b/src/game.cpp index 24eccd8b9ae52..54034634b721b 100644 --- a/src/game.cpp +++ b/src/game.cpp @@ -280,6 +280,7 @@ static const efftype_id effect_winded( "winded" ); static const faction_id faction_no_faction( "no_faction" ); static const faction_id faction_your_followers( "your_followers" ); +static const flag_id json_flag_CANNOT_MOVE( "CANNOT_MOVE" ); static const flag_id json_flag_CONVECTS_TEMPERATURE( "CONVECTS_TEMPERATURE" ); static const flag_id json_flag_LEVITATION( "LEVITATION" ); static const flag_id json_flag_NO_RELOAD( "NO_RELOAD" ); @@ -10630,7 +10631,9 @@ bool game::walk_move( const tripoint &dest_loc, const bool via_ramp, const bool u.grab( object_type::NONE ); } - if( m.impassable( dest_loc ) && !pushing && !shifting_furniture ) { + const std::vector impassable_field_ids = m.get_impassable_field_type_ids_at( dest_loc ); + + if( ( !m.passable_skip_fields(dest_loc) || (impassable_field_ids.size() > 0 && !u.is_immune_fields( impassable_field_ids ) ) ) && !pushing && !shifting_furniture ) { if( vp_there && u.mounted_creature && u.mounted_creature->has_flag( mon_flag_RIDEABLE_MECH ) && vp_there->vehicle().handle_potential_theft( u ) ) { tripoint diff = dest_loc - u.pos(); @@ -10697,7 +10700,7 @@ bool game::walk_move( const tripoint &dest_loc, const bool via_ramp, const bool const int mcost = m.combined_movecost( u.pos_bub(), tripoint_bub_ms( dest_loc ), grabbed_vehicle, modifier, - via_ramp ); + via_ramp, false, impassable_field_ids.size() > 0 && u.is_immune_fields( impassable_field_ids ) ); if( !furniture_move && grabbed_move( dest_loc - u.pos(), via_ramp ) ) { return true; @@ -12070,6 +12073,10 @@ static std::optional find_empty_spot_nearby( const tripoint &pos ) void game::vertical_move( int movez, bool force, bool peeking ) { + if( u.has_flag( json_flag_CANNOT_MOVE ) ) { + return; + } + if( u.is_mounted() ) { monster *mons = u.mounted_creature.get(); if( mons->has_flag( mon_flag_RIDEABLE_MECH ) ) { diff --git a/src/handle_action.cpp b/src/handle_action.cpp index 125a5277a0c3b..cfabf632590cb 100644 --- a/src/handle_action.cpp +++ b/src/handle_action.cpp @@ -139,6 +139,7 @@ static const gun_mode_id gun_mode_BURST( "BURST" ); static const itype_id fuel_type_animal( "animal" ); static const itype_id itype_radiocontrol( "radiocontrol" ); +static const json_character_flag json_flag_CANNOT_ATTACK( "CANNOT_ATTACK" ); static const json_character_flag json_flag_ALARMCLOCK( "ALARMCLOCK" ); static const json_character_flag json_flag_NO_PSIONICS( "NO_PSIONICS" ); static const json_character_flag json_flag_NO_SPELLCASTING( "NO_SPELLCASTING" ); @@ -1743,6 +1744,11 @@ static void fire() avatar &you = get_avatar(); map &here = get_map(); + if( you.has_flag( json_flag_CANNOT_ATTACK ) ) { + add_msg( m_info, _( "You are incapable of attacking!" ) ); + return; + } + if( !you.try_break_relax_gas( _( "Your willpower asserts itself, and so do you!" ), _( "You're too pacified to strike anything…" ) ) ) { return; @@ -1832,6 +1838,11 @@ static void cast_spell() player_character.magic->evaluate_opens_spellbook_data(); std::vector spells = player_character.magic->spells(); + if( player_character.has_flag( json_flag_CANNOT_ATTACK ) ) { + add_msg( game_message_params{ m_bad, gmf_bypass_cooldown }, + _( "You cannot cast spells at this moment." ) ); + return; + } if( spells.empty() ) { add_msg( game_message_params{ m_bad, gmf_bypass_cooldown }, _( "You don't know any spells to cast." ) ); diff --git a/src/magic.cpp b/src/magic.cpp index 834c415af6e35..96038ff396141 100644 --- a/src/magic.cpp +++ b/src/magic.cpp @@ -58,6 +58,7 @@ static const ammo_effect_str_id ammo_effect_MAGIC( "MAGIC" ); +static const json_character_flag json_flag_CANNOT_ATTACK( "CANNOT_ATTACK" ); static const json_character_flag json_flag_NO_PSIONICS( "NO_PSIONICS" ); static const json_character_flag json_flag_NO_SPELLCASTING( "NO_SPELLCASTING" ); static const json_character_flag json_flag_SILENT_SPELL( "SILENT_SPELL" ); @@ -1167,6 +1168,9 @@ bool spell::is_spell_class( const trait_id &mid ) const bool spell::can_cast( const Character &guy ) const { + if( guy.has_flag( json_flag_CANNOT_ATTACK ) ) { + return false; + } if( has_flag( spell_flag::NON_MAGICAL ) ) { return true; }; diff --git a/src/magic_spell_effect.cpp b/src/magic_spell_effect.cpp index a642f07c1e1c0..3a994e606d5e0 100644 --- a/src/magic_spell_effect.cpp +++ b/src/magic_spell_effect.cpp @@ -1165,13 +1165,9 @@ void spell_effect::directed_push( const spell &sp, Creature &caster, const tripo } } -void spell_effect::spawn_ethereal_item( const spell &sp, Creature &caster, const tripoint_bub_ms & ) +void spell_effect::spawn_ethereal_item( const spell &sp, Creature &caster, const tripoint_bub_ms ¢er ) { - if( !caster.is_avatar() ) { - debugmsg( "Spells that spawn items are only supported for the avatar, not for %s.", - caster.disp_name() ); - return; - } + Character *const character_at_target = get_creature_tracker().creature_at( center ); std::vector granted; @@ -1187,27 +1183,40 @@ void spell_effect::spawn_ethereal_item( const spell &sp, Creature &caster, const } avatar &player_character = get_avatar(); - for( item &it : granted ) { - // Spawned items are ethereal unless permanent and max level. Comestibles are never ethereal. - if( !it.is_comestible() && !sp.has_flag( spell_flag::PERMANENT_ALL_LEVELS ) && - !( sp.has_flag( spell_flag::PERMANENT ) && sp.is_max_level( caster ) ) ) { - it.set_var( "ethereal", to_turns( sp.duration_turns( caster ) ) ); - it.ethereal = true; - } - - if( it.ethereal && player_character.is_wearing( it.typeId() ) ) { - // Ethereal equipment already exists so just update its duration - item *existing_item = player_character.item_worn_with_id( it.typeId() ); - existing_item->set_var( "ethereal", to_turns( sp.duration_turns( caster ) ) ); - } else if( player_character.can_wear( it ).success() ) { - it.set_flag( json_flag_FIT ); - player_character.wear_item( it, false ); - } else if( !player_character.has_wield_conflicts( it ) && - !player_character.martial_arts_data->keep_hands_free && //No wield if hands free - player_character.wield( it, 0 ) ) { - // nothing to do - } else { - player_character.i_add( it ); + if (character_at_target == nullptr) { + for( item &it : granted ) { + // Spawned items are ethereal unless permanent and max level. Comestibles are never ethereal. + if( !it.is_comestible() && !sp.has_flag( spell_flag::PERMANENT_ALL_LEVELS ) && + !( sp.has_flag( spell_flag::PERMANENT ) && sp.is_max_level( caster ) ) ) { + it.set_var( "ethereal", to_turns( sp.duration_turns( caster ) ) ); + it.ethereal = true; + } + get_map().add_item_or_charges( center, it ); + } + + } else { + for( item &it : granted ) { + // Spawned items are ethereal unless permanent and max level. Comestibles are never ethereal. + if( !it.is_comestible() && !sp.has_flag( spell_flag::PERMANENT_ALL_LEVELS ) && + !( sp.has_flag( spell_flag::PERMANENT ) && sp.is_max_level( caster ) ) ) { + it.set_var( "ethereal", to_turns( sp.duration_turns( caster ) ) ); + it.ethereal = true; + } + + if( it.ethereal && player_character.is_wearing( it.typeId() ) ) { + // Ethereal equipment already exists so just update its duration + item *existing_item = player_character.item_worn_with_id( it.typeId() ); + existing_item->set_var( "ethereal", to_turns( sp.duration_turns( caster ) ) ); + } else if( player_character.can_wear( it ).success() ) { + it.set_flag( json_flag_FIT ); + player_character.wear_item( it, false ); + } else if( !player_character.has_wield_conflicts( it ) && + !player_character.martial_arts_data->keep_hands_free && //No wield if hands free + player_character.wield( it, 0 ) ) { + // nothing to do + } else { + player_character.i_add( it ); + } } } sp.make_sound( caster.pos_bub(), caster ); diff --git a/src/map.cpp b/src/map.cpp index 0e959cd647533..729ab3cded875 100644 --- a/src/map.cpp +++ b/src/map.cpp @@ -2517,12 +2517,12 @@ bool map::is_open_air( const tripoint_bub_ms &p ) const // Move cost: 3D -int map::move_cost( const tripoint &p, const vehicle *ignored_vehicle ) const +int map::move_cost( const tripoint &p, const vehicle *ignored_vehicle, const bool ignore_fields ) const { - return move_cost( tripoint_bub_ms( p ), ignored_vehicle ); + return move_cost( tripoint_bub_ms( p ), ignored_vehicle, ignore_fields ); } -int map::move_cost( const tripoint_bub_ms &p, const vehicle *ignored_vehicle ) const +int map::move_cost( const tripoint_bub_ms &p, const vehicle *ignored_vehicle, const bool ignore_fields ) const { // To save all of the bound checks and submaps fetching, we extract it // here instead of using furn(), field_at() and ter(). @@ -2535,6 +2535,8 @@ int map::move_cost( const tripoint_bub_ms &p, const vehicle *ignored_vehicle ) c return 0; } + field static nofield; + const furn_t &furniture = current_submap->get_furn( l ).obj(); const ter_t &terrain = current_submap->get_ter( l ).obj(); const field &field = current_submap->get_field( l ); @@ -2542,7 +2544,7 @@ int map::move_cost( const tripoint_bub_ms &p, const vehicle *ignored_vehicle ) c vehicle *const veh = ( !vp || &vp->vehicle() == ignored_vehicle ) ? nullptr : &vp->vehicle(); const int part = veh ? vp->part_index() : -1; - return move_cost_internal( furniture, terrain, field, veh, part ); + return move_cost_internal( furniture, terrain, (!ignore_fields ? field : nofield), veh, part ); } bool map::impassable( const tripoint &p ) const @@ -2565,6 +2567,16 @@ bool map::passable( const tripoint_bub_ms &p ) const return move_cost( p ) != 0; } +bool map::passable_skip_fields( const tripoint &p ) const +{ + return passable_skip_fields( tripoint_bub_ms( p ) ); +} + +bool map::passable_skip_fields( const tripoint_bub_ms &p ) const +{ + return move_cost( p, (const vehicle*)nullptr, true ) != 0; +} + int map::move_cost_ter_furn( const tripoint &p ) const { return map::move_cost_ter_furn( tripoint_bub_ms( p ) ); @@ -2614,11 +2626,11 @@ bool map::passable_ter_furn( const tripoint_bub_ms &p ) const int map::combined_movecost( const tripoint_bub_ms &from, const tripoint_bub_ms &to, const vehicle *ignored_vehicle, - const int modifier, const bool flying, const bool via_ramp ) const + const int modifier, const bool flying, const bool via_ramp, const bool ignore_fields ) const { static constexpr std::array mults = { 0, 50, 71, 100 }; - const int cost1 = move_cost( from, ignored_vehicle ); - const int cost2 = move_cost( to, ignored_vehicle ); + const int cost1 = move_cost( from, ignored_vehicle, ignore_fields ); + const int cost2 = move_cost( to, ignored_vehicle, ignore_fields ); // Multiply cost depending on the number of differing axes // 0 if all axes are equal, 100% if only 1 differs, 141% for 2, 200% for 3 size_t match = trigdist ? ( from.x() != to.x() ) + ( from.y() != to.y() ) + @@ -6839,6 +6851,50 @@ const field_entry *map::get_field( const tripoint_bub_ms &p, const field_type_id return get_field_helper( *this, p, type ); } +std::optional map::get_impassable_field_at( const tripoint_bub_ms &p ) +{ + std::optional potential_field; + for( auto &pr : field_at( p ) ) { + field_entry &fd = pr.second; + if( fd.get_intensity_level().move_cost < 0 ) { + return fd; + } + } + return potential_field; +} + +bool map::impassable_field_at( const tripoint &p ) +{ + return impassable_field_at( tripoint_bub_ms(p) ); +} + +bool map::impassable_field_at( const tripoint_bub_ms &p ) +{ + for( auto &pr : field_at( p ) ) { + field_entry &fd = pr.second; + if( fd.get_intensity_level().move_cost < 0 ) { + return true; + } + } + return false; +} + +std::vector map::get_impassable_field_type_ids_at( const tripoint &p ) +{ + return get_impassable_field_type_ids_at( tripoint_bub_ms(p) ); +} + +std::vector map::get_impassable_field_type_ids_at( const tripoint_bub_ms &p ) +{ + std::vector fields; + for( auto &fa : field_at( p ) ) { + if( fa.second.get_intensity_level().move_cost < 0 ) { + fields.emplace_back(fa.first); + } + } + return fields; +} + bool map::dangerous_field_at( const tripoint_bub_ms &p ) { for( auto &pr : field_at( p ) ) { diff --git a/src/map.h b/src/map.h index 53768702992b2..e6d815bf49729 100644 --- a/src/map.h +++ b/src/map.h @@ -599,10 +599,10 @@ class map * n > 0 | x*n turns to move past this */ // TODO: fix point types (remove the first overload) - int move_cost( const tripoint &p, const vehicle *ignored_vehicle = nullptr ) const; - int move_cost( const tripoint_bub_ms &p, const vehicle *ignored_vehicle = nullptr ) const; - int move_cost( const point_bub_ms &p, const vehicle *ignored_vehicle = nullptr ) const { - return move_cost( tripoint_bub_ms( p, abs_sub.z() ), ignored_vehicle ); + int move_cost( const tripoint &p, const vehicle *ignored_vehicle = nullptr, const bool ignore_fields = false ) const; + int move_cost( const tripoint_bub_ms &p, const vehicle *ignored_vehicle = nullptr, const bool ignore_fields = false ) const; + int move_cost( const point_bub_ms &p, const vehicle *ignored_vehicle = nullptr, const bool ignore_fields = false ) const { + return move_cost( tripoint_bub_ms( p, abs_sub.z() ), ignored_vehicle, ignore_fields ); } // TODO: fix point types (remove the first overload) bool impassable( const tripoint &p ) const; @@ -620,6 +620,8 @@ class map bool passable( const point_bub_ms &p ) const { return passable( tripoint_bub_ms( p, abs_sub.z() ) ); } + bool passable_skip_fields( const tripoint &p ) const; + bool passable_skip_fields( const tripoint_bub_ms &p ) const; // TODO: Get rid of untyped overload. bool is_wall_adjacent( const tripoint ¢er ) const; bool is_wall_adjacent( const tripoint_bub_ms ¢er ) const; @@ -646,7 +648,7 @@ class map */ int combined_movecost( const tripoint_bub_ms &from, const tripoint_bub_ms &to, const vehicle *ignored_vehicle = nullptr, - int modifier = 0, bool flying = false, bool via_ramp = false ) const; + int modifier = 0, bool flying = false, bool via_ramp = false, const bool ignore_fields = false ) const; /** * Returns true if a creature could walk from `from` to `to` in one step. @@ -1806,6 +1808,12 @@ class map // TODO: Get rid of untyped overload. bool has_field_at( const tripoint &p, const field_type_id &type ) const; bool has_field_at( const tripoint_bub_ms &p, const field_type_id &type ) const; + + // returns the a field entry that is impassable at the given point if it exists + std::optional get_impassable_field_at( const tripoint_bub_ms &p ); + std::vector get_impassable_field_type_ids_at( const tripoint &p ); + std::vector get_impassable_field_type_ids_at( const tripoint_bub_ms &p ); + /** * Get field of specific type at point. * @return NULL if there is no such field entry at that place. @@ -1813,6 +1821,8 @@ class map field_entry *get_field( const tripoint_bub_ms &p, const field_type_id &type ); const field_entry *get_field( const tripoint_bub_ms &p, const field_type_id &type ) const; bool dangerous_field_at( const tripoint_bub_ms &p ); + bool impassable_field_at( const tripoint &p ); + bool impassable_field_at( const tripoint_bub_ms &p ); // Check if player can move on top of it during mopping zone activity bool mopsafe_field_at( const tripoint_bub_ms &p ); diff --git a/src/mattack_actors.cpp b/src/mattack_actors.cpp index fa9450841390c..dd3b4439482e2 100644 --- a/src/mattack_actors.cpp +++ b/src/mattack_actors.cpp @@ -60,6 +60,7 @@ static const efftype_id effect_vampire_virus( "vampire_virus" ); static const efftype_id effect_was_laserlocked( "was_laserlocked" ); static const efftype_id effect_zombie_virus( "zombie_virus" ); +static const flag_id json_flag_CANNOT_MOVE( "CANNOT_MOVE" ); static const flag_id json_flag_GRAB( "GRAB" ); static const flag_id json_flag_GRAB_FILTER( "GRAB_FILTER" ); @@ -882,7 +883,7 @@ bool melee_actor::call( monster &z ) const } } } - if( throw_strength > 0 && !target->has_flag( mon_flag_IMMOBILE ) ) { + if( throw_strength > 0 && !( target->has_flag( mon_flag_IMMOBILE ) || target->has_effect_with_flag( json_flag_CANNOT_MOVE ) ) ) { if( g->fling_creature( target, coord_to_angle( z.pos(), target->pos() ), throw_strength ) ) { target->add_msg_player_or_npc( msg_type, throw_msg_u, diff --git a/src/melee.cpp b/src/melee.cpp index c4813d7f1852c..dd91ef801e248 100644 --- a/src/melee.cpp +++ b/src/melee.cpp @@ -117,6 +117,8 @@ static const itype_id itype_fur( "fur" ); static const itype_id itype_leather( "leather" ); static const itype_id itype_sheet_cotton( "sheet_cotton" ); +static const json_character_flag json_flag_CANNOT_ATTACK( "CANNOT_ATTACK" ); +static const json_character_flag json_flag_CANNOT_MOVE( "CANNOT_MOVE" ); static const json_character_flag json_flag_CBQ_LEARN_BONUS( "CBQ_LEARN_BONUS" ); static const json_character_flag json_flag_GRAB( "GRAB" ); static const json_character_flag json_flag_GRAB_FILTER( "GRAB_FILTER" ); @@ -124,6 +126,7 @@ static const json_character_flag json_flag_HARDTOHIT( "HARDTOHIT" ); static const json_character_flag json_flag_HYPEROPIC( "HYPEROPIC" ); static const json_character_flag json_flag_NULL( "NULL" ); static const json_character_flag json_flag_PSEUDOPOD_GRASP( "PSEUDOPOD_GRASP" ); + static const limb_score_id limb_score_block( "block" ); static const limb_score_id limb_score_grip( "grip" ); static const limb_score_id limb_score_reaction( "reaction" ); @@ -538,6 +541,10 @@ damage_instance Character::modify_damage_dealt_with_enchantments( const damage_i bool Character::melee_attack( Creature &t, bool allow_special, const matec_id &force_technique, bool allow_unarmed, int forced_movecost ) { + if( has_flag( json_flag_CANNOT_ATTACK ) ) { + add_msg_if_player( m_info, _("You are incapable of attacking!" ) ); + return false; + } if( has_effect( effect_incorporeal ) ) { add_msg_if_player( m_info, _( "You lack the substance to affect anything." ) ); return false; @@ -1775,7 +1782,7 @@ void Character::perform_technique( const ma_technique &technique, Creature &t, } } - if( technique.side_switch && !t.has_flag( mon_flag_IMMOBILE ) ) { + if( technique.side_switch && !(t.has_flag( mon_flag_IMMOBILE ) || t.has_effect_with_flag( json_flag_CANNOT_MOVE ) ) ) { const tripoint b = t.pos(); point new_; @@ -1801,7 +1808,7 @@ void Character::perform_technique( const ma_technique &technique, Creature &t, } } map &here = get_map(); - if( technique.knockback_dist && !t.has_flag( mon_flag_IMMOBILE ) ) { + if( technique.knockback_dist && !( t.has_flag( mon_flag_IMMOBILE ) || t.has_effect_with_flag( json_flag_CANNOT_MOVE ) ) ) { const tripoint_bub_ms prev_pos = t.pos_bub(); // track target startpoint for knockback_follow const point kb_offset( rng( -technique.knockback_spread, technique.knockback_spread ), rng( -technique.knockback_spread, technique.knockback_spread ) ); diff --git a/src/monattack.cpp b/src/monattack.cpp index 1dba3a4bbeb1c..a2fc8eebeb2c9 100644 --- a/src/monattack.cpp +++ b/src/monattack.cpp @@ -141,6 +141,8 @@ static const efftype_id effect_slimed( "slimed" ); static const efftype_id effect_social_dissatisfied( "social_dissatisfied" ); static const efftype_id effect_stunned( "stunned" ); +static const flag_id json_flag_CANNOT_MOVE( "CANNOT_MOVE" ); + static const itype_id itype_anesthetic( "anesthetic" ); static const itype_id itype_badge_deputy( "badge_deputy" ); static const itype_id itype_badge_detective( "badge_detective" ); @@ -3869,7 +3871,7 @@ bool mattack::leech_spawner( monster *z ) const bool u_see = get_player_view().sees( *z ); std::list allies; for( monster &candidate : g->all_monsters() ) { - if( candidate.in_species( species_LEECH_PLANT ) && !candidate.has_flag( mon_flag_IMMOBILE ) ) { + if( candidate.in_species( species_LEECH_PLANT ) && !(candidate.has_flag( mon_flag_IMMOBILE ) || candidate.has_flag( json_flag_CANNOT_MOVE ) ) ) { allies.push_back( &candidate ); } } diff --git a/src/monmove.cpp b/src/monmove.cpp index 227f04fe8b6db..a73f5e460ce5f 100644 --- a/src/monmove.cpp +++ b/src/monmove.cpp @@ -77,6 +77,8 @@ static const efftype_id effect_stunned( "stunned" ); static const field_type_str_id field_fd_last_known( "fd_last_known" ); +static const flag_id json_flag_CANNOT_ATTACK( "CANNOT_ATTACK" ); +static const flag_id json_flag_CANNOT_MOVE( "CANNOT_MOVE" ); static const flag_id json_flag_GRAB( "GRAB" ); static const flag_id json_flag_GRAB_FILTER( "GRAB_FILTER" ); @@ -845,6 +847,7 @@ void monster::move() // this into another monster type). Therefore we can not iterate over it // directly and instead iterate over the map from the monster type // (properties of monster types should never change). + if( !has_flag( json_flag_CANNOT_ATTACK ) ) { for( const auto &sp_type : type->special_attacks ) { const std::string &special_name = sp_type.first; const auto local_iter = special_attacks.find( special_name ); @@ -875,6 +878,7 @@ void monster::move() reset_special( special_name ); } } + } // Check if they're dragging a foe and find their hapless victim Character *dragged_foe = find_dragged_foe(); @@ -883,7 +887,7 @@ void monster::move() nursebot_operate( dragged_foe ); // The monster can sometimes hang in air due to last fall being blocked - if( !flies() && !here.has_floor_or_water( pos_bub() ) && !here.has_vehicle_floor( pos_bub() ) ) { + if( !flies() && !here.has_floor_or_water( pos_bub() ) && !here.has_vehicle_floor( pos_bub() ) && !has_flag( json_flag_CANNOT_MOVE ) ) { here.creature_on_trap( *this, false ); if( is_dead() ) { return; @@ -905,7 +909,7 @@ void monster::move() moves = 0; return; } - if( has_flag( mon_flag_IMMOBILE ) || has_flag( mon_flag_RIDEABLE_MECH ) ) { + if( has_flag( mon_flag_IMMOBILE ) || has_flag( mon_flag_RIDEABLE_MECH ) || has_flag( json_flag_CANNOT_MOVE) ) { moves = 0; return; } @@ -1198,7 +1202,7 @@ void monster::move() shove_vehicle( destination.raw(), candidate ); // Bail out if we can't move there and we can't bash. if( !pathed && !can_move_to( candidate ) ) { - if( !can_bash ) { + if( !can_bash || has_flag( json_flag_CANNOT_ATTACK ) ) { continue; } // Don't bash if we're just tracking a noise. @@ -1721,7 +1725,7 @@ int monster::group_bash_skill( const tripoint &target ) bool monster::attack_at( const tripoint &p ) { - if( has_flag( mon_flag_PACIFIST ) ) { + if( has_flag( mon_flag_PACIFIST ) || has_flag( json_flag_CANNOT_ATTACK ) ) { return false; } @@ -2042,7 +2046,7 @@ bool monster::push_to( const tripoint &p, const int boost, const size_t depth ) return false; } - if( !has_flag( mon_flag_PUSH_MON ) || depth > 2 || has_effect( effect_pushed ) ) { + if( !has_flag( mon_flag_PUSH_MON ) || depth > 2 || has_effect( effect_pushed ) || has_flag( json_flag_CANNOT_ATTACK ) ) { return false; } @@ -2313,7 +2317,7 @@ bool monster::will_reach( const point &p ) return false; } - if( ( has_flag( mon_flag_IMMOBILE ) || has_flag( mon_flag_RIDEABLE_MECH ) ) && + if( ( has_flag( mon_flag_IMMOBILE ) || has_flag( mon_flag_RIDEABLE_MECH ) || has_flag( json_flag_CANNOT_MOVE ) ) && ( pos().xy() != p ) ) { return false; } diff --git a/src/monster.cpp b/src/monster.cpp index 5afd56f73d69d..7a0c96826356a 100644 --- a/src/monster.cpp +++ b/src/monster.cpp @@ -138,6 +138,8 @@ static const efftype_id effect_worked_on( "worked_on" ); static const emit_id emit_emit_shock_cloud( "emit_shock_cloud" ); static const emit_id emit_emit_shock_cloud_big( "emit_shock_cloud_big" ); +static const flag_id json_flag_CANNOT_MOVE( "CANNOT_MOVE" ); +static const flag_id json_flag_CANNOT_TAKE_DAMAGE( "CANNOT_TAKE_DAMAGE" ); static const flag_id json_flag_DISABLE_FLIGHT( "DISABLE_FLIGHT" ); static const flag_id json_flag_GRAB( "GRAB" ); static const flag_id json_flag_GRAB_FILTER( "GRAB_FILTER" ); @@ -963,7 +965,7 @@ int monster::print_info( const catacurses::window &w, int vStart, int vLines, in const std::string speed_desc = speed_description( speed_rating(), - has_flag( mon_flag_IMMOBILE ), + has_flag( mon_flag_IMMOBILE ) || has_flag( json_flag_CANNOT_MOVE ), type->speed_desc ); vStart += fold_and_print( w, point( column, vStart ), max_width, c_white, speed_desc ); @@ -1051,7 +1053,7 @@ void monster::print_info_imgui() const const std::string speed_desc = speed_description( speed_rating(), - has_flag( mon_flag_IMMOBILE ), + has_flag( mon_flag_IMMOBILE ) || has_flag( json_flag_CANNOT_MOVE ), type->speed_desc ); cataimgui::draw_colored_text( speed_desc, c_white ); @@ -1154,7 +1156,7 @@ std::vector monster::extended_description() const const std::string speed_desc = speed_description( speed_rating(), - has_flag( mon_flag_IMMOBILE ), + has_flag( mon_flag_IMMOBILE ) || has_flag( json_flag_CANNOT_MOVE ), type->speed_desc ); tmp.emplace_back( speed_desc ); @@ -1969,7 +1971,7 @@ bool monster::is_immune_effect( const efftype_id &effect ) const return x_in_y( 3, 4 ); } else { return type->bodytype == "snake" || type->bodytype == "blob" || type->bodytype == "fish" || - has_flag( mon_flag_FLIES ) || has_flag( mon_flag_IMMOBILE ); + has_flag( mon_flag_FLIES ) || has_flag( mon_flag_IMMOBILE ) || has_flag( json_flag_CANNOT_MOVE ); } } return false; @@ -2318,7 +2320,7 @@ void monster::set_hp( const int hp ) void monster::apply_damage( Creature *source, bodypart_id /*bp*/, int dam, const bool /*bypass_med*/ ) { - if( is_dead_state() ) { + if( is_dead_state() || has_flag( json_flag_CANNOT_TAKE_DAMAGE ) ) { return; } // Ensure we can try to get at what hit us. @@ -3926,7 +3928,7 @@ void monster::set_horde_attraction( monster_horde_attraction mha ) bool monster::will_join_horde( int size ) { const monster_horde_attraction mha = get_horde_attraction(); - if( this->has_flag( mon_flag_IMMOBILE ) || this->has_flag( mon_flag_NEVER_WANDER ) ) { + if( this->has_flag( mon_flag_IMMOBILE ) || this->has_flag( mon_flag_NEVER_WANDER ) || this->has_flag( json_flag_CANNOT_MOVE ) ) { return false; //immobile monsters should never join a horde. Same with Never Wander monsters. } if( mha == MHA_NEVER ) { diff --git a/src/vehicle_move.cpp b/src/vehicle_move.cpp index 050ed84e61cd4..c303d8f920876 100644 --- a/src/vehicle_move.cpp +++ b/src/vehicle_move.cpp @@ -21,6 +21,7 @@ #include "debug.h" #include "enums.h" #include "explosion.h" +#include "field.h" #include "game.h" #include "item.h" #include "itype.h" @@ -920,7 +921,15 @@ veh_collision vehicle::part_collision( int part, const tripoint_bub_ms &p, //part density float part_dens = 0.0f; - if( is_body_collision ) { + std::optional potential_impassable_field = here.get_impassable_field_at( p ); + if( potential_impassable_field.has_value() ) { + // impassable fields are not destructible + ret.type = veh_coll_other; + mass2 = 1000; + e = 0.10f; + part_dens = 80; + ret.target_name = potential_impassable_field.value().name(); + } else if( is_body_collision ) { // Check any monster/NPC/player on the way // body ret.type = veh_coll_body; From a6c1f802506f903b2409dbbee5b9640e8b3f5287 Mon Sep 17 00:00:00 2001 From: b3brodie Date: Sun, 24 Nov 2024 00:37:52 -0800 Subject: [PATCH 02/48] Add dreamer spell to generate accelerated time fields --- data/mods/Xedra_Evolved/effects/effects.json | 19 ++++++++ data/mods/Xedra_Evolved/emit.json | 10 +++++ data/mods/Xedra_Evolved/field_type.json | 16 +++++++ .../Xedra_Evolved/spells/dreamer_spells.json | 21 +++++++++ .../mods/Xedra_Evolved/spells/spell_eocs.json | 44 +++++++++++++++++++ 5 files changed, 110 insertions(+) create mode 100644 data/mods/Xedra_Evolved/emit.json diff --git a/data/mods/Xedra_Evolved/effects/effects.json b/data/mods/Xedra_Evolved/effects/effects.json index 2d0abfc2c22ac..a77f9a6bdaf23 100644 --- a/data/mods/Xedra_Evolved/effects/effects.json +++ b/data/mods/Xedra_Evolved/effects/effects.json @@ -2713,5 +2713,24 @@ "rating": "good", "flags": [ "DIMENSIONAL_ANCHOR", "STABILIZED_TIMELINE" ], "show_in_info": true + }, + { + "type": "effect_type", + "id": "effect_xedra_dreamer_generate_accelerated_time", + "name": [ "Accelerated Time Emission" ], + "desc": [ "You continuously generate fields of shortlived accelerated time." ], + "enchantments": [ { "emitter": "xedra_dreamer_emit_accelerated_time" } ], + "rating": "good", + "show_in_info": true + }, + { + "type": "effect_type", + "id": "effect_xedra_accelerated_time", + "name": [ "Time Accelerated" ], + "desc": [ "Your local time is far accelerated to the baseline, allowing you to act much quicker." ], + "remove_message": "Everything seems much quicker.", + "rating": "good", + "show_in_info": true, + "enchantments": [ { "values": [ { "value": "SPEED", "multiply": 1 } ] } ] } ] diff --git a/data/mods/Xedra_Evolved/emit.json b/data/mods/Xedra_Evolved/emit.json new file mode 100644 index 0000000000000..a237a5867c79d --- /dev/null +++ b/data/mods/Xedra_Evolved/emit.json @@ -0,0 +1,10 @@ +[ + { + "id": "xedra_dreamer_emit_accelerated_time", + "type": "emit", + "field": "fd_xedra_accelerated_time", + "intensity": 1, + "qty": 20, + "chance": 100 + } +] \ No newline at end of file diff --git a/data/mods/Xedra_Evolved/field_type.json b/data/mods/Xedra_Evolved/field_type.json index f122a7cc2d1c7..4ac40a55a858a 100644 --- a/data/mods/Xedra_Evolved/field_type.json +++ b/data/mods/Xedra_Evolved/field_type.json @@ -273,5 +273,21 @@ "msg_success": "Your strength is stronger than time itself!" }, "immunity_data": { "flags": [ "STABILIZED_TIMELINE" ] } + }, + { + "id": "fd_xedra_accelerated_time", + "type": "field_type", + "intensity_levels": [ + { "name": "accelerated time", "sym": "o", "color": "light_gray", "transparent": true, "effects": [{ + "effect_id": "effect_xedra_accelerated_time", + "min_duration": "10 seconds", + "max_duration": "10 seconds", + "intensity": 1 + }] } + ], + "priority": 50, + "display_items": true, + "description_affix": "in", + "half_life": "2 seconds" } ] diff --git a/data/mods/Xedra_Evolved/spells/dreamer_spells.json b/data/mods/Xedra_Evolved/spells/dreamer_spells.json index 5618eea8ad759..ae85f08b65004 100644 --- a/data/mods/Xedra_Evolved/spells/dreamer_spells.json +++ b/data/mods/Xedra_Evolved/spells/dreamer_spells.json @@ -596,6 +596,27 @@ "final_casting_time": { "math": [ "spell_time(time(' 10 m'))" ] }, "spell_class": "DREAMER" }, + { + "id": "xedra_dreamer_generate_accelerated_time", + "type": "SPELL", + "name": "Generate Accelerated Time", + "description": "Continuously generate shortlived bubbles of accelerated time around you, allowing you and anything else that enters to act far quicker than normal.", + "teachable": false, + "valid_targets": [ "self" ], + "effect": "effect_on_condition", + "effect_str": "EOC_GENERATE_ACCELERATED_TIME_INITIATE", + "shape": "blast", + "flags": [ "NO_LEGS", "NO_HANDS", "SILENT", "NO_EXPLOSION_SFX", "NO_FAIL" ], + "skill": "deduction", + "spell_class": "DREAMER", + "energy_source": "MANA", + "difficulty": 8, + "base_casting_time": { "math": [ "u_effect_intensity('effect_xedra_dreamer_generate_accelerated_time') > -1 ? 0 : 1500" ] }, + "base_energy_cost": { "math": [ "u_effect_intensity('effect_xedra_dreamer_generate_accelerated_time') > -1 ? 0 : 200" ] }, + "max_level": { "math": [ "dreamer_level(1)" ] }, + "min_duration": { "math": [ "((u_spell_level('xedra_dreamer_generate_accelerated_time')+1)*750)*100" ] }, + "max_duration": { "math": [ "((u_spell_level('xedra_dreamer_generate_accelerated_time')+1)*750)*100" ] } + }, { "id": "spell_ethereal_wings", "type": "SPELL", diff --git a/data/mods/Xedra_Evolved/spells/spell_eocs.json b/data/mods/Xedra_Evolved/spells/spell_eocs.json index 2cbb81034048e..c6c6a51611462 100644 --- a/data/mods/Xedra_Evolved/spells/spell_eocs.json +++ b/data/mods/Xedra_Evolved/spells/spell_eocs.json @@ -65,6 +65,50 @@ "id": "EOC_EATER_DROSS_FUN_3", "effect": [ { "u_add_morale": "morale_ate_dross", "bonus": 100, "max_bonus": 200, "duration": "120 h", "decay_start": "60 h" } ] }, + { + "type": "effect_on_condition", + "id": "EOC_GENERATE_ACCELERATED_TIME_INITIATE", + "condition": { "not": { "u_has_effect": "effect_xedra_dreamer_generate_accelerated_time" } }, + "effect": [ + { "u_message": "Grey fields of time start seeping from your body.", "type": "good" }, + { "u_add_effect": "effect_xedra_dreamer_generate_accelerated_time", "duration": "PERMANENT" }, + { + "run_eocs": "EOC_GENERATE_ACCELERATED_TIME_CONTINUE", + "time_in_future": { "math": [ "((u_spell_level('xedra_dreamer_generate_accelerated_time')+1)*750)" ] } + } + ], + "false_effect": [ + { "u_lose_effect": "effect_xedra_dreamer_generate_accelerated_time" }, + { "u_message": "The world regains color as it speeds up.", "type": "neutral" } + ] + }, + { + "type": "effect_on_condition", + "id": "EOC_GENERATE_ACCELERATED_TIME_CONTINUE", + "condition": { "and": [ { "u_has_effect": "effect_xedra_dreamer_generate_accelerated_time" }, { "math": [ "u_val('mana') >= 200" ] } ] }, + "effect": [ + { "math": [ "u_val('mana')", "-=", "200" ] }, + { + "u_message": "The greyscale starts to receed from you vision before it quickly reverts.", + "type": "good" + }, + { + "run_eocs": "EOC_GENERATE_ACCELERATED_TIME_CONTINUE", + "time_in_future": { "math": [ "((u_spell_level('xedra_dreamer_generate_accelerated_time')+1)*750)" ] } + }, + { + "math": [ + "u_spell_exp('xedra_dreamer_generate_accelerated_time')", + "+=", + "spell_exp_diff(u_spell_level('xedra_dreamer_generate_accelerated_time'))/spell_train_factor(200)" + ] + } + ], + "false_effect": [ + { "u_lose_effect": "effect_xedra_dreamer_generate_accelerated_time" }, + { "u_message": "The world regains color as it speeds up.", "type": "neutral" } + ] + }, { "type": "effect_on_condition", "id": "EOC_ETHEREAL_WINGS_INITIATE", From 4ee98b46047d624a7fb352c42e488a4298ebc0ca Mon Sep 17 00:00:00 2001 From: b3brodie Date: Sun, 24 Nov 2024 00:38:44 -0800 Subject: [PATCH 03/48] don't show trap message to players because the effect will already do so --- data/mods/Xedra_Evolved/traps.json | 1 - 1 file changed, 1 deletion(-) diff --git a/data/mods/Xedra_Evolved/traps.json b/data/mods/Xedra_Evolved/traps.json index 7f0a8de9eced0..bab34c4a6f3a4 100644 --- a/data/mods/Xedra_Evolved/traps.json +++ b/data/mods/Xedra_Evolved/traps.json @@ -28,7 +28,6 @@ "trap_radius": 0, "drops": [ "xedra_dreamsmith_time_trap" ], "flags": [ "UNDODGEABLE" ], - "trigger_message_u": "You are frozen in time!", "trigger_message_npc": " is frozen in time!", "action": "spell", "spell_data": { "id": "xedra_dreamsmith_time_trap_freeze" } From 63198a6f50a737d4f45a4487bd80ecef8eb23fe0 Mon Sep 17 00:00:00 2001 From: b3brodie Date: Sun, 24 Nov 2024 00:49:24 -0800 Subject: [PATCH 04/48] Adjust effect durations to closely match being in bubble or not --- data/mods/Xedra_Evolved/effects/effects.json | 4 +++- data/mods/Xedra_Evolved/emit.json | 2 +- data/mods/Xedra_Evolved/field_type.json | 8 ++++---- 3 files changed, 8 insertions(+), 6 deletions(-) diff --git a/data/mods/Xedra_Evolved/effects/effects.json b/data/mods/Xedra_Evolved/effects/effects.json index a77f9a6bdaf23..ec159c60bf73e 100644 --- a/data/mods/Xedra_Evolved/effects/effects.json +++ b/data/mods/Xedra_Evolved/effects/effects.json @@ -2725,11 +2725,13 @@ }, { "type": "effect_type", - "id": "effect_xedra_accelerated_time", + "id": "effect_xedra_dreamer_accelerated_time", "name": [ "Time Accelerated" ], "desc": [ "Your local time is far accelerated to the baseline, allowing you to act much quicker." ], "remove_message": "Everything seems much quicker.", "rating": "good", + "max_intensity": 1, + "max_duration": "2 seconds", "show_in_info": true, "enchantments": [ { "values": [ { "value": "SPEED", "multiply": 1 } ] } ] } diff --git a/data/mods/Xedra_Evolved/emit.json b/data/mods/Xedra_Evolved/emit.json index a237a5867c79d..ab40c276321ca 100644 --- a/data/mods/Xedra_Evolved/emit.json +++ b/data/mods/Xedra_Evolved/emit.json @@ -2,7 +2,7 @@ { "id": "xedra_dreamer_emit_accelerated_time", "type": "emit", - "field": "fd_xedra_accelerated_time", + "field": "fd_xedra_dreamer_accelerated_time", "intensity": 1, "qty": 20, "chance": 100 diff --git a/data/mods/Xedra_Evolved/field_type.json b/data/mods/Xedra_Evolved/field_type.json index 4ac40a55a858a..c40840431d81a 100644 --- a/data/mods/Xedra_Evolved/field_type.json +++ b/data/mods/Xedra_Evolved/field_type.json @@ -275,13 +275,13 @@ "immunity_data": { "flags": [ "STABILIZED_TIMELINE" ] } }, { - "id": "fd_xedra_accelerated_time", + "id": "fd_xedra_dreamer_accelerated_time", "type": "field_type", "intensity_levels": [ { "name": "accelerated time", "sym": "o", "color": "light_gray", "transparent": true, "effects": [{ - "effect_id": "effect_xedra_accelerated_time", - "min_duration": "10 seconds", - "max_duration": "10 seconds", + "effect_id": "effect_xedra_dreamer_accelerated_time", + "min_duration": "2 seconds", + "max_duration": "2 seconds", "intensity": 1 }] } ], From 6d8cc2cc6730d3b788fd4b8c11637b5eb9357470 Mon Sep 17 00:00:00 2001 From: b3brodie Date: Sun, 24 Nov 2024 00:54:17 -0800 Subject: [PATCH 05/48] Add spell learning item for acceleration generator spell --- .../Xedra_Evolved/eocs/spell_learning_eoc.json | 3 ++- .../itemgroups/spell_artifacts/dreamer.json | 3 ++- .../spell_learning_items_dreamer.json | 15 +++++++++++++++ 3 files changed, 19 insertions(+), 2 deletions(-) diff --git a/data/mods/Xedra_Evolved/eocs/spell_learning_eoc.json b/data/mods/Xedra_Evolved/eocs/spell_learning_eoc.json index a5732177e5a77..22e33f6f09527 100644 --- a/data/mods/Xedra_Evolved/eocs/spell_learning_eoc.json +++ b/data/mods/Xedra_Evolved/eocs/spell_learning_eoc.json @@ -141,7 +141,8 @@ "spell_karma_arms", "spell_stalker_eyes", "spell_devil_tail", - "xedra_dreamer_time_bubble" + "xedra_dreamer_time_bubble", + "xedra_dreamer_generate_accelerated_time" ], "target_var": { "var_val": "random_dreamer_spell" } } diff --git a/data/mods/Xedra_Evolved/itemgroups/spell_artifacts/dreamer.json b/data/mods/Xedra_Evolved/itemgroups/spell_artifacts/dreamer.json index 0a00a4bf9d837..f686ac71ae92f 100644 --- a/data/mods/Xedra_Evolved/itemgroups/spell_artifacts/dreamer.json +++ b/data/mods/Xedra_Evolved/itemgroups/spell_artifacts/dreamer.json @@ -129,6 +129,7 @@ "type": "item_group", "id": "xe_dreamer_spell_tier4", "subtype": "distribution", - "entries": [ { "item": "artifact_karma_arms", "prob": 50 } ] + "entries": [ { "item": "artifact_karma_arms", "prob": 50 }, + { "item": "artifact_dreamer_accelerated_time", "prob": 50 } ] } ] diff --git a/data/mods/Xedra_Evolved/items/spell_learning_items/spell_learning_items_dreamer.json b/data/mods/Xedra_Evolved/items/spell_learning_items/spell_learning_items_dreamer.json index 09c4a3c25d894..da0cb31215dde 100644 --- a/data/mods/Xedra_Evolved/items/spell_learning_items/spell_learning_items_dreamer.json +++ b/data/mods/Xedra_Evolved/items/spell_learning_items/spell_learning_items_dreamer.json @@ -246,6 +246,21 @@ "color": "cyan", "use_action": { "type": "learn_spell", "spells": [ "spell_ethereal_wings" ] } }, + { + "id": "artifact_dreamer_accelerated_time", + "type": "GENERIC", + "category": "artifacts", + "name": "monochrome arrow", + "description": "You see a blocky arrow, unerringly pointed in some far off direction. It is completely colorless.", + "weight": "90 g", + "volume": "190 ml", + "price": "20 USD", + "price_postapoc": "10 cent", + "material": [ "forged_dreamstuff" ], + "symbol": "o", + "color": "cyan", + "use_action": { "type": "learn_spell", "spells": [ "xedra_dreamer_generate_accelerated_time" ] } + }, { "id": "artifact_karma_arms", "type": "GENERIC", From cdbf38de7a749fca799b39ca856d04b4e4ab621e Mon Sep 17 00:00:00 2001 From: b3brodie Date: Sun, 24 Nov 2024 01:12:43 -0800 Subject: [PATCH 06/48] Add pocketwatch for dreamsmith that stops time for 10 seconds and recipes to get it (also recipe for time trap). --- data/mods/Xedra_Evolved/eocs/dreamsmith.json | 3 ++- data/mods/Xedra_Evolved/items/tools.json | 17 +++++++++++++++++ .../Xedra_Evolved/recipes/dreamforged_tool.json | 14 ++++++++++++++ data/mods/Xedra_Evolved/spells/item_spells.json | 14 ++++++++++++++ 4 files changed, 47 insertions(+), 1 deletion(-) diff --git a/data/mods/Xedra_Evolved/eocs/dreamsmith.json b/data/mods/Xedra_Evolved/eocs/dreamsmith.json index ebeb9ab8f4285..e81e908d884b4 100644 --- a/data/mods/Xedra_Evolved/eocs/dreamsmith.json +++ b/data/mods/Xedra_Evolved/eocs/dreamsmith.json @@ -140,7 +140,8 @@ "dreamforged_q_staff_exp", "dreamforged_armguard_plate_gunslinger", "dreamforged_bed_of_restful_repose", - "xedra_dreamsmith_time_trap" + "xedra_dreamsmith_time_trap", + "xedra_dreamsmith_time_watch" ], "type": "recipe", "true_eocs": { diff --git a/data/mods/Xedra_Evolved/items/tools.json b/data/mods/Xedra_Evolved/items/tools.json index 907c989b48047..2fb64682332ca 100644 --- a/data/mods/Xedra_Evolved/items/tools.json +++ b/data/mods/Xedra_Evolved/items/tools.json @@ -172,6 +172,23 @@ }, "flags": [ "SINGLE_USE" ] }, + { + "id": "xedra_dreamsmith_time_watch", + "type": "TOOL", + "copy-from": "pocketwatch", + "name": { "str": "time shattering pocketwatch" }, + "description": "A pocketwatch made entirely of dreamdross. It somehow still accurately tells the time. Once per day, press the button on the right to briefly stop time for everything but you.", + "proportional": { "weight": 0.5 }, + "price": "1000 cent", + "price_postapoc": "100 cent", + "material": [ "forged_dreamstuff" ], + "symbol": ";", + "color": "light_gray", + "charges_per_use": 1, + "relic_data": { "charge_info": { "recharge_type": "periodic", "time": "24 h", "regenerate_ammo": true } }, + "pocket_data": [ { "pocket_type": "MAGAZINE", "ammo_restriction": { "glamour_charge": 1 }, "airtight": true } ], + "use_action": { "type": "cast_spell", "spell_id": "xedra_dreamsmith_time_stop", "no_fail": true, "level": 0 } + }, { "id": "dreamforged_ax", "type": "TOOL", diff --git a/data/mods/Xedra_Evolved/recipes/dreamforged_tool.json b/data/mods/Xedra_Evolved/recipes/dreamforged_tool.json index f5796da9b7730..8a5c8dcc678d8 100644 --- a/data/mods/Xedra_Evolved/recipes/dreamforged_tool.json +++ b/data/mods/Xedra_Evolved/recipes/dreamforged_tool.json @@ -74,5 +74,19 @@ "copy-from": "dreamforged_hacksaw", "components": [ [ [ "forged_dreamstuff_ingot", 9 ] ] ], "time": "4 h" + }, + { + "type": "recipe", + "result": "xedra_dreamsmith_time_trap", + "copy-from": "dreamforged_hacksaw", + "components": [ [ [ "forged_dreamstuff_ingot", 2 ] ] ], + "time": "4 h" + }, + { + "type": "recipe", + "result": "xedra_dreamsmith_time_watch", + "copy-from": "dreamforged_hacksaw", + "components": [ [ [ "forged_dreamstuff_ingot", 10 ] ] ], + "time": "24 h" } ] diff --git a/data/mods/Xedra_Evolved/spells/item_spells.json b/data/mods/Xedra_Evolved/spells/item_spells.json index 05c6db5422cef..df068e31330bb 100644 --- a/data/mods/Xedra_Evolved/spells/item_spells.json +++ b/data/mods/Xedra_Evolved/spells/item_spells.json @@ -61,6 +61,20 @@ "min_damage": 900, "max_damage": 900 }, + { + "id": "xedra_dreamsmith_time_stop", + "type": "SPELL", + "name": { "str": "Pocketwatch stop", "//~": "NO_I18N" }, + "description": { "str": "Stops time for 10 seconds. Having this spell is a bug.", "//~": "NO_I18N" }, + "message": "Time suddenly stops for everything but you.", + "valid_targets": [ "self" ], + "spell_class": "NONE", + "flags": [ "NO_LEGS", "SILENT", "NO_EXPLOSION_SFX" ], + "effect": "mod_moves", + "shape": "blast", + "min_damage": 1000, + "max_damage": 1000 + }, { "id": "spawn_milk_and_hazelnuts", "type": "SPELL", From 8bd104b1e6835e801d2cb283ca3bcfdcbf2b4583 Mon Sep 17 00:00:00 2001 From: b3brodie Date: Sun, 24 Nov 2024 01:19:31 -0800 Subject: [PATCH 07/48] more specific ammo type --- data/mods/Xedra_Evolved/items/ammo.json | 12 ++++++++++++ data/mods/Xedra_Evolved/items/ammo_type.json | 6 ++++++ data/mods/Xedra_Evolved/items/tools.json | 2 +- 3 files changed, 19 insertions(+), 1 deletion(-) diff --git a/data/mods/Xedra_Evolved/items/ammo.json b/data/mods/Xedra_Evolved/items/ammo.json index ceb87be1dfe04..da33ea0dd5fce 100644 --- a/data/mods/Xedra_Evolved/items/ammo.json +++ b/data/mods/Xedra_Evolved/items/ammo.json @@ -130,5 +130,17 @@ "ammo_type": "glamour_charge", "color": "magenta", "flags": [ "ZERO_WEIGHT" ] + }, + { + "id": "xedra_time_charge", + "type": "AMMO", + "name": { "str_sp": "collected time" }, + "description": "Stored time.", + "price": "10 USD", + "price_postapoc": "10 USD", + "symbol": "=", + "ammo_type": "xedra_time_charge", + "color": "light_gray", + "flags": [ "ZERO_WEIGHT" ] } ] diff --git a/data/mods/Xedra_Evolved/items/ammo_type.json b/data/mods/Xedra_Evolved/items/ammo_type.json index d6003334426a7..bf1aaf7edb334 100644 --- a/data/mods/Xedra_Evolved/items/ammo_type.json +++ b/data/mods/Xedra_Evolved/items/ammo_type.json @@ -35,6 +35,12 @@ "name": "glamour", "default": "glamour_charge" }, + { + "type": "ammunition_type", + "id": "xedra_time_charge", + "name": "collected time", + "default": "xedra_time_charge" + }, { "type": "ammunition_type", "id": "9x21mm", diff --git a/data/mods/Xedra_Evolved/items/tools.json b/data/mods/Xedra_Evolved/items/tools.json index 2fb64682332ca..eae37e210159c 100644 --- a/data/mods/Xedra_Evolved/items/tools.json +++ b/data/mods/Xedra_Evolved/items/tools.json @@ -186,7 +186,7 @@ "color": "light_gray", "charges_per_use": 1, "relic_data": { "charge_info": { "recharge_type": "periodic", "time": "24 h", "regenerate_ammo": true } }, - "pocket_data": [ { "pocket_type": "MAGAZINE", "ammo_restriction": { "glamour_charge": 1 }, "airtight": true } ], + "pocket_data": [ { "pocket_type": "MAGAZINE", "ammo_restriction": { "xedra_time_charge": 1 }, "airtight": true } ], "use_action": { "type": "cast_spell", "spell_id": "xedra_dreamsmith_time_stop", "no_fail": true, "level": 0 } }, { From 0f57e843c8454eb63fc7d7def85558165fc87df0 Mon Sep 17 00:00:00 2001 From: b3brodie Date: Sun, 24 Nov 2024 01:30:16 -0800 Subject: [PATCH 08/48] allow pocket watch to tell time --- data/mods/Xedra_Evolved/items/tools.json | 1 + 1 file changed, 1 insertion(+) diff --git a/data/mods/Xedra_Evolved/items/tools.json b/data/mods/Xedra_Evolved/items/tools.json index eae37e210159c..0c1dedd7c5895 100644 --- a/data/mods/Xedra_Evolved/items/tools.json +++ b/data/mods/Xedra_Evolved/items/tools.json @@ -182,6 +182,7 @@ "price": "1000 cent", "price_postapoc": "100 cent", "material": [ "forged_dreamstuff" ], + "flags": [ "WATCH", "ALARMCLOCK" ], "symbol": ";", "color": "light_gray", "charges_per_use": 1, From a4614078239063d6e80574934b015b75971132d4 Mon Sep 17 00:00:00 2001 From: b3brodie Date: Sun, 24 Nov 2024 13:27:58 -0800 Subject: [PATCH 09/48] fix recharge time to account for bug --- data/mods/Xedra_Evolved/items/tools.json | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/data/mods/Xedra_Evolved/items/tools.json b/data/mods/Xedra_Evolved/items/tools.json index 0c1dedd7c5895..cb70485ed05dc 100644 --- a/data/mods/Xedra_Evolved/items/tools.json +++ b/data/mods/Xedra_Evolved/items/tools.json @@ -186,7 +186,8 @@ "symbol": ";", "color": "light_gray", "charges_per_use": 1, - "relic_data": { "charge_info": { "recharge_type": "periodic", "time": "24 h", "regenerate_ammo": true } }, + "//": "Due to #48019, time to recharge is half of the listed numbers. When that is fixed, set this to 24 hours.", + "relic_data": { "charge_info": { "recharge_type": "periodic", "time": "48 h", "regenerate_ammo": true } }, "pocket_data": [ { "pocket_type": "MAGAZINE", "ammo_restriction": { "xedra_time_charge": 1 }, "airtight": true } ], "use_action": { "type": "cast_spell", "spell_id": "xedra_dreamsmith_time_stop", "no_fail": true, "level": 0 } }, From fa76c993bcf52b1712304216665eb44711ebf98c Mon Sep 17 00:00:00 2001 From: b3brodie Date: Sun, 24 Nov 2024 23:25:54 -0800 Subject: [PATCH 10/48] Add inventor injury reset device and allow eoc use actions to specify wielding or wearing --- data/mods/Xedra_Evolved/eocs/eoc_misc.json | 10 ++++ data/mods/Xedra_Evolved/eocs/inventor.json | 9 +++- data/mods/Xedra_Evolved/eocs/item_eocs.json | 11 +++++ .../Xedra_Evolved/items/inventor/armor.json | 48 +++++++++++++++++++ .../Xedra_Evolved/items/inventor/misc.json | 2 +- .../Xedra_Evolved/recipes/inventor/armor.json | 30 ++++++++++++ doc/JSON_INFO.md | 4 +- src/iuse_actor.cpp | 10 ++++ src/iuse_actor.h | 4 ++ 9 files changed, 124 insertions(+), 4 deletions(-) create mode 100644 data/mods/Xedra_Evolved/eocs/eoc_misc.json diff --git a/data/mods/Xedra_Evolved/eocs/eoc_misc.json b/data/mods/Xedra_Evolved/eocs/eoc_misc.json new file mode 100644 index 0000000000000..eeab1f2ec5e48 --- /dev/null +++ b/data/mods/Xedra_Evolved/eocs/eoc_misc.json @@ -0,0 +1,10 @@ +[ + { + "type": "effect_on_condition", + "id": "EOC_XEDRA_TRACK_LAST_HIT", + "eoc_type": "EVENT", + "required_event": "character_takes_damage", + "//": "This value is intended to be used for time magic related powers. It will get reset by their use, and should not be used for general purpose information.", + "effect": [ { "math": [ "u_xedra_last_damage_taken=_damage" ] } ] + } +] diff --git a/data/mods/Xedra_Evolved/eocs/inventor.json b/data/mods/Xedra_Evolved/eocs/inventor.json index 2fc29b3fa730c..de5a7c0708d4b 100644 --- a/data/mods/Xedra_Evolved/eocs/inventor.json +++ b/data/mods/Xedra_Evolved/eocs/inventor.json @@ -346,7 +346,14 @@ { "math": [ "dimension_difficulty_1", "+=", "5" ] }, { "run_eocs": "EOC_INVENTOR_PROCESS_SPARKS" }, { - "u_roll_remainder": [ "rip_ticket", "inventor_warp_grenade", "inventor_portal_closer", "teleporter_inventor", "xedra_inventor_time_pierce_tool" ], + "u_roll_remainder": [ + "rip_ticket", + "inventor_warp_grenade", + "inventor_portal_closer", + "teleporter_inventor", + "xedra_inventor_time_pierce_tool", + "xedra_inventor_damage_reversal_device" + ], "type": "recipe", "true_eocs": [ "EOC_INVENTOR_MESSAGE_GOOD" ], "false_eocs": { diff --git a/data/mods/Xedra_Evolved/eocs/item_eocs.json b/data/mods/Xedra_Evolved/eocs/item_eocs.json index ae55803e9044e..f1d4d7c8f484d 100644 --- a/data/mods/Xedra_Evolved/eocs/item_eocs.json +++ b/data/mods/Xedra_Evolved/eocs/item_eocs.json @@ -59,5 +59,16 @@ "type": "effect_on_condition", "id": "EOC_DAGWOOD", "effect": [ { "u_cast_spell": { "id": "cosmic_dagwood_regeneration" } } ] + }, + { + "type": "effect_on_condition", + "id": "EOC_XEDRA_INVENTOR_DAMAGE_REVERSAL", + "condition": [ { "math": [ "u_xedra_last_damage_taken>0" ] } ], + "effect": [ + { "math": [ "u_hp('ALL')+=u_xedra_last_damage_taken" ] }, + { "math": [ "u_xedra_last_damage_taken=0" ] }, + { "u_message": "Your wound heals!", "type": "good" } + ], + "false_effect": [ { "u_message": "You don't seem to have any wounds to heal.", "type": "neutral" } ] } ] diff --git a/data/mods/Xedra_Evolved/items/inventor/armor.json b/data/mods/Xedra_Evolved/items/inventor/armor.json index 26d76ee9c8d9e..13a0b2d2c9d3f 100644 --- a/data/mods/Xedra_Evolved/items/inventor/armor.json +++ b/data/mods/Xedra_Evolved/items/inventor/armor.json @@ -667,5 +667,53 @@ "use_action": { "type": "holster" }, "flags": [ "MORPHIC", "BELTED", "OVERSIZE", "MUNDANE", "INVENTOR_CRAFTED", "TARDIS" ], "armor": [ { "encumbrance": 1, "coverage": 5, "covers": [ "torso" ], "specifically_covers": [ "torso_upper" ] } ] + }, + { + "id": "xedra_inventor_damage_reversal_device", + "type": "TOOL_ARMOR", + "category": "armor", + "name": { "str": "Injury Reset Device" }, + "description": "A bulky wristwatch that attaches to your arm. Using it will revert the last injury that you have suffered. Also tells the time.", + "weight": "100 g", + "volume": "50 ml", + "looks_like": "wristwatch", + "ammo": [ "battery" ], + "material": [ "kevlar", "steel" ], + "symbol": "[", + "color": "light_gray", + "sided": true, + "charges_per_use": 150, + "use_action": { + "type": "effect_on_conditions", + "description": "Reverse your last injury.", + "effect_on_conditions": [ "EOC_XEDRA_INVENTOR_DAMAGE_REVERSAL" ], + "need_worn": true + }, + "pocket_data": [ + { + "pocket_type": "MAGAZINE_WELL", + "rigid": true, + "airtight": true, + "watertight": true, + "flag_restriction": [ "BATTERY_MEDIUM", "BATTERY_HEAVY" ], + "max_contains_volume": "20 L", + "max_contains_weight": "20 kg", + "default_magazine": "medium_battery_cell" + } + ], + "flags": [ + "MORPHIC", + "WATCH", + "ALARMCLOCK", + "BELTED", + "ALLOWS_NATURAL_ATTACKS", + "WATER_FRIENDLY", + "OVERSIZE", + "ELECTRONIC", + "INVENTOR_CRAFTED", + "STURDY", + "PADDED" + ], + "armor": [ { "coverage": 50, "covers": [ "hand_l", "hand_r" ], "specifically_covers": [ "hand_wrist_l", "hand_wrist_r" ] } ] } ] diff --git a/data/mods/Xedra_Evolved/items/inventor/misc.json b/data/mods/Xedra_Evolved/items/inventor/misc.json index 53663f6e3e981..fd0e1f45093fd 100644 --- a/data/mods/Xedra_Evolved/items/inventor/misc.json +++ b/data/mods/Xedra_Evolved/items/inventor/misc.json @@ -165,7 +165,7 @@ "material": [ "aluminum", "steel" ], "symbol": ";", "color": "white", - "flags": [ "ELECTRONIC", "INVENTOR_CRAFTED" ], + "flags": [ "ELECTRONIC", "INVENTOR_CRAFTED", "TRADER_AVOID" ], "ammo": [ "battery" ], "charges_per_use": 150, "use_action": { diff --git a/data/mods/Xedra_Evolved/recipes/inventor/armor.json b/data/mods/Xedra_Evolved/recipes/inventor/armor.json index 813c946bbd574..c215d5df7adf8 100644 --- a/data/mods/Xedra_Evolved/recipes/inventor/armor.json +++ b/data/mods/Xedra_Evolved/recipes/inventor/armor.json @@ -278,5 +278,35 @@ "flags": [ "SECRET" ], "category": "CC_XEDRA", "subcategory": "CSC_XEDRA_ARMOR" + }, + { + "type": "recipe", + "activity_level": "LIGHT_EXERCISE", + "result": "xedra_inventor_damage_reversal_device", + "tools": [ [ [ "laptop", 50 ] ] ], + "qualities": [ { "id": "SCREW", "level": 1 }, { "id": "SAW_M", "level": 1 }, { "id": "AI_TOOL", "level": 1 } ], + "using": [ [ "soldering_standard", 50 ], [ "welding_standard", 25 ] ], + "proficiencies": [ + { "proficiency": "prof_metalworking", "time_multiplier": 3, "skill_penalty": 0 }, + { "proficiency": "prof_welding_basic", "time_multiplier": 3, "skill_penalty": 0 }, + { "proficiency": "prof_welding", "time_multiplier": 2, "skill_penalty": 0 } + ], + "components": [ + [ [ "cable", 120 ] ], + [ [ "teleporter", 2 ] ], + [ [ "e_scrap", 2 ] ], + [ [ "power_supply", 4 ] ], + [ [ "magnetron", 1 ] ], + [ [ "processor", 8 ] ], + [ [ "kevlar_patch", 4 ] ], + [ [ "pocketwatch", 1 ] ] + ], + "time": "12 h", + "skill_used": "deduction", + "difficulty": 10, + "skills_required": [ [ "electronics", 8 ], [ "fabrication", 6 ], [ "computer", 8 ] ], + "flags": [ "SECRET" ], + "category": "CC_XEDRA", + "subcategory": "CSC_XEDRA_ARMOR" } ] diff --git a/doc/JSON_INFO.md b/doc/JSON_INFO.md index 11fb92878b59f..7399d96455997 100644 --- a/doc/JSON_INFO.md +++ b/doc/JSON_INFO.md @@ -4518,8 +4518,8 @@ The contents of `use_action` fields can either be a string indicating a built-in "need_charges": 1, // Number of charges the item needs to transform "need_charges_msg": "The lamp is empty.", // Message to display if there aren't enough charges "need_empty": true, // Whether the item must be empty to be transformed; false by default - "need_worn": true, // Whether the item must be worn to be transformed; false by default - "need_wielding": true, // Whether the item must be wielded to be transformed; false by default + "need_worn": true, // Whether the item must be worn to be transformed, cast spells, or use EOCs; false by default + "need_wielding": true, // Whether the item must be wielded to be transformed, cast spells, or use EOCs; false by default "qualities_needed": { "WRENCH_FINE": 1 }, // Tool qualities needed, e.g. "fine bolt turning 1" "target_charges": 3, // Number of charges the transformed item has "rand_target_charges": [ 10, 15, 25 ], // Randomize the charges the transformed item has. This example has a 50% chance of rng(10, 15) charges and a 50% chance of rng(15, 25) (endpoints are included) diff --git a/src/iuse_actor.cpp b/src/iuse_actor.cpp index 73950387bfc61..706417a64c1af 100644 --- a/src/iuse_actor.cpp +++ b/src/iuse_actor.cpp @@ -5617,6 +5617,8 @@ void effect_on_conditons_actor::load( const JsonObject &obj, const std::string & { obj.read( "description", description ); obj.read( "menu_text", menu_text ); + need_worn = obj.get_bool( "need_worn", false ); + need_wielding = obj.get_bool( "need_wielding", false ); for( JsonValue jv : obj.get_array( "effect_on_conditions" ) ) { eocs.emplace_back( effect_on_conditions::load_inline_eoc( jv, src ) ); } @@ -5638,6 +5640,14 @@ void effect_on_conditons_actor::info( const item &, std::vector &dump std::optional effect_on_conditons_actor::use( Character *p, item &it, const tripoint &point ) const { + if( need_worn && !p->is_worn( it ) ) { + p->add_msg_if_player( m_info, _( "You need to wear the %1$s before activating it." ), it.tname() ); + return std::nullopt; + } + if( need_wielding && !p->is_wielding( it ) ) { + p->add_msg_if_player( m_info, _( "You need to wield the %1$s before activating it." ), it.tname() ); + return std::nullopt; + } Character *char_ptr = nullptr; item_location loc; if( p ) { diff --git a/src/iuse_actor.h b/src/iuse_actor.h index b68b227a3beb0..688037b515fec 100644 --- a/src/iuse_actor.h +++ b/src/iuse_actor.h @@ -1177,6 +1177,10 @@ class effect_on_conditons_actor : public iuse_actor std::vector eocs; translation description; translation menu_text; + /**does the item requires to be worn to be activable*/ + bool need_worn = false; + /**does the item requires to be wielded to be activable*/ + bool need_wielding = false; explicit effect_on_conditons_actor( const std::string &type = "effect_on_conditions" ) : iuse_actor( type ) {} From fce173756a457585f788481f6eaa5e5c822ff66f Mon Sep 17 00:00:00 2001 From: b3brodie Date: Sun, 24 Nov 2024 23:30:57 -0800 Subject: [PATCH 11/48] adjust condition syntax --- data/mods/Xedra_Evolved/eocs/item_eocs.json | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/data/mods/Xedra_Evolved/eocs/item_eocs.json b/data/mods/Xedra_Evolved/eocs/item_eocs.json index f1d4d7c8f484d..2b87ac5059991 100644 --- a/data/mods/Xedra_Evolved/eocs/item_eocs.json +++ b/data/mods/Xedra_Evolved/eocs/item_eocs.json @@ -63,7 +63,7 @@ { "type": "effect_on_condition", "id": "EOC_XEDRA_INVENTOR_DAMAGE_REVERSAL", - "condition": [ { "math": [ "u_xedra_last_damage_taken>0" ] } ], + "condition": { "math": [ "u_xedra_last_damage_taken > 0" ] }, "effect": [ { "math": [ "u_hp('ALL')+=u_xedra_last_damage_taken" ] }, { "math": [ "u_xedra_last_damage_taken=0" ] }, From 02533b23e166fbde68d26e2b2f86d8df8783ae8d Mon Sep 17 00:00:00 2001 From: b3brodie Date: Mon, 25 Nov 2024 17:08:48 -0800 Subject: [PATCH 12/48] Add bodypart field to character_takes_damage and use to make damage reversal eoc bodypart specific --- data/mods/Xedra_Evolved/eocs/eoc_misc.json | 10 ---------- data/mods/Xedra_Evolved/eocs/item_eocs.json | 12 ++++++++--- data/mods/Xedra_Evolved/eocs/misc_eoc.json | 22 +++++++++++++++++++++ doc/EFFECT_ON_CONDITION.md | 2 +- src/character.cpp | 8 ++++---- src/event.h | 3 ++- tests/stats_tracker_test.cpp | 16 +++++++-------- 7 files changed, 46 insertions(+), 27 deletions(-) delete mode 100644 data/mods/Xedra_Evolved/eocs/eoc_misc.json diff --git a/data/mods/Xedra_Evolved/eocs/eoc_misc.json b/data/mods/Xedra_Evolved/eocs/eoc_misc.json deleted file mode 100644 index eeab1f2ec5e48..0000000000000 --- a/data/mods/Xedra_Evolved/eocs/eoc_misc.json +++ /dev/null @@ -1,10 +0,0 @@ -[ - { - "type": "effect_on_condition", - "id": "EOC_XEDRA_TRACK_LAST_HIT", - "eoc_type": "EVENT", - "required_event": "character_takes_damage", - "//": "This value is intended to be used for time magic related powers. It will get reset by their use, and should not be used for general purpose information.", - "effect": [ { "math": [ "u_xedra_last_damage_taken=_damage" ] } ] - } -] diff --git a/data/mods/Xedra_Evolved/eocs/item_eocs.json b/data/mods/Xedra_Evolved/eocs/item_eocs.json index 2b87ac5059991..69a1ae37cabbf 100644 --- a/data/mods/Xedra_Evolved/eocs/item_eocs.json +++ b/data/mods/Xedra_Evolved/eocs/item_eocs.json @@ -65,10 +65,16 @@ "id": "EOC_XEDRA_INVENTOR_DAMAGE_REVERSAL", "condition": { "math": [ "u_xedra_last_damage_taken > 0" ] }, "effect": [ - { "math": [ "u_hp('ALL')+=u_xedra_last_damage_taken" ] }, - { "math": [ "u_xedra_last_damage_taken=0" ] }, + { + "if": { "compare_string": [ "bp_null", "u_xedra_last_damage_taken_bodypart" ] }, + "then": [ { "math": [ "u_hp('ALL')+=u_xedra_last_damage_taken" ] }, { "math": [ "u_xedra_last_damage_taken=0" ] } ], + "else": [ + { "math": [ "u_hp(u_xedra_last_damage_taken_bodypart)+=u_xedra_last_damage_taken" ] }, + { "math": [ "u_xedra_last_damage_taken=0" ] } + ] + }, { "u_message": "Your wound heals!", "type": "good" } ], - "false_effect": [ { "u_message": "You don't seem to have any wounds to heal.", "type": "neutral" } ] + "false_effect": [ { "u_message": "You don't have a previous wound to heal.", "type": "neutral" } ] } ] diff --git a/data/mods/Xedra_Evolved/eocs/misc_eoc.json b/data/mods/Xedra_Evolved/eocs/misc_eoc.json index 1c54201b83933..433d4fdaf6c98 100644 --- a/data/mods/Xedra_Evolved/eocs/misc_eoc.json +++ b/data/mods/Xedra_Evolved/eocs/misc_eoc.json @@ -331,5 +331,27 @@ "required_event": "character_wakes_up", "condition": { "u_has_effect": "effect_sleep_shield" }, "effect": [ { "u_lose_effect": "effect_sleep_shield" }, { "u_teleport": { "u_val": "SLEEP_SHIELD_location" }, "force": true } ] + }, + { + "type": "effect_on_condition", + "id": "EOC_XEDRA_TRACK_LAST_HIT", + "eoc_type": "EVENT", + "required_event": "character_takes_damage", + "//": "This value is intended to be used for time magic related powers. It will get reset by their use, and should not be used for general purpose information.", + "effect": [ + { "math": [ "u_xedra_last_damage_taken=_damage" ] }, + { "set_string_var": { "context_val": "bodypart" }, "target_var": { "u_val": "xedra_last_damage_taken_bodypart" } }, + { "u_message": "damage taken = , bodypart = " } + ] + }, + { + "type": "effect_on_condition", + "id": "EOC_XEDRA_TRACK_LAST_HIT_EOC_AFS_MEDIGEL_ADD", + "eoc_type": "EVENT", + "required_event": "character_gains_effect", + "effect": [ + { "set_string_var": { "context_val": "bodypart" }, "target_var": { "u_val": "test_part" } }, + { "u_message": "bodypart = " } + ] } ] diff --git a/doc/EFFECT_ON_CONDITION.md b/doc/EFFECT_ON_CONDITION.md index a6db39c429c49..76ff25191c303 100644 --- a/doc/EFFECT_ON_CONDITION.md +++ b/doc/EFFECT_ON_CONDITION.md @@ -1492,7 +1492,7 @@ Every event EOC passes context vars with each of their key value pairs that the | character_ranged_attacks_monster | | { "attacker", `character_id` },
{ "weapon", `itype_id` },
{ "victim_type", `mtype_id` }, | character / monster | | character_smashes_tile | | { "character", `character_id` },
{ "terrain", `ter_str_id` }, { "furniture", `furn_str_id` }, | character / NONE | | character_starts_activity | Triggered when character starts or resumes activity | { "character", `character_id` },
{ "activity", `activity_id` },
{ "resume", `bool` } | character / NONE | -| character_takes_damage | triggers when character gets any damage from any creature | { "character", `character_id` },
{ "damage", `int` }, | character / attacker if exists, otherwise NONE(character or monster) | use `has_beta` conditon before interacting with beta talker +| character_takes_damage | triggers when character gets any damage from any creature | { "character", `character_id` },
{ "damage", `int` },
{ "bodypart", `bodypart_id` }, | character / attacker if exists, otherwise NONE(character or monster) | use `has_beta` conditon before interacting with beta talker | monster_takes_damage | triggers when monster gets any damage from any creature. Includes damages from effects like bleeding | { "damage", `int` },
{ "dies", `bool` }, | monster / attacker if exists, otherwise NONE(character or monster) | use `has_beta` conditon before interacting with beta talker | character_triggers_trap | | { "character", `character_id` },
{ "trap", `trap_str_id` }, | character / NONE | | character_wakes_up | triggers in the moment player lost it's sleep effect and wakes up | { "character", `character_id` }, | character / NONE | diff --git a/src/character.cpp b/src/character.cpp index 18403953fbb21..e94b23d5cb421 100644 --- a/src/character.cpp +++ b/src/character.cpp @@ -8155,10 +8155,10 @@ void Character::apply_damage( Creature *source, bodypart_id hurt, int dam, mod_part_hp_cur( part_to_damage, - dam_to_bodypart ); if( source ) { - cata::event e = cata::event::make( getID(), dam_to_bodypart ); + cata::event e = cata::event::make( getID(), dam_to_bodypart, part_to_damage.id() ); get_event_bus().send_with_talker( this, source, e ); } else { - get_event_bus().send( getID(), dam_to_bodypart ); + get_event_bus().send( getID(), dam_to_bodypart, part_to_damage.id() ); } if( !weapon.is_null() && !can_wield( weapon ).success() && @@ -8376,10 +8376,10 @@ void Character::hurtall( int dam, Creature *source, bool disturb /*= true*/ ) mod_part_hp_cur( bp, - dam_to_bodypart ); if( source ) { - cata::event e = cata::event::make( getID(), dam_to_bodypart ); + cata::event e = cata::event::make( getID(), dam_to_bodypart, body_part_bp_null ); get_event_bus().send_with_talker( this, source == nullptr ? nullptr : source, e ); } else { - get_event_bus().send( getID(), dam_to_bodypart ); + get_event_bus().send( getID(), dam_to_bodypart, body_part_bp_null ); } } diff --git a/src/event.h b/src/event.h index 99151808d454e..5a7c8c3d39efb 100644 --- a/src/event.h +++ b/src/event.h @@ -467,9 +467,10 @@ struct event_spec { template<> struct event_spec { - static constexpr std::array, 2> fields = {{ + static constexpr std::array, 3> fields = {{ { "character", cata_variant_type::character_id }, { "damage", cata_variant_type::int_ }, + { "bodypart", cata_variant_type::body_part } } }; }; diff --git a/tests/stats_tracker_test.cpp b/tests/stats_tracker_test.cpp index e0882aa4fb98b..e78ffead7cf17 100644 --- a/tests/stats_tracker_test.cpp +++ b/tests/stats_tracker_test.cpp @@ -114,16 +114,16 @@ TEST_CASE( "stats_tracker_total_events", "[stats]" ) CHECK( s.get_events( ctd ).total( "damage", damage_to_u ) == 0 ); CHECK( s.get_events( ctd ).total( "damage", damage_to_any ) == 0 ); - b.send( u_id, 10 ); + b.send( u_id, 10, body_part_bp_null ); CHECK( s.get_events( ctd ).total( "damage", damage_to_u ) == 10 ); CHECK( s.get_events( ctd ).total( "damage", damage_to_any ) == 10 ); - b.send( other_id, 10 ); + b.send( other_id, 10, body_part_bp_null ); CHECK( s.get_events( ctd ).total( "damage", damage_to_u ) == 10 ); CHECK( s.get_events( ctd ).total( "damage", damage_to_any ) == 20 ); - b.send( u_id, 10 ); + b.send( u_id, 10, body_part_bp_null ); CHECK( s.get_events( ctd ).total( "damage", damage_to_u ) == 20 ); CHECK( s.get_events( event_type::character_takes_damage ).total( "damage", damage_to_any ) == 30 ); - b.send( u_id, 5 ); + b.send( u_id, 5, body_part_bp_null ); CHECK( s.get_events( event_type::character_takes_damage ).total( "damage", damage_to_u ) == 25 ); CHECK( s.get_events( event_type::character_takes_damage ).total( "damage", damage_to_any ) == 35 ); } @@ -193,11 +193,11 @@ TEST_CASE( "stats_tracker_event_time_bounds", "[stats]" ) CHECK( !s.get_events( ctd ).first() ); CHECK( !s.get_events( ctd ).last() ); - b.send( u_id, 10 ); + b.send( u_id, 10, body_part_bp_null ); CHECK( s.get_events( ctd ).first()->second.first == start ); CHECK( s.get_events( ctd ).last()->second.last == calendar::turn ); calendar::turn += 1_minutes; - b.send( u_id, 10 ); + b.send( u_id, 10, body_part_bp_null ); CHECK( s.get_events( ctd ).first()->second.first == start ); CHECK( s.get_events( ctd ).last()->second.last == calendar::turn ); } @@ -337,7 +337,7 @@ TEST_CASE( "stats_tracker_with_event_statistics", "[stats]" ) SECTION( "damage" ) { const cata::event avatar_2_damage = - cata::event::make( u_id, 2 ); + cata::event::make( u_id, 2, body_part_bp_null ); send_game_start( b, u_id ); CHECK( score_score_damage_taken->value( s ).get() == 0 ); @@ -556,7 +556,7 @@ TEST_CASE( "stats_tracker_watchers", "[stats]" ) SECTION( "damage" ) { const cata::event avatar_2_damage = - cata::event::make( u_id, 2 ); + cata::event::make( u_id, 2, body_part_bp_null ); watch_stat damage_watcher; s.add_watcher( event_statistic_avatar_damage_taken, &damage_watcher ); From ed1f73673c06be19b967df3330f8ef23da63ffa2 Mon Sep 17 00:00:00 2001 From: b3brodie Date: Mon, 25 Nov 2024 17:10:46 -0800 Subject: [PATCH 13/48] get rid of test eoc --- data/mods/Xedra_Evolved/eocs/misc_eoc.json | 10 ---------- 1 file changed, 10 deletions(-) diff --git a/data/mods/Xedra_Evolved/eocs/misc_eoc.json b/data/mods/Xedra_Evolved/eocs/misc_eoc.json index 433d4fdaf6c98..2c0b0544acfa8 100644 --- a/data/mods/Xedra_Evolved/eocs/misc_eoc.json +++ b/data/mods/Xedra_Evolved/eocs/misc_eoc.json @@ -343,15 +343,5 @@ { "set_string_var": { "context_val": "bodypart" }, "target_var": { "u_val": "xedra_last_damage_taken_bodypart" } }, { "u_message": "damage taken = , bodypart = " } ] - }, - { - "type": "effect_on_condition", - "id": "EOC_XEDRA_TRACK_LAST_HIT_EOC_AFS_MEDIGEL_ADD", - "eoc_type": "EVENT", - "required_event": "character_gains_effect", - "effect": [ - { "set_string_var": { "context_val": "bodypart" }, "target_var": { "u_val": "test_part" } }, - { "u_message": "bodypart = " } - ] } ] From effcb9da05ac9895f39fbf30ed2e2edccd2d88f9 Mon Sep 17 00:00:00 2001 From: b3brodie Date: Mon, 25 Nov 2024 18:03:30 -0800 Subject: [PATCH 14/48] Make reverse damage revert pain and add pain to character takes damage event --- data/mods/Xedra_Evolved/eocs/item_eocs.json | 1 + data/mods/Xedra_Evolved/eocs/misc_eoc.json | 4 ++-- doc/EFFECT_ON_CONDITION.md | 2 +- src/character.cpp | 24 ++++++++++++--------- src/character.h | 2 +- src/creature.cpp | 3 ++- src/creature.h | 2 +- src/event.h | 5 +++-- tests/stats_tracker_test.cpp | 16 +++++++------- 9 files changed, 33 insertions(+), 26 deletions(-) diff --git a/data/mods/Xedra_Evolved/eocs/item_eocs.json b/data/mods/Xedra_Evolved/eocs/item_eocs.json index 69a1ae37cabbf..08d69ab2b368a 100644 --- a/data/mods/Xedra_Evolved/eocs/item_eocs.json +++ b/data/mods/Xedra_Evolved/eocs/item_eocs.json @@ -70,6 +70,7 @@ "then": [ { "math": [ "u_hp('ALL')+=u_xedra_last_damage_taken" ] }, { "math": [ "u_xedra_last_damage_taken=0" ] } ], "else": [ { "math": [ "u_hp(u_xedra_last_damage_taken_bodypart)+=u_xedra_last_damage_taken" ] }, + { "math": [ "u_pain()-=u_xedra_last_pain_taken" ] }, { "math": [ "u_xedra_last_damage_taken=0" ] } ] }, diff --git a/data/mods/Xedra_Evolved/eocs/misc_eoc.json b/data/mods/Xedra_Evolved/eocs/misc_eoc.json index 2c0b0544acfa8..e963936c4900f 100644 --- a/data/mods/Xedra_Evolved/eocs/misc_eoc.json +++ b/data/mods/Xedra_Evolved/eocs/misc_eoc.json @@ -340,8 +340,8 @@ "//": "This value is intended to be used for time magic related powers. It will get reset by their use, and should not be used for general purpose information.", "effect": [ { "math": [ "u_xedra_last_damage_taken=_damage" ] }, - { "set_string_var": { "context_val": "bodypart" }, "target_var": { "u_val": "xedra_last_damage_taken_bodypart" } }, - { "u_message": "damage taken = , bodypart = " } + { "math": [ "u_xedra_last_pain_taken=_pain" ] }, + { "set_string_var": { "context_val": "bodypart" }, "target_var": { "u_val": "xedra_last_damage_taken_bodypart" } } ] } ] diff --git a/doc/EFFECT_ON_CONDITION.md b/doc/EFFECT_ON_CONDITION.md index 76ff25191c303..fd1903d0bcef5 100644 --- a/doc/EFFECT_ON_CONDITION.md +++ b/doc/EFFECT_ON_CONDITION.md @@ -1492,7 +1492,7 @@ Every event EOC passes context vars with each of their key value pairs that the | character_ranged_attacks_monster | | { "attacker", `character_id` },
{ "weapon", `itype_id` },
{ "victim_type", `mtype_id` }, | character / monster | | character_smashes_tile | | { "character", `character_id` },
{ "terrain", `ter_str_id` }, { "furniture", `furn_str_id` }, | character / NONE | | character_starts_activity | Triggered when character starts or resumes activity | { "character", `character_id` },
{ "activity", `activity_id` },
{ "resume", `bool` } | character / NONE | -| character_takes_damage | triggers when character gets any damage from any creature | { "character", `character_id` },
{ "damage", `int` },
{ "bodypart", `bodypart_id` }, | character / attacker if exists, otherwise NONE(character or monster) | use `has_beta` conditon before interacting with beta talker +| character_takes_damage | triggers when character gets any damage from any creature | { "character", `character_id` },
{ "damage", `int` },
{ "bodypart", `bodypart_id` },
{ "pain", `int` }, | character / attacker if exists, otherwise NONE(character or monster) | use `has_beta` conditon before interacting with beta talker | monster_takes_damage | triggers when monster gets any damage from any creature. Includes damages from effects like bleeding | { "damage", `int` },
{ "dies", `bool` }, | monster / attacker if exists, otherwise NONE(character or monster) | use `has_beta` conditon before interacting with beta talker | character_triggers_trap | | { "character", `character_id` },
{ "trap", `trap_str_id` }, | character / NONE | | character_wakes_up | triggers in the moment player lost it's sleep effect and wakes up | { "character", `character_id` }, | character / NONE | diff --git a/src/character.cpp b/src/character.cpp index e94b23d5cb421..842fc097724fb 100644 --- a/src/character.cpp +++ b/src/character.cpp @@ -8145,8 +8145,9 @@ void Character::apply_damage( Creature *source, bodypart_id hurt, int dam, hurt = body_part_torso; } + int pain = 0; if( !hurt->has_flag( json_flag_BIONIC_LIMB ) ) { - mod_pain( dam / 2 ); + pain = mod_pain( dam / 2 ); } const bodypart_id &part_to_damage = hurt->main_part; @@ -8155,10 +8156,10 @@ void Character::apply_damage( Creature *source, bodypart_id hurt, int dam, mod_part_hp_cur( part_to_damage, - dam_to_bodypart ); if( source ) { - cata::event e = cata::event::make( getID(), dam_to_bodypart, part_to_damage.id() ); + cata::event e = cata::event::make( getID(), dam_to_bodypart, part_to_damage.id(), pain ); get_event_bus().send_with_talker( this, source, e ); } else { - get_event_bus().send( getID(), dam_to_bodypart, part_to_damage.id() ); + get_event_bus().send( getID(), dam_to_bodypart, part_to_damage.id(), pain ); } if( !weapon.is_null() && !can_wield( weapon ).success() && @@ -8370,22 +8371,24 @@ void Character::hurtall( int dam, Creature *source, bool disturb /*= true*/ ) return; } - for( const bodypart_id &bp : get_all_body_parts( get_body_part_flags::only_main ) ) { + // Low pain: damage is spread all over the body, so not as painful as 6 hits in one part + int pain = mod_pain( dam ); + + std::vector body_parts = get_all_body_parts( get_body_part_flags::only_main ); + for( const bodypart_id &bp : body_parts ) { // Don't use apply_damage here or it will annoy the player with 6 queries const int dam_to_bodypart = std::min( dam, get_part_hp_cur( bp ) ); mod_part_hp_cur( bp, - dam_to_bodypart ); if( source ) { - cata::event e = cata::event::make( getID(), dam_to_bodypart, body_part_bp_null ); + cata::event e = cata::event::make( getID(), dam_to_bodypart, bp.id(), pain / body_parts.size() ); get_event_bus().send_with_talker( this, source == nullptr ? nullptr : source, e ); } else { - get_event_bus().send( getID(), dam_to_bodypart, body_part_bp_null ); + get_event_bus().send( getID(), dam_to_bodypart, bp.id(), pain / body_parts.size() ); } } - // Low pain: damage is spread all over the body, so not as painful as 6 hits in one part - mod_pain( dam ); on_hurt( source, disturb ); } @@ -12415,12 +12418,12 @@ bool Character::immune_to( const bodypart_id &bp, damage_unit dam ) const return dam.amount <= 0; } -void Character::mod_pain( int npain ) +int Character::mod_pain( int npain ) { if( npain > 0 ) { double mult = enchantment_cache->get_value_multiply( enchant_vals::mod::PAIN ); if( has_flag( json_flag_PAIN_IMMUNE ) || has_effect( effect_narcosis ) ) { - return; + return 0; } // if there is a positive multiplier we always want to add at least 1 pain if( mult > 0 ) { @@ -12435,6 +12438,7 @@ void Character::mod_pain( int npain ) npain = std::max( 0, npain ); } Creature::mod_pain( npain ); + return npain; } void Character::set_pain( int npain ) diff --git a/src/character.h b/src/character.h index 2e0c6ffc232a3..a42d4e291c469 100644 --- a/src/character.h +++ b/src/character.h @@ -2617,7 +2617,7 @@ class Character : public Creature, public visitable bool immune_to( const bodypart_id &bp, damage_unit dam ) const; /** Modifies a pain value by player traits before passing it to Creature::mod_pain() */ - void mod_pain( int npain ) override; + int mod_pain( int npain ) override; /** Sets new intensity of pain an reacts to it */ void set_pain( int npain ) override; /** Returns perceived pain (reduced with painkillers)*/ diff --git a/src/creature.cpp b/src/creature.cpp index 14b7e2441c27f..5f85aac8b1481 100644 --- a/src/creature.cpp +++ b/src/creature.cpp @@ -2115,9 +2115,10 @@ void Creature::clear_values() values.clear(); } -void Creature::mod_pain( int npain ) +int Creature::mod_pain( int npain ) { mod_pain_noresist( npain ); + return npain; } void Creature::mod_pain_noresist( int npain ) diff --git a/src/creature.h b/src/creature.h index b376fe005859b..1564ece40de1b 100644 --- a/src/creature.h +++ b/src/creature.h @@ -698,7 +698,7 @@ class Creature : public viewer virtual bool has_trait( const trait_id &flag ) const; // not-quite-stats, maybe group these with stats later - virtual void mod_pain( int npain ); + virtual int mod_pain( int npain ); virtual void mod_pain_noresist( int npain ); virtual void set_pain( int npain ); virtual int get_pain() const; diff --git a/src/event.h b/src/event.h index 5a7c8c3d39efb..646ca0f4a2696 100644 --- a/src/event.h +++ b/src/event.h @@ -467,10 +467,11 @@ struct event_spec { template<> struct event_spec { - static constexpr std::array, 3> fields = {{ + static constexpr std::array, 4> fields = {{ { "character", cata_variant_type::character_id }, { "damage", cata_variant_type::int_ }, - { "bodypart", cata_variant_type::body_part } + { "bodypart", cata_variant_type::body_part }, + { "pain", cata_variant_type::int_ } } }; }; diff --git a/tests/stats_tracker_test.cpp b/tests/stats_tracker_test.cpp index e78ffead7cf17..028a9a3a91b1b 100644 --- a/tests/stats_tracker_test.cpp +++ b/tests/stats_tracker_test.cpp @@ -114,16 +114,16 @@ TEST_CASE( "stats_tracker_total_events", "[stats]" ) CHECK( s.get_events( ctd ).total( "damage", damage_to_u ) == 0 ); CHECK( s.get_events( ctd ).total( "damage", damage_to_any ) == 0 ); - b.send( u_id, 10, body_part_bp_null ); + b.send( u_id, 10, body_part_bp_null, 0 ); CHECK( s.get_events( ctd ).total( "damage", damage_to_u ) == 10 ); CHECK( s.get_events( ctd ).total( "damage", damage_to_any ) == 10 ); - b.send( other_id, 10, body_part_bp_null ); + b.send( other_id, 10, body_part_bp_null, 0 ); CHECK( s.get_events( ctd ).total( "damage", damage_to_u ) == 10 ); CHECK( s.get_events( ctd ).total( "damage", damage_to_any ) == 20 ); - b.send( u_id, 10, body_part_bp_null ); + b.send( u_id, 10, body_part_bp_null, 0 ); CHECK( s.get_events( ctd ).total( "damage", damage_to_u ) == 20 ); CHECK( s.get_events( event_type::character_takes_damage ).total( "damage", damage_to_any ) == 30 ); - b.send( u_id, 5, body_part_bp_null ); + b.send( u_id, 5, body_part_bp_null, 0 ); CHECK( s.get_events( event_type::character_takes_damage ).total( "damage", damage_to_u ) == 25 ); CHECK( s.get_events( event_type::character_takes_damage ).total( "damage", damage_to_any ) == 35 ); } @@ -193,11 +193,11 @@ TEST_CASE( "stats_tracker_event_time_bounds", "[stats]" ) CHECK( !s.get_events( ctd ).first() ); CHECK( !s.get_events( ctd ).last() ); - b.send( u_id, 10, body_part_bp_null ); + b.send( u_id, 10, body_part_bp_null, 0 ); CHECK( s.get_events( ctd ).first()->second.first == start ); CHECK( s.get_events( ctd ).last()->second.last == calendar::turn ); calendar::turn += 1_minutes; - b.send( u_id, 10, body_part_bp_null ); + b.send( u_id, 10, body_part_bp_null, 0 ); CHECK( s.get_events( ctd ).first()->second.first == start ); CHECK( s.get_events( ctd ).last()->second.last == calendar::turn ); } @@ -337,7 +337,7 @@ TEST_CASE( "stats_tracker_with_event_statistics", "[stats]" ) SECTION( "damage" ) { const cata::event avatar_2_damage = - cata::event::make( u_id, 2, body_part_bp_null ); + cata::event::make( u_id, 2, body_part_bp_null, 0 ); send_game_start( b, u_id ); CHECK( score_score_damage_taken->value( s ).get() == 0 ); @@ -556,7 +556,7 @@ TEST_CASE( "stats_tracker_watchers", "[stats]" ) SECTION( "damage" ) { const cata::event avatar_2_damage = - cata::event::make( u_id, 2, body_part_bp_null ); + cata::event::make( u_id, 2, body_part_bp_null, 0 ); watch_stat damage_watcher; s.add_watcher( event_statistic_avatar_damage_taken, &damage_watcher ); From a637fd27f4945374f16a5d3aefc01b15d8e5a78d Mon Sep 17 00:00:00 2001 From: b3brodie Date: Mon, 25 Nov 2024 18:19:22 -0800 Subject: [PATCH 15/48] spelling --- data/mods/Xedra_Evolved/effects/effects.json | 2 +- .../spell_learning_items/spell_learning_items_dreamer.json | 2 +- data/mods/Xedra_Evolved/items/tools.json | 4 ++-- data/mods/Xedra_Evolved/spells/dreamer_spells.json | 2 +- data/mods/Xedra_Evolved/spells/item_spells.json | 2 +- data/mods/Xedra_Evolved/spells/spell_eocs.json | 2 +- 6 files changed, 7 insertions(+), 7 deletions(-) diff --git a/data/mods/Xedra_Evolved/effects/effects.json b/data/mods/Xedra_Evolved/effects/effects.json index ec159c60bf73e..6b23ab3ba934d 100644 --- a/data/mods/Xedra_Evolved/effects/effects.json +++ b/data/mods/Xedra_Evolved/effects/effects.json @@ -2718,7 +2718,7 @@ "type": "effect_type", "id": "effect_xedra_dreamer_generate_accelerated_time", "name": [ "Accelerated Time Emission" ], - "desc": [ "You continuously generate fields of shortlived accelerated time." ], + "desc": [ "You continuously generate fields of short-lived accelerated time." ], "enchantments": [ { "emitter": "xedra_dreamer_emit_accelerated_time" } ], "rating": "good", "show_in_info": true diff --git a/data/mods/Xedra_Evolved/items/spell_learning_items/spell_learning_items_dreamer.json b/data/mods/Xedra_Evolved/items/spell_learning_items/spell_learning_items_dreamer.json index da0cb31215dde..2b33a4c94914d 100644 --- a/data/mods/Xedra_Evolved/items/spell_learning_items/spell_learning_items_dreamer.json +++ b/data/mods/Xedra_Evolved/items/spell_learning_items/spell_learning_items_dreamer.json @@ -171,7 +171,7 @@ "id": "artifact_amber", "type": "GENERIC", "category": "artifacts", - "name": { "str": "shard of amber" }, + "name": { "str": "shard of amber", "str_pl": "shards of amber" }, "description": "A small shard of amber. Looking carefully, you think you see some manner of creature trapped within.", "weight": "1 g", "volume": "150 ml", diff --git a/data/mods/Xedra_Evolved/items/tools.json b/data/mods/Xedra_Evolved/items/tools.json index cb70485ed05dc..a63f474f8139f 100644 --- a/data/mods/Xedra_Evolved/items/tools.json +++ b/data/mods/Xedra_Evolved/items/tools.json @@ -176,8 +176,8 @@ "id": "xedra_dreamsmith_time_watch", "type": "TOOL", "copy-from": "pocketwatch", - "name": { "str": "time shattering pocketwatch" }, - "description": "A pocketwatch made entirely of dreamdross. It somehow still accurately tells the time. Once per day, press the button on the right to briefly stop time for everything but you.", + "name": { "str": "time shattering pocket watch" }, + "description": "A pocket watch made entirely of dreamdross. It somehow still accurately tells the time. Once per day, press the button on the right to briefly stop time for everything but you.", "proportional": { "weight": 0.5 }, "price": "1000 cent", "price_postapoc": "100 cent", diff --git a/data/mods/Xedra_Evolved/spells/dreamer_spells.json b/data/mods/Xedra_Evolved/spells/dreamer_spells.json index ae85f08b65004..6d1b8aff57d6b 100644 --- a/data/mods/Xedra_Evolved/spells/dreamer_spells.json +++ b/data/mods/Xedra_Evolved/spells/dreamer_spells.json @@ -600,7 +600,7 @@ "id": "xedra_dreamer_generate_accelerated_time", "type": "SPELL", "name": "Generate Accelerated Time", - "description": "Continuously generate shortlived bubbles of accelerated time around you, allowing you and anything else that enters to act far quicker than normal.", + "description": "Continuously generate short-lived bubbles of accelerated time around you, allowing you and anything else that enters to act far quicker than normal.", "teachable": false, "valid_targets": [ "self" ], "effect": "effect_on_condition", diff --git a/data/mods/Xedra_Evolved/spells/item_spells.json b/data/mods/Xedra_Evolved/spells/item_spells.json index df068e31330bb..e2d4a8e14fc5b 100644 --- a/data/mods/Xedra_Evolved/spells/item_spells.json +++ b/data/mods/Xedra_Evolved/spells/item_spells.json @@ -537,7 +537,7 @@ "id": "xedra_inventor_time_pierce_creature", "type": "SPELL", "name": "Inventor Time Pierce - Creature", - "description": "Used by a time piercer to fix time frozen creaures. Having this spell is a bug.", + "description": "Used by a time piercer to fix time frozen creatures. Having this spell is a bug.", "teachable": false, "valid_targets": [ "self", "ally", "hostile" ], "flags": [ "SILENT", "NO_LEGS", "NO_EXPLOSION_SFX", "NON_MAGICAL", "NO_FAIL" ], diff --git a/data/mods/Xedra_Evolved/spells/spell_eocs.json b/data/mods/Xedra_Evolved/spells/spell_eocs.json index c6c6a51611462..1c596434f2a09 100644 --- a/data/mods/Xedra_Evolved/spells/spell_eocs.json +++ b/data/mods/Xedra_Evolved/spells/spell_eocs.json @@ -89,7 +89,7 @@ "effect": [ { "math": [ "u_val('mana')", "-=", "200" ] }, { - "u_message": "The greyscale starts to receed from you vision before it quickly reverts.", + "u_message": "The grayscale starts to recede from you vision before it quickly reverts.", "type": "good" }, { From d4dc55932ac6075e5a418c1234ce56f91a3802b5 Mon Sep 17 00:00:00 2001 From: b3brodie Date: Mon, 25 Nov 2024 18:33:41 -0800 Subject: [PATCH 16/48] more spelling --- data/mods/Xedra_Evolved/items/tools.json | 2 +- data/mods/Xedra_Evolved/spells/spell_eocs.json | 2 +- tools/spell_checker/dictionary.txt | 1 + 3 files changed, 3 insertions(+), 2 deletions(-) diff --git a/data/mods/Xedra_Evolved/items/tools.json b/data/mods/Xedra_Evolved/items/tools.json index a63f474f8139f..202e69ce3aee4 100644 --- a/data/mods/Xedra_Evolved/items/tools.json +++ b/data/mods/Xedra_Evolved/items/tools.json @@ -176,7 +176,7 @@ "id": "xedra_dreamsmith_time_watch", "type": "TOOL", "copy-from": "pocketwatch", - "name": { "str": "time shattering pocket watch" }, + "name": { "str": "time shattering pocket watch", "str_pl": "time shattering pocket watches" }, "description": "A pocket watch made entirely of dreamdross. It somehow still accurately tells the time. Once per day, press the button on the right to briefly stop time for everything but you.", "proportional": { "weight": 0.5 }, "price": "1000 cent", diff --git a/data/mods/Xedra_Evolved/spells/spell_eocs.json b/data/mods/Xedra_Evolved/spells/spell_eocs.json index 1c596434f2a09..2e0b8186e29ce 100644 --- a/data/mods/Xedra_Evolved/spells/spell_eocs.json +++ b/data/mods/Xedra_Evolved/spells/spell_eocs.json @@ -89,7 +89,7 @@ "effect": [ { "math": [ "u_val('mana')", "-=", "200" ] }, { - "u_message": "The grayscale starts to recede from you vision before it quickly reverts.", + "u_message": "The grayscale starts to recede from your vision before it quickly reverts.", "type": "good" }, { diff --git a/tools/spell_checker/dictionary.txt b/tools/spell_checker/dictionary.txt index 813c56ebcbc8a..13d432ba94706 100644 --- a/tools/spell_checker/dictionary.txt +++ b/tools/spell_checker/dictionary.txt @@ -2362,6 +2362,7 @@ gravesite Gravol GravyField Grayfield +grayscale greatbow greatbows greatclub From b9d9485c41c6e70261c600bf9299f10af219e908 Mon Sep 17 00:00:00 2001 From: b3brodie Date: Mon, 25 Nov 2024 21:12:54 -0800 Subject: [PATCH 17/48] Prevent interacting with things within impassable fields --- src/action.cpp | 3 +++ src/map.cpp | 2 +- 2 files changed, 4 insertions(+), 1 deletion(-) diff --git a/src/action.cpp b/src/action.cpp index 41ef5773810a1..e7b99965c3d1d 100644 --- a/src/action.cpp +++ b/src/action.cpp @@ -730,6 +730,9 @@ static bool can_pickup_at( const tripoint_bub_ms &p ) bool can_interact_at( action_id action, const tripoint_bub_ms &p ) { map &here = get_map(); + if( here.impassable_field_at(p) ) { + return false; + } tripoint_bub_ms player_pos = get_player_character().pos_bub(); switch( action ) { case ACTION_OPEN: diff --git a/src/map.cpp b/src/map.cpp index 729ab3cded875..87d0a0afbdadc 100644 --- a/src/map.cpp +++ b/src/map.cpp @@ -4907,7 +4907,7 @@ bool map::open_door( Creature const &u, const tripoint &p, const bool inside, bool map::open_door( Creature const &u, const tripoint_bub_ms &p, const bool inside, const bool check_only ) { - if( u.has_effect( effect_incorporeal ) ) { + if( u.has_effect( effect_incorporeal ) || impassable_field_at(p) ) { return false; } const ter_t &ter = this->ter( p ).obj(); From c6de5f02a82a96a244cbd292e8fe348f2ac2f171 Mon Sep 17 00:00:00 2001 From: b3brodie Date: Mon, 25 Nov 2024 21:40:29 -0800 Subject: [PATCH 18/48] prevent mining impassable fields --- src/activity_item_handling.cpp | 2 +- src/avatar_action.cpp | 2 +- src/iuse.cpp | 3 ++- 3 files changed, 4 insertions(+), 3 deletions(-) diff --git a/src/activity_item_handling.cpp b/src/activity_item_handling.cpp index a4da5ef5aec96..20dcfbab73591 100644 --- a/src/activity_item_handling.cpp +++ b/src/activity_item_handling.cpp @@ -2410,7 +2410,7 @@ static bool mine_activity( Character &you, const tripoint_bub_ms &src_loc ) } ); map &here = get_map(); if( mining_inv.empty() || you.is_mounted() || you.is_underwater() || here.veh_at( src_loc ) || - !here.has_flag( ter_furn_flag::TFLAG_MINEABLE, src_loc ) || you.has_effect( effect_incorporeal ) ) { + !here.has_flag( ter_furn_flag::TFLAG_MINEABLE, src_loc ) || you.has_effect( effect_incorporeal ) || here.impassable_field_at(src_loc) ) { return false; } item *chosen_item = nullptr; diff --git a/src/avatar_action.cpp b/src/avatar_action.cpp index 7791ab2605b4a..aa53c82a04763 100644 --- a/src/avatar_action.cpp +++ b/src/avatar_action.cpp @@ -230,7 +230,7 @@ bool avatar_action::move( avatar &you, map &m, const tripoint &d ) if( m.has_flag( ter_furn_flag::TFLAG_MINEABLE, dest_loc ) && g->mostseen == 0 && get_option( "AUTO_FEATURES" ) && get_option( "AUTO_MINING" ) && !m.veh_at( dest_loc ) && !you.is_underwater() && !you.has_effect( effect_stunned ) && - !you.has_effect( effect_psi_stunned ) && !is_riding && !you.has_effect( effect_incorporeal ) ) { + !you.has_effect( effect_psi_stunned ) && !is_riding && !you.has_effect( effect_incorporeal ) && !m.impassable_field_at(d) ) { if( weapon && weapon->has_flag( flag_DIG_TOOL ) ) { if( weapon->type->can_use( "JACKHAMMER" ) && weapon->ammo_sufficient( &you ) ) { diff --git a/src/iuse.cpp b/src/iuse.cpp index 267696020275a..7a24ae0168b37 100644 --- a/src/iuse.cpp +++ b/src/iuse.cpp @@ -3084,8 +3084,9 @@ static std::optional dig_tool( Character *p, item *it, const tripoint &pos, map &here = get_map(); const bool mineable_furn = here.has_flag_furn( ter_furn_flag::TFLAG_MINEABLE, pnt ); const bool mineable_ter = here.has_flag_ter( ter_furn_flag::TFLAG_MINEABLE, pnt ); + const bool impassable_fields = here.impassable_field_at( pnt ); const int max_mining_ability = 70; - if( !mineable_furn && !mineable_ter ) { + if( !mineable_furn && !mineable_ter || impassable_fields ) { p->add_msg_if_player( m_info, fail ); if( here.bash_resistance( pnt ) > max_mining_ability ) { p->add_msg_if_player( m_info, From d7746255a21efcdeeafffed870711894f03286ce Mon Sep 17 00:00:00 2001 From: b3brodie Date: Tue, 26 Nov 2024 01:31:52 -0800 Subject: [PATCH 19/48] Add eoc effect to cancel activities Co-authored-by: GuardianDll <67688115+GuardianDll@users.noreply.github.com> --- src/npctalk.cpp | 21 +++++++++++++++++++++ 1 file changed, 21 insertions(+) diff --git a/src/npctalk.cpp b/src/npctalk.cpp index b78c93c6791e1..588f38595e04d 100644 --- a/src/npctalk.cpp +++ b/src/npctalk.cpp @@ -5169,6 +5169,16 @@ talk_effect_fun_t::func f_die( bool is_npc ) }; } +talk_effect_fun_t::func f_cancel_activity( bool is_npc ) +{ + return [is_npc]( dialogue const & d ) { + Character *target = d.actor( is_npc )->get_character(); + if( target ) { + target->cancel_activity(); + } + }; +} + talk_effect_fun_t::func f_prevent_death( bool is_npc ) { return [is_npc]( dialogue const & d ) { @@ -7426,6 +7436,17 @@ void talk_effect_t::parse_string_effect( const std::string &effect_id, const Jso set_effect( talk_effect_fun_t( talk_effect_fun::f_die( true ) ) ); return; } + + if( effect_id == "u_cancel_activity" ) { + set_effect( talk_effect_fun_t( talk_effect_fun::f_cancel_activity( false ) ) ); + return; + } + + if( effect_id == "npc_cancel_activity" ) { + set_effect( talk_effect_fun_t( talk_effect_fun::f_cancel_activity( true ) ) ); + return; + } + if( effect_id == "u_prevent_death" ) { set_effect( talk_effect_fun_t( talk_effect_fun::f_prevent_death( false ) ) ); From 52299e7ece01bfb72b025a571a2293ea3cc79a85 Mon Sep 17 00:00:00 2001 From: b3brodie Date: Tue, 26 Nov 2024 02:04:23 -0800 Subject: [PATCH 20/48] Add time stop activity to make players not have to manually progress time --- data/mods/Xedra_Evolved/eocs/misc_eoc.json | 31 ++++++++++++++++++++++ 1 file changed, 31 insertions(+) diff --git a/data/mods/Xedra_Evolved/eocs/misc_eoc.json b/data/mods/Xedra_Evolved/eocs/misc_eoc.json index e963936c4900f..4811a8a0db10f 100644 --- a/data/mods/Xedra_Evolved/eocs/misc_eoc.json +++ b/data/mods/Xedra_Evolved/eocs/misc_eoc.json @@ -343,5 +343,36 @@ { "math": [ "u_xedra_last_pain_taken=_pain" ] }, { "set_string_var": { "context_val": "bodypart" }, "target_var": { "u_val": "xedra_last_damage_taken_bodypart" } } ] + }, + { + "type": "effect_on_condition", + "id": "eoc_xedra_time_freeze_character_start_activity", + "eoc_type": "EVENT", + "required_event": "character_gains_effect", + "condition": { "compare_string": [ "effect_xedra_time_freeze", { "context_val": "effect" } ] }, + "//": "Activity duration doesn't truly align with time stops potentially lasting indefinitely, but players should never be time stopped longer than a day or two anyways so 200 days should be good enough. If truly important making the activity based on neither rather than time and adding a blank do_turn function should allow >200 day durations", + "effect": [ + { "u_assign_activity": "act_xedra_time_freeze", "duration": "200 days" } + ] + }, + { + "type": "effect_on_condition", + "id": "eoc_xedra_time_freeze_character_end_activity", + "eoc_type": "EVENT", + "required_event": "character_loses_effect", + "condition": { "compare_string": [ "effect_xedra_time_freeze", { "context_val": "effect" } ] }, + "effect": [ + "u_cancel_activity" + ] + }, + { + "id": "act_xedra_time_freeze", + "type": "activity_type", + "activity_level": "NO_EXERCISE", + "verb": "frozen in time", + "based_on": "time", + "interruptable": false, + "interruptable_with_kb": false, + "can_resume": false } ] From fa50ebecb12c6cb3010310379965f22f0f66033a Mon Sep 17 00:00:00 2001 From: b3brodie Date: Tue, 26 Nov 2024 15:17:33 -0800 Subject: [PATCH 21/48] Characters cannot dodge with CANNOT_MOVE --- src/character.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/character.cpp b/src/character.cpp index 842fc097724fb..25577e54f5a8d 100644 --- a/src/character.cpp +++ b/src/character.cpp @@ -1233,7 +1233,7 @@ ret_val Character::can_try_dodge( bool ignore_dodges_left ) const { //If we're asleep or busy we can't dodge if( in_sleep_state() || has_effect( effect_narcosis ) || - has_effect( effect_winded ) || has_effect( effect_fearparalyze ) || is_driving() ) { + has_effect( effect_winded ) || has_effect( effect_fearparalyze ) || is_driving() || has_flag( json_flag_CANNOT_MOVE ) ) { add_msg_debug( debugmode::DF_MELEE, "Unable to dodge (sleeping, winded, or driving)" ); return ret_val::make_failure(); } From 81a0bbb6d3806129c1923d67ca6cdeaeb35c34e7 Mon Sep 17 00:00:00 2001 From: b3brodie Date: Tue, 26 Nov 2024 15:20:47 -0800 Subject: [PATCH 22/48] Monsters cannot dodge with CANNOT_MOVE flag --- src/monster.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/monster.cpp b/src/monster.cpp index 7a0c96826356a..9c5a94a1de49f 100644 --- a/src/monster.cpp +++ b/src/monster.cpp @@ -2624,7 +2624,7 @@ float monster::stability_roll() const float monster::get_dodge() const { - if( has_effect( effect_downed ) ) { + if( has_effect( effect_downed ) || has_effect_with_flag( json_flag_CANNOT_MOVE ) ) { return 0.0f; } From 0c00d2b371a72e5b4173ff707a2088ef6552dd0b Mon Sep 17 00:00:00 2001 From: b3brodie Date: Tue, 26 Nov 2024 15:57:49 -0800 Subject: [PATCH 23/48] prevent melee training on monsters that are invulnerable and cannot move --- src/melee.cpp | 9 +++++---- 1 file changed, 5 insertions(+), 4 deletions(-) diff --git a/src/melee.cpp b/src/melee.cpp index dd91ef801e248..6612b40465dc2 100644 --- a/src/melee.cpp +++ b/src/melee.cpp @@ -119,6 +119,7 @@ static const itype_id itype_sheet_cotton( "sheet_cotton" ); static const json_character_flag json_flag_CANNOT_ATTACK( "CANNOT_ATTACK" ); static const json_character_flag json_flag_CANNOT_MOVE( "CANNOT_MOVE" ); +static const json_character_flag json_flag_CANNOT_TAKE_DAMAGE( "CANNOT_TAKE_DAMAGE" ); static const json_character_flag json_flag_CBQ_LEARN_BONUS( "CBQ_LEARN_BONUS" ); static const json_character_flag json_flag_GRAB( "GRAB" ); static const json_character_flag json_flag_GRAB_FILTER( "GRAB_FILTER" ); @@ -696,8 +697,8 @@ bool Character::melee_attack_abstract( Creature &t, bool allow_special, } } - // Practice melee and relevant weapon skill (if any) except when using CQB bionic - if( !has_active_bionic( bio_cqb ) && !t.is_hallucination() ) { + // Practice melee and relevant weapon skill (if any) except when using CQB bionic, if the creature is a hallucination, or if the creature cannot move and take damage. + if( !has_active_bionic( bio_cqb ) && !t.is_hallucination() && !( t.has_effect_with_flag( json_flag_CANNOT_MOVE ) && t.has_effect_with_flag( json_flag_CANNOT_TAKE_DAMAGE ) ) ) { melee_train( *this, 2, std::min( 5, skill_training_cap ), cur_weap, attack_vector_vector_null ); } @@ -876,8 +877,8 @@ bool Character::melee_attack_abstract( Creature &t, bool allow_special, int dam = dealt_dam.total_damage(); melee::melee_stats.damage_amount += dam; - // Practice melee and relevant weapon skill (if any) except when using CQB bionic - if( !has_active_bionic( bio_cqb ) && !t.is_hallucination() ) { + // Practice melee and relevant weapon skill (if any) except when using CQB bionic, if the creature is a hallucination, or if the creature cannot move and take damage. + if( !has_active_bionic( bio_cqb ) && !t.is_hallucination() && !( t.has_effect_with_flag( json_flag_CANNOT_MOVE ) && t.has_effect_with_flag( json_flag_CANNOT_TAKE_DAMAGE ) ) ) { melee_train( *this, 5, std::min( 10, skill_training_cap ), cur_weap, vector_id ); } From 574a57f7af44f453ca617066713b5dddbf3dff46 Mon Sep 17 00:00:00 2001 From: b3brodie Date: Tue, 26 Nov 2024 16:13:29 -0800 Subject: [PATCH 24/48] prevent throwing experience too --- src/ranged.cpp | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-) diff --git a/src/ranged.cpp b/src/ranged.cpp index 8c459b5ddeb89..2bf2a6ff9dde7 100644 --- a/src/ranged.cpp +++ b/src/ranged.cpp @@ -143,6 +143,7 @@ static const fault_id fault_overheat_melting( "fault_overheat_melting" ); static const fault_id fault_overheat_safety( "fault_overheat_safety" ); static const fault_id fault_overheat_venting( "fault_overheat_venting" ); +static const flag_id json_flag_CANNOT_MOVE( "CANNOT_MOVE" ); static const flag_id json_flag_FILTHY( "FILTHY" ); static const material_id material_budget_steel( "budget_steel" ); @@ -1542,12 +1543,12 @@ dealt_projectile_attack Character::throw_item( const tripoint_bub_ms &target, co const double missed_by = dealt_attack.missed_by; if( critter && dealt_attack.hit_critter != nullptr && missed_by <= 0.1 && - !critter->has_flag( mon_flag_IMMOBILE ) ) { + !critter->has_flag( mon_flag_IMMOBILE ) && !critter->has_effect_with_flag( json_flag_CANNOT_MOVE ) ) { practice( skill_throw, final_xp_mult, MAX_SKILL ); // TODO: Check target for existence of head get_event_bus().send( getID() ); } else if( critter && dealt_attack.hit_critter != nullptr && missed_by > 0.0f && - !critter->has_flag( mon_flag_IMMOBILE ) ) { + !critter->has_flag( mon_flag_IMMOBILE ) && !critter->has_effect_with_flag( json_flag_CANNOT_MOVE ) ) { practice( skill_throw, final_xp_mult / ( 1.0f + missed_by ), MAX_SKILL ); } else { // Pure grindy practice - cap gain at lvl 2 From 7a08f06013d497d3bdb2f9ba578239d541bf3041 Mon Sep 17 00:00:00 2001 From: b3brodie Date: Tue, 26 Nov 2024 19:22:56 -0800 Subject: [PATCH 25/48] add no temperature progression flag and add to time freeze --- data/json/flags.json | 4 ++++ data/mods/Xedra_Evolved/effects/effects.json | 2 +- src/character_body.cpp | 4 ++++ 3 files changed, 9 insertions(+), 1 deletion(-) diff --git a/data/json/flags.json b/data/json/flags.json index d58d823019444..d18dc433a4f23 100644 --- a/data/json/flags.json +++ b/data/json/flags.json @@ -2627,5 +2627,9 @@ { "id": "CANNOT_TAKE_DAMAGE", "type": "json_flag" + }, + { + "id": "CANNOT_CHANGE_TEMPERATURE", + "type": "json_flag" } ] diff --git a/data/mods/Xedra_Evolved/effects/effects.json b/data/mods/Xedra_Evolved/effects/effects.json index 6b23ab3ba934d..6fa13f3fbcc0e 100644 --- a/data/mods/Xedra_Evolved/effects/effects.json +++ b/data/mods/Xedra_Evolved/effects/effects.json @@ -2701,7 +2701,7 @@ "remove_message": "Everything is suddenly different.", "rating": "neutral", "immune_flags": [ "DIMENSIONAL_ANCHOR", "STABILIZED_TIMELINE" ], - "flags": [ "CANNOT_ATTACK", "CANNOT_MOVE", "CANNOT_TAKE_DAMAGE" ], + "flags": [ "CANNOT_ATTACK", "CANNOT_MOVE", "CANNOT_TAKE_DAMAGE", "CANNOT_CHANGE_TEMPERATURE" ], "show_in_info": true }, { diff --git a/src/character_body.cpp b/src/character_body.cpp index 445d7db309b48..047c74e307088 100644 --- a/src/character_body.cpp +++ b/src/character_body.cpp @@ -90,6 +90,7 @@ static const efftype_id effect_wet( "wet" ); static const itype_id itype_rm13_armor_on( "rm13_armor_on" ); static const json_character_flag json_flag_BARKY( "BARKY" ); +static const json_character_flag json_flag_CANNOT_CHANGE_TEMPERATURE( "CANNOT_CHANGE_TEMPERATURE" ); static const json_character_flag json_flag_COLDBLOOD( "COLDBLOOD" ); static const json_character_flag json_flag_COLDBLOOD2( "COLDBLOOD2" ); static const json_character_flag json_flag_COLDBLOOD3( "COLDBLOOD3" ); @@ -446,6 +447,9 @@ void Character::update_bodytemp() set_all_parts_temp_cur( BODYTEMP_NORM ); return; } + if( has_flag( json_flag_CANNOT_CHANGE_TEMPERATURE ) ) { + return; + } weather_manager &weather_man = get_weather(); /* Cache calls to g->get_temperature( player position ), used in several places in function */ const units::temperature player_local_temp = weather_man.get_temperature( pos() ); From f3f13b0bf41a51e0ae6a85906d240fb08aca9190 Mon Sep 17 00:00:00 2001 From: b3brodie Date: Tue, 26 Nov 2024 19:35:25 -0800 Subject: [PATCH 26/48] Add some extra logic for timefrozen npcs --- data/mods/Xedra_Evolved/eocs/misc_eoc.json | 18 ++++++++++++++++-- data/mods/Xedra_Evolved/field_type.json | 2 +- 2 files changed, 17 insertions(+), 3 deletions(-) diff --git a/data/mods/Xedra_Evolved/eocs/misc_eoc.json b/data/mods/Xedra_Evolved/eocs/misc_eoc.json index 4811a8a0db10f..ae0b4f75cf70d 100644 --- a/data/mods/Xedra_Evolved/eocs/misc_eoc.json +++ b/data/mods/Xedra_Evolved/eocs/misc_eoc.json @@ -352,7 +352,14 @@ "condition": { "compare_string": [ "effect_xedra_time_freeze", { "context_val": "effect" } ] }, "//": "Activity duration doesn't truly align with time stops potentially lasting indefinitely, but players should never be time stopped longer than a day or two anyways so 200 days should be good enough. If truly important making the activity based on neither rather than time and adding a blank do_turn function should allow >200 day durations", "effect": [ - { "u_assign_activity": "act_xedra_time_freeze", "duration": "200 days" } + { "u_assign_activity": "act_xedra_time_freeze", "duration": "200 days" }, + { "math": [ "u_hp_before_time_freeze", "=", "u_hp('ALL') / 6" ] }, + { "math": [ "u_pain_before_time_freeze", "=", "u_pain()" ] }, + { "math": [ "u_kcal_before_time_freeze", "=", "u_calories()" ] }, + { "math": [ "u_thirst_before_time_freeze", "=", "u_val('thirst')" ] }, + { "math": [ "u_blood_before_time_freeze", "=", "u_vitamin('blood')" ] }, + { "math": [ "u_redcells_before_time_freeze", "=", "u_vitamin('redcells')" ] }, + { "math": [ "u_rad_before_time_freeze", "=", "u_val('rad')" ] } ] }, { @@ -362,7 +369,14 @@ "required_event": "character_loses_effect", "condition": { "compare_string": [ "effect_xedra_time_freeze", { "context_val": "effect" } ] }, "effect": [ - "u_cancel_activity" + "u_cancel_activity", + { "math": [ "u_hp('ALL')", "=", "u_hp_before_time_freeze" ] }, + { "math": [ "u_pain()", "=", "u_pain_before_time_freeze" ] }, + { "math": [ "u_calories()", "=", "u_kcal_before_time_freeze" ] }, + { "math": [ "u_val('thirst')", "=", "u_thirst_before_time_freeze" ] }, + { "math": [ "u_vitamin('blood')", "=", "u_blood_before_time_freeze" ] }, + { "math": [ "u_vitamin('redcells')", "=", "u_redcells_before_time_freeze" ] }, + { "math": [ "u_val('rad')", "=", "u_rad_before_time_freeze" ] } ] }, { diff --git a/data/mods/Xedra_Evolved/field_type.json b/data/mods/Xedra_Evolved/field_type.json index c40840431d81a..53ff1c47cbaed 100644 --- a/data/mods/Xedra_Evolved/field_type.json +++ b/data/mods/Xedra_Evolved/field_type.json @@ -258,7 +258,7 @@ "id": "fd_frozen_time", "type": "field_type", "intensity_levels": [ - { "name": "frozen time", "sym": "#", "color": "light_gray", "transparent": true, "move_cost": -1000 } + { "name": "frozen time", "sym": "O", "color": "light_gray", "transparent": true, "move_cost": -1000 } ], "priority": 100, "display_items": true, From 4918224824153dd6cd0058a3f30ff942a030fe19 Mon Sep 17 00:00:00 2001 From: b3brodie Date: Tue, 26 Nov 2024 20:11:27 -0800 Subject: [PATCH 27/48] add flag to freeze effect progression and give to time freeze --- data/json/flags.json | 5 +++++ data/mods/Xedra_Evolved/effects/effects.json | 2 +- src/creature.cpp | 7 ++++++- 3 files changed, 12 insertions(+), 2 deletions(-) diff --git a/data/json/flags.json b/data/json/flags.json index d18dc433a4f23..9ad8ad6c6b3e1 100644 --- a/data/json/flags.json +++ b/data/json/flags.json @@ -2631,5 +2631,10 @@ { "id": "CANNOT_CHANGE_TEMPERATURE", "type": "json_flag" + }, + { + "id": "FREEZE_EFFECTS", + "type": "json_flag", + "//": "Creatures with this flag will not have their effects change in duration except for the effects that contain this flag." } ] diff --git a/data/mods/Xedra_Evolved/effects/effects.json b/data/mods/Xedra_Evolved/effects/effects.json index 6fa13f3fbcc0e..3e900628780b7 100644 --- a/data/mods/Xedra_Evolved/effects/effects.json +++ b/data/mods/Xedra_Evolved/effects/effects.json @@ -2701,7 +2701,7 @@ "remove_message": "Everything is suddenly different.", "rating": "neutral", "immune_flags": [ "DIMENSIONAL_ANCHOR", "STABILIZED_TIMELINE" ], - "flags": [ "CANNOT_ATTACK", "CANNOT_MOVE", "CANNOT_TAKE_DAMAGE", "CANNOT_CHANGE_TEMPERATURE" ], + "flags": [ "CANNOT_ATTACK", "CANNOT_MOVE", "CANNOT_TAKE_DAMAGE", "CANNOT_CHANGE_TEMPERATURE", "FREEZE_EFFECTS" ], "show_in_info": true }, { diff --git a/src/creature.cpp b/src/creature.cpp index 5f85aac8b1481..08fa2a67334e7 100644 --- a/src/creature.cpp +++ b/src/creature.cpp @@ -132,9 +132,10 @@ static const efftype_id effect_zapped( "zapped" ); static const field_type_str_id field_fd_last_known( "fd_last_known" ); +static const json_character_flag json_flag_BIONIC_LIMB( "BIONIC_LIMB" ); static const json_character_flag json_flag_CANNOT_MOVE( "CANNOT_MOVE" ); static const json_character_flag json_flag_CANNOT_TAKE_DAMAGE( "CANNOT_TAKE_DAMAGE" ); -static const json_character_flag json_flag_BIONIC_LIMB( "BIONIC_LIMB" ); +static const json_character_flag json_flag_FREEZE_EFFECTS( "FREEZE_EFFECTS" ); static const json_character_flag json_flag_IGNORE_TEMP( "IGNORE_TEMP" ); static const json_character_flag json_flag_LIMB_LOWER( "LIMB_LOWER" ); static const json_character_flag json_flag_LIMB_UPPER( "LIMB_UPPER" ); @@ -2032,6 +2033,10 @@ void Creature::process_effects() // Decay/removal of effects for( auto &elem : *effects ) { for( auto &_it : elem.second ) { + // Do not freeze the effect with the FREEZE_EFFECTS flag. + if( has_effect_with_flag( json_flag_FREEZE_EFFECTS ) && !_it.second.has_flag( json_flag_FREEZE_EFFECTS ) ) { + continue; + } // Add any effects that others remove to the removal list for( const auto &removed_effect : _it.second.get_removes_effects() ) { rem_ids.push_back( removed_effect ); From ed616999522fe6c135eaa5f87ca5a534a28b62a2 Mon Sep 17 00:00:00 2001 From: b3brodie Date: Tue, 26 Nov 2024 21:21:06 -0800 Subject: [PATCH 28/48] Characters that cannot take damage cannot bleed --- data/mods/Xedra_Evolved/eocs/misc_eoc.json | 2 -- src/player_hardcoded_effects.cpp | 5 +++++ 2 files changed, 5 insertions(+), 2 deletions(-) diff --git a/data/mods/Xedra_Evolved/eocs/misc_eoc.json b/data/mods/Xedra_Evolved/eocs/misc_eoc.json index ae0b4f75cf70d..0ae2bcb5737fb 100644 --- a/data/mods/Xedra_Evolved/eocs/misc_eoc.json +++ b/data/mods/Xedra_Evolved/eocs/misc_eoc.json @@ -353,7 +353,6 @@ "//": "Activity duration doesn't truly align with time stops potentially lasting indefinitely, but players should never be time stopped longer than a day or two anyways so 200 days should be good enough. If truly important making the activity based on neither rather than time and adding a blank do_turn function should allow >200 day durations", "effect": [ { "u_assign_activity": "act_xedra_time_freeze", "duration": "200 days" }, - { "math": [ "u_hp_before_time_freeze", "=", "u_hp('ALL') / 6" ] }, { "math": [ "u_pain_before_time_freeze", "=", "u_pain()" ] }, { "math": [ "u_kcal_before_time_freeze", "=", "u_calories()" ] }, { "math": [ "u_thirst_before_time_freeze", "=", "u_val('thirst')" ] }, @@ -370,7 +369,6 @@ "condition": { "compare_string": [ "effect_xedra_time_freeze", { "context_val": "effect" } ] }, "effect": [ "u_cancel_activity", - { "math": [ "u_hp('ALL')", "=", "u_hp_before_time_freeze" ] }, { "math": [ "u_pain()", "=", "u_pain_before_time_freeze" ] }, { "math": [ "u_calories()", "=", "u_kcal_before_time_freeze" ] }, { "math": [ "u_val('thirst')", "=", "u_thirst_before_time_freeze" ] }, diff --git a/src/player_hardcoded_effects.cpp b/src/player_hardcoded_effects.cpp index 057cfcdbc3f43..7bf30276e5892 100644 --- a/src/player_hardcoded_effects.cpp +++ b/src/player_hardcoded_effects.cpp @@ -105,6 +105,7 @@ static const json_character_flag json_flag_ALARMCLOCK( "ALARMCLOCK" ); static const json_character_flag json_flag_BIONIC_LIMB( "BIONIC_LIMB" ); static const json_character_flag json_flag_BLEEDSLOW( "BLEEDSLOW" ); static const json_character_flag json_flag_BLEEDSLOW2( "BLEEDSLOW2" ); +static const json_character_flag json_flag_CANNOT_TAKE_DAMAGE( "CANNOT_TAKE_DAMAGE" ); static const json_character_flag json_flag_PAIN_IMMUNE( "PAIN_IMMUNE" ); static const json_character_flag json_flag_SEESLEEP( "SEESLEEP" ); @@ -310,6 +311,10 @@ static void eff_fun_rat( Character &u, effect &it ) } static void eff_fun_bleed( Character &u, effect &it ) { + if( u.has_flag( json_flag_CANNOT_TAKE_DAMAGE ) ) { + return; + } + // Presuming that during the first-aid process you're putting pressure // on the wound or otherwise suppressing the flow. (Kits contain either // QuikClot or bandages per the recipe.) From cb4399e4c33e239f7e4003c8c3696d09dd4b2637 Mon Sep 17 00:00:00 2001 From: b3brodie Date: Wed, 27 Nov 2024 03:06:51 -0800 Subject: [PATCH 29/48] Fix temperature being affected by body wetness with no temperature change flag --- src/character.cpp | 4 ++++ src/character_body.cpp | 2 +- 2 files changed, 5 insertions(+), 1 deletion(-) diff --git a/src/character.cpp b/src/character.cpp index 25577e54f5a8d..60ef1aa3e3edf 100644 --- a/src/character.cpp +++ b/src/character.cpp @@ -297,6 +297,7 @@ static const json_character_flag json_flag_ALARMCLOCK( "ALARMCLOCK" ); static const json_character_flag json_flag_ALWAYS_HEAL( "ALWAYS_HEAL" ); static const json_character_flag json_flag_BIONIC_LIMB( "BIONIC_LIMB" ); static const json_character_flag json_flag_BLIND( "BLIND" ); +static const json_character_flag json_flag_CANNOT_CHANGE_TEMPERATURE( "CANNOT_CHANGE_TEMPERATURE" ); static const json_character_flag json_flag_CANNOT_MOVE( "CANNOT_MOVE" ); static const json_character_flag json_flag_CANNOT_TAKE_DAMAGE( "CANNOT_TAKE_DAMAGE" ); static const json_character_flag json_flag_CLAIRVOYANCE( "CLAIRVOYANCE" ); @@ -5647,6 +5648,9 @@ void Character::toolmod_add( item_location tool, item_location mod ) void Character::temp_equalizer( const bodypart_id &bp1, const bodypart_id &bp2 ) { + if (has_flag( json_flag_CANNOT_CHANGE_TEMPERATURE ) ) { + return; + } // Body heat is moved around. // Shift in one direction only, will be shifted in the other direction separately. const units::temperature_delta diff = ( get_part_temp_cur( bp2 ) - get_part_temp_cur( bp1 ) ) * diff --git a/src/character_body.cpp b/src/character_body.cpp index 047c74e307088..8530e00c86d1f 100644 --- a/src/character_body.cpp +++ b/src/character_body.cpp @@ -186,7 +186,7 @@ void Character::update_body_wetness( const w_point &weather ) // if under 50 in the menu or 7500 temp_conv you should be able to regulate temperature by sweating // with current calcs a character moving towards 7500 heat will at most move 5 temperature points // down to not having a slowdown - if( !bp->has_flag( json_flag_IGNORE_TEMP ) ) { + if( !bp->has_flag( json_flag_IGNORE_TEMP ) && !has_flag( json_flag_CANNOT_CHANGE_TEMPERATURE ) ) { mod_part_temp_cur( bp, -0.008_C_delta * clothing_mult ); } } From ae180e4f5415f945d984a0d8e78396c1eb9fced4 Mon Sep 17 00:00:00 2001 From: b3brodie Date: Wed, 27 Nov 2024 16:46:14 -0800 Subject: [PATCH 30/48] Add erosion buff to eater of dreams --- data/mods/Xedra_Evolved/effects/effects.json | 11 +++++ .../eocs/spell_learning_eoc.json | 3 +- .../itemgroups/spell_artifacts/eater.json | 2 +- .../spell_learning_items_eater.json | 15 +++++++ .../Xedra_Evolved/spells/eater_spells.json | 43 +++++++++++++++++++ 5 files changed, 72 insertions(+), 2 deletions(-) diff --git a/data/mods/Xedra_Evolved/effects/effects.json b/data/mods/Xedra_Evolved/effects/effects.json index 3e900628780b7..7f1409587e51d 100644 --- a/data/mods/Xedra_Evolved/effects/effects.json +++ b/data/mods/Xedra_Evolved/effects/effects.json @@ -2734,5 +2734,16 @@ "max_duration": "2 seconds", "show_in_info": true, "enchantments": [ { "values": [ { "value": "SPEED", "multiply": 1 } ] } ] + }, + { + "type": "effect_type", + "id": "effect_xedra_eater_erosion", + "name": [ "Erosion" ], + "desc": [ "You maintain a field of unstable time around you. When you attack targets in melee they will degrade over time." ], + "remove_message": "Your field of unstable time fades.", + "rating": "good", + "max_intensity": 1, + "show_in_info": true, + "enchantments": [ { "hit_you_effect": [ { "id": "xedra_eater_erosion_attack" } ] } ] } ] diff --git a/data/mods/Xedra_Evolved/eocs/spell_learning_eoc.json b/data/mods/Xedra_Evolved/eocs/spell_learning_eoc.json index 22e33f6f09527..06967cea6b685 100644 --- a/data/mods/Xedra_Evolved/eocs/spell_learning_eoc.json +++ b/data/mods/Xedra_Evolved/eocs/spell_learning_eoc.json @@ -98,7 +98,8 @@ "spell_weak", "spell_unbreakable", "point_blank", - "xedra_eater_stabilize_reality" + "xedra_eater_stabilize_reality", + "xedra_eater_erosion" ], "target_var": { "var_val": "random_eater_spell" } } diff --git a/data/mods/Xedra_Evolved/itemgroups/spell_artifacts/eater.json b/data/mods/Xedra_Evolved/itemgroups/spell_artifacts/eater.json index 9c376267df0e6..fabf81ed4fbc6 100644 --- a/data/mods/Xedra_Evolved/itemgroups/spell_artifacts/eater.json +++ b/data/mods/Xedra_Evolved/itemgroups/spell_artifacts/eater.json @@ -128,6 +128,6 @@ "type": "item_group", "id": "xe_eater_spell_tier4", "subtype": "distribution", - "entries": [ { "item": "artifact_eye_right", "prob": 100 }, { "item": "ring_artifact", "prob": 50 } ] + "entries": [ { "item": "artifact_eye_right", "prob": 100 }, { "item": "ring_artifact", "prob": 50 }, { "item": "artifact_sand", "prob": 50 } ] } ] diff --git a/data/mods/Xedra_Evolved/items/spell_learning_items/spell_learning_items_eater.json b/data/mods/Xedra_Evolved/items/spell_learning_items/spell_learning_items_eater.json index 3add8a36a9347..35201f9157c26 100644 --- a/data/mods/Xedra_Evolved/items/spell_learning_items/spell_learning_items_eater.json +++ b/data/mods/Xedra_Evolved/items/spell_learning_items/spell_learning_items_eater.json @@ -322,5 +322,20 @@ "symbol": "0", "color": "dark_gray", "use_action": { "type": "learn_spell", "spells": [ "xedra_eater_stabilize_reality" ] } + }, + { + "id": "artifact_sand", + "type": "GENERIC", + "category": "artifacts", + "name": { "str": "clumped sand" }, + "description": "A pile of gray sand that is clumped together. When you separate the pieces they seem to flow back together.", + "weight": "100 g", + "volume": "100 ml", + "price": "10 USD", + "price_postapoc": "10 cent", + "material": [ "forged_dreamstuff" ], + "symbol": "0", + "color": "dark_gray", + "use_action": { "type": "learn_spell", "spells": [ "xedra_eater_erosion" ] } } ] diff --git a/data/mods/Xedra_Evolved/spells/eater_spells.json b/data/mods/Xedra_Evolved/spells/eater_spells.json index ab8be17f1c4df..8a9fb125a06fb 100644 --- a/data/mods/Xedra_Evolved/spells/eater_spells.json +++ b/data/mods/Xedra_Evolved/spells/eater_spells.json @@ -561,6 +561,49 @@ "max_duration": { "math": [ "spell_time(time(' 3 h'))" ] }, "duration_increment": { "math": [ "spell_time(time(' 6 m'))" ] } }, + { + "id": "xedra_eater_erosion", + "type": "SPELL", + "name": "Erosion", + "description": "Generate an unstable field of time close to your body that erodes creatures you attack in melee over time.", + "teachable": false, + "valid_targets": [ "self" ], + "effect": "attack", + "effect_str": "effect_xedra_eater_erosion", + "shape": "blast", + "flags": [ "NO_LEGS", "NO_HANDS", "SILENT", "NO_EXPLOSION_SFX" ], + "skill": "deduction", + "spell_class": "EATER", + "energy_source": "MANA", + "difficulty": 10, + "base_casting_time": 600, + "final_casting_time": 100, + "casting_time_increment": -20, + "base_energy_cost": 1200, + "final_energy_cost": 600, + "energy_increment": -30, + "max_level": { "math": [ "eater_level(1)" ] }, + "min_duration": { "math": [ "spell_time(time(' 5 m'))" ] }, + "max_duration": { "math": [ "spell_time(time(' 2 h'))" ] }, + "duration_increment": { "math": [ "spell_time(time(' 6 m'))" ] } + }, + { + "id": "xedra_eater_erosion_attack", + "type": "SPELL", + "name": "Erosion - Attack", + "description": "This causes the dot when attacking targets with the erosion buff. Having the spell is a bug.", + "valid_targets": [ "hostile" ], + "flags": [ "SILENT", "NO_PROJECTILE", "NO_EXPLOSION_SFX" ], + "effect": "attack", + "shape": "blast", + "min_dot": 2, + "max_dot": 2, + "min_range": 1, + "max_range": 1, + "min_duration": { "math": [ "u_spell_level('xedra_eater_erosion')*100" ] }, + "max_duration": { "math": [ "u_spell_level('xedra_eater_erosion')*100" ] }, + "damage_type": "biological" + }, { "id": "point_blank", "type": "SPELL", From 8e35ca24a0ffd7877f01732c3939831d0088a96c Mon Sep 17 00:00:00 2001 From: b3brodie Date: Wed, 27 Nov 2024 17:40:13 -0800 Subject: [PATCH 31/48] documentation pass --- doc/JSON_FLAGS.md | 1 + 1 file changed, 1 insertion(+) diff --git a/doc/JSON_FLAGS.md b/doc/JSON_FLAGS.md index 33e94c334922d..0ed6accdf8c69 100644 --- a/doc/JSON_FLAGS.md +++ b/doc/JSON_FLAGS.md @@ -371,6 +371,7 @@ Character flags can be `trait_id`, `json_flag_id` or `flag_id`. Some of these a - ```ENHANCED_VISION``` Increases the scouting range, similarly to `ZOOM` item flag. - ```EYE_MEMBRANE``` Lets you see underwater. - ```FEATHER_FALL``` You are immune to fall damage. +- ```FREEZE_EFFECTS``` Effects do not progress in duration and new effects cannot be applied. An effect with this flag is ignored and will progress normally. - ```GILLS``` You can breathe underwater. - ```GLARE_RESIST``` Protect your eyes from glare like sunglasses. - ```GLIDE``` You can glide from ledges without the use of wings, as if by magic. From c0222dfc39a5196f88caa32c669b927fcc8e5d6f Mon Sep 17 00:00:00 2001 From: b3brodie Date: Wed, 27 Nov 2024 17:44:26 -0800 Subject: [PATCH 32/48] documentation clarity --- doc/JSON_FLAGS.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/doc/JSON_FLAGS.md b/doc/JSON_FLAGS.md index 0ed6accdf8c69..1970da9714d1e 100644 --- a/doc/JSON_FLAGS.md +++ b/doc/JSON_FLAGS.md @@ -371,7 +371,7 @@ Character flags can be `trait_id`, `json_flag_id` or `flag_id`. Some of these a - ```ENHANCED_VISION``` Increases the scouting range, similarly to `ZOOM` item flag. - ```EYE_MEMBRANE``` Lets you see underwater. - ```FEATHER_FALL``` You are immune to fall damage. -- ```FREEZE_EFFECTS``` Effects do not progress in duration and new effects cannot be applied. An effect with this flag is ignored and will progress normally. +- ```FREEZE_EFFECTS``` Effects do not progress in duration. An effect with this flag is ignored and will progress normally. - ```GILLS``` You can breathe underwater. - ```GLARE_RESIST``` Protect your eyes from glare like sunglasses. - ```GLIDE``` You can glide from ledges without the use of wings, as if by magic. From 2a5b47b140be4d2ae067a75e632b63a210dd8321 Mon Sep 17 00:00:00 2001 From: b3brodie Date: Wed, 27 Nov 2024 17:58:14 -0800 Subject: [PATCH 33/48] The greatest lint of them all --- data/mods/Xedra_Evolved/effects/effects.json | 2 +- data/mods/Xedra_Evolved/effects/emit.json | 26 -------- data/mods/Xedra_Evolved/emit.json | 28 ++++++++- data/mods/Xedra_Evolved/eocs/misc_eoc.json | 7 ++- data/mods/Xedra_Evolved/field_type.json | 31 +++++----- .../itemgroups/spell_artifacts/dreamer.json | 3 +- .../itemgroups/spell_artifacts/eater.json | 6 +- .../Xedra_Evolved/items/inventor/misc.json | 2 +- .../mods/Xedra_Evolved/mutations/classes.json | 9 +-- .../recipes/dreamforged_tool.json | 2 +- .../mods/Xedra_Evolved/spells/spell_eocs.json | 9 ++- src/action.cpp | 2 +- src/activity_item_handling.cpp | 3 +- src/character.cpp | 29 +++++---- src/do_turn.cpp | 6 +- src/field.cpp | 4 +- src/field.h | 2 +- src/field_type.cpp | 2 +- src/game.cpp | 8 ++- src/magic_spell_effect.cpp | 7 ++- src/map.cpp | 18 +++--- src/map.h | 12 ++-- src/mattack_actors.cpp | 3 +- src/melee.cpp | 16 +++-- src/monattack.cpp | 3 +- src/monmove.cpp | 60 ++++++++++--------- src/monster.cpp | 3 +- src/npctalk.cpp | 2 +- src/player_hardcoded_effects.cpp | 2 +- src/ranged.cpp | 6 +- 30 files changed, 176 insertions(+), 137 deletions(-) delete mode 100644 data/mods/Xedra_Evolved/effects/emit.json diff --git a/data/mods/Xedra_Evolved/effects/effects.json b/data/mods/Xedra_Evolved/effects/effects.json index 7f1409587e51d..7b42435d0b17f 100644 --- a/data/mods/Xedra_Evolved/effects/effects.json +++ b/data/mods/Xedra_Evolved/effects/effects.json @@ -2701,7 +2701,7 @@ "remove_message": "Everything is suddenly different.", "rating": "neutral", "immune_flags": [ "DIMENSIONAL_ANCHOR", "STABILIZED_TIMELINE" ], - "flags": [ "CANNOT_ATTACK", "CANNOT_MOVE", "CANNOT_TAKE_DAMAGE", "CANNOT_CHANGE_TEMPERATURE", "FREEZE_EFFECTS" ], + "flags": [ "CANNOT_ATTACK", "CANNOT_MOVE", "CANNOT_TAKE_DAMAGE", "CANNOT_CHANGE_TEMPERATURE", "FREEZE_EFFECTS" ], "show_in_info": true }, { diff --git a/data/mods/Xedra_Evolved/effects/emit.json b/data/mods/Xedra_Evolved/effects/emit.json deleted file mode 100644 index 8a4885a6d88a8..0000000000000 --- a/data/mods/Xedra_Evolved/effects/emit.json +++ /dev/null @@ -1,26 +0,0 @@ -[ - { - "id": "emit_changeling_mist", - "type": "emit", - "//": "Slow infrequent leak of changeling mist. This should summon various changeling monsters similar to Angle Dog Fog.", - "field": "fd_mirrored", - "intensity": 3, - "qty": 10, - "chance": 15 - }, - { - "id": "emit_blood_karma", - "type": "emit", - "field": "fd_blood_karma", - "intensity": 1, - "chance": 100, - "qty": 1 - }, - { - "id": "emit_obscuring_fog", - "type": "emit", - "field": "fd_obscuring_fog", - "intensity": 3, - "qty": 80 - } -] diff --git a/data/mods/Xedra_Evolved/emit.json b/data/mods/Xedra_Evolved/emit.json index ab40c276321ca..f4c562f85a07a 100644 --- a/data/mods/Xedra_Evolved/emit.json +++ b/data/mods/Xedra_Evolved/emit.json @@ -1,4 +1,4 @@ -[ +[ { "id": "xedra_dreamer_emit_accelerated_time", "type": "emit", @@ -6,5 +6,29 @@ "intensity": 1, "qty": 20, "chance": 100 + }, + { + "id": "emit_changeling_mist", + "type": "emit", + "//": "Slow infrequent leak of changeling mist. This should summon various changeling monsters similar to Angle Dog Fog.", + "field": "fd_mirrored", + "intensity": 3, + "qty": 10, + "chance": 15 + }, + { + "id": "emit_blood_karma", + "type": "emit", + "field": "fd_blood_karma", + "intensity": 1, + "chance": 100, + "qty": 1 + }, + { + "id": "emit_obscuring_fog", + "type": "emit", + "field": "fd_obscuring_fog", + "intensity": 3, + "qty": 80 } -] \ No newline at end of file +] diff --git a/data/mods/Xedra_Evolved/eocs/misc_eoc.json b/data/mods/Xedra_Evolved/eocs/misc_eoc.json index 0ae2bcb5737fb..71da76029f2ab 100644 --- a/data/mods/Xedra_Evolved/eocs/misc_eoc.json +++ b/data/mods/Xedra_Evolved/eocs/misc_eoc.json @@ -341,8 +341,11 @@ "effect": [ { "math": [ "u_xedra_last_damage_taken=_damage" ] }, { "math": [ "u_xedra_last_pain_taken=_pain" ] }, - { "set_string_var": { "context_val": "bodypart" }, "target_var": { "u_val": "xedra_last_damage_taken_bodypart" } } - ] + { + "set_string_var": { "context_val": "bodypart" }, + "target_var": { "u_val": "xedra_last_damage_taken_bodypart" } + } + ] }, { "type": "effect_on_condition", diff --git a/data/mods/Xedra_Evolved/field_type.json b/data/mods/Xedra_Evolved/field_type.json index 53ff1c47cbaed..aa4dfad5b845c 100644 --- a/data/mods/Xedra_Evolved/field_type.json +++ b/data/mods/Xedra_Evolved/field_type.json @@ -257,33 +257,34 @@ { "id": "fd_frozen_time", "type": "field_type", - "intensity_levels": [ - { "name": "frozen time", "sym": "O", "color": "light_gray", "transparent": true, "move_cost": -1000 } - ], + "intensity_levels": [ { "name": "frozen time", "sym": "O", "color": "light_gray", "transparent": true, "move_cost": -1000 } ], "priority": 100, "display_items": true, "display_field": true, "description_affix": "in", "half_life": "1 seconds", "linear_half_life": true, - "bash": { - "str_min": 10000, - "sound_vol": 0, - "sound_fail_vol": 0, - "msg_success": "Your strength is stronger than time itself!" - }, + "bash": { "str_min": 10000, "sound_vol": 0, "sound_fail_vol": 0, "msg_success": "Your strength is stronger than time itself!" }, "immunity_data": { "flags": [ "STABILIZED_TIMELINE" ] } }, { "id": "fd_xedra_dreamer_accelerated_time", "type": "field_type", "intensity_levels": [ - { "name": "accelerated time", "sym": "o", "color": "light_gray", "transparent": true, "effects": [{ - "effect_id": "effect_xedra_dreamer_accelerated_time", - "min_duration": "2 seconds", - "max_duration": "2 seconds", - "intensity": 1 - }] } + { + "name": "accelerated time", + "sym": "o", + "color": "light_gray", + "transparent": true, + "effects": [ + { + "effect_id": "effect_xedra_dreamer_accelerated_time", + "min_duration": "2 seconds", + "max_duration": "2 seconds", + "intensity": 1 + } + ] + } ], "priority": 50, "display_items": true, diff --git a/data/mods/Xedra_Evolved/itemgroups/spell_artifacts/dreamer.json b/data/mods/Xedra_Evolved/itemgroups/spell_artifacts/dreamer.json index f686ac71ae92f..4c7e108fc3c5e 100644 --- a/data/mods/Xedra_Evolved/itemgroups/spell_artifacts/dreamer.json +++ b/data/mods/Xedra_Evolved/itemgroups/spell_artifacts/dreamer.json @@ -129,7 +129,6 @@ "type": "item_group", "id": "xe_dreamer_spell_tier4", "subtype": "distribution", - "entries": [ { "item": "artifact_karma_arms", "prob": 50 }, - { "item": "artifact_dreamer_accelerated_time", "prob": 50 } ] + "entries": [ { "item": "artifact_karma_arms", "prob": 50 }, { "item": "artifact_dreamer_accelerated_time", "prob": 50 } ] } ] diff --git a/data/mods/Xedra_Evolved/itemgroups/spell_artifacts/eater.json b/data/mods/Xedra_Evolved/itemgroups/spell_artifacts/eater.json index fabf81ed4fbc6..cbfbd8bac89d7 100644 --- a/data/mods/Xedra_Evolved/itemgroups/spell_artifacts/eater.json +++ b/data/mods/Xedra_Evolved/itemgroups/spell_artifacts/eater.json @@ -128,6 +128,10 @@ "type": "item_group", "id": "xe_eater_spell_tier4", "subtype": "distribution", - "entries": [ { "item": "artifact_eye_right", "prob": 100 }, { "item": "ring_artifact", "prob": 50 }, { "item": "artifact_sand", "prob": 50 } ] + "entries": [ + { "item": "artifact_eye_right", "prob": 100 }, + { "item": "ring_artifact", "prob": 50 }, + { "item": "artifact_sand", "prob": 50 } + ] } ] diff --git a/data/mods/Xedra_Evolved/items/inventor/misc.json b/data/mods/Xedra_Evolved/items/inventor/misc.json index fd0e1f45093fd..2f222c701ba18 100644 --- a/data/mods/Xedra_Evolved/items/inventor/misc.json +++ b/data/mods/Xedra_Evolved/items/inventor/misc.json @@ -171,7 +171,7 @@ "use_action": { "type": "cast_spell", "spell_id": "xedra_inventor_time_pierce", - "no_fail": true, + "no_fail": true, "level": 1, "need_wielding": true, "mundane": true diff --git a/data/mods/Xedra_Evolved/mutations/classes.json b/data/mods/Xedra_Evolved/mutations/classes.json index b5e4490163573..b0a4897f856b7 100644 --- a/data/mods/Xedra_Evolved/mutations/classes.json +++ b/data/mods/Xedra_Evolved/mutations/classes.json @@ -9,6 +9,7 @@ "purifiable": false, "valid": false, "enchantments": [ "BONUS_DREAMER" ], + "cancels": [ "EATER" ], "moncams": [ [ "mon_shifter", 100 ], [ "mon_duplicator", 100 ], @@ -30,7 +31,7 @@ "purifiable": false, "valid": false, "enchantments": [ "BONUS_EATER" ], - "//": "removed for testing. remember to put cancels back", + "cancels": [ "DREAMER" ], "spells_learned": [ [ "eat_dreamdross", 0 ] ] }, { @@ -42,8 +43,8 @@ "starting_trait": false, "purifiable": false, "valid": false, - "//": "removed for testing. remember to put cancels back", - "enchantments": [ "BONUS_DREAMSMITH" ] + "enchantments": [ "BONUS_DREAMSMITH" ], + "cancels": [ "INVENTOR" ] }, { "type": "mutation", @@ -55,7 +56,7 @@ "purifiable": false, "valid": false, "enchantments": [ "BONUS_INVENTOR" ], - "//": "removed for testing. remember to put cancels back", + "cancels": [ "DREAMSMITH" ], "vitamin_rates": [ [ "creative_spark", -64800 ] ] }, { diff --git a/data/mods/Xedra_Evolved/recipes/dreamforged_tool.json b/data/mods/Xedra_Evolved/recipes/dreamforged_tool.json index 8a5c8dcc678d8..dd34642cd6971 100644 --- a/data/mods/Xedra_Evolved/recipes/dreamforged_tool.json +++ b/data/mods/Xedra_Evolved/recipes/dreamforged_tool.json @@ -86,7 +86,7 @@ "type": "recipe", "result": "xedra_dreamsmith_time_watch", "copy-from": "dreamforged_hacksaw", - "components": [ [ [ "forged_dreamstuff_ingot", 10 ] ] ], + "components": [ [ [ "forged_dreamstuff_ingot", 24 ] ] ], "time": "24 h" } ] diff --git a/data/mods/Xedra_Evolved/spells/spell_eocs.json b/data/mods/Xedra_Evolved/spells/spell_eocs.json index 2e0b8186e29ce..0bf9e9f570d2e 100644 --- a/data/mods/Xedra_Evolved/spells/spell_eocs.json +++ b/data/mods/Xedra_Evolved/spells/spell_eocs.json @@ -85,13 +85,12 @@ { "type": "effect_on_condition", "id": "EOC_GENERATE_ACCELERATED_TIME_CONTINUE", - "condition": { "and": [ { "u_has_effect": "effect_xedra_dreamer_generate_accelerated_time" }, { "math": [ "u_val('mana') >= 200" ] } ] }, + "condition": { + "and": [ { "u_has_effect": "effect_xedra_dreamer_generate_accelerated_time" }, { "math": [ "u_val('mana') >= 200" ] } ] + }, "effect": [ { "math": [ "u_val('mana')", "-=", "200" ] }, - { - "u_message": "The grayscale starts to recede from your vision before it quickly reverts.", - "type": "good" - }, + { "u_message": "The grayscale starts to recede from your vision before it quickly reverts.", "type": "good" }, { "run_eocs": "EOC_GENERATE_ACCELERATED_TIME_CONTINUE", "time_in_future": { "math": [ "((u_spell_level('xedra_dreamer_generate_accelerated_time')+1)*750)" ] } diff --git a/src/action.cpp b/src/action.cpp index e7b99965c3d1d..cdd5c54ceb846 100644 --- a/src/action.cpp +++ b/src/action.cpp @@ -730,7 +730,7 @@ static bool can_pickup_at( const tripoint_bub_ms &p ) bool can_interact_at( action_id action, const tripoint_bub_ms &p ) { map &here = get_map(); - if( here.impassable_field_at(p) ) { + if( here.impassable_field_at( p ) ) { return false; } tripoint_bub_ms player_pos = get_player_character().pos_bub(); diff --git a/src/activity_item_handling.cpp b/src/activity_item_handling.cpp index 20dcfbab73591..22e45427d4dcf 100644 --- a/src/activity_item_handling.cpp +++ b/src/activity_item_handling.cpp @@ -2410,7 +2410,8 @@ static bool mine_activity( Character &you, const tripoint_bub_ms &src_loc ) } ); map &here = get_map(); if( mining_inv.empty() || you.is_mounted() || you.is_underwater() || here.veh_at( src_loc ) || - !here.has_flag( ter_furn_flag::TFLAG_MINEABLE, src_loc ) || you.has_effect( effect_incorporeal ) || here.impassable_field_at(src_loc) ) { + !here.has_flag( ter_furn_flag::TFLAG_MINEABLE, src_loc ) || you.has_effect( effect_incorporeal ) || + here.impassable_field_at( src_loc ) ) { return false; } item *chosen_item = nullptr; diff --git a/src/character.cpp b/src/character.cpp index 60ef1aa3e3edf..bac6fee0426c1 100644 --- a/src/character.cpp +++ b/src/character.cpp @@ -1234,7 +1234,8 @@ ret_val Character::can_try_dodge( bool ignore_dodges_left ) const { //If we're asleep or busy we can't dodge if( in_sleep_state() || has_effect( effect_narcosis ) || - has_effect( effect_winded ) || has_effect( effect_fearparalyze ) || is_driving() || has_flag( json_flag_CANNOT_MOVE ) ) { + has_effect( effect_winded ) || has_effect( effect_fearparalyze ) || is_driving() || + has_flag( json_flag_CANNOT_MOVE ) ) { add_msg_debug( debugmode::DF_MELEE, "Unable to dodge (sleeping, winded, or driving)" ); return ret_val::make_failure(); } @@ -5648,7 +5649,7 @@ void Character::toolmod_add( item_location tool, item_location mod ) void Character::temp_equalizer( const bodypart_id &bp1, const bodypart_id &bp2 ) { - if (has_flag( json_flag_CANNOT_CHANGE_TEMPERATURE ) ) { + if( has_flag( json_flag_CANNOT_CHANGE_TEMPERATURE ) ) { return; } // Body heat is moved around. @@ -8137,7 +8138,8 @@ void Character::on_hit( Creature *source, bodypart_id bp_hit, void Character::apply_damage( Creature *source, bodypart_id hurt, int dam, const bool bypass_med ) { - if( is_dead_state() || has_effect( effect_incorporeal ) || has_flag( json_flag_CANNOT_TAKE_DAMAGE) ) { + if( is_dead_state() || has_effect( effect_incorporeal ) || + has_flag( json_flag_CANNOT_TAKE_DAMAGE ) ) { // don't do any more damage if we're already dead // Or if we're debugging and don't want to die // Or we are intangible @@ -8160,10 +8162,12 @@ void Character::apply_damage( Creature *source, bodypart_id hurt, int dam, mod_part_hp_cur( part_to_damage, - dam_to_bodypart ); if( source ) { - cata::event e = cata::event::make( getID(), dam_to_bodypart, part_to_damage.id(), pain ); + cata::event e = cata::event::make( getID(), dam_to_bodypart, + part_to_damage.id(), pain ); get_event_bus().send_with_talker( this, source, e ); } else { - get_event_bus().send( getID(), dam_to_bodypart, part_to_damage.id(), pain ); + get_event_bus().send( getID(), dam_to_bodypart, + part_to_damage.id(), pain ); } if( !weapon.is_null() && !can_wield( weapon ).success() && @@ -8199,7 +8203,7 @@ void Character::apply_damage( Creature *source, bodypart_id hurt, int dam, dealt_damage_instance Character::deal_damage( Creature *source, bodypart_id bp, const damage_instance &d, const weakpoint_attack &attack ) { - if( has_effect( effect_incorporeal ) || has_flag( json_flag_CANNOT_TAKE_DAMAGE) ) { + if( has_effect( effect_incorporeal ) || has_flag( json_flag_CANNOT_TAKE_DAMAGE ) ) { return dealt_damage_instance(); } @@ -8371,7 +8375,7 @@ void Character::healall( int dam ) void Character::hurtall( int dam, Creature *source, bool disturb /*= true*/ ) { if( is_dead_state() || has_effect( effect_incorporeal ) || - dam <= 0 || has_flag( json_flag_CANNOT_TAKE_DAMAGE) ) { + dam <= 0 || has_flag( json_flag_CANNOT_TAKE_DAMAGE ) ) { return; } @@ -8385,10 +8389,12 @@ void Character::hurtall( int dam, Creature *source, bool disturb /*= true*/ ) mod_part_hp_cur( bp, - dam_to_bodypart ); if( source ) { - cata::event e = cata::event::make( getID(), dam_to_bodypart, bp.id(), pain / body_parts.size() ); + cata::event e = cata::event::make( getID(), dam_to_bodypart, + bp.id(), pain / body_parts.size() ); get_event_bus().send_with_talker( this, source == nullptr ? nullptr : source, e ); } else { - get_event_bus().send( getID(), dam_to_bodypart, bp.id(), pain / body_parts.size() ); + get_event_bus().send( getID(), dam_to_bodypart, bp.id(), + pain / body_parts.size() ); } } @@ -10626,7 +10632,8 @@ void Character::echo_pulse() } } // It's not moving. Must be an obstacle - if( critter->has_flag( mon_flag_IMMOBILE ) || critter->has_effect_with_flag( json_flag_CANNOT_MOVE ) ) { + if( critter->has_flag( mon_flag_IMMOBILE ) || + critter->has_effect_with_flag( json_flag_CANNOT_MOVE ) ) { echo_string = _( "click." ); } sounds::sound( origin, echo_volume, sounds::sound_t::sensory, _( echo_string ), false, @@ -12411,7 +12418,7 @@ int Character::get_lift_assist() const bool Character::immune_to( const bodypart_id &bp, damage_unit dam ) const { if( is_immune_damage( dam.type ) || - has_effect( effect_incorporeal ) || has_flag( json_flag_CANNOT_TAKE_DAMAGE) ) { + has_effect( effect_incorporeal ) || has_flag( json_flag_CANNOT_TAKE_DAMAGE ) ) { return true; } diff --git a/src/do_turn.cpp b/src/do_turn.cpp index 9f36084f57067..d71ee78ee7b4d 100644 --- a/src/do_turn.cpp +++ b/src/do_turn.cpp @@ -271,7 +271,8 @@ void monmove() for( monster &critter : g->all_monsters() ) { // Critters in impassable tiles get pushed away, unless it's not impassable for them - if( !critter.is_dead() && (m.impassable( critter.pos_bub() ) && !m.get_impassable_field_at( critter.pos_bub() ).has_value() ) && + if( !critter.is_dead() && ( m.impassable( critter.pos_bub() ) && + !m.get_impassable_field_at( critter.pos_bub() ).has_value() ) && !critter.can_move_to( critter.pos_bub() ) ) { dbg( D_ERROR ) << "game:monmove: " << critter.name() << " can't move to its location! (" << critter.posx() @@ -491,7 +492,8 @@ bool do_turn() u.gravity_check(); // If you're inside a wall or something and haven't been telefragged, let's get you out. - if( (m.impassable( u.pos_bub() ) && !m.impassable_field_at( u.pos_bub() ) ) && !m.has_flag( ter_furn_flag::TFLAG_CLIMBABLE, u.pos_bub() ) ) { + if( ( m.impassable( u.pos_bub() ) && !m.impassable_field_at( u.pos_bub() ) ) && + !m.has_flag( ter_furn_flag::TFLAG_CLIMBABLE, u.pos_bub() ) ) { u.stagger(); } diff --git a/src/field.cpp b/src/field.cpp index 1c3e6a66dcce1..6c9e05f987ca5 100644 --- a/src/field.cpp +++ b/src/field.cpp @@ -84,7 +84,7 @@ void field_entry::initialize_decay() decay_time = calendar::turn - age + type.obj().half_life; } else { std::exponential_distribution<> d( 1.0f / ( M_LOG2E * to_turns - ( type.obj().half_life ) ) ); + ( type.obj().half_life ) ) ); decay_time = calendar::turn - age + time_duration::from_turns( d( rng_get_engine() ) ); } } @@ -269,7 +269,7 @@ int field::total_move_cost() const bool field::any_negative_move_cost() const { for( const auto &fld : *_field_type_list ) { - if(fld.second.get_intensity_level().move_cost < 0) { + if( fld.second.get_intensity_level().move_cost < 0 ) { return true; } } diff --git a/src/field.h b/src/field.h index cc0ad42bc6218..a4a9f99273947 100644 --- a/src/field.h +++ b/src/field.h @@ -178,7 +178,7 @@ class field * Returns the total move cost from all fields. */ int total_move_cost() const; - + // Whether any individual field has a move cost below 0. bool any_negative_move_cost() const; diff --git a/src/field_type.cpp b/src/field_type.cpp index a36aac9cd0112..4518fef3b114c 100644 --- a/src/field_type.cpp +++ b/src/field_type.cpp @@ -294,7 +294,7 @@ void field_type::load( const JsonObject &jo, const std::string_view ) optional( jo, was_loaded, "has_fume", has_fume, false ); optional( jo, was_loaded, "priority", priority, 0 ); optional( jo, was_loaded, "half_life", half_life, 0_turns ); - optional (jo, was_loaded, "linear_half_life", linear_half_life, false); + optional( jo, was_loaded, "linear_half_life", linear_half_life, false ); const auto description_affix_reader = enum_flags_reader { "description affixes" }; optional( jo, was_loaded, "description_affix", desc_affix, description_affix_reader, description_affix::DESCRIPTION_AFFIX_IN ); diff --git a/src/game.cpp b/src/game.cpp index 54034634b721b..351aadfd224ad 100644 --- a/src/game.cpp +++ b/src/game.cpp @@ -10631,9 +10631,11 @@ bool game::walk_move( const tripoint &dest_loc, const bool via_ramp, const bool u.grab( object_type::NONE ); } - const std::vector impassable_field_ids = m.get_impassable_field_type_ids_at( dest_loc ); + const std::vector impassable_field_ids = m.get_impassable_field_type_ids_at( + dest_loc ); - if( ( !m.passable_skip_fields(dest_loc) || (impassable_field_ids.size() > 0 && !u.is_immune_fields( impassable_field_ids ) ) ) && !pushing && !shifting_furniture ) { + if( ( !m.passable_skip_fields( dest_loc ) || ( impassable_field_ids.size() > 0 && + !u.is_immune_fields( impassable_field_ids ) ) ) && !pushing && !shifting_furniture ) { if( vp_there && u.mounted_creature && u.mounted_creature->has_flag( mon_flag_RIDEABLE_MECH ) && vp_there->vehicle().handle_potential_theft( u ) ) { tripoint diff = dest_loc - u.pos(); @@ -12076,7 +12078,7 @@ void game::vertical_move( int movez, bool force, bool peeking ) if( u.has_flag( json_flag_CANNOT_MOVE ) ) { return; } - + if( u.is_mounted() ) { monster *mons = u.mounted_creature.get(); if( mons->has_flag( mon_flag_RIDEABLE_MECH ) ) { diff --git a/src/magic_spell_effect.cpp b/src/magic_spell_effect.cpp index 3a994e606d5e0..2e62266f42311 100644 --- a/src/magic_spell_effect.cpp +++ b/src/magic_spell_effect.cpp @@ -1165,7 +1165,8 @@ void spell_effect::directed_push( const spell &sp, Creature &caster, const tripo } } -void spell_effect::spawn_ethereal_item( const spell &sp, Creature &caster, const tripoint_bub_ms ¢er ) +void spell_effect::spawn_ethereal_item( const spell &sp, Creature &caster, + const tripoint_bub_ms ¢er ) { Character *const character_at_target = get_creature_tracker().creature_at( center ); @@ -1183,7 +1184,7 @@ void spell_effect::spawn_ethereal_item( const spell &sp, Creature &caster, const } avatar &player_character = get_avatar(); - if (character_at_target == nullptr) { + if( character_at_target == nullptr ) { for( item &it : granted ) { // Spawned items are ethereal unless permanent and max level. Comestibles are never ethereal. if( !it.is_comestible() && !sp.has_flag( spell_flag::PERMANENT_ALL_LEVELS ) && @@ -1211,7 +1212,7 @@ void spell_effect::spawn_ethereal_item( const spell &sp, Creature &caster, const it.set_flag( json_flag_FIT ); player_character.wear_item( it, false ); } else if( !player_character.has_wield_conflicts( it ) && - !player_character.martial_arts_data->keep_hands_free && //No wield if hands free + !player_character.martial_arts_data->keep_hands_free && //No wield if hands free player_character.wield( it, 0 ) ) { // nothing to do } else { diff --git a/src/map.cpp b/src/map.cpp index 87d0a0afbdadc..f5f6272e1baf3 100644 --- a/src/map.cpp +++ b/src/map.cpp @@ -2517,12 +2517,14 @@ bool map::is_open_air( const tripoint_bub_ms &p ) const // Move cost: 3D -int map::move_cost( const tripoint &p, const vehicle *ignored_vehicle, const bool ignore_fields ) const +int map::move_cost( const tripoint &p, const vehicle *ignored_vehicle, + const bool ignore_fields ) const { return move_cost( tripoint_bub_ms( p ), ignored_vehicle, ignore_fields ); } -int map::move_cost( const tripoint_bub_ms &p, const vehicle *ignored_vehicle, const bool ignore_fields ) const +int map::move_cost( const tripoint_bub_ms &p, const vehicle *ignored_vehicle, + const bool ignore_fields ) const { // To save all of the bound checks and submaps fetching, we extract it // here instead of using furn(), field_at() and ter(). @@ -2544,7 +2546,7 @@ int map::move_cost( const tripoint_bub_ms &p, const vehicle *ignored_vehicle, co vehicle *const veh = ( !vp || &vp->vehicle() == ignored_vehicle ) ? nullptr : &vp->vehicle(); const int part = veh ? vp->part_index() : -1; - return move_cost_internal( furniture, terrain, (!ignore_fields ? field : nofield), veh, part ); + return move_cost_internal( furniture, terrain, ( !ignore_fields ? field : nofield ), veh, part ); } bool map::impassable( const tripoint &p ) const @@ -2574,7 +2576,7 @@ bool map::passable_skip_fields( const tripoint &p ) const bool map::passable_skip_fields( const tripoint_bub_ms &p ) const { - return move_cost( p, (const vehicle*)nullptr, true ) != 0; + return move_cost( p, ( const vehicle * )nullptr, true ) != 0; } int map::move_cost_ter_furn( const tripoint &p ) const @@ -4907,7 +4909,7 @@ bool map::open_door( Creature const &u, const tripoint &p, const bool inside, bool map::open_door( Creature const &u, const tripoint_bub_ms &p, const bool inside, const bool check_only ) { - if( u.has_effect( effect_incorporeal ) || impassable_field_at(p) ) { + if( u.has_effect( effect_incorporeal ) || impassable_field_at( p ) ) { return false; } const ter_t &ter = this->ter( p ).obj(); @@ -6865,7 +6867,7 @@ std::optional map::get_impassable_field_at( const tripoint_bub_ms & bool map::impassable_field_at( const tripoint &p ) { - return impassable_field_at( tripoint_bub_ms(p) ); + return impassable_field_at( tripoint_bub_ms( p ) ); } bool map::impassable_field_at( const tripoint_bub_ms &p ) @@ -6881,7 +6883,7 @@ bool map::impassable_field_at( const tripoint_bub_ms &p ) std::vector map::get_impassable_field_type_ids_at( const tripoint &p ) { - return get_impassable_field_type_ids_at( tripoint_bub_ms(p) ); + return get_impassable_field_type_ids_at( tripoint_bub_ms( p ) ); } std::vector map::get_impassable_field_type_ids_at( const tripoint_bub_ms &p ) @@ -6889,7 +6891,7 @@ std::vector map::get_impassable_field_type_ids_at( const tripoint std::vector fields; for( auto &fa : field_at( p ) ) { if( fa.second.get_intensity_level().move_cost < 0 ) { - fields.emplace_back(fa.first); + fields.emplace_back( fa.first ); } } return fields; diff --git a/src/map.h b/src/map.h index e6d815bf49729..57aff87147675 100644 --- a/src/map.h +++ b/src/map.h @@ -599,9 +599,12 @@ class map * n > 0 | x*n turns to move past this */ // TODO: fix point types (remove the first overload) - int move_cost( const tripoint &p, const vehicle *ignored_vehicle = nullptr, const bool ignore_fields = false ) const; - int move_cost( const tripoint_bub_ms &p, const vehicle *ignored_vehicle = nullptr, const bool ignore_fields = false ) const; - int move_cost( const point_bub_ms &p, const vehicle *ignored_vehicle = nullptr, const bool ignore_fields = false ) const { + int move_cost( const tripoint &p, const vehicle *ignored_vehicle = nullptr, + const bool ignore_fields = false ) const; + int move_cost( const tripoint_bub_ms &p, const vehicle *ignored_vehicle = nullptr, + const bool ignore_fields = false ) const; + int move_cost( const point_bub_ms &p, const vehicle *ignored_vehicle = nullptr, + const bool ignore_fields = false ) const { return move_cost( tripoint_bub_ms( p, abs_sub.z() ), ignored_vehicle, ignore_fields ); } // TODO: fix point types (remove the first overload) @@ -648,7 +651,8 @@ class map */ int combined_movecost( const tripoint_bub_ms &from, const tripoint_bub_ms &to, const vehicle *ignored_vehicle = nullptr, - int modifier = 0, bool flying = false, bool via_ramp = false, const bool ignore_fields = false ) const; + int modifier = 0, bool flying = false, bool via_ramp = false, + const bool ignore_fields = false ) const; /** * Returns true if a creature could walk from `from` to `to` in one step. diff --git a/src/mattack_actors.cpp b/src/mattack_actors.cpp index dd3b4439482e2..051969bd9217f 100644 --- a/src/mattack_actors.cpp +++ b/src/mattack_actors.cpp @@ -883,7 +883,8 @@ bool melee_actor::call( monster &z ) const } } } - if( throw_strength > 0 && !( target->has_flag( mon_flag_IMMOBILE ) || target->has_effect_with_flag( json_flag_CANNOT_MOVE ) ) ) { + if( throw_strength > 0 && !( target->has_flag( mon_flag_IMMOBILE ) || + target->has_effect_with_flag( json_flag_CANNOT_MOVE ) ) ) { if( g->fling_creature( target, coord_to_angle( z.pos(), target->pos() ), throw_strength ) ) { target->add_msg_player_or_npc( msg_type, throw_msg_u, diff --git a/src/melee.cpp b/src/melee.cpp index 6612b40465dc2..fcde53b9d1d33 100644 --- a/src/melee.cpp +++ b/src/melee.cpp @@ -543,7 +543,7 @@ bool Character::melee_attack( Creature &t, bool allow_special, const matec_id &f bool allow_unarmed, int forced_movecost ) { if( has_flag( json_flag_CANNOT_ATTACK ) ) { - add_msg_if_player( m_info, _("You are incapable of attacking!" ) ); + add_msg_if_player( m_info, _( "You are incapable of attacking!" ) ); return false; } if( has_effect( effect_incorporeal ) ) { @@ -698,7 +698,9 @@ bool Character::melee_attack_abstract( Creature &t, bool allow_special, } // Practice melee and relevant weapon skill (if any) except when using CQB bionic, if the creature is a hallucination, or if the creature cannot move and take damage. - if( !has_active_bionic( bio_cqb ) && !t.is_hallucination() && !( t.has_effect_with_flag( json_flag_CANNOT_MOVE ) && t.has_effect_with_flag( json_flag_CANNOT_TAKE_DAMAGE ) ) ) { + if( !has_active_bionic( bio_cqb ) && !t.is_hallucination() && + !( t.has_effect_with_flag( json_flag_CANNOT_MOVE ) && + t.has_effect_with_flag( json_flag_CANNOT_TAKE_DAMAGE ) ) ) { melee_train( *this, 2, std::min( 5, skill_training_cap ), cur_weap, attack_vector_vector_null ); } @@ -878,7 +880,9 @@ bool Character::melee_attack_abstract( Creature &t, bool allow_special, melee::melee_stats.damage_amount += dam; // Practice melee and relevant weapon skill (if any) except when using CQB bionic, if the creature is a hallucination, or if the creature cannot move and take damage. - if( !has_active_bionic( bio_cqb ) && !t.is_hallucination() && !( t.has_effect_with_flag( json_flag_CANNOT_MOVE ) && t.has_effect_with_flag( json_flag_CANNOT_TAKE_DAMAGE ) ) ) { + if( !has_active_bionic( bio_cqb ) && !t.is_hallucination() && + !( t.has_effect_with_flag( json_flag_CANNOT_MOVE ) && + t.has_effect_with_flag( json_flag_CANNOT_TAKE_DAMAGE ) ) ) { melee_train( *this, 5, std::min( 10, skill_training_cap ), cur_weap, vector_id ); } @@ -1783,7 +1787,8 @@ void Character::perform_technique( const ma_technique &technique, Creature &t, } } - if( technique.side_switch && !(t.has_flag( mon_flag_IMMOBILE ) || t.has_effect_with_flag( json_flag_CANNOT_MOVE ) ) ) { + if( technique.side_switch && !( t.has_flag( mon_flag_IMMOBILE ) || + t.has_effect_with_flag( json_flag_CANNOT_MOVE ) ) ) { const tripoint b = t.pos(); point new_; @@ -1809,7 +1814,8 @@ void Character::perform_technique( const ma_technique &technique, Creature &t, } } map &here = get_map(); - if( technique.knockback_dist && !( t.has_flag( mon_flag_IMMOBILE ) || t.has_effect_with_flag( json_flag_CANNOT_MOVE ) ) ) { + if( technique.knockback_dist && !( t.has_flag( mon_flag_IMMOBILE ) || + t.has_effect_with_flag( json_flag_CANNOT_MOVE ) ) ) { const tripoint_bub_ms prev_pos = t.pos_bub(); // track target startpoint for knockback_follow const point kb_offset( rng( -technique.knockback_spread, technique.knockback_spread ), rng( -technique.knockback_spread, technique.knockback_spread ) ); diff --git a/src/monattack.cpp b/src/monattack.cpp index a2fc8eebeb2c9..68ab815ea7d80 100644 --- a/src/monattack.cpp +++ b/src/monattack.cpp @@ -3871,7 +3871,8 @@ bool mattack::leech_spawner( monster *z ) const bool u_see = get_player_view().sees( *z ); std::list allies; for( monster &candidate : g->all_monsters() ) { - if( candidate.in_species( species_LEECH_PLANT ) && !(candidate.has_flag( mon_flag_IMMOBILE ) || candidate.has_flag( json_flag_CANNOT_MOVE ) ) ) { + if( candidate.in_species( species_LEECH_PLANT ) && !( candidate.has_flag( mon_flag_IMMOBILE ) || + candidate.has_flag( json_flag_CANNOT_MOVE ) ) ) { allies.push_back( &candidate ); } } diff --git a/src/monmove.cpp b/src/monmove.cpp index a73f5e460ce5f..61d86979e42dd 100644 --- a/src/monmove.cpp +++ b/src/monmove.cpp @@ -848,37 +848,37 @@ void monster::move() // directly and instead iterate over the map from the monster type // (properties of monster types should never change). if( !has_flag( json_flag_CANNOT_ATTACK ) ) { - for( const auto &sp_type : type->special_attacks ) { - const std::string &special_name = sp_type.first; - const auto local_iter = special_attacks.find( special_name ); - if( local_iter == special_attacks.end() ) { - continue; - } - mon_special_attack &local_attack_data = local_iter->second; - if( !local_attack_data.enabled ) { - continue; - } + for( const auto &sp_type : type->special_attacks ) { + const std::string &special_name = sp_type.first; + const auto local_iter = special_attacks.find( special_name ); + if( local_iter == special_attacks.end() ) { + continue; + } + mon_special_attack &local_attack_data = local_iter->second; + if( !local_attack_data.enabled ) { + continue; + } - add_msg_debug( debugmode::DF_MATTACK, "%s attempting a special attack %s, cooldown %d", name(), - sp_type.first, local_attack_data.cooldown ); + add_msg_debug( debugmode::DF_MATTACK, "%s attempting a special attack %s, cooldown %d", name(), + sp_type.first, local_attack_data.cooldown ); - // Cooldowns are decremented in monster::process_turn + // Cooldowns are decremented in monster::process_turn - if( local_attack_data.cooldown == 0 && !pacified && !is_hallucination() ) { - if( !sp_type.second->call( *this ) ) { - add_msg_debug( debugmode::DF_MATTACK, "Attack failed" ); - continue; - } + if( local_attack_data.cooldown == 0 && !pacified && !is_hallucination() ) { + if( !sp_type.second->call( *this ) ) { + add_msg_debug( debugmode::DF_MATTACK, "Attack failed" ); + continue; + } - // `special_attacks` might have changed at this point. Sadly `reset_special` - // doesn't check the attack name, so we need to do it here. - if( special_attacks.count( special_name ) == 0 ) { - continue; + // `special_attacks` might have changed at this point. Sadly `reset_special` + // doesn't check the attack name, so we need to do it here. + if( special_attacks.count( special_name ) == 0 ) { + continue; + } + reset_special( special_name ); } - reset_special( special_name ); } } - } // Check if they're dragging a foe and find their hapless victim Character *dragged_foe = find_dragged_foe(); @@ -887,7 +887,8 @@ void monster::move() nursebot_operate( dragged_foe ); // The monster can sometimes hang in air due to last fall being blocked - if( !flies() && !here.has_floor_or_water( pos_bub() ) && !here.has_vehicle_floor( pos_bub() ) && !has_flag( json_flag_CANNOT_MOVE ) ) { + if( !flies() && !here.has_floor_or_water( pos_bub() ) && !here.has_vehicle_floor( pos_bub() ) && + !has_flag( json_flag_CANNOT_MOVE ) ) { here.creature_on_trap( *this, false ); if( is_dead() ) { return; @@ -909,7 +910,8 @@ void monster::move() moves = 0; return; } - if( has_flag( mon_flag_IMMOBILE ) || has_flag( mon_flag_RIDEABLE_MECH ) || has_flag( json_flag_CANNOT_MOVE) ) { + if( has_flag( mon_flag_IMMOBILE ) || has_flag( mon_flag_RIDEABLE_MECH ) || + has_flag( json_flag_CANNOT_MOVE ) ) { moves = 0; return; } @@ -2046,7 +2048,8 @@ bool monster::push_to( const tripoint &p, const int boost, const size_t depth ) return false; } - if( !has_flag( mon_flag_PUSH_MON ) || depth > 2 || has_effect( effect_pushed ) || has_flag( json_flag_CANNOT_ATTACK ) ) { + if( !has_flag( mon_flag_PUSH_MON ) || depth > 2 || has_effect( effect_pushed ) || + has_flag( json_flag_CANNOT_ATTACK ) ) { return false; } @@ -2317,7 +2320,8 @@ bool monster::will_reach( const point &p ) return false; } - if( ( has_flag( mon_flag_IMMOBILE ) || has_flag( mon_flag_RIDEABLE_MECH ) || has_flag( json_flag_CANNOT_MOVE ) ) && + if( ( has_flag( mon_flag_IMMOBILE ) || has_flag( mon_flag_RIDEABLE_MECH ) || + has_flag( json_flag_CANNOT_MOVE ) ) && ( pos().xy() != p ) ) { return false; } diff --git a/src/monster.cpp b/src/monster.cpp index 9c5a94a1de49f..caca32df05534 100644 --- a/src/monster.cpp +++ b/src/monster.cpp @@ -3928,7 +3928,8 @@ void monster::set_horde_attraction( monster_horde_attraction mha ) bool monster::will_join_horde( int size ) { const monster_horde_attraction mha = get_horde_attraction(); - if( this->has_flag( mon_flag_IMMOBILE ) || this->has_flag( mon_flag_NEVER_WANDER ) || this->has_flag( json_flag_CANNOT_MOVE ) ) { + if( this->has_flag( mon_flag_IMMOBILE ) || this->has_flag( mon_flag_NEVER_WANDER ) || + this->has_flag( json_flag_CANNOT_MOVE ) ) { return false; //immobile monsters should never join a horde. Same with Never Wander monsters. } if( mha == MHA_NEVER ) { diff --git a/src/npctalk.cpp b/src/npctalk.cpp index 588f38595e04d..47906c4531e2a 100644 --- a/src/npctalk.cpp +++ b/src/npctalk.cpp @@ -7436,7 +7436,7 @@ void talk_effect_t::parse_string_effect( const std::string &effect_id, const Jso set_effect( talk_effect_fun_t( talk_effect_fun::f_die( true ) ) ); return; } - + if( effect_id == "u_cancel_activity" ) { set_effect( talk_effect_fun_t( talk_effect_fun::f_cancel_activity( false ) ) ); return; diff --git a/src/player_hardcoded_effects.cpp b/src/player_hardcoded_effects.cpp index 7bf30276e5892..d8c3b240b63a4 100644 --- a/src/player_hardcoded_effects.cpp +++ b/src/player_hardcoded_effects.cpp @@ -314,7 +314,7 @@ static void eff_fun_bleed( Character &u, effect &it ) if( u.has_flag( json_flag_CANNOT_TAKE_DAMAGE ) ) { return; } - + // Presuming that during the first-aid process you're putting pressure // on the wound or otherwise suppressing the flow. (Kits contain either // QuikClot or bandages per the recipe.) diff --git a/src/ranged.cpp b/src/ranged.cpp index 2bf2a6ff9dde7..4d7aa3e3dc571 100644 --- a/src/ranged.cpp +++ b/src/ranged.cpp @@ -1543,12 +1543,14 @@ dealt_projectile_attack Character::throw_item( const tripoint_bub_ms &target, co const double missed_by = dealt_attack.missed_by; if( critter && dealt_attack.hit_critter != nullptr && missed_by <= 0.1 && - !critter->has_flag( mon_flag_IMMOBILE ) && !critter->has_effect_with_flag( json_flag_CANNOT_MOVE ) ) { + !critter->has_flag( mon_flag_IMMOBILE ) && + !critter->has_effect_with_flag( json_flag_CANNOT_MOVE ) ) { practice( skill_throw, final_xp_mult, MAX_SKILL ); // TODO: Check target for existence of head get_event_bus().send( getID() ); } else if( critter && dealt_attack.hit_critter != nullptr && missed_by > 0.0f && - !critter->has_flag( mon_flag_IMMOBILE ) && !critter->has_effect_with_flag( json_flag_CANNOT_MOVE ) ) { + !critter->has_flag( mon_flag_IMMOBILE ) && + !critter->has_effect_with_flag( json_flag_CANNOT_MOVE ) ) { practice( skill_throw, final_xp_mult / ( 1.0f + missed_by ), MAX_SKILL ); } else { // Pure grindy practice - cap gain at lvl 2 From 308d72fd9dd93cdacb11010456f9aca1dd1ccee0 Mon Sep 17 00:00:00 2001 From: b3brodie Date: Thu, 28 Nov 2024 22:39:47 -0800 Subject: [PATCH 34/48] missed linting these --- src/avatar_action.cpp | 5 +++-- src/creature.cpp | 10 ++++++---- 2 files changed, 9 insertions(+), 6 deletions(-) diff --git a/src/avatar_action.cpp b/src/avatar_action.cpp index aa53c82a04763..f401babaa0d0b 100644 --- a/src/avatar_action.cpp +++ b/src/avatar_action.cpp @@ -230,7 +230,8 @@ bool avatar_action::move( avatar &you, map &m, const tripoint &d ) if( m.has_flag( ter_furn_flag::TFLAG_MINEABLE, dest_loc ) && g->mostseen == 0 && get_option( "AUTO_FEATURES" ) && get_option( "AUTO_MINING" ) && !m.veh_at( dest_loc ) && !you.is_underwater() && !you.has_effect( effect_stunned ) && - !you.has_effect( effect_psi_stunned ) && !is_riding && !you.has_effect( effect_incorporeal ) && !m.impassable_field_at(d) ) { + !you.has_effect( effect_psi_stunned ) && !is_riding && !you.has_effect( effect_incorporeal ) && + !m.impassable_field_at( d ) ) { if( weapon && weapon->has_flag( flag_DIG_TOOL ) ) { if( weapon->type->can_use( "JACKHAMMER" ) && weapon->ammo_sufficient( &you ) ) { @@ -682,7 +683,7 @@ static float rate_critter( const Creature &c ) void avatar_action::autoattack( avatar &you, map &m ) { if( you.has_flag( json_flag_CANNOT_ATTACK ) ) { - add_msg( m_info, _("You are incapable of attacking!" ) ); + add_msg( m_info, _( "You are incapable of attacking!" ) ); return; } const item_location weapon = you.get_wielded_item(); diff --git a/src/creature.cpp b/src/creature.cpp index 08fa2a67334e7..2fc816fff75be 100644 --- a/src/creature.cpp +++ b/src/creature.cpp @@ -449,9 +449,10 @@ bool Creature::is_dangerous_field( const field_entry &entry ) const return entry.is_dangerous() && !is_immune_field( entry.get_field_type() ); } -bool Creature::is_immune_fields( std::vector fields ) const { - for ( const field_type_id fi: fields) { - if (!is_immune_field(fi)) { +bool Creature::is_immune_fields( std::vector fields ) const +{ + for( const field_type_id fi : fields ) { + if( !is_immune_field( fi ) ) { return false; } } @@ -2034,7 +2035,8 @@ void Creature::process_effects() for( auto &elem : *effects ) { for( auto &_it : elem.second ) { // Do not freeze the effect with the FREEZE_EFFECTS flag. - if( has_effect_with_flag( json_flag_FREEZE_EFFECTS ) && !_it.second.has_flag( json_flag_FREEZE_EFFECTS ) ) { + if( has_effect_with_flag( json_flag_FREEZE_EFFECTS ) && + !_it.second.has_flag( json_flag_FREEZE_EFFECTS ) ) { continue; } // Add any effects that others remove to the removal list From a972e1fc300e2954af764a96de06ef69203e4f25 Mon Sep 17 00:00:00 2001 From: b3brodie Date: Thu, 28 Nov 2024 23:28:14 -0800 Subject: [PATCH 35/48] cancel_activity documentation --- doc/EFFECT_ON_CONDITION.md | 17 +++++++++++++++++ 1 file changed, 17 insertions(+) diff --git a/doc/EFFECT_ON_CONDITION.md b/doc/EFFECT_ON_CONDITION.md index fd1903d0bcef5..053270e294dc7 100644 --- a/doc/EFFECT_ON_CONDITION.md +++ b/doc/EFFECT_ON_CONDITION.md @@ -4015,6 +4015,23 @@ You assign activity `ACT_GAME` for 45 minutes { "u_assign_activity": "ACT_GAME", "duration": "45 minutes" } ``` +#### `u_cancel_activity`, `npc_cancel_activity` + +NPC or character will stop their current activity + +##### Valid talkers: + +| Avatar | Character | NPC | Monster | Furniture | Item | +| ------ | --------- | --------- | ---- | ------- | --- | +| ✔️ | ✔️ | ✔️ | ❌ | ❌ | ❌ | + +##### Examples + +You cancel activity `ACT_GAME` for 45 minutes +```json +{ "u_cancel_activity" } +``` + #### `u_teleport`, `npc_teleport` You or NPC is teleported to `target_var` coordinates From 1c428a18a9b38fcd215ebffe00cecd540b1c00f6 Mon Sep 17 00:00:00 2001 From: b3brodie Date: Fri, 29 Nov 2024 14:23:41 -0800 Subject: [PATCH 36/48] tripoint conversion --- src/avatar_action.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/avatar_action.cpp b/src/avatar_action.cpp index 26edfdb7f602b..ab3d957973609 100644 --- a/src/avatar_action.cpp +++ b/src/avatar_action.cpp @@ -242,7 +242,7 @@ bool avatar_action::move( avatar &you, map &m, const tripoint_rel_ms &d ) get_option( "AUTO_FEATURES" ) && get_option( "AUTO_MINING" ) && !m.veh_at( dest_loc ) && !you.is_underwater() && !you.has_effect( effect_stunned ) && !you.has_effect( effect_psi_stunned ) && !is_riding && !you.has_effect( effect_incorporeal ) && - !m.impassable_field_at( d ) ) { + !m.impassable_field_at( d.raw() ) ) { if( weapon && weapon->has_flag( flag_DIG_TOOL ) ) { if( weapon->type->can_use( "JACKHAMMER" ) && weapon->ammo_sufficient( &you ) ) { From 2d8c2d98e8e02d93a055183c4a95750ee76b8959 Mon Sep 17 00:00:00 2001 From: b3brodie Date: Fri, 29 Nov 2024 14:46:04 -0800 Subject: [PATCH 37/48] iuse formatting --- src/iuse.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/iuse.cpp b/src/iuse.cpp index 09408e91e26cb..56058f705509a 100644 --- a/src/iuse.cpp +++ b/src/iuse.cpp @@ -3087,7 +3087,7 @@ static std::optional dig_tool( Character *p, item *it, const tripoint &pos, const bool mineable_ter = here.has_flag_ter( ter_furn_flag::TFLAG_MINEABLE, pnt ); const bool impassable_fields = here.impassable_field_at( pnt ); const int max_mining_ability = 70; - if( !mineable_furn && !mineable_ter || impassable_fields ) { + if( ( !mineable_furn && !mineable_ter ) || impassable_fields ) { p->add_msg_if_player( m_info, fail ); if( here.bash_resistance( pnt ) > max_mining_ability ) { p->add_msg_if_player( m_info, From 0134968f7b751d1cebb6726d344c57856f2444af Mon Sep 17 00:00:00 2001 From: b3brodie Date: Fri, 29 Nov 2024 15:45:34 -0800 Subject: [PATCH 38/48] move away from old cast style --- src/map.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/map.cpp b/src/map.cpp index 0bf1bea9f5ae9..0c0d77c5b5f8e 100644 --- a/src/map.cpp +++ b/src/map.cpp @@ -2575,7 +2575,7 @@ bool map::passable_skip_fields( const tripoint &p ) const bool map::passable_skip_fields( const tripoint_bub_ms &p ) const { - return move_cost( p, ( const vehicle * )nullptr, true ) != 0; + return move_cost( p, static_cast( nullptr ), true ) != 0; } int map::move_cost_ter_furn( const tripoint &p ) const From af0d2f04e8f15b06eb191c472142f2325166139f Mon Sep 17 00:00:00 2001 From: b3brodie Date: Fri, 29 Nov 2024 19:10:34 -0800 Subject: [PATCH 39/48] prevent vehicle collisions from moving unmovable creatures and bleeding undamageable creatures --- src/game.cpp | 5 +++++ src/vehicle_move.cpp | 16 +++++++++++----- 2 files changed, 16 insertions(+), 5 deletions(-) diff --git a/src/game.cpp b/src/game.cpp index 0536632442dcc..c012bf9e8709e 100644 --- a/src/game.cpp +++ b/src/game.cpp @@ -11898,6 +11898,11 @@ bool game::fling_creature( Creature *c, const units::angle &dir, float flvel, bo return false; } + if( c->has_effect_with_flag( json_flag_CANNOT_MOVE ) ) { + // cannot fling creatures that cannot move. + return false; + } + // Target creature shouldn't be grabbed if thrown // It should also not be thrown if the throw is weaker than the grab for( const effect &eff : c->get_effects_with_flag( json_flag_GRAB ) ) { diff --git a/src/vehicle_move.cpp b/src/vehicle_move.cpp index 8b6d37104cdc3..f2de2f6ff143e 100644 --- a/src/vehicle_move.cpp +++ b/src/vehicle_move.cpp @@ -51,6 +51,8 @@ static const efftype_id effect_harnessed( "harnessed" ); static const efftype_id effect_pet( "pet" ); static const efftype_id effect_stunned( "stunned" ); +static const flag_id json_flag_CANNOT_TAKE_DAMAGE( "CANNOT_TAKE_DAMAGE" ); + static const itype_id fuel_type_animal( "animal" ); static const itype_id fuel_type_battery( "battery" ); static const itype_id fuel_type_muscle( "muscle" ); @@ -831,6 +833,7 @@ static void terrain_collision_data( const tripoint_bub_ms &p, bool bash_floor, veh_collision vehicle::part_collision( int part, const tripoint_bub_ms &p, bool just_detect, bool bash_floor ) { + add_msg("vehicle::part_collision"); // Vertical collisions need to be handled differently // All collisions have to be either fully vertical or fully horizontal for now const bool vert_coll = bash_floor || p.z() != sm_pos.z; @@ -878,6 +881,7 @@ veh_collision vehicle::part_collision( int part, const tripoint_bub_ms &p, } if( is_body_collision ) { + add_msg("is_body_collision"); // critters on a BOARDABLE part in this vehicle aren't colliding if( ovp && ( &ovp->vehicle() == this ) && get_monster( ovp->part_index() ) ) { return ret; @@ -1113,13 +1117,15 @@ veh_collision vehicle::part_collision( int part, const tripoint_bub_ms &p, critter->get_armor_type( damage_bash, bodypart_id( "torso" ) ); dam = std::max( 0, dam - armor ); critter->apply_damage( driver, bodypart_id( "torso" ), dam ); - if( vpi.has_flag( "SHARP" ) ) { - critter->add_effect( effect_source( driver ), effect_bleed, 1_minutes * rng( 1, dam ), + if( !critter->has_effect_with_flag( json_flag_CANNOT_TAKE_DAMAGE ) ) { + if( vpi.has_flag( "SHARP" ) ) { + critter->add_effect( effect_source( driver ), effect_bleed, 1_minutes * rng( 1, dam ), critter->get_random_body_part_of_type( body_part_type::type::torso ) ); - } else if( dam > 18 && rng( 1, 20 ) > 15 ) { - //low chance of lighter bleed even with non sharp objects. - critter->add_effect( effect_source( driver ), effect_bleed, 1_minutes, + } else if( dam > 18 && rng( 1, 20 ) > 15 ) { + //low chance of lighter bleed even with non sharp objects. + critter->add_effect( effect_source( driver ), effect_bleed, 1_minutes, critter->get_random_body_part_of_type( body_part_type::type::torso ) ); + } } add_msg_debug( debugmode::DF_VEHICLE_MOVE, "Critter collision damage: %d", dam ); } From 89bba7ecc2f113cd672588015dcb163a783b480d Mon Sep 17 00:00:00 2001 From: b3brodie Date: Fri, 29 Nov 2024 19:19:06 -0800 Subject: [PATCH 40/48] astyle and delete prints --- src/vehicle_move.cpp | 6 ++---- 1 file changed, 2 insertions(+), 4 deletions(-) diff --git a/src/vehicle_move.cpp b/src/vehicle_move.cpp index f2de2f6ff143e..43436d5d2b1c8 100644 --- a/src/vehicle_move.cpp +++ b/src/vehicle_move.cpp @@ -833,7 +833,6 @@ static void terrain_collision_data( const tripoint_bub_ms &p, bool bash_floor, veh_collision vehicle::part_collision( int part, const tripoint_bub_ms &p, bool just_detect, bool bash_floor ) { - add_msg("vehicle::part_collision"); // Vertical collisions need to be handled differently // All collisions have to be either fully vertical or fully horizontal for now const bool vert_coll = bash_floor || p.z() != sm_pos.z; @@ -881,7 +880,6 @@ veh_collision vehicle::part_collision( int part, const tripoint_bub_ms &p, } if( is_body_collision ) { - add_msg("is_body_collision"); // critters on a BOARDABLE part in this vehicle aren't colliding if( ovp && ( &ovp->vehicle() == this ) && get_monster( ovp->part_index() ) ) { return ret; @@ -1120,11 +1118,11 @@ veh_collision vehicle::part_collision( int part, const tripoint_bub_ms &p, if( !critter->has_effect_with_flag( json_flag_CANNOT_TAKE_DAMAGE ) ) { if( vpi.has_flag( "SHARP" ) ) { critter->add_effect( effect_source( driver ), effect_bleed, 1_minutes * rng( 1, dam ), - critter->get_random_body_part_of_type( body_part_type::type::torso ) ); + critter->get_random_body_part_of_type( body_part_type::type::torso ) ); } else if( dam > 18 && rng( 1, 20 ) > 15 ) { //low chance of lighter bleed even with non sharp objects. critter->add_effect( effect_source( driver ), effect_bleed, 1_minutes, - critter->get_random_body_part_of_type( body_part_type::type::torso ) ); + critter->get_random_body_part_of_type( body_part_type::type::torso ) ); } } add_msg_debug( debugmode::DF_VEHICLE_MOVE, "Critter collision damage: %d", dam ); From 4fd959887d0b4d175a908d25be54ecc0af20707e Mon Sep 17 00:00:00 2001 From: b3brodie Date: Fri, 29 Nov 2024 20:13:25 -0800 Subject: [PATCH 41/48] small number changes --- data/mods/Xedra_Evolved/items/inventor/armor.json | 2 +- data/mods/Xedra_Evolved/spells/eater_spells.json | 4 ++-- 2 files changed, 3 insertions(+), 3 deletions(-) diff --git a/data/mods/Xedra_Evolved/items/inventor/armor.json b/data/mods/Xedra_Evolved/items/inventor/armor.json index 38d598aefabe8..2a7906ecc6d9a 100644 --- a/data/mods/Xedra_Evolved/items/inventor/armor.json +++ b/data/mods/Xedra_Evolved/items/inventor/armor.json @@ -694,7 +694,7 @@ "symbol": "[", "color": "light_gray", "sided": true, - "charges_per_use": 150, + "charges_per_use": 300, "use_action": { "type": "effect_on_conditions", "description": "Reverse your last injury.", diff --git a/data/mods/Xedra_Evolved/spells/eater_spells.json b/data/mods/Xedra_Evolved/spells/eater_spells.json index 8a9fb125a06fb..a6e39689c2bae 100644 --- a/data/mods/Xedra_Evolved/spells/eater_spells.json +++ b/data/mods/Xedra_Evolved/spells/eater_spells.json @@ -596,8 +596,8 @@ "flags": [ "SILENT", "NO_PROJECTILE", "NO_EXPLOSION_SFX" ], "effect": "attack", "shape": "blast", - "min_dot": 2, - "max_dot": 2, + "min_dot": { "math": [ "1 + u_spell_level('xedra_eater_erosion')/10" ] }, + "max_dot": { "math": [ "1 + u_spell_level('xedra_eater_erosion')/10" ] }, "min_range": 1, "max_range": 1, "min_duration": { "math": [ "u_spell_level('xedra_eater_erosion')*100" ] }, From a7044e8659a6c230d26f3efa88b6725bb4f26b65 Mon Sep 17 00:00:00 2001 From: b3brodie Date: Fri, 29 Nov 2024 20:47:11 -0800 Subject: [PATCH 42/48] prevent advanced inventory from picking up items on impassable fields --- src/advanced_inv_pane.cpp | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/src/advanced_inv_pane.cpp b/src/advanced_inv_pane.cpp index 42dd6fdbe10ad..8493e7702da7a 100644 --- a/src/advanced_inv_pane.cpp +++ b/src/advanced_inv_pane.cpp @@ -250,6 +250,10 @@ void advanced_inventory_pane::add_items_from_area( advanced_inv_area &square, square.volume = 0_ml; square.weight = 0_gram; } + // Should not be able to pick up items on terrain with impassable fields. + if ( m.impassable_field_at( square.pos ) ) { + return; + } const advanced_inv_area::itemstack &stacks = is_in_vehicle ? square.i_stacked( square.get_vehicle_stack() ) : square.i_stacked( m.i_at( square.pos ) ); From ec59fdcefa767fe436f4afa8c79d9da0f4b302c6 Mon Sep 17 00:00:00 2001 From: b3brodie Date: Fri, 29 Nov 2024 20:48:31 -0800 Subject: [PATCH 43/48] astyle --- src/advanced_inv_pane.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/advanced_inv_pane.cpp b/src/advanced_inv_pane.cpp index 8493e7702da7a..780f0c93991db 100644 --- a/src/advanced_inv_pane.cpp +++ b/src/advanced_inv_pane.cpp @@ -251,7 +251,7 @@ void advanced_inventory_pane::add_items_from_area( advanced_inv_area &square, square.weight = 0_gram; } // Should not be able to pick up items on terrain with impassable fields. - if ( m.impassable_field_at( square.pos ) ) { + if( m.impassable_field_at( square.pos ) ) { return; } const advanced_inv_area::itemstack &stacks = is_in_vehicle ? From 86a9a8fb606d9d6dacdc076fdcfbe5ebcc29c462 Mon Sep 17 00:00:00 2001 From: b3brodie Date: Fri, 29 Nov 2024 21:12:36 -0800 Subject: [PATCH 44/48] prevent sorting items in impassable fields and begining hauling items in impassable fields --- src/activity_actor.cpp | 2 +- src/activity_item_handling.cpp | 2 +- src/character.cpp | 2 +- 3 files changed, 3 insertions(+), 3 deletions(-) diff --git a/src/activity_actor.cpp b/src/activity_actor.cpp index d56b883ce9032..9c0c34db9ea25 100644 --- a/src/activity_actor.cpp +++ b/src/activity_actor.cpp @@ -7292,7 +7292,7 @@ void unload_loot_activity_actor::do_turn( player_activity &act, Character &you ) // and inaccessible furniture, like filled charcoal kiln if( mgr.has( zone_type_LOOT_IGNORE, src, fac_id ) || here.get_field( src_loc, fd_fire ) != nullptr || - !here.can_put_items_ter_furn( src_loc ) ) { + !here.can_put_items_ter_furn( src_loc ) || here.impassable_field_at( src_loc ) ) { continue; } diff --git a/src/activity_item_handling.cpp b/src/activity_item_handling.cpp index 4dccadc3b0cf9..710134401a5fe 100644 --- a/src/activity_item_handling.cpp +++ b/src/activity_item_handling.cpp @@ -2093,7 +2093,7 @@ void activity_on_turn_move_loot( player_activity &act, Character &you ) if( mgr.has( zone_type_LOOT_IGNORE, src, _fac_id( you ) ) || ignore_contents || here.get_field( src_loc, fd_fire ) != nullptr || - !here.can_put_items_ter_furn( src_loc ) ) { + !here.can_put_items_ter_furn( src_loc ) || here.impassable_field_at( src_loc ) ) { continue; } diff --git a/src/character.cpp b/src/character.cpp index edf2c38ad0436..5fd380db625f2 100644 --- a/src/character.cpp +++ b/src/character.cpp @@ -8756,7 +8756,7 @@ void Character::start_hauling( const std::vector &items_to_haul = } else if( here.has_flag( ter_furn_flag::TFLAG_DEEP_WATER, pos_bub() ) ) { add_msg( m_info, _( "You cannot haul while in deep water." ) ); return; - } else if( !here.can_put_items( pos_bub() ) ) { + } else if( !here.can_put_items( pos_bub() ) || here.impassable_field_at( pos_bub() ) ) { add_msg( m_info, _( "You cannot haul items here." ) ); return; } From 6ca53dc705e3887bf007227dbbab929fab4b8d3b Mon Sep 17 00:00:00 2001 From: b3brodie Date: Sat, 30 Nov 2024 15:22:56 -0800 Subject: [PATCH 45/48] clang fix --- src/map.h | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/src/map.h b/src/map.h index 7c03ddae4cb63..3726489b7cc5c 100644 --- a/src/map.h +++ b/src/map.h @@ -600,11 +600,11 @@ class map */ // TODO: fix point types (remove the first overload) int move_cost( const tripoint &p, const vehicle *ignored_vehicle = nullptr, - const bool ignore_fields = false ) const; + bool ignore_fields = false ) const; int move_cost( const tripoint_bub_ms &p, const vehicle *ignored_vehicle = nullptr, - const bool ignore_fields = false ) const; + bool ignore_fields = false ) const; int move_cost( const point_bub_ms &p, const vehicle *ignored_vehicle = nullptr, - const bool ignore_fields = false ) const { + bool ignore_fields = false ) const { return move_cost( tripoint_bub_ms( p, abs_sub.z() ), ignored_vehicle, ignore_fields ); } // TODO: fix point types (remove the first overload) @@ -652,7 +652,7 @@ class map int combined_movecost( const tripoint_bub_ms &from, const tripoint_bub_ms &to, const vehicle *ignored_vehicle = nullptr, int modifier = 0, bool flying = false, bool via_ramp = false, - const bool ignore_fields = false ) const; + bool ignore_fields = false ) const; /** * Returns true if a creature could walk from `from` to `to` in one step. From ef6eea5c3dbb98bae53303560fa03f4b2e7692a8 Mon Sep 17 00:00:00 2001 From: b3brodie Date: Sat, 30 Nov 2024 19:19:19 -0800 Subject: [PATCH 46/48] clang --- src/creature.cpp | 2 +- src/creature.h | 2 +- src/game.cpp | 4 ++-- src/handle_action.cpp | 2 +- 4 files changed, 5 insertions(+), 5 deletions(-) diff --git a/src/creature.cpp b/src/creature.cpp index c3c064b29a612..f1ae42777d29b 100644 --- a/src/creature.cpp +++ b/src/creature.cpp @@ -449,7 +449,7 @@ bool Creature::is_dangerous_field( const field_entry &entry ) const return entry.is_dangerous() && !is_immune_field( entry.get_field_type() ); } -bool Creature::is_immune_fields( std::vector fields ) const +bool Creature::is_immune_fields( const std::vector fields ) const { for( const field_type_id fi : fields ) { if( !is_immune_field( fi ) ) { diff --git a/src/creature.h b/src/creature.h index 1564ece40de1b..62e0fc9245f55 100644 --- a/src/creature.h +++ b/src/creature.h @@ -581,7 +581,7 @@ class Creature : public viewer } // Returns if the creature is immune to every given field type. - bool is_immune_fields( std::vector fields ) const; + bool is_immune_fields( const std::vector fields ) const; // check if the creature is immune to the effect / field based on the immunity data virtual bool check_immunity_data( const field_immunity_data & ) const { diff --git a/src/game.cpp b/src/game.cpp index c012bf9e8709e..8145806a804cb 100644 --- a/src/game.cpp +++ b/src/game.cpp @@ -10678,7 +10678,7 @@ bool game::walk_move( const tripoint_bub_ms &dest_loc, const bool via_ramp, const std::vector impassable_field_ids = m.get_impassable_field_type_ids_at( dest_loc ); - if( ( !m.passable_skip_fields( dest_loc ) || ( impassable_field_ids.size() > 0 && + if( ( !m.passable_skip_fields( dest_loc ) || ( !impassable_field_ids.empty() && !u.is_immune_fields( impassable_field_ids ) ) ) && !pushing && !shifting_furniture ) { if( vp_there && u.mounted_creature && u.mounted_creature->has_flag( mon_flag_RIDEABLE_MECH ) && vp_there->vehicle().handle_potential_theft( u ) ) { @@ -10746,7 +10746,7 @@ bool game::walk_move( const tripoint_bub_ms &dest_loc, const bool via_ramp, const int mcost = m.combined_movecost( u.pos_bub(), tripoint_bub_ms( dest_loc ), grabbed_vehicle, modifier, - via_ramp, false, impassable_field_ids.size() > 0 && u.is_immune_fields( impassable_field_ids ) ); + via_ramp, false, !impassable_field_ids.empty() && u.is_immune_fields( impassable_field_ids ) ); if( !furniture_move && grabbed_move( dest_loc - u.pos_bub(), via_ramp ) ) { return true; diff --git a/src/handle_action.cpp b/src/handle_action.cpp index 389e86cc60937..146f2695a434e 100644 --- a/src/handle_action.cpp +++ b/src/handle_action.cpp @@ -139,8 +139,8 @@ static const gun_mode_id gun_mode_BURST( "BURST" ); static const itype_id fuel_type_animal( "animal" ); static const itype_id itype_radiocontrol( "radiocontrol" ); -static const json_character_flag json_flag_CANNOT_ATTACK( "CANNOT_ATTACK" ); static const json_character_flag json_flag_ALARMCLOCK( "ALARMCLOCK" ); +static const json_character_flag json_flag_CANNOT_ATTACK( "CANNOT_ATTACK" ); static const json_character_flag json_flag_NO_PSIONICS( "NO_PSIONICS" ); static const json_character_flag json_flag_NO_SPELLCASTING( "NO_SPELLCASTING" ); static const json_character_flag json_flag_SUBTLE_SPELL( "SUBTLE_SPELL" ); From 3c6c2ce60b41408c8f923a9576ce1374e7479fc3 Mon Sep 17 00:00:00 2001 From: b3brodie Date: Sat, 30 Nov 2024 22:48:06 -0800 Subject: [PATCH 47/48] clang --- src/creature.h | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/creature.h b/src/creature.h index 62e0fc9245f55..1564ece40de1b 100644 --- a/src/creature.h +++ b/src/creature.h @@ -581,7 +581,7 @@ class Creature : public viewer } // Returns if the creature is immune to every given field type. - bool is_immune_fields( const std::vector fields ) const; + bool is_immune_fields( std::vector fields ) const; // check if the creature is immune to the effect / field based on the immunity data virtual bool check_immunity_data( const field_immunity_data & ) const { From 5acd92fb6043c5f20f985fcfaf63e3f3c4e162ff Mon Sep 17 00:00:00 2001 From: b3brodie Date: Sun, 1 Dec 2024 01:49:24 -0800 Subject: [PATCH 48/48] clang --- src/creature.cpp | 2 +- src/creature.h | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/src/creature.cpp b/src/creature.cpp index f1ae42777d29b..d102156bc51df 100644 --- a/src/creature.cpp +++ b/src/creature.cpp @@ -449,7 +449,7 @@ bool Creature::is_dangerous_field( const field_entry &entry ) const return entry.is_dangerous() && !is_immune_field( entry.get_field_type() ); } -bool Creature::is_immune_fields( const std::vector fields ) const +bool Creature::is_immune_fields( const std::vector &fields ) const { for( const field_type_id fi : fields ) { if( !is_immune_field( fi ) ) { diff --git a/src/creature.h b/src/creature.h index 1564ece40de1b..048100ccd6665 100644 --- a/src/creature.h +++ b/src/creature.h @@ -581,7 +581,7 @@ class Creature : public viewer } // Returns if the creature is immune to every given field type. - bool is_immune_fields( std::vector fields ) const; + bool is_immune_fields( const std::vector &fields ) const; // check if the creature is immune to the effect / field based on the immunity data virtual bool check_immunity_data( const field_immunity_data & ) const {