More achievements!
Travel underwater without Air Bags, fixes #209 Kill Elder Guardian without Air Bags, fixes #210 Kill the Wither as Android, fixes #206
This commit is contained in:
parent
9924711f31
commit
5b4c68b201
@ -20,17 +20,20 @@ import ru.dbotthepony.mc.otm.core.TranslatableComponent
|
|||||||
import ru.dbotthepony.mc.otm.datagen.DataGen
|
import ru.dbotthepony.mc.otm.datagen.DataGen
|
||||||
import ru.dbotthepony.mc.otm.datagen.lang.MatteryLanguageProvider
|
import ru.dbotthepony.mc.otm.datagen.lang.MatteryLanguageProvider
|
||||||
import ru.dbotthepony.mc.otm.datagen.modLocation
|
import ru.dbotthepony.mc.otm.datagen.modLocation
|
||||||
|
import ru.dbotthepony.mc.otm.registry.AndroidFeatures
|
||||||
import ru.dbotthepony.mc.otm.registry.MItemTags
|
import ru.dbotthepony.mc.otm.registry.MItemTags
|
||||||
import ru.dbotthepony.mc.otm.registry.MItems
|
import ru.dbotthepony.mc.otm.registry.MItems
|
||||||
import ru.dbotthepony.mc.otm.registry.MNames
|
import ru.dbotthepony.mc.otm.registry.MNames
|
||||||
import ru.dbotthepony.mc.otm.triggers.AndroidBatteryTrigger
|
import ru.dbotthepony.mc.otm.triggers.AndroidBatteryTrigger
|
||||||
import ru.dbotthepony.mc.otm.triggers.AndroidResearchTrigger
|
import ru.dbotthepony.mc.otm.triggers.AndroidResearchTrigger
|
||||||
|
import ru.dbotthepony.mc.otm.triggers.AndroidTravelUnderwater
|
||||||
import ru.dbotthepony.mc.otm.triggers.BecomeAndroidDeathTrigger
|
import ru.dbotthepony.mc.otm.triggers.BecomeAndroidDeathTrigger
|
||||||
import ru.dbotthepony.mc.otm.triggers.BecomeAndroidSleepTrigger
|
import ru.dbotthepony.mc.otm.triggers.BecomeAndroidSleepTrigger
|
||||||
import ru.dbotthepony.mc.otm.triggers.BecomeAndroidTrigger
|
import ru.dbotthepony.mc.otm.triggers.BecomeAndroidTrigger
|
||||||
import ru.dbotthepony.mc.otm.triggers.BecomeHumaneTrigger
|
import ru.dbotthepony.mc.otm.triggers.BecomeHumaneTrigger
|
||||||
import ru.dbotthepony.mc.otm.triggers.EnderTeleporterFallDeathTrigger
|
import ru.dbotthepony.mc.otm.triggers.EnderTeleporterFallDeathTrigger
|
||||||
import ru.dbotthepony.mc.otm.triggers.FallDampenersSaveTrigger
|
import ru.dbotthepony.mc.otm.triggers.FallDampenersSaveTrigger
|
||||||
|
import ru.dbotthepony.mc.otm.triggers.KillAsAndroidTrigger
|
||||||
import ru.dbotthepony.mc.otm.triggers.NanobotsArmorTrigger
|
import ru.dbotthepony.mc.otm.triggers.NanobotsArmorTrigger
|
||||||
import ru.dbotthepony.mc.otm.triggers.PhantomSpawnDeniedTrigger
|
import ru.dbotthepony.mc.otm.triggers.PhantomSpawnDeniedTrigger
|
||||||
import ru.dbotthepony.mc.otm.triggers.ShockwaveDamageMobTrigger
|
import ru.dbotthepony.mc.otm.triggers.ShockwaveDamageMobTrigger
|
||||||
@ -46,8 +49,8 @@ fun addAndroidAdvancements(serializer: Consumer<Advancement>, existingFileHelper
|
|||||||
title = translation.add("root", "Androids and Humans") {
|
title = translation.add("root", "Androids and Humans") {
|
||||||
russian("Андроиды и Люди")
|
russian("Андроиды и Люди")
|
||||||
},
|
},
|
||||||
description = translation.add("root.desc", "Can you make out who is cruel machine and who care about others?") {
|
description = translation.add("root.desc", "Can you make out who is cruel machine and who shows empathy?") {
|
||||||
russian("Сможете ли вы отличить бездушную машину от того, кому другие не безразличны?")
|
russian("Сможете ли вы отличить бездушную машину от того, кто показывает сочувствие?")
|
||||||
},
|
},
|
||||||
showToast = false,
|
showToast = false,
|
||||||
announceChat = false,
|
announceChat = false,
|
||||||
@ -381,4 +384,73 @@ fun addAndroidAdvancements(serializer: Consumer<Advancement>, existingFileHelper
|
|||||||
)
|
)
|
||||||
.addCriterion("shockwave_warden", ShockwaveDamageMobTrigger.Instance(EntityPredicate.Builder.entity().of(EntityType.WARDEN).build().wrap()))
|
.addCriterion("shockwave_warden", ShockwaveDamageMobTrigger.Instance(EntityPredicate.Builder.entity().of(EntityType.WARDEN).build().wrap()))
|
||||||
.save(serializer, modLocation("android/shockwave_warden"), existingFileHelper)
|
.save(serializer, modLocation("android/shockwave_warden"), existingFileHelper)
|
||||||
|
|
||||||
|
AdvancementBuilder()
|
||||||
|
.parent(root)
|
||||||
|
.display(
|
||||||
|
itemStack = ItemStack(Items.WITHER_SKELETON_SKULL),
|
||||||
|
title = translation.add("wither", "Not Quite Alive, Not Quite Undead") {
|
||||||
|
russian("Ни Живой, Ни Мёртвый")
|
||||||
|
},
|
||||||
|
description = translation.add("wither.desc", "Defeat The Wither as Android. The Wither was surely confused over kind of thing you are") {
|
||||||
|
russian("Победите Иссушителя будучи Андроидом. Наверняка Иссушитель был ошеломлён таким раскладом дел")
|
||||||
|
},
|
||||||
|
frameType = FrameType.GOAL,
|
||||||
|
hidden = true
|
||||||
|
)
|
||||||
|
.addCriterion("kill_wither", KillAsAndroidTrigger.Instance(
|
||||||
|
predicate = EntityPredicate.Builder.entity().of(EntityType.WITHER).build().wrap(),
|
||||||
|
))
|
||||||
|
.save(serializer, modLocation("android/wither"), existingFileHelper)
|
||||||
|
|
||||||
|
val underwater = AdvancementBuilder()
|
||||||
|
.parent(root)
|
||||||
|
.display(
|
||||||
|
itemStack = ItemStack(Items.TURTLE_SPAWN_EGG),
|
||||||
|
title = translation.add("travel_underwater", "Underwater Walk") {
|
||||||
|
russian("Подводная Прогулка")
|
||||||
|
},
|
||||||
|
description = translation.add("travel_underwater.desc", "Travel at least 200 meters underwater as Android without Air Bags research. This reminds us of someone...") {
|
||||||
|
russian("Преодолейте как минимум 200 метров под водой будучи Андроидом без исследования Воздушных Мешков. Кого-то это нам напоминает...")
|
||||||
|
},
|
||||||
|
frameType = FrameType.GOAL,
|
||||||
|
hidden = true
|
||||||
|
)
|
||||||
|
.addCriterion("travel", AndroidTravelUnderwater.Instance(200.0))
|
||||||
|
.save(serializer, modLocation("android/underwater"), existingFileHelper)
|
||||||
|
|
||||||
|
AdvancementBuilder()
|
||||||
|
.parent(underwater)
|
||||||
|
.display(
|
||||||
|
itemStack = ItemStack(Items.TURTLE_SPAWN_EGG),
|
||||||
|
title = translation.add("travel_underwater2", "Underwater Travel") {
|
||||||
|
russian("Подводная Прогулка")
|
||||||
|
},
|
||||||
|
description = translation.add("travel_underwater2.desc", "Travel at least 1046 meters underwater as Android without Air Bags research, like someone else did so") {
|
||||||
|
russian("Преодолейте как минимум 1046 метров под водой будучи Андроидом без исследования Воздушных Мешков, прям как тот, кто так однажды так и сделал")
|
||||||
|
},
|
||||||
|
frameType = FrameType.CHALLENGE,
|
||||||
|
hidden = true
|
||||||
|
)
|
||||||
|
.addCriterion("travel", AndroidTravelUnderwater.Instance(1046.0))
|
||||||
|
.save(serializer, modLocation("android/underwater2"), existingFileHelper)
|
||||||
|
|
||||||
|
AdvancementBuilder()
|
||||||
|
.parent(root)
|
||||||
|
.display(
|
||||||
|
itemStack = ItemStack(Items.PRISMARINE_CRYSTALS),
|
||||||
|
title = translation.add("elder_guardian", "Drowned, but Still Determined") {
|
||||||
|
russian("Затонувший, но Всё Ещё Целеустремлённый")
|
||||||
|
},
|
||||||
|
description = translation.add("elder_guardian.desc", "Slay Elder Guardian as Android without Air Bags researched") {
|
||||||
|
russian("Победите Древнего Стража будучи Андроидом без исследования Воздушных Мешков")
|
||||||
|
},
|
||||||
|
frameType = FrameType.CHALLENGE,
|
||||||
|
hidden = true
|
||||||
|
)
|
||||||
|
.addCriterion("kill_elder_guardian", KillAsAndroidTrigger.Instance(
|
||||||
|
predicate = EntityPredicate.Builder.entity().of(EntityType.ELDER_GUARDIAN).build().wrap(),
|
||||||
|
featurePredicate = KillAsAndroidTrigger.Not(KillAsAndroidTrigger.Has(AndroidFeatures.AIR_BAGS.registryName!!))
|
||||||
|
))
|
||||||
|
.save(serializer, modLocation("android/elder_guardian"), existingFileHelper)
|
||||||
}
|
}
|
||||||
|
@ -50,6 +50,7 @@ import ru.dbotthepony.mc.otm.matter.MatterManager;
|
|||||||
import ru.dbotthepony.mc.otm.network.*;
|
import ru.dbotthepony.mc.otm.network.*;
|
||||||
import ru.dbotthepony.mc.otm.registry.*;
|
import ru.dbotthepony.mc.otm.registry.*;
|
||||||
import ru.dbotthepony.mc.otm.storage.*;
|
import ru.dbotthepony.mc.otm.storage.*;
|
||||||
|
import ru.dbotthepony.mc.otm.triggers.KillAsAndroidTrigger;
|
||||||
|
|
||||||
import static net.minecraftforge.common.MinecraftForge.EVENT_BUS;
|
import static net.minecraftforge.common.MinecraftForge.EVENT_BUS;
|
||||||
|
|
||||||
@ -177,6 +178,8 @@ public final class OverdriveThatMatters {
|
|||||||
EVENT_BUS.addListener(EventPriority.NORMAL, MatteryBlockEntity.Companion::playerDisconnected);
|
EVENT_BUS.addListener(EventPriority.NORMAL, MatteryBlockEntity.Companion::playerDisconnected);
|
||||||
EVENT_BUS.addListener(EventPriority.LOWEST, MatteryBlockEntity.Companion::postLevelTick);
|
EVENT_BUS.addListener(EventPriority.LOWEST, MatteryBlockEntity.Companion::postLevelTick);
|
||||||
|
|
||||||
|
EVENT_BUS.addListener(EventPriority.LOWEST, KillAsAndroidTrigger.INSTANCE::onKill);
|
||||||
|
|
||||||
EVENT_BUS.addListener(EventPriority.NORMAL, EnderTeleporterFeature.Companion::onEntityDeath);
|
EVENT_BUS.addListener(EventPriority.NORMAL, EnderTeleporterFeature.Companion::onEntityDeath);
|
||||||
EVENT_BUS.addListener(EventPriority.HIGH, ItemTritaniumArmor.Companion::onHurt);
|
EVENT_BUS.addListener(EventPriority.HIGH, ItemTritaniumArmor.Companion::onHurt);
|
||||||
|
|
||||||
|
@ -21,6 +21,7 @@ import net.minecraft.world.entity.player.Player
|
|||||||
import net.minecraft.world.item.ItemStack
|
import net.minecraft.world.item.ItemStack
|
||||||
import net.minecraft.world.item.ProjectileWeaponItem
|
import net.minecraft.world.item.ProjectileWeaponItem
|
||||||
import net.minecraft.world.item.enchantment.EnchantmentHelper.hasVanishingCurse
|
import net.minecraft.world.item.enchantment.EnchantmentHelper.hasVanishingCurse
|
||||||
|
import net.minecraft.world.phys.Vec3
|
||||||
import net.minecraftforge.common.ForgeHooks
|
import net.minecraftforge.common.ForgeHooks
|
||||||
import net.minecraftforge.common.capabilities.Capability
|
import net.minecraftforge.common.capabilities.Capability
|
||||||
import net.minecraftforge.common.capabilities.ICapabilityProvider
|
import net.minecraftforge.common.capabilities.ICapabilityProvider
|
||||||
@ -53,16 +54,19 @@ import ru.dbotthepony.mc.otm.core.*
|
|||||||
import ru.dbotthepony.mc.otm.core.collect.UUIDIntModifiersMap
|
import ru.dbotthepony.mc.otm.core.collect.UUIDIntModifiersMap
|
||||||
import ru.dbotthepony.mc.otm.core.collect.nonEmpty
|
import ru.dbotthepony.mc.otm.core.collect.nonEmpty
|
||||||
import ru.dbotthepony.mc.otm.core.math.Decimal
|
import ru.dbotthepony.mc.otm.core.math.Decimal
|
||||||
|
import ru.dbotthepony.mc.otm.core.math.minus
|
||||||
import ru.dbotthepony.mc.otm.core.nbt.getCompoundList
|
import ru.dbotthepony.mc.otm.core.nbt.getCompoundList
|
||||||
import ru.dbotthepony.mc.otm.core.nbt.map
|
import ru.dbotthepony.mc.otm.core.nbt.map
|
||||||
import ru.dbotthepony.mc.otm.core.nbt.set
|
import ru.dbotthepony.mc.otm.core.nbt.set
|
||||||
import ru.dbotthepony.mc.otm.core.util.IntValueCodec
|
import ru.dbotthepony.mc.otm.core.util.IntValueCodec
|
||||||
|
import ru.dbotthepony.mc.otm.core.util.Savetables
|
||||||
import ru.dbotthepony.mc.otm.core.util.UUIDValueCodec
|
import ru.dbotthepony.mc.otm.core.util.UUIDValueCodec
|
||||||
import ru.dbotthepony.mc.otm.menu.ExoPackInventoryMenu
|
import ru.dbotthepony.mc.otm.menu.ExoPackInventoryMenu
|
||||||
import ru.dbotthepony.mc.otm.network.*
|
import ru.dbotthepony.mc.otm.network.*
|
||||||
import ru.dbotthepony.mc.otm.registry.AndroidFeatures
|
import ru.dbotthepony.mc.otm.registry.AndroidFeatures
|
||||||
import ru.dbotthepony.mc.otm.registry.MRegistry
|
import ru.dbotthepony.mc.otm.registry.MRegistry
|
||||||
import ru.dbotthepony.mc.otm.triggers.AndroidResearchTrigger
|
import ru.dbotthepony.mc.otm.triggers.AndroidResearchTrigger
|
||||||
|
import ru.dbotthepony.mc.otm.triggers.AndroidTravelUnderwater
|
||||||
import ru.dbotthepony.mc.otm.triggers.BecomeAndroidDeathTrigger
|
import ru.dbotthepony.mc.otm.triggers.BecomeAndroidDeathTrigger
|
||||||
import ru.dbotthepony.mc.otm.triggers.BecomeAndroidSleepTrigger
|
import ru.dbotthepony.mc.otm.triggers.BecomeAndroidSleepTrigger
|
||||||
import ru.dbotthepony.mc.otm.triggers.BecomeAndroidTrigger
|
import ru.dbotthepony.mc.otm.triggers.BecomeAndroidTrigger
|
||||||
@ -98,6 +102,11 @@ class MatteryPlayerCapability(val ply: Player) : ICapabilityProvider, INBTSerial
|
|||||||
*/
|
*/
|
||||||
val synchronizer = FieldSynchronizer()
|
val synchronizer = FieldSynchronizer()
|
||||||
|
|
||||||
|
/**
|
||||||
|
* For data to be stored and loaded from NBT automatically
|
||||||
|
*/
|
||||||
|
val savetables = Savetables()
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* For fields that need to be synchronized to everyone
|
* For fields that need to be synchronized to everyone
|
||||||
*
|
*
|
||||||
@ -251,6 +260,19 @@ class MatteryPlayerCapability(val ply: Player) : ICapabilityProvider, INBTSerial
|
|||||||
var ticksIExist = 0
|
var ticksIExist = 0
|
||||||
private set
|
private set
|
||||||
|
|
||||||
|
private var lastOutsideLiquid = Vec3(0.0, 0.0, 0.0)
|
||||||
|
private var wasInLiquid = false
|
||||||
|
private var lastDimension = ResourceLocation("overworld")
|
||||||
|
|
||||||
|
init {
|
||||||
|
savetables.int(::ticksIExist)
|
||||||
|
savetables.int(::iteration)
|
||||||
|
savetables.bool(::shouldSendIteration)
|
||||||
|
savetables.bool(::wasInLiquid)
|
||||||
|
savetables.vector(::lastOutsideLiquid)
|
||||||
|
savetables.location(::lastDimension)
|
||||||
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Whenever player should become an Android once transformation conditions are met (e.g. player dies or sleeps in bed)
|
* Whenever player should become an Android once transformation conditions are met (e.g. player dies or sleeps in bed)
|
||||||
*/
|
*/
|
||||||
@ -326,6 +348,9 @@ class MatteryPlayerCapability(val ply: Player) : ICapabilityProvider, INBTSerial
|
|||||||
androidEnergy.batteryLevel = AndroidConfig.ANDROID_MAX_ENERGY
|
androidEnergy.batteryLevel = AndroidConfig.ANDROID_MAX_ENERGY
|
||||||
androidEnergy.maxBatteryLevel = AndroidConfig.ANDROID_MAX_ENERGY
|
androidEnergy.maxBatteryLevel = AndroidConfig.ANDROID_MAX_ENERGY
|
||||||
|
|
||||||
|
lastOutsideLiquid = ply.position()
|
||||||
|
wasInLiquid = false
|
||||||
|
|
||||||
if (ply is ServerPlayer) {
|
if (ply is ServerPlayer) {
|
||||||
BecomeAndroidTrigger.trigger(ply)
|
BecomeAndroidTrigger.trigger(ply)
|
||||||
}
|
}
|
||||||
@ -374,6 +399,9 @@ class MatteryPlayerCapability(val ply: Player) : ICapabilityProvider, INBTSerial
|
|||||||
androidEnergy.maxBatteryLevel = AndroidConfig.ANDROID_MAX_ENERGY
|
androidEnergy.maxBatteryLevel = AndroidConfig.ANDROID_MAX_ENERGY
|
||||||
dropBattery()
|
dropBattery()
|
||||||
|
|
||||||
|
lastOutsideLiquid = ply.position()
|
||||||
|
wasInLiquid = false
|
||||||
|
|
||||||
if (ply is ServerPlayer) {
|
if (ply is ServerPlayer) {
|
||||||
BecomeHumaneTrigger.trigger(ply)
|
BecomeHumaneTrigger.trigger(ply)
|
||||||
}
|
}
|
||||||
@ -574,14 +602,9 @@ class MatteryPlayerCapability(val ply: Player) : ICapabilityProvider, INBTSerial
|
|||||||
}
|
}
|
||||||
|
|
||||||
override fun serializeNBT(): CompoundTag {
|
override fun serializeNBT(): CompoundTag {
|
||||||
val tag = CompoundTag()
|
val tag = savetables.serializeNBT()
|
||||||
|
|
||||||
tag["ticksIExist"] = ticksIExist
|
|
||||||
|
|
||||||
// iteration
|
// iteration
|
||||||
tag["iteration"] = iteration
|
|
||||||
tag["shouldSendIteration"] = shouldSendIteration
|
|
||||||
|
|
||||||
tag["deathLog"] = ListTag().also {
|
tag["deathLog"] = ListTag().also {
|
||||||
for ((ticks, component) in deathLog) {
|
for ((ticks, component) in deathLog) {
|
||||||
it.add(CompoundTag().also {
|
it.add(CompoundTag().also {
|
||||||
@ -626,12 +649,9 @@ class MatteryPlayerCapability(val ply: Player) : ICapabilityProvider, INBTSerial
|
|||||||
}
|
}
|
||||||
|
|
||||||
override fun deserializeNBT(tag: CompoundTag) {
|
override fun deserializeNBT(tag: CompoundTag) {
|
||||||
ticksIExist = tag.getInt("ticksIExist")
|
savetables.deserializeNBT(tag)
|
||||||
|
|
||||||
// iterations
|
// iterations
|
||||||
iteration = tag.getInt("iteration")
|
|
||||||
shouldSendIteration = tag.getBoolean("shouldSendIteration")
|
|
||||||
|
|
||||||
deathLog.clear()
|
deathLog.clear()
|
||||||
|
|
||||||
for (value in tag.getCompoundList("deathLog")) {
|
for (value in tag.getCompoundList("deathLog")) {
|
||||||
@ -773,18 +793,38 @@ class MatteryPlayerCapability(val ply: Player) : ICapabilityProvider, INBTSerial
|
|||||||
}
|
}
|
||||||
|
|
||||||
if (isAndroid) {
|
if (isAndroid) {
|
||||||
if (!ply.isSpectator && ply.airSupply < ply.maxAirSupply)
|
|
||||||
ply.airSupply = ply.maxAirSupply
|
|
||||||
|
|
||||||
// TODO: Maybe passive drain?
|
|
||||||
// extractEnergyInner(BigDecimal.valueOf(new Random().nextDouble()), false);
|
|
||||||
if (!ply.isSpectator && ply.isSwimming && !hasFeature(AndroidFeatures.AIR_BAGS)) {
|
|
||||||
ply.isSwimming = false
|
|
||||||
}
|
|
||||||
|
|
||||||
androidEnergy.tick()
|
androidEnergy.tick()
|
||||||
|
|
||||||
if (!ply.isSpectator) {
|
if (!ply.isSpectator) {
|
||||||
|
if (ply.airSupply < ply.maxAirSupply)
|
||||||
|
ply.airSupply = ply.maxAirSupply
|
||||||
|
|
||||||
|
if (ply.isSwimming && !hasFeature(AndroidFeatures.AIR_BAGS))
|
||||||
|
ply.isSwimming = false
|
||||||
|
|
||||||
|
if (ply is ServerPlayer) {
|
||||||
|
if (ply.level.dimension().location() != lastDimension) {
|
||||||
|
lastDimension = ply.level.dimension().location()
|
||||||
|
wasInLiquid = false
|
||||||
|
lastOutsideLiquid = ply.position
|
||||||
|
}
|
||||||
|
|
||||||
|
if (ply.isUnderWater) {
|
||||||
|
if (!wasInLiquid) {
|
||||||
|
wasInLiquid = true
|
||||||
|
lastOutsideLiquid = ply.position
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
if (wasInLiquid) {
|
||||||
|
wasInLiquid = false
|
||||||
|
val distance = (lastOutsideLiquid - ply.position).length()
|
||||||
|
AndroidTravelUnderwater.trigger(ply, distance)
|
||||||
|
}
|
||||||
|
|
||||||
|
lastOutsideLiquid = ply.position
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
val stats = ply.foodData
|
val stats = ply.foodData
|
||||||
|
|
||||||
while (stats.foodLevel < 18 && androidEnergy.extractEnergy(AndroidConfig.ANDROID_ENERGY_PER_HUNGER_POINT, true) >= AndroidConfig.ANDROID_ENERGY_PER_HUNGER_POINT) {
|
while (stats.foodLevel < 18 && androidEnergy.extractEnergy(AndroidConfig.ANDROID_ENERGY_PER_HUNGER_POINT, true) >= AndroidConfig.ANDROID_ENERGY_PER_HUNGER_POINT) {
|
||||||
|
@ -298,3 +298,11 @@ fun <T : Comparable<T>> BlockState.getValueNullable(prop: Property<T>): T? {
|
|||||||
|
|
||||||
return null
|
return null
|
||||||
}
|
}
|
||||||
|
|
||||||
|
fun <T> Stream<T>.asIterable(): Iterable<T> {
|
||||||
|
return object : Iterable<T> {
|
||||||
|
override fun iterator(): Iterator<T> {
|
||||||
|
return this@asIterable.iterator()
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
@ -34,7 +34,9 @@ import ru.dbotthepony.mc.otm.registry.objects.CrateProperties
|
|||||||
import ru.dbotthepony.mc.otm.registry.objects.DecorativeBlock
|
import ru.dbotthepony.mc.otm.registry.objects.DecorativeBlock
|
||||||
import ru.dbotthepony.mc.otm.registry.objects.StripedColoredDecorativeBlock
|
import ru.dbotthepony.mc.otm.registry.objects.StripedColoredDecorativeBlock
|
||||||
import ru.dbotthepony.mc.otm.triggers.AndroidBatteryTrigger
|
import ru.dbotthepony.mc.otm.triggers.AndroidBatteryTrigger
|
||||||
|
import ru.dbotthepony.mc.otm.triggers.KillAsAndroidTrigger
|
||||||
import ru.dbotthepony.mc.otm.triggers.AndroidResearchTrigger
|
import ru.dbotthepony.mc.otm.triggers.AndroidResearchTrigger
|
||||||
|
import ru.dbotthepony.mc.otm.triggers.AndroidTravelUnderwater
|
||||||
import ru.dbotthepony.mc.otm.triggers.BecomeAndroidDeathTrigger
|
import ru.dbotthepony.mc.otm.triggers.BecomeAndroidDeathTrigger
|
||||||
import ru.dbotthepony.mc.otm.triggers.BecomeAndroidSleepTrigger
|
import ru.dbotthepony.mc.otm.triggers.BecomeAndroidSleepTrigger
|
||||||
import ru.dbotthepony.mc.otm.triggers.BecomeAndroidTrigger
|
import ru.dbotthepony.mc.otm.triggers.BecomeAndroidTrigger
|
||||||
@ -265,6 +267,8 @@ object MRegistry {
|
|||||||
CriteriaTriggers.register(NanobotsArmorTrigger)
|
CriteriaTriggers.register(NanobotsArmorTrigger)
|
||||||
CriteriaTriggers.register(FallDampenersSaveTrigger)
|
CriteriaTriggers.register(FallDampenersSaveTrigger)
|
||||||
CriteriaTriggers.register(EnderTeleporterFallDeathTrigger)
|
CriteriaTriggers.register(EnderTeleporterFallDeathTrigger)
|
||||||
|
CriteriaTriggers.register(KillAsAndroidTrigger)
|
||||||
|
CriteriaTriggers.register(AndroidTravelUnderwater)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -0,0 +1,40 @@
|
|||||||
|
package ru.dbotthepony.mc.otm.triggers
|
||||||
|
|
||||||
|
import com.google.gson.JsonObject
|
||||||
|
import com.google.gson.JsonParseException
|
||||||
|
import com.google.gson.JsonPrimitive
|
||||||
|
import net.minecraft.advancements.critereon.AbstractCriterionTriggerInstance
|
||||||
|
import net.minecraft.advancements.critereon.DeserializationContext
|
||||||
|
import net.minecraft.advancements.critereon.EntityPredicate
|
||||||
|
import net.minecraft.advancements.critereon.SerializationContext
|
||||||
|
import net.minecraft.advancements.critereon.SimpleCriterionTrigger
|
||||||
|
import net.minecraft.resources.ResourceLocation
|
||||||
|
import net.minecraft.server.level.ServerPlayer
|
||||||
|
import ru.dbotthepony.mc.otm.OverdriveThatMatters
|
||||||
|
import ru.dbotthepony.mc.otm.core.set
|
||||||
|
|
||||||
|
object AndroidTravelUnderwater : SimpleCriterionTrigger<AndroidTravelUnderwater.Instance>() {
|
||||||
|
val ID = ResourceLocation(OverdriveThatMatters.MOD_ID, "android_walk_underwater")
|
||||||
|
|
||||||
|
override fun getId(): ResourceLocation {
|
||||||
|
return ID
|
||||||
|
}
|
||||||
|
|
||||||
|
override fun createInstance(pJson: JsonObject, pPlayer: EntityPredicate.Composite, pContext: DeserializationContext): Instance {
|
||||||
|
return Instance((pJson["distance_to_travel"] as? JsonPrimitive)?.asDouble ?: throw JsonParseException("Invalid 'distance_to_travel' value"))
|
||||||
|
}
|
||||||
|
|
||||||
|
fun trigger(player: ServerPlayer, travelled: Double) {
|
||||||
|
trigger(player) {
|
||||||
|
it.distanceToTravel <= travelled
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
class Instance(val distanceToTravel: Double) : AbstractCriterionTriggerInstance(ID, EntityPredicate.Composite.ANY) {
|
||||||
|
override fun serializeToJson(pConditions: SerializationContext): JsonObject {
|
||||||
|
return super.serializeToJson(pConditions).also {
|
||||||
|
it["distance_to_travel"] = JsonPrimitive(distanceToTravel)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
@ -0,0 +1,201 @@
|
|||||||
|
package ru.dbotthepony.mc.otm.triggers
|
||||||
|
|
||||||
|
import com.google.common.collect.ImmutableList
|
||||||
|
import com.google.gson.JsonArray
|
||||||
|
import com.google.gson.JsonObject
|
||||||
|
import com.google.gson.JsonSyntaxException
|
||||||
|
import net.minecraft.advancements.critereon.AbstractCriterionTriggerInstance
|
||||||
|
import net.minecraft.advancements.critereon.DeserializationContext
|
||||||
|
import net.minecraft.advancements.critereon.EntityPredicate
|
||||||
|
import net.minecraft.advancements.critereon.SerializationContext
|
||||||
|
import net.minecraft.advancements.critereon.SimpleCriterionTrigger
|
||||||
|
import net.minecraft.resources.ResourceLocation
|
||||||
|
import net.minecraft.server.level.ServerPlayer
|
||||||
|
import net.minecraft.world.entity.monster.ElderGuardian
|
||||||
|
import net.minecraftforge.event.entity.living.LivingDeathEvent
|
||||||
|
import ru.dbotthepony.mc.otm.OverdriveThatMatters
|
||||||
|
import ru.dbotthepony.mc.otm.capability.MatteryPlayerCapability
|
||||||
|
import ru.dbotthepony.mc.otm.capability.matteryPlayer
|
||||||
|
import ru.dbotthepony.mc.otm.core.asIterable
|
||||||
|
import ru.dbotthepony.mc.otm.core.set
|
||||||
|
import ru.dbotthepony.mc.otm.core.stream
|
||||||
|
import ru.dbotthepony.mc.otm.registry.MRegistry
|
||||||
|
import java.util.function.Predicate
|
||||||
|
|
||||||
|
object KillAsAndroidTrigger : SimpleCriterionTrigger<KillAsAndroidTrigger.Instance>() {
|
||||||
|
val ID = ResourceLocation(OverdriveThatMatters.MOD_ID, "kill_as_android")
|
||||||
|
|
||||||
|
override fun getId(): ResourceLocation {
|
||||||
|
return ID
|
||||||
|
}
|
||||||
|
|
||||||
|
override fun createInstance(pJson: JsonObject, pPlayer: EntityPredicate.Composite, pContext: DeserializationContext): Instance {
|
||||||
|
return Instance(
|
||||||
|
predicate = EntityPredicate.Composite.fromJson(pJson, "predicate", pContext),
|
||||||
|
playerPredicate = pPlayer,
|
||||||
|
featurePredicate = (pJson["feature_predicate"] as? JsonObject)?.let(PredicateType::from) ?: throw JsonSyntaxException("Invalid 'feature_predicate': ${pJson["feature_predicate"]}")
|
||||||
|
)
|
||||||
|
}
|
||||||
|
|
||||||
|
enum class PredicateType(val factory: (JsonObject) -> FeaturePredicate) {
|
||||||
|
ALWAYS({ Always }),
|
||||||
|
HAS(::Has),
|
||||||
|
NOT(::Not),
|
||||||
|
AND(::And),
|
||||||
|
OR(::OrPredicate);
|
||||||
|
|
||||||
|
companion object {
|
||||||
|
fun from(json: JsonObject): FeaturePredicate {
|
||||||
|
return when (val type = json["type"]?.asString?.lowercase()) {
|
||||||
|
null -> throw JsonSyntaxException("Missing feature predicate 'type'")
|
||||||
|
"has" -> HAS.factory(json)
|
||||||
|
"and" -> AND.factory(json)
|
||||||
|
"not" -> NOT.factory(json)
|
||||||
|
"or" -> OR.factory(json)
|
||||||
|
"always" -> ALWAYS.factory(json)
|
||||||
|
else -> throw JsonSyntaxException("Unknown feature predicate $type")
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
abstract class FeaturePredicate : Predicate<MatteryPlayerCapability> {
|
||||||
|
abstract val type: PredicateType
|
||||||
|
|
||||||
|
open fun toJson(): JsonObject {
|
||||||
|
return JsonObject().also {
|
||||||
|
it["type"] = type.name.lowercase()
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
object Always : FeaturePredicate() {
|
||||||
|
override val type: PredicateType
|
||||||
|
get() = PredicateType.ALWAYS
|
||||||
|
|
||||||
|
override fun test(t: MatteryPlayerCapability): Boolean {
|
||||||
|
return true
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
class Has : FeaturePredicate {
|
||||||
|
private val resolved by lazy { MRegistry.ANDROID_FEATURES.getValue(name) }
|
||||||
|
val name: ResourceLocation
|
||||||
|
|
||||||
|
constructor(name: ResourceLocation) {
|
||||||
|
this.name = name
|
||||||
|
}
|
||||||
|
|
||||||
|
constructor(value: JsonObject) {
|
||||||
|
this.name = ResourceLocation.tryParse(value["name"]?.asString ?: throw JsonSyntaxException("Invalid android feature name: ${value["name"]}")) ?: throw JsonSyntaxException("Invalid android feature name ${value["name"]}")
|
||||||
|
}
|
||||||
|
|
||||||
|
override val type: PredicateType
|
||||||
|
get() = PredicateType.HAS
|
||||||
|
|
||||||
|
override fun test(t: MatteryPlayerCapability): Boolean {
|
||||||
|
return t.hasFeature(resolved ?: return false)
|
||||||
|
}
|
||||||
|
|
||||||
|
override fun toJson(): JsonObject {
|
||||||
|
return super.toJson().also {
|
||||||
|
it["name"] = name.toString()
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
class Not(val parent: FeaturePredicate) : FeaturePredicate() {
|
||||||
|
constructor(input: JsonObject) : this(PredicateType.from(input["parent"] as? JsonObject ?: throw JsonSyntaxException("Invalid parent")))
|
||||||
|
|
||||||
|
override val type: PredicateType
|
||||||
|
get() = PredicateType.NOT
|
||||||
|
|
||||||
|
override fun test(t: MatteryPlayerCapability): Boolean {
|
||||||
|
return !parent.test(t)
|
||||||
|
}
|
||||||
|
|
||||||
|
override fun toJson(): JsonObject {
|
||||||
|
return super.toJson().also {
|
||||||
|
it["parent"] = parent.toJson()
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
class And(children: Iterable<FeaturePredicate>) : FeaturePredicate() {
|
||||||
|
constructor(input: JsonObject) : this((input["children"] as? JsonArray)?.stream()?.map { PredicateType.from(it as? JsonObject ?: throw JsonSyntaxException("Invalid element in children list: $it")) }?.asIterable() ?: throw JsonSyntaxException("Invalid children list"))
|
||||||
|
|
||||||
|
val children: ImmutableList<FeaturePredicate> = ImmutableList.copyOf(children)
|
||||||
|
|
||||||
|
override val type: PredicateType
|
||||||
|
get() = PredicateType.AND
|
||||||
|
|
||||||
|
override fun test(t: MatteryPlayerCapability): Boolean {
|
||||||
|
return children.all { it.test(t) }
|
||||||
|
}
|
||||||
|
|
||||||
|
override fun toJson(): JsonObject {
|
||||||
|
return super.toJson().also {
|
||||||
|
it["children"] = JsonArray().also {
|
||||||
|
for (child in children) {
|
||||||
|
it.add(child.toJson())
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
class OrPredicate(children: Iterable<FeaturePredicate>) : FeaturePredicate() {
|
||||||
|
constructor(input: JsonObject) : this((input["children"] as? JsonArray)?.stream()?.map { PredicateType.from(it as? JsonObject ?: throw JsonSyntaxException("Invalid element in children list: $it")) }?.asIterable() ?: throw JsonSyntaxException("Invalid children list"))
|
||||||
|
|
||||||
|
val children: ImmutableList<FeaturePredicate> = ImmutableList.copyOf(children)
|
||||||
|
|
||||||
|
override val type: PredicateType
|
||||||
|
get() = PredicateType.OR
|
||||||
|
|
||||||
|
override fun test(t: MatteryPlayerCapability): Boolean {
|
||||||
|
return children.any { it.test(t) }
|
||||||
|
}
|
||||||
|
|
||||||
|
override fun toJson(): JsonObject {
|
||||||
|
return super.toJson().also {
|
||||||
|
it["children"] = JsonArray().also {
|
||||||
|
for (child in children) {
|
||||||
|
it.add(child.toJson())
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
class Instance(
|
||||||
|
val predicate: EntityPredicate.Composite = EntityPredicate.Composite.ANY,
|
||||||
|
val featurePredicate: FeaturePredicate = Always,
|
||||||
|
playerPredicate: EntityPredicate.Composite = EntityPredicate.Composite.ANY,
|
||||||
|
) : AbstractCriterionTriggerInstance(ID, playerPredicate) {
|
||||||
|
override fun serializeToJson(pConditions: SerializationContext): JsonObject {
|
||||||
|
return super.serializeToJson(pConditions).also {
|
||||||
|
it["predicate"] = predicate.toJson(pConditions)
|
||||||
|
it["feature_predicate"] = featurePredicate.toJson()
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
fun onKill(event: LivingDeathEvent) {
|
||||||
|
if (event.entity is ElderGuardian) {
|
||||||
|
val killer = event.entity.combatTracker.killer
|
||||||
|
|
||||||
|
if (killer is ServerPlayer) {
|
||||||
|
val data = killer.matteryPlayer ?: return
|
||||||
|
|
||||||
|
if (data.isAndroid) {
|
||||||
|
val context = EntityPredicate.createContext(killer, event.entity)
|
||||||
|
|
||||||
|
trigger(killer) {
|
||||||
|
it.predicate.matches(context) &&
|
||||||
|
it.featurePredicate.test(data)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
Loading…
Reference in New Issue
Block a user