Plasma weapon heating, hud and energy usage
This commit is contained in:
parent
2314dbfa85
commit
d9ce8ca3b5
@ -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();
|
||||||
|
|
||||||
|
@ -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
|
||||||
|
@ -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)
|
||||||
|
}
|
||||||
|
@ -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
|
||||||
}
|
}
|
||||||
|
@ -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)
|
||||||
}
|
}
|
||||||
|
@ -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()
|
||||||
|
@ -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
|
||||||
|
}
|
||||||
|
}
|
@ -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)
|
||||||
|
@ -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",
|
||||||
|
@ -8,5 +8,11 @@
|
|||||||
"weight": 1
|
"weight": 1
|
||||||
}
|
}
|
||||||
]
|
]
|
||||||
|
},
|
||||||
|
|
||||||
|
"item.plasma_weapon_overheat": {
|
||||||
|
"subtitle": "otm.sound.plasma_weapon_overheat",
|
||||||
|
"sounds": [
|
||||||
|
]
|
||||||
}
|
}
|
||||||
}
|
}
|
Loading…
Reference in New Issue
Block a user