diff --git a/code/_globalvars/lists/maint_loot_tables.dm b/code/_globalvars/lists/maint_loot_tables.dm
index e77957d72a9..918287d43a6 100644
--- a/code/_globalvars/lists/maint_loot_tables.dm
+++ b/code/_globalvars/lists/maint_loot_tables.dm
@@ -104,6 +104,7 @@ GLOBAL_LIST_INIT(maintenance_loot_tier_1, list(
/obj/item/tank/internals/emergency_oxygen,
/obj/item/tank/internals/emergency_oxygen/engi,
/obj/item/vending_refill/cola,
+ /obj/item/cardpack/series_one,
) = 85,
list(
diff --git a/code/game/objects/items/storage/wallets.dm b/code/game/objects/items/storage/wallets.dm
index 09b35a6246d..ee8e5bb505e 100644
--- a/code/game/objects/items/storage/wallets.dm
+++ b/code/game/objects/items/storage/wallets.dm
@@ -30,7 +30,8 @@
/obj/item/photo,
/obj/item/reagent_containers/dropper,
/obj/item/screwdriver,
- /obj/item/stamp)
+ /obj/item/stamp,
+ /obj/item/tcg_card)
cant_hold = list(
/obj/item/screwdriver/power
)
diff --git a/code/modules/economy/merch_items.dm b/code/modules/economy/merch_items.dm
index 1344ad8021a..bbc978315c8 100644
--- a/code/modules/economy/merch_items.dm
+++ b/code/modules/economy/merch_items.dm
@@ -75,6 +75,13 @@
cost = 200
category = MERCH_CAT_TOY
+/datum/merch_item/tcg/series_one
+ name = "Battles of Orion: Series 1"
+ desc = "The brand-new trading card game on the scene with all your favorite Nanotrasen employees!"
+ typepath = /obj/item/cardpack/series_one
+ cost = 100
+ category = MERCH_CAT_TOY
+
/datum/merch_item/katana
name = "Replica Katana"
desc = "Woefully underpowered in D20."
diff --git a/code/modules/mining/ores_coins.dm b/code/modules/mining/ores_coins.dm
index aa465ed3c75..7f2a64ef5a4 100644
--- a/code/modules/mining/ores_coins.dm
+++ b/code/modules/mining/ores_coins.dm
@@ -496,6 +496,16 @@ GLOBAL_LIST_INIT(sand_recipes, list(\
name_by_cmineral = FALSE
heads_name = "valid"
+/obj/item/coin/thunderdome
+ name = "thunderdome flipper"
+ icon_state = "coin_thunderdome_nanotrasen"
+ cmineral = "thunderdome"
+ desc = "A Thunderdome TCG flipper, for deciding who gets to go first. Also conveniently acts as a counter, for various purposes."
+ sideslist = list("nanotrasen", "syndicate")
+ credits = 20
+ name_by_cmineral = FALSE
+ heads_name = "nanotrasen"
+
/obj/item/coin/antagtoken/syndicate
name = "syndicate coin"
credits = 160
diff --git a/code/modules/tcg/pack_1.dm b/code/modules/tcg/pack_1.dm
new file mode 100644
index 00000000000..0c7315fc49c
--- /dev/null
+++ b/code/modules/tcg/pack_1.dm
@@ -0,0 +1,316 @@
+/datum/tcg_card/pack_1/
+ name = ""
+ desc = ""
+ icon_state = ""
+ rarity = ""
+ card_type = ""
+
+// COMMAND
+
+/datum/tcg_card/pack_1/captain
+ name = "Captain"
+ desc = "The head of every Nanotrasen space station who spends most of their shift delegating and protecting the disk."
+ icon_state = "captain"
+ rarity = "Rare"
+ card_type = "Unit"
+
+/datum/tcg_card/pack_1/renault
+ name = "Renault"
+ desc = "The Captain's trusty pet fox who spends most shifts walking around aimlessly in the Captain's Office."
+ icon_state = "renault"
+ rarity = "Uncommon"
+ card_type = "Unit"
+
+/datum/tcg_card/pack_1/ce
+ name = "Chief Engineer"
+ desc = "The head of the engineering department and the one who ensures the station runs smoothly. Most of them fail at this."
+ icon_state = "ce"
+ rarity = "Uncommon"
+ card_type = "Unit"
+
+/datum/tcg_card/pack_1/hop
+ name = "Head of Personnel"
+ desc = "Never far far from their closest pal, Ian, they defend the ability to give out AA to anyone who passes."
+ icon_state = "hop"
+ rarity = "Rare"
+ card_type = "Unit"
+
+/datum/tcg_card/pack_1/rd
+ name = "Research Director"
+ desc = "The head of the science department who has to wrangle their explosion prone workers around."
+ icon_state = "rd"
+ rarity = "Uncommon"
+ card_type = "Unit"
+
+/datum/tcg_card/pack_1/hos
+ name = "Head of Security"
+ desc = "The head of the security department, charged with putting away Syndicate and Assistant scum alike."
+ icon_state = "hos"
+ rarity = "Uncommon"
+ card_type = "Unit"
+
+/datum/tcg_card/pack_1/cmo
+ name = "Chief Medical Officer"
+ desc = "The head of the medical department who makes sure their department isn't committing any intentional or unintentional malpractice."
+ icon_state = "cmo"
+ rarity = "Uncommon"
+ card_type = "Unit"
+
+/datum/tcg_card/pack_1/qm
+ name = "Quartermaster"
+ desc = "The head of the supply department that makes sure everyone gets their crates and their ores."
+ icon_state = "qm"
+ rarity = "Uncommon"
+ card_type = "Unit"
+
+// ENGINEERING
+
+/datum/tcg_card/pack_1/atmos_tech
+ name = "Atmospheric Technician"
+ desc = "The workers of the Engineering department who ensure the air is breathable and devoid of anything harmful."
+ icon_state = "atmos_tech"
+ rarity = "Common"
+ card_type = "Unit"
+
+/datum/tcg_card/pack_1/engineer
+ name = "Station Engineer"
+ desc = "The main working arm of the Engineering department, Station Engineers keep the hull and all the machines within intact."
+ icon_state = "engineer"
+ rarity = "Common"
+ card_type = "Unit"
+
+/datum/tcg_card/pack_1/poly
+ name = "Poly"
+ desc = "An expert in quantum cracker theory, she continues to scare enginee- INTEGRITY FAILING!"
+ icon_state = "poly"
+ rarity = "Uncommon"
+ card_type = "Unit"
+
+// MEDICAL
+
+/datum/tcg_card/pack_1/doctor
+ name = "Medical Doctor"
+ desc = "Medical Doctors are able to cure almost any ailment that may be inflicted on a worker... while also inflicting some themself."
+ icon_state = "doctor"
+ rarity = "Common"
+ card_type = "Unit"
+
+/datum/tcg_card/pack_1/chemist
+ name = "Chemist"
+ desc = "Chemists are definitely not producing meth instead of life-saving chemicals."
+ icon_state = "chemist"
+ rarity = "Common"
+ card_type = "Unit"
+
+/datum/tcg_card/pack_1/paramedic
+ name = "Paramedic"
+ desc = "The Medical Department's first response member responsible for stabilizing and rescuing Nanotrasen employees."
+ icon_state = "paramedic"
+ rarity = "Common"
+ card_type = "Unit"
+
+/datum/tcg_card/pack_1/virologist
+ name = "Virologist"
+ desc = "The virologist is the person you go crying to that you either have the common cold or a disease that kills you in a few minutes. They might have been the cause of both of them."
+ icon_state = "virologist"
+ rarity = "Common"
+ card_type = "Unit"
+
+/datum/tcg_card/pack_1/coroner
+ name = "Coroner"
+ desc = "Overseer of the morgue, the coroner ensures that dead bodies are properly stored and have their autopsies recorded."
+ icon_state = "coroner"
+ rarity = "Common"
+ card_type = "Unit"
+
+/datum/tcg_card/pack_1/psychologist
+ name = "Psychologist"
+ desc = "Hired to offer emotional reassurance to employees aboard Nanotrasen stations but is usually found secretly dealing their drugs to anyone who asks."
+ icon_state = "psych"
+ rarity = "Common"
+ card_type = "Unit"
+
+/datum/tcg_card/pack_1/runtime // the urge to make this card throw a runtime.
+ name = "Runtime"
+ desc = "GCAT. Somehow, the four letters used in genomes can spell cat. How purr-ious."
+ icon_state = "runtime"
+ rarity = "Uncommon"
+ card_type = "Unit"
+
+// RESEARCH
+
+/datum/tcg_card/pack_1/geneticist
+ name = "Geneticist"
+ desc = "Tasked with manipulating humanoid DNA, the Geneticist is able to give out genetic powers to their fellow crew."
+ icon_state = "geneticist"
+ rarity = "Common"
+ card_type = "Unit"
+
+/datum/tcg_card/pack_1/roboticist
+ name = "Roboticist"
+ desc = "The maintainer of all things cyborg, Roboticists build and maintain cyborgs for the station and are able to build a wide variety of exosuits."
+ icon_state = "roboticist"
+ rarity = "Common"
+ card_type = "Unit"
+
+/datum/tcg_card/pack_1/scientist
+ name = "Scientist"
+ desc = "A Scientist's job ranges from manning the R&D desk, to mixing chemicals, to setting up tank transfer valve bombs"
+ icon_state = "scientist"
+ rarity = "Common"
+ card_type = "Unit"
+
+/datum/tcg_card/pack_1/en
+ name = "E-N"
+ desc = "Robotics' adorable and lovable clone of Ian, he's got a heart of gold and can even do your taxes for you! Beware any unexpected sparking though."
+ icon_state = "e-n"
+ rarity = "Uncommon"
+ card_type = "Unit"
+
+// SECURITY
+
+/datum/tcg_card/pack_1/warden
+ name = "Warden"
+ desc = "Watcher of the armory and the prison wing, the Warden expertly puts down rowdy criminals with Krav Maga."
+ icon_state = "warden"
+ rarity = "Uncommon"
+ card_type = "Unit"
+
+/datum/tcg_card/pack_1/officer
+ name = "Security Officer"
+ desc = "The sworn enemy of any greytider, Security Officers are hired to keep the station in order and free of crime."
+ icon_state = "officer"
+ rarity = "Common"
+ card_type = "Unit"
+
+/datum/tcg_card/pack_1/detective
+ name = "Detective"
+ desc = "Sometimes masquerading as a noir detective, the Detective uses their deductive skills to help Security find suspects of crimes."
+ icon_state = "detective"
+ rarity = "Common"
+ card_type = "Unit"
+
+/datum/tcg_card/pack_1/araneus
+ name = "Sergeant Araneus"
+ desc = "The Head of Security's trusty pet spider is known for her violent retaliations torwards mistreatment."
+ icon_state = "araneus"
+ rarity = "Uncommon"
+ card_type = "Unit"
+
+/datum/tcg_card/pack_1/paperwork
+ name = "Paperwork"
+ desc = "The Internal Affair's pet sloth is as mopey as can be and can sometimes get around to eating paperwork. Still slightly faster than a legal case."
+ icon_state = "paperwork"
+ rarity = "Uncommon"
+ card_type = "Unit"
+
+// SERVICE
+
+/datum/tcg_card/pack_1/botanist
+ name = "Botanist"
+ desc = "The main ingredient provider for the chef, skilled botanist can produce plants that can fill a crewmember up and kill them just as quickly."
+ icon_state = "botanist"
+ rarity = "Common"
+ card_type = "Unit"
+
+/datum/tcg_card/pack_1/mime
+ name = "Mime"
+ desc = "..."
+ icon_state = "mime"
+ rarity = "Common"
+ card_type = "Unit"
+
+/datum/tcg_card/pack_1/clown
+ name = "Clown"
+ desc = "Honk!"
+ icon_state = "clown"
+ rarity = "Common"
+ card_type = "Unit"
+
+/datum/tcg_card/pack_1/janitor
+ name = "Janitor"
+ desc = "The humble Janitor travels the station in search of any messes that need cleaning."
+ icon_state = "janitor"
+ rarity = "Common"
+ card_type = "Unit"
+
+/datum/tcg_card/pack_1/chef
+ name = "Chef"
+ desc = "Wielder of CQC within their kitchen, the Chef protects their kitchen from any invaders trying to disrupt the distribution of food to the crew."
+ icon_state = "chef"
+ rarity = "Common"
+ card_type = "Unit"
+
+/datum/tcg_card/pack_1/bartender
+ name = "Bartender"
+ desc = "The station's OTHER source of emotional reassurance, the Bartender serves alcohol to anyone who wants it while shooting any disruptive patrons with their shotgun."
+ icon_state = "bartender"
+ rarity = "Common"
+ card_type = "Unit"
+
+/datum/tcg_card/pack_1/chaplain
+ name = "Chaplain"
+ desc = "The spirtual leader of the station, the Chaplain offers unique services due to their connection with religious higher-ups."
+ icon_state = "chaplain"
+ rarity = "Common"
+ card_type = "Unit"
+
+/datum/tcg_card/pack_1/librarian
+ name = "Librarian"
+ desc = "Usually found within their library writing and printing books, the Librarian is able to loan out books full of knowledge. Don't forget to return them!"
+ icon_state = "librarian"
+ rarity = "Common"
+ card_type = "Unit"
+
+// SUPPLY
+
+/datum/tcg_card/pack_1/cargo_tech
+ name = "Cargo Technician"
+ desc = "The main workhorse of the Supply department, Cargo Technicians ensure your crates are delivered soon after you order them."
+ icon_state = "cargo_tech"
+ rarity = "Common"
+ card_type = "Unit"
+
+/datum/tcg_card/pack_1/miner
+ name = "Shaft Miner"
+ desc = "Pioneers of Lavaland, Shaft Miners brave the horrors in order to bring materials to the station."
+ icon_state = "miner"
+ rarity = "Common"
+ card_type = "Unit"
+
+/datum/tcg_card/pack_1/forklift
+ name = "Forklift"
+ desc = "Supply's pet of choice, Forklift has been taught how to carry crates and wouldn't hurt a fly!"
+ icon_state = "forklift"
+ rarity = "Uncommon"
+ card_type = "Unit"
+
+/datum/tcg_card/pack_1/brad
+ name = "Brad"
+ desc = "Residing just on the outskirts of the Mining Outpost, Brad is a cockroach that has adapted to the weather patterns of Lavaland and can withstand them."
+ icon_state = "brad"
+ rarity = "Uncommon"
+ card_type = "Unit"
+
+// MISC
+
+/datum/tcg_card/pack_1/assistant
+ name = "Assistant"
+ desc = "Hired to assist employees around the station, Assistants tend to do the exact opposite of that."
+ icon_state = "assistant"
+ rarity = "Common"
+ card_type = "Unit"
+
+/datum/tcg_card/pack_1/greytide
+ name = "Greytide"
+ desc = "Born from disgruntled and abused Assistants, the Greytide are a nuisance to Security and the rest of the station alike."
+ icon_state = "greytide"
+ rarity = "Rare"
+ card_type = "Unit"
+
+/datum/tcg_card/pack_1/mouse
+ name = "Mouse"
+ desc = "The bane of engineers around the sector, the Mouse makes any cables they find a nice meal for themself."
+ icon_state = "mouse"
+ rarity = "Common"
+ card_type = "Unit"
diff --git a/code/modules/tcg/tcg_cards.dm b/code/modules/tcg/tcg_cards.dm
new file mode 100644
index 00000000000..b21af44328a
--- /dev/null
+++ b/code/modules/tcg/tcg_cards.dm
@@ -0,0 +1,461 @@
+#define ROTATED_ANGLE 90
+#define UNROTATED_ANGLE 0
+
+// Need a TCG coin or two to replace the gold one that can be dropped. Make it shrink like the cards/packs
+
+/datum/tcg_card
+ var/name = "Chrono Legionnare"
+ var/desc = "You shouldn't be seeing this. You should ahelp this!"
+ var/icon_state = "chrono"
+ var/pack = 'icons/obj/tcg/pack1.dmi'
+
+ // This will be probably implemented.... sometime.
+ // var/health = 0
+ // var/attack = 0
+ // var/mana = 0
+
+ var/faction = "Coderbus"
+ var/rarity = "Unobtainable"
+ var/card_type = "Unit"
+
+ var/obj/item/tcg_card/card
+
+/datum/tcg_card/proc/UseSelf(mob/living/user)
+ return
+
+/datum/tcg_card/proc/Rotate(mob/living/user)
+ return
+
+/datum/tcg_card/proc/Unrotate(mob/living/user)
+ return
+
+/obj/item/tcg_card
+ name = "trading card"
+ desc = "A flipped trading card."
+ icon_state = "cardback"
+ icon = 'icons/obj/tcg/pack1.dmi'
+ new_attack_chain = TRUE
+ var/datum_type = /datum/tcg_card
+ var/datum/tcg_card/card_datum
+ var/flipped = FALSE
+ var/rotated = FALSE
+
+ w_class = WEIGHT_CLASS_TINY
+
+/obj/item/tcg_card/examine(mob/user)
+ . = ..()
+ if(flipped)
+ return
+
+ . += ""
+ . += "This card has the following stats:"
+ . += "Rarity: [card_datum.rarity]"
+ . += "Card Type: [card_datum.card_type]"
+
+/obj/item/tcg_card/equipped(mob/user, slot, initial)
+ . = ..()
+ transform = matrix()
+
+/obj/item/tcg_card/dropped(mob/user, silent)
+ . = ..()
+ transform = matrix(0.5,0,0,0,0.5,0)
+
+/obj/item/tcg_card/activate_self(mob/user)
+ if(..())
+ return ITEM_INTERACT_COMPLETE
+
+ if(flipped)
+ flipped = !flipped
+ if(!flipped)
+ flipped = TRUE
+ return ITEM_INTERACT_COMPLETE
+
+/obj/item/tcg_card/New(loc, new_datum)
+ . = ..()
+
+ if(new_datum)
+ datum_type = new_datum
+ card_datum = new datum_type
+ icon = card_datum.pack
+ icon_state = card_datum.icon_state
+ name = card_datum.name
+ desc = card_datum.desc
+
+/obj/item/tcg_card/attack_hand(mob/user)
+ var/list/choices = list(
+ "Pick Up" = image(icon = 'icons/mob/radial.dmi', icon_state = "radial_pickup"),
+ "Rotate" = image(icon = 'icons/mob/radial.dmi', icon_state = "radial_rotate"),
+ "Flip" = image(icon = 'icons/mob/radial.dmi', icon_state = "radial_flip"),
+ )
+ var/result = show_radial_menu(user, src, choices, require_near = TRUE)
+ switch(result)
+ if("Pick Up")
+ . = ..()
+ if("Flip")
+ flipped = !flipped
+ if(flipped)
+ icon_state = "cardback"
+ name = "Battles of Orion card"
+ desc = "A flipped Battles of Orion-branded card."
+ else
+ name = card_datum.name
+ desc = card_datum.desc
+ icon_state = card_datum.icon_state
+ if("Rotate")
+ var/matrix/ntransform = matrix(transform)
+ if(rotated)
+ ntransform.TurnTo(ROTATED_ANGLE , UNROTATED_ANGLE)
+ else
+ ntransform.TurnTo(UNROTATED_ANGLE , ROTATED_ANGLE)
+ rotated = !rotated
+ animate(src, transform = ntransform, time = 2, easing = (EASE_IN|EASE_OUT))
+ if(rotated)
+ card_datum.Rotate(user)
+ else
+ card_datum.Unrotate(user)
+
+/obj/item/tcg_card/item_interaction(mob/living/user, obj/item/used, list/modifiers)
+ if(istype(used, /obj/item/tcg_card))
+ var/obj/item/tcg_card/second_card = used
+ if(loc == user && second_card.loc == user)
+ var/obj/item/tcgcard_hand/hand = new(get_turf(user))
+ user.unequip(src)
+ user.unequip(second_card)
+ src.forceMove(hand)
+ second_card.forceMove(hand)
+ hand.cards.Add(src)
+ hand.cards.Add(second_card)
+ user.put_in_hands(hand)
+ hand.update_icon()
+ return ITEM_INTERACT_COMPLETE
+
+ var/obj/item/tcgcard_deck/new_deck = new /obj/item/tcgcard_deck(drop_location())
+ new_deck.flipped = flipped
+ user.unequip(second_card)
+ second_card.forceMove(new_deck)
+ src.forceMove(new_deck)
+ new_deck.update_icon(UPDATE_ICON_STATE)
+ new_deck.update_icon()
+ return ITEM_INTERACT_COMPLETE
+
+ if(istype(used, /obj/item/tcgcard_deck))
+ var/obj/item/tcgcard_deck/old_deck = used
+ if(length(old_deck.contents) >= 30)
+ to_chat(user, "This pile has too many cards for a regular deck!")
+ return ITEM_INTERACT_COMPLETE
+ user.unequip(src)
+ src.forceMove(old_deck)
+ flipped = old_deck.flipped
+ old_deck.update_icon()
+ update_icon()
+ return ITEM_INTERACT_COMPLETE
+
+ return ..()
+
+/obj/item/cardpack
+ name = "Trading Card Pack: Chrono & Friends"
+ desc = "This unobtainable group certainly shouldn't be findable and you should ahelp this!"
+ icon = 'icons/obj/tcg/misc.dmi'
+ icon_state = "cardpack"
+ w_class = WEIGHT_CLASS_TINY
+ new_attack_chain = TRUE
+ /// The card series to look through
+ var/list/series = list(/datum/tcg_card/pack_1)
+ /// The chance there will be a coin in the pack
+ var/contains_coin = -1
+ /// The amount of cards you draw
+ var/card_count = 5
+ /// The rarity table
+ var/list/rarity_table = list(
+ "Common" = 900,
+ "Uncommon" = 300,
+ "Rare" = 50,
+ "Legendary" = 3
+ )
+ /// The amount of cards to draw from the guarenteed rarity table
+ var/guaranteed_count = 1
+ /// The guaranteed rarity table, acts about the same as the rarity table.
+ var/list/guar_rarity = list(
+ "Uncommon" = 30,
+ "Rare" = 9,
+ "Legendary" = 1
+ )
+
+/obj/item/cardpack/series_one
+ name = "Battles of Orion: Series 1"
+ desc = "Contains five cards from the Series 1 of Battles of Orion! Collect them all!"
+ series = list(/datum/tcg_card/pack_1)
+ contains_coin = 10
+
+/obj/item/cardpack/equipped(mob/user, slot, initial)
+ . = ..()
+ transform = matrix()
+
+/obj/item/cardpack/dropped(mob/user, silent)
+ . = ..()
+ transform = matrix(0.5,0,0,0,0.5,0)
+
+/obj/item/cardpack/activate_self(mob/user)
+ if(..())
+ return ITEM_INTERACT_COMPLETE
+
+ var/list/cards = buildCardListWithRarity(card_count, guaranteed_count)
+ var/obj/item/tcgcard_hand/hand = new(get_turf(user))
+
+ for(var/template in cards)
+ var/obj/item/tcg_card/card = new(hand, template)
+ hand.cards.Add(card)
+ user.put_in_hands(hand)
+ hand.update_icon()
+ to_chat(user, "Wow! Check out these cards!")
+ playsound(loc, 'sound/items/poster_ripped.ogg', 20, TRUE)
+ if(prob(contains_coin))
+ to_chat(user, "...and it came with a flipper, too!")
+ new /obj/item/coin/thunderdome(get_turf(user))
+ // new rulebook goes here
+ qdel(src)
+ return ITEM_INTERACT_COMPLETE
+
+/obj/item/cardpack/proc/buildCardListWithRarity(card_cnt, rarity_cnt)
+ var/list/return_cards = list()
+
+ var/list/cards = list()
+ for(var/card_type in series)
+ for(var/card in subtypesof(card_type))
+ var/datum/tcg_card/new_card = new card()
+ if(new_card.name == "Chrono Legionnare")
+ continue
+ cards.Add(card)
+ qdel(new_card)
+ var/list/possible_cards = list()
+ var/list/rarity_cards = list("Legendary" = list(),"Rare" = list(),"Uncommon" = list(),"Common" = list())
+ for(var/card in cards)
+ var/datum/tcg_card/new_card = new card()
+ if(new_card.name == "Stupid Coder")
+ continue
+ possible_cards[card] = rarity_table[new_card.rarity]
+ var/list/rarity_card_type = rarity_cards[new_card.rarity]
+ if(!rarity_card_type)
+ rarity_card_type = list()
+ rarity_card_type.Add(card)
+ rarity_cards[new_card.rarity] = rarity_card_type
+ qdel(new_card)
+
+ for(var/card_counter = 1 to card_count)
+ var/cardtype = pickweight(possible_cards)
+ return_cards.Add(cardtype)
+
+ for(var/card_counter = 1 to guaranteed_count)
+ var/card_list = pickweight(guar_rarity)
+ return_cards.Add(pick(rarity_cards[card_list]))
+
+ return return_cards
+
+/obj/item/tcgcard_deck
+ name = "Trading Card Deck"
+ desc = "A stack of Battle of Orion cards."
+ icon = 'icons/obj/tcg/misc.dmi'
+ icon_state = "deck_up"
+ w_class = WEIGHT_CLASS_TINY
+ new_attack_chain = TRUE
+
+ var/flipped = TRUE
+ var/max_cards = 30
+
+/obj/item/tcgcard_deck/examine(mob/user)
+ . = ..()
+ . += "\The [src] has [contents.len] cards inside."
+
+/obj/item/tcgcard_deck/update_icon()
+ . = ..()
+ cut_overlays()
+ if(flipped)
+ switch(contents.len)
+ if(1 to 10)
+ icon_state = "deck_low"
+ if(11 to 20)
+ icon_state = "deck_half"
+ if(21 to INFINITY)
+ icon_state = "deck_full"
+ else
+ icon_state = "deck_up"
+
+/obj/item/tcgcard_deck/Destroy()
+ for(var/obj/item/tcg_card/stored_card in contents)
+ stored_card.forceMove(drop_location())
+ . = ..()
+
+/obj/item/tcgcard_deck/attack_hand(mob/user)
+ var/list/choices = list(
+ "Draw" = image(icon = 'icons/mob/radial.dmi', icon_state = "radial_draw"),
+ "Shuffle" = image(icon = 'icons/mob/radial.dmi', icon_state = "radial_shuffle"),
+ "Pickup" = image(icon = 'icons/mob/radial.dmi', icon_state = "radial_pickup"),
+ )
+ var/choice = show_radial_menu(user, src, choices, require_near = TRUE)
+ if(!check_menu(user))
+ return
+ switch(choice)
+ if("Draw")
+ draw_card(user)
+ if("Shuffle")
+ shuffle_deck(user)
+ if("Pickup")
+ user.put_in_hands(src)
+ if("Flip")
+ flip_deck()
+
+/obj/item/tcgcard_deck/proc/check_menu(mob/user)
+ if(!istype(user))
+ return FALSE
+ if(user.incapacitated() || !user.Adjacent(src))
+ return FALSE
+ return TRUE
+
+/obj/item/tcgcard_deck/item_interaction(mob/living/user, obj/item/used, list/modifiers)
+ if(istype(used, /obj/item/tcg_card))
+ if(contents.len >= max_cards)
+ to_chat(user, "This pile has too many cards for a single deck!")
+ return ITEM_INTERACT_COMPLETE
+
+ var/obj/item/tcg_card/new_card = used
+ new_card.flipped = flipped
+ user.unequip(new_card)
+ new_card.forceMove(src)
+ update_icon()
+ return ITEM_INTERACT_COMPLETE
+
+ if(istype(used, /obj/item/tcgcard_hand))
+ var/obj/item/tcgcard_hand/hand = used
+ for(var/obj/item/tcg_card/card in hand.cards)
+ if(contents.len >= max_cards)
+ return ITEM_INTERACT_COMPLETE
+
+ card.flipped = flipped
+ card.forceMove(src)
+ hand.cards.Remove(card)
+ update_icon()
+ return ITEM_INTERACT_COMPLETE
+
+ return ..()
+
+/obj/item/tcgcard_deck/activate_self(mob/user)
+ if(..())
+ return ITEM_INTERACT_COMPLETE
+
+ shuffle_deck(user)
+ return ITEM_INTERACT_COMPLETE
+
+/obj/item/tcgcard_deck/proc/draw_card(mob/user)
+ if(!contents.len)
+ return
+ var/obj/item/tcg_card/drawn_card = contents[contents.len]
+ drawn_card.flipped = flipped
+ drawn_card.forceMove(get_turf(user))
+ user.put_in_hands(drawn_card)
+ drawn_card.update_icon()
+ user.visible_message("[user] draws a card from \the [src]!", \
+ "You draw a card from \the [src]!")
+ update_icon()
+ if(!contents.len)
+ qdel(src)
+
+/obj/item/tcgcard_deck/proc/shuffle_deck(mob/user, visible = TRUE)
+ if(!contents.len)
+ return
+ var/turf/T = get_turf(src)
+ var/list/shuffled = shuffle(contents.Copy())
+ for(var/obj/item/tcg_card/card in contents)
+ card.forceMove(T)
+ for(var/obj/item/tcg_card/card in shuffled)
+ card.forceMove(src)
+ if(visible)
+ user.visible_message("[user] shuffles \the [src]!", \
+ "You shuffle \the [src]!")
+
+/obj/item/tcgcard_deck/proc/flip_deck()
+ flipped = !flipped
+ var/turf/T = get_turf(src)
+ var/list/temp_cards = list()
+ for(var/obj/item/tcg_card/card in contents)
+ temp_cards.Add(card)
+ for(var/obj/item/tcg_card/card in temp_cards)
+ card.forceMove(T)
+ for(var/i = temp_cards.len to 1 step -1)
+ var/obj/item/tcg_card/card = temp_cards[i]
+ card.forceMove(src)
+ card.flipped = flipped
+ card.update_icon()
+ update_icon()
+
+/obj/item/tcgcard_hand
+ name = "Card Hand"
+ desc = "A hand full of Battle of Orion cards."
+ icon = 'icons/effects/effects.dmi'
+ icon_state = "nothing"
+ w_class = WEIGHT_CLASS_TINY
+ new_attack_chain = TRUE
+ var/list/cards = list()
+
+/obj/item/tcgcard_hand/update_icon()
+ . = ..()
+ cut_overlays()
+ var/angular = length(cards) / 2 * -30 + 15
+ for(var/obj/item/tcg_card/card in cards)
+ var/image/I = image(icon = card.icon, icon_state = card.icon_state)
+ var/matrix/ntransform = matrix(I.transform)
+ ntransform.TurnTo(angular, 0)
+ ntransform.Translate(sin(angular) * -15, cos(angular) * 15)
+ I.transform = ntransform
+ angular += 30
+ overlays += I
+
+
+/obj/item/tcgcard_hand/item_interaction(mob/living/user, obj/item/used, list/modifiers)
+ if(!istype(used, /obj/item/tcg_card))
+ return ..()
+
+ var/obj/item/tcg_card/card = used
+ if(loc == user && card.loc == user)
+ user.unequip(card)
+ card.forceMove(src)
+ cards.Add(card)
+ update_icon()
+ return ITEM_INTERACT_COMPLETE
+
+/obj/item/tcgcard_hand/activate_self(mob/user)
+ if(..())
+ return ITEM_INTERACT_COMPLETE
+
+ if(loc != user)
+ return ITEM_INTERACT_COMPLETE
+
+ var/list/choices = list()
+ for(var/obj/item/tcg_card/card in cards)
+ choices[card] = image(icon = card.icon, icon_state = card.icon_state)
+ var/obj/item/tcg_card/choice = show_radial_menu(user, src, choices, require_near = TRUE)
+
+ if(choice)
+ choice.forceMove(get_turf(src))
+ user.put_in_hands(choice)
+ cards.Remove(choice)
+ update_icon()
+ if(length(cards) == 0)
+ qdel(src)
+ return ITEM_INTERACT_COMPLETE
+
+/obj/item/tcgcard_hand/Destroy()
+ for(var/obj/item/tcg_card/card in cards)
+ card.forceMove(drop_location())
+ cards = list()
+ . = ..()
+
+/obj/item/tcgcard_hand/equipped(mob/user, slot, initial)
+ . = ..()
+ transform = matrix()
+
+/obj/item/tcgcard_hand/dropped(mob/user, silent)
+ . = ..()
+ transform = matrix(0.5,0,0,0,0.5,0)
+
+#undef ROTATED_ANGLE
+#undef UNROTATED_ANGLE
diff --git a/icons/mob/radial.dmi b/icons/mob/radial.dmi
index d45748ca2da..d38fa1696ac 100644
Binary files a/icons/mob/radial.dmi and b/icons/mob/radial.dmi differ
diff --git a/icons/obj/economy.dmi b/icons/obj/economy.dmi
index c81aaaeb571..bb0630e0c2b 100644
Binary files a/icons/obj/economy.dmi and b/icons/obj/economy.dmi differ
diff --git a/icons/obj/tcg/misc.dmi b/icons/obj/tcg/misc.dmi
new file mode 100644
index 00000000000..babfcaace61
Binary files /dev/null and b/icons/obj/tcg/misc.dmi differ
diff --git a/icons/obj/tcg/pack1.dmi b/icons/obj/tcg/pack1.dmi
new file mode 100644
index 00000000000..89b1b43dde7
Binary files /dev/null and b/icons/obj/tcg/pack1.dmi differ
diff --git a/paradise.dme b/paradise.dme
index 83c0017f2b2..d5aff01f59a 100644
--- a/paradise.dme
+++ b/paradise.dme
@@ -3468,6 +3468,8 @@
#include "code\modules\surgery\organs\subtypes\vox_organs.dm"
#include "code\modules\surgery\organs\subtypes\vulpkanin_organs.dm"
#include "code\modules\surgery\organs\subtypes\xenos.dm"
+#include "code\modules\tcg\pack_1.dm"
+#include "code\modules\tcg\tcg_cards.dm"
#include "code\modules\telesci\bscrystal.dm"
#include "code\modules\telesci\gps.dm"
#include "code\modules\telesci\rcs.dm"