Card Shark DLC - GIMMIE MY MONEY OR I BREAK YOUR KNEECAPS (#64200)

Co-authored-by: Seth Scherer <supernovaa41@gmx.com>
Co-authored-by: Kylerace <kylerlumpkin1@gmail.com>
This commit is contained in:
Tim
2022-05-02 16:56:30 -07:00
committed by GitHub
co-authored by Seth Scherer Kylerace
parent 115f4284b6
commit 22aa3566ab
37 changed files with 1112 additions and 792 deletions
+21
View File
@@ -0,0 +1,21 @@
/obj/item/toy/cards/deck/blank
name = "custom deck of cards"
desc = "A deck of playing cards that can be customized with writing."
cardgame_desc = "custom card game"
icon_state = "deck_white_full"
deckstyle = "white"
has_unique_card_icons = FALSE
is_standard_deck = FALSE
decksize = 25
can_play_52_card_pickup = FALSE
/obj/item/toy/cards/deck/blank/black
icon_state = "deck_black_full"
deckstyle = "black"
/obj/item/toy/cards/deck/blank/Initialize(mapload)
. = ..()
for(var/i in 1 to decksize)
var/obj/item/toy/singlecard/blank_card = new (src, "blank card", src)
blank_card.blank = TRUE
cards += blank_card
+38
View File
@@ -0,0 +1,38 @@
// CARDS AGAINST SPESS
// This is a parody of Cards Against Humanity (https://en.wikipedia.org/wiki/Cards_Against_Humanity)
// which is licensed under CC BY-NC-SA 2.0, the full text of which can be found at the following URL:
// https://creativecommons.org/licenses/by-nc-sa/2.0/legalcode
// Original code by Zuhayr, Polaris Station, ported with modifications
/obj/item/toy/cards/deck/cas
name = "\improper CAS deck (white)"
desc = "A deck for the game Cards Against Spess, still popular after all these centuries. Warning: may include traces of broken fourth wall. This is the white deck."
cardgame_desc = "Cards Against Spess game"
icon_state = "deck_white_full"
deckstyle = "white"
has_unique_card_icons = FALSE
is_standard_deck = FALSE
decksize = 150
can_play_52_card_pickup = FALSE
/obj/item/toy/cards/deck/cas/black
name = "\improper CAS deck (black)"
desc = "A deck for the game Cards Against Spess, still popular after all these centuries. Warning: may include traces of broken fourth wall. This is the black deck."
icon_state = "deck_black_full"
deckstyle = "black"
decksize = 50
GLOBAL_LIST_INIT(card_decks, list(
black = world.file2list("strings/cas_black.txt"),
white = world.file2list("strings/cas_white.txt")
))
/obj/item/toy/cards/deck/cas/Initialize(mapload)
. = ..()
var/list/cards_against_space = GLOB.card_decks[deckstyle]
var/list/possible_cards = cards_against_space.Copy()
var/list/random_cards = list()
for(var/i in 1 to decksize)
random_cards += pick_n_take(possible_cards)
for(var/card in random_cards)
cards += new /obj/item/toy/singlecard(src, card, src)
+246
View File
@@ -0,0 +1,246 @@
#define DECK_SHUFFLE_TIME (5 SECONDS)
#define DECK_SYNDIE_SHUFFLE_TIME (3 SECONDS)
/obj/item/toy/cards/deck
name = "deck of cards"
desc = "A deck of space-grade playing cards."
icon = 'icons/obj/playing_cards.dmi'
icon_state = "deck_nanotrasen_full"
w_class = WEIGHT_CLASS_SMALL
worn_icon_state = "card"
hitsound = null
attack_verb_continuous = list("attacks")
attack_verb_simple = list("attack")
/// The amount of time it takes to shuffle
var/shuffle_time = DECK_SHUFFLE_TIME
/// Deck shuffling cooldown.
COOLDOWN_DECLARE(shuffle_cooldown)
/// If the deck is the standard 52 playing card deck (used for poker and blackjack)
var/is_standard_deck = TRUE
/// The amount of cards to spawn in the deck (optional)
var/decksize = INFINITY
/// The description of the cardgame that is played with this deck (used for memories)
var/cardgame_desc = "card game"
/// Wielding status for holding with two hands
var/wielded = FALSE
/// The holodeck computer used to spawn a holographic deck (see /obj/item/toy/cards/deck/syndicate/holographic)
var/obj/machinery/computer/holodeck/holodeck
/// If the cards in the deck have different card faces icons (blank and CAS decks do not)
var/has_unique_card_icons = TRUE
/// The art style of deck used (determines both deck and card icons used)
var/deckstyle = "nanotrasen"
/obj/item/toy/cards/deck/Initialize(mapload)
. = ..()
AddElement(/datum/element/drag_pickup)
RegisterSignal(src, COMSIG_TWOHANDED_WIELD, .proc/on_wield)
RegisterSignal(src, COMSIG_TWOHANDED_UNWIELD, .proc/on_unwield)
AddComponent(/datum/component/two_handed, attacksound='sound/items/cardflip.ogg')
register_context()
if(!is_standard_deck)
return
// generate a normal playing card deck
cards += new /obj/item/toy/singlecard(src, "Joker Clown", src)
cards += new /obj/item/toy/singlecard(src, "Joker Mime", src)
for(var/suit in list("Hearts", "Spades", "Clubs", "Diamonds"))
cards += new /obj/item/toy/singlecard(src, "Ace of [suit]", src)
for(var/i in 2 to 10)
cards += new /obj/item/toy/singlecard(src, "[i] of [suit]", src)
for(var/person in list("Jack", "Queen", "King"))
cards += new /obj/item/toy/singlecard(src, "[person] of [suit]", src)
/// triggered on wield of two handed item
/obj/item/toy/cards/deck/proc/on_wield(obj/item/source, mob/user)
SIGNAL_HANDLER
wielded = TRUE
/// triggered on unwield of two handed item
/obj/item/toy/cards/deck/proc/on_unwield(obj/item/source, mob/user)
SIGNAL_HANDLER
wielded = FALSE
/obj/item/toy/cards/deck/suicide_act(mob/living/carbon/user)
user.visible_message(span_suicide("[user] is slitting [user.p_their()] wrists with \the [src]! It looks like their luck ran out!"))
playsound(src, 'sound/items/cardshuffle.ogg', 50, TRUE)
return BRUTELOSS
/obj/item/toy/cards/deck/examine(mob/user)
. = ..()
if(cards.len > 0)
var/obj/item/toy/singlecard/card = cards[1]
if(HAS_TRAIT(user, TRAIT_XRAY_VISION))
. += span_notice("You scan the deck with your x-ray vision and the top card reads: [card.cardname].")
var/marked_color = card.getMarkedColor(user)
if(marked_color)
. += span_notice("The top card of the deck has a [marked_color] mark on the corner!")
. += span_notice("Click and drag the deck to yourself to pickup.") // This should be a context screentip
/obj/item/toy/cards/deck/add_context(atom/source, list/context, obj/item/held_item, mob/living/user)
if(src == held_item)
var/obj/item/toy/cards/deck/dealer_deck = held_item
context[SCREENTIP_CONTEXT_LMB] = dealer_deck.wielded ? "Recycle mode" : "Dealer mode"
context[SCREENTIP_CONTEXT_ALT_LMB] = "Shuffle"
return CONTEXTUAL_SCREENTIP_SET
if(isnull(held_item))
context[SCREENTIP_CONTEXT_LMB] = "Draw card"
context[SCREENTIP_CONTEXT_RMB] = "Draw card faceup"
// add drag & drop screentip here in the future
return CONTEXTUAL_SCREENTIP_SET
if(istype(held_item, /obj/item/toy/singlecard))
context[SCREENTIP_CONTEXT_LMB] = "Recycle card"
return CONTEXTUAL_SCREENTIP_SET
if(istype(held_item, /obj/item/toy/cards/cardhand))
context[SCREENTIP_CONTEXT_LMB] = "Recycle cards"
return CONTEXTUAL_SCREENTIP_SET
return NONE
/**
* Shuffles the cards in the deck
*
* Arguments:
* * user - The person shuffling the cards.
*/
/obj/item/toy/cards/deck/proc/shuffle_cards(mob/living/user)
if(!COOLDOWN_FINISHED(src, shuffle_cooldown))
return
COOLDOWN_START(src, shuffle_cooldown, shuffle_time)
cards = shuffle(cards)
playsound(src, 'sound/items/cardshuffle.ogg', 50, TRUE)
user.balloon_alert_to_viewers("shuffles the deck")
addtimer(CALLBACK(src, .proc/CardgameEvent, user), 60 SECONDS, TIMER_OVERRIDE|TIMER_UNIQUE)
/// This checks if nearby mobs are playing a cardgame and triggers a mood and memory
/obj/item/toy/cards/deck/proc/CardgameEvent(mob/living/dealer)
var/card_players = list()
for(var/mob/living/carbon/person in viewers(loc, COMBAT_MESSAGE_RANGE))
var/obj/item/toy/held_card_item = person.is_holding_item_of_type(/obj/item/toy/singlecard) || person.is_holding_item_of_type(/obj/item/toy/cards/deck) || person.is_holding_item_of_type(/obj/item/toy/cards/cardhand)
if(held_card_item)
card_players[person] = held_card_item
if(length(card_players) >= 2) // need at least 2 people to play a cardgame, duh!
for(var/mob/living/carbon/player in card_players)
var/other_players = english_list(card_players - player)
var/obj/item/toy/held_card_item = card_players[player]
SEND_SIGNAL(player, COMSIG_ADD_MOOD_EVENT, "playing_cards", /datum/mood_event/playing_cards)
player.mind?.add_memory(
MEMORY_PLAYING_CARDS,
list(
DETAIL_PROTAGONIST = player,
DETAIL_PLAYERS = other_players,
DETAIL_CARDGAME = cardgame_desc,
DETAIL_DEALER = dealer,
DETAIL_HELD_CARD_ITEM = held_card_item,
),
story_value = STORY_VALUE_OKAY,
memory_flags = MEMORY_CHECK_BLINDNESS
)
/obj/item/toy/cards/deck/attack_hand(mob/living/user, list/modifiers, flip_card = FALSE)
if(!ishuman(user) || !user.canUseTopic(src, BE_CLOSE, NO_DEXTERITY, NO_TK, !iscyborg(user)))
return
var/obj/item/toy/singlecard/card = draw(user)
if(!card)
return
if(flip_card)
card.Flip()
card.pickup(user)
user.put_in_hands(card)
user.balloon_alert_to_viewers("draws a card")
/obj/item/toy/cards/deck/attack_hand_secondary(mob/living/user, list/modifiers)
attack_hand(user, modifiers, flip_card = TRUE)
return SECONDARY_ATTACK_CANCEL_ATTACK_CHAIN
/obj/item/toy/cards/deck/AltClick(mob/living/user)
if(user.canUseTopic(src, BE_CLOSE, NO_DEXTERITY, NO_TK, !iscyborg(user)))
if(wielded)
shuffle_cards(user)
else
to_chat(user, span_notice("You must hold the [src] with both hands to shuffle."))
return ..()
/obj/item/toy/cards/deck/update_icon_state()
switch(cards.len)
if(27 to INFINITY)
icon_state = "deck_[deckstyle]_full"
if(11 to 27)
icon_state = "deck_[deckstyle]_half"
if(1 to 11)
icon_state = "deck_[deckstyle]_low"
else
icon_state = "deck_[deckstyle]_empty"
return ..()
/obj/item/toy/cards/deck/insert(obj/item/toy/card_item)
// any card inserted into the deck is always facedown
if(istype(card_item, /obj/item/toy/singlecard))
var/obj/item/toy/singlecard/card = card_item
card.Flip(CARD_FACEDOWN)
if(istype(card_item, /obj/item/toy/cards/cardhand))
var/obj/item/toy/cards/cardhand/cardhand = card_item
for(var/obj/item/toy/singlecard/card in cardhand.cards)
card.Flip(CARD_FACEDOWN)
. = ..()
/obj/item/toy/cards/deck/attackby(obj/item/item, mob/living/user, params)
if(istype(item, /obj/item/toy/singlecard) || istype(item, /obj/item/toy/cards/cardhand))
insert(item)
var/card_grammar = istype(item, /obj/item/toy/singlecard) ? "card" : "cards"
user.balloon_alert_to_viewers("puts [card_grammar] in deck")
return
return ..()
/// This is how we play 52 card pickup
/obj/item/toy/cards/deck/throw_impact(mob/living/target, datum/thrownthing/throwingdatum)
. = ..()
if(. || !istype(target)) // was it caught or is the target not a living mob
return .
if(!throwingdatum?.thrower) // if a mob didn't throw it (need two people to play 52 pickup)
return
var/mob/living/thrower = throwingdatum.thrower
target.visible_message(span_warning("[target] is forced to play 52 card pickup!"), span_warning("You are forced to play 52 card pickup."))
SEND_SIGNAL(target, COMSIG_ADD_MOOD_EVENT, "lost_52_card_pickup", /datum/mood_event/lost_52_card_pickup)
SEND_SIGNAL(thrower, COMSIG_ADD_MOOD_EVENT, "won_52_card_pickup", /datum/mood_event/won_52_card_pickup)
add_memory_in_range(
target,
7,
MEMORY_PLAYING_52_PICKUP,
list(DETAIL_PROTAGONIST = thrower, DETAIL_DEUTERAGONIST = target, DETAIL_WHAT_BY = src),
story_value = STORY_VALUE_OKAY,
memory_flags = MEMORY_CHECK_BLINDNESS
)
/*
|| Syndicate playing cards, for pretending you're Gambit and playing poker for the nuke disk. ||
*/
/obj/item/toy/cards/deck/syndicate
name = "suspicious looking deck of cards"
desc = "A deck of space-grade playing cards. They seem unusually rigid."
cardgame_desc = "suspicious card game"
icon_state = "deck_syndicate_full"
deckstyle = "syndicate"
hitsound = 'sound/weapons/bladeslice.ogg'
force = 5
throwforce = 10
attack_verb_continuous = list("attacks", "slices", "dices", "slashes", "cuts")
attack_verb_simple = list("attack", "slice", "dice", "slash", "cut")
resistance_flags = NONE
shuffle_time = DECK_SYNDIE_SHUFFLE_TIME
#undef DECK_SHUFFLE_TIME
#undef DECK_SYNDIE_SHUFFLE_TIME
+21
View File
@@ -0,0 +1,21 @@
/obj/item/toy/cards/deck/kotahi
name = "\improper KOTAHI deck"
desc = "A deck of kotahi cards. House rules to argue over not included."
cardgame_desc = "KOTAHI game"
icon_state = "deck_kotahi_full"
deckstyle = "kotahi"
is_standard_deck = FALSE
/obj/item/toy/cards/deck/kotahi/Initialize(mapload)
. = ..()
for(var/colour in list("Red","Yellow","Green","Blue"))
cards += new /obj/item/toy/singlecard(src, "[colour] 0", src) //kotahi decks have only one colour of each 0, weird huh?
for(var/k in 0 to 1) //two of each colour of number
cards += new /obj/item/toy/singlecard(src, "[colour] skip", src)
cards += new /obj/item/toy/singlecard(src, "[colour] reverse", src)
cards += new /obj/item/toy/singlecard(src, "[colour] draw 2", src)
for(var/i in 1 to 9)
cards += new /obj/item/toy/singlecard(src, "[colour] [i]", src)
for(var/k in 0 to 3) //4 wilds and draw 4s
cards += new /obj/item/toy/singlecard(src, "Wildcard", src)
cards += new /obj/item/toy/singlecard(src, "Draw 4", src)
+59
View File
@@ -0,0 +1,59 @@
#define TAROT_GHOST_TIMER (666 SECONDS) // this translates into 11 mins and 6 seconds
//These cards certainly won't tell the future, but you can play some nice games with them.
/obj/item/toy/cards/deck/tarot
name = "tarot game deck"
desc = "A full 78 card game deck of tarot cards. Complete with 4 suites of 14 cards, and a full suite of trump cards."
cardgame_desc = "tarot card reading"
icon_state = "deck_tarot_full"
deckstyle = "tarot"
is_standard_deck = FALSE
/obj/item/toy/cards/deck/tarot/Initialize(mapload)
. = ..()
for(var/suit in list("Hearts", "Pikes", "Clovers", "Tiles"))
for(var/i in 1 to 10)
cards += new /obj/item/toy/singlecard(src, "[i] of [suit]", src)
for(var/person in list("Valet", "Chevalier", "Dame", "Roi"))
cards += new /obj/item/toy/singlecard(src, "[person] of [suit]", src)
for(var/trump in list("The Magician", "The High Priestess", "The Empress", "The Emperor", "The Hierophant", "The Lover", "The Chariot", "Justice", "The Hermit", "The Wheel of Fortune", "Strength", "The Hanged Man", "Death", "Temperance", "The Devil", "The Tower", "The Star", "The Moon", "The Sun", "Judgement", "The World", "The Fool"))
cards += new /obj/item/toy/singlecard(src, trump, src)
/obj/item/toy/cards/deck/tarot/draw(mob/user)
. = ..()
if(prob(50))
var/obj/item/toy/singlecard/card = .
var/matrix/M = matrix()
M.Turn(180)
card.transform = M
/obj/item/toy/cards/deck/tarot/haunted
name = "haunted tarot game deck"
desc = "A spooky looking tarot deck. You can sense a supernatural presence linked to the cards..."
/// ghost notification cooldown
COOLDOWN_DECLARE(ghost_alert_cooldown)
/obj/item/toy/cards/deck/tarot/haunted/on_wield(obj/item/source, mob/living/carbon/user)
. = ..()
ADD_TRAIT(user, TRAIT_SIXTHSENSE, MAGIC_TRAIT)
to_chat(user, span_notice("The veil to the underworld is opened. You can sense the dead souls calling out..."))
if(!COOLDOWN_FINISHED(src, ghost_alert_cooldown))
return
COOLDOWN_START(src, ghost_alert_cooldown, TAROT_GHOST_TIMER)
notify_ghosts(
"Someone has begun playing with a [src.name] in [get_area(src)]!",
source = src,
header = "Haunted Tarot Deck",
ghost_sound = 'sound/effects/ghost2.ogg',
notify_volume = 75,
action = NOTIFY_ORBIT,
)
/obj/item/toy/cards/deck/tarot/haunted/on_unwield(obj/item/source, mob/living/carbon/user)
. = ..()
REMOVE_TRAIT(user, TRAIT_SIXTHSENSE, MAGIC_TRAIT)
to_chat(user, span_notice("The veil to the underworld closes shut. You feel your senses returning to normal."))
#undef TAROT_GHOST_TIMER
+34
View File
@@ -0,0 +1,34 @@
//It's Wiz-Off, the wizard themed card game! It's modular too, in case you might want to make it Syndie, Sec and Clown themed or something stupid like that.
/obj/item/toy/cards/deck/wizoff
name = "\improper Wiz-Off deck"
desc = "A Wiz-Off deck. Fight an arcane battle for the fate of the universe: Draw 5! Play 5! Best of 5! A rules card is attached."
cardgame_desc = "Wiz-Off game"
icon_state = "deck_wizoff_full"
deckstyle = "wizoff"
is_standard_deck = FALSE
/obj/item/toy/cards/deck/wizoff/Initialize(mapload)
. = ..()
var/card_list = strings("wizoff.json", "wizard")
cards += new /obj/item/toy/singlecard/wizoff_ruleset(src) // ruleset should be the top card
for(var/card in card_list)
cards += new /obj/item/toy/singlecard(src, card, src)
/obj/item/toy/singlecard/wizoff_ruleset
desc = "A ruleset for the playing card game Wiz-Off."
cardname = "Wizoff Ruleset"
deckstyle = "black"
has_unique_card_icons = FALSE
icon_state = "singlecard_down_black"
/obj/item/toy/singlecard/wizoff_ruleset/examine(mob/living/carbon/human/user)
. = ..()
. += span_notice("Remember the rules of Wiz-Off!")
. += span_info("Each player draws 5 cards.")
. += span_info("There are five rounds. Each round, a player selects a card to play, and the winner is selected based on the following rules:")
. += span_info("Defensive beats Offensive!")
. += span_info("Offensive beats Utility!")
. += span_info("Utility beats Defensive!")
. += span_info("If both players play the same type of spell, the higher number wins!")
. += span_info("The player who wins the most of the 5 rounds wins the game!")
. += span_notice("Now get ready to battle for the fate of the universe: Wiz-Off!")