Merge branch 'feature/self-destructing-card-enhancements' into 'develop'

Self-destructing card enhancements

Closes #165

See merge request cc-ru/ocelot/ocelot-desktop!111
This commit is contained in:
Dmitry Zhidenkov 2025-08-03 19:12:34 +00:00
commit cd9866f46f
21 changed files with 568 additions and 336 deletions

BIN
sprites/particles/Smoke.png Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 1.9 KiB

View File

@ -193,3 +193,6 @@ Flash = #ffffff
RelayTextLow = #009900
RelayTextMid = #999900
RelayTextHigh = #990000
BoomCardGlowStart = #ff4010
BoomCardGlowEnd = #ff1010

Binary file not shown.

Before

Width:  |  Height:  |  Size: 148 KiB

After

Width:  |  Height:  |  Size: 149 KiB

View File

@ -1,22 +1,22 @@
BackgroundPattern 0 0 304 304
BarSegment 385 434 16 4
Empty 134 618 16 16
EmptySlot 237 567 18 18
Empty 134 632 16 16
EmptySlot 246 567 18 18
Knob 203 434 50 50
KnobCenter 254 434 50 50
KnobLimits 305 434 50 50
Loading 0 305 48 448
Logo 305 0 168 200
ShadowBorder 201 540 1 24
ShadowBorder 279 305 1 24
ShadowCorner 233 674 24 24
TabArrow 225 600 8 14
blocks/Generic 151 618 16 16
blocks/HologramEffect 213 540 4 4
blocks/HologramProjector1Top 168 618 16 16
blocks/HologramProjector2Top 185 618 16 16
blocks/HologramProjectorSide 202 618 16 16
buttons/BottomDrawerClose 256 567 18 18
buttons/BottomDrawerOpen 275 567 18 18
TabArrow 569 567 8 14
blocks/Generic 151 632 16 16
blocks/HologramEffect 291 305 4 4
blocks/HologramProjector1Top 168 632 16 16
blocks/HologramProjector2Top 185 632 16 16
blocks/HologramProjectorSide 202 632 16 16
buttons/BottomDrawerClose 265 567 18 18
buttons/BottomDrawerOpen 284 567 18 18
buttons/OpenFMRadioCloseOff 404 445 7 8
buttons/OpenFMRadioCloseOn 412 445 7 8
buttons/OpenFMRadioRedstoneOff 359 445 8 8
@ -25,318 +25,319 @@ buttons/OpenFMRadioStartOff 258 674 24 24
buttons/OpenFMRadioStartOn 283 674 24 24
buttons/OpenFMRadioStopOff 308 674 24 24
buttons/OpenFMRadioStopOn 333 674 24 24
buttons/OpenFMRadioVolumeDownOff 234 600 10 10
buttons/OpenFMRadioVolumeDownOn 245 600 10 10
buttons/OpenFMRadioVolumeUpOff 256 600 10 10
buttons/OpenFMRadioVolumeUpOn 267 600 10 10
buttons/PowerOff 294 567 18 18
buttons/PowerOn 313 567 18 18
buttons/OpenFMRadioVolumeDownOff 578 567 10 10
buttons/OpenFMRadioVolumeDownOn 589 567 10 10
buttons/OpenFMRadioVolumeUpOff 600 567 10 10
buttons/OpenFMRadioVolumeUpOn 611 567 10 10
buttons/PowerOff 303 567 18 18
buttons/PowerOn 322 567 18 18
buttons/RackRelayOff 134 655 65 18
buttons/RackRelayOn 200 655 65 18
icons/Antenna 219 618 16 16
icons/ArrowRight 236 618 16 16
icons/AspectRatio 253 618 16 16
icons/Book 270 618 16 16
icons/ButtonCheck 134 600 17 17
icons/ButtonClipboard 152 600 17 17
icons/ButtonRandomize 170 600 17 17
icons/CPU 287 618 16 16
icons/Card 304 618 16 16
icons/Close 209 600 15 14
icons/Code 321 618 16 16
icons/ComponentBus 338 618 16 16
icons/Copy 355 618 16 16
icons/Cross 372 618 16 16
icons/Delete 389 618 16 16
icons/DragLMB 500 567 21 14
icons/DragRMB 522 567 21 14
icons/EEPROM 406 618 16 16
icons/Edit 423 618 16 16
icons/Eject 440 618 16 16
icons/File 457 618 16 16
icons/Floppy 474 618 16 16
icons/Folder 491 618 16 16
icons/FolderSlash 508 618 16 16
icons/Grid 168 567 22 22
icons/GridOff 191 567 22 22
icons/Guitar 525 618 16 16
icons/HDD 542 618 16 16
icons/Help 559 618 16 16
icons/Home 214 567 22 22
icons/Keyboard 576 618 16 16
icons/KeyboardOff 593 618 16 16
icons/LMB 363 655 11 14
icons/Label 610 618 16 16
icons/LinesHorizontal 627 618 16 16
icons/Link 644 618 16 16
icons/LinkSlash 661 618 16 16
icons/Memory 678 618 16 16
icons/Microchip 695 618 16 16
icons/NA 712 618 16 16
icons/NotificationError 387 655 11 11
icons/NotificationInfo 399 655 11 11
icons/NotificationWarning 411 655 11 11
icons/Ocelot 729 618 16 16
icons/Pin 318 655 14 14
icons/Plus 746 618 16 16
icons/Power 763 618 16 16
icons/RMB 375 655 11 14
icons/Restart 780 618 16 16
icons/Save 797 618 16 16
icons/SaveAs 814 618 16 16
icons/Server 831 618 16 16
icons/SettingsKeymap 266 655 12 17
icons/SettingsSound 279 655 12 17
icons/SettingsSystem 292 655 12 17
icons/SettingsUI 305 655 12 17
icons/SideAny 423 655 11 11
icons/SideDown 435 655 11 11
icons/SideEast 447 655 11 11
icons/SideNone 459 655 11 11
icons/SideNorth 471 655 11 11
icons/SideSouth 483 655 11 11
icons/SideUndefined 495 655 11 11
icons/SideUp 507 655 11 11
icons/SideWest 519 655 11 11
icons/Tier0 848 618 16 16
icons/Tier1 865 618 16 16
icons/Tier2 882 618 16 16
icons/Tiers 899 618 16 16
icons/Unpin 333 655 14 14
icons/WaveLFSR 901 707 24 10
icons/WaveNoise 926 707 24 10
icons/WaveSawtooth 951 707 24 10
icons/WaveSine 976 707 24 10
icons/WaveSquare 134 724 24 10
icons/WaveTriangle 159 724 24 10
icons/Window 916 618 16 16
icons/WireArrowLeft 203 540 4 8
icons/WireArrowRight 208 540 4 8
icons/Antenna 219 632 16 16
icons/ArrowRight 236 632 16 16
icons/AspectRatio 253 632 16 16
icons/Book 270 632 16 16
icons/ButtonCheck 143 600 17 17
icons/ButtonClipboard 161 600 17 17
icons/ButtonRandomize 179 600 17 17
icons/CPU 287 632 16 16
icons/Card 304 632 16 16
icons/Close 553 567 15 14
icons/Code 321 632 16 16
icons/ComponentBus 338 632 16 16
icons/Copy 355 632 16 16
icons/Cross 372 632 16 16
icons/Delete 389 632 16 16
icons/DragLMB 509 567 21 14
icons/DragRMB 531 567 21 14
icons/EEPROM 406 632 16 16
icons/Edit 423 632 16 16
icons/Eject 440 632 16 16
icons/File 457 632 16 16
icons/Floppy 474 632 16 16
icons/Folder 491 632 16 16
icons/FolderSlash 508 632 16 16
icons/Grid 177 567 22 22
icons/GridOff 200 567 22 22
icons/Guitar 525 632 16 16
icons/HDD 542 632 16 16
icons/Help 559 632 16 16
icons/Home 223 567 22 22
icons/Keyboard 576 632 16 16
icons/KeyboardOff 593 632 16 16
icons/LMB 298 540 11 14
icons/Label 610 632 16 16
icons/LinesHorizontal 627 632 16 16
icons/Link 644 632 16 16
icons/LinkSlash 661 632 16 16
icons/Memory 678 632 16 16
icons/Microchip 695 632 16 16
icons/NA 712 632 16 16
icons/NotificationError 322 540 11 11
icons/NotificationInfo 334 540 11 11
icons/NotificationWarning 346 540 11 11
icons/Ocelot 729 632 16 16
icons/Pin 253 540 14 14
icons/Plus 746 632 16 16
icons/Power 763 632 16 16
icons/RMB 310 540 11 14
icons/Restart 780 632 16 16
icons/Save 797 632 16 16
icons/SaveAs 814 632 16 16
icons/Server 831 632 16 16
icons/SettingsKeymap 201 540 12 17
icons/SettingsSound 214 540 12 17
icons/SettingsSystem 227 540 12 17
icons/SettingsUI 240 540 12 17
icons/SideAny 358 540 11 11
icons/SideDown 370 540 11 11
icons/SideEast 382 540 11 11
icons/SideNone 394 540 11 11
icons/SideNorth 406 540 11 11
icons/SideSouth 418 540 11 11
icons/SideUndefined 430 540 11 11
icons/SideUp 442 540 11 11
icons/SideWest 454 540 11 11
icons/Tier0 848 632 16 16
icons/Tier1 865 632 16 16
icons/Tier2 882 632 16 16
icons/Tiers 899 632 16 16
icons/Unpin 268 540 14 14
icons/WaveLFSR 237 600 24 10
icons/WaveNoise 262 600 24 10
icons/WaveSawtooth 287 600 24 10
icons/WaveSine 312 600 24 10
icons/WaveSquare 337 600 24 10
icons/WaveTriangle 362 600 24 10
icons/Window 916 632 16 16
icons/WireArrowLeft 281 305 4 8
icons/WireArrowRight 286 305 4 8
items/APU0 49 655 16 96
items/APU1 66 655 16 96
items/APU2 83 655 16 96
items/CPU0 933 618 16 16
items/CPU1 950 618 16 16
items/CPU2 967 618 16 16
items/CardBase 984 618 16 16
items/CircuitBoard 1001 618 16 16
items/ComponentBus0 134 635 16 16
items/ComponentBus1 151 635 16 16
items/ComponentBus2 168 635 16 16
items/ComponentBus3 185 635 16 16
items/CPU0 933 632 16 16
items/CPU1 950 632 16 16
items/CPU2 967 632 16 16
items/CardBase 984 632 16 16
items/CircuitBoard 1001 632 16 16
items/ComponentBus0 358 674 16 16
items/ComponentBus1 375 674 16 16
items/ComponentBus2 392 674 16 16
items/ComponentBus3 409 674 16 16
items/DataCard0 49 526 16 128
items/DataCard1 66 526 16 128
items/DataCard2 83 526 16 128
items/DebugCard 202 635 16 16
items/DiskDriveMountable 219 635 16 16
items/EEPROM 236 635 16 16
items/FloppyDisk_dyeBlack 253 635 16 16
items/FloppyDisk_dyeBlue 270 635 16 16
items/FloppyDisk_dyeBrown 287 635 16 16
items/FloppyDisk_dyeCyan 304 635 16 16
items/FloppyDisk_dyeGray 321 635 16 16
items/FloppyDisk_dyeGreen 338 635 16 16
items/FloppyDisk_dyeLightBlue 355 635 16 16
items/FloppyDisk_dyeLightGray 372 635 16 16
items/FloppyDisk_dyeLime 389 635 16 16
items/FloppyDisk_dyeMagenta 406 635 16 16
items/FloppyDisk_dyeOrange 423 635 16 16
items/FloppyDisk_dyePink 440 635 16 16
items/FloppyDisk_dyePurple 457 635 16 16
items/FloppyDisk_dyeRed 474 635 16 16
items/FloppyDisk_dyeWhite 491 635 16 16
items/FloppyDisk_dyeYellow 508 635 16 16
items/GraphicsCard0 525 635 16 16
items/GraphicsCard1 542 635 16 16
items/GraphicsCard2 559 635 16 16
items/HardDiskDrive0 576 635 16 16
items/HardDiskDrive1 593 635 16 16
items/HardDiskDrive2 610 635 16 16
items/InternetCard 134 567 16 32
items/DebugCard 426 674 16 16
items/DiskDriveMountable 443 674 16 16
items/EEPROM 460 674 16 16
items/FloppyDisk_dyeBlack 477 674 16 16
items/FloppyDisk_dyeBlue 494 674 16 16
items/FloppyDisk_dyeBrown 511 674 16 16
items/FloppyDisk_dyeCyan 528 674 16 16
items/FloppyDisk_dyeGray 545 674 16 16
items/FloppyDisk_dyeGreen 562 674 16 16
items/FloppyDisk_dyeLightBlue 579 674 16 16
items/FloppyDisk_dyeLightGray 596 674 16 16
items/FloppyDisk_dyeLime 613 674 16 16
items/FloppyDisk_dyeMagenta 630 674 16 16
items/FloppyDisk_dyeOrange 647 674 16 16
items/FloppyDisk_dyePink 664 674 16 16
items/FloppyDisk_dyePurple 681 674 16 16
items/FloppyDisk_dyeRed 698 674 16 16
items/FloppyDisk_dyeWhite 715 674 16 16
items/FloppyDisk_dyeYellow 732 674 16 16
items/GraphicsCard0 749 674 16 16
items/GraphicsCard1 766 674 16 16
items/GraphicsCard2 783 674 16 16
items/HardDiskDrive0 800 674 16 16
items/HardDiskDrive1 817 674 16 16
items/HardDiskDrive2 834 674 16 16
items/InternetCard 143 567 16 32
items/LinkedCard 100 655 16 96
items/Memory0 627 635 16 16
items/Memory1 644 635 16 16
items/Memory2 661 635 16 16
items/Memory3 678 635 16 16
items/Memory4 695 635 16 16
items/Memory5 712 635 16 16
items/Memory6 729 635 16 16
items/NetworkCard 746 635 16 16
items/Memory0 851 674 16 16
items/Memory1 868 674 16 16
items/Memory2 885 674 16 16
items/Memory3 902 674 16 16
items/Memory4 919 674 16 16
items/Memory5 936 674 16 16
items/Memory6 953 674 16 16
items/NetworkCard 970 674 16 16
items/OcelotCard 100 526 16 128
items/RedstoneCard0 763 635 16 16
items/RedstoneCard1 780 635 16 16
items/SelfDestructingCard 151 567 16 32
items/Server0 797 635 16 16
items/Server1 814 635 16 16
items/Server2 831 635 16 16
items/Server3 848 635 16 16
items/RedstoneCard0 987 674 16 16
items/RedstoneCard1 1004 674 16 16
items/SelfDestructingCard 160 567 16 32
items/Server0 134 707 16 16
items/Server1 151 707 16 16
items/Server2 168 707 16 16
items/Server3 185 707 16 16
items/SoundCard 117 526 16 128
items/TapeCopper 865 635 16 16
items/TapeDiamond 882 635 16 16
items/TapeGold 899 635 16 16
items/TapeGreg 916 635 16 16
items/TapeIg 933 635 16 16
items/TapeIron 950 635 16 16
items/TapeNetherStar 967 635 16 16
items/TapeSteel 984 635 16 16
items/WirelessNetworkCard0 1001 635 16 16
items/WirelessNetworkCard1 358 674 16 16
light-panel/BookmarkLeft 882 707 18 14
light-panel/BookmarkRight 188 600 20 14
light-panel/BorderB 218 540 4 4
light-panel/BorderL 206 549 4 2
light-panel/BorderR 223 540 4 4
light-panel/BorderT 228 540 4 4
light-panel/CornerBL 233 540 4 4
light-panel/CornerBR 238 540 4 4
light-panel/CornerTL 243 540 4 4
light-panel/CornerTR 248 540 4 4
light-panel/Fill 332 540 2 2
items/TapeCopper 202 707 16 16
items/TapeDiamond 219 707 16 16
items/TapeGold 236 707 16 16
items/TapeGreg 253 707 16 16
items/TapeIg 270 707 16 16
items/TapeIron 287 707 16 16
items/TapeNetherStar 304 707 16 16
items/TapeSteel 321 707 16 16
items/WirelessNetworkCard0 338 707 16 16
items/WirelessNetworkCard1 355 707 16 16
light-panel/BookmarkLeft 218 600 18 14
light-panel/BookmarkRight 197 600 20 14
light-panel/BorderB 296 305 4 4
light-panel/BorderL 284 314 4 2
light-panel/BorderR 301 305 4 4
light-panel/BorderT 306 305 4 4
light-panel/CornerBL 311 305 4 4
light-panel/CornerBR 316 305 4 4
light-panel/CornerTL 321 305 4 4
light-panel/CornerTR 326 305 4 4
light-panel/Fill 410 305 2 2
light-panel/Vent 356 434 2 38
nodes/Cable 377 445 8 8
nodes/Camera 375 674 16 16
nodes/Chest 348 655 14 14
nodes/HologramProjector0 392 674 16 16
nodes/HologramProjector1 409 674 16 16
nodes/IronNoteBlock 426 674 16 16
nodes/Lamp 443 674 16 16
nodes/LampFrame 460 674 16 16
nodes/Camera 372 707 16 16
nodes/Chest 283 540 14 14
nodes/HologramProjector0 389 707 16 16
nodes/HologramProjector1 406 707 16 16
nodes/IronNoteBlock 423 707 16 16
nodes/Lamp 440 707 16 16
nodes/LampFrame 457 707 16 16
nodes/LampGlow 49 305 128 128
nodes/NewNode 477 674 16 16
nodes/NoteBlock 494 674 16 16
nodes/OpenFMRadio 511 674 16 16
nodes/Relay 528 674 16 16
nodes/TapeDrive 545 674 16 16
nodes/computer/Default 562 674 16 16
nodes/computer/DiskActivity 579 674 16 16
nodes/computer/Error 596 674 16 16
nodes/computer/On 613 674 16 16
nodes/disk-drive/Default 630 674 16 16
nodes/disk-drive/DiskActivity 647 674 16 16
nodes/disk-drive/Floppy 664 674 16 16
nodes/NewNode 474 707 16 16
nodes/NoteBlock 491 707 16 16
nodes/OpenFMRadio 508 707 16 16
nodes/Relay 525 707 16 16
nodes/TapeDrive 542 707 16 16
nodes/computer/Default 559 707 16 16
nodes/computer/DiskActivity 576 707 16 16
nodes/computer/Error 593 707 16 16
nodes/computer/On 610 707 16 16
nodes/disk-drive/Default 627 707 16 16
nodes/disk-drive/DiskActivity 644 707 16 16
nodes/disk-drive/Floppy 661 707 16 16
nodes/holidays/Christmas 134 674 32 32
nodes/holidays/Halloween 167 674 32 32
nodes/holidays/Valentines 200 674 32 32
nodes/microcontroller/Default 681 674 16 16
nodes/microcontroller/Error 698 674 16 16
nodes/microcontroller/On 715 674 16 16
nodes/microcontroller/Default 678 707 16 16
nodes/microcontroller/Error 695 707 16 16
nodes/microcontroller/On 712 707 16 16
nodes/ocelot-block/Default 117 655 16 80
nodes/ocelot-block/Rx 732 674 16 16
nodes/ocelot-block/Tx 749 674 16 16
nodes/rack/Default 766 674 16 16
nodes/rack/Empty 783 674 16 16
nodes/rack/drive/0/Default 800 674 16 16
nodes/rack/drive/0/DiskActivity 817 674 16 16
nodes/rack/drive/0/Floppy 834 674 16 16
nodes/rack/drive/1/Default 851 674 16 16
nodes/rack/drive/1/DiskActivity 868 674 16 16
nodes/rack/drive/1/Floppy 885 674 16 16
nodes/rack/drive/2/Default 902 674 16 16
nodes/rack/drive/2/DiskActivity 919 674 16 16
nodes/rack/drive/2/Floppy 936 674 16 16
nodes/rack/drive/3/Default 953 674 16 16
nodes/rack/drive/3/DiskActivity 970 674 16 16
nodes/rack/drive/3/Floppy 987 674 16 16
nodes/rack/drive/Floppy 1004 674 16 16
nodes/rack/server/0/Default 134 707 16 16
nodes/rack/server/0/DiskActivity 151 707 16 16
nodes/rack/server/0/Error 168 707 16 16
nodes/rack/server/0/NetworkActivity 185 707 16 16
nodes/rack/server/0/On 202 707 16 16
nodes/rack/server/1/Default 219 707 16 16
nodes/rack/server/1/DiskActivity 236 707 16 16
nodes/rack/server/1/Error 253 707 16 16
nodes/rack/server/1/NetworkActivity 270 707 16 16
nodes/rack/server/1/On 287 707 16 16
nodes/rack/server/2/Default 304 707 16 16
nodes/rack/server/2/DiskActivity 321 707 16 16
nodes/rack/server/2/Error 338 707 16 16
nodes/rack/server/2/NetworkActivity 355 707 16 16
nodes/rack/server/2/On 372 707 16 16
nodes/rack/server/3/Default 389 707 16 16
nodes/rack/server/3/DiskActivity 406 707 16 16
nodes/rack/server/3/Error 423 707 16 16
nodes/rack/server/3/NetworkActivity 440 707 16 16
nodes/rack/server/3/On 457 707 16 16
nodes/raid/0/DiskActivity 474 707 16 16
nodes/raid/0/Error 491 707 16 16
nodes/raid/1/DiskActivity 508 707 16 16
nodes/raid/1/Error 525 707 16 16
nodes/raid/2/DiskActivity 542 707 16 16
nodes/raid/2/Error 559 707 16 16
nodes/raid/Default 576 707 16 16
nodes/screen/BottomLeft 593 707 16 16
nodes/screen/BottomMiddle 610 707 16 16
nodes/screen/BottomRight 627 707 16 16
nodes/screen/ColumnBottom 644 707 16 16
nodes/screen/ColumnMiddle 661 707 16 16
nodes/screen/ColumnTop 678 707 16 16
nodes/screen/Middle 695 707 16 16
nodes/screen/MiddleLeft 712 707 16 16
nodes/screen/MiddleRight 729 707 16 16
nodes/screen/PowerOnOverlay 746 707 16 16
nodes/screen/RowLeft 763 707 16 16
nodes/screen/RowMiddle 780 707 16 16
nodes/screen/RowRight 797 707 16 16
nodes/screen/Standalone 814 707 16 16
nodes/screen/TopLeft 831 707 16 16
nodes/screen/TopMiddle 848 707 16 16
nodes/screen/TopRight 865 707 16 16
panel/BorderB 253 540 4 4
panel/BorderL 211 549 4 2
panel/BorderR 258 540 4 4
panel/BorderT 263 540 4 4
panel/CornerBL 268 540 4 4
panel/CornerBR 273 540 4 4
panel/CornerTL 278 540 4 4
panel/CornerTR 283 540 4 4
panel/Fill 335 540 2 2
nodes/ocelot-block/Rx 729 707 16 16
nodes/ocelot-block/Tx 746 707 16 16
nodes/rack/Default 763 707 16 16
nodes/rack/Empty 780 707 16 16
nodes/rack/drive/0/Default 797 707 16 16
nodes/rack/drive/0/DiskActivity 814 707 16 16
nodes/rack/drive/0/Floppy 831 707 16 16
nodes/rack/drive/1/Default 848 707 16 16
nodes/rack/drive/1/DiskActivity 865 707 16 16
nodes/rack/drive/1/Floppy 882 707 16 16
nodes/rack/drive/2/Default 899 707 16 16
nodes/rack/drive/2/DiskActivity 916 707 16 16
nodes/rack/drive/2/Floppy 933 707 16 16
nodes/rack/drive/3/Default 950 707 16 16
nodes/rack/drive/3/DiskActivity 967 707 16 16
nodes/rack/drive/3/Floppy 984 707 16 16
nodes/rack/drive/Floppy 1001 707 16 16
nodes/rack/server/0/Default 266 655 16 16
nodes/rack/server/0/DiskActivity 283 655 16 16
nodes/rack/server/0/Error 300 655 16 16
nodes/rack/server/0/NetworkActivity 317 655 16 16
nodes/rack/server/0/On 334 655 16 16
nodes/rack/server/1/Default 351 655 16 16
nodes/rack/server/1/DiskActivity 368 655 16 16
nodes/rack/server/1/Error 385 655 16 16
nodes/rack/server/1/NetworkActivity 402 655 16 16
nodes/rack/server/1/On 419 655 16 16
nodes/rack/server/2/Default 436 655 16 16
nodes/rack/server/2/DiskActivity 453 655 16 16
nodes/rack/server/2/Error 470 655 16 16
nodes/rack/server/2/NetworkActivity 487 655 16 16
nodes/rack/server/2/On 504 655 16 16
nodes/rack/server/3/Default 521 655 16 16
nodes/rack/server/3/DiskActivity 538 655 16 16
nodes/rack/server/3/Error 555 655 16 16
nodes/rack/server/3/NetworkActivity 572 655 16 16
nodes/rack/server/3/On 589 655 16 16
nodes/raid/0/DiskActivity 606 655 16 16
nodes/raid/0/Error 623 655 16 16
nodes/raid/1/DiskActivity 640 655 16 16
nodes/raid/1/Error 657 655 16 16
nodes/raid/2/DiskActivity 674 655 16 16
nodes/raid/2/Error 691 655 16 16
nodes/raid/Default 708 655 16 16
nodes/screen/BottomLeft 725 655 16 16
nodes/screen/BottomMiddle 742 655 16 16
nodes/screen/BottomRight 759 655 16 16
nodes/screen/ColumnBottom 776 655 16 16
nodes/screen/ColumnMiddle 793 655 16 16
nodes/screen/ColumnTop 810 655 16 16
nodes/screen/Middle 827 655 16 16
nodes/screen/MiddleLeft 844 655 16 16
nodes/screen/MiddleRight 861 655 16 16
nodes/screen/PowerOnOverlay 878 655 16 16
nodes/screen/RowLeft 895 655 16 16
nodes/screen/RowMiddle 912 655 16 16
nodes/screen/RowRight 929 655 16 16
nodes/screen/Standalone 946 655 16 16
nodes/screen/TopLeft 963 655 16 16
nodes/screen/TopMiddle 980 655 16 16
nodes/screen/TopRight 997 655 16 16
panel/BorderB 331 305 4 4
panel/BorderL 289 314 4 2
panel/BorderR 336 305 4 4
panel/BorderT 341 305 4 4
panel/CornerBL 346 305 4 4
panel/CornerBR 351 305 4 4
panel/CornerTL 356 305 4 4
panel/CornerTR 361 305 4 4
panel/Fill 413 305 2 2
particles/Note 377 434 7 10
screen/InnerBorderB 203 556 2 4
screen/InnerBorderT 206 556 2 4
screen/InnerCornerBL 288 540 4 4
screen/InnerCornerBR 293 540 4 4
screen/InnerCornerTL 298 540 4 4
screen/InnerCornerTR 303 540 4 4
screen/OuterBorderT 203 549 2 6
particles/Smoke 134 567 8 64
screen/InnerBorderB 281 321 2 4
screen/InnerBorderT 284 321 2 4
screen/InnerCornerBL 366 305 4 4
screen/InnerCornerBR 371 305 4 4
screen/InnerCornerTL 376 305 4 4
screen/InnerCornerTR 381 305 4 4
screen/OuterBorderT 281 314 2 6
screen/OuterCornerBL 386 445 8 8
screen/OuterCornerBR 395 445 8 8
screen/OuterCornerTL 359 434 8 10
screen/OuterCornerTR 368 434 8 10
window/BorderDark 328 540 1 4
window/BorderLight 330 540 1 4
window/CornerBL 308 540 4 4
window/CornerBR 313 540 4 4
window/CornerTL 318 540 4 4
window/CornerTR 323 540 4 4
window/BorderDark 406 305 1 4
window/BorderLight 408 305 1 4
window/CornerBL 386 305 4 4
window/CornerBR 391 305 4 4
window/CornerTL 396 305 4 4
window/CornerTR 401 305 4 4
window/OpenFMRadio 474 0 232 105
window/case/Motherboard 123 434 79 70
window/rack/Lines 49 434 73 91
window/rack/Motherboard 178 305 100 78
window/rack/NetworkBack 215 561 1 2
window/rack/NetworkBottom 217 561 1 2
window/rack/NetworkConnector 219 561 1 2
window/rack/NetworkLeft 221 561 1 2
window/rack/NetworkRight 223 561 1 2
window/rack/NetworkTop 225 561 1 2
window/rack/NodeBack 209 556 5 1
window/rack/NodeBottom 215 556 5 1
window/rack/NodeLeft 221 556 5 1
window/rack/NodeRight 227 556 5 1
window/rack/NodeTop 233 556 5 1
window/rack/SideBack 203 561 1 3
window/rack/SideBottom 205 561 1 3
window/rack/SideConnector 207 561 1 3
window/rack/SideLeft 209 561 1 3
window/rack/SideRight 211 561 1 3
window/rack/SideTop 213 561 1 3
window/rack/NetworkBack 293 326 1 2
window/rack/NetworkBottom 295 326 1 2
window/rack/NetworkConnector 297 326 1 2
window/rack/NetworkLeft 299 326 1 2
window/rack/NetworkRight 301 326 1 2
window/rack/NetworkTop 303 326 1 2
window/rack/NodeBack 287 321 5 1
window/rack/NodeBottom 293 321 5 1
window/rack/NodeLeft 299 321 5 1
window/rack/NodeRight 305 321 5 1
window/rack/NodeTop 311 321 5 1
window/rack/SideBack 281 326 1 3
window/rack/SideBottom 283 326 1 3
window/rack/SideConnector 285 326 1 3
window/rack/SideLeft 287 326 1 3
window/rack/SideRight 289 326 1 3
window/rack/SideTop 291 326 1 3
window/raid/Slots 134 540 66 26
window/tape/Back 332 567 20 15
window/tape/BackPressed 353 567 20 15
window/tape/Forward 374 567 20 15
window/tape/ForwardPressed 395 567 20 15
window/tape/Play 416 567 20 15
window/tape/PlayPressed 437 567 20 15
window/tape/Back 341 567 20 15
window/tape/BackPressed 362 567 20 15
window/tape/Forward 383 567 20 15
window/tape/ForwardPressed 404 567 20 15
window/tape/Play 425 567 20 15
window/tape/PlayPressed 446 567 20 15
window/tape/Screen 134 526 146 13
window/tape/Stop 458 567 20 15
window/tape/StopPressed 479 567 20 15
window/tape/Stop 467 567 20 15
window/tape/StopPressed 488 567 20 15

