diff --git a/code/controllers/subsystem/job.dm b/code/controllers/subsystem/job.dm index 7dae0d0126..0ba6076be2 100644 --- a/code/controllers/subsystem/job.dm +++ b/code/controllers/subsystem/job.dm @@ -493,24 +493,27 @@ SUBSYSTEM_DEF(job) if(ishuman(H) && H.client && N) if(H.client && H.client.prefs && length(H.client.prefs.tcg_cards)) var/obj/item/tcgcard_binder/binder = new(get_turf(H)) - if(!H.equip_to_slot_if_possible(binder, SLOT_IN_BACKPACK, disable_warning = TRUE, bypass_equip_delay_self = TRUE)) - qdel(binder) - else - for(var/card_type in H.client.prefs.tcg_cards) + H.equip_to_slot_if_possible(binder, SLOT_IN_BACKPACK, disable_warning = TRUE, bypass_equip_delay_self = TRUE) + for(var/card_type in H.client.prefs.tcg_cards) + if(card_type) var/obj/item/tcg_card/card = new(get_turf(H), card_type, H.client.prefs.tcg_cards[card_type]) card.forceMove(binder) binder.cards.Add(card) - binder.check_for_exodia() + binder.check_for_exodia() + if(length(H.client.prefs.tcg_decks)) + binder.decks = H.client.prefs.tcg_decks else if(H && N.client.prefs && length(N.client.prefs.tcg_cards)) var/obj/item/tcgcard_binder/binder = new(get_turf(H)) - if(!H.equip_to_slot_if_possible(binder, SLOT_IN_BACKPACK, disable_warning = TRUE, bypass_equip_delay_self = TRUE)) - qdel(binder) - else - for(var/card_type in N.client.prefs.tcg_cards) - var/obj/item/tcg_card/card = new(get_turf(H), card_type, H.client.prefs.tcg_cards[card_type]) + H.equip_to_slot_if_possible(binder, SLOT_IN_BACKPACK, disable_warning = TRUE, bypass_equip_delay_self = TRUE) + for(var/card_type in N.client.prefs.tcg_cards) + if(card_type) + var/obj/item/tcg_card/card = new(get_turf(H), card_type, N.client.prefs.tcg_cards[card_type]) card.forceMove(binder) binder.cards.Add(card) + binder.check_for_exodia() + if(length(N.client.prefs.tcg_decks)) + binder.decks = N.client.prefs.tcg_decks return H /* diff --git a/code/controllers/subsystem/persistence/_persistence.dm b/code/controllers/subsystem/persistence/_persistence.dm index a3be7b9c51..9b2c019db4 100644 --- a/code/controllers/subsystem/persistence/_persistence.dm +++ b/code/controllers/subsystem/persistence/_persistence.dm @@ -361,14 +361,4 @@ SUBSYSTEM_DEF(persistence) if(!original_human || original_human.stat == DEAD || !(original_human == ending_human)) continue - var/obj/item/tcgcard_binder/binder = locate() in ending_human - if(!binder || !length(binder.cards)) - continue - - var/list/card_types = list() - for(var/obj/item/tcg_card/card in binder.cards) - //if(!card.illegal) //Uncomment if you want to block syndie cards from saving - card_types[card.datum_type] = card.illegal - - ending_human.client.prefs.tcg_cards = card_types - ending_human.client.prefs.save_character(TRUE) + ending_human.SaveTCGCards() diff --git a/code/game/machinery/cryopod.dm b/code/game/machinery/cryopod.dm index ea41d77e2a..5be3e2a3a5 100644 --- a/code/game/machinery/cryopod.dm +++ b/code/game/machinery/cryopod.dm @@ -296,6 +296,12 @@ AM.forceMove(src) R.module.remove_module(I, TRUE) else + + if(ishuman(mob_occupant)) + var/mob/living/carbon/human/H = mob_occupant + if(H.mind && H.client && H.client.prefs && H == H.mind.original_character) + H.SaveTCGCards() + var/list/gear = list() if(iscarbon(mob_occupant)) // sorry simp-le-mobs deserve no mercy var/mob/living/carbon/C = mob_occupant diff --git a/code/game/objects/items/devices/PDA/PDA.dm b/code/game/objects/items/devices/PDA/PDA.dm index c09d23aafb..2820b11312 100644 --- a/code/game/objects/items/devices/PDA/PDA.dm +++ b/code/game/objects/items/devices/PDA/PDA.dm @@ -665,7 +665,8 @@ GLOBAL_LIST_EMPTY(PDAs) create_message(U, locate(href_list["target"])) if("MessageAll") - send_to_all(U) + if(cartridge?.spam_enabled) + send_to_all(U) if("toggle_block") toggle_blocking(usr, href_list["target"]) diff --git a/code/modules/antagonists/eldritch_cult/eldritch_items.dm b/code/modules/antagonists/eldritch_cult/eldritch_items.dm index fbf0740e50..ea6d1d50e2 100644 --- a/code/modules/antagonists/eldritch_cult/eldritch_items.dm +++ b/code/modules/antagonists/eldritch_cult/eldritch_items.dm @@ -50,7 +50,8 @@ background_icon_state = "bg_ecult" button_icon_state = "shatter" icon_icon = 'icons/mob/actions/actions_ecult.dmi' - check_flags = MOBILITY_HOLD|MOBILITY_MOVE|MOBILITY_USE + check_flags = NONE // required_mobility_flags handles this + required_mobility_flags = MOBILITY_HOLD|MOBILITY_MOVE|MOBILITY_USE var/mob/living/carbon/human/holder var/obj/item/melee/sickly_blade/sword @@ -62,11 +63,12 @@ /datum/action/innate/heretic_shatter/IsAvailable() if(IS_HERETIC(holder) || IS_HERETIC_MONSTER(holder)) - return TRUE + return ..() else return FALSE /datum/action/innate/heretic_shatter/Activate() + . = ..() var/turf/safe_turf = find_safe_turf(zlevels = sword.z, extended_safety_checks = TRUE) do_teleport(holder,safe_turf,forceMove = TRUE) to_chat(holder,"You feel a gust of energy flow through your body... the Rusted Hills heard your call...") diff --git a/code/modules/cargo/packs/costumes_toys.dm b/code/modules/cargo/packs/costumes_toys.dm index c0bd25b028..6a37ef80a9 100644 --- a/code/modules/cargo/packs/costumes_toys.dm +++ b/code/modules/cargo/packs/costumes_toys.dm @@ -343,7 +343,6 @@ /datum/supply_pack/costumes_toys/randomised/tcg/generate() . = ..() - var/cardpacktype var/list/cardtypes = subtypesof(/obj/item/cardpack) for(var/cardtype in cardtypes) var/obj/item/cardpack/pack = new cardtype(.) @@ -351,5 +350,5 @@ cardtypes.Remove(cardtype) qdel(pack) for(var/i in 1 to 10) - cardpacktype = pick(cardtypes) + var/cardpacktype = pick(cardtypes) new cardpacktype(.) diff --git a/code/modules/client/preferences.dm b/code/modules/client/preferences.dm index 33b8a1987c..0c21fc70f3 100644 --- a/code/modules/client/preferences.dm +++ b/code/modules/client/preferences.dm @@ -221,6 +221,7 @@ GLOBAL_LIST_EMPTY(preferences_datums) var/hide_ckey = FALSE //pref for hiding if your ckey shows round-end or not var/list/tcg_cards = list() + var/list/tcg_decks = list() /datum/preferences/New(client/C) parent = C diff --git a/code/modules/client/preferences_savefile.dm b/code/modules/client/preferences_savefile.dm index 458f607ac9..141346acde 100644 --- a/code/modules/client/preferences_savefile.dm +++ b/code/modules/client/preferences_savefile.dm @@ -666,6 +666,13 @@ SAVEFILE UPDATING/VERSIONING - 'Simplified', or rather, more coder-friendly ~Car else tcg_cards = list() + var/tcgdeckstr + S["tcg_decks"] >> tcgdeckstr + if(length(tcgdeckstr)) + tcg_decks = safe_json_decode(tcgdeckstr) + else + tcg_decks = list() + S["chosen_limb_id"] >> chosen_limb_id S["hide_ckey"] >> hide_ckey //saved per-character @@ -1108,6 +1115,11 @@ SAVEFILE UPDATING/VERSIONING - 'Simplified', or rather, more coder-friendly ~Car else S["tcg_cards"] << safe_json_encode(list()) + if(length(tcg_decks)) + S["tcg_decks"] << safe_json_encode(tcg_decks) + else + S["tcg_decks"] << safe_json_encode(list()) + cit_character_pref_save(S) return 1 diff --git a/code/modules/events/anomaly_bluespace.dm b/code/modules/events/anomaly_bluespace.dm index 7f0dedaab6..70d6b00fa4 100644 --- a/code/modules/events/anomaly_bluespace.dm +++ b/code/modules/events/anomaly_bluespace.dm @@ -11,7 +11,4 @@ anomaly_path = /obj/effect/anomaly/bluespace /datum/round_event/anomaly/anomaly_bluespace/announce(fake) - if(prob(90)) - priority_announce("Unstable bluespace anomaly detected on long range scanners. Expected location: [impact_area.name].", "Anomaly Alert") - else - print_command_report("Unstable bluespace anomaly detected on long range scanners. Expected location: [impact_area.name].", "Unstable bluespace anomaly") + priority_announce("Unstable bluespace anomaly detected on long range scanners. Expected location: [impact_area.name].", "Anomaly Alert") diff --git a/code/modules/events/anomaly_flux.dm b/code/modules/events/anomaly_flux.dm index 8047976330..0ba347af57 100644 --- a/code/modules/events/anomaly_flux.dm +++ b/code/modules/events/anomaly_flux.dm @@ -12,7 +12,5 @@ anomaly_path = /obj/effect/anomaly/flux /datum/round_event/anomaly/anomaly_flux/announce(fake) - if(prob(90)) - priority_announce("Localized hyper-energetic flux wave detected on long range scanners. Expected location: [impact_area.name].", "Anomaly Alert") - else - print_command_report("Localized hyper-energetic flux wave detected on long range scanners. Expected location: [impact_area.name].","Localized hyper-energetic flux wave") + priority_announce("Localized hyper-energetic flux wave detected on long range scanners. Expected location: [impact_area.name].", "Anomaly Alert") + diff --git a/code/modules/events/anomaly_grav.dm b/code/modules/events/anomaly_grav.dm index 7d2bb33889..01e70c290c 100644 --- a/code/modules/events/anomaly_grav.dm +++ b/code/modules/events/anomaly_grav.dm @@ -12,7 +12,4 @@ anomaly_path = /obj/effect/anomaly/grav /datum/round_event/anomaly/anomaly_grav/announce(fake) - if(prob(90)) - priority_announce("Gravitational anomaly detected on long range scanners. Expected location: [impact_area.name].", "Anomaly Alert") - else - print_command_report("Gravitational anomaly detected on long range scanners. Expected location: [impact_area.name].", "Gravitational anomaly") + priority_announce("Gravitational anomaly detected on long range scanners. Expected location: [impact_area.name].", "Anomaly Alert") diff --git a/code/modules/events/anomaly_pyro.dm b/code/modules/events/anomaly_pyro.dm index 350c8fc946..29c6e15d28 100644 --- a/code/modules/events/anomaly_pyro.dm +++ b/code/modules/events/anomaly_pyro.dm @@ -11,7 +11,4 @@ anomaly_path = /obj/effect/anomaly/pyro /datum/round_event/anomaly/anomaly_pyro/announce(fake) - if(prob(90)) - priority_announce("Pyroclastic anomaly detected on long range scanners. Expected location: [impact_area.name].", "Anomaly Alert") - else - print_command_report("Pyroclastic anomaly detected on long range scanners. Expected location: [impact_area.name].", "Pyroclastic anomaly") + priority_announce("Pyroclastic anomaly detected on long range scanners. Expected location: [impact_area.name].", "Anomaly Alert") diff --git a/code/modules/events/anomaly_vortex.dm b/code/modules/events/anomaly_vortex.dm index e2a4ceadf3..6a17a47d2b 100644 --- a/code/modules/events/anomaly_vortex.dm +++ b/code/modules/events/anomaly_vortex.dm @@ -12,7 +12,4 @@ anomaly_path = /obj/effect/anomaly/bhole /datum/round_event/anomaly/anomaly_vortex/announce(fake) - if(prob(90)) - priority_announce("Localized high-intensity vortex anomaly detected on long range scanners. Expected location: [impact_area.name]", "Anomaly Alert") - else - print_command_report("Localized high-intensity vortex anomaly detected on long range scanners. Expected location: [impact_area.name].","Vortex anomaly") + priority_announce("Localized high-intensity vortex anomaly detected on long range scanners. Expected location: [impact_area.name]", "Anomaly Alert") diff --git a/code/modules/events/brand_intelligence.dm b/code/modules/events/brand_intelligence.dm index 7c55bbfcd1..7d4ea66d30 100644 --- a/code/modules/events/brand_intelligence.dm +++ b/code/modules/events/brand_intelligence.dm @@ -35,10 +35,7 @@ source = initial(example.name) else if(originMachine) source = originMachine.name - if(prob(50)) - priority_announce("Rampant brand intelligence has been detected aboard [station_name()]. Please stand by. The origin is believed to be \a [source].", "Machine Learning Alert") - else - print_command_report("Rampant brand intelligence has been detected aboard [station_name()]. Please stand by. The origin is believed to be \a [source].", "Rampant brand intelligence") + priority_announce("Rampant brand intelligence has been detected aboard [station_name()]. Please stand by. The origin is believed to be \a [source].", "Machine Learning Alert") /datum/round_event/brand_intelligence/start() for(var/obj/machinery/vending/V in GLOB.machines) diff --git a/code/modules/events/shuttle_loan.dm b/code/modules/events/shuttle_loan.dm index bf9f25cb04..347162d9c5 100644 --- a/code/modules/events/shuttle_loan.dm +++ b/code/modules/events/shuttle_loan.dm @@ -45,7 +45,7 @@ if(ANTIDOTE_NEEDED) message = "Cargo: Your station has been chosen for an epidemiological research project. Send us your cargo shuttle to receive your research samples." title = "CentCom Research Initiatives" - if (PIZZA_DELIVERY) + if(PIZZA_DELIVERY) message = "Cargo: It looks like a neighbouring station accidentally delivered their pizza to you instead." title = "CentCom Spacepizza Division" if(ITS_HIP_TO) @@ -57,7 +57,7 @@ title = "CentCom Security Division" bonus_points = 45000 //If you mess up, people die and the shuttle gets turned into swiss cheese if(DELTA_CRATES) - message = "Cargo: We have discovered a warehouse of DELTA locked crates, we cant store any more of them at CC can you take them for us?." + message = "Cargo: We have discovered a warehouse of DELTA locked crates. We can't store any more of them at CC, can you take them for us?" title = "CentCom Security Division" bonus_points = 25000 //If you mess up, people die and the shuttle gets turned into swiss cheese if(prob(50)) diff --git a/code/modules/events/spacevine.dm b/code/modules/events/spacevine.dm index edc062f78f..c8679447b8 100644 --- a/code/modules/events/spacevine.dm +++ b/code/modules/events/spacevine.dm @@ -3,7 +3,7 @@ typepath = /datum/round_event/spacevine weight = 15 max_occurrences = 3 - min_players = 10 + min_players = 20 /datum/round_event/spacevine fakeable = FALSE diff --git a/code/modules/hydroponics/seed_extractor.dm b/code/modules/hydroponics/seed_extractor.dm index 71701d9637..e0e15ac111 100644 --- a/code/modules/hydroponics/seed_extractor.dm +++ b/code/modules/hydroponics/seed_extractor.dm @@ -76,7 +76,7 @@ /obj/machinery/seed_extractor/examine(mob/user) . = ..() if(in_range(user, src) || isobserver(user)) - . += "The status display reads: Extracting [seed_multiplier] seed(s) per piece of produce.
Machine can store up to [max_seeds]% seeds.
" + . += "The status display reads: Extracting [seed_multiplier] seed(s) per piece of produce.
Machine can store up to [max_seeds] seeds.
" /obj/machinery/seed_extractor/attackby(obj/item/O, mob/user, params) diff --git a/code/modules/mob/living/carbon/human/species_types/vampire.dm b/code/modules/mob/living/carbon/human/species_types/vampire.dm index 5e07150ce6..89b3d603ea 100644 --- a/code/modules/mob/living/carbon/human/species_types/vampire.dm +++ b/code/modules/mob/living/carbon/human/species_types/vampire.dm @@ -58,7 +58,7 @@ to_chat(C, "You ran out of blood!") C.dust() var/area/A = get_area(C) - if(istype(A, /area/chapel)) + if(istype(A, /area/chapel) && C.mind?.assigned_role != "Chaplain") to_chat(C, "You don't belong here!") C.adjustFireLoss(5) C.adjust_fire_stacks(6) diff --git a/code/modules/mob/living/carbon/say.dm b/code/modules/mob/living/carbon/say.dm index d75843a3e5..67c29b4211 100644 --- a/code/modules/mob/living/carbon/say.dm +++ b/code/modules/mob/living/carbon/say.dm @@ -10,7 +10,7 @@ /mob/living/carbon/can_speak_vocal(message) if(silent) return 0 - if(get_message_language(message) == /datum/language/signlanguage && (handcuffed || (!src.get_bodypart(BODY_ZONE_L_ARM) && !src.get_bodypart(BODY_ZONE_R_ARM)) || get_num_held_items() == held_items.len)) + if(get_selected_language() == /datum/language/signlanguage && handcuffed) return 0 return ..() diff --git a/code/modules/mob/living/say.dm b/code/modules/mob/living/say.dm index 606daed0c5..9646796802 100644 --- a/code/modules/mob/living/say.dm +++ b/code/modules/mob/living/say.dm @@ -329,8 +329,26 @@ GLOBAL_LIST_INIT(department_radio_keys, list( return 1 /mob/living/proc/can_speak_vocal(message) //Check AFTER handling of xeno and ling channels - if(HAS_TRAIT(src, TRAIT_MUTE) && get_message_language(message) != /datum/language/signlanguage) + var/obj/item/bodypart/leftarm = get_bodypart(BODY_ZONE_L_ARM) + var/obj/item/bodypart/rightarm = get_bodypart(BODY_ZONE_R_ARM) + if(HAS_TRAIT(src, TRAIT_MUTE) && get_selected_language() != /datum/language/signlanguage) return 0 + + if (get_selected_language() == /datum/language/signlanguage) + var/left_disabled = FALSE + var/right_disabled = FALSE + if (istype(leftarm)) // Need to check if the arms exist first before checking if they are disabled or else it will runtime + if (leftarm.is_disabled()) + left_disabled = TRUE + else + left_disabled = TRUE + if (istype(rightarm)) + if (rightarm.is_disabled()) + right_disabled = TRUE + else + right_disabled = TRUE + if (left_disabled && right_disabled) // We want this to only return false if both arms are either missing or disabled since you could technically sign one-handed. + return 0 if(is_muzzled()) return 0 diff --git a/code/modules/mob/living/simple_animal/bot/floorbot.dm b/code/modules/mob/living/simple_animal/bot/floorbot.dm index 47173f10ea..ff6941ec70 100644 --- a/code/modules/mob/living/simple_animal/bot/floorbot.dm +++ b/code/modules/mob/living/simple_animal/bot/floorbot.dm @@ -340,7 +340,6 @@ target = null playsound(src, 'sound/effects/whistlereset.ogg', 50, TRUE) return - if(isspaceturf(target_turf)) //Must be a hull breach or in line mode to continue. if(!is_hull_breach(target_turf) && !targetdirection) @@ -356,9 +355,9 @@ sleep(50) if(mode == BOT_REPAIRING && src.loc == target_turf) if(autotile) //Build the floor and include a tile. + target_turf.PlaceOnTop(/turf/open/floor/plasteel, flags = CHANGETURF_INHERIT_AIR) + else //Build a hull plating without a floor tile. target_turf.PlaceOnTop(/turf/open/floor/plating, flags = CHANGETURF_INHERIT_AIR) - else //Build a hull plating without a floor tile. - target_turf.PlaceOnTop(/turf/open/floor/plasteel, flags = CHANGETURF_INHERIT_AIR) else var/turf/open/floor/F = target_turf @@ -372,7 +371,7 @@ if(mode == BOT_REPAIRING && F && src.loc == F) F.broken = 0 F.burnt = 0 - F.PlaceOnTop(/turf/open/floor/plating, flags = CHANGETURF_INHERIT_AIR) + F.PlaceOnTop(/turf/open/floor/plasteel, flags = CHANGETURF_INHERIT_AIR) if(replacetiles && F.type != initial(tiletype.turf_type) && specialtiles && !isplatingturf(F)) anchored = TRUE @@ -434,4 +433,4 @@ if(robot.mode == BOT_REPAIRING) return TRUE return FALSE - + diff --git a/code/modules/reagents/chemistry/reagents/medicine_reagents.dm b/code/modules/reagents/chemistry/reagents/medicine_reagents.dm index e55286ed3f..0959fb58e0 100644 --- a/code/modules/reagents/chemistry/reagents/medicine_reagents.dm +++ b/code/modules/reagents/chemistry/reagents/medicine_reagents.dm @@ -499,7 +499,7 @@ SEND_SIGNAL(M, COMSIG_ADD_MOOD_EVENT, "painful_medicine", /datum/mood_event/painful_medicine) var/vol = reac_volume + M.reagents.get_reagent_amount(/datum/reagent/medicine/synthflesh) //Has to be at less than THRESHOLD_UNHUSK burn damage and have 100 synthflesh before unhusking. Corpses dont metabolize. - if(HAS_TRAIT_FROM(M, TRAIT_HUSK, "burn") && M.getFireLoss() < THRESHOLD_UNHUSK && (vol > 100)) + if(HAS_TRAIT_FROM(M, TRAIT_HUSK, "burn") && M.getFireLoss() < THRESHOLD_UNHUSK && (vol >= 100)) M.cure_husk("burn") M.visible_message("Most of [M]'s burnt off or charred flesh has been restored.") ..() diff --git a/code/modules/tcg/cards.dm b/code/modules/tcg/cards.dm index 970aef0bba..ff7d2fee2a 100644 --- a/code/modules/tcg/cards.dm +++ b/code/modules/tcg/cards.dm @@ -183,7 +183,6 @@ user.transferItemToLoc(second_card, new_deck)//Start a new pile with both cards, in the order of card placement. user.transferItemToLoc(src, new_deck) new_deck.update_icon_state() - user.put_in_hands(new_deck) new_deck.update_icon() if(istype(I, /obj/item/tcgcard_deck)) var/obj/item/tcgcard_deck/old_deck = I @@ -278,6 +277,8 @@ card_count = 9 guaranteed_count = 3 + illegal = TRUE + guar_rarity = list( //Better chances "Legendary" = 5, "Epic" = 10, @@ -305,7 +306,7 @@ if(prob(contains_coin)) to_chat(user, "...and it came with a flipper, too!") new /obj/item/coin/thunderdome(get_turf(user)) - new /obj/item/tcg_rules(get_turf(user)) + new /obj/item/paper/tcg_rules(get_turf(user)) qdel(src) /obj/item/cardpack/proc/buildCardListWithRarity(card_cnt, rarity_cnt) @@ -385,11 +386,11 @@ if(flipped) switch(contents.len) if(1 to 10) - icon_state = "deck_tcg_low" + icon_state = "deck_low" if(11 to 20) - icon_state = "deck_tcg_half" + icon_state = "deck_half" if(21 to INFINITY) - icon_state = "deck_tcg_full" + icon_state = "deck_full" else icon_state = "deck_up" @@ -440,6 +441,15 @@ new_card.flipped = flipped new_card.forceMove(src) + if(istype(I, /obj/item/tcgcard_hand)) + var/obj/item/tcgcard_hand/hand = I + for(var/obj/item/tcg_card/card in hand.cards) + if(contents.len > 30) + return FALSE + card.flipped = flipped + card.forceMove(src) + hand.cards.Remove(card) + /obj/item/tcgcard_deck/attack_self(mob/living/carbon/user) shuffle_deck(user) return ..() @@ -525,6 +535,14 @@ return . = ..() +/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) + /obj/item/tcgcard_binder name = "Trading Card Binder" desc = "A TCG-branded card binder, specifically for your infinite collection of TCG cards!" @@ -532,50 +550,90 @@ icon_state = "binder" var/list/cards = list() - var/mode = 0 //If 1, will show all the cards even if you don't have em + var/list/decks = list() + var/mode = 0 //If 1, will show all the cards even if you don't have em. If 2, will show your decks /obj/item/tcgcard_binder/attackby(obj/item/I, mob/living/user, params) if(istype(I, /obj/item/tcg_card)) var/obj/item/tcg_card/card = I card.forceMove(src) cards.Add(card) + if(istype(I, /obj/item/tcgcard_hand)) + var/obj/item/tcgcard_hand/hand = I + for(var/obj/item/tcg_card/card in hand.cards) + card.forceMove(src) + cards.Add(card) + qdel(I) + if(istype(I, /obj/item/tcgcard_deck)) + var/obj/item/tcgcard_deck/deck = I + var/named = input(user, "How will this deck be named? Leave this field empty if you don't want to save this deck.") + if(named) + decks[named] = list() + for(var/obj/item/tcg_card/card in deck.contents) + card.forceMove(src) + cards.Add(card) + if(named) + decks[named] += card.name + qdel(I) . = ..() /obj/item/tcgcard_binder/attack_self(mob/living/carbon/user) - mode = !mode - to_chat(user, "[src] now shows you [mode ? "all the different cards" : "the cards you already have"].") + mode = (mode + 1) % 3 + switch(mode) + if(0) + to_chat(user, "[src] now shows you the cards you already have.") + if(1) + to_chat(user, "[src] now shows you all the different cards.") + if(2) + to_chat(user, "[src] now shows you your deck menu.") /obj/item/tcgcard_binder/attack_hand(mob/living/carbon/user) if(loc == user) var/list/choices = list() - if(mode) - var/card_types = list() + switch(mode) + if(1) + var/card_types = list() - for(var/obj/item/tcg_card/card in cards) - card_types[card.datum_type] = card + for(var/obj/item/tcg_card/card in cards) + card_types[card.datum_type] = card - for(var/card_type in subtypesof(/datum/tcg_card)) - if(card_type in card_types) - var/obj/item/tcg_card/card = card_types[card_type] + for(var/card_type in subtypesof(/datum/tcg_card)) + if(card_type in card_types) + var/obj/item/tcg_card/card = card_types[card_type] + choices[card] = image(icon = card.icon, icon_state = card.icon_state) + continue + + var/datum/tcg_card/card_dat = new card_type + if(card_dat.name == "Stupid Coder") + continue + var/image/I = image(icon = card_dat.pack, icon_state = card_dat.icon_state) + I.color = "#999999" + choices[card_dat.name] = I + qdel(card_dat) + if(0) + for(var/obj/item/tcg_card/card in cards) choices[card] = image(icon = card.icon, icon_state = card.icon_state) - continue - var/datum/tcg_card/card_dat = new card_type - if(card_dat.name == "Stupid Coder") - continue - var/image/I = image(icon = card_dat.pack, icon_state = card_dat.icon_state) - I.color = "#999999" - choices[card_dat.name] = I - qdel(card_dat) - else - for(var/obj/item/tcg_card/card in cards) - choices[card] = image(icon = card.icon, icon_state = card.icon_state) + if(2) + for(var/deck in decks) + choices[deck] = image(icon = 'icons/obj/tcg/misc.dmi', icon_state = "deck_up") + var/obj/item/tcg_card/choice = show_radial_menu(user, src, choices, require_near = TRUE, tooltips = TRUE) if(choice && (choice in cards)) choice.forceMove(get_turf(src)) user.put_in_hands(choice) cards.Remove(choice) + if(choice && (choice in decks)) + var/obj/item/tcgcard_deck/new_deck = new(get_turf(user)) + var/list/required_cards = decks[choice] + for(var/obj/item/tcg_card/card in cards) + if(card.name in required_cards) + required_cards.Remove(card.name) + cards.Remove(card) + card.forceMove(new_deck) + user.put_in_hands(new_deck) + if(choice) return . = ..() @@ -612,59 +670,73 @@ card.forceMove(src) cards.Add(card) -/obj/item/tcg_rules +/obj/item/paper/tcg_rules name = "TCG Rulebook" desc = "A small rulebook containing a starter guide for TCG." icon = 'icons/obj/tcg/misc.dmi' icon_state = "deck_low" w_class = WEIGHT_CLASS_TINY -/obj/item/tcg_rules/examine(mob/user) - . = ..() - . += "*---------* \n\ + info = "*---------* \n\ Welcome to the Exciting world of Tactical Card Game! Sponsored by Nanotrasen Edu-tainment Devision. \n \ Core Rules: \n \ +
\n \ Tactical Card Game (Also known as TCG) is a traditional trading card game. It's played between two players, each with a deck or collection of cards. \n \ +
\n \ Each player's deck contains up to 30 cards. Each player's hand can hold a maximum of 7 cards. At the end of your turn, if you have more than 7 cards, you must choose cards to discard to your discard pile until you have 7 cards. \n \ To begin a match, both players must flip a coin to decide who goes first. The winner of the coin toss then decides if they go first or second. Before the match begins each player draws 5 cards each with the ability to mulligan cards from their hand facedown once (Basically, you get a first pass where you can replace cards in your hands back into your deck, shuffle your deck, then draw until you're back to 5). \n \ Each player begins with 1 Max Mana to start with, which serves as the cost to playing cards. \n \ +
\n \ In order to play the TCG, a deck is required. As stated above, decks must contain up to 30 cards. \n \ Additionally, to save cards you need to have a card binder on yourself to store the cards. When the shift ends, your cards will be automatically saved by integrated scanners in your card binder. \n \ Finally, a stock of Thunderdome Flippers to use for coin tosses and counter effects is recommended- these can be obtained occasionally from cardpacks, but any coin will do. \n \ +
\n \ Win condition is simple - kill your opponent's hero by depleting all of their 20 lifeshards. \n \ +
\n \ Gameplay Phases: \n \ +
\n \ A single turn of the game goes as follows, and the order of card effects is very similar to other card games. Within a single turn, the following phases are gone through, in order, unless otherwise altered by a card effect. Turn Phases are the Draw Phase, Effect Phase 1, Play Phase, Combat Phase, Effect Phase 2, and the End Phase. \n \ +
\n \ During the draw phase, the player whose turn it is untaps all their cards, then draws a single card. They gain 1 Max Mana, and their Mana is refilled. Cards with missing health due to defending, attacking, or damage effects return to max health at the end of the draw phase. \n \ During the First Effect Phase, this is when effects that take place at the start of your turn would occur. If an opponent's effect takes place at the start of your turn, their effects will always take place first, then yours, unless otherwise stated by a card effect. If an opponent's effect would cause you to lose the game, and your effects would prevent that condition from happening afterwards, you would lose the game. As a general roll, when it's your turn, your opponent's effects take place FIRST, then yours. \n \ +
\n \ During the Play Phase, this is when you can play, summon, or activate your own cards. Card Effects that don't state when they're activated MUST be activated during the Play Phase. Your opponent can also activate their own card effects in response to one of your actions during your play phase, if able. Any card played during the play phase can activate its effect as soon as it's played. More details within the Card Breakdown section. \n \ +
\n \ During the Battle Phase, a Unit Card is able to battle other Unit Cards, or attack their opponent once per turn. Neither player can attack on their first turn, and all cards that enter the field can attack as soon as they can, unless it is that player's first turn, or they are prevented by a card effect. More details within the Card Combat section. \n \ +
\n \ During the End Phase, end of turn effects will occur. If the active player has more than 7 cards in their hand by this point, this is when they must discard cards. All of the player's cards who used an effect at any point in the turn are refreshed, and able to use their effect again going into the opponent's turn. By the end of their turn, if the player has more than 7 cards, they must discard cards from their hand until 7 remain. \n \ After all 5 phases have passed, the players turn officially ends, and the opponent begins their turn, starting anew from the draw phase. \n \ +
\n \ Card effects are typically limited to the turn that that card is played. For example, a card effect that provides a card +1/+1 attack/health would only last until the end of the turn, unless otherwise stated, OR if the card is an Equipment Card. More on those below. \n \ +
\n \ Card Breakdown: \n \ +
\n \ Within the game, there are 3 kinds of cards (So far), Unit, Equipment and Spell cards. \n \ +
\n \ Unit Cards. All Unit Cards have 4 core values to keep in mind, Attack, Health, Faction, and Summoning Cost. Attack serves as a card's offensive value in combat. Health serves as a card's defensive value in combat, and doubles as a card's health. Factions are groupings of cards that can often share effects and traits together. Summoning Cost is how much mana a card needs in order to be summoned. \n \ +
\n \ Equipment Cards. All Equipment Cards similarly to Unit Cards have Attack, Health, and Summon Cost values, but for equipment, these values are added to the attached card's values. Equipment can only be attached (Equip) to units, and they last until the unit dies, or otherwise leaves the field, following it's equipt card. If returned to the hand, send to the discard pile, or otherwise leaves the field, it is detatched from the equipt card. When a Equipment Card increases a card's attack or health, those effects stay on the equip card until the equipment is unequip or removed from the parent card. \n \ If a card would have it's health decreased by having it's equip card removed, it's handled by having it's maximum health decreased, not it's current health. For example, lets say you had a card with 1/1 attack/health, and give it an equipment giving it +1/+2, then that card enters combat, dropping it down to 2/1. If by an opponent's card effect it lost that +1/+2 equipment now, it's stats would be 1/1 once again. If an equip card explicitly lowers a card's stats, it is possible for a card to be killed as a result, but drops in attack will always bottom out at 0 attack at any given time. \n \ +
\n \ Spell Cards. Spell Cards don't have attack or health values, instead, they activate their effects as soon as they are summoned and leave the field afterwards(if not stated otherwise). \n \ - +
\n \ Card Subtypes: \n \ - +
\n \ Card effects: \n \ Asimov - Unit cannot attack units with Human subtype \n \ Changeling - Unit posesses all the subtypes at the same time \n \ @@ -679,13 +751,13 @@ Blocker - The unit cannot declare attacks, but can defend. \n \ Hivemind - The unit enters combat with a hivemind token on it. The first time this card would take damage, remove that token instead. This does not apply to instant removal effects, only points of damage. \n \ Clockwork - The unit can copy a single keyword on another unit on the field, until they lose the clockwork keyword or leave the field. \n \ - +
\n \ Card Combat: \n \ - +
\n \ Card combat is determined as follows. On your turn, any non-tapped unit card with a positive attack power is capable of declaring an attack. Upon declaring an attack, you must state if you're attacking your opponent directly, or if you're going to attack a specific opponent's unit. Unless otherwise stated, cards can only attack or defend one time per turn. \n \ - +
\n \ An attack against a unit healths as follows: Both units will do their power as damage to the opponent's unit's health. Damage is typically dealt at the same time, and if both units would kill each other through combat, both are destroyed at the same time. If One or both units would not be destroyed by combat, they would have their health reduced by the difference of their health minus their opponent's power, until the start of your next turn. If the attacker or defender has a keyword or effect that prevents them from attacking their opponent (Like silicon, immunity), then they are not able to attack, but may still defend against the opponent's attack. Once combat has healthd, all remaining participants become tapped. \n \ - +
\n \ A direct attack healths as follows: The attacking unit declares an attack against the opponent's lifeshards. Your opponent may then declare a defender if one is available, who will then turn the combat into an attack against a unit for the purposes of combat that turn. If the attack is not blocked, and the direct attack connects, then your opponent loses a number of lifeshards equal to the attacking units power.
" /obj/item/cardboard_card @@ -709,6 +781,27 @@ . = ..() +/mob/living/carbon/human/proc/SaveTCGCards() + if(!client) + return + + var/obj/item/tcgcard_binder/binder = locate() in src + if(!binder) + var/obj/item/storage/backpack/back = locate() in src + binder = locate() in back + + if(!binder) + return + + var/list/card_types = list() + for(var/obj/item/tcg_card/card in binder.cards) + //if(!card.illegal) //Uncomment if you want to block syndie cards from saving + card_types[card.datum_type] = card.illegal + + client.prefs.tcg_decks = binder.decks + client.prefs.tcg_cards = card_types + client.prefs.save_character(TRUE) + #undef COMMON_SERIES #undef TAPPED_ANGLE #undef UNTAPPED_ANGLE diff --git a/html/changelog.html b/html/changelog.html index bdc642c889..55982e0efe 100644 --- a/html/changelog.html +++ b/html/changelog.html @@ -50,6 +50,49 @@ -->
+

21 February 2021

+

Hatterhat updated:

+
    +
  • Anomaly announcements and brand intelligence now always announce instead of having some ham-fisted chance of being a command report.
  • +
+

IronEleven updated:

+
    +
  • Raises Space Vine Population Requirement from 10 to 20
  • +
+

MrJWhit updated:

+
    +
  • Removes an unnecessary % on the seed extractor.
  • +
+

timothyteakettle updated:

+
    +
  • the query for checking mentors now gets properly deleted
  • +
  • vampires no longer burn in the chapel if they signed up as the chaplain
  • +
+ +

20 February 2021

+

Adelphon updated:

+
    +
  • polychromic pants
  • +
  • urban coat made polychromic
  • +
+

Chiirno updated:

+
    +
  • Synthflesh now unhusks with 100u instead of requiring 101u.
  • +
+

SmArtKar updated:

+
    +
  • Added some QoL changes to TCG
  • +
  • Fixed TCG cards not saving
  • +
+

TyrianTyrell updated:

+
    +
  • fixed the signed language so that you can actually use it, and that it's unusable when it's meant to be.
  • +
+

timothyteakettle updated:

+
    +
  • stops people using Message All on PDAs when their cartridge doesn't allow it
  • +
+

19 February 2021

Putnam3145 updated:

    diff --git a/html/changelogs/.all_changelog.yml b/html/changelogs/.all_changelog.yml index 4d9876efec..b7654e8973 100644 --- a/html/changelogs/.all_changelog.yml +++ b/html/changelogs/.all_changelog.yml @@ -28522,3 +28522,29 @@ DO NOT EDIT THIS FILE BY HAND! AUTOMATICALLY GENERATED BY ss13_genchangelog.py. - bugfix: Buzz Fuzz's addiction threshold is now a can and a sip as intended. timothyteakettle: - admin: staring into pierced realities is now logged +2021-02-20: + Adelphon: + - rscadd: polychromic pants + - tweak: urban coat made polychromic + Chiirno: + - tweak: Synthflesh now unhusks with 100u instead of requiring 101u. + SmArtKar: + - tweak: Added some QoL changes to TCG + - bugfix: Fixed TCG cards not saving + TyrianTyrell: + - bugfix: fixed the signed language so that you can actually use it, and that it's + unusable when it's meant to be. + timothyteakettle: + - bugfix: stops people using Message All on PDAs when their cartridge doesn't allow + it +2021-02-21: + Hatterhat: + - balance: Anomaly announcements and brand intelligence now always announce instead + of having some ham-fisted chance of being a command report. + IronEleven: + - balance: Raises Space Vine Population Requirement from 10 to 20 + MrJWhit: + - tweak: Removes an unnecessary % on the seed extractor. + timothyteakettle: + - bugfix: the query for checking mentors now gets properly deleted + - rscadd: vampires no longer burn in the chapel if they signed up as the chaplain diff --git a/html/changelogs/AutoChangeLog-pr-14256.yml b/html/changelogs/AutoChangeLog-pr-14256.yml deleted file mode 100644 index 2515417160..0000000000 --- a/html/changelogs/AutoChangeLog-pr-14256.yml +++ /dev/null @@ -1,5 +0,0 @@ -author: "Adelphon" -delete-after: True -changes: - - rscadd: "polychromic pants" - - tweak: "urban coat made polychromic" diff --git a/modular_citadel/code/modules/mentor/mentor.dm b/modular_citadel/code/modules/mentor/mentor.dm index fc9f9a6b63..47527521c4 100644 --- a/modular_citadel/code/modules/mentor/mentor.dm +++ b/modular_citadel/code/modules/mentor/mentor.dm @@ -80,10 +80,12 @@ GLOBAL_PROTECT(mentor_href_token) return var/datum/db_query/query_load_mentors = SSdbcore.NewQuery("SELECT ckey FROM [format_table_name("mentor")]") if(!query_load_mentors.Execute()) + qdel(query_load_mentors) return while(query_load_mentors.NextRow()) var/ckey = ckey(query_load_mentors.item[1]) new /datum/mentors(ckey) + qdel(query_load_mentors) // new client var: mentor_datum. Acts the same way holder does towards admin: it holds the mentor datum. if set, the guy's a mentor. /client