mirror of
https://github.com/Bubberstation/Bubberstation.git
synced 2026-08-25 22:19:30 +01:00
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:
co-authored by
Seth Scherer
Kylerace
parent
115f4284b6
commit
22aa3566ab
@@ -0,0 +1,143 @@
|
||||
/obj/item/toy/cards/cardhand
|
||||
name = "hand of cards"
|
||||
desc = "A number of cards not in a deck, customarily held in ones hand."
|
||||
icon = 'icons/obj/playing_cards.dmi'
|
||||
icon_state = "none"
|
||||
w_class = WEIGHT_CLASS_TINY
|
||||
worn_icon_state = "card"
|
||||
|
||||
/obj/item/toy/cards/cardhand/Initialize(mapload, list/cards_to_combine)
|
||||
. = ..()
|
||||
|
||||
if(!LAZYLEN(cards_to_combine) && (mapload && !LAZYLEN(cards)))
|
||||
CRASH("[src] is being made into a cardhand without a list of cards to combine")
|
||||
|
||||
if(mapload && LAZYLEN(cards)) // these cards have not been initialized
|
||||
for(var/card_name in cards)
|
||||
var/obj/item/toy/singlecard/new_card = new (loc, card_name)
|
||||
new_card.update_appearance()
|
||||
cards_to_combine += new_card
|
||||
cards = list() // reset our cards to an empty list
|
||||
|
||||
for(var/obj/item/toy/singlecard/new_card in cards_to_combine)
|
||||
new_card.forceMove(src)
|
||||
cards += new_card
|
||||
|
||||
register_context()
|
||||
update_appearance()
|
||||
|
||||
/obj/item/toy/cards/cardhand/suicide_act(mob/living/carbon/user)
|
||||
user.visible_message(span_suicide("[user] is slitting [user.p_their()] wrists with \the [src]! It looks like [user.p_they()] [user.p_have()] a crummy hand!"))
|
||||
playsound(src, 'sound/items/cardshuffle.ogg', 50, TRUE)
|
||||
return BRUTELOSS
|
||||
|
||||
/obj/item/toy/cards/cardhand/examine(mob/user)
|
||||
. = ..()
|
||||
for(var/obj/item/toy/singlecard/card in cards)
|
||||
if(HAS_TRAIT(user, TRAIT_XRAY_VISION))
|
||||
. += span_notice("You scan the cardhand with your x-ray vision and there is a: [card.cardname]")
|
||||
var/marked_color = card.getMarkedColor(user)
|
||||
if(marked_color)
|
||||
. += span_notice("There is a [marked_color] mark on the corner of a card in the cardhand!")
|
||||
|
||||
/obj/item/toy/cards/cardhand/add_context(atom/source, list/context, obj/item/held_item, mob/living/user)
|
||||
if(istype(held_item, /obj/item/toy/cards/deck))
|
||||
var/obj/item/toy/cards/deck/dealer_deck = held_item
|
||||
if(dealer_deck.wielded)
|
||||
context[SCREENTIP_CONTEXT_LMB] = "Deal card"
|
||||
context[SCREENTIP_CONTEXT_RMB] = "Deal card faceup"
|
||||
return CONTEXTUAL_SCREENTIP_SET
|
||||
context[SCREENTIP_CONTEXT_LMB] = "Recycle cards"
|
||||
return CONTEXTUAL_SCREENTIP_SET
|
||||
|
||||
if(istype(held_item, /obj/item/toy/singlecard))
|
||||
context[SCREENTIP_CONTEXT_LMB] = "Combine cards"
|
||||
context[SCREENTIP_CONTEXT_RMB] = "Combine cards faceup"
|
||||
return CONTEXTUAL_SCREENTIP_SET
|
||||
|
||||
return NONE
|
||||
|
||||
/obj/item/toy/cards/cardhand/attack_self(mob/living/user)
|
||||
if(!isliving(user) || !user.canUseTopic(src, BE_CLOSE, NO_DEXTERITY, NO_TK))
|
||||
return
|
||||
|
||||
var/list/handradial = list()
|
||||
for(var/obj/item/toy/singlecard/card in cards)
|
||||
handradial[card] = image(icon = src.icon, icon_state = card.icon_state)
|
||||
|
||||
var/obj/item/toy/singlecard/choice = show_radial_menu(usr, src, handradial, custom_check = CALLBACK(src, .proc/check_menu, user), radius = 36, require_near = TRUE)
|
||||
if(!choice)
|
||||
return FALSE
|
||||
|
||||
var/obj/item/toy/singlecard/selected_card = draw(user, choice)
|
||||
selected_card.pickup(user)
|
||||
user.put_in_hands(selected_card)
|
||||
|
||||
if(cards.len == 1)
|
||||
user.temporarilyRemoveItemFromInventory(src, TRUE)
|
||||
var/obj/item/toy/singlecard/last_card = draw(user)
|
||||
last_card.pickup(user)
|
||||
user.put_in_hands(last_card)
|
||||
qdel(src) // cardhand is empty now so delete it
|
||||
|
||||
/obj/item/toy/cards/cardhand/proc/check_menu(mob/living/user)
|
||||
return isliving(user) && !user.incapacitated()
|
||||
|
||||
/obj/item/toy/cards/cardhand/attackby(obj/item/weapon, mob/living/user, params, flip_card = FALSE)
|
||||
var/obj/item/toy/singlecard/card
|
||||
|
||||
if(istype(weapon, /obj/item/toy/singlecard))
|
||||
card = weapon
|
||||
|
||||
if(istype(weapon, /obj/item/toy/cards/deck))
|
||||
var/obj/item/toy/cards/deck/dealer_deck = weapon
|
||||
if(!dealer_deck.wielded) // recycle cardhand into deck (if unwielded)
|
||||
dealer_deck.insert(src)
|
||||
user.balloon_alert_to_viewers("puts card in deck")
|
||||
return
|
||||
card = dealer_deck.draw(user)
|
||||
|
||||
if(card)
|
||||
if(flip_card)
|
||||
card.Flip()
|
||||
insert(card)
|
||||
return
|
||||
|
||||
return ..()
|
||||
|
||||
/obj/item/toy/cards/cardhand/attackby_secondary(obj/item/weapon, mob/user, params)
|
||||
attackby(weapon, user, params, flip_card = TRUE)
|
||||
return SECONDARY_ATTACK_CONTINUE_CHAIN
|
||||
|
||||
#define CARDS_MAX_DISPLAY_LIMIT 5 // the amount of cards that are displayed in a hand
|
||||
#define CARDS_PIXEL_X_OFFSET -5 // start out displaying the 1st card -5 pixels left
|
||||
#define CARDS_ANGLE_OFFSET -45 // start out displaying the 1st card -45 degrees counter clockwise
|
||||
|
||||
/obj/item/toy/cards/cardhand/update_overlays()
|
||||
. = ..()
|
||||
cut_overlays()
|
||||
if(cards.len <= 1)
|
||||
icon_state = null // we want an error icon to appear if this doesn't get qdel
|
||||
return
|
||||
|
||||
var/starting_card_pos = max(1, cards.len - CARDS_MAX_DISPLAY_LIMIT) // only display the top cards in the cardhand
|
||||
var/cards_to_display = min(CARDS_MAX_DISPLAY_LIMIT, cards.len)
|
||||
// 90 degrees from the 1st card to the last, so split the divider by total cards displayed
|
||||
var/angle_divider = round(90/(cards_to_display - 1))
|
||||
// 10 pixels from the 1st card to the last, so split the divider by total cards displayed
|
||||
var/pixel_divider = round(10/(cards_to_display - 1))
|
||||
|
||||
// starting from the 1st card to last, we want to slowly increase the angle and pixel_x offset
|
||||
// to spread the cards out using our dividers
|
||||
for(var/i in 0 to cards_to_display - 1)
|
||||
var/obj/item/toy/singlecard/card = cards[starting_card_pos + i]
|
||||
var/image/card_overlay = image(icon, icon_state = card.icon_state, pixel_x = CARDS_PIXEL_X_OFFSET + (i * pixel_divider))
|
||||
var/rotation_angle = CARDS_ANGLE_OFFSET + (i * angle_divider)
|
||||
var/matrix/M = matrix()
|
||||
M.Turn(rotation_angle)
|
||||
card_overlay.transform = M
|
||||
add_overlay(card_overlay)
|
||||
|
||||
#undef CARDS_MAX_DISPLAY_LIMIT
|
||||
#undef CARDS_PIXEL_X_OFFSET
|
||||
#undef CARDS_ANGLE_OFFSET
|
||||
@@ -0,0 +1,114 @@
|
||||
/*
|
||||
** The base card class that is used by decks and cardhands
|
||||
*/
|
||||
/obj/item/toy/cards
|
||||
resistance_flags = FLAMMABLE
|
||||
max_integrity = 50
|
||||
/// Do all the cards drop to the floor when thrown at a person
|
||||
var/can_play_52_card_pickup = TRUE
|
||||
/// List of cards for a hand or deck
|
||||
var/list/cards = list()
|
||||
|
||||
/obj/item/toy/cards/Destroy()
|
||||
if(LAZYLEN(cards))
|
||||
QDEL_LIST(cards)
|
||||
return ..()
|
||||
|
||||
/// This is how we play 52 card pickup
|
||||
/obj/item/toy/cards/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/has_no_cards = !LAZYLEN(cards)
|
||||
if(has_no_cards)
|
||||
return
|
||||
|
||||
for(var/obj/item/toy/singlecard/card in cards)
|
||||
cards -= card
|
||||
card.forceMove(target.drop_location())
|
||||
if(prob(50))
|
||||
card.Flip()
|
||||
card.pixel_x = rand(-16, 16)
|
||||
card.pixel_y = rand(-16, 16)
|
||||
var/matrix/Matrix = matrix()
|
||||
var/angle = pick(0, 90, 180, 270)
|
||||
Matrix.Turn(angle)
|
||||
card.transform = Matrix
|
||||
card.update_appearance()
|
||||
|
||||
playsound(src, 'sound/items/cardshuffle.ogg', 50, TRUE)
|
||||
|
||||
if(istype(src, /obj/item/toy/cards/cardhand))
|
||||
qdel(src)
|
||||
return
|
||||
|
||||
update_appearance()
|
||||
|
||||
/**
|
||||
* This is used to insert a list of cards into a deck or cardhand
|
||||
*
|
||||
* All cards that are inserted have their angle and pixel offsets reset to zero however their
|
||||
* flip state does not change unless it's being inserted into a deck which is always facedown
|
||||
* (see the deck/insert proc)
|
||||
*
|
||||
* Arguments:
|
||||
* * card_item - Either a singlecard or cardhand that gets inserted into the src
|
||||
*/
|
||||
/obj/item/toy/cards/proc/insert(obj/item/toy/card_item)
|
||||
var/cards_to_add = list()
|
||||
var/obj/item/toy/cards/cardhand/recycled_cardhand
|
||||
|
||||
if(istype(card_item, /obj/item/toy/singlecard))
|
||||
cards_to_add += card_item
|
||||
|
||||
if(istype(card_item, /obj/item/toy/cards/cardhand))
|
||||
recycled_cardhand = card_item
|
||||
|
||||
for(var/obj/item/toy/singlecard/card in recycled_cardhand.cards)
|
||||
cards_to_add += card
|
||||
recycled_cardhand.cards -= card
|
||||
card.moveToNullspace()
|
||||
qdel(recycled_cardhand)
|
||||
|
||||
for(var/obj/item/toy/singlecard/card in cards_to_add)
|
||||
card.forceMove(src)
|
||||
// reset the position and angle
|
||||
card.pixel_x = 0
|
||||
card.pixel_y = 0
|
||||
var/matrix/M = matrix()
|
||||
M.Turn(0)
|
||||
card.transform = M
|
||||
card.update_appearance()
|
||||
cards += card
|
||||
cards_to_add -= card
|
||||
update_appearance()
|
||||
|
||||
/**
|
||||
* Draws a card from the deck or hand of cards.
|
||||
*
|
||||
* Draws the top card unless a card arg is supplied then it picks that specific card
|
||||
* and returns it (the card arg is used by the radial menu for cardhands to select
|
||||
* specific cards out of the cardhand)
|
||||
* Arguments:
|
||||
* * mob/living/user - The user drawing the card.
|
||||
* * obj/item/toy/singlecard/card (optional) - The card drawn from the hand
|
||||
**/
|
||||
/obj/item/toy/cards/proc/draw(mob/living/user, obj/item/toy/singlecard/card)
|
||||
if(!isliving(user) || !user.canUseTopic(src, BE_CLOSE, NO_DEXTERITY, NO_TK))
|
||||
return
|
||||
|
||||
var/has_no_cards = !LAZYLEN(cards)
|
||||
if(has_no_cards)
|
||||
to_chat(user, span_warning("There are no more cards to draw!"))
|
||||
return
|
||||
|
||||
card = card || cards[1] //draw the card on top
|
||||
cards -= card
|
||||
|
||||
update_appearance()
|
||||
playsound(src, 'sound/items/cardflip.ogg', 50, TRUE)
|
||||
return card
|
||||
@@ -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
|
||||
@@ -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)
|
||||
@@ -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
|
||||
@@ -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)
|
||||
@@ -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
|
||||
@@ -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!")
|
||||
@@ -0,0 +1,242 @@
|
||||
#define CARD_FACEDOWN 0
|
||||
#define CARD_FACEUP 1
|
||||
|
||||
/obj/item/toy/singlecard
|
||||
name = "card"
|
||||
desc = "A playing card used to play card games like poker."
|
||||
icon = 'icons/obj/playing_cards.dmi'
|
||||
icon_state = "sc_Ace of Spades_nanotrasen"
|
||||
w_class = WEIGHT_CLASS_TINY
|
||||
worn_icon_state = "card"
|
||||
pixel_x = -5
|
||||
resistance_flags = FLAMMABLE
|
||||
max_integrity = 50
|
||||
force = 0
|
||||
throwforce = 0
|
||||
throw_speed = 3
|
||||
throw_range = 7
|
||||
attack_verb_continuous = list("attacks")
|
||||
attack_verb_simple = list("attack")
|
||||
/// Artistic style of the deck
|
||||
var/deckstyle = "nanotrasen"
|
||||
/// If the cards in the deck have different icon states (blank and CAS decks do not)
|
||||
var/has_unique_card_icons = TRUE
|
||||
/// The name of the card
|
||||
var/cardname = "Ace of Spades"
|
||||
/// Is the card flipped facedown (FALSE) or flipped faceup (TRUE)
|
||||
var/flipped = FALSE
|
||||
/// The card is blank and can be written on with a pen.
|
||||
var/blank = FALSE
|
||||
/// The color used to mark a card for cheating (by pens or crayons)
|
||||
var/marked_color
|
||||
|
||||
/obj/item/toy/singlecard/Initialize(mapload, cardname, obj/item/toy/cards/deck/parent_deck)
|
||||
. = ..()
|
||||
src.cardname = cardname || src.cardname
|
||||
if(istype(parent_deck))
|
||||
deckstyle = parent_deck.deckstyle
|
||||
has_unique_card_icons = parent_deck.has_unique_card_icons
|
||||
icon_state = "singlecard_down_[parent_deck.deckstyle]"
|
||||
hitsound = parent_deck.hitsound
|
||||
force = parent_deck.force
|
||||
throwforce = parent_deck.throwforce
|
||||
throw_speed = parent_deck.throw_speed
|
||||
throw_range = parent_deck.throw_range
|
||||
attack_verb_continuous = parent_deck.attack_verb_continuous
|
||||
attack_verb_simple = parent_deck.attack_verb_simple
|
||||
|
||||
if(parent_deck.holodeck)
|
||||
flags_1 |= HOLOGRAM_1
|
||||
parent_deck.holodeck.spawned += src
|
||||
|
||||
register_context()
|
||||
|
||||
|
||||
/obj/item/toy/singlecard/examine(mob/living/carbon/human/user)
|
||||
. = ..()
|
||||
if(!ishuman(user))
|
||||
return
|
||||
|
||||
if(user.is_holding(src))
|
||||
user.visible_message(span_notice("[user] checks [user.p_their()] card."), span_notice("The card reads: [cardname]."))
|
||||
if(blank)
|
||||
. += span_notice("The card is blank. Write on it with a pen.")
|
||||
else if(HAS_TRAIT(user, TRAIT_XRAY_VISION))
|
||||
. += span_notice("You scan the card with your x-ray vision and it reads: [cardname].")
|
||||
else
|
||||
. += span_warning("You need to have the card in your hand to check it!")
|
||||
|
||||
var/marked_color = getMarkedColor(user)
|
||||
if(marked_color)
|
||||
. += span_notice("The card has a [marked_color] mark on the corner!")
|
||||
|
||||
/obj/item/toy/singlecard/add_context(atom/source, list/context, obj/item/held_item, mob/living/user)
|
||||
if(isnull(held_item) || src == held_item)
|
||||
context[SCREENTIP_CONTEXT_ALT_LMB] = "Rotate counter-clockwise" // add a ALT_RMB screentip to rotate clockwise
|
||||
context[SCREENTIP_CONTEXT_RMB] = "Flip card"
|
||||
return CONTEXTUAL_SCREENTIP_SET
|
||||
|
||||
if(istype(held_item, /obj/item/toy/cards/deck))
|
||||
var/obj/item/toy/cards/deck/dealer_deck = held_item
|
||||
if(dealer_deck.wielded)
|
||||
context[SCREENTIP_CONTEXT_LMB] = "Deal card"
|
||||
context[SCREENTIP_CONTEXT_RMB] = "Deal card faceup"
|
||||
return CONTEXTUAL_SCREENTIP_SET
|
||||
context[SCREENTIP_CONTEXT_LMB] = "Recycle card"
|
||||
return CONTEXTUAL_SCREENTIP_SET
|
||||
|
||||
if(istype(held_item, /obj/item/toy/singlecard))
|
||||
context[SCREENTIP_CONTEXT_LMB] = "Combine cards"
|
||||
context[SCREENTIP_CONTEXT_RMB] = "Combine cards faceup"
|
||||
return CONTEXTUAL_SCREENTIP_SET
|
||||
|
||||
if(istype(held_item, /obj/item/toy/cards/cardhand))
|
||||
context[SCREENTIP_CONTEXT_LMB] = "Combine cards"
|
||||
return CONTEXTUAL_SCREENTIP_SET
|
||||
|
||||
if(istype(held_item, /obj/item/toy/crayon) || istype(held_item, /obj/item/pen))
|
||||
context[SCREENTIP_CONTEXT_LMB] = blank ? "Write on card" : "Mark card"
|
||||
return CONTEXTUAL_SCREENTIP_SET
|
||||
|
||||
return NONE
|
||||
|
||||
/obj/item/toy/singlecard/suicide_act(mob/living/carbon/user)
|
||||
user.visible_message(span_suicide("[user] is slitting [user.p_their()] wrists with \the [src]! It looks like [user.p_they()] [user.p_have()] an unlucky card!"))
|
||||
playsound(src, 'sound/weapons/bladeslice.ogg', 50, TRUE)
|
||||
return BRUTELOSS
|
||||
|
||||
/**
|
||||
* Flips the card over
|
||||
*
|
||||
* * Arguments:
|
||||
* * orientation (optional) - Sets flipped state to CARD_FACEDOWN or CARD_FACEUP if given orientation (otherwise just invert the flipped state)
|
||||
*/
|
||||
/obj/item/toy/singlecard/proc/Flip(orientation)
|
||||
if(!isnull(orientation))
|
||||
flipped = orientation
|
||||
else
|
||||
flipped = !flipped
|
||||
|
||||
name = flipped ? cardname : "card"
|
||||
update_appearance()
|
||||
|
||||
/**
|
||||
* Returns a color if a card is marked and the user can see it
|
||||
*
|
||||
* * Arguments:
|
||||
* * user - We need to check if the user see the marked card
|
||||
*/
|
||||
/obj/item/toy/singlecard/proc/getMarkedColor(mob/living/carbon/user)
|
||||
if(!istype(user))
|
||||
return
|
||||
var/is_marked_with_visible_color = (marked_color && marked_color != "invisible")
|
||||
if(is_marked_with_visible_color || (marked_color == "invisible" && HAS_TRAIT(user, TRAIT_REAGENT_SCANNER)))
|
||||
return marked_color
|
||||
|
||||
/obj/item/toy/singlecard/update_icon_state()
|
||||
if(!flipped)
|
||||
icon_state = "singlecard_down_[deckstyle]"
|
||||
else if(has_unique_card_icons) // each card in a deck has a different icon
|
||||
icon_state = "sc_[cardname]_[deckstyle]"
|
||||
else // all cards are the same icon state (blank or scribble)
|
||||
icon_state = blank ? "sc_blank_[deckstyle]" : "sc_scribble_[deckstyle]"
|
||||
return ..()
|
||||
|
||||
/obj/item/toy/singlecard/update_name()
|
||||
name = flipped ? cardname : "card"
|
||||
return ..()
|
||||
|
||||
/obj/item/toy/singlecard/attackby(obj/item/item, mob/living/user, params, flip_card=FALSE)
|
||||
var/obj/item/toy/singlecard/card
|
||||
|
||||
if(istype(item, /obj/item/toy/cards/deck))
|
||||
var/obj/item/toy/cards/deck/dealer_deck = item
|
||||
if(!dealer_deck.wielded) // recycle card into deck (if unwielded)
|
||||
dealer_deck.insert(src)
|
||||
user.balloon_alert_to_viewers("puts card in deck")
|
||||
return
|
||||
card = dealer_deck.draw(user)
|
||||
|
||||
if(istype(item, /obj/item/toy/singlecard))
|
||||
card = item
|
||||
|
||||
if(card) // card + card = combine into cardhand
|
||||
if(flip_card)
|
||||
card.Flip()
|
||||
|
||||
if(istype(item, /obj/item/toy/cards/deck))
|
||||
// only decks cause a balloon alert
|
||||
user.balloon_alert_to_viewers("deals a card")
|
||||
|
||||
var/obj/item/toy/cards/cardhand/new_cardhand = new (drop_location(), list(src, card))
|
||||
new_cardhand.pixel_x = pixel_x
|
||||
new_cardhand.pixel_y = pixel_y
|
||||
|
||||
if(!isturf(loc)) // make a cardhand in our active hand
|
||||
user.temporarilyRemoveItemFromInventory(src, TRUE)
|
||||
new_cardhand.pickup(user)
|
||||
user.put_in_active_hand(new_cardhand)
|
||||
return
|
||||
|
||||
if(istype(item, /obj/item/toy/cards/cardhand)) // insert into cardhand
|
||||
var/obj/item/toy/cards/cardhand/target_cardhand = item
|
||||
target_cardhand.insert(src)
|
||||
return
|
||||
|
||||
var/can_item_write
|
||||
var/marked_cheating_color
|
||||
|
||||
if(istype(item, /obj/item/pen))
|
||||
var/obj/item/pen/pen = item
|
||||
can_item_write = TRUE
|
||||
marked_cheating_color = (pen.colour == "white" && "invisible") || pen.colour
|
||||
|
||||
if(istype(item, /obj/item/toy/crayon))
|
||||
var/obj/item/toy/crayon/crayon = item
|
||||
can_item_write = TRUE
|
||||
marked_cheating_color = (crayon.crayon_color == "mime" && "invisible") || crayon.crayon_color
|
||||
|
||||
if(can_item_write && !blank) // You cheated not only the game, but yourself
|
||||
marked_color = marked_cheating_color
|
||||
to_chat(user, span_notice("You put a [marked_color] mark in the corner of [src] with the [item]. Cheat to win!"))
|
||||
return
|
||||
|
||||
if(can_item_write)
|
||||
if(!user.is_literate())
|
||||
to_chat(user, span_notice("You scribble illegibly on [src]!"))
|
||||
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
|
||||
|
||||
cardname = cardtext
|
||||
blank = FALSE
|
||||
update_appearance()
|
||||
return
|
||||
return ..()
|
||||
|
||||
/obj/item/toy/singlecard/attackby_secondary(obj/item/item, mob/living/user, modifiers)
|
||||
attackby(item, user, modifiers, flip_card=TRUE)
|
||||
return SECONDARY_ATTACK_CANCEL_ATTACK_CHAIN
|
||||
|
||||
/obj/item/toy/singlecard/attack_hand_secondary(mob/living/carbon/human/user, modifiers)
|
||||
attack_self(user)
|
||||
return SECONDARY_ATTACK_CANCEL_ATTACK_CHAIN
|
||||
|
||||
/obj/item/toy/singlecard/attack_self_secondary(mob/living/carbon/human/user, modifiers)
|
||||
attack_self(user)
|
||||
|
||||
/obj/item/toy/singlecard/attack_self(mob/living/carbon/human/user)
|
||||
if(!ishuman(user) || !user.canUseTopic(src, BE_CLOSE, NO_DEXTERITY, NO_TK, !iscyborg(user)))
|
||||
return
|
||||
|
||||
Flip()
|
||||
if(isturf(src.loc)) // only display tihs message when flipping in a visible spot like on a table
|
||||
user.balloon_alert_to_viewers("flips a card")
|
||||
|
||||
/obj/item/toy/singlecard/AltClick(mob/living/carbon/human/user)
|
||||
if(user.canUseTopic(src, BE_CLOSE, NO_DEXTERITY, NO_TK, !iscyborg(user)))
|
||||
transform = turn(transform, 90)
|
||||
// use the simple_rotation component to make this turn with Alt+RMB & Alt+LMB at some point in the future - TimT
|
||||
return ..()
|
||||
Reference in New Issue
Block a user