cards part 1

This commit is contained in:
sarcoph
2022-04-24 20:28:30 -08:00
parent 733122f33e
commit 818fcedad6
10 changed files with 812 additions and 275 deletions
+47 -180
View File
@@ -613,12 +613,11 @@
if(prob(5))
name = "drone (760) action figure"
desc = "An action figure modeled after 'drone (760)', it seems to be a bit dusty."
/*
|| A Deck of Cards for playing various games of chance ||
*/
/obj/item/toy/cards
resistance_flags = FLAMMABLE
max_integrity = 50
@@ -636,7 +635,8 @@
playsound(src, 'sound/items/cardshuffle.ogg', 50, 1)
return BRUTELOSS
/obj/item/toy/cards/proc/apply_card_vars(obj/item/toy/cards/newobj, obj/item/toy/cards/sourceobj) // Applies variables for supporting multiple types of card deck
/obj/item/toy/cards/proc/apply_card_vars(obj/item/toy/cards/newobj, obj/item/toy/cards/sourceobj)
// Applies variables for supporting multiple types of card deck
if(!istype(sourceobj))
return
@@ -658,53 +658,24 @@
/obj/item/toy/cards/deck/proc/populate_deck()
icon_state = "deck_[deckstyle]_full"
for(var/i in 2 to 10)
cards += "[i] of Hearts"
cards += "[i] of Spades"
cards += "[i] of Clubs"
cards += "[i] of Diamonds"
cards += "King of Hearts"
cards += "King of Spades"
cards += "King of Clubs"
cards += "King of Diamonds"
cards += "Queen of Hearts"
cards += "Queen of Spades"
cards += "Queen of Clubs"
cards += "Queen of Diamonds"
cards += "Jack of Hearts"
cards += "Jack of Spades"
cards += "Jack of Clubs"
cards += "Jack of Diamonds"
cards += "Ace of Hearts"
cards += "Ace of Spades"
cards += "Ace of Clubs"
cards += "Ace of Diamonds"
var/_suits = list("Hearts", "Spades", "Clubs", "Diamonds")
var/_faces = list("Ace", "King", "Queen", "Jack")
for(var/suit in _suits)
for(var/i in 2 to 10)
cards += list(list(
"name" = "[i] of [suit]",
"icon_state" = "[i]of[lowertext(suit)]",
"rotation" = null,
"face_up" = null
))
for(var/i in _faces)
cards += list(list(
"name" = "[i] of [suit]",
"icon_state" = "[lowertext(i)]of[lowertext(suit)]",
"rotation" = null,
"face_up" = null
))
//ATTACK HAND IGNORING PARENT RETURN VALUE
//ATTACK HAND NOT CALLING PARENT
/obj/item/toy/cards/deck/attack_hand(mob/user)
draw_card(user)
/obj/item/toy/cards/deck/proc/draw_card(mob/user)
if(user.lying)
return
var/choice = null
if(cards.len == 0)
to_chat(user, "<span class='warning'>There are no more cards to draw!</span>")
return
var/obj/item/toy/cards/singlecard/H = new/obj/item/toy/cards/singlecard(user.loc)
if(holo)
holo.spawned += H // track them leaving the holodeck
choice = cards[1]
H.cardname = choice
H.parentdeck = src
var/O = src
H.apply_card_vars(H,O)
src.cards.Cut(1,2) //Removes the top card from the list
H.pickup(user)
user.put_in_hands(H)
user.visible_message("[user] draws a card from the deck.", "<span class='notice'>You draw a card from the deck.</span>")
update_icon()
/obj/item/toy/cards/deck/update_icon()
if(cards.len > original_size/2)
@@ -716,60 +687,6 @@
else if(cards.len == 0)
icon_state = "deck_[deckstyle]_empty"
/obj/item/toy/cards/deck/attack_self(mob/user)
if(cooldown < world.time - 50)
cards = shuffle(cards)
playsound(src, 'sound/items/cardshuffle.ogg', 50, 1)
user.visible_message("[user] shuffles the deck.", "<span class='notice'>You shuffle the deck.</span>")
cooldown = world.time
/obj/item/toy/cards/deck/attackby(obj/item/I, mob/living/user, params)
if(istype(I, /obj/item/toy/cards/singlecard))
var/obj/item/toy/cards/singlecard/SC = I
if(SC.parentdeck == src)
if(!user.temporarilyRemoveItemFromInventory(SC))
to_chat(user, "<span class='warning'>The card is stuck to your hand, you can't add it to the deck!</span>")
return
cards += SC.cardname
user.visible_message("[user] adds a card to the bottom of the deck.","<span class='notice'>You add the card to the bottom of the deck.</span>")
qdel(SC)
else
to_chat(user, "<span class='warning'>You can't mix cards from other decks!</span>")
update_icon()
else if(istype(I, /obj/item/toy/cards/cardhand))
var/obj/item/toy/cards/cardhand/CH = I
if(CH.parentdeck == src)
if(!user.temporarilyRemoveItemFromInventory(CH))
to_chat(user, "<span class='warning'>The hand of cards is stuck to your hand, you can't add it to the deck!</span>")
return
cards += CH.currenthand
user.visible_message("[user] puts [user.p_their()] hand of cards in the deck.", "<span class='notice'>You put the hand of cards in the deck.</span>")
qdel(CH)
else
to_chat(user, "<span class='warning'>You can't mix cards from other decks!</span>")
update_icon()
else
return ..()
/obj/item/toy/cards/deck/MouseDrop(atom/over_object)
. = ..()
var/mob/living/M = usr
if(!istype(M) || usr.incapacitated() || usr.lying)
return
if(Adjacent(usr))
if(over_object == M && loc != M)
M.put_in_hands(src)
to_chat(usr, "<span class='notice'>You pick up the deck.</span>")
else if(istype(over_object, /obj/screen/inventory/hand))
var/obj/screen/inventory/hand/H = over_object
if(M.putItemFromInventoryInHandIfPossible(src, H.held_index))
to_chat(usr, "<span class='notice'>You pick up the deck.</span>")
else
to_chat(usr, "<span class='warning'>You can't reach it from here!</span>")
/obj/item/toy/cards/cardhand
name = "hand of cards"
@@ -785,7 +702,7 @@
interact(user)
for(var/t in currenthand)
handradial[t] = image(icon = src.icon, icon_state = "sc_[t]_[deckstyle]")
handradial[t] = image(icon = src.icon, icon_state = "sc_[t["icon_state"] || t["name"]]_[deckstyle]")
if(usr.stat || !ishuman(usr))
return
@@ -795,40 +712,29 @@
if(!choice)
return FALSE
var/obj/item/toy/cards/singlecard/C = new/obj/item/toy/cards/singlecard(cardUser.loc)
choice["rotation"] = null
choice["face_up"] = null
currenthand -= choice
handradial -= choice
C.parentdeck = parentdeck
C.cardname = choice
C.card = choice
C.apply_card_vars(C,O)
C.pickup(cardUser)
cardUser.put_in_hands(C)
cardUser.visible_message("<span class='notice'>[cardUser] draws a card from [cardUser.p_their()] hand.</span>", "<span class='notice'>You take the [C.cardname] from your hand.</span>")
cardUser.visible_message("<span class='notice'>[cardUser] draws a card from [cardUser.p_their()] hand.</span>", "<span class='notice'>You take the [C.card["name"]] from your hand.</span>")
interact(cardUser)
update_sprite()
if(length(currenthand) == 1)
var/obj/item/toy/cards/singlecard/N = new/obj/item/toy/cards/singlecard(loc)
N.parentdeck = parentdeck
N.cardname = currenthand[1]
N.card = currenthand[1]
N.apply_card_vars(N,O)
qdel(src)
N.pickup(cardUser)
cardUser.put_in_hands(N)
to_chat(cardUser, "<span class='notice'>You also take [currenthand[1]] and hold it.</span>")
/obj/item/toy/cards/cardhand/attackby(obj/item/toy/cards/singlecard/C, mob/living/user, params)
if(istype(C))
if(C.parentdeck == src.parentdeck)
src.currenthand += C.cardname
user.visible_message("<span class='notice'>[user] adds a card to [user.p_their()] hand.</span>", "<span class='notice'>You add the [C.cardname] to your hand.</span>")
qdel(C)
interact(user)
update_sprite(src)
else
to_chat(user, "<span class='warning'>You can't mix cards from other decks!</span>")
else
return ..()
/obj/item/toy/cards/cardhand/apply_card_vars(obj/item/toy/cards/newobj,obj/item/toy/cards/sourceobj)
..()
newobj.deckstyle = sourceobj.deckstyle
@@ -863,7 +769,20 @@
if(overlay_cards)
var/k = overlay_cards == 2 ? 1 : overlay_cards - 2
for(var/i = k; i <= overlay_cards; i++)
var/card_overlay = image(icon=src.icon,icon_state="sc_[currenthand[i]]_[deckstyle]",pixel_x=(1-i+k)*3,pixel_y=(1-i+k)*3)
var/_card = currenthand[i]
var/_angle = _card["rotation"] || rotation
var/_dir = GetAngle(_angle)
var/card_overlay = image(
icon = src.icon,
icon_state = "sc_[_card["icon_state"] || _card["name"]]_[deckstyle]",
pixel_x = (1 - i + k)*3,
pixel_y = (1 - i + k)*3,
dir = (
_dir == 90 ? EAST :
_dir == 180 ? SOUTH :
NORTH
)
)
add_overlay(card_overlay)
/obj/item/toy/cards/singlecard
@@ -872,8 +791,7 @@
icon = 'icons/obj/toy.dmi'
icon_state = "singlecard_down_nanotrasen"
w_class = WEIGHT_CLASS_TINY
var/cardname = null
var/flipped = 0
var/card = null
pixel_x = -5
@@ -882,7 +800,9 @@
if(ishuman(user))
var/mob/living/carbon/human/cardUser = user
if(cardUser.is_holding(src))
cardUser.visible_message("[cardUser] checks [cardUser.p_their()] card.", "<span class='notice'>The card reads: [cardname].</span>")
cardUser.visible_message(
"[cardUser] checks [cardUser.p_their()] card.",
"<span class='notice'>The card reads: [card["name"]]. [card["desc"] || ""]</span>")
else
. += "<span class='warning'>You need to have the card in your hand to check it!</span>"
@@ -892,65 +812,11 @@
set src in range(1)
if(!ishuman(usr) || !usr.canUseTopic(src, BE_CLOSE))
return
if(!flipped)
src.flipped = 1
if (cardname)
src.icon_state = "sc_[cardname]_[deckstyle]"
src.name = src.cardname
else
src.icon_state = "sc_Ace of Spades_[deckstyle]"
src.name = "What Card"
src.pixel_x = 5
else if(flipped)
src.flipped = 0
src.icon_state = "singlecard_down_[deckstyle]"
src.name = "card"
src.pixel_x = -5
/obj/item/toy/cards/singlecard/attackby(obj/item/I, mob/living/user, params)
if(istype(I, /obj/item/toy/cards/singlecard/))
var/obj/item/toy/cards/singlecard/C = I
if(C.parentdeck == src.parentdeck)
var/obj/item/toy/cards/cardhand/H = new/obj/item/toy/cards/cardhand(user.loc)
H.currenthand += C.cardname
H.currenthand += src.cardname
H.parentdeck = C.parentdeck
H.apply_card_vars(H,C)
to_chat(user, "<span class='notice'>You combine the [C.cardname] and the [src.cardname] into a hand.</span>")
qdel(C)
qdel(src)
H.pickup(user)
user.put_in_active_hand(H)
else
to_chat(user, "<span class='warning'>You can't mix cards from other decks!</span>")
if(istype(I, /obj/item/toy/cards/cardhand/))
var/obj/item/toy/cards/cardhand/H = I
if(H.parentdeck == parentdeck)
H.currenthand += cardname
user.visible_message("[user] adds a card to [user.p_their()] hand.", "<span class='notice'>You add the [cardname] to your hand.</span>")
qdel(src)
H.interact(user)
if(H.currenthand.len > 4)
H.icon_state = "[deckstyle]_hand5"
else if(H.currenthand.len > 3)
H.icon_state = "[deckstyle]_hand4"
else if(H.currenthand.len > 2)
H.icon_state = "[deckstyle]_hand3"
else
to_chat(user, "<span class='warning'>You can't mix cards from other decks!</span>")
else
return ..()
/obj/item/toy/cards/singlecard/attack_self(mob/user)
if(usr.stat || !ishuman(usr) || !usr.canmove || usr.restrained())
return
Flip()
FlipCards()
/obj/item/toy/cards/singlecard/apply_card_vars(obj/item/toy/cards/singlecard/newobj,obj/item/toy/cards/sourceobj)
..()
newobj.deckstyle = sourceobj.deckstyle
newobj.icon_state = "singlecard_down_[deckstyle]" // Without this the card is invisible until flipped. It's an ugly hack, but it works.
newobj.card_hitsound = sourceobj.card_hitsound
newobj.hitsound = newobj.card_hitsound
newobj.card_force = sourceobj.card_force
@@ -963,6 +829,7 @@
newobj.throw_range = newobj.card_throw_range
newobj.card_attack_verb = sourceobj.card_attack_verb
newobj.attack_verb = newobj.card_attack_verb
newobj.update_icon()
/*
|| Syndicate playing cards, for pretending you're Gambit and playing poker for the nuke disk. ||
+92 -92
View File
@@ -55,104 +55,104 @@
P.name = "Blank Card"
P.card_icon = "cas_white"
cards += P
shuffle_inplace(cards) // distribute blank cards throughout deck
// shuffle_inplace(cards) // distribute blank cards throughout deck
/obj/item/toy/cards/deck/cas/draw_card(mob/user)
if(user.lying)
return
if(cards.len == 0)
to_chat(user, "<span class='warning'>There are no more cards to draw!</span>")
return
var/obj/item/toy/cards/singlecard/cas/H = new/obj/item/toy/cards/singlecard/cas(user.loc)
var/datum/playingcard/choice = cards[1]
if (choice.name == "Blank Card")
H.blank = 1
H.name = choice.name
H.buffertext = choice.name
H.icon_state = choice.card_icon
H.card_face = choice.card_icon
H.parentdeck = src
src.cards -= choice
H.pickup(user)
user.put_in_hands(H)
user.visible_message("[user] draws a card from the deck.", "<span class='notice'>You draw a card from the deck.</span>")
update_icon()
// /obj/item/toy/cards/deck/cas/draw_card(mob/user)
// if(user.lying)
// return
// if(cards.len == 0)
// to_chat(user, "<span class='warning'>There are no more cards to draw!</span>")
// return
// var/obj/item/toy/cards/singlecard/cas/H = new/obj/item/toy/cards/singlecard/cas(user.loc)
// var/datum/playingcard/choice = cards[1]
// if (choice.name == "Blank Card")
// H.blank = 1
// H.name = choice.name
// H.buffertext = choice.name
// H.icon_state = choice.card_icon
// H.card_face = choice.card_icon
// H.parentdeck = src
// src.cards -= choice
// H.pickup(user)
// user.put_in_hands(H)
// user.visible_message("[user] draws a card from the deck.", "<span class='notice'>You draw a card from the deck.</span>")
// update_icon()
/obj/item/toy/cards/deck/cas/attackby(obj/item/I, mob/living/user, params)
if(istype(I, /obj/item/toy/cards/singlecard/cas))
var/obj/item/toy/cards/singlecard/cas/SC = I
if(!user.temporarilyRemoveItemFromInventory(SC))
to_chat(user, "<span class='warning'>The card is stuck to your hand, you can't add it to the deck!</span>")
return
var/datum/playingcard/RC // replace null datum for the re-added card
RC = new()
RC.name = "[SC.name]"
RC.card_icon = SC.card_face
cards += RC
user.visible_message("[user] adds a card to the bottom of the deck.","<span class='notice'>You add the card to the bottom of the deck.</span>")
qdel(SC)
update_icon()
// /obj/item/toy/cards/deck/cas/attackby(obj/item/I, mob/living/user, params)
// if(istype(I, /obj/item/toy/cards/singlecard/cas))
// var/obj/item/toy/cards/singlecard/cas/SC = I
// if(!user.temporarilyRemoveItemFromInventory(SC))
// to_chat(user, "<span class='warning'>The card is stuck to your hand, you can't add it to the deck!</span>")
// return
// var/datum/playingcard/RC // replace null datum for the re-added card
// RC = new()
// RC.name = "[SC.name]"
// RC.card_icon = SC.card_face
// cards += RC
// user.visible_message("[user] adds a card to the bottom of the deck.","<span class='notice'>You add the card to the bottom of the deck.</span>")
// qdel(SC)
// update_icon()
/obj/item/toy/cards/deck/cas/update_icon()
if(cards.len < 26)
icon_state = "deck_[deckstyle]_low"
// /obj/item/toy/cards/deck/cas/update_icon()
// if(cards.len < 26)
// icon_state = "deck_[deckstyle]_low"
/obj/item/toy/cards/singlecard/cas
name = "CAS card"
desc = "A CAS card."
icon_state = "cas_white"
flipped = 0
var/card_face = "cas_white"
var/blank = 0
var/buffertext = "A funny bit of text."
// /obj/item/toy/cards/singlecard/cas
// name = "CAS card"
// desc = "A CAS card."
// icon_state = "cas_white"
// flipped = 0
// var/card_face = "cas_white"
// var/blank = 0
// var/buffertext = "A funny bit of text."
/obj/item/toy/cards/singlecard/cas/examine(mob/user)
. = ..()
if (flipped)
. += "<span class='notice'>The card is face down.</span>"
else if (blank)
. += "<span class='notice'>The card is blank. Write on it with a pen.</span>"
else
. += "<span class='notice'>The card reads: [name]</span>"
. += "<span class='notice'>Alt-click to flip it.</span>"
// /obj/item/toy/cards/singlecard/cas/examine(mob/user)
// . = ..()
// if (flipped)
// . += "<span class='notice'>The card is face down.</span>"
// else if (blank)
// . += "<span class='notice'>The card is blank. Write on it with a pen.</span>"
// else
// . += "<span class='notice'>The card reads: [name]</span>"
// . += "<span class='notice'>Alt-click to flip it.</span>"
/obj/item/toy/cards/singlecard/cas/Flip()
set name = "Flip Card"
set category = "Object"
set src in range(1)
if(!ishuman(usr) || !usr.canUseTopic(src, BE_CLOSE))
return
if(!flipped)
name = "CAS card"
else if(flipped)
name = buffertext
flipped = !flipped
update_icon()
// /obj/item/toy/cards/singlecard/cas/Flip()
// set name = "Flip Card"
// set category = "Object"
// set src in range(1)
// if(!ishuman(usr) || !usr.canUseTopic(src, BE_CLOSE))
// return
// if(!flipped)
// name = "CAS card"
// else if(flipped)
// name = buffertext
// flipped = !flipped
// update_icon()
/obj/item/toy/cards/singlecard/cas/AltClick(mob/living/user)
. = ..()
if(!ishuman(user) || !user.canUseTopic(src, BE_CLOSE))
return
Flip()
return TRUE
// /obj/item/toy/cards/singlecard/cas/AltClick(mob/living/user)
// . = ..()
// if(!ishuman(user) || !user.canUseTopic(src, BE_CLOSE))
// return
// Flip()
// return TRUE
/obj/item/toy/cards/singlecard/cas/update_icon()
if(flipped)
icon_state = "[card_face]_flipped"
else
icon_state = "[card_face]"
// /obj/item/toy/cards/singlecard/cas/update_icon()
// if(flipped)
// icon_state = "[card_face]_flipped"
// else
// icon_state = "[card_face]"
/obj/item/toy/cards/singlecard/cas/attackby(obj/item/I, mob/living/user, params)
if(istype(I, /obj/item/pen))
if(!user.is_literate())
to_chat(user, "<span class='notice'>You scribble illegibly on [src]!</span>")
return
if(!blank)
to_chat(user, "You cannot write on that card.")
return
var/cardtext = stripped_input(user, "What do you wish to write on the card?", "Card Writing", "", 50)
if(!cardtext || !user.canUseTopic(src, BE_CLOSE))
return
name = cardtext
buffertext = cardtext
blank = 0
// /obj/item/toy/cards/singlecard/cas/attackby(obj/item/I, mob/living/user, params)
// if(istype(I, /obj/item/pen))
// if(!user.is_literate())
// to_chat(user, "<span class='notice'>You scribble illegibly on [src]!</span>")
// return
// if(!blank)
// to_chat(user, "You cannot write on that card.")
// return
// var/cardtext = stripped_input(user, "What do you wish to write on the card?", "Card Writing", "", 50)
// if(!cardtext || !user.canUseTopic(src, BE_CLOSE))
// return
// name = cardtext
// buffertext = cardtext
// blank = 0
@@ -0,0 +1,400 @@
/*
* cards rework; uses TGUI and allows in-depth manipulation of cards, such as
* angles, flip states, drawing a number of cards at once, peeking, etc.
*
* sarcoph march 2022
*/
#define CARD_ROTATION_UP "upright"
#define CARD_ROTATION_SIDE "sideways"
#define CARD_ROTATION_DOWN "reversed"
// ================================= GENERAL CARDS =================================
/obj/item/toy/cards
var/face_up = FALSE
var/rotation = CARD_ROTATION_UP
var/merge_rank = 0
/obj/item/toy/cards/proc/GetAngle(_dir)
var/_angle = 0
switch(_dir)
if(CARD_ROTATION_UP)
_angle = 0
if(CARD_ROTATION_SIDE)
_angle = 90
if(CARD_ROTATION_DOWN)
_angle = 180
return _angle
/obj/item/toy/cards/proc/RotateCards(angle)
var/list/_rotations = list(CARD_ROTATION_UP, CARD_ROTATION_SIDE, CARD_ROTATION_DOWN)
var/list/_indexof = _rotations.Find(rotation)
if(angle)
rotation = angle
else
rotation = _rotations[_indexof%3 + 1]
update_icon()
/obj/item/toy/cards/proc/FlipCards(side)
if(side != null) face_up = side
else face_up = !face_up
update_icon()
/**
* Handles functionality for merging different types of cards.
*
* Arguments:
* * target - The "greater" card item that this object is going to merge into.
* * user - The mob that is performing this merge.
*
* Returns:
* * TRUE/FALSE: Whether or not this logic is considered "processed" - i.e., a merge
* was actually attempted.
*/
/obj/item/toy/cards/proc/MergeInto(obj/item/toy/cards/target, mob/living/user)
if(!user.temporarilyRemoveItemFromInventory(src))
to_chat(user, "<span class='warning'>\The [src] is stuck to your hand, you can't add it to \the [target]!</span>")
return TRUE
if(target.parentdeck != src && src.parentdeck != target && src.parentdeck != target.parentdeck)
to_chat(user, "<span class='warning'>You can't mix cards from other decks!</span>")
return TRUE
return FALSE
// unimplemented
/**
* Announces card(s) being added to a deck, and then deletes the card(s).
*/
/obj/item/toy/cards/proc/FinishMergingCards(obj/item/toy/cards/target, mob/living/user)
return FALSE // unimplemented
/obj/item/toy/cards/attackby(obj/item/I, mob/living/user, params)
if(istype(I, /obj/item/toy/cards))
var/obj/item/toy/cards/C = I
var/obj/item/toy/cards/greater = merge_rank > C.merge_rank ? src : C
var/obj/item/toy/cards/lesser = greater == src ? C : src
if(lesser.MergeInto(greater, user)) return
else
return ..()
// ================================= DECK OF CARDS =================================
/obj/item/toy/cards/deck
var/peeking = FALSE
var/dealing = FALSE
merge_rank = 3
/**
* Randomizes positions of all cards in a deck, plays a nice sound,
* and announces this to the `user`'s surroundings. There is a small
* cooldown.
*
* Arguments:
* * user - The `mob` shuffling this deck of cards.
*/
/obj/item/toy/cards/deck/proc/ShuffleCards(mob/user)
if(cooldown < world.time - 5 SECONDS)
cards = shuffle(cards)
playsound(src, 'sound/items/cardshuffle.ogg', 50, 1)
user.visible_message("[user] shuffles the deck.", "<span class='notice'>You shuffle the deck.</span>")
cooldown = world.time
/**
* Draws cards into a new hand from a list of indices, turning those new
* cards into a hand.
*
* Arguments:
* * card_indices - The `list` of card indices to remove from `cards`.
*
* Returns:
* * /obj/item/toy/cards/cardhand - A new hand containing the removed cards.
* OR
* * /obj/item/toy/cards/singlecard - A single card, if there is only one index.
*/
/obj/item/toy/cards/deck/proc/DrawCards(list/card_indices)
if(card_indices.len == 1) return DrawOneCard(card_indices)
var/obj/item/toy/cards/cardhand/H = new/obj/item/toy/cards/cardhand(usr.loc)
var/list/cards_to_remove = list()
for(var/C in card_indices)
var/card_to_add = cards[C]
card_to_add["rotation"] = rotation
card_to_add["face_up"] = face_up
H.currenthand += list(card_to_add)
cards_to_remove += list(card_to_add)
cards -= cards_to_remove
H.parentdeck = src
H.apply_card_vars(H,src)
update_icon()
return H
/obj/item/toy/cards/deck/proc/DrawOneCard(list/card_indices)
var/obj/item/toy/cards/singlecard/S = new/obj/item/toy/cards/singlecard(usr.loc)
var/_card = cards[card_indices[1]]
_card["rotation"] = rotation
_card["face_up"] = face_up
S.card = _card
S.rotation = _card["rotation"]
S.face_up = _card["face_up"]
S.parentdeck = src
S.apply_card_vars(S,src)
cards -= list(_card)
update_icon()
return S
/obj/item/toy/cards/deck/FinishMergingCards(obj/item/toy/cards/target, mob/living/user)
var/message = "[user] adds \the [target] to the bottom of \the [src]."
var/self_message = "<span class='notice'>You add \the [target] to the bottom of \the [src].</span>"
user.visible_message(message, self_message)
qdel(target)
update_icon()
/obj/item/toy/cards/deck/examine(mob/user)
. = ..()
. += "<span class='notice'>Alt-Click to quick-draw a card.</span>"
/obj/item/toy/cards/deck/AltClick(mob/user)
. = ..()
if(!ishuman(usr) || !usr.canUseTopic(src, BE_CLOSE))
return
var/obj/item/toy/cards/drawn = DrawCards(list(1))
drawn.pickup(user)
user.put_in_hands(drawn)
to_chat(user, "<span class='notice'>You draw \a [drawn] from \the [src].</span>")
// =================== TGUI stuff ===================
/obj/item/toy/cards/deck/ui_interact(mob/user, ui_key, datum/tgui/ui, force_open, datum/tgui/master_ui, datum/tgui_state/state)
ui = SStgui.try_update_ui(user, src, ui_key, ui, force_open)
if(!ui)
ui = new(user, src, ui_key, "CardsDeck", name, 300, 400, master_ui, state)
ui.open()
/obj/item/toy/cards/deck/ui_act(action, params)
if(..())
return
var/list/targets = list(usr, src)
switch(action)
if("deal")
var/n_cards = text2num(params["count"])
var/n_hands = text2num(params["hands"])
if(dealing) return FALSE
if(!n_cards || !n_hands) return FALSE
if(n_cards * n_hands > cards.len)
to_chat(usr, "<span class='warning'>You can't deal more cards than there are in the deck!</span>")
return FALSE
dealing = TRUE
to_chat(usr, "<span class='notice'>You get ready to deal cards...</span>")
if(do_after_mob(usr, targets, 1 SECONDS, progress=TRUE))
visible_message("[usr] begins dealing cards.")
var/list/holder = list()
var/broken = FALSE
for(var/C = 1, C <= n_cards, C++) holder += C // card indices placeholder
for(var/H = 1, H <= n_hands, H++)
if(do_after_mob(usr, targets, 0.5 SECONDS, progress=TRUE) && dealing)
var/obj/item/toy/cards/hand = DrawCards(holder)
step(hand, GLOB.alldirs[H])
else
broken = TRUE
break
if(broken)
visible_message("<span class='danger'>[usr] stops in the middle of dealing cards!</span>")
dealing = FALSE
if("draw")
if(!params["cards"]) return FALSE
var/list/P = splittext(params["cards"], ",")
var/list/P_cards = list()
for(var/T in P)
P_cards += text2num(T) + 1
var/obj/item/toy/cards/H = DrawCards(P_cards)
H.pickup(usr)
usr.put_in_hands(H)
if("flip")
var/P_side = params["side"]
var/flip_side = null
if(P_side)
flip_side = P_side == "face_down" ? FALSE : P_side == "face_up" ? TRUE : null
FlipCards(flip_side)
return TRUE
if("peek")
visible_message("<span class='warning'>[usr] is peeking in \the [name]!</span>")
if(do_after_mob(usr, targets, 3 SECONDS, progress=TRUE))
to_chat(usr, "<span class='notice'>You peek into \the [name].</span>")
peeking = TRUE
if("rotate")
RotateCards(params["angle"])
return TRUE
if("shuffle")
peeking = FALSE
ShuffleCards(usr)
update_icon()
return TRUE
/obj/item/toy/cards/deck/ui_data(mob/user)
var/list/data = list()
data["face_up"] = face_up
data["rotation"] = rotation
data["cards"] = cards
data["name"] = name
data["peeking"] = peeking
return data
/obj/item/toy/cards/deck/ui_static_data(mob/user)
var/list/data = list()
data["possible_rotations"] = list(CARD_ROTATION_UP, CARD_ROTATION_SIDE, CARD_ROTATION_DOWN)
return data
/obj/item/toy/cards/deck/ui_close()
dealing = FALSE
peeking = FALSE
// ================================= HAND OF CARDS =================================
/obj/item/toy/cards/cardhand
merge_rank = 2
face_up = TRUE
/obj/item/toy/cards/cardhand/proc/QuickAnnounce(mob/living/user)
if(!user.is_holding(src))
to_chat(user, "<span class='warning'>You need to be holding \the [src] to show it!</span>")
return
if(user.stat || user.restrained())
return
var/list/temp_cards = list()
var/facedown = 0
for(var/C in currenthand)
var/_flipped = C["face_up"] || face_up
var/_angle = C["rotation"] || rotation
if(_flipped)
if(is_all_same_direction())
temp_cards += "\a [C["name"]]"
else
temp_cards += "\a [_angle] [C["name"]]"
else
facedown++
if(facedown > 0)
temp_cards += "[facedown] unrevealed card\s"
visible_message("<span class='notice'>[user] shows [user.p_their()] hand: [english_list(temp_cards)].</span>")
/obj/item/toy/cards/cardhand/proc/is_all_same_direction()
var/compare_orient = currenthand[1]["rotation"]
for(var/list/C in currenthand)
var/_rotation = C["rotation"] || rotation
if(_rotation != compare_orient) return FALSE
return TRUE
/obj/item/toy/cards/cardhand/MergeInto(obj/item/toy/cards/target, mob/living/user)
if(..())
return TRUE
if(istype(target, /obj/item/toy/cards/deck))
var/obj/item/toy/cards/deck/C = target
for(var/_card = 1, _card < currenthand.len, _card++)
currenthand[_card]["rotation"] = null
currenthand[_card]["face_up"] = null
C.cards += currenthand
C.FinishMergingCards(src, user)
else if(istype(target, /obj/item/toy/cards/cardhand))
if(do_after_mob(user, list(user,src,target), 0.5 SECONDS))
var/obj/item/toy/cards/cardhand/C = target
C.currenthand += currenthand
C.FinishMergingCards(src, user)
else
return FALSE
return TRUE
/obj/item/toy/cards/cardhand/FinishMergingCards(obj/item/toy/cards/target, mob/living/user)
user.visible_message("[user] combines \the [target] into [user.p_their()] hand.",\
"<span class='notice'>You combine \the [target] into the [src].</span>")
qdel(target)
update_icon()
/obj/item/toy/cards/cardhand/examine(mob/user)
. = ..()
. += "<span class='notice'>Alt-Click to quick-announce your deck.</span>"
/obj/item/toy/cards/cardhand/AltClick(mob/user)
. = ..()
QuickAnnounce(user)
// =================== TGUI stuff ===================
// ================================= SINGLE CARDS =================================
/obj/item/toy/cards/singlecard
merge_rank = 1
/obj/item/toy/cards/singlecard/MergeInto(obj/item/toy/cards/target, mob/living/user)
if(..())
return TRUE
if(istype(target, /obj/item/toy/cards/deck))
var/obj/item/toy/cards/deck/C = target
card["rotation"] = null
card["face_up"] = null
C.cards += list(card)
C.FinishMergingCards(src, user)
else if(istype(target, /obj/item/toy/cards/cardhand))
var/obj/item/toy/cards/cardhand/C = target
C.currenthand += list(card)
C.FinishMergingCards(src, user)
else if(istype(target, /obj/item/toy/cards/singlecard))
var/obj/item/toy/cards/singlecard/C = target
var/obj/item/toy/cards/cardhand/H = new/obj/item/toy/cards/cardhand(user.loc)
H.currenthand += list(C.card)
H.currenthand += list(src.card)
H.parentdeck = C.parentdeck
H.apply_card_vars(H,C)
H.pickup(user)
user.put_in_hands(H)
C.FinishMergingCards(src, user)
else
return FALSE
return TRUE
/obj/item/toy/cards/singlecard/FinishMergingCards(obj/item/toy/cards/singlecard/target, mob/living/user)
to_chat(user, "<span class='notice'>You combine the [target.card["name"]] and the [src.card["name"]] into a hand.</span>")
qdel(target)
qdel(src)
update_icon()
/obj/item/toy/cards/singlecard/examine(mob/user)
. = ..()
. += "<span class='notice'>Click to flip. Alt-Click to rotate.</span>"
/obj/item/toy/cards/singlecard/CtrlClick(mob/user)
. = ..()
if(!ishuman(usr) || !usr.canUseTopic(src, BE_CLOSE))
return
RotateCards()
to_chat(user, "<span class='notice'>You turn \the [src] to \a [rotation] position.</span>")
/obj/item/toy/cards/singlecard/attack_self(mob/user)
. = ..()
if(!ishuman(usr) || !usr.canUseTopic(src, BE_CLOSE))
return
FlipCards()
to_chat(user, "<span class='notice'>You flip \the [src] [(face_up ? "face-up" : "face-down")]</span>.")
/obj/item/toy/cards/singlecard/update_icon()
. = ..()
var/matrix/rot_matrix = matrix()
rot_matrix.Turn(GetAngle(rotation))
transform = rot_matrix
if(face_up)
if(card)
src.icon_state = "sc_[card["icon_state"] || card["name"]]_[deckstyle]"
src.name = src.card["name"]
else
src.icon_state = "sc_aceofspades_[deckstyle]"
src.name = "What Card"
src.pixel_x = 5
else
src.icon_state = "singlecard_down_[deckstyle]"
src.name = "card"
src.pixel_x = -5
// =================== TGUI stuff ===================
@@ -0,0 +1,88 @@
/*
lover's dice: based off a really funny yakuza gif i saw on tumblr years ago
these give suggestions for sex acts to perform. it's stupid but fun.
sarcoph mar 2022
*/
// dice bag
/obj/item/storage/pill_bottle/lovedice
name = "bag of love dice"
desc = "Contains all the intimate ideas you'll ever need. A game that everyone wins!"
icon = 'hyperstation/icons/obj/toy.dmi'
icon_state = "lovedicebag"
price = 1
/obj/item/storage/pill_bottle/lovedice/Initialize()
. = ..()
new /obj/item/dice/lover/d6_gesture(src)
new /obj/item/dice/lover/d6_location(src)
new /obj/item/dice/lover/d6_action(src)
new /obj/item/dice/lover/d6_bodypart(src)
// dice
/obj/item/dice/lover
desc = "A die with six sides to inspire some bedroom action."
icon = 'hyperstation/icons/obj/toy.dmi'
sides = 6
/obj/item/dice/lover/update_icon()
return // override the dice proc for this, there is no overlay
/obj/item/dice/lover/examine(mob/user)
. = ..() // again, no overlays
. += "<span class='notice'>The top reads [result].</span>"
// actual dice
/obj/item/dice/lover/d6_gesture
name = "lover's d6 (v1)"
icon_state = "loved6_1"
special_faces = list(
"Let's hug",
"Let's kiss",
"Let's play",
"Let's fuck", // it actually says "let's do it" on the irl ones lol
"Let's wrestle",
"Let's ?"
)
/obj/item/dice/lover/d6_location
name = "lover's d6 (v2)"
icon_state = "loved6_2"
special_faces = list(
"On a chair",
"On the bed",
"On the floor",
"In the closet",
"In the bathtub",
"In the ?"
)
/obj/item/dice/lover/d6_action
name = "lover's d6 (v3)"
icon_state = "loved6_3"
special_faces = list(
"Caress my",
"Kiss my",
"Grab my",
"Rub my",
"Tickle my",
"Surprise!"
)
/obj/item/dice/lover/d6_bodypart
name = "lover's d6 (v4)"
icon_state = "loved6_4"
special_faces = list(
"Back",
"Chest",
"Face",
"Ass",
"Genitals",
"Surprise!"
)
Binary file not shown.

