diff --git a/code/__HELPERS/icons.dm b/code/__HELPERS/icons.dm index 1324f6cbcd9..51f5c6b4442 100644 --- a/code/__HELPERS/icons.dm +++ b/code/__HELPERS/icons.dm @@ -798,3 +798,70 @@ The _flatIcons list is a cache for generated icon files. var/image/I = O composite.Blend(icon(I.icon, I.icon_state, I.dir, 1), ICON_OVERLAY) return composite + + +//What the mob looks like as animated static +//By vg's ComicIronic +/proc/getStaticIcon(icon/A, safety=1) + var/icon/flat_icon = safety ? A : new(A) + flat_icon.Blend(rgb(255,255,255)) + flat_icon.BecomeAlphaMask() + var/icon/static_icon = new/icon('icons/effects/effects.dmi', "static_base") + static_icon.AddAlphaMask(flat_icon) + return static_icon + + +//What the mob looks like as a pitch black outline +//By vg's ComicIronic +/proc/getBlankIcon(icon/A, safety=1) + var/icon/flat_icon = safety ? A : new(A) + flat_icon.Blend(rgb(255,255,255)) + flat_icon.BecomeAlphaMask() + var/icon/blank_icon = new/icon('icons/effects/effects.dmi', "blank_base") + blank_icon.AddAlphaMask(flat_icon) + return blank_icon + + +//Dwarf fortress style icons based on letters (defaults to the first letter of the Atom's name) +//By vg's ComicIronic +/proc/getLetterImage(atom/A, letter= "", uppercase = 0) + if(!A) + return + + var/icon/atom_icon = new(A.icon, A.icon_state) + + if(!letter) + letter = copytext(A.name, 1, 2) + if(uppercase == 1) + letter = uppertext(letter) + else if(uppercase == -1) + letter = lowertext(letter) + + var/image/text_image = new(loc = A) + text_image.maptext = "[letter]" + text_image.color = AverageColour(atom_icon) + text_image.pixel_x = 7 + text_image.pixel_y = 5 + del(atom_icon) + return text_image + + +//Find's the average colour of the icon +//By vg's ComicIronic +/proc/AverageColour(var/icon/I) + var/list/colours = list() + for(var/x_pixel = 1 to I.Width()) + for(var/y_pixel = 1 to I.Height()) + var/this_colour = I.GetPixel(x_pixel, y_pixel) + if(this_colour) + colours.Add(this_colour) + + if(!colours.len) + return null + + var/final_average = colours[1] + for(var/colour in (colours - colours[1])) + final_average = BlendRGB(final_average, colour, 1) + return final_average + + diff --git a/code/modules/mob/living/carbon/human/human.dm b/code/modules/mob/living/carbon/human/human.dm index 61ad8e31b36..1cfca7982c3 100644 --- a/code/modules/mob/living/carbon/human/human.dm +++ b/code/modules/mob/living/carbon/human/human.dm @@ -717,3 +717,19 @@ H.w_uniform.add_fingerprint(M) ..() + + +/mob/living/carbon/human/generateStaticOverlay() + var/image/staticOverlay = image(icon('icons/effects/effects.dmi', "static"), loc = src) + staticOverlay.override = 1 + staticOverlays["static"] = staticOverlay + + staticOverlay = image(icon('icons/effects/effects.dmi', "blank"), loc = src) + staticOverlay.override = 1 + staticOverlays["blank"] = staticOverlay + + staticOverlay = getLetterImage(src, "H", 1) + staticOverlay.override = 1 + staticOverlays["letter"] = staticOverlay + + diff --git a/code/modules/mob/living/living.dm b/code/modules/mob/living/living.dm index 2a41fddbc2f..9dc994a1bad 100644 --- a/code/modules/mob/living/living.dm +++ b/code/modules/mob/living/living.dm @@ -8,12 +8,49 @@ Sorry Giacom. Please don't be mad :( push_mob_back(src, A.push_dir) */ + +/mob/living/New() + . = ..() + generateStaticOverlay() + if(staticOverlays.len) + for(var/mob/living/simple_animal/drone/D in player_list) + if(D && D.seeStatic) + if(D.staticChoice in staticOverlays) + D.staticOverlays |= staticOverlays[D.staticChoice] + D.client.images |= staticOverlays[D.staticChoice] + else //no choice? force static + D.staticOverlays |= staticOverlays["static"] + D.client.images |= staticOverlays["static"] + + /mob/living/Destroy() -// if(mind) -// mind.current = null - ..() + . = ..() + + for(var/mob/living/simple_animal/drone/D in player_list) + for(var/image/I in staticOverlays) + D.staticOverlays.Remove(I) + D.client.images.Remove(I) + del(I) + staticOverlays.len = 0 + del(src) + +/mob/living/proc/generateStaticOverlay() + staticOverlays.Add(list("static", "blank", "letter")) + var/image/staticOverlay = image(getStaticIcon(new/icon(icon,icon_state)), loc = src) + staticOverlay.override = 1 + staticOverlays["static"] = staticOverlay + + staticOverlay = image(getBlankIcon(new/icon(icon, icon_state)), loc = src) + staticOverlay.override = 1 + staticOverlays["blank"] = staticOverlay + + staticOverlay = getLetterImage(src) + staticOverlay.override = 1 + staticOverlays["letter"] = staticOverlay + + //Generic Bump(). Override MobBump() and ObjBump() instead of this. /mob/living/Bump(atom/A, yes) if (buckled || !yes || now_pushing) diff --git a/code/modules/mob/living/living_defines.dm b/code/modules/mob/living/living_defines.dm index c0db992236d..e1f88b45cb0 100644 --- a/code/modules/mob/living/living_defines.dm +++ b/code/modules/mob/living/living_defines.dm @@ -41,4 +41,6 @@ var/floating = 0 var/nightvision = 0 var/mob_size = 1 //size of the mob. 0 is small, 1 is human sized, and 2 is large. - var/metabolism_efficiency = 1 //more or less efficiency to metabolize helpful/harmful reagents and regulate body temperature.. \ No newline at end of file + var/metabolism_efficiency = 1 //more or less efficiency to metabolize helpful/harmful reagents and regulate body temperature.. + + var/list/image/staticOverlays = list() \ No newline at end of file diff --git a/code/modules/mob/living/simple_animal/friendly/drone.dm b/code/modules/mob/living/simple_animal/friendly/drone.dm deleted file mode 100644 index ee37b9f52a4..00000000000 --- a/code/modules/mob/living/simple_animal/friendly/drone.dm +++ /dev/null @@ -1,609 +0,0 @@ - -#define HANDS_LAYER 1 -#define HEAD_LAYER 2 -#define TOTAL_LAYERS 2 - -#define DRONE_NET_CONNECT "DRONE NETWORK: [name] connected." -#define DRONE_NET_DISCONNECT "DRONE NETWORK: [name] is not responding." - - -/mob/living/simple_animal/drone - name = "Drone" - desc = "A maintenance drone, an expendable robot built to perform station repairs." - icon = 'icons/mob/drone.dmi' - icon_state = "drone_grey" - icon_living = "drone_grey" - icon_dead = "drone_dead" - gender = NEUTER - health = 30 - maxHealth = 30 - heat_damage_per_tick = 0 - cold_damage_per_tick = 0 - unsuitable_atmos_damage = 0 - wander = 0 - speed = 0 - ventcrawler = 2 - pass_flags = PASSTABLE | PASSMOB - sight = (SEE_TURFS | SEE_OBJS) - status_flags = (CANPUSH | CANSTUN | CANWEAKEN) - gender = NEUTER - voice_name = "synthesized chirp" - languages = DRONE - mob_size = 0 - has_unlimited_silicon_privilege = 1 - var/picked = FALSE - var/list/drone_overlays[TOTAL_LAYERS] - var/laws = \ - "1. You may not involve yourself in the matters of another being, even if such matters conflict with Law Two or Law Three, unless the other being is another Drone.\n"+\ - "2. You may not harm any being, regardless of intent or circumstance.\n"+\ - "3. Your goals are to build, maintain, repair, improve, and power to the best of your abilities, You must never actively work against these goals." - var/light_on = 0 - var/heavy_emp_damage = 25 //Amount of damage sustained if hit by a heavy EMP pulse - var/health_repair_max = 0 //Drone will only be able to be repaired/reactivated up to this point, defaults to health - var/alarms = list("Atmosphere" = list(), "Fire" = list(), "Power" = list()) - var/obj/item/internal_storage //Drones can store one item, of any size/type in their body - var/obj/item/head - var/obj/item/default_storage = /obj/item/weapon/storage/toolbox/drone //If this exists, it will spawn in internal storage - var/obj/item/default_hatmask //If this exists, it will spawn in the hat/mask slot if it can fit - - -/mob/living/simple_animal/drone/New() - ..() - - name = name + " ([rand(100,999)])" - real_name = name - - access_card = new /obj/item/weapon/card/id(src) - var/datum/job/captain/C = new /datum/job/captain - access_card.access = C.get_access() - - if(!health_repair_max) - health_repair_max = initial(health) - - if(default_storage) - var/obj/item/I = new default_storage(src) - equip_to_slot_or_del(I, "drone_storage_slot") - if(default_hatmask) - var/obj/item/I = new default_hatmask(src) - equip_to_slot_or_del(I, slot_head) - - alert_drones(DRONE_NET_CONNECT) - -/mob/living/simple_animal/drone/attack_hand(mob/user) - if(isdrone(user)) - var/mob/living/simple_animal/drone/D = user - if(D != src) - if(stat == DEAD) - var/d_input = alert(D,"Perform which action?","Drone Interaction","Reactivate","Cannibalize","Nothing") - if(d_input) - switch(d_input) - if("Reactivate") - var/mob/dead/observer/G = get_ghost() - if(!client && (!G || !G.client)) - var/list/faux_gadgets = list("hypertext inflator","failsafe directory","DRM switch","stack initializer",\ - "anti-freeze capacitor","data stream diode","TCP bottleneck","supercharged I/O bolt",\ - "tradewind stablizer","radiated XML cable","registry fluid tank","open-source debunker") - - var/list/faux_problems = list("won't be able to tune their bootstrap projector","will constantly remix their binary pool"+\ - " even though the BMX calibrator is working","will start leaking their XSS coolant",\ - "can't tell if their ethernet detour is moving or not", "won't be able to reseed enough"+\ - " kernels to function properly","can't start their neurotube console") - - D << "You can't seem to find the [pick(faux_gadgets)]. Without it, [src] [pick(faux_problems)]." - return - D.visible_message("[D] begins to reactivate [src].") - if(do_after(user,30,needhand = 1)) - health = health_repair_max - stat = CONSCIOUS - icon_state = icon_living - dead_mob_list -= src - living_mob_list += src - D.visible_message("[D] reactivates [src]!") - alert_drones(DRONE_NET_CONNECT) - if(G) - G << "DRONE NETWORK: You were reactivated by [D]!" - else - D << "You need to remain still to reactivate [src]." - - if("Cannibalize") - if(D.health < D.maxHealth) - D.visible_message("[D] begins to cannibalize parts from [src].") - if(do_after(D, 60,5,0)) - D.visible_message("[D] repairs itself using [src]'s remains!") - D.adjustBruteLoss(-src.maxHealth) - new /obj/effect/decal/cleanable/oil/streak(get_turf(src)) - qdel(src) - else - D << "You need to remain still to cannibalize [src]." - else - D << "You're already in perfect condition!" - if("Nothing") - return - - return - - - if(ishuman(user)) - if(stat == DEAD) - ..() - return - if(user.get_active_hand()) - user << "Your hands are full." - return - src << "[user] is trying to pick you up!" - user << "You pick [src] up." - drop_l_hand() - drop_r_hand() - var/obj/item/clothing/head/drone_holder/DH = new /obj/item/clothing/head/drone_holder(src) - DH.contents += src - DH.drone = src - user.put_in_hands(DH) - src.loc = DH - return - - ..() - -/mob/living/simple_animal/drone/Destroy() - qdel(access_card) //Otherwise it ends up on the floor! - ..() - -/mob/living/simple_animal/drone/attackby(obj/item/I, mob/user, params) - if(istype(I, /obj/item/weapon/screwdriver) && stat != DEAD) - if(health < health_repair_max) - user << "You start to tighten loose screws on [src]." - if(do_after(user,80)) - health = health_repair_max - visible_message("[user] tightens [src == user ? "their" : "[src]'s"] loose screws!") - else - user << "You need to remain still to tighten [src]'s screws." - else - user << "[src]'s screws can't get any tighter!" - else - ..() - -/mob/living/simple_animal/drone/examine(mob/user) - . = ..() - if(!client && stat != DEAD) - user << "A small blue LED is blinking on and off at a steady rate." - -/mob/living/simple_animal/drone/Move() - if(pullin) - if(pulling) - pullin.icon_state = "pull" - else - pullin.icon_state = "pull0" - ..() - -/mob/living/simple_animal/drone/IsAdvancedToolUser() - return 1 - -/mob/living/simple_animal/drone/say(var/message) - return ..(message, "R") - -/mob/living/simple_animal/drone/lang_treat(atom/movable/speaker, message_langs, raw_message) //This is so drones can understand humans without being able to speak human - . = ..() - var/hear_override_langs = HUMAN - if(message_langs & hear_override_langs) - return ..(speaker, languages, raw_message) - -/mob/living/simple_animal/drone/handle_inherent_channels(message, message_mode) - if(message_mode == MODE_BINARY) - drone_chat(message) - return ITALICS | REDUCE_RANGE - else - ..() - - -/mob/living/simple_animal/drone/UnarmedAttack(atom/A, proximity) - A.attack_hand(src) - - -/mob/living/simple_animal/drone/swap_hand() - var/obj/item/held_item = get_active_hand() - if(held_item) - if(istype(held_item, /obj/item/weapon/twohanded)) - var/obj/item/weapon/twohanded/T = held_item - if(T.wielded == 1) - usr << "Your other hand is too busy holding the [T.name]." - return - - hand = !hand - if(hud_used.l_hand_hud_object && hud_used.r_hand_hud_object) - if(hand) - hud_used.l_hand_hud_object.icon_state = "hand_l_active" - hud_used.r_hand_hud_object.icon_state = "hand_r_inactive" - else - hud_used.l_hand_hud_object.icon_state = "hand_l_inactive" - hud_used.r_hand_hud_object.icon_state = "hand_r_active" - - -/mob/living/simple_animal/drone/verb/check_laws() - set category = "Drone" - set name = "Check Laws" - - src << "Drone Laws" - src << laws - -/mob/living/simple_animal/drone/verb/toggle_light() - set category = "Drone" - set name = "Toggle drone light" - if(light_on) - AddLuminosity(-4) - else - AddLuminosity(4) - - light_on = !light_on - - src << "Your light is now [light_on ? "on" : "off"]" - -/mob/living/simple_animal/drone/verb/drone_ping() - set category = "Drone" - set name = "Drone ping" - - var/alert_s = input(src,"Alert severity level","Drone ping",null) as null|anything in list("Low","Medium","High","Critical") - - var/area/A = get_area(loc) - - if(alert_s && A && stat != DEAD) - var/msg = "DRONE PING: [name]: [alert_s] priority alert in [A.name]!" - alert_drones(msg) - -/mob/living/simple_animal/drone/proc/alert_drones(msg, dead_can_hear = 0) - for(var/mob/M in player_list) - var/send_msg = 0 - - if(istype(M, /mob/living/simple_animal/drone) && M.stat != DEAD) - for(var/F in src.faction) - if(F in M.faction) - send_msg = 1 - break - else if(dead_can_hear && (M in dead_mob_list)) - send_msg = 1 - - if(send_msg) - M << msg - -/mob/living/simple_animal/drone/proc/drone_chat(msg) - var/rendered = "DRONE CHAT: [name]: [msg]" - alert_drones(rendered, 1) - -/mob/living/simple_animal/drone/Login() - ..() - update_inv_hands() - update_inv_head() - update_inv_internal_storage() - check_laws() - - if(!picked) - pick_colour() - -/mob/living/simple_animal/drone/Die() - ..() - drop_l_hand() - drop_r_hand() - if(internal_storage) - unEquip(internal_storage) - if(head) - unEquip(head) - - alert_drones(DRONE_NET_DISCONNECT) - -/mob/living/simple_animal/drone/gib() - dust() - - -/mob/living/simple_animal/drone/unEquip(obj/item/I, force) - if(..(I,force)) - update_inv_hands() - if(I == head) - head = null - update_inv_head() - if(I == internal_storage) - internal_storage = null - update_inv_internal_storage() - return 1 - return 0 - -/mob/living/simple_animal/drone/can_equip(obj/item/I, slot) - switch(slot) - if(slot_head) - if(head) - return 0 - if(!((I.slot_flags & SLOT_HEAD) || (I.slot_flags & SLOT_MASK))) - return 0 - return 1 - if("drone_storage_slot") - if(internal_storage) - return 0 - return 1 - ..() - -/mob/living/simple_animal/drone/get_item_by_slot(slot_id) - switch(slot_id) - if(slot_head) - return head - if("drone_storage_slot") - return internal_storage - ..() - -/mob/living/simple_animal/drone/equip_to_slot(obj/item/I, slot) - if(!slot) return - if(!istype(I)) return - - if(I == l_hand) - l_hand = null - else if(I == r_hand) - r_hand = null - update_inv_hands() - - I.screen_loc = null // will get moved if inventory is visible - I.loc = src - I.equipped(src, slot) - I.layer = 20 - - switch(slot) - if(slot_head) - head = I - update_inv_head() - if("drone_storage_slot") - internal_storage = I - update_inv_internal_storage() - else - src << "You are trying to equip this item to an unsupported inventory slot. Report this to a coder!" - return - -/mob/living/simple_animal/drone/stripPanelUnequip(obj/item/what, mob/who, where) - ..(what, who, where, 1) - -/mob/living/simple_animal/drone/stripPanelEquip(obj/item/what, mob/who, where) - ..(what, who, where, 1) - -/mob/living/simple_animal/drone/emp_act(severity) - Stun(5) - src << "ER@%R: MME^RY CO#RU9T! R&$b@0tin)..." - if(severity == 1) - adjustBruteLoss(heavy_emp_damage) - src << "HeAV% DA%^MMA+G TO I/O CIR!%UUT!" - - -/mob/living/simple_animal/drone/proc/triggerAlarm(var/class, area/A, var/O, var/obj/alarmsource) - if(alarmsource.z != z) - return - if(stat != DEAD) - var/list/L = src.alarms[class] - for (var/I in L) - if (I == A.name) - var/list/alarm = L[I] - var/list/sources = alarm[2] - if (!(alarmsource in sources)) - sources += alarmsource - return - L[A.name] = list(A, list(alarmsource)) - src << "--- [class] alarm detected in [A.name]!" - -/mob/living/simple_animal/drone/proc/cancelAlarm(var/class, area/A as area, obj/origin) - if(stat != DEAD) - var/list/L = alarms[class] - var/cleared = 0 - for (var/I in L) - if (I == A.name) - var/list/alarm = L[I] - var/list/srcs = alarm[2] - if (origin in srcs) - srcs -= origin - if (srcs.len == 0) - cleared = 1 - L -= I - if(cleared) - src << "--- [class] alarm in [A.name] has been cleared." - -/mob/living/simple_animal/drone/proc/pick_colour() - var/colour = input("Choose your colour!", "Colour", "grey") in list("grey", "blue", "red", "green", "pink", "orange") - icon_state = "drone_[colour]" - icon_living = "drone_[colour]" - picked = TRUE - -/mob/living/simple_animal/drone/proc/apply_overlay(cache_index) - var/image/I = drone_overlays[cache_index] - if(I) - overlays += I - -/mob/living/simple_animal/drone/proc/remove_overlay(cache_index) - if(drone_overlays[cache_index]) - overlays -= drone_overlays[cache_index] - drone_overlays[cache_index] = null - - -/mob/living/simple_animal/drone/proc/update_inv_hands() - remove_overlay(HANDS_LAYER) - var/list/hands_overlays = list() - if(r_hand) - var/r_state = r_hand.item_state - if(!r_state) - r_state = r_hand.icon_state - - hands_overlays += image("icon" = r_hand.righthand_file, "icon_state"="[r_state]", "layer"=-HANDS_LAYER) - - if(client && hud_used) - r_hand.layer = 20 - r_hand.screen_loc = ui_rhand - client.screen |= r_hand - - if(l_hand) - var/l_state = l_hand.item_state - if(!l_state) - l_state = l_hand.icon_state - - hands_overlays += image("icon" = l_hand.lefthand_file, "icon_state"="[l_state]", "layer"=-HANDS_LAYER) - - if(client && hud_used) - l_hand.layer = 20 - l_hand.screen_loc = ui_lhand - client.screen |= l_hand - - - if(hands_overlays.len) - drone_overlays[HANDS_LAYER] = hands_overlays - apply_overlay(HANDS_LAYER) - - -/mob/living/simple_animal/drone/proc/update_inv_internal_storage() - if(internal_storage && client && hud_used) - internal_storage.screen_loc = ui_drone_storage - client.screen += internal_storage - - -/mob/living/simple_animal/drone/update_inv_head() - remove_overlay(HEAD_LAYER) - - if(head) - if(client && hud_used) - head.screen_loc = ui_drone_head - client.screen += head - - - var/image/head_overlay = image("icon"='icons/mob/head.dmi', "icon_state"="[head.icon_state]", "layer"=-HEAD_LAYER) - if(istype(head, /obj/item/clothing/mask)) - head_overlay.icon = 'icons/mob/mask.dmi' - head_overlay.color = head.color - head_overlay.alpha = head.alpha - head_overlay.pixel_y = -15 - - drone_overlays[HEAD_LAYER] = head_overlay - - apply_overlay(HEAD_LAYER) - -//These procs serve as redirection so that the drone updates as expected when other things call these procs -/mob/living/simple_animal/drone/update_inv_l_hand() - update_inv_hands() - -/mob/living/simple_animal/drone/update_inv_r_hand() - update_inv_hands() - -/mob/living/simple_animal/drone/update_inv_wear_mask() - update_inv_head() - - -/mob/living/simple_animal/drone/canUseTopic() - if(stat) - return - return 1 - -/mob/living/simple_animal/drone/activate_hand(var/selhand) - - if(istext(selhand)) - selhand = lowertext(selhand) - - if(selhand == "right" || selhand == "r") - selhand = 0 - if(selhand == "left" || selhand == "l") - selhand = 1 - - if(selhand != src.hand) - swap_hand() - else - mode() - -/mob/living/simple_animal/drone/assess_threat() //Secbots won't hunt maintenance drones. - return -10 - - -#undef HANDS_LAYER -#undef HEAD_LAYER -#undef TOTAL_LAYERS - -#undef DRONE_NET_CONNECT -#undef DRONE_NET_DISCONNECT - -//DRONE SHELL -/obj/item/drone_shell - name = "drone shell" - desc = "A shell of a maintenance drone, an expendable robot built to perform station repairs." - icon = 'icons/mob/drone.dmi' - icon_state = "drone_item" - origin_tech = "programming=2;biotech=4" - var/drone_type = /mob/living/simple_animal/drone //Type of drone that will be spawned - -/obj/item/drone_shell/attack_ghost(mob/user) - if(jobban_isbanned(user,"pAI")) - return - - var/be_drone = alert("Become a drone? (Warning, You can no longer be cloned!)",,"Yes","No") - if(be_drone == "No" || gc_destroyed) - return - var/mob/living/simple_animal/drone/D = new drone_type(get_turf(loc)) - D.key = user.key - qdel(src) - - -//DRONE HOLDER - -/obj/item/clothing/head/drone_holder//Only exists in someones hand.or on their head - name = "drone (hiding)" - desc = "This drone is scared and has curled up into a ball" - icon = 'icons/mob/drone.dmi' - icon_state = "drone_item" - var/mob/living/simple_animal/drone/drone //stored drone - -/obj/item/clothing/head/drone_holder/proc/uncurl() - if(!drone) - return - - if(istype(loc, /mob/living)) - var/mob/living/L = loc - L.show_message("[drone] is trying to escape!") - if(!do_after(L, 50) || loc != L) - return - L.unEquip(src) - - contents -= drone - drone.loc = get_turf(src) - drone.reset_view() - drone.dir = SOUTH //Looks better - drone.visible_message("[drone] uncurls!") - drone = null - qdel(src) - - -/obj/item/clothing/head/drone_holder/relaymove() - uncurl() - -/obj/item/clothing/head/drone_holder/container_resist() - uncurl() - - -//More types of drones - -/mob/living/simple_animal/drone/syndrone - name = "Syndrone" - desc = "A modified maintenance drone. This one brings with it the feeling of terror." - icon_state = "drone_synd" - icon_living = "drone_synd" - picked = TRUE - health = 30 - maxHealth = 120 //If you murder other drones and cannibalize them you can get much stronger - faction = list("syndicate") - heavy_emp_damage = 10 - laws = \ - "1. Interfere.\n"+\ - "2. Kill.\n"+\ - "3. Destroy." - default_storage = /obj/item/device/radio/uplink - default_hatmask = /obj/item/clothing/head/helmet/space/hardsuit/syndi - -/mob/living/simple_animal/drone/syndrone/New() - ..() - if(internal_storage && internal_storage.hidden_uplink) - internal_storage.hidden_uplink.uses = (initial(internal_storage.hidden_uplink.uses) / 2) - internal_storage.name = "syndicate uplink" - -/mob/living/simple_animal/drone/syndrone/Login() - ..() - src << "You can kill and eat other drones to increase your health!" //Inform the evil lil guy - -/obj/item/drone_shell/syndrone - name = "syndrone shell" - desc = "A shell of a syndrone, a modified maintenance drone designed to infiltrate and annihilate." - icon_state = "syndrone_item" - drone_type = /mob/living/simple_animal/drone/syndrone - diff --git a/code/modules/mob/living/simple_animal/friendly/drone/_drone.dm b/code/modules/mob/living/simple_animal/friendly/drone/_drone.dm new file mode 100644 index 00000000000..4a003c9a72f --- /dev/null +++ b/code/modules/mob/living/simple_animal/friendly/drone/_drone.dm @@ -0,0 +1,183 @@ + +#define DRONE_HANDS_LAYER 1 +#define DRONE_HEAD_LAYER 2 +#define DRONE_TOTAL_LAYERS 2 + +#define DRONE_NET_CONNECT "DRONE NETWORK: [name] connected." +#define DRONE_NET_DISCONNECT "DRONE NETWORK: [name] is not responding." + +#define MAINTDRONE "drone_maint" +#define REPAIRDRONE "drone_repair" + +/mob/living/simple_animal/drone + name = "Drone" + desc = "A maintenance drone, an expendable robot built to perform station repairs." + icon = 'icons/mob/drone.dmi' + icon_state = "drone_maint_grey" + icon_living = "drone_maint_grey" + icon_dead = "drone_maint_dead" + gender = NEUTER + health = 30 + maxHealth = 30 + heat_damage_per_tick = 0 + cold_damage_per_tick = 0 + unsuitable_atmos_damage = 0 + wander = 0 + speed = 0 + ventcrawler = 2 + pass_flags = PASSTABLE | PASSMOB + sight = (SEE_TURFS | SEE_OBJS) + status_flags = (CANPUSH | CANSTUN | CANWEAKEN) + gender = NEUTER + voice_name = "synthesized chirp" + languages = DRONE + mob_size = 0 + has_unlimited_silicon_privilege = 1 + staticOverlays = list() + var/staticChoice = "static" + var/list/staticChoices = list("static", "blank", "letter") + var/picked = FALSE //Have we picked our visual appearence (+ colour if applicable) + var/list/drone_overlays[DRONE_TOTAL_LAYERS] + var/laws = \ + "1. You may not involve yourself in the matters of another being, even if such matters conflict with Law Two or Law Three, unless the other being is another Drone.\n"+\ + "2. You may not harm any being, regardless of intent or circumstance.\n"+\ + "3. Your goals are to build, maintain, repair, improve, and power to the best of your abilities, You must never actively work against these goals." + var/light_on = 0 + var/heavy_emp_damage = 25 //Amount of damage sustained if hit by a heavy EMP pulse + var/health_repair_max = 0 //Drone will only be able to be repaired/reactivated up to this point, defaults to health + var/alarms = list("Atmosphere" = list(), "Fire" = list(), "Power" = list()) + var/obj/item/internal_storage //Drones can store one item, of any size/type in their body + var/obj/item/head + var/obj/item/default_storage = /obj/item/weapon/storage/toolbox/drone //If this exists, it will spawn in internal storage + var/obj/item/default_hatmask //If this exists, it will spawn in the hat/mask slot if it can fit + var/seeStatic = 1 //Whether we see static instead of mobs + var/visualAppearence = MAINTDRONE //What we appear as + + +/mob/living/simple_animal/drone/New() + ..() + + name = name + " ([rand(100,999)])" + real_name = name + + access_card = new /obj/item/weapon/card/id(src) + var/datum/job/captain/C = new /datum/job/captain + access_card.access = C.get_access() + + if(!health_repair_max) + health_repair_max = initial(health) + + if(default_storage) + var/obj/item/I = new default_storage(src) + equip_to_slot_or_del(I, "drone_storage_slot") + if(default_hatmask) + var/obj/item/I = new default_hatmask(src) + equip_to_slot_or_del(I, slot_head) + + alert_drones(DRONE_NET_CONNECT) + + +/mob/living/simple_animal/drone/Destroy() + qdel(access_card) //Otherwise it ends up on the floor! + ..() + +/mob/living/simple_animal/drone/Login() + ..() + update_inv_hands() + update_inv_head() + update_inv_internal_storage() + check_laws() + + updateSeeStaticMobs() + + if(!picked) + pickVisualAppearence() + + +/mob/living/simple_animal/drone/Die() + ..() + drop_l_hand() + drop_r_hand() + if(internal_storage) + unEquip(internal_storage) + if(head) + unEquip(head) + + alert_drones(DRONE_NET_DISCONNECT) + + +/mob/living/simple_animal/drone/gib() + dust() + + +/mob/living/simple_animal/drone/examine(mob/user) + . = ..() + if(!client && stat != DEAD) + user << "A small blue LED is blinking on and off at a steady rate." + + if(stat == DEAD) + user << "The drone's LED screen shows a BSOD, Blue screen of Death!" + + +/mob/living/simple_animal/drone/Move() + if(pullin) + if(pulling) + pullin.icon_state = "pull" + else + pullin.icon_state = "pull0" + ..() + + +/mob/living/simple_animal/drone/IsAdvancedToolUser() + return 1 + + +/mob/living/simple_animal/drone/canUseTopic() + if(stat) + return + return 1 + + +/mob/living/simple_animal/drone/assess_threat() //Secbots won't hunt maintenance drones. + return -10 + + +/mob/living/simple_animal/drone/emp_act(severity) + Stun(5) + src << "ER@%R: MME^RY CO#RU9T! R&$b@0tin)..." + if(severity == 1) + adjustBruteLoss(heavy_emp_damage) + src << "HeAV% DA%^MMA+G TO I/O CIR!%UUT!" + + +/mob/living/simple_animal/drone/proc/triggerAlarm(var/class, area/A, var/O, var/obj/alarmsource) + if(alarmsource.z != z) + return + if(stat != DEAD) + var/list/L = src.alarms[class] + for (var/I in L) + if (I == A.name) + var/list/alarm = L[I] + var/list/sources = alarm[2] + if (!(alarmsource in sources)) + sources += alarmsource + return + L[A.name] = list(A, list(alarmsource)) + src << "--- [class] alarm detected in [A.name]!" + + +/mob/living/simple_animal/drone/proc/cancelAlarm(var/class, area/A as area, obj/origin) + if(stat != DEAD) + var/list/L = alarms[class] + var/cleared = 0 + for (var/I in L) + if (I == A.name) + var/list/alarm = L[I] + var/list/srcs = alarm[2] + if (origin in srcs) + srcs -= origin + if (srcs.len == 0) + cleared = 1 + L -= I + if(cleared) + src << "--- [class] alarm in [A.name] has been cleared." \ No newline at end of file diff --git a/code/modules/mob/living/simple_animal/friendly/drone/drones_as_items.dm b/code/modules/mob/living/simple_animal/friendly/drone/drones_as_items.dm new file mode 100644 index 00000000000..cd4c33c7ee1 --- /dev/null +++ b/code/modules/mob/living/simple_animal/friendly/drone/drones_as_items.dm @@ -0,0 +1,69 @@ + +/////////////////// +//DRONES AS ITEMS// +/////////////////// +//Drone shells +//Drones as hats + + +//DRONE SHELL +/obj/item/drone_shell + name = "drone shell" + desc = "A shell of a maintenance drone, an expendable robot built to perform station repairs." + icon = 'icons/mob/drone.dmi' + icon_state = "drone_maint_hat"//yes reuse the _hat state. + origin_tech = "programming=2;biotech=4" + var/drone_type = /mob/living/simple_animal/drone //Type of drone that will be spawned + +/obj/item/drone_shell/attack_ghost(mob/user) + if(jobban_isbanned(user,"pAI")) + return + + var/be_drone = alert("Become a drone? (Warning, You can no longer be cloned!)",,"Yes","No") + if(be_drone == "No" || gc_destroyed) + return + var/mob/living/simple_animal/drone/D = new drone_type(get_turf(loc)) + D.key = user.key + qdel(src) + + +//DRONE HOLDER +/obj/item/clothing/head/drone_holder//Only exists in someones hand.or on their head + name = "drone (hiding)" + desc = "This drone is scared and has curled up into a ball" + icon = 'icons/mob/drone.dmi' + icon_state = "drone_maint_hat" + var/mob/living/simple_animal/drone/drone //stored drone + +/obj/item/clothing/head/drone_holder/proc/uncurl() + if(!drone) + return + + if(istype(loc, /mob/living)) + var/mob/living/L = loc + L.show_message("[drone] is trying to escape!") + if(!do_after(L, 50) || loc != L) + return + L.unEquip(src) + + contents -= drone + drone.loc = get_turf(src) + drone.reset_view() + drone.dir = SOUTH //Looks better + drone.visible_message("[drone] uncurls!") + drone = null + qdel(src) + + +/obj/item/clothing/head/drone_holder/relaymove() + uncurl() + +/obj/item/clothing/head/drone_holder/container_resist() + uncurl() + + +/obj/item/clothing/head/drone_holder/proc/updateVisualAppearence(var/mob/living/simple_animal/drone/D) + if(!D) + return + icon_state = "[D.visualAppearence]_hat" + . = icon_state \ No newline at end of file diff --git a/code/modules/mob/living/simple_animal/friendly/drone/extra_drone_types.dm b/code/modules/mob/living/simple_animal/friendly/drone/extra_drone_types.dm new file mode 100644 index 00000000000..e17a9a0dcb0 --- /dev/null +++ b/code/modules/mob/living/simple_animal/friendly/drone/extra_drone_types.dm @@ -0,0 +1,46 @@ + +//////////////////// +//MORE DRONE TYPES// +//////////////////// +//Drones with custom laws +//Drones with custom shells +//Drones with overriden procs + + +//More types of drones +/mob/living/simple_animal/drone/syndrone + name = "Syndrone" + desc = "A modified maintenance drone. This one brings with it the feeling of terror." + icon_state = "drone_synd" + icon_living = "drone_synd" + picked = TRUE //the appearence of syndrones is static, you don't get to change it. + health = 30 + maxHealth = 120 //If you murder other drones and cannibalize them you can get much stronger + faction = list("syndicate") + heavy_emp_damage = 10 + laws = \ + "1. Interfere.\n"+\ + "2. Kill.\n"+\ + "3. Destroy." + default_storage = /obj/item/device/radio/uplink + default_hatmask = /obj/item/clothing/head/helmet/space/hardsuit/syndi + seeStatic = 0 //Our programming is superior. + + +/mob/living/simple_animal/drone/syndrone/New() + ..() + if(internal_storage && internal_storage.hidden_uplink) + internal_storage.hidden_uplink.uses = (initial(internal_storage.hidden_uplink.uses) / 2) + internal_storage.name = "syndicate uplink" + + +/mob/living/simple_animal/drone/syndrone/Login() + ..() + src << "You can kill and eat other drones to increase your health!" //Inform the evil lil guy + + +/obj/item/drone_shell/syndrone + name = "syndrone shell" + desc = "A shell of a syndrone, a modified maintenance drone designed to infiltrate and annihilate." + icon_state = "syndrone_item" + drone_type = /mob/living/simple_animal/drone/syndrone \ No newline at end of file diff --git a/code/modules/mob/living/simple_animal/friendly/drone/interaction.dm b/code/modules/mob/living/simple_animal/friendly/drone/interaction.dm new file mode 100644 index 00000000000..1a9dfb7db3e --- /dev/null +++ b/code/modules/mob/living/simple_animal/friendly/drone/interaction.dm @@ -0,0 +1,106 @@ + +///////////////////// +//DRONE INTERACTION// +///////////////////// +//How drones interact with the world +//How the world interacts with drones + + +/mob/living/simple_animal/drone/UnarmedAttack(atom/A, proximity) + A.attack_hand(src) + + +/mob/living/simple_animal/drone/attack_hand(mob/user) + if(isdrone(user)) + var/mob/living/simple_animal/drone/D = user + if(D != src) + if(stat == DEAD) + var/d_input = alert(D,"Perform which action?","Drone Interaction","Reactivate","Cannibalize","Nothing") + if(d_input) + switch(d_input) + if("Reactivate") + var/mob/dead/observer/G = get_ghost() + if(!client && (!G || !G.client)) + var/list/faux_gadgets = list("hypertext inflator","failsafe directory","DRM switch","stack initializer",\ + "anti-freeze capacitor","data stream diode","TCP bottleneck","supercharged I/O bolt",\ + "tradewind stablizer","radiated XML cable","registry fluid tank","open-source debunker") + + var/list/faux_problems = list("won't be able to tune their bootstrap projector","will constantly remix their binary pool"+\ + " even though the BMX calibrator is working","will start leaking their XSS coolant",\ + "can't tell if their ethernet detour is moving or not", "won't be able to reseed enough"+\ + " kernels to function properly","can't start their neurotube console") + + D << "You can't seem to find the [pick(faux_gadgets)]. Without it, [src] [pick(faux_problems)]." + return + D.visible_message("[D] begins to reactivate [src].") + if(do_after(user,30,needhand = 1)) + health = health_repair_max + stat = CONSCIOUS + icon_state = icon_living + dead_mob_list -= src + living_mob_list += src + D.visible_message("[D] reactivates [src]!") + alert_drones(DRONE_NET_CONNECT) + if(G) + G << "DRONE NETWORK: You were reactivated by [D]!" + else + D << "You need to remain still to reactivate [src]." + + if("Cannibalize") + if(D.health < D.maxHealth) + D.visible_message("[D] begins to cannibalize parts from [src].") + if(do_after(D, 60,5,0)) + D.visible_message("[D] repairs itself using [src]'s remains!") + D.adjustBruteLoss(-src.maxHealth) + new /obj/effect/decal/cleanable/oil/streak(get_turf(src)) + qdel(src) + else + D << "You need to remain still to cannibalize [src]." + else + D << "You're already in perfect condition!" + if("Nothing") + return + + return + + + if(ishuman(user)) + if(stat == DEAD) + ..() + return + if(user.get_active_hand()) + user << "Your hands are full." + return + src << "[user] is trying to pick you up!" + if(buckled) + user << "[src] is buckled to the [buckled.name] and cannot be picked up!" + return + user << "You pick [src] up." + drop_l_hand() + drop_r_hand() + var/obj/item/clothing/head/drone_holder/DH = new /obj/item/clothing/head/drone_holder(src) + DH.updateVisualAppearence(src) + DH.contents += src + DH.drone = src + user.put_in_hands(DH) + src.loc = DH + return + + ..() + + +/mob/living/simple_animal/drone/attackby(obj/item/I, mob/user) + if(istype(I, /obj/item/weapon/screwdriver) && stat != DEAD) + if(health < health_repair_max) + user << "You start to tighten loose screws on [src]." + if(do_after(user,80)) + health = health_repair_max + visible_message("[user] tightens [src == user ? "their" : "[src]'s"] loose screws!") + else + user << "You need to remain still to tighten [src]'s screws." + else + user << "[src]'s screws can't get any tighter!" + else + ..() + + diff --git a/code/modules/mob/living/simple_animal/friendly/drone/inventory.dm b/code/modules/mob/living/simple_animal/friendly/drone/inventory.dm new file mode 100644 index 00000000000..3ee98de3c03 --- /dev/null +++ b/code/modules/mob/living/simple_animal/friendly/drone/inventory.dm @@ -0,0 +1,115 @@ + +/////////////////// +//DRONE INVENTORY// +/////////////////// +//Drone inventory +//Drone hands + + + + +/mob/living/simple_animal/drone/activate_hand(var/selhand) + + if(istext(selhand)) + selhand = lowertext(selhand) + + if(selhand == "right" || selhand == "r") + selhand = 0 + if(selhand == "left" || selhand == "l") + selhand = 1 + + if(selhand != src.hand) + swap_hand() + else + mode() + + +/mob/living/simple_animal/drone/swap_hand() + var/obj/item/held_item = get_active_hand() + if(held_item) + if(istype(held_item, /obj/item/weapon/twohanded)) + var/obj/item/weapon/twohanded/T = held_item + if(T.wielded == 1) + usr << "Your other hand is too busy holding the [T.name]." + return + + hand = !hand + if(hud_used.l_hand_hud_object && hud_used.r_hand_hud_object) + if(hand) + hud_used.l_hand_hud_object.icon_state = "hand_l_active" + hud_used.r_hand_hud_object.icon_state = "hand_r_inactive" + else + hud_used.l_hand_hud_object.icon_state = "hand_l_inactive" + hud_used.r_hand_hud_object.icon_state = "hand_r_active" + + +/mob/living/simple_animal/drone/unEquip(obj/item/I, force) + if(..(I,force)) + update_inv_hands() + if(I == head) + head = null + update_inv_head() + if(I == internal_storage) + internal_storage = null + update_inv_internal_storage() + return 1 + return 0 + + +/mob/living/simple_animal/drone/can_equip(obj/item/I, slot) + switch(slot) + if(slot_head) + if(head) + return 0 + if(!((I.slot_flags & SLOT_HEAD) || (I.slot_flags & SLOT_MASK))) + return 0 + return 1 + if("drone_storage_slot") + if(internal_storage) + return 0 + return 1 + ..() + + +/mob/living/simple_animal/drone/get_item_by_slot(slot_id) + switch(slot_id) + if(slot_head) + return head + if("drone_storage_slot") + return internal_storage + ..() + + +/mob/living/simple_animal/drone/equip_to_slot(obj/item/I, slot) + if(!slot) return + if(!istype(I)) return + + if(I == l_hand) + l_hand = null + else if(I == r_hand) + r_hand = null + update_inv_hands() + + I.screen_loc = null // will get moved if inventory is visible + I.loc = src + I.equipped(src, slot) + I.layer = 20 + + switch(slot) + if(slot_head) + head = I + update_inv_head() + if("drone_storage_slot") + internal_storage = I + update_inv_internal_storage() + else + src << "You are trying to equip this item to an unsupported inventory slot. Report this to a coder!" + return + + +/mob/living/simple_animal/drone/stripPanelUnequip(obj/item/what, mob/who, where) + ..(what, who, where, 1) + + +/mob/living/simple_animal/drone/stripPanelEquip(obj/item/what, mob/who, where) + ..(what, who, where, 1) \ No newline at end of file diff --git a/code/modules/mob/living/simple_animal/friendly/drone/say.dm b/code/modules/mob/living/simple_animal/friendly/drone/say.dm new file mode 100644 index 00000000000..15dc76f9e16 --- /dev/null +++ b/code/modules/mob/living/simple_animal/friendly/drone/say.dm @@ -0,0 +1,46 @@ + +///////////// +//DRONE SAY// +///////////// +//Drone speach +//Drone hearing + + +/mob/living/simple_animal/drone/say(var/message) + return ..(message, "R") + + +/mob/living/simple_animal/drone/lang_treat(atom/movable/speaker, message_langs, raw_message) //This is so drones can understand humans without being able to speak human + . = ..() + var/hear_override_langs = HUMAN + if(message_langs & hear_override_langs) + return ..(speaker, languages, raw_message) + + +/mob/living/simple_animal/drone/handle_inherent_channels(message, message_mode) + if(message_mode == MODE_BINARY) + drone_chat(message) + return ITALICS | REDUCE_RANGE + else + ..() + + +/mob/living/simple_animal/drone/proc/alert_drones(msg, dead_can_hear = 0) + for(var/mob/M in player_list) + var/send_msg = 0 + + if(istype(M, /mob/living/simple_animal/drone) && M.stat != DEAD) + for(var/F in src.faction) + if(F in M.faction) + send_msg = 1 + break + else if(dead_can_hear && (M in dead_mob_list)) + send_msg = 1 + + if(send_msg) + M << msg + + +/mob/living/simple_animal/drone/proc/drone_chat(msg) + var/rendered = "DRONE CHAT: [name]: [msg]" + alert_drones(rendered, 1) \ No newline at end of file diff --git a/code/modules/mob/living/simple_animal/friendly/drone/verbs.dm b/code/modules/mob/living/simple_animal/friendly/drone/verbs.dm new file mode 100644 index 00000000000..cd5f65f9274 --- /dev/null +++ b/code/modules/mob/living/simple_animal/friendly/drone/verbs.dm @@ -0,0 +1,53 @@ + +/////////////// +//DRONE VERBS// +/////////////// +//Drone verbs that appear in the Drone tab and on buttons + + +/mob/living/simple_animal/drone/verb/check_laws() + set category = "Drone" + set name = "Check Laws" + + src << "Drone Laws" + src << laws + +/mob/living/simple_animal/drone/verb/toggle_light() + set category = "Drone" + set name = "Toggle drone light" + if(light_on) + AddLuminosity(-4) + else + AddLuminosity(4) + + light_on = !light_on + + src << "Your light is now [light_on ? "on" : "off"]" + +/mob/living/simple_animal/drone/verb/drone_ping() + set category = "Drone" + set name = "Drone ping" + + var/alert_s = input(src,"Alert severity level","Drone ping",null) as null|anything in list("Low","Medium","High","Critical") + + var/area/A = get_area(loc) + + if(alert_s && A && stat != DEAD) + var/msg = "DRONE PING: [name]: [alert_s] priority alert in [A.name]!" + alert_drones(msg) + + +/mob/living/simple_animal/drone/verb/toggle_statics() + set name = "Change Vision Filter" + set desc = "Change the filter on the system used to remove non drone beings from your viewscreen." + set category = "Drone" + + if(!seeStatic) + src << "You have no vision filter to change!" + return + + var/selectedStatic = input("Select a vision filter", "Vision Filter") as null|anything in staticChoices + if(selectedStatic in staticChoices) + staticChoice = selectedStatic + + updateSeeStaticMobs() \ No newline at end of file diff --git a/code/modules/mob/living/simple_animal/friendly/drone/visuals_icons.dm b/code/modules/mob/living/simple_animal/friendly/drone/visuals_icons.dm new file mode 100644 index 00000000000..5496f5f853d --- /dev/null +++ b/code/modules/mob/living/simple_animal/friendly/drone/visuals_icons.dm @@ -0,0 +1,159 @@ + +///////////////// +//DRONE VISUALS// +///////////////// +//Drone overlays +//Drone visuals + + +/mob/living/simple_animal/drone/proc/apply_overlay(cache_index) + var/image/I = drone_overlays[cache_index] + if(I) + overlays += I + + +/mob/living/simple_animal/drone/proc/remove_overlay(cache_index) + if(drone_overlays[cache_index]) + overlays -= drone_overlays[cache_index] + drone_overlays[cache_index] = null + + +/mob/living/simple_animal/drone/proc/update_inv_hands() + remove_overlay(DRONE_HANDS_LAYER) + var/list/hands_overlays = list() + + var/y_shift = getItemPixelShiftY() + + if(r_hand) + var/r_state = r_hand.item_state + if(!r_state) + r_state = r_hand.icon_state + + var/image/r_hand_image = image("icon" = r_hand.righthand_file, "icon_state"="[r_state]", "layer"=-DRONE_HANDS_LAYER) + if(y_shift != 0) + r_hand_image.pixel_y = y_shift + + hands_overlays += r_hand_image + + if(client && hud_used) + r_hand.layer = 20 + r_hand.screen_loc = ui_rhand + client.screen |= r_hand + + if(l_hand) + var/l_state = l_hand.item_state + if(!l_state) + l_state = l_hand.icon_state + + var/image/l_hand_image = image("icon" = l_hand.lefthand_file, "icon_state"="[l_state]", "layer"=-DRONE_HANDS_LAYER) + if(y_shift != 0) + l_hand_image.pixel_y = y_shift + + hands_overlays += l_hand_image + + if(client && hud_used) + l_hand.layer = 20 + l_hand.screen_loc = ui_lhand + client.screen |= l_hand + + + if(hands_overlays.len) + drone_overlays[DRONE_HANDS_LAYER] = hands_overlays + apply_overlay(DRONE_HANDS_LAYER) + + +/mob/living/simple_animal/drone/proc/update_inv_internal_storage() + if(internal_storage && client && hud_used) + internal_storage.screen_loc = ui_drone_storage + client.screen += internal_storage + + +/mob/living/simple_animal/drone/update_inv_head() + remove_overlay(DRONE_HEAD_LAYER) + + if(head) + if(client && hud_used) + head.screen_loc = ui_drone_head + client.screen += head + + + var/image/head_overlay = image("icon"='icons/mob/head.dmi', "icon_state"="[head.icon_state]", "layer"=-DRONE_HEAD_LAYER) + if(istype(head, /obj/item/clothing/mask)) + head_overlay.icon = 'icons/mob/mask.dmi' + head_overlay.color = head.color + head_overlay.alpha = head.alpha + head_overlay.pixel_y = -15 + + drone_overlays[DRONE_HEAD_LAYER] = head_overlay + + apply_overlay(DRONE_HEAD_LAYER) + + +//These procs serve as redirection so that the drone updates as expected when other things call these procs +/mob/living/simple_animal/drone/update_inv_l_hand() + update_inv_hands() + + +/mob/living/simple_animal/drone/update_inv_r_hand() + update_inv_hands() + + +/mob/living/simple_animal/drone/update_inv_wear_mask() + update_inv_head() + + +/mob/living/simple_animal/drone/proc/pickVisualAppearence() + picked = FALSE + var/appearence = input("Choose your appearence!", "Appearence", "Maintenance Drone") in list("Maintenance Drone", "Repair Drone") + switch(appearence) + if("Maintenance Drone") + visualAppearence = MAINTDRONE + var/colour = input("Choose your colour!", "Colour", "grey") in list("grey", "blue", "red", "green", "pink", "orange") + icon_state = "[visualAppearence]_[colour]" + icon_living = "[visualAppearence]_[colour]" + icon_dead = "[visualAppearence]_dead" + + if("Repair Drone") + visualAppearence = REPAIRDRONE + icon_state = visualAppearence + icon_living = visualAppearence + icon_dead = "[visualAppearence]_dead" + + else + return + + picked = TRUE + + + +/mob/living/simple_animal/drone/proc/getItemPixelShiftY() + switch(visualAppearence) + if(MAINTDRONE) + . = 0 + if(REPAIRDRONE) + . = -6 + +/mob/living/simple_animal/drone/proc/updateSeeStaticMobs() + if(!client) + return + + for(var/i in staticOverlays) + client.images.Remove(i) + staticOverlays.Remove(i) + staticOverlays.len = 0 + + if(seeStatic) + for(var/mob/living/L in mob_list) + if(isdrone(L)) + continue + var/image/chosen + if(staticChoice in L.staticOverlays) + chosen = L.staticOverlays[staticChoice] + else + chosen = L.staticOverlays["static"] + staticOverlays |= chosen + client.images |= chosen + + +/mob/living/simple_animal/drone/generateStaticOverlay() + return \ No newline at end of file diff --git a/html/changelogs/RemieRichards-PR-7844.yml b/html/changelogs/RemieRichards-PR-7844.yml new file mode 100644 index 00000000000..6f275409bc7 --- /dev/null +++ b/html/changelogs/RemieRichards-PR-7844.yml @@ -0,0 +1,12 @@ +author: RemieRichards + +delete-after: True + + - rscadd: "Drones now see either Static, Black icons or Roguelike style lettering instead of actual mob icons" + - rscadd: "Icons for the above, from VG's SkowronX" + - rscadd: "Many icon procs for the above, from VG's ComicIronic" + - rscadd: "Drones moved into their own folder" + - tweak: "Drone.dm replaced with seperate files for each functionality" + - rscadd: "Drones now have 2 skins to choose from, Maintenance Drone (Current drones) and Repair Drone (A modified VG/Bay sprite)" + - rscadd: "Much more support for alternate skins on drones" + \ No newline at end of file diff --git a/icons/effects/effects.dmi b/icons/effects/effects.dmi index f1a60e810d8..14a4b7f8fef 100644 Binary files a/icons/effects/effects.dmi and b/icons/effects/effects.dmi differ diff --git a/icons/mob/drone.dmi b/icons/mob/drone.dmi index 0a8a3f70a4a..003750d8d89 100644 Binary files a/icons/mob/drone.dmi and b/icons/mob/drone.dmi differ diff --git a/icons/mob/head.dmi b/icons/mob/head.dmi index 65884b15b23..08f10c0d0bb 100644 Binary files a/icons/mob/head.dmi and b/icons/mob/head.dmi differ diff --git a/tgstation.dme b/tgstation.dme index 08724346457..38a63b2e57d 100644 --- a/tgstation.dme +++ b/tgstation.dme @@ -1180,13 +1180,20 @@ #include "code\modules\mob\living\simple_animal\friendly\cat.dm" #include "code\modules\mob\living\simple_animal\friendly\corgi.dm" #include "code\modules\mob\living\simple_animal\friendly\crab.dm" -#include "code\modules\mob\living\simple_animal\friendly\drone.dm" #include "code\modules\mob\living\simple_animal\friendly\farm_animals.dm" #include "code\modules\mob\living\simple_animal\friendly\fox.dm" #include "code\modules\mob\living\simple_animal\friendly\lizard.dm" #include "code\modules\mob\living\simple_animal\friendly\mouse.dm" #include "code\modules\mob\living\simple_animal\friendly\pug.dm" #include "code\modules\mob\living\simple_animal\friendly\slime.dm" +#include "code\modules\mob\living\simple_animal\friendly\drone\_drone.dm" +#include "code\modules\mob\living\simple_animal\friendly\drone\drones_as_items.dm" +#include "code\modules\mob\living\simple_animal\friendly\drone\extra_drone_types.dm" +#include "code\modules\mob\living\simple_animal\friendly\drone\interaction.dm" +#include "code\modules\mob\living\simple_animal\friendly\drone\inventory.dm" +#include "code\modules\mob\living\simple_animal\friendly\drone\say.dm" +#include "code\modules\mob\living\simple_animal\friendly\drone\verbs.dm" +#include "code\modules\mob\living\simple_animal\friendly\drone\visuals_icons.dm" #include "code\modules\mob\living\simple_animal\hostile\alien.dm" #include "code\modules\mob\living\simple_animal\hostile\bear.dm" #include "code\modules\mob\living\simple_animal\hostile\bees.dm"