diff --git a/code/game/gamemodes/objective.dm b/code/game/gamemodes/objective.dm index 0b309bcc312..6a64033bd0e 100644 --- a/code/game/gamemodes/objective.dm +++ b/code/game/gamemodes/objective.dm @@ -361,6 +361,19 @@ GLOBAL_LIST(admin_objective_list) //Prefilled admin assignable objective list return FALSE return SSshuttle.emergency.is_hijacked() +/datum/objective/hijack/highlander + name="highlander hijack" + explanation_text = "Escape on the shuttle alone. Ensure that nobody else makes it out." + +/datum/objective/hijack/check_completion() + if(SSshuttle.emergency.mode != SHUTTLE_ENDGAME) + return FALSE + var/list/datum/mind/owners = get_owners() + for(var/datum/mind/M in owners) + if(!considered_alive(M, enforce_human = FALSE) || !SSshuttle.emergency.shuttle_areas[get_area(M.current)]) + return FALSE + return SSshuttle.emergency.is_hijacked(filter_by_human = FALSE) + /datum/objective/block name = "no organics on shuttle" explanation_text = "Do not allow any organic lifeforms to escape on the shuttle alive." diff --git a/code/game/objects/items/weaponry.dm b/code/game/objects/items/weaponry.dm index 46da249a9a1..af5df9d69aa 100644 --- a/code/game/objects/items/weaponry.dm +++ b/code/game/objects/items/weaponry.dm @@ -134,7 +134,7 @@ for further reading, please see: https://github.com/tgstation/tgstation/pull/301 /obj/item/claymore/highlander/attack(mob/living/target, mob/living/user) . = ..() - if(!QDELETED(target) && iscarbon(target) && target.stat == DEAD && target.mind && target.mind.special_role == "highlander") + if(!QDELETED(target) && target.stat == DEAD && target.mind && target.mind.special_role == "highlander") user.fully_heal(admin_revive = FALSE) //STEAL THE LIFE OF OUR FALLEN FOES add_notch(user) target.visible_message("[target] crumbles to dust beneath [user]'s blows!", "As you fall, your body crumbles to dust!") @@ -143,9 +143,13 @@ for further reading, please see: https://github.com/tgstation/tgstation/pull/301 /obj/item/claymore/highlander/attack_self(mob/living/user) var/closest_victim var/closest_distance = 255 - for(var/mob/living/carbon/human/H in GLOB.player_list - user) - if(H.mind.special_role == "highlander" && (!closest_victim || get_dist(user, closest_victim) < closest_distance)) - closest_victim = H + for(var/mob/living/carbon/human/scot in GLOB.player_list - user) + if(scot.mind.special_role == "highlander" && (!closest_victim || get_dist(user, closest_victim) < closest_distance)) + closest_victim = scot + for(var/mob/living/silicon/robot/siliscot in GLOB.player_list - user) + if(siliscot.mind.special_role == "highlander" && (!closest_victim || get_dist(user, closest_victim) < closest_distance)) + closest_victim = siliscot + if(!closest_victim) to_chat(user, "[src] thrums for a moment and falls dark. Perhaps there's nobody nearby.") return @@ -207,6 +211,23 @@ for further reading, please see: https://github.com/tgstation/tgstation/pull/301 name = new_name playsound(user, 'sound/items/screwdriver2.ogg', 50, TRUE) +/obj/item/claymore/highlander/robot //BLOODTHIRSTY BORGS NOW COME IN PLAID + var/mob/living/silicon/robot/robot + +/obj/item/claymore/highlander/robot/Initialize() + var/obj/item/robot_module/kiltkit = loc + robot = kiltkit.loc + if(!istype(robot)) + qdel(src) + return ..() + +/obj/item/claymore/highlander/robot/process() + if(robot && !src in robot.held_items) + robot.uneq_all() + robot.equip_module_to_slot(src, 1) + to_chat(robot, "The [src] forces itself into your primary equipment slot!") + return + /obj/item/katana name = "katana" desc = "Woefully underpowered in D20." diff --git a/code/modules/admin/verbs/onlyone.dm b/code/modules/admin/verbs/onlyone.dm index 3bbaca9529f..40d2fb9f14d 100644 --- a/code/modules/admin/verbs/onlyone.dm +++ b/code/modules/admin/verbs/onlyone.dm @@ -17,6 +17,22 @@ GLOBAL_VAR_INIT(highlander, FALSE) continue H.make_scottish() + for(var/mob/living/silicon/ai/AI in GLOB.player_list) + if(!istype(AI) || AI.stat == DEAD) + continue + if(AI.deployed_shell) + AI.deployed_shell.undeploy() + AI.change_mob_type(/mob/living/silicon/robot , null, null) + AI.gib() + + for(var/mob/living/silicon/robot/robot in GLOB.player_list) + if(!istype(robot) || robot.stat == DEAD) + continue + if(robot.shell) + robot.gib() + continue + robot.make_scottish() + message_admins("[key_name_admin(usr)] used THERE CAN BE ONLY ONE!") log_admin("[key_name(usr)] used THERE CAN BE ONLY ONE.") addtimer(CALLBACK(SSshuttle.emergency, /obj/docking_port/mobile/emergency.proc/request, null, 1), 50) @@ -29,3 +45,6 @@ GLOBAL_VAR_INIT(highlander, FALSE) /mob/living/carbon/human/proc/make_scottish() mind.add_antag_datum(/datum/antagonist/highlander) + +/mob/living/silicon/robot/proc/make_scottish() + mind.add_antag_datum(/datum/antagonist/highlander/robot) diff --git a/code/modules/antagonists/highlander/highlander.dm b/code/modules/antagonists/highlander/highlander.dm index 1d5c85d664a..8881e57057d 100644 --- a/code/modules/antagonists/highlander/highlander.dm +++ b/code/modules/antagonists/highlander/highlander.dm @@ -17,14 +17,14 @@ REMOVE_TRAIT(L, TRAIT_NODISMEMBER, "highlander") if(L.has_quirk(/datum/quirk/nonviolent)) ADD_TRAIT(L, TRAIT_PACIFISM, ROUNDSTART_TRAIT) + /datum/antagonist/highlander/proc/forge_objectives() var/datum/objective/steal/steal_objective = new steal_objective.owner = owner steal_objective.set_target(new /datum/objective_item/steal/nukedisc) objectives += steal_objective - var/datum/objective/hijack/hijack_objective = new - hijack_objective.explanation_text = "Escape on the shuttle alone. Ensure that nobody else makes it out." + var/datum/objective/hijack/highlander/hijack_objective = new hijack_objective.owner = owner objectives += hijack_objective @@ -54,7 +54,7 @@ H.regenerate_icons() H.revive(full_heal = TRUE, admin_revive = TRUE) H.equip_to_slot_or_del(new /obj/item/clothing/under/costume/kilt/highlander(H), ITEM_SLOT_ICLOTHING) - H.equip_to_slot_or_del(new /obj/item/radio/headset/heads/captain(H), ITEM_SLOT_EARS) + H.equip_to_slot_or_del(new /obj/item/radio/headset/syndicate(H), ITEM_SLOT_EARS) H.equip_to_slot_or_del(new /obj/item/clothing/head/beret/highlander(H), ITEM_SLOT_HEAD) H.equip_to_slot_or_del(new /obj/item/clothing/shoes/combat(H), ITEM_SLOT_FEET) H.equip_to_slot_or_del(new /obj/item/pinpointer/nuke(H), ITEM_SLOT_LPOCKET) @@ -81,3 +81,23 @@ antiwelder.desc = "You are unable to hold anything in this hand until you're the last one left!" antiwelder.icon_state = "bloodhand_right" H.put_in_hands(antiwelder) + +/datum/antagonist/highlander/robot + name="highlander" + +/datum/antagonist/highlander/robot/on_gain() + forge_objectives() + owner.special_role = "highlander" + give_equipment() + +/datum/antagonist/highlander/robot/give_equipment() + var/mob/living/silicon/robot/robotlander = owner.current + if(!istype(robotlander)) + return ..() + robotlander.set_connected_ai() //disconnect from prior AI, if any + robotlander.laws.clear_inherent_laws() + robotlander.laws.set_zeroth_law("THERE CAN ONLY BE ONE") + robotlander.laws.show_laws(robotlander) + robotlander.module.transform_to(/obj/item/robot_module/syndicate/kiltborg) + robotlander.place_on_head(new /obj/item/clothing/head/beret/highlander(robotlander)) + sword = locate(/obj/item/claymore/highlander/robot) in robotlander.module.basic_modules diff --git a/code/modules/mob/living/silicon/robot/inventory.dm b/code/modules/mob/living/silicon/robot/inventory.dm index d2fa26831b4..396a064bb5a 100644 --- a/code/modules/mob/living/silicon/robot/inventory.dm +++ b/code/modules/mob/living/silicon/robot/inventory.dm @@ -132,6 +132,8 @@ * * module_num - the slot number being repaired. */ /mob/living/silicon/robot/proc/break_cyborg_slot(module_num) + if(!module.breakable_modules) + return FALSE if(is_invalid_module_number(module_num, TRUE)) return FALSE @@ -184,6 +186,8 @@ * Breaks all of a cyborg's slots. */ /mob/living/silicon/robot/proc/break_all_cyborg_slots() + if(!module.breakable_modules) + return FALSE for(var/cyborg_slot in 1 to 3) break_cyborg_slot(cyborg_slot) diff --git a/code/modules/mob/living/silicon/robot/robot_defense.dm b/code/modules/mob/living/silicon/robot/robot_defense.dm index 3ec0361191e..4b42d6f3b5c 100644 --- a/code/modules/mob/living/silicon/robot/robot_defense.dm +++ b/code/modules/mob/living/silicon/robot/robot_defense.dm @@ -100,6 +100,9 @@ GLOBAL_LIST_INIT(blacklisted_borg_hats, typecacheof(list( //Hats that don't real return if(W.slot_flags & ITEM_SLOT_HEAD && hat_offset != INFINITY && user.a_intent == INTENT_HELP && !is_type_in_typecache(W, GLOB.blacklisted_borg_hats)) + if(HAS_TRAIT(hat, TRAIT_NODROP)) + to_chat(user, "You can't seem to remove [src]'s existing headwear!") + return to_chat(user, "You begin to place [W] on [src]'s head...") to_chat(src, "[user] is placing [W] on your head...") if(do_after(user, 30, target = src)) diff --git a/code/modules/mob/living/silicon/robot/robot_modules.dm b/code/modules/mob/living/silicon/robot/robot_modules.dm index 151e40a593e..3f2e3b71379 100644 --- a/code/modules/mob/living/silicon/robot/robot_modules.dm +++ b/code/modules/mob/living/silicon/robot/robot_modules.dm @@ -24,6 +24,8 @@ var/can_be_pushed = TRUE var/magpulsing = FALSE var/clean_on_move = FALSE + var/breakable_modules = TRUE //Whether the borg loses tool slots with damage. + var/locked_transform = TRUE //Whether swapping to this module should lockcharge the borg var/did_feedback = FALSE @@ -217,14 +219,14 @@ sleep(1) flick("[cyborg_base_icon]_transform", R) R.notransform = TRUE - R.SetLockdown(1) - R.set_anchored(TRUE) + if(locked_transform) + R.SetLockdown(TRUE) + R.set_anchored(TRUE) sleep(1) for(var/i in 1 to 4) playsound(R, pick('sound/items/drill_use.ogg', 'sound/items/jaws_cut.ogg', 'sound/items/jaws_pry.ogg', 'sound/items/welder.ogg', 'sound/items/ratchet.ogg'), 80, TRUE, -1) sleep(7) - if(!prev_lockcharge) - R.SetLockdown(0) + R.SetLockdown(prev_lockcharge) R.setDir(SOUTH) R.set_anchored(FALSE) R.notransform = FALSE @@ -642,6 +644,17 @@ hat_offset = -4 canDispose = TRUE +/obj/item/robot_module/syndicate/kiltborg + name = "Highlander" + basic_modules = list( + /obj/item/claymore/highlander/robot, + /obj/item/pinpointer/nuke,) + moduleselect_icon = "kilt" + cyborg_base_icon = "kilt" + hat_offset = -2 + breakable_modules = FALSE + locked_transform = FALSE //GO GO QUICKLY AND SLAUGHTER THEM ALL + /datum/robot_energy_storage var/name = "Generic energy storage" var/max_energy = 30000 diff --git a/code/modules/shuttle/emergency.dm b/code/modules/shuttle/emergency.dm index 781675858cc..3f90b93dff9 100644 --- a/code/modules/shuttle/emergency.dm +++ b/code/modules/shuttle/emergency.dm @@ -260,15 +260,15 @@ SSshuttle.emergencyLastCallLoc = null priority_announce("The emergency shuttle has been recalled.[SSshuttle.emergencyLastCallLoc ? " Recall signal traced. Results can be viewed on any communications console." : "" ]", null, 'sound/ai/shuttlerecalled.ogg', "Priority") -/obj/docking_port/mobile/emergency/proc/is_hijacked() +/obj/docking_port/mobile/emergency/proc/is_hijacked(filter_by_human = TRUE) var/has_people = FALSE var/hijacker_present = FALSE for(var/mob/living/player in GLOB.player_list) if(player.mind) if(player.stat != DEAD) - if(issilicon(player)) //Borgs are technically dead anyways + if(issilicon(player) && filter_by_human) //Borgs are technically dead anyways continue - if(isanimal(player)) //animals don't count + if(isanimal(player) && filter_by_human) //animals don't count continue if(isbrain(player)) //also technically dead continue diff --git a/icons/mob/robots.dmi b/icons/mob/robots.dmi index 1ff82985af9..f8ef748273f 100644 Binary files a/icons/mob/robots.dmi and b/icons/mob/robots.dmi differ diff --git a/icons/mob/screen_cyborg.dmi b/icons/mob/screen_cyborg.dmi index c0c112bdeb9..b0e8a7b3b25 100644 Binary files a/icons/mob/screen_cyborg.dmi and b/icons/mob/screen_cyborg.dmi differ