From c172e52dce5f8aeea2ad93b1270fc25a33fdc673 Mon Sep 17 00:00:00 2001 From: supersayu Date: Wed, 28 Aug 2013 22:48:15 -0400 Subject: [PATCH] Adds telekinesis to click code. Fixes issue #1202, #1129, #247. This adds two atom procs, attack_tk() and attack_self_tk(). attack_tk is used as per attack_hand; attack_self_tk exists on all atoms (not just items) but is similar to the item proc, but without the assumption that it is in the user's hand. Removes the functionality where entering throw mode would create a tk grab, as it is redundant. As a default, attack_tk does the following: * Creates a telekinetic throw for items and un-anchored objects * Does an attack_hand (paw, animal, etc) for anchored objects * Does nothing to mobs As a default, attack_self_tk does nothing. An attack_self_tk was added to closets to open and close them since that's a common thing. The following items have added attack_tk procs: * Fire axe cabinet, extinguisher cabinet, and bedsheet bin will drop into their square instead of putting it in your hand * Doors only open telekinetically if they require no access * Chairs will rotate if nobody is buckled to them * Filing cabinets will remove a paper at random. * Tables and racks return to prevent telehulk smash This is INCOMPLETE. Adding proper TK interaction to everything is something best done in pieces. In particular, interacting with mobs and items both open up the floodgates for bugs, so we/I need to decide how we want it to go before we commit, and then fix bugs along the way. Stumbling forward, fixing bugs, and then changing course halfway would be a bad idea. --- code/_onclick/adjacent.dm | 10 +- code/_onclick/click.dm | 15 +- .../tk_grab.dm => _onclick/telekinesis.dm} | 305 ++++++++++-------- code/game/machinery/doors/door.dm | 7 + .../objects/items/weapons/storage/storage.dm | 23 +- code/game/objects/structures/bedsheet_bin.dm | 24 +- .../structures/crates_lockers/closets.dm | 14 +- .../crates_lockers/closets/fireaxe.dm | 9 + code/game/objects/structures/dresser.dm | 4 +- code/game/objects/structures/extinguisher.dm | 10 +- .../structures/stool_bed_chair_nest/chairs.dm | 6 + code/game/objects/structures/tables_racks.dm | 8 +- .../game/objects/structures/tank_dispenser.dm | 2 +- code/game/objects/structures/watercloset.dm | 6 +- code/modules/mob/living/carbon/carbon.dm | 13 - code/modules/mob/mob.dm | 3 +- code/modules/mob/mob_defines.dm | 1 - code/modules/paperwork/filingcabinet.dm | 33 +- code/modules/power/cable.dm | 2 + code/modules/power/lighting.dm | 28 +- html/changelog.html | 1 + tgstation.dme | 2 +- 22 files changed, 341 insertions(+), 185 deletions(-) rename code/{game/objects/items/tk_grab.dm => _onclick/telekinesis.dm} (64%) diff --git a/code/_onclick/adjacent.dm b/code/_onclick/adjacent.dm index cc62f701aaf..aca9b94fff2 100644 --- a/code/_onclick/adjacent.dm +++ b/code/_onclick/adjacent.dm @@ -22,8 +22,8 @@ * If you are diagonally adjacent, ensure you can pass through at least one of the mutually adjacent square. * Passing through in this case ignores anything with the throwpass flag, such as tables, racks, and morgue trays. */ -/turf/Adjacent(var/mob/user, var/atom/target = null) - var/turf/T0 = get_turf(user) +/turf/Adjacent(var/atom/neighbor, var/atom/target = null) + var/turf/T0 = get_turf(neighbor) if(T0 == src) return 1 if(get_dist(src,T0) > 1) @@ -34,7 +34,7 @@ return T0.ClickCross(get_dir(T0,src), border_only = 1) && src.ClickCross(get_dir(src,T0), border_only = 1, target_atom = target) // Not orthagonal - var/in_dir = get_dir(user,src) // eg. northwest (1+8) + var/in_dir = get_dir(neighbor,src) // eg. northwest (1+8) var/d1 = in_dir&(in_dir-1) // eg west (1+8)&(8) = 8 var/d2 = in_dir - d1 // eg north (1+8) - 8 = 1 @@ -60,11 +60,11 @@ Note: Multiple-tile objects are created when the bound_width and bound_height are creater than the tile size. This is not used in stock /tg/station currently. */ -/atom/movable/Adjacent(var/mob/user) +/atom/movable/Adjacent(var/atom/neighbor) if(!isturf(loc)) return 0 for(var/turf/T in locs) if(isnull(T)) continue - if(T.Adjacent(user,src)) return 1 + if(T.Adjacent(neighbor,src)) return 1 return 0 /* diff --git a/code/_onclick/click.dm b/code/_onclick/click.dm index fa0f562e3e9..317604cad6c 100644 --- a/code/_onclick/click.dm +++ b/code/_onclick/click.dm @@ -107,9 +107,9 @@ var/obj/item/W = get_active_hand() if(W == A) - next_move = world.time + 2 // this is to be consistent with mode(), which was previously no delay at all -// if(W.flags&USEDELAY) -// next_move += 5 + next_move = world.time + 6 + if(W.flags&USEDELAY) + next_move += 5 W.attack_self(src) if(hand) update_inv_l_hand(0) @@ -163,6 +163,15 @@ else if((LASER in mutations) && a_intent == "harm") LaserEyes(A) // moved into a proc below + else if(TK in mutations) + switch(get_dist(src,A)) + if(1 to 5) // not adjacent may mean blocked by window + next_move += 2 + if(5 to 7) + next_move += 5 + if(8 to 1024) + next_move += 10 + A.attack_tk(src) return diff --git a/code/game/objects/items/tk_grab.dm b/code/_onclick/telekinesis.dm similarity index 64% rename from code/game/objects/items/tk_grab.dm rename to code/_onclick/telekinesis.dm index 5648af6a6cb..9e48c75e00e 100644 --- a/code/game/objects/items/tk_grab.dm +++ b/code/_onclick/telekinesis.dm @@ -1,128 +1,177 @@ -//This file was auto-corrected by findeclaration.exe on 25.5.2012 20:42:32 - -/obj/item/tk_grab - name = "Telekinetic Grab" - desc = "Magic" - icon = 'icons/obj/magic.dmi'//Needs sprites - icon_state = "2" - flags = USEDELAY | NOBLUDGEON - //item_state = null - w_class = 10.0 - layer = 20 - - var/last_throw = 0 - var/obj/focus = null - var/mob/living/host = null - - - dropped(mob/user as mob) - del(src) - return - - - //stops TK grabs being equipped anywhere but into hands - equipped(var/mob/user, var/slot) - if( (slot == slot_l_hand) || (slot== slot_r_hand) ) return - del(src) - return - -/* - attack_self(mob/user as mob) - if(!istype(focus,/obj/item)) return - if(!check_path()) return//No clear path - - user.put_in_hands(focus) - add_fingerprint(user) - user.update_inv_l_hand(0) - user.update_inv_r_hand() - spawn(0) - del(src) - return -*/ - - afterattack(atom/target as mob|obj|turf|area, mob/living/user as mob|obj, flag)//TODO: go over this - if(!target || !user) return - if(last_throw+3 > world.time) return - if(!host) - del(src) - return - if(!(TK in host.mutations)) - del(src) - return - if(isobj(target)) - if(!target.loc || !isturf(target.loc)) - del(src) - return - if(!focus) - focus_object(target, user) - return - var/focusturf = get_turf(focus) - if(get_dist(focusturf, target) <= 1 && !istype(target, /turf)) - target.attackby(focus, user, user:get_organ_target()) - - else if(get_dist(focusturf, target) <= 16) - apply_focus_overlay() - focus.throw_at(target, 10, 1) - last_throw = world.time - return - - - proc/focus_object(var/obj/target, var/mob/living/user) - if(!istype(target,/obj)) return//Cant throw non objects atm might let it do mobs later - if(target.anchored) - target.attack_hand(user) // you can use shit now! - return//No throwing anchored things - if(!isturf(target.loc)) - return - focus = target - update_icon() - apply_focus_overlay() - return - - - proc/apply_focus_overlay() - if(!focus) return - var/obj/effect/overlay/O = new /obj/effect/overlay(locate(focus.x,focus.y,focus.z)) - O.name = "sparkles" - O.anchored = 1 - O.density = 0 - O.layer = FLY_LAYER - O.dir = pick(cardinal) - O.icon = 'icons/effects/effects.dmi' - O.icon_state = "nothing" - flick("empdisable",O) - spawn(5) - O.delete() - return - - - update_icon() - overlays.Cut() - if(focus && focus.icon && focus.icon_state) - overlays += icon(focus.icon,focus.icon_state) - return - -/*Not quite done likely needs to use something thats not get_step_to - proc/check_path() - var/turf/ref = get_turf(src.loc) - var/turf/target = get_turf(focus.loc) - if(!ref || !target) return 0 - var/distance = get_dist(ref, target) - if(distance >= 10) return 0 - for(var/i = 1 to distance) - ref = get_step_to(ref, target, 0) - if(ref != target) return 0 - return 1 -*/ - -//equip_to_slot_or_del(obj/item/W, slot, del_on_fail = 1) -/* - if(istype(user, /mob/living/carbon)) - if(user:mutations & TK && get_dist(source, user) <= 7) - if(user:get_active_hand()) return 0 - var/X = source:x - var/Y = source:y - var/Z = source:z - -*/ - +/* + Telekinesis + + This needs more thinking out, but I might as well. +*/ + +// click on atom with an empty hand, not Adjacent +/atom/proc/attack_tk(mob/user) + if(user.stat) return + user.UnarmedAttack(src) // attack_hand, attack_paw, etc + return + +// click on atom with itself using a tk_grab, by default do nothing +/atom/proc/attack_self_tk(mob/user) + return + +/obj/attack_tk(mob/user) + if(user.stat) return + if(anchored) + ..() + return + + var/obj/item/tk_grab/O = new(src) + user.put_in_active_hand(O) + O.host = user + O.focus_object(src) + return + +/obj/item/attack_tk(mob/user) + if(user.stat || !isturf(loc)) return + if((TK in user.mutations) && !user.get_active_hand()) // both should already be true to get here + var/obj/item/tk_grab/O = new(src) + user.put_in_active_hand(O) + O.host = user + O.focus_object(src) + else + warning("Strange attack_tk(): TK([TK in user.mutations]) empty hand([!user.get_active_hand()])") + return + + +/mob/attack_tk(mob/user) + return // needs more thinking about + + +/obj/item/tk_grab + name = "Telekinetic Grab" + desc = "Magic" + icon = 'icons/obj/magic.dmi'//Needs sprites + icon_state = "2" + flags = USEDELAY | NOBLUDGEON + //item_state = null + w_class = 10.0 + layer = 20 + + var/last_throw = 0 + var/obj/focus = null + var/mob/living/host = null + + + dropped(mob/user as mob) + if(focus && user && loc != user && loc != user.loc) // drop_item() gets called when you tk-attack a table/closet with an item + if(focus.Adjacent(loc)) + focus.loc = loc + + del(src) + return + + + //stops TK grabs being equipped anywhere but into hands + equipped(var/mob/user, var/slot) + if( (slot == slot_l_hand) || (slot== slot_r_hand) ) return + del(src) + return + + + attack_self(mob/user as mob) + if(focus) + focus.attack_self_tk(user) + + afterattack(atom/target as mob|obj|turf|area, mob/living/user as mob|obj, flag)//TODO: go over this + if(!target || !user) return + if(last_throw+3 > world.time) return + if(!host) + del(src) + return + if(!(TK in host.mutations)) + del(src) + return + if(isobj(target)) + if(!target.loc || !isturf(target.loc)) + del(src) + return + if(!focus) + focus_object(target, user) + return + + if(target == focus) + target.attack_self_tk(user) + return // todo: something like attack_self not laden with assumptions inherent to attack_self + + var/focusturf = get_turf(focus) + if(get_dist(focusturf, target) <= 1 && !istype(target, /turf)) + target.attackby(focus, user, user:get_organ_target()) + + else if(get_dist(focusturf, target) <= 16) + apply_focus_overlay() + focus.throw_at(target, 10, 1) + last_throw = world.time + return + + attack(mob/living/M as mob, mob/living/user as mob, def_zone) + if(focus && focus.Adjacent(M)) + if(istype(focus,/obj/item)) + var/obj/item/I = focus + I.attack(M,user,def_zone) + return + + + proc/focus_object(var/obj/target, var/mob/living/user) + if(!istype(target,/obj)) return//Cant throw non objects atm might let it do mobs later + if(target.anchored) + target.attack_hand(user) // you can use shit now! + return//No throwing anchored things + if(!isturf(target.loc)) + return + focus = target + update_icon() + apply_focus_overlay() + return + + + proc/apply_focus_overlay() + if(!focus) return + var/obj/effect/overlay/O = new /obj/effect/overlay(locate(focus.x,focus.y,focus.z)) + O.name = "sparkles" + O.anchored = 1 + O.density = 0 + O.layer = FLY_LAYER + O.dir = pick(cardinal) + O.icon = 'icons/effects/effects.dmi' + O.icon_state = "nothing" + flick("empdisable",O) + spawn(5) + O.delete() + return + + + update_icon() + overlays.Cut() + if(focus && focus.icon && focus.icon_state) + overlays += icon(focus.icon,focus.icon_state) + return + +/*Not quite done likely needs to use something thats not get_step_to + proc/check_path() + var/turf/ref = get_turf(src.loc) + var/turf/target = get_turf(focus.loc) + if(!ref || !target) return 0 + var/distance = get_dist(ref, target) + if(distance >= 10) return 0 + for(var/i = 1 to distance) + ref = get_step_to(ref, target, 0) + if(ref != target) return 0 + return 1 +*/ + +//equip_to_slot_or_del(obj/item/W, slot, del_on_fail = 1) +/* + if(istype(user, /mob/living/carbon)) + if(user:mutations & TK && get_dist(source, user) <= 7) + if(user:get_active_hand()) return 0 + var/X = source:x + var/Y = source:y + var/Z = source:z + +*/ + diff --git a/code/game/machinery/doors/door.dm b/code/game/machinery/doors/door.dm index 40f01898536..367eed5b3a4 100644 --- a/code/game/machinery/doors/door.dm +++ b/code/game/machinery/doors/door.dm @@ -108,11 +108,18 @@ return src.attackby(user, user) +/obj/machinery/door/attack_tk(mob/user as mob) + if(requiresID() && !allowed(null)) + return + ..() + /obj/machinery/door/attackby(obj/item/I as obj, mob/user as mob) if(istype(I, /obj/item/device/detective_scanner)) return if(src.operating || isrobot(user)) return //borgs can't attack doors open because it conflicts with their AI-like interaction with them. src.add_fingerprint(user) + if(istype(I,/obj/item/tk_grab) && !Adjacent(user)) + user = null if(!src.requiresID()) user = null if(src.density && (istype(I, /obj/item/weapon/card/emag)||istype(I, /obj/item/weapon/melee/energy/blade))) diff --git a/code/game/objects/items/weapons/storage/storage.dm b/code/game/objects/items/weapons/storage/storage.dm index f6760aafaf1..adb5bcdcb45 100644 --- a/code/game/objects/items/weapons/storage/storage.dm +++ b/code/game/objects/items/weapons/storage/storage.dm @@ -26,8 +26,17 @@ /obj/item/weapon/storage/MouseDrop(obj/over_object) if(ishuman(usr) || ismonkey(usr)) //so monkeys can take off their backpacks -- Urist var/mob/M = usr + + if(over_object == M && Adjacent(M)) // this must come before the screen objects only block + orient2hud(M) // dunno why it wasn't before + if(M.s_active) + M.s_active.close(M) + show_to(M) + return + if(!( istype(over_object, /obj/screen) )) return ..() + if(!(loc == usr) || (loc && loc.loc == usr)) return playsound(loc, "rustle", 50, 1, -5) @@ -41,10 +50,6 @@ M.put_in_l_hand(src) add_fingerprint(usr) return - if(over_object == usr && in_range(src, usr) || usr.contents.Find(src)) - if(usr.s_active) - usr.s_active.close(usr) - show_to(usr) /obj/item/weapon/storage/proc/return_inv() @@ -310,16 +315,6 @@ /obj/item/weapon/storage/dropped(mob/user) return - -/obj/item/weapon/storage/MouseDrop(over_object, src_location, over_location) - ..() - orient2hud(usr) - if((over_object == usr && (in_range(src, usr) || usr.contents.Find(src)))) - if(usr.s_active) - usr.s_active.close(usr) - show_to(usr) - - /obj/item/weapon/storage/attack_hand(mob/user) playsound(loc, "rustle", 50, 1, -5) diff --git a/code/game/objects/structures/bedsheet_bin.dm b/code/game/objects/structures/bedsheet_bin.dm index f42261cdbf6..261a6c17910 100644 --- a/code/game/objects/structures/bedsheet_bin.dm +++ b/code/game/objects/structures/bedsheet_bin.dm @@ -171,4 +171,26 @@ LINEN BINS hidden = null - add_fingerprint(user) \ No newline at end of file + add_fingerprint(user) +/obj/structure/bedsheetbin/attack_tk(mob/user as mob) + if(amount >= 1) + amount-- + + var/obj/item/weapon/bedsheet/B + if(sheets.len > 0) + B = sheets[sheets.len] + sheets.Remove(B) + + else + B = new /obj/item/weapon/bedsheet(loc) + + B.loc = loc + user << "You telekinetically remove [B] from [src]." + update_icon() + + if(hidden) + hidden.loc = loc + hidden = null + + + add_fingerprint(user) diff --git a/code/game/objects/structures/crates_lockers/closets.dm b/code/game/objects/structures/crates_lockers/closets.dm index b9ee15d2b4b..9255a83c851 100644 --- a/code/game/objects/structures/crates_lockers/closets.dm +++ b/code/game/objects/structures/crates_lockers/closets.dm @@ -177,6 +177,8 @@ src.MouseDrop_T(G.affecting, user) //act like they were dragged onto the closet else user << "The locker is too small to stuff [W] into!" + if(istype(W,/obj/item/tk_grab)) + return 0 if(istype(W, /obj/item/weapon/weldingtool)) var/obj/item/weapon/weldingtool/WT = W @@ -192,10 +194,7 @@ if(isrobot(user)) return - user.drop_item() - - if(W) - W.loc = src.loc + user.drop_item(src) else if(istype(W, /obj/item/weapon/packageWrap)) return @@ -260,6 +259,13 @@ if(!src.toggle()) usr << "It won't budge!" +// tk grab then use on self +/obj/structure/closet/attack_self_tk(mob/user as mob) + src.add_fingerprint(user) + + if(!src.toggle()) + usr << "It won't budge!" + /obj/structure/closet/verb/verb_toggleopen() set src in oview(1) set category = "Object" diff --git a/code/game/objects/structures/crates_lockers/closets/fireaxe.dm b/code/game/objects/structures/crates_lockers/closets/fireaxe.dm index dbe5bf9f10b..3219a1fe942 100644 --- a/code/game/objects/structures/crates_lockers/closets/fireaxe.dm +++ b/code/game/objects/structures/crates_lockers/closets/fireaxe.dm @@ -137,6 +137,15 @@ src.icon_state = text("fireaxe[][][][]closing",hasaxe,src.localopened,src.hitstaken,src.smashed) spawn(10) update_icon() + attack_tk(mob/user as mob) + if(localopened && fireaxe) + fireaxe.loc = loc + user << "\blue You telekinetically remove the fire axe." + fireaxe = null + update_icon() + return + attack_hand(user) + verb/toggle_openness() //nice name, huh? HUH?! -Erro //YEAH -Agouri set name = "Open/Close" set category = "Object" diff --git a/code/game/objects/structures/dresser.dm b/code/game/objects/structures/dresser.dm index 517c51a6061..5daadc94866 100644 --- a/code/game/objects/structures/dresser.dm +++ b/code/game/objects/structures/dresser.dm @@ -7,11 +7,13 @@ anchored = 1 /obj/structure/dresser/attack_hand(mob/user as mob) + if(!Adjacent(user))//no tele-grooming + return if(ishuman(user)) var/mob/living/carbon/human/H = user var/new_undies = input(user, "Select your underwear", "Changing") as null|anything in underwear_all - if(!in_range(src, user))//no tele-grooming + if(!Adjacent(user))//no tele-grooming return if(new_undies) H.underwear = new_undies diff --git a/code/game/objects/structures/extinguisher.dm b/code/game/objects/structures/extinguisher.dm index 1606d63d4ac..964f634d1f4 100644 --- a/code/game/objects/structures/extinguisher.dm +++ b/code/game/objects/structures/extinguisher.dm @@ -36,7 +36,15 @@ else opened = !opened update_icon() - +/obj/structure/extinguisher_cabinet/attack_tk(mob/user) + if(has_extinguisher) + has_extinguisher.loc = loc + user << "You telekinetically remove [has_extinguisher] from [src]." + has_extinguisher = null + opened = 1 + else + opened = !opened + update_icon() /obj/structure/extinguisher_cabinet/attack_paw(mob/user) attack_hand(user) diff --git a/code/game/objects/structures/stool_bed_chair_nest/chairs.dm b/code/game/objects/structures/stool_bed_chair_nest/chairs.dm index 4176d3cd62a..c68305a7b28 100644 --- a/code/game/objects/structures/stool_bed_chair_nest/chairs.dm +++ b/code/game/objects/structures/stool_bed_chair_nest/chairs.dm @@ -26,6 +26,12 @@ SK.loc = E SK.master = E del(src) +/obj/structure/stool/bed/chair/attack_tk(mob/user as mob) + if(buckled_mob) + ..() + else + rotate() + return /obj/structure/stool/bed/chair/proc/handle_rotation() //making this into a seperate proc so office chairs can call it on Move() if(src.dir == NORTH) diff --git a/code/game/objects/structures/tables_racks.dm b/code/game/objects/structures/tables_racks.dm index 3801eafcd69..934bbb71d6e 100644 --- a/code/game/objects/structures/tables_racks.dm +++ b/code/game/objects/structures/tables_racks.dm @@ -260,6 +260,8 @@ density = 0 del(src) +/obj/structure/table/attack_tk() // no telehulk sorry + return /obj/structure/table/CanPass(atom/movable/mover, turf/target, height=0, air_group=0) if(air_group || (height==0)) return 1 @@ -281,7 +283,7 @@ return -/obj/structure/table/attackby(obj/item/weapon/W, mob/user) +/obj/structure/table/attackby(obj/item/W, mob/user) if (istype(W, /obj/item/weapon/grab) && get_dist(src, user) < 2) var/obj/item/weapon/grab/G = W if(G.affecting.buckled) @@ -564,4 +566,6 @@ visible_message("[user] smashes [src] apart!") new /obj/item/weapon/rack_parts(loc) density = 0 - del(src) \ No newline at end of file + del(src) +/obj/structure/rack/attack_tk() // no telehulk sorry + return diff --git a/code/game/objects/structures/tank_dispenser.dm b/code/game/objects/structures/tank_dispenser.dm index 76622dcb729..67552863327 100644 --- a/code/game/objects/structures/tank_dispenser.dm +++ b/code/game/objects/structures/tank_dispenser.dm @@ -67,7 +67,7 @@ /obj/structure/dispenser/Topic(href, href_list) if(usr.stat || usr.restrained()) return - if(get_dist(src, usr) <= 1) + if(Adjacent(usr)) usr.set_machine(src) if(href_list["oxygen"]) if(oxygentanks > 0) diff --git a/code/game/objects/structures/watercloset.dm b/code/game/objects/structures/watercloset.dm index 7340d7b5569..00aa0e3d787 100644 --- a/code/game/objects/structures/watercloset.dm +++ b/code/game/objects/structures/watercloset.dm @@ -337,20 +337,20 @@ /obj/structure/sink/attack_hand(mob/user) if(isrobot(user) || isAI(user)) return + if(!Adjacent(user)) + return if(busy) user << "Someone's already washing here." return - var/turf/location = user.loc - if(!isturf(location)) return user << "You start washing your hands." busy = 1 sleep(40) busy = 0 - if(user.loc != location) return //Person has moved away from the sink + if(!Adjacent(user)) return //Person has moved away from the sink user.clean_blood() user.visible_message("[user] washes their hands in [src].") diff --git a/code/modules/mob/living/carbon/carbon.dm b/code/modules/mob/living/carbon/carbon.dm index 4b1174697d0..f0faf8f357f 100644 --- a/code/modules/mob/living/carbon/carbon.dm +++ b/code/modules/mob/living/carbon/carbon.dm @@ -319,19 +319,6 @@ //Throwing stuff /mob/living/carbon/proc/toggle_throw_mode() - var/obj/item/I = get_active_hand() - if(!I)//Not holding anything - if(client && (TK in mutations)) - var/obj/item/tk_grab/O = new(src) - put_in_active_hand(O) - O.host = src - return - - if(istype(I, /obj/item/tk_grab)) - if(hand) del(l_hand) - else del(r_hand) - return - if(in_throw_mode) throw_mode_off() else diff --git a/code/modules/mob/mob.dm b/code/modules/mob/mob.dm index 4ae03ad6f05..c48ba8dca22 100644 --- a/code/modules/mob/mob.dm +++ b/code/modules/mob/mob.dm @@ -506,9 +506,8 @@ var/list/slot_equipment_priority = list( \ ..() if(M != usr) return if(usr == src) return - if(!in_range(usr, src)) return + if(!Adjacent(usr)) return if(istype(M, /mob/living/silicon/ai)) return - if(LinkBlocked(usr.loc, loc)) return show_inv(usr) diff --git a/code/modules/mob/mob_defines.dm b/code/modules/mob/mob_defines.dm index c8fc9e5b988..5f0bcf31668 100644 --- a/code/modules/mob/mob_defines.dm +++ b/code/modules/mob/mob_defines.dm @@ -44,7 +44,6 @@ var/disabilities = 0 //Carbon var/atom/movable/pulling = null var/next_move = null - var/prev_move = null var/monkeyizing = null //Carbon var/hand = null var/eye_blind = null //Carbon diff --git a/code/modules/paperwork/filingcabinet.dm b/code/modules/paperwork/filingcabinet.dm index 4d662aea876..90f55715009 100644 --- a/code/modules/paperwork/filingcabinet.dm +++ b/code/modules/paperwork/filingcabinet.dm @@ -67,6 +67,22 @@ dat += "" user << browse("[name][dat]", "window=filingcabinet;size=350x300") +/obj/structure/filingcabinet/attack_tk(mob/user) + if(anchored) + attack_self_tk(user) + else + ..() + +/obj/structure/filingcabinet/attack_self_tk(mob/user) + if(contents.len) + if(prob(40 + contents.len * 5)) + var/obj/item/I = pick(contents) + I.loc = loc + if(prob(25)) + step_rand(I) + user << "You pull \a [I] out of [src] at random." + return + user << "You find nothing in [src]." /obj/structure/filingcabinet/Topic(href, href_list) if(href_list["retrieve"]) @@ -88,7 +104,7 @@ /obj/structure/filingcabinet/security var/virgin = 1 -/obj/structure/filingcabinet/security/attack_hand(mob/user) +/obj/structure/filingcabinet/security/proc/populate() if(virgin) for(var/datum/data/record/G in data_core.general) var/datum/data/record/S = find_record("name", G.fields["name"], data_core.security) @@ -105,8 +121,12 @@ P.name = "paper - '[G.fields["name"]]'" virgin = 0 //tabbing here is correct- it's possible for people to try and use it //before the records have been generated, so we do this inside the loop. +/obj/structure/filingcabinet/security/attack_hand() + populate() + ..() +/obj/structure/filingcabinet/security/attack_tk() + populate() ..() - /* * Medical Record Cabinets @@ -114,7 +134,7 @@ /obj/structure/filingcabinet/medical var/virgin = 1 -/obj/structure/filingcabinet/medical/attack_hand(mob/user) +/obj/structure/filingcabinet/medical/proc/populate() if(virgin) for(var/datum/data/record/G in data_core.general) var/datum/data/record/M = find_record("name", G.fields["name"], data_core.medical) @@ -131,4 +151,9 @@ P.name = "paper - '[G.fields["name"]]'" virgin = 0 //tabbing here is correct- it's possible for people to try and use it //before the records have been generated, so we do this inside the loop. - ..() \ No newline at end of file +/obj/structure/filingcabinet/medical/attack_hand() + populate() + ..() +/obj/structure/filingcabinet/medical/attack_tk() + populate() + ..() diff --git a/code/modules/power/cable.dm b/code/modules/power/cable.dm index ac06014fa1b..01a130b43be 100644 --- a/code/modules/power/cable.dm +++ b/code/modules/power/cable.dm @@ -114,6 +114,8 @@ if(istype(user:gloves, /obj/item/clothing/gloves/space_ninja)&&user:gloves:candrain&&!user:gloves:draining) call(/obj/item/clothing/gloves/space_ninja/proc/drain)("WIRE",src,user:wear_suit) return +/obj/structure/cable/attack_tk(mob/user) + return /obj/structure/cable/attackby(obj/item/W, mob/user) diff --git a/code/modules/power/lighting.dm b/code/modules/power/lighting.dm index d6e56d4ea47..60103151a03 100644 --- a/code/modules/power/lighting.dm +++ b/code/modules/power/lighting.dm @@ -491,6 +491,8 @@ if(prot > 0 || (COLD_RESISTANCE in user.mutations)) user << "You remove the light [fitting]" + else if(TK in user.mutations) + user << "You telekinetically remove the light [fitting]." else user << "You try to remove the light [fitting], but you burn your hand on it!" @@ -500,7 +502,8 @@ H.update_damage_overlays(0) H.updatehealth() return // if burned, don't remove the light - + else + user << "You remove the light [fitting]." // create a light tube/bulb item and put it in the user's hand var/obj/item/weapon/light/L = new light_type() L.status = status @@ -520,6 +523,29 @@ status = LIGHT_EMPTY update() +/obj/machinery/light/attack_tk(mob/user) + if(status == LIGHT_EMPTY) + user << "There is no [fitting] in this light." + return + + user << "You telekinetically remove the light [fitting]." + // create a light tube/bulb item and put it in the user's hand + var/obj/item/weapon/light/L = new light_type() + L.status = status + L.rigged = rigged + L.brightness = brightness + + // light item inherits the switchcount, then zero it + L.switchcount = switchcount + switchcount = 0 + + L.update() + L.add_fingerprint(user) + L.loc = loc + + status = LIGHT_EMPTY + update() + // break the light and make sparks if was on /obj/machinery/light/proc/broken(var/skip_sound_and_sparks = 0) diff --git a/html/changelog.html b/html/changelog.html index 50e158546f5..baaf84c1518 100644 --- a/html/changelog.html +++ b/html/changelog.html @@ -62,6 +62,7 @@ should be listed in the changelog upon commit tho. Thanks. -->
  • Ghosts can now click on anything to examine it, or double click to jump to a turf. Double clicking a mob, bot, or (heaven forbid) singularity will let you follow it. Double clicking your own corpse re-enters it.
  • AI can double click a mob to follow it.
  • Ventcrawling mobs can alt-click a vent to start ventcrawling.
  • +
  • Telekinesis is now part of the click system. You can click on buttons, items, etc, without having a telekinetic throw in hand; the throw will appear when you click on something you can move (with your mind).
  • diff --git a/tgstation.dme b/tgstation.dme index a7c2977154f..fad66a9cc54 100644 --- a/tgstation.dme +++ b/tgstation.dme @@ -42,6 +42,7 @@ #include "code\_onclick\item_attack.dm" #include "code\_onclick\observer.dm" #include "code\_onclick\other_mobs.dm" +#include "code\_onclick\telekinesis.dm" #include "code\_onclick\hud\_defines.dm" #include "code\_onclick\hud\alien.dm" #include "code\_onclick\hud\alien_larva.dm" @@ -443,7 +444,6 @@ #include "code\game\objects\items\crayons.dm" #include "code\game\objects\items\latexballoon.dm" #include "code\game\objects\items\shooting_range.dm" -#include "code\game\objects\items\tk_grab.dm" #include "code\game\objects\items\toys.dm" #include "code\game\objects\items\trash.dm" #include "code\game\objects\items\devices\aicard.dm"