mirror of
https://github.com/yogstation13/Yogstation.git
synced 2025-02-26 09:04:50 +00:00
@@ -35,3 +35,6 @@
|
||||
temp.filename = filename
|
||||
temp.filetype = filetype
|
||||
return temp
|
||||
|
||||
/datum/computer_file/proc/try_insert(obj/item/inserted_item, mob/living/user = null)
|
||||
return FALSE
|
||||
|
||||
276
code/modules/modular_computers/file_system/programs/blackjack.dm
Normal file
276
code/modules/modular_computers/file_system/programs/blackjack.dm
Normal file
@@ -0,0 +1,276 @@
|
||||
#define BLACKJACK_CONTINUE 0
|
||||
#define BLACKJACK_LOSS 1
|
||||
#define BLACKJACK_WIN 2
|
||||
#define BLACKJACK_TIE 3
|
||||
#define BLACKJACK_IDLE 4
|
||||
#define BLACKJACK_DEALER_TURN 5
|
||||
|
||||
#define JACK_CARD "J"
|
||||
#define QUEEN_CARD "Q"
|
||||
#define KING_CARD "K"
|
||||
#define ACE_CARD "A"
|
||||
|
||||
/datum/computer_file/program/blackjack
|
||||
filename = "blackjack"
|
||||
filedesc = "Nanotrasen Micro Arcade: Blackjack"
|
||||
program_icon_state = "arcade"
|
||||
extended_desc = "Nanotrasen does not permit anyone under the age of 21 to partake in gambling. Requires an NTNet connection."
|
||||
requires_ntnet = TRUE
|
||||
network_destination = "arcade network"
|
||||
size = 4
|
||||
tgui_id = "NtosBlackjack"
|
||||
program_icon = "gamepad"
|
||||
|
||||
var/game_state = BLACKJACK_IDLE
|
||||
/// Card format is value and suit i.e. "2H" = 2 of Hearts, "KC" = King of Clubs
|
||||
var/list/active_player_cards = list()
|
||||
var/list/active_dealer_cards = list()
|
||||
var/list/current_deck = list()
|
||||
var/credits_stored = 0
|
||||
var/active_wager = 0
|
||||
var/set_wager = 5
|
||||
|
||||
var/game_end_reason = ""
|
||||
|
||||
var/game_id = 0
|
||||
|
||||
var/datum/bank_account/temp_account // Call refresh_id_account() or get_credit_amount() before using this
|
||||
|
||||
/datum/computer_file/program/blackjack/proc/refresh_id_account()
|
||||
temp_account = null
|
||||
if(holder && istype(holder.holder, /obj/item/modular_computer))
|
||||
var/obj/item/modular_computer/computer = holder.holder
|
||||
var/obj/item/card/id/stored_card = computer.GetID()
|
||||
if(istype(stored_card) && istype(stored_card.registered_account))
|
||||
temp_account = stored_card.registered_account
|
||||
return stored_card.registered_account
|
||||
|
||||
/datum/computer_file/program/blackjack/proc/get_credit_amount()
|
||||
refresh_id_account()
|
||||
return temp_account?.account_balance || credits_stored
|
||||
|
||||
/datum/computer_file/program/blackjack/proc/adjust_credits(amt)
|
||||
if(refresh_id_account())
|
||||
temp_account.adjust_money(amt)
|
||||
else
|
||||
credits_stored += amt
|
||||
|
||||
/datum/computer_file/program/blackjack/proc/new_game()
|
||||
if(set_wager <= 0 || get_credit_amount() < set_wager)
|
||||
return
|
||||
|
||||
game_id++
|
||||
|
||||
adjust_credits(-set_wager)
|
||||
active_wager = set_wager
|
||||
|
||||
game_state = BLACKJACK_CONTINUE
|
||||
game_end_reason = ""
|
||||
active_player_cards = list()
|
||||
active_dealer_cards = list()
|
||||
current_deck = list(
|
||||
"2S","3S","4S","5S","6S","7S","8S","9S","10S","JS","QS","KS","AS",
|
||||
"2H","3H","4H","5H","6H","7H","8H","9H","10H","JH","QH","KH","AH",
|
||||
"2C","3C","4C","5C","6C","7C","8C","9C","10C","JC","QC","KC","AC",
|
||||
"2D","3D","4D","5D","6D","7D","8D","9D","10D","JD","QD","KD","AD"
|
||||
)
|
||||
shuffle_inplace(current_deck)
|
||||
|
||||
// smooth
|
||||
play_snd('sound/machines/switch3.ogg')
|
||||
active_player_cards += pop(current_deck)
|
||||
active_dealer_cards += pop(current_deck)
|
||||
active_player_cards += pop(current_deck)
|
||||
|
||||
/datum/computer_file/program/blackjack/proc/calculate_hand_worth(list/hand)
|
||||
var/worth = 0
|
||||
var/aces = 0
|
||||
var/list/hand_copy = LAZYCOPY(hand)
|
||||
for(var/card in hand_copy)
|
||||
card = copytext(card, 1, -1) // Remove the suit, we do not care about it
|
||||
if(text2num(card))
|
||||
worth += text2num(card)
|
||||
else
|
||||
switch(card)
|
||||
if(JACK_CARD, QUEEN_CARD, KING_CARD) // "Picture" cards are worth 10
|
||||
worth += 10
|
||||
if(ACE_CARD) // Aces are calculated last
|
||||
aces += 1
|
||||
|
||||
for(var/i in 1 to aces) // Ace is worth either 1 or 11, whichever is more beneficial
|
||||
if(worth < 12 - aces) // This algorithm will never surpass 21 unless you have too many aces (somehow)
|
||||
worth += 11
|
||||
else
|
||||
worth += 1
|
||||
|
||||
return worth
|
||||
|
||||
/datum/computer_file/program/blackjack/ui_data(mob/user)
|
||||
var/list/data = get_header_data()
|
||||
|
||||
data["game_state"] = game_state
|
||||
data["active_dealer_cards"] = active_dealer_cards
|
||||
data["active_player_cards"] = active_player_cards
|
||||
data["credits_stored"] = get_credit_amount()
|
||||
data["local_credits"] = credits_stored
|
||||
data["has_id"] = !!temp_account
|
||||
data["active_wager"] = active_wager
|
||||
data["set_wager"] = set_wager
|
||||
data["game_end_reason"] = game_end_reason
|
||||
|
||||
return data
|
||||
|
||||
/datum/computer_file/program/blackjack/try_insert(obj/item/inserted_item, mob/living/user)
|
||||
if(!holder || !istype(holder?.holder, /obj/item/modular_computer))
|
||||
return FALSE
|
||||
|
||||
if(!inserted_item.get_item_credit_value())
|
||||
return FALSE
|
||||
|
||||
credits_stored += inserted_item.get_item_credit_value()
|
||||
QDEL_NULL(inserted_item)
|
||||
play_snd('sound/machines/ping.ogg')
|
||||
SStgui.try_update_ui(user, src)
|
||||
return TRUE
|
||||
|
||||
/datum/computer_file/program/blackjack/proc/play_snd(sound_path)
|
||||
if(holder && istype(holder.holder, /obj/item/modular_computer))
|
||||
var/obj/item/modular_computer/computer = holder.holder
|
||||
computer.play_computer_sound(sound_path, 40, 1)
|
||||
|
||||
/datum/computer_file/program/blackjack/ui_act(action, list/params, datum/tgui/ui)
|
||||
. = ..()
|
||||
if(..())
|
||||
return .
|
||||
|
||||
if(ishuman(usr))
|
||||
var/mob/living/carbon/human/user = usr
|
||||
if(user.age < 21) // We do not condone underage gambling
|
||||
play_snd('sound/machines/buzz-sigh.ogg')
|
||||
return FALSE
|
||||
|
||||
switch(action)
|
||||
if("PRG_new_game")
|
||||
new_game()
|
||||
return TRUE
|
||||
|
||||
if("PRG_eject_credits")
|
||||
if(credits_stored < 1)
|
||||
return FALSE
|
||||
var/obj/item/holochip/holochip = new (usr.drop_location(), credits_stored)
|
||||
usr.put_in_hands(holochip)
|
||||
to_chat(usr, span_notice("You withdraw [credits_stored] credits into a holochip."))
|
||||
credits_stored = 0
|
||||
play_snd('sound/machines/click.ogg')
|
||||
return TRUE
|
||||
|
||||
if("PRG_set_wager")
|
||||
if(!isnum(text2num(params["wager"])))
|
||||
return FALSE
|
||||
var/new_wager = text2num(params["wager"])
|
||||
if(round(new_wager) < 1)
|
||||
return FALSE
|
||||
set_wager = round(new_wager)
|
||||
play_snd('sound/machines/click.ogg')
|
||||
return TRUE
|
||||
|
||||
if("PRG_hit")
|
||||
if(game_state != BLACKJACK_CONTINUE)
|
||||
return FALSE
|
||||
play_snd('sound/machines/switch3.ogg')
|
||||
active_player_cards += pop(current_deck)
|
||||
check_player_hand(usr)
|
||||
return TRUE
|
||||
|
||||
if("PRG_stand")
|
||||
if(game_state != BLACKJACK_CONTINUE)
|
||||
return FALSE
|
||||
game_state = BLACKJACK_DEALER_TURN
|
||||
addtimer(CALLBACK(src, PROC_REF(dealer_turn), game_id, usr), 1 SECONDS)
|
||||
play_snd('sound/machines/click.ogg')
|
||||
return TRUE
|
||||
|
||||
if("PRG_double_down")
|
||||
if(game_state != BLACKJACK_CONTINUE)
|
||||
return FALSE
|
||||
if(get_credit_amount() < active_wager)
|
||||
return
|
||||
adjust_credits(-active_wager)
|
||||
active_wager *= 2
|
||||
play_snd('sound/machines/switch3.ogg')
|
||||
active_player_cards += pop(current_deck)
|
||||
if(!check_player_hand(usr))
|
||||
game_state = BLACKJACK_DEALER_TURN
|
||||
addtimer(CALLBACK(src, PROC_REF(dealer_turn), game_id, usr), 1 SECONDS)
|
||||
return TRUE
|
||||
|
||||
/datum/computer_file/program/blackjack/proc/check_player_hand(mob/user)
|
||||
var/worth = calculate_hand_worth(active_player_cards)
|
||||
if(worth == 21)
|
||||
game_state = BLACKJACK_DEALER_TURN
|
||||
addtimer(CALLBACK(src, PROC_REF(dealer_turn), game_id, user), 1 SECONDS)
|
||||
return TRUE
|
||||
|
||||
if(worth > 21)
|
||||
game_state = BLACKJACK_LOSS
|
||||
game_end_reason = "You busted!"
|
||||
active_wager = 0
|
||||
play_snd('sound/machines/buzz-two.ogg')
|
||||
return TRUE
|
||||
|
||||
return FALSE
|
||||
|
||||
/datum/computer_file/program/blackjack/proc/dealer_turn(g_id, mob/user)
|
||||
if(game_state != BLACKJACK_DEALER_TURN || game_id != g_id)
|
||||
return
|
||||
|
||||
play_snd('sound/machines/switch1.ogg')
|
||||
active_dealer_cards += pop(current_deck)
|
||||
SStgui.try_update_ui(user, src)
|
||||
|
||||
var/dealer_worth = calculate_hand_worth(active_dealer_cards)
|
||||
if(dealer_worth < 17) // Dealer draws until it has 17 or higher
|
||||
addtimer(CALLBACK(src, PROC_REF(dealer_turn), game_id, user), 1 SECONDS)
|
||||
return
|
||||
|
||||
var/player_worth = calculate_hand_worth(active_player_cards)
|
||||
// check_player_hand() already checked for player bust
|
||||
if(dealer_worth == player_worth)
|
||||
game_state = BLACKJACK_TIE
|
||||
adjust_credits(active_wager)
|
||||
active_wager = 0
|
||||
SStgui.try_update_ui(user, src)
|
||||
play_snd('sound/machines/button1.ogg')
|
||||
return
|
||||
|
||||
if(dealer_worth > 21 || player_worth > dealer_worth)
|
||||
if(dealer_worth > 21)
|
||||
game_end_reason = "Dealer busted!"
|
||||
else
|
||||
game_end_reason = "You won!"
|
||||
game_state = BLACKJACK_WIN
|
||||
adjust_credits(active_wager * 2)
|
||||
active_wager = 0
|
||||
SStgui.try_update_ui(user, src)
|
||||
play_snd('sound/machines/chime.ogg')
|
||||
return
|
||||
|
||||
if(player_worth < dealer_worth) // this is redundant, but it helps understand what is happening
|
||||
game_state = BLACKJACK_LOSS // | || || |_
|
||||
game_end_reason = "You lost!"
|
||||
active_wager = 0
|
||||
SStgui.try_update_ui(user, src)
|
||||
play_snd('sound/machines/buzz-two.ogg')
|
||||
return
|
||||
|
||||
#undef BLACKJACK_CONTINUE
|
||||
#undef BLACKJACK_LOSS
|
||||
#undef BLACKJACK_WIN
|
||||
#undef BLACKJACK_TIE
|
||||
#undef BLACKJACK_IDLE
|
||||
#undef BLACKJACK_DEALER_TURN
|
||||
|
||||
#undef JACK_CARD
|
||||
#undef QUEEN_CARD
|
||||
#undef KING_CARD
|
||||
#undef ACE_CARD
|
||||
@@ -121,6 +121,16 @@
|
||||
return F
|
||||
return null
|
||||
|
||||
/obj/item/computer_hardware/hard_drive/try_insert(obj/item/I, mob/living/user)
|
||||
if(!holder)
|
||||
return FALSE
|
||||
|
||||
for(var/datum/computer_file/file in stored_files)
|
||||
if(file.try_insert(I, user))
|
||||
return TRUE
|
||||
|
||||
return FALSE
|
||||
|
||||
/obj/item/computer_hardware/hard_drive/Destroy()
|
||||
for(var/F in stored_files)
|
||||
qdel(F)
|
||||
|
||||
211
tgui/packages/tgui/interfaces/NtosBlackjack.tsx
Normal file
211
tgui/packages/tgui/interfaces/NtosBlackjack.tsx
Normal file
@@ -0,0 +1,211 @@
|
||||
import { useBackend } from '../backend';
|
||||
import { Box, Button, Icon, Section, Stack } from '../components';
|
||||
import { NtosWindow } from '../layouts';
|
||||
|
||||
enum GameState {
|
||||
Continue = 0,
|
||||
Loss = 1,
|
||||
Win = 2,
|
||||
Tie = 3,
|
||||
Idle = 4,
|
||||
DealerTurn = 5,
|
||||
}
|
||||
|
||||
const GameStateFlavor = {
|
||||
0:"Good luck!",
|
||||
1:"Better luck next time!",
|
||||
2:"Congratulations!",
|
||||
3:"Tied!",
|
||||
4:"Gamble responsibly!",
|
||||
5:"Dealer is drawing...",
|
||||
};
|
||||
|
||||
const ColorSuit = {
|
||||
"S":"black",
|
||||
"H":"red",
|
||||
"C":"black",
|
||||
"D":"red",
|
||||
};
|
||||
|
||||
const IconSuit = {
|
||||
"S":"spa",
|
||||
"H":"heart",
|
||||
"C":"cubes",
|
||||
"D":"diamond",
|
||||
};
|
||||
|
||||
type Data = {
|
||||
game_state: GameState;
|
||||
active_dealer_cards: Array<string>;
|
||||
active_player_cards: Array<string>;
|
||||
credits_stored: number;
|
||||
local_credits: number;
|
||||
has_id: boolean;
|
||||
active_wager: number;
|
||||
set_wager: number;
|
||||
game_end_reason: string;
|
||||
};
|
||||
|
||||
export const NtosBlackjack = (props, context) => {
|
||||
const { act, data } = useBackend<Data>(context);
|
||||
return (
|
||||
<NtosWindow
|
||||
width={600}
|
||||
height={572}>
|
||||
<NtosWindow.Content>
|
||||
<Stack fill>
|
||||
<Stack.Item>
|
||||
<Section fill>
|
||||
<br />
|
||||
<br />
|
||||
<br />
|
||||
<Button.Confirm
|
||||
disabled={data.credits_stored < data.set_wager}
|
||||
onClick={() => act('PRG_new_game')}
|
||||
textAlign='center'
|
||||
width={15}
|
||||
content={"New Game"} />
|
||||
<br />
|
||||
<br />
|
||||
<br />
|
||||
<Button.Confirm
|
||||
disabled={data.local_credits < 1}
|
||||
onClick={() => act('PRG_eject_credits')}
|
||||
textAlign='center'
|
||||
width={15}
|
||||
content={"Eject Credits"} />
|
||||
<br />
|
||||
<Button.Input
|
||||
currentValue={data.set_wager}
|
||||
onCommit={(e:any, value:string) => act('PRG_set_wager', {
|
||||
wager: value,
|
||||
})}
|
||||
textAlign='center'
|
||||
width={15}
|
||||
content={"Set Wager"} />
|
||||
<br />
|
||||
<br />
|
||||
<br />
|
||||
<Button.Confirm
|
||||
disabled={data.game_state !== GameState.Continue}
|
||||
onClick={() => act('PRG_hit')}
|
||||
textAlign='center'
|
||||
width={15}
|
||||
content={"Hit"} />
|
||||
<br />
|
||||
<Button.Confirm
|
||||
disabled={data.game_state !== GameState.Continue}
|
||||
onClick={() => act('PRG_stand')}
|
||||
textAlign='center'
|
||||
width={15}
|
||||
content={"Stand"} />
|
||||
<br />
|
||||
<Button.Confirm
|
||||
disabled={data.game_state !== GameState.Continue || data.credits_stored < data.set_wager}
|
||||
onClick={() => act('PRG_double_down')}
|
||||
textAlign='center'
|
||||
width={15}
|
||||
content={"Double Down"} />
|
||||
<br />
|
||||
<br />
|
||||
<br />
|
||||
<Box textAlign='center'>
|
||||
Credits {data.has_id ? " in account" : ""}
|
||||
<br />
|
||||
{data.credits_stored}
|
||||
<br />
|
||||
<br />
|
||||
Active Bet
|
||||
<br />
|
||||
{data.active_wager}
|
||||
<br />
|
||||
<br />
|
||||
<br />
|
||||
<br />
|
||||
{data.game_end_reason}
|
||||
<br />
|
||||
{GameStateFlavor[data.game_state]}
|
||||
</Box>
|
||||
</Section>
|
||||
</Stack.Item>
|
||||
<Stack.Item grow>
|
||||
<Stack fill vertical>
|
||||
<Stack.Item grow>
|
||||
<Section fill>
|
||||
<Box textAlign='center'>
|
||||
Dealer's hand
|
||||
</Box>
|
||||
<br />
|
||||
<Stack>
|
||||
{data.active_dealer_cards.map((card_string, index) =>
|
||||
(<Stack.Item
|
||||
bold
|
||||
fontSize={1.4}
|
||||
height={7}
|
||||
width={5}
|
||||
backgroundColor='white'
|
||||
color={ColorSuit[card_string.slice(-1)]}
|
||||
key={'dealercard'+index}>
|
||||
<Stack fill vertical>
|
||||
<Stack.Item>
|
||||
<Box px={0.4} fill>
|
||||
{card_string.slice(0, -1)}
|
||||
</Box>
|
||||
</Stack.Item>
|
||||
<Stack.Item grow align='center'>
|
||||
<Icon name={IconSuit[card_string.slice(-1)]} />
|
||||
</Stack.Item>
|
||||
<Stack.Item align='end'>
|
||||
<Box px={0.6} fill textAlign='right'>
|
||||
{card_string.slice(0, -1)}
|
||||
</Box>
|
||||
</Stack.Item>
|
||||
</Stack>
|
||||
</Stack.Item>)
|
||||
)}
|
||||
</Stack>
|
||||
</Section>
|
||||
</Stack.Item>
|
||||
<Stack.Item grow>
|
||||
<Section fill>
|
||||
<Box textAlign='center'>
|
||||
Your hand
|
||||
</Box>
|
||||
<br />
|
||||
<Stack>
|
||||
{data.active_player_cards.map((card_string, index) =>
|
||||
(<Stack.Item
|
||||
bold
|
||||
fontSize={1.4}
|
||||
height={7}
|
||||
width={5}
|
||||
backgroundColor='white'
|
||||
color={ColorSuit[card_string.slice(-1)]}
|
||||
key={'playercard'+index}>
|
||||
<Stack fill vertical>
|
||||
<Stack.Item>
|
||||
<Box px={0.4} fill>
|
||||
{card_string.slice(0, -1)}
|
||||
</Box>
|
||||
</Stack.Item>
|
||||
<Stack.Item grow align='center'>
|
||||
<Icon name={IconSuit[card_string.slice(-1)]} />
|
||||
</Stack.Item>
|
||||
<Stack.Item align='end'>
|
||||
<Box px={0.6} fill textAlign='right'>
|
||||
{card_string.slice(0, -1)}
|
||||
</Box>
|
||||
</Stack.Item>
|
||||
</Stack>
|
||||
</Stack.Item>)
|
||||
)}
|
||||
</Stack>
|
||||
</Section>
|
||||
</Stack.Item>
|
||||
</Stack>
|
||||
</Stack.Item>
|
||||
</Stack>
|
||||
</NtosWindow.Content>
|
||||
</NtosWindow>
|
||||
);
|
||||
};
|
||||
@@ -3022,6 +3022,7 @@
|
||||
#include "code\modules\modular_computers\file_system\program.dm"
|
||||
#include "code\modules\modular_computers\file_system\program_events.dm"
|
||||
#include "code\modules\modular_computers\file_system\programs\arcade.dm"
|
||||
#include "code\modules\modular_computers\file_system\programs\blackjack.dm"
|
||||
#include "code\modules\modular_computers\file_system\programs\configurator.dm"
|
||||
#include "code\modules\modular_computers\file_system\programs\file_browser.dm"
|
||||
#include "code\modules\modular_computers\file_system\programs\minesweeper.dm"
|
||||
|
||||
Reference in New Issue
Block a user