Plasma weapons but better™️
This commit is contained in:
parent
15c4cfb488
commit
42c0c49782
@ -329,3 +329,24 @@ fun bezierCurve(t: Double, vararg values: Vector): Vector {
|
||||
}
|
||||
}
|
||||
}
|
||||
fun bezierCurve(t: Double, values: DoubleArray): Double {
|
||||
when (values.size) {
|
||||
0, 1 -> throw IllegalArgumentException("Provided array has only ${values.size} entries in it")
|
||||
else -> {
|
||||
@Suppress("NAME_SHADOWING") val values = values.clone()
|
||||
|
||||
// construct prime - 1
|
||||
for (length in values.size - 2 downTo 0) {
|
||||
// search prime
|
||||
for (j in 0 .. length) {
|
||||
val point1 = values[j]
|
||||
val point2 = values[j + 1]
|
||||
|
||||
values[j] = linearInterpolation(t, point1, point2)
|
||||
}
|
||||
}
|
||||
|
||||
return values[0]
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -43,8 +43,6 @@ class PlasmaProjectile(level: Level) : Projectile(MEntityTypes.PLASMA as EntityT
|
||||
|
||||
override fun onHitBlock(p_37258_: BlockHitResult) {
|
||||
super.onHitBlock(p_37258_)
|
||||
|
||||
println("Play sound at ${position()}")
|
||||
}
|
||||
|
||||
override fun tick() {
|
||||
|
@ -27,6 +27,7 @@ import ru.dbotthepony.mc.otm.network.MatteryNetworking
|
||||
import java.util.*
|
||||
import java.util.function.Supplier
|
||||
import kotlin.math.PI
|
||||
import kotlin.math.abs
|
||||
import kotlin.reflect.KClass
|
||||
import kotlin.reflect.full.isSubclassOf
|
||||
import kotlin.reflect.full.primaryConstructor
|
||||
@ -99,6 +100,29 @@ open class WeaponDataTable(val tag: CompoundTag) {
|
||||
var nextPrimaryFire by tag.ints
|
||||
var nextSecondaryFire by tag.ints
|
||||
var uuid by tag.uuids
|
||||
|
||||
var fireAnim = 0.0
|
||||
var fireAnimDeviation = Angle.ZERO
|
||||
|
||||
fun doFireAnim(amount: Double = 1.0, deviation: Angle? = null) {
|
||||
fireAnim = (fireAnim + amount).coerceAtLeast(0.0).coerceAtMost(1.0)
|
||||
|
||||
if (deviation != null) {
|
||||
fireAnimDeviation = Angle(
|
||||
deviation.pitch * RANDOM.nextGaussian(),
|
||||
deviation.yaw * RANDOM.nextGaussian(),
|
||||
deviation.roll * RANDOM.nextGaussian(),
|
||||
)
|
||||
} else {
|
||||
fireAnimDeviation = Angle.ZERO
|
||||
}
|
||||
}
|
||||
|
||||
var deployTime = 0.0
|
||||
|
||||
companion object {
|
||||
private val RANDOM = Random()
|
||||
}
|
||||
}
|
||||
|
||||
abstract class AbstractWeaponItem<D : WeaponDataTable>(val tables: KClass<D>, rarity: Rarity = Rarity.UNCOMMON) : Item(
|
||||
@ -144,10 +168,16 @@ abstract class AbstractWeaponItem<D : WeaponDataTable>(val tables: KClass<D>, ra
|
||||
val roundsPerSecond get() = roundsPerMinute / 60
|
||||
val fireCooldown get() = (1200 / roundsPerMinute).coerceAtLeast(1)
|
||||
|
||||
open val positionHolstered get() = Vector(1.0, -2.5, -1.0)
|
||||
open val positionIdle get() = Vector(1.0, -0.5, -1.0)
|
||||
open val positionIronSights get() = Vector(0.0, -0.23, -1.0)
|
||||
open val rotIdle get() = Angle(PI / 36, PI / 18)
|
||||
open val rotIronSights get() = Angle.ZERO
|
||||
open val rotFireAnim get() = Angle.deg(20.0, 0.0, 0.0)
|
||||
open val rotFireAnimDeviation get() = Angle.deg(2.0, 1.0, 1.0)
|
||||
|
||||
open val fireAnimRecovery = 1.0
|
||||
open val deployAnimSpeed = 1.0
|
||||
|
||||
open val primaryAutomatic = true
|
||||
open val secondaryAutomatic = true
|
||||
@ -156,9 +186,9 @@ abstract class AbstractWeaponItem<D : WeaponDataTable>(val tables: KClass<D>, ra
|
||||
|
||||
fun ironSightsProgress(itemStack: ItemStack, partialTicks: Double = 0.0, dt: D = dataTable(itemStack)): Double {
|
||||
if (!dt.wantsToScope)
|
||||
return (dt.scopeTicks.toDouble() - partialTicks).coerceAtLeast(0.0) / scopingTime.toDouble()
|
||||
return (((dt.scopeTicks.toDouble() - partialTicks).coerceAtLeast(0.0) / scopingTime.toDouble()) * 1.4).coerceAtMost(1.0)
|
||||
|
||||
return (dt.scopeTicks.toDouble() + partialTicks) / scopingTime.toDouble()
|
||||
return (((dt.scopeTicks.toDouble() + partialTicks) / scopingTime.toDouble()) * 1.4).coerceAtMost(1.0)
|
||||
}
|
||||
|
||||
abstract val scopingTime: Int
|
||||
@ -228,25 +258,39 @@ abstract class AbstractWeaponItem<D : WeaponDataTable>(val tables: KClass<D>, ra
|
||||
// client only
|
||||
private var inRender = false
|
||||
var predictedData: WeaponDataTable? = null
|
||||
private var lastFov = 1.0
|
||||
private var lastFovTime = 0L
|
||||
|
||||
@SubscribeEvent
|
||||
@Suppress("unused")
|
||||
fun fovHook(event: EntityViewRenderEvent.FieldOfView) {
|
||||
val player = event.camera.entity as? Player ?: return
|
||||
|
||||
(player.mainHandItem.item as? AbstractWeaponItem<*>)?.let {
|
||||
val it = (player.mainHandItem.item as? AbstractWeaponItem<*>)
|
||||
|
||||
if (it != null) {
|
||||
@Suppress("unchecked_cast")
|
||||
if (it.compatibleDataTable(predictedData))
|
||||
(it as AbstractWeaponItem<WeaponDataTable>).dataTable = predictedData
|
||||
|
||||
event.fov /= linearInterpolation(
|
||||
val interp = linearInterpolation(
|
||||
it.ironSightsProgress(
|
||||
player.mainHandItem,
|
||||
event.partialTicks
|
||||
) * 1.7 - 0.6, 1.0, it.ironSightsFOV
|
||||
)
|
||||
|
||||
val time = System.nanoTime()
|
||||
val diff = abs(lastFovTime - time)
|
||||
lastFov = linearInterpolation(diff.coerceAtLeast(0).coerceAtMost(10_000_000L).toDouble() / 10_000_000.0, lastFov, interp).coerceAtLeast(0.001)
|
||||
lastFovTime = time
|
||||
|
||||
event.fov /= lastFov
|
||||
|
||||
it.dataTable = null
|
||||
} else {
|
||||
lastFov = 1.0
|
||||
lastFovTime = 0L
|
||||
}
|
||||
}
|
||||
|
||||
@ -270,6 +314,29 @@ abstract class AbstractWeaponItem<D : WeaponDataTable>(val tables: KClass<D>, ra
|
||||
}
|
||||
}
|
||||
|
||||
private var lastClientRender = 0L
|
||||
|
||||
private val fireAnimInterp = doubleArrayOf(
|
||||
0.0,
|
||||
0.01,
|
||||
0.03,
|
||||
0.04,
|
||||
0.05,
|
||||
0.06,
|
||||
0.07,
|
||||
0.1,
|
||||
0.15,
|
||||
0.3,
|
||||
0.45,
|
||||
0.6,
|
||||
0.8,
|
||||
0.85,
|
||||
0.9,
|
||||
1.0,
|
||||
0.9,
|
||||
0.6,
|
||||
)
|
||||
|
||||
@SubscribeEvent
|
||||
@Suppress("unused", "unchecked_cast")
|
||||
fun renderViewModel(event: RenderHandEvent) {
|
||||
@ -277,6 +344,10 @@ abstract class AbstractWeaponItem<D : WeaponDataTable>(val tables: KClass<D>, ra
|
||||
return
|
||||
}
|
||||
|
||||
val time = System.nanoTime()
|
||||
val diff = abs(lastClientRender - time)
|
||||
lastClientRender = time
|
||||
|
||||
val stack = event.itemStack
|
||||
val item = stack.item as? AbstractWeaponItem<*> ?: return
|
||||
|
||||
@ -285,6 +356,9 @@ abstract class AbstractWeaponItem<D : WeaponDataTable>(val tables: KClass<D>, ra
|
||||
|
||||
(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?.fireAnim = (predictedData!!.fireAnim - diff.toDouble() / (300_000_000.0 * item.fireAnimRecovery)).coerceAtMost(1.0).coerceAtLeast(0.0)
|
||||
|
||||
val player = Minecraft.getInstance().player!!
|
||||
val pose = event.poseStack
|
||||
val itemInHandRenderer = Minecraft.getInstance().itemInHandRenderer
|
||||
@ -293,7 +367,11 @@ abstract class AbstractWeaponItem<D : WeaponDataTable>(val tables: KClass<D>, ra
|
||||
|
||||
val progress = item.ironSightsProgress(stack, event.partialTicks.toDouble())
|
||||
|
||||
val (x, y, z) = bezierCurve(
|
||||
val (x, y, z) = linearInterpolation(
|
||||
// 1.0 - event.equipProgress.toDouble(),
|
||||
item.dataTable?.deployTime ?: 0.0,
|
||||
item.positionHolstered,
|
||||
bezierCurve(
|
||||
progress,
|
||||
item.positionIdle,
|
||||
item.positionIdle,
|
||||
@ -303,10 +381,11 @@ abstract class AbstractWeaponItem<D : WeaponDataTable>(val tables: KClass<D>, ra
|
||||
item.positionIronSights,
|
||||
item.positionIronSights,
|
||||
)
|
||||
)
|
||||
|
||||
pose.translate(x, y, z)
|
||||
|
||||
val (pitch, yaw, roll) = bezierCurve(
|
||||
var (pitch, yaw, roll) = bezierCurve(
|
||||
progress,
|
||||
item.rotIdle,
|
||||
item.rotIdle,
|
||||
@ -319,6 +398,16 @@ abstract class AbstractWeaponItem<D : WeaponDataTable>(val tables: KClass<D>, ra
|
||||
item.rotIronSights,
|
||||
)
|
||||
|
||||
val fireAnim = bezierCurve(
|
||||
predictedData?.fireAnim ?: 0.0,
|
||||
fireAnimInterp
|
||||
)
|
||||
|
||||
val rotFire = item.rotFireAnim
|
||||
pitch += (rotFire.pitch + (predictedData?.fireAnimDeviation?.pitch ?: 0.0)) * fireAnim
|
||||
yaw += (rotFire.yaw + (predictedData?.fireAnimDeviation?.yaw ?: 0.0)) * fireAnim
|
||||
roll += (rotFire.roll + (predictedData?.fireAnimDeviation?.roll ?: 0.0)) * fireAnim
|
||||
|
||||
pose.mulPose(Vector3f.ZP.rotation(roll.toFloat()))
|
||||
pose.mulPose(Vector3f.YP.rotation(yaw.toFloat()))
|
||||
pose.mulPose(Vector3f.XP.rotation(pitch.toFloat()))
|
||||
|
@ -118,8 +118,9 @@ class VelocityCalculation(
|
||||
}
|
||||
|
||||
class PlasmaRifleItem : PlasmaWeaponItem<WeaponDataTable>(WeaponDataTable::class, ImpreciseFraction(200_000)) {
|
||||
override val roundsPerMinute: Int = 400
|
||||
override val roundsPerMinute: Int = 200
|
||||
override val scopingTime: Int = 7
|
||||
|
||||
override val positionIdle: Vector
|
||||
get() = Vector(0.2,-0.4,-0.6)
|
||||
override val positionIronSights: Vector
|
||||
@ -137,7 +138,11 @@ class PlasmaRifleItem : PlasmaWeaponItem<WeaponDataTable>(WeaponDataTable::class
|
||||
val calc = VelocityCalculation(player, force = 4.0, deviation = 0.3)
|
||||
calc.load(arrow)
|
||||
|
||||
arrow.owner = player
|
||||
|
||||
player.level.addFreshEntity(arrow)
|
||||
} else {
|
||||
dt.doFireAnim(deviation = rotFireAnimDeviation)
|
||||
}
|
||||
|
||||
return true
|
||||
|
Loading…
Reference in New Issue
Block a user