diff --git a/code/__defines/dcs/flags.dm b/code/__defines/dcs/flags.dm index 84d332bd56..8d3aab2aa7 100644 --- a/code/__defines/dcs/flags.dm +++ b/code/__defines/dcs/flags.dm @@ -42,3 +42,7 @@ //Ouch my toes! #define CALTROP_BYPASS_SHOES 1 #define CALTROP_IGNORE_WALKERS 2 + +// Conflict element IDs +#define CONFLICT_ELEMENT_CRUSHER "crusher" +#define CONFLICT_ELEMENT_KA "kinetic_accelerator" \ No newline at end of file diff --git a/code/__defines/dcs/signals.dm b/code/__defines/dcs/signals.dm index 4947337598..df83ba66ec 100644 --- a/code/__defines/dcs/signals.dm +++ b/code/__defines/dcs/signals.dm @@ -772,3 +772,9 @@ #define COMPONENT_BLOCK_LIGHT_EATER (1<<0) ///from base of [/datum/element/light_eater/proc/devour]: (atom/eaten_light) #define COMSIG_LIGHT_EATER_DEVOUR "light_eater_devour" + +// conflict checking elements +/// (id) - returns flags - Registered on something by conflict checking elements. +#define COMSIG_CONFLICT_ELEMENT_CHECK "conflict_element_check" + /// A conflict was found + #define ELEMENT_CONFLICT_FOUND (1<<0) diff --git a/code/__defines/is_helpers.dm b/code/__defines/is_helpers.dm index 0c26095401..465b0be8e9 100644 --- a/code/__defines/is_helpers.dm +++ b/code/__defines/is_helpers.dm @@ -58,5 +58,6 @@ //#define isturf(D) istype(D, /turf) //Built in #define isopenspace(A) istype(A, /turf/simulated/open) #define isspace(A) istype(A, /turf/space) +#define ismineralturf(A) istype(A, /turf/simulated/mineral) #define istaurtail(A) istype(A, /datum/sprite_accessory/tail/taur) diff --git a/code/_helpers/names.dm b/code/_helpers/names.dm index 20f7b2b31d..e85a607417 100644 --- a/code/_helpers/names.dm +++ b/code/_helpers/names.dm @@ -172,7 +172,7 @@ var/syndicate_code_response//Code response for traitors. var/safety[] = list(1,2,3)//Tells the proc which options to remove later on. var/nouns[] = list("love","hate","anger","peace","pride","sympathy","bravery","loyalty","honesty","integrity","compassion","charity","success","courage","deceit","skill","beauty","brilliance","pain","misery","beliefs","dreams","justice","truth","faith","liberty","knowledge","thought","information","culture","trust","dedication","progress","education","hospitality","leisure","trouble","friendships", "relaxation") - var/drinks[] = list("vodka and tonic","gin fizz","bahama mama","manhattan","black Russian","whiskey soda","long island tea","margarita","Irish coffee"," manly dwarf","Irish cream","doctor's delight","Beepksy Smash","tequilla sunrise","brave bull","gargle blaster","bloody mary","whiskey cola","white Russian","vodka martini","martini","Cuba libre","kahlua","vodka","wine","moonshine") + var/drinks[] = list("vodka and tonic","gin fizz","bahama mama","manhattan","black Russian","whiskey soda","long island tea","margarita","Irish coffee"," manly dwarf","Irish cream","doctor's delight","Beepksy Smash","tequilla sunrise","brave bull","gargle blaster","bloody mary","whiskey cola","white Russian","vodka martini","martini","Cuba libre","kahlua","vodka","redwine","moonshine") var/locations[] = teleportlocs.len ? teleportlocs : drinks//if null, defaults to drinks instead. var/names[] = list() diff --git a/code/_helpers/time.dm b/code/_helpers/time.dm index b75792eeed..d63d263801 100644 --- a/code/_helpers/time.dm +++ b/code/_helpers/time.dm @@ -124,12 +124,19 @@ GLOBAL_VAR_INIT(round_start_time, 0) /var/midnight_rollovers = 0 /var/rollovercheck_last_timeofday = 0 +/var/rollover_safety_date = 0 // set in world/New to the server startup day-of-month /proc/update_midnight_rollover() - if (world.timeofday < rollovercheck_last_timeofday) //TIME IS GOING BACKWARDS! - midnight_rollovers += 1 + // Day has wrapped (world.timeofday drops to 0 at the start of each real day) + if (world.timeofday < rollovercheck_last_timeofday) + // If the day started/last wrap was < 12 hours ago, this is spurious + if(rollover_safety_date < world.realtime - (12 HOURS)) + midnight_rollovers++ + rollover_safety_date = world.realtime + else + warning("Time rollover error: world.timeofday decreased from previous check, but the day or last rollover is less than 12 hours old. System clock?") rollovercheck_last_timeofday = world.timeofday return midnight_rollovers - + //Increases delay as the server gets more overloaded, //as sleeps aren't cheap and sleeping only to wake up and sleep again is wasteful #define DELTA_CALC max(((max(TICK_USAGE, world.cpu) / 100) * max(Master.sleep_delta-1,1)), 1) diff --git a/code/datums/elements/conflict_checking.dm b/code/datums/elements/conflict_checking.dm new file mode 100644 index 0000000000..cd56d28856 --- /dev/null +++ b/code/datums/elements/conflict_checking.dm @@ -0,0 +1,35 @@ +/** + * Simple conflict checking for getting number of conflicting things on someone with the same ID. + */ +/datum/element/conflict_checking + element_flags = ELEMENT_BESPOKE | ELEMENT_DETACH + id_arg_index = 1 + /// we don't need to KNOW who has us, only our ID. + var/id + +/datum/element/conflict_checking/Attach(datum/target, id) + . = ..() + if(. & ELEMENT_INCOMPATIBLE) + return + if(!isatom(target)) + return ELEMENT_INCOMPATIBLE + if(!length(id)) + . = ELEMENT_INCOMPATIBLE + CRASH("Invalid ID in conflict checking element.") + if(isnull(src.id)) + src.id = id + RegisterSignal(target, COMSIG_CONFLICT_ELEMENT_CHECK, .proc/check) + +/datum/element/conflict_checking/proc/check(datum/source, id_to_check) + if(id == id_to_check) + return ELEMENT_CONFLICT_FOUND + +/** + * Counts number of conflicts on something that have a conflict checking element. + */ +/atom/proc/ConflictElementCount(id) + . = 0 + for(var/i in GetAllContents()) + var/atom/movable/AM = i + if(SEND_SIGNAL(AM, COMSIG_CONFLICT_ELEMENT_CHECK, id) & ELEMENT_CONFLICT_FOUND) + ++. \ No newline at end of file diff --git a/code/datums/outfits/jobs/science.dm b/code/datums/outfits/jobs/science.dm index a7b7a71478..307da0a8f9 100644 --- a/code/datums/outfits/jobs/science.dm +++ b/code/datums/outfits/jobs/science.dm @@ -39,4 +39,5 @@ pda_slot = slot_r_store pda_type = /obj/item/device/pda/roboticist backpack = /obj/item/weapon/storage/backpack - satchel_one = /obj/item/weapon/storage/backpack/satchel/norm \ No newline at end of file + satchel_one = /obj/item/weapon/storage/backpack/satchel/norm + suit = /obj/item/clothing/suit/storage/toggle/labcoat/roboticist \ No newline at end of file diff --git a/code/game/objects/items.dm b/code/game/objects/items.dm index 17d5689784..3fb73c4848 100644 --- a/code/game/objects/items.dm +++ b/code/game/objects/items.dm @@ -223,6 +223,8 @@ size = "bulky" if(ITEMSIZE_HUGE) size = "huge" + if(ITEMSIZE_NO_CONTAINER) + size = "massive" return ..(user, "", "It is a [size] item.") /obj/item/attack_hand(mob/living/user as mob) diff --git a/code/game/objects/items/weapons/material/whetstone.dm b/code/game/objects/items/weapons/material/whetstone.dm index 65faf1fa7c..12da5d23fd 100644 --- a/code/game/objects/items/weapons/material/whetstone.dm +++ b/code/game/objects/items/weapons/material/whetstone.dm @@ -63,7 +63,7 @@ if(istype(W, /obj/item/weapon/material)) if(istype(W, /obj/item/weapon/material/sharpeningkit)) - to_chat(user, "Really? Sharpening a [W] with [src]? You goofball.") + to_chat(user, "As much as you'd like to sharpen [W] with [src], the logistics just don't work out.") return var/obj/item/weapon/material/M = W if(uses >= M.w_class*2) @@ -71,7 +71,7 @@ uses -= M.w_class*2 return else - to_chat(user, "Not enough material to sharpen [M]. You need [M.w_class*2] [M.material.sheet_plural_name].") + to_chat(user, "There's not enough spare sheets to sharpen [M]. You need [M.w_class*2] [M.material.sheet_plural_name].") return else to_chat(user, "You can't sharpen [W] with [src]!") diff --git a/code/game/objects/items/weapons/storage/belt_vr.dm b/code/game/objects/items/weapons/storage/belt_vr.dm index ba86f3f2f9..5710e0f4d5 100644 --- a/code/game/objects/items/weapons/storage/belt_vr.dm +++ b/code/game/objects/items/weapons/storage/belt_vr.dm @@ -48,7 +48,8 @@ /obj/item/device/ano_scanner, /obj/item/device/cataloguer, /obj/item/device/radio, - /obj/item/device/mapping_unit + /obj/item/device/mapping_unit, + /obj/item/weapon/kinetic_crusher ) /obj/item/weapon/storage/belt/explorer/pathfinder diff --git a/code/game/objects/items/weapons/storage/briefcase.dm b/code/game/objects/items/weapons/storage/briefcase.dm index ed4d8fdbbe..a3cc27d926 100644 --- a/code/game/objects/items/weapons/storage/briefcase.dm +++ b/code/game/objects/items/weapons/storage/briefcase.dm @@ -20,4 +20,13 @@ force = 0 w_class = ITEMSIZE_NORMAL max_w_class = ITEMSIZE_SMALL - max_storage_space = ITEMSIZE_COST_SMALL * 4 \ No newline at end of file + max_storage_space = ITEMSIZE_COST_SMALL * 4 + +/obj/item/weapon/storage/briefcase/bookbag + name = "bookbag" + desc = "A small bookbag for holding... things other than books?" + icon_state = "bookbag" + force = 4.0 + w_class = ITEMSIZE_LARGE + max_w_class = ITEMSIZE_NORMAL + max_storage_space = ITEMSIZE_COST_NORMAL * 4 \ No newline at end of file diff --git a/code/game/objects/random/mapping.dm b/code/game/objects/random/mapping.dm index 61a7448300..377ae5a2ea 100644 --- a/code/game/objects/random/mapping.dm +++ b/code/game/objects/random/mapping.dm @@ -64,6 +64,52 @@ /obj/structure/closet/crate/engineering, /obj/structure/closet/crate) +/obj/random/vendorall //Fully random selection of consumer vendors + name = "random vending machine" + desc = "This is a random vending machine" + icon = 'icons/obj/vending.dmi' + icon_state = "radren-off" + +/obj/random/vendorall/item_to_spawn() + return pick (/obj/machinery/vending/coffee, + /obj/machinery/vending/snack, + /obj/machinery/vending/cola, + /obj/machinery/vending/fitness, + /obj/machinery/vending/cigarette, + /obj/machinery/vending/giftvendor, + /obj/machinery/vending/hotfood, + /obj/machinery/vending/weeb, + /obj/machinery/vending/sol, + /obj/machinery/vending/snix, + /obj/machinery/vending/snlvend, + /obj/machinery/vending/sovietsoda, + /obj/machinery/vending/sovietvend, + /obj/machinery/vending/radren) + +/obj/random/vendorfood //Random food vendors for station use + name = "random snack vending machine" + desc = "This is a random food vending machine" + icon = 'icons/obj/vending.dmi' + icon_state = "snack" + +/obj/random/vendorfood/item_to_spawn() + return pick (/obj/machinery/vending/snack, + /obj/machinery/vending/weeb, + /obj/machinery/vending/sol, + /obj/machinery/vending/snix, + /obj/machinery/vending/snlvend) + +/obj/random/vendordrink //Random drink vendors for station use + name = "random drink vending machine" + desc = "This is a random drink vending machine" + icon = 'icons/obj/vending.dmi' + icon_state = "Cola_Machine" + +/obj/random/vendordrink/item_to_spawn() //Not including coffee as it's more specific in usage. + return pick (/obj/machinery/vending/cola, + /obj/machinery/vending/sovietsoda, + /obj/machinery/vending/radren) + /obj/random/obstruction //Large objects to block things off in maintenance name = "random obstruction" desc = "This is a random obstruction." diff --git a/code/game/objects/structures/crates_lockers/closets/secure/scientist.dm b/code/game/objects/structures/crates_lockers/closets/secure/scientist.dm index a1e519f509..c9cea196b3 100644 --- a/code/game/objects/structures/crates_lockers/closets/secure/scientist.dm +++ b/code/game/objects/structures/crates_lockers/closets/secure/scientist.dm @@ -34,6 +34,7 @@ /obj/item/clothing/under/rank/research_director/dress_rd, /obj/item/clothing/suit/storage/toggle/labcoat, /obj/item/clothing/suit/storage/toggle/labcoat/modern, + /obj/item/clothing/suit/storage/toggle/labcoat/rd, /obj/item/weapon/cartridge/rd, /obj/item/clothing/shoes/white, /obj/item/clothing/shoes/laceup/brown, diff --git a/code/game/world.dm b/code/game/world.dm index dbd32c5c79..f8eccd500d 100644 --- a/code/game/world.dm +++ b/code/game/world.dm @@ -1,6 +1,7 @@ #define RECOMMENDED_VERSION 501 /world/New() world_startup_time = world.timeofday + rollover_safety_date = world.realtime - world.timeofday // 00:00 today (ish, since floating point error with world.realtime) of today to_world_log("Map Loading Complete") //logs //VOREStation Edit Start 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 67e1f26e82..8177c24b7f 100644 --- a/code/modules/client/preference_setup/loadout/loadout_accessories_vr.dm +++ b/code/modules/client/preference_setup/loadout/loadout_accessories_vr.dm @@ -40,6 +40,10 @@ display_name = "collar, pink" path = /obj/item/clothing/accessory/collar/pink +/datum/gear/collar/cowbell + display_name = "collar, cowbell" + path = /obj/item/clothing/accessory/collar/cowbell + /datum/gear/collar/holo display_name = "collar, holo" path = /obj/item/clothing/accessory/collar/holo diff --git a/code/modules/client/preference_setup/loadout/loadout_suit.dm b/code/modules/client/preference_setup/loadout/loadout_suit.dm index 7b98dd5132..2f6c808046 100644 --- a/code/modules/client/preference_setup/loadout/loadout_suit.dm +++ b/code/modules/client/preference_setup/loadout/loadout_suit.dm @@ -171,6 +171,11 @@ path = /obj/item/clothing/suit/storage/toggle/labcoat/emt allowed_roles = list("Medical Doctor","Chief Medical Officer","Chemist","Paramedic","Geneticist", "Psychiatrist") +/datum/gear/suit/labcoat_rd + display_name = "labcoat, research director" + path = /obj/item/clothing/suit/storage/toggle/labcoat/rd + allowed_roles = list("Research Director") + /datum/gear/suit/miscellaneous/labcoat display_name = "plague doctor's coat" path = /obj/item/clothing/suit/storage/toggle/labcoat/plaguedoctor @@ -616,3 +621,8 @@ /datum/gear/suit/miscellaneous/cardigan/New() ..() gear_tweaks += gear_tweak_free_color_choice + +/datum/gear/suit/cmddressjacket + display_name = "command dress jacket" + path = /obj/item/clothing/suit/storage/cmddressjacket + allowed_roles = list("Site Manager", "Head of Personnel", "Command Secretary") \ No newline at end of file diff --git a/code/modules/client/preference_setup/loadout/loadout_uniform.dm b/code/modules/client/preference_setup/loadout/loadout_uniform.dm index 5b7bc83757..6905a3f0d4 100644 --- a/code/modules/client/preference_setup/loadout/loadout_uniform.dm +++ b/code/modules/client/preference_setup/loadout/loadout_uniform.dm @@ -648,4 +648,36 @@ /datum/gear/uniform/countess display_name = "countess dress" - path = /obj/item/clothing/under/dress/countess \ No newline at end of file + path = /obj/item/clothing/under/dress/countess + +/datum/gear/uniform/verglasdress + display_name = "verglas dress" + path = /obj/item/clothing/under/verglasdress + +/datum/gear/uniform/fashionminiskirt + display_name = "fashionable miniskirt" + path = /obj/item/clothing/under/fashionminiskirt + +/datum/gear/uniform/fashionminiskirt/New() + ..() + gear_tweaks += gear_tweak_free_color_choice + +/datum/gear/uniform/paramedunidark + display_name = "paramedic uniform - dark" + path = /obj/item/clothing/under/rank/paramedunidark + allowed_roles = list("Medical Doctor","Chief Medical Officer","Paramedic") + +/datum/gear/uniform/parameduniskirtdark + display_name = "paramedic skirt - dark" + path = /obj/item/clothing/under/rank/parameduniskirtdark + allowed_roles = list("Medical Doctor","Chief Medical Officer","Paramedic") + +/datum/gear/uniform/paramedunilight + display_name = "paramedic uniform - light" + path = /obj/item/clothing/under/rank/paramedunilight + allowed_roles = list("Medical Doctor","Chief Medical Officer","Paramedic") + +/datum/gear/uniform/parameduniskirtlight + display_name = "paramedic skirt - light" + path = /obj/item/clothing/under/rank/parameduniskirtlight + allowed_roles = list("Medical Doctor","Chief Medical Officer","Paramedic") \ No newline at end of file diff --git a/code/modules/clothing/head/hood.dm b/code/modules/clothing/head/hood.dm index 28bc8a8a54..db51bcb8f9 100644 --- a/code/modules/clothing/head/hood.dm +++ b/code/modules/clothing/head/hood.dm @@ -186,4 +186,10 @@ name = "corgi hood" desc = "A hood that looks just like a corgi's head, it won't guarantee dog biscuits." icon_state = "ian" - item_state_slots = list(slot_r_hand_str = "ian", slot_l_hand_str = "ian") //Does not exist -S2- \ No newline at end of file + item_state_slots = list(slot_r_hand_str = "ian", slot_l_hand_str = "ian") //Does not exist -S2- + +//Techpriest +/obj/item/clothing/head/hood/techpriest + name = "techpriest hood" + desc = "A techpriest hood." + icon_state = "techpriesthood" \ No newline at end of file diff --git a/code/modules/clothing/spacesuits/rig/modules/specific/crusher_gauntlets.dm b/code/modules/clothing/spacesuits/rig/modules/specific/crusher_gauntlets.dm new file mode 100644 index 0000000000..3dff20284f --- /dev/null +++ b/code/modules/clothing/spacesuits/rig/modules/specific/crusher_gauntlets.dm @@ -0,0 +1,55 @@ +/obj/item/rig_module/gauntlets + + name = "proto-kinetic gear unit" + desc = "A set of paired proto-kinetic gauntlets and greaves. There's no way this is actually usable. Right?" + icon_state = "module" + + interface_name = "proto-kinetic gear unit" + interface_desc = "A set of paired proto-kinetic gauntlets and greaves. For disrupting rocks and creatures' innards." + + activate_string = "Deploy Gauntlets" + deactivate_string = "Undeploy Gauntlets" + + usable = 0 + toggleable = 1 + use_power_cost = 0 + active_power_cost = 2.5 + passive_power_cost = 0 + var/obj/item/weapon/kinetic_crusher/machete/gauntlets/rig/stored_gauntlets + +/obj/item/rig_module/gauntlets/Initialize() + . = ..() + stored_gauntlets = new /obj/item/weapon/kinetic_crusher/machete/gauntlets/rig(src) + stored_gauntlets.storing_module = src + +/obj/item/rig_module/gauntlets/activate() + ..() + var/mob/living/M = holder.wearer + var/datum/gender/TU = gender_datums[M.get_visible_gender()] + + if(M.l_hand && M.r_hand) + to_chat(M, "Your hands are full.") + deactivate() + return + if(M.a_intent == I_HURT) + M.visible_message( + "[M] throws [TU.his] arms out, extending [stored_gauntlets] from \the [holder] with a click!", + "You throw your arms out, extending [stored_gauntlets] from \the [holder] with a click!", + "You hear a threatening hiss and a click." + ) + else + M.visible_message( + "[M] extends [stored_gauntlets] from \the [holder] with a click!", + "You extend [stored_gauntlets] from \the [holder] with a click!", + "You hear a hiss and a click.") + + playsound(src, 'sound/items/helmetdeploy.ogg', 40, 1) + M.put_in_hands(stored_gauntlets) + +/obj/item/rig_module/gauntlets/deactivate() + ..() + var/mob/living/M = holder.wearer + if(!M) + return + for(var/obj/item/weapon/kinetic_crusher/machete/gauntlets/gaming in M.contents) + M.drop_from_inventory(gaming, src) \ No newline at end of file diff --git a/code/modules/clothing/suits/hooded.dm b/code/modules/clothing/suits/hooded.dm index b9b311128d..1a250bc683 100644 --- a/code/modules/clothing/suits/hooded.dm +++ b/code/modules/clothing/suits/hooded.dm @@ -362,4 +362,10 @@ /obj/item/weapon/tank, /obj/item/device/radio, /obj/item/weapon/pickaxe - ) \ No newline at end of file + ) + +/obj/item/clothing/suit/storage/hooded/techpriest + name = "techpriest robes" + desc = "For those who REALLY love their toasters." + icon_state = "techpriest" + hoodtype = /obj/item/clothing/head/hood/techpriest diff --git a/code/modules/clothing/suits/jobs.dm b/code/modules/clothing/suits/jobs.dm index 1119079e2a..73d253415d 100644 --- a/code/modules/clothing/suits/jobs.dm +++ b/code/modules/clothing/suits/jobs.dm @@ -34,6 +34,12 @@ body_parts_covered = UPPER_TORSO|LOWER_TORSO|LEGS|ARMS flags_inv = HIDEHOLSTER +//Command +/obj/item/clothing/suit/storage/cmddressjacket + name = "command dress jacket" + desc = "A fancy dress jacket made for command staff. Makes you feel in charge." + icon_state = "cmddressjacket" + //Chaplain /obj/item/clothing/suit/storage/hooded/chaplain_hoodie name = "chaplain hoodie" diff --git a/code/modules/clothing/suits/labcoat.dm b/code/modules/clothing/suits/labcoat.dm index 71cd7e81a6..18c399efbc 100644 --- a/code/modules/clothing/suits/labcoat.dm +++ b/code/modules/clothing/suits/labcoat.dm @@ -33,12 +33,6 @@ icon_state = "orange_labcoat" item_state_slots = list(slot_r_hand_str = "orange_labcoat", slot_l_hand_str = "orange_labcoat") -/obj/item/clothing/suit/storage/toggle/labcoat/green - name = "green labcoat" - desc = "A suit that protects against minor chemical spills. This one is green." - icon_state = "green_labcoat" - item_state_slots = list(slot_r_hand_str = "green_labcoat", slot_l_hand_str = "green_labcoat") - /obj/item/clothing/suit/storage/toggle/labcoat/yellow name = "yellow labcoat" desc = "A suit that protects against minor chemical spills. This one is yellow." @@ -51,6 +45,18 @@ icon_state = "pink_labcoat" item_state_slots = list(slot_r_hand_str = "pink_labcoat", slot_l_hand_str = "pink_labcoat") +/obj/item/clothing/suit/storage/toggle/labcoat/green + name = "green labcoat" + desc = "A suit that protects against minor chemical spills. This one is green." + icon_state = "green_labcoat" + item_state_slots = list(slot_r_hand_str = "green_labcoat", slot_l_hand_str = "green_labcoat") + +/obj/item/clothing/suit/storage/toggle/labcoat/mad + name = "The Mad's labcoat" + desc = "It makes you look capable of konking someone on the noggin and shooting them into space." + icon_state = "green_labcoat" + item_state_slots = list(slot_r_hand_str = "green_labcoat", slot_l_hand_str = "green_labcoat") + /obj/item/clothing/suit/storage/toggle/labcoat/cmo name = "chief medical officer's labcoat" desc = "Bluer than the standard model." @@ -58,17 +64,11 @@ item_state_slots = list(slot_r_hand_str = "cmo_labcoat", slot_l_hand_str = "cmo_labcoat") /obj/item/clothing/suit/storage/toggle/labcoat/cmoalt - name = "chief medical officer labcoat" + name = "chief medical officer's labcoat" desc = "A labcoat with command blue highlights." icon_state = "labcoat_cmoalt" item_state_slots = list(slot_r_hand_str = "cmo_labcoat", slot_l_hand_str = "cmo_labcoat") -/obj/item/clothing/suit/storage/toggle/labcoat/mad - name = "The Mad's labcoat" - desc = "It makes you look capable of konking someone on the noggin and shooting them into space." - icon_state = "labgreen" - item_state_slots = list(slot_r_hand_str = "green_labcoat", slot_l_hand_str = "green_labcoat") - /obj/item/clothing/suit/storage/toggle/labcoat/genetics name = "Geneticist labcoat" desc = "A suit that protects against minor chemical spills. Has a blue stripe on the shoulder." @@ -88,12 +88,24 @@ item_state_slots = list(slot_r_hand_str = "virologist_labcoat", slot_l_hand_str = "virologist_labcoat") armor = list(melee = 0, bullet = 0, laser = 0,energy = 0, bomb = 0, bio = 60, rad = 0) +/obj/item/clothing/suit/storage/toggle/labcoat/roboticist + name = "Roboticist labcoat" + desc = "More like an eccentric coat than a labcoat. Helps pass off bloodstains as part of the aesthetic. Comes with red shoulder pads." + icon_state = "labcoat_robo" + item_state_slots = list(slot_r_hand_str = "labcoat", slot_l_hand_str = "labcoat") + /obj/item/clothing/suit/storage/toggle/labcoat/science name = "Scientist labcoat" desc = "A suit that protects against minor chemical spills. Has a purple stripe on the shoulder." icon_state = "labcoat_tox" item_state_slots = list(slot_r_hand_str = "science_labcoat", slot_l_hand_str = "science_labcoat") +/obj/item/clothing/suit/storage/toggle/labcoat/rd + name = "research director's labcoat" + desc = "A flashy labcoat with purple markings. It belongs to the Research Director." + icon_state = "labcoat_rd" + item_state_slots = list(slot_r_hand_str = "science_labcoat", slot_l_hand_str = "science_labcoat") + /obj/item/clothing/suit/storage/toggle/labcoat/emt name = "EMT's labcoat" desc = "A dark blue labcoat with reflective strips for emergency medical technicians." diff --git a/code/modules/clothing/under/accessories/accessory_vr.dm b/code/modules/clothing/under/accessories/accessory_vr.dm index f476fa417a..98743d1ab8 100644 --- a/code/modules/clothing/under/accessories/accessory_vr.dm +++ b/code/modules/clothing/under/accessories/accessory_vr.dm @@ -282,6 +282,14 @@ item_state = "collar_pnk" overlay_state = "collar_pnk" +/obj/item/clothing/accessory/collar/cowbell + name = "cowbell collar" + desc = "A collar for your little pets... or the big ones." + icon_state = "collar_cowbell" + item_state = "collar_cowbell_overlay" + overlay_state = "collar_cowbell_overlay" + + /obj/item/clothing/accessory/collar/holo name = "Holo-collar" desc = "An expensive holo-collar for the modern day pet." @@ -369,7 +377,7 @@ icon_state = "holster_machete" slot = ACCESSORY_SLOT_WEAPON concealed_holster = 0 - can_hold = list(/obj/item/weapon/material/knife/machete) + can_hold = list(/obj/item/weapon/material/knife/machete, /obj/item/weapon/kinetic_crusher/machete) //sound_in = 'sound/effects/holster/sheathin.ogg' //sound_out = 'sound/effects/holster/sheathout.ogg' diff --git a/code/modules/clothing/under/jobs/medsci.dm b/code/modules/clothing/under/jobs/medsci.dm index 87346c6741..013e3d917f 100644 --- a/code/modules/clothing/under/jobs/medsci.dm +++ b/code/modules/clothing/under/jobs/medsci.dm @@ -174,6 +174,34 @@ icon_state = "scrubs" item_state_slots = list(slot_r_hand_str = "white", slot_l_hand_str = "white") +/obj/item/clothing/under/rank/paramedunidark + name = "dark paramedic uniform" + desc = "A dark jumpsuit for those brave souls who have to deal with a CMO who thinks they're the do everything person." + icon_state = "paramedicdark" + rolled_down = -1 + rolled_sleeves = -1 + +/obj/item/clothing/under/rank/parameduniskirtdark + name = "dark paramedic uniskirt" + desc = "A dark jumpskirt for those brave souls who have to deal with a CMO who thinks they're the do everything person." + icon_state = "paramedicdark_skirt" + rolled_down = -1 + rolled_sleeves = -1 + +/obj/item/clothing/under/rank/paramedunilight + name = "light paramedic uniform" + desc = "A light jumpsuit for those brave souls who have to deal with a CMO who thinks they're the do everything person." + icon_state = "paramediclight" + rolled_down = -1 + rolled_sleeves = -1 + +/obj/item/clothing/under/rank/parameduniskirtlight + name = "light paramedic uniskirt" + desc = "A light jumpskirt for those brave souls who have to deal with a CMO who thinks they're the do everything person." + icon_state = "paramediclight_skirt" + rolled_down = -1 + rolled_sleeves = -1 + /obj/item/clothing/under/rank/psych desc = "A basic white jumpsuit. It has turqouise markings that denote the wearer as a psychiatrist." name = "psychiatrist's jumpsuit" @@ -186,7 +214,6 @@ icon_state = "psychturtle" item_state_slots = list(slot_r_hand_str = "psyche", slot_l_hand_str = "psyche") rolled_sleeves = 0 - /* * Medsci, unused (i think) stuff */ diff --git a/code/modules/clothing/under/miscellaneous.dm b/code/modules/clothing/under/miscellaneous.dm index 0f2b43c380..562950f89a 100644 --- a/code/modules/clothing/under/miscellaneous.dm +++ b/code/modules/clothing/under/miscellaneous.dm @@ -565,6 +565,11 @@ desc = "A red and black dress fit for a countess." icon_state = "countess" +/obj/item/clothing/under/verglasdress + name = "verglas dress" + desc = "The modern twist on a forgotten pattern, the Verglas style utilizes comfortable velvet and silver white satin to create an otherworldly effect evocative of winter, or the void." + icon_state = "verglas_dress" + /* * wedding stuff */ @@ -884,6 +889,10 @@ Uniforms and such desc = "A flowery skirt that comes in a variety of colors." icon_state = "flowerskirt" +/obj/item/clothing/under/fashionminiskirt + name = "fashionable miniskirt" + desc = "An impractically short miniskirt allegedly making waves through the local fashion scene." + icon_state = "miniskirt_fashion" /* * swimsuit */ @@ -946,6 +955,12 @@ Uniforms and such desc = "No honest man would wear this abomination" icon_state = "mankini" +/obj/item/clothing/under/swimsuit/cowbikini + name = "cow print bikini" + desc = "A rather skimpy cow patterned swimsuit." + icon_state = "swim_cow" + + /* * pyjamas */ diff --git a/code/modules/economy/vending_machines.dm b/code/modules/economy/vending_machines.dm index 630d198128..ad3f52d488 100644 --- a/code/modules/economy/vending_machines.dm +++ b/code/modules/economy/vending_machines.dm @@ -1324,6 +1324,9 @@ /obj/item/weapon/storage/backpack/toxins = 5, /obj/item/weapon/storage/backpack/satchel/tox = 5 ) + contraband = list( + /obj/item/clothing/suit/storage/hooded/techpriest = 2 + ) req_log_access = access_hop has_logs = 1 diff --git a/code/modules/economy/vending_machines_vr.dm b/code/modules/economy/vending_machines_vr.dm index 2d05017ca8..7647df554c 100644 --- a/code/modules/economy/vending_machines_vr.dm +++ b/code/modules/economy/vending_machines_vr.dm @@ -847,6 +847,7 @@ /obj/item/weapon/storage/box/fluff/swimsuit/science = 5, /obj/item/weapon/storage/box/fluff/swimsuit/security = 5, /obj/item/weapon/storage/box/fluff/swimsuit/medical = 5, + /obj/item/weapon/storage/box/fluff/swimsuit/cowbikini = 5, /obj/item/clothing/under/utility = 5, /obj/item/clothing/under/utility/grey = 5, /obj/item/clothing/under/utility/blue = 5, @@ -1017,6 +1018,7 @@ /obj/item/weapon/storage/box/fluff/swimsuit/science = 50, /obj/item/weapon/storage/box/fluff/swimsuit/security = 50, /obj/item/weapon/storage/box/fluff/swimsuit/medical = 50, + /obj/item/weapon/storage/box/fluff/swimsuit/cowbikini = 50, /obj/item/clothing/under/utility = 50, /obj/item/clothing/under/utility/grey = 50, /obj/item/clothing/under/utility/blue = 50, @@ -1955,6 +1957,7 @@ /obj/item/weapon/storage/box/fluff/swimsuit/science = 5, /obj/item/weapon/storage/box/fluff/swimsuit/security = 5, /obj/item/weapon/storage/box/fluff/swimsuit/medical = 5, + /obj/item/weapon/storage/box/fluff/swimsuit/cowbikini = 5, /obj/item/clothing/under/utility = 5, /obj/item/clothing/under/utility/grey = 5, /obj/item/clothing/under/utility/blue = 5, diff --git a/code/modules/food/recipes_microwave.dm b/code/modules/food/recipes_microwave.dm index 95260876f4..c909c29fc5 100644 --- a/code/modules/food/recipes_microwave.dm +++ b/code/modules/food/recipes_microwave.dm @@ -339,7 +339,7 @@ I said no! result = /obj/item/weapon/reagent_containers/food/snacks/caramelapple /datum/recipe/twobread - reagents = list("wine" = 5) + reagents = list("redwine" = 5) items = list( /obj/item/weapon/reagent_containers/food/snacks/slice/bread, /obj/item/weapon/reagent_containers/food/snacks/slice/bread, @@ -796,7 +796,7 @@ I said no! result = /obj/item/weapon/reagent_containers/food/snacks/chilicheesefries /datum/recipe/risotto - reagents = list("wine" = 5, "rice" = 10, "spacespice" = 1) + reagents = list("redwine" = 5, "rice" = 10, "spacespice" = 1) fruit = list("mushroom" = 1) reagent_mix = RECIPE_REAGENT_REPLACE //Get that rice and wine outta here result = /obj/item/weapon/reagent_containers/food/snacks/risotto diff --git a/code/modules/food/recipes_microwave_ch.dm b/code/modules/food/recipes_microwave_ch.dm index e04d35b8eb..d52b6ee716 100644 --- a/code/modules/food/recipes_microwave_ch.dm +++ b/code/modules/food/recipes_microwave_ch.dm @@ -41,7 +41,7 @@ result = /obj/item/weapon/reagent_containers/food/snacks/pandenata /datum/recipe/tocino - reagents = list("sodiumchloride" = 5, "wine" = 5) + reagents = list("sodiumchloride" = 5, "redwine" = 5) items = list( /obj/item/weapon/reagent_containers/food/snacks/rawcutlet ) @@ -105,4 +105,4 @@ /obj/item/weapon/reagent_containers/food/snacks/spreads/butter ) result = /obj/item/weapon/reagent_containers/food/snacks/butterscotch - result_quantity = 2 \ No newline at end of file + result_quantity = 2 diff --git a/code/modules/hydroponics/seed_storage.dm b/code/modules/hydroponics/seed_storage.dm index 3ff2e48174..e1d1fafd11 100644 --- a/code/modules/hydroponics/seed_storage.dm +++ b/code/modules/hydroponics/seed_storage.dm @@ -43,41 +43,46 @@ ..() wires = new(src) if(!contraband_seeds.len) - contraband_seeds = pick(list( - list( - /obj/item/seeds/ambrosiavulgarisseed = 3, - /obj/item/seeds/greengrapeseed = 3, - /obj/item/seeds/reishimycelium = 2, - /obj/item/seeds/bloodtomatoseed = 1 - ), - list( - /obj/item/seeds/ambrosiavulgarisseed = 3, - /obj/item/seeds/plastiseed = 3, - /obj/item/seeds/kudzuseed = 2, - /obj/item/seeds/rose/blood = 1 - ), - list( - /obj/item/seeds/ambrosiavulgarisseed = 3, - /obj/item/seeds/amanitamycelium = 3, - /obj/item/seeds/libertymycelium = 2, - /obj/item/seeds/glowshroom = 1 - ), - list( - /obj/item/seeds/ambrosiavulgarisseed = 3, - /obj/item/seeds/glowberryseed = 3, - /obj/item/seeds/icepepperseed = 2, - /obj/item/seeds/bluetomatoseed = 1 - ), - list( - /obj/item/seeds/durian = 2, - /obj/item/seeds/ambrosiadeusseed = 1, - /obj/item/seeds/killertomatoseed = 1 - ), - list( - /obj/item/seeds/ambrosiavulgarisseed = 3, - /obj/item/seeds/random = 6 - ) - )) + contraband_seeds = pick( /// Some form of ambrosia in all lists. + prob(30);list( /// General produce + /obj/item/seeds/ambrosiavulgarisseed = 3, + /obj/item/seeds/greengrapeseed = 3, + /obj/item/seeds/icepepperseed = 2, + /obj/item/seeds/kudzuseed = 1 + ), + prob(30);list( ///Mushroom batch + /obj/item/seeds/ambrosiavulgarisseed = 1, + /obj/item/seeds/glowberryseed = 2, + /obj/item/seeds/libertymycelium = 1, + /obj/item/seeds/reishimycelium = 2, + /obj/item/seeds/sporemycelium = 1 + ), + prob(15);list( /// Survivalist + /obj/item/seeds/ambrosiadeusseed = 2, + /obj/item/seeds/redtowermycelium = 2, + /obj/item/seeds/vale = 2, + /obj/item/seeds/siflettuce = 2 + ), + prob(20);list( /// Cold plants + /obj/item/seeds/ambrosiavulgarisseed = 2, + /obj/item/seeds/thaadra = 2, + /obj/item/seeds/icepepperseed = 2, + /obj/item/seeds/siflettuce = 1 + ), + prob(10);list( ///Poison party + /obj/item/seeds/ambrosiavulgarisseed = 3, + /obj/item/seeds/surik = 1, + /obj/item/seeds/telriis = 1, + /obj/item/seeds/nettleseed = 2, + /obj/item/seeds/poisonberryseed = 1 + ), + prob(5);list( /// Extra poison party! + /obj/item/seeds/ambrosiainfernusseed = 1, + /obj/item/seeds/amauri = 1, + /obj/item/seeds/surik = 1, + /obj/item/seeds/deathberryseed = 1 /// Very ow. + ) + ) return /obj/machinery/seed_storage/process() diff --git a/code/modules/mining/kinetic_crusher.dm b/code/modules/mining/kinetic_crusher.dm new file mode 100644 index 0000000000..498f0b16bb --- /dev/null +++ b/code/modules/mining/kinetic_crusher.dm @@ -0,0 +1,408 @@ +// ported from Citadel-Station-13/Citadel-Station-13-RP#3015, basically all the work done by silicons +// thanks silicons + +/*********************Mining Hammer****************/ +/obj/item/weapon/kinetic_crusher + icon = 'icons/obj/mining_vr.dmi' + icon_state = "crusher" + item_state = "crusher0" + item_icons = list( + slot_l_hand_str = 'icons/mob/items/lefthand_melee_vr.dmi', + slot_r_hand_str = 'icons/mob/items/righthand_melee_vr.dmi' + ) + name = "proto-kinetic crusher" + desc = "An early design of the proto-kinetic accelerator, it is little more than an combination of various mining tools cobbled together, forming a high-tech club. \ + While it is an effective mining tool, it did little to aid any but the most skilled and/or suicidal miners against local fauna." + force = 0 //You can't hit stuff unless wielded + w_class = ITEMSIZE_LARGE + slot_flags = SLOT_BACK + throwforce = 5 + throw_speed = 4 +/* + armour_penetration = 10 + custom_materials = list(/datum/material/iron=1150, /datum/material/glass=2075) +*/ + hitsound = 'sound/weapons/bladeslice.ogg' + attack_verb = list("smashed", "crushed", "cleaved", "chopped", "pulped") + sharp = TRUE + edge = TRUE + // sharpness = SHARP_EDGED + action_button_name = "Toggle Light" + // actions_types = list(/datum/action/item_action/toggle_light) + // var/list/trophies = list() + var/charged = TRUE + var/charge_time = 15 + var/detonation_damage = 50 + var/backstab_bonus = 30 + /// does it have a light icon + var/integ_light_icon = TRUE + /// is the light on? + var/integ_light_on = FALSE + var/brightness_on = 7 + var/wielded = FALSE // track wielded status on item + /// is this emagged? (unlocks !!!FUN!!!) + var/emagged = 0 + /// Damage penalty factor to detonation damage to non simple mobs + var/human_damage_nerf = 0.25 + /// Damage penalty factor to backstab bonus damage to non simple mobs + var/human_backstab_nerf = 0.25 + /// damage buff for throw impacts + var/thrown_bonus = 35 + /// do we need to be wielded? + var/requires_wield = TRUE + /// do we have a charge overlay? + var/charge_overlay = TRUE + /// do we update item state? + var/update_item_state = FALSE + +/obj/item/weapon/kinetic_crusher/cyborg //probably give this a unique sprite later + desc = "An integrated version of the standard kinetic crusher with a grinded down axe head to dissuade mis-use against crewmen. Deals damage equal to the standard crusher against creatures, however." + force = 10 //wouldn't want to give a borg a 20 brute melee weapon unemagged now would we + detonation_damage = 60 + wielded = 1 + +/obj/item/weapon/kinetic_crusher/Initialize(mapload) + . = ..() + AddElement(/datum/element/conflict_checking, CONFLICT_ELEMENT_CRUSHER) + +/* +/obj/item/weapon/kinetic_crusher/Initialize() + . = ..() + if(requires_Wield) + RegisterSignal(src, COMSIG_TWOHANDED_WIELD, .proc/on_wield) + RegisterSignal(src, COMSIG_TWOHANDED_UNWIELD, .proc/on_unwield) + +/obj/item/weapon/kinetic_crusher/ComponentInitialize() + . = ..() + if(requires_wield) + AddComponent(/datum/component/butchering, 60, 110) //technically it's huge and bulky, but this provides an incentive to use it + AddComponent(/datum/component/two_handed, force_unwielded=0, force_wielded=20) +*/ + +/obj/item/weapon/kinetic_crusher/Destroy() + // QDEL_LIST(trophies) + return ..() + +/obj/item/weapon/kinetic_crusher/emag_act() + . = ..() + if(emagged) + return + emagged = TRUE + desc = desc + " The destabilizer module occasionally sparks and glows a menacing red." + +/obj/item/weapon/kinetic_crusher/proc/can_mark(mob/living/victim) + if(emagged) + return TRUE + return !ishuman(victim) && !issilicon(victim) + +/// triggered on wield of two handed item +/obj/item/weapon/kinetic_crusher/proc/on_wield(obj/item/source, mob/user) + wielded = TRUE + +/// triggered on unwield of two handed item +/obj/item/weapon/kinetic_crusher/proc/on_unwield(obj/item/source, mob/user) + wielded = FALSE + +/obj/item/weapon/kinetic_crusher/examine(mob/living/user) + . = ..() + . += "Mark a[emagged ? "nything": " creature"] with the destabilizing force, then hit them in melee to do [force + detonation_damage] damage." + . += "Does [force + detonation_damage + backstab_bonus] damage if the target is backstabbed, instead of [force + detonation_damage]." +/* + for(var/t in trophies) + var/obj/item/crusher_trophy/T = t + . += "It has \a [T] attached, which causes [T.effect_desc()]." +*/ + +/* +/obj/item/weapon/kinetic_crusher/attackby(obj/item/I, mob/living/user) + if(I.tool_behaviour == TOOL_CROWBAR) + if(LAZYLEN(trophies)) + to_chat(user, "You remove [src]'s trophies.") + I.play_tool_sound(src) + for(var/t in trophies) + var/obj/item/crusher_trophy/T = t + T.remove_from(src, user) + else + to_chat(user, "There are no trophies on [src].") + else if(istype(I, /obj/item/crusher_trophy)) + var/obj/item/crusher_trophy/T = I + T.add_to(src, user) + else + return ..() +*/ + +/obj/item/weapon/kinetic_crusher/attack(mob/living/target, mob/living/carbon/user) + if(!wielded && requires_wield) + to_chat(user, "[src] is too heavy to use with one hand.") + return + ..() + +/obj/item/weapon/kinetic_crusher/afterattack(atom/target, mob/living/user, proximity_flag, clickparams) + . = ..() +/* + if(istype(target, /obj/item/crusher_trophy)) + var/obj/item/crusher_trophy/T = target + T.add_to(src, user) +*/ + if(requires_wield && !wielded) + return + if(!proximity_flag && charged)//Mark a target, or mine a tile. + var/turf/proj_turf = user.loc + if(!isturf(proj_turf)) + return + var/obj/item/projectile/destabilizer/D = new /obj/item/projectile/destabilizer(proj_turf) +/* + for(var/t in trophies) + var/obj/item/crusher_trophy/T = t + T.on_projectile_fire(D, user) +*/ + D.preparePixelProjectile(target, user, clickparams) + D.firer = user + D.hammer_synced = src + playsound(user, 'sound/weapons/plasma_cutter.ogg', 100, 1) + D.fire() + charged = FALSE + update_icon() + addtimer(CALLBACK(src, .proc/Recharge), charge_time) + // * (user?.ConflictElementCount(CONFLICT_ELEMENT_CRUSHER) || 1 - tentatively commented out + return + if(proximity_flag && isliving(target)) + detonate(target, user) + +/obj/item/weapon/kinetic_crusher/proc/detonate(mob/living/L, mob/living/user, thrown = FALSE) + var/datum/modifier/crusher_mark/CM = L.get_modifier_of_type(/datum/modifier/crusher_mark) + if(!CM || CM.hammer_synced != src) + return + if(!QDELETED(L)) + L.remove_modifiers_of_type(/datum/modifier/crusher_mark) + new /obj/effect/temp_visual/kinetic_blast(get_turf(L)) + var/backstab_dir = get_dir(user, L) + var/def_check = L.getarmor(null, "bomb") + var/detonation_damage = src.detonation_damage * (!ishuman(L)? 1 : human_damage_nerf) + var/backstab_bonus = src.backstab_bonus * (!ishuman(L)? 1 : human_backstab_nerf) + var/thrown_bonus = thrown? (src.thrown_bonus * (!ishuman(L)? 1 : human_damage_nerf)) : 0 + if(thrown? (get_dir(src, L) & L.dir) : ((user.dir & backstab_dir) && (L.dir & backstab_dir))) + L.apply_damage(detonation_damage + backstab_bonus + thrown_bonus, BRUTE, blocked = def_check) + playsound(src, 'sound/weapons/Kenetic_accel.ogg', 100, 1) //Seriously who spelled it wrong + else + L.apply_damage(detonation_damage + thrown_bonus, BRUTE, blocked = def_check) + +/obj/item/weapon/kinetic_crusher/throw_impact(atom/hit_atom, speed) + . = ..() + if(!isliving(hit_atom)) + return + var/mob/living/L = hit_atom + if(L.has_modifier_of_type(/datum/modifier/crusher_mark)) + detonate(L, thrower, TRUE) + +/obj/item/weapon/kinetic_crusher/proc/Recharge() + if(!charged) + charged = TRUE + update_icon() + playsound(src.loc, 'sound/weapons/kenetic_reload.ogg', 60, 1) + +/obj/item/weapon/kinetic_crusher/ui_action_click(mob/user, actiontype) + integ_light_on = !integ_light_on + playsound(src, 'sound/weapons/empty.ogg', 100, TRUE) + update_brightness(user) + update_icon() + +/obj/item/weapon/kinetic_crusher/proc/update_brightness(mob/user = null) + if(integ_light_on) + set_light(brightness_on) + else + set_light(0) + +/obj/item/weapon/kinetic_crusher/update_icon() + . = ..() + cut_overlay("[icon_state]_uncharged") + cut_overlay("[icon_state]_lit") + if(charge_overlay) + if(!charged) + add_overlay("[icon_state]_uncharged") + if(integ_light_icon) + if(integ_light_on) + add_overlay("[icon_state]_lit") + +/* +/obj/item/weapon/kinetic_crusher/glaive + name = "proto-kinetic glaive" + desc = "A modified design of a proto-kinetic crusher, it is still little more of a combination of various mining tools cobbled together \ + and kit-bashed into a high-tech cleaver on a stick - with a handguard and a goliath hide grip. While it is still of little use to any \ + but the most skilled and/or suicidal miners against local fauna, it's an elegant weapon for a more civilized hunter." + + look gary there i am + - hatterhat +*/ + + +/obj/item/weapon/kinetic_crusher/machete + name = "proto-kinetic machete" + desc = "A scaled down version of a proto-kinetic crusher, used by people who don't want to lug around an axe-hammer." + icon_state = "glaive-machete" + item_icons = list( + slot_l_hand_str = 'icons/mob/items/lefthand_melee_vr.dmi', + slot_r_hand_str = 'icons/mob/items/righthand_melee_vr.dmi', + ) + item_state = "c-machete" + w_class = ITEMSIZE_SMALL + attack_verb = list("cleaved", "chopped", "pulped", "stabbed", "skewered") + force = 24 + can_cleave = TRUE + requires_wield = FALSE + // yeah yeah buff but polaris mobs are meatwalls. + backstab_bonus = 40 + detonation_damage = 26 + // meme option + thrown_bonus = 20 + update_item_state = FALSE + + +/obj/item/weapon/kinetic_crusher/machete/gauntlets + // did someone say single target damage + name = "\improper proto-kinetic gear" + desc = "A pair of scaled-down proto-kinetic crusher destabilizer modules shoved into gauntlets and greaves, used by those who wish to spit in the eyes of God." + hitsound = 'sound/weapons/resonator_blast.ogg' + embed_chance = 0 + icon_state = "crusher-hands" + item_state = "c-gauntlets" + attack_verb = list("bashed", "kicked", "punched", "struck", "axe kicked", "uppercut", "cross-punched", "jabbed", "hammerfisted", "roundhouse kicked") + integ_light_icon = FALSE + w_class = ITEMSIZE_HUGE + force = 30 + can_cleave = FALSE + requires_wield = TRUE + backstab_bonus = 55 + detonation_damage = 35 + var/obj/item/offhand/crushergauntlets/offhand + +/obj/item/weapon/kinetic_crusher/machete/gauntlets/equipped() + . = ..() + START_PROCESSING(SSprocessing, src) + +/obj/item/weapon/kinetic_crusher/machete/gauntlets/dropped(mob/user) + ready_toggle(TRUE) + STOP_PROCESSING(SSprocessing, src) + . = ..() + +/obj/item/weapon/kinetic_crusher/machete/gauntlets/Destroy() + . = ..() + STOP_PROCESSING(SSprocessing, src) + +/obj/item/weapon/kinetic_crusher/machete/gauntlets/attack_self(mob/user) + ready_toggle() + +/obj/item/weapon/kinetic_crusher/machete/gauntlets/process() + if(wielded) // are we supposed to be wielded + if(!offhand) // does our offhand exist + ready_toggle(TRUE) // no? well, shit + +/// toggles twohand. if forced is true, forces an unready state +/obj/item/weapon/kinetic_crusher/machete/gauntlets/proc/ready_toggle(var/forced = 0) + var/mob/living/M = loc + if(istype(M) && forced == 0) + if(M.can_wield_item(src) && src.is_held_twohanded(M)) + name = initial(name) + wielded = TRUE + to_chat(M, "You ready [src].") + var/obj/item/offhand/crushergauntlets/O = new(M) + O.name = "[name] - readied" + O.desc = "As much as you'd like to punch things with one hand, [src] is far too unwieldy for that." + O.linked = src + M.put_in_inactive_hand(O) + offhand = O + else + name = "[initial(name)] (unreadied)" + wielded = FALSE + to_chat(M, "You unready [src].") + if(offhand) + QDEL_NULL(offhand) + +/obj/item/offhand + icon = 'icons/obj/weapons.dmi' + icon_state = "offhand" + name = "offhand that shouldn't exist doo dee doo" + w_class = ITEMSIZE_NO_CONTAINER + // var/linked - redefine this wherever + +/obj/item/offhand/crushergauntlets + var/obj/item/weapon/kinetic_crusher/machete/gauntlets/linked + +/obj/item/offhand/crushergauntlets/dropped(mob/user as mob) + if(linked.wielded) + linked.ready_toggle(TRUE) + +/obj/item/weapon/kinetic_crusher/machete/gauntlets/rig + name = "mounted proto-kinetic gear" + var/obj/item/rig_module/gauntlets/storing_module + +/obj/item/weapon/kinetic_crusher/machete/gauntlets/rig/dropped(mob/user) + . = ..() + if(storing_module) + src.forceMove(storing_module) + storing_module.stored_gauntlets = src + user.visible_message( + "[user] retracts [src] with a click and a hiss.", + "You retract [src] with a click and a hiss.", + "You hear a click and a hiss." + ) + playsound(src, 'sound/items/helmetdeploy.ogg', 40, 1) + storing_module.active = FALSE + else + QDEL_NULL(src) + +/obj/item/weapon/kinetic_crusher/machete/dagger + name = "proto-kinetic dagger" + desc = "A scaled down version of a proto-kinetic machete, usually used in a last ditch scenario." + icon_state = "glaive-dagger" + item_icons = list( + slot_l_hand_str = 'icons/mob/items/lefthand_melee_vr.dmi', + slot_r_hand_str = 'icons/mob/items/righthand_melee_vr.dmi', + ) + item_state = "c-knife" + w_class = ITEMSIZE_SMALL + force = 15 + requires_wield = FALSE + charge_overlay = FALSE + backstab_bonus = 35 + detonation_damage = 25 + // woohoo + thrown_bonus = 35 + + +//destablizing force +/obj/item/projectile/destabilizer + name = "destabilizing force" + icon_state = "pulse1" + nodamage = TRUE + damage = 0 //We're just here to mark people. This is still a melee weapon. + damage_type = BRUTE + check_armour = "bomb" + range = 6 + accuracy = INFINITY // NO. + // log_override = TRUE + var/obj/item/weapon/kinetic_crusher/hammer_synced + +/obj/item/projectile/destabilizer/Destroy() + hammer_synced = null + return ..() + +/obj/item/projectile/destabilizer/on_hit(atom/target, blocked = FALSE) + if(isliving(target)) + var/mob/living/L = target + L.add_modifier(/datum/modifier/crusher_mark, 30 SECONDS, firer, TRUE) + var/target_turf = get_turf(target) + if(ismineralturf(target_turf)) + var/turf/simulated/mineral/M = target_turf + new /obj/effect/temp_visual/kinetic_blast(M) + M.GetDrilled(firer) + ..() + +/* +//trophies + +there would be any if we had some +but alas +- hatterhat +*/ + diff --git a/code/modules/mining/ore_redemption_machine/equipment_vendor.dm b/code/modules/mining/ore_redemption_machine/equipment_vendor.dm index c5589fa8b0..973bb21f5f 100644 --- a/code/modules/mining/ore_redemption_machine/equipment_vendor.dm +++ b/code/modules/mining/ore_redemption_machine/equipment_vendor.dm @@ -41,6 +41,8 @@ EQUIPMENT("Defense Equipment - Razor Drone Deployer", /obj/item/weapon/grenade/spawnergrenade/manhacks/station/locked, 1000), EQUIPMENT("Defense Equipment - Sentry Drone Deployer", /obj/item/weapon/grenade/spawnergrenade/ward, 1500), EQUIPMENT("Defense Equipment - Smoke Bomb", /obj/item/weapon/grenade/smokebomb, 100), + EQUIPMENT("Hybrid Equipment - Proto-Kinetic Dagger", /obj/item/weapon/kinetic_crusher/machete/dagger, 500), + EQUIPMENT("Hybrid Equipment - Proto-Kinetic Machete", /obj/item/weapon/kinetic_crusher/machete, 1000), EQUIPMENT("Durasteel Fishing Rod", /obj/item/weapon/material/fishing_rod/modern/strong, 7500), EQUIPMENT("Titanium Fishing Rod", /obj/item/weapon/material/fishing_rod/modern, 1000), EQUIPMENT("Fishing Net", /obj/item/weapon/material/fishing_net, 500), @@ -98,14 +100,15 @@ EQUIPMENT("Industrial Equipment - Sheet-Snatcher", /obj/item/weapon/storage/bag/sheetsnatcher, 500), ) prize_list["Hardsuit"] = list( - EQUIPMENT("Hardsuit - Control Module", /obj/item/weapon/rig/industrial/vendor, 2000), - EQUIPMENT("Hardsuit - Drill", /obj/item/rig_module/device/drill, 5000), - EQUIPMENT("Hardsuit - Intelligence Storage",/obj/item/rig_module/ai_container, 2500), - EQUIPMENT("Hardsuit - Maneuvering Jets", /obj/item/rig_module/maneuvering_jets, 1250), - EQUIPMENT("Hardsuit - Material Scanner", /obj/item/rig_module/vision/material, 500), - EQUIPMENT("Hardsuit - Ore Scanner", /obj/item/rig_module/device/orescanner, 1000), - EQUIPMENT("Hardsuit - Plasma Cutter", /obj/item/rig_module/device/plasmacutter, 800), - EQUIPMENT("Hardsuit - Smoke Bomb Deployer", /obj/item/rig_module/grenade_launcher/smoke,2000), + EQUIPMENT("Hardsuit - Control Module", /obj/item/weapon/rig/industrial/vendor, 2000), + EQUIPMENT("Hardsuit - Drill", /obj/item/rig_module/device/drill, 5000), + EQUIPMENT("Hardsuit - Intelligence Storage", /obj/item/rig_module/ai_container, 2500), + EQUIPMENT("Hardsuit - Maneuvering Jets", /obj/item/rig_module/maneuvering_jets, 1250), + EQUIPMENT("Hardsuit - Material Scanner", /obj/item/rig_module/vision/material, 500), + EQUIPMENT("Hardsuit - Ore Scanner", /obj/item/rig_module/device/orescanner, 1000), + EQUIPMENT("Hardsuit - Plasma Cutter", /obj/item/rig_module/device/plasmacutter, 800), + EQUIPMENT("Hardsuit - Smoke Bomb Deployer", /obj/item/rig_module/grenade_launcher/smoke, 2000), + EQUIPMENT("Hardsuit - Proto-Kinetic Gauntlets", /obj/item/rig_module/gauntlets, 2000), ) prize_list["Miscellaneous"] = list( EQUIPMENT("Absinthe", /obj/item/weapon/reagent_containers/food/drinks/bottle/absinthe, 125), diff --git a/code/modules/mining/ore_redemption_machine/survey_vendor.dm b/code/modules/mining/ore_redemption_machine/survey_vendor.dm index 330c484b46..c5a0100489 100644 --- a/code/modules/mining/ore_redemption_machine/survey_vendor.dm +++ b/code/modules/mining/ore_redemption_machine/survey_vendor.dm @@ -55,6 +55,8 @@ EQUIPMENT("Defense Equipment - Razor Drone Deployer", /obj/item/weapon/grenade/spawnergrenade/manhacks/station/locked, 100), EQUIPMENT("Defense Equipment - Sentry Drone Deployer", /obj/item/weapon/grenade/spawnergrenade/ward, 150), EQUIPMENT("Defense Equipment - Frontier Carbine", /obj/item/weapon/gun/energy/locked/frontier/carbine, 750), + EQUIPMENT("Hybrid Equipment - Proto-Kinetic Dagger", /obj/item/weapon/kinetic_crusher/machete/dagger, 75), + EQUIPMENT("Hybrid Equipment - Proto-Kinetic Machete", /obj/item/weapon/kinetic_crusher/machete, 250), EQUIPMENT("Fishing Net", /obj/item/weapon/material/fishing_net, 50), EQUIPMENT("Titanium Fishing Rod", /obj/item/weapon/material/fishing_rod/modern, 100), EQUIPMENT("Durasteel Fishing Rod", /obj/item/weapon/material/fishing_rod/modern/strong, 750), diff --git a/code/modules/mob/_modifiers/crusher_mark.dm b/code/modules/mob/_modifiers/crusher_mark.dm new file mode 100644 index 0000000000..9af2980624 --- /dev/null +++ b/code/modules/mob/_modifiers/crusher_mark.dm @@ -0,0 +1,43 @@ +/datum/modifier/crusher_mark + name = "destabilized" + desc = "You've been struck by a destabilizing bolt. By all accounts, this is probably a bad thing." + stacks = MODIFIER_STACK_EXTEND + on_created_text = "You feel destabilized." + on_expired_text = "You feel stable again." + var/mutable_appearance/marked_underlay + var/obj/item/weapon/kinetic_crusher/hammer_synced + +/* +/datum/modifier/New(var/new_holder, var/new_origin) + holder = new_holder + if(new_origin) + origin = weakref(new_origin) + else // We assume the holder caused the modifier if not told otherwise. + origin = weakref(holder) + ..() +/mob/living/proc/add_modifier(var/modifier_type, var/expire_at = null, var/mob/living/origin = null, var/suppress_failure = FALSE) +*/ + +/datum/modifier/crusher_mark/New(var/new_holder, var/new_origin) + . = ..() + if(isliving(new_origin)) + var/mob/living/origin = new_origin + var/obj/item/weapon/kinetic_crusher/to_sync = locate(/obj/item/weapon/kinetic_crusher) in origin + if(to_sync) + hammer_synced = to_sync + if(hammer_synced? hammer_synced.can_mark(holder) : TRUE) + marked_underlay = mutable_appearance('icons/effects/effects.dmi', "shield2") + marked_underlay.pixel_x = -holder.pixel_x + marked_underlay.pixel_y = -holder.pixel_y + holder.underlays += marked_underlay + +/datum/modifier/crusher_mark/Destroy() + hammer_synced = null + if(holder) + holder.underlays -= marked_underlay + QDEL_NULL(marked_underlay) + return ..() + +/datum/modifier/crusher_mark/on_expire() + holder.underlays -= marked_underlay //if this is being called, we should have a holder at this point. + ..() \ No newline at end of file diff --git a/code/modules/mob/living/carbon/human/emote.dm b/code/modules/mob/living/carbon/human/emote.dm index a8179153d4..14d79fee30 100644 --- a/code/modules/mob/living/carbon/human/emote.dm +++ b/code/modules/mob/living/carbon/human/emote.dm @@ -6,6 +6,7 @@ var/list/_human_default_emotes = list( /decl/emote/audible/synth/confirm, /decl/emote/audible/synth/deny, /decl/emote/audible/synth/scary, + /decl/emote/audible/synth/dwoop, /decl/emote/visible/nod, /decl/emote/visible/shake, /decl/emote/visible/shiver, diff --git a/code/modules/mob/living/silicon/pai/death.dm b/code/modules/mob/living/silicon/pai/death.dm index 01650cc4b2..4989cecace 100644 --- a/code/modules/mob/living/silicon/pai/death.dm +++ b/code/modules/mob/living/silicon/pai/death.dm @@ -1,4 +1,5 @@ /mob/living/silicon/pai/death(gibbed) + release_vore_contents() if(card) card.removePersonality() //if(gibbed) //VOREStation Edit Start. This prevents pAIs from joining back into their card after the card's killed diff --git a/code/modules/mob/living/silicon/pai/pai_vr.dm b/code/modules/mob/living/silicon/pai/pai_vr.dm index c8ab1d7e07..d5f989b67e 100644 --- a/code/modules/mob/living/silicon/pai/pai_vr.dm +++ b/code/modules/mob/living/silicon/pai/pai_vr.dm @@ -25,12 +25,12 @@ /mob/living/silicon/pai/update_icon() //Some functions cause this to occur, such as resting ..() update_fullness_pai() - + if(!people_eaten && !resting) icon_state = "[chassis]" //Using icon_state here resulted in quite a few bugs. Chassis is much less buggy. else if(!people_eaten && resting) icon_state = "[chassis]_rest" - + // Unfortunately not all these states exist, ugh. else if(people_eaten && !resting) if("[chassis]_full" in cached_icon_states(icon)) @@ -81,3 +81,7 @@ chassis = possible_chassis[choice] verbs |= /mob/living/proc/hide update_icon() +// Release belly contents before being gc'd! +/mob/living/silicon/pai/Destroy() + release_vore_contents() + return ..() \ No newline at end of file diff --git a/code/modules/mob/living/simple_mob/hands.dm b/code/modules/mob/living/simple_mob/hands.dm index 9d869df631..a7aab1bee8 100644 --- a/code/modules/mob/living/simple_mob/hands.dm +++ b/code/modules/mob/living/simple_mob/hands.dm @@ -135,13 +135,6 @@ to_chat(src, "Your [hand_form] are not fit for use of \the [display_name].") return humanoid_hands -/mob/living/simple_mob/drop_from_inventory(var/obj/item/W, var/atom/target = null) - . = ..(W, target) - if(!target) - target = src.loc - if(.) - W.forceMove(src.loc) - /mob/living/simple_mob/is_holding_item_of_type(typepath) for(var/obj/item/I in list(l_hand, r_hand)) if(istype(I, typepath)) diff --git a/code/modules/mob/living/simple_mob/on_click.dm b/code/modules/mob/living/simple_mob/on_click.dm index 74b0236c13..9707e3b01d 100644 --- a/code/modules/mob/living/simple_mob/on_click.dm +++ b/code/modules/mob/living/simple_mob/on_click.dm @@ -13,7 +13,9 @@ switch(a_intent) if(I_HELP) - if(isliving(A)) + + var/mob/living/L = A + if(istype(L) && (!has_hands || !L.attempt_to_scoop(src))) if(src.zone_sel.selecting == BP_GROIN) //CHOMPEdit if(src.vore_bellyrub(A)) return @@ -23,7 +25,7 @@ if(can_special_attack(A) && special_attack_target(A)) return - else if(melee_damage_upper == 0 && istype(A,/mob/living)) + else if(melee_damage_upper == 0 && isliving(A)) custom_emote(1,"[pick(friendly)] \the [A]!") else @@ -48,4 +50,4 @@ return if(projectiletype) - shoot_target(A) \ No newline at end of file + shoot_target(A) diff --git a/code/modules/mob/living/simple_mob/simple_mob.dm b/code/modules/mob/living/simple_mob/simple_mob.dm index 8c1f02f86b..bef26d92b6 100644 --- a/code/modules/mob/living/simple_mob/simple_mob.dm +++ b/code/modules/mob/living/simple_mob/simple_mob.dm @@ -162,6 +162,7 @@ var/limb_icon // Used for if the mob can drop limbs. Overrides the icon cache key, so it doesn't keep remaking the icon needlessly. var/limb_icon_key + var/understands_common = TRUE //VOREStation Edit - Makes it so that simplemobs can understand galcomm without being able to speak it. /mob/living/simple_mob/Initialize() verbs -= /mob/verb/observe @@ -290,3 +291,10 @@ hud_list[STATUS_HUD] = gen_hud_image(buildmode_hud, src, "ai_0", plane = PLANE_BUILDMODE) hud_list[LIFE_HUD] = gen_hud_image(buildmode_hud, src, "ais_1", plane = PLANE_BUILDMODE) add_overlay(hud_list) + +//VOREStation Add Start Makes it so that simplemobs can understand galcomm without being able to speak it. +/mob/living/simple_mob/say_understands(var/mob/other, var/datum/language/speaking = null) + if(understands_common && speaking?.name == LANGUAGE_GALCOM) + return TRUE + return ..() +//Vorestation Add End \ No newline at end of file diff --git a/code/modules/mob/living/simple_mob/subtypes/animal/alien animals/catslug.dm b/code/modules/mob/living/simple_mob/subtypes/animal/alien animals/catslug.dm new file mode 100644 index 0000000000..48b3279d2a --- /dev/null +++ b/code/modules/mob/living/simple_mob/subtypes/animal/alien animals/catslug.dm @@ -0,0 +1,199 @@ +//No relation to slugcat :) + +/datum/category_item/catalogue/fauna/catslug + name = "Alien Wildlife - Catslug" + desc = "The catslug is an omnivorous terrestrial creature.\ + Exhibiting properties of both a cat and a slug (hence its name)\ + it moves somewhat awkwardly. However, the unique qualities of\ + its body make it exceedingly flexible and smooth, allowing it to\ + wiggle into and move effectively in even extremely tight spaces.\ + Additionally, it has surprisingly capable hands, and moves quite\ + well on two legs or four. Caution is advised when interacting\ + with these creatures, they are quite intelligent, and proficient\ + tool users." + value = CATALOGUER_REWARD_MEDIUM + +/mob/living/simple_mob/vore/alienanimals/catslug + name = "catslug" + desc = "A noodley bodied creature with thin arms and legs, and gloomy dark eyes." + tt_desc = "Mollusca Feline" + icon_state = "catslug" + icon_living = "catslug" + icon_dead = "catslug_dead" + icon_rest = "catslug_rest" + icon = 'icons/mob/alienanimals_x32.dmi' + + faction = "catslug" + maxHealth = 50 + health = 50 + movement_cooldown = 2 + meat_amount = 2 + meat_type = /obj/item/weapon/reagent_containers/food/snacks/meat + + response_help = "hugs" + response_disarm = "rudely paps" + response_harm = "punches" + + harm_intent_damage = 2 + melee_damage_lower = 2 + melee_damage_upper = 5 + + has_hands = TRUE + mob_size = MOB_MEDIUM + friendly = list("hugs") + + catalogue_data = list(/datum/category_item/catalogue/fauna/catslug) + ai_holder_type = /datum/ai_holder/simple_mob/melee/evasive/catslug + player_msg = "You have escaped the foul weather, into this much more pleasant place. You are an intelligent creature capable of more than most think. You can pick up and use many things, and even carry some of them with you into the vents, which you can use to move around quickly. You're quiet and capable, you speak with your hands and your deeds!
- - - - -
Keep in mind, your goal should generally be to survive. You're expected to follow the same rules as everyone else, so don't go self antagging without permission from the staff team, but you are able and capable of defending yourself from those who would attack you for no reason." + + has_langs = list("Sign Language") + + var/heal_countdown = 0 + var/picked_color = FALSE + + can_enter_vent_with = list( + /obj/item/weapon/implant, + /obj/item/device/radio/borg, + /obj/item/weapon/holder, + /obj/machinery/camera, + /obj/belly, + /obj/screen, + /atom/movable/emissive_blocker, + /obj/item/weapon/material, + /obj/item/weapon/melee, + /obj/item/stack/material, + /obj/item/weapon/tool, + /obj/item/weapon/reagent_containers/food, + /obj/item/weapon/coin, + /obj/item/weapon/aliencoin, + /obj/item/weapon/ore + ) + + vore_active = 1 + vore_capacity = 1 + vore_bump_chance = 1 + vore_ignores_undigestable = 0 + vore_default_mode = DM_DIGEST + vore_icons = SA_ICON_LIVING + vore_stomach_name = "Stomach" + vore_default_contamination_flavor = "Wet" + vore_default_contamination_color = "grey" + vore_default_item_mode = IM_DIGEST + + +/mob/living/simple_mob/vore/alienanimals/catslug/init_vore() + ..() + var/obj/belly/B = vore_selected + B.name = "stomach" + B.desc = "The hot slick gut of a catslug!! Copious slime smears over you as you’re packed away into the gloom and oppressive humidity of this churning gastric sac. The pressure around you is intense, the squashy flesh bends and forms to your figure, clinging to you insistently! There’s basically no free space at all as your ears are filled with the slick slide of flesh against flesh and the burbling of gastric juices glooping all around you. The thumping of a heart booms from somewhere nearby, making everything pulse in against you in time with it! This is it! You’ve been devoured by a catslug!!!" + B.mode_flags = 40 + B.belly_fullscreen = "yet_another_tumby" + B.digest_brute = 0.5 + B.digest_burn = 0.5 + B.digestchance = 10 + B.absorbchance = 1 + B.escapechance = 15 + +/datum/ai_holder/simple_mob/melee/evasive/catslug + hostile = FALSE + cooperative = FALSE + retaliate = TRUE + speak_chance = 0 + wander = TRUE + +/mob/living/simple_mob/vore/alienanimals/catslug/Initialize() + . = ..() + verbs += /mob/living/proc/ventcrawl + verbs += /mob/living/proc/hide + verbs += /mob/living/simple_mob/vore/alienanimals/catslug/proc/catslug_color + +/mob/living/simple_mob/vore/alienanimals/catslug/attackby(var/obj/item/weapon/reagent_containers/food/snacks/O as obj, var/mob/user as mob) + if(!istype(O, /obj/item/weapon/reagent_containers/food/snacks)) + return ..() + if(resting) + to_chat(user, "\The [src] is napping, and doesn't respond to \the [O].") + return + if(nutrition >= max_nutrition) + if(user == src) + to_chat(src, "You're too full to eat another bite.") + return + to_chat(user, "\The [src] seems too full to eat.") + return + var/nutriment_amount = O.reagents?.get_reagent_amount("nutriment") //does it have nutriment, if so how much? + var/protein_amount = O.reagents?.get_reagent_amount("protein") //does it have protein, if so how much? + var/glucose_amount = O.reagents?.get_reagent_amount("glucose") //does it have glucose, if so how much? + var/yum = nutriment_amount + protein_amount + glucose_amount + if(yum) + yum = (yum * 20) / 3 + adjust_nutrition(yum) //add the nutriment! + O.bitecount ++ + if(O.bitecount >= 3) + user.drop_from_inventory(O) + qdel(O) + visible_message("\The [src] eats \the [O].") + else + to_chat(user, "\The [src] takes a bite of \the [O].") + if(user != src) + to_chat(user, "\The [user] feeds \the [O] to you.") + playsound(src, 'sound/items/eatfood.ogg', 75, 1) + +/mob/living/simple_mob/vore/alienanimals/catslug/Life() + . = ..() + if(nutrition < 150) + return + if(health == maxHealth) + return + if(heal_countdown > 0) + heal_countdown -- + return + if(resting) + if(bruteloss > 0) + adjustBruteLoss(-10) + else if(fireloss > 0) + adjustFireLoss(-10) + nutrition -= 50 + heal_countdown = 5 + return + if(bruteloss > 0) + adjustBruteLoss(-1) + else if(fireloss > 0) + adjustFireLoss(-1) + nutrition -= 5 + heal_countdown = 5 + +/mob/living/simple_mob/vore/alienanimals/catslug/Login() //If someone plays as us let's just be a passive mob in case accidents happen if the player D/Cs + . = ..() + ai_holder.hostile = FALSE + ai_holder.wander = FALSE + +/mob/living/simple_mob/vore/alienanimals/catslug/proc/catslug_color() + set name = "Pick Color" + set category = "Abilities" + set desc = "You can set your color!" + if(picked_color) + to_chat(src, "You have already picked a color! If you picked the wrong color, ask an admin to change your picked_color variable to 0.") + return + var/newcolor = input(usr, "Choose a color.", "", color) as color|null + if(newcolor) + color = newcolor + picked_color = TRUE + +/datum/ai_holder/simple_mob/melee/evasive/catslug/handle_wander_movement() + if(holder.client) + return + if(holder.resting) + if(prob(5)) + holder.lay_down() + return + if(prob(0.5)) + holder.lay_down() + return + return ..() + +/datum/ai_holder/simple_mob/melee/evasive/catslug/on_hear_say(mob/living/speaker, message) + if(holder.client) + return + if(!speaker.client) + return + if(findtext(message, "psps") || stance == STANCE_IDLE) + set_follow(speaker, follow_for = 5 SECONDS) diff --git a/code/modules/mob/living/simple_mob/subtypes/animal/alien animals/teppi.dm b/code/modules/mob/living/simple_mob/subtypes/animal/alien animals/teppi.dm new file mode 100644 index 0000000000..59ab8e7585 --- /dev/null +++ b/code/modules/mob/living/simple_mob/subtypes/animal/alien animals/teppi.dm @@ -0,0 +1,1194 @@ +//formerly meat things +//I made these up. They aren't deliberately based on, or supposed to be anything in particular. +//They came out kind of goat-ish but that wasn't intentional. I was just going for some cute thing you could +//take care of and/or kill for meat. +//I made them to be a part of the 'low tech survival' part of the game. You can use them to obtain a relatively +//unlimited amount of meat, wool, hide, bone, and COMPANIONSHIP without the need for machines or power... hopefully. +//There's no real story behind them, they're semi-intelligent wild alien animals with a somewhat mild temperament. +//They'll beat you up if you're mean to them, they have preferences for food, affection, and the ability +//to form opinions of others. Or as close to those things as I could get with my tiny creature brain and byond. +//They're TOUGH, but pretty easy to exploit for your needs if you pay attention to them and use your head. +//They also come in a variety of colors and markings, and those factors can be kind of manipulated through controlled breeding. +//They basically do all their funny things based on nutrition, so, if you feed them and like, put them near eachother +//they do what they do when they feel like it. + +//Also they eat you and all their vore related text is custom because I'm a shameless vore idiot +//And their stomach defaults to drain, so, dunking people into there will actually help them out without (immediately) killing people SO LIKE +//you know. Feed people to them or whatever, it's cool. People getting eaten has a tangible positive mechanical impact. So do it. + +/////////////////TO DO (if I ever learn how/someone ever feels like it)////////////////////////////// +//>seek food nearby to eat, including players with the appropriate settings. +//>give baby teppi a holder thingy so you can pick them up and carry them around +//>give adult teppi the ability to be ridden at high affinity +//>give adult teppi the ability to be equipped with a bag or something, so they can carry things for you +//>baby teppi can ventcrawl when AI controlled (so they fade out, and then appear at a random vent on the Z level) +//>make it so that teppi size is a thing that can be influenced by breeding +//>make it so the teppi are better at following people they really like around without also disabling the other things that their AI does (like resting and speaking) +//>make it so that teppi gains affinity for feeding people to them WITHOUT ALSO introducing a way for people to game the system by spamclicking +//>make it so that when feeding people to the teppi you don't get a choice where to send them unless the teppi is controlled by the player (since they have a special interaction for choosing where to send people that they eat) + +//stolen from chickens +GLOBAL_VAR_CONST(max_teppi, 50) // How many teppi CAN we have? +GLOBAL_VAR_INIT(teppi_count, 0) // How mant teppi DO we have? + +/datum/category_item/catalogue/fauna/teppi + name = "Alien Wildlife - Teppi" + desc = "Teppi are large omnivorous quadrupeds with long fur.\ + Unlike many horned mammals, Teppi have developed paws with four toes rather than hooves.\ + This coupled with a thick, powerful tail makes them quite capable and balanced on many\ + kinds of terrain. A recently discovered species, their origins are something of a\ + mystery, but they have been discovered in more different regions of space with no apparent\ + connection to one another. Teppi are known to reproduce and grow rather quickly, which if\ + left unchecked can lead to serious problems for local ecology.\ + Teppi are very hardy, engaging them in combat is not recommended.\ + Teppi can be a good source of protein and materials for crafts and clothing in emergency\ + situations. They are not especially picky eaters, and have a rather mild temperament.\ + A pair of well fed Teppi can rather quickly become a small horde, so it is generally\ + advised to keep an eye on their numbers." + value = CATALOGUER_REWARD_MEDIUM + +/mob/living/simple_mob/vore/alienanimals/teppi + name = "teppi" + desc = "A large and furry creature, sporting two thick horns and a very sturdy tail. It has four toes on each paw." + tt_desc = "Ipsumollis Velodigium" //I mashed some latin words together. This is nonsense, but it comes from 'very soft furred monster' + //which I know is not how this kind of thing should honestly go but it's a weird future alien creature MANNNNNNN + icon_state = "teppi" + icon_living = "body_base" + icon_dead = "body_dead" + icon_rest = "body_rest" + icon = 'icons/mob/alienanimals_x64.dmi' + pixel_x = -16 + default_pixel_x = -16 + + faction = "teppi" + maxHealth = 600 + health = 600 + movement_cooldown = 2 + meat_amount = 10 + meat_type = /obj/item/weapon/reagent_containers/food/snacks/meat + + response_help = "pets" + response_disarm = "rudely paps" + response_harm = "punches" + + harm_intent_damage = 2 + melee_damage_lower = 2 + melee_damage_upper = 10 + + min_oxy = 2 + max_oxy = 0 + min_tox = 0 + max_tox = 15 + min_co2 = 0 + max_co2 = 50 + min_n2 = 0 + max_n2 = 0 + minbodytemp = 150 + maxbodytemp = 400 + unsuitable_atoms_damage = 0.5 + catalogue_data = list(/datum/category_item/catalogue/fauna/teppi) + vis_height = 64 + + var/affinity = list() + var/allergen_preference + var/allergen_unpreference + var/body_color + var/marking_color + var/horn_color + var/eye_color + var/skin_color + var/item_type + var/item_color + var/marking_type + var/horn_type + var/static/list/overlays_cache = list() + var/inherit_allergen = FALSE + var/inherit_colors = FALSE + var/teppi_wool = FALSE + var/amount_grown = 0 + var/teppi_adult = TRUE + var/friend_zone //where friends go when we eat them +// var/teppi_id //This is all for anti-incest business, which I might finish eventually, but am not sure if it's really deisrable right now. +// var/mom_id +// var/dad_id + var/baby_countdown = 0 + var/breedable = FALSE + var/prevent_breeding = FALSE + var/petcount = 0 + var/wantpet = 0 + var/affection_factor = 1 //Some Teppi are more happy to be loved on than others. + var/teppi_warned = FALSE + var/heal_countdown = 5 + var/teppi_mutate = FALSE //Allows Teppi to get their children's colors scrambled, and possibly other things later on! + + attacktext = list("nipped", "chomped", "bonked", "stamped on") + attack_sound = 'sound/voice/teppi/roar.ogg' // make a better one idiot + friendly = list("snoofs", "nuzzles", "nibbles", "smooshes on") + + ai_holder_type = /datum/ai_holder/simple_mob/teppi + + mob_size = MOB_LARGE + + has_langs = list("Teppi") + say_list_type = /datum/say_list/teppi + player_msg = "Teppi are large omnivorous quadrupeds. You have four toes on each paw, a long, strong tail, and are quite tough and powerful. You’re a lot more intimidating than you are actually harmful though. Your kind are ordinarily rather passive, only really rising to violence when someone does violence to you or others like you. You’re not stupid though, you can commiunicate with others of your kind, and form bonds with those who are kind to you, be they Teppi or otherwise.
- - - - -
While you may have access to galactic common, this is purely meant for making it so you can understand people in an OOC manner, for facilitating roleplay. You almost certainly should not be speaking to people or roleplaying as though you understand everything everyone says perfectly, but it's not unreasonable to be able to intuit intent and such through people's tones when they speak. Teppi are kind of smart, but they are animals, and should be roleplayed as such. ADDITIONALLY, you have the ability to produce offspring if you're well fed enough every once in a while, and the ability to disable this from happening to you. These verbs exist for to preserve the mechanical functionality of the mob you are playing. You should be aware of your surroundings when you use this verb, and NEVER use it to prefbreak or be disruptive. If in doubt, don't use it. Also, to note, AI Teppi will never initiate breeding with player Teppi." + loot_list = list(/obj/item/weapon/bone/horn = 100) + internal_organs = list(\ + /obj/item/organ/internal/brain,\ + /obj/item/organ/internal/heart,\ + /obj/item/organ/internal/liver,\ + /obj/item/organ/internal/stomach,\ + /obj/item/organ/internal/intestine,\ + /obj/item/organ/internal/lungs\ + ) + + butchery_loot = list(\ + /obj/item/stack/animalhide = 3\ + ) + +/////////////////////////////////////// Vore stuff/////////////////////////////////////////// + + swallowTime = 1 SECONDS + vore_active = 1 + vore_capacity = 3 + vore_bump_chance = 1 + vore_bump_emote = "greedily homms at" + vore_ignores_undigestable = 0 + vore_default_mode = DM_DRAIN + vore_icons = SA_ICON_LIVING + vore_stomach_name = "Stomach" + vore_default_contamination_flavor = "Wet" + vore_default_contamination_color = "grey" + vore_default_item_mode = IM_DIGEST + +/mob/living/simple_mob/vore/alienanimals/teppi/init_vore() + ..() + var/obj/belly/B = vore_selected + B.name = "stomach" + B.desc = "The heat of the roiling flesh around you bakes into you immediately as you’re cast into the gloom of a Teppi’s primary gastric chamber. The undulations are practically smothering, clinging to you and grinding you all over as the Teppi continues about its day. The walls are heavy against you, so it’s really difficult to move at all, while the heart of this creature pulses rhythmically somewhere nearby, and you can feel the throb of its pulse in the doughy squish pressing up against you. Your figure sinks a ways into the flesh as it presses in, wrapping limbs up between countless slick folds and kneading waves. It’s not long before you’re positively soaked in a thin layer of slime as you’re rocked and squeezed and jostled in the stomach of your captor." + B.mode_flags = 40 + B.belly_fullscreen = "yet_another_tumby" + B.digest_brute = 0.05 + B.digest_burn = 0.05 + B.digestchance = 5 + B.absorbchance = 1 + B.escapechance = 15 + + B.emote_lists[DM_DRAIN] = list( + "The walls press in heavily over you, holding you tightly and grinding, churning against your body powerfully!! You can feel %pred’s heartbeat through the flesh, pounding in your ears, and the groaning gurgles of the gastric chamber rolling around you, eagerly pressing in against you.", + "The squeezing touch of the practically molten walls form to your figure, pressing in close and gliding across the shapes of your body, pressing, bending, and churning you casually! The intensity of it all is almost hard to comprehend. It is not painful, so much as just, almost completely overpowering, exhausting...", + "The gurgling bubbling sounds of %pred’s body drown out much of everything else as you’re submerged in the rolling waves of wrinkled belly flesh. You can hear the flesh stretch and shift as %pred moves. The whooshing of %pred’s breath catches your attention now and then, and how things seem to get tighter for you when the whoosh draws in, squeezing you that much more.", + "The creak of muscle and bone containing you sounds through the sloppy flesh pressed in against you as %pred moves. Your body is forced into a tighter curl as %belly churns over you, forming to take up any free space. This hot, humid organic gloom seems to be totally focused on you, working hard to make use of you however it can...", + "It’s so hard to move with all the heavy flesh pressing in on you, wearing you down and making it that much harder to move as the moments pass. The squashy walls form to your figure and lets your weight sink in quite a ways before the tension builds. An idle flex of the muscles beyond shoves you back into place, and the cycle begins again.", + "%pred’s %belly rolls over you heavily a few times, burying you briefly in an intense hold and shoving you to the back end of the chamber. There’s no free space, just powerful squeezes and slimy squelches! The wrinkly walls ripple over you powerfully as your body is slowly churned from one end to the other!", + "What little air there is in here is so thick that you could cut it with a knife, HOT and humid and just totally oppressive. The throbbing bodily motions quake through you as you’re jostled and tossed around amid rolling waves of wrinkled flesh, oozing with a thin slime. %pred’s heart pulses in your ear and all around you as you’re contained completely within the %belly, confined to the pitch black, intimate space, hidden away amid %pred.", + "The chaotic pressing and churning all around you makes it hard to get your bearings. The sloppy presses of hot heavy flesh shove you here and squeeze you there, never leaving you alone as they enjoy you. It’s hard to get ANY space to yourself, and to do so, you usually have to really fight for it, and sacrifice some other part of your body to the squeezing gropes of %pred’s insistent %belly.", + "Thick rolling waves of flesh batter against and form to you as you’re smothered briefly against the doughy walls of %pred’s %belly. The hold goes on for a little too long, but just as you start to worry, it eases up a little bit and gives you an ounce of space. … For about three seconds, before the chamber collapses in on you again, grinding and squeezing and churning you around idly. The grumbling symphony of that gut working on you is impossible to tune out as the burbling sound of slick flesh and goopy insides fill your ears.", + "The walls that separate you from the outside world are thick, and not just because of the few inches of doughy, stretchy %belly lining that’s containing you immediately. Beyond that there are other organs unseen, glooping and churning and glorgling outside of your chamber, then there are layers of muscle and bone, and finally a thick hide and ample fluff. This all means that, for your part, you’re likely a small shifting shape under that fluffy exterior, packed away deep at the core of all of those layers, so far from the outside world as that chamber grinds and smothers over you, smearing you in slime and keeping you nice and tucked deep into the rumbling darkness.") + + B.emote_lists[DM_DIGEST] = list( + "The walls close in on you in thick, heavy waves, smearing you in a thick slime. Working hard to churn over your figure intensely. The heat of the chamber soaks into you along with the fluids you’re being lathered in. A telling tingle sets in the longer you are exposed to those fluids, while no part of you is spared from the probing churns and deep kneads of %pred’s insistent %belly. . .", + "The doughy press of %pred’s %belly almost seems to feel over you, actively seeking you within that gloomy humid chamber. The sloppy burbling of that thick flesh gliding and smearing over you is impossible to ignore, the sound of your own body slapping and slurping amid those active pulsing folds and the bubbling slime a sign that you are indeed held deep within the organic confines of another’s hungry gut… and it’s focused on you.", + "The sounds outside of the %belly are difficult to make out. You can hear little creaks and bumps against %pred’s hide though, the sound of the skin stretching to form to your predator’s shape, and to contain you deep within. Of course, the slurping, squishing, and GURGLING of that gut working around you is always more immediately apparent, along with the heavy throbbing of %pred’s heart.", + "You find that as you’re rocked and ground amid the gurgling %belly, the ever present thumping drone of %pred’s heartbeat pounds in your ears, the powerful thudding of it pulses through the flesh holding you, throbbing across every wrinkle and fold, every surface presses in at you just that little bit more with each and every throb of that heartbeat. The burbling grumbles of that gut working around you too, fill your ears with a deep gastric symphony as those walls work hard to break you down.", + "The gurgling walls press in heavily, overpowering your limbs briefly as the chamber collapses in to grind over you from head to toe!! No part of you is left out as the doughy flesh glides and grinds and jostles you around, smothering you in thick slime here and squeezing you down into a tight little ball there. The satisfied puffing coming from nearby through the flesh all you need to know that %pred is happy to have you.", + "The slime bubbles and glorps around you as you’re smothered in those thick walls! The slick surfaces mold to your figure as the throbbing of %pred’s pulse squeezes you that little bit more with each beat of their heart. The tingling caused by that slime spreads all across your body as you’re totally soaked in it, and there’s nowhere within this chamber to get away from it!", + "The roaring gurgles of the active gut squeezing and squelching in around you sound out for a few moments as you are smushed and squeezed intensely! This is it! %pred’s %belly is trying to claim you utterly!!!! But after a few moments the chamber eases off, leaving you sopping wet with thick, stringy slime.", + "It’s so hot, sweltering even! The burbling sounds of this organic cacophony swell and ebb all around you as thick slimes gush around you with the motion of %pred’s %belly. It’s hard to move in this tingly embrace even though the squashy walls are absolutely slippery! You can pull your limbs out from between the heavy meaty folds with some effort, and when you do there’s a messy sucking noise in the wake of the motion. Of course, such a disturbance naturally warrants that the chamber would redouble its efforts to subdue you and smother you in those thick tingling slimes.", + "The walls around you flex inward briefly, burbling and squelching heavily as everything rushed together, wringing you powerfully for a few moments while, somewhere far above you can hear the bassy rumble of a casual belch, much of the small amount of acrid air available rushing out with the sound. After several long moments held in the tight embrace of that pulsing flesh, things ease up a bit again and resume their insistent, tingly churnings.", + "It’s pitch black and completely slimy in here, %pred sways their %belly a bit here and there to toss you from one end to the other, tumbling you end over end as you’re churned in that active %belly. It’s all so slick and squishy, so it is really hard to get any footing or grip on things to stabilize your position, which means that you’re left at the mercy of those gloomy gastric affections and the tingling touch of those sticky syrupy slimes that the walls lather into your body.") + + B.emote_lists[DM_HOLD] = list( + "The burbling %belly rocks and glides over you gently as you’re held deep within %pred, the deep thumping of their heart pulses all around you as you’re caressed and pressed by heavy, doughy walls.", + "%pred’s %belly glorgles around you idly as you’re held gently by the slick, wrinkled flesh.", + "The ever present beating of %pred’s heart throbs through the chamber around you. As you sink into the flesh a little ways, you can feel the pressure of the pulse pump in against you that much more snug for an instant, just in time with the thump of the nearby heart.", + "As %pred breathes you can feel the %belly you are within compact in against you a bit more, the pressure of the inflating lungs smooshing the other organs out of the way a bit, and giving you a bit more of a squeeze, before with a whoosh the breath rushes out again, and the cycle repeats.", + "As %pred goes about their day you can feel the motions of their body jostle you a bit here and there. Bumping and bouncing you against the doughy pressure of those interior confines, the gloopy gurgles sounding off from somewhere deeper inside...", + "The walls press in heavily on you for a few moments. Squeezing across you in a heavy, possessive churn. A smothering squeeze that leaves you breathless for a few long moments, coating you in a thin layer of slick slime. The walls seem to retreat reluctantly, leaving you in the sweltering humid air of %pred’s cramped %belly.", + "It’s hard to stay in place with how slick and squashy the walls of %pred’s %belly are. Thick and smushy and soft, you can sink into them several inches before the tension catches you and rolls you around at the crater your body weight makes. A pool of thin slimes gathers around you some, clinging close as you’re held snugly deep within %pred.", + "The press of slick flesh to your body and in against itself is ever present within this slimy space. The squelches and grumbles of that tummy shifting around you never really go away. The wrinkled walls would glide against themselves here and there creating an idle cacophony of squish, while the caress of that flesh in against your body makes a more prevalent slurping that’s hard to escape.", + "Held within the pitch black gloom of this gently churning organic chamber it’s hard to get much room to yourself. The walls are always prone to rolling in and squeezing over you for long moments.", + "Despite the constant motion of fleshy waves gliding in against you and the burbling sounds of the inner workings of all those tubes and organs, the steady beating of %pred’s heart, and the gentle whooshing of their breath were surprisingly relaxing.") + + B.emote_lists[DM_ABSORB] = list( + "The intensity of the flesh pumping in against you makes it somewhat hard to tell how soft and tarry the surfaces pressing into you have gotten. As your extremities disappear between the folds of flesh inside there it’s so difficult to pull them back out, like squirming against hot, gooey quicksand! %pred’s %belly seems quite insistent on sinking you deeper, and claiming you entirely.", + "The pressure is intense, the slimy walls rolling over you again and again, really clinging to your figure, sticky and slurpy, you can feel the tug of the flesh drawing you in, and the flickers of another presence along the edges of your mind.", + "The wrinkled flesh flows between your fingers and wraps in against your body as it presses in and clings to you. The walls are extremely soft, so much so that you can sink deep into them, where, a curious tingling begins to tickle at you the deeper you go.", + "The pulse of %pred’s heart throbs all around you, through the flesh and up against you. A powerful pumping that rolls through every little bit of the %belly. The softening walls steadily flow over you, steadily sinking you into their surface a ways where that throbbing seems to get that much more intense, pulsing all around you as the flesh forms skin tight to you… and your heart seems to adjust too, thumping in your ears in time with %pred’s.", + "The pressure of %pred’s body forming against you makes it hard to move at all. The walls fold in against you, wrapping you up and steadily submerging you, a texture something akin to molten marshmallow hugs you all around, filling in the creases and spaces between, but even as you’re held there so tightly, you’d find that you’re neither crushed nor suffocated… Held so deep and tight as that %belly works to make you one with it.", + "As the flesh of %pred’s %belly forms against you and flows across your body, you can feel and hear the wet slide of its weight spreading and rubbing against you. As it forms against your ears though and really clings on to you, the sloppy wet sounds of the interior of some weird alien fade, to be replaced by a powerful thumping heartbeat. As you sink into %pred’s body, it becomes harder and harder to identify where you end and %pred begins, and that pumping heartbeat lulls your mind into something of a dull haze.", + "As the gooey touch of %pred’s body rolls over you, you can’t help but notice just how soft it all is, despite the intensity of the pressure squeezing in against you, clinging to your figure in an insistent smothering embrace, it’s never painful. The flesh you’re being held against forms to you, molding against you, creating a space that’s perfectly sized for you. A cavity shaped exactly like you. A place where you belong.", + "As the pumping flesh courses against you, gliding and throbbing against your touch, letting you sink in far beyond where it seems reasonable for tension to have caught you, you notice that whatever appendage has sunk that deep begins to feel a bit tingly, a bit starry, like it’s become a twinkling starlight. It’s weird, but not exactly uncomfortable. There’s a sense of otherness that brushes comfortably somewhere against the back of your mind, that gets stronger the deeper you sink...", + "The rippling touch of %pred’s wrinkled flesh folding in against you is hard to escape. No matter where you turn, it’s all closing in on you, pressing to you. Practically molten, the pressure of it all molds to you and leaves no part of your figure untouched, and yet, even as it forms skin tight in against you, it doesn’t stop there. You seem to still sink further into the squish, the surface of it all flows over your figure and submerges you deeper, and deeper… and deeper, until there’s nothing but the heat and the throb of %pred’s heart all around you.", + "The pressure is intense. The throbbing of %pred’s heart in your ears is impossible to ignore as the weight of your predator shifts when they move. You might notice that, as you sink deeper into the pressure of %pred, you’re more conscious of those shifts and wobbles, as if they were your own, and the appreciative flickerings of consciousness that seems to have claimed you. You can feel each shift and jiggle of the fluffy critter’s movements as you’re absorbed...") + + B.emote_lists[DM_HEAL] = list( + "The walls glide over you tenderly, gently. Lightly kneading and massaging against your figure, smooth and pillowy soft. You can sink in a ways, but it’s not hard to extract yourself from these caressing touches. The burbling of %pred’s %belly fills your ears as you’re rocked and cradled within.", + "As you soak within %pred’s %belly you can feel some of your strength returning, aches and pains easing some as time goes on. The walls knead over you gently, but are never rough. They’re soft and smushy, like a jiggly padding, protecting you from the outside world.", + "The throb of %pred’s heart rocks through the surfaces of the %belly. Even as you’re sunk into a bit of a crater in the flesh there, you can feel it pulse through the squish. The sound of %pred’s heart is a constant companion, along with the wet squelches and slurps of flesh shifting against itself and you.", + "The slow sway of %pred’s body as it moves rocks you back and forth across the %belly. With how soft and gentle it is in there, it’s not unlike relaxing in a large, dark fleshy hammock. Of course, there’s not really any airflow or even all that much space, what with the walls pressed in close and gently churning and kneading against you, so it’s not anything like a hammock, really… but you might be able to imagine it was if you put your mind to it. Either way, the gentle sway is soothing and comfortable despite how un-hammock-like this hammock is...", + "The smooth press of flesh throbs against you as %pred’s %belly kneads and smooshes over you soothingly. The pressure shifts here and there as the muscles beyond grind over you carefully. Despite the heat and the thick, stifling air, you feel slowly more refreshed as you’re held in here. It’s comfy enough to nap in.", + "As you’re held within the %belly you feel your eyelids get a bit heavy… the rhythmic thumping of %pred’s heart nearby, along with the gentle rocking shifts make snoozing an easy option, especially considering how SQUOOSHY and comfortable the stretchy flesh holding you is. It kneads and caresses you soothingly, and you might find that now and then your blinks seem to last several minutes as you’re kept close amid that comfortable %belly.", + "The walls of the %belly press in close around you for a few moments, squeezing you heavily and kneading across you. You can feel your back and joints pop here and there in just the right way, there is a moment of a kind of ache, and then a deep, delightful relief, as the walls ease up and resume their gentle smooshes.", + "With each step %pred takes, those soft, smooth wall jiggle lightly around you, quaking and swaying you this way and that. The slimy surfaces of %pred’s interior glide over your body casually, shifting and burbling here and there, holding you nice and secure.", + "The pressure around you increases a little bit each time you hear the whooooosh of %pred taking a breath in. Expanding lungs compact things inside a little bit, making your stay just that little bit more snug. The pressure is never not gentle though. Those smooth, slick walls were also always pressing and kneading against you too, so it might not be the easiest thing to notice.", + "The thumping, squeezing, kneading rhythm of %pred’s body was easy to get into. A gentle rocking here, a little bob there, a pulsing throb across the whole %belly as you’re churned and felt over. It’s easy to get lost in the grumbly gurgly rhythm of that body, hidden away in the pitch black. As it all works around you, you can feel your energy build, your muscles relax, and any aches and pains you might have would fade with time. It’s comfortable, and fills you with an alien sense of belonging.") + + B.struggle_messages_inside = list( + "As you squirm and fuss, your limbs sink into the squish a fair way! Sliding over the slick, sloppy surfaces of %pred’s %belly. The walls clamp in and churn over you heavily in response.", + "As you squirm, %pred’s %belly wobbles and smothers over you. Wrinkled walls fold against your features. The humid air hangs around you oppressively as the walls roll over you, making it hard to move.", + "You can feel the pressure of the flesh kneading you clamp down and fold over you insistently as you squirm and push at %pred’s flesh. It’s so slippery and hard to get any proper grip or footing!", + "When you shift your weight and press into the flesh of %pred’s %belly, you can feel things around you clamp down, and in a rush, what little air there is inside of there rushes out passed you. %pred emits a low, rumbling urp somewhere far above.", + "Your struggles slide over the doughy flesh. The tension of it catches you and forms to your presses, before it all flexes inward again and tries to fold you into a smaller shape again.", + "When you push and squirm against the walls of the %belly, you can hear and feel %pred give a little happy grumble, and you can feel them shift their weight, tossing you from one end of the %belly to the other, sloppy squelching sounding out as you land.", + "Your hands slip and slide against the pulsing wrinkled squish of %pred’s %belly, sinking into the doughy texture of the smooth walls and makes it hard to go anywhere except to the lowest, deepest section of the %belly.", + "The sound of your squirms is loud in your ears. The squelchy gurgly sound of sloppy wet flesh shifting in the pitch black, as your struggles force the tight space wider as you try to wriggle free.", + "When you move the %belly gurgles insistently around you. The bubbling fluids within there cling to you as you push and squirm against those wrinkly walls.", + "Your struggles are stifled by the clinging press of heavy flesh greedily pressing in on you heavily. It’s tiring to fight against those groaning guts...") + + B.struggle_messages_outside = list( + "Vague shapes shift under %pred’s hide...", + "Something solid squirms within %pred...", + "%pred emits a low ‘uurp’ as something shifts within.", + "Something bumps and thumps against the inside of %pred.", + "Something glorps inside of %pred.", + "%pred’s gut grumbles around something solid...", + "%pred’s belly rumbles and sways as something moves inside.", + "Something sloshes inside of %pred.", + "%pred’s belly burbles noisily.", + "%pred’s belly shifts noticeably.") + B.examine_messages = list( + "There is a noticable swell on their belly.", + "Their belly seems to hang a bit low.", + "There seems to be a solid shape distending their belly.") + B.digest_messages_prey = list( + "With a low grumble your body melts and falls apart within %pred. The nutrition you provide would go on to power your predator as they go on with their life. You were nutritious food, but, nothing but alien food in the end.", + "No matter your squirms and fusses you can feel those walls collapse in on you, smothering over you as the tingling fluids rise and bubble against you. Churning hard as your body is actively softened up and melted away! Your senses fading out as you’re reduced to nothing but a hot, gooey slush, a form much better suited to continuing on as food for a hungry body.", + "As your body weakens and your wiggles ebb down, the pressure of those churning walls builds, further overpowering and working to melt you that much more. The thick syrupy slime soaks into you and softens you up, not unlike ice cream on a hot summer day, and you’re soaked up just as easily.", + "%pred’s %belly gushes and schlorps around you as you are broken down and absorbed. The rippling walls churn and roll the slowly thinning contents of their sloshing depths, as more and more of you is claimed completely by %pred.", + "The gurgling sounds of your body melting slowly overtakes all the other sounds. The walls closing in and squeezing over you so heavily! Nothing you could do could help you now as you’re churned and mushed, left to steadily soften and break up into a nutritious slush. ", + "Your body softens and glorps around within the guts of %pred. The rolling rumbles and sloshes overcome you as your senses fade, and your form fades away, bubbling away to become nothing more than a part of %pred.", + "Things clamp down over you as %pred flexxes, smothering over you for a few long moments. Your senses fade away before they ease up though. Your body rapidly melted down and made to slosh through the deeper tubes, helpless but to fade away as you’re absorbed as the food you are.", + "The tide of syrupy fluids rises higher and higher, flooding over you, leaving nothing to breathe. Your senses fade away as the sloppy roiling mess softens you up and passes you along for further processing, fit only to serve to plump up %pred’s figure.", + "Over the course of several hours in the burbling organic cauldron, your body softens up little by little, soaking up the slime, the tingling spreading over you more and more as your strength fades. The walls fold over you and wrap you up, until the last thing you can sense is the throb of %pred’s heart pulsing through the very core of your being, washing you away as you become food for %pred.", + "Your final moments are spent trying to make just a little space for yourself, the doughy squish of the flesh forming to you, pressing in tighter and tighter, invading your personal space as if to show you that, you don’t have any personal space. You’re already a part of %pred, you just don’t know it yet. And so those walls come in close to press up against you and churn you away into a messy slop, to put you in your place. That being, padding the belly and hips of %pred, right where you belong.") + +// The friend zone. + var/obj/belly/p = new /obj/belly(src) + p.immutable = TRUE + p.mode_flags = 40 + p.human_prey_swallow_time = 0.01 SECONDS + p.digestchance = 0 + p.digest_brute = 0 + p.digest_burn = 0 + p.absorbchance = 0 + p.escapable = TRUE + p.escapechance = 40 + p.digest_mode = DM_HEAL + p.name = "propeutpericulum" //I'm no latin professor I just know that some organs and things are based on latin words + //and google translate says that each of these individually + //"close" "to" "danger" translate to "prope" "ut" "periculum". + //Of course it doesn't translate perfectly, and it's nonsense when squashed together, but + //I don't care that much, I just figured that the weird alien animals that store friends in + //their tummy should have a funny name for the organ they do that with. >:I + p.desc = "You seem to have found your way into something of a specialized chamber within the Teppi. The walls are slick and smooth and REALLY soft to the touch. While you can hear the Teppi’s heartbeat nearby, and feel it throb throughout its flesh, the motions around you are gentle and careful. You’re pressed into a small shape within the pleasant heat, with the flesh forming to your figure. You can wriggle around a bit and get comfortable here, but as soon as you get still for a bit the smooth, almost silky flesh seems to form to you once again, like a heavy blanket wrapping you up. As you lounge here the pleasant kneading sensations ease aches and pains, and leave you feeling fresher than before. For a curious fleshy sac inside of some alien monster, this place isn’t all that bad!" + p.contaminates = 1 + p.contamination_flavor = "Wet" + p.contamination_color = "grey" + p.item_digest_mode = IM_HOLD + p.belly_fullscreen = "yet_another_tumby" + p.fancy_vore = 1 + p.vore_verb = "nyomp" + friend_zone = p + + p.emote_lists[DM_DRAIN] = B.emote_lists[DM_DRAIN] + + p.emote_lists[DM_DIGEST] = B.emote_lists[DM_DIGEST] + + p.emote_lists[DM_HOLD] = B.emote_lists[DM_HOLD] + + p.emote_lists[DM_ABSORB] = B.emote_lists[DM_ABSORB] + + p.emote_lists[DM_HEAL] = B.emote_lists[DM_HEAL] + + p.struggle_messages_inside = B.struggle_messages_inside + + p.struggle_messages_outside = B.struggle_messages_outside + + p.examine_messages = B.examine_messages + + p.digest_messages_prey = B.digest_messages_prey + +///////////////////////////////////////Other stuff/////////////////////////////////////////// + +/mob/living/simple_mob/vore/alienanimals/teppi/Initialize() + . = ..() + + if(name == initial(name)) + name = "[name] ([rand(1, 1000)])" + real_name = name + if(!teppi_adult) + nutrition = 0 + verbs += /mob/living/proc/ventcrawl + verbs += /mob/living/proc/hide + else + verbs += /mob/living/simple_mob/vore/alienanimals/teppi/proc/produce_offspring + verbs += /mob/living/simple_mob/vore/alienanimals/teppi/proc/toggle_producing_offspring + + +// teppi_id = rand(1,100000) +// if(!dad_id || !mom_id) +// dad_id = rand(1,100000) +// mom_id = rand(1,100000) + teppi_setup() + +//Picks colors and allergens for teppi that don't have them set +/mob/living/simple_mob/vore/alienanimals/teppi/proc/teppi_setup() + var/static/list/possibleallergens = list( + ALLERGEN_MEAT, + ALLERGEN_FISH, + ALLERGEN_FRUIT, + ALLERGEN_VEGETABLE, + ALLERGEN_GRAINS, + ALLERGEN_BEANS, + ALLERGEN_SEEDS, + ALLERGEN_DAIRY, + ALLERGEN_FUNGI, + ALLERGEN_COFFEE, + ALLERGEN_SUGARS, + ALLERGEN_EGGS + ) + + var/static/list/possiblebody = list("#fff2d3" = 100, "#ffffc0" = 25, "#c69c85" = 25, "#9b7758" = 25, "#3f4a60" = 10, "#121f24" = 10, "#420824" = 1) + var/static/list/possiblemarking = list("#fff2d3" = 100, "#ffffc0" = 50, "#c69c85" = 25, "#9b7758" = 5, "#3f4a60" = 5, "#121f24" = 5, "#6300db" = 1) + var/static/list/possiblehorns = list("#454238" = 100, "#a3d5d7" = 10, "#763851" = 10, "#0d0c2f" = 5, "#ffc965" = 1) + var/static/list/possibleeyes = list("#4848a7" = 100, "#f346ff" = 25, "#b20005" = 5, "#ff9a06" = 1, "#0cb600" = 50, "#32ffff" = 5, "#272523" = 50, "#ffffff" = 1) + var/static/list/possibleskin = list("#584060" = 100, "#272523" = 50, "#ff8a8e" = 25, "#35658d" = 10, "#ffbb00" = 1) + + if(!inherit_allergen) //For new teppi + allergen_preference = pick(possibleallergens) //the food we like + allergen_unpreference = pick(possibleallergens - allergen_preference) //can't dislike the thing we like, we're not THAT picky + affection_factor = rand(1,3) + if(!inherit_colors) + color = pickweight(possiblebody) + marking_color = pickweight(possiblemarking) + horn_color = pickweight(possiblehorns) + eye_color = pickweight(possibleeyes) + skin_color = pickweight(possibleskin) + if(!marking_type) + marking_type = "[rand(0,13)]" //the babies don't have this set up by default, but they might pick it from their parents + if(teppi_adult) + if(!horn_type) + horn_type = "[rand(0,1)]" + else if(teppi_mutate) + var/list/possiblecolorlists = list(possiblebody, possiblemarking, possiblehorns, possibleeyes, possibleskin) + var/pick_a = rand(0,5) + var/pick_b = pick(possiblecolorlists) + switch(pick_a) + if(0) + color = pickweight(pick_b) + if(1) + marking_color = pickweight(pick_b) + if(2) + horn_color = pickweight(pick_b) + if(3) + eye_color = pickweight(pick_b) + if(4) + skin_color = pickweight(pick_b) + if(5) + color = pickweight(pick_b) + marking_color = pickweight(pick_b) + horn_color = pickweight(pick_b) + eye_color = pickweight(pick_b) + skin_color = pickweight(pick_b) + teppi_mutate = FALSE + + update_icon() + +//This builds, caches, and recalls parts of the teppi as it needs them, and shares them across all teppi, +//so ideally they only have to make it once as they need it since most of them will be using many of the same colored parts +/mob/living/simple_mob/vore/alienanimals/teppi/proc/teppi_icon() + var/marking_key = "marking-[marking_color]" + var/horn_key = "horn-[horn_color]" + var/eye_key = "eye-[eye_color]" + var/skin_key = "skin-[skin_color]" + var/wool_key = "wool-[marking_color]" + + var/our_state = "base" //For helping the images know what icon state they should be grabbing + if(icon_state == icon_living) + our_state = "base" + if(icon_state == icon_rest) + our_state = "rest" + if(icon_state == icon_dead) + our_state = "dead" + var/life_stage = "adult" + if(!teppi_adult) + life_stage = "baby" + /////LOWEST LAYER///// + if(teppi_adult) //Only adults get markings or wool. The marking color is a secret until they grow bigger! + var/combine_key = marking_key+our_state+marking_type //Markings first, the lowest layer, down with the base color + var/image/marking_image = overlays_cache[combine_key] + if(!marking_image) + marking_image = image(icon,null,"marking_[our_state][marking_type]") + marking_image.color = marking_color + marking_image.appearance_flags = RESET_COLOR|KEEP_APART|PIXEL_SCALE + overlays_cache[combine_key] = marking_image + add_overlay(marking_image) + + if(item_type) + var/item_key = "[item_type]-[item_color]" + var/image/item_image = overlays_cache[item_key+our_state] //Items! Like collar. Goes under everything but markings because I'll go crazy otherwise + if(!item_image) + item_image = image(icon,null,"[item_type]_[our_state]") + item_image.color = item_color + item_image.appearance_flags = RESET_COLOR|KEEP_APART|PIXEL_SCALE + overlays_cache[item_key+our_state] = item_image + add_overlay(item_image) + + if(teppi_wool) + var/image/wool_image = overlays_cache[wool_key+our_state+life_stage] //Wool comes next, goes over top of the markings, is the same color too + if(!wool_image) + wool_image = image(icon,null,"wool_[our_state]") + wool_image.color = marking_color + wool_image.appearance_flags = RESET_COLOR|KEEP_APART|PIXEL_SCALE + overlays_cache[wool_key+our_state+life_stage] = wool_image + add_overlay(wool_image) + + var/image/horn_image = overlays_cache[horn_key+our_state+life_stage+horn_type] //Horns MUST come after marking and wool for layering purposes. + if(!horn_image) + if(!teppi_adult) + horn_image = image(icon,null,"horn_[our_state]") //Babies only have one kind of horns + else + horn_image = image(icon,null,"horn_[our_state][horn_type]") + horn_image.color = horn_color + horn_image.appearance_flags = RESET_COLOR|KEEP_APART|PIXEL_SCALE + overlays_cache[horn_key+our_state+life_stage+horn_type] = horn_image + add_overlay(horn_image) + + var/image/eye_image = overlays_cache[eye_key+our_state+life_stage] //Eyes and skin should be above markings too, but their order doesn't matter + if(!eye_image) //they won't intersect with eachother or the horns, but might intersect with some markings. + eye_image = image(icon,null,"eye_[our_state]") //If we ever add horns or wool fluff that might cover them, remember to move these down as appropriate. + eye_image.color = eye_color //Otherwise they will just always be on top of them. + eye_image.appearance_flags = RESET_COLOR|KEEP_APART|PIXEL_SCALE + overlays_cache[eye_key+our_state+life_stage] = eye_image + add_overlay(eye_image) + + var/image/skin_image = overlays_cache[skin_key+our_state+life_stage] + if(!skin_image) + skin_image = image(icon,null,"skin_[our_state]") + skin_image.color = skin_color + skin_image.appearance_flags = RESET_COLOR|KEEP_APART|PIXEL_SCALE + overlays_cache[skin_key+our_state+life_stage] = skin_image + add_overlay(skin_image) + /////HIGHEST LAYER///// + +/mob/living/simple_mob/vore/alienanimals/teppi/attackby(var/obj/item/O as obj, var/mob/user as mob) + if(stat == DEAD) + return ..() + /////GRABS AND HOLDERS///// + if(istype(O, /obj/item/weapon/grab)) + return ..() + if(istype(O, /obj/item/weapon/holder)) + return ..() + if(user.a_intent != I_HELP) //be gentle + if(resting) + lay_down() + handle_affinity(user, -5) + user.visible_message(user, "\The [user] hits \the [src] with \the [O]. \The [src] grumbles at \the [user].","You hits \the [src] with \the [O]. \The [src] grumbles at you.") + playsound(src, 'sound/weapons/tap.ogg', 50, 1, -1) + return ..() + if(teppi_wool) + if(teppi_shear(user, O)) + return + /////FOOD///// + if(istype(O, /obj/item/weapon/reagent_containers/food)) + if(resting) + to_chat(user, "\The [src] is napping, and doesn't respond to \the [O].") + return + if(nutrition >= 5000) + user.visible_message("\The [user] tries to feed \the [O] to \the [src]. It snoofs but does not eat.","You try to feed \the [O] to \the [src], but it only snoofts at it.") + return + var/nutriment_amount = O.reagents?.get_reagent_amount("nutriment") //does it have nutriment, if so how much? + var/protein_amount = O.reagents?.get_reagent_amount("protein") //does it have protein, if so how much? + var/glucose_amount = O.reagents?.get_reagent_amount("glucose") //does it have glucose, if so how much? + var/yum = nutriment_amount + protein_amount + glucose_amount + if(yum) + if(!teppi_adult) + yum *= 20 + else + yum *= 10 + var/liked = FALSE + var/disliked = FALSE + for(var/datum/reagent/R as anything in O.reagents?.reagent_list) + if(R.allergen_type & allergen_preference) + liked = TRUE + if(R.allergen_type & allergen_unpreference) + disliked = TRUE + if(liked && disliked) //in case a food has both the thing they like and also the thing they don't like in it + user.visible_message("\The [user] feeds \the [O] to \the [src]. It nibbles \the [O] and looks confused.","You feed \the [O] to \the [src]. It nibbles \the [O] and looks confused.") + else if(liked && !disliked) + user.visible_message("\The [user] feeds \the [O] to \the [src]. It nibbles \the [O] excitedly.","You feed \the [O] to \the [src]. It nibbles \the [O] excitedly.") + yum *= 2 + handle_affinity(user, 5) + else if(!liked && disliked) + user.visible_message("\The [user] feeds \the [O] to \the [src]. It nibbles \the [O] slowly.","You feed \the [O] to \the [src]. It nibbles \the [O] slowly.") + yum *= 0.5 + handle_affinity(user, -5) + else + user.visible_message("\The [user] feeds \the [O] to \the [src]. It nibbles \the [O].","You feed \the [O] to \the [src]. It nibbles \the [O].") + handle_affinity(user, 1) + else + user.visible_message("\The [user] feeds \the [O] to \the [src]. It nibbles \the [O] casually.","You feed \the [O] to \the [src]. It nibbles \the [O] casually.") + adjust_nutrition(yum) //add the nutriment! + user.drop_from_inventory(O) + qdel(O) + playsound(src, 'sound/items/eatfood.ogg', 75, 1) + if(!client && lets_eat(user) && prob(1)) + visible_message("\The [src] scromfs \the [user] along with the food!!") + to_chat(user, "\The [src] leans in close, spreading its jaws in front of you. A hot, humid gust of breath blows over you as the weight of \the [src]'s presses you over, knocking you off of your feet as the warm gooey tough of jaws scromf over your figure, rapidly guzzling you away with the [O], leaving you to tumble down into the depths of its body...") + playsound(src, pick(bodyfall_sound), 75, 1) + teppi_pounce(user) + if(yum && nutrition >= 500) + to_chat(user, "\The [src] seems satisfied.") + return + /////WEAPONS///// + if(istype(O, /obj/item/weapon/material/knife)) + if(client) + return ..() + if(resting) + user.visible_message("\The [user] approaches \the [src]'s neck with \the [O].","You approach \the [src]'s neck with \the [O].") + if(do_after(user, 5 SECONDS, exclusive = TASK_USER_EXCLUSIVE, target = src)) + if(resting) + death() + return + else + to_chat(user, "\The [src] woke up! You think better of slaughtering it while it is awake.") + return + else + return ..() + if(istype(O, /obj/item/clothing/accessory/collar/craftable)) + var/obj/item/clothing/accessory/collar/craftable/C = O + if(item_type == "collar") + to_chat(user, "[src] is already wearing a collar.") + return + if(!C.given_name) + to_chat(user, "You didn't put a name on the collar. You can use it in your hand to do that!") + return + item_type = "collar" + item_color = C.color + name = C.given_name + real_name = C.given_name + update_icon() + qdel(C) + fully_replace_character_name(real_name,C.given_name) + log_admin("[key_name_admin(user)] renamed a teppi to [name] - [COORD(src)]") + return + /////EVERYTHING ELSE///// + return ..() + +//Wake up the teppi if it is resting, which they like to do sometimes. +/mob/living/simple_mob/vore/alienanimals/teppi/attack_hand(mob/living/carbon/human/M as mob) + if(stat == DEAD) + return ..() + if(M.a_intent == I_GRAB && item_type) + if(affinity[M.real_name] >= 30) + M.visible_message("\The [M.name] removes \the [src]'s [item_type].","You remove \the [src]'s [item_type].") + item_type = null + update_icon() + return + if(M.a_intent != I_HELP) //be gentle + handle_affinity(M, -5) + to_chat(M, "\The [src] fusses at your rough treatment!!") + if(resting) + lay_down() + return..() + if(resting) + M.visible_message("\The [M.name] shakes \the [src] awake from their nap.","You shake \the [src] awake!") + playsound(src, 'sound/weapons/thudswoosh.ogg', 50, 1, -1) + lay_down() + return + else if(!client) + ..() + playsound(src, 'sound/weapons/thudswoosh.ogg', 50, 1, -1) + if(wantpet >= 100) //We want pets sometimes + handle_affinity(M, 1) + if(teppi_adult) + if(prob(25)) + M.visible_message("\The [src] rumbles happily at \the [M]","\The [src] rumbles happily at you!") + playsound(src, 'sound/voice/teppi/rumble.ogg', 75, 1) + vore_selected.digest_mode = DM_DRAIN //People outside can help calm the tumby if you squirm too much + else if(prob(25)) + M.visible_message("\The [src] rumbles happily at \the [M]","\The [src] rumbles happily at you!") + playsound(src, 'sound/voice/teppi/cute_rumble.ogg', 75, 1) + if(prob(25)) + wantpet = rand(0,25) * affection_factor //We stopped wanting pets + to_chat(M, "\The [src] leans into your touch.") + petcount = 0 + else if(petcount < 20) + wantpet = 0 + petcount += 1 + if(prob(20)) + to_chat(M, "\The [src] grumbles at your touch.") + else if(lets_eat(M) && prob(50)) + to_chat(M, "\The [src] grumbles a bit... and then bowls you over, pressing their weight into yours to knock you off of your feet! In a rush of chaotic presses and schlorps, the gooey touch of Teppi flesh grinds over you as you're guzzled away! Casually swallowed down in retaliation for all of the pettings. Pumped down deep into the grumbling depths of \the [src].") + visible_message("\The [src] scromfs \the [M], before chuffing and settling down again.") + playsound(src, pick(bodyfall_sound), 75, 1) + teppi_pounce(M) + wantpet = 100 + else + return ..() + +/mob/living/simple_mob/vore/alienanimals/teppi/examine() + . = ..() + if(item_type) + . += "They are wearing a [item_type] with [name] written on it." + if(nutrition >= 1000) + . += "They look well fed." + if(nutrition <= 500) + . += "They look hungry." + if(health < maxHealth && health / maxHealth * 100 <= 75) + . += "They look beat up." + + +/mob/living/simple_mob/vore/alienanimals/teppi/update_icon() + ..() + teppi_icon() + if(ghostjoin) + ghostjoin_icon() + + +/mob/living/simple_mob/vore/alienanimals/teppi/Life() + . =..() + if(!.) + return + wantpet += rand(0,2) * affection_factor + amount_grown += rand(1,5) + var/not_hungy = FALSE + if(nutrition >= 500) + not_hungy = TRUE + if(amount_grown >= 1000) + if(teppi_adult) + if(not_hungy && !teppi_wool) + nutrition -= rand(250,500) + teppi_wool = TRUE + breedable = TRUE + meat_amount += rand(0,2) + update_icon() + else if (not_hungy) + var/nutrition_cost = 500 + (nutrition / 2) + adjust_nutrition(-nutrition_cost) + new /mob/living/simple_mob/vore/alienanimals/teppi(loc, src) + qdel(src) + else + visible_message("\The [src] whines pathetically...", runemessage = "whines") + if(prob(50)) + playsound(src, 'sound/voice/teppi/whine1.ogg', 75, 1) + else + playsound(src, 'sound/voice/teppi/whine2.ogg', 75, 1) + amount_grown -= rand(100,250) + if(not_hungy) + do_breeding() + do_healing() + if(prob(0.5)) + teppi_sound() + +/mob/living/simple_mob/vore/alienanimals/teppi/proc/do_healing() + if(health < maxHealth) + if(heal_countdown > 0) + heal_countdown -= 1 + return + if(bruteloss > 0) + adjustBruteLoss(-2) + else if(fireloss > 0) + adjustFireLoss(-0.5) + nutrition -= 5 + heal_countdown = 5 + +/mob/living/simple_mob/vore/alienanimals/teppi/proc/do_breeding() + if(!breedable || prevent_breeding) + return + if(client) //Player controlled teppi get a verb, so just do the countdown + if(baby_countdown > 0) + baby_countdown -- + return + if(baby_countdown > 0) + baby_countdown -- + return + else if(GLOB.teppi_count >= GLOB.max_teppi) //if we can't make more then we shouldn't look for partners, but we can be ready in case a slot opens + return + if(prob(1)) + for(var/mob/living/simple_mob/vore/alienanimals/teppi/alltep in oview(1,src)) + if(!teppi_adult || !alltep.teppi_adult || alltep.prevent_breeding) //Don't have babies if you or your partner is babies + continue + if(alltep.client || alltep.stat == DEAD) //Don't have babies if your partner is inhabited by a player, or dead. + continue + if(alltep) + new /mob/living/simple_mob/vore/alienanimals/teppi/baby(loc, src, alltep) + baby_countdown = 200 + if(affinity[alltep.real_name]) + return + handle_affinity(alltep, 30) //Mom and dad should like eachother when they do their business + alltep.handle_affinity(src, 30) + return + +/mob/living/simple_mob/vore/alienanimals/teppi/proc/teppi_sound() + if(!teppi_adult || client) + return + if(resting) + return + playsound(src, pick(teppi_sound), 75, 1) + +/mob/living/simple_mob/vore/alienanimals/teppi/proc/teppi_shear(var/mob/user as mob, tool) + var/sheartime = 3 SECONDS + if(istype(tool, /obj/item/weapon/material/knife)) + var/obj/item/weapon/material/knife/K = tool + if(K.default_material == MAT_PLASTIC || K.default_material == MAT_FLINT) + sheartime *= 2 + if(K.dulled) + sheartime *= 3 + if(!K.sharp) + sheartime *= 2 + if(K.edge) + sheartime *= 0.5 + else if(istype(tool, /obj/item/weapon/tool/wirecutters)) + sheartime *= 2 + else + return FALSE + if(do_after(user, sheartime, exclusive = TASK_USER_EXCLUSIVE, target = src)) + user.visible_message("\The [user] shears \the [src] with \the [tool].","You shear \the [src] with \the [tool].") + amount_grown = rand(0,250) + var/obj/item/stack/material/fur/F = new(get_turf(user)) + F.amount = rand(10,15) + F.color = marking_color + teppi_wool = FALSE + update_icon() + handle_affinity(user, 5) + teppi_sound() + return TRUE + +//Handles both growing up from a baby and also passing parent details to new babies. +/mob/living/simple_mob/vore/alienanimals/teppi/New(newloc, teppi1, teppi2) + GLOB.teppi_count ++ + if(teppi1 && !teppi2) + inherit_from_baby(teppi1) + else if (teppi1 && teppi2) + inherit_from_parents(teppi1, teppi2) + ..() + +/mob/living/simple_mob/vore/alienanimals/teppi/Destroy() + GLOB.teppi_count -- + friend_zone = null + active_ghost_pods -= src + ai_holder.leader = null + return ..() + +/mob/living/simple_mob/vore/alienanimals/teppi/lay_down() + ..() + if(client || !teppi_adult) + return + if(vore_selected == friend_zone) + return + if(resting) + vore_selected.digestchance = 60 + vore_selected.digest_brute = 6 + vore_selected.digest_burn = 6 + else + vore_selected.digestchance = 5 + vore_selected.digest_brute = 0.05 + vore_selected.digest_burn = 0.05 + +/mob/living/simple_mob/vore/alienanimals/teppi/animal_nom(mob/living/T in living_mobs(1)) + if(client) + return ..() + var/current_affinity = affinity[T.real_name] + ai_holder.busy = TRUE + T.stop_pulling() + if(current_affinity >= 50) + var/tumby = vore_selected + vore_selected = friend_zone + ..() + vore_selected = tumby + return + else if(current_affinity <= -50) + vore_selected.digest_mode = DM_DIGEST + else + vore_selected.digest_mode = DM_DRAIN + ..() + ai_holder.busy = FALSE + + +/mob/living/simple_mob/vore/alienanimals/teppi/perform_the_nom(user, mob/living/prey, user, belly, delay) + if(client) + return ..() + var/current_affinity = affinity[prey.real_name] + ai_holder.busy = TRUE + prey.stop_pulling() + if(current_affinity >= 50) + belly = friend_zone + return ..() + if(current_affinity <= -50) + vore_selected.digest_mode = DM_DIGEST + else + vore_selected.digest_mode = DM_DRAIN + ..() + ai_holder.busy = FALSE + +//Instead of copying this everywhere let's just make a proc +/mob/living/simple_mob/vore/alienanimals/teppi/proc/lets_eat(person) + if(teppi_adult && will_eat(person)) + return 1 + else + return 0 + +/mob/living/simple_mob/vore/alienanimals/teppi/proc/teppi_pounce(mob/living/carbon/human/M as mob) + M.Weaken(5) + animal_nom(M) + M.stop_pulling() + +/mob/living/simple_mob/vore/alienanimals/teppi/proc/handle_affinity(mob/living/person, amount) + affinity[person.real_name] += amount * affection_factor + var/current_affinity = affinity[person.real_name] + if(!teppi_adult) //Don't want baby getting killed by parents in case of hostile or growing up with P in their AI + return + if(current_affinity >= 250) //At this point the Teppi has joined your team + faction = person.faction + if(current_affinity <= -500 && !client) //You're doing this on purpose or really not paying attention and I'm going to kick your ass. + ai_holder.target = person + ai_holder.track_target_position() + ai_holder.set_stance(STANCE_FIGHT) + affinity[person.real_name] = -100 //Don't hold a grudge though. + +/datum/say_list/teppi + speak = list("Gyooh~", "Gyuuuh!", "Gyuh?", "Gyaah...", "Iuuuuhh.", "Uoounh!", "GyoooOOOOoooh!", "Gyoh~", "Gyouh~") + emote_hear = list("puffs", "huffs", "rumbles", "gyoohs","pants", "snoofs") + emote_see = list("sways its tail", "stretches", "yawns", "turns their head") + say_maybe_target = list("Gyuuh?") + say_got_target = list("GYOOOHHHH!!!") + +/datum/say_list/teppibaby + speak = list("Gyooh~", "Gyuuuh!", "Gyuh?", "Gyaah...", "Iuuuuhh.", "Uoounh!", "GyoooOOOOoooh!", "Gyoh~", "Gyouh~", "Yip!") + emote_hear = list("puffs", "huffs", "rumbles", "gyoohs","pants", "snoofs", "yips") + emote_see = list("sways its tail", "stretches", "yawns", "turns their head") + say_maybe_target = list("Gyuuh?") + say_got_target = list("GYOOOHHHH!!!") + + +/datum/ai_holder/simple_mob/teppi + + hostile = FALSE + cooperative = TRUE + retaliate = TRUE + speak_chance = 0.5 + wander = TRUE + +/datum/language/teppi + name = "Teppi" + desc = "The language of the meat things." + speech_verb = "rumbles" + ask_verb = "tilts" + exclaim_verb = "roars" + key = "i" + flags = RESTRICTED + machine_understands = 0 + space_chance = 100 + syllables = list("gyoh", "snoof", "gyoooooOOOooh", "iuuuuh", "gyuuuuh") + +////////////////// Da babby ////////////// + +/mob/living/simple_mob/vore/alienanimals/teppi/baby + name = "teppi" + desc = "A smallish furry creature, sporting two nubby horns and a very sturdy tail. It has four toes on each paw." + tt_desc = "Ipsumollis Velodigium" + + icon_state = "teppi" + icon_living = "body_base" + icon_dead = "body_dead" + icon_rest = "body_rest" + icon = 'icons/mob/alienanimals_x32.dmi' + pixel_x = 0 + default_pixel_x = 0 + teppi_adult = FALSE + maxHealth = 50 + health = 50 + movement_cooldown = 4 + harm_intent_damage = 5 + melee_damage_lower = 1 + melee_damage_upper = 5 + vore_active = FALSE //it's a tiny baby :O + devourable = FALSE + digestable = FALSE + vore_bump_chance = 0 + vore_pounce_chance = 0 + vis_height = 32 + meat_amount = 2 + loot_list = list() + say_list_type = /datum/say_list/teppibaby + + +/mob/living/simple_mob/vore/alienanimals/teppi/baby/init_vore() //shouldn't need all the vore bidness if they aren't using it as babbies. They get their tummies when they grow up. + return + +//This sets all the things on adult teppi when they grow from a baby +/mob/living/simple_mob/vore/alienanimals/teppi/proc/inherit_from_baby(mob/living/simple_mob/vore/alienanimals/teppi/baby/baby) + inherit_colors = TRUE + inherit_allergen = TRUE + dir = baby.dir + name = baby.name + real_name = baby.real_name + faction = baby.faction + affinity = baby.affinity + affection_factor = baby.affection_factor + nutrition = baby.nutrition + allergen_preference = baby.allergen_preference + allergen_unpreference = baby.allergen_unpreference + color = baby.color + marking_color = baby.marking_color + horn_color = baby.horn_color + eye_color = baby.eye_color + skin_color = baby.skin_color + ghostjoin = 1 + active_ghost_pods |= src + update_icon() + +//This sets all the things on baby teppi when they are bred from adult teppi +/mob/living/simple_mob/vore/alienanimals/teppi/proc/inherit_from_parents(mob/living/simple_mob/vore/alienanimals/teppi/mom, mob/living/simple_mob/vore/alienanimals/teppi/dad) + inherit_colors = TRUE +// mom_id = mom.teppi_id +// dad_id = dad.teppi_id + faction = mom.faction + color = pick(list(mom.color, dad.color, BlendRGB(mom.color, dad.color, 0.5))) + marking_color = pick(list(mom.marking_color, dad.marking_color, BlendRGB(mom.marking_color, dad.marking_color, 0.5))) + horn_color = pick(list(mom.horn_color, dad.horn_color, BlendRGB(mom.horn_color, dad.horn_color, 0.5))) + eye_color = pick(list(mom.eye_color, dad.eye_color, BlendRGB(mom.eye_color, dad.eye_color, 0.5))) + skin_color = pick(list(mom.skin_color, dad.skin_color, BlendRGB(mom.skin_color, dad.skin_color, 0.5))) + marking_type = pick(list(mom.marking_type, dad.marking_type, null)) + horn_type = pick(list(mom.horn_type, dad.horn_type, null)) + + + if(mom.teppi_mutate || dad.teppi_mutate) + teppi_mutate = TRUE + else if(prob(1)) + teppi_mutate = TRUE + mom.nutrition -= 500 + dad.nutrition -= 250 + mom.visible_message("\The [src] is born from [mom]... It's the miracle of life!", runemessage = "grunts") + handle_affinity(mom, 26) //this way the babies will follow their parents around (and keep track of them) + handle_affinity(dad, 25) + +//I ran a vote with the headmins, and this option won out considering the restrictions. +//I don't think this is a GOOD idea, but in pursuit of preserving Teppi's mechanical functionality while player controlled, there is a verb! +//This gives a strongly worded warning the first time you push the button, and has similar restrictons to AI controlled Teppi for use which will prevent spamming. +// +/mob/living/simple_mob/vore/alienanimals/teppi/proc/produce_offspring() + set name = "Produce Offspring" + set category = "Abilities" + set desc = "You can have babies if the conditions are right." + if(prevent_breeding) + to_chat(src, "You have elected to not participate in breeding mechanics, and so cannot complete that action.") + return + if(!teppi_warned) + to_chat(src, "Be aware of your surroundings when using this verb. If you use this to be disruptive or prefbreak people, you are likely to eat a ban. If whoever's tending the teppi is trying to make more babies, or you're alone, or playing with other people who you know are into it, then sure. You should not however, for example, drag another teppi to the bar (or any public place) and drop a baby in the middle of the floor. If you're not sure if it's okay to do where you are, with whoever's around, it probably isn't. This is intended to preserve the mechanical utility of the mob you are playing as, not as a scene tool.") + teppi_warned = TRUE + return + if(stat != CONSCIOUS) + to_chat(src, "I can't do that right now...") + return + if(!teppi_adult) + to_chat(src, "I'm not old enough to make babies.") + return + if(baby_countdown > 0) + to_chat(src, "It is not time yet...") + return + if(!breedable || nutrition < 500) + to_chat(src, "The conditions are not right to produce offspring.") + return + if(GLOB.teppi_count >= GLOB.max_teppi) //if we can't make more then we shouldn't look for partners + to_chat(src, "I cannot produce more offspring at the moment, there are too many of us!") + return + . = FALSE + for(var/mob/living/simple_mob/vore/alienanimals/teppi/alltep in oview(1,src)) + if(!alltep.teppi_adult || alltep.nutrition < 250 || alltep.prevent_breeding || alltep.stat == DEAD) + continue + if(alltep) + log_admin("[key_name_admin(src)] produced a baby teppi at [get_area(src)] - [COORD(src)]") //Won't show up in the chat, but makes a log of who's having babies where, for investigative purposes. + new /mob/living/simple_mob/vore/alienanimals/teppi/baby(loc, src, alltep) + baby_countdown = 400 //You don't have a random chance to deal with so the cooldown is twice as long. + if(affinity[alltep.real_name]) + return + handle_affinity(alltep, 30) //Mom and dad should like eachother when they do their business + alltep.handle_affinity(src, 30) + return + if(. == FALSE) + to_chat(src, "There are no suitable partners nearby.") + +/mob/living/simple_mob/vore/alienanimals/teppi/proc/toggle_producing_offspring() + set name = "Toggle Producing Offspring" + set category = "Abilities" + set desc = "You can toggle whether or not you can produce offspring." + if(!prevent_breeding) + to_chat(src, "You disable breeding.") + prevent_breeding = TRUE + else + to_chat(src, "You enable breeding.") + prevent_breeding = FALSE + +///////////////////AI Things//////////////////////// +//Thank you very much Aronai <3 + +/mob/living/simple_mob/vore/alienanimals/teppi/proc/do_I_know_you() + // Get list of everyone who can see us (which is everyone we can see, typically) + var/list/people_nearby = oviewers(world.view, src) + // Use the hidden . var to avoid needing to create a new local var (saves CPU) + . = list() + // Add everyone nearby to the list if they're in affinity, with key of the mob and value of the affinity + // . becomes list(jane = 1, tim = -3) etc + for(var/mob/living/M in people_nearby) + var/their_affinity = affinity[M.real_name] + if(their_affinity) + if(their_affinity >= 25 || their_affinity <= -10) + .[M] = affinity[M.real_name] + // Sort the list (timsort default sort comperator is numeric ascending, so highest affinity will be last in the list) + sortTim(., associative = TRUE) + +/datum/ai_holder/simple_mob/teppi/handle_wander_movement() + var/mob/living/simple_mob/vore/alienanimals/teppi/tepholder = holder + if(tepholder.resting) + if(prob(5)) + tepholder.lay_down() + return + // Copypasta from parent handle_wander_movement + if(isturf(holder.loc) && can_act()) + if(--wander_delay > 0) + return + if(!wander_when_pulled && (holder.pulledby || holder.grabbed_by.len)) + ai_log("handle_wander_movement() : Being pulled and cannot wander. Exiting.", AI_LOG_DEBUG) + return + // We're having our chance NOW + wander_delay = base_wander_delay + // Typecast the ai_holder 'holder' var as a teppi so we can call do_I_know_you() + var/list/affinity_nearby = tepholder.do_I_know_you() + var/turf/T // Turf we might eventually move to + // If we found any affinity people nearby + if(affinity_nearby.len) + // Extract the highest affinity person from the list, by taking the last item (the item at + // position 6 in a list that's 6 length is the last item eg) + var/mob/living/L = affinity_nearby[affinity_nearby.len] + // If >= 0, wander towards + if(affinity_nearby[L] >= 0) + T = get_step_to(holder, L, 1) + // Else wander away + else + T = get_step_away(holder, L) + // Didn't find affinity people nearby, copypasta from normal wandering. + // We don't call ..() because it'll perform some of the same work again and want to avoid that + if(!T) + if(prob(5)) + tepholder.lay_down() + return + var/moving_to = 0 // Apparently this is required or it always picks 4, according to the previous developer for simplemob AI. + moving_to = pick(cardinal) + holder.set_dir(moving_to) + T = get_step(holder,moving_to) + // Finally do move if we actually found somewhere we'd like to go + if(T) + holder.IMove(T) + +/datum/ai_holder/simple_mob/teppi/handle_idle_speaking() + if(holder.resting) + return + ..() + +/datum/ai_holder/simple_mob/teppi/baby/handle_idle_speaking() + if(holder.resting) + return + ..() + +/datum/ai_holder/simple_mob/teppi/on_hear_say(mob/living/speaker, message) + var/mob/living/simple_mob/vore/alienanimals/teppi/T = holder + if(holder.client) + return + if(!speaker.client) + return + if(!T.teppi_adult) + return + var/speaker_affinity = T.affinity[speaker.real_name] + message = html_decode(message) + if(findtext(message, "lets go") || findtext(message, "let's go") || findtext(message, "come teppi") || findtext(message, "come [holder.name]")) + if(speaker == leader) + return + if(!leader) + if(speaker_affinity >= 100) + set_follow(speaker, follow_for = 10 MINUTES) + holder.visible_message("\The [holder] starts following \the [speaker]","\The [holder] starts following you.") + return + else + var/mob/living/L = leader + if(!can_see_target(L)) + lose_follow() + if(speaker_affinity >= 100) + set_follow(speaker, follow_for = 10 MINUTES) + holder.visible_message("\The [holder] starts following \the [speaker]","\The [holder] starts following you.") + return + else if(speaker_affinity > T.affinity[L.real_name]) + holder.visible_message("\The [holder] starts following \the [speaker]","\The [holder] starts following you.") + set_follow(speaker, follow_for = 10 MINUTES) + return + if(speaker_affinity == T.affinity[L.real_name]) + lose_follow() + holder.visible_message("\The [holder] gives off an anxious whine.") + if(findtext(message, "stop teppi") || findtext(message, "stay here") || findtext(message, "stop [holder.name]")) + if(leader == speaker) + lose_follow() + holder.visible_message("\The [holder] stops following \the [speaker]","\The [holder] stops following you.") + return + +//This a teppi with funny colors will spawn! +/mob/living/simple_mob/vore/alienanimals/teppi/mutant/New() + teppi_mutate = TRUE + . = ..() + +//Custom teppi colors! For funzies. + +/mob/living/simple_mob/vore/alienanimals/teppi/cass/New() + inherit_colors = TRUE + color = "#c69c85" + marking_color = "#eeb698" + horn_color = "#272523" + eye_color = "#612c08" + skin_color = "#272523" + marking_type = "2" + horn_type = "0" + . = ..() + +/mob/living/simple_mob/vore/alienanimals/teppi/baby/cass/New() + inherit_colors = TRUE + color = "#c69c85" + marking_color = "#eeb698" + horn_color = "#272523" + eye_color = "#612c08" + skin_color = "#272523" + marking_type = "2" + horn_type = "0" + . = ..() + +/mob/living/simple_mob/vore/alienanimals/teppi/aronai/New() + inherit_colors = TRUE + color = "#404040" + marking_color = "#222222" + horn_color = "#141414" + eye_color = "#9f522c" + skin_color = "#e16f2d" + marking_type = "13" + horn_type = "1" + . = ..() + +/mob/living/simple_mob/vore/alienanimals/teppi/lira/New() + inherit_colors = TRUE + color = "#fdfae9" + marking_color = "#ffffc0" + horn_color = "#ffc965" + eye_color = "#1d7fb7" + skin_color = "#f09ca9" + marking_type = "13" + horn_type = "0" + . = ..() diff --git a/code/modules/mob/mob_grab.dm b/code/modules/mob/mob_grab.dm index 1d38d66189..83a2c06213 100644 --- a/code/modules/mob/mob_grab.dm +++ b/code/modules/mob/mob_grab.dm @@ -34,6 +34,7 @@ abstract = 1 item_state = "nothing" w_class = ITEMSIZE_HUGE + destroy_on_drop = TRUE //VOREStation Edit /obj/item/weapon/grab/New(mob/user, mob/victim) diff --git a/code/modules/mob/new_player/sprite_accessories_extra_ch.dm b/code/modules/mob/new_player/sprite_accessories_extra_ch.dm index 4c1e4fd79b..1576e74935 100644 --- a/code/modules/mob/new_player/sprite_accessories_extra_ch.dm +++ b/code/modules/mob/new_player/sprite_accessories_extra_ch.dm @@ -163,3 +163,102 @@ unshavenreversemohawk name = "Mohawk Reverse Unshaven" icon_state = "hair_unshaven_reversemohawk" + +// Extra colorable options for Vox +/datum/sprite_accessory/hair/vox_afro_color + name = "Vox Afro, Colorable" + icon = 'icons/mob/human_face_ch.dmi' + icon_add = 'icons/mob/human_face_ch_add.dmi' + icon_state = "hair_vox_afro" + species_allowed = list(SPECIES_VOX) + +/datum/sprite_accessory/hair/vox_crestedquills_color + name = "Vox Crested Quills, Colorable" + icon = 'icons/mob/human_face_ch.dmi' + icon_add = 'icons/mob/human_face_ch_add.dmi' + icon_state = "hair_vox_crestedquills" + species_allowed = list(SPECIES_VOX) + +/datum/sprite_accessory/hair/vox_empquills_color + name = "Vox Emperor Quills, Colorable" + icon = 'icons/mob/human_face_ch.dmi' + icon_add = 'icons/mob/human_face_ch_add.dmi' + icon_state = "hair_vox_emperorquills" + species_allowed = list(SPECIES_VOX) + +/datum/sprite_accessory/hair/vox_hairhorns_color + name = "Vox Hair Horns, Colorable" + icon = 'icons/mob/human_face_ch.dmi' + icon_add = 'icons/mob/human_face_ch_add.dmi' + icon_state = "hair_vox_horns" + species_allowed = list(SPECIES_VOX) + +/datum/sprite_accessory/hair/vox_keelquills_color + name = "Vox Keel Quills, Colorable" + icon = 'icons/mob/human_face_ch.dmi' + icon_add = 'icons/mob/human_face_ch_add.dmi' + icon_state = "hair_vox_keelquills" + species_allowed = list(SPECIES_VOX) + +/datum/sprite_accessory/hair/vox_keetquills_color + name = "Vox Keet Quills, Colorable" + icon = 'icons/mob/human_face_ch.dmi' + icon_add = 'icons/mob/human_face_ch_add.dmi' + icon_state = "hair_vox_keetquills" + species_allowed = list(SPECIES_VOX) + +/datum/sprite_accessory/hair/vox_kingly_color + name = "Vox Kingly Quills, Colorable" + icon = 'icons/mob/human_face_ch.dmi' + icon_add = 'icons/mob/human_face_ch_add.dmi' + icon_state = "hair_vox_kingly" + species_allowed = list(SPECIES_VOX) + +/datum/sprite_accessory/hair/vox_mohawk_color + name = "Vox Mohawk, Colorable" + icon = 'icons/mob/human_face_ch.dmi' + icon_add = 'icons/mob/human_face_ch_add.dmi' + icon_state = "hair_vox_mohawk" + species_allowed = list(SPECIES_VOX) + +/datum/sprite_accessory/hair/vox_nights_color + name = "Vox Night Quills, Colorable" + icon = 'icons/mob/human_face_ch.dmi' + icon_add = 'icons/mob/human_face_ch_add.dmi' + icon_state = "hair_vox_nights" + species_allowed = list(SPECIES_VOX) + +/datum/sprite_accessory/hair/vox_razorclipped_color + name = "Vox Razor Clipped, Colorable" + icon = 'icons/mob/human_face_ch.dmi' + icon_add = 'icons/mob/human_face_ch_add.dmi' + icon_state = "hair_vox_razorclipped" + species_allowed = list(SPECIES_VOX) + +/datum/sprite_accessory/hair/vox_razor_color + name = "Vox Razor, Colorable" + icon = 'icons/mob/human_face_ch.dmi' + icon_add = 'icons/mob/human_face_ch_add.dmi' + icon_state = "hair_vox_razor" + species_allowed = list(SPECIES_VOX) + +/datum/sprite_accessory/hair/vox_shortquills_color + name = "Vox Short Quills, Colorable" + icon = 'icons/mob/human_face_ch.dmi' + icon_add = 'icons/mob/human_face_ch_add.dmi' + icon_state = "hair_vox_shortquills" + species_allowed = list(SPECIES_VOX) + +/datum/sprite_accessory/hair/vox_tielquills_color + name = "Vox Tiel Quills, Colorable" + icon = 'icons/mob/human_face_ch.dmi' + icon_add = 'icons/mob/human_face_ch_add.dmi' + icon_state = "hair_vox_tielquills" + species_allowed = list(SPECIES_VOX) + +/datum/sprite_accessory/hair/vox_yasuquills_color + name = "Vox Yasu Quills, Colorable" + icon = 'icons/mob/human_face_ch.dmi' + icon_add = 'icons/mob/human_face_ch_add.dmi' + icon_state = "hair_vox_yasu" + species_allowed = list(SPECIES_VOX) diff --git a/code/modules/paperwork/pen.dm b/code/modules/paperwork/pen.dm index 5f5a088b5b..52234db86a 100644 --- a/code/modules/paperwork/pen.dm +++ b/code/modules/paperwork/pen.dm @@ -44,9 +44,21 @@ colour = "red" /obj/item/weapon/pen/fountain - desc = "A well made fountain pen." + desc = "A well made fountain pen, with a faux wood body." icon_state = "pen_fountain" +/obj/item/weapon/pen/fountain2 + desc = "A well made fountain pen, with a faux wood body. This one has golden accents." + icon_state = "pen_fountain" + +/obj/item/weapon/pen/fountain3 + desc = "A well made expesive rosewood pen with golden accents. Very pretty." + icon_state = "pen_fountain" + +/obj/item/weapon/pen/fountain4 + desc = "command fountain pen" + icon_state = "A well made and expensive fountain pen. The nib is quite sharp." + /obj/item/weapon/pen/multi desc = "It's a pen with multiple colors of ink!" var/selectedColor = 1 @@ -190,7 +202,7 @@ colour = "red" /obj/item/weapon/pen/blade/fountain - desc = "A well made fountain pen." + desc = "A well made fountain pen, with a faux wood body." icon_state = "pen_fountain" /* diff --git a/code/modules/projectiles/guns/projectile/boltaction.dm b/code/modules/projectiles/guns/projectile/boltaction.dm index 52e8c17ca9..d90d27ab70 100644 --- a/code/modules/projectiles/guns/projectile/boltaction.dm +++ b/code/modules/projectiles/guns/projectile/boltaction.dm @@ -1,7 +1,8 @@ // For all intents and purposes, these work exactly the same as pump shotguns. It's unnecessary to make their own procs for them. +////////Base Rifle//////// /obj/item/weapon/gun/projectile/shotgun/pump/rifle - name = "bolt action rifle" + name = "bolt-action rifle" desc = "The Hedberg-Hammarstrom Volsung is a modern interpretation of an almost ancient weapon design. The model is popular among hunters and collectors due to its reliability. Uses 7.62mm rounds." description_fluff = "Sif’s largest home-grown firearms manufacturer, the Hedberg-Hammarstrom company offers a range of high-quality, high-cost hunting rifles and shotguns designed with the Sivian wilderness - and its wildlife - in mind. \ The company operates just one production plant in Kalmar, but their weapons have found popularity on garden worlds as far afield as the Tajaran homeworld due to their excellent build quality, precision, and stopping power." @@ -14,20 +15,25 @@ ammo_type = /obj/item/ammo_casing/a762 load_method = SINGLE_CASING|SPEEDLOADER action_sound = 'sound/weapons/riflebolt.ogg' - pump_animation = null + pump_animation = "boltaction-cycling" -/obj/item/weapon/gun/projectile/shotgun/pump/rifle/practice //For target practice +////////Practice Rifle//////// +/obj/item/weapon/gun/projectile/shotgun/pump/rifle/practice // For target practice + name = "practice bolt-action rifle" + icon_state = "boltaction_practice" desc = "A bolt-action rifle with a lightweight synthetic wood stock, designed for competitive shooting. Comes shipped with practice rounds pre-loaded into the gun. Popular among professional marksmen. Uses 7.62mm rounds." ammo_type = /obj/item/ammo_casing/a762/practice + pump_animation = "boltaction_practice-cycling" +////////Ceremonial Rifle//////// /obj/item/weapon/gun/projectile/shotgun/pump/rifle/ceremonial name = "ceremonial bolt-action rifle" desc = "A bolt-action rifle with a heavy, high-quality wood stock that has a beautiful finish. Clearly not intended to be used in combat. Uses 7.62mm rounds." - icon_state = "boltaction_c" item_state = "boltaction_c" + icon_state = "ceremonial_rifle" ammo_type = /obj/item/ammo_casing/a762/blank + pump_animation = "ceremonial_rifle-cycling" -// Stole hacky terrible code from doublebarrel shotgun. -Spades /obj/item/weapon/gun/projectile/shotgun/pump/rifle/ceremonial/attackby(var/obj/item/A as obj, mob/user as mob) if(istype(A, /obj/item/weapon/surgical/circular_saw) || istype(A, /obj/item/weapon/melee/energy) || istype(A, /obj/item/weapon/pickaxe/plasmacutter) && w_class != ITEMSIZE_NORMAL) to_chat(user, "You begin to shorten the barrel and stock of \the [src].") @@ -37,7 +43,7 @@ user.visible_message("[src] goes off!", "The rifle goes off in your face!") return if(do_after(user, 30)) - icon_state = "sawnrifle" + icon_state = "sawn_rifle" w_class = ITEMSIZE_NORMAL recoil = 2 // Owch accuracy = -15 // You know damn well why. @@ -46,11 +52,14 @@ slot_flags |= (SLOT_BELT|SLOT_HOLSTER) //but you can wear it on your belt (poorly concealed under a trenchcoat, ideally) - or in a holster, why not. name = "sawn-off rifle" desc = "The firepower of a rifle, now the size of a pistol, with an effective combat range of about three feet. Uses 7.62mm rounds." + pump_animation = "sawn_rifle-cycling" to_chat(user, "You shorten the barrel and stock of \the [src]!") else ..() //Lever actions are the same thing, but bigger. + +////////Standard Lever Action Rifle//////// /obj/item/weapon/gun/projectile/shotgun/pump/rifle/lever name = "lever-action rifle" desc = "The Hedberg-Hammarstrom Edda is the latest version of an almost ancient weapon design from the 19th century, popular with some due to its simplistic design. This one uses a lever-action to move new rounds into the chamber. Uses 7.62mm rounds." @@ -61,10 +70,12 @@ max_shells = 5 caliber = "7.62mm" load_method = SINGLE_CASING + pump_animation = "leveraction-cycling" +////////Vintage Lever Action Rifle//////// /obj/item/weapon/gun/projectile/shotgun/pump/rifle/lever/vintage name = "vintage repeater" desc = "An iconic manually operated lever action rifle, offering adequate stopping power due to it's still powerful cartridge while at the same time having a rather respectable firing rate due to it's mechanism. It is very probable this is a replica instead of a museum piece, but rifles of this pattern still see usage as colonist guns in some far off regions. Uses 7.62mm rounds." - item_state = "levercarabine" // That isn't how carbine is spelled ya knob! :U - icon_state = "levercarabine" - pump_animation = "levercarabine-cycling" + item_state = "levercarbine" + icon_state = "levercarbine" + pump_animation = "levercarbine-cycling" diff --git a/code/modules/projectiles/guns/projectile/semiauto.dm b/code/modules/projectiles/guns/projectile/semiauto.dm index 1c2fc8e0e1..31dcf48873 100644 --- a/code/modules/projectiles/guns/projectile/semiauto.dm +++ b/code/modules/projectiles/guns/projectile/semiauto.dm @@ -24,6 +24,8 @@ icon_state = "[initial(icon_state)]-e" //Bastard child of a revolver and a semi-auto rifle. + +//Standard Revolving Rifle /obj/item/weapon/gun/projectile/revolvingrifle name = "revolving rifle" desc = "The Gungnir is a novel, antique idea brought into the modern era by Hedberg-Hammarstrom. The semi-automatic revolving mechanism offers no real advantage, but some colonists swear by it. Uses .44 magnum revolver rounds." @@ -31,7 +33,7 @@ The company operates just one production plant in Kalmar, but their weapons have found popularity on garden worlds as far afield as the Tajaran homeworld due to their excellent build quality, \ precision, and stopping power." icon_state = "revolvingrifle" - item_state = "boltaction" + item_state = "rifle" w_class = ITEMSIZE_LARGE caliber = ".44" origin_tech = list(TECH_COMBAT = 3, TECH_MATERIAL = 2) @@ -41,8 +43,9 @@ max_shells = 6 ammo_type = /obj/item/ammo_casing/a44/rifle -/obj/item/weapon/gun/projectile/revolvingrifle/update_icon() - if(ammo_magazine) - icon_state = initial(icon_state) - else - icon_state = "[initial(icon_state)]-e" \ No newline at end of file +//Vintage Revolving Rifle +/obj/item/weapon/gun/projectile/revolvingrifle/vintage + name = "vintage revolving rifle" + desc = "The Willhem is the Gungir's older cousin by Hedberg-Hammarstrom, the perfect collector piece. The semi-automatic revolving mechanism offers no real advantage, but some colonists swear by it. Uses .44 magnum revolver rounds." + icon_state = "vintagerevolvingrifle" + diff --git a/code/modules/projectiles/projectile.dm b/code/modules/projectiles/projectile.dm index b7d5acb883..e230bbe926 100644 --- a/code/modules/projectiles/projectile.dm +++ b/code/modules/projectiles/projectile.dm @@ -658,7 +658,7 @@ return //roll to-hit - miss_modifier = max(15*(distance-2) - accuracy + miss_modifier + target_mob.get_evasion(), 0) + miss_modifier = max(15*(distance-2) - accuracy + miss_modifier + target_mob.get_evasion(), -100) var/hit_zone = get_zone_with_miss_chance(def_zone, target_mob, miss_modifier, ranged_attack=(distance > 1 || original != target_mob)) //if the projectile hits a target we weren't originally aiming at then retain the chance to miss var/result = PROJECTILE_FORCE_MISS diff --git a/code/modules/reagents/reagent_containers/borghypo.dm b/code/modules/reagents/reagent_containers/borghypo.dm index 12a3df61df..544d6e8f42 100644 --- a/code/modules/reagents/reagent_containers/borghypo.dm +++ b/code/modules/reagents/reagent_containers/borghypo.dm @@ -158,6 +158,7 @@ "milk", "mint", "orangejuice", + "redwine", "rum", "sake", "sodawater", @@ -175,8 +176,7 @@ "vodka", "water", "watermelonjuice", - "whiskey", - "wine") + "whiskey") /obj/item/weapon/reagent_containers/borghypo/service/attack(var/mob/M, var/mob/user) return diff --git a/code/modules/surgery/robotics.dm b/code/modules/surgery/robotics.dm index 6ed7dad69d..9c210652c2 100644 --- a/code/modules/surgery/robotics.dm +++ b/code/modules/surgery/robotics.dm @@ -475,11 +475,9 @@ if(clean_name) var/okay = tgui_alert(target,"New name will be '[clean_name]', ok?", "Confirmation",list("Cancel","Ok")) if(okay == "Ok") - new_name = clean_name - - new_name = sanitizeName(new_name, allow_numbers = TRUE) - target.name = new_name - target.real_name = target.name + target.name = new_name + target.real_name = target.name + return /datum/surgery_step/robotics/install_mmi/fail_step(mob/living/user, mob/living/carbon/human/target, target_zone, obj/item/tool) user.visible_message("[user]'s hand slips.", \ diff --git a/code/modules/tgui/modules/appearance_changer.dm b/code/modules/tgui/modules/appearance_changer.dm index fe7bb95440..b125338b30 100644 --- a/code/modules/tgui/modules/appearance_changer.dm +++ b/code/modules/tgui/modules/appearance_changer.dm @@ -91,6 +91,9 @@ if("race") if(can_change(APPEARANCE_RACE) && (params["race"] in valid_species)) if(target.change_species(params["race"])) + if(params["race"] == "Custom Species") + target.custom_species = sanitize(input(usr, "Input custom species name:", + "Custom Species Name") as null|text, MAX_NAME_LEN) cut_data() generate_data(usr) changed_hook(APPEARANCECHANGER_CHANGED_RACE) diff --git a/code/modules/vore/eating/belly_obj_ch.dm b/code/modules/vore/eating/belly_obj_ch.dm index aae9f1e35c..72fd3f0ce4 100644 --- a/code/modules/vore/eating/belly_obj_ch.dm +++ b/code/modules/vore/eating/belly_obj_ch.dm @@ -148,21 +148,21 @@ generated_reagents = list("milk" = 1) reagent_name = "milk" gen_amount = 1 - gen_cost = 15 + gen_cost = 5 reagentid = "milk" reagentcolor = "#DFDFDF" if("Cream") generated_reagents = list("cream" = 1) reagent_name = "cream" gen_amount = 1 - gen_cost = 15 + gen_cost = 5 reagentid = "cream" reagentcolor = "#DFD7AF" if("Honey") generated_reagents = list("honey" = 1) reagent_name = "honey" gen_amount = 1 - gen_cost = 15 + gen_cost = 10 reagentid = "honey" reagentcolor = "#FFFF00" if("Cherry Jelly") //Kinda WIP, allows slime like folks something to stuff others with, should make a generic jelly in future diff --git a/code/modules/vore/eating/belly_obj_vr.dm b/code/modules/vore/eating/belly_obj_vr.dm index 0ccc720744..c9e8b5bb5e 100644 --- a/code/modules/vore/eating/belly_obj_vr.dm +++ b/code/modules/vore/eating/belly_obj_vr.dm @@ -473,7 +473,7 @@ // This is useful in customization boxes and such. The delimiter right now is \n\n so // in message boxes, this looks nice and is easily delimited. /obj/belly/proc/get_messages(type, delim = "\n\n") - ASSERT(type == "smo" || type == "smi" || type == "dmo" || type == "dmp" || type == "em" || type == "ema" || type == "im_digest" || type == "im_hold" || type == "im_absorb" || type == "im_heal" || type == "im_drain") + ASSERT(type == "smo" || type == "smi" || type == "dmo" || type == "dmp" || type == "em" || type == "ema" || type == "im_digest" || type == "im_hold" || type == "im_absorb" || type == "im_heal" || type == "im_drain" || type == "im_steal" || type == "im_egg" || type == "im_shrink" || type == "im_grow" || type == "im_unabsorb") var/list/raw_messages switch(type) @@ -499,7 +499,16 @@ raw_messages = emote_lists[DM_HEAL] if("im_drain") raw_messages = emote_lists[DM_DRAIN] - + if("im_steal") + raw_messages = emote_lists[DM_SIZE_STEAL] + if("im_egg") + raw_messages = emote_lists[DM_EGG] + if("im_shrink") + raw_messages = emote_lists[DM_SHRINK] + if("im_grow") + raw_messages = emote_lists[DM_GROW] + if("im_unabsorb") + raw_messages = emote_lists[DM_UNABSORB] var/messages = null if(raw_messages) messages = raw_messages.Join(delim) @@ -509,7 +518,7 @@ // replacement strings and linebreaks as delimiters (two \n\n by default). // They also sanitize the messages. /obj/belly/proc/set_messages(raw_text, type, delim = "\n\n") - ASSERT(type == "smo" || type == "smi" || type == "dmo" || type == "dmp" || type == "em" || type == "ema" || type == "im_digest" || type == "im_hold" || type == "im_absorb" || type == "im_heal" || type == "im_drain") + ASSERT(type == "smo" || type == "smi" || type == "dmo" || type == "dmp" || type == "em" || type == "ema" || type == "im_digest" || type == "im_hold" || type == "im_absorb" || type == "im_heal" || type == "im_drain" || type == "im_steal" || type == "im_egg" || type == "im_shrink" || type == "im_grow" || type == "im_unabsorb") var/list/raw_list = splittext(html_encode(raw_text),delim) if(raw_list.len > 10) @@ -517,10 +526,10 @@ log_debug("[owner] tried to set [lowertext(name)] with 11+ messages") for(var/i = 1, i <= raw_list.len, i++) - if((length(raw_list[i]) > 160 || length(raw_list[i]) < 10) && !(type == "im_digest" || type == "im_hold" || type == "im_absorb" || type == "im_heal" || type == "im_drain")) //160 is fudged value due to htmlencoding increasing the size + if((length(raw_list[i]) > 160 || length(raw_list[i]) < 10) && !(type == "im_digest" || type == "im_hold" || type == "im_absorb" || type == "im_heal" || type == "im_drain" || type == "im_steal" || type == "im_egg" || type == "im_shrink" || type == "im_grow" || type == "im_unabsorb")) //160 is fudged value due to htmlencoding increasing the size raw_list.Cut(i,i) log_debug("[owner] tried to set [lowertext(name)] with >121 or <10 char message") - else if((type == "im_digest" || type == "im_hold" || type == "im_absorb" || type == "im_heal" || type == "im_drain") && (length(raw_list[i]) > 510 || length(raw_list[i]) < 10)) + else if((type == "im_digest" || type == "im_hold" || type == "im_absorb" || type == "im_heal" || type == "im_drain" || type == "im_steal" || type == "im_egg" || type == "im_shrink" || type == "im_grow" || type == "im_unabsorb") && (length(raw_list[i]) > 510 || length(raw_list[i]) < 10)) raw_list.Cut(i,i) log_debug("[owner] tried to set [lowertext(name)] idle message with >501 or <10 char message") else @@ -553,6 +562,16 @@ emote_lists[DM_HEAL] = raw_list if("im_drain") emote_lists[DM_DRAIN] = raw_list + if("im_steal") + emote_lists[DM_SIZE_STEAL] = raw_list + if("im_egg") + emote_lists[DM_EGG] = raw_list + if("im_shrink") + emote_lists[DM_SHRINK] = raw_list + if("im_grow") + emote_lists[DM_GROW] = raw_list + if("im_unabsorb") + emote_lists[DM_UNABSORB] = raw_list return diff --git a/code/modules/vore/eating/living_vr.dm b/code/modules/vore/eating/living_vr.dm index 5976c6f3de..8651e81997 100644 --- a/code/modules/vore/eating/living_vr.dm +++ b/code/modules/vore/eating/living_vr.dm @@ -985,7 +985,7 @@ /datum/component/vore_panel/proc/vore_panel_click(source, location, control, params, user) var/mob/living/owner = user if(istype(owner) && owner.vorePanel) - INVOKE_ASYNC(owner.vorePanel, .proc/tgui_interact, user) + INVOKE_ASYNC(owner, /mob/living/proc/insidePanel, owner) //CHOMPEdit /** * Screen object for vore panel diff --git a/code/modules/vore/eating/vorepanel_vr.dm b/code/modules/vore/eating/vorepanel_vr.dm index bca8e95ab1..28969352e6 100644 --- a/code/modules/vore/eating/vorepanel_vr.dm +++ b/code/modules/vore/eating/vorepanel_vr.dm @@ -851,6 +851,31 @@ if(new_message) host.vore_selected.set_messages(new_message,"im_drain") + if("im_steal") + var/new_message = input(user,"These are sent to prey every minute when you are on Size Steal mode. Write them in 2nd person ('%pred's %belly squishes down on you.')"+help,"Idle Message (Size Steal)",host.vore_selected.get_messages("im_steal")) as message + if(new_message) + host.vore_selected.set_messages(new_message,"im_steal") + + if("im_egg") + var/new_message = input(user,"These are sent to prey every minute when you are on Encase In Egg mode. Write them in 2nd person ('%pred's %belly squishes down on you.')"+help,"Idle Message (Encase In Egg)",host.vore_selected.get_messages("im_egg")) as message + if(new_message) + host.vore_selected.set_messages(new_message,"im_egg") + + if("im_shrink") + var/new_message = input(user,"These are sent to prey every minute when you are on Shrink mode. Write them in 2nd person ('%pred's %belly squishes down on you.')"+help,"Idle Message (Shrink)",host.vore_selected.get_messages("im_shrink")) as message + if(new_message) + host.vore_selected.set_messages(new_message,"im_shrink") + + if("im_grow") + var/new_message = input(user,"These are sent to prey every minute when you are on Grow mode. Write them in 2nd person ('%pred's %belly squishes down on you.')"+help,"Idle Message (Grow)",host.vore_selected.get_messages("im_grow")) as message + if(new_message) + host.vore_selected.set_messages(new_message,"im_grow") + + if("im_unabsorb") + var/new_message = input(user,"These are sent to prey every minute when you are on Unabsorb mode. Write them in 2nd person ('%pred's %belly squishes down on you.')"+help,"Idle Message (Unabsorb)",host.vore_selected.get_messages("im_unabsorb")) as message + if(new_message) + host.vore_selected.set_messages(new_message,"im_unabsorb") + if("reset") var/confirm = tgui_alert(user,"This will delete any custom messages. Are you sure?","Confirmation",list("Cancel","DELETE")) if(confirm == "DELETE") diff --git a/code/modules/vore/fluffstuff/custom_boxes_vr.dm b/code/modules/vore/fluffstuff/custom_boxes_vr.dm index 3c20b5dd6a..70a1e99b45 100644 --- a/code/modules/vore/fluffstuff/custom_boxes_vr.dm +++ b/code/modules/vore/fluffstuff/custom_boxes_vr.dm @@ -286,6 +286,10 @@ Swimsuits, for general use, to avoid arriving to work with your swimsuit. name = "Medical Swimsuit capsule" has_items = list(/obj/item/clothing/under/swimsuit/fluff/medical) +/obj/item/weapon/storage/box/fluff/swimsuit/cowbikini + name = "Cow Bikini Swimsuit capsule" + has_items = list(/obj/item/clothing/under/swimsuit/cowbikini) + //Monkey boxes for the new primals we have /obj/item/weapon/storage/box/monkeycubes/sobakacubes name = "sobaka cube box" diff --git a/icons/inventory/accessory/item_vr.dmi b/icons/inventory/accessory/item_vr.dmi index fdb8608648..c39fad3292 100644 Binary files a/icons/inventory/accessory/item_vr.dmi and b/icons/inventory/accessory/item_vr.dmi differ diff --git a/icons/inventory/accessory/mob_vr.dmi b/icons/inventory/accessory/mob_vr.dmi index c5e7908d71..7327c9b136 100644 Binary files a/icons/inventory/accessory/mob_vr.dmi and b/icons/inventory/accessory/mob_vr.dmi differ diff --git a/icons/inventory/back/item.dmi b/icons/inventory/back/item.dmi index 050a938805..daa2c46449 100644 Binary files a/icons/inventory/back/item.dmi and b/icons/inventory/back/item.dmi differ diff --git a/icons/inventory/back/item_vr.dmi b/icons/inventory/back/item_vr.dmi index 8e5af1c2af..942813b127 100644 Binary files a/icons/inventory/back/item_vr.dmi and b/icons/inventory/back/item_vr.dmi differ diff --git a/icons/inventory/back/mob_vr.dmi b/icons/inventory/back/mob_vr.dmi index d5e2ef5adf..bfede208b8 100644 Binary files a/icons/inventory/back/mob_vr.dmi and b/icons/inventory/back/mob_vr.dmi differ diff --git a/icons/inventory/eyes/item.dmi b/icons/inventory/eyes/item.dmi index 768235110b..b4ba37ad39 100644 Binary files a/icons/inventory/eyes/item.dmi and b/icons/inventory/eyes/item.dmi differ diff --git a/icons/inventory/head/item.dmi b/icons/inventory/head/item.dmi index 4951bf32ad..bc1ad569c2 100644 Binary files a/icons/inventory/head/item.dmi and b/icons/inventory/head/item.dmi differ diff --git a/icons/inventory/head/mob.dmi b/icons/inventory/head/mob.dmi index 08bf51b4fd..3667c8597b 100644 Binary files a/icons/inventory/head/mob.dmi and b/icons/inventory/head/mob.dmi differ diff --git a/icons/inventory/suit/item.dmi b/icons/inventory/suit/item.dmi index 602ab0bcd2..7bef5fc417 100644 Binary files a/icons/inventory/suit/item.dmi and b/icons/inventory/suit/item.dmi differ diff --git a/icons/inventory/suit/mob.dmi b/icons/inventory/suit/mob.dmi index 6d959d86d8..29a4aa79c9 100644 Binary files a/icons/inventory/suit/mob.dmi and b/icons/inventory/suit/mob.dmi differ diff --git a/icons/inventory/uniform/item.dmi b/icons/inventory/uniform/item.dmi index 08cc0cb815..f0e5d69092 100644 Binary files a/icons/inventory/uniform/item.dmi and b/icons/inventory/uniform/item.dmi differ diff --git a/icons/inventory/uniform/mob.dmi b/icons/inventory/uniform/mob.dmi index 87cee8aca9..e5f028c969 100644 Binary files a/icons/inventory/uniform/mob.dmi and b/icons/inventory/uniform/mob.dmi differ diff --git a/icons/mob/alienanimals_x32.dmi b/icons/mob/alienanimals_x32.dmi new file mode 100644 index 0000000000..c6fc251dc3 Binary files /dev/null and b/icons/mob/alienanimals_x32.dmi differ diff --git a/icons/mob/human_face_ch.dmi b/icons/mob/human_face_ch.dmi index 8e180cabf8..a5d75655f9 100644 Binary files a/icons/mob/human_face_ch.dmi and b/icons/mob/human_face_ch.dmi differ diff --git a/icons/mob/human_face_ch_add.dmi b/icons/mob/human_face_ch_add.dmi index 99a94d2d02..310957e1b1 100644 Binary files a/icons/mob/human_face_ch_add.dmi and b/icons/mob/human_face_ch_add.dmi differ diff --git a/icons/mob/items/lefthand_guns.dmi b/icons/mob/items/lefthand_guns.dmi index 649ddfa028..a7360f8a34 100644 Binary files a/icons/mob/items/lefthand_guns.dmi and b/icons/mob/items/lefthand_guns.dmi differ diff --git a/icons/mob/items/lefthand_melee_vr.dmi b/icons/mob/items/lefthand_melee_vr.dmi index ad144c53b4..edf9142d1f 100644 Binary files a/icons/mob/items/lefthand_melee_vr.dmi and b/icons/mob/items/lefthand_melee_vr.dmi differ diff --git a/icons/mob/items/righthand_guns.dmi b/icons/mob/items/righthand_guns.dmi index 1d0f45bc35..26e830efde 100644 Binary files a/icons/mob/items/righthand_guns.dmi and b/icons/mob/items/righthand_guns.dmi differ diff --git a/icons/mob/items/righthand_melee_vr.dmi b/icons/mob/items/righthand_melee_vr.dmi index e669f0cc84..6558ff4593 100644 Binary files a/icons/mob/items/righthand_melee_vr.dmi and b/icons/mob/items/righthand_melee_vr.dmi differ diff --git a/icons/mob/taursuits_drake_ch.dmi b/icons/mob/taursuits_drake_ch.dmi index 2749f3876a..e427140571 100644 Binary files a/icons/mob/taursuits_drake_ch.dmi and b/icons/mob/taursuits_drake_ch.dmi differ diff --git a/icons/obj/bureaucracy.dmi b/icons/obj/bureaucracy.dmi index 039ea5b632..0c727bddc9 100644 Binary files a/icons/obj/bureaucracy.dmi and b/icons/obj/bureaucracy.dmi differ diff --git a/icons/obj/mining_vr.dmi b/icons/obj/mining_vr.dmi index 249a2b66c8..0ff360ec70 100644 Binary files a/icons/obj/mining_vr.dmi and b/icons/obj/mining_vr.dmi differ diff --git a/icons/obj/stationobjs.dmi b/icons/obj/stationobjs.dmi index 88fa2ab801..adc7011de9 100644 Binary files a/icons/obj/stationobjs.dmi and b/icons/obj/stationobjs.dmi differ diff --git a/icons/obj/storage.dmi b/icons/obj/storage.dmi index 4bcc601e70..b5f2005745 100644 Binary files a/icons/obj/storage.dmi and b/icons/obj/storage.dmi differ diff --git a/sound/items/helmetdeploy.ogg b/sound/items/helmetdeploy.ogg new file mode 100644 index 0000000000..5eca39d8e9 Binary files /dev/null and b/sound/items/helmetdeploy.ogg differ diff --git a/sound/weapons/plasma_cutter.ogg b/sound/weapons/plasma_cutter.ogg new file mode 100644 index 0000000000..d555110afa Binary files /dev/null and b/sound/weapons/plasma_cutter.ogg differ diff --git a/tgui/packages/tgui/interfaces/VorePanel.js b/tgui/packages/tgui/interfaces/VorePanel.js index 00beca1d9d..c7315d1b28 100644 --- a/tgui/packages/tgui/interfaces/VorePanel.js +++ b/tgui/packages/tgui/interfaces/VorePanel.js @@ -428,21 +428,36 @@ const VoreSelectedBelly = (props, context) => {