diff --git a/src/generated/resources/assets/gtceu/compass/nodes/machines/air_scrubber.json b/src/generated/resources/assets/gtceu/compass/nodes/machines/air_scrubber.json new file mode 100644 index 0000000000..e062820c96 --- /dev/null +++ b/src/generated/resources/assets/gtceu/compass/nodes/machines/air_scrubber.json @@ -0,0 +1,18 @@ +{ + "button_texture": { + "type": "item", + "res": "gtceu:lv_air_scrubber" + }, + "items": [ + "gtceu:lv_air_scrubber", + "gtceu:mv_air_scrubber", + "gtceu:hv_air_scrubber", + "gtceu:ev_air_scrubber" + ], + "page": "gtceu:machines/air_scrubber", + "position": [ + -100, + 200 + ], + "section": "gtceu:machines" +} \ No newline at end of file diff --git a/src/generated/resources/assets/gtceu/compass/nodes/machines/battery_buffer.json b/src/generated/resources/assets/gtceu/compass/nodes/machines/battery_buffer.json index 6629059421..8c85be4e1a 100644 --- a/src/generated/resources/assets/gtceu/compass/nodes/machines/battery_buffer.json +++ b/src/generated/resources/assets/gtceu/compass/nodes/machines/battery_buffer.json @@ -52,7 +52,7 @@ ], "page": "gtceu:machines/battery_buffer", "position": [ - -150, + -100, 250 ], "section": "gtceu:machines" diff --git a/src/generated/resources/assets/gtceu/compass/nodes/machines/block_breaker.json b/src/generated/resources/assets/gtceu/compass/nodes/machines/block_breaker.json index 78bb21b85a..2dd5501ea7 100644 --- a/src/generated/resources/assets/gtceu/compass/nodes/machines/block_breaker.json +++ b/src/generated/resources/assets/gtceu/compass/nodes/machines/block_breaker.json @@ -11,7 +11,7 @@ ], "page": "gtceu:machines/block_breaker", "position": [ - -350, + -300, 300 ], "section": "gtceu:machines" diff --git a/src/generated/resources/assets/gtceu/compass/nodes/machines/charger.json b/src/generated/resources/assets/gtceu/compass/nodes/machines/charger.json index b4cfe16726..b4068218f3 100644 --- a/src/generated/resources/assets/gtceu/compass/nodes/machines/charger.json +++ b/src/generated/resources/assets/gtceu/compass/nodes/machines/charger.json @@ -22,7 +22,7 @@ ], "page": "gtceu:machines/charger", "position": [ - -100, + -50, 250 ], "section": "gtceu:machines" diff --git a/src/generated/resources/assets/gtceu/compass/nodes/machines/combustion.json b/src/generated/resources/assets/gtceu/compass/nodes/machines/combustion.json index 3d0f88b127..cc159dcedc 100644 --- a/src/generated/resources/assets/gtceu/compass/nodes/machines/combustion.json +++ b/src/generated/resources/assets/gtceu/compass/nodes/machines/combustion.json @@ -10,7 +10,7 @@ ], "page": "gtceu:machines/combustion", "position": [ - -100, + -50, 200 ], "section": "gtceu:machines" diff --git a/src/generated/resources/assets/gtceu/compass/nodes/machines/converter.json b/src/generated/resources/assets/gtceu/compass/nodes/machines/converter.json index 5612140c95..16edb23857 100644 --- a/src/generated/resources/assets/gtceu/compass/nodes/machines/converter.json +++ b/src/generated/resources/assets/gtceu/compass/nodes/machines/converter.json @@ -67,7 +67,7 @@ ], "page": "gtceu:machines/converter", "position": [ - -300, + -250, 250 ], "section": "gtceu:machines" diff --git a/src/generated/resources/assets/gtceu/compass/nodes/machines/crate.json b/src/generated/resources/assets/gtceu/compass/nodes/machines/crate.json index 462e4763cd..309cccb4ec 100644 --- a/src/generated/resources/assets/gtceu/compass/nodes/machines/crate.json +++ b/src/generated/resources/assets/gtceu/compass/nodes/machines/crate.json @@ -14,7 +14,7 @@ ], "page": "gtceu:machines/crate", "position": [ - -300, + -250, 350 ], "section": "gtceu:machines" diff --git a/src/generated/resources/assets/gtceu/compass/nodes/machines/creative_chest.json b/src/generated/resources/assets/gtceu/compass/nodes/machines/creative_chest.json index 4d7ed9a6dc..87b3534f1c 100644 --- a/src/generated/resources/assets/gtceu/compass/nodes/machines/creative_chest.json +++ b/src/generated/resources/assets/gtceu/compass/nodes/machines/creative_chest.json @@ -8,8 +8,8 @@ ], "page": "gtceu:machines/creative_chest", "position": [ - -50, - 300 + -400, + 350 ], "section": "gtceu:machines" } \ No newline at end of file diff --git a/src/generated/resources/assets/gtceu/compass/nodes/machines/creative_energy.json b/src/generated/resources/assets/gtceu/compass/nodes/machines/creative_energy.json index c05a353005..c8ebde6ccb 100644 --- a/src/generated/resources/assets/gtceu/compass/nodes/machines/creative_energy.json +++ b/src/generated/resources/assets/gtceu/compass/nodes/machines/creative_energy.json @@ -8,7 +8,7 @@ ], "page": "gtceu:machines/creative_energy", "position": [ - -150, + -100, 300 ], "section": "gtceu:machines" diff --git a/src/generated/resources/assets/gtceu/compass/nodes/machines/creative_tank.json b/src/generated/resources/assets/gtceu/compass/nodes/machines/creative_tank.json index dd2b896202..ed37fbfce8 100644 --- a/src/generated/resources/assets/gtceu/compass/nodes/machines/creative_tank.json +++ b/src/generated/resources/assets/gtceu/compass/nodes/machines/creative_tank.json @@ -8,7 +8,7 @@ ], "page": "gtceu:machines/creative_tank", "position": [ - -100, + -50, 300 ], "section": "gtceu:machines" diff --git a/src/generated/resources/assets/gtceu/compass/nodes/machines/drum.json b/src/generated/resources/assets/gtceu/compass/nodes/machines/drum.json index d28892f501..82251b3939 100644 --- a/src/generated/resources/assets/gtceu/compass/nodes/machines/drum.json +++ b/src/generated/resources/assets/gtceu/compass/nodes/machines/drum.json @@ -15,7 +15,7 @@ ], "page": "gtceu:machines/drum", "position": [ - -250, + -200, 350 ], "section": "gtceu:machines" diff --git a/src/generated/resources/assets/gtceu/compass/nodes/machines/fisher.json b/src/generated/resources/assets/gtceu/compass/nodes/machines/fisher.json index c3474b7083..7cc0aa00a4 100644 --- a/src/generated/resources/assets/gtceu/compass/nodes/machines/fisher.json +++ b/src/generated/resources/assets/gtceu/compass/nodes/machines/fisher.json @@ -11,7 +11,7 @@ ], "page": "gtceu:machines/fisher", "position": [ - -400, + -350, 300 ], "section": "gtceu:machines" diff --git a/src/generated/resources/assets/gtceu/compass/nodes/machines/gas_turbine.json b/src/generated/resources/assets/gtceu/compass/nodes/machines/gas_turbine.json index 9a4a71e19a..7df244dc5f 100644 --- a/src/generated/resources/assets/gtceu/compass/nodes/machines/gas_turbine.json +++ b/src/generated/resources/assets/gtceu/compass/nodes/machines/gas_turbine.json @@ -10,7 +10,7 @@ ], "page": "gtceu:machines/gas_turbine", "position": [ - -400, + -350, 250 ], "section": "gtceu:machines" diff --git a/src/generated/resources/assets/gtceu/compass/nodes/machines/item_collector.json b/src/generated/resources/assets/gtceu/compass/nodes/machines/item_collector.json index 8fe432ec5f..723729effd 100644 --- a/src/generated/resources/assets/gtceu/compass/nodes/machines/item_collector.json +++ b/src/generated/resources/assets/gtceu/compass/nodes/machines/item_collector.json @@ -11,7 +11,7 @@ ], "page": "gtceu:machines/item_collector", "position": [ - -200, + -150, 300 ], "section": "gtceu:machines" diff --git a/src/generated/resources/assets/gtceu/compass/nodes/machines/ld_fluid_pipeline.json b/src/generated/resources/assets/gtceu/compass/nodes/machines/ld_fluid_pipeline.json index 332f046ec1..52d3cf3b0c 100644 --- a/src/generated/resources/assets/gtceu/compass/nodes/machines/ld_fluid_pipeline.json +++ b/src/generated/resources/assets/gtceu/compass/nodes/machines/ld_fluid_pipeline.json @@ -8,7 +8,7 @@ ], "page": "gtceu:machines/ld_fluid_pipeline", "position": [ - -200, + -150, 250 ], "section": "gtceu:machines" diff --git a/src/generated/resources/assets/gtceu/compass/nodes/machines/ld_item_pipeline.json b/src/generated/resources/assets/gtceu/compass/nodes/machines/ld_item_pipeline.json index 61d44dfb65..69c90a5870 100644 --- a/src/generated/resources/assets/gtceu/compass/nodes/machines/ld_item_pipeline.json +++ b/src/generated/resources/assets/gtceu/compass/nodes/machines/ld_item_pipeline.json @@ -8,7 +8,7 @@ ], "page": "gtceu:machines/ld_item_pipeline", "position": [ - -250, + -200, 250 ], "section": "gtceu:machines" diff --git a/src/generated/resources/assets/gtceu/compass/nodes/machines/miner.json b/src/generated/resources/assets/gtceu/compass/nodes/machines/miner.json index 35f63cffb8..ec94d560c9 100644 --- a/src/generated/resources/assets/gtceu/compass/nodes/machines/miner.json +++ b/src/generated/resources/assets/gtceu/compass/nodes/machines/miner.json @@ -10,7 +10,7 @@ ], "page": "gtceu:machines/miner", "position": [ - -300, + -250, 300 ], "section": "gtceu:machines" diff --git a/src/generated/resources/assets/gtceu/compass/nodes/machines/pump.json b/src/generated/resources/assets/gtceu/compass/nodes/machines/pump.json index 721aee5db0..04ed479a97 100644 --- a/src/generated/resources/assets/gtceu/compass/nodes/machines/pump.json +++ b/src/generated/resources/assets/gtceu/compass/nodes/machines/pump.json @@ -11,8 +11,8 @@ ], "page": "gtceu:machines/pump", "position": [ - -50, - 250 + -400, + 300 ], "section": "gtceu:machines" } \ No newline at end of file diff --git a/src/generated/resources/assets/gtceu/compass/nodes/machines/steam_turbine.json b/src/generated/resources/assets/gtceu/compass/nodes/machines/steam_turbine.json index 466f0fab7a..84c2d23c30 100644 --- a/src/generated/resources/assets/gtceu/compass/nodes/machines/steam_turbine.json +++ b/src/generated/resources/assets/gtceu/compass/nodes/machines/steam_turbine.json @@ -10,8 +10,8 @@ ], "page": "gtceu:machines/steam_turbine", "position": [ - -50, - 200 + -400, + 250 ], "section": "gtceu:machines" } \ No newline at end of file diff --git a/src/generated/resources/assets/gtceu/compass/nodes/machines/super_chest.json b/src/generated/resources/assets/gtceu/compass/nodes/machines/super_chest.json index 86e7da147d..28b905bff0 100644 --- a/src/generated/resources/assets/gtceu/compass/nodes/machines/super_chest.json +++ b/src/generated/resources/assets/gtceu/compass/nodes/machines/super_chest.json @@ -20,7 +20,7 @@ ], "page": "gtceu:machines/super_chest", "position": [ - -400, + -350, 350 ], "section": "gtceu:machines" diff --git a/src/generated/resources/assets/gtceu/compass/nodes/machines/super_tank.json b/src/generated/resources/assets/gtceu/compass/nodes/machines/super_tank.json index 83556c3776..5eb07aaa61 100644 --- a/src/generated/resources/assets/gtceu/compass/nodes/machines/super_tank.json +++ b/src/generated/resources/assets/gtceu/compass/nodes/machines/super_tank.json @@ -20,7 +20,7 @@ ], "page": "gtceu:machines/super_tank", "position": [ - -350, + -300, 350 ], "section": "gtceu:machines" diff --git a/src/generated/resources/assets/gtceu/compass/nodes/machines/transformer.json b/src/generated/resources/assets/gtceu/compass/nodes/machines/transformer.json index aae3cf2026..a613f32d6e 100644 --- a/src/generated/resources/assets/gtceu/compass/nodes/machines/transformer.json +++ b/src/generated/resources/assets/gtceu/compass/nodes/machines/transformer.json @@ -43,7 +43,7 @@ ], "page": "gtceu:machines/transformer", "position": [ - -350, + -300, 250 ], "section": "gtceu:machines" diff --git a/src/generated/resources/assets/gtceu/compass/nodes/machines/world_accelerator.json b/src/generated/resources/assets/gtceu/compass/nodes/machines/world_accelerator.json index 542a38694e..18d82d23b5 100644 --- a/src/generated/resources/assets/gtceu/compass/nodes/machines/world_accelerator.json +++ b/src/generated/resources/assets/gtceu/compass/nodes/machines/world_accelerator.json @@ -15,7 +15,7 @@ ], "page": "gtceu:machines/world_accelerator", "position": [ - -250, + -200, 300 ], "section": "gtceu:machines" diff --git a/src/generated/resources/assets/gtceu/lang/en_ud.json b/src/generated/resources/assets/gtceu/lang/en_ud.json index fd3867f8e5..8f6e9f9707 100644 --- a/src/generated/resources/assets/gtceu/lang/en_ud.json +++ b/src/generated/resources/assets/gtceu/lang/en_ud.json @@ -20,7 +20,11 @@ "behavior.portable_scanner.energy_container_in": "Ɐ %s ʇɐ ∩Ǝ )%s( %s :NI xɐW", "behavior.portable_scanner.energy_container_out": "Ɐ %s ʇɐ ∩Ǝ )%s( %s :⟘∩O xɐW", "behavior.portable_scanner.energy_container_storage": "∩Ǝ %s / ∩Ǝ %s :ʎbɹǝuƎ", + "behavior.portable_scanner.environmental_hazard": "ɯdd %s - ɹ§%s :ʞunɥƆ uI pɹɐzɐH ןɐʇuǝɯuoɹıʌuƎ", + "behavior.portable_scanner.environmental_hazard.nothing": "ɹ§buıɥʇoN9§ :ʞunɥƆ uI pɹɐzɐH ןɐʇuǝɯuoɹıʌuƎ", "behavior.portable_scanner.eu_per_sec": "ʇ/∩Ǝ %s :)puoɔǝs ʇsɐן( ǝbɐɹǝʌⱯ", + "behavior.portable_scanner.local_hazard": "ɯdd %s - ɹ§%s :ʞunɥƆ uI pɹɐzɐH ןɐɔoꞀ", + "behavior.portable_scanner.local_hazard.nothing": "ɹ§buıɥʇoN9§ :ʞunɥƆ uI pɹɐzɐH ןɐɔoꞀ", "behavior.portable_scanner.machine_disabled": "˙pǝןqɐsıᗡ", "behavior.portable_scanner.machine_front_facing": "%s :buıɔɐℲ ʇuoɹℲ", "behavior.portable_scanner.machine_power_loss": "˙ssoן ɹǝʍod oʇ ǝnp uʍop ʇnɥS", @@ -161,6 +165,7 @@ "block.gtceu.ev_1a_energy_converter": "ɹǝʇɹǝʌuoƆ ʎbɹǝuƎ ⱯƖ ΛƎ", "block.gtceu.ev_4a_energy_converter": "ɹǝʇɹǝʌuoƆ ʎbɹǝuƎ Ɐㄣ ΛƎ", "block.gtceu.ev_8a_energy_converter": "ɹǝʇɹǝʌuoƆ ʎbɹǝuƎ Ɐ8 ΛƎ", + "block.gtceu.ev_air_scrubber": "ɹ§III ɹǝqqnɹɔS ɹıⱯ pǝɔuɐʌpⱯϛ§", "block.gtceu.ev_alloy_smelter": "ɹ§III ɹǝʇןǝɯS ʎoןןⱯ pǝɔuɐʌpⱯϛ§", "block.gtceu.ev_arc_furnace": "ɹ§III ǝɔɐuɹnℲ ɔɹⱯ pǝɔuɐʌpⱯϛ§", "block.gtceu.ev_assembler": "ɹ§III ɹǝןqɯǝssⱯ pǝɔuɐʌpⱯϛ§", @@ -289,10 +294,12 @@ "block.gtceu.hpca_empty_component": "ʇuǝuodɯoƆ ⱯƆԀH ʎʇdɯƎ", "block.gtceu.hpca_heat_sink_component": "ʇuǝuodɯoƆ ʞuıS ʇɐǝH ⱯƆԀH", "block.gtceu.hssg_coil_block": "ʞɔoןᗺ ןıoƆ ⅁-SSH", + "block.gtceu.huge_duct_pipe": "ǝdıԀ ʇɔnᗡ ǝbnH", "block.gtceu.hv_16a_energy_converter": "ɹǝʇɹǝʌuoƆ ʎbɹǝuƎ Ɐ9Ɩ ΛH", "block.gtceu.hv_1a_energy_converter": "ɹǝʇɹǝʌuoƆ ʎbɹǝuƎ ⱯƖ ΛH", "block.gtceu.hv_4a_energy_converter": "ɹǝʇɹǝʌuoƆ ʎbɹǝuƎ Ɐㄣ ΛH", "block.gtceu.hv_8a_energy_converter": "ɹǝʇɹǝʌuoƆ ʎbɹǝuƎ Ɐ8 ΛH", + "block.gtceu.hv_air_scrubber": "ɹ§II ɹǝqqnɹɔS ɹıⱯ pǝɔuɐʌpⱯ9§", "block.gtceu.hv_alloy_smelter": "ɹ§II ɹǝʇןǝɯS ʎoןןⱯ pǝɔuɐʌpⱯ9§", "block.gtceu.hv_arc_furnace": "ɹ§II ǝɔɐuɹnℲ ɔɹⱯ pǝɔuɐʌpⱯ9§", "block.gtceu.hv_assembler": "ɹ§II ɹǝןqɯǝssⱯ pǝɔuɐʌpⱯ9§", @@ -469,6 +476,7 @@ "block.gtceu.large_combustion_engine": "ǝuıbuƎ uoıʇsnqɯoƆ ǝbɹɐꞀ", "block.gtceu.large_cutter": "ʍɐS buıʇʇnƆ ǝbɹɐꞀ", "block.gtceu.large_distillery": "ʎɹǝןןıʇsıᗡ buıʇɐuoıʇɔɐɹℲ ǝbɹɐꞀ", + "block.gtceu.large_duct_pipe": "ǝdıԀ ʇɔnᗡ ǝbɹɐꞀ", "block.gtceu.large_electrolyzer": "ɹǝqɯɐɥƆ sısʎןoɹʇɔǝןƎ ǝbɹɐꞀ", "block.gtceu.large_electromagnet": "ʇǝubɐɯoɹʇɔǝןƎ ǝbɹɐꞀ", "block.gtceu.large_engraving_laser": "ɹǝsɐꞀ buıʌɐɹbuƎ ǝbɹɐꞀ", @@ -606,6 +614,7 @@ "block.gtceu.lv_1a_energy_converter": "ɹǝʇɹǝʌuoƆ ʎbɹǝuƎ ⱯƖ ΛꞀ", "block.gtceu.lv_4a_energy_converter": "ɹǝʇɹǝʌuoƆ ʎbɹǝuƎ Ɐㄣ ΛꞀ", "block.gtceu.lv_8a_energy_converter": "ɹǝʇɹǝʌuoƆ ʎbɹǝuƎ Ɐ8 ΛꞀ", + "block.gtceu.lv_air_scrubber": "ɹ§ ɹǝqqnɹɔS ɹıⱯ ɔısɐᗺ", "block.gtceu.lv_alloy_smelter": "ɹ§ ɹǝʇןǝɯS ʎoןןⱯ ɔısɐᗺ", "block.gtceu.lv_arc_furnace": "ɹ§ ǝɔɐuɹnℲ ɔɹⱯ ɔısɐᗺ", "block.gtceu.lv_assembler": "ɹ§ ɹǝןqɯǝssⱯ ɔısɐᗺ", @@ -735,6 +744,7 @@ "block.gtceu.mv_1a_energy_converter": "ɹǝʇɹǝʌuoƆ ʎbɹǝuƎ ⱯƖ ΛW", "block.gtceu.mv_4a_energy_converter": "ɹǝʇɹǝʌuoƆ ʎbɹǝuƎ Ɐㄣ ΛW", "block.gtceu.mv_8a_energy_converter": "ɹǝʇɹǝʌuoƆ ʎbɹǝuƎ Ɐ8 ΛW", + "block.gtceu.mv_air_scrubber": "ɹ§ ɹǝqqnɹɔS ɹıⱯ pǝɔuɐʌpⱯq§", "block.gtceu.mv_alloy_smelter": "ɹ§ ɹǝʇןǝɯS ʎoןןⱯ pǝɔuɐʌpⱯq§", "block.gtceu.mv_arc_furnace": "ɹ§ ǝɔɐuɹnℲ ɔɹⱯ pǝɔuɐʌpⱯq§", "block.gtceu.mv_assembler": "ɹ§ ɹǝןqɯǝssⱯ pǝɔuɐʌpⱯq§", @@ -811,6 +821,7 @@ "block.gtceu.nichrome_coil_block": "ʞɔoןᗺ ןıoƆ ǝɯoɹɥɔıN", "block.gtceu.noise_hazard_sign_block": "ʞɔoןᗺ ubıS pɹɐzɐH ǝsıoN", "block.gtceu.nonconducting_casing": "buısɐƆ buıʇɔnpuoɔuoN", + "block.gtceu.normal_duct_pipe": "ǝdıԀ ʇɔnᗡ ןɐɯɹoN", "block.gtceu.normal_laser_pipe": "ǝdıԀ ɹǝsɐꞀ ןɐɯɹoN", "block.gtceu.normal_optical_pipe": "ǝdıԀ ןɐɔıʇdO ןɐɯɹoN", "block.gtceu.object_holder": "ɹǝpןoH ʇɔǝظqO", @@ -945,6 +956,7 @@ "block.gtceu.shock_proof_cutting_casing": "buısɐƆ buıʇʇnƆ ɟooɹԀ ʞɔoɥS", "block.gtceu.slicing_blades": "sǝpɐןᗺ buıɔıןS", "block.gtceu.small_dark_concrete_bricks": "sʞɔıɹᗺ ǝʇǝɹɔuoƆ ʞɹɐᗡ ןןɐɯS", + "block.gtceu.small_duct_pipe": "ǝdıԀ ʇɔnᗡ ןןɐɯS", "block.gtceu.small_light_concrete_bricks": "sʞɔıɹᗺ ǝʇǝɹɔuoƆ ʇɥbıꞀ ןןɐɯS", "block.gtceu.small_marble_bricks": "sʞɔıɹᗺ ǝןqɹɐW ןןɐɯS", "block.gtceu.small_red_granite_bricks": "sʞɔıɹᗺ ǝʇıuɐɹ⅁ pǝᴚ ןןɐɯS", @@ -1544,6 +1556,10 @@ "block.gtceu.zpm_world_accelerator": "ɹ§III ɹoʇɐɹǝןǝɔɔⱯ pןɹoM ǝʇıןƎɔ§", "block.sterilizing_filter_casing.tooltip": "ʇuǝɯuoɹıʌuǝ ㄥ§pǝzıןıɹǝʇSɐ§ ɐ sǝʇɐǝɹƆ", "block.surface_rock": "ʞɔoᴚ ǝɔɐɟɹnS %s", + "command.gtceu.medical_condition.get": ":suoıʇıpuoɔ ןɐɔıpǝɯ ǝsǝɥʇ sɐɥ %s ɹǝʎɐןԀ", + "command.gtceu.medical_condition.get.element": "spuoɔǝs %s :ɹ§%s uoıʇıpuoƆ", + "command.gtceu.medical_condition.get.element.permanent": ")ʇuǝuɐɯɹǝd( spuoɔǝs %s :ɹ§%s uoıʇıpuoƆ", + "command.gtceu.medical_condition.get.empty": "˙suoıʇıpuoɔ ןɐɔıpǝɯ ou sɐɥ %s ɹǝʎɐןԀ", "compass.node.gtceu.batteries/energy_cluster": "ɹǝʇsnןƆ ʎbɹǝuƎ", "compass.node.gtceu.batteries/energy_crystal": "ןɐʇsʎɹƆ ʎbɹǝuƎ", "compass.node.gtceu.batteries/energy_module": "ǝןnpoW ʎbɹǝuƎ", @@ -1711,6 +1727,7 @@ "compass.node.gtceu.luv/mega_vacuum_freezer": "ɹǝzǝǝɹℲ ɯnnɔɐΛ ɐbǝW", "compass.node.gtceu.luv/uv_fusion_reactor": "ɹoʇɔɐǝᴚ uoısnℲ ʌ∩", "compass.node.gtceu.luv/zpm_fusion_reactor": "ɹoʇɔɐǝᴚ uoısnℲ ɯdZ", + "compass.node.gtceu.machines/air_scrubber": "ɹǝqqnɹɔS ɹıⱯ", "compass.node.gtceu.machines/alloy_smelter": "ɹǝʇןǝɯS ʎoןןⱯ", "compass.node.gtceu.machines/arc_furnace": "ǝɔɐuɹnℲ ɔɹⱯ", "compass.node.gtceu.machines/assembler": "ɹǝןqɯǝssⱯ", @@ -2045,6 +2062,7 @@ "config.gtceu.option.energy": "ʎbɹǝuǝ", "config.gtceu.option.energyConsumption": "uoıʇdɯnsuoƆʎbɹǝuǝ", "config.gtceu.option.energyUsageMultiplier": "ɹǝıןdıʇןnWǝbɐs∩ʎbɹǝuǝ", + "config.gtceu.option.environmentalHazards": "spɹɐzɐHןɐʇuǝɯuoɹıʌuǝ", "config.gtceu.option.euToPlatformRatio": "oıʇɐᴚɯɹoɟʇɐןԀo⟘nǝ", "config.gtceu.option.flintAndSteelRequireSteel": "ןǝǝʇSǝɹınbǝᴚןǝǝʇSpuⱯʇuıןɟ", "config.gtceu.option.gameplay": "ʎɐןdǝɯɐb", @@ -2313,6 +2331,19 @@ "death.attack.gtceu.hoe": "%s ʎq pǝןןıʇ pɐǝɥ ɹıǝɥʇ pɐɥ %s", "death.attack.gtceu.knife": "%s ʎq pǝʞod ʎןʇuǝb sɐʍ %s", "death.attack.gtceu.mallet": "%s ʎq ɥʇɐǝp oʇ pǝɹǝɯɯɐɥ ʇob %s", + "death.attack.gtceu.medical_condition/arsenicosis": "buıuosıod ɔıuǝsɹɐ ʇob %s", + "death.attack.gtceu.medical_condition/asbestosis": "ɐɯoıןǝɥʇosǝɯ ʇob %s", + "death.attack.gtceu.medical_condition/berylliosis": "ʎןıpǝǝɹb ooʇ ʇıq ɐ spןɐɹǝɯǝ pǝuıɯ %s", + "death.attack.gtceu.medical_condition/carbon_monoxide_poisoning": "uo ǝʌoʇs ǝɥʇ ʇɟǝן %s", + "death.attack.gtceu.medical_condition/carcinogen": "ɐıɯǝʞnǝן ʇob %s", + "death.attack.gtceu.medical_condition/chemical_burns": "ʇuǝpıɔɔɐ ןɐɔıɯǝɥɔ ɐ pɐɥ %s", + "death.attack.gtceu.medical_condition/irritant": "ɥsɐɹ pɐq ɹ§ʎꞀꞀⱯƎᴚן§u§ ɐ ʇob %s", + "death.attack.gtceu.medical_condition/methanol_poisoning": "uoıʇıqıɥoɹd ǝɥʇ buıɹnp ǝuıɥsuooɯ ʞuıɹp oʇ pǝıɹʇ %s", + "death.attack.gtceu.medical_condition/nausea": "ɐǝsnɐu ɟo pǝıp %s", + "death.attack.gtceu.medical_condition/none": "¿buıɥʇou ˙˙˙ɟo pǝıp %s", + "death.attack.gtceu.medical_condition/poison": "snouosıod 'ʇɔɐɟ uı 'ǝɹɐ sןɐıɹǝʇɐɯ snouosıod ʇɐɥʇ ʇobɹoɟ %s", + "death.attack.gtceu.medical_condition/silicosis": "˙sısoɔıןıs sɐʍ ʇı ˙sısoןnɔɹǝqnʇ ɟo ǝıp ʇ,upıp %s", + "death.attack.gtceu.medical_condition/weak_poison": ")¡ʎɹnɔɹǝɯ ɹo( pɐǝן ǝʇɐ %s", "death.attack.gtceu.mining_hammer": "%s ʎq ǝɹO ɹoɟ uǝʞɐʇsıɯ sɐʍ %s", "death.attack.gtceu.mortar": "%s ʎq ʇsnp oʇ punoɹb sɐʍ %s", "death.attack.gtceu.pickaxe": "%s ʎq pǝuıɯ ʇob %s", @@ -2342,6 +2373,7 @@ "fluid.tile.lava": "ɐʌɐꞀ", "fluid.tile.water": "ɹǝʇɐM", "fluid_cell.empty": "ʎʇdɯƎ", + "gtceu.air_scrubber": "ɹǝqqnɹɔS ɹıⱯ", "gtceu.alloy_blast_smelter": "ɹǝʇןǝɯS ʇsɐןᗺ ʎoןןⱯ", "gtceu.alloy_smelter": "ɹǝʇןǝɯS ʎoןןⱯ", "gtceu.arc_furnace": "ǝɔɐuɹnℲ ɔɹⱯ", @@ -2549,17 +2581,6 @@ "gtceu.gui.title_bar.page_switcher": "sǝbɐԀ", "gtceu.gui.toggle_view.disabled": ")spınןℲ( ʍǝıΛ ǝןbbo⟘", "gtceu.gui.toggle_view.enabled": ")sɯǝʇI( ʍǝıΛ ǝןbbo⟘", - "gtceu.hazard.antidote.description": "sןıɐʇǝp ʍoɥs oʇ ʇɟıɥS pןoHㄥ§ ǝʇopıʇuⱯɐ§", - "gtceu.hazard.antidote.description.effect_removed": "sʇɔǝɟɟǝ ,sʇuǝɯןıɐ ʇuǝɹɹnɔ ɟo %s%% sǝʌoɯǝᴚ", - "gtceu.hazard.antidote.description.effect_removed.all": "sʇɔǝɟɟǝ ,sʇuǝɯןıɐ ʇuǝɹɹnɔ ɟo ןןɐ sǝʌoɯǝᴚ", - "gtceu.hazard.antidote.description_shift": ":sǝdʎʇ sǝɹnƆɐ§", - "gtceu.hazard.contact_poison": "uosıoԀ ʇɔɐʇuoƆϛ§", - "gtceu.hazard.corrosive": "ǝʌısoɹɹoƆ9§", - "gtceu.hazard.description": "sןıɐʇǝp ʍoɥs oʇ ʇɟıɥS pןoHㄥ§ S∩OᗡᴚⱯZⱯHɔ§ן§", - "gtceu.hazard.description_shift": ":S∩OᗡᴚⱯZⱯHɔ§ן§", - "gtceu.hazard.inhalation_poison": "pǝןɐɥuı uǝɥʍ snouosıoԀᄅ§", - "gtceu.hazard.none": "snoɹǝbuɐᗡ ʇoNᄅ§", - "gtceu.hazard.radioactive": "ǝʌıʇɔɐoıpɐᴚǝ§", "gtceu.implosion_compressor": "ɹossǝɹdɯoƆ uoısoןdɯI", "gtceu.io.both": "ɥʇoᗺ", "gtceu.io.export": "ʇɹodxƎ", @@ -3273,6 +3294,25 @@ "gtceu.maintenance.configurable_time": "xɟ% :ǝɯı⟘", "gtceu.maintenance.configurable_time.changed_description": "˙ǝʇɐɹ ןɐɯɹou ǝɥʇ xɟ% ʇɐ ɹnɔɔo ןןıʍ sɯǝןqoɹd ǝɔuɐuǝʇuıɐW", "gtceu.maintenance.configurable_time.unchanged_description": "˙ǝʇɐpdn oʇ uoıʇɐɹnbıɟuoɔ ǝbuɐɥƆ ˙ǝʇɐɹ ןɐɯɹou ʇɐ ɹnɔɔo ןןıʍ sɯǝןqoɹd ǝɔuɐuǝʇuıɐW", + "gtceu.medical_condition.antidote.description": "sןıɐʇǝp ʍoɥs oʇ ʇɟıɥS pןoHㄥ§ ǝʇopıʇuⱯɐ§", + "gtceu.medical_condition.antidote.description.effect_removed": "sʇɔǝɟɟǝ ,suoıʇıpuoɔ ʇuǝɹɹnɔ ɟo %s%% sǝʌoɯǝᴚ", + "gtceu.medical_condition.antidote.description.effect_removed.all": "sʇɔǝɟɟǝ ,suoıʇıpuoɔ ʇuǝɹɹnɔ ɟo ןןɐ sǝʌoɯǝᴚ", + "gtceu.medical_condition.antidote.description_shift": ":suoıʇıpuoɔ ǝsǝɥʇ sǝɹnƆɐ§", + "gtceu.medical_condition.arsenicosis": "sısoɔıuǝsɹⱯq§", + "gtceu.medical_condition.asbestosis": "sısoʇsǝqsⱯp§", + "gtceu.medical_condition.berylliosis": "sısoıןןʎɹǝᗺϛ§", + "gtceu.medical_condition.carbon_monoxide_poisoning": "buıuosıoԀ ǝpıxouoW uoqɹɐƆㄥ§", + "gtceu.medical_condition.carcinogen": "ɔıuǝbouıɔɹɐƆǝ§", + "gtceu.medical_condition.chemical_burns": "suɹnq ןɐɔıɯǝɥƆϛ§", + "gtceu.medical_condition.description": "sןıɐʇǝp ʍoɥs oʇ ʇɟıɥS pןoHㄥ§ S∩OᗡᴚⱯZⱯHɔ§ן§", + "gtceu.medical_condition.description_shift": ":S∩OᗡᴚⱯZⱯHɔ§ן§", + "gtceu.medical_condition.irritant": "ʇuɐʇıɹɹI9§", + "gtceu.medical_condition.methanol_poisoning": "buıuosıoԀ ןouɐɥʇǝW9§", + "gtceu.medical_condition.nausea": "buıʇɐǝsnɐNƐ§", + "gtceu.medical_condition.none": "snoɹǝbuɐᗡ ʇoNᄅ§", + "gtceu.medical_condition.poison": "snouosıoԀᄅ§", + "gtceu.medical_condition.silicosis": "sısoɔıןıSƖ§", + "gtceu.medical_condition.weak_poison": "snouosıod ʎןʞɐǝMɐ§", "gtceu.mixer": "ɹǝxıW", "gtceu.mode.both": "ɹ§)ɯǝʇI puⱯ pınןℲ( ɥʇoᗺp§", "gtceu.mode.fluid": "ɹ§pınןℲ6§", @@ -3517,6 +3557,8 @@ "gtceu.recipe.computation_per_tick": "ʇ/∩MƆ %s :uoıʇɐʇndɯoƆ ˙uıW", "gtceu.recipe.dimensions": "%s :suoısuǝɯıᗡ", "gtceu.recipe.duration": "sɔǝs %s :uoıʇɐɹnᗡ", + "gtceu.recipe.environmental_hazard": "%s ǝʌɐɥ ʇsnɯ ɐǝɹⱯ", + "gtceu.recipe.environmental_hazard.reverse": "%s ɟo ǝǝɹɟ ǝq ʇsnɯ ɐǝɹⱯ", "gtceu.recipe.eu": "ʇ/∩Ǝ %s :ǝbɐs∩", "gtceu.recipe.eu_inverted": "ʇ/∩Ǝ %s :uoıʇɐɹǝuǝ⅁", "gtceu.recipe.eu_to_start": "∩Ǝ%s :ʇɹɐʇS o⟘ ʎbɹǝuƎ", diff --git a/src/generated/resources/assets/gtceu/lang/en_us.json b/src/generated/resources/assets/gtceu/lang/en_us.json index 240c63fd7a..41276a6e74 100644 --- a/src/generated/resources/assets/gtceu/lang/en_us.json +++ b/src/generated/resources/assets/gtceu/lang/en_us.json @@ -20,7 +20,11 @@ "behavior.portable_scanner.energy_container_in": "Max IN: %s (%s) EU at %s A", "behavior.portable_scanner.energy_container_out": "Max OUT: %s (%s) EU at %s A", "behavior.portable_scanner.energy_container_storage": "Energy: %s EU / %s EU", + "behavior.portable_scanner.environmental_hazard": "Environmental Hazard In Chunk: %s§r - %s ppm", + "behavior.portable_scanner.environmental_hazard.nothing": "Environmental Hazard In Chunk: §6Nothing§r", "behavior.portable_scanner.eu_per_sec": "Average (last second): %s EU/t", + "behavior.portable_scanner.local_hazard": "Local Hazard In Chunk: %s§r - %s ppm", + "behavior.portable_scanner.local_hazard.nothing": "Local Hazard In Chunk: §6Nothing§r", "behavior.portable_scanner.machine_disabled": "Disabled.", "behavior.portable_scanner.machine_front_facing": "Front Facing: %s", "behavior.portable_scanner.machine_power_loss": "Shut down due to power loss.", @@ -161,6 +165,7 @@ "block.gtceu.ev_1a_energy_converter": "EV 1A Energy Converter", "block.gtceu.ev_4a_energy_converter": "EV 4A Energy Converter", "block.gtceu.ev_8a_energy_converter": "EV 8A Energy Converter", + "block.gtceu.ev_air_scrubber": "§5Advanced Air Scrubber III§r", "block.gtceu.ev_alloy_smelter": "§5Advanced Alloy Smelter III§r", "block.gtceu.ev_arc_furnace": "§5Advanced Arc Furnace III§r", "block.gtceu.ev_assembler": "§5Advanced Assembler III§r", @@ -289,10 +294,12 @@ "block.gtceu.hpca_empty_component": "Empty HPCA Component", "block.gtceu.hpca_heat_sink_component": "HPCA Heat Sink Component", "block.gtceu.hssg_coil_block": "HSS-G Coil Block", + "block.gtceu.huge_duct_pipe": "Huge Duct Pipe", "block.gtceu.hv_16a_energy_converter": "HV 16A Energy Converter", "block.gtceu.hv_1a_energy_converter": "HV 1A Energy Converter", "block.gtceu.hv_4a_energy_converter": "HV 4A Energy Converter", "block.gtceu.hv_8a_energy_converter": "HV 8A Energy Converter", + "block.gtceu.hv_air_scrubber": "§6Advanced Air Scrubber II§r", "block.gtceu.hv_alloy_smelter": "§6Advanced Alloy Smelter II§r", "block.gtceu.hv_arc_furnace": "§6Advanced Arc Furnace II§r", "block.gtceu.hv_assembler": "§6Advanced Assembler II§r", @@ -469,6 +476,7 @@ "block.gtceu.large_combustion_engine": "Large Combustion Engine", "block.gtceu.large_cutter": "Large Cutting Saw", "block.gtceu.large_distillery": "Large Fractionating Distillery", + "block.gtceu.large_duct_pipe": "Large Duct Pipe", "block.gtceu.large_electrolyzer": "Large Electrolysis Chamber", "block.gtceu.large_electromagnet": "Large Electromagnet", "block.gtceu.large_engraving_laser": "Large Engraving Laser", @@ -606,6 +614,7 @@ "block.gtceu.lv_1a_energy_converter": "LV 1A Energy Converter", "block.gtceu.lv_4a_energy_converter": "LV 4A Energy Converter", "block.gtceu.lv_8a_energy_converter": "LV 8A Energy Converter", + "block.gtceu.lv_air_scrubber": "Basic Air Scrubber §r", "block.gtceu.lv_alloy_smelter": "Basic Alloy Smelter §r", "block.gtceu.lv_arc_furnace": "Basic Arc Furnace §r", "block.gtceu.lv_assembler": "Basic Assembler §r", @@ -735,6 +744,7 @@ "block.gtceu.mv_1a_energy_converter": "MV 1A Energy Converter", "block.gtceu.mv_4a_energy_converter": "MV 4A Energy Converter", "block.gtceu.mv_8a_energy_converter": "MV 8A Energy Converter", + "block.gtceu.mv_air_scrubber": "§bAdvanced Air Scrubber §r", "block.gtceu.mv_alloy_smelter": "§bAdvanced Alloy Smelter §r", "block.gtceu.mv_arc_furnace": "§bAdvanced Arc Furnace §r", "block.gtceu.mv_assembler": "§bAdvanced Assembler §r", @@ -811,6 +821,7 @@ "block.gtceu.nichrome_coil_block": "Nichrome Coil Block", "block.gtceu.noise_hazard_sign_block": "Noise Hazard Sign Block", "block.gtceu.nonconducting_casing": "Nonconducting Casing", + "block.gtceu.normal_duct_pipe": "Normal Duct Pipe", "block.gtceu.normal_laser_pipe": "Normal Laser Pipe", "block.gtceu.normal_optical_pipe": "Normal Optical Pipe", "block.gtceu.object_holder": "Object Holder", @@ -945,6 +956,7 @@ "block.gtceu.shock_proof_cutting_casing": "Shock Proof Cutting Casing", "block.gtceu.slicing_blades": "Slicing Blades", "block.gtceu.small_dark_concrete_bricks": "Small Dark Concrete Bricks", + "block.gtceu.small_duct_pipe": "Small Duct Pipe", "block.gtceu.small_light_concrete_bricks": "Small Light Concrete Bricks", "block.gtceu.small_marble_bricks": "Small Marble Bricks", "block.gtceu.small_red_granite_bricks": "Small Red Granite Bricks", @@ -1544,6 +1556,10 @@ "block.gtceu.zpm_world_accelerator": "§cElite World Accelerator III§r", "block.sterilizing_filter_casing.tooltip": "Creates a §aSterilized§7 environment", "block.surface_rock": "%s Surface Rock", + "command.gtceu.medical_condition.get": "Player %s has these medical conditions:", + "command.gtceu.medical_condition.get.element": "Condition %s§r: %s seconds", + "command.gtceu.medical_condition.get.element.permanent": "Condition %s§r: %s seconds (permanent)", + "command.gtceu.medical_condition.get.empty": "Player %s has no medical conditions.", "compass.node.gtceu.batteries/energy_cluster": "Energy Cluster", "compass.node.gtceu.batteries/energy_crystal": "Energy Crystal", "compass.node.gtceu.batteries/energy_module": "Energy Module", @@ -1711,6 +1727,7 @@ "compass.node.gtceu.luv/mega_vacuum_freezer": "Mega Vacuum Freezer", "compass.node.gtceu.luv/uv_fusion_reactor": "Uv Fusion Reactor", "compass.node.gtceu.luv/zpm_fusion_reactor": "Zpm Fusion Reactor", + "compass.node.gtceu.machines/air_scrubber": "Air Scrubber", "compass.node.gtceu.machines/alloy_smelter": "Alloy Smelter", "compass.node.gtceu.machines/arc_furnace": "Arc Furnace", "compass.node.gtceu.machines/assembler": "Assembler", @@ -2045,6 +2062,7 @@ "config.gtceu.option.energy": "energy", "config.gtceu.option.energyConsumption": "energyConsumption", "config.gtceu.option.energyUsageMultiplier": "energyUsageMultiplier", + "config.gtceu.option.environmentalHazards": "environmentalHazards", "config.gtceu.option.euToPlatformRatio": "euToPlatformRatio", "config.gtceu.option.flintAndSteelRequireSteel": "flintAndSteelRequireSteel", "config.gtceu.option.gameplay": "gameplay", @@ -2313,6 +2331,19 @@ "death.attack.gtceu.hoe": "%s had their head tilled by %s", "death.attack.gtceu.knife": "%s was gently poked by %s", "death.attack.gtceu.mallet": "%s got hammered to death by %s", + "death.attack.gtceu.medical_condition/arsenicosis": "%s got arsenic poisoning", + "death.attack.gtceu.medical_condition/asbestosis": "%s got mesothelioma", + "death.attack.gtceu.medical_condition/berylliosis": "%s mined emeralds a bit too greedily", + "death.attack.gtceu.medical_condition/carbon_monoxide_poisoning": "%s left the stove on", + "death.attack.gtceu.medical_condition/carcinogen": "%s got leukemia", + "death.attack.gtceu.medical_condition/chemical_burns": "%s had a chemical accident", + "death.attack.gtceu.medical_condition/irritant": "%s got a §n§lREALLY§r bad rash", + "death.attack.gtceu.medical_condition/methanol_poisoning": "%s tried to drink moonshine during the prohibition", + "death.attack.gtceu.medical_condition/nausea": "%s died of nausea", + "death.attack.gtceu.medical_condition/none": "%s died of... nothing?", + "death.attack.gtceu.medical_condition/poison": "%s forgot that poisonous materials are, in fact, poisonous", + "death.attack.gtceu.medical_condition/silicosis": "%s didn't die of tuberculosis. it was silicosis.", + "death.attack.gtceu.medical_condition/weak_poison": "%s ate lead (or mercury!)", "death.attack.gtceu.mining_hammer": "%s was mistaken for Ore by %s", "death.attack.gtceu.mortar": "%s was ground to dust by %s", "death.attack.gtceu.pickaxe": "%s got mined by %s", @@ -2342,6 +2373,7 @@ "fluid.tile.lava": "Lava", "fluid.tile.water": "Water", "fluid_cell.empty": "Empty", + "gtceu.air_scrubber": "Air Scrubber", "gtceu.alloy_blast_smelter": "Alloy Blast Smelter", "gtceu.alloy_smelter": "Alloy Smelter", "gtceu.arc_furnace": "Arc Furnace", @@ -2549,17 +2581,6 @@ "gtceu.gui.title_bar.page_switcher": "Pages", "gtceu.gui.toggle_view.disabled": "Toggle View (Fluids)", "gtceu.gui.toggle_view.enabled": "Toggle View (Items)", - "gtceu.hazard.antidote.description": "§aAntidote §7Hold Shift to show details", - "gtceu.hazard.antidote.description.effect_removed": "Removes %s%% of current ailments' effects", - "gtceu.hazard.antidote.description.effect_removed.all": "Removes all of current ailments' effects", - "gtceu.hazard.antidote.description_shift": "§aCures types:", - "gtceu.hazard.contact_poison": "§5Contact Poison", - "gtceu.hazard.corrosive": "§6Corrosive", - "gtceu.hazard.description": "§l§cHAZARDOUS §7Hold Shift to show details", - "gtceu.hazard.description_shift": "§l§cHAZARDOUS:", - "gtceu.hazard.inhalation_poison": "§2Poisonous when inhaled", - "gtceu.hazard.none": "§2Not Dangerous", - "gtceu.hazard.radioactive": "§eRadioactive", "gtceu.implosion_compressor": "Implosion Compressor", "gtceu.io.both": "Both", "gtceu.io.export": "Export", @@ -3273,6 +3294,25 @@ "gtceu.maintenance.configurable_time": "Time: %fx", "gtceu.maintenance.configurable_time.changed_description": "Maintenance problems will occur at %fx the normal rate.", "gtceu.maintenance.configurable_time.unchanged_description": "Maintenance problems will occur at normal rate. Change configuration to update.", + "gtceu.medical_condition.antidote.description": "§aAntidote §7Hold Shift to show details", + "gtceu.medical_condition.antidote.description.effect_removed": "Removes %s%% of current conditions' effects", + "gtceu.medical_condition.antidote.description.effect_removed.all": "Removes all of current conditions' effects", + "gtceu.medical_condition.antidote.description_shift": "§aCures these conditions:", + "gtceu.medical_condition.arsenicosis": "§bArsenicosis", + "gtceu.medical_condition.asbestosis": "§dAsbestosis", + "gtceu.medical_condition.berylliosis": "§5Berylliosis", + "gtceu.medical_condition.carbon_monoxide_poisoning": "§7Carbon Monoxide Poisoning", + "gtceu.medical_condition.carcinogen": "§eCarcinogenic", + "gtceu.medical_condition.chemical_burns": "§5Chemical burns", + "gtceu.medical_condition.description": "§l§cHAZARDOUS §7Hold Shift to show details", + "gtceu.medical_condition.description_shift": "§l§cHAZARDOUS:", + "gtceu.medical_condition.irritant": "§6Irritant", + "gtceu.medical_condition.methanol_poisoning": "§6Methanol Poisoning", + "gtceu.medical_condition.nausea": "§3Nauseating", + "gtceu.medical_condition.none": "§2Not Dangerous", + "gtceu.medical_condition.poison": "§2Poisonous", + "gtceu.medical_condition.silicosis": "§1Silicosis", + "gtceu.medical_condition.weak_poison": "§aWeakly poisonous", "gtceu.mixer": "Mixer", "gtceu.mode.both": "§dBoth (Fluid And Item)§r", "gtceu.mode.fluid": "§9Fluid§r", @@ -3517,6 +3557,8 @@ "gtceu.recipe.computation_per_tick": "Min. Computation: %s CWU/t", "gtceu.recipe.dimensions": "Dimensions: %s", "gtceu.recipe.duration": "Duration: %s secs", + "gtceu.recipe.environmental_hazard": "Area must have %s", + "gtceu.recipe.environmental_hazard.reverse": "Area must be free of %s", "gtceu.recipe.eu": "Usage: %s EU/t", "gtceu.recipe.eu_inverted": "Generation: %s EU/t", "gtceu.recipe.eu_to_start": "Energy To Start: %sEU", diff --git a/src/generated/resources/data/forge/tags/blocks/mineable/wrench.json b/src/generated/resources/data/forge/tags/blocks/mineable/wrench.json index c397898a5b..e00d5e419e 100644 --- a/src/generated/resources/data/forge/tags/blocks/mineable/wrench.json +++ b/src/generated/resources/data/forge/tags/blocks/mineable/wrench.json @@ -143,6 +143,10 @@ "gtceu:turret_hazard_sign_block", "gtceu:void_hazard_sign_block", "gtceu:yellow_stripes_block_a", - "gtceu:yellow_stripes_block_b" + "gtceu:yellow_stripes_block_b", + "gtceu:small_duct_pipe", + "gtceu:normal_duct_pipe", + "gtceu:large_duct_pipe", + "gtceu:huge_duct_pipe" ] } \ No newline at end of file diff --git a/src/generated/resources/data/gtceu/damage_type/medical_condition/arsenicosis.json b/src/generated/resources/data/gtceu/damage_type/medical_condition/arsenicosis.json new file mode 100644 index 0000000000..fc256cc8b6 --- /dev/null +++ b/src/generated/resources/data/gtceu/damage_type/medical_condition/arsenicosis.json @@ -0,0 +1,5 @@ +{ + "exhaustion": 0.0, + "message_id": "gtceu.medical_condition/arsenicosis", + "scaling": "always" +} \ No newline at end of file diff --git a/src/generated/resources/data/gtceu/damage_type/medical_condition/asbestosis.json b/src/generated/resources/data/gtceu/damage_type/medical_condition/asbestosis.json new file mode 100644 index 0000000000..175050d2d3 --- /dev/null +++ b/src/generated/resources/data/gtceu/damage_type/medical_condition/asbestosis.json @@ -0,0 +1,5 @@ +{ + "exhaustion": 0.0, + "message_id": "gtceu.medical_condition/asbestosis", + "scaling": "always" +} \ No newline at end of file diff --git a/src/generated/resources/data/gtceu/damage_type/medical_condition/berylliosis.json b/src/generated/resources/data/gtceu/damage_type/medical_condition/berylliosis.json new file mode 100644 index 0000000000..5e77ab6812 --- /dev/null +++ b/src/generated/resources/data/gtceu/damage_type/medical_condition/berylliosis.json @@ -0,0 +1,5 @@ +{ + "exhaustion": 0.0, + "message_id": "gtceu.medical_condition/berylliosis", + "scaling": "always" +} \ No newline at end of file diff --git a/src/generated/resources/data/gtceu/damage_type/medical_condition/carbon_monoxide_poisoning.json b/src/generated/resources/data/gtceu/damage_type/medical_condition/carbon_monoxide_poisoning.json new file mode 100644 index 0000000000..da142f1fa1 --- /dev/null +++ b/src/generated/resources/data/gtceu/damage_type/medical_condition/carbon_monoxide_poisoning.json @@ -0,0 +1,5 @@ +{ + "exhaustion": 0.0, + "message_id": "gtceu.medical_condition/carbon_monoxide_poisoning", + "scaling": "always" +} \ No newline at end of file diff --git a/src/generated/resources/data/gtceu/damage_type/medical_condition/carcinogen.json b/src/generated/resources/data/gtceu/damage_type/medical_condition/carcinogen.json new file mode 100644 index 0000000000..3880244f58 --- /dev/null +++ b/src/generated/resources/data/gtceu/damage_type/medical_condition/carcinogen.json @@ -0,0 +1,5 @@ +{ + "exhaustion": 0.0, + "message_id": "gtceu.medical_condition/carcinogen", + "scaling": "always" +} \ No newline at end of file diff --git a/src/generated/resources/data/gtceu/damage_type/medical_condition/chemical_burns.json b/src/generated/resources/data/gtceu/damage_type/medical_condition/chemical_burns.json new file mode 100644 index 0000000000..1f05224b0a --- /dev/null +++ b/src/generated/resources/data/gtceu/damage_type/medical_condition/chemical_burns.json @@ -0,0 +1,5 @@ +{ + "exhaustion": 0.0, + "message_id": "gtceu.medical_condition/chemical_burns", + "scaling": "always" +} \ No newline at end of file diff --git a/src/generated/resources/data/gtceu/damage_type/medical_condition/irritant.json b/src/generated/resources/data/gtceu/damage_type/medical_condition/irritant.json new file mode 100644 index 0000000000..fa520fc7cc --- /dev/null +++ b/src/generated/resources/data/gtceu/damage_type/medical_condition/irritant.json @@ -0,0 +1,5 @@ +{ + "exhaustion": 0.0, + "message_id": "gtceu.medical_condition/irritant", + "scaling": "always" +} \ No newline at end of file diff --git a/src/generated/resources/data/gtceu/damage_type/medical_condition/methanol_poisoning.json b/src/generated/resources/data/gtceu/damage_type/medical_condition/methanol_poisoning.json new file mode 100644 index 0000000000..07cab19834 --- /dev/null +++ b/src/generated/resources/data/gtceu/damage_type/medical_condition/methanol_poisoning.json @@ -0,0 +1,5 @@ +{ + "exhaustion": 0.0, + "message_id": "gtceu.medical_condition/methanol_poisoning", + "scaling": "always" +} \ No newline at end of file diff --git a/src/generated/resources/data/gtceu/damage_type/medical_condition/nausea.json b/src/generated/resources/data/gtceu/damage_type/medical_condition/nausea.json new file mode 100644 index 0000000000..469ecdef5c --- /dev/null +++ b/src/generated/resources/data/gtceu/damage_type/medical_condition/nausea.json @@ -0,0 +1,5 @@ +{ + "exhaustion": 0.0, + "message_id": "gtceu.medical_condition/nausea", + "scaling": "always" +} \ No newline at end of file diff --git a/src/generated/resources/data/gtceu/damage_type/medical_condition/none.json b/src/generated/resources/data/gtceu/damage_type/medical_condition/none.json new file mode 100644 index 0000000000..1ef834f484 --- /dev/null +++ b/src/generated/resources/data/gtceu/damage_type/medical_condition/none.json @@ -0,0 +1,5 @@ +{ + "exhaustion": 0.0, + "message_id": "gtceu.medical_condition/none", + "scaling": "always" +} \ No newline at end of file diff --git a/src/generated/resources/data/gtceu/damage_type/medical_condition/poison.json b/src/generated/resources/data/gtceu/damage_type/medical_condition/poison.json new file mode 100644 index 0000000000..402d4470b7 --- /dev/null +++ b/src/generated/resources/data/gtceu/damage_type/medical_condition/poison.json @@ -0,0 +1,5 @@ +{ + "exhaustion": 0.0, + "message_id": "gtceu.medical_condition/poison", + "scaling": "always" +} \ No newline at end of file diff --git a/src/generated/resources/data/gtceu/damage_type/medical_condition/silicosis.json b/src/generated/resources/data/gtceu/damage_type/medical_condition/silicosis.json new file mode 100644 index 0000000000..7538a7a628 --- /dev/null +++ b/src/generated/resources/data/gtceu/damage_type/medical_condition/silicosis.json @@ -0,0 +1,5 @@ +{ + "exhaustion": 0.0, + "message_id": "gtceu.medical_condition/silicosis", + "scaling": "always" +} \ No newline at end of file diff --git a/src/generated/resources/data/gtceu/damage_type/medical_condition/weak_poison.json b/src/generated/resources/data/gtceu/damage_type/medical_condition/weak_poison.json new file mode 100644 index 0000000000..462488da67 --- /dev/null +++ b/src/generated/resources/data/gtceu/damage_type/medical_condition/weak_poison.json @@ -0,0 +1,5 @@ +{ + "exhaustion": 0.0, + "message_id": "gtceu.medical_condition/weak_poison", + "scaling": "always" +} \ No newline at end of file diff --git a/src/generated/resources/data/gtceu/loot_tables/blocks/huge_duct_pipe.json b/src/generated/resources/data/gtceu/loot_tables/blocks/huge_duct_pipe.json new file mode 100644 index 0000000000..5d5feeb4b8 --- /dev/null +++ b/src/generated/resources/data/gtceu/loot_tables/blocks/huge_duct_pipe.json @@ -0,0 +1,21 @@ +{ + "type": "minecraft:block", + "pools": [ + { + "bonus_rolls": 0.0, + "conditions": [ + { + "condition": "minecraft:survives_explosion" + } + ], + "entries": [ + { + "type": "minecraft:item", + "name": "gtceu:huge_duct_pipe" + } + ], + "rolls": 1.0 + } + ], + "random_sequence": "gtceu:blocks/huge_duct_pipe" +} \ No newline at end of file diff --git a/src/generated/resources/data/gtceu/loot_tables/blocks/large_duct_pipe.json b/src/generated/resources/data/gtceu/loot_tables/blocks/large_duct_pipe.json new file mode 100644 index 0000000000..3fc36553a0 --- /dev/null +++ b/src/generated/resources/data/gtceu/loot_tables/blocks/large_duct_pipe.json @@ -0,0 +1,21 @@ +{ + "type": "minecraft:block", + "pools": [ + { + "bonus_rolls": 0.0, + "conditions": [ + { + "condition": "minecraft:survives_explosion" + } + ], + "entries": [ + { + "type": "minecraft:item", + "name": "gtceu:large_duct_pipe" + } + ], + "rolls": 1.0 + } + ], + "random_sequence": "gtceu:blocks/large_duct_pipe" +} \ No newline at end of file diff --git a/src/generated/resources/data/gtceu/loot_tables/blocks/normal_duct_pipe.json b/src/generated/resources/data/gtceu/loot_tables/blocks/normal_duct_pipe.json new file mode 100644 index 0000000000..ad7dfb81e2 --- /dev/null +++ b/src/generated/resources/data/gtceu/loot_tables/blocks/normal_duct_pipe.json @@ -0,0 +1,21 @@ +{ + "type": "minecraft:block", + "pools": [ + { + "bonus_rolls": 0.0, + "conditions": [ + { + "condition": "minecraft:survives_explosion" + } + ], + "entries": [ + { + "type": "minecraft:item", + "name": "gtceu:normal_duct_pipe" + } + ], + "rolls": 1.0 + } + ], + "random_sequence": "gtceu:blocks/normal_duct_pipe" +} \ No newline at end of file diff --git a/src/generated/resources/data/gtceu/loot_tables/blocks/small_duct_pipe.json b/src/generated/resources/data/gtceu/loot_tables/blocks/small_duct_pipe.json new file mode 100644 index 0000000000..51aaac2bbc --- /dev/null +++ b/src/generated/resources/data/gtceu/loot_tables/blocks/small_duct_pipe.json @@ -0,0 +1,21 @@ +{ + "type": "minecraft:block", + "pools": [ + { + "bonus_rolls": 0.0, + "conditions": [ + { + "condition": "minecraft:survives_explosion" + } + ], + "entries": [ + { + "type": "minecraft:item", + "name": "gtceu:small_duct_pipe" + } + ], + "rolls": 1.0 + } + ], + "random_sequence": "gtceu:blocks/small_duct_pipe" +} \ No newline at end of file diff --git a/src/main/java/com/gregtechceu/gtceu/api/capability/GTCapabilityHelper.java b/src/main/java/com/gregtechceu/gtceu/api/capability/GTCapabilityHelper.java index d8cb3b798a..26f3f8f931 100644 --- a/src/main/java/com/gregtechceu/gtceu/api/capability/GTCapabilityHelper.java +++ b/src/main/java/com/gregtechceu/gtceu/api/capability/GTCapabilityHelper.java @@ -108,6 +108,11 @@ public static IDataAccessHatch getDataAccess(Level level, BlockPos pos, @Nullabl return getBlockEntityCapability(GTCapability.CAPABILITY_DATA_ACCESS, level, pos, side); } + @Nullable + public static IHazardParticleContainer getHazardContainer(Level level, BlockPos pos, @Nullable Direction side) { + return getBlockEntityCapability(GTCapability.CAPABILITY_HAZARD_CONTAINER, level, pos, side); + } + @Nullable private static T getBlockEntityCapability(Capability capability, Level level, BlockPos pos, @Nullable Direction side) { @@ -121,7 +126,7 @@ private static T getBlockEntityCapability(Capability capability, Level le } @Nullable - public static IHazardEffectTracker getHazardEffectTracker(@NotNull Entity entity) { - return entity.getCapability(GTCapability.CAPABILITY_HAZARD_EFFECT_TRACKER, null).resolve().orElse(null); + public static IMedicalConditionTracker getMedicalConditionTracker(@NotNull Entity entity) { + return entity.getCapability(GTCapability.CAPABILITY_MEDICAL_CONDITION_TRACKER, null).resolve().orElse(null); } } diff --git a/src/main/java/com/gregtechceu/gtceu/api/capability/IHazardEffectTracker.java b/src/main/java/com/gregtechceu/gtceu/api/capability/IHazardEffectTracker.java deleted file mode 100644 index b753ce9e5f..0000000000 --- a/src/main/java/com/gregtechceu/gtceu/api/capability/IHazardEffectTracker.java +++ /dev/null @@ -1,32 +0,0 @@ -package com.gregtechceu.gtceu.api.capability; - -import com.gregtechceu.gtceu.api.data.chemical.material.Material; - -import it.unimi.dsi.fastutil.objects.Object2IntMap; - -import java.util.Set; - -public interface IHazardEffectTracker { - - /** - * @return a set of hazard effect to how long it's been applied for. - */ - Set getExtraHazards(); - - /** - * @return a map of material to how long its effects been applied for. - */ - Object2IntMap getCurrentHazards(); - - /** - * @return the maximum air supply for the entity this is attached to. -1 for default (300). - */ - // default maxAirSupply for players is 300. - int getMaxAirSupply(); - - void startTick(); - - void tick(Material material); - - void endTick(); -} diff --git a/src/main/java/com/gregtechceu/gtceu/api/capability/IHazardParticleContainer.java b/src/main/java/com/gregtechceu/gtceu/api/capability/IHazardParticleContainer.java new file mode 100644 index 0000000000..0be8c435a0 --- /dev/null +++ b/src/main/java/com/gregtechceu/gtceu/api/capability/IHazardParticleContainer.java @@ -0,0 +1,88 @@ +package com.gregtechceu.gtceu.api.capability; + +import com.gregtechceu.gtceu.api.data.medicalcondition.MedicalCondition; + +import net.minecraft.core.Direction; + +public interface IHazardParticleContainer { + + /** + * @return if this container accepts particles from the given side + */ + boolean inputsHazard(Direction side, MedicalCondition condition); + + /** + * @return if this container can output particles to the given side + */ + default boolean outputsHazard(Direction side, MedicalCondition condition) { + return false; + } + + /** + * This changes the amount stored. + * + * @param differenceAmount amount of particles to add (>0) or remove (<0) + * @return amount of particles added or removed + */ + float changeHazard(MedicalCondition condition, float differenceAmount); + + /** + * Adds specified amount of particles to this particles container + * + * @param particlesToAdd amount of particles to add + * @return amount of particles added + */ + default float addHazard(MedicalCondition condition, float particlesToAdd) { + return changeHazard(condition, particlesToAdd); + } + + /** + * Removes specified amount of particles from this particles container + * + * @param particlesToRemove amount of particles to remove + * @return amount of particles removed + */ + default float removeHazard(MedicalCondition condition, float particlesToRemove) { + return -changeHazard(condition, -particlesToRemove); + } + + /** + * @return the maximum amount of particles that can be inserted + */ + default float getHazardCanBeInserted(MedicalCondition condition) { + return getHazardCapacity(condition) - getHazardStored(condition); + } + + /** + * @return amount of currently stored particles + */ + float getHazardStored(MedicalCondition condition); + + /** + * @return maximum amount of storable particles + */ + float getHazardCapacity(MedicalCondition condition); + + IHazardParticleContainer DEFAULT = new IHazardParticleContainer() { + + @Override + public boolean inputsHazard(Direction side, MedicalCondition condition) { + return false; + } + + @Override + public float changeHazard(MedicalCondition condition, float differenceAmount) { + return 0; + } + + @Override + public float getHazardStored(MedicalCondition condition) { + return 0; + } + + @Override + public float getHazardCapacity(MedicalCondition condition) { + return 0; + } + }; +} diff --git a/src/main/java/com/gregtechceu/gtceu/api/capability/IMedicalConditionTracker.java b/src/main/java/com/gregtechceu/gtceu/api/capability/IMedicalConditionTracker.java new file mode 100644 index 0000000000..2479a48a36 --- /dev/null +++ b/src/main/java/com/gregtechceu/gtceu/api/capability/IMedicalConditionTracker.java @@ -0,0 +1,40 @@ +package com.gregtechceu.gtceu.api.capability; + +import com.gregtechceu.gtceu.api.data.chemical.material.Material; +import com.gregtechceu.gtceu.api.data.chemical.material.properties.HazardProperty; +import com.gregtechceu.gtceu.api.data.chemical.material.properties.PropertyKey; +import com.gregtechceu.gtceu.api.data.medicalcondition.MedicalCondition; + +import net.minecraft.world.effect.MobEffect; + +import it.unimi.dsi.fastutil.objects.Object2FloatMap; +import org.jetbrains.annotations.NotNull; + +public interface IMedicalConditionTracker { + + /** + * @return Map of medical condition to its progression. + */ + Object2FloatMap getMedicalConditions(); + + /** + * @return the maximum air supply for the entity this is attached to. -1 for default (300). + */ + // default maxAirSupply for players is 300. + int getMaxAirSupply(); + + void tick(); + + default void progressRelatedCondition(@NotNull Material material) { + HazardProperty materialHazard = material.getProperty(PropertyKey.HAZARD); + progressCondition(materialHazard.condition, materialHazard.progressionMultiplier); + } + + void progressCondition(@NotNull MedicalCondition condition, float strength); + + void heal(MedicalCondition condition, int progression); + + void setMobEffect(MobEffect effect, int amplifier); + + void removeMedicalCondition(MedicalCondition condition); +} diff --git a/src/main/java/com/gregtechceu/gtceu/api/capability/forge/GTCapability.java b/src/main/java/com/gregtechceu/gtceu/api/capability/forge/GTCapability.java index 3330870b89..89535cd5ca 100644 --- a/src/main/java/com/gregtechceu/gtceu/api/capability/forge/GTCapability.java +++ b/src/main/java/com/gregtechceu/gtceu/api/capability/forge/GTCapability.java @@ -39,8 +39,10 @@ public class GTCapability { .get(new CapabilityToken<>() {}); public static final Capability CAPABILITY_DATA_ACCESS = CapabilityManager .get(new CapabilityToken<>() {}); + public static final Capability CAPABILITY_HAZARD_CONTAINER = CapabilityManager + .get(new CapabilityToken<>() {}); - public static final Capability CAPABILITY_HAZARD_EFFECT_TRACKER = CapabilityManager + public static final Capability CAPABILITY_MEDICAL_CONDITION_TRACKER = CapabilityManager .get(new CapabilityToken<>() {}); public static void register(RegisterCapabilitiesEvent event) { @@ -57,7 +59,7 @@ public static void register(RegisterCapabilitiesEvent event) { event.register(ILaserContainer.class); event.register(IOpticalComputationProvider.class); event.register(IDataAccessHatch.class); - - event.register(IHazardEffectTracker.class); + event.register(IMedicalConditionTracker.class); + event.register(IHazardParticleContainer.class); } } diff --git a/src/main/java/com/gregtechceu/gtceu/api/data/chemical/material/Material.java b/src/main/java/com/gregtechceu/gtceu/api/data/chemical/material/Material.java index 5271f1004b..8b6bef06a9 100644 --- a/src/main/java/com/gregtechceu/gtceu/api/data/chemical/material/Material.java +++ b/src/main/java/com/gregtechceu/gtceu/api/data/chemical/material/Material.java @@ -7,6 +7,7 @@ import com.gregtechceu.gtceu.api.data.chemical.material.info.MaterialIconSet; import com.gregtechceu.gtceu.api.data.chemical.material.properties.*; import com.gregtechceu.gtceu.api.data.chemical.material.stack.MaterialStack; +import com.gregtechceu.gtceu.api.data.medicalcondition.MedicalCondition; import com.gregtechceu.gtceu.api.data.tag.TagUtil; import com.gregtechceu.gtceu.api.fluids.FluidBuilder; import com.gregtechceu.gtceu.api.fluids.FluidState; @@ -15,6 +16,7 @@ import com.gregtechceu.gtceu.api.item.tool.MaterialToolTier; import com.gregtechceu.gtceu.api.registry.registrate.BuilderBase; import com.gregtechceu.gtceu.common.data.GTMaterials; +import com.gregtechceu.gtceu.common.data.GTMedicalConditions; import com.gregtechceu.gtceu.integration.kjs.helpers.MaterialStackWrapper; import com.gregtechceu.gtceu.utils.FormattingUtil; @@ -24,8 +26,6 @@ import net.minecraft.network.chat.MutableComponent; import net.minecraft.resources.ResourceLocation; import net.minecraft.tags.TagKey; -import net.minecraft.world.entity.ai.attributes.Attribute; -import net.minecraft.world.entity.ai.attributes.AttributeModifier; import net.minecraft.world.item.Item; import net.minecraft.world.item.enchantment.Enchantment; import net.minecraft.world.level.material.Fluid; @@ -246,7 +246,6 @@ public FluidStack getFluid(long amount) { } /** - * * @param key the key for the fluid * @param amount the amount the FluidStack should have * @return a FluidStack with the fluid and amount @@ -1054,121 +1053,40 @@ public Builder blastTemp(int temp, BlastProperty.GasTier gasTier, int eutOverrid // Tons of shortcut functions for adding various hazard effects. - public Builder hazard(HazardProperty.HazardType hazardType, HazardProperty.HazardEffect effect, - HazardProperty.HazardDamage damage, boolean applyToDerivatives) { - properties.setProperty(HAZARD, new HazardProperty(hazardType, effect, damage, applyToDerivatives)); - return this; - } - - public Builder hazard(HazardProperty.HazardType hazardType, HazardProperty.HazardEffect effect, - HazardProperty.HazardDamage damage) { - properties.setProperty(HAZARD, new HazardProperty(hazardType, effect, damage, true)); - return this; - } - - public Builder hazard(HazardProperty.HazardType hazardType, HazardProperty.HazardEffect effect, - boolean applyToDerivatives) { - properties.setProperty(HAZARD, new HazardProperty(hazardType, effect, null, applyToDerivatives)); - return this; - } - - public Builder hazard(HazardProperty.HazardType hazardType, HazardProperty.HazardDamage damage, - boolean applyToDerivatives) { - properties.setProperty(HAZARD, new HazardProperty(hazardType, List.of(), damage, applyToDerivatives)); - return this; - } - - @HideFromJS - public Builder hazard(HazardProperty.HazardType hazardType, HazardProperty.HazardEffect effect) { - properties.setProperty(HAZARD, new HazardProperty(hazardType, effect, null, true)); - return this; - } - - public Builder hazard(HazardProperty.HazardType hazardType, HazardProperty.HazardDamage damage) { - properties.setProperty(HAZARD, new HazardProperty(hazardType, List.of(), damage, true)); - return this; - } - - public Builder hazard(HazardProperty.HazardType hazardType, List effects) { - properties.setProperty(HAZARD, new HazardProperty(hazardType, effects, null, true)); - return this; - } - - public Builder hazard(HazardProperty.HazardType hazardType, List effects, - boolean applyToDerivatives) { - properties.setProperty(HAZARD, new HazardProperty(hazardType, effects, null, applyToDerivatives)); - return this; - } - - public Builder hazard(HazardProperty.HazardType hazardType, int secondsToMax, Attribute attribute, - AttributeModifier maxModifier) { - properties.setProperty(HAZARD, new HazardProperty(hazardType, - new HazardProperty.HazardEffect(secondsToMax, Map.of(attribute, maxModifier)), null, true)); - return this; - } - - public Builder hazard(HazardProperty.HazardType hazardType, int secondsToMax, Attribute attribute, - AttributeModifier maxModifier, boolean applyToDerivatives) { + public Builder removeHazard() { properties.setProperty(HAZARD, - new HazardProperty(hazardType, - new HazardProperty.HazardEffect(secondsToMax, Map.of(attribute, maxModifier)), null, - applyToDerivatives)); + new HazardProperty(HazardProperty.HazardTrigger.NONE, GTMedicalConditions.NONE, + 0, false)); return this; } - public Builder hazard(HazardProperty.HazardType hazardType, int secondsToMax, Attribute attribute, - AttributeModifier maxModifier, int maxAirModifier) { - properties.setProperty(HAZARD, new HazardProperty(hazardType, - new HazardProperty.HazardEffect(secondsToMax, Map.of(attribute, maxModifier), maxAirModifier), null, - true)); + public Builder radioactiveHazard(int multiplier) { + properties.setProperty(HAZARD, new HazardProperty(HazardProperty.HazardTrigger.ANY, + GTMedicalConditions.CARCINOGEN, multiplier, true)); return this; } - public Builder hazard(HazardProperty.HazardType hazardType, int secondsToMax, Attribute attribute, - AttributeModifier maxModifier, int maxAirModifier, boolean applyToDerivatives) { - properties.setProperty(HAZARD, new HazardProperty(hazardType, - new HazardProperty.HazardEffect(secondsToMax, Map.of(attribute, maxModifier), maxAirModifier), null, - applyToDerivatives)); + public Builder hazard(HazardProperty.HazardTrigger trigger, MedicalCondition condition) { + properties.setProperty(HAZARD, new HazardProperty(trigger, condition, 1, false)); return this; } - public Builder hazard(HazardProperty.HazardType hazardType, boolean applyToDerivatives) { - properties.setProperty(HAZARD, new HazardProperty(hazardType, HazardProperty.poisonEffect(1000, 2000, 3), - null, applyToDerivatives)); + public Builder hazard(HazardProperty.HazardTrigger trigger, MedicalCondition condition, + float progressionMultiplier) { + properties.setProperty(HAZARD, new HazardProperty(trigger, condition, progressionMultiplier, false)); return this; } - public Builder hazard(HazardProperty.HazardType hazardType) { + public Builder hazard(HazardProperty.HazardTrigger trigger, MedicalCondition condition, + float progressionMultiplier, boolean applyToDerivatives) { properties.setProperty(HAZARD, - new HazardProperty(hazardType, HazardProperty.poisonEffect(1000, 2000, 3), null, true)); + new HazardProperty(trigger, condition, progressionMultiplier, applyToDerivatives)); return this; } - public Builder radioactiveHazard(float multiplier) { - int effectAmplifier = (int) (multiplier - 1); - properties.setProperty(HAZARD, new HazardProperty( - HazardProperty.HazardType.RADIOACTIVE, - List.of( - HazardProperty.slownessEffect(4000, (int) (2000 / multiplier), effectAmplifier), - HazardProperty.weaknessEffect(4000, (int) (2000 / multiplier), effectAmplifier), - HazardProperty.miningFautigueEffect(4000, (int) (3000 / multiplier), effectAmplifier), - HazardProperty.maxAirLoweringEffect(1000, (int) (4000 / multiplier), - (int) (100 / multiplier)), - HazardProperty.maxHealthLoweringEffect(4000, (int) (6000 / multiplier), 10), - HazardProperty.witherEffect(10000, (int) (24000 / multiplier), effectAmplifier)), - null, - true)); - return this; - } - - public Builder irritantHazard(boolean applyToDerivatives) { - properties.setProperty(HAZARD, new HazardProperty( - HazardProperty.HazardType.CONTACT_POISON, - List.of( - HazardProperty.slownessEffect(200, 200, 0), - HazardProperty.miningFautigueEffect(200, 300, 0)), - null, - applyToDerivatives)); + public Builder hazard(HazardProperty.HazardTrigger trigger, MedicalCondition condition, + boolean applyToDerivatives) { + properties.setProperty(HAZARD, new HazardProperty(trigger, condition, 1, applyToDerivatives)); return this; } @@ -1298,14 +1216,14 @@ public Material buildAndRegister() { if (!properties.hasProperty(HAZARD)) { for (MaterialStack materialStack : materialInfo.componentList) { Material material = materialStack.material(); - if (material.hasProperty(HAZARD) && material.getProperty(HAZARD).isApplyToDerivatives()) { + if (material.hasProperty(HAZARD) && material.getProperty(HAZARD).applyToDerivatives) { properties.setProperty(HAZARD, material.getProperty(HAZARD)); break; } } } if (properties.hasProperty(HAZARD) && - properties.getProperty(HAZARD).getHazardType() == HazardProperty.HazardType.NONE) { + properties.getProperty(HAZARD).hazardTrigger == HazardProperty.HazardTrigger.NONE) { properties.removeProperty(HAZARD); } diff --git a/src/main/java/com/gregtechceu/gtceu/api/data/chemical/material/properties/HazardProperty.java b/src/main/java/com/gregtechceu/gtceu/api/data/chemical/material/properties/HazardProperty.java index d22eed16af..ea6a4a1b4d 100644 --- a/src/main/java/com/gregtechceu/gtceu/api/data/chemical/material/properties/HazardProperty.java +++ b/src/main/java/com/gregtechceu/gtceu/api/data/chemical/material/properties/HazardProperty.java @@ -3,31 +3,24 @@ import com.gregtechceu.gtceu.api.data.chemical.ChemicalHelper; import com.gregtechceu.gtceu.api.data.chemical.material.Material; import com.gregtechceu.gtceu.api.data.chemical.material.stack.UnificationEntry; +import com.gregtechceu.gtceu.api.data.medicalcondition.MedicalCondition; import com.gregtechceu.gtceu.api.data.tag.TagPrefix; import com.gregtechceu.gtceu.api.item.TagPrefixItem; import com.gregtechceu.gtceu.api.item.armor.ArmorComponentItem; import com.gregtechceu.gtceu.api.item.forge.GTBucketItem; -import com.gregtechceu.gtceu.common.data.GTMobEffects; import com.gregtechceu.gtceu.config.ConfigHolder; import com.gregtechceu.gtceu.data.recipe.CustomTags; import net.minecraft.util.StringRepresentable; -import net.minecraft.world.effect.MobEffectInstance; -import net.minecraft.world.effect.MobEffects; import net.minecraft.world.entity.LivingEntity; -import net.minecraft.world.entity.ai.attributes.Attribute; -import net.minecraft.world.entity.ai.attributes.AttributeModifier; -import net.minecraft.world.entity.ai.attributes.Attributes; import net.minecraft.world.item.ArmorItem; import net.minecraft.world.item.BucketItem; import net.minecraft.world.item.ItemStack; -import it.unimi.dsi.fastutil.objects.Object2ObjectMaps; import lombok.Getter; import org.jetbrains.annotations.Nullable; import java.util.*; -import java.util.function.Supplier; /** * @author h3tR @@ -36,56 +29,39 @@ */ public class HazardProperty implements IMaterialProperty { - public static final UUID HAZARD_MAX_HEALTH_UUID = UUID.fromString("607aa6d9-a7e4-4919-9962-f007104c4be8"); - public static final String HAZARD_MAX_HEALTH_KEY = "gtceu.hazard.max_health"; + public final MedicalCondition condition; + public final HazardTrigger hazardTrigger; + public final boolean applyToDerivatives; + public final float progressionMultiplier; - @Getter - @Nullable - private final HazardProperty.HazardDamage damage; - @Getter - private final List effects = new ArrayList<>(); - @Getter - private final HazardType hazardType; - @Getter - private final boolean applyToDerivatives; - - public HazardProperty(HazardType hazardType, @Nullable HazardProperty.HazardEffect effect, - @Nullable HazardProperty.HazardDamage damage, boolean applyToDerivatives) { - this.hazardType = hazardType; - this.effects.add(effect); - this.damage = damage; - this.applyToDerivatives = applyToDerivatives; - } - - public HazardProperty(HazardType hazardType, List effects, - @Nullable HazardProperty.HazardDamage damage, boolean applyToDerivatives) { - this.hazardType = hazardType; - this.effects.addAll(effects); - this.damage = damage; + public HazardProperty(HazardTrigger hazardTrigger, MedicalCondition condition, float progressionMultiplier, + boolean applyToDerivatives) { + this.hazardTrigger = hazardTrigger; + this.condition = condition; this.applyToDerivatives = applyToDerivatives; + this.progressionMultiplier = progressionMultiplier; } @Override public void verifyProperty(MaterialProperties properties) {} - public record HazardType(String name, ProtectionType protectionType, Set affectedTagPrefixes) + public record HazardTrigger(String name, ProtectionType protectionType, Set affectedTagPrefixes) implements StringRepresentable { - public static final Map ALL_HAZARDS = new HashMap<>(); + public static final Map ALL_TRIGGERS = new HashMap<>(); - public static final HazardType INHALATION_POISON = new HazardType("inhalation_poison", ProtectionType.MASK, + public static final HazardTrigger INHALATION = new HazardTrigger("inhalation", ProtectionType.MASK, TagPrefix.dust, TagPrefix.dustSmall, TagPrefix.dustTiny, TagPrefix.dustPure, TagPrefix.dustImpure); - public static final HazardType CONTACT_POISON = new HazardType("contact_poison", ProtectionType.FULL); - public static final HazardType RADIOACTIVE = new HazardType("radioactive", ProtectionType.FULL); - public static final HazardType CORROSIVE = new HazardType("corrosive", ProtectionType.HANDS, + public static final HazardTrigger ANY = new HazardTrigger("any", ProtectionType.FULL); + public static final HazardTrigger SKIN_CONTACT = new HazardTrigger("skin_contact", ProtectionType.HANDS, TagPrefix.dust, TagPrefix.dustSmall, TagPrefix.dustTiny); - public static final HazardType NONE = new HazardType("none", ProtectionType.NONE); + public static final HazardTrigger NONE = new HazardTrigger("none", ProtectionType.NONE); - public HazardType { - ALL_HAZARDS.put(name, this); + public HazardTrigger { + ALL_TRIGGERS.put(name, this); } - public HazardType(String name, ProtectionType protectionType, TagPrefix... tagPrefixes) { + public HazardTrigger(String name, ProtectionType protectionType, TagPrefix... tagPrefixes) { this(name, protectionType, new HashSet<>()); affectedTagPrefixes.addAll(Arrays.asList(tagPrefixes)); } @@ -132,47 +108,6 @@ public boolean isProtected(LivingEntity livingEntity) { } } - public static HazardProperty.HazardEffect maxHealthLoweringEffect(int secondsToMax, int startTime, int modifier) { - return new HazardProperty.HazardEffect(secondsToMax, startTime, - Map.of(Attributes.MAX_HEALTH, new AttributeModifier(HazardProperty.HAZARD_MAX_HEALTH_UUID, - HazardProperty.HAZARD_MAX_HEALTH_KEY, -modifier, AttributeModifier.Operation.ADDITION))); - } - - public static HazardProperty.HazardEffect maxAirLoweringEffect(int secondsToMax, int startTime, - int newMaxAirSupply) { - return new HazardProperty.HazardEffect(secondsToMax, startTime, newMaxAirSupply); - } - - public static HazardProperty.HazardEffect witherEffect(int duration, int startTime, int amplifier) { - return new HazardProperty.HazardEffect(duration, startTime, - () -> new MobEffectInstance(MobEffects.WITHER, 1, amplifier)); - } - - public static HazardProperty.HazardEffect slownessEffect(int duration, int startTime, int amplifier) { - return new HazardProperty.HazardEffect(duration, startTime, - () -> new MobEffectInstance(MobEffects.MOVEMENT_SLOWDOWN, 1, amplifier)); - } - - public static HazardProperty.HazardEffect miningFautigueEffect(int duration, int startTime, int amplifier) { - return new HazardProperty.HazardEffect(duration, startTime, - () -> new MobEffectInstance(MobEffects.DIG_SLOWDOWN, 1, amplifier)); - } - - public static HazardProperty.HazardEffect poisonEffect(int duration, int startTime, int amplifier) { - return new HazardProperty.HazardEffect(duration, startTime, - () -> new MobEffectInstance(GTMobEffects.WEAK_POISON.get(), 1, amplifier)); - } - - public static HazardProperty.HazardEffect weaknessEffect(int duration, int startTime, int amplifier) { - return new HazardProperty.HazardEffect(duration, startTime, - () -> new MobEffectInstance(MobEffects.WEAKNESS, 1, amplifier)); - } - - public static HazardProperty.HazardEffect blindnessEffect(int duration, int startTime, int amplifier) { - return new HazardProperty.HazardEffect(duration, startTime, - () -> new MobEffectInstance(MobEffects.BLINDNESS, 1, amplifier)); - } - @Nullable public static Material getValidHazardMaterial(ItemStack item) { Material material = null; @@ -200,94 +135,9 @@ public static Material getValidHazardMaterial(ItemStack item) { if (property == null) { return null; } - if (!isFluid && !property.getHazardType().isAffected(prefix)) { + if (!isFluid && !property.hazardTrigger.isAffected(prefix)) { return null; } return material; } - - /** - * @param damage amount of damage applied every {@code delay} seconds. - * @param delay damage is applied every {@code delay} seconds - */ - public record HazardDamage(int damage, int delay) {} - - /** - * A group of effects applied by a hazard. - * - * @param duration if this is a potion effect, the time (in ticks) the effect has. else it's the ramp-up - * time (in ticks) for the attribute modifiers. - * @param modifierStartTime the time (in seconds) before the modifier is applied at all. - * @param effects the mob effects, if any. - * @param modifiers the attribute modifiers, if any. - */ - public record HazardEffect(int duration, int modifierStartTime, List> effects, - Map modifiers, int newMaxAirSupply) { - - @SafeVarargs - public HazardEffect(int duration, Supplier... effects) { - this(duration, 0, Arrays.stream(effects).toList(), Object2ObjectMaps.emptyMap(), -1); - } - - @SafeVarargs - public HazardEffect(int duration, int modifierStartTime, Supplier... effects) { - this(duration, modifierStartTime, Arrays.stream(effects).toList(), Object2ObjectMaps.emptyMap(), -1); - } - - public HazardEffect(int secondsToMax, Map modifiers) { - this(secondsToMax, 0, List.of(), modifiers, -1); - } - - public HazardEffect(int secondsToMax, int modifierStartTime, Map modifiers) { - this(secondsToMax, modifierStartTime, List.of(), modifiers, -1); - } - - public HazardEffect(int secondsToMax, Map modifiers, int maxAirModifier) { - this(secondsToMax, 0, List.of(), modifiers, maxAirModifier); - } - - public HazardEffect(int secondsToMax, int maxAirModifier) { - this(secondsToMax, 0, List.of(), Object2ObjectMaps.emptyMap(), maxAirModifier); - } - - public HazardEffect(int secondsToMax, int modifierStartTime, int maxAirModifier) { - this(secondsToMax, modifierStartTime, List.of(), Object2ObjectMaps.emptyMap(), maxAirModifier); - } - - public List getEffectInstancesAtTime(int timeFromStart) { - if (this.effects.isEmpty()) { - return List.of(); - } - List effectInstances = new ArrayList<>(); - for (Supplier effectSupplier : effects) { - MobEffectInstance effect = effectSupplier.get(); - // the effects get stronger the longer you hold the item. - int effectDuration = duration == -1 ? -1 : effect.getDuration() * duration * timeFromStart / 500; - int effectAmplifier = effect.getAmplifier() * timeFromStart / 1000; - effectInstances.add(new MobEffectInstance(effect.getEffect(), effectDuration, effectAmplifier)); - } - return effectInstances; - } - - public Map getModifiersAtTime(int timeFromStart) { - if (this.modifiers.isEmpty()) { - return Object2ObjectMaps.emptyMap(); - } - Map modifierMap = new HashMap<>(); - for (var entry : this.modifiers.entrySet()) { - AttributeModifier modifier = entry.getValue(); - double amount = modifier.getAmount() * (double) timeFromStart / Math.max(duration, 1); - modifierMap.put(entry.getKey(), - new AttributeModifier(modifier.getId(), modifier.getName(), amount, modifier.getOperation())); - } - return modifierMap; - } - - public int getNewMaxAirSupplyAtTime(int timeFromStart) { - if (newMaxAirSupply == -1) { - return -1; - } - return newMaxAirSupply / Math.max(Math.round((float) timeFromStart / Math.max(duration, 1)), 1); - } - } } diff --git a/src/main/java/com/gregtechceu/gtceu/api/data/damagesource/DamageTypeData.java b/src/main/java/com/gregtechceu/gtceu/api/data/damagesource/DamageTypeData.java index 8964461237..e08ceedd28 100644 --- a/src/main/java/com/gregtechceu/gtceu/api/data/damagesource/DamageTypeData.java +++ b/src/main/java/com/gregtechceu/gtceu/api/data/damagesource/DamageTypeData.java @@ -117,7 +117,7 @@ public DamageTypeData.Builder location(String path) { */ public DamageTypeData.Builder simpleId(ResourceLocation location) { location(location); - return msgId(location.getNamespace() + "." + location.getPath()); + return msgId(location.toLanguageKey()); } public DamageTypeData.Builder simpleId(String path) { diff --git a/src/main/java/com/gregtechceu/gtceu/api/data/medicalcondition/MedicalCondition.java b/src/main/java/com/gregtechceu/gtceu/api/data/medicalcondition/MedicalCondition.java new file mode 100644 index 0000000000..a7b2ba18e5 --- /dev/null +++ b/src/main/java/com/gregtechceu/gtceu/api/data/medicalcondition/MedicalCondition.java @@ -0,0 +1,67 @@ +package com.gregtechceu.gtceu.api.data.medicalcondition; + +import com.gregtechceu.gtceu.api.data.damagesource.DamageTypeData; +import com.gregtechceu.gtceu.common.capability.MedicalConditionTracker; + +import net.minecraft.tags.DamageTypeTags; +import net.minecraft.world.damagesource.DamageScaling; +import net.minecraft.world.damagesource.DamageSource; +import net.minecraft.world.level.Level; + +import java.util.*; + +public class MedicalCondition { + + public static final Map CONDITIONS = new HashMap<>(); + + public final String name; + public final int color; + public final float maxProgression; // amount of seconds until maximum progression is reached + public final Set symptoms = new HashSet<>(); + private final DamageTypeData damageTypeData; + public final IdleProgressionType idleProgressionType; + public final float idleProgressionRate; + public final boolean canBePermanent; + + public MedicalCondition(String name, int color, int maxProgression, IdleProgressionType idleProgressionType, + float idleProgressionRate, boolean canBePermanent, Symptom.ConfiguredSymptom... symptoms) { + this.name = name; + this.color = color; + this.maxProgression = maxProgression; + this.damageTypeData = new DamageTypeData.Builder() + .simpleId("medical_condition/" + name) + .scaling(DamageScaling.ALWAYS) + .tag(DamageTypeTags.BYPASSES_ARMOR) + .build(); + + this.symptoms.addAll(Arrays.asList(symptoms)); + this.idleProgressionType = idleProgressionType; + this.idleProgressionRate = idleProgressionRate; + this.canBePermanent = canBePermanent; + + CONDITIONS.put(name, this); + } + + public MedicalCondition(String name, int color, int maxProgression, IdleProgressionType progressionType, + boolean canBePermanent, Symptom.ConfiguredSymptom... symptoms) { + this(name, color, maxProgression, progressionType, 1, canBePermanent, symptoms); + } + + public MedicalCondition(String name, int color, int maxProgression, Symptom.ConfiguredSymptom... symptoms) { + this(name, color, maxProgression, IdleProgressionType.NONE, 0, false, symptoms); + } + + public DamageSource getDamageSource(MedicalConditionTracker tracker) { + return damageTypeData.source(tracker.getPlayer().level()); + } + + public DamageSource getDamageSource(Level level) { + return damageTypeData.source(level); + } + + public enum IdleProgressionType { + UNTREATED_PROGRESSION, + HEAL, + NONE + } +} diff --git a/src/main/java/com/gregtechceu/gtceu/api/data/medicalcondition/Symptom.java b/src/main/java/com/gregtechceu/gtceu/api/data/medicalcondition/Symptom.java new file mode 100644 index 0000000000..473f36b40b --- /dev/null +++ b/src/main/java/com/gregtechceu/gtceu/api/data/medicalcondition/Symptom.java @@ -0,0 +1,197 @@ +package com.gregtechceu.gtceu.api.data.medicalcondition; + +import com.gregtechceu.gtceu.api.GTValues; +import com.gregtechceu.gtceu.common.capability.MedicalConditionTracker; +import com.gregtechceu.gtceu.common.data.GTMobEffects; + +import net.minecraft.world.effect.MobEffect; +import net.minecraft.world.effect.MobEffects; +import net.minecraft.world.entity.ai.attributes.Attribute; +import net.minecraft.world.entity.ai.attributes.AttributeModifier; +import net.minecraft.world.entity.ai.attributes.Attributes; +import net.minecraft.world.entity.player.Player; + +import org.jetbrains.annotations.Nullable; + +import java.util.UUID; +import java.util.function.Supplier; + +public class Symptom { + + public static final UUID SYMPTOM_HEALTH_DEBUFF_UUID = UUID.fromString("607aa6d9-a7e4-4919-9962-f007104c4be8"); + public static final UUID SYMPTOM_ATTACK_SPEED_DEBUFF_UUID = UUID.fromString("f2378ee6-3427-45b5-8440-4b797f7b664a"); + public static final UUID SYMPTOM_WEAKNESS_UUID = UUID.fromString("482e64e0-de77-49cd-b9bc-96b7e7eb16db"); + public static final UUID SYMPTOM_SLOWNESS_UUID = UUID.fromString("b3ac6b40-2d30-419f-9cac-5b2cf998ad72"); + + public static final Symptom DEATH = new Symptom(defaultKey("death"), 1, 1, + ((medicalConditionTracker, condition, configuredSymptom, baseSymptom, modifier) -> { + if (modifier > 0) { + Player player = medicalConditionTracker.getPlayer(); + player.hurt(condition.getDamageSource(medicalConditionTracker), player.getHealth()); + } + })); + public static final Symptom RANDOM_DAMAGE = new Symptom(defaultKey("random_damage"), 10, 1, + (medicalConditionTracker, condition, configuredSymptom, baseSymptom, modifier) -> {}, + (medicalConditionTracker, condition, configuredSymptom, baseSymptom, modifier) -> { + int stages = configuredSymptom != null ? configuredSymptom.stages : baseSymptom.defaultStages; + if (modifier > 0 && GTValues.RNG.nextInt(stages * 500 / modifier) == 0) { + medicalConditionTracker.getPlayer().hurt(condition.getDamageSource(medicalConditionTracker), 0.5f); + } + }); + public static final Symptom HEALTH_DEBUFF = new Symptom(defaultKey("health_debuff"), 10, 1, 1, + Attributes.MAX_HEALTH, SYMPTOM_HEALTH_DEBUFF_UUID); + public static final Symptom ATTACK_SPEED_DEBUFF = new Symptom(defaultKey("attack_speed_debuff"), 10, 1, .2f, + Attributes.ATTACK_SPEED, SYMPTOM_ATTACK_SPEED_DEBUFF_UUID); + public static final Symptom WEAKNESS = new Symptom(defaultKey("weakness"), 10, 1, .1f, Attributes.ATTACK_DAMAGE, + SYMPTOM_WEAKNESS_UUID); + public static final Symptom SLOWNESS = new Symptom(defaultKey("slowness"), 7, 1, .005f, Attributes.MOVEMENT_SPEED, + SYMPTOM_SLOWNESS_UUID); + public static final Symptom AIR_SUPPLY_DEBUFF = new Symptom(defaultKey("air_supply_debuff"), 10, 1, + (hazardEffectTracker, damageSource, configuredSymptom, baseSymptom, modifier) -> hazardEffectTracker + .setMaxAirSupply(300 - 10 * modifier)); + public static final Symptom BLINDNESS = new Symptom(defaultKey("blindness"), 10, 0, MobEffects.BLINDNESS); + public static final Symptom NAUSEA = new Symptom(defaultKey("nausea"), 10, 0, MobEffects.CONFUSION); + public static final Symptom MINING_FATIGUE = new Symptom(defaultKey("mining_fatigue"), 10, 1, + MobEffects.DIG_SLOWDOWN); + public static final Symptom WITHER = new Symptom(defaultKey("wither"), 1, 1, + MobEffects.WITHER); + public static final Symptom WEAK_POISONING = new Symptom(defaultKey("weak_poisoning"), 10, + 1, GTMobEffects.WEAK_POISON::get); + public static final Symptom POISONING = new Symptom(defaultKey("poisoning"), 10, + 1, MobEffects.POISON); + public static final Symptom HUNGER = new Symptom(defaultKey("hunger"), 5, 1, MobEffects.HUNGER); + + public final String name; + public final int defaultStages; + public final float defaultProgressionThreshold; + + // integer corresponds to symptom stage, if integer is 0 symptom effects should be removed + private final Effect progressionEffect; + private final Effect tickEffect; + + public Symptom(String name, int defaultStages, float defaultProgressionThreshold, + Effect progressionEffect, Effect tickEffect) { + this.name = name; + this.defaultStages = defaultStages; + this.defaultProgressionThreshold = defaultProgressionThreshold; + this.progressionEffect = progressionEffect; + this.tickEffect = tickEffect; + } + + public Symptom(String name, int defaultStages, float defaultProgressionThreshold, Effect progressionEffect) { + this(name, defaultStages, defaultProgressionThreshold, progressionEffect, + (tracker, condition, configuredSymptom, baseSymptom, amplifier) -> {}); + } + + /** + * @param multiplier multiplier for Attribute modification + * @param attribute Attribute to modify + * @param uuid AttributeModifier UUID + */ + public Symptom(String name, int defaultStages, float defaultProgressionThreshold, float multiplier, + Attribute attribute, UUID uuid) { + this(name, defaultStages, defaultProgressionThreshold, + ((medicalConditionTracker, $1, $2, $3, modifier) -> { + if (!medicalConditionTracker.getPlayer().getAttributes().hasAttribute(attribute)) { + return; + } + medicalConditionTracker.getPlayer().getAttribute(attribute).removeModifier(uuid); + if (modifier != 0) { + medicalConditionTracker.getPlayer().getAttribute(attribute).addPermanentModifier( + new AttributeModifier(uuid, name, -modifier * multiplier, + AttributeModifier.Operation.ADDITION)); + } + // re-set the health data value so the max health change is applied immediately + if (attribute == Attributes.MAX_HEALTH) { + medicalConditionTracker.getPlayer().setHealth(medicalConditionTracker.getPlayer().getHealth()); + } + })); + } + + /** + * @param mobEffect MobEffect to apply + * @param amplifierMultiplier amplifier added to MobEffect every progression + */ + public Symptom(String name, int defaultStages, float defaultProgressionThreshold, MobEffect mobEffect, + int amplifierMultiplier) { + this(name, defaultStages, defaultProgressionThreshold, + (medicalConditionTracker, $1, $2, $3, modifier) -> medicalConditionTracker.setMobEffect(mobEffect, + amplifierMultiplier * modifier)); + } + + /** + * @param mobEffect MobEffect to apply + * @param amplifierMultiplier amplifier added to MobEffect every progression + */ + public Symptom(String name, int defaultStages, float defaultProgressionThreshold, Supplier mobEffect, + int amplifierMultiplier) { + this(name, defaultStages, defaultProgressionThreshold, + (hazardEffectTracker, $1, $2, $3, modifier) -> hazardEffectTracker.setMobEffect(mobEffect.get(), + amplifierMultiplier * modifier)); + } + + /** + * @param mobEffect MobEffect to apply + */ + public Symptom(String name, int defaultStages, float defaultProgressionThreshold, MobEffect mobEffect) { + this(name, defaultStages, defaultProgressionThreshold, + (hazardEffectTracker, $1, $2, $3, modifier) -> hazardEffectTracker.setMobEffect(mobEffect, modifier)); + } + + /** + * @param mobEffect MobEffect to apply + */ + public Symptom(String name, int defaultStages, float defaultProgressionThreshold, Supplier mobEffect) { + this(name, defaultStages, defaultProgressionThreshold, + (hazardEffectTracker, $1, $2, $3, modifier) -> hazardEffectTracker.setMobEffect(mobEffect.get(), + modifier)); + } + + public void applyProgression(MedicalConditionTracker subject, MedicalCondition condition, + @Nullable ConfiguredSymptom symptom, int modifier) { + progressionEffect.apply(subject, condition, symptom, this, modifier); + } + + public void tick(MedicalConditionTracker subject, MedicalCondition condition, + @Nullable ConfiguredSymptom symptom, int modifier) { + tickEffect.apply(subject, condition, symptom, this, modifier); + } + + public static class ConfiguredSymptom { + + public final Symptom symptom; + public final int stages; + public final float progressionThreshold; + public final float relativeHarshness; + + public ConfiguredSymptom(Symptom symptom, int stages, float progressionThreshold) { + this.symptom = symptom; + this.stages = stages; + this.progressionThreshold = progressionThreshold; + this.relativeHarshness = (float) stages / symptom.defaultStages; + } + + public ConfiguredSymptom(Symptom symptom) { + this(symptom, symptom.defaultStages, symptom.defaultProgressionThreshold); + } + + public ConfiguredSymptom(Symptom symptom, int stages) { + this(symptom, stages, symptom.defaultProgressionThreshold); + } + + public ConfiguredSymptom(Symptom symptom, float progressionThreshold) { + this(symptom, symptom.defaultStages, progressionThreshold); + } + } + + @FunctionalInterface + public interface Effect { + + void apply(MedicalConditionTracker tracker, MedicalCondition condition, + @Nullable ConfiguredSymptom configuredSymptom, Symptom baseSymptom, int amplifier); + } + + private static String defaultKey(String name) { + return "symptom.gtceu." + name; + } +} diff --git a/src/main/java/com/gregtechceu/gtceu/api/data/worldgen/bedrockfluid/BedrockFluidVeinSavedData.java b/src/main/java/com/gregtechceu/gtceu/api/data/worldgen/bedrockfluid/BedrockFluidVeinSavedData.java index bd70abb4c6..df665401f3 100644 --- a/src/main/java/com/gregtechceu/gtceu/api/data/worldgen/bedrockfluid/BedrockFluidVeinSavedData.java +++ b/src/main/java/com/gregtechceu/gtceu/api/data/worldgen/bedrockfluid/BedrockFluidVeinSavedData.java @@ -54,11 +54,10 @@ public BedrockFluidVeinSavedData(ServerLevel serverLevel) { public BedrockFluidVeinSavedData(ServerLevel serverLevel, CompoundTag nbt) { this(serverLevel); var list = nbt.getList("veinInfo", Tag.TAG_COMPOUND); - for (Tag tag : list) { - if (tag instanceof CompoundTag compoundTag) { - var chunkPos = new ChunkPos(compoundTag.getLong("p")); - veinFluids.put(chunkPos, FluidVeinWorldEntry.readFromNBT(compoundTag.getCompound("d"))); - } + for (int i = 0; i < list.size(); ++i) { + CompoundTag compoundTag = list.getCompound(i); + var chunkPos = new ChunkPos(compoundTag.getLong("p")); + veinFluids.put(chunkPos, FluidVeinWorldEntry.readFromNBT(compoundTag.getCompound("d"))); } } diff --git a/src/main/java/com/gregtechceu/gtceu/api/item/DuctPipeBlockItem.java b/src/main/java/com/gregtechceu/gtceu/api/item/DuctPipeBlockItem.java new file mode 100644 index 0000000000..5563d6a409 --- /dev/null +++ b/src/main/java/com/gregtechceu/gtceu/api/item/DuctPipeBlockItem.java @@ -0,0 +1,30 @@ +package com.gregtechceu.gtceu.api.item; + +import com.gregtechceu.gtceu.common.block.DuctPipeBlock; + +import com.lowdragmc.lowdraglib.client.renderer.IItemRendererProvider; +import com.lowdragmc.lowdraglib.client.renderer.IRenderer; + +import net.minecraft.world.item.ItemStack; + +import org.jetbrains.annotations.NotNull; +import org.jetbrains.annotations.Nullable; + +public class DuctPipeBlockItem extends PipeBlockItem implements IItemRendererProvider { + + public DuctPipeBlockItem(DuctPipeBlock block, Properties properties) { + super(block, properties); + } + + @Override + @NotNull + public DuctPipeBlock getBlock() { + return (DuctPipeBlock) super.getBlock(); + } + + @Nullable + @Override + public IRenderer getRenderer(ItemStack stack) { + return getBlock().getRenderer(getBlock().defaultBlockState()); + } +} diff --git a/src/main/java/com/gregtechceu/gtceu/api/item/TagPrefixItem.java b/src/main/java/com/gregtechceu/gtceu/api/item/TagPrefixItem.java index 509c25185c..11b23d0da7 100644 --- a/src/main/java/com/gregtechceu/gtceu/api/item/TagPrefixItem.java +++ b/src/main/java/com/gregtechceu/gtceu/api/item/TagPrefixItem.java @@ -8,7 +8,6 @@ import com.gregtechceu.gtceu.api.item.armor.ArmorComponentItem; import com.gregtechceu.gtceu.client.renderer.item.TagPrefixItemRenderer; import com.gregtechceu.gtceu.common.data.GTDamageTypes; -import com.gregtechceu.gtceu.utils.GTUtil; import com.lowdragmc.lowdraglib.Platform; @@ -77,7 +76,6 @@ public void appendHoverText(ItemStack stack, @Nullable Level level, List tooltipComponents, - TooltipFlag isAdvanced) { - super.appendHoverText(stack, level, tooltipComponents, isAdvanced); - GTUtil.appendHazardTooltips(material, tooltipComponents); - } - @Override public Component getName(ItemStack stack) { return this.getDescription(); diff --git a/src/main/java/com/gregtechceu/gtceu/api/machine/feature/IEnvironmentalHazardEmitter.java b/src/main/java/com/gregtechceu/gtceu/api/machine/feature/IEnvironmentalHazardEmitter.java new file mode 100644 index 0000000000..cb2d1c6188 --- /dev/null +++ b/src/main/java/com/gregtechceu/gtceu/api/machine/feature/IEnvironmentalHazardEmitter.java @@ -0,0 +1,45 @@ +package com.gregtechceu.gtceu.api.machine.feature; + +import com.gregtechceu.gtceu.api.capability.GTCapabilityHelper; +import com.gregtechceu.gtceu.api.capability.IHazardParticleContainer; +import com.gregtechceu.gtceu.api.data.chemical.material.properties.HazardProperty; +import com.gregtechceu.gtceu.api.data.medicalcondition.MedicalCondition; +import com.gregtechceu.gtceu.common.capability.EnvironmentalHazardSavedData; +import com.gregtechceu.gtceu.common.data.GTMedicalConditions; + +import net.minecraft.server.level.ServerLevel; + +/** + * @author screret + * @date 2024/6/8 + * @apiNote common interface for environmental hazard (e.g. pollution) emitters like mufflers. + */ +public interface IEnvironmentalHazardEmitter extends IMachineFeature { + + /** + * @return the medical condition this hazard emitter creates. + */ + default MedicalCondition getConditionToEmit() { + return GTMedicalConditions.CARBON_MONOXIDE_POISONING; + } + + /** + * @return the starting strength of the hazard zone. + */ + int hazardStrengthPerOperation(); + + default void spreadEnvironmentalHazard() { + if (self().getLevel() instanceof ServerLevel serverLevel) { + IHazardParticleContainer container = GTCapabilityHelper.getHazardContainer(serverLevel, + self().getPos().relative(self().getFrontFacing()), self().getFrontFacing().getOpposite()); + if (container != null) { + container.addHazard(getConditionToEmit(), hazardStrengthPerOperation()); + return; + } + + var savedData = EnvironmentalHazardSavedData.getOrCreate(serverLevel); + savedData.addZone(self().getPos(), hazardStrengthPerOperation(), true, + HazardProperty.HazardTrigger.INHALATION, getConditionToEmit()); + } + } +} diff --git a/src/main/java/com/gregtechceu/gtceu/api/machine/feature/ILocalizedHazardEmitter.java b/src/main/java/com/gregtechceu/gtceu/api/machine/feature/ILocalizedHazardEmitter.java new file mode 100644 index 0000000000..bbf5c6626c --- /dev/null +++ b/src/main/java/com/gregtechceu/gtceu/api/machine/feature/ILocalizedHazardEmitter.java @@ -0,0 +1,45 @@ +package com.gregtechceu.gtceu.api.machine.feature; + +import com.gregtechceu.gtceu.api.capability.GTCapabilityHelper; +import com.gregtechceu.gtceu.api.capability.IHazardParticleContainer; +import com.gregtechceu.gtceu.api.data.chemical.material.properties.HazardProperty; +import com.gregtechceu.gtceu.api.data.medicalcondition.MedicalCondition; +import com.gregtechceu.gtceu.common.capability.LocalizedHazardSavedData; +import com.gregtechceu.gtceu.common.data.GTMedicalConditions; + +import net.minecraft.server.level.ServerLevel; + +/** + * @author screret + * @date 2024/6/9 + * @apiNote common interface for localized hazard (e.g. radiation) emitters like nuclear reactors. + */ +public interface ILocalizedHazardEmitter extends IMachineFeature { + + /** + * @return the medical condition this hazard emitter creates. + */ + default MedicalCondition getConditionToEmit() { + return GTMedicalConditions.CARCINOGEN; + } + + /** + * @return the starting strength of the hazard zone. recommended values are in the range [1,5) + */ + int hazardSizePerOperation(); + + default void spreadLocalizedHazard() { + if (self().getLevel() instanceof ServerLevel serverLevel) { + IHazardParticleContainer container = GTCapabilityHelper.getHazardContainer(serverLevel, + self().getPos().relative(self().getFrontFacing()), self().getFrontFacing().getOpposite()); + if (container != null) { + container.addHazard(getConditionToEmit(), hazardSizePerOperation()); + return; + } + + var savedData = LocalizedHazardSavedData.getOrCreate(serverLevel); + savedData.addSphericalZone(self().getPos(), hazardSizePerOperation(), false, + HazardProperty.HazardTrigger.INHALATION, getConditionToEmit()); + } + } +} diff --git a/src/main/java/com/gregtechceu/gtceu/api/machine/feature/multiblock/IMufflerMachine.java b/src/main/java/com/gregtechceu/gtceu/api/machine/feature/multiblock/IMufflerMachine.java index 3b1ae22283..b3c48498f1 100644 --- a/src/main/java/com/gregtechceu/gtceu/api/machine/feature/multiblock/IMufflerMachine.java +++ b/src/main/java/com/gregtechceu/gtceu/api/machine/feature/multiblock/IMufflerMachine.java @@ -1,9 +1,12 @@ package com.gregtechceu.gtceu.api.machine.feature.multiblock; import com.gregtechceu.gtceu.api.GTValues; +import com.gregtechceu.gtceu.api.capability.GTCapabilityHelper; import com.gregtechceu.gtceu.api.gui.GuiTextures; import com.gregtechceu.gtceu.api.gui.fancy.IFancyTooltip; import com.gregtechceu.gtceu.api.gui.fancy.TooltipsPanel; +import com.gregtechceu.gtceu.api.machine.feature.IEnvironmentalHazardEmitter; +import com.gregtechceu.gtceu.api.machine.multiblock.part.TieredPartMachine; import com.gregtechceu.gtceu.api.recipe.GTRecipe; import net.minecraft.ChatFormatting; @@ -16,21 +19,30 @@ import java.util.List; -public interface IMufflerMachine extends IMultiPart { +public interface IMufflerMachine extends IMultiPart, IEnvironmentalHazardEmitter { void recoverItemsTable(ItemStack... recoveryItems); /** - * @return true if front face is free and contains only air blocks in 1x1 area + * @return true if front face is free and contains only air blocks in 1x1 area OR has a duct block on it. */ default boolean isFrontFaceFree() { var frontPos = self().getPos().relative(self().getFrontFacing()); - return self().getLevel().getBlockState(frontPos).isAir(); + return self().getLevel().getBlockState(frontPos).isAir() || + GTCapabilityHelper.getHazardContainer(self().getLevel(), + frontPos, self().getFrontFacing().getOpposite()) != null; } default void emitPollutionParticles() { var pos = self().getPos(); var facing = self().getFrontFacing(); + + if (GTCapabilityHelper.getHazardContainer(self().getLevel(), + pos.relative(facing), facing.getOpposite()) != null) { + // do not emit particles if front face has a duct on it. + return; + } + float xPos = facing.getStepX() * 0.76F + pos.getX() + 0.25F; float yPos = facing.getStepY() * 0.76F + pos.getY() + 0.25F; float zPos = facing.getStepZ() * 0.76F + pos.getZ() + 0.25F; @@ -62,8 +74,15 @@ default GTRecipe modifyRecipe(GTRecipe recipe) { return IMultiPart.super.modifyRecipe(recipe); } + @Override + default int hazardStrengthPerOperation() { + int outputAmount = 5; + return this instanceof TieredPartMachine tiered ? outputAmount / Math.max(tiered.getTier(), 1) : outputAmount; + } + @Override default boolean afterWorking(IWorkableMultiController controller) { + spreadEnvironmentalHazard(); val supplier = controller.self().getDefinition().getRecoveryItems(); if (supplier != null) { recoverItemsTable(supplier.get()); diff --git a/src/main/java/com/gregtechceu/gtceu/client/TooltipsHandler.java b/src/main/java/com/gregtechceu/gtceu/client/TooltipsHandler.java index 53994f82be..35eb404cfb 100644 --- a/src/main/java/com/gregtechceu/gtceu/client/TooltipsHandler.java +++ b/src/main/java/com/gregtechceu/gtceu/client/TooltipsHandler.java @@ -2,7 +2,10 @@ import com.gregtechceu.gtceu.GTCEu; import com.gregtechceu.gtceu.api.data.chemical.ChemicalHelper; +import com.gregtechceu.gtceu.api.data.chemical.material.Material; +import com.gregtechceu.gtceu.api.data.chemical.material.properties.HazardProperty; import com.gregtechceu.gtceu.data.lang.LangHandler; +import com.gregtechceu.gtceu.utils.GTUtil; import net.minecraft.ChatFormatting; import net.minecraft.client.resources.language.I18n; @@ -28,18 +31,6 @@ public class TooltipsHandler { private static final String BLOCK_PREFIX = "block." + GTCEu.MOD_ID; public static void appendTooltips(ItemStack stack, TooltipFlag flag, List tooltips) { - // Energy Item - /* - * var energyItem = GTCapabilityHelper.getElectricItem(stack); - * if (energyItem != null) { - * tooltips.add(1, Component.translatable("metaitem.generic.electric_item.stored", - * energyItem.getCharge(), - * energyItem.getMaxCharge(), - * Component.literal(String.format("%.2f%%", energyItem.getCharge() * 100f / - * energyItem.getMaxCharge())).withStyle(ChatFormatting.GREEN))); - * } - */ - // Formula var unificationEntry = ChemicalHelper.getUnificationEntry(stack.getItem()); if (unificationEntry != null && unificationEntry.material != null) { @@ -57,11 +48,17 @@ public static void appendTooltips(ItemStack stack, TooltipFlag flag, List multiLang = LangHandler.getMultiLang(tooltipKey); - if (multiLang != null && multiLang.size() > 0) { + if (multiLang != null && !multiLang.isEmpty()) { tooltips.addAll(1, multiLang); } } } + + Material material = HazardProperty.getValidHazardMaterial(stack); + if (material == null) { + return; + } + GTUtil.appendHazardTooltips(material, tooltips); } public static void appendFluidTooltips(Fluid fluid, List tooltips, TooltipFlag flag) { diff --git a/src/main/java/com/gregtechceu/gtceu/client/renderer/machine/MachineRenderer.java b/src/main/java/com/gregtechceu/gtceu/client/renderer/machine/MachineRenderer.java index c0d3ffb40b..aa51bba997 100644 --- a/src/main/java/com/gregtechceu/gtceu/client/renderer/machine/MachineRenderer.java +++ b/src/main/java/com/gregtechceu/gtceu/client/renderer/machine/MachineRenderer.java @@ -84,8 +84,7 @@ public void renderItem(ItemStack stack, ItemDisplayContext transformType, boolea @Override @OnlyIn(Dist.CLIENT) - public List getQuads(@org.jetbrains.annotations.Nullable BlockState state, - @org.jetbrains.annotations.Nullable Direction direction, + public List getQuads(@Nullable BlockState state, @Nullable Direction direction, RandomSource random) { List quads = new LinkedList<>(); renderMachine(quads, machineItem.getDefinition(), null, Direction.NORTH, direction, random, @@ -117,16 +116,18 @@ public final List renderModel(@Nullable BlockAndTintGetter level, @Nu var itemFace = autoOutputItem.getOutputFacingItems(); if (itemFace != null && side == itemFace) { quads.add( - StaticFaceBakery.bakeFace(modelFacing, ModelFactory.getBlockSprite(PIPE_OVERLAY), - modelState)); + StaticFaceBakery.bakeFace(StaticFaceBakery.SLIGHTLY_OVER_BLOCK, + modelFacing, ModelFactory.getBlockSprite(PIPE_OVERLAY), + modelState, -1, 0, true, true)); } } if (machine instanceof IAutoOutputFluid autoOutputFluid) { var fluidFace = autoOutputFluid.getOutputFacingFluids(); if (fluidFace != null && side == fluidFace) { quads.add( - StaticFaceBakery.bakeFace(modelFacing, ModelFactory.getBlockSprite(PIPE_OVERLAY), - modelState)); + StaticFaceBakery.bakeFace(StaticFaceBakery.SLIGHTLY_OVER_BLOCK, + modelFacing, ModelFactory.getBlockSprite(PIPE_OVERLAY), modelState, + -1, 0, true, true)); } } @@ -134,8 +135,9 @@ public final List renderModel(@Nullable BlockAndTintGetter level, @Nu var itemFace = autoOutputItem.getOutputFacingItems(); if (itemFace != null && side == itemFace) { if (autoOutputItem.isAutoOutputItems()) { - quads.add(StaticFaceBakery.bakeFace(modelFacing, - ModelFactory.getBlockSprite(ITEM_OUTPUT_OVERLAY), modelState, -101, 15)); + quads.add(StaticFaceBakery.bakeFace(StaticFaceBakery.SLIGHTLY_OVER_BLOCK, + modelFacing, ModelFactory.getBlockSprite(ITEM_OUTPUT_OVERLAY), modelState, + -101, 15, true, true)); } } } @@ -144,8 +146,9 @@ public final List renderModel(@Nullable BlockAndTintGetter level, @Nu var fluidFace = autoOutputFluid.getOutputFacingFluids(); if (fluidFace != null && side == fluidFace) { if (autoOutputFluid.isAutoOutputFluids()) { - quads.add(StaticFaceBakery.bakeFace(modelFacing, - ModelFactory.getBlockSprite(FLUID_OUTPUT_OVERLAY), modelState, -101, 15)); + quads.add(StaticFaceBakery.bakeFace(StaticFaceBakery.SLIGHTLY_OVER_BLOCK, + modelFacing, ModelFactory.getBlockSprite(FLUID_OUTPUT_OVERLAY), modelState, + -101, 15, true, true)); } } } diff --git a/src/main/java/com/gregtechceu/gtceu/client/util/StaticFaceBakery.java b/src/main/java/com/gregtechceu/gtceu/client/util/StaticFaceBakery.java index 217be75df0..3f55ef5a2a 100644 --- a/src/main/java/com/gregtechceu/gtceu/client/util/StaticFaceBakery.java +++ b/src/main/java/com/gregtechceu/gtceu/client/util/StaticFaceBakery.java @@ -27,8 +27,8 @@ public class StaticFaceBakery { - public static final AABB SLIGHTLY_OVER_BLOCK = new AABB(-0.001f, -0.001f, -0.001f, 1.001f, 1.001f, - 1.001f); + public static final AABB SLIGHTLY_OVER_BLOCK = new AABB(-0.001f, -0.001f, -0.001f, + 1.001f, 1.001f, 1.001f); public static final int VERTEX_INT_SIZE = 8; private static final float RESCALE_22_5 = 1.0F / (float) Math.cos((float) (Math.PI / 8)) - 1.0F; diff --git a/src/main/java/com/gregtechceu/gtceu/common/block/DuctPipeBlock.java b/src/main/java/com/gregtechceu/gtceu/common/block/DuctPipeBlock.java new file mode 100644 index 0000000000..91bcd91853 --- /dev/null +++ b/src/main/java/com/gregtechceu/gtceu/common/block/DuctPipeBlock.java @@ -0,0 +1,90 @@ +package com.gregtechceu.gtceu.common.block; + +import com.gregtechceu.gtceu.api.block.PipeBlock; +import com.gregtechceu.gtceu.api.blockentity.PipeBlockEntity; +import com.gregtechceu.gtceu.api.capability.forge.GTCapability; +import com.gregtechceu.gtceu.api.pipenet.IPipeNode; +import com.gregtechceu.gtceu.client.model.PipeModel; +import com.gregtechceu.gtceu.client.renderer.block.PipeBlockRenderer; +import com.gregtechceu.gtceu.common.blockentity.DuctPipeBlockEntity; +import com.gregtechceu.gtceu.common.data.GTBlockEntities; +import com.gregtechceu.gtceu.common.pipelike.duct.DuctPipeProperties; +import com.gregtechceu.gtceu.common.pipelike.duct.DuctPipeType; +import com.gregtechceu.gtceu.common.pipelike.duct.LevelDuctPipeNet; + +import net.minecraft.MethodsReturnNonnullByDefault; +import net.minecraft.core.Direction; +import net.minecraft.server.level.ServerLevel; +import net.minecraft.world.item.ItemStack; +import net.minecraft.world.level.block.entity.BlockEntity; +import net.minecraft.world.level.block.entity.BlockEntityType; +import net.minecraft.world.level.block.state.BlockState; + +import org.jetbrains.annotations.Nullable; + +import javax.annotation.ParametersAreNonnullByDefault; + +@ParametersAreNonnullByDefault +@MethodsReturnNonnullByDefault +public class DuctPipeBlock extends PipeBlock { + + public final PipeBlockRenderer renderer; + public final PipeModel model; + private final DuctPipeProperties properties; + + public DuctPipeBlock(Properties properties, DuctPipeType type) { + super(properties, type); + this.properties = new DuctPipeProperties(type.getRateMultiplier()); + this.model = type.createPipeModel(); + this.renderer = new PipeBlockRenderer(this.model); + } + + @Override + public LevelDuctPipeNet getWorldPipeNet(ServerLevel world) { + return LevelDuctPipeNet.getOrCreate(world); + } + + @Override + public BlockEntityType> getBlockEntityType() { + return GTBlockEntities.DUCT_PIPE.get(); + } + + @Override + public DuctPipeProperties createRawData(BlockState pState, @Nullable ItemStack pStack) { + return properties; + } + + @Override + public DuctPipeProperties createProperties(IPipeNode pipeTile) { + DuctPipeType pipeType = pipeTile.getPipeType(); + if (pipeType == null) return getFallbackType(); + return this.pipeType.modifyProperties(properties); + } + + @Override + public DuctPipeProperties getFallbackType() { + return properties; + } + + @Override + public @Nullable PipeBlockRenderer getRenderer(BlockState state) { + return renderer; + } + + @Override + protected PipeModel getPipeModel() { + return model; + } + + @Override + public boolean canPipesConnect(IPipeNode selfTile, Direction side, + IPipeNode sideTile) { + return selfTile instanceof DuctPipeBlockEntity && sideTile instanceof DuctPipeBlockEntity; + } + + @Override + public boolean canPipeConnectToBlock(IPipeNode selfTile, Direction side, + @Nullable BlockEntity tile) { + return tile != null && tile.getCapability(GTCapability.CAPABILITY_LASER, side.getOpposite()).isPresent(); + } +} diff --git a/src/main/java/com/gregtechceu/gtceu/common/blockentity/DuctPipeBlockEntity.java b/src/main/java/com/gregtechceu/gtceu/common/blockentity/DuctPipeBlockEntity.java new file mode 100644 index 0000000000..c4ef806c7c --- /dev/null +++ b/src/main/java/com/gregtechceu/gtceu/common/blockentity/DuctPipeBlockEntity.java @@ -0,0 +1,149 @@ +package com.gregtechceu.gtceu.common.blockentity; + +import com.gregtechceu.gtceu.api.blockentity.PipeBlockEntity; +import com.gregtechceu.gtceu.api.capability.GTCapabilityHelper; +import com.gregtechceu.gtceu.api.capability.IHazardParticleContainer; +import com.gregtechceu.gtceu.api.capability.forge.GTCapability; +import com.gregtechceu.gtceu.api.data.medicalcondition.MedicalCondition; +import com.gregtechceu.gtceu.api.machine.IMachineBlockEntity; +import com.gregtechceu.gtceu.api.machine.feature.IEnvironmentalHazardEmitter; +import com.gregtechceu.gtceu.common.machine.electric.AirScrubberMachine; +import com.gregtechceu.gtceu.common.pipelike.duct.*; +import com.gregtechceu.gtceu.utils.GTUtil; + +import net.minecraft.core.BlockPos; +import net.minecraft.core.Direction; +import net.minecraft.server.level.ServerLevel; +import net.minecraft.world.level.block.entity.BlockEntityType; +import net.minecraft.world.level.block.state.BlockState; +import net.minecraftforge.common.capabilities.Capability; +import net.minecraftforge.common.util.LazyOptional; + +import lombok.Getter; +import org.jetbrains.annotations.NotNull; +import org.jetbrains.annotations.Nullable; + +import java.lang.ref.WeakReference; +import java.util.EnumMap; + +public class DuctPipeBlockEntity extends PipeBlockEntity { + + @Getter + protected final EnumMap handlers = new EnumMap<>(Direction.class); + // the DuctNetHandler can only be created on the server, so we have an empty placeholder for the client + public final IHazardParticleContainer clientCapability = new DefaultDuctContainer(); + private WeakReference currentPipeNet = new WeakReference<>(null); + @Getter + protected DuctNetHandler defaultHandler; + + protected DuctPipeBlockEntity(BlockEntityType type, BlockPos pos, BlockState blockState) { + super(type, pos, blockState); + } + + public static DuctPipeBlockEntity create(BlockEntityType type, BlockPos pos, BlockState blockState) { + return new DuctPipeBlockEntity(type, pos, blockState); + } + + public static void onBlockEntityRegister(BlockEntityType ductBlockEntityBlockEntityType) {} + + @Override + public @NotNull LazyOptional getCapability(@NotNull Capability cap, @Nullable Direction side) { + if (cap == GTCapability.CAPABILITY_HAZARD_CONTAINER) { + if (getLevel().isClientSide()) + return GTCapability.CAPABILITY_HAZARD_CONTAINER.orEmpty(cap, LazyOptional.of(() -> clientCapability)); + + if (handlers.isEmpty()) { + initHandlers(); + } + checkNetwork(); + return GTCapability.CAPABILITY_HAZARD_CONTAINER.orEmpty(cap, + LazyOptional.of(() -> handlers.getOrDefault(side, defaultHandler))); + } else if (cap == GTCapability.CAPABILITY_COVERABLE) { + return GTCapability.CAPABILITY_COVERABLE.orEmpty(cap, LazyOptional.of(this::getCoverContainer)); + } else if (cap == GTCapability.CAPABILITY_TOOLABLE) { + return GTCapability.CAPABILITY_TOOLABLE.orEmpty(cap, LazyOptional.of(() -> this)); + } + return super.getCapability(cap, side); + } + + @Override + public boolean canHaveBlockedFaces() { + return false; + } + + public void initHandlers() { + DuctPipeNet net = getDuctPipeNet(); + if (net == null) return; + for (Direction facing : GTUtil.DIRECTIONS) { + handlers.put(facing, new DuctNetHandler(net, this, facing)); + } + defaultHandler = new DuctNetHandler(net, this, null); + } + + public void checkNetwork() { + if (defaultHandler != null) { + DuctPipeNet current = getDuctPipeNet(); + if (defaultHandler.getNet() != current) { + defaultHandler.updateNetwork(current); + for (DuctNetHandler handler : handlers.values()) { + handler.updateNetwork(current); + } + } + } + } + + public DuctPipeNet getDuctPipeNet() { + if (level == null || level.isClientSide) { + return null; + } + DuctPipeNet currentPipeNet = this.currentPipeNet.get(); + if (currentPipeNet != null && currentPipeNet.isValid() && currentPipeNet.containsNode(getPipePos())) { + return currentPipeNet; + } + LevelDuctPipeNet worldNet = (LevelDuctPipeNet) getPipeBlock().getWorldPipeNet((ServerLevel) getPipeLevel()); + currentPipeNet = worldNet.getNetFromPos(getPipePos()); + if (currentPipeNet != null) { + this.currentPipeNet = new WeakReference<>(currentPipeNet); + } + return currentPipeNet; + } + + @Override + public boolean canAttachTo(Direction side) { + if (level != null) { + if (level.getBlockEntity(getBlockPos().relative(side)) instanceof DuctPipeBlockEntity) { + return false; + } + return GTCapabilityHelper.getHazardContainer(level, getBlockPos().relative(side), side.getOpposite()) != + null || + (level.getBlockEntity( + getBlockPos().relative(side)) instanceof IMachineBlockEntity machineBlockEntity && + (machineBlockEntity.getMetaMachine() instanceof AirScrubberMachine || + machineBlockEntity.getMetaMachine() instanceof IEnvironmentalHazardEmitter)); + } + return false; + } + + private static class DefaultDuctContainer implements IHazardParticleContainer { + + @Override + public boolean inputsHazard(Direction side, MedicalCondition condition) { + return false; + } + + @Override + public float changeHazard(MedicalCondition condition, float differenceAmount) { + return 0; + } + + @Override + public float getHazardStored(MedicalCondition condition) { + return 0; + } + + @Override + public float getHazardCapacity(MedicalCondition condition) { + return 0; + } + } +} diff --git a/src/main/java/com/gregtechceu/gtceu/common/capability/EnvironmentalHazardSavedData.java b/src/main/java/com/gregtechceu/gtceu/common/capability/EnvironmentalHazardSavedData.java new file mode 100644 index 0000000000..b05b1d92c6 --- /dev/null +++ b/src/main/java/com/gregtechceu/gtceu/common/capability/EnvironmentalHazardSavedData.java @@ -0,0 +1,250 @@ +package com.gregtechceu.gtceu.common.capability; + +import com.gregtechceu.gtceu.api.GTValues; +import com.gregtechceu.gtceu.api.capability.GTCapabilityHelper; +import com.gregtechceu.gtceu.api.capability.IMedicalConditionTracker; +import com.gregtechceu.gtceu.api.data.chemical.material.properties.HazardProperty; +import com.gregtechceu.gtceu.api.data.medicalcondition.MedicalCondition; +import com.gregtechceu.gtceu.config.ConfigHolder; + +import net.minecraft.core.BlockPos; +import net.minecraft.core.particles.DustParticleOptions; +import net.minecraft.nbt.CompoundTag; +import net.minecraft.nbt.ListTag; +import net.minecraft.nbt.NbtUtils; +import net.minecraft.nbt.Tag; +import net.minecraft.server.level.ServerLevel; +import net.minecraft.server.level.ServerPlayer; +import net.minecraft.world.item.ArmorItem; +import net.minecraft.world.level.ChunkPos; +import net.minecraft.world.level.saveddata.SavedData; +import net.minecraft.world.phys.Vec3; + +import lombok.Getter; +import org.jetbrains.annotations.NotNull; +import org.jetbrains.annotations.Nullable; + +import java.util.HashMap; +import java.util.HashSet; +import java.util.Map; +import java.util.Set; +import java.util.stream.Stream; + +/** + * Full-chunk environmental hazards. e.g. pollution. + */ +public class EnvironmentalHazardSavedData extends SavedData { + + public static final int MIN_STRENGTH_FOR_SPREAD = 1000; + + private final ServerLevel serverLevel; + + /** + * Map of source position to a triple of (trigger, material). + */ + @Getter + private final Map hazardZones = new HashMap<>(); + + public static EnvironmentalHazardSavedData getOrCreate(ServerLevel serverLevel) { + return serverLevel.getDataStorage().computeIfAbsent(tag -> new EnvironmentalHazardSavedData(serverLevel, tag), + () -> new EnvironmentalHazardSavedData(serverLevel), "gtceu_environmental_hazard_tracker"); + } + + public EnvironmentalHazardSavedData(ServerLevel serverLevel) { + this.serverLevel = serverLevel; + } + + public EnvironmentalHazardSavedData(ServerLevel serverLevel, CompoundTag tag) { + this(serverLevel); + ListTag allHazardZones = tag.getList("zones", Tag.TAG_COMPOUND); + for (int i = 0; i < allHazardZones.size(); ++i) { + CompoundTag zoneTag = allHazardZones.getCompound(i); + + ChunkPos source = new ChunkPos(zoneTag.getLong("pos")); + HazardZone zone = HazardZone.deserializeNBT(zoneTag); + + this.hazardZones.put(source, zone); + } + } + + public void tick() { + if (!ConfigHolder.INSTANCE.gameplay.environmentalHazards) { + return; + } + + Set zonesToSpread = new HashSet<>(); + for (final var entry : hazardZones.entrySet()) { + HazardZone zone = entry.getValue(); + if (zone.strength() >= MIN_STRENGTH_FOR_SPREAD / 5) { + ChunkPos chunkPos = entry.getKey(); + BlockPos source = entry.getKey().getMiddleBlockPosition(zone.source().getY()); + for (BlockPos pos : BlockPos.betweenClosed( + chunkPos.getMinBlockX(), source.getY() - 8, chunkPos.getMinBlockZ(), + chunkPos.getMaxBlockX(), source.getY() + 8, chunkPos.getMaxBlockZ())) { + if (GTValues.RNG.nextInt(32000 / zone.strength()) == 0) { + serverLevel.sendParticles( + new DustParticleOptions(Vec3.fromRGB24(zone.condition.color).toVector3f(), 1), + pos.getX() + 0.5, pos.getY() + 0.5, pos.getZ() + 0.5, + 1, 0, 0.1, 0, 0.1); + } + } + } + + Stream playersInZone = serverLevel.players() + .stream() + .filter(player -> new ChunkPos(BlockPos.containing(player.getEyePosition())) + .equals(entry.getKey())); + tickPlayerHazards(zone, playersInZone); + + if (zone.canSpread() && zone.strength() > MIN_STRENGTH_FOR_SPREAD) { + zonesToSpread.add(entry.getKey()); + } + } + + for (ChunkPos pos : zonesToSpread) { + final HazardZone zone = hazardZones.get(pos); + ChunkPos[] relativePositions = new ChunkPos[] { + new ChunkPos(pos.x, pos.z - 1), + new ChunkPos(pos.x, pos.z + 1), + new ChunkPos(pos.x - 1, pos.z), + new ChunkPos(pos.x + 1, pos.z) + }; + int removedStrength = 0; + for (ChunkPos relativePos : relativePositions) { + hazardZones.compute(relativePos, (k, v) -> { + if (v != null && v.condition() == zone.condition() && v.trigger() == zone.trigger()) { + return new HazardZone(v.source(), 20 + v.strength(), true, + v.trigger(), v.condition()); + } else { + return new HazardZone(k.getMiddleBlockPosition(zone.source().getY()), 20, true, + zone.trigger(), zone.condition()); + } + }); + removedStrength += 20; + } + hazardZones.replace(pos, new HazardZone(zone.source(), + zone.strength - removedStrength, false, zone.trigger(), zone.condition())); + this.setDirty(); + } + } + + public void tickPlayerHazards(final HazardZone zone, Stream playerStream) { + playerStream.forEach(player -> { + if (zone.trigger().protectionType().isProtected(player)) { + // entity has proper safety equipment, so damage it per material every 5 seconds. + if (player.level().getGameTime() % 100 == 0) { + for (ArmorItem.Type type : zone.trigger().protectionType().getEquipmentTypes()) { + player.getItemBySlot(type.getSlot()).hurtAndBreak(1, player, + p -> p.broadcastBreakEvent(type.getSlot())); + } + } + // don't progress this material condition if entity is protected + return; + } + + IMedicalConditionTracker tracker = GTCapabilityHelper.getMedicalConditionTracker(player); + if (tracker == null) { + return; + } + tracker.progressCondition(zone.condition(), zone.strength() / 1000f); + }); + } + + /** + * finds the hazard zone that's in the chunk the block pos is in and has the correct condition. + * + * @param containedPos the position to find zones for. + * @return all zones that were found. + */ + @Nullable + public HazardZone getZoneByContainedPos(BlockPos containedPos) { + return hazardZones.get(new ChunkPos(containedPos)); + } + + /** + * finds all hazard zones that contain the given position and have the correct condition. + * + * @param containedPos the position to find zones for. + * @return all zones that were found. + */ + @Nullable + public HazardZone getZoneByContainedPosAndCondition(BlockPos containedPos, MedicalCondition condition) { + HazardZone zone = hazardZones.get(new ChunkPos(containedPos)); + return zone != null && zone.condition == condition ? zone : null; + } + + public void removeZone(BlockPos inChunkPos) { + this.removeZone(new ChunkPos(inChunkPos)); + } + + public void removeZone(BlockPos inChunkPos, MedicalCondition condition) { + ChunkPos chunkPos = new ChunkPos(inChunkPos); + if (this.hazardZones.get(chunkPos).condition() == condition) { + this.hazardZones.remove(chunkPos); + } + } + + public void removeZone(ChunkPos chunkPos) { + this.hazardZones.remove(chunkPos); + } + + public void addZone(ChunkPos source, HazardZone zone) { + if (!ConfigHolder.INSTANCE.gameplay.environmentalHazards) { + return; + } + if (this.hazardZones.containsKey(source) && this.hazardZones.get(source).condition == zone.condition) { + // noinspection DataFlowIssue + this.hazardZones.compute(source, (k, oldZone) -> new HazardZone(oldZone.source(), + oldZone.strength() + zone.strength(), zone.canSpread(), zone.trigger(), zone.condition())); + } else if (!this.hazardZones.containsKey(source)) { + this.hazardZones.put(source, zone); + } + this.setDirty(); + } + + public void addZone(BlockPos source, int strength, boolean canSpread, + HazardProperty.HazardTrigger trigger, MedicalCondition condition) { + addZone(new ChunkPos(source), new HazardZone(source, strength, canSpread, trigger, condition)); + } + + @NotNull + @Override + public CompoundTag save(@NotNull CompoundTag compoundTag) { + ListTag hazardZonesTag = new ListTag(); + for (var entry : hazardZones.entrySet()) { + CompoundTag zoneTag = new CompoundTag(); + + zoneTag.putLong("pos", entry.getKey().toLong()); + entry.getValue().serializeNBT(zoneTag); + + hazardZonesTag.add(zoneTag); + } + compoundTag.put("zones", hazardZonesTag); + return compoundTag; + } + + public record HazardZone(BlockPos source, int strength, boolean canSpread, + HazardProperty.HazardTrigger trigger, MedicalCondition condition) { + + public CompoundTag serializeNBT(CompoundTag zoneTag) { + zoneTag.put("source", NbtUtils.writeBlockPos(source)); + zoneTag.putInt("strength", strength); + zoneTag.putBoolean("can_spread", canSpread); + zoneTag.putString("trigger", trigger.name()); + zoneTag.putString("condition", condition.name); + + return zoneTag; + } + + public static HazardZone deserializeNBT(CompoundTag zoneTag) { + BlockPos source = NbtUtils.readBlockPos(zoneTag.getCompound("source")); + int strength = zoneTag.getInt("strength"); + boolean canSpread = zoneTag.getBoolean("can_spread"); + HazardProperty.HazardTrigger trigger = HazardProperty.HazardTrigger.ALL_TRIGGERS + .get(zoneTag.getString("trigger")); + MedicalCondition condition = MedicalCondition.CONDITIONS.get(zoneTag.getString("condition")); + + return new HazardZone(source, strength, canSpread, trigger, condition); + } + } +} diff --git a/src/main/java/com/gregtechceu/gtceu/common/capability/HazardEffectTracker.java b/src/main/java/com/gregtechceu/gtceu/common/capability/HazardEffectTracker.java deleted file mode 100644 index 248434454e..0000000000 --- a/src/main/java/com/gregtechceu/gtceu/common/capability/HazardEffectTracker.java +++ /dev/null @@ -1,168 +0,0 @@ -package com.gregtechceu.gtceu.common.capability; - -import com.gregtechceu.gtceu.api.GTCEuAPI; -import com.gregtechceu.gtceu.api.capability.IHazardEffectTracker; -import com.gregtechceu.gtceu.api.data.chemical.material.Material; -import com.gregtechceu.gtceu.api.data.chemical.material.properties.HazardProperty; -import com.gregtechceu.gtceu.api.data.chemical.material.properties.PropertyKey; - -import net.minecraft.nbt.CompoundTag; -import net.minecraft.nbt.ListTag; -import net.minecraft.nbt.StringTag; -import net.minecraft.nbt.Tag; -import net.minecraft.world.effect.MobEffectInstance; -import net.minecraft.world.entity.ai.attributes.AttributeInstance; -import net.minecraft.world.entity.ai.attributes.AttributeModifier; -import net.minecraft.world.entity.player.Player; -import net.minecraft.world.item.ArmorItem; -import net.minecraftforge.common.util.INBTSerializable; - -import it.unimi.dsi.fastutil.objects.Object2IntMap; -import it.unimi.dsi.fastutil.objects.Object2IntOpenHashMap; -import lombok.Getter; -import lombok.Setter; -import org.jetbrains.annotations.NotNull; - -import java.util.HashSet; -import java.util.Set; - -public class HazardEffectTracker implements IHazardEffectTracker, INBTSerializable { - - @Getter - @Setter - private int maxAirSupply = -1; - @Getter - private final Set extraHazards = new HashSet<>(); - @Getter - private final Object2IntMap currentHazards = new Object2IntOpenHashMap<>(); - - private final Player player; - - private int totalMaxAirSupply, maxAirSupplySetterAmount; - - public HazardEffectTracker(Player player) { - this.player = player; - } - - @Override - public void startTick() { - for (Material material : this.getExtraHazards()) { - tick(material); - } - } - - @Override - public void tick(@NotNull Material material) { - HazardProperty property = material.getProperty(PropertyKey.HAZARD); - if (property == null) { - return; - } - int time = currentHazards.getOrDefault(material, 0); - - if (property.getHazardType().protectionType().isProtected(player)) { - // entity has proper safety equipment, so damage it per material every 5 seconds. - if (player.level().getGameTime() % 100 == 0) { - for (ArmorItem.Type type : property.getHazardType().protectionType().getEquipmentTypes()) { - player.getItemBySlot(type.getSlot()).hurtAndBreak(1, player, - p -> p.broadcastBreakEvent(type.getSlot())); - } - } - // exit the hazard applying after. - return; - } - - int totalTime = 0; - int effectsCount = 0; - for (HazardProperty.HazardEffect effect : property.getEffects()) { - totalTime += effect.duration() + effect.modifierStartTime(); - effectsCount++; - if (time < effect.modifierStartTime()) { - // if the current applied time is less than the minimum for effects to be applied, return early. - continue; - } - - for (MobEffectInstance mobEffect : effect.getEffectInstancesAtTime(time)) { - player.addEffect(mobEffect); - } - var attributeModifiers = effect.getModifiersAtTime(time); - for (var modifierEntry : attributeModifiers.entrySet()) { - AttributeModifier modifier = modifierEntry.getValue(); - AttributeInstance attributeInstance = player.getAttribute(modifierEntry.getKey()); - if (attributeInstance == null) { - continue; - } - - if (attributeInstance.hasModifier(modifier)) { - attributeInstance.removeModifier(modifier); - } - attributeInstance.addPermanentModifier(modifier); - } - int maxAirSupply = effect.getNewMaxAirSupplyAtTime(time); - if (maxAirSupply >= 0) { - totalMaxAirSupply += maxAirSupply; - maxAirSupplySetterAmount++; - } - } - - currentHazards.put(material, time += 1); - // if the hazardous material has been held for 5x the average of the effects' start times, make it permanent. - // this also makes it tick 1 more time per tick, thus speeding up the effects. - if (time >= 5 * (totalTime / effectsCount)) { - extraHazards.add(material); - } - } - - @Override - public void endTick() { - if (maxAirSupplySetterAmount > 0) { - this.setMaxAirSupply(totalMaxAirSupply / maxAirSupplySetterAmount); - } - totalMaxAirSupply = 0; - maxAirSupplySetterAmount = 0; - } - - @Override - public CompoundTag serializeNBT() { - CompoundTag tag = new CompoundTag(); - - ListTag effectsTag = new ListTag(); - for (var effect : currentHazards.object2IntEntrySet()) { - if (effect.getKey() == null) { - continue; - } - CompoundTag effectTag = new CompoundTag(); - effectTag.putString("material", effect.getKey().getResourceLocation().toString()); - effectTag.putInt("time", effect.getIntValue()); - effectsTag.add(effectTag); - } - tag.put("effects", effectsTag); - - ListTag extrasTag = new ListTag(); - for (Material material : extraHazards) { - extrasTag.add(StringTag.valueOf(material.getResourceLocation().toString())); - } - tag.put("extras", extrasTag); - - return tag; - } - - @Override - public void deserializeNBT(CompoundTag arg) { - ListTag effects = arg.getList("effects", Tag.TAG_COMPOUND); - for (Tag tag : effects) { - if (!(tag instanceof CompoundTag compoundTag)) { - continue; - } - Material material = GTCEuAPI.materialManager.getMaterial(compoundTag.getString("material")); - int time = compoundTag.getInt("time"); - currentHazards.put(material, time); - } - ListTag extras = arg.getList("extras", Tag.TAG_STRING); - for (Tag tag : extras) { - if (!(tag instanceof StringTag stringTag)) { - continue; - } - extraHazards.add(GTCEuAPI.materialManager.getMaterial(stringTag.getAsString())); - } - } -} diff --git a/src/main/java/com/gregtechceu/gtceu/common/capability/LocalizedHazardSavedData.java b/src/main/java/com/gregtechceu/gtceu/common/capability/LocalizedHazardSavedData.java new file mode 100644 index 0000000000..4e730ea5d3 --- /dev/null +++ b/src/main/java/com/gregtechceu/gtceu/common/capability/LocalizedHazardSavedData.java @@ -0,0 +1,332 @@ +package com.gregtechceu.gtceu.common.capability; + +import com.gregtechceu.gtceu.api.GTValues; +import com.gregtechceu.gtceu.api.capability.GTCapabilityHelper; +import com.gregtechceu.gtceu.api.capability.IMedicalConditionTracker; +import com.gregtechceu.gtceu.api.data.chemical.material.properties.HazardProperty; +import com.gregtechceu.gtceu.api.data.medicalcondition.MedicalCondition; +import com.gregtechceu.gtceu.config.ConfigHolder; +import com.gregtechceu.gtceu.utils.BreadthFirstBlockSearch; + +import net.minecraft.core.BlockPos; +import net.minecraft.core.particles.DustParticleOptions; +import net.minecraft.nbt.CompoundTag; +import net.minecraft.nbt.ListTag; +import net.minecraft.nbt.NbtUtils; +import net.minecraft.nbt.Tag; +import net.minecraft.server.level.ServerLevel; +import net.minecraft.server.level.ServerPlayer; +import net.minecraft.world.item.ArmorItem; +import net.minecraft.world.level.saveddata.SavedData; +import net.minecraft.world.phys.Vec3; + +import it.unimi.dsi.fastutil.objects.Object2IntMap; +import it.unimi.dsi.fastutil.objects.Object2IntOpenHashMap; +import lombok.Getter; +import org.jetbrains.annotations.NotNull; +import org.jetbrains.annotations.Nullable; + +import java.util.*; +import java.util.stream.Collectors; +import java.util.stream.Stream; + +/** + * localized, block-based environmental hazards. e.g. radiation. + * do not use for large-scale effects, as this stores all blocks where an effect is, and thus will be too slow for that. + */ +public class LocalizedHazardSavedData extends SavedData { + + public static final int MIN_STRENGTH_FOR_SPREAD = 100; + + private final ServerLevel serverLevel; + + /** + * Map of source position to a triple of (trigger, material). + */ + @Getter + private final Map hazardZones = new HashMap<>(); + + public static LocalizedHazardSavedData getOrCreate(ServerLevel serverLevel) { + return serverLevel.getDataStorage().computeIfAbsent(tag -> new LocalizedHazardSavedData(serverLevel, tag), + () -> new LocalizedHazardSavedData(serverLevel), "gtceu_localized_hazard_tracker"); + } + + public LocalizedHazardSavedData(ServerLevel serverLevel) { + this.serverLevel = serverLevel; + } + + public LocalizedHazardSavedData(ServerLevel serverLevel, CompoundTag tag) { + this(serverLevel); + ListTag allHazardZones = tag.getList("zones", Tag.TAG_COMPOUND); + for (int i = 0; i < allHazardZones.size(); ++i) { + CompoundTag zoneTag = allHazardZones.getCompound(i); + + BlockPos source = BlockPos.of(zoneTag.getLong("pos")); + HazardZone zone = HazardZone.deserializeNBT(zoneTag); + + this.hazardZones.put(source, zone); + } + } + + public void tick() { + if (!ConfigHolder.INSTANCE.gameplay.environmentalHazards) { + return; + } + + Object2IntMap zonesToSpread = new Object2IntOpenHashMap<>(); + for (final var entry : hazardZones.entrySet()) { + HazardZone zone = entry.getValue(); + if (zone.strength() >= MIN_STRENGTH_FOR_SPREAD / 5) { + // try to spawn particles on every block in the zone if it's loaded and empty. + for (BlockPos pos : zone.blocks()) { + if (serverLevel.isLoaded(pos) && serverLevel.getBlockState(pos).isAir() && + GTValues.RNG.nextInt(32000 / zone.strength()) == 0) { + serverLevel.sendParticles( + new DustParticleOptions(Vec3.fromRGB24(zone.condition.color).toVector3f(), 1), + pos.getX() + 0.5, pos.getY() + 0.5, pos.getZ() + 0.5, + 1, 0, 0.1, 0, 0.1); + } + } + } + + Stream playersInZone = serverLevel.players() + .stream() + .filter(player -> zone.blocks().contains(BlockPos.containing(player.getEyePosition()))); + tickPlayerHazards(zone, playersInZone); + + if (zone.canSpread() && zone.strength() > MIN_STRENGTH_FOR_SPREAD) { + zonesToSpread.put(entry.getKey(), (zone.strength() - MIN_STRENGTH_FOR_SPREAD) / 500); + } + } + + zonesToSpread.forEach(this::expandHazard); + } + + public void tickPlayerHazards(final HazardZone zone, Stream playerStream) { + playerStream.forEach(player -> { + if (zone.trigger().protectionType().isProtected(player)) { + // entity has proper safety equipment, so damage it per material every 5 seconds. + if (player.level().getGameTime() % 100 == 0) { + for (ArmorItem.Type type : zone.trigger().protectionType().getEquipmentTypes()) { + player.getItemBySlot(type.getSlot()).hurtAndBreak(1, player, + p -> p.broadcastBreakEvent(type.getSlot())); + } + } + // don't progress this material condition if entity is protected + return; + } + + IMedicalConditionTracker tracker = GTCapabilityHelper.getMedicalConditionTracker(player); + if (tracker == null) { + return; + } + tracker.progressCondition(zone.condition(), zone.strength() / 1000f); + }); + } + + /** + * finds the hazard zone that's in the chunk the block pos is in and has the correct condition. + * + * @param containedPos the position to find zones for. + * @return all zones that were found. + */ + @Nullable + public HazardZone getZoneByContainedPos(BlockPos containedPos) { + for (HazardZone zone : hazardZones.values()) { + if (zone.blocks().contains(containedPos)) { + return zone; + } + } + return null; + } + + /** + * finds all hazard zones that contain the given position and have the correct condition. + * + * @param containedPos the position to find zones for. + * @return all zones that were found. + */ + @Nullable + public HazardZone getZoneByContainedPosAndCondition(BlockPos containedPos, MedicalCondition condition) { + for (HazardZone zone : hazardZones.values()) { + if (zone.condition() == condition && zone.blocks().contains(containedPos)) { + return zone; + } + } + return null; + } + + public void removeZoneByPosition(BlockPos containedPos) { + BlockPos toRemove = null; + for (var entry : hazardZones.entrySet()) { + if (entry.getValue().blocks().contains(containedPos)) { + toRemove = entry.getKey(); + } + } + hazardZones.remove(toRemove); + } + + public void removeZoneByPosition(BlockPos containedPos, MedicalCondition condition) { + BlockPos toRemove = null; + for (var entry : hazardZones.entrySet()) { + if (entry.getValue().condition() == condition && entry.getValue().blocks().contains(containedPos)) { + toRemove = entry.getKey(); + } + } + hazardZones.remove(toRemove); + } + + public boolean expandHazard(BlockPos source, int blocksToAdd) { + if (blocksToAdd <= 0) { + return false; + } + if (this.hazardZones.containsKey(source)) { + final HazardZone zone = hazardZones.get(source); + + Set allValidBlocks = BreadthFirstBlockSearch.search(blockPos -> !zone.blocks().contains(blockPos), + source, blocksToAdd); + + for (BlockPos found : allValidBlocks) { + zone.blocks().add(found); + } + this.setDirty(); + return true; + } + return false; + } + + public void addSphericalZone(BlockPos source, int sphereRadius, boolean canSpread, + HazardProperty.HazardTrigger trigger, MedicalCondition condition) { + if (expandHazard(source, (int) ((4.0 / 3) * Math.PI * Math.pow(sphereRadius, 3) / 50))) { + return; + } + + Set blocks = new HashSet<>(); + for (int x = -sphereRadius; x < sphereRadius; x++) { + for (int y = -sphereRadius; y < sphereRadius; y++) { + for (int z = -sphereRadius; z < sphereRadius; z++) { + float sizeFractionX = (float) x / sphereRadius; + float sizeFractionY = (float) y / sphereRadius; + float sizeFractionZ = (float) z / sphereRadius; + if ((sizeFractionX * sizeFractionX) + + (sizeFractionY * sizeFractionY) + + (sizeFractionZ * sizeFractionZ) <= 1) { + blocks.add(source.offset(x, y, z)); + } + } + } + } + + this.hazardZones.put(source, new HazardZone(blocks, canSpread, trigger, condition)); + this.setDirty(); + } + + public void addCuboidZone(BlockPos source, int sizeX, int sizeY, int sizeZ, boolean canSpread, + HazardProperty.HazardTrigger trigger, MedicalCondition condition) { + if (expandHazard(source, sizeX * sizeY * sizeZ / 100)) { + return; + } + + Set blocks = new HashSet<>(); + sizeX = sizeX / 2; + sizeY = sizeY / 2; + sizeZ = sizeZ / 2; + for (int x = -sizeX; x < sizeX; x++) { + for (int y = -sizeY; y < sizeY; y++) { + for (int z = -sizeZ; z < sizeZ; z++) { + blocks.add(source.offset(x, y, z)); + } + } + } + + this.hazardZones.put(source, new HazardZone(blocks, canSpread, trigger, condition)); + this.setDirty(); + } + + public void addCuboidZone(BlockPos source, int size, boolean canSpread, + HazardProperty.HazardTrigger trigger, MedicalCondition condition) { + if (expandHazard(source, size * size * size / 100)) { + return; + } + + Set blocks = new HashSet<>(); + size = size / 2; + for (int x = -size; x < size; x++) { + for (int y = -size; y < size; y++) { + for (int z = -size; z < size; z++) { + blocks.add(source.offset(x, y, z)); + } + } + } + + this.hazardZones.put(source, new HazardZone(blocks, canSpread, trigger, condition)); + this.setDirty(); + } + + public void addCuboidZone(BlockPos source, BlockPos start, BlockPos end, boolean canSpread, + HazardProperty.HazardTrigger trigger, MedicalCondition condition) { + int sizeX = start.getX() - end.getX(); + int sizeY = start.getY() - end.getY(); + int sizeZ = start.getZ() - end.getZ(); + if (expandHazard(source, Math.abs(sizeX * sizeY * sizeZ) / 100)) { + return; + } + + Set blocks = new HashSet<>(); + for (BlockPos pos : BlockPos.betweenClosed(start, end)) { + blocks.add(pos.immutable()); + } + this.hazardZones.put(source, new HazardZone(blocks, canSpread, trigger, condition)); + this.setDirty(); + } + + @NotNull + @Override + public CompoundTag save(@NotNull CompoundTag compoundTag) { + ListTag hazardZonesTag = new ListTag(); + for (var entry : hazardZones.entrySet()) { + CompoundTag zoneTag = new CompoundTag(); + + zoneTag.putLong("pos", entry.getKey().asLong()); + entry.getValue().serializeNBT(zoneTag); + + hazardZonesTag.add(zoneTag); + } + compoundTag.put("zones", hazardZonesTag); + return compoundTag; + } + + public record HazardZone(Set blocks, boolean canSpread, + HazardProperty.HazardTrigger trigger, MedicalCondition condition) { + + public int strength() { + return blocks.size(); + } + + public CompoundTag serializeNBT(CompoundTag zoneTag) { + ListTag blocksTag = new ListTag(); + blocks.stream() + .map(NbtUtils::writeBlockPos) + .forEach(blocksTag::add); + zoneTag.put("blocks", blocksTag); + zoneTag.putBoolean("can_spread", canSpread); + zoneTag.putString("trigger", trigger.name()); + zoneTag.putString("condition", condition.name); + + return zoneTag; + } + + public static HazardZone deserializeNBT(CompoundTag zoneTag) { + Set blocks = zoneTag.getList("blocks", Tag.TAG_COMPOUND).stream() + .map(CompoundTag.class::cast) + .map(NbtUtils::readBlockPos) + .collect(Collectors.toSet()); + boolean canSpread = zoneTag.getBoolean("can_spread"); + HazardProperty.HazardTrigger trigger = HazardProperty.HazardTrigger.ALL_TRIGGERS + .get(zoneTag.getString("trigger")); + MedicalCondition condition = MedicalCondition.CONDITIONS.get(zoneTag.getString("condition")); + + return new HazardZone(blocks, canSpread, trigger, condition); + } + } +} diff --git a/src/main/java/com/gregtechceu/gtceu/common/capability/MedicalConditionTracker.java b/src/main/java/com/gregtechceu/gtceu/common/capability/MedicalConditionTracker.java new file mode 100644 index 0000000000..06cfaa04b0 --- /dev/null +++ b/src/main/java/com/gregtechceu/gtceu/common/capability/MedicalConditionTracker.java @@ -0,0 +1,224 @@ +package com.gregtechceu.gtceu.common.capability; + +import com.gregtechceu.gtceu.api.capability.IMedicalConditionTracker; +import com.gregtechceu.gtceu.api.data.medicalcondition.MedicalCondition; +import com.gregtechceu.gtceu.api.data.medicalcondition.Symptom; + +import net.minecraft.nbt.CompoundTag; +import net.minecraft.nbt.ListTag; +import net.minecraft.nbt.StringTag; +import net.minecraft.nbt.Tag; +import net.minecraft.world.effect.MobEffect; +import net.minecraft.world.effect.MobEffectInstance; +import net.minecraft.world.entity.player.Player; +import net.minecraftforge.common.util.INBTSerializable; + +import it.unimi.dsi.fastutil.objects.Object2FloatMap; +import it.unimi.dsi.fastutil.objects.Object2FloatOpenHashMap; +import it.unimi.dsi.fastutil.objects.Object2IntMap; +import it.unimi.dsi.fastutil.objects.Object2IntOpenHashMap; +import lombok.Getter; +import lombok.Setter; +import org.jetbrains.annotations.NotNull; + +import java.util.*; + +public class MedicalConditionTracker implements IMedicalConditionTracker, INBTSerializable { + + @Getter + private final Object2FloatMap medicalConditions = new Object2FloatOpenHashMap<>(); + private final Set permanentConditions = new HashSet<>(); + private final Object2IntMap activeSymptoms = new Object2IntOpenHashMap<>(); + private final Object2IntMap activeMobEffects = new Object2IntOpenHashMap<>(); + + private final Set flaggedForRemoval = new HashSet<>(); + + @Setter + private int maxAirSupply = -1; + + @Getter + private final Player player; + + public MedicalConditionTracker(Player player) { + this.player = player; + } + + @Override + public void tick() { + for (var entry : activeMobEffects.object2IntEntrySet()) { + player.addEffect(new MobEffectInstance(entry.getKey(), 100, entry.getIntValue())); + } + + if (player.level().getGameTime() % 20 == 0) { // apply idle progression every second + for (MedicalCondition condition : medicalConditions.keySet()) { + if (condition.idleProgressionType == MedicalCondition.IdleProgressionType.NONE) { + continue; + } + if (permanentConditions.contains(condition) && + condition.idleProgressionType == MedicalCondition.IdleProgressionType.HEAL) { + // can't automatically heal permanent conditions. + continue; + } + int multiplier = (condition.idleProgressionType == MedicalCondition.IdleProgressionType.HEAL) ? -1 : 1; + medicalConditions.replace(condition, + medicalConditions.getFloat(condition) + condition.idleProgressionRate * multiplier); + evaluateMedicalCondition(condition); + } + if (!medicalConditions.isEmpty()) { + updateActiveSymptoms(); + } + } + } + + public void progressCondition(@NotNull MedicalCondition condition, float strength) { + medicalConditions.put(condition, medicalConditions.getOrDefault(condition, 0) + strength); + + updateActiveSymptoms(); + } + + private void updateActiveSymptoms() { + for (MedicalCondition condition : medicalConditions.keySet()) { + if (medicalConditions.getFloat(condition) >= condition.maxProgression * 2) { + // If condition has been applied for 2x the maximum time, make it permanent. + permanentConditions.add(condition); + } + + for (Symptom.ConfiguredSymptom symptom : condition.symptoms) { + int stage = calculateStage(condition, symptom); + if (stage <= 0) { + continue; + } + symptom.symptom.tick(this, condition, symptom, stage); + + Optional currentSymptomOptional = activeSymptoms.keySet() + .stream() + .filter(symptom1 -> symptom1.symptom == symptom.symptom) + .findFirst(); + if (currentSymptomOptional.isEmpty()) { + activeSymptoms.put(symptom, stage); + symptom.symptom.applyProgression(this, condition, null, stage); + continue; + } + Symptom.ConfiguredSymptom currentSymptom = currentSymptomOptional.get(); + if (currentSymptom == symptom && stage > activeSymptoms.getOrDefault(symptom, 0)) { + symptom.symptom.applyProgression(this, condition, symptom, + activeSymptoms.getOrDefault(symptom, 0)); + activeSymptoms.replace(symptom, stage); + symptom.symptom.applyProgression(this, condition, symptom, stage); + continue; + } + if (symptom.relativeHarshness * stage > + currentSymptom.relativeHarshness * activeSymptoms.getOrDefault(currentSymptom, 0)) { + currentSymptom.symptom.applyProgression(this, condition, symptom, + activeSymptoms.getOrDefault(currentSymptom, 0)); + activeSymptoms.removeInt(currentSymptom); + activeSymptoms.put(symptom, stage); + symptom.symptom.applyProgression(this, condition, symptom, stage); + } + } + } + + if (flaggedForRemoval.isEmpty()) { + return; + } + for (MedicalCondition condition : flaggedForRemoval) { + for (Symptom.ConfiguredSymptom configuredSymptom : activeSymptoms.keySet().stream() + .filter(condition.symptoms::contains).toList()) { + // reset all symptom effects for this condition + configuredSymptom.symptom.applyProgression(this, condition, configuredSymptom, 0); + } + medicalConditions.removeFloat(condition); + } + flaggedForRemoval.clear(); + } + + @Override + public void removeMedicalCondition(MedicalCondition condition) { + flaggedForRemoval.add(condition); + permanentConditions.remove(condition); + } + + private int calculateStage(MedicalCondition condition, Symptom.ConfiguredSymptom symptom) { + return (int) Math.floor(Math.min(medicalConditions.getFloat(condition), condition.maxProgression) / + (symptom.progressionThreshold * condition.maxProgression * symptom.stages)); + } + + // removes MedicalConditions without progression + private void evaluateMedicalCondition(MedicalCondition condition) { + if (permanentConditions.contains(condition)) { + return; + } + if (medicalConditions.getFloat(condition) <= 0) { + removeMedicalCondition(condition); + } + } + + /** + * called on antidote/cure consumption + * + * @param condition MedicalCondition to heal + * @param progression amount of progression to decrease + */ + @Override + public void heal(MedicalCondition condition, int progression) { + if (progression >= medicalConditions.getOrDefault(condition, 0)) { + medicalConditions.removeFloat(condition); + permanentConditions.remove(condition); + return; + } + medicalConditions.replace(condition, medicalConditions.getOrDefault(condition, 0) - progression); + } + + @Override + public int getMaxAirSupply() { + return maxAirSupply; + } + + @Override + public void setMobEffect(MobEffect effect, int amplifier) { + if (amplifier <= 0) { + activeMobEffects.removeInt(effect); + } else if (amplifier >= activeMobEffects.getOrDefault(effect, -1)) { + activeMobEffects.put(effect, amplifier); + } + } + + @Override + public CompoundTag serializeNBT() { + CompoundTag tag = new CompoundTag(); + + ListTag effectsTag = new ListTag(); + for (var entry : medicalConditions.object2FloatEntrySet()) { + CompoundTag medicalConditionTag = new CompoundTag(); + medicalConditionTag.putString("condition", entry.getKey().name); + medicalConditionTag.putFloat("progression", entry.getFloatValue()); + effectsTag.add(medicalConditionTag); + } + tag.put("medical_conditions", effectsTag); + + ListTag permanentsTag = new ListTag(); + for (MedicalCondition condition : permanentConditions) { + permanentsTag.add(StringTag.valueOf(condition.name)); + } + tag.put("permanent_conditions", permanentsTag); + + return tag; + } + + @Override + public void deserializeNBT(CompoundTag arg) { + ListTag medicalConditionsTag = arg.getList("medical_conditions", Tag.TAG_COMPOUND); + for (int i = 0; i < medicalConditionsTag.size(); ++i) { + CompoundTag compoundTag = medicalConditionsTag.getCompound(i); + MedicalCondition condition = MedicalCondition.CONDITIONS.get(compoundTag.getString("condition")); + float progression = compoundTag.getFloat("progression"); + + medicalConditions.put(condition, progression); + } + + ListTag permanentConditionsTag = arg.getList("permanent_conditions", Tag.TAG_STRING); + for (int i = 0; i < permanentConditionsTag.size(); ++i) { + permanentConditions.add(MedicalCondition.CONDITIONS.get(permanentConditionsTag.getString(i))); + } + } +} diff --git a/src/main/java/com/gregtechceu/gtceu/common/commands/ServerCommands.java b/src/main/java/com/gregtechceu/gtceu/common/commands/ServerCommands.java index 2c4aaa17bb..3817cb59d6 100644 --- a/src/main/java/com/gregtechceu/gtceu/common/commands/ServerCommands.java +++ b/src/main/java/com/gregtechceu/gtceu/common/commands/ServerCommands.java @@ -1,27 +1,38 @@ package com.gregtechceu.gtceu.common.commands; import com.gregtechceu.gtceu.api.capability.GTCapabilityHelper; -import com.gregtechceu.gtceu.api.capability.IHazardEffectTracker; -import com.gregtechceu.gtceu.api.data.chemical.material.Material; +import com.gregtechceu.gtceu.api.capability.IMedicalConditionTracker; import com.gregtechceu.gtceu.api.data.chemical.material.properties.HazardProperty; -import com.gregtechceu.gtceu.api.data.chemical.material.properties.PropertyKey; +import com.gregtechceu.gtceu.api.data.medicalcondition.MedicalCondition; import com.gregtechceu.gtceu.api.gui.factory.GTUIEditorFactory; import com.gregtechceu.gtceu.api.recipe.GTRecipe; -import com.gregtechceu.gtceu.common.commands.arguments.MaterialArgument; +import com.gregtechceu.gtceu.common.capability.EnvironmentalHazardSavedData; +import com.gregtechceu.gtceu.common.capability.LocalizedHazardSavedData; +import com.gregtechceu.gtceu.common.commands.arguments.MedicalConditionArgument; import net.minecraft.commands.CommandSourceStack; import net.minecraft.commands.Commands; import net.minecraft.commands.arguments.EntityArgument; +import net.minecraft.commands.arguments.coordinates.BlockPosArgument; +import net.minecraft.core.BlockPos; import net.minecraft.network.chat.Component; +import net.minecraft.server.level.ServerLevel; import net.minecraft.server.level.ServerPlayer; import net.minecraft.world.item.crafting.Recipe; +import com.mojang.brigadier.arguments.*; import com.mojang.brigadier.builder.LiteralArgumentBuilder; +import com.mojang.brigadier.context.CommandContext; +import com.mojang.brigadier.exceptions.CommandSyntaxException; import com.mojang.brigadier.exceptions.SimpleCommandExceptionType; +import org.jetbrains.annotations.Nullable; import java.util.Collection; +import java.util.Collections; import java.util.List; +import static net.minecraft.commands.Commands.*; + /** * @author KilaBash * @date 2023/2/9 @@ -30,22 +41,20 @@ public class ServerCommands { private static final SimpleCommandExceptionType ERROR_CLEAR_EVERYTHING_FAILED = new SimpleCommandExceptionType( - Component.translatable("commands.effect.clear.everything.failed")); - private static final SimpleCommandExceptionType ERROR_INVALID_MATERIAL = new SimpleCommandExceptionType( - Component.translatable("commands.gtceu.hazard.invalid.material")); + Component.translatable("effect.clear.everything.failed")); private static final SimpleCommandExceptionType ERROR_GIVE_FAILED = new SimpleCommandExceptionType( - Component.translatable("commands.effect.give.failed")); + Component.translatable("effect.give.failed")); public static List> createServerCommands() { return List.of( - Commands.literal("gtceu") - .then(Commands.literal("ui_editor") + literal("gtceu") + .then(literal("ui_editor") .executes(context -> { GTUIEditorFactory.INSTANCE.openUI(GTUIEditorFactory.INSTANCE, context.getSource().getPlayerOrException()); return 1; })) - .then(Commands.literal("check_recipes_valid") + .then(literal("check_recipes_valid") .requires(cs -> cs.hasPermission(0)) .executes(context -> { for (Recipe recipe : context.getSource().getServer().getRecipeManager() @@ -59,66 +68,205 @@ public static List> createServerComma } return 1; })) - .then(Commands.literal("hazard") + .then(literal("medical_condition") .requires(source -> source.hasPermission(2)) - .then(Commands.literal("clear") - .executes(context -> { - ServerPlayer target = context.getSource().getPlayerOrException(); - IHazardEffectTracker tracker = GTCapabilityHelper - .getHazardEffectTracker(target); - if (tracker == null) { - throw EntityArgument.NO_PLAYERS_FOUND.create(); - } - int count = tracker.getCurrentHazards().keySet().size(); - tracker.getCurrentHazards().clear(); - return count; - }) - .then(Commands.argument("targets", EntityArgument.players()) - .executes(context -> { - Collection targets = EntityArgument - .getPlayers(context, "targets"); - int count = 0; - for (ServerPlayer target : targets) { - IHazardEffectTracker tracker = GTCapabilityHelper - .getHazardEffectTracker(target); - if (tracker == null) { - continue; - } - count += tracker.getCurrentHazards().keySet().size(); - tracker.getCurrentHazards().clear(); - } - if (count == 0) { - throw ERROR_CLEAR_EVERYTHING_FAILED.create(); - } - return count; - }))) - .then(Commands.literal("apply") - .then(Commands.argument("targets", EntityArgument.players()) - .then(Commands.argument("material", MaterialArgument.material()) + .then(literal("query") + .executes(context -> queryMedicalConditions( + context.getSource().getPlayerOrException())) + .then(argument("target", EntityArgument.player()) + .executes(context -> queryMedicalConditions( + EntityArgument.getPlayer(context, "target"))))) + .then(literal("clear") + .executes(context -> clearMedicalConditions( + Collections.singleton(context.getSource().getPlayerOrException()), + null)) + .then(argument("targets", EntityArgument.players()) + .executes(context -> clearMedicalConditions( + EntityArgument.getPlayers(context, "targets"), null)) + .then(argument("condition", + MedicalConditionArgument.medicalCondition()) + .executes(context -> { + Collection targets = EntityArgument + .getPlayers(context, "targets"); + MedicalCondition condition = MedicalConditionArgument + .getCondition(context, "condition"); + return clearMedicalConditions(targets, condition); + })))) + .then(literal("apply") + .then(argument("targets", EntityArgument.players()) + .then(argument("condition", + MedicalConditionArgument.medicalCondition()) .executes(context -> { - Material material = MaterialArgument.getMaterial(context, - "material"); + MedicalCondition condition = MedicalConditionArgument + .getCondition(context, "condition"); Collection players = EntityArgument .getPlayers(context, "targets"); - int success = 0; - HazardProperty property = material - .getProperty(PropertyKey.HAZARD); - if (property == null) { - throw ERROR_INVALID_MATERIAL.create(); - } - for (ServerPlayer player : players) { - IHazardEffectTracker tracker = GTCapabilityHelper - .getHazardEffectTracker(player); - if (tracker == null) { - continue; - } - tracker.getExtraHazards().add(material); - success++; - } - if (success == 0) { - throw ERROR_GIVE_FAILED.create(); - } - return success; + return applyMedicalConditions(players, condition, 1); + }).then(argument("progression_multiplier", + FloatArgumentType.floatArg(0)) + .executes(context -> { + MedicalCondition condition = MedicalConditionArgument + .getCondition(context, "condition"); + Collection players = EntityArgument + .getPlayers(context, "targets"); + float strength = FloatArgumentType.getFloat( + context, + "progression_multiplier"); + return applyMedicalConditions(players, + condition, strength); + })))))) + .then(literal("environmental_hazard") + .then(argument("condition", MedicalConditionArgument.medicalCondition()) + .then(argument("can_spread", BoolArgumentType.bool()) + .then(argument("source", BlockPosArgument.blockPos()) + .then(literal("chunk") + .then(Commands + .argument("strength", + IntegerArgumentType.integer(1)) + .executes( + ServerCommands::spawnChunkEnvironmentalHazard))) + .then(literal("local") + .then(Commands + .argument("from", BlockPosArgument.blockPos()) + .then(Commands + .argument("to", + BlockPosArgument.blockPos()) + .executes( + ServerCommands::spawnLocalEnvironmentalHazard))))))) + .then(literal("clear") + .then(argument("source", BlockPosArgument.blockPos()) + .executes(context -> { + BlockPos source = BlockPosArgument.getBlockPos(context, "source"); + return clearEnvironmentalHazard(context, source, null); + }) + .then(argument("condition", MedicalConditionArgument.medicalCondition()) + .executes(context -> { + BlockPos source = BlockPosArgument.getBlockPos(context, + "source"); + MedicalCondition condition = MedicalConditionArgument + .getCondition(context, "condition"); + return clearEnvironmentalHazard(context, source, condition); })))))); } + + private static int queryMedicalConditions(ServerPlayer target) throws CommandSyntaxException { + IMedicalConditionTracker tracker = GTCapabilityHelper + .getMedicalConditionTracker(target); + if (tracker == null) { + throw EntityArgument.NO_PLAYERS_FOUND.create(); + } + int count = tracker.getMedicalConditions().size(); + if (count == 0) { + + target.sendSystemMessage( + Component.translatable( + "command.gtceu.medical_condition.get.empty", + target.getName())); + } else { + target.sendSystemMessage( + Component.translatable("command.gtceu.medical_condition.get", + target.getName())); + } + for (var entry : tracker.getMedicalConditions().object2FloatEntrySet()) { + String langKey = "command.gtceu.medical_condition.get.element"; + if (entry.getKey().maxProgression * 2 <= entry.getFloatValue() && + entry.getKey().canBePermanent) { + langKey = "command.gtceu.medical_condition.get.element.permanent"; + } + target.sendSystemMessage( + Component.translatable( + langKey, + Component.translatable("gtceu.medical_condition." + + entry.getKey().name), + entry.getFloatValue() / 20f)); + } + return count; + } + + private static int clearMedicalConditions(Collection targets, + @Nullable MedicalCondition condition) throws CommandSyntaxException { + int count = 0; + for (ServerPlayer target : targets) { + IMedicalConditionTracker tracker = GTCapabilityHelper + .getMedicalConditionTracker(target); + if (tracker == null) { + continue; + } + if (condition == null) { + count += tracker.getMedicalConditions().keySet().size(); + for (MedicalCondition medicalCondition : tracker.getMedicalConditions() + .keySet()) { + tracker.removeMedicalCondition(medicalCondition); + } + } else { + count++; + tracker.removeMedicalCondition(condition); + } + } + if (count == 0) { + throw ERROR_CLEAR_EVERYTHING_FAILED.create(); + } + return count; + } + + private static int applyMedicalConditions(Collection targets, + MedicalCondition condition, + float strength) throws CommandSyntaxException { + int success = 0; + for (ServerPlayer player : targets) { + IMedicalConditionTracker tracker = GTCapabilityHelper + .getMedicalConditionTracker(player); + if (tracker == null) { + continue; + } + tracker.progressCondition(condition, strength); + success++; + } + if (success == 0) { + throw ERROR_GIVE_FAILED.create(); + } + return success; + } + + private static int spawnChunkEnvironmentalHazard(CommandContext context) { + ServerLevel serverLevel = context.getSource().getLevel(); + + BlockPos source = BlockPosArgument.getBlockPos(context, "source"); + int strength = IntegerArgumentType.getInteger(context, "strength"); + MedicalCondition condition = MedicalConditionArgument.getCondition(context, "condition"); + boolean canSpread = BoolArgumentType.getBool(context, "can_spread"); + + EnvironmentalHazardSavedData.getOrCreate(serverLevel) + .addZone(source, strength, canSpread, HazardProperty.HazardTrigger.INHALATION, condition); + + return 1; + } + + private static int spawnLocalEnvironmentalHazard(CommandContext context) { + ServerLevel serverLevel = context.getSource().getLevel(); + BlockPos source = BlockPosArgument.getBlockPos(context, "source"); + BlockPos from = BlockPosArgument.getBlockPos(context, "from"); + BlockPos to = BlockPosArgument.getBlockPos(context, "to"); + + MedicalCondition condition = MedicalConditionArgument.getCondition(context, "condition"); + boolean canSpread = BoolArgumentType.getBool(context, "can_spread"); + + LocalizedHazardSavedData.getOrCreate(serverLevel) + .addCuboidZone(source, from, to, canSpread, HazardProperty.HazardTrigger.INHALATION, condition); + + return 1; + } + + private static int clearEnvironmentalHazard(CommandContext context, + BlockPos clearAt, MedicalCondition condition) { + ServerLevel serverLevel = context.getSource().getLevel(); + if (condition == null) { + EnvironmentalHazardSavedData.getOrCreate(serverLevel).removeZone(clearAt); + LocalizedHazardSavedData.getOrCreate(serverLevel).removeZoneByPosition(clearAt); + } else { + EnvironmentalHazardSavedData.getOrCreate(serverLevel).removeZone(clearAt, condition); + LocalizedHazardSavedData.getOrCreate(serverLevel).removeZoneByPosition(clearAt, condition); + } + return 1; + } } diff --git a/src/main/java/com/gregtechceu/gtceu/common/commands/arguments/MaterialParser.java b/src/main/java/com/gregtechceu/gtceu/common/commands/arguments/MaterialParser.java index cd2b4b55e9..1f20096401 100644 --- a/src/main/java/com/gregtechceu/gtceu/common/commands/arguments/MaterialParser.java +++ b/src/main/java/com/gregtechceu/gtceu/common/commands/arguments/MaterialParser.java @@ -64,10 +64,9 @@ public static CompletableFuture fillSuggestions(IMaterialRegistryMa try { materialParser.parse(); - } catch (CommandSyntaxException var6) {} + } catch (CommandSyntaxException ignored) {} - return (CompletableFuture) materialParser.suggestions - .apply(builder.createOffset(stringReader.getCursor())); + return materialParser.suggestions.apply(builder.createOffset(stringReader.getCursor())); } private void readMaterial() throws CommandSyntaxException { @@ -85,14 +84,6 @@ private void parse() throws CommandSyntaxException { this.readMaterial(); } - private CompletableFuture suggestOpenNbt(SuggestionsBuilder builder) { - if (builder.getRemaining().isEmpty()) { - builder.suggest(String.valueOf('{')); - } - - return builder.buildFuture(); - } - private CompletableFuture suggestMaterial(SuggestionsBuilder builder) { return SharedSuggestionProvider.suggestResource( this.materials.getRegisteredMaterials().stream().map(Material::getResourceLocation), builder); diff --git a/src/main/java/com/gregtechceu/gtceu/common/commands/arguments/MedicalConditionArgument.java b/src/main/java/com/gregtechceu/gtceu/common/commands/arguments/MedicalConditionArgument.java new file mode 100644 index 0000000000..c3fdae68a4 --- /dev/null +++ b/src/main/java/com/gregtechceu/gtceu/common/commands/arguments/MedicalConditionArgument.java @@ -0,0 +1,44 @@ +package com.gregtechceu.gtceu.common.commands.arguments; + +import com.gregtechceu.gtceu.api.data.medicalcondition.MedicalCondition; + +import com.mojang.brigadier.StringReader; +import com.mojang.brigadier.arguments.ArgumentType; +import com.mojang.brigadier.context.CommandContext; +import com.mojang.brigadier.exceptions.CommandSyntaxException; +import com.mojang.brigadier.suggestion.Suggestions; +import com.mojang.brigadier.suggestion.SuggestionsBuilder; + +import java.util.Arrays; +import java.util.Collection; +import java.util.concurrent.CompletableFuture; + +public class MedicalConditionArgument implements ArgumentType { + + private static final Collection EXAMPLES = Arrays.asList("chemical_burns", "carcinogen", "asbestosis"); + + public MedicalConditionArgument() {} + + public static MedicalConditionArgument medicalCondition() { + return new MedicalConditionArgument(); + } + + @Override + public MedicalCondition parse(StringReader reader) throws CommandSyntaxException { + return MedicalConditionParser.parseForMedicalCondition(reader); + } + + public static MedicalCondition getCondition(CommandContext context, String name) { + return context.getArgument(name, MedicalCondition.class); + } + + @Override + public CompletableFuture listSuggestions(CommandContext context, SuggestionsBuilder builder) { + return MedicalConditionParser.fillSuggestions(builder); + } + + @Override + public Collection getExamples() { + return EXAMPLES; + } +} diff --git a/src/main/java/com/gregtechceu/gtceu/common/commands/arguments/MedicalConditionParser.java b/src/main/java/com/gregtechceu/gtceu/common/commands/arguments/MedicalConditionParser.java new file mode 100644 index 0000000000..201b06a4fb --- /dev/null +++ b/src/main/java/com/gregtechceu/gtceu/common/commands/arguments/MedicalConditionParser.java @@ -0,0 +1,82 @@ +package com.gregtechceu.gtceu.common.commands.arguments; + +import com.gregtechceu.gtceu.api.data.medicalcondition.MedicalCondition; + +import net.minecraft.commands.SharedSuggestionProvider; +import net.minecraft.network.chat.Component; +import net.minecraft.resources.ResourceLocation; + +import com.mojang.brigadier.StringReader; +import com.mojang.brigadier.exceptions.CommandSyntaxException; +import com.mojang.brigadier.exceptions.DynamicCommandExceptionType; +import com.mojang.brigadier.suggestion.Suggestions; +import com.mojang.brigadier.suggestion.SuggestionsBuilder; + +import java.util.Optional; +import java.util.concurrent.CompletableFuture; +import java.util.function.Function; + +public class MedicalConditionParser { + + private static final DynamicCommandExceptionType ERROR_UNKNOWN_ITEM = new DynamicCommandExceptionType( + id -> Component.translatable("argument.item.id.invalid", id)); + private static final Function> SUGGEST_NOTHING = SuggestionsBuilder::buildFuture; + private final StringReader reader; + private MedicalCondition result; + /** + * Builder to be used when creating a list of suggestions + */ + private Function> suggestions = SUGGEST_NOTHING; + + private MedicalConditionParser(StringReader reader) { + this.reader = reader; + } + + public static MedicalCondition parseForMedicalCondition(StringReader reader) throws CommandSyntaxException { + int i = reader.getCursor(); + + try { + MedicalConditionParser materialParser = new MedicalConditionParser(reader); + materialParser.parse(); + return materialParser.result; + } catch (CommandSyntaxException var5) { + reader.setCursor(i); + throw var5; + } + } + + public static CompletableFuture fillSuggestions(SuggestionsBuilder builder) { + StringReader stringReader = new StringReader(builder.getInput()); + stringReader.setCursor(builder.getStart()); + MedicalConditionParser materialParser = new MedicalConditionParser(stringReader); + + try { + materialParser.parse(); + } catch (CommandSyntaxException ignored) {} + + return materialParser.suggestions.apply(builder.createOffset(stringReader.getCursor())); + } + + private void readMedicalCondition() throws CommandSyntaxException { + int i = this.reader.getCursor(); + + while (reader.canRead() && ResourceLocation.isAllowedInResourceLocation(reader.peek())) { + reader.skip(); + } + String name = reader.getString().substring(i, reader.getCursor()); + MedicalCondition material = MedicalCondition.CONDITIONS.get(name); + this.result = Optional.ofNullable(material).orElseThrow(() -> { + this.reader.setCursor(i); + return ERROR_UNKNOWN_ITEM.createWithContext(this.reader, name); + }); + } + + private void parse() throws CommandSyntaxException { + this.suggestions = this::suggestMedicalCondition; + this.readMedicalCondition(); + } + + private CompletableFuture suggestMedicalCondition(SuggestionsBuilder builder) { + return SharedSuggestionProvider.suggest(MedicalCondition.CONDITIONS.keySet(), builder); + } +} diff --git a/src/main/java/com/gregtechceu/gtceu/common/data/GTBlockEntities.java b/src/main/java/com/gregtechceu/gtceu/common/data/GTBlockEntities.java index 560d4fcbed..8ea9fd9630 100644 --- a/src/main/java/com/gregtechceu/gtceu/common/data/GTBlockEntities.java +++ b/src/main/java/com/gregtechceu/gtceu/common/data/GTBlockEntities.java @@ -48,6 +48,12 @@ public class GTBlockEntities { .validBlocks(GTBlocks.OPTICAL_PIPES) .register(); + public static final BlockEntityEntry DUCT_PIPE = REGISTRATE + .blockEntity("duct_pipe", DuctPipeBlockEntity::create) + .onRegister(DuctPipeBlockEntity::onBlockEntityRegister) + .validBlocks(GTBlocks.DUCT_PIPES) + .register(); + public static final BlockEntityEntry GT_SIGN = REGISTRATE .blockEntity("sign", SignBlockEntity::new) .validBlocks(GTBlocks.RUBBER_SIGN, diff --git a/src/main/java/com/gregtechceu/gtceu/common/data/GTBlocks.java b/src/main/java/com/gregtechceu/gtceu/common/data/GTBlocks.java index 115f9d5a58..be6189e0e4 100644 --- a/src/main/java/com/gregtechceu/gtceu/common/data/GTBlocks.java +++ b/src/main/java/com/gregtechceu/gtceu/common/data/GTBlocks.java @@ -26,6 +26,7 @@ import com.gregtechceu.gtceu.common.block.explosive.IndustrialTNTBlock; import com.gregtechceu.gtceu.common.block.explosive.PowderbarrelBlock; import com.gregtechceu.gtceu.common.pipelike.cable.Insulation; +import com.gregtechceu.gtceu.common.pipelike.duct.DuctPipeType; import com.gregtechceu.gtceu.common.pipelike.fluidpipe.FluidPipeType; import com.gregtechceu.gtceu.common.pipelike.fluidpipe.longdistance.LDFluidPipeType; import com.gregtechceu.gtceu.common.pipelike.item.ItemPipeType; @@ -132,6 +133,7 @@ public class GTBlocks { public static Table> ITEM_PIPE_BLOCKS; public static final BlockEntry[] LASER_PIPES = new BlockEntry[LaserPipeType.values().length]; public static final BlockEntry[] OPTICAL_PIPES = new BlockEntry[OpticalPipeType.values().length]; + public static final BlockEntry[] DUCT_PIPES = new BlockEntry[DuctPipeType.VALUES.length]; ////////////////////////////////////// // ***** Procedural Blocks *****// @@ -454,6 +456,32 @@ private static void registerOpticalPipeBlock(int index) { OPTICAL_PIPES[index] = entry; } + // Optical Pipe Blocks + private static void generateDuctPipeBlocks() { + GTCEu.LOGGER.debug("Generating GTCEu Duct Pipe Blocks..."); + for (int i = 0; i < DuctPipeType.VALUES.length; ++i) { + registerDuctPipeBlock(i); + } + GTCEu.LOGGER.debug("Generating GTCEu Duct Pipe Blocks... Complete!"); + } + + private static void registerDuctPipeBlock(int index) { + var type = DuctPipeType.VALUES[index]; + var entry = REGISTRATE + .block("%s_duct_pipe".formatted(type.getSerializedName()), (p) -> new DuctPipeBlock(p, type)) + .initialProperties(() -> Blocks.IRON_BLOCK) + .properties(p -> p.dynamicShape().noOcclusion().forceSolidOn()) + .blockstate(NonNullBiConsumer.noop()) + .defaultLoot() + .tag(GTToolType.WRENCH.harvestTags.get(0)) + .addLayer(() -> RenderType::cutoutMipped) + .item(DuctPipeBlockItem::new) + .model(NonNullBiConsumer.noop()) + .build() + .register(); + DUCT_PIPES[index] = entry; + } + ////////////////////////////////////// // ***** General Pipes ******// ////////////////////////////////////// @@ -1659,6 +1687,7 @@ public static void init() { generateItemPipeBlocks(); // Item Pipe Blocks generateLaserPipeBlocks(); // Laser Pipe Blocks generateOpticalPipeBlocks(); // Optical Pipe Blocks + generateDuctPipeBlocks(); // Duct Pipe Blocks // Remove Builder Tables MATERIAL_BLOCKS_BUILDER = null; diff --git a/src/main/java/com/gregtechceu/gtceu/common/data/GTCommandArguments.java b/src/main/java/com/gregtechceu/gtceu/common/data/GTCommandArguments.java index f330235d72..ff24048674 100644 --- a/src/main/java/com/gregtechceu/gtceu/common/data/GTCommandArguments.java +++ b/src/main/java/com/gregtechceu/gtceu/common/data/GTCommandArguments.java @@ -2,6 +2,7 @@ import com.gregtechceu.gtceu.GTCEu; import com.gregtechceu.gtceu.common.commands.arguments.MaterialArgument; +import com.gregtechceu.gtceu.common.commands.arguments.MedicalConditionArgument; import net.minecraft.commands.synchronization.ArgumentTypeInfo; import net.minecraft.commands.synchronization.ArgumentTypeInfos; @@ -21,6 +22,11 @@ public class GTCommandArguments { "material", () -> ArgumentTypeInfos.registerByClass(MaterialArgument.class, SingletonArgumentInfo.contextFree(MaterialArgument::material))); + private static final RegistryObject> MEDICAL_CONDITION_ARGUMENT_TYPE = COMMAND_ARGUMENT_TYPES + .register("medical_condition", + () -> ArgumentTypeInfos.registerByClass(MedicalConditionArgument.class, + SingletonArgumentInfo.contextFree(MedicalConditionArgument::medicalCondition))); + public static void init(IEventBus modBus) { COMMAND_ARGUMENT_TYPES.register(modBus); } diff --git a/src/main/java/com/gregtechceu/gtceu/common/data/GTItems.java b/src/main/java/com/gregtechceu/gtceu/common/data/GTItems.java index bee01f2a7c..e376aa2c5a 100644 --- a/src/main/java/com/gregtechceu/gtceu/common/data/GTItems.java +++ b/src/main/java/com/gregtechceu/gtceu/common/data/GTItems.java @@ -11,7 +11,6 @@ import com.gregtechceu.gtceu.api.data.chemical.material.MarkerMaterial; import com.gregtechceu.gtceu.api.data.chemical.material.MarkerMaterials; import com.gregtechceu.gtceu.api.data.chemical.material.Material; -import com.gregtechceu.gtceu.api.data.chemical.material.properties.HazardProperty; import com.gregtechceu.gtceu.api.data.chemical.material.properties.PropertyKey; import com.gregtechceu.gtceu.api.data.chemical.material.registry.MaterialRegistry; import com.gregtechceu.gtceu.api.data.chemical.material.stack.ItemMaterialInfo; @@ -2240,18 +2239,22 @@ public Component getItemName(ItemStack stack) { .lang("Gas Mask Filter") .properties(p -> p.stacksTo(1)) .register(); + // TODO add more medications for specific conditions & then remove them from paracetamol public static ItemEntry PARACETAMOL_PILL = REGISTRATE.item("paracetamol_pill", ComponentItem::create) .lang("Paracetamol Pill") .properties(p -> p.food(GTFoods.ANTIDOTE)) - .onRegister(attach(new AntidoteBehavior(15, - HazardProperty.HazardType.CONTACT_POISON, - HazardProperty.HazardType.INHALATION_POISON, - HazardProperty.HazardType.CORROSIVE))) + .onRegister(attach(new AntidoteBehavior(10, + GTMedicalConditions.CHEMICAL_BURNS, + GTMedicalConditions.WEAK_POISON, + GTMedicalConditions.NAUSEA, + GTMedicalConditions.IRRITANT, + GTMedicalConditions.METHANOL_POISONING, + GTMedicalConditions.CARBON_MONOXIDE_POISONING))) .register(); public static ItemEntry RAD_AWAY_PILL = REGISTRATE.item("rad_away_pill", ComponentItem::create) .lang("RadAway™ Pill") .properties(p -> p.food(GTFoods.ANTIDOTE)) - .onRegister(attach(new AntidoteBehavior(50, HazardProperty.HazardType.RADIOACTIVE))) + .onRegister(attach(new AntidoteBehavior(50, GTMedicalConditions.CARCINOGEN))) .register(); public static ItemEntry NANO_SABER = REGISTRATE.item("nano_saber", ComponentItem::create) diff --git a/src/main/java/com/gregtechceu/gtceu/common/data/GTMachines.java b/src/main/java/com/gregtechceu/gtceu/common/data/GTMachines.java index da160a7bf5..c6925e081a 100644 --- a/src/main/java/com/gregtechceu/gtceu/common/data/GTMachines.java +++ b/src/main/java/com/gregtechceu/gtceu/common/data/GTMachines.java @@ -13,6 +13,7 @@ import com.gregtechceu.gtceu.api.data.RotationState; import com.gregtechceu.gtceu.api.data.chemical.material.Material; import com.gregtechceu.gtceu.api.data.chemical.material.properties.PropertyKey; +import com.gregtechceu.gtceu.api.data.medicalcondition.MedicalCondition; import com.gregtechceu.gtceu.api.data.tag.TagPrefix; import com.gregtechceu.gtceu.api.fluids.PropertyFluidFilter; import com.gregtechceu.gtceu.api.item.DrumMachineItem; @@ -142,6 +143,7 @@ public class GTMachines { REGISTRATE.creativeModeTab(() -> MACHINE); GTRegistries.MACHINES.unfreeze(); } + ////////////////////////////////////// // ****** Steam Machine ******// ////////////////////////////////////// @@ -236,7 +238,7 @@ public class GTMachines { public static final MachineDefinition[] ARC_FURNACE = registerSimpleMachines("arc_furnace", GTRecipeTypes.ARC_FURNACE_RECIPES, hvCappedTankSizeFunction); public static final MachineDefinition[] ASSEMBLER = registerSimpleMachines("assembler", - GTRecipeTypes.ASSEMBLER_RECIPES, hvCappedTankSizeFunction); + GTRecipeTypes.ASSEMBLER_RECIPES, hvCappedTankSizeFunction, true); public static final MachineDefinition[] AUTOCLAVE = registerSimpleMachines("autoclave", GTRecipeTypes.AUTOCLAVE_RECIPES, hvCappedTankSizeFunction); public static final MachineDefinition[] BENDER = registerSimpleMachines("bender", GTRecipeTypes.BENDER_RECIPES); @@ -248,7 +250,7 @@ public class GTMachines { public static final MachineDefinition[] CHEMICAL_BATH = registerSimpleMachines("chemical_bath", GTRecipeTypes.CHEMICAL_BATH_RECIPES, hvCappedTankSizeFunction); public static final MachineDefinition[] CHEMICAL_REACTOR = registerSimpleMachines("chemical_reactor", - GTRecipeTypes.CHEMICAL_RECIPES, tier -> 16 * FluidHelper.getBucket()); + GTRecipeTypes.CHEMICAL_RECIPES, tier -> 16 * FluidHelper.getBucket(), true); public static final MachineDefinition[] COMPRESSOR = registerSimpleMachines("compressor", GTRecipeTypes.COMPRESSOR_RECIPES); public static final MachineDefinition[] CUTTER = registerSimpleMachines("cutter", GTRecipeTypes.CUTTER_RECIPES); @@ -282,14 +284,14 @@ public class GTMachines { public static final MachineDefinition[] POLARIZER = registerSimpleMachines("polarizer", GTRecipeTypes.POLARIZER_RECIPES); public static final MachineDefinition[] LASER_ENGRAVER = registerSimpleMachines("laser_engraver", - GTRecipeTypes.LASER_ENGRAVER_RECIPES); + GTRecipeTypes.LASER_ENGRAVER_RECIPES, defaultTankSizeFunction, true); public static final MachineDefinition[] SIFTER = registerSimpleMachines("sifter", GTRecipeTypes.SIFTER_RECIPES); public static final MachineDefinition[] THERMAL_CENTRIFUGE = registerSimpleMachines("thermal_centrifuge", GTRecipeTypes.THERMAL_CENTRIFUGE_RECIPES); public static final MachineDefinition[] WIREMILL = registerSimpleMachines("wiremill", GTRecipeTypes.WIREMILL_RECIPES); public static final MachineDefinition[] CIRCUIT_ASSEMBLER = registerSimpleMachines("circuit_assembler", - GTRecipeTypes.CIRCUIT_ASSEMBLER_RECIPES, hvCappedTankSizeFunction); + GTRecipeTypes.CIRCUIT_ASSEMBLER_RECIPES, hvCappedTankSizeFunction, true); public static final MachineDefinition[] MACERATOR = registerTieredMachines("macerator", (holder, tier) -> new SimpleTieredMachine(holder, tier, defaultTankSizeFunction), (tier, builder) -> builder .langValue("%s Macerator %s".formatted(VLVH[tier], VLVT[tier])) @@ -310,7 +312,7 @@ public class GTMachines { .register(), ELECTRIC_TIERS); public static final MachineDefinition[] GAS_COLLECTOR = registerSimpleMachines("gas_collector", - GTRecipeTypes.GAS_COLLECTOR_RECIPES, largeTankSizeFunction); + GTRecipeTypes.GAS_COLLECTOR_RECIPES, largeTankSizeFunction, true); public static final MachineDefinition[] ROCK_CRUSHER = registerTieredMachines("rock_crusher", RockCrusherMachine::new, (tier, builder) -> builder .langValue("%s Rock Crusher %s".formatted(VLVH[tier], VLVT[tier])) @@ -326,6 +328,21 @@ public class GTMachines { .compassNode("rock_crusher") .register(), ELECTRIC_TIERS); + public static final MachineDefinition[] AIR_SCRUBBER = registerTieredMachines("air_scrubber", + AirScrubberMachine::new, (tier, builder) -> builder + .langValue("%s Air Scrubber %s".formatted(VLVH[tier], VLVT[tier])) + .editableUI(SimpleTieredMachine.EDITABLE_UI_CREATOR.apply(GTCEu.id("air_scrubber"), + GTRecipeTypes.AIR_SCRUBBER_RECIPES)) + .rotationState(RotationState.NON_Y_AXIS) + .recipeType(GTRecipeTypes.AIR_SCRUBBER_RECIPES) + .recipeModifier(GTRecipeModifiers.ELECTRIC_OVERCLOCK.apply(OverclockingLogic.NON_PERFECT_OVERCLOCK)) + .workableTieredHullRenderer(GTCEu.id("block/machines/air_scrubber")) + .tooltips(workableTiered(tier, GTValues.V[tier], GTValues.V[tier] * 64, + GTRecipeTypes.AIR_SCRUBBER_RECIPES, defaultTankSizeFunction.apply(tier), true)) + .tooltips(explosion()) + .compassNode("air_scrubber") + .register(), + LOW_TIERS); ////////////////////////////////////// // **** Simple Generator ****// @@ -1167,9 +1184,11 @@ public static BiConsumer> createTankTooltips(String n public static final MultiblockMachineDefinition LARGE_CHEMICAL_REACTOR = REGISTRATE .multiblock("large_chemical_reactor", WorkableElectricMultiblockMachine::new) + .tooltips(GTMachines.defaultEnvironmentRequirement()) .rotationState(RotationState.ALL) .recipeType(GTRecipeTypes.LARGE_CHEMICAL_RECIPES) - .recipeModifier(GTRecipeModifiers.ELECTRIC_OVERCLOCK.apply(OverclockingLogic.PERFECT_OVERCLOCK)) + .recipeModifiers(GTRecipeModifiers.DEFAULT_ENVIRONMENT_REQUIREMENT, + GTRecipeModifiers.ELECTRIC_OVERCLOCK.apply(OverclockingLogic.PERFECT_OVERCLOCK)) .appearanceBlock(CASING_PTFE_INERT) .pattern(definition -> { var casing = blocks(CASING_PTFE_INERT.get()).setMinGlobalLimited(10); @@ -1503,7 +1522,8 @@ public static BiConsumer> createTankTooltips(String n .rotationState(RotationState.ALL) .recipeType(GTRecipeTypes.ASSEMBLY_LINE_RECIPES) .alwaysTryModifyRecipe(true) - .recipeModifier(GTRecipeModifiers.ELECTRIC_OVERCLOCK.apply(OverclockingLogic.NON_PERFECT_OVERCLOCK)) + .recipeModifiers(GTRecipeModifiers.DEFAULT_ENVIRONMENT_REQUIREMENT, + GTRecipeModifiers.ELECTRIC_OVERCLOCK.apply(OverclockingLogic.NON_PERFECT_OVERCLOCK)) .appearanceBlock(CASING_STEEL_SOLID) .pattern(definition -> FactoryBlockPattern.start(BACK, UP, RIGHT) .aisle("FIF", "RTR", "SAG", "#Y#") @@ -1610,7 +1630,8 @@ public static BiConsumer> createTankTooltips(String n .rotationState(RotationState.ALL) .langValue("Fusion Reactor Computer MK %s".formatted(toRomanNumeral(tier - 5))) .recipeType(GTRecipeTypes.FUSION_RECIPES) - .recipeModifier(FusionReactorMachine::recipeModifier) + .recipeModifiers(GTRecipeModifiers.DEFAULT_ENVIRONMENT_REQUIREMENT, + FusionReactorMachine::recipeModifier) .tooltips( Component.translatable("gtceu.machine.fusion_reactor.capacity", FusionReactorMachine.calculateEnergyStorageFactor(tier, 16) / 1000000L), @@ -2121,26 +2142,40 @@ public static MachineDefinition[] registerTransformerMachines(String langName, i public static MachineDefinition[] registerSimpleMachines(String name, GTRecipeType recipeType, Int2LongFunction tankScalingFunction, + boolean hasPollutionDebuff, int... tiers) { return registerTieredMachines(name, - (holder, tier) -> new SimpleTieredMachine(holder, tier, tankScalingFunction), (tier, builder) -> builder - .langValue("%s %s %s".formatted(VLVH[tier], toEnglishName(name), VLVT[tier])) - .editableUI(SimpleTieredMachine.EDITABLE_UI_CREATOR.apply(GTCEu.id(name), recipeType)) - .rotationState(RotationState.NON_Y_AXIS) - .recipeType(recipeType) - .recipeModifier( - GTRecipeModifiers.ELECTRIC_OVERCLOCK.apply(OverclockingLogic.NON_PERFECT_OVERCLOCK)) - .workableTieredHullRenderer(GTCEu.id("block/machines/" + name)) - .tooltips(workableTiered(tier, GTValues.V[tier], GTValues.V[tier] * 64, recipeType, - tankScalingFunction.apply(tier), true)) - .compassNode(name) - .register(), + (holder, tier) -> new SimpleTieredMachine(holder, tier, tankScalingFunction), (tier, builder) -> { + if (hasPollutionDebuff) { + builder.recipeModifier(GTRecipeModifiers.ENVIRONMENT_REQUIREMENT + .apply(GTMedicalConditions.CARBON_MONOXIDE_POISONING, 100 * tier)) + .tooltips(defaultEnvironmentRequirement()); + } + return builder + .langValue("%s %s %s".formatted(VLVH[tier], toEnglishName(name), VLVT[tier])) + .editableUI(SimpleTieredMachine.EDITABLE_UI_CREATOR.apply(GTCEu.id(name), recipeType)) + .rotationState(RotationState.NON_Y_AXIS) + .recipeType(recipeType) + .recipeModifier( + GTRecipeModifiers.ELECTRIC_OVERCLOCK.apply(OverclockingLogic.NON_PERFECT_OVERCLOCK)) + .workableTieredHullRenderer(GTCEu.id("block/machines/" + name)) + .tooltips(workableTiered(tier, GTValues.V[tier], GTValues.V[tier] * 64, recipeType, + tankScalingFunction.apply(tier), true)) + .compassNode(name) + .register(); + }, tiers); } + public static MachineDefinition[] registerSimpleMachines(String name, GTRecipeType recipeType, + Int2LongFunction tankScalingFunction, + boolean hasPollutionDebuff) { + return registerSimpleMachines(name, recipeType, tankScalingFunction, hasPollutionDebuff, ELECTRIC_TIERS); + } + public static MachineDefinition[] registerSimpleMachines(String name, GTRecipeType recipeType, Int2LongFunction tankScalingFunction) { - return registerSimpleMachines(name, recipeType, tankScalingFunction, ELECTRIC_TIERS); + return registerSimpleMachines(name, recipeType, tankScalingFunction, false); } public static MachineDefinition[] registerSimpleMachines(String name, GTRecipeType recipeType) { @@ -2513,6 +2548,15 @@ public static Component explosion() { return null; } + public static Component environmentRequirement(MedicalCondition condition) { + return Component.translatable("gtceu.recipe.environmental_hazard.reverse", + Component.translatable("gtceu.medical_condition." + condition.name)); + } + + public static Component defaultEnvironmentRequirement() { + return environmentRequirement(GTMedicalConditions.CARBON_MONOXIDE_POISONING); + } + public static Component[] workableTiered(int tier, long voltage, long energyCapacity, GTRecipeType recipeType, long tankCapacity, boolean input) { List tooltipComponents = new ArrayList<>(); diff --git a/src/main/java/com/gregtechceu/gtceu/common/data/GTMedicalConditions.java b/src/main/java/com/gregtechceu/gtceu/common/data/GTMedicalConditions.java new file mode 100644 index 0000000000..3b71582276 --- /dev/null +++ b/src/main/java/com/gregtechceu/gtceu/common/data/GTMedicalConditions.java @@ -0,0 +1,74 @@ +package com.gregtechceu.gtceu.common.data; + +import com.gregtechceu.gtceu.api.data.medicalcondition.MedicalCondition; +import com.gregtechceu.gtceu.api.data.medicalcondition.Symptom; + +public class GTMedicalConditions { + + // General Conditions + public static final MedicalCondition NONE = new MedicalCondition("none", 0xffffff, 0); + public static final MedicalCondition CHEMICAL_BURNS = new MedicalCondition("chemical_burns", 0xbc305a, 200, + MedicalCondition.IdleProgressionType.HEAL, 2, false, + new Symptom.ConfiguredSymptom(Symptom.WEAKNESS)); + public static final MedicalCondition POISON = new MedicalCondition("poison", 0xA36300, 600, + MedicalCondition.IdleProgressionType.HEAL, 2, true, + new Symptom.ConfiguredSymptom(Symptom.WEAK_POISONING), + new Symptom.ConfiguredSymptom(Symptom.WEAKNESS, .5f)); + public static final MedicalCondition WEAK_POISON = new MedicalCondition("weak_poison", 0x6D7917, 3000, + MedicalCondition.IdleProgressionType.NONE, 0, false, + new Symptom.ConfiguredSymptom(Symptom.WEAK_POISONING, 6, .3f)); + public static final MedicalCondition IRRITANT = new MedicalCondition("irritant", 0x02512f, 600, + MedicalCondition.IdleProgressionType.HEAL, 5, false, + new Symptom.ConfiguredSymptom(Symptom.RANDOM_DAMAGE), + new Symptom.ConfiguredSymptom(Symptom.WEAKNESS, 0.5f)); + public static final MedicalCondition NAUSEA = new MedicalCondition("nausea", 0x1D4A00, 600, + MedicalCondition.IdleProgressionType.HEAL, 5, false, + new Symptom.ConfiguredSymptom(Symptom.NAUSEA)); + public static final MedicalCondition CARCINOGEN = new MedicalCondition("carcinogen", 0x181818, 20000, + MedicalCondition.IdleProgressionType.NONE, 0, true, + new Symptom.ConfiguredSymptom(Symptom.DEATH), + new Symptom.ConfiguredSymptom(Symptom.HEALTH_DEBUFF, .75f), + new Symptom.ConfiguredSymptom(Symptom.AIR_SUPPLY_DEBUFF, .5f), + new Symptom.ConfiguredSymptom(Symptom.MINING_FATIGUE, .4f), + new Symptom.ConfiguredSymptom(Symptom.SLOWNESS, .4f), + new Symptom.ConfiguredSymptom(Symptom.HUNGER, .3f), + new Symptom.ConfiguredSymptom(Symptom.WEAKNESS, .2f)); + + // Material specific Conditions + public static final MedicalCondition ASBESTOSIS = new MedicalCondition("asbestosis", 0xe3e3e3, 5000, + MedicalCondition.IdleProgressionType.UNTREATED_PROGRESSION, 1, true, + new Symptom.ConfiguredSymptom(Symptom.HEALTH_DEBUFF, .6f), + new Symptom.ConfiguredSymptom(Symptom.AIR_SUPPLY_DEBUFF, .3f), + new Symptom.ConfiguredSymptom(Symptom.HUNGER, .2f), + new Symptom.ConfiguredSymptom(Symptom.WEAKNESS, .2f)); + public static final MedicalCondition ARSENICOSIS = new MedicalCondition("arsenicosis", 0xbd4b15, 1000, + MedicalCondition.IdleProgressionType.UNTREATED_PROGRESSION, 1, true, + new Symptom.ConfiguredSymptom(Symptom.WITHER), + new Symptom.ConfiguredSymptom(Symptom.HEALTH_DEBUFF, .6f), + new Symptom.ConfiguredSymptom(Symptom.SLOWNESS, 2, .5f), + new Symptom.ConfiguredSymptom(Symptom.WEAKNESS, 2, .3f), + new Symptom.ConfiguredSymptom(Symptom.HUNGER, 2, .2f), + new Symptom.ConfiguredSymptom(Symptom.NAUSEA, .1f)); + public static final MedicalCondition SILICOSIS = new MedicalCondition("silicosis", 0x5d6c91, 15000, + MedicalCondition.IdleProgressionType.UNTREATED_PROGRESSION, .5f, true, + new Symptom.ConfiguredSymptom(Symptom.HEALTH_DEBUFF, 4, .75f), + new Symptom.ConfiguredSymptom(Symptom.AIR_SUPPLY_DEBUFF, .6f)); + public static final MedicalCondition BERYLLIOSIS = new MedicalCondition("berylliosis", 0x0c6539, 10000, + MedicalCondition.IdleProgressionType.UNTREATED_PROGRESSION, .5f, true, + new Symptom.ConfiguredSymptom(Symptom.WITHER), + new Symptom.ConfiguredSymptom(Symptom.RANDOM_DAMAGE, 1, .7f), + new Symptom.ConfiguredSymptom(Symptom.SLOWNESS, 2, .5f), + new Symptom.ConfiguredSymptom(Symptom.WEAKNESS, 2, .4f)); + public static final MedicalCondition METHANOL_POISONING = new MedicalCondition("methanol_poisoning", 0xaa8800, 500, + MedicalCondition.IdleProgressionType.UNTREATED_PROGRESSION, .5f, true, + new Symptom.ConfiguredSymptom(Symptom.POISONING), + new Symptom.ConfiguredSymptom(Symptom.SLOWNESS, 1, .75f), + new Symptom.ConfiguredSymptom(Symptom.WEAKNESS, 2, .5f), + new Symptom.ConfiguredSymptom(Symptom.BLINDNESS, 2, .25f)); + public static final MedicalCondition CARBON_MONOXIDE_POISONING = new MedicalCondition("carbon_monoxide_poisoning", + 0x041525, 2000, MedicalCondition.IdleProgressionType.HEAL, 1, true, + new Symptom.ConfiguredSymptom(Symptom.DEATH), + new Symptom.ConfiguredSymptom(Symptom.SLOWNESS, 1, .75f), + new Symptom.ConfiguredSymptom(Symptom.NAUSEA, 2, .5f), + new Symptom.ConfiguredSymptom(Symptom.WEAKNESS, 2, .25f)); +} diff --git a/src/main/java/com/gregtechceu/gtceu/common/data/GTRecipeConditions.java b/src/main/java/com/gregtechceu/gtceu/common/data/GTRecipeConditions.java index 29d1daf2da..de0ee01bca 100644 --- a/src/main/java/com/gregtechceu/gtceu/common/data/GTRecipeConditions.java +++ b/src/main/java/com/gregtechceu/gtceu/common/data/GTRecipeConditions.java @@ -31,6 +31,8 @@ public static void init() { GTRegistries.RECIPE_CONDITIONS.register(VentCondition.INSTANCE.getType(), VentCondition.class); GTRegistries.RECIPE_CONDITIONS.register(CleanroomCondition.INSTANCE.getType(), CleanroomCondition.class); GTRegistries.RECIPE_CONDITIONS.register(ResearchCondition.INSTANCE.getType(), ResearchCondition.class); + GTRegistries.RECIPE_CONDITIONS.register(EnvironmentalHazardCondition.INSTANCE.getType(), + EnvironmentalHazardCondition.class); if (GTCEu.isCreateLoaded()) { GTRegistries.RECIPE_CONDITIONS.register(RPMCondition.INSTANCE.getType(), RPMCondition.class); } diff --git a/src/main/java/com/gregtechceu/gtceu/common/data/GTRecipeModifiers.java b/src/main/java/com/gregtechceu/gtceu/common/data/GTRecipeModifiers.java index 4f766ac179..95742312e5 100644 --- a/src/main/java/com/gregtechceu/gtceu/common/data/GTRecipeModifiers.java +++ b/src/main/java/com/gregtechceu/gtceu/common/data/GTRecipeModifiers.java @@ -4,6 +4,7 @@ import com.gregtechceu.gtceu.api.capability.IParallelHatch; import com.gregtechceu.gtceu.api.capability.recipe.EURecipeCapability; import com.gregtechceu.gtceu.api.capability.recipe.IRecipeCapabilityHolder; +import com.gregtechceu.gtceu.api.data.medicalcondition.MedicalCondition; import com.gregtechceu.gtceu.api.machine.MetaMachine; import com.gregtechceu.gtceu.api.machine.feature.IOverclockMachine; import com.gregtechceu.gtceu.api.machine.feature.ITieredMachine; @@ -16,9 +17,14 @@ import com.gregtechceu.gtceu.api.recipe.content.ContentModifier; import com.gregtechceu.gtceu.api.recipe.modifier.ParallelLogic; import com.gregtechceu.gtceu.api.recipe.modifier.RecipeModifier; +import com.gregtechceu.gtceu.common.capability.EnvironmentalHazardSavedData; +import com.gregtechceu.gtceu.config.ConfigHolder; import net.minecraft.MethodsReturnNonnullByDefault; import net.minecraft.Util; +import net.minecraft.core.BlockPos; +import net.minecraft.server.level.ServerLevel; +import net.minecraft.world.level.Level; import com.mojang.datafixers.util.Pair; import org.jetbrains.annotations.NotNull; @@ -26,6 +32,7 @@ import java.util.List; import java.util.Optional; +import java.util.function.BiFunction; import java.util.function.Function; import javax.annotation.ParametersAreNonnullByDefault; @@ -44,6 +51,29 @@ public class GTRecipeModifiers { .memoize(ElectricOverclockModifier::new); public static final RecipeModifier PARALLEL_HATCH = (machine, recipe) -> GTRecipeModifiers .hatchParallel(machine, recipe, false).getFirst(); + public static final BiFunction ENVIRONMENT_REQUIREMENT = Util + .memoize((condition, maxAllowedAffectedBlocks) -> (machine, recipe) -> { + if (!ConfigHolder.INSTANCE.gameplay.environmentalHazards) return recipe; + Level level = machine.getLevel(); + if (!(level instanceof ServerLevel serverLevel)) { + return null; + } + EnvironmentalHazardSavedData data = EnvironmentalHazardSavedData.getOrCreate(serverLevel); + BlockPos machinePos = machine.getPos(); + var zone = data.getZoneByContainedPosAndCondition(machinePos, condition); + if (zone == null) { + return recipe; + } + int strength = zone.strength(); + if (strength < maxAllowedAffectedBlocks) { + return recipe; + } + recipe = recipe.copy(); + recipe.duration *= Math.max(1, maxAllowedAffectedBlocks / Math.max(strength, 1)); + return recipe; + }); + public static final RecipeModifier DEFAULT_ENVIRONMENT_REQUIREMENT = ENVIRONMENT_REQUIREMENT + .apply(GTMedicalConditions.CARBON_MONOXIDE_POISONING, 500); @MethodsReturnNonnullByDefault @ParametersAreNonnullByDefault @@ -71,7 +101,7 @@ public GTRecipe apply(MetaMachine machine, @NotNull GTRecipe recipe) { /** * Fast parallel, the parallel amount is always the 2 times the divisor of maxParallel。 - * + * * @param machine recipe holder * @param recipe current recipe * @param maxParallel max parallel limited @@ -94,7 +124,7 @@ public static Pair fastParallel(MetaMachine machine, @NotNull /** * Accurate parallel, always look for the maximum parallel value within maxParallel. - * + * * @param machine recipe holder * @param recipe current recipe * @param maxParallel max parallel limited diff --git a/src/main/java/com/gregtechceu/gtceu/common/data/GTRecipeTypes.java b/src/main/java/com/gregtechceu/gtceu/common/data/GTRecipeTypes.java index 4db1237bda..ab9a793551 100644 --- a/src/main/java/com/gregtechceu/gtceu/common/data/GTRecipeTypes.java +++ b/src/main/java/com/gregtechceu/gtceu/common/data/GTRecipeTypes.java @@ -402,6 +402,12 @@ public class GTRecipeTypes { .setOffsetVoltageText(true) .setSound(GTSoundEntries.COOLING); + public final static GTRecipeType AIR_SCRUBBER_RECIPES = register("air_scrubber", ELECTRIC) + .setMaxIOSize(1, 3, 1, 3).setEUIO(IO.IN) + .setProgressBar(GuiTextures.PROGRESS_BAR_GAS_COLLECTOR, LEFT_TO_RIGHT) + .setMaxTooltips(4) + .setSound(GTSoundEntries.COOLING); + public static final GTRecipeType RESEARCH_STATION_RECIPES = register("research_station", ELECTRIC) .setMaxIOSize(2, 1, 0, 0) .setProgressBar(GuiTextures.PROGRESS_BAR_ARROW, LEFT_TO_RIGHT) diff --git a/src/main/java/com/gregtechceu/gtceu/common/data/machines/GCyMMachines.java b/src/main/java/com/gregtechceu/gtceu/common/data/machines/GCyMMachines.java index 8266703b01..7a5afac0ae 100644 --- a/src/main/java/com/gregtechceu/gtceu/common/data/machines/GCyMMachines.java +++ b/src/main/java/com/gregtechceu/gtceu/common/data/machines/GCyMMachines.java @@ -16,10 +16,7 @@ import com.gregtechceu.gtceu.api.pattern.Predicates; import com.gregtechceu.gtceu.api.pattern.TraceabilityPredicate; import com.gregtechceu.gtceu.api.recipe.OverclockingLogic; -import com.gregtechceu.gtceu.common.data.GTCompassSections; -import com.gregtechceu.gtceu.common.data.GTMaterials; -import com.gregtechceu.gtceu.common.data.GTRecipeModifiers; -import com.gregtechceu.gtceu.common.data.GTRecipeTypes; +import com.gregtechceu.gtceu.common.data.*; import com.gregtechceu.gtceu.common.machine.multiblock.part.ParallelHatchPartMachine; import net.minecraft.core.Direction; @@ -287,9 +284,10 @@ public static void init() {} .tooltips(Component.translatable("gtceu.multiblock.parallelizable.tooltip")) .tooltips(Component.translatable("gtceu.machine.available_recipe_map_1.tooltip", Component.translatable("gtceu.assembler"))) + .tooltips(GTMachines.defaultEnvironmentRequirement()) .rotationState(RotationState.ALL) .recipeType(ASSEMBLER_RECIPES) - .recipeModifiers(GTRecipeModifiers.PARALLEL_HATCH, + .recipeModifiers(GTRecipeModifiers.DEFAULT_ENVIRONMENT_REQUIREMENT, GTRecipeModifiers.PARALLEL_HATCH, GTRecipeModifiers.ELECTRIC_OVERCLOCK.apply(OverclockingLogic.NON_PERFECT_OVERCLOCK)) .appearanceBlock(CASING_LARGE_SCALE_ASSEMBLING) .pattern(definition -> FactoryBlockPattern.start() @@ -318,9 +316,10 @@ public static void init() {} .tooltips(Component.translatable("gtceu.multiblock.parallelizable.tooltip")) .tooltips(Component.translatable("gtceu.machine.available_recipe_map_1.tooltip", Component.translatable("gtceu.circuit_assembler"))) + .tooltips(GTMachines.defaultEnvironmentRequirement()) .rotationState(RotationState.ALL) .recipeType(CIRCUIT_ASSEMBLER_RECIPES) - .recipeModifiers(GTRecipeModifiers.PARALLEL_HATCH, + .recipeModifiers(GTRecipeModifiers.DEFAULT_ENVIRONMENT_REQUIREMENT, GTRecipeModifiers.PARALLEL_HATCH, GTRecipeModifiers.ELECTRIC_OVERCLOCK.apply(OverclockingLogic.NON_PERFECT_OVERCLOCK)) .appearanceBlock(CASING_LARGE_SCALE_ASSEMBLING) .pattern(definition -> FactoryBlockPattern.start() @@ -385,9 +384,10 @@ public static void init() {} .tooltips(Component.translatable("gtceu.multiblock.parallelizable.tooltip")) .tooltips(Component.translatable("gtceu.machine.available_recipe_map_1.tooltip", Component.translatable("gtceu.laser_engraver"))) + .tooltips(GTMachines.defaultEnvironmentRequirement()) .rotationState(RotationState.ALL) .recipeType(LASER_ENGRAVER_RECIPES) - .recipeModifiers(GTRecipeModifiers.PARALLEL_HATCH, + .recipeModifiers(GTRecipeModifiers.DEFAULT_ENVIRONMENT_REQUIREMENT, GTRecipeModifiers.PARALLEL_HATCH, GTRecipeModifiers.ELECTRIC_OVERCLOCK.apply(OverclockingLogic.NON_PERFECT_OVERCLOCK)) .appearanceBlock(CASING_LASER_SAFE_ENGRAVING) .pattern(definition -> FactoryBlockPattern.start() @@ -628,7 +628,7 @@ public static void init() {} .tooltips(Component.translatable("gtceu.multiblock.parallelizable.tooltip")) .tooltips(Component.translatable("gtceu.machine.available_recipe_map_2.tooltip", Component.translatable("gtceu.distillation_tower"), Component.translatable("gtceu.distillery"))) - .rotationState(RotationState.ALL) + .rotationState(RotationState.NON_Y_AXIS) .recipeTypes(DISTILLATION_RECIPES, DISTILLERY_RECIPES) .recipeModifiers(GTRecipeModifiers.PARALLEL_HATCH, GTRecipeModifiers.ELECTRIC_OVERCLOCK.apply(OverclockingLogic.NON_PERFECT_OVERCLOCK)) diff --git a/src/main/java/com/gregtechceu/gtceu/common/data/materials/ElementMaterials.java b/src/main/java/com/gregtechceu/gtceu/common/data/materials/ElementMaterials.java index c3277e6243..9401cb0059 100644 --- a/src/main/java/com/gregtechceu/gtceu/common/data/materials/ElementMaterials.java +++ b/src/main/java/com/gregtechceu/gtceu/common/data/materials/ElementMaterials.java @@ -13,8 +13,7 @@ import com.gregtechceu.gtceu.api.fluids.store.FluidStorageKeys; import com.gregtechceu.gtceu.api.item.tool.GTToolType; import com.gregtechceu.gtceu.common.data.GTElements; - -import java.util.List; +import com.gregtechceu.gtceu.common.data.GTMedicalConditions; import static com.gregtechceu.gtceu.api.GTValues.LV; import static com.gregtechceu.gtceu.api.data.chemical.material.info.MaterialFlags.*; @@ -75,7 +74,7 @@ public static void register() { .temperature(887)) .color(0x9c9c8d).secondaryColor(0x676756) .element(GTElements.As) - .hazard(HazardProperty.HazardType.CONTACT_POISON) + .hazard(HazardProperty.HazardTrigger.ANY, GTMedicalConditions.ARSENICOSIS) .buildAndRegister(); Astatine = new Material.Builder(GTCEu.id("astatine")) @@ -100,7 +99,7 @@ public static void register() { .ore() .color(0x98d677).secondaryColor(0x254d40).iconSet(METALLIC) .appendFlags(STD_METAL) - .hazard(HazardProperty.HazardType.CONTACT_POISON, false) + .hazard(HazardProperty.HazardTrigger.ANY, GTMedicalConditions.BERYLLIOSIS, false) .element(GTElements.Be) .buildAndRegister(); @@ -156,7 +155,7 @@ public static void register() { .dust() .color(0x636377).secondaryColor(0x412738).iconSet(SHINY) .element(GTElements.Cd) - .hazard(HazardProperty.HazardType.CONTACT_POISON) + .hazard(HazardProperty.HazardTrigger.ANY, GTMedicalConditions.POISON) .buildAndRegister(); Cerium = new Material.Builder(GTCEu.id("cerium")) @@ -169,10 +168,7 @@ public static void register() { Chlorine = new Material.Builder(GTCEu.id("chlorine")) .gas(new FluidBuilder().state(FluidState.GAS).customStill()) .element(GTElements.Cl) - .hazard(HazardProperty.HazardType.INHALATION_POISON, - List.of(HazardProperty.blindnessEffect(2000, 1000, 3), - HazardProperty.poisonEffect(2000, 1000, 3)), - false) + // TODO hazard .buildAndRegister(); Chromium = new Material.Builder(GTCEu.id("chromium")) @@ -184,7 +180,7 @@ public static void register() { .rotorStats(130, 155, 3.0f, 512) .fluidPipeProperties(2180, 35, true, true, false, false) .blastTemp(1700, GasTier.LOW) - .irritantHazard(false) + .hazard(HazardProperty.HazardTrigger.SKIN_CONTACT, GTMedicalConditions.CARCINOGEN) .buildAndRegister(); Cobalt = new Material.Builder(GTCEu.id("cobalt")) @@ -282,7 +278,7 @@ public static void register() { Fluorine = new Material.Builder(GTCEu.id("fluorine")) .gas(new FluidBuilder().state(FluidState.GAS).customStill()) .element(GTElements.F) - .hazard(HazardProperty.HazardType.CONTACT_POISON, false) + .hazard(HazardProperty.HazardTrigger.SKIN_CONTACT, GTMedicalConditions.CHEMICAL_BURNS, false) .buildAndRegister(); Francium = new Material.Builder(GTCEu.id("francium")) @@ -433,7 +429,7 @@ public static void register() { .element(GTElements.Pb) .cableProperties(GTValues.V[0], 2, 2) .fluidPipeProperties(1200, 32, true) - .hazard(HazardProperty.HazardType.INHALATION_POISON) + .hazard(HazardProperty.HazardTrigger.INHALATION, GTMedicalConditions.WEAK_POISON) .buildAndRegister(); Lithium = new Material.Builder(GTCEu.id("lithium")) @@ -486,7 +482,7 @@ public static void register() { .fluid() .color(0xE6DCDC).iconSet(DULL) .element(GTElements.Hg) - .hazard(HazardProperty.HazardType.CONTACT_POISON) + .hazard(HazardProperty.HazardTrigger.ANY, GTMedicalConditions.WEAK_POISON) .buildAndRegister(); Molybdenum = new Material.Builder(GTCEu.id("molybdenum")) @@ -629,7 +625,7 @@ public static void register() { .ore(true) .color(0xba2727).secondaryColor(0x222730).iconSet(RADIOACTIVE) .element(GTElements.Pu239) - .radioactiveHazard(1.5f) + // TODO.radioactiveHazard(1.5f) .buildAndRegister(); Plutonium241 = new Material.Builder(GTCEu.id("plutonium_241")) @@ -638,7 +634,7 @@ public static void register() { .color(0xfa7272).secondaryColor(0x222730).iconSet(RADIOACTIVE) .appendFlags(EXT_METAL) .element(GTElements.Pu241) - .radioactiveHazard(1.5f) + // TODO.radioactiveHazard(1.5f) .buildAndRegister(); Potassium = new Material.Builder(GTCEu.id("potassium")) @@ -857,7 +853,7 @@ public static void register() { .color(0xff316b).secondaryColor(0xd00000) .iconSet(METALLIC) .element(GTElements.T) - .radioactiveHazard(1) + // TODO.radioactiveHazard(1) .buildAndRegister(); Tungsten = new Material.Builder(GTCEu.id("tungsten")) @@ -879,7 +875,7 @@ public static void register() { .color(0x1d891d).secondaryColor(0x33342c).iconSet(RADIOACTIVE) .appendFlags(EXT_METAL) .element(GTElements.U238) - .radioactiveHazard(1) + // TODO.radioactiveHazard(1) .buildAndRegister(); Uranium235 = new Material.Builder(GTCEu.id("uranium_235")) @@ -888,7 +884,7 @@ public static void register() { .color(0x46FA46).secondaryColor(0x33342c).iconSet(RADIOACTIVE) .appendFlags(EXT_METAL) .element(GTElements.U235) - .radioactiveHazard(1) + // TODO.radioactiveHazard(1) .buildAndRegister(); Vanadium = new Material.Builder(GTCEu.id("vanadium")) @@ -940,7 +936,7 @@ public static void register() { .cableProperties(GTValues.V[7], 2, 2) .fluidPipeProperties(3776, 200, true, false, true, true) .blastTemp(5000, GasTier.HIGH, GTValues.VA[GTValues.IV], 600) - .radioactiveHazard(2) + // TODO.radioactiveHazard(2) .buildAndRegister(); NaquadahEnriched = new Material.Builder(GTCEu.id("enriched_naquadah")) @@ -950,7 +946,7 @@ public static void register() { .appendFlags(EXT_METAL, GENERATE_FOIL) .element(GTElements.Nq1) .blastTemp(7000, GasTier.HIGH, GTValues.VA[GTValues.IV], 1000) - .radioactiveHazard(2.5f) + // TODO.radioactiveHazard(2.5f) .buildAndRegister(); Naquadria = new Material.Builder(GTCEu.id("naquadria")) @@ -960,7 +956,7 @@ public static void register() { .appendFlags(EXT_METAL, GENERATE_FOIL, GENERATE_GEAR, GENERATE_FINE_WIRE, GENERATE_BOLT_SCREW) .element(GTElements.Nq2) .blastTemp(9000, GasTier.HIGH, GTValues.VA[GTValues.ZPM], 1200) - .radioactiveHazard(3) + // TODO.radioactiveHazard(3) .buildAndRegister(); Neutronium = new Material.Builder(GTCEu.id("neutronium")) @@ -973,7 +969,7 @@ public static void register() { .attackSpeed(0.5F).enchantability(33).magnetic().unbreakable().build()) .rotorStats(400, 250, 12.0f, 655360) .fluidPipeProperties(100_000, 5000, true, true, true, true) - .radioactiveHazard(10) + // TODO.radioactiveHazard(10) .buildAndRegister(); Tritanium = new Material.Builder(GTCEu.id("tritanium")) diff --git a/src/main/java/com/gregtechceu/gtceu/common/data/materials/FirstDegreeMaterials.java b/src/main/java/com/gregtechceu/gtceu/common/data/materials/FirstDegreeMaterials.java index d3396a9741..898a4c77fd 100644 --- a/src/main/java/com/gregtechceu/gtceu/common/data/materials/FirstDegreeMaterials.java +++ b/src/main/java/com/gregtechceu/gtceu/common/data/materials/FirstDegreeMaterials.java @@ -11,9 +11,8 @@ import com.gregtechceu.gtceu.api.fluids.FluidState; import com.gregtechceu.gtceu.api.fluids.attribute.FluidAttributes; import com.gregtechceu.gtceu.api.item.tool.GTToolType; +import com.gregtechceu.gtceu.common.data.GTMedicalConditions; -import net.minecraft.world.effect.MobEffectInstance; -import net.minecraft.world.effect.MobEffects; import net.minecraft.world.item.enchantment.Enchantments; import static com.gregtechceu.gtceu.api.GTValues.*; @@ -49,7 +48,7 @@ public static void register() { Asbestos = new Material.Builder(GTCEu.id("asbestos")) .dust(1).ore(3, 1) .color(0xE6E6E6).secondaryColor(0xdbd7bf) - .hazard(HazardProperty.HazardType.INHALATION_POISON) + .hazard(HazardProperty.HazardTrigger.INHALATION, GTMedicalConditions.ASBESTOSIS) .components(Magnesium, 3, Silicon, 2, Hydrogen, 4, Oxygen, 9) .buildAndRegister(); @@ -854,6 +853,7 @@ public static void register() { .color(0xf2f2f2).secondaryColor(0xb2c4c7).iconSet(QUARTZ) .flags(NO_SMASHING, NO_SMELTING) .components(Silicon, 1, Oxygen, 2) + .hazard(HazardProperty.HazardTrigger.INHALATION, GTMedicalConditions.SILICOSIS, false) .buildAndRegister(); MagnesiumChloride = new Material.Builder(GTCEu.id("magnesium_chloride")) @@ -879,9 +879,7 @@ public static void register() { .dust(1) .color(0xecfff3).secondaryColor(0x7d8e83) .components(Calcium, 1, Oxygen, 1) - .hazard(HazardProperty.HazardType.CORROSIVE, - new HazardProperty.HazardEffect(5000, () -> new MobEffectInstance(MobEffects.WEAKNESS, 1), - () -> new MobEffectInstance(MobEffects.DIG_SLOWDOWN, 1))) + .hazard(HazardProperty.HazardTrigger.SKIN_CONTACT, GTMedicalConditions.CHEMICAL_BURNS) .buildAndRegister(); SodiumBisulfate = new Material.Builder(GTCEu.id("sodium_bisulfate")) @@ -927,14 +925,14 @@ public static void register() { .dust(1) .color(0xff6000).secondaryColor(0xFF0000) .components(Potassium, 2, Chromium, 2, Oxygen, 7) - .hazard(HazardProperty.HazardType.CONTACT_POISON) + .hazard(HazardProperty.HazardTrigger.ANY, GTMedicalConditions.POISON) .buildAndRegister(); ChromiumTrioxide = new Material.Builder(GTCEu.id("chromium_trioxide")) .dust(1) .color(0xFFE4E1) .components(Chromium, 1, Oxygen, 3) - .irritantHazard(true) + .hazard(HazardProperty.HazardTrigger.SKIN_CONTACT, GTMedicalConditions.IRRITANT) .buildAndRegister(); AntimonyTrioxide = new Material.Builder(GTCEu.id("antimony_trioxide")) @@ -990,9 +988,7 @@ public static void register() { .color(0xf5feff).secondaryColor(0xa4ebf1) .flags(DISABLE_DECOMPOSITION) .components(Sodium, 1, Oxygen, 1, Hydrogen, 1) - .hazard(HazardProperty.HazardType.CORROSIVE, - new HazardProperty.HazardEffect(5000, () -> new MobEffectInstance(MobEffects.WEAKNESS, 1), - () -> new MobEffectInstance(MobEffects.DIG_SLOWDOWN, 1))) + .hazard(HazardProperty.HazardTrigger.SKIN_CONTACT, GTMedicalConditions.CHEMICAL_BURNS) .buildAndRegister(); SodiumPersulfate = new Material.Builder(GTCEu.id("sodium_persulfate")) @@ -1113,13 +1109,13 @@ public static void register() { .gas() .color(0x85FCFF) .components(Nitrogen, 1, Oxygen, 2) - .hazard(HazardProperty.HazardType.INHALATION_POISON) + .hazard(HazardProperty.HazardTrigger.INHALATION, GTMedicalConditions.POISON, 10) .buildAndRegister(); HydrogenSulfide = new Material.Builder(GTCEu.id("hydrogen_sulfide")) .gas(new FluidBuilder().customStill()) .components(Hydrogen, 2, Sulfur, 1) - .hazard(HazardProperty.HazardType.INHALATION_POISON) + .hazard(HazardProperty.HazardTrigger.INHALATION, GTMedicalConditions.POISON, 5) .buildAndRegister(); NitricAcid = new Material.Builder(GTCEu.id("nitric_acid")) @@ -1146,21 +1142,21 @@ public static void register() { .gas() .color(0xA0A014) .components(Sulfur, 1, Oxygen, 3) - .hazard(HazardProperty.HazardType.INHALATION_POISON) + .hazard(HazardProperty.HazardTrigger.INHALATION, GTMedicalConditions.POISON, 1) .buildAndRegister(); SulfurDioxide = new Material.Builder(GTCEu.id("sulfur_dioxide")) .gas() .color(0x0E4880) .components(Sulfur, 1, Oxygen, 2) - .hazard(HazardProperty.HazardType.INHALATION_POISON) + .hazard(HazardProperty.HazardTrigger.INHALATION, GTMedicalConditions.POISON, 1) .buildAndRegister(); CarbonMonoxide = new Material.Builder(GTCEu.id("carbon_monoxide")) .gas() .color(0x0E4880) .components(Carbon, 1, Oxygen, 1) - .hazard(HazardProperty.HazardType.INHALATION_POISON) + .hazard(HazardProperty.HazardTrigger.INHALATION, GTMedicalConditions.CARBON_MONOXIDE_POISONING) .buildAndRegister(); HypochlorousAcid = new Material.Builder(GTCEu.id("hypochlorous_acid")) @@ -1179,14 +1175,14 @@ public static void register() { .liquid(new FluidBuilder().attribute(FluidAttributes.ACID)) .color(0x0088AA) .components(Hydrogen, 1, Fluorine, 1) - .hazard(HazardProperty.HazardType.CONTACT_POISON) + // TODO HF poisoning .hazard(HazardProperty.HazardTrigger.ANY) .buildAndRegister(); NitricOxide = new Material.Builder(GTCEu.id("nitric_oxide")) .gas() .color(0x7DC8F0) .components(Nitrogen, 1, Oxygen, 1) - .hazard(HazardProperty.HazardType.INHALATION_POISON) + .hazard(HazardProperty.HazardTrigger.INHALATION, GTMedicalConditions.POISON, 1) .buildAndRegister(); Iron3Chloride = new Material.Builder(GTCEu.id("iron_iii_chloride")) @@ -1229,7 +1225,7 @@ public static void register() { .gas() .color(0x7DC8FF) .components(Nitrogen, 2, Oxygen, 1) - .hazard(HazardProperty.HazardType.INHALATION_POISON) + .hazard(HazardProperty.HazardTrigger.INHALATION, GTMedicalConditions.POISON, .5f) .buildAndRegister(); EnderPearl = new Material.Builder(GTCEu.id("ender_pearl")) @@ -1237,7 +1233,6 @@ public static void register() { .color(0x8cf4e2).secondaryColor(0x032620).iconSet(SHINY) .flags(NO_SMASHING, NO_SMELTING, GENERATE_PLATE) .components(Beryllium, 1, Potassium, 4, Nitrogen, 5) - .hazard(HazardProperty.HazardType.NONE) .buildAndRegister(); PotassiumFeldspar = new Material.Builder(GTCEu.id("potassium_feldspar")) @@ -1416,7 +1411,7 @@ public static void register() { .color(0xACAD71).secondaryColor(0x291f34).iconSet(METALLIC) .flags(DISABLE_DECOMPOSITION) .components(Osmium, 1, Oxygen, 4) - .hazard(HazardProperty.HazardType.CONTACT_POISON) + // TODO Osmium tetroxide poisoning .hazard(HazardProperty.HazardTrigger.ANY) .buildAndRegister(); IridiumChloride = new Material.Builder(GTCEu.id("iridium_chloride")) @@ -1506,9 +1501,7 @@ public static void register() { PotassiumHydroxide = new Material.Builder(GTCEu.id("potassium_hydroxide")) .dust(1) .color(0xd1c299).secondaryColor(0x85623a).iconSet(METALLIC) - .hazard(HazardProperty.HazardType.CORROSIVE, - new HazardProperty.HazardEffect(5000, () -> new MobEffectInstance(MobEffects.WEAKNESS, 1), - () -> new MobEffectInstance(MobEffects.DIG_SLOWDOWN, 1))) + .hazard(HazardProperty.HazardTrigger.SKIN_CONTACT, GTMedicalConditions.CHEMICAL_BURNS) .components(Potassium, 1, Oxygen, 1, Hydrogen, 1) .buildAndRegister(); @@ -1542,6 +1535,7 @@ public static void register() { .dust() .color(0x72dbd4).secondaryColor(0x138a80).iconSet(ROUGH) .components(Calcium, 1, Oxygen, 2, Hydrogen, 2) + .hazard(HazardProperty.HazardTrigger.SKIN_CONTACT, GTMedicalConditions.CHEMICAL_BURNS) .buildAndRegister() .setFormula("Ca(OH)2", true); @@ -1555,21 +1549,21 @@ public static void register() { .dust() .color(0x93badb).secondaryColor(0x0c5696).iconSet(ROUGH) .components(Potassium, 1, Carbon, 1, Nitrogen, 1) - .hazard(HazardProperty.HazardType.INHALATION_POISON, HazardProperty.poisonEffect(100, 0, 4), true) + .hazard(HazardProperty.HazardTrigger.ANY, GTMedicalConditions.CHEMICAL_BURNS, true) .buildAndRegister(); HydrogenCyanide = new Material.Builder(GTCEu.id("hydrogen_cyanide")) .gas() .color(0x72dbd4) .components(Hydrogen, 1, Carbon, 1, Nitrogen, 1) - .hazard(HazardProperty.HazardType.INHALATION_POISON, HazardProperty.poisonEffect(100, 0, 4), true) + .hazard(HazardProperty.HazardTrigger.ANY, GTMedicalConditions.CHEMICAL_BURNS, true) .buildAndRegister(); FormicAcid = new Material.Builder(GTCEu.id("formic_acid")) .gas() .color(0xa6a6a6) .components(Carbon, 1, Hydrogen, 2, Oxygen, 2) - .hazard(HazardProperty.HazardType.INHALATION_POISON) + .hazard(HazardProperty.HazardTrigger.INHALATION, GTMedicalConditions.CHEMICAL_BURNS) .buildAndRegister(); PotassiumSulfate = new Material.Builder(GTCEu.id("potassium_sulfate")) @@ -1592,7 +1586,7 @@ public static void register() { .color(0xddeced) .flags(DECOMPOSITION_BY_ELECTROLYZING) .components(Carbon, 1, Hydrogen, 2, Oxygen, 1) - .hazard(HazardProperty.HazardType.INHALATION_POISON) + .hazard(HazardProperty.HazardTrigger.INHALATION, GTMedicalConditions.POISON) .buildAndRegister(); Glycolonitrile = new Material.Builder(GTCEu.id("glycolonitrile")) diff --git a/src/main/java/com/gregtechceu/gtceu/common/data/materials/OrganicChemistryMaterials.java b/src/main/java/com/gregtechceu/gtceu/common/data/materials/OrganicChemistryMaterials.java index 0d1b1dcd9c..af25ab93d3 100644 --- a/src/main/java/com/gregtechceu/gtceu/common/data/materials/OrganicChemistryMaterials.java +++ b/src/main/java/com/gregtechceu/gtceu/common/data/materials/OrganicChemistryMaterials.java @@ -7,9 +7,7 @@ import com.gregtechceu.gtceu.api.fluids.FluidBuilder; import com.gregtechceu.gtceu.api.fluids.attribute.FluidAttributes; import com.gregtechceu.gtceu.api.item.tool.GTToolType; - -import net.minecraft.world.effect.MobEffectInstance; -import net.minecraft.world.effect.MobEffects; +import com.gregtechceu.gtceu.common.data.GTMedicalConditions; import static com.gregtechceu.gtceu.api.data.chemical.material.info.MaterialFlags.*; import static com.gregtechceu.gtceu.api.data.chemical.material.info.MaterialIconSet.FINE; @@ -35,7 +33,7 @@ public static void register() { .color(0x704936) .flags(DISABLE_DECOMPOSITION) .components(Carbon, 6, Hydrogen, 5, Nitrogen, 1, Oxygen, 2) - .hazard(HazardProperty.HazardType.INHALATION_POISON) + .hazard(HazardProperty.HazardTrigger.INHALATION, GTMedicalConditions.CARCINOGEN) .buildAndRegister(); RawRubber = new Material.Builder(GTCEu.id("raw_rubber")) @@ -185,7 +183,7 @@ public static void register() { .fluid() .color(0x892CA0) .components(Carbon, 1, Hydrogen, 1, Chlorine, 3) - .hazard(HazardProperty.HazardType.INHALATION_POISON) + .hazard(HazardProperty.HazardTrigger.INHALATION, GTMedicalConditions.POISON) .buildAndRegister(); Cumene = new Material.Builder(GTCEu.id("cumene")) @@ -288,7 +286,7 @@ public static void register() { .color(0x0F2828) .flags(DISABLE_DECOMPOSITION) .components(Carbon, 1, Nitrogen, 4, Oxygen, 8) - .hazard(HazardProperty.HazardType.INHALATION_POISON) + .hazard(HazardProperty.HazardTrigger.INHALATION, GTMedicalConditions.WEAK_POISON) .buildAndRegister(); Dimethylamine = new Material.Builder(GTCEu.id("dimethylamine")) @@ -303,7 +301,7 @@ public static void register() { .color(0x000055) .flags(DISABLE_DECOMPOSITION) .components(Carbon, 2, Hydrogen, 8, Nitrogen, 2) - .hazard(HazardProperty.HazardType.INHALATION_POISON) + .hazard(HazardProperty.HazardTrigger.INHALATION, GTMedicalConditions.CARCINOGEN) .buildAndRegister(); DinitrogenTetroxide = new Material.Builder(GTCEu.id("dinitrogen_tetroxide")) @@ -352,7 +350,7 @@ public static void register() { .color(0x784421) .flags(DISABLE_DECOMPOSITION) .components(Carbon, 6, Hydrogen, 6, Oxygen, 1) - .hazard(HazardProperty.HazardType.INHALATION_POISON) + .hazard(HazardProperty.HazardTrigger.INHALATION, GTMedicalConditions.CARCINOGEN) .buildAndRegister(); BisphenolA = new Material.Builder(GTCEu.id("bisphenol_a")) @@ -367,7 +365,7 @@ public static void register() { .color(0xE1F0F0) .flags(DISABLE_DECOMPOSITION) .components(Carbon, 2, Hydrogen, 3, Chlorine, 1) - .hazard(HazardProperty.HazardType.INHALATION_POISON) + .hazard(HazardProperty.HazardTrigger.INHALATION, GTMedicalConditions.CARCINOGEN) .buildAndRegister(); Ethylene = new Material.Builder(GTCEu.id("ethylene")) @@ -382,7 +380,7 @@ public static void register() { .color(0x1A1A1A) .flags(DISABLE_DECOMPOSITION) .components(Carbon, 6, Hydrogen, 6) - .hazard(HazardProperty.HazardType.INHALATION_POISON) + .hazard(HazardProperty.HazardTrigger.INHALATION, GTMedicalConditions.CARCINOGEN) .buildAndRegister(); Acetone = new Material.Builder(GTCEu.id("acetone")) @@ -402,15 +400,13 @@ public static void register() { .fluid() .color(0xAA8800) .components(Carbon, 1, Hydrogen, 4, Oxygen, 1) - .hazard(HazardProperty.HazardType.INHALATION_POISON, HazardProperty.blindnessEffect(200, 200, 3)) + .hazard(HazardProperty.HazardTrigger.INHALATION, GTMedicalConditions.METHANOL_POISONING) .buildAndRegister(); Ethanol = new Material.Builder(GTCEu.id("ethanol")) .liquid(new FluidBuilder().customStill()) .flags(DISABLE_DECOMPOSITION) - .hazard(HazardProperty.HazardType.INHALATION_POISON, - new HazardProperty.HazardEffect(200, () -> new MobEffectInstance(MobEffects.CONFUSION, 1))) - .components(Carbon, 2, Hydrogen, 6, Oxygen, 1) + // TODO ethanol intoxication .hazard(HazardProperty.HazardTrigger.INHALATION, .buildAndRegister(); Toluene = new Material.Builder(GTCEu.id("toluene")) @@ -470,7 +466,7 @@ public static void register() { .color(0x326A3E) .flags(DISABLE_DECOMPOSITION) .components(Carbon, 6, Hydrogen, 5, Chlorine, 1) - .hazard(HazardProperty.HazardType.INHALATION_POISON) + .hazard(HazardProperty.HazardTrigger.INHALATION, GTMedicalConditions.CARCINOGEN) .buildAndRegister(); Octane = new Material.Builder(GTCEu.id("octane")) @@ -491,7 +487,7 @@ public static void register() { .fluid() .flags(DISABLE_DECOMPOSITION) .components(Carbon, 8, Hydrogen, 10) - .hazard(HazardProperty.HazardType.INHALATION_POISON) + .hazard(HazardProperty.HazardTrigger.INHALATION, GTMedicalConditions.CARCINOGEN) .buildAndRegister(); Naphthalene = new Material.Builder(GTCEu.id("naphthalene")) @@ -545,7 +541,7 @@ public static void register() { .color(0x554A3F) .flags(DISABLE_DECOMPOSITION) .components(Carbon, 4, Hydrogen, 8, Oxygen, 1) - .hazard(HazardProperty.HazardType.INHALATION_POISON, false) + .hazard(HazardProperty.HazardTrigger.INHALATION, GTMedicalConditions.NAUSEA, false) .buildAndRegister(); PolyvinylButyral = new Material.Builder(GTCEu.id("polyvinyl_butyral")) @@ -568,7 +564,7 @@ public static void register() { .color(0xCACC0E) .flags(DISABLE_DECOMPOSITION) .components(Carbon, 12, Hydrogen, 8, Chlorine, 2) - .hazard(HazardProperty.HazardType.INHALATION_POISON) + .hazard(HazardProperty.HazardTrigger.INHALATION, GTMedicalConditions.CARCINOGEN) .buildAndRegister() .setFormula("(C6H4Cl)2", true); @@ -599,14 +595,14 @@ public static void register() { .gas() .color(0x93badb) .components(Carbon, 1, Hydrogen, 5, Nitrogen, 1, Oxygen, 2) - .hazard(HazardProperty.HazardType.INHALATION_POISON) + .hazard(HazardProperty.HazardTrigger.INHALATION, GTMedicalConditions.IRRITANT) .buildAndRegister(); Formamide = new Material.Builder(GTCEu.id("formamide")) .liquid() .color(0x5cccb6) .components(Carbon, 1, Hydrogen, 3, Nitrogen, 1, Oxygen, 1) - .hazard(HazardProperty.HazardType.INHALATION_POISON) + .hazard(HazardProperty.HazardTrigger.INHALATION, GTMedicalConditions.CHEMICAL_BURNS) .buildAndRegister(); } } diff --git a/src/main/java/com/gregtechceu/gtceu/common/data/materials/SecondDegreeMaterials.java b/src/main/java/com/gregtechceu/gtceu/common/data/materials/SecondDegreeMaterials.java index e60d37b4a4..2acdcec244 100644 --- a/src/main/java/com/gregtechceu/gtceu/common/data/materials/SecondDegreeMaterials.java +++ b/src/main/java/com/gregtechceu/gtceu/common/data/materials/SecondDegreeMaterials.java @@ -10,6 +10,7 @@ import com.gregtechceu.gtceu.api.fluids.FluidBuilder; import com.gregtechceu.gtceu.api.fluids.attribute.FluidAttributes; import com.gregtechceu.gtceu.api.item.tool.GTToolType; +import com.gregtechceu.gtceu.common.data.GTMedicalConditions; import net.minecraft.world.item.enchantment.Enchantments; @@ -322,7 +323,7 @@ public static void register() { .color(0xa8aa9a).iconSet(ROUGH) .flags(DECOMPOSITION_BY_CENTRIFUGING) .components(Asbestos, 4, Saltpeter, 1) - .hazard(HazardProperty.HazardType.NONE) + .removeHazard() .buildAndRegister(); NaquadahAlloy = new Material.Builder(GTCEu.id("naquadah_alloy")) @@ -408,7 +409,7 @@ public static void register() { .color(0x4C3434) .flags(DISABLE_DECOMPOSITION) .components(CarbonMonoxide, 78, HydrogenSulfide, 21, Neon, 9) - .hazard(HazardProperty.HazardType.INHALATION_POISON) + .hazard(HazardProperty.HazardTrigger.INHALATION, GTMedicalConditions.CHEMICAL_BURNS) .buildAndRegister(); LiquidNetherAir = new Material.Builder(GTCEu.id("liquid_nether_air")) @@ -499,7 +500,7 @@ public static void register() { .flags(GENERATE_PLATE, NO_SMASHING, NO_SMELTING, EXCLUDE_BLOCK_CRAFTING_BY_HAND_RECIPES, EXCLUDE_PLATE_COMPRESSOR_RECIPE, DECOMPOSITION_BY_CENTRIFUGING) .components(Silicon, 1, Pyrite, 5, Ruby, 1, Mercury, 3) - .hazard(HazardProperty.HazardType.NONE) + .removeHazard() .buildAndRegister(); Dichloroethane = new Material.Builder(GTCEu.id("dichloroethane")) @@ -514,7 +515,7 @@ public static void register() { .color(0xa9d9a7) .flags(DISABLE_DECOMPOSITION) .components(Carbon, 4, Hydrogen, 13, Nitrogen, 3) - .hazard(HazardProperty.HazardType.CONTACT_POISON) + .hazard(HazardProperty.HazardTrigger.ANY, GTMedicalConditions.CHEMICAL_BURNS) .buildAndRegister(); RawBrine = new Material.Builder(GTCEu.id("raw_brine")) diff --git a/src/main/java/com/gregtechceu/gtceu/common/data/materials/UnknownCompositionMaterials.java b/src/main/java/com/gregtechceu/gtceu/common/data/materials/UnknownCompositionMaterials.java index 3daa931ec7..e21a17c358 100644 --- a/src/main/java/com/gregtechceu/gtceu/common/data/materials/UnknownCompositionMaterials.java +++ b/src/main/java/com/gregtechceu/gtceu/common/data/materials/UnknownCompositionMaterials.java @@ -7,6 +7,7 @@ import com.gregtechceu.gtceu.api.fluids.FluidBuilder; import com.gregtechceu.gtceu.api.fluids.attribute.FluidAttributes; import com.gregtechceu.gtceu.api.item.tool.GTToolType; +import com.gregtechceu.gtceu.common.data.GTMedicalConditions; import static com.gregtechceu.gtceu.api.data.chemical.material.info.MaterialFlags.*; import static com.gregtechceu.gtceu.api.data.chemical.material.info.MaterialIconSet.*; @@ -557,7 +558,7 @@ public static void register() { PCBCoolant = new Material.Builder(GTCEu.id("pcb_coolant")) .fluid().color(0xD5D69C) - .hazard(HazardProperty.HazardType.INHALATION_POISON) + .hazard(HazardProperty.HazardTrigger.INHALATION, GTMedicalConditions.CARCINOGEN) .buildAndRegister(); } } diff --git a/src/main/java/com/gregtechceu/gtceu/common/item/AntidoteBehavior.java b/src/main/java/com/gregtechceu/gtceu/common/item/AntidoteBehavior.java index 1f152f64e3..fa9729751e 100644 --- a/src/main/java/com/gregtechceu/gtceu/common/item/AntidoteBehavior.java +++ b/src/main/java/com/gregtechceu/gtceu/common/item/AntidoteBehavior.java @@ -1,10 +1,8 @@ package com.gregtechceu.gtceu.common.item; import com.gregtechceu.gtceu.api.capability.GTCapabilityHelper; -import com.gregtechceu.gtceu.api.capability.IHazardEffectTracker; -import com.gregtechceu.gtceu.api.data.chemical.material.Material; -import com.gregtechceu.gtceu.api.data.chemical.material.properties.HazardProperty; -import com.gregtechceu.gtceu.api.data.chemical.material.properties.PropertyKey; +import com.gregtechceu.gtceu.api.capability.IMedicalConditionTracker; +import com.gregtechceu.gtceu.api.data.medicalcondition.MedicalCondition; import com.gregtechceu.gtceu.api.item.component.IAddInformation; import com.gregtechceu.gtceu.api.item.component.IInteractionItem; import com.gregtechceu.gtceu.config.ConfigHolder; @@ -16,7 +14,6 @@ import net.minecraft.world.item.TooltipFlag; import net.minecraft.world.level.Level; -import org.jetbrains.annotations.NotNull; import org.jetbrains.annotations.Nullable; import java.util.Arrays; @@ -31,10 +28,10 @@ * @param removePercent the time to remove from the chosen hazard, as a percentage of the current time [0, 100]. * -1 for all. */ -public record AntidoteBehavior(Set types, int removePercent) +public record AntidoteBehavior(Set types, int removePercent) implements IInteractionItem, IAddInformation { - public AntidoteBehavior(int timeToRemove, HazardProperty.HazardType... types) { + public AntidoteBehavior(int timeToRemove, MedicalCondition... types) { this(new HashSet<>(), timeToRemove); this.types.addAll(Arrays.asList(types)); } @@ -42,63 +39,53 @@ public AntidoteBehavior(int timeToRemove, HazardProperty.HazardType... types) { @Override public ItemStack finishUsingItem(ItemStack stack, Level level, LivingEntity livingEntity) { ItemStack itemstack = IInteractionItem.super.finishUsingItem(stack, level, livingEntity); - IHazardEffectTracker tracker = GTCapabilityHelper.getHazardEffectTracker(livingEntity); + IMedicalConditionTracker tracker = GTCapabilityHelper.getMedicalConditionTracker(livingEntity); if (tracker == null) { return itemstack; } - var iterator = tracker.getCurrentHazards().object2IntEntrySet().iterator(); - while (iterator.hasNext()) { - var entry = iterator.next(); - if (entry.getKey() == null) { + for (var entry : tracker.getMedicalConditions().object2FloatEntrySet()) { + MedicalCondition condition = entry.getKey(); + if (condition == null) { continue; } - HazardProperty.HazardType type = getHazardTypeFromMaterial(entry.getKey()); - if (type == null || !this.types.contains(type)) { + if (!this.types.contains(condition)) { continue; } if (removePercent == -1) { - iterator.remove(); + tracker.removeMedicalCondition(condition); } else { - int time = entry.getIntValue(); + float time = entry.getFloatValue(); float timeToRemove = time * (removePercent / 100.0f); if (timeToRemove > 0.05f * time) { - iterator.remove(); + tracker.removeMedicalCondition(condition); continue; } - entry.setValue((int) (time - timeToRemove)); + tracker.heal(condition, (int) timeToRemove); } } return itemstack; } - @Nullable - public static HazardProperty.HazardType getHazardTypeFromMaterial(@NotNull Material material) { - HazardProperty property = material.getProperty(PropertyKey.HAZARD); - if (property == null) { - return null; - } - return property.getHazardType(); - } - @Override public void appendHoverText(ItemStack stack, @Nullable Level level, List tooltipComponents, TooltipFlag isAdvanced) { if (!ConfigHolder.INSTANCE.gameplay.hazardsEnabled) return; if (GTUtil.isShiftDown()) { - tooltipComponents.add(Component.translatable("gtceu.hazard.antidote.description_shift")); + tooltipComponents.add(Component.translatable("gtceu.medical_condition.antidote.description_shift")); for (var type : types) { - tooltipComponents.add(Component - .translatable("gtceu.hazard." + type.getSerializedName())); + tooltipComponents.add(Component.translatable("gtceu.medical_condition." + type.name)); } if (removePercent == -1) { - tooltipComponents.add(Component.translatable("gtceu.hazard.antidote.description.effect_removed.all")); + tooltipComponents + .add(Component.translatable("gtceu.medical_condition.antidote.description.effect_removed.all")); } else { tooltipComponents - .add(Component.translatable("gtceu.hazard.antidote.description.effect_removed", removePercent)); + .add(Component.translatable("gtceu.medical_condition.antidote.description.effect_removed", + removePercent)); } return; } - tooltipComponents.add(Component.translatable("gtceu.hazard.antidote.description")); + tooltipComponents.add(Component.translatable("gtceu.medical_condition.antidote.description")); } } diff --git a/src/main/java/com/gregtechceu/gtceu/common/item/PortableScannerBehavior.java b/src/main/java/com/gregtechceu/gtceu/common/item/PortableScannerBehavior.java index 915cc555c9..18c9773a97 100644 --- a/src/main/java/com/gregtechceu/gtceu/common/item/PortableScannerBehavior.java +++ b/src/main/java/com/gregtechceu/gtceu/common/item/PortableScannerBehavior.java @@ -20,6 +20,8 @@ import com.gregtechceu.gtceu.api.recipe.GTRecipe; import com.gregtechceu.gtceu.api.recipe.RecipeHelper; import com.gregtechceu.gtceu.common.blockentity.FluidPipeBlockEntity; +import com.gregtechceu.gtceu.common.capability.EnvironmentalHazardSavedData; +import com.gregtechceu.gtceu.common.capability.LocalizedHazardSavedData; import com.gregtechceu.gtceu.common.data.GTSoundEntries; import com.gregtechceu.gtceu.utils.FormattingUtil; import com.gregtechceu.gtceu.utils.GTUtil; @@ -408,16 +410,28 @@ else if (machine instanceof IDataInfoProvider) } else { list.add(Component.translatable("behavior.portable_scanner.bedrock_fluid.nothing")); } - } - // TODO When pollution is in - // Pollution - // if (GT_Pollution.hasPollution(currentChunk)) { - // list.add("Pollution in Chunk: " + ChatFormatting.RED + - // GTUtility.formatNumbers(GT_Pollution.getPollution(currentChunk)) + ChatFormatting.RESET + " gibbl"); - // } else { - // list.add(ChatFormatting.GREEN + "No Pollution in Chunk! HAYO!" + ChatFormatting.RESET); - // } + // Pollution + var environmental = EnvironmentalHazardSavedData.getOrCreate(serverLevel); + var environmentHazardZone = environmental.getZoneByContainedPos(pos); + if (environmentHazardZone != null) { + list.add(Component.translatable("behavior.portable_scanner.environmental_hazard", + Component.translatable("gtceu.medical_condition." + environmentHazardZone.condition().name), + Component.literal(FormattingUtil.formatNumbers(environmentHazardZone.strength())))); + } else { + list.add(Component.translatable("behavior.portable_scanner.environmental_hazard.nothing")); + } + + var local = LocalizedHazardSavedData.getOrCreate(serverLevel); + var localHazardZone = local.getZoneByContainedPos(pos); + if (localHazardZone != null) { + list.add(Component.translatable("behavior.portable_scanner.local_hazard", + Component.translatable("gtceu.medical_condition." + localHazardZone.condition().name), + Component.literal(FormattingUtil.formatNumbers(localHazardZone.strength())))); + } else { + list.add(Component.translatable("behavior.portable_scanner.local_hazard.nothing")); + } + } } // Add optional debug info diff --git a/src/main/java/com/gregtechceu/gtceu/common/machine/electric/AirScrubberMachine.java b/src/main/java/com/gregtechceu/gtceu/common/machine/electric/AirScrubberMachine.java new file mode 100644 index 0000000000..915a632349 --- /dev/null +++ b/src/main/java/com/gregtechceu/gtceu/common/machine/electric/AirScrubberMachine.java @@ -0,0 +1,123 @@ +package com.gregtechceu.gtceu.common.machine.electric; + +import com.gregtechceu.gtceu.api.capability.GTCapabilityHelper; +import com.gregtechceu.gtceu.api.capability.IHazardParticleContainer; +import com.gregtechceu.gtceu.api.capability.recipe.IO; +import com.gregtechceu.gtceu.api.machine.IMachineBlockEntity; +import com.gregtechceu.gtceu.api.machine.SimpleTieredMachine; +import com.gregtechceu.gtceu.api.machine.trait.RecipeLogic; +import com.gregtechceu.gtceu.api.recipe.GTRecipe; +import com.gregtechceu.gtceu.common.capability.EnvironmentalHazardSavedData; +import com.gregtechceu.gtceu.common.data.GTMachines; +import com.gregtechceu.gtceu.common.recipe.EnvironmentalHazardCondition; + +import net.minecraft.core.Direction; +import net.minecraft.server.level.ServerLevel; +import net.minecraft.world.level.ChunkPos; + +import org.apache.commons.lang3.mutable.MutableBoolean; +import org.jetbrains.annotations.NotNull; + +public class AirScrubberMachine extends SimpleTieredMachine { + + public static final int CLEANING_PER_OPERATION = 10; + + public AirScrubberMachine(IMachineBlockEntity holder, int tier, Object... args) { + super(holder, tier, GTMachines.defaultTankSizeFunction, args); + } + + @NotNull + @Override + public RecipeLogic createRecipeLogic(Object... args) { + return new AirScrubberLogic(this); + } + + @Override + public boolean dampingWhenWaiting() { + return false; + } + + @Override + public boolean onWorking() { + if (getOffsetTimer() % 20 == 0) { + ServerLevel serverLevel = (ServerLevel) getLevel(); + EnvironmentalHazardSavedData savedData = EnvironmentalHazardSavedData.getOrCreate(serverLevel); + + final ChunkPos pos = new ChunkPos(getPos()); + ChunkPos[] relativePositions = new ChunkPos[] { + pos, + new ChunkPos(pos.x, pos.z - 1), + new ChunkPos(pos.x, pos.z + 1), + new ChunkPos(pos.x - 1, pos.z), + new ChunkPos(pos.x + 1, pos.z) + }; + for (ChunkPos rel : relativePositions) { + savedData.getHazardZones().compute(rel, (k, v) -> { + if (v == null || v.strength() <= 0) { + return null; + } + EnvironmentalHazardSavedData.HazardZone zone; + if (k.equals(pos)) { + zone = new EnvironmentalHazardSavedData.HazardZone( + v.source(), + v.strength() - CLEANING_PER_OPERATION * 2 * getTier(), + v.canSpread(), + v.trigger(), + v.condition()); + } else { + zone = new EnvironmentalHazardSavedData.HazardZone( + v.source(), + v.strength() - CLEANING_PER_OPERATION * getTier(), + v.canSpread(), + v.trigger(), + v.condition()); + } + if (zone.strength() <= 0) return null; + else return zone; + }); + } + } + return super.onWorking(); + } + + public static class AirScrubberLogic extends RecipeLogic { + + public AirScrubberLogic(AirScrubberMachine machine) { + super(machine); + } + + @Override + public AirScrubberMachine getMachine() { + return (AirScrubberMachine) super.getMachine(); + } + + @Override + protected boolean handleRecipeIO(GTRecipe recipe, IO io) { + Direction front = getMachine().getOutputFacingFluids(); + if (front == null) { + return super.handleRecipeIO(recipe, io); + } + final IHazardParticleContainer container = GTCapabilityHelper.getHazardContainer( + getMachine().getLevel(), getMachine().getPos().relative(front), front.getOpposite()); + if (container != null) { + // if we have a valid hazard container on the fluid output, then push the particles into it instead of + // converting them into fluid/item form. + MutableBoolean didFindCondition = new MutableBoolean(false); + recipe.conditions + .stream() + .filter(EnvironmentalHazardCondition.class::isInstance) + .map(EnvironmentalHazardCondition.class::cast) + .findFirst() + .ifPresent(condition -> { + container.addHazard(condition.getCondition(), + 6 * CLEANING_PER_OPERATION * getMachine().getTier()); + didFindCondition.setTrue(); + }); + if (didFindCondition.getValue()) { + return true; + } + } + return super.handleRecipeIO(recipe, io); + } + } +} diff --git a/src/main/java/com/gregtechceu/gtceu/common/machine/multiblock/primitive/PrimitiveWorkableMachine.java b/src/main/java/com/gregtechceu/gtceu/common/machine/multiblock/primitive/PrimitiveWorkableMachine.java index 66f25d89fc..80e6e86a50 100644 --- a/src/main/java/com/gregtechceu/gtceu/common/machine/multiblock/primitive/PrimitiveWorkableMachine.java +++ b/src/main/java/com/gregtechceu/gtceu/common/machine/multiblock/primitive/PrimitiveWorkableMachine.java @@ -5,6 +5,7 @@ import com.gregtechceu.gtceu.api.capability.recipe.ItemRecipeCapability; import com.gregtechceu.gtceu.api.machine.IMachineBlockEntity; import com.gregtechceu.gtceu.api.machine.MetaMachine; +import com.gregtechceu.gtceu.api.machine.feature.IEnvironmentalHazardEmitter; import com.gregtechceu.gtceu.api.machine.feature.IMachineModifyDrops; import com.gregtechceu.gtceu.api.machine.multiblock.WorkableMultiblockMachine; import com.gregtechceu.gtceu.api.machine.trait.NotifiableFluidTank; @@ -29,7 +30,8 @@ */ @ParametersAreNonnullByDefault @MethodsReturnNonnullByDefault -public class PrimitiveWorkableMachine extends WorkableMultiblockMachine implements IMachineModifyDrops { +public class PrimitiveWorkableMachine extends WorkableMultiblockMachine + implements IMachineModifyDrops, IEnvironmentalHazardEmitter { protected static final ManagedFieldHolder MANAGED_FIELD_HOLDER = new ManagedFieldHolder( PrimitiveWorkableMachine.class, WorkableMultiblockMachine.MANAGED_FIELD_HOLDER); @@ -82,4 +84,15 @@ public void onDrops(List drops, Player entity) { MetaMachine.clearInventory(drops, importItems.storage); MetaMachine.clearInventory(drops, exportItems.storage); } + + @Override + public int hazardStrengthPerOperation() { + return 1; + } + + @Override + public void afterWorking() { + super.afterWorking(); + spreadEnvironmentalHazard(); + } } diff --git a/src/main/java/com/gregtechceu/gtceu/common/machine/trait/CleanroomLogic.java b/src/main/java/com/gregtechceu/gtceu/common/machine/trait/CleanroomLogic.java index 01cd101387..72fe315b70 100644 --- a/src/main/java/com/gregtechceu/gtceu/common/machine/trait/CleanroomLogic.java +++ b/src/main/java/com/gregtechceu/gtceu/common/machine/trait/CleanroomLogic.java @@ -6,6 +6,7 @@ import com.gregtechceu.gtceu.api.capability.recipe.EURecipeCapability; import com.gregtechceu.gtceu.api.machine.feature.multiblock.IMaintenanceMachine; import com.gregtechceu.gtceu.api.machine.trait.RecipeLogic; +import com.gregtechceu.gtceu.common.capability.EnvironmentalHazardSavedData; import com.gregtechceu.gtceu.common.machine.multiblock.electric.CleanroomMachine; import com.gregtechceu.gtceu.config.ConfigHolder; @@ -13,6 +14,7 @@ import com.lowdragmc.lowdraglib.syncdata.field.ManagedFieldHolder; import net.minecraft.network.chat.Component; +import net.minecraft.server.level.ServerLevel; import lombok.Getter; import lombok.Setter; @@ -57,8 +59,12 @@ public ManagedFieldHolder getFieldHolder() { */ public void serverTick() { if (!isSuspend() && duration > 0) { - // all maintenance problems not fixed means the machine does not run - if (maintenanceMachine == null || maintenanceMachine.getNumMaintenanceProblems() < 6) { + EnvironmentalHazardSavedData environmentalHazards = EnvironmentalHazardSavedData + .getOrCreate((ServerLevel) this.getMachine().getLevel()); + var zone = environmentalHazards.getZoneByContainedPos(getMachine().getPos()); + // all maintenance problems not being fixed or there are environmental hazards in the area + // means the machine does not run + if (maintenanceMachine == null || maintenanceMachine.getNumMaintenanceProblems() < 6 || zone != null) { // drain the energy if (!consumeEnergy()) { if (progress > 0 && machine.dampingWhenWaiting()) { diff --git a/src/main/java/com/gregtechceu/gtceu/common/pipelike/duct/DuctNetHandler.java b/src/main/java/com/gregtechceu/gtceu/common/pipelike/duct/DuctNetHandler.java new file mode 100644 index 0000000000..51121626a0 --- /dev/null +++ b/src/main/java/com/gregtechceu/gtceu/common/pipelike/duct/DuctNetHandler.java @@ -0,0 +1,139 @@ +package com.gregtechceu.gtceu.common.pipelike.duct; + +import com.gregtechceu.gtceu.api.capability.IHazardParticleContainer; +import com.gregtechceu.gtceu.api.data.chemical.material.properties.HazardProperty; +import com.gregtechceu.gtceu.api.data.medicalcondition.MedicalCondition; +import com.gregtechceu.gtceu.common.blockentity.DuctPipeBlockEntity; +import com.gregtechceu.gtceu.common.capability.EnvironmentalHazardSavedData; + +import net.minecraft.core.Direction; + +import lombok.Getter; +import org.jetbrains.annotations.NotNull; +import org.jetbrains.annotations.Nullable; + +import java.util.List; +import java.util.Objects; + +public class DuctNetHandler implements IHazardParticleContainer { + + @Getter + private DuctPipeNet net; + private final DuctPipeBlockEntity pipe; + private final Direction facing; + + public DuctNetHandler(DuctPipeNet net, @NotNull DuctPipeBlockEntity pipe, @Nullable Direction facing) { + this.net = net; + this.pipe = pipe; + this.facing = facing; + } + + public void updateNetwork(DuctPipeNet net) { + this.net = net; + } + + @Nullable + private IHazardParticleContainer getInnerContainer() { + if (net == null || pipe.isInValid() || facing == null || pipe.isBlocked(facing)) { + return null; + } + + final List data = net.getNetData(pipe.getPipePos(), facing); + if (data == null) { + return null; + } + + return new IHazardParticleContainer() { + + @Override + public boolean inputsHazard(Direction side, MedicalCondition condition) { + return data.stream() + .map(path -> path.getHandler(net.getLevel())) + .filter(Objects::nonNull) + .anyMatch(handler -> handler.inputsHazard(side, condition)); + } + + @Override + public float changeHazard(MedicalCondition condition, float differenceAmount) { + float total = 0; + for (DuctRoutePath path : data) { + IHazardParticleContainer handler = path.getHandler(net.getLevel()); + if (handler == null && path.getTargetPipe().isConnected(path.getTargetFacing())) { + var savedData = EnvironmentalHazardSavedData.getOrCreate(net.getLevel()); + savedData.addZone(path.getTargetPipePos().relative(path.getTargetFacing()), + Math.round(differenceAmount), true, HazardProperty.HazardTrigger.INHALATION, condition); + total += differenceAmount; + break; + } + if (handler == null) { + continue; + } + float change = handler.changeHazard(condition, differenceAmount); + differenceAmount -= change; + total += change; + if (differenceAmount <= 0) { + break; + } + } + return total; + } + + @Override + public float getHazardStored(MedicalCondition condition) { + float total = 0; + for (DuctRoutePath path : data) { + IHazardParticleContainer handler = path.getHandler(net.getLevel()); + if (handler != null) { + total += handler.getHazardStored(condition); + } + } + return total; + } + + @Override + public float getHazardCapacity(MedicalCondition condition) { + float total = 0; + for (DuctRoutePath path : data) { + IHazardParticleContainer handler = path.getHandler(net.getLevel()); + if (handler != null) { + total += handler.getHazardCapacity(condition); + } + } + return total; + } + }; + } + + @Override + public boolean inputsHazard(Direction side, MedicalCondition condition) { + IHazardParticleContainer handler = getInnerContainer(); + if (handler == null) return false; + return handler.inputsHazard(side, condition); + } + + @Override + public boolean outputsHazard(Direction side, MedicalCondition condition) { + return true; + } + + @Override + public float changeHazard(MedicalCondition condition, float differenceAmount) { + IHazardParticleContainer handler = getInnerContainer(); + if (handler == null) return 0; + return handler.changeHazard(condition, differenceAmount); + } + + @Override + public float getHazardStored(MedicalCondition condition) { + IHazardParticleContainer handler = getInnerContainer(); + if (handler == null) return 0; + return handler.getHazardStored(condition); + } + + @Override + public float getHazardCapacity(MedicalCondition condition) { + IHazardParticleContainer handler = getInnerContainer(); + if (handler == null) return 0; + return handler.getHazardCapacity(condition); + } +} diff --git a/src/main/java/com/gregtechceu/gtceu/common/pipelike/duct/DuctNetWalker.java b/src/main/java/com/gregtechceu/gtceu/common/pipelike/duct/DuctNetWalker.java new file mode 100644 index 0000000000..46878c5012 --- /dev/null +++ b/src/main/java/com/gregtechceu/gtceu/common/pipelike/duct/DuctNetWalker.java @@ -0,0 +1,95 @@ +package com.gregtechceu.gtceu.common.pipelike.duct; + +import com.gregtechceu.gtceu.GTCEu; +import com.gregtechceu.gtceu.api.capability.IHazardParticleContainer; +import com.gregtechceu.gtceu.api.capability.forge.GTCapability; +import com.gregtechceu.gtceu.api.pipenet.PipeNetWalker; +import com.gregtechceu.gtceu.common.blockentity.DuctPipeBlockEntity; + +import net.minecraft.core.BlockPos; +import net.minecraft.core.Direction; +import net.minecraft.world.level.block.entity.BlockEntity; +import net.minecraftforge.common.util.LazyOptional; + +import org.jetbrains.annotations.NotNull; +import org.jetbrains.annotations.Nullable; + +import java.util.ArrayList; +import java.util.List; + +public class DuctNetWalker extends PipeNetWalker { + + public static List createNetData(DuctPipeNet pipeNet, BlockPos sourcePipe, Direction sourceFacing) { + if (!(pipeNet.getLevel().getBlockEntity(sourcePipe) instanceof DuctPipeBlockEntity)) { + return null; + } + try { + DuctNetWalker walker = new DuctNetWalker(pipeNet, sourcePipe, 1, new ArrayList<>(), null); + walker.sourcePipe = sourcePipe; + walker.facingToHandler = sourceFacing; + walker.traversePipeNet(); + return walker.inventories; + } catch (Exception e) { + GTCEu.LOGGER.error("error while create net data for DuctPipeNet", e); + } + return null; + } + + private DuctPipeProperties minProperties; + private final List inventories; + private BlockPos sourcePipe; + private Direction facingToHandler; + + protected DuctNetWalker(DuctPipeNet world, BlockPos sourcePipe, int distance, List inventories, + DuctPipeProperties properties) { + super(world, sourcePipe, distance); + this.inventories = inventories; + this.minProperties = properties; + } + + @NotNull + @Override + protected PipeNetWalker createSubWalker(DuctPipeNet pipeNet, + Direction facingToNextPos, + BlockPos nextPos, + int walkedBlocks) { + DuctNetWalker walker = new DuctNetWalker(pipeNet, nextPos, walkedBlocks, inventories, minProperties); + walker.facingToHandler = facingToHandler; + walker.sourcePipe = sourcePipe; + return walker; + } + + @Override + protected Class getBasePipeClass() { + return DuctPipeBlockEntity.class; + } + + @Override + protected void checkPipe(DuctPipeBlockEntity pipeTile, BlockPos pos) { + DuctPipeProperties pipeProperties = pipeTile.getNodeData(); + if (minProperties == null) { + minProperties = pipeProperties; + } else { + minProperties = new DuctPipeProperties( + Math.min(minProperties.getTransferRate(), pipeProperties.getTransferRate())); + } + } + + @Override + protected void checkNeighbour(DuctPipeBlockEntity pipeTile, BlockPos pipePos, Direction faceToNeighbour, + @Nullable BlockEntity neighbourTile) { + if ((pipePos.equals(sourcePipe) && faceToNeighbour == facingToHandler)) { + return; + } + if (neighbourTile != null) { + LazyOptional handler = neighbourTile.getCapability( + GTCapability.CAPABILITY_HAZARD_CONTAINER, + faceToNeighbour.getOpposite()); + if (handler.isPresent()) { + inventories.add(new DuctRoutePath(pipeTile, faceToNeighbour, getWalkedBlocks(), minProperties)); + } + } else if (pipeTile.isConnected(faceToNeighbour)) { + inventories.add(new DuctRoutePath(pipeTile, faceToNeighbour, getWalkedBlocks(), minProperties)); + } + } +} diff --git a/src/main/java/com/gregtechceu/gtceu/common/pipelike/duct/DuctPipeNet.java b/src/main/java/com/gregtechceu/gtceu/common/pipelike/duct/DuctPipeNet.java new file mode 100644 index 0000000000..26d7247ed6 --- /dev/null +++ b/src/main/java/com/gregtechceu/gtceu/common/pipelike/duct/DuctPipeNet.java @@ -0,0 +1,61 @@ +package com.gregtechceu.gtceu.common.pipelike.duct; + +import com.gregtechceu.gtceu.api.pipenet.LevelPipeNet; +import com.gregtechceu.gtceu.api.pipenet.Node; +import com.gregtechceu.gtceu.api.pipenet.PipeNet; + +import net.minecraft.core.BlockPos; +import net.minecraft.core.Direction; +import net.minecraft.nbt.CompoundTag; + +import java.util.*; + +public class DuctPipeNet extends PipeNet { + + private final Map> NET_DATA = new HashMap<>(); + + public DuctPipeNet(LevelPipeNet> world) { + super(world); + } + + public List getNetData(BlockPos pipePos, Direction facing) { + List data = NET_DATA.get(pipePos); + if (data == null) { + data = DuctNetWalker.createNetData(this, pipePos, facing); + if (data == null) { + // walker failed, don't cache so it tries again on next insertion + return Collections.emptyList(); + } + NET_DATA.put(pipePos, data); + } + return data; + } + + @Override + public void onNeighbourUpdate(BlockPos fromPos) { + NET_DATA.clear(); + } + + @Override + public void onPipeConnectionsUpdate() { + NET_DATA.clear(); + } + + @Override + protected void transferNodeData(Map> transferredNodes, + PipeNet parentNet) { + super.transferNodeData(transferredNodes, parentNet); + NET_DATA.clear(); + ((DuctPipeNet) parentNet).NET_DATA.clear(); + } + + @Override + protected void writeNodeData(DuctPipeProperties nodeData, CompoundTag tagCompound) { + tagCompound.putFloat("Rate", nodeData.getTransferRate()); + } + + @Override + protected DuctPipeProperties readNodeData(CompoundTag tagCompound) { + return new DuctPipeProperties(tagCompound.getFloat("Rate")); + } +} diff --git a/src/main/java/com/gregtechceu/gtceu/common/pipelike/duct/DuctPipeProperties.java b/src/main/java/com/gregtechceu/gtceu/common/pipelike/duct/DuctPipeProperties.java new file mode 100644 index 0000000000..2812f1b832 --- /dev/null +++ b/src/main/java/com/gregtechceu/gtceu/common/pipelike/duct/DuctPipeProperties.java @@ -0,0 +1,47 @@ +package com.gregtechceu.gtceu.common.pipelike.duct; + +import lombok.Getter; +import lombok.Setter; + +import java.util.Objects; + +public class DuctPipeProperties { + + /** + * rate in stacks per sec + */ + @Getter + @Setter + private float transferRate; + + public DuctPipeProperties(float transferRate) { + this.transferRate = transferRate; + } + + /** + * Default property constructor. + */ + public DuctPipeProperties() { + this(0.25f); + } + + @Override + public boolean equals(Object o) { + if (this == o) return true; + if (o == null || getClass() != o.getClass()) return false; + DuctPipeProperties that = (DuctPipeProperties) o; + return Float.compare(that.transferRate, transferRate) == 0; + } + + @Override + public int hashCode() { + return Objects.hash(transferRate); + } + + @Override + public String toString() { + return "DuctPipeProperties{" + + "transferRate=" + transferRate + + '}'; + } +} diff --git a/src/main/java/com/gregtechceu/gtceu/common/pipelike/duct/DuctPipeType.java b/src/main/java/com/gregtechceu/gtceu/common/pipelike/duct/DuctPipeType.java new file mode 100644 index 0000000000..e05d0292b8 --- /dev/null +++ b/src/main/java/com/gregtechceu/gtceu/common/pipelike/duct/DuctPipeType.java @@ -0,0 +1,63 @@ +package com.gregtechceu.gtceu.common.pipelike.duct; + +import com.gregtechceu.gtceu.GTCEu; +import com.gregtechceu.gtceu.api.pipenet.IPipeType; +import com.gregtechceu.gtceu.client.model.PipeModel; + +import net.minecraft.resources.ResourceLocation; +import net.minecraft.util.StringRepresentable; + +import lombok.Getter; + +import java.util.Locale; + +public enum DuctPipeType implements IPipeType, StringRepresentable { + + SMALL("small", 0.375f, 0.5f), + NORMAL("normal", 0.5f, 1f), + LARGE("large", 0.75f, 2f), + HUGE("huge", 0.875f, 4f), + ; + + public static final ResourceLocation TYPE_ID = GTCEu.id("duct"); + public static final DuctPipeType[] VALUES = values(); + + @Getter + public final String name; + @Getter + private final float thickness; + @Getter + private final float rateMultiplier; + + DuctPipeType(String name, float thickness, float rateMultiplier) { + this.name = name; + this.thickness = thickness; + this.rateMultiplier = rateMultiplier; + } + + @Override + public DuctPipeProperties modifyProperties(DuctPipeProperties baseProperties) { + return baseProperties; + } + + @Override + public boolean isPaintable() { + return true; + } + + @Override + public ResourceLocation type() { + return TYPE_ID; + } + + @Override + public String getSerializedName() { + return name().toLowerCase(Locale.ROOT); + } + + public PipeModel createPipeModel() { + return new PipeModel(thickness, () -> GTCEu.id("block/pipe/pipe_duct_side"), + () -> GTCEu.id("block/pipe/pipe_duct_in"), + null, null); + } +} diff --git a/src/main/java/com/gregtechceu/gtceu/common/pipelike/duct/DuctRoutePath.java b/src/main/java/com/gregtechceu/gtceu/common/pipelike/duct/DuctRoutePath.java new file mode 100644 index 0000000000..8488e7e589 --- /dev/null +++ b/src/main/java/com/gregtechceu/gtceu/common/pipelike/duct/DuctRoutePath.java @@ -0,0 +1,51 @@ +package com.gregtechceu.gtceu.common.pipelike.duct; + +import com.gregtechceu.gtceu.api.capability.GTCapabilityHelper; +import com.gregtechceu.gtceu.api.capability.IHazardParticleContainer; +import com.gregtechceu.gtceu.api.pipenet.IRoutePath; +import com.gregtechceu.gtceu.common.blockentity.DuctPipeBlockEntity; +import com.gregtechceu.gtceu.utils.FacingPos; + +import net.minecraft.core.BlockPos; +import net.minecraft.core.Direction; +import net.minecraft.world.level.Level; + +import lombok.Getter; +import org.jetbrains.annotations.NotNull; +import org.jetbrains.annotations.Nullable; + +public class DuctRoutePath implements IRoutePath { + + @Getter + private final DuctPipeBlockEntity targetPipe; + @NotNull + @Getter + private final Direction targetFacing; + @Getter + private final int distance; + @Getter + private final DuctPipeProperties properties; + + public DuctRoutePath(DuctPipeBlockEntity targetPipe, @NotNull Direction facing, int distance, + DuctPipeProperties properties) { + this.targetPipe = targetPipe; + this.targetFacing = facing; + this.distance = distance; + this.properties = properties; + } + + @Override + public @NotNull BlockPos getTargetPipePos() { + return targetPipe.getPipePos(); + } + + @Override + public @Nullable IHazardParticleContainer getHandler(Level world) { + return GTCapabilityHelper.getHazardContainer(world, getTargetPipePos().relative(targetFacing), + targetFacing.getOpposite()); + } + + public FacingPos toFacingPos() { + return new FacingPos(getTargetPipePos(), targetFacing); + } +} diff --git a/src/main/java/com/gregtechceu/gtceu/common/pipelike/duct/LevelDuctPipeNet.java b/src/main/java/com/gregtechceu/gtceu/common/pipelike/duct/LevelDuctPipeNet.java new file mode 100644 index 0000000000..ab88dab06a --- /dev/null +++ b/src/main/java/com/gregtechceu/gtceu/common/pipelike/duct/LevelDuctPipeNet.java @@ -0,0 +1,29 @@ +package com.gregtechceu.gtceu.common.pipelike.duct; + +import com.gregtechceu.gtceu.api.pipenet.LevelPipeNet; + +import net.minecraft.nbt.CompoundTag; +import net.minecraft.server.level.ServerLevel; + +public class LevelDuctPipeNet extends LevelPipeNet { + + private static final String DATA_ID = "gtceu_duct_pipe_net"; + + public static LevelDuctPipeNet getOrCreate(ServerLevel serverLevel) { + return serverLevel.getDataStorage().computeIfAbsent(tag -> new LevelDuctPipeNet(serverLevel, tag), + () -> new LevelDuctPipeNet(serverLevel), DATA_ID); + } + + public LevelDuctPipeNet(ServerLevel serverLevel) { + super(serverLevel); + } + + public LevelDuctPipeNet(ServerLevel serverLevel, CompoundTag tag) { + super(serverLevel, tag); + } + + @Override + protected DuctPipeNet createNetInstance() { + return new DuctPipeNet(this); + } +} diff --git a/src/main/java/com/gregtechceu/gtceu/common/recipe/EnvironmentalHazardCondition.java b/src/main/java/com/gregtechceu/gtceu/common/recipe/EnvironmentalHazardCondition.java new file mode 100644 index 0000000000..427ee1ed44 --- /dev/null +++ b/src/main/java/com/gregtechceu/gtceu/common/recipe/EnvironmentalHazardCondition.java @@ -0,0 +1,86 @@ +package com.gregtechceu.gtceu.common.recipe; + +import com.gregtechceu.gtceu.api.data.medicalcondition.MedicalCondition; +import com.gregtechceu.gtceu.api.machine.trait.RecipeLogic; +import com.gregtechceu.gtceu.api.recipe.GTRecipe; +import com.gregtechceu.gtceu.api.recipe.RecipeCondition; +import com.gregtechceu.gtceu.common.capability.EnvironmentalHazardSavedData; +import com.gregtechceu.gtceu.common.data.GTMedicalConditions; + +import net.minecraft.network.FriendlyByteBuf; +import net.minecraft.network.chat.Component; +import net.minecraft.server.level.ServerLevel; +import net.minecraft.util.GsonHelper; + +import com.google.gson.JsonObject; +import lombok.AllArgsConstructor; +import lombok.Getter; +import lombok.NoArgsConstructor; +import org.jetbrains.annotations.NotNull; + +@NoArgsConstructor +@AllArgsConstructor +public class EnvironmentalHazardCondition extends RecipeCondition { + + public final static EnvironmentalHazardCondition INSTANCE = new EnvironmentalHazardCondition(); + + @Getter + private MedicalCondition condition = GTMedicalConditions.CARBON_MONOXIDE_POISONING; + + @Override + public String getType() { + return "environmental_hazard"; + } + + @Override + public Component getTooltips() { + return isReverse ? + Component.translatable("gtceu.recipe.environmental_hazard.reverse", + Component.translatable("gtceu.medical_condition." + condition.name)) : + Component.translatable("gtceu.recipe.environmental_hazard", + Component.translatable("gtceu.medical_condition." + condition.name)); + } + + @Override + public boolean test(@NotNull GTRecipe recipe, @NotNull RecipeLogic recipeLogic) { + if (!(recipeLogic.getMachine().getLevel() instanceof ServerLevel serverLevel)) { + return false; + } + EnvironmentalHazardSavedData savedData = EnvironmentalHazardSavedData.getOrCreate(serverLevel); + var zone = savedData.getZoneByContainedPos(recipeLogic.getMachine().getPos()); + return zone != null && zone.strength() > 0; + } + + @NotNull + @Override + public JsonObject serialize() { + JsonObject value = super.serialize(); + value.addProperty("condition", condition.name); + return value; + } + + @Override + public RecipeCondition deserialize(@NotNull JsonObject config) { + super.deserialize(config); + this.condition = MedicalCondition.CONDITIONS.get(GsonHelper.getAsString(config, "condition")); + return this; + } + + @Override + public void toNetwork(FriendlyByteBuf buf) { + super.toNetwork(buf); + buf.writeUtf(this.condition.name); + } + + @Override + public RecipeCondition fromNetwork(FriendlyByteBuf buf) { + super.fromNetwork(buf); + this.condition = MedicalCondition.CONDITIONS.get(buf.readUtf()); + return this; + } + + @Override + public RecipeCondition createTemplate() { + return new EnvironmentalHazardCondition(); + } +} diff --git a/src/main/java/com/gregtechceu/gtceu/config/ConfigHolder.java b/src/main/java/com/gregtechceu/gtceu/config/ConfigHolder.java index e9118756e7..3ee4a5ad68 100644 --- a/src/main/java/com/gregtechceu/gtceu/config/ConfigHolder.java +++ b/src/main/java/com/gregtechceu/gtceu/config/ConfigHolder.java @@ -462,6 +462,10 @@ public static class GameplayConfigs { "true = all, false = GT only.", "Default: true" }) public boolean universalHazards = true; @Configurable + @Configurable.Comment({ "Whether environmental hazards like pollution or radiation are active", + "Default: true" }) + public boolean environmentalHazards = true; + @Configurable @Configurable.Comment({ "Whether the GTCEu's ingame guidebook, 'Compass', be enabled.", "WARNING: INCOMPLETE", "Default: false" }) public boolean enableCompass = false; diff --git a/src/main/java/com/gregtechceu/gtceu/core/mixins/EntityMixin.java b/src/main/java/com/gregtechceu/gtceu/core/mixins/EntityMixin.java index d068c1e940..08113337fa 100644 --- a/src/main/java/com/gregtechceu/gtceu/core/mixins/EntityMixin.java +++ b/src/main/java/com/gregtechceu/gtceu/core/mixins/EntityMixin.java @@ -1,7 +1,7 @@ package com.gregtechceu.gtceu.core.mixins; import com.gregtechceu.gtceu.api.capability.GTCapabilityHelper; -import com.gregtechceu.gtceu.api.capability.IHazardEffectTracker; +import com.gregtechceu.gtceu.api.capability.IMedicalConditionTracker; import com.gregtechceu.gtceu.core.IFireImmuneEntity; import net.minecraft.world.entity.Entity; @@ -48,7 +48,7 @@ public abstract class EntityMixin implements IFireImmuneEntity { if (!gtceu$isEntityInit) { return original; } - IHazardEffectTracker tracker = GTCapabilityHelper.getHazardEffectTracker((Entity) (Object) this); + IMedicalConditionTracker tracker = GTCapabilityHelper.getMedicalConditionTracker((Entity) (Object) this); if (tracker != null && tracker.getMaxAirSupply() != -1) { return tracker.getMaxAirSupply(); } diff --git a/src/main/java/com/gregtechceu/gtceu/data/lang/LangHandler.java b/src/main/java/com/gregtechceu/gtceu/data/lang/LangHandler.java index b8294b9200..0f13da0bb9 100644 --- a/src/main/java/com/gregtechceu/gtceu/data/lang/LangHandler.java +++ b/src/main/java/com/gregtechceu/gtceu/data/lang/LangHandler.java @@ -119,19 +119,31 @@ public static void init(RegistrateLangProvider provider) { provider.add("gtceu.tool.class.shears", "Shears"); provider.add("gtceu.tool.class.drill", "Drill"); - provider.add("gtceu.hazard.description", "§l§cHAZARDOUS §7Hold Shift to show details"); - provider.add("gtceu.hazard.description_shift", "§l§cHAZARDOUS:"); - provider.add("gtceu.hazard.contact_poison", "§5Contact Poison"); - provider.add("gtceu.hazard.inhalation_poison", "§2Poisonous when inhaled"); - provider.add("gtceu.hazard.corrosive", "§6Corrosive"); - provider.add("gtceu.hazard.radioactive", "§eRadioactive"); - provider.add("gtceu.hazard.none", "§2Not Dangerous"); - provider.add("gtceu.hazard.antidote.description", "§aAntidote §7Hold Shift to show details"); - provider.add("gtceu.hazard.antidote.description_shift", "§aCures types:"); - provider.add("gtceu.hazard.antidote.description.effect_removed", - "Removes %s%% of current ailments' effects"); - provider.add("gtceu.hazard.antidote.description.effect_removed.all", - "Removes all of current ailments' effects"); + provider.add("command.gtceu.medical_condition.get", "Player %s has these medical conditions:"); + provider.add("command.gtceu.medical_condition.get.empty", "Player %s has no medical conditions."); + provider.add("command.gtceu.medical_condition.get.element", "Condition %s§r: %s seconds"); + provider.add("command.gtceu.medical_condition.get.element.permanent", "Condition %s§r: %s seconds (permanent)"); + provider.add("gtceu.medical_condition.description", "§l§cHAZARDOUS §7Hold Shift to show details"); + provider.add("gtceu.medical_condition.description_shift", "§l§cHAZARDOUS:"); + provider.add("gtceu.medical_condition.chemical_burns", "§5Chemical burns"); + provider.add("gtceu.medical_condition.poison", "§2Poisonous"); + provider.add("gtceu.medical_condition.weak_poison", "§aWeakly poisonous"); + provider.add("gtceu.medical_condition.irritant", "§6Irritant"); + provider.add("gtceu.medical_condition.nausea", "§3Nauseating"); + provider.add("gtceu.medical_condition.carcinogen", "§eCarcinogenic"); + provider.add("gtceu.medical_condition.asbestosis", "§dAsbestosis"); + provider.add("gtceu.medical_condition.arsenicosis", "§bArsenicosis"); + provider.add("gtceu.medical_condition.silicosis", "§1Silicosis"); + provider.add("gtceu.medical_condition.berylliosis", "§5Berylliosis"); + provider.add("gtceu.medical_condition.methanol_poisoning", "§6Methanol Poisoning"); + provider.add("gtceu.medical_condition.carbon_monoxide_poisoning", "§7Carbon Monoxide Poisoning"); + provider.add("gtceu.medical_condition.none", "§2Not Dangerous"); + provider.add("gtceu.medical_condition.antidote.description", "§aAntidote §7Hold Shift to show details"); + provider.add("gtceu.medical_condition.antidote.description_shift", "§aCures these conditions:"); + provider.add("gtceu.medical_condition.antidote.description.effect_removed", + "Removes %s%% of current conditions' effects"); + provider.add("gtceu.medical_condition.antidote.description.effect_removed.all", + "Removes all of current conditions' effects"); provider.add("item.gtceu.tool.replace_tool_head", "Craft with a new Tool Head to replace it"); provider.add("item.gtceu.tool.usable_as", "§8Usable as: §f%s"); @@ -713,6 +725,11 @@ public static void init(RegistrateLangProvider provider) { provider.add("behavior.portable_scanner.bedrock_fluid.amount", "Fluid In Deposit: %s %s - %s%%"); provider.add("behavior.portable_scanner.bedrock_fluid.amount_unknown", "Fluid In Deposit: %s%%"); provider.add("behavior.portable_scanner.bedrock_fluid.nothing", "Fluid In Deposit: §6Nothing§r"); + provider.add("behavior.portable_scanner.environmental_hazard", "Environmental Hazard In Chunk: %s§r - %s ppm"); + provider.add("behavior.portable_scanner.environmental_hazard.nothing", + "Environmental Hazard In Chunk: §6Nothing§r"); + provider.add("behavior.portable_scanner.local_hazard", "Local Hazard In Chunk: %s§r - %s ppm"); + provider.add("behavior.portable_scanner.local_hazard.nothing", "Local Hazard In Chunk: §6Nothing§r"); provider.add("behavior.portable_scanner.block_hardness", "Hardness: %s Blast Resistance: %s"); provider.add("behavior.portable_scanner.block_name", "Name: %s MetaData: %s"); provider.add("behavior.portable_scanner.debug_cpu_load", @@ -875,6 +892,8 @@ public static void init(RegistrateLangProvider provider) { provider.add("gtceu.recipe.eu_to_start", "Energy To Start: %sEU"); provider.add("gtceu.recipe.dimensions", "Dimensions: %s"); provider.add("gtceu.recipe.cleanroom", "Requires %s"); + provider.add("gtceu.recipe.environmental_hazard.reverse", "Area must be free of %s"); + provider.add("gtceu.recipe.environmental_hazard", "Area must have %s"); provider.add("gtceu.recipe.cleanroom.display_name", "Cleanroom"); provider.add("gtceu.recipe.cleanroom_sterile.display_name", "Sterile Cleanroom"); provider.add("gtceu.recipe.research", "Requires Research"); diff --git a/src/main/java/com/gregtechceu/gtceu/data/lang/ToolLang.java b/src/main/java/com/gregtechceu/gtceu/data/lang/ToolLang.java index e1c31ee892..6b0d8527c1 100644 --- a/src/main/java/com/gregtechceu/gtceu/data/lang/ToolLang.java +++ b/src/main/java/com/gregtechceu/gtceu/data/lang/ToolLang.java @@ -47,6 +47,23 @@ private static void initDeathMessages(RegistrateLangProvider provider) { provider.add("death.attack.gtceu.wrench_iv", "%s had a Monkey Wrench thrown into their plans by %s"); provider.add("death.attack.gtceu.buzzsaw", "%s got buzzed by %s"); provider.add("death.attack.gtceu.screwdriver_lv", "%s had their screws removed by %s"); + + provider.add("death.attack.gtceu.medical_condition/asbestosis", "%s got mesothelioma"); + provider.add("death.attack.gtceu.medical_condition/chemical_burns", "%s had a chemical accident"); + provider.add("death.attack.gtceu.medical_condition/poison", + "%s forgot that poisonous materials are, in fact, poisonous"); + provider.add("death.attack.gtceu.medical_condition/silicosis", + "%s didn't die of tuberculosis. it was silicosis."); + provider.add("death.attack.gtceu.medical_condition/arsenicosis", "%s got arsenic poisoning"); + provider.add("death.attack.gtceu.medical_condition/berylliosis", "%s mined emeralds a bit too greedily"); + provider.add("death.attack.gtceu.medical_condition/carcinogen", "%s got leukemia"); + provider.add("death.attack.gtceu.medical_condition/irritant", "%s got a §n§lREALLY§r bad rash"); + provider.add("death.attack.gtceu.medical_condition/methanol_poisoning", + "%s tried to drink moonshine during the prohibition"); + provider.add("death.attack.gtceu.medical_condition/nausea", "%s died of nausea"); + provider.add("death.attack.gtceu.medical_condition/none", "%s died of... nothing?"); + provider.add("death.attack.gtceu.medical_condition/weak_poison", "%s ate lead (or mercury!)"); + provider.add("death.attack.gtceu.medical_condition/carbon_monoxide_poisoning", "%s left the stove on"); } private static void initToolInfo(RegistrateLangProvider provider) {} diff --git a/src/main/java/com/gregtechceu/gtceu/data/recipe/builder/GTRecipeBuilder.java b/src/main/java/com/gregtechceu/gtceu/data/recipe/builder/GTRecipeBuilder.java index c3fb2014ff..99690b2c92 100644 --- a/src/main/java/com/gregtechceu/gtceu/data/recipe/builder/GTRecipeBuilder.java +++ b/src/main/java/com/gregtechceu/gtceu/data/recipe/builder/GTRecipeBuilder.java @@ -5,6 +5,7 @@ import com.gregtechceu.gtceu.api.data.chemical.ChemicalHelper; import com.gregtechceu.gtceu.api.data.chemical.material.Material; import com.gregtechceu.gtceu.api.data.chemical.material.stack.UnificationEntry; +import com.gregtechceu.gtceu.api.data.medicalcondition.MedicalCondition; import com.gregtechceu.gtceu.api.data.tag.TagPrefix; import com.gregtechceu.gtceu.api.data.tag.TagUtil; import com.gregtechceu.gtceu.api.item.component.IDataItem; @@ -646,6 +647,14 @@ public GTRecipeBuilder rpm(float rpm) { return rpm(rpm, false); } + public GTRecipeBuilder environmentalHazard(MedicalCondition condition, boolean reverse) { + return addCondition(new EnvironmentalHazardCondition(condition).setReverse(reverse)); + } + + public GTRecipeBuilder environmentalHazard(MedicalCondition condition) { + return environmentalHazard(condition, false); + } + private boolean applyResearchProperty(ResearchData.ResearchEntry researchEntry) { if (!ConfigHolder.INSTANCE.machines.enableResearch) return false; if (researchEntry == null) { diff --git a/src/main/java/com/gregtechceu/gtceu/data/recipe/generated/PipeRecipeHandler.java b/src/main/java/com/gregtechceu/gtceu/data/recipe/generated/PipeRecipeHandler.java index 3c16f7fe33..f2af6bd781 100644 --- a/src/main/java/com/gregtechceu/gtceu/data/recipe/generated/PipeRecipeHandler.java +++ b/src/main/java/com/gregtechceu/gtceu/data/recipe/generated/PipeRecipeHandler.java @@ -8,7 +8,9 @@ import com.gregtechceu.gtceu.api.data.chemical.material.properties.PropertyKey; import com.gregtechceu.gtceu.api.data.chemical.material.stack.UnificationEntry; import com.gregtechceu.gtceu.api.data.tag.TagPrefix; +import com.gregtechceu.gtceu.common.data.GTBlocks; import com.gregtechceu.gtceu.common.data.GTItems; +import com.gregtechceu.gtceu.common.pipelike.duct.DuctPipeType; import com.gregtechceu.gtceu.data.recipe.VanillaRecipeHelper; import com.gregtechceu.gtceu.utils.FormattingUtil; import com.gregtechceu.gtceu.utils.GTUtil; @@ -21,7 +23,7 @@ import static com.gregtechceu.gtceu.api.GTValues.*; import static com.gregtechceu.gtceu.api.data.chemical.material.info.MaterialFlags.NO_SMASHING; import static com.gregtechceu.gtceu.api.data.tag.TagPrefix.*; -import static com.gregtechceu.gtceu.common.data.GTMaterials.Iron; +import static com.gregtechceu.gtceu.common.data.GTMaterials.*; import static com.gregtechceu.gtceu.common.data.GTRecipeTypes.*; public class PipeRecipeHandler { @@ -46,6 +48,10 @@ public static void init(Consumer provider) { PipeRecipeHandler::processRestrictivePipe); pipeLargeRestrictive.executeHandler(provider, PropertyKey.ITEM_PIPE, PipeRecipeHandler::processRestrictivePipe); pipeHugeRestrictive.executeHandler(provider, PropertyKey.ITEM_PIPE, PipeRecipeHandler::processRestrictivePipe); + + addDuctRecipes(provider, Steel, 2); + addDuctRecipes(provider, StainlessSteel, 4); + addDuctRecipes(provider, TungstenSteel, 8); } private static void processRestrictivePipe(TagPrefix pipePrefix, Material material, ItemPipeProperties property, @@ -242,6 +248,21 @@ private static void processPipeNonuple(TagPrefix pipePrefix, Material material, .save(provider); } + private static void addDuctRecipes(Consumer provider, Material material, int outputAmount) { + VanillaRecipeHelper.addShapedRecipe(provider, "small_duct_%s".formatted(material.getName()), + GTBlocks.DUCT_PIPES[DuctPipeType.SMALL.ordinal()].asStack(outputAmount * 2), "w", "X", "h", + 'X', new UnificationEntry(plate, material)); + VanillaRecipeHelper.addShapedRecipe(provider, "medium_duct_%s".formatted(material.getName()), + GTBlocks.DUCT_PIPES[DuctPipeType.NORMAL.ordinal()].asStack(outputAmount), " X ", "wXh", " X ", + 'X', new UnificationEntry(plate, material)); + VanillaRecipeHelper.addShapedRecipe(provider, "large_duct_%s".formatted(material.getName()), + GTBlocks.DUCT_PIPES[DuctPipeType.LARGE.ordinal()].asStack(outputAmount), "XwX", "X X", "XhX", + 'X', new UnificationEntry(plate, material)); + VanillaRecipeHelper.addShapedRecipe(provider, "huge_duct_%s".formatted(material.getName()), + GTBlocks.DUCT_PIPES[DuctPipeType.HUGE.ordinal()].asStack(outputAmount), "XwX", "X X", "XhX", + 'X', new UnificationEntry(plateDouble, material)); + } + private static int getVoltageMultiplier(Material material) { return material.getBlastTemperature() >= 2800 ? VA[LV] : VA[ULV]; } diff --git a/src/main/java/com/gregtechceu/gtceu/data/recipe/misc/MetaTileEntityLoader.java b/src/main/java/com/gregtechceu/gtceu/data/recipe/misc/MetaTileEntityLoader.java index feb25d0377..fd607926af 100644 --- a/src/main/java/com/gregtechceu/gtceu/data/recipe/misc/MetaTileEntityLoader.java +++ b/src/main/java/com/gregtechceu/gtceu/data/recipe/misc/MetaTileEntityLoader.java @@ -814,6 +814,8 @@ public static void init(Consumer provider) { CABLE, 'H', HULL, 'S', SENSOR); registerMachineRecipe(provider, GTMachines.GAS_COLLECTOR, "WFW", "PHP", "WCW", 'W', Blocks.IRON_BARS, 'F', GTItems.FLUID_FILTER, 'P', PUMP, 'H', HULL, 'C', CIRCUIT); + registerMachineRecipe(provider, GTMachines.AIR_SCRUBBER, "PFP", "FHF", "CFC", 'F', GTItems.FLUID_FILTER, + 'P', PUMP, 'H', HULL, 'C', CIRCUIT); registerMachineRecipe(provider, GTMachines.ROCK_CRUSHER, "PMW", "CHC", "GGG", 'P', PISTON, 'M', MOTOR, 'W', GRINDER, 'C', CABLE, 'H', HULL, 'G', GLASS); registerMachineRecipe(provider, GTMachines.PUMP, "WGW", "GMG", "TGT", 'M', HULL, 'W', CIRCUIT, 'G', PUMP, 'T', diff --git a/src/main/java/com/gregtechceu/gtceu/data/recipe/serialized/chemistry/AirScrubberRecipes.java b/src/main/java/com/gregtechceu/gtceu/data/recipe/serialized/chemistry/AirScrubberRecipes.java new file mode 100644 index 0000000000..84dd9adc14 --- /dev/null +++ b/src/main/java/com/gregtechceu/gtceu/data/recipe/serialized/chemistry/AirScrubberRecipes.java @@ -0,0 +1,102 @@ +package com.gregtechceu.gtceu.data.recipe.serialized.chemistry; + +import com.gregtechceu.gtceu.common.data.GTMedicalConditions; + +import net.minecraft.data.recipes.FinishedRecipe; + +import java.util.function.Consumer; + +import static com.gregtechceu.gtceu.api.GTValues.*; +import static com.gregtechceu.gtceu.api.data.tag.TagPrefix.*; +import static com.gregtechceu.gtceu.common.data.GTMaterials.*; +import static com.gregtechceu.gtceu.common.data.GTRecipeTypes.AIR_SCRUBBER_RECIPES; + +public class AirScrubberRecipes { + + public static void init(Consumer provider) { + AIR_SCRUBBER_RECIPES.recipeBuilder("chemical_burns") + .circuitMeta(1) + .inputFluids(Air.getFluid(10000)) + .outputFluids(DilutedHydrochloricAcid.getFluid(2000)) + .outputFluids(DilutedSulfuricAcid.getFluid(2000)) + .environmentalHazard(GTMedicalConditions.CHEMICAL_BURNS) + .duration(200).EUt(VHA[LV]).save(provider); + + AIR_SCRUBBER_RECIPES.recipeBuilder("poison") + .circuitMeta(2) + .inputFluids(Air.getFluid(10000)) + .outputFluids(SulfurTrioxide.getFluid(2000)) + .environmentalHazard(GTMedicalConditions.POISON) + .duration(200).EUt(VHA[LV]).save(provider); + + AIR_SCRUBBER_RECIPES.recipeBuilder("weak_poison") + .circuitMeta(3) + .inputFluids(Air.getFluid(10000)) + .outputFluids(NitricOxide.getFluid(2000)) + .environmentalHazard(GTMedicalConditions.WEAK_POISON) + .duration(200).EUt(VHA[LV]).save(provider); + + AIR_SCRUBBER_RECIPES.recipeBuilder("irritant") + .circuitMeta(4) + .inputFluids(Air.getFluid(10000)) + .outputItems(dust, DarkAsh, 8) + .environmentalHazard(GTMedicalConditions.IRRITANT) + .duration(200).EUt(VHA[LV]).save(provider); + + AIR_SCRUBBER_RECIPES.recipeBuilder("nausea") + .circuitMeta(5) + .inputFluids(Air.getFluid(10000)) + .outputFluids(CarbonMonoxide.getFluid(50)) + .environmentalHazard(GTMedicalConditions.NAUSEA) + .duration(200).EUt(VHA[LV]).save(provider); + + AIR_SCRUBBER_RECIPES.recipeBuilder("carcinogen") + .circuitMeta(6) + .inputFluids(Air.getFluid(10000)) + // TODO radioactive waste output + .environmentalHazard(GTMedicalConditions.CARCINOGEN) + .duration(200).EUt(VHA[LV]).save(provider); + + AIR_SCRUBBER_RECIPES.recipeBuilder("asbestosis") + .circuitMeta(7) + .inputFluids(Air.getFluid(10000)) + .outputItems(dust, Asbestos, 8) + .environmentalHazard(GTMedicalConditions.ASBESTOSIS) + .duration(200).EUt(VHA[LV]).save(provider); + + AIR_SCRUBBER_RECIPES.recipeBuilder("arsenicosis") + .circuitMeta(8) + .inputFluids(Air.getFluid(10000)) + .outputItems(dust, Arsenic, 8) + .environmentalHazard(GTMedicalConditions.ARSENICOSIS) + .duration(200).EUt(VHA[LV]).save(provider); + + AIR_SCRUBBER_RECIPES.recipeBuilder("silicosis") + .circuitMeta(9) + .inputFluids(Air.getFluid(10000)) + .outputItems(dust, SiliconDioxide, 8) + .environmentalHazard(GTMedicalConditions.SILICOSIS) + .duration(200).EUt(VHA[LV]).save(provider); + + AIR_SCRUBBER_RECIPES.recipeBuilder("berylliosis") + .circuitMeta(10) + .inputFluids(Air.getFluid(10000)) + .outputItems(dust, Beryllium, 8) + .environmentalHazard(GTMedicalConditions.BERYLLIOSIS) + .duration(200).EUt(VHA[LV]).save(provider); + + AIR_SCRUBBER_RECIPES.recipeBuilder("methanol_poisoning") + .circuitMeta(11) + .inputFluids(Air.getFluid(10000)) + .outputFluids(Methanol.getFluid(1000)) + .environmentalHazard(GTMedicalConditions.METHANOL_POISONING) + .duration(200).EUt(VHA[LV]).save(provider); + + AIR_SCRUBBER_RECIPES.recipeBuilder("carbon_monoxide_poisoning") + .circuitMeta(12) + .inputFluids(Air.getFluid(10000)) + .outputFluids(CarbonMonoxide.getFluid(1000)) + .environmentalHazard(GTMedicalConditions.CARBON_MONOXIDE_POISONING) + .duration(200).EUt(VHA[LV]).save(provider); + } +} diff --git a/src/main/java/com/gregtechceu/gtceu/data/recipe/serialized/chemistry/ChemistryRecipes.java b/src/main/java/com/gregtechceu/gtceu/data/recipe/serialized/chemistry/ChemistryRecipes.java index 701b29ead6..b5068986e7 100644 --- a/src/main/java/com/gregtechceu/gtceu/data/recipe/serialized/chemistry/ChemistryRecipes.java +++ b/src/main/java/com/gregtechceu/gtceu/data/recipe/serialized/chemistry/ChemistryRecipes.java @@ -35,6 +35,7 @@ public static void init(Consumer provider) { SeparationRecipes.init(provider); BrineRecipes.init(provider); AntidoteRecipes.init(provider); + AirScrubberRecipes.init(provider); // A Few Random Recipes FLUID_HEATER_RECIPES.recipeBuilder("ethenone") diff --git a/src/main/java/com/gregtechceu/gtceu/forge/ForgeCommonEventListener.java b/src/main/java/com/gregtechceu/gtceu/forge/ForgeCommonEventListener.java index ca31a7f86d..940e8ab8d6 100644 --- a/src/main/java/com/gregtechceu/gtceu/forge/ForgeCommonEventListener.java +++ b/src/main/java/com/gregtechceu/gtceu/forge/ForgeCommonEventListener.java @@ -5,11 +5,12 @@ import com.gregtechceu.gtceu.api.block.MaterialBlock; import com.gregtechceu.gtceu.api.block.MetaMachineBlock; import com.gregtechceu.gtceu.api.capability.GTCapabilityHelper; -import com.gregtechceu.gtceu.api.capability.IHazardEffectTracker; +import com.gregtechceu.gtceu.api.capability.IMedicalConditionTracker; import com.gregtechceu.gtceu.api.capability.forge.GTCapability; import com.gregtechceu.gtceu.api.capability.forge.compat.EUToFEProvider; import com.gregtechceu.gtceu.api.data.chemical.material.Material; import com.gregtechceu.gtceu.api.data.chemical.material.properties.HazardProperty; +import com.gregtechceu.gtceu.api.data.chemical.material.properties.PropertyKey; import com.gregtechceu.gtceu.api.data.tag.TagPrefix; import com.gregtechceu.gtceu.api.item.DrumMachineItem; import com.gregtechceu.gtceu.api.item.IComponentItem; @@ -17,7 +18,9 @@ import com.gregtechceu.gtceu.api.item.armor.ArmorComponentItem; import com.gregtechceu.gtceu.api.machine.feature.IInteractedMachine; import com.gregtechceu.gtceu.api.registry.GTRegistries; -import com.gregtechceu.gtceu.common.capability.HazardEffectTracker; +import com.gregtechceu.gtceu.common.capability.EnvironmentalHazardSavedData; +import com.gregtechceu.gtceu.common.capability.LocalizedHazardSavedData; +import com.gregtechceu.gtceu.common.capability.MedicalConditionTracker; import com.gregtechceu.gtceu.common.commands.ServerCommands; import com.gregtechceu.gtceu.common.data.GTBlocks; import com.gregtechceu.gtceu.common.data.GTItems; @@ -43,6 +46,7 @@ import net.minecraft.world.entity.Mob; import net.minecraft.world.entity.monster.Zombie; import net.minecraft.world.entity.player.Player; +import net.minecraft.world.item.ArmorItem; import net.minecraft.world.item.ItemStack; import net.minecraft.world.level.block.entity.BlockEntity; import net.minecraftforge.common.capabilities.Capability; @@ -113,8 +117,8 @@ public LazyOptional getCapability(@NotNull Capability cap, @Nullable D @SubscribeEvent public static void registerEntityCapabilities(AttachCapabilitiesEvent event) { if (event.getObject() instanceof Player entity) { - final HazardEffectTracker tracker = new HazardEffectTracker(entity); - event.addCapability(GTCEu.id("hazard_tracker"), new ICapabilitySerializable() { + final MedicalConditionTracker tracker = new MedicalConditionTracker(entity); + event.addCapability(GTCEu.id("medical_condition_tracker"), new ICapabilitySerializable() { @Override public CompoundTag serializeNBT() { @@ -129,7 +133,7 @@ public void deserializeNBT(CompoundTag arg) { @Override public @NotNull LazyOptional getCapability(@NotNull Capability capability, @Nullable Direction arg) { - return GTCapability.CAPABILITY_HAZARD_EFFECT_TRACKER.orEmpty(capability, + return GTCapability.CAPABILITY_MEDICAL_CONDITION_TRACKER.orEmpty(capability, LazyOptional.of(() -> tracker)); } }); @@ -147,19 +151,32 @@ public static void tickPlayerInventoryHazards(TickEvent.PlayerTickEvent event) { return; } Player player = event.player; - IHazardEffectTracker tracker = GTCapabilityHelper.getHazardEffectTracker(player); + IMedicalConditionTracker tracker = GTCapabilityHelper.getMedicalConditionTracker(player); IItemHandler inventory = player.getCapability(ForgeCapabilities.ITEM_HANDLER, null).resolve().orElse(null); - if (tracker != null && inventory != null) { - tracker.startTick(); - for (int i = 0; i < inventory.getSlots(); ++i) { - ItemStack stack = inventory.getStackInSlot(i); - Material material = HazardProperty.getValidHazardMaterial(stack); - if (material == null) { - continue; + if (tracker == null || inventory == null) { + return; + } + tracker.tick(); + + for (int i = 0; i < inventory.getSlots(); ++i) { + ItemStack stack = inventory.getStackInSlot(i); + Material material = HazardProperty.getValidHazardMaterial(stack); + if (material == null || !material.hasProperty(PropertyKey.HAZARD)) { + continue; + } + HazardProperty property = material.getProperty(PropertyKey.HAZARD); + if (property.hazardTrigger.protectionType().isProtected(player)) { + // entity has proper safety equipment, so damage it per material every 5 seconds. + if (player.level().getGameTime() % 100 == 0) { + for (ArmorItem.Type type : property.hazardTrigger.protectionType().getEquipmentTypes()) { + player.getItemBySlot(type.getSlot()).hurtAndBreak(1, player, + p -> p.broadcastBreakEvent(type.getSlot())); + } } - tracker.tick(material); + // don't progress this material condition if entity is protected + continue; } - tracker.endTick(); + tracker.progressRelatedCondition(material); } } @@ -191,6 +208,8 @@ public static void registerReloadListeners(AddReloadListenerEvent event) { public static void levelTick(TickEvent.LevelTickEvent event) { if (event.phase == TickEvent.Phase.END && event.level instanceof ServerLevel serverLevel) { TaskHandler.onTickUpdate(serverLevel); + EnvironmentalHazardSavedData.getOrCreate(serverLevel).tick(); + LocalizedHazardSavedData.getOrCreate(serverLevel).tick(); } } diff --git a/src/main/java/com/gregtechceu/gtceu/integration/kjs/GregTechKubeJSPlugin.java b/src/main/java/com/gregtechceu/gtceu/integration/kjs/GregTechKubeJSPlugin.java index d672103a44..4d3da42fb6 100644 --- a/src/main/java/com/gregtechceu/gtceu/integration/kjs/GregTechKubeJSPlugin.java +++ b/src/main/java/com/gregtechceu/gtceu/integration/kjs/GregTechKubeJSPlugin.java @@ -16,6 +16,8 @@ import com.gregtechceu.gtceu.api.data.chemical.material.properties.ToolProperty; import com.gregtechceu.gtceu.api.data.chemical.material.stack.MaterialStack; import com.gregtechceu.gtceu.api.data.chemical.material.stack.UnificationEntry; +import com.gregtechceu.gtceu.api.data.medicalcondition.MedicalCondition; +import com.gregtechceu.gtceu.api.data.medicalcondition.Symptom; import com.gregtechceu.gtceu.api.data.tag.TagPrefix; import com.gregtechceu.gtceu.api.data.worldgen.*; import com.gregtechceu.gtceu.api.data.worldgen.generator.IndicatorGenerator; @@ -194,6 +196,7 @@ public void registerBindings(BindingsEvent event) { event.add("GCyMMachines", GCyMMachines.class); event.add("GTItems", GTItems.class); event.add("GTRecipeTypes", GTRecipeTypes.class); + event.add("GTMedicalConditions", GTMedicalConditions.class); event.add("TagPrefix", TagPrefix.class); event.add("ItemGenerationCondition", TagPrefix.Conditions.class); event.add("UnificationEntry", UnificationEntry.class); @@ -205,6 +208,8 @@ public void registerBindings(BindingsEvent event) { event.add("PropertyKey", PropertyKey.class); event.add("ToolProperty", ToolProperty.class); event.add("HazardProperty", HazardProperty.class); + event.add("MedicalCondition", MedicalCondition.class); + event.add("Symptom", Symptom.class); event.add("CleanroomType", CleanroomType.class); event.add("ChemicalHelper", ChemicalHelper.class); @@ -344,6 +349,11 @@ public void registerTypeWrappers(ScriptType type, TypeWrappers typeWrappers) { if (o instanceof CharSequence str) return IndicatorPlacement.getByName(str.toString()); return null; }); + typeWrappers.register(MedicalCondition.class, (ctx, o) -> { + if (o instanceof MedicalCondition condition) return condition; + if (o instanceof CharSequence str) return MedicalCondition.CONDITIONS.get(str.toString()); + return null; + }); // jank because Rhino doesn't agree that it's an interface typeWrappers.register(IWorldGenLayer.RuleTestSupplier.class, (ctx, o) -> { if (o instanceof IWorldGenLayer.RuleTestSupplier supplier) return supplier; diff --git a/src/main/java/com/gregtechceu/gtceu/integration/kjs/recipe/GTRecipeSchema.java b/src/main/java/com/gregtechceu/gtceu/integration/kjs/recipe/GTRecipeSchema.java index bf266f974d..11afaec294 100644 --- a/src/main/java/com/gregtechceu/gtceu/integration/kjs/recipe/GTRecipeSchema.java +++ b/src/main/java/com/gregtechceu/gtceu/integration/kjs/recipe/GTRecipeSchema.java @@ -5,6 +5,7 @@ import com.gregtechceu.gtceu.api.data.chemical.ChemicalHelper; import com.gregtechceu.gtceu.api.data.chemical.material.Material; import com.gregtechceu.gtceu.api.data.chemical.material.stack.UnificationEntry; +import com.gregtechceu.gtceu.api.data.medicalcondition.MedicalCondition; import com.gregtechceu.gtceu.api.data.tag.TagPrefix; import com.gregtechceu.gtceu.api.item.component.IDataItem; import com.gregtechceu.gtceu.api.machine.MachineDefinition; @@ -545,6 +546,14 @@ public GTRecipeJS rpm(float rpm) { return rpm(rpm, false); } + public GTRecipeJS environmentalHazard(MedicalCondition condition, boolean reverse) { + return addCondition(new EnvironmentalHazardCondition(condition).setReverse(reverse)); + } + + public GTRecipeJS environmentalHazard(MedicalCondition condition) { + return environmentalHazard(condition, false); + } + private boolean applyResearchProperty(ResearchData.ResearchEntry researchEntry) { if (!ConfigHolder.INSTANCE.machines.enableResearch) return false; if (researchEntry == null) { diff --git a/src/main/java/com/gregtechceu/gtceu/utils/BreadthFirstBlockSearch.java b/src/main/java/com/gregtechceu/gtceu/utils/BreadthFirstBlockSearch.java new file mode 100644 index 0000000000..72da4af1c0 --- /dev/null +++ b/src/main/java/com/gregtechceu/gtceu/utils/BreadthFirstBlockSearch.java @@ -0,0 +1,46 @@ +package com.gregtechceu.gtceu.utils; + +import net.minecraft.core.BlockPos; +import net.minecraft.core.Direction; + +import java.util.*; +import java.util.function.Predicate; + +public class BreadthFirstBlockSearch { + + public static Set search(Predicate value, BlockPos start, int limit) { + Set alreadyVisited = new HashSet<>(); + Set valid = new HashSet<>(); + int iteration = 0; + + Queue queue = new ArrayDeque<>(); + queue.add(start); + + BlockPos currentNode; + + while (!queue.isEmpty()) { + currentNode = queue.remove(); + + if (value.test(currentNode)) { + if (limit < iteration++) { + break; + } + valid.add(currentNode); + } else { + alreadyVisited.add(currentNode); + queue.addAll(getNeighbors(currentNode)); + queue.removeAll(alreadyVisited); + } + } + + return valid; + } + + public static Collection getNeighbors(BlockPos pos) { + Set neighbors = new HashSet<>(); + for (Direction dir : GTUtil.DIRECTIONS) { + neighbors.add(pos.relative(dir)); + } + return neighbors; + } +} diff --git a/src/main/java/com/gregtechceu/gtceu/utils/GTUtil.java b/src/main/java/com/gregtechceu/gtceu/utils/GTUtil.java index 3efaf680bb..0d93adbdf3 100644 --- a/src/main/java/com/gregtechceu/gtceu/utils/GTUtil.java +++ b/src/main/java/com/gregtechceu/gtceu/utils/GTUtil.java @@ -423,11 +423,11 @@ public static void appendHazardTooltips(Material material, List toolt if (!ConfigHolder.INSTANCE.gameplay.hazardsEnabled || !material.hasProperty(HAZARD)) return; if (GTUtil.isShiftDown()) { - tooltipComponents.add(Component.translatable("gtceu.hazard.description_shift")); + tooltipComponents.add(Component.translatable("gtceu.medical_condition.description_shift")); tooltipComponents.add(Component - .translatable("gtceu.hazard." + material.getProperty(HAZARD).getHazardType().name().toLowerCase())); + .translatable("gtceu.medical_condition." + material.getProperty(HAZARD).condition.name)); return; } - tooltipComponents.add(Component.translatable("gtceu.hazard.description")); + tooltipComponents.add(Component.translatable("gtceu.medical_condition.description")); } } diff --git a/src/main/resources/assets/gtceu/textures/block/machines/air_scrubber/overlay_back.png b/src/main/resources/assets/gtceu/textures/block/machines/air_scrubber/overlay_back.png new file mode 100644 index 0000000000..0f45a3e2d6 Binary files /dev/null and b/src/main/resources/assets/gtceu/textures/block/machines/air_scrubber/overlay_back.png differ diff --git a/src/main/resources/assets/gtceu/textures/block/machines/air_scrubber/overlay_back_active.png b/src/main/resources/assets/gtceu/textures/block/machines/air_scrubber/overlay_back_active.png new file mode 100644 index 0000000000..04b7be74d1 Binary files /dev/null and b/src/main/resources/assets/gtceu/textures/block/machines/air_scrubber/overlay_back_active.png differ diff --git a/src/main/resources/assets/gtceu/textures/block/machines/air_scrubber/overlay_back_active_emissive.png b/src/main/resources/assets/gtceu/textures/block/machines/air_scrubber/overlay_back_active_emissive.png new file mode 100644 index 0000000000..c20a1c9810 Binary files /dev/null and b/src/main/resources/assets/gtceu/textures/block/machines/air_scrubber/overlay_back_active_emissive.png differ diff --git a/src/main/resources/assets/gtceu/textures/block/machines/air_scrubber/overlay_back_emissive.png b/src/main/resources/assets/gtceu/textures/block/machines/air_scrubber/overlay_back_emissive.png new file mode 100644 index 0000000000..c20a1c9810 Binary files /dev/null and b/src/main/resources/assets/gtceu/textures/block/machines/air_scrubber/overlay_back_emissive.png differ diff --git a/src/main/resources/assets/gtceu/textures/block/machines/air_scrubber/overlay_bottom.png b/src/main/resources/assets/gtceu/textures/block/machines/air_scrubber/overlay_bottom.png new file mode 100644 index 0000000000..6626c95c96 Binary files /dev/null and b/src/main/resources/assets/gtceu/textures/block/machines/air_scrubber/overlay_bottom.png differ diff --git a/src/main/resources/assets/gtceu/textures/block/machines/air_scrubber/overlay_bottom_active.png b/src/main/resources/assets/gtceu/textures/block/machines/air_scrubber/overlay_bottom_active.png new file mode 100644 index 0000000000..77255d076e Binary files /dev/null and b/src/main/resources/assets/gtceu/textures/block/machines/air_scrubber/overlay_bottom_active.png differ diff --git a/src/main/resources/assets/gtceu/textures/block/machines/air_scrubber/overlay_bottom_active_emissive.png b/src/main/resources/assets/gtceu/textures/block/machines/air_scrubber/overlay_bottom_active_emissive.png new file mode 100644 index 0000000000..c20a1c9810 Binary files /dev/null and b/src/main/resources/assets/gtceu/textures/block/machines/air_scrubber/overlay_bottom_active_emissive.png differ diff --git a/src/main/resources/assets/gtceu/textures/block/machines/air_scrubber/overlay_bottom_emissive.png b/src/main/resources/assets/gtceu/textures/block/machines/air_scrubber/overlay_bottom_emissive.png new file mode 100644 index 0000000000..c20a1c9810 Binary files /dev/null and b/src/main/resources/assets/gtceu/textures/block/machines/air_scrubber/overlay_bottom_emissive.png differ diff --git a/src/main/resources/assets/gtceu/textures/block/machines/air_scrubber/overlay_front.png b/src/main/resources/assets/gtceu/textures/block/machines/air_scrubber/overlay_front.png new file mode 100644 index 0000000000..9a73c1c099 Binary files /dev/null and b/src/main/resources/assets/gtceu/textures/block/machines/air_scrubber/overlay_front.png differ diff --git a/src/main/resources/assets/gtceu/textures/block/machines/air_scrubber/overlay_front_active.png b/src/main/resources/assets/gtceu/textures/block/machines/air_scrubber/overlay_front_active.png new file mode 100644 index 0000000000..30eff79ea4 Binary files /dev/null and b/src/main/resources/assets/gtceu/textures/block/machines/air_scrubber/overlay_front_active.png differ diff --git a/src/main/resources/assets/gtceu/textures/block/machines/air_scrubber/overlay_front_active_emissive.png b/src/main/resources/assets/gtceu/textures/block/machines/air_scrubber/overlay_front_active_emissive.png new file mode 100644 index 0000000000..c20a1c9810 Binary files /dev/null and b/src/main/resources/assets/gtceu/textures/block/machines/air_scrubber/overlay_front_active_emissive.png differ diff --git a/src/main/resources/assets/gtceu/textures/block/machines/air_scrubber/overlay_front_emissive.png b/src/main/resources/assets/gtceu/textures/block/machines/air_scrubber/overlay_front_emissive.png new file mode 100644 index 0000000000..c20a1c9810 Binary files /dev/null and b/src/main/resources/assets/gtceu/textures/block/machines/air_scrubber/overlay_front_emissive.png differ diff --git a/src/main/resources/assets/gtceu/textures/block/machines/air_scrubber/overlay_side.png b/src/main/resources/assets/gtceu/textures/block/machines/air_scrubber/overlay_side.png new file mode 100644 index 0000000000..9a73c1c099 Binary files /dev/null and b/src/main/resources/assets/gtceu/textures/block/machines/air_scrubber/overlay_side.png differ diff --git a/src/main/resources/assets/gtceu/textures/block/machines/air_scrubber/overlay_side_active.png b/src/main/resources/assets/gtceu/textures/block/machines/air_scrubber/overlay_side_active.png new file mode 100644 index 0000000000..04b7be74d1 Binary files /dev/null and b/src/main/resources/assets/gtceu/textures/block/machines/air_scrubber/overlay_side_active.png differ diff --git a/src/main/resources/assets/gtceu/textures/block/machines/air_scrubber/overlay_side_active_emissive.png b/src/main/resources/assets/gtceu/textures/block/machines/air_scrubber/overlay_side_active_emissive.png new file mode 100644 index 0000000000..c20a1c9810 Binary files /dev/null and b/src/main/resources/assets/gtceu/textures/block/machines/air_scrubber/overlay_side_active_emissive.png differ diff --git a/src/main/resources/assets/gtceu/textures/block/machines/air_scrubber/overlay_side_emissive.png b/src/main/resources/assets/gtceu/textures/block/machines/air_scrubber/overlay_side_emissive.png new file mode 100644 index 0000000000..c20a1c9810 Binary files /dev/null and b/src/main/resources/assets/gtceu/textures/block/machines/air_scrubber/overlay_side_emissive.png differ diff --git a/src/main/resources/assets/gtceu/textures/block/machines/air_scrubber/overlay_top.png b/src/main/resources/assets/gtceu/textures/block/machines/air_scrubber/overlay_top.png new file mode 100644 index 0000000000..92bee664c6 Binary files /dev/null and b/src/main/resources/assets/gtceu/textures/block/machines/air_scrubber/overlay_top.png differ diff --git a/src/main/resources/assets/gtceu/textures/block/machines/air_scrubber/overlay_top_active.png b/src/main/resources/assets/gtceu/textures/block/machines/air_scrubber/overlay_top_active.png new file mode 100644 index 0000000000..d8d3ece879 Binary files /dev/null and b/src/main/resources/assets/gtceu/textures/block/machines/air_scrubber/overlay_top_active.png differ diff --git a/src/main/resources/assets/gtceu/textures/block/machines/air_scrubber/overlay_top_active_emissive.png b/src/main/resources/assets/gtceu/textures/block/machines/air_scrubber/overlay_top_active_emissive.png new file mode 100644 index 0000000000..fcb4c97ca1 Binary files /dev/null and b/src/main/resources/assets/gtceu/textures/block/machines/air_scrubber/overlay_top_active_emissive.png differ diff --git a/src/main/resources/assets/gtceu/textures/block/machines/air_scrubber/overlay_top_emissive.png b/src/main/resources/assets/gtceu/textures/block/machines/air_scrubber/overlay_top_emissive.png new file mode 100644 index 0000000000..6c7e63b924 Binary files /dev/null and b/src/main/resources/assets/gtceu/textures/block/machines/air_scrubber/overlay_top_emissive.png differ diff --git a/src/main/resources/assets/gtceu/textures/block/machines/air_scrubber/overlay_top_paused.png b/src/main/resources/assets/gtceu/textures/block/machines/air_scrubber/overlay_top_paused.png new file mode 100644 index 0000000000..b2ed08f57d Binary files /dev/null and b/src/main/resources/assets/gtceu/textures/block/machines/air_scrubber/overlay_top_paused.png differ diff --git a/src/main/resources/assets/gtceu/textures/block/machines/air_scrubber/overlay_top_paused_emissive.png b/src/main/resources/assets/gtceu/textures/block/machines/air_scrubber/overlay_top_paused_emissive.png new file mode 100644 index 0000000000..b27e8c3b2e Binary files /dev/null and b/src/main/resources/assets/gtceu/textures/block/machines/air_scrubber/overlay_top_paused_emissive.png differ diff --git a/src/main/resources/assets/gtceu/textures/block/pipe/pipe_duct_in.png b/src/main/resources/assets/gtceu/textures/block/pipe/pipe_duct_in.png new file mode 100644 index 0000000000..be031204b0 Binary files /dev/null and b/src/main/resources/assets/gtceu/textures/block/pipe/pipe_duct_in.png differ diff --git a/src/main/resources/assets/gtceu/textures/block/pipe/pipe_duct_side.png b/src/main/resources/assets/gtceu/textures/block/pipe/pipe_duct_side.png new file mode 100644 index 0000000000..aaaa35edb5 Binary files /dev/null and b/src/main/resources/assets/gtceu/textures/block/pipe/pipe_duct_side.png differ