diff --git a/code/_onclick/ai.dm b/code/_onclick/ai.dm
index 4dee15388de..dfb6de5e911 100644
--- a/code/_onclick/ai.dm
+++ b/code/_onclick/ai.dm
@@ -31,7 +31,7 @@
build_click(src, client.buildmode, params, A)
return
- if(control_disabled || stat)
+ if(stat)
return
var/list/modifiers = params2list(params)
@@ -51,7 +51,7 @@
CtrlClickOn(A)
return
- if(!canClick())
+ if(control_disabled || !canClick())
return
if(aiCamera.in_camera_mode)
@@ -89,13 +89,24 @@
*/
/mob/living/silicon/ai/ShiftClickOn(var/atom/A)
- A.AIShiftClick(src)
+ if(!control_disabled && A.AIShiftClick(src))
+ return
+ ..()
+
/mob/living/silicon/ai/CtrlClickOn(var/atom/A)
- A.AICtrlClick(src)
+ if(!control_disabled && A.AICtrlClick(src))
+ return
+ ..()
+
/mob/living/silicon/ai/AltClickOn(var/atom/A)
- A.AIAltClick(src)
+ if(!control_disabled && A.AIAltClick(src))
+ return
+ ..()
+
/mob/living/silicon/ai/MiddleClickOn(var/atom/A)
- A.AIMiddleClick(src)
+ if(!control_disabled && A.AIMiddleClick(src))
+ return
+ ..()
/*
The following criminally helpful code is just the previous code cleaned up;
@@ -105,11 +116,6 @@
/atom/proc/AICtrlShiftClick()
return
-/obj/machinery/door/airlock/AICtrlShiftClick()
- if(emagged)
- return
- return
-
/atom/proc/AIShiftClick()
return
@@ -118,7 +124,7 @@
Topic(src, list("src"= "\ref[src]", "command"="open", "activate" = "1"), 1) // 1 meaning no window (consistency!)
else
Topic(src, list("src"= "\ref[src]", "command"="open", "activate" = "0"), 1)
- return
+ return 1
/atom/proc/AICtrlClick()
return
@@ -128,15 +134,18 @@
Topic(src, list("src"= "\ref[src]", "command"="bolts", "activate" = "0"), 1)// 1 meaning no window (consistency!)
else
Topic(src, list("src"= "\ref[src]", "command"="bolts", "activate" = "1"), 1)
+ return 1
/obj/machinery/power/apc/AICtrlClick() // turns off/on APCs.
Topic(src, list("src"= "\ref[src]", "breaker"="1"), 1) // 1 meaning no window (consistency!)
+ return 1
/obj/machinery/turretid/AICtrlClick() //turns off/on Turrets
Topic(src, list("src"= "\ref[src]", "command"="enable", "value"="[!enabled]"), 1) // 1 meaning no window (consistency!)
+ return 1
/atom/proc/AIAltClick(var/atom/A)
- AltClick(A)
+ return AltClick(A)
/obj/machinery/door/airlock/AIAltClick() // Electrifies doors.
if(!electrified_until)
@@ -145,20 +154,25 @@
else
// disable/6 is not in Topic; disable/5 disables both temporary and permanent shock
Topic(src, list("src"= "\ref[src]", "command"="electrify_permanently", "activate" = "0"), 1)
- return
+ return 1
/obj/machinery/turretid/AIAltClick() //toggles lethal on turrets
Topic(src, list("src"= "\ref[src]", "command"="lethal", "value"="[!lethal]"), 1) // 1 meaning no window (consistency!)
+ return 1
-/atom/proc/AIMiddleClick()
- return
+/atom/proc/AIMiddleClick(var/mob/living/silicon/user)
+ return 0
/obj/machinery/door/airlock/AIMiddleClick() // Toggles door bolt lights.
+
+ if(..())
+ return
+
if(!src.lights)
Topic(src, list("src"= "\ref[src]", "command"="lights", "activate" = "1"), 1) // 1 meaning no window (consistency!)
else
Topic(src, list("src"= "\ref[src]", "command"="lights", "activate" = "0"), 1)
- return
+ return 1
//
// Override AdjacentQuick for AltClicking
diff --git a/code/_onclick/click.dm b/code/_onclick/click.dm
index 5a4ce2bb8ed..2261ceb3683 100644
--- a/code/_onclick/click.dm
+++ b/code/_onclick/click.dm
@@ -108,7 +108,7 @@
// faster access to objects already on you
if(A.loc != src)
setMoveCooldown(10) //getting something out of a backpack
-
+
if(W)
var/resolved = W.resolve_attackby(A, src)
if(!resolved && A && W)
@@ -128,7 +128,7 @@
if(isturf(A) || isturf(A.loc) || (sdepth != -1 && sdepth <= 1))
if(A.Adjacent(src)) // see adjacent.dm
setMoveCooldown(5)
-
+
if(W)
// Return 1 in attackby() to prevent afterattack() effects (when safely moving items for example)
var/resolved = W.resolve_attackby(A,src)
@@ -224,10 +224,8 @@
Only used for swapping hands
*/
/mob/proc/MiddleClickOn(var/atom/A)
- return
-
-/mob/living/carbon/MiddleClickOn(var/atom/A)
swap_hand()
+ return
// In case of use break glass
/*
@@ -278,7 +276,7 @@
else
user.listed_turf = T
user.client.statpanel = T.name
- return
+ return 1
/mob/proc/TurfAdjacent(var/turf/T)
return T.AdjacentQuick(src)
diff --git a/code/_onclick/rig.dm b/code/_onclick/rig.dm
index 600d8c56193..436e7353ec7 100644
--- a/code/_onclick/rig.dm
+++ b/code/_onclick/rig.dm
@@ -29,34 +29,53 @@
src << "Somehow you bugged the system. Setting your hardsuit mode to middle-click."
hardsuit_click_mode = MIDDLE_CLICK
-/mob/living/carbon/human/MiddleClickOn(atom/A)
+/mob/living/MiddleClickOn(atom/A)
if(client && client.hardsuit_click_mode == MIDDLE_CLICK)
if(HardsuitClickOn(A))
return
..()
-/mob/living/carbon/human/AltClickOn(atom/A)
+/mob/living/AltClickOn(atom/A)
if(client && client.hardsuit_click_mode == ALT_CLICK)
if(HardsuitClickOn(A))
return
..()
-/mob/living/carbon/human/CtrlClickOn(atom/A)
+/mob/living/CtrlClickOn(atom/A)
if(client && client.hardsuit_click_mode == CTRL_CLICK)
if(HardsuitClickOn(A))
return
..()
-/mob/living/carbon/human/proc/HardsuitClickOn(atom/A)
- if(!canClick())
- return
- if(back)
- var/obj/item/weapon/rig/rig = back
- if(istype(rig) && rig.selected_module)
- rig.selected_module.engage(A)
- if(ismob(A)) // No instant mob attacking - though modules have their own cooldowns
- setClickCooldown(DEFAULT_ATTACK_COOLDOWN)
- return 1
+/mob/living/proc/can_use_rig()
+ return 0
+
+/mob/living/carbon/human/can_use_rig()
+ return 1
+
+/mob/living/carbon/brain/can_use_rig()
+ return istype(loc, /obj/item/device/mmi)
+
+/mob/living/silicon/ai/can_use_rig()
+ return carded
+
+/mob/living/silicon/pai/can_use_rig()
+ return loc == card
+
+/mob/living/proc/HardsuitClickOn(var/atom/A, var/alert_ai = 0)
+ if(!can_use_rig() || !canClick())
+ return 0
+ var/obj/item/weapon/rig/rig = get_rig()
+ if(istype(rig) && !rig.offline && rig.selected_module)
+ if(src != rig.wearer)
+ if(rig.ai_can_move_suit(src, check_user_module = 1))
+ message_admins("[key_name_admin(src, include_name = 1)] is trying to force \the [key_name_admin(rig.wearer, include_name = 1)] to use a hardsuit module.")
+ else
+ return 0
+ rig.selected_module.engage(A, alert_ai)
+ if(ismob(A)) // No instant mob attacking - though modules have their own cooldowns
+ setClickCooldown(DEFAULT_ATTACK_COOLDOWN)
+ return 1
return 0
#undef MIDDLE_CLICK
diff --git a/code/game/objects/items/devices/aicard.dm b/code/game/objects/items/devices/aicard.dm
index 577ee1010bf..356ee87f609 100644
--- a/code/game/objects/items/devices/aicard.dm
+++ b/code/game/objects/items/devices/aicard.dm
@@ -105,12 +105,13 @@
if(istype(ai.loc, /turf/))
new /obj/structure/AIcore/deactivated(get_turf(ai))
+ ai.carded = 1
admin_attack_log(user, ai, "Carded with [src.name]", "Was carded with [src.name]", "used the [src.name] to card")
src.name = "[initial(name)] - [ai.name]"
ai.loc = src
- ai.cancel_camera()
ai.destroy_eyeobj(src)
+ ai.cancel_camera()
ai.control_disabled = 1
ai.aiRestorePowerRoutine = 0
carded_ai = ai
@@ -120,10 +121,14 @@
if(user.client)
user << "Transfer successful: [ai.name] ([rand(1000,9999)].exe) removed from host terminal and stored within local memory."
+ ai.canmove = 1
update_icon()
return 1
/obj/item/device/aicard/proc/clear()
+ if(carded_ai && istype(carded_ai.loc, /turf))
+ carded_ai.canmove = 0
+ carded_ai.carded = 0
name = initial(name)
carded_ai = null
update_icon()
@@ -140,10 +145,9 @@
carded_ai.show_message(rendered, type)
..()
-/*
/obj/item/device/aicard/relaymove(var/mob/user, var/direction)
- if(src.loc && istype(src.loc.loc, /obj/item/rig_module))
- var/obj/item/rig_module/module = src.loc.loc
- if(!module.holder || !direction)
- return
- module.holder.forced_move(direction)*/
+ if(user.stat || user.stunned)
+ return
+ var/obj/item/weapon/rig/rig = src.get_rig()
+ if(istype(rig))
+ rig.forced_move(direction, user)
diff --git a/code/game/objects/items/devices/paicard.dm b/code/game/objects/items/devices/paicard.dm
index f7fa46678b0..685f2a90431 100644
--- a/code/game/objects/items/devices/paicard.dm
+++ b/code/game/objects/items/devices/paicard.dm
@@ -10,12 +10,12 @@
var/looking_for_personality = 0
var/mob/living/silicon/pai/pai
-/*/obj/item/device/paicard/relaymove(var/mob/user, var/direction)
- if(src.loc && istype(src.loc.loc, /obj/item/rig_module))
- var/obj/item/rig_module/module = src.loc.loc
- if(!module.holder || !direction)
- return
- module.holder.forced_move(direction)*/
+/obj/item/device/paicard/relaymove(var/mob/user, var/direction)
+ if(user.stat || user.stunned)
+ return
+ var/obj/item/weapon/rig/rig = src.get_rig()
+ if(istype(rig))
+ rig.forced_move(direction, user)
/obj/item/device/paicard/New()
..()
diff --git a/code/modules/clothing/spacesuits/rig/modules/ninja.dm b/code/modules/clothing/spacesuits/rig/modules/ninja.dm
index 6b1362a7666..778c30dedea 100644
--- a/code/modules/clothing/spacesuits/rig/modules/ninja.dm
+++ b/code/modules/clothing/spacesuits/rig/modules/ninja.dm
@@ -95,7 +95,7 @@
playsound(T, "sparks", 50, 1)
anim(T,M,'icons/mob/mob.dmi',,"phaseout",,M.dir)
-/obj/item/rig_module/teleporter/engage(atom/target)
+/obj/item/rig_module/teleporter/engage(var/atom/target, var/notify_ai)
if(!..()) return 0
diff --git a/code/modules/clothing/spacesuits/rig/rig.dm b/code/modules/clothing/spacesuits/rig/rig.dm
index d2412dd6c8f..60a4c5ce24d 100644
--- a/code/modules/clothing/spacesuits/rig/rig.dm
+++ b/code/modules/clothing/spacesuits/rig/rig.dm
@@ -27,6 +27,8 @@
var/interface_path = "hardsuit.tmpl"
var/ai_interface_path = "hardsuit.tmpl"
var/interface_title = "Hardsuit Controller"
+ var/wearer_move_delay //Used for AI moving.
+ var/ai_controlled_move_delay = 10
// Keeps track of what this rig should spawn with.
var/suit_type = "hardsuit"
@@ -179,8 +181,8 @@
for(var/obj/item/piece in list(helmet,boots,gloves,chest))
if(!piece) continue
piece.icon_state = "[initial(icon_state)]"
- if(airtight)
- piece.item_flags &= ~(STOPPRESSUREDAMAGE|AIRTIGHT)
+ if(airtight)
+ piece.item_flags &= ~(STOPPRESSUREDAMAGE|AIRTIGHT)
update_icon(1)
/obj/item/weapon/rig/proc/toggle_seals(var/mob/living/carbon/human/M,var/instant)
@@ -268,9 +270,9 @@
for(var/obj/item/piece in list(helmet,boots,gloves,chest))
if(!piece) continue
piece.icon_state = "[initial(icon_state)][!seal_target ? "" : "_sealed"]"
- canremove = !seal_target
+ canremove = !seal_target
if(airtight)
- update_component_sealed()
+ update_component_sealed()
update_icon(1)
return 0
@@ -289,9 +291,9 @@
for(var/obj/item/piece in list(helmet,boots,gloves,chest))
if(canremove)
piece.item_flags &= ~(STOPPRESSUREDAMAGE|AIRTIGHT)
- else
+ else
piece.item_flags |= (STOPPRESSUREDAMAGE|AIRTIGHT)
- update_icon(1)
+ update_icon(1)
/obj/item/weapon/rig/process()
@@ -324,6 +326,8 @@
else
if(offline)
offline = 0
+ if(istype(wearer) && !wearer.wearing_rig)
+ wearer.wearing_rig = src
chest.slowdown = initial(slowdown)
if(offline)
@@ -540,12 +544,10 @@
return 0
/obj/item/weapon/rig/proc/notify_ai(var/message)
- if(!message || !installed_modules || !installed_modules.len)
- return
- for(var/obj/item/rig_module/module in installed_modules)
- for(var/mob/living/silicon/ai/ai in module.contents)
- if(ai && ai.client && !ai.stat)
- ai << "[message]"
+ for(var/obj/item/rig_module/ai_container/module in installed_modules)
+ if(module.integrated_ai && module.integrated_ai.client && !module.integrated_ai.stat)
+ module.integrated_ai << "[message]"
+ . = 1
/obj/item/weapon/rig/equipped(mob/living/carbon/human/M)
..()
@@ -562,6 +564,7 @@
if(istype(M) && M.back == src)
M.visible_message("[M] struggles into \the [src].", "You struggle into \the [src].")
wearer = M
+ wearer.wearing_rig = src
update_icon()
/obj/item/weapon/rig/proc/toggle_piece(var/piece, var/mob/living/carbon/human/H, var/deploy_mode)
@@ -673,6 +676,7 @@
..()
for(var/piece in list("helmet","gauntlets","chest","boots"))
toggle_piece(piece, user, ONLY_RETRACT)
+ wearer.wearing_rig = null
wearer = null
//Todo
@@ -754,14 +758,128 @@
return 1
return 0
-/*/obj/item/weapon/rig/proc/forced_move(dir)
- if(locked_down)
+/obj/item/weapon/rig/proc/ai_can_move_suit(var/mob/user, var/check_user_module = 0, var/check_for_ai = 0)
+
+ if(check_for_ai)
+ if(!(locate(/obj/item/rig_module/ai_container) in contents))
+ return 0
+ var/found_ai
+ for(var/obj/item/rig_module/ai_container/module in contents)
+ if(module.damage >= 2)
+ continue
+ if(module.integrated_ai && module.integrated_ai.client && !module.integrated_ai.stat)
+ found_ai = 1
+ break
+ if(!found_ai)
+ return 0
+
+ if(check_user_module)
+ if(!user || !user.loc || !user.loc.loc)
+ return 0
+ var/obj/item/rig_module/ai_container/module = user.loc.loc
+ if(!istype(module) || module.damage >= 2)
+ user << "Your host module is unable to interface with the suit."
+ return 0
+
+ if(offline || !cell || !cell.charge || locked_down)
+ if(user) user << "Your host rig is unpowered and unresponsive."
return 0
- if(!control_overridden)
- return
if(!wearer || wearer.back != src)
+ if(user) user << "Your host rig is not being worn."
return 0
- wearer.Move(null,dir)*/
+ if(!wearer.stat && !control_overridden && !ai_override_enabled)
+ if(user) user << "You are locked out of the suit servo controller."
+ return 0
+ return 1
+
+/obj/item/weapon/rig/proc/force_rest(var/mob/user)
+ if(!ai_can_move_suit(user, check_user_module = 1))
+ return
+ wearer.lay_down()
+ user << "\The [wearer] is now [wearer.resting ? "resting" : "getting up"]."
+
+/obj/item/weapon/rig/proc/forced_move(var/direction, var/mob/user)
+
+ // Why is all this shit in client/Move()? Who knows?
+ if(world.time < wearer_move_delay)
+ return
+
+ if(!wearer || !wearer.loc || !ai_can_move_suit(user, check_user_module = 1))
+ return
+
+ //This is sota the goto stop mobs from moving var
+ if(wearer.transforming || !wearer.canmove)
+ return
+
+ if(locate(/obj/effect/stop/, wearer.loc))
+ for(var/obj/effect/stop/S in wearer.loc)
+ if(S.victim == wearer)
+ return
+
+ if(!wearer.lastarea)
+ wearer.lastarea = get_area(wearer.loc)
+
+ if((istype(wearer.loc, /turf/space)) || (wearer.lastarea.has_gravity == 0))
+ if(!wearer.Process_Spacemove(0))
+ return 0
+
+ if(malfunctioning)
+ direction = pick(cardinal)
+
+ // Inside an object, tell it we moved.
+ if(isobj(wearer.loc) || ismob(wearer.loc))
+ var/atom/O = wearer.loc
+ return O.relaymove(wearer, direction)
+
+ if(isturf(wearer.loc))
+ if(wearer.restrained())//Why being pulled while cuffed prevents you from moving
+ for(var/mob/M in range(wearer, 1))
+ if(M.pulling == wearer)
+ if(!M.restrained() && M.stat == 0 && M.canmove && wearer.Adjacent(M))
+ user << "Your host is restrained! They can't move!"
+ return 0
+ else
+ M.stop_pulling()
+
+ if(wearer.pinned.len)
+ src << "Your host is pinned to a wall by [wearer.pinned[1]]!"
+ return 0
+
+ // AIs are a bit slower than regular and ignore move intent.
+ wearer.last_move_intent = world.time + ai_controlled_move_delay
+ wearer_move_delay = world.time + ai_controlled_move_delay
+
+ var/tickcomp = 0
+ if(config.Tickcomp)
+ tickcomp = ((1/(world.tick_lag))*1.3) - 1.3
+ wearer_move_delay += tickcomp
+
+ if(istype(wearer.buckled, /obj/vehicle))
+ //manually set move_delay for vehicles so we don't inherit any mob movement penalties
+ //specific vehicle move delays are set in code\modules\vehicles\vehicle.dm
+ wearer_move_delay = world.time + tickcomp
+ return wearer.buckled.relaymove(wearer, direction)
+
+ if(istype(wearer.machine, /obj/machinery))
+ if(wearer.machine.relaymove(wearer, direction))
+ return
+
+ if(wearer.pulledby || wearer.buckled) // Wheelchair driving!
+ if(istype(wearer.loc, /turf/space))
+ return // No wheelchair driving in space
+ if(istype(wearer.pulledby, /obj/structure/bed/chair/wheelchair))
+ return wearer.pulledby.relaymove(wearer, direction)
+ else if(istype(wearer.buckled, /obj/structure/bed/chair/wheelchair))
+ if(ishuman(wearer.buckled))
+ var/obj/item/organ/external/l_hand = wearer.get_organ("l_hand")
+ var/obj/item/organ/external/r_hand = wearer.get_organ("r_hand")
+ if((!l_hand || (l_hand.status & ORGAN_DESTROYED)) && (!r_hand || (r_hand.status & ORGAN_DESTROYED)))
+ return // No hands to drive your chair? Tough luck!
+ wearer_move_delay += 2
+ return wearer.buckled.relaymove(wearer,direction)
+
+ cell.use(200) //Arbitrary, TODO
+ wearer.Move(get_step(get_turf(wearer),direction),direction)
// This returns the rig if you are contained inside one, but not if you are wearing it
/atom/proc/get_rig()
@@ -772,6 +890,9 @@
/obj/item/weapon/rig/get_rig()
return src
+/mob/living/carbon/human/get_rig()
+ return back
+
#undef ONLY_DEPLOY
#undef ONLY_RETRACT
#undef SEAL_DELAY
diff --git a/code/modules/hydroponics/trays/tray.dm b/code/modules/hydroponics/trays/tray.dm
index 4716a191b84..63c950058a6 100644
--- a/code/modules/hydroponics/trays/tray.dm
+++ b/code/modules/hydroponics/trays/tray.dm
@@ -126,7 +126,7 @@
/obj/machinery/portable_atmospherics/hydroponics/AltClick()
if(mechanical && !usr.stat && !usr.lying && Adjacent(usr))
close_lid(usr)
- return
+ return 1
return ..()
/obj/machinery/portable_atmospherics/hydroponics/attack_ghost(var/mob/dead/observer/user)
diff --git a/code/modules/mob/living/carbon/brain/MMI.dm b/code/modules/mob/living/carbon/brain/MMI.dm
index 49e8c6ad528..d9b84ea3b06 100644
--- a/code/modules/mob/living/carbon/brain/MMI.dm
+++ b/code/modules/mob/living/carbon/brain/MMI.dm
@@ -122,6 +122,13 @@
locked = 1
return
+/obj/item/device/mmi/relaymove(var/mob/user, var/direction)
+ if(user.stat || user.stunned)
+ return
+ var/obj/item/weapon/rig/rig = src.get_rig()
+ if(rig)
+ rig.forced_move(direction, user)
+
/obj/item/device/mmi/Destroy()
if(isrobot(loc))
var/mob/living/silicon/robot/borg = loc
diff --git a/code/modules/mob/living/carbon/brain/brain.dm b/code/modules/mob/living/carbon/brain/brain.dm
index e72671d78ad..aaf947a13d4 100644
--- a/code/modules/mob/living/carbon/brain/brain.dm
+++ b/code/modules/mob/living/carbon/brain/brain.dm
@@ -49,12 +49,12 @@
return 1
return ..()
-
/mob/living/carbon/brain/update_canmove()
- if(in_contents_of(/obj/mecha))
+ if(in_contents_of(/obj/mecha) || istype(loc, /obj/item/device/mmi))
canmove = 1
- use_me = 1 //If it can move, let it emote
- else canmove = 0
+ use_me = 1
+ else
+ canmove = 0
return canmove
/mob/living/carbon/brain/binarycheck()
diff --git a/code/modules/mob/living/carbon/carbon.dm b/code/modules/mob/living/carbon/carbon.dm
index 73624912ece..65927322776 100644
--- a/code/modules/mob/living/carbon/carbon.dm
+++ b/code/modules/mob/living/carbon/carbon.dm
@@ -136,8 +136,10 @@
return shock_damage
+/mob/proc/swap_hand()
+ return
-/mob/living/carbon/proc/swap_hand()
+/mob/living/carbon/swap_hand()
var/obj/item/item_in_hand = src.get_active_hand()
if(item_in_hand) //this segment checks if the item in your hand is twohanded.
if(istype(item_in_hand,/obj/item/weapon/material/twohanded))
diff --git a/code/modules/mob/living/carbon/human/death.dm b/code/modules/mob/living/carbon/human/death.dm
index 1eb0b53f04f..ff7255523d3 100644
--- a/code/modules/mob/living/carbon/human/death.dm
+++ b/code/modules/mob/living/carbon/human/death.dm
@@ -61,11 +61,13 @@
if(!gibbed && species.death_sound)
playsound(loc, species.death_sound, 80, 1, 1)
-
if(ticker && ticker.mode)
sql_report_death(src)
ticker.mode.check_win()
+ if(wearing_rig)
+ wearing_rig.notify_ai("Warning: user death event. Mobility control passed to integrated intelligence system.")
+
return ..(gibbed,species.death_message)
/mob/living/carbon/human/proc/ChangeToHusk()
diff --git a/code/modules/mob/living/carbon/human/human.dm b/code/modules/mob/living/carbon/human/human.dm
index 65d1f0fa898..3b43c16543a 100644
--- a/code/modules/mob/living/carbon/human/human.dm
+++ b/code/modules/mob/living/carbon/human/human.dm
@@ -7,6 +7,7 @@
var/list/hud_list[10]
var/embedded_flag //To check if we've need to roll for damage on movement while an item is imbedded in us.
+ var/obj/item/weapon/rig/wearing_rig // This is very not good, but it's much much better than calling get_rig() every update_canmove() call.
/mob/living/carbon/human/New(var/new_loc, var/new_species = null)
@@ -1370,6 +1371,16 @@
handle_regular_hud_updates()
/mob/living/carbon/human/Check_Shoegrip()
- if(istype(shoes, /obj/item/clothing/shoes/magboots) && (shoes.item_flags & NOSLIP)) //magboots + dense_object = no floating
+ if((shoes.item_flags & NOSLIP) && istype(shoes, /obj/item/clothing/shoes/magboots)) //magboots + dense_object = no floating
+ return 1
+ return 0
+
+/mob/living/carbon/human/can_stand_overridden()
+ if(wearing_rig && wearing_rig.ai_can_move_suit(check_for_ai = 1))
+ // Actually missing a leg will screw you up. Everything else can be compensated for.
+ for(var/limbcheck in list("l_leg","r_leg"))
+ var/obj/item/organ/affecting = get_organ(limbcheck)
+ if(!affecting)
+ return 0
return 1
return 0
diff --git a/code/modules/mob/living/carbon/human/human_damage.dm b/code/modules/mob/living/carbon/human/human_damage.dm
index efe203c51cc..575fa0c5316 100644
--- a/code/modules/mob/living/carbon/human/human_damage.dm
+++ b/code/modules/mob/living/carbon/human/human_damage.dm
@@ -144,6 +144,9 @@
/mob/living/carbon/human/Paralyse(amount)
if(HULK in mutations) return
+ // Notify our AI if they can now control the suit.
+ if(wearing_rig && !stat && paralysis < amount) //We are passing out right this second.
+ wearing_rig.notify_ai("Warning: user consciousness failure. Mobility control passed to integrated intelligence system.")
..()
/mob/living/carbon/human/getCloneLoss()
diff --git a/code/modules/mob/living/carbon/human/life.dm b/code/modules/mob/living/carbon/human/life.dm
index ca5de28d739..d160d5c5e96 100644
--- a/code/modules/mob/living/carbon/human/life.dm
+++ b/code/modules/mob/living/carbon/human/life.dm
@@ -52,6 +52,10 @@
// update the current life tick, can be used to e.g. only do something every 4 ticks
life_tick++
+ // This is not an ideal place for this but it will do for now.
+ if(wearing_rig && wearing_rig.offline)
+ wearing_rig = null
+
in_stasis = istype(loc, /obj/structure/closet/body_bag/cryobag) && loc:opened == 0
if(in_stasis) loc:used++
diff --git a/code/modules/mob/living/living.dm b/code/modules/mob/living/living.dm
index c306bacdcde..40790cd04a0 100644
--- a/code/modules/mob/living/living.dm
+++ b/code/modules/mob/living/living.dm
@@ -657,7 +657,7 @@ default behaviour is:
set category = "IC"
resting = !resting
- src << "\blue You are now [resting ? "resting" : "getting up"]"
+ src << "You are now [resting ? "resting" : "getting up"]."
/mob/living/proc/handle_ventcrawl(var/obj/machinery/atmospherics/unary/vent_pump/vent_found = null, var/ignore_items = 0) // -- TLE -- Merged by Carn
if(stat)
diff --git a/code/modules/mob/living/silicon/ai/ai.dm b/code/modules/mob/living/silicon/ai/ai.dm
index a183d49be95..8ff4a106524 100644
--- a/code/modules/mob/living/silicon/ai/ai.dm
+++ b/code/modules/mob/living/silicon/ai/ai.dm
@@ -81,7 +81,7 @@ var/list/ai_verbs_default = list(
var/datum/ai_icon/selected_sprite // The selected icon set
var/custom_sprite = 0 // Whether the selected icon is custom
-
+ var/carded
/mob/living/silicon/ai/proc/add_ai_verbs()
src.verbs |= ai_verbs_default
@@ -684,5 +684,15 @@ var/list/ai_verbs_default = list(
icon_state = selected_sprite.alive_icon
set_light(1, 1, selected_sprite.alive_light)
+// Pass lying down or getting up to our pet human, if we're in a rig.
+/mob/living/silicon/ai/lay_down()
+ set name = "Rest"
+ set category = "IC"
+
+ resting = 0
+ var/obj/item/weapon/rig/rig = src.get_rig()
+ if(rig)
+ rig.force_rest(src)
+
#undef AI_CHECK_WIRELESS
#undef AI_CHECK_RADIO
diff --git a/code/modules/mob/living/silicon/pai/pai.dm b/code/modules/mob/living/silicon/pai/pai.dm
index 4641c7d2de7..88c3e812f05 100644
--- a/code/modules/mob/living/silicon/pai/pai.dm
+++ b/code/modules/mob/living/silicon/pai/pai.dm
@@ -72,8 +72,6 @@
var/current_pda_messaging = null
/mob/living/silicon/pai/New(var/obj/item/device/paicard)
-
- canmove = 0
src.loc = paicard
card = paicard
sradio = new(src)
@@ -276,8 +274,6 @@
var/obj/item/device/pda/holder = card.loc
holder.pai = null
- canmove = 1
-
src.client.perspective = EYE_PERSPECTIVE
src.client.eye = src
src.forceMove(get_turf(card))
@@ -339,12 +335,16 @@
set name = "Rest"
set category = "IC"
+ // Pass lying down or getting up to our pet human, if we're in a rig.
if(istype(src.loc,/obj/item/device/paicard))
resting = 0
+ var/obj/item/weapon/rig/rig = src.get_rig()
+ if(istype(rig))
+ rig.force_rest(src)
else
resting = !resting
icon_state = resting ? "[chassis]_rest" : "[chassis]"
- src << "\blue You are now [resting ? "resting" : "getting up"]"
+ src << "You are now [resting ? "resting" : "getting up"]"
canmove = !resting
@@ -393,7 +393,8 @@
card.loc = get_turf(card)
src.forceMove(card)
card.forceMove(card.loc)
- canmove = 0
+ canmove = 1
+ resting = 0
icon_state = "[chassis]"
/mob/living/silicon/pai/start_pulling(var/atom/movable/AM)
diff --git a/code/modules/mob/mob.dm b/code/modules/mob/mob.dm
index 43269113d9d..a0555a003dc 100644
--- a/code/modules/mob/mob.dm
+++ b/code/modules/mob/mob.dm
@@ -692,40 +692,52 @@
if(transforming) return 0
return 1
+// Not sure what to call this. Used to check if humans are wearing an AI-controlled exosuit and hence don't need to fall over yet.
+/mob/proc/can_stand_overridden()
+ return 0
+
+/mob/proc/cannot_stand()
+ return incapacitated() || restrained() || resting || sleeping || (status_flags & FAKEDEATH)
+
//Updates canmove, lying and icons. Could perhaps do with a rename but I can't think of anything to describe it.
/mob/proc/update_canmove()
- if(istype(buckled, /obj/vehicle))
- var/obj/vehicle/V = buckled
- if(stat || weakened || paralysis || resting || sleeping || (status_flags & FAKEDEATH))
- lying = 1
- canmove = 0
- pixel_y = V.mob_offset_y - 5
- else
- if(buckled.buckle_lying != -1) lying = buckled.buckle_lying
- canmove = 1
- pixel_y = V.mob_offset_y
- else if(buckled)
- anchored = 1
- canmove = 0
- if(istype(buckled))
- if(buckled.buckle_lying != -1)
- lying = buckled.buckle_lying
- if(buckled.buckle_movable)
- anchored = 0
- canmove = 1
- else if( stat || weakened || paralysis || resting || sleeping || (status_flags & FAKEDEATH))
- lying = 1
- canmove = 0
- else if(stunned)
- canmove = 0
- else if(captured)
- anchored = 1
- canmove = 0
- lying = 0
- else
+ if(!resting && cannot_stand() && can_stand_overridden())
lying = 0
canmove = 1
+ else
+ if(istype(buckled, /obj/vehicle))
+ var/obj/vehicle/V = buckled
+ if(cannot_stand())
+ lying = 1
+ canmove = 0
+ pixel_y = V.mob_offset_y - 5
+ else
+ if(buckled.buckle_lying != -1) lying = buckled.buckle_lying
+ canmove = 1
+ pixel_y = V.mob_offset_y
+ else if(buckled)
+ anchored = 1
+ canmove = 0
+ if(istype(buckled))
+ if(buckled.buckle_lying != -1)
+ lying = buckled.buckle_lying
+ if(buckled.buckle_movable)
+ anchored = 0
+ canmove = 1
+
+ else if(cannot_stand())
+ lying = 1
+ canmove = 0
+ else if(stunned)
+ canmove = 0
+ else if(captured)
+ anchored = 1
+ canmove = 0
+ lying = 0
+ else
+ lying = 0
+ canmove = 1
if(lying)
density = 0
diff --git a/code/modules/mob/mob_movement.dm b/code/modules/mob/mob_movement.dm
index 8f0c90062b3..e0235f6d5fc 100644
--- a/code/modules/mob/mob_movement.dm
+++ b/code/modules/mob/mob_movement.dm
@@ -233,7 +233,6 @@
if(Process_Grab()) return
-
if(!mob.canmove)
return
@@ -246,7 +245,6 @@
if((istype(mob.loc, /turf/space)) || (mob.lastarea.has_gravity == 0))
if(!mob.Process_Spacemove(0)) return 0
-
if(isobj(mob.loc) || ismob(mob.loc))//Inside an object, tell it we moved
var/atom/O = mob.loc
return O.relaymove(mob, direct)
diff --git a/html/changelogs/Zuhayr-hardsuits.yml b/html/changelogs/Zuhayr-hardsuits.yml
new file mode 100644
index 00000000000..187e90e25ff
--- /dev/null
+++ b/html/changelogs/Zuhayr-hardsuits.yml
@@ -0,0 +1,4 @@
+author: Zuhayr
+delete-after: True
+changes:
+ - rscadd: "Added the ability for AIs in hardsuits to control suit modules and movement with a dead or unconcious wearer."
\ No newline at end of file