|
| 1 | +#define LOOKING_DIRECTION_UP 1 |
| 2 | +#define LOOKING_DIRECTION_NONE 0 |
| 3 | +#define LOOKING_DIRECTION_DOWN -1 |
| 4 | + |
| 5 | +/// The current direction the player is ACTUALLY looking, regardless of intent. |
| 6 | +/mob/living/var/looking_direction = LOOKING_DIRECTION_NONE |
| 7 | +/// The current direction the player is trying to look. |
| 8 | +/mob/living/var/attempt_looking_direction = LOOKING_DIRECTION_NONE |
| 9 | + |
| 10 | +///Checks if the user is incapacitated and cannot look up/down |
| 11 | +/mob/living/proc/can_look_direction() |
| 12 | + return !(incapacitated(ignore_restraints = TRUE)) |
| 13 | + |
| 14 | +/// Tell the mob to attempt to look this direction until it's set back to NONE |
| 15 | +/mob/living/proc/set_attempted_looking_direction(direction) |
| 16 | + if(attempt_looking_direction == direction && direction != LOOKING_DIRECTION_NONE) // we are already trying to look this way, reset |
| 17 | + set_attempted_looking_direction(LOOKING_DIRECTION_NONE) |
| 18 | + return |
| 19 | + attempt_looking_direction = direction |
| 20 | + set_look_direction(attempt_looking_direction) |
| 21 | + |
| 22 | +/// Actually sets the looking direction, but it won't try to stay that way if we move out of range |
| 23 | +/mob/living/proc/set_look_direction(direction, automatic = FALSE) |
| 24 | + // Handle none/failure |
| 25 | + if(direction == LOOKING_DIRECTION_NONE || !can_look_direction(direction)) |
| 26 | + looking_direction = LOOKING_DIRECTION_NONE |
| 27 | + reset_perspective() |
| 28 | + return |
| 29 | + // Automatic attempts should not trigger the cooldown |
| 30 | + if(!automatic) |
| 31 | + changeNext_move(CLICK_CD_LOOK_UP) |
| 32 | + looking_direction = direction |
| 33 | + var/look_str = direction == LOOKING_DIRECTION_UP ? "up" : "down" |
| 34 | + if(update_looking_move(automatic)) |
| 35 | + visible_message("<span class='notice'>[src] looks [look_str].</span>", "<span class='notice'>You look [look_str].</span>") |
| 36 | + |
| 37 | +/// Called by /mob/living/Moved(), checks if we can continue looking |
| 38 | +/mob/living/proc/update_looking_move(automatic = FALSE) |
| 39 | + // Try looking the attempted direction now that we've moved |
| 40 | + if(attempt_looking_direction != LOOKING_DIRECTION_NONE && looking_direction == LOOKING_DIRECTION_NONE) |
| 41 | + set_look_direction(attempt_looking_direction, automatic = TRUE) // this won't loop recursively because looking_direction cannot be NONE above |
| 42 | + // We can't try looking nowhere! |
| 43 | + if(looking_direction == LOOKING_DIRECTION_NONE) |
| 44 | + return FALSE |
| 45 | + // Something changed, stop looking |
| 46 | + if(!can_look_direction(looking_direction)) |
| 47 | + set_look_direction(LOOKING_DIRECTION_NONE) |
| 48 | + // Update perspective |
| 49 | + var/turf/base = find_visible_hole_in_direction(looking_direction) |
| 50 | + if(!isturf(base)) |
| 51 | + if(!automatic) |
| 52 | + to_chat(src, "<span class='warning'>You can't see through the [looking_direction == LOOKING_DIRECTION_UP ? "ceiling above" : "floor below"] you.</span>") |
| 53 | + set_look_direction(LOOKING_DIRECTION_NONE) |
| 54 | + return FALSE |
| 55 | + reset_perspective(base) |
| 56 | + return TRUE |
| 57 | + |
| 58 | +/mob/living/verb/look_up_short() |
| 59 | + set name = "Look Up" |
| 60 | + set category = "IC" |
| 61 | + // you pressed the verb while holding a keybind, unlock! |
| 62 | + attempt_looking_direction = LOOKING_DIRECTION_NONE |
| 63 | + if(looking_direction == LOOKING_DIRECTION_UP) |
| 64 | + set_look_direction(LOOKING_DIRECTION_NONE) |
| 65 | + return |
| 66 | + look_up() |
| 67 | + |
| 68 | +/** |
| 69 | + * look_up Changes the perspective of the mob to any openspace turf above the mob |
| 70 | + * lock: If it should continue to try looking even if there is no seethrough turf |
| 71 | + */ |
| 72 | +/mob/living/proc/look_up(lock = FALSE) |
| 73 | + if(lock) |
| 74 | + set_attempted_looking_direction(LOOKING_DIRECTION_UP) |
| 75 | + else |
| 76 | + set_look_direction(LOOKING_DIRECTION_UP) |
| 77 | + |
| 78 | +/mob/living/verb/look_down_short() |
| 79 | + set name = "Look Down" |
| 80 | + set category = "IC" |
| 81 | + // you pressed the verb while holding a keybind, unlock! |
| 82 | + attempt_looking_direction = LOOKING_DIRECTION_NONE |
| 83 | + if(looking_direction == LOOKING_DIRECTION_DOWN) |
| 84 | + set_look_direction(LOOKING_DIRECTION_NONE) |
| 85 | + return |
| 86 | + look_down() |
| 87 | + |
| 88 | +/** |
| 89 | + * look_down Changes the perspective of the mob to any openspace turf below the mob |
| 90 | + * lock: If it should continue to try looking even if there is no seethrough turf |
| 91 | + */ |
| 92 | +/mob/living/proc/look_down(lock = FALSE) |
| 93 | + if(lock) |
| 94 | + set_attempted_looking_direction(LOOKING_DIRECTION_DOWN) |
| 95 | + else |
| 96 | + set_look_direction(LOOKING_DIRECTION_DOWN) |
| 97 | + |
| 98 | +/// Helper, resets from looking up or down, and unlocks the view. |
| 99 | +/mob/living/proc/look_reset() |
| 100 | + set_attempted_looking_direction(LOOKING_DIRECTION_NONE) |
| 101 | + |
| 102 | +/mob/living/proc/find_visible_hole_in_direction(direction) |
| 103 | + // Our current z-level turf |
| 104 | + var/turf/turf_base = get_turf(src) |
| 105 | + // The target z-level turf |
| 106 | + var/turf/turf_other = get_step_multiz(turf_base, direction == LOOKING_DIRECTION_UP ? UP : DOWN) |
| 107 | + if(!turf_other) // There is nothing above/below |
| 108 | + return FALSE |
| 109 | + // This turf is the one we are looking through |
| 110 | + var/turf/seethrough_turf = direction == LOOKING_DIRECTION_UP ? turf_other : turf_base |
| 111 | + // The turf we should end up looking at. |
| 112 | + var/turf/end_turf = turf_other |
| 113 | + if(istransparentturf(seethrough_turf)) //There is no turf we can look through directly above/below us, look for nearby turfs |
| 114 | + return end_turf |
| 115 | + // Turf in front of you to try to look through before anything else |
| 116 | + var/turf/seethrough_turf_front = get_step(seethrough_turf, dir) |
| 117 | + if(istransparentturf(seethrough_turf_front)) |
| 118 | + return direction == LOOKING_DIRECTION_UP ? seethrough_turf_front : get_step_multiz(seethrough_turf_front, DOWN) |
| 119 | + var/target_z = direction == LOOKING_DIRECTION_UP ? turf_other.z : z |
| 120 | + var/list/checkturfs = block(locate(x-1,y-1,target_z),locate(x+1,y+1,target_z))-turf_base-turf_other |
| 121 | + for(var/turf/checkhole in checkturfs) |
| 122 | + if(istransparentturf(checkhole)) |
| 123 | + seethrough_turf = checkhole |
| 124 | + end_turf = direction == LOOKING_DIRECTION_UP ? checkhole : get_step_multiz(checkhole, DOWN) |
| 125 | + break |
| 126 | + if(!istransparentturf(seethrough_turf)) |
| 127 | + return FALSE |
| 128 | + return end_turf |
| 129 | + |
| 130 | +#undef LOOKING_DIRECTION_UP |
| 131 | +#undef LOOKING_DIRECTION_NONE |
| 132 | +#undef LOOKING_DIRECTION_DOWN |
0 commit comments