Roulette Machine

initial work

more work

more roulette work

more work

more

yet more

FINALLY

small fixes

use global colors for last spun box

no low memory mode

cleanup

nuke old roulette assets

kills remaining 2 usages

forgot this var
This commit is contained in:
actioninja
2020-01-10 20:05:11 -08:00
parent 51236f08db
commit db161a7570
16 changed files with 610 additions and 36 deletions
+55 -19
View File
@@ -1,10 +1,17 @@
#define ROULETTE_SINGLES_PAYOUT 35
#define ROULETTE_SINGLES_PAYOUT 36
#define ROULETTE_SIMPLE_PAYOUT 2
#define ROULETTE_DOZ_COL_PAYOUT 3
#define ROULETTE_BET_ODD "odd"
#define ROULETTE_BET_EVEN "even"
#define ROULETTE_BET_1TO18 "s1-18" //adds s to prevent text2num from working
#define ROULETTE_BET_19TO36 "s19-36" //adds s to prevent text2num from working
#define ROULETTE_BET_1TO12 "s1-12"
#define ROULETTE_BET_13TO24 "s13-24"
#define ROULETTE_BET_25TO36 "s25-36"
#define ROULETTE_BET_2TO1_FIRST "s1st col"
#define ROULETTE_BET_2TO1_SECOND "s2nd col"
#define ROULETTE_BET_2TO1_THIRD "s3rd col"
#define ROULETTE_BET_BLACK "black"
#define ROULETTE_BET_RED "red"
@@ -22,6 +29,8 @@
idle_power_usage = 10
active_power_usage = 100
max_integrity = 500
ui_x = 603
ui_y = 475
armor = list("melee" = 45, "bullet" = 30, "laser" = 30, "energy" = 30, "bomb" = 10, "bio" = 30, "rad" = 30, "fire" = 30, "acid" = 30)
var/static/list/numbers = list("0" = "green", "1" = "red", "3" = "red", "5" = "red", "7" = "red", "9" = "red", "12" = "red", "14" = "red", "16" = "red",\
"18" = "red", "19" = "red", "21" = "red", "23" = "red", "25" = "red", "27" = "red", "30" = "red", "32" = "red", "34" = "red", "36" = "red",\
@@ -29,7 +38,7 @@
"22" = "black", "24" = "black", "26" = "black", "28" = "black", "29" = "black", "31" = "black", "33" = "black", "35" = "black")
var/chosen_bet_amount = 10
var/chosen_bet_type = 0
var/chosen_bet_type = "0"
var/last_anti_spam = 0
var/anti_spam_cooldown = 20
var/obj/item/card/id/my_card
@@ -39,8 +48,8 @@
var/static/list/coin_values = list(/obj/item/coin/diamond = 100, /obj/item/coin/gold = 25, /obj/item/coin/silver = 10, /obj/item/coin/iron = 1) //Make sure this is ordered from left to right.
var/list/coins_to_dispense = list()
var/datum/looping_sound/jackpot/jackpot_loop
var/datum/asset/spritesheet/simple/assets
var/on = TRUE
var/last_spin = 13
/obj/machinery/roulette/Initialize()
. = ..()
@@ -56,9 +65,7 @@
return
ui = SStgui.try_update_ui(user, src, ui_key, ui, force_open)
if(!ui)
var/datum/asset/spritesheet/simple/assets = get_asset_datum(/datum/asset/spritesheet/simple/roulette)
assets.send(user)
ui = new(user, src, ui_key, "roulette", name, 455, 520, master_ui, state)
ui = new(user, src, ui_key, "roulette", name, ui_x, ui_y, master_ui, state)
ui.open()
/obj/machinery/roulette/ui_data(mob/user)
@@ -67,6 +74,8 @@
data["BetAmount"] = chosen_bet_amount
data["BetType"] = chosen_bet_type
data["HouseBalance"] = my_card?.registered_account.account_balance
data["LastSpin"] = last_spin
data["Spinning"] = playing
if(ishuman(user))
var/mob/living/carbon/human/H = user
var/obj/item/card/id/C = H.get_idcard(TRUE)
@@ -76,8 +85,6 @@
data["AccountBalance"] = 0
data["CanUnbolt"] = (H.get_idcard() == my_card)
if(!assets)
assets = get_asset_datum(/datum/asset/spritesheet/simple/roulette)
return data
/obj/machinery/roulette/ui_act(action, params)
@@ -90,19 +97,11 @@
if("ChangeBetAmount")
chosen_bet_amount = CLAMP(text2num(params["amount"]), 10, 500)
. = TRUE
if("ChangeBetAmountCustom")
var/amount = input(usr, "Bet amount between 10 and 500:") as num|null
if(amount)
chosen_bet_amount = CLAMP(amount, 10, 500)
if("ChangeBetType")
chosen_bet_type = params["type"]
. = TRUE
update_icon() // Not applicable to all objects.
/obj/machinery/roulette/ui_base_html(html)
var/datum/asset/spritesheet/simple/assets = get_asset_datum(/datum/asset/spritesheet/simple/roulette)
. = replacetext(html, "<!--customheadhtml-->", assets.css_tag())
///Handles setting ownership and the betting itself.
/obj/machinery/roulette/attackby(obj/item/W, mob/user, params)
if(stat & MAINT && is_wire_tool(W))
@@ -126,7 +125,26 @@
if(!chosen_bet_amount || isnull(chosen_bet_type))
return FALSE
var/potential_payout = text2num(chosen_bet_type) ? chosen_bet_amount * ROULETTE_SINGLES_PAYOUT : chosen_bet_amount * ROULETTE_SIMPLE_PAYOUT
//double to nothing bets
var/list/doubles = list(
ROULETTE_BET_2TO1_FIRST,
ROULETTE_BET_2TO1_SECOND,
ROULETTE_BET_2TO1_THIRD,
ROULETTE_BET_1TO12,
ROULETTE_BET_13TO24,
ROULETTE_BET_25TO36
)
//result of text2num is null if text starts with a character, meaning it's not a singles bet
var/single = !isnull(text2num(chosen_bet_type))
var/potential_payout_mult
if (single)
potential_payout_mult = ROULETTE_SINGLES_PAYOUT
else
if (chosen_bet_type in doubles)
potential_payout_mult = ROULETTE_DOZ_COL_PAYOUT
else
potential_payout_mult = ROULETTE_SIMPLE_PAYOUT
var/potential_payout = chosen_bet_amount * potential_payout_mult
if(!check_bartender_funds(potential_payout))
return FALSE //bartender is too poor
@@ -181,6 +199,7 @@
///Ran after a while to check if the player won or not.
/obj/machinery/roulette/proc/finish_play(obj/item/card/id/player_id, bet_type, bet_amount, potential_payout, rolled_number)
last_spin = rolled_number
var/is_winner = check_win(bet_type, bet_amount, rolled_number) //Predetermine if we won
var/color = numbers["[rolled_number]"] //Weird syntax, but dict uses strings.
@@ -275,8 +294,25 @@
return "black" == numbers["[rolled_number]"]//Check if our number is black in the numbers dict
if(ROULETTE_BET_RED)
return "red" == numbers["[rolled_number]"] //Check if our number is black in the numbers dict
if("0")
return "0" == "rolled_number" //Check if our number is 0
if(ROULETTE_BET_1TO12)
return (rolled_number >= 1 && rolled_number <= 12)
if(ROULETTE_BET_13TO24)
return (rolled_number >= 13 && rolled_number <= 24)
if(ROULETTE_BET_25TO36)
return (rolled_number >= 25 && rolled_number <= 36)
if(ROULETTE_BET_2TO1_FIRST)
//You could do this mathematically but w/e this is easy to understand
//numbers in the first column
var/list/winners = list(1, 4, 7, 10, 13, 16, 19, 22, 25, 28, 31, 34)
return (rolled_number in winners)
if(ROULETTE_BET_2TO1_SECOND)
//numbers in the second column
var/list/winners = list(2, 5, 8, 11, 14, 17, 20, 23, 26, 29, 32, 35)
return (rolled_number in winners)
if(ROULETTE_BET_2TO1_THIRD)
//numbers in the third column
var/list/winners = list(3, 5, 8, 12, 15, 18, 21, 24, 27, 30, 33, 36)
return (rolled_number in winners)
///Returns TRUE if the owner has enough funds to payout
-16
View File
@@ -630,22 +630,6 @@ GLOBAL_LIST_EMPTY(asset_datums)
"pill22" = 'icons/UI_Icons/Pills/pill22.png',
)
/datum/asset/spritesheet/simple/roulette
name = "roulette"
assets = list(
"black" = 'icons/UI_Icons/Roulette/black.png',
"red" = 'icons/UI_Icons/Roulette/red.png',
"odd" = 'icons/UI_Icons/Roulette/odd.png',
"even" = 'icons/UI_Icons/Roulette/even.png',
"low" = 'icons/UI_Icons/Roulette/1-18.png',
"high" = 'icons/UI_Icons/Roulette/19-36.png',
"nano" = 'icons/UI_Icons/Roulette/nano.png',
"zero" = 'icons/UI_Icons/Roulette/0.png'
)
//this exists purely to avoid meta by pre-loading all language icons.
/datum/asset/language/register()
for(var/path in typesof(/datum/language))
Binary file not shown.

