diff --git a/code/_helpers/type2type.dm b/code/_helpers/type2type.dm index ef25f44142..e21d973b1b 100644 --- a/code/_helpers/type2type.dm +++ b/code/_helpers/type2type.dm @@ -293,21 +293,122 @@ return strtype return copytext(strtype, delim_pos) +// Concatenates a list of strings into a single string. A seperator may optionally be provided. +/proc/list2text(list/ls, sep) + if (ls.len <= 1) // Early-out code for empty or singleton lists. + return ls.len ? ls[1] : "" + + var/l = ls.len // Made local for sanic speed. + var/i = 0 // Incremented every time a list index is accessed. + + if (sep != null) + // Macros expand to long argument lists like so: sep, ls[++i], sep, ls[++i], sep, ls[++i], etc... + #define S1 sep, ls[++i] + #define S4 S1, S1, S1, S1 + #define S16 S4, S4, S4, S4 + #define S64 S16, S16, S16, S16 + + . = "[ls[++i]]" // Make sure the initial element is converted to text. + + // Having the small concatenations come before the large ones boosted speed by an average of at least 5%. + if (l-1 & 0x01) // 'i' will always be 1 here. + . = text("[][][]", ., S1) // Append 1 element if the remaining elements are not a multiple of 2. + if (l-i & 0x02) + . = text("[][][][][]", ., S1, S1) // Append 2 elements if the remaining elements are not a multiple of 4. + if (l-i & 0x04) + . = text("[][][][][][][][][]", ., S4) // And so on.... + if (l-i & 0x08) + . = text("[][][][][][][][][][][][][][][][][]", ., S4, S4) + if (l-i & 0x10) + . = text("[][][][][][][][][][][][][][][][][][][][][][][][][][][][][][][][][]", ., S16) + if (l-i & 0x20) + . = text("[][][][][][][][][][][][][][][][][][][][][][][][][][][][][][][][][]\ + [][][][][][][][][][][][][][][][][][][][][][][][][][][][][][][][]", ., S16, S16) + if (l-i & 0x40) + . = text("[][][][][][][][][][][][][][][][][][][][][][][][][][][][][][][][][]\ + [][][][][][][][][][][][][][][][][][][][][][][][][][][][][][][][]\ + [][][][][][][][][][][][][][][][][][][][][][][][][][][][][][][][]\ + [][][][][][][][][][][][][][][][][][][][][][][][][][][][][][][][]", ., S64) + while (l > i) // Chomp through the rest of the list, 128 elements at a time. + . = text("[][][][][][][][][][][][][][][][][][][][][][][][][][][][][][][][][]\ + [][][][][][][][][][][][][][][][][][][][][][][][][][][][][][][][]\ + [][][][][][][][][][][][][][][][][][][][][][][][][][][][][][][][]\ + [][][][][][][][][][][][][][][][][][][][][][][][][][][][][][][][]\ + [][][][][][][][][][][][][][][][][][][][][][][][][][][][][][][][]\ + [][][][][][][][][][][][][][][][][][][][][][][][][][][][][][][][]\ + [][][][][][][][][][][][][][][][][][][][][][][][][][][][][][][][]\ + [][][][][][][][][][][][][][][][][][][][][][][][][][][][][][][][]", ., S64, S64) + + #undef S64 + #undef S16 + #undef S4 + #undef S1 + else + // Macros expand to long argument lists like so: ls[++i], ls[++i], ls[++i], etc... + #define S1 ls[++i] + #define S4 S1, S1, S1, S1 + #define S16 S4, S4, S4, S4 + #define S64 S16, S16, S16, S16 + + . = "[ls[++i]]" // Make sure the initial element is converted to text. + + if (l-1 & 0x01) // 'i' will always be 1 here. + . += S1 // Append 1 element if the remaining elements are not a multiple of 2. + if (l-i & 0x02) + . = text("[][][]", ., S1, S1) // Append 2 elements if the remaining elements are not a multiple of 4. + if (l-i & 0x04) + . = text("[][][][][]", ., S4) // And so on... + if (l-i & 0x08) + . = text("[][][][][][][][][]", ., S4, S4) + if (l-i & 0x10) + . = text("[][][][][][][][][][][][][][][][][]", ., S16) + if (l-i & 0x20) + . = text("[][][][][][][][][][][][][][][][][][][][][][][][][][][][][][][][][]", ., S16, S16) + if (l-i & 0x40) + . = text("[][][][][][][][][][][][][][][][][][][][][][][][][][][][][][][][][]\ + [][][][][][][][][][][][][][][][][][][][][][][][][][][][][][][][]", ., S64) + while (l > i) // Chomp through the rest of the list, 128 elements at a time. + . = text("[][][][][][][][][][][][][][][][][][][][][][][][][][][][][][][][][]\ + [][][][][][][][][][][][][][][][][][][][][][][][][][][][][][][][]\ + [][][][][][][][][][][][][][][][][][][][][][][][][][][][][][][][]\ + [][][][][][][][][][][][][][][][][][][][][][][][][][][][][][][][]", ., S64, S64) + + #undef S64 + #undef S16 + #undef S4 + #undef S1 + +// Converts a string into a list by splitting the string at each delimiter found. (discarding the seperator) +/proc/text2list(text, delimiter="\n") + var/delim_len = length(delimiter) + if (delim_len < 1) + return list(text) + + . = list() + var/last_found = 1 + var/found + + do + found = findtext(text, delimiter, last_found, 0) + . += copytext(text, last_found, found) + last_found = found + delim_len + while (found) + /proc/type2parent(child) var/string_type = "[child]" var/last_slash = findlasttext(string_type, "/") - if(last_slash == 1) - switch(child) - if(/datum) - return null - if(/obj || /mob) - return /atom/movable - if(/area || /turf) - return /atom - else - return /datum + if (last_slash != 1) + return text2path(copytext(string_type, 1, last_slash)) + switch (child) + if (/datum) + return null + if (/obj, /mob) + return /atom/movable + if (/area, /turf) + return /atom + else + return /datum - return text2path(copytext(string_type, 1, last_slash)) //checks if a file exists and contains text //returns text as a string if these conditions are met diff --git a/code/datums/components/material_container.dm b/code/datums/components/material_container.dm index fbad2752ee..2b0c74e269 100644 --- a/code/datums/components/material_container.dm +++ b/code/datums/components/material_container.dm @@ -152,6 +152,11 @@ to_chat(user, "[parent] cannot contain [material].") return + // Our sheet had no material. Whoops. + if(!matter_per_sheet) + to_chat(user, "[S] does not contain any matter acceptable by [parent].") + return + // If we can't fit the material for one sheet, we're full. if(!has_space(matter_per_sheet)) to_chat(user, "[parent] is full. Please remove materials from [parent] in order to insert more.") diff --git a/code/datums/looping_sounds/machinery_sounds.dm b/code/datums/looping_sounds/machinery_sounds.dm index 0330811428..d7011dd094 100644 --- a/code/datums/looping_sounds/machinery_sounds.dm +++ b/code/datums/looping_sounds/machinery_sounds.dm @@ -80,7 +80,7 @@ /datum/looping_sound/cerealmaker start_sound = 'sound/machines/kitchen/cerealmaker/cerealmaker-start.ogg' - start_length = 10 + start_length = 10 mid_sounds = list('sound/machines/kitchen/cerealmaker/cerealmaker-mid1.ogg'=10) mid_length = 60 end_sound = 'sound/machines/kitchen/cerealmaker/cerealmaker-stop.ogg' @@ -104,4 +104,14 @@ mid_length = 70 end_sound = 'sound/machines/air_pump/airpumpshutdown.ogg' volume = 15 - pref_check = /datum/client_preference/air_pump_noise \ No newline at end of file + pref_check = /datum/client_preference/air_pump_noise + +//////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// + +/datum/looping_sound/vehicle_engine + start_sound = 'sound/machines/vehicle/engine_start.ogg' + start_length = 2 + mid_sounds = list('sound/machines/vehicle/engine_mid.ogg'=1) + mid_length = 6 + end_sound = 'sound/machines/vehicle/engine_end.ogg' + volume = 20 diff --git a/code/datums/riding.dm b/code/datums/riding.dm index 9dd32dcd93..ec5afff5d5 100644 --- a/code/datums/riding.dm +++ b/code/datums/riding.dm @@ -225,3 +225,28 @@ /datum/riding/boat/get_offsets(pass_index) // list(dir = x, y, layer) return list("[NORTH]" = list(1, 2), "[SOUTH]" = list(1, 2), "[EAST]" = list(1, 2), "[WEST]" = list(1, 2)) + +/datum/riding/snowmobile + only_one_driver = TRUE // Keep your hands to yourself back there! + +/datum/riding/snowmobile/get_offsets(pass_index) // list(dir = x, y, layer) + var/H = 3 // Horizontal seperation. + var/V = 2 // Vertical seperation. + var/O = 2 // Vertical offset. + switch(pass_index) + if(1) // Person on front. + return list( + "[NORTH]" = list( 0, O+V, MOB_LAYER), + "[SOUTH]" = list( 0, O, ABOVE_MOB_LAYER), + "[EAST]" = list( H, O, MOB_LAYER), + "[WEST]" = list(-H, O, MOB_LAYER) + ) + if(2) // Person on back. + return list( + "[NORTH]" = list( 0, O, ABOVE_MOB_LAYER), + "[SOUTH]" = list( 0, O+V, MOB_LAYER), + "[EAST]" = list(-H, O, MOB_LAYER), + "[WEST]" = list( H, O, MOB_LAYER) + ) + else + return null // This will runtime, but we want that since this is out of bounds. diff --git a/code/datums/supplypacks/hydroponics_vr.dm b/code/datums/supplypacks/hydroponics_vr.dm index 7476fdd29b..fa912852e7 100644 --- a/code/datums/supplypacks/hydroponics_vr.dm +++ b/code/datums/supplypacks/hydroponics_vr.dm @@ -70,4 +70,10 @@ name = "Jerboa crate" cost = 10 containertype = /obj/structure/largecrate/animal/jerboa - containername = "Jerboa crate" \ No newline at end of file + containername = "Jerboa crate" + +/datum/supply_pack/hydro/tits + name = "A pair of great tits" + cost = 10 + containertype = /obj/structure/largecrate/tits + containername = "A pair of great tits" diff --git a/code/datums/supplypacks/security.dm b/code/datums/supplypacks/security.dm index 5c4ddf1a6a..fc8d9b373b 100644 --- a/code/datums/supplypacks/security.dm +++ b/code/datums/supplypacks/security.dm @@ -444,7 +444,8 @@ /obj/item/weapon/storage/belt/security = 3, /obj/item/clothing/glasses/sunglasses/sechud = 3, /obj/item/device/radio/headset/headset_sec/alt = 3, - /obj/item/clothing/suit/storage/hooded/wintercoat/security = 3 + /obj/item/clothing/suit/storage/hooded/wintercoat/security = 3, + /obj/item/clothing/glasses/sunglasses/sechud/tactical_sec_vis = 3 ) cost = 10 containertype = /obj/structure/closet/crate/nanothreads diff --git a/code/game/gamemodes/events/holidays/Holidays.dm b/code/game/gamemodes/events/holidays/Holidays.dm index 9b31ad9a50..90a195d1d6 100644 --- a/code/game/gamemodes/events/holidays/Holidays.dm +++ b/code/game/gamemodes/events/holidays/Holidays.dm @@ -22,7 +22,7 @@ var/global/list/Holiday = list() //Holidays are lists now, so we can have more t Holiday = list() // reset our switch now so we can recycle it as our Holiday name - var/YY = text2num(time2text(world.timeofday, "YY")) // get the current year + //var/YY = text2num(time2text(world.timeofday, "YY")) // get the current year - unused currently but can be used for floating dates var/MM = text2num(time2text(world.timeofday, "MM")) // get the current month var/DD = text2num(time2text(world.timeofday, "DD")) // get the current day @@ -36,56 +36,63 @@ var/global/list/Holiday = list() //Holidays are lists now, so we can have more t Holiday["New Years's Day"] = "The day of the new solar year on Sol." if(12) Holiday["Vertalliq-Qerr"] = "Vertalliq-Qerr, translated to mean 'Festival of the Royals', is a \ - Skrell holiday that celebrates the Qerr-Katish and all they have provided for the rest of Skrell society, \ + skrellian holiday that celebrates the Qerr-Katish and all they have provided for the rest of skrellian society, \ it often features colourful displays and skilled performers take this time to show off some of their more \ - fancy displays." + elaborate displays." + if(14) + Holiday["Lohri"] = "A human festival traditionally celebrating the end of winter on the Indian subcontinent. \ + The holiday is now celebrated independently of seasons in many colonies with large populations of Indian \ + descent. Traditions include the burning of bonfires, dancing, and door-to-door singing in exchange for treats." + if(30) + Holiday["Lunar New Year"] = "Originally the new year on the ancient lunisolar calendar, the Lunar New Year is \ + celebrated with a wide variety of east Asian traditions with roots in Chinese, Japanese, Korean, Vietnamese, \ + Tibetan, Mongolian, and Ryukyu cultures. Elaborate parades, performances, dances and meals are usual staples." if(2) //Feb switch(DD) if(2) - Holiday["Groundhog Day"] = "An unoffical holiday based on ancient folklore that originated on Earth, \ - that involves the worship of an almighty groundhog, that could control the weather based on if it casted a shadow." + Holiday["Groundhog Day"] = "An unoffical holiday based on medieval folklore that originated on Earth, \ + that involves the reverence of a prophetic animal - traditionally a badger, fox or groundhog - that was \ + said to be able to predict, or even control the changing of the seasons." if(14) - Holiday["Valentine's Day"] = "An old holiday that revolves around romance and love." + Holiday["Valentine's Day"] = "A human holiday that revolves around expressions of romance and love. \ + In particular, the exchanging of gifts, letters and cards is traditional." + if(15) + Holiday["Lantern Festival"] = "A human holiday with origins in Chinese new year celebrations. Participants \ + carry or hang elaborate paper lanterns that are thought to bring good luck. Today, electric lights are often used \ + in environments where open flames would be hazardous or non-functional." if(17) Holiday["Random Acts of Kindness Day"] = "An unoffical holiday that challenges everyone to perform \ - acts of kindness to their friends, co-workers, and strangers, for no reason." + acts of kindness to their friends, co-workers, and strangers, with no strings attached." if(3) //Mar switch(DD) if(3) - Holiday["Qixm-tes"] = "Qixm-tes, or 'Day of mourning', is a Skrell holiday where Skrell gather at places \ - of worship and sing a song of mourning for all those who have died in service to their empire." + Holiday["Qixm-tes"] = "Qixm-tes, or 'Day of mourning', is a skrellian holiday where skrell gather at places \ + of worship and sing a song of mourning for all those who have died in service to their kingdoms." if(14) Holiday["Pi Day"] = "An unoffical holiday celebrating the mathematical constant Pi. It is celebrated on \ March 14th, as the digits form 3 14, the first three significant digits of Pi. Observance of Pi Day generally \ involve eating (or throwing) pie, due to a pun. Pies also tend to be round, and thus relatable to Pi." if(17) - Holiday["St. Patrick's Day"] = "An old holiday originating from Earth, Sol, celebrating the color green, \ - shamrocks, attending parades, and drinking alcohol." + Holiday["St. Patrick's Day"] = "A holiday originating on Earth, celebrating a popular version of Irish culture. \ + Traditions include elaborate parades, wearing of the colour green, and drinking alcohol." + if(18) + Holiday["Holi"] = "Also known as the Festival of Colours, a human Hindu festival celebrating divine love and the \ + triumph of good over evil. Traditionally a bonfire is lit overnight, followed by the free-for-all smearing of \ + celebrants with colourful pigments, and the forgiveness of past wrongs." if(27) - if(YY == 16) - Holiday["Easter"] = "" - if(31) - if(YY == 13) - Holiday["Easter"] = "" + Holiday["Easter"] = "A Earth springtime festival variously celebrating rebirth and the beginning of the planting \ + season. Traditionally celebrated with the painting and exchange of eggs, sometimes made from chocolate. \ + The holiday's date was standardized in the 22nd century." if(4) //Apr switch(DD) if(1) - Holiday["April Fool's Day"] = "An old holiday that endevours one to pull pranks and spread hoaxes on their friends." - if(YY == 18) - Holiday["Easter"] = "" - if(8) - if(YY == 15) - Holiday["Easter"] = "" - if(16) - if(YY == 17) //Easter can go die for all of this copypasta. - Holiday["Easter"] = "" - - if(20) - if(YY == 14) - Holiday["Easter"] = "" + Holiday["April Fool's Day"] = "A human holiday that endevours one to pull pranks and spread hoaxes on their friends." + if(5) + Holiday["First Day of Passover"] = "The first of eight days of a human holiday celebrating the exodus of ancient Jewish people \ + from slavery, and of the spring harvest. The most well-known tradition is the Sedar meal. The date was standardized in the 22nd century." if(22) Holiday["Earth Day"] = "A holiday of enviromentalism, that originated on it's namesake, Earth." @@ -100,7 +107,7 @@ var/global/list/Holiday = list() //Holidays are lists now, so we can have more t Observance of this day varies throughout human space, but most common traditions are the act of bringing flowers to graves,\ attending parades, and the wearing of poppies (either paper or real) in one's clothing." if(28) - Holiday["Jiql-tes"] = "A Skrellian holiday that translates to 'Day of Celebration', Skrell communities \ + Holiday["Jiql-tes"] = "A skrellian holiday that translates to 'Day of Celebration', skrell communities \ gather for a grand feast and give gifts to friends and close relatives." if(6) //Jun @@ -113,7 +120,11 @@ var/global/list/Holiday = list() //Holidays are lists now, so we can have more t and to thank blood donors for their voluntary, life-saving gifts of blood." if(20) Holiday["Civil Servant's Day"] = "Civil Servant's Day is a holiday observed in SCG member states that honors civil servants everywhere,\ -+ (especially those who are members of the armed forces and the emergency services), or have been or have been civil servants in the past." + (especially those who are members of the armed forces and the emergency services), or have been or have been civil servants in the past." +/* if(25) + Holiday["Merhyat Njarha"] = "A Njarir'Akhan tajaran tradition translating to \"Harmony of the House\", in which Njarjirii citizens pay \ + homage to their ruling house and their ancestors. Traditions include large communal meals and dances hosted by the ruling house, \ + and the intensive upkeep of community spaces."*/ if(7) //Jul switch(DD) @@ -126,36 +137,51 @@ var/global/list/Holiday = list() //Holidays are lists now, so we can have more t if(8) //Aug switch(DD) -// if(10) -// Holiday["S'randarr's Day"] = "A Tajaran holiday that occurs on the longest day of the year in summer, -// on Ahdomai. It is named after the Tajaran deity of Light, and huge celebrations are common." //VOREStation Add - Of course we need this. if(8) Holiday["Vore Day"] = "A holiday representing the innate desire in all/most/some/a few of us to devour each other or be devoured. \ That's probably why you're here, isn't it? Get to it, then!" //VOREStation Add End. - +/* if(10) + Holiday["S'randarr's Day"] = "A Tajaran holiday that occurs on the longest day of the year in summer, + on Ahdomai. It is named after the Tajaran deity of Light, and huge celebrations are common." + if(11) + Holiday["Tajaran Contact Day"] = "The anniversary of first contact between SolGov and the tajaran species, widely observed\ + throughout tajaran and human space. Marks the date that in 2513, a human exploration team investigating electromagnetic \ + emissions from the Meralar system made radio contact with the tajaran scientific outpost that had broadcast them."*/ + if(20) + Holiday["Obon"] = "An ancient Earth holiday originating in east Asia, for the honouring of one's ancestral spirits. \ + Traditions include the maintenance of grave sites and memorials, and community traditional dance performances." if(27) Holiday["Forgiveness Day"] = "A time to forgive and be forgiven." if(9) //Sep switch(DD) if(17) - Holiday["Qill-xamr"] = "Translated to 'Night of the dead', it is a Skrell holiday where Skrell \ + Holiday["Qill-xamr"] = "Translated to 'Night of the dead', it is a skrellian holiday where skrell \ communities hold parties in order to remember loved ones who passed, unlike Qixm-tes, this applies to everyone \ and is a joyful celebration." if(19) - Holiday["Talk-Like-a-Pirate Day"] = "Ahoy, matey! Tis unoffical holiday be celebratin' the jolly \ - good humor of speakin' like the pirates of old." + Holiday["Talk-Like-a-Pirate Day"] = "Ahoy, matey! It be the unoffical holiday celebratin' the salty \ + sea humor of speakin' like the pirates of old." + if(20) + Holiday["Rosh Hashanah"] = "An old human holiday that marks the traditional Hebrew new year." if(28) Holiday["Stupid-Questions Day"] = "Known as Ask A Stupid Question Day, it is an unoffical holiday \ created by teachers in Sol, very long ago, to encourage students to ask more questions in the classroom." if(10) //Oct switch(DD) + if(9) + Holiday["Lief Eriksson Day"] = "A day commemorating Norse explorer Lief Eriksson, an early Scandinavian cultural figure \ + who is thought to have been the first European to set foot in North America." if(16) Holiday["Boss' Day"] = "Boss' Day has traditionally been a day for employees to thank their bosses for the difficult work that they do \ throughout the year. This day was created for the purpose of strengthening the bond between employer and employee." + if(21) + Holiday["First Day of Diwali"] = "An ancient Hindu, Jain and Sikh festival lasting five days, celebrating victory of light over darkness, good over \ + evil, and knowledge over ignorance. It is celebrated by the wearing of your finest clothes, decorating with oil lamps and rangolis, \ + fireworks, and gift-giving. Electric lights are often used in modern times where oil lamps would be hazardous or inoperable." if(31) Holiday["Halloween"] = "Originating from Earth, Halloween is also known as All Saints' Eve, and \ is celebrated by some by attending costume parties, trick-or-treating, carving faces in pumpkins, or visiting \ @@ -163,6 +189,10 @@ var/global/list/Holiday = list() //Holidays are lists now, so we can have more t if(11) //Nov switch(DD) + if(1) + Holiday["Day of the Dead"] = "An old human holiday celebrating the lives of deceased friends and family members, \ + by means of good humour and joyful parties. Offerings are often left at altars to the dead, and exchanging gifts \ + among the living is not uncommon." if(13) Holiday["Kindness Day"] = "Kindness Day is an unofficial holiday to highlight good deeds in the \ community, focusing on the positive power and the common thread of kindness which binds humanity and \ @@ -182,16 +212,17 @@ var/global/list/Holiday = list() //Holidays are lists now, so we can have more t if(10) Holiday["Human-Rights Day"] = "An old holiday created by an intergovernmental organization known back than as the United Nations, \ human rights were not recognized globally at the time, and the holiday was made in honor of the Universal Declaration of Human Rights. \ - These days, SolGov ensures that past efforts were not in vein, and continues to honor this holiday across the galaxy." + These days, SolGov ensures that past efforts were not in vein, and continues to honor this holiday across the galaxy as a historical \ + reminder." if(22) - Holiday["Vertalliq-qixim"] = "A Skrellian holiday that celebrates the Skrell's first landing on one of \ - their moons. It's often celebrated with grand festivals." + Holiday["Vertalliq-qixim"] = "A skrellian holiday that celebrates the skrell's first landing on one of \ + their moons. It's often celebrated with grand festivals." if(24) Holiday["Christmas Eve"] = "The eve of Christmas, an old holiday from Earth that mainly involves gift \ giving, decorating, family reunions, and a fat red human breaking into people's homes to steal milk and cookies." if(25) Holiday["Christmas"] = "Christmas is a very old holiday that originated in Earth, Sol. It was a \ - religious holiday for the Christian religion, which would later form Unitarianism. Nowdays, the holiday is celebrated \ + religious holiday for the Christian religion, which would later form Unitarianism. Nowadays, the holiday is celebrated \ generally by giving gifts, symbolic decoration, and reuniting with one's family. It also features a mythical fat \ red human, known as Santa, who broke into people's homes to loot cookies and milk." if(31) diff --git a/code/game/objects/items/weapons/storage/belt.dm b/code/game/objects/items/weapons/storage/belt.dm index 3afc5d64a5..c218e6cc08 100644 --- a/code/game/objects/items/weapons/storage/belt.dm +++ b/code/game/objects/items/weapons/storage/belt.dm @@ -116,6 +116,40 @@ desc = "Holds tools, looks snazzy." icon_state = "utilitybelt_ce" item_state = "utility_ce" + storage_slots = 8 //If they get better everything-else, why not the belt too? + can_hold = list( + /obj/item/weapon/rcd, //They've given one from the get-go, it's hard to imagine they wouldn't be given something that can store it neater than a bag + /obj/item/weapon/tool/crowbar, + /obj/item/weapon/tool/screwdriver, + /obj/item/weapon/weldingtool, + /obj/item/weapon/tool/wirecutters, + /obj/item/weapon/tool/wrench, + /obj/item/device/multitool, + /obj/item/device/flashlight, + /obj/item/weapon/cell/device, + /obj/item/stack/cable_coil, + /obj/item/device/t_scanner, + /obj/item/device/analyzer, + /obj/item/clothing/glasses, + /obj/item/clothing/gloves, + /obj/item/device/pda, + /obj/item/device/megaphone, + /obj/item/taperoll, + /obj/item/device/radio/headset, + /obj/item/device/robotanalyzer, + /obj/item/weapon/material/minihoe, + /obj/item/weapon/material/knife/machete/hatchet, + /obj/item/device/analyzer/plant_analyzer, + /obj/item/weapon/extinguisher/mini, + /obj/item/weapon/tape_roll, + /obj/item/device/integrated_electronics/wirer, + /obj/item/device/integrated_electronics/debugger, + /obj/item/weapon/shovel/spade, + /obj/item/stack/nanopaste, + /obj/item/device/geiger, + /obj/item/areaeditor/blueprints, //It's a bunch of paper that could prolly be rolled up & slipped into the belt, not to mention CE only, see the RCD's thing above + /obj/item/wire_reader //As above + ) /obj/item/weapon/storage/belt/utility/chief/full starts_with = list( @@ -296,9 +330,11 @@ /obj/item/device/flash, /obj/item/weapon/flame/lighter, /obj/item/weapon/reagent_containers/food/snacks/donut/, - /obj/item/ammo_magazine, - /obj/item/weapon/gun/projectile/colt/detective, - /obj/item/device/holowarrant + ///obj/item/ammo_magazine, //Detectives don't get projectile weapons as standard here + ///obj/item/weapon/gun/projectile/colt/detective, //Detectives don't get projectile weapons as standard here + /obj/item/weapon/gun/energy/stunrevolver/detective, //In keeping with the same vein as above, they can store their special one + /obj/item/device/holowarrant, + /obj/item/weapon/reagent_containers/food/drinks/flask ) /obj/item/weapon/storage/belt/soulstone diff --git a/code/game/objects/structures/crates_lockers/largecrate_vr.dm b/code/game/objects/structures/crates_lockers/largecrate_vr.dm index cc88e0f871..0e890c37e8 100644 --- a/code/game/objects/structures/crates_lockers/largecrate_vr.dm +++ b/code/game/objects/structures/crates_lockers/largecrate_vr.dm @@ -144,4 +144,9 @@ /obj/structure/largecrate/animal/weretiger name = "Weretiger Crate" desc = "You can hear a lot of annoyed scratches, clearly someone doesn't enjoy being locked up." - starts_with = list(/mob/living/simple_mob/vore/weretiger) \ No newline at end of file + starts_with = list(/mob/living/simple_mob/vore/weretiger) + +/obj/structure/largecrate/tits + name = "A pair of Great tits" + desc = "You can hear two round things inside" + starts_with = list (/mob/living/simple_mob/animal/passive/bird/azure_tit/great, /mob/living/simple_mob/animal/passive/bird/azure_tit/great) diff --git a/code/modules/client/preference_setup/loadout/loadout_accessories_vr.dm b/code/modules/client/preference_setup/loadout/loadout_accessories_vr.dm index 11edb589b3..15519c440d 100644 --- a/code/modules/client/preference_setup/loadout/loadout_accessories_vr.dm +++ b/code/modules/client/preference_setup/loadout/loadout_accessories_vr.dm @@ -133,3 +133,9 @@ Talon pin display_name = "Talon pin" description = "A small enamel pin of the Talon logo." path = /obj/item/clothing/accessory/talon + +//Rat badge + +/datum/gear/accessory/altevian_badge + display_name = "altevian badge" + path = /obj/item/clothing/accessory/altevian_badge \ No newline at end of file diff --git a/code/modules/client/preference_setup/loadout/loadout_eyes_vr.dm b/code/modules/client/preference_setup/loadout/loadout_eyes_vr.dm index 23c3d490e1..e444dcaa85 100644 --- a/code/modules/client/preference_setup/loadout/loadout_eyes_vr.dm +++ b/code/modules/client/preference_setup/loadout/loadout_eyes_vr.dm @@ -66,6 +66,10 @@ display_name = "Security HUDpatch MKII" path = /obj/item/clothing/glasses/hud/security/eyepatch2 +/datum/gear/eyes/security/tac_sec_visor + display_name = "Tactical AR visor (Security)" + path = /obj/item/clothing/glasses/sunglasses/sechud/tactical_sec_vis + /datum/gear/eyes/medical/medpatch display_name = "Health HUDpatch" path = /obj/item/clothing/glasses/hud/health/eyepatch diff --git a/code/modules/client/preference_setup/loadout/loadout_fluffitems_vr.dm b/code/modules/client/preference_setup/loadout/loadout_fluffitems_vr.dm index 560e2ea90e..0baf1d2d19 100644 --- a/code/modules/client/preference_setup/loadout/loadout_fluffitems_vr.dm +++ b/code/modules/client/preference_setup/loadout/loadout_fluffitems_vr.dm @@ -320,6 +320,18 @@ ckeywhitelist = list("chaleur") character_name = list("Hisako Arato") +/datum/gear/fluff/perrin_robes + path = /obj/item/clothing/under/fluff/gildedrobe_perrin + display_name = "Perrin's Robes" + ckeywhitelist = list("codeme") + character_name = list("Perrin Kade") + +/datum/gear/fluff/perrin_shoes + path = /obj/item/clothing/shoes/fluff/gildedshoes_perrin + display_name = "Perrin's Shoes" + ckeywhitelist = list("codeme") + character_name = list("Perrin Kade") + /datum/gear/fluff/jade_stamp path = /obj/item/weapon/stamp/fluff/jade_horror display_name = "Official Council of Mid Horror rubber stamp" @@ -1114,6 +1126,12 @@ ckeywhitelist = list("stiphs") character_name = list("Lilith Vespers") +/datum/gear/fluff/greek_dress + path = /obj/item/clothing/under/fluff/greek_dress + display_name = "mytilenean Dress" + ckeywhitelist = list("sudate") + character_name = list("Shea Corbett") + /datum/gear/fluff/silent_mimemask path = /obj/item/clothing/mask/gas/sexymime display_name = "Silent Stripe's Mime Mask" @@ -1177,6 +1195,13 @@ ckeywhitelist = list("thedavestdave") character_name = list("Roy Tilton") +/datum/gear/fluff/lucky_amour + path = /obj/item/clothing/suit/armor/combat/crusader_costume/lucky + display_name = "Lucky's amour" + ckeywhitelist = list ("thedavestdave") + character_name = list("Lucky") + allowed_roles = list("Chaplain") + /datum/gear/fluff/monty_balaclava path = /obj/item/clothing/mask/balaclava display_name = "Monty's Balaclava" @@ -1438,16 +1463,3 @@ display_name = "Health Service Achievement medal" ckeywhitelist = list("zodiacshadow") character_name = list("Nehi Maximus") - -/datum/gear/fluff/lucky_amour - path = /obj/item/clothing/suit/armor/combat/crusader_costume/lucky - display_name = "Lucky's amour" - ckeywhitelist = list ("thedavestdave") - character_name = list("Lucky") - allowed_roles = "Chaplain" - -/datum/gear/fluff/greek_dress - path = /obj/item/clothing/under/fluff/greek_dress - display_name = "mytilenean Dress" - ckeywhitelist = list("sudate") - character_name = list("Shea Corbett") diff --git a/code/modules/client/preference_setup/loadout/loadout_xeno_vr.dm b/code/modules/client/preference_setup/loadout/loadout_xeno_vr.dm index 51edb25537..e7e4a45a56 100644 --- a/code/modules/client/preference_setup/loadout/loadout_xeno_vr.dm +++ b/code/modules/client/preference_setup/loadout/loadout_xeno_vr.dm @@ -94,6 +94,7 @@ /datum/gear/uniform/altevian_outfit description = "A uniform commonly seen from altevians during their work. The material on this uniform seems to be made of durable thread that can handle the stress of most matters of labor." display_name = "altevian duty jumpsuit selection (Altevian)" + whitelisted = SPECIES_ALTEVIAN sort_category = "Xenowear" /datum/gear/uniform/altevian_outfit/New() @@ -103,6 +104,24 @@ pants[initial(uniform_type.name)] = uniform_type gear_tweaks += new/datum/gear_tweak/path(sortAssoc(pants)) +/datum/gear/accessory/altevian_aquila + description = "An emblem commonly seen worn by the altevians for their work operations." + display_name = "royal altevian navy emblem selection" + whitelisted = SPECIES_ALTEVIAN + sort_category = "Xenowear" + +/datum/gear/accessory/altevian_aquila/New() + ..() + var/list/badges = list( + "gold emblem" = /obj/item/clothing/accessory/altevian_badge/aquila, + "silver emblem" = /obj/item/clothing/accessory/altevian_badge/aquila/silver, + "bronze emblem" = /obj/item/clothing/accessory/altevian_badge/aquila/bronze, + "black emblem" = /obj/item/clothing/accessory/altevian_badge/aquila/black, + "blue emblem" = /obj/item/clothing/accessory/altevian_badge/aquila/exotic, + "purple emblem" = /obj/item/clothing/accessory/altevian_badge/aquila/phoron, + "red emblem" = /obj/item/clothing/accessory/altevian_badge/aquila/hydrogen) + gear_tweaks += new/datum/gear_tweak/path(sortAssoc(badges)) + // Taur stuff /datum/gear/suit/taur/drake_cloak display_name = "drake cloak (Drake-taur)" diff --git a/code/modules/clothing/glasses/glasses_vr.dm b/code/modules/clothing/glasses/glasses_vr.dm index 2a01488a63..5eadbedef5 100644 --- a/code/modules/clothing/glasses/glasses_vr.dm +++ b/code/modules/clothing/glasses/glasses_vr.dm @@ -72,6 +72,45 @@ off_state = "eyepatch" enables_planes = list(VIS_CH_STATUS,VIS_CH_HEALTH,VIS_FULLBRIGHT,VIS_MESONS) +/obj/item/clothing/glasses/sunglasses/sechud/tactical_sec_vis + name = "tactical AR visor" + desc = "Special AR visor designed for security teams, protects your eyes and provides useful data. The red lights provide extra style and intimidation." + icon_state = "tacsecvis1" + icon = 'icons/inventory/eyes/item_vr.dmi' + icon_override = 'icons/inventory/eyes/mob_vr.dmi' + enables_planes = list(VIS_CH_ID,VIS_CH_WANTED,VIS_CH_IMPTRACK,VIS_CH_IMPLOYAL,VIS_CH_IMPCHEM) + flash_protection = FLASH_PROTECTION_MODERATE + item_flags = AIRTIGHT + body_parts_covered = EYES + action_button_name = "Change scanning pattern" + action_button_is_hands_free = TRUE + var/static/list/tac_sec_vis_anim = list() + +/obj/item/clothing/glasses/sunglasses/sechud/tactical_sec_vis/Initialize(mapload) + . = ..() + tac_sec_vis_anim = list( + "Scanning pattern 1" = image(icon = src.icon, icon_state = "tacsecvis1"), + "Scanning pattern 2" = image(icon = src.icon, icon_state = "tacsecvis2"), + "Scanning pattern 3" = image(icon = src.icon, icon_state = "tacsecvis3"), + "Scanning pattern 4" = image(icon = src.icon, icon_state = "tacsecvis4"), + ) + +/obj/item/clothing/glasses/sunglasses/sechud/tactical_sec_vis/attack_self(mob/user) + . = ..() + if(!istype(user) || user.incapacitated()) + return + + var/static/list/options = list("Scanning pattern 1" = "tacsecvis1", "Scanning pattern 2" = "tacsecvis2", "Scanning pattern 3" = "tacsecvis3","Scanning pattern 4" ="tacsecvis4") + + var/choice = show_radial_menu(user, src, tac_sec_vis_anim, custom_check = FALSE, radius = 36, require_near = TRUE) + + if(src && choice && !user.incapacitated() && in_range(user,src)) + icon_state = options[choice] + user.update_inv_glasses() + user.update_action_buttons() + to_chat(user, "Your [src] now displays [choice] .") + return 1 + /*---Tajaran-specific Eyewear---*/ /obj/item/clothing/glasses/tajblind diff --git a/code/modules/clothing/under/accessories/altevian_vr.dm b/code/modules/clothing/under/accessories/altevian_vr.dm index ec3322d185..b75757b94a 100644 --- a/code/modules/clothing/under/accessories/altevian_vr.dm +++ b/code/modules/clothing/under/accessories/altevian_vr.dm @@ -75,4 +75,35 @@ name = "Purple Comfortable Scarf" icon_state = "altevian-scarf-purple" item_state = "altevian-scarf-purple" - overlay_state = "altevian-scarf-purple" \ No newline at end of file + overlay_state = "altevian-scarf-purple" + + + +/obj/item/clothing/accessory/altevian_badge + name = "Altevian Civilian Badge" + desc = "An emblem commonly seen worn by the altevians off-work or by visitors of their ships." + icon_state = "altevian_badge" + slot = ACCESSORY_SLOT_MEDAL + +/obj/item/clothing/accessory/altevian_badge/aquila + name = "Royal Altevian Navy Emblem" + desc = "An emblem commonly seen worn by the altevians for their work operations." + icon_state = "altevian_aquila" + +/obj/item/clothing/accessory/altevian_badge/aquila/silver + icon_state = "altevian_aquila_silver" + +/obj/item/clothing/accessory/altevian_badge/aquila/bronze + icon_state = "altevian_aquila_bronze" + +/obj/item/clothing/accessory/altevian_badge/aquila/black + icon_state = "altevian_aquila_black" + +/obj/item/clothing/accessory/altevian_badge/aquila/exotic + icon_state = "altevian_aquila_exotic" + +/obj/item/clothing/accessory/altevian_badge/aquila/phoron + icon_state = "altevian_aquila_phoron" + +/obj/item/clothing/accessory/altevian_badge/aquila/hydrogen + icon_state = "altevian_aquila_hydrogen" \ No newline at end of file diff --git a/code/modules/economy/vending_machines.dm b/code/modules/economy/vending_machines.dm index 2d152ff76d..e0c7511f0f 100644 --- a/code/modules/economy/vending_machines.dm +++ b/code/modules/economy/vending_machines.dm @@ -1237,6 +1237,7 @@ /obj/item/clothing/mask/bandana/red = 5, /obj/item/clothing/suit/storage/hooded/wintercoat/security = 5, /obj/item/clothing/accessory/armband = 5, + /obj/item/clothing/glasses/sunglasses/sechud/tactical_sec_vis = 5, //VoreStation edit - cool visor!!! /obj/item/clothing/glasses/hud/security/eyepatch2 = 5, //VoreStation edit - cool eyepatch! /obj/item/clothing/accessory/holster/armpit = 2, //VOREStation edit - gives some variety of available holsters for those who forgot to bring their own /obj/item/clothing/accessory/holster/waist = 2, //VOREStation edit - But also reduces the number per type, so there's 8 overall rather than like, 20 diff --git a/code/modules/emotes/emote_mob.dm b/code/modules/emotes/emote_mob.dm index e7611b8480..d28418c214 100644 --- a/code/modules/emotes/emote_mob.dm +++ b/code/modules/emotes/emote_mob.dm @@ -128,6 +128,7 @@ if(findtext(subtext, "*")) // abort abort! to_chat(emoter, SPAN_WARNING("You may use only one \"["*"]\" symbol in your emote.")) + to_chat(emoter, SPAN_WARNING(message)) return if(pretext) diff --git a/code/modules/food/food/snacks.dm b/code/modules/food/food/snacks.dm index a58c6bf82a..dc81b52097 100644 --- a/code/modules/food/food/snacks.dm +++ b/code/modules/food/food/snacks.dm @@ -1884,7 +1884,6 @@ . = ..() reagents.add_reagent("protein", 3) - /obj/item/weapon/reagent_containers/food/snacks/rofflewaffles name = "Roffle Waffles" desc = "Waffles from Roffle. Co." @@ -2141,6 +2140,15 @@ . = ..() reagents.add_reagent("protein", 3) +/obj/item/weapon/reagent_containers/food/snacks/clubsandwich + name = "Club Sandwich" + desc = "Tastes like the good feelings when you're part of a clique." + icon_state = "clubsandwich" + trash = "obj/item/trash/plate" + nutriment_amt = 3 + nutriment_desc = list("a galactic economy coming together in pursuit of mundane foods" = 3) + bitesize = 2 + /obj/item/weapon/reagent_containers/food/snacks/toastedsandwich name = "Toasted Sandwich" desc = "Now if you only had a pepper bar." diff --git a/code/modules/food/recipes_microwave.dm b/code/modules/food/recipes_microwave.dm index 1f470c81bb..7993260ee0 100644 --- a/code/modules/food/recipes_microwave.dm +++ b/code/modules/food/recipes_microwave.dm @@ -236,6 +236,17 @@ I said no! ) result = /obj/item/weapon/reagent_containers/food/snacks/jellysandwich/peanutbutter +/datum/recipe/clubsandwich + reagents = list("mayo" = 5) + items = list( + /obj/item/weapon/reagent_containers/food/snacks/slice/bread, + /obj/item/weapon/reagent_containers/food/snacks/slice/bread, + /obj/item/weapon/reagent_containers/food/snacks/meat/chicken, + /obj/item/weapon/reagent_containers/food/snacks/bacon, + /obj/item/weapon/reagent_containers/food/snacks/cheesewedge + ) + fruit = list("tomato" = 1, "lettuce" = 1) + result = /obj/item/weapon/reagent_containers/food/snacks/clubsandwich /datum/recipe/tomatosoup fruit = list("tomato" = 2) diff --git a/code/modules/hydroponics/seed_packets.dm b/code/modules/hydroponics/seed_packets.dm index 4a08f897da..1574365617 100644 --- a/code/modules/hydroponics/seed_packets.dm +++ b/code/modules/hydroponics/seed_packets.dm @@ -118,6 +118,9 @@ GLOBAL_LIST_BOILERPLATE(all_seed_packs, /obj/item/seeds) /obj/item/seeds/glowberryseed seed_type = "glowberries" +/obj/item/seeds/peppercornseed + seed_type = "peppercorns" + /obj/item/seeds/bananaseed seed_type = "banana" diff --git a/code/modules/hydroponics/seed_storage_vr.dm b/code/modules/hydroponics/seed_storage_vr.dm index b09b0063c1..9de8cf53a1 100644 --- a/code/modules/hydroponics/seed_storage_vr.dm +++ b/code/modules/hydroponics/seed_storage_vr.dm @@ -24,6 +24,7 @@ /obj/item/seeds/orangeseed = 3, /obj/item/seeds/onionseed = 3, /obj/item/seeds/peanutseed = 3, + /obj/item/seeds/peppercornseed = 2, /obj/item/seeds/plumpmycelium = 3, /obj/item/seeds/poppyseed = 3, /obj/item/seeds/potatoseed = 3, @@ -80,6 +81,7 @@ /obj/item/seeds/nettleseed = 2, /obj/item/seeds/orangeseed = 3, /obj/item/seeds/peanutseed = 3, + /obj/item/seeds/peppercornseed = 2, /obj/item/seeds/plastiseed = 3, /obj/item/seeds/plumpmycelium = 3, /obj/item/seeds/poppyseed = 3, diff --git a/code/modules/hydroponics/seedtypes/berries.dm b/code/modules/hydroponics/seedtypes/berries.dm index 2ad36353fe..3654a62cb3 100644 --- a/code/modules/hydroponics/seedtypes/berries.dm +++ b/code/modules/hydroponics/seedtypes/berries.dm @@ -67,4 +67,16 @@ set_trait(TRAIT_YIELD,3) set_trait(TRAIT_POTENCY,50) set_trait(TRAIT_PRODUCT_COLOUR,"#7A5454") - set_trait(TRAIT_NUTRIENT_CONSUMPTION, 0.35) \ No newline at end of file + set_trait(TRAIT_NUTRIENT_CONSUMPTION, 0.35) + +/datum/seed/berry/peppercorn + name = "peppercorns" + seed_name = "peppercorn berry" + kitchen_tag = "peppercorns" + display_name = "peppercorn bush" + chems = list("blackpepper" = list(5,10)) + +/datum/seed/berry/peppercorn/New() + ..() + set_trait(TRAIT_PRODUCT_COLOUR,"#303030") + set_trait(TRAIT_WATER_CONSUMPTION, 2) \ No newline at end of file diff --git a/code/modules/instruments/songs/play_legacy.dm b/code/modules/instruments/songs/play_legacy.dm index 9d7ba493d4..bd964765cb 100644 --- a/code/modules/instruments/songs/play_legacy.dm +++ b/code/modules/instruments/songs/play_legacy.dm @@ -86,5 +86,8 @@ var/mob/living/L = M L.apply_status_effect(STATUS_EFFECT_GOOD_MUSIC) */ + if(!M) + hearing_mobs -= M + continue M.playsound_local(source, null, volume * using_instrument.volume_multiplier, S = music_played, preference = /datum/client_preference/instrument_toggle, volume_channel = VOLUME_CHANNEL_INSTRUMENTS) // Could do environment and echo later but not for now diff --git a/code/modules/mob/dead/observer/observer.dm b/code/modules/mob/dead/observer/observer.dm index ec5b3f2d75..33b618edf0 100644 --- a/code/modules/mob/dead/observer/observer.dm +++ b/code/modules/mob/dead/observer/observer.dm @@ -455,7 +455,7 @@ This is the proc mobs get to turn into a ghost. Forked from ghostize due to comp to_chat(usr, "You cannot follow a mob standing on holy grounds!") return if(get_z(target) in using_map?.secret_levels) - to_chat(src, SPAN_WARNING("Sorry, that target is in an area that ghosts aren't allowed to go.")) + to_chat(src, "Sorry, that target is in an area that ghosts aren't allowed to go.") return if(target != src) if(following && following == target) @@ -463,7 +463,11 @@ This is the proc mobs get to turn into a ghost. Forked from ghostize due to comp following = target to_chat(src, "Now following [target]") if(ismob(target)) - forceMove(get_turf(target)) + var/target_turf = get_turf(target) + if(!target_turf) + to_chat(usr, "This mob does not seem to exist in the tangible world.") + return + forceMove(target_turf) var/mob/M = target M.following_mobs += src else diff --git a/code/modules/mob/living/carbon/human/human.dm b/code/modules/mob/living/carbon/human/human.dm index 1d4e67f509..b716183134 100644 --- a/code/modules/mob/living/carbon/human/human.dm +++ b/code/modules/mob/living/carbon/human/human.dm @@ -863,7 +863,7 @@ if(VISIBLE_GENDER_FORCE_BIOLOGICAL) return gender else - if((wear_mask || (head?.flags_inv & HIDEMASK)) && (wear_suit?.flags_inv & HIDEJUMPSUIT)) + if(((wear_mask?.flags_inv & HIDEFACE) || (head?.flags_inv & HIDEMASK) || (head?.flags_inv & HIDEFACE)) && (wear_suit?.flags_inv & HIDEJUMPSUIT)) return PLURAL if(species?.ambiguous_genders && user) if(ishuman(user)) diff --git a/code/modules/mob/living/carbon/human/human_defense.dm b/code/modules/mob/living/carbon/human/human_defense.dm index 6a60ec0448..f5dd0d3aca 100644 --- a/code/modules/mob/living/carbon/human/human_defense.dm +++ b/code/modules/mob/living/carbon/human/human_defense.dm @@ -402,7 +402,7 @@ emp_act return // PERSON BEING HIT: CAN BE DROP PRED, ALLOWS THROW VORE. // PERSON BEING THROWN: DEVOURABLE, ALLOWS THROW VORE, CAN BE DROP PREY. - if((can_be_drop_pred && throw_vore) && (thrown_mob.devourable && thrown_mob.throw_vore && thrown_mob.can_be_drop_prey)) //Prey thrown into pred. + if((can_be_drop_pred && throw_vore && vore_selected) && (thrown_mob.devourable && thrown_mob.throw_vore && thrown_mob.can_be_drop_prey)) //Prey thrown into pred. vore_selected.nom_mob(thrown_mob) //Eat them!!! visible_message("[thrown_mob] is thrown right into [src]'s [lowertext(vore_selected.name)]!") if(thrown_mob.loc != vore_selected) @@ -412,7 +412,7 @@ emp_act // PERSON BEING HIT: CAN BE DROP PREY, ALLOWS THROW VORE, AND IS DEVOURABLE. // PERSON BEING THROWN: CAN BE DROP PRED, ALLOWS THROW VORE. - else if((can_be_drop_prey && throw_vore && devourable) && (thrown_mob.can_be_drop_pred && thrown_mob.throw_vore)) //Pred thrown into prey. + else if((can_be_drop_prey && throw_vore && devourable) && (thrown_mob.can_be_drop_pred && thrown_mob.throw_vore && thrown_mob.vore_selected)) //Pred thrown into prey. visible_message("[src] suddenly slips inside of [thrown_mob]'s [lowertext(thrown_mob.vore_selected.name)] as [thrown_mob] flies into them!") thrown_mob.vore_selected.nom_mob(src) //Eat them!!! if(src.loc != thrown_mob.vore_selected) diff --git a/code/modules/mob/living/carbon/human/species/station/station_special_abilities_vr.dm b/code/modules/mob/living/carbon/human/species/station/station_special_abilities_vr.dm index da3d92fda8..f743dfd432 100644 --- a/code/modules/mob/living/carbon/human/species/station/station_special_abilities_vr.dm +++ b/code/modules/mob/living/carbon/human/species/station/station_special_abilities_vr.dm @@ -97,10 +97,10 @@ if (getBruteLoss() || getFireLoss() || getHalLoss() || getToxLoss() || getOxyLoss() || getBrainLoss()) //fails if they have any of the main damage types return FALSE for (var/obj/item/organ/O in organs) //check their organs just in case they're being sneaky and somehow have organ damage but no health damage - if (O.damage) + if (O.is_damaged() || O.status) return FALSE for (var/obj/item/organ/O in internal_organs) //check their organs just in case they're being sneaky and somehow have organ damage but no health damage - if (O.damage) + if (O.is_damaged() || O.status) return FALSE return TRUE diff --git a/code/modules/mob/living/carbon/human/species/station/xenochimera_trait_vr.dm b/code/modules/mob/living/carbon/human/species/station/xenochimera_trait_vr.dm index b85f1627ff..8fbffbd7eb 100644 --- a/code/modules/mob/living/carbon/human/species/station/xenochimera_trait_vr.dm +++ b/code/modules/mob/living/carbon/human/species/station/xenochimera_trait_vr.dm @@ -64,6 +64,8 @@ custom_only = FALSE /datum/trait/positive/winged_flight/xenochimera + sort = TRAIT_SORT_SPECIES + allowed_species = list(SPECIES_XENOCHIMERA) name = "Xenochhimera: Winged Flight" desc = "Allows you to fly by using your wings. Don't forget to bring them!" cost = 0 diff --git a/code/modules/mob/living/silicon/robot/robot_modules/station_vr.dm b/code/modules/mob/living/silicon/robot/robot_modules/station_vr.dm index 5a089818e7..d14cba2694 100644 --- a/code/modules/mob/living/silicon/robot/robot_modules/station_vr.dm +++ b/code/modules/mob/living/silicon/robot/robot_modules/station_vr.dm @@ -77,6 +77,7 @@ "Acheron" = "mechoid-Medical", "Shellguard Noble" = "Noble-MED", "ZOOM-BA" = "zoomba-medical", + "W02M" = "worm-surgeon", "Feminine Humanoid" = "uptall-medical" ) @@ -87,6 +88,7 @@ "Acheron" = "mechoid-Medical", "Shellguard Noble" = "Noble-MED", "ZOOM-BA" = "zoomba-crisis", + "W02M" = "worm-crisis", "Feminine Humanoid" = "uptall-crisis" ) @@ -98,6 +100,7 @@ "Acheron" = "mechoid-Service", "Shellguard Noble" = "Noble-SRV", "ZOOM-BA" = "zoomba-service", + "W02M" = "worm-service", "Feminine Humanoid" = "uptall-service" ) @@ -108,6 +111,7 @@ "Acheron" = "mechoid-Service", "Shellguard Noble" = "Noble-SRV", "ZOOM-BA" = "zoomba-clerical", + "W02M" = "worm-service", "Feminine Humanoid" = "uptall-service" ) @@ -118,6 +122,7 @@ "Acheron" = "mechoid-Janitor", "Shellguard Noble" = "Noble-CLN", "ZOOM-BA" = "zoomba-janitor", + "W02M" = "worm-janitor", "Feminine Humanoid" = "uptall-janitor" ) @@ -128,6 +133,7 @@ "Acheron" = "mechoid-Security", "Shellguard Noble" = "Noble-SEC", "ZOOM-BA" = "zoomba-security", + "W02M" = "worm-security", "Feminine Humanoid" = "uptall-security" ) @@ -138,6 +144,7 @@ "Acheron" = "mechoid-Miner", "Shellguard Noble" = "Noble-DIG", "ZOOM-BA" = "zoomba-miner", + "W02M" = "worm-miner", "Feminine Humanoid" = "uptall-miner" ) @@ -148,6 +155,7 @@ "Acheron" = "mechoid-Standard", "Shellguard Noble" = "Noble-STD", "ZOOM-BA" = "zoomba-standard", + "W02M" = "worm-standard", "Feminine Humanoid" = "uptall-standard", "Feminine Humanoid, Variant 2" = "uptall-standard2" ) @@ -157,6 +165,7 @@ "Acheron" = "mechoid-Engineering", "Shellguard Noble" = "Noble-ENG", "ZOOM-BA" = "zoomba-engineering", + "W02M" = "worm-engineering", "Feminine Humanoid" = "uptall-engineering" ) @@ -166,6 +175,7 @@ "Acheron" = "mechoid-Science", "ZOOM-BA" = "zoomba-research", "XI-GUS" = "spiderscience", + "W02M" = "worm-janitor", "Feminine Humanoid" = "uptall-science" ) @@ -174,6 +184,7 @@ vr_sprites = list( "Acheron" = "mechoid-Combat", "ZOOM-BA" = "zoomba-combat", + "W02M" = "worm-combat", "Feminine Humanoid" = "uptall-security" ) diff --git a/code/modules/mob/living/silicon/robot/robot_vr.dm b/code/modules/mob/living/silicon/robot/robot_vr.dm index bcd6a9114b..19865a89a6 100644 --- a/code/modules/mob/living/silicon/robot/robot_vr.dm +++ b/code/modules/mob/living/silicon/robot/robot_vr.dm @@ -65,7 +65,16 @@ "uptall-engineering", "uptall-miner", "uptall-security", - "uptall-science" + "uptall-science", + "worm-standard", + "worm-engineering", + "worm-janitor", + "worm-crisis", + "worm-miner", + "worm-security", + "worm-combat", + "worm-surgeon", + "worm-service" ) //List of all used sprites that are in robots_vr.dmi diff --git a/code/modules/mob/living/simple_mob/simple_mob_vr.dm b/code/modules/mob/living/simple_mob/simple_mob_vr.dm index da2017b34c..1f6db8ab00 100644 --- a/code/modules/mob/living/simple_mob/simple_mob_vr.dm +++ b/code/modules/mob/living/simple_mob/simple_mob_vr.dm @@ -57,8 +57,7 @@ // Release belly contents before being gc'd! /mob/living/simple_mob/Destroy() release_vore_contents() - if(prey_excludes) - prey_excludes.Cut() + LAZYCLEARLIST(prey_excludes) return ..() //For all those ID-having mobs @@ -113,7 +112,7 @@ if(!M.allowmobvore || !M.devourable) // Don't eat people who don't want to be ate by mobs //ai_log("vr/wont eat [M] because they don't allow mob vore", 3) //VORESTATION AI TEMPORARY REMOVAL return 0 - if(M in prey_excludes) // They're excluded + if(LAZYFIND(prey_excludes, M)) // They're excluded //ai_log("vr/wont eat [M] because they are excluded", 3) //VORESTATION AI TEMPORARY REMOVAL return 0 if(M.size_multiplier < vore_min_size || M.size_multiplier > vore_max_size) @@ -258,6 +257,7 @@ "The churning walls slowly pulverize you into meaty nutrients.", "The stomach glorps and gurgles as it tries to work you into slop.") can_be_drop_pred = TRUE // Mobs will eat anyone that decides to drop/slip into them by default. + B.belly_fullscreen = "yet_another_tumby" /mob/living/simple_mob/Bumped(var/atom/movable/AM, yes) if(tryBumpNom(AM)) diff --git a/code/modules/mob/living/simple_mob/subtypes/animal/pets/bird_vr.dm b/code/modules/mob/living/simple_mob/subtypes/animal/pets/bird_vr.dm index 1640d2ddea..0b0f55351a 100644 --- a/code/modules/mob/living/simple_mob/subtypes/animal/pets/bird_vr.dm +++ b/code/modules/mob/living/simple_mob/subtypes/animal/pets/bird_vr.dm @@ -1,4 +1,9 @@ /mob/living/simple_mob/animal/passive/bird/azure_tit/tweeter name = "Tweeter" desc = "A beautiful little blue and white bird, if only excessively loud for no reason sometimes." - makes_dirt = FALSE \ No newline at end of file + makes_dirt = FALSE + +/mob/living/simple_mob/animal/passive/bird/azure_tit/great + name = "Great Tit" + desc = "A species of bird, colored blue and white. Isn't it great?" + size_multiplier = 2 diff --git a/code/modules/mob/living/simple_mob/subtypes/vore/pakkun.dm b/code/modules/mob/living/simple_mob/subtypes/vore/pakkun.dm index 2972d33b18..baa9dd42bb 100644 --- a/code/modules/mob/living/simple_mob/subtypes/vore/pakkun.dm +++ b/code/modules/mob/living/simple_mob/subtypes/vore/pakkun.dm @@ -61,7 +61,7 @@ if(autorest_cooldown) autorest_cooldown -- - else if(prob(5) && ai_holder.stance == STANCE_IDLE) + else if(prob(5) && (resting || ai_holder.stance == STANCE_IDLE)) autorest_cooldown = rand(50,200) lay_down() @@ -109,7 +109,7 @@ continue if(istype(holder, /mob/living/simple_mob)) var/mob/living/simple_mob/SM = holder - our_targets -= SM.prey_excludes + our_targets -= SM.prey_excludes // Lazylist, but subtracting a null from the list seems fine. return our_targets /datum/ai_holder/simple_mob/ranged/pakkun/can_attack(atom/movable/the_target, var/vision_required = TRUE) @@ -120,14 +120,14 @@ return FALSE if(istype(holder, /mob/living/simple_mob)) var/mob/living/simple_mob/SM = holder - if(L in SM.prey_excludes) + if(LAZYFIND(SM.prey_excludes, L)) return FALSE else return FALSE /mob/living/simple_mob/vore/pakkun/on_throw_vore_special(var/pred, var/mob/living/target) - if(pred && !extra_posessive) - prey_excludes += target + if(pred && !extra_posessive && !(LAZYFIND(prey_excludes, target))) + LAZYSET(prey_excludes, target, world.time) addtimer(CALLBACK(src, .proc/removeMobFromPreyExcludes, weakref(target)), 5 MINUTES) if(ai_holder) ai_holder.remove_target() @@ -151,8 +151,8 @@ user.visible_message("[user] swats [src] with [O]!") release_vore_contents() for(var/mob/living/L in living_mobs(0)) - if(!(L in prey_excludes)) - prey_excludes += L + if(!(LAZYFIND(prey_excludes, L))) + LAZYSET(prey_excludes, L, world.time) addtimer(CALLBACK(src, .proc/removeMobFromPreyExcludes, weakref(L)), 5 MINUTES) else ..() @@ -184,6 +184,8 @@ icon_living = "snappy" icon_state = "snappy" icon_rest = "snappy-rest" + digestable = 0 // pet mob, do not eat + devourable = 0 ai_holder_type = /datum/ai_holder/simple_mob/ranged/pakkun/snappy vore_default_mode = DM_HOLD @@ -211,6 +213,11 @@ petters += M //YOU HAVE OFFERED YOURSELF TO THE LIZARD return ..() +/mob/living/simple_mob/vore/pakkun/snapdragon/snappy/lay_down() + if(LAZYLEN(petters) && prob(50) && !resting) //50% chance she'll forgive a random person when she takes a nap + petters -= pick(petters) + ..() + /mob/living/simple_mob/vore/pakkun/snapdragon/snappy/init_vore() ..() var/obj/belly/B = vore_selected diff --git a/code/modules/mob/living/simple_mob/subtypes/vore/zz_vore_overrides.dm b/code/modules/mob/living/simple_mob/subtypes/vore/zz_vore_overrides.dm index 5744f8cccb..fbc3830ca4 100644 --- a/code/modules/mob/living/simple_mob/subtypes/vore/zz_vore_overrides.dm +++ b/code/modules/mob/living/simple_mob/subtypes/vore/zz_vore_overrides.dm @@ -188,10 +188,10 @@ /* //VOREStation AI Temporary Removal /mob/living/simple_mob/animal/passive/cat/fluff/EatTarget() var/mob/living/TM = target_mob - prey_excludes += TM //so they won't immediately re-eat someone who struggles out (or gets newspapered out) as soon as they're ate + LAZYSET(prey_excludes, TM, world.time) //so they won't immediately re-eat someone who struggles out (or gets newspapered out) as soon as they're ate spawn(3600) // but if they hang around and get comfortable, they might get ate again if(src && TM) - prey_excludes -= TM + LAZYREMOVE(prey_excludes, TM) ..() // will_eat check is carried out before EatTarget is called, so prey on the prey_excludes list isn't a problem. */ @@ -246,4 +246,4 @@ B.digest_mode = safe ? DM_HOLD : vore_default_mode /mob/living/simple_mob/animal/passive/mouse - faction = "mouse" //Giving mice a faction so certain mobs can get along with them. \ No newline at end of file + faction = "mouse" //Giving mice a faction so certain mobs can get along with them. diff --git a/code/modules/mob/new_player/sprite_accessories.dm b/code/modules/mob/new_player/sprite_accessories.dm index 510ce77a26..434bfa2e3c 100644 --- a/code/modules/mob/new_player/sprite_accessories.dm +++ b/code/modules/mob/new_player/sprite_accessories.dm @@ -1708,22 +1708,49 @@ shaved //Skrell 'hairstyles' /datum/sprite_accessory/hair/skr - name = "Skrell Average Tentacles" - icon_state = "skrell_hair_average" + name = "Tentacles, Average" + icon_state = "skrell_short" species_allowed = list(SPECIES_SKRELL, SPECIES_EVENT1, SPECIES_EVENT2, SPECIES_EVENT3) -/datum/sprite_accessory/hair/skr/tentacle_veryshort - name = "Skrell Short Tentacles" - icon_state = "skrell_hair_short" - gender = MALE +/datum/sprite_accessory/hair/skr/pullback + name = "Tentacles, Average, Pullback" + icon_state = "skrell_short_pullback" -/datum/sprite_accessory/hair/skr/tentacle_average - name = "Skrell Long Tentacles" - icon_state = "skrell_hair_long" +/datum/sprite_accessory/hair/skr/very_short + name = "Tentacles, Short" + icon_state = "skrell_very_short" -/datum/sprite_accessory/hair/skr/tentacle_verylong - name = "Skrell Very Long Tentacles" - icon_state = "skrell_hair_verylong" +/datum/sprite_accessory/hair/skr/long + name = "Tentacles, Long" + icon_state = "skrell_long" + +/datum/sprite_accessory/hair/skr/long/pullback + name = "Tentacles, Long, Pullback" + icon_state = "skrell_long_pullback" + +/datum/sprite_accessory/hair/skr/long/scarf + name = "Tentacles, Long, Scarf" + icon_state = "skrell_long_scarf" + +/datum/sprite_accessory/hair/skr/long/wavy + name = "Tentacles, Long, Wavy" + icon_state = "skrell_long_wavy" + +/datum/sprite_accessory/hair/skr/very_long + name = "Tentacles, Very Long" + icon_state = "skrell_very_long" + +/datum/sprite_accessory/hair/skr/very_long/pullback + name = "Tentacles, Very Long, Pullback" + icon_state = "skrell_very_long_pullback" + +/datum/sprite_accessory/hair/skr/very_long/scarf + name = "Tentacles, Very Long, Scarf" + icon_state = "skrell_very_long_scarf" + +/datum/sprite_accessory/hair/skr/very_long/wavy + name = "Tentacles, Very Long, Wavy" + icon_state = "skrell_very_long_wavy" //Tajaran hairstyles /datum/sprite_accessory/hair/taj diff --git a/code/modules/mob/new_player/sprite_accessories_extra_vr.dm b/code/modules/mob/new_player/sprite_accessories_extra_vr.dm index aa01f6c465..c73d6e354e 100644 --- a/code/modules/mob/new_player/sprite_accessories_extra_vr.dm +++ b/code/modules/mob/new_player/sprite_accessories_extra_vr.dm @@ -885,4 +885,32 @@ icon = 'icons/mob/human_races/markings_vr.dmi' icon_state = "altevian-incisors" color_blend_mode = ICON_MULTIPLY - body_parts = list(BP_HEAD) \ No newline at end of file + body_parts = list(BP_HEAD) + +/datum/sprite_accessory/marking/vr_eldritch_markings + name = "Eldritch Markings" + icon = 'icons/mob/human_races/markings_vr.dmi' + icon_state = "perrinmarkings" + color_blend_mode = ICON_MULTIPLY + body_parts = list(BP_HEAD,BP_L_ARM,BP_L_HAND,BP_R_ARM,BP_R_HAND,BP_L_LEG,BP_L_FOOT,BP_R_LEG,BP_R_FOOT) + +/datum/sprite_accessory/marking/vr_tesh_beak + name = "Teshari beak, pointed" + icon = 'icons/mob/human_races/markings_vr.dmi' + icon_state = "tesh-beak" + color_blend_mode = ICON_MULTIPLY + body_parts = list(BP_HEAD) + +/datum/sprite_accessory/marking/vr_tesh_beak_alt + name = "Teshari beak, rounded" + icon = 'icons/mob/human_races/markings_vr.dmi' + icon_state = "tesh-beak-alt" + color_blend_mode = ICON_MULTIPLY + body_parts = list(BP_HEAD) + +/datum/sprite_accessory/marking/vr_crab_claws + name = "Crab claws" + icon = 'icons/mob/human_races/markings_vr.dmi' + icon_state = "crabclaws" + color_blend_mode = ICON_MULTIPLY + body_parts = list(BP_L_HAND,BP_R_HAND) diff --git a/code/modules/mob/new_player/sprite_accessories_tail_vr.dm b/code/modules/mob/new_player/sprite_accessories_tail_vr.dm index ec8b9c273d..bf8104862f 100644 --- a/code/modules/mob/new_player/sprite_accessories_tail_vr.dm +++ b/code/modules/mob/new_player/sprite_accessories_tail_vr.dm @@ -1201,6 +1201,12 @@ do_colouration = 1 color_blend_mode = ICON_MULTIPLY +/datum/sprite_accessory/tail/perrin_tentacles + name = "octopus tentacles (Perrin Kade)" + desc = "" + icon_state = "perrintentacles" + ckeys_allowed = list("codeme") + //LONG TAILS ARE NOT TAUR BUTTS >:O /datum/sprite_accessory/tail/longtail name = "You should not see this..." diff --git a/code/modules/mob/new_player/sprite_accessories_wing.dm b/code/modules/mob/new_player/sprite_accessories_wing.dm index ded7a70937..3b13156b9d 100644 --- a/code/modules/mob/new_player/sprite_accessories_wing.dm +++ b/code/modules/mob/new_player/sprite_accessories_wing.dm @@ -151,3 +151,10 @@ desc = "" icon_state = "cyberdoe_s" do_colouration = 0 + +/datum/sprite_accessory/wing/mantisarms + name = "Mantis arms" + desc = "" + icon_state = "mantisarms_s" + do_colouration = 1 + color_blend_mode = ICON_MULTIPLY diff --git a/code/modules/mob/new_player/sprite_accessories_wing_vr.dm b/code/modules/mob/new_player/sprite_accessories_wing_vr.dm index fc04d43a42..37080444ea 100644 --- a/code/modules/mob/new_player/sprite_accessories_wing_vr.dm +++ b/code/modules/mob/new_player/sprite_accessories_wing_vr.dm @@ -129,6 +129,45 @@ extra_overlay = "harpywings_batmarkings" extra_overlay2 = "neckfur" +/datum/sprite_accessory/wing/harpyarmwings + name = "harpy arm wings, colorable" + desc = "" + icon_state = "harpyarmwings" + do_colouration = 1 + color_blend_mode = ICON_MULTIPLY + +/datum/sprite_accessory/wing/harpyarmwings_alt + name = "harpy arm wings alt, colorable" + desc = "" + icon_state = "harpyarmwings_alt" + do_colouration = 1 + color_blend_mode = ICON_MULTIPLY + +/datum/sprite_accessory/wing/harpyarmwings_alt_neckfur + name = "harpy arm wings alt & neckfur" + desc = "" + icon_state = "harpyarmwings_alt" + do_colouration = 1 + color_blend_mode = ICON_MULTIPLY + extra_overlay = "neckfur" + +/datum/sprite_accessory/wing/harpyarmwings_bat + name = "harpy arm wings, bat" + desc = "" + icon_state = "harpyarmwings_bat" + do_colouration = 1 + color_blend_mode = ICON_MULTIPLY + extra_overlay = "harpyarmwings_batmarkings" + +/datum/sprite_accessory/wing/harpyarmwings_bat_neckfur + name = "harpy arm wings, bat & neckfur" + desc = "" + icon_state = "harpyarmwings_bat" + do_colouration = 1 + color_blend_mode = ICON_MULTIPLY + extra_overlay = "harpyarmwings_batmarkings" + extra_overlay2 = "neckfur" + /datum/sprite_accessory/wing/neckfur name = "neck fur" desc = "" diff --git a/code/modules/mob/say_vr.dm b/code/modules/mob/say_vr.dm index d8ed1c311e..7bfe1b201b 100644 --- a/code/modules/mob/say_vr.dm +++ b/code/modules/mob/say_vr.dm @@ -306,3 +306,49 @@ else //There wasn't anyone to send the message to, pred or prey, so let's just emote it instead and correct our psay just in case. M.forced_psay = FALSE M.me_verb(message) + +/mob/living/verb/player_narrate(message as text|null) + set category = "IC" + set name = "Narrate (Player)" + set desc = "Narrate an action or event! An alternative to emoting, for when your emote shouldn't start with your name!" + + if(src.client) + if(client.prefs.muted & MUTE_IC) + to_chat(src, "You cannot speak in IC (muted).") + return + if(!message) + message = tgui_input_text(usr, "Type a message to narrate.","Narrate") + message = sanitize_or_reflect(message,src) + if(!message) + return + if(stat == DEAD) + return say_dead(message) + if(stat) + to_chat(src, "You need to be concious to narrate: [message]") + return + message = "([name]) [message]" + + //Below here stolen from emotes + var/turf/T = get_turf(src) + + if(!T) return + + var/ourfreq = null + if(voice_freq > 0 ) + ourfreq = voice_freq + + if(client) + playsound(T, pick(emote_sound), 25, TRUE, falloff = 1 , is_global = TRUE, frequency = ourfreq, ignore_walls = FALSE, preference = /datum/client_preference/emote_sounds) + + var/list/in_range = get_mobs_and_objs_in_view_fast(T,world.view,2,remote_ghosts = client ? TRUE : FALSE) + var/list/m_viewers = in_range["mobs"] + + for(var/mob/M as anything in m_viewers) + spawn(0) // It's possible that it could be deleted in the meantime, or that it runtimes. + if(M) + if(isobserver(M)) + message = "[message] ([ghost_follow_link(src, M)])" + if(M.stat == UNCONSCIOUS || M.sleeping > 0) + continue + to_chat(M, message) + log_emote(message, src) diff --git a/code/modules/recycling/disposal.dm b/code/modules/recycling/disposal.dm index 662295e578..a5e95899f5 100644 --- a/code/modules/recycling/disposal.dm +++ b/code/modules/recycling/disposal.dm @@ -1539,6 +1539,12 @@ if(trunk) trunk.linked = src // link the pipe trunk to self +/obj/structure/disposaloutlet/Destroy() + var/obj/structure/disposalpipe/trunk/trunk = locate() in loc + if(trunk && trunk.linked == src) + trunk.linked = null + return ..() + // expel the contents of the holder object, then delete it // called when the holder exits the outlet /obj/structure/disposaloutlet/proc/expel(var/obj/structure/disposalholder/H) diff --git a/code/modules/research/mechfab_designs.dm b/code/modules/research/mechfab_designs.dm index 2480bda5c6..834ba13efb 100644 --- a/code/modules/research/mechfab_designs.dm +++ b/code/modules/research/mechfab_designs.dm @@ -804,13 +804,21 @@ build_path = /obj/item/weapon/vehicle_assembly/spacebike /datum/design/item/mechfab/vehicle/quadbike_chassis - name = "Quadbike Chassis" - desc = "A space-bike's un-assembled frame." + name = "Quad bike Chassis" + desc = "A quad bike's un-assembled frame." id = "vehicle_chassis_quadbike" req_tech = list(TECH_MATERIAL = 5, TECH_ENGINEERING = 6, TECH_MAGNET = 3, TECH_POWER = 2) materials = list(MAT_STEEL = 15000, MAT_SILVER = 3000, MAT_PLASTIC = 3000, MAT_OSMIUM = 1000) build_path = /obj/item/weapon/vehicle_assembly/quadbike +/datum/design/item/mechfab/vehicle/snowmobile_chassis + name = "Snowmobile Chassis" + desc = "A snowmobile's un-assembled frame." + id = "vehicle_chassis_snowmobile" + req_tech = list(TECH_MATERIAL = 5, TECH_ENGINEERING = 6, TECH_MAGNET = 3, TECH_POWER = 2) + materials = list(MAT_STEEL = 12000, MAT_SILVER = 3000, MAT_PLASTIC = 3000, MAT_OSMIUM = 1000) + build_path = /obj/item/weapon/vehicle_assembly/snowmobile + /* * Rigsuits */ @@ -1235,4 +1243,4 @@ id = "exo_int_actuator_overclock" req_tech = list(TECH_MATERIAL = 5, TECH_ENGINEERING = 4, TECH_POWER = 4) materials = list(MAT_PLASTEEL = 10000, MAT_OSMIUM = 3000, MAT_GOLD = 5000) - build_path = /obj/item/mecha_parts/component/actuator/hispeed \ No newline at end of file + build_path = /obj/item/mecha_parts/component/actuator/hispeed diff --git a/code/modules/tgs/v5/chat_commands.dm b/code/modules/tgs/v5/chat_commands.dm index 5a4386e6da..6fcc8bc235 100644 --- a/code/modules/tgs/v5/chat_commands.dm +++ b/code/modules/tgs/v5/chat_commands.dm @@ -8,6 +8,9 @@ var/afks = 0 var/active = 0 var/bellied = 0 + var/map_name = "n/a" + if(using_map && using_map.full_name) + map_name = using_map.full_name for(var/X in GLOB.clients) var/client/C = X @@ -21,7 +24,7 @@ else active++ - return "Current server status:\n**Web Manifest:** \n**Players:** [counts]\n**Active:** [active]\n**AFK:** [afks]\n**Bellied:** [bellied]\n\n**Round Duration:** [roundduration2text()]" + return "Current server status:\n**Web Manifest:** \n**Players:** [counts]\n**Active:** [active]\n**AFK:** [afks]\n**Bellied:** [bellied]\n\n**Round Duration:** [roundduration2text()]\n**Current Map:** [map_name]" */ /datum/tgs_chat_command/parsetest @@ -142,7 +145,9 @@ GLOBAL_LIST_EMPTY(pending_discord_registrations) var/counts = 0 var/afks = 0 var/active = 0 - + var/map_name = "n/a" + if(using_map && using_map.full_name) + map_name = using_map.full_name for(var/X in GLOB.clients) var/client/C = X if(C) @@ -152,7 +157,7 @@ GLOBAL_LIST_EMPTY(pending_discord_registrations) else active++ - return "Current server status: **Players:** [counts]\n**Active:** [active]\n**AFK:** [afks]\n\n**Round Duration:** [roundduration2text()]" + return "Current server status: **Players:** [counts]\n**Active:** [active]\n**AFK:** [afks]\n\n**Round Duration:** [roundduration2text()]\n**Current Map:** [map_name]" // - FAX /datum/tgs_chat_command/readfax diff --git a/code/modules/vchat/css/ss13styles.css b/code/modules/vchat/css/ss13styles.css index 4f1fc8df99..e14d98098c 100644 --- a/code/modules/vchat/css/ss13styles.css +++ b/code/modules/vchat/css/ss13styles.css @@ -199,6 +199,8 @@ h1.alert, h2.alert {color: #000000;} .inverted .blue {color: #6666FF;} .inverted .green {color: #44FF44;} +.pnarrate {color: #009AB2;} + /*BIG IMG.icon {width: 32px; height: 32px;}*/ img.icon {vertical-align: middle; max-height: 1em;} img.icon.bigicon {max-height: 32px;} diff --git a/code/modules/vehicles/cargo_train.dm b/code/modules/vehicles/cargo_train.dm index c213161a3b..b9a3bb20a3 100644 --- a/code/modules/vehicles/cargo_train.dm +++ b/code/modules/vehicles/cargo_train.dm @@ -48,6 +48,7 @@ key = new key_type(src) var/image/I = new(icon = 'icons/obj/vehicles_vr.dmi', icon_state = "cargo_engine_overlay", layer = src.layer + 0.2) //over mobs //VOREStation edit add_overlay(I) + update_icon() turn_off() //so engine verbs are correctly set /obj/vehicle/train/engine/Move(var/turf/destination) diff --git a/code/modules/vehicles/construction.dm b/code/modules/vehicles/construction.dm index bb0ca7cb0b..20adccd5f0 100644 --- a/code/modules/vehicles/construction.dm +++ b/code/modules/vehicles/construction.dm @@ -12,7 +12,6 @@ density = TRUE slowdown = 10 //It's a vehicle frame, what do you expect? w_class = 5 - pixel_x = -16 var/build_stage = 0 var/obj/item/weapon/cell/cell = null @@ -38,6 +37,7 @@ name = "all terrain vehicle assembly" desc = "The frame of an ATV." icon_state = "quad-frame" + pixel_x = -16 /obj/item/weapon/vehicle_assembly/quadbike/attackby(var/obj/item/weapon/W as obj, var/mob/user as mob) ..() @@ -143,11 +143,13 @@ user.drop_from_inventory(src) qdel(src) return + ..() /obj/item/weapon/vehicle_assembly/quadtrailer name = "all terrain trailer" desc = "The frame of a small trailer." icon_state = "quadtrailer-frame" + pixel_x = -16 /obj/item/weapon/vehicle_assembly/quadtrailer/attackby(var/obj/item/weapon/W as obj, var/mob/user as mob) ..() @@ -272,3 +274,104 @@ user.drop_from_inventory(src) qdel(src) return + +/* + * Snowmobile. + */ + +/obj/item/weapon/vehicle_assembly/snowmobile + name = "snowmobile assembly" + desc = "The frame of a snowmobile." + icon = 'icons/obj/vehicles.dmi' + icon_state = "snowmobile-frame" + +/obj/item/weapon/vehicle_assembly/snowmobile/attackby(var/obj/item/W as obj, var/mob/user as mob) + switch(build_stage) + if(0) + if(istype(W, /obj/item/stack/material/steel)) + var/obj/item/stack/material/steel/S = W + if (S.get_amount() < 6) + to_chat(user, "You need six sheets of steel to add treads to \the [src].") + return + to_chat(user, "You start to add treads to [src].") + if(do_after(user, 40) && build_stage == 0) + if(S.use(6)) + to_chat(user, "You add treads to \the [src].") + increase_step("tracked [initial(name)]") + return + + if(1) + if(istype(W, /obj/item/weapon/stock_parts/console_screen)) + user.drop_item() + qdel(W) + to_chat(user, "You add the lights to \the [src].") + increase_step() + return + + if(2) + if(istype(W, /obj/item/weapon/stock_parts/spring)) + user.drop_item() + qdel(W) + to_chat(user, "You add the control system to \the [src].") + increase_step() + return + + if(3) + if(istype(W, /obj/item/stack/cable_coil)) + var/obj/item/stack/cable_coil/C = W + if (C.get_amount() < 2) + to_chat(user, "You need two coils of wire to wire [src].") + return + to_chat(user, "You start to wire [src].") + if(do_after(user, 40) && build_stage == 3) + if(C.use(2)) + to_chat(user, "You wire \the [src].") + increase_step("wired [initial(name)]") + return + + if(4) + if(istype(W, /obj/item/weapon/cell)) + user.drop_item() + W.forceMove(src) + cell = W + to_chat(user, "You add the power supply to \the [src].") + increase_step("powered [initial(name)]") + return + + if(5) + if(istype(W, /obj/item/weapon/stock_parts/motor)) + user.drop_item() + qdel(W) + to_chat(user, "You add the motor to \the [src].") + increase_step() + return + + if(6) + if(istype(W, /obj/item/stack/material/plasteel)) + var/obj/item/stack/material/plasteel/PL = W + if (PL.get_amount() < 2) + to_chat(user, "You need two sheets of plasteel to add reinforcement to \the [src].") + return + to_chat(user, "You start to add reinforcement to [src].") + if(do_after(user, 40) && build_stage == 6) + if(PL.use(2)) + to_chat(user, "You add reinforcement to \the [src].") + increase_step("reinforced [initial(name)]") + return + + if(7) + if(W.is_wrench() || W.is_screwdriver()) + playsound(src, W.usesound, 50, 1) + to_chat(user, "You begin your finishing touches on \the [src].") + if(do_after(user, 20) && build_stage == 7) + playsound(src, W.usesound, 30, 1) + var/obj/vehicle/train/engine/quadbike/snowmobile/built/product = new(src) + to_chat(user, "You finish \the [product]") + product.loc = get_turf(src) + product.cell = cell + cell.forceMove(product) + cell = null + user.drop_from_inventory(src) + qdel(src) + return + ..() diff --git a/code/modules/vehicles/quad.dm b/code/modules/vehicles/quad.dm index c66b2987b0..00bedf8778 100644 --- a/code/modules/vehicles/quad.dm +++ b/code/modules/vehicles/quad.dm @@ -19,7 +19,9 @@ key_type = /obj/item/weapon/key/quadbike var/frame_state = "quad" //Custom-item proofing! + var/paint_base = 'icons/obj/vehicles_64x64.dmi' var/custom_frame = FALSE + var/datum/looping_sound/vehicle_engine/soundloop paint_color = "#ffffff" @@ -28,7 +30,10 @@ /obj/vehicle/train/engine/quadbike/New() cell = new /obj/item/weapon/cell/high(src) key = new key_type(src) + soundloop = new(list(src), FALSE) + . = ..() turn_off() + update_icon() /obj/vehicle/train/engine/quadbike/built/New() key = new key_type(src) @@ -38,6 +43,10 @@ paint_color = rgb(rand(1,255),rand(1,255),rand(1,255)) ..() +/obj/vehicle/train/engine/quadbike/Destroy() + QDEL_NULL(soundloop) + return ..() + /obj/item/weapon/key/quadbike name = "key" desc = "A keyring with a small steel key, and a blue fob reading \"ZOOM!\"." @@ -47,20 +56,28 @@ /obj/vehicle/train/engine/quadbike/Moved(atom/old_loc, direction, forced = FALSE) . = ..() //Move it move it, so we can test it test it. - if(!istype(loc, old_loc.type) && !istype(old_loc, loc.type)) //Did we move at all, and are we changing turf types? - if(istype(loc, /turf/simulated/floor/water)) - speed_mod = outdoors_speed_mod * 4 //It kind of floats due to its tires, but it is slow. - else if(istype(loc, /turf/simulated/floor/outdoors/rocks)) - speed_mod = initial(speed_mod) //Rocks are good, rocks are solid. - else if(istype(loc, /turf/simulated/floor/outdoors/dirt) || istype(loc, /turf/simulated/floor/outdoors/grass)) - speed_mod = outdoors_speed_mod //Dirt and grass are the outdoors bench mark. - else if(istype(loc, /turf/simulated/floor/outdoors/mud)) - speed_mod = outdoors_speed_mod * 1.5 //Gets us roughly 1. Mud may be fun, but it's not the best. - else if(istype(loc, /turf/simulated/floor/outdoors/snow)) - speed_mod = outdoors_speed_mod * 1.7 //Roughly a 1.25. Snow is coarse and wet and gets everywhere, especially your electric motors. - else - speed_mod = initial(speed_mod) - update_car(train_length, active_engines) + get_turf_speeds(old_loc) + handle_vehicle_icon() + +/obj/vehicle/train/engine/quadbike/proc/get_turf_speeds(atom/prev_loc) + // Same speed if turf type doesn't change + if(istype(loc, prev_loc.type) || istype(prev_loc, loc.type)) + return + if(istype(loc, /turf/simulated/floor/water)) + speed_mod = outdoors_speed_mod * 4 //It kind of floats due to its tires, but it is slow. + else if(istype(loc, /turf/simulated/floor/outdoors/rocks)) + speed_mod = initial(speed_mod) //Rocks are good, rocks are solid. + else if(istype(loc, /turf/simulated/floor/outdoors/dirt) || istype(loc, /turf/simulated/floor/outdoors/grass) || istype(loc, /turf/simulated/floor/outdoors/newdirt) || istype(loc, /turf/simulated/floor/outdoors/newdirt_nograss)) + speed_mod = outdoors_speed_mod //Dirt and grass are the outdoors bench mark. + else if(istype(loc, /turf/simulated/floor/outdoors/mud)) + speed_mod = outdoors_speed_mod * 1.5 //Gets us roughly 1. Mud may be fun, but it's not the best. + else if(istype(loc, /turf/simulated/floor/outdoors/snow)) + speed_mod = outdoors_speed_mod * 1.7 //Roughly a 1.25. Snow is coarse and wet and gets everywhere, especially your electric motors. + else + speed_mod = initial(speed_mod) + update_car(train_length, active_engines) + +/obj/vehicle/train/engine/quadbike/proc/handle_vehicle_icon() switch(dir) //Due to being a Big Boy sprite, it has to have special pixel shifting to look 'normal' when being driven. if(1) pixel_y = -6 @@ -71,7 +88,6 @@ if(8) pixel_y = 0 - /obj/vehicle/train/engine/quadbike/attackby(obj/item/weapon/W as obj, mob/user as mob) if(istype(W, /obj/item/device/multitool) && open) var/new_paint = input(usr, "Please select paint color.", "Paint Color", paint_color) as color|null @@ -99,12 +115,12 @@ add_overlay(Overmob_color) return - var/image/Bodypaint = new(icon = 'icons/obj/vehicles_64x64.dmi', icon_state = "[frame_state]_a", layer = src.layer) + var/image/Bodypaint = new(icon = paint_base, icon_state = "[frame_state]_a", layer = src.layer) Bodypaint.color = paint_color add_overlay(Bodypaint) - var/image/Overmob = new(icon = 'icons/obj/vehicles_64x64.dmi', icon_state = "[frame_state]_overlay", layer = src.layer + 0.2) //over mobs - var/image/Overmob_color = new(icon = 'icons/obj/vehicles_64x64.dmi', icon_state = "[frame_state]_overlay_a", layer = src.layer + 0.2) //over the over mobs, gives the color. + var/image/Overmob = new(icon = paint_base, icon_state = "[frame_state]_overlay", layer = src.layer + 0.2) //over mobs + var/image/Overmob_color = new(icon = paint_base, icon_state = "[frame_state]_overlay_a", layer = src.layer + 0.2) //over the over mobs, gives the color. Overmob.plane = MOB_PLANE Overmob_color.plane = MOB_PLANE Overmob_color.color = paint_color @@ -152,6 +168,18 @@ var/turf/T = get_step(M, pick(throw_dirs)) M.throw_at(T, 1, 1, src) +/obj/vehicle/train/engine/quadbike/turn_on() + ..() + if(on) + src.visible_message("\The [src] rumbles to life.", "You hear something rumble deeply.") + soundloop.start() + +/obj/vehicle/train/engine/quadbike/turn_off() + if(on) + src.visible_message("\The [src] putters before turning off.", "You hear something putter slowly.") + soundloop.stop() + ..() + /* * Trailer bits and bobs. */ diff --git a/code/modules/vehicles/snowmobile.dm b/code/modules/vehicles/snowmobile.dm new file mode 100644 index 0000000000..dd45207fea --- /dev/null +++ b/code/modules/vehicles/snowmobile.dm @@ -0,0 +1,82 @@ +/obj/vehicle/train/engine/quadbike/snowmobile + name = "snowmobile" + desc = "An electric snowmobile for traversing snow and ice with ease! Other terrain, not so much." + description_info = "Use ctrl-click to quickly toggle the engine if you're adjacent. Alt-click to quickly remove keys. Click-drag yourself or another person to mount as a passenger (passengers can't drive!)." + icon = 'icons/obj/vehicles.dmi' + icon_state = "snowmobile" + + load_item_visible = 1 + speed_mod = 0.6 //Speed on non-specially-defined tiles + car_limit = 0 //No trailers. + max_buckled_mobs = 2 + active_engines = 1 + key_type = /obj/item/key/snowmobile + outdoors_speed_mod = 0.7 //The general 'outdoors' speed. I.E., the general difference you'll be at when driving outside on ideal terrain (...Snow) + frame_state = "snowmobile" //Custom-item proofing! + paint_base = 'icons/obj/vehicles.dmi' + pixel_x = 0 + latch_on_start = 0 + + var/riding_datum_type = /datum/riding/snowmobile + +/obj/item/key/snowmobile + name = "key" + desc = "A keyring with a small steel key, and an ice-blue fob reading \"CHILL\"." + icon = 'icons/obj/vehicles.dmi' + icon_state = "sno_keys" + w_class = ITEMSIZE_TINY + +/obj/vehicle/train/engine/quadbike/snowmobile/random/Initialize() + paint_color = rgb(rand(1,255),rand(1,255),rand(1,255)) + . = ..() + +/obj/vehicle/train/engine/quadbike/snowmobile/Initialize() + . = ..() + riding_datum = new riding_datum_type(src) + +/obj/vehicle/train/engine/quadbike/snowmobile/built/Initialize() + dir = 2 //To match the under construction frame + . = ..() + +/obj/vehicle/train/engine/quadbike/snowmobile/get_turf_speeds(atom/prev_loc) + // Same speed if turf type doesn't change + if(istype(loc, prev_loc.type) || istype(prev_loc, loc.type)) + return + if(istype(loc, /turf/simulated/floor/water)) + speed_mod = outdoors_speed_mod * 6 //Well that was a stupid idea wasn't it? + else if(istype(loc, /turf/simulated/floor/outdoors/rocks)) + speed_mod = initial(speed_mod) * 1.5 //Rocks are hard, hard and skids don't mix so you're relying on the treads. Basically foot speed. + else if(istype(loc, /turf/simulated/floor/outdoors/dirt) || istype(loc, /turf/simulated/floor/outdoors/grass) || istype(loc, /turf/simulated/floor/outdoors/newdirt) || istype(loc, /turf/simulated/floor/outdoors/newdirt_nograss)) + speed_mod = outdoors_speed_mod //Dirt and grass aren't strictly what this is designed for but its a baseline. + else if(istype(loc, /turf/simulated/floor/outdoors/mud)) + speed_mod = outdoors_speed_mod * 1.4 //Workable, not great though. + else if(istype(loc, /turf/simulated/floor/outdoors/snow) || istype(loc, /turf/simulated/floor/outdoors/ice)) + speed_mod = outdoors_speed_mod * 0.8 //Now we're talking! + else + speed_mod = initial(speed_mod) + update_car(train_length, active_engines) + +/obj/vehicle/train/engine/quadbike/snowmobile/handle_vehicle_icon() + return + +//Required for the riding datum to behave: +/obj/vehicle/train/engine/quadbike/snowmobile/MouseDrop_T(var/atom/movable/C, var/mob/user as mob) + if(ismob(C)) + if(C in buckled_mobs) + user_unbuckle_mob(C, user) + else + user_buckle_mob(C, user) + else + ..(C, user) + +/obj/vehicle/train/engine/quadbike/snowmobile/attack_hand(var/mob/user as mob) + if(user == load) + unload(load, user) + to_chat(user, "You unbuckle yourself from \the [src].") + return + if(user in buckled_mobs) + unbuckle_mob(user) + return + else if(!load && load(user, user)) + to_chat(user, "You buckle yourself to \the [src].") + return diff --git a/code/modules/vehicles/train.dm b/code/modules/vehicles/train.dm index 67fc0735a3..a92b9828f6 100644 --- a/code/modules/vehicles/train.dm +++ b/code/modules/vehicles/train.dm @@ -13,6 +13,7 @@ var/active_engines = 0 var/train_length = 0 + var/latch_on_start = 1 var/obj/vehicle/train/lead var/obj/vehicle/train/tow @@ -25,7 +26,8 @@ /obj/vehicle/train/Initialize() . = ..() for(var/obj/vehicle/train/T in orange(1, src)) - latch(T, null) + if(latch_on_start) + latch(T, null) /obj/vehicle/train/Move() var/old_loc = get_turf(src) @@ -156,7 +158,7 @@ return if (T.tow) - if(user) + if(user) to_chat(user, "[T] is already towing something.") return diff --git a/code/modules/vehicles/vehicle.dm b/code/modules/vehicles/vehicle.dm index b9eada1d12..2989dcad63 100644 --- a/code/modules/vehicles/vehicle.dm +++ b/code/modules/vehicles/vehicle.dm @@ -197,12 +197,17 @@ return FALSE if(powered && cell.charge < charge_use) return FALSE + if(on) + return FALSE on = 1 + playsound(src, 'sound/machines/vehicle/ignition.ogg', 50, 1, -3) set_light(initial(light_range)) update_icon() return TRUE /obj/vehicle/proc/turn_off() + if(!on) + return FALSE if(!mechanical) return FALSE on = 0 diff --git a/code/modules/vore/eating/living_vr.dm b/code/modules/vore/eating/living_vr.dm index f8431fa383..8020233ad1 100644 --- a/code/modules/vore/eating/living_vr.dm +++ b/code/modules/vore/eating/living_vr.dm @@ -493,7 +493,7 @@ muffled = FALSE //Removes Muffling forceMove(get_turf(src)) //Just move me up to the turf, let's not cascade through bellies, there's been a problem, let's just leave. for(var/mob/living/simple_mob/SA in range(10)) - SA.prey_excludes[src] = world.time + LAZYSET(SA.prey_excludes, src, world.time) log_and_message_admins("[key_name(src)] used the OOC escape button to get out of [key_name(B.owner)] ([B.owner ? "JMP" : "null"])") if(!ishuman(B.owner)) @@ -776,7 +776,7 @@ if(istype(I, /obj/item/device/paicard)) var/obj/item/device/paicard/palcard = I var/mob/living/silicon/pai/pocketpal = palcard.pai - if(!pocketpal.devourable) + if(pocketpal && (!pocketpal.devourable)) to_chat(src, "\The [pocketpal] doesn't allow you to eat it.") return diff --git a/code/modules/vore/eating/simple_animal_vr.dm b/code/modules/vore/eating/simple_animal_vr.dm index f9744d8ac7..680e650113 100644 --- a/code/modules/vore/eating/simple_animal_vr.dm +++ b/code/modules/vore/eating/simple_animal_vr.dm @@ -1,7 +1,7 @@ ///////////////////// Simple Animal ///////////////////// /mob/living/simple_mob var/swallowTime = (3 SECONDS) //How long it takes to eat its prey in 1/10 of a second. The default is 3 seconds. - var/list/prey_excludes = list() //For excluding people from being eaten. + var/list/prey_excludes = null //For excluding people from being eaten. // // Simple nom proc for if you get ckey'd into a simple_mob mob! Avoids grabs. @@ -86,17 +86,16 @@ user.visible_message("[user] swats [src] with [O]!") release_vore_contents() for(var/mob/living/L in living_mobs(0)) //add everyone on the tile to the do-not-eat list for a while - if(!(L in prey_excludes)) // Unless they're already on it, just to avoid fuckery. - prey_excludes += L + if(!(LAZYFIND(prey_excludes, L))) // Unless they're already on it, just to avoid fuckery. + LAZYSET(prey_excludes, L, world.time) addtimer(CALLBACK(src, .proc/removeMobFromPreyExcludes, weakref(L)), 5 MINUTES) else if(istype(O, /obj/item/device/healthanalyzer)) var/healthpercent = health/maxHealth*100 - to_chat(user, "[src] seems to be [healthpercent]% healthy.") + to_chat(user, "[src] seems to be [healthpercent]% healthy.") else ..() /mob/living/simple_mob/proc/removeMobFromPreyExcludes(weakref/target) if(isweakref(target)) var/mob/living/L = target.resolve() - if(L) - LAZYREMOVE(prey_excludes, L) + LAZYREMOVE(prey_excludes, L) // It's fine to remove a null from the list if we couldn't resolve L diff --git a/code/modules/vore/fluffstuff/custom_clothes_vr.dm b/code/modules/vore/fluffstuff/custom_clothes_vr.dm index b0aa01cb29..e38f5ba79d 100644 --- a/code/modules/vore/fluffstuff/custom_clothes_vr.dm +++ b/code/modules/vore/fluffstuff/custom_clothes_vr.dm @@ -26,21 +26,21 @@ //Natje: Awen Henry /obj/item/clothing/head/fluff/wolfgirl - name = "Wolfgirl Hat" - desc = "An odd, small hat with two strings attached to it." + name = "Wolfgirl Hat" + desc = "An odd, small hat with two strings attached to it." - icon_state = "wolfgirlhat" - icon = 'icons/vore/custom_clothes_vr.dmi' - icon_override = 'icons/vore/custom_onmob_vr.dmi' + icon_state = "wolfgirlhat" + icon = 'icons/vore/custom_clothes_vr.dmi' + icon_override = 'icons/vore/custom_onmob_vr.dmi' //Natje: Awen Henry /obj/item/clothing/shoes/fluff/wolfgirl - name = "Red Sandals" - desc = "A pair of sandals that make you want to awoo!" + name = "Red Sandals" + desc = "A pair of sandals that make you want to awoo!" - icon_state = "wolfgirlsandals" - icon = 'icons/vore/custom_clothes_vr.dmi' - icon_override = 'icons/vore/custom_onmob_vr.dmi' + icon_state = "wolfgirlsandals" + icon = 'icons/vore/custom_clothes_vr.dmi' + icon_override = 'icons/vore/custom_onmob_vr.dmi' //Natje: Awen Henry /obj/item/clothing/under/fluff/wolfgirl @@ -2482,11 +2482,11 @@ Departamental Swimsuits, for general use //Uncle_Fruit_VEVO - Bradley Khatibi /obj/item/clothing/shoes/fluff/airjordans - name = "A pair of Air Jordan 1 Mid 'Black Gym Red's" - desc = "Appearing in a classic Jordan Brand colorway, the Air Jordan 1 Mid 'Black Gym Red' released in May 2021. Built with leather, the shoe's upper sports a white base, contrasted by black on the overlays and highlighted by Gym Red on the padded collar, 'Wings' logo and Swoosh branding. A breathable nylon tongue and perforated toe box support the fit, while underfoot, a standard rubber cupsole with Air in the heel anchors the build." - icon_state = "airjordans" - icon = 'icons/vore/custom_clothes_vr.dmi' - icon_override = 'icons/vore/custom_onmob_vr.dmi' + name = "A pair of Air Jordan 1 Mid 'Black Gym Red's" + desc = "Appearing in a classic Jordan Brand colorway, the Air Jordan 1 Mid 'Black Gym Red' released in May 2021. Built with leather, the shoe's upper sports a white base, contrasted by black on the overlays and highlighted by Gym Red on the padded collar, 'Wings' logo and Swoosh branding. A breathable nylon tongue and perforated toe box support the fit, while underfoot, a standard rubber cupsole with Air in the heel anchors the build." + icon_state = "airjordans" + icon = 'icons/vore/custom_clothes_vr.dmi' + icon_override = 'icons/vore/custom_onmob_vr.dmi' //Pandora029:Seona Young /obj/item/clothing/under/fluff/foxoflightsuit @@ -2511,29 +2511,54 @@ Departamental Swimsuits, for general use item_state = null // i swear to god this works - hatterhat icon_override = 'icons/vore/custom_onmob_vr.dmi' + //Sudate: Shea Corbett /obj/item/clothing/under/fluff/greek_dress - name = "mytilenean dress" - desc = "It's a breezy, colorful two-part dress woven from linen, with the top consisting of white linen, and the skirt of rougher, sturdy fabric. It's adorned with a yellow belt and embroidered stripes in the hem, and blue highlights at the sleeves. More notably, however, it exposes the wearer's chest entirely." + name = "mytilenean dress" + desc = "It's a breezy, colorful two-part dress woven from linen, with the top consisting of white linen, and the skirt of rougher, sturdy fabric. It's adorned with a yellow belt and embroidered stripes in the hem, and blue highlights at the sleeves. More notably, however, it exposes the wearer's chest entirely." - icon = 'icons/vore/custom_clothes_vr.dmi' - icon_state = "greek_dress" - worn_state = "greek_dress" - rolled_sleeves = 0 - rolled_down = 0 + icon = 'icons/vore/custom_clothes_vr.dmi' + icon_state = "greek_dress" + worn_state = "greek_dress" + rolled_sleeves = 0 + rolled_down = 0 + + icon_override = 'icons/vore/custom_clothes_vr.dmi' + item_state = "greek_dress" + body_parts_covered = UPPER_TORSO|LOWER_TORSO|ARMS|LEGS - icon_override = 'icons/vore/custom_clothes_vr.dmi' - item_state = "greek_dress" - body_parts_covered = UPPER_TORSO|LOWER_TORSO|ARMS|LEGS //JadeManique: Freyr /obj/item/clothing/mask/fluff/freyr_mask - name = "Freyr's Mask" - desc = "A pristine white mask with antlers. Its silky to the touch, like porcelain!" - icon = 'icons/vore/custom_clothes_vr.dmi' - icon_state = "freyrmask" - icon_override = 'icons/vore/custom_onmob_vr.dmi' - item_state = "freyrmask_mob" - item_state_slots = null - body_parts_covered = FACE + name = "Freyr's Mask" + desc = "A pristine white mask with antlers. Its silky to the touch, like porcelain!" + icon = 'icons/vore/custom_clothes_vr.dmi' + icon_state = "freyrmask" + icon_override = 'icons/vore/custom_onmob_vr.dmi' + item_state = "freyrmask_mob" + item_state_slots = null + body_parts_covered = FACE + flags_inv = HIDEFACE + item_flags = FLEXIBLEMATERIAL +//codeme: Perrin Kade +/obj/item/clothing/shoes/fluff/gildedshoes_perrin + name = "gilded shoes" + desc = "Black shoes with gilding, revealing and comfortable for any wearer!" + icon_state = "perrinshoes" + icon = 'icons/vore/custom_clothes_vr.dmi' + icon_override = 'icons/vore/custom_onmob_vr.dmi' + +/obj/item/clothing/under/fluff/gildedrobe_perrin + name = "gilded robe" + desc = "Black robe with gilding, revealing and comfortable for any wearer!" + + icon = 'icons/vore/custom_clothes_vr.dmi' + icon_state = "perrinrobes" + worn_state = "perrinrobes_s" + rolled_sleeves = 0 + rolled_down = 0 + + icon_override = 'icons/vore/custom_onmob_vr.dmi' + item_state = "perrinrobes_s" + body_parts_covered = UPPER_TORSO|LOWER_TORSO \ No newline at end of file diff --git a/code/modules/vore/fluffstuff/custom_items_vr.dm b/code/modules/vore/fluffstuff/custom_items_vr.dm index ca67610a31..716389af8e 100644 --- a/code/modules/vore/fluffstuff/custom_items_vr.dm +++ b/code/modules/vore/fluffstuff/custom_items_vr.dm @@ -1447,8 +1447,7 @@ M.add_language(LANGUAGE_ECHOSONG) to_chat(M,"LANGUAGES - INITIALISED") -//thedavestdave Lucky -///I know this is pretty bodgey but if it stupid and it works it isn't stupid +//thedavestdave - Lucky /obj/item/clothing/suit/armor/combat/crusader_costume/lucky icon = 'icons/vore/custom_clothes_vr.dmi' icon_state = "luck" diff --git a/code/modules/whitelist/whitelist.dm b/code/modules/whitelist/whitelist.dm new file mode 100644 index 0000000000..2bc269acf7 --- /dev/null +++ b/code/modules/whitelist/whitelist.dm @@ -0,0 +1,100 @@ +/client/var/list/whitelists = null + + +// Prints the client's whitelist entries +/client/verb/print_whitelist() + set name = "Show Whitelist Entries" + set desc = "Print the set of things you're whitelisted for." + set category = "OOC" + + to_chat(src, "You are whitelisted for:") + to_chat(src, jointext(get_whitelists_list(), "\n")) + +/client/proc/get_whitelists_list() + . = list() + if(src.whitelists == null) + src.whitelists = load_whitelist(src.ckey) + for(var/key in src.whitelists) + try + . += initial(initial(key:name)) + catch() + . += key + + +/proc/load_whitelist(var/key) + var/filename = "data/player_saves/[copytext(ckey(key),1,2)]/[ckey(key)]/whitelist.json" + try + // Check the player-specific whitelist file, if it exists. + if(fexists(filename)) + // Load the whitelist entries from file, or empty string if empty.` + . = list() + for(var/T in json_decode(file2text(filename) || "")) + T = text2path(T) + if(!ispath(T)) + continue + .[T] = TRUE + + // Something was removing an entry from the whitelist and interrupted mid-overwrite. + else if(fexists(filename + ".tmp") && fcopy(filename + ".tmp", filename)) + . = load_whitelist(key) + if(!fdel(filename + ".tmp")) + error("Exception when deleting tmp whitelist file [filename].tmp") + + // Whitelist file doesn't exist, so they aren't whitelisted for anything. Create the file. + else if(fexists("data/player_saves/[copytext(ckey(key),1,2)]/[ckey(key)]/preferences.sav")) + text2file("", filename) + . = list() + + catch(var/exception/E) + error("Exception when loading whitelist file [filename]: [E]") + + +// Returns true if the specified path is in the player's whitelists, false otw. +/client/proc/is_whitelisted(var/path) + if(istext(path)) + path = text2path(path) + if(!ispath(path)) + return + // If it hasn't already been loaded, load it. + if(src.whitelists == null) + src.whitelists = load_whitelist(src.ckey) + return src.whitelists[path] + + +/proc/is_alien_whitelisted(mob/M, var/datum/species/species) + //They are admin or the whitelist isn't in use + if(whitelist_overrides(M)) + return TRUE + + //You did something wrong + if(!M || !species) + return FALSE + + //The species isn't even whitelisted + if(!(species.spawn_flags & SPECIES_IS_WHITELISTED)) + return TRUE + + var/client/C = (!isclient(M)) ? M.client : M + return C.is_whitelisted(species.type) + + +/proc/is_lang_whitelisted(mob/M, var/datum/language/language) + //They are admin or the whitelist isn't in use + if(whitelist_overrides(M)) + return TRUE + + var/client/C = (!isclient(M)) ? M.client : M + + //You did something wrong + if(!istype(C) || !istype(language)) + return FALSE + + //The language isn't even whitelisted + if(!(language.flags & WHITELISTED)) + return TRUE + + return C.is_whitelisted(language.type) + + +/proc/whitelist_overrides(mob/M) + return !config.usealienwhitelist || check_rights(R_ADMIN|R_EVENT, 0, M) diff --git a/code/stylesheet.dm b/code/stylesheet.dm index cade52a0ee..837333d31c 100644 --- a/code/stylesheet.dm +++ b/code/stylesheet.dm @@ -141,5 +141,7 @@ BIG IMG.icon {width: 32px; height: 32px;} .blue {color: #0000FF;} .green {color: #00DD00;} +.pnarrate {color: #009AB2;} + "} diff --git a/icons/inventory/accessory/item.dmi b/icons/inventory/accessory/item.dmi index aa939635c3..90eb88540a 100644 Binary files a/icons/inventory/accessory/item.dmi and b/icons/inventory/accessory/item.dmi differ diff --git a/icons/inventory/accessory/mob.dmi b/icons/inventory/accessory/mob.dmi index 7774d2ab7b..6c2f202809 100644 Binary files a/icons/inventory/accessory/mob.dmi and b/icons/inventory/accessory/mob.dmi differ diff --git a/icons/inventory/eyes/item_vr.dmi b/icons/inventory/eyes/item_vr.dmi index 4822216c87..cc158df7ad 100644 Binary files a/icons/inventory/eyes/item_vr.dmi and b/icons/inventory/eyes/item_vr.dmi differ diff --git a/icons/inventory/eyes/mob.dmi b/icons/inventory/eyes/mob.dmi index f2fdd8a45f..60edef888f 100644 Binary files a/icons/inventory/eyes/mob.dmi and b/icons/inventory/eyes/mob.dmi differ diff --git a/icons/inventory/eyes/mob_vr.dmi b/icons/inventory/eyes/mob_vr.dmi index e2ad4dd16c..2a413394e9 100644 Binary files a/icons/inventory/eyes/mob_vr.dmi and b/icons/inventory/eyes/mob_vr.dmi differ diff --git a/icons/inventory/suit/item_vr.dmi b/icons/inventory/suit/item_vr.dmi index 970690999c..2ec42eea27 100644 Binary files a/icons/inventory/suit/item_vr.dmi and b/icons/inventory/suit/item_vr.dmi differ diff --git a/icons/mob/human_face_alt.dmi b/icons/mob/human_face_alt.dmi index 6d02bc14bf..6811bb8fd6 100644 Binary files a/icons/mob/human_face_alt.dmi and b/icons/mob/human_face_alt.dmi differ diff --git a/icons/mob/human_races/markings_vr.dmi b/icons/mob/human_races/markings_vr.dmi index ee1c196b37..fb79d4e785 100644 Binary files a/icons/mob/human_races/markings_vr.dmi and b/icons/mob/human_races/markings_vr.dmi differ diff --git a/icons/mob/human_races/r_def_skrell.dmi b/icons/mob/human_races/r_def_skrell.dmi index 7b24ba3b4d..5224f7dd59 100644 Binary files a/icons/mob/human_races/r_def_skrell.dmi and b/icons/mob/human_races/r_def_skrell.dmi differ diff --git a/icons/mob/human_races/r_skrell.dmi b/icons/mob/human_races/r_skrell.dmi index 05e51ca0da..cf99d43e60 100644 Binary files a/icons/mob/human_races/r_skrell.dmi and b/icons/mob/human_races/r_skrell.dmi differ diff --git a/icons/mob/robots_vr.dmi b/icons/mob/robots_vr.dmi index fab80dec2d..2432498e71 100644 Binary files a/icons/mob/robots_vr.dmi and b/icons/mob/robots_vr.dmi differ diff --git a/icons/mob/vore.dmi b/icons/mob/vore.dmi index 884e241c18..4265bd359f 100644 Binary files a/icons/mob/vore.dmi and b/icons/mob/vore.dmi differ diff --git a/icons/mob/vore/tails_vr.dmi b/icons/mob/vore/tails_vr.dmi index 74b8d5fe60..f3cf3be825 100644 Binary files a/icons/mob/vore/tails_vr.dmi and b/icons/mob/vore/tails_vr.dmi differ diff --git a/icons/mob/vore/wings_vr.dmi b/icons/mob/vore/wings_vr.dmi index 68432f86f2..a6653ebcf3 100644 Binary files a/icons/mob/vore/wings_vr.dmi and b/icons/mob/vore/wings_vr.dmi differ diff --git a/icons/obj/food.dmi b/icons/obj/food.dmi index f1637aca4b..d302c760fc 100644 Binary files a/icons/obj/food.dmi and b/icons/obj/food.dmi differ diff --git a/icons/obj/gun.dmi b/icons/obj/gun.dmi index 42ce468bce..3e4b9152ad 100644 Binary files a/icons/obj/gun.dmi and b/icons/obj/gun.dmi differ diff --git a/icons/obj/vehicles.dmi b/icons/obj/vehicles.dmi index 6379879df7..271ba8f180 100644 Binary files a/icons/obj/vehicles.dmi and b/icons/obj/vehicles.dmi differ diff --git a/icons/vore/custom_clothes_vr.dmi b/icons/vore/custom_clothes_vr.dmi index 4abd369691..7c03befdfa 100644 Binary files a/icons/vore/custom_clothes_vr.dmi and b/icons/vore/custom_clothes_vr.dmi differ diff --git a/icons/vore/custom_onmob_vr.dmi b/icons/vore/custom_onmob_vr.dmi index 68403c0974..b401831f62 100644 Binary files a/icons/vore/custom_onmob_vr.dmi and b/icons/vore/custom_onmob_vr.dmi differ diff --git a/maps/cynosure/cynosure-2.dmm b/maps/cynosure/cynosure-2.dmm index d38f4e7d6d..95bc2a15d1 100644 --- a/maps/cynosure/cynosure-2.dmm +++ b/maps/cynosure/cynosure-2.dmm @@ -45225,6 +45225,9 @@ /obj/effect/floor_decal/steeldecal/steel_decals_central5{ dir = 1 }, +/obj/vehicle/train/engine/quadbike/snowmobile/random{ + dir = 1 + }, /turf/simulated/floor/tiled/old_tile/gray, /area/surface/station/garage) "uBP" = ( diff --git a/maps/tether/tether-02-surface2.dmm b/maps/tether/tether-02-surface2.dmm index b769623ee6..e6fbf5ee80 100644 --- a/maps/tether/tether-02-surface2.dmm +++ b/maps/tether/tether-02-surface2.dmm @@ -32843,6 +32843,10 @@ /obj/machinery/atmospherics/pipe/simple/hidden/scrubbers, /turf/simulated/floor/tiled/white, /area/tether/surfacebase/medical/breakroom) +"byX" = ( +/mob/living/simple_mob/vore/pakkun/snapdragon/snappy, +/turf/simulated/floor/beach/sand/desert, +/area/tether/surfacebase/fish_farm) "bCs" = ( /obj/effect/floor_decal/techfloor{ dir = 8 @@ -42947,7 +42951,7 @@ ayw azq azq ayw -axR +byX aCr ayw azq diff --git a/sound/machines/vehicle/engine_end.ogg b/sound/machines/vehicle/engine_end.ogg new file mode 100644 index 0000000000..7f3c179ad8 Binary files /dev/null and b/sound/machines/vehicle/engine_end.ogg differ diff --git a/sound/machines/vehicle/engine_mid.ogg b/sound/machines/vehicle/engine_mid.ogg new file mode 100644 index 0000000000..cf7173c8e8 Binary files /dev/null and b/sound/machines/vehicle/engine_mid.ogg differ diff --git a/sound/machines/vehicle/engine_start.ogg b/sound/machines/vehicle/engine_start.ogg new file mode 100644 index 0000000000..e4b5ac744b Binary files /dev/null and b/sound/machines/vehicle/engine_start.ogg differ diff --git a/sound/machines/vehicle/ignition.ogg b/sound/machines/vehicle/ignition.ogg new file mode 100644 index 0000000000..cf0718c6e3 Binary files /dev/null and b/sound/machines/vehicle/ignition.ogg differ diff --git a/vorestation.dme b/vorestation.dme index 1e63f33684..c30bd85438 100644 --- a/vorestation.dme +++ b/vorestation.dme @@ -4094,6 +4094,7 @@ #include "code\modules\vehicles\construction.dm" #include "code\modules\vehicles\quad.dm" #include "code\modules\vehicles\Securitrain_vr.dm" +#include "code\modules\vehicles\snowmobile.dm" #include "code\modules\vehicles\train.dm" #include "code\modules\vehicles\vehicle.dm" #include "code\modules\ventcrawl\ventcrawl.dm" @@ -4145,6 +4146,7 @@ #include "code\modules\vore\fluffstuff\custom_clothes_vr.dm" #include "code\modules\vore\fluffstuff\custom_clothes_yw.dm" #include "code\modules\vore\fluffstuff\custom_furniture_yw.dm" +#include "code\modules\vore\fluffstuff\custom_implants_vr.dm" #include "code\modules\vore\fluffstuff\custom_items_vr.dm" #include "code\modules\vore\fluffstuff\custom_items_yw.dm" #include "code\modules\vore\fluffstuff\custom_mecha_vr.dm"