diff --git a/_maps/RandomRuins/AnywhereRuins/golem_ship.dmm b/_maps/RandomRuins/AnywhereRuins/golem_ship.dmm index 274c814cf5..e20fa042d7 100644 --- a/_maps/RandomRuins/AnywhereRuins/golem_ship.dmm +++ b/_maps/RandomRuins/AnywhereRuins/golem_ship.dmm @@ -139,6 +139,7 @@ dir = 4; name = "shrine of the liberator" }, +/obj/item/tcg_card/special/golem, /turf/open/floor/mineral/titanium/purple, /area/ruin/powered/golem_ship) "v" = ( diff --git a/_maps/RandomRuins/IceRuins/icemoon_surface_hotsprings.dmm b/_maps/RandomRuins/IceRuins/icemoon_surface_hotsprings.dmm index 93b221c446..a32c526ec4 100644 --- a/_maps/RandomRuins/IceRuins/icemoon_surface_hotsprings.dmm +++ b/_maps/RandomRuins/IceRuins/icemoon_surface_hotsprings.dmm @@ -14,6 +14,10 @@ }, /turf/open/floor/plating/beach/sand, /area/icemoon/surface/outdoors) +"l" = ( +/obj/item/tcg_card/special/morph, +/turf/open/floor/plating/beach/sand, +/area/icemoon/surface/outdoors) "I" = ( /turf/closed/indestructible/fakeglass, /area/icemoon/surface/outdoors) @@ -72,7 +76,7 @@ L c c c -U +l U a b diff --git a/_maps/RandomRuins/IceRuins/icemoon_surface_lust.dmm b/_maps/RandomRuins/IceRuins/icemoon_surface_lust.dmm index 704ac63a7d..7a41256478 100644 --- a/_maps/RandomRuins/IceRuins/icemoon_surface_lust.dmm +++ b/_maps/RandomRuins/IceRuins/icemoon_surface_lust.dmm @@ -20,6 +20,10 @@ }, /turf/open/floor/mineral/diamond, /area/icemoon/surface/outdoors) +"f" = ( +/obj/item/tcg_card/special/xenomaid, +/turf/open/floor/mineral/diamond, +/area/icemoon/surface/outdoors) (1,1,1) = {" a @@ -65,7 +69,7 @@ a a a b -c +f c c b diff --git a/_maps/RandomRuins/IceRuins/icemoon_surface_mining_site.dmm b/_maps/RandomRuins/IceRuins/icemoon_surface_mining_site.dmm index 23abc4b731..9ea8747846 100644 --- a/_maps/RandomRuins/IceRuins/icemoon_surface_mining_site.dmm +++ b/_maps/RandomRuins/IceRuins/icemoon_surface_mining_site.dmm @@ -49,6 +49,7 @@ /area/ruin/unpowered) "k" = ( /obj/structure/closet/crate/freezer, +/obj/item/tcg_card/special/demonic_miner, /turf/open/floor/wood, /area/ruin/unpowered) "l" = ( diff --git a/_maps/RandomRuins/IceRuins/icemoon_underground_wendigo_cave.dmm b/_maps/RandomRuins/IceRuins/icemoon_underground_wendigo_cave.dmm index a383c2e8c4..5861309eff 100644 --- a/_maps/RandomRuins/IceRuins/icemoon_underground_wendigo_cave.dmm +++ b/_maps/RandomRuins/IceRuins/icemoon_underground_wendigo_cave.dmm @@ -31,6 +31,10 @@ "N" = ( /turf/open/indestructible/necropolis/ice, /area/icemoon/underground/explored) +"S" = ( +/obj/item/tcg_card/special/wendigo, +/turf/open/indestructible/necropolis/ice, +/area/icemoon/underground/explored) "U" = ( /obj/item/paper/crumpled/bloody{ info = "for your own sake, do not enter" @@ -451,7 +455,7 @@ a N N N -N +S N N N diff --git a/_maps/RandomRuins/LavaRuins/lavaland_biodome_clown_planet.dmm b/_maps/RandomRuins/LavaRuins/lavaland_biodome_clown_planet.dmm index 639d63772c..cd512e44b6 100644 --- a/_maps/RandomRuins/LavaRuins/lavaland_biodome_clown_planet.dmm +++ b/_maps/RandomRuins/LavaRuins/lavaland_biodome_clown_planet.dmm @@ -862,6 +862,7 @@ /obj/structure/disposalpipe/segment{ dir = 10 }, +/obj/item/tcg_card/special/honk, /turf/open/floor/plating, /area/ruin/powered/clownplanet) "bF" = ( diff --git a/_maps/RandomRuins/LavaRuins/lavaland_surface_dead_ratvar.dmm b/_maps/RandomRuins/LavaRuins/lavaland_surface_dead_ratvar.dmm index d8713fd40a..134a692e41 100644 --- a/_maps/RandomRuins/LavaRuins/lavaland_surface_dead_ratvar.dmm +++ b/_maps/RandomRuins/LavaRuins/lavaland_surface_dead_ratvar.dmm @@ -155,6 +155,12 @@ /obj/item/stack/tile/brass/fifty, /turf/open/floor/plating/asteroid/basalt/lava_land_surface, /area/lavaland/surface/outdoors/unexplored) +"Y" = ( +/obj/item/tcg_card/special/ratvar, +/turf/open/floor/clockwork{ + initial_gas_mix = "o2=14;n2=23;TEMP=300" + }, +/area/lavaland/surface/outdoors/unexplored) (1,1,1) = {" a @@ -484,7 +490,7 @@ h h h h -h +Y h l l @@ -709,7 +715,7 @@ b l l b -h +Y h t b diff --git a/_maps/RandomRuins/LavaRuins/lavaland_surface_hierophant.dmm b/_maps/RandomRuins/LavaRuins/lavaland_surface_hierophant.dmm index cad120c3f2..c307c2caae 100644 --- a/_maps/RandomRuins/LavaRuins/lavaland_surface_hierophant.dmm +++ b/_maps/RandomRuins/LavaRuins/lavaland_surface_hierophant.dmm @@ -26,6 +26,10 @@ }, /turf/open/indestructible/hierophant/two, /area/ruin/unpowered/hierophant) +"s" = ( +/obj/item/tcg_card/special/hierophant, +/turf/open/indestructible/hierophant, +/area/ruin/unpowered/hierophant) (1,1,1) = {" a @@ -494,7 +498,7 @@ b b b c -b +s a a b diff --git a/_maps/RandomRuins/LavaRuins/lavaland_surface_ufo_crash.dmm b/_maps/RandomRuins/LavaRuins/lavaland_surface_ufo_crash.dmm index f4c8c7ea0e..7ac6d32b80 100644 --- a/_maps/RandomRuins/LavaRuins/lavaland_surface_ufo_crash.dmm +++ b/_maps/RandomRuins/LavaRuins/lavaland_surface_ufo_crash.dmm @@ -11,6 +11,13 @@ "d" = ( /turf/closed/wall/mineral/abductor, /area/ruin/unpowered) +"h" = ( +/obj/structure/closet/abductor, +/obj/item/tcg_card/special/abductor, +/turf/open/floor/plating/abductor{ + initial_gas_mix = "o2=14;n2=23;TEMP=300" + }, +/area/ruin/unpowered) "j" = ( /obj/machinery/abductor/experiment{ team_number = 100 @@ -188,7 +195,7 @@ a a c d -q +h t q d diff --git a/_maps/RandomRuins/SpaceRuins/abandonedzoo.dmm b/_maps/RandomRuins/SpaceRuins/abandonedzoo.dmm index d83b4cf2c3..d4b0e65f2d 100644 --- a/_maps/RandomRuins/SpaceRuins/abandonedzoo.dmm +++ b/_maps/RandomRuins/SpaceRuins/abandonedzoo.dmm @@ -567,6 +567,7 @@ "bm" = ( /obj/structure/closet/wardrobe/science_white, /obj/structure/disposalpipe/segment, +/obj/item/tcg_card/special/space_carp, /turf/open/floor/plasteel{ icon_state = "dark" }, diff --git a/_maps/RandomRuins/SpaceRuins/caravanambush.dmm b/_maps/RandomRuins/SpaceRuins/caravanambush.dmm index a1171400e6..bba36470dd 100644 --- a/_maps/RandomRuins/SpaceRuins/caravanambush.dmm +++ b/_maps/RandomRuins/SpaceRuins/caravanambush.dmm @@ -16,8 +16,8 @@ /area/template_noop) "ae" = ( /obj/structure/fluff/broken_flooring{ - icon_state = "plating"; - dir = 4 + dir = 4; + icon_state = "plating" }, /turf/template_noop, /area/template_noop) @@ -66,8 +66,8 @@ "an" = ( /obj/structure/lattice, /obj/structure/fluff/broken_flooring{ - icon_state = "plating"; - dir = 4 + dir = 4; + icon_state = "plating" }, /turf/template_noop, /area/template_noop) @@ -78,8 +78,8 @@ "ap" = ( /obj/structure/lattice, /obj/structure/fluff/broken_flooring{ - icon_state = "pile"; - dir = 8 + dir = 8; + icon_state = "pile" }, /turf/template_noop, /area/template_noop) @@ -133,8 +133,8 @@ /area/template_noop) "aE" = ( /obj/structure/fluff/broken_flooring{ - icon_state = "pile"; - dir = 4 + dir = 4; + icon_state = "pile" }, /turf/template_noop, /area/template_noop) @@ -1054,6 +1054,7 @@ /obj/effect/decal/cleanable/dirt, /obj/structure/closet/crate/secure/weapon, /obj/item/gun/ballistic/automatic/pistol/APS, +/obj/item/tcg_card/special/spess_pirate, /turf/open/floor/plasteel/airless/dark, /area/shuttle/caravan/freighter2) "js" = ( diff --git a/_maps/RandomRuins/SpaceRuins/gondolaasteroid.dmm b/_maps/RandomRuins/SpaceRuins/gondolaasteroid.dmm index e3b105d06e..ab5086e534 100644 --- a/_maps/RandomRuins/SpaceRuins/gondolaasteroid.dmm +++ b/_maps/RandomRuins/SpaceRuins/gondolaasteroid.dmm @@ -91,6 +91,10 @@ }, /turf/open/floor/plating/asteroid/airless, /area/ruin/space/has_grav) +"Y" = ( +/obj/item/tcg_card/special/gondola, +/turf/open/floor/plating/asteroid/airless, +/area/ruin/space/has_grav) (1,1,1) = {" a @@ -339,7 +343,7 @@ b c c c -c +Y o c r diff --git a/_maps/RandomRuins/SpaceRuins/mechtransport.dmm b/_maps/RandomRuins/SpaceRuins/mechtransport.dmm index 6e35de07be..a9beb9540e 100644 --- a/_maps/RandomRuins/SpaceRuins/mechtransport.dmm +++ b/_maps/RandomRuins/SpaceRuins/mechtransport.dmm @@ -19,6 +19,7 @@ /area/ruin/space/has_grav/powered/mechtransport) "g" = ( /obj/structure/closet/crate/secure/loot, +/obj/item/tcg_card/special/phazon, /turf/open/floor/mineral/titanium/blue, /area/ruin/space/has_grav/powered/mechtransport) "h" = ( diff --git a/code/__DEFINES/language.dm b/code/__DEFINES/language.dm index add4a8e277..798ea478c2 100644 --- a/code/__DEFINES/language.dm +++ b/code/__DEFINES/language.dm @@ -24,3 +24,4 @@ #define LANGUAGE_STONER "stoner" #define LANGUAGE_VASSAL "vassal" #define LANGUAGE_VOICECHANGE "voicechange" +#define LANGUAGE_MULTILINGUAL "multilingual" diff --git a/code/__DEFINES/robots.dm b/code/__DEFINES/robots.dm index a0fded3798..dda9cfd430 100644 --- a/code/__DEFINES/robots.dm +++ b/code/__DEFINES/robots.dm @@ -69,8 +69,8 @@ //Checks to determine borg availability depending on the server's config. These are defines in the interest of reducing copypasta #define BORG_SEC_AVAILABLE (!CONFIG_GET(flag/disable_secborg) && GLOB.security_level >= CONFIG_GET(number/minimum_secborg_alert)) -//silicon_priviledges flags -#define PRIVILEDGES_SILICON (1<<0) -#define PRIVILEDGES_PAI (1<<1) -#define PRIVILEDGES_BOT (1<<2) -#define PRIVILEDGES_DRONE (1<<3) +//silicon_privileges flags +#define PRIVILEGES_SILICON (1<<0) +#define PRIVILEGES_PAI (1<<1) +#define PRIVILEGES_BOT (1<<2) +#define PRIVILEGES_DRONE (1<<3) diff --git a/code/__DEFINES/subsystems.dm b/code/__DEFINES/subsystems.dm index cbf701e1d3..e84f6eb50b 100644 --- a/code/__DEFINES/subsystems.dm +++ b/code/__DEFINES/subsystems.dm @@ -204,7 +204,7 @@ ///Compile all the overlays for an atom from the cache lists // |= on overlays is not actually guaranteed to not add same appearances but we're optimistically using it anyway. #define COMPILE_OVERLAYS(A)\ - if (TRUE) {\ + do {\ var/list/ad = A.add_overlays;\ var/list/rm = A.remove_overlays;\ if(LAZYLEN(rm)){\ @@ -216,7 +216,7 @@ ad.Cut();\ }\ A.flags_1 &= ~OVERLAY_QUEUED_1;\ - } + } while(FALSE) /** diff --git a/code/__HELPERS/_lists.dm b/code/__HELPERS/_lists.dm index a59ee9fcb0..a554397c41 100644 --- a/code/__HELPERS/_lists.dm +++ b/code/__HELPERS/_lists.dm @@ -66,7 +66,7 @@ } while(FALSE) //Returns a list in plain english as a string -/proc/english_list(list/input, nothing_text = "nothing", and_text = " and ", comma_text = ", ", final_comma_text = "" ) +/proc/english_list(list/input, nothing_text = "nothing", and_text = " and ", comma_text = ", ", final_comma_text = "") var/total = length(input) switch(total) if (0) @@ -87,6 +87,34 @@ return "[output][and_text][input[index]]" +/** + * English_list but associative supporting. Higher overhead. + */ +/proc/english_list_assoc(list/input, nothing_text = "nothing", and_text = " and ", comma_text = ", ", final_comma_text = "") + var/total = length(input) + switch(total) + if (0) + return "[nothing_text]" + if (1) + var/assoc = input[input[1]] == null? "" : " = [input[input[1]]]" + return "[input[1]][assoc]" + if (2) + var/assoc = input[input[1]] == null? "" : " = [input[input[1]]]" + var/assoc2 = input[input[2]] == null? "" : " = [input[input[2]]]" + return "[input[1]][assoc][and_text][input[2]][assoc2]" + else + var/output = "" + var/index = 1 + var/assoc + while (index < total) + if (index == total - 1) + comma_text = final_comma_text + assoc = input[input[index]] == null? "" : " = [input[input[index]]]" + output += "[input[index]][assoc][comma_text]" + ++index + assoc = input[input[index]] == null? "" : " = [input[input[index]]]" + return "[output][and_text][input[index]]" + //Returns list element or null. Should prevent "index out of bounds" error. /proc/listgetindex(list/L, index) if(LAZYLEN(L)) diff --git a/code/__HELPERS/_logging.dm b/code/__HELPERS/_logging.dm index 18d02229dd..8464e373d5 100644 --- a/code/__HELPERS/_logging.dm +++ b/code/__HELPERS/_logging.dm @@ -231,10 +231,10 @@ src_object = window.locked_by.src_object // Insert src_object info if(src_object) - entry += "\nUsing: [src_object.type] [REF(src_object)]" + entry += "Using: [src_object.type] [REF(src_object)]" // Insert message if(message) - entry += "\n[message]" + entry += "[message]" WRITE_LOG(GLOB.tgui_log, entry) /* Close open log handles. This should be called as late as possible, and no logging should hapen after. */ diff --git a/code/_onclick/hud/human.dm b/code/_onclick/hud/human.dm index 04141becf2..841a3e8303 100644 --- a/code/_onclick/hud/human.dm +++ b/code/_onclick/hud/human.dm @@ -118,27 +118,7 @@ action_intent.hud = src static_inventory += action_intent - using = new /obj/screen/mov_intent - using.icon = tg_ui_icon_to_cit_ui(ui_style) // CIT CHANGE - overrides mov intent icon - using.icon_state = (mymob.m_intent == MOVE_INTENT_RUN ? "running" : "walking") - using.screen_loc = ui_movi - using.hud = src - static_inventory += using - - //CITADEL CHANGES - sprint button - using = new /obj/screen/sprintbutton - using.icon = tg_ui_icon_to_cit_ui(ui_style) - using.icon_state = ((owner.combat_flags & COMBAT_FLAG_SPRINT_ACTIVE) ? "act_sprint_on" : "act_sprint") - using.screen_loc = ui_movi - using.hud = src - static_inventory += using - //END OF CITADEL CHANGES - - //same as above but buffer. - sprint_buffer = new /obj/screen/sprint_buffer - sprint_buffer.screen_loc = ui_sprintbufferloc - sprint_buffer.hud = src - static_inventory += sprint_buffer + assert_move_intent_ui(owner, TRUE) // clickdelay clickdelay = new @@ -393,6 +373,51 @@ update_locked_slots() +/datum/hud/human/proc/assert_move_intent_ui(mob/living/carbon/human/owner = mymob, on_new = FALSE) + var/obj/screen/using + // delete old ones + var/list/obj/screen/victims = list() + victims += locate(/obj/screen/mov_intent) in static_inventory + victims += locate(/obj/screen/sprintbutton) in static_inventory + victims += locate(/obj/screen/sprint_buffer) in static_inventory + if(victims) + static_inventory -= victims + if(mymob?.client) + mymob.client.screen -= victims + QDEL_LIST(victims) + + // make new ones + // walk/run + using = new /obj/screen/mov_intent + using.icon = tg_ui_icon_to_cit_ui(ui_style) // CIT CHANGE - overrides mov intent icon + using.screen_loc = ui_movi + using.hud = src + using.update_icon() + static_inventory += using + if(!on_new) + owner?.client?.screen += using + + if(!CONFIG_GET(flag/sprint_enabled)) + return + + // sprint button + using = new /obj/screen/sprintbutton + using.icon = tg_ui_icon_to_cit_ui(ui_style) + using.icon_state = ((owner.combat_flags & COMBAT_FLAG_SPRINT_ACTIVE) ? "act_sprint_on" : "act_sprint") + using.screen_loc = ui_movi + using.hud = src + static_inventory += using + if(!on_new) + owner?.client?.screen += using + + // same as above but buffer. + sprint_buffer = new /obj/screen/sprint_buffer + sprint_buffer.screen_loc = ui_sprintbufferloc + sprint_buffer.hud = src + static_inventory += sprint_buffer + if(!on_new) + owner?.client?.screen += using + /datum/hud/human/update_locked_slots() if(!mymob) return diff --git a/code/_onclick/hud/screen_objects.dm b/code/_onclick/hud/screen_objects.dm index 53915ff42b..64515260ec 100644 --- a/code/_onclick/hud/screen_objects.dm +++ b/code/_onclick/hud/screen_objects.dm @@ -351,6 +351,10 @@ icon = 'icons/mob/screen_midnight.dmi' icon_state = "running" +/obj/screen/mov_intent/Initialize(mapload) + . = ..() + update_icon() + /obj/screen/mov_intent/Click() toggle(usr) @@ -359,7 +363,7 @@ if(MOVE_INTENT_WALK) icon_state = "walking" if(MOVE_INTENT_RUN) - icon_state = "running" + icon_state = CONFIG_GET(flag/sprint_enabled)? "running" : "running_nosprint" /obj/screen/mov_intent/proc/toggle(mob/user) if(isobserver(user)) diff --git a/code/controllers/configuration/entries/game_options.dm b/code/controllers/configuration/entries/game_options.dm index e9f759fd42..4034722417 100644 --- a/code/controllers/configuration/entries/game_options.dm +++ b/code/controllers/configuration/entries/game_options.dm @@ -290,6 +290,17 @@ var/datum/movespeed_modifier/config_walk_run/M = get_cached_movespeed_modifier(/datum/movespeed_modifier/config_walk_run/walk) M.sync() +/datum/config_entry/flag/sprint_enabled + config_entry_value = TRUE + +/datum/config_entry/flag/sprint_enabled/ValidateAndSet(str_val) + . = ..() + for(var/datum/hud/human/H) + H.assert_move_intent_ui() + if(!config_entry_value) // disabled + for(var/mob/living/L in world) + L.disable_intentional_sprint_mode() + /datum/config_entry/number/movedelay/sprint_speed_increase config_entry_value = 1 diff --git a/code/controllers/configuration/entries/general.dm b/code/controllers/configuration/entries/general.dm index 3c93952b65..4d985c7234 100644 --- a/code/controllers/configuration/entries/general.dm +++ b/code/controllers/configuration/entries/general.dm @@ -26,50 +26,6 @@ /datum/config_entry/flag/hub // if the game appears on the hub or not -/datum/config_entry/flag/log_ooc // log OOC channel - -/datum/config_entry/flag/log_access // log login/logout - -/datum/config_entry/flag/log_say // log client say - -/datum/config_entry/flag/log_admin // log admin actions - protection = CONFIG_ENTRY_LOCKED - -/datum/config_entry/flag/log_prayer // log prayers - -/datum/config_entry/flag/log_law // log lawchanges - -/datum/config_entry/flag/log_game // log game events - -/datum/config_entry/flag/log_virus // log virology data - -/datum/config_entry/flag/log_vote // log voting - -/datum/config_entry/flag/log_craft // log crafting - -/datum/config_entry/flag/log_whisper // log client whisper - -/datum/config_entry/flag/log_attack // log attack messages - -/datum/config_entry/flag/log_emote // log emotes - -/datum/config_entry/flag/log_adminchat // log admin chat messages - protection = CONFIG_ENTRY_LOCKED - -/datum/config_entry/flag/log_shuttle // log shuttle related actions, ie shuttle computers, shuttle manipulator, emergency console - -/datum/config_entry/flag/log_pda // log pda messages - -/datum/config_entry/flag/log_telecomms // log telecomms messages - -/datum/config_entry/flag/log_twitter // log certain expliotable parrots and other such fun things in a JSON file of twitter valid phrases. - -/datum/config_entry/flag/log_world_topic // log all world.Topic() calls - -/datum/config_entry/flag/log_manifest // log crew manifest to seperate file - -/datum/config_entry/flag/log_job_debug // log roundstart divide occupations debug information to a file - /datum/config_entry/flag/allow_admin_ooccolor // Allows admins with relevant permissions to have their own ooc colour /datum/config_entry/flag/allow_vote_restart // allow votes to restart @@ -472,10 +428,6 @@ /datum/config_entry/string/default_view_square config_entry_value = "15x15" -/datum/config_entry/flag/log_pictures - -/datum/config_entry/flag/picture_logging_camera - /datum/config_entry/number/max_bunker_days config_entry_value = 7 min_val = 1 diff --git a/code/controllers/configuration/entries/logging.dm b/code/controllers/configuration/entries/logging.dm new file mode 100644 index 0000000000..1cb47d6ab7 --- /dev/null +++ b/code/controllers/configuration/entries/logging.dm @@ -0,0 +1,70 @@ +/datum/config_entry/flag/log_ooc // log OOC channel + config_entry_value = TRUE + +/datum/config_entry/flag/log_access // log login/logout + config_entry_value = TRUE + +/datum/config_entry/flag/log_say // log client say + config_entry_value = TRUE + +/datum/config_entry/flag/log_admin // log admin actions + protection = CONFIG_ENTRY_LOCKED + +/datum/config_entry/flag/log_prayer // log prayers + config_entry_value = TRUE + +/datum/config_entry/flag/log_law // log lawchanges + config_entry_value = TRUE + +/datum/config_entry/flag/log_game // log game events + config_entry_value = TRUE + +/datum/config_entry/flag/log_virus // log virology data + config_entry_value = TRUE + +/datum/config_entry/flag/log_vote // log voting + config_entry_value = TRUE + +/datum/config_entry/flag/log_craft // log crafting + config_entry_value = TRUE + +/datum/config_entry/flag/log_whisper // log client whisper + config_entry_value = TRUE + +/datum/config_entry/flag/log_attack // log attack messages + config_entry_value = TRUE + +/datum/config_entry/flag/log_emote // log emotes + config_entry_value = TRUE + +/datum/config_entry/flag/log_adminchat // log admin chat messages + protection = CONFIG_ENTRY_LOCKED + +/datum/config_entry/flag/log_shuttle // log shuttle related actions, ie shuttle computers, shuttle manipulator, emergency console + config_entry_value = TRUE + +/datum/config_entry/flag/log_pda // log pda messages + config_entry_value = TRUE + +/datum/config_entry/flag/log_telecomms // log telecomms messages + config_entry_value = TRUE + +/datum/config_entry/flag/log_twitter // log certain expliotable parrots and other such fun things in a JSON file of twitter valid phrases. + config_entry_value = TRUE + +/datum/config_entry/flag/log_world_topic // log all world.Topic() calls + config_entry_value = TRUE + +/datum/config_entry/flag/log_manifest // log crew manifest to seperate file + config_entry_value = TRUE + +/datum/config_entry/flag/log_job_debug // log roundstart divide occupations debug information to a file + config_entry_value = TRUE + +/datum/config_entry/flag/log_pictures + +/datum/config_entry/flag/picture_logging_camera + +/// forces log_href for tgui +/datum/config_entry/flag/emergency_tgui_logging + config_entry_value = FALSE diff --git a/code/controllers/subsystem/job.dm b/code/controllers/subsystem/job.dm index 165f6e9d81..7dae0d0126 100644 --- a/code/controllers/subsystem/job.dm +++ b/code/controllers/subsystem/job.dm @@ -490,6 +490,28 @@ SUBSYSTEM_DEF(job) job.after_spawn(H, M, joined_late) // note: this happens before the mob has a key! M will always have a client, H might not. equip_loadout(N, H, TRUE)//CIT CHANGE - makes players spawn with in-backpack loadout items properly. A little hacky but it works + 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) + 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() + 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]) + card.forceMove(binder) + binder.cards.Add(card) + return H /* /datum/controller/subsystem/job/proc/handle_auto_deadmin_roles(client/C, rank) diff --git a/code/controllers/subsystem/persistence/_persistence.dm b/code/controllers/subsystem/persistence/_persistence.dm index e8faf80e5d..a3be7b9c51 100644 --- a/code/controllers/subsystem/persistence/_persistence.dm +++ b/code/controllers/subsystem/persistence/_persistence.dm @@ -88,6 +88,7 @@ SUBSYSTEM_DEF(persistence) SavePhotoPersistence() //THIS IS PERSISTENCE, NOT THE LOGGING PORTION. SavePaintings() SaveScars() + SaveTCGCards() /** * Loads persistent data relevant to the current map: Objects, etc. @@ -349,3 +350,25 @@ SUBSYSTEM_DEF(persistence) if(!ending_human.client) return ending_human.client.prefs.save_character() + +/datum/controller/subsystem/persistence/proc/SaveTCGCards() + for(var/i in GLOB.joined_player_list) + var/mob/living/carbon/human/ending_human = get_mob_by_ckey(i) + if(!istype(ending_human) || !ending_human.mind || !ending_human.client || !ending_human.client.prefs || !ending_human.client.prefs.tcg_cards) + continue + + var/mob/living/carbon/human/original_human = ending_human.mind.original_character + 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) diff --git a/code/datums/components/gps.dm b/code/datums/components/gps.dm index 61098c8b66..f3ff912321 100644 --- a/code/datums/components/gps.dm +++ b/code/datums/components/gps.dm @@ -26,15 +26,16 @@ GLOBAL_LIST_EMPTY(GPS_list) if(. == COMPONENT_INCOMPATIBLE || !isitem(parent)) return COMPONENT_INCOMPATIBLE var/atom/A = parent - A.add_overlay("working") + if(starton) + A.add_overlay("working") + else + tracking = FALSE A.name = "[initial(A.name)] ([gpstag])" RegisterSignal(parent, COMSIG_ITEM_ATTACK_SELF, .proc/interact) if(!emp_proof) RegisterSignal(parent, COMSIG_ATOM_EMP_ACT, .proc/on_emp_act) RegisterSignal(parent, COMSIG_PARENT_EXAMINE, .proc/on_examine) RegisterSignal(parent, COMSIG_CLICK_ALT, .proc/on_AltClick) - if(!starton) - tracking = FALSE ///Called on COMSIG_ITEM_ATTACK_SELF /datum/component/gps/item/proc/interact(datum/source, mob/user) diff --git a/code/datums/components/storage/concrete/tcg.dm b/code/datums/components/storage/concrete/tcg.dm new file mode 100644 index 0000000000..a9d8012a4b --- /dev/null +++ b/code/datums/components/storage/concrete/tcg.dm @@ -0,0 +1,49 @@ +/** + *A storage component to be used on card piles, for use as hands/decks/discard piles. Don't use on something that's not a card pile! + */ +/datum/component/storage/concrete/tcg + display_numerical_stacking = FALSE + max_w_class = WEIGHT_CLASS_TINY + max_items = 30 + max_combined_w_class = WEIGHT_CLASS_TINY * 30 + ///The deck that the card pile is using for FAIR PLAY. + +/datum/component/storage/concrete/tcg/can_be_inserted(obj/item/I, stop_messages, mob/M) + . = ..() + return istype(I, /obj/item/tcg_card) + +/datum/component/storage/concrete/tcg/PostTransfer() + . = ..() + handle_empty_deck() + +/datum/component/storage/concrete/tcg/remove_from_storage(atom/movable/AM, atom/new_location) + . = ..() + handle_empty_deck() + +/datum/component/storage/concrete/tcg/ui_show(mob/M) + . = ..() + M.visible_message("[M] starts to look through the contents of \the [parent]!", \ + "You begin looking into the contents of \the [parent]!") + +/datum/component/storage/concrete/tcg/close(mob/M) + . = ..() + var/list/card_contents = contents() + var/obj/temp_parent = parent + temp_parent.visible_message("\the [parent] is shuffled after looking through it.") + card_contents = shuffle(card_contents) + +/datum/component/storage/concrete/tcg/mass_remove_from_storage(atom/target, list/things, datum/progressbar/progress, trigger_on_found) + . = ..() + if(!things.len) + qdel(parent) + +/datum/component/storage/concrete/tcg/proc/handle_empty_deck() + var/list/contents = contents() + //You can't have a deck of one card! + if(contents.len == 1) + var/obj/item/tcgcard_deck/deck = parent + var/obj/item/tcg_card/card = contents[1] + remove_from_storage(card, card.drop_location()) + card.flipped = deck.flipped + card.update_icon_state() + qdel(parent) diff --git a/code/datums/traits/good.dm b/code/datums/traits/good.dm index 4a4108f005..659149a123 100644 --- a/code/datums/traits/good.dm +++ b/code/datums/traits/good.dm @@ -228,10 +228,10 @@ gain_text = "You've learned an extra language!" lose_text = "You've forgotten your extra language." -/datum/quirk/multilingual/add() +/datum/quirk/multilingual/post_add() var/mob/living/carbon/human/H = quirk_holder - H.grant_language(H.client.prefs.language, TRUE, TRUE, LANGUAGE_MIND) + H.grant_language(H.client.prefs.language, TRUE, TRUE, LANGUAGE_MULTILINGUAL) /datum/quirk/multilingual/remove() var/mob/living/carbon/human/H = quirk_holder - H.remove_language(H.client.prefs.language, TRUE, TRUE, LANGUAGE_MIND) + H.remove_language(H.client.prefs.language, TRUE, TRUE, LANGUAGE_MULTILINGUAL) diff --git a/code/game/machinery/computer/security.dm b/code/game/machinery/computer/security.dm index 0157f4ca87..45bb9bd327 100644 --- a/code/game/machinery/computer/security.dm +++ b/code/game/machinery/computer/security.dm @@ -264,6 +264,8 @@ What a mess.*/ active1 = null if(!( GLOB.data_core.security.Find(active2) )) active2 = null + if(!authenticated && href_list["choice"] != "Log In") // logging in is the only action you can do if not logged in + return if(usr.contents.Find(src) || (in_range(src, usr) && isturf(loc)) || hasSiliconAccessInArea(usr) || IsAdminGhost(usr)) usr.set_machine(src) switch(href_list["choice"]) diff --git a/code/game/objects/items/armor_kits.dm b/code/game/objects/items/armor_kits.dm index fa88b77600..906d7c5f81 100644 --- a/code/game/objects/items/armor_kits.dm +++ b/code/game/objects/items/armor_kits.dm @@ -10,35 +10,41 @@ /obj/item/armorkit/afterattack(atom/target, mob/user, proximity_flag, click_parameters) // yeah have fun making subtypes and modifying the afterattack if you want to make variants // idiot - // - hatter var/used = FALSE if(isobj(target) && istype(target, /obj/item/clothing/under)) var/obj/item/clothing/under/C = target - if(C.armor.melee < 10) - C.armor.melee = 10 + if(C.damaged_clothes) + to_chat(user,"You should repair the damage done to [C] first.") + return + if(C.attached_accessory) + to_chat(user,"Kind of hard to sew around [C.attached_accessory].") + return + if(C.armor.getRating("melee") < 10) + C.armor = C.armor.setRating("melee" = 10) used = TRUE - if(C.armor.laser < 10) - C.armor.laser = 10 + if(C.armor.getRating("laser") < 10) + C.armor = C.armor.setRating("laser" = 10) used = TRUE - if(C.armor.fire < 40) - C.armor.fire = 40 + if(C.armor.getRating("fire") < 40) + C.armor = C.armor.setRating("fire" = 40) used = TRUE - if(C.armor.acid < 10) - C.armor.acid = 10 + if(C.armor.getRating("acid") < 10) + C.armor = C.armor.setRating("acid" = 10) used = TRUE - if(C.armor.bomb < 5) - C.armor.bomb = 5 + if(C.armor.getRating("bomb") < 5) + C.armor = C.armor.setRating("bomb" = 5) used = TRUE if(used) - user.visible_message("[user] uses [src] on [C], reinforcing it and tossing the empty case away afterwards.", \ - "You reinforce [C] with [src], making it a little more protective! You toss the empty casing away afterwards.") - C.name = "durathread [C.name]" // this disappears if it gets repaired, which is annoying + user.visible_message("[user] reinforces [C] with [src].", \ + "You reinforce [C] with [src], making it as protective as a durathread jumpsuit.") + C.name = "durathread [C.name]" + C.upgrade_prefix = "durathread" // god i hope this works qdel(src) return else - to_chat(user, "You stare at [src] and [C], coming to the conclusion that you probably don't need to reinforce it any further.") + to_chat(user, "You don't need to reinforce [C] any further.") return else return diff --git a/code/game/objects/items/devices/gps.dm b/code/game/objects/items/devices/gps.dm index a0b695e29f..e0453cebc0 100644 --- a/code/game/objects/items/devices/gps.dm +++ b/code/game/objects/items/devices/gps.dm @@ -8,11 +8,12 @@ slot_flags = ITEM_SLOT_BELT obj_flags = UNIQUE_RENAME var/gpstag = "COM0" + var/emp_proof = FALSE var/starton = TRUE /obj/item/gps/Initialize() . = ..() - AddComponent(/datum/component/gps/item, gpstag, starton) + AddComponent(/datum/component/gps/item, gpstag, emp_proof, starton) /obj/item/gps/science icon_state = "gps-s" diff --git a/code/game/objects/items/handcuffs.dm b/code/game/objects/items/handcuffs.dm index 296b46bf85..59b6d56b51 100644 --- a/code/game/objects/items/handcuffs.dm +++ b/code/game/objects/items/handcuffs.dm @@ -245,6 +245,9 @@ slowdown = 7 breakouttime = 300 //Deciseconds = 30s = 0.5 minute +/obj/item/restraints/legcuffs/proc/on_removed() + return + /obj/item/restraints/legcuffs/beartrap name = "bear trap" throw_speed = 1 @@ -376,4 +379,8 @@ icon_state = "ebola" hitsound = 'sound/weapons/taserhit.ogg' w_class = WEIGHT_CLASS_SMALL - breakouttime = 60 + breakouttime = 25 + +/obj/item/restraints/legcuffs/bola/energy/on_removed() + do_sparks(1, TRUE, src) + qdel(src) diff --git a/code/game/objects/items/stacks/sheets/sheet_types.dm b/code/game/objects/items/stacks/sheets/sheet_types.dm index 62949b45a8..798f1d3a6a 100644 --- a/code/game/objects/items/stacks/sheets/sheet_types.dm +++ b/code/game/objects/items/stacks/sheets/sheet_types.dm @@ -466,6 +466,7 @@ GLOBAL_LIST_INIT(cardboard_recipes, list ( \ new/datum/stack_recipe("cardboard cutout", /obj/item/cardboard_cutout, 5), \ new/datum/stack_recipe("pizza box", /obj/item/pizzabox), \ new/datum/stack_recipe("folder", /obj/item/folder), \ + new/datum/stack_recipe("cardboard card", /obj/item/cardboard_card, 1), \ // holy fuck why are there so many boxes new/datum/stack_recipe_list("fancy boxes", list ( \ new /datum/stack_recipe("donut box", /obj/item/storage/fancy/donut_box), \ diff --git a/code/game/objects/items/storage/uplink_kits.dm b/code/game/objects/items/storage/uplink_kits.dm index 97012528a0..ae2f432d2e 100644 --- a/code/game/objects/items/storage/uplink_kits.dm +++ b/code/game/objects/items/storage/uplink_kits.dm @@ -526,3 +526,8 @@ new /obj/item/book/granter/martial/carp(src) new /obj/item/clothing/suit/hooded/carp_costume(src) new /obj/item/staff/bostaff(src) + +/obj/item/storage/box/syndie_kit/sleepytime/cardpack/PopulateContents() + . = ..() + new /obj/item/cardpack/syndicate(src) + new /obj/item/cardpack/syndicate(src) diff --git a/code/modules/antagonists/brother/brother.dm b/code/modules/antagonists/brother/brother.dm index 0a2e079921..30e6a80e85 100644 --- a/code/modules/antagonists/brother/brother.dm +++ b/code/modules/antagonists/brother/brother.dm @@ -149,8 +149,6 @@ if(prob(50)) if(LAZYLEN(active_ais()) && prob(100/GLOB.joined_player_list.len)) add_objective(new/datum/objective/destroy, TRUE) - else if(prob(30)) - add_objective(new/datum/objective/maroon, TRUE) else add_objective(new/datum/objective/assassinate, TRUE) else diff --git a/code/modules/antagonists/changeling/changeling.dm b/code/modules/antagonists/changeling/changeling.dm index 7a34af4d13..ba4578add9 100644 --- a/code/modules/antagonists/changeling/changeling.dm +++ b/code/modules/antagonists/changeling/changeling.dm @@ -441,19 +441,20 @@ else kill_objective.find_target() objectives += kill_objective - else + + /*else var/datum/objective/maroon/maroon_objective = new maroon_objective.owner = owner if(team_mode) maroon_objective.find_target_by_role(role = ROLE_CHANGELING, role_type = 1, invert = 1) else maroon_objective.find_target() - objectives += maroon_objective + objectives += maroon_objective*/ if (!(locate(/datum/objective/escape) in objectives) && escape_objective_possible) var/datum/objective/escape/escape_with_identity/identity_theft = new identity_theft.owner = owner - identity_theft.target = maroon_objective.target + identity_theft.target = kill_objective.target identity_theft.update_explanation_text() objectives += identity_theft escape_objective_possible = FALSE diff --git a/code/modules/antagonists/clockcult/clock_scriptures/scripture_applications.dm b/code/modules/antagonists/clockcult/clock_scriptures/scripture_applications.dm index cbf3bdaa38..77dc174238 100644 --- a/code/modules/antagonists/clockcult/clock_scriptures/scripture_applications.dm +++ b/code/modules/antagonists/clockcult/clock_scriptures/scripture_applications.dm @@ -8,7 +8,7 @@ descname = "Powers Nearby Structures" name = "Sigil of Transmission" desc = "Places a sigil that can drain and will store energy to power clockwork structures." - invocations = list("Divinity...", "...power our creations!") + invocations = list("Divinity...", "...power our creations.") channel_time = 70 power_cost = 200 whispered = TRUE @@ -28,7 +28,7 @@ descname = "Powered Structure, Delay Emergency Shuttles" name = "Prolonging Prism" desc = "Creates a mechanized prism which will delay the arrival of an emergency shuttle by 2 minutes at a massive power cost." - invocations = list("May this prism...", "...grant us time to enact his will!") + invocations = list("May this prism...", "...grant us time to enact his will.") channel_time = 80 power_cost = 300 object_path = /obj/structure/destructible/clockwork/powered/prolonging_prism @@ -60,7 +60,7 @@ descname = "Powered Structure, Area Denial" name = "Mania Motor" desc = "Creates a mania motor which causes minor damage and a variety of negative mental effects in nearby non-Servant humans, potentially up to and including conversion." - invocations = list("May this transmitter...", "...break the will of all who oppose us!") + invocations = list("May this transmitter...", "...break the will of all who oppose us.") channel_time = 80 power_cost = 750 object_path = /obj/structure/destructible/clockwork/powered/mania_motor @@ -83,7 +83,7 @@ descname = "Powered Structure, Teleportation Hub" name = "Clockwork Obelisk" desc = "Creates a clockwork obelisk that can broadcast messages over the Hierophant Network or open a Spatial Gateway to any living Servant or clockwork obelisk." - invocations = list("May this obelisk...", "...take us to all places!") + invocations = list("May this obelisk...", "...take us to all places.") channel_time = 80 power_cost = 300 object_path = /obj/structure/destructible/clockwork/powered/clockwork_obelisk @@ -163,7 +163,7 @@ descname = "Well-Rounded Combat Construct" name = "Clockwork Marauder" desc = "Creates a shell for a clockwork marauder, a balanced frontline construct that can deflect projectiles with its shield." - invocations = list("Arise, avatar of Arbiter!", "Defend the Ark with vengeful zeal.") + invocations = list("Arise, avatar of Arbiter!", "Defend the Ark with vengeful zeal!") channel_time = 80 power_cost = 8000 creator_message = "Your slab disgorges several chunks of replicant alloy that form into a suit of thrumming armor." diff --git a/code/modules/antagonists/clockcult/clock_scriptures/scripture_drivers.dm b/code/modules/antagonists/clockcult/clock_scriptures/scripture_drivers.dm index 0a59656e31..b79bcfa03d 100644 --- a/code/modules/antagonists/clockcult/clock_scriptures/scripture_drivers.dm +++ b/code/modules/antagonists/clockcult/clock_scriptures/scripture_drivers.dm @@ -7,7 +7,7 @@ descname = "Generates Power From Starlight" name = "Stargazer" desc = "Forms a weak structure that generates power every second while within three tiles of starlight." - invocations = list("Capture their inferior light for us!") + invocations = list("Capture their inferior light for us.") channel_time = 50 power_cost = 200 object_path = /obj/structure/destructible/clockwork/stargazer @@ -16,6 +16,7 @@ usage_tip = "For obvious reasons, make sure to place this near a window or somewhere else that can see space!" tier = SCRIPTURE_DRIVER one_per_tile = TRUE + whispered = TRUE primary_component = HIEROPHANT_ANSIBLE sort_priority = 1 quickbind = TRUE @@ -34,7 +35,7 @@ descname = "Power Generation" name = "Integration Cog" desc = "Fabricates an integration cog, which can be used on an open APC to replace its innards and passively siphon its power." - invocations = list("Take that which sustains them!") + invocations = list("Take that which sustains them.") channel_time = 10 power_cost = 10 whispered = TRUE @@ -55,7 +56,7 @@ descname = "Trap, Stunning" name = "Sigil of Transgression" desc = "Wards a tile with a sigil, which will briefly stun the next non-Servant to cross it and apply Belligerent to them." - invocations = list("Divinity, smite...", "...those who trespass here!") + invocations = list("Divinity, smite...", "...those who trespass here.") channel_time = 50 power_cost = 50 whispered = TRUE @@ -75,7 +76,7 @@ descname = "Trap, Conversion" name = "Sigil of Submission" desc = "Places a luminous sigil that will convert any non-Servants that remain on it for 8 seconds." - invocations = list("Divinity, enlighten...", "...those who trespass here!") + invocations = list("Divinity, enlighten...", "...those who trespass here.") channel_time = 60 power_cost = 125 whispered = TRUE @@ -95,7 +96,7 @@ descname = "Short-Range Single-Target Stun" name = "Kindle" desc = "Charges your slab with divine energy, allowing you to overwhelm a target with Ratvar's light." - invocations = list("Divinity, show them your light!") + invocations = list("Divinity, show them your light.") whispered = TRUE channel_time = 25 //2.5 seconds should be a okay compromise between being able to use it when needed, and not being able to just pause in combat for a second and hardstunning your enemy power_cost = 125 @@ -118,7 +119,7 @@ descname = "Handcuffs" name = "Hateful Manacles" desc = "Forms replicant manacles around a target's wrists that function like handcuffs." - invocations = list("Shackle the heretic!", "Break them in body and spirit!") + invocations = list("Shackle the heretic!", "Break them in body and spirit.") channel_time = 15 power_cost = 25 whispered = TRUE @@ -269,7 +270,7 @@ descname = "New Clockwork Slab" name = "Replicant" desc = "Creates a new clockwork slab." - invocations = list("Metal, become greater!") + invocations = list("Metal, become greater.") channel_time = 10 power_cost = 25 whispered = TRUE @@ -290,7 +291,7 @@ descname = "Limited Xray Vision Glasses" name = "Wraith Spectacles" desc = "Fabricates a pair of glasses which grant true sight but cause gradual vision loss." - invocations = list("Show the truth of this world to me!") + invocations = list("Show the truth of this world to me.") channel_time = 10 power_cost = 50 whispered = TRUE @@ -310,7 +311,7 @@ name = "Spatial Gateway" desc = "Tears open a miniaturized gateway in spacetime to any conscious servant that can transport objects or creatures to its destination. \ Each servant assisting in the invocation adds one additional use and four additional seconds to the gateway's uses and duration." - invocations = list("Spatial Gateway...", "...activate!") + invocations = list("Spatial Gateway...", "...activate.") channel_time = 30 power_cost = 400 whispered = TRUE diff --git a/code/modules/antagonists/clockcult/clock_scriptures/scripture_scripts.dm b/code/modules/antagonists/clockcult/clock_scriptures/scripture_scripts.dm index b559b34d5e..7ba4ce0936 100644 --- a/code/modules/antagonists/clockcult/clock_scriptures/scripture_scripts.dm +++ b/code/modules/antagonists/clockcult/clock_scriptures/scripture_scripts.dm @@ -29,7 +29,7 @@ descname = "Structure, Turret" name = "Ocular Warden" desc = "Forms an automatic short-range turret which will automatically attack nearby unrestrained non-Servants that can see it." - invocations = list("Guardians of Engine...", "...judge those who would harm us!") + invocations = list("Guardians of Engine...", "...judge those who would harm us.") channel_time = 100 power_cost = 250 object_path = /obj/structure/destructible/clockwork/ocular_warden @@ -105,7 +105,7 @@ descname = "Delayed Area Knockdown Glasses" name = "Judicial Visor" desc = "Creates a visor that can smite an area, applying Belligerent and briefly stunning. The smote area will explode after 3 seconds." - invocations = list("Grant me the flames of Engine!") + invocations = list("Grant me the flames of Engine.") channel_time = 10 power_cost = 400 whispered = TRUE @@ -124,7 +124,7 @@ descname = "Shield with empowerable bashes" name = "Nezbere's shield" desc = "Creates a shield which generates charge from blocking damage, using it to empower its bashes tremendously. It is repaired with brass, and while very durable, extremely weak to lasers and, even more so, to energy weaponry." - invocations = list("Shield me...", "... from the coming dark!") + invocations = list("Shield me...", "... from the coming dark.") channel_time = 20 power_cost = 600 //Shouldn't be too spammable but not too hard to get either whispered = TRUE @@ -143,7 +143,7 @@ descname = "Summonable Armor and Weapons" name = "Clockwork Armaments" desc = "Allows the invoker to summon clockwork armor and a Ratvarian spear at will. The spear's attacks will generate Vitality, used for healing." - invocations = list("Grant me armaments...", "...from the forge of Armorer!") + invocations = list("Grant me armaments...", "...from the forge of Armorer.") channel_time = 20 power_cost = 250 whispered = TRUE diff --git a/code/modules/antagonists/clockcult/clockcult.dm b/code/modules/antagonists/clockcult/clockcult.dm index b6ed7dfe65..b935258c27 100644 --- a/code/modules/antagonists/clockcult/clockcult.dm +++ b/code/modules/antagonists/clockcult/clockcult.dm @@ -15,13 +15,16 @@ var/ignore_holy_water = FALSE /datum/antagonist/clockcult/silent + name = "Silent Clock Cultist" silent = TRUE show_in_antagpanel = FALSE //internal /datum/antagonist/clockcult/neutered + name = "Neutered Clock Cultist" neutered = TRUE /datum/antagonist/clockcult/neutered/traitor + name = "Traitor Clock Cultist" ignore_eligibility_check = TRUE ignore_holy_water = TRUE show_in_roundend = FALSE @@ -185,7 +188,7 @@ /datum/antagonist/clockcult/admin_add(datum/mind/new_owner,mob/admin) - add_servant_of_ratvar(new_owner.current, TRUE) + add_servant_of_ratvar(new_owner.current, TRUE, override_type = type) message_admins("[key_name_admin(admin)] has made [new_owner.current] into a servant of Ratvar.") log_admin("[key_name(admin)] has made [new_owner.current] into a servant of Ratvar.") diff --git a/code/modules/antagonists/cult/cult.dm b/code/modules/antagonists/cult/cult.dm index a2ec4a47a4..09d8771a62 100644 --- a/code/modules/antagonists/cult/cult.dm +++ b/code/modules/antagonists/cult/cult.dm @@ -19,9 +19,11 @@ var/ignore_holy_water = FALSE /datum/antagonist/cult/neutered + name = "Neutered Cultist" neutered = TRUE /datum/antagonist/cult/neutered/traitor + name = "Traitor Cultist" ignore_eligibility_checks = TRUE ignore_holy_water = TRUE show_in_roundend = FALSE diff --git a/code/modules/antagonists/traitor/classes/assassin.dm b/code/modules/antagonists/traitor/classes/assassin.dm index 6b709aac59..8175ad9736 100644 --- a/code/modules/antagonists/traitor/classes/assassin.dm +++ b/code/modules/antagonists/traitor/classes/assassin.dm @@ -8,11 +8,9 @@ /datum/traitor_class/human/assassin/forge_single_objective(datum/antagonist/traitor/T) .=1 var/permakill_prob = 20 - var/is_dynamic = FALSE var/datum/game_mode/dynamic/mode if(istype(SSticker.mode,/datum/game_mode/dynamic)) mode = SSticker.mode - is_dynamic = TRUE permakill_prob = max(0,mode.threat_level-50) var/list/active_ais = active_ais() if(active_ais.len && prob(100/GLOB.joined_player_list.len)) @@ -20,11 +18,6 @@ destroy_objective.owner = T.owner destroy_objective.find_target() T.add_objective(destroy_objective) - else if(prob(30) || (is_dynamic && (mode.storyteller.flags & NO_ASSASSIN))) - var/datum/objective/maroon/maroon_objective = new - maroon_objective.owner = T.owner - maroon_objective.find_target() - T.add_objective(maroon_objective) else if(prob(permakill_prob)) var/datum/objective/assassinate/kill_objective = new kill_objective.owner = T.owner diff --git a/code/modules/antagonists/traitor/classes/human.dm b/code/modules/antagonists/traitor/classes/human.dm index 30aa11e39d..16f65a63c3 100644 --- a/code/modules/antagonists/traitor/classes/human.dm +++ b/code/modules/antagonists/traitor/classes/human.dm @@ -41,11 +41,6 @@ destroy_objective.owner = T.owner destroy_objective.find_target() T.add_objective(destroy_objective) - else if(prob(30) || (is_dynamic && (mode.storyteller.flags & NO_ASSASSIN))) - var/datum/objective/maroon/maroon_objective = new - maroon_objective.owner = T.owner - maroon_objective.find_target() - T.add_objective(maroon_objective) else if(prob(max(0,assassin_prob-20))) var/datum/objective/assassinate/kill_objective = new kill_objective.owner = T.owner diff --git a/code/modules/antagonists/traitor/classes/subterfuge.dm b/code/modules/antagonists/traitor/classes/subterfuge.dm index 07707b69e1..ea073f38c1 100644 --- a/code/modules/antagonists/traitor/classes/subterfuge.dm +++ b/code/modules/antagonists/traitor/classes/subterfuge.dm @@ -17,11 +17,6 @@ kill_objective.owner = T.owner kill_objective.find_target() T.add_objective(kill_objective) - else - var/datum/objective/maroon/maroon_objective = new - maroon_objective.owner = T.owner - maroon_objective.find_target() - T.add_objective(maroon_objective) else var/list/weights = list() weights["sabo"] = length(subtypesof(/datum/sabotage_objective)) diff --git a/code/modules/atmospherics/machinery/airalarm.dm b/code/modules/atmospherics/machinery/airalarm.dm index 6049ee965e..ccb8a3d81c 100644 --- a/code/modules/atmospherics/machinery/airalarm.dm +++ b/code/modules/atmospherics/machinery/airalarm.dm @@ -304,7 +304,7 @@ "danger_level" = cur_tlv.get_danger_level(environment.get_moles(gas_id) * partial_pressure) )) - if(!locked || hasSiliconAccessInArea(user, PRIVILEDGES_SILICON|PRIVILEDGES_DRONE)) + if(!locked || hasSiliconAccessInArea(user, PRIVILEGES_SILICON|PRIVILEGES_DRONE)) data["vents"] = list() for(var/id_tag in A.air_vent_names) var/long_name = A.air_vent_names[id_tag] @@ -385,13 +385,13 @@ if(..() || buildstage != 2) return var/silicon_access = hasSiliconAccessInArea(usr) - var/bot_priviledges = silicon_access || (usr.silicon_privileges & PRIVILEDGES_DRONE) - if((locked && !bot_priviledges) || (silicon_access && aidisabled)) + var/bot_privileges = silicon_access || (usr.silicon_privileges & PRIVILEGES_DRONE) + if((locked && !bot_privileges) || (silicon_access && aidisabled)) return var/device_id = params["id_tag"] switch(action) if("lock") - if(bot_priviledges && !wires.is_cut(WIRE_IDSCAN)) + if(bot_privileges && !wires.is_cut(WIRE_IDSCAN)) locked = !locked . = TRUE if("power", "toggle_filter", "widenet", "scrubbing") diff --git a/code/modules/cargo/packs/costumes_toys.dm b/code/modules/cargo/packs/costumes_toys.dm index 08f9a927c6..c0bd25b028 100644 --- a/code/modules/cargo/packs/costumes_toys.dm +++ b/code/modules/cargo/packs/costumes_toys.dm @@ -318,7 +318,7 @@ /obj/item/clothing/under/suit/white, // white is a weird color for a groom but some people are weird /obj/item/clothing/under/suit/polychromic, /obj/item/clothing/under/suit/polychromic, // in case you can't be satisfied with the most fitting choices, of course. - /obj/item/clothing/under/dress/wedding, + /obj/item/clothing/under/dress/wedding, /obj/item/clothing/under/dress/wedding, // this is what you actually bought the crate for. You can't get these anywhere else. /obj/item/clothing/under/dress/wedding/orange, /obj/item/clothing/under/dress/wedding/orange, @@ -333,4 +333,23 @@ /obj/item/storage/fancy/ringbox/silver, /obj/item/storage/fancy/ringbox/silver) //diamond rings cost the same price as this crate via cargo so we're not giving you two for free. Wedding rings are traditionally less valuable anyway. crate_name = "wedding crate" - + +/datum/supply_pack/costumes_toys/randomised/tcg + name = "Big-Ass Booster Pack Pack" + desc = "A bumper load of NT TCG Booster Packs of varying series. Collect them all!" + cost = 3000 + contains = list() + crate_name = "booster pack pack" + +/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(.) + if(pack.illegal) + cardtypes.Remove(cardtype) + qdel(pack) + for(var/i in 1 to 10) + cardpacktype = pick(cardtypes) + new cardpacktype(.) diff --git a/code/modules/client/client_procs.dm b/code/modules/client/client_procs.dm index 5f567f1360..970e34cabe 100644 --- a/code/modules/client/client_procs.dm +++ b/code/modules/client/client_procs.dm @@ -76,9 +76,15 @@ GLOBAL_LIST_INIT(blacklisted_builds, list( to_chat(src, "Your previous action was ignored because you've done too many in a second") return - //Logs all hrefs, except chat pings - if(!(href_list["_src_"] == "chat" && href_list["proc"] == "ping" && LAZYLEN(href_list) == 2)) - log_href("[src] (usr:[usr]\[[COORD(usr)]\]) : [hsrc ? "[hsrc] " : ""][href]") + + // Tgui Topic middleware + if(tgui_Topic(href_list)) + if(CONFIG_GET(flag/emergency_tgui_logging)) + log_href("[src] (usr:[usr]\[[COORD(usr)]\]) : [hsrc ? "[hsrc] " : ""][href]") + return + + //Logs all hrefs + log_href("[src] (usr:[usr]\[[COORD(usr)]\]) : [hsrc ? "[hsrc] " : ""][href]") //byond bug ID:2256651 if (asset_cache_job && (asset_cache_job in completed_asset_jobs)) @@ -105,10 +111,6 @@ GLOBAL_LIST_INIT(blacklisted_builds, list( handle_statpanel_click(href_list) return - // Tgui Topic middleware - if(tgui_Topic(href_list)) - return - // Admin PM if(href_list["priv_msg"]) cmd_admin_pm(href_list["priv_msg"],null) diff --git a/code/modules/client/preferences.dm b/code/modules/client/preferences.dm index 572c71b1e0..3b3b72b840 100644 --- a/code/modules/client/preferences.dm +++ b/code/modules/client/preferences.dm @@ -220,6 +220,8 @@ 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() + /datum/preferences/New(client/C) parent = C diff --git a/code/modules/client/preferences_savefile.dm b/code/modules/client/preferences_savefile.dm index 088f7753cf..458f607ac9 100644 --- a/code/modules/client/preferences_savefile.dm +++ b/code/modules/client/preferences_savefile.dm @@ -271,7 +271,7 @@ SAVEFILE UPDATING/VERSIONING - 'Simplified', or rather, more coder-friendly ~Car loadout_data["SAVE_[i]"] = list() for(var/some_gear_item in saved_loadout_paths) if(!ispath(text2path(some_gear_item))) - message_admins("Failed to copy item [some_gear_item] to new loadout system when migrating from version [current_version] to 40, issue: item is not a path") + log_game("Failed to copy item [some_gear_item] to new loadout system when migrating from version [current_version] to 40, issue: item is not a path") continue var/datum/gear/gear_item = text2path(some_gear_item) if(!(initial(gear_item.loadout_flags) & LOADOUT_CAN_COLOR_POLYCHROMIC)) @@ -658,6 +658,14 @@ SAVEFILE UPDATING/VERSIONING - 'Simplified', or rather, more coder-friendly ~Car modified_limbs = safe_json_decode(limbmodstr) else modified_limbs = list() + + var/tcgcardstr + S["tcg_cards"] >> tcgcardstr + if(length(tcgcardstr)) + tcg_cards = safe_json_decode(tcgcardstr) + else + tcg_cards = list() + S["chosen_limb_id"] >> chosen_limb_id S["hide_ckey"] >> hide_ckey //saved per-character @@ -1095,6 +1103,11 @@ SAVEFILE UPDATING/VERSIONING - 'Simplified', or rather, more coder-friendly ~Car else S["loadout"] << safe_json_encode(list()) + if(length(tcg_cards)) + S["tcg_cards"] << safe_json_encode(tcg_cards) + else + S["tcg_cards"] << safe_json_encode(list()) + cit_character_pref_save(S) return 1 diff --git a/code/modules/clothing/clothing.dm b/code/modules/clothing/clothing.dm index ea01b0c0ed..018c3d9a3f 100644 --- a/code/modules/clothing/clothing.dm +++ b/code/modules/clothing/clothing.dm @@ -31,6 +31,9 @@ // What items can be consumed to repair this clothing (must by an /obj/item/stack) var/repairable_by = /obj/item/stack/sheet/cloth + // has this item been upgraded by an upgrade kit (see: durathread armor kits) + var/upgrade_prefix + //Var modification - PLEASE be careful with this I know who you are and where you live var/list/user_vars_to_edit //VARNAME = VARVALUE eg: "name" = "butts" var/list/user_vars_remembered //Auto built by the above + dropped() + equipped() @@ -120,6 +123,8 @@ update_clothes_damaged_state(CLOTHING_PRISTINE) obj_integrity = max_integrity name = initial(name) // remove "tattered" or "shredded" if there's a prefix + if(upgrade_prefix) + name = upgrade_prefix + " " + initial(name) body_parts_covered = initial(body_parts_covered) slot_flags = initial(slot_flags) damage_by_parts = null diff --git a/code/modules/clothing/gloves/miscellaneous.dm b/code/modules/clothing/gloves/miscellaneous.dm index a558abbfe8..4728001699 100644 --- a/code/modules/clothing/gloves/miscellaneous.dm +++ b/code/modules/clothing/gloves/miscellaneous.dm @@ -220,8 +220,8 @@ parry_max_attacks = INFINITY parry_failed_cooldown_duration = 2.25 SECONDS parry_failed_stagger_duration = 2.25 SECONDS - parry_cooldown = 0 - parry_failed_clickcd_duration = 0 + parry_cooldown = 3 SECONDS + parry_failed_clickcd_duration = 0.5 SECONDS /obj/item/clothing/gloves/botanic_leather name = "botanist's leather gloves" diff --git a/code/modules/clothing/shoes/colour.dm b/code/modules/clothing/shoes/colour.dm index df0f03f614..9d51753c78 100644 --- a/code/modules/clothing/shoes/colour.dm +++ b/code/modules/clothing/shoes/colour.dm @@ -51,6 +51,17 @@ desc = "Very gay shoes." icon_state = "rain_bow" +/obj/item/clothing/shoes/sneakers/poly/polychromic + name = "polychromic shoes" + desc = "Every color." + icon_state = "poly" + item_state = "poly" + var/list/poly_colors = list("#FFFFFF", "#1D1D1D") + +/obj/item/clothing/shoes/sneakers/poly/polychromic/ComponentInitialize() + . = ..() + AddElement(/datum/element/polychromic, poly_colors, 2) + /obj/item/clothing/shoes/sneakers/orange name = "orange shoes" icon_state = "orange" diff --git a/code/modules/clothing/suits/cloaks.dm b/code/modules/clothing/suits/cloaks.dm index 133956e44e..f4fd844e8a 100644 --- a/code/modules/clothing/suits/cloaks.dm +++ b/code/modules/clothing/suits/cloaks.dm @@ -102,7 +102,18 @@ /obj/item/clothing/neck/cloak/polychromic/ComponentInitialize() . = ..() AddElement(/datum/element/polychromic, poly_colors, 3) - + +/obj/item/clothing/neck/cancloak/polychromic + name = "canvas cloak" + desc = "A rugged cloak made of canvas." + icon_state = "cancloak" + item_state = "cancloak" + var/list/poly_colors = list("#585858", "#373737", "#BEBEBE") + +/obj/item/clothing/neck/cancloak/polychromic/ComponentInitialize() + . = ..() + AddElement(/datum/element/polychromic, poly_colors, 3) + /obj/item/clothing/neck/cloak/alt name = "cloak" desc = "A ragged up white cloak. It reminds you of a place not far from here." diff --git a/code/modules/clothing/suits/miscellaneous.dm b/code/modules/clothing/suits/miscellaneous.dm index 0b705f7797..2a69a5d669 100644 --- a/code/modules/clothing/suits/miscellaneous.dm +++ b/code/modules/clothing/suits/miscellaneous.dm @@ -1030,6 +1030,16 @@ alternate_worn_layer = UNDER_HEAD_LAYER mutantrace_variation = STYLE_DIGITIGRADE|STYLE_NO_ANTHRO_ICON +/obj/item/clothing/suit/toggle/wbreakpoly + name = "polychromic windbreaker" + desc = "Perfect for windy days." + icon_state = "wbreakpoly" + item_state = "wbreakpoly" + +/obj/item/clothing/suit/toggle/wbreakpoly/polychromic/ComponentInitialize() + . = ..() + AddElement(/datum/element/polychromic, list("#464F65", "#916035", "#474747"), 3) + /obj/item/clothing/suit/flakjack name = "flak jacket" desc = "A dilapidated jacket made of a supposedly bullet-proof material (Hint: It isn't.). Smells faintly of napalm." diff --git a/code/modules/clothing/under/_under.dm b/code/modules/clothing/under/_under.dm index e617d2d57b..3207a5842f 100644 --- a/code/modules/clothing/under/_under.dm +++ b/code/modules/clothing/under/_under.dm @@ -32,6 +32,9 @@ /obj/item/clothing/under/attackby(obj/item/I, mob/user, params) if((has_sensor == BROKEN_SENSORS) && istype(I, /obj/item/stack/cable_coil)) + if(damaged_clothes) + to_chat(user,"You should repair the damage done to [src] first.") + return 0 var/obj/item/stack/cable_coil/C = I I.use_tool(src, user, 0, 1) has_sensor = HAS_SENSORS diff --git a/code/modules/food_and_drinks/food/snacks_pie.dm b/code/modules/food_and_drinks/food/snacks_pie.dm index a4287d3d19..5329829637 100644 --- a/code/modules/food_and_drinks/food/snacks_pie.dm +++ b/code/modules/food_and_drinks/food/snacks_pie.dm @@ -54,7 +54,7 @@ H.visible_message("[H] is creamed by [src]!", "You've been creamed by [src]!") playsound(H, "desceration", 50, TRUE) if(!H.is_mouth_covered()) - reagents.trans_to(H, 15, log = TRUE) //Cream pie combat + reagents.trans_to(H, 15, log = "creampie hit") //Cream pie combat if(!H.creamed) // one layer at a time H.add_overlay(creamoverlay) H.creamed = TRUE diff --git a/code/modules/food_and_drinks/kitchen_machinery/deep_fryer.dm b/code/modules/food_and_drinks/kitchen_machinery/deep_fryer.dm index fecc9467a1..ebde504ec0 100644 --- a/code/modules/food_and_drinks/kitchen_machinery/deep_fryer.dm +++ b/code/modules/food_and_drinks/kitchen_machinery/deep_fryer.dm @@ -79,7 +79,7 @@ God bless America. to_chat(user, "There's nothing to dissolve [I] in!") return user.visible_message("[user] drops [I] into [src].", "You dissolve [I] in [src].") - I.reagents.trans_to(src, I.reagents.total_volume) + I.reagents.trans_to(src, I.reagents.total_volume, log = "pill into deep fryer") qdel(I) return if(istype(I,/obj/item/clothing/head/mob_holder)) diff --git a/code/modules/holodeck/computer.dm b/code/modules/holodeck/computer.dm index e5cd36cad6..e94cc17041 100644 --- a/code/modules/holodeck/computer.dm +++ b/code/modules/holodeck/computer.dm @@ -115,13 +115,20 @@ return FALSE var/valid = FALSE var/list/checked = program_cache.Copy() - if(obj_flags & EMAGGED) - checked |= emag_programs for(var/prog in checked) var/list/P = prog if(P["type"] == program_to_load) valid = TRUE break + if(obj_flags & EMAGGED) //split up into separate for loops instead of together so we can adminlog it + checked = emag_programs.Copy() + for(var/prog in checked) + var/list/P = prog + if(P["type"] == program_to_load) + valid = TRUE + log_game("[key_name(usr)] has loaded the restricted holodeck program [program_to_load]") + message_admins("[ADMIN_LOOKUPFLW(usr)] has loaded the restricted holodeck program [program_to_load]") + break if(!valid) return FALSE @@ -134,6 +141,14 @@ nerf(obj_flags & EMAGGED) obj_flags ^= EMAGGED say("Safeties restored. Restarting...") + if(obj_flags & EMAGGED) + to_chat(usr,"You vastly increase projector power and override the safety and security protocols.") + log_game("[key_name(usr)] has disabled safeties on the holodeck computer") + message_admins("[ADMIN_LOOKUPFLW(usr)] has disabled safeties on the holodeck computer") + else + to_chat(usr,"You restore the safeties to the holodeck.") + log_game("[key_name(usr)] has reenabled safeties on the holodeck computer") + message_admins("[ADMIN_LOOKUPFLW(usr)] has reenabled safeties on the holodeck computer") /obj/machinery/computer/holodeck/process() if(damaged && prob(10)) @@ -179,6 +194,7 @@ to_chat(user, "You vastly increase projector power and override the safety and security protocols.") say("Warning. Automatic shutoff and derezzing protocols have been corrupted. Please call Nanotrasen maintenance and do not use the simulator.") log_game("[key_name(user)] emagged the Holodeck Control Console") + message_admins("[ADMIN_LOOKUPFLW(user)] emagged the Holodeck Control Console.") nerf(!(obj_flags & EMAGGED)) /obj/machinery/computer/holodeck/emp_act(severity) diff --git a/code/modules/hydroponics/hydroponics.dm b/code/modules/hydroponics/hydroponics.dm index 24f65756c8..e186364cff 100644 --- a/code/modules/hydroponics/hydroponics.dm +++ b/code/modules/hydroponics/hydroponics.dm @@ -527,12 +527,13 @@ else if(istype(O, /obj/item/seeds) && !istype(O, /obj/item/seeds/sample)) if(!myseed) if(istype(O, /obj/item/seeds/kudzu)) - investigate_log("had Kudzu planted in it by [key_name(user)] at [AREACOORD(src)]","kudzu") + investigate_log("had Kudzu planted in it by [key_name(user)] at [AREACOORD(src)]", INVESTIGATE_BOTANY) if(!user.transferItemToLoc(O, src)) return to_chat(user, "You plant [O].") dead = FALSE myseed = O + investigate_log("planting: [user] planted [O] with traits [english_list(myseed)] and reagents [english_list_assoc(myseed.reagents_add)] and potency [myseed.potency]", INVESTIGATE_BOTANY) TRAY_NAME_UPDATE age = 1 plant_health = myseed.endurance diff --git a/code/modules/hydroponics/seeds.dm b/code/modules/hydroponics/seeds.dm index d8082e667d..577635cd1c 100644 --- a/code/modules/hydroponics/seeds.dm +++ b/code/modules/hydroponics/seeds.dm @@ -188,6 +188,8 @@ ///The Number of products produced by the plant, typically the yield. var/product_count = getYield() + parent.investigate_log("manual harvest by [key_name(user)] of [getYield()] of [src], with seed traits [english_list(genes)] and reagents_add [english_list_assoc(reagents_add)] and potency [potency].", INVESTIGATE_BOTANY) + while(t_amount < product_count) var/obj/item/reagent_containers/food/snacks/grown/t_prod if(instability >= 30 && (seed_flags & MUTATE_EARLY) && LAZYLEN(mutatelist) && prob(instability/3)) diff --git a/code/modules/mob/dead/new_player/new_player.dm b/code/modules/mob/dead/new_player/new_player.dm index 00c22ad96d..dbab6a558c 100644 --- a/code/modules/mob/dead/new_player/new_player.dm +++ b/code/modules/mob/dead/new_player/new_player.dm @@ -128,10 +128,58 @@ if(dbflags & DB_FLAG_AGE_CONFIRMATION_INCOMPLETE) //they have not completed age gate var/age_verification = age_gate() if(age_verification != 1) - client.add_system_note("Automated-Age-Gate", "Failed automatic age gate process") + client.add_system_note("Automated-Age-Gate", "Failed automatic age gate process.") //ban them and kick them - AddBan(client.ckey, client.computer_id, "SYSTEM BAN - Inputted date during join verification was under 18 years of age. Contact administration on discord for verification.", "SYSTEM", FALSE, null, client.address) + + //parameters used by sql line, easier to read: + var/bantype_str = "ADMIN_PERMABAN" + var/reason = "SYSTEM BAN - Inputted date during join verification was under 18 years of age. Contact administration on discord for verification." + var/duration = -1 + var/sql_ckey = sanitizeSQL(client.ckey) + var/computerid = client.computer_id + if(!computerid) + computerid = "0" + var/sql_computerid = sanitizeSQL(computerid) + var/ip = client.address + if(!ip) + ip = "0.0.0.0" + var/sql_ip = sanitizeSQL(ip) + + //parameter not used as there's no job but i want to fill out all parameters for the insert line + var/sql_job + + // these are typically the banning admin's, but it's the system so we leave them null, but they're still here for the sake of a full set of values + var/sql_a_ckey + var/sql_a_computerid + var/sql_a_ip + + // record all admins and non-admins online at the time + var/who + for(var/client/C in GLOB.clients) + if(!who) + who = "[C]" + else + who += ", [C]" + + var/adminwho + for(var/client/C in GLOB.admins) + if(!adminwho) + adminwho = "[C]" + else + adminwho += ", [C]" + + var/sql = "INSERT INTO [format_table_name("ban")] (`bantime`,`server_ip`,`server_port`,`round_id`,`bantype`,`reason`,`job`,`duration`,`expiration_time`,`ckey`,`computerid`,`ip`,`a_ckey`,`a_computerid`,`a_ip`,`who`,`adminwho`) VALUES (Now(), INET_ATON(IF('[world.internet_address]' LIKE '', '0', '[world.internet_address]')), '[world.port]', '[GLOB.round_id]', '[bantype_str]', '[reason]', '[sql_job]', [(duration)?"[duration]":"0"], Now() + INTERVAL [(duration>0) ? duration : 0] MINUTE, '[sql_ckey]', '[sql_computerid]', INET_ATON('[sql_ip]'), '[sql_a_ckey]', '[sql_a_computerid]', INET_ATON('[sql_a_ip]'), '[who]', '[adminwho]')" + var/datum/DBQuery/query_add_ban = SSdbcore.NewQuery(sql) + qdel(query_add_ban) + + // announce this + message_admins("[html_encode(client.ckey)] has been banned for failing the automatic age gate.") + send2irc("[html_encode(client.ckey)] has been banned for failing the automatic age gate.") + + // removing the client disconnects them qdel(client) + + return FALSE else //they claim to be of age, so allow them to continue and update their flags diff --git a/code/modules/mob/living/carbon/alien/larva/larva.dm b/code/modules/mob/living/carbon/alien/larva/larva.dm index 8f0ef2b384..77c9a8c579 100644 --- a/code/modules/mob/living/carbon/alien/larva/larva.dm +++ b/code/modules/mob/living/carbon/alien/larva/larva.dm @@ -11,6 +11,8 @@ maxHealth = 25 health = 25 + can_ventcrawl = TRUE + var/amount_grown = 0 var/max_grown = 100 var/time_of_birth diff --git a/code/modules/mob/living/carbon/carbon.dm b/code/modules/mob/living/carbon/carbon.dm index 979baeb065..f143f6302d 100644 --- a/code/modules/mob/living/carbon/carbon.dm +++ b/code/modules/mob/living/carbon/carbon.dm @@ -434,6 +434,9 @@ legcuffed.forceMove(drop_location()) legcuffed = null I.dropped(src) + if(istype(I, /obj/item/restraints/legcuffs)) + var/obj/item/restraints/legcuffs/lgcf = I + lgcf.on_removed() update_inv_legcuffed() return else diff --git a/code/modules/mob/living/carbon/human/human_defines.dm b/code/modules/mob/living/carbon/human/human_defines.dm index eedc59d9d5..772022a987 100644 --- a/code/modules/mob/living/carbon/human/human_defines.dm +++ b/code/modules/mob/living/carbon/human/human_defines.dm @@ -95,9 +95,10 @@ parry_efficiency_considered_successful = 0.01 parry_efficiency_to_counterattack = 0.01 parry_max_attacks = 3 - parry_cooldown = 30 - parry_failed_stagger_duration = 0 - parry_failed_clickcd_duration = 0.4 + parry_cooldown = 3 SECONDS + parry_failed_cooldown_duration = 1.5 SECONDS + parry_failed_stagger_duration = 1 SECONDS + parry_failed_clickcd_duration = 0.4 SECONDS parry_data = list( // yeah it's snowflake "UNARMED_PARRY_STAGGER" = 3 SECONDS, @@ -135,16 +136,16 @@ parry_imperfect_falloff_percent = 20 parry_efficiency_perfect = 100 parry_efficiency_perfect_override = list( - ATTACK_TYPE_PROJECTILE_TEXT = 60, + TEXT_ATTACK_TYPE_PROJECTILE = 60, ) parry_efficiency_considered_successful = 0.01 parry_efficiency_to_counterattack = 0.01 parry_max_attacks = INFINITY - parry_failed_cooldown_duration = 1.5 SECONDS - parry_failed_stagger_duration = 0 - parry_cooldown = 0 - parry_failed_clickcd_duration = 0.8 + parry_failed_cooldown_duration = 3 SECONDS + parry_failed_stagger_duration = 2 SECONDS + parry_cooldown = 3 SECONDS + parry_failed_clickcd_duration = 0.8 SECONDS parry_data = list( // yeah it's snowflake "UNARMED_PARRY_STAGGER" = 3 SECONDS, diff --git a/code/modules/mob/living/carbon/human/species.dm b/code/modules/mob/living/carbon/human/species.dm index 8d473639b4..c3cdb3354f 100644 --- a/code/modules/mob/living/carbon/human/species.dm +++ b/code/modules/mob/living/carbon/human/species.dm @@ -1425,8 +1425,6 @@ GLOBAL_LIST_EMPTY(roundstart_race_names) var/damage = rand(user.dna.species.punchdamagelow, user.dna.species.punchdamagehigh) var/punchwoundbonus = user.dna.species.punchwoundbonus - var/puncherstam = user.getStaminaLoss() - var/puncherbrute = user.getBruteLoss() var/punchedstam = target.getStaminaLoss() var/punchedbrute = target.getBruteLoss() @@ -1434,7 +1432,7 @@ GLOBAL_LIST_EMPTY(roundstart_race_names) if(!SEND_SIGNAL(target, COMSIG_COMBAT_MODE_CHECK, COMBAT_MODE_INACTIVE)) damage *= 1.2 if(!CHECK_MOBILITY(user, MOBILITY_STAND)) - damage *= 0.8 + damage *= 0.65 if(SEND_SIGNAL(user, COMSIG_COMBAT_MODE_CHECK, COMBAT_MODE_INACTIVE)) damage *= 0.8 //END OF CITADEL CHANGES @@ -1446,19 +1444,7 @@ GLOBAL_LIST_EMPTY(roundstart_race_names) if(!affecting) //Maybe the bodypart is missing? Or things just went wrong.. affecting = target.get_bodypart(BODY_ZONE_CHEST) //target chest instead, as failsafe. Or hugbox? You decide. - var/miss_chance = 100//calculate the odds that a punch misses entirely. considers stamina and brute damage of the puncher. punches miss by default to prevent weird cases - if(attackchain_flags & ATTACK_IS_PARRY_COUNTERATTACK) - miss_chance = 0 - else - if(user.dna.species.punchdamagelow) - if(atk_verb == ATTACK_EFFECT_KICK) //kicks never miss (provided your species deals more than 0 damage) - miss_chance = 0 - else if(HAS_TRAIT(user, TRAIT_PUGILIST)) //pugilists, being good at Punching People, also never miss - miss_chance = 0 - else - miss_chance = min(10 + max(puncherstam * 0.5, puncherbrute * 0.5), 100) //probability of miss has a base of 10, and modified based on half brute total. Capped at max 100 to prevent weirdness in prob() - - if(!damage || !affecting || prob(miss_chance))//future-proofing for species that have 0 damage/weird cases where no zone is targeted + if(!damage || !affecting)//future-proofing for species that have 0 damage/weird cases where no zone is targeted playsound(target.loc, user.dna.species.miss_sound, 25, TRUE, -1) target.visible_message("[user]'s [atk_verb] misses [target]!", \ "You avoid [user]'s [atk_verb]!", "You hear a swoosh!", null, COMBAT_MESSAGE_RANGE, null, \ diff --git a/code/modules/mob/living/living_sprint.dm b/code/modules/mob/living/living_sprint.dm index 3ef67c9edd..728645c3eb 100644 --- a/code/modules/mob/living/living_sprint.dm +++ b/code/modules/mob/living/living_sprint.dm @@ -26,6 +26,8 @@ update_sprint_icon() /mob/living/proc/enable_sprint_mode(update_icon = TRUE) + if(!CONFIG_GET(flag/sprint_enabled)) + return if(combat_flags & COMBAT_FLAG_SPRINT_ACTIVE) return ENABLE_BITFIELD(combat_flags, COMBAT_FLAG_SPRINT_ACTIVE) @@ -61,6 +63,8 @@ update_sprint_icon() /mob/living/proc/user_toggle_intentional_sprint_mode() + if(!CONFIG_GET(flag/sprint_enabled)) + return var/old = (combat_flags & COMBAT_FLAG_SPRINT_TOGGLED) if(old) if(combat_flags & COMBAT_FLAG_SPRINT_FORCED) diff --git a/code/modules/mob/living/silicon/pai/pai.dm b/code/modules/mob/living/silicon/pai/pai.dm index 5740f98e90..4e33fba208 100644 --- a/code/modules/mob/living/silicon/pai/pai.dm +++ b/code/modules/mob/living/silicon/pai/pai.dm @@ -11,7 +11,7 @@ maxHealth = 500 layer = BELOW_MOB_LAYER var/obj/item/instrument/piano_synth/internal_instrument - silicon_privileges = PRIVILEDGES_PAI + silicon_privileges = PRIVILEGES_PAI var/network = "ss13" var/obj/machinery/camera/current = null diff --git a/code/modules/mob/living/silicon/robot/robot_sprint.dm b/code/modules/mob/living/silicon/robot/robot_sprint.dm index dff0d9dd0d..80adfe80fd 100644 --- a/code/modules/mob/living/silicon/robot/robot_sprint.dm +++ b/code/modules/mob/living/silicon/robot/robot_sprint.dm @@ -1,4 +1,7 @@ /mob/living/silicon/robot/default_toggle_sprint(shutdown = FALSE) + if(!CONFIG_GET(flag/sprint_enabled)) + disable_intentional_sprint_mode() + return var/current = (combat_flags & COMBAT_FLAG_SPRINT_ACTIVE) if(current || shutdown || !cell || (cell.charge < 25) || !cansprint) disable_intentional_sprint_mode() diff --git a/code/modules/mob/living/silicon/silicon.dm b/code/modules/mob/living/silicon/silicon.dm index 944b909463..b2b27c7d70 100644 --- a/code/modules/mob/living/silicon/silicon.dm +++ b/code/modules/mob/living/silicon/silicon.dm @@ -1,6 +1,6 @@ /mob/living/silicon gender = NEUTER - silicon_privileges = PRIVILEDGES_SILICON + silicon_privileges = PRIVILEGES_SILICON verb_say = "states" verb_ask = "queries" verb_exclaim = "declares" diff --git a/code/modules/mob/living/simple_animal/bot/bot.dm b/code/modules/mob/living/simple_animal/bot/bot.dm index bb7c437ca7..d3838a580f 100644 --- a/code/modules/mob/living/simple_animal/bot/bot.dm +++ b/code/modules/mob/living/simple_animal/bot/bot.dm @@ -15,7 +15,7 @@ maxbodytemp = INFINITY minbodytemp = 0 blood_volume = 0 - silicon_privileges = PRIVILEDGES_BOT + silicon_privileges = PRIVILEGES_BOT sentience_type = SENTIENCE_ARTIFICIAL status_flags = NONE //no default canpush verb_say = "states" diff --git a/code/modules/mob/living/simple_animal/bot/floorbot.dm b/code/modules/mob/living/simple_animal/bot/floorbot.dm index ff6941ec70..47173f10ea 100644 --- a/code/modules/mob/living/simple_animal/bot/floorbot.dm +++ b/code/modules/mob/living/simple_animal/bot/floorbot.dm @@ -340,6 +340,7 @@ 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) @@ -355,9 +356,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 @@ -371,7 +372,7 @@ if(mode == BOT_REPAIRING && F && src.loc == F) F.broken = 0 F.burnt = 0 - F.PlaceOnTop(/turf/open/floor/plasteel, flags = CHANGETURF_INHERIT_AIR) + F.PlaceOnTop(/turf/open/floor/plating, flags = CHANGETURF_INHERIT_AIR) if(replacetiles && F.type != initial(tiletype.turf_type) && specialtiles && !isplatingturf(F)) anchored = TRUE @@ -433,4 +434,4 @@ if(robot.mode == BOT_REPAIRING) return TRUE return FALSE - + diff --git a/code/modules/mob/living/simple_animal/friendly/drone/_drone.dm b/code/modules/mob/living/simple_animal/friendly/drone/_drone.dm index e11facb4ba..ecd5db3ccf 100644 --- a/code/modules/mob/living/simple_animal/friendly/drone/_drone.dm +++ b/code/modules/mob/living/simple_animal/friendly/drone/_drone.dm @@ -40,7 +40,7 @@ bubble_icon = "machine" initial_language_holder = /datum/language_holder/drone mob_size = MOB_SIZE_SMALL - silicon_privileges = PRIVILEDGES_DRONE + silicon_privileges = PRIVILEGES_DRONE damage_coeff = list(BRUTE = 1, BURN = 1, TOX = 0, CLONE = 0, STAMINA = 0, OXY = 0) hud_possible = list(DIAG_STAT_HUD, DIAG_HUD, ANTAG_HUD) unique_name = TRUE diff --git a/code/modules/mob/mob_helpers.dm b/code/modules/mob/mob_helpers.dm index 605f0a2d55..4b0f505067 100644 --- a/code/modules/mob/mob_helpers.dm +++ b/code/modules/mob/mob_helpers.dm @@ -408,7 +408,7 @@ It's fairly easy to fix if dealing with single letters but not so much with comp return return TRUE -/atom/proc/hasSiliconAccessInArea(mob/user, flags = PRIVILEDGES_SILICON) +/atom/proc/hasSiliconAccessInArea(mob/user, flags = PRIVILEGES_SILICON) return user.silicon_privileges & (flags) || (user.siliconaccesstoggle && (get_area(src) in user.siliconaccessareas)) /mob/proc/toggleSiliconAccessArea(area/area) @@ -496,7 +496,7 @@ It's fairly easy to fix if dealing with single letters but not so much with comp colored_message = "[message]" else colored_message = "[message]" - + //This makes readability a bit better for admins. switch(message_type) if(LOG_WHISPER) @@ -507,7 +507,7 @@ It's fairly easy to fix if dealing with single letters but not so much with comp colored_message = "(ASAY) [colored_message]" if(LOG_EMOTE) colored_message = "(EMOTE) [colored_message]" - + var/list/timestamped_message = list("\[[TIME_STAMP("hh:mm:ss", FALSE)]\] [key_name(src)] [loc_name(src)] (Event #[LAZYLEN(logging[smessage_type])])" = colored_message) logging[smessage_type] += timestamped_message diff --git a/code/modules/pool/pool_controller.dm b/code/modules/pool/pool_controller.dm index 17faa7a3e3..9f670de282 100644 --- a/code/modules/pool/pool_controller.dm +++ b/code/modules/pool/pool_controller.dm @@ -146,7 +146,7 @@ return reagents.clear_reagents() // This also reacts them. No nitroglycerin deathpools, sorry gamers :( - W.reagents.trans_to(reagents, max_beaker_transfer) + W.reagents.trans_to(reagents, max_beaker_transfer, log = "pool fill from reagent container") user.visible_message("[src] makes a slurping noise.", "All of the contents of [W] are quickly suctioned out by the machine![user] tries to squirt something into [target]'s eyes, but fails!", \ "[user] tries to squirt something into [target]'s eyes, but fails!") @@ -67,7 +67,7 @@ var/mob/M = target log_combat(user, M, "squirted", reagents.log_list()) - trans = src.reagents.trans_to(target, amount_per_transfer_from_this) + trans = src.reagents.trans_to(target, amount_per_transfer_from_this, log = "dropper drop") to_chat(user, "You transfer [trans] unit\s of the solution.") update_icon() @@ -81,7 +81,7 @@ to_chat(user, "[target] is empty!") return - var/trans = target.reagents.trans_to(src, amount_per_transfer_from_this) + var/trans = target.reagents.trans_to(src, amount_per_transfer_from_this, log = "dropper fill") to_chat(user, "You fill [src] with [trans] unit\s of the solution.") diff --git a/code/modules/reagents/reagent_containers/hypospray.dm b/code/modules/reagents/reagent_containers/hypospray.dm index 1f89af420e..143025aed1 100644 --- a/code/modules/reagents/reagent_containers/hypospray.dm +++ b/code/modules/reagents/reagent_containers/hypospray.dm @@ -41,7 +41,7 @@ if(M.reagents) var/trans = 0 if(!infinite) - trans = reagents.trans_to(M, amount_per_transfer_from_this, log = TRUE) + trans = reagents.trans_to(M, amount_per_transfer_from_this, log = "hypospray injection") else trans = reagents.copy_to(M, amount_per_transfer_from_this) @@ -427,7 +427,7 @@ var/fraction = min(vial.amount_per_transfer_from_this/vial.reagents.total_volume, 1) vial.reagents.reaction(L, method, fraction) - vial.reagents.trans_to(target, vial.amount_per_transfer_from_this, log = TRUE) + vial.reagents.trans_to(target, vial.amount_per_transfer_from_this, log = "hypospray fill") var/long_sound = vial.amount_per_transfer_from_this >= 15 playsound(loc, long_sound ? 'sound/items/hypospray_long.ogg' : pick('sound/items/hypospray.ogg','sound/items/hypospray2.ogg'), 50, 1, -1) to_chat(user, "You [fp_verb] [vial.amount_per_transfer_from_this] units of the solution. The hypospray's cartridge now contains [vial.reagents.total_volume] units.") diff --git a/code/modules/reagents/reagent_containers/rags.dm b/code/modules/reagents/reagent_containers/rags.dm index 5d94e78809..8a6e2bf2e7 100644 --- a/code/modules/reagents/reagent_containers/rags.dm +++ b/code/modules/reagents/reagent_containers/rags.dm @@ -39,7 +39,7 @@ C.visible_message("[user] is trying to smother \the [C] with \the [src]!", "[user] is trying to smother you with \the [src]!", "You hear some struggling and muffled cries of surprise.") if(do_after(user, 20, target = C)) reagents.reaction(C, INGEST) - reagents.trans_to(C, 5, log = TRUE) + reagents.trans_to(C, 5, log = "rag smother") C.visible_message("[user] has smothered \the [C] with \the [src]!", "[user] has smothered you with \the [src]!", "You hear some struggling and a heavy breath taken.") log_combat(user, C, "smothered", log_object) else @@ -107,7 +107,7 @@ reagents.clear_reagents() else msg += "'s liquids into \the [target]" - reagents.trans_to(target, reagents.total_volume, log = TRUE) + reagents.trans_to(target, reagents.total_volume, log = "rag squeeze dry") to_chat(user, "[msg].") return TRUE diff --git a/code/modules/surgery/dental_implant.dm b/code/modules/surgery/dental_implant.dm index 311c886c9d..f41f299439 100644 --- a/code/modules/surgery/dental_implant.dm +++ b/code/modules/surgery/dental_implant.dm @@ -36,6 +36,6 @@ log_combat(owner, null, "swallowed an implanted pill", target) if(target.reagents.total_volume) target.reagents.reaction(owner, INGEST) - target.reagents.trans_to(owner, target.reagents.total_volume, log = TRUE) + target.reagents.trans_to(owner, target.reagents.total_volume, log = "dental pill swallow") qdel(target) return 1 diff --git a/code/modules/tcg/cards.dm b/code/modules/tcg/cards.dm new file mode 100644 index 0000000000..970aef0bba --- /dev/null +++ b/code/modules/tcg/cards.dm @@ -0,0 +1,714 @@ +#define TAPPED_ANGLE 90 +#define UNTAPPED_ANGLE 0 + +#define COMMON_SERIES list(/datum/tcg_card/pack_1, /datum/tcg_card/exodia) //So star cards don't drop + +/datum/tcg_card + var/name = "Stupid Coder" + var/desc = "A coder that fucked up this card. Report if you see this." + var/rules = "Tap this card. It will ahelp itself" + var/icon_state = "cardback" + var/pack = 'icons/obj/tcg/pack_1.dmi' + + var/mana_cost = 0 + var/attack = 0 + var/health = 0 + + var/faction = "Coderbus" + var/rarity = "Stoopid" + var/card_type = "Unit" + + var/obj/item/tcg_card/card + +/*Uncomment if you want to make the game automatic + +/datum/tcg_card/proc/Use(datum/tcg_card/affected_card, mob/living/user) + if(card_type == "Equipment") + affected_card.health += health + affected_card.attack += attack + to_chat(user, "You use [card] on [affected_card.card], upgrading it's stats.") + user.emote("uses [card] on [affected_card.card], upgrading it's stats.") //To get that visible emote. Useful if you want nice gameplay + else if (card_type == "Unit") + affected_card.health -= attack + health -= affected_card.attack + var/flavortext = "." + if(affected_card.health <= 0) + flavortext = ", killing [affected_card.card]!" + if(health <= 0) + flavortext = ", killing both [affected_card.card] and [card]!" + else + flavortext = ", killing [card] in the process!" + to_chat(user, "You attack [affected_card.card] with [card][flavortext]") + user.emote("attacks [affected_card.card] with [card][flavortext]") + +*/ + +/datum/tcg_card/proc/UseSelf(mob/living/user) + return + +/datum/tcg_card/proc/Tap(mob/living/user) //Actually runtimes on tap! Tapping is basically disabling a card for a turn in exchange for special effects + if(type == /datum/tcg_card) + log_runtime("[user] managed to get a blank TCG card.") + +/datum/tcg_card/proc/Untap(mob/living/user) + return + +/datum/tcg_card/proc/Reset(mob/living/user) + to_chat(user, "You reset [card]'s stats to original.") + mana_cost = initial(mana_cost) + rules = initial(rules) + health = initial(health) + attack = initial(attack) + faction = initial(faction) + +/obj/item/tcg_card + name = "TCG card" + desc = "A flipped TCG-branded card." + icon_state = "cardback" + icon = 'icons/obj/tcg/pack_1.dmi' + + var/datum_type = /datum/tcg_card + var/datum/tcg_card/card_datum + + w_class = WEIGHT_CLASS_TINY + + var/flipped = FALSE + var/tapped = FALSE + var/special = FALSE + var/illegal = FALSE + +/obj/item/tcg_card/special + special = TRUE + +/obj/item/tcg_card/examine(mob/user) + . = ..() + sleep(2) //So it prints this shit after the examine + if(flipped) + return + to_chat(user, "This card has following stats:") + to_chat(user, "Mana cost: [card_datum.mana_cost]") + to_chat(user, "Health: [card_datum.health]") + to_chat(user, "Attack: [card_datum.attack]") + to_chat(user, "Faction: [card_datum.faction]") + to_chat(user, "Rarity: [card_datum.rarity]") + to_chat(user, "Card Type: [card_datum.card_type]") + to_chat(user, "It's effect is: [card_datum.rules]") + if(illegal) + to_chat(user, "It's a low-quality copy of a real card. TCG Gaming Community won't probably accept it.") //Doesn't do crap, just for lulz + +/obj/item/tcg_card/openTip(location, control, params, user) //Overriding for nice UI + if(flipped) + return ..() + var/desc_content = "[desc]
\ + This card has following stats:
\ + Mana cost: [card_datum.mana_cost]
\ + Health: [card_datum.health]
\ + Attack: [card_datum.attack]
\ + Faction: [card_datum.faction]
\ + Rarity: [card_datum.rarity]
\ + Card Type: [card_datum.card_type]
\ + It's effect is: [card_datum.rules]" + openToolTip(user,src,params,title = name,content = desc_content,theme = "") + +/obj/item/tcg_card/New(loc, new_datum, illegal_card = FALSE) + . = ..() + if(!special) + 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 + illegal = illegal_card + + switch(card_datum.rarity) + if("Common") + grind_results = list(/datum/reagent/card_powder/green = 1) + if("Rare") + grind_results = list(/datum/reagent/card_powder/blue = 1) + if("Epic") + grind_results = list(/datum/reagent/card_powder/purple = 1) + if("Legendary") + grind_results = list(/datum/reagent/card_powder/yellow = 1) + if("Exodia") + grind_results = list(/datum/reagent/card_powder/black = 1) + +/obj/item/tcg_card/attack_hand(mob/user) + var/list/possible_actions = list( + "Pick Up" = image(icon = 'icons/mob/radial.dmi', icon_state = "radial_pickup"), + "Tap" = image(icon = 'icons/mob/radial.dmi', icon_state = "radial_tap"), + "Flip" = image(icon = 'icons/mob/radial.dmi', icon_state = "radial_flip") + ) + var/result = show_radial_menu(user, src, possible_actions, require_near = TRUE, tooltips = TRUE) + switch(result) + if("Pick Up") + . = ..() + if("Flip") + flipped = !flipped + if(flipped) + icon_state = "cardback" + name = "TCG card" + desc = "A flipped TCG-branded card." + else + name = card_datum.name + desc = card_datum.desc + icon_state = card_datum.icon_state + if("Tap") + var/matrix/ntransform = matrix(transform) + if(tapped) + ntransform.TurnTo(TAPPED_ANGLE , UNTAPPED_ANGLE) + else + ntransform.TurnTo(UNTAPPED_ANGLE , TAPPED_ANGLE) + tapped = !tapped + animate(src, transform = ntransform, time = 2, easing = (EASE_IN|EASE_OUT)) + if(tapped) + card_datum.Tap(user) + else + card_datum.Untap(user) + +/obj/item/tcg_card/attackby(obj/item/I, mob/living/user, params) + if(istype(I, /obj/item/tcg_card)) + var/obj/item/tcg_card/second_card = I + if(loc == user && second_card.loc == user) + var/obj/item/tcgcard_hand/hand = new(get_turf(user)) + 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 ..() + var/obj/item/tcgcard_deck/new_deck = new /obj/item/tcgcard_deck(drop_location()) + new_deck.flipped = flipped + 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 + if(length(old_deck.contents) >= 30) + to_chat(user, "This pile has too many cards for a regular deck!") + return + user.transferItemToLoc(src, old_deck) + flipped = old_deck.flipped + old_deck.update_icon() + update_icon() + return ..() + +/obj/item/tcg_card/attack_self(mob/user) + var/list/possible_actions = list( + "Reset to Default" = image(icon = 'icons/mob/radial.dmi', icon_state = "radial_reset"), + "Change stats" = image(icon = 'icons/mob/radial.dmi', icon_state = "radial_change_stats") + ) + var/result = show_radial_menu(user, src, possible_actions, require_near = TRUE, tooltips = TRUE) + switch(result) + if("Reset to Default") + card_datum.Reset(user) + user.visible_message("[user] resets [src]'s stats.") + if("Change stats") + possible_actions = list( + "Health" = image(icon = 'icons/mob/radial.dmi', icon_state = "radial_health"), + "Attack" = image(icon = 'icons/mob/radial.dmi', icon_state = "radial_attack"), + "Mana" = image(icon = 'icons/mob/radial.dmi', icon_state = "radial_mana") + ) + result = show_radial_menu(user, src, possible_actions, require_near = TRUE, tooltips = TRUE) + switch(result) + if("Health") + card_datum.health = input(user, "What do you want health to be?", "Changing [src]'s health") as num|null + if("Attack") + card_datum.attack = input(user, "What do you want attack to be?", "Changing [src]'s attack") as num|null + if("Mana") + card_datum.mana_cost = input(user, "What do you want mana cost to be?", "Changing [src]'s mana cost") as num|null + user.visible_message("[user] changes [src]'s [result].") + +/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/cardpack + name = "Trading Card Pack: Coder" + desc = "Contains six complete fuckups by the coders. Report this on github please!" + icon = 'icons/obj/tcg/misc.dmi' + icon_state = "cardpack" + w_class = WEIGHT_CLASS_TINY + ///The card series to look in + var/list/series = list(/datum/tcg_card/pack_1, /datum/tcg_card/exodia) + ///Chance of the pack having a coin in it out of 10 + var/contains_coin = -1 + ///The amount of cards to draw from the rarity table + var/card_count = 5 + ///The rarity table, the set must contain at least one of each + var/list/rarity_table = list( + "Common" = 900, + "Rare" = 300, + "Epic" = 50, + "Legendary" = 3, + "Exodia" = 1) //Basically 0.1%, it doesn't have guar. rarity + ///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. it can have as many or as few raritys as you'd like + var/list/guar_rarity = list( + "Legendary" = 1, + "Epic" = 9, + "Rare" = 30) + + var/illegal = FALSE //Can cargo get it? + + custom_price = PRICE_EXPENSIVE + +/obj/item/cardpack/series_one + name = "Trading Card Pack: 2560 Core Set" + desc = "Contains six cards of varying rarity from the 2560 Core Set. Collect them all!" + icon_state = "cardpack" + series = list(/datum/tcg_card/pack_1, /datum/tcg_card/exodia) + contains_coin = 10 + +/obj/item/cardpack/syndicate //More cards. Perfect stuff for gaming gang + name = "Trading Card Pack: Nuclear Danger" + desc = "Contains twelve cards of varying rarity from 2560 Core Set and 2560 Nuclear Danger. This pack was stamped by Waffle Co." + icon_state = "cardpack_syndicate" + series = list(/datum/tcg_card/pack_1, /datum/tcg_card/pack_nuclear) + contains_coin = 100 + + card_count = 9 + guaranteed_count = 3 + + guar_rarity = list( //Better chances + "Legendary" = 5, + "Epic" = 10, + "Rare" = 30) + +/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/attack_self(mob/user) + . = ..() + 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, illegal) + 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 /obj/item/tcg_rules(get_turf(user)) + qdel(src) + +/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 == "Stupid Coder") + continue + cards.Add(card) + qdel(new_card) + var/list/possible_cards = list() + var/list/rarity_cards = list("Exodia" = list(), "Legendary" = list(), "Epic" = list(), "Rare" = 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 //FUCK CI + 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/coin/thunderdome + name = "Thunderdome Flipper" + desc = "A Thunderdome TCG flipper, for deciding who gets to go first. Also conveniently acts as a counter, for various purposes." + icon = 'icons/obj/tcg/misc.dmi' + icon_state = "coin_nanotrasen" + custom_materials = list(/datum/material/plastic = 400) + material_flags = NONE + sideslist = list("nanotrasen", "syndicate") + +/obj/item/coin/thunderdome/Initialize() + . = ..() + transform = matrix(0.5,0,0,0,0.5,0) + +/obj/item/coin/thunderdome/equipped(mob/user, slot, initial) + . = ..() + transform = matrix() + +/obj/item/coin/thunderdome/dropped(mob/user, silent) + . = ..() + transform = matrix(0.5,0,0,0,0.5,0) + +/obj/item/tcgcard_deck + name = "Trading Card Pile" + desc = "A stack of TCG cards." + icon = 'icons/obj/tcg/misc.dmi' + icon_state = "deck_up" + + var/flipped = FALSE + + var/static/radial_draw = image(icon = 'icons/mob/radial.dmi', icon_state = "radial_draw") + var/static/radial_shuffle = image(icon = 'icons/mob/radial.dmi', icon_state = "radial_shuffle") + var/static/radial_pickup = image(icon = 'icons/mob/radial.dmi', icon_state = "radial_pickup") + +/obj/item/tcgcard_deck/Initialize() + . = ..() + LoadComponent(/datum/component/storage/concrete/tcg) + +/obj/item/tcgcard_deck/update_icon_state() + . = ..() + if(flipped) + switch(contents.len) + if(1 to 10) + icon_state = "deck_tcg_low" + if(11 to 20) + icon_state = "deck_tcg_half" + if(21 to INFINITY) + icon_state = "deck_tcg_full" + else + icon_state = "deck_up" + +/obj/item/tcgcard_deck/examine(mob/user) + . = ..() + . += "\The [src] has [contents.len] cards inside." + +/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"), + "Flip" = image(icon = 'icons/mob/radial.dmi', icon_state = "radial_flip"), + ) + var/choice = show_radial_menu(user, src, choices, custom_check = CALLBACK(src, .proc/check_menu, user), require_near = TRUE, tooltips = 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/Destroy() + for(var/card in 1 to contents.len) + var/obj/item/tcg_card/stored_card = contents[card] + stored_card.forceMove(drop_location()) + . = ..() + +/obj/item/tcgcard_deck/proc/check_menu(mob/living/user) + if(!istype(user)) + return FALSE + if(user.incapacitated() || !user.Adjacent(src)) + return FALSE + return TRUE + +/obj/item/tcgcard_deck/attackby(obj/item/I, mob/living/user, params) + . = ..() + if(istype(I, /obj/item/tcg_card)) + if(contents.len > 30) + to_chat(user, "This pile has too many cards for a regular deck!") + return FALSE + var/obj/item/tcg_card/new_card = I + new_card.flipped = flipped + new_card.forceMove(src) + +/obj/item/tcgcard_deck/attack_self(mob/living/carbon/user) + shuffle_deck(user) + return ..() + +/obj/item/tcgcard_deck/proc/draw_card(mob/user) + if(!contents.len) + CRASH("A TCG deck was created with no cards inside of it.") + var/obj/item/tcg_card/drawn_card = contents[contents.len] + user.put_in_hands(drawn_card) + drawn_card.flipped = flipped //If it's a face down deck, it'll be drawn face down, if it's a face up pile you'll draw it face up. + drawn_card.update_icon_state() + user.visible_message("[user] draws a card from \the [src]!", \ + "You draw a card from \the [src]!") + if(contents.len <= 1) + var/obj/item/tcg_card/final_card = contents[1] + user.transferItemToLoc(final_card, drop_location()) + qdel(src) + +/obj/item/tcgcard_deck/proc/shuffle_deck(mob/user, visable = TRUE) + if(!contents) + return + contents = shuffle(contents) + if(user.active_storage) + user.active_storage.close(user) + if(visable) + user.visible_message("[user] shuffles \the [src]!", \ + "You shuffle \the [src]!") + +/obj/item/tcgcard_deck/proc/flip_deck() + flipped = !flipped + var/list/temp_deck = contents.Copy() + contents = reverseRange(temp_deck) + //Now flip the cards to their opposite positions. + for(var/a in 1 to contents.len) + var/obj/item/tcg_card/nu_card = contents[a] + nu_card.flipped = flipped + nu_card.update_icon_state() + update_icon_state() + +/obj/item/tcgcard_hand + name = "Trading Card Hand" + desc = "A hand full of TCG cards." + icon = 'icons/effects/effects.dmi' + icon_state = "nothing" + w_class = WEIGHT_CLASS_TINY + 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/attackby(obj/item/I, mob/living/user, params) + if(istype(I, /obj/item/tcg_card)) + var/obj/item/tcg_card/card = I + if(loc == user && card.loc == user) + card.forceMove(src) + cards.Add(card) + update_icon() + . = ..() + +/obj/item/tcgcard_hand/attack_hand(mob/living/carbon/user) + if(loc == user) + 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, tooltips = 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 + . = ..() + +/obj/item/tcgcard_binder + name = "Trading Card Binder" + desc = "A TCG-branded card binder, specifically for your infinite collection of TCG cards!" + icon = 'icons/obj/tcg/misc.dmi' + icon_state = "binder" + + var/list/cards = list() + var/mode = 0 //If 1, will show all the cards even if you don't have em + +/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) + . = ..() + +/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"].") + +/obj/item/tcgcard_binder/attack_hand(mob/living/carbon/user) + if(loc == user) + var/list/choices = list() + if(mode) + var/card_types = list() + + 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] + 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) + 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) + return + . = ..() + +/obj/item/tcgcard_binder/proc/check_for_exodia() + var/list/card_types = list() + for(var/obj/item/tcg_card/card in cards) + card_types.Add(card.datum_type) + + for(var/card_type in subtypesof(/datum/tcg_card)) + var/datum/tcg_card/card_dat = new card_type + + if(card_dat.name == "Eldritch Horror" && (card_type in card_types)) //We already have Exodia saved + qdel(card_dat) + return + + if(card_dat.name == "Stupid Coder" || card_dat.name == "Eldritch Horror") //It would be stupid if we require exodia or system cards to get exodia + continue + qdel(card_dat) + if(!(card_type in card_types)) + return + + var/obj/item/tcg_card/card = new(get_turf(src), /datum/tcg_card/exodia/exodia) + card.forceMove(src) + cards.Add(card) + +/obj/item/tcgcard_binder/full/Initialize() //For admemes. + . = ..() + for(var/cardtype in subtypesof(/datum/tcg_card)) + var/obj/item/tcg_card/card = new(get_turf(src), cardtype) + if(card.card_datum.name == "Stupid Coder") + qdel(card) + continue + card.forceMove(src) + cards.Add(card) + +/obj/item/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\ + Welcome to the Exciting world of Tactical Card Game! Sponsored by Nanotrasen Edu-tainment Devision. \n \ + Core Rules: \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 \ + + 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 \ + + 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 \ + + Win condition is simple - kill your opponent's hero by depleting all of their 20 lifeshards. \n \ + + Gameplay Phases: \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 \ + + 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 \ + + 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 \ + + 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 \ + + 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 \ + + 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 \ + + Card Breakdown: \n \ + + Within the game, there are 3 kinds of cards (So far), Unit, Equipment and Spell cards. \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 \ + + 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 \ + + 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 \ + + Card Subtypes: \n \ + + Card effects: \n \ + Asimov - Unit cannot attack units with Human subtype \n \ + Changeling - Unit posesses all the subtypes at the same time \n \ + Greytide - On summon, unit gains amount of power equal to amount of other units with Greytide for 1 turn \n \ + Holy - Unit can't be targeted by spells \n \ + Taunt - All opposing unit attacks must be directed towards the unit with Taunt. \n \ + First Strike - This unit attacks first. If attacked unit is dead, unit doesn't recieve damage from it. \n \ + Deadeye - This unit can always hit opponents, regardless of effects or immunities. \n \ + Squad Tactics - When this unit attacks an opponent's unit and defeats it in combat, the owner of the defeated card takes 1 lifeshard of damage from combat. \n \ + Immunity - The unit cannot be affected by card effects or combat of its immunity type. This includes both friendly and opposing effects. \n \ + Fury - The unit must attack at every possibility. \n \ + 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 \ + + Card Combat: \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 \ + + 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 \ + + 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 + name = "cardboard card cutout" + desc = "A small piece of cardboard shaped as a TCG card." + icon = 'icons/obj/tcg/misc.dmi' + icon_state = "template" + +/datum/reagent/card_powder/reaction_obj(obj/O, reac_volume) + if(istype(O, /obj/item/cardboard_card)) + var/list/possible_cards = list() + for(var/card_series in COMMON_SERIES) + for(var/card_type in subtypesof(card_series)) + var/datum/tcg_card/card = new card_type + if(card.rarity == rarity) + possible_cards.Add(card_type) + qdel(card) + if(length(possible_cards)) + new /obj/item/tcg_card(get_turf(O), pick(possible_cards), TRUE) + qdel(O) + + . = ..() + +#undef COMMON_SERIES +#undef TAPPED_ANGLE +#undef UNTAPPED_ANGLE diff --git a/code/modules/tcg/pack_1.dm b/code/modules/tcg/pack_1.dm new file mode 100644 index 0000000000..a3920fcdaa --- /dev/null +++ b/code/modules/tcg/pack_1.dm @@ -0,0 +1,1431 @@ +/datum/tcg_card/pack_1 + pack = 'icons/obj/tcg/pack_1.dmi' + +//COMMAND + +/datum/tcg_card/pack_1/captain + name = "Captain" + desc = "Nanotrasen hires a captain for every station. However, most of the time they just drink wishkey and secure the disk." + rules = "Human. Tap this card for 1 mana: inflict -1/-1 to an opposing creature card." + icon_state = "captain" + + mana_cost = 7 + attack = 5 + health = 5 + + faction = "Command" + rarity = "Epic" + card_type = "Unit" + +/datum/tcg_card/pack_1/captain_hardsuit + name = "Apadyne Technologies Mk.2 R.I.O.T. Suit (Captain's Version)" + desc = "A heavily customised Apadyne Technologies Mk.2 R.I.O.T. Suit, rebuilt and refitted to Nanotrasen's highest standards for issue to Station Captains." + rules = "On equip: Equipped unit gains +1/+1 for one turn" + icon_state = "captain_hardsuit" + + mana_cost = 3 + attack = -1 + health = 5 + + faction = "Command" + rarity = "Legendary" + card_type = "Equipment" + +/datum/tcg_card/pack_1/hop + name = "Head of Personnel" + desc = "The head of the Cargo and Service Departments, guardian of all access, and Ian's lovable, yet dumb, sidekick." + rules = "Human. Blocker. Once per turn: A friendly card of your choice attacks twice." + icon_state = "hop" + + mana_cost = 7 + attack = 4 + health = 3 + + faction = "Command" + rarity = "Rare" + card_type = "Unit" + +/datum/tcg_card/pack_1/ian_hop + name = "Head of Ians" + desc = "What can be better than a corgi? A corgi with all access and HoP's hat!" + rules = "On summon: Summon a Command unit for free." + icon_state = "hop_ian" + + mana_cost = 5 + attack = 0 + health = 4 + + faction = "Command" + rarity = "Epic" + card_type = "Unit" + +/datum/tcg_card/pack_1/cmo + name = "Chief Medical Officer" + desc = "Head of the medical department, the CMO is expected to maintain the standards of his underlings." + rules = "Human. Whenever a Medical unit gains power, it gains +1 more." + icon_state = "cmo" + + mana_cost = 5 + attack = 4 + health = 4 + + faction = "Command" + rarity = "Common" + card_type = "Unit" + +/datum/tcg_card/pack_1/cmo_suit + name = "DeForest Medical Corporation 'Lifesaver' Carapace" + desc = "An advanced voidsuit designed for emergency medical personnel. Features include a built-in medical HUD and advanced medical gauntlets." + rules = "Tap this card: Re-equip 'DeForest Medical Corporation 'Lifesaver' Carapace' on a different friendly creature" + icon_state = "cmo_hardsuit" + + mana_cost = 3 + attack = 1 + health = 3 + + faction = "Command" + rarity = "Rare" + card_type = "Equipment" + +/datum/tcg_card/pack_1/hos + name = "Head of Security" + desc = "Nanotrasen hires most heads of staff based on their qualifications as being amicable, good at conflict resolution, ability to handle high-stakes situations, humanity, and desire to learn. Heads of Security only need a highschool degree." + rules = "Human. All opponent's cards cost 1 more until Head Of Security is removed from the battlefield." + icon_state = "hos" + + mana_cost = 7 + attack = 4 + health = 4 + + faction = "Command" + rarity = "Rare" + card_type = "Unit" + +/datum/tcg_card/pack_1/hos_suit + name = "Apadyne Technologies 'Tyrant' Class Hardshell" + desc = "The distinctive shape of the Tyrant Class Hardshell is caused, in part, by the large amount of kevlar reinforcement and the ablative armour layer. Perhaps more importantly, it also looks rad." + rules = "Grant the equipped card Fury." + icon_state = "hos_hardsuit" + + mana_cost = 6 + attack = 4 + health = 2 + + faction = "Command" + rarity = "Epic" + card_type = "Equipment" + +/datum/tcg_card/pack_1/ce + name = "Chief Engineer" + desc = "The Chief Engineer is in charge of keeping the station powered and intact. Most of CE's usually fail this task." + rules = "Human. Protect a friendly card from one spell." + icon_state = "ce" + + mana_cost = 6 + attack = 3 + health = 6 + + faction = "Command" + rarity = "Rare" + card_type = "Unit" + +/datum/tcg_card/pack_1/ce_suit + name = "Nakamura Engineering R.I.G.Suit (Advanced)" + desc = "An updated version of Nakamura Engineering's R.I.G.Suit fitted with advanced radiation shielding and extra armour." + rules = "On equip: Equipped creature is protected from one spell." + icon_state = "ce_hardsuit" + + mana_cost = 3 + attack = 0 + health = 3 + + faction = "Command" + rarity = "Rare" + card_type = "Equipment" + +/datum/tcg_card/pack_1/rd + name = "Research Director" + desc = "The Research Director is the head of the Science Division and is responsible for shockingly directing research." + rules = "Human. All Science card activate their effects twice." + icon_state = "rd" + + mana_cost = 7 + attack = 2 + health = 5 + + faction = "Command" + rarity = "Common" + card_type = "Unit" + +/datum/tcg_card/pack_1/rd_suit + name = "Nakamura Engineering B.O.M.B.Suit" + desc = "The Nakamura Engineering B.O.M.B.Suit is an innovative combination of a R.I.G.Suit and a bomb suit perfect for toxins research." + rules = "Reduces all incoming damage for 1. Does not work if damage is lethal." + icon_state = "rd_hardsuit" + + mana_cost = 3 + attack = 0 + health = 0 + + faction = "Command" + rarity = "Rare" + card_type = "Equipment" + + +//COMMAND END + +//SILICONS + +/datum/tcg_card/pack_1/ai + name = "AI" + desc = "The latest generation of NT's top secret artificial intelligence project this time with actual human brains in a jar! Don't tell the press though." + rules = "Asimov. All silicon cards gain +1/0 while this creature is alive." + icon_state = "ai" + + mana_cost = 5 + attack = 3 + health = 6 + + faction = "Silicon" + rarity = "Epic" + card_type = "Unit" + +/datum/tcg_card/pack_1/pai + name = "Personal AI Device" + desc = "Personal AI Devices are able to take the form of many household pets to provide a homely sense of comfort and companionship to their owners." + rules = "Asimov. Taunt." + icon_state = "pai" + + mana_cost = 2 + attack = 1 + health = 1 + + faction = "Silicon" + rarity = "Common" + card_type = "Unit" + +/datum/tcg_card/pack_1/cyborg + name = "Cyborg" + desc = "Created as part of humanity's first foray into artificial intelligence the original cyborg models used organic parts in lieu of sophisticated artificial brains." + rules = "Asimov." + icon_state = "borg_basic" + + mana_cost = 2 + attack = 3 + health = 3 + + faction = "Silicon" + rarity = "Common" + card_type = "Unit" + +/datum/tcg_card/pack_1/cyborg_clown + name = "Cyborg (Clown Shell)" + desc = "The clown shell is a new development in cyborg technology designed to capture the joyous hijinks of the station clown in a notably more macabre and disturbing fashion." + rules = "Asimov. Taunt." + icon_state = "borg_clown" + + mana_cost = 2 + attack = 2 + health = 4 + + faction = "Silicon" + rarity = "Common" + card_type = "Unit" + +/datum/tcg_card/pack_1/cyborg_engi + name = "Cyborg (Engineering Shell)" + desc = "A common sight on Nanotrasen Stations Engineering Shells maintain critical station systems in hazardous conditions." + rules = "Asimov." + icon_state = "borg_engi" + + mana_cost = 2 + attack = 4 + health = 2 + + faction = "Silicon" + rarity = "Rare" + card_type = "Unit" + +/datum/tcg_card/pack_1/cyborg_sec + name = "Cyborg (Security Shell)" + desc = "Following an incident in 2554 the Security Cyborg Shell was unilaterally phased out and replaced by the Peacekeeper. Nonetheless many units remain in service with various other organisations such as private militaries." + rules = "Asimov. Can attack humans, but deals only 1 damage." + icon_state = "borg_sec" + + mana_cost = 6 + attack = 4 + health = 2 + + faction = "Silicon" + rarity = "Rare" + card_type = "Unit" + +/datum/tcg_card/pack_1/cyborg_sec + name = "Cyborg (Peacekeeper Shell)" + desc = "After the unilateral phasing out of Security Shells in 2554 following mass reports of cyborg-on-human violence the Peacekeeper Shell was introduced as a stopgap solution until the problems could be resolved." + rules = "Asimov. Tap this card: Restore 2 health for a friendly creature." + icon_state = "borg_peace" + + mana_cost = 2 + attack = 4 + health = 3 + + faction = "Silicon" + rarity = "Common" + card_type = "Unit" + +/datum/tcg_card/pack_1/cyborg_med + name = "Cyborg (Medical Shell)" + desc = "A state of the art medical shell for when biological life just can't take care of itself. Comes equipped with built-in surgical equipment and all the medicated lollipops you could ever want." + rules = "Asimov. Loses 1 power for every Human on opponent's field." + icon_state = "borg_med" + + mana_cost = 2 + attack = 4 + health = 3 + + faction = "Silicon" + rarity = "Common" + card_type = "Unit" + +/datum/tcg_card/pack_1/cyborg_service + name = "Cyborg (Service Shell)" + desc = "Sometimes a cyborg just needs to show a bit of flamboyance you know?" + rules = "Asimov. Gains +2/+2 when it's the only card on your field." + icon_state = "borg_service" + + mana_cost = 1 + attack = 0 + health = 1 + + faction = "Silicon" + rarity = "Common" + card_type = "Unit" + +/datum/tcg_card/pack_1/cyborg_janitor + name = "Cyborg (Custodial Shell)" + desc = "A powerful state of the act cleaning machine. They exist to eradicate stains snag garbage and replace lights forever. We are legally obligated by the Janitor's Union to state that these machines are no replacement for a flesh-and-blood janitor." + rules = "Asimov. After tapping this card, tap an opponent's Human card as well." + icon_state = "borg_janitor" + + mana_cost = 2 + attack = 1 + health = 3 + + faction = "Silicon" + rarity = "Common" + card_type = "Unit" + +/datum/tcg_card/pack_1/cyborg_miner + name = "Cyborg (Mining Shell)" + desc = "Fitted with a drill and tracks the Mining Shell is designed to hold up to the rigours of mining be that on the hellish surface of Indecipheres or in the silent vacuum of the asteroid belt." + rules = "Asimov. Gain 1 additional mana every turn." + icon_state = "borg_miner" + + mana_cost = 2 + attack = 3 + health = 1 + + faction = "Silicon" + rarity = "Rare" + card_type = "Unit" + +//SILICONS END + +//CIVILIANS + +/datum/tcg_card/pack_1/assistant + name = "Assistant" + desc = "The lowest ladder on the Nanotrasen Employment Ladder, Assistants are employed to help out with tasks deemed 'too menial for robots'." + rules = "Greytide." + icon_state = "assistant" + + mana_cost = 1 + attack = 1 + health = 1 + + faction = "Civilian" + rarity = "Common" + card_type = "Unit" + +/datum/tcg_card/pack_1/greytider + name = "Greytider" + desc = "The lowest ladder on the Nanotrasen Employment Ladder, Assistants are employed to help out with tasks deemed 'too menial for robots'." + rules = "Greytide. Instead of getting +1/+1 on the first turn, get it permanently." + icon_state = "greytider" + + mana_cost = 1 + attack = 2 + health = 1 + + faction = "Civilian" + rarity = "Rare" + card_type = "Unit" + +/datum/tcg_card/pack_1/bartender + name = "Bartender" + desc = "Prior to the introduction of on-station psychologists the Bartender served to alleviate many employees' woes and fears. Remember always drink responsibly." + rules = "" + icon_state = "bartender" + + mana_cost = 3 + attack = 3 + health = 2 + + faction = "Civilian" + rarity = "Common" + card_type = "Unit" + +/datum/tcg_card/pack_1/botanist + name = "Botanist" + desc = "The Botanist is in charge of keeping the station's food supply happy healthy and preferably not laced with hallucinogens." + rules = "" + icon_state = "botanist" + + mana_cost = 1 + attack = 1 + health = 4 + + faction = "Civilian" + rarity = "Common" + card_type = "Unit" + +/datum/tcg_card/pack_1/botanist + name = "Botanist" + desc = "The Botanist is in charge of keeping the station's food supply happy healthy and preferably not laced with hallucinogens." + rules = "" + icon_state = "botanist" + + mana_cost = 1 + attack = 1 + health = 4 + + faction = "Civilian" + rarity = "Common" + card_type = "Unit" + +/datum/tcg_card/pack_1/chaplain + name = "Chaplain" + desc = "Every station should have it's own chaplain for religious purposes. Keyword is 'Should'." + rules = "Holy" + icon_state = "chaplain" + + mana_cost = 2 + attack = 2 + health = 3 + + faction = "Civilian" + rarity = "Common" + card_type = "Unit" + +/datum/tcg_card/pack_1/inquisitor + name = "Inquisitor's Hardsuit" + desc = "Nanotrasen officially doesn't believe in ghosts magic or anything that can't be solved with science. When you see someone show up in one of these let that remind you of that fact." + rules = "Holy. First Strike." + icon_state = "inquisitor" + + mana_cost = 4 + attack = 2 + health = 2 + + faction = "Civilian" + rarity = "Epic" + card_type = "Equipment" + +/datum/tcg_card/pack_1/janitor + name = "Janitor" + desc = "A true testament to futility they clean and they clean and they clean knowing that there's no way they can clean it all. Yet they perservere knowing that without them the crew would simply give in to their base animalistic nature." + rules = "Taunt" + icon_state = "janitor" + + mana_cost = 1 + attack = 1 + health = 1 + + faction = "Civilian" + rarity = "Common" + card_type = "Unit" + +/datum/tcg_card/pack_1/lawyer + name = "Lawyer" + desc = "Nanotrasen knows the value of a good lawyer. That's why they're all working hard at our home offices defending us from frivolous labor suits from lazy no-good employees who should be working hard instead of slacking off reading trading cards." + rules = "When an opponent attacks with a creature with 3 or more power this card gains Taunt." + icon_state = "lawyer" + + mana_cost = 2 + attack = 0 + health = 4 + + faction = "Civilian" + rarity = "Common" + card_type = "Unit" + +/datum/tcg_card/pack_1/clown + name = "Clown" + desc = "Every Nanotrasen station has a clown on board as high command believes that a source of entertainment will reduce instances of murder-suicide on board Spinward Stations. The results of this hypothesis are as of yet unproven." + rules = "Taunt. When killed, attacking creature dies as well" + icon_state = "clown" + + mana_cost = 3 + attack = 2 + health = 4 + + faction = "Civilian" + rarity = "Rare" + card_type = "Unit" + +/datum/tcg_card/pack_1/clown_hardsuit + name = "HONK Ltd. Entertainment Voidsuit" + desc = "The most advanced clown suit produced by HONK Ltd. the Entertainment Voidsuit is designed to withstand extreme conditions while still maintaining the aesthetic expected of clowns." + rules = "Give the equipped unit Taunt." + icon_state = "clown_hardsuit" + + mana_cost = 2 + attack = 1 + health = 5 + + faction = "Civilian" + rarity = "Legendary" + card_type = "Equipment" + +/datum/tcg_card/pack_1/mime + name = "Mime" + desc = "Si vous regardez attentivement dans les yeux d'un mime vous pouvez voir le tourment sans fin derrière leur façade silencieuse. C'est vraiment tragique." + rules = "Tap this card: Pick an opponent's card and nullify it's effect until it leaves play." + icon_state = "mime" + + mana_cost = 1 + attack = 2 + health = 1 + + faction = "Civilian" + rarity = "Rare" + card_type = "Unit" + +/datum/tcg_card/pack_1/cook + name = "Cook" + desc = "Every Nanotrasen chef is trained in 3 cuisines of their choosing upon being hired alongside the closely guarded secret of Close Quarters Cooking." + rules = "First Strike. When attacked, gain +1/0." + icon_state = "cook" + + mana_cost = 3 + attack = 3 + health = 2 + + faction = "Civilian" + rarity = "Common" + card_type = "Unit" + +/datum/tcg_card/pack_1/curator + name = "Curator" + desc = "In Nanotrasen polls the Curator has ranked as the most pointless job on station much to the ire of the Curator's union. Thankfully we don't have to listen to them." + rules = "On Summon: Draw a card. If it's a spell, discard it." + icon_state = "curator" + + mana_cost = 2 + attack = 1 + health = 1 + + faction = "Civilian" + rarity = "Common" + card_type = "Unit" + +/datum/tcg_card/pack_1/ian + name = "Ian" + desc = "This adorable corgi has become the defacto mascot of the Spinward Stations to many. He comes in many forms many sizes and many shapes but he's still just as lovable. Hand wash only." + rules = "Holy. Taunt." + icon_state = "ian" + + mana_cost = 3 + attack = 0 + health = 2 + + faction = "Civilian" + rarity = "Rare" + card_type = "Unit" + +//CIVILIAN END + +//SECURITY + +/datum/tcg_card/pack_1/sec_officer + name = "Security Officer" + desc = "Nanotrasen would like to remind all employees to support their station security team; remember the boys in red keep you safe!" + rules = "Squad Tactics." + icon_state = "officer" + + mana_cost = 3 + attack = 2 + health = 2 + + faction = "Security" + rarity = "Common" + card_type = "Unit" + +/datum/tcg_card/pack_1/warden + name = "Warden" + desc = "The Warden is tasked with the herculean (and futile) feat of defending the armory and brig and never leaving his post no matter the situation." + rules = "Squad Tactics. Blocker." + icon_state = "warden" + + mana_cost = 4 + attack = 2 + health = 4 + + faction = "Security" + rarity = "Rare" + card_type = "Unit" + +/datum/tcg_card/pack_1/detective + name = "Security Officer" + desc = "Nanotrasen hires nothing but the best detectives to investigate crime on our stations. A penchant for cigarettes and outdated fashion isn't mandatory but is appreciated." + rules = "Deadeye." + icon_state = "detective" + + mana_cost = 5 + attack = 3 + health = 2 + + faction = "Security" + rarity = "Common" + card_type = "Unit" + +/datum/tcg_card/pack_1/officer_ethereal + name = "Security Officer(Ethereal)" + desc = "A trained officer with BlueShift equipment. Wait, is he a red boy or a blue boy?" + rules = "Squad Tactics. On summon: This character can't be attacked for the first turn." + icon_state = "officer_ethereal" + + mana_cost = 6 + attack = 4 + health = 4 + + faction = "Security" + rarity = "Rare" + card_type = "Unit" + +//SECURITY END + +//RESEARCH AND DEVELOPMENT + +/datum/tcg_card/pack_1/scientist + name = "Scientist" + desc = "Rumours that Nanotrasen hires 'mad scientists' are greatly exaggerated. Scientists are regularly screened to ensure that their insanity remains within acceptable limits." + rules = "When this card is targeted by an opponent's single target spell you gain 1 lifeshard." + icon_state = "scientist" + + mana_cost = 4 + attack = 1 + health = 2 + + faction = "Research" + rarity = "Common" + card_type = "Unit" + +/datum/tcg_card/pack_1/scientist_moth + name = "Scientist(Moth)" + desc = "Moths are a common sight in Nanotrasen research departments acting as integral ideas guys for new clothing designs and lighting innovations." + rules = "" + icon_state = "scientist_moth" + + mana_cost = 1 + attack = 2 + health = 2 + + faction = "Research" + rarity = "Common" + card_type = "Unit" + +/datum/tcg_card/pack_1/roboticist + name = "Roboticist" + desc = "The roboticist's work is as close as Nanotrasen legally allows its employees to come to necromancy." + rules = "If a Asimov card on your side of the field is destroyed you may pay 2 mana and tap this card: Return that card to your hand." + icon_state = "roboticist" + + mana_cost = 3 + attack = 2 + health = 2 + + faction = "Research" + rarity = "Rare" + card_type = "Unit" + +/datum/tcg_card/pack_1/monkey + name = "Monkey" + desc = "Nanotrasen seeks to phase out animal testing by 2570 in accordance with new TerraGov legislation. This will be replaced with more ethical solutions such as computer simulations or experimentation on Assistants." + rules = "Greytide. This card is considered Human with a Geneticist on your side of the field." + icon_state = "monkey" + + mana_cost = 1 + attack = 1 + health = 1 + + faction = "Research" + rarity = "Common" + card_type = "Unit" + +/datum/tcg_card/pack_1/geneticist + name = "Geneticist" + desc = "Geneticists are tasked with manipulating human DNA to produce special effects. Nanotrasen maintains a strict 'no superhero' policy for mutations following the Superhero Civil War of 2150." + rules = "Tap this card and pay 3 mana: Give a friendly creature Human until this card leaves the field." + icon_state = "geneticist" + + mana_cost = 3 + attack = 3 + health = 4 + + faction = "Research" + rarity = "Common" + card_type = "Unit" + +/datum/tcg_card/pack_1/borgi + name = "Borgi Ian" + desc = "While Ian's cyborg costume is very convincing we at the NTED would like to remind all employees that Ian has not been experimented on." + rules = "Asimov. You may sacrifice this card in play: Summon a Silicon type card from your hand worth up to double this card's cost." + icon_state = "ian_robot" + + mana_cost = 2 + attack = 0 + health = 3 + + faction = "Research" + rarity = "Rare" + card_type = "Unit" + +//SCIENCE END + +//MEDICAL + +/datum/tcg_card/pack_1/doctor + name = "Medical Doctor" + desc = "Nanotrasen's doctors are well known for their ability to treat almost any ailment known to mankind... as well as causing a fair few in the process." + rules = "Tap this card: Select a card that has less attack than this card from your graveyard and summon it to your side of the field." + icon_state = "doctor" + + mana_cost = 3 + attack = 2 + health = 3 + + faction = "Medical" + rarity = "Common" + card_type = "Unit" + +/datum/tcg_card/pack_1/runtime + name = "Runtime" + desc = "Runtime is the CMO's personal feline companion and is well known for her laziness. It's said that opening a tin of tuna anywhere on the station will bring her running." + rules = "You may sacrifice this card: reduce the cost of summoning a Medical card this turn by 2 mana." + icon_state = "runtime" + + mana_cost = 3 + attack = 0 + health = 1 + + faction = "Medical" + rarity = "Rare" + card_type = "Unit" + +/datum/tcg_card/pack_1/chemist + name = "Chemist" + desc = "Chemists are encouraged to not set up illicit methamphetamine factories on the company's dime." + rules = "Tap this card: flip a coin. If heads: a friendly Medical card gains 0/+2. If tails an opponents unit of your choice gains +2/0." + icon_state = "chemist" + + mana_cost = 2 + attack = 0 + health = 3 + + faction = "Medical" + rarity = "Rare" + card_type = "Unit" + +/datum/tcg_card/pack_1/virologist + name = "Virologist" + desc = "Officially the virologist is present on station to deal with novel diseases and ailments that originate from deep space. As everyone knows this is not what the virologist actually does." + rules = "" + icon_state = "virologist" + + mana_cost = 3 + attack = 5 + health = 1 + + faction = "Medical" + rarity = "Common" + card_type = "Unit" + +/datum/tcg_card/pack_1/paramedic + name = "Paramedic" + desc = "Nanotrasen encourages all paramedics to think of others before themselves- if this means running through a plasma fire to save a colleague so be it." + rules = "Taunt, First Strike" + icon_state = "paramedic" + + mana_cost = 3 + attack = 2 + health = 3 + + faction = "Medical" + rarity = "Common" + card_type = "Unit" + +//MEDICAL END + +//ENGINEERING + +/datum/tcg_card/pack_1/engineer + name = "Station Engineer" + desc = "Station Engineers maintain the intricate and delicate web of machinery that keeps you and everyone else aboard your station alive. No pressure there then." + rules = "Tap this card: Reduce the first hit taken by an ally to zero." + icon_state = "engineer" + + mana_cost = 4 + attack = 2 + health = 2 + + faction = "Engineering" + rarity = "Common" + card_type = "Unit" + +/datum/tcg_card/pack_1/engi_hardsuit + name = "Nakamura Engineering's R.I.G.Suit" + desc = "Nakamura Engineering's R.I.G. is a hardsuit, specifically designed for engineers working in hostile enviroments. It features good armor and is rad-proof." + rules = "" + icon_state = "engineer_hardsuit" + + mana_cost = 2 + attack = 0 + health = 3 + + faction = "Engineering" + rarity = "Common" + card_type = "Equipment" + +/datum/tcg_card/pack_1/engineer_plasmaman + name = "Station Engineer (Plasmaman)" + desc = "The ever industrious plasmamen are well suited to engineering work due to their natural radiation resistance." + rules = "Immune to all spells except Security and Syndicate ones." + icon_state = "engineer_plasmeme" + + mana_cost = 5 + attack = 2 + health = 4 + + faction = "Engineering" + rarity = "Rare" + card_type = "Unit" + +/datum/tcg_card/pack_1/atmos_tech + name = "Atmospheric Technician" + desc = "The Atmospheric Technicians are tasked with keeping the station's air clean breathable and most importantly devoid of plasma." + rules = "On Summon: Search your deck for an Engineering Spell card and add it to your hand. Shuffle your deck afterward." + icon_state = "atmos_tech" + + mana_cost = 4 + attack = 2 + health = 3 + + faction = "Engineering" + rarity = "Common" + card_type = "Unit" + +/datum/tcg_card/pack_1/atmos_hardsuit + name = "Nakamura Atmospherics's R.I.G.Suit" + desc = "Nakamura Atmospherics's R.I.G. is just an old modified Engineering R.I.G.Suit that lacks rad-protection. Some technicans painted it blue and now it's 'fireproof'." + rules = "Equipped creature gains immunity to engineering spells." + icon_state = "atmos_tech_hardsuit" + + mana_cost = 2 + attack = 0 + health = 2 + + faction = "Engineering" + rarity = "Rare" + card_type = "Equipment" + +//ENGINEERING END + +//CARGO + +/datum/tcg_card/pack_1/cargo_tech + name = "Cargo Technician" + desc = "The grunts of Cargo. Any reports that Cargo Technicians are frequently overcome by revolutionary fervour are exaggerated." + rules = "Once per turn: Give this card -1/0 and gain 1 mana." + icon_state = "cargo_tech" + + mana_cost = 2 + attack = 3 + health = 1 + + faction = "Cargo" + rarity = "Common" + card_type = "Unit" + +/datum/tcg_card/pack_1/shaft_miner + name = "Shaft Miner" + desc = "When the station needs materials these are the guys who risk their lives bravely pioneering the wastes of Indecipheres to bring them in." + rules = "Tap this card: Draw one card. If it's not a spell, discard it." + icon_state = "miner" + + mana_cost = 6 + attack = 6 + health = 4 + + faction = "Cargo" + rarity = "Rare" + card_type = "Unit" + +/datum/tcg_card/pack_1/citrus + name = "Citrus" + desc = "Cargo's happy sloth pal. Known for his cute sweater and always getting in the way." + rules = "Taunt. Tap this card: Tap an opponent's card until the start of your next turn." + icon_state = "citrus" + + mana_cost = 2 + attack = 0 + health = 3 + + faction = "Cargo" + rarity = "Common" + card_type = "Unit" + +/datum/tcg_card/pack_1/quartermaster + name = "Quartermaster" + desc = "Every Nanotrasen station has a Quartermaster who controls the flow of cargo to and from the station and by extension to and from the hands of the crew. He's not given the distinction of being a head though. His job isn't hard enough." + rules = "Permanently tap this card. All cargo cards on your side gain +2/+2 until this card leaves the play." + icon_state = "quartermaster" + + mana_cost = 10 + attack = 4 + health = 4 + + faction = "Cargo" + rarity = "Rare" + card_type = "Unit" + +/datum/tcg_card/pack_1/explorer + name = "Explorer" + desc = "The Nanotrasen Explorers Corps boldly goes where humanity has never gone before. Or would if they weren't buried under mounds of bureaucracy." + rules = "Tap this card: Flip a coin if heads gain 4 mana this turn, if tails tap this card for 2 turns." + icon_state = "explorer" + + mana_cost = 2 + attack = 3 + health = 3 + + faction = "Cargo" + rarity = "Legendary" + card_type = "Unit" + +//CARGO END + +//CENTCOM + +/datum/tcg_card/pack_1/intern + name = "Intern" + desc = "All Nanotrasen interns come with 3 things: A resume a desire to learn and vague promises that they're getting paid at some point. So don't be too rough on them." + rules = "First Strike. Greytide." + icon_state = "intern" + + mana_cost = 1 + attack = 1 + health = 1 + + faction = "Centcom" + rarity = "Common" + card_type = "Unit" + +/datum/tcg_card/pack_1/ert_command + name = "NT P.A.V. Suit (Command)" + desc = "Issued to members of Emergency Response Teams the P.A.V. Suit gives superior protection from any threat the galaxy can throw at it. This particular model is outfitted with a sidearm holster and a sleek blue finish." + rules = "While equipped give the equipped unit Squad Tactics and First Strike." + icon_state = "ert_command" + + mana_cost = 2 + attack = 2 + health = 2 + + faction = "Centcom" + rarity = "Epic" + card_type = "Equipment" + +/datum/tcg_card/pack_1/ert_sec + name = "NT P.A.V. Suit (Security)" + desc = "Issued to members of Emergency Response Teams the P.A.V. Suit gives superior protection from any threat the galaxy can throw at it. This particular model is outfitted with bulletproof padding and an intimidating red finish." + rules = "While equipped give the equipped unit Squad Tactics." + icon_state = "ert_sec" + + mana_cost = 2 + attack = 2 + health = 1 + + faction = "Centcom" + rarity = "Rare" + card_type = "Equipment" + +/datum/tcg_card/pack_1/ert_med + name = "NT P.A.V. Suit (Medical)" + desc = "Issued to members of Emergency Response Teams the P.A.V. Suit gives superior protection from any threat the galaxy can throw at it. This particular model is outfitted with a sterile coating and a calming white finish." + rules = "While equipped give the equipped unit Squad Tactics." + icon_state = "ert_med" + + mana_cost = 2 + attack = 1 + health = 2 + + faction = "Centcom" + rarity = "Common" + card_type = "Equipment" + +/datum/tcg_card/pack_1/ert_engi + name = "NT P.A.V. Suit (Engineering)" + desc = "Issued to members of Emergency Response Teams the P.A.V. Suit gives superior protection from any threat the galaxy can throw at it. This particular model is outfitted with a welding screen and a flashy yellow finish." + rules = "While equipped give the equipped unit Squad Tactics." + icon_state = "ert_engi" + + mana_cost = 1 + attack = 1 + health = 2 + + faction = "Centcom" + rarity = "Common" + card_type = "Equipment" + +/datum/tcg_card/pack_1/deathsquad + name = "Deathsquad Officer" + desc = "There were rumors about 'Deathsquads' killing station where something horrible happened, but we remind you that's it's just a lie." + rules = "Taunt. First Strike." + icon_state = "deathsquad" + + mana_cost = 8 + attack = 8 + health = 6 + + faction = "Centcom" + rarity = "Epic" + card_type = "Unit" + +//CENTCOM END + +//ANTAGONISTS + +/datum/tcg_card/pack_1/changeling + name = "Armored Changeling" + desc = "The strange creatures known as changelings have been known to develop natural armour as a defense mechanism when in combat." + rules = "Changeling." + icon_state = "changeling" + + mana_cost = 6 + attack = 2 + health = 8 + + faction = "Syndicate" + rarity = "Rare" + card_type = "Unit" + +/datum/tcg_card/pack_1/chrono_legionare + name = "Chrono Legionare" + desc = "Currently in the earliest stages of development the Chrono Legionnaire project is expected to weaponise time itself." + rules = "If this card is destroyed or discarded flip 3 coins. If the result has 2 or more heads add this card back to your hand. Otherwise send it to your graveyard." + icon_state = "chrono_legionare" + + mana_cost = 4 + attack = 6 + health = 2 + + faction = "Syndicate" + rarity = "Epic" + card_type = "Unit" + +/datum/tcg_card/pack_1/abductor_armor + name = "Combat Abductor Armor" + desc = "Recovered from the strange alien species known as the Abductors this armour is made from an extremely tough yet flexible material that has been dubbed as Alien Alloy by researchers." + rules = "Give equipped unit immunity to spells for 3 turns. Unequipped after 3 turns." + icon_state = "abductor" + + mana_cost = 6 + attack = 1 + health = 2 + + faction = "Syndicate" + rarity = "Common" + card_type = "Equipment" + +/datum/tcg_card/pack_1/wizard + name = "Wizard" + desc = "A strange men(or golem) wearing blue robes. For some reason, he looks like a total nerd." + rules = "Flip a coin every turn. If tails, deal 2 damage to any enemy unit except Holy ones. If heads, deal 2 damage to self." + icon_state = "wizard" + + mana_cost = 8 + attack = 6 + health = 4 + + faction = "Syndicate" + rarity = "Rare" + card_type = "Unit" + +/datum/tcg_card/pack_1/abductor_armor + name = "Wizard Federation Standard Issue Hardsuit" + desc = "Seemingly reverse engineered from captured engineering hardsuits the iconic Wizard Federation Hardsuit is a spectacular melding of technology and magic." + rules = "On Equip: The equipped creature cannot attack targets with Holy." + icon_state = "wizard_hardsuit" + + mana_cost = 1 + attack = 3 + health = 1 + + faction = "Syndicate" + rarity = "Rare" + card_type = "Equipment" + +/datum/tcg_card/pack_1/swarmer + name = "Swarmer" + desc = "Leading researchers theorise that Swarmers were designed as some kind of vanguard for an alien invasion force which seemingly has never materialised." + rules = "Greytide." + icon_state = "swarmer" + + mana_cost = 1 + attack = 1 + health = 1 + + faction = "Syndicate" + rarity = "Common" + card_type = "Unit" + +/datum/tcg_card/pack_1/swarmer_beacon + name = "Swarmer Beacon" + desc = "A strange device that can construct swarmers." + rules = "Every turn: Draw a card. If it's a Swarmer, play it for free. Else, discard it." + icon_state = "swarmer_beacon" + + mana_cost = 4 + attack = 0 + health = 1 + + faction = "Syndicate" + rarity = "Epic" + card_type = "Unit" + +/datum/tcg_card/pack_1/nukie + name = "Nuclear Operative" + desc = "The frontline grunts of the syndicate army Nuclear Operatives are typically well trained and equipped for their grim duty." + rules = "Squad Tactics." + icon_state = "nukie" + + mana_cost = 4 + attack = 4 + health = 2 + + faction = "Syndicate" + rarity = "Rare" + card_type = "Unit" + +/datum/tcg_card/pack_1/nukie_elite + name = "Elite Syndicate Nuclear Stormtrooper" + desc = "The best of the best of the syndicate troops elite stormtroopers can be distinguished by their black armour. Shoot on sight ask questions later!" + rules = "Squad Tactics. Fury." + icon_state = "nukie_elite" + + mana_cost = 7 + attack = 5 + health = 5 + + faction = "Syndicate" + rarity = "Epic" + card_type = "Unit" + +/datum/tcg_card/pack_1/clockwork_cultist + name = "Ratvarian Clockwork Cuirass" + desc = "Fashioned from paranormally reinforced brass the Ratvar Cult's clockwork armour is as beautiful as it is heretical." + rules = "While equipped give the equipped unit Clockwork." + icon_state = "clockwork_cultist" + + mana_cost = 4 + attack = 2 + health = 2 + + faction = "Syndicate" + rarity = "Rare" + card_type = "Equipment" + +/datum/tcg_card/pack_1/revenant + name = "Revenant" + desc = "The revenant is a spirit of pure hatred kept alive by drawing the life force of its enemies." + rules = "When a unit on dies Revenant gains 1/0." + icon_state = "revenant" + + mana_cost = 3 + attack = 2 + health = 3 + + faction = "Syndicate" + rarity = "Common" + card_type = "Unit" + +/datum/tcg_card/pack_1/angry_slime + name = "Crazy Slime" + desc = "An agressive slime who seeks blood. You totally should extinguish him." + rules = "When attacking, search your deck for Crazy Slime and add it to your hand. Shuffle your deck afterwards." + icon_state = "angry_slime" + + mana_cost = 2 + attack = 1 + health = 1 + + faction = "Syndicate" + rarity = "Common" + card_type = "Unit" + +//ANTAGONISTS END + +//SPELLS + +/datum/tcg_card/pack_1/adrenals + name = "Adrenals" + desc = "A potent mixture of stimulants designed to enhance a soldier's ability in the field. Technically illegal in Terragov territory but since when has that stopped anyone?" + rules = "Grant +2/+1 to a friendly unit." + icon_state = "adrenals" + + mana_cost = 1 + + faction = "Medical" + rarity = "Common" + card_type = "Spell" + +/datum/tcg_card/pack_1/defib + name = "Defibrillator" + desc = "A device that allows to re-start hearts using electricity. It also can be used as a weapon!" + rules = "Resurrect a friendly unit with 1 HP." + icon_state = "defib" + + mana_cost = 4 + + faction = "Medical" + rarity = "Rare" + card_type = "Spell" + +/datum/tcg_card/pack_1/morphine + name = "Morphine" + desc = "A sedative chemical that puts everyone who uses it into sleep." + rules = "Tap an enemy card without activating it's effect for 1 turn." + icon_state = "morphine" + + mana_cost = 2 + + faction = "Medical" + rarity = "Common" + card_type = "Spell" + +/datum/tcg_card/pack_1/bluespace + name = "Bluespace Flux" + desc = "Despite being a revolutionary new technology bluespace still has some... kinks that need sorted out." + rules = "Active for 3 turns. Every player can pay 2 mana to draw an additional card from their deck." + icon_state = "bluespace" + + mana_cost = 5 + + faction = "Research" + rarity = "Common" + card_type = "Spell" + +/datum/tcg_card/pack_1/bag_of_holding + name = "Bag Of Greed" + desc = "BAG OF GREED ALLOWS ME TO DRAW TWO MORE CARDS. I WILL START MY TURN BY PLAYING BAG OF GREED WHICH ALLOWS ME TO DRAW TWO MORE CARDS. I WILL PLAY THE EVENT CARD BAG OF GREED WHICH ALLOWS ME TO DRAW TWO NEW CARDS." + rules = "Draw 2 cards from your deck." + icon_state = "bag_of_holding" + + mana_cost = 3 + + faction = "Research" + rarity = "Common" + card_type = "Spell" + +/datum/tcg_card/pack_1/malfunction + name = "Glitch in the System" + desc = "Even a meticulously maintained AI system will eventually develop errors. Many are benign but some may cause unforeseen problems..." + rules = "Remove Asimov from one of your cards." + icon_state = "malfunction" + + mana_cost = 1 + + faction = "Research" + rarity = "Common" + card_type = "Spell" + +/datum/tcg_card/pack_1/botanist_plant + name = "Comitted Botanist" + desc = "When you've grown the plants nurtured the plants and harvested the plants there's only one place to go from there... becoming the plant." + rules = "Only usable when Botanist is on the field. This turn all service cards cost 2 mana less(but not below 1)." + icon_state = "botanist_plant" + + mana_cost = 4 + + faction = "Service" + rarity = "Rare" + card_type = "Spell" + +/datum/tcg_card/pack_1/gaia + name = "Ambrosia Gaia" + desc = "If Ambrosia is the gold of Botany the rare Gaia variety is the platinum. Almost nobody has seen this illusive plant with their own eyes." + rules = "During the draw phase you may sacrifice Ambrosia Gaia to gain 3 mana." + icon_state = "gaia" + + mana_cost = 0 + + faction = "Service" + rarity = "Legendary" + card_type = "Spell" + +/datum/tcg_card/pack_1/deep_fryer + name = "Deep Fryer" + desc = "God bless the United States of Space America." + rules = "Destroy an opponent's equipment card." + icon_state = "deep_fryer" + + mana_cost = 2 + + faction = "Service" + rarity = "Common" + card_type = "Spell" + +/datum/tcg_card/pack_1/bepis + name = "B.E.P.I.S." + desc = "God bless the United States of Space America." + rules = "Flip a coin. If heads, gain 2 mana. If tails, lose 2 mana." + icon_state = "bepis" + + mana_cost = 0 + + faction = "Cargo" + rarity = "Common" + card_type = "Spell" + +/datum/tcg_card/pack_1/economy_crash + name = "Economy Crash" + desc = "So cargo sold 20 canisters of miasma and now the galactic economy is experiencing what's known as 'a catastrophic collapse'." + rules = "All cards cost 1 more mana to play." + icon_state = "economy_crash" + + mana_cost = 2 + + faction = "Cargo" + rarity = "Common" + card_type = "Spell" + +/datum/tcg_card/pack_1/additional_supplies + name = "Additional Supplies" + desc = "Well, cargonia ordered 10 crates of buckshots and slugs. Looks like we need to dispose of them quickly." + rules = "For 3 turns, you draw an additional page every turn." + icon_state = "additional_supplies" + + mana_cost = 3 + + faction = "Cargo" + rarity = "Rare" + card_type = "Spell" + +/datum/tcg_card/pack_1/bsa_barrage + name = "BSA Barrage" + desc = "The officers at Centcom are well known for their ability to hit targets extremely accurately with their bluespace artillery especially when stupid pictures show up at their fax machine." + rules = "Destroy an opponent's unit. Deal 2 damage to all units on the field." + icon_state = "bsa_barrage" + + mana_cost = 4 + + faction = "Security" + rarity = "Rare" + card_type = "Spell" + +/datum/tcg_card/pack_1/reeducation + name = "Re-education" + desc = "Nobody ever seems to return from re-education. Probably best not to question it." + rules = "Deal 4 damage to an enemy's unit." + icon_state = "re-education" + + mana_cost = 2 + + faction = "Security" + rarity = "Common" + card_type = "Spell" + +/datum/tcg_card/pack_1/just_losses + name = "Justifiable Casualties" + desc = "The beat is hell. Officers die. The strongest they live." + rules = "Sacrifice two friendly creatures from the battlefield then summon a creature from your hand at no mana cost." + icon_state = "just_losses" + + mana_cost = 2 + + faction = "Security" + rarity = "Common" + card_type = "Spell" + +/datum/tcg_card/pack_1/sleeping_carp + name = "Sleeping Carp" + desc = "Created by the long-extinct Carp Monks of Space Tibet the Sleeping Carp style has been kept alive by dedicated practitioners and even found its way into the Syndicate's training regime." + rules = "Give a friendly unit +3/+1. Draw an additional card every turn while they are alive." + icon_state = "sleeping_carp" + + mana_cost = 6 + + faction = "Syndicate" + rarity = "Epic" + card_type = "Spell" + +/datum/tcg_card/pack_1/tough_choices + name = "Tough Choices" + desc = "Every Nanotrasen employee will at some point be forced to make a tough choice. Make sure you make the right one!" + rules = "Draw the top three cards from your deck. Summon one at no cost and discard the other two." + icon_state = "tough_choices" + + mana_cost = 2 + + faction = "Syndicate" + rarity = "Common" + card_type = "Spell" + +/datum/tcg_card/pack_1/nuclear_explosion + name = "Nuclear Explosion" + desc = "The Gorlex Marauders are well known for their nuclear weapons and their nuke first second third and fourth policy with regards to deploying them." + rules = "Kill all units on the battlefield." + icon_state = "nuclear_explosion" + + mana_cost = 5 + + faction = "Syndicate" + rarity = "Rare" + card_type = "Spell" + +/datum/tcg_card/pack_1/inducer + name = "Inducer" + desc = "The inducer is a marvelous piece of tech allowing the recharging of an internal cell without opening a machine." + rules = "Pay 3 lifeshards: Gain 3 mana this turn." + icon_state = "inducer" + + mana_cost = 0 + + faction = "Engineering" + rarity = "Rare" + card_type = "Spell" + +/datum/tcg_card/pack_1/plasmafire + name = "Atmospherics Incident" + desc = "Accidents happen." + rules = "For 3 turns, add -1/-1 to every unit." + icon_state = "plasmafire" + + mana_cost = 3 + + faction = "Engineering" + rarity = "Rare" + card_type = "Spell" + +/datum/tcg_card/pack_1/supermatter + name = "Supermatter" + desc = "A glowing crystal, made of hyper-pressurised plasma, widely known for it's radiation production." + rules = "Destroy an enemy's unit." + icon_state = "supermatter" + + mana_cost = 4 + + faction = "Engineering" + rarity = "Rare" + card_type = "Spell" diff --git a/code/modules/tcg/pack_nuclear.dm b/code/modules/tcg/pack_nuclear.dm new file mode 100644 index 0000000000..96ec174a4b --- /dev/null +++ b/code/modules/tcg/pack_nuclear.dm @@ -0,0 +1,483 @@ +/datum/tcg_card/pack_nuclear + pack = 'icons/obj/tcg/pack_nuclear.dmi' + +/datum/tcg_card/pack_nuclear/cayenne + name = "Cayenne" + desc = "A failed Syndicate experiment in weaponized space carp technology, it now serves as a lovable mascot." + rules = "Only playable when there are other Syndicate units on the field." + icon_state = "cayenne" + + mana_cost = 4 + attack = 4 + health = 3 + + faction = "Syndicate" + rarity = "Rare" + card_type = "Unit" + +/datum/tcg_card/pack_nuclear/esword + name = "Energy Sword" + desc = "Hard-light sword that doesn't leave burns. Don't ask questions." + rules = "" + icon_state = "esword" + + mana_cost = 3 + attack = 2 + health = 0 + + faction = "Syndicate" + rarity = "Common" + card_type = "Equipment" + +/datum/tcg_card/pack_nuclear/stechkin + name = "Stechkin Pistol" + desc = "A small, easily concealable 10mm handgun. Has a threaded barrel for suppressors." + rules = "When equipping this card, flip it so opponent won't see it. Flip the card after the first attack." + icon_state = "stechkin" + + mana_cost = 2 + attack = 2 + health = 0 + + faction = "Syndicate" + rarity = "Common" + card_type = "Equipment" + +/datum/tcg_card/pack_nuclear/c20r + name = "C-20R SMG" + desc = "A bullpup two-round burst .45 SMG, designated 'C-20r'. Has a 'Scarborough Arms - Per falcis, per pravitas' buttstamp." + rules = "After attack, flip a coin. If heads, leave the weapon. If tails, unequip this card." + icon_state = "c20r" + + mana_cost = 4 + attack = 4 + health = 0 + + faction = "Syndicate" + rarity = "Rare" + card_type = "Equipment" + +/datum/tcg_card/pack_nuclear/l6saw + name = "L6 Saw LMG" + desc = "A heavily modified 1.95x129mm light machine gun, designated 'L6 SAW'. Has 'Aussec Armoury - 2531' engraved on the receiver below the designation." + rules = "After equipped unit dies, this card goes to the bottom of draw deck" + icon_state = "l6saw" + + mana_cost = 8 + attack = 6 + health = 0 + + faction = "Syndicate" + rarity = "Epic" + card_type = "Equipment" + +/datum/tcg_card/pack_nuclear/bulldog + name = "Bulldog Shotgun" + desc = "A semi-auto, mag-fed shotgun for combat in narrow corridors, nicknamed 'Bulldog' by boarding parties. Compatible only with specialized 8-round drum magazines." + rules = "After attack, deal 1 damage to enemy units next to the attacked one." + icon_state = "bulldog" + + mana_cost = 3 + attack = 3 + health = 0 + + faction = "Syndicate" + rarity = "Rare" + card_type = "Equipment" + +/datum/tcg_card/pack_nuclear/nuke_op_leader + name = "Nuclear Team Commander" + desc = "All commanders of elite nuclear teams are equipped with high-tier gear and weaponery. And, sometimes, gaming cards." + rules = "Squad Tactics. Give all Syndicate units on your side +1/0." + icon_state = "nuke_op_leader" + + mana_cost = 5 + attack = 3 + health = 4 + + faction = "Syndicate" + rarity = "Epic" + card_type = "Unit" + +/datum/tcg_card/pack_nuclear/nuke_op + name = "Nuclear Team Commander" + desc = "An unequipped nuclear operative, ready to buy some gear and go full ham!" + rules = "Squad Tactics. On summon: Search your deck for Syndicate equipment. Equip it on this unit. Shuffle it afterwards." + icon_state = "nuke_op" + + mana_cost = 3 + attack = 2 + health = 3 + + faction = "Syndicate" + rarity = "Common" + card_type = "Unit" + +/datum/tcg_card/pack_nuclear/dark_gygax + name = "Dark Gygax" + desc = "A lightweight exosuit, painted in a dark scheme. This model appears to have some modifications." + rules = "Squad Tactics." + icon_state = "dark_gygax" + + mana_cost = 6 + attack = 8 + health = 4 + + faction = "Syndicate" + rarity = "Epic" + card_type = "Unit" + +/datum/tcg_card/pack_nuclear/mauler + name = "Mauler" + desc = "Heavy-duty, combat exosuit, developed off of the existing Marauder model. A perfect killing machine equipped with best weaponery in the world." + rules = "Squad Tactics. Deadeye." + icon_state = "mauler" + + mana_cost = 8 + attack = 8 + health = 8 + + faction = "Syndicate" + rarity = "Legendary" + card_type = "Unit" + +/datum/tcg_card/pack_nuclear/saboteur + name = "Syndicate Saboteur Cyborg" + desc = "A streamlined engineering cyborg, equipped with covert modules. Allows to sabotage all the systems you want without being suspicious." + rules = "Block the first spell your opponent plays against your hero." + icon_state = "saboteur" + + mana_cost = 3 + attack = 1 + health = 3 + + faction = "Syndicate" + rarity = "Rare" + card_type = "Unit" + +/datum/tcg_card/pack_nuclear/medic + name = "Syndicate Medical Cyborg" + desc = "A combat medical cyborg. Has limited offensive potential, but makes more than up for it with its support capabilities." + rules = "Each turn you can give one of your units 0/+1." + icon_state = "medic" + + mana_cost = 4 + attack = 1 + health = 2 + + faction = "Syndicate" + rarity = "Rare" + card_type = "Unit" + +/datum/tcg_card/pack_nuclear/combat + name = "Syndicate Assault Cyborg" + desc = "A cyborg designed and programmed for systematic extermination of non-Syndicate personnel." + rules = "Squad Tactics. Fury." + icon_state = "combat" + + mana_cost = 5 + attack = 4 + health = 4 + + faction = "Syndicate" + rarity = "Epic" + card_type = "Unit" + +/datum/tcg_card/pack_nuclear/emag + name = "Cryptographic Sequencer" + desc = "It's a card with a magnetic strip attached to some circuitry." + rules = "Convert an enemy silicon unit to your side." + icon_state = "emag" + + mana_cost = 4 + + faction = "Syndicate" + rarity = "Common" + card_type = "Spell" + +/datum/tcg_card/pack_nuclear/bomb + name = "Syndicate Bomb" + desc = "A large and menacing device. Can be bolted down with a wrench." + rules = "Deal 6 damage to all units on the field after 2 turns." + icon_state = "bomb" + + mana_cost = 6 + + faction = "Syndicate" + rarity = "Rare" + card_type = "Spell" + +/datum/tcg_card/pack_nuclear/honkbomb + name = "H.O.N.K. Bomb" + desc = "A bomb filled to the brim with bananium and dehydrated clowns!" + rules = "Search your deck for up to 3 Clowns. Play them for free. Shuffle the deck afterwards." + icon_state = "honkbomb" + + mana_cost = 8 + + faction = "Syndicate" + rarity = "Epic" + card_type = "Spell" + +/datum/tcg_card/pack_nuclear/assault_pod + name = "Assault Pod" + desc = "Raining Steel. Nothing personnel, just disky." + rules = "Summon up to 3 units from your hand with 4 mana discount each." + icon_state = "assault_pod" + + mana_cost = 8 + + faction = "Syndicate" + rarity = "Epic" + card_type = "Spell" + +/datum/tcg_card/pack_nuclear/c4 + name = "C4" + desc = "A bunch of plastic explosives wired together." + rules = "Deal 2 damage to an enemy unit." + icon_state = "c4" + + mana_cost = 1 + + faction = "Syndicate" + rarity = "Common" + card_type = "Spell" + +/datum/tcg_card/pack_nuclear/emp + name = "EMP Grenade" + desc = "A modern-looking grenade which creates a powerful EMP upon activation. Do not eat." + rules = "Deal 2 damage to an enemy silicon unit." + icon_state = "emp" + + mana_cost = 0 + + faction = "Syndicate" + rarity = "Common" + card_type = "Spell" + +/datum/tcg_card/pack_nuclear/zombie + name = "Romerol Zombie" + desc = "A horrible abomination, resembling a dead human. Has green skin and red claws. Wait, is it blood dripping from them?" + rules = "After killing an enemy unit, search your deck for a Zombie and summon it for free." + icon_state = "zombie" + + mana_cost = 8 + attack = 4 + health = 3 + + faction = "Syndicate" + rarity = "Epic" + card_type = "Unit" + +/datum/tcg_card/pack_nuclear/north_star + name = "North Star Armbands" + desc = "The armbands of a deadly martial artist. Makes you pretty keen to put an end to evil in an extremely violent manner." + rules = "Equipped unit can attack twice per turn." + icon_state = "north_star" + + mana_cost = 4 + + faction = "Syndicate" + rarity = "Rare" + card_type = "Equipment" + +/datum/tcg_card/pack_nuclear/fastdetonation + name = "Big-Ass Red Button" + desc = "A menacing red button. What could it do?" + rules = "Activate all spells that require several turns to occur." + icon_state = "fastdetonation" + + mana_cost = 2 + + faction = "Syndicate" + rarity = "Common" + card_type = "Spell" + +/datum/tcg_card/pack_nuclear/rpg + name = "PML-9 Rocket Launcher" + desc = "A reusable rocket propelled grenade launcher. The words \"NT this way\" and an arrow have been written near the barrel." + rules = "When equipped unit attacks enemy units, flip a coin. If heads, destroy the unit. If tails, deal 1/2 damage instead of the full blow." + icon_state = "rpg" + + mana_cost = 8 + attack = 6 + + faction = "Syndicate" + rarity = "Legendary" + card_type = "Equipment" + +/datum/tcg_card/pack_nuclear/darkhonk + name = "Dark H.O.N.K. Mech" + desc = "Produced by \"Tyranny of Honk, INC\", this exosuit is designed as heavy clown-support. This one was painted black for maximum HONKing!" + rules = "Taunt. Squad Tactics. Blocker." + icon_state = "darkhonk" + + mana_cost = 8 + attack = 6 + health = 8 + + faction = "Syndicate" + rarity = "Epic" + card_type = "Unit" + +/datum/tcg_card/pack_nuclear/shielded_hardsuit + name = "Shielded Blood-red Hardsuit" + desc = "An advanced version of Gorlex Maradeurs' hardsuit with built-in energy shielding." + rules = "Give equipped unit First Strike." + icon_state = "shielded_hardsuit" + + mana_cost = 4 + attack = 0 + health = 4 + + faction = "Syndicate" + rarity = "Epic" + card_type = "Equipment" + +/datum/tcg_card/pack_nuclear/nuclear_disk + name = "Nuclear Authentication Disk" + desc = "Better keep this safe." + rules = "Give equipped unit Taunt. After the equipped unit dies, re-equip this card to the killer." + icon_state = "nuclear_disk" + + mana_cost = 0 + attack = 1 + health = 1 + + faction = "Syndicate" + rarity = "Epic" + card_type = "Equipment" + +/datum/tcg_card/pack_nuclear/buzzkill + name = "Buzzkill grenade" + desc = "A whole swarm of angry bees filled with deadly toxins. Nasty!" + rules = "Hivemind." + icon_state = "buzzkill" + + mana_cost = 4 + attack = 1 + health = 5 + + faction = "Syndicate" + rarity = "Rare" + card_type = "Unit" + +/datum/tcg_card/pack_nuclear/syndicate_minibomb + name = "Syndicate Minibomb" + desc = "A syndicate manufactured explosive used to sow destruction and chaos." + rules = "Deal 3 damage to an enemy unit and units adjacent to it." + icon_state = "syndicate_minibomb" + + mana_cost = 3 + + faction = "Syndicate" + rarity = "Common" + card_type = "Spell" + +/datum/tcg_card/pack_nuclear/viscerator + name = "Viscerator" + desc = "A small yet deadly machine, designed to rip it's targets apart." + rules = "Gain +1/+1 for every other viscerator on field." + icon_state = "viscerator" + + mana_cost = 2 + attack = 3 + health = 1 + + faction = "Syndicate" + rarity = "Common" + card_type = "Unit" + +/datum/tcg_card/pack_nuclear/cqc + name = "CQC Manual" + desc = "A manual that teaches a single user tactical Close-Quarters Combat before self-destructing." + rules = "Give equipped unit Deadeye and First Strike." + icon_state = "cqc" + + mana_cost = 4 + attack = 4 + health = 3 + + faction = "Syndicate" + rarity = "Epic" + card_type = "Equipment" + +/datum/tcg_card/pack_nuclear/holoparasite + name = "Holoparasite" + desc = "A mysterious being that stands by its charge, ever vigilant." + rules = "On summon: \"Link\" this unit to another unit. Whenever this unit takes damage, instead, transfer all damage to the linked unit." + icon_state = "holoparasite" + + mana_cost = 6 + attack = 8 + health = 0 + + faction = "Syndicate" + rarity = "Legendary" + card_type = "Unit" + +/datum/tcg_card/pack_nuclear/rapier + name = "Rapier" + desc = "An elegant plastitanium rapier with a diamond tip and coated in a specialized knockout poison." + rules = "" + icon_state = "rapier" + + mana_cost = 2 + attack = 3 + health = 0 + + faction = "Syndicate" + rarity = "Rare" + card_type = "Equipment" + +/datum/tcg_card/pack_nuclear/sniper + name = "Sniper Rifle" + desc = "A long ranged weapon that does significant damage. No, you can't quickscope." + rules = "Give equipped unit Deadeye." + icon_state = "sniper" + + mana_cost = 6 + attack = 5 + health = 0 + + faction = "Syndicate" + rarity = "Epic" + card_type = "Equipment" + +/datum/tcg_card/pack_nuclear/honksword + name = "Bananium Sword" + desc = "An elegant weapon, for a more \"civilized\" age." + rules = "Equipped unit does not deal damage. Instead, it taps the attacked card without activating it's effects." + icon_state = "honksword" + + mana_cost = 3 + attack = 0 + health = 0 + + faction = "Syndicate" + rarity = "Common" + card_type = "Equipment" + +/datum/tcg_card/pack_nuclear/mustache + name = "Mustache Grenade" + desc = "A handsomely-attired teargas grenade." + rules = "Unequip all enemy units. Unequipped equipment cards must be discarded." + icon_state = "mustache" + + mana_cost = 5 + + faction = "Syndicate" + rarity = "Common" + card_type = "Spell" + +/datum/tcg_card/pack_nuclear/taeclowndo + name = "Tae-Clown-Do" + desc = "A pair of clown shoes, infused with bananium. Rumors say that these can teach their wearer the art of Tae-Clown-Do." + rules = "Flip a coin. If heads, your enemy skips a turn. If tails, you skip a turn instead." + icon_state = "taeclowndo" + + mana_cost = 3 + + faction = "Syndicate" + rarity = "Epic" + card_type = "Spell" diff --git a/code/modules/tcg/pack_star.dm b/code/modules/tcg/pack_star.dm new file mode 100644 index 0000000000..4b8e32e631 --- /dev/null +++ b/code/modules/tcg/pack_star.dm @@ -0,0 +1,304 @@ +/datum/tcg_card/pack_star + pack = 'icons/obj/tcg/pack_star.dmi' + +/datum/tcg_card/pack_star/golem + name = "Adamantine Golem" + desc = "An adamantine golem, immune to magic and being able to coordinate other golems, has a great power in combat." + rules = "Holy. Taunt." + icon_state = "golem" + + mana_cost = 4 + attack = 4 + health = 5 + + faction = "Unique" + rarity = "Rare" + card_type = "Unit" + +/obj/item/tcg_card/special/golem + datum_type = /datum/tcg_card/pack_star/golem + +/datum/tcg_card/pack_star/xenomaid + name = "Lusty Xenomorph Maid" + desc = "Just a lusty xenomorph maid, nothing to see here." + rules = "Blocker. Each turn, gain -1/-1." + icon_state = "xenomaid" + + mana_cost = 3 + attack = 6 + health = 6 + + faction = "Unique" + rarity = "Epic" + card_type = "Unit" + +/obj/item/tcg_card/special/xenomaid + datum_type = /datum/tcg_card/pack_star/xenomaid + +/datum/tcg_card/pack_star/morph + name = "Morph" + desc = "A revolting, pulsating pile of flesh that can mimic everything it sees." + rules = "On summon: Copy stats of an opponent's card." + icon_state = "morph" + + mana_cost = 4 + attack = 0 + health = 1 + + faction = "Unique" + rarity = "Common" + card_type = "Unit" + +/obj/item/tcg_card/special/morph + datum_type = /datum/tcg_card/pack_star/morph + +/datum/tcg_card/pack_star/demonic_miner + name = "Demonic Miner" + desc = "An soul of extremely geared miner, driven crazy or possessed by the demonic forces here, either way a terrifying enemy." + rules = "Each turn: Deal 1 damage to all the creatures on the field." + icon_state = "demonic_miner" + + mana_cost = 7 + attack = 4 + health = 5 + + faction = "Unique" + rarity = "Rare" + card_type = "Unit" + +/obj/item/tcg_card/special/demonic_miner + datum_type = /datum/tcg_card/pack_star/demonic_miner + +/datum/tcg_card/pack_star/wendigo + name = "Wendigo" + desc = "A mythological man-eating legendary creature, you probably aren't going to survive this." + rules = "" + icon_state = "wendigo" + + mana_cost = 6 + attack = 5 + health = 3 + + faction = "Unique" + rarity = "Common" + card_type = "Unit" + +/obj/item/tcg_card/special/wendigo + datum_type = /datum/tcg_card/pack_star/wendigo + +/datum/tcg_card/pack_star/honk + name = "H.O.N.K. Mech" + desc = "Produced by \"Tyranny of Honk, INC\", this exosuit is designed as heavy clown-support. Used to spread the fun and joy of life. HONK!" + rules = "Taunt." + icon_state = "honk" + + mana_cost = 8 + attack = 6 + health = 8 + + faction = "Unique" + rarity = "Epic" + card_type = "Unit" + +/obj/item/tcg_card/special/honk + datum_type = /datum/tcg_card/pack_star/honk + +/datum/tcg_card/pack_star/ratvar + name = "Clockwork Slab" + desc = "A link between clockwork servants and the Celestial Derelict. It contains information, recites scripture, and is Servant's most vital tool." + rules = "Equipped unit gains Clockwork and can't attack units with Holy." + icon_state = "ratvar" + + mana_cost = 2 + attack = 3 + health = 0 + + faction = "Unique" + rarity = "Common" + card_type = "Equipment" + +/obj/item/tcg_card/special/ratvar + datum_type = /datum/tcg_card/pack_star/ratvar + +/datum/tcg_card/pack_star/hierophant + name = "Hierophant Club" + desc = "The strange technology of this large club allows various nigh-magical feats. It used to beat you, but now you can set the beat." + rules = "Give equipped unit First Strike." + icon_state = "hierophant" + + mana_cost = 4 + attack = 2 + health = 0 + + faction = "Unique" + rarity = "Rare" + card_type = "Equipment" + +/obj/item/tcg_card/special/hierophant + datum_type = /datum/tcg_card/pack_star/hierophant + +/datum/tcg_card/pack_star/abductor + name = "Alien Gland" + desc = "A nausea-inducing hunk of twisting flesh and metal. These things are often found after people were abducted by grey-skinned aliens." + rules = "Each turn: Flip a coin. If heads, unit gain +1/+1. If tails, unit gains -2/-1." + icon_state = "abductor" + + mana_cost = 2 + attack = 0 + health = 0 + + faction = "Unique" + rarity = "Common" + card_type = "Equipment" + +/obj/item/tcg_card/special/abductor + datum_type = /datum/tcg_card/pack_star/abductor + +/datum/tcg_card/pack_star/space_carp + name = "Space Carp" + desc = "A failed weaponery experiment, looking like a ferocious, fang-bearing creature that resembles a fish." + rules = "" + icon_state = "space_carp" + + mana_cost = 1 + attack = 2 + health = 1 + + faction = "Unique" + rarity = "Common" + card_type = "Unit" + +/obj/item/tcg_card/special/space_carp + datum_type = /datum/tcg_card/pack_star/space_carp + +/datum/tcg_card/pack_star/spess_pirate + name = "Space Pirate" + desc = "Space Pirate does whatever he wants because he is free. Sadly, Space Rum insn't free." + rules = "On summon: Draw 2 cards. If there are no spells, discard them." + icon_state = "spess_pirate" + + mana_cost = 4 + attack = 3 + health = 2 + + faction = "Unique" + rarity = "Rare" + card_type = "Unit" + +/obj/item/tcg_card/special/spess_pirate + datum_type = /datum/tcg_card/pack_star/spess_pirate + +/datum/tcg_card/pack_star/gondola + name = "Gondola" + desc = "Gondola is the silent walker. Having no hands he embodies the Taoist principle of wu-wei (non-action) while his smiling facial expression shows his utter and complete acceptance of the world as it is. Its hide is extremely valuable." + rules = "Taunt. Holy." + icon_state = "gondola" + + mana_cost = 6 + attack = 0 + health = 6 + + faction = "Unique" + rarity = "Epic" + card_type = "Unit" + +/obj/item/tcg_card/special/gondola + datum_type = /datum/tcg_card/pack_star/gondola + +/datum/tcg_card/pack_star/phazon + name = "Phazon" + desc = "The pinnacle of scientific research and pride of Nanotrasen, Phazon uses cutting edge bluespace technology and expensive materials." + rules = "Whenever this unit takes damage, flip a coin. If heads, take no damage. If tails, take double damage." + icon_state = "phazon" + + mana_cost = 8 + attack = 5 + health = 7 + + faction = "Unique" + rarity = "Rare" + card_type = "Unit" + +/obj/item/tcg_card/special/phazon + datum_type = /datum/tcg_card/pack_star/phazon + +//Ultimate Exodia cards. I really, really doubt that someone will ever find them. + +/datum/tcg_card/exodia + pack = 'icons/obj/tcg/pack_star.dmi' + +/datum/tcg_card/exodia/exodia_singulo + name = "Singularity" + desc = "A monstrous gravitational singularity, pitch black(but not quiet) and very menacings." + rules = "This card doesn't leave field. At the end of each turn: Remove all the cards(except other Exodia cards) from the field." + icon_state = "exodia_singularity" + + mana_cost = 8 + + faction = "Exodia" + rarity = "Exodia" + card_type = "Spell" + +/datum/tcg_card/exodia/exodia_tesla + name = "Energy Orb" + desc = "An orb made out of hypercharged plasma. An ultimate bug zapper." + rules = "This card doesn't leave field. Every turn all units take 4 damage." + icon_state = "exodia_tesla" + + mana_cost = 8 + + faction = "Exodia" + rarity = "Exodia" + card_type = "Spell" + +/datum/tcg_card/exodia/exodia_narie + name = "Nar-Sie" + desc = "An avatar of the Nar-Sie, one of the Eldritch Gods." + rules = "This card doesn't leave field. Every turn all units take 1 damage and you restore 1 lifeshard." + icon_state = "exodia_narsie" + + mana_cost = 8 + + faction = "Exodia" + rarity = "Exodia" + card_type = "Spell" + +/datum/tcg_card/exodia/exodia_ratvar + name = "Ratvar" + desc = "Ratvar, the god of cogs and clockwork mechanisms, was trapped by Nar-Sie a long ago." + rules = "This card doesn't leave field. Every turn enemy hero recieves 2 lifeshard damage." + icon_state = "exodia_ratvar" + + mana_cost = 8 + + faction = "Exodia" + rarity = "Exodia" + card_type = "Spell" + +/datum/tcg_card/exodia/exodia + name = "Eldritch Horror" + desc = "The Eldritch Horror is a long forgotten demon that was the beginning of everything. Afterwards, his creations revolted and left him abadoned in endless void." + rules = "This card doesn't leave field. If all other 4 Exodia cards are on the field(Singularity, Energy Orb, Nar-Sie and Ratvar), the game is won." + icon_state = "exodia_eldritch" + + mana_cost = 8 + + faction = "Exodia" + rarity = "Unique" //No drop lads + card_type = "Spell" + +/obj/item/tcg_card/special/exodia_singulo + datum_type = /datum/tcg_card/exodia/exodia_singulo + +/obj/item/tcg_card/special/exodia_tesla + datum_type = /datum/tcg_card/exodia/exodia_tesla + +/obj/item/tcg_card/special/exodia_narie + datum_type = /datum/tcg_card/exodia/exodia_narie + +/obj/item/tcg_card/special/exodia_ratvar + datum_type = /datum/tcg_card/exodia/exodia_ratvar + +/obj/item/tcg_card/special/exodia + datum_type = /datum/tcg_card/exodia/exodia + diff --git a/code/modules/uplink/uplink_items/uplink_badass.dm b/code/modules/uplink/uplink_items/uplink_badass.dm index 43e5523bad..ec0ebf66d1 100644 --- a/code/modules/uplink/uplink_items/uplink_badass.dm +++ b/code/modules/uplink/uplink_items/uplink_badass.dm @@ -78,3 +78,16 @@ limited_stock = 1 cant_discount = TRUE include_modes = list(/datum/game_mode/nuclear, /datum/game_mode/nuclear/clown_ops) + +/datum/uplink_item/badass/gaming_cardpack + name = "TCG Card Operatives Bundle" + desc = "A bundle full of goodies required to work as a TCG Card Operative. A warm pajama, a mug of cocoa, a plushie and a two packs full of rare 2560 Core Set cards!" + item = /obj/item/storage/box/syndie_kit/sleepytime/cardpack + cost = 20 + include_modes = list(/datum/game_mode/nuclear, /datum/game_mode/nuclear/clown_ops) + +/datum/uplink_item/badass/cardpack + name = "TCG Nuclear Cardpack" + desc = "A cardpack filled with top-tier TCG cards." + item = /obj/item/cardpack/syndicate + cost = 4 diff --git a/code/modules/vending/clothesmate.dm b/code/modules/vending/clothesmate.dm index 09881da469..b68105dcf8 100644 --- a/code/modules/vending/clothesmate.dm +++ b/code/modules/vending/clothesmate.dm @@ -21,6 +21,7 @@ /obj/item/clothing/suit/jacket/puffer/vest = 4, /obj/item/clothing/suit/jacket/puffer = 4, /obj/item/clothing/suit/hooded/cloak/david = 4, + /obj/item/clothing/neck/cancloak = 4, /obj/item/clothing/suit/bomber = 5, /obj/item/clothing/under/suit/turtle/teal = 3, /obj/item/clothing/under/suit/turtle/grey = 3, @@ -212,7 +213,9 @@ /obj/item/clothing/neck/necklace/dope = 5, /obj/item/clothing/suit/jacket/letterman_nanotrasen = 5, /obj/item/clothing/under/misc/corporateuniform = 5, - /obj/item/clothing/suit/hooded/wintercoat/polychromic = 5) + /obj/item/clothing/suit/hooded/wintercoat/polychromic = 5, + /obj/item/clothing/suit/toggle/wbreakpoly/polychromic = 5, + /obj/item/clothing/shoes/sneakers/poly/polychromic = 10) refill_canister = /obj/item/vending_refill/clothing default_price = PRICE_CHEAP extra_price = PRICE_BELOW_NORMAL diff --git a/code/modules/vending/games.dm b/code/modules/vending/games.dm index 6c29b412e7..cea9c5ae70 100644 --- a/code/modules/vending/games.dm +++ b/code/modules/vending/games.dm @@ -7,7 +7,9 @@ /obj/item/storage/dice = 10, /obj/item/toy/cards/deck/cas = 3, /obj/item/toy/cards/deck/cas/black = 3, - /obj/item/toy/cards/deck/unum = 3) + /obj/item/toy/cards/deck/unum = 3, + /obj/item/cardpack/series_one = 10, + /obj/item/tcgcard_binder = 5) contraband = list(/obj/item/dice/fudge = 9) premium = list(/obj/item/melee/skateboard/pro = 3, /obj/item/melee/skateboard/hoverboard = 1) diff --git a/html/changelog.html b/html/changelog.html index 81b8534776..a67ca05dab 100644 --- a/html/changelog.html +++ b/html/changelog.html @@ -66,40 +66,116 @@

11 February 2021

-

Adelphon updated:

+

18 February 2021

+

BlueWildrose updated:

-

DeltaFire15 updated:

+

Hatterhat updated:

-

Putnam3145 updated:

+

LetterN updated:

+

SmArtKar updated:

+

dzahlus updated:

-

keronshb updated:

+

shellspeed1 updated:

+

silicons updated:

+ + +

16 February 2021

+

silicons updated:

+ + +

15 February 2021

+

Adelphon updated:

+ +

DeltaFire15 updated:

+ +

dzahlus updated:

+ +

silicons updated:

+ + +

14 February 2021

+

DeltaFire15 updated:

+ +

Hatterhat updated:

+ +

TyrianTyrell updated:

+ + +

13 February 2021

+

Hatterhat updated:

+

timothyteakettle updated:

-

zeroisthebiggay updated:

- -

09 February 2021

-

Chiirno updated:

+

12 February 2021

+

Hatterhat updated:

+ +

MrJWhit updated:

+ +

silicons updated:

+ + +

11 February 2021

+

Adelphon updated:

@@ -116,6 +192,66 @@
  • sentient viruses can now infect synths and ipcs
  • +

    07 February 2021

    +

    Thalpy updated:

    + +

    TyrianTyrell updated:

    + +

    dzahlus updated:

    + +

    silicons updated:

    + + +

    05 February 2021

    +

    SmArtKar updated:

    + +

    keronshb updated:

    + +

    raspy-on-osu updated:

    + +

    shellspeed1 updated:

    + +

    timothyteakettle updated:

    + +

    07 February 2021

    Thalpy updated: