Skip to content

Commit

Permalink
Adds telekinesis to click code. Fixes issue tgstation#1202, tgstation…
Browse files Browse the repository at this point in the history
…#1129, tgstation#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.
  • Loading branch information
SuperSayu committed Sep 17, 2013
1 parent 62f7bc1 commit c172e52
Show file tree
Hide file tree
Showing 22 changed files with 341 additions and 185 deletions.
10 changes: 5 additions & 5 deletions code/_onclick/adjacent.dm
Original file line number Diff line number Diff line change
Expand Up @@ -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)
Expand All @@ -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

Expand All @@ -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

/*
Expand Down
15 changes: 12 additions & 3 deletions code/_onclick/click.dm
Original file line number Diff line number Diff line change
Expand Up @@ -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)
Expand Down Expand Up @@ -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

Expand Down
305 changes: 177 additions & 128 deletions code/game/objects/items/tk_grab.dm → code/_onclick/telekinesis.dm
Original file line number Diff line number Diff line change
@@ -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
*/

7 changes: 7 additions & 0 deletions code/game/machinery/doors/door.dm
Original file line number Diff line number Diff line change
Expand Up @@ -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)))
Expand Down
Loading

0 comments on commit c172e52

Please sign in to comment.