mirror of
https://github.com/chylex/Hardcore-Ender-Expansion-2.git
synced 2025-11-19 08:22:35 +01:00
Compare commits
7 Commits
wip4
...
components
| Author | SHA1 | Date | |
|---|---|---|---|
| b64005357e | |||
| 3279dde625 | |||
| a9df51e315 | |||
| 322c005648 | |||
| 5211731e62 | |||
| 08d2fcb19c | |||
| e9077c680f |
@@ -22,7 +22,6 @@ import net.minecraft.block.BlockState
|
||||
import net.minecraft.enchantment.EnchantmentHelper
|
||||
import net.minecraft.enchantment.Enchantments
|
||||
import net.minecraft.entity.Entity
|
||||
import net.minecraft.entity.EntitySpawnPlacementRegistry.PlacementType
|
||||
import net.minecraft.entity.EntityType
|
||||
import net.minecraft.util.math.BlockPos
|
||||
import net.minecraft.world.IBlockReader
|
||||
@@ -48,6 +47,14 @@ class BlockDustyStoneUnstable(builder: BlockBuilder) : BlockDustyStone(builder),
|
||||
|
||||
return null
|
||||
}
|
||||
|
||||
private fun isNonCreative(entity: Entity): Boolean {
|
||||
return entity !is EntityPlayer || !entity.isCreative
|
||||
}
|
||||
|
||||
private fun isLightMob(entity: Entity): Boolean {
|
||||
return entity.height <= 0.5F || (entity.height <= 1F && entity.width <= 0.5F)
|
||||
}
|
||||
}
|
||||
|
||||
override fun canHarvestBlock(state: BlockState, world: IBlockReader, pos: BlockPos, player: EntityPlayer): Boolean {
|
||||
@@ -87,7 +94,7 @@ class BlockDustyStoneUnstable(builder: BlockBuilder) : BlockDustyStone(builder),
|
||||
}
|
||||
|
||||
override fun onEntityCollisionAbove(world: World, pos: BlockPos, entity: Entity) {
|
||||
if (!world.isRemote && world.totalTime % 4L == 0L && !(entity.height <= 0.5F || (entity.height <= 1F && entity.width <= 0.5F)) && isNonCreative(entity)) {
|
||||
if (!world.isRemote && world.totalTime % 4L == 0L && !isLightMob(entity) && isNonCreative(entity)) {
|
||||
if (!doCrumbleTest(world, pos)) {
|
||||
return
|
||||
}
|
||||
@@ -103,7 +110,7 @@ class BlockDustyStoneUnstable(builder: BlockBuilder) : BlockDustyStone(builder),
|
||||
}
|
||||
|
||||
override fun onFallenUpon(world: World, pos: BlockPos, entity: Entity, fallDistance: Float) {
|
||||
if (!world.isRemote && entity is EntityLivingBase && fallDistance > 1.3F && isNonCreative(entity)) {
|
||||
if (!world.isRemote && entity is EntityLivingBase && fallDistance > (if (isLightMob(entity)) 3.3F else 1.3F) && isNonCreative(entity)) {
|
||||
val rand = world.rand
|
||||
val aabb = entity.boundingBox
|
||||
val y = pos.y
|
||||
@@ -135,12 +142,8 @@ class BlockDustyStoneUnstable(builder: BlockBuilder) : BlockDustyStone(builder),
|
||||
super.onFallenUpon(world, pos, entity, fallDistance)
|
||||
}
|
||||
|
||||
override fun canCreatureSpawn(state: BlockState, world: IBlockReader, pos: BlockPos, placementType: PlacementType, entityType: EntityType<*>?): Boolean {
|
||||
return super.canCreatureSpawn(state, world, pos, placementType, entityType) && getCrumbleStartPos(world, pos) == null
|
||||
}
|
||||
|
||||
private fun isNonCreative(entity: Entity): Boolean {
|
||||
return entity !is EntityPlayer || !entity.isCreative
|
||||
override fun canEntitySpawn(state: BlockState, world: IBlockReader, pos: BlockPos, entityType: EntityType<*>): Boolean {
|
||||
return super.canEntitySpawn(state, world, pos, entityType) && getCrumbleStartPos(world, pos) == null
|
||||
}
|
||||
|
||||
private fun doCrumbleTest(world: World, pos: BlockPos): Boolean {
|
||||
|
||||
@@ -9,14 +9,13 @@ import chylex.hee.game.entity.technical.EntityTechnicalTrigger.Types.ENERGY_SHRI
|
||||
import chylex.hee.game.world.center
|
||||
import chylex.hee.game.world.feature.energyshrine.EnergyShrinePieces
|
||||
import net.minecraft.block.BlockState
|
||||
import net.minecraft.entity.EntitySpawnPlacementRegistry.PlacementType
|
||||
import net.minecraft.entity.EntityType
|
||||
import net.minecraft.util.math.BlockPos
|
||||
import net.minecraft.world.IBlockReader
|
||||
import net.minecraft.world.IEntityReader
|
||||
|
||||
class BlockGloomrock(builder: BlockBuilder) : BlockSimple(builder) {
|
||||
override fun canCreatureSpawn(state: BlockState, world: IBlockReader, pos: BlockPos, type: PlacementType, entityType: EntityType<*>?): Boolean {
|
||||
override fun canEntitySpawn(state: BlockState, world: IBlockReader, pos: BlockPos, entityType: EntityType<*>?): Boolean {
|
||||
if (world !is IEntityReader) {
|
||||
HEE.log.warn("[BlockGloomrock] attempted to check spawn on a world != IEntityReader (${world.javaClass})")
|
||||
return false
|
||||
|
||||
@@ -25,6 +25,7 @@ import chylex.hee.system.random.nextFloat
|
||||
import chylex.hee.system.random.nextInt
|
||||
import net.minecraft.block.Block
|
||||
import net.minecraft.block.BlockState
|
||||
import net.minecraft.entity.EntityType
|
||||
import net.minecraft.item.BlockItemUseContext
|
||||
import net.minecraft.item.ItemStack
|
||||
import net.minecraft.state.StateContainer.Builder
|
||||
@@ -88,6 +89,12 @@ open class BlockGraveDirt(builder: BlockBuilder) : BlockSimpleShaped(builder, Ax
|
||||
super.getShape(state, source, pos, context)
|
||||
}
|
||||
|
||||
// Mobs
|
||||
|
||||
override fun canEntitySpawn(state: BlockState, worldIn: IBlockReader, pos: BlockPos, type: EntityType<*>): Boolean {
|
||||
return true
|
||||
}
|
||||
|
||||
// Explosions
|
||||
|
||||
override fun canDropFromExplosion(explosion: Explosion): Boolean {
|
||||
|
||||
@@ -76,8 +76,8 @@ class EntityMobAngryEnderman(type: EntityType<EntityMobAngryEnderman>, world: Wo
|
||||
}
|
||||
|
||||
override fun updateAITasks() {
|
||||
teleportHandler.update()
|
||||
waterHandler.update()
|
||||
teleportHandler.tickServer()
|
||||
waterHandler.tickServer()
|
||||
|
||||
val currentTarget = attackTarget
|
||||
|
||||
|
||||
@@ -26,6 +26,10 @@ import chylex.hee.game.mechanics.causatum.events.CausatumEventEndermanKill
|
||||
import chylex.hee.game.world.playServer
|
||||
import chylex.hee.init.ModEntities
|
||||
import chylex.hee.init.ModSounds
|
||||
import chylex.hee.system.component.EntityComponents
|
||||
import chylex.hee.system.component.general.deserializeFrom
|
||||
import chylex.hee.system.component.general.serializeTo
|
||||
import chylex.hee.system.component.general.tick
|
||||
import chylex.hee.system.facades.Resource
|
||||
import chylex.hee.system.forge.SubscribeAllEvents
|
||||
import chylex.hee.system.forge.SubscribeEvent
|
||||
@@ -76,8 +80,6 @@ class EntityMobEnderman(type: EntityType<EntityMobEnderman>, world: World) : Ent
|
||||
|
||||
@SubscribeAllEvents(modid = HEE.ID)
|
||||
companion object {
|
||||
private const val TELEPORT_HANDLER_TAG = "Teleport"
|
||||
private const val WATER_HANDLER_TAG = "Water"
|
||||
private const val CAN_PICK_UP_BLOCKS_TAG = "CanPickUpBlocks"
|
||||
private const val HELD_BLOCK_TIMER_TAG = "HeldBlockTimer"
|
||||
private const val HELD_BLOCK_DESPAWNS_TAG = "HeldBlockDespawns"
|
||||
@@ -202,8 +204,9 @@ class EntityMobEnderman(type: EntityType<EntityMobEnderman>, world: World) : Ent
|
||||
|
||||
// Instance
|
||||
|
||||
private lateinit var components: EntityComponents
|
||||
|
||||
private lateinit var teleportHandler: EndermanTeleportHandler
|
||||
private lateinit var waterHandler: EndermanWaterHandler
|
||||
private lateinit var blockHandler: EndermanBlockHandler
|
||||
|
||||
private lateinit var aiAttackTarget: AIToggle
|
||||
@@ -227,6 +230,13 @@ class EntityMobEnderman(type: EntityType<EntityMobEnderman>, world: World) : Ent
|
||||
|
||||
// Initialization
|
||||
|
||||
override fun registerData() {
|
||||
super.registerData()
|
||||
|
||||
components = EntityComponents()
|
||||
components.attach(EndermanWaterHandler(this, takeDamageAfterWetTicks = 80))
|
||||
}
|
||||
|
||||
override fun registerAttributes() {
|
||||
super.registerAttributes()
|
||||
|
||||
@@ -238,8 +248,7 @@ class EntityMobEnderman(type: EntityType<EntityMobEnderman>, world: World) : Ent
|
||||
}
|
||||
|
||||
override fun registerGoals() {
|
||||
teleportHandler = EndermanTeleportHandler(this)
|
||||
waterHandler = EndermanWaterHandler(this, takeDamageAfterWetTicks = 80)
|
||||
teleportHandler = EndermanTeleportHandler(this).also(components::attach)
|
||||
blockHandler = EndermanBlockHandler(this)
|
||||
|
||||
aiWatchTargetInShock = AIWatchTargetInShock(this, maxDistance = 72.0)
|
||||
@@ -265,10 +274,9 @@ class EntityMobEnderman(type: EntityType<EntityMobEnderman>, world: World) : Ent
|
||||
override fun livingTick() {
|
||||
super.livingTick()
|
||||
|
||||
components.tick(this)
|
||||
|
||||
if (!world.isRemote) {
|
||||
teleportHandler.update()
|
||||
waterHandler.update()
|
||||
|
||||
if (heldBlockTimer > 0 && --heldBlockTimer == 0.toShort()) {
|
||||
if (heldBlockDespawns || !blockHandler.tryPlaceBlock(allowPlayerProximity = false)) {
|
||||
teleportHandler.teleportOutOfWorld(force = rand.nextBoolean())
|
||||
@@ -536,8 +544,7 @@ class EntityMobEnderman(type: EntityType<EntityMobEnderman>, world: World) : Ent
|
||||
override fun writeAdditional(nbt: TagCompound) = nbt.heeTag.use {
|
||||
super.writeAdditional(nbt)
|
||||
|
||||
put(TELEPORT_HANDLER_TAG, teleportHandler.serializeNBT())
|
||||
put(WATER_HANDLER_TAG, waterHandler.serializeNBT())
|
||||
components.serializeTo(this)
|
||||
|
||||
putBoolean(CAN_PICK_UP_BLOCKS_TAG, aiPickUpBlocks.enabled)
|
||||
putShort(HELD_BLOCK_TIMER_TAG, heldBlockTimer)
|
||||
@@ -547,8 +554,7 @@ class EntityMobEnderman(type: EntityType<EntityMobEnderman>, world: World) : Ent
|
||||
override fun readAdditional(nbt: TagCompound) = nbt.heeTag.use {
|
||||
super.readAdditional(nbt)
|
||||
|
||||
teleportHandler.deserializeNBT(getCompound(TELEPORT_HANDLER_TAG))
|
||||
waterHandler.deserializeNBT(getCompound(WATER_HANDLER_TAG))
|
||||
components.deserializeFrom(this)
|
||||
|
||||
aiPickUpBlocks.enabled = getBoolean(CAN_PICK_UP_BLOCKS_TAG)
|
||||
heldBlockTimer = getShort(HELD_BLOCK_TIMER_TAG)
|
||||
|
||||
@@ -56,11 +56,15 @@ import net.minecraft.block.BlockState
|
||||
import net.minecraft.entity.CreatureAttribute
|
||||
import net.minecraft.entity.Entity
|
||||
import net.minecraft.entity.EntityType
|
||||
import net.minecraft.entity.ILivingEntityData
|
||||
import net.minecraft.entity.SharedMonsterAttributes.ATTACK_DAMAGE
|
||||
import net.minecraft.entity.SharedMonsterAttributes.FOLLOW_RANGE
|
||||
import net.minecraft.entity.SharedMonsterAttributes.MAX_HEALTH
|
||||
import net.minecraft.entity.SharedMonsterAttributes.MOVEMENT_SPEED
|
||||
import net.minecraft.entity.SpawnReason
|
||||
import net.minecraft.entity.SpawnReason.SPAWNER
|
||||
import net.minecraft.entity.ai.attributes.AttributeModifier
|
||||
import net.minecraft.nbt.CompoundNBT
|
||||
import net.minecraft.network.IPacket
|
||||
import net.minecraft.network.datasync.DataSerializers
|
||||
import net.minecraft.pathfinding.PathNavigator
|
||||
@@ -76,6 +80,8 @@ import net.minecraft.util.math.RayTraceResult.Type
|
||||
import net.minecraft.util.math.Vec3d
|
||||
import net.minecraft.world.Difficulty.HARD
|
||||
import net.minecraft.world.Difficulty.NORMAL
|
||||
import net.minecraft.world.DifficultyInstance
|
||||
import net.minecraft.world.IWorld
|
||||
import net.minecraft.world.IWorldReader
|
||||
import net.minecraft.world.LightType.BLOCK
|
||||
import net.minecraft.world.LightType.SKY
|
||||
@@ -213,7 +219,7 @@ class EntityMobSpiderling(type: EntityType<EntityMobSpiderling>, world: World) :
|
||||
}
|
||||
else if (wakeUpTimer > 0) {
|
||||
if (--wakeUpTimer == 0) {
|
||||
wakeUp(instant = false, preventSleep = false)
|
||||
wakeUp(preventSleep = false)
|
||||
}
|
||||
}
|
||||
else if (ticksExisted % 4 == 0) {
|
||||
@@ -291,10 +297,18 @@ class EntityMobSpiderling(type: EntityType<EntityMobSpiderling>, world: World) :
|
||||
}
|
||||
}
|
||||
|
||||
private fun wakeUp(instant: Boolean, preventSleep: Boolean) {
|
||||
fun wakeUpInstantly(preventSleep: Boolean) {
|
||||
wakeUp(preventSleep, aiDelayTicks = 1)
|
||||
}
|
||||
|
||||
fun wakeUp(preventSleep: Boolean) {
|
||||
wakeUp(preventSleep, aiDelayTicks = rand.nextInt(25, 40))
|
||||
}
|
||||
|
||||
fun wakeUp(preventSleep: Boolean, aiDelayTicks: Int) {
|
||||
if (isSleeping) {
|
||||
isSleepingProp = false
|
||||
wakeUpDelayAI = if (instant) 1 else rand.nextInt(25, 40)
|
||||
wakeUpDelayAI = aiDelayTicks
|
||||
|
||||
if (preventSleep) {
|
||||
canSleepAgain = false
|
||||
@@ -303,7 +317,7 @@ class EntityMobSpiderling(type: EntityType<EntityMobSpiderling>, world: World) :
|
||||
}
|
||||
|
||||
override fun setFire(seconds: Int) {
|
||||
wakeUp(instant = true, preventSleep = true)
|
||||
wakeUpInstantly(preventSleep = true)
|
||||
super.setFire(seconds)
|
||||
}
|
||||
|
||||
@@ -314,7 +328,7 @@ class EntityMobSpiderling(type: EntityType<EntityMobSpiderling>, world: World) :
|
||||
// Behavior (Light)
|
||||
|
||||
override fun onLightStartled(): Boolean {
|
||||
wakeUp(instant = false, preventSleep = true)
|
||||
wakeUp(preventSleep = true)
|
||||
|
||||
if (world.totalTime < lightStartleResetTime) {
|
||||
return false
|
||||
@@ -401,7 +415,7 @@ class EntityMobSpiderling(type: EntityType<EntityMobSpiderling>, world: World) :
|
||||
return false
|
||||
}
|
||||
|
||||
wakeUp(instant = true, preventSleep = true)
|
||||
wakeUpInstantly(preventSleep = true)
|
||||
|
||||
if (!super.attackEntityFrom(source, if (source.isFireDamage) amount * 1.25F else amount)) {
|
||||
return false
|
||||
@@ -445,6 +459,16 @@ class EntityMobSpiderling(type: EntityType<EntityMobSpiderling>, world: World) :
|
||||
return true
|
||||
}
|
||||
|
||||
// Spawning
|
||||
|
||||
override fun onInitialSpawn(world: IWorld, difficulty: DifficultyInstance, reason: SpawnReason, data: ILivingEntityData?, nbt: CompoundNBT?): ILivingEntityData? {
|
||||
if (reason == SPAWNER) {
|
||||
wakeUpInstantly(preventSleep = true)
|
||||
}
|
||||
|
||||
return super.onInitialSpawn(world, difficulty, reason, data, nbt)
|
||||
}
|
||||
|
||||
// Despawning
|
||||
|
||||
override fun isDespawnPeaceful(): Boolean {
|
||||
@@ -515,7 +539,7 @@ class EntityMobSpiderling(type: EntityType<EntityMobSpiderling>, world: World) :
|
||||
val sleepState = getInt(SLEEP_STATE_TAG)
|
||||
|
||||
if (sleepState != 2) {
|
||||
wakeUp(instant = true, preventSleep = sleepState != 1)
|
||||
wakeUpInstantly(preventSleep = sleepState != 1)
|
||||
}
|
||||
|
||||
lightStartleResetTime = getLong(LIGHT_STARTLE_RESET_TIME_TAG)
|
||||
|
||||
@@ -137,19 +137,19 @@ class EntityMobUndread(type: EntityType<EntityMobUndread>, world: World) : Entit
|
||||
super.onDeathUpdate()
|
||||
}
|
||||
|
||||
override fun playStepSound(pos: BlockPos, state: BlockState) {
|
||||
public override fun playStepSound(pos: BlockPos, state: BlockState) {
|
||||
playSound(Sounds.ENTITY_ZOMBIE_STEP, rand.nextFloat(0.4F, 0.5F), rand.nextFloat(0.9F, 1F))
|
||||
}
|
||||
|
||||
override fun getHurtSound(source: DamageSource): SoundEvent {
|
||||
public override fun getHurtSound(source: DamageSource): SoundEvent {
|
||||
return ModSounds.MOB_UNDREAD_HURT
|
||||
}
|
||||
|
||||
override fun getDeathSound(): SoundEvent {
|
||||
public override fun getDeathSound(): SoundEvent {
|
||||
return ModSounds.MOB_UNDREAD_DEATH
|
||||
}
|
||||
|
||||
override fun getSoundPitch(): Float {
|
||||
public override fun getSoundPitch(): Float {
|
||||
return rand.nextFloat(0.8F, 1F)
|
||||
}
|
||||
}
|
||||
|
||||
@@ -7,8 +7,8 @@ import chylex.hee.game.particle.spawner.ParticleSpawnerCustom
|
||||
import chylex.hee.game.particle.spawner.properties.IShape.Point
|
||||
import chylex.hee.game.world.bottomCenter
|
||||
import chylex.hee.network.client.PacketClientFX
|
||||
import chylex.hee.network.fx.IFxData
|
||||
import chylex.hee.network.fx.IFxHandler
|
||||
import chylex.hee.network.fx.FxVecData
|
||||
import chylex.hee.network.fx.FxVecHandler
|
||||
import chylex.hee.system.color.IntColor.Companion.RGB
|
||||
import chylex.hee.system.math.Vec
|
||||
import chylex.hee.system.math.Vec3
|
||||
@@ -21,10 +21,7 @@ import chylex.hee.system.serialization.NBTList.Companion.putList
|
||||
import chylex.hee.system.serialization.NBTObjectList
|
||||
import chylex.hee.system.serialization.TagCompound
|
||||
import chylex.hee.system.serialization.getListOfCompounds
|
||||
import chylex.hee.system.serialization.readVec
|
||||
import chylex.hee.system.serialization.use
|
||||
import chylex.hee.system.serialization.writeVec
|
||||
import net.minecraft.network.PacketBuffer
|
||||
import net.minecraft.util.math.BlockPos
|
||||
import net.minecraft.util.math.Vec3d
|
||||
import net.minecraft.world.World
|
||||
@@ -50,15 +47,9 @@ class EnderEyeSpawnerParticles(private val entity: EntityBossEnderEye) : INBTSer
|
||||
hideOnMinimalSetting = false
|
||||
)
|
||||
|
||||
class ParticleData(private val point: Vec3d) : IFxData {
|
||||
override fun write(buffer: PacketBuffer) = buffer.use {
|
||||
writeVec(point)
|
||||
}
|
||||
}
|
||||
|
||||
val FX_PARTICLE = object : IFxHandler<ParticleData> {
|
||||
override fun handle(buffer: PacketBuffer, world: World, rand: Random) = buffer.use {
|
||||
PARTICLE_TICK.spawn(Point(readVec(), 2), rand)
|
||||
val FX_PARTICLE = object : FxVecHandler() {
|
||||
override fun handle(world: World, rand: Random, vec: Vec3d) {
|
||||
PARTICLE_TICK.spawn(Point(vec, 2), rand)
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -95,7 +86,7 @@ class EnderEyeSpawnerParticles(private val entity: EntityBossEnderEye) : INBTSer
|
||||
else -> 1.0
|
||||
}
|
||||
|
||||
PacketClientFX(FX_PARTICLE, ParticleData(pos.addY(sqrt(progressCurvePoint) * 6.0))).sendToAllAround(entity.world, pos, 256.0)
|
||||
PacketClientFX(FX_PARTICLE, FxVecData(pos.addY(sqrt(progressCurvePoint) * 6.0))).sendToAllAround(entity.world, pos, 256.0)
|
||||
}
|
||||
|
||||
if (distSq > prevDistSq || distSq < square(0.15)) {
|
||||
|
||||
@@ -29,6 +29,8 @@ import chylex.hee.network.client.PacketClientFX
|
||||
import chylex.hee.network.fx.FxEntityData
|
||||
import chylex.hee.network.fx.FxEntityHandler
|
||||
import chylex.hee.system.color.IntColor.Companion.RGB
|
||||
import chylex.hee.system.component.general.SerializableComponent
|
||||
import chylex.hee.system.component.general.TickableComponent
|
||||
import chylex.hee.system.math.Vec
|
||||
import chylex.hee.system.math.Vec3
|
||||
import chylex.hee.system.math.addY
|
||||
@@ -53,13 +55,12 @@ import net.minecraft.util.SoundCategory
|
||||
import net.minecraft.util.math.AxisAlignedBB
|
||||
import net.minecraft.util.math.BlockPos
|
||||
import net.minecraft.util.math.Vec3d
|
||||
import net.minecraftforge.common.util.INBTSerializable
|
||||
import java.util.Random
|
||||
import java.util.UUID
|
||||
import kotlin.math.min
|
||||
import kotlin.math.sqrt
|
||||
|
||||
class EndermanTeleportHandler(private val enderman: EntityMobAbstractEnderman) : INBTSerializable<TagCompound> {
|
||||
class EndermanTeleportHandler(private val enderman: EntityMobAbstractEnderman) : TickableComponent, SerializableComponent {
|
||||
companion object {
|
||||
private const val DEFAULT_RESTORE_Y = -256.0
|
||||
|
||||
@@ -117,6 +118,9 @@ class EndermanTeleportHandler(private val enderman: EntityMobAbstractEnderman) :
|
||||
}
|
||||
}
|
||||
|
||||
override val serializationKey
|
||||
get() = "Teleport"
|
||||
|
||||
val preventDespawn
|
||||
get() = tpDelayTicks > 0
|
||||
|
||||
@@ -133,7 +137,7 @@ class EndermanTeleportHandler(private val enderman: EntityMobAbstractEnderman) :
|
||||
|
||||
private var lastDodged: UUID? = null
|
||||
|
||||
fun update() {
|
||||
override fun tickServer() {
|
||||
if (tpCooldown > 0) {
|
||||
--tpCooldown
|
||||
}
|
||||
|
||||
@@ -4,15 +4,16 @@ import chylex.hee.game.entity.OPERATION_MUL_INCR_INDIVIDUAL
|
||||
import chylex.hee.game.entity.living.EntityMobAbstractEnderman
|
||||
import chylex.hee.game.entity.tryApplyModifier
|
||||
import chylex.hee.game.entity.tryRemoveModifier
|
||||
import chylex.hee.system.component.general.SerializableComponent
|
||||
import chylex.hee.system.component.general.TickableComponent
|
||||
import chylex.hee.system.random.nextInt
|
||||
import chylex.hee.system.serialization.TagCompound
|
||||
import chylex.hee.system.serialization.use
|
||||
import net.minecraft.entity.SharedMonsterAttributes.ATTACK_DAMAGE
|
||||
import net.minecraft.entity.ai.attributes.AttributeModifier
|
||||
import net.minecraft.util.DamageSource
|
||||
import net.minecraftforge.common.util.INBTSerializable
|
||||
|
||||
class EndermanWaterHandler(private val enderman: EntityMobAbstractEnderman, private val takeDamageAfterWetTicks: Int) : INBTSerializable<TagCompound> {
|
||||
class EndermanWaterHandler(private val enderman: EntityMobAbstractEnderman, private val takeDamageAfterWetTicks: Int) : TickableComponent, SerializableComponent {
|
||||
private companion object {
|
||||
private val DEBUFF_WEAKNESS = AttributeModifier("Water weakness", -0.5, OPERATION_MUL_INCR_INDIVIDUAL)
|
||||
|
||||
@@ -20,10 +21,13 @@ class EndermanWaterHandler(private val enderman: EntityMobAbstractEnderman, priv
|
||||
private const val DEBUFF_TICKS_TAG = "DebuffTicks"
|
||||
}
|
||||
|
||||
override val serializationKey
|
||||
get() = "Water"
|
||||
|
||||
private var wetCounter = 0
|
||||
private var debuffTicks = 0
|
||||
|
||||
fun update() {
|
||||
override fun tickServer() {
|
||||
val isWet = enderman.isWet
|
||||
|
||||
if (isWet) {
|
||||
|
||||
@@ -9,6 +9,7 @@ import chylex.hee.game.world.feature.stronghold.piece.StrongholdRoom_Main_Portal
|
||||
import chylex.hee.game.world.feature.stronghold.piece.StrongholdRoom_Trap_CornerHoles
|
||||
import chylex.hee.game.world.feature.stronghold.piece.StrongholdRoom_Trap_Prison
|
||||
import chylex.hee.game.world.feature.stronghold.piece.StrongholdRoom_Trap_TallIntersection
|
||||
import chylex.hee.game.world.feature.tombdungeon.piece.TombDungeonRoom_Tomb
|
||||
import chylex.hee.init.ModEntities
|
||||
import chylex.hee.system.delegate.NotifyOnChange
|
||||
import chylex.hee.system.serialization.TagCompound
|
||||
@@ -28,6 +29,10 @@ class EntityTechnicalTrigger(type: EntityType<EntityTechnicalTrigger>, world: Wo
|
||||
this.type = type
|
||||
}
|
||||
|
||||
constructor(world: World, type: Types, nbt: TagCompound) : this(world, type) {
|
||||
handler.deserializeNBT(nbt)
|
||||
}
|
||||
|
||||
private companion object {
|
||||
private const val TYPE_TAG = "Type"
|
||||
private const val DATA_TAG = "Data"
|
||||
@@ -62,6 +67,7 @@ class EntityTechnicalTrigger(type: EntityType<EntityTechnicalTrigger>, world: Wo
|
||||
STRONGHOLD_TRAP_TALL_INTERSECTION({ StrongholdRoom_Trap_TallIntersection.Trigger }),
|
||||
ENERGY_SHRINE_GENERATOR({ EnergyShrineGenerator.GeneratorTrigger }),
|
||||
ENERGY_SHRINE_GLOBAL({ EnergyShrineRoom_Main_Start.Particles }),
|
||||
TOMB_DUNGEON_UNDREAD_SPAWNER(TombDungeonRoom_Tomb::MobSpawnerTrigger),
|
||||
OBSIDIAN_TOWER_TOP_GLOWSTONE(ObsidianTowerLevel_Top::GlowstoneTrigger),
|
||||
OBSIDIAN_TOWER_DEATH_ANIMATION(ObsidianTowerLevel_Top::DeathAnimationTrigger)
|
||||
}
|
||||
|
||||
@@ -3,6 +3,7 @@ package chylex.hee.game.item
|
||||
import chylex.hee.game.block.entity.TileEntityEnergyCluster
|
||||
import chylex.hee.game.inventory.heeTag
|
||||
import chylex.hee.game.inventory.heeTagOrNull
|
||||
import chylex.hee.game.item.components.UseOnBlockComponent
|
||||
import chylex.hee.game.mechanics.energy.IEnergyQuantity
|
||||
import chylex.hee.game.mechanics.energy.IEnergyQuantity.Units
|
||||
import chylex.hee.game.particle.ParticleEnergyTransferToPlayer
|
||||
@@ -36,11 +37,11 @@ import chylex.hee.system.serialization.use
|
||||
import chylex.hee.system.serialization.writePos
|
||||
import net.minecraft.client.util.ITooltipFlag
|
||||
import net.minecraft.entity.Entity
|
||||
import net.minecraft.item.Item
|
||||
import net.minecraft.item.ItemStack
|
||||
import net.minecraft.item.ItemUseContext
|
||||
import net.minecraft.network.PacketBuffer
|
||||
import net.minecraft.util.ActionResultType
|
||||
import net.minecraft.util.math.BlockPos
|
||||
import net.minecraft.util.math.MathHelper
|
||||
import net.minecraft.util.text.ITextComponent
|
||||
import net.minecraft.util.text.TranslationTextComponent
|
||||
@@ -50,7 +51,7 @@ import java.util.Random
|
||||
import kotlin.math.max
|
||||
import kotlin.math.pow
|
||||
|
||||
abstract class ItemAbstractEnergyUser(properties: Properties) : Item(properties) {
|
||||
abstract class ItemAbstractEnergyUser(properties: Properties) : ItemWithComponents(properties), UseOnBlockComponent {
|
||||
companion object {
|
||||
private const val ENERGY_LEVEL_TAG = "EnergyLevel"
|
||||
|
||||
@@ -100,6 +101,8 @@ abstract class ItemAbstractEnergyUser(properties: Properties) : Item(properties)
|
||||
init {
|
||||
@Suppress("DEPRECATION")
|
||||
require(maxStackSize == 1) { "energy item must have a maximum stack size of 1" }
|
||||
|
||||
components.attach(this)
|
||||
}
|
||||
|
||||
protected abstract fun getEnergyCapacity(stack: ItemStack): Units
|
||||
@@ -163,15 +166,11 @@ abstract class ItemAbstractEnergyUser(properties: Properties) : Item(properties)
|
||||
|
||||
// Energy charging
|
||||
|
||||
override fun onItemUse(context: ItemUseContext): ActionResultType {
|
||||
val player = context.player ?: return FAIL
|
||||
val world = context.world
|
||||
val pos = context.pos
|
||||
|
||||
override fun useOnBlock(world: World, pos: BlockPos, player: EntityPlayer, item: ItemStack, ctx: ItemUseContext): ActionResultType? {
|
||||
val tile = pos.getTile<TileEntityEnergyCluster>(world)
|
||||
val stack = player.getHeldItem(context.hand)
|
||||
val stack = player.getHeldItem(ctx.hand)
|
||||
|
||||
if (tile == null || !player.canPlayerEdit(pos, context.face, stack)) {
|
||||
if (tile == null || !player.canPlayerEdit(pos, ctx.face, stack)) {
|
||||
return FAIL
|
||||
}
|
||||
else if (world.isRemote) {
|
||||
|
||||
@@ -13,7 +13,7 @@ import net.minecraft.util.text.StringTextComponent
|
||||
import net.minecraft.util.text.TranslationTextComponent
|
||||
import net.minecraft.world.World
|
||||
|
||||
abstract class ItemAbstractInfusable(properties: Properties) : Item(properties), IInfusableItem {
|
||||
abstract class ItemAbstractInfusable(properties: Properties) : ItemWithComponents(properties), IInfusableItem {
|
||||
companion object {
|
||||
fun onCanApplyInfusion(item: Item, infusion: Infusion): Boolean {
|
||||
return infusion.targetItems.contains(item)
|
||||
|
||||
@@ -1,6 +1,7 @@
|
||||
package chylex.hee.game.item
|
||||
|
||||
import chylex.hee.game.inventory.size
|
||||
import chylex.hee.game.item.components.UseOnBlockComponent
|
||||
import chylex.hee.game.world.BlockEditor
|
||||
import chylex.hee.init.ModItems
|
||||
import chylex.hee.network.client.PacketClientFX
|
||||
@@ -15,7 +16,6 @@ import chylex.hee.system.migration.ItemBoneMeal
|
||||
import net.minecraft.block.DispenserBlock.FACING
|
||||
import net.minecraft.dispenser.IBlockSource
|
||||
import net.minecraft.dispenser.OptionalDispenseBehavior
|
||||
import net.minecraft.item.Item
|
||||
import net.minecraft.item.ItemStack
|
||||
import net.minecraft.item.ItemUseContext
|
||||
import net.minecraft.util.ActionResultType
|
||||
@@ -25,7 +25,7 @@ import net.minecraft.world.server.ServerWorld
|
||||
import net.minecraftforge.common.util.FakePlayerFactory
|
||||
import java.util.Random
|
||||
|
||||
class ItemCompost(properties: Properties) : Item(properties) {
|
||||
class ItemCompost(properties: Properties) : ItemWithComponents(properties) {
|
||||
companion object {
|
||||
private const val BONE_MEAL_EQUIVALENT = 2
|
||||
|
||||
@@ -61,6 +61,24 @@ class ItemCompost(properties: Properties) : Item(properties) {
|
||||
}
|
||||
|
||||
init {
|
||||
components.attach(object : UseOnBlockComponent {
|
||||
override fun useOnBlock(world: World, pos: BlockPos, player: EntityPlayer, item: ItemStack, ctx: ItemUseContext): ActionResultType {
|
||||
if (!BlockEditor.canEdit(pos, player, item)) {
|
||||
return FAIL
|
||||
}
|
||||
else if (world.isRemote) {
|
||||
return SUCCESS
|
||||
}
|
||||
|
||||
if (applyCompost(world, pos, player)) {
|
||||
item.shrink(1)
|
||||
return SUCCESS
|
||||
}
|
||||
|
||||
return PASS
|
||||
}
|
||||
})
|
||||
|
||||
BlockDispenser.registerDispenseBehavior(this, object : OptionalDispenseBehavior() {
|
||||
override fun dispenseStack(source: IBlockSource, stack: ItemStack): ItemStack {
|
||||
val world = source.world
|
||||
@@ -77,26 +95,4 @@ class ItemCompost(properties: Properties) : Item(properties) {
|
||||
}
|
||||
})
|
||||
}
|
||||
|
||||
override fun onItemUse(context: ItemUseContext): ActionResultType {
|
||||
val player = context.player ?: return FAIL
|
||||
val world = context.world
|
||||
val pos = context.pos
|
||||
|
||||
val heldItem = player.getHeldItem(context.hand)
|
||||
|
||||
if (!BlockEditor.canEdit(pos, player, heldItem)) {
|
||||
return FAIL
|
||||
}
|
||||
else if (world.isRemote) {
|
||||
return SUCCESS
|
||||
}
|
||||
|
||||
if (applyCompost(world, pos, player)) {
|
||||
heldItem.shrink(1)
|
||||
return SUCCESS
|
||||
}
|
||||
|
||||
return PASS
|
||||
}
|
||||
}
|
||||
|
||||
@@ -2,27 +2,27 @@ package chylex.hee.game.item
|
||||
|
||||
import chylex.hee.game.block.IBlockDeathFlowerDecaying
|
||||
import chylex.hee.game.entity.item.EntityItemCauldronTrigger
|
||||
import chylex.hee.game.item.components.UseOnBlockComponent
|
||||
import chylex.hee.game.world.BlockEditor
|
||||
import chylex.hee.game.world.getBlock
|
||||
import chylex.hee.system.migration.ActionResult.FAIL
|
||||
import chylex.hee.system.migration.ActionResult.PASS
|
||||
import chylex.hee.system.migration.ActionResult.SUCCESS
|
||||
import chylex.hee.system.migration.EntityPlayer
|
||||
import net.minecraft.entity.Entity
|
||||
import net.minecraft.item.Item
|
||||
import net.minecraft.item.ItemStack
|
||||
import net.minecraft.item.ItemUseContext
|
||||
import net.minecraft.util.ActionResultType
|
||||
import net.minecraft.util.math.BlockPos
|
||||
import net.minecraft.world.World
|
||||
|
||||
class ItemEndPowder(properties: Properties) : Item(properties) {
|
||||
override fun onItemUse(context: ItemUseContext): ActionResultType {
|
||||
val player = context.player ?: return FAIL
|
||||
val world = context.world
|
||||
val pos = context.pos
|
||||
|
||||
val heldItem = player.getHeldItem(context.hand)
|
||||
|
||||
if (!BlockEditor.canEdit(pos, player, heldItem)) {
|
||||
class ItemEndPowder(properties: Properties) : ItemWithComponents(properties), UseOnBlockComponent {
|
||||
init {
|
||||
components.attach(this)
|
||||
}
|
||||
|
||||
override fun useOnBlock(world: World, pos: BlockPos, player: EntityPlayer, item: ItemStack, ctx: ItemUseContext): ActionResultType? {
|
||||
if (!BlockEditor.canEdit(pos, player, item)) {
|
||||
return FAIL
|
||||
}
|
||||
|
||||
@@ -33,7 +33,7 @@ class ItemEndPowder(properties: Properties) : Item(properties) {
|
||||
block.healDeathFlower(world, pos)
|
||||
}
|
||||
|
||||
heldItem.shrink(1)
|
||||
item.shrink(1)
|
||||
return SUCCESS
|
||||
}
|
||||
|
||||
|
||||
@@ -28,7 +28,6 @@ import chylex.hee.system.math.angleBetween
|
||||
import chylex.hee.system.math.floorToInt
|
||||
import chylex.hee.system.math.over
|
||||
import chylex.hee.system.math.toDegrees
|
||||
import chylex.hee.system.migration.ActionResult.FAIL
|
||||
import chylex.hee.system.migration.ActionResult.SUCCESS
|
||||
import chylex.hee.system.migration.EntityLivingBase
|
||||
import chylex.hee.system.migration.EntityPlayer
|
||||
@@ -150,17 +149,13 @@ class ItemEnergyOracle(properties: Properties) : ItemAbstractEnergyUser(properti
|
||||
return ItemAbstractInfusable.onCanApplyInfusion(this, infusion)
|
||||
}
|
||||
|
||||
override fun onItemUse(context: ItemUseContext): ActionResultType {
|
||||
val player = context.player ?: return FAIL
|
||||
val world = context.world
|
||||
val pos = context.pos
|
||||
|
||||
override fun useOnBlock(world: World, pos: BlockPos, player: EntityPlayer, item: ItemStack, ctx: ItemUseContext): ActionResultType? {
|
||||
if (player.isSneaking && pos.getTile<TileEntityEnergyCluster>(world) != null) {
|
||||
if (world.isRemote) {
|
||||
return SUCCESS
|
||||
}
|
||||
|
||||
val heldItem = player.getHeldItem(context.hand)
|
||||
val heldItem = player.getHeldItem(ctx.hand)
|
||||
val entry = pos.toLong()
|
||||
|
||||
with(heldItem.heeTag) {
|
||||
@@ -176,7 +171,7 @@ class ItemEnergyOracle(properties: Properties) : ItemAbstractEnergyUser(properti
|
||||
return SUCCESS
|
||||
}
|
||||
|
||||
return super.onItemUse(context)
|
||||
return super.useOnBlock(world, pos, player, item, ctx)
|
||||
}
|
||||
|
||||
override fun inventoryTick(stack: ItemStack, world: World, entity: Entity, itemSlot: Int, isSelected: Boolean) {
|
||||
|
||||
@@ -4,6 +4,7 @@ import chylex.hee.client.color.NO_TINT
|
||||
import chylex.hee.game.block.entity.TileEntityEnergyCluster
|
||||
import chylex.hee.game.inventory.heeTag
|
||||
import chylex.hee.game.inventory.heeTagOrNull
|
||||
import chylex.hee.game.item.components.UseOnBlockComponent
|
||||
import chylex.hee.game.item.infusion.Infusion.SAFETY
|
||||
import chylex.hee.game.item.infusion.Infusion.STABILITY
|
||||
import chylex.hee.game.item.infusion.InfusionList
|
||||
@@ -27,10 +28,10 @@ import chylex.hee.system.forge.Side
|
||||
import chylex.hee.system.forge.Sided
|
||||
import chylex.hee.system.migration.ActionResult.FAIL
|
||||
import chylex.hee.system.migration.ActionResult.SUCCESS
|
||||
import chylex.hee.system.migration.EntityPlayer
|
||||
import chylex.hee.system.serialization.TagCompound
|
||||
import chylex.hee.system.serialization.getIntegerOrNull
|
||||
import chylex.hee.system.serialization.hasKey
|
||||
import chylex.hee.system.serialization.use
|
||||
import net.minecraft.client.renderer.color.IItemColor
|
||||
import net.minecraft.client.util.ITooltipFlag
|
||||
import net.minecraft.entity.Entity
|
||||
@@ -43,7 +44,7 @@ import net.minecraft.util.text.TranslationTextComponent
|
||||
import net.minecraft.world.World
|
||||
import kotlin.math.pow
|
||||
|
||||
class ItemEnergyReceptacle(properties: Properties) : ItemAbstractInfusable(properties) {
|
||||
class ItemEnergyReceptacle(properties: Properties) : ItemAbstractInfusable(properties), UseOnBlockComponent {
|
||||
private companion object {
|
||||
private const val CLUSTER_SNAPSHOT_TAG = "Cluster"
|
||||
private const val UPDATE_TIME_TAG = "UpdateTime"
|
||||
@@ -105,18 +106,14 @@ class ItemEnergyReceptacle(properties: Properties) : ItemAbstractInfusable(prope
|
||||
}
|
||||
|
||||
// POLISH tweak animation
|
||||
|
||||
components.attach(this)
|
||||
}
|
||||
|
||||
override fun onItemUse(context: ItemUseContext): ActionResultType {
|
||||
val player = context.player ?: return FAIL
|
||||
val world = context.world
|
||||
val pos = context.pos
|
||||
|
||||
val stack = player.getHeldItem(context.hand)
|
||||
|
||||
stack.heeTag.use {
|
||||
override fun useOnBlock(world: World, pos: BlockPos, player: EntityPlayer, item: ItemStack, ctx: ItemUseContext): ActionResultType? {
|
||||
with(item.heeTag) {
|
||||
if (hasKey(CLUSTER_SNAPSHOT_TAG)) {
|
||||
val finalPos = BlockEditor.place(ModBlocks.ENERGY_CLUSTER, player, stack, context)
|
||||
val finalPos = BlockEditor.place(ModBlocks.ENERGY_CLUSTER, player, item, ctx)
|
||||
|
||||
if (world.isRemote) {
|
||||
return SUCCESS
|
||||
@@ -126,7 +123,7 @@ class ItemEnergyReceptacle(properties: Properties) : ItemAbstractInfusable(prope
|
||||
finalPos.getTile<TileEntityEnergyCluster>(world)?.let {
|
||||
it.loadClusterSnapshot(ClusterSnapshot(getCompound(CLUSTER_SNAPSHOT_TAG)), inactive = false)
|
||||
|
||||
if (shouldLoseHealth(it, this, InfusionTag.getList(stack))) {
|
||||
if (shouldLoseHealth(it, this, InfusionTag.getList(item))) {
|
||||
it.deteriorateHealth()
|
||||
}
|
||||
}
|
||||
@@ -141,7 +138,7 @@ class ItemEnergyReceptacle(properties: Properties) : ItemAbstractInfusable(prope
|
||||
return SUCCESS
|
||||
}
|
||||
}
|
||||
else if (BlockEditor.canEdit(pos, player, stack)) {
|
||||
else if (BlockEditor.canEdit(pos, player, item)) {
|
||||
if (world.isRemote) {
|
||||
return SUCCESS
|
||||
}
|
||||
|
||||
@@ -6,6 +6,7 @@ import chylex.hee.game.entity.heeTag
|
||||
import chylex.hee.game.entity.heeTagOrNull
|
||||
import chylex.hee.game.entity.posVec
|
||||
import chylex.hee.game.inventory.doDamage
|
||||
import chylex.hee.game.item.components.UseOnBlockComponent
|
||||
import chylex.hee.game.world.BlockEditor
|
||||
import chylex.hee.game.world.FLAG_NONE
|
||||
import chylex.hee.game.world.getBlock
|
||||
@@ -14,7 +15,6 @@ import chylex.hee.game.world.playServer
|
||||
import chylex.hee.game.world.removeBlock
|
||||
import chylex.hee.game.world.setBlock
|
||||
import chylex.hee.init.ModBlocks
|
||||
import chylex.hee.system.compatibility.MinecraftForgeEventBus
|
||||
import chylex.hee.system.forge.EventPriority
|
||||
import chylex.hee.system.forge.SubscribeAllEvents
|
||||
import chylex.hee.system.forge.SubscribeEvent
|
||||
@@ -26,7 +26,6 @@ import chylex.hee.system.migration.EntityPlayer
|
||||
import chylex.hee.system.migration.Sounds
|
||||
import chylex.hee.system.random.nextFloat
|
||||
import net.minecraft.block.Blocks
|
||||
import net.minecraft.item.Item
|
||||
import net.minecraft.item.ItemStack
|
||||
import net.minecraft.item.ItemUseContext
|
||||
import net.minecraft.util.ActionResultType
|
||||
@@ -36,7 +35,7 @@ import net.minecraft.util.math.BlockPos
|
||||
import net.minecraft.world.World
|
||||
import net.minecraftforge.event.world.ExplosionEvent
|
||||
|
||||
class ItemFlintAndInfernium(properties: Properties) : Item(properties) {
|
||||
class ItemFlintAndInfernium(properties: Properties) : ItemWithComponents(properties), UseOnBlockComponent {
|
||||
@SubscribeAllEvents(modid = HEE.ID)
|
||||
companion object {
|
||||
private const val CREEPER_INFERNIUM_TAG = "Infernium"
|
||||
@@ -55,7 +54,7 @@ class ItemFlintAndInfernium(properties: Properties) : Item(properties) {
|
||||
}
|
||||
|
||||
init {
|
||||
MinecraftForgeEventBus.register(this)
|
||||
components.attach(this)
|
||||
}
|
||||
|
||||
fun igniteTNT(world: World, pos: BlockPos, player: EntityPlayer?, ignoreTrap: Boolean) {
|
||||
@@ -67,14 +66,8 @@ class ItemFlintAndInfernium(properties: Properties) : Item(properties) {
|
||||
pos.removeBlock(world)
|
||||
}
|
||||
|
||||
override fun onItemUse(context: ItemUseContext): ActionResultType {
|
||||
val player = context.player ?: return FAIL
|
||||
val world = context.world
|
||||
val pos = context.pos
|
||||
|
||||
val heldItem = player.getHeldItem(context.hand)
|
||||
|
||||
if (!BlockEditor.canEdit(pos, player, heldItem)) {
|
||||
override fun useOnBlock(world: World, pos: BlockPos, player: EntityPlayer, item: ItemStack, ctx: ItemUseContext): ActionResultType? {
|
||||
if (!BlockEditor.canEdit(pos, player, item)) {
|
||||
return FAIL
|
||||
}
|
||||
|
||||
@@ -85,11 +78,11 @@ class ItemFlintAndInfernium(properties: Properties) : Item(properties) {
|
||||
igniteTNT(world, pos, player, ignoreTrap = false)
|
||||
}
|
||||
else {
|
||||
BlockEditor.place(ModBlocks.ETERNAL_FIRE, player, heldItem, context) ?: return FAIL
|
||||
BlockEditor.place(ModBlocks.ETERNAL_FIRE, player, item, ctx) ?: return FAIL
|
||||
}
|
||||
|
||||
Sounds.ITEM_FLINTANDSTEEL_USE.playServer(world, pos, SoundCategory.BLOCKS, volume = 1.1F, pitch = world.rand.nextFloat(0.4F, 0.5F))
|
||||
heldItem.doDamage(1, player, context.hand)
|
||||
item.doDamage(1, player, ctx.hand)
|
||||
}
|
||||
|
||||
return SUCCESS
|
||||
|
||||
@@ -9,6 +9,7 @@ import chylex.hee.game.entity.item.EntityTokenHolder
|
||||
import chylex.hee.game.entity.selectExistingEntities
|
||||
import chylex.hee.game.inventory.heeTag
|
||||
import chylex.hee.game.inventory.heeTagOrNull
|
||||
import chylex.hee.game.item.components.UseOnBlockComponent
|
||||
import chylex.hee.game.mechanics.portal.DimensionTeleporter
|
||||
import chylex.hee.game.mechanics.portal.EntityPortalContact
|
||||
import chylex.hee.game.world.BlockEditor
|
||||
@@ -34,7 +35,6 @@ import chylex.hee.system.serialization.putEnum
|
||||
import net.minecraft.client.renderer.color.IItemColor
|
||||
import net.minecraft.client.util.ITooltipFlag
|
||||
import net.minecraft.entity.Entity
|
||||
import net.minecraft.item.Item
|
||||
import net.minecraft.item.ItemGroup
|
||||
import net.minecraft.item.ItemStack
|
||||
import net.minecraft.item.ItemUseContext
|
||||
@@ -43,13 +43,14 @@ import net.minecraft.util.ActionResultType
|
||||
import net.minecraft.util.Hand
|
||||
import net.minecraft.util.NonNullList
|
||||
import net.minecraft.util.math.AxisAlignedBB
|
||||
import net.minecraft.util.math.BlockPos
|
||||
import net.minecraft.util.text.ITextComponent
|
||||
import net.minecraft.util.text.StringTextComponent
|
||||
import net.minecraft.util.text.TranslationTextComponent
|
||||
import net.minecraft.world.World
|
||||
import net.minecraft.world.dimension.DimensionType
|
||||
|
||||
class ItemPortalToken(properties: Properties) : Item(properties) {
|
||||
class ItemPortalToken(properties: Properties) : ItemWithComponents(properties), UseOnBlockComponent {
|
||||
companion object {
|
||||
private const val TYPE_TAG = "Type"
|
||||
private const val TERRITORY_TYPE_TAG = "Territory"
|
||||
@@ -72,6 +73,8 @@ class ItemPortalToken(properties: Properties) : Item(properties) {
|
||||
}
|
||||
|
||||
init {
|
||||
components.attach(this)
|
||||
|
||||
addPropertyOverride(Resource.Custom("token_type")) { stack, _, _ ->
|
||||
getTokenType(stack).propertyValue + (if (stack.heeTagOrNull.hasKey(IS_CORRUPTED_TAG)) 0.5F else 0F)
|
||||
}
|
||||
@@ -178,10 +181,7 @@ class ItemPortalToken(properties: Properties) : Item(properties) {
|
||||
return ActionResult(SUCCESS, heldItem)
|
||||
}
|
||||
|
||||
override fun onItemUse(context: ItemUseContext): ActionResultType {
|
||||
val player = context.player ?: return FAIL
|
||||
val world = context.world
|
||||
|
||||
override fun useOnBlock(world: World, pos: BlockPos, player: EntityPlayer, item: ItemStack, ctx: ItemUseContext): ActionResultType {
|
||||
if (!player.isCreative || player.isSneaking) {
|
||||
return PASS
|
||||
}
|
||||
@@ -190,16 +190,14 @@ class ItemPortalToken(properties: Properties) : Item(properties) {
|
||||
return SUCCESS
|
||||
}
|
||||
|
||||
val targetPos = context.pos.up()
|
||||
val targetPos = pos.up()
|
||||
val territoryType = getTerritoryType(item)
|
||||
|
||||
val heldItem = player.getHeldItem(context.hand)
|
||||
val territoryType = getTerritoryType(heldItem)
|
||||
|
||||
if (territoryType == null || context.face != UP || !BlockEditor.canEdit(targetPos, player, heldItem) || world.selectExistingEntities.inBox<EntityTokenHolder>(AxisAlignedBB(targetPos)).any()) {
|
||||
if (territoryType == null || ctx.face != UP || !BlockEditor.canEdit(targetPos, player, item) || world.selectExistingEntities.inBox<EntityTokenHolder>(AxisAlignedBB(targetPos)).any()) {
|
||||
return FAIL
|
||||
}
|
||||
|
||||
world.addEntity(EntityTokenHolder(world, targetPos, getTokenType(heldItem), territoryType))
|
||||
world.addEntity(EntityTokenHolder(world, targetPos, getTokenType(item), territoryType))
|
||||
return SUCCESS
|
||||
}
|
||||
|
||||
|
||||
@@ -1,6 +1,7 @@
|
||||
package chylex.hee.game.item
|
||||
|
||||
import chylex.hee.game.block.entity.TileEntityMinersBurialAltar
|
||||
import chylex.hee.game.item.components.UseOnBlockComponent
|
||||
import chylex.hee.game.world.BlockEditor
|
||||
import chylex.hee.game.world.getTile
|
||||
import chylex.hee.game.world.playUniversal
|
||||
@@ -8,33 +9,34 @@ import chylex.hee.init.ModSounds
|
||||
import chylex.hee.system.migration.ActionResult.FAIL
|
||||
import chylex.hee.system.migration.ActionResult.PASS
|
||||
import chylex.hee.system.migration.ActionResult.SUCCESS
|
||||
import net.minecraft.item.Item
|
||||
import chylex.hee.system.migration.EntityPlayer
|
||||
import net.minecraft.item.ItemStack
|
||||
import net.minecraft.item.ItemUseContext
|
||||
import net.minecraft.util.ActionResultType
|
||||
import net.minecraft.util.SoundCategory
|
||||
import net.minecraft.util.math.BlockPos
|
||||
import net.minecraft.world.World
|
||||
|
||||
class ItemPuzzleMedallion(properties: Properties) : Item(properties) {
|
||||
override fun onItemUse(context: ItemUseContext): ActionResultType {
|
||||
val player = context.player ?: return FAIL
|
||||
val world = context.world
|
||||
val pos = context.pos
|
||||
|
||||
val heldItem = player.getHeldItem(context.hand)
|
||||
|
||||
if (!BlockEditor.canEdit(pos, player, heldItem)) {
|
||||
return FAIL
|
||||
}
|
||||
|
||||
val tile = pos.getTile<TileEntityMinersBurialAltar>(world)
|
||||
|
||||
if (tile != null && !tile.hasMedallion) {
|
||||
tile.hasMedallion = true
|
||||
heldItem.shrink(1)
|
||||
|
||||
ModSounds.ITEM_PUZZLE_MEDALLION_INSERT.playUniversal(player, pos, SoundCategory.BLOCKS, volume = 2F, pitch = 0.8F)
|
||||
return SUCCESS
|
||||
}
|
||||
|
||||
return PASS
|
||||
class ItemPuzzleMedallion(properties: Properties) : ItemWithComponents(properties) {
|
||||
init {
|
||||
components.attach(object : UseOnBlockComponent {
|
||||
override fun useOnBlock(world: World, pos: BlockPos, player: EntityPlayer, item: ItemStack, ctx: ItemUseContext): ActionResultType {
|
||||
if (!BlockEditor.canEdit(pos, player, item)) {
|
||||
return FAIL
|
||||
}
|
||||
|
||||
val tile = pos.getTile<TileEntityMinersBurialAltar>(world)
|
||||
|
||||
if (tile != null && !tile.hasMedallion) {
|
||||
tile.hasMedallion = true
|
||||
item.shrink(1)
|
||||
|
||||
ModSounds.ITEM_PUZZLE_MEDALLION_INSERT.playUniversal(player, pos, SoundCategory.BLOCKS, volume = 2F, pitch = 0.8F)
|
||||
return SUCCESS
|
||||
}
|
||||
|
||||
return PASS
|
||||
}
|
||||
})
|
||||
}
|
||||
}
|
||||
|
||||
@@ -3,6 +3,7 @@ package chylex.hee.game.item
|
||||
import chylex.hee.client.model.ModelHelper
|
||||
import chylex.hee.game.block.entity.TileEntityEnergyCluster
|
||||
import chylex.hee.game.entity.item.EntityItemRevitalizationSubstance
|
||||
import chylex.hee.game.item.components.UseOnBlockComponent
|
||||
import chylex.hee.game.mechanics.energy.IClusterHealth.HealthOverride.REVITALIZING
|
||||
import chylex.hee.game.particle.ParticleSmokeCustom
|
||||
import chylex.hee.game.particle.spawner.ParticleSpawnerCustom
|
||||
@@ -26,7 +27,6 @@ import chylex.hee.system.serialization.readPos
|
||||
import chylex.hee.system.serialization.use
|
||||
import chylex.hee.system.serialization.writePos
|
||||
import net.minecraft.entity.Entity
|
||||
import net.minecraft.item.Item
|
||||
import net.minecraft.item.ItemStack
|
||||
import net.minecraft.item.ItemUseContext
|
||||
import net.minecraft.network.PacketBuffer
|
||||
@@ -37,7 +37,7 @@ import net.minecraft.util.math.BlockPos
|
||||
import net.minecraft.world.World
|
||||
import java.util.Random
|
||||
|
||||
class ItemRevitalizationSubstance(properties: Properties) : Item(properties) {
|
||||
class ItemRevitalizationSubstance(properties: Properties) : ItemWithComponents(properties), UseOnBlockComponent {
|
||||
companion object {
|
||||
private val PARTICLE_FAIL = ParticleSpawnerCustom(
|
||||
type = ParticleSmokeCustom,
|
||||
@@ -70,11 +70,11 @@ class ItemRevitalizationSubstance(properties: Properties) : Item(properties) {
|
||||
}
|
||||
}
|
||||
|
||||
override fun onItemUse(context: ItemUseContext): ActionResultType {
|
||||
val player = context.player ?: return FAIL
|
||||
val world = context.world
|
||||
val pos = context.pos
|
||||
|
||||
init {
|
||||
components.attach(this)
|
||||
}
|
||||
|
||||
override fun useOnBlock(world: World, pos: BlockPos, player: EntityPlayer, item: ItemStack, ctx: ItemUseContext): ActionResultType? {
|
||||
if (world.isRemote) {
|
||||
return FAIL // disable animation
|
||||
}
|
||||
@@ -83,11 +83,11 @@ class ItemRevitalizationSubstance(properties: Properties) : Item(properties) {
|
||||
|
||||
if (cluster.currentHealth != REVITALIZING) {
|
||||
if (cluster.addRevitalizationSubstance()) {
|
||||
player.getHeldItem(context.hand).shrink(1)
|
||||
player.getHeldItem(ctx.hand).shrink(1)
|
||||
ModSounds.ITEM_REVITALIZATION_SUBSTANCE_USE_SUCCESS.playServer(world, pos, SoundCategory.BLOCKS, volume = 0.5F)
|
||||
}
|
||||
else {
|
||||
PacketClientFX(FX_FAIL, FxUseData(pos, player, context.hand)).sendToAllAround(player, 24.0)
|
||||
PacketClientFX(FX_FAIL, FxUseData(pos, player, ctx.hand)).sendToAllAround(player, 24.0)
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -2,33 +2,33 @@ package chylex.hee.game.item
|
||||
|
||||
import chylex.hee.game.block.BlockAbstractTableTile
|
||||
import chylex.hee.game.block.BlockTableBase
|
||||
import chylex.hee.game.item.components.UseOnBlockComponent
|
||||
import chylex.hee.game.world.BlockEditor
|
||||
import chylex.hee.game.world.breakBlock
|
||||
import chylex.hee.game.world.getBlock
|
||||
import chylex.hee.game.world.setBlock
|
||||
import chylex.hee.system.forge.Side
|
||||
import chylex.hee.system.forge.Sided
|
||||
import chylex.hee.system.migration.EntityPlayer
|
||||
import net.minecraft.client.util.ITooltipFlag
|
||||
import net.minecraft.item.Item
|
||||
import net.minecraft.item.ItemStack
|
||||
import net.minecraft.item.ItemUseContext
|
||||
import net.minecraft.util.ActionResultType
|
||||
import net.minecraft.util.ActionResultType.FAIL
|
||||
import net.minecraft.util.ActionResultType.PASS
|
||||
import net.minecraft.util.ActionResultType.SUCCESS
|
||||
import net.minecraft.util.math.BlockPos
|
||||
import net.minecraft.util.text.ITextComponent
|
||||
import net.minecraft.util.text.TranslationTextComponent
|
||||
import net.minecraft.world.World
|
||||
|
||||
class ItemTableCore(private val tableBlocks: Array<BlockAbstractTableTile<*>>, properties: Properties) : Item(properties) {
|
||||
override fun onItemUse(context: ItemUseContext): ActionResultType {
|
||||
val player = context.player ?: return FAIL
|
||||
val world = context.world
|
||||
val pos = context.pos
|
||||
|
||||
val heldItem = player.getHeldItem(context.hand)
|
||||
|
||||
if (!BlockEditor.canEdit(pos, player, heldItem)) {
|
||||
class ItemTableCore(private val tableBlocks: Array<BlockAbstractTableTile<*>>, properties: Properties) : ItemWithComponents(properties), UseOnBlockComponent {
|
||||
init {
|
||||
components.attach(this)
|
||||
}
|
||||
|
||||
override fun useOnBlock(world: World, pos: BlockPos, player: EntityPlayer, item: ItemStack, ctx: ItemUseContext): ActionResultType {
|
||||
if (!BlockEditor.canEdit(pos, player, item)) {
|
||||
return FAIL
|
||||
}
|
||||
|
||||
@@ -42,7 +42,7 @@ class ItemTableCore(private val tableBlocks: Array<BlockAbstractTableTile<*>>, p
|
||||
pos.setBlock(world, table)
|
||||
}
|
||||
|
||||
heldItem.shrink(1)
|
||||
item.shrink(1)
|
||||
return SUCCESS
|
||||
}
|
||||
|
||||
|
||||
@@ -12,6 +12,7 @@ import chylex.hee.game.item.ItemTableLink.Companion.SoundType.LINK_FAIL
|
||||
import chylex.hee.game.item.ItemTableLink.Companion.SoundType.LINK_OUTPUT
|
||||
import chylex.hee.game.item.ItemTableLink.Companion.SoundType.LINK_RESTART
|
||||
import chylex.hee.game.item.ItemTableLink.Companion.SoundType.LINK_SUCCESS
|
||||
import chylex.hee.game.item.components.UseOnBlockComponent
|
||||
import chylex.hee.game.world.getBlock
|
||||
import chylex.hee.game.world.getTile
|
||||
import chylex.hee.game.world.playClient
|
||||
@@ -26,6 +27,7 @@ import chylex.hee.system.forge.Sided
|
||||
import chylex.hee.system.migration.ActionResult.FAIL
|
||||
import chylex.hee.system.migration.ActionResult.SUCCESS
|
||||
import chylex.hee.system.migration.EntityItem
|
||||
import chylex.hee.system.migration.EntityPlayer
|
||||
import chylex.hee.system.random.nextFloat
|
||||
import chylex.hee.system.serialization.getPos
|
||||
import chylex.hee.system.serialization.hasKey
|
||||
@@ -34,7 +36,6 @@ import chylex.hee.system.serialization.readPos
|
||||
import chylex.hee.system.serialization.use
|
||||
import chylex.hee.system.serialization.writePos
|
||||
import net.minecraft.entity.Entity
|
||||
import net.minecraft.item.Item
|
||||
import net.minecraft.item.ItemStack
|
||||
import net.minecraft.item.ItemUseContext
|
||||
import net.minecraft.network.PacketBuffer
|
||||
@@ -44,7 +45,7 @@ import net.minecraft.util.math.BlockPos
|
||||
import net.minecraft.world.World
|
||||
import java.util.Random
|
||||
|
||||
class ItemTableLink(properties: Properties) : Item(properties) {
|
||||
class ItemTableLink(properties: Properties) : ItemWithComponents(properties), UseOnBlockComponent {
|
||||
companion object {
|
||||
private const val POS_TAG = "StoredPos"
|
||||
private const val TIME_TAG = "StoredTime"
|
||||
@@ -106,11 +107,11 @@ class ItemTableLink(properties: Properties) : Item(properties) {
|
||||
}
|
||||
}
|
||||
|
||||
override fun onItemUse(context: ItemUseContext): ActionResultType {
|
||||
val player = context.player ?: return FAIL
|
||||
val world = context.world
|
||||
val pos = context.pos
|
||||
|
||||
init {
|
||||
components.attach(this)
|
||||
}
|
||||
|
||||
override fun useOnBlock(world: World, pos: BlockPos, player: EntityPlayer, item: ItemStack, ctx: ItemUseContext): ActionResultType? {
|
||||
if (!player.isSneaking || !isValidTarget(world, pos)) {
|
||||
val pedestal = pos.getTile<TileEntityTablePedestal>(world)
|
||||
|
||||
@@ -131,7 +132,7 @@ class ItemTableLink(properties: Properties) : Item(properties) {
|
||||
return SUCCESS
|
||||
}
|
||||
|
||||
val heldItem = player.getHeldItem(context.hand)
|
||||
val heldItem = player.getHeldItem(ctx.hand)
|
||||
var newStoredPos = pos
|
||||
var soundType = LINK_RESTART
|
||||
|
||||
|
||||
@@ -21,6 +21,7 @@ import chylex.hee.game.world.structure.trigger.EntityStructureTrigger
|
||||
import chylex.hee.game.world.territory.TerritoryType
|
||||
import chylex.hee.init.ModBlocks
|
||||
import chylex.hee.network.client.PacketClientFX
|
||||
import chylex.hee.network.fx.FxVecData
|
||||
import chylex.hee.system.facades.Facing4
|
||||
import chylex.hee.system.math.addY
|
||||
import chylex.hee.system.math.offsetTowards
|
||||
@@ -145,9 +146,8 @@ abstract class ObsidianTowerLevel_Top(file: String) : ObsidianTowerLevel_General
|
||||
|
||||
val offsetProgress = chargeAnim.pow(0.8F).toDouble()
|
||||
val particlePos = start.center.offsetTowards(tokenHolder.posVec.addY(tokenHolder.height * 0.5), offsetProgress).addY(progressCurvePoint * 6.0)
|
||||
val particleData = EnderEyeSpawnerParticles.Companion.ParticleData(particlePos)
|
||||
|
||||
PacketClientFX(EnderEyeSpawnerParticles.FX_PARTICLE, particleData).sendToAllAround(entity.world, pos, 256.0)
|
||||
PacketClientFX(EnderEyeSpawnerParticles.FX_PARTICLE, FxVecData(particlePos)).sendToAllAround(entity.world, pos, 256.0)
|
||||
}
|
||||
|
||||
if (chargeAnim == 1F) {
|
||||
|
||||
@@ -1,5 +1,7 @@
|
||||
package chylex.hee.game.world.feature.tombdungeon
|
||||
|
||||
import chylex.hee.game.world.feature.tombdungeon.TombDungeonLevel.MobAmount.HIGH
|
||||
import chylex.hee.game.world.feature.tombdungeon.TombDungeonLevel.MobAmount.MEDIUM
|
||||
import chylex.hee.game.world.feature.tombdungeon.TombDungeonPieces.PIECE_TOMB_RANDOM_MASS_5X_BASIC
|
||||
import chylex.hee.game.world.feature.tombdungeon.TombDungeonPieces.PIECE_TOMB_RANDOM_MASS_5X_BORDER
|
||||
import chylex.hee.game.world.feature.tombdungeon.TombDungeonPieces.PIECE_TOMB_RANDOM_MASS_5X_SPLIT
|
||||
@@ -19,6 +21,7 @@ import chylex.hee.game.world.feature.tombdungeon.piece.TombDungeonAbstractPiece
|
||||
import chylex.hee.system.math.floorToInt
|
||||
import chylex.hee.system.random.nextFloat
|
||||
import chylex.hee.system.random.nextInt
|
||||
import chylex.hee.system.random.nextRounded
|
||||
import java.util.Random
|
||||
import kotlin.math.max
|
||||
import kotlin.math.min
|
||||
@@ -101,4 +104,46 @@ enum class TombDungeonLevel(val isFancy: Boolean, private val corridorFactor: In
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
fun pickUndreadAndSpiderlingSpawns(rand: Random, amount: MobAmount): Pair<Int, Int> {
|
||||
val m = if (amount >= MEDIUM) 1 else 0
|
||||
val h = if (amount >= HIGH) 1 else 0
|
||||
|
||||
return when(this) {
|
||||
FIRST -> when(rand.nextInt(0, 3)) {
|
||||
0 -> MOBS(undreads = rand.nextRounded(0.2F), spiderlings = 1 + m + rand.nextInt(0, h))
|
||||
1 -> MOBS(undreads = rand.nextRounded(0.3F * m), spiderlings = 1 + h + rand.nextInt(0, m))
|
||||
2 -> MOBS(undreads = rand.nextRounded(0.3F * h), spiderlings = 2 + m)
|
||||
else -> MOBS(undreads = 0, spiderlings = 1 + rand.nextInt(0, 1 + m))
|
||||
}
|
||||
|
||||
SECOND -> when(rand.nextInt(0, 3)) {
|
||||
0 -> MOBS(undreads = rand.nextRounded(0.3F), spiderlings = 1 + m + rand.nextInt(0, h))
|
||||
1 -> MOBS(undreads = rand.nextRounded(0.4F * m), spiderlings = 1 + rand.nextInt(0, 2 * m))
|
||||
else -> MOBS(undreads = 0, spiderlings = rand.nextRounded(1.8F + (m * 0.55F) + (h * 0.55F)))
|
||||
}
|
||||
|
||||
THIRD -> when(rand.nextInt(0, 2)) {
|
||||
0 -> MOBS(undreads = rand.nextInt(0, 1 + h), spiderlings = rand.nextRounded(1.4F + (m * 0.5F)) + rand.nextInt(0, m))
|
||||
1 -> MOBS(undreads = rand.nextInt(0, 1 + m), spiderlings = rand.nextRounded(1.2F) + rand.nextInt(0, 2 * h))
|
||||
else -> MOBS(undreads = rand.nextInt(0, 1 + m), spiderlings = 2 + rand.nextInt(0, m + h))
|
||||
}
|
||||
|
||||
FOURTH -> when(rand.nextInt(0, 5)) {
|
||||
in 0..1 -> MOBS(undreads = 1 + rand.nextInt(h, 3 + h), spiderlings = rand.nextRounded(0.4F * m) + rand.nextInt(0, m + h))
|
||||
else -> MOBS(undreads = 2 + rand.nextInt(m, 2 * m), spiderlings = rand.nextRounded(0.3F + (m * 0.1F) + (h * 0.3F)))
|
||||
}
|
||||
|
||||
else -> when(rand.nextInt(0, 2)) {
|
||||
0 -> MOBS(undreads = 1 + h + rand.nextInt(m, 1 + (m * 2)) + rand.nextInt(h, 1 + h), spiderlings = rand.nextInt(0, m))
|
||||
else -> MOBS(undreads = 2 + h + rand.nextInt(m, 2 * m), spiderlings = rand.nextRounded(0.2F + (m * 0.2F)))
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
private fun MOBS(undreads: Int, spiderlings: Int) = undreads to spiderlings
|
||||
|
||||
enum class MobAmount {
|
||||
LOW, MEDIUM, HIGH
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1,10 +1,57 @@
|
||||
package chylex.hee.game.world.feature.tombdungeon.piece
|
||||
|
||||
import chylex.hee.game.block.BlockGraveDirt
|
||||
import chylex.hee.game.entity.living.EntityMobSpiderling
|
||||
import chylex.hee.game.entity.living.EntityMobUndread
|
||||
import chylex.hee.game.entity.posVec
|
||||
import chylex.hee.game.entity.selectExistingEntities
|
||||
import chylex.hee.game.entity.selectVulnerableEntities
|
||||
import chylex.hee.game.entity.technical.EntityTechnicalTrigger
|
||||
import chylex.hee.game.entity.technical.EntityTechnicalTrigger.ITriggerHandler
|
||||
import chylex.hee.game.entity.technical.EntityTechnicalTrigger.Types.TOMB_DUNGEON_UNDREAD_SPAWNER
|
||||
import chylex.hee.game.world.Pos
|
||||
import chylex.hee.game.world.distanceSqTo
|
||||
import chylex.hee.game.world.feature.tombdungeon.TombDungeonLevel
|
||||
import chylex.hee.game.world.feature.tombdungeon.TombDungeonLevel.MobAmount
|
||||
import chylex.hee.game.world.feature.tombdungeon.connection.TombDungeonConnection
|
||||
import chylex.hee.game.world.feature.tombdungeon.connection.TombDungeonConnectionType.TOMB_ENTRANCE_INSIDE
|
||||
import chylex.hee.game.world.getBlock
|
||||
import chylex.hee.game.world.getState
|
||||
import chylex.hee.game.world.isAir
|
||||
import chylex.hee.game.world.offsetWhile
|
||||
import chylex.hee.game.world.playClient
|
||||
import chylex.hee.game.world.structure.IStructureWorld
|
||||
import chylex.hee.game.world.structure.piece.IStructurePieceConnection
|
||||
import chylex.hee.game.world.structure.trigger.EntityStructureTrigger
|
||||
import chylex.hee.init.ModEntities
|
||||
import chylex.hee.network.client.PacketClientFX
|
||||
import chylex.hee.network.fx.FxVecData
|
||||
import chylex.hee.network.fx.FxVecHandler
|
||||
import chylex.hee.system.math.Vec
|
||||
import chylex.hee.system.math.Vec3
|
||||
import chylex.hee.system.math.addY
|
||||
import chylex.hee.system.math.directionTowards
|
||||
import chylex.hee.system.math.square
|
||||
import chylex.hee.system.math.toYaw
|
||||
import chylex.hee.system.migration.BlockWeb
|
||||
import chylex.hee.system.migration.EntityLivingBase
|
||||
import chylex.hee.system.migration.EntityPlayer
|
||||
import chylex.hee.system.migration.Facing.DOWN
|
||||
import chylex.hee.system.migration.Facing.NORTH
|
||||
import chylex.hee.system.migration.Facing.SOUTH
|
||||
import chylex.hee.system.random.nextFloat
|
||||
import chylex.hee.system.random.nextInt
|
||||
import chylex.hee.system.random.nextItem
|
||||
import chylex.hee.system.serialization.TagCompound
|
||||
import chylex.hee.system.serialization.use
|
||||
import net.minecraft.entity.EntitySpawnPlacementRegistry
|
||||
import net.minecraft.entity.SpawnReason.STRUCTURE
|
||||
import net.minecraft.util.Direction.Axis
|
||||
import net.minecraft.util.math.AxisAlignedBB
|
||||
import net.minecraft.util.math.BlockPos
|
||||
import net.minecraft.util.math.Vec3d
|
||||
import net.minecraft.world.World
|
||||
import java.util.Random
|
||||
|
||||
abstract class TombDungeonRoom_Tomb(file: String, entranceY: Int, allowSecrets: Boolean, isFancy: Boolean) : TombDungeonRoom(file, isFancy) {
|
||||
final override val secretAttachWeight = if (allowSecrets) 2 else 0
|
||||
@@ -13,4 +60,176 @@ abstract class TombDungeonRoom_Tomb(file: String, entranceY: Int, allowSecrets:
|
||||
final override val connections = arrayOf<IStructurePieceConnection>(
|
||||
TombDungeonConnection(TOMB_ENTRANCE_INSIDE, Pos(centerX, entranceY, maxZ), SOUTH)
|
||||
)
|
||||
|
||||
override fun generate(world: IStructureWorld, instance: Instance) {
|
||||
super.generate(world, instance)
|
||||
generateSpawnerTrigger(world, instance)
|
||||
}
|
||||
|
||||
protected open fun generateSpawnerTrigger(world: IStructureWorld, instance: Instance) {
|
||||
val rand = world.rand
|
||||
val level = instance.context ?: return
|
||||
val mobAmount = getSpawnerTriggerMobAmount(rand, level) ?: return
|
||||
|
||||
val (undreads, spiderlings) = level.pickUndreadAndSpiderlingSpawns(rand, mobAmount)
|
||||
MobSpawnerTrigger.place(world, entrance = connections.first().offset, width = maxX, depth = maxZ, undreads, spiderlings)
|
||||
}
|
||||
|
||||
protected abstract fun getSpawnerTriggerMobAmount(rand: Random, level: TombDungeonLevel): MobAmount?
|
||||
|
||||
class MobSpawnerTrigger() : ITriggerHandler {
|
||||
companion object {
|
||||
private const val WIDTH_TAG = "Width"
|
||||
private const val DEPTH_TAG = "Depth"
|
||||
private const val UNDREADS_TAG = "Undreads"
|
||||
private const val SPIDERLINGS_TAG = "Spiderlings"
|
||||
|
||||
fun place(world: IStructureWorld, entrance: BlockPos, width: Int, depth: Int, undreads: Int, spiderlings: Int) {
|
||||
val nbt = MobSpawnerTrigger(width - 1.0, depth - 1.0, undreads, spiderlings).serializeNBT()
|
||||
|
||||
world.addTrigger(entrance, EntityStructureTrigger({ wrld ->
|
||||
EntityTechnicalTrigger(wrld, TOMB_DUNGEON_UNDREAD_SPAWNER, nbt).apply { rotationYaw = NORTH.horizontalAngle }
|
||||
}, yOffset = 0.5))
|
||||
}
|
||||
|
||||
val FX_SPAWN_UNDREAD = object : FxVecHandler() {
|
||||
override fun handle(world: World, rand: Random, vec: Vec3d) {
|
||||
EntityMobUndread(world).apply {
|
||||
setLocationAndAngles(vec.x, vec.y, vec.z, 0F, 0F)
|
||||
spawnExplosionParticle()
|
||||
deathSound.playClient(vec, soundCategory, volume = 1.2F, pitch = soundPitch * 0.7F)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
val FX_SPAWN_SPIDERLING = object : FxVecHandler() {
|
||||
override fun handle(world: World, rand: Random, vec: Vec3d) {
|
||||
EntityMobSpiderling(world).apply {
|
||||
setLocationAndAngles(vec.x, vec.y, vec.z, 0F, 0F)
|
||||
spawnExplosionParticle()
|
||||
ambientSound.playClient(vec, soundCategory, volume = 1F, pitch = soundPitch)
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
private var width = 0.0
|
||||
private var depth = 0.0
|
||||
private var undreads = 0
|
||||
private var spiderlings = 0
|
||||
|
||||
constructor(width: Double, depth: Double, undreads: Int, spiderlings: Int) : this() {
|
||||
this.width = width
|
||||
this.depth = depth
|
||||
this.undreads = undreads
|
||||
this.spiderlings = spiderlings
|
||||
}
|
||||
|
||||
override fun check(world: World): Boolean {
|
||||
return !world.isRemote
|
||||
}
|
||||
|
||||
override fun update(entity: EntityTechnicalTrigger) {
|
||||
val world = entity.world
|
||||
val facing = entity.horizontalFacing
|
||||
val vecF = Vec3.fromYaw(facing.horizontalAngle)
|
||||
val vecL = Vec3.fromYaw(facing.rotateYCCW().horizontalAngle)
|
||||
val vecR = Vec3.fromYaw(facing.rotateY().horizontalAngle)
|
||||
|
||||
val aabb = AxisAlignedBB(
|
||||
vecL.scale(width * 0.5).add(vecF.scale(0.3)),
|
||||
vecR.scale(width * 0.5).add(vecF.scale(depth)).addY(2.5)
|
||||
).offset(entity.posVec)
|
||||
|
||||
val nearbyPlayers = world.selectVulnerableEntities.inBox<EntityPlayer>(aabb)
|
||||
if (nearbyPlayers.isEmpty()) {
|
||||
return
|
||||
}
|
||||
|
||||
val rand = world.rand
|
||||
val minPlayerDist = ((depth * 0.4) + (width * 0.16)).coerceIn(1.5, 3.5)
|
||||
|
||||
for((entityCount, entityType, spawnParticle) in listOf(
|
||||
Triple(undreads, ModEntities.UNDREAD, FX_SPAWN_UNDREAD),
|
||||
Triple(spiderlings, ModEntities.SPIDERLING, FX_SPAWN_SPIDERLING)
|
||||
)) {
|
||||
repeat(entityCount) {
|
||||
var bestPos: BlockPos? = null
|
||||
|
||||
for(attempt in 1..75) {
|
||||
val pos = Pos(
|
||||
rand.nextFloat(aabb.minX, aabb.maxX),
|
||||
rand.nextFloat(aabb.minY, aabb.maxY) + 0.5,
|
||||
rand.nextFloat(aabb.minZ, aabb.maxZ),
|
||||
).offsetWhile(DOWN, 1..3) {
|
||||
it.isAir(world) || it.getBlock(world) is BlockWeb
|
||||
}
|
||||
|
||||
val collisionCheckAABB = entityType.getBoundingBoxWithSizeApplied(pos.x + 0.5, pos.y.toDouble(), pos.z + 0.5).grow(0.2, 0.0, 0.2)
|
||||
|
||||
if (EntitySpawnPlacementRegistry.func_223515_a(entityType, world, STRUCTURE, pos, rand) &&
|
||||
world.hasNoCollisions(collisionCheckAABB) &&
|
||||
world.selectExistingEntities.inBox<EntityLivingBase>(collisionCheckAABB.grow(0.4, 0.0, 0.4)).isEmpty() &&
|
||||
world.players.none { pos.distanceSqTo(it) < square(minPlayerDist) }
|
||||
) {
|
||||
bestPos = pos
|
||||
|
||||
if (entityType === ModEntities.UNDREAD) {
|
||||
if (rand.nextInt(5) == 0 || pos.down().getBlock(world) is BlockGraveDirt) {
|
||||
break
|
||||
}
|
||||
}
|
||||
else {
|
||||
break
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if (bestPos != null) {
|
||||
val x = bestPos.x + rand.nextFloat(0.35, 0.65)
|
||||
val y = bestPos.y + bestPos.down().getState(world).getCollisionShape(world, bestPos).getEnd(Axis.Y) - 1.0
|
||||
val z = bestPos.z + rand.nextFloat(0.35, 0.65)
|
||||
val vec = Vec(x, y, z)
|
||||
val target = rand.nextItem(nearbyPlayers)
|
||||
|
||||
entityType.create(world)?.apply {
|
||||
setLocationAndAngles(x, y, z, vec.directionTowards(target.posVec).toYaw(), 0F)
|
||||
rotationYawHead = rotationYaw
|
||||
attackTarget = target
|
||||
onGround = true // allow instant pathfinding in MeleeAttackGoal
|
||||
|
||||
if (this is EntityMobSpiderling) {
|
||||
wakeUp(preventSleep = true, aiDelayTicks = if (rand.nextInt(10) == 0) rand.nextInt(4, 6) else rand.nextInt(11, 18))
|
||||
}
|
||||
|
||||
onInitialSpawn(world, world.getDifficultyForLocation(bestPos), STRUCTURE, null, null)
|
||||
world.addEntity(this)
|
||||
|
||||
PacketClientFX(spawnParticle, FxVecData(vec)).sendToAllAround(this, 24.0)
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
entity.remove()
|
||||
}
|
||||
|
||||
override fun nextTimer(rand: Random): Int {
|
||||
return 3
|
||||
}
|
||||
|
||||
override fun serializeNBT() = TagCompound().apply {
|
||||
putDouble(WIDTH_TAG, width)
|
||||
putDouble(DEPTH_TAG, depth)
|
||||
putInt(UNDREADS_TAG, undreads)
|
||||
putInt(SPIDERLINGS_TAG, spiderlings)
|
||||
}
|
||||
|
||||
override fun deserializeNBT(nbt: TagCompound) = nbt.use {
|
||||
width = getDouble(WIDTH_TAG)
|
||||
depth = getDouble(DEPTH_TAG)
|
||||
undreads = getInt(UNDREADS_TAG)
|
||||
spiderlings = getInt(SPIDERLINGS_TAG)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -2,9 +2,12 @@ package chylex.hee.game.world.feature.tombdungeon.piece
|
||||
|
||||
import chylex.hee.game.block.BlockGraveDirt
|
||||
import chylex.hee.game.world.Pos
|
||||
import chylex.hee.game.world.feature.tombdungeon.TombDungeonLevel
|
||||
import chylex.hee.game.world.feature.tombdungeon.TombDungeonLevel.MobAmount
|
||||
import chylex.hee.game.world.feature.tombdungeon.TombDungeonPieces
|
||||
import chylex.hee.game.world.feature.tombdungeon.connection.TombDungeonConnection
|
||||
import chylex.hee.game.world.feature.tombdungeon.connection.TombDungeonConnectionType.TOMB_ENTRANCE_INSIDE
|
||||
import chylex.hee.game.world.feature.tombdungeon.piece.TombDungeonRoom_Tomb.MobSpawnerTrigger
|
||||
import chylex.hee.game.world.generation.IBlockPicker.Single
|
||||
import chylex.hee.game.world.generation.IBlockPicker.Single.Air
|
||||
import chylex.hee.game.world.math.Size
|
||||
@@ -32,6 +35,8 @@ class TombDungeonRoom_Tomb_Mass(width: Int, depth: Int, private val border: Bool
|
||||
super.generate(world, instance)
|
||||
|
||||
val rand = world.rand
|
||||
val level = instance.context
|
||||
|
||||
val centerX = size.centerX
|
||||
val maxX = size.maxX
|
||||
val maxY = size.maxY
|
||||
@@ -56,8 +61,21 @@ class TombDungeonRoom_Tomb_Mass(width: Int, depth: Int, private val border: Bool
|
||||
|
||||
if (rand.nextInt(6) == 0 && (border || split)) {
|
||||
placeJars(world, instance, listOf(Pos(centerX, 2, 1)))
|
||||
|
||||
if (level != null && rand.nextInt(9) != 0) {
|
||||
placeSpawnerTrigger(world, level)
|
||||
}
|
||||
}
|
||||
else if (level != null && rand.nextInt(3) != 0) {
|
||||
placeSpawnerTrigger(world, level)
|
||||
}
|
||||
|
||||
placeCobwebs(world, instance)
|
||||
}
|
||||
|
||||
private fun placeSpawnerTrigger(world: IStructureWorld, level: TombDungeonLevel) {
|
||||
val area = (size.x - 2) * (size.z - 2)
|
||||
val (undreads, spiderlings) = level.pickUndreadAndSpiderlingSpawns(world.rand, if (area <= 30) MobAmount.LOW else MobAmount.MEDIUM)
|
||||
MobSpawnerTrigger.place(world, entrance = connections.first().offset, width = size.maxX, depth = size.maxZ, undreads, spiderlings)
|
||||
}
|
||||
}
|
||||
|
||||
@@ -2,9 +2,11 @@ package chylex.hee.game.world.feature.tombdungeon.piece
|
||||
|
||||
import chylex.hee.game.world.Pos
|
||||
import chylex.hee.game.world.feature.tombdungeon.TombDungeonLevel
|
||||
import chylex.hee.game.world.feature.tombdungeon.TombDungeonLevel.MobAmount
|
||||
import chylex.hee.game.world.structure.IStructureWorld
|
||||
import chylex.hee.system.migration.Facing.NORTH
|
||||
import chylex.hee.system.random.nextInt
|
||||
import java.util.Random
|
||||
|
||||
class TombDungeonRoom_Tomb_MassSpacious(file: String, entranceY: Int, isFancy: Boolean) : TombDungeonRoom_Tomb(file, entranceY, allowSecrets = false, isFancy) {
|
||||
override fun generate(world: IStructureWorld, instance: Instance) {
|
||||
@@ -32,4 +34,8 @@ class TombDungeonRoom_Tomb_MassSpacious(file: String, entranceY: Int, isFancy: B
|
||||
placeJars(world, instance, listOf(Pos(jarX, 3, maxZ - 2)))
|
||||
}
|
||||
}
|
||||
|
||||
override fun getSpawnerTriggerMobAmount(rand: Random, level: TombDungeonLevel): MobAmount? {
|
||||
return MobAmount.HIGH.takeIf { rand.nextInt(11) < (if (level <= TombDungeonLevel.SECOND) 7 else 4) }
|
||||
}
|
||||
}
|
||||
|
||||
@@ -2,11 +2,14 @@ package chylex.hee.game.world.feature.tombdungeon.piece
|
||||
|
||||
import chylex.hee.game.block.BlockGraveDirt
|
||||
import chylex.hee.game.world.Pos
|
||||
import chylex.hee.game.world.feature.tombdungeon.TombDungeonLevel
|
||||
import chylex.hee.game.world.feature.tombdungeon.TombDungeonLevel.MobAmount
|
||||
import chylex.hee.game.world.structure.IStructureWorld
|
||||
import chylex.hee.system.migration.Facing.EAST
|
||||
import chylex.hee.system.migration.Facing.WEST
|
||||
import chylex.hee.system.random.nextInt
|
||||
import chylex.hee.system.random.nextRounded
|
||||
import java.util.Random
|
||||
|
||||
class TombDungeonRoom_Tomb_MultiDeep(file: String, private val tombsPerColumn: Int, entranceY: Int, isFancy: Boolean) : TombDungeonRoom_Tomb(file, entranceY, allowSecrets = false, isFancy) {
|
||||
override fun generate(world: IStructureWorld, instance: Instance) {
|
||||
@@ -37,4 +40,15 @@ class TombDungeonRoom_Tomb_MultiDeep(file: String, private val tombsPerColumn: I
|
||||
})
|
||||
}
|
||||
}
|
||||
|
||||
override fun getSpawnerTriggerMobAmount(rand: Random, level: TombDungeonLevel): MobAmount? {
|
||||
if (rand.nextBoolean()) {
|
||||
return null
|
||||
}
|
||||
|
||||
return when {
|
||||
tombsPerColumn <= 6 -> MobAmount.MEDIUM
|
||||
else -> MobAmount.HIGH
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1,7 +1,10 @@
|
||||
package chylex.hee.game.world.feature.tombdungeon.piece
|
||||
|
||||
import chylex.hee.game.world.Pos
|
||||
import chylex.hee.game.world.feature.tombdungeon.TombDungeonLevel
|
||||
import chylex.hee.game.world.feature.tombdungeon.TombDungeonLevel.MobAmount
|
||||
import chylex.hee.game.world.structure.IStructureWorld
|
||||
import java.util.Random
|
||||
|
||||
class TombDungeonRoom_Tomb_MultiNarrow(file: String, private val tombsPerColumn: Int, entranceY: Int, isFancy: Boolean) : TombDungeonRoom_Tomb(file, entranceY, allowSecrets = false, isFancy) {
|
||||
override fun generate(world: IStructureWorld, instance: Instance) {
|
||||
@@ -18,4 +21,16 @@ class TombDungeonRoom_Tomb_MultiNarrow(file: String, private val tombsPerColumn:
|
||||
})
|
||||
}
|
||||
}
|
||||
|
||||
override fun getSpawnerTriggerMobAmount(rand: Random, level: TombDungeonLevel): MobAmount? {
|
||||
if (rand.nextInt(10) >= if (level.isFancy) 3 else 5) {
|
||||
return null
|
||||
}
|
||||
|
||||
return when {
|
||||
tombsPerColumn <= 4 -> MobAmount.LOW
|
||||
tombsPerColumn <= 6 -> MobAmount.MEDIUM
|
||||
else -> MobAmount.HIGH
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -2,11 +2,14 @@ package chylex.hee.game.world.feature.tombdungeon.piece
|
||||
|
||||
import chylex.hee.game.block.BlockGraveDirt
|
||||
import chylex.hee.game.world.Pos
|
||||
import chylex.hee.game.world.feature.tombdungeon.TombDungeonLevel
|
||||
import chylex.hee.game.world.feature.tombdungeon.TombDungeonLevel.MobAmount
|
||||
import chylex.hee.game.world.structure.IStructureWorld
|
||||
import chylex.hee.system.migration.Facing.EAST
|
||||
import chylex.hee.system.migration.Facing.WEST
|
||||
import chylex.hee.system.random.nextInt
|
||||
import chylex.hee.system.random.nextRounded
|
||||
import java.util.Random
|
||||
|
||||
class TombDungeonRoom_Tomb_MultiSpacious(file: String, private val tombsPerColumn: Int, entranceY: Int, isFancy: Boolean) : TombDungeonRoom_Tomb(file, entranceY, allowSecrets = false, isFancy) {
|
||||
override fun generate(world: IStructureWorld, instance: Instance) {
|
||||
@@ -37,4 +40,15 @@ class TombDungeonRoom_Tomb_MultiSpacious(file: String, private val tombsPerColum
|
||||
})
|
||||
}
|
||||
}
|
||||
|
||||
override fun getSpawnerTriggerMobAmount(rand: Random, level: TombDungeonLevel): MobAmount? {
|
||||
if (rand.nextInt(10) >= 6) {
|
||||
return null
|
||||
}
|
||||
|
||||
return when {
|
||||
tombsPerColumn <= 6 -> MobAmount.MEDIUM
|
||||
else -> MobAmount.HIGH
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -0,0 +1,26 @@
|
||||
package chylex.hee.game.world.feature.tombdungeon.piece
|
||||
|
||||
import chylex.hee.game.world.Pos
|
||||
import chylex.hee.game.world.feature.tombdungeon.TombDungeonLevel
|
||||
import chylex.hee.game.world.feature.tombdungeon.TombDungeonLevel.MobAmount
|
||||
import chylex.hee.game.world.structure.IStructureWorld
|
||||
import chylex.hee.system.migration.Facing.SOUTH
|
||||
import java.util.Random
|
||||
|
||||
abstract class TombDungeonRoom_Tomb_Single(file: String, entranceY: Int, isFancy: Boolean) : TombDungeonRoom_Tomb(file, entranceY, allowSecrets = false, isFancy) {
|
||||
override fun generate(world: IStructureWorld, instance: Instance) {
|
||||
super.generate(world, instance)
|
||||
|
||||
if (world.rand.nextInt(10) < 3) {
|
||||
placeChest(world, instance, Pos(centerX, 1, maxZ - 4), SOUTH)
|
||||
}
|
||||
}
|
||||
|
||||
final override fun getSpawnerTriggerMobAmount(rand: Random, level: TombDungeonLevel): MobAmount? {
|
||||
return null
|
||||
}
|
||||
|
||||
protected fun placeSingleTombUndreadSpawner(world: IStructureWorld) {
|
||||
MobSpawnerTrigger.place(world, entrance = connections.first().offset, width = maxX, depth = maxZ, undreads = 1, spiderlings = 0)
|
||||
}
|
||||
}
|
||||
@@ -1,15 +1,13 @@
|
||||
package chylex.hee.game.world.feature.tombdungeon.piece
|
||||
|
||||
import chylex.hee.game.world.Pos
|
||||
import chylex.hee.game.world.structure.IStructureWorld
|
||||
import chylex.hee.system.migration.Facing.SOUTH
|
||||
|
||||
open class TombDungeonRoom_Tomb_SingleNarrow(file: String, entranceY: Int, isFancy: Boolean) : TombDungeonRoom_Tomb(file, entranceY, allowSecrets = false, isFancy) {
|
||||
class TombDungeonRoom_Tomb_SingleNarrow(file: String, entranceY: Int, isFancy: Boolean) : TombDungeonRoom_Tomb_Single(file, entranceY, isFancy) {
|
||||
override fun generate(world: IStructureWorld, instance: Instance) {
|
||||
super.generate(world, instance)
|
||||
|
||||
if (world.rand.nextInt(10) < 3) {
|
||||
placeChest(world, instance, Pos(centerX, 1, maxZ - 4), SOUTH)
|
||||
if (world.rand.nextInt(5) == 0) {
|
||||
placeSingleTombUndreadSpawner(world)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -3,7 +3,7 @@ package chylex.hee.game.world.feature.tombdungeon.piece
|
||||
import chylex.hee.game.world.Pos
|
||||
import chylex.hee.game.world.structure.IStructureWorld
|
||||
|
||||
class TombDungeonRoom_Tomb_SingleSpacious(file: String, entranceY: Int, isFancy: Boolean) : TombDungeonRoom_Tomb_SingleNarrow(file, entranceY, isFancy) {
|
||||
class TombDungeonRoom_Tomb_SingleSpacious(file: String, entranceY: Int, isFancy: Boolean) : TombDungeonRoom_Tomb_Single(file, entranceY, isFancy) {
|
||||
override fun generate(world: IStructureWorld, instance: Instance) {
|
||||
super.generate(world, instance)
|
||||
|
||||
@@ -14,6 +14,11 @@ class TombDungeonRoom_Tomb_SingleSpacious(file: String, entranceY: Int, isFancy:
|
||||
Pos(centerX - 2, 4, if (rand.nextBoolean()) maxZ - 3 else maxZ - 4),
|
||||
Pos(centerX + 2, 4, if (rand.nextBoolean()) maxZ - 3 else maxZ - 4),
|
||||
))
|
||||
|
||||
placeSingleTombUndreadSpawner(world)
|
||||
}
|
||||
else if (rand.nextInt(10) < 4) {
|
||||
placeSingleTombUndreadSpawner(world)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -28,6 +28,7 @@ import chylex.hee.game.item.ItemTableLink
|
||||
import chylex.hee.game.mechanics.scorching.ScorchingHelper
|
||||
import chylex.hee.game.mechanics.table.TableParticleHandler
|
||||
import chylex.hee.game.potion.PotionBanishment
|
||||
import chylex.hee.game.world.feature.tombdungeon.piece.TombDungeonRoom_Tomb
|
||||
import chylex.hee.network.BaseClientPacket
|
||||
import chylex.hee.network.fx.IFxData
|
||||
import chylex.hee.network.fx.IFxHandler
|
||||
@@ -79,7 +80,9 @@ class PacketClientFX<T : IFxData>() : BaseClientPacket() {
|
||||
EnderEyeSpawnerParticles.FX_PARTICLE,
|
||||
EndermanTeleportHandler.FX_TELEPORT_FAIL,
|
||||
EndermanTeleportHandler.FX_TELEPORT_OUT_OF_WORLD,
|
||||
PotionBanishment.FX_BANISH
|
||||
PotionBanishment.FX_BANISH,
|
||||
TombDungeonRoom_Tomb.MobSpawnerTrigger.FX_SPAWN_UNDREAD,
|
||||
TombDungeonRoom_Tomb.MobSpawnerTrigger.FX_SPAWN_SPIDERLING,
|
||||
)
|
||||
}
|
||||
|
||||
|
||||
@@ -0,0 +1,18 @@
|
||||
package chylex.hee.game.item
|
||||
|
||||
import chylex.hee.game.item.components.UseOnBlockComponent
|
||||
import chylex.hee.system.component.EntityComponents
|
||||
import net.minecraft.item.Item
|
||||
import net.minecraft.item.ItemUseContext
|
||||
import net.minecraft.util.ActionResultType
|
||||
import net.minecraft.util.ActionResultType.FAIL
|
||||
import net.minecraft.util.ActionResultType.PASS
|
||||
|
||||
open class ItemWithComponents(properties: Properties) : Item(properties) {
|
||||
val components = EntityComponents()
|
||||
|
||||
final override fun onItemUse(context: ItemUseContext): ActionResultType {
|
||||
val player = context.player ?: return FAIL
|
||||
return components.handle<UseOnBlockComponent, ActionResultType> { useOnBlock(context.world, context.pos, player, context.item, context) } ?: PASS
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,12 @@
|
||||
package chylex.hee.game.item.components
|
||||
|
||||
import chylex.hee.system.migration.EntityPlayer
|
||||
import net.minecraft.item.ItemStack
|
||||
import net.minecraft.item.ItemUseContext
|
||||
import net.minecraft.util.ActionResultType
|
||||
import net.minecraft.util.math.BlockPos
|
||||
import net.minecraft.world.World
|
||||
|
||||
interface UseOnBlockComponent { // TODO use as objects instead of inheriting the interface on Item
|
||||
fun useOnBlock(world: World, pos: BlockPos, player: EntityPlayer, item: ItemStack, ctx: ItemUseContext): ActionResultType?
|
||||
}
|
||||
@@ -10,24 +10,6 @@ class RandomBiasedValueRange(range: ClosedFloatingPointRange<Float>, private val
|
||||
require(highestChanceValue in min..max) { "highestChanceValue must be between min and max" }
|
||||
}
|
||||
|
||||
/*
|
||||
|
||||
import java.util.Random
|
||||
import chylex.hee.system.random.nextBiasedFloat
|
||||
import kotlin.math.roundToInt
|
||||
|
||||
val rand = Random()
|
||||
|
||||
(1..100000).map {
|
||||
val min = 3F
|
||||
val max = 10F
|
||||
val highestChanceValue = 6.5F
|
||||
val biasSoftener = 3F
|
||||
(highestChanceValue + (rand.nextBiasedFloat(biasSoftener) * (0.5F + max - highestChanceValue)) - (rand.nextBiasedFloat(biasSoftener) * (0.5F + highestChanceValue - min))).roundToInt()
|
||||
}.groupBy { it }.mapValues { it.value.size }.toList().sortedBy { it.first }
|
||||
|
||||
*/
|
||||
|
||||
override fun generateInt(rand: Random): Int {
|
||||
return (highestChanceValue + (rand.nextBiasedFloat(biasSoftener) * (0.5F + max - highestChanceValue)) - (rand.nextBiasedFloat(biasSoftener) * (0.5F + highestChanceValue - min))).roundToInt()
|
||||
}
|
||||
|
||||
12
src/system/src/main/java/chylex/hee/network/fx/FxVecData.kt
Normal file
12
src/system/src/main/java/chylex/hee/network/fx/FxVecData.kt
Normal file
@@ -0,0 +1,12 @@
|
||||
package chylex.hee.network.fx
|
||||
|
||||
import chylex.hee.system.serialization.use
|
||||
import chylex.hee.system.serialization.writeVec
|
||||
import net.minecraft.network.PacketBuffer
|
||||
import net.minecraft.util.math.Vec3d
|
||||
|
||||
class FxVecData(private val vec: Vec3d) : IFxData {
|
||||
override fun write(buffer: PacketBuffer) = buffer.use {
|
||||
writeVec(vec)
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,16 @@
|
||||
package chylex.hee.network.fx
|
||||
|
||||
import chylex.hee.system.serialization.readVec
|
||||
import chylex.hee.system.serialization.use
|
||||
import net.minecraft.network.PacketBuffer
|
||||
import net.minecraft.util.math.Vec3d
|
||||
import net.minecraft.world.World
|
||||
import java.util.Random
|
||||
|
||||
abstract class FxVecHandler : IFxHandler<FxVecData> {
|
||||
override fun handle(buffer: PacketBuffer, world: World, rand: Random) = buffer.use {
|
||||
handle(world, rand, readVec())
|
||||
}
|
||||
|
||||
abstract fun handle(world: World, rand: Random, vec: Vec3d)
|
||||
}
|
||||
@@ -0,0 +1,8 @@
|
||||
package chylex.hee.system.component
|
||||
|
||||
abstract class AbstractAwareComponent {
|
||||
var entityComponents: EntityComponents? = null
|
||||
|
||||
open fun onComponentAttached() {}
|
||||
open fun onComponentDetached() {}
|
||||
}
|
||||
@@ -0,0 +1,56 @@
|
||||
package chylex.hee.system.component
|
||||
|
||||
class EntityComponents {
|
||||
private val mutableComponents = mutableListOf<Any>()
|
||||
|
||||
val components: List<Any>
|
||||
get() = mutableComponents
|
||||
|
||||
fun attach(component: Any) {
|
||||
require(!mutableComponents.contains(component)) { "[EntityComponents] component must not be registered twice" }
|
||||
mutableComponents.add(component)
|
||||
|
||||
if (component is AbstractAwareComponent) {
|
||||
require(component.entityComponents === null) { "[EntityComponents] component must not be registered in two entities" }
|
||||
component.entityComponents = this
|
||||
component.onComponentAttached()
|
||||
}
|
||||
}
|
||||
|
||||
fun detach(component: Any) {
|
||||
if (!mutableComponents.remove(component)) {
|
||||
return
|
||||
}
|
||||
|
||||
if (component is AbstractAwareComponent) {
|
||||
require(component.entityComponents === this) { "[EntityComponents] component was not registered correctly" }
|
||||
component.onComponentDetached()
|
||||
component.entityComponents = null
|
||||
}
|
||||
}
|
||||
|
||||
inline fun <reified T> on(f: T.() -> Unit) {
|
||||
for(component in components) {
|
||||
if (component is T) {
|
||||
f(component)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
inline fun <reified T, U> handle(f: T.() -> U?): U? {
|
||||
for(component in components) {
|
||||
if (component is T) {
|
||||
val result = f(component)
|
||||
if (result != null) {
|
||||
return result
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return null
|
||||
}
|
||||
|
||||
inline fun <reified T> list(): List<T> {
|
||||
return components.filterIsInstance<T>()
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,20 @@
|
||||
package chylex.hee.system.component.general
|
||||
|
||||
import chylex.hee.system.component.EntityComponents
|
||||
import chylex.hee.system.serialization.TagCompound
|
||||
import net.minecraftforge.common.util.INBTSerializable
|
||||
|
||||
interface SerializableComponent : INBTSerializable<TagCompound> {
|
||||
val serializationKey: String
|
||||
}
|
||||
|
||||
fun EntityComponents.serializeTo(tag: TagCompound) {
|
||||
this.on<SerializableComponent> {
|
||||
require(!tag.contains(serializationKey)) { "[SerializableComponent] cannot serialize duplicate key: $serializationKey" }
|
||||
tag.put(serializationKey, serializeNBT())
|
||||
}
|
||||
}
|
||||
|
||||
fun EntityComponents.deserializeFrom(tag: TagCompound) {
|
||||
this.on<SerializableComponent> { deserializeNBT(tag.getCompound(serializationKey)) }
|
||||
}
|
||||
@@ -0,0 +1,19 @@
|
||||
package chylex.hee.system.component.general
|
||||
|
||||
import chylex.hee.system.component.EntityComponents
|
||||
import net.minecraft.entity.Entity
|
||||
|
||||
interface TickableComponent {
|
||||
@JvmDefault fun tickClient() {}
|
||||
@JvmDefault fun tickServer() {}
|
||||
}
|
||||
|
||||
@JvmName("tickEntity")
|
||||
fun <T : Entity> EntityComponents.tick(entity: T) {
|
||||
if (entity.world.isRemote) {
|
||||
this.on(TickableComponent::tickClient)
|
||||
}
|
||||
else {
|
||||
this.on(TickableComponent::tickServer)
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,28 @@
|
||||
package chylex.hee.test.main
|
||||
import chylex.hee.game.loot.rng.RandomBiasedValueRange
|
||||
import java.util.Random
|
||||
import kotlin.math.roundToInt
|
||||
|
||||
fun main() {
|
||||
val min = 3F
|
||||
val max = 10F
|
||||
val highestChanceValue = 6.5F
|
||||
val biasSoftener = 3F
|
||||
|
||||
val rand = Random()
|
||||
val generator = RandomBiasedValueRange(min..max, highestChanceValue, biasSoftener)
|
||||
val reps = 100000
|
||||
|
||||
val results = (1..reps).map { generator.generateInt(rand) }
|
||||
.groupBy { it }
|
||||
.mapValues { it.value.size }
|
||||
.toList()
|
||||
.sortedBy { it.first }
|
||||
|
||||
val pad1 = results.maxOf { it.first.toString().length }
|
||||
val pad2 = results.maxOf { it.second.toString().length }
|
||||
|
||||
println(results.joinToString("\n") {
|
||||
"${it.first.toString().padStart(pad1)} | ${it.second.toString().padStart(pad2)} | ${((it.second * 100.0) / reps).roundToInt().toString().padStart(2)} %"
|
||||
})
|
||||
}
|
||||
35
src/test/java/chylex/hee/test/main/TombDungeonMobCounts.kt
Normal file
35
src/test/java/chylex/hee/test/main/TombDungeonMobCounts.kt
Normal file
@@ -0,0 +1,35 @@
|
||||
package chylex.hee.test.main
|
||||
|
||||
import chylex.hee.game.world.feature.tombdungeon.TombDungeonLevel
|
||||
import chylex.hee.game.world.feature.tombdungeon.TombDungeonLevel.MobAmount
|
||||
import java.util.Locale.ROOT
|
||||
import java.util.Random
|
||||
import kotlin.math.roundToInt
|
||||
|
||||
fun main() {
|
||||
val rand = Random()
|
||||
|
||||
for(level in TombDungeonLevel.values()) {
|
||||
val reps = 100000
|
||||
|
||||
println()
|
||||
println("== ${level.name} ${"=".repeat(24 - level.name.length)}")
|
||||
|
||||
for(amount in MobAmount.values()) {
|
||||
println()
|
||||
println(" ${amount.name}")
|
||||
println()
|
||||
|
||||
val results = (1..reps)
|
||||
.map { level.pickUndreadAndSpiderlingSpawns(rand, amount) }
|
||||
.groupingBy { it }
|
||||
.eachCount()
|
||||
.entries
|
||||
.map { ((it.value * 100.0) / reps).roundToInt() to it.key }
|
||||
.sortedWith(compareBy({ -it.first }, { -it.second.first }, { -it.second.second }))
|
||||
|
||||
println(results.joinToString("\n") { " U = ${it.second.first} S = ${it.second.second} ${it.first.toString().padStart(2)} %" })
|
||||
println(" U ~ ${"%.1f".format(ROOT, results.sumBy { it.second.first * it.first } * 0.01)} S ~ ${"%.1f".format(ROOT, results.sumBy { it.second.second * it.first } * 0.01)}")
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -1,4 +1,4 @@
|
||||
package chylex.hee.test.mechanics.damage
|
||||
package chylex.hee.test.unit.mechanics.damage
|
||||
|
||||
import chylex.hee.game.mechanics.damage.DamageProperties
|
||||
import chylex.hee.game.mechanics.damage.DamageType
|
||||
@@ -1,4 +1,4 @@
|
||||
package chylex.hee.test.mechanics.energy
|
||||
package chylex.hee.test.unit.mechanics.energy
|
||||
|
||||
import chylex.hee.game.mechanics.energy.IEnergyQuantity.Floating
|
||||
import chylex.hee.game.mechanics.energy.IEnergyQuantity.Internal
|
||||
@@ -1,4 +1,4 @@
|
||||
package chylex.hee.test.system.util
|
||||
package chylex.hee.test.unit.system
|
||||
|
||||
import chylex.hee.game.world.Pos
|
||||
import chylex.hee.system.math.Vec
|
||||
@@ -1,4 +1,4 @@
|
||||
package chylex.hee.test.system.util
|
||||
package chylex.hee.test.unit.system
|
||||
|
||||
import chylex.hee.game.inventory.cleanupNBT
|
||||
import chylex.hee.game.inventory.heeTag
|
||||
Reference in New Issue
Block a user