View File

@ -44,6 +44,8 @@ object SoundBuffers extends Resource {
lazy val MinecraftClickRelease: SoundBuffer = load("/ocelot/desktop/sounds/minecraft/click_release.ogg")
lazy val MinecraftExplosion: SoundBuffer = load("/ocelot/desktop/sounds/minecraft/explosion.ogg")
lazy val SelfDestructingCardCountdownBeep: SoundBuffer = load("/ocelot/desktop/sounds/minecraft/countdown_beep.ogg")
lazy val NoteBlock: Map[String, SoundBuffer] = List(
"banjo", "basedrum", "bass", "bell", "bit", "chime", "cow_bell", "didgeridoo", "flute", "guitar",
"harp", "hat", "iron_xylophone", "pling", "snare", "xylophone",

View File

@ -132,4 +132,7 @@ object SoundSource {
lazy val MachineFloppyEject: SoundSource =
SoundSource.fromBuffer(SoundBuffers.MachineFloppyEject, SoundCategory.Environment)
lazy val SelfDestructingCardCountdownBeep: SoundSource =
SoundSource.fromBuffer(SoundBuffers.SelfDestructingCardCountdownBeep, SoundCategory.Environment)
}

View File

@ -1,5 +1,6 @@
package ocelot.desktop.color
import ocelot.desktop.geometry.FloatUtils.ExtendedFloat
import ocelot.desktop.geometry.Vector3D
import java.nio.ByteBuffer
@ -60,6 +61,15 @@ case class RGBAColorNorm(r: Float, g: Float, b: Float, a: Float = 1f) extends Co
HSVAColor(hue, saturation, value, a)
}
def lerp(dst: RGBAColorNorm, t: Float): RGBAColorNorm = {
RGBAColorNorm(
r.lerp(dst.r, t),
g.lerp(dst.g, t),
b.lerp(dst.b, t),
a.lerp(dst.a, t),
)
}
def withAlpha(alpha: Float): RGBAColorNorm = RGBAColorNorm(r, g, b, alpha)
// ʕʔ

View File

@ -345,7 +345,40 @@ class Graphics(private var width: Int, private var height: Int, private var scal
animation: Option[Animation] = None): Unit = {
sprite = name
foreground = color
_rect(x, y, width, height, fixUV = true, animation)
val spriteRect = animation match {
case Some(animation) =>
val duration = animation.frames.map(_._2).sum
var timeOffset = 0f
var curFrame = 0
breakable {
for ((idx, dur) <- animation.frames) {
timeOffset += dur
curFrame = idx
if (timeOffset >= time % duration) break
}
}
val size = animation.frameSize match {
case Some(size) => Size2D(this.spriteRect.w, this.spriteRect.w * size.height / size.width)
case None => Size2D(this.spriteRect.w, this.spriteRect.w)
}
Some(this.spriteRect.copy(y = this.spriteRect.y + curFrame * size.height, h = size.height))
case None => None
}
_rect(x, y, width, height, fixUV = true, spriteRect)
}
def sprite(name: String, x: Float, y: Float, width: Float, height: Float,
color: Color,
spriteRect: Rect2D): Unit = {
sprite = name
foreground = color
_rect(x, y, width, height, fixUV = true, Some(spriteRect))
}
def rect(r: Rect2D, color: Color): Unit = {
@ -368,28 +401,8 @@ class Graphics(private var width: Int, private var height: Int, private var scal
private def _rect(x: Float, y: Float, width: Float, height: Float,
fixUV: Boolean = true,
animation: Option[Animation] = None): Unit = {
val spriteRect = animation match {
case None => this.spriteRect
case Some(animation) =>
val duration = animation.frames.map(_._2).sum
var timeOffset = 0f
var curFrame = 0
breakable {
for ((idx, dur) <- animation.frames) {
timeOffset += dur
curFrame = idx
if (timeOffset >= time % duration) break
}
}
val size = animation.frameSize match {
case Some(size) => Size2D(this.spriteRect.w, this.spriteRect.w * size.height / size.width)
case None => Size2D(this.spriteRect.w, this.spriteRect.w)
}
this.spriteRect.copy(y = this.spriteRect.y + curFrame * size.height, h = size.height)
}
spriteRectOptional: Option[Rect2D] = None): Unit = {
val spriteRect = spriteRectOptional.getOrElse(this.spriteRect)
val uvTransform = Transform2D.translate(spriteRect.x, spriteRect.y) >>
(if (fixUV)

View File

@ -367,4 +367,10 @@ object IconSource {
val InnerBorderB: IconSource = IconSource(s"$prefix/InnerBorderB")
}
// ----------------------- Particles -----------------------
object Particles {
val Smoke: IconSource = IconSource("particles/Smoke")
}
}

View File

@ -22,7 +22,7 @@ class SelfDestructingCardItem(val card: SelfDestructingCard)
tooltip.addLine(
if (card.remainingTime < 0) "Fuse has not been set"
else if (card.remainingTime == 0) "BOOM!"
else card.remainingTime.toString
else f"Time to explosion: ${card.remainingTime / 20f}%.2fs"
)
}
}

View File

@ -0,0 +1,94 @@
package ocelot.desktop.node
import ocelot.desktop.audio.SoundSource
import ocelot.desktop.color.Color
import ocelot.desktop.geometry.FloatUtils.ExtendedFloat
import ocelot.desktop.graphics.{Graphics, IconSource}
import ocelot.desktop.inventory.item.SelfDestructingCardItem
import ocelot.desktop.node.BoomCardFxHandler.{ExpandIntensity, ExpandPeriod, FlickerAlpha, FlickerDuty, GlowAlpha, MaxSize, MinSize}
import ocelot.desktop.ui.UiHandler
import ocelot.desktop.ui.event.BrainEvent
import ocelot.desktop.{ColorScheme, OcelotDesktop}
import totoro.ocelot.brain.event.SelfDestructingCardBoomEvent
trait BoomCardFxHandler extends Node with PositionalSoundSourcesNode with SmokeParticleNode {
private var boomPhase: Float = -1
override def soundSources: Seq[SoundSource] = super.soundSources ++ Seq(
SoundSource.MinecraftExplosion,
SoundSource.SelfDestructingCardCountdownBeep,
)
eventHandlers += {
case BrainEvent(_: SelfDestructingCardBoomEvent) =>
OcelotDesktop.updateThreadTasks.add(() => {
SoundSource.MinecraftExplosion.play()
emitSmoke()
destroy()
})
}
protected def selfDestructingCards: IterableOnce[SelfDestructingCardItem]
private var phase = 0f
private var flickerPhase = 0f
private def updateBoomCardState(): Unit = {
phase = (phase + UiHandler.dt / ExpandPeriod) % 1f
flickerPhase = 0f.max(flickerPhase - UiHandler.dt)
boomPhase = -1
for (item <- selfDestructingCards) {
if (item.card.time > 0) {
// If multiple SDCs are ticking, let the most soon exploding one to define the glow
boomPhase = boomPhase.max(1 - item.card.time.toFloat / item.card.initialTime)
if (item.card.lastBeepTime < 0 || item.card.lastBeepTime - item.card.time >= 20) {
SoundSource.SelfDestructingCardCountdownBeep.play()
item.card.lastBeepTime = item.card.time
flickerPhase = FlickerDuty
}
}
}
}
override def update(): Unit = {
super.update()
updateBoomCardState()
}
private def expandFactor(phase: Float): Float = {
math.sin(2 * math.Pi * phase).toFloat
}
override def drawLight(g: Graphics): Unit = {
super.drawLight(g)
if (boomPhase > 0) {
val expand = expandFactor(phase)
val glowSize = MinSize.lerp(MaxSize, boomPhase + ExpandIntensity * expand)
val alpha = boomPhase * GlowAlpha
if (flickerPhase >= 0.01) {
g.rect(bounds, Color.White.withAlpha(FlickerAlpha * (1 - boomPhase)))
}
g.sprite(
IconSource.Nodes.Lamp.Glow,
position - size * glowSize,
size * (1 + 2 * glowSize),
ColorScheme("BoomCardGlowStart").lerp(ColorScheme("BoomCardGlowEnd"), boomPhase).withAlpha(alpha),
)
}
}
}
object BoomCardFxHandler {
private val ExpandPeriod = 1f
private val ExpandIntensity = 0.05f
private val FlickerDuty = 0.33f
private val FlickerAlpha = 0.05f
private val MinSize = 0.1f
private val MaxSize = 0.5f
private val GlowAlpha = 0.4f
}

View File

@ -1,6 +1,5 @@
package ocelot.desktop.node
import ocelot.desktop.{ColorScheme, OcelotDesktop, Settings => DesktopSettings}
import ocelot.desktop.audio._
import ocelot.desktop.graphics.{Graphics, IconSource}
import ocelot.desktop.inventory.SyncedInventory
@ -11,6 +10,7 @@ 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 ocelot.desktop.{ColorScheme, Settings => DesktopSettings}
import totoro.ocelot.brain.Settings
import totoro.ocelot.brain.entity.traits.{Entity, Environment, WorkspaceAware}
import totoro.ocelot.brain.event._
@ -18,10 +18,11 @@ import totoro.ocelot.brain.event._
import java.util.Calendar
abstract class ComputerAwareNode(entity: Entity with Environment with WorkspaceAware)
extends EntityNode(entity)
extends EntityNode(entity)
with SyncedInventory
with DiskActivityHandler
with OcelotLogParticleNode
with BoomCardFxHandler
with ShiftClickNode {
private lazy val soundCardSounds: (SoundStream, SoundSource) = Audio.newStream(SoundCategory.Records)
@ -50,12 +51,6 @@ abstract class ComputerAwareNode(entity: Entity with Environment with WorkspaceA
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()
destroy()
})
}
protected def drawOverlay(g: Graphics): Unit = HolidayIcon match {

View File

@ -6,7 +6,7 @@ import ocelot.desktop.{OcelotDesktop, Settings}
trait PositionalSoundSourcesNode extends Node {
// Every node can have multiple sound sources playing at the same time
def soundSources: Seq[SoundSource]
def soundSources: Seq[SoundSource] = Seq()
override def update(): Unit = {
super.update()

View File

@ -0,0 +1,79 @@
package ocelot.desktop.node
import ocelot.desktop.color.RGBAColorNorm
import ocelot.desktop.geometry.{Size2D, Vector2D}
import ocelot.desktop.graphics.{Graphics, IconSource}
import ocelot.desktop.node.SmokeParticleNode._
import ocelot.desktop.ui.UiHandler
import ocelot.desktop.ui.particle.Particle
import ocelot.desktop.util.Spritesheet
import scala.util.Random
trait SmokeParticleNode extends Node {
protected def emitSmoke(): Unit = synchronized {
for (_ <- 1 to randomCount) {
UiHandler.root.workspaceView.particleSystem.add(new SmokeParticle)
}
}
private class SmokeParticle extends Particle(ttl = randomDuration) {
private val color: RGBAColorNorm = randomColor
private var velocity: Vector2D = Vector2D(randomVelocityComponent, randomVelocityComponent)
private var offset: Vector2D = Vector2D(0, 0)
override def update(dt: Float): Unit = {
time += dt
offset += (velocity + SmokeParticleVolatilizationSpeed) * dt * speed
velocity *= math.pow(SmokeParticleVelocityDamping, dt)
}
override def draw(g: Graphics): Unit = {
val spriteRect = Spritesheet.sprites(IconSource.Particles.Smoke.path)
val animationFrameCount = spriteRect.h / spriteRect.w
val animationFrame = (time / ttl * animationFrameCount).toInt
val particlePosition = bounds.center + offset - SmokeParticleSize.toVector * .5f
g.sprite(
IconSource.Particles.Smoke.path,
particlePosition.x,
particlePosition.y,
SmokeParticleSize.width,
SmokeParticleSize.height,
color,
spriteRect.copy(
y = spriteRect.y + animationFrame * spriteRect.w,
h = spriteRect.w,
),
)
}
}
}
private object SmokeParticleNode {
private final val SmokeParticleSize: Size2D = Size2D(32, 32)
private final val SmokeParticleVelocityRange: Float = 300
private final val SmokeParticleVolatilizationSpeed: Vector2D = Vector2D(0, -50)
private final val SmokeParticleVelocityDamping: Float = .1f
private final val SmokeParticleCount: (Int, Int) = (10, 20)
private final val SmokeParticleAnimationDuration: (Float, Float) = (1f, 4f)
private def randomVelocityComponent: Float = Random.between(
-SmokeParticleVelocityRange,
SmokeParticleVelocityRange,
)
private def randomColor: RGBAColorNorm = {
val channel = Random.between(.5f, .9f)
RGBAColorNorm(channel, channel, channel)
}
private def randomDuration: Float = Random.between(
SmokeParticleAnimationDuration._1,
SmokeParticleAnimationDuration._2,
)
private def randomCount: Int = Random.between(
SmokeParticleCount._1,
SmokeParticleCount._2,
)
}

View File

@ -2,6 +2,7 @@ package ocelot.desktop.node.nodes
import ocelot.desktop.color.Color
import ocelot.desktop.graphics.{Graphics, IconSource}
import ocelot.desktop.inventory.item.SelfDestructingCardItem
import ocelot.desktop.node.Node.HighlightThickness
import ocelot.desktop.node.{ComputerAwareNode, WindowedNode}
import ocelot.desktop.ui.event.ClickEvent
@ -15,7 +16,10 @@ import totoro.ocelot.brain.entity.traits.Inventory
import totoro.ocelot.brain.util.Tier
class ComputerNode(val computerCase: Case)
extends ComputerAwareNode(computerCase) with AudibleComputerAware with WindowedNode[ComputerWindow] {
extends ComputerAwareNode(computerCase)
with AudibleComputerAware
with WindowedNode[ComputerWindow] {
override val iconSource: IconSource = IconSource.Nodes.Computer.Default
override def iconColor: Color = TierColor.get(computerCase.tier)
@ -30,6 +34,12 @@ class ComputerNode(val computerCase: Case)
super.setupContextMenu(menu, event)
}
override protected def selfDestructingCards: IterableOnce[SelfDestructingCardItem] = {
inventoryIterator.flatMap(_.get).collect {
case item: SelfDestructingCardItem => item
}
}
override def update(): Unit = {
super.update()

View File

@ -20,6 +20,7 @@ class MicrocontrollerNode(val microcontroller: Microcontroller)
with ComputerAware
with DefaultSlotItemsFillable
with WindowedNode[ComputerWindow] {
override val iconSource: IconSource = IconSource.Nodes.Microcontroller.Default
override def setupContextMenu(menu: ContextMenu, event: ClickEvent): Unit = {
@ -67,6 +68,12 @@ class MicrocontrollerNode(val microcontroller: Microcontroller)
override def computerType: ComputerType = ComputerType.Microcontroller
override def brainInventory: Inventory = microcontroller.inventory.owner
override protected def selfDestructingCards: IterableOnce[SelfDestructingCardItem] = {
inventoryIterator.flatMap(_.get).collect {
case item: SelfDestructingCardItem => item
}
}
override def addSlotsBasedOnTier(): Unit = {
microcontroller.tier match {
case Tier.One =>

View File

@ -3,7 +3,7 @@ package ocelot.desktop.node.nodes
import ocelot.desktop.geometry.{Rect2D, Size2D, Vector2D}
import ocelot.desktop.graphics.{Graphics, IconSource}
import ocelot.desktop.inventory.Item
import ocelot.desktop.inventory.item.{DiskDriveMountableItem, ServerItem}
import ocelot.desktop.inventory.item.{DiskDriveMountableItem, SelfDestructingCardItem, ServerItem}
import ocelot.desktop.inventory.traits.RackMountableItem
import ocelot.desktop.node.Node.{HighlightThickness, NoHighlightSize, Size, TexelCount}
import ocelot.desktop.node.{ComputerAwareNode, NodePort, WindowedNode}
@ -45,6 +45,15 @@ class RackNode(val rack: Rack) extends ComputerAwareNode(rack) with WindowedNode
}
}
override protected def selfDestructingCards: IterableOnce[SelfDestructingCardItem] = {
inventoryIterator.flatMap(_.get).collect({
case item: ServerItem =>
item.inventoryIterator.flatMap(_.get).collect {
case card: SelfDestructingCardItem => card
}
}).flatten
}
override def setupContextMenu(menu: ContextMenu, event: ClickEvent): Unit = {
RackNode.addContextMenuEntriesOfMountable(menu, getMountableByClick(event))

View File

@ -72,7 +72,7 @@ class TapeDriveNode(val tapeDrive: TapeDrive)
// -------------------------------- PositionalSoundSourcesNode --------------------------------
override def soundSources: Seq[SoundSource] = Seq(source)
override def soundSources: Seq[SoundSource] = super.soundSources ++ Seq(source)
// -------------------------------- Inventory --------------------------------

View File

@ -2,7 +2,7 @@ package ocelot.desktop.util
import ocelot.desktop.graphics.IconSource
import ocelot.desktop.inventory.item._
import ocelot.desktop.inventory.traits.ComponentItem
import ocelot.desktop.inventory.traits.EntityItem
import ocelot.desktop.inventory.{Item, SyncedInventory}
import ocelot.desktop.ui.widget.contextmenu.{ContextMenu, ContextMenuEntry, ContextMenuIcon, ContextMenuSubmenu}
import ocelot.desktop.ui.widget.slot._
@ -18,7 +18,7 @@ import scala.math.Ordering.Implicits.infixOrderingOps
import scala.reflect.ClassTag
trait ComputerAware extends Logging with SyncedInventory with DefaultSlotItemsFillable with Windowed[ComputerWindow] {
override type I = Item with ComponentItem
override type I = Item with EntityItem
def computer: Computer with TieredPersistable

View File

@ -1,6 +1,6 @@
package ocelot.desktop.util
import ocelot.desktop.geometry.{Rect2D, Size2D}
import ocelot.desktop.geometry.{Rect2D, Size2D, Vector2D}
import ocelot.desktop.graphics.{IconSource, Texture}
import javax.imageio.ImageIO