mirror of
https://gitlab.com/cc-ru/ocelot/ocelot-desktop.git
synced 2025-12-20 11:09:20 +01:00
169 lines
5.4 KiB
Scala
169 lines
5.4 KiB
Scala
package ocelot.desktop.node
|
|
|
|
import ocelot.desktop.{ColorScheme, OcelotDesktop, Settings => DesktopSettings}
|
|
import ocelot.desktop.audio._
|
|
import ocelot.desktop.color.Color
|
|
import ocelot.desktop.graphics.{Graphics, IconSource}
|
|
import ocelot.desktop.inventory.SyncedInventory
|
|
import ocelot.desktop.node.ComputerAwareNode._
|
|
import ocelot.desktop.node.Node.Size
|
|
import ocelot.desktop.ui.UiHandler
|
|
import ocelot.desktop.ui.event.BrainEvent
|
|
import ocelot.desktop.ui.event.handlers.DiskActivityHandler
|
|
import ocelot.desktop.ui.particle.Particle
|
|
import ocelot.desktop.util.Messages
|
|
import totoro.ocelot.brain.Settings
|
|
import totoro.ocelot.brain.entity.traits.{Entity, Environment, WorkspaceAware}
|
|
import totoro.ocelot.brain.entity.SelfDestructingCard
|
|
import totoro.ocelot.brain.event._
|
|
|
|
import java.util.Calendar
|
|
|
|
abstract class ComputerAwareNode(entity: Entity with Environment with WorkspaceAware)
|
|
extends EntityNode(entity)
|
|
with SyncedInventory
|
|
with DiskActivityHandler
|
|
with OcelotLogParticleNode
|
|
with SmokeParticleNode
|
|
with ShiftClickNode
|
|
with PositionalSoundSourcesNode {
|
|
|
|
private lazy val soundCardSounds: (SoundStream, SoundSource) = Audio.newStream(SoundCategory.Records)
|
|
private def soundCardStream: SoundStream = soundCardSounds._1
|
|
private def soundCardSource: SoundSource = soundCardSounds._2
|
|
|
|
// PositionalSoundSourcesNode
|
|
override def soundSources: Seq[SoundSource] = Seq(
|
|
SoundSource.MinecraftExplosion,
|
|
SoundSource.SelfDestructingCardCountdownBeep,
|
|
)
|
|
|
|
private var boomGlowIntensity: Float = -1
|
|
|
|
eventHandlers += {
|
|
case BrainEvent(event: MachineCrashEvent) =>
|
|
val message = Messages.lift(event.message) match {
|
|
case Some(message) =>
|
|
logger.info(s"[EVENT] Machine crash (address = ${event.address})! Message code ${event.message}: $message")
|
|
message
|
|
case None =>
|
|
logger.info(s"[EVENT] Machine crash (address = ${event.address})! Message: ${event.message}")
|
|
event.message
|
|
}
|
|
UiHandler.root.workspaceView.particleSystem.add(new ErrorMessageParticle(message))
|
|
|
|
case BrainEvent(event: BeepEvent) if !Audio.isDisabled =>
|
|
BeepGenerator.newBeep(".", event.frequency, event.duration).play()
|
|
|
|
case BrainEvent(event: BeepPatternEvent) if !Audio.isDisabled =>
|
|
BeepGenerator.newBeep(event.pattern, 1000, 200).play()
|
|
|
|
case BrainEvent(event: SoundCardAudioEvent) if !Audio.isDisabled =>
|
|
val samples = SoundSamples(event.data, Settings.get.soundCardSampleRate, SoundSamples.Format.Mono8)
|
|
soundCardStream.enqueue(samples)
|
|
soundCardSource.volume = event.volume
|
|
|
|
case BrainEvent(_: SelfDestructingCardBoomEvent) =>
|
|
OcelotDesktop.updateThreadTasks.add(() => {
|
|
SoundSource.MinecraftExplosion.play()
|
|
emitSmoke()
|
|
destroy()
|
|
})
|
|
}
|
|
|
|
override def update(): Unit = {
|
|
super.update()
|
|
updateBoomCardState()
|
|
}
|
|
|
|
private def updateBoomCardState(): Unit = {
|
|
boomGlowIntensity = -1
|
|
|
|
for (slot <- brainInventory.inventory) {
|
|
slot.get match {
|
|
case Some(card: SelfDestructingCard) =>
|
|
if (card.time > 0) {
|
|
// If multiple SDCs are ticking, let the most soon exploding one to define the glow
|
|
boomGlowIntensity = boomGlowIntensity.max(1 - card.time.toFloat / card.initialTime)
|
|
|
|
if (card.lastBeepTime < 0 || card.lastBeepTime - card.time >= 20) {
|
|
SoundSource.SelfDestructingCardCountdownBeep.play()
|
|
card.lastBeepTime = card.time
|
|
}
|
|
}
|
|
|
|
case _ =>
|
|
}
|
|
}
|
|
}
|
|
|
|
protected def drawOverlay(g: Graphics): Unit = HolidayIcon match {
|
|
case Some(icon) if DesktopSettings.get.enableFestiveDecorations =>
|
|
val holidayOverlaySize = Size * 1.6f
|
|
val offset = (holidayOverlaySize - Size) / 2
|
|
|
|
g.sprite(
|
|
icon,
|
|
position.x - offset,
|
|
position.y - offset,
|
|
holidayOverlaySize,
|
|
holidayOverlaySize,
|
|
)
|
|
|
|
case _ =>
|
|
}
|
|
|
|
override def drawLight(g: Graphics): Unit = {
|
|
super.drawLight(g)
|
|
|
|
if (boomGlowIntensity > 0) {
|
|
g.sprite(
|
|
IconSource.Nodes.Lamp.Glow,
|
|
position - size / 2,
|
|
size * 2,
|
|
Color.Transparent.lerp(ColorScheme("BoomCardGlow"), boomGlowIntensity),
|
|
)
|
|
}
|
|
}
|
|
|
|
override def draw(g: Graphics): Unit = {
|
|
super.draw(g)
|
|
drawOverlay(g)
|
|
}
|
|
|
|
private class ErrorMessageParticle(message: String) extends Particle(speed = ErrorMessageMoveSpeed) {
|
|
private val offsetX = size.width / 2 - message.length * 4
|
|
private val offsetY = -8
|
|
override def draw(g: Graphics): Unit = {
|
|
g.setSmallFont()
|
|
g.foreground = ColorScheme("ErrorMessage").withAlpha(1 - (2 * time - 1).min(1).max(0))
|
|
g.text(position.x + offsetX, position.y + offsetY - MaxErrorMessageDistance * time, message)
|
|
g.setNormalFont()
|
|
}
|
|
}
|
|
}
|
|
|
|
object ComputerAwareNode {
|
|
private val MaxErrorMessageDistance: Float = 50f
|
|
private val ErrorMessageMoveSpeed: Float = 0.5f
|
|
|
|
private val HolidayIcon: Option[IconSource] = {
|
|
var dayOfYear = Calendar.getInstance().get(Calendar.DAY_OF_YEAR)
|
|
val maxDuration = 5
|
|
|
|
if (dayOfYear >= 365 - maxDuration) {
|
|
dayOfYear -= 365
|
|
}
|
|
|
|
val holidays: Array[(Int, IconSource)] = Array(
|
|
(1, IconSource.Nodes.Holidays.Christmas),
|
|
(45, IconSource.Nodes.Holidays.Valentines),
|
|
(305, IconSource.Nodes.Holidays.Halloween),
|
|
)
|
|
|
|
holidays
|
|
.find(holiday => dayOfYear >= holiday._1 - maxDuration && dayOfYear <= holiday._1 + maxDuration)
|
|
.map(holiday => holiday._2)
|
|
}
|
|
}
|