From a5e60d12416daacb7ff6892d712615633a12884c Mon Sep 17 00:00:00 2001 From: L <105110468+kittysmooch@users.noreply.github.com> Date: Mon, 26 Aug 2024 09:58:39 -0700 Subject: [PATCH 01/28] does most of the porting --- .../machines/machine_circuitboards.dm | 4 + .../clutter objects/icons/janitor.dmi | Bin 0 -> 1073 bytes .../alcohol reagents.dm | 899 ++++++++++++++++++ .../modular_food_and_drinks/drink_reagents.dm | 79 ++ .../modular_food_and_drinks/drinks_recipes.dm | 421 ++++++++ .../modular_food_and_drinks/icons/drinks.dmi | Bin 0 -> 30301 bytes .../code/vendor_containers.dm | 89 ++ .../vending_machines/code/vendor_food.dm | 318 +++++++ .../vending_machines/code/vendor_snacks.dm | 302 ++++++ .../vending_machines/code/vendors.dm | 229 +++++ .../icons/imported_quick_foods.dmi | Bin 0 -> 10720 bytes .../icons/imported_vendors.dmi | Bin 0 -> 9002 bytes modular_doppler/vending_machines/readme.md | 26 + tgstation.dme | 7 + 14 files changed, 2374 insertions(+) create mode 100644 modular_doppler/clutter objects/icons/janitor.dmi create mode 100644 modular_doppler/modular_food_and_drinks/alcohol reagents.dm create mode 100644 modular_doppler/modular_food_and_drinks/drink_reagents.dm create mode 100644 modular_doppler/modular_food_and_drinks/drinks_recipes.dm create mode 100644 modular_doppler/modular_food_and_drinks/icons/drinks.dmi create mode 100644 modular_doppler/vending_machines/code/vendor_containers.dm create mode 100644 modular_doppler/vending_machines/code/vendor_food.dm create mode 100644 modular_doppler/vending_machines/code/vendor_snacks.dm create mode 100644 modular_doppler/vending_machines/code/vendors.dm create mode 100644 modular_doppler/vending_machines/icons/imported_quick_foods.dmi create mode 100644 modular_doppler/vending_machines/icons/imported_vendors.dmi create mode 100644 modular_doppler/vending_machines/readme.md diff --git a/code/game/objects/items/circuitboards/machines/machine_circuitboards.dm b/code/game/objects/items/circuitboards/machines/machine_circuitboards.dm index 64f4ee35f6076..d5c5dbd4db39e 100644 --- a/code/game/objects/items/circuitboards/machines/machine_circuitboards.dm +++ b/code/game/objects/items/circuitboards/machines/machine_circuitboards.dm @@ -666,6 +666,10 @@ /obj/machinery/vending/wardrobe/science_wardrobe = "SciDrobe", /obj/machinery/vending/wardrobe/sec_wardrobe = "SecDrobe", /obj/machinery/vending/wardrobe/viro_wardrobe = "ViroDrobe", + /obj/machinery/vending/imported = "NT Sustenance Supplier", //DOPPLER ADDITION + /obj/machinery/vending/imported/yangyu = "Fudobenda", //DOPPLER ADDITION + /obj/machinery/vending/imported/mothic = "Nomad Fleet Ration Chit Exchange", //DOPPLER ADDITION + /obj/machinery/vending/imported/tiziran = "Tiziran Imported Delicacies", //DOPPLER ADDITION ) /obj/item/circuitboard/machine/vendor/screwdriver_act(mob/living/user, obj/item/tool) diff --git a/modular_doppler/clutter objects/icons/janitor.dmi b/modular_doppler/clutter objects/icons/janitor.dmi new file mode 100644 index 0000000000000000000000000000000000000000..fb41f7464c829fd55900417f38162c63d232138c GIT binary patch literal 1073 zcmV-11kU@3P)Ayyc9oTt-{0TrOD>rkRREIAm>&h%LI_e)Qcw~xa1u)%X?*2W8=f0qKn*VdZ=)7Y zTmOIn%ocR-@9$rq-~f=+|NsBX(9xx^wg8#`@VqDRS{Ux`?sy~?+uPg3#Kiyb0MRLO z-O4aUhhe(9x}1?ny_`IfdrJ~bD;r!k3_l`@ii&=Ie&oe4JcnGWs;bh`(oIcGRGD#w zv6%JV9CoIP`{zMkr+vV{z_wl~YbOGjP6bLD0L5?|a1tV(8z%CRFw4!+%oZh35*Ay4 zO|Jj|00DGTPE!Ct=GbNc006OiR9JLGWpiV4X>fFDZ*Bkpc$|fi%?g7s5QNX>DT3Zh z|E|3hrFf{XAZxRlr7?j`RP^Z^D)d%zn^`_)+1Wzgt4H0)@>z=+*^{&KCa;I1$QDvT zM{_xgOd}0C?8XNO7-hboQDldXYgP?%123YMrjNm`g!p2j5ib{v4y_YAQk!nVWzy9-%0<@X04JMweA9O|%N0006| zNkl0FrLpk_&RAU*QOEiJe`yloalWKuS6BOxy?onp z_DXm;5Tem&H2+J1{|cYz4YN?NOykr1jbT}qX&E=b-{$@n_`BTSp+M1gOv5l?pyXyA z1w1eFFkqK$!*ZNr5qQ^kg|C!QAn=5*R$-u4wjH}@oYGJ$`_P2Xp{`aPPPMlH>sO#$zxX z0?!M*AL0ZkK-{M%-*?>#@?N*`*bIj76%bM`_xpH0A$+`#=MxeHUQ;$-(3i{?$mRU%;P}jVc?lMV!fX{1OLJ< ze)n3JikKh-$SB!Ugb3!%~$XjADT`|x_ti{00000NkvXXu0mjf*xLdD literal 0 HcmV?d00001 diff --git a/modular_doppler/modular_food_and_drinks/alcohol reagents.dm b/modular_doppler/modular_food_and_drinks/alcohol reagents.dm new file mode 100644 index 0000000000000..2eb87b99c6e9d --- /dev/null +++ b/modular_doppler/modular_food_and_drinks/alcohol reagents.dm @@ -0,0 +1,899 @@ +/*STUFF WE CAN'T USE YET BECAUSE WE HAVEN'T PORTED THEIR PRECURSORS + +// Modular Booze REAGENTS, see the following file for the mixes: modular_nova\modules\customization\modules\food_and_drinks\recipes\drinks_recipes.dm + +/datum/reagent/consumable/ethanol/whiskey + process_flags = REAGENT_ORGANIC | REAGENT_SYNTHETIC //let's not force the detective to change his alcohol brand + + +/datum/reagent/consumable/ethanol/bloody_mary + chemical_flags_nova = REAGENT_BLOOD_REGENERATING +*/ + +/*SYNTHETIC DRINKS +/datum/reagent/consumable/ethanol/synthanol + name = "Synthanol" + description = "A runny liquid with conductive capacities. Its effects on synthetics are similar to those of alcohol on organics." + color = "#1BB1FF" + process_flags = REAGENT_ORGANIC | REAGENT_SYNTHETIC + boozepwr = 50 + quality = DRINK_NICE + taste_description = "motor oil" + +/datum/glass_style/drinking_glass/synthanol + required_drink_type = /datum/reagent/consumable/ethanol/synthanol + icon = 'modular_doppler/modular_food_and_drinks/icons/drinks.dmi' + icon_state = "synthanolglass" + name = "glass of synthanol" + desc = "The equivalent of alcohol for synthetic crewmembers. They'd find it awful if they had tastebuds too." + +/datum/reagent/consumable/ethanol/synthanol/on_mob_life(mob/living/carbon/affected_mob, seconds_per_tick, times_fired) + if(!(affected_mob.mob_biotypes & MOB_ROBOTIC)) + affected_mob.reagents.remove_reagent(type, 3.6 * REM * seconds_per_tick) //gets removed from organics very fast + if(prob(25)) + affected_mob.vomit(VOMIT_CATEGORY_DEFAULT, lost_nutrition = 5) + return ..() + +/datum/reagent/consumable/ethanol/synthanol/expose_mob(mob/living/carbon/C, method=TOUCH, volume) + . = ..() + if(C.mob_biotypes & MOB_ROBOTIC) + return + if(method == INGEST) + to_chat(C, pick(span_danger("That was awful!"), span_danger("That was disgusting!"))) + +/datum/reagent/consumable/ethanol/synthanol/robottears + name = "Robot Tears" + description = "An oily substance that an IPC could technically consider a 'drink'." + color = "#363636" + quality = DRINK_GOOD + boozepwr = 25 + taste_description = "existential angst" + +/datum/glass_style/drinking_glass/synthanol/robottears + required_drink_type = /datum/reagent/consumable/ethanol/synthanol/robottears + icon_state = "robottearsglass" + name = "glass of robot tears" + desc = "No robots were hurt in the making of this drink." + +/datum/reagent/consumable/ethanol/synthanol/trinary + name = "Trinary" + description = "A fruit drink meant only for synthetics, however that works." + color = "#ADB21f" + quality = DRINK_GOOD + boozepwr = 20 + taste_description = "modem static" + +/datum/glass_style/drinking_glass/synthanol/trinary + required_drink_type = /datum/reagent/consumable/ethanol/synthanol/trinary + icon_state = "trinaryglass" + name = "glass of trinary" + desc = "Colorful drink made for synthetic crewmembers. It doesn't seem like it would taste well." + +/datum/reagent/consumable/ethanol/synthanol/servo + name = "Servo" + description = "A drink containing some organic ingredients, but meant only for synthetics." + color = "#5B3210" + quality = DRINK_GOOD + boozepwr = 25 + taste_description = "motor oil and cocoa" + +/datum/glass_style/drinking_glass/synthanol/servo + required_drink_type = /datum/reagent/consumable/ethanol/synthanol/servo + icon_state = "servoglass" + name = "glass of servo" + desc = "Chocolate - based drink made for IPCs. Not sure if anyone's actually tried out the recipe." + +/datum/reagent/consumable/ethanol/synthanol/uplink + name = "Uplink" + description = "A potent mix of alcohol and synthanol. Will only work on synthetics." + color = "#E7AE04" + quality = DRINK_GOOD + boozepwr = 15 + taste_description = "a GUI in visual basic" + +/datum/glass_style/drinking_glass/synthanol/uplink + required_drink_type = /datum/reagent/consumable/ethanol/synthanol/uplink + icon_state = "uplinkglass" + name = "glass of uplink" + desc = "An exquisite mix of the finest liquoirs and synthanol. Meant only for synthetics." + +/datum/reagent/consumable/ethanol/synthanol/synthncoke + name = "Synth 'n Coke" + description = "The classic drink adjusted for a robot's tastes." + color = "#7204E7" + quality = DRINK_GOOD + boozepwr = 25 + taste_description = "fizzy motor oil" + +/datum/glass_style/drinking_glass/synthanol/synthncoke + required_drink_type = /datum/reagent/consumable/ethanol/synthanol/synthncoke + icon_state = "synthncokeglass" + name = "glass of synth 'n coke" + desc = "Classic drink altered to fit the tastes of a robot, contains de-rustifying properties. Bad idea to drink if you're made of carbon." + +/datum/reagent/consumable/ethanol/synthanol/synthignon + name = "Synthignon" + description = "Someone mixed wine and alcohol for robots. Hope you're proud of yourself." + color = "#D004E7" + quality = DRINK_GOOD + boozepwr = 25 + taste_description = "fancy motor oil" + +/datum/glass_style/drinking_glass/synthanol/synthignon + required_drink_type = /datum/reagent/consumable/ethanol/synthanol/synthignon + icon_state = "synthignonglass" + name = "glass of synthignon" + desc = "Someone mixed good wine and robot booze. Romantic, but atrocious." +*/ +// Other Booze + +/datum/reagent/consumable/ethanol/hot_toddy + name = "Hot Toddy" + description = "An old fashioned cocktail made of honey, rum, and tea." + color = "#e4830d" + boozepwr = 40 + quality = DRINK_GOOD + taste_description = "sweet spiced tea" + +/datum/glass_style/drinking_glass/hot_toddy + required_drink_type = /datum/reagent/consumable/ethanol/hot_toddy + icon = 'modular_doppler/modular_food_and_drinks/icons/drinks.dmi' + icon_state = "hot_toddy" + name = "hot toddy glass" + desc = "An old fashioned cocktail made of honey, rum, and tea, it tastes like sweet holiday spices." + +/datum/reagent/consumable/ethanol/hellfire + name = "Hellfire" + description = "A nice drink that isn't quite as hot as it looks." + color = "#fb2203" + boozepwr = 60 + quality = DRINK_VERYGOOD + taste_description = "cold flames that lick at the top of your mouth" + +/datum/glass_style/drinking_glass/hellfire + required_drink_type = /datum/reagent/consumable/ethanol/hellfire + icon = 'modular_doppler/modular_food_and_drinks/icons/drinks.dmi' + icon_state = "hellfire" + name = "glass of hellfire" + desc = "An amber colored drink that isn't quite as hot as it looks." + +/datum/reagent/consumable/ethanol/hellfire/on_mob_life(mob/living/carbon/affected_mob, seconds_per_tick, times_fired) + . = ..() + affected_mob.adjust_bodytemperature(30 * TEMPERATURE_DAMAGE_COEFFICIENT * REM * seconds_per_tick, 0, BODYTEMP_NORMAL + 30) + +/datum/reagent/consumable/ethanol/sins_delight + name = "Sin's Delight" + description = "The drink smells like the seven sins." + color = "#330000" + boozepwr = 66 + quality = DRINK_FANTASTIC + taste_description = "overpowering sweetness with a touch of sourness, followed by iron and the sensation of a warm summer breeze" +// chemical_flags_skyrat = REAGENT_BLOOD_REGENERATING //component drink is demon's blood, thus this drink is made with blood so hemophages can comfortably drink it + +/datum/glass_style/drinking_glass/sins_delight + required_drink_type = /datum/reagent/consumable/ethanol/sins_delight + icon = 'modular_doppler/modular_food_and_drinks/icons/drinks.dmi' + icon_state = "sins_delight" + name = "glass of sin's delight" + desc = "You can smell the seven sins rolling off the top of the glass." + +/datum/reagent/consumable/ethanol/strawberry_daiquiri + name = "Strawberry Daiquiri" + description = "Pink looking alcoholic drink." + boozepwr = 20 + color = "#FF4A74" + quality = DRINK_NICE + taste_description = "sweet strawberry, lime and the ocean breeze" + +/datum/glass_style/drinking_glass/strawberry_daiquiri + required_drink_type = /datum/reagent/consumable/ethanol/strawberry_daiquiri + icon = 'modular_doppler/modular_food_and_drinks/icons/drinks.dmi' + icon_state = "strawberry_daiquiri" + name = "glass of strawberry daiquiri" + desc = "Pink looking drink with flowers and a big straw to sip it. Looks sweet and refreshing, perfect for warm days." + +/datum/reagent/consumable/ethanol/liz_fizz + name = "Liz Fizz" + description = "Triple citrus layered with some ice and cream." + boozepwr = 0 + color = "#D8FF59" + quality = DRINK_NICE + taste_description = "brain freezing sourness" + +/datum/glass_style/drinking_glass/liz_fizz + required_drink_type = /datum/reagent/consumable/ethanol/liz_fizz + icon = 'modular_doppler/modular_food_and_drinks/icons/drinks.dmi' + icon_state = "liz_fizz" + name = "glass of liz fizz" + desc = "Looks like a citrus sherbet seperated in layers? Why would anyone want that is beyond you." + +/datum/reagent/consumable/ethanol/miami_vice + name = "Miami Vice" + description = "A drink layering Pina Colada and Strawberry Daiquiri" + boozepwr = 30 + color = "#D8FF59" + quality = DRINK_FANTASTIC + taste_description = "sweet and refreshing flavor, complemented with strawberries and coconut, and hints of citrus" + +/datum/glass_style/drinking_glass/miami_vice + required_drink_type = /datum/reagent/consumable/ethanol/miami_vice + icon = 'modular_doppler/modular_food_and_drinks/icons/drinks.dmi' + icon_state = "miami_vice" + name = "glass of miami vice" + desc = "Strawberries and coconut, like yin and yang." + +/datum/reagent/consumable/ethanol/malibu_sunset + name = "Malibu Sunset" + description = "A drink consisting of creme de coconut and tropical juices" + boozepwr = 20 + color = "#FF9473" + quality = DRINK_VERYGOOD + taste_description = "coconut, with orange and grenadine accents" + +/datum/glass_style/drinking_glass/malibu_sunset + required_drink_type = /datum/reagent/consumable/ethanol/malibu_sunset + icon = 'modular_doppler/modular_food_and_drinks/icons/drinks.dmi' + icon_state = "malibu_sunset" + name = "glass of malibu sunset" + desc = "Tropical looking drinks, with ice cubes hovering on the surface and grenadine coloring the bottom." + +/datum/reagent/consumable/ethanol/hotlime_miami + name = "Hotlime Miami" + description = "The essence of the 90's, if they were a bloody mess that is." + boozepwr = 40 + color = "#A7FAE8" + quality = DRINK_FANTASTIC + taste_description = "coconut and aesthetic violence" + +/datum/glass_style/drinking_glass/hotlime_miami + required_drink_type = /datum/reagent/consumable/ethanol/hotlime_miami + icon = 'modular_doppler/modular_food_and_drinks/icons/drinks.dmi' + icon_state = "hotlime_miami" + name = "glass of hotlime miami" + desc = "This looks very aesthetically pleasing." + +/datum/reagent/consumable/ethanol/hotlime_miami/on_mob_life(mob/living/carbon/affected_mob, seconds_per_tick, times_fired) + . = ..() + affected_mob.set_drugginess(1.5 MINUTES * REM * seconds_per_tick) + if(affected_mob.adjustStaminaLoss(-2 * REM * seconds_per_tick, updating_stamina = FALSE)) + return UPDATE_MOB_HEALTH + +/datum/reagent/consumable/ethanol/coggrog + name = "Cog Grog" + description = "Now you can fill yourself with the power of Ratvar!" + color = rgb(255, 201, 49) + boozepwr = 10 + quality = DRINK_FANTASTIC + taste_description = "a brass taste with a hint of oil" + +/datum/glass_style/drinking_glass/coggrog + required_drink_type = /datum/reagent/consumable/ethanol/coggrog + icon = 'modular_doppler/modular_food_and_drinks/icons/drinks.dmi' + icon_state = "coggrog" + name = "glass of cog grog" + desc = "Not even Ratvar's Four Generals could withstand this! Qevax Jryy!" + +/datum/reagent/consumable/ethanol/badtouch + name = "Bad Touch" + description = "A sour and vintage drink. Some say the inventor gets slapped a lot." + color = rgb(31, 181, 99) + boozepwr = 35 + quality = DRINK_GOOD + taste_description = "a slap to the face" + +/datum/glass_style/drinking_glass/badtouch + required_drink_type = /datum/reagent/consumable/ethanol/badtouch + icon = 'modular_doppler/modular_food_and_drinks/icons/drinks.dmi' + icon_state = "badtouch" + name = "glass of bad touch" + desc = "We're nothing but mammals after all." + +/datum/reagent/consumable/ethanol/marsblast + name = "Marsblast" + description = "A spicy and manly drink in honor of the first colonists on Mars." + color = rgb(246, 143, 55) + boozepwr = 70 + quality = DRINK_FANTASTIC + taste_description = "hot red sand" + +/datum/glass_style/drinking_glass/marsblast + required_drink_type = /datum/reagent/consumable/ethanol/marsblast + icon = 'modular_doppler/modular_food_and_drinks/icons/drinks.dmi' + icon_state = "marsblast" + name = "glass of marsblast" + desc = "One of these is enough to leave your face as red as the planet." + +/datum/reagent/consumable/ethanol/mercuryblast + name = "Mercuryblast" + description = "A sour burningly cold drink that's sure to chill the drinker." + color = rgb(29, 148, 213) + boozepwr = 40 + quality = DRINK_VERYGOOD + taste_description = "chills down your spine" + +/datum/glass_style/drinking_glass/mercuryblast + required_drink_type = /datum/reagent/consumable/ethanol/mercuryblast + icon = 'modular_doppler/modular_food_and_drinks/icons/drinks.dmi' + icon_state = "mercuryblast" + name = "glass of mercuryblast" + desc = "No thermometers were harmed in the creation of this drink" + +/datum/reagent/consumable/ethanol/mercuryblast/on_mob_life(mob/living/carbon/affected_mob, seconds_per_tick, times_fired) + . = ..() + affected_mob.adjust_bodytemperature(-30 * TEMPERATURE_DAMAGE_COEFFICIENT * REM * seconds_per_tick, T0C) + +/datum/reagent/consumable/ethanol/piledriver + name = "Piledriver" + description = "A bright drink that leaves you with a burning sensation." + color = rgb(241, 146, 59) + boozepwr = 45 + quality = DRINK_NICE + taste_description = "a fire in your throat" + +/datum/glass_style/drinking_glass/piledriver + required_drink_type = /datum/reagent/consumable/ethanol/piledriver + icon = 'modular_doppler/modular_food_and_drinks/icons/drinks.dmi' + icon_state = "piledriver" + name = "glass of piledriver" + desc = "Not the only thing to leave your throat sore." + +/datum/reagent/consumable/ethanol/zenstar + name = "Zen Star" + description = "A sour and bland drink, rather disappointing." + color = rgb(51, 87, 203) + boozepwr = 35 + quality = DRINK_NICE + taste_description = "disappointment" + +/datum/glass_style/drinking_glass/zenstar + required_drink_type = /datum/reagent/consumable/ethanol/zenstar + icon = 'modular_doppler/modular_food_and_drinks/icons/drinks.dmi' + icon_state = "zenstar" + name = "glass of zen star" + desc = "You'd think something so balanced would actually taste nice... you'd be dead wrong." + + +/* MORE RACE SPECIFIC STUFF WE DON'T HAVE SUPPORT FOR YET +// RACE SPECIFIC DRINKS + +/datum/reagent/consumable/ethanol/coldscales + name = "Coldscales" + color = "#5AEB52" //(90, 235, 82) + description = "A cold looking drink made for people with scales." + boozepwr = 50 //strong! + taste_description = "dead flies" + +/datum/glass_style/drinking_glass/coldscales + required_drink_type = /datum/reagent/consumable/ethanol/coldscales + icon = 'modular_doppler/modular_food_and_drinks/icons/drinks.dmi' + icon_state = "coldscales" + name = "glass of coldscales" + desc = "A soft green drink that looks inviting!" + +/datum/reagent/consumable/ethanol/coldscales/expose_mob(mob/living/exposed_mob, methods, reac_volume) + if(islizard(exposed_mob)) + quality = RACE_DRINK + else + quality = DRINK_GOOD + return ..() + +/datum/reagent/consumable/ethanol/oil_drum + name = "Oil Drum" + color = "#000000" //(0, 0, 0) + description = "Industrial grade oil mixed with some ethanol to make it a drink. Somehow not known to be toxic." + boozepwr = 45 + taste_description = "oil spill" + +/datum/glass_style/drinking_glass/oil_drum + required_drink_type = /datum/reagent/consumable/ethanol/oil_drum + icon = 'modular_doppler/modular_food_and_drinks/icons/drinks.dmi' + icon_state = "oil_drum" + name = "drum of oil" + desc = "A gray can of booze and oil..." + +/datum/reagent/consumable/ethanol/oil_drum/expose_mob(mob/living/exposed_mob, methods, reac_volume) + if(MOB_ROBOTIC) + quality = RACE_DRINK + else + quality = DRINK_GOOD + return ..() + +/datum/reagent/consumable/ethanol/nord_king + name = "Nord King" + color = "#EB1010" //(235, 16, 16) + description = "Strong mead mixed with more honey and ethanol. Beloved by its human patrons." + boozepwr = 50 //strong! + taste_description = "honey and red wine" + chemical_flags_skyrat = REAGENT_BLOOD_REGENERATING + +/datum/glass_style/drinking_glass/nord_king + required_drink_type = /datum/reagent/consumable/ethanol/nord_king + icon = 'modular_doppler/modular_food_and_drinks/icons/drinks.dmi' + icon_state = "nord_king" + name = "keg of nord king" + desc = "A dripping keg of red mead." + +/datum/reagent/consumable/ethanol/nord_king/expose_mob(mob/living/exposed_mob, methods, reac_volume) + if(ishumanbasic(exposed_mob) || isdwarf(exposed_mob)) + quality = RACE_DRINK + else + quality = DRINK_GOOD + return ..() + +/datum/reagent/consumable/ethanol/velvet_kiss + name = "Velvet Kiss" + color = "#EB1010" //(235, 16, 16) + description = "A bloody drink mixed with wine." + boozepwr = 10 //weak + taste_description = "iron with grapejuice" + chemical_flags = REAGENT_CAN_BE_SYNTHESIZED + chemical_flags_skyrat = REAGENT_BLOOD_REGENERATING + +/datum/glass_style/drinking_glass/velvet_kiss + required_drink_type = /datum/reagent/consumable/ethanol/velvet_kiss + icon = 'modular_doppler/modular_food_and_drinks/icons/drinks.dmi' + icon_state = "velvet_kiss" + name = "glass of velvet kiss" + desc = "Red and white drink for the upper classes or undead." + +/datum/reagent/consumable/ethanol/velvet_kiss/expose_mob(mob/living/exposed_mob, methods, reac_volume) + if(iszombie(exposed_mob) || isvampire(exposed_mob) || isdullahan(exposed_mob) || ishemophage(exposed_mob)) //Rare races! + quality = RACE_DRINK + else + quality = DRINK_GOOD + return ..() + +/datum/reagent/consumable/ethanol/velvet_kiss/on_mob_life(mob/living/carbon/drinker, seconds_per_tick, times_fired) + . = ..() + if(drinker.blood_volume < BLOOD_VOLUME_NORMAL) + drinker.blood_volume = min(drinker.blood_volume + (1 * REM * seconds_per_tick), BLOOD_VOLUME_NORMAL) //Same as Bloody Mary, as it is roughly the same difficulty to make. Gives hemophages a bit more choices to supplant their blood levels. + +/datum/reagent/consumable/ethanol/abduction_fruit + name = "Abduction Fruit" + color = "#DEFACD" //(222, 250, 205) + description = "Mixing of juices to make an alien taste." + boozepwr = 80 //Strong + taste_description = "grass and lime" + +/datum/glass_style/drinking_glass/abduction_fruit + required_drink_type = /datum/reagent/consumable/ethanol/abduction_fruit + icon = 'modular_doppler/modular_food_and_drinks/icons/drinks.dmi' + icon_state = "abduction_fruit" + name = "glass of abduction fruit" + desc = "Mixed fruits that were never meant to be mixed..." + +/datum/reagent/consumable/ethanol/abduction_fruit/expose_mob(mob/living/exposed_mob, methods, reac_volume) + if(isabductor(exposed_mob) || isxenohybrid(exposed_mob)) + quality = RACE_DRINK + else + quality = DRINK_GOOD + return ..() + +/datum/reagent/consumable/ethanol/bug_zapper + name = "Bug Zapper" + color = "#F5882A" //(222, 250, 205) + description = "Copper and lemon juice. Hardly even a drink." + boozepwr = 5 //No booze really + taste_description = "copper and AC power" + +/datum/glass_style/drinking_glass/bug_zapper + required_drink_type = /datum/reagent/consumable/ethanol/bug_zapper + icon = 'modular_doppler/modular_food_and_drinks/icons/drinks.dmi' + icon_state = "bug_zapper" + name = "glass of bug zapper" + desc = "An odd mix of copper, lemon juice and power meant for non-human consumption." + +/datum/reagent/consumable/ethanol/bug_zapper/expose_mob(mob/living/exposed_mob, methods, reac_volume) + if(isinsect(exposed_mob) || isflyperson(exposed_mob) || ismoth(exposed_mob)) + quality = RACE_DRINK + else + quality = DRINK_GOOD + return ..() + +/datum/reagent/consumable/ethanol/mush_crush + name = "Mush Crush" + color = "#F5882A" //(222, 250, 205) + description = "Soil in a glass." + boozepwr = 5 //No booze really + taste_description = "dirt and iron" + +/datum/glass_style/drinking_glass/mush_crush + required_drink_type = /datum/reagent/consumable/ethanol/mush_crush + icon = 'modular_doppler/modular_food_and_drinks/icons/drinks.dmi' + icon_state = "mush_crush" + name = "glass of mush crush" + desc = "Popular among people that want to grow their own food rather than drink the soil." + +/datum/reagent/consumable/ethanol/mush_crush/expose_mob(mob/living/exposed_mob, methods, reac_volume) + if(ispodperson(exposed_mob) || issnail(exposed_mob)) + quality = RACE_DRINK + else + quality = DRINK_GOOD + return ..() + +/datum/reagent/consumable/ethanol/hollow_bone + name = "Hollow Bone" + color = "#FCF7D4" //(252, 247, 212) + description = "Shockingly none-harmful mix of toxins and milk." + boozepwr = 15 + taste_description = "Milk and salt" + +/datum/glass_style/drinking_glass/hollow_bone + required_drink_type = /datum/reagent/consumable/ethanol/hollow_bone + icon = 'modular_doppler/modular_food_and_drinks/icons/drinks.dmi' + icon_state = "hollow_bone" + name = "skull of hollow bone" + desc = "Mixing of milk and bone hurting juice for enjoyment for rather skinny people." + +/datum/reagent/consumable/ethanol/hollow_bone/expose_mob(mob/living/exposed_mob, methods, reac_volume) + if(isplasmaman(exposed_mob) || isskeleton(exposed_mob)) + quality = RACE_DRINK + else + quality = DRINK_GOOD + return ..() + +/datum/reagent/consumable/ethanol/jell_wyrm + name = "Jell Wyrm" + color = "#FF6200" //(255, 98, 0) + description = "Horrible mix of CO2, toxins, and heat. Meant for slime based life." + boozepwr = 40 + taste_description = "tropical sea" + +/datum/glass_style/drinking_glass/jell_wyrm + required_drink_type = /datum/reagent/consumable/ethanol/jell_wyrm + icon = 'modular_doppler/modular_food_and_drinks/icons/drinks.dmi' + icon_state = "jell_wyrm" + name = "glass of jell wyrm" + desc = "A bubbly drink that is rather inviting to those that don't know who it's meant for." + +/datum/reagent/consumable/ethanol/jell_wyrm/on_mob_life(mob/living/carbon/affected_mob, seconds_per_tick, times_fired) + . = ..() + if(prob(20)) + if(affected_mob.adjustToxLoss(0.5 * REM * seconds_per_tick, updating_health = FALSE)) + return UPDATE_MOB_HEALTH + +#define JELLWYRM_DISGUST 25 + +/datum/reagent/consumable/ethanol/jell_wyrm/expose_mob(mob/living/exposed_mob, methods, reac_volume) + if(isjellyperson(exposed_mob) || isslimeperson(exposed_mob) || isluminescent(exposed_mob)) + quality = RACE_DRINK + else //if youre not a slime, jell wyrm should be GROSS + exposed_mob.adjust_disgust(JELLWYRM_DISGUST) + return ..() + +#undef JELLWYRM_DISGUST + +/datum/reagent/consumable/ethanol/laval_spit //Yes Laval + name = "Laval Spit" + color = "#DE3009" //(222, 48, 9) + description = "Heat minerals and some mauna loa. Meant for rock based life." + boozepwr = 30 + taste_description = "tropical island" + +/datum/glass_style/drinking_glass/laval_spit + required_drink_type = /datum/reagent/consumable/ethanol/laval_spit + icon = 'modular_doppler/modular_food_and_drinks/icons/drinks.dmi' + icon_state = "laval_spit" + name = "glass of laval spit" + desc = "Piping hot drink for those who can stomach the heat of lava." + +/datum/reagent/consumable/ethanol/laval_spit/expose_mob(mob/living/exposed_mob, methods, reac_volume) + if(isgolem(exposed_mob)) + quality = RACE_DRINK + else + quality = DRINK_GOOD + return ..() + +/datum/reagent/consumable/ethanol/frisky_kitty + name = "Frisky Kitty" + color = "#FCF7D4" //(252, 247, 212) + description = "Warm milk mixed with catnip." + boozepwr = 0 + taste_description = "Warm milk and catnip" + +/datum/glass_style/drinking_glass/frisky_kitty + required_drink_type = /datum/reagent/consumable/ethanol/frisky_kitty + icon = 'modular_doppler/modular_food_and_drinks/icons/drinks.dmi' + icon_state = "frisky_kitty" + name = "cup of frisky kitty" + desc = "Warm milk and some catnip." + +/datum/reagent/consumable/ethanol/frisky_kitty/expose_mob(mob/living/exposed_mob, methods, reac_volume) + if(isfeline(exposed_mob)) + quality = RACE_DRINK + else + quality = DRINK_GOOD + return ..() + + +/datum/reagent/consumable/ethanol/bloodshot_base + name = "Bloodshot Base" + description = "The bootleg blend of nutrients and alcohol that goes into making Bloodshots. Doesn't taste too great on its own, for Hemophages at least." + color = "#c29ca1" + boozepwr = 25 // Still more concentrated than in Bloodshot. + taste_description = "nutritious mix with an alcoholic kick to it" + chemical_flags = REAGENT_CAN_BE_SYNTHESIZED + + +/datum/reagent/consumable/ethanol/bloodshot + name = "Bloodshot" + description = "The history of the 'Bloodshot' is based in a mix of flavor-neutral chems devised to help deliver nutrients to a Hemophage's tumorous organs. Due to the expense of the real thing and the clinical nature of it, this liquor has been designed as a 'improvised' alternative; though, still tasting like a hangover cure. It smells like iron, giving a clue to the key ingredient." + color = "#a30000" + boozepwr = 20 // The only booze in it is Bloody Mary + taste_description = "blood filled to the brim with nutrients of all kinds" + chemical_flags = REAGENT_CAN_BE_SYNTHESIZED + chemical_flags_skyrat = REAGENT_BLOOD_REGENERATING + + +/datum/glass_style/drinking_glass/bloodshot + required_drink_type = /datum/reagent/consumable/ethanol/bloodshot + icon = 'modular_doppler/modular_food_and_drinks/icons/drinks.dmi' + icon_state = "bloodshot" + name = "glass of bloodshot" + desc = "The history of the 'Bloodshot' is based in a mix of flavor-neutral chems devised to help deliver nutrients to a Hemophage's tumorous organs. Due to the expense of the real thing and the clinical nature of it, this liquor has been designed as a 'improvised' alternative; though, still tasting like a hangover cure. It smells like iron, giving a clue to the key ingredient." + + +#define BLOODSHOT_DISGUST 25 + +/datum/reagent/consumable/ethanol/bloodshot/expose_mob(mob/living/exposed_mob, methods, reac_volume) + if(ishemophage(exposed_mob)) + quality = RACE_DRINK + + else if(exposed_mob.blood_volume < exposed_mob.blood_volume_normal) + quality = DRINK_GOOD + + if(!quality) // Basically, you don't have a reason to want to have this in your system, it doesn't taste good to you! + exposed_mob.adjust_disgust(BLOODSHOT_DISGUST) + + return ..() + +#undef BLOODSHOT_DISGUST + +/datum/reagent/consumable/ethanol/bloodshot/on_mob_life(mob/living/carbon/drinker, seconds_per_tick, times_fired) + . = ..() + if(drinker.blood_volume < drinker.blood_volume_normal) + drinker.blood_volume = max(drinker.blood_volume, min(drinker.blood_volume + (3 * REM * seconds_per_tick), BLOOD_VOLUME_NORMAL)) //Bloodshot quickly restores blood loss. + +/datum/reagent/consumable/ethanol/blizzard_brew + name = "Blizzard Brew" + description = "An ancient recipe. Served best chilled as much as dwarvenly possible." + color = rgb(180, 231, 216) + boozepwr = 25 + metabolization_rate = 1.25 * REAGENTS_METABOLISM + taste_description = "ancient icicles" + overdose_threshold = 25 + var/obj/structure/ice_stasis/cube + var/atom/movable/screen/alert/status_effect/freon/cryostylane_alert + +/datum/glass_style/drinking_glass/blizzard_brew + required_drink_type = /datum/reagent/consumable/ethanol/blizzard_brew + icon = 'modular_doppler/modular_food_and_drinks/icons/drinks.dmi' + icon_state = "blizzard_brew" + name = "glass of Blizzard Brew" + desc = "An ancient recipe. Served best chilled as much as dwarvenly possible." + +/datum/reagent/consumable/ethanol/blizzard_brew/expose_mob(mob/living/exposed_mob, methods, reac_volume) + if(isdwarf(exposed_mob)) + quality = RACE_DRINK + else + quality = DRINK_NICE + return ..() + +/datum/reagent/consumable/ethanol/blizzard_brew/overdose_start(mob/living/carbon/drinker) + . = ..() + cube = new /obj/structure/ice_stasis(get_turf(drinker)) + cube.color = COLOR_CYAN + cube.set_anchored(TRUE) + drinker.forceMove(cube) + cryostylane_alert = drinker.throw_alert("cryostylane_alert", /atom/movable/screen/alert/status_effect/freon/cryostylane) + cryostylane_alert.attached_effect = src //so the alert can reference us, if it needs to + +/datum/reagent/consumable/ethanol/blizzard_brew/on_mob_delete(mob/living/carbon/drinker, amount) + QDEL_NULL(cube) + drinker.clear_alert("cryostylane_alert") + return ..() + +/datum/reagent/consumable/ethanol/molten_mead + name = "Molten Mead" + description = "Famously known to set beards aflame. Ingest at your own risk!" + color = rgb(224, 78, 16) + boozepwr = 35 + metabolization_rate = 1.25 * REAGENTS_METABOLISM + taste_description = "burning wasps" + overdose_threshold = 25 + +/datum/glass_style/drinking_glass/molten_mead + required_drink_type = /datum/reagent/consumable/ethanol/molten_mead + icon = 'modular_doppler/modular_food_and_drinks/icons/drinks.dmi' + icon_state = "molten_mead" + name = "glass of Molten Mead" + desc = "Famously known to set beards aflame. Ingest at your own risk!" + +/datum/reagent/consumable/ethanol/molten_mead/expose_mob(mob/living/exposed_mob, methods, reac_volume) + if(isdwarf(exposed_mob)) + quality = RACE_DRINK + else + quality = DRINK_VERYGOOD + return ..() + +/datum/reagent/consumable/ethanol/molten_mead/overdose_start(mob/living/carbon/drinker) + drinker.adjust_fire_stacks(2) + drinker.ignite_mob() + ..() +*/ +/datum/reagent/consumable/ethanol/hippie_hooch + name = "Hippie Hooch" + description = "Peace and love! Under request of the HR department, this drink is sure to sober you up quickly." + color = rgb(77, 138, 34) + boozepwr = -20 + taste_description = "eggy hemp" + var/static/list/status_effects_to_clear = list( + /datum/status_effect/confusion, + /datum/status_effect/dizziness, + /datum/status_effect/drowsiness, + /datum/status_effect/speech/slurring/drunk, + ) + +/datum/glass_style/drinking_glass/hippie_hooch + required_drink_type = /datum/reagent/consumable/ethanol/hippie_hooch + icon = 'modular_doppler/modular_food_and_drinks/icons/drinks.dmi' + icon_state = "hippie_hooch" + name = "glass of Hippie Hooch" + desc = "Peace and love! Under request of the HR department, this drink is sure to sober you up quickly." + +/datum/reagent/consumable/ethanol/hippie_hooch/expose_mob(mob/living/exposed_mob, methods, reac_volume) + if(isdwarf(exposed_mob)) + quality = RACE_DRINK + else + quality = DRINK_FANTASTIC + return ..() + +/datum/reagent/consumable/ethanol/hippie_hooch/on_mob_life(mob/living/carbon/affected_mob, seconds_per_tick, times_fired) + for(var/effect in status_effects_to_clear) + affected_mob.remove_status_effect(effect) + affected_mob.reagents.remove_reagent(/datum/reagent/consumable/ethanol, 3 * REM * seconds_per_tick, include_subtypes = TRUE) + . = ..() + if(affected_mob.adjustToxLoss(-0.2 * REM * seconds_per_tick, updating_health = FALSE, required_biotype = affected_biotype)) + . = UPDATE_MOB_HEALTH + affected_mob.adjust_drunk_effect(-10 * REM * seconds_per_tick) + +/datum/reagent/consumable/ethanol/research_rum + name = "Research Rum" + description = "Cooked up by dwarven scientists, this glowing pink brew is sure to supercharge your thinking. How? Science!" + color = rgb(169, 69, 169) + boozepwr = 50 + taste_description = "slippery grey matter" + +/datum/glass_style/drinking_glass/research_rum + required_drink_type = /datum/reagent/consumable/ethanol/research_rum + icon = 'modular_doppler/modular_food_and_drinks/icons/drinks.dmi' + icon_state = "research_rum" + name = "glass of Research Rum" + desc = "Cooked up by dwarven scientists, this glowing pink brew is sure to supercharge your thinking. How? Science!" + +/datum/reagent/consumable/ethanol/research_rum/expose_mob(mob/living/exposed_mob, methods, reac_volume) + if(isdwarf(exposed_mob)) + quality = RACE_DRINK + else + quality = DRINK_GOOD + return ..() + +/datum/reagent/consumable/ethanol/research_rum/on_mob_life(mob/living/carbon/drinker, seconds_per_tick, times_fired) + . = ..() + if(prob(5)) + drinker.say(pick_list_replacements(VISTA_FILE, "ballmer_good_msg"), forced = "ballmer") + +/datum/reagent/consumable/ethanol/golden_grog + name = "Golden Grog" + description = "A drink concocted by a dwarven Quartermaster who had too much time and money on his hands. Commonly ordered by influencers looking to flaunt their wealth." + color = rgb(247, 230, 141) + boozepwr = 70 + taste_description = "sweet credit holochips" + +/datum/glass_style/drinking_glass/golden_grog + required_drink_type = /datum/reagent/consumable/ethanol/golden_grog + icon = 'modular_doppler/modular_food_and_drinks/icons/drinks.dmi' + icon_state = "golden_grog" + name = "glass of Golden Grog" + desc = "A drink concocted by a dwarven Quartermaster who had too much time and money on his hands. Commonly ordered by influencers looking to flaunt their wealth." + +/datum/reagent/consumable/ethanol/golden_grog/expose_mob(mob/living/exposed_mob, methods, reac_volume) + if(isdwarf(exposed_mob)) + quality = RACE_DRINK + else + quality = DRINK_FANTASTIC + return ..() + +// RACIAL DRINKS END + +/datum/reagent/consumable/ethanol/appletini + name = "Appletini" + color = "#9bd1a9" //(155, 209, 169) + description = "The electric-green appley beverage nobody can turn down!" + boozepwr = 50 + taste_description = "Sweet and green" + quality = DRINK_GOOD + +/datum/glass_style/drinking_glass/appletini + required_drink_type = /datum/reagent/consumable/ethanol/appletini + icon = 'modular_doppler/modular_food_and_drinks/icons/drinks.dmi' + icon_state = "appletini" + name = "glass of appletini" + desc = "An appley beverage in a martini glass" + +/datum/reagent/consumable/ethanol/quadruple_sec/cityofsin //making this a subtype was some REAL JANK, but it saves me a headache, and it looks good! + name = "City of Sin" + color = "#eb9378" //(235, 147, 120) + description = "A smooth, fancy drink for people of ill repute" + boozepwr = 70 + taste_description = "Your own sins" + quality = DRINK_VERYGOOD //takes extra effort + chemical_flags = REAGENT_CAN_BE_SYNTHESIZED + +/datum/glass_style/drinking_glass/cityofsin + required_drink_type = /datum/reagent/consumable/ethanol/quadruple_sec/cityofsin + icon = 'modular_doppler/modular_food_and_drinks/icons/drinks.dmi' + icon_state = "cityofsin" + name = "glass of city of sin" + desc = "Looking at it makes you recall every mistake you've made." + +/datum/reagent/consumable/ethanol/shakiri + name = "Shakiri" + description = "A sweet, fragrant red drink made from fermented kiri fruits. It seems to gently sparkle when exposed to light." + boozepwr = 45 + color = "#cf3c3c" + quality = DRINK_GOOD + taste_description = "delicious liquified jelly" + chemical_flags = REAGENT_CAN_BE_SYNTHESIZED + +/datum/glass_style/drinking_glass/shakiri + required_drink_type = /datum/reagent/consumable/ethanol/shakiri + icon = 'modular_doppler/modular_food_and_drinks/icons/drinks.dmi' + icon_state = "shakiri" + name = "glass of shakiri" + desc = "A sweet, fragrant red drink made from fermented kiri fruits. It seems to gently sparkle when exposed to light." + +/datum/reagent/consumable/ethanol/shakiri_spritz + name = "Shakiri Spritz" + description = "A carbonated cocktail made from shakiri and orange juice with soda water." + color = "#cf863c" + quality = DRINK_GOOD + boozepwr = 45 + taste_description = "tangy, carbonated sweetness" + +/datum/glass_style/drinking_glass/shakiri_spritz + required_drink_type = /datum/reagent/consumable/ethanol/shakiri_spritz + icon = 'modular_doppler/modular_food_and_drinks/icons/drinks.dmi' + icon_state = "shakiri_spritz" + name = "glass of shakiri spritz" + desc = "A carbonated cocktail made from shakiri and orange juice with soda water." + +/datum/reagent/consumable/ethanol/crimson_hurricane + name = "Crimson Hurricane" + description = "A strong, citrusy cocktail of human origin, now made with shakiri and kiri jelly for a delightfully sweet drink." + color = "#b86637" + quality = DRINK_VERYGOOD + boozepwr = 60 + taste_description = "thick, fruity sweetness with a punch" + +/datum/glass_style/drinking_glass/crimson_hurricane + required_drink_type = /datum/reagent/consumable/ethanol/crimson_hurricane + icon = 'modular_doppler/modular_food_and_drinks/icons/drinks.dmi' + icon_state = "crimson_hurricane" + name = "glass of crimson hurricane" + desc = "A strong, citrusy cocktail of human origin, now with shakiri and kiri jelly for a delightfully sweet drink." + +/datum/reagent/consumable/ethanol/shakiri_rogers + name = "Shakiri Rogers" + description = "A take on the classic Roy Rogers, with shakiri instead of grenadine. Sweet and refreshing." + color = "#6F2B1A" + quality = DRINK_GOOD + boozepwr = 45 + taste_description = "fruity, carbonated soda with a slight kick" + +/datum/glass_style/drinking_glass/shakiri_rogers + required_drink_type = /datum/reagent/consumable/ethanol/shakiri_rogers + icon = 'modular_doppler/modular_food_and_drinks/icons/drinks.dmi' + icon_state = "shakiri_rogers" + name = "glass of shakiri rogers" + desc = "A take on the classic Roy Rogers, with shakiri instead of grenadine. Sweet and refreshing." diff --git a/modular_doppler/modular_food_and_drinks/drink_reagents.dm b/modular_doppler/modular_food_and_drinks/drink_reagents.dm new file mode 100644 index 0000000000000..0becf4329ae8f --- /dev/null +++ b/modular_doppler/modular_food_and_drinks/drink_reagents.dm @@ -0,0 +1,79 @@ +/datum/reagent/consumable/pinkmilk + name = "Strawberry Milk" + description = "A drink of a bygone era of milk and artificial sweetener back on a rock." + color = "#f76aeb"//rgb(247, 106, 235) + quality = DRINK_VERYGOOD + taste_description = "sweet strawberry and milk cream" + +/datum/glass_style/drinking_glass/pinkmilk + required_drink_type = /datum/reagent/consumable/pinkmilk + icon = 'modular_nova/master_files/icons/obj/drinks.dmi' + icon_state = "pinkmilk" + name = "tall glass of strawberry milk" + desc = "Delicious flavored strawberry syrup mixed with milk." + +/datum/reagent/consumable/pinkmilk/on_mob_life(mob/living/carbon/M) + if(prob(15)) + to_chat(M, span_notice("[pick("You cant help to smile.","You feel nostalgia all of sudden.","You remember to relax.")]")) + ..() + . = 1 + +/datum/reagent/consumable/pinktea //Tiny Tim song + name = "Strawberry Tea" + description = "A timeless classic!" + color = "#f76aeb"//rgb(247, 106, 235) + quality = DRINK_VERYGOOD + taste_description = "sweet tea with a hint of strawberry" + +/datum/glass_style/drinking_glass/pinktea + required_drink_type = /datum/reagent/consumable/pinktea + icon = 'modular_nova/master_files/icons/obj/drinks.dmi' + icon_state = "pinktea" + name = "mug of strawberry tea" + desc = "Delicious traditional tea flavored with strawberries." + +/datum/reagent/consumable/pinktea/on_mob_life(mob/living/carbon/M) + if(prob(10)) + to_chat(M, span_notice("[pick("Diamond skies where white deer fly.","Sipping strawberry tea.","Silver raindrops drift through timeless, Neverending June.","Crystal ... pearls free, with love!","Beaming love into me.")]")) + ..() + . = TRUE + +/datum/reagent/consumable/catnip_tea + name = "Catnip Tea" + description = "A sleepy and tasty catnip tea!" + color = "#101000" // rgb: 16, 16, 0 + taste_description = "sugar and catnip" + +/datum/glass_style/drinking_glass/catnip_tea + required_drink_type = /datum/reagent/consumable/catnip_tea + icon = 'modular_nova/master_files/icons/obj/drinks.dmi' + icon_state = "catnip_tea" + name = "glass of catnip tea" + desc = "A purrfect drink for a cat." + +/datum/reagent/consumable/catnip_tea/on_mob_life(mob/living/carbon/M) + M.adjustStaminaLoss(min(50 - M.getStaminaLoss(), 3)) + if(isfeline(M)) + if(prob(20)) + M.emote("nya") + if(prob(20)) + to_chat(M, span_notice("[pick("Headpats feel nice.", "Backrubs would be nice.", "Mew")]")) + else + to_chat(M, span_notice("[pick("I feel oddly calm.", "I feel relaxed.", "Mew?")]")) + ..() + +/datum/reagent/consumable/ethanol/beerbatter + name = "Beer Batter" + description = "Probably not the greatest idea to drink...sludge." + color = "#f5f4e9" + nutriment_factor = 2 * REAGENTS_METABOLISM + taste_description = "flour and cheap booze" + boozepwr = 8 // beer diluted at about a 1:3 ratio + ph = 6 + +/datum/glass_style/drinking_glass/beerbatter + required_drink_type = /datum/reagent/consumable/ethanol/beerbatter + icon = 'icons/obj/drinks/shakes.dmi' + icon_state = "chocolatepudding" + name = "glass of beer batter" + desc = "Used in cooking, pure cholesterol, Scottish people eat it." diff --git a/modular_doppler/modular_food_and_drinks/drinks_recipes.dm b/modular_doppler/modular_food_and_drinks/drinks_recipes.dm new file mode 100644 index 0000000000000..46e4a95a37e42 --- /dev/null +++ b/modular_doppler/modular_food_and_drinks/drinks_recipes.dm @@ -0,0 +1,421 @@ +/*STUFF WE CAN'T USE YET + +/datum/chemical_reaction/drink/synthanol + results = list(/datum/reagent/consumable/ethanol/synthanol = 3) + required_reagents = list( + /datum/reagent/lube = 1, + /datum/reagent/toxin/plasma = 1, + /datum/reagent/fuel = 1, + ) + mix_message = "The chemicals mix to create shiny, blue substance." + +/datum/chemical_reaction/drink/robottears + results = list(/datum/reagent/consumable/ethanol/synthanol/robottears = 3) + required_reagents = list( + /datum/reagent/consumable/ethanol/synthanol = 1, + /datum/reagent/fuel/oil = 1, + /datum/reagent/consumable/sodawater = 1, + ) + mix_message = "The ingredients combine into a stiff, dark goo." + +/datum/chemical_reaction/drink/trinary + results = list(/datum/reagent/consumable/ethanol/synthanol/trinary = 3) + required_reagents = list( + /datum/reagent/consumable/ethanol/synthanol = 1, + /datum/reagent/consumable/limejuice = 1, + /datum/reagent/consumable/orangejuice = 1, + ) + mix_message = "The ingredients mix into a colorful substance." + +/datum/chemical_reaction/drink/servo + results = list(/datum/reagent/consumable/ethanol/synthanol/servo = 4) + required_reagents = list( + /datum/reagent/consumable/ethanol/synthanol = 2, + /datum/reagent/consumable/cream = 1, + /datum/reagent/consumable/hot_coco = 1, + ) + mix_message = "The ingredients mix into a dark brown substance." + +/datum/chemical_reaction/drink/uplink + results = list(/datum/reagent/consumable/ethanol/synthanol/uplink = 5) + required_reagents = list( + /datum/reagent/consumable/ethanol/synthanol = 1, + /datum/reagent/consumable/ethanol/rum = 1, + /datum/reagent/consumable/ethanol/vodka = 1, + /datum/reagent/consumable/ethanol/tequila = 1, + /datum/reagent/consumable/ethanol/whiskey = 1, + ) + mix_message = "The chemicals mix to create a shiny, orange substance." + +/datum/chemical_reaction/drink/synthncoke + results = list(/datum/reagent/consumable/ethanol/synthanol/synthncoke = 2) + required_reagents = list( + /datum/reagent/consumable/ethanol/synthanol = 1, + /datum/reagent/consumable/space_cola = 1, + ) + mix_message = "The chemicals mix to create a smooth, fizzy substance." + +/datum/chemical_reaction/drink/synthignon + results = list(/datum/reagent/consumable/ethanol/synthanol/synthignon = 2) + required_reagents = list( + /datum/reagent/consumable/ethanol/synthanol = 1, + /datum/reagent/consumable/ethanol/wine = 1, + ) + mix_message = "The chemicals mix to create a fine, red substance." +*/ +// Other Booze + +/datum/chemical_reaction/drink/hot_toddy + results = list(/datum/reagent/consumable/ethanol/hot_toddy = 5) + required_reagents = list( + /datum/reagent/consumable/ethanol/rum = 1, + /datum/reagent/consumable/tea = 3, + /datum/reagent/consumable/honey = 1, + ) + mix_message = "A loud popping begins to fill the air as the drink is mixed." + +/datum/chemical_reaction/drink/hellfire + results = list(/datum/reagent/consumable/ethanol/hellfire = 4) + required_reagents = list( + /datum/reagent/consumable/ethanol/rum = 2, + /datum/reagent/consumable/ice = 1, + /datum/reagent/consumable/ethanol/crevice_spike = 1, + ) + mix_message = "The liquid begins to churn as it changes to an amber orange and catches on fire." + +/datum/chemical_reaction/drink/sins_delight + results = list(/datum/reagent/consumable/ethanol/sins_delight = 5) + required_reagents = list( + /datum/reagent/consumable/ethanol/demonsblood = 2, + /datum/reagent/consumable/ethanol/triple_sec = 1, + /datum/reagent/consumable/ethanol/martini = 1, + /datum/reagent/consumable/ethanol/changelingsting = 1, + ) + mix_message = "The liquid starts swirling, before forming a pink cloud that dissipates in the air." + +/datum/chemical_reaction/drink/strawberry_daiquiri + results = list(/datum/reagent/consumable/ethanol/strawberry_daiquiri = 7) + required_reagents = list( + /datum/reagent/consumable/ethanol/rum = 2, + /datum/reagent/consumable/limejuice = 1, + /datum/reagent/consumable/sugar = 1, + /datum/reagent/consumable/berryjuice = 2, + /datum/reagent/consumable/ice = 1, + ) + +/datum/chemical_reaction/drink/miami_vice + results = list(/datum/reagent/consumable/ethanol/miami_vice = 2) + required_reagents = list( + /datum/reagent/consumable/ethanol/pina_colada = 1, + /datum/reagent/consumable/ethanol/strawberry_daiquiri = 1, + ) + +/datum/chemical_reaction/drink/malibu_sunset + results = list(/datum/reagent/consumable/ethanol/malibu_sunset = 5) + required_reagents = list( + /datum/reagent/consumable/ethanol/painkiller = 2, + /datum/reagent/consumable/grenadine = 1, + /datum/reagent/consumable/orangejuice = 1, + /datum/reagent/consumable/ice = 1, + ) + +/datum/chemical_reaction/drink/liz_fizz + results = list(/datum/reagent/consumable/ethanol/liz_fizz = 5) + required_reagents = list( + /datum/reagent/consumable/triple_citrus = 3, + /datum/reagent/consumable/ice = 1, + /datum/reagent/consumable/cream = 1,) + +/datum/chemical_reaction/drink/hotlime_miami + results = list(/datum/reagent/consumable/ethanol/hotlime_miami = 2) + required_reagents = list( + /datum/reagent/medicine/ephedrine = 1, + /datum/reagent/consumable/ethanol/pina_colada = 1, + ) + +/datum/chemical_reaction/drink/coggrog + results = list(/datum/reagent/consumable/ethanol/coggrog = 3) + required_reagents = list( + /datum/reagent/consumable/ethanol/cognac = 1, + /datum/reagent/fuel = 1, + /datum/reagent/consumable/ethanol/screwdrivercocktail = 1, + ) + mix_message = "You hear faint sounds of gears turning as it mixes." + mix_sound = 'sound/machines/clockcult/steam_whoosh.ogg' + +/datum/chemical_reaction/drink/badtouch + results = list(/datum/reagent/consumable/ethanol/badtouch = 5) + required_reagents = list( + /datum/reagent/consumable/ethanol/cognac = 2, + /datum/reagent/consumable/limejuice = 2, + /datum/reagent/consumable/orangejuice=1, + ) + +/datum/chemical_reaction/drink/marsblast + results = list(/datum/reagent/consumable/ethanol/marsblast = 5) + required_reagents = list( + /datum/reagent/consumable/ethanol/whiskey = 3, + /datum/reagent/consumable/dr_gibb = 2, + ) + +/datum/chemical_reaction/drink/mercuryblast + results = list(/datum/reagent/consumable/ethanol/mercuryblast = 4) + required_reagents = list( + /datum/reagent/consumable/ethanol/vodka = 2, + /datum/reagent/consumable/spacemountainwind = 1, + /datum/reagent/consumable/ice = 1, + ) + +/datum/chemical_reaction/drink/piledriver + results = list(/datum/reagent/consumable/ethanol/piledriver = 6) + required_reagents = list( + /datum/reagent/consumable/ethanol/screwdrivercocktail = 1, + /datum/reagent/consumable/ethanol/rum_coke = 1, + ) + +/datum/chemical_reaction/drink/zenstar + results = list(/datum/reagent/consumable/ethanol/zenstar = 5) + required_reagents = list( + /datum/reagent/consumable/ethanol/triple_sec = 2, + /datum/reagent/consumable/lemonjuice = 2, + /datum/reagent/consumable/grenadine = 1, + ) + +/datum/chemical_reaction/drink/appletini + results = list(/datum/reagent/consumable/ethanol/appletini = 5) + required_reagents = list( + /datum/reagent/consumable/ethanol/vodka = 3, + /datum/reagent/consumable/ethanol/hcider = 1, + /datum/reagent/consumable/lemonjuice = 1, + ) + +/datum/chemical_reaction/drink/quadruple_sec/cityofsin + results = list(/datum/reagent/consumable/ethanol/quadruple_sec/cityofsin = 4) + required_reagents = list( + /datum/reagent/consumable/ethanol/vodka = 2, + /datum/reagent/consumable/ethanol/champagne = 1, + /datum/reagent/consumable/berryjuice = 1, + ) + +/datum/chemical_reaction/drink/blizzard_brew + results = list(/datum/reagent/consumable/ethanol/blizzard_brew = 3) + required_reagents = list( + /datum/reagent/consumable/ethanol/iced_beer = 1, + /datum/reagent/consumable/ice = 1, + /datum/reagent/inverse/cryostylane = 1, + ) + mix_message = "You hear crackling ice as it mixes." + mix_sound = 'sound/effects/ice_shovel.ogg' + +/datum/chemical_reaction/drink/molten_mead + results = list(/datum/reagent/consumable/ethanol/molten_mead = 3) + required_reagents = list( + /datum/reagent/consumable/condensedcapsaicin = 2, + /datum/reagent/consumable/ethanol/mead = 2, + /datum/reagent/consumable/ethanol/mauna_loa = 1, + ) + mix_message = "You hear sizzling flesh and angry wasps buzzing as it mixes." + mix_sound = 'sound/effects/wounds/sizzle2.ogg' + +/datum/chemical_reaction/drink/hippie_hooch + results = list(/datum/reagent/consumable/ethanol/hippie_hooch = 5) + required_reagents = list( + /datum/reagent/medicine/antihol = 1, + /datum/reagent/consumable/ethanol/crevice_spike = 3, + /datum/reagent/medicine/earthsblood = 1, + ) + mix_message = "You hear wood flutes and nature as it mixes." + mix_sound = 'modular_skyrat/modules/emotes/sound/voice/hoot.ogg' + +/datum/chemical_reaction/drink/research_rum + results = list(/datum/reagent/consumable/ethanol/research_rum = 4) + required_reagents = list( + /datum/reagent/consumable/ethanol/bananahonk = 2, + /datum/reagent/inverse/neurine = 1, + /datum/reagent/consumable/ethanol/grog = 1, + ) + mix_message = "You hear gurgling and dinging as it mixes." + mix_sound = 'sound/machines/microwave/microwave-end.ogg' + +/datum/chemical_reaction/drink/golden_grog + results = list(/datum/reagent/consumable/ethanol/golden_grog = 5) + required_reagents = list( + /datum/reagent/consumable/ethanol/goldschlager = 10, + /datum/reagent/gold = 1, + /datum/reagent/silver = 1, + /datum/reagent/cellulose = 1, + /datum/reagent/spraytan = 1, + ) + mix_message = "You hear golden coins and snobby rich laughing as it mixes." + mix_sound = 'sound/items/coinflip.ogg' + +/* DEPRECATED UNTIL WE'RE READY +// RACE SPECIFIC DRINKS + +/datum/chemical_reaction/drink/coldscales + results = list(/datum/reagent/consumable/ethanol/coldscales = 3) + required_reagents = list( + /datum/reagent/consumable/tea = 1, + /datum/reagent/toxin/slimejelly = 1, + /datum/reagent/consumable/menthol = 1, + ) + +/datum/chemical_reaction/drink/oil_drum + results = list(/datum/reagent/consumable/ethanol/oil_drum = 3) + required_reagents = list( + /datum/reagent/consumable/ethanol = 1, + /datum/reagent/fuel/oil = 1, + /datum/reagent/consumable/ethanol/champagne = 12, + ) + +/datum/chemical_reaction/drink/nord_king + results = list(/datum/reagent/consumable/ethanol/nord_king = 10) + required_reagents = list( + /datum/reagent/consumable/ethanol = 5, + /datum/reagent/consumable/honey = 1, + /datum/reagent/consumable/ethanol/red_mead = 10, + ) + +/datum/chemical_reaction/drink/velvet_kiss + results = list(/datum/reagent/consumable/ethanol/velvet_kiss = 15) //Limited races use this + required_reagents = list( + /datum/reagent/blood = 5, + /datum/reagent/consumable/tea = 1, + /datum/reagent/consumable/ethanol/wine = 10, + ) + +/datum/chemical_reaction/drink/abduction_fruit + results = list(/datum/reagent/consumable/ethanol/abduction_fruit = 3) + required_reagents = list( + /datum/reagent/consumable/limejuice = 10, + /datum/reagent/consumable/berryjuice = 5, + /datum/reagent/consumable/watermelonjuice = 10, + ) + +/datum/chemical_reaction/drink/bug_zapper + results = list(/datum/reagent/consumable/ethanol/bug_zapper = 20) //Harder to make + required_reagents = list( + /datum/reagent/consumable/lemonjuice = 10, + /datum/reagent/teslium = 1, + /datum/reagent/copper = 10, + ) + +/datum/chemical_reaction/drink/mush_crush + results = list(/datum/reagent/consumable/ethanol/mush_crush = 10) + required_reagents = list( + /datum/reagent/iron = 5, + /datum/reagent/ash = 5, + /datum/reagent/toxin/coffeepowder = 10, + ) + +/datum/chemical_reaction/drink/hollow_bone + results = list(/datum/reagent/consumable/ethanol/hollow_bone = 10) + required_reagents = list( + /datum/reagent/toxin/bonehurtingjuice = 10, + /datum/reagent/consumable/soymilk = 15, + ) + +/datum/chemical_reaction/drink/jell_wyrm + results = list(/datum/reagent/consumable/ethanol/jell_wyrm = 2) + required_reagents = list( + /datum/reagent/toxin/slimejelly = 1, + /datum/reagent/toxin/carpotoxin = 1, + /datum/reagent/carbondioxide = 5, + ) + required_temp = 333 // (59.85'C) + +/datum/chemical_reaction/drink/laval_spit + results = list(/datum/reagent/consumable/ethanol/laval_spit = 20) //Limited use + required_reagents = list( + /datum/reagent/iron = 5, + /datum/reagent/consumable/ethanol/mauna_loa = 10, + /datum/reagent/sulfur = 5, + ) + required_temp = 900 // (626.85'C) + +/datum/chemical_reaction/drink/frisky_kitty + results = list(/datum/reagent/consumable/ethanol/frisky_kitty = 2) + required_reagents = list( + /datum/reagent/consumable/catnip_tea = 1, + /datum/reagent/consumable/milk = 1, + ) + required_temp = 296 //Just above room temp (22.85'C) + +/datum/chemical_reaction/drink/bloodshot_base + results = list(/datum/reagent/consumable/ethanol/bloodshot_base = 2) + required_reagents = list( + /datum/reagent/consumable/ethanol/bloody_mary = 1, + /datum/reagent/consumable/sugar = 1, + ) + reaction_tags = REACTION_TAG_DRINK | REACTION_TAG_EASY | REACTION_TAG_OTHER + +/datum/chemical_reaction/drink/bloodshot + results = list(/datum/reagent/consumable/ethanol/bloodshot = 5) + required_reagents = list( + /datum/reagent/blood = 3, + /datum/reagent/consumable/ethanol/bloodshot_base = 2, + ) + reaction_tags = REACTION_TAG_DRINK | REACTION_TAG_EASY | REACTION_TAG_OTHER +*/ + +// Non-Booze, see modular_skyrat\modules\customization\modules\reagents\chemistry\reagents\drink_reagents.dm + +/datum/chemical_reaction/drink/pinkmilk + results = list(/datum/reagent/consumable/pinkmilk = 2) + required_reagents = list( + /datum/reagent/consumable/berryjuice = 1, + /datum/reagent/consumable/milk = 1, + /datum/reagent/consumable/sugar = 1, + ) + +/datum/chemical_reaction/drink/pinktea + results = list(/datum/reagent/consumable/pinktea = 5) + required_reagents = list( + /datum/reagent/consumable/berryjuice = 1, + /datum/reagent/consumable/tea/arnold_palmer = 1, + /datum/reagent/consumable/sugar = 1, + ) + +/datum/chemical_reaction/drink/catnip_tea + results = list(/datum/reagent/consumable/catnip_tea = 10) + required_reagents = list( + /datum/reagent/consumable/tea = 5, + /datum/reagent/pax/catnip = 2, + ) + +/datum/chemical_reaction/drink/beerbatter + results = list(/datum/reagent/consumable/ethanol/beerbatter = 4) + required_reagents = list( + /datum/reagent/consumable/nutriment/fat/oil = 1, + /datum/reagent/consumable/ethanol/beer = 1, + /datum/reagent/consumable/flour = 1, + ) + mix_message = "Sizzling and cracking is heard as you beat the mixture into submission." + +/datum/chemical_reaction/drink/shakiri_spritz + results = list(/datum/reagent/consumable/ethanol/shakiri_spritz = 3) + required_reagents = list( + /datum/reagent/consumable/ethanol/shakiri = 1, + /datum/reagent/consumable/sodawater = 1, + /datum/reagent/consumable/orangejuice = 1, + ) + mix_message = "The liquids combine to create a pleasant orange mixture." + +/datum/chemical_reaction/drink/crimson_hurricane + results = list(/datum/reagent/consumable/ethanol/crimson_hurricane = 5) + required_reagents = list( + /datum/reagent/consumable/ethanol/shakiri = 1, + /datum/reagent/consumable/ethanol/rum = 2, + /datum/reagent/consumable/grenadine = 1, + /datum/reagent/consumable/limejuice = 1, + ) + mix_message = "The mixture develops into a rich red color." + +/datum/chemical_reaction/drink/shakiri_rogers + results = list(/datum/reagent/consumable/ethanol/shakiri_rogers = 10) + required_reagents = list( + /datum/reagent/consumable/ethanol/shakiri = 1, + /datum/reagent/consumable/space_cola = 5, + /datum/reagent/consumable/ice = 2, + ) + mix_message = "Bubbles of carbonation rise and pop at the surface of the dark mixture." diff --git a/modular_doppler/modular_food_and_drinks/icons/drinks.dmi b/modular_doppler/modular_food_and_drinks/icons/drinks.dmi new file mode 100644 index 0000000000000000000000000000000000000000..9ccaa586ac7eba21ef0c14347097ca79d0718ff7 GIT binary patch literal 30301 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 literal 0 HcmV?d00001 diff --git a/modular_doppler/vending_machines/code/vendor_containers.dm b/modular_doppler/vending_machines/code/vendor_containers.dm new file mode 100644 index 0000000000000..7feb74dfbcfd6 --- /dev/null +++ b/modular_doppler/vending_machines/code/vendor_containers.dm @@ -0,0 +1,89 @@ +/obj/item/storage/box/foodpack + name = "wrapped meal container" + desc = "A generic brown paper food package, you aren't quite sure where this comes from." + icon = 'modular_doppler/vending_machines/icons/imported_quick_foods.dmi' + icon_state = "foodpack_generic_big" + illustration = null + custom_price = PAYCHECK_CREW * 1.8 + ///What the main course of this package is + var/main_course = /obj/item/trash/empty_food_tray + ///What the side of this package should be + var/side_item = /obj/item/food/vendor_snacks + ///What kind of condiment pack should we give the package + var/condiment_pack = /obj/item/reagent_containers/condiment/pack/ketchup + +/obj/item/storage/box/foodpack/PopulateContents() + . = ..() + new main_course(src) + new side_item(src) + new condiment_pack(src) + +/obj/item/storage/box/foodpack/nt + name = "\improper NT-Combo Meal - Salisbury Steak" + desc = "A relatively bland package made of reflective metal foil, it has a blue sprite and the letters 'NT' printed on the top." + icon_state = "foodpack_nt_big" + main_course = /obj/item/food/vendor_tray_meal + side_item = /obj/effect/spawner/random/vendor_meal_sides/nt + condiment_pack = /obj/item/reagent_containers/condiment/pack/ketchup + +/obj/item/storage/box/foodpack/nt/burger + name = "\improper NT-Combo Meal - Cheeseburger" + main_course = /obj/item/food/vendor_tray_meal/burger + +/obj/item/storage/box/foodpack/nt/chicken_sammy + name = "\improper NT-Combo Meal - Spicy Chicken Sandwich" + main_course = /obj/item/food/vendor_tray_meal/chicken_sandwich + +/obj/item/storage/box/foodpack/yangyu + name = "\improper Atatakai shokuji - Homestyle Noodles" + desc = "A well decorated red and white plastic package, covered in nearly incomprehensible yangyu text." + icon_state = "foodpack_yangyu_big" + main_course = /obj/item/food/vendor_tray_meal/ramen + side_item = /obj/effect/spawner/random/vendor_meal_sides/yangyu + condiment_pack = /obj/item/reagent_containers/condiment/pack/hotsauce + +/obj/item/storage/box/foodpack/yangyu/sushi + name = "\improper Atatakai shokuji - Carp Sushi Rolls" + main_course = /obj/item/food/vendor_tray_meal/sushi + +/obj/item/storage/box/foodpack/yangyu/beef_rice + name = "\improper Atatakai shokuji - Beef and Rice" + main_course = /obj/item/food/vendor_tray_meal/beef_rice + +/obj/item/storage/box/foodpack/moth + name = "\improper Ration Type M - Pesto Pizza" + desc = "A cardboard-colored paper package with the symbol of the nomad fleet stamped upon it." + icon_state = "foodpack_moth_big" + main_course = /obj/item/food/vendor_tray_meal/pesto_pizza + side_item = /obj/effect/spawner/random/vendor_meal_sides/moth + condiment_pack = /obj/item/reagent_containers/condiment/pack/astrotame + +/obj/item/storage/box/foodpack/moth/baked_rice + name = "\improper Ration Type M - Baked Rice and Grilled Cheese" + main_course = /obj/item/food/vendor_tray_meal/baked_rice + +/obj/item/storage/box/foodpack/moth/fuel_jack + name = "\improper Ration Type M - Fueljack's Feast" + main_course = /obj/item/food/vendor_tray_meal/fueljack + +/obj/item/storage/box/foodpack/tizira + name = "\improper Tizira Imports Pack - Moonfish Nizaya" + desc = "A dull, metal foil package with the colors of the Tiziran flag striped across it, as well as a stamp of legitimate origin from the Tiziran exports office." + icon_state = "foodpack_tizira_big" + main_course = /obj/item/food/vendor_tray_meal/moonfish_nizaya + side_item = /obj/effect/spawner/random/vendor_meal_sides/tizira + condiment_pack = /obj/item/reagent_containers/condiment/pack/bbqsauce + custom_price = PAYCHECK_CREW * 2 //Tiziran imports are a bit more expensive + +/obj/item/storage/box/foodpack/tizira/examine_more(mob/user) + . = ..() + . += span_notice("Now that you look at it, the origin stamp appears to be a poor imitation of the real thing!") + return . + +/obj/item/storage/box/foodpack/tizira/roll + name = "\improper Tizira Imports Pack - Emperor Roll" + main_course = /obj/item/food/vendor_tray_meal/emperor_roll + +/obj/item/storage/box/foodpack/tizira/stir_fry + name = "\improper Tizira Imports Pack - Mushroom Stirfry" + main_course = /obj/item/food/vendor_tray_meal/mushroom_fry diff --git a/modular_doppler/vending_machines/code/vendor_food.dm b/modular_doppler/vending_machines/code/vendor_food.dm new file mode 100644 index 0000000000000..2e036b9ec31a2 --- /dev/null +++ b/modular_doppler/vending_machines/code/vendor_food.dm @@ -0,0 +1,318 @@ +// Packaged whole meals and sides for the 'meals' tab of vendors + +/* TRASH */ + +/obj/item/trash/empty_food_tray + name = "empty plastic food tray" + desc = "The condensation and what you can only hope are the leftovers of food make this a bit hard to reuse." + icon = 'modular_doppler/vending_machines/icons/imported_quick_foods.dmi' + icon_state = "foodtray_empty" + custom_materials = list( + /datum/material/plastic = HALF_SHEET_MATERIAL_AMOUNT, + ) + +/obj/item/trash/empty_side_pack + name = "empty side wrapper" + desc = "Unfortunately, this no longer holds any sides to distract you from the other 'food'." + icon = 'modular_doppler/vending_machines/icons/imported_quick_foods.dmi' + icon_state = "foodpack_generic_trash" + custom_materials = list( + /datum/material/plastic = HALF_SHEET_MATERIAL_AMOUNT, + ) + +/obj/item/trash/empty_side_pack/nt + icon_state = "foodpack_nt_trash" + +/obj/item/trash/empty_side_pack/yangyu + icon_state = "foodpack_yangyu_trash" + +/obj/item/trash/empty_side_pack/moth + icon_state = "foodpack_moth_trash" + +/obj/item/trash/empty_side_pack/tizira + icon_state = "foodpack_tizira_trash" + +/* MEALS */ + +/* +* NT Meals +*/ + +/obj/item/food/vendor_tray_meal + name = "\improper NT-Meal: Steak and Macaroni" + desc = "A 'salisbury steak' drowning in something similar to a gravy, with a macaroni and cheese substitute mix sitting right beside it." + icon = 'modular_doppler/vending_machines/icons/imported_quick_foods.dmi' + icon_state = "foodtray_sad_steak" + trash_type = /obj/item/trash/empty_food_tray + food_reagents = list(/datum/reagent/consumable/nutriment = 8) + tastes = list("meat?" = 2, "cheese?" = 2, "laziness" = 1) + foodtypes = MEAT | GRAIN | DAIRY + food_flags = FOOD_FINGER_FOOD + w_class = WEIGHT_CLASS_SMALL + ///Does this food have the steam effect on it when initialized + var/hot_and_steamy = TRUE + +/obj/item/food/vendor_tray_meal/Initialize(mapload) + . = ..() + if(hot_and_steamy) + overlays += mutable_appearance('icons/effects/steam.dmi', "steam_triple", ABOVE_OBJ_LAYER) + +/obj/item/food/vendor_tray_meal/examine_more(mob/user) + . = ..() + . += span_notice("You browse the back of the box...") + . += "\t[span_warning("Warning: Packaged in a factory where every allergen known is present.")]" + . += "\t[span_warning("Warning: Contents might be hot.")]" + . += "\t[span_info("Per 200g serving contains: 8g Sodium; 25g Fat, of which 22g are saturated; 2g Sugar.")]" + return . + +/obj/item/food/vendor_tray_meal/burger + name = "\improper NT-Meal: Cheeseburger" + desc = "A pretty sad looking burger with a kinda soggy bottom bun and highlighter yellow cheese." + icon_state = "foodtray_burg" + tastes = list("bread" = 2, "meat?" = 2, "cheese?" = 2, "laziness" = 1) + foodtypes = MEAT | GRAIN | DAIRY + +/obj/item/food/vendor_tray_meal/chicken_sandwich + name = "\improper NT-Meal: Spicy Chicken Sandwich" + desc = "A pretty sad looking chicken sandwich, the 'meat' patty is covered in so many manufactured spices that it has become an eerie red color." + icon_state = "foodtray_chickie_sandwich" + food_reagents = list(/datum/reagent/consumable/nutriment = 5, /datum/reagent/consumable/capsaicin = 10) + tastes = list("bread" = 2, "chicken?" = 2, "overwhelming spice" = 2, "laziness" = 1) + foodtypes = MEAT | GRAIN | DAIRY + +/* +* Yangyu Meals +*/ + +/obj/item/food/vendor_tray_meal/ramen + name = "\improper Meinkosu: Homestyle Noodles" + desc = "A brick of the finest factory made ramen, with a small amount of rehydrated vegetables and herbs floating around." + icon_state = "foodtray_noodle" + tastes = list("cheap noodles" = 2, "laziness" = 1) + foodtypes = GRAIN | VEGETABLES + +/obj/item/food/vendor_tray_meal/sushi + name = "\improper Meinkosu: Fresh Carp Rolls" + desc = "A pair of sushi rolls, the appearance of which would suggest that the label is lying to you." + icon_state = "foodtray_gas_station_sushi" + tastes = list("imitation space carp" = 2, "stale rice" = 2, "laziness" = 1) + foodtypes = GRAIN | SEAFOOD + +/obj/item/food/vendor_tray_meal/beef_rice + name = "\improper Meinkosu: Beef and Fried Rice" + desc = "A few slices of seemingly grilled beef, paired with a disproportionately large amount of rice." + icon_state = "foodtray_beef_n_rice" + tastes = list("cheap beef" = 1, "rice" = 3, "laziness" = 1) + foodtypes = GRAIN | MEAT + +/* +* Mothic Meals +*/ + +/obj/item/food/vendor_tray_meal/pesto_pizza + name = "\improper Main Course - Type M: Pesto Pizza" + desc = "A rectangular pizza with a suspiciously bright green pesto in place of the standard tomato sauce." + icon_state = "foodtray_pesto_pizza" + tastes = list("tomato?" = 2, "cheese?" = 2, "herbs" = 1, "laziness" = 1) + foodtypes = GRAIN | DAIRY | VEGETABLES + +/obj/item/food/vendor_tray_meal/baked_rice + name = "\improper Main Course - Type M: Baked Rice and Grilled Cheese" + desc = "Some sub-par looking fleet style rice, with a very grilled chunk of cheese." + icon_state = "foodtray_rice_n_grilled_cheese" + tastes = list("rice" = 2, "peppers" = 2, "charred cheese" = 2, "laziness" = 1) + foodtypes = GRAIN | DAIRY | VEGETABLES + +/obj/item/food/vendor_tray_meal/fueljack + name = "\improper Main Course - Type M: Fueljack's Tray" + desc = "A flat chunk of fueljack's lunch, seemingly missing most of the usual variety in ingredients." + icon_state = "foodtray_fuel_jacks_meal" + tastes = list("potato" = 2, "cabbage" = 2, "cheese?" = 2, "laziness" = 1) + foodtypes = DAIRY | VEGETABLES + +/* +* Tiziran Meals +*/ + +/obj/item/food/vendor_tray_meal/moonfish_nizaya + name = "\improper Tizira Imports: Moonfish and Nizaya" + desc = "An almost synthetic looking cut of moonfish, paired with an equal helping of nizaya pasta." + icon_state = "foodtray_moonfish_nizaya" + tastes = list("fish?" = 2, "cheap noodles" = 2, "laziness" = 1) + foodtypes = VEGETABLES | NUTS | SEAFOOD + +/obj/item/food/vendor_tray_meal/emperor_roll + name = "\improper Tizira Imports: Emperor Roll" + desc = "A pretty sad looking emperor roll, if you can even call it that; it seems caviar wasn't in the budget." + icon_state = "foodtray_emperor_roll" + tastes = list("bread" = 2, "cheese?" = 2, "liver?" = 2, "laziness" = 1) + foodtypes = VEGETABLES | NUTS | MEAT | GORE + +/obj/item/food/vendor_tray_meal/mushroom_fry + name = "\improper Tizira Imports: Mushroom Stirfry" + desc = "A mix of what was likely mushrooms too low quality to be used in making actual food, lightly fried and tossed in a plastic container together." + icon_state = "foodtray_shroom_fry" + tastes = list("mushroom" = 4, "becoming rich" = 1, "laziness" = 1) + foodtypes = VEGETABLES + +/* SIDES */ + +/obj/effect/spawner/random/vendor_meal_sides + name = "random side spawner" + desc = "I hope I get one that actually matches my meal." + icon_state = "loot" + +/* +* NT Sides +*/ + +/obj/effect/spawner/random/vendor_meal_sides/nt + name = "random nt side spawner" + +/obj/effect/spawner/random/vendor_meal_sides/nt/Initialize(mapload) + loot = list( + /obj/item/food/vendor_tray_meal/side, + /obj/item/food/vendor_tray_meal/side/crackers_and_jam, + /obj/item/food/vendor_tray_meal/side/crackers_and_cheese, + ) + . = ..() + +/obj/item/food/vendor_tray_meal/side + name = "\improper NT-Side: Flatbread and Peanut Butter" + desc = "A small stack of tough flatbread, and a small spread of peanut butter for each." + icon_state = "foodpack_nt" + trash_type = /obj/item/trash/empty_side_pack/nt + food_reagents = list(/datum/reagent/consumable/nutriment = 5) + tastes = list("tough bread" = 2, "peanut butter" = 2) + foodtypes = GRAIN + hot_and_steamy = FALSE + custom_price = PAYCHECK_LOWER * 2.5 + +/obj/item/food/vendor_tray_meal/side/crackers_and_jam + name = "\improper NT-Side: Flatbread and Berry Jelly" + desc = "A small stack of tough flatbread, and a small spread of nondescript berry jelly for each." + tastes = list("tough bread" = 2, "berries" = 2) + foodtypes = GRAIN | FRUIT + +/obj/item/food/vendor_tray_meal/side/crackers_and_cheese + name = "\improper NT-Side: Flatbread and Cheese Spread" + desc = "A small stack of tough flatbread, and a small spread of cheese for each." + tastes = list("tough bread" = 2, "cheese" = 2) + foodtypes = GRAIN | DAIRY + +/* +* Yangyu Sides +*/ + +/obj/effect/spawner/random/vendor_meal_sides/yangyu + name = "random yangyu side spawner" + +/obj/effect/spawner/random/vendor_meal_sides/yangyu/Initialize(mapload) + loot = list( + /obj/item/food/vendor_tray_meal/side/miso, + /obj/item/food/vendor_tray_meal/side/rice, + /obj/item/food/vendor_tray_meal/side/pickled_vegetables, + ) + . = ..() + +/obj/item/food/vendor_tray_meal/side/miso + name = "\improper Fukusai: Miso Soup" + desc = "This is quite literally just a plastic bag full of miso soup, opening it on any side other than the one indicated may result in spilled soup." + icon_state = "foodpack_yangyu" + trash_type = /obj/item/trash/empty_side_pack/yangyu + tastes = list("miso" = 2) + foodtypes = VEGETABLES + +/obj/item/food/vendor_tray_meal/side/rice + name = "\improper Fukusai: White Rice" + desc = "A bag stuffed full of white rice, in case your meal didn't come with enough to sate your needs." + icon_state = "foodpack_yangyu" + trash_type = /obj/item/trash/empty_side_pack/yangyu + tastes = list("old rice" = 2) + foodtypes = GRAIN + +/obj/item/food/vendor_tray_meal/side/pickled_vegetables + name = "\improper Fukusai: Pickled Vegetables" + desc = "Contains a small assortment of vegetables pickled in a vinegar-like solution." + icon_state = "foodpack_yangyu" + trash_type = /obj/item/trash/empty_side_pack/yangyu + tastes = list("vinegar" = 4) + foodtypes = VEGETABLES + +/* +* Mothic Sides +*/ + +/obj/effect/spawner/random/vendor_meal_sides/moth + name = "random mothic side spawner" + +/obj/effect/spawner/random/vendor_meal_sides/moth/Initialize(mapload) + loot = list( + /obj/item/food/vendor_tray_meal/side/moffin, + /obj/item/food/vendor_tray_meal/side/cornbread, + /obj/item/food/vendor_tray_meal/side/roasted_seeds, + ) + . = ..() + +/obj/item/food/vendor_tray_meal/side/moffin + name = "\improper Side Course - Type M: Moffin" + desc = "The result of taking a perfectly fine moffin, and flattening it into a more wafer-like form." + icon_state = "foodpack_moth" + trash_type = /obj/item/trash/empty_side_pack/moth + tastes = list("fabric?" = 2, "sugar" = 2) + foodtypes = CLOTH | GRAIN | SUGAR + +/obj/item/food/vendor_tray_meal/side/cornbread + name = "\improper Side Course - Type M: Cornbread" + desc = "A flattened cut of sweetened cornbread, goes well with butter." + icon_state = "foodpack_moth" + trash_type = /obj/item/trash/empty_side_pack/moth + tastes = list("cornbread" = 2, "sweetness" = 2) + foodtypes = GRAIN | SUGAR + +/obj/item/food/vendor_tray_meal/side/roasted_seeds + name = "\improper Side Course - Type M: Roasted Seeds" + desc = "A packet full of various oven roasted seeds." + icon_state = "foodpack_moth" + trash_type = /obj/item/trash/empty_side_pack/moth + tastes = list("seeds" = 2, "char" = 2) + foodtypes = NUTS + +/* +* Tiziran Sides +*/ + +/obj/effect/spawner/random/vendor_meal_sides/tizira + name = "random tiziran side spawner" + +/obj/effect/spawner/random/vendor_meal_sides/tizira/Initialize(mapload) + loot = list( + /obj/item/food/vendor_tray_meal/side/root_crackers, + /obj/item/food/vendor_tray_meal/side/korta_brittle, + /obj/item/food/vendor_tray_meal/side/crispy_headcheese, + ) + . = ..() + +/obj/item/food/vendor_tray_meal/side/root_crackers + name = "\improper Tizira Imports: Rootbread Crackers and Pate" + desc = "A small stack of rootbread crackers, with a small spread of meat pate for each." + icon_state = "foodpack_tizira" + trash_type = /obj/item/trash/empty_side_pack/tizira + tastes = list("tough rootbread" = 2, "pate" = 2) + foodtypes = VEGETABLES | NUTS | MEAT + +/obj/item/food/vendor_tray_meal/side/korta_brittle + name = "\improper Tizira Imports: Korta Brittle" + desc = "A perfectly rectangular portion of unsweetened korta brittle." + icon_state = "foodpack_tizira" + trash_type = /obj/item/trash/empty_side_pack/tizira + tastes = list("peppery heat" = 2) + foodtypes = NUTS + +/obj/item/food/vendor_tray_meal/side/crispy_headcheese + name = "\improper Tizira Imports: Crisped Headcheese" + desc = "A processed looking block of breaded headcheese." + icon_state = "foodpack_tizira" + trash_type = /obj/item/trash/empty_side_pack/tizira + tastes = list("cheese" = 1, "oil" = 1) + foodtypes = MEAT | VEGETABLES | NUTS | GORE diff --git a/modular_doppler/vending_machines/code/vendor_snacks.dm b/modular_doppler/vending_machines/code/vendor_snacks.dm new file mode 100644 index 0000000000000..36778ad36f5cc --- /dev/null +++ b/modular_doppler/vending_machines/code/vendor_snacks.dm @@ -0,0 +1,302 @@ +// Snacks and drinks for the 'snacks' tab of vendors + +/obj/item/food/vendor_snacks + name = "\improper God's Strongest Snacks" + desc = "You best hope you aren't a sinner. (You should never see this item please report it)" + icon = 'modular_doppler/vending_machines/icons/imported_quick_foods.dmi' + icon_state = "foodpack_generic" + trash_type = /obj/item/trash/vendor_trash + bite_consumption = 10 + food_reagents = list(/datum/reagent/consumable/nutriment = INFINITY) + junkiness = 10 + custom_price = PAYCHECK_LOWER * INFINITY + tastes = list("the unmatched power of the sun" = 10) + foodtypes = JUNKFOOD | CLOTH | GORE | NUTS | FRIED | FRUIT //You don't want to know what's in the broken debug snacks + w_class = WEIGHT_CLASS_SMALL + +/obj/item/trash/vendor_trash + name = "\improper God's Weakest Snacks" + desc = "The leftovers of what was likely a great snack in a past time." + icon = 'modular_doppler/vending_machines/icons/imported_quick_foods.dmi' + icon_state = "foodpack_generic_trash" + custom_materials = list( + /datum/material/plastic = HALF_SHEET_MATERIAL_AMOUNT, + ) + +/* +* Yangyu Snacks +*/ + +/obj/item/reagent_containers/cup/glass/dry_ramen/prepared + name = "cup ramen" + desc = "This one even comes with water, amazing!" + list_reagents = list(/datum/reagent/consumable/hot_ramen = 15, /datum/reagent/consumable/salt = 3) + +/obj/item/reagent_containers/cup/glass/dry_ramen/prepared/hell + name = "spicy cup ramen" + desc = "This one comes with water, AND a security checkpoint's worth of capsaicin!" + list_reagents = list(/datum/reagent/consumable/hell_ramen = 15, /datum/reagent/consumable/salt = 3) + +/obj/item/food/vendor_snacks/rice_crackers + name = "rice crackers" + desc = "Despite most of the package being clear, you will never truly know what flavor these are until you eat them." + icon_state = "rice_cracka" + trash_type = /obj/item/trash/vendor_trash/rice_crackers + food_reagents = list(/datum/reagent/consumable/nutriment = 2, /datum/reagent/consumable/rice = 2) + tastes = list("incomprehensible flavoring" = 1, "rice cracker" = 2) + foodtypes = JUNKFOOD | GRAIN + custom_price = PAYCHECK_LOWER * 0.8 + +/obj/item/food/vendor_snacks/rice_crackers/make_leave_trash() + AddElement(/datum/element/food_trash, trash_type, FOOD_TRASH_POPABLE) + +/obj/item/trash/vendor_trash/rice_crackers + name = "empty rice crackers bag" + desc = "You never did find out what flavor that was supposed to be, did you?" + icon_state = "rice_cracka_trash" + +/obj/item/food/vendor_snacks/mochi_ice_cream + name = "mochi ice cream balls - vanilla" + desc = "A six pack of mochi ice cream, which is to say vanilla icecream surrounded by mochi. Comes with small plastic skewer for consumption." + icon_state = "mochi_ice" + trash_type = /obj/item/trash/vendor_trash/mochi_ice_cream + food_reagents = list(/datum/reagent/consumable/nutriment = 3, /datum/reagent/consumable/ice = 3) + tastes = list("rice cake" = 2, "vanilla" = 2) + foodtypes = JUNKFOOD | DAIRY | GRAIN + custom_price = PAYCHECK_LOWER + +/obj/item/food/vendor_snacks/mochi_ice_cream/matcha + name = "mochi ice cream balls - matcha" + desc = "A six pack of mochi ice cream - or, more specifically, matcha icecream surrounded by mochi. Comes with small plastic skewer for consumption." + icon_state = "mochi_ice_green" + food_reagents = list(/datum/reagent/consumable/nutriment = 3, /datum/reagent/consumable/ice = 1, /datum/reagent/consumable/tea = 2) + tastes = list("rice cake" = 1, "bitter matcha" = 2) + custom_price = PAYCHECK_LOWER * 1.2 + +/obj/item/food/vendor_snacks/mochi_ice_cream/matcha/examine_more(mob/user) + . = ..() + . += span_notice("A small label on the container specifies that this icecream is made using only culinary grade matcha grown outside of the Sol system.") + return . + +/obj/item/trash/vendor_trash/mochi_ice_cream + name = "empty mochi ice cream tray" + desc = "Somehow, that tiny plastic skewer it came with has gone missing." + icon_state = "mochi_ice_trash" + +/obj/item/reagent_containers/cup/glass/waterbottle/tea + name = "bottle of tea" + desc = "A bottle of tea brought to you in a convenient plastic bottle." + icon = 'modular_doppler/modular_food_and_drinks/icons/drinks.dmi' + icon_state = "tea_bottle" + list_reagents = list(/datum/reagent/consumable/tea = 40) + cap_icon_state = "bottle_cap_tea" + flip_chance = 5 //I fucking dare you + custom_price = PAYCHECK_LOWER * 1.2 + fill_icon_state = null + +/obj/item/reagent_containers/cup/glass/waterbottle/tea/astra + name = "bottle of tea astra" + desc = "A bottle of tea astra, known for the rather unusual tastes the leaf is known to give when brewed." + icon_state = "tea_bottle_blue" + list_reagents = list( + /datum/reagent/consumable/tea = 25, + /datum/reagent/medicine/salglu_solution = 10, // I know this looks strange but this is what tea astra grinds into, tea in the year 25whatever baby + /datum/reagent/consumable/nutriment/vitamin = 5, + ) + custom_price = PAYCHECK_LOWER * 2 + +/obj/item/reagent_containers/cup/glass/waterbottle/tea/strawberry + name = "bottle of strawberry tea" + desc = "A bottle of strawberry flavored tea; does not contain any actual strawberries." + icon_state = "tea_bottle_pink" + list_reagents = list(/datum/reagent/consumable/pinktea = 40) + custom_price = PAYCHECK_LOWER * 2 + +/obj/item/reagent_containers/cup/glass/waterbottle/tea/nip + name = "bottle of catnip tea" + desc = "A bottle of catnip tea, required to be at or under a 50% concentration by the SFDA for safety purposes." + icon_state = "tea_bottle_pink" + list_reagents = list( + /datum/reagent/consumable/catnip_tea = 20, + /datum/reagent/consumable/pinkmilk = 20, // I can't believe they would cut my catnip + ) + custom_price = PAYCHECK_LOWER * 2.5 + +/* +* Mothic Snacks +*/ + +/obj/item/food/vendor_snacks/mothmallow + name = "mothmallow" + desc = "A vacuum sealed bag containing a pretty crushed looking mothmallow, someone save him!" + icon_state = "mothmallow" + trash_type = /obj/item/trash/vendor_trash/mothmallow + food_reagents = list(/datum/reagent/consumable/nutriment = 2, /datum/reagent/consumable/sugar = 4) + tastes = list("vanilla" = 1, "cotton" = 1, "chocolate" = 1) + foodtypes = VEGETABLES | SUGAR + custom_price = PAYCHECK_LOWER + +/obj/item/food/vendor_snacks/mothmallow/make_leave_trash() + AddElement(/datum/element/food_trash, trash_type, FOOD_TRASH_POPABLE) + +/obj/item/trash/vendor_trash/mothmallow + name = "empty mothmallow bag" + desc = "Finally he is free." + icon_state = "mothmallow_trash" + +/obj/item/food/vendor_snacks/moth_bag + name = "engine fodder" + desc = "A vacuum sealed bag containing a small portion of colorful engine fodder." + icon_state = "fodder" + trash_type = /obj/item/trash/vendor_trash/moth_bag + food_reagents = list(/datum/reagent/consumable/sugar = 3, /datum/reagent/consumable/nutriment = 2, /datum/reagent/consumable/salt = 2) + tastes = list("seeds" = 1, "nuts" = 1, "chocolate" = 1, "salt" = 1, "popcorn" = 1, "potato" = 1) + foodtypes = GRAIN | NUTS | VEGETABLES | SUGAR + custom_price = PAYCHECK_LOWER * 1.2 + +/obj/item/food/vendor_snacks/moth_bag/fuel_jack + name = "fueljack's snack" + desc = "A vacuum sealed bag containing a smaller than usual brick of fueljack's lunch, ultimately downgrading it to a fueljack's snack." + icon_state = "fuel_jack_snack" + food_reagents = list(/datum/reagent/consumable/nutriment = 3, /datum/reagent/consumable/nutriment/protein = 1) + tastes = list("cabbage" = 1, "potato" = 1, "onion" = 1, "chili" = 1, "cheese" = 1) + foodtypes = DAIRY | VEGETABLES + custom_price = PAYCHECK_LOWER * 1.2 + +/obj/item/food/vendor_snacks/moth_bag/cheesecake + name = "chocolate cheesecake cube" + desc = "A vacuum sealed bag containing a small cube of a mothic style cheesecake, this one is covered in chocolate." + icon_state = "choco_cheese_cake" + food_reagents = list(/datum/reagent/consumable/nutriment/protein = 2, /datum/reagent/consumable/sugar = 4) + tastes = list("cheesecake" = 1, "chocolate" = 1) + foodtypes = SUGAR | FRIED | DAIRY | GRAIN + custom_price = PAYCHECK_LOWER * 1.4 + +/obj/item/food/vendor_snacks/moth_bag/cheesecake/honey + name = "honey cheesecake cube" + desc = "A vacuum sealed bag containing a small cube of a mothic style cheesecake, this one is covered in honey." + icon_state = "honey_cheese_cake" + tastes = list("cheesecake" = 1, "honey" = 1) + foodtypes = SUGAR | FRIED | DAIRY | GRAIN + +/obj/item/trash/vendor_trash/moth_bag + name = "empty mothic snack bag" + desc = "The clear plastic reveals that this no longer holds tasty treats for your winged friends." + icon_state = "moth_bag_trash" + +/obj/item/reagent_containers/cup/soda_cans/nova/lemonade + name = "\improper Gyárhajó 1023: Lemonade" + desc = "A can of lemonade, for those who are into that kind of thing, or just have no choice." + icon_state = "lemonade" + list_reagents = list(/datum/reagent/consumable/lemonade = 30) + drink_type = FRUIT + +/obj/item/reagent_containers/cup/soda_cans/nova/lemonade/examine_more(mob/user) + . = ..() + . += span_notice("Markings on the can indicate this one was made on factory ship 1023 of the Grand Nomad Fleet.") + return . + +/obj/item/reagent_containers/cup/soda_cans/nova/navy_rum + name = "\improper Gyárhajó 1506: Navy Rum" + desc = "A can of navy rum brewed up and imported from a detachment of the nomad fleet, or so the can says." + icon_state = "navy_rum" + list_reagents = list(/datum/reagent/consumable/ethanol/navy_rum = 30) + drink_type = ALCOHOL + +/obj/item/reagent_containers/cup/soda_cans/nova/navy_rum/examine_more(mob/user) + . = ..() + . += span_notice("Markings on the can indicate this one was made on factory ship 1506 of the Grand Nomad Fleet.") + return . + +/obj/item/reagent_containers/cup/soda_cans/nova/soda_water_moth + name = "\improper Gyárhajó 1023: Soda Water" + desc = "A can of soda water. Why not make a rum and soda? Now that you think of it, maybe not." + icon_state = "soda_water" + list_reagents = list(/datum/reagent/consumable/sodawater = 30) + drink_type = SUGAR + +/obj/item/reagent_containers/cup/soda_cans/nova/soda_water_moth/examine_more(mob/user) + . = ..() + . += span_notice("Markings on the can indicate this one was made on factory ship 1023 of the Grand Nomad Fleet.") + return . + +/obj/item/reagent_containers/cup/soda_cans/nova/ginger_beer + name = "\improper Gyárhajó 1023: Ginger Beer" + desc = "A can of ginger beer, don't let the beer part mislead you, this is entirely non-alcoholic." + icon_state = "gingie_beer" + list_reagents = list(/datum/reagent/consumable/sol_dry = 30) + drink_type = SUGAR + +/obj/item/reagent_containers/cup/soda_cans/nova/ginger_beer/examine_more(mob/user) + . = ..() + . += span_notice("Markings on the can indicate this one was made on factory ship 1023 of the Grand Nomad Fleet.") + return . + +/* +* Tiziran Snacks +*/ + +/obj/item/food/vendor_snacks/lizard_bag + name = "candied mushroom" + desc = "An odd treat of the lizard empire, a mushroom dipped in caramel; unfortunately, it seems to have been bagged before the caramel fully hardened." + icon_state = "candied_shroom" + trash_type = /obj/item/trash/vendor_trash/lizard_bag + food_reagents = list(/datum/reagent/consumable/nutriment = 3, /datum/reagent/consumable/caramel = 2) + tastes = list("savouriness" = 1, "sweetness" = 1) + foodtypes = SUGAR | VEGETABLES + custom_price = PAYCHECK_LOWER * 1.4 //Tiziran imports are a bit more expensive overall + +/obj/item/food/vendor_snacks/lizard_bag/make_leave_trash() + AddElement(/datum/element/food_trash, trash_type, FOOD_TRASH_POPABLE) + +/obj/item/food/vendor_snacks/lizard_bag/moon_jerky + name = "moonfish jerky" + desc = "A fish jerky, made from what you can only hope is moonfish. It also seems to taste subtly of barbecue" + icon_state = "moon_jerky" + food_reagents = list(/datum/reagent/consumable/nutriment/protein = 2, /datum/reagent/consumable/bbqsauce = 2) + tastes = list("fish" = 1, "smokey sauce" = 1) + foodtypes = MEAT + custom_price = PAYCHECK_LOWER * 1.6 + +/obj/item/trash/vendor_trash/lizard_bag + name = "empty tiziran snack bag" + desc = "All that money importing tiziran snacks just to end at this?" + icon_state = "tizira_bag_trash" + +/obj/item/food/vendor_snacks/lizard_box + name = "tiziran dumplings" + desc = "A three pack of tiziran style dumplings, not actually stuffed with anything." + icon_state = "dumpling" + trash_type = /obj/item/trash/vendor_trash/lizard_box + food_reagents = list(/datum/reagent/consumable/nutriment = 3) + tastes = list("potato" = 1, "earthy heat" = 1) + foodtypes = VEGETABLES | NUTS + custom_price = PAYCHECK_LOWER * 1.6 + +/obj/item/food/vendor_snacks/lizard_box/sweet_roll + name = "honey roll" + desc = "Definitely don't let the guards find out that someone stole your last one." + icon_state = "sweet_roll" + food_reagents = list(/datum/reagent/consumable/nutriment = 2, /datum/reagent/consumable/honey = 2) + tastes = list("bread" = 1, "honey" = 1, "fruit" = 1) + foodtypes = VEGETABLES | NUTS | FRUIT + custom_price = PAYCHECK_LOWER *1.8 + +/obj/item/trash/vendor_trash/lizard_box + name = "empty tiziran snack box" + desc = "Tizira, contributing to the space plastic crisis since 2530." + icon_state = "tizira_box_trash" + +/obj/item/reagent_containers/cup/glass/waterbottle/tea/mushroom + name = "bottle of mushroom tea" + desc = "A bottle of somewhat bitter mushroom tea, a favorite of the Tiziran empire." + icon_state = "tea_bottle_grey" + list_reagents = list(/datum/reagent/consumable/mushroom_tea = 40) + custom_price = PAYCHECK_LOWER * 2 + +/obj/item/reagent_containers/cup/soda_cans/nova/kortara + name = "kortara" + desc = "A can of kortara, alcohol brewed from korta seeds, which gives it a unique peppery spice flavor." + icon_state = "kortara" + list_reagents = list(/datum/reagent/consumable/ethanol/kortara = 30) + drink_type = ALCOHOL diff --git a/modular_doppler/vending_machines/code/vendors.dm b/modular_doppler/vending_machines/code/vendors.dm new file mode 100644 index 0000000000000..de0a4fe451256 --- /dev/null +++ b/modular_doppler/vending_machines/code/vendors.dm @@ -0,0 +1,229 @@ +/obj/effect/spawner/random/vending/snackvend + loot = list( + /obj/machinery/vending/imported/nt, + /obj/machinery/vending/imported/yangyu, + /obj/machinery/vending/imported/mothic, + /obj/machinery/vending/imported/tiziran, +// /obj/machinery/vending/deforest_medvend, //commented out until i'm ready to port them + ) + +/obj/effect/spawner/random/vending/colavend //These can serve both snacks AND drinks so its kinda both of them? + loot = list( + /obj/machinery/vending/imported/nt, + /obj/machinery/vending/imported/yangyu, + /obj/machinery/vending/imported/mothic, + /obj/machinery/vending/imported/tiziran, +// /obj/machinery/vending/deforest_medvend, //commented out until i'm ready to port them + ) + +/datum/supply_pack/vending/imported/fill(obj/structure/closet/crate/target_crate) + . = ..() + for(var/obj/vendor_refill as anything in subtypesof(/obj/item/vending_refill/snack/imported)) + new vendor_refill(target_crate) + +/obj/machinery/vending/imported + icon = 'modular_doppler/vending_machines/icons/imported_vendors.dmi' + icon_state = null + panel_type = "panel15" + default_price = PAYCHECK_CREW * 0.5 + extra_price = PAYCHECK_COMMAND + payment_department = NO_FREEBIES + +/obj/machinery/vending/imported/nt + name = "NT Sustenance Supplier" + desc = "A vending machine serving up only the finest of human college student food." + icon_state = "nt_food" + light_mask = "nt_food-light-mask" + light_color = LIGHT_COLOR_LIGHT_CYAN + product_slogans = "Caution, contents may be selling hot!;Look at these low prices!;Hungry? Me too- Wait, no, you didn't hear that!" + product_categories = list( + list( + "name" = "Snacks", + "icon" = "cookie", + "products" = list( + /obj/item/food/peanuts/random = 6, + /obj/item/food/cnds/random = 6, + /obj/item/food/pistachios = 6, + /obj/item/food/cornchips/random = 6, + /obj/item/food/sosjerky = 6, + /obj/item/reagent_containers/cup/soda_cans/cola = 6, + /obj/item/reagent_containers/cup/soda_cans/lemon_lime = 6, + /obj/item/reagent_containers/cup/soda_cans/starkist = 6, + /obj/item/reagent_containers/cup/soda_cans/pwr_game = 6, + ), + ), + list( + "name" = "Meals", + "icon" = "pizza-slice", + "products" = list( + /obj/item/storage/box/foodpack/nt = 6, + /obj/item/storage/box/foodpack/nt/burger = 6, + /obj/item/storage/box/foodpack/nt/chicken_sammy = 6, + /obj/item/food/vendor_tray_meal/side = 6, + /obj/item/food/vendor_tray_meal/side/crackers_and_jam = 6, + /obj/item/food/vendor_tray_meal/side/crackers_and_cheese = 6, + ), + ), + ) + + refill_canister = /obj/item/vending_refill/snack/imported/nt + +/obj/item/vending_refill/snack/imported/nt + machine_name = "NT Sustenance Supplier" + +/obj/machinery/vending/imported/yangyu + name = "Fudobenda" + desc = "A vendor selling traditional Sol eastern foods of dubious quality." + icon_state = "yangyu_food" + light_mask = "yangyu_food-light-mask" + light_color = LIGHT_COLOR_FLARE + product_slogans = "Fresh farmed space carp from local space!;Imitation lobstrocity sushi choices availible!;Made with traditional recipes and care!" + product_categories = list( + list( + "name" = "Snacks", + "icon" = "cookie", + "products" = list( + /obj/item/reagent_containers/cup/glass/dry_ramen/prepared = 6, + /obj/item/reagent_containers/cup/glass/dry_ramen/prepared/hell = 6, + /obj/item/food/vendor_snacks/rice_crackers = 6, + /obj/item/food/vendor_snacks/mochi_ice_cream = 6, + /obj/item/food/vendor_snacks/mochi_ice_cream/matcha = 6, + /obj/item/reagent_containers/cup/glass/waterbottle/tea = 6, + /obj/item/reagent_containers/cup/glass/waterbottle/tea/astra = 6, + /obj/item/reagent_containers/cup/glass/waterbottle/tea/strawberry = 6, + /obj/item/reagent_containers/cup/glass/waterbottle/tea/nip = 6, + ), + ), + list( + "name" = "Meals", + "icon" = "pizza-slice", + "products" = list( + /obj/item/storage/box/foodpack/yangyu = 6, + /obj/item/storage/box/foodpack/yangyu/sushi = 6, + /obj/item/storage/box/foodpack/yangyu/beef_rice = 6, + /obj/item/food/vendor_tray_meal/side/miso = 6, + /obj/item/food/vendor_tray_meal/side/rice = 6, + /obj/item/food/vendor_tray_meal/side/pickled_vegetables = 6, + ), + ), + ) + + refill_canister = /obj/item/vending_refill/snack/imported/yangyu + initial_language_holder = /datum/language_holder/yangyu_vendor + +/datum/language_holder/yangyu_vendor + understood_languages = list( + /datum/language/yangyu = list(LANGUAGE_ATOM), + ) + spoken_languages = list( + /datum/language/yangyu = list(LANGUAGE_ATOM), + ) + +/obj/machinery/vending/imported/yangyu/examine_more(mob/user) + . = ..() + . += span_notice("Someone appears to have written \"Don't trust the sushi!\" in marker on the side of the vendor.") + return . + +/obj/item/vending_refill/snack/imported/yangyu + machine_name = "Fudobenda" + +/obj/machinery/vending/imported/mothic + name = "Nomad Fleet Ration Chit Exchange" + desc = "One of the Nomad Fleet's own ration vendors; in spite of the name engraved into it, it's been fitted to accept credits." + icon_state = "moth_food" + light_mask = "moth_food-light-mask" + light_color = LIGHT_COLOR_HALOGEN + product_slogans = "Support the fleet, conserve rations today!;Some options in reduced portion and cost!;Do your part to keep the fleet flying!" + product_categories = list( + list( + "name" = "Snacks", + "icon" = "cookie", + "products" = list( + /obj/item/food/vendor_snacks/mothmallow = 6, + /obj/item/food/vendor_snacks/moth_bag = 6, + /obj/item/food/vendor_snacks/moth_bag/fuel_jack = 6, + /obj/item/food/vendor_snacks/moth_bag/cheesecake = 6, + /obj/item/food/vendor_snacks/moth_bag/cheesecake/honey = 6, + /obj/item/reagent_containers/cup/soda_cans/nova/lemonade = 6, + /obj/item/reagent_containers/cup/soda_cans/nova/navy_rum = 6, + /obj/item/reagent_containers/cup/soda_cans/nova/soda_water_moth = 6, + /obj/item/reagent_containers/cup/soda_cans/nova/ginger_beer = 6, + ), + ), + list( + "name" = "Meals", + "icon" = "pizza-slice", + "products" = list( + /obj/item/storage/box/foodpack/moth = 6, + /obj/item/storage/box/foodpack/moth/baked_rice = 6, + /obj/item/storage/box/foodpack/moth/fuel_jack = 6, + /obj/item/food/vendor_tray_meal/side/moffin = 6, + /obj/item/food/vendor_tray_meal/side/cornbread = 6, + /obj/item/food/vendor_tray_meal/side/roasted_seeds = 6, + ), + ), + ) + + refill_canister = /obj/item/vending_refill/snack/imported/mothic + initial_language_holder = /datum/language_holder/moffic_vendor + +/datum/language_holder/moffic_vendor + understood_languages = list( + /datum/language/moffic = list(LANGUAGE_ATOM), + ) + spoken_languages = list( + /datum/language/moffic = list(LANGUAGE_ATOM), + ) + +/obj/item/vending_refill/snack/imported/mothic + machine_name = "Nomad Fleet Ration Chit Exchange" + +/obj/machinery/vending/imported/tiziran + name = "Tiziran Imported Delicacies" + desc = "A vendor serving a fine collection of what is very likely knock-offs of popular Tiziran brands." + icon_state = "tizira_food" + light_mask = "tizira_food-light-mask" + light_color = LIGHT_COLOR_FIRE + product_slogans = "Real imports from the capital itself, we promise!;Rare selections of salt water catch!;Moonfish glaze included with all meat options!" + product_categories = list( + list( + "name" = "Snacks", + "icon" = "cookie", + "products" = list( + /obj/item/food/chips/shrimp = 6, + /obj/item/food/vendor_snacks/lizard_bag = 6, + /obj/item/food/vendor_snacks/lizard_bag/moon_jerky = 6, + /obj/item/food/vendor_snacks/lizard_box = 6, + /obj/item/food/vendor_snacks/lizard_box/sweet_roll = 6, + /obj/item/reagent_containers/cup/glass/bottle/mushi_kombucha = 6, + /obj/item/reagent_containers/cup/glass/waterbottle/tea/mushroom = 6, + /obj/item/reagent_containers/cup/soda_cans/nova/kortara = 6, + ), + ), + list( + "name" = "Meals", + "icon" = "pizza-slice", + "products" = list( + /obj/item/storage/box/foodpack/tizira = 6, + /obj/item/storage/box/foodpack/tizira/roll = 6, + /obj/item/storage/box/foodpack/tizira/stir_fry = 6, + /obj/item/food/vendor_tray_meal/side/root_crackers = 6, + /obj/item/food/vendor_tray_meal/side/korta_brittle = 6, + /obj/item/food/vendor_tray_meal/side/crispy_headcheese = 6, + ), + ), + ) + + refill_canister = /obj/item/vending_refill/snack/imported/tiziran + initial_language_holder = /datum/language_holder/draconic_vendor + +/datum/language_holder/draconic_vendor + understood_languages = list( + /datum/language/draconic = list(LANGUAGE_ATOM), + ) + spoken_languages = list( + /datum/language/draconic = list(LANGUAGE_ATOM), + ) + +/obj/item/vending_refill/snack/imported/tiziran + machine_name = "Tiziran Imported Delicacies" diff --git a/modular_doppler/vending_machines/icons/imported_quick_foods.dmi b/modular_doppler/vending_machines/icons/imported_quick_foods.dmi new file mode 100644 index 0000000000000000000000000000000000000000..4249a5f4f0a482878be19e1225dd95a3314b6a3e GIT binary patch literal 10720 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 xS)%M7x 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 W!qU2Pv`79ma4IXP%a_ZV1^*98e`VnS literal 0 HcmV?d00001 diff --git a/modular_doppler/vending_machines/icons/imported_vendors.dmi b/modular_doppler/vending_machines/icons/imported_vendors.dmi new file mode 100644 index 0000000000000000000000000000000000000000..d26e14e5a38ed97f46a9c43c8ef3b9b28497bb85 GIT binary patch literal 9002 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 Date: Mon, 26 Aug 2024 14:59:39 -0700 Subject: [PATCH 02/28] augh. oraugh. --- .../modular_food_and_drinks/icons/drinks.dmi | Bin 30301 -> 0 bytes .../chemistry_reagents | 101 ++++++++++++++++++ .../food_and_drinks}/alcohol reagents.dm | 97 ++++++++--------- .../food_and_drinks}/drink_reagents.dm | 8 +- .../food_and_drinks/drinks.dm | 87 +++++++++++++++ .../food_and_drinks}/drinks_recipes.dm | 12 +-- .../icons/drinks.dmi | Bin 0 -> 31307 bytes .../vending_machines/code/vendor_snacks.dm | 28 ++--- .../vending_machines/code/vendors.dm | 16 +-- tgstation.dme | 8 +- 10 files changed, 274 insertions(+), 83 deletions(-) delete mode 100644 modular_doppler/modular_food_and_drinks/icons/drinks.dmi create mode 100644 modular_doppler/modular_food_drinks_and_chems/chemistry_reagents rename modular_doppler/{modular_food_and_drinks => modular_food_drinks_and_chems/food_and_drinks}/alcohol reagents.dm (90%) rename modular_doppler/{modular_food_and_drinks => modular_food_drinks_and_chems/food_and_drinks}/drink_reagents.dm (92%) create mode 100644 modular_doppler/modular_food_drinks_and_chems/food_and_drinks/drinks.dm rename modular_doppler/{modular_food_and_drinks => modular_food_drinks_and_chems/food_and_drinks}/drinks_recipes.dm (98%) create mode 100644 modular_doppler/modular_food_drinks_and_chems/icons/drinks.dmi diff --git a/modular_doppler/modular_food_and_drinks/icons/drinks.dmi b/modular_doppler/modular_food_and_drinks/icons/drinks.dmi deleted file mode 100644 index 9ccaa586ac7eba21ef0c14347097ca79d0718ff7..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 30301 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 diff --git a/modular_doppler/modular_food_drinks_and_chems/chemistry_reagents b/modular_doppler/modular_food_drinks_and_chems/chemistry_reagents new file mode 100644 index 0000000000000..99b6fc2339b82 --- /dev/null +++ b/modular_doppler/modular_food_drinks_and_chems/chemistry_reagents @@ -0,0 +1,101 @@ +/* +/datum/reagent/fuel + process_flags = REAGENT_ORGANIC | REAGENT_SYNTHETIC + +/datum/reagent/fuel/oil + process_flags = REAGENT_ORGANIC | REAGENT_SYNTHETIC + +/datum/reagent/stable_plasma + process_flags = REAGENT_ORGANIC | REAGENT_SYNTHETIC + +/datum/reagent/pax + process_flags = REAGENT_ORGANIC | REAGENT_SYNTHETIC + +/datum/reagent/water + process_flags = REAGENT_ORGANIC | REAGENT_SYNTHETIC + +/datum/reagent/hellwater + process_flags = REAGENT_ORGANIC | REAGENT_SYNTHETIC + +/datum/reagent/carbondioxide + process_flags = REAGENT_ORGANIC | REAGENT_SYNTHETIC + +/datum/reagent/iron + chemical_flags_nova = REAGENT_BLOOD_REGENERATING + +/datum/reagent/blood + chemical_flags_nova = REAGENT_BLOOD_REGENERATING // For Hemophages to be able to drink it without any issue. + +/datum/reagent/blood/on_new(list/data) + . = ..() + + if(!src.data["blood_type"]) + src.data["blood_type"] = random_blood_type() // This is so we don't get blood without a blood type spawned from something that doesn't explicitly set the blood type. + + + +/datum/reagent/stable_plasma/on_mob_life(mob/living/carbon/C) + if(C.mob_biotypes & MOB_ROBOTIC) + C.nutrition = min(C.nutrition + 5, NUTRITION_LEVEL_FULL-1) + ..() + +/datum/reagent/fuel/on_mob_life(mob/living/carbon/C) + if(C.mob_biotypes & MOB_ROBOTIC) + C.nutrition = min(C.nutrition + 5, NUTRITION_LEVEL_FULL-1) + ..() + +/datum/reagent/fuel/oil/on_mob_life(mob/living/carbon/C) + if(C.mob_biotypes & MOB_ROBOTIC && C.blood_volume < BLOOD_VOLUME_NORMAL) + C.blood_volume += 0.5 + ..() + +/datum/reagent/carbondioxide/on_mob_life(mob/living/carbon/C) + if(C.mob_biotypes & MOB_ROBOTIC) + C.nutrition = min(C.nutrition + 5, NUTRITION_LEVEL_FULL-1) + ..() +*/ +// Catnip +/datum/reagent/pax/catnip + name = "Catnip" + taste_description = "grass" + description = "A colourless liquid that makes people more peaceful and felines happier." + metabolization_rate = 1.75 * REAGENTS_METABOLISM + +/datum/reagent/pax/catnip/on_mob_life(mob/living/carbon/M) + if(isfelinid(M)) + if(prob(20)) + M.emote("nya") + if(prob(20)) + to_chat(M, span_notice("[pick("Headpats feel nice.", "Backrubs would be nice.", "Mew")]")) + else + to_chat(M, span_notice("[pick("I feel oddly calm.", "I feel relaxed.", "Mew?")]")) + ..() + +/* +#define DERMAGEN_SCAR_FIX_AMOUNT 10 + +/datum/reagent/medicine/dermagen + name = "Dermagen" + description = "Heals scars formed by past physical trauma when applied. Minimum 10u needed, only works when applied topically." + reagent_state = LIQUID + color = "#FFEBEB" + ph = 6 + chemical_flags = REAGENT_CAN_BE_SYNTHESIZED + +/datum/reagent/medicine/dermagen/expose_mob(mob/living/exposed_mob, methods=TOUCH, reac_volume, show_message = TRUE) + . = ..() + if(!iscarbon(exposed_mob)) + return + if(!(methods & (PATCH|TOUCH|VAPOR))) + return + var/mob/living/carbon/scarred = exposed_mob + if(scarred.stat == DEAD) + show_message = FALSE + if(show_message) + to_chat(scarred, span_danger("The scars on your body start to fade and disappear.")) + if(reac_volume >= DERMAGEN_SCAR_FIX_AMOUNT) + for(var/i in scarred.all_scars) + qdel(i) + +#undef DERMAGEN_SCAR_FIX_AMOUNT +*/ diff --git a/modular_doppler/modular_food_and_drinks/alcohol reagents.dm b/modular_doppler/modular_food_drinks_and_chems/food_and_drinks/alcohol reagents.dm similarity index 90% rename from modular_doppler/modular_food_and_drinks/alcohol reagents.dm rename to modular_doppler/modular_food_drinks_and_chems/food_and_drinks/alcohol reagents.dm index 2eb87b99c6e9d..8e639ef8f63b5 100644 --- a/modular_doppler/modular_food_and_drinks/alcohol reagents.dm +++ b/modular_doppler/modular_food_drinks_and_chems/food_and_drinks/alcohol reagents.dm @@ -22,7 +22,7 @@ /datum/glass_style/drinking_glass/synthanol required_drink_type = /datum/reagent/consumable/ethanol/synthanol - icon = 'modular_doppler/modular_food_and_drinks/icons/drinks.dmi' + icon = 'modular_doppler/modular_food_drinks_and_chems/icons/drinks.dmi' icon_state = "synthanolglass" name = "glass of synthanol" desc = "The equivalent of alcohol for synthetic crewmembers. They'd find it awful if they had tastebuds too." @@ -137,7 +137,7 @@ /datum/glass_style/drinking_glass/hot_toddy required_drink_type = /datum/reagent/consumable/ethanol/hot_toddy - icon = 'modular_doppler/modular_food_and_drinks/icons/drinks.dmi' + icon = 'modular_doppler/modular_food_drinks_and_chems/icons/drinks.dmi' icon_state = "hot_toddy" name = "hot toddy glass" desc = "An old fashioned cocktail made of honey, rum, and tea, it tastes like sweet holiday spices." @@ -152,7 +152,7 @@ /datum/glass_style/drinking_glass/hellfire required_drink_type = /datum/reagent/consumable/ethanol/hellfire - icon = 'modular_doppler/modular_food_and_drinks/icons/drinks.dmi' + icon = 'modular_doppler/modular_food_drinks_and_chems/icons/drinks.dmi' icon_state = "hellfire" name = "glass of hellfire" desc = "An amber colored drink that isn't quite as hot as it looks." @@ -172,7 +172,7 @@ /datum/glass_style/drinking_glass/sins_delight required_drink_type = /datum/reagent/consumable/ethanol/sins_delight - icon = 'modular_doppler/modular_food_and_drinks/icons/drinks.dmi' + icon = 'modular_doppler/modular_food_drinks_and_chems/icons/drinks.dmi' icon_state = "sins_delight" name = "glass of sin's delight" desc = "You can smell the seven sins rolling off the top of the glass." @@ -187,7 +187,7 @@ /datum/glass_style/drinking_glass/strawberry_daiquiri required_drink_type = /datum/reagent/consumable/ethanol/strawberry_daiquiri - icon = 'modular_doppler/modular_food_and_drinks/icons/drinks.dmi' + icon = 'modular_doppler/modular_food_drinks_and_chems/icons/drinks.dmi' icon_state = "strawberry_daiquiri" name = "glass of strawberry daiquiri" desc = "Pink looking drink with flowers and a big straw to sip it. Looks sweet and refreshing, perfect for warm days." @@ -202,7 +202,7 @@ /datum/glass_style/drinking_glass/liz_fizz required_drink_type = /datum/reagent/consumable/ethanol/liz_fizz - icon = 'modular_doppler/modular_food_and_drinks/icons/drinks.dmi' + icon = 'modular_doppler/modular_food_drinks_and_chems/icons/drinks.dmi' icon_state = "liz_fizz" name = "glass of liz fizz" desc = "Looks like a citrus sherbet seperated in layers? Why would anyone want that is beyond you." @@ -217,7 +217,7 @@ /datum/glass_style/drinking_glass/miami_vice required_drink_type = /datum/reagent/consumable/ethanol/miami_vice - icon = 'modular_doppler/modular_food_and_drinks/icons/drinks.dmi' + icon = 'modular_doppler/modular_food_drinks_and_chems/icons/drinks.dmi' icon_state = "miami_vice" name = "glass of miami vice" desc = "Strawberries and coconut, like yin and yang." @@ -232,7 +232,7 @@ /datum/glass_style/drinking_glass/malibu_sunset required_drink_type = /datum/reagent/consumable/ethanol/malibu_sunset - icon = 'modular_doppler/modular_food_and_drinks/icons/drinks.dmi' + icon = 'modular_doppler/modular_food_drinks_and_chems/icons/drinks.dmi' icon_state = "malibu_sunset" name = "glass of malibu sunset" desc = "Tropical looking drinks, with ice cubes hovering on the surface and grenadine coloring the bottom." @@ -247,7 +247,7 @@ /datum/glass_style/drinking_glass/hotlime_miami required_drink_type = /datum/reagent/consumable/ethanol/hotlime_miami - icon = 'modular_doppler/modular_food_and_drinks/icons/drinks.dmi' + icon = 'modular_doppler/modular_food_drinks_and_chems/icons/drinks.dmi' icon_state = "hotlime_miami" name = "glass of hotlime miami" desc = "This looks very aesthetically pleasing." @@ -268,7 +268,7 @@ /datum/glass_style/drinking_glass/coggrog required_drink_type = /datum/reagent/consumable/ethanol/coggrog - icon = 'modular_doppler/modular_food_and_drinks/icons/drinks.dmi' + icon = 'modular_doppler/modular_food_drinks_and_chems/icons/drinks.dmi' icon_state = "coggrog" name = "glass of cog grog" desc = "Not even Ratvar's Four Generals could withstand this! Qevax Jryy!" @@ -283,7 +283,7 @@ /datum/glass_style/drinking_glass/badtouch required_drink_type = /datum/reagent/consumable/ethanol/badtouch - icon = 'modular_doppler/modular_food_and_drinks/icons/drinks.dmi' + icon = 'modular_doppler/modular_food_drinks_and_chems/icons/drinks.dmi' icon_state = "badtouch" name = "glass of bad touch" desc = "We're nothing but mammals after all." @@ -298,7 +298,7 @@ /datum/glass_style/drinking_glass/marsblast required_drink_type = /datum/reagent/consumable/ethanol/marsblast - icon = 'modular_doppler/modular_food_and_drinks/icons/drinks.dmi' + icon = 'modular_doppler/modular_food_drinks_and_chems/icons/drinks.dmi' icon_state = "marsblast" name = "glass of marsblast" desc = "One of these is enough to leave your face as red as the planet." @@ -313,7 +313,7 @@ /datum/glass_style/drinking_glass/mercuryblast required_drink_type = /datum/reagent/consumable/ethanol/mercuryblast - icon = 'modular_doppler/modular_food_and_drinks/icons/drinks.dmi' + icon = 'modular_doppler/modular_food_drinks_and_chems/icons/drinks.dmi' icon_state = "mercuryblast" name = "glass of mercuryblast" desc = "No thermometers were harmed in the creation of this drink" @@ -332,7 +332,7 @@ /datum/glass_style/drinking_glass/piledriver required_drink_type = /datum/reagent/consumable/ethanol/piledriver - icon = 'modular_doppler/modular_food_and_drinks/icons/drinks.dmi' + icon = 'modular_doppler/modular_food_drinks_and_chems/icons/drinks.dmi' icon_state = "piledriver" name = "glass of piledriver" desc = "Not the only thing to leave your throat sore." @@ -347,7 +347,7 @@ /datum/glass_style/drinking_glass/zenstar required_drink_type = /datum/reagent/consumable/ethanol/zenstar - icon = 'modular_doppler/modular_food_and_drinks/icons/drinks.dmi' + icon = 'modular_doppler/modular_food_drinks_and_chems/icons/drinks.dmi' icon_state = "zenstar" name = "glass of zen star" desc = "You'd think something so balanced would actually taste nice... you'd be dead wrong." @@ -365,7 +365,7 @@ /datum/glass_style/drinking_glass/coldscales required_drink_type = /datum/reagent/consumable/ethanol/coldscales - icon = 'modular_doppler/modular_food_and_drinks/icons/drinks.dmi' + icon = 'modular_doppler/modular_food_drinks_and_chems/icons/drinks.dmi' icon_state = "coldscales" name = "glass of coldscales" desc = "A soft green drink that looks inviting!" @@ -386,7 +386,7 @@ /datum/glass_style/drinking_glass/oil_drum required_drink_type = /datum/reagent/consumable/ethanol/oil_drum - icon = 'modular_doppler/modular_food_and_drinks/icons/drinks.dmi' + icon = 'modular_doppler/modular_food_drinks_and_chems/icons/drinks.dmi' icon_state = "oil_drum" name = "drum of oil" desc = "A gray can of booze and oil..." @@ -408,7 +408,7 @@ /datum/glass_style/drinking_glass/nord_king required_drink_type = /datum/reagent/consumable/ethanol/nord_king - icon = 'modular_doppler/modular_food_and_drinks/icons/drinks.dmi' + icon = 'modular_doppler/modular_food_drinks_and_chems/icons/drinks.dmi' icon_state = "nord_king" name = "keg of nord king" desc = "A dripping keg of red mead." @@ -431,7 +431,7 @@ /datum/glass_style/drinking_glass/velvet_kiss required_drink_type = /datum/reagent/consumable/ethanol/velvet_kiss - icon = 'modular_doppler/modular_food_and_drinks/icons/drinks.dmi' + icon = 'modular_doppler/modular_food_drinks_and_chems/icons/drinks.dmi' icon_state = "velvet_kiss" name = "glass of velvet kiss" desc = "Red and white drink for the upper classes or undead." @@ -457,7 +457,7 @@ /datum/glass_style/drinking_glass/abduction_fruit required_drink_type = /datum/reagent/consumable/ethanol/abduction_fruit - icon = 'modular_doppler/modular_food_and_drinks/icons/drinks.dmi' + icon = 'modular_doppler/modular_food_drinks_and_chems/icons/drinks.dmi' icon_state = "abduction_fruit" name = "glass of abduction fruit" desc = "Mixed fruits that were never meant to be mixed..." @@ -478,7 +478,7 @@ /datum/glass_style/drinking_glass/bug_zapper required_drink_type = /datum/reagent/consumable/ethanol/bug_zapper - icon = 'modular_doppler/modular_food_and_drinks/icons/drinks.dmi' + icon = 'modular_doppler/modular_food_drinks_and_chems/icons/drinks.dmi' icon_state = "bug_zapper" name = "glass of bug zapper" desc = "An odd mix of copper, lemon juice and power meant for non-human consumption." @@ -499,7 +499,7 @@ /datum/glass_style/drinking_glass/mush_crush required_drink_type = /datum/reagent/consumable/ethanol/mush_crush - icon = 'modular_doppler/modular_food_and_drinks/icons/drinks.dmi' + icon = 'modular_doppler/modular_food_drinks_and_chems/icons/drinks.dmi' icon_state = "mush_crush" name = "glass of mush crush" desc = "Popular among people that want to grow their own food rather than drink the soil." @@ -520,7 +520,7 @@ /datum/glass_style/drinking_glass/hollow_bone required_drink_type = /datum/reagent/consumable/ethanol/hollow_bone - icon = 'modular_doppler/modular_food_and_drinks/icons/drinks.dmi' + icon = 'modular_doppler/modular_food_drinks_and_chems/icons/drinks.dmi' icon_state = "hollow_bone" name = "skull of hollow bone" desc = "Mixing of milk and bone hurting juice for enjoyment for rather skinny people." @@ -541,7 +541,7 @@ /datum/glass_style/drinking_glass/jell_wyrm required_drink_type = /datum/reagent/consumable/ethanol/jell_wyrm - icon = 'modular_doppler/modular_food_and_drinks/icons/drinks.dmi' + icon = 'modular_doppler/modular_food_drinks_and_chems/icons/drinks.dmi' icon_state = "jell_wyrm" name = "glass of jell wyrm" desc = "A bubbly drink that is rather inviting to those that don't know who it's meant for." @@ -572,7 +572,7 @@ /datum/glass_style/drinking_glass/laval_spit required_drink_type = /datum/reagent/consumable/ethanol/laval_spit - icon = 'modular_doppler/modular_food_and_drinks/icons/drinks.dmi' + icon = 'modular_doppler/modular_food_drinks_and_chems/icons/drinks.dmi' icon_state = "laval_spit" name = "glass of laval spit" desc = "Piping hot drink for those who can stomach the heat of lava." @@ -583,6 +583,7 @@ else quality = DRINK_GOOD return ..() +*/ /datum/reagent/consumable/ethanol/frisky_kitty name = "Frisky Kitty" @@ -593,19 +594,19 @@ /datum/glass_style/drinking_glass/frisky_kitty required_drink_type = /datum/reagent/consumable/ethanol/frisky_kitty - icon = 'modular_doppler/modular_food_and_drinks/icons/drinks.dmi' + icon = 'modular_doppler/modular_food_drinks_and_chems/icons/drinks.dmi' icon_state = "frisky_kitty" name = "cup of frisky kitty" desc = "Warm milk and some catnip." -/datum/reagent/consumable/ethanol/frisky_kitty/expose_mob(mob/living/exposed_mob, methods, reac_volume) - if(isfeline(exposed_mob)) +/*/datum/reagent/consumable/ethanol/frisky_kitty/expose_mob(mob/living/exposed_mob, methods, reac_volume) + if(isfelinid(exposed_mob)) quality = RACE_DRINK else quality = DRINK_GOOD - return ..() - + return ..()*/ +/* /datum/reagent/consumable/ethanol/bloodshot_base name = "Bloodshot Base" description = "The bootleg blend of nutrients and alcohol that goes into making Bloodshots. Doesn't taste too great on its own, for Hemophages at least." @@ -627,7 +628,7 @@ /datum/glass_style/drinking_glass/bloodshot required_drink_type = /datum/reagent/consumable/ethanol/bloodshot - icon = 'modular_doppler/modular_food_and_drinks/icons/drinks.dmi' + icon = 'modular_doppler/modular_food_drinks_and_chems/icons/drinks.dmi' icon_state = "bloodshot" name = "glass of bloodshot" desc = "The history of the 'Bloodshot' is based in a mix of flavor-neutral chems devised to help deliver nutrients to a Hemophage's tumorous organs. Due to the expense of the real thing and the clinical nature of it, this liquor has been designed as a 'improvised' alternative; though, still tasting like a hangover cure. It smells like iron, giving a clue to the key ingredient." @@ -667,7 +668,7 @@ /datum/glass_style/drinking_glass/blizzard_brew required_drink_type = /datum/reagent/consumable/ethanol/blizzard_brew - icon = 'modular_doppler/modular_food_and_drinks/icons/drinks.dmi' + icon = 'modular_doppler/modular_food_drinks_and_chems/icons/drinks.dmi' icon_state = "blizzard_brew" name = "glass of Blizzard Brew" desc = "An ancient recipe. Served best chilled as much as dwarvenly possible." @@ -704,7 +705,7 @@ /datum/glass_style/drinking_glass/molten_mead required_drink_type = /datum/reagent/consumable/ethanol/molten_mead - icon = 'modular_doppler/modular_food_and_drinks/icons/drinks.dmi' + icon = 'modular_doppler/modular_food_drinks_and_chems/icons/drinks.dmi' icon_state = "molten_mead" name = "glass of Molten Mead" desc = "Famously known to set beards aflame. Ingest at your own risk!" @@ -736,17 +737,17 @@ /datum/glass_style/drinking_glass/hippie_hooch required_drink_type = /datum/reagent/consumable/ethanol/hippie_hooch - icon = 'modular_doppler/modular_food_and_drinks/icons/drinks.dmi' + icon = 'modular_doppler/modular_food_drinks_and_chems/icons/drinks.dmi' icon_state = "hippie_hooch" name = "glass of Hippie Hooch" desc = "Peace and love! Under request of the HR department, this drink is sure to sober you up quickly." -/datum/reagent/consumable/ethanol/hippie_hooch/expose_mob(mob/living/exposed_mob, methods, reac_volume) +/*/datum/reagent/consumable/ethanol/hippie_hooch/expose_mob(mob/living/exposed_mob, methods, reac_volume) if(isdwarf(exposed_mob)) quality = RACE_DRINK else quality = DRINK_FANTASTIC - return ..() + return ..()*/ /datum/reagent/consumable/ethanol/hippie_hooch/on_mob_life(mob/living/carbon/affected_mob, seconds_per_tick, times_fired) for(var/effect in status_effects_to_clear) @@ -766,17 +767,17 @@ /datum/glass_style/drinking_glass/research_rum required_drink_type = /datum/reagent/consumable/ethanol/research_rum - icon = 'modular_doppler/modular_food_and_drinks/icons/drinks.dmi' + icon = 'modular_doppler/modular_food_drinks_and_chems/icons/drinks.dmi' icon_state = "research_rum" name = "glass of Research Rum" desc = "Cooked up by dwarven scientists, this glowing pink brew is sure to supercharge your thinking. How? Science!" -/datum/reagent/consumable/ethanol/research_rum/expose_mob(mob/living/exposed_mob, methods, reac_volume) +/*/datum/reagent/consumable/ethanol/research_rum/expose_mob(mob/living/exposed_mob, methods, reac_volume) if(isdwarf(exposed_mob)) quality = RACE_DRINK else quality = DRINK_GOOD - return ..() + return ..()*/ /datum/reagent/consumable/ethanol/research_rum/on_mob_life(mob/living/carbon/drinker, seconds_per_tick, times_fired) . = ..() @@ -792,17 +793,17 @@ /datum/glass_style/drinking_glass/golden_grog required_drink_type = /datum/reagent/consumable/ethanol/golden_grog - icon = 'modular_doppler/modular_food_and_drinks/icons/drinks.dmi' + icon = 'modular_doppler/modular_food_drinks_and_chems/icons/drinks.dmi' icon_state = "golden_grog" name = "glass of Golden Grog" desc = "A drink concocted by a dwarven Quartermaster who had too much time and money on his hands. Commonly ordered by influencers looking to flaunt their wealth." -/datum/reagent/consumable/ethanol/golden_grog/expose_mob(mob/living/exposed_mob, methods, reac_volume) +/*/datum/reagent/consumable/ethanol/golden_grog/expose_mob(mob/living/exposed_mob, methods, reac_volume) if(isdwarf(exposed_mob)) quality = RACE_DRINK else quality = DRINK_FANTASTIC - return ..() + return ..()*/ // RACIAL DRINKS END @@ -816,7 +817,7 @@ /datum/glass_style/drinking_glass/appletini required_drink_type = /datum/reagent/consumable/ethanol/appletini - icon = 'modular_doppler/modular_food_and_drinks/icons/drinks.dmi' + icon = 'modular_doppler/modular_food_drinks_and_chems/icons/drinks.dmi' icon_state = "appletini" name = "glass of appletini" desc = "An appley beverage in a martini glass" @@ -832,7 +833,7 @@ /datum/glass_style/drinking_glass/cityofsin required_drink_type = /datum/reagent/consumable/ethanol/quadruple_sec/cityofsin - icon = 'modular_doppler/modular_food_and_drinks/icons/drinks.dmi' + icon = 'modular_doppler/modular_food_drinks_and_chems/icons/drinks.dmi' icon_state = "cityofsin" name = "glass of city of sin" desc = "Looking at it makes you recall every mistake you've made." @@ -848,7 +849,7 @@ /datum/glass_style/drinking_glass/shakiri required_drink_type = /datum/reagent/consumable/ethanol/shakiri - icon = 'modular_doppler/modular_food_and_drinks/icons/drinks.dmi' + icon = 'modular_doppler/modular_food_drinks_and_chems/icons/drinks.dmi' icon_state = "shakiri" name = "glass of shakiri" desc = "A sweet, fragrant red drink made from fermented kiri fruits. It seems to gently sparkle when exposed to light." @@ -863,7 +864,7 @@ /datum/glass_style/drinking_glass/shakiri_spritz required_drink_type = /datum/reagent/consumable/ethanol/shakiri_spritz - icon = 'modular_doppler/modular_food_and_drinks/icons/drinks.dmi' + icon = 'modular_doppler/modular_food_drinks_and_chems/icons/drinks.dmi' icon_state = "shakiri_spritz" name = "glass of shakiri spritz" desc = "A carbonated cocktail made from shakiri and orange juice with soda water." @@ -878,7 +879,7 @@ /datum/glass_style/drinking_glass/crimson_hurricane required_drink_type = /datum/reagent/consumable/ethanol/crimson_hurricane - icon = 'modular_doppler/modular_food_and_drinks/icons/drinks.dmi' + icon = 'modular_doppler/modular_food_drinks_and_chems/icons/drinks.dmi' icon_state = "crimson_hurricane" name = "glass of crimson hurricane" desc = "A strong, citrusy cocktail of human origin, now with shakiri and kiri jelly for a delightfully sweet drink." @@ -893,7 +894,7 @@ /datum/glass_style/drinking_glass/shakiri_rogers required_drink_type = /datum/reagent/consumable/ethanol/shakiri_rogers - icon = 'modular_doppler/modular_food_and_drinks/icons/drinks.dmi' + icon = 'modular_doppler/modular_food_drinks_and_chems/icons/drinks.dmi' icon_state = "shakiri_rogers" name = "glass of shakiri rogers" desc = "A take on the classic Roy Rogers, with shakiri instead of grenadine. Sweet and refreshing." diff --git a/modular_doppler/modular_food_and_drinks/drink_reagents.dm b/modular_doppler/modular_food_drinks_and_chems/food_and_drinks/drink_reagents.dm similarity index 92% rename from modular_doppler/modular_food_and_drinks/drink_reagents.dm rename to modular_doppler/modular_food_drinks_and_chems/food_and_drinks/drink_reagents.dm index 0becf4329ae8f..645a22c886455 100644 --- a/modular_doppler/modular_food_and_drinks/drink_reagents.dm +++ b/modular_doppler/modular_food_drinks_and_chems/food_and_drinks/drink_reagents.dm @@ -7,7 +7,7 @@ /datum/glass_style/drinking_glass/pinkmilk required_drink_type = /datum/reagent/consumable/pinkmilk - icon = 'modular_nova/master_files/icons/obj/drinks.dmi' + icon = 'modular_doppler/modular_food_drinks_and_chems/icons/drinks.dmi' icon_state = "pinkmilk" name = "tall glass of strawberry milk" desc = "Delicious flavored strawberry syrup mixed with milk." @@ -27,7 +27,7 @@ /datum/glass_style/drinking_glass/pinktea required_drink_type = /datum/reagent/consumable/pinktea - icon = 'modular_nova/master_files/icons/obj/drinks.dmi' + icon = 'modular_doppler/modular_food_drinks_and_chems/icons/drinks.dmi' icon_state = "pinktea" name = "mug of strawberry tea" desc = "Delicious traditional tea flavored with strawberries." @@ -46,14 +46,14 @@ /datum/glass_style/drinking_glass/catnip_tea required_drink_type = /datum/reagent/consumable/catnip_tea - icon = 'modular_nova/master_files/icons/obj/drinks.dmi' + icon = 'modular_doppler/modular_food_drinks_and_chems/icons/drinks.dmi' icon_state = "catnip_tea" name = "glass of catnip tea" desc = "A purrfect drink for a cat." /datum/reagent/consumable/catnip_tea/on_mob_life(mob/living/carbon/M) M.adjustStaminaLoss(min(50 - M.getStaminaLoss(), 3)) - if(isfeline(M)) + if(isfelinid(M)) if(prob(20)) M.emote("nya") if(prob(20)) diff --git a/modular_doppler/modular_food_drinks_and_chems/food_and_drinks/drinks.dm b/modular_doppler/modular_food_drinks_and_chems/food_and_drinks/drinks.dm new file mode 100644 index 0000000000000..882f440c220c7 --- /dev/null +++ b/modular_doppler/modular_food_drinks_and_chems/food_and_drinks/drinks.dm @@ -0,0 +1,87 @@ +/// How much fizziness is added to the can of soda by throwing it, in percentage points +#define SODA_FIZZINESS_THROWN 15 +/// How much fizziness is added to the can of soda by shaking it, in percentage points +#define SODA_FIZZINESS_SHAKE 5 + +/obj/item/reagent_containers/cup/soda_cans/doppler + icon = 'modular_doppler/modular_food_drinks_and_chems/icons/drinks.dmi' + icon_state = null + +/obj/item/reagent_containers/cup/soda_cans/doppler/attack(mob/M, mob/living/user) + if(istype(M, /mob/living/carbon) && !reagents.total_volume && user.combat_mode && user.zone_selected == BODY_ZONE_HEAD) + if(M == user) + user.visible_message(span_warning("[user] crushes the can of [src] on [user.p_their()] forehead!"), span_notice("You crush the can of [src] on your forehead.")) + else + user.visible_message(span_warning("[user] crushes the can of [src] on [M]'s forehead!"), span_notice("You crush the can of [src] on [M]'s forehead.")) + playsound(M,'sound/weapons/pierce.ogg', rand(10,50), TRUE) + var/obj/item/trash/can/doppler/crushed_can = new /obj/item/trash/can/doppler(M.loc) + crushed_can.icon_state = icon_state + qdel(src) + return TRUE + . = ..() + +/obj/item/reagent_containers/cup/soda_cans/doppler/bullet_act(obj/projectile/hitting_projectile, def_zone, piercing_hit = FALSE) + . = ..() + + if(. != BULLET_ACT_HIT) + return + + if(hitting_projectile.damage > 0 && hitting_projectile.damage_type == BRUTE && !QDELETED(src)) + var/obj/item/trash/can/doppler/crushed_can = new /obj/item/trash/can/doppler(src.loc) + crushed_can.icon_state = icon_state + var/atom/throw_target = get_edge_target_turf(crushed_can, pick(GLOB.alldirs)) + crushed_can.throw_at(throw_target, rand(1,2), 7) + qdel(src) + return + +/** + * Burst the soda open on someone. Fun! Opens and empties the soda can, but does not crush it. + * + * Arguments: + * * target - Who's getting covered in soda + * * hide_message - Stops the generic fizzing message, so you can do your own + */ + +/obj/item/reagent_containers/cup/soda_cans/doppler/throw_impact(atom/hit_atom, datum/thrownthing/throwingdatum) + . = ..() + if(. || spillable || !reagents.total_volume) // if it was caught, already opened, or has nothing in it + return + + fizziness += SODA_FIZZINESS_THROWN + if(!prob(fizziness)) + return + + burst_soda(hit_atom, hide_message = TRUE) + visible_message(span_danger("[src]'s impact with [hit_atom] causes it to rupture, spilling everywhere!")) + var/obj/item/trash/can/doppler/crushed_can = new /obj/item/trash/can/doppler(src.loc) + crushed_can.icon_state = icon_state + moveToNullspace() + QDEL_IN(src, 1 SECONDS) // give it a second so it can still be logged for the throw impact + +/obj/item/trash/can/doppler + icon = 'modular_doppler/clutter objects/icons/janitor.dmi' + icon_state = "lemonade" + +/obj/item/reagent_containers/cup/soda_cans/doppler/lubricola + name = "LubriCola" + desc = "The perfect lubricant for your weary gears." + icon_state = "lubricola" + list_reagents = list(/datum/reagent/fuel/oil = 30) + custom_price = PAYCHECK_LOWER * 1.2 + +/obj/item/reagent_containers/cup/soda_cans/doppler/welding_fizz + name = "Welding Fizz" + desc = "More energy than in an IED! Now carbonated. WARNING: Contains toxic and flammable fuels." + icon_state = "welding_fizz" + list_reagents = list(/datum/reagent/fuel = 25, /datum/reagent/carbondioxide = 5) + custom_price = PAYCHECK_LOWER * 1.2 + +/*/obj/item/reagent_containers/cup/soda_cans/doppler/synthanolcan + name = "Silly Cone's Synthanol" + desc = "A recompiling can of synthanol." + icon_state = "synthanolcan" + list_reagents = list(/datum/reagent/consumable/ethanol/synthanol = 30) + custom_price = PAYCHECK_CREW*/ + +#undef SODA_FIZZINESS_THROWN +#undef SODA_FIZZINESS_SHAKE diff --git a/modular_doppler/modular_food_and_drinks/drinks_recipes.dm b/modular_doppler/modular_food_drinks_and_chems/food_and_drinks/drinks_recipes.dm similarity index 98% rename from modular_doppler/modular_food_and_drinks/drinks_recipes.dm rename to modular_doppler/modular_food_drinks_and_chems/food_and_drinks/drinks_recipes.dm index 46e4a95a37e42..0e9f8686d0386 100644 --- a/modular_doppler/modular_food_and_drinks/drinks_recipes.dm +++ b/modular_doppler/modular_food_drinks_and_chems/food_and_drinks/drinks_recipes.dm @@ -197,7 +197,7 @@ /datum/reagent/consumable/berryjuice = 1, ) -/datum/chemical_reaction/drink/blizzard_brew +/*/datum/chemical_reaction/drink/blizzard_brew results = list(/datum/reagent/consumable/ethanol/blizzard_brew = 3) required_reagents = list( /datum/reagent/consumable/ethanol/iced_beer = 1, @@ -215,7 +215,7 @@ /datum/reagent/consumable/ethanol/mauna_loa = 1, ) mix_message = "You hear sizzling flesh and angry wasps buzzing as it mixes." - mix_sound = 'sound/effects/wounds/sizzle2.ogg' + mix_sound = 'sound/effects/wounds/sizzle2.ogg'*/ /datum/chemical_reaction/drink/hippie_hooch results = list(/datum/reagent/consumable/ethanol/hippie_hooch = 5) @@ -225,7 +225,7 @@ /datum/reagent/medicine/earthsblood = 1, ) mix_message = "You hear wood flutes and nature as it mixes." - mix_sound = 'modular_skyrat/modules/emotes/sound/voice/hoot.ogg' + mix_sound = 'modular_doppler/emotes/sound/hoot.ogg' /datum/chemical_reaction/drink/research_rum results = list(/datum/reagent/consumable/ethanol/research_rum = 4) @@ -332,7 +332,7 @@ /datum/reagent/sulfur = 5, ) required_temp = 900 // (626.85'C) - +*/ /datum/chemical_reaction/drink/frisky_kitty results = list(/datum/reagent/consumable/ethanol/frisky_kitty = 2) required_reagents = list( @@ -340,7 +340,7 @@ /datum/reagent/consumable/milk = 1, ) required_temp = 296 //Just above room temp (22.85'C) - +/* /datum/chemical_reaction/drink/bloodshot_base results = list(/datum/reagent/consumable/ethanol/bloodshot_base = 2) required_reagents = list( @@ -358,7 +358,7 @@ reaction_tags = REACTION_TAG_DRINK | REACTION_TAG_EASY | REACTION_TAG_OTHER */ -// Non-Booze, see modular_skyrat\modules\customization\modules\reagents\chemistry\reagents\drink_reagents.dm +// Non-Booze /datum/chemical_reaction/drink/pinkmilk results = list(/datum/reagent/consumable/pinkmilk = 2) diff --git a/modular_doppler/modular_food_drinks_and_chems/icons/drinks.dmi b/modular_doppler/modular_food_drinks_and_chems/icons/drinks.dmi new file mode 100644 index 0000000000000000000000000000000000000000..0b1eaf31cf57162d001c77b3d106de269c5afab0 GIT binary patch literal 31307 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 literal 0 HcmV?d00001 diff --git a/modular_doppler/vending_machines/code/vendor_snacks.dm b/modular_doppler/vending_machines/code/vendor_snacks.dm index 36778ad36f5cc..4d2b42c3911c3 100644 --- a/modular_doppler/vending_machines/code/vendor_snacks.dm +++ b/modular_doppler/vending_machines/code/vendor_snacks.dm @@ -11,7 +11,7 @@ junkiness = 10 custom_price = PAYCHECK_LOWER * INFINITY tastes = list("the unmatched power of the sun" = 10) - foodtypes = JUNKFOOD | CLOTH | GORE | NUTS | FRIED | FRUIT //You don't want to know what's in the broken debug snacks + foodtypes = JUNKFOOD | CLOTH | GORE | NUTS | FRIED | FRUIT w_class = WEIGHT_CLASS_SMALL /obj/item/trash/vendor_trash @@ -86,11 +86,11 @@ /obj/item/reagent_containers/cup/glass/waterbottle/tea name = "bottle of tea" desc = "A bottle of tea brought to you in a convenient plastic bottle." - icon = 'modular_doppler/modular_food_and_drinks/icons/drinks.dmi' + icon = 'modular_doppler/modular_food_drinks_and_chems/icons/drinks.dmi' icon_state = "tea_bottle" list_reagents = list(/datum/reagent/consumable/tea = 40) cap_icon_state = "bottle_cap_tea" - flip_chance = 5 //I fucking dare you + flip_chance = 5 custom_price = PAYCHECK_LOWER * 1.2 fill_icon_state = null @@ -100,7 +100,7 @@ icon_state = "tea_bottle_blue" list_reagents = list( /datum/reagent/consumable/tea = 25, - /datum/reagent/medicine/salglu_solution = 10, // I know this looks strange but this is what tea astra grinds into, tea in the year 25whatever baby + /datum/reagent/medicine/salglu_solution = 10, /datum/reagent/consumable/nutriment/vitamin = 5, ) custom_price = PAYCHECK_LOWER * 2 @@ -118,7 +118,7 @@ icon_state = "tea_bottle_pink" list_reagents = list( /datum/reagent/consumable/catnip_tea = 20, - /datum/reagent/consumable/pinkmilk = 20, // I can't believe they would cut my catnip + /datum/reagent/consumable/pinkmilk = 20, ) custom_price = PAYCHECK_LOWER * 2.5 @@ -184,50 +184,50 @@ desc = "The clear plastic reveals that this no longer holds tasty treats for your winged friends." icon_state = "moth_bag_trash" -/obj/item/reagent_containers/cup/soda_cans/nova/lemonade +/obj/item/reagent_containers/cup/soda_cans/doppler/lemonade name = "\improper Gyárhajó 1023: Lemonade" desc = "A can of lemonade, for those who are into that kind of thing, or just have no choice." icon_state = "lemonade" list_reagents = list(/datum/reagent/consumable/lemonade = 30) drink_type = FRUIT -/obj/item/reagent_containers/cup/soda_cans/nova/lemonade/examine_more(mob/user) +/obj/item/reagent_containers/cup/soda_cans/doppler/lemonade/examine_more(mob/user) . = ..() . += span_notice("Markings on the can indicate this one was made on factory ship 1023 of the Grand Nomad Fleet.") return . -/obj/item/reagent_containers/cup/soda_cans/nova/navy_rum +/obj/item/reagent_containers/cup/soda_cans/doppler/navy_rum name = "\improper Gyárhajó 1506: Navy Rum" desc = "A can of navy rum brewed up and imported from a detachment of the nomad fleet, or so the can says." icon_state = "navy_rum" list_reagents = list(/datum/reagent/consumable/ethanol/navy_rum = 30) drink_type = ALCOHOL -/obj/item/reagent_containers/cup/soda_cans/nova/navy_rum/examine_more(mob/user) +/obj/item/reagent_containers/cup/soda_cans/doppler/navy_rum/examine_more(mob/user) . = ..() . += span_notice("Markings on the can indicate this one was made on factory ship 1506 of the Grand Nomad Fleet.") return . -/obj/item/reagent_containers/cup/soda_cans/nova/soda_water_moth +/obj/item/reagent_containers/cup/soda_cans/doppler/soda_water_moth name = "\improper Gyárhajó 1023: Soda Water" desc = "A can of soda water. Why not make a rum and soda? Now that you think of it, maybe not." icon_state = "soda_water" list_reagents = list(/datum/reagent/consumable/sodawater = 30) drink_type = SUGAR -/obj/item/reagent_containers/cup/soda_cans/nova/soda_water_moth/examine_more(mob/user) +/obj/item/reagent_containers/cup/soda_cans/doppler/soda_water_moth/examine_more(mob/user) . = ..() . += span_notice("Markings on the can indicate this one was made on factory ship 1023 of the Grand Nomad Fleet.") return . -/obj/item/reagent_containers/cup/soda_cans/nova/ginger_beer +/obj/item/reagent_containers/cup/soda_cans/doppler/ginger_beer name = "\improper Gyárhajó 1023: Ginger Beer" desc = "A can of ginger beer, don't let the beer part mislead you, this is entirely non-alcoholic." icon_state = "gingie_beer" list_reagents = list(/datum/reagent/consumable/sol_dry = 30) drink_type = SUGAR -/obj/item/reagent_containers/cup/soda_cans/nova/ginger_beer/examine_more(mob/user) +/obj/item/reagent_containers/cup/soda_cans/doppler/ginger_beer/examine_more(mob/user) . = ..() . += span_notice("Markings on the can indicate this one was made on factory ship 1023 of the Grand Nomad Fleet.") return . @@ -294,7 +294,7 @@ list_reagents = list(/datum/reagent/consumable/mushroom_tea = 40) custom_price = PAYCHECK_LOWER * 2 -/obj/item/reagent_containers/cup/soda_cans/nova/kortara +/obj/item/reagent_containers/cup/soda_cans/doppler/kortara name = "kortara" desc = "A can of kortara, alcohol brewed from korta seeds, which gives it a unique peppery spice flavor." icon_state = "kortara" diff --git a/modular_doppler/vending_machines/code/vendors.dm b/modular_doppler/vending_machines/code/vendors.dm index de0a4fe451256..f5a4085f79a4c 100644 --- a/modular_doppler/vending_machines/code/vendors.dm +++ b/modular_doppler/vending_machines/code/vendors.dm @@ -4,16 +4,16 @@ /obj/machinery/vending/imported/yangyu, /obj/machinery/vending/imported/mothic, /obj/machinery/vending/imported/tiziran, -// /obj/machinery/vending/deforest_medvend, //commented out until i'm ready to port them +// /obj/machinery/vending/deforest_medvend, ) -/obj/effect/spawner/random/vending/colavend //These can serve both snacks AND drinks so its kinda both of them? +/obj/effect/spawner/random/vending/colavend //These can serve both snacks AND drinks so it's kinda both of them? loot = list( /obj/machinery/vending/imported/nt, /obj/machinery/vending/imported/yangyu, /obj/machinery/vending/imported/mothic, /obj/machinery/vending/imported/tiziran, -// /obj/machinery/vending/deforest_medvend, //commented out until i'm ready to port them +// /obj/machinery/vending/deforest_medvend, ) /datum/supply_pack/vending/imported/fill(obj/structure/closet/crate/target_crate) @@ -144,10 +144,10 @@ /obj/item/food/vendor_snacks/moth_bag/fuel_jack = 6, /obj/item/food/vendor_snacks/moth_bag/cheesecake = 6, /obj/item/food/vendor_snacks/moth_bag/cheesecake/honey = 6, - /obj/item/reagent_containers/cup/soda_cans/nova/lemonade = 6, - /obj/item/reagent_containers/cup/soda_cans/nova/navy_rum = 6, - /obj/item/reagent_containers/cup/soda_cans/nova/soda_water_moth = 6, - /obj/item/reagent_containers/cup/soda_cans/nova/ginger_beer = 6, + /obj/item/reagent_containers/cup/soda_cans/doppler/lemonade = 6, + /obj/item/reagent_containers/cup/soda_cans/doppler/navy_rum = 6, + /obj/item/reagent_containers/cup/soda_cans/doppler/soda_water_moth = 6, + /obj/item/reagent_containers/cup/soda_cans/doppler/ginger_beer = 6, ), ), list( @@ -197,7 +197,7 @@ /obj/item/food/vendor_snacks/lizard_box/sweet_roll = 6, /obj/item/reagent_containers/cup/glass/bottle/mushi_kombucha = 6, /obj/item/reagent_containers/cup/glass/waterbottle/tea/mushroom = 6, - /obj/item/reagent_containers/cup/soda_cans/nova/kortara = 6, + /obj/item/reagent_containers/cup/soda_cans/doppler/kortara = 6, ), ), list( diff --git a/tgstation.dme b/tgstation.dme index 09e3158f0e881..6912ffc21f0a7 100644 --- a/tgstation.dme +++ b/tgstation.dme @@ -6362,9 +6362,11 @@ #include "modular_doppler\emotes\code\added_emotes\robot_sounds.dm" #include "modular_doppler\face_mouse_preferences\code\face_mouse_pref.dm" #include "modular_doppler\languages\language_datums.dm" -#include "modular_doppler\modular_food_and_drinks\alcohol reagents.dm" -#include "modular_doppler\modular_food_and_drinks\drink_reagents.dm" -#include "modular_doppler\modular_food_and_drinks\drinks_recipes.dm" +#include "modular_doppler\modular_food_drinks_and_chems\chemistry_reagents" +#include "modular_doppler\modular_food_drinks_and_chems\food_and_drinks\alcohol reagents.dm" +#include "modular_doppler\modular_food_drinks_and_chems\food_and_drinks\drink_reagents.dm" +#include "modular_doppler\modular_food_drinks_and_chems\food_and_drinks\drinks.dm" +#include "modular_doppler\modular_food_drinks_and_chems\food_and_drinks\drinks_recipes.dm" #include "modular_doppler\vending_machines\code\vendor_containers.dm" #include "modular_doppler\vending_machines\code\vendor_food.dm" #include "modular_doppler\vending_machines\code\vendor_snacks.dm" From a5bdef1cf51281a8464f4eb40f86335b21386c30 Mon Sep 17 00:00:00 2001 From: L <105110468+kittysmooch@users.noreply.github.com> Date: Mon, 26 Aug 2024 15:10:54 -0700 Subject: [PATCH 03/28] who among us has never fallen prey to this one --- .../{chemistry_reagents => chemistry_reagents.dm} | 0 tgstation.dme | 2 +- 2 files changed, 1 insertion(+), 1 deletion(-) rename modular_doppler/modular_food_drinks_and_chems/{chemistry_reagents => chemistry_reagents.dm} (100%) diff --git a/modular_doppler/modular_food_drinks_and_chems/chemistry_reagents b/modular_doppler/modular_food_drinks_and_chems/chemistry_reagents.dm similarity index 100% rename from modular_doppler/modular_food_drinks_and_chems/chemistry_reagents rename to modular_doppler/modular_food_drinks_and_chems/chemistry_reagents.dm diff --git a/tgstation.dme b/tgstation.dme index 6912ffc21f0a7..d2e9d8eab8465 100644 --- a/tgstation.dme +++ b/tgstation.dme @@ -6362,7 +6362,7 @@ #include "modular_doppler\emotes\code\added_emotes\robot_sounds.dm" #include "modular_doppler\face_mouse_preferences\code\face_mouse_pref.dm" #include "modular_doppler\languages\language_datums.dm" -#include "modular_doppler\modular_food_drinks_and_chems\chemistry_reagents" +#include "modular_doppler\modular_food_drinks_and_chems\chemistry_reagents.dm" #include "modular_doppler\modular_food_drinks_and_chems\food_and_drinks\alcohol reagents.dm" #include "modular_doppler\modular_food_drinks_and_chems\food_and_drinks\drink_reagents.dm" #include "modular_doppler\modular_food_drinks_and_chems\food_and_drinks\drinks.dm" From 49d5d1014457de201022dd014413339127b26aaf Mon Sep 17 00:00:00 2001 From: L <105110468+kittysmooch@users.noreply.github.com> Date: Mon, 26 Aug 2024 19:15:23 -0700 Subject: [PATCH 04/28] ez --- .../items/circuitboards/machines/machine_circuitboards.dm | 2 +- modular_doppler/vending_machines/code/vendor_snacks.dm | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/code/game/objects/items/circuitboards/machines/machine_circuitboards.dm b/code/game/objects/items/circuitboards/machines/machine_circuitboards.dm index d5c5dbd4db39e..53fef07eb194a 100644 --- a/code/game/objects/items/circuitboards/machines/machine_circuitboards.dm +++ b/code/game/objects/items/circuitboards/machines/machine_circuitboards.dm @@ -666,7 +666,7 @@ /obj/machinery/vending/wardrobe/science_wardrobe = "SciDrobe", /obj/machinery/vending/wardrobe/sec_wardrobe = "SecDrobe", /obj/machinery/vending/wardrobe/viro_wardrobe = "ViroDrobe", - /obj/machinery/vending/imported = "NT Sustenance Supplier", //DOPPLER ADDITION + /obj/machinery/vending/imported/nt = "NT Sustenance Supplier", //DOPPLER ADDITION /obj/machinery/vending/imported/yangyu = "Fudobenda", //DOPPLER ADDITION /obj/machinery/vending/imported/mothic = "Nomad Fleet Ration Chit Exchange", //DOPPLER ADDITION /obj/machinery/vending/imported/tiziran = "Tiziran Imported Delicacies", //DOPPLER ADDITION diff --git a/modular_doppler/vending_machines/code/vendor_snacks.dm b/modular_doppler/vending_machines/code/vendor_snacks.dm index 4d2b42c3911c3..0b5fd481f2b4d 100644 --- a/modular_doppler/vending_machines/code/vendor_snacks.dm +++ b/modular_doppler/vending_machines/code/vendor_snacks.dm @@ -86,7 +86,7 @@ /obj/item/reagent_containers/cup/glass/waterbottle/tea name = "bottle of tea" desc = "A bottle of tea brought to you in a convenient plastic bottle." - icon = 'modular_doppler/modular_food_drinks_and_chems/icons/drinks.dmi' + icon = 'modular_doppler/vending_machines/icons/imported_quick_foods.dmi' icon_state = "tea_bottle" list_reagents = list(/datum/reagent/consumable/tea = 40) cap_icon_state = "bottle_cap_tea" From 268cec510864815276508128935d9d68ec74950a Mon Sep 17 00:00:00 2001 From: L <105110468+kittysmooch@users.noreply.github.com> Date: Thu, 29 Aug 2024 04:11:30 -0700 Subject: [PATCH 05/28] yeah that's fine --- .../food_and_drinks/drink_reagents.dm | 2 +- .../food_and_drinks/drinks_recipes.dm | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/modular_doppler/modular_food_drinks_and_chems/food_and_drinks/drink_reagents.dm b/modular_doppler/modular_food_drinks_and_chems/food_and_drinks/drink_reagents.dm index 645a22c886455..062854fc73b3d 100644 --- a/modular_doppler/modular_food_drinks_and_chems/food_and_drinks/drink_reagents.dm +++ b/modular_doppler/modular_food_drinks_and_chems/food_and_drinks/drink_reagents.dm @@ -18,7 +18,7 @@ ..() . = 1 -/datum/reagent/consumable/pinktea //Tiny Tim song +/datum/reagent/consumable/pinktea name = "Strawberry Tea" description = "A timeless classic!" color = "#f76aeb"//rgb(247, 106, 235) diff --git a/modular_doppler/modular_food_drinks_and_chems/food_and_drinks/drinks_recipes.dm b/modular_doppler/modular_food_drinks_and_chems/food_and_drinks/drinks_recipes.dm index 0e9f8686d0386..420fea48fb751 100644 --- a/modular_doppler/modular_food_drinks_and_chems/food_and_drinks/drinks_recipes.dm +++ b/modular_doppler/modular_food_drinks_and_chems/food_and_drinks/drinks_recipes.dm @@ -249,7 +249,7 @@ mix_message = "You hear golden coins and snobby rich laughing as it mixes." mix_sound = 'sound/items/coinflip.ogg' -/* DEPRECATED UNTIL WE'RE READY +/* MORE STUFF WE CAN'T USE YET // RACE SPECIFIC DRINKS /datum/chemical_reaction/drink/coldscales From 0160217c44c79d876b541561d02732164202f543 Mon Sep 17 00:00:00 2001 From: Kaostico Date: Sat, 31 Aug 2024 03:16:42 -0300 Subject: [PATCH 06/28] first commit - 224 changes - my computer dies and I die --- code/__DEFINES/icon_smoothing.dm | 4 + .../chemical_flags_doppler.dm | 2 + code/__DEFINES/~doppler_defines/keybinds.dm | 1 + .../~doppler_defines/obj_flags_doppler.dm | 2 + .../~doppler_defines/reagent_forging_tools.dm | 4 + .../~doppler_defines/reskin_defines.dm | 8 + code/__DEFINES/~doppler_defines/signals.dm | 2 + code/__DEFINES/~doppler_defines/sound.dm | 6 + code/__DEFINES/~doppler_defines/span.dm | 1 + .../~doppler_defines/techweb_nodes.dm | 4 + code/__DEFINES/~doppler_defines/traits.dm | 11 + code/__HELPERS/~doppler_helpers/is_helpers.dm | 4 + .../~doppler_globalvars/bitfields.dm | 7 + .../~doppler_globalvars/objective.dm | 2 + .../~doppler_globalvars/religion.dm | 8 + .../subsystem/processing/quirks.dm | 3 + code/game/atom/atom_tool_acts.dm | 10 + code/game/sound.dm | 1 + config/config.txt | 1 + config/doppler/config_doppler.txt | 2 + .../advanced_reskin/code/advanced_reskin.dm | 68 ++ .../code/crafting_extended.dm | 9 + modular_doppler/cryosleep/code/admin.dm | 27 + modular_doppler/cryosleep/code/ai.dm | 20 + modular_doppler/cryosleep/code/config.dm | 2 + .../cryosleep/code/cryo_console_return.dm | 23 + modular_doppler/cryosleep/code/cryopod.dm | 548 +++++++++ modular_doppler/cryosleep/code/job.dm | 19 + modular_doppler/cryosleep/code/jobs.dm | 20 + modular_doppler/cryosleep/code/mind.dm | 2 + modular_doppler/cryosleep/code/mood.dm | 9 + modular_doppler/cryosleep/code/objective.dm | 9 + .../cryosleep/icons/cryogenics.dmi | Bin 0 -> 11831 bytes modular_doppler/cryosleep/readme.md | 23 + modular_doppler/emotes/sound/female_sniff.ogg | Bin 0 -> 8427 bytes .../primitive_catgirls/code/clothing.dm | 180 +++ .../code/clothing_vendor.dm | 53 + .../primitive_catgirls/code/language.dm | 18 + .../primitive_catgirls/code/map_items.dm | 100 ++ .../primitive_catgirls/code/objects.dm | 111 ++ .../primitive_catgirls/code/organs.dm | 71 ++ .../primitive_catgirls/code/pet_commands.dm | 29 + .../primitive_catgirls/code/smelling_salts.dm | 70 ++ .../primitive_catgirls/code/spawner.dm | 317 ++++++ .../primitive_catgirls/code/special_metals.dm | 117 ++ .../primitive_catgirls/code/species.dm | 128 +++ .../primitive_catgirls/code/translator.dm | 73 ++ .../icons/clothing_greyscale.dmi | Bin 0 -> 4011 bytes .../primitive_catgirls/icons/gods_statue.dmi | Bin 0 -> 821 bytes .../icons/language_icon.dmi | Bin 0 -> 417 bytes .../primitive_catgirls/icons/objects.dmi | Bin 0 -> 1445 bytes .../primitive_catgirls/icons/organs.dmi | Bin 0 -> 719 bytes .../primitive_catgirls/icons/salts.dmi | Bin 0 -> 451 bytes .../icons/special_metals_stack.dmi | Bin 0 -> 408 bytes .../primitive_catgirls/icons/translator.dmi | Bin 0 -> 1673 bytes .../icons/translator_worn.dmi | Bin 0 -> 547 bytes .../code/big_mortar.dm | 224 ++++ .../code/cauldron.dm | 339 ++++++ .../code/cookware.dm | 33 + .../code/cutting_board.dm | 146 +++ .../code/millstone.dm | 156 +++ .../code/plant_bag.dm | 69 ++ .../code/stone_griddle.dm | 32 + .../code/stone_oven.dm | 74 ++ .../code/stone_stove.dm | 70 ++ .../icons/cooking_structures.dmi | Bin 0 -> 628 bytes .../icons/cookware.dmi | Bin 0 -> 909 bytes .../icons/millstone.dmi | Bin 0 -> 1847 bytes .../icons/plant_bag.dmi | Bin 0 -> 417 bytes .../icons/plant_bag_worn.dmi | Bin 0 -> 432 bytes .../icons/plant_bag_worn_mirror.dmi | Bin 0 -> 435 bytes .../icons/stone_kitchen_machines.dmi | Bin 0 -> 6428 bytes .../primitive_cooking_additions/readme.md | 23 + .../primitive_production/code/antfarm.dm | 98 ++ .../primitive_production/code/ceramics.dm | 265 +++++ .../primitive_production/code/farming.dm | 296 +++++ .../primitive_production/code/glassblowing.dm | 540 +++++++++ .../primitive_production/code/misc.dm | 35 + .../code/production_skill.dm | 18 + .../primitive_production/code/wormfarm.dm | 139 +++ .../primitive_production/icons/cloaks.dmi | Bin 0 -> 1280 bytes .../primitive_production/icons/misc.dmi | Bin 0 -> 324 bytes .../primitive_production/icons/neck.dmi | Bin 0 -> 1336 bytes .../primitive_production/icons/prim_fun.dmi | Bin 0 -> 4209 bytes .../primitive_production/icons/structures.dmi | Bin 0 -> 2006 bytes .../hearthkin/primitive_production/readme.md | 25 + .../primitive_structures/code/fencing.dm | 109 ++ .../primitive_structures/code/fuelwell.dm | 53 + .../primitive_structures/code/furniture.dm | 73 ++ .../primitive_structures/code/railroad.dm | 161 +++ .../code/storage_structures.dm | 160 +++ .../code/totally_thatch_roof.dm | 68 ++ .../primitive_structures/code/wall_torch.dm | 204 ++++ .../primitive_structures/code/windows.dm | 20 + .../code/wooden_ladder.dm | 7 + .../primitive_structures/icons/lighting.dmi | Bin 0 -> 2170 bytes .../primitive_structures/icons/railroad.dmi | Bin 0 -> 1862 bytes .../primitive_structures/icons/storage.dmi | Bin 0 -> 2845 bytes .../primitive_structures/icons/thatch.dmi | Bin 0 -> 2678 bytes .../primitive_structures/icons/thatch_obj.dmi | Bin 0 -> 643 bytes .../icons/tile_lefthand.dmi | Bin 0 -> 308 bytes .../icons/tile_righthand.dmi | Bin 0 -> 309 bytes .../icons/tribal_beds.dmi | Bin 0 -> 2132 bytes .../primitive_structures/icons/windows.dmi | Bin 0 -> 432 bytes .../icons/wooden_fence.dmi | Bin 0 -> 2057 bytes .../icons/wooden_gate.dmi | Bin 0 -> 1178 bytes .../icons/wooden_ladder.dmi | Bin 0 -> 747 bytes .../hearthkin/primitive_structures/readme.md | 23 + .../indicators/code/combat_indicator.dm | 237 ++++ .../indicators/code/emote_popup.dm | 64 ++ modular_doppler/indicators/code/sealed.dm | 17 + .../indicators/code/ssd_indicator.dm | 38 + .../indicators/icons/DNR_trait_overlay.dmi | Bin 0 -> 264 bytes .../indicators/icons/combat_indicator.dmi | Bin 0 -> 749 bytes .../indicators/icons/emote_indicator.dmi | Bin 0 -> 728 bytes .../indicators/icons/popup_flicks.dmi | Bin 0 -> 520 bytes .../indicators/icons/ssd_indicator.dmi | Bin 0 -> 311 bytes .../icons/temporary_flavor_text_indicator.dmi | Bin 0 -> 279 bytes .../indicators/icons/typing_indicator.dmi | Bin 0 -> 697 bytes modular_doppler/indicators/readme.md | 42 + .../reagents/code/reagents.dm | 4 + .../modular_mob_spawn/code/mob_spawn.dm | 80 ++ modular_doppler/modular_persistence/README.md | 23 + .../code/modular_persistence.dm | 138 +++ modular_doppler/modular_sounds/code/sounds.dm | 16 + .../sound/bricks/attributions.txt | 1 + .../sound/bricks/brick_drop_1.ogg | Bin 0 -> 7163 bytes .../sound/bricks/brick_drop_2.ogg | Bin 0 -> 7918 bytes .../sound/bricks/brick_drop_3.ogg | Bin 0 -> 7994 bytes .../sound/bricks/brick_pick_up_1.ogg | Bin 0 -> 7109 bytes .../sound/bricks/brick_pick_up_2.ogg | Bin 0 -> 7405 bytes .../modular_traits/code/neutral.dm | 22 + modular_doppler/modular_traits/code/organs.dm | 9 + modular_doppler/modular_traits/readme.md | 25 + .../obj_flags_doppler/code/objs.dm | 3 + modular_doppler/reagent_forging/code/anvil.dm | 163 +++ .../reagent_forging/code/centrifuge.dm | 51 + .../reagent_forging/code/crafting_bench.dm | 384 +++++++ .../code/crafting_bench_recipes.dm | 134 +++ modular_doppler/reagent_forging/code/forge.dm | 1008 +++++++++++++++++ .../reagent_forging/code/forge_clothing.dm | 152 +++ .../reagent_forging/code/forge_items.dm | 326 ++++++ .../reagent_forging/code/forge_recipes.dm | 30 + .../reagent_forging/code/forge_weapons.dm | 343 ++++++ .../reagent_forging/code/reagent_component.dm | 117 ++ .../reagent_forging/code/seedmesh.dm | 36 + .../reagent_forging/code/smith_skill.dm | 18 + .../reagent_forging/code/tool_override.dm | 31 + .../reagent_forging/code/water_basin.dm | 110 ++ .../icons/hud/forge_radials.dmi | Bin 0 -> 541 bytes .../icons/mob/clothing/forge_clothing.dmi | Bin 0 -> 1392 bytes .../mob/clothing/forge_clothing_digi.dmi | Bin 0 -> 674 bytes .../mob/clothing/forge_clothing_newvox.dmi | Bin 0 -> 1227 bytes .../mob/clothing/forge_clothing_oldvox.dmi | Bin 0 -> 1272 bytes .../mob/clothing/forge_clothing_teshari.dmi | Bin 0 -> 1332 bytes .../icons/mob/forge_weapon_l.dmi | Bin 0 -> 1934 bytes .../icons/mob/forge_weapon_r.dmi | Bin 0 -> 1889 bytes .../icons/mob/forge_weapon_worn.dmi | Bin 0 -> 5277 bytes .../reagent_forging/icons/mob/neck.dmi | Bin 0 -> 2017 bytes .../reagent_forging/icons/obj/cloaks.dmi | Bin 0 -> 1742 bytes .../icons/obj/forge_clothing.dmi | Bin 0 -> 994 bytes .../reagent_forging/icons/obj/forge_items.dmi | Bin 0 -> 6469 bytes .../icons/obj/forge_structures.dmi | Bin 0 -> 3464 bytes .../reagent_forging/icons/obj/misc_tools.dmi | Bin 0 -> 715 bytes modular_doppler/reagent_forging/readme.md | 30 + .../reagent_forging/sound/forge.ogg | Bin 0 -> 16811 bytes .../reagent_forging/sound/hot_hiss.ogg | Bin 0 -> 15870 bytes modular_doppler/religion/code/chaplain.dm | 21 + .../religion/code/religious_sects.dm | 86 ++ modular_doppler/stone/code/ore_veins.dm | 116 ++ modular_doppler/stone/code/stone.dm | 152 +++ modular_doppler/stone/icons/ore.dmi | Bin 0 -> 12142 bytes modular_doppler/stone/icons/wall.dmi | Bin 0 -> 4110 bytes .../code/ammo/caseless/arrow.dm | 20 + .../code/ammo/reusable/arrow.dm | 63 ++ .../tribal_extended/code/crafting.dm | 25 + .../tribal_extended/code/recipes.dm | 109 ++ .../tribal_extended/code/weapons/bow.dm | 31 + .../tribal_extended/code/weapons/shield.dm | 14 + .../tribal_extended/code/weapons/sword.dm | 23 + .../tribal_extended/icons/ammo.dmi | Bin 0 -> 1129 bytes .../tribal_extended/icons/back.dmi | Bin 0 -> 5675 bytes .../tribal_extended/icons/belt.dmi | Bin 0 -> 439 bytes .../tribal_extended/icons/bows_lefthand.dmi | Bin 0 -> 2923 bytes .../tribal_extended/icons/bows_righthand.dmi | Bin 0 -> 2993 bytes .../tribal_extended/icons/crafting.dmi | Bin 0 -> 391 bytes .../tribal_extended/icons/dice.dmi | Bin 0 -> 507 bytes .../icons/items_and_weapons.dmi | Bin 0 -> 1177 bytes .../tribal_extended/icons/projectile.dmi | Bin 0 -> 1552 bytes .../tribal_extended/icons/shields.dmi | Bin 0 -> 389 bytes .../icons/shields_lefthand.dmi | Bin 0 -> 631 bytes .../icons/shields_righthand.dmi | Bin 0 -> 605 bytes .../tribal_extended/icons/swords_lefthand.dmi | Bin 0 -> 453 bytes .../icons/swords_righthand.dmi | Bin 0 -> 460 bytes .../sound/sound_weapons_bowdraw.ogg | Bin 0 -> 39260 bytes .../sound/sound_weapons_bowfire.ogg | Bin 0 -> 77974 bytes .../code/modules/hydroponics/amauri.dm | 28 + .../code/modules/hydroponics/gelthi.dm | 28 + .../code/modules/hydroponics/jurlmah.dm | 28 + .../code/modules/hydroponics/nofruit.dm | 28 + .../code/modules/hydroponics/shand.dm | 28 + .../code/modules/hydroponics/surik.dm | 28 + .../code/modules/hydroponics/telriis.dm | 29 + .../code/modules/hydroponics/thaadra.dm | 28 + .../xenoarch/code/modules/hydroponics/vale.dm | 28 + .../code/modules/hydroponics/vaporsac.dm | 28 + .../research/xenoarch/designs_and_tech.dm | 239 ++++ .../xenoarch/glassblowing_integration.dm | 18 + .../modules/research/xenoarch/strange_rock.dm | 305 +++++ .../research/xenoarch/xenoarch_item.dm | 255 +++++ .../research/xenoarch/xenoarch_machine.dm | 313 +++++ .../research/xenoarch/xenoarch_reward.dm | 97 ++ .../research/xenoarch/xenoarch_tool.dm | 306 +++++ modular_doppler/xenoarch/icons/growing.dmi | Bin 0 -> 16266 bytes modular_doppler/xenoarch/icons/harvest.dmi | Bin 0 -> 4749 bytes modular_doppler/xenoarch/icons/mining.dmi | Bin 0 -> 48636 bytes .../xenoarch/icons/ore_visuals.dmi | Bin 0 -> 28220 bytes modular_doppler/xenoarch/icons/seeds.dmi | Bin 0 -> 2600 bytes .../xenoarch/icons/smoothrocks.dmi | Bin 0 -> 4092 bytes .../xenoarch/icons/xenoarch_area.dmi | Bin 0 -> 1020 bytes .../xenoarch/icons/xenoarch_items.dmi | Bin 0 -> 11058 bytes .../xenoarch/icons/xenoarch_machines.dmi | Bin 0 -> 1040 bytes modular_doppler/xenoarch/readme.md | 23 + tgstation.dme | 115 ++ 224 files changed, 11853 insertions(+) create mode 100644 code/__DEFINES/~doppler_defines/chemical_flags_doppler.dm create mode 100644 code/__DEFINES/~doppler_defines/keybinds.dm create mode 100644 code/__DEFINES/~doppler_defines/obj_flags_doppler.dm create mode 100644 code/__DEFINES/~doppler_defines/reagent_forging_tools.dm create mode 100644 code/__DEFINES/~doppler_defines/reskin_defines.dm create mode 100644 code/__DEFINES/~doppler_defines/signals.dm create mode 100644 code/__DEFINES/~doppler_defines/sound.dm create mode 100644 code/__DEFINES/~doppler_defines/span.dm create mode 100644 code/__DEFINES/~doppler_defines/techweb_nodes.dm create mode 100644 code/__DEFINES/~doppler_defines/traits.dm create mode 100644 code/__HELPERS/~doppler_helpers/is_helpers.dm create mode 100644 code/_globalvars/~doppler_globalvars/bitfields.dm create mode 100644 code/_globalvars/~doppler_globalvars/objective.dm create mode 100644 code/_globalvars/~doppler_globalvars/religion.dm create mode 100644 config/doppler/config_doppler.txt create mode 100644 modular_doppler/advanced_reskin/code/advanced_reskin.dm create mode 100644 modular_doppler/crafting_extended/code/crafting_extended.dm create mode 100644 modular_doppler/cryosleep/code/admin.dm create mode 100644 modular_doppler/cryosleep/code/ai.dm create mode 100644 modular_doppler/cryosleep/code/config.dm create mode 100644 modular_doppler/cryosleep/code/cryo_console_return.dm create mode 100644 modular_doppler/cryosleep/code/cryopod.dm create mode 100644 modular_doppler/cryosleep/code/job.dm create mode 100644 modular_doppler/cryosleep/code/jobs.dm create mode 100644 modular_doppler/cryosleep/code/mind.dm create mode 100644 modular_doppler/cryosleep/code/mood.dm create mode 100644 modular_doppler/cryosleep/code/objective.dm create mode 100644 modular_doppler/cryosleep/icons/cryogenics.dmi create mode 100644 modular_doppler/cryosleep/readme.md create mode 100644 modular_doppler/emotes/sound/female_sniff.ogg create mode 100644 modular_doppler/hearthkin/primitive_catgirls/code/clothing.dm create mode 100644 modular_doppler/hearthkin/primitive_catgirls/code/clothing_vendor.dm create mode 100644 modular_doppler/hearthkin/primitive_catgirls/code/language.dm create mode 100644 modular_doppler/hearthkin/primitive_catgirls/code/map_items.dm create mode 100644 modular_doppler/hearthkin/primitive_catgirls/code/objects.dm create mode 100644 modular_doppler/hearthkin/primitive_catgirls/code/organs.dm create mode 100644 modular_doppler/hearthkin/primitive_catgirls/code/pet_commands.dm create mode 100644 modular_doppler/hearthkin/primitive_catgirls/code/smelling_salts.dm create mode 100644 modular_doppler/hearthkin/primitive_catgirls/code/spawner.dm create mode 100644 modular_doppler/hearthkin/primitive_catgirls/code/special_metals.dm create mode 100644 modular_doppler/hearthkin/primitive_catgirls/code/species.dm create mode 100644 modular_doppler/hearthkin/primitive_catgirls/code/translator.dm create mode 100644 modular_doppler/hearthkin/primitive_catgirls/icons/clothing_greyscale.dmi create mode 100644 modular_doppler/hearthkin/primitive_catgirls/icons/gods_statue.dmi create mode 100644 modular_doppler/hearthkin/primitive_catgirls/icons/language_icon.dmi create mode 100644 modular_doppler/hearthkin/primitive_catgirls/icons/objects.dmi create mode 100644 modular_doppler/hearthkin/primitive_catgirls/icons/organs.dmi create mode 100644 modular_doppler/hearthkin/primitive_catgirls/icons/salts.dmi create mode 100644 modular_doppler/hearthkin/primitive_catgirls/icons/special_metals_stack.dmi create mode 100644 modular_doppler/hearthkin/primitive_catgirls/icons/translator.dmi create mode 100644 modular_doppler/hearthkin/primitive_catgirls/icons/translator_worn.dmi create mode 100644 modular_doppler/hearthkin/primitive_cooking_additions/code/big_mortar.dm create mode 100644 modular_doppler/hearthkin/primitive_cooking_additions/code/cauldron.dm create mode 100644 modular_doppler/hearthkin/primitive_cooking_additions/code/cookware.dm create mode 100644 modular_doppler/hearthkin/primitive_cooking_additions/code/cutting_board.dm create mode 100644 modular_doppler/hearthkin/primitive_cooking_additions/code/millstone.dm create mode 100644 modular_doppler/hearthkin/primitive_cooking_additions/code/plant_bag.dm create mode 100644 modular_doppler/hearthkin/primitive_cooking_additions/code/stone_griddle.dm create mode 100644 modular_doppler/hearthkin/primitive_cooking_additions/code/stone_oven.dm create mode 100644 modular_doppler/hearthkin/primitive_cooking_additions/code/stone_stove.dm create mode 100644 modular_doppler/hearthkin/primitive_cooking_additions/icons/cooking_structures.dmi create mode 100644 modular_doppler/hearthkin/primitive_cooking_additions/icons/cookware.dmi create mode 100644 modular_doppler/hearthkin/primitive_cooking_additions/icons/millstone.dmi create mode 100644 modular_doppler/hearthkin/primitive_cooking_additions/icons/plant_bag.dmi create mode 100644 modular_doppler/hearthkin/primitive_cooking_additions/icons/plant_bag_worn.dmi create mode 100644 modular_doppler/hearthkin/primitive_cooking_additions/icons/plant_bag_worn_mirror.dmi create mode 100644 modular_doppler/hearthkin/primitive_cooking_additions/icons/stone_kitchen_machines.dmi create mode 100644 modular_doppler/hearthkin/primitive_cooking_additions/readme.md create mode 100644 modular_doppler/hearthkin/primitive_production/code/antfarm.dm create mode 100644 modular_doppler/hearthkin/primitive_production/code/ceramics.dm create mode 100644 modular_doppler/hearthkin/primitive_production/code/farming.dm create mode 100644 modular_doppler/hearthkin/primitive_production/code/glassblowing.dm create mode 100644 modular_doppler/hearthkin/primitive_production/code/misc.dm create mode 100644 modular_doppler/hearthkin/primitive_production/code/production_skill.dm create mode 100644 modular_doppler/hearthkin/primitive_production/code/wormfarm.dm create mode 100644 modular_doppler/hearthkin/primitive_production/icons/cloaks.dmi create mode 100644 modular_doppler/hearthkin/primitive_production/icons/misc.dmi create mode 100644 modular_doppler/hearthkin/primitive_production/icons/neck.dmi create mode 100644 modular_doppler/hearthkin/primitive_production/icons/prim_fun.dmi create mode 100644 modular_doppler/hearthkin/primitive_production/icons/structures.dmi create mode 100644 modular_doppler/hearthkin/primitive_production/readme.md create mode 100644 modular_doppler/hearthkin/primitive_structures/code/fencing.dm create mode 100644 modular_doppler/hearthkin/primitive_structures/code/fuelwell.dm create mode 100644 modular_doppler/hearthkin/primitive_structures/code/furniture.dm create mode 100644 modular_doppler/hearthkin/primitive_structures/code/railroad.dm create mode 100644 modular_doppler/hearthkin/primitive_structures/code/storage_structures.dm create mode 100644 modular_doppler/hearthkin/primitive_structures/code/totally_thatch_roof.dm create mode 100644 modular_doppler/hearthkin/primitive_structures/code/wall_torch.dm create mode 100644 modular_doppler/hearthkin/primitive_structures/code/windows.dm create mode 100644 modular_doppler/hearthkin/primitive_structures/code/wooden_ladder.dm create mode 100644 modular_doppler/hearthkin/primitive_structures/icons/lighting.dmi create mode 100644 modular_doppler/hearthkin/primitive_structures/icons/railroad.dmi create mode 100644 modular_doppler/hearthkin/primitive_structures/icons/storage.dmi create mode 100644 modular_doppler/hearthkin/primitive_structures/icons/thatch.dmi create mode 100644 modular_doppler/hearthkin/primitive_structures/icons/thatch_obj.dmi create mode 100644 modular_doppler/hearthkin/primitive_structures/icons/tile_lefthand.dmi create mode 100644 modular_doppler/hearthkin/primitive_structures/icons/tile_righthand.dmi create mode 100644 modular_doppler/hearthkin/primitive_structures/icons/tribal_beds.dmi create mode 100644 modular_doppler/hearthkin/primitive_structures/icons/windows.dmi create mode 100644 modular_doppler/hearthkin/primitive_structures/icons/wooden_fence.dmi create mode 100644 modular_doppler/hearthkin/primitive_structures/icons/wooden_gate.dmi create mode 100644 modular_doppler/hearthkin/primitive_structures/icons/wooden_ladder.dmi create mode 100644 modular_doppler/hearthkin/primitive_structures/readme.md create mode 100644 modular_doppler/indicators/code/combat_indicator.dm create mode 100644 modular_doppler/indicators/code/emote_popup.dm create mode 100644 modular_doppler/indicators/code/sealed.dm create mode 100644 modular_doppler/indicators/code/ssd_indicator.dm create mode 100644 modular_doppler/indicators/icons/DNR_trait_overlay.dmi create mode 100644 modular_doppler/indicators/icons/combat_indicator.dmi create mode 100644 modular_doppler/indicators/icons/emote_indicator.dmi create mode 100644 modular_doppler/indicators/icons/popup_flicks.dmi create mode 100644 modular_doppler/indicators/icons/ssd_indicator.dmi create mode 100644 modular_doppler/indicators/icons/temporary_flavor_text_indicator.dmi create mode 100644 modular_doppler/indicators/icons/typing_indicator.dmi create mode 100644 modular_doppler/indicators/readme.md create mode 100644 modular_doppler/modular_chemistry/reagents/code/reagents.dm create mode 100644 modular_doppler/modular_mob_spawn/code/mob_spawn.dm create mode 100644 modular_doppler/modular_persistence/README.md create mode 100644 modular_doppler/modular_persistence/code/modular_persistence.dm create mode 100644 modular_doppler/modular_sounds/code/sounds.dm create mode 100644 modular_doppler/modular_sounds/sound/bricks/attributions.txt create mode 100644 modular_doppler/modular_sounds/sound/bricks/brick_drop_1.ogg create mode 100644 modular_doppler/modular_sounds/sound/bricks/brick_drop_2.ogg create mode 100644 modular_doppler/modular_sounds/sound/bricks/brick_drop_3.ogg create mode 100644 modular_doppler/modular_sounds/sound/bricks/brick_pick_up_1.ogg create mode 100644 modular_doppler/modular_sounds/sound/bricks/brick_pick_up_2.ogg create mode 100644 modular_doppler/modular_traits/code/neutral.dm create mode 100644 modular_doppler/modular_traits/code/organs.dm create mode 100644 modular_doppler/modular_traits/readme.md create mode 100644 modular_doppler/obj_flags_doppler/code/objs.dm create mode 100644 modular_doppler/reagent_forging/code/anvil.dm create mode 100644 modular_doppler/reagent_forging/code/centrifuge.dm create mode 100644 modular_doppler/reagent_forging/code/crafting_bench.dm create mode 100644 modular_doppler/reagent_forging/code/crafting_bench_recipes.dm create mode 100644 modular_doppler/reagent_forging/code/forge.dm create mode 100644 modular_doppler/reagent_forging/code/forge_clothing.dm create mode 100644 modular_doppler/reagent_forging/code/forge_items.dm create mode 100644 modular_doppler/reagent_forging/code/forge_recipes.dm create mode 100644 modular_doppler/reagent_forging/code/forge_weapons.dm create mode 100644 modular_doppler/reagent_forging/code/reagent_component.dm create mode 100644 modular_doppler/reagent_forging/code/seedmesh.dm create mode 100644 modular_doppler/reagent_forging/code/smith_skill.dm create mode 100644 modular_doppler/reagent_forging/code/tool_override.dm create mode 100644 modular_doppler/reagent_forging/code/water_basin.dm create mode 100644 modular_doppler/reagent_forging/icons/hud/forge_radials.dmi create mode 100644 modular_doppler/reagent_forging/icons/mob/clothing/forge_clothing.dmi create mode 100644 modular_doppler/reagent_forging/icons/mob/clothing/forge_clothing_digi.dmi create mode 100644 modular_doppler/reagent_forging/icons/mob/clothing/forge_clothing_newvox.dmi create mode 100644 modular_doppler/reagent_forging/icons/mob/clothing/forge_clothing_oldvox.dmi create mode 100644 modular_doppler/reagent_forging/icons/mob/clothing/forge_clothing_teshari.dmi create mode 100644 modular_doppler/reagent_forging/icons/mob/forge_weapon_l.dmi create mode 100644 modular_doppler/reagent_forging/icons/mob/forge_weapon_r.dmi create mode 100644 modular_doppler/reagent_forging/icons/mob/forge_weapon_worn.dmi create mode 100644 modular_doppler/reagent_forging/icons/mob/neck.dmi create mode 100644 modular_doppler/reagent_forging/icons/obj/cloaks.dmi create mode 100644 modular_doppler/reagent_forging/icons/obj/forge_clothing.dmi create mode 100644 modular_doppler/reagent_forging/icons/obj/forge_items.dmi create mode 100644 modular_doppler/reagent_forging/icons/obj/forge_structures.dmi create mode 100644 modular_doppler/reagent_forging/icons/obj/misc_tools.dmi create mode 100644 modular_doppler/reagent_forging/readme.md create mode 100644 modular_doppler/reagent_forging/sound/forge.ogg create mode 100644 modular_doppler/reagent_forging/sound/hot_hiss.ogg create mode 100644 modular_doppler/religion/code/chaplain.dm create mode 100644 modular_doppler/religion/code/religious_sects.dm create mode 100644 modular_doppler/stone/code/ore_veins.dm create mode 100644 modular_doppler/stone/code/stone.dm create mode 100644 modular_doppler/stone/icons/ore.dmi create mode 100644 modular_doppler/stone/icons/wall.dmi create mode 100644 modular_doppler/tribal_extended/code/ammo/caseless/arrow.dm create mode 100644 modular_doppler/tribal_extended/code/ammo/reusable/arrow.dm create mode 100644 modular_doppler/tribal_extended/code/crafting.dm create mode 100644 modular_doppler/tribal_extended/code/recipes.dm create mode 100644 modular_doppler/tribal_extended/code/weapons/bow.dm create mode 100644 modular_doppler/tribal_extended/code/weapons/shield.dm create mode 100644 modular_doppler/tribal_extended/code/weapons/sword.dm create mode 100644 modular_doppler/tribal_extended/icons/ammo.dmi create mode 100644 modular_doppler/tribal_extended/icons/back.dmi create mode 100644 modular_doppler/tribal_extended/icons/belt.dmi create mode 100644 modular_doppler/tribal_extended/icons/bows_lefthand.dmi create mode 100644 modular_doppler/tribal_extended/icons/bows_righthand.dmi create mode 100644 modular_doppler/tribal_extended/icons/crafting.dmi create mode 100644 modular_doppler/tribal_extended/icons/dice.dmi create mode 100644 modular_doppler/tribal_extended/icons/items_and_weapons.dmi create mode 100644 modular_doppler/tribal_extended/icons/projectile.dmi create mode 100644 modular_doppler/tribal_extended/icons/shields.dmi create mode 100644 modular_doppler/tribal_extended/icons/shields_lefthand.dmi create mode 100644 modular_doppler/tribal_extended/icons/shields_righthand.dmi create mode 100644 modular_doppler/tribal_extended/icons/swords_lefthand.dmi create mode 100644 modular_doppler/tribal_extended/icons/swords_righthand.dmi create mode 100644 modular_doppler/tribal_extended/sound/sound_weapons_bowdraw.ogg create mode 100644 modular_doppler/tribal_extended/sound/sound_weapons_bowfire.ogg create mode 100644 modular_doppler/xenoarch/code/modules/hydroponics/amauri.dm create mode 100644 modular_doppler/xenoarch/code/modules/hydroponics/gelthi.dm create mode 100644 modular_doppler/xenoarch/code/modules/hydroponics/jurlmah.dm create mode 100644 modular_doppler/xenoarch/code/modules/hydroponics/nofruit.dm create mode 100644 modular_doppler/xenoarch/code/modules/hydroponics/shand.dm create mode 100644 modular_doppler/xenoarch/code/modules/hydroponics/surik.dm create mode 100644 modular_doppler/xenoarch/code/modules/hydroponics/telriis.dm create mode 100644 modular_doppler/xenoarch/code/modules/hydroponics/thaadra.dm create mode 100644 modular_doppler/xenoarch/code/modules/hydroponics/vale.dm create mode 100644 modular_doppler/xenoarch/code/modules/hydroponics/vaporsac.dm create mode 100644 modular_doppler/xenoarch/code/modules/research/xenoarch/designs_and_tech.dm create mode 100644 modular_doppler/xenoarch/code/modules/research/xenoarch/glassblowing_integration.dm create mode 100644 modular_doppler/xenoarch/code/modules/research/xenoarch/strange_rock.dm create mode 100644 modular_doppler/xenoarch/code/modules/research/xenoarch/xenoarch_item.dm create mode 100644 modular_doppler/xenoarch/code/modules/research/xenoarch/xenoarch_machine.dm create mode 100644 modular_doppler/xenoarch/code/modules/research/xenoarch/xenoarch_reward.dm create mode 100644 modular_doppler/xenoarch/code/modules/research/xenoarch/xenoarch_tool.dm create mode 100644 modular_doppler/xenoarch/icons/growing.dmi create mode 100644 modular_doppler/xenoarch/icons/harvest.dmi create mode 100644 modular_doppler/xenoarch/icons/mining.dmi create mode 100644 modular_doppler/xenoarch/icons/ore_visuals.dmi create mode 100644 modular_doppler/xenoarch/icons/seeds.dmi create mode 100644 modular_doppler/xenoarch/icons/smoothrocks.dmi create mode 100644 modular_doppler/xenoarch/icons/xenoarch_area.dmi create mode 100644 modular_doppler/xenoarch/icons/xenoarch_items.dmi create mode 100644 modular_doppler/xenoarch/icons/xenoarch_machines.dmi create mode 100644 modular_doppler/xenoarch/readme.md diff --git a/code/__DEFINES/icon_smoothing.dm b/code/__DEFINES/icon_smoothing.dm index a853fde0c5dee..af219a90eb1f4 100644 --- a/code/__DEFINES/icon_smoothing.dm +++ b/code/__DEFINES/icon_smoothing.dm @@ -162,6 +162,10 @@ DEFINE_BITFIELD(smoothing_junction, list( #define SMOOTH_GROUP_BAMBOO_WALLS S_TURF(17) //![/turf/closed/wall/mineral/bamboo, /obj/structure/falsewall/bamboo] #define SMOOTH_GROUP_PLASTINUM_WALLS S_TURF(18) //![turf/closed/indestructible/riveted/plastinum] +//DOPPLER EDIT ADDITION +#define SMOOTH_GROUP_STONE_WALLS S_OBJ(20) ///turf/closed/wall/mineral/stone, /obj/structure/falsewall/stone +//DOPPLER EDIT END + #define SMOOTH_GROUP_PAPERFRAME S_OBJ(21) ///obj/structure/window/paperframe, /obj/structure/mineral_door/paperframe #define SMOOTH_GROUP_WINDOW_FULLTILE S_OBJ(22) ///turf/closed/indestructible/fakeglass, /obj/structure/window/fulltile, /obj/structure/window/reinforced/fulltile, /obj/structure/window/reinforced/tinted/fulltile, /obj/structure/window/plasma/fulltile, /obj/structure/window/reinforced/plasma/fulltile diff --git a/code/__DEFINES/~doppler_defines/chemical_flags_doppler.dm b/code/__DEFINES/~doppler_defines/chemical_flags_doppler.dm new file mode 100644 index 0000000000000..981a465137ccb --- /dev/null +++ b/code/__DEFINES/~doppler_defines/chemical_flags_doppler.dm @@ -0,0 +1,2 @@ +/// This reagent is useful for blood regeneration. Useful for Hemophages. +#define REAGENT_BLOOD_REGENERATING (1<<0) diff --git a/code/__DEFINES/~doppler_defines/keybinds.dm b/code/__DEFINES/~doppler_defines/keybinds.dm new file mode 100644 index 0000000000000..cd88e31255d5d --- /dev/null +++ b/code/__DEFINES/~doppler_defines/keybinds.dm @@ -0,0 +1 @@ +#define COMSIG_KB_LIVING_COMBAT_INDICATOR "keybinding_living_combat_indicator" diff --git a/code/__DEFINES/~doppler_defines/obj_flags_doppler.dm b/code/__DEFINES/~doppler_defines/obj_flags_doppler.dm new file mode 100644 index 0000000000000..da544ce37cbc1 --- /dev/null +++ b/code/__DEFINES/~doppler_defines/obj_flags_doppler.dm @@ -0,0 +1,2 @@ +/// Whether something is repairable by the anvil +#define ANVIL_REPAIR (1<<0) diff --git a/code/__DEFINES/~doppler_defines/reagent_forging_tools.dm b/code/__DEFINES/~doppler_defines/reagent_forging_tools.dm new file mode 100644 index 0000000000000..e64be4c609a38 --- /dev/null +++ b/code/__DEFINES/~doppler_defines/reagent_forging_tools.dm @@ -0,0 +1,4 @@ +#define TOOL_BILLOW "billow" +#define TOOL_TONG "tong" +#define TOOL_HAMMER "hammer" +#define TOOL_BLOWROD "blowrod" diff --git a/code/__DEFINES/~doppler_defines/reskin_defines.dm b/code/__DEFINES/~doppler_defines/reskin_defines.dm new file mode 100644 index 0000000000000..035e00b038c53 --- /dev/null +++ b/code/__DEFINES/~doppler_defines/reskin_defines.dm @@ -0,0 +1,8 @@ +#define RESKIN_ICON "reskin_icon" +#define RESKIN_ICON_STATE "reskin_icon_state" +#define RESKIN_WORN_ICON "reskin_worn_icon" +#define RESKIN_WORN_ICON_STATE "reskin_worn_icon_state" +#define RESKIN_SUPPORTS_VARIATIONS_FLAGS "reskin_supports_variations_flags" +#define RESKIN_INHAND_L "reskin_inhand_l" +#define RESKIN_INHAND_R "reskin_inhand_r" +#define RESKIN_INHAND_STATE "reskin_inhand_state" diff --git a/code/__DEFINES/~doppler_defines/signals.dm b/code/__DEFINES/~doppler_defines/signals.dm new file mode 100644 index 0000000000000..9142e6086a8ab --- /dev/null +++ b/code/__DEFINES/~doppler_defines/signals.dm @@ -0,0 +1,2 @@ +///Fired in combat_indicator.dm, used for syncing CI between mech and pilot +#define COMSIG_MOB_CI_TOGGLED "mob_ci_toggled" diff --git a/code/__DEFINES/~doppler_defines/sound.dm b/code/__DEFINES/~doppler_defines/sound.dm new file mode 100644 index 0000000000000..b125bb5460ac7 --- /dev/null +++ b/code/__DEFINES/~doppler_defines/sound.dm @@ -0,0 +1,6 @@ +/** + * Sound effect defines, used in modular_sounds on proc get_sfx. + */ + +#define SFX_BRICK_DROP "brick_drop" +#define SFX_BRICK_PICKUP "brick_pickup" diff --git a/code/__DEFINES/~doppler_defines/span.dm b/code/__DEFINES/~doppler_defines/span.dm new file mode 100644 index 0000000000000..c72af85fd2664 --- /dev/null +++ b/code/__DEFINES/~doppler_defines/span.dm @@ -0,0 +1 @@ +#define span_italics(str) ("" + str + "") diff --git a/code/__DEFINES/~doppler_defines/techweb_nodes.dm b/code/__DEFINES/~doppler_defines/techweb_nodes.dm new file mode 100644 index 0000000000000..3070194171011 --- /dev/null +++ b/code/__DEFINES/~doppler_defines/techweb_nodes.dm @@ -0,0 +1,4 @@ +#define TECHWEB_NODE_XENOARCH_ADVANCED "adv_xenoarch" +#define TECHWEB_NODE_XENOARCH_BASIC "basic_xenoarch" +#define TECHWEB_NODE_XENOARCH_MACHINES "xenoarch_machines" +#define TECHWEB_NODE_XENOARCH_STORAGE "xenoarch_storage" diff --git a/code/__DEFINES/~doppler_defines/traits.dm b/code/__DEFINES/~doppler_defines/traits.dm new file mode 100644 index 0000000000000..2c9804211f5a6 --- /dev/null +++ b/code/__DEFINES/~doppler_defines/traits.dm @@ -0,0 +1,11 @@ +/// trait that lets you do xenoarch magnification +#define TRAIT_XENOARCH_QUALIFIED "trait_xenoarch_qualified" + +/// Traits granted by glassblowing +#define TRAIT_GLASSBLOWING "glassblowing" + +/// Trait that is applied whenever someone or something is glassblowing +#define TRAIT_CURRENTLY_GLASSBLOWING "currently_glassblowing" + +// felinid traits +#define TRAIT_FELINE "feline_aspect" diff --git a/code/__HELPERS/~doppler_helpers/is_helpers.dm b/code/__HELPERS/~doppler_helpers/is_helpers.dm new file mode 100644 index 0000000000000..ec8c01e36274c --- /dev/null +++ b/code/__HELPERS/~doppler_helpers/is_helpers.dm @@ -0,0 +1,4 @@ +//Species +#define isprimitivedemihuman(A) (is_species(A, /datum/species/human/felinid/primitive)) +//Customization bases +#define isfeline(A) (isfelinid(A) || HAS_TRAIT(A, TRAIT_FELINE)) diff --git a/code/_globalvars/~doppler_globalvars/bitfields.dm b/code/_globalvars/~doppler_globalvars/bitfields.dm new file mode 100644 index 0000000000000..eb35bab2e0ce7 --- /dev/null +++ b/code/_globalvars/~doppler_globalvars/bitfields.dm @@ -0,0 +1,7 @@ +DEFINE_BITFIELD(obj_flags_doppler, list( + "ANVIL_REPAIR" = ANVIL_REPAIR, +)) + +DEFINE_BITFIELD(chemical_flags_doppler, list( + "REAGENT_BLOOD_REGENERATING" = REAGENT_BLOOD_REGENERATING, +)) diff --git a/code/_globalvars/~doppler_globalvars/objective.dm b/code/_globalvars/~doppler_globalvars/objective.dm new file mode 100644 index 0000000000000..8658fb496e17e --- /dev/null +++ b/code/_globalvars/~doppler_globalvars/objective.dm @@ -0,0 +1,2 @@ +///new addition to cryosleep module +GLOBAL_LIST_EMPTY(objectives) diff --git a/code/_globalvars/~doppler_globalvars/religion.dm b/code/_globalvars/~doppler_globalvars/religion.dm new file mode 100644 index 0000000000000..b7ac48a69008c --- /dev/null +++ b/code/_globalvars/~doppler_globalvars/religion.dm @@ -0,0 +1,8 @@ +/// list of weakrefs to highpriest successor candidates. Every chaplain who joins after the initial chaplain is added to this list. The next high priest is chosen from them by seniority. +GLOBAL_LIST(holy_successors) +/// A weakref to the current high priest mob +GLOBAL_VAR(current_highpriest) +/// The previous sect's favor value +GLOBAL_VAR(prev_favor) +/// The previous sect's typepath +GLOBAL_VAR(prev_sect_type) diff --git a/code/controllers/subsystem/processing/quirks.dm b/code/controllers/subsystem/processing/quirks.dm index 45354d4bd6164..1f52c6812021f 100644 --- a/code/controllers/subsystem/processing/quirks.dm +++ b/code/controllers/subsystem/processing/quirks.dm @@ -26,6 +26,9 @@ GLOBAL_LIST_INIT_TYPED(quirk_blacklist, /list/datum/quirk, list( list(/datum/quirk/photophobia, /datum/quirk/nyctophobia), list(/datum/quirk/item_quirk/settler, /datum/quirk/freerunning), list(/datum/quirk/numb, /datum/quirk/selfaware), + //DOPPLER EDIT ADDITION BEGIN + list(/datum/quirk/feline_aspect) + //DOPPLER EDIT ADDITION END )) GLOBAL_LIST_INIT(quirk_string_blacklist, generate_quirk_string_blacklist()) diff --git a/code/game/atom/atom_tool_acts.dm b/code/game/atom/atom_tool_acts.dm index 10bed5a407760..301b6fe8ec394 100644 --- a/code/game/atom/atom_tool_acts.dm +++ b/code/game/atom/atom_tool_acts.dm @@ -109,6 +109,16 @@ act_result = is_left_clicking ? welder_act(user, tool) : welder_act_secondary(user, tool) if(TOOL_ANALYZER) act_result = is_left_clicking ? analyzer_act(user, tool) : analyzer_act_secondary(user, tool) + // DOPPLER EDIT ADDITION START - REAGENT FORGING TOOLS + if(TOOL_BILLOW) + act_result = is_left_clicking ? billow_act(user, tool) : billow_act_secondary(user, tool) + if(TOOL_TONG) + act_result = is_left_clicking ? tong_act(user, tool) : tong_act_secondary(user, tool) + if(TOOL_HAMMER) + act_result = is_left_clicking ? hammer_act(user, tool) : hammer_act_secondary(user, tool) + if(TOOL_BLOWROD) + act_result = is_left_clicking ? blowrod_act(user, tool) : blowrod_act_secondary(user, tool) + // DOPPLER EDIT ADDITION END if(!act_result) return NONE diff --git a/code/game/sound.dm b/code/game/sound.dm index 49c716d8e0c56..17e5f6e3e3209 100644 --- a/code/game/sound.dm +++ b/code/game/sound.dm @@ -205,6 +205,7 @@ /proc/get_sfx(soundin) if(!istext(soundin)) return soundin + soundin = get_sfx_doppler(soundin) // DOPPLER EDIT ADDITION - MODULAR SOUNDS switch(soundin) if(SFX_SHATTER) soundin = pick('sound/effects/glassbr1.ogg','sound/effects/glassbr2.ogg','sound/effects/glassbr3.ogg') diff --git a/config/config.txt b/config/config.txt index 6252c3bae659e..d7cd6f5a33df9 100644 --- a/config/config.txt +++ b/config/config.txt @@ -2,6 +2,7 @@ $include game_options.txt $include dbconfig.txt +$include doppler/config_doppler.txt $include comms.txt $include logging.txt $include resources.txt diff --git a/config/doppler/config_doppler.txt b/config/doppler/config_doppler.txt new file mode 100644 index 0000000000000..418749c3311a3 --- /dev/null +++ b/config/doppler/config_doppler.txt @@ -0,0 +1,2 @@ +## Combat indicator, comment out to disable it +COMBAT_INDICATOR diff --git a/modular_doppler/advanced_reskin/code/advanced_reskin.dm b/modular_doppler/advanced_reskin/code/advanced_reskin.dm new file mode 100644 index 0000000000000..6b461839c85f6 --- /dev/null +++ b/modular_doppler/advanced_reskin/code/advanced_reskin.dm @@ -0,0 +1,68 @@ +/obj/item + /// Does this use the advanced reskinning setup? + var/uses_advanced_reskins = FALSE + +/obj/item/reskin_obj(mob/M) + if(!uses_advanced_reskins) + return ..() + if(!LAZYLEN(unique_reskin)) + return + + /// Is the obj a glasses icon with swappable item states? + var/is_swappable = FALSE + // /// if the item are glasses, this variable stores the item. + // var/obj/item/clothing/glasses/reskinned_glasses + + // if(istype(src, /obj/item/clothing/glasses)) // TODO - Remove this mess about glasses, it shouldn't be necessary anymore. + // reskinned_glasses = src + // if(reskinned_glasses.can_switch_eye) + // is_swappable = TRUE + + var/list/items = list() + + + for(var/reskin_option in unique_reskin) + var/image/item_image = image(icon = unique_reskin[reskin_option][RESKIN_ICON] ? unique_reskin[reskin_option][RESKIN_ICON] : icon, icon_state = "[unique_reskin[reskin_option][RESKIN_ICON_STATE]]") + items += list("[reskin_option]" = item_image) + sort_list(items) + + var/pick = show_radial_menu(M, src, items, custom_check = CALLBACK(src, PROC_REF(check_reskin_menu), M), radius = 38, require_near = TRUE) + if(!pick) + return + if(!unique_reskin[pick]) + return + current_skin = pick + + if(unique_reskin[pick][RESKIN_ICON]) + icon = unique_reskin[pick][RESKIN_ICON] + + if(unique_reskin[pick][RESKIN_ICON_STATE]) + if(is_swappable) + base_icon_state = unique_reskin[pick][RESKIN_ICON_STATE] + icon_state = base_icon_state + else + icon_state = unique_reskin[pick][RESKIN_ICON_STATE] + + if(unique_reskin[pick][RESKIN_WORN_ICON]) + worn_icon = unique_reskin[pick][RESKIN_WORN_ICON] + + if(unique_reskin[pick][RESKIN_WORN_ICON_STATE]) + worn_icon_state = unique_reskin[pick][RESKIN_WORN_ICON_STATE] + + if(unique_reskin[pick][RESKIN_INHAND_L]) + lefthand_file = unique_reskin[pick][RESKIN_INHAND_L] + if(unique_reskin[pick][RESKIN_INHAND_R]) + righthand_file = unique_reskin[pick][RESKIN_INHAND_R] + if(unique_reskin[pick][RESKIN_INHAND_STATE]) + inhand_icon_state = unique_reskin[pick][RESKIN_INHAND_STATE] + if(unique_reskin[pick][RESKIN_SUPPORTS_VARIATIONS_FLAGS]) + supports_variations_flags = unique_reskin[pick][RESKIN_SUPPORTS_VARIATIONS_FLAGS] + if(ishuman(M)) + var/mob/living/carbon/human/wearer = M + wearer.regenerate_icons() // update that mf + to_chat(M, "[src] is now skinned as '[pick].'") + post_reskin(M) + +/// Automatically called after a reskin, for any extra variable changes. +/obj/item/proc/post_reskin(mob/our_mob) + return diff --git a/modular_doppler/crafting_extended/code/crafting_extended.dm b/modular_doppler/crafting_extended/code/crafting_extended.dm new file mode 100644 index 0000000000000..f8abb76282073 --- /dev/null +++ b/modular_doppler/crafting_extended/code/crafting_extended.dm @@ -0,0 +1,9 @@ +/** + * The opposite of proc/teach_crafting_recipe + * will attempt to remove the arg "recipe" from the learned recipes + */ +/datum/mind/proc/unteach_crafting_recipe(recipe) + if(!learned_recipes) + return + + learned_recipes &= ~recipe diff --git a/modular_doppler/cryosleep/code/admin.dm b/modular_doppler/cryosleep/code/admin.dm new file mode 100644 index 0000000000000..4b6ce389eee24 --- /dev/null +++ b/modular_doppler/cryosleep/code/admin.dm @@ -0,0 +1,27 @@ +/// Send player in not-quiet cryopod. If with_paper = TRUE, place a paper with notification under player. +/mob/proc/send_to_cryo(with_paper = FALSE) + //effect + playsound(loc, 'sound/magic/Repulse.ogg', 100, 1) + var/datum/effect_system/spark_spread/quantum/sparks = new + sparks.set_up(10, 1, loc) + sparks.attach(loc) + sparks.start() + + //make a paper if need + if(with_paper) + var/obj/item/paper/cryo_paper = new /obj/item/paper(loc) + cryo_paper.name = "Notification - [name]" + cryo_paper.add_raw_text("Our sincerest apologies, [name][job ? ", [job]," : ""] had to be sent back in Cryogenic Storage for reasons that cannot be elaborated on at the moment.

Sincerely,
Nanotrasen Anti-Sudden Sleep Disorder Agency") + cryo_paper.update_appearance() + //find cryopod + for(var/obj/machinery/cryopod/cryo in GLOB.valid_cryopods) + if(!cryo.occupant && cryo.state_open && !cryo.panel_open) //free, opened, and panel closed? + if(buckled) + buckled.unbuckle_mob(src, TRUE) + if(buckled_mobs) + for(var/mob/buckled_mob in buckled_mobs) + unbuckle_mob(buckled_mob) + cryo.close_machine(src) //put player + break + + diff --git a/modular_doppler/cryosleep/code/ai.dm b/modular_doppler/cryosleep/code/ai.dm new file mode 100644 index 0000000000000..5397311dc2f89 --- /dev/null +++ b/modular_doppler/cryosleep/code/ai.dm @@ -0,0 +1,20 @@ +/mob/living/silicon/ai/verb/ai_cryo() + set name = "AI Cryogenic Stasis" + set desc = "Puts the current AI personality into cryogenic stasis, freeing the space for another." + set category = "AI Commands" + + if(incapacitated()) + return + switch(alert("Would you like to enter cryo? This will ghost you. Remember to AHELP before cryoing out of important roles, even with no admins online.",,"Yes.","No.")) + if("Yes.") + src.ghostize(FALSE) + minor_announce("Station AI has disconnected from system networks and moved to remote storage. Preparing for new AI personality upload.", "Station AI") + new /obj/structure/ai_core/latejoin_inactive(loc) + if(src.mind) + //Handle job slot/tater cleanup. + if(src.mind.assigned_role.title == JOB_AI) + SSjob.FreeRole(JOB_AI) + src.mind.special_role = null + qdel(src) + else + return diff --git a/modular_doppler/cryosleep/code/config.dm b/modular_doppler/cryosleep/code/config.dm new file mode 100644 index 0000000000000..c3d9565771b32 --- /dev/null +++ b/modular_doppler/cryosleep/code/config.dm @@ -0,0 +1,2 @@ +/datum/config_entry/number/cryo_min_ssd_time + config_entry_value = 15 diff --git a/modular_doppler/cryosleep/code/cryo_console_return.dm b/modular_doppler/cryosleep/code/cryo_console_return.dm new file mode 100644 index 0000000000000..4da60b9ad1876 --- /dev/null +++ b/modular_doppler/cryosleep/code/cryo_console_return.dm @@ -0,0 +1,23 @@ +/// Returns any items inside of the `items_to_send` list to a cryo console on station. +/mob/living/carbon/human/proc/return_items_to_console(list/items_to_send) + var/list/held_contents = get_contents() + if(!held_contents || !items_to_send) + return FALSE + + var/obj/machinery/computer/cryopod/target_console + for(var/obj/machinery/computer/cryopod/cryo_console in GLOB.cryopod_computers) + target_console = cryo_console + var/turf/target_turf = get_turf(target_console) + if(is_station_level(target_turf.z)) //If we find a cryo console on station, send items to it first and foremost. + break + + if(!target_console) + return FALSE + + for(var/obj/item/found_item in held_contents) + if(!is_type_in_list(found_item, items_to_send)) + continue + transferItemToLoc(found_item, target_console, force = TRUE, silent = TRUE) + target_console.frozen_item += found_item + + return TRUE diff --git a/modular_doppler/cryosleep/code/cryopod.dm b/modular_doppler/cryosleep/code/cryopod.dm new file mode 100644 index 0000000000000..110e762c822e4 --- /dev/null +++ b/modular_doppler/cryosleep/code/cryopod.dm @@ -0,0 +1,548 @@ +#define AHELP_FIRST_MESSAGE "Please adminhelp before leaving the round, even if there are no administrators online!" + +/* + * Cryogenic refrigeration unit. Basically a despawner. + * Stealing a lot of concepts/code from sleepers due to massive laziness. + * The despawn tick will only fire if it's been more than time_till_despawned ticks + * since time_entered, which is world.time when the occupant moves in. + * ~ Zuhayr + */ +GLOBAL_LIST_EMPTY(cryopod_computers) + +GLOBAL_LIST_EMPTY(ghost_records) + +/// A list of all cryopods that aren't quiet, to be used by the "Send to Cryogenic Storage" VV action. +GLOBAL_LIST_EMPTY(valid_cryopods) + +//Main cryopod console. + +/obj/machinery/computer/cryopod + name = "cryogenic oversight console" + desc = "An interface between crew and the cryogenic storage oversight systems." + icon = 'modular_doppler/cryosleep/icons/cryogenics.dmi' + icon_state = "cellconsole_1" + icon_keyboard = null + icon_screen = null + use_power = FALSE + density = FALSE + interaction_flags_machine = INTERACT_MACHINE_OFFLINE + req_one_access = list(ACCESS_COMMAND, ACCESS_ARMORY) // Heads of staff or the warden can go here to claim recover items from their department that people went were cryodormed with. + verb_say = "coldly states" + verb_ask = "queries" + verb_exclaim = "alarms" + + /// Used for logging people entering cryosleep and important items they are carrying. + var/list/frozen_crew = list() + /// The items currently stored in the cryopod control panel. + var/list/frozen_item = list() + + /// This is what the announcement system uses to make announcements. Make sure to set a radio that has the channel you want to broadcast on. + var/obj/item/radio/headset/radio = /obj/item/radio/headset/silicon/ai + /// The channel to be broadcast on, valid values are the values of any of the "RADIO_CHANNEL_" defines. + var/announcement_channel = null // RADIO_CHANNEL_COMMON doesn't work here. + +MAPPING_DIRECTIONAL_HELPERS(/obj/machinery/computer/cryopod, 32) + +/obj/machinery/computer/cryopod/Initialize(mapload) + . = ..() + GLOB.cryopod_computers += src + radio = new radio(src) + +/obj/machinery/computer/cryopod/Destroy() + GLOB.cryopod_computers -= src + QDEL_NULL(radio) + return ..() + +/obj/machinery/computer/cryopod/update_icon_state() + if(machine_stat & (NOPOWER|BROKEN)) + icon_state = "cellconsole" + return ..() + icon_state = "cellconsole_1" + return ..() + +/obj/machinery/computer/cryopod/ui_interact(mob/user, datum/tgui/ui) + . = ..() + if(machine_stat & (NOPOWER|BROKEN)) + return + + add_fingerprint(user) + + ui = SStgui.try_update_ui(user, src, ui) + if(!ui) + ui = new(user, src, "CryopodConsole", name) + ui.open() + +/obj/machinery/computer/cryopod/ui_data(mob/user) + var/list/data = list() + data["frozen_crew"] = frozen_crew + + /// The list of references to the stored items. + var/list/item_ref_list = list() + /// The associative list of the reference to an item and its name. + var/list/item_ref_name = list() + + for(var/obj/item/item in frozen_item) + var/ref = REF(item) + item_ref_list += ref + item_ref_name[ref] = item.name + + data["item_ref_list"] = item_ref_list + data["item_ref_name"] = item_ref_name + + // Check Access for item dropping. + var/item_retrieval_allowed = allowed(user) + data["item_retrieval_allowed"] = item_retrieval_allowed + + var/obj/item/card/id/id_card + if(isliving(user)) + var/mob/living/person = user + id_card = person.get_idcard() + if(id_card?.registered_name) + data["account_name"] = id_card.registered_name + + return data + +/obj/machinery/computer/cryopod/ui_act(action, list/params, datum/tgui/ui, datum/ui_state/state) + . = ..() + if(.) + return + switch(action) + if("item_get") + // This is using references, kinda clever, not gonna lie. Good work Zephyr + var/item_get = params["item_get"] + var/obj/item/item = locate(item_get) + if(item in frozen_item) + item.forceMove(drop_location()) + frozen_item.Remove(item_get, item) + visible_message("[src] dispenses \the [item].") + message_admins("[item] was retrieved from cryostorage at [ADMIN_COORDJMP(src)]") + else + CRASH("Invalid REF# for ui_act. Not inside internal list!") + return TRUE + + else + CRASH("Illegal action for ui_act: '[action]'") + +/obj/machinery/computer/cryopod/proc/announce(message_type, user, rank, occupant_departments_bitflags, occupant_job_radio) + switch(message_type) + if("CRYO_JOIN") + radio.talk_into(src, "[user][rank ? ", [rank]" : ""] has woken up from cryo storage.", announcement_channel) + if("CRYO_LEAVE") + if (occupant_job_radio) + if (occupant_departments_bitflags & DEPARTMENT_BITFLAG_COMMAND) + if (occupant_job_radio != RADIO_CHANNEL_COMMAND) + radio.talk_into(src, "[user][rank ? ", [rank]" : ""] has been moved to cryo storage.", RADIO_CHANNEL_COMMAND) + radio.use_command = TRUE + radio.talk_into(src, "[user][rank ? ", [rank]" : ""] has been moved to cryo storage.", occupant_job_radio) + radio.use_command = FALSE + radio.talk_into(src, "[user][rank ? ", [rank]" : ""] has been moved to cryo storage.", announcement_channel) + +// Cryopods themselves. +/obj/machinery/cryopod + name = "cryogenic freezer" + desc = "Suited for Cyborgs and Humanoids, the pod is a safe place for personnel affected by the Space Sleep Disorder to get some rest." + icon = 'modular_doppler/cryosleep/icons/cryogenics.dmi' + icon_state = "cryopod-open" + base_icon_state = "cryopod" + use_power = FALSE + density = TRUE + anchored = TRUE + state_open = TRUE + interaction_flags_mouse_drop = NEED_DEXTERITY + + var/open_icon_state = "cryopod-open" + /// Whether the cryopod respects the minimum time someone has to be disconnected before they can be put into cryo by another player + var/allow_timer_override = FALSE + /// Minimum time for someone to be SSD before another player can cryo them. + var/ssd_time = 30 MINUTES //Replace with "cryo_min_ssd_time" CONFIG + + /// Time until despawn when a mob enters a cryopod. You cannot other people in pods unless they're catatonic. + var/time_till_despawn = 30 SECONDS + /// Cooldown for when it's now safe to try an despawn the player. + COOLDOWN_DECLARE(despawn_world_time) + + ///Weakref to our controller + var/datum/weakref/control_computer_weakref + COOLDOWN_DECLARE(last_no_computer_message) + /// if false, plays announcement on cryo + var/quiet = FALSE + /// Has the occupant been tucked in? + var/tucked = FALSE + +/obj/machinery/cryopod/quiet + quiet = TRUE + +/obj/machinery/cryopod/Initialize(mapload) + ..() + if(!quiet) + GLOB.valid_cryopods += src + return INITIALIZE_HINT_LATELOAD //Gotta populate the cryopod computer GLOB first + +/obj/machinery/cryopod/post_machine_initialize() + . = ..() + update_icon() + find_control_computer() + +// This is not a good situation +/obj/machinery/cryopod/Destroy() + GLOB.valid_cryopods -= src + control_computer_weakref = null + return ..() + +/obj/machinery/cryopod/proc/find_control_computer(urgent = FALSE) + for(var/cryo_console as anything in GLOB.cryopod_computers) + var/obj/machinery/computer/cryopod/console = cryo_console + if(get_area(console) == get_area(src)) + control_computer_weakref = WEAKREF(console) + break + + // Don't send messages unless we *need* the computer, and less than five minutes have passed since last time we messaged + if(!control_computer_weakref && urgent && COOLDOWN_FINISHED(src, last_no_computer_message)) + COOLDOWN_START(src, last_no_computer_message, 5 MINUTES) + log_admin("Cryopod in [get_area(src)] could not find control computer!") + message_admins("Cryopod in [get_area(src)] could not find control computer!") + last_no_computer_message = world.time + + return control_computer_weakref != null + +/obj/machinery/cryopod/close_machine(atom/movable/target, density_to_set = TRUE) + if(!control_computer_weakref) + find_control_computer(TRUE) + if((isnull(target) || isliving(target)) && state_open && !panel_open) + ..(target) + var/mob/living/mob_occupant = occupant + if(mob_occupant && mob_occupant.stat != DEAD) + to_chat(occupant, span_notice("You feel cool air surround you. You go numb as your senses turn inward.")) + + var/mob/living/carbon/human/human_occupant = occupant + if(istype(human_occupant) && human_occupant.mind) + human_occupant.save_individual_persistence(mob_occupant.ckey || mob_occupant.mind?.key) + + COOLDOWN_START(src, despawn_world_time, time_till_despawn) + +/obj/machinery/cryopod/open_machine(drop = TRUE, density_to_set = FALSE) + ..() + set_density(TRUE) + name = initial(name) + tucked = FALSE + +/obj/machinery/cryopod/container_resist_act(mob/living/user) + visible_message(span_notice("[occupant] emerges from [src]!"), + span_notice("You climb out of [src]!")) + open_machine() + +/obj/machinery/cryopod/relaymove(mob/user) + container_resist_act(user) + +/obj/machinery/cryopod/process() + if(!occupant) + return + + var/mob/living/mob_occupant = occupant + if(mob_occupant.stat == DEAD) + open_machine() + + if(!mob_occupant.client && COOLDOWN_FINISHED(src, despawn_world_time)) + if(!control_computer_weakref) + find_control_computer(urgent = TRUE) + + despawn_occupant() + +/obj/machinery/cryopod/proc/handle_objectives() + var/mob/living/mob_occupant = occupant + // Update any existing objectives involving this mob. + for(var/datum/objective/objective in GLOB.objectives) + // We don't want revs to get objectives that aren't for heads of staff. Letting + // them win or lose based on cryo is silly so we remove the objective. + if(istype(objective,/datum/objective/mutiny) && objective.target == mob_occupant.mind) + objective.team.objectives -= objective + qdel(objective) + for(var/datum/mind/mind in objective.team.members) + to_chat(mind.current, "
[span_userdanger("Your target is no longer within reach. Objective removed!")]") + mind.announce_objectives() + else if(istype(objective.target) && objective.target == mob_occupant.mind) + if(!istype(objective, /datum/objective/contract)) + return + // var/datum/opposing_force/affected_contractor = objective.owner.opposing_force + // var/datum/contractor_hub/affected_contractor_hub = affected_contractor.contractor_hub + // for(var/datum/syndicate_contract/affected_contract as anything in affected_contractor_hub.assigned_contracts) + // if(!(affected_contract.contract == objective)) + // continue + // var/contract_id = affected_contract.id + // affected_contractor_hub.create_single_contract(objective.owner, affected_contract.payout_type) + // affected_contractor_hub.assigned_contracts[contract_id].status = CONTRACT_STATUS_ABORTED + // if (affected_contractor_hub.current_contract == objective) + // affected_contractor_hub.current_contract = null + // to_chat(objective.owner.current, "
[span_userdanger("Contract target out of reach. Contract rerolled.")]") + // break + else if(istype(objective.target) && objective.target == mob_occupant.mind) + var/old_target = objective.target + objective.target = null + if(!objective) + return + objective.find_target() + if(!objective.target && objective.owner) + to_chat(objective.owner.current, "
[span_userdanger("Your target is no longer within reach. Objective removed!")]") + for(var/datum/antagonist/antag in objective.owner.antag_datums) + antag.objectives -= objective + if (!objective.team) + objective.update_explanation_text() + objective.owner.announce_objectives() + to_chat(objective.owner.current, "
[span_userdanger("You get the feeling your target is no longer within reach. Time for Plan [pick("A","B","C","D","X","Y","Z")]. Objectives updated!")]") + else + var/list/objectivestoupdate + for(var/datum/mind/objective_owner in objective.get_owners()) + to_chat(objective_owner.current, "
[span_userdanger("You get the feeling your target is no longer within reach. Time for Plan [pick("A","B","C","D","X","Y","Z")]. Objectives updated!")]") + for(var/datum/objective/update_target_objective in objective_owner.get_all_objectives()) + LAZYADD(objectivestoupdate, update_target_objective) + objectivestoupdate += objective.team.objectives + for(var/datum/objective/update_objective in objectivestoupdate) + if(update_objective.target != old_target || !istype(update_objective,objective.type)) + continue + update_objective.target = objective.target + update_objective.update_explanation_text() + to_chat(objective.owner.current, "
[span_userdanger("You get the feeling your target is no longer within reach. Time for Plan [pick("A","B","C","D","X","Y","Z")]. Objectives updated!")]") + update_objective.owner.announce_objectives() + qdel(objective) + +/// This function can not be undone; do not call this unless you are sure. +/// Handles despawning the player. +/obj/machinery/cryopod/proc/despawn_occupant() + var/mob/living/mob_occupant = occupant + + var/occupant_ckey = mob_occupant.ckey || mob_occupant.mind?.key + var/occupant_name = mob_occupant.name + var/occupant_rank = mob_occupant.mind?.assigned_role.title + var/occupant_departments_bitflags = mob_occupant.mind?.assigned_role.departments_bitflags + var/occupant_job_radio = mob_occupant.mind?.assigned_role.default_radio_channel + + SSjob.FreeRole(occupant_rank) + + // Handle holy successor removal + var/list/holy_successors = list_holy_successors() + if(mob_occupant in holy_successors) // if this mob was a holy successor then remove them from the pool + GLOB.holy_successors -= WEAKREF(mob_occupant) + + if(mob_occupant.mind) + // Handle tater cleanup. + if(LAZYLEN(mob_occupant.mind.objectives)) + mob_occupant.mind.objectives.Cut() + mob_occupant.mind.special_role = null + // Handle freeing the high priest role for the next chaplain in line + if(mob_occupant.mind.holy_role == HOLY_ROLE_HIGHPRIEST) + reset_religion() + else + // handle the case of the high priest no longer having a mind + var/datum/weakref/current_highpriest = GLOB.current_highpriest + if(current_highpriest?.resolve() == mob_occupant) + reset_religion() + + // Delete them from datacore and ghost records. + var/announce_rank = null + + for(var/list/record in GLOB.ghost_records) + if(record["name"] == occupant_name) + announce_rank = record["rank"] + GLOB.ghost_records.Remove(list(record)) + break + + if(!announce_rank) // No need to loop over all of those if we already found it beforehand. + for(var/datum/record/crew/possible_target_record as anything in GLOB.manifest.general) + if(possible_target_record.name == occupant_name && (occupant_rank == "N/A" || possible_target_record.trim == occupant_rank)) + announce_rank = possible_target_record.rank + qdel(possible_target_record) + break + + var/obj/machinery/computer/cryopod/control_computer = control_computer_weakref?.resolve() + if(!control_computer) + control_computer_weakref = null + else + control_computer.frozen_crew += list(list("name" = occupant_name, "job" = occupant_rank)) + + // Make an announcement and log the person entering storage. If set to quiet, does not make an announcement. + if(!quiet) + control_computer.announce("CRYO_LEAVE", mob_occupant.real_name, announce_rank, occupant_departments_bitflags, occupant_job_radio) + + visible_message(span_notice("[src] hums and hisses as it moves [mob_occupant.real_name] into storage.")) + + for(var/obj/item/item_content as anything in mob_occupant) + if(!istype(item_content) || HAS_TRAIT(item_content, TRAIT_NODROP)) + continue + if (issilicon(mob_occupant) && istype(item_content, /obj/item/mmi)) + continue + if(control_computer) + if(istype(item_content, /obj/item/modular_computer)) + var/obj/item/modular_computer/computer = item_content + for(var/datum/computer_file/program/messenger/message_app in computer.stored_files) + message_app.invisible = TRUE + mob_occupant.transferItemToLoc(item_content, control_computer, force = TRUE, silent = TRUE) + item_content.dropped(mob_occupant) + control_computer.frozen_item += item_content + else + mob_occupant.transferItemToLoc(item_content, drop_location(), force = TRUE, silent = TRUE) + + GLOB.joined_player_list -= occupant_ckey + + handle_objectives() + mob_occupant.ghostize() + QDEL_NULL(occupant) + open_machine() + name = initial(name) + +/obj/machinery/cryopod/mouse_drop_receive(mob/living/target, mob/user, params) + if(!istype(target) || !ismob(target) || isanimal(target) || !istype(user.loc, /turf) || target.buckled) + return + + if(occupant) + to_chat(user, span_notice("[src] is already occupied!")) + return + + if(target.stat == DEAD) + to_chat(user, span_notice("Dead people can not be put into cryo.")) + return + +// Allows admins to enable players to override SSD Time check. + if(allow_timer_override) + if(tgui_alert(user, "Would you like to place [target] into [src]?", "Place into Cryopod?", list("Yes", "No")) != "No") + to_chat(user, span_danger("You put [target] into [src]. [target.p_Theyre()] in the cryopod.")) + log_admin("[key_name(user)] has put [key_name(target)] into a overridden stasis pod.") + message_admins("[key_name(user)] has put [key_name(target)] into a overridden stasis pod. [ADMIN_JMP(src)]") + + add_fingerprint(target) + + close_machine(target) + name = "[name] ([target.name])" + +// Allows players to cryo others. Checks if they have been AFK for 30 minutes. + if(target.key && user != target) + if (target.get_organ_by_type(/obj/item/organ/internal/brain) ) //Target the Brain + if(!target.mind || target.ssd_indicator ) // Is the character empty / AI Controlled + if(target.lastclienttime + ssd_time >= world.time) + to_chat(user, span_notice("You can't put [target] into [src] for another [round(((ssd_time - (world.time - target.lastclienttime)) / (1 MINUTES)), 1)] minutes.")) + log_admin("[key_name(user)] has attempted to put [key_name(target)] into a stasis pod, but they were only disconnected for [round(((world.time - target.lastclienttime) / (1 MINUTES)), 1)] minutes.") + message_admins("[key_name(user)] has attempted to put [key_name(target)] into a stasis pod. [ADMIN_JMP(src)]") + return + else if(tgui_alert(user, "Would you like to place [target] into [src]?", "Place into Cryopod?", list("Yes", "No")) == "Yes") + if(target.mind.assigned_role.req_admin_notify) + tgui_alert(user, "They are an important role! [AHELP_FIRST_MESSAGE]") + to_chat(user, span_danger("You put [target] into [src]. [target.p_Theyre()] in the cryopod.")) + log_admin("[key_name(user)] has put [key_name(target)] into a stasis pod.") + message_admins("[key_name(user)] has put [key_name(target)] into a stasis pod. [ADMIN_JMP(src)]") + + add_fingerprint(target) + + close_machine(target) + name = "[name] ([target.name])" + + else if(iscyborg(target)) + to_chat(user, span_danger("You can't put [target] into [src]. [target.p_Theyre()] online.")) + else + to_chat(user, span_danger("You can't put [target] into [src]. [target.p_Theyre()] conscious.")) + return + + if(target == user && (tgui_alert(target, "Would you like to enter cryosleep?", "Enter Cryopod?", list("Yes", "No")) != "Yes")) + return + + if(target == user) + if(target.mind.assigned_role.req_admin_notify) + tgui_alert(target, "You're an important role! [AHELP_FIRST_MESSAGE]") + var/datum/antagonist/antag = target.mind.has_antag_datum(/datum/antagonist) + if(antag) + tgui_alert(target, "You're \a [antag.name]! [AHELP_FIRST_MESSAGE]") + + if(LAZYLEN(target.buckled_mobs) > 0) + if(target == user) + to_chat(user, span_danger("You can't fit into the cryopod while someone is buckled to you.")) + else + to_chat(user, span_danger("You can't fit [target] into the cryopod while someone is buckled to them.")) + return + + if(!istype(target) || !can_interact(user) || !target.Adjacent(user) || !ismob(target) || isanimal(target) || !istype(user.loc, /turf) || target.buckled) + return + // rerun the checks in case of shenanigans + + if(occupant) + to_chat(user, span_notice("[src] is already occupied!")) + return + + if(target == user) + visible_message(span_infoplain("[user] starts climbing into the cryo pod.")) + else + visible_message(span_infoplain("[user] starts putting [target] into the cryo pod.")) + + to_chat(target, span_warning("If you ghost, log out or close your client now, your character will shortly be permanently removed from the round.")) + + log_admin("[key_name(target)] entered a stasis pod.") + message_admins("[key_name_admin(target)] entered a stasis pod. [ADMIN_JMP(src)]") + add_fingerprint(target) + + close_machine(target) + name = "[name] ([target.name])" + +// Attacks/effects. +/obj/machinery/cryopod/blob_act() + return // Sorta gamey, but we don't really want these to be destroyed. + +/obj/machinery/cryopod/attackby(obj/item/weapon, mob/living/carbon/human/user, params) + . = ..() + if(istype(weapon, /obj/item/bedsheet)) + if(!occupant || !istype(occupant, /mob/living)) + return + if(tucked) + to_chat(user, span_warning("[occupant.name] already looks pretty comfortable!")) + return + to_chat(user, span_notice("You tuck [occupant.name] into their pod!")) + qdel(weapon) + user.add_mood_event("tucked", /datum/mood_event/tucked_in, occupant) + tucked = TRUE + +/obj/machinery/cryopod/update_icon_state() + icon_state = state_open ? open_icon_state : base_icon_state + return ..() + +/// Special wall mounted cryopod for the prison, making it easier to autospawn. +/obj/machinery/cryopod/prison + icon_state = "prisonpod" + base_icon_state = "prisonpod" + open_icon_state = "prisonpod" + density = FALSE + +MAPPING_DIRECTIONAL_HELPERS(/obj/machinery/cryopod/prison, 18) + +/obj/machinery/cryopod/prison/set_density(new_value) + // Simple way to make it always non-dense. + return ..(FALSE) + +/obj/machinery/cryopod/prison/close_machine(atom/movable/target, density_to_set = TRUE) + . = ..() + // Flick the pod for a second when user enters + flick("prisonpod-open", src) + +// Wake-up notifications + +/obj/effect/mob_spawn/ghost_role + /// For figuring out where the local cryopod computer is. Must be set for cryo computer announcements. + var/area/computer_area + +/obj/effect/mob_spawn/ghost_role/create(mob/mob_possessor, newname) + var/mob/living/spawned_mob = ..() + var/obj/machinery/computer/cryopod/control_computer = find_control_computer() + + GLOB.ghost_records.Add(list(list("name" = spawned_mob.real_name, "rank" = name))) + if(control_computer) + control_computer.announce("CRYO_JOIN", spawned_mob.real_name, name) + + return spawned_mob + +/obj/effect/mob_spawn/ghost_role/proc/find_control_computer() + if(!computer_area) + return + for(var/cryo_console as anything in GLOB.cryopod_computers) + var/obj/machinery/computer/cryopod/console = cryo_console + var/area/area = get_area(cryo_console) // Define moment + if(area.type == computer_area) + return console + + return + +#undef AHELP_FIRST_MESSAGE diff --git a/modular_doppler/cryosleep/code/job.dm b/modular_doppler/cryosleep/code/job.dm new file mode 100644 index 0000000000000..fcd218d473918 --- /dev/null +++ b/modular_doppler/cryosleep/code/job.dm @@ -0,0 +1,19 @@ +/datum/controller/subsystem/job/proc/FreeRole(rank) + if(!rank) + return + JobDebug("Freeing role: [rank]") + var/datum/job/job = GetJob(rank) + if(!job) + return FALSE + job.current_positions = max(0, job.current_positions - 1) + +/// Used for clocking back in, re-claiming the previously freed role. Returns false if no slot is available. +/datum/controller/subsystem/job/proc/OccupyRole(rank) + if(!rank) + return FALSE + JobDebug("Occupying role: [rank]") + var/datum/job/job = GetJob(rank) + if(!job || job.current_positions >= job.total_positions) + return FALSE + job.current_positions = job.current_positions + 1 + return TRUE diff --git a/modular_doppler/cryosleep/code/jobs.dm b/modular_doppler/cryosleep/code/jobs.dm new file mode 100644 index 0000000000000..0d225d934f3ca --- /dev/null +++ b/modular_doppler/cryosleep/code/jobs.dm @@ -0,0 +1,20 @@ +/datum/job + var/default_radio_channel = null +/datum/job/chief_medical_officer + default_radio_channel = RADIO_CHANNEL_MEDICAL +/datum/job/chief_engineer + default_radio_channel = RADIO_CHANNEL_ENGINEERING +/datum/job/head_of_security + default_radio_channel = RADIO_CHANNEL_SECURITY +/datum/job/head_of_personnel + default_radio_channel = RADIO_CHANNEL_SERVICE +/datum/job/research_director + default_radio_channel = RADIO_CHANNEL_SCIENCE +/datum/job/quartermaster + default_radio_channel = RADIO_CHANNEL_SUPPLY +/datum/job/captain + default_radio_channel = RADIO_CHANNEL_COMMAND +/datum/job/blueshield + default_radio_channel = RADIO_CHANNEL_COMMAND +/datum/job/nanotrasen_consultant + default_radio_channel = RADIO_CHANNEL_COMMAND diff --git a/modular_doppler/cryosleep/code/mind.dm b/modular_doppler/cryosleep/code/mind.dm new file mode 100644 index 0000000000000..c71983ae4845d --- /dev/null +++ b/modular_doppler/cryosleep/code/mind.dm @@ -0,0 +1,2 @@ +/datum/mind + var/list/datum/objective/objectives = list() diff --git a/modular_doppler/cryosleep/code/mood.dm b/modular_doppler/cryosleep/code/mood.dm new file mode 100644 index 0000000000000..a64cfaf19c5d3 --- /dev/null +++ b/modular_doppler/cryosleep/code/mood.dm @@ -0,0 +1,9 @@ +/datum/mood_event/tucked_in + description = "I feel better having tucked someone in for a good night's rest!" + mood_change = 3 + timeout = 2 MINUTES + +/datum/mood_event/tucked_in/add_effects(mob/tuckee) + if(!tuckee) + return + description = "I feel better having tucked in [tuckee.name] for a good night's rest!" diff --git a/modular_doppler/cryosleep/code/objective.dm b/modular_doppler/cryosleep/code/objective.dm new file mode 100644 index 0000000000000..b279c7e21bd8e --- /dev/null +++ b/modular_doppler/cryosleep/code/objective.dm @@ -0,0 +1,9 @@ +//Redefining objective New and Destroy to avoid editing TG original files. + +/datum/objective/New(text) + GLOB.objectives += src + ..() + +/datum/objective/Destroy() + GLOB.objectives -= src + return ..() diff --git a/modular_doppler/cryosleep/icons/cryogenics.dmi b/modular_doppler/cryosleep/icons/cryogenics.dmi new file mode 100644 index 0000000000000000000000000000000000000000..9b7ff616aafd74b647ed8abe55d5fbb533a263fb GIT binary patch literal 11831 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 Ck7V)y literal 0 HcmV?d00001 diff --git a/modular_doppler/cryosleep/readme.md b/modular_doppler/cryosleep/readme.md new file mode 100644 index 0000000000000..35ee69f313b4b --- /dev/null +++ b/modular_doppler/cryosleep/readme.md @@ -0,0 +1,23 @@ +## Title: Cryosleep + +MODULE ID: CRYOSLEEP + +### Description: + +Adds in a green sleeper-like cryosleep machine, to allow people who wish to stop playing the game to exit with an IC way. + +### TG Proc Changes: + + - ADDITION: /code/game/machinery/announcement_system.dm > /obj/machinery/announcement_system/proc/announce() + +### Defines: + +N/A + +### Included files: + +N/A + +### Credits: + +Azarak - Porting/refactoring diff --git a/modular_doppler/emotes/sound/female_sniff.ogg b/modular_doppler/emotes/sound/female_sniff.ogg new file mode 100644 index 0000000000000000000000000000000000000000..6f4ce34b0b8941d233c3d8c07aceb3425558cda3 GIT binary patch literal 8427 zcmch6dsLcNy7vo$0wDwy3|dV9QGuWpl@zV%0A2!k2_RT7+JksW)HEY1nI_YA5rT?D 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 N=wO1c=AZ}ke*s;Y#zp`D literal 0 HcmV?d00001 diff --git a/modular_doppler/hearthkin/primitive_catgirls/code/clothing.dm b/modular_doppler/hearthkin/primitive_catgirls/code/clothing.dm new file mode 100644 index 0000000000000..54e99cc5f9888 --- /dev/null +++ b/modular_doppler/hearthkin/primitive_catgirls/code/clothing.dm @@ -0,0 +1,180 @@ +// The naming of every path in this file is going to be awful :smiling_imp: + +// Outfit Datum + +/datum/outfit/primitive_catgirl + name = "Icemoon Dweller" + + uniform = /obj/item/clothing/under/dress/skirt/primitive_catgirl_body_wraps + shoes = /obj/item/clothing/shoes/winterboots/ice_boots/primitive_catgirl_boots + gloves = /obj/item/clothing/gloves/fingerless/primitive_catgirl_armwraps + suit = /obj/item/clothing/suit/jacket/primitive_catgirl_coat + neck = /obj/item/clothing/neck/scarf/primitive_catgirl_scarf + + back = /obj/item/forging/reagent_weapon/axe/fake_copper + +// Under + +/obj/item/clothing/under/dress/skirt/primitive_catgirl_body_wraps + name = "body wraps" + desc = "Some pretty simple wraps to cover up your lower bits." + icon_state = "wraps" + icon = 'modular_doppler/hearthkin/primitive_catgirls/icons/clothing_greyscale.dmi' + worn_icon = 'modular_doppler/hearthkin/primitive_catgirls/icons/clothing_greyscale.dmi' + body_parts_covered = GROIN + // greyscale_config = /datum/greyscale_config/primitive_catgirl_wraps + // greyscale_config_worn = /datum/greyscale_config/primitive_catgirl_wraps/worn + greyscale_colors = "#cec8bf#364660" + flags_1 = IS_PLAYER_COLORABLE_1 + has_sensor = FALSE + +/obj/item/clothing/under/dress/skirt/primitive_catgirl_tailored_dress + name = "tailored dress" + desc = "A handmade dress, tailored to fit perfectly to its wearer's body measurements." + icon_state = "tailored_dress" + icon = 'modular_doppler/hearthkin/primitive_catgirls/icons/clothing_greyscale.dmi' + worn_icon = 'modular_doppler/hearthkin/primitive_catgirls/icons/clothing_greyscale.dmi' + body_parts_covered = GROIN|CHEST + // greyscale_config = /datum/greyscale_config/primitive_catgirl_tailored_dress + // greyscale_config_worn = /datum/greyscale_config/primitive_catgirl_tailored_dress/worn + greyscale_colors = "#cec8bf#364660" + flags_1 = IS_PLAYER_COLORABLE_1 + has_sensor = FALSE + +/obj/item/clothing/under/dress/skirt/primitive_catgirl_tunic + name = "handmade tunic" + desc = "A simple garment that reaches from the shoulders to above the knee. This one has a belt to secure it." + icon_state = "tunic" + icon = 'modular_doppler/hearthkin/primitive_catgirls/icons/clothing_greyscale.dmi' + worn_icon = 'modular_doppler/hearthkin/primitive_catgirls/icons/clothing_greyscale.dmi' + body_parts_covered = GROIN|CHEST + // greyscale_config = /datum/greyscale_config/primitive_catgirl_tunic + // greyscale_config_worn = /datum/greyscale_config/primitive_catgirl_tunic/worn + greyscale_colors = "#cec8bf#faece4#594032" + flags_1 = IS_PLAYER_COLORABLE_1 + has_sensor = FALSE + +// Hands + +/obj/item/clothing/gloves/fingerless/primitive_catgirl_armwraps + name = "arm wraps" + desc = "Simple cloth to wrap around one's arms." + icon_state = "armwraps" + icon = 'modular_doppler/hearthkin/primitive_catgirls/icons/clothing_greyscale.dmi' + worn_icon = 'modular_doppler/hearthkin/primitive_catgirls/icons/clothing_greyscale.dmi' + // greyscale_config = /datum/greyscale_config/primitive_catgirl_armwraps + // greyscale_config_worn = /datum/greyscale_config/primitive_catgirl_armwraps/worn + greyscale_colors = "#cec8bf" + flags_1 = IS_PLAYER_COLORABLE_1 + +/obj/item/clothing/gloves/fingerless/primitive_catgirl_gauntlets + name = "gauntlets" + desc = "Simple cloth arm wraps with overlying metal protection." + icon_state = "gauntlets" + icon = 'modular_doppler/hearthkin/primitive_catgirls/icons/clothing_greyscale.dmi' + worn_icon = 'modular_doppler/hearthkin/primitive_catgirls/icons/clothing_greyscale.dmi' + // greyscale_config = /datum/greyscale_config/primitive_catgirl_gauntlets + // greyscale_config_worn = /datum/greyscale_config/primitive_catgirl_gauntlets/worn + greyscale_config_inhand_left = null + greyscale_config_inhand_right = null + greyscale_colors = "#cec8bf#c55a1d" + flags_1 = IS_PLAYER_COLORABLE_1 + +// Suit + +/obj/item/clothing/suit/jacket/primitive_catgirl_coat + name = "primitive fur coat" + desc = "A large piece of animal hide stuffed with fur, likely from the same animal." + icon_state = "coat" + icon = 'modular_doppler/hearthkin/primitive_catgirls/icons/clothing_greyscale.dmi' + worn_icon = 'modular_doppler/hearthkin/primitive_catgirls/icons/clothing_greyscale.dmi' + body_parts_covered = CHEST + cold_protection = CHEST + min_cold_protection_temperature = FIRE_SUIT_MIN_TEMP_PROTECT + supports_variations_flags = CLOTHING_DIGITIGRADE_VARIATION_NO_NEW_ICON + // greyscale_config = /datum/greyscale_config/primitive_catgirl_coat + // greyscale_config_worn = /datum/greyscale_config/primitive_catgirl_coat/worn + greyscale_colors = "#594032#cec8bf" + flags_1 = IS_PLAYER_COLORABLE_1 + +/obj/item/clothing/suit/apron/chef/colorable_apron/primitive_catgirl_leather + greyscale_colors = "#594032" + +// Shoes + +/obj/item/clothing/shoes/winterboots/ice_boots/primitive_catgirl_boots + name = "primitive hiking boots" + desc = "A pair of heavy boots lined with fur and with soles special built to prevent slipping on ice." + icon_state = "boots" + icon = 'modular_doppler/hearthkin/primitive_catgirls/icons/clothing_greyscale.dmi' + worn_icon = 'modular_doppler/hearthkin/primitive_catgirls/icons/clothing_greyscale.dmi' + // greyscale_config = /datum/greyscale_config/primitive_catgirl_boots + // greyscale_config_worn = /datum/greyscale_config/primitive_catgirl_boots/worn + greyscale_colors = "#594032#cec8bf" + flags_1 = IS_PLAYER_COLORABLE_1 + +// Neck + +/obj/item/clothing/neck/scarf/primitive_catgirl_scarf + greyscale_colors = "#cec8bf#cec8bf" + +/obj/item/clothing/neck/large_scarf/primitive_catgirl_off_white + greyscale_colors = "#cec8bf#cec8bf" + +/obj/item/clothing/neck/infinity_scarf/primitive_catgirl_blue + greyscale_colors = "#364660" + +/obj/item/clothing/neck/mantle/recolorable/primitive_catgirl_off_white + greyscale_colors = "#cec8bf" + +/obj/item/clothing/neck/ranger_poncho/primitive_catgirl_leather + greyscale_colors = "#594032#594032" + +// Masks + +/obj/item/clothing/mask/neck_gaiter/primitive_catgirl_gaiter + greyscale_colors = "#364660" + +// Head + +/obj/item/clothing/head/standalone_hood/primitive_catgirl_colors + greyscale_colors = "#594032#364660" + +/obj/item/clothing/head/primitive_catgirl_ferroniere + name = "Ferroniere" + desc = "A style of headband that encircles the wearer's forehead, with a small jewel suspended in the centre." + icon_state = "ferroniere" + icon = 'modular_doppler/hearthkin/primitive_catgirls/icons/clothing_greyscale.dmi' + worn_icon = 'modular_doppler/hearthkin/primitive_catgirls/icons/clothing_greyscale.dmi' + // greyscale_config = /datum/greyscale_config/primitive_catgirl_ferroniere + // greyscale_config_worn = /datum/greyscale_config/primitive_catgirl_ferroniere/worn + greyscale_colors = "#f1f6ff#364660" + w_class = WEIGHT_CLASS_TINY + flags_1 = IS_PLAYER_COLORABLE_1 + +// Misc Items + +/obj/item/forging/reagent_weapon/axe/fake_copper + custom_materials = list(/datum/material/copporcitite = SHEET_MATERIAL_AMOUNT) + +/obj/item/clothing/suit/armor/forging_plate_armor/hearthkin + name = "handcrafted hearthkin armor" + desc = "An armor obviously crafted by the expertise of a hearthkin. It has leather shoulder pads and a chain mail underneath." + icon_state = "chained_leather_armor" + icon = 'modular_doppler/hearthkin/primitive_catgirls/icons/objects.dmi' + worn_icon = 'modular_doppler/hearthkin/primitive_catgirls/icons/clothing_greyscale.dmi' + body_parts_covered = GROIN|CHEST + +/datum/crafting_recipe/handcrafted_hearthkin_armor + name = "Handcrafted Hearthkin Armor" + category = CAT_CLOTHING + + //recipe given to icecats as part of their spawner/team setting + crafting_flags = CRAFT_CHECK_DENSITY | CRAFT_MUST_BE_LEARNED + + reqs = list( + /obj/item/forging/complete/chain = 4, + /obj/item/stack/sheet/leather = 2, + ) + + result = /obj/item/clothing/suit/armor/forging_plate_armor/hearthkin diff --git a/modular_doppler/hearthkin/primitive_catgirls/code/clothing_vendor.dm b/modular_doppler/hearthkin/primitive_catgirls/code/clothing_vendor.dm new file mode 100644 index 0000000000000..57d11862f9e1a --- /dev/null +++ b/modular_doppler/hearthkin/primitive_catgirls/code/clothing_vendor.dm @@ -0,0 +1,53 @@ +/obj/machinery/vending/primitive_catgirl_clothing_vendor + name = "wardrobe" + desc = "It's a big wardrobe filled up with all sorts of clothing." + icon = 'icons/obj/storage/closet.dmi' + icon_state = "cabinet" + + use_power = FALSE + + shut_up = TRUE + vend_reply = null + + products = list( + /obj/item/clothing/under/dress/skirt/primitive_catgirl_body_wraps = 15, + /obj/item/clothing/under/dress/skirt/primitive_catgirl_tailored_dress = 15, + /obj/item/clothing/under/dress/skirt/primitive_catgirl_tunic = 15, + // /obj/item/clothing/under/dress/skirt/nova/loincloth = 5, + // /obj/item/clothing/under/dress/skirt/nova/loincloth/loincloth_alt = 5, + /obj/item/clothing/suit/jacket/primitive_catgirl_coat = 15, + /obj/item/clothing/gloves/fingerless/primitive_catgirl_armwraps = 15, + /obj/item/clothing/shoes/winterboots/ice_boots/primitive_catgirl_boots = 15, + /obj/item/clothing/gloves/fingerless/primitive_catgirl_gauntlets = 10, + /obj/item/clothing/mask/neck_gaiter/primitive_catgirl_gaiter = 10, + /obj/item/clothing/suit/apron/chef/colorable_apron/primitive_catgirl_leather = 10, + /obj/item/clothing/head/standalone_hood/primitive_catgirl_colors = 10, + /obj/item/clothing/neck/scarf/primitive_catgirl_scarf = 5, + // /obj/item/clothing/neck/face_scarf = 5, + /obj/item/clothing/neck/large_scarf/primitive_catgirl_off_white = 5, + /obj/item/clothing/neck/infinity_scarf/primitive_catgirl_blue = 5, + /obj/item/clothing/neck/mantle/recolorable/primitive_catgirl_off_white = 5, + /obj/item/clothing/neck/ranger_poncho/primitive_catgirl_leather = 5, + // /obj/item/clothing/neck/wide_cape = 5, + // /obj/item/clothing/neck/robe_cape = 5, + // /obj/item/clothing/neck/long_cape = 5, + // /obj/item/clothing/glasses/eyepatch/wrap = 5, + /obj/item/clothing/head/primitive_catgirl_ferroniere = 5, + // /obj/item/clothing/head/pelt/snow_tiger = 5, + // /obj/item/clothing/head/pelt = 5, + // /obj/item/clothing/head/pelt/black = 5, + // /obj/item/clothing/head/pelt/white = 5, + // /obj/item/clothing/head/pelt/wolf = 5, + // /obj/item/clothing/head/pelt/wolf/white = 5, + // /obj/item/clothing/head/costume/nova/papakha = 5, + // /obj/item/clothing/head/costume/nova/papakha/white = 5, + // /obj/item/clothing/head/hair_tie = 5, + ) + +/obj/machinery/vending/primitive_catgirl_clothing_vendor/Initialize(mapload) + . = ..() + + onstation = FALSE + +/obj/machinery/vending/primitive_catgirl_clothing_vendor/speak(message) + return diff --git a/modular_doppler/hearthkin/primitive_catgirls/code/language.dm b/modular_doppler/hearthkin/primitive_catgirls/code/language.dm new file mode 100644 index 0000000000000..2d5ae205c967a --- /dev/null +++ b/modular_doppler/hearthkin/primitive_catgirls/code/language.dm @@ -0,0 +1,18 @@ +/datum/language/primitive_catgirl + name = "Ættmál" + desc = "A liturgical language passed through three centuries of Hearthkin culture, the only tongue which their literature is allowed to be spoken in; \ + especially relating to their pagan practices. While Siik'Tajr is used as a trade language with outsiders, Ættmál remains sacred and mostly unknown \ + to those outside the Hearth." + key = "H" + flags = TONGUELESS_SPEECH + space_chance = 70 + syllables = list ( + "al", "an", "ar", "að", "eg", "en", "er", "ha", "he", "il", "in", "ir", "ið", "ki", "le", "na", "nd", "ng", "nn", "og", "ra", "ri", + "se", "st", "ta", "ur", "ði", "va", "ve", "sem", "sta", "til", "tur", "var", "ver", "við", "ður", "það", "þei", "með", "ega", "ann", + "tur", "egr", "eda", "eva", "ada", "the", "tre", "tai", "thor", "thur", "ohd", "din", "gim", "per", "ger", "héð", "bur", "kóp", "vog", + "bar", "dar", "akur", "jer", "bær", "múl", "fjörð", "jah", "dah", "dim", "din", "dir", "dur", "nya", "miau", "mjau", "ný", "kt", "hø", + ) + icon_state = "omgkittyhiii" + icon = 'modular_doppler/hearthkin/primitive_catgirls/icons/language_icon.dmi' + default_priority = 94 + // secret = TRUE //this needs a dedicated module for language diff --git a/modular_doppler/hearthkin/primitive_catgirls/code/map_items.dm b/modular_doppler/hearthkin/primitive_catgirls/code/map_items.dm new file mode 100644 index 0000000000000..c1b383741fe9c --- /dev/null +++ b/modular_doppler/hearthkin/primitive_catgirls/code/map_items.dm @@ -0,0 +1,100 @@ +// Bonfires but with a grill pre-attached + +/obj/structure/bonfire/grill_pre_attached + +/obj/structure/bonfire/grill_pre_attached/Initialize(mapload) + . = ..() + + grill = TRUE + add_overlay("bonfire_grill") + +// Dirt but icebox and also farmable + +/turf/open/misc/dirt/icemoon + baseturfs = /turf/open/openspace/icemoon + initial_gas_mix = "ICEMOON_ATMOS" + +/turf/open/misc/dirt/icemoon/Initialize(mapload) + . = ..() + AddComponent(/datum/component/simple_farm, set_plant = TRUE) + +// Water that can be fished out of + +/turf/open/water/hot_spring + desc = "Water kept warm through some unknown heat source, possibly a geothermal heat source far underground. \ + Whatever it is, it feels pretty damn nice to swim in given the rest of the environment around here, and you \ + can even catch a glimpse of the odd fish darting through the water." + baseturfs = /turf/open/openspace/icemoon + initial_gas_mix = "ICEMOON_ATMOS" + /// Holder for the steam particles that show up sometimes + var/obj/effect/abstract/particle_holder/particle_effect + +/turf/open/water/hot_spring/Initialize(mapload) + . = ..() + AddElement(/datum/element/lazy_fishing_spot, /datum/fish_source/icecat_hot_spring) + if(prob(60)) + particle_effect = new(src, /particles/hotspring_steam) + +/turf/open/water/hot_spring/Destroy() + QDEL_NULL(particle_effect) + return ..() + +/turf/open/water/hot_spring/Entered(atom/movable/arrived) + ..() + wash_atom(arrived) + wash_atom(loc) + +/// Cleans the given atom of whatever dirties it +/turf/open/water/hot_spring/proc/wash_atom(atom/nasty) + nasty.wash(CLEAN_WASH) + +/turf/open/water/hot_spring/Entered(atom/movable/arrived) + ..() + if(istype(arrived, /mob/living)) + hotspring_mood(arrived) + +/// Applies the hot water mood buff on the passed mob +/turf/open/water/hot_spring/proc/hotspring_mood(mob/living/swimmer) + swimmer.add_mood_event("hotspring", /datum/mood_event/hotspring/nerfed) + +/datum/mood_event/hotspring/nerfed + description = span_nicegreen("The water was enjoyably warm!\n") + mood_change = 2 + +// Steam particles for pairing with the hotsprings above + +/particles/hotspring_steam + icon = 'icons/effects/particles/smoke.dmi' + icon_state = list( + "steam_1" = 2, + "steam_2" = 2, + "steam_3" = 1, + ) + width = 64 + height = 64 + count = 5 + spawning = 0.2 + lifespan = 1 SECONDS + fade = 0.5 SECONDS + color = "#ffffff" + position = generator(GEN_BOX, list(-32,-32,0), list(32,32,0), NORMAL_RAND) + scale = generator(GEN_VECTOR, list(0.9,0.9), list(1.1,1.1), NORMAL_RAND) + drift = generator(GEN_VECTOR, list(-0.1,0), list(0.1,0.025), UNIFORM_RAND) + spin = generator(GEN_NUM, list(-15,15), NORMAL_RAND) + +// Fishing source for the above water turfs + +/datum/fish_source/icecat_hot_spring + fish_table = list( + /obj/item/fish/dwarf_moonfish = 5, + /obj/item/fish/needlefish = 10, + /obj/item/fish/armorfish = 10, + /obj/item/fish/chasm_crab/ice = 5, + /obj/item/stack/sheet/bone = 5, + ) + catalog_description = "Hot Springs" + +// The area + +/area/ruin/unpowered/primitive_catgirl_den + name = "\improper Icewalker Camp" diff --git a/modular_doppler/hearthkin/primitive_catgirls/code/objects.dm b/modular_doppler/hearthkin/primitive_catgirls/code/objects.dm new file mode 100644 index 0000000000000..f1c7b430b780d --- /dev/null +++ b/modular_doppler/hearthkin/primitive_catgirls/code/objects.dm @@ -0,0 +1,111 @@ +/obj/item/anointing_oil + name = "anointing bloodresin" + desc = "And so Helgar Knife-Arm spoke to the Hearth, and decreed that all of the Kin who gave name to beasts would do so with conquest and blood." + icon = 'modular_doppler/hearthkin/primitive_catgirls/icons/objects.dmi' + icon_state = "anointingbloodresin" + throwforce = 0 + w_class = WEIGHT_CLASS_TINY + + var/being_used = FALSE + +/obj/item/anointing_oil/attack(mob/living/target_mob, mob/living/user, params) + if (!is_species(user, /datum/species/human/felinid/primitive)) + to_chat(user, span_warning("You have no idea what this disgusting concoction is used for.")) + return + if(being_used || !ismob(target_mob)) //originally this was going to check if the mob was friendly, but if an icecat wants to name some terror mob while it's tearing chunks out of them, why not? + return + if(target_mob.ckey) + to_chat(user, span_warning("You would never shame a creature so intelligent by not allowing it to choose its own name.")) + return + + if(try_anoint(target_mob, user)) + qdel(src) + else + being_used = FALSE + +/obj/item/anointing_oil/proc/try_anoint(mob/living/target_mob, mob/living/user) + being_used = TRUE + + var/new_name = sanitize_name(tgui_input_text(user, "Speak forth this beast's new name for all the Kin to hear.", "Input a name", target_mob.name, MAX_NAME_LEN)) + + if(!new_name || QDELETED(src) || QDELETED(target_mob) || new_name == target_mob.name || !target_mob.Adjacent(user)) + being_used = FALSE + return FALSE + + target_mob.visible_message(span_notice("[user] leans down and smears twinned streaks of glistening bloodresin upon [target_mob], then straightens up with ritual purpose...")) + user.say("Let the ice know you forevermore as +[new_name]+.") + + user.log_message("used [src] on [target_mob], renaming it to [new_name].", LOG_GAME) + + target_mob.name = new_name + + //give the stupid dog zoomies from getting named + if(istype(target_mob, /mob/living/basic/mining/wolf)) + target_mob.emote("awoo") + target_mob.emote("spin") + + return TRUE + +/obj/item/anointing_oil/examine(mob/user) + . = ..() + if(is_species(user, /datum/species/human/felinid/primitive)) + . += span_info("Using this on the local wildlife will allow you to give them a name.") + +/datum/crafting_recipe/anointing_oil + name = "Anointing Bloodresin" + category = CAT_MISC + //recipe given to icecats as part of their spawner/team setting + crafting_flags = CRAFT_CHECK_DENSITY | CRAFT_MUST_BE_LEARNED + + reqs = list( + /datum/reagent/consumable/liquidgibs = 20, + /datum/reagent/blood = 20, + ) + + result = /obj/item/anointing_oil + +// Hearthkin exclusive object to make their special lungs. +/obj/item/frozen_breath + name = "Frozen Breath" + desc = "A strange brew, it smells minty and is extremely cold to the touch. It is rumored that a cold-hearted witch managed to make this, to mend the breath of her kindred." + icon = 'modular_doppler/hearthkin/primitive_catgirls/icons/objects.dmi' + icon_state = "frozenbreath" + throwforce = 0 + w_class = WEIGHT_CLASS_TINY + +/obj/item/frozen_breath/interact_with_atom(atom/interacting_with, mob/living/user, list/modifiers) + if (!is_species(user, /datum/species/human/felinid/primitive)) + to_chat(user, span_warning("You have no idea how to use this freezing concoction.")) + return + + if(istype(interacting_with, /obj/item/organ/internal/lungs)) + var/obj/item/organ/internal/lungs/target_lungs = interacting_with + if(IS_ROBOTIC_ORGAN(target_lungs)) + user.balloon_alert(user, "The lungs have to be organic!") + return + var/location = get_turf(target_lungs) + playsound(location, 'sound/effects/slosh.ogg', 25, TRUE) + user.visible_message(span_notice("[user] pours a strange blue liquid over the set of lungs. The flesh starts glistening in a strange cyan light, transforming before your very eyes!"), + span_notice("Recalling the instructions for the lung transfiguration ritual, you pour the liquid over the flesh of the organ. Soon, the lungs glow in a mute cyan light, before they turn dim and change form before your very eyes!")) + var/obj/item/organ/internal/lungs/icebox_adapted/new_lungs = new(location) + new_lungs.damage = target_lungs.damage + qdel(target_lungs) + qdel(src) + +/obj/item/frozen_breath/examine(mob/user) + . = ..() + if(is_species(user, /datum/species/human/felinid/primitive)) + . += span_info("Using this on a pair of organic lungs transforms them into hardy lungs. This will remove any other special features from the old lungs, if there were any.") + +/datum/crafting_recipe/frozen_breath + name = "Frozen Breath" + category = CAT_MISC + //recipe given to icecats as part of their spawner/team setting + crafting_flags = CRAFT_CHECK_DENSITY | CRAFT_MUST_BE_LEARNED + + reqs = list( + /datum/reagent/consumable/frostoil = 50, + /datum/reagent/medicine/c2/synthflesh = 50, + ) + + result = /obj/item/frozen_breath diff --git a/modular_doppler/hearthkin/primitive_catgirls/code/organs.dm b/modular_doppler/hearthkin/primitive_catgirls/code/organs.dm new file mode 100644 index 0000000000000..acc10d2153c63 --- /dev/null +++ b/modular_doppler/hearthkin/primitive_catgirls/code/organs.dm @@ -0,0 +1,71 @@ +#define GAS_TOLERANCE 5 + +// Lungs + +/obj/item/organ/internal/lungs/icebox_adapted + name = "hardy lungs" + desc = "Lungs adapted to frozen environments that would be otherwise inhospitable to most races. Feels cold." + icon_state = "hardylungs" + icon = 'modular_doppler/hearthkin/primitive_catgirls/icons/organs.dmi' + +/obj/item/organ/internal/lungs/icebox_adapted/Initialize(mapload) + . = ..() + + var/datum/gas_mixture/immutable/planetary/mix = SSair.planetary[ICEMOON_DEFAULT_ATMOS] + + if(!mix?.total_moles()) // If there is no icemoon atmos then we have problems, return now + return + + // Take a "breath" of the air + var/datum/gas_mixture/breath = mix.remove(mix.total_moles() * BREATH_PERCENTAGE) + + var/list/breath_gases = breath.gases + + breath.assert_gases( + /datum/gas/oxygen, + /datum/gas/plasma, + /datum/gas/carbon_dioxide, + /datum/gas/nitrogen, + /datum/gas/bz, + /datum/gas/miasma, + ) + + var/oxygen_pp = breath.get_breath_partial_pressure(breath_gases[/datum/gas/oxygen][MOLES]) + var/nitrogen_pp = breath.get_breath_partial_pressure(breath_gases[/datum/gas/nitrogen][MOLES]) + var/plasma_pp = breath.get_breath_partial_pressure(breath_gases[/datum/gas/plasma][MOLES]) + var/carbon_dioxide_pp = breath.get_breath_partial_pressure(breath_gases[/datum/gas/carbon_dioxide][MOLES]) + var/bz_pp = breath.get_breath_partial_pressure(breath_gases[/datum/gas/bz][MOLES]) + var/miasma_pp = breath.get_breath_partial_pressure(breath_gases[/datum/gas/miasma][MOLES]) + + safe_oxygen_min = max(0, oxygen_pp - GAS_TOLERANCE) + safe_nitro_min = max(0, nitrogen_pp - GAS_TOLERANCE) + safe_plasma_min = max(0, plasma_pp - GAS_TOLERANCE) + + // Increase plasma tolerance based on amount in base air + safe_plasma_max += plasma_pp + + // CO2 is always a waste gas, so none is required, but ashwalkers + // tolerate the base amount plus tolerance*2 (humans tolerate only 10 pp) + + safe_co2_max = carbon_dioxide_pp + GAS_TOLERANCE * 2 + + // The lung tolerance against BZ is also increased the amount of BZ in the base air + BZ_trip_balls_min += bz_pp + BZ_brain_damage_min += bz_pp + + // Lungs adapted to a high miasma atmosphere do not process it, and breathe it back out + if(miasma_pp) + suffers_miasma = FALSE + +// Eyes + +/obj/item/organ/internal/eyes/low_light_adapted + color_cutoffs = list(30, 15, 15) + + +// Tongue +/obj/item/organ/internal/tongue/cat/primitive + liked_foodtypes = SEAFOOD | MEAT | GORE + + +#undef GAS_TOLERANCE diff --git a/modular_doppler/hearthkin/primitive_catgirls/code/pet_commands.dm b/modular_doppler/hearthkin/primitive_catgirls/code/pet_commands.dm new file mode 100644 index 0000000000000..35f0c0573b43e --- /dev/null +++ b/modular_doppler/hearthkin/primitive_catgirls/code/pet_commands.dm @@ -0,0 +1,29 @@ +/datum/component/obeys_commands/RegisterWithParent() + . = ..() + RegisterSignal(parent, COMSIG_ATOM_EXAMINE_MORE, PROC_REF(on_examine_more)) + +/datum/component/obeys_commands/UnregisterFromParent() + . = ..() + UnregisterSignal(parent, COMSIG_ATOM_EXAMINE_MORE) + +/datum/component/obeys_commands/on_examine(mob/living/source, mob/user, list/examine_list) + . = ..() + examine_list += span_italics("You can alt+click [source.p_them()] when adjacent to see available commands.") + examine_list += span_italics("You can also examine [source.p_them()] closely to check on [source.p_their()] wounds. Many companions can be healed with sutures or creams!") + +/datum/component/obeys_commands/proc/on_examine_more(mob/living/source, mob/user, list/examine_list) + SIGNAL_HANDLER + + if (IS_DEAD_OR_INCAP(source)) + return + if (!(user in source.ai_controller?.blackboard[BB_FRIENDS_LIST])) + return + + if (source.health < source.maxHealth*0.2) + examine_list += span_bolddanger("[source.p_They()] look[source.p_s()] severely injured.") + else if (source.health < source.maxHealth*0.5) + examine_list += span_danger("[source.p_They()] look[source.p_s()] moderately injured.") + else if (source.health < source.maxHealth*0.8) + examine_list += span_warning("[source.p_They()] look[source.p_s()] slightly injured.") + else + examine_list += span_notice("[source.p_They()] look[source.p_s()] to be in good condition.") diff --git a/modular_doppler/hearthkin/primitive_catgirls/code/smelling_salts.dm b/modular_doppler/hearthkin/primitive_catgirls/code/smelling_salts.dm new file mode 100644 index 0000000000000..6996855fbb427 --- /dev/null +++ b/modular_doppler/hearthkin/primitive_catgirls/code/smelling_salts.dm @@ -0,0 +1,70 @@ +/obj/item/smelling_salts + name = "smelling salts" + desc = "A small pile of a salt-like substance that smells absolutely repulsive. Rumor has it that the smell is so pungent that even the dead will come back to life to escape it." + icon_state = "smelling_salts" + icon = 'modular_doppler/hearthkin/primitive_catgirls/icons/salts.dmi' + w_class = WEIGHT_CLASS_TINY + resistance_flags = FLAMMABLE + item_flags = NOBLUDGEON + +/obj/item/smelling_salts/attack(mob/living/mob_attacked, mob/user) + . = ..() + if(!iscarbon(mob_attacked)) + to_chat(user, span_warning("On second thought, maybe [src] won't work on [mob_attacked].")) + return + + if(mob_attacked == user) + to_chat(user, span_warning("You can't bring yourself to get [src] anywhere near your face.")) + return + + if(mob_attacked.stat != DEAD) + to_chat(user, span_warning("On second thought, maybe you shouldn't use this on [mob_attacked] if they're not dead.")) + return + + try_revive(mob_attacked, user) + +/// If the right conditions are present (basically could this person be defibrilated), revives the target +/obj/item/smelling_salts/proc/try_revive(mob/living/carbon/carbon_target, mob/user) + carbon_target.notify_revival("You are being brought back to life!") + carbon_target.grab_ghost() + + user.balloon_alert_to_viewers("trying to revive [carbon_target]") + + if(!do_after(user, 3 SECONDS, carbon_target)) + user.balloon_alert(user, "stopped reviving [carbon_target]") + return + + if(carbon_target.stat != DEAD) + to_chat(user, span_warning("Wait, [carbon_target] isn't actually dead!")) + return + + var/defib_result = carbon_target.can_defib() + var/fail_reason + + switch (defib_result) + if (DEFIB_FAIL_SUICIDE, DEFIB_FAIL_BLACKLISTED, DEFIB_FAIL_NO_INTELLIGENCE) + fail_reason = "[carbon_target] doesn't respond at all... You don't think they're coming back." + if (DEFIB_FAIL_NO_HEART, DEFIB_FAIL_FAILING_HEART, DEFIB_FAIL_FAILING_BRAIN) + fail_reason = "[carbon_target] seems to respond just a little, but something you can't see must be wrong about them..." + if (DEFIB_FAIL_TISSUE_DAMAGE, DEFIB_FAIL_HUSK) + fail_reason = "[carbon_target]'s body seems way too damaged for this to work..." + if (DEFIB_FAIL_NO_BRAIN) + fail_reason = "[carbon_target]'s head looks like it's missing something important." + + if(carbon_target.health <= HEALTH_THRESHOLD_FULLCRIT) + fail_reason = "[carbon_target]'s body seems just a little too damaged for this to work..." + + if(fail_reason) + to_chat(user, span_boldwarning("[fail_reason]")) + return + + carbon_target.adjustOxyLoss(amount = 60, updating_health = TRUE) + playsound(src, 'modular_doppler/emotes/sound/female_sniff.ogg', 50, FALSE) + carbon_target.set_heartattack(FALSE) + + if(defib_result == DEFIB_POSSIBLE) + carbon_target.grab_ghost() + + carbon_target.revive() + // to_chat(carbon_target, span_userdanger("[CONFIG_GET(string/blackoutpolicy)]")) + log_combat(user, carbon_target, "revived", src) diff --git a/modular_doppler/hearthkin/primitive_catgirls/code/spawner.dm b/modular_doppler/hearthkin/primitive_catgirls/code/spawner.dm new file mode 100644 index 0000000000000..6609cc69e1c03 --- /dev/null +++ b/modular_doppler/hearthkin/primitive_catgirls/code/spawner.dm @@ -0,0 +1,317 @@ +/obj/effect/mob_spawn/ghost_role/human/primitive_catgirl + name = "hole in the ground" + desc = "A clearly hand dug hole in the ground that appears to lead into a small cave of some kind? It's pretty dark in there." + prompt_name = "icemoon dweller" + icon = 'icons/mob/simple/lavaland/nest.dmi' + icon_state = "hole" + mob_species = /datum/species/human/felinid/primitive + outfit = /datum/outfit/primitive_catgirl + density = FALSE + you_are_text = "You are an icemoon dweller." + flavour_text = "For as long as you can remember, the icemoon has been your home. \ + It's been the home of your ancestors, and their ancestors, and the ones before them. \ + Currently, you and your kin live in uneasy tension with your nearby human-and-otherwise \ + neighbors. Keep your village and your Kin safe, but bringing death on their heads from \ + being reckless with the outsiders will not have the Gods be so kind." + spawner_job_path = /datum/job/primitive_catgirl + interaction_flags_mouse_drop = NEED_DEXTERITY + + /// The team the spawner will assign players to and use to keep track of people that have already used the spawner + var/datum/team/primitive_catgirls/team + + restricted_species = list(/datum/species/human/felinid/primitive) + quirks_enabled = TRUE + random_appearance = FALSE + loadout_enabled = FALSE + infinite_use = TRUE + deletes_on_zero_uses_left = FALSE + + /// The list of real names of those that have gone back into the hole. + /// Should get modified automatically by `create()` and `put_back_in()`. + var/list/went_back_to_sleep = list() + /// The cached string to display for additional info on who joined and who left. + /// Nulled every time someone joins or leaves to ensure it gets re-generated. + var/join_and_leave_log_cache = null + /// The minimum time someone needs to be SSD before they can be put back in + var/ssd_time = 30 MINUTES + +/obj/effect/mob_spawn/ghost_role/human/primitive_catgirl/Initialize(mapload) + . = ..() + team = new /datum/team/primitive_catgirls() + + // important_text = "Read the full policy here." + +/obj/effect/mob_spawn/ghost_role/human/primitive_catgirl/Destroy() + team = null + return ..() + +/obj/effect/mob_spawn/ghost_role/human/primitive_catgirl/examine(mob/user) + . = ..() + + if(isprimitivedemihuman(user) || isobserver(user)) + . += span_notice("You could examine it more thoroughly...") + + return . + + +/obj/effect/mob_spawn/ghost_role/human/primitive_catgirl/examine_more(mob/user) + . = ..() + + if(!isprimitivedemihuman(user) && !isobserver(user)) + return + + . += get_joined_and_left_log() + + +/** + * Returns the `join_and_leave_log_cache` string if it already exists, otherwise + * generates and returns it. + */ +/obj/effect/mob_spawn/ghost_role/human/primitive_catgirl/proc/get_joined_and_left_log() + if(join_and_leave_log_cache) + return join_and_leave_log_cache + + var/list/joined_player_names = list() + + for(var/datum/mind/joined_mind in team.members) + joined_player_names += joined_mind.name + + if(!length(joined_player_names) && !length(went_back_to_sleep)) + join_and_leave_log_cache = span_notice("Everyone still seems to be sleeping peacefully in the hole.") + return join_and_leave_log_cache + + var/nobody_joined = !length(joined_player_names) + var/nobody_returned = !length(went_back_to_sleep) + var/should_add_newline = !nobody_returned && !nobody_joined // if we have both missing kin and kin who went back to sleep, add a newline + + join_and_leave_log_cache = span_notice( \ + "[nobody_joined ? "" : "You smell that the following kin are missing from the hole:\n\ + [joined_player_names.Join(", ")]"]\ + [should_add_newline ? "\n\n" : ""]\ + [nobody_returned ? "" : "You catch the scent of the following kin having recently went back to sleep:\n\ + [went_back_to_sleep.Join(", ")]"]" \ + ) + + return join_and_leave_log_cache + + +/obj/effect/mob_spawn/ghost_role/human/primitive_catgirl/allow_spawn(mob/user, silent = FALSE) + if(!(user.key in team.players_spawned)) // One spawn per person + return TRUE + if(!silent) + to_chat(user, span_warning("It'd be weird if there were multiple of you in that cave, wouldn't it?")) + return FALSE + + +/obj/effect/mob_spawn/ghost_role/human/primitive_catgirl/create(mob/mob_possessor, newname) + . = ..() + + // We remove their name from there if they come back. + went_back_to_sleep -= newname + join_and_leave_log_cache = null + + +// This stuff is put on equip because it turns out /special sometimes just don't get called because Nova +/obj/effect/mob_spawn/ghost_role/human/primitive_catgirl/equip(mob/living/carbon/human/spawned_human) + . = ..() + + spawned_human.mind.add_antag_datum(/datum/antagonist/primitive_catgirl, team) + + team.players_spawned += (spawned_human.key) + + +/obj/effect/mob_spawn/ghost_role/human/primitive_catgirl/mouse_drop_receive(mob/living/carbon/human/target, mob/user, params) + if(!istype(target)) + return + if(!isprimitivedemihuman(target) || target.buckled) + return + + if(target.stat == DEAD) + to_chat(user, span_danger("Dead kin cannot be put back to sleep.")) + return + + if(target.key && target != user) + if(!target.get_organ_by_type(/obj/item/organ/internal/brain) || (target.mind && !target.ssd_indicator)) + to_chat(user, span_danger("Awake kin cannot be put back to sleep against their will.")) + return + + if(target.lastclienttime + ssd_time >= world.time) + to_chat(user, span_userdanger("You can't put [target] into [src] for another [round(((ssd_time - (world.time - target.lastclienttime)) / (1 MINUTES)), 1)] minutes.")) + log_admin("[key_name(user)] has attempted to put [key_name(target)] back into [src], but they were only disconnected for [round(((world.time - target.lastclienttime) / (1 MINUTES)), 1)] minutes.") + message_admins("[key_name(user)] has attempted to put [key_name(target)] back into [src]. [ADMIN_JMP(src)]") + return + + else if(tgui_alert(user, "Would you like to place [target] into [src]?", "Put back to sleep?", list("Yes", "No")) == "Yes") + + visible_message(span_infoplain("[user] starts putting [target] into [src]...")) + + if(!do_after(user, 3 SECONDS, target)) + balloon_alert(user, "cancelled transfer!") + return + + to_chat(user, span_danger("You put [target] into [src].")) + log_admin("[key_name(user)] has put [key_name(target)] back into [src].") + message_admins("[key_name(user)] has put [key_name(target)] back into [src]. [ADMIN_JMP(src)]") + + if(target == user) + if(tgui_alert(target, "Would you like to go back to sleep?", "Go back to sleep?", list("Yes", "No")) != "Yes") + return + + visible_message(span_infoplain("[user] starts climbing down into [src]...")) + + if(!do_after(user, 3 SECONDS, target)) + balloon_alert(user, "cancelled transfer!") + return + + if(LAZYLEN(target.buckled_mobs) > 0) + if(target == user) + to_chat(user, span_danger("You can't fit into [src] while someone is buckled to you.")) + else + to_chat(user, span_danger("You can't fit [target] into [src] while someone is buckled to them.")) + + return + + // Just in case something happened in-between, to make sure it doesn't do unexpected behaviors. + if(!isprimitivedemihuman(target) || !can_interact(user) || !target.Adjacent(user) || target.buckled || target.stat == DEAD) + return + + if(target == user) + visible_message(span_infoplain("[user] climbs down into [src].")) + else + visible_message(span_infoplain("[user] puts [target] into [src].")) + + log_admin("[key_name(target)] returned to [src].") + message_admins("[key_name_admin(target)] returned to [src]. [ADMIN_JMP(src)]") + add_fingerprint(target) + put_back_in(target) + + +/** + * Puts the target back into the spawner, effectively qdel'ing them after + * stripping them of all their items, and finishes by adding back a use to the + * spawner. + */ +/obj/effect/mob_spawn/ghost_role/human/primitive_catgirl/proc/put_back_in(mob/living/carbon/human/target) + if(!istype(target)) + return + + // We don't want to constantly drop stuff that they spawn with. + var/static/list/item_drop_blacklist + if(!item_drop_blacklist) + item_drop_blacklist = generate_item_drop_blacklist() + + for(var/obj/item/item in target) + if(item_drop_blacklist[item.type] || (item.item_flags & ABSTRACT) || HAS_TRAIT(item, TRAIT_NODROP)) + continue + + target.dropItemToGround(item, FALSE) + + // We make sure people can come back in again, if they needed to fix prefs + // or whatever. + team.players_spawned -= (target.key) + team.remove_member(target.mind) + went_back_to_sleep += target.real_name + join_and_leave_log_cache = null + + for(var/list/record in GLOB.ghost_records) + if(record["name"] == target.real_name) + GLOB.ghost_records.Remove(list(record)) + break + + // Just so the target's ghost ends up above the hole. + target.forceMove(loc) + target.ghostize(FALSE) + + qdel(target) + + +/** + * Simple helper to generate the item drop blacklist based on the spawner's + * outfit, only taking the used slots into account. + */ +/obj/effect/mob_spawn/ghost_role/human/primitive_catgirl/proc/generate_item_drop_blacklist() + PROTECTED_PROC(TRUE) + + var/list/blacklist = list() + + blacklist[initial(outfit.uniform)] = TRUE + blacklist[initial(outfit.shoes)] = TRUE + blacklist[initial(outfit.gloves)] = TRUE + blacklist[initial(outfit.suit)] = TRUE + blacklist[initial(outfit.neck)] = TRUE + blacklist[initial(outfit.back)] = TRUE + + return blacklist + + +/datum/job/primitive_catgirl + title = "Icemoon Dweller" + +// Antag and team datums + +/datum/team/primitive_catgirls + name = "Icewalkers" + member_name = "Icewalker" + show_roundend_report = FALSE + +/datum/team/primitive_catgirls/roundend_report() + var/list/report = list() + + report += span_header("An Ice Walker Tribe inhabited the wastes...
") + if(length(members)) + report += "The [member_name]s were:" + report += printplayerlist(members) + else + report += "But none of its members woke up!" + + return "
[report.Join("
")]
" + +// Antagonist datum + +/datum/antagonist/primitive_catgirl + name = "\improper Icewalker" + job_rank = ROLE_LAVALAND // If you're ashwalker banned you should also not be playing this, other way around as well + show_in_antagpanel = FALSE + show_to_ghosts = TRUE + prevent_roundtype_conversion = FALSE + antagpanel_category = "Icemoon Dwellers" + count_against_dynamic_roll_chance = FALSE + show_in_roundend = FALSE + + /// Tracks the antag datum's 'team' for showing in the ghost orbit menu + var/datum/team/primitive_catgirls/feline_team + + var/list/antag_recipes = list( + /datum/crafting_recipe/boneaxe, + /datum/crafting_recipe/bonespear, + /datum/crafting_recipe/bonedagger, + /datum/crafting_recipe/anointing_oil, + /datum/crafting_recipe/handcrafted_hearthkin_armor, + /datum/crafting_recipe/black_pelt_bed, + /datum/crafting_recipe/white_pelt_bed, + /datum/crafting_recipe/frozen_breath, + ) + +/datum/antagonist/primitive_catgirl/on_gain() + . = ..() + for(var/recipe_datum in antag_recipes) + owner.teach_crafting_recipe(recipe_datum) + +/datum/antagonist/primitive_catgirl/on_removal() + . = ..() + for(var/recipe_datum in antag_recipes) + owner.unteach_crafting_recipe(recipe_datum) + +/datum/antagonist/primitive_catgirl/Destroy() + feline_team = null + return ..() + +/datum/antagonist/primitive_catgirl/create_team(datum/team/team) + if(team) + feline_team = team + objectives |= feline_team.objectives + else + feline_team = new + +/datum/antagonist/primitive_catgirl/get_team() + return feline_team diff --git a/modular_doppler/hearthkin/primitive_catgirls/code/special_metals.dm b/modular_doppler/hearthkin/primitive_catgirls/code/special_metals.dm new file mode 100644 index 0000000000000..ae969d27ca8df --- /dev/null +++ b/modular_doppler/hearthkin/primitive_catgirls/code/special_metals.dm @@ -0,0 +1,117 @@ +// Completely made up materials to be sold in bar form by jarnsmiour in cargo, *should* be unobtainable otherwise + +// Darkish blue kinda material + +/datum/material/cobolterium + name = "cobolterium" + desc = "Cobolterium" + color = list(0.2,0.5,0.7,0, 0,0,0,0, 0,0,0,0, 0,0,0,1, 0,0,0,0) + greyscale_colors = "#264d61" + categories = list(MAT_CATEGORY_RIGID = TRUE, MAT_CATEGORY_BASE_RECIPES = TRUE, MAT_CATEGORY_ITEM_MATERIAL = TRUE) + sheet_type = /obj/item/stack/sheet/cobolterium + +/datum/material/cobolterium/on_accidental_mat_consumption(mob/living/carbon/victim, obj/item/source_item) + victim.apply_damage(10, BRUTE, BODY_ZONE_HEAD, wound_bonus = 5) + return TRUE + +/obj/item/stack/sheet/cobolterium + name = "cobolterium bars" + desc = "Cobalt-blue metal that might actually just be cobalt." + singular_name = "cobolterium bar" + icon = 'modular_doppler/hearthkin/primitive_catgirls/icons/special_metals_stack.dmi' + icon_state = "precious-metals" + material_flags = MATERIAL_EFFECTS | MATERIAL_COLOR + mats_per_unit = list(/datum/material/cobolterium = SHEET_MATERIAL_AMOUNT) + merge_type = /obj/item/stack/sheet/cobolterium + material_type = /datum/material/cobolterium + material_modifier = 1 + +/obj/item/stack/sheet/cobolterium/three + amount = 3 + +// More copper colored material + +/datum/material/copporcitite + name = "copporcitite" + desc = "Copporcitite" + color = list(0.8,0.35,0.1,0, 0,0,0,0, 0,0,0,0, 0,0,0,1, 0,0,0,0) + greyscale_colors = "#c55a1d" + categories = list(MAT_CATEGORY_RIGID = TRUE, MAT_CATEGORY_BASE_RECIPES = TRUE, MAT_CATEGORY_ITEM_MATERIAL = TRUE) + sheet_type = /obj/item/stack/sheet/copporcitite + +/datum/material/copporcitite/on_accidental_mat_consumption(mob/living/carbon/victim, obj/item/source_item) + victim.apply_damage(10, BRUTE, BODY_ZONE_HEAD, wound_bonus = 5) + return TRUE + +/obj/item/stack/sheet/copporcitite + name = "copporcitite bars" + desc = "Copper colored metal that might actually just be copper." + singular_name = "copporcitite bar" + icon = 'modular_doppler/hearthkin/primitive_catgirls/icons/special_metals_stack.dmi' + icon_state = "precious-metals" + material_flags = MATERIAL_EFFECTS | MATERIAL_COLOR + mats_per_unit = list(/datum/material/copporcitite = SHEET_MATERIAL_AMOUNT) + merge_type = /obj/item/stack/sheet/copporcitite + material_type = /datum/material/copporcitite + material_modifier = 1 + +/obj/item/stack/sheet/copporcitite/three + amount = 3 + +// Super blued-silver color + +/datum/material/tinumium + name = "tinumium" + desc = "Tinumium" + color = list(0.45,0.5,0.6,0, 0,0,0,0, 0,0,0,0, 0,0,0,1, 0,0,0,0) + greyscale_colors = "#717e97" + categories = list(MAT_CATEGORY_RIGID = TRUE, MAT_CATEGORY_BASE_RECIPES = TRUE, MAT_CATEGORY_ITEM_MATERIAL = TRUE) + sheet_type = /obj/item/stack/sheet/tinumium + +/datum/material/tinumium/on_accidental_mat_consumption(mob/living/carbon/victim, obj/item/source_item) + victim.apply_damage(10, BRUTE, BODY_ZONE_HEAD, wound_bonus = 5) + return TRUE + +/obj/item/stack/sheet/tinumium + name = "tinumium bars" + desc = "Heavily blued, silver colored metal." + singular_name = "tinumium bar" + icon = 'modular_doppler/hearthkin/primitive_catgirls/icons/special_metals_stack.dmi' + icon_state = "precious-metals" + material_flags = MATERIAL_EFFECTS | MATERIAL_COLOR + mats_per_unit = list(/datum/material/tinumium = SHEET_MATERIAL_AMOUNT ) + merge_type = /obj/item/stack/sheet/tinumium + material_type = /datum/material/tinumium + material_modifier = 1 + +/obj/item/stack/sheet/tinumium/three + amount = 3 + +// Brassy yellow color + +/datum/material/brussite + name = "brussite" + desc = "Brussite" + color = list(0.9,0.75,0.4,0, 0,0,0,0, 0,0,0,0, 0,0,0,1, 0,0,0,0) + greyscale_colors = "#E1C16E" + categories = list(MAT_CATEGORY_RIGID = TRUE, MAT_CATEGORY_BASE_RECIPES = TRUE, MAT_CATEGORY_ITEM_MATERIAL = TRUE) + sheet_type = /obj/item/stack/sheet/brussite + +/datum/material/brussite/on_accidental_mat_consumption(mob/living/carbon/victim, obj/item/source_item) + victim.apply_damage(10, BRUTE, BODY_ZONE_HEAD, wound_bonus = 5) + return TRUE + +/obj/item/stack/sheet/brussite + name = "brussite bars" + desc = "Brassy-yellow metal that might actually just be brass." + singular_name = "brussite bar" + icon = 'modular_doppler/hearthkin/primitive_catgirls/icons/special_metals_stack.dmi' + icon_state = "precious-metals" + material_flags = MATERIAL_EFFECTS | MATERIAL_COLOR + mats_per_unit = list(/datum/material/brussite = SHEET_MATERIAL_AMOUNT ) + merge_type = /obj/item/stack/sheet/brussite + material_type = /datum/material/brussite + material_modifier = 1 + +/obj/item/stack/sheet/brussite/three + amount = 3 diff --git a/modular_doppler/hearthkin/primitive_catgirls/code/species.dm b/modular_doppler/hearthkin/primitive_catgirls/code/species.dm new file mode 100644 index 0000000000000..9590424c29320 --- /dev/null +++ b/modular_doppler/hearthkin/primitive_catgirls/code/species.dm @@ -0,0 +1,128 @@ +#define SPECIES_FELINE_PRIMITIVE "primitive_felinid" //This should go on a dedicated define DNA file + +/mob/living/carbon/human/species/felinid/primitive + race = /datum/species/human/felinid/primitive + +/datum/language_holder/primitive_felinid + understood_languages = list( + /datum/language/primitive_catgirl = list(LANGUAGE_ATOM), + /datum/language/uncommon = list(LANGUAGE_ATOM), + ) + spoken_languages = list( + /datum/language/primitive_catgirl = list(LANGUAGE_ATOM), + /datum/language/uncommon = list(LANGUAGE_ATOM), + ) + selected_language = /datum/language/primitive_catgirl + +/datum/species/human/felinid/primitive + name = "Primitive Demihuman" + id = SPECIES_FELINE_PRIMITIVE + + mutantlungs = /obj/item/organ/internal/lungs/icebox_adapted + mutanteyes = /obj/item/organ/internal/eyes/low_light_adapted + mutanttongue = /obj/item/organ/internal/tongue/cat/primitive + + species_language_holder = /datum/language_holder/primitive_felinid + // language_prefs_whitelist = list(/datum/language/primitive_catgirl) //this needs a dedicated module for language + + bodytemp_normal = 270 // If a normal human gets hugged by one it's gonna feel cold + bodytemp_heat_damage_limit = 283 // To them normal station atmos would be sweltering + bodytemp_cold_damage_limit = 213 // Man up bro it's not even that cold out here + + inherent_traits = list( + TRAIT_CATLIKE_GRACE, + TRAIT_VIRUSIMMUNE, + TRAIT_RESISTCOLD, + TRAIT_USES_SKINTONES, + ) + + // always_customizable = TRUE //this needs a dedicated module for species customization + +/datum/species/human/felinid/primitive/on_species_gain(mob/living/carbon/new_primitive, datum/species/old_species, pref_load) + . = ..() + var/mob/living/carbon/human/hearthkin = new_primitive + if(!istype(hearthkin)) + return + hearthkin.dna.add_mutation(/datum/mutation/human/olfaction, MUT_NORMAL) + hearthkin.dna.activate_mutation(/datum/mutation/human/olfaction) + + // >mfw I take mutadone and my nose clogs + var/datum/mutation/human/olfaction/mutation = locate() in hearthkin.dna.mutations + mutation.mutadone_proof = TRUE + mutation.instability = 0 + +/datum/species/human/felinid/primitive/on_species_loss(mob/living/carbon/former_primitive, datum/species/new_species, pref_load) + . = ..() + var/mob/living/carbon/human/hearthkin = former_primitive + if(!istype(hearthkin)) + return + hearthkin.dna.remove_mutation(/datum/mutation/human/olfaction) + +/datum/species/human/felinid/primitive/prepare_human_for_preview(mob/living/carbon/human/human_for_preview) + human_for_preview.hairstyle = "Blunt Bangs Alt" + human_for_preview.hair_color = "#323442" + human_for_preview.skin_tone = "mediterranean" + + human_for_preview.update_body_parts() + + human_for_preview.dna.species.mutant_bodyparts["tail"] = list(MUTANT_INDEX_NAME = "Cat", MUTANT_INDEX_COLOR_LIST = list(human_for_preview.hair_color)) + human_for_preview.dna.species.mutant_bodyparts["ears"] = list(MUTANT_INDEX_NAME = "Cat", MUTANT_INDEX_COLOR_LIST = list(human_for_preview.hair_color)) + + human_for_preview.update_mutant_bodyparts() + human_for_preview.update_body(is_creating = TRUE) + +/datum/species/human/felinid/primitive/get_species_description() + return list( + "Genetically modified humanoids believed to be descendants of a now centuries old colony \ + ship from the pre-bluespace travel era. Still having at least some human traits, they \ + are most comparable to today's felinids with most sporting features likely spliced from \ + the icemoon's many fauna." + ) + +/datum/species/human/felinid/primitive/get_species_lore() + return list( + "The Hearthkin are a culture of disparate Scandinavian groups all sharing a common origin \ + as descendents from demihuman genemodders aboard the good ship Stjarndrakkr, or Star Dragon; \ + an enormous colony ship almost 40km tall. This ship first reached the orbit of its last \ + resting place three hundred years ago, before the advent of bluespace travel; coming from \ + a world known to the Hearthkin as 'Asgard.' When it reached the atmosphere of the ice moon, \ + or 'Niflheim' as they consider it, the vessel detonated in low orbit for unknown reasons. \ + Large sections of the Star Dragon broke up and sealed themselves, \ + coming to a rest all over the moon itself.", + + "At first, life was incredibly difficult for the would-be colonists. Generations were very short, \ + and most of the personnel able to even fix the vessel had died either on impact, or later on. \ + While their genetic modifications and pre-existing comfort in frozen climates somewhat helped them, \ + the Ancestors were said to have made one last desperate move to put all their resources together to \ + fully modify and adapt themselves to the climes of Niflheim; forever.", + + "Nowadays, the Hearthkin are removed from the original culture of the Ancestors, building one all of their own. \ + Many of the original, largest segments of the Star Dragon are buried under ice and snow, and the Hearthkin have \ + created a culture of building separate dwellings to keep them secret. Dwelling in longhouses and sleeping in the \ + warm undergrounds of Niflheim, and hunting native creatures and those coming from portals to the moon's planet; \ + Muspelheim. Their pagan faith has strengthened over the centuries, from occasional prayers for a blizzard to end \ + soon, to now full-on worship and sacrifices to their various Gods. Hearthkin still hold immense reverence for their \ + Ancestors, but tend to have varying opinions and speculation on what exactly they were like, and why they came to \ + Niflheim in the first place.", + + "Their names are two-part; a birth name, and a title. Their birth names still hold resemblance to 'Asgardian' culture, \ + typically a Nordic name such as 'Solveig Helgasdottir,' or 'Bjorn Lukasson.' However, their last name is then exchanged \ + for a 'Title' when the Hearthkin is no longer 'Unproven.' These are a two-parter, based on either great deeds, \ + embarrassing moments, or aspects of the person's personality. Some examples would be 'Soul-Drowner' after the night of \ + a Hearthkin drinking herself half-dead, or one might be known as 'Glacier-Shaped' for being abnormally large. \ + These titles are always given by ones' kin.", + + "The Hearth itself is an area that the kindred hold incredibly sacred, primarily hating Outsiders for more \ + practical reasons. They think themselves as having been there first, many of them knowing they were 'promised' \ + Niflheim by the Ancestors. Unlike the Ashwalkers of Muspelheim, the Hearthkin are a more technologically \ + advanced society; having use for not only metal, but gold and silver for accessory. They are known to employ \ + artifacts thought to be of either the planet their moon orbits, or leftovers from their Ancestors; however, for \ + a variety of reasons from Kin to Kin, they tend to shy away from using modern human technology.", + + "Physically, the Hearthkin always come in the form of demihumans; appearing similar to normal Earthlings, \ + but with the tails, ears, and sometimes limbs of various arctic animals; wolves, bears, and felines to only name a few. \ + They seem perfectly adapted to their lands of ice and mist, but find even the mild controlled temperatures of \ + NanoTrasen stations to be swelteringly hot. Their view of 'station' genemodders is that of 'halflings': \ + Ancestral bodies, but with the blood and spirit of the humans of Midgard, \ + tending to look down on them even more than other aliens.", + ) diff --git a/modular_doppler/hearthkin/primitive_catgirls/code/translator.dm b/modular_doppler/hearthkin/primitive_catgirls/code/translator.dm new file mode 100644 index 0000000000000..4963f7160ab99 --- /dev/null +++ b/modular_doppler/hearthkin/primitive_catgirls/code/translator.dm @@ -0,0 +1,73 @@ +//TRANSLATOR NECKLACE// +#define LANGUAGE_TRANSLATOR "translator" + +/obj/item/clothing/neck/necklace/translator/ + name = "antique necklace" + desc = "A necklace with a old, strange device as its pendant. Symbols \ + constantly seem to appear on its screen, as noises happen around it, \ + but its purpose is not immediately apparent." + icon = 'modular_doppler/hearthkin/primitive_catgirls/icons/translator.dmi' + worn_icon = 'modular_doppler/hearthkin/primitive_catgirls/icons/translator_worn.dmi' + icon_state = "translator" + slot_flags = ITEM_SLOT_NECK | ITEM_SLOT_OCLOTHING + w_class = WEIGHT_CLASS_SMALL //allows this to fit inside of pockets. + /// The language granted by this necklace + var/datum/language/language_granted = /datum/language/uncommon + + +/obj/item/clothing/neck/necklace/translator/Initialize(mapload) + . = ..() + RegisterSignal(src, COMSIG_ITEM_EQUIPPED, PROC_REF(on_necklace_equip)) + + +/// Handles giving the language to the equipper when equipped. +/obj/item/clothing/neck/necklace/translator/proc/on_necklace_equip(datum/source, mob/living/carbon/human/equipper, slot) + SIGNAL_HANDLER + + if(!(slot_flags & slot)) + return + + if(!istype(equipper)) + return + + equipper.grant_language(language_granted, source = LANGUAGE_TRANSLATOR) + RegisterSignal(src, COMSIG_ITEM_DROPPED, PROC_REF(on_necklace_unequip)) + + equip_feedback(equipper) + + +/// Handles sending text feedback to the equipper. Override to change the text. +/obj/item/clothing/neck/necklace/translator/proc/equip_feedback(mob/living/carbon/human/equipper) + to_chat(equipper, span_notice( \ + "Slipping the necklace on, you notice a slight buzzing in your ears, \ + and that any word in [initial(language_granted.name)] said in your \ + general vicinity is immediately translated to your native language, \ + directly in your ears. Not only that, but you find yourself able to \ + speak your mind in such a way that the pendant translates your words \ + back in [initial(language_granted.name)]." \ + )) + + +/// Handles removing the language from the unequipper when unequipped. +/obj/item/clothing/neck/necklace/translator/proc/on_necklace_unequip(obj/item/source, mob/living/carbon/human/unequipper) + SIGNAL_HANDLER + + if(!istype(unequipper)) + return + + unequipper.remove_language(language_granted, source = LANGUAGE_TRANSLATOR) + UnregisterSignal(source, COMSIG_ITEM_DROPPED) + + unequip_feedback(unequipper) + + +/// Handles sending text feedback to the unequipper. Override to change the text. +/obj/item/clothing/neck/necklace/translator/proc/unequip_feedback(mob/living/carbon/human/unequipper) + to_chat(unequipper, span_boldnotice( \ + "\The [src]'s constant buzzing suddenly stops. Peace, at last. \ + You also lose your artificial grasp on [initial(language_granted.name)], \ + unfortunately. Such is the price for peace and quiet." \ + )) + + +#undef LANGUAGE_TRANSLATOR diff --git a/modular_doppler/hearthkin/primitive_catgirls/icons/clothing_greyscale.dmi b/modular_doppler/hearthkin/primitive_catgirls/icons/clothing_greyscale.dmi new file mode 100644 index 0000000000000000000000000000000000000000..4599c4404da66fb6632e4662eac21276cfe7cb6e GIT binary patch literal 4011 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 literal 0 HcmV?d00001 diff --git a/modular_doppler/hearthkin/primitive_catgirls/icons/gods_statue.dmi b/modular_doppler/hearthkin/primitive_catgirls/icons/gods_statue.dmi new file mode 100644 index 0000000000000000000000000000000000000000..5a61f361489141efae5ced3d15ae4b0ba98ac1ba GIT binary patch literal 821 zcmV-51Iqk~P)$-vmZ3EauFQZPK&M)>GlwRCn`gF6SPF2PfL*|XU`{5d(>JlhMsI4y7 z>YDbjNok=6@jz^H$ab6?lJL0@QY4SLwzMo9Lo#3iR4rpj1~roifK-^kC8N`1(q|7L zbw*$)wLQd1n^8%uW$6?XxKU#11ttPX;PMGMdibE53cK7Rd*c8_UUM&d^d7Cuou|}G zu?ygZiD7`Xxh?=lssm@yaqs2D!7vl90KD{RyKCC9_O53t;iSjkz{Ex2_i>lI^dS%x8ioTUjzrm_ss9rHOf(uG;z0;l6DDkrbfMX-9fZy8Lh zM(d^!a*AM+DsBA~4l06tQseF81Qfw?$n&^;d&Tr=K&6vA$-}ZMG=YQ-cEMD+cXZK#a00000NkvXXu0mjfzr1ib literal 0 HcmV?d00001 diff --git a/modular_doppler/hearthkin/primitive_catgirls/icons/language_icon.dmi b/modular_doppler/hearthkin/primitive_catgirls/icons/language_icon.dmi new file mode 100644 index 0000000000000000000000000000000000000000..02cec3342ba777e225b84e29322735a18d646493 GIT binary patch literal 417 zcmV;S0bc%zP)V=-0C=2JR&a84_w-Y6@%7{?OD!tS%+FJ>RWQ*r;NmRLOex6#atzJ5I5Sc+ z(=$pSoZ^zil2jm5DL*$oJF}#uG9xoHQ;CZ+C9|j)q=Jhxttc@!6~b0laP@Nmn+^ag zWF0CgTk4Gf008YtL_t(|oQ+b;3Bphi+!s=Tf{KU*hYRIlh|Kdy zFw=g0k0ha7gs-F(hyXH37}2ZxMBgy>3V__ai*`-&WIFFA(+BTC^fHk{Pq5DI2Pnc@ z=@WlrM?g#rNeaG?j0^UNWb_U)<|Ok^sUJX!%KhhMh60h8FWKV@StF_HYUAS`00000 LNkvXXu0mjf?Uu3m literal 0 HcmV?d00001 diff --git a/modular_doppler/hearthkin/primitive_catgirls/icons/objects.dmi b/modular_doppler/hearthkin/primitive_catgirls/icons/objects.dmi new file mode 100644 index 0000000000000000000000000000000000000000..2382f1e7d08080512e514659d4c8c37a3705cce8 GIT binary patch literal 1445 zcmV;W1zP%vP)Hqlq|J?KcKAEx$VR^{&|6kJM#N+>Ej>4|{ z|H%FS8#{I3^Z!(|&MJbM;r9Qh`}fcJ|LO1lDrK59U8<+)`x{e+AV-o5*!LhRk^oGS z6^70LS&{%hk^n4y5EV&Nbh0~6szECnWlA;1p@dOBFv^HQ|E8uS4GpRX5cISLABP)#ry z6x`h0`1t=oBpzTvJWw?;lb58OrmVHV#>L9ev9r0#)!a`xHoeH9dt=KA&Z_1DhM z@95~Vt+&6wzs94ym;e9(0d!JMQvg8b*k%9#0GoPLSad{Xb7OL8aCB*JZU6vyoQ03E z3c^4TMC-e+IFeqB+S*8hq%gk_Hr^(;knF(;`^e&4YOiQ@TrYZ97-rTKhna zB<#-awA)+rB%i_x$AdKiX$t8JF+svL7Ng1wc~FED3Tr%R%&s+~!h$(hTNzl06Y(_6 zB3>~P|8?#Gh|%|RUO??Z7tzhCeyq|pUH$p-1_Z%A-{s1hl>h((n@L1LRA_}=!YKRzZES6fJF$8>q?f?HF-MxuZYi{nU8)lr=6CT5Sd(ZCP z8D@?U&w64?rA9`E$wg}Ph2DV4pM3 zgsy_iu^>YjaCjOyju2DA=HtL8C!s<;1fN6usp;%gCNndmsNnKhBWGmh=BHjyFJu;H zqBC&0n9UaqV<9^~J-v`K7T-h-m>dfVh1^^=`_?EJIi&%Mi+B0=P+@$SGw>@~z~xvV zD{=*t(tyRqQXVQ~jk8sl)`|?#Y%ZKsE}GuC(Y#uP!XuKo;-&UpdwJItTJG7tSGOR@F|x!hQXl%N>Cd^ z;<5x4i`o2tPzA){bc4-L`UV6i^L=G&OW%OtRKDM?Y;IPzcOK2Dd~a5*-QDfl-eb8S z^Sy2D?^iVgQk=^7wp9g#_yH*{hdpq~%VT1U5F9)<5;1C!D4)^C_gZO+e|E3Mp@o_zLxNSi3 zKP$xLd)v0Gz~Fl$RLy(?@jZzff+eZaY5&M^OhdN@0IVldd~N>o__u(8*uYK zA%6bXD}nq^h@bx{e|G-Y`!n-@v)OF5f3#ch9b>@D|8Dcd^IC4p^G=#>%z&Ky-)y>` z=eeHzRPDgb|2V&k^TXR!?ZD0dFh4kV{FdLr4sK)xX8wnZX>~h(uiNSN{7x5s-dTa0 z|KVb~!tb4)wa-p_zUad5$a!Y|2c2JBUY%TBUYsj0fSdn8onE^SPp_lA0B-&V`KSHC z^`JlSBP5CZj~iUe4Xz^_B$EGegSOnD9oZm}{Er*-2l9z-AQH&`xWUg~^0~V~GWlPl zWb!}JfS><0N+|#9IwX?+2_=yK=@#7l|8MFyy$jBPHl@gV00000NkvXXu0mjfFoVUi literal 0 HcmV?d00001 diff --git a/modular_doppler/hearthkin/primitive_catgirls/icons/organs.dmi b/modular_doppler/hearthkin/primitive_catgirls/icons/organs.dmi new file mode 100644 index 0000000000000000000000000000000000000000..dd5a091866b39f9e6193069ac9a28311e1130b96 GIT binary patch literal 719 zcmV;=0x+qPQqGHkf=X0|NKw#=e}YL=hDcDrdv1kEQG85UeoI&Bw5_*pWPwUmPOPG5CS zU*fj2;-j6RV^x7lROPj>+oh!0xxHsoYHv_u*rul5q@m%Xp1FN=kXTH%es|oZqt>UX z%&M_sRc>BZanQWQ(WtGykdWWEwt7ulids^5OzianX9m~%Sc{>G)ZlTjik7-#HX01Qa@BrKvtld zt*^AreUYv#Omiqrc6pMrk)OM-w9K2Fu|q^)K}BMhowcd9(u$$MbCkCvPkJCxeto9S zn!DhLqQiTUur*0+GfHiQqsN!L<9esj9#Mc9Q-frg$6buLYnQ-&rOhZ#cPCDGYL~!V zjk#l)#~4$D8&ZNCQh^;(fErVSq-?d%00001bW%=J06^y0W&i*HZhBN$bVOxyV{&P5 zbZKvH004NLQ&wa3CJ@sv*1_2%Ep9Gnw^1zlZ$~Hr#ufY6DuDRzknbP zc_CpDUM5j7aS2H&>le3KrgR6;~yN4$>1zz4hzJC4;0f9lmA)(k5goQ^$MnyBkc*n-YCty>M zn3SB7n#PbGo{^cAh}9d}i8;AIDlaEL8>{@V1^{mY8xH8m5v~9L002ovPDHLkV1f(S BNap|m literal 0 HcmV?d00001 diff --git a/modular_doppler/hearthkin/primitive_catgirls/icons/salts.dmi b/modular_doppler/hearthkin/primitive_catgirls/icons/salts.dmi new file mode 100644 index 0000000000000000000000000000000000000000..dfb65f36f19773cc846a61f85948d8ccc500ed94 GIT binary patch literal 451 zcmV;!0X+VRP)V=-0C=2JR&a84_w-Y6@%7{?OD!tS%+FJ>RWQ*r;NmRLOex6#a*U0*I5Sc+ z(=$pSoZ^zil2jm5sW>+^Cnqy6J-#?Gr=(bki!&v&s2C_=$iAKQfRPl%_wL>MkIaAf=qQ7boHd3z zB_$=I%_UkP$nxW-Z@~G&EO)`Qh_C>|+dnEOYE_lQiFO1NDVD3LNQ1Gu_*=N;Z{B_Y zI_3_8kRTTv-@f+}BeZY<7Ge}3gSQV3!7V>`@dksDz6O|n^6U_UZ&(hg#*yX#kmbS( zb_|eqg92*78v>3P!;w7zLvM1OQa&TZGLr@mK%=002ovPDHLkV1n2fx>*1K literal 0 HcmV?d00001 diff --git a/modular_doppler/hearthkin/primitive_catgirls/icons/special_metals_stack.dmi b/modular_doppler/hearthkin/primitive_catgirls/icons/special_metals_stack.dmi new file mode 100644 index 0000000000000000000000000000000000000000..8a7ff309998e743ca1562ecfd483c4a994f1c567 GIT binary patch literal 408 zcmV;J0cZY+P)V_Yo&W#=`8>faG>ruS005{-L_t(YiS3k23V<*SMC-!65ielH3+M^Ffe5|-RV0KU z)6)8>pn|hYd`)KI#F$?>Du}8iP+QyH4B*a!7yuXeqPASaj86jHI1Wi*B5Lx0-nj(; z-iZ}<43ESLJNrQC+>8}=ejU{lS@azQS@horzxllYI}jk^f?}jGt(5Cmdja`b6RR>X_^9JW?Gh(<|{=! zR#NuRX_>2d6gD%LbkcJ9MA1wf@lfIi0`8}I`fF!rf85VK_j~X8-p}KnbI(%!ylkxO ztsoGHjrR`9Zg8#u2Yaq1i08u&Ie=4oa$s;gCH#2UvBR6Y~m|msj`3H{(plrJTI9@qoM*w?-jV5`v3vI_{ON?;H-qG*>(72y0F| zt-O#+Z(k09SUmBjcmyVODS9MPi^CT;t0U&dbr-LEM`?dmb^pFA;#36z#}5oZo|3kd zqLBNIK1TTCB-PL^TjZ&%rPriS(pT7aXKlYisY8@rYur(Bxj5orVavvGqQuyx{FA6u zhIjSW)1Lu&J#m+%5t7nYkzbmk$X zlis(PQ(Wf6{6^KSgs&vFS{H6X04%^`sZmofJaD3CH2(7TgwcXJJ#CxT+=r+poiu&| zJQfm9=i8dfSVZEUI1Qi}zhkqgGA@`*!f%OTs7LEZ;OQP!G2iv$$h8B9ds!nF9t6=7 z-RzX;i9lihUcym+#itY|&s(IEkabedBRa=CAx=y~Ai3@2DIU)E`g~ffMyb-LH+#v4 zN`ev;gMuy~rgtL(Fzau+Rm4DwetmSrEWdJval$zc;#Eq%bvAp6wsYWivi7RvO&g!y z@%8~Xm_8|;9EN*0wn7%RS;kJvYR*ih8dOpE-wb^pZj9+9eP|o$YdE*M&6M&7LPW1Z z-Kt5~?B4?og-h$^OfV~+wOY%$ zvb4B4s?yO+J9OqPaxzAs==zw2b6$J1B&uf99d>sV?k6my-(N_D34np3w|2JsVNP2f zL_S7l^#4pA-Q4kpAW--@Pzvp&$zPvW^5}eJ{)VjEA+@cZu}jGh=Ug{^n2%9-C0499 ztrtwawe(H)Ihulszc(2hkL}Ugf7S2buWw5<=G!_8t;-ZAI5i$B)5LLt^hH;z8~~^# zJH>F5AenXWNuxn!(sJzAnID^VuM5KQE-o&Mn|gYTzsn3QrSbyn{vuZ>pwMz0)*0~P zD0V&S4OjOXb#*eLJ9^?q>QrKwSse*6q@Qh&TpgGkMICVu8HLKPR7Zl^m2l67gTqv3 zY_76~`v`h#6=RBFZ!09(L~iv>%_HP^i|9PMaZ-{L#MFSPhizJRt`h2Kf3fly0i#a> zf`B2|V7B3ZK*l&U`@MLeNX82ncl2V>wg)llK{5$*(EGMJCd z!pZ*)re$Bs&7_aFz?)Fovk_vH_OQFru%QC642=|8aT)H6fK(?eC13-_6Sh0>qvi51 z<(a+z2H`!1sOo*YomRZl$5I5!6TX}lBHczR_i>#^(zAh>m+F{?+M=xtRwt{7D$W4RYav%2i-YP{-AYu)HtjnY~${-By9uV$mwb zUTlIJ7$#^nq3?4tWynQ^zmPbN4wk~cY4VjUM?E{Ch368UFYRpqdYLU=bg{MzXjs$ L=|{P{m3HbMy^3BV literal 0 HcmV?d00001 diff --git a/modular_doppler/hearthkin/primitive_catgirls/icons/translator_worn.dmi b/modular_doppler/hearthkin/primitive_catgirls/icons/translator_worn.dmi new file mode 100644 index 0000000000000000000000000000000000000000..2934348e8eec970de0c32f220808dad0cb79c20b GIT binary patch literal 547 zcmeAS@N?(olHy`uVBq!ia0vp^4j|0I1|(Ny7TyC=g;gODB`&GO$wiq3C7Jno3=9>F zsy(N<8WaQ=&c6%SDeaHDt{2$S{)gSsd!fj+rFHhJZ=aD_cBC+F$)U`t1(9BMY%&|x zX9;XKf3vAXmm~e}yC2h!%*s91wr@F)UQhM8^f@0Ne4it-M+WFM z2ymE}Ra$#^`@Fk%W7y9=a?;B$k6iv);&Al6``^X2HW%;v_w7}ct^7&R3|X`FhuN7k ze8ZOgy>x1p&At1l!v897uU~es_w_m75dSB;x9LZ|`FDZwjK0pVl}~ej*6f%t{rU1o zj4!x)rl0=f4)?L2q?sHf){a-d$}jL`X6-8P+2#>x$o%ZZx3~(e&m|D zE-qSo`t#-$3encP|1)Rn*oSE?{l|D_mhYoaw+{M*G`#w_dwb85vmpNJ%ZFDm%&vC7 zXEez?+pP0+@_y|F7p6_zlesza$kS`(9}wP$I>UkSH9x0kx8u#~30pxzp00i_>zopr E057fQdjJ3c literal 0 HcmV?d00001 diff --git a/modular_doppler/hearthkin/primitive_cooking_additions/code/big_mortar.dm b/modular_doppler/hearthkin/primitive_cooking_additions/code/big_mortar.dm new file mode 100644 index 0000000000000..783924133f266 --- /dev/null +++ b/modular_doppler/hearthkin/primitive_cooking_additions/code/big_mortar.dm @@ -0,0 +1,224 @@ +#define LARGE_MORTAR_STAMINA_MINIMUM 50 //What is the amount of stam damage that we prevent mortar use at +#define LARGE_MORTAR_STAMINA_USE 70 //How much stam damage is given to people when the mortar is used + +/obj/structure/large_mortar + name = "large mortar" + desc = "A large bowl perfect for grinding or juicing a large number of things at once." + icon = 'modular_doppler/hearthkin/primitive_cooking_additions/icons/cooking_structures.dmi' + icon_state = "big_mortar" + density = TRUE + anchored = TRUE + max_integrity = 100 + pass_flags = PASSTABLE + resistance_flags = FLAMMABLE + custom_materials = list( + /datum/material/wood = SHEET_MATERIAL_AMOUNT * 10, + ) + /// The maximum number of items this structure can store + var/maximum_contained_items = 10 + +/obj/structure/large_mortar/Initialize(mapload) + . = ..() + create_reagents(200, OPENCONTAINER) + + AddElement(/datum/element/falling_hazard, damage = 20, wound_bonus = 5, hardhat_safety = TRUE, crushes = FALSE) + +/obj/structure/large_mortar/examine(mob/user) + . = ..() + . += span_notice("It currently contains [length(contents)]/[maximum_contained_items] items.") + . += span_notice("It can be (un)secured with Right Click") + . += span_notice("You can empty all of the items out of it with Alt Click") + +/obj/structure/large_mortar/Destroy() + drop_everything_contained() + return ..() + +/obj/structure/large_mortar/click_alt(mob/user) + if(!length(contents)) + balloon_alert(user, "nothing inside") + return CLICK_ACTION_BLOCKING + + drop_everything_contained() + balloon_alert(user, "removed all items") + return CLICK_ACTION_SUCCESS + +/// Drops all contents at the mortar +/obj/structure/large_mortar/proc/drop_everything_contained() + if(!length(contents)) + return + + for(var/obj/target_item as anything in contents) + target_item.forceMove(get_turf(src)) + +/obj/structure/large_mortar/attack_hand_secondary(mob/user, list/modifiers) + . = ..() + if(. == SECONDARY_ATTACK_CANCEL_ATTACK_CHAIN) + return + + if(!can_interact(user) || !user.can_perform_action(src)) + return + + set_anchored(!anchored) + balloon_alert_to_viewers(anchored ? "secured" : "unsecured") + return SECONDARY_ATTACK_CANCEL_ATTACK_CHAIN + +/obj/structure/large_mortar/attackby(obj/item/attacking_item, mob/living/carbon/human/user) + if(attacking_item.is_refillable()) + return + +/obj/structure/large_mortar/item_interaction(mob/living/user, obj/item/tool, list/modifiers, is_right_clicking) + . = ..() + if(. || user.combat_mode || tool.is_refillable()) + return . + if(istype(tool, /obj/item/storage/bag)) + if(length(contents) >= maximum_contained_items) + balloon_alert(user, "already full!") + return ITEM_INTERACT_BLOCKING + + if(!length(tool.contents)) + balloon_alert(user, "nothing to transfer!") + return ITEM_INTERACT_BLOCKING + + for(var/obj/item/target_item in tool.contents) + if(length(contents) >= maximum_contained_items) + break + + if(target_item.juice_typepath || target_item.grind_results) + target_item.forceMove(src) + + if (length(contents) >= maximum_contained_items) + balloon_alert(user, "filled") + else + balloon_alert(user, "transferred") + return ITEM_INTERACT_SUCCESS + + if(istype(tool, /obj/item/pestle)) + if(!anchored) + balloon_alert(user, "not secured!") + return ITEM_INTERACT_BLOCKING + + if(!length(contents) && reagents.total_volume == 0) + balloon_alert(user, "mortar empty!") + return ITEM_INTERACT_BLOCKING + + var/list/choose_options = list( + "Grind" = image(icon = 'icons/hud/radial.dmi', icon_state = "radial_grind"), + "Juice" = image(icon = 'icons/hud/radial.dmi', icon_state = "radial_juice"), + "Mix" = image(icon = 'icons/hud/radial.dmi', icon_state = "radial_mix"), + ) + var/picked_option = show_radial_menu(user, src, choose_options, radius = 38, require_near = TRUE) + + if(user.getStaminaLoss() > LARGE_MORTAR_STAMINA_MINIMUM) + balloon_alert(user, "too tired!") + return ITEM_INTERACT_BLOCKING + + if(!in_range(src, user) || !user.is_holding(tool) || !picked_option) + return ITEM_INTERACT_BLOCKING + var/act_verb = LOWER_TEXT(picked_option) + var/act_verb_ing + if(act_verb == "juice") + act_verb_ing = "juicing" + else + act_verb_ing = "[act_verb]ing" + + var/has_resource + if(picked_option == "Mix") + has_resource = reagents.total_volume > 0 + else + has_resource = length(contents) > 0 + + if(!has_resource) + balloon_alert(user, "nothing to [act_verb]!") + return ITEM_INTERACT_BLOCKING + + balloon_alert_to_viewers("[act_verb_ing]...") + if(!do_after(user, 5 SECONDS, target = src)) + balloon_alert_to_viewers("stopped [act_verb_ing]") + return ITEM_INTERACT_BLOCKING + + user.adjustStaminaLoss(LARGE_MORTAR_STAMINA_USE) //This is a bit more tiring than a normal sized mortar and pestle + switch(picked_option) + if("Juice") + for(var/obj/item/target_item as anything in contents) + if (reagents.total_volume >= reagents.maximum_volume) + balloon_alert(user, "overflowing!") + break + if(target_item.juice_typepath) + juice_target_item(target_item, user) + else + grind_target_item(target_item, user) + + if("Grind") + for(var/obj/item/target_item as anything in contents) + if (reagents.total_volume >= reagents.maximum_volume) + balloon_alert(user, "overflowing!") + break + if(target_item.grind_results) + grind_target_item(target_item, user) + else + juice_target_item(target_item, user) + if("Mix") + mix() + + return ITEM_INTERACT_SUCCESS + + if(!tool.grind_results && !tool.juice_typepath) + balloon_alert(user, "can't grind this!") + return ITEM_INTERACT_BLOCKING + + if(length(contents) >= maximum_contained_items) + balloon_alert(user, "already full!") + return ITEM_INTERACT_BLOCKING + + tool.forceMove(src) + return ITEM_INTERACT_SUCCESS + +///Juices the passed target item, and transfers any contained chems to the mortar as well +/obj/structure/large_mortar/proc/juice_target_item(obj/item/to_be_juiced, mob/living/carbon/human/user) + if(to_be_juiced.flags_1 & HOLOGRAM_1) + to_chat(user, span_notice("You try to juice [to_be_juiced], but it fades away!")) + qdel(to_be_juiced) + return + + if(!to_be_juiced.juice(src.reagents, user)) + to_chat(user, span_danger("You fail to juice [to_be_juiced].")) + + to_chat(user, span_notice("You juice [to_be_juiced] into a liquid.")) + QDEL_NULL(to_be_juiced) + +///Grinds the passed target item, and transfers any contained chems to the mortar as well +/obj/structure/large_mortar/proc/grind_target_item(obj/item/to_be_ground, mob/living/carbon/human/user) + if(to_be_ground.flags_1 & HOLOGRAM_1) + to_chat(user, span_notice("You try to grind [to_be_ground], but it fades away!")) + qdel(to_be_ground) + return + + if(!to_be_ground.grind(src.reagents, user)) + if(isstack(to_be_ground)) + to_chat(user, span_notice("[src] attempts to grind as many pieces of [to_be_ground] as possible.")) + else + to_chat(user, span_danger("You fail to grind [to_be_ground].")) + + to_chat(user, span_notice("You break [to_be_ground] into a fine powder.")) + QDEL_NULL(to_be_ground) + +///Mixes contained reagents, creating butter/mayo/whipped cream +/obj/structure/large_mortar/proc/mix() + //Recipe to make Butter + var/butter_amt = FLOOR(reagents.get_reagent_amount(/datum/reagent/consumable/milk) / MILK_TO_BUTTER_COEFF, 1) + var/purity = reagents.get_reagent_purity(/datum/reagent/consumable/milk) + reagents.remove_reagent(/datum/reagent/consumable/milk, MILK_TO_BUTTER_COEFF * butter_amt) + for(var/i in 1 to butter_amt) + var/obj/item/food/butter/tasty_butter = new(drop_location()) + tasty_butter.reagents.set_all_reagents_purity(purity) + + //Recipe to make Mayonnaise + if (reagents.has_reagent(/datum/reagent/consumable/eggyolk)) + reagents.convert_reagent(/datum/reagent/consumable/eggyolk, /datum/reagent/consumable/mayonnaise) + + //Recipe to make whipped cream + if (reagents.has_reagent(/datum/reagent/consumable/cream)) + reagents.convert_reagent(/datum/reagent/consumable/cream, /datum/reagent/consumable/whipped_cream) + +#undef LARGE_MORTAR_STAMINA_MINIMUM +#undef LARGE_MORTAR_STAMINA_USE diff --git a/modular_doppler/hearthkin/primitive_cooking_additions/code/cauldron.dm b/modular_doppler/hearthkin/primitive_cooking_additions/code/cauldron.dm new file mode 100644 index 0000000000000..911beb129215f --- /dev/null +++ b/modular_doppler/hearthkin/primitive_cooking_additions/code/cauldron.dm @@ -0,0 +1,339 @@ +/obj/machinery/cauldron + name = "stone cauldron" + desc = "Cooks and boils stuff the old fashioned way." + icon = 'modular_doppler/hearthkin/primitive_cooking_additions/icons/stone_kitchen_machines.dmi' + icon_state = "cauldron_back_off" + density = TRUE + pass_flags_self = PASSMACHINE | PASSTABLE| LETPASSTHROW // It's roughly the height of a table. + layer = BELOW_OBJ_LAYER + use_power = FALSE + circuit = null + resistance_flags = FIRE_PROOF + /// Whether it's currently cooking + var/operating + /// Lid position + var/open + /// Cauldron max capacity + var/max_n_of_items = 10 + /// Ingredients - may only contain /atom/movables + var/list/ingredients = list() + /// When this is the nth ingredient, whats its pixel_x? + var/list/ingredient_shifts_x = list( + -1, + 1, + -2, + 2, + -3, + 0, + ) + /// When this is the nth ingredient, whats its pixel_y? + var/list/ingredient_shifts_y = list( + 7, + 6, + 5, + ) + + /// Radial list icons + var/static/radial_eject = image(icon = 'icons/hud/radial.dmi', icon_state = "radial_eject") + var/static/radial_cook = image(icon = 'icons/hud/radial.dmi', icon_state = "radial_cook") + + /// Radial list options + var/static/list/radial_options = list("eject" = radial_eject, "cook" = radial_cook) + +/obj/machinery/cauldron/Initialize(mapload) + . = ..() + register_context() + update_appearance(UPDATE_ICON) + +/obj/machinery/cauldron/examine(mob/user) + . = ..() + + . += span_notice("It can be taken apart with a crowbar.") + + if(!in_range(user, src) && !isobserver(user)) + . += span_warning("You're too far away to examine [src]'s contents!") + return + + if(length(ingredients)) + . += span_notice("\The [src] contains:") + var/list/items_counts = new + for(var/i in ingredients) + if(isstack(i)) + var/obj/item/stack/item_stack = i + items_counts[item_stack.name] += item_stack.amount + else + var/atom/movable/single_item = i + items_counts[single_item.name]++ + for(var/item in items_counts) + . += span_notice("- [items_counts[item]]x [item].") + else + . += span_notice("\The [src] is empty.") + +/obj/machinery/cauldron/Exited(atom/movable/gone, direction) + if(gone in ingredients) + ingredients -= gone + if(!QDELING(gone) && ingredients.len && isitem(gone)) + var/obj/item/itemized_ingredient = gone + if(!(itemized_ingredient.item_flags & NO_PIXEL_RANDOM_DROP)) + itemized_ingredient.pixel_x = itemized_ingredient.base_pixel_x + rand(-6, 6) + itemized_ingredient.pixel_y = itemized_ingredient.base_pixel_y + rand(-5, 6) + return ..() + +/obj/machinery/cauldron/on_deconstruction(disassembled) + eject() + return ..() + +/obj/machinery/cauldron/Destroy() + QDEL_LIST(ingredients) + return ..() + +/obj/machinery/cauldron/add_context(atom/source, list/context, obj/item/held_item, mob/user) + . = ..() + if(held_item?.tool_behaviour == TOOL_WRENCH) + context[SCREENTIP_CONTEXT_LMB] = "[anchored ? "Unsecure" : "Secure"]" + return CONTEXTUAL_SCREENTIP_SET + + if(held_item?.tool_behaviour == TOOL_CROWBAR) + context[SCREENTIP_CONTEXT_LMB] = "Deconstruct" + return CONTEXTUAL_SCREENTIP_SET + + context[SCREENTIP_CONTEXT_LMB] = "Show menu" + + if(length(ingredients) != 0) + context[SCREENTIP_CONTEXT_RMB] = "Start cooking" + + return CONTEXTUAL_SCREENTIP_SET + +#define CAULDRON_INGREDIENT_OVERLAY_SIZE 14 + +/obj/machinery/cauldron/update_overlays() + . = ..() + + var/ingredient_count = 0 + + for(var/atom/movable/ingredient as anything in ingredients) + var/image/ingredient_overlay = image(ingredient, src) + + var/list/icon_dimensions = get_icon_dimensions(ingredient.icon) + ingredient_overlay.transform = ingredient_overlay.transform.Scale( + CAULDRON_INGREDIENT_OVERLAY_SIZE / icon_dimensions["width"], + CAULDRON_INGREDIENT_OVERLAY_SIZE / icon_dimensions["height"], + ) + + ingredient_overlay.pixel_x = ingredient_shifts_x[(ingredient_count % ingredient_shifts_x.len) + 1] + ingredient_overlay.pixel_y = ingredient_shifts_y[(ingredient_count % ingredient_shifts_y.len) + 1] + ingredient_overlay.layer = FLOAT_LAYER + ingredient_overlay.plane = FLOAT_PLANE + ingredient_overlay.blend_mode = BLEND_INSET_OVERLAY + + ingredient_count += 1 + + . += ingredient_overlay + + var/base_icon_state = "cauldron_front" + var/lid_icon_state + + if(open) + lid_icon_state = "cauldron_lid_open" + else + lid_icon_state = "cauldron_lid_closed" + + + . += mutable_appearance( + icon, + lid_icon_state, + ) + + . += base_icon_state + +#undef CAULDRON_INGREDIENT_OVERLAY_SIZE + +/obj/machinery/cauldron/update_icon_state() + if(operating) + icon_state = "cauldron_back_cooking" + else + icon_state = "cauldron_back_off" + + return ..() + +/obj/machinery/cauldron/wrench_act(mob/living/user, obj/item/tool) + if(default_unfasten_wrench(user, tool)) + update_appearance() + return ITEM_INTERACT_SUCCESS + +/obj/machinery/cauldron/crowbar_act(mob/living/user, obj/item/tool) + user.balloon_alert_to_viewers("disassembling...") + if(!tool.use_tool(src, user, 2 SECONDS, volume = 100)) + return + new /obj/item/stack/sheet/mineral/stone(drop_location(), 5) // Made with stone instead of iron so that it doesn't outbalance microwaves on station + deconstruct(TRUE) + return ITEM_INTERACT_SUCCESS + +/obj/machinery/cauldron/attackby(obj/item/item, mob/living/user, params) + if(operating) + return + + if(!anchored) + if(IS_EDIBLE(item)) + balloon_alert(user, "not secured!") + return TRUE + return ..() + + if(istype(item, /obj/item/storage)) + var/obj/item/storage/tray = item + var/loaded = 0 + + if(!istype(item, /obj/item/storage/bag/tray)) + // Non-tray dumping requires a do_after + to_chat(user, span_notice("You start dumping out the contents of [item] into [src]...")) + if(!do_after(user, 2 SECONDS, target = tray)) + return + + for(var/obj/tray_item in tray.contents) + if(!IS_EDIBLE(tray_item)) + continue + if(ingredients.len >= max_n_of_items) + balloon_alert(user, "it's full!") + return TRUE + if(tray.atom_storage.attempt_remove(tray_item, src)) + loaded++ + ingredients += tray_item + if(loaded) + open() + to_chat(user, span_notice("You insert [loaded] items into \the [src].")) + update_appearance() + return + + if(item.w_class <= WEIGHT_CLASS_NORMAL && !istype(item, /obj/item/storage) && !user.combat_mode) + if(ingredients.len >= max_n_of_items) + balloon_alert(user, "it's full!") + return TRUE + if(!user.transferItemToLoc(item, src)) + balloon_alert(user, "it's stuck to your hand!") + return FALSE + + ingredients += item + open() + user.visible_message(span_notice("[user] adds \a [item] to \the [src]."), span_notice("You add [item] to \the [src].")) + update_appearance() + return + + return ..() + +/obj/machinery/cauldron/attack_hand_secondary(mob/user, list/modifiers) + if(user.can_perform_action(src)) + if(!length(ingredients)) + balloon_alert(user, "it's empty!") + return SECONDARY_ATTACK_CANCEL_ATTACK_CHAIN + + cook(user) + + return SECONDARY_ATTACK_CANCEL_ATTACK_CHAIN + +/obj/machinery/cauldron/ui_interact(mob/user) + . = ..() + + if(!anchored) + balloon_alert(user, "not secured!") + return + if(operating || !user.can_perform_action(src)) + return + + if(!length(ingredients)) + if(isAI(user)) + examine(user) + else + balloon_alert(user, "it's empty!") + return + + var/choice = show_radial_menu(user, src, radial_options, require_near = TRUE) + + // post choice verification + if(!anchored) + balloon_alert(user, "not secured!") + return + if(operating || !user.can_perform_action(src)) + return + + switch(choice) + if("eject") + eject() + if("cook") + cook(user) + if("examine") + examine(user) + +/** + * Ejects all the ingredients currently stored in the cauldron. + * Called by deconstruction, finishing cooking, or user selecting the eject option. + */ +/obj/machinery/cauldron/proc/eject() + var/atom/drop_loc = drop_location() + for(var/atom/movable/movable_ingredient as anything in ingredients) + movable_ingredient.forceMove(drop_loc) + open() + +/** + * Begins the process of cooking the included ingredients. + * + * * cooker - The mob that initiated the cook cycle + */ +/obj/machinery/cauldron/proc/cook(mob/cooker) + if(operating || !anchored) + return + + start(cooker) + +/** + * The start of the cook loop + * + * * cooker - The mob that initiated the cook cycle + */ +/obj/machinery/cauldron/proc/start(mob/cooker) + visible_message(span_notice("\The [src] turns on."), null, span_hear("You hear bubbling as the cauldron ignites.")) + operating = TRUE + update_appearance() + cook_loop(cycles = 10, cooker = cooker) + +/** + * The actual cook loop started via [proc/start] + * * time - how many loops are left, base case for recursion + * * wait - deciseconds between loops + * * cooker - The mob that initiated the cook cycle + */ +/obj/machinery/cauldron/proc/cook_loop(cycles, wait = max(12, 2), mob/cooker) + if(cycles <= 0 || !length(ingredients)) + loop_finish(cooker) + return + cycles-- + addtimer(CALLBACK(src, PROC_REF(cook_loop), cycles, wait, cooker), wait) + +/** + * Called when the cook_loop is done successfully + * + * * cooker - The mob that initiated the cook cycle + */ +/obj/machinery/cauldron/proc/loop_finish(mob/cooker) + operating = FALSE + + for(var/obj/item/cooked_item in ingredients) + cooked_item.microwave_act(src, cooker, randomize_pixel_offset = ingredients.len) + + eject() + +/** + * Temporary opens the cauldron, called when ingredients are added or ejected + * + * autoclose - how long it stays open before calling the close() proc + */ +/obj/machinery/cauldron/proc/open(autoclose = 0.6 SECONDS) + open = TRUE + update_appearance() + addtimer(CALLBACK(src, PROC_REF(close)), autoclose) + +/** + * Closes the cauldron, called by the open() proc after some delay + */ +/obj/machinery/cauldron/proc/close() + open = FALSE + update_appearance() diff --git a/modular_doppler/hearthkin/primitive_cooking_additions/code/cookware.dm b/modular_doppler/hearthkin/primitive_cooking_additions/code/cookware.dm new file mode 100644 index 0000000000000..2c92a4ba45011 --- /dev/null +++ b/modular_doppler/hearthkin/primitive_cooking_additions/code/cookware.dm @@ -0,0 +1,33 @@ +/obj/item/reagent_containers/cup/soup_pot/material + icon = 'modular_doppler/hearthkin/primitive_cooking_additions/icons/cookware.dmi' + material_flags = MATERIAL_EFFECTS | MATERIAL_ADD_PREFIX | MATERIAL_COLOR | MATERIAL_AFFECT_STATISTICS + +// A few random preset types as well + +/obj/item/reagent_containers/cup/soup_pot/material/fake_copper + custom_materials = list(/datum/material/copporcitite=SHEET_MATERIAL_AMOUNT) + +/obj/item/reagent_containers/cup/soup_pot/material/fake_brass + custom_materials = list(/datum/material/brussite=SHEET_MATERIAL_AMOUNT) + +/obj/item/reagent_containers/cup/soup_pot/material/fake_tin + custom_materials = list(/datum/material/tinumium=SHEET_MATERIAL_AMOUNT) + +// Oven Trays +/obj/item/plate/oven_tray/material + desc = "Time to bake hardtack!" + icon = 'modular_doppler/hearthkin/primitive_cooking_additions/icons/cookware.dmi' + material_flags = MATERIAL_EFFECTS | MATERIAL_ADD_PREFIX | MATERIAL_COLOR | MATERIAL_AFFECT_STATISTICS + fragile = FALSE + +// A few random preset types as well + +/obj/item/plate/oven_tray/material/fake_copper + custom_materials = list(/datum/material/copporcitite=SHEET_MATERIAL_AMOUNT) + +/obj/item/plate/oven_tray/material/fake_brass + custom_materials = list(/datum/material/brussite=SHEET_MATERIAL_AMOUNT) + +/obj/item/plate/oven_tray/material/fake_tin + custom_materials = list(/datum/material/tinumium=SHEET_MATERIAL_AMOUNT) + diff --git a/modular_doppler/hearthkin/primitive_cooking_additions/code/cutting_board.dm b/modular_doppler/hearthkin/primitive_cooking_additions/code/cutting_board.dm new file mode 100644 index 0000000000000..69a1f26e06334 --- /dev/null +++ b/modular_doppler/hearthkin/primitive_cooking_additions/code/cutting_board.dm @@ -0,0 +1,146 @@ +#define GET_RECIPE(input_thing) LAZYACCESS(processor_inputs[/obj/machinery/processor], input_thing.type) + +/obj/item/cutting_board + name = "cutting board" + desc = "Processing food before electricity was cool, because you can just do your regular cutting on the table next to this right?" + icon = 'modular_doppler/hearthkin/primitive_cooking_additions/icons/cooking_structures.dmi' + icon_state = "cutting_board" + force = 5 + throwforce = 7 //Imagine someone just throws the entire fucking cutting board at you + w_class = WEIGHT_CLASS_NORMAL + pass_flags = PASSTABLE + layer = BELOW_OBJ_LAYER //So newly spawned food appears on top of the board rather than under it + resistance_flags = FLAMMABLE + ///List containg list of possible inputs and resulting recipe items, taken from processor.dm and processor_recipes.dm + var/static/list/processor_inputs + +/obj/item/cutting_board/Initialize(mapload) + . = ..() + if(processor_inputs) + return + + processor_inputs = list() + for(var/datum/food_processor_process/recipe as anything in subtypesof(/datum/food_processor_process)) //this is how tg food processors do it just in case this is digusting + if(!initial(recipe.input)) + continue + + recipe = new recipe + var/list/typecache = list() + var/list/bad_types + + for(var/bad_type in recipe.blacklist) + LAZYADD(bad_types, typesof(bad_type)) + + for(var/input_type in typesof(recipe.input) - bad_types) + typecache[input_type] = recipe + + for(var/machine_type in typesof(recipe.required_machine)) + LAZYADD(processor_inputs[machine_type], typecache) + +/obj/item/cutting_board/update_appearance() + . = ..() + cut_overlays() + if(!length(contents)) + return + var/image/overlayed_item = image(icon = contents[1].icon, icon_state = contents[1].icon_state, pixel_y = 2) + add_overlay(overlayed_item) + +/obj/item/cutting_board/examine(mob/user) + . = ..() + . += span_notice("You can process food similar to a food processor by putting food on this and using a knife on it.") + . += span_notice("It can be (un)secured with Right Click") + . += span_notice("You can make it drop its item with Alt Click") + if(length(contents)) + . += span_notice("It has [contents[1]] sitting on it.") + +/obj/item/cutting_board/Destroy() + drop_everything_contained() + return ..() + +/obj/item/cutting_board/click_alt(mob/user) + if(!length(contents)) + balloon_alert(user, "nothing on board") + return CLICK_ACTION_BLOCKING + + drop_everything_contained() + balloon_alert(user, "cleared board") + return CLICK_ACTION_SUCCESS + +///Drops all contents at the turf of the item +/obj/item/cutting_board/proc/drop_everything_contained() + if(!length(contents)) + return + + for(var/obj/target_item as anything in contents) + target_item.forceMove(get_turf(src)) + +/obj/item/cutting_board/attack_hand_secondary(mob/user, list/modifiers) + . = ..() + if(. == SECONDARY_ATTACK_CANCEL_ATTACK_CHAIN) + return + + if(!can_interact(user) || !user.can_perform_action(src)) + return + + set_anchored(!anchored) + balloon_alert_to_viewers(anchored ? "secured" : "unsecured") + return SECONDARY_ATTACK_CANCEL_ATTACK_CHAIN + +///Takes the given obj (processed thing) and gets its results from the recipe list, spawning the results and deleting the original obj +/obj/item/cutting_board/proc/process_food(datum/food_processor_process/recipe, obj/processed_thing) + if(!recipe.output || !loc || QDELETED(src)) + return + + var/food_multiplier = recipe.food_multiplier + for(var/i in 1 to food_multiplier) + var/obj/new_food_item = new recipe.output(drop_location()) + new_food_item.pixel_x = rand(-6, 6) + new_food_item.pixel_y = rand(-6, 6) + + if(!processed_thing.reagents) //backup in case we really fuck up + continue + + processed_thing.reagents.copy_to(new_food_item, processed_thing.reagents.total_volume, multiplier = 1 / food_multiplier) + + qdel(processed_thing) + update_appearance() + +/obj/item/cutting_board/attackby(obj/item/attacking_item, mob/living/user, params) + if(user.combat_mode) + return ..() + + if(attacking_item.tool_behaviour == TOOL_KNIFE) + if(!length(contents)) + balloon_alert(user, "nothing to process") + return + + var/datum/food_processor_process/item_process_recipe = GET_RECIPE(contents[1]) + if(!item_process_recipe) + log_admin("DEBUG: [src] (cutting board item) just tried to process [contents[1]] but wasn't able to get a recipe somehow, this should not be able to happen.") + return + + playsound(src, 'sound/effects/butcher.ogg', 50, TRUE) + balloon_alert_to_viewers("cutting...") + if(!do_after(user, 3 SECONDS, target = src)) + balloon_alert_to_viewers("stopped cutting") + return + + process_food(item_process_recipe, contents[1]) + return + + var/datum/food_processor_process/gotten_recipe = GET_RECIPE(attacking_item) + if(gotten_recipe) + if(length(contents)) + balloon_alert(user, "board is full") + return + + attacking_item.forceMove(src) + balloon_alert(user, "placed [attacking_item] on board") + update_appearance() + return + + if(IS_EDIBLE(attacking_item)) //We may have failed but the user wants some feedback on why they can't put x food item on the board + balloon_alert(user, "[attacking_item] can't be processed") + return ..() + +#undef GET_RECIPE diff --git a/modular_doppler/hearthkin/primitive_cooking_additions/code/millstone.dm b/modular_doppler/hearthkin/primitive_cooking_additions/code/millstone.dm new file mode 100644 index 0000000000000..0f567e8d7b071 --- /dev/null +++ b/modular_doppler/hearthkin/primitive_cooking_additions/code/millstone.dm @@ -0,0 +1,156 @@ +#define MILLSTONE_STAMINA_MINIMUM 50 //What is the amount of stam damage that we prevent mill use at +#define MILLSTONE_STAMINA_USE 100 //How much stam damage is given to people when the mill is used + +/obj/structure/millstone + name = "millstone" + desc = "Two big disks of something heavy and tough. Put a plant between them and spin, and you'll end up with seeds and a really ground up plant." + icon = 'modular_doppler/hearthkin/primitive_cooking_additions/icons/millstone.dmi' + icon_state = "millstone" + density = TRUE + anchored = TRUE + max_integrity = 200 + pass_flags = PASSTABLE + custom_materials = list( + /datum/material/stone = SHEET_MATERIAL_AMOUNT * 6, + ) + drag_slowdown = 2 + /// The maximum number of items this structure can store + var/maximum_contained_items = 10 + +/obj/structure/millstone/examine(mob/user) + . = ..() + + . += span_notice("It currently contains [length(contents)]/[maximum_contained_items] items.") + . += span_notice("You can process [src]'s contents with Right Click") + . += span_notice("You can empty all of the items out of it with Alt Click") + + if(length(contents)) + . += span_notice("Inside, you can see:") + var/list/stuff_inside = list() + for(var/obj/thing as anything in contents) + stuff_inside[thing.type] += 1 + + for(var/obj/thing as anything in stuff_inside) + . += span_notice("• [stuff_inside[thing]] [initial(thing.name)]\s") + + . += span_notice("And it can fit [maximum_contained_items - length(contents)] more items in it.") + else + . += span_notice("It can hold [maximum_contained_items] items, and there is nothing in it presently.") + + . += span_notice("You can [anchored ? "un" : ""]secure [src] with CTRL-Shift-Click.") + . += span_notice("With a prying tool of some sort, you could take [src] apart.") + +/obj/structure/millstone/Destroy() + drop_everything_contained() + return ..() + +/obj/structure/millstone/atom_deconstruct(disassembled) + var/obj/item/stack/sheet/mineral/stone/stone = new(drop_location(), 6) + transfer_fingerprints_to(stone) + return ..() + +/obj/structure/millstone/click_alt(mob/user) + if(!length(contents)) + balloon_alert(user, "nothing inside!") + return CLICK_ACTION_BLOCKING + + drop_everything_contained() + balloon_alert(user, "removed all items") + return CLICK_ACTION_SUCCESS + +/obj/structure/millstone/click_ctrl_shift(mob/user) + set_anchored(!anchored) + balloon_alert(user, "[anchored ? "secured" : "unsecured"]") + +/// Drops all contents at the mortar +/obj/structure/millstone/proc/drop_everything_contained() + if(!length(contents)) + return + + for(var/obj/target_item as anything in contents) + target_item.forceMove(get_turf(src)) + +/obj/structure/millstone/attack_hand_secondary(mob/user, list/modifiers) + . = ..() + if(. == SECONDARY_ATTACK_CANCEL_ATTACK_CHAIN) + return + + if(!can_interact(user) || !user.can_perform_action(src)) + return + + mill_it_up(user) + return SECONDARY_ATTACK_CANCEL_ATTACK_CHAIN + +/obj/structure/millstone/crowbar_act(mob/living/user, obj/item/tool) + . = ..() + balloon_alert_to_viewers("disassembling...") + if(!do_after(user, 2 SECONDS, src)) + return + deconstruct(TRUE) + +/obj/structure/millstone/attackby(obj/item/attacking_item, mob/user) + if(istype(attacking_item, /obj/item/storage/bag)) + if(length(contents) >= maximum_contained_items) + balloon_alert(user, "already full") + return TRUE + + if(!length(attacking_item.contents)) + balloon_alert(user, "nothing to transfer!") + return TRUE + + for(var/obj/item/food/grown/target_item in attacking_item.contents) + if(length(contents) >= maximum_contained_items) + break + + target_item.forceMove(src) + + if (length(contents) >= maximum_contained_items) + balloon_alert(user, "filled!") + else + balloon_alert(user, "transferred") + + return TRUE + + if(!(istype(attacking_item, /obj/item/food/grown) || istype(attacking_item, /obj/item/grown))) + balloon_alert(user, "can only mill plants") + return ..() + + if(length(contents) >= maximum_contained_items) + balloon_alert(user, "already full") + return + + attacking_item.forceMove(src) + balloon_alert(user, "transferred [attacking_item]") + return TRUE + +/// Takes the content's seeds and spits them out on the turf, as well as grinding whatever the contents may be +/obj/structure/millstone/proc/mill_it_up(mob/living/carbon/human/user) + if(!length(contents)) + balloon_alert(user, "nothing to mill") + return + + if(user.getStaminaLoss() > MILLSTONE_STAMINA_MINIMUM) + balloon_alert(user, "too tired") + return + + if(!length(contents) || !in_range(src, user)) + return + + balloon_alert_to_viewers("grinding...") + + flick("millstone_spin", src) + playsound(src, 'sound/effects/stonedoor_openclose.ogg', 50, TRUE) + + user.adjustStaminaLoss(MILLSTONE_STAMINA_USE) // Prevents spamming it + + if(!do_after(user, 5 SECONDS, target = src)) + balloon_alert_to_viewers("stopped grinding") + return + + for(var/target_item as anything in contents) + seedify(target_item, t_max = 1) + + balloon_alert_to_viewers("finished grinding") + +#undef MILLSTONE_STAMINA_MINIMUM +#undef MILLSTONE_STAMINA_USE diff --git a/modular_doppler/hearthkin/primitive_cooking_additions/code/plant_bag.dm b/modular_doppler/hearthkin/primitive_cooking_additions/code/plant_bag.dm new file mode 100644 index 0000000000000..9ceadd7057980 --- /dev/null +++ b/modular_doppler/hearthkin/primitive_cooking_additions/code/plant_bag.dm @@ -0,0 +1,69 @@ +#define RESKIN_LINEN "Linen" + +/obj/item/storage/bag/plants + uses_advanced_reskins = TRUE + unique_reskin = list( + "Original" = list( + RESKIN_ICON = 'icons/obj/service/hydroponics/equipment.dmi', + RESKIN_ICON_STATE = "plantbag", + RESKIN_WORN_ICON = 'icons/mob/clothing/belt.dmi', + RESKIN_WORN_ICON_STATE = "plantbag", + ), + RESKIN_LINEN = list( + RESKIN_ICON = 'modular_doppler/hearthkin/primitive_cooking_additions/icons/plant_bag.dmi', + RESKIN_ICON_STATE = "plantbag_primitive", + RESKIN_WORN_ICON = 'modular_doppler/hearthkin/primitive_cooking_additions/icons/plant_bag_worn.dmi', + RESKIN_WORN_ICON_STATE = "plantbag_primitive", + ), + ) + + +// This is so the linen reskin shows properly in the suit storage. +/obj/item/storage/bag/plants/build_worn_icon(default_layer, default_icon_file, isinhands, female_uniform, override_state, override_file, mutant_styles) + if(default_layer == SUIT_STORE_LAYER && current_skin == RESKIN_LINEN) + override_file = 'modular_doppler/hearthkin/primitive_cooking_additions/icons/plant_bag_worn_mirror.dmi' + + return ..() + + +/// Simple helper to reskin this item into its primitive variant. +/obj/item/storage/bag/plants/proc/make_primitive() + current_skin = RESKIN_LINEN + + icon = unique_reskin[current_skin][RESKIN_ICON] + icon_state = unique_reskin[current_skin][RESKIN_ICON_STATE] + worn_icon = unique_reskin[current_skin][RESKIN_WORN_ICON] + worn_icon_state = unique_reskin[current_skin][RESKIN_WORN_ICON_STATE] + + update_appearance() + + +/// A helper for the primitive variant, for mappers. +/obj/item/storage/bag/plants/primitive + current_skin = RESKIN_LINEN // Just so it displays properly when in suit storage + uses_advanced_reskins = FALSE + unique_reskin = null + icon = 'modular_doppler/hearthkin/primitive_cooking_additions/icons/plant_bag.dmi' + icon_state = "plantbag_primitive" + worn_icon = 'modular_doppler/hearthkin/primitive_cooking_additions/icons/plant_bag_worn.dmi' + worn_icon_state = "plantbag_primitive" + + +/obj/item/stack/sheet/cloth/on_item_crafted(mob/builder, atom/created) + if(!istype(created, /obj/item/storage/bag/plants)) + return + + if(!isprimitivedemihuman(builder)) + return + + var/obj/item/storage/bag/plants/bag = created + + bag.make_primitive() + + +/obj/item/storage/bag/plants/portaseeder + uses_advanced_reskins = FALSE + unique_reskin = null + + +#undef RESKIN_LINEN diff --git a/modular_doppler/hearthkin/primitive_cooking_additions/code/stone_griddle.dm b/modular_doppler/hearthkin/primitive_cooking_additions/code/stone_griddle.dm new file mode 100644 index 0000000000000..a78d5ef140574 --- /dev/null +++ b/modular_doppler/hearthkin/primitive_cooking_additions/code/stone_griddle.dm @@ -0,0 +1,32 @@ +/obj/machinery/griddle/stone + name = "stone griddle" + desc = "You could probably cook an egg on this... the griddle slab looks very unsanitary." + icon = 'modular_doppler/hearthkin/primitive_cooking_additions/icons/stone_kitchen_machines.dmi' + icon_state = "griddle1_off" + density = TRUE + pass_flags_self = PASSMACHINE | PASSTABLE| LETPASSTHROW // It's roughly the height of a table. + layer = BELOW_OBJ_LAYER + use_power = FALSE + circuit = null + resistance_flags = FIRE_PROOF + processing_flags = START_PROCESSING_MANUALLY + variant = 1 + +/obj/machinery/griddle/Initialize(mapload) + . = ..() + grill_loop = new(src, FALSE) + if(isnum(variant)) + variant = 1 + +/obj/machinery/griddle/stone/examine(mob/user) + . = ..() + + . += span_notice("It can be taken apart with a crowbar.") + +/obj/machinery/griddle/stone/crowbar_act(mob/living/user, obj/item/tool) + user.balloon_alert_to_viewers("disassembling...") + if(!tool.use_tool(src, user, 2 SECONDS, volume = 100)) + return + new /obj/item/stack/sheet/mineral/stone(drop_location(), 5) + deconstruct(TRUE) + return ITEM_INTERACT_SUCCESS diff --git a/modular_doppler/hearthkin/primitive_cooking_additions/code/stone_oven.dm b/modular_doppler/hearthkin/primitive_cooking_additions/code/stone_oven.dm new file mode 100644 index 0000000000000..676c49ee06d2f --- /dev/null +++ b/modular_doppler/hearthkin/primitive_cooking_additions/code/stone_oven.dm @@ -0,0 +1,74 @@ +#define OVEN_TRAY_Y_OFFSET -12 + +/obj/machinery/oven/stone + name = "stone oven" + desc = "Sorry buddy, all this stone used up the budget that would have normally gone to garfield comic jokes." + icon = 'modular_doppler/hearthkin/primitive_cooking_additions/icons/stone_kitchen_machines.dmi' + circuit = null + use_power = FALSE + + /// A list of the different oven trays we can spawn with + var/static/list/random_oven_tray_types = list( + /obj/item/plate/oven_tray/material/fake_copper, + /obj/item/plate/oven_tray/material/fake_brass, + /obj/item/plate/oven_tray/material/fake_tin, + ) + +/obj/machinery/oven/stone/Initialize(mapload) + . = ..() + + if(!mapload) + return + + if(used_tray) // We have to get rid of normal generic tray that normal ovens spawn with + QDEL_NULL(used_tray) + + var/new_tray_type_to_use = pick(random_oven_tray_types) + add_tray_to_oven(new new_tray_type_to_use(src)) + +/obj/machinery/oven/stone/examine(mob/user) + . = ..() + + . += span_notice("It can be taken apart with a crowbar.") + +// formerly NO_DECONSTRUCTION +/obj/machinery/oven/stone/default_deconstruction_screwdriver(mob/user, icon_state_open, icon_state_closed, obj/item/screwdriver) + return NONE + +/obj/machinery/oven/stone/default_deconstruction_crowbar(obj/item/crowbar, ignore_panel, custom_deconstruct) + return NONE + +/obj/machinery/oven/stone/default_pry_open(obj/item/crowbar, close_after_pry, open_density, closed_density) + return NONE + +/obj/machinery/oven/stone/add_tray_to_oven(obj/item/plate/oven_tray, mob/baker) + used_tray = oven_tray + + if(!open) + oven_tray.vis_flags |= VIS_HIDE + vis_contents += oven_tray + oven_tray.flags_1 |= IS_ONTOP_1 + oven_tray.vis_flags |= VIS_INHERIT_PLANE + oven_tray.pixel_y = OVEN_TRAY_Y_OFFSET + + RegisterSignal(used_tray, COMSIG_MOVABLE_MOVED, PROC_REF(on_tray_moved)) + update_baking_audio() + update_appearance() + +/obj/machinery/oven/stone/set_smoke_state(new_state) + . = ..() + + if(particles) + particles.position = list(0, 10, 0) + +/obj/machinery/oven/stone/crowbar_act(mob/living/user, obj/item/tool) + user.balloon_alert_to_viewers("disassembling...") + if(!tool.use_tool(src, user, 2 SECONDS, volume = 100)) + return + deconstruct(TRUE) + return ITEM_INTERACT_SUCCESS + +/obj/machinery/oven/stone/on_deconstruction(disassembled) + new /obj/item/stack/sheet/mineral/stone(drop_location(), 5) + +#undef OVEN_TRAY_Y_OFFSET diff --git a/modular_doppler/hearthkin/primitive_cooking_additions/code/stone_stove.dm b/modular_doppler/hearthkin/primitive_cooking_additions/code/stone_stove.dm new file mode 100644 index 0000000000000..b7ea86609802e --- /dev/null +++ b/modular_doppler/hearthkin/primitive_cooking_additions/code/stone_stove.dm @@ -0,0 +1,70 @@ +/obj/machinery/primitive_stove + name = "stone stove" + desc = "You think you'll stick to just putting pots on this, the grill part looks very unsanitary." + icon = 'modular_doppler/hearthkin/primitive_cooking_additions/icons/stone_kitchen_machines.dmi' + icon_state = "stove_off" + base_icon_state = "stove" + density = TRUE + pass_flags_self = PASSMACHINE | LETPASSTHROW + layer = BELOW_OBJ_LAYER + use_power = FALSE + circuit = null + resistance_flags = FIRE_PROOF + +/obj/machinery/primitive_stove/Initialize(mapload) + . = ..() + var/obj/item/reagent_containers/cup/soup_pot/mapload_container + if(mapload) + mapload_container = new(loc) + + AddComponent(/datum/component/stove/primitive, container_x = -7, container_y = 7, spawn_container = mapload_container) + +/obj/machinery/primitive_stove/examine(mob/user) + . = ..() + + . += span_notice("It can be taken apart with a crowbar.") + +// formerly NO_DECONSTRUCTION +/obj/machinery/primitive_stove/default_deconstruction_screwdriver(mob/user, icon_state_open, icon_state_closed, obj/item/screwdriver) + return NONE + +/obj/machinery/primitive_stove/default_deconstruction_crowbar(obj/item/crowbar, ignore_panel, custom_deconstruct) + return NONE + +/obj/machinery/primitive_stove/crowbar_act(mob/living/user, obj/item/tool) + user.balloon_alert_to_viewers("disassembling...") + if(!tool.use_tool(src, user, 2 SECONDS, volume = 100)) + return + deconstruct(TRUE) + return ITEM_INTERACT_SUCCESS + +/obj/machinery/primitive_stove/on_deconstruction(disassembled) + new /obj/item/stack/sheet/mineral/stone(drop_location(), 5) + +/// Stove component subtype with changed visuals and not much else +/datum/component/stove/primitive + flame_color = "#ff9900" + +/datum/component/stove/primitive/on_overlay_update(obj/machinery/source, list/overlays) + update_smoke() + + var/obj/real_parent = parent + + if(!on) + real_parent.icon_state = "[real_parent.base_icon_state]_off" // Not an overlay but do you really want me to override a second proc? I don't + real_parent.set_light(0, 0) + return + + real_parent.icon_state = "[real_parent.base_icon_state]_on" + real_parent.set_light(3, 1, LIGHT_COLOR_FIRE) + + overlays += emissive_appearance(real_parent.icon, "[real_parent.base_icon_state]_on_fire_emissive", real_parent, alpha = real_parent.alpha) + + if(!container) + overlays += emissive_appearance(real_parent.icon, "[real_parent.base_icon_state]_on_hole_emissive", real_parent, alpha = real_parent.alpha) + + // Flames around the pot + var/mutable_appearance/flames = mutable_appearance(real_parent.icon, "[real_parent.base_icon_state]_on_flame", alpha = real_parent.alpha) + flames.color = flame_color + overlays += flames + overlays += emissive_appearance(real_parent.icon, "[real_parent.base_icon_state]_on_flame", real_parent, alpha = real_parent.alpha) diff --git a/modular_doppler/hearthkin/primitive_cooking_additions/icons/cooking_structures.dmi b/modular_doppler/hearthkin/primitive_cooking_additions/icons/cooking_structures.dmi new file mode 100644 index 0000000000000000000000000000000000000000..296899c42af563d4dfa9c7a5fef3bc6765539df6 GIT binary patch literal 628 zcmV-)0*n2LP)V=-0C=2JR&a84_w-Y6@%7{?OD!tS%+FJ>RWQ*r;NmRLOex6#a*U0*I5Sc+ z(=$pSoZ^zil2jm5DJe5OJ~zLpB(X?|i!&v&s2C_{$iY00FQ`L_t(|oMSw2-~huw0tW|&0kxlLKy4oc zU^D;*+5rO%Mgw4=9Wc;f#0LNiDT=SpFa57)ri@q3rBinqG!wfSDRLDZ0V6T(0FcK) z^qymnh%(g0N)AjD6A-xC0l})`|B14UNU-+yORR1om;zw2-Zx=C(UyS%s;Iz`;Sx|U zIjI5Uc`*qg20bMnQng|Qm+pOG2xegTk1Y`JmI35=9tJ>qKzd=RXRrd2%77PNe-fom zf}5Qz#|#9(8vw984@%ButviS|6ckWh)gIsi5oCsDB4v)GB_LQ0g7Oc@BQdV3L>mfH z3(^D9JJV=-0C=2JR&a84_w-Y6@%7{?OD!tS%+FJ>RWQ*r;NmRLOex6#a*U0*I5Sc+ z(=$pSoZ^zil2jm5sUW{ZiHkEOv#1!zGvwk-D@x2wg|Ly;#HVHE(*1K~#90?V3Mm6hRcmHzG%bwAWaO zL>rSbMFc@PuMi0$7O@IK>@5ThB!z`V0?{u0U1OCLB0iLgR&t3w|0JZ=&W&m3N8#90{ zfX(r|f4q8SDa2>3ep&WcR&Gxer0Gb>Y=8#-aQ(jQpFVX`KF`m0e?MCzwI3S4tiF~C#ELFh%aBi1rOF91utGcNqt=QOfYo|(BL=Lw`5*YFMsw5Z>-bZWiotU6qrDzbi2ETgmrUVZvl}d;$>+w>L z0%+!J;#d9Sr>>OGo~g>V^RyLYH6hUe*OhGTy^=g|7(c%MlrBZzSP009OvJ z!1X(VhaqvIxuNVc#Kab$0U#g5$9@;+0>hpM6vfythRguA05+-D0{uSSUjok^T1UtK zQR)96vrwHIV2HyApc!As{;a{5ejX4oiMsM8l|fqCHEbnQM>WsV(gQk8Ne36 z#tdK!U}FZb1+Xy#*aFy?0c-(m%mB6kHi@gjZnrzo)17LyTIyA!R~&+mJ^<1C{#iIT zGwn5jeM7`4OoMmb{z?n(8u?6M8!+}czzkpuU}FZb1+Xy#*aFy?0c-(moCaVPsIS2c z%B`ilg&b!XI2S{Io&h$(K}|sLWqxj$_>K@v@YT_$!Y;}jJV^bH(Eo}hLAC%kW&m3N j8#90{fQ=cz7Qp5g?t2jR-(l^Z00000NkvXXu0mjf*~q2# literal 0 HcmV?d00001 diff --git a/modular_doppler/hearthkin/primitive_cooking_additions/icons/millstone.dmi b/modular_doppler/hearthkin/primitive_cooking_additions/icons/millstone.dmi new file mode 100644 index 0000000000000000000000000000000000000000..ba7d14985cb3a8671ffaecb1f2e1e68564d75c38 GIT binary patch literal 1847 zcmZvacT^Kt8pVT%xCu=Jf+&O13Cu)HD61mU6JdaX2&{xK6hQ=(IuKeAAs9eJP$|+o z3`G}FN+c^FO(67uQL{)SkWfZK$^=L@&L02Sv+tbu?svXF-nr*@FTvH>K^CY61ONcC zNQAAMSbr7YyrW0NFAsR@j95w%P+l>%*P{cXLLy>9Zr=g`;!E8yY3NRIdq8Q zkC4f6viq~EXQyHR{%k~cG8hF!<=pQwhq=LKVOK7nQ$fGgA?P$+u6Mf?ch|Kxl%U9+*q)BP27xm+f6$WueJ^DqJdOyQkj+%i>)}mjEaE;pMO5`gipBG`UAItQu{Y_xvDJ&O#w+>-f%WIw_hXBG4Ry6?506t~823 z$C$}=eA2-dV|7$7S7wK*n^H*Y0ajy96JFr-;mfnOEh>OZEwTz!kUwEFxsy*hF2W7S ztJ?@YB-eb;y7?S--x4UoJW0IlBFN!})7o29_UhX9#jLKF^}W@R>48>x&E3di;A%c3 z%>U*=N3ctRh7@9NowtjO4a0?=V1~A`C?d2*2qB1jl!MuTWU?`Y6wbBr?cT}tB>75} zbBT8dOOoRb9i}K&CeUEhGG%}I1}?{pz6}SIRRXOX)VF*I{)Uzgq*!I!6?IOk67ES2 zd2V>O=;}!6{({4?o7{#PNIHw!#4<%`=0{VOb@prqTv|vSYFms-0q&ZOa zt2Tj*kMlOP(36N$EX|@V08Wv3ex<_e=_ww{@>j1B2uiF!6c1ij<*dBo;x{*E4Rstl z<#N}PqjxWWY%|V!N*oSW|J1M(%}xZx3W^z?tMmZx6MS85=PwMpyh@JPD+Hm@t)|ue zxFXw<4}RX>w;xskxfibNUodnppy?wSqJ95?O|4CFug3Sff75#DowW3W5s)HR3yN5L zKs@b-dqO-tX_v>v@mI4Az2`396s=*cj5G8nMBL~G4@kh;EOlA^sm*@P_M-~T1qF$jdS#<`vsbK-Vp`ZNEIJbwe zfJQ#joRQu*Qfv%glZzL14!b`da17%*L&h8L82d4#UPnd+d^B7~IGMCNycbsuQHwuv zerP1XxWH{IaQj8!U8d%mD2kz6x6{E+J8A;YDW# z&@!Ver16<2rJjS6pe!H5!g7k%W-vo41CMW_a}ayk??7W^lmJ0A1vi7WGT2GL^Cx)C zBY!RPdxhW8SS}GOQCJH!uJP17L#l3!wJeyRbO}dS|2r$&u)e{w{9l^lh3=a4cjBq4 zFDg8HWI8gq?7o=YKeBRXt{3aXd|j8Ttcm$Ymu>iz{-37g*U1J?7DH8%lA3Q*Epd@? z$tea{3jv;apf{;h01oU8`YBDSp6b2nR(nNJ=L=_T59>Gzs?M!yTN<|XIr#}t6~5Qk zFXmCh)n6RbEe6*XhPp})uIlntVeO2C2Q>JDaP_W^3d-}l_L@+{?bN9$)yH7^`-=GBCY&V()Anu~G?4BL-~{D@&=|&?>Tt4JPlI2G*)yh@?x+Z$K|W8-JSu z^jAuxixVsUD=J#Iq<_Bk%`ukosE^25auAQ2%clg0IoeH1=zLMWFM9#nD6hj1b6>(* zp|K%YiV=-0C=2JR&a84_w-Y6@%7{?OD!tS%+FJ>RWQ*r;NmRLOex6#a*U0*I5Sc+ z(=$pSoZ^zil2jm5sURmYuOulkJ-(nQGdHs&vn*AKi!&v&s2C_|$itvYZc4s!V2K|bdb)r>hO76Pw}5MAe)UF&TTl62~VvfG`jM>+CBQ?ZvCL5k)NY z3lecP3mzd^^!r}jOfwT=SvPHuRoB8v&hxQjfq4{zx_A=vNS1;!#EX$%yl9~Z1H0;7 zM!gKy@y5a@1)wH&{w;u-o!;o>1VXI)>U-P*K_8E`WPpMI0068>L_t(oh3%HH4g(N*(eB2JDz@I0VOWoL>;*o{zviCq~l62yD!W9txPtWvV5k zfW(oW3J9oes;z>6C{R~GKyOoRJ+1?o4;ofG`jM>+CBQ?ZvCL5k)NY z3lecP3mzd^^!r}jOfwT=SvPHuRoB8v&hxQjfq4{zx_A=vNS1;!#EX$%yl9~Z1H0;7 zM!gKy@y5a@1)wH&{w;u-o!;o>1VXI)>U-P*K_8E`WPpMI006H^L_t(oh3%Hh62l+} zMFZN{AW8oJZ>vnYs*ud2oo?<~3ZC(?;7$_&0Q?Lhr@+_tbIQpnobG*eI44gq7wagq zCwO+4Qg#H3Scfd0pmvyO{0dA}tV3#e59M`y2R(m-w_$t&^?v8GQ+2$4RR9100DO^c zi>hw=Fl_FZNWjkMKd`yKOC)g8%Ry~}zr+GdA3<1>PAF)ki)m|wQcEA}ojI@V1ov`+ dmp;H>c>yrm1A6m*V(Qv2i_e@XsywlzFgq}zpEoE|2W>NqE$W>Jo^>BH|-;&xZ~ejr2^SNE~(a8tu7dCfm1$Jr&G)(eK+>_#Om!hB6xz z@Ec~5NTZjXe}6)0NILpdjF!@2eo{Wy=8g^e!-tM}mf7AnC|N-R8=F!{qg9>hB5VX*Py?wstCwMoMFwEUM(tWJ$?DP(;AK)R69%Ibh{ z#(qG$uy{vD$4im>w0M8{uvb_h_2I`Pi%Nlbi~&J-tKR)o{G{Z zB)ME7+F8{bKWg$j(s(X-u@zQd?=yy`2C3ZkR z@zUk%*4z5}6F+5T9+@m5(Lxf!km8C8`k|tnJc$WJ`U@QWIF4Lx92d}TVI#IVh zIf!or*|w47SIWUuDX3cZlQOKUleShw=ZCdX+*f$xH!OUS*F#5Sr740btz5*doC6@@ zT$2G40!J5%q;aAj1|h#6H2DW!pPvWAc>u2M4;w{A)rH#>oqHQau4P6y_h8-_(Z`5c zC|-m3aEn_)Gt}XE_x_I0S39=kENd5qLg#!-6Kvv}x6ISB!o*8`dMRJx^AT2pwaE-3 z`IWA)ZNh(+2U90Z+OHvFVgr(~x&FTcl2j~VFb@P7e#n!-!NH}O>O7{2&~EC1N$Dmf zdF=UE%5UJNcIyu4@*sXq;Oz*Zw(8?X4OU@l@r1L=Ey}H~|_dvwOxd0tO zC#~F01J1-h?#nXzt7bl4*ulP`|$2Y+EDP`frjumGbz@ArdxGQ{+bI=3A+}ALQMP{eL-_6R_efu zvwrO~z3ZC;N}-|x|Dc}C#Obrf6pVMFP!qY1bM>{!@c5q3(@vho!djGB`k$cKIvQGI zJieXV=c=@Lzkc#Ch)RTEj?0A3HQh!J*pksa;wS~HO>O<%#HO?Nb*~Jj(m((%*Dxpf z)N7iWn1wm66l%ivTd}N7g%{1=$&64$ErEP_PzUD)2S z=wtaW8_(Xs&t5VT_t`@%a4-Xu62<9z^VxF*i; zeXyHZxJp*o?Ba*jsLHitn|*+Nd$~v5Ou+9J%lg&j#1b=YfjoBD+OhWzpaIS}|E%W{ zA~Sszij7Ns>Eq=^lyPE>IcZN{z^X50a$IiL@L%r6qClJB6W7Z1#p?`XO(!9u{u$n; zW4`tr0T=T??OmUK5FqUJ^RCZb;-?!*QhS`GTk&ymzzl&E4}#W;kVa~cXW36`7VH^- zw*!eOE^qmZu*jND6xW)wbxYwRI=RE4(|`D1azsi&U4_!ElMiY~4W1Oy>-YQWX;K6rq6 zjrS%T^IYotDLBgkbAqBQx=Q1MElMM@+`N>M+Fwz#NJX}(djp7d?0lnr5VL17(&i}@ zFe>@^vM3nICJST{x-lUISe9!KLTsFYxVoB6Y2zdnG?d7yJ-^Xsw*b{$#S=Hvc_j=D zA^=8xCrJUf&uIv2^eTY(HN*iRCMuv-CPi2JQbw)dZqEyZ!jv5hn%K|@2snJQ~p zWcUcN3#!Vxb^G|{{e9yPC6k0R&BLYrJjJtTOP`GorPOsT6TymkH2{#OYidQz-O4Pi zmEd3o(aFnd_s$e=TRoyLs2Nhsa1AXe6)L077^40u7AT1O+7X8RA0^~)GyT|nF9qAV zhM&it+k`_YIZkZZ7U~NrV8+|6AL_G$I2TjEey4*&pU-8HhzFd>dF{tJMB@;h4Iw$H zKSVFKqaOpJ^nH76{O29|6jM{g>E$9tDcZRHr)k#Lv(rAVI;%3`d;aZZCdiLf4muk4WClpR6LishbOR*Mcon*4JC012W{bSeOs{>YtN^7jBkqh0<3s z6di2QNngP;9?a2s-hlxE1JFyA3UzP1I*jEnw1H{WY|5$3`&Xf16+(=x#>+F8RkP4U zp0E9McPuuAnE$aDxpaTWoNYl#%+#Ljtj1v*2v8jk=gYpo^+K*3pX%XtMMe0M2iv>% z?#9zk9d^>vr+aE*_voW2K34}%&BTsZ8AQ0TOwU^l;rnIr_xRr;DR## zmJ4dJRiSR1C{Iqthk~W8-N^0YaHc7DTqq)SWhA>LaYB#p?mObIwlOH%hXt2Si!SvB zR^uB{&Q* z3YJ1)33Ty({uKP-P(lcAw>)&HG$83%PkBIcwi7zuBost!_6TwGBQ@n=cAA3HN7b7U z&VeTOk9fvbCB`_t&{2NF66<@Hx%J(LUi%hWV8&T+`dzXQ;%9t%*h-gy(0h;M@jrTa z?I@uVa$(EgG9r_o=rDFEK$&r6Z-IK3wWLv{MXY|2)-9JL<~!UeAOD>9N5?00D&M94 zsDYmN`X;Pd){u5}CAMF00>|kZLR4r)%hrH8tLD3N`g;WlUe zVBJl7Yinj}R$m;OAv8<8VLmo4P76Tvq3wG4%G7k_^1!^Z^sgbpNLC7EoT_^2{|J|M z52aJ%SN6@^q!ySS!|N=exS7Kbi5!hub_>0dwd`6Z9?np$9qK`bCFjD^z{S=-)ndPm zJ%-5Y2KH|g@b{h_hK2sjVZCo;qH1~9fr6br`vvdar(B8W^FYCB_r_Dp7(W?72YE}J ze0gbjZ(nnSoYS@z zrhevwr@u84~MIg=7&Z5WfbO>CxS#cb$IhpOMfEE(VyZ-E#(=GR#ybrN>)nlkzp zA0mef%bVEfhQ!1jugXO&e`^~s9}kbgDU~GExxPckoVvC|L*_>@vG;!2{0_LrvAd0p zP4Lye2gbMMI}7Q-+1>LH(Ys4**PDojSsA*CAPT@@AOY*FmG)Dn2SeZr<@**sO&c3q zpS;={Fj?Mzq&9?uJd$8`;{P~!1;-T(Hl7-2A1z0YBiTrGOaB&>ydLQA^@Q`NrN>a{ z@c(;f6r{!nX~|j+3jZ`&{PQKZfCR4`MEdk#O;+3550h3}ZB{!qeM{laa{raEvZl*o zb3wXIDrIn|yE?AfZE8`kx(xY>CqkyR#k^{qPl$L6&JGn_cwgZ4ycE$?OBN&Qr%OxY zusm9>8=nTh^oG^VflTGb$O%IpzzSHEs__3lAMmVybkYT19aee~*w)BQ!P!^5_E@7g z@S!vBdt5CysudDVFTjt+t?6oFzXq2@y>Dl4Lv>$IjMTrVFP!Psi=fob?_y*?ji%mA zR`82pt4$sZ!@i5&+-J*rI0RA?fXHx=p+?b*N=wG>$)$htw}j=?#33@eb5#^N|BefH z0jWXM-{Ii?22vCGTSM0)(}|x$|0Q^p-X_p5w{~C~C^=eI26pkPXgf%R2_pKAjZMh2 zd1x}TI+`il=apyAFr0^tCpkGg1U+#sVL3H-I=p*MARsY;km*Jafd}=8!=Jug0-?<+ z{2+?9nOJ0nbi)5rEn@Fg4qGWc$+(ZS3f#nm2UmT91@KK1E#S^#!}Js58<#Ow=r0ur57SFAD>^HsMQ*YG=Z$flC3C`@apo{05y^_+b?CF+myOyhLVfX4H$L|&3TdmYY?=7Lv z=_KKVHM1F$B$IBCTrbr!Jdva6^SBPi!ttZobK%}0U;IKZ_Enx_E*lnv>*l$HOxx|r za}x1S)$*)^uV|qXEG#*u4mj((?DJI=`G(`_awiGQCBjV05M*yp{PgM5(yiKt22NHj zNnm_hDVr4$GQZcGq|ME}V&nu5w&{zDDl{}ht)3@h9wmSet=6e^oZxsOwOMy^=#IV7 zcVpOV5o!RFy{sH)>wcv+MFPS8v(t;U5v!8jOJeCI_ps5?V+D^Pp|`%s{|PMtQ)=no z0KoXzky@HMG{=)ursDY|X7XcpFsnSC2YI%tYc;Rv+tYe_mbruSu)gzz?e@Yww+-4C_Z@y`nA%;a_5dR#j4vD{PmnQ6bT1syJ742@+T}g zm{=az@o@=x0@x8{KR%KTfzj|On3=sj*x!Ims307t<-VY) z=ZbJ%-H4O@>T){?Om&a^5uiJs@NWTuZ(hNO!w!-!*Vu zHB1#k_0>@u>2y;!Ljf8y0;M~zWo}TPN472pK(-!mtVGt9W7vo!N%n!I$Wb8p@0E3* zE(SyPYGDK_@g!1m54Cmhc0>{pIh`i5d?wBKSaRhO<2-r%CZN7^W9RLNFDnFvK0MEQ zO@8oBJvBs!&;J^N;(9~L{mb-L_CXNB+Er`Ab%|&EA*97(Yde5gaGJXQ_3|Y~EFhr% zUV|Wk8;h)Ld~Rtezd(5a77P#q5AdtV&Y)7RSXo(1@L7DaSbWR#56V~08Fr5jcUl3X z-}xht5mQIY#}uc*MuvtUAh?sgw5;qIZqC|{Cw}2OvE8xI&Uoa>yfcmBN#izi@LwNv z=uB6{Vn?;zadxPCC(=qdA~lt1j6?vZWfoi{w-~A*u>>nQy_)Y=F@KHK^M7Z)e7WI8 z5BD3+tFFS{G7-Q?z0e1uU3i{?hoOX-ciq^a_uWJ+bb*2%9%{1cIwS;Zd z$U$v94!|xL*!tBaaLk! z<5}$UrZkx#tqV5~O~=6N#UXvb1s7jln&!=QgxSf2j>aARCzul+xaTTb+IJDCVw94> zQ=Z@g){fs?1VzLgom<Bb#7vM7QnEp+;WA4P0t(n(Oc8 z6~dR$4Pi{&^`r?tFd4sjAFe1%%7yGhnj7jr4 z?HP253oAGY0@8L|S97l%26LF>$Rp!I+LjjrAU#Wc8@_X=oz)UR-`sOdrn*M2wO>8B z%2LnVj29AwnpE7{HxUPQuPX*#{~C&nAJ06Aj@p*q%kHY)W}CYH*KJEJUT2)#a$}Vu z|D>hYwo9wGgVP#sn<&W8{$V3QX{wK0$44sR-{t7CWkEp;eig%MPLTY{a>&2brua_3 z$~$)`U9#xs0U;qF>4`b<9+Pxr-4pp$;yVbNZC%#`f_7^O`j`VK^*7X^N)f;HG&HhqNrQ>Uv~m#IK|$)b%3> zMTLbsvV?RmRrU$jAjhJUu}pa-#l^h+$UHq~`dqgJRwgYMAq@^1+}jNyy>C;|0zKm~ z{c*q3zn9b7I)UjNkBL+;fV<@v-K+M-cgNfxFM16hXy)kSFn*17;4GS9w$uF^Sqo!K z_8W>Y^GwcsjyDfRaZ{z(AYc)=(L$l(l&F2-2fOkp#U=xZtOy6jUoHON9Gzk^#1a+J ztNE30zFoMWla8nYls!l~V1IbXUx+z#q~ODErtOqgX*{e}q#IpB-)pGThere are currently [has_ants ? "" : "no "]ants in the farm.") + if(!has_ants) + . += span_notice("To add ants, feed the farm some food.") + +/obj/structure/antfarm/attackby(obj/item/attacking_item, mob/user, params) + if(istype(attacking_item, /obj/item/food)) + if(has_ants) + balloon_alert(user, "ants block the way!") + return + + qdel(attacking_item) + balloon_alert(user, "food has been placed") + ant_chance++ + return + + if(istype(attacking_item, /obj/item/storage/bag/plants)) + if(has_ants) + balloon_alert(user, "ants block the way!") + return + + balloon_alert(user, "feeding the ants") + for(var/obj/item/food/selected_food in attacking_item.contents) + if(has_ants || !do_after(user, 0.5 SECONDS, src)) + return + + qdel(selected_food) + ant_chance++ + + return + + return ..() diff --git a/modular_doppler/hearthkin/primitive_production/code/ceramics.dm b/modular_doppler/hearthkin/primitive_production/code/ceramics.dm new file mode 100644 index 0000000000000..a7105a0ca4359 --- /dev/null +++ b/modular_doppler/hearthkin/primitive_production/code/ceramics.dm @@ -0,0 +1,265 @@ +#define DEFAULT_SPIN (4 SECONDS) + +/* + * Clay Bricks + */ + +/obj/item/stack/sheet/mineral/clay + name = "clay brick" + desc = "A heavy clay brick." + singular_name = "clay brick" + icon = 'modular_doppler/hearthkin/primitive_production/icons/prim_fun.dmi' + icon_state = "sheet-clay" + inhand_icon_state = null + throw_speed = 3 + throw_range = 5 + merge_type = /obj/item/stack/sheet/mineral/clay + drop_sound = SFX_BRICK_DROP + pickup_sound = SFX_BRICK_PICKUP + +GLOBAL_LIST_INIT(clay_recipes, list ( \ + new/datum/stack_recipe("clay range", /obj/machinery/primitive_stove, 10, time = 5 SECONDS, crafting_flags = CRAFT_CHECK_DENSITY | CRAFT_ONE_PER_TURF | CRAFT_ON_SOLID_GROUND, category = CAT_MISC), \ + new/datum/stack_recipe("clay oven", /obj/machinery/oven/stone, 10, time = 5 SECONDS, crafting_flags = CRAFT_CHECK_DENSITY | CRAFT_ONE_PER_TURF | CRAFT_ON_SOLID_GROUND, category = CAT_MISC) \ + )) + +/obj/item/stack/sheet/mineral/clay/get_main_recipes() + . = ..() + . += GLOB.clay_recipes + +/obj/structure/water_source/puddle/attackby(obj/item/O, mob/user, params) + if(istype(O, /obj/item/stack/ore/glass)) + var/obj/item/stack/ore/glass/glass_item = O + if(!glass_item.use(1)) + return + new /obj/item/stack/clay(get_turf(src)) + user.mind.adjust_experience(/datum/skill/production, 1) + return + return ..() + +/turf/open/water/attackby(obj/item/C, mob/user, params) + if(istype(C, /obj/item/stack/ore/glass)) + var/obj/item/stack/ore/glass/glass_item = C + if(!glass_item.use(1)) + return + new /obj/item/stack/clay(src) + user.mind.adjust_experience(/datum/skill/production, 1) + return + return ..() + +/obj/structure/sink/attackby(obj/item/O, mob/living/user, params) + if(istype(O, /obj/item/stack/ore/glass)) + if(dispensedreagent != /datum/reagent/water) + return + if(reagents.total_volume <= 0) + return + var/obj/item/stack/ore/glass/glass_item = O + if(!glass_item.use(1)) + return + new /obj/item/stack/clay(get_turf(src)) + user.mind.adjust_experience(/datum/skill/production, 1) + return + return ..() + +/obj/item/ceramic + icon = 'modular_doppler/hearthkin/primitive_production/icons/prim_fun.dmi' + var/forge_item + +/obj/item/ceramic/attackby(obj/item/attacking_item, mob/living/user, params) + if(istype(attacking_item, /obj/item/toy/crayon)) + var/obj/item/toy/crayon/crayon_item = attacking_item + if(!forge_item || !crayon_item.paint_color) + return + color = crayon_item.paint_color + to_chat(user, span_notice("You color [src] with [crayon_item]...")) + return + return ..() + +/obj/item/stack/clay + name = "clay" + desc = "A pile of clay that can be used to create ceramic artwork." + icon = 'modular_doppler/hearthkin/primitive_production/icons/prim_fun.dmi' + icon_state = "clay" + merge_type = /obj/item/stack/clay + singular_name = "glob of clay" + +/datum/export/ceramics + cost = CARGO_CRATE_VALUE * 2 + unit_name = "ceramic product" + export_types = list( + /obj/item/plate/ceramic, + /obj/item/plate/oven_tray/material/ceramic, + /obj/item/reagent_containers/cup/bowl/ceramic, + /obj/item/reagent_containers/cup/beaker/large/ceramic, + ) + +/datum/export/ceramics/sell_object(obj/O, datum/export_report/report, dry_run, apply_elastic = FALSE) //I really dont want them to feel gimped + . = ..() + +/datum/export/ceramics_unfinished + cost = CARGO_CRATE_VALUE * 0.5 + unit_name = "unfinished ceramic product" + export_types = list(/obj/item/ceramic/plate, + /obj/item/ceramic/bowl, + /obj/item/ceramic/tray, + /obj/item/ceramic/cup) + +/datum/export/ceramics_unfinished/sell_object(obj/O, datum/export_report/report, dry_run, apply_elastic = FALSE) //I really dont want them to feel gimped + . = ..() + +/obj/item/ceramic/plate + name = "ceramic plate" + desc = "A piece of clay that is flat, in the shape of a plate." + icon_state = "clay_plate" + forge_item = /obj/item/plate/ceramic + +/obj/item/plate/ceramic + name = "ceramic plate" + icon = 'modular_doppler/hearthkin/primitive_production/icons/prim_fun.dmi' + icon_state = "clay_plate" + +/obj/item/ceramic/tray + name = "ceramic tray" + desc = "A piece of clay that is flat, in the shape of a tray." + icon_state = "clay_tray" + forge_item = /obj/item/plate/oven_tray/material/ceramic + +/obj/item/plate/oven_tray/material/ceramic + name = "ceramic oven tray" + icon = 'modular_doppler/hearthkin/primitive_production/icons/prim_fun.dmi' + icon_state = "clay_tray" + +/obj/item/ceramic/bowl + name = "ceramic bowl" + desc = "A piece of clay with a raised lip, in the shape of a bowl." + icon_state = "clay_bowl" + forge_item = /obj/item/reagent_containers/cup/bowl/ceramic + +/obj/item/reagent_containers/cup/bowl/ceramic + name = "ceramic bowl" + icon = 'modular_doppler/hearthkin/primitive_production/icons/prim_fun.dmi' + icon_state = "clay_bowl" + custom_materials = null + +/obj/item/ceramic/cup + name = "ceramic cup" + desc = "A piece of clay with high walls, in the shape of a cup. It can hold 120 units." + icon_state = "clay_cup" + forge_item = /obj/item/reagent_containers/cup/beaker/large/ceramic + +/obj/item/reagent_containers/cup/beaker/large/ceramic + name = "ceramic cup" + desc = "A cup that is made from ceramic." + icon = 'modular_doppler/hearthkin/primitive_production/icons/prim_fun.dmi' + icon_state = "clay_cup" + custom_materials = null + +/obj/item/ceramic/brick + name = "ceramic brick" + desc = "A dense block of clay, ready to be fired into a brick!" + icon = 'modular_doppler/hearthkin/primitive_production/icons/prim_fun.dmi' + icon_state = "sheet-clay" + forge_item = /obj/item/stack/sheet/mineral/clay + +/obj/structure/throwing_wheel + name = "throwing wheel" + desc = "A machine that allows you to throw clay." + icon = 'modular_doppler/hearthkin/primitive_production/icons/prim_fun.dmi' + icon_state = "throw_wheel_empty" + density = TRUE + anchored = TRUE + ///if the structure has clay + var/has_clay = FALSE + //if the structure is in use or not + var/in_use = FALSE + ///the list of messages that are sent whilst "working" the clay + var/static/list/given_message = list( + "You slowly start spinning the throwing wheel...", + "You place your hands on the clay, slowly shaping it...", + "You start becoming satisfied with what you have made...", + "You stop the throwing wheel, admiring your new creation...", + ) + +/obj/structure/throwing_wheel/attackby(obj/item/attacking_item, mob/living/user, params) + if(istype(attacking_item, /obj/item/stack/clay)) + if(has_clay) + return + var/obj/item/stack/stack_item = attacking_item + if(!stack_item.use(1)) + return + has_clay = TRUE + icon_state = "throw_wheel_full" + return + return ..() + +/obj/structure/throwing_wheel/crowbar_act(mob/living/user, obj/item/tool) + tool.play_tool_sound(src) + new /obj/item/stack/sheet/iron/ten(get_turf(src)) + if(has_clay) + new /obj/item/stack/clay(get_turf(src)) + qdel(src) + +/obj/structure/throwing_wheel/wrench_act(mob/living/user, obj/item/tool) + tool.play_tool_sound(src) + anchored = !anchored + +/obj/structure/throwing_wheel/proc/use_clay(spawn_type, mob/user) + var/spinning_speed = user.mind.get_skill_modifier(/datum/skill/production, SKILL_SPEED_MODIFIER) * DEFAULT_SPIN + for(var/loop_try in 1 to length(given_message)) + if(!do_after(user, spinning_speed, target = src)) + in_use = FALSE + return + to_chat(user, span_notice(given_message[loop_try])) + new spawn_type(get_turf(src)) + user.mind.adjust_experience(/datum/skill/production, 50) + has_clay = FALSE + icon_state = "throw_wheel_empty" + +/obj/structure/throwing_wheel/attack_hand(mob/living/user, list/modifiers) + . = ..() + if(in_use) + return + use(user) + in_use = FALSE + +/** + * Prompts user for how they wish to use the throwing wheel + * + * To make sure in_use var always gets set back to FALSE no matter what happens, do the actual 'using' in its own proc and do the setting to FALSE in attack_hand + * + * Arguments: + * * user - the mob who is using the throwing wheel + */ +/obj/structure/throwing_wheel/proc/use(mob/living/user) + in_use = TRUE + var/spinning_speed = user.mind.get_skill_modifier(/datum/skill/production, SKILL_SPEED_MODIFIER) * DEFAULT_SPIN + if(!has_clay) + balloon_alert(user, "there is no clay!") + return + var/user_input = tgui_alert(user, "What would you like to do?", "Choice Selection", list("Create", "Remove")) + if(!user_input) + return + switch(user_input) + if("Create") + var/creation_choice = tgui_input_list(user, "What you like to create?", "Creation Choice", list("Cup", "Plate", "Bowl", "Tray", "Brick")) + if(!creation_choice) + return + switch(creation_choice) + if("Cup") + use_clay(/obj/item/ceramic/cup, user) + if("Plate") + use_clay(/obj/item/ceramic/plate, user) + if("Bowl") + use_clay(/obj/item/ceramic/bowl, user) + if("Tray") + use_clay(/obj/item/ceramic/tray, user) + if("Brick") + use_clay(/obj/item/ceramic/brick, user) + if("Remove") + if(!do_after(user, spinning_speed, target = src)) + return + var/atom/movable/new_clay = new /obj/item/stack/clay(get_turf(src)) + user.put_in_active_hand(new_clay) + has_clay = FALSE + icon_state = "throw_wheel_empty" + +#undef DEFAULT_SPIN diff --git a/modular_doppler/hearthkin/primitive_production/code/farming.dm b/modular_doppler/hearthkin/primitive_production/code/farming.dm new file mode 100644 index 0000000000000..f6ccf6c8a8c47 --- /dev/null +++ b/modular_doppler/hearthkin/primitive_production/code/farming.dm @@ -0,0 +1,296 @@ +/datum/component/simple_farm + ///whether we limit the amount of plants you can have per turf + var/one_per_turf = TRUE + ///the reference to the movable parent the component is attached to + var/atom/atom_parent + ///the amount of pixels shifted (x,y) + var/list/pixel_shift = 0 + +/datum/component/simple_farm/Initialize(set_plant = FALSE, set_turf_limit = TRUE, list/set_shift = list(0, 0)) + //we really need to check if its movable + if(!isatom(parent)) + return COMPONENT_INCOMPATIBLE + atom_parent = parent + //important to allow people to just straight up set allowing to plant + one_per_turf = set_turf_limit + pixel_shift = set_shift + //now lets register the signals + RegisterSignal(atom_parent, COMSIG_ATOM_ATTACKBY, PROC_REF(check_attack)) + RegisterSignal(atom_parent, COMSIG_ATOM_EXAMINE, PROC_REF(check_examine)) + RegisterSignal(atom_parent, COMSIG_QDELETING, PROC_REF(delete_farm)) + +/datum/component/simple_farm/Destroy(force) + //lets not hard del + UnregisterSignal(atom_parent, list(COMSIG_ATOM_ATTACKBY, COMSIG_ATOM_EXAMINE, COMSIG_QDELETING)) + atom_parent = null + return ..() + +/** + * check_attack is meant to listen for the COMSIG_ATOM_ATTACKBY signal, where it essentially functions like the attackby proc + */ +/datum/component/simple_farm/proc/check_attack(datum/source, obj/item/attacking_item, mob/user) + SIGNAL_HANDLER + + //if its a seed, lets try to plant + if(istype(attacking_item, /obj/item/seeds)) + var/obj/structure/simple_farm/locate_farm = locate() in get_turf(atom_parent) + + if(one_per_turf && locate_farm) + atom_parent.balloon_alert_to_viewers("cannot plant more seeds here!") + return + + locate_farm = new(get_turf(atom_parent)) + locate_farm.pixel_x = pixel_shift[1] + locate_farm.pixel_y = pixel_shift[2] + locate_farm.layer = atom_parent.layer + 0.1 + if(ismovable(atom_parent)) + var/atom/movable/movable_parent = atom_parent + locate_farm.glide_size = movable_parent.glide_size + attacking_item.forceMove(locate_farm) + locate_farm.planted_seed = attacking_item + locate_farm.attached_atom = atom_parent + atom_parent.balloon_alert_to_viewers("seed has been planted!") + locate_farm.update_appearance() + locate_farm.late_setup() + +/** + * check_examine is meant to listen for the COMSIG_ATOM_EXAMINE signal, where it will put additional information in the examine + */ +/datum/component/simple_farm/proc/check_examine(datum/source, mob/user, list/examine_list) + examine_list += span_notice("
You are able to plant seeds here!") + +/** + * delete_farm is meant to be called when the parent of this component has been deleted-- thus deleting the ability to grow the simple farm + * it will delete the farm that can be found on the turf of the parent of this component + */ +/datum/component/simple_farm/proc/delete_farm() + SIGNAL_HANDLER + + var/obj/structure/simple_farm/locate_farm = locate() in get_turf(atom_parent) + if(locate_farm) + qdel(locate_farm) + +/obj/structure/simple_farm + name = "simple farm" + desc = "A small little plant that has adapted to the surrounding environment." + //it needs to be able to be walked through + density = FALSE + //it should not be pulled by anything + anchored = TRUE + ///the atom the farm is attached to + var/atom/attached_atom + ///the seed that is held within + var/obj/item/seeds/planted_seed + ///the max amount harvested from the plants + var/max_harvest = 3 + ///the cooldown amount between each harvest + var/harvest_cooldown = 1 MINUTES + //the cooldown between each harvest + COOLDOWN_DECLARE(harvest_timer) + +/obj/structure/simple_farm/Initialize(mapload) + . = ..() + START_PROCESSING(SSobj, src) + COOLDOWN_START(src, harvest_timer, harvest_cooldown) + +/obj/structure/simple_farm/Destroy() + STOP_PROCESSING(SSobj, src) + + if(planted_seed) + planted_seed.forceMove(get_turf(src)) + planted_seed = null + + if(attached_atom) + if(ismovable(attached_atom)) + UnregisterSignal(attached_atom, COMSIG_MOVABLE_MOVED) + + attached_atom = null + + return ..() + +/obj/structure/simple_farm/examine(mob/user) + . = ..() + . += span_notice("
[src] will be ready for harvest in [DisplayTimeText(COOLDOWN_TIMELEFT(src, harvest_timer))]") + if(max_harvest < 6) + . += span_notice("You can use goliath hides or worm fertilizer to increase the amount dropped per harvest!") + if(harvest_cooldown > 30 SECONDS) + . += span_notice("
You can use sinew or worm fertilizer to lower the time between each harvest!") + +/obj/structure/simple_farm/process(seconds_per_tick) + update_appearance() + +/obj/structure/simple_farm/update_appearance(updates) + if(!planted_seed) + return + + icon = planted_seed.growing_icon + + if(COOLDOWN_FINISHED(src, harvest_timer)) + if(planted_seed.icon_harvest) + icon_state = planted_seed.icon_harvest + + else + icon_state = "[planted_seed.icon_grow][planted_seed.growthstages]" + + name = LOWER_TEXT(planted_seed.plantname) + + else + icon_state = "[planted_seed.icon_grow]1" + name = LOWER_TEXT("harvested [planted_seed.plantname]") + + return ..() + +/obj/structure/simple_farm/attack_hand(mob/living/user, list/modifiers) + if(!COOLDOWN_FINISHED(src, harvest_timer)) + balloon_alert(user, "plant not ready for harvest!") + return + + COOLDOWN_START(src, harvest_timer, harvest_cooldown) + create_harvest() + update_appearance() + return ..() + +/obj/structure/simple_farm/attackby(obj/item/attacking_item, mob/user, params) + //if its a shovel or knife, dismantle + if(attacking_item.tool_behaviour == TOOL_SHOVEL || attacking_item.tool_behaviour == TOOL_KNIFE) + var/turf/src_turf = get_turf(src) + src_turf.balloon_alert_to_viewers("the plant crumbles!") + Destroy() + return + + if(istype(attacking_item, /obj/item/storage/bag/plants)) + if(!COOLDOWN_FINISHED(src, harvest_timer)) + return + + COOLDOWN_START(src, harvest_timer, harvest_cooldown) + create_harvest(attacking_item, user) + update_appearance() + return + + var/obj/item/stack/use_item = attacking_item + if(istype(use_item) && !use_item.tool_use_check(1)) + return + + //if its sinew, lower the cooldown + if(istype(use_item, /obj/item/stack/sheet/sinew)) + if(decrease_cooldown(user)) + use_item.use(1) + return + + //if its goliath hide, increase the amount dropped + if(istype(use_item, /obj/item/stack/sheet/animalhide/goliath_hide)) + if(increase_yield(user)) + use_item.use(1) + return + + if(istype(use_item, /obj/item/stack/worm_fertilizer)) + var/cooldown_improved = decrease_cooldown(user, silent = TRUE) + var/yield_improved = increase_yield(user, silent = TRUE) + if (cooldown_improved || yield_improved) + use_item.use(1) + balloon_alert(user, "fertilized") + else + balloon_alert(user, "already fertilized!") + return + + + return ..() + +/** + * a proc that will increase the amount of items the crop could produce (at a maximum of 6, from base of 3) + */ +/obj/structure/simple_farm/proc/increase_yield(mob/user, var/silent = FALSE) + if(max_harvest >= 6) + if(!silent) + balloon_alert(user, "plant is at maximum yield") + + return FALSE + + max_harvest++ + + if(!silent) + balloon_alert_to_viewers("plant will have increased yield") + + return TRUE + +/** + * a proc that will decrease the amount of time it takes to be ready for harvest (at a maximum of 30 seconds, from a base of 1 minute) + */ +/obj/structure/simple_farm/proc/decrease_cooldown(mob/user, var/silent = FALSE) + if(harvest_cooldown <= 30 SECONDS) + if(!silent) + balloon_alert(user, "already at maximum growth speed!") + + return FALSE + + var/timeleft_percent = COOLDOWN_TIMELEFT(src, harvest_timer) / harvest_cooldown + harvest_cooldown -= 10 SECONDS + COOLDOWN_START(src, harvest_timer, harvest_cooldown * timeleft_percent) + + if(!silent) + balloon_alert_to_viewers("plant will grow faster") + + return TRUE + +/** + * used during the component so that it can move when it's attached atom moves + */ +/obj/structure/simple_farm/proc/late_setup() + if(!ismovable(attached_atom)) + return + RegisterSignal(attached_atom, COMSIG_MOVABLE_MOVED, PROC_REF(move_plant)) + +/** + * a simple proc to forcemove the plant on top of the movable atom its attached to + */ +/obj/structure/simple_farm/proc/move_plant() + forceMove(get_turf(attached_atom)) + +/** + * will create a harvest of the seeds product, with a chance to create a mutated version + */ +/obj/structure/simple_farm/proc/create_harvest(var/obj/item/storage/bag/plants/plant_bag, var/mob/user) + if(!planted_seed) + return + + for(var/i in 1 to rand(1, max_harvest)) + var/obj/creating_obj + + if(prob(15) && length(planted_seed.mutatelist)) + var/obj/item/seeds/choose_seed = pick(planted_seed.mutatelist) + creating_obj = initial(choose_seed.product) + + if(!creating_obj) + creating_obj = choose_seed + + var/created_special = new creating_obj(get_turf(src)) + + plant_bag?.atom_storage?.attempt_insert(created_special, user, TRUE) + + balloon_alert_to_viewers("something special drops!") + continue + + creating_obj = planted_seed.product + + if(!creating_obj) + creating_obj = planted_seed.type + + var/created_harvest = new creating_obj(get_turf(src)) + + plant_bag?.atom_storage?.attempt_insert(created_harvest, user, TRUE) + +/turf/open/misc/asteroid/basalt/getDug() + . = ..() + AddComponent(/datum/component/simple_farm) + +/turf/open/misc/asteroid/basalt/refill_dug() + . = ..() + qdel(GetComponent(/datum/component/simple_farm)) + +/turf/open/misc/asteroid/snow/getDug() + . = ..() + AddComponent(/datum/component/simple_farm) + +/turf/open/misc/asteroid/snow/refill_dug() + . = ..() + qdel(GetComponent(/datum/component/simple_farm)) diff --git a/modular_doppler/hearthkin/primitive_production/code/glassblowing.dm b/modular_doppler/hearthkin/primitive_production/code/glassblowing.dm new file mode 100644 index 0000000000000..261f5ba411eab --- /dev/null +++ b/modular_doppler/hearthkin/primitive_production/code/glassblowing.dm @@ -0,0 +1,540 @@ +#define DEFAULT_TIMED (4 SECONDS) +#define STEP_BLOW "blow" +#define STEP_SPIN "spin" +#define STEP_PADDLE "paddle" +#define STEP_SHEAR "shear" +#define STEP_JACKS "jacks" + +/obj/item/glassblowing + icon = 'modular_doppler/hearthkin/primitive_production/icons/prim_fun.dmi' + +/obj/item/glassblowing/glass_globe + name = "glass globe" + desc = "A glass bowl that is capable of carrying things." + icon_state = "glass_globe" + material_flags = MATERIAL_COLOR + custom_materials = list( + /datum/material/glass = HALF_SHEET_MATERIAL_AMOUNT, + ) + +/datum/export/glassblowing + cost = CARGO_CRATE_VALUE * 5 + unit_name = "glassblowing product" + export_types = list( + /obj/item/glassblowing/glass_lens, + /obj/item/glassblowing/glass_globe, + /obj/item/reagent_containers/cup/bowl/blowing_glass, + /obj/item/reagent_containers/cup/beaker/large/blowing_glass, + /obj/item/plate/blowing_glass + ) + +/datum/export/glassblowing/sell_object(obj/O, datum/export_report/report, dry_run, apply_elastic = FALSE) //I really dont want them to feel gimped + return ..() + +/obj/item/glassblowing/glass_lens + name = "glass lens" + desc = "A convex glass lens that would make an excellent magnifying glass if it were attached to a handle." + icon_state = "glass_lens" + +/obj/item/reagent_containers/cup/bowl/blowing_glass + name = "glass bowl" + desc = "A glass bowl that is capable of carrying things." + icon = 'modular_doppler/hearthkin/primitive_production/icons/prim_fun.dmi' + icon_state = "glass_bowl" + custom_materials = list(/datum/material/glass=SHEET_MATERIAL_AMOUNT) + material_flags = MATERIAL_EFFECTS | MATERIAL_COLOR + +/obj/item/reagent_containers/cup/beaker/large/blowing_glass + name = "glass cup" + desc = "A glass cup that is capable of carrying liquids." + icon = 'modular_doppler/hearthkin/primitive_production/icons/prim_fun.dmi' + icon_state = "glass_cup" + material_flags = MATERIAL_EFFECTS | MATERIAL_COLOR + +/obj/item/plate/blowing_glass + name = "glass plate" + desc = "A glass plate that is capable of carrying things." + icon = 'modular_doppler/hearthkin/primitive_production/icons/prim_fun.dmi' + icon_state = "glass_plate" + custom_materials = list(/datum/material/glass=SHEET_MATERIAL_AMOUNT) + material_flags = MATERIAL_EFFECTS | MATERIAL_COLOR + +/obj/item/glassblowing/molten_glass + name = "molten glass" + desc = "A glob of molten glass, ready to be shaped into art." + icon_state = "molten_glass" + ///the cooldown if it's still molten / requires heating up + COOLDOWN_DECLARE(remaining_heat) + ///the typepath of the item that will be produced when the required actions are met + var/chosen_item + ///the list of steps remaining + var/list/steps_remaining + ///the amount of time this glass will stay heated, updated each time it gets put in the forge based on the user's skill + var/total_time + ///whether this glass's chosen item has completed all its steps. So we don't have to keep checking this a million times once it's done. + var/is_finished = FALSE + +/obj/item/glassblowing/molten_glass/examine(mob/user) + . = ..() + var/message = get_examine_message(src) + if(message) + . += message + +/obj/item/glassblowing/molten_glass/pickup(mob/living/user) + if(!istype(user)) + return ..() + + . = ..() + + try_burn_user(user) + +/** + * Tries to burn the user if the glass is still molten hot. + * + * Arguments: + * * mob/living/user - user to burn + */ +/obj/item/glassblowing/molten_glass/proc/try_burn_user(mob/living/user) + if(!COOLDOWN_FINISHED(src, remaining_heat)) + to_chat(user, span_warning("You burn your hands trying to pick up [src]!")) + user.emote("scream") + user.dropItemToGround(src) + var/obj/item/bodypart/affecting = user.get_active_hand() + user.investigate_log("was burned their hand on [src] for [15] at [AREACOORD(user)]", INVESTIGATE_CRAFTING) + return affecting?.receive_damage(0, 15, wound_bonus = CANT_WOUND) + +/obj/item/glassblowing/blowing_rod + name = "blowing rod" + desc = "A tool that is used to hold the molten glass as well as help shape it." + icon_state = "blow_pipe_empty" + tool_behaviour = TOOL_BLOWROD + /// Whether the rod is in use currently; will try to prevent many other actions on it + var/in_use = FALSE + /// A ref to the glass item being blown + var/datum/weakref/glass_ref + +/obj/item/glassblowing/blowing_rod/examine(mob/user) + . = ..() + var/obj/item/glassblowing/molten_glass/glass = glass_ref.resolve() + if(!glass) + return + var/message = get_examine_message(glass) + if(message) + . += message + + +/** + * Create the examine message and return it. + * + * This will include all the remaining steps and whether the glass has cooled down or not. + * + * Arguments: + * * obj/item/glassblowing/molten_glass/glass - the glass object being examined + * + * Returns the examine message. + */ +/obj/item/glassblowing/proc/get_examine_message(obj/item/glassblowing/molten_glass/glass) + if(COOLDOWN_FINISHED(glass, remaining_heat)) + . += span_warning("The glass has cooled down and will require reheating to modify! ") + if(!length(glass.steps_remaining)) + return + if(glass.steps_remaining[STEP_BLOW]) + . += "The glass requires [glass.steps_remaining[STEP_BLOW]] more blowing actions! " + if(glass.steps_remaining[STEP_SPIN]) + . += "The glass requires [glass.steps_remaining[STEP_SPIN]] more spinning actions! " + if(glass.steps_remaining[STEP_PADDLE]) + . += "The glass requires [glass.steps_remaining[STEP_PADDLE]] more paddling actions! " + if(glass.steps_remaining[STEP_SHEAR]) + . += "The glass requires [glass.steps_remaining[STEP_SHEAR]] more shearing actions! " + if(glass.steps_remaining[STEP_JACKS]) + . += "The glass requires [glass.steps_remaining[STEP_JACKS]] more jacking actions!" + +/obj/item/glassblowing/blowing_rod/interact_with_atom(atom/interacting_with, mob/living/user, list/modifiers) + var/obj/item/glassblowing/molten_glass/attacking_glass = interacting_with + if(!istype(attacking_glass)) + return NONE + + if(glass_ref?.resolve()) + to_chat(user, span_warning("[src] already has some glass on it!")) + return ITEM_INTERACT_BLOCKING + if(!user.transferItemToLoc(attacking_glass, src)) + return ITEM_INTERACT_BLOCKING + glass_ref = WEAKREF(attacking_glass) + to_chat(user, span_notice("[src] picks up [attacking_glass].")) + icon_state = "blow_pipe_full" + return ITEM_INTERACT_SUCCESS + +/obj/item/glassblowing/blowing_rod/attackby(obj/item/attacking_item, mob/living/user, params) + var/actioning_speed = user.mind.get_skill_modifier(/datum/skill/production, SKILL_SPEED_MODIFIER) * DEFAULT_TIMED + var/obj/item/glassblowing/molten_glass/glass = glass_ref?.resolve() + + if(istype(attacking_item, /obj/item/glassblowing/molten_glass)) + if(glass) + to_chat(user, span_warning("[src] already has some glass on it still!")) + return + if(!user.transferItemToLoc(attacking_item, src)) + return + glass_ref = WEAKREF(attacking_item) + to_chat(user, span_notice("[src] picks up [attacking_item].")) + icon_state = "blow_pipe_full" + return + + if(istype(attacking_item, /obj/item/glassblowing/paddle)) + do_glass_step(STEP_PADDLE, user, actioning_speed, glass) + return + + if(istype(attacking_item, /obj/item/glassblowing/shears)) + do_glass_step(STEP_SHEAR, user, actioning_speed, glass) + return + + if(istype(attacking_item, /obj/item/glassblowing/jacks)) + do_glass_step(STEP_JACKS, user, actioning_speed, glass) + return + + return ..() + +/obj/item/glassblowing/blowing_rod/attack_self(mob/user, modifiers) + return ..() + +/obj/item/glassblowing/blowing_rod/ui_interact(mob/user, datum/tgui/ui) + ui = SStgui.try_update_ui(user, src, ui) + if(!ui) + ui = new(user, src, "GlassBlowing", name) + ui.open() + +/obj/item/glassblowing/blowing_rod/ui_data() + var/obj/item/glassblowing/molten_glass/glass = glass_ref?.resolve() + + var/data = list() + data["inUse"] = in_use + + if(glass) + data["glass"] = list( + timeLeft = COOLDOWN_TIMELEFT(glass, remaining_heat), + totalTime = glass.total_time, + chosenItem = null, + stepsRemaining = glass.steps_remaining, + isFinished = glass.is_finished + ) + + var/obj/item_path = glass.chosen_item + data["glass"]["chosenItem"] = item_path ? list(name = initial(item_path.name), type = item_path) : null + else + data["glass"] = null + + return data + +/obj/item/glassblowing/blowing_rod/ui_act(action, params) + . = ..() + if(.) + return + if(!Adjacent(usr)) + return + add_fingerprint(usr) + + var/obj/item/glassblowing/molten_glass/glass = glass_ref?.resolve() + var/actioning_speed = usr.mind.get_skill_modifier(/datum/skill/production, SKILL_SPEED_MODIFIER) * DEFAULT_TIMED + + if(!glass) + return + + if(action == "Remove") + if(!glass.chosen_item) + remove_glass(usr, glass) + in_use = FALSE + return + + if(glass.is_finished) + create_item(usr, glass) + in_use = FALSE + else + remove_glass(usr, glass) + return + + if(!glass.chosen_item) + switch(action) + if("Plate") + glass.chosen_item = /obj/item/plate/blowing_glass + glass.steps_remaining = list(blow=3,spin=3,paddle=3,shear=0,jacks=0) //blowing, spinning, paddling + if("Bowl") + glass.chosen_item = /obj/item/reagent_containers/cup/bowl/blowing_glass + glass.steps_remaining = list(blow=2,spin=2,paddle=2,shear=0,jacks=3) //blowing, spinning, paddling + if("Globe") + glass.chosen_item = /obj/item/glassblowing/glass_globe + glass.steps_remaining = list(blow=6,spin=3,paddle=0,shear=0,jacks=0) //blowing, spinning + if("Cup") + glass.chosen_item = /obj/item/reagent_containers/cup/beaker/large/blowing_glass + glass.steps_remaining = list(blow=3,spin=3,paddle=3,shear=0,jacks=0) //blowing, spinning, paddling + if("Lens") + glass.chosen_item = /obj/item/glassblowing/glass_lens + glass.steps_remaining = list(blow=0,spin=0,paddle=3,shear=3,jacks=3) //paddling, shearing, jacking + if("Bottle") + glass.chosen_item = /obj/item/reagent_containers/cup/glass/bottle/small + glass.steps_remaining = list(blow=3,spin=2,paddle=3,shear=0,jacks=0) //blowing, spinning, paddling + else + switch(action) + if("Blow") + do_glass_step(STEP_BLOW, usr, actioning_speed, glass) + if("Spin") + do_glass_step(STEP_SPIN, usr, actioning_speed, glass) + if("Paddle") + do_glass_step(STEP_PADDLE, usr, actioning_speed, glass) + if("Shear") + do_glass_step(STEP_SHEAR, usr, actioning_speed, glass) + if("Jacks") + do_glass_step(STEP_JACKS, usr, actioning_speed, glass) + if("Cancel") + glass.chosen_item = null + glass.steps_remaining = null + glass.is_finished = FALSE + to_chat(usr, span_notice("You start over with the [src].")) + + +/** + * Removes the glass object from the rod. + * + * Try to put the glass into the user's hands, or on the floor if that fails. + * + * Arguments: + * * mob/user - the mob doing the removing + * * obj/item/glassblowing/molten_glass/glass - the glass object + * + * Returns TRUE or FALSE. + */ +/obj/item/glassblowing/blowing_rod/proc/remove_glass(mob/user, obj/item/glassblowing/molten_glass/glass) + if(!glass) + return + + in_use = FALSE + user.put_in_hands(glass) + glass.try_burn_user(user) + glass_ref = null + icon_state = "blow_pipe_empty" + +/** + * Creates the finished product and delete the glass object used to make it. + * + * Try to put the finished product into the user's hands + * + * Arguments: + * * mob/user - the user doing the creating + * * obj/item/glassblowing/molten_glass/glass - the glass object + * + * Returns TRUE or FALSE. + */ +/obj/item/glassblowing/blowing_rod/proc/create_item(mob/user, obj/item/glassblowing/molten_glass/glass) + if(!glass) + return + if(in_use) + return + + in_use = TRUE + user.put_in_hands(new glass.chosen_item) + user.mind.adjust_experience(/datum/skill/production, 30) + glass_ref = null + qdel(glass) + icon_state = "blow_pipe_empty" + return + +/** + * Display fail message and reset in_use. + * + * Craft is finished when all steps in steps_remaining are 0. + * + * Arguments: + * * mob/user - mob to display to + * * message - to display + */ +/obj/item/glassblowing/blowing_rod/proc/fail_message(message, mob/user) + to_chat(user, span_warning(message)) + in_use = FALSE + +/** + * Try to do a glassblowing action. + * + * Checks for a table and valid tool if applicable, and updates the steps_remaining on the glass object. + * + * Arguments: + * * step_id - the step id e.g. STEP_BLOW + * * actioning_speed - the speed based on the user's production skill + * * obj/item/glassblowing/molten_glass/glass - the glass object + */ +/obj/item/glassblowing/blowing_rod/proc/do_glass_step(step_id, mob/user, actioning_speed, obj/item/glassblowing/molten_glass/glass) + if(!glass) + return + + if(COOLDOWN_FINISHED(glass, remaining_heat)) + balloon_alert(user, "glass too cool!") + return FALSE + + if(in_use) + return + + in_use = TRUE + + if(!check_valid_table(user)) + fail_message("You must be near a non-flammable table!", user) + return + + var/atom/movable/tool_to_use = check_valid_tool(user, step_id) + if(!tool_to_use) + in_use = FALSE + return FALSE + + to_chat(user, span_notice("You begin to [step_id] [src].")) + if(!do_after(user, actioning_speed, target = src)) + fail_message("You interrupt an action!", user) + REMOVE_TRAIT(tool_to_use, TRAIT_CURRENTLY_GLASSBLOWING, TRAIT_GLASSBLOWING) + return FALSE + + if(glass.steps_remaining) + // We do not want to have negative values here + if(glass.steps_remaining[step_id] > 0) + glass.steps_remaining[step_id]-- + if(check_finished(glass)) + glass.is_finished = TRUE + + REMOVE_TRAIT(tool_to_use, TRAIT_CURRENTLY_GLASSBLOWING, TRAIT_GLASSBLOWING) + in_use = FALSE + + to_chat(user, span_notice("You finish trying to [step_id] [src].")) + user.mind.adjust_experience(/datum/skill/production, 10) + + +/** + * Check if there is a non-flammable table nearby to do the crafting on. + * + * If the user is a master in the production skill, they can skip tables. + * + * Arguments: + * * mob/living/user - the mob doing the action + * + * Returns TRUE or FALSE. + */ +/obj/item/glassblowing/blowing_rod/proc/check_valid_table(mob/living/user) + var/skill_level = user.mind.get_skill_level(/datum/skill/production) + if(skill_level >= SKILL_LEVEL_MASTER) // + return TRUE + for(var/obj/structure/table/check_table in range(1, get_turf(src))) + if(!(check_table.resistance_flags & FLAMMABLE)) + return TRUE + return FALSE + +/** + * Check if user is carrying the proper tool for the step. + * + * Arguments: + * * mob/living/carbon/human/user - the mob doing the action + * * step_id - the step id of the action being done + * + * We check to see if the user is using the right tool and if they are currently glassblowing with it. + * If the correct tool is being used we return the tool. Otherwise we return `FALSE` + */ +/obj/item/glassblowing/blowing_rod/proc/check_valid_tool(mob/living/carbon/human/user, step_id) + if(!istype(user)) + return FALSE + + if(step_id == STEP_BLOW || step_id == STEP_SPIN) + if(HAS_TRAIT(user, TRAIT_CURRENTLY_GLASSBLOWING)) + balloon_alert(user, "already glassblowing!") + return FALSE + + ADD_TRAIT(user, TRAIT_CURRENTLY_GLASSBLOWING, TRAIT_GLASSBLOWING) + return user + + var/obj/item/glassblowing/used_tool + switch(step_id) + if(STEP_PADDLE) + used_tool = user.is_holding_item_of_type(/obj/item/glassblowing/paddle) + if(STEP_SHEAR) + used_tool = user.is_holding_item_of_type(/obj/item/glassblowing/shears) + if(STEP_JACKS) + used_tool = user.is_holding_item_of_type(/obj/item/glassblowing/jacks) + + if(!used_tool) + balloon_alert(user, "need the right tool!") + return FALSE + + if(HAS_TRAIT(used_tool, TRAIT_CURRENTLY_GLASSBLOWING)) + balloon_alert(user, "already in use!") + return FALSE + + ADD_TRAIT(used_tool, TRAIT_CURRENTLY_GLASSBLOWING, TRAIT_GLASSBLOWING) + return used_tool + +/** + * Checks if the glass is ready to craft into its chosen item. + * + * Craft is finished when all steps in steps_remaining are 0. + * + * Arguments: + * * obj/item/glassblowing/molten_glass/glass - the glass object + * + * Returns TRUE or FALSE. + */ +/obj/item/glassblowing/blowing_rod/proc/check_finished(obj/item/glassblowing/molten_glass/glass) + for(var/step_id in glass.steps_remaining) + if(glass.steps_remaining[step_id] != 0) + return FALSE + return TRUE + +/datum/crafting_recipe/glassblowing_recipe + reqs = list(/obj/item/stack/sheet/iron = 5) + category = CAT_MISC + +/datum/crafting_recipe/glassblowing_recipe/glass_blowing_rod + name = "Glass-blowing Blowing Rod" + result = /obj/item/glassblowing/blowing_rod + +/obj/item/glassblowing/jacks + name = "jacks" + desc = "A tool that helps shape glass during the art process." + icon_state = "jacks" + +/datum/crafting_recipe/glassblowing_recipe/glass_jack + name = "Glass-blowing Jacks" + result = /obj/item/glassblowing/jacks + +/obj/item/glassblowing/paddle + name = "paddle" + desc = "A tool that helps shape glass during the art process." + icon_state = "paddle" + +/datum/crafting_recipe/glassblowing_recipe/glass_paddle + name = "Glass-blowing Paddle" + result = /obj/item/glassblowing/paddle + +/obj/item/glassblowing/shears + name = "shears" + desc = "A tool that helps shape glass during the art process." + icon_state = "shears" + +/datum/crafting_recipe/glassblowing_recipe/glass_shears + name = "Glass-blowing Shears" + result = /obj/item/glassblowing/shears + +/obj/item/glassblowing/metal_cup + name = "metal cup" + desc = "A tool that helps shape glass during the art process." + icon_state = "metal_cup_empty" + var/has_sand = FALSE + +/datum/crafting_recipe/glassblowing_recipe/glass_metal_cup + name = "Glass-blowing Metal Cup" + result = /obj/item/glassblowing/metal_cup + +/obj/item/glassblowing/metal_cup/attackby(obj/item/I, mob/living/user, params) + if(istype(I, /obj/item/stack/ore/glass)) + var/obj/item/stack/ore/glass/glass_obj = I + if(!glass_obj.use(1)) + return + has_sand = TRUE + icon_state = "metal_cup_full" + return ..() + +#undef DEFAULT_TIMED +#undef STEP_BLOW +#undef STEP_SPIN +#undef STEP_PADDLE +#undef STEP_SHEAR +#undef STEP_JACKS diff --git a/modular_doppler/hearthkin/primitive_production/code/misc.dm b/modular_doppler/hearthkin/primitive_production/code/misc.dm new file mode 100644 index 0000000000000..18bcafa8664e9 --- /dev/null +++ b/modular_doppler/hearthkin/primitive_production/code/misc.dm @@ -0,0 +1,35 @@ +/obj/item/shard/attackby(obj/item/item, mob/user, params) + //xenoarch hammer, forging hammer, etc. + if(item.tool_behaviour == TOOL_HAMMER) + var/added_color + switch(src.type) + if(/obj/item/shard) + added_color = "#88cdf1" + + if(/obj/item/shard/plasma) + added_color = "#ff80f4" + + if(/obj/item/shard/plastitanium) + added_color = "#5d3369" + + if(/obj/item/shard/titanium) + added_color = "#cfbee0" + + var/obj/colored_item = new /obj/item/stack/ore/glass/zero_cost(get_turf(src)) + colored_item.add_atom_colour(added_color, FIXED_COLOUR_PRIORITY) + new /obj/effect/decal/cleanable/glass(get_turf(src)) + user.balloon_alert(user, "[src] shatters!") + playsound(src, SFX_SHATTER, 30, TRUE) + qdel(src) + return TRUE + + return ..() + +/obj/item/stack/ore/glass/zero_cost + points = 0 + merge_type = /obj/item/stack/ore/glass/zero_cost + +/obj/item/stack/ore/examine(mob/user) + . = ..() + if(points == 0) + . += span_warning("
[src] is worthless and will not reward any mining points!") diff --git a/modular_doppler/hearthkin/primitive_production/code/production_skill.dm b/modular_doppler/hearthkin/primitive_production/code/production_skill.dm new file mode 100644 index 0000000000000..b591706ac86b3 --- /dev/null +++ b/modular_doppler/hearthkin/primitive_production/code/production_skill.dm @@ -0,0 +1,18 @@ +/datum/skill/production + name = "Production" + title = "Producer" + desc = "The artist who finds themselves using multiple mediums in which to express their creativity." + modifiers = list( + SKILL_SPEED_MODIFIER = list(1, 0.95, 0.9, 0.85, 0.75, 0.6, 0.5), + SKILL_PROBS_MODIFIER = list(10, 15, 20, 25, 30, 35, 40) + ) + skill_item_path = /obj/item/clothing/neck/cloak/skill_reward/production + +/obj/item/clothing/neck/cloak/skill_reward/production + name = "legendary producer's cloak" + desc = "Worn by the most skilled producers, this legendary cloak is only attainable by knowing how to create the best products. \ + This status symbol represents a being who has crafted some of the finest glass and ceramic works." + icon = 'modular_doppler/hearthkin/primitive_production/icons/cloaks.dmi' + worn_icon = 'modular_doppler/hearthkin/primitive_production/icons/neck.dmi' + icon_state = "productioncloak" + associated_skill_path = /datum/skill/production diff --git a/modular_doppler/hearthkin/primitive_production/code/wormfarm.dm b/modular_doppler/hearthkin/primitive_production/code/wormfarm.dm new file mode 100644 index 0000000000000..4fa88b9a4a1d5 --- /dev/null +++ b/modular_doppler/hearthkin/primitive_production/code/wormfarm.dm @@ -0,0 +1,139 @@ +/obj/structure/wormfarm + name = "worm farm" + desc = "A wonderfully dirty barrel where worms can have a happy little life." + icon = 'modular_doppler/hearthkin/primitive_production/icons/structures.dmi' + icon_state = "wormbarrel" + density = TRUE + anchored = FALSE + /// How many worms can the barrel hold + var/max_worm = 10 + /// How many worms the barrel is currently holding + var/current_worm = 0 + /// How much food was inserted into the barrel that needs to be composted + var/current_food = 0 + /// If the barrel is currently being used by someone + var/in_use = FALSE + // The cooldown between each worm "breeding" + COOLDOWN_DECLARE(worm_timer) + +/obj/structure/wormfarm/Initialize(mapload) + . = ..() + START_PROCESSING(SSobj, src) + COOLDOWN_START(src, worm_timer, 30 SECONDS) + +/obj/structure/wormfarm/Destroy() + STOP_PROCESSING(SSobj, src) + return ..() + +//process is currently only used for making more worms +/obj/structure/wormfarm/process(seconds_per_tick) + if(!COOLDOWN_FINISHED(src, worm_timer)) + return + + COOLDOWN_START(src, worm_timer, 30 SECONDS) + + if(current_worm >= 2 && current_worm < max_worm) + current_worm++ + + if(current_food > 0 && current_worm > 1) + current_food-- + new /obj/item/stack/worm_fertilizer(get_turf(src)) + +/obj/structure/wormfarm/examine(mob/user) + . = ..() + . += span_notice("
There are currently [current_worm]/[max_worm] worms in the barrel.") + if(current_worm < max_worm) + . += span_notice("You can place more worms in the barrel.") + if(current_worm > 0) + . += span_notice("You can get fertilizer by feeding the worms food.") + +/obj/structure/wormfarm/attack_hand(mob/living/user, list/modifiers) + if(in_use) + balloon_alert(user, "currently in use") + return ..() + + balloon_alert(user, "digging up worms") + if(!do_after(user, 2 SECONDS, src)) + balloon_alert(user, "stopped digging") + in_use = FALSE + return ..() + + if(current_worm <= 0) + balloon_alert(user, "no worms available") + in_use = FALSE + return ..() + + new /obj/item/food/bait/worm(get_turf(src)) + current_worm-- + in_use = FALSE + + return ..() + +/obj/structure/wormfarm/attackby(obj/item/attacking_item, mob/user, params) + //we want to check for worms first because they are a type of food as well... + if(istype(attacking_item, /obj/item/food/bait/worm)) + if(current_worm >= max_worm) + balloon_alert(user, "too many worms in the barrel") + return + + qdel(attacking_item) + balloon_alert(user, "worm released into barrel") + current_worm++ + return + + //if it aint a worm, lets check for any other food items + if(istype(attacking_item, /obj/item/food)) + if(in_use) + balloon_alert(user, "currently in use") + return + in_use = TRUE + + balloon_alert(user, "feeding the worms") + if(!do_after(user, 1 SECONDS, src)) + balloon_alert(user, "stopped feeding the worms") + in_use = FALSE + return + + // if someone has built multiple worm farms, I want to make sure they can't just use one singular piece of food for more than one barrel + if(!attacking_item) + in_use = FALSE + return + + qdel(attacking_item) + balloon_alert(user, "feeding complete, check back later") + + current_food++ + + in_use = FALSE + return + + if(istype(attacking_item, /obj/item/storage/bag/plants)) + if(in_use) + balloon_alert(user, "currently in use") + return + in_use = TRUE + + balloon_alert(user, "feeding the worms") + for(var/obj/item/food/selected_food in attacking_item.contents) + if(!do_after(user, 1 SECONDS, src)) + in_use = FALSE + return + + qdel(selected_food) + current_food++ + + in_use = FALSE + return + + //it wasn't a worm, or a piece of food + return ..() + +//produced by feeding worms food and can be ground up for plant nutriment or used directly on ash farming +/obj/item/stack/worm_fertilizer + name = "worm fertilizer" + desc = "When you fed your worms, you should have expected this." + icon = 'modular_doppler/hearthkin/primitive_production/icons/misc.dmi' + icon_state = "fertilizer" + grind_results = list(/datum/reagent/plantnutriment/eznutriment = 3, /datum/reagent/plantnutriment/left4zednutriment = 3, /datum/reagent/plantnutriment/robustharvestnutriment = 3) + singular_name = "fertilizer" + merge_type = /obj/item/stack/worm_fertilizer diff --git a/modular_doppler/hearthkin/primitive_production/icons/cloaks.dmi b/modular_doppler/hearthkin/primitive_production/icons/cloaks.dmi new file mode 100644 index 0000000000000000000000000000000000000000..b4467ca916ddcb470837c0f15b0dc2495c5ae0d2 GIT binary patch literal 1280 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 N{&iz`sg6^`{{g`+`yT)R literal 0 HcmV?d00001 diff --git a/modular_doppler/hearthkin/primitive_production/icons/structures.dmi b/modular_doppler/hearthkin/primitive_production/icons/structures.dmi new file mode 100644 index 0000000000000000000000000000000000000000..0682447f8d302270842ea9edaa63c1ccc335bd97 GIT binary patch literal 2006 zcmV;{2Pyc8P)V=-0C=30%DoE0FcgO2Ik}3Db{GHFERrG_+FK|`dTN4gDklef`wj&+5x4h+ zr^cnZh7P_B_Qg`tlHqXP?X6kUpb-wIqcxG!J?b_^Nf{0mWsPZ?Dr<%$1r7&mMxmLv z{oAn?5JX+AHNpKmLRH8?MoG9=;9s4Ym+M@8?&?ZvX%X1W80eRCt{2TVIG1 zM;QM_1Ic35Tbc`X4^7RTgpogTvczXJ_X3 zoA3MPo88k_EEe%1!{6-*c*Xvq?Z(#rO}6)Q#U=bc_pi@wf4=9z1FWRu10mbCnY>DW zcOyp6djKKNl4eO-VHIcp(00Q~gq{|FC2w6>Hy~m-iO|ymu;ks6wzhK$7odl8z>&SX z3_J4s#-gU{@ev8X{#^h7{BdW&bdMGB!tI$lFId;=iMI;zfe`k@C3?MYEQ+oDo3L*z zit!N%^YgWkAmj;7efpM3q&;!T))RW(1NOvgtGl@jJPy{{G`a?=-f=fmu=N1XIpFNs zvj)$8?AS5ad#@X?Za=;v!c}>JuI%`Tg!9+#V{kA;uZd9e^C|`hLniWeImD9(5b{$~ zQzm;Nk!Yy^9~?Yv=npdZC>BK~uhxZw)#cfhA0Mf;Bjn=)AzYOgAPmRx)Ah@yd3y4I zLZJXjl1#QlA^`xHoSZaHo;=wS5j3?3aX1d3L~VC7HPZ8W6`y_hX5Dk=uieMyGQUq@ zI1Wv%Uu;hTh@uEx*O5ph5Dtf_U6y5tqUfb7M+DUzGyt>lQ3S$3=HAV^B*qG2hfH2Y zVD|ysSX_jr77B^j}dFAxRPxMF9YW!{L^NL2d7zL$0`lzqW0o z_g;VJ6O7tC7x;4)vj7zi0Q3hL?68#5EL;g-UHw=r23eK?0D>R@02QK@Ad}vy+^41R zUk>dF@zA3=`h3QLJmA3tG)<$ft|$sbQG}*x&@` z2vHQ<9ty2OLk}nv3S5%bHj1J^mSu#)VMHR4Rf!-B$D4VqseV1}0zl2(tsrGGNs_Cn z3^la~gobDx05pEF!2|2|>dQmkN?|Jja?S1lq!NroA^@skA_xLaglxEY!R%0BnE(NHcOvf zjTZ#f9P*3(0Dwa$lGHwZ;XB)-EwKl79{>Ohp;ij>&H;dn5Fo3`x;?1^**2sSj6@=) z`>QFBLyzV#_aI}kjUGAfSPBFDQkYNQMgVsI2db`}&1R`b*oh$sf+pIO1*=!cgcma7WZY5$z%&wi&2a-Ag$ks(%pJa5e zG0l1ln-@~4lqVs0BDfL24SB#KKsuc^rl+R?RFj?8RVQFymH^eQldU3~5dnas7x1nD zH2gH?D;A4Lr_&7!mg(tfjE>r+pIRHTwb#`X6BDk5AR+*OQ&_M& zgqx3~4PT1diDR9-lZal3x&bSO6<)p!13mm*pi}7CFGHQengHFNK)10bK({B*ZLA5< z?Fn=nFT4QsIGju-jl*AklkUWzmrs2;VLcCYYkXP>&OB6&U%oiliShC7nd{i~O2{O@ z%tO^E8~$^h7(eK%93|t^5Lh;9<#k}gM(%@tzx@j&>pk|`+8;ZXldWA~$KvLIXHTC1 zsF5H9DwT@K&Vt{xDW?E*WN$pfrJd8Apm zu{ni8FM!U@Scwak0FR*G?>E^48#bCkrc$Yx+VDcb;KaLO7*OW_Il3w~E+M^I`-2NA zKrmSQ13N287FIhO-#pShuw${d#hJSRfKsVccfS?r>+1smM2BCaHg3SO1e{jf$<_>5 z;$*U|La9{Z3Tw&%ycl&_aVHyr-|zPn`+a?VEhq2PZ(R~3ux9hXhK=z1{kBPxcMVhp zd@i;@D|jnksZ_X0lC1FhKy$Cry9tv3c3W1Xy`8LZBM<6Dm;|t^-Wp|f9^B-PUI1OD zi)T*bAlt-Click to attach a rail cart to this cart.") + . += span_notice("
Filling it with 10 sand will allow it to be used as a planter!") + +/obj/vehicle/ridden/rail_cart/Initialize(mapload) + . = ..() + attach_trailer() + railoverlay = mutable_appearance(icon, "railoverlay", ABOVE_MOB_LAYER, src) + AddElement(/datum/element/ridable, /datum/component/riding/vehicle/rail_cart) + + create_storage(max_total_storage = 21, max_slots = 21) + +/obj/vehicle/ridden/rail_cart/post_buckle_mob(mob/living/M) + . = ..() + update_overlays() + +/obj/vehicle/ridden/rail_cart/post_unbuckle_mob(mob/living/M) + . = ..() + update_overlays() + +/obj/vehicle/ridden/rail_cart/update_overlays() + . = ..() + if(has_buckled_mobs()) + add_overlay(railoverlay) + else + cut_overlay(railoverlay) + +/obj/vehicle/ridden/rail_cart/relaymove(mob/living/user, direction) + var/obj/structure/railroad/locate_rail = locate() in get_step(src, direction) + if(!canmove || !locate_rail) + return FALSE + if(is_driver(user)) + return relaydrive(user, direction) + return FALSE + +/obj/vehicle/ridden/rail_cart/click_alt(mob/user) + attach_trailer() + return CLICK_ACTION_SUCCESS + +/obj/vehicle/ridden/rail_cart/attack_hand(mob/living/user, list/modifiers) + . = ..() + atom_storage?.show_contents(user) + +/obj/vehicle/ridden/rail_cart/attackby(obj/item/attacking_item, mob/user, params) + if(istype(attacking_item, /obj/item/stack/ore/glass)) + var/obj/item/stack/ore/glass/use_item = attacking_item + if(has_sand || !use_item.use(10)) + return ..() + AddComponent(/datum/component/simple_farm, TRUE, TRUE, list(0, 16)) + has_sand = TRUE + RemoveElement(/datum/element/ridable) + return + + if(attacking_item.tool_behaviour == TOOL_SHOVEL) + var/datum/component/remove_component = GetComponent(/datum/component/simple_farm) + if(!remove_component) + return ..() + qdel(remove_component) + has_sand = FALSE + AddElement(/datum/element/ridable, /datum/component/riding/vehicle/rail_cart) + return + + return ..() + +/// searches the cardinal directions to add this cart to another cart's trailer +/obj/vehicle/ridden/rail_cart/proc/attach_trailer() + if(trailer) + remove_trailer() + return + for(var/direction in GLOB.cardinals) + var/obj/vehicle/ridden/rail_cart/locate_cart = locate() in get_step(src, direction) + if(!locate_cart || locate_cart.trailer == src) + continue + add_trailer(locate_cart) + break + +/datum/component/riding/vehicle/rail_cart + vehicle_move_delay = 0.5 + ride_check_flags = RIDER_NEEDS_LEGS | RIDER_NEEDS_ARMS | UNBUCKLE_DISABLED_RIDER + +/datum/component/riding/vehicle/rail_cart/handle_specials() + . = ..() + set_riding_offsets(RIDING_OFFSET_ALL, list(TEXT_NORTH = list(0, 13), TEXT_SOUTH = list(0, 13), TEXT_EAST = list(0, 13), TEXT_WEST = list(0, 13))) + set_vehicle_dir_layer(SOUTH, OBJ_LAYER) + set_vehicle_dir_layer(NORTH, OBJ_LAYER) + set_vehicle_dir_layer(EAST, OBJ_LAYER) + set_vehicle_dir_layer(WEST, OBJ_LAYER) diff --git a/modular_doppler/hearthkin/primitive_structures/code/storage_structures.dm b/modular_doppler/hearthkin/primitive_structures/code/storage_structures.dm new file mode 100644 index 0000000000000..9a8a44939ba68 --- /dev/null +++ b/modular_doppler/hearthkin/primitive_structures/code/storage_structures.dm @@ -0,0 +1,160 @@ +// Wooden shelves that force items placed on them to be visually placed them + +/obj/structure/rack/wooden + name = "shelf" + icon_state = "shelf_wood" + icon = 'modular_doppler/hearthkin/primitive_structures/icons/storage.dmi' + resistance_flags = FLAMMABLE + interaction_flags_mouse_drop = NEED_DEXTERITY + +/obj/structure/rack/wooden/mouse_drop_receive(atom/dropping, mob/user, params) + if ((!isitem(dropping) || user.get_active_held_item() != dropping)) + return + + if(!user.dropItemToGround(dropping)) + return + + if(dropping.loc != src.loc) + step(dropping, get_dir(dropping, src)) + + var/list/modifiers = params2list(params) + if(!LAZYACCESS(modifiers, ICON_X) || !LAZYACCESS(modifiers, ICON_Y)) + return + + dropping.pixel_x = clamp(text2num(LAZYACCESS(modifiers, ICON_X)) - 16, -(world.icon_size / 3), world.icon_size / 3) + dropping.pixel_y = text2num(LAZYACCESS(modifiers, ICON_Y)) > 16 ? 10 : -4 + +/obj/structure/rack/wooden/wrench_act_secondary(mob/living/user, obj/item/tool) + return NONE + +/obj/structure/rack/wooden/crowbar_act(mob/living/user, obj/item/tool) + user.balloon_alert_to_viewers("disassembling...") + if(!tool.use_tool(src, user, 2 SECONDS, volume = 100)) + return + + deconstruct(TRUE) + return ITEM_INTERACT_SUCCESS + +/obj/structure/rack/wooden/atom_deconstruct(disassembled = TRUE) + new /obj/item/stack/sheet/mineral/wood(drop_location(), 2) + +// Barrel but it works like a crate + +/obj/structure/closet/crate/wooden/storage_barrel + name = "storage barrel" + desc = "This barrel can't hold liquids, it can just hold things inside of it however!" + icon_state = "barrel" + base_icon_state = "barrel" + icon = 'modular_doppler/hearthkin/primitive_structures/icons/storage.dmi' + resistance_flags = FLAMMABLE + material_drop = /obj/item/stack/sheet/mineral/wood + material_drop_amount = 4 + cutting_tool = /obj/item/crowbar + +/obj/machinery/smartfridge/wooden + name = "debug wooden smartfridge" + desc = "You should not be seeing this!" + icon = 'modular_doppler/hearthkin/primitive_structures/icons/storage.dmi' + resistance_flags = FLAMMABLE + base_build_path = /obj/machinery/smartfridge/wooden + icon_state = "producebin" + base_icon_state = "producebin" + use_power = NO_POWER_USE + light_power = 0 + idle_power_usage = 0 + circuit = null + has_emissive = FALSE + integrity_failure = 0 + can_atmos_pass = ATMOS_PASS_YES + visible_contents = TRUE + can_be_welded_down = FALSE + has_emissive = FALSE + vend_sound = null + +/obj/machinery/smartfridge/wooden/Initialize(mapload) + . = ..() + if(type == /obj/machinery/smartfridge/wooden) // don't even let these prototypes exist + return INITIALIZE_HINT_QDEL + +/obj/machinery/smartfridge/wooden/visible_items() + return contents.len + +// formerly NO_DECONSTRUCTION +/obj/machinery/smartfridge/wooden/default_deconstruction_screwdriver(mob/user, icon_state_open, icon_state_closed, obj/item/screwdriver) + return NONE + +/obj/machinery/smartfridge/wooden/default_deconstruction_crowbar(obj/item/crowbar, ignore_panel, custom_deconstruct) + return NONE + +/obj/machinery/smartfridge/wooden/default_pry_open(obj/item/crowbar, close_after_pry, open_density, closed_density) + return NONE + +/obj/machinery/smartfridge/wooden/crowbar_act(mob/living/user, obj/item/tool) + user.balloon_alert_to_viewers("disassembling...") + if(!tool.use_tool(src, user, 2 SECONDS, volume = 100)) + return + + deconstruct(TRUE) + return ITEM_INTERACT_SUCCESS + +/obj/machinery/smartfridge/wooden/on_deconstruction(disassembled) + new /obj/item/stack/sheet/mineral/wood(drop_location(), 10) + +/obj/machinery/smartfridge/wooden/structure_examine() + . = span_info("The whole rack can be [EXAMINE_HINT("pried")] apart.") + +/obj/machinery/smartfridge/wooden/produce_bin + name = "produce bin" + desc = "A wooden hamper, used to hold plant products and try to keep them safe from pests." + icon_state = "producebin" + base_icon_state = "producebin" + contents_overlay_icon = "produce" + base_build_path = /obj/machinery/smartfridge/wooden/produce_bin + +/obj/machinery/smartfridge/wooden/produce_bin/accept_check(obj/item/item_to_check) + var/static/list/accepted_items = list( + /obj/item/food/grown, + /obj/item/grown, + /obj/item/graft, + ) + + return is_type_in_list(item_to_check, accepted_items) + +/obj/machinery/smartfridge/wooden/seed_shelf + name = "seed shelf" + desc = "A wooden shelf, used to hold seeds, preventing them from germinating early." + icon_state = "seedshelf" + base_icon_state = "seedshelf" + contents_overlay_icon = "seed" + base_build_path = /obj/machinery/smartfridge/wooden/seed_shelf + +/obj/machinery/smartfridge/wooden/seed_shelf/accept_check(obj/item/item_to_check) + return istype(item_to_check, /obj/item/seeds) + +/obj/machinery/smartfridge/wooden/ration_shelf + name = "ration shelf" + desc = "A wooden shelf, used to store food... Preferably preserved." + icon_state = "rationshelf" + base_icon_state = "rationshelf" + contents_overlay_icon = "ration" + base_build_path = /obj/machinery/smartfridge/wooden/ration_shelf + +/obj/machinery/smartfridge/wooden/ration_shelf/accept_check(obj/item/item_to_check) + return (IS_EDIBLE(item_to_check) || (istype(item_to_check,/obj/item/reagent_containers/cup/bowl) && length(item_to_check.reagents?.reagent_list))) + +/obj/machinery/smartfridge/wooden/produce_display + name = "produce display" + desc = "A wooden table with awning, used to display produce items." + icon_state = "producedisplay" + base_icon_state = "producedisplay" + contents_overlay_icon = "nonfood" + base_build_path = /obj/machinery/smartfridge/wooden/produce_display + +/obj/machinery/smartfridge/wooden/produce_display/accept_check(obj/item/item_to_check) + var/static/list/accepted_items = list( + /obj/item/grown, + /obj/item/bouquet, + /obj/item/clothing/head/costume/garland, + ) + var/fancy_food = istype(item_to_check, /obj/item/food/grown) && item_to_check.slot_flags != NONE // mostly things like flowers + return fancy_food || is_type_in_list(item_to_check, accepted_items) diff --git a/modular_doppler/hearthkin/primitive_structures/code/totally_thatch_roof.dm b/modular_doppler/hearthkin/primitive_structures/code/totally_thatch_roof.dm new file mode 100644 index 0000000000000..5474ca0814259 --- /dev/null +++ b/modular_doppler/hearthkin/primitive_structures/code/totally_thatch_roof.dm @@ -0,0 +1,68 @@ +/turf/open/misc/grass/roofing + name = "thatched roof" + desc = "A collection of various dried greens, not so green anymore, that makes a passable roof material." + baseturfs = /turf/open/openspace/icemoon + initial_gas_mix = "ICEMOON_ATMOS" + icon_state = "grass-255" + icon = 'modular_doppler/hearthkin/primitive_structures/icons/thatch.dmi' + smooth_icon = 'modular_doppler/hearthkin/primitive_structures/icons/thatch.dmi' + + +/turf/open/floor/grass/thatch + name = "thatch patch" + desc = "A collection of various dried greens, not so green anymore, that makes a passable floor material" + icon_state = "grass-255" + base_icon_state = "grass" + icon = 'modular_doppler/hearthkin/primitive_structures/icons/thatch.dmi' + damaged_dmi = 'icons/turf/damaged.dmi' + floor_tile = /obj/item/stack/tile/grass/thatch + bullet_bounce_sound = null + smoothing_flags = SMOOTH_BITMASK + smoothing_groups = SMOOTH_GROUP_TURF_OPEN + SMOOTH_GROUP_FLOOR_GRASS + canSmoothWith = SMOOTH_GROUP_FLOOR_GRASS + SMOOTH_GROUP_CLOSED_TURFS + layer = HIGH_TURF_LAYER + /// Icon used for smoothing + var/smooth_icon = 'modular_doppler/hearthkin/primitive_structures/icons/thatch.dmi' + + +/turf/open/floor/grass/thatch/Initialize(mapload) + . = ..() + if(smoothing_flags) + var/matrix/translation = new + translation.Translate(-9, -9) + transform = translation + icon = smooth_icon + + +/turf/open/floor/grass/thatch/broken_states() + return list("grass_damaged") + + +/turf/open/floor/grass/thatch/burnt_states() + return list("grass_damaged") + + +/obj/item/stack/tile/grass/thatch + name = "thatch tile" + singular_name = "thatch floor tile" + desc = "A patch of thatch like in those old-school barns." + icon_state = "tile_thatch" + inhand_icon_state = "tile-thatch" + icon = 'modular_doppler/hearthkin/primitive_structures/icons/thatch_obj.dmi' + lefthand_file = 'modular_doppler/hearthkin/primitive_structures/icons/tile_lefthand.dmi' + righthand_file = 'modular_doppler/hearthkin/primitive_structures/icons/tile_righthand.dmi' + resistance_flags = FLAMMABLE + turf_type = /turf/open/floor/grass/thatch + merge_type = /obj/item/stack/tile/grass/thatch + + +/obj/item/food/grown/grass/thatch + name = "thatch" + desc = "Yellow and dry." + icon = 'modular_doppler/hearthkin/primitive_structures/icons/thatch_obj.dmi' + icon_state = "thatch_clump" + stacktype = /obj/item/stack/tile/grass/thatch + + +/obj/item/food/grown/grass/make_dryable() + AddElement(/datum/element/dryable, /obj/item/food/grown/grass/thatch) diff --git a/modular_doppler/hearthkin/primitive_structures/code/wall_torch.dm b/modular_doppler/hearthkin/primitive_structures/code/wall_torch.dm new file mode 100644 index 0000000000000..00a76e9e80917 --- /dev/null +++ b/modular_doppler/hearthkin/primitive_structures/code/wall_torch.dm @@ -0,0 +1,204 @@ +/obj/structure/wall_torch + name = "mounted torch" + desc = "A simple torch mounted to the wall, for lighting and such." + icon = 'modular_doppler/hearthkin/primitive_structures/icons/lighting.dmi' + icon_state = "walltorch" + base_icon_state = "walltorch" + anchored = TRUE + density = FALSE + light_color = LIGHT_COLOR_FIRE + /// Torch contained by the wall torch, if it was mounted manually. + /// Will be `TRUE` if it was intended to spawn in with a torch, + /// without actually initializing a torch in it to save on memory. + var/obj/item/flashlight/flare/torch/mounted_torch = TRUE + /// is the bonfire lit? + var/burning = FALSE + /// Does this torch spawn pre-lit? + var/spawns_lit = FALSE + /// What this item turns back into when wrenched off the wall. + var/wallmount_item_type = /obj/item/wallframe/torch_mount + +MAPPING_DIRECTIONAL_HELPERS(/obj/structure/wall_torch, 28) + +/obj/structure/wall_torch/Initialize(mapload) + . = ..() + if(mounted_torch && spawns_lit) + light_it_up() + + update_appearance(UPDATE_NAME | UPDATE_DESC | UPDATE_ICON_STATE) + find_and_hang_on_wall() + + +/obj/structure/wall_torch/Destroy() + drop_torch() // So it drops on the floor when destroyed. + return ..() + + +/obj/structure/wall_torch/update_icon_state() + icon_state = "[base_icon_state][mounted_torch ? (burning ? "_on" : "") : "_mount"]" + return ..() + + +/obj/structure/wall_torch/update_name(updates) + . = ..() + name = mounted_torch ? "mounted torch" : "torch mount" + + +/obj/structure/wall_torch/update_desc(updates) + . = ..() + desc = mounted_torch ? "A simple torch mounted to the wall, for lighting and such." : "A simple torch mount, torches go here." + + +/obj/structure/wall_torch/attackby(obj/item/used_item, mob/living/user, params) + if(!mounted_torch) + if(!istype(used_item, /obj/item/flashlight/flare/torch)) + return ..() + + mounted_torch = used_item + RegisterSignal(used_item, COMSIG_QDELETING, PROC_REF(remove_torch)) + used_item.forceMove(src) + update_appearance(UPDATE_NAME | UPDATE_DESC) + + if(mounted_torch.light_on) + light_it_up() + else + extinguish() + + mounted_torch.turn_off() + + return + + if(!burning && used_item.get_temperature()) + light_it_up() + else + return ..() + + +/obj/structure/wall_torch/fire_act(exposed_temperature, exposed_volume) + light_it_up() + + +/// Sets the torch's icon to burning and sets the light up +/obj/structure/wall_torch/proc/light_it_up() + burning = TRUE + set_light(4) + update_icon_state() + update_appearance(UPDATE_ICON) + + +/obj/structure/wall_torch/extinguish() + . = ..() + if(!burning) + return + + burning = FALSE + set_light(0) + update_appearance(UPDATE_ICON) + + +/obj/structure/wall_torch/attack_hand(mob/living/user, list/modifiers) + . = ..() + if(.) + return + + remove_torch(user) + + +/** + * Helper proc that handles removing the torch and trying to put it in the user's hand. + */ +/obj/structure/wall_torch/proc/remove_torch(mob/living/user, update_visuals = TRUE) + if(!mounted_torch) + return + + if(!istype(mounted_torch)) + mounted_torch = new(src) + + if(burning) + mounted_torch.toggle_light() + + if(user) + mounted_torch.attempt_pickup(user) + + else + mounted_torch.forceMove(drop_location()) + + UnregisterSignal(mounted_torch, COMSIG_QDELETING) + + mounted_torch = null + burning = FALSE + set_light(0) + update_appearance(UPDATE_ICON | UPDATE_NAME | UPDATE_DESC) + + +/obj/structure/wall_torch/wrench_act(mob/living/user, obj/item/tool) + tool.play_tool_sound(src) + to_chat(user, span_notice("You detach [src] from its place.")) + + remove_torch(user) + + var/obj/item/wallframe/torch_mount/mount_item = new /obj/item/wallframe/torch_mount(drop_location()) + transfer_fingerprints_to(mount_item) + + qdel(src) + return TRUE + + +/// Simple helper to drop the torch upon the mount being qdel'd. +/obj/structure/wall_torch/proc/drop_torch() + if(!mounted_torch) + return + + if(!istype(mounted_torch)) + mounted_torch = new(src) + + if(burning) + mounted_torch.toggle_light() + + mounted_torch.forceMove(drop_location()) + + UnregisterSignal(mounted_torch, COMSIG_QDELETING) + + mounted_torch = null + + +/obj/structure/wall_torch/mount_only + name = "torch mount" + mounted_torch = null + +MAPPING_DIRECTIONAL_HELPERS(/obj/structure/wall_torch/mount_only, 28) + + +/obj/structure/wall_torch/spawns_lit + spawns_lit = TRUE + +MAPPING_DIRECTIONAL_HELPERS(/obj/structure/wall_torch/spawns_lit, 28) + + +/obj/item/wallframe/torch_mount + name = "torch mount" + desc = "Used to attach torches to walls." + icon = 'modular_doppler/hearthkin/primitive_structures/icons/lighting.dmi' + icon_state = "walltorch_mount" + custom_materials = list(/datum/material/iron = SHEET_MATERIAL_AMOUNT) + result_path = /obj/structure/wall_torch/mount_only + pixel_shift = 28 + + +/obj/item/wallframe/torch_mount/try_build(turf/on_wall, mob/user) + if(get_dist(on_wall,user) > 1) + balloon_alert(user, "you are too far!") + return + + var/floor_to_wall = get_dir(user, on_wall) + if(!(floor_to_wall in GLOB.cardinals)) + balloon_alert(user, "stand in line with wall!") + return + + var/turf/user_turf = get_turf(user) + + if(check_wall_item(user_turf, floor_to_wall, wall_external)) + balloon_alert(user, "already something here!") + return + + return TRUE diff --git a/modular_doppler/hearthkin/primitive_structures/code/windows.dm b/modular_doppler/hearthkin/primitive_structures/code/windows.dm new file mode 100644 index 0000000000000..c2e38e491813e --- /dev/null +++ b/modular_doppler/hearthkin/primitive_structures/code/windows.dm @@ -0,0 +1,20 @@ +/obj/structure/window/green_glass_pane + name = "green glass window" + desc = "A handcrafted green glass window. At least you can still see through it." + icon = 'modular_doppler/hearthkin/primitive_structures/icons/windows.dmi' + icon_state = "green_glass" + flags_1 = NONE + obj_flags = parent_type::obj_flags | NO_DEBRIS_AFTER_DECONSTRUCTION + can_be_unanchored = FALSE + fulltile = TRUE + flags_1 = PREVENT_CLICK_UNDER_1 + +/datum/crafting_recipe/green_glass_pane + name = "green glass window" + result = /obj/structure/window/green_glass_pane + time = 0.2 SECONDS + reqs = list( + /datum/reagent/iron = 5, + /obj/item/stack/sheet/glass = 2, + ) + category = CAT_STRUCTURE diff --git a/modular_doppler/hearthkin/primitive_structures/code/wooden_ladder.dm b/modular_doppler/hearthkin/primitive_structures/code/wooden_ladder.dm new file mode 100644 index 0000000000000..136cc715d64e1 --- /dev/null +++ b/modular_doppler/hearthkin/primitive_structures/code/wooden_ladder.dm @@ -0,0 +1,7 @@ +// Ladder structure, behaves identical to a normal ladder except flammable + +/obj/structure/ladder/wood + name = "wooden ladder" + desc = "Up or down, whatever your mood you sure wood find what you're looking for with this ladder." + icon = 'modular_doppler/hearthkin/primitive_structures/icons/wooden_ladder.dmi' + resistance_flags = FLAMMABLE diff --git a/modular_doppler/hearthkin/primitive_structures/icons/lighting.dmi b/modular_doppler/hearthkin/primitive_structures/icons/lighting.dmi new file mode 100644 index 0000000000000000000000000000000000000000..be2d9f0d956a6e2f627a61c89cea9a684545fe75 GIT binary patch literal 2170 zcmV-=2!;2FP)V=-0C=2rjj;;CFc^gA{7-STtB6&>DT|~?hV~UCm}mlN0?Dt%w|D3wSh?jp z__%9v?k{?T8Z^CJsUasw9Jf0XbFl0oaoCgaE<8LhrLtiMiDou2axORDkg%atNOUCb z#Y}GDU-O#Nx_lyGT{Le z=6vUzna#Z443Nf%r>0SN4F5|+)0|P)@Z#0Eqb{bDBG%kO01%y(B$rb(&Zbx~)jw#_ zS*fG}$mfSOpPBB&6pb)(dqyKVE1B5XqPdvldIp^UZ`6rs#Me2wx^R#G_k`^khv=xF z=&0~VfVZ98PtjZ)_<@Tp^GU8r(h)T`)4}Qa;)R)+odEJBl26bZ_T-Bse%^KS!CccaUU1MNc(JLGn1sqyAJ7Bu-CXNAfL_F_O&` zT~&TJklE)L*p?7^RS19pHU%HV)e`|M z0WcTw-lYJ>xqlc0uvcoAwrniB2L_WqgC=x$j|Bjt>p}uR`F)?FqwWE$eDEp&Er|Di zq$CdDA;i1;9sTFxu?8PSB!&Y-ES$;E^D_$eGx+s zZ@2uZH~chgY=UL2l8Qlk3et&p8JKm&xHJ80$_YKZ-EZiX^#=fSOE*4{rU~#^S@XT_ z5Kww;-FbaqDgpV|T*uR`2hDX)_WR4__kN;WKb6Oy)*~PjkU9xZ%)Sg`^KQh~0LESp zOpL{V{d>;%y;PA&`cetV&CA2&>n9~`+qpwZUy4l9mrB4uEOy%UpvfeC>C2~Zehv$A zv$1<%5MBEYDY*{MM16A-){IGjW=sM!V-lbllK{<_1ZYM&0SA9Mmh`EbOwm8D5uoa3 zjL|n332meO zB939Th9|dH#B_}a(KLrn9Ch@Ppd*$<-)OKxjkBGDtS@p8{4^l|%m;~p>VmmDB!C>{t^(1$Vu!(;| z@*v5LB)?TN5+1*SBn8Fh zvS4lE?i^2k$z*mZZ2+<^LHl*Zjo&bXqNT*GS{Y0Tq$$t@_#XXN=W=-d_gKr3^<#m= z&@h8!E!kC>qz-rmgfCHSoEHr&0H;9WIg&rR-uOdq20y)%VJToQf2>3D`lhR!y;7M+M0iw>aZ%lFcLslnsC9c$-PCCAo&= zem9mFWiNlFd_nPd+hLbh!JgLw;AL3WV`}W-UUD6pE37@Lw9y-O^Phi^#SE8zDQb6Swv^4f4cQ_($AO?kgk~e z0L}WQK0vd+sSnVsZ|Vay>zk9XW=sM!V-lbllK{<_1Zc)2Kr^O3K(oH74@hHugTY`h z7(hO5>IEc`erlrVsis{#6&UJA{Ec0yjOnZ(dkK7|%#b_ka12Qat}q1_b zh62+L5~(RDw6Mz(eM7{hov;^0fN4bl+~oXlI56LiT|6IR%SqzkQH1W_W|1EgC;||J zWnE=?zRXZrd)iD(=l)Ch%b!7Z(0*(I>_xKxECuif;%)5+EqL2P*2SrgF$ue}5cu`D z>y-A+Jx4&UqFwq5?9yFC1{{^Xy=#1L$I18uRaZ^DK>_riXE3?SXtq4WZ=j7`l zcNJ9DZi!A1r<@KKD&K1T-ddh>$-<69DUEKV?roiZ1ADfRvhEK60H^xX^D@~ literal 0 HcmV?d00001 diff --git a/modular_doppler/hearthkin/primitive_structures/icons/railroad.dmi b/modular_doppler/hearthkin/primitive_structures/icons/railroad.dmi new file mode 100644 index 0000000000000000000000000000000000000000..2ec8d3ce0e635a85a591dd55afdec4871658dbc3 GIT binary patch literal 1862 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 literal 0 HcmV?d00001 diff --git a/modular_doppler/hearthkin/primitive_structures/icons/thatch.dmi b/modular_doppler/hearthkin/primitive_structures/icons/thatch.dmi new file mode 100644 index 0000000000000000000000000000000000000000..53299ab681d04856892597486d058970c7bc2d92 GIT binary patch literal 2678 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 BYheHY literal 0 HcmV?d00001 diff --git a/modular_doppler/hearthkin/primitive_structures/icons/tile_righthand.dmi b/modular_doppler/hearthkin/primitive_structures/icons/tile_righthand.dmi new file mode 100644 index 0000000000000000000000000000000000000000..3546b59d19ec73c2bd3adb5eef7992bc93441a06 GIT binary patch literal 309 zcmeAS@N?(olHy`uVBq!ia0vp^4j|0J3?w7mbKU|e{s5m4*8>L*6xeIt+h)7H((u*o zW|OU-+<;PyB|(0{3=Yq3qyaevRUr{2E~&-IMVSR9nfZAP3>9;N!wQN@zkdlX`1tjS zmbb3fxija3H-s8oG=A_%=e&>RNrs}H-W?XkLB^Mjy%gp=nsj7Rh(hp66=U_#?JCL} zRVmdKI;Vst08M3U AKL7v# literal 0 HcmV?d00001 diff --git a/modular_doppler/hearthkin/primitive_structures/icons/tribal_beds.dmi b/modular_doppler/hearthkin/primitive_structures/icons/tribal_beds.dmi new file mode 100644 index 0000000000000000000000000000000000000000..0b84f6d85d13d78d06e11eec5a0301b6c7278e1a GIT binary patch literal 2132 zcmV-a2&?yrP);DH|6wAs#Ow895~(E+8Ep6A|9F zJ?h(ow|OyeKPhQWMYgBE*U8}P{Qv*||9519IVK=+7?%nF0004WQchCV=-0C=2JR&a84_w-Y6@%7{?OD!tS%+FJ>RWQ*r;NmRLOex6# za*U0*I5Sc+(=$pSoZ^zil2jm5sUS6{Bt9uMB|a%9F*#d_i!&v&s2HT1i!-e#F*g;& zHbf{d$w(|o&H!mZC^f{c6mD{PMrKJWE|ZlNT>V_YE(ZV^{y43!3JhBS00$IFL_t(& zfyG&ia-2F01p}KvHf>{`%jW;T^GfH);LXG8Oy*AA0yeUBj9!+qRrQZsU3(LL#y`|` zZ~z>7RW*f1fZ_~~UN!C6nrwh>qX5k@{5-2|Jh}jM-Q{xWT}7140A$_28QKYOm|xf07Sfu=qXPgJ>9+mmvksbM>|L6T%cH9m2_bV9 z+kW#1@PURKmU{FGAK0AUOHrjs6j5tNl1<^`LJ^hd3IKgW`3*&5YLXEE8q*VvH)Zrj(xP3uK|o?F~!1;N5^^4 zbu=Yd)TJdIR&3`18FbVnB&iI#<2)$P31C**whTrjJpvqrbZ#(uHXc1cGI0{M7PCHD zQFoA%+j5OZ*Kpl5hp)7>f4aRi05sVv`nd%!UFy-R=jY~GS~ll7Wd!nC0Z8SWeA+XX zdi1K7XWyTbWb~X`-w$;?^x2DS8dvomy&C%Get7A7ntC?c zqgStkuos^~0-2uc}}2_WJt!&)b{MczgXV|K2bV z{+jxcgS;Z?iou`Xue$EnU(hSze*Ge)yvh{oITL&aUy<|I-UOGyzif3Ct1(t_(%U$W z75_)MNA3FS%PrK?IK>zzdCYNA2*tt`=W(1TZ@pU|EV9!WfdZgun&py?zMICSS_@49 zy!s#rSKYDVjDS)IVLsyhvTkQvvjMs*0Lt~j60u=ONMI&zpASJ3fLm(Y*;j!5mH>+N z!2)3jw^=X*Wajqu`2k=%0e0oT?>WG?^??FV_O@{WfSjo9MR%&)mEEQQGGzbwf^vPZ z==Nh`uaf6;f+3BngI#%U=>vrEz7dQ7PJI9+k5jb$YiFL4*d`H?YI6tw)x<-vT>+kI zw?0tzup*U7guGN0L=@7hwgY)XRy(j@Lwf=!*9U?2ACv9RBfO64n5VE}w>w!X`~5K2 z6QEQdgelIdS+yG7_Z&x)j|yv69jv(Yz9$!0b0wGSgP8;Leo(Ft!gN~EsPTsq8#yKbjMBuUmpR&IA}ZGh3;6IhL*MgZQ3jy=Hh350lsrv` z)IqU6SP(oZ4>2D#A(IuZK#p7TF0$XD=`|_2SRX7=0}vg-^qjPzCL31UeTqMaE2wRm z4vO_bh!hYV0ZxJAU}69dDx&QOK&lF$?GFH@`XErb2-gfq<8(%jqyr5>%JT;6G=STF z1iM0gfG-%a@6ohDt)o8^U{5+gEZX)D0LA(sm=8}D8nOdT9{|`Xl+D1t04UT4OFRNy zwD3R^Wl#+aM9B?kLHquogK~Ya;FPoz0p|^MY%w-IoRT+&y3^|zu8Z}-GBRFc@8fxF zvL{xw!oO0?qx~~vND~0BK3JgMbPkM+-KWf!Gle+Wo=pI}`XC@SM8s5u86Wsh;Vx|M z_nhfDxZj7`tq)rYwEE0`^v z4tZ*6^D<^0-K`I7hj@eJ{$_#KCVF(YKB$=&@C}z)Zj94o_2_PWP(Q7f1Z+I6rR6!l zM|bN3FxZpYHLb}+D5sT2ck2T%IE-v(j(_I-t4DY1gF}gHGWI=vIWCXx)(5AZpPpi_ zh1B1pyY+#JU^5f5NtWuY_(+fL)(67C;a(zG|G<*P?`>jT{(<+mFP^C>P|J-S;T zh>Xqgj^v)=;4W8>?$!s1!A>8fa5-x24=e4YvYkfr(e7o`3k-K`Jo z@Bd8buft$zKL7rIKYkzhmhRUFKmC2cuMd9u`+#2`{Pg#MBKbeqbGzBoN$L^+0000< KMNUMnLSTZL3GOTa literal 0 HcmV?d00001 diff --git a/modular_doppler/hearthkin/primitive_structures/icons/windows.dmi b/modular_doppler/hearthkin/primitive_structures/icons/windows.dmi new file mode 100644 index 0000000000000000000000000000000000000000..02f84bea3823db8cf505238fb815a930d00b1c03 GIT binary patch literal 432 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 SNpFFL4TGnvpUXO@geCy~W%(Td literal 0 HcmV?d00001 diff --git a/modular_doppler/hearthkin/primitive_structures/icons/wooden_ladder.dmi b/modular_doppler/hearthkin/primitive_structures/icons/wooden_ladder.dmi new file mode 100644 index 0000000000000000000000000000000000000000..b9a782ea52ae0c2ac7f1ff512f75e0ec309f9af5 GIT binary patch literal 747 zcmVV=-0C=2JR&a84_w-Y6@%7{?OD!tS%+FJ>RWQ*r;NmRLOex6#a*U0*I5Sc+ z(=$pSoZ^zil2jm5DJL-{CAG-FK#7YpC9|j)C}haRnO2mTn+jp0DKsQjp@AW>CgN16 ztl;YB0`?RDM0PzHEMzxO0006mNklo_U;vhiN)SW=f#_0&URxI{q|Q0X*)hH+MTye$J?C=1SH}*53gdh~j5}vX zF`N(A>M^z**vf5HwkyTEX%1NrBhZUJ&_10Bz{PP3ZQI`247!gmC|f5201tH14oQ4F z5de6ba6lli_5h5%69E9gxW2sW*D$tF1b3UOD8EapAF-9R?6xMM3;+Pe9yax4P>$O& zkvRmeyZyR$RHJ*kU>f~A%oTca#r-4pw5bp4P<5jwG1&B3p)7g zX(|zKCo90i=fWg~fdaUD(bKsfpeWEm3v8tV;Idz1X$tAO_b z(2~JZDJ50tMY;N7g`Z_G?dEX!J-e#U9Tt(HUw^nFXp*02gV;_Kk)bj`#qYfecpm`e z5Ri9j0wA>nk}0-m1~$E)FU}_T(OYC>!nER&l%BGt#MJzMCMIIyu-)9!@2vt)(evbt doeY`c{{d8({Z;6U0YU%(002ovPDHLkV1l~`Oz;2z literal 0 HcmV?d00001 diff --git a/modular_doppler/hearthkin/primitive_structures/readme.md b/modular_doppler/hearthkin/primitive_structures/readme.md new file mode 100644 index 0000000000000..038eb3b894cd9 --- /dev/null +++ b/modular_doppler/hearthkin/primitive_structures/readme.md @@ -0,0 +1,23 @@ +## Title: PRIMITIVE + +### Description: + +Contains various items of primitive style for icecats and sometimes even ashwalkers + +### TG Proc/File Changes: + +- N/A + +### Defines: + +- N/A + +### Master file additions + +- N/A + +### Included files that are not contained in this module: + +- N/A + +### Credits: diff --git a/modular_doppler/indicators/code/combat_indicator.dm b/modular_doppler/indicators/code/combat_indicator.dm new file mode 100644 index 0000000000000..567e1d3a8d39c --- /dev/null +++ b/modular_doppler/indicators/code/combat_indicator.dm @@ -0,0 +1,237 @@ +#define COMBAT_NOTICE_COOLDOWN (10 SECONDS) +GLOBAL_VAR_INIT(combat_indicator_overlay, GenerateCombatOverlay()) + +/proc/GenerateCombatOverlay() + var/mutable_appearance/combat_indicator = mutable_appearance('modular_doppler/indicators/icons/combat_indicator.dmi', "combat", FLY_LAYER) + combat_indicator.appearance_flags = APPEARANCE_UI_IGNORE_ALPHA | KEEP_APART + return combat_indicator + +/mob/living + /// Is combat indicator enabled for this mob? Boolean. + var/combat_indicator = FALSE + /// When is the next time this mob will be able to use flick_emote and put the fluff text in chat? + var/nextcombatpopup = 0 + +/** + * Called whenever a mob inside a vehicle/sealed/ toggles CI status. + * + * Tied to the COMSIG_MOB_CI_TOGGLED signal, said signal is assigned when a mob enters a vehicle and unassigned when the mob exits, and is sent whenever set_combat_indicator is called. + * + * Arguments: + * * source -- The mob in question that toggled CI status. + */ + +/obj/vehicle/sealed/proc/mob_toggled_ci(mob/living/source) + SIGNAL_HANDLER + if ((src.max_occupants > src.max_drivers) && (!(source in return_drivers())) && (src.driver_amount() > 0)) // Only returms true if the mob in question has the driver control flags and/or there are drivers. + return + combat_indicator_vehicle = source.combat_indicator // Sync CI between mob and vehicle. + if (combat_indicator_vehicle) + if(world.time > vehicle_next_combat_popup) // As of the time of writing, COMBAT_NOTICE_COOLDOWN is 10 secs, so this is asking "has 10 secs past between last activation of CI?" + vehicle_next_combat_popup = world.time + COMBAT_NOTICE_COOLDOWN + playsound(src, 'sound/machines/chime.ogg', vol = 10, vary = FALSE, extrarange = -6, falloff_exponent = 4, frequency = null, channel = 0, pressure_affected = FALSE, ignore_walls = FALSE, falloff_distance = 1) + flick_emote_popup_on_obj("combat", 20) + visible_message(span_boldwarning("[src] prepares for combat!")) + combat_indicator_vehicle = TRUE + else + combat_indicator_vehicle = FALSE + update_appearance(UPDATE_ICON|UPDATE_OVERLAYS) + +/mob/living/update_overlays() + . = ..() + if(combat_indicator) + . += GLOB.combat_indicator_overlay + +/obj/vehicle/sealed/update_overlays() + . = ..() + if(combat_indicator_vehicle) + . += GLOB.combat_indicator_overlay + +/** + * Called whenever a mob's stat changes. + * Checks if the mob's stat is greater than SOFT_CRIT, and if it is, it will disable CI. + * + * Arguments: + * * source -- The mob in question that toggled CI status. + * * new_stat -- The new stat of the mob. + */ + +/mob/living/proc/ci_on_stat_change(mob/source, new_stat) + SIGNAL_HANDLER + if(new_stat <= SOFT_CRIT) + return + set_combat_indicator(FALSE, involuntary = TRUE) + +/** + * Called whenever a mob's CI status changes for any reason. + * + * Checks if the mob is dead, if config disallows CI, or if the current CI status is the same as state, and if it is, it will change CI status to state. + * + * Arguments: + * * state -- Boolean. Inherited from the procs that call this, basically it's what that proc wants CI to change to - true or false, on or off. + * * involuntary -- Boolean. If true, the mob is dead or unconscious, and the log will reflect that. + */ + +/mob/living/proc/set_combat_indicator(state, involuntary = FALSE) + if(!CONFIG_GET(flag/combat_indicator)) + return + + if(combat_indicator == state) // If the mob is dead (should not happen) or if the combat_indicator is the same as state (also shouldnt happen) kill the proc. + return + + if(stat == DEAD) + disable_combat_indicator(involuntary) + + combat_indicator = state + + SEND_SIGNAL(src, COMSIG_MOB_CI_TOGGLED) + + if(combat_indicator) + enable_combat_indicator() + else + disable_combat_indicator() + +/** + * Called whenever a mob enables CI. + * + * Plays a sound, sents a message to chat, updates their overlay, and sets the mob's CI status to true. + */ + +/mob/living/proc/enable_combat_indicator() + if(world.time > nextcombatpopup) // As of the time of writing, COMBAT_NOTICE_COOLDOWN is 10 secs, so this is asking "has 10 secs past between last activation of CI?" + nextcombatpopup = world.time + COMBAT_NOTICE_COOLDOWN + playsound(src, 'sound/machines/chime.ogg', vol = 10, vary = FALSE, extrarange = -6, falloff_exponent = 4, frequency = null, channel = 0, pressure_affected = FALSE, ignore_walls = FALSE, falloff_distance = 1) + flick_emote_popup_on_mob("combat", 20) + var/ciweapon + if(get_active_held_item()) + ciweapon = get_active_held_item() + if(istype(ciweapon, /obj/item/gun)) + visible_message(span_boldwarning("[src] raises \the [ciweapon] with their finger on the trigger, ready for combat!")) + else + visible_message(span_boldwarning("[src] readies \the [ciweapon] with a tightened grip and offensive stance, ready for combat!")) + else + if(issilicon(src)) + visible_message(span_boldwarning("[src] shifts its armour plating into a defensive stance, ready for combat!")) + if(ishuman(src)) + visible_message(span_boldwarning("[src] raises [p_their()] fists in an offensive stance, ready for combat!")) + if(isalien(src)) + visible_message(span_boldwarning("[src] hisses in a terrifying stance, claws raised and ready for combat!")) + else + visible_message(span_boldwarning("[src] gets ready for combat!")) + combat_indicator = TRUE + apply_status_effect(/datum/status_effect/grouped/surrender, src) + log_message("[src] has turned ON the combat indicator!", LOG_ATTACK) + RegisterSignal(src, COMSIG_MOB_STATCHANGE , PROC_REF(ci_on_stat_change)) + update_appearance(UPDATE_ICON|UPDATE_OVERLAYS) + +/** + * Called whenever a mob disables CI. Or when they die or fall unconscious. + * + * Arguments: + * * involuntary -- Boolean. If true, the mob is dead or unconscious, and the log will reflect that. + */ + +/mob/living/proc/disable_combat_indicator(involuntary = FALSE) + combat_indicator = FALSE + remove_status_effect(/datum/status_effect/grouped/surrender, src) + if(involuntary) + log_message("[src] has fallen unconsious or has died and lost their combat indicator!", LOG_ATTACK) + else + log_message("[src] has turned OFF the combat indicator!", LOG_ATTACK) + UnregisterSignal(src, COMSIG_MOB_STATCHANGE) + update_appearance(UPDATE_ICON|UPDATE_OVERLAYS) + +/** + * Called whenever the user hits their combat indicator keybind, defaulted to C. + * + * If the user is conscious, it will set CI to be whatever the opposite of what it is currently. + */ + +/mob/living/proc/user_toggle_combat_indicator() + if(stat != CONSCIOUS) + return + set_combat_indicator(!combat_indicator) // Set CI status to whatever is the opposite of the current status. + +/** + * Called whenever a mob enters a vehicle/sealed, after everything else. + * + * Sets the vehicle's CI status to that of the mob if the mob is a driver and there are no other drivers, or if the mob is a passenger and there are no drivers. + * + * Arguments: + * * user -- mob/living, the mob that is entering the vehicle. + */ + +/obj/vehicle/sealed/proc/handle_ci_migration(mob/living/user) + if(!typesof(user.loc, /obj/vehicle/sealed)) //Sanity check: If the mob's location (not the tile they are on) is NOT a type of vehicle/sealed, kill the proc. + return + //If the vehicle can have more passenger seats than driver seats (note: each driver seat counts as a passenger seat) AND both: The mob is not a driver, and the vehicle has a driver, return. + if ((src.max_occupants > src.max_drivers) && ((!(user in return_drivers())) && (src.driver_amount() > 0))) + return + if (user.combat_indicator && !combat_indicator_vehicle) // Finally, if all conditions prior are not met, and the mob has CI enabled and the vehicle doesn't, enable CI. + combat_indicator_vehicle = TRUE + update_appearance(UPDATE_ICON|UPDATE_OVERLAYS) + +/** + * Called whenever a mob exits a vehicle/sealed, after everything else. + * + * Disables the vehicle's CI if it was enabled, and if it was the only occupant (or there was noone else in the mech with CI enabled). + * + * Arguments: + * * user -- mob/living, the mob that is exiting the vehicle. + */ + +/obj/vehicle/sealed/proc/disable_ci(mob/living/user) + // If the vehicle can have more occupants than drivers, and either 1. The mob is not a driver and the vehicle has drivers, or 2. The user IS a driver but there is an occupant (drivers count as occupants), return. + if ((src.max_occupants > src.max_drivers) && ((!(user in return_drivers()) && (src.driver_amount() > 0)) || ((user in return_drivers()) && (src.occupant_amount() > 0)))) + return + // If the preceding conditions are not met, and the vehicle has CI, look at each occupant to see if there is a non-driver with CI enabled. If yes, stop the proc, if no, disable CI. + if (combat_indicator_vehicle) + var/has_occupant_with_ci = FALSE + if (src.occupant_amount() > src.driver_amount()) + for (var/mob/living/vehicle_occupant in return_occupants()) + if (vehicle_occupant in return_drivers()) //this for loop does not account for multiple clowns in clown cars. i will not account for that. fuck that. + continue + if (vehicle_occupant.combat_indicator) + has_occupant_with_ci = TRUE + break + if (!has_occupant_with_ci) + combat_indicator_vehicle = FALSE + update_appearance(UPDATE_ICON|UPDATE_OVERLAYS) + +#undef COMBAT_NOTICE_COOLDOWN + +/datum/keybinding/living/combat_indicator + hotkey_keys = list("C") + name = "combat_indicator" + full_name = "Combat Indicator" + description = "Indicates that you're escalating to mechanics. YOU NEED TO USE THIS" + keybind_signal = COMSIG_KB_LIVING_COMBAT_INDICATOR + +/datum/keybinding/living/combat_indicator/down(client/user) + . = ..() + if(.) + return + var/mob/living/L = user.mob + L.user_toggle_combat_indicator() + +/datum/config_entry/flag/combat_indicator + +// Surrender shit +/atom/movable/screen/alert/status_effect/surrender/ + desc = "You're either in combat or being held up. Click here to surrender and show that you don't wish to fight. You will be incapacitated. (You can also say '*surrender' at any time to do this.)" + +/datum/emote/living/surrender + message = "drops to the floor and raises their hands defensively! They surrender%s!" + stat_allowed = SOFT_CRIT + +/datum/emote/living/surrender/run_emote(mob/user, params, type_override, intentional) + . = ..() + if(. && isliving(user)) + var/mob/living/living_user = user + living_user.set_combat_indicator(FALSE) + +/datum/emote/living/surrender/select_message_type(mob/user, intentional) + var/mob/living/living_mob = user + if(living_mob?.body_position == LYING_DOWN) + return "raises their hands defensively! They surrender%s!" + . = ..() diff --git a/modular_doppler/indicators/code/emote_popup.dm b/modular_doppler/indicators/code/emote_popup.dm new file mode 100644 index 0000000000000..e262c38b57950 --- /dev/null +++ b/modular_doppler/indicators/code/emote_popup.dm @@ -0,0 +1,64 @@ +/obj/effect/overlay/emote_popup + icon = 'modular_doppler/indicators/icons/popup_flicks.dmi' + icon_state = "combat" + layer = FLY_LAYER + plane = GAME_PLANE + appearance_flags = APPEARANCE_UI_IGNORE_ALPHA | KEEP_APART + mouse_opacity = MOUSE_OPACITY_TRANSPARENT + +/** + * A proc type that, when called, causes a image/sprite to appear above whatever entity it is called on. + * + * There are two types: on_mob and on_obj, they can only be called on their respective typepaths. + * + * Arguments: + * * state -- The icon_state of whatever .dmi file you're attempting to use for the sprite, in "" format. Ex. "combat", not combat.dmi. + * * time -- The amount of time the sprite remains before remove_emote_popup_on_mob is called. Is used in the addtimer. + */ +/mob/living/proc/flick_emote_popup_on_mob(state, time) + var/obj/effect/overlay/emote_popup/emote_overlay = new + emote_overlay.icon_state = state + vis_contents += emote_overlay + animate(emote_overlay, alpha = 255, time = 5, easing = BOUNCE_EASING, pixel_y = 10) + addtimer(CALLBACK(src, PROC_REF(remove_emote_popup_on_mob), emote_overlay), time) + +/** + * A proc type that, when called, causes a image/sprite to appear above whatever entity it is called on. + * + * There are two types: on_mob and on_obj, they can only be called on their respective typepaths. + * + * Arguments: + * * state -- The icon_state of whatever .dmi file you're attempting to use for the sprite, in "" format. Ex. "combat", not combat.dmi. + * * time -- The amount of time the sprite remains before remove_emote_popup_on_obj is called. Is used in the addtimer. + */ + +/obj/proc/flick_emote_popup_on_obj(state, time) + var/obj/effect/overlay/emote_popup/emote_overlay = new + emote_overlay.icon_state = state + vis_contents += emote_overlay + animate(emote_overlay, alpha = 255, time = 5, easing = BOUNCE_EASING, pixel_y = 10) + addtimer(CALLBACK(src, PROC_REF(remove_emote_popup_on_obj), emote_overlay), time) + +/** + * A proc that is automatically called whenever flick_emote_popup_on_mob's addtimer expires, and removes the popup. + * + * Arguments: + * * emote_overlay -- Inherits state from the preceding proc. + */ + +/mob/living/proc/remove_emote_popup_on_mob(obj/effect/overlay/emote_popup/emote_overlay) + vis_contents -= emote_overlay + qdel(emote_overlay) + return + +/** + * A proc that is automatically called whenever flick_emote_popup_on_obj's addtimer expires, and removes the popup. + * + * Arguments: + * * emote_overlay -- Inherits state from the preceding proc. + */ + +/obj/proc/remove_emote_popup_on_obj(obj/effect/overlay/emote_popup/emote_overlay) + vis_contents -= emote_overlay + qdel(emote_overlay) + return diff --git a/modular_doppler/indicators/code/sealed.dm b/modular_doppler/indicators/code/sealed.dm new file mode 100644 index 0000000000000..15b1c7f2e15ad --- /dev/null +++ b/modular_doppler/indicators/code/sealed.dm @@ -0,0 +1,17 @@ +/obj/vehicle/sealed + /// Is combat indicator on for this vehicle? Boolean. + var/combat_indicator_vehicle = FALSE + /// When is the next time this vehicle will be able to use flick_emote and put the fluff text in chat? + var/vehicle_next_combat_popup = 0 + +//Register the signal to the mob and mechs will listen for when CI is toggled, then call the parent proc, then turn on CI if the mob had CI on. +/obj/vehicle/sealed/add_occupant(mob/occupant_entering, control_flags) + RegisterSignal(occupant_entering, COMSIG_MOB_CI_TOGGLED, PROC_REF(mob_toggled_ci)) + . = ..() + handle_ci_migration(occupant_entering) + +//Unregister the signal then disable CI if the vehicle has no other drivers within it. +/obj/vehicle/sealed/remove_occupant(mob/occupant_exiting) + UnregisterSignal(occupant_exiting, COMSIG_MOB_CI_TOGGLED) + . = ..() + disable_ci(occupant_exiting) diff --git a/modular_doppler/indicators/code/ssd_indicator.dm b/modular_doppler/indicators/code/ssd_indicator.dm new file mode 100644 index 0000000000000..79bd363de019e --- /dev/null +++ b/modular_doppler/indicators/code/ssd_indicator.dm @@ -0,0 +1,38 @@ +GLOBAL_VAR_INIT(ssd_indicator_overlay, mutable_appearance('modular_doppler/indicators/icons/ssd_indicator.dmi', "default0", FLY_LAYER)) + +/mob/living + var/ssd_indicator = FALSE + var/lastclienttime = 0 + +/mob/living/proc/set_ssd_indicator(state) + if(state == ssd_indicator) + return + ssd_indicator = state + if(ssd_indicator) + add_overlay(GLOB.ssd_indicator_overlay) + log_message("has went SSD and got their indicator!", LOG_ATTACK) + else + cut_overlay(GLOB.ssd_indicator_overlay) + log_message("is no longer SSD and lost their indicator!", LOG_ATTACK) + +/mob/living/Login() + . = ..() + set_ssd_indicator(FALSE) + +/mob/living/Logout() + lastclienttime = world.time + set_ssd_indicator(TRUE) + . = ..() + +//Temporary, look below for the reason +/mob/living/ghostize(can_reenter_corpse = TRUE) + . = ..() + set_ssd_indicator(FALSE) + +/* +//EDIT - TRANSFER CKEY IS NOT A THING ON THE TG CODEBASE, if things break too bad because of it, consider implementing it +//This proc should stop mobs from having the overlay when someone keeps jumping control of mobs, unfortunately it causes Aghosts to have their character without the SSD overlay, I wasn't able to find a better proc unfortunately +/mob/living/transfer_ckey(mob/new_mob, send_signal = TRUE) + ..() + set_ssd_indicator(FALSE) +*/ diff --git a/modular_doppler/indicators/icons/DNR_trait_overlay.dmi b/modular_doppler/indicators/icons/DNR_trait_overlay.dmi new file mode 100644 index 0000000000000000000000000000000000000000..950b5503c00eb03ff0b3d40f03ee305104b6295f GIT binary patch literal 264 zcmeAS@N?(olHy`uVBq!ia0vp^3LwnE1|*BCs=ffJoT`wB5|`BCkq)?Vp-kR2URZC;>OZHdKB;E_<9?${W z8}8}i7!uL?_Ub|20|q=y4l8y||9p~RrU~;GXSL$v4+Qrxs5ho~HGP)Lu3})cU^G3( z)Nozwo^AJ@9ZVDEi(jy1yv)|OrTfT4v(Ma2910B#U}7EnAMxcv9UhK1*nw6sc)I$z JtaD0e0svs+WbOa} literal 0 HcmV?d00001 diff --git a/modular_doppler/indicators/icons/combat_indicator.dmi b/modular_doppler/indicators/icons/combat_indicator.dmi new file mode 100644 index 0000000000000000000000000000000000000000..f4987e829ba8a191cb589cb0ee8bc9e04febf0da GIT binary patch literal 749 zcmeAS@N?(olHy`uVBq!ia0vp^4M3d0!3HF+R#kZdsrssrh!U67;^d;tf|AVqJO+k} zIl0F-avd@dV0-ZMoo3yw&?6z&qg7muw!9ZOo5{4T^+`ZYHGBBaW$TYu?rD*%3{0AyE{-7;bKc(FoqISyfc0YR!KDTPoPKv0BiBZ< zco!Uq+QO&8wdp~HeB;c?KPJaGNpuMC*rkWI?$BGT?~p9XFo*E~f~YO&OMO;W6CXN% z?(KK~_uv17#}a#-<|P&ll>9S@6q{;8{eN_Z+d>> z+Q<37@7~V;?fhpmP+LIgd`ZEb?&lfy@{P{-PEPJI_Ezg<1*vZY?DckNO@cv->o$oaa7WQn1h_x8I zx|n>1nbEqZul>vTQf#;Vv6S0e`RfKn|G$3Cx0P2=QmU_Oo5wG3S!Cxr=kw|vJLZcU zWbJ>q|Ax}8|FwTU)>Ivt;l9LwOMT?^fAxv~H^pDiPAOq8IQ0DS%HPv#_wN@jx09^7?^$;JYD@<);T3K0RURpK|KHf literal 0 HcmV?d00001 diff --git a/modular_doppler/indicators/icons/emote_indicator.dmi b/modular_doppler/indicators/icons/emote_indicator.dmi new file mode 100644 index 0000000000000000000000000000000000000000..97defc8388f3205eeda0a03013ed34bede71d845 GIT binary patch literal 728 zcmeAS@N?(olHy`uVBq!ia0vp^2_VeD1|%QND7OGo{Z%0mB`&GO$wiq3C7Jno3=9=> zN>6X(JES1OdST{wQS-N6K3fg;9lapY_D$a4f>Y3KmVn3itu0E5Yz}7@%I1|dN$T!( z(#yPmAYggl5$m5)2Vdx`BzbtRv7hoPi(&D{#Io~S%Xm5G7coBeNjmpVkW0drQ$FlF zqqDc}*N^Y2er978JRyuEwSm&sA2 z;oEInHj-|O z%64&?5+s+r=vtNO-&pO)=lol*oqx#xzP*00+%6rZ&wmt^`uN{(>A1;0Kjq)5tFo{2 zzcH?3FOa>`L$mkJT6_1Qug32`SNmOi>;?06 z+x=4K?f8otWYN?^a^M5B_{A z6Z~AgK3TT#hoAjBuBtZe!qz5f4@(mMVVXQnHF^}J>BIe+}}^RJt4u+Es* zzx@2`^o<>_nT?|5Z$IvT{#f}|9ovOJ-`R6kbSrO~d6)I)`S*u&HHZ!jkWb$*|JnJS V;YssOFJMw-@O1TaS?83{1ONeyHm(2w literal 0 HcmV?d00001 diff --git a/modular_doppler/indicators/icons/popup_flicks.dmi b/modular_doppler/indicators/icons/popup_flicks.dmi new file mode 100644 index 0000000000000000000000000000000000000000..4224b98ac6e4567adcec05e04a99fbaf19fd3336 GIT binary patch literal 520 zcmV+j0{8uiP)V=-0C=2*%P|hZFc1aN+Ixzxq(=m3-5^KEMREs&7i@{d(RxX)PXQ7o-AwUX zocoI(;Ra7DOU-45#c8)Ev*oA>7RLjb#QBl*GgX5!ESmZf;W@H2WMY;Ii;m1)!o=Tx zma@R2`FFme|Bg83AXE1GvalcfV(xXKO(=ve^Iaa89Y@9fE|FX1i%i! zRsvuLU@HNz1F)3<*a6r|0PFy4B>;8+wh{n409y%w9e}NW58xZEZiB4?6$7jQ0000< KMNUMnLSTZ9DBbJ; literal 0 HcmV?d00001 diff --git a/modular_doppler/indicators/icons/ssd_indicator.dmi b/modular_doppler/indicators/icons/ssd_indicator.dmi new file mode 100644 index 0000000000000000000000000000000000000000..3f7d100b6c67e725055ef21a964cbcbb113dca6c GIT binary patch literal 311 zcmeAS@N?(olHy`uVBq!ia0vp^3LwnE1|*BCs=ffJ{HliLl8Vm$j4_H-qwSRlG-d9=Bb7470iYcT0gf&&Q+`DHA9k#g1nzrpr!Ksf{3onM7 zt~9UWyzn9_sPVDb6Mr#vp58;BU%iWc)ikAF(|NJtR<-gE?}Z*GC8T-FPfC$i=+qJG z0$Sbd>Eaj?(fam^A>RQ74%UGE9|QLOf3o&PfT5_*@}|@3hKi<|{#~sdQzl#Xud3cD(Xnp937P3qET zuudpu*edNf;oHvH1)_z&{9m+BU|`}5|`BCki*hDIPeSIX}k2aJpCP0S_IK>Yw*z&6E|lF5-{UlA78SwyGRx zajK__V@O16vQ5DQhQkg_%NV!TUSV9!CsBG}1+$y1!K;Qq_8zMQ1B-^%dDCv**XffE zU^f7PC37{~HmA@0a><@6ZRQuH%O#};9KYUkeetK!vt>g-0uac&6$k3P!l- zN>6X(JES1OdST{wQS-N6K3fg;9lapY_D$a4f>Y3KmVn3itu0E5Yz}7@%I1|dN$T!( z(#yPmAYggl5$m5)2Vdx`BzbtRv7hoPi(&D{#Io~S%Xm5G7coBeNjmpVkW0drQ$FlF zqqDc}*N^Y2rjAz z!$rwL<6TX9ho0{0SmPjmx&Qil7S7IZ&-Y5ttX>e%m9i`*C+=WMwyu(r(PugBwOeoh zO5YnYcmCR~C(itqN!og4hAP+j^Bp&2?6Nxd#_v1zCwM*g>-uR7Gd6#Uqn6q`TV--v-kFMd8$@e z)qfWG@-ElXY3WbT`!%aS|7V!Nn84N`$&f}ABf{;-mzS<==9O*urMj-`iD@ z=J#31w*7tV{!4%E_AgI=cBT4H4sJEN`5q~PV{vo|bXPzP1U`sZiEs}IkaSM6s8k?bENxJa;zhv7H# Y)mG`&^w{Z4z_iHV>FVdQ&MBb@08$1fG5`Po literal 0 HcmV?d00001 diff --git a/modular_doppler/indicators/readme.md b/modular_doppler/indicators/readme.md new file mode 100644 index 0000000000000..248a0c8de4b0c --- /dev/null +++ b/modular_doppler/indicators/readme.md @@ -0,0 +1,42 @@ +https://github.com/Skyrat-SS13/Skyrat-tg/pull/9922 -- Mech CI PR from Niko + +## Title: Indicators + +MODULE ID: INDICATORS + +### Description: + +The compilation of all player indicators (CI, SSD, Typing) +Combat Indicator - Toggleable by players, declares intent to engage in combat +SSD Indicator - Automatically shows when a player has disconnected +Typing Indicator - Shows when a player is typing +Emote Popup - Added from another module because it was only by Combat Indicator + +### TG Proc Changes: +Combat Indicator + - ADDITION: code/modules/mob/living/death.dm > /mob/living/death() + - CHANGE: code/datums/keybinding/mob.dm > /datum/keybinding/mob/toggle_move_intent() +Typing Indicator + - APPEND: code/modules/keybindings/setup.dm > /datum/proc/key_down() + - ADDITION: code/onclick/_click.dm > /mob/proc/ClickOn() + - ADDITION: code/modules/mob/mob_say.dm > /mob/verb/say_verb(), /mob/verb/me_verb() + - CHANGE: code\modules\mob\living\living_say.dm > /mob/living/send_speech + - ADDITION: code/modules/mob/living/death.dm > /mob/living/death() +SSD Indicator + ./code/modules/mob/living/carbon/human/examine.dm > /mob/living/carbon/human/examine() + - ADDITION: code/modules/mob/living/death.dm > /mob/living/death() + +### Defines: + +N/A + +### Included files: + +N/A + +### Credits: + +Azarak - Porting and OG code for Combat Indicator, Typing Indicator, SSD Indicator +FlamingLily - Consolidation, surrender alert +Niko - making CI work with mechs and stuff +GoldenAlphrex - Being invaluably helpful in telling me (niko) how to do things diff --git a/modular_doppler/modular_chemistry/reagents/code/reagents.dm b/modular_doppler/modular_chemistry/reagents/code/reagents.dm new file mode 100644 index 0000000000000..97411f3583ccd --- /dev/null +++ b/modular_doppler/modular_chemistry/reagents/code/reagents.dm @@ -0,0 +1,4 @@ +/datum/reagent + /// Modular version of `chemical_flags`, so we don't have to worry about + /// it causing conflicts in the future. + var/chemical_flags_doppler = NONE diff --git a/modular_doppler/modular_mob_spawn/code/mob_spawn.dm b/modular_doppler/modular_mob_spawn/code/mob_spawn.dm new file mode 100644 index 0000000000000..ba8a290d49f72 --- /dev/null +++ b/modular_doppler/modular_mob_spawn/code/mob_spawn.dm @@ -0,0 +1,80 @@ +/obj/effect/mob_spawn + /// Do we use a random appearance for this role? + var/random_appearance = TRUE + +/obj/effect/mob_spawn/ghost_role + /// set this to make the spawner use the outfit.name instead of its name var for things like cryo announcements and ghost records + /// modifying the actual name during the game will cause issues with the GLOB.mob_spawners associative list + var/use_outfit_name + /// Can we use our loadout for this role? + var/loadout_enabled = FALSE + /// Can we use our quirks for this role? + var/quirks_enabled = FALSE + /// Are we limited to a certain species type? LISTED TYPE + var/restricted_species + +/obj/effect/mob_spawn/ghost_role/create(mob/mob_possessor, newname) + var/load_prefs = FALSE + //if we can load our own appearance and it's not restricted, try + if(!random_appearance && mob_possessor?.client) + //if we have gotten to this point, they have already waived their species pref.-- they were told they need to use the specific species already + if((restricted_species && (mob_possessor?.client?.prefs?.read_preference(/datum/preference/choiced/species) in restricted_species)) || !restricted_species) + var/appearance_choice = tgui_alert(mob_possessor, "Use currently loaded character preferences?", "Appearance Type", list("Yes", "No")) + if(appearance_choice == "Yes") + load_prefs = TRUE + + var/mob/living/spawned_mob = ..(mob_possessor, newname, load_prefs) + + var/mob/living/carbon/human/spawned_human + if (istype(spawned_mob, /mob/living/carbon/human)) + spawned_human = spawned_mob + + if(!load_prefs) + var/datum/language_holder/holder = spawned_human.get_language_holder() + holder.get_selected_language() //we need this here so a language starts off selected + + return spawned_human + + spawned_human?.client?.prefs?.safe_transfer_prefs_to(spawned_human) + spawned_human.dna.update_dna_identity() + if(spawned_human.mind) + spawned_human.mind.name = spawned_human.real_name // the mind gets initialized with the random name given as a result of the parent create() so we need to readjust it + spawned_human.dna.species.give_important_for_life(spawned_human) // make sure they get plasmaman/vox internals etc before anything else + + if(quirks_enabled) + SSquirks.AssignQuirks(spawned_human, spawned_human.client) + + post_transfer_prefs(spawned_human) + + if(load_prefs && loadout_enabled) + spawned_human?.equip_outfit_and_loadout(outfit, spawned_mob.client.prefs) + else if (!isnull(spawned_human)) + equip(spawned_human) + + return spawned_mob + +/// This edit would cause somewhat ugly diffs, so I'm just replacing it. +/// Original proc in code/modules/mob_spawn/mob_spawn.dm ~line 39. +/obj/effect/mob_spawn/create(mob/mob_possessor, newname, is_pref_loaded) + var/mob/living/spawned_mob = new mob_type(get_turf(src)) //living mobs only + name_mob(spawned_mob, newname) + special(spawned_mob, mob_possessor) + if(!is_pref_loaded) + equip(spawned_mob) + return spawned_mob + +// Anything that can potentially be overwritten by transferring prefs must go in this proc +// This is needed because safe_transfer_prefs_to() can override some things that get set in special() for certain roles, like name replacement +// In those cases, please override this proc as well as special() +// TODO: refactor create() and special() so that this is no longer necessary +/obj/effect/mob_spawn/ghost_role/proc/post_transfer_prefs(mob/living/new_spawn) + return + + +/obj/effect/mob_spawn/ghost_role/human/special(mob/living/spawned_mob, mob/mob_possessor) + . = ..() + var/mob/living/carbon/human/spawned_human = spawned_mob + var/datum/job/spawned_job = SSjob.GetJobType(spawner_job_path) + + spawned_human.job = spawned_job.title + diff --git a/modular_doppler/modular_persistence/README.md b/modular_doppler/modular_persistence/README.md new file mode 100644 index 0000000000000..f0ff7028236a6 --- /dev/null +++ b/modular_doppler/modular_persistence/README.md @@ -0,0 +1,23 @@ +## Modular Persistence + +Module ID: MODULAR_PERSISTENCE + +### Description: + +An extremely easy to extend per-character persistence file. Supports all the basic types, plus lists. + +Simply add the vars you want to have saved to `/datum/modular_persistence`, and make sure those var values are updated before round end so that they're saved. + +Loaded and saved on only station-side players for now. Will be expanded to support more in the future. + +### TG Proc/File Changes: + +- `code\modules\mob\dead\new_player\new_player.dm`: `/mob/dead/new_player/proc/AttemptLateSpawn` +- `code\controllers\subsystem\persistence.dm`: `/datum/controller/subsystem/persistence/proc/collect_data` + +### Defines: + +- `modular_nova\modules\modular_persistence\code\modular_persistence.dm`: `GLOB.modular_persistence_ignored_vars` + +### Credits: +- RimiNosha - Code diff --git a/modular_doppler/modular_persistence/code/modular_persistence.dm b/modular_doppler/modular_persistence/code/modular_persistence.dm new file mode 100644 index 0000000000000..69f5efbe91009 --- /dev/null +++ b/modular_doppler/modular_persistence/code/modular_persistence.dm @@ -0,0 +1,138 @@ +/// A list of vars that shouldn't be tracked by persistence. +GLOBAL_LIST_INIT(modular_persistence_ignored_vars, list( + "datum_flags", + "_datum_components", + "_listen_lookup", + "tgui_shared_states", + "gc_destroyed", + "_active_timers", + "_status_traits", + "_signal_procs", + "cached_ref", + "weak_reference", + "cooldowns", + "__auxtools_weakref_id", + "tag", + "type", + "parent_type", + "owner_brain", + "vars", + "stored_character_slot_index", +)) + +/obj/item/organ/internal/brain + /// The modular persistence data for a character. + var/datum/modular_persistence/modular_persistence + +/// Saves the contents of the modular persistence datum for the player's client to their file. +/datum/controller/subsystem/persistence/proc/save_modular_persistence() + for(var/mob/living/carbon/human/player in GLOB.human_list) + player.save_individual_persistence() + +/// Loads the contents of the player's modular_persistence file to their character. +/datum/controller/subsystem/persistence/proc/load_modular_persistence(obj/item/organ/internal/brain/brain) + if(!brain) + return FALSE + + if(!ishuman(brain.owner)) + return FALSE + + var/mob/living/carbon/human/player = brain.owner + + var/json_file = file("data/player_saves/[player.ckey[1]]/[player.ckey]/modular_persistence.json") + var/list/json = fexists(json_file) ? json_decode(file2text(json_file)) : null + + brain.modular_persistence = new(brain, islist(json) ? json["[player.mind.original_character_slot_index]"] : null) + +/// The master persistence datum. Add vars onto this in your own code. Just be aware that you'll need to use simple data types, such as strings, ints, and lists. +/datum/modular_persistence + /// The human that this is attached to. + var/datum/weakref/owner_brain + /// The owner's character slot index. + var/stored_character_slot_index + +/datum/modular_persistence/New(obj/item/organ/internal/brain/brain, list/persistence_data) + owner_brain = WEAKREF(brain) + . = ..() + + var/obj/item/organ/internal/brain/our_brain = owner_brain?.resolve() + if(!our_brain) + owner_brain = null + return + + RegisterSignal(our_brain, COMSIG_QDELETING, PROC_REF(on_brain_deleted)) + stored_character_slot_index = our_brain.owner.mind?.original_character_slot_index + + if(!persistence_data) + return + + for(var/var_name in vars) + if(var_name in GLOB.modular_persistence_ignored_vars) + continue + + var/var_entry = persistence_data[var_name] + + if(var_entry) + vars[var_name] = var_entry + + if(!our_brain.owner) + CRASH("Tried to load modular persistence on a brain with no owner! How did this happen?! (\ref[brain], [brain.brainmob?.ckey], [brain])") + +/datum/modular_persistence/Destroy(force) + owner_brain = null + return ..() + +/datum/modular_persistence/proc/on_brain_deleted(datum/source) + SIGNAL_HANDLER + + qdel(src) + +// On a base datum, this should be empty, at a glance. +/datum/modular_persistence/proc/serialize_contents_to_list() + var/list/returned_list = list() + + var/obj/item/organ/internal/brain/our_brain = owner_brain?.resolve() + if(!our_brain) + owner_brain = null + return + + for(var/var_name in vars) + if(var_name in GLOB.modular_persistence_ignored_vars) + continue + + var/var_entry = vars[var_name] + + if(!isnull(var_entry)) + returned_list[var_name] = var_entry + + return returned_list + +/// Saves the held persistence data to where it needs to go. +/datum/modular_persistence/proc/save_data(var/ckey) + var/obj/item/organ/internal/brain/our_brain = owner_brain?.resolve() + if(!our_brain) + owner_brain = null + return + + ckey = replacetext(ckey || our_brain.owner?.ckey || our_brain.brainmob?.ckey, "@", "") + if(!our_brain.owner && !our_brain.brainmob) + CRASH("Modular persistence save called on a brain with no owning mob or brainmob! How did this happen?! (\ref[our_brain], [our_brain])") + if(!ckey) + CRASH("Modular persistence save called on a brain with no ckey! How did this happen?! (\ref[our_brain], [our_brain])") + + var/json_file = file("data/player_saves/[ckey[1]]/[ckey]/modular_persistence.json") + var/list/json = fexists(json_file) ? json_decode(file2text(json_file)) : list() + fdel(json_file) + + if(!islist(json)) + json = list() + + json["[stored_character_slot_index]"] = serialize_contents_to_list() + WRITE_FILE(json_file, json_encode(json)) + return TRUE + +/// Saves the persistence data for the owner. +/mob/living/carbon/human/proc/save_individual_persistence(var/ckey) + var/obj/item/organ/internal/brain/brain = get_organ_slot(ORGAN_SLOT_BRAIN) + + return brain?.modular_persistence?.save_data(ckey) diff --git a/modular_doppler/modular_sounds/code/sounds.dm b/modular_doppler/modular_sounds/code/sounds.dm new file mode 100644 index 0000000000000..928086d6280b6 --- /dev/null +++ b/modular_doppler/modular_sounds/code/sounds.dm @@ -0,0 +1,16 @@ +/proc/get_sfx_doppler(soundin) + if(istext(soundin)) + switch(soundin) + if(SFX_BRICK_DROP) + soundin = pick( + 'modular_doppler/modular_sounds/sound/bricks/brick_drop_1.ogg', + 'modular_doppler/modular_sounds/sound/bricks/brick_drop_2.ogg', + 'modular_doppler/modular_sounds/sound/bricks/brick_drop_3.ogg', + ) + if(SFX_BRICK_PICKUP) + soundin = pick( + 'modular_doppler/modular_sounds/sound/bricks/brick_pick_up_1.ogg', + 'modular_doppler/modular_sounds/sound/bricks/brick_pick_up_2.ogg', + ) + + return soundin diff --git a/modular_doppler/modular_sounds/sound/bricks/attributions.txt b/modular_doppler/modular_sounds/sound/bricks/attributions.txt new file mode 100644 index 0000000000000..73ec0f37d5ff3 --- /dev/null +++ b/modular_doppler/modular_sounds/sound/bricks/attributions.txt @@ -0,0 +1 @@ +All sounds taken from 'Brick pick up and put down close mic' by vintage2005 via Pixabay - https://pixabay.com/sound-effects/brick-pick-up-and-put-down-close-mic-28684/ diff --git a/modular_doppler/modular_sounds/sound/bricks/brick_drop_1.ogg b/modular_doppler/modular_sounds/sound/bricks/brick_drop_1.ogg new file mode 100644 index 0000000000000000000000000000000000000000..94bdeed6333b5ba94e4d0e26c568f999ca2530f9 GIT binary patch literal 7163 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 T{iZ`Vf7x-g6H9lSy$AgV{)$@Z literal 0 HcmV?d00001 diff --git a/modular_doppler/modular_sounds/sound/bricks/brick_drop_3.ogg b/modular_doppler/modular_sounds/sound/bricks/brick_drop_3.ogg new file mode 100644 index 0000000000000000000000000000000000000000..1b057e707a6f7f27c8df66f6447299d649d2abc9 GIT binary patch literal 7994 zcmeHscT|&0xA%k^If#J3Nf4AkC{aKH0Rhn$Lk~q0L8-?BA#@N3VE4o$QX(LR03i?r z0zsMzhzg2gqew5(6uT4wQL!8gdMCki?|Z-X-Mij(*ZuR(n#?oL?3VfM{p{IKvOPF> zClCWao0IJFWU+B+2C){Aus1d!lrCHnYw=sAgh?PolM2Lkq2#|ep`?%^6I`@*mFa9Mnq`9E|GQ(CkVHcGU8oM_t zk`@(*6WTyXF6+P$ZFV7mH2^50{Cde6YKCRIGA0dOQbfFmYf~roVfa{^6w6lAHWbyN zF_1~@IM$cx0fYjjYP)yDIvGqA(D|s{T`|)daQ0FoxGQFbHk@TxOtE4!@XJ)WSe%gW zn34lCrW^%lrD||?Ryd2qUuMPjSisq&MlvP#oT-qC3YLrgMX04!sBc!NInDI)&@!Kh zSu~^x)r)3P_$d|oIiVJKtG2wRK?qa^nE(_O>oK3{$;qqM$$)kMY<#DEi8%5Y-fH)QLSd6=lbt;7({$2X_#JqLC<1ggkJ-m9i<0H~}Ys ziEC4%cj4PKj>{TP7iGCwc9gQ*Ebn3Y8I*8bgVIiy+LtQSnug&5`uS}*Y8t*3^&f+l z2nM)ec`0;YCj5elN+PAPP@mfJwjfdXFsRv4unw_U2Nt%2rSFtw)mbm>u0yu2${zPU zB1b+(?)ez`_&)9NN7{q?G`}3$L_?(Cu%F*Z{D1DEturJ5BjW``9d^fzQb!q)b21S? z9x(Xk%;%2K9~s(SES=Dt-~&132e@Zb*NRx6V<2jmLP10Q7mdsi@^0ga8+8)Q$H8~hnGyNm2Yen`fL?`%0ol8WJ%lmf7^mq zwksq0-Tzl?5mrG%(A+=Sx-Vfxh7Y``L0ixeS^0m%)=!oHclkdA{woAvh)bBmk0oDy~sln{)q9+awN`Mjo zWRprlL8q9fiuEAiO1-gS=!&_l7M^{2(eNm{ux)2R3`3M$$WYeqG`91dRfzB#!PI1{ zP&jp<1PRZw!9=}-g`q^HExiPPZb=B&TFDibE!M}xfi+_#SMj8{l4_kIK&}8rdQ94Z zLOo_lXl3OranNeJl3hQ+<9>W`XrV3>3Rb>qdSkVnUSOrJtN$QcxHs>vJ1Ag|^NJ8T;qD>4S;*l1St^0 zG%^WaCQDT$;fnoTNKR$$6bh+=O(K$T*%T)yTp7ifgex1SXlrM)D3zsbcM3@oFx1WA zN91P-@D3tN%nX3FN-3L!pDdtLNM$Hkq2RQsX|P~nv+%72bT?852d?Rs1$M!;EQ%$p zWaOdZxE>2+8Jj|!R!gLia6Gyk5!Pywa&1bR=>rfKtKQXiWFbK%SI$91YkmP>JB*n17yRQBvr1}PL@|Sgv5i6E%H$~| zOeve_h&z!94_bsYV1U*4tcx)l5Da%1yg%y?Q4#Vl4She$x}T+3mirJ+ahtrjO6hP}ffu!>=@vhg-K!DjVA54EC9q%dVF!up1TpE`S2 zROt+pQVm2k&!t_YzpJ0ofRjJ#AQAIFRYXGB|KHl*EX%6?y@rwm94m8Rtvzafn>66{ zG$dLC(?bASP%uckERY!Jd|X9CkA*Zw7y-EK9EuAXMhdc6NWe9)EvJN`0RxduajuD% zBMJ$kTW=Ymgp)QTz)dO~U1x1JizFma!VDUQNw^9~ z5b;GAoS;zF{G}XkxP=^V=bF320pT?bL*C8? zWkW)gM*|`Z1VZ%L=d+jkT8MIE(-^GxGv8%Bz&h!?x9K{|epbK}9 z)XtKn$X04);dODrDTE}Y(n8!j4n;Nq>2$&kpIoD}&Usp6xF}7*unYwwa~ohVV91I~ zNSeS03i!XUF4AJO6t4tE@)(n2+b{(4b_s@b3bF!d;J1;R`Xn*7nTCJrue}oetabIK zg1+LF%TLLyt&(4^GsGCH00S$5Oi2kkck7v$mJRhd z|Mqintnkf5l-nib84QMKCcI}bmR}1Qn?*}N_*w|l5->`rKB;3HPX8k+f#wuSJr)}t z5`NewFziTNSU5d8HX(BF{`hcuOn4%F?|YpgqvjQ+UFS5EUER86wRUdCr#&~)t_ifw zt2*7&6TjP80X zochjysHlX92z~riHP&*fx>mo_Xr#Nl0o`d_vatAB=lkMOw~tHL9#0q0&8TUod*c1_ zX;f-zW7N5NbSG-2V740j`Q_5P&|8Jg=*aLink6oXBUk2?Bh)wNP0}k(U9c>G_c%<5w;XP{=#<#|O8$GF9zpfrR)DWO| zYd@2E)A@FFm3rr5y`!(G=^WEP=xEHzUp{gy#WnzNszU367W>NduQ*E zml>5|%E`rLX2j>saOMMs3DV9S=lD3CTfRY>Ib+z^% z05fr`XHGgkhX#G*#DZrNEe*>;j9ZMvPdqHxdgROdima?Gs#8+xCes(qmuq@@F8Ozi zqB`sJsnoQzGzE*^xs2fXTMv2R*_U{;1+!m2XK$G`@{7WM|1sD9R-lEj)s7fFRHA4$ zw`H9dArPyf<*_~0Ga$wICeo=^tD}osN;Rn;o-jGI&)&hLO-+54gNuVNk=%@#!ShC? zA(oSMhWY$K#hZbaanr$Ltl-DI)tqnC;0b~k$9klGq65iac;SM;ZqOVs@=`dRv<~fR zmn6}TZPa7R8Ok*UIq@(uqu5J^1+I!~IC!Ghtv)6-36s&n+6^GUU{Tl^kdWy6QW)l@s^v-zi( z$-4_ja!xD!_;dh4DF0SFA{xGlgHaR1J0;>EOgVkF;()#H6rT>k*bVFBYQg&4@YieS6x(`(zvbJ*ks@S4;Yh+AZGFGvHYXGEc}vS zuQNEv8TVOX4U#LGvw=kP697)0cue!P*qy+T1KI972m7w*zbZ2hcx7~?z`D|=%@8dh zQ}ga;EFNC8REUeCVr?GmfAsKc%Cx5U#i8*ML_bE*@aenHKW0WEfXAPE-|HXqOg2YH z)$K+iHJcCC>te_4)1CZ27<#Gft%y0eT z*3*5}IDNdet-=XN?Njm#ux;Md!S2IHK(E<4P9`<$|IOV9a3%sK4i{`@H~X4}yH5A%im zHCi8bMJe)+UmE8SBzGmA{A0X@{3X@h-ZM?{+k4JG z^y#m*Td%gIKJZz@-4)>kUCxC%KC- z66E2bsjaeIFVn@|i6~pras5oY&uo(6^U~dAOf0pcgqJ^wd;b36Ji6ET(^ZVp#vhi- z^doN%?-`pZpL@411BfLBFZA13HaM=e@bOmUX-BIh>N2neBzz4oVk2^n*8eA_4EgE zxfVgC;-;2k#@waC!jO*xzP#6;UM{WwHS&wsjE>K_cPACX4bBwAb>g4<5es5d23JM- z*Ep&>Xm0b0l6-Hp>Cd&3_HVjC`i47Rlq}YZDxc znVWm%1Y1ngRki3t1U`S_OYi6>`uFJ-Kw<;m_~yN{U2Y~%FPNx?#iERlykdt26*TGd z)MqB=PQPdYqSuNnD1$iAiKDr@vzI^-NMq!i0PgZN=Tis-(rM z6^#LY6=$XG>|-|tZ8%>MGWdSK#fhxx4)aC4#Y9E!gz3S1fhCWnuitBu?wgkTJv)9? zQNKDv`1)E{??Ky?EvCswP$Hc_=zIv`?)7EcHGEMU+?Vwj^*J|IDWRtH~{;7Yv6-*4YTQu@h*=tocXz-AzOU~=Ta#OB``fC)A8H0h*KGIjXqX~H%IJI z>wo;k!Ofn0?oh~4#Rih2NBOU-_J!>;`9_MbYnw8BdYw=9(Ap^YAW^Klglr8facDkD zJ>XR!_UP<5G!o)I51-y^V;!k0ry^eZdYnil`qrY{OfmOoP<|V-1<~K?+Wvv7{9Nht z`s#hP&w)dst7nW-+WQ<|6@Kg+jw4(Pj61k7_IbS034;5#aPO^?g1uogl@lSoZE+4aSAos{;?@z-!3b(Y4)rMA(b~p_aB(w}}umgMrK|?#9 zBXR7^ET_d9<7e{DTQ-dqK2&f<*?TD*Ju5`h++B#KBcoV99L-kL$-=w2qqSS*#Ssd& z7xD^g?tWd!+P<|Zb~jI*J73tnzxSv*ZvTpWpTUE9BTsloS7O5ZP8n?cVfKyR=9FL0 zbvme$wZwbtqMdFOdo|be4$6idG91(9+NEhR^6UEF&T_YjfgPeT+WJ9ObWdz+RV7>g z?uuG@3NehNgj_60J{tM{EBmRA?#CO~3$AEAysx%#O^8|6Ky>3&bBGgl@7Khu#x*hC z><5R+KYiaBc=(S3^hKEs-5>9~8^Er(TE+WK@^$Zv;!@L1Zv&1c<12FSi+yhs;`*&t zh^zEPgi24WX%#6|_c^9iuwJ`Z{`i}tAK$MGskZKkMsyO)rErGu+*z`qka0Jl>Du;+MlucD#F3T-~15 zZPB#b`)GxI0j{VK7v6CLYp(=-(mT(~R9+d%7%CzV&-EctNHh4k^9*RI7-nm-dk&oogIlVhBzqS3N{?E6S z9xD8=F1NaKuO7LIj5A%tiHEnmTE8jv`KGU&am24{%o4XrNNnt4JUM}W(sih&%khkg@g57)`mu;|4tvo1adYpaqH}{u{R*_rls&b(DNu7T zDP%J~BQmhoi~fpp{JNHIZBigN$3G!KX)1$r>ga3EU*(3#swg+$Qfo!Y$K^PL)qkCc zHcjA|#eM1Oi3_;b7ZW@1d(cId@PX4|n_M{XRYg`+#ATUvSbT^s~;dLFhjs&tOaH(stomr!7sqKa7kPcpGmhb{*duG1WRdkp+Bl zmU3#M;T!ysVK|9y8!T2d;1WqUt+d0`b7^^{mYah|LL(PT-qzIEmBB4?PR2Mk;AV{52(~Vd z?QGo_Zb+#f{9?ZgD9A5gG!SdSljsMqAd(^4t7vRU&o`@yyq>2r=15kd1*r4TlvIEA ziUF7K0gT{f(69KROp8Hn<{PiyCx5*@!FQ`%bKO>o95Je9@#{; zELq>K*3*%zrz)@*u1@0`9Qt%vO}+lCgqI*C$M+wFs$Y4L#3h+gCu_kGNB&{I7xWJO zeDjUxf2ikL4__N@FU?3Y?~O7{i#XKTcX(4(Xi&}M{>~u$ly4d0C~BMz`ZVH~FCXmf zSM_*!q*8WhnreHvxhBe=I&meBT$^F(;3SJ+JN#$#ky&wApUF3SHqk@dZ=kqa9qFC~)=S$L+LRK<0DAMZY^ppsiq@ zgH8Cm1I+Ir$YxD3!sGkp&oX;uZRNh3?RlDhto`Pi2jb@`u98I1en*k4pNLdiHEB$< z9}IaX@%(z#-o-oZE0fPZfA{+G*GRsr!(NBI(qHBu8Pt{rY;kED*!yXL>9|c@3j7
Xenoarchaeology Guide

\ + Let's start right from the beginning: what is Xenoarchaeology?
\ + Great question! Xenoarchaeology is the study of ancient foreign bodies that are trapped within strange rocks.
\ + Your goal as a xenoarchaeologist is to find these strange rocks and unearth the secrets that are held within.
\ + You will find that these rocks are plentiful throughout the astronomical bodies that we typically orbit.
\ +
\ + Tools of the Trade
\ +
\ + There are plenty of tools that are required (and some just for the quality of life for the xenoarchaeologist).
\ + There are the hammers, the brushes, the tape, the belt, the bag, the handheld machines, and the machines.
\ + In this line of work, the brushes and hammers will be the bread and butter.
\ + They will allow you to unearth the foreign bodies held within the strange rocks.
\ + The hammers (with varying depths) allow you to reach the depths in a faster manner than the brushes.
\ + The brushes allow you to uncover the items within the proper depths without damaging it.
\ + The tape will allow you to tag the strange rock with the current depth. Continue to examine the rock for updates.
\ + The belt will allow you to store your mobile/handheld tools for easy access.
\ + The bag will allow you to store and automatically pickup strange rocks that you find lying on the floor.
\ + The handheld machines allow you to not have to be stuck at the machines. There are only handheld scanners and recoverers.
\ + The Scanner is a machine which allows you to tag the strange rock with its max and safe depth.
\ + The Researcher is a machine that allows you to compile/condense relics and items into larger strange artifacts.
\ + The Recoverer is a machine that allows you to recover long lost objects from broken items.
\ +
\ + The Process
\ +
\ + 1) Find yourself a strange rock out in the wilderness.
\ + 2) Go back (or stay) to the xenoarchaeology labratory.
\ + 3) Process the rock in the scanner (or use the handheld scanner).
\ + 4) Use the measuring tape on the rock.
\ + 5) Subtract the safe depth (SD) from the max depth (MD).
\ + 5a) QUESTION: What is the depth you dig to when the MD is 50 and the SD is 16?
\ + ANSWER: 34. Just make sure to not dig 34 as there will be previous depth involved.
\ + 6) Subtract the current depth (CD) from the answer to step 5.
\ + 7) Use the hammers to dig the answer to step 6.
\ + 8) Once you've reached the answer to step 5, use the brush until you reveal the item.
\ + 9) Enjoy the use of your unearthed secret!
\ + 9a) If it is a useless relic, sell it or use it in the Researcher for a surprise.
\ + 9b) If it is a broken item, sell it or use it in the Recoverer for a surprise.
\ +
\ + I hope this has been helpful and I wish you great success!
\ +
\ + - KB
\ + Director of Xenoarchaeological Studies"} diff --git a/modular_doppler/xenoarch/code/modules/research/xenoarch/xenoarch_machine.dm b/modular_doppler/xenoarch/code/modules/research/xenoarch/xenoarch_machine.dm new file mode 100644 index 0000000000000..e15a3468845f0 --- /dev/null +++ b/modular_doppler/xenoarch/code/modules/research/xenoarch/xenoarch_machine.dm @@ -0,0 +1,313 @@ +// Researcher, Scanner, Recoverer, and Digger + +/obj/machinery/xenoarch + icon = 'modular_doppler/xenoarch/icons/xenoarch_machines.dmi' + density = TRUE + layer = BELOW_OBJ_LAYER + use_power = IDLE_POWER_USE + idle_power_usage = 100 + pass_flags = PASSTABLE + /// the item that holds everything + var/obj/item/storage_unit + ///how long between each process + var/process_speed = 10 SECONDS + COOLDOWN_DECLARE(process_delay) + +/obj/machinery/xenoarch/Initialize(mapload) + . = ..() + storage_unit = new /obj/item(src) + +/obj/machinery/xenoarch/Destroy() + QDEL_NULL(storage_unit) + return ..() + +/obj/machinery/xenoarch/RefreshParts() + . = ..() + var/efficiency = -2 //to allow t1 parts to not change the base speed + for(var/datum/stock_part/stockpart in component_parts) + efficiency += stockpart.tier + + process_speed = initial(process_speed) - (efficiency) + +/obj/machinery/xenoarch/process() + if(machine_stat & (NOPOWER|BROKEN) || !anchored) + COOLDOWN_RESET(src, process_delay) //if you are broken or no power (or not anchored), you aren't allowed to progress! + return + + if(!COOLDOWN_FINISHED(src, process_delay)) + return + + COOLDOWN_START(src, process_delay, process_speed) + xenoarch_process() + +/obj/machinery/xenoarch/proc/xenoarch_process() + return + +/obj/machinery/xenoarch/wrench_act(mob/living/user, obj/item/tool) + . = ..() + + if(default_unfasten_wrench(user, tool)) + return ITEM_INTERACT_SUCCESS + +/obj/machinery/xenoarch/screwdriver_act(mob/living/user, obj/item/tool) + . = ..() + + toggle_panel_open() + to_chat(user, span_notice("You [panel_open ? "open":"close"] the maintenance panel of [src].")) + tool.play_tool_sound(src) + return ITEM_INTERACT_SUCCESS + +/obj/machinery/xenoarch/crowbar_act(mob/living/user, obj/item/tool) + . = ..() + + if(default_deconstruction_crowbar(tool)) + return ITEM_INTERACT_SUCCESS + +/obj/machinery/xenoarch/researcher + name = "xenoarch researcher" + desc = "A machine that is used to condense strange rocks, useless relics, and broken objects into bigger artifacts." + icon_state = "researcher" + circuit = /obj/item/circuitboard/machine/xenoarch_machine/xenoarch_researcher + /// the amount of research that is currently done + var/current_research = 0 + /// the max amount of value we can have + var/max_research = 300 + /// the value of each accepted item + var/list/accepted_types = list( + /obj/item/xenoarch/strange_rock = 1, + /obj/item/xenoarch/useless_relic = 5, + /obj/item/xenoarch/useless_relic/magnified = 10, + /obj/item/xenoarch/broken_item = 10, + ) + +/obj/machinery/xenoarch/researcher/examine(mob/user) + . = ..() + + . += span_notice("
[current_research]/[max_research] research available.") + . += span_notice("L-Click to insert items or take out all the strange rocks. R-Click to use research points.") + +/obj/machinery/xenoarch/researcher/attackby(obj/item/weapon, mob/user, params) + if(istype(weapon, /obj/item/storage/bag/xenoarch)) + for(var/obj/strange_rocks in weapon.contents) + strange_rocks.forceMove(storage_unit) + + balloon_alert(user, "rocks inserted!") + return + + if(is_type_in_list(weapon, accepted_types)) + weapon.forceMove(storage_unit) + balloon_alert(user, "item inserted!") + return + + return ..() + +/obj/machinery/xenoarch/researcher/attack_hand(mob/living/user, list/modifiers) + . = ..() + var/choice = tgui_input_list(user, "Remove the rocks from [src]?", "Rock Removal", list("Yes", "No")) + if(choice != "Yes") + return + var/turf/src_turf = get_turf(src) + for(var/obj/item/removed_item in storage_unit.contents) + removed_item.forceMove(src_turf) + + balloon_alert(user, "items removed!") + +/obj/machinery/xenoarch/researcher/attack_hand_secondary(mob/user, list/modifiers) + . = ..() + var/turf/src_turf = get_turf(src) + var/choice = tgui_input_list(user, "Choose which reward you would like!", "Reward Choice", list("Lavaland Chest (150)", "Anomalous Crystal (150)", "Bepis Tech (100)")) + if(!choice) + return SECONDARY_ATTACK_CANCEL_ATTACK_CHAIN + + switch(choice) + if("Lavaland Chest (150)") + if(current_research < 150) + balloon_alert(user, "insufficient research!") + return SECONDARY_ATTACK_CANCEL_ATTACK_CHAIN + + current_research -= 150 + new /obj/structure/closet/crate/necropolis/tendril(src_turf) + + if("Anomalous Crystal (150)") + if(current_research < 150) + balloon_alert(user, "insufficient research!") + return SECONDARY_ATTACK_CANCEL_ATTACK_CHAIN + + current_research -= 150 + var/list/choices = subtypesof(/obj/machinery/anomalous_crystal) - /obj/machinery/anomalous_crystal/theme_warp + var/random_crystal = pick(choices) + new random_crystal(src_turf) + + if("Bepis Tech (100)") + if(current_research < 100) + balloon_alert(user, "insufficient research!") + return SECONDARY_ATTACK_CANCEL_ATTACK_CHAIN + + current_research -= 100 + new /obj/item/disk/design_disk/bepis/remove_tech(src_turf) + + return SECONDARY_ATTACK_CANCEL_ATTACK_CHAIN + +/obj/machinery/xenoarch/researcher/xenoarch_process() + if(length(storage_unit.contents) <= 0) + return + + if(current_research >= max_research) + return + + var/obj/item/first_item = storage_unit.contents[1] + var/reward_attempt = accepted_types[first_item.type] + current_research = min(current_research + reward_attempt, 300) + qdel(first_item) + +/obj/machinery/xenoarch/scanner + name = "xenoarch scanner" + desc = "A machine that is used to scan strange rocks, making it easier to extract the item inside." + icon_state = "scanner" + circuit = /obj/item/circuitboard/machine/xenoarch_machine/xenoarch_scanner + +/obj/machinery/xenoarch/scanner/attackby(obj/item/weapon, mob/user, params) + if(istype(weapon, /obj/item/storage/bag/xenoarch)) + for(var/obj/item/xenoarch/strange_rock/chosen_rocks in weapon.contents) + chosen_rocks.get_scanned() + + balloon_alert(user, "scan complete!") + return + + if(istype(weapon, /obj/item/xenoarch/strange_rock)) + var/obj/item/xenoarch/strange_rock/chosen_rock + if(chosen_rock.get_scanned()) + balloon_alert(user, "scan complete!") + return + + to_chat(user, span_warning("[chosen_rock] was unable to be scanned, perhaps it was already scanned?")) + return + + return ..() + +/obj/machinery/xenoarch/recoverer + name = "xenoarch recoverer" + desc = "A machine that will recover the damaged, destroyed objects found within the strange rocks." + icon_state = "recoverer" + circuit = /obj/item/circuitboard/machine/xenoarch_machine/xenoarch_recoverer + +/obj/machinery/xenoarch/recoverer/examine(mob/user) + . = ..() + . += span_notice("
L-Click to remove all items inside [src].") + +/obj/machinery/xenoarch/recoverer/attackby(obj/item/weapon, mob/user, params) + if(istype(weapon, /obj/item/xenoarch/broken_item)) + weapon.forceMove(storage_unit) + balloon_alert(user, "item inserted!") + return + + return ..() + +/obj/machinery/xenoarch/recoverer/attack_hand(mob/living/user, list/modifiers) + var/choice = tgui_input_list(user, "Remove the broken items from [src]?", "Item Removal", list("Yes", "No")) + if(choice != "Yes") + return + + var/turf/src_turf = get_turf(src) + for(var/obj/item/removed_item in storage_unit.contents) + removed_item.forceMove(src_turf) + + balloon_alert(user, "items removed!") + +/obj/machinery/xenoarch/recoverer/xenoarch_process() + var/turf/src_turf = get_turf(src) + if(length(storage_unit.contents) <= 0) + return + + var/obj/item/content_obj = storage_unit.contents[1] + if(!istype(content_obj, /obj/item/xenoarch/broken_item)) + qdel(content_obj) + return + + if(istype(content_obj, /obj/item/xenoarch/broken_item/tech)) + var/spawn_item = pick_weight(GLOB.tech_reward) + recover_item(spawn_item, content_obj) + return + + if(istype(content_obj, /obj/item/xenoarch/broken_item/weapon)) + var/spawn_item = pick_weight(GLOB.weapon_reward) + recover_item(spawn_item, content_obj) + return + + if(istype(content_obj, /obj/item/xenoarch/broken_item/illegal)) + var/spawn_item = pick_weight(GLOB.illegal_reward) + recover_item(spawn_item, content_obj) + return + + if(istype(content_obj, /obj/item/xenoarch/broken_item/alien)) + var/spawn_item = pick_weight(GLOB.alien_reward) + recover_item(spawn_item, content_obj) + return + + if(istype(content_obj, /obj/item/xenoarch/broken_item/plant)) + var/spawn_item = pick_weight(GLOB.plant_reward) + recover_item(spawn_item, content_obj) + return + + if(istype(content_obj, /obj/item/xenoarch/broken_item/clothing)) + var/spawn_item = pick_weight(GLOB.clothing_reward) + recover_item(spawn_item, content_obj) + return + + if(istype(content_obj, /obj/item/xenoarch/broken_item/animal)) + var/spawn_item + for(var/looptime in 1 to rand(1,4)) + spawn_item = pick_weight(GLOB.animal_reward) + new spawn_item(src_turf) + + recover_item(spawn_item, content_obj) + return + +/obj/machinery/xenoarch/recoverer/proc/recover_item(obj/insert_obj, obj/delete_obj) + var/src_turf = get_turf(src) + new insert_obj(src_turf) + playsound(src, 'sound/machines/click.ogg', 50, TRUE) + qdel(delete_obj) + +/obj/machinery/xenoarch/digger + name = "xenoarch digger" + desc = "A machine that is used to slowly uncover items within strange rocks." + icon_state = "digger" + circuit = /obj/item/circuitboard/machine/xenoarch_machine/xenoarch_digger + +/obj/machinery/xenoarch/digger/examine(mob/user) + . = ..() + . += span_notice("
L-Click to remove all items inside [src].") + +/obj/machinery/xenoarch/digger/attackby(obj/item/weapon, mob/user, params) + if(istype(weapon, /obj/item/storage/bag/xenoarch)) + for(var/obj/strange_rocks in weapon.contents) + strange_rocks.forceMove(storage_unit) + + balloon_alert(user, "rocks inserted!") + return + + if(istype(weapon, /obj/item/xenoarch/strange_rock)) + weapon.forceMove(src) + balloon_alert(user, "rock inserted!") + return + +/obj/machinery/xenoarch/digger/attack_hand(mob/living/user, list/modifiers) + var/choice = tgui_input_list(user, "Remove the rocks from [src]?", "Rock Removal", list("Yes", "No")) + if(choice != "Yes") + return + + var/turf/src_turf = get_turf(src) + for(var/obj/item/removed_item in storage_unit.contents) + removed_item.forceMove(src_turf) + + balloon_alert(user, "items removed!") + +/obj/machinery/xenoarch/digger/xenoarch_process() + var/turf/src_turf = get_turf(src) + if(length(storage_unit.contents) <= 0) + return + + var/obj/item/xenoarch/strange_rock/first_item = storage_unit.contents[1] + new first_item.hidden_item(src_turf) + qdel(first_item) diff --git a/modular_doppler/xenoarch/code/modules/research/xenoarch/xenoarch_reward.dm b/modular_doppler/xenoarch/code/modules/research/xenoarch/xenoarch_reward.dm new file mode 100644 index 0000000000000..afed67fefe23b --- /dev/null +++ b/modular_doppler/xenoarch/code/modules/research/xenoarch/xenoarch_reward.dm @@ -0,0 +1,97 @@ +GLOBAL_LIST_INIT(tier1_reward, list( + /obj/item/xenoarch/useless_relic = 5, + /obj/item/stack/sheet/sinew = 1, + /obj/item/stack/sheet/animalhide/goliath_hide = 1, + /obj/item/stack/sheet/bone = 1, + /obj/item/organ/internal/monster_core/regenerative_core/legion = 1, +)) + +GLOBAL_LIST_INIT(tier2_reward, list( + /obj/item/xenoarch/broken_item/tech = 1, + /obj/item/xenoarch/broken_item/plant = 1, + /obj/item/xenoarch/broken_item/clothing = 1, + /obj/item/xenoarch/broken_item/animal = 1, + /obj/item/xenoarch/useless_relic = 5, +)) + +GLOBAL_LIST_INIT(tier3_reward, list( + /obj/item/xenoarch/broken_item/weapon = 3, + /obj/item/xenoarch/broken_item/illegal = 1, + /obj/item/xenoarch/broken_item/alien = 1, + /obj/item/stack/spacecash/c10000 = 1, +)) + + + +GLOBAL_LIST_INIT(tech_reward, list( + /obj/item/pipe_dispenser = 1, + /obj/item/construction/rcd = 1, + /obj/item/anomaly_neutralizer = 1, + /obj/item/megaphone = 1, + /obj/item/bodybag/bluespace = 1, + /obj/item/relic = 1, + /obj/item/raw_anomaly_core/random = 1, + /obj/item/bag_of_holding_inert = 1, + /obj/item/construction/plumbing = 1, + /obj/item/mmi/posibrain = 1, + /obj/item/storage/portable_chem_mixer = 1, +)) + +GLOBAL_LIST_INIT(weapon_reward, list( + /obj/item/spear/bonespear = 6, + /obj/item/gun/ballistic/bow/tribalbow/ashen = 2, + /obj/item/ammo_casing/arrow/ash = 1, + /obj/item/claymore/cutlass = 1, + /obj/item/gun/ballistic/automatic/pistol = 1, + /obj/item/shield/riot = 1, + /obj/item/shield/roman = 1, + /obj/item/pneumatic_cannon = 1, + /obj/item/gun/syringe/rapidsyringe = 1, +)) + +GLOBAL_LIST_INIT(clothing_reward, list( + /obj/item/clothing/neck/necklace/translator = 1, + /obj/item/clothing/head/helmet/gladiator = 1, + /obj/item/clothing/under/costume/gladiator/ash_walker = 1, +)) + +GLOBAL_LIST_INIT(illegal_reward, list( + /obj/item/stack/telecrystal = 1, + /obj/item/storage/box/rndboards = 1, +)) + +GLOBAL_LIST_INIT(plant_reward, list( + /obj/item/food/grown/gelthi = 1, + /obj/item/seeds/random = 1, + /obj/item/food/grown/amauri = 1, + /obj/item/food/grown/jurlmah = 1, + /obj/item/food/grown/nofruit = 1, + /obj/item/food/grown/shand = 1, + /obj/item/food/grown/surik = 1, + /obj/item/food/grown/telriis = 1, + /obj/item/food/grown/thaadra = 1, + /obj/item/food/grown/vale = 1, + /obj/item/food/grown/vaporsac = 1, +)) + +GLOBAL_LIST_INIT(animal_reward, list( + /obj/item/stack/sheet/sinew = 1, + /obj/item/stack/sheet/animalhide/goliath_hide = 1, + /obj/item/stack/sheet/bone = 1, + /obj/item/organ/internal/monster_core/regenerative_core/legion = 1, +)) + +GLOBAL_LIST_INIT(alien_reward, list( + /obj/item/wrench/abductor = 1, + /obj/item/wirecutters/abductor = 1, + /obj/item/weldingtool/abductor = 1, + /obj/item/screwdriver/abductor = 1, + /obj/item/crowbar/abductor = 1, + /obj/item/multitool/abductor = 1, + /obj/item/scalpel/alien = 1, + /obj/item/hemostat/alien = 1, + /obj/item/retractor/alien = 1, + /obj/item/circular_saw/alien = 1, + /obj/item/surgicaldrill/alien = 1, + /obj/item/cautery/alien = 1, +)) diff --git a/modular_doppler/xenoarch/code/modules/research/xenoarch/xenoarch_tool.dm b/modular_doppler/xenoarch/code/modules/research/xenoarch/xenoarch_tool.dm new file mode 100644 index 0000000000000..3bc98a517bae2 --- /dev/null +++ b/modular_doppler/xenoarch/code/modules/research/xenoarch/xenoarch_tool.dm @@ -0,0 +1,306 @@ +/obj/item/xenoarch + name = "parent dev item" + icon = 'modular_doppler/xenoarch/icons/xenoarch_items.dmi' + +// HAMMERS + +/obj/item/xenoarch/hammer + name = "parent dev item" + desc = "A hammer that can be used to remove dirt from strange rocks." + tool_behaviour = TOOL_HAMMER + var/dig_amount = 1 + var/dig_speed = 1 SECONDS + var/advanced = FALSE + +/obj/item/xenoarch/hammer/examine(mob/user) + . = ..() + if(advanced) + . += span_notice("This is an advanced hammer. It can change its digging depth from 1 to 30. Click to change depth.") + . += span_notice("Current Digging Depth: [dig_amount]cm") + +/obj/item/xenoarch/hammer/attack_self(mob/user, modifiers) + . = ..() + if(!advanced) + to_chat(user, span_warning("This is not an advanced hammer, it cannot change its digging depth.")) + return + var/user_choice = input(user, "Choose the digging depth. 1 to 30", "Digging Depth Selection") as null|num + if(!user_choice) + dig_amount = 1 + dig_speed = 1 + return + if(dig_amount <= 0) + dig_amount = 1 + dig_speed = 1 + return + var/round_dig = round(user_choice) + if(round_dig >= 30) + dig_amount = 30 + dig_speed = 30 + return + dig_amount = round_dig + dig_speed = round_dig * 0.5 + to_chat(user, span_notice("You change the hammer's digging depth to [round_dig]cm.")) + +/obj/item/xenoarch/hammer/cm1 + name = "hammer (1cm)" + icon_state = "hammer1" + dig_amount = 1 + dig_speed = 0.5 SECONDS + +/obj/item/xenoarch/hammer/cm2 + name = "hammer (2cm)" + icon_state = "hammer2" + dig_amount = 2 + dig_speed = 1 SECONDS + +/obj/item/xenoarch/hammer/cm3 + name = "hammer (3cm)" + icon_state = "hammer3" + dig_amount = 3 + dig_speed = 1.5 SECONDS + +/obj/item/xenoarch/hammer/cm4 + name = "hammer (4cm)" + icon_state = "hammer4" + dig_amount = 4 + dig_speed = 2 SECONDS + +/obj/item/xenoarch/hammer/cm5 + name = "hammer (5cm)" + icon_state = "hammer5" + dig_amount = 5 + dig_speed = 2.5 SECONDS + +/obj/item/xenoarch/hammer/cm6 + name = "hammer (6cm)" + icon_state = "hammer6" + dig_amount = 6 + dig_speed = 3 SECONDS + +/obj/item/xenoarch/hammer/cm10 + name = "hammer (10cm)" + icon_state = "hammer10" + dig_amount = 10 + dig_speed = 5 SECONDS + +/obj/item/xenoarch/hammer/adv + name = "advanced hammer" + icon_state = "adv_hammer" + dig_amount = 1 + dig_speed = 1 + advanced = TRUE + +// BRUSHES + +/obj/item/xenoarch/brush + name = "brush" + desc = "A brush that is used to uncover the secrets of the past from strange rocks." + var/dig_speed = 3 SECONDS + icon_state = "brush" + +/obj/item/xenoarch/brush/adv + name = "advanced brush" + dig_speed = 0.5 SECONDS + icon_state = "adv_brush" + +// MISC. + +/obj/item/xenoarch/tape_measure + name = "measuring tape" + desc = "A measuring tape specifically produced to measure the depth that has been dug into strange rocks." + icon_state = "tape" + +/obj/item/xenoarch/handheld_scanner + name = "handheld scanner" + desc = "A handheld scanner for strange rocks. It tags the depths to the rock." + icon_state = "scanner" + var/scanning_speed = 3 SECONDS + var/scan_advanced = FALSE + +/obj/item/xenoarch/handheld_scanner/advanced + name = "advanced handheld scanner" + icon_state = "adv_scanner" + scanning_speed = 0.5 SECONDS + scan_advanced = TRUE + +/obj/item/xenoarch/handheld_recoverer + name = "handheld recoverer" + desc = "An item that has the capabilities to recover items lost due to time." + icon_state = "recoverer" + +/obj/item/xenoarch/handheld_recoverer/interact_with_atom(atom/interacting_with, mob/living/user, list/modifiers) + var/turf/target_turf = get_turf(interacting_with) + . = ITEM_INTERACT_SUCCESS + if(istype(interacting_with, /obj/item/xenoarch/broken_item/tech)) + var/spawn_item = pick_weight(GLOB.tech_reward) + new spawn_item(target_turf) + qdel(interacting_with) + return + if(istype(interacting_with, /obj/item/xenoarch/broken_item/weapon)) + var/spawn_item = pick_weight(GLOB.weapon_reward) + new spawn_item(target_turf) + qdel(interacting_with) + return + if(istype(interacting_with, /obj/item/xenoarch/broken_item/illegal)) + var/spawn_item = pick_weight(GLOB.illegal_reward) + new spawn_item(target_turf) + qdel(interacting_with) + return + if(istype(interacting_with, /obj/item/xenoarch/broken_item/alien)) + var/spawn_item = pick_weight(GLOB.alien_reward) + new spawn_item(target_turf) + qdel(interacting_with) + return + if(istype(interacting_with, /obj/item/xenoarch/broken_item/plant)) + var/spawn_item = pick_weight(GLOB.plant_reward) + new spawn_item(target_turf) + qdel(interacting_with) + return + if(istype(interacting_with, /obj/item/xenoarch/broken_item/clothing)) + var/spawn_item = pick_weight(GLOB.clothing_reward) + new spawn_item(target_turf) + qdel(interacting_with) + return + if(istype(interacting_with, /obj/item/xenoarch/broken_item/animal)) + var/spawn_item + var/turf/src_turf = get_turf(src) + for(var/looptime in 1 to rand(1,4)) + spawn_item = pick_weight(GLOB.animal_reward) + new spawn_item(src_turf) + qdel(interacting_with) + return + return NONE + +/obj/item/storage/belt/utility/xenoarch + name = "xenoarch toolbelt" + desc = "Holds tools." + icon = 'modular_doppler/xenoarch/icons/xenoarch_items.dmi' + icon_state = "xenoarch_belt" + content_overlays = FALSE + custom_premium_price = PAYCHECK_CREW * 2 + +/obj/item/storage/belt/utility/xenoarch/Initialize(mapload) + . = ..() + atom_storage.max_total_storage = 100 + atom_storage.max_slots = 15 + atom_storage.set_holdable(list( + /obj/item/xenoarch/hammer, + /obj/item/xenoarch/brush, + /obj/item/xenoarch/tape_measure, + /obj/item/xenoarch/handheld_scanner, + /obj/item/xenoarch/handheld_recoverer, + /obj/item/t_scanner/adv_mining_scanner, + /obj/item/mining_scanner, + /obj/item/gps + )) + +/obj/item/storage/bag/xenoarch + name = "xenoarch mining satchel" + desc = "This little bugger can be used to store and transport strange rocks." + icon = 'modular_doppler/xenoarch/icons/xenoarch_items.dmi' + icon_state = "satchel" + worn_icon_state = "satchel" + w_class = WEIGHT_CLASS_TINY + resistance_flags = FLAMMABLE + var/insert_speed = 1 SECONDS + var/mob/listeningTo + var/range = null + + var/spam_protection = FALSE //If this is TRUE, the holder won't receive any messages when they fail to pick up ore through crossing it + +/obj/item/storage/bag/xenoarch/Initialize(mapload) + . = ..() + atom_storage.max_specific_storage = WEIGHT_CLASS_GIGANTIC + atom_storage.allow_quick_empty = TRUE + atom_storage.max_total_storage = 1000 + atom_storage.max_slots = 25 + atom_storage.numerical_stacking = FALSE + atom_storage.can_hold = typecacheof(list(/obj/item/xenoarch/strange_rock)) + +/obj/item/storage/bag/xenoarch/equipped(mob/user) + . = ..() + if(listeningTo == user) + return + if(listeningTo) + UnregisterSignal(listeningTo, COMSIG_MOVABLE_MOVED) + RegisterSignal(user, COMSIG_MOVABLE_MOVED, PROC_REF(pickup_rocks)) + listeningTo = user + +/obj/item/storage/bag/xenoarch/dropped(mob/user) + . = ..() + if(listeningTo) + UnregisterSignal(listeningTo, COMSIG_MOVABLE_MOVED) + listeningTo = null + +/obj/item/storage/bag/xenoarch/proc/pickup_rocks(mob/living/user) + SIGNAL_HANDLER + var/show_message = FALSE + var/turf/tile = user.loc + if (!isturf(tile)) + return + + if(atom_storage) + for(var/A in tile) + if (!is_type_in_typecache(A, atom_storage.can_hold)) + continue + else if(atom_storage.attempt_insert(A, user)) + show_message = TRUE + else + if(!spam_protection) + to_chat(user, span_warning("Your [name] is full and can't hold any more!")) + spam_protection = TRUE + continue + if(show_message) + playsound(user, SFX_RUSTLE, 50, TRUE) + user.visible_message(span_notice("[user] scoops up the rocks beneath [user.p_them()]."), \ + span_notice("You scoop up the rocks beneath you with your [name].")) + spam_protection = FALSE + +/obj/item/storage/bag/xenoarch/adv + name = "advanced xenoarch mining satchel" + icon_state = "adv_satchel" + insert_speed = 0.1 SECONDS + +/obj/item/storage/bag/xenoarch/adv/Initialize(mapload) + . = ..() + atom_storage.max_slots = 50 + +/obj/structure/closet/xenoarch + name = "xenoarchaeology equipment locker" + icon_state = "science" + +/obj/structure/closet/xenoarch/PopulateContents() + . = ..() + new /obj/item/xenoarch/hammer/cm1(src) + new /obj/item/xenoarch/hammer/cm2(src) + new /obj/item/xenoarch/hammer/cm3(src) + new /obj/item/xenoarch/hammer/cm4(src) + new /obj/item/xenoarch/hammer/cm5(src) + new /obj/item/xenoarch/hammer/cm6(src) + new /obj/item/xenoarch/hammer/cm10(src) + new /obj/item/xenoarch/brush(src) + new /obj/item/xenoarch/tape_measure(src) + new /obj/item/xenoarch/handheld_scanner(src) + new /obj/item/storage/bag/xenoarch(src) + new /obj/item/storage/belt/utility/xenoarch(src) + new /obj/item/t_scanner/adv_mining_scanner(src) + new /obj/item/pickaxe(src) + new /obj/item/paper/fluff/xenoarch_guide(src) + +/obj/structure/closet/xenoarch/ashwalker_version + name = "dusty xenoarchaeology equipment locker" + +/obj/structure/closet/xenoarch/ashwalker_version/PopulateContents() + . = ..() + new /obj/item/xenoarch/handheld_recoverer(src) + +/obj/item/skillchip/xenoarch_magnifier + name = "R3T3N-T1VE skillchip" + desc = "This biochip integrates with user's brain to enable the mastery of a specific skill. Consult certified Nanotrasen neurosurgeon before use. \ + There's a little face etched into the back of the skillchip, with buck teeth and goofy-looking glasses." + auto_traits = list(TRAIT_XENOARCH_QUALIFIED) + skill_name = "Xenoarchaeological Analysis" + skill_description = "Allows for the more thorough magnification and notice of details on freshly-excavated xenoarchaeological garbage." + skill_icon = "magnifying-glass" + activate_message = span_notice("You feel the gleaned knowledge of a xenoarchaeological digsite internship reveal itself to your mind.") + deactivate_message = span_notice("The knowledge from a digsite internship fades away into jumbled coffee orders from ungrateful supervisors.") diff --git a/modular_doppler/xenoarch/icons/growing.dmi b/modular_doppler/xenoarch/icons/growing.dmi new file mode 100644 index 0000000000000000000000000000000000000000..4bab24c4fc374afb3073a7430c73b1e6f6cd51d7 GIT binary patch literal 16266 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 OQnXdsKrmtliwd(onwX8AF;=eJRL&=p5_+U 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 literal 0 HcmV?d00001 diff --git a/modular_doppler/xenoarch/icons/harvest.dmi b/modular_doppler/xenoarch/icons/harvest.dmi new file mode 100644 index 0000000000000000000000000000000000000000..1bdf1e3ea825bf25027116de0df8260a45e0f8da GIT binary patch literal 4749 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 OfQKqth$wQIcoW3=u}} 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 literal 0 HcmV?d00001 diff --git a/modular_doppler/xenoarch/icons/ore_visuals.dmi b/modular_doppler/xenoarch/icons/ore_visuals.dmi new file mode 100644 index 0000000000000000000000000000000000000000..ec45ede83c4a3c809e79ea4647801353f5f45519 GIT binary patch literal 28220 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 literal 0 HcmV?d00001 diff --git a/modular_doppler/xenoarch/icons/seeds.dmi b/modular_doppler/xenoarch/icons/seeds.dmi new file mode 100644 index 0000000000000000000000000000000000000000..e1aa7739f73608000d84915f420cd672af3356ae GIT binary patch literal 2600 zcmb7`c{J1w7sr2Nmo3}adKi?YXsm;5L)P@9WE*=U`xs-FC1c4>l&vE32#+iogCc9z zLKsWLc$kJTJeDkt{nhi|d*0`t_m6u&=iGbGJ@?#m?)l#2+qaB4&Iz9b0D!~P#K7W= z*fVosVLI~@;o+udcoS}E8)V=X=o;XK3G(to13*|o`fxL6rvm#Uvc`jRm4$kwFLLGl z)RDG0LkHwCqlPJYOXzZ~cwM3MLGInorZ$z|EPY)Co_yS9;Jh_cs0!Va#l}%SJcmcJ zd8OwoaI4E;y5$^fDF_MmDf=eExzMy@3~fg^cpM%im>e1GKkH_o;vb z_nw~Gn=WfABjZh9WFQO47m?(nv{~vfD)E~XmX}=y2VI+RB zRA2t(!@W3}S6r|!1V@6?CbH}z*qbOq8`(U{kuJ(2sTn~o&fvfzKU+M*PAI1j^r%#- z{=IwRa5R4s25%M_QFn>3(2 zJft123J6ySTW#}(f=a&8!!t@jm1BV>l~S>mk-(-0LZMauuaTo)naK>Ls^*&Rk)vW6 z2~ACr2M-mf>6XesQEmQiIDK<%rUsSOiGH_w(B@8G9~v1yv7*s$H1jK+X&dV8 zRPw32?RfKxfB0k z{FwTwxu%qAP&-RW(mG;=zTbCx^CVIUE z{y6d;gHbiyct5@XZ-ENs;a*!{l*2J=@Rr+sqNFN|mQyX8U%e_h{jJo68eB9xVcD*S zSw$EUv>=ADmYlE3m_k8#JleG;RttX=hxW7ir9Zgqtjv0Nt;1nqzwJ_`4)UA51Bj}z z5q_*XKNB;*>iif0kgL?VqPw_;hTy;8=K&I0?E2djX}AWp&6`&ZHh}rR!E$7q?1h>Gj@cI9!`y zN`_+`tvhmpaF?Q;|Ng{d=XmR9!s6WQW~NFjlIK+}>jdF-Of#l#GOliTPbl}a-~ChG z%AhT5y3z@z%GJ0dirL^g^&uUCOnL-T;}(l4CO%Sw<}x}!xAb?(hl@~-&*qnPfHXTP zyae>qKNr&B3B{w;5QyI^V|%`78Y?5BABPWw)DC;to$&8pu^J$)HKFZJEMskeOku_m z4VDY#bu0Vt#k0W($tP-5*Gb=^ra7^)aQ0WNbuX+{L|kw~OzrBiG1o*6oQV&Ca2a_* zam%ZS82VB%t31OfdFYJt>}(j6aCuS~ZCR-Jc#U|1D8Vutisz{w*Eh16kh_hLvj}G17XttF0ax zMl7+Xs2P&cGiKX5rzby868iRL;b*}difvXq55)rwv-@&a2Y=PLcs$$hO`}4V4_NvEjD@DAj zuZzuT2=Y*8Hmy14QcchKrFQ(BN8}0DWY*H$!%v$>k|)i{+cU)zehi?aV_>jLApYME zBV%3dQNT{t?tLSJ?QQVCXvQxgp#=l_4>5mpS>Sf>+QM{!2HHf0WCD~)F%{3Q;QK7Q zw~%5ocq85}jqRe~iKJG*x0IdzCD$puIHUJgjk$+NuI^8$=B28e3A@XFTW_PT?By0Y zsSI84fumP%y*?G_J?-I9hB$GnoV9A9ICV?)R^;wxM34jbGoRl((~_`-Zhl#LdC`>> z)(W@81Sv%=Ew_BufMG3h#JYWIZ&$vHRdwGRty%G0bY0j5 zxf;}dc4wAgq7;2&1ZmS@Pv+3n=LuxN=k&0_PPRNhiWA@bZ0Hp^$JmD$)(AdB&hWzV z*)*vSH%@c#9P_9UIw11R*F2@Prd|MB!TLP~x-q8kK_3aV+5&M1#1bwO06=z+uVm_O zcJyP7-uZQZk%*ww^OxJEmkN4_t71rlaHuDX zDkvQ^AL=jc`EjldqUd}QeJ1$*xXdl9^oo8wIDJiP5iJszj*#+3N?G8s0K^qwf;?A7o77&;S4c literal 0 HcmV?d00001 diff --git a/modular_doppler/xenoarch/icons/smoothrocks.dmi b/modular_doppler/xenoarch/icons/smoothrocks.dmi new file mode 100644 index 0000000000000000000000000000000000000000..a546f339460176a3cb6e3f026dced2fcc85b0006 GIT binary patch literal 4092 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 XW337rLRj#BKE&So6teP|AK`xhj=d^o literal 0 HcmV?d00001 diff --git a/modular_doppler/xenoarch/icons/xenoarch_area.dmi b/modular_doppler/xenoarch/icons/xenoarch_area.dmi new file mode 100644 index 0000000000000000000000000000000000000000..bc892c06fddc5dc2b79d7cbe9ad5796b8aad2352 GIT binary patch literal 1020 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 literal 0 HcmV?d00001 diff --git a/modular_doppler/xenoarch/icons/xenoarch_machines.dmi b/modular_doppler/xenoarch/icons/xenoarch_machines.dmi new file mode 100644 index 0000000000000000000000000000000000000000..f3183bec26eea97a95b138c22ae4e917223a76a6 GIT binary patch literal 1040 zcmeAS@N?(olHy`uVBq!ia0vp^2_VeD1|%QND7OGobE-ljN?cNllZ!G7N;32F7#J$% zOg+7kugO4w?ZM9PBJ~BP#};LaGaK@J;M;1ODct&G-N7H<`1q_WPW<4#&$j&A9o~#z zePUu~KeMzy&hvjZG1;@g;!29pbHl0TTYelWSkW?dZ_AOOiJg%meACW^{+TPvXFBtQ z`Tv&YySL7FSIS(MwCI5hE&XXJI6l%vV+92`3fp7v%NxcIu1Iw85qpuQwY4GDm~fSD1_%5i_l+|6|1hS z^)Og!e1E}#2}>7wY!C?TX!Ozz+V7CErp0KMX8n{K;p)>*SAVkI|8&)@lkbbx*Z3{@ zZs@?Fm=v-^eS*92{low63(CoOoI9!#CYDh0@%NOi9M?nGom*ZmQk&!)93=P4;NQ=w ztS?w(FW0HAP4K^R|0C05zEs8~68G~??fT0wO^iW8uWF{aJj1&5zn|a!tNWFb%xt}T z_m9FNqv^FDK3^1!%gYzv^>X)<^EwO+f8Lg{KR*9eRrlxL$ER1uCr|$W@OP>1|Ly6= zcOEa|7EtG$m!GTXCv?ZwXN#J^`42_2|ID8!m-Tbv6Mu!x4F7k<{;{*ZJUMO8bCc)0 z9-Y@YaCWNbort)3uUVEIRIPs}#=`Jcqv?Lmvp$9kSzFglF_G$>srI}n{-@~{{gcwZ zkDKBn8_Gm9-7oKW@LW{kP53?LbN>E?b%l+yp8NJ}t*R}!_x9@5JKtX%`FLh>@xk?b znErjKS`oH-X0l-A#K-G?Pi5T^x^~g^*QtHo2UzzPaj&}iy4gFo=FQ{vYtQBy>HR9M z=R7|1Rf@ zzh~Gve$V6=_+~7x@Fu-{%ZB+s84~T+12NEqx@XKSND2}b&WF3bWs0!2d^|schkMi$ z?Wb>jw{B*5nPRtajcdSjW~a~R&xb$UUVF3V5L1Adg1|ZUit2eQ>IHB7{PFAK+ht2` z^Cx68HauK3z2YO|Gv+D(Di=-Vuh{s-%lqHEPiL>J-*_~CmebFMxlguEQ)!E{b2zo1 zV+PEDb`CerzsrC)E)K(iKp)s0aI%MlZi_(kANIf{ZnK`9{CEzS#Th(Z{an^LB{Ts5 D5JmOk literal 0 HcmV?d00001 diff --git a/modular_doppler/xenoarch/readme.md b/modular_doppler/xenoarch/readme.md new file mode 100644 index 0000000000000..238ca5c47562a --- /dev/null +++ b/modular_doppler/xenoarch/readme.md @@ -0,0 +1,23 @@ +## Title: Xenoarchaeology + +MODULE ID: XENOARCH + +### Description: + +Xenoarch: Archaeology based around foreign bodies. Dig up encased relics of a time long past (or dig up our garbage on accident). + +### TG Proc Changes: + +N/A + +### Defines: + +N/A + +### Included files: + +N/A + +### Credits: + +Jake Park diff --git a/tgstation.dme b/tgstation.dme index 130d18e5df590..560fc96039899 100644 --- a/tgstation.dme +++ b/tgstation.dme @@ -395,6 +395,16 @@ #include "code\__DEFINES\traits\declarations.dm" #include "code\__DEFINES\traits\macros.dm" #include "code\__DEFINES\traits\sources.dm" +#include "code\__DEFINES\~doppler_defines\chemical_flags_doppler.dm" +#include "code\__DEFINES\~doppler_defines\keybinds.dm" +#include "code\__DEFINES\~doppler_defines\obj_flags_doppler.dm" +#include "code\__DEFINES\~doppler_defines\reagent_forging_tools.dm" +#include "code\__DEFINES\~doppler_defines\reskin_defines.dm" +#include "code\__DEFINES\~doppler_defines\signals.dm" +#include "code\__DEFINES\~doppler_defines\sound.dm" +#include "code\__DEFINES\~doppler_defines\span.dm" +#include "code\__DEFINES\~doppler_defines\techweb_nodes.dm" +#include "code\__DEFINES\~doppler_defines\traits.dm" #include "code\__HELPERS\_auxtools_api.dm" #include "code\__HELPERS\_dreamluau.dm" #include "code\__HELPERS\_lists.dm" @@ -509,6 +519,7 @@ #include "code\__HELPERS\paths\sssp.dm" #include "code\__HELPERS\sorts\helpers.dm" #include "code\__HELPERS\sorts\sort_instance.dm" +#include "code\__HELPERS\~doppler_helpers\is_helpers.dm" #include "code\_globalvars\_regexes.dm" #include "code\_globalvars\admin.dm" #include "code\_globalvars\arcade.dm" @@ -553,6 +564,9 @@ #include "code\_globalvars\lists\xenobiology.dm" #include "code\_globalvars\traits\_traits.dm" #include "code\_globalvars\traits\admin_tooling.dm" +#include "code\_globalvars\~doppler_globalvars\bitfields.dm" +#include "code\_globalvars\~doppler_globalvars\objective.dm" +#include "code\_globalvars\~doppler_globalvars\religion.dm" #include "code\_js\byjax.dm" #include "code\_js\menus.dm" #include "code\_onclick\adjacent.dm" @@ -6356,16 +6370,117 @@ #include "interface\fonts\spess_font.dm" #include "interface\fonts\tiny_unicode.dm" #include "interface\fonts\vcr_osd_mono.dm" +#include "modular_doppler\advanced_reskin\code\advanced_reskin.dm" +#include "modular_doppler\crafting_extended\code\crafting_extended.dm" +#include "modular_doppler\cryosleep\code\admin.dm" +#include "modular_doppler\cryosleep\code\ai.dm" +#include "modular_doppler\cryosleep\code\config.dm" +#include "modular_doppler\cryosleep\code\cryopod.dm" +#include "modular_doppler\cryosleep\code\cryo_console_return.dm" +#include "modular_doppler\cryosleep\code\job.dm" +#include "modular_doppler\cryosleep\code\jobs.dm" +#include "modular_doppler\cryosleep\code\mind.dm" +#include "modular_doppler\cryosleep\code\mood.dm" #include "modular_doppler\emotes\code\emotes.dm" #include "modular_doppler\emotes\code\added_emotes\animal_sounds.dm" #include "modular_doppler\emotes\code\added_emotes\human_things.dm" #include "modular_doppler\emotes\code\added_emotes\robot_sounds.dm" #include "modular_doppler\face_mouse_preferences\code\face_mouse_pref.dm" +#include "modular_doppler\hearthkin\primitive_catgirls\code\clothing.dm" +#include "modular_doppler\hearthkin\primitive_catgirls\code\clothing_vendor.dm" +#include "modular_doppler\hearthkin\primitive_catgirls\code\language.dm" +#include "modular_doppler\hearthkin\primitive_catgirls\code\map_items.dm" +#include "modular_doppler\hearthkin\primitive_catgirls\code\objects.dm" +#include "modular_doppler\hearthkin\primitive_catgirls\code\organs.dm" +#include "modular_doppler\hearthkin\primitive_catgirls\code\pet_commands.dm" +#include "modular_doppler\hearthkin\primitive_catgirls\code\smelling_salts.dm" +#include "modular_doppler\hearthkin\primitive_catgirls\code\spawner.dm" +#include "modular_doppler\hearthkin\primitive_catgirls\code\special_metals.dm" +#include "modular_doppler\hearthkin\primitive_catgirls\code\species.dm" +#include "modular_doppler\hearthkin\primitive_catgirls\code\translator.dm" +#include "modular_doppler\hearthkin\primitive_cooking_additions\code\big_mortar.dm" +#include "modular_doppler\hearthkin\primitive_cooking_additions\code\cauldron.dm" +#include "modular_doppler\hearthkin\primitive_cooking_additions\code\cookware.dm" +#include "modular_doppler\hearthkin\primitive_cooking_additions\code\cutting_board.dm" +#include "modular_doppler\hearthkin\primitive_cooking_additions\code\millstone.dm" +#include "modular_doppler\hearthkin\primitive_cooking_additions\code\plant_bag.dm" +#include "modular_doppler\hearthkin\primitive_cooking_additions\code\stone_griddle.dm" +#include "modular_doppler\hearthkin\primitive_cooking_additions\code\stone_oven.dm" +#include "modular_doppler\hearthkin\primitive_cooking_additions\code\stone_stove.dm" +#include "modular_doppler\hearthkin\primitive_production\code\antfarm.dm" +#include "modular_doppler\hearthkin\primitive_production\code\ceramics.dm" +#include "modular_doppler\hearthkin\primitive_production\code\farming.dm" +#include "modular_doppler\hearthkin\primitive_production\code\glassblowing.dm" +#include "modular_doppler\hearthkin\primitive_production\code\misc.dm" +#include "modular_doppler\hearthkin\primitive_production\code\production_skill.dm" +#include "modular_doppler\hearthkin\primitive_production\code\wormfarm.dm" +#include "modular_doppler\hearthkin\primitive_structures\code\fencing.dm" +#include "modular_doppler\hearthkin\primitive_structures\code\fuelwell.dm" +#include "modular_doppler\hearthkin\primitive_structures\code\furniture.dm" +#include "modular_doppler\hearthkin\primitive_structures\code\railroad.dm" +#include "modular_doppler\hearthkin\primitive_structures\code\storage_structures.dm" +#include "modular_doppler\hearthkin\primitive_structures\code\totally_thatch_roof.dm" +#include "modular_doppler\hearthkin\primitive_structures\code\wall_torch.dm" +#include "modular_doppler\hearthkin\primitive_structures\code\windows.dm" +#include "modular_doppler\hearthkin\primitive_structures\code\wooden_ladder.dm" +#include "modular_doppler\indicators\code\combat_indicator.dm" +#include "modular_doppler\indicators\code\emote_popup.dm" +#include "modular_doppler\indicators\code\sealed.dm" +#include "modular_doppler\indicators\code\ssd_indicator.dm" #include "modular_doppler\languages\language_datums.dm" +#include "modular_doppler\modular_chemistry\reagents\code\reagents.dm" #include "modular_doppler\modular_cosmetics\code\jacket_pockets.dm" #include "modular_doppler\modular_cosmetics\code\suits\jacket.dm" +#include "modular_doppler\modular_mob_spawn\code\mob_spawn.dm" +#include "modular_doppler\modular_sounds\code\sounds.dm" +#include "modular_doppler\modular_traits\code\neutral.dm" +#include "modular_doppler\modular_traits\code\organs.dm" +#include "modular_doppler\modular_persistence\code\modular_persistence.dm" +#include "modular_doppler\obj_flags_doppler\code\objs.dm" +#include "modular_doppler\reagent_forging\code\anvil.dm" +#include "modular_doppler\reagent_forging\code\centrifuge.dm" +#include "modular_doppler\reagent_forging\code\crafting_bench.dm" +#include "modular_doppler\reagent_forging\code\crafting_bench_recipes.dm" +#include "modular_doppler\reagent_forging\code\forge.dm" +#include "modular_doppler\reagent_forging\code\forge_clothing.dm" +#include "modular_doppler\reagent_forging\code\forge_items.dm" +#include "modular_doppler\reagent_forging\code\forge_recipes.dm" +#include "modular_doppler\reagent_forging\code\forge_weapons.dm" +#include "modular_doppler\reagent_forging\code\reagent_component.dm" +#include "modular_doppler\reagent_forging\code\seedmesh.dm" +#include "modular_doppler\reagent_forging\code\smith_skill.dm" +#include "modular_doppler\reagent_forging\code\tool_override.dm" +#include "modular_doppler\reagent_forging\code\water_basin.dm" +#include "modular_doppler\religion\code\chaplain.dm" +#include "modular_doppler\religion\code\religious_sects.dm" +#include "modular_doppler\stone\code\ore_veins.dm" +#include "modular_doppler\stone\code\stone.dm" #include "modular_doppler\tableflip\tableflip.dm" +#include "modular_doppler\tribal_extended\code\crafting.dm" +#include "modular_doppler\tribal_extended\code\recipes.dm" +#include "modular_doppler\tribal_extended\code\ammo\caseless\arrow.dm" +#include "modular_doppler\tribal_extended\code\ammo\reusable\arrow.dm" +#include "modular_doppler\tribal_extended\code\weapons\bow.dm" +#include "modular_doppler\tribal_extended\code\weapons\shield.dm" +#include "modular_doppler\tribal_extended\code\weapons\sword.dm" #include "modular_doppler\wargaming\code\game_kit.dm" #include "modular_doppler\wargaming\code\holograms.dm" #include "modular_doppler\wargaming\code\projectors.dm" +#include "modular_doppler\xenoarch\code\modules\hydroponics\amauri.dm" +#include "modular_doppler\xenoarch\code\modules\hydroponics\gelthi.dm" +#include "modular_doppler\xenoarch\code\modules\hydroponics\jurlmah.dm" +#include "modular_doppler\xenoarch\code\modules\hydroponics\nofruit.dm" +#include "modular_doppler\xenoarch\code\modules\hydroponics\shand.dm" +#include "modular_doppler\xenoarch\code\modules\hydroponics\surik.dm" +#include "modular_doppler\xenoarch\code\modules\hydroponics\telriis.dm" +#include "modular_doppler\xenoarch\code\modules\hydroponics\thaadra.dm" +#include "modular_doppler\xenoarch\code\modules\hydroponics\vale.dm" +#include "modular_doppler\xenoarch\code\modules\hydroponics\vaporsac.dm" +#include "modular_doppler\xenoarch\code\modules\research\xenoarch\designs_and_tech.dm" +#include "modular_doppler\xenoarch\code\modules\research\xenoarch\glassblowing_integration.dm" +#include "modular_doppler\xenoarch\code\modules\research\xenoarch\strange_rock.dm" +#include "modular_doppler\xenoarch\code\modules\research\xenoarch\xenoarch_item.dm" +#include "modular_doppler\xenoarch\code\modules\research\xenoarch\xenoarch_machine.dm" +#include "modular_doppler\xenoarch\code\modules\research\xenoarch\xenoarch_reward.dm" +#include "modular_doppler\xenoarch\code\modules\research\xenoarch\xenoarch_tool.dm" // END_INCLUDE From 2ce70a44f3c496e8506ec2bf5cfb083ea1ae9998 Mon Sep 17 00:00:00 2001 From: Kaostico Date: Sat, 31 Aug 2024 21:39:42 -0300 Subject: [PATCH 07/28] removing unnecesary stuff --- code/__DEFINES/~doppler_defines/chemical_flags_doppler.dm | 2 -- code/_globalvars/~doppler_globalvars/bitfields.dm | 4 ---- modular_doppler/modular_chemistry/reagents/code/reagents.dm | 4 ---- tgstation.dme | 2 -- 4 files changed, 12 deletions(-) delete mode 100644 code/__DEFINES/~doppler_defines/chemical_flags_doppler.dm delete mode 100644 modular_doppler/modular_chemistry/reagents/code/reagents.dm diff --git a/code/__DEFINES/~doppler_defines/chemical_flags_doppler.dm b/code/__DEFINES/~doppler_defines/chemical_flags_doppler.dm deleted file mode 100644 index 981a465137ccb..0000000000000 --- a/code/__DEFINES/~doppler_defines/chemical_flags_doppler.dm +++ /dev/null @@ -1,2 +0,0 @@ -/// This reagent is useful for blood regeneration. Useful for Hemophages. -#define REAGENT_BLOOD_REGENERATING (1<<0) diff --git a/code/_globalvars/~doppler_globalvars/bitfields.dm b/code/_globalvars/~doppler_globalvars/bitfields.dm index eb35bab2e0ce7..315c2e0ec5cd6 100644 --- a/code/_globalvars/~doppler_globalvars/bitfields.dm +++ b/code/_globalvars/~doppler_globalvars/bitfields.dm @@ -1,7 +1,3 @@ DEFINE_BITFIELD(obj_flags_doppler, list( "ANVIL_REPAIR" = ANVIL_REPAIR, )) - -DEFINE_BITFIELD(chemical_flags_doppler, list( - "REAGENT_BLOOD_REGENERATING" = REAGENT_BLOOD_REGENERATING, -)) diff --git a/modular_doppler/modular_chemistry/reagents/code/reagents.dm b/modular_doppler/modular_chemistry/reagents/code/reagents.dm deleted file mode 100644 index 97411f3583ccd..0000000000000 --- a/modular_doppler/modular_chemistry/reagents/code/reagents.dm +++ /dev/null @@ -1,4 +0,0 @@ -/datum/reagent - /// Modular version of `chemical_flags`, so we don't have to worry about - /// it causing conflicts in the future. - var/chemical_flags_doppler = NONE diff --git a/tgstation.dme b/tgstation.dme index 560fc96039899..910d23c5a190b 100644 --- a/tgstation.dme +++ b/tgstation.dme @@ -395,7 +395,6 @@ #include "code\__DEFINES\traits\declarations.dm" #include "code\__DEFINES\traits\macros.dm" #include "code\__DEFINES\traits\sources.dm" -#include "code\__DEFINES\~doppler_defines\chemical_flags_doppler.dm" #include "code\__DEFINES\~doppler_defines\keybinds.dm" #include "code\__DEFINES\~doppler_defines\obj_flags_doppler.dm" #include "code\__DEFINES\~doppler_defines\reagent_forging_tools.dm" @@ -6428,7 +6427,6 @@ #include "modular_doppler\indicators\code\sealed.dm" #include "modular_doppler\indicators\code\ssd_indicator.dm" #include "modular_doppler\languages\language_datums.dm" -#include "modular_doppler\modular_chemistry\reagents\code\reagents.dm" #include "modular_doppler\modular_cosmetics\code\jacket_pockets.dm" #include "modular_doppler\modular_cosmetics\code\suits\jacket.dm" #include "modular_doppler\modular_mob_spawn\code\mob_spawn.dm" From 6c49358efa7679a6206639bb63a48040c0b63308 Mon Sep 17 00:00:00 2001 From: Kaostico Date: Mon, 2 Sep 2024 13:14:42 -0300 Subject: [PATCH 08/28] tribal arrows now visible millstone stamina damage changed for in_use flag changed path name of dusty xenoarch locker from ashlizard to tribal --- .../code/millstone.dm | 41 +++++++++++++------ .../code/ammo/caseless/arrow.dm | 3 ++ .../research/xenoarch/xenoarch_tool.dm | 4 +- 3 files changed, 34 insertions(+), 14 deletions(-) diff --git a/modular_doppler/hearthkin/primitive_cooking_additions/code/millstone.dm b/modular_doppler/hearthkin/primitive_cooking_additions/code/millstone.dm index 0f567e8d7b071..e251c3f629f17 100644 --- a/modular_doppler/hearthkin/primitive_cooking_additions/code/millstone.dm +++ b/modular_doppler/hearthkin/primitive_cooking_additions/code/millstone.dm @@ -1,6 +1,3 @@ -#define MILLSTONE_STAMINA_MINIMUM 50 //What is the amount of stam damage that we prevent mill use at -#define MILLSTONE_STAMINA_USE 100 //How much stam damage is given to people when the mill is used - /obj/structure/millstone name = "millstone" desc = "Two big disks of something heavy and tough. Put a plant between them and spin, and you'll end up with seeds and a really ground up plant." @@ -16,6 +13,8 @@ drag_slowdown = 2 /// The maximum number of items this structure can store var/maximum_contained_items = 10 + /// Is the millstone processing plants? If true, prevents most interactions with the millstone + var/in_use = FALSE /obj/structure/millstone/examine(mob/user) . = ..() @@ -50,6 +49,10 @@ return ..() /obj/structure/millstone/click_alt(mob/user) + if(in_use) // If the millstone is currently in use by someone then we cannot use it + balloon_alert(user, "millstone busy") + return CLICK_ACTION_BLOCKING + if(!length(contents)) balloon_alert(user, "nothing inside!") return CLICK_ACTION_BLOCKING @@ -59,6 +62,9 @@ return CLICK_ACTION_SUCCESS /obj/structure/millstone/click_ctrl_shift(mob/user) + if(in_use) // If the millstone is currently in use by someone then we cannot use it + balloon_alert(user, "millstone busy") + return set_anchored(!anchored) balloon_alert(user, "[anchored ? "secured" : "unsecured"]") @@ -71,6 +77,10 @@ target_item.forceMove(get_turf(src)) /obj/structure/millstone/attack_hand_secondary(mob/user, list/modifiers) + if(in_use) // If the millstone is currently in use by someone then we cannot use it + balloon_alert(user, "millstone busy") + return + . = ..() if(. == SECONDARY_ATTACK_CANCEL_ATTACK_CHAIN) return @@ -82,6 +92,10 @@ return SECONDARY_ATTACK_CANCEL_ATTACK_CHAIN /obj/structure/millstone/crowbar_act(mob/living/user, obj/item/tool) + if(in_use) // If the millstone is currently in use by someone then we cannot use it + balloon_alert(user, "millstone busy") + return + . = ..() balloon_alert_to_viewers("disassembling...") if(!do_after(user, 2 SECONDS, src)) @@ -89,6 +103,10 @@ deconstruct(TRUE) /obj/structure/millstone/attackby(obj/item/attacking_item, mob/user) + if(in_use) // If the millstone is currently in use by someone then we cannot use it + balloon_alert(user, "millstone busy") + return + if(istype(attacking_item, /obj/item/storage/bag)) if(length(contents) >= maximum_contained_items) balloon_alert(user, "already full") @@ -125,12 +143,12 @@ /// Takes the content's seeds and spits them out on the turf, as well as grinding whatever the contents may be /obj/structure/millstone/proc/mill_it_up(mob/living/carbon/human/user) - if(!length(contents)) - balloon_alert(user, "nothing to mill") + if(in_use) // If the millstone is currently in use by someone then we cannot use it + balloon_alert(user, "millstone busy") return - if(user.getStaminaLoss() > MILLSTONE_STAMINA_MINIMUM) - balloon_alert(user, "too tired") + if(!length(contents)) + balloon_alert(user, "nothing to mill") return if(!length(contents) || !in_range(src, user)) @@ -138,19 +156,18 @@ balloon_alert_to_viewers("grinding...") + in_use = TRUE + flick("millstone_spin", src) playsound(src, 'sound/effects/stonedoor_openclose.ogg', 50, TRUE) - user.adjustStaminaLoss(MILLSTONE_STAMINA_USE) // Prevents spamming it - if(!do_after(user, 5 SECONDS, target = src)) balloon_alert_to_viewers("stopped grinding") + in_use = FALSE return + in_use = FALSE for(var/target_item as anything in contents) seedify(target_item, t_max = 1) balloon_alert_to_viewers("finished grinding") - -#undef MILLSTONE_STAMINA_MINIMUM -#undef MILLSTONE_STAMINA_USE diff --git a/modular_doppler/tribal_extended/code/ammo/caseless/arrow.dm b/modular_doppler/tribal_extended/code/ammo/caseless/arrow.dm index e098d5e7277fe..f10d3500fd3b7 100644 --- a/modular_doppler/tribal_extended/code/ammo/caseless/arrow.dm +++ b/modular_doppler/tribal_extended/code/ammo/caseless/arrow.dm @@ -3,6 +3,7 @@ desc = "An arrow made from ash and iron. They're cheap, but they fell the beasts of lavaland like none other." icon = 'modular_doppler/tribal_extended/icons/ammo.dmi' icon_state = "ashenarrow" + base_icon_state = "ashenarrow" projectile_type = /obj/projectile/bullet/arrow/ash /obj/item/ammo_casing/arrow/bone @@ -10,6 +11,7 @@ desc = "An arrow made of bone and sinew. The tip is sharp and jagged, suitable for digging into flesh." icon = 'modular_doppler/tribal_extended/icons/ammo.dmi' icon_state = "bonearrow" + base_icon_state = "ashenarrow" projectile_type = /obj/projectile/bullet/arrow/bone /obj/item/ammo_casing/arrow/bronze @@ -17,4 +19,5 @@ desc = "An arrow tipped with bronze. Fit for killing gods." icon = 'modular_doppler/tribal_extended/icons/ammo.dmi' icon_state = "bronzearrow" + base_icon_state = "ashenarrow" projectile_type = /obj/projectile/bullet/arrow/bronze diff --git a/modular_doppler/xenoarch/code/modules/research/xenoarch/xenoarch_tool.dm b/modular_doppler/xenoarch/code/modules/research/xenoarch/xenoarch_tool.dm index 3bc98a517bae2..f29654aad4043 100644 --- a/modular_doppler/xenoarch/code/modules/research/xenoarch/xenoarch_tool.dm +++ b/modular_doppler/xenoarch/code/modules/research/xenoarch/xenoarch_tool.dm @@ -287,10 +287,10 @@ new /obj/item/pickaxe(src) new /obj/item/paper/fluff/xenoarch_guide(src) -/obj/structure/closet/xenoarch/ashwalker_version +/obj/structure/closet/xenoarch/tribal_version name = "dusty xenoarchaeology equipment locker" -/obj/structure/closet/xenoarch/ashwalker_version/PopulateContents() +/obj/structure/closet/xenoarch/tribal_version/PopulateContents() . = ..() new /obj/item/xenoarch/handheld_recoverer(src) From 646a0131b11b3e1a55855b49a873b04d363d2a6f Mon Sep 17 00:00:00 2001 From: Kaostico Date: Mon, 2 Sep 2024 13:56:50 -0300 Subject: [PATCH 09/28] fixed some config stuff --- config/doppler/config_doppler.txt | 3 +++ modular_doppler/cryosleep/code/config.dm | 2 +- modular_doppler/cryosleep/code/cryopod.dm | 2 +- .../hearthkin/primitive_catgirls/code/smelling_salts.dm | 1 - modular_doppler/hearthkin/primitive_catgirls/code/spawner.dm | 4 +--- 5 files changed, 6 insertions(+), 6 deletions(-) diff --git a/config/doppler/config_doppler.txt b/config/doppler/config_doppler.txt index 418749c3311a3..edb507a2066e1 100644 --- a/config/doppler/config_doppler.txt +++ b/config/doppler/config_doppler.txt @@ -1,2 +1,5 @@ ## Combat indicator, comment out to disable it COMBAT_INDICATOR + +## How long until someone can be put in cryo if they are SSD, default is 9000 (15 minutes) +CRYO_MIN_SSD_TIME 9000 diff --git a/modular_doppler/cryosleep/code/config.dm b/modular_doppler/cryosleep/code/config.dm index c3d9565771b32..cd99eca3b9829 100644 --- a/modular_doppler/cryosleep/code/config.dm +++ b/modular_doppler/cryosleep/code/config.dm @@ -1,2 +1,2 @@ /datum/config_entry/number/cryo_min_ssd_time - config_entry_value = 15 + config_entry_value = 9000 diff --git a/modular_doppler/cryosleep/code/cryopod.dm b/modular_doppler/cryosleep/code/cryopod.dm index 110e762c822e4..6ff3ac5e959da 100644 --- a/modular_doppler/cryosleep/code/cryopod.dm +++ b/modular_doppler/cryosleep/code/cryopod.dm @@ -154,7 +154,7 @@ MAPPING_DIRECTIONAL_HELPERS(/obj/machinery/computer/cryopod, 32) /// Whether the cryopod respects the minimum time someone has to be disconnected before they can be put into cryo by another player var/allow_timer_override = FALSE /// Minimum time for someone to be SSD before another player can cryo them. - var/ssd_time = 30 MINUTES //Replace with "cryo_min_ssd_time" CONFIG + var/ssd_time = CONFIG_GET(number/cryo_min_ssd_time) //"cryo_min_ssd_time" in CONFIG /// Time until despawn when a mob enters a cryopod. You cannot other people in pods unless they're catatonic. var/time_till_despawn = 30 SECONDS diff --git a/modular_doppler/hearthkin/primitive_catgirls/code/smelling_salts.dm b/modular_doppler/hearthkin/primitive_catgirls/code/smelling_salts.dm index 6996855fbb427..a91337b514a28 100644 --- a/modular_doppler/hearthkin/primitive_catgirls/code/smelling_salts.dm +++ b/modular_doppler/hearthkin/primitive_catgirls/code/smelling_salts.dm @@ -66,5 +66,4 @@ carbon_target.grab_ghost() carbon_target.revive() - // to_chat(carbon_target, span_userdanger("[CONFIG_GET(string/blackoutpolicy)]")) log_combat(user, carbon_target, "revived", src) diff --git a/modular_doppler/hearthkin/primitive_catgirls/code/spawner.dm b/modular_doppler/hearthkin/primitive_catgirls/code/spawner.dm index 6609cc69e1c03..ae625f315ad1e 100644 --- a/modular_doppler/hearthkin/primitive_catgirls/code/spawner.dm +++ b/modular_doppler/hearthkin/primitive_catgirls/code/spawner.dm @@ -33,14 +33,12 @@ /// Nulled every time someone joins or leaves to ensure it gets re-generated. var/join_and_leave_log_cache = null /// The minimum time someone needs to be SSD before they can be put back in - var/ssd_time = 30 MINUTES + var/ssd_time = CONFIG_GET(number/cryo_min_ssd_time) /obj/effect/mob_spawn/ghost_role/human/primitive_catgirl/Initialize(mapload) . = ..() team = new /datum/team/primitive_catgirls() - // important_text = "Read the full policy here." - /obj/effect/mob_spawn/ghost_role/human/primitive_catgirl/Destroy() team = null return ..() From 2e77613c1bc9e9ecd7077653fae8a99d3f916adb Mon Sep 17 00:00:00 2001 From: Kaostico Date: Mon, 2 Sep 2024 14:27:32 -0300 Subject: [PATCH 10/28] modularize antagonist recipes --- .../hearthkin/primitive_catgirls/code/spawner.dm | 12 +----------- .../modular_antagonist/code/antag_datum.dm | 13 +++++++++++++ 2 files changed, 14 insertions(+), 11 deletions(-) create mode 100644 modular_doppler/modular_antagonist/code/antag_datum.dm diff --git a/modular_doppler/hearthkin/primitive_catgirls/code/spawner.dm b/modular_doppler/hearthkin/primitive_catgirls/code/spawner.dm index ae625f315ad1e..ae4cdc529c3c9 100644 --- a/modular_doppler/hearthkin/primitive_catgirls/code/spawner.dm +++ b/modular_doppler/hearthkin/primitive_catgirls/code/spawner.dm @@ -279,7 +279,7 @@ /// Tracks the antag datum's 'team' for showing in the ghost orbit menu var/datum/team/primitive_catgirls/feline_team - var/list/antag_recipes = list( + antag_recipes = list( /datum/crafting_recipe/boneaxe, /datum/crafting_recipe/bonespear, /datum/crafting_recipe/bonedagger, @@ -290,16 +290,6 @@ /datum/crafting_recipe/frozen_breath, ) -/datum/antagonist/primitive_catgirl/on_gain() - . = ..() - for(var/recipe_datum in antag_recipes) - owner.teach_crafting_recipe(recipe_datum) - -/datum/antagonist/primitive_catgirl/on_removal() - . = ..() - for(var/recipe_datum in antag_recipes) - owner.unteach_crafting_recipe(recipe_datum) - /datum/antagonist/primitive_catgirl/Destroy() feline_team = null return ..() diff --git a/modular_doppler/modular_antagonist/code/antag_datum.dm b/modular_doppler/modular_antagonist/code/antag_datum.dm new file mode 100644 index 0000000000000..dec9482937530 --- /dev/null +++ b/modular_doppler/modular_antagonist/code/antag_datum.dm @@ -0,0 +1,13 @@ +/datum/antagonist + /// the list of recipes that an antag will learn/unlearn on gain/loss + var/list/antag_recipes = list() + +/datum/antagonist/on_gain() + . = ..() + for(var/recipe_datum in antag_recipes) + owner.teach_crafting_recipe(recipe_datum) + +/datum/antagonist/on_removal() + . = ..() + for(var/recipe_datum in antag_recipes) + owner.unteach_crafting_recipe(recipe_datum) From 1a1d74531cf8a8875ba702ac861dabacbeb726a2 Mon Sep 17 00:00:00 2001 From: Kaostico Date: Mon, 2 Sep 2024 21:31:22 -0300 Subject: [PATCH 11/28] fixes after merging and adding hearthkin to species --- config/doppler/config_doppler.txt | 3 +++ modular_doppler/cryosleep/code/cryopod.dm | 17 +++-------------- .../primitive_catgirls/code/spawner.dm | 6 +++--- .../primitive_catgirls/code/species.dm | 17 ++++++++++------- tgstation.dme | 1 + 5 files changed, 20 insertions(+), 24 deletions(-) diff --git a/config/doppler/config_doppler.txt b/config/doppler/config_doppler.txt index edb507a2066e1..0da710789294f 100644 --- a/config/doppler/config_doppler.txt +++ b/config/doppler/config_doppler.txt @@ -3,3 +3,6 @@ COMBAT_INDICATOR ## How long until someone can be put in cryo if they are SSD, default is 9000 (15 minutes) CRYO_MIN_SSD_TIME 9000 + +## Primitive demihumans +ROUNDSTART_RACES primitive_felinid diff --git a/modular_doppler/cryosleep/code/cryopod.dm b/modular_doppler/cryosleep/code/cryopod.dm index 6ff3ac5e959da..6a05501152950 100644 --- a/modular_doppler/cryosleep/code/cryopod.dm +++ b/modular_doppler/cryosleep/code/cryopod.dm @@ -153,8 +153,8 @@ MAPPING_DIRECTIONAL_HELPERS(/obj/machinery/computer/cryopod, 32) var/open_icon_state = "cryopod-open" /// Whether the cryopod respects the minimum time someone has to be disconnected before they can be put into cryo by another player var/allow_timer_override = FALSE - /// Minimum time for someone to be SSD before another player can cryo them. - var/ssd_time = CONFIG_GET(number/cryo_min_ssd_time) //"cryo_min_ssd_time" in CONFIG + /// Minimum time for someone to be SSD before another player can cryo them. Customizable in "cryo_min_ssd_time" in config_doppler + var/ssd_time = 15 MINUTES /// Time until despawn when a mob enters a cryopod. You cannot other people in pods unless they're catatonic. var/time_till_despawn = 30 SECONDS @@ -174,6 +174,7 @@ MAPPING_DIRECTIONAL_HELPERS(/obj/machinery/computer/cryopod, 32) /obj/machinery/cryopod/Initialize(mapload) ..() + ssd_time = CONFIG_GET(number/cryo_min_ssd_time) if(!quiet) GLOB.valid_cryopods += src return INITIALIZE_HINT_LATELOAD //Gotta populate the cryopod computer GLOB first @@ -263,18 +264,6 @@ MAPPING_DIRECTIONAL_HELPERS(/obj/machinery/computer/cryopod, 32) else if(istype(objective.target) && objective.target == mob_occupant.mind) if(!istype(objective, /datum/objective/contract)) return - // var/datum/opposing_force/affected_contractor = objective.owner.opposing_force - // var/datum/contractor_hub/affected_contractor_hub = affected_contractor.contractor_hub - // for(var/datum/syndicate_contract/affected_contract as anything in affected_contractor_hub.assigned_contracts) - // if(!(affected_contract.contract == objective)) - // continue - // var/contract_id = affected_contract.id - // affected_contractor_hub.create_single_contract(objective.owner, affected_contract.payout_type) - // affected_contractor_hub.assigned_contracts[contract_id].status = CONTRACT_STATUS_ABORTED - // if (affected_contractor_hub.current_contract == objective) - // affected_contractor_hub.current_contract = null - // to_chat(objective.owner.current, "
[span_userdanger("Contract target out of reach. Contract rerolled.")]") - // break else if(istype(objective.target) && objective.target == mob_occupant.mind) var/old_target = objective.target objective.target = null diff --git a/modular_doppler/hearthkin/primitive_catgirls/code/spawner.dm b/modular_doppler/hearthkin/primitive_catgirls/code/spawner.dm index ae4cdc529c3c9..53cfa3f244280 100644 --- a/modular_doppler/hearthkin/primitive_catgirls/code/spawner.dm +++ b/modular_doppler/hearthkin/primitive_catgirls/code/spawner.dm @@ -32,12 +32,12 @@ /// The cached string to display for additional info on who joined and who left. /// Nulled every time someone joins or leaves to ensure it gets re-generated. var/join_and_leave_log_cache = null - /// The minimum time someone needs to be SSD before they can be put back in - var/ssd_time = CONFIG_GET(number/cryo_min_ssd_time) - + /// The minimum time someone needs to be SSD before they can be put back in. Shares config "cryo_min_ssd_time" with cryopod + var/ssd_time = 15 MINUTES /obj/effect/mob_spawn/ghost_role/human/primitive_catgirl/Initialize(mapload) . = ..() team = new /datum/team/primitive_catgirls() + ssd_time = CONFIG_GET(number/cryo_min_ssd_time) /obj/effect/mob_spawn/ghost_role/human/primitive_catgirl/Destroy() team = null diff --git a/modular_doppler/hearthkin/primitive_catgirls/code/species.dm b/modular_doppler/hearthkin/primitive_catgirls/code/species.dm index 9590424c29320..e521896baccdd 100644 --- a/modular_doppler/hearthkin/primitive_catgirls/code/species.dm +++ b/modular_doppler/hearthkin/primitive_catgirls/code/species.dm @@ -59,16 +59,19 @@ hearthkin.dna.remove_mutation(/datum/mutation/human/olfaction) /datum/species/human/felinid/primitive/prepare_human_for_preview(mob/living/carbon/human/human_for_preview) - human_for_preview.hairstyle = "Blunt Bangs Alt" - human_for_preview.hair_color = "#323442" + human_for_preview.set_haircolor("#323442", update = FALSE) + human_for_preview.set_hairstyle("Blunt Bangs Alt", update = TRUE) human_for_preview.skin_tone = "mediterranean" - human_for_preview.update_body_parts() + var/obj/item/organ/internal/ears/cat/cat_ears = human_for_preview.get_organ_by_type(/obj/item/organ/internal/ears/cat) + var/obj/item/organ/external/tail/cat/cat_tail = human_for_preview.get_organ_by_type(/obj/item/organ/external/tail/cat) + if (cat_ears) + cat_ears.color = human_for_preview.hair_color + if (cat_tail) + cat_tail.color = human_for_preview.hair_color + if (cat_ears || cat_tail) + human_for_preview.update_body() - human_for_preview.dna.species.mutant_bodyparts["tail"] = list(MUTANT_INDEX_NAME = "Cat", MUTANT_INDEX_COLOR_LIST = list(human_for_preview.hair_color)) - human_for_preview.dna.species.mutant_bodyparts["ears"] = list(MUTANT_INDEX_NAME = "Cat", MUTANT_INDEX_COLOR_LIST = list(human_for_preview.hair_color)) - - human_for_preview.update_mutant_bodyparts() human_for_preview.update_body(is_creating = TRUE) /datum/species/human/felinid/primitive/get_species_description() diff --git a/tgstation.dme b/tgstation.dme index 5befea5d54ee7..791f1570c42fc 100644 --- a/tgstation.dme +++ b/tgstation.dme @@ -6430,6 +6430,7 @@ #include "modular_doppler\indicators\code\sealed.dm" #include "modular_doppler\indicators\code\ssd_indicator.dm" #include "modular_doppler\languages\language_datums.dm" +#include "modular_doppler\modular_antagonist\code\antag_datum.dm" #include "modular_doppler\modular_cosmetics\code\jacket_pockets.dm" #include "modular_doppler\modular_cosmetics\code\neck\collar.dm" #include "modular_doppler\modular_cosmetics\code\suits\jacket.dm" From 60792c4f40aed42f2452cdc015acf03bf2511783 Mon Sep 17 00:00:00 2001 From: Kaostico Date: Mon, 2 Sep 2024 21:37:03 -0300 Subject: [PATCH 12/28] moved hearthkin dna definitions to doppler_defines --- code/__DEFINES/~doppler_defines/DNA.dm | 2 ++ modular_doppler/hearthkin/primitive_catgirls/code/species.dm | 2 -- 2 files changed, 2 insertions(+), 2 deletions(-) create mode 100644 code/__DEFINES/~doppler_defines/DNA.dm diff --git a/code/__DEFINES/~doppler_defines/DNA.dm b/code/__DEFINES/~doppler_defines/DNA.dm new file mode 100644 index 0000000000000..cf52d6b80ba82 --- /dev/null +++ b/code/__DEFINES/~doppler_defines/DNA.dm @@ -0,0 +1,2 @@ +//Species IDs added from Doppler Shift. +#define SPECIES_FELINE_PRIMITIVE "primitive_felinid" diff --git a/modular_doppler/hearthkin/primitive_catgirls/code/species.dm b/modular_doppler/hearthkin/primitive_catgirls/code/species.dm index e521896baccdd..edcbc0b1ae0cd 100644 --- a/modular_doppler/hearthkin/primitive_catgirls/code/species.dm +++ b/modular_doppler/hearthkin/primitive_catgirls/code/species.dm @@ -1,5 +1,3 @@ -#define SPECIES_FELINE_PRIMITIVE "primitive_felinid" //This should go on a dedicated define DNA file - /mob/living/carbon/human/species/felinid/primitive race = /datum/species/human/felinid/primitive From 01ec337392921c6cba47f1a2a789ae1b14da0be4 Mon Sep 17 00:00:00 2001 From: Kaostico Date: Tue, 3 Sep 2024 11:20:25 -0300 Subject: [PATCH 13/28] First batch of clothes - aka my personal hell --- .../primitive_catgirls/code/clothing.dm | 105 +++++++++++++++--- .../code/clothing_vendor.dm | 17 +-- .../code/greyscale_config.dm | 89 +++++++++++++++ .../primitive_catgirls/icons/loincloth.dmi | Bin 0 -> 409 bytes .../primitive_catgirls/icons/pelt.dmi | Bin 0 -> 1809 bytes .../primitive_catgirls/icons/pelt_big.dmi | Bin 0 -> 2686 bytes .../primitive_catgirls/icons/pelt_worn.dmi | Bin 0 -> 4649 bytes .../GAGS/json_configs/heartkin/armwraps.json | 10 ++ .../json_configs/heartkin/armwraps_worn.json | 10 ++ .../json_configs/heartkin/body_wraps.json | 16 +++ .../heartkin/body_wraps_worn.json | 16 +++ .../GAGS/json_configs/heartkin/boots.json | 16 +++ .../json_configs/heartkin/boots_worn.json | 16 +++ .../GAGS/json_configs/heartkin/coat.json | 16 +++ .../GAGS/json_configs/heartkin/coat_worn.json | 16 +++ .../json_configs/heartkin/ferroniere.json | 16 +++ .../heartkin/ferroniere_worn.json | 16 +++ .../GAGS/json_configs/heartkin/gauntlets.json | 16 +++ .../json_configs/heartkin/gauntlets_worn.json | 16 +++ .../GAGS/json_configs/heartkin/loincloth.json | 10 ++ .../json_configs/heartkin/loincloth_alt.json | 10 ++ .../heartkin/loincloth_alt_worn.json | 10 ++ .../json_configs/heartkin/loincloth_worn.json | 10 ++ .../json_configs/heartkin/tailored_dress.json | 16 +++ .../heartkin/tailored_dress_worn.json | 16 +++ .../GAGS/json_configs/heartkin/tunic.json | 22 ++++ .../json_configs/heartkin/tunic_worn.json | 22 ++++ tgstation.dme | 6 +- 28 files changed, 487 insertions(+), 26 deletions(-) create mode 100644 modular_doppler/hearthkin/primitive_catgirls/code/greyscale_config.dm create mode 100644 modular_doppler/hearthkin/primitive_catgirls/icons/loincloth.dmi create mode 100644 modular_doppler/hearthkin/primitive_catgirls/icons/pelt.dmi create mode 100644 modular_doppler/hearthkin/primitive_catgirls/icons/pelt_big.dmi create mode 100644 modular_doppler/hearthkin/primitive_catgirls/icons/pelt_worn.dmi create mode 100644 modular_doppler/modular_cosmetics/GAGS/json_configs/heartkin/armwraps.json create mode 100644 modular_doppler/modular_cosmetics/GAGS/json_configs/heartkin/armwraps_worn.json create mode 100644 modular_doppler/modular_cosmetics/GAGS/json_configs/heartkin/body_wraps.json create mode 100644 modular_doppler/modular_cosmetics/GAGS/json_configs/heartkin/body_wraps_worn.json create mode 100644 modular_doppler/modular_cosmetics/GAGS/json_configs/heartkin/boots.json create mode 100644 modular_doppler/modular_cosmetics/GAGS/json_configs/heartkin/boots_worn.json create mode 100644 modular_doppler/modular_cosmetics/GAGS/json_configs/heartkin/coat.json create mode 100644 modular_doppler/modular_cosmetics/GAGS/json_configs/heartkin/coat_worn.json create mode 100644 modular_doppler/modular_cosmetics/GAGS/json_configs/heartkin/ferroniere.json create mode 100644 modular_doppler/modular_cosmetics/GAGS/json_configs/heartkin/ferroniere_worn.json create mode 100644 modular_doppler/modular_cosmetics/GAGS/json_configs/heartkin/gauntlets.json create mode 100644 modular_doppler/modular_cosmetics/GAGS/json_configs/heartkin/gauntlets_worn.json create mode 100644 modular_doppler/modular_cosmetics/GAGS/json_configs/heartkin/loincloth.json create mode 100644 modular_doppler/modular_cosmetics/GAGS/json_configs/heartkin/loincloth_alt.json create mode 100644 modular_doppler/modular_cosmetics/GAGS/json_configs/heartkin/loincloth_alt_worn.json create mode 100644 modular_doppler/modular_cosmetics/GAGS/json_configs/heartkin/loincloth_worn.json create mode 100644 modular_doppler/modular_cosmetics/GAGS/json_configs/heartkin/tailored_dress.json create mode 100644 modular_doppler/modular_cosmetics/GAGS/json_configs/heartkin/tailored_dress_worn.json create mode 100644 modular_doppler/modular_cosmetics/GAGS/json_configs/heartkin/tunic.json create mode 100644 modular_doppler/modular_cosmetics/GAGS/json_configs/heartkin/tunic_worn.json diff --git a/modular_doppler/hearthkin/primitive_catgirls/code/clothing.dm b/modular_doppler/hearthkin/primitive_catgirls/code/clothing.dm index 54e99cc5f9888..15e6e8a61451f 100644 --- a/modular_doppler/hearthkin/primitive_catgirls/code/clothing.dm +++ b/modular_doppler/hearthkin/primitive_catgirls/code/clothing.dm @@ -22,8 +22,8 @@ icon = 'modular_doppler/hearthkin/primitive_catgirls/icons/clothing_greyscale.dmi' worn_icon = 'modular_doppler/hearthkin/primitive_catgirls/icons/clothing_greyscale.dmi' body_parts_covered = GROIN - // greyscale_config = /datum/greyscale_config/primitive_catgirl_wraps - // greyscale_config_worn = /datum/greyscale_config/primitive_catgirl_wraps/worn + greyscale_config = /datum/greyscale_config/primitive_catgirl_wraps + greyscale_config_worn = /datum/greyscale_config/primitive_catgirl_wraps/worn greyscale_colors = "#cec8bf#364660" flags_1 = IS_PLAYER_COLORABLE_1 has_sensor = FALSE @@ -35,8 +35,8 @@ icon = 'modular_doppler/hearthkin/primitive_catgirls/icons/clothing_greyscale.dmi' worn_icon = 'modular_doppler/hearthkin/primitive_catgirls/icons/clothing_greyscale.dmi' body_parts_covered = GROIN|CHEST - // greyscale_config = /datum/greyscale_config/primitive_catgirl_tailored_dress - // greyscale_config_worn = /datum/greyscale_config/primitive_catgirl_tailored_dress/worn + greyscale_config = /datum/greyscale_config/primitive_catgirl_tailored_dress + greyscale_config_worn = /datum/greyscale_config/primitive_catgirl_tailored_dress/worn greyscale_colors = "#cec8bf#364660" flags_1 = IS_PLAYER_COLORABLE_1 has_sensor = FALSE @@ -48,12 +48,33 @@ icon = 'modular_doppler/hearthkin/primitive_catgirls/icons/clothing_greyscale.dmi' worn_icon = 'modular_doppler/hearthkin/primitive_catgirls/icons/clothing_greyscale.dmi' body_parts_covered = GROIN|CHEST - // greyscale_config = /datum/greyscale_config/primitive_catgirl_tunic - // greyscale_config_worn = /datum/greyscale_config/primitive_catgirl_tunic/worn + greyscale_config = /datum/greyscale_config/primitive_catgirl_tunic + greyscale_config_worn = /datum/greyscale_config/primitive_catgirl_tunic/worn greyscale_colors = "#cec8bf#faece4#594032" flags_1 = IS_PLAYER_COLORABLE_1 has_sensor = FALSE +/obj/item/clothing/under/dress/skirt/loincloth + name = "loincloth" + desc = "A simple elegant cloth, to use wrapped around your waist and groin." + icon_state = "loincloth" + icon = 'modular_doppler/hearthkin/primitive_catgirls/icons/loincloth.dmi' + worn_icon = 'modular_doppler/hearthkin/primitive_catgirls/icons/loincloth.dmi' + greyscale_config = /datum/greyscale_config/loincloth + greyscale_config_worn = /datum/greyscale_config/loincloth/worn + greyscale_colors = "#413069" + flags_1 = IS_PLAYER_COLORABLE_1 + body_parts_covered = GROIN|LEGS + has_sensor = NO_SENSORS + supports_variations_flags = CLOTHING_DIGITIGRADE_VARIATION_NO_NEW_ICON + +/obj/item/clothing/under/dress/skirt/loincloth/loincloth_alt + name = "shorter loincloth" + desc = "A simple elegant cloth, to use wrapped around your waist and groin. This one uses a shorter cloth." + icon_state = "loincloth_alt" + greyscale_config = /datum/greyscale_config/loincloth_alt + greyscale_config_worn = /datum/greyscale_config/loincloth_alt/worn + // Hands /obj/item/clothing/gloves/fingerless/primitive_catgirl_armwraps @@ -62,8 +83,8 @@ icon_state = "armwraps" icon = 'modular_doppler/hearthkin/primitive_catgirls/icons/clothing_greyscale.dmi' worn_icon = 'modular_doppler/hearthkin/primitive_catgirls/icons/clothing_greyscale.dmi' - // greyscale_config = /datum/greyscale_config/primitive_catgirl_armwraps - // greyscale_config_worn = /datum/greyscale_config/primitive_catgirl_armwraps/worn + greyscale_config = /datum/greyscale_config/primitive_catgirl_armwraps + greyscale_config_worn = /datum/greyscale_config/primitive_catgirl_armwraps/worn greyscale_colors = "#cec8bf" flags_1 = IS_PLAYER_COLORABLE_1 @@ -73,8 +94,8 @@ icon_state = "gauntlets" icon = 'modular_doppler/hearthkin/primitive_catgirls/icons/clothing_greyscale.dmi' worn_icon = 'modular_doppler/hearthkin/primitive_catgirls/icons/clothing_greyscale.dmi' - // greyscale_config = /datum/greyscale_config/primitive_catgirl_gauntlets - // greyscale_config_worn = /datum/greyscale_config/primitive_catgirl_gauntlets/worn + greyscale_config = /datum/greyscale_config/primitive_catgirl_gauntlets + greyscale_config_worn = /datum/greyscale_config/primitive_catgirl_gauntlets/worn greyscale_config_inhand_left = null greyscale_config_inhand_right = null greyscale_colors = "#cec8bf#c55a1d" @@ -92,8 +113,8 @@ cold_protection = CHEST min_cold_protection_temperature = FIRE_SUIT_MIN_TEMP_PROTECT supports_variations_flags = CLOTHING_DIGITIGRADE_VARIATION_NO_NEW_ICON - // greyscale_config = /datum/greyscale_config/primitive_catgirl_coat - // greyscale_config_worn = /datum/greyscale_config/primitive_catgirl_coat/worn + greyscale_config = /datum/greyscale_config/primitive_catgirl_coat + greyscale_config_worn = /datum/greyscale_config/primitive_catgirl_coat/worn greyscale_colors = "#594032#cec8bf" flags_1 = IS_PLAYER_COLORABLE_1 @@ -108,8 +129,8 @@ icon_state = "boots" icon = 'modular_doppler/hearthkin/primitive_catgirls/icons/clothing_greyscale.dmi' worn_icon = 'modular_doppler/hearthkin/primitive_catgirls/icons/clothing_greyscale.dmi' - // greyscale_config = /datum/greyscale_config/primitive_catgirl_boots - // greyscale_config_worn = /datum/greyscale_config/primitive_catgirl_boots/worn + greyscale_config = /datum/greyscale_config/primitive_catgirl_boots + greyscale_config_worn = /datum/greyscale_config/primitive_catgirl_boots/worn greyscale_colors = "#594032#cec8bf" flags_1 = IS_PLAYER_COLORABLE_1 @@ -146,8 +167,8 @@ icon_state = "ferroniere" icon = 'modular_doppler/hearthkin/primitive_catgirls/icons/clothing_greyscale.dmi' worn_icon = 'modular_doppler/hearthkin/primitive_catgirls/icons/clothing_greyscale.dmi' - // greyscale_config = /datum/greyscale_config/primitive_catgirl_ferroniere - // greyscale_config_worn = /datum/greyscale_config/primitive_catgirl_ferroniere/worn + greyscale_config = /datum/greyscale_config/primitive_catgirl_ferroniere + greyscale_config_worn = /datum/greyscale_config/primitive_catgirl_ferroniere/worn greyscale_colors = "#f1f6ff#364660" w_class = WEIGHT_CLASS_TINY flags_1 = IS_PLAYER_COLORABLE_1 @@ -178,3 +199,55 @@ ) result = /obj/item/clothing/suit/armor/forging_plate_armor/hearthkin + +//Pelts +/obj/item/clothing/head/pelt + icon = 'modular_doppler/hearthkin/primitive_catgirls/icons/pelt.dmi' + worn_icon = 'modular_doppler/hearthkin/primitive_catgirls/icons/pelt_worn.dmi' + name = "bear pelt" + desc = "A luxurious bear pelt, good to keep warm in winter. Or to sleep through it." + icon_state = "bearpelt_brown" + inhand_icon_state = "cowboy_hat_brown" + cold_protection = CHEST|HEAD + min_cold_protection_temperature = FIRE_SUIT_MIN_TEMP_PROTECT + +/obj/item/clothing/head/pelt/black + icon_state = "bearpelt_black" + inhand_icon_state = "cowboy_hat_black" + +/obj/item/clothing/head/pelt/white + icon_state = "bearpelt_white" + inhand_icon_state = "cowboy_hat_white" + +/obj/item/clothing/head/pelt/tiger + name = "shiny tiger pelt" + desc = "A vibrant tiger pelt, particularly fabulous." + icon_state = "tigerpelt_shiny" + inhand_icon_state = "cowboy_hat_grey" + +/obj/item/clothing/head/pelt/snow_tiger + name = "snow tiger pelt" + desc = "A pelt of a less vibrant tiger, but rather warm." + icon_state = "tigerpelt_snow" + inhand_icon_state = "cowboy_hat_white" + +/obj/item/clothing/head/pelt/pink_tiger + name = "pink tiger pelt" + desc = "A particularly vibrant tiger pelt, for those who want to be the most fabulous at parties." + icon_state = "tigerpelt_pink" + inhand_icon_state = "cowboy_hat_red" + +/obj/item/clothing/head/pelt/wolf + name = "wolf pelt" + desc = "A fuzzy wolf pelt that demands respect as a hunter... assuming it wasn't just purchased, that is, for all the glory but none of the credit." + worn_icon = 'modular_doppler/hearthkin/primitive_catgirls/icons/pelt_big.dmi' + icon_state = "wolfpelt_brown" + +/obj/item/clothing/head/pelt/wolf/black + icon_state = "wolfpelt_gray" + inhand_icon_state = "cowboy_hat_grey" + +/obj/item/clothing/head/pelt/wolf/white + icon_state = "wolfpelt_white" + inhand_icon_state = "cowboy_hat_white" +//End Pelts diff --git a/modular_doppler/hearthkin/primitive_catgirls/code/clothing_vendor.dm b/modular_doppler/hearthkin/primitive_catgirls/code/clothing_vendor.dm index 57d11862f9e1a..d828f754547f6 100644 --- a/modular_doppler/hearthkin/primitive_catgirls/code/clothing_vendor.dm +++ b/modular_doppler/hearthkin/primitive_catgirls/code/clothing_vendor.dm @@ -13,8 +13,8 @@ /obj/item/clothing/under/dress/skirt/primitive_catgirl_body_wraps = 15, /obj/item/clothing/under/dress/skirt/primitive_catgirl_tailored_dress = 15, /obj/item/clothing/under/dress/skirt/primitive_catgirl_tunic = 15, - // /obj/item/clothing/under/dress/skirt/nova/loincloth = 5, - // /obj/item/clothing/under/dress/skirt/nova/loincloth/loincloth_alt = 5, + /obj/item/clothing/under/dress/skirt/loincloth = 5, + /obj/item/clothing/under/dress/skirt/loincloth/loincloth_alt = 5, /obj/item/clothing/suit/jacket/primitive_catgirl_coat = 15, /obj/item/clothing/gloves/fingerless/primitive_catgirl_armwraps = 15, /obj/item/clothing/shoes/winterboots/ice_boots/primitive_catgirl_boots = 15, @@ -33,12 +33,13 @@ // /obj/item/clothing/neck/long_cape = 5, // /obj/item/clothing/glasses/eyepatch/wrap = 5, /obj/item/clothing/head/primitive_catgirl_ferroniere = 5, - // /obj/item/clothing/head/pelt/snow_tiger = 5, - // /obj/item/clothing/head/pelt = 5, - // /obj/item/clothing/head/pelt/black = 5, - // /obj/item/clothing/head/pelt/white = 5, - // /obj/item/clothing/head/pelt/wolf = 5, - // /obj/item/clothing/head/pelt/wolf/white = 5, + /obj/item/clothing/head/pelt/snow_tiger = 5, + /obj/item/clothing/head/pelt = 5, + /obj/item/clothing/head/pelt/black = 5, + /obj/item/clothing/head/pelt/white = 5, + /obj/item/clothing/head/pelt/wolf = 5, + /obj/item/clothing/head/pelt/wolf/black = 5, + /obj/item/clothing/head/pelt/wolf/white = 5, // /obj/item/clothing/head/costume/nova/papakha = 5, // /obj/item/clothing/head/costume/nova/papakha/white = 5, // /obj/item/clothing/head/hair_tie = 5, diff --git a/modular_doppler/hearthkin/primitive_catgirls/code/greyscale_config.dm b/modular_doppler/hearthkin/primitive_catgirls/code/greyscale_config.dm new file mode 100644 index 0000000000000..9782467fe18f4 --- /dev/null +++ b/modular_doppler/hearthkin/primitive_catgirls/code/greyscale_config.dm @@ -0,0 +1,89 @@ +/datum/greyscale_config/primitive_catgirl_wraps + name = "Primitive Body Wraps" + icon_file = 'modular_doppler/hearthkin/primitive_catgirls/icons/clothing_greyscale.dmi' + json_config = 'modular_doppler/modular_cosmetics/GAGS/json_configs/heartkin/body_wraps.json' + +/datum/greyscale_config/primitive_catgirl_wraps/worn + name = "Primitive Body Wraps (Worn)" + json_config = 'modular_doppler/modular_cosmetics/GAGS/json_configs/heartkin/body_wraps_worn.json' + +/datum/greyscale_config/primitive_catgirl_armwraps + name = "Arm Wraps" + icon_file = 'modular_doppler/hearthkin/primitive_catgirls/icons/clothing_greyscale.dmi' + json_config = 'modular_doppler/modular_cosmetics/GAGS/json_configs/heartkin/armwraps.json' + +/datum/greyscale_config/primitive_catgirl_armwraps/worn + name = "Arm Wraps (Worn)" + json_config = 'modular_doppler/modular_cosmetics/GAGS/json_configs/heartkin/armwraps_worn.json' + +/datum/greyscale_config/primitive_catgirl_coat + name = "Primitive Fur Coat" + icon_file = 'modular_doppler/hearthkin/primitive_catgirls/icons/clothing_greyscale.dmi' + json_config = 'modular_doppler/modular_cosmetics/GAGS/json_configs/heartkin/coat.json' + +/datum/greyscale_config/primitive_catgirl_coat/worn + name = "Primitive Fur Coat (Worn)" + json_config = 'modular_doppler/modular_cosmetics/GAGS/json_configs/heartkin/coat_worn.json' + +/datum/greyscale_config/primitive_catgirl_boots + name = "Primitive Winter Boots" + icon_file = 'modular_doppler/hearthkin/primitive_catgirls/icons/clothing_greyscale.dmi' + json_config = 'modular_doppler/modular_cosmetics/GAGS/json_configs/heartkin/boots.json' + +/datum/greyscale_config/primitive_catgirl_boots/worn + name = "Primitive Winter Boots (Worn)" + json_config = 'modular_doppler/modular_cosmetics/GAGS/json_configs/heartkin/boots_worn.json' + +/datum/greyscale_config/primitive_catgirl_gauntlets + name = "Gauntlets" + icon_file = 'modular_doppler/hearthkin/primitive_catgirls/icons/clothing_greyscale.dmi' + json_config = 'modular_doppler/modular_cosmetics/GAGS/json_configs/heartkin/gauntlets.json' + +/datum/greyscale_config/primitive_catgirl_gauntlets/worn + name = "Gauntlets (Worn)" + json_config = 'modular_doppler/modular_cosmetics/GAGS/json_configs/heartkin/gauntlets_worn.json' + +/datum/greyscale_config/primitive_catgirl_tailored_dress + name = "Tailored Dress" + icon_file = 'modular_doppler/hearthkin/primitive_catgirls/icons/clothing_greyscale.dmi' + json_config = 'modular_doppler/modular_cosmetics/GAGS/json_configs/heartkin/tailored_dress.json' + +/datum/greyscale_config/primitive_catgirl_tailored_dress/worn + name = "Tailored Dress (Worn)" + json_config = 'modular_doppler/modular_cosmetics/GAGS/json_configs/heartkin/tailored_dress_worn.json' + +/datum/greyscale_config/primitive_catgirl_ferroniere + name = "Ferroniere" + icon_file = 'modular_doppler/hearthkin/primitive_catgirls/icons/clothing_greyscale.dmi' + json_config = 'modular_doppler/modular_cosmetics/GAGS/json_configs/heartkin/ferroniere.json' + +/datum/greyscale_config/primitive_catgirl_ferroniere/worn + name = "Ferroniere (Worn)" + json_config = 'modular_doppler/modular_cosmetics/GAGS/json_configs/heartkin/ferroniere_worn.json' + +/datum/greyscale_config/primitive_catgirl_tunic + name = "Handmade Tunic" + icon_file = 'modular_doppler/hearthkin/primitive_catgirls/icons/clothing_greyscale.dmi' + json_config = 'modular_doppler/modular_cosmetics/GAGS/json_configs/heartkin/tunic.json' + +/datum/greyscale_config/primitive_catgirl_tunic/worn + name = "Handmade Tunic (Worn)" + json_config = 'modular_doppler/modular_cosmetics/GAGS/json_configs/heartkin/tunic_worn.json' + +/datum/greyscale_config/loincloth + name = "Loincloth" + icon_file = 'modular_doppler/hearthkin/primitive_catgirls/icons/loincloth.dmi' + json_config = 'modular_doppler/modular_cosmetics/GAGS/json_configs/heartkin/loincloth.json' + +/datum/greyscale_config/loincloth/worn + name = "Loincloth (Worn)" + json_config = 'modular_doppler/modular_cosmetics/GAGS/json_configs/heartkin/loincloth_worn.json' + +/datum/greyscale_config/loincloth_alt + name = "Shorter Loincloth" + icon_file = 'modular_doppler/hearthkin/primitive_catgirls/icons/loincloth.dmi' + json_config = 'modular_doppler/modular_cosmetics/GAGS/json_configs/heartkin/loincloth_alt.json' + +/datum/greyscale_config/loincloth_alt/worn + name = "Shorter Loincloth (Worn)" + json_config = 'modular_doppler/modular_cosmetics/GAGS/json_configs/heartkin/loincloth_alt_worn.json' diff --git a/modular_doppler/hearthkin/primitive_catgirls/icons/loincloth.dmi b/modular_doppler/hearthkin/primitive_catgirls/icons/loincloth.dmi new file mode 100644 index 0000000000000000000000000000000000000000..a409593f875d5292d2482f005c3b356901b585fc GIT binary patch literal 409 zcmV;K0cQS*P)>3hz5njy)!Xa;|NkBw9G$Jvxy0Uxcx|Ygke`r( zx+G%fVv*lGatjIze|ogZ#J%^p#hQkCz_z#KF@X8S`GJa~iFtC9 zkBxF)R(5f3TS-A(SXM_vLNhTjm5hFsjHeM08Wa>3TxEH0dXm+YvmF2c00DGTPE!Ct z=GbNc0069dR9JLGWpiV4X>fFDZ*Bkpc$}5dy$ZrG5C`x%d5X~P;@9dTEz-fhf~5AE z9JWbG4ufxRu@Ib$+3wH%hWjYRxxO^5sICovg7avNIEmwC%UQsl^b!tx&NQIXv<6R- zU?~ei1#X6sZeF8#6`b|x{Lya^gl1g*E&H z7+~XI92*-X1uZxU#t57RN$lF@{a-4ldj?}hJ@!R%kyNQE6;tl2^Kp8*2MGs36;=G7 zLMeA~9<{n%)N5kC(X@+ZL)QPPrR<_D5jr(XsMmBy$afo-&}{U&5}@C1wbU1-TCJ80 z&@~|H^&0d=K(7Hrv)O>Y2ngCO^>gbBu6AF{gK$x+;}Q)p;g?1emu!G63;(r-l{dzqV3uFm5wHu#46S|GAUq5K8tE;Q)Yt{AwZYVwg z*zf^HR}8owdGh+kgb&dB1TY#I!e}Jd2o1#gXeBX^24Z=%l9*R&G++Q09(`k>RuchD z>VF0_L_oW()SwSQf6$h;8AE^$fuuyMEs-lBNMWb`c1! zg&q&siBPhj`h8=72}-#ZP6iCYZPoV%h)`yd2@3jxB${Ti&Bk-LjZV1 zvo>@AAiM(z)7zEM6As-lW2s;J_h#CT#Cld+f&Lw9i=pFLkh zV@sHf<4Dr~Z5rA|A`#TrnSH+aIu{91JO*Mi8AD$JB*}DopM>|*X(9sV^Vv+zm72}w zGJpubk0-c910YQA|ClBru0+hwXX?+{oUXZ;527fBi8z)GkcGwK;o%|l0_Mx*!X!q0}De~EaVzt3s`@-lxqb2*Z{^NAPg-a45w0FDGNZSN_h+cItcpI zO2Q~(2n=DdNTz}X41pmmm-CrqfjX2oftodr%K%g;B?IXq#I%(GsL+NCY?ey&5YqtL zE&`&IM}<-btkZNMOaeath5=8T%~F_zmbpjs;GZ@1gz8We&HHe9t{uyc3c2yu2v_43qaxD^vOf&|s-?Q53xc2-BRB z0bUt`o8OQDUKv6O07MX2c_B#%`OhcBC;2L>sG^E0{+;;Cd3WQR^X|sPc`xa2?P4nv zzU}N{CllVDTjcvH=x*J`dF*!X;ym8&rli{{ip&acGZ~Ou;ax5RVkaiKkceUX2M ziSLC6fSb-AF!3Yu0fJ5j51ID-iw1-o9`d4)^+AXuegO07(~qyuczOTBvELUjc>*qfte;DS)gi(yGwa790WGxEY(QsQVV}`L zyMhfA`A*npw9q(W15rE{_8FR(VOt^)+&nZf!?r{qxOr$|hHZ&JDCuWpzz{O>;2cN0 zoD3L3P9B`&2v5K;U;EWLSBUo(bfPZi*o!MI33NgVgA)TeRLQE* z3FSN?g3OMw{C$8=ZO2&tKES6Ybv9JRe<}V3Qj`9`ZOj|O00000NkvXXu0mjf=?q1i literal 0 HcmV?d00001 diff --git a/modular_doppler/hearthkin/primitive_catgirls/icons/pelt_big.dmi b/modular_doppler/hearthkin/primitive_catgirls/icons/pelt_big.dmi new file mode 100644 index 0000000000000000000000000000000000000000..53c897995a49c229e458790fb530df7823fec704 GIT binary patch literal 2686 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 Date: Tue, 3 Sep 2024 11:24:45 -0300 Subject: [PATCH 14/28] Check needed for hearthkin so loadout clothes and accesories are not loaded --- code/modules/mob_spawn/mob_spawn.dm | 15 ++++++++++++--- .../hearthkin/primitive_catgirls/code/spawner.dm | 1 + 2 files changed, 13 insertions(+), 3 deletions(-) diff --git a/code/modules/mob_spawn/mob_spawn.dm b/code/modules/mob_spawn/mob_spawn.dm index 4af39c20d148a..6a47eb5a7f17b 100644 --- a/code/modules/mob_spawn/mob_spawn.dm +++ b/code/modules/mob_spawn/mob_spawn.dm @@ -34,6 +34,8 @@ var/datum/weakref/spawned_mob_ref /// DOPPLER SHIFT ADDITION: allowing players to have their current character loaded var/allow_prefs = TRUE + /// DOPPLER SHIFT ADDITION: allowing players to have their current loadout and clothes loaded + var/allow_loadout = TRUE /obj/effect/mob_spawn/Initialize(mapload) . = ..() @@ -100,14 +102,18 @@ if(allow_prefs && spawned_human.client) spawned_human.client?.prefs.safe_transfer_prefs_to(spawned_human) SSquirks.AssignQuirks(spawned_human, spawned_human.client) - spawned_human.equip_outfit_and_loadout(outfit, spawned_human.client?.prefs) + if(allow_loadout) + spawned_human.equip_outfit_and_loadout(outfit, spawned_human.client?.prefs) + else + spawned_human.equipOutfit(outfit) else spawned_human.equipOutfit(outfit) else if(allow_prefs && spawned_mob.client) var/mob/living/carbon/human/spawned_human = spawned_mob spawned_human.client?.prefs.safe_transfer_prefs_to(spawned_human) SSquirks.AssignQuirks(spawned_human, spawned_human.client) - spawned_human.equip_outfit_and_loadout(new /datum/outfit(), spawned_human.client?.prefs) + if(allow_loadout) + spawned_human.equip_outfit_and_loadout(new /datum/outfit(), spawned_human.client?.prefs) /// DOPPLER SHIFT ADDITION END ///these mob spawn subtypes do not trigger until attacked by a ghost. @@ -178,7 +184,10 @@ prompt += " (Warning, You can no longer be revived!)" /// DOPPLER SHIFT ADDITION BEGIN if(allow_prefs) - prompt += "\nYou will be loaded in with your current character, [realname] - loadout & quirks included! Make sure they fit the role!" + prompt += "\nYou will be loaded in with your current character, [realname] -" + if(allow_loadout) + prompt += " loadout &" + prompt += " quirks included! Make sure they fit the role!" /// DOPPLER SHIFT ADDITION END var/ghost_role = tgui_alert(usr, prompt, buttons = list("Yes", "No"), timeout = 10 SECONDS) if(ghost_role != "Yes" || !loc || QDELETED(user)) diff --git a/modular_doppler/hearthkin/primitive_catgirls/code/spawner.dm b/modular_doppler/hearthkin/primitive_catgirls/code/spawner.dm index 53cfa3f244280..dc891746e46cc 100644 --- a/modular_doppler/hearthkin/primitive_catgirls/code/spawner.dm +++ b/modular_doppler/hearthkin/primitive_catgirls/code/spawner.dm @@ -15,6 +15,7 @@ being reckless with the outsiders will not have the Gods be so kind." spawner_job_path = /datum/job/primitive_catgirl interaction_flags_mouse_drop = NEED_DEXTERITY + allow_loadout = FALSE /// The team the spawner will assign players to and use to keep track of people that have already used the spawner var/datum/team/primitive_catgirls/team From 9db4d2d1988ac33ef50b365b33522af62382ddce Mon Sep 17 00:00:00 2001 From: Kaostico Date: Tue, 3 Sep 2024 14:00:33 -0300 Subject: [PATCH 15/28] modular_crafting with crafting_extended and added recipes. moved the is_helpers to defines. --- .../~doppler_defines}/is_helpers.dm | 0 code/__HELPERS/global_lists.dm | 1 + .../~doppler_helpers/global_lists.dm | 29 ++++ .../code/crafting_extended.dm | 0 .../modular_crafting/code/sheet_types.dm | 143 ++++++++++++++++++ 5 files changed, 173 insertions(+) rename code/{__HELPERS/~doppler_helpers => __DEFINES/~doppler_defines}/is_helpers.dm (100%) create mode 100644 code/__HELPERS/~doppler_helpers/global_lists.dm rename modular_doppler/{crafting_extended => modular_crafting}/code/crafting_extended.dm (100%) create mode 100644 modular_doppler/modular_crafting/code/sheet_types.dm diff --git a/code/__HELPERS/~doppler_helpers/is_helpers.dm b/code/__DEFINES/~doppler_defines/is_helpers.dm similarity index 100% rename from code/__HELPERS/~doppler_helpers/is_helpers.dm rename to code/__DEFINES/~doppler_defines/is_helpers.dm diff --git a/code/__HELPERS/global_lists.dm b/code/__HELPERS/global_lists.dm index 1bacd0ce2c774..8d49d79c240d2 100644 --- a/code/__HELPERS/global_lists.dm +++ b/code/__HELPERS/global_lists.dm @@ -15,6 +15,7 @@ // I tried to eliminate this proc but I couldn't untangle their init-order interdependencies -Dominion/Cyberboss init_keybindings() GLOB.emote_list = init_emote_list() // WHY DOES THIS NEED TO GO HERE? IT JUST INITS DATUMS + init_doppler_stack_recipes() //DOPPLER EDIT ADDITION - MODULAR CRAFTING init_crafting_recipes() init_crafting_recipes_atoms() diff --git a/code/__HELPERS/~doppler_helpers/global_lists.dm b/code/__HELPERS/~doppler_helpers/global_lists.dm new file mode 100644 index 0000000000000..5691430eecd6d --- /dev/null +++ b/code/__HELPERS/~doppler_helpers/global_lists.dm @@ -0,0 +1,29 @@ +/proc/init_doppler_stack_recipes() + var/list/additional_stack_recipes = list( + /obj/item/stack/sheet/leather = list(GLOB.doppler_leather_recipes, GLOB.doppler_leather_belt_recipes), + /obj/item/stack/sheet/iron = list(GLOB.doppler_metal_recipes), + /obj/item/stack/sheet/plasteel = list(GLOB.doppler_plasteel_recipes), + /obj/item/stack/sheet/mineral/wood = list(GLOB.doppler_wood_recipes), + /obj/item/stack/sheet/cloth = list(GLOB.doppler_cloth_recipes), + /obj/item/stack/ore/glass = list(GLOB.doppler_sand_recipes), + /obj/item/stack/rods = list(GLOB.doppler_rod_recipes), + /obj/item/stack/sheet/mineral/stone = list(GLOB.stone_recipes), + /obj/item/stack/sheet/mineral/clay = list(GLOB.clay_recipes), + ) + for(var/stack in additional_stack_recipes) + for(var/material_list in additional_stack_recipes[stack]) + for(var/stack_recipe in material_list) + if(istype(stack_recipe, /datum/stack_recipe_list)) + var/datum/stack_recipe_list/stack_recipe_list = stack_recipe + for(var/nested_recipe in stack_recipe_list.recipes) + if(!nested_recipe) + continue + var/datum/crafting_recipe/stack/recipe = new/datum/crafting_recipe/stack(stack, nested_recipe) + if(recipe.name != "" && recipe.result) + GLOB.crafting_recipes += recipe + else + if(!stack_recipe) + continue + var/datum/crafting_recipe/stack/recipe = new/datum/crafting_recipe/stack(stack, stack_recipe) + if(recipe.name != "" && recipe.result) + GLOB.crafting_recipes += recipe diff --git a/modular_doppler/crafting_extended/code/crafting_extended.dm b/modular_doppler/modular_crafting/code/crafting_extended.dm similarity index 100% rename from modular_doppler/crafting_extended/code/crafting_extended.dm rename to modular_doppler/modular_crafting/code/crafting_extended.dm diff --git a/modular_doppler/modular_crafting/code/sheet_types.dm b/modular_doppler/modular_crafting/code/sheet_types.dm new file mode 100644 index 0000000000000..f9e2ef3710918 --- /dev/null +++ b/modular_doppler/modular_crafting/code/sheet_types.dm @@ -0,0 +1,143 @@ +// Add modular crafting recipes here, NOT IN BASE /tg/ CRAFTING LISTS + +/** + * Add a list of recipes to an existing recipe sublist. + * + * Arguments: + * * stack_recipes - the existing list of stack recipes. + * * recipe_list_title - the title for the recipe list we're adding to + * * appent_recipes - Add these recipes to the given recipe list. + */ +/proc/add_recipes_to_sublist(list/stack_recipes, recipe_list_title, list/append_recipes) + for(var/datum/stack_recipe_list/sublist in stack_recipes) + if(sublist.title != recipe_list_title) + continue + + sublist.recipes += append_recipes + return + + CRASH("Could not find recipe sublist [recipe_list_title] to add more recipes!") + +// Iron + +GLOBAL_LIST_INIT(doppler_metal_recipes, list( + new/datum/stack_recipe("anvil", /obj/structure/reagent_anvil, 10, time = 2 SECONDS, crafting_flags = CRAFT_CHECK_DENSITY | CRAFT_ONE_PER_TURF | CRAFT_ON_SOLID_GROUND, category = CAT_TOOLS), + new/datum/stack_recipe("forge", /obj/structure/reagent_forge, 10, time = 2 SECONDS, crafting_flags = CRAFT_CHECK_DENSITY | CRAFT_ONE_PER_TURF | CRAFT_ON_SOLID_GROUND, category = CAT_TOOLS), + new/datum/stack_recipe("throwing wheel", /obj/structure/throwing_wheel, 10, time = 2 SECONDS, crafting_flags = CRAFT_CHECK_DENSITY | CRAFT_ONE_PER_TURF | CRAFT_ON_SOLID_GROUND, category = CAT_TOOLS), +)) + +GLOBAL_LIST_INIT(doppler_metal_airlock_recipes, list( +)) + +/obj/item/stack/sheet/iron/get_main_recipes() + . = ..() + . += GLOB.doppler_metal_recipes + add_recipes_to_sublist(., "airlock assemblies", GLOB.doppler_metal_airlock_recipes) + +// Plasteel + +GLOBAL_LIST_INIT(doppler_plasteel_recipes, list( +)) + +/obj/item/stack/sheet/plasteel/get_main_recipes() + . = ..() + . += GLOB.doppler_plasteel_recipes + +// Rods + +GLOBAL_LIST_INIT(doppler_rod_recipes, list( + new/datum/stack_recipe("crutch", /obj/item/cane/crutch, 3, time = 1 SECONDS, category = CAT_TOOLS), + new/datum/stack_recipe("torch mount", /obj/item/wallframe/torch_mount, 2, category = CAT_MISC), +)) + +/obj/item/stack/rods/get_main_recipes() + . = ..() + . += GLOB.doppler_rod_recipes + +// Wood + +GLOBAL_LIST_INIT(doppler_wood_recipes, list( + new/datum/stack_recipe("water basin", /obj/structure/reagent_water_basin, 5, time = 2 SECONDS, crafting_flags = CRAFT_CHECK_DENSITY | CRAFT_ONE_PER_TURF | CRAFT_ON_SOLID_GROUND, category = CAT_TOOLS), + new/datum/stack_recipe("forging work bench", /obj/structure/reagent_crafting_bench, 5, time = 2 SECONDS, crafting_flags = CRAFT_CHECK_DENSITY | CRAFT_ONE_PER_TURF | CRAFT_ON_SOLID_GROUND, category = CAT_TOOLS), + new/datum/stack_recipe("large wooden mortar", /obj/structure/large_mortar, 10, time = 3 SECONDS, crafting_flags = CRAFT_CHECK_DENSITY | CRAFT_ONE_PER_TURF | CRAFT_ON_SOLID_GROUND, category = CAT_TOOLS), + new/datum/stack_recipe("wooden cutting board", /obj/item/cutting_board, 5, time = 2 SECONDS, category = CAT_TOOLS), + new/datum/stack_recipe("wooden shelf", /obj/structure/rack/wooden, 2, time = 2 SECONDS, crafting_flags = CRAFT_CHECK_DENSITY | CRAFT_ONE_PER_TURF | CRAFT_ON_SOLID_GROUND, category = CAT_STRUCTURE), + new/datum/stack_recipe("seed shelf", /obj/machinery/smartfridge/wooden/seed_shelf, 10, time = 2 SECONDS, crafting_flags = CRAFT_CHECK_DENSITY | CRAFT_ONE_PER_TURF | CRAFT_ON_SOLID_GROUND, category = CAT_STRUCTURE), + new/datum/stack_recipe("produce bin", /obj/machinery/smartfridge/wooden/produce_bin, 10, time = 2 SECONDS, crafting_flags = CRAFT_CHECK_DENSITY | CRAFT_ONE_PER_TURF | CRAFT_ON_SOLID_GROUND, category = CAT_STRUCTURE), + new/datum/stack_recipe("produce display", /obj/machinery/smartfridge/wooden/produce_display, 10, time = 2 SECONDS, crafting_flags = CRAFT_ONE_PER_TURF | CRAFT_ON_SOLID_GROUND, category = CAT_STRUCTURE), + new/datum/stack_recipe("ration shelf", /obj/machinery/smartfridge/wooden/ration_shelf, 10, time = 2 SECONDS, crafting_flags = CRAFT_CHECK_DENSITY | CRAFT_ONE_PER_TURF | CRAFT_ON_SOLID_GROUND, category = CAT_STRUCTURE), + new/datum/stack_recipe("storage barrel", /obj/structure/closet/crate/wooden/storage_barrel, 4, time = 2 SECONDS, crafting_flags = CRAFT_CHECK_DENSITY | CRAFT_ONE_PER_TURF | CRAFT_ON_SOLID_GROUND, category = CAT_STRUCTURE), + new/datum/stack_recipe("worm barrel", /obj/structure/wormfarm, 5, time = 2 SECONDS, crafting_flags = CRAFT_CHECK_DENSITY | CRAFT_ONE_PER_TURF | CRAFT_ON_SOLID_GROUND, category = CAT_TOOLS), + new/datum/stack_recipe("gutlunch trough", /obj/structure/ore_container/food_trough/gutlunch_trough, 5, time = 2 SECONDS, crafting_flags = CRAFT_CHECK_DENSITY | CRAFT_ONE_PER_TURF | CRAFT_ON_SOLID_GROUND, category = CAT_STRUCTURE), + new/datum/stack_recipe("sturdy wooden fence", /obj/structure/railing/wooden_fencing, 5, time = 2 SECONDS, crafting_flags = CRAFT_CHECK_DENSITY | CRAFT_ONE_PER_TURF | CRAFT_ON_SOLID_GROUND, category = CAT_STRUCTURE), + new/datum/stack_recipe("sturdy wooden fence gate", /obj/structure/railing/wooden_fencing/gate, 5, time = 2 SECONDS, crafting_flags = CRAFT_CHECK_DENSITY | CRAFT_ONE_PER_TURF | CRAFT_ON_SOLID_GROUND, category = CAT_STRUCTURE), + new/datum/stack_recipe("large wooden gate", /obj/structure/mineral_door/wood/large_gate, 10, time = 5 SECONDS, crafting_flags = CRAFT_CHECK_DENSITY | CRAFT_ONE_PER_TURF | CRAFT_ON_SOLID_GROUND, category = CAT_STRUCTURE), + new/datum/stack_recipe("wooden bowl", /obj/item/reagent_containers/cup/bowl/wood_bowl, 3, time = 2 SECONDS, category = CAT_TOOLS), +)) + + +/obj/item/stack/sheet/mineral/wood/get_main_recipes() + . = ..() + . += GLOB.doppler_wood_recipes + +// Cardboard + +GLOBAL_LIST_INIT(doppler_cardboard_recipes, list( +)) + +/obj/item/stack/sheet/cardboard/get_main_recipes() + . = ..() + . += GLOB.doppler_cardboard_recipes + +// Cloth + +GLOBAL_LIST_INIT(doppler_cloth_recipes, list( + new/datum/stack_recipe("eyepatch", /obj/item/clothing/glasses/eyepatch, 2, category = CAT_CLOTHING), + new/datum/stack_recipe("xenoarch bag", /obj/item/storage/bag/xenoarch, 4, category = CAT_CONTAINERS), +)) + +/obj/item/stack/sheet/cloth/get_main_recipes() + . = ..() + . += GLOB.doppler_cloth_recipes + +// Leather + +GLOBAL_LIST_INIT(doppler_leather_recipes, list( +)) + +GLOBAL_LIST_INIT(doppler_leather_belt_recipes, list( + new/datum/stack_recipe("xenoarch belt", /obj/item/storage/belt/utility/xenoarch, 4, category = CAT_CONTAINERS), +)) + +/obj/item/stack/sheet/leather/get_main_recipes() + . = ..() + . += GLOB.doppler_leather_recipes + add_recipes_to_sublist(., "belts", GLOB.doppler_leather_belt_recipes) + +// Titanium + +GLOBAL_LIST_INIT(doppler_titanium_recipes, list( +)) + +/obj/item/stack/sheet/mineral/titanium/get_main_recipes() + . = ..() + . += GLOB.doppler_titanium_recipes + +// Snow + +GLOBAL_LIST_INIT(doppler_snow_recipes, list( +)) + +/obj/item/stack/sheet/mineral/snow/get_main_recipes() + . = ..() + . += GLOB.doppler_snow_recipes + +// Sand + +GLOBAL_LIST_INIT(doppler_sand_recipes, list( + new/datum/stack_recipe("ant farm", /obj/structure/antfarm, 20, time = 2 SECONDS, crafting_flags = CRAFT_CHECK_DENSITY | CRAFT_ONE_PER_TURF | CRAFT_ON_SOLID_GROUND, category = CAT_TOOLS), +)) + +/obj/item/stack/ore/glass/get_main_recipes() + . = ..() + . += GLOB.doppler_sand_recipes From 38ec5b0cbee1a2cc2f282280b0cd9c62f293ca0e Mon Sep 17 00:00:00 2001 From: Kaostico Date: Tue, 3 Sep 2024 19:52:29 -0300 Subject: [PATCH 16/28] Reworked modular mob spawn so it actually restricts species on restricted_species. Added the tgstation.dme from the last commit I forgor --- .../primitive_catgirls/code/spawner.dm | 3 - .../primitive_catgirls/code/species.dm | 3 +- .../modular_mob_spawn/code/mob_spawn.dm | 88 +++---------------- tgstation.dme | 6 +- 4 files changed, 17 insertions(+), 83 deletions(-) diff --git a/modular_doppler/hearthkin/primitive_catgirls/code/spawner.dm b/modular_doppler/hearthkin/primitive_catgirls/code/spawner.dm index dc891746e46cc..d10dfa45615c9 100644 --- a/modular_doppler/hearthkin/primitive_catgirls/code/spawner.dm +++ b/modular_doppler/hearthkin/primitive_catgirls/code/spawner.dm @@ -21,9 +21,6 @@ var/datum/team/primitive_catgirls/team restricted_species = list(/datum/species/human/felinid/primitive) - quirks_enabled = TRUE - random_appearance = FALSE - loadout_enabled = FALSE infinite_use = TRUE deletes_on_zero_uses_left = FALSE diff --git a/modular_doppler/hearthkin/primitive_catgirls/code/species.dm b/modular_doppler/hearthkin/primitive_catgirls/code/species.dm index edcbc0b1ae0cd..577d5adb6cc47 100644 --- a/modular_doppler/hearthkin/primitive_catgirls/code/species.dm +++ b/modular_doppler/hearthkin/primitive_catgirls/code/species.dm @@ -22,6 +22,7 @@ species_language_holder = /datum/language_holder/primitive_felinid // language_prefs_whitelist = list(/datum/language/primitive_catgirl) //this needs a dedicated module for language + // always_customizable = TRUE //this needs a dedicated module for species customization bodytemp_normal = 270 // If a normal human gets hugged by one it's gonna feel cold bodytemp_heat_damage_limit = 283 // To them normal station atmos would be sweltering @@ -34,8 +35,6 @@ TRAIT_USES_SKINTONES, ) - // always_customizable = TRUE //this needs a dedicated module for species customization - /datum/species/human/felinid/primitive/on_species_gain(mob/living/carbon/new_primitive, datum/species/old_species, pref_load) . = ..() var/mob/living/carbon/human/hearthkin = new_primitive diff --git a/modular_doppler/modular_mob_spawn/code/mob_spawn.dm b/modular_doppler/modular_mob_spawn/code/mob_spawn.dm index ba8a290d49f72..2d03b49a52953 100644 --- a/modular_doppler/modular_mob_spawn/code/mob_spawn.dm +++ b/modular_doppler/modular_mob_spawn/code/mob_spawn.dm @@ -1,80 +1,16 @@ -/obj/effect/mob_spawn - /// Do we use a random appearance for this role? - var/random_appearance = TRUE - /obj/effect/mob_spawn/ghost_role - /// set this to make the spawner use the outfit.name instead of its name var for things like cryo announcements and ghost records - /// modifying the actual name during the game will cause issues with the GLOB.mob_spawners associative list - var/use_outfit_name - /// Can we use our loadout for this role? - var/loadout_enabled = FALSE - /// Can we use our quirks for this role? - var/quirks_enabled = FALSE /// Are we limited to a certain species type? LISTED TYPE - var/restricted_species + var/list/restricted_species = list() /obj/effect/mob_spawn/ghost_role/create(mob/mob_possessor, newname) - var/load_prefs = FALSE - //if we can load our own appearance and it's not restricted, try - if(!random_appearance && mob_possessor?.client) - //if we have gotten to this point, they have already waived their species pref.-- they were told they need to use the specific species already - if((restricted_species && (mob_possessor?.client?.prefs?.read_preference(/datum/preference/choiced/species) in restricted_species)) || !restricted_species) - var/appearance_choice = tgui_alert(mob_possessor, "Use currently loaded character preferences?", "Appearance Type", list("Yes", "No")) - if(appearance_choice == "Yes") - load_prefs = TRUE - - var/mob/living/spawned_mob = ..(mob_possessor, newname, load_prefs) - - var/mob/living/carbon/human/spawned_human - if (istype(spawned_mob, /mob/living/carbon/human)) - spawned_human = spawned_mob - - if(!load_prefs) - var/datum/language_holder/holder = spawned_human.get_language_holder() - holder.get_selected_language() //we need this here so a language starts off selected - - return spawned_human - - spawned_human?.client?.prefs?.safe_transfer_prefs_to(spawned_human) - spawned_human.dna.update_dna_identity() - if(spawned_human.mind) - spawned_human.mind.name = spawned_human.real_name // the mind gets initialized with the random name given as a result of the parent create() so we need to readjust it - spawned_human.dna.species.give_important_for_life(spawned_human) // make sure they get plasmaman/vox internals etc before anything else - - if(quirks_enabled) - SSquirks.AssignQuirks(spawned_human, spawned_human.client) - - post_transfer_prefs(spawned_human) - - if(load_prefs && loadout_enabled) - spawned_human?.equip_outfit_and_loadout(outfit, spawned_mob.client.prefs) - else if (!isnull(spawned_human)) - equip(spawned_human) - - return spawned_mob - -/// This edit would cause somewhat ugly diffs, so I'm just replacing it. -/// Original proc in code/modules/mob_spawn/mob_spawn.dm ~line 39. -/obj/effect/mob_spawn/create(mob/mob_possessor, newname, is_pref_loaded) - var/mob/living/spawned_mob = new mob_type(get_turf(src)) //living mobs only - name_mob(spawned_mob, newname) - special(spawned_mob, mob_possessor) - if(!is_pref_loaded) - equip(spawned_mob) - return spawned_mob - -// Anything that can potentially be overwritten by transferring prefs must go in this proc -// This is needed because safe_transfer_prefs_to() can override some things that get set in special() for certain roles, like name replacement -// In those cases, please override this proc as well as special() -// TODO: refactor create() and special() so that this is no longer necessary -/obj/effect/mob_spawn/ghost_role/proc/post_transfer_prefs(mob/living/new_spawn) - return - - -/obj/effect/mob_spawn/ghost_role/human/special(mob/living/spawned_mob, mob/mob_possessor) - . = ..() - var/mob/living/carbon/human/spawned_human = spawned_mob - var/datum/job/spawned_job = SSjob.GetJobType(spawner_job_path) - - spawned_human.job = spawned_job.title - + if((restricted_species && !(mob_possessor?.client?.prefs?.read_preference(/datum/preference/choiced/species) in restricted_species))) + var/text = "Current loaded character doesn't match required species: " + var/i = 1 + for(var/datum/species/speciesItem as anything in restricted_species) + text += "[speciesItem.name]" + if(i < restricted_species.len) + text += ", " + i++ + tgui_alert(mob_possessor, text) + return FALSE + return ..() diff --git a/tgstation.dme b/tgstation.dme index c08c064259bd2..2edb9a8b3370e 100644 --- a/tgstation.dme +++ b/tgstation.dme @@ -396,6 +396,7 @@ #include "code\__DEFINES\traits\macros.dm" #include "code\__DEFINES\traits\sources.dm" #include "code\__DEFINES\~doppler_defines\DNA.dm" +#include "code\__DEFINES\~doppler_defines\is_helpers.dm" #include "code\__DEFINES\~doppler_defines\keybinds.dm" #include "code\__DEFINES\~doppler_defines\obj_flags_doppler.dm" #include "code\__DEFINES\~doppler_defines\reagent_forging_tools.dm" @@ -519,7 +520,7 @@ #include "code\__HELPERS\paths\sssp.dm" #include "code\__HELPERS\sorts\helpers.dm" #include "code\__HELPERS\sorts\sort_instance.dm" -#include "code\__HELPERS\~doppler_helpers\is_helpers.dm" +#include "code\__HELPERS\~doppler_helpers\global_lists.dm" #include "code\_globalvars\_regexes.dm" #include "code\_globalvars\admin.dm" #include "code\_globalvars\arcade.dm" @@ -6371,7 +6372,6 @@ #include "interface\fonts\tiny_unicode.dm" #include "interface\fonts\vcr_osd_mono.dm" #include "modular_doppler\advanced_reskin\code\advanced_reskin.dm" -#include "modular_doppler\crafting_extended\code\crafting_extended.dm" #include "modular_doppler\cryosleep\code\admin.dm" #include "modular_doppler\cryosleep\code\ai.dm" #include "modular_doppler\cryosleep\code\config.dm" @@ -6437,6 +6437,8 @@ #include "modular_doppler\modular_cosmetics\code\neck\collar.dm" #include "modular_doppler\modular_cosmetics\code\suits\jacket.dm" #include "modular_doppler\modular_cosmetics\GAGS\greyscale_configs_neck.dm" +#include "modular_doppler\modular_crafting\code\crafting_extended.dm" +#include "modular_doppler\modular_crafting\code\sheet_types.dm" #include "modular_doppler\modular_mob_spawn\code\mob_spawn.dm" #include "modular_doppler\modular_persistence\code\modular_persistence.dm" #include "modular_doppler\modular_sounds\code\sounds.dm" From f48223b5d7c1ef15ffc797273be19c6224b4ea45 Mon Sep 17 00:00:00 2001 From: Kaostico Date: Tue, 3 Sep 2024 20:20:40 -0300 Subject: [PATCH 17/28] Commented out the clothes for the next batch --- .../primitive_catgirls/code/clothing_vendor.dm | 10 +++++----- 1 file changed, 5 insertions(+), 5 deletions(-) diff --git a/modular_doppler/hearthkin/primitive_catgirls/code/clothing_vendor.dm b/modular_doppler/hearthkin/primitive_catgirls/code/clothing_vendor.dm index d828f754547f6..04fe22a194a53 100644 --- a/modular_doppler/hearthkin/primitive_catgirls/code/clothing_vendor.dm +++ b/modular_doppler/hearthkin/primitive_catgirls/code/clothing_vendor.dm @@ -19,15 +19,15 @@ /obj/item/clothing/gloves/fingerless/primitive_catgirl_armwraps = 15, /obj/item/clothing/shoes/winterboots/ice_boots/primitive_catgirl_boots = 15, /obj/item/clothing/gloves/fingerless/primitive_catgirl_gauntlets = 10, - /obj/item/clothing/mask/neck_gaiter/primitive_catgirl_gaiter = 10, - /obj/item/clothing/suit/apron/chef/colorable_apron/primitive_catgirl_leather = 10, - /obj/item/clothing/head/standalone_hood/primitive_catgirl_colors = 10, + // /obj/item/clothing/mask/neck_gaiter/primitive_catgirl_gaiter = 10, + // /obj/item/clothing/suit/apron/chef/colorable_apron/primitive_catgirl_leather = 10, + // /obj/item/clothing/head/standalone_hood/primitive_catgirl_colors = 10, /obj/item/clothing/neck/scarf/primitive_catgirl_scarf = 5, // /obj/item/clothing/neck/face_scarf = 5, /obj/item/clothing/neck/large_scarf/primitive_catgirl_off_white = 5, /obj/item/clothing/neck/infinity_scarf/primitive_catgirl_blue = 5, - /obj/item/clothing/neck/mantle/recolorable/primitive_catgirl_off_white = 5, - /obj/item/clothing/neck/ranger_poncho/primitive_catgirl_leather = 5, + // /obj/item/clothing/neck/mantle/recolorable/primitive_catgirl_off_white = 5, + // /obj/item/clothing/neck/ranger_poncho/primitive_catgirl_leather = 5, // /obj/item/clothing/neck/wide_cape = 5, // /obj/item/clothing/neck/robe_cape = 5, // /obj/item/clothing/neck/long_cape = 5, From 64ce917132587d632e0b9bd3e06e928a23e001d9 Mon Sep 17 00:00:00 2001 From: Kaostico Date: Wed, 4 Sep 2024 00:53:49 -0300 Subject: [PATCH 18/28] last touches to finish this behemoth (IMSOSORRYNAAKA) --- code/game/atom/atom_tool_acts.dm | 2 +- modular_doppler/advanced_reskin/readme.md | 25 ++++ modular_doppler/cryosleep/code/cryopod.dm | 4 - modular_doppler/cryosleep/readme.md | 4 +- .../code/greyscale_config.dm | 40 ++--- .../hearthkin/primitive_catgirls/readme.md | 29 ++++ .../code/big_mortar.dm | 33 +++-- .../primitive_cooking_additions/readme.md | 13 +- .../hearthkin/primitive_production/readme.md | 15 +- .../primitive_structures/code/furniture.dm | 2 +- .../hearthkin/primitive_structures/readme.md | 15 +- modular_doppler/hearthkin/readme.md | 33 +++++ .../code/ammo/caseless/arrow.dm | 6 +- .../code/ammo/reusable/arrow.dm | 0 .../tribal_extended/code/crafting.dm | 6 +- .../tribal_extended/code/recipes.dm | 0 .../tribal_extended/code/weapons/bow.dm | 12 +- .../tribal_extended/code/weapons/shield.dm | 8 +- .../tribal_extended/code/weapons/sword.dm | 8 +- .../tribal_extended/icons/ammo.dmi | Bin .../tribal_extended/icons/back.dmi | Bin .../tribal_extended/icons/belt.dmi | Bin .../tribal_extended/icons/bows_lefthand.dmi | Bin .../tribal_extended/icons/bows_righthand.dmi | Bin .../tribal_extended/icons/crafting.dmi | Bin .../tribal_extended/icons/dice.dmi | Bin .../icons/items_and_weapons.dmi | Bin .../tribal_extended/icons/projectile.dmi | Bin .../tribal_extended/icons/shields.dmi | Bin .../icons/shields_lefthand.dmi | Bin .../icons/shields_righthand.dmi | Bin .../tribal_extended/icons/swords_lefthand.dmi | Bin .../icons/swords_righthand.dmi | Bin .../hearthkin/tribal_extended/readme.md | 25 ++++ .../sound/sound_weapons_bowdraw.ogg | Bin .../sound/sound_weapons_bowfire.ogg | Bin modular_doppler/indicators/readme.md | 6 +- modular_doppler/modular_antagonist/readme.md | 25 ++++ .../{heartkin => hearthkin}/armwraps.json | 0 .../armwraps_worn.json | 0 .../{heartkin => hearthkin}/body_wraps.json | 0 .../body_wraps_worn.json | 0 .../{heartkin => hearthkin}/boots.json | 0 .../{heartkin => hearthkin}/boots_worn.json | 0 .../{heartkin => hearthkin}/coat.json | 0 .../{heartkin => hearthkin}/coat_worn.json | 0 .../{heartkin => hearthkin}/ferroniere.json | 0 .../ferroniere_worn.json | 0 .../{heartkin => hearthkin}/gauntlets.json | 0 .../gauntlets_worn.json | 0 .../{heartkin => hearthkin}/loincloth.json | 0 .../loincloth_alt.json | 0 .../loincloth_alt_worn.json | 0 .../loincloth_worn.json | 0 .../tailored_dress.json | 0 .../tailored_dress_worn.json | 0 .../{heartkin => hearthkin}/tunic.json | 0 .../{heartkin => hearthkin}/tunic_worn.json | 0 modular_doppler/modular_crafting/readme.md | 27 ++++ .../modular_mob_spawn/code/mob_spawn.dm | 4 +- modular_doppler/modular_mob_spawn/readme.md | 27 ++++ modular_doppler/modular_persistence/README.md | 23 --- .../code/modular_persistence.dm | 138 ------------------ modular_doppler/modular_sounds/readme.md | 23 +++ modular_doppler/modular_traits/readme.md | 10 +- modular_doppler/obj_flags_doppler/readme.md | 25 ++++ .../reagent_forging/code/forge_clothing.dm | 32 ++-- .../icons/mob/clothing/forge_clothing.dmi | Bin 1392 -> 960 bytes .../icons/obj/forge_clothing.dmi | Bin 994 -> 665 bytes modular_doppler/reagent_forging/readme.md | 17 ++- modular_doppler/religion/code/mind.dm | 11 ++ modular_doppler/religion/readme.md | 25 ++++ modular_doppler/stone/readme.md | 25 ++++ modular_doppler/xenoarch/readme.md | 5 +- tgstation.dme | 16 +- 75 files changed, 442 insertions(+), 277 deletions(-) create mode 100644 modular_doppler/advanced_reskin/readme.md create mode 100644 modular_doppler/hearthkin/primitive_catgirls/readme.md create mode 100644 modular_doppler/hearthkin/readme.md rename modular_doppler/{ => hearthkin}/tribal_extended/code/ammo/caseless/arrow.dm (79%) rename modular_doppler/{ => hearthkin}/tribal_extended/code/ammo/reusable/arrow.dm (100%) rename modular_doppler/{ => hearthkin}/tribal_extended/code/crafting.dm (77%) rename modular_doppler/{ => hearthkin}/tribal_extended/code/recipes.dm (100%) rename modular_doppler/{ => hearthkin}/tribal_extended/code/weapons/bow.dm (62%) rename modular_doppler/{ => hearthkin}/tribal_extended/code/weapons/shield.dm (54%) rename modular_doppler/{ => hearthkin}/tribal_extended/code/weapons/sword.dm (64%) rename modular_doppler/{ => hearthkin}/tribal_extended/icons/ammo.dmi (100%) rename modular_doppler/{ => hearthkin}/tribal_extended/icons/back.dmi (100%) rename modular_doppler/{ => hearthkin}/tribal_extended/icons/belt.dmi (100%) rename modular_doppler/{ => hearthkin}/tribal_extended/icons/bows_lefthand.dmi (100%) rename modular_doppler/{ => hearthkin}/tribal_extended/icons/bows_righthand.dmi (100%) rename modular_doppler/{ => hearthkin}/tribal_extended/icons/crafting.dmi (100%) rename modular_doppler/{ => hearthkin}/tribal_extended/icons/dice.dmi (100%) rename modular_doppler/{ => hearthkin}/tribal_extended/icons/items_and_weapons.dmi (100%) rename modular_doppler/{ => hearthkin}/tribal_extended/icons/projectile.dmi (100%) rename modular_doppler/{ => hearthkin}/tribal_extended/icons/shields.dmi (100%) rename modular_doppler/{ => hearthkin}/tribal_extended/icons/shields_lefthand.dmi (100%) rename modular_doppler/{ => hearthkin}/tribal_extended/icons/shields_righthand.dmi (100%) rename modular_doppler/{ => hearthkin}/tribal_extended/icons/swords_lefthand.dmi (100%) rename modular_doppler/{ => hearthkin}/tribal_extended/icons/swords_righthand.dmi (100%) create mode 100644 modular_doppler/hearthkin/tribal_extended/readme.md rename modular_doppler/{ => hearthkin}/tribal_extended/sound/sound_weapons_bowdraw.ogg (100%) rename modular_doppler/{ => hearthkin}/tribal_extended/sound/sound_weapons_bowfire.ogg (100%) create mode 100644 modular_doppler/modular_antagonist/readme.md rename modular_doppler/modular_cosmetics/GAGS/json_configs/{heartkin => hearthkin}/armwraps.json (100%) rename modular_doppler/modular_cosmetics/GAGS/json_configs/{heartkin => hearthkin}/armwraps_worn.json (100%) rename modular_doppler/modular_cosmetics/GAGS/json_configs/{heartkin => hearthkin}/body_wraps.json (100%) rename modular_doppler/modular_cosmetics/GAGS/json_configs/{heartkin => hearthkin}/body_wraps_worn.json (100%) rename modular_doppler/modular_cosmetics/GAGS/json_configs/{heartkin => hearthkin}/boots.json (100%) rename modular_doppler/modular_cosmetics/GAGS/json_configs/{heartkin => hearthkin}/boots_worn.json (100%) rename modular_doppler/modular_cosmetics/GAGS/json_configs/{heartkin => hearthkin}/coat.json (100%) rename modular_doppler/modular_cosmetics/GAGS/json_configs/{heartkin => hearthkin}/coat_worn.json (100%) rename modular_doppler/modular_cosmetics/GAGS/json_configs/{heartkin => hearthkin}/ferroniere.json (100%) rename modular_doppler/modular_cosmetics/GAGS/json_configs/{heartkin => hearthkin}/ferroniere_worn.json (100%) rename modular_doppler/modular_cosmetics/GAGS/json_configs/{heartkin => hearthkin}/gauntlets.json (100%) rename modular_doppler/modular_cosmetics/GAGS/json_configs/{heartkin => hearthkin}/gauntlets_worn.json (100%) rename modular_doppler/modular_cosmetics/GAGS/json_configs/{heartkin => hearthkin}/loincloth.json (100%) rename modular_doppler/modular_cosmetics/GAGS/json_configs/{heartkin => hearthkin}/loincloth_alt.json (100%) rename modular_doppler/modular_cosmetics/GAGS/json_configs/{heartkin => hearthkin}/loincloth_alt_worn.json (100%) rename modular_doppler/modular_cosmetics/GAGS/json_configs/{heartkin => hearthkin}/loincloth_worn.json (100%) rename modular_doppler/modular_cosmetics/GAGS/json_configs/{heartkin => hearthkin}/tailored_dress.json (100%) rename modular_doppler/modular_cosmetics/GAGS/json_configs/{heartkin => hearthkin}/tailored_dress_worn.json (100%) rename modular_doppler/modular_cosmetics/GAGS/json_configs/{heartkin => hearthkin}/tunic.json (100%) rename modular_doppler/modular_cosmetics/GAGS/json_configs/{heartkin => hearthkin}/tunic_worn.json (100%) create mode 100644 modular_doppler/modular_crafting/readme.md create mode 100644 modular_doppler/modular_mob_spawn/readme.md delete mode 100644 modular_doppler/modular_persistence/README.md delete mode 100644 modular_doppler/modular_persistence/code/modular_persistence.dm create mode 100644 modular_doppler/modular_sounds/readme.md create mode 100644 modular_doppler/obj_flags_doppler/readme.md create mode 100644 modular_doppler/religion/code/mind.dm create mode 100644 modular_doppler/religion/readme.md create mode 100644 modular_doppler/stone/readme.md diff --git a/code/game/atom/atom_tool_acts.dm b/code/game/atom/atom_tool_acts.dm index 301b6fe8ec394..8c71fc17c1b6a 100644 --- a/code/game/atom/atom_tool_acts.dm +++ b/code/game/atom/atom_tool_acts.dm @@ -109,7 +109,7 @@ act_result = is_left_clicking ? welder_act(user, tool) : welder_act_secondary(user, tool) if(TOOL_ANALYZER) act_result = is_left_clicking ? analyzer_act(user, tool) : analyzer_act_secondary(user, tool) - // DOPPLER EDIT ADDITION START - REAGENT FORGING TOOLS + // DOPPLER EDIT ADDITION START - REAGENT FORGING AND GLASSBLOWING TOOLS if(TOOL_BILLOW) act_result = is_left_clicking ? billow_act(user, tool) : billow_act_secondary(user, tool) if(TOOL_TONG) diff --git a/modular_doppler/advanced_reskin/readme.md b/modular_doppler/advanced_reskin/readme.md new file mode 100644 index 0000000000000..8ac6d8dc3f3da --- /dev/null +++ b/modular_doppler/advanced_reskin/readme.md @@ -0,0 +1,25 @@ +## Title: Advanced Reskin + +MODULE ID: ADVANCED_RESKIN + +### Description: + +This module adds more customization to the reskin function, as well as serving as a place to add more to it. + +### TG Proc Changes: + +N/A + +### Defines: + +- `code\__DEFINES\~doppler_defines\reskin_defines.dm` module's defines + +### Master file additions + +N/A + +### Included files that are not contained in this module: + +N/A + +### Credits: diff --git a/modular_doppler/cryosleep/code/cryopod.dm b/modular_doppler/cryosleep/code/cryopod.dm index 6a05501152950..8c0f6d47169bb 100644 --- a/modular_doppler/cryosleep/code/cryopod.dm +++ b/modular_doppler/cryosleep/code/cryopod.dm @@ -215,10 +215,6 @@ MAPPING_DIRECTIONAL_HELPERS(/obj/machinery/computer/cryopod, 32) if(mob_occupant && mob_occupant.stat != DEAD) to_chat(occupant, span_notice("You feel cool air surround you. You go numb as your senses turn inward.")) - var/mob/living/carbon/human/human_occupant = occupant - if(istype(human_occupant) && human_occupant.mind) - human_occupant.save_individual_persistence(mob_occupant.ckey || mob_occupant.mind?.key) - COOLDOWN_START(src, despawn_world_time, time_till_despawn) /obj/machinery/cryopod/open_machine(drop = TRUE, density_to_set = FALSE) diff --git a/modular_doppler/cryosleep/readme.md b/modular_doppler/cryosleep/readme.md index 35ee69f313b4b..6a8dde917b021 100644 --- a/modular_doppler/cryosleep/readme.md +++ b/modular_doppler/cryosleep/readme.md @@ -6,9 +6,11 @@ MODULE ID: CRYOSLEEP Adds in a green sleeper-like cryosleep machine, to allow people who wish to stop playing the game to exit with an IC way. +The time of how long until someone can be put in cryo if they are SSD `CRYO_MIN_SSD_TIME` was added in the configuration file `config\doppler\config_doppler.txt` + ### TG Proc Changes: - - ADDITION: /code/game/machinery/announcement_system.dm > /obj/machinery/announcement_system/proc/announce() +N/A ### Defines: diff --git a/modular_doppler/hearthkin/primitive_catgirls/code/greyscale_config.dm b/modular_doppler/hearthkin/primitive_catgirls/code/greyscale_config.dm index 9782467fe18f4..31620b2368ee4 100644 --- a/modular_doppler/hearthkin/primitive_catgirls/code/greyscale_config.dm +++ b/modular_doppler/hearthkin/primitive_catgirls/code/greyscale_config.dm @@ -1,89 +1,89 @@ /datum/greyscale_config/primitive_catgirl_wraps name = "Primitive Body Wraps" icon_file = 'modular_doppler/hearthkin/primitive_catgirls/icons/clothing_greyscale.dmi' - json_config = 'modular_doppler/modular_cosmetics/GAGS/json_configs/heartkin/body_wraps.json' + json_config = 'modular_doppler/modular_cosmetics/GAGS/json_configs/hearthkin/body_wraps.json' /datum/greyscale_config/primitive_catgirl_wraps/worn name = "Primitive Body Wraps (Worn)" - json_config = 'modular_doppler/modular_cosmetics/GAGS/json_configs/heartkin/body_wraps_worn.json' + json_config = 'modular_doppler/modular_cosmetics/GAGS/json_configs/hearthkin/body_wraps_worn.json' /datum/greyscale_config/primitive_catgirl_armwraps name = "Arm Wraps" icon_file = 'modular_doppler/hearthkin/primitive_catgirls/icons/clothing_greyscale.dmi' - json_config = 'modular_doppler/modular_cosmetics/GAGS/json_configs/heartkin/armwraps.json' + json_config = 'modular_doppler/modular_cosmetics/GAGS/json_configs/hearthkin/armwraps.json' /datum/greyscale_config/primitive_catgirl_armwraps/worn name = "Arm Wraps (Worn)" - json_config = 'modular_doppler/modular_cosmetics/GAGS/json_configs/heartkin/armwraps_worn.json' + json_config = 'modular_doppler/modular_cosmetics/GAGS/json_configs/hearthkin/armwraps_worn.json' /datum/greyscale_config/primitive_catgirl_coat name = "Primitive Fur Coat" icon_file = 'modular_doppler/hearthkin/primitive_catgirls/icons/clothing_greyscale.dmi' - json_config = 'modular_doppler/modular_cosmetics/GAGS/json_configs/heartkin/coat.json' + json_config = 'modular_doppler/modular_cosmetics/GAGS/json_configs/hearthkin/coat.json' /datum/greyscale_config/primitive_catgirl_coat/worn name = "Primitive Fur Coat (Worn)" - json_config = 'modular_doppler/modular_cosmetics/GAGS/json_configs/heartkin/coat_worn.json' + json_config = 'modular_doppler/modular_cosmetics/GAGS/json_configs/hearthkin/coat_worn.json' /datum/greyscale_config/primitive_catgirl_boots name = "Primitive Winter Boots" icon_file = 'modular_doppler/hearthkin/primitive_catgirls/icons/clothing_greyscale.dmi' - json_config = 'modular_doppler/modular_cosmetics/GAGS/json_configs/heartkin/boots.json' + json_config = 'modular_doppler/modular_cosmetics/GAGS/json_configs/hearthkin/boots.json' /datum/greyscale_config/primitive_catgirl_boots/worn name = "Primitive Winter Boots (Worn)" - json_config = 'modular_doppler/modular_cosmetics/GAGS/json_configs/heartkin/boots_worn.json' + json_config = 'modular_doppler/modular_cosmetics/GAGS/json_configs/hearthkin/boots_worn.json' /datum/greyscale_config/primitive_catgirl_gauntlets name = "Gauntlets" icon_file = 'modular_doppler/hearthkin/primitive_catgirls/icons/clothing_greyscale.dmi' - json_config = 'modular_doppler/modular_cosmetics/GAGS/json_configs/heartkin/gauntlets.json' + json_config = 'modular_doppler/modular_cosmetics/GAGS/json_configs/hearthkin/gauntlets.json' /datum/greyscale_config/primitive_catgirl_gauntlets/worn name = "Gauntlets (Worn)" - json_config = 'modular_doppler/modular_cosmetics/GAGS/json_configs/heartkin/gauntlets_worn.json' + json_config = 'modular_doppler/modular_cosmetics/GAGS/json_configs/hearthkin/gauntlets_worn.json' /datum/greyscale_config/primitive_catgirl_tailored_dress name = "Tailored Dress" icon_file = 'modular_doppler/hearthkin/primitive_catgirls/icons/clothing_greyscale.dmi' - json_config = 'modular_doppler/modular_cosmetics/GAGS/json_configs/heartkin/tailored_dress.json' + json_config = 'modular_doppler/modular_cosmetics/GAGS/json_configs/hearthkin/tailored_dress.json' /datum/greyscale_config/primitive_catgirl_tailored_dress/worn name = "Tailored Dress (Worn)" - json_config = 'modular_doppler/modular_cosmetics/GAGS/json_configs/heartkin/tailored_dress_worn.json' + json_config = 'modular_doppler/modular_cosmetics/GAGS/json_configs/hearthkin/tailored_dress_worn.json' /datum/greyscale_config/primitive_catgirl_ferroniere name = "Ferroniere" icon_file = 'modular_doppler/hearthkin/primitive_catgirls/icons/clothing_greyscale.dmi' - json_config = 'modular_doppler/modular_cosmetics/GAGS/json_configs/heartkin/ferroniere.json' + json_config = 'modular_doppler/modular_cosmetics/GAGS/json_configs/hearthkin/ferroniere.json' /datum/greyscale_config/primitive_catgirl_ferroniere/worn name = "Ferroniere (Worn)" - json_config = 'modular_doppler/modular_cosmetics/GAGS/json_configs/heartkin/ferroniere_worn.json' + json_config = 'modular_doppler/modular_cosmetics/GAGS/json_configs/hearthkin/ferroniere_worn.json' /datum/greyscale_config/primitive_catgirl_tunic name = "Handmade Tunic" icon_file = 'modular_doppler/hearthkin/primitive_catgirls/icons/clothing_greyscale.dmi' - json_config = 'modular_doppler/modular_cosmetics/GAGS/json_configs/heartkin/tunic.json' + json_config = 'modular_doppler/modular_cosmetics/GAGS/json_configs/hearthkin/tunic.json' /datum/greyscale_config/primitive_catgirl_tunic/worn name = "Handmade Tunic (Worn)" - json_config = 'modular_doppler/modular_cosmetics/GAGS/json_configs/heartkin/tunic_worn.json' + json_config = 'modular_doppler/modular_cosmetics/GAGS/json_configs/hearthkin/tunic_worn.json' /datum/greyscale_config/loincloth name = "Loincloth" icon_file = 'modular_doppler/hearthkin/primitive_catgirls/icons/loincloth.dmi' - json_config = 'modular_doppler/modular_cosmetics/GAGS/json_configs/heartkin/loincloth.json' + json_config = 'modular_doppler/modular_cosmetics/GAGS/json_configs/hearthkin/loincloth.json' /datum/greyscale_config/loincloth/worn name = "Loincloth (Worn)" - json_config = 'modular_doppler/modular_cosmetics/GAGS/json_configs/heartkin/loincloth_worn.json' + json_config = 'modular_doppler/modular_cosmetics/GAGS/json_configs/hearthkin/loincloth_worn.json' /datum/greyscale_config/loincloth_alt name = "Shorter Loincloth" icon_file = 'modular_doppler/hearthkin/primitive_catgirls/icons/loincloth.dmi' - json_config = 'modular_doppler/modular_cosmetics/GAGS/json_configs/heartkin/loincloth_alt.json' + json_config = 'modular_doppler/modular_cosmetics/GAGS/json_configs/hearthkin/loincloth_alt.json' /datum/greyscale_config/loincloth_alt/worn name = "Shorter Loincloth (Worn)" - json_config = 'modular_doppler/modular_cosmetics/GAGS/json_configs/heartkin/loincloth_alt_worn.json' + json_config = 'modular_doppler/modular_cosmetics/GAGS/json_configs/hearthkin/loincloth_alt_worn.json' diff --git a/modular_doppler/hearthkin/primitive_catgirls/readme.md b/modular_doppler/hearthkin/primitive_catgirls/readme.md new file mode 100644 index 0000000000000..d0785dbeb8441 --- /dev/null +++ b/modular_doppler/hearthkin/primitive_catgirls/readme.md @@ -0,0 +1,29 @@ +## Title: Primitive Catgirls + +MODULE ID: PRIMITIVE_CATGIRLS + +### Description: + +Main module of the Hearthkin. It adds species, unique language, special organs and map items as well as unique objects and clothing. +Special metals, as well as the pet commands functionality have been added too. + +The species ID `primitive_felinid` was added in the configuration file `config\doppler\config_doppler.txt` as a round start species + +### TG Proc Changes: + +N/A + +### Defines: + +- `code\__DEFINES\~doppler_defines\DNA.dm` species id +- `code\__DEFINES\~doppler_defines\is_helpers.dm` is_type identificator for species + +### Master file additions + +N/A + +### Included files that are not contained in this module: + +N/A + +### Credits: diff --git a/modular_doppler/hearthkin/primitive_cooking_additions/code/big_mortar.dm b/modular_doppler/hearthkin/primitive_cooking_additions/code/big_mortar.dm index 783924133f266..76e8176ffb87e 100644 --- a/modular_doppler/hearthkin/primitive_cooking_additions/code/big_mortar.dm +++ b/modular_doppler/hearthkin/primitive_cooking_additions/code/big_mortar.dm @@ -1,6 +1,3 @@ -#define LARGE_MORTAR_STAMINA_MINIMUM 50 //What is the amount of stam damage that we prevent mortar use at -#define LARGE_MORTAR_STAMINA_USE 70 //How much stam damage is given to people when the mortar is used - /obj/structure/large_mortar name = "large mortar" desc = "A large bowl perfect for grinding or juicing a large number of things at once." @@ -16,6 +13,7 @@ ) /// The maximum number of items this structure can store var/maximum_contained_items = 10 + var/in_use = FALSE /obj/structure/large_mortar/Initialize(mapload) . = ..() @@ -34,6 +32,10 @@ return ..() /obj/structure/large_mortar/click_alt(mob/user) + if(in_use) // If the big mortar is currently in use by someone then we cannot use it + balloon_alert(user, "big mortar busy") + return CLICK_ACTION_BLOCKING + if(!length(contents)) balloon_alert(user, "nothing inside") return CLICK_ACTION_BLOCKING @@ -51,6 +53,10 @@ target_item.forceMove(get_turf(src)) /obj/structure/large_mortar/attack_hand_secondary(mob/user, list/modifiers) + if(in_use) // If the big mortar is currently in use by someone then we cannot use it + balloon_alert(user, "big mortar busy") + return + . = ..() if(. == SECONDARY_ATTACK_CANCEL_ATTACK_CHAIN) return @@ -63,10 +69,18 @@ return SECONDARY_ATTACK_CANCEL_ATTACK_CHAIN /obj/structure/large_mortar/attackby(obj/item/attacking_item, mob/living/carbon/human/user) + if(in_use) // If the big mortar is currently in use by someone then we cannot use it + balloon_alert(user, "big mortar busy") + return + if(attacking_item.is_refillable()) return /obj/structure/large_mortar/item_interaction(mob/living/user, obj/item/tool, list/modifiers, is_right_clicking) + if(in_use) // If the big mortar is currently in use by someone then we cannot use it + balloon_alert(user, "big mortar busy") + return ITEM_INTERACT_BLOCKING + . = ..() if(. || user.combat_mode || tool.is_refillable()) return . @@ -108,10 +122,6 @@ ) var/picked_option = show_radial_menu(user, src, choose_options, radius = 38, require_near = TRUE) - if(user.getStaminaLoss() > LARGE_MORTAR_STAMINA_MINIMUM) - balloon_alert(user, "too tired!") - return ITEM_INTERACT_BLOCKING - if(!in_range(src, user) || !user.is_holding(tool) || !picked_option) return ITEM_INTERACT_BLOCKING var/act_verb = LOWER_TEXT(picked_option) @@ -132,11 +142,14 @@ return ITEM_INTERACT_BLOCKING balloon_alert_to_viewers("[act_verb_ing]...") + + in_use = TRUE + if(!do_after(user, 5 SECONDS, target = src)) balloon_alert_to_viewers("stopped [act_verb_ing]") + in_use = FALSE return ITEM_INTERACT_BLOCKING - user.adjustStaminaLoss(LARGE_MORTAR_STAMINA_USE) //This is a bit more tiring than a normal sized mortar and pestle switch(picked_option) if("Juice") for(var/obj/item/target_item as anything in contents) @@ -160,6 +173,7 @@ if("Mix") mix() + in_use = FALSE return ITEM_INTERACT_SUCCESS if(!tool.grind_results && !tool.juice_typepath) @@ -219,6 +233,3 @@ //Recipe to make whipped cream if (reagents.has_reagent(/datum/reagent/consumable/cream)) reagents.convert_reagent(/datum/reagent/consumable/cream, /datum/reagent/consumable/whipped_cream) - -#undef LARGE_MORTAR_STAMINA_MINIMUM -#undef LARGE_MORTAR_STAMINA_USE diff --git a/modular_doppler/hearthkin/primitive_cooking_additions/readme.md b/modular_doppler/hearthkin/primitive_cooking_additions/readme.md index bec80c6709924..e65eeba2b3d88 100644 --- a/modular_doppler/hearthkin/primitive_cooking_additions/readme.md +++ b/modular_doppler/hearthkin/primitive_cooking_additions/readme.md @@ -1,4 +1,6 @@ -## Title: PRIMITIVE COOKING ADDITIONS +## Title: Primitive Cooking Additions + +MODULE ID: PRIMITIVE_COOKING_ADDITIONS ### Description: @@ -6,18 +8,19 @@ Adds several ways to cook and prepare foods without the use of powered machines ### TG Proc/File Changes: -- N/A +N/A ### Defines: -- N/A +N/A ### Master file additions -- N/A +N/A ### Included files that are not contained in this module: -- N/A +- `modular_doppler\modular_crafting\code\sheet_types.dm` crafting recipes +- `modular_doppler\stone\code\stone.dm` crafting recipes ### Credits: diff --git a/modular_doppler/hearthkin/primitive_production/readme.md b/modular_doppler/hearthkin/primitive_production/readme.md index fb479a888da86..f105311083886 100644 --- a/modular_doppler/hearthkin/primitive_production/readme.md +++ b/modular_doppler/hearthkin/primitive_production/readme.md @@ -1,24 +1,29 @@ -## Title: PRIMITIVE PRODUCTION +## Title: Primitive Production +MODULE ID: PRIMITIVE_PRODUCTION ### Description: Adds a variety of 'primitive' ways to produce items +Antfarming, wormfarming and the normal kind of farming were added as well. ### TG Proc/File Changes: -- N/A +| proc | file | +| --------------------------------------------------------------------- | ----------------------------------- | +| `/atom/proc/tool_act(mob/living/user, obj/item/tool, list/modifiers)` | `code\game\atom\atom_tool_acts.dm` | ### Defines: -- N/A +- `code\__DEFINES\~doppler_defines\reagent_forging_tools.dm` glassblowing tools' define +- `code\__DEFINES\~doppler_defines\traits.dm` trait for glassblowing ### Master file additions -- N/A +N/A ### Included files that are not contained in this module: -- N/A +- `modular_doppler\modular_crafting\code\sheet_types.dm` crafting recipes ### Credits: diff --git a/modular_doppler/hearthkin/primitive_structures/code/furniture.dm b/modular_doppler/hearthkin/primitive_structures/code/furniture.dm index e1ee468b82daf..92333fc129b87 100644 --- a/modular_doppler/hearthkin/primitive_structures/code/furniture.dm +++ b/modular_doppler/hearthkin/primitive_structures/code/furniture.dm @@ -1,7 +1,7 @@ /obj/item/target/archery name = "archery target" desc = "A shooting target, specifically for bows." - icon = 'modular_doppler/tribal_extended/icons/items_and_weapons.dmi' + icon = 'modular_doppler/hearthkin/tribal_extended/icons/items_and_weapons.dmi' icon_state = "archery_target" // impact_sound = SFX_BULLET_IMPACT_WOOD diff --git a/modular_doppler/hearthkin/primitive_structures/readme.md b/modular_doppler/hearthkin/primitive_structures/readme.md index 038eb3b894cd9..c1950a1484aa9 100644 --- a/modular_doppler/hearthkin/primitive_structures/readme.md +++ b/modular_doppler/hearthkin/primitive_structures/readme.md @@ -1,23 +1,26 @@ -## Title: PRIMITIVE +## Title: Primitive Structures + +MODULE ID: PRIMITIVE_STRUCTURES ### Description: -Contains various items of primitive style for icecats and sometimes even ashwalkers +Contains various items of primitive style for icecats +Fuel wells and railroads were added as well. ### TG Proc/File Changes: -- N/A +N/A ### Defines: -- N/A +N/A ### Master file additions -- N/A +N/A ### Included files that are not contained in this module: -- N/A +- `modular_doppler\modular_crafting\code\sheet_types.dm` crafting recipes ### Credits: diff --git a/modular_doppler/hearthkin/readme.md b/modular_doppler/hearthkin/readme.md new file mode 100644 index 0000000000000..2aac6a25cb0e1 --- /dev/null +++ b/modular_doppler/hearthkin/readme.md @@ -0,0 +1,33 @@ +## Title: Hearthkin + +MODULE ID: HEARTHKIN + +### Description: + +Contains the main sub-modules for the Hearthkin, a tribe of genetically modified humanoids that inhabits the Ice Moon. They have their own primitive means of cooking, farming, production and much more. + +The species ID `primitive_felinid` was added in the configuration file `config\doppler\config_doppler.txt` as a round start species + +### TG Proc Changes: + +| proc | file | +| --------------------------------------------------------------------- | ----------------------------------- | +| `/atom/proc/tool_act(mob/living/user, obj/item/tool, list/modifiers)` | `code\game\atom\atom_tool_acts.dm` | + +### Defines: + +- `code\__DEFINES\~doppler_defines\DNA.dm` species id +- `code\__DEFINES\~doppler_defines\is_helpers.dm` is_type identificator for species +- `code\__DEFINES\~doppler_defines\reagent_forging_tools.dm` glassblowing tools' define +- `code\__DEFINES\~doppler_defines\traits.dm` trait for glassblowing + +### Master file additions + +N/A + +### Included files that are not contained in this module: + +- `modular_doppler\modular_crafting\code\sheet_types.dm` crafting recipes +- `modular_doppler\stone\code\stone.dm` crafting recipes + +### Credits: diff --git a/modular_doppler/tribal_extended/code/ammo/caseless/arrow.dm b/modular_doppler/hearthkin/tribal_extended/code/ammo/caseless/arrow.dm similarity index 79% rename from modular_doppler/tribal_extended/code/ammo/caseless/arrow.dm rename to modular_doppler/hearthkin/tribal_extended/code/ammo/caseless/arrow.dm index f10d3500fd3b7..4ad8836986cb5 100644 --- a/modular_doppler/tribal_extended/code/ammo/caseless/arrow.dm +++ b/modular_doppler/hearthkin/tribal_extended/code/ammo/caseless/arrow.dm @@ -1,7 +1,7 @@ /obj/item/ammo_casing/arrow/ash name = "ashen arrow" desc = "An arrow made from ash and iron. They're cheap, but they fell the beasts of lavaland like none other." - icon = 'modular_doppler/tribal_extended/icons/ammo.dmi' + icon = 'modular_doppler/hearthkin/tribal_extended/icons/ammo.dmi' icon_state = "ashenarrow" base_icon_state = "ashenarrow" projectile_type = /obj/projectile/bullet/arrow/ash @@ -9,7 +9,7 @@ /obj/item/ammo_casing/arrow/bone name = "bone arrow" desc = "An arrow made of bone and sinew. The tip is sharp and jagged, suitable for digging into flesh." - icon = 'modular_doppler/tribal_extended/icons/ammo.dmi' + icon = 'modular_doppler/hearthkin/tribal_extended/icons/ammo.dmi' icon_state = "bonearrow" base_icon_state = "ashenarrow" projectile_type = /obj/projectile/bullet/arrow/bone @@ -17,7 +17,7 @@ /obj/item/ammo_casing/arrow/bronze name = "bronze arrow" desc = "An arrow tipped with bronze. Fit for killing gods." - icon = 'modular_doppler/tribal_extended/icons/ammo.dmi' + icon = 'modular_doppler/hearthkin/tribal_extended/icons/ammo.dmi' icon_state = "bronzearrow" base_icon_state = "ashenarrow" projectile_type = /obj/projectile/bullet/arrow/bronze diff --git a/modular_doppler/tribal_extended/code/ammo/reusable/arrow.dm b/modular_doppler/hearthkin/tribal_extended/code/ammo/reusable/arrow.dm similarity index 100% rename from modular_doppler/tribal_extended/code/ammo/reusable/arrow.dm rename to modular_doppler/hearthkin/tribal_extended/code/ammo/reusable/arrow.dm diff --git a/modular_doppler/tribal_extended/code/crafting.dm b/modular_doppler/hearthkin/tribal_extended/code/crafting.dm similarity index 77% rename from modular_doppler/tribal_extended/code/crafting.dm rename to modular_doppler/hearthkin/tribal_extended/code/crafting.dm index 113ac5aa69f8f..b6705ad928954 100644 --- a/modular_doppler/tribal_extended/code/crafting.dm +++ b/modular_doppler/hearthkin/tribal_extended/code/crafting.dm @@ -1,20 +1,20 @@ /obj/item/weaponcrafting/silkstring name = "string" desc = "A long piece of string that looks like a cable coil." - icon = 'modular_doppler/tribal_extended/icons/crafting.dmi' + icon = 'modular_doppler/hearthkin/tribal_extended/icons/crafting.dmi' icon_state = "silkstring" /obj/item/dice/d6/bone name = "bone die" desc = "A die carved from a creature's bone. Dried blood marks the indented pits." - icon = 'modular_doppler/tribal_extended/icons/dice.dmi' + icon = 'modular_doppler/hearthkin/tribal_extended/icons/dice.dmi' icon_state = "db6" microwave_riggable = FALSE // You can't melt bone in the microwave /obj/item/reagent_containers/cup/bowl/wood_bowl name = "wooden bowl" desc = "A bowl made out of wood. Primitive, but effective." - icon = 'modular_doppler/tribal_extended/icons/crafting.dmi' + icon = 'modular_doppler/hearthkin/tribal_extended/icons/crafting.dmi' icon_state = "wood_bowl" fill_icon_state = "fullbowl" fill_icon = 'icons/obj/mining_zones/ash_flora.dmi' diff --git a/modular_doppler/tribal_extended/code/recipes.dm b/modular_doppler/hearthkin/tribal_extended/code/recipes.dm similarity index 100% rename from modular_doppler/tribal_extended/code/recipes.dm rename to modular_doppler/hearthkin/tribal_extended/code/recipes.dm diff --git a/modular_doppler/tribal_extended/code/weapons/bow.dm b/modular_doppler/hearthkin/tribal_extended/code/weapons/bow.dm similarity index 62% rename from modular_doppler/tribal_extended/code/weapons/bow.dm rename to modular_doppler/hearthkin/tribal_extended/code/weapons/bow.dm index 64f9e9ab659fe..28a602dfbbfc1 100644 --- a/modular_doppler/tribal_extended/code/weapons/bow.dm +++ b/modular_doppler/hearthkin/tribal_extended/code/weapons/bow.dm @@ -1,8 +1,8 @@ /obj/item/gun/ballistic/bow/tribalbow - icon = 'modular_doppler/tribal_extended/icons/projectile.dmi' - lefthand_file = 'modular_doppler/tribal_extended/icons/bows_lefthand.dmi' - righthand_file = 'modular_doppler/tribal_extended/icons/bows_righthand.dmi' - worn_icon = 'modular_doppler/tribal_extended/icons/back.dmi' + icon = 'modular_doppler/hearthkin/tribal_extended/icons/projectile.dmi' + lefthand_file = 'modular_doppler/hearthkin/tribal_extended/icons/bows_lefthand.dmi' + righthand_file = 'modular_doppler/hearthkin/tribal_extended/icons/bows_righthand.dmi' + worn_icon = 'modular_doppler/hearthkin/tribal_extended/icons/back.dmi' inhand_icon_state = "bow" icon_state = null base_icon_state = "bow" @@ -12,7 +12,7 @@ /obj/item/gun/ballistic/bow/tribalbow/ashen name = "bone bow" desc = "Some sort of primitive projectile weapon made of bone and wrapped sinew, oddly robust." - icon = 'modular_doppler/tribal_extended/icons/projectile.dmi' + icon = 'modular_doppler/hearthkin/tribal_extended/icons/projectile.dmi' icon_state = "ashenbow" base_icon_state = "ashenbow" inhand_icon_state = "ashenbow" @@ -22,7 +22,7 @@ /obj/item/gun/ballistic/bow/tribalbow/pipe name = "pipe bow" desc = "Portable and sleek, but you'd be better off hitting someone with a pool noodle." - icon = 'modular_doppler/tribal_extended/icons/projectile.dmi' + icon = 'modular_doppler/hearthkin/tribal_extended/icons/projectile.dmi' icon_state = "pipebow" base_icon_state = "pipebow" inhand_icon_state = "pipebow" diff --git a/modular_doppler/tribal_extended/code/weapons/shield.dm b/modular_doppler/hearthkin/tribal_extended/code/weapons/shield.dm similarity index 54% rename from modular_doppler/tribal_extended/code/weapons/shield.dm rename to modular_doppler/hearthkin/tribal_extended/code/weapons/shield.dm index ee3069f0579fc..2a6b325182002 100644 --- a/modular_doppler/tribal_extended/code/weapons/shield.dm +++ b/modular_doppler/hearthkin/tribal_extended/code/weapons/shield.dm @@ -1,11 +1,11 @@ /obj/item/shield/goliath name = "goliath shield" desc = "A shield made from interwoven plates of goliath hide." - icon = 'modular_doppler/tribal_extended/icons/shields.dmi' + icon = 'modular_doppler/hearthkin/tribal_extended/icons/shields.dmi' icon_state = "goliath_shield" - lefthand_file = 'modular_doppler/tribal_extended/icons/shields_lefthand.dmi' - righthand_file = 'modular_doppler/tribal_extended/icons/shields_righthand.dmi' - worn_icon = 'modular_doppler/tribal_extended/icons/back.dmi' + lefthand_file = 'modular_doppler/hearthkin/tribal_extended/icons/shields_lefthand.dmi' + righthand_file = 'modular_doppler/hearthkin/tribal_extended/icons/shields_righthand.dmi' + worn_icon = 'modular_doppler/hearthkin/tribal_extended/icons/back.dmi' worn_icon_state = "goliath_shield" inhand_icon_state = "goliath_shield" max_integrity = 200 diff --git a/modular_doppler/tribal_extended/code/weapons/sword.dm b/modular_doppler/hearthkin/tribal_extended/code/weapons/sword.dm similarity index 64% rename from modular_doppler/tribal_extended/code/weapons/sword.dm rename to modular_doppler/hearthkin/tribal_extended/code/weapons/sword.dm index c8f006fc6733a..a2c7cff9cdccc 100644 --- a/modular_doppler/tribal_extended/code/weapons/sword.dm +++ b/modular_doppler/hearthkin/tribal_extended/code/weapons/sword.dm @@ -1,10 +1,10 @@ /obj/item/claymore/bone name = "bone sword" desc = "Jagged pieces of bone are tied to what looks like a goliaths femur." - icon = 'modular_doppler/tribal_extended/icons/items_and_weapons.dmi' - lefthand_file = 'modular_doppler/tribal_extended/icons/swords_lefthand.dmi' - righthand_file = 'modular_doppler/tribal_extended/icons/swords_righthand.dmi' - worn_icon = 'modular_doppler/tribal_extended/icons/back.dmi' + icon = 'modular_doppler/hearthkin/tribal_extended/icons/items_and_weapons.dmi' + lefthand_file = 'modular_doppler/hearthkin/tribal_extended/icons/swords_lefthand.dmi' + righthand_file = 'modular_doppler/hearthkin/tribal_extended/icons/swords_righthand.dmi' + worn_icon = 'modular_doppler/hearthkin/tribal_extended/icons/back.dmi' icon_state = "bone_sword" inhand_icon_state = "bone_sword" worn_icon_state = "bone_sword" diff --git a/modular_doppler/tribal_extended/icons/ammo.dmi b/modular_doppler/hearthkin/tribal_extended/icons/ammo.dmi similarity index 100% rename from modular_doppler/tribal_extended/icons/ammo.dmi rename to modular_doppler/hearthkin/tribal_extended/icons/ammo.dmi diff --git a/modular_doppler/tribal_extended/icons/back.dmi b/modular_doppler/hearthkin/tribal_extended/icons/back.dmi similarity index 100% rename from modular_doppler/tribal_extended/icons/back.dmi rename to modular_doppler/hearthkin/tribal_extended/icons/back.dmi diff --git a/modular_doppler/tribal_extended/icons/belt.dmi b/modular_doppler/hearthkin/tribal_extended/icons/belt.dmi similarity index 100% rename from modular_doppler/tribal_extended/icons/belt.dmi rename to modular_doppler/hearthkin/tribal_extended/icons/belt.dmi diff --git a/modular_doppler/tribal_extended/icons/bows_lefthand.dmi b/modular_doppler/hearthkin/tribal_extended/icons/bows_lefthand.dmi similarity index 100% rename from modular_doppler/tribal_extended/icons/bows_lefthand.dmi rename to modular_doppler/hearthkin/tribal_extended/icons/bows_lefthand.dmi diff --git a/modular_doppler/tribal_extended/icons/bows_righthand.dmi b/modular_doppler/hearthkin/tribal_extended/icons/bows_righthand.dmi similarity index 100% rename from modular_doppler/tribal_extended/icons/bows_righthand.dmi rename to modular_doppler/hearthkin/tribal_extended/icons/bows_righthand.dmi diff --git a/modular_doppler/tribal_extended/icons/crafting.dmi b/modular_doppler/hearthkin/tribal_extended/icons/crafting.dmi similarity index 100% rename from modular_doppler/tribal_extended/icons/crafting.dmi rename to modular_doppler/hearthkin/tribal_extended/icons/crafting.dmi diff --git a/modular_doppler/tribal_extended/icons/dice.dmi b/modular_doppler/hearthkin/tribal_extended/icons/dice.dmi similarity index 100% rename from modular_doppler/tribal_extended/icons/dice.dmi rename to modular_doppler/hearthkin/tribal_extended/icons/dice.dmi diff --git a/modular_doppler/tribal_extended/icons/items_and_weapons.dmi b/modular_doppler/hearthkin/tribal_extended/icons/items_and_weapons.dmi similarity index 100% rename from modular_doppler/tribal_extended/icons/items_and_weapons.dmi rename to modular_doppler/hearthkin/tribal_extended/icons/items_and_weapons.dmi diff --git a/modular_doppler/tribal_extended/icons/projectile.dmi b/modular_doppler/hearthkin/tribal_extended/icons/projectile.dmi similarity index 100% rename from modular_doppler/tribal_extended/icons/projectile.dmi rename to modular_doppler/hearthkin/tribal_extended/icons/projectile.dmi diff --git a/modular_doppler/tribal_extended/icons/shields.dmi b/modular_doppler/hearthkin/tribal_extended/icons/shields.dmi similarity index 100% rename from modular_doppler/tribal_extended/icons/shields.dmi rename to modular_doppler/hearthkin/tribal_extended/icons/shields.dmi diff --git a/modular_doppler/tribal_extended/icons/shields_lefthand.dmi b/modular_doppler/hearthkin/tribal_extended/icons/shields_lefthand.dmi similarity index 100% rename from modular_doppler/tribal_extended/icons/shields_lefthand.dmi rename to modular_doppler/hearthkin/tribal_extended/icons/shields_lefthand.dmi diff --git a/modular_doppler/tribal_extended/icons/shields_righthand.dmi b/modular_doppler/hearthkin/tribal_extended/icons/shields_righthand.dmi similarity index 100% rename from modular_doppler/tribal_extended/icons/shields_righthand.dmi rename to modular_doppler/hearthkin/tribal_extended/icons/shields_righthand.dmi diff --git a/modular_doppler/tribal_extended/icons/swords_lefthand.dmi b/modular_doppler/hearthkin/tribal_extended/icons/swords_lefthand.dmi similarity index 100% rename from modular_doppler/tribal_extended/icons/swords_lefthand.dmi rename to modular_doppler/hearthkin/tribal_extended/icons/swords_lefthand.dmi diff --git a/modular_doppler/tribal_extended/icons/swords_righthand.dmi b/modular_doppler/hearthkin/tribal_extended/icons/swords_righthand.dmi similarity index 100% rename from modular_doppler/tribal_extended/icons/swords_righthand.dmi rename to modular_doppler/hearthkin/tribal_extended/icons/swords_righthand.dmi diff --git a/modular_doppler/hearthkin/tribal_extended/readme.md b/modular_doppler/hearthkin/tribal_extended/readme.md new file mode 100644 index 0000000000000..5eb036d18e8fe --- /dev/null +++ b/modular_doppler/hearthkin/tribal_extended/readme.md @@ -0,0 +1,25 @@ +## Title: Tribal Extended + +MODULE ID: TRIBAL_EXTENDED + +### Description: + +Adds different types of bows and arrows as well as other tribal miscellaneous. + +### TG Proc Changes: + +N/A + +### Defines: + +N/A + +### Master file additions + +N/A + +### Included files that are not contained in this module: + +N/A + +### Credits: diff --git a/modular_doppler/tribal_extended/sound/sound_weapons_bowdraw.ogg b/modular_doppler/hearthkin/tribal_extended/sound/sound_weapons_bowdraw.ogg similarity index 100% rename from modular_doppler/tribal_extended/sound/sound_weapons_bowdraw.ogg rename to modular_doppler/hearthkin/tribal_extended/sound/sound_weapons_bowdraw.ogg diff --git a/modular_doppler/tribal_extended/sound/sound_weapons_bowfire.ogg b/modular_doppler/hearthkin/tribal_extended/sound/sound_weapons_bowfire.ogg similarity index 100% rename from modular_doppler/tribal_extended/sound/sound_weapons_bowfire.ogg rename to modular_doppler/hearthkin/tribal_extended/sound/sound_weapons_bowfire.ogg diff --git a/modular_doppler/indicators/readme.md b/modular_doppler/indicators/readme.md index 248a0c8de4b0c..08ee1eb4de163 100644 --- a/modular_doppler/indicators/readme.md +++ b/modular_doppler/indicators/readme.md @@ -12,6 +12,9 @@ SSD Indicator - Automatically shows when a player has disconnected Typing Indicator - Shows when a player is typing Emote Popup - Added from another module because it was only by Combat Indicator +`COMBAT_INDICATOR` was added in the configuration file `config\doppler\config_doppler.txt`. Comment out to disable the module. + + ### TG Proc Changes: Combat Indicator - ADDITION: code/modules/mob/living/death.dm > /mob/living/death() @@ -28,7 +31,8 @@ SSD Indicator ### Defines: -N/A +- `code\__DEFINES\~doppler_defines\keybinds.dm` +- `code\__DEFINES\~doppler_defines\signals.dm` ### Included files: diff --git a/modular_doppler/modular_antagonist/readme.md b/modular_doppler/modular_antagonist/readme.md new file mode 100644 index 0000000000000..4dd62b72c6df3 --- /dev/null +++ b/modular_doppler/modular_antagonist/readme.md @@ -0,0 +1,25 @@ +## Title: Modular Antagonist + +MODULE ID: MODULAR_ANTAGONIST + +### Description: + +Extends the antag_datum with their own recipes, which the acquire when gaining the antag and forget when losing it. + +### TG Proc Changes: + +N/A + +### Defines: + +N/A + +### Master file additions + +N/A + +### Included files that are not contained in this module: + +N/A + +### Credits: diff --git a/modular_doppler/modular_cosmetics/GAGS/json_configs/heartkin/armwraps.json b/modular_doppler/modular_cosmetics/GAGS/json_configs/hearthkin/armwraps.json similarity index 100% rename from modular_doppler/modular_cosmetics/GAGS/json_configs/heartkin/armwraps.json rename to modular_doppler/modular_cosmetics/GAGS/json_configs/hearthkin/armwraps.json diff --git a/modular_doppler/modular_cosmetics/GAGS/json_configs/heartkin/armwraps_worn.json b/modular_doppler/modular_cosmetics/GAGS/json_configs/hearthkin/armwraps_worn.json similarity index 100% rename from modular_doppler/modular_cosmetics/GAGS/json_configs/heartkin/armwraps_worn.json rename to modular_doppler/modular_cosmetics/GAGS/json_configs/hearthkin/armwraps_worn.json diff --git a/modular_doppler/modular_cosmetics/GAGS/json_configs/heartkin/body_wraps.json b/modular_doppler/modular_cosmetics/GAGS/json_configs/hearthkin/body_wraps.json similarity index 100% rename from modular_doppler/modular_cosmetics/GAGS/json_configs/heartkin/body_wraps.json rename to modular_doppler/modular_cosmetics/GAGS/json_configs/hearthkin/body_wraps.json diff --git a/modular_doppler/modular_cosmetics/GAGS/json_configs/heartkin/body_wraps_worn.json b/modular_doppler/modular_cosmetics/GAGS/json_configs/hearthkin/body_wraps_worn.json similarity index 100% rename from modular_doppler/modular_cosmetics/GAGS/json_configs/heartkin/body_wraps_worn.json rename to modular_doppler/modular_cosmetics/GAGS/json_configs/hearthkin/body_wraps_worn.json diff --git a/modular_doppler/modular_cosmetics/GAGS/json_configs/heartkin/boots.json b/modular_doppler/modular_cosmetics/GAGS/json_configs/hearthkin/boots.json similarity index 100% rename from modular_doppler/modular_cosmetics/GAGS/json_configs/heartkin/boots.json rename to modular_doppler/modular_cosmetics/GAGS/json_configs/hearthkin/boots.json diff --git a/modular_doppler/modular_cosmetics/GAGS/json_configs/heartkin/boots_worn.json b/modular_doppler/modular_cosmetics/GAGS/json_configs/hearthkin/boots_worn.json similarity index 100% rename from modular_doppler/modular_cosmetics/GAGS/json_configs/heartkin/boots_worn.json rename to modular_doppler/modular_cosmetics/GAGS/json_configs/hearthkin/boots_worn.json diff --git a/modular_doppler/modular_cosmetics/GAGS/json_configs/heartkin/coat.json b/modular_doppler/modular_cosmetics/GAGS/json_configs/hearthkin/coat.json similarity index 100% rename from modular_doppler/modular_cosmetics/GAGS/json_configs/heartkin/coat.json rename to modular_doppler/modular_cosmetics/GAGS/json_configs/hearthkin/coat.json diff --git a/modular_doppler/modular_cosmetics/GAGS/json_configs/heartkin/coat_worn.json b/modular_doppler/modular_cosmetics/GAGS/json_configs/hearthkin/coat_worn.json similarity index 100% rename from modular_doppler/modular_cosmetics/GAGS/json_configs/heartkin/coat_worn.json rename to modular_doppler/modular_cosmetics/GAGS/json_configs/hearthkin/coat_worn.json diff --git a/modular_doppler/modular_cosmetics/GAGS/json_configs/heartkin/ferroniere.json b/modular_doppler/modular_cosmetics/GAGS/json_configs/hearthkin/ferroniere.json similarity index 100% rename from modular_doppler/modular_cosmetics/GAGS/json_configs/heartkin/ferroniere.json rename to modular_doppler/modular_cosmetics/GAGS/json_configs/hearthkin/ferroniere.json diff --git a/modular_doppler/modular_cosmetics/GAGS/json_configs/heartkin/ferroniere_worn.json b/modular_doppler/modular_cosmetics/GAGS/json_configs/hearthkin/ferroniere_worn.json similarity index 100% rename from modular_doppler/modular_cosmetics/GAGS/json_configs/heartkin/ferroniere_worn.json rename to modular_doppler/modular_cosmetics/GAGS/json_configs/hearthkin/ferroniere_worn.json diff --git a/modular_doppler/modular_cosmetics/GAGS/json_configs/heartkin/gauntlets.json b/modular_doppler/modular_cosmetics/GAGS/json_configs/hearthkin/gauntlets.json similarity index 100% rename from modular_doppler/modular_cosmetics/GAGS/json_configs/heartkin/gauntlets.json rename to modular_doppler/modular_cosmetics/GAGS/json_configs/hearthkin/gauntlets.json diff --git a/modular_doppler/modular_cosmetics/GAGS/json_configs/heartkin/gauntlets_worn.json b/modular_doppler/modular_cosmetics/GAGS/json_configs/hearthkin/gauntlets_worn.json similarity index 100% rename from modular_doppler/modular_cosmetics/GAGS/json_configs/heartkin/gauntlets_worn.json rename to modular_doppler/modular_cosmetics/GAGS/json_configs/hearthkin/gauntlets_worn.json diff --git a/modular_doppler/modular_cosmetics/GAGS/json_configs/heartkin/loincloth.json b/modular_doppler/modular_cosmetics/GAGS/json_configs/hearthkin/loincloth.json similarity index 100% rename from modular_doppler/modular_cosmetics/GAGS/json_configs/heartkin/loincloth.json rename to modular_doppler/modular_cosmetics/GAGS/json_configs/hearthkin/loincloth.json diff --git a/modular_doppler/modular_cosmetics/GAGS/json_configs/heartkin/loincloth_alt.json b/modular_doppler/modular_cosmetics/GAGS/json_configs/hearthkin/loincloth_alt.json similarity index 100% rename from modular_doppler/modular_cosmetics/GAGS/json_configs/heartkin/loincloth_alt.json rename to modular_doppler/modular_cosmetics/GAGS/json_configs/hearthkin/loincloth_alt.json diff --git a/modular_doppler/modular_cosmetics/GAGS/json_configs/heartkin/loincloth_alt_worn.json b/modular_doppler/modular_cosmetics/GAGS/json_configs/hearthkin/loincloth_alt_worn.json similarity index 100% rename from modular_doppler/modular_cosmetics/GAGS/json_configs/heartkin/loincloth_alt_worn.json rename to modular_doppler/modular_cosmetics/GAGS/json_configs/hearthkin/loincloth_alt_worn.json diff --git a/modular_doppler/modular_cosmetics/GAGS/json_configs/heartkin/loincloth_worn.json b/modular_doppler/modular_cosmetics/GAGS/json_configs/hearthkin/loincloth_worn.json similarity index 100% rename from modular_doppler/modular_cosmetics/GAGS/json_configs/heartkin/loincloth_worn.json rename to modular_doppler/modular_cosmetics/GAGS/json_configs/hearthkin/loincloth_worn.json diff --git a/modular_doppler/modular_cosmetics/GAGS/json_configs/heartkin/tailored_dress.json b/modular_doppler/modular_cosmetics/GAGS/json_configs/hearthkin/tailored_dress.json similarity index 100% rename from modular_doppler/modular_cosmetics/GAGS/json_configs/heartkin/tailored_dress.json rename to modular_doppler/modular_cosmetics/GAGS/json_configs/hearthkin/tailored_dress.json diff --git a/modular_doppler/modular_cosmetics/GAGS/json_configs/heartkin/tailored_dress_worn.json b/modular_doppler/modular_cosmetics/GAGS/json_configs/hearthkin/tailored_dress_worn.json similarity index 100% rename from modular_doppler/modular_cosmetics/GAGS/json_configs/heartkin/tailored_dress_worn.json rename to modular_doppler/modular_cosmetics/GAGS/json_configs/hearthkin/tailored_dress_worn.json diff --git a/modular_doppler/modular_cosmetics/GAGS/json_configs/heartkin/tunic.json b/modular_doppler/modular_cosmetics/GAGS/json_configs/hearthkin/tunic.json similarity index 100% rename from modular_doppler/modular_cosmetics/GAGS/json_configs/heartkin/tunic.json rename to modular_doppler/modular_cosmetics/GAGS/json_configs/hearthkin/tunic.json diff --git a/modular_doppler/modular_cosmetics/GAGS/json_configs/heartkin/tunic_worn.json b/modular_doppler/modular_cosmetics/GAGS/json_configs/hearthkin/tunic_worn.json similarity index 100% rename from modular_doppler/modular_cosmetics/GAGS/json_configs/heartkin/tunic_worn.json rename to modular_doppler/modular_cosmetics/GAGS/json_configs/hearthkin/tunic_worn.json diff --git a/modular_doppler/modular_crafting/readme.md b/modular_doppler/modular_crafting/readme.md new file mode 100644 index 0000000000000..9d12e928291bd --- /dev/null +++ b/modular_doppler/modular_crafting/readme.md @@ -0,0 +1,27 @@ +## Title: Modular Crafting + +MODULE ID: MODULAR_CRAFTING + +### Description: + +Module to add recipes unobtrusively without touching TG code, as well as serving as a place to add anything related to them. + +### TG Proc Changes: + +| proc | file | +| ----------------------------------- | -------------------------------- | +| /proc/make_datum_reference_lists() | code\__HELPERS\global_lists.dm | + +### Defines: + +N/A + +### Master file additions + +N/A + +### Included files that are not contained in this module: + +- `code\__HELPERS\~doppler_helpers\global_lists.dm` method to initialize recipes + +### Credits: diff --git a/modular_doppler/modular_mob_spawn/code/mob_spawn.dm b/modular_doppler/modular_mob_spawn/code/mob_spawn.dm index 2d03b49a52953..c3a0ca11c061c 100644 --- a/modular_doppler/modular_mob_spawn/code/mob_spawn.dm +++ b/modular_doppler/modular_mob_spawn/code/mob_spawn.dm @@ -1,9 +1,9 @@ /obj/effect/mob_spawn/ghost_role - /// Are we limited to a certain species type? LISTED TYPE + /// List of ghost role restricted species var/list/restricted_species = list() /obj/effect/mob_spawn/ghost_role/create(mob/mob_possessor, newname) - if((restricted_species && !(mob_possessor?.client?.prefs?.read_preference(/datum/preference/choiced/species) in restricted_species))) + if(restricted_species && !(mob_possessor?.client?.prefs?.read_preference(/datum/preference/choiced/species) in restricted_species)) var/text = "Current loaded character doesn't match required species: " var/i = 1 for(var/datum/species/speciesItem as anything in restricted_species) diff --git a/modular_doppler/modular_mob_spawn/readme.md b/modular_doppler/modular_mob_spawn/readme.md new file mode 100644 index 0000000000000..6065edd6db776 --- /dev/null +++ b/modular_doppler/modular_mob_spawn/readme.md @@ -0,0 +1,27 @@ +## Title: Modular Mob Spawn + +MODULE ID: MODULAR_MOB_SPAWN + +### Description: + +Allows ghost role spawners to have species restrictions. + +### TG Proc Changes: + +N/A + +### Defines: + +N/A + +### Master file additions + +N/A + +### Included files that are not contained in this module: + +N/A + +### Credits: + +Kaostico diff --git a/modular_doppler/modular_persistence/README.md b/modular_doppler/modular_persistence/README.md deleted file mode 100644 index f0ff7028236a6..0000000000000 --- a/modular_doppler/modular_persistence/README.md +++ /dev/null @@ -1,23 +0,0 @@ -## Modular Persistence - -Module ID: MODULAR_PERSISTENCE - -### Description: - -An extremely easy to extend per-character persistence file. Supports all the basic types, plus lists. - -Simply add the vars you want to have saved to `/datum/modular_persistence`, and make sure those var values are updated before round end so that they're saved. - -Loaded and saved on only station-side players for now. Will be expanded to support more in the future. - -### TG Proc/File Changes: - -- `code\modules\mob\dead\new_player\new_player.dm`: `/mob/dead/new_player/proc/AttemptLateSpawn` -- `code\controllers\subsystem\persistence.dm`: `/datum/controller/subsystem/persistence/proc/collect_data` - -### Defines: - -- `modular_nova\modules\modular_persistence\code\modular_persistence.dm`: `GLOB.modular_persistence_ignored_vars` - -### Credits: -- RimiNosha - Code diff --git a/modular_doppler/modular_persistence/code/modular_persistence.dm b/modular_doppler/modular_persistence/code/modular_persistence.dm deleted file mode 100644 index 69f5efbe91009..0000000000000 --- a/modular_doppler/modular_persistence/code/modular_persistence.dm +++ /dev/null @@ -1,138 +0,0 @@ -/// A list of vars that shouldn't be tracked by persistence. -GLOBAL_LIST_INIT(modular_persistence_ignored_vars, list( - "datum_flags", - "_datum_components", - "_listen_lookup", - "tgui_shared_states", - "gc_destroyed", - "_active_timers", - "_status_traits", - "_signal_procs", - "cached_ref", - "weak_reference", - "cooldowns", - "__auxtools_weakref_id", - "tag", - "type", - "parent_type", - "owner_brain", - "vars", - "stored_character_slot_index", -)) - -/obj/item/organ/internal/brain - /// The modular persistence data for a character. - var/datum/modular_persistence/modular_persistence - -/// Saves the contents of the modular persistence datum for the player's client to their file. -/datum/controller/subsystem/persistence/proc/save_modular_persistence() - for(var/mob/living/carbon/human/player in GLOB.human_list) - player.save_individual_persistence() - -/// Loads the contents of the player's modular_persistence file to their character. -/datum/controller/subsystem/persistence/proc/load_modular_persistence(obj/item/organ/internal/brain/brain) - if(!brain) - return FALSE - - if(!ishuman(brain.owner)) - return FALSE - - var/mob/living/carbon/human/player = brain.owner - - var/json_file = file("data/player_saves/[player.ckey[1]]/[player.ckey]/modular_persistence.json") - var/list/json = fexists(json_file) ? json_decode(file2text(json_file)) : null - - brain.modular_persistence = new(brain, islist(json) ? json["[player.mind.original_character_slot_index]"] : null) - -/// The master persistence datum. Add vars onto this in your own code. Just be aware that you'll need to use simple data types, such as strings, ints, and lists. -/datum/modular_persistence - /// The human that this is attached to. - var/datum/weakref/owner_brain - /// The owner's character slot index. - var/stored_character_slot_index - -/datum/modular_persistence/New(obj/item/organ/internal/brain/brain, list/persistence_data) - owner_brain = WEAKREF(brain) - . = ..() - - var/obj/item/organ/internal/brain/our_brain = owner_brain?.resolve() - if(!our_brain) - owner_brain = null - return - - RegisterSignal(our_brain, COMSIG_QDELETING, PROC_REF(on_brain_deleted)) - stored_character_slot_index = our_brain.owner.mind?.original_character_slot_index - - if(!persistence_data) - return - - for(var/var_name in vars) - if(var_name in GLOB.modular_persistence_ignored_vars) - continue - - var/var_entry = persistence_data[var_name] - - if(var_entry) - vars[var_name] = var_entry - - if(!our_brain.owner) - CRASH("Tried to load modular persistence on a brain with no owner! How did this happen?! (\ref[brain], [brain.brainmob?.ckey], [brain])") - -/datum/modular_persistence/Destroy(force) - owner_brain = null - return ..() - -/datum/modular_persistence/proc/on_brain_deleted(datum/source) - SIGNAL_HANDLER - - qdel(src) - -// On a base datum, this should be empty, at a glance. -/datum/modular_persistence/proc/serialize_contents_to_list() - var/list/returned_list = list() - - var/obj/item/organ/internal/brain/our_brain = owner_brain?.resolve() - if(!our_brain) - owner_brain = null - return - - for(var/var_name in vars) - if(var_name in GLOB.modular_persistence_ignored_vars) - continue - - var/var_entry = vars[var_name] - - if(!isnull(var_entry)) - returned_list[var_name] = var_entry - - return returned_list - -/// Saves the held persistence data to where it needs to go. -/datum/modular_persistence/proc/save_data(var/ckey) - var/obj/item/organ/internal/brain/our_brain = owner_brain?.resolve() - if(!our_brain) - owner_brain = null - return - - ckey = replacetext(ckey || our_brain.owner?.ckey || our_brain.brainmob?.ckey, "@", "") - if(!our_brain.owner && !our_brain.brainmob) - CRASH("Modular persistence save called on a brain with no owning mob or brainmob! How did this happen?! (\ref[our_brain], [our_brain])") - if(!ckey) - CRASH("Modular persistence save called on a brain with no ckey! How did this happen?! (\ref[our_brain], [our_brain])") - - var/json_file = file("data/player_saves/[ckey[1]]/[ckey]/modular_persistence.json") - var/list/json = fexists(json_file) ? json_decode(file2text(json_file)) : list() - fdel(json_file) - - if(!islist(json)) - json = list() - - json["[stored_character_slot_index]"] = serialize_contents_to_list() - WRITE_FILE(json_file, json_encode(json)) - return TRUE - -/// Saves the persistence data for the owner. -/mob/living/carbon/human/proc/save_individual_persistence(var/ckey) - var/obj/item/organ/internal/brain/brain = get_organ_slot(ORGAN_SLOT_BRAIN) - - return brain?.modular_persistence?.save_data(ckey) diff --git a/modular_doppler/modular_sounds/readme.md b/modular_doppler/modular_sounds/readme.md new file mode 100644 index 0000000000000..ff42c5b4b201e --- /dev/null +++ b/modular_doppler/modular_sounds/readme.md @@ -0,0 +1,23 @@ +## Title: Modular sounds + +MODULE ID: MODULAR_SOUNDS + +### Description: + +Module to add sounds in an unobtrusive way without touching TG code + +### TG Proc Changes: + +| proc | file | +| ------------------------ | -------------------- | +| `/proc/get_sfx(soundin)` | `code\game\sound.dm` | + +### Defines: + +- `code\__DEFINES\~doppler_defines\sound.dm` + +### Included files: + +N/A + +### Credits: diff --git a/modular_doppler/modular_traits/readme.md b/modular_doppler/modular_traits/readme.md index 0591520685fe6..18c230c7fe1d2 100644 --- a/modular_doppler/modular_traits/readme.md +++ b/modular_doppler/modular_traits/readme.md @@ -4,22 +4,22 @@ MODULE ID: MODULAR_TRAITS ### Description: -Modular Traits is where we are going to code anything related to traits. All the new quirks need to be added in code\controllers\subsystem\processing\quirks.dm, on the GLOBAL_LIST_INIT_TYPED for them to be available before the subsystem inits. +Anything related to new traits. All the new quirks need to be added in `code\controllers\subsystem\processing\quirks.dm`, on the `GLOBAL_LIST_INIT_TYPED` for them to be available before the subsystem inits. ### TG Proc Changes: -- N/A +N/A ### Defines: -- code\__DEFINES\~doppler_defines\traits.dm +- `code\__DEFINES\~doppler_defines\traits.dm` ### Master file additions -- N/A +N/A ### Included files that are not contained in this module: -- N/A +- `code\controllers\subsystem\processing\quirks.dm` original TG list of quirks ### Credits: diff --git a/modular_doppler/obj_flags_doppler/readme.md b/modular_doppler/obj_flags_doppler/readme.md new file mode 100644 index 0000000000000..0444237141c93 --- /dev/null +++ b/modular_doppler/obj_flags_doppler/readme.md @@ -0,0 +1,25 @@ +## Title: Obj Flags Doppler + +MODULE ID: OBJ_FLAGS_DOPPLER + +### Description: + +Currently, it's only function is to extend the `/obj` with `obj_flags_doppler`. Basically Doppler Shift version of `obj_flags`, to prevent any potential future conflict. Honestly, I didn't know where to put this. + +### TG Proc Changes: + +N/A + +### Defines: + +N/A + +### Master file additions + +N/A + +### Included files that are not contained in this module: + +- `code\_globalvars\~doppler_globalvars\bitfields.dm` + +### Credits: diff --git a/modular_doppler/reagent_forging/code/forge_clothing.dm b/modular_doppler/reagent_forging/code/forge_clothing.dm index ffdf7f5341097..e4ccfd58ffbf0 100644 --- a/modular_doppler/reagent_forging/code/forge_clothing.dm +++ b/modular_doppler/reagent_forging/code/forge_clothing.dm @@ -124,22 +124,22 @@ . = ..() AddComponent(/datum/component/reagent_clothing, ITEM_SLOT_GLOVES) -// /obj/item/clothing/neck/collar/reagent_clothing -// name = "reagent collar" -// desc = "A collar that is ready to be worn for certain individuals." -// icon = 'modular_doppler/modular_items/lewd_items/icons/obj/lewd_clothing/lewd_neck.dmi' -// worn_icon = 'modular_doppler/modular_items/lewd_items/icons/mob/lewd_clothing/lewd_neck.dmi' -// icon_state = "collar_cyan" -// inhand_icon_state = null -// body_parts_covered = NECK -// slot_flags = ITEM_SLOT_NECK -// w_class = WEIGHT_CLASS_SMALL -// material_flags = MATERIAL_EFFECTS | MATERIAL_ADD_PREFIX | MATERIAL_GREYSCALE | MATERIAL_COLOR -// obj_flags_doppler = ANVIL_REPAIR - -// /obj/item/clothing/neck/collar/reagent_clothing/Initialize(mapload) -// . = ..() -// AddComponent(/datum/component/reagent_clothing, ITEM_SLOT_NECK) +/obj/item/clothing/neck/collar/reagent_clothing + name = "reagent collar" + desc = "A collar that is ready to be worn for certain individuals." + icon = 'modular_doppler/reagent_forging/icons/obj/forge_clothing.dmi' + worn_icon = 'modular_doppler/reagent_forging/icons/mob/clothing/forge_clothing.dmi' + icon_state = "collar" + inhand_icon_state = null + body_parts_covered = NECK + slot_flags = ITEM_SLOT_NECK + w_class = WEIGHT_CLASS_SMALL + material_flags = MATERIAL_EFFECTS | MATERIAL_ADD_PREFIX | MATERIAL_GREYSCALE | MATERIAL_COLOR + obj_flags_doppler = ANVIL_REPAIR + +/obj/item/clothing/neck/collar/reagent_clothing/Initialize(mapload) + . = ..() + AddComponent(/datum/component/reagent_clothing, ITEM_SLOT_NECK) /obj/item/restraints/handcuffs/reagent_clothing name = "reagent handcuffs" diff --git a/modular_doppler/reagent_forging/icons/mob/clothing/forge_clothing.dmi b/modular_doppler/reagent_forging/icons/mob/clothing/forge_clothing.dmi index bab8703cd0d06033864944d6ecf3a0072fcdc0f7..6b74fa160261b09c92c63146b8486b8fb5ecac7c 100644 GIT binary patch delta 875 zcmV-x1C;#m3cv?{iBL{Q4GJ0x0000DNk~Le0001>0001h1Oos70Det>C;$KeDo{*R zMF0Q*ii)1X!O83E>q$pkUaRXua;`f_aV=-0C=2JR&a8WJY#gNIu2mr8TPut^EFth*w0;@?xK~!jg?V3++)G!prZBL*Z7RgHv5ZiMAVqYL0%>mdH zl^q+X*s-cK2jB{@Wsf)j5;s6xfYab1RO9zT99i+A75-_e_RBnfaUB17w#wLl0#`Dx zAy`vqHPpuTIsJbeNY#uP4R^h-WJW(Gd;>yGL*^JCvl>>=W%bM7ZL)XlLZR>=fO`5_ z(th;IF_aa=Cl@Ul*L|RUc-w~&fTt&}nXpEA*@p!nD;L>XsI#fr6n!x!I5yQs-T?V;Qbxf~97izHdCD^oum*#icS`*W2I8Z3R zJ8Ri3>s5Br4k*8K`Z|VHyfIUhJA3e zzkkaG&8CBF45wLt5Ft$XYp&1n!Ts+I@k>F5Q}c4Opcy^nnJna@+D)6HN-t>7f$Zcw zu3J=M5)~}ybNsx98h4w`$(g|0S2u6vLZMJ76dndI{(LUHVNYI%8i|RgF~6&~H!p9) z3#Vh7SMNjp@tPL7eiyCb>B~1{!0xcTI^FyT_4f~-aKMb8pX1-NyI-ODdb<>N&$G3F zRd~PI0wZ!CHHl59y#HXgUyn&bWd2u*LZR@u`3)fmQ;!--4TS&z002ovPDHLkV1nIP BlEwf4 delta 1288 zcmV+j1^4>E2k;6diBL{Q4GJ0x0000DNk~Le0001h0001h2nGNE0K-0E%K!iXg^_4_ zf4CGYE4cc(fPDx6DgQ*hHNzE(000E0Nkla#?t}Y}ws-E`-PBm#%X7bI!LD7ux|`a9`_EJn`n(0re@e^vsdSlb zg+$THA6p+eW;Xz9X(kQoE5d)THqBSDZ7Z_|nWweejk;^<~Xno|$8ap)hSTLK~*kdhEuUn6Uz2i$7(?pH` zq8>1y@j_W6?WXwC7bVp`>Eg+$PXFjXIO&1x}UKA&#Y^&TI; z-A%Q%sW9f?;Nfm+UDK`G`_;Axf5o@?YU~?|?}vh#@l#{V9B~Aa?ti4~BX@qY_5u8k z)zDa@_gd|UX?|m4UHV?cj^NNTN9+iuF(P+90sL=@#w&l^Z6eRUtucOd8EVGQIuGE3 zr)TBt{fG)!Yy7A()Q+Fs0DN$rh&b;QZB1*6??siNcKq3`B|Y3S*6pNwfBvmb#tg;x zddF{FhF0;j3VC*RwjDdh*0K8D-d?jVQ1NX+b^LAYSXf&|%lO7$iPKisI_4Ow51Xn^ zN*Z4FwSci>?1*D;#ka~=_is~O7LDLnzP~onOIn8C4Iu09vs7{ym?n?_#*dUNvf?@Ct>VE?pYTGGCj|M81WtxP325mXpk zF@0Hj^Z>pL(dz*K0000000000000000000000000K%}f&iN|h3e~!96xp#aY%dFvc z?4{+&P7|kmG(I7Nk|adr>FF7NC`X@i^F`$;Ok<9fXYRbR8h~$UmYqWhiY!Z4#N%3q z($nd6RD6r&a|0Qzh{!~de&ze*UAc9T)c_R4r)bmbsSIMZ`1$)RUG{!Ne4hbCJ&;dX z7nP|@DPoi=e#uajf87I&rA3QMm*y*6G3~V~BZ|6UzcEBSu*%2Ka)&%MYz=JT)80qy z{ir8~`SSF(v3%Mb@bE?4y98;5{lJqQT{eDo^b?&uRc; zk0Ox{tVG$bW=p4c5LOK)E69lyuCODw6U$pjJp_M@Dc>Xxac$qRbN zkDhm_(t0wpS~7&>-uGVnKKb79qvpL-N!ccE4%Lm1xi>x9_iNm+**kvpyi1kVlbLJ) yOR`?n*iw4O?=kNZYs;1b0000000000*5enS>RHgO#nagU00002bl$biBL{Q4GJ0x0000DNk~Le0001B0000$1Oos702dl>JpcdzDo{*R zMF0Q*Nk?3Yik`y3$?NOuGBZ;V=-0C=2JR&a8WJY#gNIu2mqt?Pt1C>0eAoa0fb3JK~zYI?Nvce!!QtZ61C^X;Q?LS4`{vq0P#M63jz*E zJ%M;Yp%P~heLQJYFyid;i9u!vr^U_wK2 zIVdp5Fb5W)=4Z%K*~clDuegrKnA3eVNCCGtm$z8-l^ z5rm~eg9b5VXc1jZ#|S(kQ<8_!x+pDomeScGSf0QnK^1>NhlLUf6kkbcQ)?chPL@hP zE3*I6h!G?H9?IGGoF2uTLq+WK$?56UDksn_hmKB*=z6o=-Dda|gt_z7@51Th+1>gk z(;|>t~(dpdu5*{(B=IH8Qjm~wM+ z|NcDOfI~VqAaI6=%(;Af9p-aDb#bF*=BSShzYD0YwuT((u*J`*BmNCO0bS%pGL5Y~ Q%m4rY07*qoM6N<$f|RuUjQ{`u delta 887 zcmV--1Bm>Y1>y%KiBL{Q4GJ0x0000DNk~Le0000$0000$2nGNE0IF$m-T(jqg^_4_ zf4CGYE4cc(fPDx6AFM>NVzNX~0009RNkl6&p5QR4}T4`Yst5g;y(JEC^ zDJm+0=`3wxAIm^ey(lQ8v9Ogqk^BL%5D6-#GOeIC>R-9$JUx%&vb%TgbsvJx2O+t; zn>%}EXZJ45gy1-i<2a7af;}$5*sY~>kBY;BV3BcRBiRItOZEb^uORehCN#K6>~hq}pqu@61I(pDobo z3`iY%Ft)k1o*X~P2%uO}+8QN_4oIyyMWJ0I0OTA|gI{-w?3tpg-{t<1bpXZl#DxLC z%MaSM55~C_Cb{zZ?$}NryIBWde>E9a>RoNuKAi-krnVz;Uji-!ze-0DV18%T0l6Dh z+fA$X1xTUz)M3~5iOi98KrXyet6B=nn$Y=)z23xQ9LI4S$8j9TaU92S9LI6~d60}n zKBLS3^h%G%86z->ijbV$R0RmcOWM4#&ZV;h;!>Fiv*EsWe~R2~)Cm-ie|!NGGn-rM z&BaU0t#dinXA&v#b8~0H@e?P*%=D?j*KZ%UyS%rJgZGCG-VJdJ3+KYM>nmY)c5$%3 z|6*IkBPVeG!M(7wG=J28I;`HhJs3WFTAYh{wOH(sD~TaYOmrz!Dgp7D@fi+ZjJIGBXCS95=@hX_*5EPe{+Wllcay@gjhUDIUzNUQGx!P6U-$t5U*7tYEYjsrbe0^ z;_CJ+2AMHltSX9;|R|k76}JiaDZPlc#z% Date: Wed, 4 Sep 2024 01:38:46 -0300 Subject: [PATCH 19/28] In theory, this should fix the indentation error --- code/_globalvars/~doppler_globalvars/bitfields.dm | 1 + 1 file changed, 1 insertion(+) diff --git a/code/_globalvars/~doppler_globalvars/bitfields.dm b/code/_globalvars/~doppler_globalvars/bitfields.dm index 315c2e0ec5cd6..a83cc511e6ffa 100644 --- a/code/_globalvars/~doppler_globalvars/bitfields.dm +++ b/code/_globalvars/~doppler_globalvars/bitfields.dm @@ -1,3 +1,4 @@ +///reagent forging module DEFINE_BITFIELD(obj_flags_doppler, list( "ANVIL_REPAIR" = ANVIL_REPAIR, )) From eb49ff4de33365ef50362138669106a55c0135da Mon Sep 17 00:00:00 2001 From: Kaostico Date: Wed, 4 Sep 2024 03:32:10 -0300 Subject: [PATCH 20/28] forgot this on this readme --- modular_doppler/stone/readme.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/modular_doppler/stone/readme.md b/modular_doppler/stone/readme.md index b3a6e1d9bfa6a..033a152106fac 100644 --- a/modular_doppler/stone/readme.md +++ b/modular_doppler/stone/readme.md @@ -20,6 +20,6 @@ N/A ### Included files that are not contained in this module: -N/A +- `code\__DEFINES\icon_smoothing.dm` added the smoothing group `SMOOTH_GROUP_STONE_WALLS`used in `/turf/closed/wall/mineral/stone` ### Credits: From 6dc1039bb5a168e07fd3794998ffd3620ab2233b Mon Sep 17 00:00:00 2001 From: Kaostico Date: Wed, 4 Sep 2024 03:35:12 -0300 Subject: [PATCH 21/28] Update bitfields.dm This should fix it Signed-off-by: Kaostico --- code/_globalvars/~doppler_globalvars/bitfields.dm | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/code/_globalvars/~doppler_globalvars/bitfields.dm b/code/_globalvars/~doppler_globalvars/bitfields.dm index a83cc511e6ffa..2795c9528166d 100644 --- a/code/_globalvars/~doppler_globalvars/bitfields.dm +++ b/code/_globalvars/~doppler_globalvars/bitfields.dm @@ -1,4 +1,4 @@ ///reagent forging module DEFINE_BITFIELD(obj_flags_doppler, list( - "ANVIL_REPAIR" = ANVIL_REPAIR, + "ANVIL_REPAIR" = ANVIL_REPAIR, )) From b2a925f98fa2bc05fa97e51765ec5720f49f4f6e Mon Sep 17 00:00:00 2001 From: Kaostico Date: Wed, 4 Sep 2024 10:41:35 -0300 Subject: [PATCH 22/28] rings for the reagent forging god --- .../modular_cosmetics/code/hands/rings.dm | 37 ++++++++++++++++++ .../modular_cosmetics/code/storage/rings.dm | 28 +++++++++++++ .../icons/mob/hands/rings.dmi | Bin 0 -> 331 bytes .../icons/mob/inhands/rings_lefthand.dmi | Bin 0 -> 352 bytes .../icons/mob/inhands/rings_righthand.dmi | Bin 0 -> 348 bytes .../icons/obj/hands/rings.dmi | Bin 0 -> 665 bytes .../icons/obj/storage/rings.dmi | Bin 0 -> 446 bytes tgstation.dme | 2 + 8 files changed, 67 insertions(+) create mode 100644 modular_doppler/modular_cosmetics/code/hands/rings.dm create mode 100644 modular_doppler/modular_cosmetics/code/storage/rings.dm create mode 100644 modular_doppler/modular_cosmetics/icons/mob/hands/rings.dmi create mode 100644 modular_doppler/modular_cosmetics/icons/mob/inhands/rings_lefthand.dmi create mode 100644 modular_doppler/modular_cosmetics/icons/mob/inhands/rings_righthand.dmi create mode 100644 modular_doppler/modular_cosmetics/icons/obj/hands/rings.dmi create mode 100644 modular_doppler/modular_cosmetics/icons/obj/storage/rings.dmi diff --git a/modular_doppler/modular_cosmetics/code/hands/rings.dm b/modular_doppler/modular_cosmetics/code/hands/rings.dm new file mode 100644 index 0000000000000..6e24f4796b70a --- /dev/null +++ b/modular_doppler/modular_cosmetics/code/hands/rings.dm @@ -0,0 +1,37 @@ +/obj/item/clothing/gloves/ring + icon = 'modular_doppler/modular_cosmetics/icons/obj/hands/rings.dmi' + worn_icon = 'modular_doppler/modular_cosmetics/icons/mob/hands/rings.dmi' + lefthand_file = 'modular_doppler/modular_cosmetics/icons/mob/inhands/rings_lefthand.dmi' + righthand_file = 'modular_doppler/modular_cosmetics/icons/mob/inhands/rings_righthand.dmi' + name = "gold ring" + desc = "A tiny gold ring, sized to wrap around a finger." + gender = NEUTER + w_class = WEIGHT_CLASS_TINY + icon_state = "ringgold" + inhand_icon_state = "ringgold" + worn_icon_state = "gring" + body_parts_covered = 0 + strip_delay = 4 SECONDS + clothing_traits = list(TRAIT_FINGERPRINT_PASSTHROUGH) + +/obj/item/clothing/gloves/ring/suicide_act(mob/living/carbon/user) + user.visible_message(span_suicide("\[user] is putting the [src] in [user.p_their()] mouth! It looks like [user] is trying to choke on the [src]!")) + return OXYLOSS + + +/obj/item/clothing/gloves/ring/diamond + name = "diamond ring" + desc = "An expensive ring, studded with a diamond. Cultures have used these rings in courtship for a millenia." + icon_state = "ringdiamond" + inhand_icon_state = "ringdiamond" + worn_icon_state = "dring" + +/obj/item/clothing/gloves/ring/diamond/attack_self(mob/user) + user.visible_message(span_warning("\The [user] gets down on one knee, presenting \the [src]."),span_warning("You get down on one knee, presenting \the [src].")) + +/obj/item/clothing/gloves/ring/silver + name = "silver ring" + desc = "A tiny silver ring, sized to wrap around a finger." + icon_state = "ringsilver" + inhand_icon_state = "ringsilver" + worn_icon_state = "sring" diff --git a/modular_doppler/modular_cosmetics/code/storage/rings.dm b/modular_doppler/modular_cosmetics/code/storage/rings.dm new file mode 100644 index 0000000000000..8ec270b1fc6a3 --- /dev/null +++ b/modular_doppler/modular_cosmetics/code/storage/rings.dm @@ -0,0 +1,28 @@ +/* + * Ring Box + */ + +/obj/item/storage/fancy/ringbox + name = "ring box" + desc = "A tiny box covered in soft red felt made for holding rings." + icon = 'modular_doppler/modular_cosmetics/icons/obj/storage/rings.dmi' + icon_state = "gold ringbox" + base_icon_state = "gold ringbox" + w_class = WEIGHT_CLASS_TINY + spawn_type = /obj/item/clothing/gloves/ring + spawn_count = 1 + +/obj/item/storage/fancy/ringbox/Initialize(mapload) + . = ..() + atom_storage.max_slots = 1 + atom_storage.can_hold = typecacheof(list(/obj/item/clothing/gloves/ring)) + +/obj/item/storage/fancy/ringbox/diamond + icon_state = "diamond ringbox" + base_icon_state = "diamond ringbox" + spawn_type = /obj/item/clothing/gloves/ring/diamond + +/obj/item/storage/fancy/ringbox/silver + icon_state = "silver ringbox" + base_icon_state = "silver ringbox" + spawn_type = /obj/item/clothing/gloves/ring/silver diff --git a/modular_doppler/modular_cosmetics/icons/mob/hands/rings.dmi b/modular_doppler/modular_cosmetics/icons/mob/hands/rings.dmi new file mode 100644 index 0000000000000000000000000000000000000000..696cc75c32a8f264878c9241b4fee2cf6aede1d9 GIT binary patch literal 331 zcmeAS@N?(olHy`uVBq!ia0vp^3xK$Ri5WDsf;oBsb7 zow~ddD9%_CjJaWn(XeIgchCnG~WBthraiSUmOW?A@@qptKydw`@Jp00i_>zopr0M>AO;Q#;t literal 0 HcmV?d00001 diff --git a/modular_doppler/modular_cosmetics/icons/mob/inhands/rings_lefthand.dmi b/modular_doppler/modular_cosmetics/icons/mob/inhands/rings_lefthand.dmi new file mode 100644 index 0000000000000000000000000000000000000000..58a42f2c7f88fdb5b2919f2f7b987f18a6db78e4 GIT binary patch literal 352 zcmeAS@N?(olHy`uVBq!ia0vp^4M3d0!VDzUL(;2<h3}i0gp^2mb&6fBpLPsZ*zJ z0-=fkr`~8pe_!zhDN3XE)M-oVu!zh!U67;^d;tf|AVqJO+k}Il*BC zMWx@r1Q&e#`b5iHSL@uF^T8WJ4K5l#c%*aQNAn~@QBUs<3*#W;%f?;`a~@4PGATqM zc%_E1zOAaUp}D=jYiGBy>gE*^OQv=kuhlR#7d>L;5*j^cCi9jijioPtT3Vb92`l(o z%xEpaz?5QI-kJC&ALx=CPZ!6Kh}O5)4EY)qcv=%hre0kv;s4+PqfM9a^Ku=P)(Jvl zpX)DY-@4Fe!OmcBB3iWh=Y*Olxd^?J+b?~u+*zHvY@dSu?X w$zopr0Fuv+D*ylh literal 0 HcmV?d00001 diff --git a/modular_doppler/modular_cosmetics/icons/mob/inhands/rings_righthand.dmi b/modular_doppler/modular_cosmetics/icons/mob/inhands/rings_righthand.dmi new file mode 100644 index 0000000000000000000000000000000000000000..a3e3f09605aa58d6107178e167ba5d951b158d0d GIT binary patch literal 348 zcmeAS@N?(olHy`uVBq!ia0vp^4M3d0!VDzUL(;2<h3}i0gp^2mb&6KXvNV>({Su z0kT|MgO@Z66eXY8Xp`{DK)Ap4~_Ta_Xu=B1&9Ri<65o3raHc^B5Q^<^+co z6qSDe5?t`{>k}<+U9EFx&IfM@HMnT};E~RGAI*~tMLoScER2JUFB^L)%y~5F$fOX3 z;FTK2`nIaZhUWJAuASY+s+(6xEScJEyjH`|T=a;UOK9|*nao?7G?u>nX=!mbB&^_T zF{8Bv15=7=d1vCAe4tA*JY5_^B3j>G+s%7Gfu|+$`QEmrIuisnj5uPWzOBEM#KI&V zIP3rGcLL$jEDQ<0&9RpwUy7Y=5-ZMHd}nH-X-eY0H^~C(o7or`cKzGWzw6X*pqVu} s(r;$X^C~~0b0kTx>+-xk_6*a-XDYKyGmLkd0hDL(boFyt=akR{0K~J5FaQ7m literal 0 HcmV?d00001 diff --git a/modular_doppler/modular_cosmetics/icons/obj/hands/rings.dmi b/modular_doppler/modular_cosmetics/icons/obj/hands/rings.dmi new file mode 100644 index 0000000000000000000000000000000000000000..9cd9d5cd81621c3fb2e96a12ed3131fafd74f0c4 GIT binary patch literal 665 zcmV;K0%rY*P)00001bW%=J06^y0W&i*Hg?dz2bVOxyV{&P5bZKvH004NLQ&wiF3FFid!Cq;>i zGbOXA7${`O#hF%=n41b=qbN+uNleZrN@YrBVs3sOai$h$<^WxdOR2JgtDg(lYXH#9 zLAmdd+&%yR0ZK_kK~z|U?UKuKgdh+_8QzRIQ3PQ|iIe#M|CnZyCCw^}q>8)HMSD(l zwU>~doGsZb@%!L#J95}C(VqBwhX`~d59oQ9krZr}egE5j)Yi-@Y)b*-( z31Se#FaSE*8zxW+4xll?MasgH@m3f7@C|{GbOfH3XC<7eLZUnf1brJvxBw<#94^RE z0il9U(`0R(F9vWx(BDX*0+Ypyq{|8%{fWgu+db48??6vaPfyS9XP%vNjrp>8@A0t- zW?jL7eh^cP;6VAixj&r4cSt6I0pB4QV?udvbwk>XN#5t25yNYPB6zP0;=b>I9{E`p z%pZ^NAh=*jsqo}@VuJOX3ocaWOHBR%-j`=X02jan(SIHXTmTUex4IC*w$*t;eDvpe z=8W;gK?U-L7s*2f&fF?es{=2CZ}zaK=RfBQBbXB+RT1}s00000NkvXXu0mjfj^#D= literal 0 HcmV?d00001 diff --git a/modular_doppler/modular_cosmetics/icons/obj/storage/rings.dmi b/modular_doppler/modular_cosmetics/icons/obj/storage/rings.dmi new file mode 100644 index 0000000000000000000000000000000000000000..81b89718e753791bcdc69714e1cc8ba803e4e0f1 GIT binary patch literal 446 zcmV;v0YUzWP)MD!)_ zvtFgTMl#+^OKRI0$oPOYnSuO)dgp#XL_}BcGoHN-;fbn(iOi o9OL_d?0vw3@1Xnu?gK=q6XnZU`G+C`zyJUM07*qoM6N<$f>l?$djJ3c literal 0 HcmV?d00001 diff --git a/tgstation.dme b/tgstation.dme index cfac8ec295c03..468dab3b16ec0 100644 --- a/tgstation.dme +++ b/tgstation.dme @@ -6441,7 +6441,9 @@ #include "modular_doppler\languages\language_datums.dm" #include "modular_doppler\modular_antagonist\code\antag_datum.dm" #include "modular_doppler\modular_cosmetics\code\jacket_pockets.dm" +#include "modular_doppler\modular_cosmetics\code\hands\rings.dm" #include "modular_doppler\modular_cosmetics\code\neck\collar.dm" +#include "modular_doppler\modular_cosmetics\code\storage\rings.dm" #include "modular_doppler\modular_cosmetics\code\suits\jacket.dm" #include "modular_doppler\modular_cosmetics\GAGS\greyscale_configs_neck.dm" #include "modular_doppler\modular_crafting\code\crafting_extended.dm" From 033f9c11995c157f65cf36b640eb471448105de8 Mon Sep 17 00:00:00 2001 From: Kaostico Date: Wed, 4 Sep 2024 11:32:29 -0300 Subject: [PATCH 23/28] this should be it, PROMISE: the sad story of a boy who would forgor --- code/_globalvars/traits/_traits.dm | 8 ++++++++ code/_globalvars/traits/admin_tooling.dm | 8 ++++++++ code/modules/unit_tests/turf_icons.dm | 2 +- 3 files changed, 17 insertions(+), 1 deletion(-) diff --git a/code/_globalvars/traits/_traits.dm b/code/_globalvars/traits/_traits.dm index dcda2365c4b0f..0dfcc67c5e1be 100644 --- a/code/_globalvars/traits/_traits.dm +++ b/code/_globalvars/traits/_traits.dm @@ -658,6 +658,14 @@ GLOBAL_LIST_INIT(traits_by_type, list( "TRAIT_TURF_IGNORE_SLIPPERY" = TRAIT_TURF_IGNORE_SLIPPERY, "TRAIT_TURF_IGNORE_SLOWDOWN" = TRAIT_TURF_IGNORE_SLOWDOWN, ), + // DOPPLER EDIT ADDITION START - DOPPLER TRAITS + /obj/item/clothing/suit/jacket/doppler = list( + "TRAIT_CURRENTLY_GLASSBLOWING" = TRAIT_CURRENTLY_GLASSBLOWING, + "TRAIT_FELINE" = TRAIT_FELINE, + "TRAIT_GLASSBLOWING" = TRAIT_GLASSBLOWING, + "TRAIT_XENOARCH_QUALIFIED" = TRAIT_XENOARCH_QUALIFIED, + ), + // DOPPLER EDIT ADDITION END )) /// value -> trait name, list of ALL traits that exist in the game, used for any type of accessing. diff --git a/code/_globalvars/traits/admin_tooling.dm b/code/_globalvars/traits/admin_tooling.dm index 98c3fd6ab1fca..585d121e6ce67 100644 --- a/code/_globalvars/traits/admin_tooling.dm +++ b/code/_globalvars/traits/admin_tooling.dm @@ -357,6 +357,14 @@ GLOBAL_LIST_INIT(admin_visible_traits, list( /obj/item/organ/internal/lungs = list( "TRAIT_SPACEBREATHING" = TRAIT_SPACEBREATHING, ), + // DOPPLER EDIT ADDITION START - DOPPLER TRAITS + /obj/item/clothing/suit/jacket/doppler = list( + "TRAIT_CURRENTLY_GLASSBLOWING" = TRAIT_CURRENTLY_GLASSBLOWING, + "TRAIT_FELINE" = TRAIT_FELINE, + "TRAIT_GLASSBLOWING" = TRAIT_GLASSBLOWING, + "TRAIT_XENOARCH_QUALIFIED" = TRAIT_XENOARCH_QUALIFIED, + ), + // DOPPLER EDIT ADDITION END )) /// value -> trait name, generated as needed for adminning. diff --git a/code/modules/unit_tests/turf_icons.dm b/code/modules/unit_tests/turf_icons.dm index 6f37117289880..d7e415a408ec2 100644 --- a/code/modules/unit_tests/turf_icons.dm +++ b/code/modules/unit_tests/turf_icons.dm @@ -1,6 +1,6 @@ /// Makes sure turf icons actually exist. :) /datum/unit_test/turf_icons - var/modular_mineral_turf_file //= 'icons/turf/mining.dmi' //MODULARITY SUPPORT - insert your snowflake MAP_SWITCH icon file here if you use that define. + var/modular_mineral_turf_file = 'modular_doppler/xenoarch/icons/mining.dmi' //MODULARITY SUPPORT - insert your snowflake MAP_SWITCH icon file here if you use that define. /datum/unit_test/turf_icons/Run() for(var/turf/turf_path as anything in (subtypesof(/turf) - typesof(/turf/closed/mineral))) From 3ea5261e62bc4bd6c0709b2d8f122a808c5c21a3 Mon Sep 17 00:00:00 2001 From: Kaostico Date: Wed, 4 Sep 2024 12:35:01 -0300 Subject: [PATCH 24/28] in my defense, I didn't even know this existed! --- ...ds__datum_species_human_felinid_primitive.png | Bin 0 -> 1038 bytes 1 file changed, 0 insertions(+), 0 deletions(-) create mode 100644 code/modules/unit_tests/screenshots/screenshot_humanoids__datum_species_human_felinid_primitive.png diff --git a/code/modules/unit_tests/screenshots/screenshot_humanoids__datum_species_human_felinid_primitive.png b/code/modules/unit_tests/screenshots/screenshot_humanoids__datum_species_human_felinid_primitive.png new file mode 100644 index 0000000000000000000000000000000000000000..762355d1c894dd0e585d12392dbf001f3230af87 GIT binary patch literal 1038 zcmV+p1o8WcP)Ja(dxgnl)tu#iHYH_rm(QEynAsqI6;n(lNuT!R$61Tv$J$} zfOmU?QBPYD6ci#RCKwzXr>eHp*WZbYq9i0LEiE(4&C%}e?j0T^rKz@bae}|j1cd+q z00DGTPE!Ct=GbNc003orR9JLGWpiV4X>fFDZ*Bkpc$`yKaB_9`^iy#0_2eo`Eh^5; z&r`5fFwryM;w;ZhDainGjE%TBGg33tGfE(w;*!LYR3KAHiHkEOv#1!Po{KZBC^0t` z#5UwoR&e!m0hcIB763~k;DL9|0H>zc0e7!sTc#1zH~U<^L`7$dep(2K|N8AZ;_TJ^;&K8y!z)jZc27E1W1@1-VXU5#FX{ZOGghgbl6SzOHvvV}4#@`q*_X;0_(6a>4tD_swtjt2 zpQe|WN%7b8E&crZdY)!APkd3;=V{TWxvHzn`Fy!t)%C&`-_U=KiJkKcDy-4FZvZWI z&X4%6;Xz%SK&IDvCwE6@c3SsFCQ$!?{x2^<+VB7%0~|f}>>{M#dRDDaj(CIJo~&)G zfDy@Bl-K&h;G49!*0%NlG8g0;fICJk882&N!f=pt;r6&CXpPQ|s@i%779Zo00*y5+c^ifxT}|pB^rPbbKyo`0i?C0lyjb@O%q~1mfN&oaI%+ z>`>rb(c=L_fIA+ao}~<)pN>cNIS8|A$&T9Xn^kh#0qGB+8Gj?l@l0sOFN9Y7e*gne zlI9j*MnP%;mge6e% Date: Thu, 5 Sep 2024 04:53:12 -0300 Subject: [PATCH 25/28] Update language.dm Totally forgot about that other language. Changed description. Doing this commit from the cellphone in bed at 5 in the morning. Why am I like this? Signed-off-by: Kaostico --- modular_doppler/hearthkin/primitive_catgirls/code/language.dm | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/modular_doppler/hearthkin/primitive_catgirls/code/language.dm b/modular_doppler/hearthkin/primitive_catgirls/code/language.dm index 2d5ae205c967a..8a97197d279fc 100644 --- a/modular_doppler/hearthkin/primitive_catgirls/code/language.dm +++ b/modular_doppler/hearthkin/primitive_catgirls/code/language.dm @@ -1,7 +1,7 @@ /datum/language/primitive_catgirl name = "Ættmál" desc = "A liturgical language passed through three centuries of Hearthkin culture, the only tongue which their literature is allowed to be spoken in; \ - especially relating to their pagan practices. While Siik'Tajr is used as a trade language with outsiders, Ættmál remains sacred and mostly unknown \ + especially relating to their pagan practices. While Galactic Uncommon is used as a trade language with outsiders, Ættmál remains sacred and mostly unknown \ to those outside the Hearth." key = "H" flags = TONGUELESS_SPEECH From 331d800f962064a424e0bcf7d3ce746ddc24bae5 Mon Sep 17 00:00:00 2001 From: Kaostico Date: Fri, 6 Sep 2024 19:31:20 -0300 Subject: [PATCH 26/28] forgor this changes from the merge --- code/__DEFINES/~doppler_defines/DNA.dm | 2 - .../__DEFINES/~doppler_defines/keybindings.dm | 1 + code/__DEFINES/~doppler_defines/keybinds.dm | 1 - code/__DEFINES/~doppler_defines/species.dm | 2 + config/admins.txt | 146 +----------------- tgstation.dme | 14 +- 6 files changed, 10 insertions(+), 156 deletions(-) delete mode 100644 code/__DEFINES/~doppler_defines/DNA.dm delete mode 100644 code/__DEFINES/~doppler_defines/keybinds.dm diff --git a/code/__DEFINES/~doppler_defines/DNA.dm b/code/__DEFINES/~doppler_defines/DNA.dm deleted file mode 100644 index cf52d6b80ba82..0000000000000 --- a/code/__DEFINES/~doppler_defines/DNA.dm +++ /dev/null @@ -1,2 +0,0 @@ -//Species IDs added from Doppler Shift. -#define SPECIES_FELINE_PRIMITIVE "primitive_felinid" diff --git a/code/__DEFINES/~doppler_defines/keybindings.dm b/code/__DEFINES/~doppler_defines/keybindings.dm index 23bcff0827dc0..ef4105eaad209 100644 --- a/code/__DEFINES/~doppler_defines/keybindings.dm +++ b/code/__DEFINES/~doppler_defines/keybindings.dm @@ -1,2 +1,3 @@ +#define COMSIG_KB_LIVING_COMBAT_INDICATOR "keybinding_living_combat_indicator" #define COMSIG_KB_MOB_PIXEL_SHIFT_DOWN "keybinding_mob_pixel_shift_down" #define COMSIG_KB_MOB_PIXEL_SHIFT_UP "keybinding_mob_pixel_shift_up" diff --git a/code/__DEFINES/~doppler_defines/keybinds.dm b/code/__DEFINES/~doppler_defines/keybinds.dm deleted file mode 100644 index cd88e31255d5d..0000000000000 --- a/code/__DEFINES/~doppler_defines/keybinds.dm +++ /dev/null @@ -1 +0,0 @@ -#define COMSIG_KB_LIVING_COMBAT_INDICATOR "keybinding_living_combat_indicator" diff --git a/code/__DEFINES/~doppler_defines/species.dm b/code/__DEFINES/~doppler_defines/species.dm index 77e3b78260ad1..a354e5dfbdbb0 100644 --- a/code/__DEFINES/~doppler_defines/species.dm +++ b/code/__DEFINES/~doppler_defines/species.dm @@ -1,2 +1,4 @@ +// Hearthkin, from the Ice Moon +#define SPECIES_FELINE_PRIMITIVE "primitive_felinid" // Slugcats, from Talon III. #define SPECIES_SLUGCAT "slugcat" diff --git a/config/admins.txt b/config/admins.txt index f48ff5bc03c3a..b7ee4a2da2d54 100644 --- a/config/admins.txt +++ b/config/admins.txt @@ -4,148 +4,4 @@ #Ranks will match to those with the same name in admin_ranks.txt, if a match isn't found the user won't be adminned. #If SQL-based admin loading is enabled, admins listed here will always be loaded first and will override any duplicate entries in the database. -Optimumtact = Host -CitrusGender = Game Master -NewSta = Game Master -Expletives = Game Master -kingofkosmos = Game Master -MrStonedOne = Lazy Master -microscopics = Game Master -Gun Hog = Game Master -KorPhaeron = Game Master -razharas = Game Master -Lordpidey = Game Master -Niknakflak = Game Master -rolan7 = Game Master -quarxink = Game Master -adrix89 = Game Master -tle = Game Master -xsi = Game Master -scaredofshadows = Game Master -neofite = Game Master -trubblebass = Game Master -mport2004 = Game Master -deuryn = Game Master -agouri = Game Master -errorage = Game Master -superxpdude = Game Master -petethegoat = Game Master -nodrak = Game Master -carnwennan = Game Master -ikarrus = Game Master -cheridan = Game Master -giacomand = Game Master -rockdtben = Game Master -sieve = Game Master -aranclanos = Game Master -intigracy = Game Master -dumpdavidson = Game Master -kazeespada = Game Master -malkevin = Game Master -incoming = Game Master -demas = Game Master -fleure = Game Master -ricotez = Game Master -misterperson = Game Master -crimsonvision = Game Master -iamgoofball = Game Master -zelacks = Game Master -androidsfv = Game Master -miggles = Game Master -jordie0608 = Game Master -s0ldi3rkr4s0 = Game Master -ergovisavi = Game Master -vistapowa = Game Master -miauw62 = Game Master -rumia29 = Game Master -bobylein = Game Master -sirbayer = Game Master -hornygranny = Game Master -yota = Game Master -firecage = Game Master -donkieyo = Game Master -argoneus = Game Master -paprka = Game Master -cookingboy3 = Game Master -limeliz = Game Master -steelpoint = Game Master -phil235 = Game Master -CorruptComputer = Game Master -xxnoob = Game Master -tkdrg = Game Master -Cuboos = Game Master -thunder12345 = Game Master -wjohnston = Game Master -mandurrh = Game Master -thurgatar = Game Master -xerux = Game Master -dannno = Game Master -lo6a4evskiy = Game Master -vekter = Game Master -Ahammer18 = Game Master -ACCount12 = Game Master -fayrik = Game Master -shadowlight213 = Game Master -drovidicorv = Game Master -Dunc = Game Master -MMMiracles = Game Master -bear1ake = Game Master -CoreOverload = Game Master -Jalleo = Game Master -ChangelingRain = Game Master -FoxPMcCloud = Game Master -Xhuis = Game Master -Astralenigma = Game Master -Tokiko1 = Game Master -SuperSayu = Game Master -Lzimann = Game Master -As334 = Game Master -neersighted = Game Master -Swankcookie = Game Master -Ressler = Game Master -Folix = Game Master -Bawhoppennn = Game Master -Anturke = Host -Lumipharon = Game Master -bgobandit = Game Master -coiax = Game Master -RandomMarine = Game Master -PKPenguin321 = Game Master -TechnoAlchemist = Game Master -Aloraydrel = Game Master -Quiltyquilty = Game Master -SnipeDragon = Game Master -Fjeld = Game Master -kevinz000 = Game Master -Tacolizard = Game Master -TrustyGun = Game Master -Cyberboss = Game Master -PJB3005 = Game Master -Sweaterkittens = Game Master -Feemjmeem = Game Master -JStheguy = Game Master -excessiveuseofcobby = Game Master -Plizzard = Game Master -octareenroon91 = Game Master -Serpentarium = Game Master -Averagejoe82 = Game Master -The Dreamweaver = Game Master -Denton-30 = Game Master -Naksuasdf = Game Master -MrDoomBringer = Game Master -shizcalev = Game Master -NicBR = Game Master -LoserWasTaken = Game Master -Fikou = Game Master -Magatsuchi = Game Master -Skoglol = Game Master -4dplanner = Game Master -Time-Green = Game Master -StyleMistake = Game Master -actioninja = Game Master -bobbahbrown = Game Master -Jaredfogle = Game Master+Coder -WaylandSmithy = Game Master -NamelessFairy = Game Master -WalterMeldron = Game Master -san7890 = Game Master +Kaostico = Host diff --git a/tgstation.dme b/tgstation.dme index ef64aba99bd30..70e6ae185f69c 100644 --- a/tgstation.dme +++ b/tgstation.dme @@ -396,11 +396,9 @@ #include "code\__DEFINES\traits\declarations.dm" #include "code\__DEFINES\traits\macros.dm" #include "code\__DEFINES\traits\sources.dm" -#include "code\__DEFINES\~doppler_defines\DNA.dm" #include "code\__DEFINES\~doppler_defines\enterprise_resource_planning.dm" #include "code\__DEFINES\~doppler_defines\is_helpers.dm" #include "code\__DEFINES\~doppler_defines\keybindings.dm" -#include "code\__DEFINES\~doppler_defines\keybinds.dm" #include "code\__DEFINES\~doppler_defines\living.dm" #include "code\__DEFINES\~doppler_defines\obj_flags_doppler.dm" #include "code\__DEFINES\~doppler_defines\reagent_forging_tools.dm" @@ -6376,7 +6374,6 @@ #include "interface\fonts\spess_font.dm" #include "interface\fonts\tiny_unicode.dm" #include "interface\fonts\vcr_osd_mono.dm" - #include "modular_doppler\advanced_reskin\code\advanced_reskin.dm" #include "modular_doppler\customization\code\accessory_overrides.dm" #include "modular_doppler\customization\code\accessory_overrides_lizard.dm" @@ -6390,7 +6387,8 @@ #include "modular_doppler\customization\species\lizards\code\lizard_species.dm" #include "modular_doppler\customization\species\scugs\code\slugcat_accessories.dm" #include "modular_doppler\customization\species\scugs\code\slugcat_bodyparts.dm" -#include "modular_doppler\customization\species\scugs\code\slugcat_species.dm"#include "modular_doppler\cryosleep\code\admin.dm" +#include "modular_doppler\customization\species\scugs\code\slugcat_species.dm" +#include "modular_doppler\cryosleep\code\admin.dm" #include "modular_doppler\cryosleep\code\ai.dm" #include "modular_doppler\cryosleep\code\config.dm" #include "modular_doppler\cryosleep\code\cryo_console_return.dm" @@ -6466,15 +6464,14 @@ #include "modular_doppler\modular_cosmetics\code\storage\rings.dm" #include "modular_doppler\modular_cosmetics\code\suits\jacket.dm" #include "modular_doppler\modular_cosmetics\GAGS\greyscale_configs_neck.dm" - - #include "modular_doppler\modular_crafting\code\crafting_extended.dm" #include "modular_doppler\modular_crafting\code\sheet_types.dm" #include "modular_doppler\modular_food_drinks_and_chems\chemistry_reagents.dm" #include "modular_doppler\modular_food_drinks_and_chems\food_and_drinks\alcohol reagents.dm" #include "modular_doppler\modular_food_drinks_and_chems\food_and_drinks\drink_reagents.dm" #include "modular_doppler\modular_food_drinks_and_chems\food_and_drinks\drinks.dm" -#include "modular_doppler\modular_food_drinks_and_chems\food_and_drinks\drinks_recipes.dm"#include "modular_doppler\modular_mob_spawn\code\mob_spawn.dm" +#include "modular_doppler\modular_food_drinks_and_chems\food_and_drinks\drinks_recipes.dm" +#include "modular_doppler\modular_mob_spawn\code\mob_spawn.dm" #include "modular_doppler\modular_sounds\code\sounds.dm" #include "modular_doppler\modular_traits\code\neutral.dm" #include "modular_doppler\modular_traits\code\organs.dm" @@ -6483,7 +6480,8 @@ #include "modular_doppler\pixel_shift\living_movement.dm" #include "modular_doppler\pixel_shift\code\pixel_shift_component.dm" #include "modular_doppler\pixel_shift\code\pixel_shift_keybind.dm" -#include "modular_doppler\pixel_shift\code\pixel_shift_mob.dm"#include "modular_doppler\reagent_forging\code\anvil.dm" +#include "modular_doppler\pixel_shift\code\pixel_shift_mob.dm" +#include "modular_doppler\reagent_forging\code\anvil.dm" #include "modular_doppler\reagent_forging\code\centrifuge.dm" #include "modular_doppler\reagent_forging\code\crafting_bench.dm" #include "modular_doppler\reagent_forging\code\crafting_bench_recipes.dm" From d4576a53c435c91de4e65bdea03754fcfeed4906 Mon Sep 17 00:00:00 2001 From: Kaostico Date: Fri, 6 Sep 2024 19:42:15 -0300 Subject: [PATCH 27/28] reverting admins.txt and reordering tgstation.dme because Linters my beloved... --- config/admins.txt | 146 +++++++++++++++++++++++++++++++++++++++++++++- tgstation.dme | 18 +++--- 2 files changed, 154 insertions(+), 10 deletions(-) diff --git a/config/admins.txt b/config/admins.txt index b7ee4a2da2d54..f48ff5bc03c3a 100644 --- a/config/admins.txt +++ b/config/admins.txt @@ -4,4 +4,148 @@ #Ranks will match to those with the same name in admin_ranks.txt, if a match isn't found the user won't be adminned. #If SQL-based admin loading is enabled, admins listed here will always be loaded first and will override any duplicate entries in the database. -Kaostico = Host +Optimumtact = Host +CitrusGender = Game Master +NewSta = Game Master +Expletives = Game Master +kingofkosmos = Game Master +MrStonedOne = Lazy Master +microscopics = Game Master +Gun Hog = Game Master +KorPhaeron = Game Master +razharas = Game Master +Lordpidey = Game Master +Niknakflak = Game Master +rolan7 = Game Master +quarxink = Game Master +adrix89 = Game Master +tle = Game Master +xsi = Game Master +scaredofshadows = Game Master +neofite = Game Master +trubblebass = Game Master +mport2004 = Game Master +deuryn = Game Master +agouri = Game Master +errorage = Game Master +superxpdude = Game Master +petethegoat = Game Master +nodrak = Game Master +carnwennan = Game Master +ikarrus = Game Master +cheridan = Game Master +giacomand = Game Master +rockdtben = Game Master +sieve = Game Master +aranclanos = Game Master +intigracy = Game Master +dumpdavidson = Game Master +kazeespada = Game Master +malkevin = Game Master +incoming = Game Master +demas = Game Master +fleure = Game Master +ricotez = Game Master +misterperson = Game Master +crimsonvision = Game Master +iamgoofball = Game Master +zelacks = Game Master +androidsfv = Game Master +miggles = Game Master +jordie0608 = Game Master +s0ldi3rkr4s0 = Game Master +ergovisavi = Game Master +vistapowa = Game Master +miauw62 = Game Master +rumia29 = Game Master +bobylein = Game Master +sirbayer = Game Master +hornygranny = Game Master +yota = Game Master +firecage = Game Master +donkieyo = Game Master +argoneus = Game Master +paprka = Game Master +cookingboy3 = Game Master +limeliz = Game Master +steelpoint = Game Master +phil235 = Game Master +CorruptComputer = Game Master +xxnoob = Game Master +tkdrg = Game Master +Cuboos = Game Master +thunder12345 = Game Master +wjohnston = Game Master +mandurrh = Game Master +thurgatar = Game Master +xerux = Game Master +dannno = Game Master +lo6a4evskiy = Game Master +vekter = Game Master +Ahammer18 = Game Master +ACCount12 = Game Master +fayrik = Game Master +shadowlight213 = Game Master +drovidicorv = Game Master +Dunc = Game Master +MMMiracles = Game Master +bear1ake = Game Master +CoreOverload = Game Master +Jalleo = Game Master +ChangelingRain = Game Master +FoxPMcCloud = Game Master +Xhuis = Game Master +Astralenigma = Game Master +Tokiko1 = Game Master +SuperSayu = Game Master +Lzimann = Game Master +As334 = Game Master +neersighted = Game Master +Swankcookie = Game Master +Ressler = Game Master +Folix = Game Master +Bawhoppennn = Game Master +Anturke = Host +Lumipharon = Game Master +bgobandit = Game Master +coiax = Game Master +RandomMarine = Game Master +PKPenguin321 = Game Master +TechnoAlchemist = Game Master +Aloraydrel = Game Master +Quiltyquilty = Game Master +SnipeDragon = Game Master +Fjeld = Game Master +kevinz000 = Game Master +Tacolizard = Game Master +TrustyGun = Game Master +Cyberboss = Game Master +PJB3005 = Game Master +Sweaterkittens = Game Master +Feemjmeem = Game Master +JStheguy = Game Master +excessiveuseofcobby = Game Master +Plizzard = Game Master +octareenroon91 = Game Master +Serpentarium = Game Master +Averagejoe82 = Game Master +The Dreamweaver = Game Master +Denton-30 = Game Master +Naksuasdf = Game Master +MrDoomBringer = Game Master +shizcalev = Game Master +NicBR = Game Master +LoserWasTaken = Game Master +Fikou = Game Master +Magatsuchi = Game Master +Skoglol = Game Master +4dplanner = Game Master +Time-Green = Game Master +StyleMistake = Game Master +actioninja = Game Master +bobbahbrown = Game Master +Jaredfogle = Game Master+Coder +WaylandSmithy = Game Master +NamelessFairy = Game Master +WalterMeldron = Game Master +san7890 = Game Master diff --git a/tgstation.dme b/tgstation.dme index 70e6ae185f69c..f851caa90d8f8 100644 --- a/tgstation.dme +++ b/tgstation.dme @@ -6375,6 +6375,15 @@ #include "interface\fonts\tiny_unicode.dm" #include "interface\fonts\vcr_osd_mono.dm" #include "modular_doppler\advanced_reskin\code\advanced_reskin.dm" +#include "modular_doppler\cryosleep\code\admin.dm" +#include "modular_doppler\cryosleep\code\ai.dm" +#include "modular_doppler\cryosleep\code\config.dm" +#include "modular_doppler\cryosleep\code\cryo_console_return.dm" +#include "modular_doppler\cryosleep\code\cryopod.dm" +#include "modular_doppler\cryosleep\code\job.dm" +#include "modular_doppler\cryosleep\code\jobs.dm" +#include "modular_doppler\cryosleep\code\mind.dm" +#include "modular_doppler\cryosleep\code\mood.dm" #include "modular_doppler\customization\code\accessory_overrides.dm" #include "modular_doppler\customization\code\accessory_overrides_lizard.dm" #include "modular_doppler\customization\code\accessory_overrides_moth.dm" @@ -6388,15 +6397,6 @@ #include "modular_doppler\customization\species\scugs\code\slugcat_accessories.dm" #include "modular_doppler\customization\species\scugs\code\slugcat_bodyparts.dm" #include "modular_doppler\customization\species\scugs\code\slugcat_species.dm" -#include "modular_doppler\cryosleep\code\admin.dm" -#include "modular_doppler\cryosleep\code\ai.dm" -#include "modular_doppler\cryosleep\code\config.dm" -#include "modular_doppler\cryosleep\code\cryo_console_return.dm" -#include "modular_doppler\cryosleep\code\cryopod.dm" -#include "modular_doppler\cryosleep\code\job.dm" -#include "modular_doppler\cryosleep\code\jobs.dm" -#include "modular_doppler\cryosleep\code\mind.dm" -#include "modular_doppler\cryosleep\code\mood.dm" #include "modular_doppler\emotes\code\emotes.dm" #include "modular_doppler\emotes\code\added_emotes\animal_sounds.dm" #include "modular_doppler\emotes\code\added_emotes\human_things.dm" From 64016bfb227bcf7806bd78b9e03420eb9ec0a22f Mon Sep 17 00:00:00 2001 From: Kaostico Date: Fri, 6 Sep 2024 20:01:36 -0300 Subject: [PATCH 28/28] fixed readmes --- modular_doppler/hearthkin/primitive_catgirls/readme.md | 2 +- modular_doppler/hearthkin/readme.md | 2 +- modular_doppler/indicators/readme.md | 2 +- 3 files changed, 3 insertions(+), 3 deletions(-) diff --git a/modular_doppler/hearthkin/primitive_catgirls/readme.md b/modular_doppler/hearthkin/primitive_catgirls/readme.md index d0785dbeb8441..b2556a429e167 100644 --- a/modular_doppler/hearthkin/primitive_catgirls/readme.md +++ b/modular_doppler/hearthkin/primitive_catgirls/readme.md @@ -15,8 +15,8 @@ N/A ### Defines: -- `code\__DEFINES\~doppler_defines\DNA.dm` species id - `code\__DEFINES\~doppler_defines\is_helpers.dm` is_type identificator for species +- `code\__DEFINES\~doppler_defines\species.dm` species id ### Master file additions diff --git a/modular_doppler/hearthkin/readme.md b/modular_doppler/hearthkin/readme.md index 2aac6a25cb0e1..14d7d45aeb079 100644 --- a/modular_doppler/hearthkin/readme.md +++ b/modular_doppler/hearthkin/readme.md @@ -16,9 +16,9 @@ The species ID `primitive_felinid` was added in the configuration file `config\d ### Defines: -- `code\__DEFINES\~doppler_defines\DNA.dm` species id - `code\__DEFINES\~doppler_defines\is_helpers.dm` is_type identificator for species - `code\__DEFINES\~doppler_defines\reagent_forging_tools.dm` glassblowing tools' define +- `code\__DEFINES\~doppler_defines\species.dm` species id - `code\__DEFINES\~doppler_defines\traits.dm` trait for glassblowing ### Master file additions diff --git a/modular_doppler/indicators/readme.md b/modular_doppler/indicators/readme.md index 08ee1eb4de163..9ec04fab0b92b 100644 --- a/modular_doppler/indicators/readme.md +++ b/modular_doppler/indicators/readme.md @@ -31,7 +31,7 @@ SSD Indicator ### Defines: -- `code\__DEFINES\~doppler_defines\keybinds.dm` +- `code\__DEFINES\~doppler_defines\keybindings.dm` - `code\__DEFINES\~doppler_defines\signals.dm` ### Included files:

=+a{A`}i&u>p?6BXOlwUZS6w&+qVUz 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 dVd92I1~5A*2lV$xR@iSkCNc98{2j(^!ae{1 literal 0 HcmV?d00001 diff --git a/modular_doppler/modular_sounds/sound/bricks/brick_pick_up_2.ogg b/modular_doppler/modular_sounds/sound/bricks/brick_pick_up_2.ogg new file mode 100644 index 0000000000000000000000000000000000000000..e72228ca6dd2905c193e54c41102a8ace4380f12 GIT binary patch literal 7405 zcmeHMc{tSF+dp;*iAf{WU}Q$bj3q>meHnvH_T?$YzQ&-mXcU?zi7~{47)Dt}mJr&W z${>59L}^DVEvl#eJu~(E-rxIP@9({y>%D$|zUMk~zUO=HZO(n)-}`*NGj8GG+ki0m z)ohploE)hP`Y5zkC?!5IIFiC&6221nlM*E=B$(6)x$!0c(fE>lN}MY3j}^8*{<*b@ z{M2Iz$v%-gBR0AvhNEI4gS`aWQBEklK3-pclfEGeLkbN^CP&7FqwL~RA`|1|VngGS zuzVXrVn21LS=)FC0ZRao)^gfnTyl4Q!99^@v&}+J3=HPx(WfQS{zI22G zJ>fJG&Z<=4>Bp)E9Xsxo+M%8-AriOFq0X9>Ud~;j9m89CfMT?L3_b&bnfgAuq2oqX*4_Zw?>$$N+7tk0M1?eBmR0$0F2UO{EZSwkK;V5^uUM{IRbFdf^Y zLK(pIpbkmn=gRY4&HAbsu4XsTl{utnY%5|LvFWKIncF&1LOE-NC1>M!$p0KP1a5#E zmJ?SB$%S7q10hhF2=%G_+!iGA9|jdW651gV?Z80yF?5{r&HG#U-Q||8%PP-t&)C}^ zVz+;Yof!|E`4Boa9vWB}dapG$a3V19cJhDif~`|U0X63d^g8U0IaQ8Qg5cx|0Xaae zG@(Csgz?DH^kuA%EDTRAJe|rqb7ZZ61qKFs4K^xU5H_@LVRdBLX@0P4Yw6WBwY5>K z>d61S3sF_AEMY9J#FAkoWm4P{{e z`NaU*O~lY$)X)uPv7kA<11?Lz1@W^^{aXA#UUJQ4UfZr5v0eE~9vZTB7qcDz%NDfa zwn}K!f8_y~;-V(-<0F}w zRWAu1i2~^yvM&G+92wO@fU4od5(j`)eMB7|>a6wjf2HPcufwt{t^%ts5hDT(iUKwO z(pl_C&@b$xXgLO0;;+rATEavH{@I7w36HWyt8KvvR6%iZhq88g=>E6n5&UliOOx%& zve{I&Bs|N;GBA6}BCQb?!-hdDb_B~3;R0ccWx5Ekq{^`5kBT7HG|L0YWk4T84^1t@ z(Akl-wF}l`=57ePQA5x14gGxEp74YSRiX*3bT;USjCt_Y`4)y!`F7#?E#d(+ zc^Aeim)ABdbT-FK0eGrF`jq&CPI$Vv>B1OX5dx?yl4gBpnkAK8&c6n559)vhU6}1o zz;UF>@&s%}5Ru@-@gR{1HB5pv0b4+Fa>8;*cmkF)LDJMLV32C7m>wj87@(?}z>gr# zqTns`taWZM#41%x0`6G}g+$;WAwt1wlCvRTVKQ*M5{fIKuL!PbaY6>*T0Y4PA{jZT zIBCdKlEWlfdP2-s4JtTn`HVzLmi7}H~1_2oSxdI_WHsCvEudXx*HsT<4~?Z%+wjC^*}6+zA@!Q57p#B$_F1hp!r zwIen&7ap`i5`YR6Zdg{RZ4jb*z~udfKLjA;Zw({AVBIgMC%}7uV{iqiluVH;t{F0Q z8YPHhVv2&SlzTJs5l zTR$njgp(#Dz)d2oVIDD{1`g9N8po6;VL1>0YS+Njb=G7u2z&x5O1E`_fUSW90bh)6 zCW)kt~3jLh9-4nsl+}2xu&bpjid@tV# zj?t~=t8azLGa@K5D+?5ZPb+z^P1lf8T3`Mb7!t+1;I*(uSJ9`D%$p??{tmKw8PX)_ zT8(_17B-w_n1!e+!@eydNe4?hWxC=HbJwqPosiVuYrH{$v$R1xI_Y-FbQ&#{gT2zuo3v0OgNLa&$e5mr;V-Ym} z%|uY!Mdhees$j;yr&0y4g`$l{f+fIzErewWSR39vu#OVHFDWTGWnc2%LvFEg(MR^} zPTR9*|GuQGbBJ4~1sHWUt+ z+Iwrn-aMF+J(S&0NW6A8FH)&g{rlp(4$8@?nT30PPG+YgZW6+;H79YCTQpjh`90IF z&XZc^bXvdA@op8zH=rHF!3 zC%Zf|yG8V=Drhh}y!hpmDQn2FNB(QS%aUR98msOYqvhbPY1i42454yL%Jzz7B2-ai zaqId}V`gZckB+&wXCz(4I-9YIeb9XKd)`#fFflf4K1QQ>cl)~t#d=V~#G>8iWN2&|dH3~WN33q>&@^pxpK~Dn zRP4q#Ym&8AFQ!f{>F(mF+;3kKEn6-^nTe`5rOFPRUFK1#w(TIrv!fP))yDXls6RqF z7m>pv!(5&lmZe@$v1o3m6hw30jQn=FY~!=%EgB79UPU+tu1my@uWmM5;_Ygl9?70> zJbs$Ir~O2Qu5zh2+h=2)UbczXu-b<&dhKckd(`iTFF@Eb*OCmu#D%8keFGggJUG{B zT5Q{`=0+wo%tT~Z65+19^Jcu(xyiQBADb;^=^ktIPKvesITt@q*Gu}M6*KuB56OxAfXhrL9`h<2Z4*Z(*CfD(g|aNLYXBRn_E({jrH_^+QIqlX<&V9Mhis zT6Zt7&N=$+gTO+$SNk<1oz%W7WQ`5aDG6P2^bbd^N9@RJ8?q!~u0-QoNKSa02d0lb zJ=bf>y`-Z3al5Iaol(W^?-EaqkGGTzu?^b4oy;uD8pVEYy47apJW8%^ZEDcJ`kh5@ zbq*#J1S@dkL#Ocm7A^}-7O($&sbc)F!};xs;t}Qfy@(GB;%h%kto5C;L#YGx=q^cH z(JRrtY@Ox?mgsP51Mw-L$%dweWFLI#F=49^X>a<$#OSad^5J*;kN1z1mD@1m-Ue2U zhdxVbayTSjSwEtX_MX-;_*MDZ(B}G~{QblmMTuP$8NCe(-m0gU_9j^5_{VI?c+>1h zX-ZqG-fu$$ioTl_tBRzky?2{X-5%hpm94K{f0k6=W@7P$>oMDs2 z3f`1?euu9lK-cY?%`2#XTk0^O#U>etphWNn3cBma(pD=GY^%r~UXe|Bec*>vj}mwz zte`plDh;I;VFMz00Bx^Rvy#h;@R7sK${XMg=LD^BDKsJv4H}}!8!PAWs#;oiix}%s z(X$cP3}5N?-_m*d7!l=DciJ| z7l1#QRO)M%<=Xdx*JwPFG;{(6zSaLe-=>1*Y9n4F9jlYyj|m4V^oDtzxaA{cx?dI z#5P;A=L{_)+$+IAGTGM2-1ll8%Eyy`27T!tGk8sV(85@wzv9 z&Mulh9*sWfC7NArr?4yK!qT61IjgQU#C5)J{5{z3=J$g#WTOMl7fQ;W+DmPDq!y!e zwC7G@=dsvh4sTw6+T(V0Hbv_dt2aCOaF^=+KUumv4OEevE`=?hCQ9(+cZB#FdPJ{M zYm9g}PP|B@qm>VFFp>Q~h`lIQ(3(Jn=*GoI9pUs`<0?{^_u#;Om66uo-Of+FLib*9 z&G&5HTp&VA;?i@mpZ}0gQ*9qc#tiD6zOqO4twn1)PyFGihTZ2C?-3J<-y_yE#{e<> z@oKex@vW$LtO0y~R&%|?>uC#vp*c1kDU7o}sPPANsFh@&r59eQ7%hKp!_Xk6_RIkz zRkI@F{CNfOm4OULcg%Q)ZEJCcmt&Jw8{N)fpIB@cF<|@Qr$mQ+%He=ok8ha~YYysq z6q&JStTkVDa;hlX?t8Lc&{kXXC$h?=zF*xJ2`crJZVDjNJ>WJi7n3)>1@cY;eI$_t2e`LoZif zPl$bm{J7KEPeG+mC0xQ>hyE3F%Dm@LfZHdR(zIh>Z6B*0lv4xH(f5U^!ifhCp4rs5 z^*9DStQ+82u#FvSN28DCG=rB9?-vW7G9kl`BN{Eq&R)`@;$Solk3tQYJ>vFpAD- zU4$j7horjVjq=|95Sf0%##&8=za>&r-1X?Rd(`{Y}v$^!{6(%y738b?y; zI||SBY9%njue-lgn%cYhsg}lXhDp;WukQC;Oe62m!Wrx@p2x^TKX=>0NE?r%9lxvfLUERezWe8lrNSmd2h@^O znc0SAJLQCGS{OiL<<18H{4TF$^)$*mrCc6R<*mL=HE>4}IoK=eNCtREBv*&RSUVHP^ANw#Qd#F9uZBtja2W2tX^!jTh z%OgYZ?-qJ)@X{<{`q2f?w~1e0O(eSXEP2kTk%WII`0MM-S+bdJJ9eO`*Q04!G1+_a z7)fF7gML+5VXy(yo2a8&8Cr-e-G6_O@-cjh^77LzVckd0=pDz(%jSCzJh?xA;5ox7 z`FYvy~tW0a0oE3eN_Kq8hdp9#g>e?snww{4sH6dAs< z>-3gOo6gJy$lo&atn~_Lc6@c!(LN~j`eBFq`Pr!3g(oxYw52rbTyq}B%pP60)=Q~T zsVjWoEGSblP=vpe$A=C00FZRyx8MaUZ~+~sK-35*z@_L|*UBfHw#Q)PO!I;ra7uFW zSTy+$<|jfa&GN*)HJHHrk*hAIwpVr_k0btITF&llKO5W1 zYYvz@Y^FNx@4Tt|{N(Nri{!%epy!gt%d5T!ZK*Mk2Y~oI8@`quZb=vI_29N3j#g#L zAq|jPtYTNU7sK zFZNfKUOG)b=TbXuUOjz%?Xix5B7#OGKpixqG;2ki4?1@!S3$J&fzYKt6IE#1YvwY# zPdv8t7`4<=$^AX3rFyyv^Gx;BwCx*sAcSJcg1QVm-a7Cz@(JcG*#SSeI& zW{_`_$79ahh)Cvc6nk0mfvdM&wfV_(`u<%d#>jrm`}5mFm5e18=Rf8t*VhcM%-c4z zEM-D+13O=@eucz!$t`o(ZK)0^rXwR`sUzE}-{!nXEU!5IPG~+!et9^d^&Dxdx#mhN zp$bh_l;us$FTCs=fIp?7=5W8q&$vp=J$Q00FXni=Mnywq^TJ%;8{Q4S(Tk@xGq3e! cs(4L247rukys7nY5u$$X&ycg_emxie1NcEAA^-pY literal 0 HcmV?d00001 diff --git a/modular_doppler/modular_traits/code/neutral.dm b/modular_doppler/modular_traits/code/neutral.dm new file mode 100644 index 0000000000000..1bff3c1539b0f --- /dev/null +++ b/modular_doppler/modular_traits/code/neutral.dm @@ -0,0 +1,22 @@ +/datum/quirk/feline_aspect + name = "Feline Traits" + desc = "You happen to act like a feline, for whatever reason. This will replace most other tongue-based speech quirks." + gain_text = span_notice("Nya could go for some catnip right about now...") + lose_text = span_notice("You feel less attracted to lasers.") + medical_record_text = "Patient seems to possess behavior much like a feline." + mob_trait = TRAIT_FELINE + icon = FA_ICON_CAT + +/datum/quirk/feline_aspect/add_unique(client/client_source) + var/mob/living/carbon/human/human_holder = quirk_holder + var/obj/item/organ/internal/tongue/cat/new_tongue = new(get_turf(human_holder)) + + new_tongue.copy_traits_from(human_holder.get_organ_slot(ORGAN_SLOT_TONGUE)) + new_tongue.Insert(human_holder, special = TRUE, movement_flags = DELETE_IF_REPLACED) + +/datum/quirk/feline_aspect/remove() + var/mob/living/carbon/human/human_holder = quirk_holder + var/obj/item/organ/internal/tongue/new_tongue = new human_holder.dna.species.mutanttongue + + new_tongue.copy_traits_from(human_holder.get_organ_slot(ORGAN_SLOT_TONGUE)) + new_tongue.Insert(human_holder, special = TRUE, movement_flags = DELETE_IF_REPLACED) diff --git a/modular_doppler/modular_traits/code/organs.dm b/modular_doppler/modular_traits/code/organs.dm new file mode 100644 index 0000000000000..8dd357630e4f8 --- /dev/null +++ b/modular_doppler/modular_traits/code/organs.dm @@ -0,0 +1,9 @@ +/// Copy traits from one organ to another - e.g. with custom roundstart organs that should still get species traits applied. +/obj/item/organ/proc/copy_traits_from(obj/item/organ/old_organ, copy_actions = FALSE) + if(isnull(old_organ)) + return + + if(copy_actions) + // for when you want to make sure the organ gets any actions from the old one + for(var/datum/action/action as anything in old_organ.actions) + add_item_action(action.type) diff --git a/modular_doppler/modular_traits/readme.md b/modular_doppler/modular_traits/readme.md new file mode 100644 index 0000000000000..0591520685fe6 --- /dev/null +++ b/modular_doppler/modular_traits/readme.md @@ -0,0 +1,25 @@ +## Title: Modular Traits + +MODULE ID: MODULAR_TRAITS + +### Description: + +Modular Traits is where we are going to code anything related to traits. All the new quirks need to be added in code\controllers\subsystem\processing\quirks.dm, on the GLOBAL_LIST_INIT_TYPED for them to be available before the subsystem inits. + +### TG Proc Changes: + +- N/A + +### Defines: + +- code\__DEFINES\~doppler_defines\traits.dm + +### Master file additions + +- N/A + +### Included files that are not contained in this module: + +- N/A + +### Credits: diff --git a/modular_doppler/obj_flags_doppler/code/objs.dm b/modular_doppler/obj_flags_doppler/code/objs.dm new file mode 100644 index 0000000000000..55b595bb1aefc --- /dev/null +++ b/modular_doppler/obj_flags_doppler/code/objs.dm @@ -0,0 +1,3 @@ +/obj + ///the Doppler Shift version of obj_flags, to prevent any potential future conflict + var/obj_flags_doppler = null diff --git a/modular_doppler/reagent_forging/code/anvil.dm b/modular_doppler/reagent_forging/code/anvil.dm new file mode 100644 index 0000000000000..e175bd6eb089e --- /dev/null +++ b/modular_doppler/reagent_forging/code/anvil.dm @@ -0,0 +1,163 @@ +/obj/structure/reagent_anvil + name = "smithing anvil" + desc = "Essentially a big block of metal that you can hammer other metals on top of, crucial for anyone working metal by hand." + icon = 'modular_doppler/reagent_forging/icons/obj/forge_structures.dmi' + icon_state = "anvil_empty" + + anchored = TRUE + density = TRUE + +/obj/structure/reagent_anvil/Initialize(mapload) + . = ..() + + AddElement(/datum/element/falling_hazard, damage = 40, wound_bonus = 10, hardhat_safety = FALSE, crushes = TRUE) + +/obj/structure/reagent_anvil/update_appearance() + . = ..() + cut_overlays() + if(!length(contents)) + return + + var/image/overlayed_item = image(icon = contents[1].icon, icon_state = contents[1].icon_state) + overlayed_item.transform = matrix(, 0, 0, 0, 0.8, 0) + add_overlay(overlayed_item) + +/obj/structure/reagent_anvil/examine(mob/user) + . = ..() + . += span_notice("You can place hot metal objects on this using some tongs.") + . += span_notice("It can be (un)secured with Right Click") + + if(length(contents)) + . += span_notice("It has [contents[1]] sitting on it.") + +/obj/structure/reagent_anvil/attack_hand_secondary(mob/user, list/modifiers) + . = ..() + if(. == SECONDARY_ATTACK_CANCEL_ATTACK_CHAIN) + return + + if(!can_interact(user) || !user.can_perform_action(src)) + return + + set_anchored(!anchored) + balloon_alert_to_viewers(anchored ? "secured" : "unsecured") + return SECONDARY_ATTACK_CANCEL_ATTACK_CHAIN + +/obj/structure/reagent_anvil/wrench_act(mob/living/user, obj/item/tool) + balloon_alert_to_viewers("deconstructing...") + + if(!do_after(user, 2 SECONDS, src)) + balloon_alert_to_viewers("stopped deconstructing") + return TRUE + + tool.play_tool_sound(src) + deconstruct(TRUE) + return TRUE + +/obj/structure/reagent_anvil/atom_deconstruct(disassembled = TRUE) + new /obj/item/stack/sheet/iron/ten(get_turf(src)) + return ..() + +/obj/structure/reagent_anvil/tong_act(mob/living/user, obj/item/tool) + var/obj/item/forging/forge_item = tool + var/obj/obj_anvil_search = locate() in contents + + if(forge_item.in_use) + balloon_alert(user, "already in use") + return ITEM_INTERACT_SUCCESS + + var/obj/obj_tong_search = locate() in forge_item.contents + if(obj_anvil_search && !obj_tong_search) + obj_anvil_search.forceMove(forge_item) + update_appearance() + forge_item.icon_state = "tong_full" + return ITEM_INTERACT_SUCCESS + + if(!obj_anvil_search && obj_tong_search) + obj_tong_search.forceMove(src) + update_appearance() + forge_item.icon_state = "tong_empty" + return ITEM_INTERACT_SUCCESS + +/obj/structure/reagent_anvil/hammer_act(mob/living/user, obj/item/tool) + //do we have an incomplete item to hammer out? if so, here is our block of code + var/obj/item/forging/incomplete/locate_incomplete = locate() in contents + if(locate_incomplete) + if (locate_incomplete.in_use) + balloon_alert(user, "being worked on") + return ITEM_INTERACT_SUCCESS + locate_incomplete.in_use = TRUE + do_hammer(user, tool, locate_incomplete) + locate_incomplete.in_use = FALSE + return ITEM_INTERACT_SUCCESS + + //okay, so we didn't find an incomplete item to hammer, do we have a hammerable item? + var/obj/locate_obj = locate() in contents + if(locate_obj && (locate_obj.obj_flags_doppler & ANVIL_REPAIR)) + if(locate_obj.get_integrity() >= locate_obj.max_integrity) + balloon_alert(user, "already repaired") + return ITEM_INTERACT_SUCCESS + + while(locate_obj.get_integrity() < locate_obj.max_integrity) + if(!do_after(user, 1 SECONDS, src)) + balloon_alert(user, "stopped repairing") + return ITEM_INTERACT_SUCCESS + + locate_obj.repair_damage(locate_obj.get_integrity() + 10) + user.mind.adjust_experience(/datum/skill/smithing, 5) //repairing does give some experience + playsound(src, 'modular_doppler/reagent_forging/sound/forge.ogg', 50, TRUE, ignore_walls = FALSE) + + return ITEM_INTERACT_SUCCESS + +/obj/structure/reagent_anvil/proc/do_hammer(mob/living/user, obj/item/tool, obj/item/forging/incomplete/locate_incomplete) + while(locate_incomplete.times_hit < locate_incomplete.average_hits) + var/skill_modifier = user.mind.get_skill_modifier(/datum/skill/smithing, SKILL_SPEED_MODIFIER) * locate_incomplete.average_wait + + if(!do_after(user, skill_modifier * tool.toolspeed, src)) + balloon_alert(user, "stopped hammering") + locate_incomplete.in_use = FALSE + return ITEM_INTERACT_SUCCESS + + if(locate_incomplete.loc != src) + balloon_alert(user, "workpiece moved!") + locate_incomplete.in_use = FALSE + return ITEM_INTERACT_SUCCESS + + playsound(src, 'modular_doppler/reagent_forging/sound/forge.ogg', 50, TRUE, ignore_walls = FALSE) + if(COOLDOWN_FINISHED(locate_incomplete, heating_remainder)) + balloon_alert(user, "metal too cool!") + locate_incomplete.times_hit -= 3 + if(locate_incomplete.times_hit <= -locate_incomplete.average_hits) + balloon_alert_to_viewers("workpiece breaks!") + qdel(locate_incomplete) + update_appearance() + return ITEM_INTERACT_SUCCESS + + locate_incomplete.times_hit++ + user.mind.adjust_experience(/datum/skill/smithing, 1) //A good hit gives minimal experience + + balloon_alert(user, "workpiece sounds ready") + +/obj/structure/reagent_anvil/hammer_act_secondary(mob/living/user, obj/item/tool) + hammer_act(user, tool) + +/obj/structure/reagent_anvil/onZImpact(turf/impacted_turf, levels, message = TRUE) + var/mob/living/poor_target = locate(/mob/living) in impacted_turf + if(!poor_target) + return ..() + + poor_target.apply_damage(60 * levels, forced = TRUE) + + if(istype(poor_target, /mob/living/carbon)) //If this mob is a carbon, break a few of their limbs + poor_target.take_bodypart_damage(40 * levels, wound_bonus = 5 * levels) + poor_target.take_bodypart_damage(40 * levels, wound_bonus = 5 * levels) + + poor_target.AddElement(/datum/element/squish, 30 SECONDS) + poor_target.visible_message( + span_bolddanger("[src] falls on [poor_target], crushing them!"), + span_userdanger("You are crushed by [src]!") + ) + poor_target.Paralyze(5 SECONDS) + poor_target.emote("scream") + playsound(poor_target, 'sound/magic/clockwork/fellowship_armory.ogg', 50, TRUE) + add_memory_in_range(poor_target, 7, /datum/memory/witness_vendor_crush, protagonist = poor_target, antognist = src) + return TRUE diff --git a/modular_doppler/reagent_forging/code/centrifuge.dm b/modular_doppler/reagent_forging/code/centrifuge.dm new file mode 100644 index 0000000000000..9bb4272a5c0cc --- /dev/null +++ b/modular_doppler/reagent_forging/code/centrifuge.dm @@ -0,0 +1,51 @@ +/obj/item/reagent_containers/cup/primitive_centrifuge + name = "primitive centrifuge" + desc = "A small cup that allows a person to slowly spin out liquids they do not desire." + icon = 'modular_doppler/reagent_forging/icons/obj/misc_tools.dmi' + icon_state = "primitive_centrifuge" + material_flags = MATERIAL_EFFECTS | MATERIAL_ADD_PREFIX | MATERIAL_GREYSCALE | MATERIAL_COLOR + +/obj/item/reagent_containers/cup/primitive_centrifuge/examine() + . = ..() + . += span_notice("Ctrl + Click to select chemicals to remove.") + . += span_notice("Ctrl + Shift + Click to select a chemical to keep, the rest removed.") + +/obj/item/reagent_containers/cup/primitive_centrifuge/item_ctrl_click(mob/user) + if(!length(reagents.reagent_list)) + return CLICK_ACTION_BLOCKING + + var/datum/user_input = tgui_input_list(user, "Select which chemical to remove.", "Removal Selection", reagents.reagent_list) + + if(!user_input) + balloon_alert(user, "no selection!") + return CLICK_ACTION_BLOCKING + + user.balloon_alert_to_viewers("spinning [src]...") + if(!do_after(user, 5 SECONDS, target = src)) + user.balloon_alert_to_viewers("stopped spinning [src]") + return CLICK_ACTION_BLOCKING + + reagents.del_reagent(user_input.type) + balloon_alert(user, "removed reagent from [src]") + return CLICK_ACTION_SUCCESS + +/obj/item/reagent_containers/cup/primitive_centrifuge/click_ctrl_shift(mob/user) + if(!length(reagents.reagent_list)) + return + + var/datum/user_input = tgui_input_list(user, "Select which chemical to keep, the rest removed.", "Keep Selection", reagents.reagent_list) + + if(!user_input) + balloon_alert(user, "no selection!") + return + + user.balloon_alert_to_viewers("spinning [src]...") + if(!do_after(user, 5 SECONDS, target = src)) + user.balloon_alert_to_viewers("stopped spinning [src]") + return + + for(var/datum/reagent/remove_reagent in reagents.reagent_list) + if(!istype(remove_reagent, user_input.type)) + reagents.del_reagent(remove_reagent.type) + + balloon_alert(user, "removed reagents from [src]") diff --git a/modular_doppler/reagent_forging/code/crafting_bench.dm b/modular_doppler/reagent_forging/code/crafting_bench.dm new file mode 100644 index 0000000000000..2f98728a6a018 --- /dev/null +++ b/modular_doppler/reagent_forging/code/crafting_bench.dm @@ -0,0 +1,384 @@ +/// How many planks of wood are required to complete a weapon? +#define WEAPON_COMPLETION_WOOD_AMOUNT 2 + +/// The number of hits you are set back when a bad hit is made +#define BAD_HIT_PENALTY 3 + +/obj/structure/reagent_crafting_bench + name = "forging workbench" + desc = "A crafting bench fitted with tools, securing mechanisms, and a steady surface for blacksmithing." + icon = 'modular_doppler/reagent_forging/icons/obj/forge_structures.dmi' + icon_state = "crafting_bench_empty" + + anchored = TRUE + density = TRUE + ///whether the crafting is being hammered + var/in_use = FALSE + + /// What the currently picked recipe is + var/datum/crafting_bench_recipe/selected_recipe + /// How many successful hits towards completion of the item have we done + var/current_hits_to_completion = 0 + /// Is this bench able to complete forging items? Exists to allow non-forging workbenches to exist + var/finishes_forging_weapons = TRUE + /// The cooldown from the last hit before we allow another 'good hit' to happen + COOLDOWN_DECLARE(hit_cooldown) + /// What recipes are we allowed to choose from? + var/list/allowed_choices = list( + /datum/crafting_bench_recipe/plate_helmet, + /datum/crafting_bench_recipe/plate_vest, + /datum/crafting_bench_recipe/plate_gloves, + /datum/crafting_bench_recipe/plate_boots, + /datum/crafting_bench_recipe/ring, + // /datum/crafting_bench_recipe/collar, + /datum/crafting_bench_recipe/handcuffs, + /datum/crafting_bench_recipe/pavise, + /datum/crafting_bench_recipe/buckler, + /datum/crafting_bench_recipe/seed_mesh, + /datum/crafting_bench_recipe/centrifuge, + /datum/crafting_bench_recipe/soup_pot, + /datum/crafting_bench_recipe/bokken, + /datum/crafting_bench_recipe/bow, + ) + /// Radial options for recipes in the allowed_choices list, populated by populate_radial_choice_list + var/list/radial_choice_list = list() + /// An associative list of names --> recipe path that the radial recipe picker will choose from later + var/list/recipe_names_to_path = list() + +/obj/structure/reagent_crafting_bench/Initialize(mapload) + . = ..() + populate_radial_choice_list() + +/obj/structure/reagent_crafting_bench/proc/populate_radial_choice_list() + if(!length(allowed_choices)) + return + + if(length(radial_choice_list) && length(recipe_names_to_path)) // We already have both of these and don't need it, if this is called after these are generated for some reason + return + + for(var/recipe in allowed_choices) + var/datum/crafting_bench_recipe/recipe_to_take_from = new recipe() + var/obj/recipe_resulting_item = recipe_to_take_from.resulting_item + radial_choice_list[recipe_to_take_from.recipe_name] = image(icon = initial(recipe_resulting_item.icon), icon_state = initial(recipe_resulting_item.icon_state)) + recipe_names_to_path[recipe_to_take_from.recipe_name] = recipe + qdel(recipe_to_take_from) + + +/obj/structure/reagent_crafting_bench/examine(mob/user) + . = ..() + + if(length(contents)) + if(istype(contents[1], /obj/item/forging/complete)) + var/obj/item/forging/complete/contained_forge_item = contents[1] + + . += span_notice("[src] has a [initial(contained_forge_item.name)] sitting on it, awaiting completion.
") + var/obj/item/completion_item = contained_forge_item.spawning_item + . += span_notice("With [WEAPON_COMPLETION_WOOD_AMOUNT] sheets of wood nearby, and some hammering, it could be completed into a [initial(completion_item.name)].") + return // We don't want to show any selected recipes if there's weapon head on the bench + + if(!selected_recipe) + return + + var/obj/resulting_item = selected_recipe.resulting_item + . += span_notice("The selected recipe's resulting item is: [initial(resulting_item.name)]
") + . += span_notice("Gather the required materials, listed below, near the bench, then start hammering to complete it!
") + + if(!length(selected_recipe.recipe_requirements)) + . += span_boldwarning("Somehow, this recipe has no requirements, report this as this shouldn't happen.") + return + + for(var/obj/requirement_item as anything in selected_recipe.recipe_requirements) + if(!selected_recipe.recipe_requirements[requirement_item]) + . += span_boldwarning("[requirement_item] does not have an amount required set, this should not happen, report it.") + continue + + . += span_notice("[selected_recipe.recipe_requirements[requirement_item]] - [initial(requirement_item.name)]") + + return . + +/obj/structure/reagent_crafting_bench/update_appearance(updates) + . = ..() + cut_overlays() + + if(!length(contents)) + return + + var/image/overlayed_item = image(icon = contents[1].icon, icon_state = contents[1].icon_state) + add_overlay(overlayed_item) + +/obj/structure/reagent_crafting_bench/attack_hand(mob/living/user, list/modifiers) + . = ..() + if(in_use) + balloon_alert(user, "already in use") + return + + update_appearance() + + if(length(contents)) + var/obj/item/contained_item = contents[1] + user.put_in_hands(contained_item) + balloon_alert(user, "[contained_item] retrieved") + update_appearance() + return + + if(selected_recipe) + clear_recipe() + balloon_alert_to_viewers("recipe cleared") + update_appearance() + return + + var/chosen_recipe = show_radial_menu(user, src, radial_choice_list, radius = 38, require_near = TRUE, tooltips = TRUE) + + if(!chosen_recipe) + balloon_alert(user, "no recipe choice") + return + + var/datum/crafting_bench_recipe/recipe_to_use = recipe_names_to_path[chosen_recipe] + selected_recipe = new recipe_to_use + + balloon_alert(user, "recipe chosen") + update_appearance() + +/// Clears the current recipe and sets hits to completion to zero +/obj/structure/reagent_crafting_bench/proc/clear_recipe() + QDEL_NULL(selected_recipe) + current_hits_to_completion = 0 + +/obj/structure/reagent_crafting_bench/attackby(obj/item/attacking_item, mob/user, params) + if(in_use) + balloon_alert(user, "already in use") + return + + if(istype(attacking_item, /obj/item/forging/complete)) + if(length(contents)) + balloon_alert(user, "already full") + return TRUE + + attacking_item.forceMove(src) + balloon_alert_to_viewers("placed [attacking_item]") + update_appearance() + return TRUE + + return ..() + +/obj/structure/reagent_crafting_bench/wrench_act(mob/living/user, obj/item/tool) + if(in_use) + balloon_alert(user, "it's currently in use!") + return + + user.balloon_alert_to_viewers("disassembling...") + if(!tool.use_tool(src, user, 2 SECONDS, volume = 100)) + return + + deconstruct(disassembled = TRUE) + return ITEM_INTERACT_SUCCESS + +/obj/structure/reagent_crafting_bench/atom_deconstruct(disassembled = TRUE) + new /obj/item/stack/sheet/mineral/wood(drop_location(), 5) + +/obj/structure/reagent_crafting_bench/hammer_act(mob/living/user, obj/item/tool) + if(in_use) + balloon_alert(user, "already in use") + return ITEM_INTERACT_SUCCESS + + if(length(contents)) + if(!istype(contents[1], /obj/item/forging/complete)) + balloon_alert(user, "invalid item") + return ITEM_INTERACT_SUCCESS + + var/obj/item/forging/complete/weapon_to_finish = contents[1] + + if(!weapon_to_finish.spawning_item) + balloon_alert(user, "[weapon_to_finish] cannot be completed") + return ITEM_INTERACT_SUCCESS + + var/list/wood_required_for_weapons = list( + /obj/item/stack/sheet/mineral/wood = WEAPON_COMPLETION_WOOD_AMOUNT, + ) + + if(!can_we_craft_this(wood_required_for_weapons)) + balloon_alert(user, "not enough wood") + return ITEM_INTERACT_SUCCESS + + var/list/things_to_use = can_we_craft_this(wood_required_for_weapons, TRUE) + var/obj/thing_just_made = create_thing_from_requirements(things_to_use, user = user, skill_to_grant = /datum/skill/smithing, skill_amount = 30, completing_a_weapon = TRUE) + + if(!thing_just_made) + message_admins("[src] just tried to finish a weapon but somehow created nothing! This is not working as intended!") + return ITEM_INTERACT_SUCCESS + + playsound(src, 'modular_doppler/reagent_forging/sound/forge.ogg', 50, TRUE) + + balloon_alert_to_viewers("[thing_just_made] created") + update_appearance() + return ITEM_INTERACT_SUCCESS + + if(!selected_recipe) + balloon_alert(user, "no recipe selected") + return ITEM_INTERACT_SUCCESS + + if(!can_we_craft_this(selected_recipe.recipe_requirements)) + balloon_alert(user, "missing ingredients") + return ITEM_INTERACT_SUCCESS + + in_use = TRUE + do_hammer(user, selected_recipe, current_hits_to_completion) + in_use = FALSE + var/list/things_to_use = can_we_craft_this(selected_recipe.recipe_requirements, TRUE) + create_thing_from_requirements(things_to_use, selected_recipe, user, selected_recipe.relevant_skill, selected_recipe.relevant_skill_reward) + return ITEM_INTERACT_SUCCESS + +/obj/structure/reagent_crafting_bench/proc/do_hammer(mob/living/user, datum/crafting_bench_recipe/selected_recipe, current_hits_to_completion) + while(current_hits_to_completion < selected_recipe.required_good_hits) + var/skill_modifier = user.mind.get_skill_modifier(selected_recipe.relevant_skill, SKILL_SPEED_MODIFIER) * 1 SECONDS + + if(!do_after(user, skill_modifier, src)) + balloon_alert(user, "stopped hammering") + in_use = FALSE + return ITEM_INTERACT_SUCCESS + + if(!can_we_craft_this(selected_recipe.recipe_requirements)) + balloon_alert(user, "missing ingredients") + in_use = FALSE + return ITEM_INTERACT_SUCCESS + + playsound(src, 'modular_doppler/reagent_forging/sound/forge.ogg', 50, TRUE) + current_hits_to_completion++ + user.mind.adjust_experience(selected_recipe.relevant_skill, selected_recipe.relevant_skill_reward / 15) + +/// Takes the given list of item requirements and checks the surroundings for them, returns TRUE unless return_ingredients_list is set, in which case a list of all the items to use is returned +/obj/structure/reagent_crafting_bench/proc/can_we_craft_this(list/required_items, return_ingredients_list = FALSE) + if(!length(required_items)) + message_admins("[src] just tried to check for ingredients nearby without having a list of items to check for!") + return FALSE + + var/list/surrounding_items = list() + var/list/requirement_items = list() + + for(var/obj/item/potential_requirement in get_environment()) + surrounding_items += potential_requirement + + for(var/obj/item/requirement_path as anything in required_items) + var/required_amount = required_items[requirement_path] + + for(var/obj/item/nearby_item as anything in surrounding_items) + if(!istype(nearby_item, requirement_path)) + continue + + if(isstack(nearby_item)) // If the item is a stack, check if that stack has enough material in it to fill out the amount + var/obj/item/stack/nearby_stack = nearby_item + if(required_amount > 0) + requirement_items += nearby_item + required_amount -= nearby_stack.amount + else // Otherwise, we still exist and should subtract one from the required number of items + if(required_amount > 0) + requirement_items += nearby_item + required_amount -= 1 + + if(required_amount > 0) + return FALSE + + if(return_ingredients_list) + return requirement_items + else + return TRUE + +/// Passes the list of found ingredients + the recipe to use_or_delete_recipe_requirements, then spawns the given recipe's result +/obj/structure/reagent_crafting_bench/proc/create_thing_from_requirements(list/things_to_use, datum/crafting_bench_recipe/recipe_to_follow, mob/living/user, datum/skill/skill_to_grant, skill_amount, completing_a_weapon) + + if(!recipe_to_follow && !completing_a_weapon) + message_admins("[src] just tried to complete a recipe without having a recipe, and without it being the completion of a forging weapon!") + return FALSE + + if(completing_a_weapon && (!length(contents) || !istype(contents[1], /obj/item/forging/complete))) + message_admins("[src] just tried to complete a forge weapon without there being a weapon head inside it to complete!") + return FALSE + + if(!length(things_to_use)) + message_admins("[src] just tried to craft something from requirements, but was not given a list of requirements!") + return FALSE + + if(completing_a_weapon) + recipe_to_follow = new /datum/crafting_bench_recipe/weapon_completion_recipe + + var/materials_to_transfer = list() + var/list/temporary_materials_list = use_or_delete_recipe_requirements(things_to_use, recipe_to_follow) + for(var/material as anything in temporary_materials_list) + materials_to_transfer[material] += temporary_materials_list[material] + + var/obj/newly_created_thing + + if(completing_a_weapon) + var/obj/item/forging/complete/completed_forge_item = contents[1] + newly_created_thing = new completed_forge_item.spawning_item(src) + if(completed_forge_item.custom_materials) // We need to add the weapon head's materials to the completed item, too + for(var/custom_material in completed_forge_item.custom_materials) + materials_to_transfer[custom_material] += completed_forge_item.custom_materials[custom_material] + qdel(completed_forge_item) // And then we also need to 'use' the item + + else + newly_created_thing = new recipe_to_follow.resulting_item(src) + + if(!newly_created_thing) + message_admins("[src] just failed to create something while crafting!") + return FALSE + + if(recipe_to_follow.transfers_materials) + newly_created_thing.set_custom_materials(materials_to_transfer, multiplier = 1) + + user.mind.adjust_experience(skill_to_grant, skill_amount) + + clear_recipe() + update_appearance() + return newly_created_thing + +/// Takes the given list, things_to_use, compares it to recipe_to_follow's requirements, then either uses items from a stack, or deletes them otherwise. Returns custom material of forge items in the end. +/obj/structure/reagent_crafting_bench/proc/use_or_delete_recipe_requirements(list/things_to_use, datum/crafting_bench_recipe/recipe_to_follow) + var/list/materials_to_transfer = list() + + for(var/obj/requirement_item as anything in things_to_use) + if(isstack(requirement_item)) + var/stack_type + for(var/recipe_thing_to_reference as anything in recipe_to_follow.recipe_requirements) + if(!istype(requirement_item, recipe_thing_to_reference)) + continue + stack_type = recipe_thing_to_reference + break + + var/obj/item/stack/requirement_stack = requirement_item + + if(requirement_stack.amount < recipe_to_follow.recipe_requirements[stack_type]) + recipe_to_follow.recipe_requirements[stack_type] -= requirement_stack.amount + requirement_stack.use(requirement_stack.amount) + continue + + requirement_stack.use(recipe_to_follow.recipe_requirements[stack_type]) + + else if(istype(requirement_item, /obj/item/forging/complete)) + if(!requirement_item.custom_materials || !recipe_to_follow.transfers_materials) + qdel(requirement_item) + continue + + for(var/custom_material as anything in requirement_item.custom_materials) + materials_to_transfer += custom_material + qdel(requirement_item) + + else + qdel(requirement_item) + + return materials_to_transfer + +/// Gets movable atoms within one tile of range of the crafting bench +/obj/structure/reagent_crafting_bench/proc/get_environment() + . = list() + + if(!get_turf(src)) + return + + for(var/atom/movable/found_movable_atom in range(1, src)) + if((found_movable_atom.flags_1 & HOLOGRAM_1)) + continue + . += found_movable_atom + return . + +#undef WEAPON_COMPLETION_WOOD_AMOUNT diff --git a/modular_doppler/reagent_forging/code/crafting_bench_recipes.dm b/modular_doppler/reagent_forging/code/crafting_bench_recipes.dm new file mode 100644 index 0000000000000..6e608996abf38 --- /dev/null +++ b/modular_doppler/reagent_forging/code/crafting_bench_recipes.dm @@ -0,0 +1,134 @@ +/datum/crafting_bench_recipe + /// The name of the recipe to show + var/recipe_name = "generic debug recipe" + /// The items required to create the resulting item + var/list/recipe_requirements + /// What the end result of this recipe should be + var/resulting_item = /obj/item/forging + /// If we use the materials from the component parts + var/transfers_materials = TRUE + /// How many times should you have to swing the hammer to finish this item + var/required_good_hits = 6 + /// What skill is relevant to the creation of this item? + var/relevant_skill = /datum/skill/smithing + /// How much experience in our relevant skill do we give upon completion? + var/relevant_skill_reward = 30 + +/datum/crafting_bench_recipe/weapon_completion_recipe //Exists so I don't have to modify the code too much for weapon completion + recipe_name = "generic weapon completion recipe (should not be visible)" + recipe_requirements = list( + /obj/item/stack/sheet/mineral/wood = 2, + ) + +/datum/crafting_bench_recipe/plate_helmet + recipe_name = "plate helmet" + recipe_requirements = list( + /obj/item/forging/complete/plate = 4, + ) + resulting_item = /obj/item/clothing/head/helmet/forging_plate_helmet + required_good_hits = 8 + +/datum/crafting_bench_recipe/plate_vest + recipe_name = "plate vest" + recipe_requirements = list( + /obj/item/forging/complete/plate = 6, + ) + resulting_item = /obj/item/clothing/suit/armor/forging_plate_armor + required_good_hits = 12 + +/datum/crafting_bench_recipe/plate_gloves + recipe_name = "plate gloves" + recipe_requirements = list( + /obj/item/forging/complete/plate = 2, + ) + resulting_item = /obj/item/clothing/gloves/forging_plate_gloves + required_good_hits = 4 + +/datum/crafting_bench_recipe/plate_boots + recipe_name = "plate boots" + recipe_requirements = list( + /obj/item/forging/complete/plate = 4, + ) + resulting_item = /obj/item/clothing/shoes/forging_plate_boots + required_good_hits = 8 + +/datum/crafting_bench_recipe/ring + recipe_name = "ring" + recipe_requirements = list( + /obj/item/forging/complete/chain = 2, + ) + resulting_item = /obj/item/clothing/gloves/ring/reagent_clothing + required_good_hits = 4 + +// /datum/crafting_bench_recipe/collar +// recipe_name = "collar" +// recipe_requirements = list( +// /obj/item/forging/complete/chain = 3, +// ) +// resulting_item = /obj/item/clothing/neck/collar/reagent_clothing +// required_good_hits = 6 + +/datum/crafting_bench_recipe/handcuffs + recipe_name = "handcuffs" + recipe_requirements = list( + /obj/item/forging/complete/chain = 5, + ) + resulting_item = /obj/item/restraints/handcuffs/reagent_clothing + required_good_hits = 10 + +/datum/crafting_bench_recipe/pavise + recipe_name = "pavise" + recipe_requirements = list( + /obj/item/forging/complete/plate = 8, + ) + resulting_item = /obj/item/shield/buckler/reagent_weapon/pavise + required_good_hits = 16 + +/datum/crafting_bench_recipe/buckler + recipe_name = "buckler" + recipe_requirements = list( + /obj/item/forging/complete/plate = 5, + ) + resulting_item = /obj/item/shield/buckler/reagent_weapon + required_good_hits = 10 + +/datum/crafting_bench_recipe/seed_mesh + recipe_name = "seed mesh" + recipe_requirements = list( + /obj/item/forging/complete/plate = 1, + /obj/item/forging/complete/chain = 2, + ) + resulting_item = /obj/item/seed_mesh + required_good_hits = 10 + +/datum/crafting_bench_recipe/centrifuge + recipe_name = "centrifuge" + recipe_requirements = list( + /obj/item/forging/complete/plate = 1, + ) + resulting_item = /obj/item/reagent_containers/cup/primitive_centrifuge + required_good_hits = 4 + +/datum/crafting_bench_recipe/soup_pot + recipe_name = "soup pot" + recipe_requirements = list( + /obj/item/forging/complete/plate = 4, + ) + resulting_item = /obj/item/reagent_containers/cup/soup_pot + required_good_hits = 10 + +/datum/crafting_bench_recipe/bokken + recipe_name = "bokken" + recipe_requirements = list( + /obj/item/stack/sheet/mineral/wood = 4, + ) + resulting_item = /obj/item/forging/reagent_weapon/bokken + required_good_hits = 8 + +/datum/crafting_bench_recipe/bow + recipe_name = "bow" + recipe_requirements = list( + /obj/item/stack/sheet/mineral/wood = 4, + ) + resulting_item = /obj/item/forging/incomplete_bow + required_good_hits = 8 diff --git a/modular_doppler/reagent_forging/code/forge.dm b/modular_doppler/reagent_forging/code/forge.dm new file mode 100644 index 0000000000000..27902e41c9cbe --- /dev/null +++ b/modular_doppler/reagent_forging/code/forge.dm @@ -0,0 +1,1008 @@ +/// The baseline time to take for doing actions with the forge, like heating glass, setting ceramics, etc. +#define BASELINE_ACTION_TIME (4 SECONDS) + +/// The basline for how long an item such as molten glass will be kept workable after heating +#define BASELINE_HEATING_DURATION (25 SECONDS) + +/// The amount the forge's temperature will change per process +#define FORGE_DEFAULT_TEMPERATURE_CHANGE 5 +/// The maximum temperature the forge can reach +#define MAX_FORGE_TEMP 100 +/// The minimum temperature for using the forge +#define MIN_FORGE_TEMP 50 +/// The duration that objects heated in the forge are heated for +#define FORGE_HEATING_DURATION (1 MINUTES) + +/// Defines for different levels of the forge, ranging from no level (you play like a noob) to legendary +#define FORGE_LEVEL_YOU_PLAY_LIKE_A_NOOB 1 +#define FORGE_LEVEL_NOVICE 2 +#define FORGE_LEVEL_APPRENTICE 3 +#define FORGE_LEVEL_JOURNEYMAN 4 +#define FORGE_LEVEL_EXPERT 5 +#define FORGE_LEVEL_MASTER 6 +#define FORGE_LEVEL_LEGENDARY 7 + +/// The maximum amount of temperature loss decrease that upgrades can give the forge +#define MAX_TEMPERATURE_LOSS_DECREASE 5 + +/// The chance per piece of wood added that charcoal will form later +#define CHARCOAL_CHANCE 45 + +/// The minimum units of a reagent rerquired to imbue it into a weapon +#define MINIMUM_IMBUING_REAGENT_AMOUNT 100 + +/// Defines for the different levels of smoke coming out of the forge, (good, neutral, bad) are all used for baking, (not cooking) is used for when there is no tray in the forge +#define SMOKE_STATE_NONE 0 +#define SMOKE_STATE_GOOD 1 +#define SMOKE_STATE_NEUTRAL 2 +#define SMOKE_STATE_BAD 3 +#define SMOKE_STATE_NOT_COOKING 4 + +/obj/structure/reagent_forge + name = "forge" + desc = "A structure built out of bricks, for heating up metal, or glass, or ceramic, or food, or anything really." + icon = 'modular_doppler/reagent_forging/icons/obj/forge_structures.dmi' + icon_state = "forge_inactive" + + anchored = TRUE + density = TRUE + + /// What the current internal temperature of the forge is + var/forge_temperature = 0 + /// What temperature the forge is moving towards + var/target_temperature = 0 + /// What the minimum target temperature is, used for upgrades + var/minimum_target_temperature = 0 + /// What is the current reduction for temperature decrease + var/temperature_loss_reduction = 0 + /// How many seconds of weak fuel (wood) does the forge have left + var/forge_fuel_weak = 0 + /// How many seconds of strong fuel (coal) does the forge have left + var/forge_fuel_strong = 0 + /// If the forge is capable of reagent forging or not + var/reagent_forging = FALSE + /// Cooldown time for processing on the forge + COOLDOWN_DECLARE(forging_cooldown) + /// Is the forge in use or not? If true, prevents most interactions with the forge + var/in_use = FALSE + /// The current 'level' of the forge, how upgraded is it from zero to three + var/forge_level = FORGE_LEVEL_YOU_PLAY_LIKE_A_NOOB + /// What smoke particles should be coming out of the forge + var/smoke_state = SMOKE_STATE_NONE + /// Tracks any oven tray placed inside of the forge + var/obj/item/plate/oven_tray/used_tray + /// The list of possible things to make with materials used on the forge + var/static/list/choice_list = list( + "Chain" = /obj/item/forging/incomplete/chain, + "Plate" = /obj/item/forging/incomplete/plate, + "Sword" = /obj/item/forging/incomplete/sword, + "Katana" = /obj/item/forging/incomplete/katana, + "Dagger" = /obj/item/forging/incomplete/dagger, + "Staff" = /obj/item/forging/incomplete/staff, + "Spear" = /obj/item/forging/incomplete/spear, + "Axe" = /obj/item/forging/incomplete/axe, + "Hammer" = /obj/item/forging/incomplete/hammer, + "Pickaxe" = /obj/item/forging/incomplete/pickaxe, + "Shovel" = /obj/item/forging/incomplete/shovel, + "Arrowhead" = /obj/item/forging/incomplete/arrowhead, + "Rail Nail" = /obj/item/forging/incomplete/rail_nail, + "Rail Cart" = /obj/item/forging/incomplete/rail_cart, + ) + /// List of possible choices for the selection radial + var/list/radial_choice_list = list() + /// Blacklist that contains reagents that weapons and armor are unable to be imbued with. + var/static/list/disallowed_reagents = typecacheof(list( + /datum/reagent/inverse/, + /datum/reagent/consumable/entpoly, + /datum/reagent/pax, + /datum/reagent/consumable/liquidelectricity/enriched, + /datum/reagent/teslium, + /datum/reagent/eigenstate, + /datum/reagent/toxin/acid, + /datum/reagent/phlogiston, + /datum/reagent/napalm, + /datum/reagent/thermite, + /datum/reagent/medicine/earthsblood, + /datum/reagent/medicine/ephedrine, + /datum/reagent/medicine/epinephrine, + )) + +/obj/structure/reagent_forge/examine(mob/user) + . = ..() + + if(used_tray) + . += span_notice("It has [used_tray] in it, which can be removed with an empty hand.") + else + . += span_notice("You can place an oven tray in this to bake any items on it.") + + if(forge_level < FORGE_LEVEL_LEGENDARY) + . += span_notice("Using an empty hand on [src] will upgrade it, if your forging skill level is above the current upgrade's level.") + + switch(forge_level) + if(FORGE_LEVEL_YOU_PLAY_LIKE_A_NOOB) + . += span_notice("This forge has not been upgraded yet.") + + if(FORGE_LEVEL_NOVICE) + . += span_notice("This forge has been upgraded by a novice smith.") + + if(FORGE_LEVEL_APPRENTICE) + . += span_notice("This forge has been upgraded by an apprentice smith.") + + if(FORGE_LEVEL_JOURNEYMAN) + . += span_notice("This forge has been upgraded by a journeyman smith.") + + if(FORGE_LEVEL_EXPERT) + . += span_notice("This forge has been upgraded by an expert smith.") + + if(FORGE_LEVEL_MASTER) + . += span_notice("This forge has been upgraded by a master smith.") + + if(FORGE_LEVEL_LEGENDARY) + . += span_hierophant("This forge has been upgraded by a legendary smith.") // Legendary skills give you the greatest gift of all, cool text + + switch(temperature_loss_reduction) + if(0) + . += span_notice("[src] will lose heat at a normal rate.") + if(1) + . += span_notice("[src] will lose heat slightly slower than usual.") + if(2) + . += span_notice("[src] will lose heat a bit slower than usual.") + if(3) + . += span_notice("[src] will lose heat much slower than usual.") + if(4) + . += span_notice("[src] will lose heat signficantly slower than usual.") + if(5) + . += span_notice("[src] will lose heat at a practically negligible rate.") + + . += span_notice("
[src] is currently [forge_temperature] degrees hot, going towards [target_temperature] degrees.
") + + if(reagent_forging && (is_species(user, /datum/species/lizard/ashwalker) || is_species(user, /datum/species/human/felinid/primitive))) + . += span_warning("[src] has a fine gold trim, it is ready to imbue chemicals into reagent objects.") + + return . + +/obj/structure/reagent_forge/Initialize(mapload) + . = ..() + START_PROCESSING(SSobj, src) + populate_radial_choice_list() + update_appearance() + upgrade_forge(forced = TRUE) + +/// Fills out the radial choice list with everything in the choice_list's contents +/obj/structure/reagent_forge/proc/populate_radial_choice_list() + if(!length(choice_list)) + return + + if(length(radial_choice_list)) + return + + for(var/forge_option in choice_list) + var/obj/resulting_item = choice_list[forge_option] + radial_choice_list[forge_option] = image(icon = initial(resulting_item.icon), icon_state = initial(resulting_item.icon_state)) + +/obj/structure/reagent_forge/Destroy() + STOP_PROCESSING(SSobj, src) + QDEL_NULL(particles) + if(used_tray) + QDEL_NULL(used_tray) + . = ..() + +/obj/structure/reagent_forge/update_appearance(updates) + . = ..() + cut_overlays() + + if(reagent_forging) // If we can do reagent forging, give the forge the gold trim + var/image/gold_overlay = image(icon = icon, icon_state = "forge_masterwork_trim") + add_overlay(gold_overlay) + + if(used_tray) // If we have a tray inside, check if the forge is on or not, then give the corresponding tray overlay + var/image/tray_overlay = image(icon = icon, icon_state = "forge_tray_[check_fuel(just_checking = TRUE) ? "active" : "inactive"]") + add_overlay(tray_overlay) + +/// Checks if the forge has fuel, if so what type. If it has either type of fuel, returns TRUE, otherwise returns FALSE. just_checking will check if there is fuel without taking actions +/obj/structure/reagent_forge/proc/check_fuel(just_checking = FALSE) + if(forge_fuel_strong) // Check for strong fuel (coal) first, as it has more power over weaker fuels + if(just_checking) + return TRUE + + forge_fuel_strong -= 5 SECONDS + target_temperature = 100 + return TRUE + + if(forge_fuel_weak) // If there's no strong fuel, maybe we have weak fuel (wood) + if(just_checking) + return TRUE + + forge_fuel_weak -= 5 SECONDS + target_temperature = 50 + return TRUE + + if(just_checking) + return FALSE + + target_temperature = minimum_target_temperature // If the forge has no fuel, then we should lowly return to the minimum lowest temp we can do + return FALSE + +/// Gives the forge the ability to imbue reagents into things +/obj/structure/reagent_forge/proc/create_reagent_forge() + if(reagent_forging) // If the forge can already do reagent forging, then we can skip the rest of this + return + reagent_forging = TRUE + update_appearance() + +/// Creates both a fail message balloon alert, and sets in_use to false +/obj/structure/reagent_forge/proc/fail_message(mob/living/user, message) + balloon_alert(user, message) + in_use = FALSE + +/// Adjust the temperature to head towards the target temperature, changing icon and creating light if the temperature is rising +/obj/structure/reagent_forge/proc/check_temp() + if(forge_temperature > target_temperature) // Being above the target temperature will cause the forge to cool down + forge_temperature -= (FORGE_DEFAULT_TEMPERATURE_CHANGE - temperature_loss_reduction) + return + + else if((forge_temperature < target_temperature) && (forge_fuel_weak || forge_fuel_strong)) // Being below the target temp, and having fuel, will cause the temp to rise + forge_temperature += FORGE_DEFAULT_TEMPERATURE_CHANGE + return + +/// If the forge is in use, checks if there is an oven tray, then if there are any mobs actually in use range. If not sets the forge to not be in use. +/obj/structure/reagent_forge/proc/check_in_use() + if(!in_use) + return + + if(used_tray) // We check if there's a tray because trays inside of the forge count as it being in use, even if nobody is around + return + + for(var/mob/living/living_mob in range(1,src)) + if(!living_mob) + in_use = FALSE + +/// Spawns a piece of coal at the forge and renames it to charcoal +/obj/structure/reagent_forge/proc/spawn_coal() + var/obj/item/stack/sheet/mineral/coal/spawn_coal = new(get_turf(src)) + spawn_coal.name = "charcoal" + +/obj/structure/reagent_forge/process(seconds_per_tick) + if(!COOLDOWN_FINISHED(src, forging_cooldown)) + return + + COOLDOWN_START(src, forging_cooldown, 5 SECONDS) + check_fuel() + check_temp() + check_in_use() // This is here to ensure the forge doesn't remain in_use if it really isn't + + + + if(!used_tray && check_fuel(just_checking = TRUE)) + set_smoke_state(SMOKE_STATE_NOT_COOKING) // If there is no tray but we have fuel, use the not cooking smoke state + return + + if(!check_fuel(just_checking = TRUE)) // If there's no fuel, remove it all + set_smoke_state(SMOKE_STATE_NONE) + return + + handle_baking_things(seconds_per_tick) + +/// Sends signals to bake and items on the used tray, setting the smoke state of the forge according to the most cooked item in it +/obj/structure/reagent_forge/proc/handle_baking_things(seconds_per_tick) + if(forge_temperature < MIN_FORGE_TEMP) // If we are below minimum forge temp, don't continue on to cooking + return + + /// The worst off item being baked in our forge right now, to ensure people know when gordon ramsay is gonna be upset at them + var/worst_cooked_food_state = 0 + for(var/obj/item/baked_item as anything in used_tray.contents) + + var/signal_result = SEND_SIGNAL(baked_item, COMSIG_ITEM_OVEN_PROCESS, src, seconds_per_tick) + + if(signal_result & COMPONENT_HANDLED_BAKING) + if(signal_result & COMPONENT_BAKING_GOOD_RESULT && worst_cooked_food_state < SMOKE_STATE_GOOD) + worst_cooked_food_state = SMOKE_STATE_GOOD + else if(signal_result & COMPONENT_BAKING_BAD_RESULT && worst_cooked_food_state < SMOKE_STATE_NEUTRAL) + worst_cooked_food_state = SMOKE_STATE_NEUTRAL + continue + + worst_cooked_food_state = SMOKE_STATE_BAD + baked_item.fire_act(1000) // Overcooked food really does burn, hot hot hot! + + if(SPT_PROB(10, seconds_per_tick)) + var/list/asomnia_havers = get_hearers_in_view(DEFAULT_MESSAGE_RANGE, src) + for(var/mob/cannot_smell in asomnia_havers) + if(!HAS_TRAIT(cannot_smell, TRAIT_ANOSMIA)) + asomnia_havers -= cannot_smell + visible_message(span_danger("You smell a burnt smell coming from [src]!"), ignored_mobs = asomnia_havers) + // Give indication that something is burning in the oven + set_smoke_state(worst_cooked_food_state) + +/// Sets the type of particles that the forge should be generating +/obj/structure/reagent_forge/proc/set_smoke_state(new_state) + if(new_state == smoke_state) + return + + smoke_state = new_state + + QDEL_NULL(particles) + + switch(smoke_state) + if(SMOKE_STATE_NONE) + icon_state = "forge_inactive" + set_light(0, 0) // If we aren't heating up and thus not on fire, turn the fire light off + return + + if(SMOKE_STATE_BAD) + particles = new /particles/smoke() + particles.position = list(6, 4, 0) + + if(SMOKE_STATE_NEUTRAL) + particles = new /particles/smoke/steam() + particles.position = list(6, 4, 0) + + if(SMOKE_STATE_GOOD) + particles = new /particles/smoke/steam/mild() + particles.position = list(6, 4, 0) + + if(SMOKE_STATE_NOT_COOKING) + particles = new /particles/smoke/mild() + particles.position = list(6, 4, 0) + + icon_state = "forge_active" + set_light(3, 1, LIGHT_COLOR_FIRE) + +/obj/structure/reagent_forge/attack_hand(mob/living/user, list/modifiers) + . = ..() + if(used_tray) + remove_tray_from_forge(user) + return + + upgrade_forge(user) + +/obj/structure/reagent_forge/proc/upgrade_forge(mob/living/user, forced = FALSE) + var/level_to_upgrade_to + + if(forced || !user) // This is to make sure the ready subtype of forge still works + level_to_upgrade_to = forge_level + else + level_to_upgrade_to = user.mind.get_skill_level(/datum/skill/smithing) + + if((forge_level == level_to_upgrade_to) && !forced) + to_chat(user, span_notice("[src] was already upgraded by your level of expertise!")) + return + + switch(level_to_upgrade_to) // Remember to carry things over from past levels in case someone skips levels in upgrading + if(SKILL_LEVEL_NONE) + if(!forced) + to_chat(user, span_notice("You'll need some forging skills to really understand how to upgrade [src].")) + return + + if(SKILL_LEVEL_NOVICE) + if(!forced) + to_chat(user, span_notice("With some experience, you've come to realize there are some easily fixable spots with poor insulation...")) + temperature_loss_reduction = 1 + forge_level = FORGE_LEVEL_NOVICE + + if(SKILL_LEVEL_APPRENTICE) + if(!forced) + to_chat(user, span_notice("Further insulation and protection of the thinner areas means [src] will lose heat just that little bit slower.")) + temperature_loss_reduction = 2 + forge_level = FORGE_LEVEL_APPRENTICE + + if(SKILL_LEVEL_JOURNEYMAN) + if(!forced) + to_chat(user, span_notice("Some careful placement and stoking of the flame will allow you to keep at least the embers burning...")) + minimum_target_temperature = 25 // Will allow quicker reheating from having no fuel + temperature_loss_reduction = 3 + forge_level = FORGE_LEVEL_JOURNEYMAN + + if(SKILL_LEVEL_EXPERT) + if(!forced) + to_chat(user, span_notice("[src] has become nearly perfect, able to hold heat for long enough that even a piece of wood can outmatch the longevity of lesser forges.")) + temperature_loss_reduction = 4 + minimum_target_temperature = 25 + forge_level = FORGE_LEVEL_EXPERT + + if(SKILL_LEVEL_MASTER) + if(!forced) + to_chat(user, span_notice("The perfect forge for a perfect metalsmith, with your knowledge it should bleed heat so slowly, that not even you will live to see [src] cool.")) + temperature_loss_reduction = MAX_TEMPERATURE_LOSS_DECREASE + minimum_target_temperature = 25 + forge_level = FORGE_LEVEL_MASTER + + if(SKILL_LEVEL_LEGENDARY) + if(!forced) + if(is_species(user, /datum/species/lizard/ashwalker) || is_species(user, /datum/species/human/felinid/primitive)) + to_chat(user, span_notice("With just the right heat treating technique, metal could be made to accept reagents...")) + create_reagent_forge() + if(forge_level == FORGE_LEVEL_MASTER) + to_chat(user, span_warning("It is impossible to further improve the forge!")) + temperature_loss_reduction = MAX_TEMPERATURE_LOSS_DECREASE + minimum_target_temperature = 25 // This won't matter except in a few cases here, but we still need to cover those few cases + forge_level = FORGE_LEVEL_LEGENDARY + + playsound(src, 'sound/weapons/parry.ogg', 50, TRUE) // Play a feedback sound to really let players know we just did an upgrade + +/obj/structure/reagent_forge/attackby(obj/item/attacking_item, mob/living/user, params) + if(!used_tray && istype(attacking_item, /obj/item/plate/oven_tray)) + add_tray_to_forge(user, attacking_item) + return TRUE + + if(in_use) // If the forge is currently in use by someone (or there is a tray in it) then we cannot use it + if(used_tray) + balloon_alert(user, "remove [used_tray] first") + balloon_alert(user, "forge busy") + return TRUE + + if(istype(attacking_item, /obj/item/stack/sheet/mineral/wood)) // Wood is a weak fuel, and will only get the forge up to 50 temperature + refuel(attacking_item, user) + return TRUE + + if(istype(attacking_item, /obj/item/stack/sheet/mineral/coal)) // Coal is a strong fuel that doesn't need bellows to heat up properly + refuel(attacking_item, user, TRUE) + return TRUE + + if(istype(attacking_item, /obj/item/stack/ore)) + smelt_ore(attacking_item, user) + return TRUE + + if(attacking_item.GetComponent(/datum/component/reagent_weapon)) + handle_weapon_imbue(attacking_item, user) + return TRUE + + if(attacking_item.GetComponent(/datum/component/reagent_clothing)) + handle_clothing_imbue(attacking_item, user) + return TRUE + + if(istype(attacking_item, /obj/item/ceramic)) + handle_ceramics(attacking_item, user) + return TRUE + + if(istype(attacking_item, /obj/item/stack/sheet/glass)) + handle_glass_sheet_melting(attacking_item, user) + return TRUE + + if(istype(attacking_item, /obj/item/glassblowing/metal_cup)) + handle_metal_cup_melting(attacking_item, user) + return TRUE + + if(istype(attacking_item, /obj/item/stack/rods)) + in_use = TRUE + smelt_iron_rods(attacking_item, user) + in_use = FALSE + return TRUE + + return ..() + +/// Take the given tray and place it inside the forge, updating everything relevant to that +/obj/structure/reagent_forge/proc/add_tray_to_forge(mob/living/user, obj/item/plate/oven_tray/tray) + if(used_tray) // This shouldn't be able to happen but just to be safe + balloon_alert_to_viewers("already has tray") + return + + if(!user.transferItemToLoc(tray, src, silent = FALSE)) + return + + // need to send the right signal for each item in the tray + for(var/obj/item/baked_item in tray.contents) + SEND_SIGNAL(baked_item, COMSIG_ITEM_OVEN_PLACED_IN, src, user) + + balloon_alert_to_viewers("put [tray] in [src]") + used_tray = tray + in_use = TRUE // You can't use the forge if there's a tray sitting in it + update_appearance() + +/// Take the used_tray and spit it out, updating everything relevant to that +/obj/structure/reagent_forge/proc/remove_tray_from_forge(mob/living/carbon/user) + if(!used_tray) + if(user) + balloon_alert_to_viewers("no tray") + return + + if(user) + user.put_in_hands(used_tray) + balloon_alert_to_viewers("removed [used_tray]") + else + used_tray.forceMove(get_turf(src)) + used_tray = null + in_use = FALSE + +/// Adds to either the strong or weak fuel timers from the given stack +/obj/structure/reagent_forge/proc/refuel(obj/item/stack/refueling_stack, mob/living/user, is_strong_fuel = FALSE) + in_use = TRUE + + if(is_strong_fuel) + if(forge_fuel_strong >= 5 MINUTES) + fail_message(user, "[src] is full on coal") + return + if(forge_fuel_weak >= 5 MINUTES) + fail_message(user, "[src] is full on wood") + return + + balloon_alert_to_viewers("refueling...") + + var/obj/item/stack/sheet/stack_sheet = refueling_stack + if(!do_after(user, 3 SECONDS, target = src) || !stack_sheet.use(1)) + fail_message(user, "stopped fueling") + return + + if(is_strong_fuel) + forge_fuel_strong += 5 MINUTES + else + forge_fuel_weak += 5 MINUTES + in_use = FALSE + balloon_alert(user, "fueled [src]") + user.mind.adjust_experience(/datum/skill/smithing, 5) // You gain small amounts of experience from useful fueling + + if(prob(CHARCOAL_CHANCE) && !is_strong_fuel) + to_chat(user, span_notice("[src]'s fuel is packed densely enough to have made some charcoal!")) + addtimer(CALLBACK(src, PROC_REF(spawn_coal)), 1 MINUTES) + +/// Takes given ore and smelts it, possibly producing extra sheets if upgraded +/obj/structure/reagent_forge/proc/smelt_ore(obj/item/stack/ore/ore_item, mob/living/user) + in_use = TRUE + + if(forge_temperature < MIN_FORGE_TEMP) + fail_message(user, "forge too cool") + return + + var/skill_modifier = user.mind.get_skill_modifier(/datum/skill/smithing, SKILL_SPEED_MODIFIER) + + if(!ore_item.refined_type) + fail_message(user, "cannot smelt [ore_item]") + return + + balloon_alert_to_viewers("smelting...") + + if(!do_after(user, skill_modifier * 3 SECONDS, target = src)) + fail_message(user, "stopped smelting [ore_item]") + return + + var/src_turf = get_turf(src) + var/spawning_item = ore_item.refined_type + var/ore_to_sheet_amount = ore_item.amount + + for(var/spawn_ore in 1 to ore_to_sheet_amount) + new spawning_item(src_turf) + + in_use = FALSE + qdel(ore_item) + return + +/// Handles weapon reagent imbuing +/obj/structure/reagent_forge/proc/handle_weapon_imbue(obj/attacking_item, mob/living/user) + //This code will refuse all non-ashwalkers & non-icecats from imbuing + if(!ishuman(user)) + to_chat(user, span_danger("It is impossible for you to imbue!")) //maybe remove (ashwalkers & icecats only) after some time + return + + var/mob/living/carbon/human/human_user = user + if(!is_species(human_user, /datum/species/lizard/ashwalker) && !is_species(human_user, /datum/species/human/felinid/primitive)) + to_chat(user, span_danger("It is impossible for you to imbue!")) //maybe remove (ashwalkers & icecats only) after some time + return + + in_use = TRUE + balloon_alert_to_viewers("imbuing...") + + var/obj/item/attacking_weapon = attacking_item + + var/datum/component/reagent_weapon/weapon_component = attacking_weapon.GetComponent(/datum/component/reagent_weapon) + if(!weapon_component) + fail_message(user, "cannot imbue") + return + + if(length(weapon_component.imbued_reagent)) + fail_message(user, "already imbued") + return + + if(!do_after(user, 10 SECONDS, target = src)) + fail_message(user, "stopped imbuing") + return + + for(var/datum/reagent/weapon_reagent as anything in attacking_weapon.reagents.reagent_list) + if(weapon_reagent.volume < MINIMUM_IMBUING_REAGENT_AMOUNT) + attacking_weapon.reagents.remove_reagent(weapon_reagent.type) + continue + + if(is_type_in_typecache(weapon_reagent, disallowed_reagents)) + balloon_alert(user, "cannot imbue with [weapon_reagent.name]") + attacking_weapon.reagents.remove_reagent(weapon_reagent.type, include_subtypes = TRUE) + continue + + weapon_component.imbued_reagent += weapon_reagent.type + attacking_weapon.name = "[weapon_reagent.name] [attacking_weapon.name]" + + attacking_weapon.color = mix_color_from_reagents(attacking_weapon.reagents.reagent_list) + balloon_alert_to_viewers("imbued [attacking_weapon]") + user.mind.adjust_experience(/datum/skill/smithing, 60) + playsound(src, 'sound/magic/demon_consume.ogg', 50, TRUE) + in_use = FALSE + return TRUE + +/// Handles clothing imbuing, extremely similar to weapon imbuing but not in the same proc because of how uhh... goofy the way this has to be done is +/obj/structure/reagent_forge/proc/handle_clothing_imbue(obj/attacking_item, mob/living/user) + //This code will refuse all non-ashwalkers & non-icecats from imbuing + if(!ishuman(user)) + to_chat(user, span_danger("It is impossible for you to imbue!")) //maybe remove (ashwalkers & icecats only) after some time + return + + var/mob/living/carbon/human/human_user = user + if(!is_species(human_user, /datum/species/lizard/ashwalker) && !is_species(human_user, /datum/species/human/felinid/primitive)) + to_chat(user, span_danger("It is impossible for you to imbue!")) //maybe remove (ashwalkers & icecats only) after some time + return + + in_use = TRUE + balloon_alert_to_viewers("imbuing...") + + var/obj/item/attacking_clothing = attacking_item + + var/datum/component/reagent_clothing/clothing_component = attacking_clothing.GetComponent(/datum/component/reagent_clothing) + if(!clothing_component) + fail_message(user, "cannot imbue") + return + + if(length(clothing_component.imbued_reagent)) + fail_message(user, "already imbued") + return + + if(!do_after(user, 10 SECONDS, target = src)) + fail_message(user, "stopped imbuing") + return + + for(var/datum/reagent/clothing_reagent as anything in attacking_clothing.reagents.reagent_list) + if(clothing_reagent.volume < MINIMUM_IMBUING_REAGENT_AMOUNT) + attacking_clothing.reagents.remove_reagent(clothing_reagent.type, include_subtypes = TRUE) + continue + + if(is_type_in_typecache(clothing_reagent, disallowed_reagents)) + balloon_alert(user, "cannot imbue with [clothing_reagent.name]") + attacking_clothing.reagents.remove_reagent(clothing_reagent.type, include_subtypes = TRUE) + continue + + clothing_component.imbued_reagent += clothing_reagent.type + attacking_clothing.name = "[clothing_reagent.name] [attacking_clothing.name]" + + attacking_clothing.color = mix_color_from_reagents(attacking_clothing.reagents.reagent_list) + balloon_alert_to_viewers("imbued [attacking_clothing]") + user.mind.adjust_experience(/datum/skill/smithing, 60) + playsound(src, 'sound/magic/demon_consume.ogg', 50, TRUE) + in_use = FALSE + return TRUE + +/// Sets ceramic items from their unusable state into their finished form +/obj/structure/reagent_forge/proc/handle_ceramics(obj/attacking_item, mob/living/user) + in_use = TRUE + + if(forge_temperature < MIN_FORGE_TEMP) + fail_message(user, "forge too cool") + return + + var/obj/item/ceramic/ceramic_item = attacking_item + var/ceramic_speed = user.mind.get_skill_modifier(/datum/skill/production, SKILL_SPEED_MODIFIER) * BASELINE_ACTION_TIME + + if(!ceramic_item.forge_item) + fail_message(user, "cannot set [ceramic_item]") + return + + balloon_alert_to_viewers("setting [ceramic_item]") + + if(!do_after(user, ceramic_speed, target = src)) + fail_message("stopped setting [ceramic_item]") + return + + balloon_alert(user, "finished setting [ceramic_item]") + var/obj/item/ceramic/spawned_ceramic = new ceramic_item.forge_item(get_turf(src)) + user.mind.adjust_experience(/datum/skill/production, 50) + spawned_ceramic.color = ceramic_item.color + qdel(ceramic_item) + in_use = FALSE + +/// Handles the creation of molten glass from glass sheets +/obj/structure/reagent_forge/proc/handle_glass_sheet_melting(obj/attacking_item, mob/living/user) + in_use = TRUE + + if(forge_temperature < MIN_FORGE_TEMP) + fail_message(user, "forge too cool") + return + + var/obj/item/stack/sheet/glass/glass_item = attacking_item + var/glassblowing_speed = user.mind.get_skill_modifier(/datum/skill/production, SKILL_SPEED_MODIFIER) * BASELINE_ACTION_TIME + var/glassblowing_amount = BASELINE_HEATING_DURATION / user.mind.get_skill_modifier(/datum/skill/production, SKILL_SPEED_MODIFIER) + + balloon_alert_to_viewers("heating...") + + if(!do_after(user, glassblowing_speed, target = src) || !glass_item.use(1)) + fail_message(user, "stopped heating [glass_item]") + return + + in_use = FALSE + var/obj/item/glassblowing/molten_glass/spawned_glass = new /obj/item/glassblowing/molten_glass(get_turf(src)) + user.mind.adjust_experience(/datum/skill/production, 10) + COOLDOWN_START(spawned_glass, remaining_heat, glassblowing_amount) + spawned_glass.total_time = glassblowing_amount + +/// Handles creating molten glass from a metal cup filled with sand +/obj/structure/reagent_forge/proc/handle_metal_cup_melting(obj/attacking_item, mob/living/user) + in_use = TRUE + + if(forge_temperature < MIN_FORGE_TEMP) + fail_message(user, "forge too cool") + return + + var/obj/item/glassblowing/metal_cup/metal_item = attacking_item + var/glassblowing_speed = user.mind.get_skill_modifier(/datum/skill/production, SKILL_SPEED_MODIFIER) * BASELINE_ACTION_TIME + var/glassblowing_amount = BASELINE_HEATING_DURATION / user.mind.get_skill_modifier(/datum/skill/production, SKILL_SPEED_MODIFIER) + + if(!metal_item.has_sand) + fail_message(user, "[metal_item] has no sand") + return + + balloon_alert_to_viewers("heating...") + + if(!do_after(user, glassblowing_speed, target = src)) + fail_message(user, "stopped heating [metal_item]") + return + + in_use = FALSE + metal_item.has_sand = FALSE + metal_item.icon_state = "metal_cup_empty" // This should be handled a better way but presently this is how it works + var/obj/item/glassblowing/molten_glass/spawned_glass = new /obj/item/glassblowing/molten_glass(get_turf(src)) + user.mind.adjust_experience(/datum/skill/production, 10) + COOLDOWN_START(spawned_glass, remaining_heat, glassblowing_amount) + spawned_glass.total_time = glassblowing_amount + +/// Almost a copy from the proc smelt_ore but to smelt iron rods +/obj/structure/reagent_forge/proc/smelt_iron_rods(obj/attacking_item, mob/living/user) + + var/obj/item/stack/rods/rod_item = attacking_item + + if(!istype(rod_item)) + return + + if(forge_temperature < MIN_FORGE_TEMP) + fail_message(user, "forge too cool") + return + + var/skill_modifier = user.mind.get_skill_modifier(/datum/skill/smithing, SKILL_SPEED_MODIFIER) + + if(rod_item.amount < 2) + fail_message(user, "too few iron rods to smelt") + return + + balloon_alert_to_viewers("smelting...") + + if(!do_after(user, skill_modifier * 3 SECONDS, target = src)) + fail_message(user, "stopped smelting [rod_item]") + return + + var/rods_to_sheet_amount = round((rod_item.amount / 2)) + var/used_rods = rod_item.amount + + if(ISODD(used_rods)) + used_rods = used_rods - 1 + + rod_item.use(used_rods) + new /obj/item/stack/sheet/iron(drop_location(), rods_to_sheet_amount) + + balloon_alert_to_viewers("finished smelting!") + +/obj/structure/reagent_forge/billow_act(mob/living/user, obj/item/tool) + if(in_use) // Preventing billow use if the forge is in use to prevent spam + fail_message(user, "forge busy") + return ITEM_INTERACT_SUCCESS + + var/skill_modifier = user.mind.get_skill_modifier(/datum/skill/smithing, SKILL_SPEED_MODIFIER) + var/obj/item/forging/forge_item = tool + + if(!forge_fuel_strong && !forge_fuel_weak) + fail_message(user, "no fuel in [src]") + return ITEM_INTERACT_SUCCESS + + if(forge_temperature >= MAX_FORGE_TEMP) + fail_message(user, "[src] cannot heat further") + return ITEM_INTERACT_SUCCESS + + balloon_alert_to_viewers("billowing...") + + in_use = TRUE + while(forge_temperature < 91) + if(!do_after(user, (skill_modifier * forge_item.toolspeed) SECONDS, target = src)) + balloon_alert_to_viewers("stopped billowing") + in_use = FALSE + return ITEM_INTERACT_SUCCESS + + forge_temperature += 10 + user.mind.adjust_experience(/datum/skill/smithing, 5) // Billowing, like fueling, gives you some experience in forging + + in_use = FALSE + balloon_alert(user, "successfully heated [src]") + return ITEM_INTERACT_SUCCESS + +/obj/structure/reagent_forge/tong_act(mob/living/user, obj/item/tool) + var/skill_modifier = user.mind.get_skill_modifier(/datum/skill/smithing, SKILL_SPEED_MODIFIER) + var/obj/item/forging/forge_item = tool + + if(in_use || forge_item.in_use) + fail_message(user, "forge busy") + return ITEM_INTERACT_SUCCESS + + in_use = TRUE + forge_item.in_use = TRUE + + if(forge_temperature < MIN_FORGE_TEMP) + fail_message(user, "forge too cool") + forge_item.in_use = FALSE + return ITEM_INTERACT_SUCCESS + + // Here we check the item used on us (tongs) for an incomplete forge item of some kind to heat + var/obj/item/forging/incomplete/search_incomplete = locate(/obj/item/forging/incomplete) in forge_item.contents + if(search_incomplete) + if(!COOLDOWN_FINISHED(search_incomplete, heating_remainder)) + fail_message(user, "metal doesn't need heating") + forge_item.in_use = FALSE + return ITEM_INTERACT_SUCCESS + + balloon_alert_to_viewers("heating [search_incomplete]") + + if(!do_after(user, skill_modifier * forge_item.toolspeed, target = src)) + balloon_alert_to_viewers("stopped heating [search_incomplete]") + forge_item.in_use = FALSE + return ITEM_INTERACT_SUCCESS + + COOLDOWN_START(search_incomplete, heating_remainder, FORGE_HEATING_DURATION) + in_use = FALSE + forge_item.in_use = FALSE + user.mind.adjust_experience(/datum/skill/smithing, 5) // Heating up forge items grants some experience + balloon_alert(user, "successfully heated [search_incomplete]") + return ITEM_INTERACT_SUCCESS + + // Here we check the item used on us (tongs) for a stack of some kind to create an object from + var/obj/item/stack/search_stack = locate(/obj/item/stack) in forge_item.contents + if(search_stack) + var/user_choice = show_radial_menu(user, src, radial_choice_list, radius = 38, require_near = TRUE, tooltips = TRUE) + if(!user_choice) + fail_message(user, "nothing chosen") + forge_item.in_use = FALSE + return ITEM_INTERACT_SUCCESS + + // Sets up a list of the materials to give to the item later + var/list/material_list = list() + + if(search_stack.material_type) + material_list[GET_MATERIAL_REF(search_stack.material_type)] = SHEET_MATERIAL_AMOUNT + + else + for(var/material as anything in search_stack.custom_materials) + material_list[material] = SHEET_MATERIAL_AMOUNT + + if(!search_stack.use(1)) + fail_message(user, "not enough of [search_stack]") + forge_item.in_use = FALSE + return ITEM_INTERACT_SUCCESS + + balloon_alert_to_viewers("heating [search_stack]") + + if(!do_after(user, skill_modifier * forge_item.toolspeed, target = src)) + balloon_alert_to_viewers("stopped heating [search_stack]") + forge_item.in_use = FALSE + return ITEM_INTERACT_SUCCESS + + var/spawn_item = choice_list[user_choice] + var/obj/item/forging/incomplete/incomplete_item = new spawn_item(get_turf(src)) + + if(material_list) + incomplete_item.set_custom_materials(material_list) + + COOLDOWN_START(incomplete_item, heating_remainder, FORGE_HEATING_DURATION) + in_use = FALSE + forge_item.in_use = FALSE + balloon_alert(user, "prepared [search_incomplete] into [user_choice]") + search_stack = locate(/obj/item/stack) in forge_item.contents + + if(!search_stack) + forge_item.icon_state = "tong_empty" + return ITEM_INTERACT_SUCCESS + + in_use = FALSE + forge_item.in_use = FALSE + return ITEM_INTERACT_SUCCESS + +/obj/structure/reagent_forge/blowrod_act(mob/living/user, obj/item/tool) + var/obj/item/glassblowing/blowing_rod/blowing_item = tool + var/glassblowing_speed = user.mind.get_skill_modifier(/datum/skill/production, SKILL_SPEED_MODIFIER) * BASELINE_ACTION_TIME + var/glassblowing_amount = BASELINE_HEATING_DURATION / user.mind.get_skill_modifier(/datum/skill/production, SKILL_SPEED_MODIFIER) + + if(in_use) + to_chat(user, span_warning("You cannot do multiple things at the same time!")) + return ITEM_INTERACT_SUCCESS + in_use = TRUE + + if(forge_temperature < MIN_FORGE_TEMP) + fail_message(user, "The temperature is not hot enough to start heating [blowing_item].") + return ITEM_INTERACT_SUCCESS + + var/obj/item/glassblowing/molten_glass/find_glass = locate() in blowing_item.contents + if(!find_glass) + fail_message(user, "[blowing_item] does not have any glass to heat up.") + return ITEM_INTERACT_SUCCESS + + if(!COOLDOWN_FINISHED(find_glass, remaining_heat)) + fail_message(user, "[find_glass] is still has remaining heat.") + return ITEM_INTERACT_SUCCESS + + to_chat(user, span_notice("You begin heating up [blowing_item].")) + + if(!do_after(user, glassblowing_speed, target = src)) + fail_message(user, "[blowing_item] is interrupted in its heating process.") + return ITEM_INTERACT_SUCCESS + + COOLDOWN_START(find_glass, remaining_heat, glassblowing_amount) + find_glass.total_time = glassblowing_amount + to_chat(user, span_notice("You finish heating up [blowing_item].")) + user.mind.adjust_experience(/datum/skill/smithing, 5) + user.mind.adjust_experience(/datum/skill/production, 10) + in_use = FALSE + return ITEM_INTERACT_SUCCESS + +/obj/structure/reagent_forge/wrench_act(mob/living/user, obj/item/tool) + user.balloon_alert_to_viewers("disassembling...") + if(!tool.use_tool(src, user, 2 SECONDS, volume = 100)) + return + deconstruct(TRUE) + return TRUE + +/obj/structure/reagent_forge/atom_deconstruct(disassembled) + new /obj/item/stack/sheet/iron/ten(get_turf(src)) + return ..() + +/obj/structure/reagent_forge/tier2 + forge_level = FORGE_LEVEL_NOVICE + +/obj/structure/reagent_forge/tier3 + forge_level = FORGE_LEVEL_APPRENTICE + +/obj/structure/reagent_forge/tier4 + forge_level = FORGE_LEVEL_JOURNEYMAN + +/obj/structure/reagent_forge/tier5 + forge_level = FORGE_LEVEL_EXPERT + +/obj/structure/reagent_forge/tier6 + forge_level = FORGE_LEVEL_MASTER + +/obj/structure/reagent_forge/tier7 + forge_level = FORGE_LEVEL_LEGENDARY + +/obj/structure/reagent_forge/tier7/imbuing/Initialize(mapload) + . = ..() + create_reagent_forge() + +/particles/smoke/mild + spawning = 1 + velocity = list(0, 0.3, 0) + friction = 0.25 + +#undef BASELINE_ACTION_TIME + +#undef BASELINE_HEATING_DURATION + +#undef FORGE_DEFAULT_TEMPERATURE_CHANGE +#undef MAX_FORGE_TEMP +#undef MIN_FORGE_TEMP +#undef FORGE_HEATING_DURATION + +#undef FORGE_LEVEL_YOU_PLAY_LIKE_A_NOOB +#undef FORGE_LEVEL_NOVICE +#undef FORGE_LEVEL_APPRENTICE +#undef FORGE_LEVEL_JOURNEYMAN +#undef FORGE_LEVEL_EXPERT +#undef FORGE_LEVEL_MASTER +#undef FORGE_LEVEL_LEGENDARY + +#undef MAX_TEMPERATURE_LOSS_DECREASE + +#undef CHARCOAL_CHANCE + +#undef MINIMUM_IMBUING_REAGENT_AMOUNT + +#undef SMOKE_STATE_NONE +#undef SMOKE_STATE_GOOD +#undef SMOKE_STATE_NEUTRAL +#undef SMOKE_STATE_BAD +#undef SMOKE_STATE_NOT_COOKING diff --git a/modular_doppler/reagent_forging/code/forge_clothing.dm b/modular_doppler/reagent_forging/code/forge_clothing.dm new file mode 100644 index 0000000000000..ffdf7f5341097 --- /dev/null +++ b/modular_doppler/reagent_forging/code/forge_clothing.dm @@ -0,0 +1,152 @@ +// Vests +/obj/item/clothing/suit/armor/forging_plate_armor + name = "reagent plate vest" + desc = "An armor vest made of hammered, interlocking plates." + icon = 'modular_doppler/reagent_forging/icons/obj/forge_clothing.dmi' + worn_icon = 'modular_doppler/reagent_forging/icons/mob/clothing/forge_clothing.dmi' + // worn_icon_better_vox = 'modular_doppler/reagent_forging/icons/mob/clothing/forge_clothing_newvox.dmi' + // worn_icon_vox = 'modular_doppler/reagent_forging/icons/mob/clothing/forge_clothing_oldvox.dmi' + // worn_icon_teshari = 'modular_doppler/reagent_forging/icons/mob/clothing/forge_clothing_teshari.dmi' + icon_state = "plate_vest" + supports_variations_flags = CLOTHING_DIGITIGRADE_VARIATION_NO_NEW_ICON + resistance_flags = FIRE_PROOF + obj_flags_doppler = ANVIL_REPAIR + armor_type = /datum/armor/armor_forging_plate_armor + material_flags = MATERIAL_EFFECTS | MATERIAL_ADD_PREFIX | MATERIAL_GREYSCALE | MATERIAL_COLOR + +/datum/armor/armor_forging_plate_armor + melee = 40 + bullet = 40 + fire = 50 + wound = 30 + +/obj/item/clothing/suit/armor/forging_plate_armor/Initialize(mapload) + . = ..() + AddComponent(/datum/component/armor_plate, 4) + AddComponent(/datum/component/reagent_clothing, ITEM_SLOT_OCLOTHING) + + allowed += /obj/item/forging/reagent_weapon + +// Gloves +/obj/item/clothing/gloves/forging_plate_gloves + name = "reagent plate gloves" + desc = "A set of leather gloves with protective armor plates connected to the wrists." + icon = 'modular_doppler/reagent_forging/icons/obj/forge_clothing.dmi' + worn_icon = 'modular_doppler/reagent_forging/icons/mob/clothing/forge_clothing.dmi' + // worn_icon_better_vox = 'modular_doppler/reagent_forging/icons/mob/clothing/forge_clothing_newvox.dmi' + // worn_icon_vox = 'modular_doppler/reagent_forging/icons/mob/clothing/forge_clothing_oldvox.dmi' + // worn_icon_teshari = 'modular_doppler/reagent_forging/icons/mob/clothing/forge_clothing_teshari.dmi' + icon_state = "plate_gloves" + resistance_flags = FIRE_PROOF + obj_flags_doppler = ANVIL_REPAIR + armor_type = /datum/armor/gloves_forging_plate_gloves + material_flags = MATERIAL_EFFECTS | MATERIAL_ADD_PREFIX | MATERIAL_GREYSCALE | MATERIAL_COLOR + body_parts_covered = HANDS|ARMS + +/datum/armor/gloves_forging_plate_gloves + melee = 40 + bullet = 40 + fire = 50 + wound = 30 + +/obj/item/clothing/gloves/forging_plate_gloves/Initialize(mapload) + . = ..() + AddComponent(/datum/component/armor_plate, 4) + AddComponent(/datum/component/reagent_clothing, ITEM_SLOT_GLOVES) + +// Helmets +/obj/item/clothing/head/helmet/forging_plate_helmet + name = "reagent plate helmet" + desc = "A helmet out of hammered plates with a leather neck guard and chin strap." + icon = 'modular_doppler/reagent_forging/icons/obj/forge_clothing.dmi' + worn_icon = 'modular_doppler/reagent_forging/icons/mob/clothing/forge_clothing.dmi' + // worn_icon_better_vox = 'modular_doppler/reagent_forging/icons/mob/clothing/forge_clothing_newvox.dmi' + // worn_icon_vox = 'modular_doppler/reagent_forging/icons/mob/clothing/forge_clothing_oldvox.dmi' + // worn_icon_teshari = 'modular_doppler/reagent_forging/icons/mob/clothing/forge_clothing_teshari.dmi' + icon_state = "plate_helmet" + // supports_variations_flags = CLOTHING_SNOUTED_VARIATION_NO_NEW_ICON + resistance_flags = FIRE_PROOF + flags_inv = null + obj_flags_doppler = ANVIL_REPAIR + armor_type = /datum/armor/helmet_forging_plate_helmet + material_flags = MATERIAL_EFFECTS | MATERIAL_ADD_PREFIX | MATERIAL_GREYSCALE | MATERIAL_COLOR + +/datum/armor/helmet_forging_plate_helmet + melee = 40 + bullet = 40 + fire = 50 + wound = 30 + +/obj/item/clothing/head/helmet/forging_plate_helmet/Initialize(mapload) + . = ..() + AddComponent(/datum/component/armor_plate, 4) + AddComponent(/datum/component/reagent_clothing, ITEM_SLOT_HEAD) + +// Boots +/obj/item/clothing/shoes/forging_plate_boots + name = "reagent plate boots" + desc = "A pair of leather boots with protective armor plates over the shins and toes." + icon = 'modular_doppler/reagent_forging/icons/obj/forge_clothing.dmi' + worn_icon = 'modular_doppler/reagent_forging/icons/mob/clothing/forge_clothing.dmi' + // worn_icon_digi = 'modular_doppler/reagent_forging/icons/mob/clothing/forge_clothing_digi.dmi' + // worn_icon_better_vox = 'modular_doppler/reagent_forging/icons/mob/clothing/forge_clothing_newvox.dmi' + // worn_icon_vox = 'modular_doppler/reagent_forging/icons/mob/clothing/forge_clothing_oldvox.dmi' + // worn_icon_teshari = 'modular_doppler/reagent_forging/icons/mob/clothing/forge_clothing_teshari.dmi' + icon_state = "plate_boots" + supports_variations_flags = CLOTHING_DIGITIGRADE_VARIATION + armor_type = /datum/armor/shoes_forging_plate_boots + material_flags = MATERIAL_EFFECTS | MATERIAL_ADD_PREFIX | MATERIAL_GREYSCALE | MATERIAL_COLOR + resistance_flags = FIRE_PROOF + obj_flags_doppler = ANVIL_REPAIR + can_be_tied = FALSE + body_parts_covered = FEET|LEGS + +/datum/armor/shoes_forging_plate_boots + melee = 20 + bullet = 20 + +/obj/item/clothing/shoes/forging_plate_boots/Initialize(mapload) + . = ..() + AddComponent(/datum/component/armor_plate, 2) + AddComponent(/datum/component/reagent_clothing, ITEM_SLOT_FEET) + +// Misc +/obj/item/clothing/gloves/ring/reagent_clothing + name = "reagent ring" + desc = "A tiny ring, sized to wrap around a finger." + icon_state = "ringsilver" + worn_icon_state = "sring" + inhand_icon_state = "ringsilver" + material_flags = MATERIAL_EFFECTS | MATERIAL_ADD_PREFIX | MATERIAL_COLOR + obj_flags_doppler = ANVIL_REPAIR + +/obj/item/clothing/gloves/ring/reagent_clothing/Initialize(mapload) + . = ..() + AddComponent(/datum/component/reagent_clothing, ITEM_SLOT_GLOVES) + +// /obj/item/clothing/neck/collar/reagent_clothing +// name = "reagent collar" +// desc = "A collar that is ready to be worn for certain individuals." +// icon = 'modular_doppler/modular_items/lewd_items/icons/obj/lewd_clothing/lewd_neck.dmi' +// worn_icon = 'modular_doppler/modular_items/lewd_items/icons/mob/lewd_clothing/lewd_neck.dmi' +// icon_state = "collar_cyan" +// inhand_icon_state = null +// body_parts_covered = NECK +// slot_flags = ITEM_SLOT_NECK +// w_class = WEIGHT_CLASS_SMALL +// material_flags = MATERIAL_EFFECTS | MATERIAL_ADD_PREFIX | MATERIAL_GREYSCALE | MATERIAL_COLOR +// obj_flags_doppler = ANVIL_REPAIR + +// /obj/item/clothing/neck/collar/reagent_clothing/Initialize(mapload) +// . = ..() +// AddComponent(/datum/component/reagent_clothing, ITEM_SLOT_NECK) + +/obj/item/restraints/handcuffs/reagent_clothing + name = "reagent handcuffs" + desc = "A pair of handcuffs that are ready to keep someone captive." + material_flags = MATERIAL_EFFECTS | MATERIAL_ADD_PREFIX | MATERIAL_GREYSCALE | MATERIAL_COLOR + obj_flags_doppler = ANVIL_REPAIR + +/obj/item/restraints/handcuffs/reagent_clothing/Initialize(mapload) + . = ..() + AddComponent(/datum/component/reagent_clothing, ITEM_SLOT_HANDCUFFED) diff --git a/modular_doppler/reagent_forging/code/forge_items.dm b/modular_doppler/reagent_forging/code/forge_items.dm new file mode 100644 index 0000000000000..3d19ad9caad6c --- /dev/null +++ b/modular_doppler/reagent_forging/code/forge_items.dm @@ -0,0 +1,326 @@ +GLOBAL_LIST_INIT(allowed_forging_materials, list( + /datum/material/iron, + /datum/material/silver, + /datum/material/gold, + /datum/material/uranium, + /datum/material/bananium, + /datum/material/titanium, + /datum/material/runite, + /datum/material/adamantine, + /datum/material/mythril, + /datum/material/metalhydrogen, + /datum/material/runedmetal, + /datum/material/bronze, + /datum/material/hauntium, + /datum/material/alloy/plasteel, + /datum/material/alloy/plastitanium, + /datum/material/alloy/alien, + /datum/material/cobolterium, + /datum/material/copporcitite, + /datum/material/tinumium, + /datum/material/brussite, +)) + +/obj/item/forging + icon = 'modular_doppler/reagent_forging/icons/obj/forge_items.dmi' + lefthand_file = 'modular_doppler/reagent_forging/icons/mob/forge_weapon_l.dmi' + righthand_file = 'modular_doppler/reagent_forging/icons/mob/forge_weapon_r.dmi' + toolspeed = 1 + ///whether the item is in use or not + var/in_use = FALSE + +/obj/item/forging/tongs + name = "forging tongs" + desc = "A set of tongs specifically crafted for use in forging. A wise man once said 'I lift things up and put them down.'" + icon = 'modular_doppler/reagent_forging/icons/obj/forge_items.dmi' + icon_state = "tong_empty" + tool_behaviour = TOOL_TONG + +/obj/item/forging/tongs/primitive + name = "primitive forging tongs" + toolspeed = 2 + +/obj/item/forging/tongs/attack_self(mob/user, modifiers) + . = ..() + var/obj/search_obj = locate(/obj) in contents + if(search_obj) + search_obj.forceMove(get_turf(src)) + icon_state = "tong_empty" + return + +/obj/item/forging/hammer + name = "forging mallet" + desc = "A mallet specifically crafted for use in forging. Used to slowly shape metal; careful, you could break something with it!" + icon_state = "hammer" + inhand_icon_state = "hammer" + worn_icon_state = "hammer_back" + tool_behaviour = TOOL_HAMMER + ///the list of things that, if attacked, will set the attack speed to rapid + var/static/list/fast_attacks = list( + /obj/structure/reagent_anvil, + /obj/structure/reagent_crafting_bench + ) + +/obj/item/forging/hammer/afterattack(atom/target, mob/user, click_parameters) + . = ..() + if(!is_type_in_list(target, fast_attacks)) + return + user.changeNext_move(CLICK_CD_RAPID) + +/obj/item/forging/hammer/primitive + name = "primitive forging hammer" + +/obj/item/forging/billow + name = "forging billow" + desc = "A billow specifically crafted for use in forging. Used to stoke the flames and keep the forge lit." + icon_state = "billow" + tool_behaviour = TOOL_BILLOW + +/obj/item/forging/billow/primitive + name = "primitive forging billow" + toolspeed = 2 + +//incomplete pre-complete items +/obj/item/forging/incomplete + name = "parent dev item" + desc = "An incomplete forge item, continue to work hard to be rewarded for your efforts." + //the time remaining that you can hammer before too cool + COOLDOWN_DECLARE(heating_remainder) + //the time between each strike + COOLDOWN_DECLARE(striking_cooldown) + ///the amount of times it takes for the item to become ready + var/average_hits = 30 + ///the amount of times the item has been hit currently + var/times_hit = 0 + ///the required time before each strike to prevent spamming + var/average_wait = 1 SECONDS + ///the path of the item that will be spawned upon completion + var/spawn_item + //because who doesn't want to have a plasma sword? + material_flags = MATERIAL_EFFECTS | MATERIAL_ADD_PREFIX | MATERIAL_GREYSCALE | MATERIAL_COLOR + +/obj/item/forging/incomplete/tong_act(mob/living/user, obj/item/tool) + . = ..() + if(length(tool.contents) > 0) + user.balloon_alert(user, "tongs are full already!") + return + forceMove(tool) + tool.icon_state = "tong_full" + +/obj/item/forging/incomplete/chain + name = "incomplete chain" + icon_state = "hot_chain" + average_hits = 10 + average_wait = 0.5 SECONDS + spawn_item = /obj/item/forging/complete/chain + +/obj/item/forging/incomplete/plate + name = "incomplete plate" + icon_state = "hot_plate" + average_hits = 10 + average_wait = 0.5 SECONDS + spawn_item = /obj/item/forging/complete/plate + +/obj/item/forging/incomplete/sword + name = "incomplete sword blade" + icon_state = "hot_blade" + spawn_item = /obj/item/forging/complete/sword + +/obj/item/forging/incomplete/katana + name = "incomplete katana blade" + icon_state = "hot_katanablade" + spawn_item = /obj/item/forging/complete/katana + +/obj/item/forging/incomplete/dagger + name = "incomplete dagger blade" + icon_state = "hot_daggerblade" + spawn_item = /obj/item/forging/complete/dagger + +/obj/item/forging/incomplete/staff + name = "incomplete staff head" + icon_state = "hot_staffhead" + spawn_item = /obj/item/forging/complete/staff + +/obj/item/forging/incomplete/spear + name = "incomplete spear head" + icon_state = "hot_spearhead" + spawn_item = /obj/item/forging/complete/spear + +/obj/item/forging/incomplete/axe + name = "incomplete axe head" + icon_state = "hot_axehead" + spawn_item = /obj/item/forging/complete/axe + +/obj/item/forging/incomplete/hammer + name = "incomplete hammer head" + icon_state = "hot_hammerhead" + spawn_item = /obj/item/forging/complete/hammer + +/obj/item/forging/incomplete/pickaxe + name = "incomplete pickaxe head" + icon_state = "hot_pickaxehead" + spawn_item = /obj/item/forging/complete/pickaxe + +/obj/item/forging/incomplete/shovel + name = "incomplete shovel head" + icon_state = "hot_shovelhead" + spawn_item = /obj/item/forging/complete/shovel + +/obj/item/forging/incomplete/arrowhead + name = "incomplete arrowhead" + icon_state = "hot_arrowhead" + average_hits = 12 + average_wait = 0.5 SECONDS + spawn_item = /obj/item/forging/complete/arrowhead + +/obj/item/forging/incomplete/rail_nail + name = "incomplete rail nail" + icon = 'modular_doppler/hearthkin/primitive_structures/icons/railroad.dmi' + icon_state = "hot_nail" + average_hits = 10 + average_wait = 0.5 SECONDS + spawn_item = /obj/item/forging/complete/rail_nail + +/obj/item/forging/incomplete/rail_cart + name = "incomplete rail cart" + icon = 'modular_doppler/hearthkin/primitive_structures/icons/railroad.dmi' + icon_state = "hot_cart" + spawn_item = /obj/vehicle/ridden/rail_cart + +//"complete" pre-complete items +/obj/item/forging/complete + ///the path of the item that will be created + var/spawning_item + //because who doesn't want to have a plasma sword? + material_flags = MATERIAL_EFFECTS | MATERIAL_ADD_PREFIX | MATERIAL_GREYSCALE | MATERIAL_COLOR + +/obj/item/forging/complete/examine(mob/user) + . = ..() + if(spawning_item) + . += span_notice("
In order to finish this item, a workbench will be necessary!") + +/obj/item/forging/complete/chain + name = "chain" + desc = "A singular chain, best used in combination with multiple chains." + icon_state = "chain" + +/obj/item/forging/complete/plate + name = "plate" + desc = "A plate, best used in combination with multiple plates." + icon_state = "plate" + +/obj/item/forging/complete/sword + name = "sword blade" + desc = "A sword blade, ready to get some wood for completion." + icon_state = "blade" + spawning_item = /obj/item/forging/reagent_weapon/sword + +/obj/item/forging/complete/katana + name = "katana blade" + desc = "A katana blade, ready to get some wood for completion." + icon_state = "katanablade" + spawning_item = /obj/item/forging/reagent_weapon/katana + +/obj/item/forging/complete/dagger + name = "dagger blade" + desc = "A dagger blade, ready to get some wood for completion." + icon_state = "daggerblade" + spawning_item = /obj/item/forging/reagent_weapon/dagger + +/obj/item/forging/complete/staff + name = "staff head" + desc = "A staff head, ready to get some wood for completion." + icon_state = "staffhead" + spawning_item = /obj/item/forging/reagent_weapon/staff + +/obj/item/forging/complete/spear + name = "spear head" + desc = "A spear head, ready to get some wood for completion." + icon_state = "spearhead" + spawning_item = /obj/item/forging/reagent_weapon/spear + +/obj/item/forging/complete/axe + name = "axe head" + desc = "An axe head, ready to get some wood for completion." + icon_state = "axehead" + spawning_item = /obj/item/forging/reagent_weapon/axe + +/obj/item/forging/complete/hammer + name = "hammer head" + desc = "A hammer head, ready to get some wood for completion." + icon_state = "hammerhead" + spawning_item = /obj/item/forging/reagent_weapon/hammer + +/obj/item/forging/complete/pickaxe + name = "pickaxe head" + desc = "A pickaxe head, ready to get some wood for completion." + icon_state = "pickaxehead" + spawning_item = /obj/item/pickaxe/reagent_weapon + +/obj/item/forging/complete/shovel + name = "shovel head" + desc = "A shovel head, ready to get some wood for completion." + icon_state = "shovelhead" + spawning_item = /obj/item/shovel/reagent_weapon + +/obj/item/forging/complete/arrowhead + name = "arrowhead" + desc = "An arrowhead, ready to get some wood for completion." + icon_state = "arrowhead" + spawning_item = /obj/item/arrow_spawner + +/obj/item/forging/complete/rail_nail + name = "rail nail" + desc = "A nail, ready to be used with some wood in order to make tracks." + icon = 'modular_doppler/hearthkin/primitive_structures/icons/railroad.dmi' + icon_state = "nail" + spawning_item = /obj/item/stack/rail_track/ten + +/obj/item/forging/incomplete_bow + name = "incomplete longbow" + desc = "A wooden bow that has yet to be strung." + icon_state = "nostring_bow" + +/obj/item/forging/incomplete_bow/attackby(obj/item/attacking_item, mob/user, params) + if(istype(attacking_item, /obj/item/weaponcrafting/silkstring)) + new /obj/item/gun/ballistic/bow/longbow(get_turf(src)) + qdel(attacking_item) + qdel(src) + return + return ..() + +/obj/item/arrow_spawner + name = "arrow spawner" + desc = "You shouldn't see this." + /// the amount of arrows that are spawned from the spawner + var/spawning_amount = 4 + +/obj/item/arrow_spawner/Initialize(mapload) + . = ..() + var/turf/src_turf = get_turf(src) + for(var/i in 1 to spawning_amount) + new /obj/item/ammo_casing/arrow/(src_turf) + qdel(src) + +/obj/item/stack/tong_act(mob/living/user, obj/item/tool) + . = ..() + if(!(material_type in GLOB.allowed_forging_materials)) + user.balloon_alert(user, "can only forge metal!") + return + if(length(tool.contents) > 0) + user.balloon_alert(user, "tongs are full already!") + return FALSE + if(!material_type && !custom_materials) + user.balloon_alert(user, "invalid material!") + return + forceMove(tool) + tool.icon_state = "tong_full" + +/obj/tong_act(mob/living/user, obj/item/tool) + . = ..() + if(length(tool.contents)) + user.balloon_alert(user, "tongs are full already!") + return FALSE + if(obj_flags_doppler & ANVIL_REPAIR) + forceMove(tool) + tool.icon_state = "tong_full" diff --git a/modular_doppler/reagent_forging/code/forge_recipes.dm b/modular_doppler/reagent_forging/code/forge_recipes.dm new file mode 100644 index 0000000000000..1db5e5f6233f4 --- /dev/null +++ b/modular_doppler/reagent_forging/code/forge_recipes.dm @@ -0,0 +1,30 @@ +/datum/crafting_recipe/primitive_billow + name = "Primitive Forging Billow" + result = /obj/item/forging/billow/primitive + reqs = list(/obj/item/stack/sheet/mineral/wood = 5) + category = CAT_TOOLS + +/datum/crafting_recipe/primitive_tong + name = "Primitive Forging Tong" + result = /obj/item/forging/tongs/primitive + reqs = list(/obj/item/stack/sheet/iron = 5) + category = CAT_TOOLS + +/datum/crafting_recipe/primitive_hammer + name = "Primitive Forging Hammer" + result = /obj/item/forging/hammer/primitive + reqs = list(/obj/item/stack/sheet/iron = 5) + category = CAT_TOOLS + +//cargo supply pack for items +/datum/supply_pack/service/forging_items + name = "Forging Starter Item Pack" + desc = "Featuring: Forging. This pack is full of three items necessary to start your forging career: tongs, hammer, and billow." + cost = CARGO_CRATE_VALUE * 4 + contains = list(/obj/item/forging/tongs, /obj/item/forging/hammer, /obj/item/forging/billow) + crate_name = "forging start items" + crate_type = /obj/structure/closet/crate/forging_items + +/obj/structure/closet/crate/forging_items + name = "forging starter items" + desc = "A crate filled with the items necessary to start forging (billow, hammer, and tongs)." diff --git a/modular_doppler/reagent_forging/code/forge_weapons.dm b/modular_doppler/reagent_forging/code/forge_weapons.dm new file mode 100644 index 0000000000000..7eb24174bc0cf --- /dev/null +++ b/modular_doppler/reagent_forging/code/forge_weapons.dm @@ -0,0 +1,343 @@ +/obj/item/forging/reagent_weapon + icon = 'modular_doppler/reagent_forging/icons/obj/forge_items.dmi' + lefthand_file = 'modular_doppler/reagent_forging/icons/mob/forge_weapon_l.dmi' + righthand_file = 'modular_doppler/reagent_forging/icons/mob/forge_weapon_r.dmi' + worn_icon = 'modular_doppler/reagent_forging/icons/mob/forge_weapon_worn.dmi' + material_flags = MATERIAL_EFFECTS | MATERIAL_ADD_PREFIX | MATERIAL_GREYSCALE | MATERIAL_COLOR + obj_flags = UNIQUE_RENAME + obj_flags_doppler = ANVIL_REPAIR + toolspeed = 0.9 //Slightly better than avg. - A forged hammer or knife is probably better than a standard one + +/obj/item/forging/reagent_weapon/Initialize(mapload) + . = ..() + AddComponent(/datum/component/reagent_weapon) + +/obj/item/forging/reagent_weapon/examine(mob/user) + . = ..() + . += span_notice("Using a hammer on [src] will repair its damage!") + +//vanilla sword with no quirks, at least it's good versus other melees :) +/obj/item/forging/reagent_weapon/sword + name = "forged sword" + desc = "A sharp, one-handed sword most adept at blocking opposing melee strikes." + force = 20 + armour_penetration = 10 + icon_state = "sword" + inhand_icon_state = "sword" + worn_icon_state = "sword_back" + belt_icon_state = "sword_belt" + hitsound = 'sound/weapons/bladeslice.ogg' + throwforce = 10 + block_chance = 25 + slot_flags = ITEM_SLOT_BELT | ITEM_SLOT_BACK + w_class = WEIGHT_CLASS_BULKY + resistance_flags = FIRE_PROOF + attack_verb_continuous = list("attacks", "slashes", "stabs", "slices", "tears", "lacerates", "rips", "dices", "cuts") + attack_verb_simple = list("attack", "slash", "stab", "slice", "tear", "lacerate", "rip", "dice", "cut") + sharpness = SHARP_EDGED + max_integrity = 150 + +//katana, one which shall cut through your puny armour +/obj/item/forging/reagent_weapon/katana + name = "forged katana" + desc = "A katana sharp enough to penetrate body armor, but not quite million-times-folded sharp." + force = 20 + armour_penetration = 25 + icon_state = "katana" + inhand_icon_state = "katana" + worn_icon_state = "katana_back" + belt_icon_state = "katana_belt" + hitsound = 'sound/weapons/bladeslice.ogg' + throwforce = 10 + block_chance = 20 + slot_flags = ITEM_SLOT_BELT | ITEM_SLOT_BACK + w_class = WEIGHT_CLASS_BULKY + resistance_flags = FIRE_PROOF + attack_verb_continuous = list("attacks", "slashes", "stabs", "slices", "tears", "lacerates", "rips", "dices", "cuts") + attack_verb_simple = list("attack", "slash", "stab", "slice", "tear", "lacerate", "rip", "dice", "cut") + sharpness = SHARP_EDGED + +//quirky knife that lets you click fast +/obj/item/forging/reagent_weapon/dagger + name = "forged dagger" + desc = "A lightweight dagger with an extremely quick swing!" + force = 13 + icon_state = "dagger" + inhand_icon_state = "dagger" + worn_icon_state = "dagger_back" + belt_icon_state = "dagger_belt" + hitsound = 'sound/weapons/bladeslice.ogg' + throw_speed = 4 + embed_type = /datum/embed_data/forged_dagger + throwforce = 15 + slot_flags = ITEM_SLOT_BELT | ITEM_SLOT_BACK + w_class = WEIGHT_CLASS_SMALL + resistance_flags = FIRE_PROOF + attack_verb_continuous = list("attacks", "slashes", "stabs", "slices", "tears", "lacerates", "rips", "dices", "cuts") + attack_verb_simple = list("attack", "slash", "stab", "slice", "tear", "lacerate", "rip", "dice", "cut") + sharpness = SHARP_EDGED + tool_behaviour = TOOL_KNIFE + +/datum/embed_data/forged_dagger + embed_chance = 50 + fall_chance = 1 + pain_mult = 2 + +//what a cute gimmick +/obj/item/forging/reagent_weapon/dagger/attack(mob/living/M, mob/living/user, params) + . = ..() + user.changeNext_move(CLICK_CD_RANGE) + +//this isnt a weapon... +/obj/item/forging/reagent_weapon/staff + name = "forged staff" + desc = "A staff most notably capable of being imbued with reagents, especially useful alongside its otherwise harmless nature." + force = 0 + icon_state = "staff" + inhand_icon_state = "staff" + worn_icon_state = "staff_back" + throwforce = 0 + slot_flags = ITEM_SLOT_BACK + w_class = WEIGHT_CLASS_NORMAL + resistance_flags = FIRE_PROOF + attack_verb_continuous = list("bonks", "bashes", "whacks", "pokes", "prods") + attack_verb_simple = list("bonk", "bash", "whack", "poke", "prod") + +//omg, two tile range! surely i wont lose a fight now... +/obj/item/forging/reagent_weapon/spear + name = "forged spear" + desc = "A long spear that can be wielded in two hands to boost damage at the cost of single-handed versatility." + force = 13 + armour_penetration = 15 + icon_state = "spear" + inhand_icon_state = "spear" + worn_icon_state = "spear_back" + throwforce = 22 + throw_speed = 4 + embed_data = /datum/embed_data/forged_spear + slot_flags = ITEM_SLOT_BACK + w_class = WEIGHT_CLASS_BULKY + resistance_flags = FIRE_PROOF + hitsound = 'sound/weapons/bladeslice.ogg' + attack_verb_continuous = list("attacks", "pokes", "jabs", "tears", "lacerates", "gores") + attack_verb_simple = list("attack", "poke", "jab", "tear", "lacerate", "gore") + wound_bonus = -15 + bare_wound_bonus = 15 + reach = 2 + sharpness = SHARP_EDGED + +/datum/embed_data/forged_spear + embed_chance = 75 + fall_chance = 0 + pain_mult = 6 + +//this is 1:1 with the bonespear, lets use this as a 'balance anchor'. weapons that blatantly outclass this are powercrept. +/obj/item/forging/reagent_weapon/spear/Initialize(mapload) + . = ..() + AddComponent(/datum/component/two_handed, force_unwielded = 13, force_wielded = 23) + +//throwing weapons, what a fun gimmick. lets make them actually worth using +/obj/item/forging/reagent_weapon/axe + name = "forged axe" + desc = "An axe especially balanced for throwing and embedding into fleshy targets. Nonetheless useful as a traditional melee tool." + force = 13 + armour_penetration = 10 + icon_state = "axe" + inhand_icon_state = "axe" + worn_icon_state = "axe_back" + throwforce = 18 + throw_speed = 4 + embed_type = /datum/embed_data/forged_axe + slot_flags = ITEM_SLOT_BACK + w_class = WEIGHT_CLASS_NORMAL + resistance_flags = FIRE_PROOF + attack_verb_continuous = list("slashes", "bashes") + attack_verb_simple = list("slash", "bash") + sharpness = SHARP_EDGED + +/datum/embed_data/forged_axe + embed_chance = 65 + fall_chance = 10 + pain_mult = 4 + +//Boring option for doing the most raw damage +/obj/item/forging/reagent_weapon/hammer + name = "forged hammer" + desc = "A heavy, weighted hammer that packs an incredible punch but can prove to be unwieldy. Useful for forging!" + force = 24 //Requires wielding + armour_penetration = 10 + icon_state = "crush_hammer" + inhand_icon_state = "crush_hammer" + worn_icon_state = "hammer_back" + throwforce = 10 + slot_flags = ITEM_SLOT_BACK + w_class = WEIGHT_CLASS_BULKY + resistance_flags = FIRE_PROOF + attack_verb_continuous = list("bashes", "whacks") + attack_verb_simple = list("bash", "whack") + tool_behaviour = TOOL_HAMMER + ///the list of things that, if attacked, will set the attack speed to rapid + var/static/list/fast_attacks = list( + /obj/structure/reagent_anvil, + /obj/structure/reagent_crafting_bench + ) + +/obj/item/forging/reagent_weapon/hammer/Initialize(mapload) + . = ..() + AddComponent(/datum/component/two_handed, force_unwielded = 24, force_wielded = 24, require_twohands = TRUE) + AddElement(/datum/element/kneejerk) + +/obj/item/forging/reagent_weapon/hammer/attack_atom(atom/attacked_atom, mob/living/user, params) + . = ..() + if(!is_type_in_list(attacked_atom, fast_attacks)) + return + user.changeNext_move(CLICK_CD_RAPID) + +/obj/item/shield/buckler/reagent_weapon + name = "forged buckler shield" + desc = "A small, round shield best used in tandem with a melee weapon in close-quarters combat." + icon = 'modular_doppler/reagent_forging/icons/obj/forge_items.dmi' + worn_icon = 'modular_doppler/reagent_forging/icons/mob/forge_weapon_worn.dmi' + icon_state = "buckler" + inhand_icon_state = "buckler" + worn_icon_state = "buckler_back" + lefthand_file = 'modular_doppler/reagent_forging/icons/mob/forge_weapon_l.dmi' + righthand_file = 'modular_doppler/reagent_forging/icons/mob/forge_weapon_r.dmi' + custom_materials = list(/datum/material/iron=HALF_SHEET_MATERIAL_AMOUNT) + resistance_flags = FIRE_PROOF + block_chance = 30 + transparent = FALSE + max_integrity = 150 //over double that of a wooden one + w_class = WEIGHT_CLASS_NORMAL + material_flags = MATERIAL_EFFECTS | MATERIAL_ADD_PREFIX | MATERIAL_GREYSCALE | MATERIAL_AFFECT_STATISTICS + obj_flags_doppler = ANVIL_REPAIR + shield_break_sound = 'sound/effects/bang.ogg' + shield_break_leftover = /obj/item/forging/complete/plate + +/obj/item/shield/buckler/reagent_weapon/Initialize(mapload) + . = ..() + AddComponent(/datum/component/reagent_weapon) + +/obj/item/shield/buckler/reagent_weapon/examine(mob/user) + . = ..() + . += span_notice("Using a hammer on [src] will repair its damage!") + +/obj/item/shield/buckler/reagent_weapon/attackby(obj/item/attacking_item, mob/user, params) + if(atom_integrity >= max_integrity) + return ..() + if(istype(attacking_item, /obj/item/forging/hammer)) + var/obj/item/forging/hammer/attacking_hammer = attacking_item + var/skill_modifier = user.mind.get_skill_modifier(/datum/skill/smithing, SKILL_SPEED_MODIFIER) * attacking_hammer.toolspeed + while(atom_integrity < max_integrity) + if(!do_after(user, skill_modifier SECONDS, src)) + return + var/fixing_amount = min(max_integrity - atom_integrity, 5) + atom_integrity += fixing_amount + user.mind.adjust_experience(/datum/skill/smithing, 5) //useful heating means you get some experience + balloon_alert(user, "partially repaired!") + return + return ..() + +/obj/item/shield/buckler/reagent_weapon/pavise //similar to the adamantine shield. Huge, slow, lets you soak damage and packs a wallop. + name = "forged pavise shield" + desc = "An oblong shield used by ancient crossbowmen as cover while reloading. Probably just as useful with an actual gun." + icon_state = "pavise" + inhand_icon_state = "pavise" + worn_icon_state = "pavise_back" + block_chance = 75 + item_flags = SLOWS_WHILE_IN_HAND + w_class = WEIGHT_CLASS_HUGE + slot_flags = ITEM_SLOT_BACK + max_integrity = 300 //tanky + +/obj/item/shield/buckler/reagent_weapon/pavise/Initialize(mapload) + . = ..() + AddComponent(/datum/component/two_handed, require_twohands = TRUE, force_wielded = 15) + +/obj/item/pickaxe/reagent_weapon + name = "forged pickaxe" + +/obj/item/pickaxe/reagent_weapon/Initialize(mapload) + . = ..() + AddComponent(/datum/component/reagent_weapon) + +/obj/item/shovel/reagent_weapon + name = "forged shovel" + +/obj/item/shovel/reagent_weapon/Initialize(mapload) + . = ..() + AddComponent(/datum/component/reagent_weapon) + +/obj/item/ammo_casing/arrow/attackby(obj/item/attacking_item, mob/user, params) + var/spawned_item + if(istype(attacking_item, /obj/item/stack/sheet/sinew)) + spawned_item = /obj/item/ammo_casing/arrow/ash + + if(istype(attacking_item, /obj/item/stack/sheet/bone)) + spawned_item = /obj/item/ammo_casing/arrow/bone + + if(istype(attacking_item, /obj/item/stack/tile/bronze)) + spawned_item = /obj/item/ammo_casing/arrow/bronze + + if(!spawned_item) + return ..() + + var/obj/item/stack/stack_item = attacking_item + if(!stack_item.use(1)) + return + + var/obj/item/ammo_casing/arrow/converted_arrow = new spawned_item(get_turf(src)) + transfer_fingerprints_to(converted_arrow) + remove_item_from_storage(user) + user.put_in_hands(converted_arrow) + qdel(src) + +#define INCREASE_BLOCK_CHANCE 2 + +/obj/item/forging/reagent_weapon/bokken + name = "bokken" + desc = "A bokken that is capable of blocking attacks when wielding in two hands, possibly including bullets should the user be brave enough." + force = 20 + icon_state = "bokken" + inhand_icon_state = "bokken" + worn_icon_state = "bokken_back" + throwforce = 10 + block_chance = 20 + slot_flags = ITEM_SLOT_BACK + w_class = WEIGHT_CLASS_BULKY + resistance_flags = FIRE_PROOF + attack_verb_continuous = list("bonks", "bashes", "whacks", "pokes", "prods") + attack_verb_simple = list("bonk", "bash", "whack", "poke", "prod") + ///whether the bokken is being wielded or not + var/wielded = FALSE + +/obj/item/forging/reagent_weapon/bokken/hit_reaction(mob/living/carbon/human/owner, atom/movable/hitby, attack_text, final_block_chance, damage, attack_type) + if(wielded) + final_block_chance *= INCREASE_BLOCK_CHANCE + if(prob(final_block_chance)) + if(attack_type == PROJECTILE_ATTACK) + owner.visible_message(span_danger("[owner] deflects [attack_text] with [src]!")) + playsound(src, pick('sound/weapons/effects/ric1.ogg', 'sound/weapons/effects/ric2.ogg', 'sound/weapons/effects/ric3.ogg', 'sound/weapons/effects/ric4.ogg', 'sound/weapons/effects/ric5.ogg'), 100, TRUE) + else + playsound(src, 'sound/weapons/parry.ogg', 75, TRUE) + owner.visible_message(span_danger("[owner] parries [attack_text] with [src]!")) + var/owner_turf = get_turf(owner) + new block_effect(owner_turf, COLOR_YELLOW) + return TRUE + return FALSE + +#undef INCREASE_BLOCK_CHANCE + +/obj/item/forging/reagent_weapon/bokken/Initialize(mapload) + . = ..() + RegisterSignal(src, COMSIG_TWOHANDED_WIELD, PROC_REF(on_wield)) + RegisterSignal(src, COMSIG_TWOHANDED_UNWIELD, PROC_REF(on_unwield)) + AddComponent(/datum/component/two_handed, force_unwielded = 20, force_wielded = 10) + +/obj/item/forging/reagent_weapon/bokken/proc/on_wield() + SIGNAL_HANDLER + wielded = TRUE + +/obj/item/forging/reagent_weapon/bokken/proc/on_unwield() + SIGNAL_HANDLER + wielded = FALSE diff --git a/modular_doppler/reagent_forging/code/reagent_component.dm b/modular_doppler/reagent_forging/code/reagent_component.dm new file mode 100644 index 0000000000000..fcffd58d779d4 --- /dev/null +++ b/modular_doppler/reagent_forging/code/reagent_component.dm @@ -0,0 +1,117 @@ +#define MAX_IMBUE_STORAGE 250 +#define REAGENT_CLOTHING_INJECT_AMOUNT 0.5 +#define REAGENT_WEAPON_INJECT_AMOUNT 1 +#define REAGENT_WEAPON_DAMAGE_MULTIPLIER 2 + +//the component that is attached to clothes that allows them to be imbued +//ONLY USE THIS FOR CLOTHING +/datum/component/reagent_clothing + ///the item that the component is attached to + var/obj/item/parent_clothing + ///the slot that the item will check + var/checking_slot + ///the human that is wearing the parent_clothing + var/mob/living/carbon/human/cloth_wearer + ///the container that will apply the chemicals + var/obj/item/reagent_containers/applying_container + ///the list of imbued reagents that will given to the human owner + var/list/imbued_reagent = list() + //the cooldown between each imbue + COOLDOWN_DECLARE(imbue_cooldown) + +/datum/component/reagent_clothing/Initialize(set_slot = null) + if(!istype(parent, /obj/item)) + return COMPONENT_INCOMPATIBLE //they need to be clothing, I already said this + + if(set_slot) + checking_slot = set_slot + + parent_clothing = parent + parent_clothing.create_reagents(MAX_IMBUE_STORAGE, INJECTABLE | REFILLABLE) + applying_container = new /obj/item/reagent_containers(src) + RegisterSignal(parent_clothing, COMSIG_ITEM_EQUIPPED, PROC_REF(set_wearer)) + RegisterSignal(parent_clothing, COMSIG_ITEM_PRE_UNEQUIP, PROC_REF(remove_wearer)) + RegisterSignal(parent_clothing, COMSIG_ATOM_EXAMINE, PROC_REF(on_examine)) + START_PROCESSING(SSdcs, src) + +/datum/component/reagent_clothing/Destroy(force) + parent_clothing = null + cloth_wearer = null + QDEL_NULL(applying_container) + STOP_PROCESSING(SSdcs, src) + return ..() + +/datum/component/reagent_clothing/proc/on_examine(datum/source, mob/user, list/examine_list) + SIGNAL_HANDLER + examine_list += span_notice("[parent_clothing] is able to be inbued with a chemical at a reagent forge!") + +/datum/component/reagent_clothing/proc/set_wearer() + SIGNAL_HANDLER + + if(!ishuman(parent_clothing.loc)) + return + cloth_wearer = parent_clothing.loc + +/datum/component/reagent_clothing/proc/remove_wearer() + SIGNAL_HANDLER + cloth_wearer = null + +/datum/component/reagent_clothing/process(seconds_per_tick) + if(!parent_clothing || !cloth_wearer || !length(imbued_reagent)) + return + + if(parent_clothing != cloth_wearer.get_item_by_slot(checking_slot)) + return + + if(!COOLDOWN_FINISHED(src, imbue_cooldown)) + return + + COOLDOWN_START(src, imbue_cooldown, 3 SECONDS) + + for(var/create_reagent in imbued_reagent) + applying_container.reagents.add_reagent(create_reagent, REAGENT_CLOTHING_INJECT_AMOUNT) + applying_container.reagents.trans_to(target = cloth_wearer, amount = REAGENT_CLOTHING_INJECT_AMOUNT, methods = INJECT) + +//the component that is attached to weapons that allows them to be imbued +//ONLY USE THIS FOR WEAPONS +/datum/component/reagent_weapon + ///the item that the component is attached to + var/obj/item/parent_weapon + ///the list of imbued reagents that will given to the human owner + var/list/imbued_reagent = list() + +/datum/component/reagent_weapon/Initialize(...) + if(!istype(parent, /obj/item)) + return COMPONENT_INCOMPATIBLE //they need to be weapons, I already said this + parent_weapon = parent + parent_weapon.create_reagents(MAX_IMBUE_STORAGE, INJECTABLE | REFILLABLE) + RegisterSignal(parent_weapon, COMSIG_ITEM_ATTACK, PROC_REF(inject_attacked)) + RegisterSignal(parent_weapon, COMSIG_ATOM_EXAMINE, PROC_REF(on_examine)) + +/datum/component/reagent_weapon/Destroy(force) + parent_weapon = null + return ..() + +/datum/component/reagent_weapon/proc/on_examine(datum/source, mob/user, list/examine_list) + SIGNAL_HANDLER + examine_list += span_notice("[parent_weapon] is able to be imbued with a chemical at a reagent forge!") + +/datum/component/reagent_weapon/proc/inject_attacked(datum/source, mob/living/target, mob/living/user, params) + SIGNAL_HANDLER + + //don't have the weapon or any imbued reagents? don't try + if(!parent_weapon || !length(imbued_reagent)) + return + + //lets inject that target + var/mob/living_target = target + for(var/create_reagent in imbued_reagent) + living_target.reagents.add_reagent(create_reagent, REAGENT_WEAPON_INJECT_AMOUNT) + + //now lets take damage corresponding to the amount of chems we have imbued (hit either 100 times or 50 times before it breaks) + parent_weapon.take_damage(length(imbued_reagent) * REAGENT_WEAPON_DAMAGE_MULTIPLIER) + +#undef MAX_IMBUE_STORAGE +#undef REAGENT_CLOTHING_INJECT_AMOUNT +#undef REAGENT_WEAPON_INJECT_AMOUNT +#undef REAGENT_WEAPON_DAMAGE_MULTIPLIER diff --git a/modular_doppler/reagent_forging/code/seedmesh.dm b/modular_doppler/reagent_forging/code/seedmesh.dm new file mode 100644 index 0000000000000..f4a01e0582d4c --- /dev/null +++ b/modular_doppler/reagent_forging/code/seedmesh.dm @@ -0,0 +1,36 @@ +/obj/item/seed_mesh + name = "seed mesh" + desc = "A little mesh that, when paired with sand, has the possibility of filtering out large seeds." + icon = 'modular_doppler/reagent_forging/icons/obj/misc_tools.dmi' + icon_state = "mesh" + var/list/static/seeds_blacklist = list( + /obj/item/seeds/lavaland, + /obj/item/seeds/gatfruit, + /obj/item/seeds/seedling/evil, + ) + +/obj/item/seed_mesh/attackby(obj/item/attacking_item, mob/user, params) + if(istype(attacking_item, /obj/item/stack/ore/glass)) + var/obj/item/stack/ore/ore_item = attacking_item + if(ore_item.points == 0) + user.balloon_alert(user, "[ore_item] is worthless!") + return + + while(ore_item.amount >= 5) + if(!do_after(user, 2 SECONDS, src)) + user.balloon_alert(user, "have to stand still!") + return + + if(!ore_item.use(5)) + user.balloon_alert(user, "unable to use five of [ore_item]!") + return + + if(prob(50)) + user.balloon_alert(user, "[ore_item] reveals nothing!") + continue + + var/spawn_seed = pick(subtypesof(/obj/item/seeds) - seeds_blacklist) + new spawn_seed(get_turf(src)) + user.balloon_alert(user, "[ore_item] revealed something!") + + return ..() diff --git a/modular_doppler/reagent_forging/code/smith_skill.dm b/modular_doppler/reagent_forging/code/smith_skill.dm new file mode 100644 index 0000000000000..248a2275bb915 --- /dev/null +++ b/modular_doppler/reagent_forging/code/smith_skill.dm @@ -0,0 +1,18 @@ +/datum/skill/smithing + name = "Smithing" + title = "Smithy" + desc = "The desperate artist who strives after the flames of the forge." + modifiers = list( + SKILL_SPEED_MODIFIER = list(1, 0.95, 0.9, 0.85, 0.75, 0.6, 0.5), + SKILL_PROBS_MODIFIER = list(10, 15, 20, 25, 30, 35, 40) + ) + skill_item_path = /obj/item/clothing/neck/cloak/skill_reward/smithing + +/obj/item/clothing/neck/cloak/skill_reward/smithing + name = "legendary smithy's cloak" + desc = "Worn by the most skilled smithies, this legendary cloak is only attainable by knowing every inch of the blacksmith's forge. \ + This status symbol represents a being who has forged some of the finest weapons and armors." + icon = 'modular_doppler/reagent_forging/icons/obj/cloaks.dmi' + worn_icon = 'modular_doppler/reagent_forging/icons/mob/neck.dmi' + icon_state = "smithingcloak" + associated_skill_path = /datum/skill/smithing diff --git a/modular_doppler/reagent_forging/code/tool_override.dm b/modular_doppler/reagent_forging/code/tool_override.dm new file mode 100644 index 0000000000000..4448c27d63721 --- /dev/null +++ b/modular_doppler/reagent_forging/code/tool_override.dm @@ -0,0 +1,31 @@ +/// Called on an object when a tool with wrench capabilities is used to left click an object +/atom/proc/billow_act(mob/living/user, obj/item/tool) + return + +/// Called on an object when a tool with wrench capabilities is used to right click an object +/atom/proc/billow_act_secondary(mob/living/user, obj/item/tool) + return + +/// Called on an object when a tool with wrench capabilities is used to left click an object +/atom/proc/tong_act(mob/living/user, obj/item/tool) + return + +/// Called on an object when a tool with wrench capabilities is used to right click an object +/atom/proc/tong_act_secondary(mob/living/user, obj/item/tool) + return + +/// Called on an object when a tool with wrench capabilities is used to left click an object +/atom/proc/hammer_act(mob/living/user, obj/item/tool) + return + +/// Called on an object when a tool with wrench capabilities is used to right click an object +/atom/proc/hammer_act_secondary(mob/living/user, obj/item/tool) + return + +/// Called on an object when a tool with wrench capabilities is used to left click an object +/atom/proc/blowrod_act(mob/living/user, obj/item/tool) + return + +/// Called on an object when a tool with wrench capabilities is used to right click an object +/atom/proc/blowrod_act_secondary(mob/living/user, obj/item/tool) + return diff --git a/modular_doppler/reagent_forging/code/water_basin.dm b/modular_doppler/reagent_forging/code/water_basin.dm new file mode 100644 index 0000000000000..049bc3a9719ce --- /dev/null +++ b/modular_doppler/reagent_forging/code/water_basin.dm @@ -0,0 +1,110 @@ +/obj/structure/reagent_water_basin + name = "water basin" + desc = "A basin full of water, ready to quench the hot metal." + icon = 'modular_doppler/reagent_forging/icons/obj/forge_structures.dmi' + icon_state = "water_basin" + anchored = TRUE + density = TRUE + + /// Tracks if you can fish from this basin + var/datum/component/fishing_spot/fishable + +/obj/structure/reagent_water_basin/Initialize(mapload) + . = ..() + +/obj/structure/reagent_water_basin/Destroy() + QDEL_NULL(fishable) + return ..() + +/obj/structure/reagent_water_basin/examine(mob/user) + . = ..() + if(!fishable) + . += span_notice("[src] can be upgraded through a bluespace crystal or a journeyman smithy!") + + else + . += span_notice("[src] looks to be a bottomless basin of water... You can even see fish swimming around down there!") + +/obj/structure/reagent_water_basin/attack_hand(mob/living/user, list/modifiers) + . = ..() + var/smithing_skill = user.mind.get_skill_level(/datum/skill/smithing) + if(smithing_skill < SKILL_LEVEL_JOURNEYMAN || fishable) + return + + balloon_alert(user, "the water deepens!") + fishable = AddComponent(/datum/component/fishing_spot, /datum/fish_source/water_basin) + +/obj/structure/reagent_water_basin/attackby(obj/item/attacking_item, mob/living/user, params) + if(istype(attacking_item, /obj/item/stack/ore/glass)) + var/obj/item/stack/ore/glass/glass_obj = attacking_item + if(!glass_obj.use(1)) + return + + new /obj/item/stack/clay(get_turf(src)) + user.mind.adjust_experience(/datum/skill/production, 1) + return + + if(istype(attacking_item, /obj/item/stack/ore/bluespace_crystal)) + if(fishable) + return + var/obj/item/stack/ore/bluespace_crystal/bs_crystal = attacking_item + + if(!bs_crystal.use(1)) + return + + balloon_alert(user, "the water deepens!") + fishable = AddComponent(/datum/component/fishing_spot, /datum/fish_source/water_basin) + return + + return ..() + +/obj/structure/reagent_water_basin/wrench_act(mob/living/user, obj/item/tool) + user.balloon_alert_to_viewers("disassembling...") + if(!tool.use_tool(src, user, 2 SECONDS, volume = 100)) + return + + deconstruct(disassembled = TRUE) + return ITEM_INTERACT_SUCCESS + +/obj/structure/reagent_water_basin/atom_deconstruct(disassembled = TRUE) + new /obj/item/stack/sheet/mineral/wood(drop_location(), 5) + +/obj/structure/reagent_water_basin/tong_act(mob/living/user, obj/item/tool) + var/obj/item/forging/incomplete/search_incomplete = locate(/obj/item/forging/incomplete) in tool.contents + if(!search_incomplete) + return ITEM_INTERACT_SUCCESS + + playsound(src, 'modular_doppler/reagent_forging/sound/hot_hiss.ogg', 50, TRUE) + + if(search_incomplete?.times_hit < search_incomplete.average_hits) + to_chat(user, span_warning("You cool down [search_incomplete], but it wasn't ready yet.")) + COOLDOWN_RESET(search_incomplete, heating_remainder) + return ITEM_INTERACT_SUCCESS + + if(search_incomplete?.times_hit >= search_incomplete.average_hits) + to_chat(user, span_notice("You cool down [search_incomplete] and it's ready.")) + user.mind.adjust_experience(/datum/skill/smithing, 10) //using the water basin on a ready item gives decent experience. + + var/obj/spawned_obj = new search_incomplete.spawn_item(get_turf(src)) + if(search_incomplete.custom_materials) + spawned_obj.set_custom_materials(search_incomplete.custom_materials, 1) //lets set its material + + qdel(search_incomplete) + tool.icon_state = "tong_empty" + return ITEM_INTERACT_SUCCESS + +/// Fishing source for fishing out of basins that have been upgraded, contains saltwater fish (lizard fish fall under this too!) +/datum/fish_source/water_basin + catalog_description = "Bottomless Water Basins" + fish_table = list( + /obj/item/fish/clownfish = 15, + /obj/item/fish/pufferfish = 10, + /obj/item/fish/cardinal = 15, + /obj/item/fish/greenchromis = 15, + /obj/item/fish/lanternfish = 5, + /obj/item/fish/dwarf_moonfish = 15, + /obj/item/fish/gunner_jellyfish = 15, + /obj/item/fish/needlefish = 10, + /obj/item/fish/armorfish = 10, + /obj/effect/spawner/random/maintenance = 10, + /obj/effect/spawner/random/trash/garbage = 15, + ) diff --git a/modular_doppler/reagent_forging/icons/hud/forge_radials.dmi b/modular_doppler/reagent_forging/icons/hud/forge_radials.dmi new file mode 100644 index 0000000000000000000000000000000000000000..4beb99bcd449c4f442897154b864a870295639e6 GIT binary patch literal 541 zcmV+&0^DtVo9sqy<0RI4NVpaL{q~XgiOtNq3$!CRS zSy548Pft%pMMXS1KY)OM#guW9b7dD77pSPH+_QsZSy5C+Js&P}bN~PV0d!JMQvg8b z*k%9#0Cjp)Sad{Xb7OL8aCB*JZU6vyoKseCa&`CgQ*iP1KKYmgaQjVw+EkZ@VqoZ zlrIFaA>c7g0v}hfMZhZ(FuwEQ%oXe%te`9pSRkgsW0*jKNq3825O=LEqT_<}YN-~_5uSwY+P`2^E2E4540rqw$@--00000NkvXXu0mjfxCP>k literal 0 HcmV?d00001 diff --git a/modular_doppler/reagent_forging/icons/mob/clothing/forge_clothing.dmi b/modular_doppler/reagent_forging/icons/mob/clothing/forge_clothing.dmi new file mode 100644 index 0000000000000000000000000000000000000000..bab8703cd0d06033864944d6ecf3a0072fcdc0f7 GIT binary patch literal 1392 zcmV-$1&{iPP)V=-0C=2JR&a84_w-Y6@%7{?OD!tS%+FJ>RWQ*r;NmRLOex6#a*U0*I5Sc+ z(=$pSoZ^zil2jm5sUQc)h)>GTFDX{y;!MdbDh6rg;!G<_%uNNc4bjzRq~_$NmJq49 zEVYf}ThyJD@-mfS@7^06I31MO-*neCTMf9nW~?jDy}s zLgxO&XFMLy_~-g~vjG4A0000000000000000000N)up*#JUV*4y}5s5^Y!%G=J4?G zKYw@L=S%gDe_okBefYR}_x>a#?t}Y}ws-E`-PBm#%X7bI!LD7ux|`a9`_EJn`n(0r ze@e^vsdSlbg+$THA6p+eW;Xz9X(kQoE5d)THqBSDZ7Zz&@xBt2&OS2cRm69Z;Hk%f81>%&%UiOesmdX z#?Lwr;De`UQ7pL3R9X>{wV^M$7odUy0LJ*E;4H zs}Gy1PD&bH_O*bqW9*1yZ^gIDSNCsIT^5btSH8bC(Mwu}-whz^@3UL3wgA7gp>yLA z=fnLLD3RCW(`)fjJx|K_hD&~vP*mu&5+Z*Lq4;(lTnqo=`K$2w{`$WfW6RUeo(;D) zP0!Gl)WPhFL86N?HU?YEw`t@>7{ym?n?_#*dUNvf?@Ct>VE?pYTGGCj|M81WtxP32 z5mXpkF@0Hj^Z>pL(dz*K0000000000000000000000000K%}f&iN|h3j=DX$cYGhq ztl@U-rRB*^6Q_JMJ|TmWBt+!t=^1}0N1t-@Mdc|>V~&+)?!2-ZfNyD*okIzVEK66! z<64H&)9H0oe2e9C0~xJ|$V8ET<@@Aaxpk1$02IWhXw&Pd3}UtT`THzg_I^Zsp8-TY zkWX0`m8ncAVw5U=$xxKt1B|6bi%OT~D_k+{wJIZux?sOCL_Dy{$IxQ*4}dn(1V+zy5O`ty^=-NsPpWjfT7?$Dj=f4<%lXz?K;nD z0Ar6Q@wsYSN*~kWML)aGXg?q{=pVJ7QIy>S_(~r8e@ngNr=rVHJ6=`;NV8-c?Ud;l zIX7AHMT$Q}SxcpLe5(V$%uC}H9R{Xd{+#Ff*3dhCDt(+?WDlTawlYLzC7qBJBWcb?cCD@$))>>ax9_iNm+**kvpyi1kVlbLJ) yOR`?n*iw4O?=kNZYs;1b0000000000*5enS>RHgO#nagU0000V=-0C=2JR&a84_w-Y6@%7{?OD!tS%+FJ>RWQ*r;NmRLOex6#a*U0*I5Sc+ z(=$pSoZ^zil2jm5sUQc)h)>GTFDX{y;!MdbDh6rg;!G<_%uNNc4Y`yRT>V_Yh64Zt z)*Py+n$Ir)00HhvL_t(|ob8%1P6IIzMK_3(&;bVs6$mI01viM0LQg>x2@U{KT6)rO z0}4a|2r6;_pyMh_zQsp_@or|9bsGL_OvYyZdhBsCQxrl7A%qY@2qA201#O#!XVhq z+jU(-ztrB}8w7of{DwCA?f`)Iw~ud;$NPuyH%5wbJ{RzxI%OU}8+~^GkXIMym&Igq z6E?lQyA$jf@f&u`=g9w9AEVW`_NMyo0N|RPo*h@_80?sj--oWqrSFQ?^V76sjw8|l zr+#~P-9rxYG={^2Fybn1ZuL963Dk#Qrdvwirh-?0*|W$#EX;iiZEYVSufBbIQu^_F zA%qY@2qA{Q@}S=^)7gD-vHL%Y#lyjTLkPA;FU)ZVw)Ft0N4ir zY-JX|4+ked=5s;~+aqA#A_l~p28}vIfUU#Z$0m1w07&%+@DZ%*9jL?oT2}P|*ptZB z9{{R)6tMBC-UW|ecM5zt45w@R0IKX=lj>1`_AK~i%I@|12@wj1a9AX{s{jB107*qo IM6N<$g8MWoiU0rr literal 0 HcmV?d00001 diff --git a/modular_doppler/reagent_forging/icons/mob/clothing/forge_clothing_newvox.dmi b/modular_doppler/reagent_forging/icons/mob/clothing/forge_clothing_newvox.dmi new file mode 100644 index 0000000000000000000000000000000000000000..5ae74329a15f9d72b5a0bbef12d85f53f85195cd GIT binary patch literal 1227 zcmY*WdsNZ~6#m&e9nH$J$B1TA$@iH@Cz^@VQVGiOGl!$H;-~=$=6edt?4jiY4}~j- zNowG0nmMMd)JpS(Lihm6lIBv(V2BS;Dw%cmkN2GKe&_q{Klk46YUt4*i1{va001B% z!GYLiW_-eib<4f|;2F^}T}}(bB?d+%5aNk(i9{*|08%+%cwBsvVGfMb&A)Lt;_M*q zlYsY*yGh+&k2y)u`+I=+y!>V_cdYxMJ8CayjMc#k+Y46hUEiH^tXJZ?KYVNq-Q(o2 zjyOJsc0~1I);2(-!_gHJZ+JzPRn1OW}}cn-vI141-5v!Z@UHn zYs^9d{lii@npeJ*t^PYYFKoSV`2=H=7qSwG`~}|Zf5|G%yf`=xC>*HZ+HdKFz%AEu zD{R&S-Y$g!J5J@=|GYE0%jd!DnGTbD$N8Aj2#H$#VxYAVw|wf#Vq^}p8>k1oQX3x% z5)yRd>UU=|O+AsBP5;gd(^TnS!qhI>(YB^@?C(0XvnpokcCFu6F--)rdbjhWF`rx$ zWKrM|STE;l_(Ofx%0=fHENyo!M)v2+*t|V}XD`}o15Nebz~*Tj@IGWFDWIRGD^c3G z+N!sb@pUx_>e7;?%K;4*NXvbx_3{c@DS7B?!7QCp^DyZwokf@f?#*&|eirw;B2}Er zOH|(N?1_oCv_)eXR4^03Oey`?p!J30-}^nC1R0n{N#p_O0oC(aeOf9#6s4u>M-Ma1z&;sV5iLYD}ZRf=>Qtpp``FbQAW^$%U zBMK|4Q)`BeE_*}ds+rMrUF#v|dh>c>qy(ORa8fQi*gqKDaSA6%gc+|;7DZb#_ z$A~bMTP8%ZH>lBFp7z|1>_MN*SNe2i0S`Y`>kO`cEK@Kz`BUw;@J}jIGJ5TX>;WIYP6}E>2dgPJN)pJlcmNH7&;LCqj^rDhLd#I7c%W}1T(@i-Ybdj9 jA#LvF zg2M`mO22;zF8KKMiI%sn*10q1gExd4Tr__0Nawtd=1GR4p57f6#zDrHjlC4+JeqW5 zQiwwEN(J^49sZ}z>uZKRdgOCbM~f}<=_4O)uQR@^8+k8YODp!wfrujygYE(Qh`Jx>?Mkcv5P@7m^x7>XSD=y}BRMFX>n zD2Ijst9i!+Cx1s_PCka9sH#f^%v>&v8Y@pQHuSC5*>k{K?%2E=a`x3t|MsVC-P}2U z|FL_rC%>660zHWW8dhg%f9L1tzn@c9p646yx8IMQ-T&Xu{ip5Xvr1~demHpV*}K2h zlY2#XKNGw??c?X;{+ECA=WkEC?saL;wBPMQPmY~^{akWm>lL3D&*e;NH8Z->YZ9fS zl8>&d>^#zO_4l$R!a2|XEezYkGI_zJ7oY5M{_JFna=Lu=M$pGkadD>n^FF%XxFDom zcGmj_n~-(cT9K#Mby2}Ulx6Sgr-#yE6h3lVi{rLIM4{Pt^IGtsCuln0{pmTC{*T-G{wc+a|?P{(G ziQj&9FQ3e}RdJ`@{MT15+bJEARAs3AHc}=}~Z=zi3gjMyKKSFjtSvJ>{ z^@hILMn%8%m9>JGzXTP>RGfX?ePe!??e5)&H&tD8T=g&cy6tiYhX1oyJv{X9o!CA9 z``5(k_4MO@e(VbVB6A>3rRJ5Wo$MDQt2)29sOQIx{R-JPNM2+YxYzG+UBrH>`0CO+ zo5v~N=X`iRZGxi4x7-_#XJ_c_dn&tMMStz5%i4S>(Tc)}kT(-uB{0u_Lz^vE_UFJY zzA>*Nro|oK+S8Yxd{g&U$$GoHs&_u0knpY7lUL0YdoL^@C!K8ks4~h;XJ6cF$$0Bo zc@xt=D_gf#%SjaqzF&0iE#E8C=wsrg4Ayr%63ff$@{{$Vr@o%3Ixp$B@T=c)A6xG- z#aS=B=B_W~y}do&>Xm3I!`sZn#I4V(?>Cy&zWrPE{CkJ|CBY5pkG0>j#D3?RXDzw< zdfD1wB^G_=?ApyMI_8@F%H!ua=fSvkDvxntlQ*BbBqXU2y{pMJpw zPc4sz+A|+M^v%MelJ{e>%{g_SiGs_^+1XKo7sy#7Rm~D=VQF`_=Z>_-lGT&5u4$an zEH1*<`Zq~i3j#+TC gxKRt{mK{-bOede5V_uyz!3QMf>FVdQ&MBb@0DUY|X8-^I literal 0 HcmV?d00001 diff --git a/modular_doppler/reagent_forging/icons/mob/clothing/forge_clothing_teshari.dmi b/modular_doppler/reagent_forging/icons/mob/clothing/forge_clothing_teshari.dmi new file mode 100644 index 0000000000000000000000000000000000000000..3c7d86b79fddc743903dc46f53d8f4b125f36750 GIT binary patch literal 1332 zcmZWndo@^(e{%1on?|$H#;kns$y}B}%C`)4&Z9`Y5zdHAO&gc6%pT9om`}usY`S~8v(lF8h06^>5QN)QY zPWuXV@Ye2jJJY{KSCRsQFCuVp5hOhEBK~|V03?MkM|*=8%TS>P6EG#F)hdBhtEa&Z-p4z1O@LiS8c9Kil9e?OAa%$paPXz- zs`e$TrE2{*hA+6E$+{bT*VlM}>~r(btc2s*{@Wn#t5YsK@DwtFa%@9;1VuDW~Df-S-up6tBnhI7Hz5!$}00bom^vWGXjzOoV1{FSvU*S%i+c(02fb;Xa8ig?%=IidFuP9+|VB}v$)o^T0IS)ic z&chXz&bs+(C8~Z~u-amiHMF6|3&)1&kGNJ+eOb(_x zrYeEj2$KK75N8&_+v-5$)Eex*LC$5uc{?K1LTYGHx)UB+npgwlCl~rK( z6#8fiB&eBqGwggfgBUueAON2FXV%GCOr!ArNxA}*G0IUdXi9%TSdJ$I65_QuknYjW z(QGW!{mTX%V{;kHFo`z8Tu>gm)3l@57oGUbqlmZ0R;re4Fv2$H^00s7dK~lYM^xvW zyj^3n{8){d{liwUr;_0k56gI0XDYhAcd!bjS!R~~DqSi!G$<1rv&Rc|OQ=8>t?)|8 z)b{E6$_zo9eYQqX~C8;wXLaL-P<W$vve{JG!^`X(p?oSn5`RhK}O-=H?>aae0jms%F& zzwV9&Sf|Yd-spdp@NNQjjtOhf$$_BmPf?X^vtF-6J|`FEqC2yx$7ys$-VRKylq;YO)Z^@*&qgUP-hxsls(8TyXWQ}- zaT(jEIG`__PTyt`JvUgJu(|JdZn3Lu#xL1C?t}fgLF0u(kpW#RZPsyKAxK9i2)U?4 o8!_U$q?YWp?0ECdn^XQ7^wyV;BI+7G`dZDg-+U2`hr-hT0}7XS@&Et; literal 0 HcmV?d00001 diff --git a/modular_doppler/reagent_forging/icons/mob/forge_weapon_l.dmi b/modular_doppler/reagent_forging/icons/mob/forge_weapon_l.dmi new file mode 100644 index 0000000000000000000000000000000000000000..5767aaef5e2624513eee1efe076b202332c0a63f GIT binary patch literal 1934 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 literal 0 HcmV?d00001 diff --git a/modular_doppler/reagent_forging/icons/obj/forge_clothing.dmi b/modular_doppler/reagent_forging/icons/obj/forge_clothing.dmi new file mode 100644 index 0000000000000000000000000000000000000000..e0453211c4b388ddd91654ee73be188490586f19 GIT binary patch literal 994 zcmV<810DQ{P)V=-0C=2JR&a84_w-Y6@%7{?OD!tS%+FJ>RWQ*r;NmRLOex6#a*U0*I5Sc+ z(=$pSoZ^zil2jm5sUQc)h)>GTFDX{y;!MdbDh7%ga&e{=CFZ6=*l23YQj1H7RGN{R zlbcGc;`E$+pwYM#D=WDAxqy8L03WPGv0}1BPyhe}7)eAyRCt{2nlWotK@f#EFY+Hx$^q%*iIk2SqES>8CL3DZPz}X1f!<5BXVB?E(E_yM-gCt zXVw9^8&%s)tM&y*q4?Bc*Y=6bk##^Wyi%)L3d@?%`H8*W#A6)CaU92S9LI4S$8j9T zasGLbj72`9%m4IBkH;A!Fo}wgoZVCf2*gX;ys^%uvjgH%nFzDtzIK0#+-=ke6pwrX z6EmAz>&?YW%dK-c)@Kqa@pE%$!toO)!_4%l!Pjpex4XQzjf3}x4c-lL3k&DMwd*Tk zc6M>FzyD%e#Um$h|G~Ymv^0Oze>$w*x;+>^ds>`}d9_&VkSmEHOiXksR4M`Sn(-M9 zUyidt{F^pYl_PLWDH2SRg!oh%TyuvClcay@gjhUDIUzNUQGx!P6U-$t5U*7tYEYjs zrbe0^;_CJ+2AMHltSX9;|R|k76}JiaDZPlc#z% zK8}% zI!IN5=-s3=E~eK+wP=yl60W4mb3sXzI>K@}o9NB023-X?j^j9v<2a6u9~|c`PI>kf QF#rGn07*qoM6N<$f|TadBme*a literal 0 HcmV?d00001 diff --git a/modular_doppler/reagent_forging/icons/obj/forge_items.dmi b/modular_doppler/reagent_forging/icons/obj/forge_items.dmi new file mode 100644 index 0000000000000000000000000000000000000000..c333e753d6594c63199ad940ab57eb532c0c3174 GIT binary patch literal 6469 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 literal 0 HcmV?d00001 diff --git a/modular_doppler/reagent_forging/readme.md b/modular_doppler/reagent_forging/readme.md new file mode 100644 index 0000000000000..56233e82e9f0a --- /dev/null +++ b/modular_doppler/reagent_forging/readme.md @@ -0,0 +1,30 @@ +## Title: Reagent Forging + +MODULE ID: REAGENT_FORGING + +### Description: + +Reagent forging is a form of forging where users are able to create various items that have the ability to become imbued with reagents. Items that have been imbued have the ability to permanently inject +imbued reagents into the targets. + +### TG Proc Changes: + +| proc | file | +| -------------------------------------------------------------------- | ----------------------------------- | +| /atom/proc/tool_act(mob/living/user, obj/item/tool, list/modifiers) | code\game\atom\atom_tool_acts.dm | + +### Defines: + +- N/A + +### Master file additions + +- N/A + +### Included files that are not contained in this module: + +- N/A + +### Credits: + +Jake Park diff --git a/modular_doppler/reagent_forging/sound/forge.ogg b/modular_doppler/reagent_forging/sound/forge.ogg new file mode 100644 index 0000000000000000000000000000000000000000..8ade5b6485d0c0bb6d3353b3c9c23eee9159bdf2 GIT binary patch literal 16811 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 a@bXLnAS9Eq)O;KR2KISbP5|ig!T$pA%>g(7 literal 0 HcmV?d00001 diff --git a/modular_doppler/reagent_forging/sound/hot_hiss.ogg b/modular_doppler/reagent_forging/sound/hot_hiss.ogg new file mode 100644 index 0000000000000000000000000000000000000000..36f312b210f0c999a34bccc7570362d12fe239b0 GIT binary patch literal 15870 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 zXchisel
or even a pickaxe of some kind, you could cut this into blocks.") + +/obj/item/stack/stone/attackby(obj/item/attacking_item, mob/user, params) + if((attacking_item.tool_behaviour != TOOL_MINING) && !(istype(attacking_item, /obj/item/chisel))) + return ..() + playsound(src, 'sound/effects/picaxe1.ogg', 50, TRUE) + balloon_alert_to_viewers("cutting...") + if(!do_after(user, 5 SECONDS, target = src)) + balloon_alert_to_viewers("stopped cutting") + return FALSE + new /obj/item/stack/sheet/mineral/stone(get_turf(src), amount) + qdel(src) + +/obj/item/stack/tile/mineral/stone + name = "stone tile" + singular_name = "stone floor tile" + desc = "A tile made of stone bricks, for that fortress look." + icon_state = "tile_herringbone" + inhand_icon_state = "tile" + turf_type = /turf/open/floor/stone + mineralType = "stone" + mats_per_unit = list(/datum/material/stone= HALF_SHEET_MATERIAL_AMOUNT) + merge_type = /obj/item/stack/tile/mineral/stone + +/turf/open/floor/stone + desc = "Blocks of stone arranged in a tile-like pattern, odd, really, how it looks like real stone too, because it is!" //A play on the original description for stone tiles + +/turf/closed/wall/mineral/stone + name = "stone wall" + desc = "A wall made of solid stone bricks." + icon = 'modular_doppler/stone/icons/wall.dmi' + icon_state = "wall-0" + base_icon_state = "wall" + sheet_type = /obj/item/stack/sheet/mineral/stone + explosive_resistance = 2 // Rock and stone to the bone, or at least a bit longer than walls made of metal sheets! + smoothing_flags = SMOOTH_BITMASK + smoothing_groups = SMOOTH_GROUP_STONE_WALLS + SMOOTH_GROUP_WALLS + SMOOTH_GROUP_CLOSED_TURFS + canSmoothWith = SMOOTH_GROUP_STONE_WALLS + custom_materials = list( + /datum/material/stone = SHEET_MATERIAL_AMOUNT * 2, + ) + +/turf/closed/wall/mineral/stone/try_decon(obj/item/item_used, mob/user) // Lets you break down stone walls with stone breaking tools + if(item_used.tool_behaviour != TOOL_MINING) + return ..() + + if(!item_used.tool_start_check(user, amount = 0)) + return FALSE + + balloon_alert_to_viewers("breaking down...") + + if(!item_used.use_tool(src, user, 5 SECONDS)) + return FALSE + dismantle_wall() + return TRUE + +/turf/closed/indestructible/stone + name = "stone wall" + desc = "A wall made of unusually solid stone bricks." + icon = 'modular_doppler/stone/icons/wall.dmi' + icon_state = "wall-0" + base_icon_state = "wall" + smoothing_flags = SMOOTH_BITMASK + smoothing_groups = SMOOTH_GROUP_STONE_WALLS + SMOOTH_GROUP_WALLS + SMOOTH_GROUP_CLOSED_TURFS + canSmoothWith = SMOOTH_GROUP_STONE_WALLS + custom_materials = list( + /datum/material/stone = SHEET_MATERIAL_AMOUNT * 2, + ) + +/obj/structure/falsewall/stone + name = "stone wall" + desc = "A wall made of solid stone bricks." + icon = 'modular_doppler/stone/icons/wall.dmi' + icon_state = "wall-open" + base_icon_state = "wall" + fake_icon = 'modular_doppler/stone/icons/wall.dmi' + mineral = /obj/item/stack/sheet/mineral/stone + walltype = /turf/closed/wall/mineral/stone + smoothing_flags = SMOOTH_BITMASK + smoothing_groups = SMOOTH_GROUP_STONE_WALLS + SMOOTH_GROUP_WALLS + SMOOTH_GROUP_CLOSED_TURFS + canSmoothWith = SMOOTH_GROUP_STONE_WALLS + +/turf/closed/mineral/gets_drilled(mob/user, give_exp = FALSE) + if(prob(5)) + new /obj/item/stack/stone(src) + + return ..() + +/obj/item/stack/sheet/mineral/stone/fifty + amount = 50 diff --git a/modular_doppler/stone/icons/ore.dmi b/modular_doppler/stone/icons/ore.dmi new file mode 100644 index 0000000000000000000000000000000000000000..398c03567fb0ced2cf63f16345734dea26a9307c GIT binary patch literal 12142 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 literal 0 HcmV?d00001 diff --git a/modular_doppler/stone/icons/wall.dmi b/modular_doppler/stone/icons/wall.dmi new file mode 100644 index 0000000000000000000000000000000000000000..1384db4a89a006f1ee6ecd1f31be2aa56ab9f718 GIT binary patch literal 4110 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 literal 0 HcmV?d00001 diff --git a/modular_doppler/tribal_extended/icons/back.dmi b/modular_doppler/tribal_extended/icons/back.dmi new file mode 100644 index 0000000000000000000000000000000000000000..43055d5b5992eabaef16a4f58220b4b1044557ed GIT binary patch literal 5675 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 literal 0 HcmV?d00001 diff --git a/modular_doppler/tribal_extended/icons/bows_lefthand.dmi b/modular_doppler/tribal_extended/icons/bows_lefthand.dmi new file mode 100644 index 0000000000000000000000000000000000000000..5ce0b6afdb417a9d5cde9e4d66f85e99440a2c0e GIT binary patch literal 2923 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 bkouFWM``U~Njm7)C=H-2Y|ZP;ypsP7AnItg literal 0 HcmV?d00001 diff --git a/modular_doppler/tribal_extended/icons/bows_righthand.dmi b/modular_doppler/tribal_extended/icons/bows_righthand.dmi new file mode 100644 index 0000000000000000000000000000000000000000..6e8651a1df8c1fad7512cc208c25387eb4ac166a GIT binary patch literal 2993 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 rSADaDk)fsbj@zED00000NkvXXu0mjfk8&BE literal 0 HcmV?d00001 diff --git a/modular_doppler/tribal_extended/icons/projectile.dmi b/modular_doppler/tribal_extended/icons/projectile.dmi new file mode 100644 index 0000000000000000000000000000000000000000..3dfc194ae30223b35d0afbf2f6f1aa155cd16537 GIT binary patch literal 1552 zcmV+r2JiWaP)V=-0C=2JR&a84_w-Y6@%7{?OD!tS%+FJ>RWQ*r;NmRLOex7wuvIWN;^NFm z%}mcIfpCgT5=&AQY!#FWG7D0Z^2?RDI8!ouu5<{rk7}FrpNQFwpS(0WAe}+a~?^wGT7&^idr&2pa9a>>4 zt<eamjD20n%1;GB$G*_=1j3z0syS6u23&#gI|100a{r) zotEkysX6172!8OJR8FVUOpes9_4OAh6be{bT@jK|_|K=O7p0V{s!FRyST9vo>D|vh zr_3 z%Sz>P8HbhEm`+ano?tuW+p2sKL})wB&btUq>&&SLwGhSnJyFKPXWnR>hyVb^Vks~Y zSomB!Ede3q(j{gQ9zXs%P!U-8{Kw&=<8vi~vw8rh2L zZ?g0znDDZ=FcEy(U_I#zv=X6K=;X4h2m*vKtoWWaMrtBxnr5u7t{Sme%vnNobWG|Z z4fj>$!-~&U6y-Hd)1YY@lF1~1lUYzG6da9J6_m?VO{MMlmL)L}MnS2jY3APx+JY~g zB_6(~0{kEB!Z%0X3J|mdLED8Fp!NF!GgA}*Hn$G|0Lshf=)ZQ-josQPAy*Co05W>T zn-;l`{H7V8&P>r;W0%p}uVA3B6Uxiy=$f2FWMUEkP`Z8_8NEWh{PBMB&%Pf}h41Zj zV0Wv8KUaQ%GBS+P?|)$^a)`U%eT9w1pYUqvBlEvA(AQ~xe_{DYS55`NKeGfjw-3;} zqhNQd1a0{T3Cm|6)@HsiUTu_cV?r@M>+M%?_5EY>2e=U-2!7KZu)9?<)orwzQ*%9% zkt>Iwj0{)roH*@v1_Z%(bQW0LH_W}`-uS2iz|v_iOf0{lU!J@ZrwLi+>dzr$>9!o+Y0iLmVWoVm5(ta`kr>r(lugd34A4nBiQylb-6Oi&+9G5=S1 zd2aa3^?*cJrfa&+e0CTMhmF%P1&n>#&m5|FS#J2ukc?j8UJk%XrZ&*mX(lUv87rSl z<)wW}7Dulzi}2*evM^zR;?$U3AEmL+F~EWcu-5m^EL(9>B7TtBgCfqBFkkvZ?0000S*-B9=_900001bW%=J06^y0W&i*Ha(Yx)bVOxyV{&P5 zbZKvH004NLQ&wLwhE~ldE0Iub6(alE(+Sa=R zf%*asSV_@0M2`gzsE94#cSG9-3nOM3-M6)p*xV=-0C=2JR&a84_w-Y6@%7{?OD!tS%+FJ>RWQ*r;NmRLOex6#a*U0*I5Sc+ z(=$pSoZ^zil2jm5DLp?YGqEHizBnT@H77-hi!&v&s2HT1i!-e#F*g;&Hsn%PaP@Nm zn-2hL#~sc(p%AtJ00E0hL_t(YiS3lXQ-d%R$3yhcu_S3-8w@fBs$C5ooT;8&L5HrE zJN^3&2`4Y@($aJcQ?BQA`pCN9ZM+qaTD#h=S*-O)xa=Xir%H0004WQchCV=-0C=2JR&a84_w-Y6@%7{?OD!tS%+FJ>RWQ*r;NmRLOex6#a*U0*I5Sc+ z(=$pSoZ^zil2jm5DLp?YGqEHizBnT@H77-hi!&v&s2HT1i!-e#F*g;&Hsn%PaP@Nm zn-2hL#~sc(p%AtJ00D7HL_t(YiS3j}?N46oliKs=0H<5J9LKH<1bt@D-fnUo@Fu#tlWH=abu3uOg&G8~k#ZXg>SJ@%V=-f6ff7Ot|A8N;^yS?MMR zOx^2a<+z>`&hp%>g zJxy?92qU0>5d373tv?APpf49R!FLs5MBgN7LLp&9RDzp|Fk&bX3al|LBTj;svmUxP z5;6i7XFYIR5k?FSL5UUslo5}S15!rhTj~HxQAXrl9$03!pp1Ac8M_N_@7Oei5%|$o r2%&-#^2TqviAc}^fiMB!Pcz~db3QU0_k2nW00000NkvXXu0mjfd1&wD literal 0 HcmV?d00001 diff --git a/modular_doppler/tribal_extended/icons/swords_lefthand.dmi b/modular_doppler/tribal_extended/icons/swords_lefthand.dmi new file mode 100644 index 0000000000000000000000000000000000000000..3ee1edbc282002a0bfc254bdef721d3d0bb9e5b8 GIT binary patch literal 453 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 literal 0 HcmV?d00001 diff --git a/modular_doppler/xenoarch/code/modules/hydroponics/amauri.dm b/modular_doppler/xenoarch/code/modules/hydroponics/amauri.dm new file mode 100644 index 0000000000000..0315da4335804 --- /dev/null +++ b/modular_doppler/xenoarch/code/modules/hydroponics/amauri.dm @@ -0,0 +1,28 @@ +/obj/item/seeds/amauri + name = "amauri seed pack" + desc = "These seeds grow into amauri plants. Grows bulbs full of potent toxins." + icon = 'modular_doppler/xenoarch/icons/seeds.dmi' + icon_state = "amauri" + species = "amauri" + plantname = "Amauri Plant" + product = /obj/item/food/grown/amauri + lifespan = 55 + endurance = 35 + yield = 5 + growing_icon = 'modular_doppler/xenoarch/icons/growing.dmi' + icon_grow = "amauri-stage" + growthstages = 3 + genes = list(/datum/plant_gene/trait/repeated_harvest, /datum/plant_gene/trait/preserved) + reagents_add = list(/datum/reagent/toxin = 0.1, /datum/reagent/toxin/venom = 0.1, /datum/reagent/toxin/hot_ice = 0.1) + +/obj/item/food/grown/amauri + seed = /obj/item/seeds/amauri + name = "amauri" + desc = "A toxic amauri bulb, you shouldn't eat this." + icon = 'modular_doppler/xenoarch/icons/harvest.dmi' + icon_state = "amauri" + filling_color = "#FF4500" + bite_consumption_mod = 0.5 + foodtypes = FRUIT + juice_typepath = /datum/reagent/toxin + tastes = list("poison" = 1) diff --git a/modular_doppler/xenoarch/code/modules/hydroponics/gelthi.dm b/modular_doppler/xenoarch/code/modules/hydroponics/gelthi.dm new file mode 100644 index 0000000000000..174daadc33eaa --- /dev/null +++ b/modular_doppler/xenoarch/code/modules/hydroponics/gelthi.dm @@ -0,0 +1,28 @@ +/obj/item/seeds/gelthi + name = "gelthi seed pack" + desc = "These seeds grow into gelthi plants. Lauded by chefs for its unique ability to produce honey, and often hoarded for this very reason." + icon = 'modular_doppler/xenoarch/icons/seeds.dmi' + icon_state = "gelthi" + species = "gelthi" + plantname = "Gelthi Plant" + product = /obj/item/food/grown/gelthi + lifespan = 55 + endurance = 35 + yield = 5 + growing_icon = 'modular_doppler/xenoarch/icons/growing.dmi' + icon_grow = "gelthi-stage" + growthstages = 3 + genes = list(/datum/plant_gene/trait/repeated_harvest, /datum/plant_gene/trait/squash) + reagents_add = list(/datum/reagent/consumable/sprinkles = 0.1, /datum/reagent/consumable/astrotame = 0.1, /datum/reagent/consumable/honey = 0.2) + +/obj/item/food/grown/gelthi + seed = /obj/item/seeds/gelthi + name = "gelthi" + desc = "A cluster of gelthi pods. Each pod contains a different sweetener, and the pods can be juiced into raw sugar." + icon = 'modular_doppler/xenoarch/icons/harvest.dmi' + icon_state = "gelthi" + filling_color = "#FF4500" + bite_consumption_mod = 0.5 + foodtypes = FRUIT + juice_typepath = /datum/reagent/consumable/sugar + tastes = list("overpowering sweetness" = 1) diff --git a/modular_doppler/xenoarch/code/modules/hydroponics/jurlmah.dm b/modular_doppler/xenoarch/code/modules/hydroponics/jurlmah.dm new file mode 100644 index 0000000000000..1fc8b2d9fd4bd --- /dev/null +++ b/modular_doppler/xenoarch/code/modules/hydroponics/jurlmah.dm @@ -0,0 +1,28 @@ +/obj/item/seeds/jurlmah + name = "jurlmah seed pack" + desc = "These seeds grow into jurlmah plants. Often used as makeshift cryo-treatment in areas where a dedicated cryotube setup is impossible." + icon = 'modular_doppler/xenoarch/icons/seeds.dmi' + icon_state = "jurlmah" + species = "jurlmah" + plantname = "Jurlmah Plant" + product = /obj/item/food/grown/jurlmah + lifespan = 55 + endurance = 35 + yield = 5 + growing_icon = 'modular_doppler/xenoarch/icons/growing.dmi' + icon_grow = "jurlmah-stage" + growthstages = 5 + genes = list(/datum/plant_gene/trait/repeated_harvest, /datum/plant_gene/trait/glow/blue) + reagents_add = list(/datum/reagent/medicine/cryoxadone = 0.1, /datum/reagent/inverse/healing/tirimol = 0.1, /datum/reagent/consumable/frostoil = 0.1) + +/obj/item/food/grown/jurlmah + seed = /obj/item/seeds/jurlmah + name = "jurlmah" + desc = "A frosty jurlmah fruit, it feels cold to the touch." + icon = 'modular_doppler/xenoarch/icons/harvest.dmi' + icon_state = "jurlmah" + filling_color = "#FF4500" + bite_consumption_mod = 0.5 + foodtypes = FRUIT + juice_typepath = /datum/reagent/medicine/cryoxadone + tastes = list("snow" = 1) diff --git a/modular_doppler/xenoarch/code/modules/hydroponics/nofruit.dm b/modular_doppler/xenoarch/code/modules/hydroponics/nofruit.dm new file mode 100644 index 0000000000000..5e003367e498e --- /dev/null +++ b/modular_doppler/xenoarch/code/modules/hydroponics/nofruit.dm @@ -0,0 +1,28 @@ +/obj/item/seeds/nofruit + name = "nofruit seed pack" + desc = "These seeds grow into nofruit plants. A strange plant often cultivated by silent performers." + icon = 'modular_doppler/xenoarch/icons/seeds.dmi' + icon_state = "nofruit" + species = "nofruit" + plantname = "Nofruit Plant" + product = /obj/item/food/grown/nofruit + lifespan = 55 + endurance = 35 + yield = 5 + growing_icon = 'modular_doppler/xenoarch/icons/growing.dmi' + icon_grow = "nofruit-stage" + growthstages = 4 + genes = list(/datum/plant_gene/trait/repeated_harvest) + reagents_add = list(/datum/reagent/consumable/nothing = 0.1, /datum/reagent/toxin/mimesbane = 0.1, /datum/reagent/toxin/mutetoxin = 0.1) + +/obj/item/food/grown/nofruit + seed = /obj/item/seeds/nofruit + name = "nofruit" + desc = "A cubic nofruit, the leaf on top of the nofruit gesticulates wildly." + icon = 'modular_doppler/xenoarch/icons/harvest.dmi' + icon_state = "nofruit" + filling_color = "#FF4500" + bite_consumption_mod = 0.5 + foodtypes = FRUIT + juice_typepath = /datum/reagent/consumable/nothing + tastes = list("nothing" = 1) diff --git a/modular_doppler/xenoarch/code/modules/hydroponics/shand.dm b/modular_doppler/xenoarch/code/modules/hydroponics/shand.dm new file mode 100644 index 0000000000000..349eaec78b892 --- /dev/null +++ b/modular_doppler/xenoarch/code/modules/hydroponics/shand.dm @@ -0,0 +1,28 @@ +/obj/item/seeds/shand + name = "shand seed pack" + desc = "These seeds grow into shand plants. While not very useful on its own, it is full of chemicals that no other plant can produce. A good candidate for crossbreeding." + icon = 'modular_doppler/xenoarch/icons/seeds.dmi' + icon_state = "shand" + species = "shand" + plantname = "Shand Plant" + product = /obj/item/food/grown/shand + lifespan = 55 + endurance = 35 + yield = 5 + growing_icon = 'modular_doppler/xenoarch/icons/growing.dmi' + icon_grow = "shand-stage" + growthstages = 3 + genes = list(/datum/plant_gene/trait/repeated_harvest, /datum/plant_gene/trait/maxchem) + reagents_add = list(/datum/reagent/bromine = 0.1, /datum/reagent/sodium = 0.1, /datum/reagent/copper = 0.1) + +/obj/item/food/grown/shand + seed = /obj/item/seeds/shand + name = "shand" + desc = "A handful of shand leaves, the leaves are oily and smell like a laboratory." + icon = 'modular_doppler/xenoarch/icons/harvest.dmi' + icon_state = "shand" + filling_color = "#FF4500" + bite_consumption_mod = 0.5 + foodtypes = FRUIT + juice_typepath = /datum/reagent/bromine + tastes = list("chemicals" = 1) diff --git a/modular_doppler/xenoarch/code/modules/hydroponics/surik.dm b/modular_doppler/xenoarch/code/modules/hydroponics/surik.dm new file mode 100644 index 0000000000000..a70eeb6ebdce5 --- /dev/null +++ b/modular_doppler/xenoarch/code/modules/hydroponics/surik.dm @@ -0,0 +1,28 @@ +/obj/item/seeds/surik + name = "surik seed pack" + desc = "These seeds grow into surik plants. Said to contain the very essence of Indecipheres." + icon = 'modular_doppler/xenoarch/icons/seeds.dmi' + icon_state = "surik" + species = "surik" + plantname = "Surik Plant" + product = /obj/item/food/grown/surik + lifespan = 55 + endurance = 35 + yield = 5 + growing_icon = 'modular_doppler/xenoarch/icons/growing.dmi' + icon_grow = "surik-stage" + growthstages = 4 + genes = list(/datum/plant_gene/trait/repeated_harvest, /datum/plant_gene/trait/fire_resistance) + reagents_add = list(/datum/reagent/brimdust = 0.1, /datum/reagent/medicine/omnizine/godblood = 0.1, /datum/reagent/wittel = 0.1) + +/obj/item/food/grown/surik + seed = /obj/item/seeds/surik + name = "surik" + desc = "A shimmering surik crystal. The center of the gem thrums with volcanic activity." + icon = 'modular_doppler/xenoarch/icons/harvest.dmi' + icon_state = "surik" + filling_color = "#FF4500" + bite_consumption_mod = 0.5 + foodtypes = FRUIT + juice_typepath = /datum/reagent/brimdust + tastes = list("crystals" = 1) diff --git a/modular_doppler/xenoarch/code/modules/hydroponics/telriis.dm b/modular_doppler/xenoarch/code/modules/hydroponics/telriis.dm new file mode 100644 index 0000000000000..23a3994e0b0ae --- /dev/null +++ b/modular_doppler/xenoarch/code/modules/hydroponics/telriis.dm @@ -0,0 +1,29 @@ +/obj/item/seeds/telriis + name = "telriis seed pack" + desc = "These seeds grow into telriis plants. A distant relative of milkweed, this grass can actually be juiced into milk." + icon = 'modular_doppler/xenoarch/icons/seeds.dmi' + icon_state = "telriis" + species = "telriis" + plantname = "Telriis Plant" + product = /obj/item/food/grown/telriis + lifespan = 55 + endurance = 35 + yield = 5 + growing_icon = 'modular_doppler/xenoarch/icons/growing.dmi' + icon_grow = "telriis-stage" + growthstages = 4 + plant_icon_offset = 7 + genes = list(/datum/plant_gene/trait/repeated_harvest, /datum/plant_gene/trait/invasive) + reagents_add = list(/datum/reagent/consumable/milk = 0.1, /datum/reagent/consumable/soymilk = 0.1, /datum/reagent/consumable/korta_milk) + +/obj/item/food/grown/telriis + seed = /obj/item/seeds/telriis + name = "telriis" + desc = "A sheaf of telris, it can be ground or juiced into a milky liquid." + icon = 'modular_doppler/xenoarch/icons/harvest.dmi' + icon_state = "telriis" + filling_color = "#FF4500" + bite_consumption_mod = 0.5 + foodtypes = FRUIT + juice_typepath = /datum/reagent/consumable/coconut_milk + tastes = list("milk" = 1) diff --git a/modular_doppler/xenoarch/code/modules/hydroponics/thaadra.dm b/modular_doppler/xenoarch/code/modules/hydroponics/thaadra.dm new file mode 100644 index 0000000000000..550a9f25b1b27 --- /dev/null +++ b/modular_doppler/xenoarch/code/modules/hydroponics/thaadra.dm @@ -0,0 +1,28 @@ +/obj/item/seeds/thaadra + name = "thaadra seed pack" + desc = "These seeds grow into thaadra plants. A strange flower full of unique medicines and silver." + icon = 'modular_doppler/xenoarch/icons/seeds.dmi' + icon_state = "thaadra" + species = "thaadra" + plantname = "Thaadra Plant" + product = /obj/item/food/grown/thaadra + lifespan = 55 + endurance = 35 + yield = 5 + growing_icon = 'modular_doppler/xenoarch/icons/growing.dmi' + icon_grow = "thaadra-stage" + growthstages = 4 + genes = list(/datum/plant_gene/trait/repeated_harvest, /datum/plant_gene/trait/preserved) + reagents_add = list(/datum/reagent/silver = 0.1, /datum/reagent/medicine/sansufentanyl = 0.1, /datum/reagent/medicine/cordiolis_hepatico = 0.1) + +/obj/item/food/grown/thaadra + seed = /obj/item/seeds/thaadra + name = "thaadra" + desc = "A cluster of thaadra petals, full of niche medicinal chemicals." + icon = 'modular_doppler/xenoarch/icons/harvest.dmi' + icon_state = "thaadra" + filling_color = "#FF4500" + bite_consumption_mod = 0.5 + foodtypes = FRUIT + juice_typepath = /datum/reagent/silver + tastes = list("silver" = 1) diff --git a/modular_doppler/xenoarch/code/modules/hydroponics/vale.dm b/modular_doppler/xenoarch/code/modules/hydroponics/vale.dm new file mode 100644 index 0000000000000..cfd420c8c6835 --- /dev/null +++ b/modular_doppler/xenoarch/code/modules/hydroponics/vale.dm @@ -0,0 +1,28 @@ +/obj/item/seeds/vale + name = "vale seed pack" + desc = "These seeds grow into vale plants. Once sold as a luxury for their unique aesthetics, after the trees suddenly combusted they were taken off of the market." + icon = 'modular_doppler/xenoarch/icons/seeds.dmi' + icon_state = "vale" + species = "vale" + plantname = "Vale Plant" + product = /obj/item/food/grown/vale + lifespan = 55 + endurance = 35 + yield = 5 + growing_icon = 'modular_doppler/xenoarch/icons/growing.dmi' + icon_grow = "vale-stage" + growthstages = 4 + genes = list(/datum/plant_gene/trait/repeated_harvest, /datum/plant_gene/trait/glow/pink) + reagents_add = list(/datum/reagent/stable_plasma = 0.1, /datum/reagent/toxin/plasma = 0.1, /datum/reagent/napalm = 0.1) + +/obj/item/food/grown/vale + seed = /obj/item/seeds/vale + name = "vale" + desc = "A cluster of vale leaves, keep away from open flames." + icon = 'modular_doppler/xenoarch/icons/harvest.dmi' + icon_state = "vale" + filling_color = "#FF4500" + bite_consumption_mod = 0.5 + foodtypes = FRUIT + juice_typepath = /datum/reagent/toxin/plasma + tastes = list("plasma" = 1) diff --git a/modular_doppler/xenoarch/code/modules/hydroponics/vaporsac.dm b/modular_doppler/xenoarch/code/modules/hydroponics/vaporsac.dm new file mode 100644 index 0000000000000..efa36cec89b49 --- /dev/null +++ b/modular_doppler/xenoarch/code/modules/hydroponics/vaporsac.dm @@ -0,0 +1,28 @@ +/obj/item/seeds/vaporsac + name = "vaporsac seed pack" + desc = "These seeds grow into vaporsac plants. Normally vaporsac plants spread by floating through the air and exploding, but this strand of vaporsac thankfully does not." + icon = 'modular_doppler/xenoarch/icons/seeds.dmi' + icon_state = "vaporsac" + species = "vaporsac" + plantname = "Vaporsac Plant" + product = /obj/item/food/grown/vaporsac + lifespan = 55 + endurance = 35 + yield = 5 + growing_icon = 'modular_doppler/xenoarch/icons/growing.dmi' + icon_grow = "vaporsac-stage" + growthstages = 3 + genes = list(/datum/plant_gene/trait/squash, /datum/plant_gene/trait/smoke) + reagents_add = list(/datum/reagent/nitrous_oxide = 0.1, /datum/reagent/medicine/muscle_stimulant = 0.1, /datum/reagent/medicine/coagulant = 0.1) + +/obj/item/food/grown/vaporsac + seed = /obj/item/seeds/vaporsac + name = "vaporsac" + desc = "An buoyant vaporsac, full of aerosolized chemicals." + icon = 'modular_doppler/xenoarch/icons/harvest.dmi' + icon_state = "vaporsac" + filling_color = "#FF4500" + bite_consumption_mod = 0.5 + foodtypes = FRUIT + juice_typepath = /datum/reagent/nitrous_oxide + tastes = list("sleep" = 1) diff --git a/modular_doppler/xenoarch/code/modules/research/xenoarch/designs_and_tech.dm b/modular_doppler/xenoarch/code/modules/research/xenoarch/designs_and_tech.dm new file mode 100644 index 0000000000000..903bc2c129297 --- /dev/null +++ b/modular_doppler/xenoarch/code/modules/research/xenoarch/designs_and_tech.dm @@ -0,0 +1,239 @@ +#define RND_SUBCATEGORY_MACHINE_XENOARCH "/Xenoarchaeology Machinery" +#define RND_SUBCATEGORY_EQUIPMENT_XENOARCH "/Xenoarchaeology Equipment" +#define RND_SUBCATEGORY_TOOLS_XENOARCH "/Xenoarchaeology Tools" +#define RND_SUBCATEGORY_TOOLS_XENOARCH_ADVANCED "/Xenoarchaeology Tools (Advanced)" + +/datum/design/xenoarch + build_type = PROTOLATHE | AWAY_LATHE + departmental_flags = DEPARTMENT_BITFLAG_SCIENCE | DEPARTMENT_BITFLAG_CARGO + materials = list( + /datum/material/iron = HALF_SHEET_MATERIAL_AMOUNT, + /datum/material/plastic = HALF_SHEET_MATERIAL_AMOUNT, + ) + +/datum/design/xenoarch/tool + category = list( + RND_CATEGORY_TOOLS + RND_SUBCATEGORY_TOOLS_XENOARCH, + ) + +/datum/design/xenoarch/tool/hammer + desc = "A hammer that can slowly remove debris on strange rocks." + +/datum/design/xenoarch/tool/hammer/cm1 + name = "Hammer (cm 1)" + id = "hammer_cm1" + build_path = /obj/item/xenoarch/hammer/cm1 + +/datum/design/xenoarch/tool/hammer/cm2 + name = "Hammer (cm 2)" + id = "hammer_cm2" + build_path = /obj/item/xenoarch/hammer/cm2 + +/datum/design/xenoarch/tool/hammer/cm3 + name = "Hammer (cm 3)" + id = "hammer_cm3" + build_path = /obj/item/xenoarch/hammer/cm3 + +/datum/design/xenoarch/tool/hammer/cm4 + name = "Hammer (cm 4)" + id = "hammer_cm4" + build_path = /obj/item/xenoarch/hammer/cm4 + +/datum/design/xenoarch/tool/hammer/cm5 + name = "Hammer (cm 5)" + id = "hammer_cm5" + build_path = /obj/item/xenoarch/hammer/cm5 + +/datum/design/xenoarch/tool/hammer/cm6 + name = "Hammer (cm 6)" + id = "hammer_cm6" + build_path = /obj/item/xenoarch/hammer/cm6 + +/datum/design/xenoarch/tool/hammer/cm10 + name = "Hammer (cm 10)" + id = "hammer_cm10" + build_path = /obj/item/xenoarch/hammer/cm10 + +/datum/design/xenoarch/tool/brush + name = "Brush" + desc = "A brush that can slowly remove debris on a strange rock." + id = "xenoarch_brush" + build_path = /obj/item/xenoarch/brush + +/datum/design/xenoarch/tool/xeno_tape + name = "Xenoarch Tape Measure" + desc = "A tape measure used to measure the dug depth of strange rocks." + id = "xenoarch_tapemeasure" + build_path = /obj/item/xenoarch/tape_measure + +/datum/design/xenoarch/tool/scanner + name = "Xenoarch Handheld Scanner" + desc = "A handheld scanner for strange rocks, capable of tagging a \"safe\" depth and maximum depth." + id = "xenoarch_handscanner" + build_path = /obj/item/xenoarch/handheld_scanner + +/datum/design/xenoarch/tool/advanced + materials = list( + /datum/material/iron = HALF_SHEET_MATERIAL_AMOUNT, + /datum/material/plastic = HALF_SHEET_MATERIAL_AMOUNT, + /datum/material/diamond = HALF_SHEET_MATERIAL_AMOUNT, + ) + category = list( + RND_CATEGORY_TOOLS + RND_SUBCATEGORY_TOOLS_XENOARCH_ADVANCED, + ) + + +/datum/design/xenoarch/tool/advanced/scanner + name = "Xenoarch Advanced Handheld Scanner" + id = "xenoarch_handscanner_adv" + build_path = /obj/item/xenoarch/handheld_scanner/advanced + +/datum/design/xenoarch/tool/advanced/recoverer + name = "Xenoarch Handheld Recoverer" + desc = "A device with the capabilities to recover items lost due to time." + id = "xenoarch_handrecoverer" + materials = list( + /datum/material/iron = HALF_SHEET_MATERIAL_AMOUNT, + /datum/material/plastic = HALF_SHEET_MATERIAL_AMOUNT, + ) + // rebalance material req after first repath/categorization? + build_path = /obj/item/xenoarch/handheld_recoverer + +/datum/design/xenoarch/tool/advanced/adv_hammer + name = "Advanced Hammer" + desc = "A hammer that can quickly remove debris on a strange rock and change digging depths." + id = "xenoarch_adv_hammer" + build_path = /obj/item/xenoarch/hammer/adv + +/datum/design/xenoarch/tool/advanced/adv_brush + name = "Advanced Brush" + desc = "A brush that can quickly remove debris on a strange rock." + id = "xenoarch_adv_brush" + build_path = /obj/item/xenoarch/brush/adv + +/datum/design/xenoarch/equipment + // everything under this except the adv bag feels redundant because cloth/leather are there too + // but i guess we'll burn that bridge another time + category = list( + RND_CATEGORY_EQUIPMENT + RND_SUBCATEGORY_EQUIPMENT_XENOARCH, + ) + +/datum/design/xenoarch/equipment/bag + name = "Xenoarchaeology Bag" + desc = "A bag that can hold about twenty-five strange rocks." + id = "xenoarch_bag" + build_path = /obj/item/storage/bag/xenoarch + +/datum/design/xenoarch/equipment/belt + name = "Xenoarchaeology Belt" + desc = "A belt that can hold all of the essential tools for xenoarchaeology." + id = "xenoarch_belt" + build_path = /obj/item/storage/belt/utility/xenoarch + +/datum/design/xenoarch/equipment/bag_adv + name = "Advanced Xenoarch Bag" + desc = "A bag that can hold about fifty strange rocks." + id = "xenoarch_bag_adv" + materials = list( + /datum/material/iron = HALF_SHEET_MATERIAL_AMOUNT, + /datum/material/plastic = HALF_SHEET_MATERIAL_AMOUNT, + /datum/material/diamond = HALF_SHEET_MATERIAL_AMOUNT, + ) + // i kinda hate how this requires diamond, but this is supposed to be a fix pr, burn the gbp on it later + build_path = /obj/item/storage/bag/xenoarch/adv + +/datum/design/board/xenoarch + category = list( + RND_CATEGORY_MACHINE + RND_SUBCATEGORY_MACHINE_XENOARCH, + ) + departmental_flags = DEPARTMENT_BITFLAG_SCIENCE + +/datum/design/board/xenoarch/researcher + name = "Machine Design (Xenoarch Researcher)" + desc = "Allows for the construction of circuit boards used to build a new xenoarch researcher." + id = "xeno_researcher" + build_path = /obj/item/circuitboard/machine/xenoarch_machine/xenoarch_researcher + +/datum/design/board/xenoarch/scanner + name = "Machine Design (Xenoarch Scanner)" + desc = "Allows for the construction of circuit boards used to build a new xenoarch scanner." + id = "xeno_scanner" + build_path = /obj/item/circuitboard/machine/xenoarch_machine/xenoarch_scanner + +/datum/design/board/xenoarch/recoverer + name = "Machine Design (Xenoarch Recoverer)" + desc = "Allows for the construction of circuit boards used to build a new xenoarch recoverer." + id = "xeno_recoverer" + build_path = /obj/item/circuitboard/machine/xenoarch_machine/xenoarch_recoverer + +/datum/design/board/xenoarch/digger + name = "Machine Design (Xenoarch Digger)" + desc = "Allows for the construction of circuit boards used to build a new xenoarch digger." + id = "xeno_digger" + build_path = /obj/item/circuitboard/machine/xenoarch_machine/xenoarch_digger + +/datum/techweb_node/basic_xenoarch + id = TECHWEB_NODE_XENOARCH_BASIC + starting_node = TRUE + display_name = "Basic Xenoarchaeology" + description = "The basic designs of xenoarchaeology." + design_ids = list( + "hammer_cm1", + "hammer_cm2", + "hammer_cm3", + "hammer_cm4", + "hammer_cm5", + "hammer_cm6", + "hammer_cm10", + "xenoarch_brush", + "xenoarch_tapemeasure", + "xenoarch_handscanner", + ) + +/datum/techweb_node/xenoarch_storage + id = TECHWEB_NODE_XENOARCH_STORAGE + display_name = "Xenoarchaeology Storage" + description = "When dealing with xenoarchaeology, one may need storage." + prereq_ids = list(TECHWEB_NODE_XENOARCH_BASIC) + design_ids = list( + "xenoarch_belt", + "xenoarch_bag", + ) + research_costs = list(TECHWEB_POINT_TYPE_GENERIC = TECHWEB_TIER_1_POINTS) + +/datum/techweb_node/xenoarch_machines + id = TECHWEB_NODE_XENOARCH_MACHINES + display_name = "Xenoarchaeology Machines" + description = "Sometimes, xenoarchaeology can be time consuming, perhaps machines can help?" + prereq_ids = list(TECHWEB_NODE_XENOARCH_BASIC) + design_ids = list( + "xeno_researcher", + "xeno_scanner", + "xeno_recoverer", + ) + research_costs = list(TECHWEB_POINT_TYPE_GENERIC = TECHWEB_TIER_1_POINTS) + +/datum/techweb_node/adv_xenoarch + id = TECHWEB_NODE_XENOARCH_ADVANCED + display_name = "Advanced Xenoarchaeology" + description = "After some time, those tools we used have become antiquated-- we need an upgrade." + prereq_ids = list(TECHWEB_NODE_XENOARCH_BASIC, TECHWEB_NODE_XENOARCH_MACHINES, TECHWEB_NODE_XENOARCH_STORAGE) + design_ids = list( + "xenoarch_adv_hammer", + "xenoarch_adv_brush", + "xenoarch_bag_adv", + "xenoarch_handscanner_adv", + "xenoarch_handrecoverer", + "xeno_digger", + ) + research_costs = list(TECHWEB_POINT_TYPE_GENERIC = TECHWEB_TIER_2_POINTS) + required_experiments = list(/datum/experiment/scanning/points/xenoarch) + +/datum/experiment/scanning/points/xenoarch + name = "Advanced Xenoarchaeology Tools" + description = "It is possible to create even more advanced tools for xenoarchaeoloy." + required_points = 10 + required_atoms = list( + /obj/item/xenoarch/useless_relic = 1, + /obj/item/xenoarch/broken_item = 2, + ) diff --git a/modular_doppler/xenoarch/code/modules/research/xenoarch/glassblowing_integration.dm b/modular_doppler/xenoarch/code/modules/research/xenoarch/glassblowing_integration.dm new file mode 100644 index 0000000000000..d9813652ed136 --- /dev/null +++ b/modular_doppler/xenoarch/code/modules/research/xenoarch/glassblowing_integration.dm @@ -0,0 +1,18 @@ +/obj/item/glassblowing/magnifying_glass + name = "magnifying glass" + desc = "A tool that, with the assistance of a magnifying lens, allows you to view what is small." + icon_state = "magnifying_glass" + +/obj/item/glassblowing/magnifying_glass/examine(mob/user) + . = ..() + if(HAS_TRAIT(user, TRAIT_XENOARCH_QUALIFIED)) + . += span_notice("You can use [src] on useless relics to realize their full potential!") + +/datum/crafting_recipe/magnifying_glass + name = "Magnifying Glass" + result = /obj/item/glassblowing/magnifying_glass + reqs = list( + /obj/item/stack/sheet/mineral/wood = 1, + /obj/item/glassblowing/glass_lens = 1, + ) + category = CAT_EQUIPMENT diff --git a/modular_doppler/xenoarch/code/modules/research/xenoarch/strange_rock.dm b/modular_doppler/xenoarch/code/modules/research/xenoarch/strange_rock.dm new file mode 100644 index 0000000000000..25908df022a79 --- /dev/null +++ b/modular_doppler/xenoarch/code/modules/research/xenoarch/strange_rock.dm @@ -0,0 +1,305 @@ +#define DIG_UNDEFINED (1<<0) //when the strange rock is dug by an item with no dig depth. +#define DIG_DELETE (1<<1) //when the strange rock is dug too deep and gets destroyed in the process. +#define DIG_ROCK (1<<2) //when the strange rock is just dug, with no additional effects. + +#define BRUSH_DELETE (2<<0) //when the strange rock is brushed and the strange rock gets destroyed. +#define BRUSH_UNCOVER (2<<1) //when the strange rock is brushed and the strange rock reveals what it held. +#define BRUSH_NONE (2<<2) //when the strange rock is brushed, with no additional effects. + +#define REWARD_ONE 1 +#define REWARD_TWO 2 +#define REWARD_THREE 3 + +/obj/item/xenoarch/strange_rock + name = "strange rock" + desc = "A mysterious, strange rock that has the potential to have a wonderful item. Also possible for it to have our disposed garbage." + icon_state = "rock" + + ///The max depth a strange rock can be + var/max_depth + ///The depth away/subtracted from the max_depth + var/safe_depth + //The depth chosen between the max and the max - safe depth + var/item_depth + //The depth that has been currently dug + var/dug_depth = 0 + //The item that is hidden within the strange rock + var/hidden_item + ///Whether the item has been measured, revealing the dug depth + var/measured = FALSE + ///Whether the ite has been scanned, revealing the max and safe depth + var/scanned = FALSE + ///Whether the ite has been advance scanned, revealing the true depth + var/adv_scanned = FALSE + ///The scan state for when encountering the strange rock ore in mining. + var/scan_state = "rock_Strange" + ///The tier of the item that was chosen, 1-100 then 1-3 + var/choose_tier + +/obj/item/xenoarch/strange_rock/Initialize(mapload) + . = ..() + create_item() + create_depth() + +/obj/item/xenoarch/strange_rock/examine(mob/user) + . = ..() + . += span_notice("[scanned ? "This item has been scanned. Max Depth: [max_depth] cm. Safe Depth: [safe_depth] cm." : "This item has not been scanned."]") + if(adv_scanned) + . += span_notice("The item depth is [item_depth] cm.") + . += span_notice("[measured ? "This item has been measured. Dug Depth: [dug_depth]." : "This item has not been measured."]") + if(measured && dug_depth > item_depth) + . += span_warning("The rock is crumbling, even just brushing it will destroy it!") + +/obj/item/xenoarch/strange_rock/proc/create_item() + choose_tier = rand(1,100) + switch(choose_tier) + if(1 to 60) + hidden_item = pick_weight(GLOB.tier1_reward) + choose_tier = REWARD_ONE + if(61 to 87) + hidden_item = pick_weight(GLOB.tier2_reward) + choose_tier = REWARD_TWO + if(88 to 100) + hidden_item = pick_weight(GLOB.tier3_reward) + choose_tier = REWARD_THREE + +/obj/item/xenoarch/strange_rock/proc/create_depth() + max_depth = rand(21, (22 * choose_tier)) + safe_depth = rand(1, 10) + item_depth = rand((max_depth - safe_depth), max_depth) + dug_depth = rand(0, 10) + +//returns true if the strange rock is measured +/obj/item/xenoarch/strange_rock/proc/get_measured() + if(measured) + return FALSE + measured = TRUE + return TRUE + +//returns true if the strange rock is scanned +/obj/item/xenoarch/strange_rock/proc/get_scanned(use_advanced = FALSE) + if(scanned) + if(!adv_scanned && use_advanced) + adv_scanned = TRUE + return TRUE + return FALSE + scanned = TRUE + if(use_advanced) + adv_scanned = TRUE + return TRUE + +/obj/item/xenoarch/strange_rock/proc/try_dig(dig_amount) + if(!dig_amount) + return DIG_UNDEFINED + dug_depth += dig_amount + if(dug_depth > item_depth) + qdel(src) + return DIG_DELETE + return DIG_ROCK + +/obj/item/xenoarch/strange_rock/proc/try_uncover() + if(dug_depth > item_depth) + qdel(src) + return BRUSH_DELETE + if(dug_depth == item_depth) + new hidden_item(get_turf(src)) + qdel(src) + return BRUSH_UNCOVER + try_dig(1) + return BRUSH_NONE + +/obj/item/xenoarch/strange_rock/attackby(obj/item/I, mob/living/user, params) + . = ..() + if(istype(I, /obj/item/xenoarch/hammer)) + var/obj/item/xenoarch/hammer/xeno_hammer = I + to_chat(user, span_notice("You begin carefully using your hammer.")) + if(!do_after(user, xeno_hammer.dig_speed, target = src)) + to_chat(user, span_warning("You interrupt your careful planning, damaging the rock in the process!")) + dug_depth += rand(1,5) + return + switch(try_dig(xeno_hammer.dig_amount)) + if(DIG_UNDEFINED) + message_admins("Tell coders something broke with xenoarch hammers and dig amount.") + return + if(DIG_DELETE) + to_chat(user, span_warning("The rock crumbles, leaving nothing behind.")) + return + if(DIG_ROCK) + to_chat(user, span_notice("You successfully dig around the item.")) + + if(istype(I, /obj/item/xenoarch/brush)) + var/obj/item/xenoarch/brush/xeno_brush = I + to_chat(user, span_notice("You begin carefully using your brush.")) + if(!do_after(user, xeno_brush.dig_speed, target = src)) + to_chat(user, span_warning("You interrupt your careful planning, damaging the rock in the process!")) + dug_depth += rand(1,5) + return + switch(try_uncover()) + if(BRUSH_DELETE) + to_chat(user, span_warning("The rock crumbles, leaving nothing behind.")) + return + if(BRUSH_UNCOVER) + to_chat(user, span_notice("You successfully brush around the item, fully revealing the item!")) + return + if(BRUSH_NONE) + to_chat(user, span_notice("You brush around the item, but it wasn't revealed... hammer some more.")) + + if(istype(I, /obj/item/xenoarch/tape_measure)) + to_chat(user, span_notice("You begin carefully using your measuring tape.")) + if(!do_after(user, 4 SECONDS, target = src)) + to_chat(user, span_warning("You interrupt your careful planning, damaging the rock in the process!")) + dug_depth += rand(1,5) + return + if(get_measured()) + to_chat(user, span_notice("You successfully attach a holo measuring tape to the strange rock; the strange rock will now report its dug depth always!")) + return + to_chat(user, span_warning("The strange rock was already marked with a holo measuring tape.")) + + if(istype(I, /obj/item/xenoarch/handheld_scanner)) + var/obj/item/xenoarch/handheld_scanner/item_scanner = I + to_chat(user, span_notice("You begin to scan [src] using [item_scanner].")) + if(!do_after(user, item_scanner.scanning_speed, target = src)) + to_chat(user, span_warning("You interrupt your scanning, damaging the rock in the process!")) + dug_depth += rand(1,5) + return + if(get_scanned(item_scanner.scan_advanced)) + to_chat(user, span_notice("You successfully attach a holo scanning module to the strange rock; the strange rock will now report its depth information always!")) + if(adv_scanned) + to_chat(user, span_notice("The rock's item depth is being reported!")) + return + to_chat(user, span_warning("The strange rock was already marked with a holo scanning module.")) + +//turfs +/turf/closed/mineral/strange_rock + mineralAmt = 1 + icon = MAP_SWITCH('modular_doppler/xenoarch/icons/smoothrocks.dmi', 'modular_doppler/xenoarch/icons/mining.dmi') + scan_state = "rock_Strange" + mineralType = /obj/item/xenoarch/strange_rock + +/turf/closed/mineral/strange_rock/volcanic + turf_type = /turf/open/misc/asteroid/basalt/lava_land_surface + baseturfs = /turf/open/misc/asteroid/basalt/lava_land_surface + initial_gas_mix = LAVALAND_DEFAULT_ATMOS + defer_change = TRUE + +/turf/closed/mineral/random/volcanic + turf_type = /turf/open/misc/asteroid/basalt/lava_land_surface + baseturfs = /turf/open/misc/asteroid/basalt/lava_land_surface + initial_gas_mix = LAVALAND_DEFAULT_ATMOS + defer_change = TRUE + mineralChance = 10 + +/turf/closed/mineral/random/volcanic/mineral_chances() + return list( + /obj/item/stack/ore/iron = 40, + /obj/item/stack/ore/plasma = 20, + /obj/item/stack/ore/silver = 12, + /obj/item/stack/ore/titanium = 11, + /obj/item/stack/ore/gold = 10, + /turf/closed/mineral/strange_rock/volcanic = 10, + /obj/item/stack/ore/uranium = 5, + /turf/closed/mineral/gibtonite/volcanic = 4, + /obj/item/stack/ore/diamond = 1, + /obj/item/stack/ore/bluespace_crystal = 1 + ) + +/turf/closed/mineral/strange_rock/ice + icon = MAP_SWITCH('icons/turf/walls/icerock_wall.dmi', 'modular_doppler/xenoarch/icons/mining.dmi') + icon_state = "icerock_strange" + base_icon_state = "icerock_wall" + smoothing_flags = SMOOTH_BITMASK | SMOOTH_BORDER + turf_type = /turf/open/misc/asteroid/snow/ice + baseturfs = /turf/open/misc/asteroid/snow/ice + initial_gas_mix = FROZEN_ATMOS + defer_change = TRUE + +/turf/closed/mineral/strange_rock/ice/icemoon + turf_type = /turf/open/misc/asteroid/snow/ice/icemoon + baseturfs = /turf/open/misc/asteroid/snow/ice/icemoon + initial_gas_mix = ICEMOON_DEFAULT_ATMOS + +/turf/closed/mineral/random/snow/mineral_chances() + return list( + /obj/item/stack/ore/iron = 40, + /obj/item/stack/ore/plasma = 20, + /obj/item/stack/ore/silver = 12, + /obj/item/stack/ore/titanium = 11, + /obj/item/stack/ore/gold = 10, + /turf/closed/mineral/strange_rock/ice/icemoon = 10, + /obj/item/stack/ore/uranium = 5, + /turf/closed/mineral/gibtonite/ice/icemoon = 4, + /obj/item/stack/ore/diamond = 1, + /obj/item/stack/ore/bluespace_crystal = 1, + ) + +/turf/closed/mineral/random/snow/underground + baseturfs = /turf/open/misc/asteroid/snow/icemoon + // abundant ore + mineralChance = 20 + +/turf/closed/mineral/random/snow/underground/mineral_chances() + return list( + /obj/item/stack/ore/silver = 24, + /obj/item/stack/ore/titanium = 22, + /obj/item/stack/ore/gold = 20, + /obj/item/stack/ore/plasma = 20, + /obj/item/stack/ore/iron = 20, + /obj/item/stack/ore/uranium = 10, + /turf/closed/mineral/strange_rock/ice/icemoon = 10, + /turf/closed/mineral/gibtonite/ice/icemoon = 8, + /obj/item/stack/ore/diamond = 4, + /obj/item/stack/ore/bluespace_crystal = 2, + /obj/item/stack/ore/bananium = 1, + ) + +//small gibonite fix +/turf/closed/mineral/gibtonite/asteroid + icon = MAP_SWITCH('modular_doppler/xenoarch/icons/mining.dmi', 'icons/turf/mining.dmi') + icon_state = "redrock_Gibonite_inactive" + base_icon_state = "red_wall" + smoothing_flags = SMOOTH_BITMASK | SMOOTH_BORDER + turf_type = /turf/open/misc/asteroid + baseturfs = /turf/open/misc/asteroid + initial_gas_mix = OPENTURF_DEFAULT_ATMOS + defer_change = TRUE + +/turf/closed/mineral/strange_rock/asteroid + icon = MAP_SWITCH('modular_doppler/xenoarch/icons/mining.dmi', 'icons/turf/mining.dmi') + icon_state = "redrock_strange" + base_icon_state = "red_wall" + smoothing_flags = SMOOTH_BITMASK | SMOOTH_BORDER + turf_type = /turf/open/misc/asteroid + baseturfs = /turf/open/misc/asteroid + initial_gas_mix = OPENTURF_DEFAULT_ATMOS + defer_change = TRUE + +/turf/closed/mineral/random/stationside/asteroid/rockplanet + initial_gas_mix = OPENTURF_DEFAULT_ATMOS + turf_type = /turf/open/misc/asteroid + mineralChance = 30 + +/turf/closed/mineral/random/stationside/asteroid/rockplanet/mineral_chances() + return list( + /obj/item/stack/ore/iron = 40, + /obj/item/stack/ore/plasma = 20, + /obj/item/stack/ore/silver = 12, + /obj/item/stack/ore/titanium = 11, + /obj/item/stack/ore/gold = 10, + /turf/closed/mineral/strange_rock/asteroid = 10, + /obj/item/stack/ore/uranium = 5, + /turf/closed/mineral/gibtonite/asteroid = 4, + /obj/item/stack/ore/bluespace_crystal = 1, + /obj/item/stack/ore/diamond = 1, + ) + +#undef DIG_UNDEFINED +#undef DIG_DELETE +#undef DIG_ROCK + +#undef BRUSH_DELETE +#undef BRUSH_UNCOVER +#undef BRUSH_NONE + +#undef REWARD_ONE +#undef REWARD_TWO +#undef REWARD_THREE diff --git a/modular_doppler/xenoarch/code/modules/research/xenoarch/xenoarch_item.dm b/modular_doppler/xenoarch/code/modules/research/xenoarch/xenoarch_item.dm new file mode 100644 index 0000000000000..f70d56f492051 --- /dev/null +++ b/modular_doppler/xenoarch/code/modules/research/xenoarch/xenoarch_item.dm @@ -0,0 +1,255 @@ +//useless relics +/obj/item/xenoarch/useless_relic + name = "useless relic" + desc = "A useless relic that can be redeemed for cargo or research points." + ///Used to spawn the same relic + var/magnified_number + +/obj/item/xenoarch/useless_relic/Initialize(mapload) + . = ..() + magnified_number = rand(1,8) + icon_state = "useless[magnified_number]" + +/obj/item/xenoarch/useless_relic/attackby(obj/item/attacking_item, mob/user, params) + if(istype(attacking_item, /obj/item/glassblowing/magnifying_glass)) + if(istype(src, /obj/item/xenoarch/useless_relic/magnified)) + balloon_alert(user, "already magnified!") + return + if(!HAS_TRAIT(user, TRAIT_XENOARCH_QUALIFIED)) + balloon_alert(user, "needs training!") // it was very tempting to replace this with "skill issue" + return + balloon_alert(user, "starting analysis!") + if(!do_after(user, 5 SECONDS, target = src)) + balloon_alert(user, "stand still!") + return + loc.balloon_alert(user, "magnified!") + spawn_magnified(magnified_number) + return + return ..() + +#define ANCIENT_URN 1 +#define ANCIENT_BOWL 2 +#define ANCIENT_CROWN 3 +#define ANCIENT_COIL 4 +#define ANCIENT_LIGHT 5 +#define ANCIENT_CUP 6 +#define ANCIENT_UTENSILS 7 +#define ANCIENT_R_BOWL 8 + +/obj/item/xenoarch/useless_relic/proc/spawn_magnified(type_number) + var/obj/item/xenoarch/useless_relic/magnified/new_item = new(get_turf(src)) + new_item.icon_state = "useless[type_number]" + switch(type_number) + if(ANCIENT_URN) + new_item.name = "ancient urn" + new_item.desc = "This useless relic is an ancient urn that dates from around [rand(400,600)] years ago. \ + It has made of a ceramic substance and is clearly crumbling at the edges. Perhaps it has ashes \ + of someone from long ago." + if(ANCIENT_BOWL) + new_item.name = "ancient bowl" + new_item.desc = "This useless relic is an ancient bowl that dates from around [rand(400,600)] years ago. \ + It is made of a bronze alloy and is dented, with some scratches along the inside. Perhaps it could \ + have had DNA of someone from long ago." + if(ANCIENT_CROWN) + new_item.name = "ancient crown" + new_item.desc = "This useless relic is an ancient crown that dates from around [rand(900,1100)] years ago. \ + It is made from some unknown alloy, with small inlets that would have been used for jewels. Perhaps if we \ + look around, we could find some of those old jewels." + if(ANCIENT_COIL) + new_item.name = "ancient coil" + new_item.desc = "This useless relic is an ancient coil that dates from around [rand(400,600)] years ago. \ + It is made of iron and copper. It has some burn marks around the iron rod. Perhaps later on, we could \ + use it for some machines." + if(ANCIENT_LIGHT) + new_item.name = "ancient light" + new_item.desc = "This useless relic is an ancient light that dates from around [rand(400,600)] years ago. \ + It is made of iron and has glass shards around it. It has dents on the iron and clear damage from misuse. \ + Perhaps we could research this later on to see how the ancients made lights." + if(ANCIENT_CUP) + new_item.name = "ancient cup" + new_item.desc = "This useless relic is an ancient cup that dates from around [rand(900,1100)] years ago. \ + It is made of hardened stone. There are small cracks all along the surface, as long as chisel marks. \ + Perhaps it will give insight into the ancient's eating and drinking habits." + if(ANCIENT_UTENSILS) + new_item.name = "ancient utensils" + new_item.desc = "These useless relics are ancient utensils that dates from around [rand(900,1100)] years ago. \ + It is made of hardened stone. There are small cracks all along the surface, as long as chisel marks. \ + Perhaps it will give insight into the ancient's eating and drinking habits." + if(ANCIENT_R_BOWL) + new_item.name = "ancient rock bowl" + new_item.desc = "This useless relic is an ancient rock bowl that dates from around [rand(900,1100)] years ago. \ + It is made of hardened stone. There are small cracks all along the surface, as long as chisel marks. \ + Perhaps it will give insight into the ancient's eating and drinking habits." + new_item.desc += " Whatever use it possibly had in the past, its only use now is either as a museum piece, or being sold off to collectors via the Cargo shuttle." + qdel(src) + +#undef ANCIENT_URN +#undef ANCIENT_BOWL +#undef ANCIENT_CROWN +#undef ANCIENT_COIL +#undef ANCIENT_LIGHT +#undef ANCIENT_CUP +#undef ANCIENT_UTENSILS +#undef ANCIENT_R_BOWL + +/obj/item/xenoarch/useless_relic/magnified + name = "magnified useless relic" + desc = "A useless relic that can be exported through Cargo. Has been magnified." + +/datum/export/xenoarch/useless_relic + cost = CARGO_CRATE_VALUE * 3 //600 + unit_name = "useless relic" + export_types = list(/obj/item/xenoarch/useless_relic) + include_subtypes = FALSE + k_elasticity = 0 + +/datum/export/xenoarch/broken_item + cost = CARGO_CRATE_VALUE*5 + unit_name = "broken object" + export_types = list(/obj/item/xenoarch/broken_item) + include_subtypes = TRUE + k_elasticity = 0 + +/datum/export/xenoarch/useless_relic/magnified + cost = CARGO_CRATE_VALUE * 6 //1200 + unit_name = "magnified useless relic" + export_types = list(/obj/item/xenoarch/useless_relic/magnified) + include_subtypes = FALSE + +//broken items +/obj/item/xenoarch/broken_item + name = "broken item" + desc = "An item that has been damaged, destroyed for quite some time. It is possible to recover it." + +/obj/item/xenoarch/broken_item/tech + name = "broken tech" + icon_state = "recover_tech" + +/obj/item/xenoarch/broken_item/weapon + name = "broken weapon" + icon_state = "recover_weapon" + +/obj/item/xenoarch/broken_item/illegal + name = "broken unknown object" + icon_state = "recover_illegal" + +/obj/item/xenoarch/broken_item/alien + name = "broken unknown object" + icon_state = "recover_illegal" + +/obj/item/xenoarch/broken_item/plant + name = "withered plant" + desc = "A plant that is long past its prime. It is possible to recover it." + icon_state = "recover_plant" + +/obj/item/xenoarch/broken_item/animal + name = "preserved animal carcass" + desc = "An animal that is long past its prime. It is possible to recover it. Can be swabbed to recover its original animal's remnant DNA." + icon_state = "recover_animal" + +/obj/item/xenoarch/broken_item/animal/Initialize(mapload) + . = ..() + var/pick_celltype = pick(CELL_LINE_TABLE_BEAR, + CELL_LINE_TABLE_BLOBBERNAUT, + CELL_LINE_TABLE_BLOBSPORE, + CELL_LINE_TABLE_CARP, + CELL_LINE_TABLE_CAT, + CELL_LINE_TABLE_CHICKEN, + CELL_LINE_TABLE_COCKROACH, + CELL_LINE_TABLE_CORGI, + CELL_LINE_TABLE_COW, + CELL_LINE_TABLE_MOONICORN, + CELL_LINE_TABLE_GELATINOUS, + CELL_LINE_TABLE_GRAPE, + CELL_LINE_TABLE_MEGACARP, + CELL_LINE_TABLE_MOUSE, + CELL_LINE_TABLE_PINE, + CELL_LINE_TABLE_PUG, + CELL_LINE_TABLE_SLIME, + CELL_LINE_TABLE_SNAKE, + CELL_LINE_TABLE_VATBEAST, + CELL_LINE_TABLE_NETHER, + CELL_LINE_TABLE_GLUTTON, + CELL_LINE_TABLE_FROG, + CELL_LINE_TABLE_WALKING_MUSHROOM, + CELL_LINE_TABLE_QUEEN_BEE, + CELL_LINE_TABLE_MEGA_ARACHNID) + AddElement(/datum/element/swabable, pick_celltype, CELL_VIRUS_TABLE_GENERIC_MOB, 1, 5) + +/obj/item/xenoarch/broken_item/clothing + name = "petrified clothing" + desc = "A piece of clothing that has long since lost its beauty." + icon_state = "recover_clothing" + + +//circuit boards +/obj/item/circuitboard/machine/xenoarch_machine + greyscale_colors = CIRCUIT_COLOR_SCIENCE + req_components = list( + /datum/stock_part/micro_laser = 1, + /datum/stock_part/matter_bin = 1, + /obj/item/stack/cable_coil = 2, + /obj/item/stack/sheet/glass = 2, + ) + needs_anchored = TRUE + +/obj/item/circuitboard/machine/xenoarch_machine/xenoarch_researcher + name = "Xenoarch Researcher (Machine Board)" + build_path = /obj/machinery/xenoarch/researcher + +/obj/item/circuitboard/machine/xenoarch_machine/xenoarch_scanner + name = "Xenoarch Scanner (Machine Board)" + build_path = /obj/machinery/xenoarch/scanner + +/obj/item/circuitboard/machine/xenoarch_machine/xenoarch_recoverer + name = "Xenoarch Recoverer (Machine Board)" + build_path = /obj/machinery/xenoarch/recoverer + +/obj/item/circuitboard/machine/xenoarch_machine/xenoarch_digger + name = "Xenoarch Digger (Machine Board)" + build_path = /obj/machinery/xenoarch/digger + +/obj/item/paper/fluff/xenoarch_guide + name = "xenoarchaeology guide - MUST READ" + default_raw_text = {"