Before

Width:  |  Height:  |  Size: 2.7 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 3.5 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 4.3 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 4.7 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 4.3 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 5.1 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 3.8 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 6.0 KiB

@@ -0,0 +1,401 @@
import { classes } from "common/react";
import { useBackend } from "../backend";
import { Box, Button, Grid, NumberInput } from "../components";
import { createLogger } from "../logging";
import { Fragment, Component } from "inferno";
import { act } from "../byond";
const logger = createLogger('Roulette');
const getNumberColor = number => {
if (number === 0) {
return 'green';
}
const evenRedRanges = [
[1, 10],
[19, 28],
];
let oddRed = true;
for (let i = 0; i < evenRedRanges.length; i++) {
let range = evenRedRanges[i];
if (number >= range[0] && number <= range[1]) {
oddRed = false;
break;
}
}
const isOdd = (number % 2 === 0);
return (oddRed ? isOdd : !isOdd) ? 'red' : 'black';
};
export const RouletteNumberButton = props => {
const { number } = props;
const { act } = useBackend(props);
return (
<Button
bold
content={number}
color={getNumberColor(number)}
width="40px"
height="28px"
fontSize="20px"
textAlign="center"
mb={0}
className="Roulette__board-extrabutton"
onClick={() => act('ChangeBetType', { type: number })}
/>
);
};
export const RouletteBoard = props => {
const { state } = props;
const { act } = useBackend(props);
const firstRow = [3, 6, 9, 12, 15, 18, 21, 24, 27, 30, 33, 36];
const secondRow = [2, 5, 8, 11, 14, 17, 20, 23, 26, 29, 32, 35];
const thirdRow = [1, 4, 7, 10, 13, 16, 19, 22, 25, 28, 31, 34];
return (
<table
className="Table"
style={{
// Setting it to 1 px makes sure it always takes up minimum width
'width': '1px',
}}>
<tr className="Roulette__board-row">
<td
rowSpan="3"
className="Roulette__board-cell">
<Button
content="0"
color="transparent"
height="88px"
className="Roulette__board-extrabutton"
onClick={() => act('ChangeBetType', { type: 0 })}
/>
</td>
{firstRow.map(number => (
<td
key={number}
className="Roulette__board-cell Table__cell-collapsing">
<RouletteNumberButton state={state} number={number} />
</td>
))}
<td className="Roulette__board-cell">
<Button
fluid
bold
content="2 to 1"
color="transparent"
className="Roulette__board-extrabutton"
onClick={() => act('ChangeBetType', { type: "s3rd col" })}
/>
</td>
</tr>
<tr>
{secondRow.map(number => (
<td
key={number}
className="Roulette__board-cell Table__cell-collapsing">
<RouletteNumberButton state={state} number={number} />
</td>
))}
<td className="Roulette__board-cell">
<Button
fluid
bold
content="2 to 1"
color="transparent"
className="Roulette__board-extrabutton"
onClick={() => act('ChangeBetType', { type: "s2nd col" })}
/>
</td>
</tr>
<tr>
{thirdRow.map(number => (
<td
key={number}
className="Roulette__board-cell Table__cell-collapsing">
<RouletteNumberButton state={state} number={number} />
</td>
))}
<td className="Roulette__board-cell">
<Button
fluid
bold
content="2 to 1"
color="transparent"
className="Roulette__board-extrabutton"
onClick={() => act('ChangeBetType', { type: "s1st col" })}
/>
</td>
</tr>
<tr>
<td />
<td colSpan="4" className="Roulette__board-cell">
<Button
fluid
bold
content="1st 12"
color="transparent"
className="Roulette__board-extrabutton"
onClick={() => act('ChangeBetType', { type: "s1-12" })}
/>
</td>
<td colSpan="4" className="Roulette__board-cell">
<Button
fluid
bold
content="2nd 12"
color="transparent"
className="Roulette__board-extrabutton"
onClick={() => act('ChangeBetType', { type: "s13-24" })}
/>
</td>
<td colSpan="4" className="Roulette__board-cell">
<Button
fluid
bold
content="3rd 12"
color="transparent"
className="Roulette__board-extrabutton"
onClick={() => act('ChangeBetType', { type: "s25-36" })}
/>
</td>
</tr>
<tr>
<td />
<td colSpan="2" className="Roulette__board-cell">
<Button
fluid
bold
content="1-18"
color="transparent"
className="Roulette__board-extrabutton"
onClick={() => act('ChangeBetType', { type: "s1-18" })}
/>
</td>
<td colSpan="2" className="Roulette__board-cell">
<Button
fluid
bold
content="Even"
color="transparent"
className="Roulette__board-extrabutton"
onClick={() => act('ChangeBetType', { type: "even" })}
/>
</td>
<td colSpan="2" className="Roulette__board-cell">
<Button
fluid
bold
content="Black"
color="black"
className="Roulette__board-extrabutton"
onClick={() => act('ChangeBetType', { type: "black" })}
/>
</td>
<td colSpan="2" className="Roulette__board-cell">
<Button
fluid
bold
content="Red"
color="red"
className="Roulette__board-extrabutton"
onClick={() => act('ChangeBetType', { type: "red" })}
/>
</td>
<td colSpan="2" className="Roulette__board-cell">
<Button
fluid
bold
content="Odd"
color="transparent"
className="Roulette__board-extrabutton"
onClick={() => act('ChangeBetType', { type: "odd" })}
/>
</td>
<td colSpan="2" className="Roulette__board-cell">
<Button
fluid
bold
content="19-36"
color="transparent"
className="Roulette__board-extrabutton"
onClick={() => act('ChangeBetType', { type: "s19-36" })}
/>
</td>
</tr>
</table>
);
};
export class RouletteBetTable extends Component {
constructor() {
super();
this.state = {
customBet: 500,
};
}
setCustomBet(customBet) {
this.setState({
customBet,
});
}
render() {
const { act, data } = useBackend(this.props);
let {
BetType,
} = data;
if (BetType.startsWith('s')) {
BetType = BetType.substring(1, BetType.length);
}
return (
<table className="Roulette__lowertable">
<tr>
<th
className={classes([
'Roulette',
'Roulette__lowertable--cell',
'Roulette__lowertable--header',
])}>
Last Spun:
</th>
<th
className={classes([
'Roulette',
'Roulette__lowertable--cell',
'Roulette__lowertable--header',
])}>
Current Bet:
</th>
</tr>
<tr>
<td className={classes([
'Roulette',
'Roulette__lowertable--cell',
'Roulette__lowertable--spinresult',
'Roulette__lowertable--spinresult-' + getNumberColor(data.LastSpin),
])}>
{data.LastSpin}
</td>
<td className={classes([
'Roulette',
'Roulette__lowertable--cell',
'Roulette__lowertable--betscell',
])}>
<Box
bold
mt={1}
mb={1}
fontSize="25px"
textAlign="center">
{data.BetAmount} cr on {BetType}
</Box>
<Box ml={1} mr={1}>
<Button
fluid
content="Bet 10 cr"
onClick={() => act('ChangeBetAmount', {
amount: 10,
})}
/>
<Button
fluid
content="Bet 50 cr"
onClick={() => act('ChangeBetAmount', {
amount: 50,
})}
/>
<Button
fluid
content="Bet 100 cr"
onClick={() => act('ChangeBetAmount', {
amount: 100,
})}
/>
<Button
fluid
content="Bet 500 cr"
onClick={() => act('ChangeBetAmount', {
amount: 500,
})}
/>
<Grid>
<Grid.Column>
<Button
fluid
content="Bet custom amount..."
onClick={() => act('ChangeBetAmount', {
amount: this.state.customBet,
})}
/>
</Grid.Column>
<Grid.Column size={0.1}>
<NumberInput
value={this.state.customBet}
minValue={0}
maxValue={1000}
step={10}
stepPixelSize={4}
width="40px"
onChange={(e, value) => this.setCustomBet(value)}
/>
</Grid.Column>
</Grid>
</Box>
</td>
</tr>
<tr>
<td colSpan="2">
<Box
bold
m={1}
fontSize="14px"
textAlign="center">
Swipe an ID card with a connected account to spin!
</Box>
</td>
</tr>
<tr>
<td className="Roulette__lowertable--cell">
<Box inline bold mr={1}>
House Balance:
</Box>
<Box inline>
{data.HouseBalance ? data.HouseBalance + ' cr': "None"}
</Box>
</td>
<td className="Roulette__lowertable--cell">
<Button
fluid
content={data.IsAnchored ? "Bolted" : "Unbolted"}
m={1}
color="transparent"
textAlign="center"
onClick={() => act('anchor')}
/>
</td>
</tr>
</table>
);
}
}
export const Roulette = props => {
return (
<Fragment>
<RouletteBoard state={props.state} />
<RouletteBetTable state={props.state} />
</Fragment>
);
};
+6
View File
@@ -78,6 +78,7 @@ import { PortablePump, PortableScrubber } from './interfaces/PortableAtmos';
import { PowerMonitor } from './interfaces/PowerMonitor';
import { Radio } from './interfaces/Radio';
import { RapidPipeDispenser } from './interfaces/RapidPipeDispenser';
import { Roulette } from './interfaces/Roulette';
import { SatelliteControl } from './interfaces/SatelliteControl';
import { ScannerGate } from './interfaces/ScannerGate';
import { ShuttleManipulator } from './interfaces/ShuttleManipulator';
@@ -452,6 +453,11 @@ const ROUTES = {
component: () => Radio,
scrollable: false,
},
roulette: {
component: () => Roulette,
scrollable: false,
theme: 'cardtable',
},
rpd: {
component: () => RapidPipeDispenser,
scrollable: true,
@@ -0,0 +1,99 @@
@use '../colors.scss';
.Roulette {
font-family: Palatino;
}
.Roulette__board {
display: table;
width: 100%;
border-collapse: collapse;
border: 2px solid white;
margin: 0;
}
.Roulette__board-row {
padding: 0;
margin: 0;
}
.Roulette__board-cell {
display: table-cell;
padding: 0;
margin: 0;
border: 2px solid white;
font-family: Palatino;
&:first-child {
padding-left: 0;
}
&:last-child {
padding-right: 0;
}
}
.Roulette__board-extrabutton {
text-align: center;
font-size: 20px;
font-weight: bold;
height: 28px;
border: none !important;
margin: 0 !important;
padding-top: 4px !important;
color: #FFFFFF !important;
}
.Roulette__lowertable {
margin-top: 8px;
margin-left: 80px;
margin-right: 80px;
border-collapse: collapse;
border: 2px solid white;
border-spacing: 0;
}
.Roulette__lowertable--cell {
border: 2px solid white;
padding: 0px;
margin: 0px;
}
.Roulette__lowertable--betscell {
vertical-align: top;
}
.Roulette__lowertable--spinresult {
text-align: center;
font-size: 100px;
font-weight: bold;
vertical-align: middle;
}
.Roulette__lowertable--spinresult-black {
background-color: colors.$black;
}
.Roulette__lowertable--spinresult-red {
background-color: colors.$red;
}
.Roulette__lowertable--spinresult-green {
background-color: colors.$green;
}
.Roulette__lowertable--spinbutton {
margin: 0 !important;
border: none !important;
font-size: 50px;
line-height: 60px !important;
text-align: center;
font-weight: bold;
}
.Roulette__lowertable--header {
width: 1%;
text-align: center;
font-size: 20px;
font-weight: bold;
}
+1
View File
@@ -28,6 +28,7 @@
@include meta.load-css('./components/NuclearBomb.scss');
@include meta.load-css('./components/NumberInput.scss');
@include meta.load-css('./components/ProgressBar.scss');
@include meta.load-css('./components/Roulette.scss');
@include meta.load-css('./components/Section.scss');
@include meta.load-css('./components/Table.scss');
@include meta.load-css('./components/Tabs.scss');
@@ -0,0 +1,46 @@
@use 'sass:color';
@use 'sass:meta';
@use '../colors.scss' with (
$primary: #000000,
$fg-map-keys: (),
$bg-map-keys: (),
);
@use '../base.scss' with (
$color-bg: #117039,
$color-bg-grad-spread: 0%,
$border-radius: 0px,
);
//Made for the roulette table, probably requires a bunch of manual hacks to work for anything else
.theme-cardtable {
// Atomic classes
@include meta.load-css('../atomic/color.scss');
// Components
@include meta.load-css('../components/Button.scss', $with: (
'color-default': #117039,
'color-disabled': #363636,
'color-selected': #9d0808,
'color-caution': #be6209,
'color-danger': #9a9d00,
));
@include meta.load-css('../components/Layout.scss');
@include meta.load-css('../components/NumberInput.scss', $with: (
'border-color': #FFFFFF,
));
@include meta.load-css('../components/ProgressBar.scss', $with: (
'color-background': rgba(0, 0, 0, 0.5),
));
@include meta.load-css('../components/Section.scss');
@include meta.load-css('../components/TitleBar.scss', $with: (
'color-background': #381608,
));
.Button {
border-color: #FFFFFF;
border-width: 2px;
border-style: solid;
}
}
+2 -1
View File
@@ -20,10 +20,11 @@ module.exports = (env = {}, argv) => {
entry: {
tgui: [
path.resolve(__dirname, './styles/main.scss'),
path.resolve(__dirname, './styles/themes/cardtable.scss'),
path.resolve(__dirname, './styles/themes/ntos.scss'),
path.resolve(__dirname, './styles/themes/syndicate.scss'),
path.resolve(__dirname, './styles/themes/hackerman.scss'),
path.resolve(__dirname, './styles/themes/retro.scss'),
path.resolve(__dirname, './styles/themes/syndicate.scss'),
path.resolve(__dirname, './index.js'),
],
},