diff --git a/code/__defines/_planes+layers.dm b/code/__defines/_planes+layers.dm index 3bee841881..c54fbe93cc 100644 --- a/code/__defines/_planes+layers.dm +++ b/code/__defines/_planes+layers.dm @@ -145,6 +145,7 @@ What is the naming convention for planes or layers? #define LAYER_HUD_ITEM 3 //Things sitting on HUD items (largely irrelevant because PLANE_PLAYER_HUD_ITEMS) #define LAYER_HUD_ABOVE 4 //Things that reside above items (highlights) #define PLANE_PLAYER_HUD_ITEMS 96 //Separate layer with which to apply colorblindness +#define PLANE_PLAYER_HUD_ABOVE 97 //Things above the player hud #define PLANE_ADMIN3 99 //Purely for shenanigans (above HUD) diff --git a/code/__defines/misc.dm b/code/__defines/misc.dm index 7f9128a64f..e59d3765dc 100644 --- a/code/__defines/misc.dm +++ b/code/__defines/misc.dm @@ -351,3 +351,8 @@ var/global/list/##LIST_NAME = list();\ #define RAD_LEVEL_MODERATE 10 #define RAD_LEVEL_HIGH 25 #define RAD_LEVEL_VERY_HIGH 50 + +//https://secure.byond.com/docs/ref/info.html#/atom/var/mouse_opacity +#define MOUSE_OPACITY_TRANSPARENT 0 +#define MOUSE_OPACITY_ICON 1 +#define MOUSE_OPACITY_OPAQUE 2 diff --git a/code/_helpers/_lists.dm b/code/_helpers/_lists.dm index 5e322e1928..1eb8ac5456 100644 --- a/code/_helpers/_lists.dm +++ b/code/_helpers/_lists.dm @@ -758,3 +758,8 @@ proc/dd_sortedTextList(list/incoming) . |= i #define listequal(A, B) (A.len == B.len && !length(A^B)) + +/proc/popleft(list/L) + if(L.len) + . = L[1] + L.Cut(1,2) diff --git a/code/_onclick/hud/radial.dm b/code/_onclick/hud/radial.dm new file mode 100644 index 0000000000..e83e5d732c --- /dev/null +++ b/code/_onclick/hud/radial.dm @@ -0,0 +1,313 @@ +#define NEXT_PAGE_ID "__next__" +#define DEFAULT_CHECK_DELAY 20 + +GLOBAL_LIST_EMPTY(radial_menus) + +// Ported from TG + +/obj/screen/radial + icon = 'icons/mob/radial.dmi' + layer = LAYER_HUD_ABOVE + plane = PLANE_PLAYER_HUD_ABOVE + var/datum/radial_menu/parent + +/obj/screen/radial/slice + icon_state = "radial_slice" + var/choice + var/next_page = FALSE + var/tooltips = FALSE + +/obj/screen/radial/slice/MouseEntered(location, control, params) + . = ..() + icon_state = "radial_slice_focus" + if(tooltips) + openToolTip(usr, src, params, title = name) + +/obj/screen/radial/slice/MouseExited(location, control, params) + . = ..() + icon_state = "radial_slice" + if(tooltips) + closeToolTip(usr) + +/obj/screen/radial/slice/Click(location, control, params) + if(usr.client == parent.current_user) + if(next_page) + parent.next_page() + else + parent.element_chosen(choice,usr) + +/obj/screen/radial/center + name = "Close Menu" + icon_state = "radial_center" + +/obj/screen/radial/center/MouseEntered(location, control, params) + . = ..() + icon_state = "radial_center_focus" + +/obj/screen/radial/center/MouseExited(location, control, params) + . = ..() + icon_state = "radial_center" + +/obj/screen/radial/center/Click(location, control, params) + if(usr.client == parent.current_user) + parent.finished = TRUE + +/datum/radial_menu + var/list/choices = list() //List of choice id's + var/list/choices_icons = list() //choice_id -> icon + var/list/choices_values = list() //choice_id -> choice + var/list/page_data = list() //list of choices per page + + + var/selected_choice + var/list/obj/screen/elements = list() + var/obj/screen/radial/center/close_button + var/client/current_user + var/atom/anchor + var/image/menu_holder + var/finished = FALSE + var/datum/callback/custom_check_callback + var/next_check = 0 + var/check_delay = DEFAULT_CHECK_DELAY + + var/radius = 32 + var/starting_angle = 0 + var/ending_angle = 360 + var/zone = 360 + var/min_angle = 45 //Defaults are setup for this value, if you want to make the menu more dense these will need changes. + var/max_elements + var/pages = 1 + var/current_page = 1 + + var/hudfix_method = TRUE //TRUE to change anchor to user, FALSE to shift by py_shift + var/py_shift = 0 + var/entry_animation = TRUE + +//If we swap to vis_contens inventory these will need a redo +/datum/radial_menu/proc/check_screen_border(mob/user) + var/atom/movable/AM = anchor + if(!istype(AM) || !AM.screen_loc) + return + if(AM in user.client.screen) + if(hudfix_method) + anchor = user + else + py_shift = 32 + restrict_to_dir(NORTH) //I was going to parse screen loc here but that's more effort than it's worth. + +//Sets defaults +//These assume 45 deg min_angle +/datum/radial_menu/proc/restrict_to_dir(dir) + switch(dir) + if(NORTH) + starting_angle = 270 + ending_angle = 135 + if(SOUTH) + starting_angle = 90 + ending_angle = 315 + if(EAST) + starting_angle = 0 + ending_angle = 225 + if(WEST) + starting_angle = 180 + ending_angle = 45 + +/datum/radial_menu/proc/setup_menu(use_tooltips) + if(ending_angle > starting_angle) + zone = ending_angle - starting_angle + else + zone = 360 - starting_angle + ending_angle + + max_elements = round(zone / min_angle) + var/paged = max_elements < choices.len + if(elements.len < max_elements) + var/elements_to_add = max_elements - elements.len + for(var/i in 1 to elements_to_add) //Create all elements + var/obj/screen/radial/slice/new_element = new /obj/screen/radial/slice + new_element.tooltips = use_tooltips + new_element.parent = src + elements += new_element + + var/page = 1 + page_data = list(null) + var/list/current = list() + var/list/choices_left = choices.Copy() + while(choices_left.len) + if(current.len == max_elements) + page_data[page] = current + page++ + page_data.len++ + current = list() + if(paged && current.len == max_elements - 1) + current += NEXT_PAGE_ID + continue + else + current += popleft(choices_left) + if(paged && current.len < max_elements) + current += NEXT_PAGE_ID + + page_data[page] = current + pages = page + current_page = 1 + update_screen_objects(anim = entry_animation) + +/datum/radial_menu/proc/update_screen_objects(anim = FALSE) + var/list/page_choices = page_data[current_page] + var/angle_per_element = round(zone / page_choices.len) + for(var/i in 1 to elements.len) + var/obj/screen/radial/E = elements[i] + var/angle = WRAP(starting_angle + (i - 1) * angle_per_element,0,360) + if(i > page_choices.len) + HideElement(E) + else + SetElement(E,page_choices[i],angle,anim = anim,anim_order = i) + +/datum/radial_menu/proc/HideElement(obj/screen/radial/slice/E) + E.cut_overlays() + E.alpha = 0 + E.name = "None" + E.maptext = null + E.mouse_opacity = MOUSE_OPACITY_TRANSPARENT + E.choice = null + E.next_page = FALSE + +/datum/radial_menu/proc/SetElement(obj/screen/radial/slice/E,choice_id,angle,anim,anim_order) + //Position + var/py = round(cos(angle) * radius) + py_shift + var/px = round(sin(angle) * radius) + if(anim) + var/timing = anim_order * 0.5 + var/matrix/starting = matrix() + starting.Scale(0.1,0.1) + E.transform = starting + var/matrix/TM = matrix() + animate(E,pixel_x = px,pixel_y = py, transform = TM, time = timing) + else + E.pixel_y = py + E.pixel_x = px + + //Visuals + E.alpha = 255 + E.mouse_opacity = MOUSE_OPACITY_ICON + E.cut_overlays() + if(choice_id == NEXT_PAGE_ID) + E.name = "Next Page" + E.next_page = TRUE + E.add_overlay("radial_next") + else + if(istext(choices_values[choice_id])) + E.name = choices_values[choice_id] + else + var/atom/movable/AM = choices_values[choice_id] //Movables only + E.name = AM.name + E.choice = choice_id + E.maptext = null + E.next_page = FALSE + if(choices_icons[choice_id]) + E.add_overlay(choices_icons[choice_id]) + +/datum/radial_menu/New() + close_button = new + close_button.parent = src + +/datum/radial_menu/proc/Reset() + choices.Cut() + choices_icons.Cut() + choices_values.Cut() + current_page = 1 + +/datum/radial_menu/proc/element_chosen(choice_id,mob/user) + selected_choice = choices_values[choice_id] + +/datum/radial_menu/proc/get_next_id() + return "c_[choices.len]" + +/datum/radial_menu/proc/set_choices(list/new_choices, use_tooltips) + if(choices.len) + Reset() + for(var/E in new_choices) + var/id = get_next_id() + choices += id + choices_values[id] = E + if(new_choices[E]) + var/I = extract_image(new_choices[E]) + if(I) + choices_icons[id] = I + setup_menu(use_tooltips) + + +/datum/radial_menu/proc/extract_image(E) + var/mutable_appearance/MA = new /mutable_appearance(E) + if(MA) + MA.layer = LAYER_HUD_ABOVE + MA.appearance_flags |= RESET_TRANSFORM + return MA + + +/datum/radial_menu/proc/next_page() + if(pages > 1) + current_page = WRAP(current_page + 1,1,pages+1) + update_screen_objects() + +/datum/radial_menu/proc/show_to(mob/M) + if(current_user) + hide() + if(!M.client || !anchor) + return + current_user = M.client + //Blank + menu_holder = image(icon='icons/effects/effects.dmi',loc=anchor,icon_state="nothing",layer = LAYER_HUD_ABOVE) + menu_holder.appearance_flags |= KEEP_APART + menu_holder.vis_contents += elements + close_button + current_user.images += menu_holder + +/datum/radial_menu/proc/hide() + if(current_user) + current_user.images -= menu_holder + +/datum/radial_menu/proc/wait(atom/user, atom/anchor, require_near = FALSE) + while (current_user && !finished && !selected_choice) + if(require_near && !in_range(anchor, user)) + return + if(custom_check_callback && next_check < world.time) + if(!custom_check_callback.Invoke()) + return + else + next_check = world.time + check_delay + stoplag(1) + +/datum/radial_menu/Destroy() + Reset() + hide() + QDEL_NULL(custom_check_callback) + . = ..() + +/* + Presents radial menu to user anchored to anchor (or user if the anchor is currently in users screen) + Choices should be a list where list keys are movables or text used for element names and return value + and list values are movables/icons/images used for element icons +*/ +/proc/show_radial_menu(mob/user, atom/anchor, list/choices, uniqueid, radius, datum/callback/custom_check, require_near = FALSE, tooltips = FALSE) + if(!user || !anchor || !length(choices)) + return + if(!uniqueid) + uniqueid = "defmenu_[REF(user)]_[REF(anchor)]" + + if(GLOB.radial_menus[uniqueid]) + return + + var/datum/radial_menu/menu = new + GLOB.radial_menus[uniqueid] = menu + if(radius) + menu.radius = radius + if(istype(custom_check)) + menu.custom_check_callback = custom_check + menu.anchor = anchor + menu.check_screen_border(user) //Do what's needed to make it look good near borders or on hud + menu.set_choices(choices, tooltips) + menu.show_to(user) + menu.wait(user, anchor, require_near) + var/answer = menu.selected_choice + QDEL_NULL(menu) + GLOB.radial_menus -= uniqueid + return answer \ No newline at end of file diff --git a/code/_onclick/hud/radial_persistent.dm b/code/_onclick/hud/radial_persistent.dm new file mode 100644 index 0000000000..feaf17c1b2 --- /dev/null +++ b/code/_onclick/hud/radial_persistent.dm @@ -0,0 +1,75 @@ +/* + A derivative of radial menu which persists onscreen until closed and invokes a callback each time an element is clicked +*/ + +/obj/screen/radial/persistent/center + name = "Close Menu" + icon_state = "radial_center" + +/obj/screen/radial/persistent/center/Click(location, control, params) + if(usr.client == parent.current_user) + parent.element_chosen(null,usr) + +/obj/screen/radial/persistent/center/MouseEntered(location, control, params) + . = ..() + icon_state = "radial_center_focus" + +/obj/screen/radial/persistent/center/MouseExited(location, control, params) + . = ..() + icon_state = "radial_center" + + + +/datum/radial_menu/persistent + var/uniqueid + var/datum/callback/select_proc_callback + +/datum/radial_menu/persistent/New() + close_button = new /obj/screen/radial/persistent/center + close_button.parent = src + + +/datum/radial_menu/persistent/element_chosen(choice_id,mob/user) + select_proc_callback.Invoke(choices_values[choice_id]) + + +/datum/radial_menu/persistent/proc/change_choices(list/newchoices, tooltips) + if(!newchoices.len) + return + Reset() + set_choices(newchoices,tooltips) + +/datum/radial_menu/persistent/Destroy() + QDEL_NULL(select_proc_callback) + GLOB.radial_menus -= uniqueid + Reset() + hide() + . = ..() + +/* + Creates a persistent radial menu and shows it to the user, anchored to anchor (or user if the anchor is currently in users screen). + Choices should be a list where list keys are movables or text used for element names and return value + and list values are movables/icons/images used for element icons + Select_proc is the proc to be called each time an element on the menu is clicked, and should accept the chosen element as its final argument + Clicking the center button will return a choice of null +*/ +/proc/show_radial_menu_persistent(mob/user, atom/anchor, list/choices, datum/callback/select_proc, uniqueid, radius, tooltips = FALSE) + if(!user || !anchor || !length(choices) || !select_proc) + return + if(!uniqueid) + uniqueid = "defmenu_[REF(user)]_[REF(anchor)]" + + if(GLOB.radial_menus[uniqueid]) + return + + var/datum/radial_menu/persistent/menu = new + menu.uniqueid = uniqueid + GLOB.radial_menus[uniqueid] = menu + if(radius) + menu.radius = radius + menu.select_proc_callback = select_proc + menu.anchor = anchor + menu.check_screen_border(user) //Do what's needed to make it look good near borders or on hud + menu.set_choices(choices, tooltips) + menu.show_to(user) + return menu diff --git a/code/controllers/Processes/supply.dm b/code/controllers/Processes/supply.dm index f71cd8fd1d..640b99121f 100644 --- a/code/controllers/Processes/supply.dm +++ b/code/controllers/Processes/supply.dm @@ -226,7 +226,7 @@ var/datum/controller/supply/supply_controller = new() A.req_access = list(SP.access) else if(islist(SP.access)) var/list/L = SP.access // access var is a plain var, we need a list - A.req_access = L.Copy() + A.req_one_access = L.Copy() //VOREStation Edit: Lets make sense else log_debug("Supply pack with invalid access restriction [SP.access] encountered!") diff --git a/code/controllers/subsystems/timer.dm b/code/controllers/subsystems/timer.dm index b743e8ff9e..3dcc64db28 100644 --- a/code/controllers/subsystems/timer.dm +++ b/code/controllers/subsystems/timer.dm @@ -1,12 +1,11 @@ -#define BUCKET_LEN (world.fps*1*60) //how many ticks should we keep in the bucket. (1 minutes worth) -#define BUCKET_POS(timer) ((round((timer.timeToRun - SStimer.head_offset) / world.tick_lag) % BUCKET_LEN)||BUCKET_LEN) +#define BUCKET_LEN (round(10*(60/world.tick_lag), 1)) //how many ticks should we keep in the bucket. (1 minutes worth) +#define BUCKET_POS(timer) (((round((timer.timeToRun - SStimer.head_offset) / world.tick_lag)+1) % BUCKET_LEN)||BUCKET_LEN) #define TIMER_MAX (world.time + TICKS2DS(min(BUCKET_LEN-(SStimer.practical_offset-DS2TICKS(world.time - SStimer.head_offset))-1, BUCKET_LEN-1))) #define TIMER_ID_MAX (2**24) //max float with integer precision SUBSYSTEM_DEF(timer) name = "Timer" wait = 1 //SS_TICKER subsystem, so wait is in ticks - priority = FIRE_PRIORITY_TIMERS //VOREStation Emergency Edit init_order = INIT_ORDER_TIMER flags = SS_TICKER|SS_NO_INIT @@ -95,8 +94,8 @@ SUBSYSTEM_DEF(timer) if(ctime_timer.flags & TIMER_LOOP) ctime_timer.spent = 0 - clienttime_timers.Insert(ctime_timer, 1) - cut_start_index++ + ctime_timer.timeToRun = REALTIMEOFDAY + ctime_timer.wait + BINARY_INSERT(ctime_timer, clienttime_timers, datum/timedevent, timeToRun) else qdel(ctime_timer) @@ -270,7 +269,7 @@ SUBSYSTEM_DEF(timer) var/new_bucket_count var/i = 1 for (i in 1 to length(alltimers)) - var/datum/timedevent/timer = alltimers[1] + var/datum/timedevent/timer = alltimers[i] if (!timer) continue diff --git a/code/datums/supplypacks/contraband.dm b/code/datums/supplypacks/contraband.dm index 11ec2f8862..d0caadf74f 100644 --- a/code/datums/supplypacks/contraband.dm +++ b/code/datums/supplypacks/contraband.dm @@ -84,7 +84,8 @@ /obj/item/weapon/storage/box/syndie_kit/chameleon, /obj/item/device/encryptionkey/syndicate, /obj/item/weapon/card/id/syndicate, - /obj/item/clothing/mask/gas/voice + /obj/item/clothing/mask/gas/voice, + /obj/item/weapon/makeover ), list( //the professional, /obj/item/weapon/gun/energy/ionrifle/pistol, diff --git a/code/datums/supplypacks/engineering_vr.dm b/code/datums/supplypacks/engineering_vr.dm index e334268426..273d3f6558 100644 --- a/code/datums/supplypacks/engineering_vr.dm +++ b/code/datums/supplypacks/engineering_vr.dm @@ -4,6 +4,7 @@ cost = 30 containertype = /obj/structure/closet/crate/large containername = "thermal regulator crate" + access = access_atmospherics /datum/supply_pack/eng/radsuit contains = list( diff --git a/code/datums/supplypacks/misc_vr.dm b/code/datums/supplypacks/misc_vr.dm index 973840f5b2..f85d7b9723 100644 --- a/code/datums/supplypacks/misc_vr.dm +++ b/code/datums/supplypacks/misc_vr.dm @@ -39,7 +39,10 @@ cost = 150 containertype = /obj/structure/closet/crate/secure/gear containername = "eva hardsuit crate" - access = access_mining + access = list(access_mining, + access_eva, + access_explorer, + access_pilot) /datum/supply_pack/misc/mining_rig name = "industrial hardsuit (empty)" @@ -49,4 +52,5 @@ cost = 150 containertype = /obj/structure/closet/crate/secure/gear containername = "industrial hardsuit crate" - access = access_mining \ No newline at end of file + access = list(access_mining, + access_eva) \ No newline at end of file diff --git a/code/datums/supplypacks/security.dm b/code/datums/supplypacks/security.dm index 40698def5d..4e4c8c1311 100644 --- a/code/datums/supplypacks/security.dm +++ b/code/datums/supplypacks/security.dm @@ -31,7 +31,6 @@ cost = 40 containertype = /obj/structure/closet/crate/secure/gear containername = "Armor crate" - access_armory //VOREStation Add - Armor is for the armory. /datum/supply_pack/security/riot_gear name = "Gear - Riot" diff --git a/code/datums/supplypacks/security_vr.dm b/code/datums/supplypacks/security_vr.dm index 3538a311d5..12f2fa33b3 100644 --- a/code/datums/supplypacks/security_vr.dm +++ b/code/datums/supplypacks/security_vr.dm @@ -17,6 +17,9 @@ access_xenobiology) */ +/datum/supply_pack/randomised/security/armor + access = access_armory + /datum/supply_pack/security/biosuit contains = list( /obj/item/clothing/head/bio_hood/security = 3, diff --git a/code/datums/supplypacks/voidsuits_vr.dm b/code/datums/supplypacks/voidsuits_vr.dm index ccf296a10a..8fcfd8ae50 100644 --- a/code/datums/supplypacks/voidsuits_vr.dm +++ b/code/datums/supplypacks/voidsuits_vr.dm @@ -62,7 +62,6 @@ ) /datum/supply_pack/voidsuits/supply - name = "Mining voidsuits" contains = list( /obj/item/clothing/suit/space/void/mining = 3, /obj/item/clothing/head/helmet/space/void/mining = 3, diff --git a/code/datums/uplink/stealth_items.dm b/code/datums/uplink/stealth_items.dm index 57d379d3fc..0a17e659a6 100644 --- a/code/datums/uplink/stealth_items.dm +++ b/code/datums/uplink/stealth_items.dm @@ -33,3 +33,8 @@ name = "Voice Changer" item_cost = 15 path = /obj/item/clothing/mask/gas/voice + +/datum/uplink_item/item/stealth_items/makeover + name = "Makeover Kit" + item_cost = 5 + path = /obj/item/weapon/makeover \ No newline at end of file diff --git a/code/game/atoms_movable.dm b/code/game/atoms_movable.dm index 104fa066b6..7154b9f47d 100644 --- a/code/game/atoms_movable.dm +++ b/code/game/atoms_movable.dm @@ -16,7 +16,8 @@ var/moved_recently = 0 var/mob/pulledby = null var/item_state = null // Used to specify the item state for the on-mob overlays. - var/icon_scale = 1 // Used to scale icons up or down in update_transform(). + var/icon_scale_x = 1 // Used to scale icons up or down horizonally in update_transform(). + var/icon_scale_y = 1 // Used to scale icons up or down vertically in update_transform(). var/icon_rotation = 0 // Used to rotate icons in update_transform() var/old_x = 0 var/old_y = 0 @@ -476,13 +477,18 @@ /atom/movable/proc/update_transform() var/matrix/M = matrix() - M.Scale(icon_scale) + M.Scale(icon_scale_x, icon_scale_y) M.Turn(icon_rotation) src.transform = M // Use this to set the object's scale. -/atom/movable/proc/adjust_scale(new_scale) - icon_scale = new_scale +/atom/movable/proc/adjust_scale(new_scale_x, new_scale_y) + if(isnull(new_scale_y)) + new_scale_y = new_scale_x + if(new_scale_x != 0) + icon_scale_x = new_scale_x + if(new_scale_y != 0) + icon_scale_y = new_scale_y update_transform() /atom/movable/proc/adjust_rotation(new_rotation) diff --git a/code/game/objects/items/bells.dm b/code/game/objects/items/bells.dm new file mode 100644 index 0000000000..43046d22b7 --- /dev/null +++ b/code/game/objects/items/bells.dm @@ -0,0 +1,90 @@ +/obj/item/weapon/deskbell + name = "desk bell" + desc = "An annoying bell. Ring for service." + icon = 'icons/obj/items.dmi' + icon_state = "deskbell" + force = 2 + throwforce = 2 + w_class = 2.0 + var/broken + attack_verb = list("annoyed") + var/static/radial_examine = image(icon = 'icons/mob/radial.dmi', icon_state = "radial_examine") + var/static/radial_use = image(icon = 'icons/mob/radial.dmi', icon_state = "radial_use") + +/obj/item/weapon/deskbell/examine(mob/user) + ..() + if(broken) + to_chat(user,"It looks damaged, the ringer is stuck firmly inside.") + +/obj/item/weapon/deskbell/attack(mob/target as mob, mob/living/user as mob) + if(!broken) + playsound(user.loc, 'sound/effects/deskbell.ogg', 50, 1) + ..() + +/obj/item/weapon/deskbell/attack_hand(mob/user) + + //This defines the radials and what call we're assiging to them. + var/list/options = list() + options["examine"] = radial_examine + if(!broken) + options["use"] = radial_use + + + // Just an example, if the bell had no options, due to conditionals, nothing would happen here. + if(length(options) < 1) + return + + // Right, if there's only one available radial... + // For example, say, the bell's broken so you can only examine, it just does that (doesn't show radial).. + var/list/choice = list() + if(length(options) == 1) + for(var/key in options) + choice = key + else + // If we have other options, it will show the radial menu for the player to decide. + choice = show_radial_menu(user, src, options, require_near = !issilicon(user)) + + // Once the player has decided their option, choose the behaviour that will happen under said option. + switch(choice) + if("examine") + examine(user) + + if("use") + if(check_ability(user)) + ring(user) + add_fingerprint(user) + +/obj/item/weapon/deskbell/proc/ring(mob/user) + if(user.a_intent == "harm") + playsound(user.loc, 'sound/effects/deskbell_rude.ogg', 50, 1) + to_chat(user,"You hammer [src] rudely!") + if (prob(2)) + break_bell(user) + else + playsound(user.loc, 'sound/effects/deskbell.ogg', 50, 1) + to_chat(user,"You gracefully ring [src].") + +/obj/item/weapon/deskbell/proc/check_ability(mob/user) + if (ishuman(user)) + var/mob/living/carbon/human/H = user + var/obj/item/organ/external/temp = H.organs_by_name["r_hand"] + if (H.hand) + temp = H.organs_by_name["l_hand"] + if(temp && !temp.is_usable()) + to_chat(H,"You try to move your [temp.name], but cannot!") + return 0 + return 1 + else + to_chat(user,"You are not able to ring [src].") + return 0 + +/obj/item/weapon/deskbell/attackby(obj/item/i, mob/user, params) + if(!istype(i)) + return + if(!broken) + ring(user) + + +/obj/item/weapon/deskbell/proc/break_bell(mob/user) + to_chat(user,"The ringing abruptly stops as [src]'s ringer gets jammed inside!") + broken = 1 diff --git a/code/game/objects/items/weapons/cosmetics.dm b/code/game/objects/items/weapons/cosmetics.dm index 3d142b223a..4533f41537 100644 --- a/code/game/objects/items/weapons/cosmetics.dm +++ b/code/game/objects/items/weapons/cosmetics.dm @@ -87,4 +87,26 @@ text = "guy" if(FEMALE) text = "lady" - user.visible_message("[user] uses [src] to comb their hair with incredible style and sophistication. What a [text].") \ No newline at end of file + user.visible_message("[user] uses [src] to comb their hair with incredible style and sophistication. What a [text].") + +/obj/item/weapon/makeover + name = "makeover kit" + desc = "A tiny case containing a mirror and some contact lenses." + w_class = ITEMSIZE_TINY + icon = 'icons/obj/items.dmi' + icon_state = "trinketbox" + var/list/ui_users = list() + +/obj/item/weapon/makeover/attack_self(mob/living/carbon/user as mob) + if(ishuman(user)) + to_chat(user, "You flip open \the [src] and begin to adjust your appearance.") + var/datum/nano_module/appearance_changer/AC = ui_users[user] + if(!AC) + AC = new(src, user) + AC.name = "SalonPro Porta-Makeover Deluxe™" + ui_users[user] = AC + AC.ui_interact(user) + var/mob/living/carbon/human/H = user + var/obj/item/organ/internal/eyes/E = H.internal_organs_by_name[O_EYES] + if(istype(E)) + E.change_eye_color() \ No newline at end of file diff --git a/code/game/objects/items/weapons/storage/wallets.dm b/code/game/objects/items/weapons/storage/wallets.dm index ce1227014c..95db86460e 100644 --- a/code/game/objects/items/weapons/storage/wallets.dm +++ b/code/game/objects/items/weapons/storage/wallets.dm @@ -35,7 +35,8 @@ /obj/item/weapon/tool/screwdriver, /obj/item/weapon/stamp, /obj/item/clothing/accessory/permit, - /obj/item/clothing/accessory/badge + /obj/item/clothing/accessory/badge, + /obj/item/weapon/makeover ) cant_hold = list(/obj/item/weapon/tool/screwdriver/power) slot_flags = SLOT_ID diff --git a/code/game/objects/random/misc.dm b/code/game/objects/random/misc.dm index 0f9f85582f..8f3a50bbed 100644 --- a/code/game/objects/random/misc.dm +++ b/code/game/objects/random/misc.dm @@ -519,4 +519,13 @@ /obj/effect/decal/cleanable/ash, /obj/item/weapon/cigbutt, /obj/item/weapon/cigbutt/cigarbutt, - /obj/effect/decal/remains/mouse) \ No newline at end of file + /obj/effect/decal/remains/mouse) + +/obj/random/janusmodule + name = "random janus circuit" + desc = "A random (possibly broken) Janus module." + icon = 'icons/obj/abductor.dmi' + icon_state = "circuit_damaged" + +/obj/random/janusmodule/item_to_spawn() + return pick(subtypesof(/obj/item/weapon/circuitboard/mecha/imperion)) diff --git a/code/game/objects/structures/flora/trees.dm b/code/game/objects/structures/flora/trees.dm index 6db66fc01a..c02d813ffc 100644 --- a/code/game/objects/structures/flora/trees.dm +++ b/code/game/objects/structures/flora/trees.dm @@ -14,11 +14,27 @@ var/product_amount = 10 // How much of a stack you get, if the above is defined. var/is_stump = FALSE // If true, suspends damage tracking and most other effects. var/indestructable = FALSE // If true, the tree cannot die. + var/randomize_size = FALSE // If true, the tree will choose a random scale in the X and Y directions to stretch. /obj/structure/flora/tree/Initialize() icon_state = choose_icon_state() + + if(randomize_size) + icon_scale_x = rand(90, 125) / 100 + icon_scale_y = rand(90, 125) / 100 + + if(prob(50)) + icon_scale_x *= -1 + update_transform() + return ..() +/obj/structure/flora/tree/update_transform() + var/matrix/M = matrix() + M.Scale(icon_scale_x, icon_scale_y) + M.Translate(0, 16*(icon_scale_y-1)) + animate(src, transform = M, time = 10) + // Override this for special icons. /obj/structure/flora/tree/proc/choose_icon_state() return icon_state @@ -57,8 +73,11 @@ /obj/structure/flora/tree/proc/hit_animation() var/init_px = pixel_x var/shake_dir = pick(-1, 1) - animate(src, transform=turn(matrix(), shake_animation_degrees * shake_dir), pixel_x=init_px + 2*shake_dir, time=1) - animate(transform=null, pixel_x=init_px, time=6, easing=ELASTIC_EASING) + var/matrix/M = matrix() + M.Scale(icon_scale_x, icon_scale_y) + M.Translate(0, 16*(icon_scale_y-1)) + animate(src, transform=turn(M, shake_animation_degrees * shake_dir), pixel_x=init_px + 2*shake_dir, time=1) + animate(transform=M, pixel_x=init_px, time=6, easing=ELASTIC_EASING) // Used when the tree gets hurt. /obj/structure/flora/tree/proc/adjust_health(var/amount, var/damage_wood = FALSE) @@ -282,13 +301,19 @@ base_state = "tree_sif" product = /obj/item/stack/material/log/sif catalogue_data = list(/datum/category_item/catalogue/flora/sif_tree) + randomize_size = TRUE + var/light_shift = 0 + +/obj/structure/flora/tree/sif/choose_icon_state() + light_shift = rand(0, 5) + return "[base_state][light_shift]" /obj/structure/flora/tree/sif/Initialize() + . = ..() update_icon() - return ..() /obj/structure/flora/tree/sif/update_icon() - set_light(5, 1, "#33ccff") - var/image/glow = image(icon = 'icons/obj/flora/deadtrees.dmi', icon_state = "[base_state]_glow") + set_light(5 - light_shift, 1, "#33ccff") // 5 variants, missing bulbs. 5th has no bulbs, so no glow. + var/image/glow = image(icon = icon, icon_state = "[base_state][light_shift]_glow") glow.plane = PLANE_LIGHTING_ABOVE overlays = list(glow) diff --git a/code/game/objects/structures/loot_piles.dm b/code/game/objects/structures/loot_piles.dm index c9731a0568..c94003e9fb 100644 --- a/code/game/objects/structures/loot_piles.dm +++ b/code/game/objects/structures/loot_piles.dm @@ -781,7 +781,8 @@ Loot piles can be depleted, if loot_depleted is turned on. Note that players wh // Todo: Better loot. /obj/structure/loot_pile/mecha/gygax/dark/adv icon_state = "darkgygax_adv-broken" - icon_scale = 1.5 + icon_scale_x = 1.5 + icon_scale_y = 1.5 pixel_y = 8 /obj/structure/loot_pile/mecha/gygax/medgax diff --git a/code/modules/client/preference_setup/general/03_body.dm b/code/modules/client/preference_setup/general/03_body.dm index cda61be1b3..6f35aff05f 100644 --- a/code/modules/client/preference_setup/general/03_body.dm +++ b/code/modules/client/preference_setup/general/03_body.dm @@ -383,6 +383,16 @@ var/global/list/valid_bloodtypes = list("A+", "A-", "B+", "B-", "AB+", "AB-", "O if(!pref.species_preview || !(pref.species_preview in all_species)) return TOPIC_NOACTION + var/datum/species/setting_species + + if(all_species[href_list["set_species"]]) + setting_species = all_species[href_list["set_species"]] + else + return TOPIC_NOACTION + + if(((!(setting_species.spawn_flags & SPECIES_CAN_JOIN)) || (!is_alien_whitelisted(preference_mob(),setting_species))) && !check_rights(R_ADMIN, 0)) + return TOPIC_NOACTION + var/prev_species = pref.species pref.species = href_list["set_species"] if(prev_species != pref.species) diff --git a/code/modules/events/event_container.dm b/code/modules/events/event_container.dm index dee085dc2b..a4c55b27ae 100644 --- a/code/modules/events/event_container.dm +++ b/code/modules/events/event_container.dm @@ -22,6 +22,9 @@ var/global/list/severity_to_string = list(EVENT_LEVEL_MUNDANE = "Mundane", EVENT var/last_world_time = 0 /datum/event_container/process() + if(!round_start_time) + return //don't do events if the round hasn't even started yet + if(!next_event_time) set_event_delay() diff --git a/code/modules/materials/material_recipes.dm b/code/modules/materials/material_recipes.dm index 721b54826e..f45adba787 100644 --- a/code/modules/materials/material_recipes.dm +++ b/code/modules/materials/material_recipes.dm @@ -14,6 +14,7 @@ recipes += new/datum/stack_recipe("[display_name] grave marker", /obj/item/weapon/material/gravemarker, 5, time = 50, supplied_material = "[name]") recipes += new/datum/stack_recipe("[display_name] ring", /obj/item/clothing/gloves/ring/material, 1, on_floor = 1, supplied_material = "[name]") recipes += new/datum/stack_recipe("[display_name] bracelet", /obj/item/clothing/accessory/bracelet/material, 1, on_floor = 1, supplied_material = "[name]") + recipes += new/datum/stack_recipe("[display_name] deskbell", /obj/item/weapon/deskbell, 1, on_floor = 1, supplied_material = "[name]") if(integrity>=50) recipes += new/datum/stack_recipe("[display_name] door", /obj/structure/simple_door, 10, one_per_turf = 1, on_floor = 1, supplied_material = "[name]") diff --git a/code/modules/materials/material_sheets.dm b/code/modules/materials/material_sheets.dm index 1035c70eba..1fbecaec7e 100644 --- a/code/modules/materials/material_sheets.dm +++ b/code/modules/materials/material_sheets.dm @@ -275,6 +275,8 @@ return /obj/item/stack/material/supermatter/attack_hand(mob/user) + . = ..() + update_mass() radiation_repository.radiate(src, 5 + amount) var/mob/living/M = user diff --git a/code/modules/mining/drilling/drill.dm b/code/modules/mining/drilling/drill.dm index 08580c7f97..bdfab8f92b 100644 --- a/code/modules/mining/drilling/drill.dm +++ b/code/modules/mining/drilling/drill.dm @@ -318,13 +318,13 @@ name = "mining drill brace" desc = "A machinery brace for an industrial drill. It looks easily two feet thick." icon_state = "mining_brace" + circuit = /obj/item/weapon/circuitboard/miningdrillbrace var/obj/machinery/mining/drill/connected /obj/machinery/mining/brace/New() ..() component_parts = list() - component_parts += new /obj/item/weapon/circuitboard/miningdrillbrace(src) /obj/machinery/mining/brace/attackby(obj/item/weapon/W as obj, mob/user as mob) if(connected && connected.active) diff --git a/code/modules/mob/_modifiers/modifiers.dm b/code/modules/mob/_modifiers/modifiers.dm index 6e738094a1..665ae80617 100644 --- a/code/modules/mob/_modifiers/modifiers.dm +++ b/code/modules/mob/_modifiers/modifiers.dm @@ -42,7 +42,8 @@ var/accuracy // Positive numbers makes hitting things with guns easier, negatives make it harder. var/accuracy_dispersion // Positive numbers make gun firing cover a wider tile range, and therefore more inaccurate. Negatives help negate dispersion penalties. var/metabolism_percent // Adjusts the mob's metabolic rate, which affects reagent processing. Won't affect mobs without reagent processing. - var/icon_scale_percent // Makes the holder's icon get scaled up or down. + var/icon_scale_x_percent // Makes the holder's icon get scaled wider or thinner. + var/icon_scale_y_percent // Makes the holder's icon get scaled taller or shorter. var/attack_speed_percent // Makes the holder's 'attack speed' (click delay) shorter or longer. var/pain_immunity // Makes the holder not care about pain while this is on. Only really useful to human mobs. var/pulse_modifier // Modifier for pulse, will be rounded on application, then added to the normal 'pulse' multiplier which ranges between 0 and 5 normally. Only applied if they're living. @@ -73,7 +74,7 @@ holder.modifiers.Remove(src) if(mob_overlay_state) // We do this after removing ourselves from the list so that the overlay won't remain. holder.update_modifier_visuals() - if(icon_scale_percent) // Correct the scaling. + if(icon_scale_x_percent || icon_scale_y_percent) // Correct the scaling. holder.update_transform() if(client_color) holder.update_client_color() @@ -140,7 +141,7 @@ mod.on_applied() if(mod.mob_overlay_state) update_modifier_visuals() - if(mod.icon_scale_percent) + if(mod.icon_scale_x_percent || mod.icon_scale_y_percent) update_transform() if(mod.client_color) update_client_color() @@ -232,8 +233,11 @@ effects += "Your metabolism is [metabolism_percent > 1.0 ? "faster" : "slower"], \ causing reagents in your body to process, and hunger to occur [multipler_to_percentage(metabolism_percent, TRUE)] [metabolism_percent > 1.0 ? "faster" : "slower"]." - if(!isnull(icon_scale_percent)) - effects += "Your appearance is [multipler_to_percentage(icon_scale_percent, TRUE)] [icon_scale_percent > 1 ? "larger" : "smaller"]." + if(!isnull(icon_scale_x_percent)) + effects += "Your appearance is [multipler_to_percentage(icon_scale_x_percent, TRUE)] [icon_scale_x_percent > 1 ? "wider" : "thinner"]." + + if(!isnull(icon_scale_y_percent)) + effects += "Your appearance is [multipler_to_percentage(icon_scale_y_percent, TRUE)] [icon_scale_y_percent > 1 ? "taller" : "shorter"]." if(!isnull(attack_speed_percent)) effects += "The delay between attacking is [multipler_to_percentage(attack_speed_percent, TRUE)] [disable_duration_percent > 1.0 ? "longer" : "shorter"]." diff --git a/code/modules/mob/_modifiers/modifiers_misc.dm b/code/modules/mob/_modifiers/modifiers_misc.dm index 7d1ab792ff..e81cf0aaa8 100644 --- a/code/modules/mob/_modifiers/modifiers_misc.dm +++ b/code/modules/mob/_modifiers/modifiers_misc.dm @@ -56,7 +56,8 @@ the artifact triggers the rage. outgoing_melee_damage_percent = 1.5 // 50% more damage from melee. max_health_percent = 1.5 // More health as a buffer, however the holder might fall into crit after this expires if they're mortally wounded. disable_duration_percent = 0.25 // Disables only last 25% as long. - icon_scale_percent = 1.2 // Look scarier. + icon_scale_x_percent = 1.2 // Look scarier. + icon_scale_y_percent = 1.2 pain_immunity = TRUE // Avoid falling over from shock (at least until it expires). // The less good stuff. diff --git a/code/modules/mob/_modifiers/traits.dm b/code/modules/mob/_modifiers/traits.dm index d0b0abfd89..200f8eabfb 100644 --- a/code/modules/mob/_modifiers/traits.dm +++ b/code/modules/mob/_modifiers/traits.dm @@ -64,25 +64,29 @@ name = "Larger" desc = "Your body is larger than average." - icon_scale_percent = 1.1 + icon_scale_x_percent = 1.1 + icon_scale_y_percent = 1.1 /datum/modifier/trait/large name = "Large" desc = "Your body is a bit larger than average." - icon_scale_percent = 1.05 + icon_scale_x_percent = 1.05 + icon_scale_y_percent = 1.05 /datum/modifier/trait/small name = "Small" desc = "Your body is a bit smaller than average." - icon_scale_percent = 0.95 + icon_scale_x_percent = 0.95 + icon_scale_y_percent = 0.95 /datum/modifier/trait/smaller name = "Smaller" desc = "Your body is smaller than average." - icon_scale_percent = 0.9 + icon_scale_x_percent = 0.9 + icon_scale_y_percent = 0.9 /datum/modifier/trait/colorblind_protanopia name = "Protanopia" diff --git a/code/modules/mob/_modifiers/unholy.dm b/code/modules/mob/_modifiers/unholy.dm index 0eadabc83a..0b6f69a21b 100644 --- a/code/modules/mob/_modifiers/unholy.dm +++ b/code/modules/mob/_modifiers/unholy.dm @@ -14,7 +14,8 @@ disable_duration_percent = 0.25 // Disables only last 25% as long. incoming_damage_percent = 0.5 // 50% incoming damage. - icon_scale_percent = 1.2 // Become a bigger target. + icon_scale_x_percent = 1.2 // Become a bigger target. + icon_scale_y_percent = 1.2 pain_immunity = TRUE slowdown = 2 diff --git a/code/modules/mob/living/carbon/human/human.dm b/code/modules/mob/living/carbon/human/human.dm index 90c8f40ec0..0cf20396d8 100644 --- a/code/modules/mob/living/carbon/human/human.dm +++ b/code/modules/mob/living/carbon/human/human.dm @@ -1139,8 +1139,8 @@ if(species.default_language) add_language(species.default_language) - //if(species.icon_scale != 1) //VOREStation Removal - // update_transform() //VOREStation Removal + //if(species.icon_scale_x != 1 || species.icon_scale_y != 1) //VOREStation Removal + // update_transform() //VOREStation Removal if(example) //VOREStation Edit begin if(!(example == src)) diff --git a/code/modules/mob/living/carbon/human/species/species.dm b/code/modules/mob/living/carbon/human/species/species.dm index 95f909950c..c2bb8cafe4 100644 --- a/code/modules/mob/living/carbon/human/species/species.dm +++ b/code/modules/mob/living/carbon/human/species/species.dm @@ -32,7 +32,8 @@ var/tail_animation // If set, the icon to obtain tail animation states from. var/tail_hair - var/icon_scale = 1 // Makes the icon larger/smaller. + var/icon_scale_x = 1 // Makes the icon wider/thinner. + var/icon_scale_y = 1 // Makes the icon taller/shorter. var/race_key = 0 // Used for mob icon cache string. var/icon/icon_template // Used for mob icon generation for non-32x32 species. diff --git a/code/modules/mob/living/carbon/human/update_icons.dm b/code/modules/mob/living/carbon/human/update_icons.dm index 7a96239092..bb861986b8 100644 --- a/code/modules/mob/living/carbon/human/update_icons.dm +++ b/code/modules/mob/living/carbon/human/update_icons.dm @@ -124,15 +124,20 @@ var/global/list/damage_icon_parts = list() //see UpdateDamageIcon() /mob/living/carbon/human/update_transform() /* VOREStation Edit START - TODO - Consider switching to icon_scale // First, get the correct size. - var/desired_scale = icon_scale + var/desired_scale_x = icon_scale_x + var/desired_scale_y = icon_scale_y - desired_scale *= species.icon_scale + desired_scale_x *= species.icon_scale_x + desired_scale_y *= species.icon_scale_y for(var/datum/modifier/M in modifiers) - if(!isnull(M.icon_scale_percent)) - desired_scale *= M.icon_scale_percent + if(!isnull(M.icon_scale_x_percent)) + desired_scale_x *= M.icon_scale_x_percent + if(!isnull(M.icon_scale_y_percent)) + desired_scale_y *= M.icon_scale_y_percent */ - var/desired_scale = size_multiplier + var/desired_scale_x = size_multiplier + var/desired_scale_y = size_multiplier //VOREStation Edit End // Regular stuff again. @@ -145,12 +150,12 @@ var/global/list/damage_icon_parts = list() //see UpdateDamageIcon() if(lying && !species.prone_icon) //Only rotate them if we're not drawing a specific icon for being prone. M.Turn(90) - M.Scale(desired_scale) + M.Scale(desired_scale_x, desired_scale_y) M.Translate(1,-6) layer = MOB_LAYER -0.01 // Fix for a byond bug where turf entry order no longer matters else - M.Scale(desired_scale) - M.Translate(0, 16*(desired_scale-1)) + M.Scale(desired_scale_x, desired_scale_y) + M.Translate(0, 16*(desired_scale_y-1)) layer = MOB_LAYER // Fix for a byond bug where turf entry order no longer matters animate(src, transform = M, time = anim_time) diff --git a/code/modules/mob/living/living.dm b/code/modules/mob/living/living.dm index 4020f13d14..d5295289fa 100644 --- a/code/modules/mob/living/living.dm +++ b/code/modules/mob/living/living.dm @@ -1174,19 +1174,20 @@ default behaviour is: /mob/living/update_transform() // First, get the correct size. - var/desired_scale = size_multiplier //VOREStation edit + var/desired_scale_x = size_multiplier //VOREStation edit + var/desired_scale_y = size_multiplier //VOREStation edit for(var/datum/modifier/M in modifiers) - if(!isnull(M.icon_scale_percent)) - desired_scale *= M.icon_scale_percent + if(!isnull(M.icon_scale_x_percent)) + desired_scale_x *= M.icon_scale_x_percent + if(!isnull(M.icon_scale_y_percent)) + desired_scale_y *= M.icon_scale_y_percent // Now for the regular stuff. var/matrix/M = matrix() - M.Scale(desired_scale) - M.Translate(0, 16*(desired_scale-1)) - src.transform = M + M.Scale(desired_scale_x, desired_scale_y) + M.Translate(0, 16*(desired_scale_y-1)) //animate(src, transform = M, time = 10) //VOREStation edit - // This handles setting the client's color variable, which makes everything look a specific color. // This proc is here so it can be called without needing to check if the client exists, or if the client relogs. /mob/living/update_client_color() diff --git a/code/modules/mob/living/silicon/robot/subtypes/gravekeeper.dm b/code/modules/mob/living/silicon/robot/subtypes/gravekeeper.dm index d722027ad3..255eef5318 100644 --- a/code/modules/mob/living/silicon/robot/subtypes/gravekeeper.dm +++ b/code/modules/mob/living/silicon/robot/subtypes/gravekeeper.dm @@ -7,6 +7,7 @@ braintype = "Drone" idcard_type = /obj/item/weapon/card/id icon_selected = FALSE + can_be_antagged = FALSE /mob/living/silicon/robot/gravekeeper/init() aiCamera = new/obj/item/device/camera/siliconcam/robot_camera(src) @@ -23,4 +24,4 @@ laws = new /datum/ai_laws/gravekeeper() - playsound(loc, 'sound/mecha/nominalsyndi.ogg', 75, 0) \ No newline at end of file + playsound(loc, 'sound/mecha/nominalsyndi.ogg', 75, 0) diff --git a/code/modules/mob/living/simple_animal/slime/subtypes.dm b/code/modules/mob/living/simple_animal/slime/subtypes.dm new file mode 100644 index 0000000000..18b43dc33c --- /dev/null +++ b/code/modules/mob/living/simple_animal/slime/subtypes.dm @@ -0,0 +1,748 @@ +// Tier 1 + +/mob/living/simple_animal/slime/purple + desc = "This slime is rather toxic to handle, as it is poisonous." + color = "#CC23FF" + slime_color = "purple" + coretype = /obj/item/slime_extract/purple + reagent_injected = "toxin" + + description_info = "This slime spreads a toxin when it attacks. A biosuit or other thick armor can protect from the toxic attack." + + slime_mutation = list( + /mob/living/simple_animal/slime/dark_purple, + /mob/living/simple_animal/slime/dark_blue, + /mob/living/simple_animal/slime/green, + /mob/living/simple_animal/slime + ) + + +/mob/living/simple_animal/slime/orange + desc = "This slime is known to be flammable and can ignite enemies." + color = "#FFA723" + slime_color = "orange" + coretype = /obj/item/slime_extract/orange + + description_info = "Attacks from this slime can ignite you. A firesuit can protect from the burning attacks of this slime." + + slime_mutation = list( + /mob/living/simple_animal/slime/dark_purple, + /mob/living/simple_animal/slime/yellow, + /mob/living/simple_animal/slime/red, + /mob/living/simple_animal/slime + ) + +/mob/living/simple_animal/slime/orange/post_attack(mob/living/L, intent) + if(intent != I_HELP) + L.adjust_fire_stacks(1) + if(prob(25)) + L.IgniteMob() + ..() + +/mob/living/simple_animal/slime/blue + desc = "This slime produces 'cryotoxin' and uses it against their foes. Very deadly to other slimes." + color = "#19FFFF" + slime_color = "blue" + coretype = /obj/item/slime_extract/blue + reagent_injected = "cryotoxin" + + description_info = "Attacks from this slime can chill you. A biosuit or other thick armor can protect from the chilling attack." + + slime_mutation = list( + /mob/living/simple_animal/slime/dark_blue, + /mob/living/simple_animal/slime/silver, + /mob/living/simple_animal/slime/pink, + /mob/living/simple_animal/slime + ) + + +/mob/living/simple_animal/slime/metal + desc = "This slime is a lot more resilient than the others, due to having a metamorphic metallic and sloped surface." + color = "#5F5F5F" + slime_color = "metal" + shiny = 1 + coretype = /obj/item/slime_extract/metal + + description_info = "This slime is a lot more durable and tough to damage than the others." + + resistance = 10 // Sloped armor is strong. + maxHealth = 250 + maxHealth_adult = 350 + + slime_mutation = list( + /mob/living/simple_animal/slime/silver, + /mob/living/simple_animal/slime/yellow, + /mob/living/simple_animal/slime/gold, + /mob/living/simple_animal/slime + ) + +// Tier 2 + +/mob/living/simple_animal/slime/yellow + desc = "This slime is very conductive, and is known to use electricity as a means of defense moreso than usual for slimes." + color = "#FFF423" + slime_color = "yellow" + coretype = /obj/item/slime_extract/yellow + + ranged = 1 + shoot_range = 3 + firing_lines = 1 + projectiletype = /obj/item/projectile/beam/lightning/slime + projectilesound = 'sound/weapons/gauss_shoot.ogg' // Closest thing to a 'thunderstrike' sound we have. + glows = TRUE + + description_info = "This slime will fire lightning attacks at enemies if they are at range, and generate electricity \ + for their stun attack faster than usual. Insulative or reflective armor can protect from the lightning." + + slime_mutation = list( + /mob/living/simple_animal/slime/bluespace, + /mob/living/simple_animal/slime/bluespace, + /mob/living/simple_animal/slime/metal, + /mob/living/simple_animal/slime/orange + ) + +/mob/living/simple_animal/slime/yellow/handle_regular_status_updates() + if(stat == CONSCIOUS) + if(prob(25)) + power_charge = between(0, power_charge + 1, 10) + ..() + +/obj/item/projectile/beam/lightning/slime + power = 15 + +/mob/living/simple_animal/slime/yellow/ClosestDistance() // Needed or else they won't eat monkeys outside of melee range. + if(target_mob && ishuman(target_mob)) + var/mob/living/carbon/human/H = target_mob + if(istype(H.species, /datum/species/monkey)) + return 1 + return ..() + + +/mob/living/simple_animal/slime/dark_purple + desc = "This slime produces ever-coveted phoron. Risky to handle but very much worth it." + color = "#660088" + slime_color = "dark purple" + coretype = /obj/item/slime_extract/dark_purple + reagent_injected = "phoron" + + description_info = "This slime applies phoron to enemies it attacks. A biosuit or other thick armor can protect from the toxic attack. \ + If hit with a burning attack, it will erupt in flames." + + slime_mutation = list( + /mob/living/simple_animal/slime/purple, + /mob/living/simple_animal/slime/orange, + /mob/living/simple_animal/slime/ruby, + /mob/living/simple_animal/slime/ruby + ) + +/mob/living/simple_animal/slime/dark_purple/proc/ignite() + visible_message("\The [src] erupts in an inferno!") + for(var/turf/simulated/target_turf in view(2, src)) + target_turf.assume_gas("phoron", 30, 1500+T0C) + spawn(0) + target_turf.hotspot_expose(1500+T0C, 400) + qdel(src) + +/mob/living/simple_animal/slime/dark_purple/ex_act(severity) + log_and_message_admins("[src] ignited due to a chain reaction with an explosion.") + ignite() + +/mob/living/simple_animal/slime/dark_purple/fire_act(datum/gas_mixture/air, temperature, volume) + log_and_message_admins("[src] ignited due to exposure to fire.") + ignite() + +/mob/living/simple_animal/slime/dark_purple/bullet_act(var/obj/item/projectile/P, var/def_zone) + if(P.damage_type && P.damage_type == BURN && P.damage) // Most bullets won't trigger the explosion, as a mercy towards Security. + log_and_message_admins("[src] ignited due to bring hit by a burning projectile[P.firer ? " by [key_name(P.firer)]" : ""].") + ignite() + else + ..() + +/mob/living/simple_animal/slime/dark_purple/attackby(var/obj/item/weapon/W, var/mob/user) + if(istype(W) && W.force && W.damtype == BURN) + log_and_message_admins("[src] ignited due to being hit with a burning weapon ([W]) by [key_name(user)].") + ignite() + else + ..() + + + + +/mob/living/simple_animal/slime/dark_blue + desc = "This slime makes other entities near it feel much colder, and is more resilient to the cold. It tends to kill other slimes rather quickly." + color = "#2398FF" + glows = TRUE + slime_color = "dark blue" + coretype = /obj/item/slime_extract/dark_blue + + description_info = "This slime is immune to the cold, however water will still kill it. A winter coat or other cold-resistant clothing can protect from the chilling aura." + + slime_mutation = list( + /mob/living/simple_animal/slime/purple, + /mob/living/simple_animal/slime/blue, + /mob/living/simple_animal/slime/cerulean, + /mob/living/simple_animal/slime/cerulean + ) + + minbodytemp = 0 + cold_damage_per_tick = 0 + +/mob/living/simple_animal/slime/dark_blue/Life() + if(stat != DEAD) + cold_aura() + ..() + +/mob/living/simple_animal/slime/dark_blue/proc/cold_aura() + for(var/mob/living/L in view(2, src)) + var/protection = L.get_cold_protection() + + if(protection < 1) + var/cold_factor = abs(protection - 1) + var/delta = -20 + delta *= cold_factor + L.bodytemperature = max(50, L.bodytemperature + delta) + var/turf/T = get_turf(src) + var/datum/gas_mixture/env = T.return_air() + if(env) + env.add_thermal_energy(-10 * 1000) + +/mob/living/simple_animal/slime/dark_blue/get_cold_protection() + return 1 // This slime is immune to cold. + +// Surface variant +/mob/living/simple_animal/slime/dark_blue/feral + name = "feral slime" + desc = "The result of slimes escaping containment from some xenobiology lab. The slime makes other entities near it feel much colder, \ + and it is more resilient to the cold. These qualities have made this color of slime able to thrive on a harsh, cold world and is able to rival \ + the ferocity of other apex predators in this region of Sif. As such, it is a very invasive species." + description_info = "This slime makes other entities near it feel much colder, and is more resilient to the cold. It also has learned advanced combat tactics from \ + having to endure the harsh world outside its lab. Note that processing this large slime will give six cores." + icon_scale_x = 2 + icon_scale_y = 2 + optimal_combat = TRUE // Gotta be sharp to survive out there. + rabid = TRUE + rainbow_core_candidate = FALSE + cores = 6 + maxHealth = 150 + maxHealth_adult = 250 + type_on_death = /mob/living/simple_animal/slime/dark_blue // Otherwise infinite slimes might occur. + pixel_y = -10 // Since the base sprite isn't centered properly, the pixel auto-adjustment needs some help. + +/mob/living/simple_animal/slime/dark_blue/feral/New() + ..() + make_adult() + +/mob/living/simple_animal/slime/silver + desc = "This slime is shiny, and can deflect lasers or other energy weapons directed at it." + color = "#AAAAAA" + slime_color = "silver" + coretype = /obj/item/slime_extract/silver + shiny = TRUE + + description_info = "Tasers, including the slime version, are ineffective against this slime. The slimebation still works." + + slime_mutation = list( + /mob/living/simple_animal/slime/metal, + /mob/living/simple_animal/slime/blue, + /mob/living/simple_animal/slime/amber, + /mob/living/simple_animal/slime/amber + ) + +/mob/living/simple_animal/slime/silver/bullet_act(var/obj/item/projectile/P, var/def_zone) + if(istype(P,/obj/item/projectile/beam) || istype(P, /obj/item/projectile/energy)) + visible_message("\The [src] reflects \the [P]!") + + // Find a turf near or on the original location to bounce to + var/new_x = P.starting.x + pick(0, 0, 0, -1, 1, -2, 2) + var/new_y = P.starting.y + pick(0, 0, 0, -1, 1, -2, 2) + var/turf/curloc = get_turf(src) + + // redirect the projectile + P.redirect(new_x, new_y, curloc, src) + return PROJECTILE_CONTINUE // complete projectile permutation + else + ..() + + +// Tier 3 + +/mob/living/simple_animal/slime/bluespace + desc = "Trapping this slime in a cell is generally futile, as it can teleport at will." + color = null + slime_color = "bluespace" + icon_state_override = "bluespace" + coretype = /obj/item/slime_extract/bluespace + + description_info = "This slime will teleport to attack something if it is within a range of seven tiles. The teleport has a cooldown of five seconds." + + slime_mutation = list( + /mob/living/simple_animal/slime/bluespace, + /mob/living/simple_animal/slime/bluespace, + /mob/living/simple_animal/slime/yellow, + /mob/living/simple_animal/slime/yellow + ) + + spattack_prob = 100 + spattack_min_range = 3 + spattack_max_range = 7 + var/last_tele = null // Uses world.time + var/tele_cooldown = 5 SECONDS + +/mob/living/simple_animal/slime/bluespace/ClosestDistance() // Needed or the SA AI won't ever try to teleport. + if(world.time > last_tele + tele_cooldown) + return spattack_max_range - 1 + return ..() + +/mob/living/simple_animal/slime/bluespace/SpecialAtkTarget() + // Teleport attack. + if(!target_mob) + to_chat(src, "There's nothing to teleport to.") + return FALSE + + if(world.time < last_tele + tele_cooldown) + to_chat(src, "You can't teleport right now, wait a few seconds.") + return FALSE + + var/list/nearby_things = range(1, target_mob) + var/list/valid_turfs = list() + + // All this work to just go to a non-dense tile. + for(var/turf/potential_turf in nearby_things) + var/valid_turf = TRUE + if(potential_turf.density) + continue + for(var/atom/movable/AM in potential_turf) + if(AM.density) + valid_turf = FALSE + if(valid_turf) + valid_turfs.Add(potential_turf) + + + + var/turf/T = get_turf(src) + var/turf/target_turf = pick(valid_turfs) + + if(!target_turf) + to_chat(src, "There wasn't an unoccupied spot to teleport to.") + return FALSE + + var/datum/effect/effect/system/spark_spread/s1 = new /datum/effect/effect/system/spark_spread + s1.set_up(5, 1, T) + var/datum/effect/effect/system/spark_spread/s2 = new /datum/effect/effect/system/spark_spread + s2.set_up(5, 1, target_turf) + + + T.visible_message("\The [src] vanishes!") + s1.start() + + forceMove(target_turf) + playsound(target_turf, 'sound/effects/phasein.ogg', 50, 1) + to_chat(src, "You teleport to \the [target_turf].") + + target_turf.visible_message("\The [src] appears!") + s2.start() + + last_tele = world.time + + if(Adjacent(target_mob)) + PunchTarget() + return TRUE + +/mob/living/simple_animal/slime/ruby + desc = "This slime has great physical strength." + color = "#FF3333" + slime_color = "ruby" + shiny = TRUE + glows = TRUE + coretype = /obj/item/slime_extract/ruby + + description_info = "This slime is unnaturally stronger, allowing it to hit much harder, take less damage, and be stunned for less time. \ + Their glomp attacks also send the victim flying." + + slime_mutation = list( + /mob/living/simple_animal/slime/dark_purple, + /mob/living/simple_animal/slime/dark_purple, + /mob/living/simple_animal/slime/ruby, + /mob/living/simple_animal/slime/ruby + ) + +/mob/living/simple_animal/slime/ruby/New() + ..() + add_modifier(/datum/modifier/slime_strength, null, src) // Slime is always swole. + +/mob/living/simple_animal/slime/ruby/DoPunch(var/mob/living/L) + ..() // Do regular attacks. + + if(istype(L)) + if(a_intent == I_HURT) + visible_message("\The [src] sends \the [L] flying with the impact!") + playsound(src, "punch", 50, 1) + L.Weaken(1) + var/throwdir = get_dir(src, L) + L.throw_at(get_edge_target_turf(L, throwdir), 3, 1, src) + + +/mob/living/simple_animal/slime/amber + desc = "This slime seems to be an expert in the culinary arts, as they create their own food to share with others. \ + They would probably be very important to other slimes, if the other colors didn't try to kill them." + color = "#FFBB00" + slime_color = "amber" + shiny = TRUE + glows = TRUE + coretype = /obj/item/slime_extract/amber + + description_info = "This slime feeds nearby entities passively while it is alive. This can cause uncontrollable \ + slime growth and reproduction if not kept in check. The amber slime cannot feed itself, but can be fed by other amber slimes." + + slime_mutation = list( + /mob/living/simple_animal/slime/silver, + /mob/living/simple_animal/slime/silver, + /mob/living/simple_animal/slime/amber, + /mob/living/simple_animal/slime/amber + ) + +/mob/living/simple_animal/slime/amber/Life() + if(stat != DEAD) + feed_aura() + ..() + +/mob/living/simple_animal/slime/amber/proc/feed_aura() + for(var/mob/living/L in view(2, src)) + if(L == src) // Don't feed themselves, or it is impossible to stop infinite slimes without killing all of the ambers. + continue + if(isslime(L)) + var/mob/living/simple_animal/slime/S = L + S.adjust_nutrition(rand(15, 25)) + if(ishuman(L)) + var/mob/living/carbon/human/H = L + if(H.isSynthetic()) + continue + H.nutrition = between(0, H.nutrition + rand(15, 25), 600) + + + +/mob/living/simple_animal/slime/cerulean + desc = "This slime is generally superior in a wide range of attributes, compared to the common slime. The jack of all trades, but master of none." + color = "#4F7EAA" + slime_color = "cerulean" + coretype = /obj/item/slime_extract/cerulean + + // Less than the specialized slimes, but higher than the rest. + maxHealth = 200 + maxHealth_adult = 250 + + melee_damage_lower = 10 + melee_damage_upper = 30 + + move_to_delay = 3 + + + + slime_mutation = list( + /mob/living/simple_animal/slime/dark_blue, + /mob/living/simple_animal/slime/dark_blue, + /mob/living/simple_animal/slime/cerulean, + /mob/living/simple_animal/slime/cerulean + ) + +// Tier 4 + +/mob/living/simple_animal/slime/red + desc = "This slime is full of energy, and very aggressive. 'The red ones go faster.' seems to apply here." + color = "#FF3333" + slime_color = "red" + coretype = /obj/item/slime_extract/red + move_to_delay = 3 // The red ones go faster. + + description_info = "This slime is faster than the others. Attempting to discipline this slime will always cause it to go berserk." + + slime_mutation = list( + /mob/living/simple_animal/slime/red, + /mob/living/simple_animal/slime/oil, + /mob/living/simple_animal/slime/oil, + /mob/living/simple_animal/slime/orange + ) + + +/mob/living/simple_animal/slime/red/adjust_discipline(amount) + if(amount > 0) + if(!rabid) + enrage() // How dare you try to control the red slime. + say("Grrr...!") + +/mob/living/simple_animal/slime/red/enrage() + ..() + add_modifier(/datum/modifier/berserk, 30 SECONDS) + + +/mob/living/simple_animal/slime/green + desc = "This slime is radioactive." + color = "#14FF20" + slime_color = "green" + coretype = /obj/item/slime_extract/green + glows = TRUE + reagent_injected = "radium" + var/rads = 25 + + description_info = "This slime will irradiate anything nearby passively, and will inject radium on attack. \ + A radsuit or other thick and radiation-hardened armor can protect from this. It will only radiate while alive." + + slime_mutation = list( + /mob/living/simple_animal/slime/purple, + /mob/living/simple_animal/slime/green, + /mob/living/simple_animal/slime/emerald, + /mob/living/simple_animal/slime/emerald + ) + +/mob/living/simple_animal/slime/green/Life() + if(stat != DEAD) + irradiate() + ..() + +/mob/living/simple_animal/slime/green/proc/irradiate() + radiation_repository.radiate(src, rads) + + +/mob/living/simple_animal/slime/pink + desc = "This slime has regenerative properties." + color = "#FF0080" + slime_color = "pink" + coretype = /obj/item/slime_extract/pink + glows = TRUE + + description_info = "This slime will passively heal nearby entities within two tiles, including itself. It will only do this while alive." + + slime_mutation = list( + /mob/living/simple_animal/slime/blue, + /mob/living/simple_animal/slime/light_pink, + /mob/living/simple_animal/slime/light_pink, + /mob/living/simple_animal/slime/pink + ) + +/mob/living/simple_animal/slime/pink/Life() + if(stat != DEAD) + heal_aura() + ..() + +/mob/living/simple_animal/slime/pink/proc/heal_aura() + for(var/mob/living/L in view(src, 2)) + if(L.stat == DEAD || L == target_mob) + continue + L.add_modifier(/datum/modifier/slime_heal, 5 SECONDS, src) + +/datum/modifier/slime_heal + name = "slime mending" + desc = "You feel somewhat gooy." + mob_overlay_state = "pink_sparkles" + + on_created_text = "Twinkling spores of goo surround you. It makes you feel healthier." + on_expired_text = "The spores of goo have faded, although you feel much healthier than before." + stacks = MODIFIER_STACK_EXTEND + +/datum/modifier/slime_heal/tick() + if(holder.stat == DEAD) // Required or else simple animals become immortal. + expire() + + if(ishuman(holder)) // Robolimbs need this code sadly. + var/mob/living/carbon/human/H = holder + for(var/obj/item/organ/external/E in H.organs) + var/obj/item/organ/external/O = E + O.heal_damage(2, 2, 0, 1) + else + holder.adjustBruteLoss(-2) + holder.adjustFireLoss(-2) + + holder.adjustToxLoss(-2) + holder.adjustOxyLoss(-2) + holder.adjustCloneLoss(-1) + + + +/mob/living/simple_animal/slime/gold + desc = "This slime absorbs energy, and cannot be stunned by normal means." + color = "#EEAA00" + shiny = TRUE + slime_color = "gold" + coretype = /obj/item/slime_extract/gold + description_info = "This slime is immune to the slimebaton and taser, and will actually charge the slime, however it will still discipline the slime." + + slime_mutation = list( + /mob/living/simple_animal/slime/metal, + /mob/living/simple_animal/slime/gold, + /mob/living/simple_animal/slime/sapphire, + /mob/living/simple_animal/slime/sapphire + ) + +/mob/living/simple_animal/slime/gold/Weaken(amount) + power_charge = between(0, power_charge + amount, 10) + return + +/mob/living/simple_animal/slime/gold/Stun(amount) + power_charge = between(0, power_charge + amount, 10) + return + +/mob/living/simple_animal/slime/gold/get_description_interaction() // So it doesn't say to use a baton on them. + return list() + + +// Tier 5 + +/mob/living/simple_animal/slime/oil + desc = "This slime is explosive and volatile. Smoking near it is probably a bad idea." + color = "#333333" + slime_color = "oil" + shiny = TRUE + coretype = /obj/item/slime_extract/oil + + description_info = "If this slime suffers damage from a fire or heat based source, or if it is caught inside \ + an explosion, it will explode. Rabid oil slimes will charge at enemies, then suicide-bomb themselves. \ + Bomb suits can protect from the explosion." + + slime_mutation = list( + /mob/living/simple_animal/slime/oil, + /mob/living/simple_animal/slime/oil, + /mob/living/simple_animal/slime/red, + /mob/living/simple_animal/slime/red + ) + +/mob/living/simple_animal/slime/oil/proc/explode() + if(stat != DEAD) + // explosion(src.loc, 1, 2, 4) + explosion(src.loc, 0, 2, 4) // A bit weaker since the suicide charger tended to gib the poor sod being targeted. + if(src) // Delete ourselves if the explosion didn't do it. + qdel(src) + +/mob/living/simple_animal/slime/oil/post_attack(var/mob/living/L, var/intent = I_HURT) + if(!rabid) + return ..() + if(intent == I_HURT || intent == I_GRAB) + say(pick("Sacrifice...!", "Sssss...", "Boom...!")) + sleep(2 SECOND) + log_and_message_admins("[src] has suicide-bombed themselves while trying to kill \the [L].") + explode() + +/mob/living/simple_animal/slime/oil/ex_act(severity) + log_and_message_admins("[src] exploded due to a chain reaction with another explosion.") + explode() + +/mob/living/simple_animal/slime/oil/fire_act(datum/gas_mixture/air, temperature, volume) + log_and_message_admins("[src] exploded due to exposure to fire.") + explode() + +/mob/living/simple_animal/slime/oil/bullet_act(var/obj/item/projectile/P, var/def_zone) + if(P.damage_type && P.damage_type == BURN && P.damage) // Most bullets won't trigger the explosion, as a mercy towards Security. + log_and_message_admins("[src] exploded due to bring hit by a burning projectile[P.firer ? " by [key_name(P.firer)]" : ""].") + explode() + else + ..() + +/mob/living/simple_animal/slime/oil/attackby(var/obj/item/weapon/W, var/mob/user) + if(istype(W) && W.force && W.damtype == BURN) + log_and_message_admins("[src] exploded due to being hit with a burning weapon ([W]) by [key_name(user)].") + explode() + else + ..() + + +/mob/living/simple_animal/slime/sapphire + desc = "This slime seems a bit brighter than the rest, both figuratively and literally." + color = "#2398FF" + slime_color = "sapphire" + shiny = TRUE + glows = TRUE + coretype = /obj/item/slime_extract/sapphire + + optimal_combat = TRUE // Lift combat AI restrictions to look smarter. + run_at_them = FALSE // Use fancy A* pathing. + astar_adjacent_proc = /turf/proc/TurfsWithAccess // Normal slimes don't care about cardinals (because BYOND) so smart slimes shouldn't as well. + move_to_delay = 3 // A* chasing is slightly slower in terms of movement speed than regular pathing so reducing this hopefully makes up for that. + + description_info = "This slime uses more robust tactics when fighting and won't hold back, so it is dangerous to be alone \ + with one if hostile, and especially dangerous if they outnumber you." + + slime_mutation = list( + /mob/living/simple_animal/slime/sapphire, + /mob/living/simple_animal/slime/sapphire, + /mob/living/simple_animal/slime/gold, + /mob/living/simple_animal/slime/gold + ) + +/mob/living/simple_animal/slime/emerald + desc = "This slime is faster than usual, even more so than the red slimes." + color = "#22FF22" + shiny = TRUE + glows = TRUE + slime_color = "emerald" + coretype = /obj/item/slime_extract/emerald + + description_info = "This slime will make everything around it, and itself, faster for a few seconds, if close by." + move_to_delay = 2 + + slime_mutation = list( + /mob/living/simple_animal/slime/green, + /mob/living/simple_animal/slime/green, + /mob/living/simple_animal/slime/emerald, + /mob/living/simple_animal/slime/emerald + ) + +/mob/living/simple_animal/slime/emerald/Life() + if(stat != DEAD) + zoom_aura() + ..() + +/mob/living/simple_animal/slime/emerald/proc/zoom_aura() + for(var/mob/living/L in view(src, 2)) + if(L.stat == DEAD || L == target_mob) + continue + L.add_modifier(/datum/modifier/technomancer/haste, 5 SECONDS, src) + +/mob/living/simple_animal/slime/light_pink + desc = "This slime seems a lot more peaceful than the others." + color = "#FF8888" + slime_color = "light pink" + coretype = /obj/item/slime_extract/light_pink + + description_info = "This slime is effectively always disciplined initially." + obedience = 5 + discipline = 5 + + slime_mutation = list( + /mob/living/simple_animal/slime/pink, + /mob/living/simple_animal/slime/pink, + /mob/living/simple_animal/slime/light_pink, + /mob/living/simple_animal/slime/light_pink + ) + +// Special +/mob/living/simple_animal/slime/rainbow + desc = "This slime changes colors constantly." + color = null // Only slime subtype that uses a different icon_state. + slime_color = "rainbow" + coretype = /obj/item/slime_extract/rainbow + icon_state_override = "rainbow" + unity = TRUE + + description_info = "This slime is considered to be the same color as all other slime colors at the same time for the purposes of \ + other slimes being friendly to them, and therefore will never be harmed by another slime. \ + Attacking this slime will provoke the wrath of all slimes within range." + + slime_mutation = list( + /mob/living/simple_animal/slime/rainbow, + /mob/living/simple_animal/slime/rainbow, + /mob/living/simple_animal/slime/rainbow, + /mob/living/simple_animal/slime/rainbow + ) + +/mob/living/simple_animal/slime/rainbow/New() + unify() + ..() + +// The RD's pet slime. +/mob/living/simple_animal/slime/rainbow/kendrick + name = "Kendrick" + desc = "The Research Director's pet slime. It shifts colors constantly." + rainbow_core_candidate = FALSE + +/mob/living/simple_animal/slime/rainbow/kendrick/New() + pacify() + ..() \ No newline at end of file diff --git a/code/modules/mob/living/simple_mob/subtypes/animal/borer/borer.dm b/code/modules/mob/living/simple_mob/subtypes/animal/borer/borer.dm index b5b4489f57..6ea44df66d 100644 --- a/code/modules/mob/living/simple_mob/subtypes/animal/borer/borer.dm +++ b/code/modules/mob/living/simple_mob/subtypes/animal/borer/borer.dm @@ -1,237 +1,261 @@ -// Borers are probably still going to be buggy as fuck, this is just bringing their mob defines up to the new system. -// IMO they're a relic of several ages we're long past, their code and their design showing this plainly, but removing them would -// make certain people Unhappy so here we are. They need a complete redesign but thats beyond the scope of the rewrite. - -/mob/living/simple_mob/animal/borer - name = "cortical borer" - desc = "A small, quivering sluglike creature." - icon_state = "brainslug" - item_state = "brainslug" - icon_living = "brainslug" - icon_dead = "brainslug_dead" - - response_help = "pokes" - response_disarm = "prods" - response_harm = "stomps on" - attacktext = list("nipped") - friendly = list("prods") - - status_flags = CANPUSH - pass_flags = PASSTABLE - movement_cooldown = 5 - - universal_understand = TRUE - can_be_antagged = TRUE - - holder_type = /obj/item/weapon/holder/borer - ai_holder_type = null // This is player-controlled, always. - - var/chemicals = 10 // A resource used for reproduction and powers. - var/mob/living/carbon/human/host = null // The humanoid host for the brain worm. - var/true_name = null // String used when speaking among other worms. - var/mob/living/captive_brain/host_brain // Used for swapping control of the body back and forth. - var/controlling = FALSE // Used in human death ceck. - var/docile = FALSE // Sugar can stop borers from acting. - var/has_reproduced = FALSE - var/roundstart = FALSE // If true, spawning won't try to pull a ghost. - var/used_dominate // world.time when the dominate power was last used. - - -/mob/living/simple_mob/animal/borer/roundstart - roundstart = TRUE - -/mob/living/simple_mob/animal/borer/Login() - ..() - if(mind) - borers.add_antagonist(mind) - -/mob/living/simple_mob/animal/borer/Initialize() - add_language("Cortical Link") - - verbs += /mob/living/proc/ventcrawl - verbs += /mob/living/proc/hide - - true_name = "[pick("Primary","Secondary","Tertiary","Quaternary")] [rand(1000,9999)]" - - if(!roundstart) - request_player() - - return ..() - -/mob/living/simple_mob/animal/borer/handle_special() - if(host && !stat && !host.stat) - // Handle docility. - if(host.reagents.has_reagent("sugar") && !docile) - var/message = "You feel the soporific flow of sugar in your host's blood, lulling you into docility." - var/target = controlling ? host : src - to_chat(target, span("warning", message)) - docile = TRUE - - else if(docile) - var/message = "You shake off your lethargy as the sugar leaves your host's blood." - var/target = controlling ? host : src - to_chat(target, span("notice", message)) - docile = FALSE - - // Chem regen. - if(chemicals < 250) - chemicals++ - - // Control stuff. - if(controlling) - if(docile) - to_chat(host, span("warning", "You are feeling far too docile to continue controlling your host...")) - host.release_control() - return - - if(prob(5)) - host.adjustBrainLoss(0.1) - - if(prob(host.brainloss/20)) - host.say("*[pick(list("blink","blink_r","choke","aflap","drool","twitch","twitch_v","gasp"))]") - -/mob/living/simple_mob/animal/borer/Stat() - ..() - if(client.statpanel == "Status") - statpanel("Status") - if(emergency_shuttle) - var/eta_status = emergency_shuttle.get_status_panel_eta() - if(eta_status) - stat(null, eta_status) - stat("Chemicals", chemicals) - -/mob/living/simple_mob/animal/borer/proc/detatch() - if(!host || !controlling) - return - - if(istype(host, /mob/living/carbon/human)) - var/mob/living/carbon/human/H = host - var/obj/item/organ/external/head = H.get_organ(BP_HEAD) - if(head) - head.implants -= src - - controlling = FALSE - - host.remove_language("Cortical Link") - host.verbs -= /mob/living/carbon/proc/release_control - host.verbs -= /mob/living/carbon/proc/punish_host - host.verbs -= /mob/living/carbon/proc/spawn_larvae - - if(host_brain) - // these are here so bans and multikey warnings are not triggered on the wrong people when ckey is changed. - // computer_id and IP are not updated magically on their own in offline mobs -walter0o - - // This shit need to die in a phoron fire. - - // host -> self - var/h2s_id = host.computer_id - var/h2s_ip= host.lastKnownIP - host.computer_id = null - host.lastKnownIP = null - - src.ckey = host.ckey - - if(!src.computer_id) - src.computer_id = h2s_id - - if(!host_brain.lastKnownIP) - src.lastKnownIP = h2s_ip - - // brain -> host - var/b2h_id = host_brain.computer_id - var/b2h_ip= host_brain.lastKnownIP - host_brain.computer_id = null - host_brain.lastKnownIP = null - - host.ckey = host_brain.ckey - - if(!host.computer_id) - host.computer_id = b2h_id - - if(!host.lastKnownIP) - host.lastKnownIP = b2h_ip - - qdel(host_brain) - - -/mob/living/simple_mob/animal/borer/proc/leave_host() - if(!host) - return - - if(host.mind) - borers.remove_antagonist(host.mind) - - forceMove(get_turf(host)) - - reset_view(null) - machine = null - - host.reset_view(null) - host.machine = null - host = null - -/mob/living/simple_mob/animal/borer/proc/request_player() - var/datum/ghost_query/Q = new /datum/ghost_query/borer() - var/list/winner = Q.query() // This will sleep the proc for awhile. - if(winner.len) - var/mob/observer/dead/D = winner[1] - transfer_personality(D) - -/mob/living/simple_mob/animal/borer/proc/transfer_personality(mob/candidate) - if(!candidate || !candidate.mind) - return - - src.mind = candidate.mind - candidate.mind.current = src - ckey = candidate.ckey - - if(mind) - mind.assigned_role = "Cortical Borer" - mind.special_role = "Cortical Borer" - - to_chat(src, span("notice", "You are a cortical borer! You are a brain slug that worms its way \ - into the head of its victim. Use stealth, persuasion and your powers of mind control to keep you, \ - your host and your eventual spawn safe and warm.")) - to_chat(src, "You can speak to your victim with say, to other borers with say :x, and use your Abilities tab to access powers.") - -/mob/living/simple_mob/animal/borer/cannot_use_vents() - return - -// This is awful but its literally say code. -/mob/living/simple_mob/animal/borer/say(message) - message = sanitize(message) - message = capitalize(message) - - if(!message) - return - - if(stat >= DEAD) - return say_dead(message) - else if(stat) - return - - if(client && client.prefs.muted & MUTE_IC) - to_chat(src, span("danger", "You cannot speak in IC (muted).")) - return - - if(copytext(message, 1, 2) == "*") - return emote(copytext(message, 2)) - - var/datum/language/L = parse_language(message) - if(L && L.flags & HIVEMIND) - L.broadcast(src,trim(copytext(message,3)), src.true_name) - return - - if(!host) - //TODO: have this pick a random mob within 3 tiles to speak for the borer. - to_chat(src, span("warning", "You have no host to speak to.")) - return //No host, no audible speech. - - to_chat(src, "You drop words into [host]'s mind: \"[message]\"") - to_chat(host, "Your own thoughts speak: \"[message]\"") - - for(var/mob/M in player_list) - if(istype(M, /mob/new_player)) - continue - else if(M.stat == DEAD && M.is_preference_enabled(/datum/client_preference/ghost_ears)) - to_chat(M, "[src.true_name] whispers to [host], \"[message]\"") +// Borers are probably still going to be buggy as fuck, this is just bringing their mob defines up to the new system. +// IMO they're a relic of several ages we're long past, their code and their design showing this plainly, but removing them would +// make certain people Unhappy so here we are. They need a complete redesign but thats beyond the scope of the rewrite. + +/mob/living/simple_mob/animal/borer + name = "cortical borer" + desc = "A small, quivering sluglike creature." + icon_state = "brainslug" + item_state = "brainslug" + icon_living = "brainslug" + icon_dead = "brainslug_dead" + + response_help = "pokes" + response_disarm = "prods" + response_harm = "stomps on" + attacktext = list("nipped") + friendly = list("prods") + + status_flags = CANPUSH + pass_flags = PASSTABLE + movement_cooldown = 5 + + universal_understand = TRUE + can_be_antagged = TRUE + + holder_type = /obj/item/weapon/holder/borer + ai_holder_type = null // This is player-controlled, always. + + var/chemicals = 10 // A resource used for reproduction and powers. + var/max_chemicals = 250 // Max of said resource. + var/mob/living/carbon/human/host = null // The humanoid host for the brain worm. + var/true_name = null // String used when speaking among other worms. + var/mob/living/captive_brain/host_brain // Used for swapping control of the body back and forth. + var/controlling = FALSE // Used in human death ceck. + var/docile = FALSE // Sugar can stop borers from acting. + var/has_reproduced = FALSE + var/roundstart = FALSE // If true, spawning won't try to pull a ghost. + var/used_dominate // world.time when the dominate power was last used. + + +/mob/living/simple_mob/animal/borer/roundstart + roundstart = TRUE + +/mob/living/simple_mob/animal/borer/Login() + ..() + if(mind) + borers.add_antagonist(mind) + +/mob/living/simple_mob/animal/borer/Initialize() + add_language("Cortical Link") + + verbs += /mob/living/proc/ventcrawl + verbs += /mob/living/proc/hide + + true_name = "[pick("Primary","Secondary","Tertiary","Quaternary")] [rand(1000,9999)]" + + if(!roundstart) + request_player() + + return ..() + +/mob/living/simple_mob/animal/borer/handle_special() + if(host && !stat && !host.stat) + // Handle docility. + if(host.reagents.has_reagent("sugar") && !docile) + var/message = "You feel the soporific flow of sugar in your host's blood, lulling you into docility." + var/target = controlling ? host : src + to_chat(target, span("warning", message)) + docile = TRUE + + else if(docile) + var/message = "You shake off your lethargy as the sugar leaves your host's blood." + var/target = controlling ? host : src + to_chat(target, span("notice", message)) + docile = FALSE + + // Chem regen. + if(chemicals < max_chemicals) + chemicals++ + + // Control stuff. + if(controlling) + if(docile) + to_chat(host, span("warning", "You are feeling far too docile to continue controlling your host...")) + host.release_control() + return + + if(prob(5)) + host.adjustBrainLoss(0.1) + + if(prob(host.brainloss/20)) + host.say("*[pick(list("blink","blink_r","choke","aflap","drool","twitch","twitch_v","gasp"))]") + +/mob/living/simple_mob/animal/borer/Stat() + ..() + if(client.statpanel == "Status") + statpanel("Status") + if(emergency_shuttle) + var/eta_status = emergency_shuttle.get_status_panel_eta() + if(eta_status) + stat(null, eta_status) + stat("Chemicals", chemicals) + +/mob/living/simple_mob/animal/borer/proc/detatch() + if(!host || !controlling) + return + + if(istype(host, /mob/living/carbon/human)) + var/mob/living/carbon/human/H = host + var/obj/item/organ/external/head = H.get_organ(BP_HEAD) + if(head) + head.implants -= src + + controlling = FALSE + + host.remove_language("Cortical Link") + host.verbs -= /mob/living/carbon/proc/release_control + host.verbs -= /mob/living/carbon/proc/punish_host + host.verbs -= /mob/living/carbon/proc/spawn_larvae + + if(host_brain) + // these are here so bans and multikey warnings are not triggered on the wrong people when ckey is changed. + // computer_id and IP are not updated magically on their own in offline mobs -walter0o + + // This shit need to die in a phoron fire. + + // host -> self + var/h2s_id = host.computer_id + var/h2s_ip= host.lastKnownIP + host.computer_id = null + host.lastKnownIP = null + + src.ckey = host.ckey + + if(!src.computer_id) + src.computer_id = h2s_id + + if(!host_brain.lastKnownIP) + src.lastKnownIP = h2s_ip + + // brain -> host + var/b2h_id = host_brain.computer_id + var/b2h_ip= host_brain.lastKnownIP + host_brain.computer_id = null + host_brain.lastKnownIP = null + + host.ckey = host_brain.ckey + + if(!host.computer_id) + host.computer_id = b2h_id + + if(!host.lastKnownIP) + host.lastKnownIP = b2h_ip + + qdel(host_brain) + + +/mob/living/simple_mob/animal/borer/proc/leave_host() + if(!host) + return + + if(host.mind) + borers.remove_antagonist(host.mind) + + forceMove(get_turf(host)) + + reset_view(null) + machine = null + + if(istype(host, /mob/living/carbon/human)) + var/mob/living/carbon/human/H = host + var/obj/item/organ/external/head = H.get_organ(BP_HEAD) + if(head) + head.implants -= src + + host.reset_view(null) + host.machine = null + host = null + +/mob/living/simple_mob/animal/borer/proc/request_player() + var/datum/ghost_query/Q = new /datum/ghost_query/borer() + var/list/winner = Q.query() // This will sleep the proc for awhile. + if(winner.len) + var/mob/observer/dead/D = winner[1] + transfer_personality(D) + +/mob/living/simple_mob/animal/borer/proc/transfer_personality(mob/candidate) + if(!candidate || !candidate.mind) + return + + src.mind = candidate.mind + candidate.mind.current = src + ckey = candidate.ckey + + if(mind) + mind.assigned_role = "Cortical Borer" + mind.special_role = "Cortical Borer" + + to_chat(src, span("notice", "You are a cortical borer! You are a brain slug that worms its way \ + into the head of its victim. Use stealth, persuasion and your powers of mind control to keep you, \ + your host and your eventual spawn safe and warm.")) + to_chat(src, "You can speak to your victim with say, to other borers with say :x, and use your Abilities tab to access powers.") + +/mob/living/simple_mob/animal/borer/cannot_use_vents() + return + +// This is awful but its literally say code. +/mob/living/simple_mob/animal/borer/say(message) + message = sanitize(message) + message = capitalize(message) + + if(!message) + return + + if(stat >= DEAD) + return say_dead(message) + else if(stat) + return + + if(client && client.prefs.muted & MUTE_IC) + to_chat(src, span("danger", "You cannot speak in IC (muted).")) + return + + if(copytext(message, 1, 2) == "*") + return emote(copytext(message, 2)) + + var/datum/language/L = parse_language(message) + if(L && L.flags & HIVEMIND) + L.broadcast(src,trim(copytext(message,3)), src.true_name) + return + + if(!host) + if(chemicals >= 30) + to_chat(src, span("alien", "..You emit a psionic pulse with an encoded message..")) + var/list/nearby_mobs = list() + for(var/mob/living/LM in view(src, 1 + round(6 * (chemicals / max_chemicals)))) + if(LM == src) + continue + if(!LM.stat) + nearby_mobs += LM + var/mob/living/speaker + if(nearby_mobs.len) + speaker = input("Choose a target speaker.") as null|anything in nearby_mobs + if(speaker) + log_admin("[src.ckey]/([src]) tried to force [speaker] to say: [message]") + message_admins("[src.ckey]/([src]) tried to force [speaker] to say: [message]") + speaker.say("[message]") + return + to_chat(src, span("alien", "..But nothing heard it..")) + else + to_chat(src, span("warning", "You have no host to speak to.")) + return //No host, no audible speech. + + to_chat(src, "You drop words into [host]'s mind: \"[message]\"") + to_chat(host, "Your own thoughts speak: \"[message]\"") + + for(var/mob/M in player_list) + if(istype(M, /mob/new_player)) + continue + else if(M.stat == DEAD && M.is_preference_enabled(/datum/client_preference/ghost_ears)) + to_chat(M, "[src.true_name] whispers to [host], \"[message]\"") diff --git a/code/modules/mob/living/simple_mob/subtypes/animal/pets/bird.dm b/code/modules/mob/living/simple_mob/subtypes/animal/pets/bird.dm index 5e77a57a3c..4042dd30b4 100644 --- a/code/modules/mob/living/simple_mob/subtypes/animal/pets/bird.dm +++ b/code/modules/mob/living/simple_mob/subtypes/animal/pets/bird.dm @@ -57,7 +57,8 @@ icon_state = "commonblackbird" icon_dead = "commonblackbird-dead" tt_desc = "E Turdus merula" - icon_scale = 0.5 + icon_scale_x = 0.5 + icon_scale_y = 0.5 /mob/living/simple_mob/animal/passive/bird/azure_tit name = "azure tit" @@ -65,7 +66,8 @@ icon_state = "azuretit" icon_dead = "azuretit-dead" tt_desc = "E Cyanistes cyanus" - icon_scale = 0.5 + icon_scale_x = 0.5 + icon_scale_y = 0.5 /mob/living/simple_mob/animal/passive/bird/european_robin name = "european robin" @@ -73,7 +75,8 @@ icon_state = "europeanrobin" icon_dead = "europeanrobin-dead" tt_desc = "E Erithacus rubecula" - icon_scale = 0.5 + icon_scale_x = 0.5 + icon_scale_y = 0.5 /mob/living/simple_mob/animal/passive/bird/goldcrest name = "goldcrest" @@ -82,7 +85,8 @@ icon_state = "goldcrest" icon_dead = "goldcrest-dead" tt_desc = "E Regulus regulus" - icon_scale = 0.5 + icon_scale_x = 0.5 + icon_scale_y = 0.5 /mob/living/simple_mob/animal/passive/bird/ringneck_dove name = "ringneck dove" @@ -90,4 +94,5 @@ icon_state = "ringneckdove" icon_dead = "ringneckdove-dead" tt_desc = "E Streptopelia risoria" // This is actually disputed IRL but since we can't tell the future it'll stay the same for 500+ years. - icon_scale = 0.5 + icon_scale_x = 0.5 + icon_scale_y = 0.5 diff --git a/code/modules/mob/living/simple_mob/subtypes/animal/sif/hooligan_crab.dm b/code/modules/mob/living/simple_mob/subtypes/animal/sif/hooligan_crab.dm index ca8288e421..32eccb00af 100644 --- a/code/modules/mob/living/simple_mob/subtypes/animal/sif/hooligan_crab.dm +++ b/code/modules/mob/living/simple_mob/subtypes/animal/sif/hooligan_crab.dm @@ -32,7 +32,8 @@ icon_state = "sif_crab" icon_living = "sif_crab" icon_dead = "sif_crab_dead" - icon_scale = 1.5 + icon_scale_x = 1.5 + icon_scale_y = 1.5 faction = "crabs" diff --git a/code/modules/mob/living/simple_mob/subtypes/animal/sif/shantak.dm b/code/modules/mob/living/simple_mob/subtypes/animal/sif/shantak.dm index 881615138e..bb6a25604a 100644 --- a/code/modules/mob/living/simple_mob/subtypes/animal/sif/shantak.dm +++ b/code/modules/mob/living/simple_mob/subtypes/animal/sif/shantak.dm @@ -67,7 +67,8 @@ name = "big shantak" desc = "A piglike creature with a bright iridiscent mane that sparkles as though lit by an inner light. \ This one seems bigger than the others, and has a commanding presence." - icon_scale = 1.5 + icon_scale_x = 1.5 + icon_scale_y = 1.5 maxHealth = 125 player_msg = "You have the ability to command other shantaks to follow you." diff --git a/code/modules/mob/living/simple_mob/subtypes/humanoid/mercs/mercs_vr.dm b/code/modules/mob/living/simple_mob/subtypes/humanoid/mercs/mercs_vr.dm index 026c803e4b..36253dce84 100644 --- a/code/modules/mob/living/simple_mob/subtypes/humanoid/mercs/mercs_vr.dm +++ b/code/modules/mob/living/simple_mob/subtypes/humanoid/mercs/mercs_vr.dm @@ -1,3 +1,9 @@ /datum/say_list/merc/unknown_ind speak = list("One day the'll fix that damn engine..","Next time, We're hidding on the tropical beach planet.","Wish I had better equipment...","I knew I should have been a line chef...","Fuckin' helmet keeps fogging up.","Hate this blocky ass ship.") - say_got_target = list("Looks like trouble!","Contact!","We've got company!","Perimeter Breached!!") \ No newline at end of file + say_got_target = list("Looks like trouble!","Contact!","We've got company!","Perimeter Breached!!") + +/mob/living/simple_mob/humanoid/merc/melee/sword/space + name = "mercenary commando" + +/mob/living/simple_mob/humanoid/merc/ranged/space + name = "mercenary commando" \ No newline at end of file diff --git a/code/modules/mob/living/simple_mob/subtypes/mechanical/hivebot/ranged_damage.dm b/code/modules/mob/living/simple_mob/subtypes/mechanical/hivebot/ranged_damage.dm index 5e4d877751..bf2e3eb18a 100644 --- a/code/modules/mob/living/simple_mob/subtypes/mechanical/hivebot/ranged_damage.dm +++ b/code/modules/mob/living/simple_mob/subtypes/mechanical/hivebot/ranged_damage.dm @@ -105,7 +105,8 @@ name = "siege engine hivebot" desc = "A large robot capable of delivering long range bombardment." projectiletype = /obj/item/projectile/arc/test - icon_scale = 2 + icon_scale_x = 2 + icon_scale_y = 2 icon_state = "red" icon_living = "red" diff --git a/code/modules/mob/living/simple_mob/subtypes/mechanical/hivebot/tank.dm b/code/modules/mob/living/simple_mob/subtypes/mechanical/hivebot/tank.dm index 007f190c04..7f4e10f05d 100644 --- a/code/modules/mob/living/simple_mob/subtypes/mechanical/hivebot/tank.dm +++ b/code/modules/mob/living/simple_mob/subtypes/mechanical/hivebot/tank.dm @@ -39,7 +39,8 @@ desc = "A large robot." maxHealth = 10 LASERS_TO_KILL // 300 health health = 10 LASERS_TO_KILL - icon_scale = 2 + icon_scale_x = 2 + icon_scale_y = 2 player_msg = "You have a very large amount of health." @@ -49,7 +50,8 @@ desc = "A robot clad in heavy armor." maxHealth = 5 LASERS_TO_KILL // 150 health. health = 5 LASERS_TO_KILL - icon_scale = 1.5 + icon_scale_x = 1.5 + icon_scale_y = 1.5 player_msg = "You are heavily armored." // Note that armor effectively makes lasers do about 9 damage instead of 30, // so it has an effective health of ~16.6 LASERS_TO_KILL if regular lasers are used. diff --git a/code/modules/mob/living/simple_mob/subtypes/mechanical/mecha/adv_dark_gygax.dm b/code/modules/mob/living/simple_mob/subtypes/mechanical/mecha/adv_dark_gygax.dm index 2f9420bf64..39708365df 100644 --- a/code/modules/mob/living/simple_mob/subtypes/mechanical/mecha/adv_dark_gygax.dm +++ b/code/modules/mob/living/simple_mob/subtypes/mechanical/mecha/adv_dark_gygax.dm @@ -77,7 +77,8 @@ catalogue_data = list(/datum/category_item/catalogue/technology/adv_dark_gygax) icon_state = "darkgygax_adv" wreckage = /obj/structure/loot_pile/mecha/gygax/dark/adv - icon_scale = 1.5 + icon_scale_x = 1.5 + icon_scale_y = 1.5 movement_shake_radius = 14 maxHealth = 450 diff --git a/code/modules/mob/living/simple_mob/subtypes/occult/constructs/juggernaut.dm b/code/modules/mob/living/simple_mob/subtypes/occult/constructs/juggernaut.dm index 31dfa4d34a..8a56f08ddd 100644 --- a/code/modules/mob/living/simple_mob/subtypes/occult/constructs/juggernaut.dm +++ b/code/modules/mob/living/simple_mob/subtypes/occult/constructs/juggernaut.dm @@ -106,7 +106,8 @@ friendly = list("pokes") //Anything nice the Behemoth would do would still Kill the Human. Leave it at poke. attack_sound = 'sound/weapons/heavysmash.ogg' resistance = 10 - icon_scale = 2 + icon_scale_x = 2 + icon_scale_y = 2 var/energy = 0 var/max_energy = 1000 armor = list( diff --git a/code/modules/mob/living/simple_mob/subtypes/slime/feral/feral.dm b/code/modules/mob/living/simple_mob/subtypes/slime/feral/feral.dm index 91aa0b0a79..2fc06815ca 100644 --- a/code/modules/mob/living/simple_mob/subtypes/slime/feral/feral.dm +++ b/code/modules/mob/living/simple_mob/subtypes/slime/feral/feral.dm @@ -1,94 +1,96 @@ -// These slimes lack certain xenobio features but get more combat-oriented goodies. Generally these are more oriented towards Explorers than Xenobiologists. - -/mob/living/simple_mob/slime/feral - name = "feral slime" - desc = "The result of slimes escaping containment from some xenobiology lab. \ - Having the means to successfully escape their lab, as well as having to survive on a harsh, cold world has made these \ - creatures rival the ferocity of other apex predators in this region of Sif. It is considered to be a very invasive species." - description_info = "Note that processing this large slime will give six cores." - - cores = 6 // Xenobio will love getting their hands on these. - - icon_state = "slime adult" - icon_living = "slime adult" - icon_dead = "slime adult dead" - glow_range = 5 - glow_intensity = 4 - icon_scale = 2 // Twice as big as the xenobio variant. - pixel_y = -10 // Since the base sprite isn't centered properly, the pixel auto-adjustment needs some help. - default_pixel_y = -10 // To prevent resetting above var. - - maxHealth = 300 - movement_cooldown = 10 - melee_attack_delay = 0.5 SECONDS - - ai_holder_type = /datum/ai_holder/simple_mob/ranged/pointblank - - -// Slimebatoning/xenotasing it just makes it mad at you (which can be good if you're heavily armored and your friends aren't). -/mob/living/simple_mob/slime/feral/slimebatoned(mob/living/user, amount) - taunt(user, TRUE) - - -// *********** -// *Dark Blue* -// *********** - -// Dark Blue feral slimes can fire a strong icicle projectile every few seconds. The icicle hits hard and has some armor penetration. -// They also have a similar aura as their xenobio counterparts, which inflicts cold damage. It also chills non-resistant mobs. - -/mob/living/simple_mob/slime/feral/dark_blue - name = "dark blue feral slime" - color = "#2398FF" - glow_toggle = TRUE - slime_color = "dark blue" - coretype = /obj/item/slime_extract/dark_blue - cold_resist = 1 // Complete immunity. - minbodytemp = 0 - cold_damage_per_tick = 0 - - projectiletype = /obj/item/projectile/icicle - base_attack_cooldown = 2 SECONDS - ranged_attack_delay = 1 SECOND - - player_msg = "You can fire an icicle projectile every two seconds. It hits hard, and armor has a hard time resisting it.
\ - You are also immune to the cold, and you cause enemies around you to suffer periodic harm from the cold, if unprotected.
\ - Unprotected enemies are also Chilled, making them slower and less evasive, and disabling effects last longer." - -/obj/item/projectile/icicle - name = "icicle" - icon_state = "ice_2" - damage = 40 - damage_type = BRUTE - check_armour = "melee" - armor_penetration = 30 - speed = 2 - icon_scale = 2 // It hits like a truck. - sharp = TRUE - -/obj/item/projectile/icicle/on_impact(atom/A) - playsound(get_turf(A), "shatter", 70, 1) - return ..() - -/obj/item/projectile/icicle/get_structure_damage() - return damage / 2 // They're really deadly against mobs, but less effective against solid things. - -/mob/living/simple_mob/slime/feral/dark_blue/handle_special() - if(stat != DEAD) - cold_aura() - ..() - -/mob/living/simple_mob/slime/feral/dark_blue/proc/cold_aura() - for(var/mob/living/L in view(3, src)) - if(L == src) - continue - chill(L) - -/mob/living/simple_mob/slime/feral/dark_blue/proc/chill(mob/living/L) - L.inflict_cold_damage(10) - if(L.get_cold_protection() < 1) - L.add_modifier(/datum/modifier/chilled, 5 SECONDS, src) - - if(L.has_AI()) // Other AIs should react to hostile auras. - L.ai_holder.react_to_attack(src) +// These slimes lack certain xenobio features but get more combat-oriented goodies. Generally these are more oriented towards Explorers than Xenobiologists. + +/mob/living/simple_mob/slime/feral + name = "feral slime" + desc = "The result of slimes escaping containment from some xenobiology lab. \ + Having the means to successfully escape their lab, as well as having to survive on a harsh, cold world has made these \ + creatures rival the ferocity of other apex predators in this region of Sif. It is considered to be a very invasive species." + description_info = "Note that processing this large slime will give six cores." + + cores = 6 // Xenobio will love getting their hands on these. + + icon_state = "slime adult" + icon_living = "slime adult" + icon_dead = "slime adult dead" + glow_range = 5 + glow_intensity = 4 + icon_scale_x = 2 // Twice as big as the xenobio variant. + icon_scale_y = 2 + pixel_y = -10 // Since the base sprite isn't centered properly, the pixel auto-adjustment needs some help. + default_pixel_y = -10 // To prevent resetting above var. + + maxHealth = 300 + movement_cooldown = 10 + melee_attack_delay = 0.5 SECONDS + + ai_holder_type = /datum/ai_holder/simple_mob/ranged/pointblank + + +// Slimebatoning/xenotasing it just makes it mad at you (which can be good if you're heavily armored and your friends aren't). +/mob/living/simple_mob/slime/feral/slimebatoned(mob/living/user, amount) + taunt(user, TRUE) + + +// *********** +// *Dark Blue* +// *********** + +// Dark Blue feral slimes can fire a strong icicle projectile every few seconds. The icicle hits hard and has some armor penetration. +// They also have a similar aura as their xenobio counterparts, which inflicts cold damage. It also chills non-resistant mobs. + +/mob/living/simple_mob/slime/feral/dark_blue + name = "dark blue feral slime" + color = "#2398FF" + glow_toggle = TRUE + slime_color = "dark blue" + coretype = /obj/item/slime_extract/dark_blue + cold_resist = 1 // Complete immunity. + minbodytemp = 0 + cold_damage_per_tick = 0 + + projectiletype = /obj/item/projectile/icicle + base_attack_cooldown = 2 SECONDS + ranged_attack_delay = 1 SECOND + + player_msg = "You can fire an icicle projectile every two seconds. It hits hard, and armor has a hard time resisting it.
\ + You are also immune to the cold, and you cause enemies around you to suffer periodic harm from the cold, if unprotected.
\ + Unprotected enemies are also Chilled, making them slower and less evasive, and disabling effects last longer." + +/obj/item/projectile/icicle + name = "icicle" + icon_state = "ice_2" + damage = 40 + damage_type = BRUTE + check_armour = "melee" + armor_penetration = 30 + speed = 2 + icon_scale_x = 2 // It hits like a truck. + icon_scale_y = 2 + sharp = TRUE + +/obj/item/projectile/icicle/on_impact(atom/A) + playsound(get_turf(A), "shatter", 70, 1) + return ..() + +/obj/item/projectile/icicle/get_structure_damage() + return damage / 2 // They're really deadly against mobs, but less effective against solid things. + +/mob/living/simple_mob/slime/feral/dark_blue/handle_special() + if(stat != DEAD) + cold_aura() + ..() + +/mob/living/simple_mob/slime/feral/dark_blue/proc/cold_aura() + for(var/mob/living/L in view(3, src)) + if(L == src) + continue + chill(L) + +/mob/living/simple_mob/slime/feral/dark_blue/proc/chill(mob/living/L) + L.inflict_cold_damage(10) + if(L.get_cold_protection() < 1) + L.add_modifier(/datum/modifier/chilled, 5 SECONDS, src) + + if(L.has_AI()) // Other AIs should react to hostile auras. + L.ai_holder.react_to_attack(src) diff --git a/code/modules/modular_computers/computers/subtypes/dev_console.dm b/code/modules/modular_computers/computers/subtypes/dev_console.dm index 4a8981d41b..d7f977f33b 100644 --- a/code/modules/modular_computers/computers/subtypes/dev_console.dm +++ b/code/modules/modular_computers/computers/subtypes/dev_console.dm @@ -1,7 +1,7 @@ /obj/item/modular_computer/console name = "console" desc = "A stationary computer." - icon = 'icons/obj/modular_console.dmi' + icon = 'icons/obj/modular_console_vr.dmi' //VOREStation Edit icon_state = "console" icon_state_unpowered = "console" icon_state_screensaver = "standby" diff --git a/code/modules/modular_computers/computers/subtypes/dev_laptop.dm b/code/modules/modular_computers/computers/subtypes/dev_laptop.dm index 851008b23d..3a9cab6bc2 100644 --- a/code/modules/modular_computers/computers/subtypes/dev_laptop.dm +++ b/code/modules/modular_computers/computers/subtypes/dev_laptop.dm @@ -28,8 +28,6 @@ //VOREStation Addition Begin var/supported = FALSE for(var/obj/structure/table/S in loc) - if(istype(S, /obj/structure/table/bench) || istype(S, /obj/structure/table/rack)) - continue supported = TRUE if(!supported) to_chat(usr, "You will need a better supporting surface before opening \the [src]!") diff --git a/code/modules/modular_computers/computers/subtypes/preset_laptop.dm b/code/modules/modular_computers/computers/subtypes/preset_laptop.dm index 3152878fc2..905df24590 100644 --- a/code/modules/modular_computers/computers/subtypes/preset_laptop.dm +++ b/code/modules/modular_computers/computers/subtypes/preset_laptop.dm @@ -31,6 +31,11 @@ battery_module = new/obj/item/weapon/computer_hardware/battery_module/advanced(src) battery_module.charge_to_full() +/obj/item/modular_computer/laptop/preset/custom_loadout/elite + icon_state_unpowered = "adv-laptop-open" + icon_state = "adv-laptop-open" + icon_state_closed = "adv-laptop-closed" + /obj/item/modular_computer/laptop/preset/custom_loadout/elite/install_default_hardware() ..() processor_unit = new/obj/item/weapon/computer_hardware/processor_unit(src) @@ -41,3 +46,23 @@ card_slot = new/obj/item/weapon/computer_hardware/card_slot(src) battery_module = new/obj/item/weapon/computer_hardware/battery_module/super(src) battery_module.charge_to_full() + +//VOREStation Add Start +/obj/item/modular_computer/laptop/preset/custom_loadout/rugged + name = "rugged laptop computer" + desc = "A rugged portable computer." + icon = 'icons/obj/modular_laptop_vr.dmi' + max_damage = 300 + broken_damage = 200 + +/obj/item/modular_computer/laptop/preset/custom_loadout/rugged/install_default_hardware() + ..() + processor_unit = new/obj/item/weapon/computer_hardware/processor_unit/small(src) + tesla_link = new/obj/item/weapon/computer_hardware/tesla_link(src) + hard_drive = new/obj/item/weapon/computer_hardware/hard_drive/advanced(src) + network_card = new/obj/item/weapon/computer_hardware/network_card/advanced(src) + nano_printer = new/obj/item/weapon/computer_hardware/nano_printer(src) + card_slot = new/obj/item/weapon/computer_hardware/card_slot(src) + battery_module = new/obj/item/weapon/computer_hardware/battery_module/super(src) + battery_module.charge_to_full() +//VOREStation Add End \ No newline at end of file diff --git a/code/modules/projectiles/projectile/arc.dm b/code/modules/projectiles/projectile/arc.dm index 97069db1fb..0c4c9f4caa 100644 --- a/code/modules/projectiles/projectile/arc.dm +++ b/code/modules/projectiles/projectile/arc.dm @@ -162,7 +162,8 @@ /obj/item/projectile/arc/radioactive name = "radiation blast" icon_state = "green_pellet" - icon_scale = 2 + icon_scale_x = 2 + icon_scale_y = 2 var/rad_power = 50 /obj/item/projectile/arc/radioactive/on_impact(turf/T) diff --git a/code/modules/research/designs/precursor.dm b/code/modules/research/designs/precursor.dm index 88575e5667..eaf7b3a923 100644 --- a/code/modules/research/designs/precursor.dm +++ b/code/modules/research/designs/precursor.dm @@ -58,6 +58,15 @@ build_path = /obj/item/weapon/weldingtool/experimental/hybrid sort_string = "PATCW" +/datum/design/item/precursor/janusmodule + name = "Blackbox Circuit Datamass" + desc = "A design that seems to be in a constantly shifting superposition." + id = "janus_module" + materials = list(MAT_DURASTEEL = 3000, MAT_MORPHIUM = 2000, MAT_METALHYDROGEN = 6000, MAT_URANIUM = 6000, MAT_VERDANTIUM = 1500) + req_tech = list(TECH_MATERIAL = 7, TECH_BLUESPACE = 5, TECH_MAGNET = 6, TECH_PHORON = 3, TECH_ARCANE = 1, TECH_PRECURSOR = 2) + build_path = /obj/random/janusmodule + sort_string = "PAJAA" + /datum/design/item/anomaly/AssembleDesignName() ..() name = "Anomalous prototype ([item_name])" @@ -67,4 +76,4 @@ if(build_path) var/obj/item/I = build_path desc = initial(I.desc) - ..() \ No newline at end of file + ..() diff --git a/html/changelogs/Mechoid - Borers.yml b/html/changelogs/Mechoid - Borers.yml new file mode 100644 index 0000000000..f92c619d86 --- /dev/null +++ b/html/changelogs/Mechoid - Borers.yml @@ -0,0 +1,37 @@ +################################ +# Example Changelog File +# +# Note: This file, and files beginning with ".", and files that don't end in ".yml" will not be read. If you change this file, you will look really dumb. +# +# Your changelog will be merged with a master changelog. (New stuff added only, and only on the date entry for the day it was merged.) +# When it is, any changes listed below will disappear. +# +# Valid Prefixes: +# bugfix +# wip (For works in progress) +# tweak +# soundadd +# sounddel +# rscadd (general adding of nice things) +# rscdel (general deleting of nice things) +# imageadd +# imagedel +# maptweak +# spellcheck (typo fixes) +# experiment +################################# + +# Your name. +author: Mechoid + +# Optional: Remove this file after generating master changelog. Useful for PR changelogs that won't get used again. +delete-after: True + +# Any changes you've made. See valid prefix list above. +# INDENT WITH TWO SPACES. NOT TABS. SPACES. +# SCREW THIS UP AND IT WON'T WORK. +# Also, all entries are changed into a single [] after a master changelog generation. Just remove the brackets when you add new entries. +# Please surround your changes in double quotes ("), as certain characters otherwise screws up compiling. The quotes will not show up in the changelog. +changes: + - tweak: "Borers can speak through nearby mobs if they have a sufficient build-up of chemicals." + - tweak: "Borers have a max chemical volume." diff --git a/html/changelogs/Novacat - Fucktimers.yml b/html/changelogs/Novacat - Fucktimers.yml new file mode 100644 index 0000000000..4be0cb5dfc --- /dev/null +++ b/html/changelogs/Novacat - Fucktimers.yml @@ -0,0 +1,36 @@ +################################ +# Example Changelog File +# +# Note: This file, and files beginning with ".", and files that don't end in ".yml" will not be read. If you change this file, you will look really dumb. +# +# Your changelog will be merged with a master changelog. (New stuff added only, and only on the date entry for the day it was merged.) +# When it is, any changes listed below will disappear. +# +# Valid Prefixes: +# bugfix +# wip (For works in progress) +# tweak +# soundadd +# sounddel +# rscadd (general adding of nice things) +# rscdel (general deleting of nice things) +# imageadd +# imagedel +# maptweak +# spellcheck (typo fixes) +# experiment +################################# + +# Your name. +author: Novacat + +# Optional: Remove this file after generating master changelog. Useful for PR changelogs that won't get used again. +delete-after: True + +# Any changes you've made. See valid prefix list above. +# INDENT WITH TWO SPACES. NOT TABS. SPACES. +# SCREW THIS UP AND IT WON'T WORK. +# Also, all entries are changed into a single [] after a master changelog generation. Just remove the brackets when you add new entries. +# Please surround your changes in double quotes ("), as certain characters otherwise screws up compiling. The quotes will not show up in the changelog. +changes: + - bugfix: "Attempts to fix the timer SS to be moore robust" diff --git a/html/changelogs/mistyLuminescence - makeover.yml b/html/changelogs/mistyLuminescence - makeover.yml new file mode 100644 index 0000000000..e55f71a2ec --- /dev/null +++ b/html/changelogs/mistyLuminescence - makeover.yml @@ -0,0 +1,36 @@ +################################ +# Example Changelog File +# +# Note: This file, and files beginning with ".", and files that don't end in ".yml" will not be read. If you change this file, you will look really dumb. +# +# Your changelog will be merged with a master changelog. (New stuff added only, and only on the date entry for the day it was merged.) +# When it is, any changes listed below will disappear. +# +# Valid Prefixes: +# bugfix +# wip (For works in progress) +# tweak +# soundadd +# sounddel +# rscadd (general adding of nice things) +# rscdel (general deleting of nice things) +# imageadd +# imagedel +# maptweak +# spellcheck (typo fixes) +# experiment +################################# + +# Your name. +author: mistyLuminescence + +# Optional: Remove this file after generating master changelog. Useful for PR changelogs that won't get used again. +delete-after: True + +# Any changes you've made. See valid prefix list above. +# INDENT WITH TWO SPACES. NOT TABS. SPACES. +# SCREW THIS UP AND IT WON'T WORK. +# Also, all entries are changed into a single [] after a master changelog generation. Just remove the brackets when you add new entries. +# Please surround your changes in double quotes ("), as certain characters otherwise screws up compiling. The quotes will not show up in the changelog. +changes: + - rscadd: "Adds the makeover kit to the traitor uplink for 5 TC, also available in the Infiltrator bundle null crate in Cargo. Makeover kits can be used to change the user's hair style and color, and eye color." diff --git a/html/changelogs/mistyLuminescence - randomevents.yml b/html/changelogs/mistyLuminescence - randomevents.yml new file mode 100644 index 0000000000..e5659f8a4e --- /dev/null +++ b/html/changelogs/mistyLuminescence - randomevents.yml @@ -0,0 +1,36 @@ +################################ +# Example Changelog File +# +# Note: This file, and files beginning with ".", and files that don't end in ".yml" will not be read. If you change this file, you will look really dumb. +# +# Your changelog will be merged with a master changelog. (New stuff added only, and only on the date entry for the day it was merged.) +# When it is, any changes listed below will disappear. +# +# Valid Prefixes: +# bugfix +# wip (For works in progress) +# tweak +# soundadd +# sounddel +# rscadd (general adding of nice things) +# rscdel (general deleting of nice things) +# imageadd +# imagedel +# maptweak +# spellcheck (typo fixes) +# experiment +################################# + +# Your name. +author: mistyLuminescence + +# Optional: Remove this file after generating master changelog. Useful for PR changelogs that won't get used again. +delete-after: True + +# Any changes you've made. See valid prefix list above. +# INDENT WITH TWO SPACES. NOT TABS. SPACES. +# SCREW THIS UP AND IT WON'T WORK. +# Also, all entries are changed into a single [] after a master changelog generation. Just remove the brackets when you add new entries. +# Please surround your changes in double quotes ("), as certain characters otherwise screws up compiling. The quotes will not show up in the changelog. +changes: + - bugfix: Random event timers now wait until the round starts to begin counting down. \ No newline at end of file diff --git a/icons/mob/human_races/cyberlimbs/morpheus/morpheus_alt2.dmi b/icons/mob/human_races/cyberlimbs/morpheus/morpheus_alt2.dmi index 6bee009356..26f2ccb4e7 100644 Binary files a/icons/mob/human_races/cyberlimbs/morpheus/morpheus_alt2.dmi and b/icons/mob/human_races/cyberlimbs/morpheus/morpheus_alt2.dmi differ diff --git a/icons/mob/radial.dmi b/icons/mob/radial.dmi new file mode 100644 index 0000000000..cfdd0e549a Binary files /dev/null and b/icons/mob/radial.dmi differ diff --git a/icons/obj/flora/deadtrees.dmi b/icons/obj/flora/deadtrees.dmi index 7a0b164619..2a3655b0d2 100644 Binary files a/icons/obj/flora/deadtrees.dmi and b/icons/obj/flora/deadtrees.dmi differ diff --git a/icons/obj/items.dmi b/icons/obj/items.dmi index d2d986c205..e3de287a99 100644 Binary files a/icons/obj/items.dmi and b/icons/obj/items.dmi differ diff --git a/icons/obj/modular_console_vr.dmi b/icons/obj/modular_console_vr.dmi new file mode 100644 index 0000000000..125711410d Binary files /dev/null and b/icons/obj/modular_console_vr.dmi differ diff --git a/icons/obj/modular_laptop.dmi b/icons/obj/modular_laptop.dmi index af1883055e..8f060dd500 100644 Binary files a/icons/obj/modular_laptop.dmi and b/icons/obj/modular_laptop.dmi differ diff --git a/icons/obj/modular_laptop_vr.dmi b/icons/obj/modular_laptop_vr.dmi new file mode 100644 index 0000000000..6dc2af2d01 Binary files /dev/null and b/icons/obj/modular_laptop_vr.dmi differ diff --git a/maps/submaps/shelters/shelter_3.dmm b/maps/submaps/shelters/shelter_3.dmm index 42321a3d26..c288aa9702 100644 --- a/maps/submaps/shelters/shelter_3.dmm +++ b/maps/submaps/shelters/shelter_3.dmm @@ -52,7 +52,7 @@ /obj/item/weapon/storage/pill_bottle/antitox, /obj/item/weapon/storage/firstaid/adv, /obj/item/weapon/storage/firstaid/regular, -/obj/item/modular_computer/laptop/preset/custom_loadout/elite, +/obj/item/modular_computer/laptop/preset/custom_loadout/rugged, /obj/item/weapon/storage/box/survival/comp{ starts_with = list(/obj/item/weapon/tool/prybar/red,/obj/item/clothing/glasses/goggles,/obj/item/weapon/reagent_containers/hypospray/autoinjector,/obj/item/stack/medical/bruise_pack,/obj/item/device/flashlight/glowstick,/obj/item/weapon/reagent_containers/food/snacks/candy/proteinbar,/obj/item/clothing/mask/breath,/obj/item/weapon/tank/emergency/oxygen/engi) }, diff --git a/maps/tether/tether-06-station2.dmm b/maps/tether/tether-06-station2.dmm index 8e5d0ca44e..fa40d5e3b7 100644 --- a/maps/tether/tether-06-station2.dmm +++ b/maps/tether/tether-06-station2.dmm @@ -3958,6 +3958,9 @@ /obj/item/device/radio/intercom/department/medbay{ pixel_y = -24 }, +/obj/effect/landmark/start{ + name = "Paramedic" + }, /turf/simulated/floor/tiled/dark, /area/medical/medbay_emt_bay) "fP" = ( @@ -18063,6 +18066,9 @@ /obj/effect/floor_decal/corner/paleblue/border{ dir = 6 }, +/obj/effect/landmark/start{ + name = "Paramedic" + }, /turf/simulated/floor/tiled/dark, /area/medical/medbay_emt_bay) "Bx" = ( @@ -18278,7 +18284,7 @@ dir = 8 }, /obj/effect/landmark/start{ - name = "Pathfinder" + name = "Paramedic" }, /turf/simulated/floor/tiled/dark, /area/medical/medbay_emt_bay) @@ -18460,7 +18466,7 @@ dir = 4 }, /obj/effect/landmark/start{ - name = "Pathfinder" + name = "Paramedic" }, /turf/simulated/floor/tiled/dark, /area/medical/medbay_emt_bay) diff --git a/maps/tether/tether-10-colony.dmm b/maps/tether/tether-10-colony.dmm index b0704731b3..9ced842fdb 100644 --- a/maps/tether/tether-10-colony.dmm +++ b/maps/tether/tether-10-colony.dmm @@ -778,21 +778,11 @@ }) "bj" = ( /obj/structure/table/rack, -/obj/item/clothing/gloves/swat{ - armor = list("melee" = 80, "bullet" = 80, "laser" = 80, "energy" = 80, "bomb" = 80, "bio" = 80, "rad" = 80) - }, -/obj/item/clothing/gloves/swat{ - armor = list("melee" = 80, "bullet" = 80, "laser" = 80, "energy" = 80, "bomb" = 80, "bio" = 80, "rad" = 80) - }, -/obj/item/clothing/gloves/swat{ - armor = list("melee" = 80, "bullet" = 80, "laser" = 80, "energy" = 80, "bomb" = 80, "bio" = 80, "rad" = 80) - }, -/obj/item/clothing/gloves/swat{ - armor = list("melee" = 80, "bullet" = 80, "laser" = 80, "energy" = 80, "bomb" = 80, "bio" = 80, "rad" = 80) - }, -/obj/item/clothing/gloves/swat{ - armor = list("melee" = 80, "bullet" = 80, "laser" = 80, "energy" = 80, "bomb" = 80, "bio" = 80, "rad" = 80) - }, +/obj/item/clothing/gloves/swat, +/obj/item/clothing/gloves/swat, +/obj/item/clothing/gloves/swat, +/obj/item/clothing/gloves/swat, +/obj/item/clothing/gloves/swat, /obj/item/clothing/shoes/boots/swat, /obj/item/clothing/shoes/boots/swat, /obj/item/clothing/shoes/boots/swat, @@ -806,47 +796,36 @@ /obj/item/clothing/suit/armor/swat, /obj/item/clothing/suit/armor/swat, /obj/item/clothing/mask/gas/commando{ - armor = list("melee" = 50, "bullet" = 50, "laser" = 50, "energy" = 50, "bomb" = 50, "bio" = 75, "rad" = 0); name = "Commando Mask" }, /obj/item/clothing/mask/gas/commando{ - armor = list("melee" = 50, "bullet" = 50, "laser" = 50, "energy" = 50, "bomb" = 50, "bio" = 75, "rad" = 0); name = "Commando Mask" }, /obj/item/clothing/mask/gas/commando{ - armor = list("melee" = 50, "bullet" = 50, "laser" = 50, "energy" = 50, "bomb" = 50, "bio" = 75, "rad" = 0); name = "Commando Mask" }, /obj/item/clothing/mask/gas/commando{ - armor = list("melee" = 50, "bullet" = 50, "laser" = 50, "energy" = 50, "bomb" = 50, "bio" = 75, "rad" = 0); name = "Commando Mask" }, /obj/item/clothing/mask/gas/commando{ - armor = list("melee" = 50, "bullet" = 50, "laser" = 50, "energy" = 50, "bomb" = 50, "bio" = 75, "rad" = 0); name = "Commando Mask" }, /obj/item/clothing/head/helmet/space/deathsquad{ - armor = list("melee" = 80, "bullet" = 80, "laser" = 60, "energy" = 70, "bomb" = 50, "bio" = 100, "rad" = 60); name = "swat helmet" }, /obj/item/clothing/head/helmet/space/deathsquad{ - armor = list("melee" = 80, "bullet" = 80, "laser" = 60, "energy" = 70, "bomb" = 50, "bio" = 100, "rad" = 60); name = "swat helmet" }, /obj/item/clothing/head/helmet/space/deathsquad{ - armor = list("melee" = 80, "bullet" = 80, "laser" = 60, "energy" = 70, "bomb" = 50, "bio" = 100, "rad" = 60); name = "swat helmet" }, /obj/item/clothing/head/helmet/space/deathsquad{ - armor = list("melee" = 80, "bullet" = 80, "laser" = 60, "energy" = 70, "bomb" = 50, "bio" = 100, "rad" = 60); name = "swat helmet" }, /obj/item/clothing/head/helmet/space/deathsquad{ - armor = list("melee" = 80, "bullet" = 80, "laser" = 60, "energy" = 70, "bomb" = 50, "bio" = 100, "rad" = 60); name = "swat helmet" }, /obj/item/clothing/head/helmet/space/deathsquad{ - armor = list("melee" = 80, "bullet" = 80, "laser" = 60, "energy" = 70, "bomb" = 50, "bio" = 100, "rad" = 60); name = "swat helmet" }, /turf/unsimulated/floor{ @@ -10902,7 +10881,6 @@ "tO" = ( /obj/structure/table/steel, /obj/item/clothing/shoes/boots/jackboots{ - armor = list("melee" = 69, "bullet" = 69, "laser" = 69, "energy" = 69, "bomb" = 69, "bio" = 69, "rad" = 69); desc = "This pair of Jackboots look worn and freshly used. They have several claw markings inside and you can read the initials D and M at the bottom"; name = "Dhaeleena's Jackboots" }, diff --git a/sound/effects/deskbell.ogg b/sound/effects/deskbell.ogg new file mode 100644 index 0000000000..ef40794cf4 Binary files /dev/null and b/sound/effects/deskbell.ogg differ diff --git a/sound/effects/deskbell_rude.ogg b/sound/effects/deskbell_rude.ogg new file mode 100644 index 0000000000..1698a15fb7 Binary files /dev/null and b/sound/effects/deskbell_rude.ogg differ diff --git a/vorestation.dme b/vorestation.dme index 63c326d73f..96a687412d 100644 --- a/vorestation.dme +++ b/vorestation.dme @@ -146,6 +146,8 @@ #include "code\_onclick\hud\human.dm" #include "code\_onclick\hud\movable_screen_objects.dm" #include "code\_onclick\hud\other_mobs.dm" +#include "code\_onclick\hud\radial.dm" +#include "code\_onclick\hud\radial_persistent.dm" #include "code\_onclick\hud\robot.dm" #include "code\_onclick\hud\robot_vr.dm" #include "code\_onclick\hud\screen_objects.dm" @@ -947,6 +949,7 @@ #include "code\game\objects\effects\temporary_visuals\projectiles\tracer.dm" #include "code\game\objects\items\antag_spawners.dm" #include "code\game\objects\items\apc_frame.dm" +#include "code\game\objects\items\bells.dm" #include "code\game\objects\items\blueprints.dm" #include "code\game\objects\items\bodybag.dm" #include "code\game\objects\items\contraband.dm" @@ -2392,8 +2395,8 @@ #include "code\modules\mob\living\simple_mob\subtypes\animal\pets\fox_vr.dm" #include "code\modules\mob\living\simple_mob\subtypes\animal\pets\parrot.dm" #include "code\modules\mob\living\simple_mob\subtypes\animal\sif\diyaab.dm" -#include "code\modules\mob\living\simple_mob\subtypes\animal\sif\fluffy_vr.dm" #include "code\modules\mob\living\simple_mob\subtypes\animal\sif\duck.dm" +#include "code\modules\mob\living\simple_mob\subtypes\animal\sif\fluffy_vr.dm" #include "code\modules\mob\living\simple_mob\subtypes\animal\sif\frostfly.dm" #include "code\modules\mob\living\simple_mob\subtypes\animal\sif\glitterfly.dm" #include "code\modules\mob\living\simple_mob\subtypes\animal\sif\hooligan_crab.dm"