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