Plasma weapon heating, hud and energy usage

This commit is contained in:
DBotThePony 2022-05-15 13:53:11 +07:00
parent 2314dbfa85
commit d9ce8ca3b5
Signed by: DBot
GPG Key ID: DCC23B5715498507
10 changed files with 347 additions and 123 deletions

View File

@ -340,6 +340,8 @@ public class RenderHelper {
private static RGBAColor draw_color = new RGBAColor(255, 255, 255, 255); private static RGBAColor draw_color = new RGBAColor(255, 255, 255, 255);
public static boolean forwardWinding = true;
/** /**
* Draws a solid color rectangle on screen, defined by last setDrawColor(RGBColor rect_color) call * Draws a solid color rectangle on screen, defined by last setDrawColor(RGBColor rect_color) call
* *
@ -368,10 +370,17 @@ public class RenderHelper {
builder.begin(VertexFormat.Mode.QUADS, DefaultVertexFormat.POSITION_COLOR); builder.begin(VertexFormat.Mode.QUADS, DefaultVertexFormat.POSITION_COLOR);
if (forwardWinding) {
builder.vertex(matrix, x, y + height, depth_z).color(draw_color.getRed(), draw_color.getGreen(), draw_color.getBlue(), draw_color.getAlpha()).endVertex(); builder.vertex(matrix, x, y + height, depth_z).color(draw_color.getRed(), draw_color.getGreen(), draw_color.getBlue(), draw_color.getAlpha()).endVertex();
builder.vertex(matrix, x + width, y + height, depth_z).color(draw_color.getRed(), draw_color.getGreen(), draw_color.getBlue(), draw_color.getAlpha()).endVertex(); builder.vertex(matrix, x + width, y + height, depth_z).color(draw_color.getRed(), draw_color.getGreen(), draw_color.getBlue(), draw_color.getAlpha()).endVertex();
builder.vertex(matrix, x + width, y, depth_z).color(draw_color.getRed(), draw_color.getGreen(), draw_color.getBlue(), draw_color.getAlpha()).endVertex(); builder.vertex(matrix, x + width, y, depth_z).color(draw_color.getRed(), draw_color.getGreen(), draw_color.getBlue(), draw_color.getAlpha()).endVertex();
builder.vertex(matrix, x, y, depth_z).color(draw_color.getRed(), draw_color.getGreen(), draw_color.getBlue(), draw_color.getAlpha()).endVertex(); builder.vertex(matrix, x, y, depth_z).color(draw_color.getRed(), draw_color.getGreen(), draw_color.getBlue(), draw_color.getAlpha()).endVertex();
} else {
builder.vertex(matrix, x, y, depth_z).color(draw_color.getRed(), draw_color.getGreen(), draw_color.getBlue(), draw_color.getAlpha()).endVertex();
builder.vertex(matrix, x + width, y, depth_z).color(draw_color.getRed(), draw_color.getGreen(), draw_color.getBlue(), draw_color.getAlpha()).endVertex();
builder.vertex(matrix, x + width, y + height, depth_z).color(draw_color.getRed(), draw_color.getGreen(), draw_color.getBlue(), draw_color.getAlpha()).endVertex();
builder.vertex(matrix, x, y + height, depth_z).color(draw_color.getRed(), draw_color.getGreen(), draw_color.getBlue(), draw_color.getAlpha()).endVertex();
}
tess.end(); tess.end();

View File

@ -261,6 +261,15 @@ data class MutableAngle(override var pitch: Double = 0.0, override var yaw: Doub
} }
} }
fun linearInterpolation(t: Float, a: Float, b: Float): Float {
if (t <= 0f)
return a
else if (t >= 1f)
return b
return a + t * (b - a)
}
fun linearInterpolation(t: Double, a: Double, b: Double): Double { fun linearInterpolation(t: Double, a: Double, b: Double): Double {
if (t <= 0.0) if (t <= 0.0)
return a return a

View File

@ -41,6 +41,15 @@ data class RGBAColor(val red: Float, val green: Float, val blue: Float, val alph
RenderHelper.setDrawColor(this) RenderHelper.setDrawColor(this)
} }
fun linearInterpolation(t: Float, other: RGBAColor): RGBAColor {
return RGBAColor(
linearInterpolation(t, red, other.red),
linearInterpolation(t, green, other.green),
linearInterpolation(t, blue, other.blue),
linearInterpolation(t, alpha, other.alpha),
)
}
companion object { companion object {
val BLACK = RGBAColor(0f, 0f, 0f, 1f) val BLACK = RGBAColor(0f, 0f, 0f, 1f)
val WHITE = RGBAColor(1f, 1f, 1f, 1f) val WHITE = RGBAColor(1f, 1f, 1f, 1f)
@ -56,3 +65,7 @@ data class RGBAColor(val red: Float, val green: Float, val blue: Float, val alph
} }
} }
} }
fun linearInterpolation(t: Float, a: RGBAColor, b: RGBAColor): RGBAColor {
return a.linearInterpolation(t, b)
}

View File

@ -1,11 +1,15 @@
package ru.dbotthepony.mc.otm.item.weapon package ru.dbotthepony.mc.otm.item.weapon
import com.mojang.blaze3d.systems.RenderSystem
import com.mojang.blaze3d.vertex.*
import com.mojang.math.Vector3f import com.mojang.math.Vector3f
import net.minecraft.client.Minecraft import net.minecraft.client.Minecraft
import net.minecraft.client.model.HumanoidModel import net.minecraft.client.model.HumanoidModel
import net.minecraft.client.renderer.GameRenderer
import net.minecraft.client.renderer.block.model.ItemTransforms import net.minecraft.client.renderer.block.model.ItemTransforms
import net.minecraft.nbt.CompoundTag import net.minecraft.nbt.CompoundTag
import net.minecraft.network.FriendlyByteBuf import net.minecraft.network.FriendlyByteBuf
import net.minecraft.server.level.ServerPlayer
import net.minecraft.world.entity.Entity import net.minecraft.world.entity.Entity
import net.minecraft.world.entity.player.Player import net.minecraft.world.entity.player.Player
import net.minecraft.world.item.Item import net.minecraft.world.item.Item
@ -20,9 +24,14 @@ import net.minecraftforge.event.TickEvent
import net.minecraftforge.eventbus.api.SubscribeEvent import net.minecraftforge.eventbus.api.SubscribeEvent
import net.minecraftforge.fml.LogicalSide import net.minecraftforge.fml.LogicalSide
import net.minecraftforge.network.NetworkEvent import net.minecraftforge.network.NetworkEvent
import org.lwjgl.opengl.GL30
import ru.dbotthepony.mc.otm.* import ru.dbotthepony.mc.otm.*
import ru.dbotthepony.mc.otm.capability.matteryEnergy
import ru.dbotthepony.mc.otm.client.font
import ru.dbotthepony.mc.otm.client.render.RenderHelper
import ru.dbotthepony.mc.otm.core.* import ru.dbotthepony.mc.otm.core.*
import ru.dbotthepony.mc.otm.core.Vector import ru.dbotthepony.mc.otm.core.Vector
import ru.dbotthepony.mc.otm.menu.FormattingHelper
import ru.dbotthepony.mc.otm.network.MatteryNetworking import ru.dbotthepony.mc.otm.network.MatteryNetworking
import java.util.* import java.util.*
import java.util.function.Supplier import java.util.function.Supplier
@ -104,7 +113,7 @@ open class WeaponDataTable(val tag: CompoundTag) {
var fireAnim = 0.0 var fireAnim = 0.0
var fireAnimDeviation = Angle.ZERO var fireAnimDeviation = Angle.ZERO
fun doFireAnim(amount: Double = 1.0, deviation: Angle? = null) { fun doFireAnim(amount: Double = 0.8, deviation: Angle? = null) {
fireAnim = (fireAnim + amount).coerceAtLeast(0.0).coerceAtMost(1.0) fireAnim = (fireAnim + amount).coerceAtLeast(0.0).coerceAtMost(1.0)
if (deviation != null) { if (deviation != null) {
@ -225,8 +234,17 @@ abstract class AbstractWeaponItem<D : WeaponDataTable>(val tables: KClass<D>, ra
return false return false
} }
open fun canPrimaryFire(itemStack: ItemStack, player: Player, dt: D = dataTable(itemStack)): Boolean {
if (player is ServerPlayer) {
// allow a little deviation, becuse nothing is perfect
return dt.nextPrimaryFire <= 2
}
return dt.nextPrimaryFire <= 0
}
fun tryPrimaryFire(itemStack: ItemStack, player: Player, dt: D = dataTable(itemStack)): Boolean { fun tryPrimaryFire(itemStack: ItemStack, player: Player, dt: D = dataTable(itemStack)): Boolean {
if (dt.nextPrimaryFire <= 0 && primaryFire(itemStack, player, dt)) { if (canPrimaryFire(itemStack, player, dt) && primaryFire(itemStack, player, dt)) {
dt.nextPrimaryFire = fireCooldown dt.nextPrimaryFire = fireCooldown
return true return true
} }
@ -357,7 +375,7 @@ abstract class AbstractWeaponItem<D : WeaponDataTable>(val tables: KClass<D>, ra
(item as AbstractWeaponItem<WeaponDataTable>).dataTable = predictedData (item as AbstractWeaponItem<WeaponDataTable>).dataTable = predictedData
predictedData?.deployTime = (predictedData!!.deployTime + diff.toDouble() / (300_000_000.0 * item.deployAnimSpeed)).coerceAtMost(1.0).coerceAtLeast(0.0) predictedData?.deployTime = (predictedData!!.deployTime + diff.toDouble() / (300_000_000.0 * item.deployAnimSpeed)).coerceAtMost(1.0).coerceAtLeast(0.0)
predictedData?.fireAnim = (predictedData!!.fireAnim - diff.toDouble() / (300_000_000.0 * item.fireAnimRecovery)).coerceAtMost(1.0).coerceAtLeast(0.0) predictedData?.fireAnim = (predictedData!!.fireAnim - diff.toDouble() / (400_000_000.0 * item.fireAnimRecovery)).coerceAtMost(1.0).coerceAtLeast(0.0)
val player = Minecraft.getInstance().player!! val player = Minecraft.getInstance().player!!
val pose = event.poseStack val pose = event.poseStack
@ -404,9 +422,9 @@ abstract class AbstractWeaponItem<D : WeaponDataTable>(val tables: KClass<D>, ra
) )
val rotFire = item.rotFireAnim val rotFire = item.rotFireAnim
pitch += (rotFire.pitch + (predictedData?.fireAnimDeviation?.pitch ?: 0.0)) * fireAnim pitch += (rotFire.pitch + (predictedData?.fireAnimDeviation?.pitch ?: 0.0)) * fireAnim * (1.0 - progress * 0.6)
yaw += (rotFire.yaw + (predictedData?.fireAnimDeviation?.yaw ?: 0.0)) * fireAnim yaw += (rotFire.yaw + (predictedData?.fireAnimDeviation?.yaw ?: 0.0)) * fireAnim * (1.0 - progress * 0.6)
roll += (rotFire.roll + (predictedData?.fireAnimDeviation?.roll ?: 0.0)) * fireAnim roll += (rotFire.roll + (predictedData?.fireAnimDeviation?.roll ?: 0.0)) * fireAnim * (1.0 - progress * 0.6)
pose.mulPose(Vector3f.ZP.rotation(roll.toFloat())) pose.mulPose(Vector3f.ZP.rotation(roll.toFloat()))
pose.mulPose(Vector3f.YP.rotation(yaw.toFloat())) pose.mulPose(Vector3f.YP.rotation(yaw.toFloat()))
@ -422,12 +440,51 @@ abstract class AbstractWeaponItem<D : WeaponDataTable>(val tables: KClass<D>, ra
event.packedLight event.packedLight
) )
if (item is PlasmaWeaponItem<*>) {
// RenderSystem.setShader(GameRenderer::getPositionColorShader)
// RenderSystem.disableTexture()
// RenderSystem.enableBlend()
RenderSystem.setShaderColor(1f, 1f, 1f, 1f)
pose.translate(-0.85, 0.25, -0.25)
pose.mulPose(Vector3f.ZP.rotationDegrees(180f))
pose.mulPose(Vector3f.YP.rotationDegrees(180f))
pose.scale(0.01f, 0.01f, 0.01f)
RenderHelper.setDrawColor(holoHudBackground)
RenderHelper.drawRect(pose, -2f, -2f, 72f, 34f)
stack.matteryEnergy?.let {
pose.pushPose()
pose.translate(0.0, 0.0, -1.0)
pose.scale(0.7f, 0.7f, 0.7f)
val text = FormattingHelper.formatPower(it.batteryLevel)
font.draw(pose, text, 2f, 2f, RGBAColor.WHITE.toInt())
pose.popPose()
}
pose.translate(60.0, 0.0, 0.0)
RenderHelper.setDrawColor(heatBackground)
RenderHelper.drawRect(pose, -1f, -1f, 9f, 32f)
val heat = item.heatProgress(stack, event.partialTicks.toDouble()).toFloat()
RenderHelper.setDrawColor(linearInterpolation(heat, initialHeatColor, finalHeatColor))
RenderHelper.drawRect(pose, 0f, 30f * (1f - heat), 7f, 30f * heat)
}
pose.popPose() pose.popPose()
item.dataTable = null item.dataTable = null
inRender = false inRender = false
} }
private val holoHudBackground get() = RGBAColor(75, 75, 75, 160)
private val heatBackground get() = RGBAColor(40, 144, 210, 160)
private val initialHeatColor get() = RGBAColor(85, 68, 7, 160)
private val finalHeatColor get() = RGBAColor(245, 118, 41, 160)
private val localPlayer: Player? get() { private val localPlayer: Player? get() {
return Minecraft.getInstance().player return Minecraft.getInstance().player
} }
@ -486,6 +543,9 @@ abstract class AbstractWeaponItem<D : WeaponDataTable>(val tables: KClass<D>, ra
} }
(stack.item as? AbstractWeaponItem<*>)?.let { (stack.item as? AbstractWeaponItem<*>)?.let {
if (event.side == LogicalSide.CLIENT && stack.weaponDataTable?.uuid != predictedData?.uuid)
return@let
if (event.side == LogicalSide.CLIENT) { if (event.side == LogicalSide.CLIENT) {
(it as AbstractWeaponItem<WeaponDataTable>).dataTable = predictedData (it as AbstractWeaponItem<WeaponDataTable>).dataTable = predictedData
} }

View File

@ -6,6 +6,7 @@ import net.minecraft.world.entity.Entity
import net.minecraft.world.entity.player.Player import net.minecraft.world.entity.player.Player
import net.minecraft.world.item.ItemStack import net.minecraft.world.item.ItemStack
import net.minecraft.world.phys.Vec3 import net.minecraft.world.phys.Vec3
import ru.dbotthepony.mc.otm.capability.extractEnergyInnerExact
import ru.dbotthepony.mc.otm.core.* import ru.dbotthepony.mc.otm.core.*
import ru.dbotthepony.mc.otm.core.Vector import ru.dbotthepony.mc.otm.core.Vector
import ru.dbotthepony.mc.otm.entity.PlasmaProjectile import ru.dbotthepony.mc.otm.entity.PlasmaProjectile
@ -16,123 +17,20 @@ import kotlin.math.PI
import kotlin.math.cos import kotlin.math.cos
import kotlin.math.sin import kotlin.math.sin
private val random = Random() class PlasmaRifleItem : PlasmaWeaponItem<PlasmaWeaponDataTable>(PlasmaWeaponDataTable::class, ImpreciseFraction(200_000)) {
private const val DEGS = PI / 180.0
class VelocityCalculation(
xRot: Double,
yRot: Double,
zRot: Double = 0.0,
force: Double,
deviation: Double = 0.0,
owner: Entity? = null,
) {
constructor(
xRot: Float,
yRot: Float,
zRot: Float = 0f,
force: Double,
deviation: Double = 0.0,
owner: Entity? = null,
) : this(xRot.toDouble(), yRot.toDouble(), zRot.toDouble(), force, deviation, owner)
constructor(
xRot: Float,
yRot: Float,
zRot: Float = 0f,
force: Float,
deviation: Double = 0.0,
owner: Entity? = null,
) : this(xRot.toDouble(), yRot.toDouble(), zRot.toDouble(), force.toDouble(), deviation, owner)
constructor(
xRot: Float,
yRot: Float,
zRot: Float = 0f,
force: Float,
deviation: Float,
owner: Entity? = null,
) : this(xRot.toDouble(), yRot.toDouble(), zRot.toDouble(), force.toDouble(), deviation.toDouble(), owner)
constructor(
owner: Entity,
force: Float,
deviation: Float,
) : this(owner.xRot.toDouble() - 4.5 * (1 / force), owner.yRot.toDouble(), 0.0, force.toDouble(), deviation.toDouble(), owner)
constructor(
owner: Entity,
force: Double,
deviation: Float,
) : this(owner.xRot.toDouble() - 4.5 * (1 / force), owner.yRot.toDouble(), 0.0, force, deviation.toDouble(), owner)
constructor(
owner: Entity,
force: Double,
deviation: Double,
) : this(owner.xRot.toDouble() - 4.5 * (1 / force), owner.yRot.toDouble(), 0.0, force, deviation, owner)
val xVelocity = -sin(yRot * DEGS) * cos(xRot * (PI / 180.0))
val yVelocity = -sin((xRot + zRot) * DEGS)
val zVelocity = cos(yRot * DEGS) * cos(xRot * DEGS)
val velocity: Vec3
init {
var velocity = Vec3(
xVelocity,
yVelocity,
zVelocity
).normalize()
velocity += Vec3(
random.nextGaussian() * 0.0075 * deviation,
random.nextGaussian() * 0.0075 * deviation,
random.nextGaussian() * 0.0075 * deviation,
)
velocity *= force
if (owner != null) {
val ownerVel = owner.deltaMovement
if (owner.isOnGround) {
velocity += ownerVel
} else {
velocity += Vec3(ownerVel.x, 0.0, ownerVel.z)
}
}
this.velocity = velocity
}
val yRotation = Mth.atan2(velocity.x, velocity.z).toFloat() * (180f / Math.PI.toFloat())
val xRotation = Mth.atan2(velocity.y, velocity.horizontalDistance()).toFloat() * (180f / Math.PI.toFloat())
fun load(onto: Entity, withRotation: Boolean = true) {
if (withRotation) {
onto.xRot = xRotation
onto.yRot = yRotation
}
onto.deltaMovement = velocity
}
}
class PlasmaRifleItem : PlasmaWeaponItem<WeaponDataTable>(WeaponDataTable::class, ImpreciseFraction(200_000)) {
override val roundsPerMinute: Int = 200 override val roundsPerMinute: Int = 200
override val scopingTime: Int = 7 override val scopingTime: Int = 7
override val positionIdle: Vector override val positionIdle: Vector
get() = Vector(0.2,-0.4,-0.6) get() = Vector(0.2, -0.4, -0.6)
override val positionIronSights: Vector override val positionIronSights: Vector
get() = Vector(0.0,-0.24,-1.0) get() = Vector(0.0, -0.24, -1.0)
override val rotIdle: Angle override val rotIdle: Angle
get() = Angle(0.0, -0.02, 0.0) get() = Angle(0.0, -0.02, 0.0)
override val rotIronSights: Angle override val rotIronSights: Angle
get() = Angle(-0.02, 0.0, 0.0) get() = Angle(-0.02, 0.0, 0.0)
override fun primaryFire(itemStack: ItemStack, player: Player, dt: WeaponDataTable): Boolean { override fun primaryFire(itemStack: ItemStack, player: Player, dt: PlasmaWeaponDataTable): Boolean {
if (!player.level.isClientSide) { if (!player.level.isClientSide) {
val arrow = PlasmaProjectile(player.level) val arrow = PlasmaProjectile(player.level)
arrow.position = player.eyePosition arrow.position = player.eyePosition
@ -147,18 +45,26 @@ class PlasmaRifleItem : PlasmaWeaponItem<WeaponDataTable>(WeaponDataTable::class
dt.doFireAnim(deviation = rotFireAnimDeviation) dt.doFireAnim(deviation = rotFireAnimDeviation)
} }
receiveHeat(itemStack, player, 10.0, dt)
player.level.playSound( player.level.playSound(
player, player,
player, player,
MSoundEvents.RIFLE_SHOT, MSoundEvents.RIFLE_SHOT,
SoundSource.NEUTRAL, SoundSource.PLAYERS,
1f, 1f,
1f 1f
) )
energyData(itemStack).extractEnergyInner(ENERGY_PER_SHOT, false)
return true return true
} }
override fun canPrimaryFire(itemStack: ItemStack, player: Player, dt: PlasmaWeaponDataTable): Boolean {
return super.canPrimaryFire(itemStack, player, dt) && energyData(itemStack).extractEnergyInnerExact(ENERGY_PER_SHOT, true).isPositive
}
companion object { companion object {
private val ENERGY_PER_SHOT = ImpreciseFraction(3_000) private val ENERGY_PER_SHOT = ImpreciseFraction(3_000)
} }

View File

@ -5,6 +5,8 @@ import net.minecraft.core.Direction
import net.minecraft.nbt.CompoundTag import net.minecraft.nbt.CompoundTag
import net.minecraft.network.chat.Component import net.minecraft.network.chat.Component
import net.minecraft.network.chat.TranslatableComponent import net.minecraft.network.chat.TranslatableComponent
import net.minecraft.server.level.ServerPlayer
import net.minecraft.sounds.SoundSource
import net.minecraft.world.entity.player.Player import net.minecraft.world.entity.player.Player
import net.minecraft.world.item.ItemStack import net.minecraft.world.item.ItemStack
import net.minecraft.world.item.TooltipFlag import net.minecraft.world.item.TooltipFlag
@ -16,8 +18,12 @@ import net.minecraftforge.common.util.LazyOptional
import net.minecraftforge.energy.CapabilityEnergy import net.minecraftforge.energy.CapabilityEnergy
import ru.dbotthepony.mc.otm.capability.* import ru.dbotthepony.mc.otm.capability.*
import ru.dbotthepony.mc.otm.core.ImpreciseFraction import ru.dbotthepony.mc.otm.core.ImpreciseFraction
import ru.dbotthepony.mc.otm.core.bezierCurve
import ru.dbotthepony.mc.otm.doubles
import ru.dbotthepony.mc.otm.ifPresentK import ru.dbotthepony.mc.otm.ifPresentK
import ru.dbotthepony.mc.otm.ints
import ru.dbotthepony.mc.otm.menu.FormattingHelper import ru.dbotthepony.mc.otm.menu.FormattingHelper
import ru.dbotthepony.mc.otm.registry.MSoundEvents
import ru.dbotthepony.mc.otm.set import ru.dbotthepony.mc.otm.set
import kotlin.reflect.KClass import kotlin.reflect.KClass
@ -112,7 +118,7 @@ class PlasmaWeaponEnergy(val itemStack: ItemStack, private val innerCapacity: Im
return totalReceived return totalReceived
} }
val newEnergy = (innerBatteryLevel - howMuch).coerceAtMost(innerCapacity) val newEnergy = (innerBatteryLevel + howMuch).coerceAtMost(innerCapacity)
val diff = newEnergy - innerBatteryLevel val diff = newEnergy - innerBatteryLevel
if (!simulate) { if (!simulate) {
@ -145,7 +151,12 @@ class PlasmaWeaponEnergy(val itemStack: ItemStack, private val innerCapacity: Im
get() = (battery.energy?.maxEnergyStoredMattery ?: ImpreciseFraction.ZERO) + innerCapacity get() = (battery.energy?.maxEnergyStoredMattery ?: ImpreciseFraction.ZERO) + innerCapacity
} }
abstract class PlasmaWeaponItem<D : WeaponDataTable>(tables: KClass<D>, private val energyCapacity: ImpreciseFraction) : AbstractWeaponItem<D>(tables) { open class PlasmaWeaponDataTable(tag: CompoundTag) : WeaponDataTable(tag) {
var heatScore by tag.doubles
var heatCooldown by tag.ints
}
abstract class PlasmaWeaponItem<D : PlasmaWeaponDataTable>(tables: KClass<D>, private val energyCapacity: ImpreciseFraction) : AbstractWeaponItem<D>(tables) {
override fun appendHoverText( override fun appendHoverText(
itemStack: ItemStack, itemStack: ItemStack,
p_41422_: Level?, p_41422_: Level?,
@ -167,9 +178,97 @@ abstract class PlasmaWeaponItem<D : WeaponDataTable>(tables: KClass<D>, private
fun energyData(itemStack: ItemStack) = itemStack.matteryEnergy as PlasmaWeaponEnergy fun energyData(itemStack: ItemStack) = itemStack.matteryEnergy as PlasmaWeaponEnergy
open val cooldownSpeed get() = 1.0
open val maxHeat = 40.0
open val overheatCooldown = 30
open val cooldownSpline = doubleArrayOf(
0.1,
0.14,
0.18,
0.25,
0.35,
0.45,
0.6,
0.8,
0.97,
1.0,
1.0,
1.0,
1.0,
1.0,
1.0,
1.1,
1.2,
1.3,
1.4,
)
override fun canPrimaryFire(itemStack: ItemStack, player: Player, dt: D): Boolean {
if (player is ServerPlayer) {
// allow little deviation because nothing is perfect
return super.canPrimaryFire(itemStack, player, dt) && dt.heatCooldown <= 2
}
return super.canPrimaryFire(itemStack, player, dt) && dt.heatCooldown <= 0
}
open fun canCooldown(itemStack: ItemStack, player: Player, dt: D = dataTable(itemStack)): Boolean {
return true
}
protected open fun coolWeaponDown(itemStack: ItemStack, player: Player, dt: D) {
if (!canCooldown(itemStack, player, dt))
return
if (dt.heatScore > 0.0)
dt.heatScore = (dt.heatScore - cooldownSpeed * bezierCurve(heatProgress(itemStack, dt = dt), cooldownSpline)).coerceAtLeast(0.0)
if (dt.heatCooldown > 0)
dt.heatCooldown--
}
open fun heatProgress(itemStack: ItemStack, partialTicks: Double = 0.0, dt: D = dataTable(itemStack)): Double {
if (dt.heatScore <= 0)
return 0.0
if (dt.heatScore - cooldownSpeed > maxHeat)
return 1.0
val result = dt.heatScore - cooldownSpeed * partialTicks
return result / maxHeat
}
open fun overheatProgress(itemStack: ItemStack, partialTicks: Double = 0.0, dt: D = dataTable(itemStack)): Double {
if (dt.heatCooldown <= 0)
return 0.0
if (dt.heatCooldown - partialTicks > overheatCooldown)
return 1.0
val result = dt.heatCooldown - partialTicks
return result / overheatCooldown
}
open fun receiveHeat(itemStack: ItemStack, player: Player, byTicks: Double, dt: D = dataTable(itemStack)) {
dt.heatScore = (dt.heatScore + byTicks).coerceAtMost(maxHeat * 2)
if (dt.heatScore > maxHeat) {
val before = dt.heatCooldown > 0
dt.heatCooldown = overheatCooldown
if (!before) {
player.level.playSound(player, player, MSoundEvents.PLASMA_WEAPON_OVERHEAT, SoundSource.PLAYERS, 1f, 1f)
}
}
}
override fun think2(itemStack: ItemStack, player: Player, dt: D) { override fun think2(itemStack: ItemStack, player: Player, dt: D) {
super.think2(itemStack, player, dt) super.think2(itemStack, player, dt)
coolWeaponDown(itemStack, player, dt)
itemStack.getCapability(MatteryCapability.ENERGY).ifPresentK { itemStack.getCapability(MatteryCapability.ENERGY).ifPresentK {
it as PlasmaWeaponEnergy it as PlasmaWeaponEnergy
it.think() it.think()

View File

@ -0,0 +1,114 @@
package ru.dbotthepony.mc.otm.item.weapon
import net.minecraft.util.Mth
import net.minecraft.world.entity.Entity
import net.minecraft.world.phys.Vec3
import ru.dbotthepony.mc.otm.core.plus
import ru.dbotthepony.mc.otm.core.times
import java.util.*
import kotlin.math.PI
import kotlin.math.cos
import kotlin.math.sin
private val random = Random()
private const val DEGS = PI / 180.0
class VelocityCalculation(
xRot: Double,
yRot: Double,
zRot: Double = 0.0,
force: Double,
deviation: Double = 0.0,
owner: Entity? = null,
) {
constructor(
xRot: Float,
yRot: Float,
zRot: Float = 0f,
force: Double,
deviation: Double = 0.0,
owner: Entity? = null,
) : this(xRot.toDouble(), yRot.toDouble(), zRot.toDouble(), force, deviation, owner)
constructor(
xRot: Float,
yRot: Float,
zRot: Float = 0f,
force: Float,
deviation: Double = 0.0,
owner: Entity? = null,
) : this(xRot.toDouble(), yRot.toDouble(), zRot.toDouble(), force.toDouble(), deviation, owner)
constructor(
xRot: Float,
yRot: Float,
zRot: Float = 0f,
force: Float,
deviation: Float,
owner: Entity? = null,
) : this(xRot.toDouble(), yRot.toDouble(), zRot.toDouble(), force.toDouble(), deviation.toDouble(), owner)
constructor(
owner: Entity,
force: Float,
deviation: Float,
) : this(owner.xRot.toDouble() - 4.5 * (1 / force), owner.yRot.toDouble(), 0.0, force.toDouble(), deviation.toDouble(), owner)
constructor(
owner: Entity,
force: Double,
deviation: Float,
) : this(owner.xRot.toDouble() - 4.5 * (1 / force), owner.yRot.toDouble(), 0.0, force, deviation.toDouble(), owner)
constructor(
owner: Entity,
force: Double,
deviation: Double,
) : this(owner.xRot.toDouble() - 4.5 * (1 / force), owner.yRot.toDouble(), 0.0, force, deviation, owner)
val xVelocity = -sin(yRot * DEGS) * cos(xRot * (PI / 180.0))
val yVelocity = -sin((xRot + zRot) * DEGS)
val zVelocity = cos(yRot * DEGS) * cos(xRot * DEGS)
val velocity: Vec3
init {
var velocity = Vec3(
xVelocity,
yVelocity,
zVelocity
).normalize()
velocity += Vec3(
random.nextGaussian() * 0.0075 * deviation,
random.nextGaussian() * 0.0075 * deviation,
random.nextGaussian() * 0.0075 * deviation,
)
velocity *= force
if (owner != null) {
val ownerVel = owner.deltaMovement
if (owner.isOnGround) {
velocity += ownerVel
} else {
velocity += Vec3(ownerVel.x, 0.0, ownerVel.z)
}
}
this.velocity = velocity
}
val yRotation = Mth.atan2(velocity.x, velocity.z).toFloat() * (180f / Math.PI.toFloat())
val xRotation = Mth.atan2(velocity.y, velocity.horizontalDistance()).toFloat() * (180f / Math.PI.toFloat())
fun load(onto: Entity, withRotation: Boolean = true) {
if (withRotation) {
onto.xRot = xRotation
onto.yRot = yRotation
}
onto.deltaMovement = velocity
}
}

View File

@ -2,6 +2,7 @@ package ru.dbotthepony.mc.otm.registry
import net.minecraft.resources.ResourceLocation import net.minecraft.resources.ResourceLocation
import net.minecraft.sounds.SoundEvent import net.minecraft.sounds.SoundEvent
import net.minecraft.sounds.SoundEvents
import net.minecraft.world.entity.EntityType import net.minecraft.world.entity.EntityType
import net.minecraftforge.fml.javafmlmod.FMLJavaModLoadingContext import net.minecraftforge.fml.javafmlmod.FMLJavaModLoadingContext
import net.minecraftforge.registries.DeferredRegister import net.minecraftforge.registries.DeferredRegister
@ -11,7 +12,10 @@ import ru.dbotthepony.mc.otm.OverdriveThatMatters
object MSoundEvents { object MSoundEvents {
private val registry: DeferredRegister<SoundEvent> = DeferredRegister.create(ForgeRegistries.SOUND_EVENTS, OverdriveThatMatters.MOD_ID) private val registry: DeferredRegister<SoundEvent> = DeferredRegister.create(ForgeRegistries.SOUND_EVENTS, OverdriveThatMatters.MOD_ID)
val RIFLE_SHOT by registry.register("item.rifle_shot") { SoundEvent(ResourceLocation(OverdriveThatMatters.MOD_ID, "item.rifle_shot")) } private fun make(name: String) = registry.register(name) { SoundEvent(ResourceLocation(OverdriveThatMatters.MOD_ID, name)) }
val RIFLE_SHOT: SoundEvent by make("item.rifle_shot")
val PLASMA_WEAPON_OVERHEAT: SoundEvent by make("item.plasma_weapon_overheat")
internal fun register() { internal fun register() {
registry.register(FMLJavaModLoadingContext.get().modEventBus) registry.register(FMLJavaModLoadingContext.get().modEventBus)

View File

@ -1,5 +1,7 @@
{ {
"otm.sound.rifle_shoot": "Plasma rifle fire", "otm.sound.rifle_shoot": "Plasma rifle fires",
"otm.sound.plasma_weapon_overheat": "Plasma weapon overheats",
"itemGroup.otm": "Overdrive That Matters", "itemGroup.otm": "Overdrive That Matters",
"otm.pill.warning": "WARNING: This will INSTANTLY decommission you upon ingestion!", "otm.pill.warning": "WARNING: This will INSTANTLY decommission you upon ingestion!",
@ -287,6 +289,8 @@
"item.overdrive_that_matters.tritanium_pants": "Tritanium Leggings", "item.overdrive_that_matters.tritanium_pants": "Tritanium Leggings",
"item.overdrive_that_matters.tritanium_boots": "Tritanium Boots", "item.overdrive_that_matters.tritanium_boots": "Tritanium Boots",
"item.overdrive_that_matters.plasma_rifle": "Plasma Rifle",
"item.overdrive_that_matters.matter_capacitor_parts": "Matter Capacitor Parts", "item.overdrive_that_matters.matter_capacitor_parts": "Matter Capacitor Parts",
"item.overdrive_that_matters.matter_capacitor_basic": "Basic Matter Capacitor", "item.overdrive_that_matters.matter_capacitor_basic": "Basic Matter Capacitor",
"item.overdrive_that_matters.matter_capacitor_normal": "Matter Capacitor", "item.overdrive_that_matters.matter_capacitor_normal": "Matter Capacitor",

View File

@ -8,5 +8,11 @@
"weight": 1 "weight": 1
} }
] ]
},
"item.plasma_weapon_overheat": {
"subtitle": "otm.sound.plasma_weapon_overheat",
"sounds": [
]
} }
} }