diff --git a/src/data/kotlin/ru/dbotthepony/mc/otm/datagen/lang/English.kt b/src/data/kotlin/ru/dbotthepony/mc/otm/datagen/lang/English.kt index 2e8e1c4ec..8efb2f333 100644 --- a/src/data/kotlin/ru/dbotthepony/mc/otm/datagen/lang/English.kt +++ b/src/data/kotlin/ru/dbotthepony/mc/otm/datagen/lang/English.kt @@ -334,6 +334,7 @@ private fun death(provider: MatteryLanguageProvider) { death("otm_event_horizon", "%1\$s never crossed the event horizon") death("otm_hawking_radiation", "%1\$s discovered Hawking radiation") death("otm_emp", "%1\$s electronics' fried") + death("otm_cosmic_rays", "%1\$s electronics' got scrambled by cosmic radiation") death("otm_become_android.player", "%1\$s lost their humanity whilst %2\$s tried to reason with them") death("otm_become_humane.player", "%1\$s gained their humanity whilst %2\$s tried to reason with them") diff --git a/src/data/kotlin/ru/dbotthepony/mc/otm/datagen/lang/Russian.kt b/src/data/kotlin/ru/dbotthepony/mc/otm/datagen/lang/Russian.kt index 451628da2..de15bde54 100644 --- a/src/data/kotlin/ru/dbotthepony/mc/otm/datagen/lang/Russian.kt +++ b/src/data/kotlin/ru/dbotthepony/mc/otm/datagen/lang/Russian.kt @@ -341,6 +341,7 @@ private fun death(provider: MatteryLanguageProvider) { death("otm_event_horizon", "%1\$s никогда не пересёк горизонт событий") death("otm_hawking_radiation", "%1\$s открыл излучение Хокинга") death("otm_emp", "Электроника %1\$s перегорела") + death("otm_cosmic_rays", "Электроника %1\$s была ошеломлена космическим излучением") death("otm_become_android.player", "%1\$s потерял свою человечность, когда %2\$s пытался образумить их") death("otm_become_humane.player", "%1\$s восстановил свою человечность, когда %2\$s пытался образумить их") diff --git a/src/main/java/ru/dbotthepony/mc/otm/OverdriveThatMatters.java b/src/main/java/ru/dbotthepony/mc/otm/OverdriveThatMatters.java index 5915b8e75..748bb0dc1 100644 --- a/src/main/java/ru/dbotthepony/mc/otm/OverdriveThatMatters.java +++ b/src/main/java/ru/dbotthepony/mc/otm/OverdriveThatMatters.java @@ -201,6 +201,7 @@ public final class OverdriveThatMatters { if (AdAstraCompatKt.isAdAstraLoaded()) { EVENT_BUS.addListener(EventPriority.NORMAL, AdAstraCompatKt::onDamageEvent); + EVENT_BUS.addListener(EventPriority.NORMAL, AdAstraCompatKt::onMatteryTick); } } diff --git a/src/main/java/ru/dbotthepony/mc/otm/mixin/compat/ad_astra/EntityTemperatureSystemMixin.java b/src/main/java/ru/dbotthepony/mc/otm/mixin/compat/ad_astra/EntityTemperatureSystemMixin.java index a68cc5728..421069a9c 100644 --- a/src/main/java/ru/dbotthepony/mc/otm/mixin/compat/ad_astra/EntityTemperatureSystemMixin.java +++ b/src/main/java/ru/dbotthepony/mc/otm/mixin/compat/ad_astra/EntityTemperatureSystemMixin.java @@ -1,8 +1,7 @@ package ru.dbotthepony.mc.otm.mixin.compat.ad_astra; -import earth.terrarium.ad_astra.common.data.Planet; -import earth.terrarium.ad_astra.common.data.PlanetData; import earth.terrarium.ad_astra.common.entity.system.EntityTemperatureSystem; +import earth.terrarium.ad_astra.common.util.ModUtils; import net.minecraft.server.level.ServerLevel; import net.minecraft.world.entity.LivingEntity; import org.spongepowered.asm.mixin.Mixin; @@ -21,7 +20,7 @@ public class EntityTemperatureSystemMixin { remap = false ) private static void temperatureTick(LivingEntity entity, ServerLevel level, CallbackInfo hook) { - if (ServerCompatConfig.AdAstra.INSTANCE.getWHATS_UP_WITH_TEMPERATURE() && !PlanetData.getPlanetFromLevel(level.dimension()).map(Planet::hasAtmosphere).orElse(true)) { + if (ServerCompatConfig.AdAstra.INSTANCE.getWHATS_UP_WITH_TEMPERATURE() && !ModUtils.planetHasAtmosphere(level)) { hook.cancel(); } } diff --git a/src/main/kotlin/ru/dbotthepony/mc/otm/capability/MatteryPlayerCapability.kt b/src/main/kotlin/ru/dbotthepony/mc/otm/capability/MatteryPlayerCapability.kt index 0cfa76cc1..448ca8554 100644 --- a/src/main/kotlin/ru/dbotthepony/mc/otm/capability/MatteryPlayerCapability.kt +++ b/src/main/kotlin/ru/dbotthepony/mc/otm/capability/MatteryPlayerCapability.kt @@ -21,8 +21,10 @@ import net.minecraft.world.entity.player.Player import net.minecraft.world.item.ItemStack import net.minecraft.world.item.ProjectileWeaponItem import net.minecraft.world.item.enchantment.EnchantmentHelper.hasVanishingCurse +import net.minecraft.world.level.Level import net.minecraft.world.phys.Vec3 import net.minecraftforge.common.ForgeHooks +import net.minecraftforge.common.MinecraftForge import net.minecraftforge.common.capabilities.Capability import net.minecraftforge.common.capabilities.ICapabilityProvider import net.minecraftforge.common.util.INBTSerializable @@ -80,6 +82,32 @@ import kotlin.collections.HashMap @Suppress("unused") class MatteryPlayerCapability(val ply: Player) : ICapabilityProvider, INBTSerializable { + /** + * This event is fired on main event bus before ticking logic takes place. + * + * Cancelling it is probably not a good idea, but you can do it anyway. + */ + data class PreTick(val capability: MatteryPlayerCapability) : Event() { + override fun isCancelable() = true + override fun hasResult() = false + override fun setResult(value: Result) {} + + val player get() = capability.ply + val level: Level get() = capability.ply.level + } + + /** + * This event is fired on main event bus after ticking logic took place. + */ + data class PostTick(val capability: MatteryPlayerCapability) : Event() { + override fun isCancelable() = false + override fun hasResult() = false + override fun setResult(value: Result) {} + + val player get() = capability.ply + val level: Level get() = capability.ply.level + } + private inner class PlayerMatteryContainer(size: Int) : MatteryContainer(size) { override fun setChanged(slot: Int, new: ItemStack, old: ItemStack) { super.setChanged(slot, new, old) @@ -777,6 +805,11 @@ class MatteryPlayerCapability(val ply: Player) : ICapabilityProvider, INBTSerial private fun tick() { if (!ply.isAlive) return + PreTick(this).also { + MinecraftForge.EVENT_BUS.post(it) + if (it.isCanceled) return + } + ticksIExist++ if (willBecomeAndroid) { @@ -930,6 +963,10 @@ class MatteryPlayerCapability(val ply: Player) : ICapabilityProvider, INBTSerial } tickInventory() + + PostTick(this).also { + MinecraftForge.EVENT_BUS.post(it) + } } private val resolver = LazyOptional.of { this } diff --git a/src/main/kotlin/ru/dbotthepony/mc/otm/compat/adastra/AdAstraCompat.kt b/src/main/kotlin/ru/dbotthepony/mc/otm/compat/adastra/AdAstraCompat.kt index 61d89098b..c9f5af444 100644 --- a/src/main/kotlin/ru/dbotthepony/mc/otm/compat/adastra/AdAstraCompat.kt +++ b/src/main/kotlin/ru/dbotthepony/mc/otm/compat/adastra/AdAstraCompat.kt @@ -1,12 +1,18 @@ package ru.dbotthepony.mc.otm.compat.adastra import earth.terrarium.ad_astra.AdAstra +import earth.terrarium.ad_astra.common.data.PlanetData +import earth.terrarium.ad_astra.common.item.armor.SpaceSuit import earth.terrarium.ad_astra.common.registry.ModDamageSource +import earth.terrarium.ad_astra.common.util.ModUtils import net.minecraft.world.entity.player.Player import net.minecraftforge.event.entity.living.LivingHurtEvent import net.minecraftforge.fml.ModList +import ru.dbotthepony.mc.otm.capability.MatteryPlayerCapability import ru.dbotthepony.mc.otm.capability.matteryPlayer import ru.dbotthepony.mc.otm.config.ServerCompatConfig +import ru.dbotthepony.mc.otm.registry.MItems +import ru.dbotthepony.mc.otm.registry.MRegistry val isAdAstraLoaded by lazy { ModList.get().isLoaded(AdAstra.MOD_ID) @@ -26,3 +32,23 @@ fun onDamageEvent(event: LivingHurtEvent) { } } } + +fun onMatteryTick(event: MatteryPlayerCapability.PostTick) { + check(isAdAstraLoaded) { "Ad Astra is not loaded!" } + + if ( + ServerCompatConfig.AdAstra.ANDROID_COSMIC_RAYS && + !event.player.abilities.invulnerable && + event.capability.isAndroid && + !ModUtils.planetHasAtmosphere(event.level) + ) { + val rand = event.level.random + + val noSpacesuits = event.player.armorSlots.count { it.item !is SpaceSuit } + val yesTritanium = if (!ServerCompatConfig.AdAstra.TRITANIUM_ARMOR_PROTECTS_AGAINST_COSMIC_RAYS) 0.0 else event.player.armorSlots.count { it.item in MItems.TRITANIUM_ARMOR } * 0.5 + + if (rand.nextDouble() <= (noSpacesuits - yesTritanium) * ServerCompatConfig.AdAstra.ANDROID_COSMIC_RAYS_CHANCE) { + event.player.hurt(MRegistry.DAMAGE_COSMIC_RAYS, 1f) + } + } +} diff --git a/src/main/kotlin/ru/dbotthepony/mc/otm/config/ServerCompatConfig.kt b/src/main/kotlin/ru/dbotthepony/mc/otm/config/ServerCompatConfig.kt index 1b1150dc4..ab60743e0 100644 --- a/src/main/kotlin/ru/dbotthepony/mc/otm/config/ServerCompatConfig.kt +++ b/src/main/kotlin/ru/dbotthepony/mc/otm/config/ServerCompatConfig.kt @@ -15,6 +15,20 @@ object ServerCompatConfig : AbstractConfig("compat-server") { .comment("I attended physics classes in middle school, and this kills me.") .define("WHATS_UP_WITH_TEMPERATURE", true) + val ANDROID_COSMIC_RAYS: Boolean by builder + .comment("Androids without spacesuit will get damaged over time by cosmic radiation") + .comment("on planets without atmosphere.") + .define("ANDROID_COSMIC_RAYS", true) + + val ANDROID_COSMIC_RAYS_CHANCE: Double by builder + .comment("Chance in percent android will be damaged this tick per missing piece of spacesuit") + .comment("Max chance in tick of damage is this value multiplied by 4 (spacesuit is completely missing)") + .defineInRange("ANDROID_COSMIC_RAYS_CHANCE", 0.015, 0.0, 1.0) + + val TRITANIUM_ARMOR_PROTECTS_AGAINST_COSMIC_RAYS: Boolean by builder + .comment("Should androids get half protection from cosmic rays per piece of tritanium armor") + .define("TRITANIUM_ARMOR_PROTECTS_AGAINST_COSMIC_RAYS", true) + init { builder.pop() } diff --git a/src/main/kotlin/ru/dbotthepony/mc/otm/registry/DamageSources.kt b/src/main/kotlin/ru/dbotthepony/mc/otm/registry/DamageSources.kt index 5d6580085..64b91e687 100644 --- a/src/main/kotlin/ru/dbotthepony/mc/otm/registry/DamageSources.kt +++ b/src/main/kotlin/ru/dbotthepony/mc/otm/registry/DamageSources.kt @@ -138,7 +138,7 @@ class ImmutableDamageSource(private val parent: DamageSource) : DamageSource(par } } -abstract class MatteryDamageSource(name: String, private val entity: Entity? = null, private val inflictor: ItemStack? = null) : DamageSource(name) { +abstract class MatteryDamageSource(name: String, private val entity: Entity? = null, val inflictor: ItemStack? = null) : DamageSource(name) { override fun getLocalizedDeathMessage(victim: LivingEntity): Component { val itemStack = inflictor ?: (entity as LivingEntity?)?.mainHandItem ?: ItemStack.EMPTY diff --git a/src/main/kotlin/ru/dbotthepony/mc/otm/registry/MRegistry.kt b/src/main/kotlin/ru/dbotthepony/mc/otm/registry/MRegistry.kt index 82e118108..244a0a876 100644 --- a/src/main/kotlin/ru/dbotthepony/mc/otm/registry/MRegistry.kt +++ b/src/main/kotlin/ru/dbotthepony/mc/otm/registry/MRegistry.kt @@ -192,6 +192,10 @@ object MRegistry { const val DAMAGE_EVENT_HORIZON_ID = "otm_event_horizon" const val DAMAGE_HAWKING_RADIATION_ID = "otm_hawking_radiation" const val DAMAGE_EXOPACK_PROBE_ID = "otm_exopack_probe" + const val DAMAGE_EMP_NAME = "otm_emp" + const val DAMAGE_SHOCKWAVE_NAME = "otm_shockwave" + const val DAMAGE_PLASMA_NAME = "otm_plasma" + const val DAMAGE_COSMIC_RAYS_NAME = "otm_cosmic_rays" val DAMAGE_EXOPACK_PROBE = ImmutableDamageSource(DamageSource(DAMAGE_EXOPACK_PROBE_ID).bypassArmor().bypassMagic()) @@ -199,9 +203,8 @@ object MRegistry { val DAMAGE_BECOME_HUMANE = ImmutableDamageSource(DamageSource(DAMAGE_BECOME_HUMANE_ID).bypassArmor().bypassInvul().bypassMagic()) val DAMAGE_EVENT_HORIZON = ImmutableDamageSource(DamageSource(DAMAGE_EVENT_HORIZON_ID).bypassMagic().bypassArmor()) val DAMAGE_HAWKING_RADIATION = ImmutableDamageSource(DamageSource(DAMAGE_HAWKING_RADIATION_ID)) - const val DAMAGE_EMP_NAME = "otm_emp" - const val DAMAGE_SHOCKWAVE_NAME = "otm_shockwave" - const val DAMAGE_PLASMA_NAME = "otm_plasma" + val DAMAGE_COSMIC_RAYS = ImmutableDamageSource(DamageSource(DAMAGE_COSMIC_RAYS_NAME).bypassArmor().bypassMagic()) + val DAMAGE_EMP: DamageSource = ImmutableDamageSource(EMPDamageSource()) val TRITANIUM_STRIPED_BLOCK = StripedColoredDecorativeBlock(MNames.TRITANIUM_STRIPED_BLOCK, { colorA, _ ->