From 14c77736e7829cbfd52fb30979e9db8f24ed8dfd Mon Sep 17 00:00:00 2001 From: Tim Date: Fri, 3 Apr 2026 09:25:31 -0500 Subject: [PATCH] Slot Machine DLC - Diversified Debt for Every Department (#95513) ## About The Pull Request This PR takes the improvements from: - #95313 And builds on it quite a bit. Slots now have: - New symbol icons based on SS13 objects instead of Font Awesome icons - Several new slot machine subtypes for every department - New slot machine random spawner that is used to replace all slot machines on all maps - ~~Greyscaled the slot machine sprite and replaced it with GAGs (to color them by department)~~ - New rare trap/hazard abilities depending on symbols (syndiebomb = flashbang, handcuffs = cuff, singulo = shock, etc.) - Syndie slot machine that comes preinstalled in all syndie outposts/nuke bases - Slot machines circuits can be configured with a screwdriver to change the type and emagging results in the syndicate version - Tweaked the pixel offset for the jackpot flashing icon so it is in the correct position - Improved the name generator with more adjectives and nouns for all subtypes (ex. clown slot machine = "Lucky Giggles") - IDs and Department budget cards can be linked as the owner of the slot machine, however NT takes a 40% cut off the profits since jackpots/bonus spins are paid out by NT ##### And yes... there is a clown and mime subtype... honk ## Why It's Good For The Game dreamseeker_t8lLODECva Better slot machine icons and code. ## Changelog :cl: add: To help cover budget expenses, NT has redesigned and installed new slot machines that are themed by department. Slot machines can also be linked to bank accounts via ID cards or department budget cards. NT takes a 40% cut of profit to payout major jackpots and bonus spins. Please gamble responsibly. map: Replaced all slot machines with slot machine random spawners. Added syndicate slot machines to Syndicate bases and nuke outposts. /:cl: --------- Co-authored-by: Lucy --- .../LavaRuins/lavaland_biodome_beach.dmm | 2 +- .../lavaland_surface_syndicate_base1.dmm | 1 + .../SpaceRuins/listeningstation.dmm | 6 +- _maps/RandomZLevels/SnowCabin.dmm | 2 +- _maps/RandomZLevels/TheBeach.dmm | 2 +- .../CatwalkStation/CatwalkStation_2023.dmm | 18 +- .../map_files/Deltastation/DeltaStation2.dmm | 4 +- .../map_files/IceBoxStation/IceBoxStation.dmm | 6 +- _maps/map_files/MetaStation/MetaStation.dmm | 10 +- .../map_files/NebulaStation/NebulaStation.dmm | 8 +- _maps/map_files/tramstation/tramstation.dmm | 6 +- _maps/map_files/wawastation/wawastation.dmm | 12 +- _maps/shuttles/emergency_casino.dmm | 10 +- _maps/shuttles/emergency_discoinferno.dmm | 4 +- _maps/shuttles/hunter_psyker.dmm | 2 +- _maps/templates/lazy_templates/nukie_base.dmm | 1 + _maps/virtual_domains/beach_bar.dmm | 2 +- .../virtual_domains/fredingtonfastingbear.dmm | 2 +- _maps/virtual_domains/island_brawl.dmm | 2 +- code/game/machinery/slotmachine.dm | 420 +++++++++++++++--- .../effects/spawners/random/entertainment.dm | 17 + .../circuitboards/computer_circuitboards.dm | 44 ++ .../asset_cache/assets/slot_machines.dm | 24 + icons/effects/random_spawners.dmi | Bin 97950 -> 98522 bytes tgstation.dme | 1 + tgui/packages/tgui/interfaces/SlotMachine.tsx | 196 ++++---- .../tgui/styles/interfaces/SlotMachine.scss | 23 +- 27 files changed, 637 insertions(+), 188 deletions(-) create mode 100644 code/modules/asset_cache/assets/slot_machines.dm diff --git a/_maps/RandomRuins/LavaRuins/lavaland_biodome_beach.dmm b/_maps/RandomRuins/LavaRuins/lavaland_biodome_beach.dmm index 2e6a25bdab3..caf994011d8 100644 --- a/_maps/RandomRuins/LavaRuins/lavaland_biodome_beach.dmm +++ b/_maps/RandomRuins/LavaRuins/lavaland_biodome_beach.dmm @@ -1075,7 +1075,7 @@ /turf/closed/wall/mineral/sandstone, /area/ruin/powered/beach) "NJ" = ( -/obj/machinery/computer/slot_machine, +/obj/effect/spawner/random/entertainment/slot_machine, /turf/open/floor/wood, /area/ruin/powered/beach) "NK" = ( diff --git a/_maps/RandomRuins/LavaRuins/lavaland_surface_syndicate_base1.dmm b/_maps/RandomRuins/LavaRuins/lavaland_surface_syndicate_base1.dmm index b79b3650238..4a71ef27f78 100644 --- a/_maps/RandomRuins/LavaRuins/lavaland_surface_syndicate_base1.dmm +++ b/_maps/RandomRuins/LavaRuins/lavaland_surface_syndicate_base1.dmm @@ -4099,6 +4099,7 @@ "Ue" = ( /obj/effect/decal/cleanable/dirt, /obj/effect/turf_decal/tile/neutral/fourcorners, +/obj/machinery/computer/slot_machine/syndicate, /turf/open/floor/iron/dark, /area/ruin/syndicate_lava_base/bar) "Um" = ( diff --git a/_maps/RandomRuins/SpaceRuins/listeningstation.dmm b/_maps/RandomRuins/SpaceRuins/listeningstation.dmm index cb069a04b11..0ce9d1fb7c4 100644 --- a/_maps/RandomRuins/SpaceRuins/listeningstation.dmm +++ b/_maps/RandomRuins/SpaceRuins/listeningstation.dmm @@ -186,6 +186,10 @@ /obj/machinery/hydroponics/soil, /turf/open/floor/iron, /area/ruin/space/has_grav/listeningstation) +"iN" = ( +/obj/machinery/computer/slot_machine/syndicate, +/turf/open/floor/plating, +/area/ruin/space/has_grav/listeningstation) "jr" = ( /obj/machinery/power/port_gen/pacman{ anchored = 1 @@ -1346,7 +1350,7 @@ FV ca BX dW -We +iN JB vI vI diff --git a/_maps/RandomZLevels/SnowCabin.dmm b/_maps/RandomZLevels/SnowCabin.dmm index 52579ccdacc..d164796beab 100644 --- a/_maps/RandomZLevels/SnowCabin.dmm +++ b/_maps/RandomZLevels/SnowCabin.dmm @@ -639,7 +639,7 @@ /turf/open/floor/wood, /area/awaymission/cabin) "cN" = ( -/obj/machinery/computer/slot_machine, +/obj/effect/spawner/random/entertainment/slot_machine, /turf/open/floor/carpet, /area/awaymission/cabin) "cO" = ( diff --git a/_maps/RandomZLevels/TheBeach.dmm b/_maps/RandomZLevels/TheBeach.dmm index 1cecb4bebfe..3eb04da8ee6 100644 --- a/_maps/RandomZLevels/TheBeach.dmm +++ b/_maps/RandomZLevels/TheBeach.dmm @@ -4026,7 +4026,7 @@ /obj/structure/sign/directions/medical/directional/north{ pixel_y = 29 }, -/obj/machinery/computer/slot_machine, +/obj/effect/spawner/random/entertainment/slot_machine, /turf/open/floor/wood/large, /area/awaymission/beach) "Zt" = ( diff --git a/_maps/map_files/CatwalkStation/CatwalkStation_2023.dmm b/_maps/map_files/CatwalkStation/CatwalkStation_2023.dmm index fe79d7aa3aa..3ad6324e364 100644 --- a/_maps/map_files/CatwalkStation/CatwalkStation_2023.dmm +++ b/_maps/map_files/CatwalkStation/CatwalkStation_2023.dmm @@ -10861,7 +10861,7 @@ /turf/open/floor/iron, /area/station/hallway/secondary/construction) "cOJ" = ( -/obj/machinery/computer/slot_machine{ +/obj/effect/spawner/random/entertainment/slot_machine{ pixel_y = 2 }, /obj/effect/decal/cleanable/glitter, @@ -24017,7 +24017,7 @@ "goW" = ( /obj/effect/decal/cleanable/cobweb/cobweb2, /obj/effect/decal/cleanable/dirt, -/obj/machinery/computer/slot_machine{ +/obj/effect/spawner/random/entertainment/slot_machine{ pixel_y = 2 }, /turf/open/floor/wood, @@ -31604,7 +31604,7 @@ "itr" = ( /obj/effect/turf_decal/siding/thinplating_new/dark, /obj/structure/extinguisher_cabinet/directional/south, -/obj/machinery/computer/slot_machine{ +/obj/effect/spawner/random/entertainment/slot_machine{ pixel_y = 2 }, /turf/open/floor/iron/dark/smooth_large, @@ -33224,7 +33224,7 @@ /turf/open/floor/iron/white, /area/station/hallway/secondary/entry) "iPv" = ( -/obj/machinery/computer/slot_machine{ +/obj/effect/spawner/random/entertainment/slot_machine{ pixel_y = 2 }, /obj/effect/decal/cleanable/dirt, @@ -60940,7 +60940,7 @@ /turf/open/floor/iron, /area/station/maintenance/starboard/aft) "qjy" = ( -/obj/machinery/computer/slot_machine{ +/obj/effect/spawner/random/entertainment/slot_machine{ pixel_y = 2 }, /turf/open/floor/iron, @@ -63099,7 +63099,7 @@ /turf/open/floor/iron/dark/textured, /area/station/cargo/sorting) "qNo" = ( -/obj/machinery/computer/slot_machine{ +/obj/effect/spawner/random/entertainment/slot_machine{ pixel_y = 2 }, /obj/effect/decal/cleanable/blood/oil, @@ -65052,7 +65052,7 @@ /turf/open/floor/iron, /area/station/science/research) "rpq" = ( -/obj/machinery/computer/slot_machine{ +/obj/effect/spawner/random/entertainment/slot_machine{ pixel_y = 2 }, /turf/open/floor/plating, @@ -79748,7 +79748,7 @@ /turf/open/floor/iron/dark, /area/station/service/chapel) "vgV" = ( -/obj/machinery/computer/slot_machine{ +/obj/effect/spawner/random/entertainment/slot_machine{ pixel_y = 2 }, /obj/effect/decal/cleanable/dirt, @@ -84488,7 +84488,7 @@ /turf/open/floor/iron, /area/station/cargo/storage) "wtN" = ( -/obj/machinery/computer/slot_machine{ +/obj/effect/spawner/random/entertainment/slot_machine{ pixel_y = 2 }, /obj/effect/decal/cleanable/vomit/old, diff --git a/_maps/map_files/Deltastation/DeltaStation2.dmm b/_maps/map_files/Deltastation/DeltaStation2.dmm index ab953026673..c9d741ff81e 100644 --- a/_maps/map_files/Deltastation/DeltaStation2.dmm +++ b/_maps/map_files/Deltastation/DeltaStation2.dmm @@ -3868,7 +3868,7 @@ /obj/structure/disposalpipe/segment{ dir = 4 }, -/obj/machinery/computer/slot_machine, +/obj/effect/spawner/random/entertainment/slot_machine, /obj/effect/decal/cleanable/dirt, /obj/effect/turf_decal/tile/neutral/half/contrasted{ dir = 1 @@ -56213,7 +56213,7 @@ /obj/structure/disposalpipe/segment{ dir = 10 }, -/obj/machinery/computer/slot_machine, +/obj/effect/spawner/random/entertainment/slot_machine, /obj/effect/turf_decal/tile/neutral{ dir = 1 }, diff --git a/_maps/map_files/IceBoxStation/IceBoxStation.dmm b/_maps/map_files/IceBoxStation/IceBoxStation.dmm index 1dc2cef08cc..ddd0b28d8f1 100644 --- a/_maps/map_files/IceBoxStation/IceBoxStation.dmm +++ b/_maps/map_files/IceBoxStation/IceBoxStation.dmm @@ -17243,7 +17243,7 @@ /obj/machinery/camera/directional/east{ c_tag = "Service - Gambling Lounge" }, -/obj/machinery/computer/slot_machine{ +/obj/effect/spawner/random/entertainment/slot_machine{ name = "two-armed bandit" }, /turf/open/floor/wood/large, @@ -28771,7 +28771,7 @@ /area/station/security/prison/rec) "ibJ" = ( /obj/item/radio/intercom/directional/east, -/obj/machinery/computer/slot_machine{ +/obj/effect/spawner/random/entertainment/slot_machine{ name = "two-armed bandit" }, /turf/open/floor/wood/large, @@ -52934,7 +52934,7 @@ /turf/open/floor/iron/grimy, /area/station/maintenance/aft/greater) "oMP" = ( -/obj/machinery/computer/slot_machine, +/obj/effect/spawner/random/entertainment/slot_machine, /turf/open/floor/wood, /area/station/command/meeting_room) "oMR" = ( diff --git a/_maps/map_files/MetaStation/MetaStation.dmm b/_maps/map_files/MetaStation/MetaStation.dmm index fcfef778c10..0b681656f74 100644 --- a/_maps/map_files/MetaStation/MetaStation.dmm +++ b/_maps/map_files/MetaStation/MetaStation.dmm @@ -11658,7 +11658,7 @@ /turf/open/floor/iron, /area/station/service/hydroponics) "ebG" = ( -/obj/machinery/computer/slot_machine{ +/obj/effect/spawner/random/entertainment/slot_machine{ pixel_y = 2 }, /obj/effect/mapping_helpers/broken_floor, @@ -12536,7 +12536,7 @@ /turf/open/floor/wood, /area/station/commons/lounge) "eov" = ( -/obj/machinery/computer/slot_machine{ +/obj/effect/spawner/random/entertainment/slot_machine{ pixel_y = 2 }, /obj/effect/mapping_helpers/broken_floor, @@ -22916,7 +22916,7 @@ /turf/open/floor/engine, /area/station/science/xenobiology) "hWj" = ( -/obj/machinery/computer/slot_machine{ +/obj/effect/spawner/random/entertainment/slot_machine{ pixel_y = 2 }, /turf/open/floor/wood, @@ -40886,7 +40886,7 @@ /area/station/command/bridge) "nXG" = ( /obj/machinery/newscaster/directional/north, -/obj/machinery/computer/slot_machine{ +/obj/effect/spawner/random/entertainment/slot_machine{ pixel_y = 2 }, /obj/effect/turf_decal/tile/bar/opposingcorners, @@ -51307,7 +51307,7 @@ /area/station/security/interrogation) "rzi" = ( /obj/machinery/airalarm/directional/north, -/obj/machinery/computer/slot_machine{ +/obj/effect/spawner/random/entertainment/slot_machine{ pixel_y = 2 }, /obj/effect/turf_decal/tile/bar/opposingcorners, diff --git a/_maps/map_files/NebulaStation/NebulaStation.dmm b/_maps/map_files/NebulaStation/NebulaStation.dmm index 39dc26cc6e4..0060c13dc5a 100644 --- a/_maps/map_files/NebulaStation/NebulaStation.dmm +++ b/_maps/map_files/NebulaStation/NebulaStation.dmm @@ -90828,7 +90828,7 @@ /obj/effect/turf_decal/siding/wood{ dir = 6 }, -/obj/machinery/computer/slot_machine, +/obj/effect/spawner/random/entertainment/slot_machine, /obj/effect/turf_decal/siding/wood/corner{ dir = 1 }, @@ -137223,7 +137223,7 @@ /obj/effect/turf_decal/siding/wood{ dir = 5 }, -/obj/machinery/computer/slot_machine, +/obj/effect/spawner/random/entertainment/slot_machine, /obj/effect/turf_decal/siding/wood/corner{ dir = 8 }, @@ -139659,7 +139659,7 @@ /turf/open/floor/wood, /area/station/security/courtroom) "uFM" = ( -/obj/machinery/computer/slot_machine, +/obj/effect/spawner/random/entertainment/slot_machine, /obj/effect/turf_decal/siding/wood{ dir = 6 }, @@ -150211,7 +150211,7 @@ /turf/open/floor/wood/large, /area/station/service/library/upper) "wiG" = ( -/obj/machinery/computer/slot_machine, +/obj/effect/spawner/random/entertainment/slot_machine, /obj/effect/turf_decal/siding/wood{ dir = 10 }, diff --git a/_maps/map_files/tramstation/tramstation.dmm b/_maps/map_files/tramstation/tramstation.dmm index 6edd7fc9d11..bc99abb402b 100644 --- a/_maps/map_files/tramstation/tramstation.dmm +++ b/_maps/map_files/tramstation/tramstation.dmm @@ -12214,7 +12214,7 @@ /turf/open/floor/iron/dark, /area/station/medical/morgue) "dds" = ( -/obj/machinery/computer/slot_machine{ +/obj/effect/spawner/random/entertainment/slot_machine{ pixel_y = 2 }, /obj/machinery/light/cold/directional/north, @@ -12503,7 +12503,7 @@ /turf/open/floor/iron/dark, /area/station/ai/satellite/foyer) "diN" = ( -/obj/machinery/computer/slot_machine{ +/obj/effect/spawner/random/entertainment/slot_machine{ pixel_y = 2 }, /turf/open/floor/iron/dark, @@ -67354,7 +67354,7 @@ /turf/open/floor/wood, /area/station/service/bar/backroom) "wwj" = ( -/obj/machinery/computer/slot_machine{ +/obj/effect/spawner/random/entertainment/slot_machine{ pixel_y = 2 }, /obj/machinery/light/cold/directional/south, diff --git a/_maps/map_files/wawastation/wawastation.dmm b/_maps/map_files/wawastation/wawastation.dmm index 2a439748deb..5ce45523ec0 100644 --- a/_maps/map_files/wawastation/wawastation.dmm +++ b/_maps/map_files/wawastation/wawastation.dmm @@ -5627,7 +5627,7 @@ "bXx" = ( /obj/machinery/camera/autoname/directional/south, /obj/machinery/airalarm/directional/south, -/obj/machinery/computer/slot_machine{ +/obj/effect/spawner/random/entertainment/slot_machine{ pixel_y = 2 }, /turf/open/floor/wood, @@ -6753,7 +6753,7 @@ /turf/open/floor/glass/reinforced, /area/station/security/prison) "ctP" = ( -/obj/machinery/computer/slot_machine, +/obj/effect/spawner/random/entertainment/slot_machine, /obj/effect/decal/cleanable/dirt/dust, /obj/effect/decal/cleanable/dirt, /turf/open/floor/iron/grimy, @@ -39342,7 +39342,7 @@ /turf/closed/wall/r_wall, /area/station/maintenance/central/greater) "nzw" = ( -/obj/machinery/computer/slot_machine, +/obj/effect/spawner/random/entertainment/slot_machine, /obj/effect/turf_decal/sand/plating, /turf/open/floor/plating, /area/station/maintenance/central/greater) @@ -41216,7 +41216,7 @@ /turf/open/floor/iron, /area/station/hallway/primary/central) "olC" = ( -/obj/machinery/computer/slot_machine, +/obj/effect/spawner/random/entertainment/slot_machine, /obj/effect/decal/cleanable/dirt/dust, /obj/effect/decal/cleanable/dirt, /obj/machinery/light/small/directional/west, @@ -62694,7 +62694,7 @@ "vxl" = ( /obj/machinery/power/apc/auto_name/directional/south, /obj/structure/cable, -/obj/machinery/computer/slot_machine{ +/obj/effect/spawner/random/entertainment/slot_machine{ pixel_y = 2 }, /turf/open/floor/wood, @@ -63653,7 +63653,7 @@ /turf/open/floor/iron/white/smooth_large, /area/station/science/research) "vNT" = ( -/obj/machinery/computer/slot_machine, +/obj/effect/spawner/random/entertainment/slot_machine, /obj/effect/decal/cleanable/dirt/dust, /turf/open/floor/iron/grimy, /area/station/maintenance/central/lesser) diff --git a/_maps/shuttles/emergency_casino.dmm b/_maps/shuttles/emergency_casino.dmm index 1bfe4744198..e4521dc80b6 100644 --- a/_maps/shuttles/emergency_casino.dmm +++ b/_maps/shuttles/emergency_casino.dmm @@ -33,7 +33,7 @@ /turf/open/floor/wood, /area/shuttle/escape) "bT" = ( -/obj/machinery/computer/slot_machine, +/obj/effect/spawner/random/entertainment/slot_machine, /obj/structure/window/reinforced/spawner/directional/west, /obj/structure/window/reinforced/spawner/directional/north, /turf/open/floor/carpet/green, @@ -431,7 +431,7 @@ /turf/open/floor/carpet/royalblue, /area/shuttle/escape) "mx" = ( -/obj/machinery/computer/slot_machine, +/obj/effect/spawner/random/entertainment/slot_machine, /obj/structure/window/reinforced/spawner/directional/east, /obj/structure/window/reinforced/spawner/directional/north, /turf/open/floor/carpet/green, @@ -509,7 +509,7 @@ /turf/open/floor/mineral/plastitanium/red, /area/shuttle/escape/brig) "oB" = ( -/obj/machinery/computer/slot_machine, +/obj/effect/spawner/random/entertainment/slot_machine, /obj/structure/window/reinforced/spawner/directional/north, /turf/open/floor/carpet/green, /area/shuttle/escape) @@ -739,7 +739,7 @@ /turf/open/floor/sepia, /area/shuttle/escape) "we" = ( -/obj/machinery/computer/slot_machine, +/obj/effect/spawner/random/entertainment/slot_machine, /obj/effect/turf_decal/siding/thinplating{ dir = 8 }, @@ -911,7 +911,7 @@ /turf/open/floor/mineral/plastitanium/red, /area/shuttle/escape/brig) "Bf" = ( -/obj/machinery/computer/slot_machine, +/obj/effect/spawner/random/entertainment/slot_machine, /turf/open/floor/carpet/green, /area/shuttle/escape) "Bj" = ( diff --git a/_maps/shuttles/emergency_discoinferno.dmm b/_maps/shuttles/emergency_discoinferno.dmm index d6dedd686af..73a76ec0556 100644 --- a/_maps/shuttles/emergency_discoinferno.dmm +++ b/_maps/shuttles/emergency_discoinferno.dmm @@ -122,7 +122,7 @@ /turf/open/floor/wood, /area/shuttle/escape) "C" = ( -/obj/machinery/computer/slot_machine, +/obj/effect/spawner/random/entertainment/slot_machine, /obj/machinery/light/directional/west, /turf/open/floor/wood, /area/shuttle/escape) @@ -160,7 +160,7 @@ /turf/open/floor/wood, /area/shuttle/escape) "I" = ( -/obj/machinery/computer/slot_machine, +/obj/effect/spawner/random/entertainment/slot_machine, /turf/open/floor/wood, /area/shuttle/escape) "J" = ( diff --git a/_maps/shuttles/hunter_psyker.dmm b/_maps/shuttles/hunter_psyker.dmm index b16650013c9..3aff0d2eed0 100644 --- a/_maps/shuttles/hunter_psyker.dmm +++ b/_maps/shuttles/hunter_psyker.dmm @@ -273,7 +273,7 @@ /area/shuttle/hunter) "lD" = ( /obj/machinery/atmospherics/pipe/smart/manifold4w/supply/hidden, -/obj/machinery/computer/slot_machine, +/obj/effect/spawner/random/entertainment/slot_machine, /obj/effect/decal/cleanable/wrapping, /turf/open/floor/iron/grimy, /area/shuttle/hunter) diff --git a/_maps/templates/lazy_templates/nukie_base.dmm b/_maps/templates/lazy_templates/nukie_base.dmm index 7d87dc7d4e6..537fe8fda84 100644 --- a/_maps/templates/lazy_templates/nukie_base.dmm +++ b/_maps/templates/lazy_templates/nukie_base.dmm @@ -3633,6 +3633,7 @@ /area/centcom/syndicate_mothership/control) "Ni" = ( /obj/machinery/light/small/directional/north, +/obj/machinery/computer/slot_machine/syndicate, /turf/open/floor/wood/tile, /area/centcom/syndicate_mothership/control) "No" = ( diff --git a/_maps/virtual_domains/beach_bar.dmm b/_maps/virtual_domains/beach_bar.dmm index e3e4a09e96b..a41b0c87d93 100644 --- a/_maps/virtual_domains/beach_bar.dmm +++ b/_maps/virtual_domains/beach_bar.dmm @@ -1006,7 +1006,7 @@ /turf/open/floor/wood, /area/virtual_domain/fullbright) "VA" = ( -/obj/machinery/computer/slot_machine, +/obj/effect/spawner/random/entertainment/slot_machine, /turf/open/floor/wood, /area/virtual_domain/fullbright) "VE" = ( diff --git a/_maps/virtual_domains/fredingtonfastingbear.dmm b/_maps/virtual_domains/fredingtonfastingbear.dmm index e28813d8c94..24174de946b 100644 --- a/_maps/virtual_domains/fredingtonfastingbear.dmm +++ b/_maps/virtual_domains/fredingtonfastingbear.dmm @@ -362,7 +362,7 @@ /turf/open/floor/iron/kitchen, /area/virtual_domain) "sk" = ( -/obj/machinery/computer/slot_machine, +/obj/effect/spawner/random/entertainment/slot_machine, /turf/open/floor/iron/kitchen, /area/virtual_domain) "sl" = ( diff --git a/_maps/virtual_domains/island_brawl.dmm b/_maps/virtual_domains/island_brawl.dmm index 31a65f790ab..4688e496bbf 100644 --- a/_maps/virtual_domains/island_brawl.dmm +++ b/_maps/virtual_domains/island_brawl.dmm @@ -2228,7 +2228,7 @@ /obj/structure/sign/directions/medical/directional/north{ pixel_y = 29 }, -/obj/machinery/computer/slot_machine, +/obj/effect/spawner/random/entertainment/slot_machine, /turf/open/floor/wood/large, /area/virtual_domain) "BW" = ( diff --git a/code/game/machinery/slotmachine.dm b/code/game/machinery/slotmachine.dm index cd61dcebac0..4ff3d99a004 100644 --- a/code/game/machinery/slotmachine.dm +++ b/code/game/machinery/slotmachine.dm @@ -16,7 +16,6 @@ #define PRIZE_JACKPOT 10000 #define SPIN_TIME 4 SECONDS #define REEL_DEACTIVATE_DELAY 0.4 SECONDS -#define JACKPOT_SEVENS FA_ICON_7 #define HOLOCHIP 1 #define COIN 2 @@ -29,8 +28,8 @@ icon_screen = "slots_screen" density = TRUE circuit = /obj/item/circuitboard/computer/slot_machine - light_color = LIGHT_COLOR_BROWN interaction_flags_machine = INTERACT_MACHINE_ALLOW_SILICON // don't need to be literate to play slots + light_color = LIGHT_COLOR_BROWN var/money = 3000 // How much money it has CONSUMED var/plays = 0 var/working = FALSE @@ -39,17 +38,35 @@ var/jackpots = 0 var/paymode = HOLOCHIP // toggles between HOLOCHIP/COIN, defined above var/cointype = /obj/item/coin/iron //default cointype - /// Icons that can be displayed by the slot machine. - var/static/list/icons = list( - FA_ICON_LEMON, - FA_ICON_STAR, - FA_ICON_BOMB, - FA_ICON_BIOHAZARD, - FA_ICON_APPLE_WHOLE, - FA_ICON_7, - FA_ICON_DOLLAR_SIGN, + + /// The optional bank account used as the machine's bank. Player losses are deposited here, while payouts and jackpots are deducted from its balance + var/datum/bank_account/house_bank_account + + /// Typepaths representing the symbols shown on this machine's reels + var/list/symbol_paths = list( + /obj/item/storage/bag/money, + /obj/item/food/grown/cherry_bomb, + /obj/item/grenade/flashbang, + /obj/item/poker_chip, + /obj/item/food/grown/chili, + /obj/item/clothing/neck/necklace/dope, + /obj/item/stack/spacecash/c20, ) + /// Used to determine the 1st name of the slot machine. Name = "[adjective] [noun]" + var/list/slot_adjectives = list("Blazing", "Bonus", "Grand", "Greedy", "Jumbo", "Platinum", "Lucky", "Mega", "Robust", "Super", "Turbo", "Wild") + /// Used to determine the 2nd name of the slot machine. Name = "[adjective] [noun]" + var/list/slot_nouns = list("Bankroll", "Cashout", "Fortune", "Jackpot", "Luck", "Money", "Payday", "Reels", "Riches", "Spinner", "Spins", "Strike", "Treasure", "Spess") + + /// The symbol typepath that pays out the jackpot when it lines up five wide + var/jackpot_path = /obj/item/food/grown/cherry_bomb + + /// The symbol typepath that activates a trap when it lines up five wide (set to null to disable) + var/trap_path = /obj/item/grenade/flashbang + + /// Cached list of symbol data (id/name/icon/icon_state) sent to ui_static_data + var/list/symbol_data + var/static/list/coinvalues var/list/reels = list( list("", "", ""), @@ -58,13 +75,21 @@ list("", "", ""), list("", "", ""), ) - var/static/list/ray_filter = list(type = "rays", y = 16, size = 40, density = 4, color = COLOR_RED_LIGHT, factor = 15, flags = FILTER_OVERLAY) + var/static/list/ray_filter = list(type = "rays", y = 14, size = 40, density = 4, color = COLOR_RED_LIGHT, factor = 15, flags = FILTER_OVERLAY) /obj/machinery/computer/slot_machine/Initialize(mapload) . = ..() jackpots = rand(1, 4) //false hope plays = rand(75, 200) + name = make_machine_name() + + if(jackpot_path && !(jackpot_path in symbol_paths)) + stack_trace("[type] has jackpot_path [jackpot_path] not present in symbol_paths!") + if(trap_path && !(trap_path in symbol_paths)) + stack_trace("[type] has trap_path [trap_path] not present in symbol_paths!") + + build_symbol_data() // Populate the reels randomize_reels() @@ -76,6 +101,26 @@ coinvalues["[cointype]"] = C.get_item_credit_value() qdel(C) //Sigh +/obj/machinery/computer/slot_machine/Destroy() + house_bank_account = null + . = ..() + +/// Generates a randomised slot name by pulling an adjective and a noun +/// Produces things like "Lucky Sevens", "Robust Payday", "Honking Bonanza", etc. +/obj/machinery/computer/slot_machine/proc/make_machine_name() + var/adjective = pick(slot_adjectives) + var/noun = pick(slot_nouns) + return "[adjective] [noun]" + +/// Builds symbol_data from symbol_paths to be used for DmIcon in TGUI +/obj/machinery/computer/slot_machine/proc/build_symbol_data() + symbol_data = list() + for(var/obj/symbol as anything in symbol_paths) + symbol_data += list(list( + "id" = "[symbol]", + "icon_id" = sanitize_css_class_name("[symbol::icon][symbol::icon_state]") + )) + /obj/machinery/computer/slot_machine/on_deconstruction(disassembled) if(balance) give_payout(balance) @@ -138,6 +183,35 @@ balloon_alert(user, "coins only!") return ITEM_INTERACT_BLOCKING + var/obj/item/card/id/id_card = inserted.GetID() + if(isidcard(id_card)) + if(house_bank_account) + say("Already linked to [house_bank_account.account_holder]!") + playsound(src, 'sound/machines/buzz/buzz-two.ogg', 30, TRUE) + return ITEM_INTERACT_BLOCKING + + var/datum/bank_account/id_bank_account = id_card.registered_account + + if(!id_bank_account) + say("No bank account detected on id card!") + playsound(src, 'sound/machines/buzz/buzz-two.ogg', 30, TRUE) + return ITEM_INTERACT_BLOCKING + + if(!id_bank_account.has_money(PRIZE_SMALL)) + say("Insufficent funds for potential payout. Minimum of [PRIZE_SMALL] credits needed!") + playsound(src, 'sound/machines/buzz/buzz-two.ogg', 30, TRUE) + return ITEM_INTERACT_BLOCKING + + var/msg = tgui_input_text(user, "Name of your slot machine (optional)", "Slot Customization", "Slot Machine", max_length = MAX_NAME_LEN) + if(msg) + name = msg + + playsound(src, 'sound/machines/terminal/terminal_success.ogg', 50, TRUE) + desc = "Owned by [id_bank_account.account_holder], draws directly from [user.p_their()] account." + house_bank_account = id_bank_account + to_chat(user, span_notice("You link the slot machine to [id_bank_account.account_holder]'s account.")) + return ITEM_INTERACT_SUCCESS + return NONE /obj/machinery/computer/slot_machine/multitool_act(mob/living/user, obj/item/tool) @@ -163,6 +237,11 @@ balloon_alert(user, "machine rigged") return TRUE +/obj/machinery/computer/slot_machine/ui_assets(mob/user) + return list( + get_asset_datum(/datum/asset/spritesheet_batched/slot_machines), + ) + /obj/machinery/computer/slot_machine/ui_interact(mob/living/user, datum/tgui/ui) . = ..() ui = SStgui.try_update_ui(user, src, ui) @@ -172,9 +251,12 @@ /obj/machinery/computer/slot_machine/ui_static_data(mob/user) var/list/data = list() - data["icons"] = icons + data["symbols"] = symbol_data data["cost"] = SPIN_PRICE data["jackpot"] = PRIZE_JACKPOT + data["jackpot_id"] = "[jackpot_path]" + if(trap_path) + data["trap_id"] = "[trap_path]" return data /obj/machinery/computer/slot_machine/ui_data(mob/user) @@ -182,7 +264,7 @@ var/list/_reels = list() for(var/reel in reels) _reels += list(list( - "icons" = reel, + "symbols" = reel, )) data["reels"] = _reels data["balance"] = balance @@ -224,10 +306,25 @@ money -= max(0, give_payout(min(rand(-50, 100 * severity_ascending)), money)) //This starts at -50 because it shouldn't always dispense coins yo spin() +/// Returns TRUE if the owner has enough funds to payout +/obj/machinery/computer/slot_machine/proc/has_funds_to_pay(payout) + if(!house_bank_account) // no owner so NT is paying + return TRUE + + if(house_bank_account.has_money(payout)) + return TRUE + + say("The bank account of [house_bank_account.account_holder] does not have enough funds to pay out the potential prize, contact them to fill up their account or lower your bet!") + playsound(src, 'sound/machines/buzz/buzz-two.ogg', 30, TRUE) + return FALSE + /obj/machinery/computer/slot_machine/proc/spin(mob/user) if(!can_spin(user)) return + if(!has_funds_to_pay(PRIZE_SMALL)) + return + if(!use_energy(active_power_usage, force = FALSE)) say("Not enough energy!") return @@ -244,6 +341,12 @@ balance -= SPIN_PRICE money += SPIN_PRICE + + if(house_bank_account) + // Since big jackpots & free games aren't deducted directly from the account holder NT takes a 40% cut of profit + // Also discourages infinite money exploits since people playing slot machines they own will cause them to slowly lose money + house_bank_account.adjust_money(SPIN_PRICE * 0.60, "Slot Machine: Spin") + plays += 1 working = TRUE @@ -284,28 +387,44 @@ /// Randomize the states of all reels /obj/machinery/computer/slot_machine/proc/randomize_reels() - for(var/reel in reels) - reel[1] = pick(icons) - reel[2] = pick(icons) - reel[3] = pick(icons) + for(var/list/reel in reels) + reel[1] = "[pick(symbol_paths)]" + reel[2] = "[pick(symbol_paths)]" + reel[3] = "[pick(symbol_paths)]" + +/// Triggers a negative effect for a slot machine if all trap icons are lined up in the middle +/obj/machinery/computer/slot_machine/proc/activate_trap(mob/living/user) + visible_message("[src] says, 'Big Loser! Prepare for your special prize!'") + + switch(trap_path) + if(/obj/item/restraints/handcuffs) + if(iscarbon(user)) + var/mob/living/carbon/carbon_user = user + playsound(loc, 'sound/items/weapons/handcuffs.ogg', 30, TRUE, -2) + carbon_user.set_handcuffed(new /obj/item/restraints/handcuffs(user)) + if(/obj/item/suspiciousphone) + playsound(loc, 'sound/items/dump_it.ogg', 30, TRUE, -2) + balance = 0 + if(/obj/singularity) + user.electrocute_act(80, src, flags = SHOCK_ILLUSION | SHOCK_NOGLOVES) + else // gibonite, syndicate bombs, flashbangs, etc. + var/obj/item/grenade/flashbang/bang = new(get_turf(src)) + bang.arm_grenade(null, 1 SECONDS) /// Checks if any prizes have been won, and pays them out -/obj/machinery/computer/slot_machine/proc/give_prizes(usrname, mob/user) +/obj/machinery/computer/slot_machine/proc/give_prizes(usrname, mob/living/user) var/linelength = get_lines() var/did_player_win = TRUE - if(check_jackpot(FA_ICON_BOMB)) - var/obj/item/grenade/flashbang/bang = new(get_turf(src)) - bang.arm_grenade(null, 1 SECONDS) + if(trap_path && check_middle_row_all(trap_path)) + activate_trap(user) - else if(check_jackpot(JACKPOT_SEVENS)) + else if(check_middle_row_all(jackpot_path)) winning = WINNING_JACKPOT var/prize = money + PRIZE_JACKPOT visible_message("[src] says, 'JACKPOT! You win [prize] [MONEY_NAME]!'") priority_announce("Congratulations to [user ? user.real_name : usrname] for winning the jackpot at the slot machine in [get_area(src)]!") - if(isliving(user) && (user in viewers(src))) - var/mob/living/living_user = user - living_user.add_mood_event("slots", /datum/mood_event/slots/win/jackpot) + user.add_mood_event("slots", /datum/mood_event/slots/win/jackpot) jackpots += 1 money = 0 if(paymode == HOLOCHIP) @@ -322,17 +441,13 @@ winning = WINNING_BIG visible_message("[src] says, 'Big Winner! You win a thousand [MONEY_NAME]!'") give_money(PRIZE_BIG) - if(isliving(user) && (user in viewers(src))) - var/mob/living/living_user = user - living_user.add_mood_event("slots", /datum/mood_event/slots/win/big) + user.add_mood_event("slots", /datum/mood_event/slots/win/big) else if(linelength == 4) winning = WINNING_SMALL visible_message("[src] says, 'Winner! You win four hundred [MONEY_NAME]!'") give_money(PRIZE_SMALL) - if(isliving(user) && (user in viewers(src))) - var/mob/living/living_user = user - living_user.add_mood_event("slots", /datum/mood_event/slots/win) + user.add_mood_event("slots", /datum/mood_event/slots/win) else if(linelength == 3) winning = WINNING_FREESPIN @@ -344,9 +459,7 @@ winning = WINNING_NOTHING balloon_alert(user, "no luck!") did_player_win = FALSE - if(isliving(user) && (user in viewers(src))) - var/mob/living/living_user = user - living_user.add_mood_event("slots", /datum/mood_event/slots/loss) + user.add_mood_event("slots", /datum/mood_event/slots/loss) playsound(src, 'sound/machines/lever/lever_stop.ogg', 50) @@ -362,30 +475,31 @@ /obj/machinery/computer/slot_machine/proc/clear_winning() winning = WINNING_NOTHING -/// Checks for a jackpot (5 matching icons in the middle row) with the given icon name -/obj/machinery/computer/slot_machine/proc/check_jackpot(name) - for(var/reel in reels) - if(reel[2] != name) +/// Checks for a jackpot (5 matching symbols in the middle row) for the given symbol typepath +/obj/machinery/computer/slot_machine/proc/check_middle_row_all(symbol_path) + var/symbol_id = "[symbol_path]" + for(var/list/reel in reels) + if(reel[2] != symbol_id) return FALSE return TRUE /// Finds the largest number of consecutive matching icons in a row /obj/machinery/computer/slot_machine/proc/get_lines() - var/amountthesame + var/amountthesame = 0 - for(var/i in 1 to 3) - var/inputtext = reels[1][i] + reels[2][i] + reels[3][i] + reels[4][i] + reels[5][i] - for(var/icon in icons) - var/j = 3 //The lowest value we have to check for. - var/symboltext = icon + icon + icon - while(j <= 5) - if(findtext(inputtext, symboltext)) - amountthesame = max(j, amountthesame) - j++ - symboltext += icon + for(var/row in 1 to 3) + var/current_symbol = null + var/current_run = 0 - if(amountthesame) - break + for(var/list/reel in reels) + var/symbol = reel[row] + if(symbol == current_symbol) + current_run++ + else + current_symbol = symbol + current_run = 1 + if(current_run >= 3) + amountthesame = max(amountthesame, current_run) return amountthesame @@ -396,6 +510,9 @@ money -= amount_to_give balance += surplus + if(house_bank_account) + house_bank_account.adjust_money(-amount_to_give, "Slot Machine: Payout") + /// Pay out the specified amount in either coins or holochips /obj/machinery/computer/slot_machine/proc/give_payout(amount) if(paymode == HOLOCHIP) @@ -436,6 +553,204 @@ playsound(src, pick(list('sound/machines/coindrop.ogg', 'sound/machines/coindrop2.ogg')), 50, TRUE) return amount +/obj/machinery/computer/slot_machine/command + name = "command slot machine" + desc = "The handle is made of solid gold, and the screen is polished with the tears of overworked assistants." + symbol_paths = list( + /obj/item/disk/nuclear, + /obj/item/clothing/accessory/medal/gold, + /obj/item/hand_tele, + /mob/living/basic/pet/dog/corgi, + /obj/item/card/id/advanced/gold, + /obj/item/melee/sabre, + /obj/item/grenade/syndieminibomb + ) + jackpot_path = /obj/item/clothing/accessory/medal/gold + trap_path = /obj/item/grenade/syndieminibomb + +/obj/machinery/computer/slot_machine/command/Initialize(mapload) + slot_adjectives += list("Royal", "Regal", "Golden", "Captain's", "Glorious") + slot_nouns += list("Medal", "Ransom", "Authority", "Command") + . = ..() + +/obj/machinery/computer/slot_machine/security + name = "security slot machine" + desc = "Repurposed from a confiscated syndicate gambling ring. Losing is a crime. Winning is also a crime." + symbol_paths = list( + /obj/item/food/donut/berry, + /mob/living/simple_animal/bot/secbot/beepsky, + /obj/item/melee/baton/security/loaded, + /obj/item/gun/energy/disabler, + /obj/vehicle/sealed/mecha/ripley/paddy, + /obj/item/book/manual/wiki/security_space_law, + /obj/item/grown/bananapeel + ) + jackpot_path = /obj/item/food/donut/berry + trap_path = /obj/item/grown/bananapeel + +/obj/machinery/computer/slot_machine/security/Initialize(mapload) + slot_adjectives += list("Stunned", "Flashed", "Confiscated", "Loyal", "Arrested") + slot_nouns += list("Baton", "Donut", "Contraband", "Brig", "Security") + . = ..() + +/obj/machinery/computer/slot_machine/medical + name = "medical slot machine" + desc = "A miracle of modern medicine! It cures boredom, but causes acute financial necrosis." + symbol_paths = list( + /obj/item/storage/medkit/brute, + /obj/vehicle/sealed/mecha/odysseus, + /obj/item/clothing/glasses/hud/health, + /mob/living/basic/pet/cat/runtime, + /obj/item/plunger, + /obj/item/clothing/neck/stethoscope, + /obj/machinery/syndicatebomb, + ) + jackpot_path = /obj/item/clothing/neck/stethoscope + trap_path = /obj/machinery/syndicatebomb + +/obj/machinery/computer/slot_machine/medical/Initialize(mapload) + slot_adjectives += list("Mutated", "Overdosed", "Infectious", "Healing", "Husked") + slot_nouns += list("Medkit", "Defib", "Patient", "Doctor", "Cure") + . = ..() + +/obj/machinery/computer/slot_machine/engineering + name = "engineering slot machine" + desc = "Gambling for those who think wearing insulated gloves makes them invincible. Ground yourself before playing." + symbol_paths = list( + /obj/item/storage/toolbox/mechanical, + /obj/item/blueprints, + /obj/item/clothing/gloves/color/yellow, + /obj/item/clothing/head/utility/welding, + /obj/item/clothing/glasses/meson, + /mob/living/basic/parrot/poly, + /obj/singularity, + ) + jackpot_path = /obj/item/blueprints + trap_path = /obj/singularity + +/obj/machinery/computer/slot_machine/engineering/Initialize(mapload) + slot_adjectives += list("Supercharged", "Pressurized", "Radioactive", "Overloaded", "Delaminating", "Insulated") + slot_nouns += list("Toolbox", "Emitter", "Supermatter") + . = ..() + +/obj/machinery/computer/slot_machine/cargo + name = "cargo slot machine" + desc = "Every credit spent here is a credit that won't be spent on 'useless' things, like food or medicine." + symbol_paths = list( + /obj/item/bounty_cube, + /obj/item/clipboard, + /obj/item/universal_scanner, + /mob/living/basic/sloth, + /obj/item/multitool, + /obj/vehicle/sealed/mecha/ripley, + /obj/item/suspiciousphone, + ) + jackpot_path = /obj/item/bounty_cube + trap_path = /obj/item/suspiciousphone + +/obj/machinery/computer/slot_machine/cargo/Initialize(mapload) + slot_adjectives += list("Express", "Smuggled", "Stolen", "Overdue", "Subsidized", "Manifested") + slot_nouns += list("Bounty", "Crate", "Manifest", "MULE", "Profit") + . = ..() + +/obj/machinery/computer/slot_machine/service + name = "service slot machine" + desc = "The handle is a repurposed rolling pin. Every loss is just another ingredient for the daily special." + symbol_paths = list( + /obj/item/clothing/head/hats/tophat, + /obj/item/reagent_containers/cup/watering_can, + /obj/item/clothing/shoes/galoshes, + /mob/living/basic/goat/pete, + /obj/item/book/bible, + /obj/item/kitchen/rollingpin, + /obj/item/seeds/random, + ) + jackpot_path = /obj/item/seeds/random + trap_path = /mob/living/basic/goat/pete + +/obj/machinery/computer/slot_machine/service/Initialize(mapload) + slot_adjectives += list("Fermented", "Seasoned", "Tipsy", "Cleaned", "Organic", "Culinary", "Refreshing", "Divine", "Holy") + slot_nouns += list("Recipe", "Cocktail", "Harvest", "Scrubber") + . = ..() + +/obj/machinery/computer/slot_machine/science + name = "research slot machine" + desc = "The reels seem to exist in multiple dimensions at once. It still takes your money in all of them." + symbol_paths = list( + /obj/item/stack/sheet/mineral/gold, + /obj/item/stack/sheet/mineral/silver, + /obj/item/stack/sheet/mineral/uranium, + /obj/item/stack/sheet/mineral/plasma, + /obj/item/stack/sheet/mineral/runite, + /obj/item/clothing/mask/facehugger/lamarr, + /obj/item/gibtonite, + ) + jackpot_path = /obj/item/stack/sheet/mineral/runite + trap_path = /obj/item/gibtonite + +/obj/machinery/computer/slot_machine/science/Initialize(mapload) + slot_adjectives += list("Atomic", "Bluespace", "Cosmic", "Golden", "Diamond", "Silver", "Uranium", "Quantum", "Anomalous", "Plasma", "Experimental", "Robotic") + slot_nouns += list("Anomaly", "Artifact", "Slime", "Extract", "Circuit", "Discovery", "Explosion") + . = ..() + +/obj/machinery/computer/slot_machine/clown + desc = "Gambling is fun! Smells like bananas, wet shoes, and regret. HONK!" + symbol_paths = list( + /obj/item/food/grown/banana, + /obj/item/toy/crayon/spraycan/lubecan, + /obj/item/card/id/advanced/rainbow, + /obj/vehicle/sealed/mecha/honker, + /obj/item/clothing/mask/gas/clown_hat, + /obj/item/storage/backpack/clown, + /obj/item/restraints/handcuffs, + ) + jackpot_path = /obj/vehicle/sealed/mecha/honker + trap_path = /obj/item/restraints/handcuffs + +/obj/machinery/computer/slot_machine/clown/Initialize(mapload) + slot_adjectives += list("Honking", "Slippery", "Pranked", "Squeaky", "Hilarious", "Giggling") + slot_nouns += list("Banana", "Peel", "Prank", "Joke", "Punchline", "Candy", "Honk") + . = ..() + +/obj/machinery/computer/slot_machine/mime + desc = "Gambling is a silent tragedy. The machine stares back at you with a cold indifference." + symbol_paths = list( + /obj/item/book/granter/action/spell/mime/mimery, + /obj/item/clothing/mask/gas/mime, + /obj/item/toy/crayon/spraycan/mimecan, + /obj/item/reagent_containers/cup/glass/bottle/bottleofnothing, + /obj/item/clothing/gloves/color/white, + /obj/item/storage/backpack/mime, + /obj/item/restraints/handcuffs, + ) + jackpot_path = /obj/item/book/granter/action/spell/mime/mimery + trap_path = /obj/item/restraints/handcuffs + +/obj/machinery/computer/slot_machine/mime/Initialize(mapload) + slot_adjectives += list("Silent", "Transparent", "Unspeakable", "Voiceless", "Quiet", "Hushed", "Invisible", "Imaginary", "Empty") + slot_nouns += list("Silence", "Mute", "Introvert", "Nothing", "Baguette") + . = ..() + +/obj/machinery/computer/slot_machine/syndicate + name = "syndicate slot machine" + desc = "Gambling for the operative who's already lost everything. Death to Nanotrasen, and death to your wallet." + symbol_paths = list( + /obj/machinery/nuclearbomb, + /obj/item/card/emag, + /obj/item/storage/toolbox/syndicate, + /obj/vehicle/sealed/mecha/gygax/dark, + /obj/item/soap/syndie, + /obj/item/gun/energy/recharge/ebow, + /obj/item/restraints/handcuffs, + ) + jackpot_path = /obj/machinery/nuclearbomb + trap_path = /obj/item/restraints/handcuffs + +/obj/machinery/computer/slot_machine/syndicate/Initialize(mapload) + slot_adjectives += list("Covert", "Nuclear", "Suspicious", "Bloody", "Syndie", "Sabotaged", "Clandestine", "Illicit", "Traitorous") + slot_nouns += list("Telecrystal", "Uplink", "Bomb", "Operative", "Disk", "Nuke", "Syndicate", "Traitor") + . = ..() + #undef SPIN_PRICE #undef WINNING_NOTHING #undef WINNING_FREESPIN @@ -447,6 +762,5 @@ #undef PRIZE_JACKPOT #undef SPIN_TIME #undef REEL_DEACTIVATE_DELAY -#undef JACKPOT_SEVENS #undef HOLOCHIP #undef COIN diff --git a/code/game/objects/effects/spawners/random/entertainment.dm b/code/game/objects/effects/spawners/random/entertainment.dm index ddc3dd790dc..fc766d6bd36 100644 --- a/code/game/objects/effects/spawners/random/entertainment.dm +++ b/code/game/objects/effects/spawners/random/entertainment.dm @@ -12,6 +12,23 @@ /obj/machinery/computer/arcade/amputation = 2, ) +/obj/effect/spawner/random/entertainment/slot_machine + name = "spawn random slot machine" + desc = "Automagically transforms into a random slot machine. If you see this while in a shift, please create a bug report." + icon_state = "arcade" + loot = list( // syndie slots omitted + /obj/machinery/computer/slot_machine = 20, + /obj/machinery/computer/slot_machine/security = 10, + /obj/machinery/computer/slot_machine/medical = 10, + /obj/machinery/computer/slot_machine/engineering = 10, + /obj/machinery/computer/slot_machine/cargo = 10, + /obj/machinery/computer/slot_machine/service = 10, + /obj/machinery/computer/slot_machine/science = 10, + /obj/machinery/computer/slot_machine/command = 10, + /obj/machinery/computer/slot_machine/clown = 5, + /obj/machinery/computer/slot_machine/mime = 5, + ) + /obj/effect/spawner/random/entertainment/musical_instrument name = "musical instrument spawner" icon_state = "eguitar" diff --git a/code/game/objects/items/circuitboards/computer_circuitboards.dm b/code/game/objects/items/circuitboards/computer_circuitboards.dm index b1a7e0bb445..8dd950e3a6c 100644 --- a/code/game/objects/items/circuitboards/computer_circuitboards.dm +++ b/code/game/objects/items/circuitboards/computer_circuitboards.dm @@ -313,6 +313,50 @@ name = "Slot Machine" greyscale_colors = CIRCUIT_COLOR_GENERIC build_path = /obj/machinery/computer/slot_machine + desc = "You can change the theme using a screwdriver." + /// List of pickable slot machines + var/static/list/slot_themes = list( + "Default" = /obj/machinery/computer/slot_machine, + "Command" = /obj/machinery/computer/slot_machine/command, + "Security" = /obj/machinery/computer/slot_machine/security, + "Medical" = /obj/machinery/computer/slot_machine/medical, + "Engineering" = /obj/machinery/computer/slot_machine/engineering, + "Cargo" = /obj/machinery/computer/slot_machine/cargo, + "Service" = /obj/machinery/computer/slot_machine/service, + "Science" = /obj/machinery/computer/slot_machine/science, + "Clown" = /obj/machinery/computer/slot_machine/clown, + "Mime" = /obj/machinery/computer/slot_machine/mime, + ) + +/obj/item/circuitboard/computer/slot_machine/examine(mob/user) + . = ..() + var/current_theme = "Unknown" + for(var/theme_name in slot_themes) + if(slot_themes[theme_name] == build_path) + current_theme = theme_name + break + . += span_info("[src] is set to the [current_theme] theme. You can use a screwdriver to reconfigure it.") + +/obj/item/circuitboard/computer/slot_machine/screwdriver_act(mob/living/user, obj/item/tool) + if(obj_flags & EMAGGED) + balloon_alert(user, "board mode is broken!") + return FALSE + + var/choice = tgui_input_list(user, "Choose a slot machine theme", "Theme Selection", slot_themes) + if(isnull(choice)) + return ITEM_INTERACT_BLOCKING + build_path = slot_themes[choice] + to_chat(user, span_notice("You set the board to the [choice] theme.")) + return ITEM_INTERACT_SUCCESS + +/obj/item/circuitboard/computer/slot_machine/emag_act(mob/user, obj/item/card/emag/emag_card) + if(obj_flags & EMAGGED) + return FALSE + + obj_flags |= EMAGGED + build_path = /obj/machinery/computer/slot_machine/syndicate + balloon_alert(user, "illegal slot machine loaded") + return TRUE /obj/item/circuitboard/computer/swfdoor name = "Magix" diff --git a/code/modules/asset_cache/assets/slot_machines.dm b/code/modules/asset_cache/assets/slot_machines.dm new file mode 100644 index 00000000000..c3210bb3672 --- /dev/null +++ b/code/modules/asset_cache/assets/slot_machines.dm @@ -0,0 +1,24 @@ +/datum/asset/spritesheet_batched/slot_machines + name = "slotmachines" + +/datum/asset/spritesheet_batched/slot_machines/create_spritesheets() + // initialising the list of items we need + var/list/target_items = list() + for(var/obj/machinery/computer/slot_machine/slot_machine as anything in typesof(/obj/machinery/computer/slot_machine)) + slot_machine = new slot_machine() + target_items |= slot_machine.symbol_paths // no dupes + qdel(slot_machine) + + for(var/atom/atom as anything in target_items) + var/icon = initial(atom.icon) + var/icon_state = initial(atom.icon_state) + var/id = sanitize_css_class_name("[icon][icon_state]") + + var/has_gags = atom::greyscale_config && atom::greyscale_colors + var/has_color = atom::color && icon_state + // GAGS and colored icons must be pregenerated so blacklist them for now + if(has_gags || has_color) + stack_trace("[atom] is either using GAGS or colored icons which is not supported for slot machine reels") + continue + + insert_icon(id, uni_icon(icon, icon_state)) diff --git a/icons/effects/random_spawners.dmi b/icons/effects/random_spawners.dmi index 3450f6754c2614def035d9e638c29ad67e7c3624..4d816c6df8005f3f9e11c2d1b6ca613699f4146c 100644 GIT binary patch delta 7312 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 delta 6736 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 T-OS%nkV92TOR-MgD*S%{h|*>} diff --git a/tgstation.dme b/tgstation.dme index ca737cae21b..247820c849f 100644 --- a/tgstation.dme +++ b/tgstation.dme @@ -3716,6 +3716,7 @@ #include "code\modules\asset_cache\assets\safe.dm" #include "code\modules\asset_cache\assets\seeds.dm" #include "code\modules\asset_cache\assets\sheetmaterials.dm" +#include "code\modules\asset_cache\assets\slot_machines.dm" #include "code\modules\asset_cache\assets\supplypods.dm" #include "code\modules\asset_cache\assets\tcomms.dm" #include "code\modules\asset_cache\assets\tgfont.dm" diff --git a/tgui/packages/tgui/interfaces/SlotMachine.tsx b/tgui/packages/tgui/interfaces/SlotMachine.tsx index 54045ecfac1..784e6b98d57 100644 --- a/tgui/packages/tgui/interfaces/SlotMachine.tsx +++ b/tgui/packages/tgui/interfaces/SlotMachine.tsx @@ -1,12 +1,12 @@ -import { useEffect, useRef, useState } from 'react'; -import { Blink, Box, Button, Icon, Section, Stack } from 'tgui-core/components'; +import { useEffect, useMemo, useRef, useState } from 'react'; +import { Blink, Box, Button, Section, Stack } from 'tgui-core/components'; import { formatMoney } from 'tgui-core/format'; import { classes } from 'tgui-core/react'; import { useBackend } from '../backend'; import { Window } from '../layouts'; type Data = { - icons: string[]; + symbols: SlotSymbol[]; reels: Reel[]; balance: number; working: number; @@ -17,36 +17,24 @@ type Data = { jackpots: number; jackpot: number; paymode: number; + jackpot_id: string; + trap_id: string; +}; + +type SlotSymbol = { + id: string; + icon_id: string; }; type Reel = { - icons: string[]; - spinning: number; -}; - -type IconMeta = { - color: string; -}; - -const iconMetaByName: Record = { - 'fa-7': { color: '#b22' }, - 'fa-star': { color: '#fd6' }, - 'fa-lemon': { color: '#ce0' }, - 'fa-apple-whole': { color: '#d64' }, - 'fa-biohazard': { color: '#2c0' }, - 'fa-dollar-sign': { color: '#08b' }, - 'fa-bomb': { color: '#876' }, + symbols: string[]; }; const pluralS = (amount: number) => { return amount === 1 ? '' : 's'; }; -const slotIconToColor = (iconName: string): string => { - return iconMetaByName[iconName]?.color || '#f0f'; -}; - -const pickRandomMany = (items: T[], n: number) => { +const pickRandomMany = (items: T[], n: number) => { const result: T[] = []; for (let i = 0; i < n; i += 1) { result.push(pickRandom(items)); @@ -54,17 +42,28 @@ const pickRandomMany = (items: T[], n: number) => { return result; }; -const pickRandom = (items: T[]) => { +const pickRandom = (items: T[]) => { return items[Math.floor(Math.random() * items.length)]; }; export const SlotMachine = () => { const { act, data } = useBackend(); - const { icons, cost, reels, balance } = data; + const { symbols, cost, reels, balance } = data; const spinning = data.working === 1; + const symbolsById = useMemo(() => { + const map: Record = {}; + for (const symbol of symbols) { + map[symbol.id] = symbol; + } + return map; + }, [symbols]); + + const jackpotSymbol = symbolsById[data.jackpot_id]; + const trapSymbol = data.trap_id ? symbolsById[data.trap_id] : null; + return ( - +
@@ -72,43 +71,82 @@ export const SlotMachine = () => { {reels.map((reel, i) => (
))}
- - -
act('payout')} disabled={balance <= 0}> - Refund - - } - > - - {formatMoney(balance)} cr + + +
+ + Jackpot: + {jackpotSymbol && ( + + )} + + {trapSymbol && ( + <> + + Trap: + + + + )}
-
- -
+ + +
act('payout')} + disabled={balance <= 0} + > + Refund + + } + > + + {formatMoney(balance)} cr + +
+
+ +
+ +
+
+
@@ -301,30 +339,32 @@ const BannerStats = () => { const ICON_STRIP_LENGTH = 30; type IconStripProps = { - icons: string[]; - iconsNeeded: string[]; + symbols: SlotSymbol[]; + symbolsById: Record; + symbolsNeeded: string[]; spinning?: boolean; }; const IconStrip = (props: IconStripProps) => { - const { icons, iconsNeeded, spinning } = props; + const { symbols, symbolsById, symbolsNeeded, spinning } = props; + const symbolIds = useMemo(() => symbols.map((s) => s.id), [symbols]); - const [drawnIcons, setDrawnIcons] = useState([ - ...pickRandomMany(icons, ICON_STRIP_LENGTH - 3), - ...iconsNeeded, + const [drawnSymbols, setDrawnSymbols] = useState([ + ...pickRandomMany(symbolIds, ICON_STRIP_LENGTH - 3), + ...symbolsNeeded, ]); useEffect(() => { if (spinning) { - setDrawnIcons((drawnIcons) => [ - ...drawnIcons.slice(-3), - ...pickRandomMany(icons, ICON_STRIP_LENGTH - 6), - ...iconsNeeded, + setDrawnSymbols((drawn) => [ + ...drawn.slice(-3), + ...pickRandomMany(symbolIds, ICON_STRIP_LENGTH - 6), + ...symbolsNeeded, ]); } else { - setDrawnIcons([ - ...pickRandomMany(icons, ICON_STRIP_LENGTH - 3), - ...iconsNeeded, + setDrawnSymbols([ + ...pickRandomMany(symbolIds, ICON_STRIP_LENGTH - 3), + ...symbolsNeeded, ]); } }, [spinning]); @@ -336,18 +376,16 @@ const IconStrip = (props: IconStripProps) => { spinning && 'SlotMachine__IconStrip--spinning', ])} > - {drawnIcons.map((icon, i) => ( - - ))} + {drawnSymbols.map((symbolId, i) => { + const symbol = symbolsById[symbolId]; + return ( +
+ {symbol && ( + + )} +
+ ); + })} ); }; diff --git a/tgui/packages/tgui/styles/interfaces/SlotMachine.scss b/tgui/packages/tgui/styles/interfaces/SlotMachine.scss index 82599f53d22..48583d4d982 100644 --- a/tgui/packages/tgui/styles/interfaces/SlotMachine.scss +++ b/tgui/packages/tgui/styles/interfaces/SlotMachine.scss @@ -152,15 +152,6 @@ transform: translateY(calc(-60px * 27)); // animation-duration: 3.5s; text-align: center; - // animation: scroll-up 2s linear infinite; - // animation-play-state: paused; - // transform: translateY(0px); - text-shadow: - 2px 2px 6px #000, - 0 2px #000, - 0 -2px #000, - 2px 0 #000, - -2px 0 #000; } .SlotMachine__IconStrip--spinning { @@ -171,6 +162,20 @@ animation-timing-function: cubic-bezier(1, 1.26, 0.88, 0.96); } +.SlotMachine__Symbol { + height: 60px; + display: flex; + align-items: center; + justify-content: center; + + .slotmachines32x32 { + width: 32px; + height: 32px; + image-rendering: pixelated; + filter: drop-shadow(1px 1px 1px black); + } +} + @keyframes SlotMachine__Spin { 0% { transform: translateY(0);