diff --git a/injected_interfaces/interfaces.json b/injected_interfaces/interfaces.json index 9704941a618..1ab154b3032 100644 --- a/injected_interfaces/interfaces.json +++ b/injected_interfaces/interfaces.json @@ -1,5 +1,9 @@ { "net/minecraft/client/renderer/block/model/BakedQuad": [ "com/gregtechceu/gtceu/core/IGTBakedQuad" + ], + "net/minecraft/world/entity/Entity": [ + "com/gregtechceu/gtceu/core/IFireImmuneEntity", + "com/gregtechceu/gtceu/core/IBreathingEntity" ] } diff --git a/src/generated/resources/assets/gtceu/lang/en_ud.json b/src/generated/resources/assets/gtceu/lang/en_ud.json index 892d9e3836c..bf0a7e5ea8e 100644 --- a/src/generated/resources/assets/gtceu/lang/en_ud.json +++ b/src/generated/resources/assets/gtceu/lang/en_ud.json @@ -1737,10 +1737,22 @@ "command.gtceu.cape.use.success": "%s ǝdɐɔ buısn ʍou sı %s", "command.gtceu.cape.use.success.none": "ǝdɐɔ ɐ buısn ɹǝbuoן ou sı %s", "command.gtceu.dump_data.success": "%s oʇ %s ʎɹʇsıbǝɹ ɯoɹɟ sǝɔɹnosǝɹ %s pǝdɯnᗡ", - "command.gtceu.medical_condition.get": ":suoıʇıpuoɔ ןɐɔıpǝɯ ǝsǝɥʇ sɐɥ %s ɹǝʎɐןԀ", - "command.gtceu.medical_condition.get.element": "spuoɔǝs %s sǝʇnuıɯ %s :ɹ§%s uoıʇıpuoƆ", - "command.gtceu.medical_condition.get.element.permanent": ")ʇuǝuɐɯɹǝd( spuoɔǝs %s sǝʇnuıɯ %s :ɹ§%s uoıʇıpuoƆ", - "command.gtceu.medical_condition.get.empty": "˙suoıʇıpuoɔ ןɐɔıpǝɯ ou sɐɥ %s ɹǝʎɐןԀ", + "command.gtceu.medical_condition.clear.everything.failed": "ǝʌoɯǝɹ oʇ suoıʇıpuoɔ ou sɐɥ ʇǝbɹɐ⟘", + "command.gtceu.medical_condition.clear.everything.success.multiple": "sʇǝbɹɐʇ %s ɯoɹɟ suoıʇıpuoɔ ןןɐ pǝʌoɯǝᴚ", + "command.gtceu.medical_condition.clear.everything.success.single": "%s ɯoɹɟ suoıʇıpuoɔ ןןɐ pǝʌoɯǝᴚ", + "command.gtceu.medical_condition.clear.specific.failed": "uoıʇıpuoɔ pǝʇsǝnbǝɹ ǝɥʇ ǝʌɐɥ ʇ,usǝop ʇǝbɹɐ⟘", + "command.gtceu.medical_condition.clear.specific.success.multiple": "sʇǝbɹɐʇ %s ɯoɹɟ %s pǝʌoɯǝᴚ", + "command.gtceu.medical_condition.clear.specific.success.single": "%s ɯoɹɟ %s pǝʌoɯǝᴚ", + "command.gtceu.medical_condition.get": "sɐɥ %s", + "command.gtceu.medical_condition.get.element": "spuoɔǝs %s sǝʇnuıɯ %s ɹoɟ %s -", + "command.gtceu.medical_condition.get.element.permanent": ")ʇuǝuɐɯɹǝd( spuoɔǝs %s sǝʇnuıɯ %s ɹoɟ %s -", + "command.gtceu.medical_condition.get.empty": "˙ʎɥʇןɐǝɥ ʎןʇɔǝɟɹǝd sı %s", + "command.gtceu.medical_condition.get.symptoms": ":sɯoʇdɯʎs ǝsǝɥʇ sɐɥ %s ʎןʇuǝɹɹnƆ", + "command.gtceu.medical_condition.get.symptoms.element": "%s -", + "command.gtceu.medical_condition.get.symptoms.empty": "˙sɯoʇdɯʎs ou sɐɥ %s", + "command.gtceu.medical_condition.give.failed": ")ʇǝbɹɐʇ pıןɐʌuı( uoıʇıpuoɔ sıɥʇ ʎןddɐ oʇ ǝןqɐu∩", + "command.gtceu.medical_condition.give.success.multiple": "sʇǝbɹɐʇ %s oʇ %s pǝıןddⱯ", + "command.gtceu.medical_condition.give.success.single": "%s oʇ %s pǝıןddⱯ", "command.gtceu.place_vein.failure": "%s uoıʇısod ʇɐ %s uıǝʌ ǝɔɐןd oʇ pǝןıɐℲ", "command.gtceu.place_vein.success": "%s uoıʇısod ʇɐ %s uıǝʌ pǝɔɐןԀ", "command.gtceu.share_prospection_data.notification": "¡noʎ ɥʇıʍ ɐʇɐp buıʇɔǝdsoɹd buıɹɐɥs sı %s", @@ -1751,6 +1763,7 @@ "config.gtceu.option.animationTime": "ǝɯı⟘uoıʇɐɯıuɐ", "config.gtceu.option.arcRecyclingYield": "pןǝıʎbuıןɔʎɔǝᴚɔɹɐ", "config.gtceu.option.armorHud": "pnHɹoɯɹɐ", + "config.gtceu.option.autoRebuildResources": "sǝɔɹnosǝᴚpןınqǝᴚoʇnɐ", "config.gtceu.option.batchDuration": "uoıʇɐɹnᗡɥɔʇɐq", "config.gtceu.option.bedrockOreDistance": "ǝɔuɐʇsıᗡǝɹOʞɔoɹpǝq", "config.gtceu.option.bedrockOreDropTagPrefix": "xıɟǝɹԀbɐ⟘doɹᗡǝɹOʞɔoɹpǝq", @@ -2162,11 +2175,11 @@ "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/nausea": "ɐǝsnɐu oʇ pǝqɯnɔɔns %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.medical_condition/silicosis": "sısoɔıןıs sɐʍ ʇI ˙sısoןnɔɹǝqnʇ ɟo ǝıp ʇ,upıp %s", + "death.attack.gtceu.medical_condition/weak_poison": "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", @@ -2295,6 +2308,8 @@ "gtceu.creative_tooltip.3": "sıɥʇ ǝsn oʇ ㄥ§", "gtceu.cutter": "ɹǝʇʇnƆ", "gtceu.debug.f3_h.enabled": "ǝɹoɯ ǝǝs oʇ ǝןıɟ bıɟuoɔ ɥɔǝ⟘bǝɹ⅁ ǝɥʇ uı uoıʇdo bıɟuoɔ bnqǝp:ɔsıɯ ǝɥʇ ǝןqɐuǝ :sɹǝdoןǝʌǝᗡ ɹoℲ ¡oɟuı bnqǝp ǝɥʇ pǝıɟıpoɯ sɐɥ ɥɔǝ⟘bǝɹ⅁", + "gtceu.debug.resource_rebuild.done": "%s uı ǝuop pןınqǝɹ ǝɔɹnosǝɹ ǝןpɐɹ⅁", + "gtceu.debug.resource_rebuild.start": ")sǝɔɹnosǝᴚssǝɔoɹd: ʍǝןpɐɹb/˙( pןınqǝɹ ǝɔɹnosǝɹ ǝןpɐɹb buıʞoʌuI", "gtceu.direction.tooltip.back": "ʞɔɐᗺ", "gtceu.direction.tooltip.down": "uʍoᗡ", "gtceu.direction.tooltip.front": "ʇuoɹℲ", @@ -2492,12 +2507,6 @@ "gtceu.gui.toggle_view.disabled": ")spınןℲ( ʍǝıΛ ǝןbbo⟘", "gtceu.gui.toggle_view.enabled": ")sɯǝʇI( ʍǝıΛ ǝןbbo⟘", "gtceu.gui.waiting_list": ":ǝnǝnὉ buıpuǝS", - "gtceu.hazard_trigger.any": "ʇɔɐʇuoɔ ʎuⱯ", - "gtceu.hazard_trigger.description": ":ʎq pǝsnɐƆ", - "gtceu.hazard_trigger.inhalation": "uoıʇɐןɐɥuI", - "gtceu.hazard_trigger.none": "buıɥʇoN", - "gtceu.hazard_trigger.protection.description": ":ɯoɹɟ sʇɔǝʇoɹԀ", - "gtceu.hazard_trigger.skin_contact": "ʇɔɐʇuoɔ uıʞS", "gtceu.implosion_compressor": "ɹossǝɹdɯoƆ uoısoןdɯI", "gtceu.io.both": "ɥʇoᗺ", "gtceu.io.export": "ʇɹodxƎ", @@ -3253,25 +3262,6 @@ "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.minimap.ore_vein.depleted": "pǝʇǝןdǝᗡ", "gtceu.mixer": "ɹǝxıW", "gtceu.mode.both": "ɹ§)ɯǝʇI puⱯ pınןℲ( ɥʇoᗺp§", @@ -3655,6 +3645,9 @@ "gtceu.placeholder_info.if.0": "˙0 oʇ ןɐnbǝ ʇou sı puɐ buıɹʇs ʎʇdɯǝ uɐ ʇou sı ʇı ɟı ǝnɹʇ pǝɹǝpısuoɔ sı uoıʇıpuoɔ ǝɥ⟘ ˙uoıʇıpuoɔ ǝɥʇ uo buıpuǝdǝp sʇuǝɯnbɹɐ ǝɥʇ ɟo ǝuo suɹnʇǝᴚ", "gtceu.placeholder_info.if.1": ":ǝbɐs∩", "gtceu.placeholder_info.if.2": "}]ǝsןɐɟ‾ɟı‾pǝuɹnʇǝɹ[ >ǝnɹʇ‾ɟı‾pǝuɹnʇǝɹ< >uoıʇıpuoɔ< ɟı{ ", + "gtceu.placeholder_info.item.0": "ʇoןs pǝıɟıɔǝds ɐ uı ɯǝʇı ǝɥʇ ɟo pı puɐ ʇunoɯɐ ǝɥʇ suɹnʇǝᴚ", + "gtceu.placeholder_info.item.1": ":ǝbɐs∩", + "gtceu.placeholder_info.item.2": ")ǝןdɯɐxǝ ɹoɟ( \"puoɯɐıp:ʇɟɐɹɔǝuıɯ ƖƐ\" >- }>ʇoןs< ɯǝʇı{ ", "gtceu.placeholder_info.itemCount.0": "˙)pǝɹǝʇןıɟ ǝq uɐɔ( sɯǝʇı ɟo ʇunoɯɐ ǝɥʇ suɹnʇǝᴚ", "gtceu.placeholder_info.itemCount.1": ":ǝbɐs∩", "gtceu.placeholder_info.itemCount.2": "ʇunoɯɐ ɯǝʇı ןɐʇoʇ >- }ʇunoƆɯǝʇı{ ", @@ -3668,6 +3661,9 @@ "gtceu.placeholder_info.maxProgress.1": ",%}00Ɩ * }}ssǝɹboɹԀxɐɯ{ / }ssǝɹboɹd{ ɔןɐɔ{ ɔןɐɔ{ :ssǝɹboɹԀ, :ǝןdɯɐxƎ", "gtceu.placeholder_info.maxProgress.2": ":ǝbɐs∩", "gtceu.placeholder_info.maxProgress.3": "ǝdıɔǝɹ buıuunɹ ʎןʇuǝɹɹnɔ ǝɥʇ ɟo ssǝɹboɹd xɐɯ ǝɥʇ >- }ssǝɹboɹԀxɐɯ{ ", + "gtceu.placeholder_info.module.0": ")ɹǝʌoɔ ɐ uı ʞɹoʍ ʇou sǝop( ɹoʇıuoɯ ןɐɹʇuǝɔ ǝɥʇ oʇuo ʇoןs pǝıɟıɔǝds ǝɥʇ uı ǝןnpoɯ ǝɥʇ sɹǝpuǝᴚ", + "gtceu.placeholder_info.module.1": ":ǝbɐs∩", + "gtceu.placeholder_info.module.2": "buıɹʇs ʎʇdɯǝ >- }>ʎ< >x< >ʇoןs< ǝןnpoɯ{ ", "gtceu.placeholder_info.nbt.0": "ʇoןs pǝıɟıɔǝds ǝɥʇ uı ɯǝʇı ǝɥʇ ɟo ɐʇɐp ʇqu ǝɥʇ suɹnʇǝᴚ", "gtceu.placeholder_info.nbt.1": ":ǝbɐs∩", "gtceu.placeholder_info.nbt.2": "]˙˙˙[]Ɛʎǝʞ[]ᄅʎǝʞ[]Ɩʎǝʞ[ʇqu‾ɯǝʇı >- }˙˙˙ ]Ɛʎǝʞ[ ]ᄅʎǝʞ[ ]Ɩʎǝʞ[ >ʇoןs< ʇqu{ ", @@ -3681,9 +3677,16 @@ "gtceu.placeholder_info.progress.1": "}ssǝɹboɹԀxɐɯ{ puɐ 0 uǝǝʍʇǝq ɹǝbǝʇuı uɐ sı ssǝɹboɹd ʇɐɥʇ ǝʇoN", "gtceu.placeholder_info.progress.2": ":ǝbɐs∩", "gtceu.placeholder_info.progress.3": "ǝdıɔǝɹ buıuunɹ ʎןʇuǝɹɹnɔ ǝɥʇ ɟo ssǝɹboɹd ǝɥʇ >- }ssǝɹboɹd{ ", + "gtceu.placeholder_info.quad.0": ")sǝɔıʇɹǝʌ ㄣ ןןɐ ɹoɟ sɹǝʇǝɯɐɹɐd ʎɟıɔǝds ʇsnɯ( pɐnb ɐ sʍɐɹᗡ", + "gtceu.placeholder_info.quad.1": ":ǝbɐs∩", + "gtceu.placeholder_info.quad.2": "buıɹʇs ʎʇdɯǝ >- }>ㄣɹoןoɔ< >Ɛɹoןoɔ< >ᄅɹoןoɔ< >Ɩɹoןoɔ< >ㄣʎ< >ㄣx< >Ɛʎ< >Ɛx< >ᄅʎ< >ᄅx< >Ɩʎ< >Ɩx< pɐnb{ ", "gtceu.placeholder_info.random.0": "˙)ǝʌısnןɔuı( ןɐʌɹǝʇuı pǝıɟıɔǝds ǝɥʇ uı ɹǝqɯnu ɯopuɐɹ ɐ suɹnʇǝᴚ", "gtceu.placeholder_info.random.1": ":ǝbɐs∩", "gtceu.placeholder_info.random.2": ")ǝʌısnןɔuı( xɐɯ puɐ uıɯ uǝǝʍʇǝq ɹǝqɯnu ɯopuɐɹ ɐ >- }>xɐɯ< >uıɯ< ɯopuɐɹ{ ", + "gtceu.placeholder_info.rect.0": "ǝzıs puɐ sǝʇɐuıpɹooɔ pǝıɟıɔǝds ǝɥʇ ɥʇıʍ uoıʇısod pǝıɟıɔǝds ǝɥʇ ʇɐ ǝןbuɐʇɔǝɹ ɐ sʍɐɹᗡ", + "gtceu.placeholder_info.rect.1": ":ǝbɐs∩", + "gtceu.placeholder_info.rect.2": "buıɹʇs ʎʇdɯǝ >- }>ᗺ⅁ᴚⱯɹoןoɔ< >ʇɥbıǝɥ< >ɥʇpıʍ< >ʎ< >x< ʇɔǝɹ{ ", + "gtceu.placeholder_info.rect.3": ")Ɩ 'ᄅ( ǝzıs ǝɥʇ ɥʇıʍ )ϛᄅ˙0 'ϛ˙0( ʇɐ ǝןbuɐʇɔǝɹ ǝʇıɥʍ ɐ sʍɐɹp >- }ℲℲℲℲℲℲℲℲx0 Ɩ ᄅ ϛᄅ˙0 ϛ˙0 ʇɔǝɹ{ ", "gtceu.placeholder_info.redstone.0": "ɥʇbuǝɹʇs ʇndʇno ǝuoʇspǝɹ ǝɥʇ sʇǝs ɹo ɥʇbuǝɹʇs ןɐubıs ǝuoʇspǝɹ ǝɥʇ suɹnʇǝᴚ", "gtceu.placeholder_info.redstone.1": ":ǝbɐs∩", "gtceu.placeholder_info.redstone.2": "ǝpıs pǝıɟıɔǝds ǝɥʇ ʇɐ )ϛƖ-0( ɥʇbuǝɹʇs ןɐubıs ǝuoʇspǝɹ >- }>ʇsǝʍ|ʇsɐǝ|ɥʇnos|ɥʇɹou|uʍop|dn< ʇǝb ǝuoʇspǝɹ{ ", @@ -3696,6 +3699,9 @@ "gtceu.placeholder_info.select.0": ")0 ɯoɹɟ buıʇɹɐʇs( xǝpuı pǝıɟıɔǝds ǝɥʇ ʇɐ ʇuǝɯnbɹɐ ǝɥʇ suɹnʇǝᴚ", "gtceu.placeholder_info.select.1": ":ǝbɐs∩", "gtceu.placeholder_info.select.2": "xǝpuı pǝıɟıɔǝds ǝɥʇ ʇɐ ʇuǝɯnbɹɐ >- ˙˙˙ ]Ɛbɹɐ[ ]ᄅbɹɐ[ ]Ɩbɹɐ[ >xǝpuı< ʇɔǝןǝs{ ", + "gtceu.placeholder_info.setImage.0": "ʇoןs pǝıɟıɔǝds ǝɥʇ uı ǝןnpoɯ ǝbɐɯı uɐ uı Ꞁᴚ∩ ǝbɐɯı ǝɥʇ sʇǝS", + "gtceu.placeholder_info.setImage.1": ":ǝbɐs∩", + "gtceu.placeholder_info.setImage.2": "buıɹʇs ʎʇdɯǝ >- }>ןɹn< >ʇoןs< ǝbɐɯIʇǝs{ ", "gtceu.placeholder_info.strike.0": "ʇno pǝssoɹɔ sɐʍ ʇı ɟı sɐ ʇı buıʎɐןdsıp 'ʇxǝʇ ʇsɹıɟ ǝɥʇ ɯoɹɟ ʇxǝʇ ǝɥʇ suɹnʇǝᴚ", "gtceu.placeholder_info.strike.1": ":ǝbɐs∩", "gtceu.placeholder_info.strike.2": "ʇxǝʇ ʇno-pǝssoɹɔ >- }>ʇxǝʇ< ǝʞıɹʇs{ ", @@ -4789,7 +4795,7 @@ "item.gtceu.tool.behavior.block_rotation": "sʞɔoןᗺ sǝʇɐʇoᴚɟ§ :ɔıuɐɥɔǝWᄅ§", "item.gtceu.tool.behavior.crop_harvesting": "sdoɹƆ sʇsǝʌɹɐHɟ§ :ɹǝʇsǝʌɹɐHɐ§", "item.gtceu.tool.behavior.damage_boost": "%s ʇsuıɐbɐ ǝbɐɯɐp ɐɹʇxƎɟ§ :ʇsooᗺ ǝbɐɯɐᗡㄣ§", - "item.gtceu.tool.behavior.dowse_campfire": "sǝɹıɟdɯɐƆ sǝsʍoᗡɟ§ :ɹǝʇɥbıɟǝɹıℲƖ§", + "item.gtceu.tool.behavior.dowse_campfire": "sǝɹıɟdɯɐƆ sǝsʍoᗡɟ§ :ɹǝʇɥbıɟǝɹıℲ9§", "item.gtceu.tool.behavior.grass_path": "sɥʇɐԀ ssɐɹ⅁ sǝʇɐǝɹƆɟ§ :ɹǝdɐɔspuɐꞀǝ§", "item.gtceu.tool.behavior.ground_tilling": "punoɹ⅁ sןןı⟘ɟ§ :ɹǝɯɹɐℲǝ§", "item.gtceu.tool.behavior.plunger": "spınןℲ suıɐɹᗡɟ§ :ɹǝqɯnןԀ6§", @@ -5687,6 +5693,23 @@ "material.gtceu.zinc_sulfide": "ǝpıɟןnS ɔuıZ", "material.gtceu.zincite": "ǝʇıɔuıZ", "material.gtceu.zirconium": "ɯnıuoɔɹıZ", + "medical_condition.gtceu.arsenicosis": "sısoɔıuǝsɹⱯq§", + "medical_condition.gtceu.asbestosis": "sısoʇsǝqsⱯp§", + "medical_condition.gtceu.carbon_monoxide_poisoning": "buıuosıoԀ ǝpıxouoW uoqɹɐƆㄥ§", + "medical_condition.gtceu.carcinogen": "ɔıuǝbouıɔɹɐƆǝ§", + "medical_condition.gtceu.carcinogen.affected": "ɹǝɔuɐƆǝ§", + "medical_condition.gtceu.chemical_burns": "suɹnq ןɐɔıɯǝɥƆϛ§", + "medical_condition.gtceu.irritant": "ʇuɐʇıɹɹI9§", + "medical_condition.gtceu.irritant.affected": "uoıʇɐʇıɹɹI9§", + "medical_condition.gtceu.methanol_poisoning": "buıuosıoԀ ןouɐɥʇǝW9§", + "medical_condition.gtceu.nausea": "buıʇɐǝsnɐNƐ§", + "medical_condition.gtceu.nausea.affected": "ɐǝsnɐNƐ§", + "medical_condition.gtceu.none": "snoɹǝbuɐᗡ ʇoNᄅ§", + "medical_condition.gtceu.none.affected": "¿buıɥʇoNᄅ§", + "medical_condition.gtceu.poison": "snouosıoԀᄅ§", + "medical_condition.gtceu.poison.affected": "buıuosıoԀᄅ§", + "medical_condition.gtceu.weak_poison": "snouosıod ʎןʞɐǝMɐ§", + "medical_condition.gtceu.weak_poison.affected": "buıuosıod ɹouıWɐ§", "message.gtceu.new_veins.amount": "¡suıǝʌ ʍǝu %d pǝʇɔǝdsoɹԀ", "message.gtceu.new_veins.name": "¡%s pǝʇɔǝdsoɹԀ", "metaarmor.energy_share.disable": "pǝןqɐsıp buıbɹɐɥɔ sʇǝbpɐ⅁ :ʎןddnS ʎbɹǝuƎ", @@ -5809,6 +5832,20 @@ "recipe.condition.rain.tooltip": "%d :ןǝʌǝꞀ uıɐᴚ", "recipe.condition.steam_vent.tooltip": "ʇuǝʌ ɯɐǝʇs uɐǝןƆ", "recipe.condition.thunder.tooltip": "%d :ןǝʌǝꞀ ɹǝpunɥ⟘", + "symptom.gtceu.air_supply_debuff": "ʎʇıɔɐdɐɔ bunן pǝɹǝʍoꞀ", + "symptom.gtceu.blindness": "ssǝupuıןᗺ", + "symptom.gtceu.darkness": "ssǝuʞɹɐᗡ", + "symptom.gtceu.death": "ɥʇɐǝᗡ", + "symptom.gtceu.health_debuff": "ɥʇןɐǝɥ ɯnɯıxɐɯ pǝɹǝʍoꞀ", + "symptom.gtceu.hunger": "ǝʇıʇǝddɐ pǝsɐǝɹɔuI", + "symptom.gtceu.mining_fatigue": "ǝnbıʇɐℲ", + "symptom.gtceu.nausea": "ɐǝsnɐN", + "symptom.gtceu.poisoning": "buıuosıoԀ", + "symptom.gtceu.random_damage": "ǝbɐɯɐp ןɐuoısɐɔɔO", + "symptom.gtceu.slowness": "ssǝuʍoןS", + "symptom.gtceu.weak_poisoning": "buıuosıod ʞɐǝM", + "symptom.gtceu.weakness": "ssǝuʞɐǝM", + "symptom.gtceu.wither": "sısoɹɔǝN", "tagprefix.andesite": "ǝɹO %s ǝʇısǝpuⱯ", "tagprefix.basalt": "ǝɹO %s ʇןɐsɐᗺ", "tagprefix.blackstone": "ǝɹO %s ǝuoʇsʞɔɐןᗺ", @@ -5920,5 +5957,17 @@ "tile.gtceu.petrified_foam.name": "ɯɐoℲ pǝıɟıɹʇǝԀ", "tile.gtceu.reinforced_foam.name": "ɯɐoℲ pǝɔɹoɟuıǝᴚ", "tile.gtceu.reinforced_stone.name": "ǝuoʇS pǝɔɹoɟuıǝᴚ", - "tile.gtceu.seal.name": "ʞɔoןᗺ pǝןɐǝS" + "tile.gtceu.seal.name": "ʞɔoןᗺ pǝןɐǝS", + "tooltip.gtceu.antidote.description": "sןıɐʇǝp ʍoɥs oʇ ʇɟıɥS pןoHㄥ§ ǝʇopıʇuⱯɐ§", + "tooltip.gtceu.antidote.description.effect_removed": "sʇɔǝɟɟǝ ,suoıʇıpuoɔ ʇuǝɹɹnɔ ɟo %s%% sǝʌoɯǝᴚ", + "tooltip.gtceu.antidote.description.effect_removed.all": "sʇɔǝɟɟǝ ,suoıʇıpuoɔ ʇuǝɹɹnɔ ɟo ןןɐ sǝʌoɯǝᴚ", + "tooltip.gtceu.antidote.description_shift": ":suoıʇıpuoɔ ǝsǝɥʇ sǝɹnƆɐ§", + "tooltip.gtceu.hazard_trigger": ":ʎq pǝsnɐƆ", + "tooltip.gtceu.hazard_trigger.any": "ʇɔɐʇuoɔ ʎuⱯ", + "tooltip.gtceu.hazard_trigger.inhalation": "uoıʇɐןɐɥuI", + "tooltip.gtceu.hazard_trigger.none": "buıɥʇoN", + "tooltip.gtceu.hazard_trigger.protection": ":ɯoɹɟ sʇɔǝʇoɹԀ", + "tooltip.gtceu.hazard_trigger.skin_contact": "ʇɔɐʇuoɔ uıʞS", + "tooltip.gtceu.medical_condition.description": "sןıɐʇǝp ʍoɥs oʇ ʇɟıɥS pןoHㄥ§ S∩OᗡᴚⱯZⱯHɔ§ן§", + "tooltip.gtceu.medical_condition.description_shift": ":S∩OᗡᴚⱯZⱯHɔ§ן§" } \ No newline at end of file diff --git a/src/generated/resources/assets/gtceu/lang/en_us.json b/src/generated/resources/assets/gtceu/lang/en_us.json index 35d0223ccab..46c94563701 100644 --- a/src/generated/resources/assets/gtceu/lang/en_us.json +++ b/src/generated/resources/assets/gtceu/lang/en_us.json @@ -1737,10 +1737,22 @@ "command.gtceu.cape.use.success": "%s is now using cape %s", "command.gtceu.cape.use.success.none": "%s is no longer using a cape", "command.gtceu.dump_data.success": "Dumped %s resources from registry %s to %s", - "command.gtceu.medical_condition.get": "Player %s has these medical conditions:", - "command.gtceu.medical_condition.get.element": "Condition %s§r: %s minutes %s seconds", - "command.gtceu.medical_condition.get.element.permanent": "Condition %s§r: %s minutes %s seconds (permanent)", - "command.gtceu.medical_condition.get.empty": "Player %s has no medical conditions.", + "command.gtceu.medical_condition.clear.everything.failed": "Target has no conditions to remove", + "command.gtceu.medical_condition.clear.everything.success.multiple": "Removed all conditions from %s targets", + "command.gtceu.medical_condition.clear.everything.success.single": "Removed all conditions from %s", + "command.gtceu.medical_condition.clear.specific.failed": "Target doesn't have the requested condition", + "command.gtceu.medical_condition.clear.specific.success.multiple": "Removed %s from %s targets", + "command.gtceu.medical_condition.clear.specific.success.single": "Removed %s from %s", + "command.gtceu.medical_condition.get": "%s has", + "command.gtceu.medical_condition.get.element": "- %s for %s minutes %s seconds", + "command.gtceu.medical_condition.get.element.permanent": "- %s for %s minutes %s seconds (permanent)", + "command.gtceu.medical_condition.get.empty": "%s is perfectly healthy.", + "command.gtceu.medical_condition.get.symptoms": "Currently %s has these symptoms:", + "command.gtceu.medical_condition.get.symptoms.element": "- %s", + "command.gtceu.medical_condition.get.symptoms.empty": "%s has no symptoms.", + "command.gtceu.medical_condition.give.failed": "Unable to apply this condition (invalid target)", + "command.gtceu.medical_condition.give.success.multiple": "Applied %s to %s targets", + "command.gtceu.medical_condition.give.success.single": "Applied %s to %s", "command.gtceu.place_vein.failure": "Failed to place vein %s at position %s", "command.gtceu.place_vein.success": "Placed vein %s at position %s", "command.gtceu.share_prospection_data.notification": "%s is sharing prospecting data with you!", @@ -1751,6 +1763,7 @@ "config.gtceu.option.animationTime": "animationTime", "config.gtceu.option.arcRecyclingYield": "arcRecyclingYield", "config.gtceu.option.armorHud": "armorHud", + "config.gtceu.option.autoRebuildResources": "autoRebuildResources", "config.gtceu.option.batchDuration": "batchDuration", "config.gtceu.option.bedrockOreDistance": "bedrockOreDistance", "config.gtceu.option.bedrockOreDropTagPrefix": "bedrockOreDropTagPrefix", @@ -2162,11 +2175,11 @@ "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/nausea": "%s succumbed to 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.medical_condition/silicosis": "%s didn't die of tuberculosis. It was silicosis", + "death.attack.gtceu.medical_condition/weak_poison": "%s ate lead", "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", @@ -2295,6 +2308,8 @@ "gtceu.creative_tooltip.3": "§7 to use this", "gtceu.cutter": "Cutter", "gtceu.debug.f3_h.enabled": "GregTech has modified the debug info! For Developers: enable the misc:debug config option in the GregTech config file to see more", + "gtceu.debug.resource_rebuild.done": "Gradle resource rebuild done in %s", + "gtceu.debug.resource_rebuild.start": "Invoking gradle resource rebuild (./gradlew :processResources)", "gtceu.direction.tooltip.back": "Back", "gtceu.direction.tooltip.down": "Down", "gtceu.direction.tooltip.front": "Front", @@ -2492,12 +2507,6 @@ "gtceu.gui.toggle_view.disabled": "Toggle View (Fluids)", "gtceu.gui.toggle_view.enabled": "Toggle View (Items)", "gtceu.gui.waiting_list": "Sending Queue:", - "gtceu.hazard_trigger.any": "Any contact", - "gtceu.hazard_trigger.description": "Caused by:", - "gtceu.hazard_trigger.inhalation": "Inhalation", - "gtceu.hazard_trigger.none": "Nothing", - "gtceu.hazard_trigger.protection.description": "Protects from:", - "gtceu.hazard_trigger.skin_contact": "Skin contact", "gtceu.implosion_compressor": "Implosion Compressor", "gtceu.io.both": "Both", "gtceu.io.export": "Export", @@ -3253,25 +3262,6 @@ "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.minimap.ore_vein.depleted": "Depleted", "gtceu.mixer": "Mixer", "gtceu.mode.both": "§dBoth (Fluid And Item)§r", @@ -3655,6 +3645,9 @@ "gtceu.placeholder_info.if.0": "Returns one of the arguments depending on the condition. The condition is considered true if it is not an empty string and is not equal to 0.", "gtceu.placeholder_info.if.1": "Usage:", "gtceu.placeholder_info.if.2": " {if [returned_if_false]}", + "gtceu.placeholder_info.item.0": "Returns the amount and id of the item in a specified slot", + "gtceu.placeholder_info.item.1": "Usage:", + "gtceu.placeholder_info.item.2": " {item } -> \"31 minecraft:diamond\" (for example)", "gtceu.placeholder_info.itemCount.0": "Returns the amount of items (can be filtered).", "gtceu.placeholder_info.itemCount.1": "Usage:", "gtceu.placeholder_info.itemCount.2": " {itemCount} -> total item amount", @@ -3668,6 +3661,9 @@ "gtceu.placeholder_info.maxProgress.1": "Example: 'Progress: {calc {calc {progress} / {maxProgress}} * 100}%'", "gtceu.placeholder_info.maxProgress.2": "Usage:", "gtceu.placeholder_info.maxProgress.3": " {maxProgress} -> the max progress of the currently running recipe", + "gtceu.placeholder_info.module.0": "Renders the module in the specified slot onto the central monitor (does not work in a cover)", + "gtceu.placeholder_info.module.1": "Usage:", + "gtceu.placeholder_info.module.2": " {module } -> empty string", "gtceu.placeholder_info.nbt.0": "Returns the nbt data of the item in the specified slot", "gtceu.placeholder_info.nbt.1": "Usage:", "gtceu.placeholder_info.nbt.2": " {nbt [key1] [key2] [key3] ...} -> item_nbt[key1][key2][key3][...]", @@ -3681,9 +3677,16 @@ "gtceu.placeholder_info.progress.1": "Note that progress is an integer between 0 and {maxProgress}", "gtceu.placeholder_info.progress.2": "Usage:", "gtceu.placeholder_info.progress.3": " {progress} -> the progress of the currently running recipe", + "gtceu.placeholder_info.quad.0": "Draws a quad (must specify parameters for all 4 vertices)", + "gtceu.placeholder_info.quad.1": "Usage:", + "gtceu.placeholder_info.quad.2": " {quad } -> empty string", "gtceu.placeholder_info.random.0": "Returns a random number in the specified interval (inclusive).", "gtceu.placeholder_info.random.1": "Usage:", "gtceu.placeholder_info.random.2": " {random } -> a random number between min and max (inclusive)", + "gtceu.placeholder_info.rect.0": "Draws a rectangle at the specified position with the specified coordinates and size", + "gtceu.placeholder_info.rect.1": "Usage:", + "gtceu.placeholder_info.rect.2": " {rect } -> empty string", + "gtceu.placeholder_info.rect.3": " {rect 0.5 0.25 2 1 0xFFFFFFFF} -> draws a white rectangle at (0.5, 0.25) with the size (2, 1)", "gtceu.placeholder_info.redstone.0": "Returns the redstone signal strength or sets the redstone output strength", "gtceu.placeholder_info.redstone.1": "Usage:", "gtceu.placeholder_info.redstone.2": " {redstone get } -> redstone signal strength (0-15) at the specified side", @@ -3696,6 +3699,9 @@ "gtceu.placeholder_info.select.0": "Returns the argument at the specified index (starting from 0)", "gtceu.placeholder_info.select.1": "Usage:", "gtceu.placeholder_info.select.2": " {select [arg1] [arg2] [arg3] ... -> argument at the specified index", + "gtceu.placeholder_info.setImage.0": "Sets the image URL in an image module in the specified slot", + "gtceu.placeholder_info.setImage.1": "Usage:", + "gtceu.placeholder_info.setImage.2": " {setImage } -> empty string", "gtceu.placeholder_info.strike.0": "Returns the text from the first text, displaying it as if it was crossed out", "gtceu.placeholder_info.strike.1": "Usage:", "gtceu.placeholder_info.strike.2": " {strike } -> crossed-out text", @@ -4789,7 +4795,7 @@ "item.gtceu.tool.behavior.block_rotation": "§2Mechanic: §fRotates Blocks", "item.gtceu.tool.behavior.crop_harvesting": "§aHarvester: §fHarvests Crops", "item.gtceu.tool.behavior.damage_boost": "§4Damage Boost: §fExtra damage against %s", - "item.gtceu.tool.behavior.dowse_campfire": "§1Firefighter: §fDowses Campfires", + "item.gtceu.tool.behavior.dowse_campfire": "§6Firefighter: §fDowses Campfires", "item.gtceu.tool.behavior.grass_path": "§eLandscaper: §fCreates Grass Paths", "item.gtceu.tool.behavior.ground_tilling": "§eFarmer: §fTills Ground", "item.gtceu.tool.behavior.plunger": "§9Plumber: §fDrains Fluids", @@ -5687,6 +5693,23 @@ "material.gtceu.zinc_sulfide": "Zinc Sulfide", "material.gtceu.zincite": "Zincite", "material.gtceu.zirconium": "Zirconium", + "medical_condition.gtceu.arsenicosis": "§bArsenicosis", + "medical_condition.gtceu.asbestosis": "§dAsbestosis", + "medical_condition.gtceu.carbon_monoxide_poisoning": "§7Carbon Monoxide Poisoning", + "medical_condition.gtceu.carcinogen": "§eCarcinogenic", + "medical_condition.gtceu.carcinogen.affected": "§eCancer", + "medical_condition.gtceu.chemical_burns": "§5Chemical burns", + "medical_condition.gtceu.irritant": "§6Irritant", + "medical_condition.gtceu.irritant.affected": "§6Irritation", + "medical_condition.gtceu.methanol_poisoning": "§6Methanol Poisoning", + "medical_condition.gtceu.nausea": "§3Nauseating", + "medical_condition.gtceu.nausea.affected": "§3Nausea", + "medical_condition.gtceu.none": "§2Not Dangerous", + "medical_condition.gtceu.none.affected": "§2Nothing?", + "medical_condition.gtceu.poison": "§2Poisonous", + "medical_condition.gtceu.poison.affected": "§2Poisoning", + "medical_condition.gtceu.weak_poison": "§aWeakly poisonous", + "medical_condition.gtceu.weak_poison.affected": "§aMinor poisoning", "message.gtceu.new_veins.amount": "Prospected %d new veins!", "message.gtceu.new_veins.name": "Prospected %s!", "metaarmor.energy_share.disable": "Energy Supply: Gadgets charging disabled", @@ -5809,6 +5832,20 @@ "recipe.condition.rain.tooltip": "Rain Level: %d", "recipe.condition.steam_vent.tooltip": "Clean steam vent", "recipe.condition.thunder.tooltip": "Thunder Level: %d", + "symptom.gtceu.air_supply_debuff": "Lowered lung capacity", + "symptom.gtceu.blindness": "Blindness", + "symptom.gtceu.darkness": "Darkness", + "symptom.gtceu.death": "Death", + "symptom.gtceu.health_debuff": "Lowered maximum health", + "symptom.gtceu.hunger": "Increased appetite", + "symptom.gtceu.mining_fatigue": "Fatigue", + "symptom.gtceu.nausea": "Nausea", + "symptom.gtceu.poisoning": "Poisoning", + "symptom.gtceu.random_damage": "Occasional damage", + "symptom.gtceu.slowness": "Slowness", + "symptom.gtceu.weak_poisoning": "Weak poisoning", + "symptom.gtceu.weakness": "Weakness", + "symptom.gtceu.wither": "Necrosis", "tagprefix.andesite": "Andesite %s Ore", "tagprefix.basalt": "Basalt %s Ore", "tagprefix.blackstone": "Blackstone %s Ore", @@ -5920,5 +5957,17 @@ "tile.gtceu.petrified_foam.name": "Petrified Foam", "tile.gtceu.reinforced_foam.name": "Reinforced Foam", "tile.gtceu.reinforced_stone.name": "Reinforced Stone", - "tile.gtceu.seal.name": "Sealed Block" + "tile.gtceu.seal.name": "Sealed Block", + "tooltip.gtceu.antidote.description": "§aAntidote §7Hold Shift to show details", + "tooltip.gtceu.antidote.description.effect_removed": "Removes %s%% of current conditions' effects", + "tooltip.gtceu.antidote.description.effect_removed.all": "Removes all of current conditions' effects", + "tooltip.gtceu.antidote.description_shift": "§aCures these conditions:", + "tooltip.gtceu.hazard_trigger": "Caused by:", + "tooltip.gtceu.hazard_trigger.any": "Any contact", + "tooltip.gtceu.hazard_trigger.inhalation": "Inhalation", + "tooltip.gtceu.hazard_trigger.none": "Nothing", + "tooltip.gtceu.hazard_trigger.protection": "Protects from:", + "tooltip.gtceu.hazard_trigger.skin_contact": "Skin contact", + "tooltip.gtceu.medical_condition.description": "§l§cHAZARDOUS §7Hold Shift to show details", + "tooltip.gtceu.medical_condition.description_shift": "§l§cHAZARDOUS:" } \ 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 deleted file mode 100644 index d7f7f62336a..00000000000 --- a/src/generated/resources/data/gtceu/damage_type/medical_condition/berylliosis.json +++ /dev/null @@ -1,5 +0,0 @@ -{ - "exhaustion": 0.0, - "message_id": "gtceu.medical_condition/berylliosis", - "scaling": "never" -} \ 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 deleted file mode 100644 index 917b648aecf..00000000000 --- a/src/generated/resources/data/gtceu/damage_type/medical_condition/silicosis.json +++ /dev/null @@ -1,5 +0,0 @@ -{ - "exhaustion": 0.0, - "message_id": "gtceu.medical_condition/silicosis", - "scaling": "never" -} \ No newline at end of file diff --git a/src/generated/resources/data/minecraft/tags/damage_type/bypasses_armor.json b/src/generated/resources/data/minecraft/tags/damage_type/bypasses_armor.json index fc6bd8cfd19..cc2216956ca 100644 --- a/src/generated/resources/data/minecraft/tags/damage_type/bypasses_armor.json +++ b/src/generated/resources/data/minecraft/tags/damage_type/bypasses_armor.json @@ -9,8 +9,6 @@ "gtceu:medical_condition/carcinogen", "gtceu:medical_condition/asbestosis", "gtceu:medical_condition/arsenicosis", - "gtceu:medical_condition/silicosis", - "gtceu:medical_condition/berylliosis", "gtceu:medical_condition/methanol_poisoning", "gtceu:medical_condition/carbon_monoxide_poisoning", "gtceu:heat", diff --git a/src/generated/resources/data/minecraft/tags/damage_type/bypasses_cooldown.json b/src/generated/resources/data/minecraft/tags/damage_type/bypasses_cooldown.json new file mode 100644 index 00000000000..7789592165e --- /dev/null +++ b/src/generated/resources/data/minecraft/tags/damage_type/bypasses_cooldown.json @@ -0,0 +1,15 @@ +{ + "values": [ + "gtceu:medical_condition/none", + "gtceu:medical_condition/chemical_burns", + "gtceu:medical_condition/poison", + "gtceu:medical_condition/weak_poison", + "gtceu:medical_condition/irritant", + "gtceu:medical_condition/nausea", + "gtceu:medical_condition/carcinogen", + "gtceu:medical_condition/asbestosis", + "gtceu:medical_condition/arsenicosis", + "gtceu:medical_condition/methanol_poisoning", + "gtceu:medical_condition/carbon_monoxide_poisoning" + ] +} \ No newline at end of file diff --git a/src/generated/resources/data/minecraft/tags/damage_type/bypasses_invulnerability.json b/src/generated/resources/data/minecraft/tags/damage_type/bypasses_invulnerability.json new file mode 100644 index 00000000000..7789592165e --- /dev/null +++ b/src/generated/resources/data/minecraft/tags/damage_type/bypasses_invulnerability.json @@ -0,0 +1,15 @@ +{ + "values": [ + "gtceu:medical_condition/none", + "gtceu:medical_condition/chemical_burns", + "gtceu:medical_condition/poison", + "gtceu:medical_condition/weak_poison", + "gtceu:medical_condition/irritant", + "gtceu:medical_condition/nausea", + "gtceu:medical_condition/carcinogen", + "gtceu:medical_condition/asbestosis", + "gtceu:medical_condition/arsenicosis", + "gtceu:medical_condition/methanol_poisoning", + "gtceu:medical_condition/carbon_monoxide_poisoning" + ] +} \ No newline at end of file diff --git a/src/generated/resources/data/minecraft/tags/damage_type/bypasses_resistance.json b/src/generated/resources/data/minecraft/tags/damage_type/bypasses_resistance.json new file mode 100644 index 00000000000..7789592165e --- /dev/null +++ b/src/generated/resources/data/minecraft/tags/damage_type/bypasses_resistance.json @@ -0,0 +1,15 @@ +{ + "values": [ + "gtceu:medical_condition/none", + "gtceu:medical_condition/chemical_burns", + "gtceu:medical_condition/poison", + "gtceu:medical_condition/weak_poison", + "gtceu:medical_condition/irritant", + "gtceu:medical_condition/nausea", + "gtceu:medical_condition/carcinogen", + "gtceu:medical_condition/asbestosis", + "gtceu:medical_condition/arsenicosis", + "gtceu:medical_condition/methanol_poisoning", + "gtceu:medical_condition/carbon_monoxide_poisoning" + ] +} \ No newline at end of file diff --git a/src/main/java/com/gregtechceu/gtceu/api/capability/GTCapability.java b/src/main/java/com/gregtechceu/gtceu/api/capability/GTCapability.java index 66a0aa5c6b3..5ebaccf61d1 100644 --- a/src/main/java/com/gregtechceu/gtceu/api/capability/GTCapability.java +++ b/src/main/java/com/gregtechceu/gtceu/api/capability/GTCapability.java @@ -1,6 +1,7 @@ package com.gregtechceu.gtceu.api.capability; import com.gregtechceu.gtceu.api.machine.feature.multiblock.IMaintenanceMachine; +import com.gregtechceu.gtceu.common.capability.MedicalConditionTracker; import net.minecraftforge.common.capabilities.Capability; import net.minecraftforge.common.capabilities.CapabilityManager; @@ -33,7 +34,7 @@ public class GTCapability { public static final Capability CAPABILITY_MONITOR_COMPONENT = CapabilityManager .get(new CapabilityToken<>() {}); - public static final Capability CAPABILITY_MEDICAL_CONDITION_TRACKER = CapabilityManager + public static final Capability CAPABILITY_MEDICAL_CONDITION_TRACKER = CapabilityManager .get(new CapabilityToken<>() {}); public static void register(RegisterCapabilitiesEvent event) { @@ -48,7 +49,7 @@ public static void register(RegisterCapabilitiesEvent event) { event.register(ILaserContainer.class); event.register(IOpticalComputationProvider.class); event.register(IDataAccessHatch.class); - event.register(IMedicalConditionTracker.class); + event.register(MedicalConditionTracker.class); event.register(IHazardParticleContainer.class); event.register(IMonitorComponent.class); } 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 ddd096e5fab..973d8f534d2 100644 --- a/src/main/java/com/gregtechceu/gtceu/api/capability/GTCapabilityHelper.java +++ b/src/main/java/com/gregtechceu/gtceu/api/capability/GTCapabilityHelper.java @@ -1,6 +1,7 @@ package com.gregtechceu.gtceu.api.capability; import com.gregtechceu.gtceu.api.machine.feature.multiblock.IMaintenanceMachine; +import com.gregtechceu.gtceu.common.capability.MedicalConditionTracker; import net.minecraft.core.BlockPos; import net.minecraft.core.Direction; @@ -123,7 +124,7 @@ private static T getBlockEntityCapability(Capability capability, Level le } @Nullable - public static IMedicalConditionTracker getMedicalConditionTracker(@NotNull Entity entity) { + public static MedicalConditionTracker 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/IMedicalConditionTracker.java b/src/main/java/com/gregtechceu/gtceu/api/capability/IMedicalConditionTracker.java deleted file mode 100644 index 2479a48a36e..00000000000 --- a/src/main/java/com/gregtechceu/gtceu/api/capability/IMedicalConditionTracker.java +++ /dev/null @@ -1,40 +0,0 @@ -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/data/chemical/material/properties/HazardProperty.java b/src/main/java/com/gregtechceu/gtceu/api/data/chemical/material/properties/HazardProperty.java index 6f3a184a71a..dc39dbb59b9 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 @@ -2,7 +2,6 @@ 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.stack.MaterialEntry; import com.gregtechceu.gtceu.api.data.medicalcondition.MedicalCondition; import com.gregtechceu.gtceu.api.data.tag.TagPrefix; @@ -13,6 +12,7 @@ import com.gregtechceu.gtceu.config.ConfigHolder; import com.gregtechceu.gtceu.data.recipe.CustomTags; +import net.minecraft.network.chat.Component; import net.minecraft.util.StringRepresentable; import net.minecraft.world.entity.LivingEntity; import net.minecraft.world.entity.player.Player; @@ -21,6 +21,7 @@ import net.minecraft.world.item.ItemStack; import lombok.Getter; +import org.jetbrains.annotations.NotNull; import top.theillusivec4.curios.api.CuriosApi; import top.theillusivec4.curios.api.SlotResult; import top.theillusivec4.curios.api.type.capability.ICuriosItemHandler; @@ -57,6 +58,8 @@ public record HazardTrigger(String name, ProtectionType protectionType, Set CONDITIONS = new HashMap<>(); - public static final Codec CODEC = Codec.STRING.xmap(MedicalCondition.CONDITIONS::get, - MedicalCondition::getName); + public static final Codec CODEC = GTRegistries.MEDICAL_CONDITIONS.codec(); + public static final String AFFECTED_SUFFIX = ".affected"; - @Getter - public final String name; + /** + * The ID of this medical condition in the registry.
+ * The tooltip text is derived from this in the form of {@code "medical_condition.."} + *

+ * If the name of this medical condition is queried in the context of affecting a player, and a language key + * {@code "medical_condition...affected"} exists, it'll be used instead of the generic one.
+ * For example, the {@code gtceu:carcinogenic} medical condition's tooltip name is "Carcinogenic". + * When a player with cancer checks their status with {@code /medical_condition query}, + * the command will display "Player <player> has cancer" instead of "... has Carcinogenic" + *

+ */ + public final ResourceLocation id; public final int color; public final float maxProgression; // amount of seconds until maximum progression is reached public final Set symptoms = new HashSet<>(); @@ -36,47 +50,74 @@ public class MedicalCondition { public final float idleProgressionRate; public final boolean canBePermanent; /** - * This should mirror the {@link AirScrubberRecipes} recipe's outputs for this condition. + * This should mirror the associated {@linkplain AirScrubberRecipes air scrubber recipe's} outputs for this + * condition. */ @Getter @Setter @NotNull public Consumer recipeModifier = builder -> {}; - public MedicalCondition(String name, int color, int maxProgression, IdleProgressionType idleProgressionType, - float idleProgressionRate, boolean canBePermanent, Symptom.ConfiguredSymptom... symptoms) { - this.name = name; + public MedicalCondition(ResourceLocation id, int color, + int maxProgression, IdleProgressionType progressionType, float progressionRate, + boolean canBePermanent, Symptom.ConfiguredSymptom... symptoms) { + this.id = id; this.color = color; this.maxProgression = maxProgression; this.damageTypeData = new DamageTypeData.Builder() - .simpleId("medical_condition/" + name) + .simpleId(id.withPrefix("medical_condition/")) .scaling(DamageScaling.NEVER) - .tag(DamageTypeTags.BYPASSES_ARMOR) + // all medical conditions' damage types MUST have the bypasses_invulnerability and bypasses_cooldown + // tags so the death symptom works properly + .tag(DamageTypeTags.BYPASSES_ARMOR, DamageTypeTags.BYPASSES_RESISTANCE, + DamageTypeTags.BYPASSES_INVULNERABILITY, DamageTypeTags.BYPASSES_COOLDOWN) .build(); - this.symptoms.addAll(Arrays.asList(symptoms)); - this.idleProgressionType = idleProgressionType; - this.idleProgressionRate = idleProgressionRate; + for (Symptom.ConfiguredSymptom symptom : symptoms) { + symptom.addedToCondition(this, this.symptoms.size()); + this.symptoms.add(symptom); + } + this.idleProgressionType = progressionType; + this.idleProgressionRate = progressionRate; this.canBePermanent = canBePermanent; + } - CONDITIONS.put(name, this); + public DamageSource getDamageSource(MedicalConditionTracker tracker) { + return this.damageTypeData.source(tracker.getPlayer().level()); } - public MedicalCondition(String name, int color, int maxProgression, IdleProgressionType progressionType, - boolean canBePermanent, Symptom.ConfiguredSymptom... symptoms) { - this(name, color, maxProgression, progressionType, 1, canBePermanent, symptoms); + public DamageSource getDamageSource(Level level) { + return this.damageTypeData.source(level); } - public MedicalCondition(String name, int color, int maxProgression, Symptom.ConfiguredSymptom... symptoms) { - this(name, color, maxProgression, IdleProgressionType.NONE, 0, false, symptoms); + public String getTranslationKey() { + return this.id.toLanguageKey("medical_condition"); } - public DamageSource getDamageSource(MedicalConditionTracker tracker) { - return damageTypeData.source(tracker.getPlayer().level()); + public Component getTranslatableName() { + return Component.translatable(this.getTranslationKey()).withStyle(style -> style.withColor(this.color)); } - public DamageSource getDamageSource(Level level) { - return damageTypeData.source(level); + public Component getAffectedName() { + String key = this.getTranslationKey(); + String affectedKey = key + AFFECTED_SUFFIX; + if (Language.getInstance().has(affectedKey)) { + key = affectedKey; + } + return Component.translatable(key).withStyle(style -> style.withColor(this.color)); + } + + @Override + public String toString() { + StringJoiner stringJoiner = new StringJoiner(", ", "[", "]"); + stringJoiner.add("color=#" + FormattingUtil.HEX_FORMAT.toHexDigits(this.color)); + stringJoiner.add("maxProgression=" + this.maxProgression); + stringJoiner.add("symptoms=" + this.symptoms); + stringJoiner.add("damageType=" + this.damageTypeData.id); + stringJoiner.add("idleProgressionType=" + this.idleProgressionType.name().toLowerCase(Locale.ROOT)); + stringJoiner.add("idleProgressionRate=" + this.idleProgressionRate); + + return this.id.toString() + stringJoiner.toString(); } public enum IdleProgressionType { 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 index 154a2a69b99..9d933417b5d 100644 --- a/src/main/java/com/gregtechceu/gtceu/api/data/medicalcondition/Symptom.java +++ b/src/main/java/com/gregtechceu/gtceu/api/data/medicalcondition/Symptom.java @@ -1,86 +1,146 @@ 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.util.Mth; 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.AttributeInstance; 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 com.google.common.base.Preconditions; +import lombok.Getter; +import java.util.StringJoiner; import java.util.UUID; import java.util.function.Supplier; public class Symptom { + // spotless:off 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_MINING_FATIGUE_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), Float.MAX_VALUE); + public static final Symptom DEATH = new Symptom(defaultKey("death"), 1, 1.0f, 1.0f, + (tracker, condition, configuredSymptom, baseSymptom, stage) -> { + if (stage > 0) { + Player player = tracker.getPlayer(); + // this should replicate the logic in LivingEntity#kill, but + // with the medical condition's damage type instead of `generic_kill`. + player.hurt(condition.getDamageSource(tracker), Float.MAX_VALUE); } - })); - 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 RANDOM_DAMAGE = new Symptom(defaultKey("random_damage"), 10, 0.2f, 1.0f, + Effect.NO_OP, + (tracker, condition, configuredSymptom, baseSymptom, stage) -> { + int stages = configuredSymptom.getStages(); + if (stage > 0 && tracker.getPlayer().getRandom().nextInt(stages * 500 / stage) == 0) { + tracker.getPlayer().hurt(condition.getDamageSource(tracker), 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); + // default is 20, stage 10 result will be 10 + // the health debuff stage is a special case because it has to resync the player's current health to the client + public static final Symptom HEALTH_DEBUFF = new Symptom(defaultKey("health_debuff"), 10, 0.0f, 1.0f, + (tracker, $1, $2, symptom, stage) -> { + Player player = tracker.getPlayer(); + AttributeInstance instance = player.getAttribute(Attributes.MAX_HEALTH); + if (instance == null) { + return; + } + instance.removeModifier(SYMPTOM_HEALTH_DEBUFF_UUID); + + if (stage != 0) { + instance.addPermanentModifier(new AttributeModifier(SYMPTOM_HEALTH_DEBUFF_UUID, symptom.name, + -stage, AttributeModifier.Operation.ADDITION)); + } + // reset the health data value so the max health change is applied immediately + if (player.getHealth() > player.getMaxHealth()) { + player.setHealth(player.getHealth()); + } + }); + // default is 4, stage 10 result will be 1.6 + public static final Symptom MINING_FATIGUE = Symptom.ofAttributeModifier(defaultKey("mining_fatigue"), 10, 0.0f, 1.0f, + 0.04f, Attributes.ATTACK_SPEED, SYMPTOM_MINING_FATIGUE_UUID); + // default is 2, stage 10 result will be 0.5 + public static final Symptom WEAKNESS = Symptom.ofAttributeModifier(defaultKey("weakness"), 10, 0.0f, 1.0f, + 0.025f, Attributes.ATTACK_DAMAGE, SYMPTOM_WEAKNESS_UUID); + // default is 0.1, stage 7 result will be 0.065 + // REMEMBER TO UPDATE TESTS IF YOU CHANGE THIS + public static final Symptom SLOWNESS = Symptom.ofAttributeModifier(defaultKey("slowness"), 7, 0.0f, 1.0f, + 0.05f, Attributes.MOVEMENT_SPEED, SYMPTOM_SLOWNESS_UUID); + // default is 300, stage 10 result will be 200 + public static final Symptom AIR_SUPPLY_DEBUFF = new Symptom(defaultKey("air_supply_debuff"), 10, 0.0f, 1.0f, + (tracker, condition, configuredSymptom, baseSymptom, stage) -> { + if (stage != 0) { + tracker.getPlayer().gtceu$setMaxAirSupply(tracker.getPlayer().gtceu$getOriginalMaxAirSupply() - 10 * stage); + } else { + tracker.getPlayer().gtceu$setMaxAirSupply(-1); + } + }); + + public static final Symptom BLINDNESS = Symptom.ofEffect(defaultKey("blindness"), 10, 0.0f, 1.0f, MobEffects.BLINDNESS); + public static final Symptom DARKNESS = Symptom.ofEffect(defaultKey("darkness"), 10, 0.0f, 1.0f, MobEffects.DARKNESS); + public static final Symptom NAUSEA = Symptom.ofEffect(defaultKey("nausea"), 1, 0.95f, 1.0f, MobEffects.CONFUSION); + public static final Symptom WITHER = Symptom.ofEffect(defaultKey("wither"), 1, 1.0f, 1.0f, MobEffects.WITHER); + public static final Symptom WEAK_POISONING = Symptom.ofEffect(defaultKey("weak_poisoning"), 10, 0.0f, 1.0f, GTMobEffects.WEAK_POISON); + public static final Symptom POISONING = Symptom.ofEffect(defaultKey("poisoning"), 10, 0.0f, 1.0f, MobEffects.POISON); + public static final Symptom HUNGER = Symptom.ofEffect(defaultKey("hunger"), 5, 0.0f, 1.0f, MobEffects.HUNGER); + // spotless:on public final String name; public final int defaultStages; - public final float defaultProgressionThreshold; + /** + * The (relative) threshold this symptom will start occurring at.
+ * The range is [0.0,1.0], with 0.0 meaning "as soon as the player gains the condition" + * and 1.0 meaning "at the condition's max progress value". + *

+ * If this symptom's {@link #defaultStages} is >0, the symptom will start occurring at + * {@link #minThreshold} and the maximum stage will be reached at {@link #maxThreshold}. + *

+ *

+ * For example: The relative minimum threshold of this symptom is 0.5 and + * the condition's maximum progress is 200 seconds. + * This symptom will start occurring when the player has had the condition for 100 seconds. + *

+ */ + public final float minThreshold; + /** + * The (relative) threshold at which this symptom will be reach its maximum potential.
+ * The range is [0.0,1.0], with 0.0 meaning "as soon as the player gains the condition" + * and 1.0 meaning "at the condition's max progress value". + *

+ * If this symptom's {@link #defaultStages} is >0, the symptom will start occurring at + * {@link #minThreshold} and the maximum stage will be reached at {@link #maxThreshold}. + *

+ *

+ * For example: tThe relative maximum threshold of this symptom is 0.75 and the + * condition's maximum progress is 200 seconds. + * This symptom will reach its peak when the player has had the condition for 150 seconds. + *

+ */ + public final float maxThreshold; - // 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, + public Symptom(String name, int defaultStages, float minThreshold, float maxThreshold, Effect progressionEffect, Effect tickEffect) { this.name = name; this.defaultStages = defaultStages; - this.defaultProgressionThreshold = defaultProgressionThreshold; + this.minThreshold = minThreshold; + this.maxThreshold = maxThreshold; 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) -> {}); + public Symptom(String name, int defaultStages, float minThreshold, float maxThreshold, Effect progressionEffect) { + this(name, defaultStages, minThreshold, maxThreshold, progressionEffect, Effect.NO_OP); } /** @@ -88,107 +148,201 @@ public Symptom(String name, int defaultStages, float defaultProgressionThreshold * @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)) { + public static Symptom ofAttributeModifier(String name, int defaultStages, float minThreshold, float maxThreshold, + float multiplier, Attribute attribute, UUID uuid) { + return new Symptom(name, defaultStages, minThreshold, maxThreshold, + (tracker, condition, symptom, baseSymptom, stage) -> { + Player player = tracker.getPlayer(); + AttributeInstance instance = player.getAttribute(attribute); + if (instance == null) { 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()); + instance.removeModifier(uuid); + + if (stage != 0) { + instance.addPermanentModifier(new AttributeModifier(uuid, name, + -stage * multiplier, AttributeModifier.Operation.MULTIPLY_BASE)); } - })); + }); } /** - * @param mobEffect MobEffect to apply - * @param amplifierMultiplier amplifier added to MobEffect every progression + * @param mobEffect effect to apply + * @param amplifierMultiplier amplifier added to effect every progression tick */ - 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)); + public static Symptom ofEffect(String name, int defaultStages, float minThreshold, float maxThreshold, + Supplier mobEffect, int amplifierMultiplier) { + return new Symptom(name, defaultStages, minThreshold, maxThreshold, + (tracker, $1, $2, $3, stage) -> { + MobEffect effect = mobEffect.get(); + tracker.setMobEffect(effect, amplifierMultiplier * stage); + if (stage == 0) { + tracker.getPlayer().removeEffect(effect); + } + }); } /** * @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)); + public static Symptom ofEffect(String name, int defaultStages, float minThreshold, float maxThreshold, + MobEffect mobEffect, int amplifierMultiplier) { + return ofEffect(name, defaultStages, minThreshold, maxThreshold, + () -> mobEffect, amplifierMultiplier); } /** - * @param mobEffect MobEffect to apply + * @param mobEffect effect 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)); + public static Symptom ofEffect(String name, int defaultStages, float minThreshold, float maxThreshold, + Supplier mobEffect) { + return ofEffect(name, defaultStages, minThreshold, maxThreshold, mobEffect, 1); } /** - * @param mobEffect MobEffect to apply + * @param mobEffect effect 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 static Symptom ofEffect(String name, int defaultStages, float minThreshold, float maxThreshold, + MobEffect mobEffect) { + return ofEffect(name, defaultStages, minThreshold, maxThreshold, () -> mobEffect); } public void applyProgression(MedicalConditionTracker subject, MedicalCondition condition, - @Nullable ConfiguredSymptom symptom, int modifier) { - progressionEffect.apply(subject, condition, symptom, this, modifier); + ConfiguredSymptom symptom, int stage) { + progressionEffect.apply(subject, condition, symptom, this, stage); } public void tick(MedicalConditionTracker subject, MedicalCondition condition, - @Nullable ConfiguredSymptom symptom, int modifier) { - tickEffect.apply(subject, condition, symptom, this, modifier); + ConfiguredSymptom symptom, int stage) { + tickEffect.apply(subject, condition, symptom, this, stage); + } + + @Override + public String toString() { + return this.name; } public static class ConfiguredSymptom { - public final Symptom symptom; - public final int stages; - public final float progressionThreshold; - public final float relativeHarshness; + @Getter + private final Symptom symptom; + @Getter + private final int stages; + @Getter + private final float relativeHarshness; + /** + * The threshold this symptom will start occurring at. + *

+ * If this symptom's {@link #stages} is >0, the symptom will start occurring at {@link #minThreshold} + * and the maximum stage will be reached at {@link #maxThreshold}. + *

+ *

+ * For example: The minimum threshold of this symptom is 100 and + * the condition's maximum progress is 200 seconds. + * This symptom will start occurring when the player has had the condition for 100 seconds. + *

+ */ + @Getter + private float minThreshold; + /** + * The threshold at which this symptom will be reach its maximum potential. + *

+ * If this symptom's {@link #stages} is >0, the symptom will start occurring at {@link #minThreshold} + * and the maximum stage will be reached at {@link #maxThreshold}. + *

+ *

+ * For example: The maximum threshold of this symptom is 150 and + * the condition's maximum progress is 200 seconds. + * This symptom will reach its peak when the player has had the condition for 150 seconds. + *

+ */ + @Getter + private float maxThreshold; - public ConfiguredSymptom(Symptom symptom, int stages, float progressionThreshold) { + /** + * Whether this {@code ConfiguredSymptom} uses the default progression thresholds for its {@link #symptom} + * and should recalculate absolute progression values for the {@linkplain MedicalCondition} it's a part of + */ + private boolean relativeThresholds = false; + + protected ConfiguredSymptom(Symptom symptom, int stages, + float relativeMinThreshold, float relativeMaxThreshold) { this.symptom = symptom; this.stages = stages; - this.progressionThreshold = progressionThreshold; this.relativeHarshness = (float) stages / symptom.defaultStages; + + this.minThreshold = relativeMinThreshold; + this.maxThreshold = relativeMaxThreshold; } - public ConfiguredSymptom(Symptom symptom) { - this(symptom, symptom.defaultStages, symptom.defaultProgressionThreshold); + public ConfiguredSymptom(Symptom symptom, int stages, int absMinThreshold, int absMaxThreshold) { + this(symptom, stages, (float) absMinThreshold, (float) absMaxThreshold); + } + + public ConfiguredSymptom(Symptom symptom, int absMinThreshold, int absMaxThreshold) { + this(symptom, symptom.defaultStages, absMinThreshold, absMaxThreshold); } public ConfiguredSymptom(Symptom symptom, int stages) { - this(symptom, stages, symptom.defaultProgressionThreshold); + this(symptom, stages, symptom.minThreshold, symptom.maxThreshold); + this.relativeThresholds = true; } - public ConfiguredSymptom(Symptom symptom, float progressionThreshold) { - this(symptom, symptom.defaultStages, progressionThreshold); + public ConfiguredSymptom(Symptom symptom) { + this(symptom, symptom.defaultStages); + } + + /** + * Update the stored progression threshold values based on the passed condition's + * {@link MedicalCondition#maxProgression maxProgression} value + * + * @param condition the medical condition that the threshold values will be based on + * @param index the index in the condition's symptom list this symptom will be added to + */ + public void addedToCondition(MedicalCondition condition, int index) { + if (this.relativeThresholds) { + this.relativeThresholds = false; + this.minThreshold = this.minThreshold * condition.maxProgression; + this.maxThreshold = this.maxThreshold * condition.maxProgression; + } + + this.minThreshold = Mth.clamp(this.minThreshold, 0.0f, condition.maxProgression); + this.maxThreshold = Mth.clamp(this.maxThreshold, 0.0f, condition.maxProgression); + + Preconditions.checkArgument(minThreshold <= maxThreshold, + "minProgressThreshold must be <= maxProgressThreshold for symptom %s (%s) of condition %s (min %s > max %s)", + index, symptom.name, condition.id.toString(), minThreshold, maxThreshold); + } + + @Override + public String toString() { + StringJoiner stringJoiner = new StringJoiner(", ", "[", "]"); + stringJoiner.add("stages=" + this.stages); + stringJoiner.add("relativeHarshness=" + this.relativeHarshness); + stringJoiner.add("minTreshold=" + this.minThreshold); + stringJoiner.add("maxTreshold=" + this.maxThreshold); + + return this.symptom.toString() + stringJoiner; } } @FunctionalInterface public interface Effect { + Effect NO_OP = (tracker, condition, configuredSymptom, baseSymptom, amplifier) -> {}; + + /** + * If {@code stage} is 0, any effects should be removed. + * + * @param tracker the medical condition tracker processing this effect + * @param condition the medical condition this symptom belongs to + * @param configuredSymptom the symptom this effect belongs to + * @param baseSymptom the unconfigured symptom + * @param stage the stage of this symptom + */ void apply(MedicalConditionTracker tracker, MedicalCondition condition, - @Nullable ConfiguredSymptom configuredSymptom, Symptom baseSymptom, int amplifier); + ConfiguredSymptom configuredSymptom, Symptom baseSymptom, int stage); } private static String defaultKey(String name) { diff --git a/src/main/java/com/gregtechceu/gtceu/api/registry/GTRegistries.java b/src/main/java/com/gregtechceu/gtceu/api/registry/GTRegistries.java index 67f38bf2942..a42b600a203 100644 --- a/src/main/java/com/gregtechceu/gtceu/api/registry/GTRegistries.java +++ b/src/main/java/com/gregtechceu/gtceu/api/registry/GTRegistries.java @@ -5,6 +5,7 @@ import com.gregtechceu.gtceu.api.cover.CoverDefinition; import com.gregtechceu.gtceu.api.data.DimensionMarker; import com.gregtechceu.gtceu.api.data.chemical.Element; +import com.gregtechceu.gtceu.api.data.medicalcondition.MedicalCondition; import com.gregtechceu.gtceu.api.data.worldgen.GTOreDefinition; import com.gregtechceu.gtceu.api.data.worldgen.bedrockfluid.BedrockFluidDefinition; import com.gregtechceu.gtceu.api.data.worldgen.bedrockore.BedrockOreDefinition; @@ -65,6 +66,9 @@ public final class GTRegistries { public static final GTRegistry.RL ORE_VEINS = new GTRegistry.RL<>(GTCEu.id("ore_vein")); public static final GTRegistry.RL DIMENSION_MARKERS = new GTRegistry.RL<>( GTCEu.id("dimension_marker")); + public static final GTRegistry.RL MEDICAL_CONDITIONS = new GTRegistry.RL<>( + GTCEu.id("medical_condition")); + public static final DeferredRegister> TRUNK_PLACER_TYPE = DeferredRegister .create(Registries.TRUNK_PLACER_TYPE, GTCEu.MOD_ID); public static final DeferredRegister> PLACEMENT_MODIFIER = DeferredRegister diff --git a/src/main/java/com/gregtechceu/gtceu/client/TooltipsHandler.java b/src/main/java/com/gregtechceu/gtceu/client/TooltipsHandler.java index 780f55eeadb..bcdb461bd08 100644 --- a/src/main/java/com/gregtechceu/gtceu/client/TooltipsHandler.java +++ b/src/main/java/com/gregtechceu/gtceu/client/TooltipsHandler.java @@ -73,7 +73,7 @@ public static void appendTooltips(ItemStack stack, TooltipFlag flag, List event) { if (event.getObject() instanceof Player entity) { final MedicalConditionTracker tracker = new MedicalConditionTracker(entity); - event.addCapability(GTCEu.id("medical_condition_tracker"), new ICapabilitySerializable() { - - @Override - public CompoundTag serializeNBT() { - return tracker.serializeNBT(); - } - - @Override - public void deserializeNBT(CompoundTag arg) { - tracker.deserializeNBT(arg); - } - - @Override - public @NotNull LazyOptional getCapability(@NotNull Capability capability, - @Nullable Direction arg) { - return GTCapability.CAPABILITY_MEDICAL_CONDITION_TRACKER.orEmpty(capability, - LazyOptional.of(() -> tracker)); - } - }); + event.addCapability(GTCEu.id("medical_condition_tracker"), tracker); } } @@ -171,13 +149,18 @@ public static void registerCapes(RegisterGTCapesEvent event) { } @SubscribeEvent - public static void tickPlayerInventoryHazards(TickEvent.PlayerTickEvent event) { + public static void tickPlayerHazards(TickEvent.PlayerTickEvent event) { if (event.side == LogicalSide.CLIENT || event.phase != TickEvent.Phase.END) { return; } Player player = event.player; - IMedicalConditionTracker tracker = GTCapabilityHelper.getMedicalConditionTracker(player); + // update the tracker every second, including clearing everything when the config changes. + if (player.tickCount % 20 != 0) { + return; + } + + MedicalConditionTracker tracker = GTCapabilityHelper.getMedicalConditionTracker(player); if (tracker == null) { return; } @@ -192,22 +175,23 @@ public static void tickPlayerInventoryHazards(TickEvent.PlayerTickEvent event) { if (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.isNull() || !material.hasProperty(PropertyKey.HAZARD)) { + MaterialEntry entry = HazardProperty.getValidHazardMaterial(stack); + if (entry.material().isNull()) { continue; } - HazardProperty property = material.getProperty(PropertyKey.HAZARD); + HazardProperty property = entry.material().getProperty(PropertyKey.HAZARD); if (property.hazardTrigger.protectionType().isProtected(player)) { // entity has proper safety equipment, so damage it per material every 5 seconds. property.hazardTrigger.protectionType().damageEquipment(player, 1); // don't progress this material condition if entity is protected continue; } - tracker.progressRelatedCondition(material); + tracker.progressRelatedCondition(entry, stack.getCount()); } } @@ -230,6 +214,31 @@ public static void onMobEffectEvent(MobEffectEvent.Applicable event) { } } + @SubscribeEvent + public static void onItemUseFinished(LivingEntityUseItemEvent.Finish event) { + if (!(event.getEntity() instanceof Player player) || player.level().isClientSide) { + return; + } + + ItemStack usedItem = event.getItem(); + if (!usedItem.isEdible()) { + return; + } + MedicalConditionTracker tracker = GTCapabilityHelper.getMedicalConditionTracker(player); + if (tracker == null) { + return; + } + + MaterialEntry entry = HazardProperty.getValidHazardMaterial(usedItem); + if (entry.material().isNull()) { + return; + } + HazardProperty property = entry.material().getProperty(PropertyKey.HAZARD); + if (property.hazardTrigger == HazardProperty.HazardTrigger.CONSUMPTION) { + tracker.progressRelatedCondition(entry, 1); + } + } + @SubscribeEvent public static void onLeftClickBlock(PlayerInteractEvent.LeftClickBlock event) { var machine = MetaMachine.getMachine(event.getLevel(), event.getPos()); @@ -432,7 +441,7 @@ public static void stepAssistHandler(LivingEvent.LivingTickEvent event) { @SubscribeEvent public static void onEntityDie(LivingDeathEvent event) { if (event.getEntity() instanceof Player player) { - IMedicalConditionTracker tracker = GTCapabilityHelper.getMedicalConditionTracker(player); + MedicalConditionTracker tracker = GTCapabilityHelper.getMedicalConditionTracker(player); if (tracker == null) { return; } @@ -504,6 +513,77 @@ public static void onEquipmentChange(LivingEquipmentChangeEvent event) { } } + @SubscribeEvent + public static void modifyBreakSpeed(PlayerEvent.BreakSpeed event) { + Player player = event.getEntity(); + for (ItemStack stack : player.getArmorSlots()) { + if (!(stack.getItem() instanceof ArmorComponentItem componentItem)) { + continue; + } + if (!(componentItem.getArmorLogic() instanceof IJetpack jetpack) || !jetpack.removeMiningSpeedPenalty()) { + continue; + } + // undo flight mining speed debuff + if (!player.onGround()) { + event.setNewSpeed(event.getNewSpeed() * 5); + } + // and also underwater debuff + if (player.isEyeInFluidType(ForgeMod.WATER_TYPE.get()) && !EnchantmentHelper.hasAquaAffinity(player)) { + event.setNewSpeed(event.getNewSpeed() * 5); + } + } + + MedicalConditionTracker tracker = GTCapabilityHelper.getMedicalConditionTracker(player); + if (tracker == null || !ConfigHolder.INSTANCE.gameplay.hazardsEnabled) { + return; + } + if (player.getAttributes().hasModifier(Attributes.ATTACK_SPEED, Symptom.SYMPTOM_MINING_FATIGUE_UUID)) { + float miningFatigueModifier = (float) player.getAttributes() + .getModifierValue(Attributes.ATTACK_SPEED, Symptom.SYMPTOM_MINING_FATIGUE_UUID); + // mimic how AttributeInstance handles MULTIPLY_BASE modifiers + event.setNewSpeed(event.getNewSpeed() + event.getNewSpeed() * miningFatigueModifier); + } + } + + @SubscribeEvent + public static void addAlloyBlastProperties(PostMaterialEvent event) { + for (Material material : GTCEuAPI.materialManager.getRegisteredMaterials()) { + if (!material.hasFlag(MaterialFlags.DISABLE_ALLOY_PROPERTY)) { + addAlloyBlastProperty(material); + } + } + // Alloy Blast Overriding + GTMaterials.NiobiumNitride.getProperty(PropertyKey.ALLOY_BLAST) + .setRecipeProducer(new CustomAlloyBlastRecipeProducer(1, 11, -1)); + + GTMaterials.IndiumTinBariumTitaniumCuprate.getProperty(PropertyKey.ALLOY_BLAST) + .setRecipeProducer(new CustomAlloyBlastRecipeProducer(-1, -1, 16)); + } + + public static void addAlloyBlastProperty(@NotNull Material material) { + final List components = material.getMaterialComponents(); + // ignore materials which are not alloys + if (components.size() < 2) return; + + BlastProperty blastProperty = material.getProperty(PropertyKey.BLAST); + if (blastProperty == null) return; + + if (!material.hasProperty(PropertyKey.FLUID)) return; + + // if there are more than 2 fluid-only components in the material, do not generate a hot fluid + if (components.stream().filter(CommonEventListener::isMaterialStackFluidOnly).limit(3).count() > 2) { + return; + } + + material.setProperty(PropertyKey.ALLOY_BLAST, new AlloyBlastProperty(material.getBlastTemperature())); + material.getProperty(PropertyKey.FLUID).getStorage().enqueueRegistration(FluidStorageKeys.MOLTEN, + new FluidBuilder().state(FluidState.LIQUID)); + } + + private static boolean isMaterialStackFluidOnly(@NotNull MaterialStack ms) { + return !ms.material().hasProperty(PropertyKey.DUST) && ms.material().hasProperty(PropertyKey.FLUID); + } + @SubscribeEvent public static void remapIds(MissingMappingsEvent event) { event.getMappings(Registries.BLOCK, GTCEu.MOD_ID).forEach(mapping -> { @@ -663,55 +743,4 @@ public static void remapIds(MissingMappingsEvent event) { }); } } - - @SubscribeEvent - public static void breakSpeed(PlayerEvent.BreakSpeed event) { - Player player = event.getEntity(); - for (ItemStack stack : player.getArmorSlots()) { - if (stack.getItem() instanceof ArmorComponentItem componentItem) { - if (componentItem.getArmorLogic() instanceof IJetpack jetpack && jetpack.removeMiningSpeedPenalty()) { - if (!player.onGround() || player.isUnderWater()) event.setNewSpeed(event.getOriginalSpeed() * 5); - } - } - } - } - - @SubscribeEvent - public static void addAlloyBlastProperties(PostMaterialEvent event) { - for (Material material : GTCEuAPI.materialManager.getRegisteredMaterials()) { - if (!material.hasFlag(MaterialFlags.DISABLE_ALLOY_PROPERTY)) { - addAlloyBlastProperty(material); - } - } - // Alloy Blast Overriding - GTMaterials.NiobiumNitride.getProperty(PropertyKey.ALLOY_BLAST) - .setRecipeProducer(new CustomAlloyBlastRecipeProducer(1, 11, -1)); - - GTMaterials.IndiumTinBariumTitaniumCuprate.getProperty(PropertyKey.ALLOY_BLAST) - .setRecipeProducer(new CustomAlloyBlastRecipeProducer(-1, -1, 16)); - } - - public static void addAlloyBlastProperty(@NotNull Material material) { - final List components = material.getMaterialComponents(); - // ignore materials which are not alloys - if (components.size() < 2) return; - - BlastProperty blastProperty = material.getProperty(PropertyKey.BLAST); - if (blastProperty == null) return; - - if (!material.hasProperty(PropertyKey.FLUID)) return; - - // if there are more than 2 fluid-only components in the material, do not generate a hot fluid - if (components.stream().filter(CommonEventListener::isMaterialStackFluidOnly).limit(3).count() > 2) { - return; - } - - material.setProperty(PropertyKey.ALLOY_BLAST, new AlloyBlastProperty(material.getBlastTemperature())); - material.getProperty(PropertyKey.FLUID).getStorage().enqueueRegistration(FluidStorageKeys.MOLTEN, - new FluidBuilder().state(FluidState.LIQUID)); - } - - private static boolean isMaterialStackFluidOnly(@NotNull MaterialStack ms) { - return !ms.material().hasProperty(PropertyKey.DUST) && ms.material().hasProperty(PropertyKey.FLUID); - } } diff --git a/src/main/java/com/gregtechceu/gtceu/common/CommonProxy.java b/src/main/java/com/gregtechceu/gtceu/common/CommonProxy.java index 68b203df551..ccd0d830521 100644 --- a/src/main/java/com/gregtechceu/gtceu/common/CommonProxy.java +++ b/src/main/java/com/gregtechceu/gtceu/common/CommonProxy.java @@ -128,6 +128,7 @@ public static void init() { MaterialIconSet.init(); MaterialIconType.init(); initMaterials(); + GTMedicalConditions.init(); TagPrefix.init(); GTSoundEntries.init(); GTDamageTypes.init(); diff --git a/src/main/java/com/gregtechceu/gtceu/common/capability/EnvironmentalHazardSavedData.java b/src/main/java/com/gregtechceu/gtceu/common/capability/EnvironmentalHazardSavedData.java index c15fe81bafc..b47e9e9f210 100644 --- a/src/main/java/com/gregtechceu/gtceu/common/capability/EnvironmentalHazardSavedData.java +++ b/src/main/java/com/gregtechceu/gtceu/common/capability/EnvironmentalHazardSavedData.java @@ -1,9 +1,10 @@ package com.gregtechceu.gtceu.common.capability; +import com.gregtechceu.gtceu.GTCEu; 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.api.registry.GTRegistries; import com.gregtechceu.gtceu.common.network.GTNetwork; import com.gregtechceu.gtceu.common.network.packets.hazard.SPacketAddHazardZone; import com.gregtechceu.gtceu.common.network.packets.hazard.SPacketRemoveHazardZone; @@ -16,6 +17,7 @@ import net.minecraft.nbt.NbtUtils; import net.minecraft.nbt.Tag; import net.minecraft.network.FriendlyByteBuf; +import net.minecraft.resources.ResourceLocation; import net.minecraft.server.level.ServerLevel; import net.minecraft.server.level.ServerPlayer; import net.minecraft.world.level.ChunkPos; @@ -71,6 +73,9 @@ public EnvironmentalHazardSavedData(ServerLevel serverLevel, CompoundTag tag) { ChunkPos source = new ChunkPos(zoneTag.getLong("pos")); HazardZone zone = HazardZone.deserializeNBT(zoneTag); + if (zone == null) { + continue; + } this.hazardZones.put(source, zone); } @@ -153,7 +158,7 @@ public void tickPlayerHazards(final HazardZone zone, Stream player return; } - IMedicalConditionTracker tracker = GTCapabilityHelper.getMedicalConditionTracker(player); + MedicalConditionTracker tracker = GTCapabilityHelper.getMedicalConditionTracker(player); if (tracker == null) { return; } @@ -285,19 +290,22 @@ public CompoundTag serializeNBT(CompoundTag zoneTag) { zoneTag.putFloat("strength", strength); zoneTag.putBoolean("can_spread", canSpread); zoneTag.putString("trigger", trigger.name()); - zoneTag.putString("condition", condition.name); + zoneTag.putString("condition", condition.id.toString()); return zoneTag; } - public static HazardZone deserializeNBT(CompoundTag zoneTag) { + public static @Nullable HazardZone deserializeNBT(CompoundTag zoneTag) { BlockPos source = NbtUtils.readBlockPos(zoneTag.getCompound("source")); float strength = zoneTag.getFloat("strength"); boolean canSpread = zoneTag.getBoolean("can_spread"); HazardProperty.HazardTrigger trigger = HazardProperty.HazardTrigger.ALL_TRIGGERS .get(zoneTag.getString("trigger")); - MedicalCondition condition = com.gregtechceu.gtceu.api.data.medicalcondition.MedicalCondition.CONDITIONS - .get(zoneTag.getString("condition")); + ResourceLocation id = GTCEu.id(zoneTag.getString("condition")); + if (!GTRegistries.MEDICAL_CONDITIONS.containKey(id)) { + return null; + } + MedicalCondition condition = GTRegistries.MEDICAL_CONDITIONS.get(id); return new HazardZone(source, strength, canSpread, trigger, condition); } @@ -307,7 +315,7 @@ public void toNetwork(FriendlyByteBuf buf) { buf.writeFloat(strength); buf.writeBoolean(canSpread); buf.writeUtf(trigger.name()); - buf.writeUtf(condition.name); + buf.writeResourceLocation(condition.id); } public static HazardZone fromNetwork(FriendlyByteBuf buf) { @@ -315,7 +323,7 @@ public static HazardZone fromNetwork(FriendlyByteBuf buf) { float strength = buf.readFloat(); boolean canSpread = buf.readBoolean(); HazardProperty.HazardTrigger trigger = HazardProperty.HazardTrigger.ALL_TRIGGERS.get(buf.readUtf()); - MedicalCondition condition = MedicalCondition.CONDITIONS.get(buf.readUtf()); + MedicalCondition condition = GTRegistries.MEDICAL_CONDITIONS.get(buf.readResourceLocation()); return new HazardZone(source, strength, canSpread, trigger, condition); } } diff --git a/src/main/java/com/gregtechceu/gtceu/common/capability/LocalizedHazardSavedData.java b/src/main/java/com/gregtechceu/gtceu/common/capability/LocalizedHazardSavedData.java index 3e345aa7b74..497f787dfa2 100644 --- a/src/main/java/com/gregtechceu/gtceu/common/capability/LocalizedHazardSavedData.java +++ b/src/main/java/com/gregtechceu/gtceu/common/capability/LocalizedHazardSavedData.java @@ -1,10 +1,11 @@ package com.gregtechceu.gtceu.common.capability; +import com.gregtechceu.gtceu.GTCEu; 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.api.registry.GTRegistries; import com.gregtechceu.gtceu.common.particle.HazardParticleOptions; import com.gregtechceu.gtceu.config.ConfigHolder; import com.gregtechceu.gtceu.utils.BreadthFirstBlockSearch; @@ -14,6 +15,7 @@ import net.minecraft.nbt.ListTag; import net.minecraft.nbt.NbtUtils; import net.minecraft.nbt.Tag; +import net.minecraft.resources.ResourceLocation; import net.minecraft.server.level.ServerLevel; import net.minecraft.server.level.ServerPlayer; import net.minecraft.util.RandomSource; @@ -119,7 +121,7 @@ public void tickPlayerHazards(final HazardZone zone, Stream player return; } - IMedicalConditionTracker tracker = GTCapabilityHelper.getMedicalConditionTracker(player); + MedicalConditionTracker tracker = GTCapabilityHelper.getMedicalConditionTracker(player); if (tracker == null) { return; } @@ -318,7 +320,7 @@ public CompoundTag serializeNBT(CompoundTag zoneTag) { zoneTag.put("blocks", blocksTag); zoneTag.putBoolean("can_spread", canSpread); zoneTag.putString("trigger", trigger.name()); - zoneTag.putString("condition", condition.name); + zoneTag.putString("condition", condition.id.toString()); return zoneTag; } @@ -331,7 +333,12 @@ public static HazardZone deserializeNBT(CompoundTag zoneTag) { 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")); + + ResourceLocation id = GTCEu.id(zoneTag.getString("condition")); + if (!GTRegistries.MEDICAL_CONDITIONS.containKey(id)) { + return null; + } + MedicalCondition condition = GTRegistries.MEDICAL_CONDITIONS.get(id); 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 index 4a38d76fe08..b2754afada1 100644 --- a/src/main/java/com/gregtechceu/gtceu/common/capability/MedicalConditionTracker.java +++ b/src/main/java/com/gregtechceu/gtceu/common/capability/MedicalConditionTracker.java @@ -1,123 +1,137 @@ package com.gregtechceu.gtceu.common.capability; -import com.gregtechceu.gtceu.api.capability.IMedicalConditionTracker; +import com.gregtechceu.gtceu.GTCEu; +import com.gregtechceu.gtceu.api.GTValues; +import com.gregtechceu.gtceu.api.capability.forge.GTCapability; +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.stack.MaterialEntry; import com.gregtechceu.gtceu.api.data.medicalcondition.MedicalCondition; +import com.gregtechceu.gtceu.api.data.medicalcondition.MedicalCondition.IdleProgressionType; import com.gregtechceu.gtceu.api.data.medicalcondition.Symptom; +import com.gregtechceu.gtceu.api.data.medicalcondition.Symptom.ConfiguredSymptom; +import com.gregtechceu.gtceu.api.registry.GTRegistries; +import net.minecraft.core.Direction; import net.minecraft.nbt.CompoundTag; import net.minecraft.nbt.ListTag; import net.minecraft.nbt.StringTag; import net.minecraft.nbt.Tag; +import net.minecraft.resources.ResourceLocation; +import net.minecraft.util.Mth; 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 net.minecraftforge.common.capabilities.Capability; +import net.minecraftforge.common.capabilities.ICapabilitySerializable; +import net.minecraftforge.common.util.LazyOptional; -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 it.unimi.dsi.fastutil.objects.*; import lombok.Getter; -import lombok.Setter; import org.jetbrains.annotations.NotNull; +import org.jetbrains.annotations.Nullable; +import org.jetbrains.annotations.VisibleForTesting; import java.util.*; -public class MedicalConditionTracker implements IMedicalConditionTracker, INBTSerializable { +public class MedicalConditionTracker implements ICapabilitySerializable { @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<>(); + @VisibleForTesting + final Reference2FloatOpenHashMap medicalConditions = new Reference2FloatOpenHashMap<>(); + private final Set permanentConditions = new ReferenceOpenHashSet<>(); + @Getter + private final Object2IntMap activeSymptoms = new Object2IntOpenHashMap<>(); + private final Reference2IntMap activeMobEffects = new Reference2IntOpenHashMap<>(); - @Setter - private int maxAirSupply = -1; + private final Set flaggedForRemoval = new ReferenceOpenHashSet<>(); @Getter private final Player player; + private final LazyOptional holder = LazyOptional.of(() -> this); + public MedicalConditionTracker(Player player) { this.player = player; } - @Override public void tick() { if (player.isCreative()) return; - for (var entry : activeMobEffects.object2IntEntrySet()) { + for (var entry : activeMobEffects.reference2IntEntrySet()) { 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); + for (MedicalCondition condition : medicalConditions.keySet()) { + if (condition.idleProgressionType == IdleProgressionType.NONE || + condition.idleProgressionRate == 0.0f) { + continue; } - if (!medicalConditions.isEmpty()) { - updateActiveSymptoms(); + if (permanentConditions.contains(condition) && + condition.idleProgressionType == IdleProgressionType.HEAL) { + // can't automatically heal permanent conditions. + continue; } + int multiplier = (condition.idleProgressionType == IdleProgressionType.HEAL) ? -1 : 1; + medicalConditions.addTo(condition, condition.idleProgressionRate * multiplier); + evaluateMedicalCondition(condition); + } + if (!medicalConditions.isEmpty()) { + updateActiveSymptoms(); } } - public void progressCondition(@NotNull MedicalCondition condition, float strength) { - if (player.isCreative()) return; + public void progressRelatedCondition(@NotNull MaterialEntry materialEntry, int count) { + HazardProperty materialHazard = materialEntry.material().getProperty(PropertyKey.HAZARD); + float strength = (float) (materialEntry.getMaterialAmount() / GTValues.M) * count * + materialHazard.progressionMultiplier; + progressCondition(materialHazard.condition, strength); + } - medicalConditions.put(condition, medicalConditions.getOrDefault(condition, 0) + strength); + public void progressCondition(@NotNull MedicalCondition condition, float progression) { + if (player.isCreative()) return; + medicalConditions.addTo(condition, progression); updateActiveSymptoms(); } - private void updateActiveSymptoms() { + @VisibleForTesting + 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) { + for (ConfiguredSymptom symptom : condition.symptoms) { + int lastStage = activeSymptoms.getInt(symptom); int stage = calculateStage(condition, symptom); if (stage <= 0) { continue; } - symptom.symptom.tick(this, condition, symptom, stage); + Symptom baseSymptom = symptom.getSymptom(); + baseSymptom.tick(this, condition, symptom, stage); - Optional currentSymptomOptional = activeSymptoms.keySet() + Optional maybeExistingSymptom = activeSymptoms.keySet() .stream() - .filter(symptom1 -> symptom1.symptom == symptom.symptom) + .filter(s -> s.getSymptom() == baseSymptom) .findFirst(); - if (currentSymptomOptional.isEmpty()) { + if (maybeExistingSymptom.isEmpty()) { activeSymptoms.put(symptom, stage); - symptom.symptom.applyProgression(this, condition, null, stage); + baseSymptom.applyProgression(this, condition, symptom, 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); + ConfiguredSymptom existingSymptom = maybeExistingSymptom.get(); + int existingStage = activeSymptoms.getInt(existingSymptom); + if (existingSymptom == symptom && stage > lastStage) { + activeSymptoms.put(symptom, stage); + baseSymptom.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); + if (symptom.getRelativeHarshness() * stage > existingSymptom.getRelativeHarshness() * existingStage) { + activeSymptoms.removeInt(existingSymptom); activeSymptoms.put(symptom, stage); - symptom.symptom.applyProgression(this, condition, symptom, stage); + baseSymptom.applyProgression(this, condition, symptom, stage); } } } @@ -126,25 +140,41 @@ private void updateActiveSymptoms() { 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); + Set toRemove = new HashSet<>(); + activeSymptoms.keySet().stream() + .filter(condition.symptoms::contains) + .forEach(symptom -> { + // reset all symptom effects for this condition + symptom.getSymptom().applyProgression(this, condition, symptom, 0); + toRemove.add(symptom); + }); + for (ConfiguredSymptom symptom : toRemove) { + activeSymptoms.removeInt(symptom); } + 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)); + private int calculateStage(MedicalCondition condition, ConfiguredSymptom symptom) { + float minThreshold = symptom.getMinThreshold(); + float maxThreshold = symptom.getMaxThreshold(); + float progression = medicalConditions.getFloat(condition); + + if (progression < minThreshold) { + return 0; + } + if (progression >= maxThreshold) { + return symptom.getStages(); + } + float delta = Mth.inverseLerp(Math.min(progression, condition.maxProgression), minThreshold, maxThreshold); + return (int) (delta * symptom.getStages()); } // removes MedicalConditions without progression @@ -163,28 +193,21 @@ private void evaluateMedicalCondition(MedicalCondition condition) { * @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)) { + if (progression >= medicalConditions.getFloat(condition)) { medicalConditions.removeFloat(condition); permanentConditions.remove(condition); return; } - medicalConditions.replace(condition, medicalConditions.getOrDefault(condition, 0) - progression); + medicalConditions.addTo(condition, -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); + return; } + activeMobEffects.mergeInt(effect, amplifier, Math::max); } @Override @@ -192,9 +215,9 @@ public CompoundTag serializeNBT() { CompoundTag tag = new CompoundTag(); ListTag effectsTag = new ListTag(); - for (var entry : medicalConditions.object2FloatEntrySet()) { + for (var entry : medicalConditions.reference2FloatEntrySet()) { CompoundTag medicalConditionTag = new CompoundTag(); - medicalConditionTag.putString("condition", entry.getKey().name); + medicalConditionTag.putString("condition", entry.getKey().id.toString()); medicalConditionTag.putFloat("progression", entry.getFloatValue()); effectsTag.add(medicalConditionTag); } @@ -202,7 +225,7 @@ public CompoundTag serializeNBT() { ListTag permanentsTag = new ListTag(); for (MedicalCondition condition : permanentConditions) { - permanentsTag.add(StringTag.valueOf(condition.name)); + permanentsTag.add(StringTag.valueOf(condition.id.toString())); } tag.put("permanent_conditions", permanentsTag); @@ -211,10 +234,19 @@ public CompoundTag serializeNBT() { @Override public void deserializeNBT(CompoundTag arg) { + // ensure the medical condition map(s) is actually empty before loading. + // IDK if this actually happens, but better be safe than sorry. + medicalConditions.clear(); + permanentConditions.clear(); + 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")); + ResourceLocation id = GTCEu.id(compoundTag.getString("condition")); + if (!GTRegistries.MEDICAL_CONDITIONS.containKey(id)) { + continue; + } + MedicalCondition condition = GTRegistries.MEDICAL_CONDITIONS.get(id); float progression = compoundTag.getFloat("progression"); medicalConditions.put(condition, progression); @@ -222,7 +254,16 @@ public void deserializeNBT(CompoundTag arg) { 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))); + ResourceLocation id = GTCEu.id(permanentConditionsTag.getString(i)); + if (!GTRegistries.MEDICAL_CONDITIONS.containKey(id)) { + continue; + } + permanentConditions.add(GTRegistries.MEDICAL_CONDITIONS.get(id)); } } + + @Override + public @NotNull LazyOptional getCapability(@NotNull Capability cap, @Nullable Direction side) { + return GTCapability.CAPABILITY_MEDICAL_CONDITION_TRACKER.orEmpty(cap, this.holder); + } } diff --git a/src/main/java/com/gregtechceu/gtceu/common/commands/GTCommands.java b/src/main/java/com/gregtechceu/gtceu/common/commands/GTCommands.java index 3b9463eb764..49c7a7f71bb 100644 --- a/src/main/java/com/gregtechceu/gtceu/common/commands/GTCommands.java +++ b/src/main/java/com/gregtechceu/gtceu/common/commands/GTCommands.java @@ -96,7 +96,7 @@ public static void register(CommandDispatcher dispatcher, Co GTOreDefinition.FULL_CODEC, GTOreLoader.FOLDER)))) .then(literal("place_vein") - .requires(ctx -> ctx.hasPermission(LEVEL_ADMINS)) + .requires(ctx -> ctx.hasPermission(LEVEL_GAMEMASTERS)) .then(argument("vein", GTRegistryArgument.registry(GTRegistries.ORE_VEINS, ResourceLocation.class)) .executes(context -> { return GTCommands.placeVein(context, BlockPos.containing(context.getSource().getPosition())); diff --git a/src/main/java/com/gregtechceu/gtceu/common/commands/MedicalConditionCommands.java b/src/main/java/com/gregtechceu/gtceu/common/commands/MedicalConditionCommands.java index 602408e1666..3055c97a4ac 100644 --- a/src/main/java/com/gregtechceu/gtceu/common/commands/MedicalConditionCommands.java +++ b/src/main/java/com/gregtechceu/gtceu/common/commands/MedicalConditionCommands.java @@ -1,8 +1,9 @@ package com.gregtechceu.gtceu.common.commands; import com.gregtechceu.gtceu.api.capability.GTCapabilityHelper; -import com.gregtechceu.gtceu.api.capability.IMedicalConditionTracker; import com.gregtechceu.gtceu.api.data.medicalcondition.MedicalCondition; +import com.gregtechceu.gtceu.api.data.medicalcondition.Symptom; +import com.gregtechceu.gtceu.common.capability.MedicalConditionTracker; import com.gregtechceu.gtceu.common.commands.arguments.MedicalConditionArgument; import net.minecraft.commands.CommandBuildContext; @@ -15,6 +16,7 @@ import com.mojang.brigadier.arguments.FloatArgumentType; import com.mojang.brigadier.exceptions.CommandSyntaxException; import com.mojang.brigadier.exceptions.SimpleCommandExceptionType; +import org.jetbrains.annotations.NotNull; import org.jetbrains.annotations.Nullable; import java.util.Collection; @@ -25,9 +27,11 @@ public class MedicalConditionCommands { private static final SimpleCommandExceptionType ERROR_CLEAR_EVERYTHING_FAILED = new SimpleCommandExceptionType( - Component.translatable("commands.effect.clear.everything.failed")); + Component.translatable("command.gtceu.medical_condition.clear.everything.failed")); private static final SimpleCommandExceptionType ERROR_GIVE_FAILED = new SimpleCommandExceptionType( - Component.translatable("commands.effect.give.failed")); + Component.translatable("command.gtceu.medical_condition.give.failed")); + private static final SimpleCommandExceptionType ERROR_CLEAR_SPECIFIC_FAILED = new SimpleCommandExceptionType( + Component.translatable("command.gtceu.medical_condition.clear.specific.failed")); // spotless:off public static void register(CommandDispatcher dispatcher, CommandBuildContext buildContext) { @@ -35,122 +39,200 @@ public static void register(CommandDispatcher dispatcher, Co literal("medical_condition") .then(literal("query") .executes(ctx -> { - return queryMedicalConditions(ctx.getSource().getPlayerOrException()); + return queryMedicalConditions(ctx.getSource(), ctx.getSource().getPlayerOrException()); }) .then(argument("target", EntityArgument.player()) .requires(source -> source.hasPermission(LEVEL_GAMEMASTERS)) .executes(context -> { - return queryMedicalConditions(EntityArgument.getPlayer(context, "target")); - }))) + return queryMedicalConditions(context.getSource(), EntityArgument.getPlayer(context, "target")); + })) + .then(literal("symptoms") + .executes(ctx -> { + return querySymptoms(ctx.getSource(), ctx.getSource().getPlayerOrException()); + }) + .then(argument("target", EntityArgument.player()) + .requires(source -> source.hasPermission(LEVEL_GAMEMASTERS)) + .executes(context -> { + return querySymptoms(context.getSource(), EntityArgument.getPlayer(context, "target")); + })))) .then(literal("clear") - .requires(ctx -> ctx.hasPermission(LEVEL_ADMINS)) + .requires(ctx -> ctx.hasPermission(LEVEL_GAMEMASTERS)) .executes(ctx -> { - return clearMedicalConditions( - Collections.singleton(ctx.getSource().getPlayerOrException()), null); + return clearMedicalConditions(ctx.getSource(), Collections.singleton(ctx.getSource().getPlayerOrException()), null); }) .then(argument("targets", EntityArgument.players()) .executes(ctx -> { - return clearMedicalConditions(EntityArgument.getPlayers(ctx, "targets"), - null); + return clearMedicalConditions(ctx.getSource(), EntityArgument.getPlayers(ctx, "targets"), null); }) .then(argument("condition", MedicalConditionArgument.medicalCondition()) .executes(ctx -> { - Collection targets = EntityArgument.getPlayers(ctx, - "targets"); - MedicalCondition condition = MedicalConditionArgument - .getCondition(ctx, "condition"); - return clearMedicalConditions(targets, condition); + Collection targets = EntityArgument.getPlayers(ctx, "targets"); + MedicalCondition condition = MedicalConditionArgument.getCondition(ctx, "condition"); + return clearMedicalConditions(ctx.getSource(), targets, condition); })))) .then(literal("apply") .requires(ctx -> ctx.hasPermission(LEVEL_GAMEMASTERS)) .then(argument("targets", EntityArgument.players()) .then(argument("condition", MedicalConditionArgument.medicalCondition()) .executes(ctx -> { - MedicalCondition condition = MedicalConditionArgument - .getCondition(ctx, "condition"); - Collection players = EntityArgument.getPlayers(ctx, - "targets"); - return applyMedicalConditions(players, condition, 1); + MedicalCondition condition = MedicalConditionArgument.getCondition(ctx, "condition"); + Collection players = EntityArgument.getPlayers(ctx, "targets"); + return applyMedicalConditions(ctx.getSource(), players, condition, 20); }) - .then(argument("progression_multiplier", FloatArgumentType.floatArg(0)) + .then(argument("progression", FloatArgumentType.floatArg()) .executes(ctx -> { - MedicalCondition condition = MedicalConditionArgument - .getCondition(ctx, "condition"); - Collection players = EntityArgument - .getPlayers(ctx, "targets"); - float strength = FloatArgumentType.getFloat(ctx, - "progression_multiplier"); - return applyMedicalConditions(players, condition, strength); + MedicalCondition condition = MedicalConditionArgument.getCondition(ctx, "condition"); + Collection players = EntityArgument.getPlayers(ctx, "targets"); + float progression = FloatArgumentType.getFloat(ctx, "progression"); + return applyMedicalConditions(ctx.getSource(), players, condition, progression); })))))); } - // spotless:off + // spotless:on - 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())); + private static int queryMedicalConditions(CommandSourceStack source, + ServerPlayer target) throws CommandSyntaxException { + MedicalConditionTracker tracker = getMedicalConditionTracker(target); + + int conditions = tracker.getMedicalConditions().size(); + if (conditions == 0) { + source.sendSuccess(() -> { + return Component.translatable("command.gtceu.medical_condition.get.empty", target.getName()); + }, false); + return 0; } else { - target.sendSystemMessage( - Component.translatable("command.gtceu.medical_condition.get", target.getName())); + source.sendSuccess(() -> { + return Component.translatable("command.gtceu.medical_condition.get", target.getName()); + }, false); } - for (var entry : tracker.getMedicalConditions().object2FloatEntrySet()) { - String langKey = "command.gtceu.medical_condition.get.element"; - if (entry.getKey().maxProgression * 2 <= entry.getFloatValue() && - entry.getKey().canBePermanent) { + for (var entry : tracker.getMedicalConditions().reference2FloatEntrySet()) { + String langKey; + if (!entry.getKey().canBePermanent || entry.getFloatValue() < entry.getKey().maxProgression * 2) { + langKey = "command.gtceu.medical_condition.get.element"; + } else { langKey = "command.gtceu.medical_condition.get.element.permanent"; } float time = entry.getFloatValue(); - target.sendSystemMessage( - Component.translatable(langKey, - Component.translatable("gtceu.medical_condition." + entry.getKey().name), - (int) (time / 60), (int) (time % 60))); + source.sendSuccess(() -> { + return Component.translatable(langKey, + entry.getKey().getAffectedName(), (int) (time / 60), (int) (time % 60)); + }, false); } - return count; + return conditions; } - private static int clearMedicalConditions(Collection targets, + private static int querySymptoms(CommandSourceStack source, ServerPlayer target) throws CommandSyntaxException { + MedicalConditionTracker tracker = getMedicalConditionTracker(target); + + int symptoms = tracker.getActiveSymptoms().size(); + if (symptoms == 0) { + source.sendSuccess(() -> { + return Component.translatable("command.gtceu.medical_condition.get.symptoms.empty", target.getName()); + }, false); + return 0; + } else { + source.sendSuccess(() -> { + return Component.translatable("command.gtceu.medical_condition.get.symptoms", target.getName()); + }, false); + } + for (Symptom.ConfiguredSymptom symptom : tracker.getActiveSymptoms().keySet()) { + source.sendSuccess(() -> { + return Component.translatable("command.gtceu.medical_condition.get.symptoms.element", + Component.translatable(symptom.getSymptom().name)); + }, false); + } + return symptoms; + } + + private static int clearMedicalConditions(CommandSourceStack source, Collection targets, @Nullable MedicalCondition condition) throws CommandSyntaxException { - int count = 0; + int removed = 0; for (ServerPlayer target : targets) { - IMedicalConditionTracker tracker = GTCapabilityHelper.getMedicalConditionTracker(target); + MedicalConditionTracker tracker = GTCapabilityHelper.getMedicalConditionTracker(target); if (tracker == null) { continue; } if (condition == null) { - count += tracker.getMedicalConditions().keySet().size(); + removed += tracker.getMedicalConditions().size(); for (MedicalCondition medicalCondition : tracker.getMedicalConditions().keySet()) { tracker.removeMedicalCondition(medicalCondition); } } else { - count++; + removed++; tracker.removeMedicalCondition(condition); } } - if (count == 0) { - throw ERROR_CLEAR_EVERYTHING_FAILED.create(); + + if (removed == 0) { + if (condition == null) { + throw ERROR_CLEAR_EVERYTHING_FAILED.create(); + } else { + throw ERROR_CLEAR_SPECIFIC_FAILED.create(); + } + } + if (targets.size() == 1) { + if (condition == null) { + source.sendSuccess(() -> { + return Component.translatable("command.gtceu.medical_condition.clear.everything.success.single", + targets.iterator().next().getDisplayName()); + }, true); + } else { + source.sendSuccess(() -> { + return Component.translatable("command.gtceu.medical_condition.clear.specific.success.single", + condition.getAffectedName(), targets.iterator().next().getDisplayName()); + }, true); + } + } else { + if (condition == null) { + source.sendSuccess(() -> { + return Component.translatable("command.gtceu.medical_condition.clear.everything.success.multiple", + targets.size()); + }, true); + } else { + source.sendSuccess(() -> { + return Component.translatable("command.gtceu.medical_condition.clear.specific.success.multiple", + condition.getAffectedName(), targets.size()); + }, true); + } } - return count; + + return removed; } - private static int applyMedicalConditions(Collection targets, MedicalCondition condition, - float strength) throws CommandSyntaxException { - int success = 0; + private static int applyMedicalConditions(CommandSourceStack source, Collection targets, + MedicalCondition condition, + float progression) throws CommandSyntaxException { + int applied = 0; for (ServerPlayer player : targets) { - IMedicalConditionTracker tracker = GTCapabilityHelper.getMedicalConditionTracker(player); + MedicalConditionTracker tracker = GTCapabilityHelper.getMedicalConditionTracker(player); if (tracker == null) { continue; } - tracker.progressCondition(condition, strength); - success++; + tracker.progressCondition(condition, progression); + applied++; } - if (success == 0) { + if (applied == 0) { throw ERROR_GIVE_FAILED.create(); } - return success; + + if (targets.size() == 1) { + source.sendSuccess(() -> { + return Component.translatable("command.gtceu.medical_condition.give.success.single", + condition.getAffectedName(), targets.iterator().next().getDisplayName()); + }, true); + } else { + source.sendSuccess(() -> { + return Component.translatable("command.gtceu.medical_condition.give.success.multiple", + condition.getAffectedName(), targets.size()); + }, true); + } + return applied; + } + + private static @NotNull MedicalConditionTracker getMedicalConditionTracker(@Nullable ServerPlayer target) throws CommandSyntaxException { + if (target == null) throw EntityArgument.NO_PLAYERS_FOUND.create(); + MedicalConditionTracker tracker = GTCapabilityHelper.getMedicalConditionTracker(target); + if (tracker == null) throw EntityArgument.NO_PLAYERS_FOUND.create(); + + return tracker; } } 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 1f200964014..1fd78749b78 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 @@ -14,7 +14,6 @@ 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; @@ -71,12 +70,14 @@ public static CompletableFuture fillSuggestions(IMaterialRegistryMa private void readMaterial() throws CommandSyntaxException { int i = this.reader.getCursor(); - ResourceLocation resourceLocation = ResourceLocation.read(this.reader); - Material material = this.materials.getRegistry(resourceLocation.getNamespace()).get(resourceLocation.getPath()); - this.result = Optional.ofNullable(material).orElseThrow(() -> { + ResourceLocation id = ResourceLocation.read(this.reader); + + Material material = this.materials.getRegistry(id.getNamespace()).get(id.getPath()); + if (material == null || material.isNull()) { this.reader.setCursor(i); - return ERROR_UNKNOWN_ITEM.createWithContext(this.reader, resourceLocation); - }); + throw ERROR_UNKNOWN_ITEM.createWithContext(this.reader, id); + } + this.result = material; } private void parse() throws CommandSyntaxException { 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 index 201b06a4fbc..596557038f8 100644 --- a/src/main/java/com/gregtechceu/gtceu/common/commands/arguments/MedicalConditionParser.java +++ b/src/main/java/com/gregtechceu/gtceu/common/commands/arguments/MedicalConditionParser.java @@ -1,6 +1,7 @@ package com.gregtechceu.gtceu.common.commands.arguments; import com.gregtechceu.gtceu.api.data.medicalcondition.MedicalCondition; +import com.gregtechceu.gtceu.api.registry.GTRegistries; import net.minecraft.commands.SharedSuggestionProvider; import net.minecraft.network.chat.Component; @@ -12,7 +13,6 @@ 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; @@ -59,16 +59,14 @@ public static CompletableFuture fillSuggestions(SuggestionsBuilder private void readMedicalCondition() throws CommandSyntaxException { int i = this.reader.getCursor(); + ResourceLocation id = ResourceLocation.read(this.reader); - 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(() -> { + MedicalCondition condition = GTRegistries.MEDICAL_CONDITIONS.get(id); + if (condition == null) { this.reader.setCursor(i); - return ERROR_UNKNOWN_ITEM.createWithContext(this.reader, name); - }); + throw ERROR_UNKNOWN_ITEM.createWithContext(this.reader, id.toString()); + } + this.result = condition; } private void parse() throws CommandSyntaxException { @@ -77,6 +75,6 @@ private void parse() throws CommandSyntaxException { } private CompletableFuture suggestMedicalCondition(SuggestionsBuilder builder) { - return SharedSuggestionProvider.suggest(MedicalCondition.CONDITIONS.keySet(), builder); + return SharedSuggestionProvider.suggestResource(GTRegistries.MEDICAL_CONDITIONS.keys(), builder); } } 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 4ce5ab3e790..7cef69333c5 100644 --- a/src/main/java/com/gregtechceu/gtceu/common/data/GTItems.java +++ b/src/main/java/com/gregtechceu/gtceu/common/data/GTItems.java @@ -2337,8 +2337,8 @@ public static ItemEntry createFluidCell(Material mat, int capacit .tag(Tags.Items.ARMORS_HELMETS) .tag(CustomTags.PPE_ARMOR) .onRegister(attach(new TooltipBehavior(tooltips -> { - tooltips.add(Component.translatable("gtceu.hazard_trigger.protection.description")); - tooltips.add(Component.translatable("gtceu.hazard_trigger.inhalation")); + tooltips.add(Component.translatable("tooltip.gtceu.hazard_trigger.protection")); + tooltips.add(Component.translatable("tooltip.gtceu.hazard_trigger.inhalation")); }))) .register(); public static ItemEntry RUBBER_GLOVES = REGISTRATE @@ -2349,8 +2349,8 @@ public static ItemEntry createFluidCell(Material mat, int capacit .tag(Tags.Items.ARMORS_CHESTPLATES) .tag(CustomTags.PPE_ARMOR) .onRegister(attach(new TooltipBehavior(tooltips -> { - tooltips.add(Component.translatable("gtceu.hazard_trigger.protection.description")); - tooltips.add(Component.translatable("gtceu.hazard_trigger.skin_contact")); + tooltips.add(Component.translatable("tooltip.gtceu.hazard_trigger.protection")); + tooltips.add(Component.translatable("tooltip.gtceu.hazard_trigger.skin_contact")); }))) .register(); public static ItemEntry HAZMAT_CHESTPLATE = REGISTRATE diff --git a/src/main/java/com/gregtechceu/gtceu/common/data/GTMedicalConditions.java b/src/main/java/com/gregtechceu/gtceu/common/data/GTMedicalConditions.java index 5781aec5d5c..795b25d83d9 100644 --- a/src/main/java/com/gregtechceu/gtceu/common/data/GTMedicalConditions.java +++ b/src/main/java/com/gregtechceu/gtceu/common/data/GTMedicalConditions.java @@ -1,100 +1,153 @@ package com.gregtechceu.gtceu.common.data; +import com.gregtechceu.gtceu.GTCEu; +import com.gregtechceu.gtceu.api.GTCEuAPI; import com.gregtechceu.gtceu.api.data.medicalcondition.MedicalCondition; import com.gregtechceu.gtceu.api.data.medicalcondition.Symptom; +import com.gregtechceu.gtceu.api.registry.GTRegistries; + +import net.minecraft.resources.ResourceLocation; +import net.minecraftforge.fml.ModLoader; import static com.gregtechceu.gtceu.api.data.tag.TagPrefix.dust; import static com.gregtechceu.gtceu.common.data.GTMaterials.*; public class GTMedicalConditions { + static { + GTRegistries.MEDICAL_CONDITIONS.unfreeze(); + } + // General Conditions - public static final MedicalCondition NONE = new MedicalCondition("none", 0xffffff, 0); - public static final MedicalCondition CHEMICAL_BURNS = new MedicalCondition("chemical_burns", 0xbc305a, 200, + public static final MedicalCondition NONE = register("none", 0xffffff, 0, + MedicalCondition.IdleProgressionType.NONE, 0, false); + // takes 5 minutes of having burn-causing items in the player's inventory for them to get the weakness effect + // heals 2 seconds' worth of progression every second when not holding those items + public static final MedicalCondition CHEMICAL_BURNS = register("chemical_burns", 0xbc305a, 300, MedicalCondition.IdleProgressionType.HEAL, 2, false, new Symptom.ConfiguredSymptom(Symptom.WEAKNESS)) .setRecipeModifier(builder -> builder .outputFluids(DilutedHydrochloricAcid.getFluid(500)) .outputFluids(DilutedSulfuricAcid.getFluid(750))); - public static final MedicalCondition POISON = new MedicalCondition("poison", 0xA36300, 600, + // takes 5 minutes of having poisonous items in the player's inventory for them to get the weakness effect + // at 10 minutes, they get a weaker version of the poison effect + // heals 2 seconds' worth of progression every second when not holding those items + public static final MedicalCondition POISON = register("poison", 0xA36300, 600, MedicalCondition.IdleProgressionType.HEAL, 2, true, new Symptom.ConfiguredSymptom(Symptom.WEAK_POISONING), - new Symptom.ConfiguredSymptom(Symptom.WEAKNESS, .5f)) + new Symptom.ConfiguredSymptom(Symptom.WEAKNESS, 300, 600)) .setRecipeModifier(builder -> builder .outputFluids(SulfurTrioxide.getFluid(1000))); - public static final MedicalCondition WEAK_POISON = new MedicalCondition("weak_poison", 0x6D7917, 3000, + // having weakly poisonous items in the player's inventory gives them the weak poison effect + // the effect ramps up in 6 "stages", getting progressively worse every stage. It caps out at Weak Poison 10. + // does NOT heal automatically + public static final MedicalCondition WEAK_POISON = register("weak_poison", 0x6D7917, 1800, MedicalCondition.IdleProgressionType.NONE, 0, false, - new Symptom.ConfiguredSymptom(Symptom.WEAK_POISONING, 6, .3f)) + new Symptom.ConfiguredSymptom(Symptom.WEAK_POISONING, 6, 1800)) .setRecipeModifier(builder -> builder .outputFluids(NitricOxide.getFluid(1000))); - public static final MedicalCondition IRRITANT = new MedicalCondition("irritant", 0x02512f, 600, + // takes 2.5 minutes of having irritating items in the player's inventory for them to get the weakness effect + // at 5 minutes, they begin getting random damage every so often + // heals 5 seconds' worth of progression every second when not holding those items + public static final MedicalCondition IRRITANT = register("irritant", 0x02512f, 600, MedicalCondition.IdleProgressionType.HEAL, 5, false, new Symptom.ConfiguredSymptom(Symptom.RANDOM_DAMAGE), - new Symptom.ConfiguredSymptom(Symptom.WEAKNESS, 0.5f)) + new Symptom.ConfiguredSymptom(Symptom.WEAKNESS, 300, 600)) .setRecipeModifier(builder -> builder .outputItems(dust, DarkAsh, 4)); - public static final MedicalCondition NAUSEA = new MedicalCondition("nausea", 0x1D4A00, 600, + // takes 5 minutes of having nauseating items in the player's inventory for them to get the nausea effect + // heals 5 seconds' worth of progression every second when not holding those items + public static final MedicalCondition NAUSEA = register("nausea", 0x1D4A00, 600, MedicalCondition.IdleProgressionType.HEAL, 5, false, - new Symptom.ConfiguredSymptom(Symptom.NAUSEA)) + new Symptom.ConfiguredSymptom(Symptom.NAUSEA, 1, 420, 600)) .setRecipeModifier(builder -> builder .outputFluids(CarbonMonoxide.getFluid(50))); - public static final MedicalCondition CARCINOGEN = new MedicalCondition("carcinogen", 0x0f570f, 20000, + /** + * All effects: + *
    + *
  • After an hour, the player's attack damage and mining speed will start lowering.
  • + *
  • After 2 hours, the player's max air supply and movement speed will start lowering.
  • + *
  • After 3 hours, the player's max health will start lowering.
  • + *
  • After 4 hours, the player's attack damage and mining speed are at their lowest.
  • + *
  • After 5 hours, the player will have the lowest max air supply of 200/300 (so 6/10 bubbles) and their speed is + * at its lowest.
  • + *
  • After 6 hours, the player will have the lowest max HP of 10/20 (so 5/10 hearts).
  • + *
  • After 10 real-life hours (30 MC days) of having cancer, the player will die.
  • + *
+ *

+ * Do note that while the effects do not get worse when the player isn't holding anything radioactive, + * the progression they've already gained will stay as is and reactivate if they pick up e.g. a uranium ingot.
+ * + * This condition does NOT heal automatically. You can use {@linkplain GTItems#RAD_AWAY_PILL + * rad-away pills} to heal it. + */ + public static final MedicalCondition CARCINOGEN = register("carcinogen", 0x0f570f, 36000, 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)); + new Symptom.ConfiguredSymptom(Symptom.HEALTH_DEBUFF, 10800, 21600), + new Symptom.ConfiguredSymptom(Symptom.AIR_SUPPLY_DEBUFF, 7200, 18000), + new Symptom.ConfiguredSymptom(Symptom.MINING_FATIGUE, 3600, 14400), + new Symptom.ConfiguredSymptom(Symptom.SLOWNESS, 7200, 18000), + // new Symptom.ConfiguredSymptom(Symptom.HUNGER, 0, 10800), + new Symptom.ConfiguredSymptom(Symptom.WEAKNESS, 3600, 14400)); // Material specific Conditions - public static final MedicalCondition ASBESTOSIS = new MedicalCondition("asbestosis", 0xe3e3e3, 5000, + public static final MedicalCondition ASBESTOSIS = register("asbestosis", 0xe3e3e3, 5000, MedicalCondition.IdleProgressionType.HEAL, 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)) + // new Symptom.ConfiguredSymptom(Symptom.HEALTH_DEBUFF, 3000, 5000), + // new Symptom.ConfiguredSymptom(Symptom.AIR_SUPPLY_DEBUFF, 1500, 3500), + // new Symptom.ConfiguredSymptom(Symptom.HUNGER, 500, 4000), + new Symptom.ConfiguredSymptom(Symptom.WEAKNESS, 1200, 5000)) .setRecipeModifier(builder -> builder .outputItems(dust, Asbestos, 4)); - public static final MedicalCondition ARSENICOSIS = new MedicalCondition("arsenicosis", 0xbd4b15, 1000, + public static final MedicalCondition ARSENICOSIS = register("arsenicosis", 0xbd4b15, 1000, MedicalCondition.IdleProgressionType.HEAL, 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)) + new Symptom.ConfiguredSymptom(Symptom.NAUSEA), + new Symptom.ConfiguredSymptom(Symptom.SLOWNESS, 2, 500, 1000), + new Symptom.ConfiguredSymptom(Symptom.WEAKNESS, 2, 330, 1000)) + // new Symptom.ConfiguredSymptom(Symptom.HUNGER, 2, .2f)) .setRecipeModifier(builder -> builder .outputItems(dust, Arsenic, 4)); - public static final MedicalCondition SILICOSIS = new MedicalCondition("silicosis", 0x5d6c91, 15000, - MedicalCondition.IdleProgressionType.HEAL, .5f, true, - new Symptom.ConfiguredSymptom(Symptom.HEALTH_DEBUFF, 4, .75f), - new Symptom.ConfiguredSymptom(Symptom.AIR_SUPPLY_DEBUFF, .6f)) - .setRecipeModifier(builder -> builder - .outputItems(dust, SiliconDioxide, 4)); - public static final MedicalCondition BERYLLIOSIS = new MedicalCondition("berylliosis", 0x0c6539, 10000, - MedicalCondition.IdleProgressionType.HEAL, .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)) - .setRecipeModifier(builder -> builder - .outputItems(dust, Beryllium, 4)); - public static final MedicalCondition METHANOL_POISONING = new MedicalCondition("methanol_poisoning", 0xaa8800, 500, + public static final MedicalCondition METHANOL_POISONING = register("methanol_poisoning", 0xaa8800, 600, MedicalCondition.IdleProgressionType.HEAL, .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)) + new Symptom.ConfiguredSymptom(Symptom.BLINDNESS, 2, 450, 600), + new Symptom.ConfiguredSymptom(Symptom.WEAKNESS, 2, 300, 600), + new Symptom.ConfiguredSymptom(Symptom.SLOWNESS, 1, 150, 600)) .setRecipeModifier(builder -> builder .outputFluids(Methanol.getFluid(1000))); - public static final MedicalCondition CARBON_MONOXIDE_POISONING = new MedicalCondition("carbon_monoxide_poisoning", + public static final MedicalCondition CARBON_MONOXIDE_POISONING = register("carbon_monoxide_poisoning", 0x041525, 2000, MedicalCondition.IdleProgressionType.HEAL, 1, true, new Symptom.ConfiguredSymptom(Symptom.DEATH), - new Symptom.ConfiguredSymptom(Symptom.SLOWNESS, 2, .75f), - new Symptom.ConfiguredSymptom(Symptom.NAUSEA, 2, .5f), - new Symptom.ConfiguredSymptom(Symptom.WEAKNESS, 2, .25f)) + new Symptom.ConfiguredSymptom(Symptom.NAUSEA), + new Symptom.ConfiguredSymptom(Symptom.SLOWNESS, 2, 1500, 2000), + new Symptom.ConfiguredSymptom(Symptom.WEAKNESS, 2, 500, 2000)) .setRecipeModifier(builder -> builder .outputFluids(CarbonMonoxide.getFluid(1000))); + + public static MedicalCondition register(ResourceLocation id, int color, + int maxProgression, MedicalCondition.IdleProgressionType progressionType, + float progressionRate, boolean canBePermanent, + Symptom.ConfiguredSymptom... symptoms) { + var condition = new MedicalCondition(id, color, maxProgression, + progressionType, progressionRate, canBePermanent, symptoms); + GTRegistries.MEDICAL_CONDITIONS.register(id, condition); + return condition; + } + + // internal variant of the above that skips having to write `register(GTCEu.id(...` + private static MedicalCondition register(String id, int color, + int maxProgression, MedicalCondition.IdleProgressionType progressionType, + float progressionRate, boolean canBePermanent, + Symptom.ConfiguredSymptom... symptoms) { + return register(GTCEu.id(id), color, maxProgression, progressionType, progressionRate, canBePermanent, + symptoms); + } + + public static void init() { + ModLoader.get() + .postEvent(new GTCEuAPI.RegisterEvent<>(GTRegistries.MEDICAL_CONDITIONS, MedicalCondition.class)); + GTRegistries.MEDICAL_CONDITIONS.freeze(); + } } diff --git a/src/main/java/com/gregtechceu/gtceu/common/data/GTMobEffects.java b/src/main/java/com/gregtechceu/gtceu/common/data/GTMobEffects.java index ea0041cdc44..921d81e03b3 100644 --- a/src/main/java/com/gregtechceu/gtceu/common/data/GTMobEffects.java +++ b/src/main/java/com/gregtechceu/gtceu/common/data/GTMobEffects.java @@ -15,7 +15,7 @@ public class GTMobEffects { public static final DeferredRegister MOB_EFFECTS = DeferredRegister.create(ForgeRegistries.MOB_EFFECTS, GTCEu.MOD_ID); - public static final RegistryObject WEAK_POISON = MOB_EFFECTS.register("weak_poison", + public static final RegistryObject WEAK_POISON = MOB_EFFECTS.register("weak_poison", () -> new GTPoisonEffect(MobEffectCategory.HARMFUL, 0x6D7917)); public static void init(IEventBus modBus) { diff --git a/src/main/java/com/gregtechceu/gtceu/common/data/machines/GTMachineUtils.java b/src/main/java/com/gregtechceu/gtceu/common/data/machines/GTMachineUtils.java index 2f881c2b87b..811b6093911 100644 --- a/src/main/java/com/gregtechceu/gtceu/common/data/machines/GTMachineUtils.java +++ b/src/main/java/com/gregtechceu/gtceu/common/data/machines/GTMachineUtils.java @@ -896,8 +896,7 @@ public static Component explosion() { } public static Component environmentRequirement(MedicalCondition condition) { - return Component.translatable("gtceu.recipe.environmental_hazard.reverse", - Component.translatable("gtceu.medical_condition." + condition.name)); + return Component.translatable("gtceu.recipe.environmental_hazard.reverse", condition.getTranslatableName()); } public static Component defaultEnvironmentRequirement() { 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 62409787155..432009190f2 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 @@ -100,7 +100,6 @@ public static void register() { .ore() .color(0x73d73d).secondaryColor(0x184537).iconSet(METALLIC) .appendFlags(STD_METAL) - .hazard(HazardProperty.HazardTrigger.SKIN_CONTACT, GTMedicalConditions.BERYLLIOSIS, false) .element(GTElements.Be) .buildAndRegister(); 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 ee7a481a008..9869897279d 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 @@ -887,7 +887,6 @@ 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")) diff --git a/src/main/java/com/gregtechceu/gtceu/common/item/behavior/AntidoteBehavior.java b/src/main/java/com/gregtechceu/gtceu/common/item/behavior/AntidoteBehavior.java index 3046608a508..abceafab1f8 100644 --- a/src/main/java/com/gregtechceu/gtceu/common/item/behavior/AntidoteBehavior.java +++ b/src/main/java/com/gregtechceu/gtceu/common/item/behavior/AntidoteBehavior.java @@ -1,10 +1,10 @@ package com.gregtechceu.gtceu.common.item.behavior; import com.gregtechceu.gtceu.api.capability.GTCapabilityHelper; -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.common.capability.MedicalConditionTracker; import com.gregtechceu.gtceu.config.ConfigHolder; import com.gregtechceu.gtceu.utils.GTUtil; @@ -25,25 +25,25 @@ * Defines an antidote for a hazard (e.g. poisoning) * * @param types the type of the hazard to remove - * @param removePercent the time to remove from the chosen hazard, as a percentage of the current time [0, 100]. - * -1 for all. + * @param removePercent how many 'counts' should be removed from the chosen condition(s), + * as a percentage of the current 'counts' in the range [0, 100]. -1 for all. */ public record AntidoteBehavior(Set types, int removePercent) implements IInteractionItem, IAddInformation { - public AntidoteBehavior(int timeToRemove, MedicalCondition... types) { - this(new HashSet<>(), timeToRemove); + public AntidoteBehavior(int removePercent, MedicalCondition... types) { + this(new HashSet<>(), removePercent); this.types.addAll(Arrays.asList(types)); } @Override public ItemStack finishUsingItem(ItemStack stack, Level level, LivingEntity livingEntity) { ItemStack itemstack = IInteractionItem.super.finishUsingItem(stack, level, livingEntity); - IMedicalConditionTracker tracker = GTCapabilityHelper.getMedicalConditionTracker(livingEntity); + MedicalConditionTracker tracker = GTCapabilityHelper.getMedicalConditionTracker(livingEntity); if (tracker == null) { return itemstack; } - for (var entry : tracker.getMedicalConditions().object2FloatEntrySet()) { + for (var entry : tracker.getMedicalConditions().reference2FloatEntrySet()) { MedicalCondition condition = entry.getKey(); if (condition == null) { continue; @@ -72,20 +72,20 @@ public void appendHoverText(ItemStack stack, @Nullable Level level, List getType() { @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)); + Component.translatable("gtceu.recipe.environmental_hazard.reverse", condition.getTranslatableName()) : + Component.translatable("gtceu.recipe.environmental_hazard", condition.getTranslatableName()); } @Override diff --git a/src/main/java/com/gregtechceu/gtceu/core/IBreathingEntity.java b/src/main/java/com/gregtechceu/gtceu/core/IBreathingEntity.java new file mode 100644 index 00000000000..372a43ad6e8 --- /dev/null +++ b/src/main/java/com/gregtechceu/gtceu/core/IBreathingEntity.java @@ -0,0 +1,12 @@ +package com.gregtechceu.gtceu.core; + +public interface IBreathingEntity { + + default int gtceu$getOriginalMaxAirSupply() { + throw new AssertionError("Mixin didn't apply"); + } + + default void gtceu$setMaxAirSupply(int newMaxAirSupply) { + throw new AssertionError("Mixin didn't apply"); + } +} diff --git a/src/main/java/com/gregtechceu/gtceu/core/IFireImmuneEntity.java b/src/main/java/com/gregtechceu/gtceu/core/IFireImmuneEntity.java index ebbdfff3cd2..f31d534985f 100644 --- a/src/main/java/com/gregtechceu/gtceu/core/IFireImmuneEntity.java +++ b/src/main/java/com/gregtechceu/gtceu/core/IFireImmuneEntity.java @@ -2,5 +2,7 @@ public interface IFireImmuneEntity { - void gtceu$setFireImmune(boolean isImmune); + default void gtceu$setFireImmune(boolean isImmune) { + throw new AssertionError("Mixin didn't apply"); + } } 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 f8e65ae9d87..6a2201c3a9d 100644 --- a/src/main/java/com/gregtechceu/gtceu/core/mixins/EntityMixin.java +++ b/src/main/java/com/gregtechceu/gtceu/core/mixins/EntityMixin.java @@ -1,8 +1,7 @@ package com.gregtechceu.gtceu.core.mixins; -import com.gregtechceu.gtceu.api.capability.GTCapabilityHelper; -import com.gregtechceu.gtceu.api.capability.IMedicalConditionTracker; import com.gregtechceu.gtceu.config.ConfigHolder; +import com.gregtechceu.gtceu.core.IBreathingEntity; import com.gregtechceu.gtceu.core.IFireImmuneEntity; import net.minecraft.world.entity.Entity; @@ -15,19 +14,23 @@ import org.spongepowered.asm.mixin.Unique; import org.spongepowered.asm.mixin.injection.At; import org.spongepowered.asm.mixin.injection.Inject; +import org.spongepowered.asm.mixin.injection.ModifyVariable; import org.spongepowered.asm.mixin.injection.callback.CallbackInfo; @Mixin(Entity.class) -public abstract class EntityMixin implements IFireImmuneEntity { +public abstract class EntityMixin implements IFireImmuneEntity, IBreathingEntity { @Shadow - public abstract EntityType getType(); + public abstract int getMaxAirSupply(); @Unique private boolean gtceu$fireImmune = false; @Unique private boolean gtceu$isEntityInit = false; + @Unique + private int gtceu$modifiedMaxAirSupply = -1; + @ModifyReturnValue(method = "fireImmune", at = @At("RETURN")) private boolean gtceu$changeFireImmune(boolean original) { return original || gtceu$fireImmune; @@ -38,19 +41,55 @@ public abstract class EntityMixin implements IFireImmuneEntity { gtceu$isEntityInit = true; } - public void gtceu$setFireImmune(boolean isImmune) { - this.gtceu$fireImmune = isImmune; + @ModifyReturnValue(method = "getMaxAirSupply", at = @At("RETURN")) + private int gtceu$limitGetMaxAirSupply(int original) { + return gtceu$limitAirSupply(original); } - @ModifyReturnValue(method = "getMaxAirSupply", at = @At("RETURN")) - private int gtceu$hazardModifyMaxAir(int original) { + @ModifyVariable(method = "setAirSupply", at = @At("HEAD"), argsOnly = true) + private int gtceu$limitSetAirSupply(int original) { + return gtceu$limitAirSupply(original); + } + + @ModifyReturnValue(method = "getAirSupply", at = @At("RETURN")) + private int gtceu$limitGetAirSupply(int original) { + return gtceu$limitAirSupply(original); + } + + @Unique + private int gtceu$limitAirSupply(int original) { if (!gtceu$isEntityInit) return original; if (!ConfigHolder.INSTANCE.gameplay.hazardsEnabled) return original; - IMedicalConditionTracker tracker = GTCapabilityHelper.getMedicalConditionTracker((Entity) (Object) this); - if (tracker != null && tracker.getMaxAirSupply() != -1) { - return tracker.getMaxAirSupply(); + if (gtceu$modifiedMaxAirSupply > 0 && gtceu$modifiedMaxAirSupply < original) { + return gtceu$modifiedMaxAirSupply; } return original; } + + @Override + public void gtceu$setFireImmune(boolean isImmune) { + this.gtceu$fireImmune = isImmune; + } + + @Override + public int gtceu$getOriginalMaxAirSupply() { + if (!this.gtceu$isEntityInit) { + return getMaxAirSupply(); + } + + try { + // set the "in init" flag when getting the original value so the mixin to change it doesn't do anything + this.gtceu$isEntityInit = false; + return this.getMaxAirSupply(); + } finally { + // then set it back after + this.gtceu$isEntityInit = true; + } + } + + @Override + public void gtceu$setMaxAirSupply(int newMaxAirSupply) { + this.gtceu$modifiedMaxAirSupply = newMaxAirSupply; + } } 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 f36f4b91036..5ad68a29427 100644 --- a/src/main/java/com/gregtechceu/gtceu/data/lang/LangHandler.java +++ b/src/main/java/com/gregtechceu/gtceu/data/lang/LangHandler.java @@ -124,11 +124,30 @@ public static void init(RegistrateLangProvider provider) { provider.add("gtceu.tool.class.shears", "Shears"); provider.add("gtceu.tool.class.drill", "Drill"); - 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 minutes %s seconds"); + provider.add("command.gtceu.medical_condition.clear.everything.failed", "Target has no conditions to remove"); + provider.add("command.gtceu.medical_condition.clear.everything.success.multiple", + "Removed all conditions from %s targets"); + provider.add("command.gtceu.medical_condition.clear.everything.success.single", + "Removed all conditions from %s"); + provider.add("command.gtceu.medical_condition.clear.specific.failed", + "Target doesn't have the requested condition"); + provider.add("command.gtceu.medical_condition.clear.specific.success.multiple", "Removed %s from %s targets"); + provider.add("command.gtceu.medical_condition.clear.specific.success.single", "Removed %s from %s"); + + provider.add("command.gtceu.medical_condition.give.failed", "Unable to apply this condition (invalid target)"); + provider.add("command.gtceu.medical_condition.give.success.multiple", "Applied %s to %s targets"); + provider.add("command.gtceu.medical_condition.give.success.single", "Applied %s to %s"); + + provider.add("command.gtceu.medical_condition.get", "%s has"); + provider.add("command.gtceu.medical_condition.get.empty", "%s is perfectly healthy."); + provider.add("command.gtceu.medical_condition.get.element", "- %s for %s minutes %s seconds"); provider.add("command.gtceu.medical_condition.get.element.permanent", - "Condition %s§r: %s minutes %s seconds (permanent)"); + "- %s for %s minutes %s seconds (permanent)"); + + provider.add("command.gtceu.medical_condition.get.symptoms.empty", "%s has no symptoms."); + provider.add("command.gtceu.medical_condition.get.symptoms", "Currently %s has these symptoms:"); + provider.add("command.gtceu.medical_condition.get.symptoms.element", "- %s"); + provider.add("command.gtceu.dump_data.success", "Dumped %s resources from registry %s to %s"); provider.add("command.gtceu.place_vein.failure", "Failed to place vein %s at position %s"); provider.add("command.gtceu.place_vein.success", "Placed vein %s at position %s"); @@ -145,33 +164,53 @@ public static void init(RegistrateLangProvider provider) { provider.add("command.gtceu.cape.use.success", "%s is now using cape %s"); provider.add("command.gtceu.cape.use.success.none", "%s is no longer using a cape"); - 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.hazard_trigger.description", "Caused by:"); - provider.add("gtceu.hazard_trigger.protection.description", "Protects from:"); - provider.add("gtceu.hazard_trigger.inhalation", "Inhalation"); - provider.add("gtceu.hazard_trigger.any", "Any contact"); - - provider.add("gtceu.hazard_trigger.skin_contact", "Skin contact"); - provider.add("gtceu.hazard_trigger.none", "Nothing"); - 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", + provider.add("tooltip.gtceu.medical_condition.description", "§l§cHAZARDOUS §7Hold Shift to show details"); + provider.add("tooltip.gtceu.medical_condition.description_shift", "§l§cHAZARDOUS:"); + provider.add("medical_condition.gtceu.chemical_burns", "§5Chemical burns"); + provider.add("medical_condition.gtceu.poison", "§2Poisonous"); + provider.add("medical_condition.gtceu.poison.affected", "§2Poisoning"); + provider.add("medical_condition.gtceu.weak_poison", "§aWeakly poisonous"); + provider.add("medical_condition.gtceu.weak_poison.affected", "§aMinor poisoning"); + provider.add("medical_condition.gtceu.irritant", "§6Irritant"); + provider.add("medical_condition.gtceu.irritant.affected", "§6Irritation"); + provider.add("medical_condition.gtceu.nausea", "§3Nauseating"); + provider.add("medical_condition.gtceu.nausea.affected", "§3Nausea"); + provider.add("medical_condition.gtceu.carcinogen", "§eCarcinogenic"); + provider.add("medical_condition.gtceu.carcinogen.affected", "§eCancer"); + provider.add("medical_condition.gtceu.asbestosis", "§dAsbestosis"); + provider.add("medical_condition.gtceu.arsenicosis", "§bArsenicosis"); + provider.add("medical_condition.gtceu.methanol_poisoning", "§6Methanol Poisoning"); + provider.add("medical_condition.gtceu.carbon_monoxide_poisoning", "§7Carbon Monoxide Poisoning"); + provider.add("medical_condition.gtceu.none", "§2Not Dangerous"); + provider.add("medical_condition.gtceu.none.affected", "§2Nothing?"); + + provider.add("symptom.gtceu.death", "Death"); + provider.add("symptom.gtceu.random_damage", "Occasional damage"); + provider.add("symptom.gtceu.health_debuff", "Lowered maximum health"); + provider.add("symptom.gtceu.air_supply_debuff", "Lowered lung capacity"); + provider.add("symptom.gtceu.mining_fatigue", "Fatigue"); + provider.add("symptom.gtceu.weakness", "Weakness"); + provider.add("symptom.gtceu.slowness", "Slowness"); + provider.add("symptom.gtceu.blindness", "Blindness"); + provider.add("symptom.gtceu.darkness", "Darkness"); + provider.add("symptom.gtceu.nausea", "Nausea"); + provider.add("symptom.gtceu.wither", "Necrosis"); + provider.add("symptom.gtceu.weak_poisoning", "Weak poisoning"); + provider.add("symptom.gtceu.poisoning", "Poisoning"); + provider.add("symptom.gtceu.hunger", "Increased appetite"); + + provider.add("tooltip.gtceu.hazard_trigger", "Caused by:"); + provider.add("tooltip.gtceu.hazard_trigger.protection", "Protects from:"); + provider.add("tooltip.gtceu.hazard_trigger.inhalation", "Inhalation"); + provider.add("tooltip.gtceu.hazard_trigger.any", "Any contact"); + provider.add("tooltip.gtceu.hazard_trigger.skin_contact", "Skin contact"); + provider.add("tooltip.gtceu.hazard_trigger.none", "Nothing"); + + provider.add("tooltip.gtceu.antidote.description", "§aAntidote §7Hold Shift to show details"); + provider.add("tooltip.gtceu.antidote.description_shift", "§aCures these conditions:"); + provider.add("tooltip.gtceu.antidote.description.effect_removed", "Removes %s%% of current conditions' effects"); - provider.add("gtceu.medical_condition.antidote.description.effect_removed.all", + provider.add("tooltip.gtceu.antidote.description.effect_removed.all", "Removes all of current conditions' effects"); provider.add("gtceu.multiblock.dimension", "§eDimensions: §r%sx%sx%s"); @@ -193,7 +232,7 @@ public static void init(RegistrateLangProvider provider) { provider.add("item.gtceu.tool.behavior.crop_harvesting", "§aHarvester: §fHarvests Crops"); provider.add("item.gtceu.tool.behavior.plunger", "§9Plumber: §fDrains Fluids"); provider.add("item.gtceu.tool.behavior.block_rotation", "§2Mechanic: §fRotates Blocks"); - provider.add("item.gtceu.tool.behavior.dowse_campfire", "§1Firefighter: §fDowses Campfires"); + provider.add("item.gtceu.tool.behavior.dowse_campfire", "§6Firefighter: §fDowses Campfires"); provider.add("item.gtceu.tool.behavior.damage_boost", "§4Damage Boost: §fExtra damage against %s"); provider.add("item.gtceu.tool.behavior.prospecting.ore", "Found ore: %s"); provider.add("item.gtceu.tool.behavior.prospecting.air", "Found an air pocket"); 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 6b0d8527c1d..38835fbc589 100644 --- a/src/main/java/com/gregtechceu/gtceu/data/lang/ToolLang.java +++ b/src/main/java/com/gregtechceu/gtceu/data/lang/ToolLang.java @@ -53,16 +53,16 @@ private static void initDeathMessages(RegistrateLangProvider provider) { 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."); + "%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/nausea", "%s succumbed to 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/weak_poison", "%s ate lead"); provider.add("death.attack.gtceu.medical_condition/carbon_monoxide_poisoning", "%s left the stove on"); } 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 d829715d5de..e007aa4151b 100644 --- a/src/main/java/com/gregtechceu/gtceu/integration/kjs/GregTechKubeJSPlugin.java +++ b/src/main/java/com/gregtechceu/gtceu/integration/kjs/GregTechKubeJSPlugin.java @@ -473,7 +473,7 @@ public void registerTypeWrappers(ScriptType type, TypeWrappers typeWrappers) { }); typeWrappers.registerSimple(MedicalCondition.class, o -> { if (o instanceof MedicalCondition condition) return condition; - if (o instanceof CharSequence str) return MedicalCondition.CONDITIONS.get(str.toString()); + if (o instanceof CharSequence str) return GTRegistries.MEDICAL_CONDITIONS.get(GTCEu.id(str.toString())); return null; }); typeWrappers.registerSimple(IWorldGenLayer.RuleTestSupplier.class, o -> { diff --git a/src/main/java/com/gregtechceu/gtceu/utils/FormattingUtil.java b/src/main/java/com/gregtechceu/gtceu/utils/FormattingUtil.java index 493f7798fb9..caeaf139aed 100644 --- a/src/main/java/com/gregtechceu/gtceu/utils/FormattingUtil.java +++ b/src/main/java/com/gregtechceu/gtceu/utils/FormattingUtil.java @@ -15,6 +15,7 @@ import java.text.DecimalFormat; import java.text.NumberFormat; import java.util.Arrays; +import java.util.HexFormat; import java.util.Locale; import java.util.stream.Collectors; @@ -29,6 +30,7 @@ public class FormattingUtil { public static final DecimalFormat DECIMAL_FORMAT_2F = new DecimalFormat("#,##0.##"); public static final DecimalFormat DECIMAL_FORMAT_SIC = new DecimalFormat("0E00"); public static final DecimalFormat DECIMAL_FORMAT_SIC_2F = new DecimalFormat("0.00E00"); + public static final HexFormat HEX_FORMAT = HexFormat.of().withUpperCase(); private static final int SMALL_DOWN_NUMBER_BASE = '\u2080'; private static final int SMALL_UP_NUMBER_BASE = '\u2070'; diff --git a/src/main/java/com/gregtechceu/gtceu/utils/GTUtil.java b/src/main/java/com/gregtechceu/gtceu/utils/GTUtil.java index 04a9f1fefae..f43ee33f385 100644 --- a/src/main/java/com/gregtechceu/gtceu/utils/GTUtil.java +++ b/src/main/java/com/gregtechceu/gtceu/utils/GTUtil.java @@ -580,15 +580,13 @@ 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.medical_condition.description_shift")); - tooltipComponents.add(Component - .translatable("gtceu.medical_condition." + material.getProperty(HAZARD).condition.name)); - tooltipComponents.add(Component.translatable("gtceu.hazard_trigger.description")); - tooltipComponents.add(Component - .translatable("gtceu.hazard_trigger." + material.getProperty(HAZARD).hazardTrigger.name())); + tooltipComponents.add(Component.translatable("tooltip.gtceu.medical_condition.description_shift")); + tooltipComponents.add(material.getProperty(HAZARD).condition.getTranslatableName()); + tooltipComponents.add(Component.translatable("tooltip.gtceu.hazard_trigger")); + tooltipComponents.add(material.getProperty(HAZARD).hazardTrigger.getTranslatableName()); return; } - tooltipComponents.add(Component.translatable("gtceu.medical_condition.description")); + tooltipComponents.add(Component.translatable("tooltip.gtceu.medical_condition.description")); } public static CompoundTag saveItemStack(ItemStack itemStack, CompoundTag compoundTag) { diff --git a/src/main/java/com/gregtechceu/gtceu/utils/fakeplayer/FakeServerGamePacketListenerImpl.java b/src/main/java/com/gregtechceu/gtceu/utils/fakeplayer/FakeServerGamePacketListenerImpl.java new file mode 100644 index 00000000000..e828f23673e --- /dev/null +++ b/src/main/java/com/gregtechceu/gtceu/utils/fakeplayer/FakeServerGamePacketListenerImpl.java @@ -0,0 +1,207 @@ +package com.gregtechceu.gtceu.utils.fakeplayer; + +import net.minecraft.network.Connection; +import net.minecraft.network.PacketSendListener; +import net.minecraft.network.chat.ChatType; +import net.minecraft.network.chat.Component; +import net.minecraft.network.chat.PlayerChatMessage; +import net.minecraft.network.protocol.Packet; +import net.minecraft.network.protocol.PacketFlow; +import net.minecraft.network.protocol.game.*; +import net.minecraft.server.MinecraftServer; +import net.minecraft.server.level.ServerPlayer; +import net.minecraft.server.network.ServerGamePacketListenerImpl; +import net.minecraft.world.entity.RelativeMovement; + +import org.jetbrains.annotations.Nullable; + +import java.util.Set; + +import javax.annotation.ParametersAreNonnullByDefault; + +@ParametersAreNonnullByDefault +public class FakeServerGamePacketListenerImpl extends ServerGamePacketListenerImpl { + + private static final Connection DUMMY_CONNECTION = new Connection(PacketFlow.CLIENTBOUND); + + public FakeServerGamePacketListenerImpl(MinecraftServer server, ServerPlayer player) { + super(server, DUMMY_CONNECTION, player); + } + + @Override + public void tick() {} + + @Override + public void resetPosition() {} + + @Override + public void disconnect(Component message) {} + + @Override + public void handlePlayerInput(ServerboundPlayerInputPacket packet) {} + + @Override + public void handleMoveVehicle(ServerboundMoveVehiclePacket packet) {} + + @Override + public void handleAcceptTeleportPacket(ServerboundAcceptTeleportationPacket packet) {} + + @Override + public void handleRecipeBookSeenRecipePacket(ServerboundRecipeBookSeenRecipePacket packet) {} + + @Override + public void handleRecipeBookChangeSettingsPacket(ServerboundRecipeBookChangeSettingsPacket packet) {} + + @Override + public void handleSeenAdvancements(ServerboundSeenAdvancementsPacket packet) {} + + @Override + public void handleCustomCommandSuggestions(ServerboundCommandSuggestionPacket packet) {} + + @Override + public void handleSetCommandBlock(ServerboundSetCommandBlockPacket packet) {} + + @Override + public void handleSetCommandMinecart(ServerboundSetCommandMinecartPacket packet) {} + + @Override + public void handlePickItem(ServerboundPickItemPacket packet) {} + + @Override + public void handleRenameItem(ServerboundRenameItemPacket packet) {} + + @Override + public void handleSetBeaconPacket(ServerboundSetBeaconPacket packet) {} + + @Override + public void handleSetStructureBlock(ServerboundSetStructureBlockPacket packet) {} + + @Override + public void handleSetJigsawBlock(ServerboundSetJigsawBlockPacket packet) {} + + @Override + public void handleJigsawGenerate(ServerboundJigsawGeneratePacket packet) {} + + @Override + public void handleSelectTrade(ServerboundSelectTradePacket packet) {} + + @Override + public void handleEditBook(ServerboundEditBookPacket packet) {} + + @Override + public void handleEntityTagQuery(ServerboundEntityTagQuery packet) {} + + @Override + public void handleBlockEntityTagQuery(ServerboundBlockEntityTagQuery packet) {} + + @Override + public void handleMovePlayer(ServerboundMovePlayerPacket packet) {} + + @Override + public void teleport(double x, double y, double z, float yaw, float pitch) {} + + @Override + public void handlePlayerAction(ServerboundPlayerActionPacket packet) {} + + @Override + public void handleUseItemOn(ServerboundUseItemOnPacket packet) {} + + @Override + public void handleUseItem(ServerboundUseItemPacket packet) {} + + @Override + public void handleTeleportToEntityPacket(ServerboundTeleportToEntityPacket packet) {} + + @Override + public void handleResourcePackResponse(ServerboundResourcePackPacket packet) {} + + @Override + public void handlePaddleBoat(ServerboundPaddleBoatPacket packet) {} + + @Override + public void onDisconnect(Component message) {} + + @Override + public void send(Packet packet) {} + + @Override + public void send(Packet packet, @Nullable PacketSendListener sendListener) {} + + @Override + public void handleSetCarriedItem(ServerboundSetCarriedItemPacket packet) {} + + @Override + public void handleChat(ServerboundChatPacket packet) {} + + @Override + public void handleAnimate(ServerboundSwingPacket packet) {} + + @Override + public void handlePlayerCommand(ServerboundPlayerCommandPacket packet) {} + + @Override + public void handleInteract(ServerboundInteractPacket packet) {} + + @Override + public void handleClientCommand(ServerboundClientCommandPacket packet) {} + + @Override + public void handleContainerClose(ServerboundContainerClosePacket packet) {} + + @Override + public void handleContainerClick(ServerboundContainerClickPacket packet) {} + + @Override + public void handlePlaceRecipe(ServerboundPlaceRecipePacket packet) {} + + @Override + public void handleContainerButtonClick(ServerboundContainerButtonClickPacket packet) {} + + @Override + public void handleSetCreativeModeSlot(ServerboundSetCreativeModeSlotPacket packet) {} + + @Override + public void handleSignUpdate(ServerboundSignUpdatePacket packet) {} + + @Override + public void handleKeepAlive(ServerboundKeepAlivePacket packet) {} + + @Override + public void handlePlayerAbilities(ServerboundPlayerAbilitiesPacket packet) {} + + @Override + public void handleClientInformation(ServerboundClientInformationPacket packet) {} + + @Override + public void handleCustomPayload(ServerboundCustomPayloadPacket packet) {} + + @Override + public void handleChangeDifficulty(ServerboundChangeDifficultyPacket packet) {} + + @Override + public void handleLockDifficulty(ServerboundLockDifficultyPacket packet) {} + + @Override + public void teleport(double x, double y, double z, float yaw, float pitch, Set relativeSet) {} + + @Override + public void ackBlockChangesUpTo(int sequence) {} + + @Override + public void handleChatCommand(ServerboundChatCommandPacket packet) {} + + @Override + public void handleChatAck(ServerboundChatAckPacket packet) {} + + @Override + public void addPendingMessage(PlayerChatMessage message) {} + + @Override + public void sendPlayerChatMessage(PlayerChatMessage message, ChatType.Bound boundChatType) {} + + @Override + public void sendDisguisedChatMessage(Component content, ChatType.Bound boundChatType) {} + + @Override + public void handleChatSessionUpdate(ServerboundChatSessionUpdatePacket packet) {} +} diff --git a/src/main/resources/assets/gtceu/lang/ja_jp.json b/src/main/resources/assets/gtceu/lang/ja_jp.json index e734b1e3c55..f1d64562414 100644 --- a/src/main/resources/assets/gtceu/lang/ja_jp.json +++ b/src/main/resources/assets/gtceu/lang/ja_jp.json @@ -2457,12 +2457,12 @@ "gtceu.gui.toggle_view.disabled": "液体スロット切り替え", "gtceu.gui.toggle_view.enabled": "アイテムスロット切り替え", "gtceu.gui.waiting_list": "送信キュー:", - "gtceu.hazard_trigger.any": "接続先", - "gtceu.hazard_trigger.description": "原因:", - "gtceu.hazard_trigger.inhalation": "吸入", - "gtceu.hazard_trigger.none": "何もない", - "gtceu.hazard_trigger.protection.description": "保護する:", - "gtceu.hazard_trigger.skin_contact": "皮膚接触", + "tooltip.gtceu.hazard_trigger.any": "接続先", + "tooltip.gtceu.hazard_trigger": "原因:", + "tooltip.gtceu.hazard_trigger.inhalation": "吸入", + "tooltip.gtceu.hazard_trigger.none": "何もない", + "tooltip.gtceu.hazard_trigger.protection": "保護する:", + "tooltip.gtceu.hazard_trigger.skin_contact": "皮膚接触", "gtceu.implosion_compressor": "内破圧縮機", "gtceu.io.both": "両方", "gtceu.io.export": "搬出", @@ -3208,25 +3208,23 @@ "gtceu.maintenance.configurable_time": "故障率: %fx", "gtceu.maintenance.configurable_time.changed_description": "故障は通常の%f倍の頻度で発生します", "gtceu.maintenance.configurable_time.unchanged_description": "故障は通常の頻度で発生します。設定を変更するとアップデートされます。", - "gtceu.medical_condition.antidote.description": "§a解毒剤 §7Shiftを押して詳細を表示する", - "gtceu.medical_condition.antidote.description.effect_removed": "現在の状態の効果を%s%%で取り除く", - "gtceu.medical_condition.antidote.description.effect_removed.all": "現在の状態の効果をすべて取り除く", - "gtceu.medical_condition.antidote.description_shift": "§aこれらの状態を治す:", - "gtceu.medical_condition.arsenicosis": "§bヒ素中毒", - "gtceu.medical_condition.asbestosis": "§dアスベスト症", - "gtceu.medical_condition.berylliosis": "§5ベリリウム症", - "gtceu.medical_condition.carbon_monoxide_poisoning": "§7一酸化炭素中毒", - "gtceu.medical_condition.carcinogen": "§e発がん性", - "gtceu.medical_condition.chemical_burns": "§5化学熱傷", - "gtceu.medical_condition.description": "§l§c汚染§7 詳細を表示するにはshiftを押す", - "gtceu.medical_condition.description_shift": "§l§c汚染:", - "gtceu.medical_condition.irritant": "§6発疹", - "gtceu.medical_condition.methanol_poisoning": "§6メタノール中毒", - "gtceu.medical_condition.nausea": "§3吐き気", - "gtceu.medical_condition.none": "§2危険ではない", - "gtceu.medical_condition.poison": "§2有毒", - "gtceu.medical_condition.silicosis": "§1珪肺", - "gtceu.medical_condition.weak_poison": "§a弱毒", + "tooltip.gtceu.antidote.description": "§a解毒剤 §7Shiftを押して詳細を表示する", + "tooltip.gtceu.antidote.description.effect_removed": "現在の状態の効果を%s%%で取り除く", + "tooltip.gtceu.antidote.description.effect_removed.all": "現在の状態の効果をすべて取り除く", + "tooltip.gtceu.antidote.description_shift": "§aこれらの状態を治す:", + "medical_condition.gtceu.arsenicosis": "§bヒ素中毒", + "medical_condition.gtceu.asbestosis": "§dアスベスト症", + "medical_condition.gtceu.carbon_monoxide_poisoning": "§7一酸化炭素中毒", + "medical_condition.gtceu.carcinogen": "§e発がん性", + "medical_condition.gtceu.chemical_burns": "§5化学熱傷", + "tooltip.gtceu.medical_condition.description": "§l§c汚染§7 詳細を表示するにはshiftを押す", + "tooltip.gtceu.medical_condition.description_shift": "§l§c汚染:", + "medical_condition.gtceu.irritant": "§6発疹", + "medical_condition.gtceu.methanol_poisoning": "§6メタノール中毒", + "medical_condition.gtceu.nausea": "§3吐き気", + "medical_condition.gtceu.none": "§2危険ではない", + "medical_condition.gtceu.poison": "§2有毒", + "medical_condition.gtceu.weak_poison": "§a弱毒", "gtceu.minimap.ore_vein.depleted": "枯渇", "gtceu.mixer": "ミキサー", "gtceu.mode.both": "§d両方(液体とアイテム) §r", diff --git a/src/main/resources/assets/gtceu/lang/ru_ru.json b/src/main/resources/assets/gtceu/lang/ru_ru.json index 49a097fe4c1..d681ed7a117 100644 --- a/src/main/resources/assets/gtceu/lang/ru_ru.json +++ b/src/main/resources/assets/gtceu/lang/ru_ru.json @@ -5008,22 +5008,20 @@ "config.gtceu.option.meHatchEnergyUsage": "meHatchEnergyUsage", "config.gtceu.option.orderedAssemblyLineFluids": "orderedAssemblyLineFluids", "config.gtceu.option.orderedAssemblyLineItems": "orderedAssemblyLineItems", - "gtceu.medical_condition.antidote.description.effect_removed.all": "Убирает все последствия текущих заболеваний", - "gtceu.medical_condition.antidote.description.effect_removed": "Убирает %s%% последствий текущих заболеваний", - "gtceu.medical_condition.antidote.description_shift": "§aЛечит следующие заболевания:", - "gtceu.medical_condition.antidote.description": "§aАнтидот §7Зажмите Shift, чтобы просмотреть подробную информацию", - "gtceu.medical_condition.arsenicosis": "§bОтравление мышьяком", - "gtceu.medical_condition.asbestosis": "§dАсбестоз", - "gtceu.medical_condition.berylliosis": "§5Бериллиоз", - "gtceu.medical_condition.carcinogen": "§eКанцерогенный", - "gtceu.medical_condition.chemical_burns": "§5Химический ожог", - "gtceu.medical_condition.description_shift": "§l§cОПАСНЫЙ:", - "gtceu.medical_condition.methanol_poisoning": "§6Отравление метанолом", - "gtceu.medical_condition.nausea": "§3Тошнотворный", - "gtceu.medical_condition.none": "§2Не опасный", - "gtceu.medical_condition.poison": "§2Ядовитый", - "gtceu.medical_condition.silicosis": "§1Силикоз", - "gtceu.medical_condition.weak_poison": "§aСлабо ядовитый", + "tooltip.gtceu.antidote.description.effect_removed.all": "Убирает все последствия текущих заболеваний", + "tooltip.gtceu.antidote.description.effect_removed": "Убирает %s%% последствий текущих заболеваний", + "tooltip.gtceu.antidote.description_shift": "§aЛечит следующие заболевания:", + "tooltip.gtceu.antidote.description": "§aАнтидот §7Зажмите Shift, чтобы просмотреть подробную информацию", + "medical_condition.gtceu.arsenicosis": "§bОтравление мышьяком", + "medical_condition.gtceu.asbestosis": "§dАсбестоз", + "medical_condition.gtceu.carcinogen": "§eКанцерогенный", + "medical_condition.gtceu.chemical_burns": "§5Химический ожог", + "tooltip.gtceu.medical_condition.description_shift": "§l§cОПАСНЫЙ:", + "medical_condition.gtceu.methanol_poisoning": "§6Отравление метанолом", + "medical_condition.gtceu.nausea": "§3Тошнотворный", + "medical_condition.gtceu.none": "§2Не опасный", + "medical_condition.gtceu.poison": "§2Ядовитый", + "medical_condition.gtceu.weak_poison": "§aСлабо ядовитый", "gtceu.recipe.total_computation": "Вычисление: %s CWU", "gtceu.subtitle.assembler": "Сборщик собирает", "gtceu.subtitle.bath": "Ванна шипит", @@ -5072,12 +5070,12 @@ "config.gtceu.option.ae2": "ae2", "block.gtceu.mv_air_scrubber": "§bУлучшенный очиститель воздуха §r", "config.gtceu.option.energyConsumption": "energyConsumption", - "gtceu.medical_condition.carbon_monoxide_poisoning": "§7Отравление угарным газом", + "medical_condition.gtceu.carbon_monoxide_poisoning": "§7Отравление угарным газом", "gtceu.subtitle.file": "Напильник скрежет", "gtceu.subtitle.macerator": "Измельчитель измельчает", "gtceu.subtitle.replicator": "Репликатор копирует", "gtceu.top.item_auto_output": "Вывод предметов: %s", - "gtceu.medical_condition.description": "§l§cОПАСНЫЙ §7Удерживайте Shift, чтобы просмотреть подробную информацию", + "tooltip.gtceu.medical_condition.description": "§l§cОПАСНЫЙ §7Удерживайте Shift, чтобы просмотреть подробную информацию", "gtceu.subtitle.combustion": "Сгорание", "gtceu.subtitle.computation": "Компьютер пикает", "gtceu.subtitle.metal_pipe": "Очень_громкий_металичнский_труба.wav", @@ -5123,14 +5121,14 @@ "gtceu.air_scrubber": "Очиститель воздуха", "gtceu.duct_pipe.transfer_rate": "§bСкорость передачи воздуха: %s", "gtceu.evaporation": "Выпаривание", - "gtceu.hazard_trigger.any": "При любом контакте", - "gtceu.hazard_trigger.description": "Проявляется при:", - "gtceu.hazard_trigger.inhalation": "Вдыхание вредных веществ", - "gtceu.hazard_trigger.none": "Ничем", - "gtceu.hazard_trigger.protection.description": "Защищает от:", - "gtceu.hazard_trigger.skin_contact": "Контакт с кожей", + "tooltip.gtceu.hazard_trigger.any": "При любом контакте", + "tooltip.gtceu.hazard_trigger": "Проявляется при:", + "tooltip.gtceu.hazard_trigger.inhalation": "Вдыхание вредных веществ", + "tooltip.gtceu.hazard_trigger.none": "Ничем", + "tooltip.gtceu.hazard_trigger.protection": "Защищает от:", + "tooltip.gtceu.hazard_trigger.skin_contact": "Контакт с кожей", "gtceu.jade.cleaned_this_second": "Убирает опасность: %s/с", - "gtceu.medical_condition.irritant": "§6Раздражитель", + "medical_condition.gtceu.irritant": "§6Раздражитель", "gtceu.subtitle.turbine": "Турбина воет", "gtceu.subtitle.wirecutter": "Провод перекусился", "gtceu.subtitle.wrench": "Ключ стрекочет", diff --git a/src/main/resources/assets/gtceu/lang/uk_ua.json b/src/main/resources/assets/gtceu/lang/uk_ua.json index cc680221e39..d9acf9579b9 100644 --- a/src/main/resources/assets/gtceu/lang/uk_ua.json +++ b/src/main/resources/assets/gtceu/lang/uk_ua.json @@ -2474,13 +2474,13 @@ "gtceu.gui.title_bar.page_switcher": "Сторінки", "gtceu.gui.toggle_view.disabled": "Перемкнути вид (Рідини)", "gtceu.gui.toggle_view.enabled": "Перемкнути вид (Предмети)", - "gtceu.gui.waiting_list": "Черга на відправлення:", - "gtceu.hazard_trigger.any": "При будь-якому контакті", - "gtceu.hazard_trigger.description": "Спричиняється:", - "gtceu.hazard_trigger.inhalation": "При вдиханні", - "gtceu.hazard_trigger.none": "Ніяк", - "gtceu.hazard_trigger.protection.description": "Захищає:", - "gtceu.hazard_trigger.skin_contact": "При контакті зі шкірою", + "gtceu.gui.waiting_list": "Черга надсилання:", + "tooltip.gtceu.hazard_trigger": "Спричиняється:", + "tooltip.gtceu.hazard_trigger.protection": "Захищає:", + "tooltip.gtceu.hazard_trigger.any": "При будь-якому контакті", + "tooltip.gtceu.hazard_trigger.inhalation": "При вдиханні", + "tooltip.gtceu.hazard_trigger.skin_contact": "При контакті зі шкірою", + "tooltip.gtceu.hazard_trigger.none": "Ніяк", "gtceu.implosion_compressor": "Компресор надмірного тиску", "gtceu.io.both": "Обидва", "gtceu.io.export": "Експорт", @@ -3227,25 +3227,23 @@ "gtceu.maintenance.configurable_time": "Час: %fx", "gtceu.maintenance.configurable_time.changed_description": "Проблеми з обслуговуванням виникатимуть у %f разів частіше.", "gtceu.maintenance.configurable_time.unchanged_description": "Проблеми з обслуговуванням виникатимуть зі звичайною швидкістю. Змініть конфігурацію для оновлення.", - "gtceu.medical_condition.antidote.description": "§aПротиотрута§7 Утримуйте Shift для подробиць", - "gtceu.medical_condition.antidote.description.effect_removed": "Знешкоджує %s%% наявних ефектів уражень", - "gtceu.medical_condition.antidote.description.effect_removed.all": "Знешкоджує усі ураження", - "gtceu.medical_condition.antidote.description_shift": "§aВиліковує ці ураження:", - "gtceu.medical_condition.arsenicosis": "§bОтруєння миш'яком", - "gtceu.medical_condition.asbestosis": "§dАзбестоз", - "gtceu.medical_condition.berylliosis": "§5Бериліоз", - "gtceu.medical_condition.carbon_monoxide_poisoning": "§7Отруєння монооксидом вуглецю", - "gtceu.medical_condition.carcinogen": "§eРадіоактивне опромінення", - "gtceu.medical_condition.chemical_burns": "§5Хімічні опіки", - "gtceu.medical_condition.description": "§l§cНЕБЕЗПЕЧНО§7 Утримуйте Shift для подробиць", - "gtceu.medical_condition.description_shift": "§l§cНЕБЕЗПЕКА:", - "gtceu.medical_condition.irritant": "§6Подразення", - "gtceu.medical_condition.methanol_poisoning": "§6Отруєння метанолом", - "gtceu.medical_condition.nausea": "§3Нудота", - "gtceu.medical_condition.none": "§2(Не²)Безпечно", - "gtceu.medical_condition.poison": "§2Отрута", - "gtceu.medical_condition.silicosis": "§1Силікоз", - "gtceu.medical_condition.weak_poison": "§aСлабка отрута", + "tooltip.gtceu.antidote.description": "§aПротиотрута§7 Утримуйте Shift для подробиць", + "tooltip.gtceu.antidote.description.effect_removed": "Знешкоджує %s%% наявних ефектів уражень", + "tooltip.gtceu.antidote.description.effect_removed.all": "Знешкоджує усі ураження", + "tooltip.gtceu.antidote.description_shift": "§aВиліковує ці ураження:", + "tooltip.gtceu.medical_condition.description": "§l§cНЕБЕЗПЕЧНО§7 Утримуйте Shift для подробиць", + "tooltip.gtceu.medical_condition.description_shift": "§l§cНЕБЕЗПЕКА:", + "medical_condition.gtceu.arsenicosis": "§bОтруєння миш'яком", + "medical_condition.gtceu.asbestosis": "§dАзбестоз", + "medical_condition.gtceu.carbon_monoxide_poisoning": "§7Отруєння монооксидом вуглецю", + "medical_condition.gtceu.carcinogen": "§eРадіоактивне опромінення", + "medical_condition.gtceu.chemical_burns": "§5Хімічні опіки", + "medical_condition.gtceu.irritant": "§6Подразення", + "medical_condition.gtceu.methanol_poisoning": "§6Отруєння метанолом", + "medical_condition.gtceu.nausea": "§3Нудота", + "medical_condition.gtceu.none": "§2(Не²)Безпечно", + "medical_condition.gtceu.poison": "§2Отрута", + "medical_condition.gtceu.weak_poison": "§aСлабка отрута", "gtceu.minimap.ore_vein.depleted": "Виснажено", "gtceu.mixer": "Змішувач", "gtceu.mode.both": "§dСпільний (Рідини та предмети)§r", @@ -5881,7 +5879,7 @@ "tile.gtceu.reinforced_foam.name": "Посилена піна", "tile.gtceu.reinforced_stone.name": "Зміцнений камінь", "tile.gtceu.seal.name": "Герметичний блок", - + "comment": "застарілі рядки", "behaviour.soft_hammer.idle_after_cycle": "Зупинити машину після завершення циклу роботи", "block.gtceu.evaporation_plant": "Випарна вежа", diff --git a/src/main/resources/assets/gtceu/lang/zh_cn.json b/src/main/resources/assets/gtceu/lang/zh_cn.json index 057f5ffa80c..03f03315e53 100644 --- a/src/main/resources/assets/gtceu/lang/zh_cn.json +++ b/src/main/resources/assets/gtceu/lang/zh_cn.json @@ -2488,12 +2488,12 @@ "gtceu.gui.toggle_view.disabled": "切换视图(流体)", "gtceu.gui.toggle_view.enabled": "切换视图(物品)", "gtceu.gui.waiting_list": "发送队列:", - "gtceu.hazard_trigger.any": "任何方式", - "gtceu.hazard_trigger.description": "由此导致:", - "gtceu.hazard_trigger.inhalation": "吸入", - "gtceu.hazard_trigger.none": "无", - "gtceu.hazard_trigger.protection.description": "免受:", - "gtceu.hazard_trigger.skin_contact": "皮肤接触", + "tooltip.gtceu.hazard_trigger.any": "任何方式", + "tooltip.gtceu.hazard_trigger": "由此导致:", + "tooltip.gtceu.hazard_trigger.inhalation": "吸入", + "tooltip.gtceu.hazard_trigger.none": "无", + "tooltip.gtceu.hazard_trigger.protection": "免受:", + "tooltip.gtceu.hazard_trigger.skin_contact": "皮肤接触", "gtceu.implosion_compressor": "聚爆压缩机", "gtceu.io.both": "同时", "gtceu.io.export": "输出", @@ -3249,25 +3249,23 @@ "gtceu.maintenance.configurable_time": "故障概率:%fx", "gtceu.maintenance.configurable_time.changed_description": "故障的发生概率现为正常值的%f倍。", "gtceu.maintenance.configurable_time.unchanged_description": "故障的发生概率为正常值。更改配置以更新。", - "gtceu.medical_condition.antidote.description": "§a解毒剂 §7按住Shift以显示详情", - "gtceu.medical_condition.antidote.description.effect_removed": "疾病效果持续时间降低%s%%", - "gtceu.medical_condition.antidote.description.effect_removed.all": "消除所有疾病效果", - "gtceu.medical_condition.antidote.description_shift": "§a治愈以下疾病:", - "gtceu.medical_condition.arsenicosis": "§b砷中毒", - "gtceu.medical_condition.asbestosis": "§d石棉肺", - "gtceu.medical_condition.berylliosis": "§5铍中毒", - "gtceu.medical_condition.carbon_monoxide_poisoning": "§7一氧化碳污染", - "gtceu.medical_condition.carcinogen": "§e致癌", - "gtceu.medical_condition.chemical_burns": "§5化学烧伤", - "gtceu.medical_condition.description": "§c§l危险物质 §7按住Shift以显示详情", - "gtceu.medical_condition.description_shift": "§c§l危险物质:", - "gtceu.medical_condition.irritant": "§6刺激性", - "gtceu.medical_condition.methanol_poisoning": "§6甲醇中毒", - "gtceu.medical_condition.nausea": "§3恶心", - "gtceu.medical_condition.none": "§2无害", - "gtceu.medical_condition.poison": "§2中毒", - "gtceu.medical_condition.silicosis": "§1矽肺病", - "gtceu.medical_condition.weak_poison": "§a轻度中毒", + "tooltip.gtceu.antidote.description": "§a解毒剂 §7按住Shift以显示详情", + "tooltip.gtceu.antidote.description.effect_removed": "疾病效果持续时间降低%s%%", + "tooltip.gtceu.antidote.description.effect_removed.all": "消除所有疾病效果", + "tooltip.gtceu.antidote.description_shift": "§a治愈以下疾病:", + "medical_condition.gtceu.arsenicosis": "§b砷中毒", + "medical_condition.gtceu.asbestosis": "§d石棉肺", + "medical_condition.gtceu.carbon_monoxide_poisoning": "§7一氧化碳污染", + "medical_condition.gtceu.carcinogen": "§e致癌", + "medical_condition.gtceu.chemical_burns": "§5化学烧伤", + "tooltip.gtceu.medical_condition.description": "§c§l危险物质 §7按住Shift以显示详情", + "tooltip.gtceu.medical_condition.description_shift": "§c§l危险物质:", + "medical_condition.gtceu.irritant": "§6刺激性", + "medical_condition.gtceu.methanol_poisoning": "§6甲醇中毒", + "medical_condition.gtceu.nausea": "§3恶心", + "medical_condition.gtceu.none": "§2无害", + "medical_condition.gtceu.poison": "§2中毒", + "medical_condition.gtceu.weak_poison": "§a轻度中毒", "gtceu.minimap.ore_vein.depleted": "已枯竭", "gtceu.mixer": "搅拌机", "gtceu.mode.both": "§d全部(流体和物品)§r", diff --git a/src/main/resources/assets/gtceu/lang/zh_tw.json b/src/main/resources/assets/gtceu/lang/zh_tw.json index d295c7330e8..15f79b5205b 100644 --- a/src/main/resources/assets/gtceu/lang/zh_tw.json +++ b/src/main/resources/assets/gtceu/lang/zh_tw.json @@ -2382,12 +2382,12 @@ "gtceu.gui.toggle_view.disabled": "切換檢視(流體)", "gtceu.gui.toggle_view.enabled": "切換檢視(物品)", "gtceu.gui.waiting_list": "傳送佇列:", - "gtceu.hazard_trigger.any": "任何方式", - "gtceu.hazard_trigger.description": "肇因:", - "gtceu.hazard_trigger.inhalation": "吸入", - "gtceu.hazard_trigger.none": "無", - "gtceu.hazard_trigger.protection.description": "免受:", - "gtceu.hazard_trigger.skin_contact": "皮膚接觸", + "tooltip.gtceu.hazard_trigger.any": "任何方式", + "tooltip.gtceu.hazard_trigger": "肇因:", + "tooltip.gtceu.hazard_trigger.inhalation": "吸入", + "tooltip.gtceu.hazard_trigger.none": "無", + "tooltip.gtceu.hazard_trigger.protection": "免受:", + "tooltip.gtceu.hazard_trigger.skin_contact": "皮膚接觸", "gtceu.implosion_compressor": "聚爆壓縮機", "gtceu.io.both": "同時", "gtceu.io.export": "輸出", @@ -3128,25 +3128,23 @@ "gtceu.maintenance.configurable_time": "故障機率:%fx", "gtceu.maintenance.configurable_time.changed_description": "故障的發生機率現為正常值的%f倍。", "gtceu.maintenance.configurable_time.unchanged_description": "故障的發生機率為正常值。更改設定以更新。", - "gtceu.medical_condition.antidote.description": "§a解毒劑 §7按住Shift以顯示詳情", - "gtceu.medical_condition.antidote.description.effect_removed": "疾病效果持續時間降低%s%%", - "gtceu.medical_condition.antidote.description.effect_removed.all": "消除所有疾病效果", - "gtceu.medical_condition.antidote.description_shift": "§a治癒以下疾病:", - "gtceu.medical_condition.arsenicosis": "§b砷中毒", - "gtceu.medical_condition.asbestosis": "§d石棉肺", - "gtceu.medical_condition.berylliosis": "§5鈹中毒", - "gtceu.medical_condition.carbon_monoxide_poisoning": "§7一氧化碳汙染", - "gtceu.medical_condition.carcinogen": "§e致癌", - "gtceu.medical_condition.chemical_burns": "§5化學燒傷", - "gtceu.medical_condition.description": "§c§l危險物質 §7按住Shift以顯示詳情", - "gtceu.medical_condition.description_shift": "§c§l危險物質:", - "gtceu.medical_condition.irritant": "§6刺激性", - "gtceu.medical_condition.methanol_poisoning": "§6甲醇中毒", - "gtceu.medical_condition.nausea": "§3噁心", - "gtceu.medical_condition.none": "§2無害", - "gtceu.medical_condition.poison": "§2中毒", - "gtceu.medical_condition.silicosis": "§1矽肺病", - "gtceu.medical_condition.weak_poison": "§a輕度中毒", + "tooltip.gtceu.antidote.description": "§a解毒劑 §7按住Shift以顯示詳情", + "tooltip.gtceu.antidote.description.effect_removed": "疾病效果持續時間降低%s%%", + "tooltip.gtceu.antidote.description.effect_removed.all": "消除所有疾病效果", + "tooltip.gtceu.antidote.description_shift": "§a治癒以下疾病:", + "medical_condition.gtceu.arsenicosis": "§b砷中毒", + "medical_condition.gtceu.asbestosis": "§d石棉肺", + "medical_condition.gtceu.carbon_monoxide_poisoning": "§7一氧化碳汙染", + "medical_condition.gtceu.carcinogen": "§e致癌", + "medical_condition.gtceu.chemical_burns": "§5化學燒傷", + "tooltip.gtceu.medical_condition.description": "§c§l危險物質 §7按住Shift以顯示詳情", + "tooltip.gtceu.medical_condition.description_shift": "§c§l危險物質:", + "medical_condition.gtceu.irritant": "§6刺激性", + "medical_condition.gtceu.methanol_poisoning": "§6甲醇中毒", + "medical_condition.gtceu.nausea": "§3噁心", + "medical_condition.gtceu.none": "§2無害", + "medical_condition.gtceu.poison": "§2中毒", + "medical_condition.gtceu.weak_poison": "§a輕度中毒", "gtceu.minimap.ore_vein.depleted": "已枯竭", "gtceu.mixer": "攪拌機", "gtceu.mode.both": "§d全部(流體和物品)§r", diff --git a/src/test/java/com/gregtechceu/gtceu/common/capability/MedicalConditionTest.java b/src/test/java/com/gregtechceu/gtceu/common/capability/MedicalConditionTest.java new file mode 100644 index 00000000000..41cb339519f --- /dev/null +++ b/src/test/java/com/gregtechceu/gtceu/common/capability/MedicalConditionTest.java @@ -0,0 +1,340 @@ +package com.gregtechceu.gtceu.common.capability; + +import com.gregtechceu.gtceu.GTCEu; +import com.gregtechceu.gtceu.api.data.chemical.ChemicalHelper; +import com.gregtechceu.gtceu.api.data.medicalcondition.Symptom; +import com.gregtechceu.gtceu.api.data.tag.TagPrefix; +import com.gregtechceu.gtceu.common.data.GTItems; +import com.gregtechceu.gtceu.common.data.GTMaterials; +import com.gregtechceu.gtceu.common.data.GTMedicalConditions; +import com.gregtechceu.gtceu.gametest.util.TestUtils; + +import net.minecraft.gametest.framework.BeforeBatch; +import net.minecraft.gametest.framework.GameTest; +import net.minecraft.gametest.framework.GameTestHelper; +import net.minecraft.server.level.ServerLevel; +import net.minecraft.server.level.ServerPlayer; +import net.minecraft.util.Mth; +import net.minecraft.world.InteractionHand; +import net.minecraft.world.effect.MobEffectInstance; +import net.minecraft.world.effect.MobEffects; +import net.minecraft.world.entity.EquipmentSlot; +import net.minecraft.world.entity.ai.attributes.Attributes; +import net.minecraft.world.item.ItemStack; +import net.minecraft.world.item.Items; +import net.minecraftforge.gametest.GameTestHolder; +import net.minecraftforge.gametest.PrefixGameTestTemplate; + +import lombok.experimental.ExtensionMethod; + +@SuppressWarnings("unused") +@PrefixGameTestTemplate(false) +@GameTestHolder(GTCEu.MOD_ID) +@ExtensionMethod({ TestUtils.class, MedicalConditionTestHelpers.class }) +public class MedicalConditionTest { + + @BeforeBatch(batch = "medical_conditions") + public static void prepare(ServerLevel level) {} + + // spotless:off + // FIXME this is optional because the nausea potion effect doesnt want to stick + // and I haven't been able to figure out why + @GameTest(template = "empty", batch = "medical_conditions", timeoutTicks = 450, required = false) + public static void testMedicalConditionTicking(GameTestHelper helper) { + ServerPlayer player = helper.makeMockSurvivalServerPlayer(); + // add a reasonable count of nausea (100 counts) + helper.addMedicalConditionCounts(player, GTMedicalConditions.NAUSEA, 450); + + helper.startSequence() + // tick the medical condition tracker for 5 seconds + // this clears 20 counts of nausea + .thenExecuteFor(2 * 20, player::doTick) + // check if player has nausea effect + .thenExecute(() -> helper.assertTrue(player.hasEffect(MobEffects.CONFUSION), + "Player " + player + " should have nausea effect")) + // remove extra nausea + .thenExecute(() -> helper.getMedicalConditionTracker(player).heal(GTMedicalConditions.NAUSEA, 350)) + // nausea condition lowers by 5 'counts' per second + // so the player should have it for another (90 / 5) = 18 seconds + // see comment on the next thing for explanation about why 15 instead of 18 + .thenExecuteFor(15 * 20, () -> { + player.doTick(); + helper.assertHasCondition(player, GTMedicalConditions.NAUSEA); + }) + // I'm not actually sure how long this should be applying for, so... + // tick the player for 5 more seconds, just to be safe + .thenExecuteFor(5 * 20, player::doTick) + .thenExecute(() -> helper.assertFreeOfCondition(player, GTMedicalConditions.NAUSEA)) + .thenSucceed(); + } + + @GameTest(template = "empty", batch = "medical_conditions", timeoutTicks = 450) + public static void testItemHazardApplication(GameTestHelper helper) { + ServerPlayer player = helper.makeMockSurvivalServerPlayer(); + // give player 1x Nt ingot (VERY radioactive, 10 'counts' per second) + player.addItem(ChemicalHelper.get(TagPrefix.ingot, GTMaterials.Neutronium)); + + helper.startSequence() + // tick the medical condition tracker for 10 seconds + .thenExecuteFor(10 * 20, player::doTick) + // check if player has 100 'counts' of cancer + .thenExecute(() -> helper.assertConditionCountEquals(player, GTMedicalConditions.CARCINOGEN, 100)) + // remove Nt ingot from player + .thenExecute(() -> player.getInventory().clearContent()) + // tick the medical condition tracker for 10 seconds + .thenExecuteFor(10 * 20, player::doTick) + // check that count hasn't changed + .thenExecute(() -> helper.assertConditionCountEquals(player, GTMedicalConditions.CARCINOGEN, 100)) + // add more cancer to reach max slowness symptom + .thenExecute(() -> helper.setMedicalConditionCounts(player, GTMedicalConditions.CARCINOGEN, 18000)) + // tick the medical condition tracker for 2 ticks, just to be safe + .thenExecuteFor(2, player::doTick) + // check that the slowness attribute modifier is properly applied. + .thenExecute(() -> { + double modifier = MedicalConditionTestHelpers.getAndAssertAttributeModifier(player, Attributes.MOVEMENT_SPEED, Symptom.SYMPTOM_SLOWNESS_UUID); + // this value is based on the slowness symptom's default stage count and multiplier (7 and 0.08 respectively) + helper.assertTrue(Mth.equal(modifier, -7 * 0.05f), + "Slowness symprom attribute modifier should have a value of " + (-7 * 0.05f) + " at 18000 counts. (is " + modifier + ")"); + }) + .thenSucceed(); + } + + @GameTest(template = "empty", batch = "medical_conditions", timeoutTicks = 450) + public static void testHazardProtectionInhalation(GameTestHelper helper) { + ServerPlayer player = helper.makeMockSurvivalServerPlayer(); + // equip face mask + player.setItemSlot(EquipmentSlot.HEAD, GTItems.FACE_MASK.asStack()); + // give 16x asbestos dust + player.addItem(ChemicalHelper.get(TagPrefix.dust, GTMaterials.Asbestos, 16)); + + helper.startSequence() + // tick the medical condition tracker for 10 seconds + .thenExecuteFor(10 * 20, player::doTick) + // check if player did NOT get asbestosis + .thenExecute(() -> helper.assertFreeOfCondition(player, GTMedicalConditions.ASBESTOSIS)) + // remove face mask + .thenExecute(() -> player.setItemSlot(EquipmentSlot.HEAD, ItemStack.EMPTY)) + // tick the medical condition tracker for 10 seconds + .thenExecuteFor(10 * 20, player::doTick) + // check if player DID get asbestosis this time + .thenExecute(() -> { + if (!player.isAlive()) return; // we don't care if the player died here, that means the asbestos got them + helper.assertHasCondition(player, GTMedicalConditions.ASBESTOSIS); + }) + .thenSucceed(); + } + + @GameTest(template = "empty", batch = "medical_conditions", timeoutTicks = 450) + public static void testHazardProtectionSkinContact(GameTestHelper helper) { + ServerPlayer player = helper.makeMockSurvivalServerPlayer(); + // equip rubber gloves + player.setItemSlot(EquipmentSlot.CHEST, GTItems.RUBBER_GLOVES.asStack()); + // give a bucket of Fluorine + player.addItem(new ItemStack(GTMaterials.Fluorine.getBucket())); + + helper.startSequence() + // tick the medical condition tracker for 10 seconds + .thenExecuteFor(10 * 20, player::doTick) + // check if player did NOT get chemical burns + .thenExecute(() -> helper.assertFreeOfCondition(player, GTMedicalConditions.CHEMICAL_BURNS)) + // remove rubber gloves + .thenExecute(() -> player.setItemSlot(EquipmentSlot.CHEST, ItemStack.EMPTY)) + // tick the medical condition tracker for 10 seconds + .thenExecuteFor(10 * 20, player::doTick) + // check if player DID get chemical burns this time + .thenExecute(() -> { + if (!player.isAlive()) return; // we don't care if the player died here, that means the chemical burns got them + helper.assertHasCondition(player, GTMedicalConditions.CHEMICAL_BURNS); + }) + .thenSucceed(); + } + + @GameTest(template = "empty", batch = "medical_conditions", timeoutTicks = 450) + public static void testHazardProtectionAnyContact(GameTestHelper helper) { + ServerPlayer player = helper.makeMockSurvivalServerPlayer(); + // equip hazmat suit + player.setItemSlot(EquipmentSlot.HEAD, GTItems.HAZMAT_HELMET.asStack()); + player.setItemSlot(EquipmentSlot.CHEST, GTItems.HAZMAT_CHESTPLATE.asStack()); + player.setItemSlot(EquipmentSlot.LEGS, GTItems.HAZMAT_LEGGINGS.asStack()); + player.setItemSlot(EquipmentSlot.FEET, GTItems.HAZMAT_BOOTS.asStack()); + // give 16x Cadmium dust + player.addItem(ChemicalHelper.get(TagPrefix.dust, GTMaterials.Cadmium, 16)); + + helper.startSequence() + // tick the medical condition tracker for 10 seconds + .thenExecuteFor(10 * 20, player::doTick) + // check if player did NOT get poisoned + .thenExecute(() -> helper.assertFreeOfCondition(player, GTMedicalConditions.POISON)) + // remove hazmat suit + .thenExecute(() -> { + player.setItemSlot(EquipmentSlot.HEAD, ItemStack.EMPTY); + player.setItemSlot(EquipmentSlot.CHEST, ItemStack.EMPTY); + player.setItemSlot(EquipmentSlot.LEGS, ItemStack.EMPTY); + player.setItemSlot(EquipmentSlot.FEET, ItemStack.EMPTY); + }) + // tick the medical condition tracker for 10 seconds + .thenExecuteFor(10 * 20, player::doTick) + // check if player DID get poisoned this time + .thenExecute(() -> { + if (!player.isAlive()) return; // we don't care if the player died here, that means the poisoning got them + helper.assertHasCondition(player, GTMedicalConditions.POISON); + }) + .thenSucceed(); + } + + // TODO add test for consumption hazard if that ever gets used for anything + + @GameTest(template = "empty", batch = "medical_conditions", timeoutTicks = 350) + public static void testGeneralAntidoteWorksOnWeakPoison(GameTestHelper helper) { + ServerPlayer player = helper.makeMockSurvivalServerPlayer(); + // give the player Regeneration 7 so they don't die + player.addEffect(new MobEffectInstance(MobEffects.REGENERATION, 350, 6)); + // add a low-ish count of weak poisoning + helper.addMedicalConditionCounts(player, GTMedicalConditions.WEAK_POISON, 100); + // give Player 16x Paracetamol + ItemStack pillStack = GTItems.PARACETAMOL_PILL.asStack(16); + player.setItemInHand(InteractionHand.MAIN_HAND, pillStack); + + final long startTick = helper.getTick(); + + helper.startSequence() + // tick the medical condition tracker for 2 seconds + .thenExecuteFor(2 * 20, player::doTick) + // check that count hasn't changed + .thenExecute(() -> helper.assertConditionCountEquals(player, GTMedicalConditions.WEAK_POISON, 100)) + // make player eat Paracetamol for 16 * 16 = 256 ticks + // (+2 for safety) + .thenExecuteFor(16 * 16 + 2, () -> { + player.doTick(); + // constantly eat another item + var result = helper.useItem(player, + player.getItemInHand(InteractionHand.MAIN_HAND)); + if (result.getResult().consumesAction()) { + player.setItemInHand(InteractionHand.MAIN_HAND, result.getObject()); + } + }) + .thenExecute(() -> { + // check if they were all consumed + helper.assertHeldItemCountIs(player, Items.AIR, 0, InteractionHand.MAIN_HAND); + // check that the poisoning is gone + helper.assertFreeOfCondition(player, GTMedicalConditions.WEAK_POISON); + }) + .thenSucceed(); + } + + @GameTest(template = "empty", batch = "medical_conditions", timeoutTicks = 350) + public static void testGeneralAntidoteDoesntWorkOnCancer(GameTestHelper helper) { + ServerPlayer player = helper.makeMockSurvivalServerPlayer(); + // give the player Regeneration 7 so they don't die + player.addEffect(new MobEffectInstance(MobEffects.REGENERATION, 350, 6)); + // add a low-ish count of weak poisoning + helper.addMedicalConditionCounts(player, GTMedicalConditions.CARCINOGEN, 100); + // give Player 16x Paracetamol + ItemStack pillStack = GTItems.PARACETAMOL_PILL.asStack(16); + player.setItemInHand(InteractionHand.MAIN_HAND, pillStack); + + final long startTick = helper.getTick(); + + helper.startSequence() + // tick the medical condition tracker for 2 seconds + .thenExecuteFor(2 * 20, player::doTick) + // check that count hasn't changed + .thenExecute(() -> helper.assertConditionCountEquals(player, GTMedicalConditions.CARCINOGEN, 100)) + // make player eat Paracetamol for 16 * 16 = 256 ticks + // (+2 for safety) + .thenExecuteFor(16 * 16 + 2, () -> { + player.doTick(); + // constantly eat another item + var result = helper.useItem(player, + player.getItemInHand(InteractionHand.MAIN_HAND)); + if (result.getResult().consumesAction()) { + player.setItemInHand(InteractionHand.MAIN_HAND, result.getObject()); + } + }) + .thenExecute(() -> { + // check if they were all consumed + helper.assertHeldItemCountIs(player, Items.AIR, 0, InteractionHand.MAIN_HAND); + // check that count is STILL 100, as Paracetamol shouldn't be able to remove cancer. + helper.assertConditionCountEquals(player, GTMedicalConditions.CARCINOGEN, 100); + }) + .thenSucceed(); + } + + @GameTest(template = "empty", batch = "medical_conditions", timeoutTicks = 350) + public static void testRadAwayWorksOnCancer(GameTestHelper helper) { + ServerPlayer player = helper.makeMockSurvivalServerPlayer(); + // give the player Regeneration 7 so they don't + player.addEffect(new MobEffectInstance(MobEffects.REGENERATION, 350, 6)); + // add a low count of cancer + helper.addMedicalConditionCounts(player, GTMedicalConditions.CARCINOGEN, 100); + // give Player 16x RadAway + ItemStack pillStack = GTItems.RAD_AWAY_PILL.asStack(16); + player.setItemInHand(InteractionHand.MAIN_HAND, pillStack); + + final long startTick = helper.getTick(); + + helper.startSequence() + // tick the medical condition tracker for 2 seconds + .thenExecuteFor(2 * 20, player::doTick) + // check that count hasn't changed + .thenExecute(() -> helper.assertConditionCountEquals(player, GTMedicalConditions.CARCINOGEN, 100)) + // make player eat RadAway for 16 * 16 = 256 ticks + // (+2 for safety) + .thenExecuteFor(16 * 16 + 2, () -> { + player.doTick(); + // constantly eat another item + var result = helper.useItem(player, + player.getItemInHand(InteractionHand.MAIN_HAND)); + if (result.getResult().consumesAction()) { + player.setItemInHand(InteractionHand.MAIN_HAND, result.getObject()); + } + }) + .thenExecute(() -> { + // check if they were all consumed + helper.assertHeldItemCountIs(player, Items.AIR, 0, InteractionHand.MAIN_HAND); + // check that the cancer is gone + helper.assertFreeOfCondition(player, GTMedicalConditions.CARCINOGEN); + }) + .thenSucceed(); + } + + @GameTest(template = "empty", batch = "medical_conditions", timeoutTicks = 350) + public static void testRadAwayDoesntWorkOnWeakPoison(GameTestHelper helper) { + ServerPlayer player = helper.makeMockSurvivalServerPlayer(); + // give the player Regeneration 7 so they don't + player.addEffect(new MobEffectInstance(MobEffects.REGENERATION, 350, 6)); + // add a low-ish count of weak poisoning + helper.addMedicalConditionCounts(player, GTMedicalConditions.WEAK_POISON, 100); + // give Player 16x RadAway + ItemStack pillStack = GTItems.RAD_AWAY_PILL.asStack(16); + player.setItemInHand(InteractionHand.MAIN_HAND, pillStack); + + final long startTick = helper.getTick(); + + helper.startSequence() + // tick the medical condition tracker for 2 seconds + .thenExecuteFor(2 * 20, player::doTick) + // check that count hasn't changed + .thenExecute(() -> helper.assertConditionCountEquals(player, GTMedicalConditions.WEAK_POISON, 100)) + // make player eat RadAway for 16 * 16 = 256 ticks + // (+2 for safety) + .thenExecuteFor(16 * 16 + 2, () -> { + player.doTick(); + // constantly eat another item + var result = helper.useItem(player, + player.getItemInHand(InteractionHand.MAIN_HAND)); + if (result.getResult().consumesAction()) { + player.setItemInHand(InteractionHand.MAIN_HAND, result.getObject()); + } + }) + .thenExecute(() -> { + // check if they were all consumed + helper.assertHeldItemCountIs(player, Items.AIR, 0, InteractionHand.MAIN_HAND); + // check that count is STILL 100, as RadAway shouldn't be able to remove weak poisoning. + helper.assertConditionCountEquals(player, GTMedicalConditions.WEAK_POISON, 100); + }) + .thenSucceed(); + } + + // spotless:on +} diff --git a/src/test/java/com/gregtechceu/gtceu/common/capability/MedicalConditionTestHelpers.java b/src/test/java/com/gregtechceu/gtceu/common/capability/MedicalConditionTestHelpers.java new file mode 100644 index 00000000000..35ac98256c3 --- /dev/null +++ b/src/test/java/com/gregtechceu/gtceu/common/capability/MedicalConditionTestHelpers.java @@ -0,0 +1,64 @@ +package com.gregtechceu.gtceu.common.capability; + +import com.gregtechceu.gtceu.api.capability.GTCapabilityHelper; +import com.gregtechceu.gtceu.api.data.medicalcondition.MedicalCondition; +import com.gregtechceu.gtceu.gametest.util.TestUtils; + +import net.minecraft.gametest.framework.GameTestHelper; +import net.minecraft.util.Mth; +import net.minecraft.world.entity.ai.attributes.Attribute; +import net.minecraft.world.entity.player.Player; + +import lombok.experimental.ExtensionMethod; + +import java.util.UUID; + +@ExtensionMethod(TestUtils.class) +public class MedicalConditionTestHelpers { + + public static void addMedicalConditionCounts(GameTestHelper helper, Player player, + MedicalCondition condition, float counts) { + getMedicalConditionTracker(helper, player).progressCondition(condition, counts); + } + + public static void setMedicalConditionCounts(GameTestHelper helper, Player player, + MedicalCondition condition, float counts) { + MedicalConditionTracker tracker = getMedicalConditionTracker(helper, player); + tracker.medicalConditions.put(condition, counts); + tracker.updateActiveSymptoms(); + } + + public static void clearMedicalCondition(GameTestHelper helper, Player player, MedicalCondition condition) { + getMedicalConditionTracker(helper, player).removeMedicalCondition(condition); + } + + public static MedicalConditionTracker getMedicalConditionTracker(GameTestHelper helper, Player player) { + helper.assertEntityAlive(player); + MedicalConditionTracker tracker = GTCapabilityHelper.getMedicalConditionTracker(player); + helper.assertTrue(tracker != null, + "Player " + player + " doesn't have a medical condition tracker capability"); + return tracker; + } + + public static void assertHasCondition(GameTestHelper helper, Player player, MedicalCondition condition) { + helper.assertTrue(getMedicalConditionTracker(helper, player).medicalConditions.containsKey(condition), + "Player " + player + " should have medical condition " + condition.id); + } + + public static void assertFreeOfCondition(GameTestHelper helper, Player player, MedicalCondition condition) { + helper.assertFalse(getMedicalConditionTracker(helper, player).medicalConditions.containsKey(condition), + "Player " + player + " should not have medical condition " + condition.id); + } + + public static void assertConditionCountEquals(GameTestHelper helper, Player player, + MedicalCondition condition, float expectedCounts) { + float counts = getMedicalConditionTracker(helper, player).medicalConditions.getFloat(condition); + helper.assertTrue(Mth.equal(counts, expectedCounts), + "Player " + player + " should have " + expectedCounts + " 'counts' of medical condition " + + condition.id + ", has " + counts); + } + + public static double getAndAssertAttributeModifier(Player player, Attribute attribute, UUID modifierId) { + return player.getAttributes().getModifierValue(attribute, modifierId); + } +} diff --git a/src/test/java/com/gregtechceu/gtceu/gametest/util/TestUtils.java b/src/test/java/com/gregtechceu/gtceu/gametest/util/TestUtils.java index 6c2840a8c17..e49368fbfd3 100644 --- a/src/test/java/com/gregtechceu/gtceu/gametest/util/TestUtils.java +++ b/src/test/java/com/gregtechceu/gtceu/gametest/util/TestUtils.java @@ -16,12 +16,20 @@ import com.gregtechceu.gtceu.api.recipe.GTRecipeType; import com.gregtechceu.gtceu.api.registry.GTRegistries; import com.gregtechceu.gtceu.common.item.behavior.CoverPlaceBehavior; +import com.gregtechceu.gtceu.utils.fakeplayer.FakeServerGamePacketListenerImpl; import net.minecraft.core.BlockPos; import net.minecraft.core.Direction; import net.minecraft.gametest.framework.GameTestAssertPosException; import net.minecraft.gametest.framework.GameTestHelper; import net.minecraft.network.chat.MutableComponent; +import net.minecraft.server.MinecraftServer; +import net.minecraft.server.level.ServerPlayer; +import net.minecraft.world.InteractionHand; +import net.minecraft.world.InteractionResultHolder; +import net.minecraft.world.entity.Entity; +import net.minecraft.world.entity.player.Player; +import net.minecraft.world.item.Item; import net.minecraft.world.item.ItemStack; import net.minecraft.world.item.Items; import net.minecraft.world.item.crafting.RecipeType; @@ -29,10 +37,12 @@ import net.minecraft.world.level.block.RedstoneLampBlock; import net.minecraftforge.fluids.FluidStack; +import com.mojang.authlib.GameProfile; import org.jetbrains.annotations.Nullable; import java.util.List; import java.util.Objects; +import java.util.UUID; import static com.gregtechceu.gtceu.common.data.GTRecipeTypes.ELECTRIC; @@ -313,4 +323,45 @@ public static void assertRedstoneEither(GameTestHelper helper, BlockPos pos, int absolutePos, pos, helper.getTick()); } } + + public static ServerPlayer makeMockSurvivalServerPlayer(GameTestHelper helper) { + MinecraftServer server = helper.getLevel().getServer(); + ServerPlayer player = new ServerPlayer(server, helper.getLevel(), + new GameProfile(UUID.randomUUID(), "test-mock-player")) { + + public boolean isSpectator() { + return false; + } + + public boolean isCreative() { + return false; + } + }; + player.connection = new FakeServerGamePacketListenerImpl(server, player); + return player; + } + + public static InteractionResultHolder useItem(GameTestHelper helper, Player player, ItemStack item) { + return useItem(helper, player, item, InteractionHand.MAIN_HAND); + } + + public static InteractionResultHolder useItem(GameTestHelper helper, Player player, ItemStack item, + InteractionHand hand) { + return item.use(helper.getLevel(), player, hand); + } + + public static void assertHeldItemCountIs(GameTestHelper helper, Player player, + @Nullable Item item, int count, InteractionHand hand) { + ItemStack stack = player.getItemInHand(hand); + if (item != null && item != Items.AIR) { + helper.assertTrue(stack.is(item), "Item stack " + stack + " in hand " + hand + " is not a " + item); + } + helper.assertTrue(stack.getCount() == count, + "Item stack " + stack + " in hand " + hand + " should have " + count + " items, has " + + stack.getCount()); + } + + public static void assertEntityAlive(GameTestHelper helper, Entity entity) { + helper.assertTrue(entity.isAlive(), "Entity " + entity + " should be alive"); + } }