mirror of
https://github.com/Bubberstation/Bubberstation.git
synced 2026-07-17 02:54:44 +01:00
Makes wayfinding great again (#56055)
Interacting with the wayfinding pinpointer dispenser recently after leaving it untouched basically since I added it I realised it has a bunch of bad design decisions that make it unpleasant to interact with so while this can never solve the lack of desirability of the pinpointers themselves hopefully it prevents the machine from contributing to the problem.
This commit is contained in:
@@ -1,121 +1,246 @@
|
||||
#define COOLDOWN_SPAWN 3 MINUTES
|
||||
#define COOLDOWN_INTERACT 6 SECONDS
|
||||
#define COOLDOWN_SLOGAN 5 MINUTES
|
||||
#define COOLDOWN_SPEW 5 MINUTES
|
||||
/obj/machinery/pinpointer_dispenser
|
||||
name = "wayfinding pinpointer synthesizer"
|
||||
icon = 'icons/obj/machines/wayfinding.dmi'
|
||||
icon_state = "pinpointersynth"
|
||||
desc = "Having trouble finding your way? This machine synthesizes pinpointers that point to common locations."
|
||||
desc = "A machine given the thankless job of trying to sell wayfinding pinpointers. They point to common locations."
|
||||
density = FALSE
|
||||
layer = HIGH_OBJ_LAYER
|
||||
armor = list(MELEE = 80, BULLET = 30, LASER = 30, ENERGY = 60, BOMB = 90, BIO = 0, RAD = 0, FIRE = 100, ACID = 80)
|
||||
payment_department = ACCOUNT_CIV
|
||||
light_power = 0.5
|
||||
light_range = MINIMUM_USEFUL_LIGHT_RANGE
|
||||
///List of user-specific cooldowns to prevent pinpointer spam.
|
||||
var/list/user_spawn_cooldowns = list()
|
||||
///List of user-specific cooldowns to prevent message spam.
|
||||
var/list/user_interact_cooldowns = list()
|
||||
var/spawn_cooldown = 5 MINUTES //time per person to spawn another pinpointer
|
||||
var/interact_cooldown = 20 SECONDS //time per person for subsequent interactions
|
||||
var/start_bal = 200 //how much money it starts with to cover wayfinder refunds
|
||||
var/refund_amt = 40 //how much money recycling a pinpointer rewards you
|
||||
///How many credits the dispenser account starts with to cover wayfinder refunds.
|
||||
var/start_bal = 400
|
||||
///How many credits recycling a pinpointer rewards you.
|
||||
var/refund_amt = 40
|
||||
var/datum/bank_account/synth_acc = new /datum/bank_account/remote
|
||||
var/ppt_cost = 65 //Jan 6 '20: Assistant can buy one roundstart (125 cr starting)
|
||||
var/ppt_cost = 0 //Jan 9 '21: 2560 had its difficulties for NT as well
|
||||
var/expression_timer
|
||||
///Avoid being Reddit.
|
||||
var/funnyprob = 2
|
||||
///List of slogans used by the dispenser to attract customers.
|
||||
var/list/slogan_list = list("Find a wayfinding pinpointer? Give it to me! I'll make it worth your while. Please. Daddy needs his medicine.", //last sentence is a reference to Sealab 2021
|
||||
"See a wayfinding pinpointer? Don't let it go to the crusher! Recycle it with me instead. I'll pay you!", //I see these things heading for disposals through cargo all the time
|
||||
"Need the disk? Can't get a pinpointer? Buy a wayfinding pinpointer and find the captain's office today!",
|
||||
"Bleeding to death? Can't read? Find your way to medbay today!", //there are signs that point to medbay but you need basic literacy to get the most out of them
|
||||
"Voted tenth best pinpointer in the universe in 2560!", //there were no more than ten pinpointers in the game in 2020
|
||||
"Helping assistants find the departments they tide since 2560.", //not really but it's advertising
|
||||
"These pinpointers are flying out the airlock!", //because they're being thrown into space
|
||||
"Grey pinpointers for the grey tide!", //I didn't pick the colour but it works
|
||||
"Feeling lost? Find direction.",
|
||||
"Automate your sense of direction. Buy a wayfinding pinpointer today!",
|
||||
"Feed me a stray pinpointer.", //American Psycho reference
|
||||
"We need a slogan!") //Liberal Crime Squad reference
|
||||
///Number of the list entry of the slogan we're up to.
|
||||
var/slogan_entry = 0
|
||||
///Next tick we can say a slogan.
|
||||
COOLDOWN_DECLARE(next_slogan_tick)
|
||||
///Next tick the dispenser's spew rejection of non-wayfinding pinpointers can be triggered.
|
||||
COOLDOWN_DECLARE(next_spew_tick)
|
||||
|
||||
/obj/machinery/pinpointer_dispenser/Initialize(mapload)
|
||||
. = ..()
|
||||
var/datum/bank_account/civ_acc = SSeconomy.get_dep_account(ACCOUNT_CIV)
|
||||
var/datum/bank_account/civ_acc = SSeconomy.get_dep_account(payment_department)
|
||||
if(civ_acc)
|
||||
synth_acc.transfer_money(civ_acc, start_bal) //float has to come from somewhere, right?
|
||||
|
||||
synth_acc.account_holder = name
|
||||
|
||||
desc += " Only [ppt_cost] credits! It also likes making costumes..."
|
||||
desc += " [ppt_cost ? "Only [ppt_cost] credits! " : ""]It also synthesises costumes for some reason."
|
||||
|
||||
set_expression("neutral")
|
||||
power_change()
|
||||
|
||||
COOLDOWN_START(src, next_slogan_tick, COOLDOWN_SLOGAN)
|
||||
slogan_list = shuffle(slogan_list) //minimise repetition
|
||||
|
||||
/obj/machinery/pinpointer_dispenser/power_change()
|
||||
. = ..()
|
||||
cut_overlays()
|
||||
if(powered())
|
||||
set_expression("veryhappy", 2 SECONDS) //v happy to be back in the pinpointer business
|
||||
START_PROCESSING(SSmachines, src)
|
||||
|
||||
/obj/machinery/pinpointer_dispenser/update_icon_state()
|
||||
if(machine_stat & BROKEN)
|
||||
set_light(0)
|
||||
else if(powered())
|
||||
set_light(1.4)
|
||||
else
|
||||
set_light(0)
|
||||
|
||||
/obj/machinery/pinpointer_dispenser/process(delta_time)
|
||||
if(machine_stat & (BROKEN|NOPOWER))
|
||||
return PROCESS_KILL
|
||||
|
||||
if(!length(slogan_list) || !COOLDOWN_FINISHED(src, next_slogan_tick))
|
||||
return
|
||||
if(++slogan_entry > length(slogan_list))
|
||||
slogan_entry = 1
|
||||
var/slogan = slogan_list[slogan_entry]
|
||||
say(slogan)
|
||||
COOLDOWN_START(src, next_slogan_tick, COOLDOWN_SLOGAN)
|
||||
|
||||
/obj/machinery/pinpointer_dispenser/Destroy()
|
||||
for(var/i in 1 to rand(3, 9)) //Doesn't synthesise them in real time and instead stockpiles completed ones (though this is not how the cooldown works)
|
||||
new /obj/item/pinpointer/wayfinding (loc)
|
||||
say("Ouch.")
|
||||
//An inexplicable explosion is never not funny plus it kind of explains why the machine just disappears
|
||||
if(!isnull(loc))
|
||||
explosion(get_turf(src), devastation_range = 0, heavy_impact_range = 0, light_impact_range = 1, flash_range = 3, flame_range = 1, smoke = TRUE)
|
||||
return ..()
|
||||
|
||||
/obj/machinery/pinpointer_dispenser/attack_hand(mob/living/user)
|
||||
if(world.time < user_interact_cooldowns[user.real_name])
|
||||
to_chat(user, "<span class='warning'>It doesn't respond.</span>")
|
||||
. = ..()
|
||||
|
||||
if(machine_stat & (BROKEN|NOPOWER))
|
||||
return
|
||||
|
||||
user_interact_cooldowns[user.real_name] = world.time + interact_cooldown
|
||||
if(world.time < user_interact_cooldowns[user.real_name])
|
||||
set_expression("veryhappy", 2 SECONDS)
|
||||
to_chat(user, "<span class='notice'>It just grins at you. Maybe you should give it a bit?</span>") //telling instead of showing but I'm lazy
|
||||
return
|
||||
|
||||
user_interact_cooldowns[user.real_name] = world.time + COOLDOWN_INTERACT
|
||||
|
||||
for(var/obj/item/pinpointer/wayfinding/WP in user.GetAllContents())
|
||||
set_expression("unsure", 2 SECONDS)
|
||||
say("<span class='robot'>I can detect the pinpointer on you, [user.first_name()].</span>")
|
||||
user_spawn_cooldowns[user.real_name] = world.time + spawn_cooldown //spawn timer resets for trickers
|
||||
set_expression("veryhappy", 2 SECONDS)
|
||||
say("<span class='robot'>You already have a pinpointer!</span>")
|
||||
return
|
||||
|
||||
var/msg
|
||||
var/dispense = TRUE
|
||||
var/obj/item/pinpointer/wayfinding/pointat
|
||||
for(var/obj/item/pinpointer/wayfinding/WP in range(7, user))
|
||||
if(WP.Adjacent(user))
|
||||
set_expression("facepalm", 2 SECONDS)
|
||||
say("<span class='robot'>[WP.owner == user.real_name ? "Your" : "A"] pinpointer is right there.</span>")
|
||||
pointat(WP)
|
||||
user_spawn_cooldowns[user.real_name] = world.time + spawn_cooldown
|
||||
return
|
||||
else if(WP in oview(7, user))
|
||||
pointat = WP
|
||||
break
|
||||
var/pnpts_found = 0
|
||||
for(var/obj/item/pinpointer/wayfinding/WP in view(9, src))
|
||||
point_at(WP)
|
||||
pnpts_found++
|
||||
|
||||
if(pnpts_found)
|
||||
set_expression("veryhappy", 2 SECONDS)
|
||||
say("<span class='robot'>[pnpts_found == 1 ? "There's a pinpointer" : "There are pinpointers"] there!</span>")
|
||||
return
|
||||
|
||||
if(world.time < user_spawn_cooldowns[user.real_name])
|
||||
var/secsleft = (user_spawn_cooldowns[user.real_name] - world.time) / 10
|
||||
msg += "to wait another [secsleft/60 > 1 ? "[round(secsleft/60,1)] minute\s" : "[round(secsleft)] second\s"]"
|
||||
msg += "to wait [secsleft/60 > 1 ? "[round(secsleft/60,1)] more minute\s" : "[round(secsleft)] more second\s"] before I can give you another pinpointer"
|
||||
dispense = FALSE
|
||||
|
||||
var/datum/bank_account/cust_acc = user.get_bank_account()
|
||||
|
||||
if(cust_acc)
|
||||
if(!cust_acc.has_money(ppt_cost))
|
||||
if(ppt_cost)
|
||||
if(!cust_acc)
|
||||
msg += "a bank account to buy a pinpointer"
|
||||
dispense = FALSE
|
||||
else if(!cust_acc.has_money(ppt_cost))
|
||||
msg += "[!msg ? "to find [ppt_cost-cust_acc.account_balance] more credit\s" : " and find [ppt_cost-cust_acc.account_balance] more credit\s"]"
|
||||
dispense = FALSE
|
||||
else if(synth_acc.transfer_money(cust_acc, ppt_cost))
|
||||
dispense = TRUE
|
||||
|
||||
if(!dispense)
|
||||
set_expression("sad", 2 SECONDS)
|
||||
if(pointat)
|
||||
msg += ". I suggest you get [pointat.owner == user.real_name ? "your" : "that"] pinpointer over there instead"
|
||||
pointat(pointat)
|
||||
say("<span class='robot'>You will need [msg], [user.first_name()].</span>")
|
||||
return
|
||||
|
||||
if(synth_acc.transfer_money(cust_acc, ppt_cost))
|
||||
say("<span class='robot'>Sorry, [user.first_name()]! You'll need [msg]!</span>")
|
||||
else
|
||||
set_expression("veryhappy", 2 SECONDS)
|
||||
say("<span class='robot'>That is [ppt_cost] credits. Here is your pinpointer.</span>")
|
||||
say("<span class='robot'>Here's your pinpointer!</span>")
|
||||
var/obj/item/pinpointer/wayfinding/P = new /obj/item/pinpointer/wayfinding(get_turf(src))
|
||||
user_spawn_cooldowns[user.real_name] = world.time + spawn_cooldown
|
||||
user_spawn_cooldowns[user.real_name] = world.time + COOLDOWN_SPAWN
|
||||
user.put_in_hands(P)
|
||||
P.owner = user.real_name
|
||||
|
||||
/obj/machinery/pinpointer_dispenser/attackby(obj/item/I, mob/user, params)
|
||||
if(machine_stat & (BROKEN|NOPOWER))
|
||||
return ..()
|
||||
|
||||
if(istype(I, /obj/item/pinpointer/wayfinding))
|
||||
var/obj/item/pinpointer/wayfinding/WP = I
|
||||
|
||||
to_chat(user, "<span class='notice'>You put \the [WP] in the return slot.</span>")
|
||||
var/rfnd_amt
|
||||
if((!WP.roundstart || WP.owner != user.real_name) && synth_acc.has_money(TRUE)) //can't recycle own pinpointer for money if not bought; given by a neutral quirk
|
||||
if(synth_acc.has_money(refund_amt))
|
||||
rfnd_amt = refund_amt
|
||||
else
|
||||
rfnd_amt = synth_acc.account_balance
|
||||
synth_acc._adjust_money(-rfnd_amt)
|
||||
var/obj/item/holochip/HC = new /obj/item/holochip(user.loc)
|
||||
HC.credits = rfnd_amt
|
||||
HC.name = "[HC.credits] credit holochip"
|
||||
if(istype(user, /mob/living/carbon/human))
|
||||
var/mob/living/carbon/human/H = user
|
||||
H.put_in_hands(HC)
|
||||
else
|
||||
var/crap = pick(subtypesof(/obj/effect/spawner/bundle/costume)) //harmless garbage some people may appreciate
|
||||
new crap(user.loc)
|
||||
qdel(WP)
|
||||
set_expression("happy", 2 SECONDS)
|
||||
say("<span class='robot'>Thank you for recycling, [user.first_name()]! Here is [rfnd_amt ? "[rfnd_amt] credits." : "a freshly synthesized costume!"]</span>")
|
||||
|
||||
var/refundiscredits = FALSE
|
||||
var/itsmypinpointer = TRUE
|
||||
|
||||
//Will they meet the conditions to get a credit reward for recycling?
|
||||
if(WP.owner != user.real_name)
|
||||
itsmypinpointer = FALSE
|
||||
|
||||
if(synth_acc.has_money(refund_amt) && !WP.roundstart) //can it afford to refund and is the pinpointer not from the quirk
|
||||
refundiscredits = TRUE
|
||||
qdel(WP)
|
||||
synth_acc._adjust_money(-refund_amt)
|
||||
var/obj/item/holochip/holochip = new (loc)
|
||||
holochip.credits = refund_amt
|
||||
holochip.name = "[holochip.credits] credit holochip"
|
||||
if(ishuman(user))
|
||||
var/mob/living/carbon/human/customer = user
|
||||
customer.put_in_hands(holochip)
|
||||
|
||||
if(!refundiscredits)
|
||||
qdel(WP)
|
||||
var/costume = pick(subtypesof(/obj/effect/spawner/bundle/costume))
|
||||
new costume(user.loc)
|
||||
|
||||
set_expression("veryhappy", 2 SECONDS)
|
||||
|
||||
var/is_a_thing = "are [refund_amt] credit\s."
|
||||
if(!refundiscredits)
|
||||
is_a_thing = "is a freshly synthesised costume!"
|
||||
if(prob(funnyprob))
|
||||
is_a_thing = "is a pulse rifle! Just kidding it's a costume."
|
||||
|
||||
var/recycling = "recycling"
|
||||
if(prob(funnyprob))
|
||||
recycling = "feeding me"
|
||||
|
||||
//To imply they got a costume instead of money because it was their pinpointer they recycled
|
||||
var/the_pinpointer = "your pinpointer"
|
||||
if(!itsmypinpointer)
|
||||
the_pinpointer = "that pinpointer"
|
||||
|
||||
say("<span class='robot'>Thank you for [recycling] [the_pinpointer]! Here [is_a_thing]</span>")
|
||||
|
||||
return
|
||||
|
||||
else if(istype(I, /obj/item/pinpointer))
|
||||
set_expression("sad", 2 SECONDS)
|
||||
user_interact_cooldowns[user.real_name] = world.time + COOLDOWN_INTERACT
|
||||
|
||||
//Any other type of pinpointer can make it throw up.
|
||||
if(COOLDOWN_FINISHED(src, next_spew_tick))
|
||||
I.forceMove(loc)
|
||||
visible_message("<span class='warning'>\The [src] smartly rejects [I].</span>")
|
||||
say("BLEURRRRGH!")
|
||||
I.throw_at(user, 2, 3)
|
||||
COOLDOWN_START(src, next_spew_tick, COOLDOWN_SPEW)
|
||||
|
||||
return
|
||||
|
||||
else if(I.force)
|
||||
set_expression("sad", 2 SECONDS)
|
||||
|
||||
return ..()
|
||||
|
||||
/obj/machinery/pinpointer_dispenser/proc/set_expression(type, duration)
|
||||
cut_overlays()
|
||||
|
||||
if(machine_stat & (BROKEN|NOPOWER))
|
||||
return
|
||||
|
||||
deltimer(expression_timer)
|
||||
add_overlay(type)
|
||||
if(duration)
|
||||
expression_timer = addtimer(CALLBACK(src, .proc/set_expression, "neutral"), duration, TIMER_STOPPABLE)
|
||||
expression_timer = addtimer(CALLBACK(src, .proc/set_expression, "happy"), duration, TIMER_STOPPABLE)
|
||||
|
||||
/obj/machinery/pinpointer_dispenser/proc/pointat(atom)
|
||||
visible_message("<span class='name'>[src]</span> points at [atom].")
|
||||
new /obj/effect/temp_visual/point(atom,invisibility)
|
||||
/obj/machinery/pinpointer_dispenser/point_at(A)
|
||||
. = ..()
|
||||
visible_message("<span class='name'>[src]</span> points at [A]. [prob(funnyprob) ? "How'd it do that?" : ""]")
|
||||
|
||||
//Pinpointer itself
|
||||
/obj/item/pinpointer/wayfinding //Help players new to a station find their way around
|
||||
|
||||
Reference in New Issue
Block a user