After

Width:  |  Height:  |  Size: 835 B

BIN
View File
Binary file not shown.

Before

Width:  |  Height:  |  Size: 38 KiB

After

Width:  |  Height:  |  Size: 38 KiB

@@ -70,6 +70,7 @@
/obj/item/electropack/vibrator = 2,
/obj/item/fleshlight = 2,
/obj/item/storage/box/portallight = 1,
/obj/item/storage/pill_bottle/lovedice = 5,
)
contraband = list(
/obj/item/clothing/under/gear_harness = 3,
+2
View File
@@ -3101,8 +3101,10 @@
#include "hyperstation\code\datums\weather\oxygen_rain.dm"
#include "hyperstation\code\game\machinery\lore_terminal.dm"
#include "hyperstation\code\game\objects\railings.dm"
#include "hyperstation\code\game\objects\items\cards.dm"
#include "hyperstation\code\game\objects\items\coconutcannon.dm"
#include "hyperstation\code\game\objects\items\cosmetics.dm"
#include "hyperstation\code\game\objects\items\lovedice.dm"
#include "hyperstation\code\game\objects\items\storage\big_bag.dm"
#include "hyperstation\code\game\objects\structures\bench.dm"
#include "hyperstation\code\game\objects\structures\ghost_role_spawners.dm"
+179
View File
@@ -0,0 +1,179 @@
import { useBackend, useLocalState } from '../backend';
import { Box, Button, Dropdown, LabeledList, NumberInput, Section, Table, Tabs } from '../components';
import { Window } from '../layouts';
export const CardsDeck = (props, context) => {
const { data, act } = useBackend(context);
const {
face_up,
rotation,
cards,
name,
peeking,
possible_rotations,
} = data;
const [tab, setTab] = useLocalState(context, 'tab', 0);
const [drawCount, setDrawCount] = useLocalState(context, 'drawCount', 1);
const [dealCardsCount, setDealCardsCount] = useLocalState(context, 'dealCards', 1);
const [dealHandsCount, setDealHandsCount] = useLocalState(context, 'dealHands', 1);
const [selectedCards, setSelectedCards] = useLocalState(context, 'selectedCards', []);
const select_card = card => {
if (selectedCards.includes(card)) {
setSelectedCards(selectedCards.filter(element => element !== card));
}
else {
setSelectedCards([...selectedCards, card]);
}
};
return (
<Window resizable>
<Window.Content scrollable>
<Section title={name}>
<Box>
This <b>{name}</b> contains <b>{cards.length} cards</b>.
</Box>
<Box>
The deck is <b>{rotation}</b> and turned <b>{face_up ? "face-up" : "face-down"}</b>.
</Box>
{!!face_up && cards.length > 0 && (
<Box>
You can see a <b>{cards[cards.length - 1].name}</b> on top.
</Box>
) || null}
</Section>
<Tabs>
<Tabs.Tab
selected={tab === 0}
onClick={() => setTab(0)}>
Controls
</Tabs.Tab>
<Tabs.Tab
selected={tab === 1}
onClick={() => setTab(1)}>
Peek
</Tabs.Tab>
</Tabs>
{tab === 0 && (
<Section title="Controls">
<LabeledList>
<LabeledList.Item label="Flip">
<Button
onClick={() => act('flip')}
content={face_up ? "face-up" : "face-down"} />
</LabeledList.Item>
<LabeledList.Item label="Rotate">
<Dropdown
selected={rotation}
options={possible_rotations}
onSelected={selected => act('rotate', { angle: selected })} />
</LabeledList.Item>
<LabeledList.Item label="Draw">
<NumberInput
minValue={1}
maxValue={cards.length}
unit="cards"
value={drawCount}
onChange={(e, value) => setDrawCount(parseInt(value, 10) || 1)} />
<Button
onClick={() => act('draw', { cards: Object.keys(cards.slice(0, drawCount)) })}
content="into new hand" />
</LabeledList.Item>
<LabeledList.Item label="Deal">
<NumberInput
minValue={1}
maxValue={8}
unit="hands"
value={dealHandsCount}
onChange={(e, value) => setDealHandsCount(parseInt(value, 10) || 1)} />
with
<NumberInput
minValue={1}
maxValue={Math.ceil(cards.length/4)}
unit="cards"
value={dealCardsCount}
onChange={(e, value) => setDealCardsCount(parseInt(value, 10) || 1)} />
<Button
onClick={() => act('deal', { count: dealCardsCount, hands: dealHandsCount })}
content="Deal" />
<Box as="small" color={dealCardsCount * dealHandsCount > cards.length ? "bad" : "good"}>
({dealCardsCount * dealHandsCount} cards total)
</Box>
</LabeledList.Item>
<LabeledList.Item label="Shuffle">
<Button
content="Shuffle deck"
icon="retweet"
onClick={() => {
act('shuffle');
act('flip', { side: "face_down" });
setDrawCount(1);
setSelectedCards([]);
}} />
</LabeledList.Item>
</LabeledList>
</Section>
)}
{tab === 1 && (
<Section title="Peek">
{peeking && (
<>
<Box style={{ "padding-bottom": "10px" }}>
<Button
content="Draw"
onClick={() => {
act('draw', { cards: selectedCards });
setSelectedCards([]);
}} />
<Button
content="Select All"
onClick={() => setSelectedCards(Array.from(Array(cards.length).keys()))} />
<Button
content="Deselect All"
onClick={() => setSelectedCards([])} />
</Box>
<Box
overflowY="scroll"
height="calc(100vh - 270px)">
<Table>
{cards.map((card, i) => (
<Table.Row key={card.name}>
<Table.Cell color="label">
{i + 1}
</Table.Cell>
<Table.Cell>
<Button.Checkbox
checked={selectedCards.includes(i)}
onClick={() => select_card(i)} />
</Table.Cell>
<Table.Cell>
{card.name}
</Table.Cell>
<Table.Cell>
<Button
content="Draw 1"
onClick={() => act('draw', { cards: [i] })} />
</Table.Cell>
</Table.Row>
))}
</Table>
</Box>
</>
)
|| (
<Box textAlign="center">
<Button
onClick={() => act('peek')}
content="Peek in deck" />
<Box color="average">
(Announces to surroundings!)
</Box>
</Box>
)}
</Section>
)}
</Window.Content>
</Window>
);
};
File diff suppressed because one or more lines are too long