diff --git a/code/game/objects/structures/spirit_board.dm b/code/game/objects/structures/spirit_board.dm index d30e1363052..2e6a2bd9a07 100644 --- a/code/game/objects/structures/spirit_board.dm +++ b/code/game/objects/structures/spirit_board.dm @@ -6,77 +6,102 @@ resistance_flags = FLAMMABLE density = TRUE anchored = FALSE + /// Whether no one has moved the planchette yet. var/virgin = TRUE //applies especially to admins - var/next_use = 0 - var/planchette = "A" + /// How long between planchette movements. + COOLDOWN_DECLARE(next_use) + /// Where the planchette is currently pointing. + var/planchette + /// Ckey of last mob to use the board. var/lastuser = null + /// List of options ghosts (or people) can pick from. + var/list/ghosty_options = list( + "A","B","C","D","E","F","G","H","I","J","K","L","M","N","O","P","Q","R","S","T","U","V","W","X","Y","Z", + "1","2","3","4","5","6","7","8","9","0", + "Yes","No", + ) + /// Number of living, willing mobs adjacent to the board required for a seance to occur. + var/required_user_count = 2 + +/obj/structure/spirit_board/Initialize(mapload) + . = ..() + if(prob(1)) + name = "luigi board" + planchette = ghosty_options[1] /obj/structure/spirit_board/examine() - desc = "[initial(desc)] The planchette is sitting at \"[planchette]\"." . = ..() + if(planchette) + . += span_notice("The planchette is currently at the letter \"[planchette]\".") + else + . += span_notice("The planchette is in the middle of the board on no particular letter.") /obj/structure/spirit_board/attack_hand(mob/user, list/modifiers) . = ..() if(.) - return + return . spirit_board_pick_letter(user) + return TRUE - -//ATTACK GHOST IGNORING PARENT RETURN VALUE /obj/structure/spirit_board/attack_ghost(mob/dead/observer/user) + . = ..() + if(.) + return . spirit_board_pick_letter(user) - return ..() + return TRUE -/obj/structure/spirit_board/proc/spirit_board_pick_letter(mob/M) - if(!spirit_board_checks(M)) - return FALSE +/obj/structure/spirit_board/proc/spirit_board_pick_letter(mob/ghost) + if(!spirit_board_checks(ghost)) + return if(virgin) virgin = FALSE - notify_ghosts("Someone has begun playing with a [src.name] in [get_area(src)]!", source = src, header = "Spirit board") + notify_ghosts("Someone has begun playing with \a [src] in [get_area(src)]!", source = src, header = "Spirit board") - planchette = tgui_input_list(M, "Choose the letter.", "Seance!", list("A","B","C","D","E","F","G","H","I","J","K","L","M","N","O","P","Q","R","S","T","U","V","W","X","Y","Z")) - if(isnull(planchette)) + var/new_planchette = tgui_input_list(ghost, "Choose the letter.", "Seance!", ghosty_options) + if(isnull(new_planchette)) return - if(!Adjacent(M) || next_use > world.time) + if(!Adjacent(ghost) || !COOLDOWN_FINISHED(src, next_use)) return - M.log_message("picked a letter on [src], which was \"[planchette]\".", LOG_GAME) - next_use = world.time + rand(30,50) - lastuser = M.ckey - //blind message is the same because not everyone brings night vision to seances - var/msg = span_notice("The planchette slowly moves... and stops at the letter \"[planchette]\".") - visible_message(msg,"",msg) + planchette = new_planchette + ghost.log_message("picked a letter on [src], which was \"[planchette]\".", LOG_GAME) + COOLDOWN_START(src, next_use, rand(3 SECONDS, 5 SECONDS)) + lastuser = ghost.ckey + for(var/mob/viewer in range(2, src)) + if(isnull(viewer.client)) + continue + if(viewer.stat != CONSCIOUS && viewer.stat != DEAD) // You gotta be awake or dead to pay the toll + continue + if(viewer.is_blind()) + to_chat(viewer, span_hear("You hear a scraping sound...")) + else + to_chat(viewer, span_notice("The planchette slowly moves... and stops at the letter \"[planchette]\".")) -/obj/structure/spirit_board/proc/spirit_board_checks(mob/M) - //cooldown - var/bonus = 0 - if(M.ckey == lastuser) - bonus = 10 //Give some other people a chance, hog. +/obj/structure/spirit_board/proc/spirit_board_checks(mob/ghost) + var/cd_penalty = (ghost.ckey == lastuser) ? 1 SECONDS : 0 SECONDS //Give some other people a chance, hog. - if(next_use - bonus > world.time ) + if(next_use - cd_penalty > world.time) return FALSE //No feedback here, hiding the cooldown a little makes it harder to tell who's really picking letters. - //lighting check - var/light_amount = 0 - var/turf/T = get_turf(src) - light_amount = T.get_lumcount() + var/turf/play_turf = get_turf(src) + if(play_turf?.get_lumcount() > 0.2) + to_chat(ghost, span_warning("It's too bright here to use [src]!")) + return FALSE + if(required_user_count > 0) + var/users_in_range = 0 + for(var/mob/living/player in orange(1, src)) + if(isnull(player.ckey) || isnull(player.client)) + continue - if(light_amount > 0.2) - to_chat(M, span_warning("It's too bright here to use [src.name]!")) - return FALSE + if(player.client?.is_afk() || player.stat != CONSCIOUS || HAS_TRAIT(player, TRAIT_HANDS_BLOCKED))//no playing with braindeads or corpses or handcuffed dudes. + to_chat(ghost, span_warning("[player] doesn't seem to be paying attention...")) + continue - //mobs in range check - var/users_in_range = 0 - for(var/mob/living/L in orange(1,src)) - if(L.ckey && L.client) - if((world.time - L.client.inactivity) < (world.time - 300) || L.stat != CONSCIOUS || HAS_TRAIT(L, TRAIT_HANDS_BLOCKED))//no playing with braindeads or corpses or handcuffed dudes. - to_chat(M, span_warning("[L] doesn't seem to be paying attention...")) - else - users_in_range++ + users_in_range++ - if(users_in_range < 2) - to_chat(M, span_warning("There aren't enough people to use the [src.name]!")) - return FALSE + if(users_in_range < required_user_count) + to_chat(ghost, span_warning("There aren't enough people around to use [src]!")) + return FALSE return TRUE diff --git a/code/modules/mob/living/basic/space_fauna/revenant/_revenant.dm b/code/modules/mob/living/basic/space_fauna/revenant/_revenant.dm index b3c6935c92e..526d268df03 100644 --- a/code/modules/mob/living/basic/space_fauna/revenant/_revenant.dm +++ b/code/modules/mob/living/basic/space_fauna/revenant/_revenant.dm @@ -202,6 +202,18 @@ if(ishuman(A) && in_range(src, A)) attempt_harvest(A) + return + + // This is probably the most cringe place I could put this but whatever - + // Revenants can click on spirit boards for seances like ghosts + if(istype(A, /obj/structure/spirit_board) \ + && !HAS_TRAIT(src, TRAIT_REVENANT_REVEALED) \ + && !HAS_TRAIT(src, TRAIT_NO_TRANSFORM) \ + && !HAS_TRAIT(src, TRAIT_REVENANT_INHIBITED)) + + var/obj/structure/spirit_board/board = A + board.spirit_board_pick_letter(src) + return /mob/living/basic/revenant/ranged_secondary_attack(atom/target, modifiers) if(HAS_TRAIT(src, TRAIT_REVENANT_INHIBITED) || HAS_TRAIT(src, TRAIT_REVENANT_REVEALED) || HAS_TRAIT(src, TRAIT_NO_TRANSFORM) || !Adjacent(target) || !incorporeal_move_check(target))