Files
Bubberstation/code/datums/wires/vending.dm
SyncIt21 0b6101a37e General maintenance for vending machines (#91987)
## About The Pull Request
**1. Code Improvements**
- Removed unused vars `coin`, `bill` & other stuff
- Removed duplicate definition of `on_deconstruction()`
- Autodoc for a lot of procs
- Merged smaller procs into larger ones to avoid scrolling in the code
editor & reduced overhead
- Split the vending machine file into several smaller files for easy
code management

**2. Qol**
- Implemented vending machine ads. They now display random stuff on the
UI


https://github.com/user-attachments/assets/9720ea60-f268-4ca2-940d-243e3d0ac75f
- More error messages for custom & normal vendors as to why an item
could not be loaded
- Custom vending machines can be deconstructed safely via crowbar
without any explosion only after unlinking your account from the machine
else you get the same explosion. Upon deconstruction all loaded items
are moved into its restock canister meaning the machine can be safely
moved with all its products just like a regular vending machine to a new
location

**3. Fixes**
- Fixes #81917. Any returned items in the vending machine now show up as
free in the UI & won't cost credits to buy them
- Fixes #87416. Custom & normal vendors now keep track of products
removed via `Exited()` so the UI gets always updated
- Fixes #83151. Items with different names & custom prices now show up
in unique rows
- Fixes #92170 Custom vendors now show the correct icon for inserted
items
- Closes #80010. From the above fix this situation is impossible so it's
safe to close this as a duplicate
- Closes #78016 same problem as above with `Exited()` duplicate
- Custom vendors can now actually be used by players who are not the
owner instead of locking down the UI
- Vending machines keep track of `max_amount` of stocked items by hand
as well & not just RPED

**4. Refactor**
- Separates custom vending machine code from normal vending machine
code. This prime Marely focus on the `vending_machine_input` list which
now only exists inside the custom vending machine
- Compressed the UI code for vending machine so both custom & normal
vending machines can send the same data instead of separating the 2.
Overall less code
- Moved attack chain from `attackby()` to `item_interaction()` for
loading items

## Changelog
🆑
code: cleaned up vending machine code
qol: vending machines now have more product slogans you never heard
before
qol: custom & normal vending machines now have more feedback on why an
item could not be loaded
qol: vending machines now display random ads on the UI
qol: custom vending machines can be deconstructed via crowbar safely
only after unlinking your account from the machine.
qol: upon deconstructing a custom vendor all its products are moved into
its refill canister & it will be restored when reconstructing the
machine elsewhere
fix: Returned items to the vending machine now show up as free in the UI
and won't be greyed out if you don't have credits to get them back
fix: items that leave the vending machine by any means will update the
UI in all cases
fix: loading items by hand to the vending machine now respects the
max_amount for that category
fix: custom vendors can now actually be used by players who are not the
owner thus enabling them to transfer credits to the owner during
purchases & basically they do their job again
fix: custom vendors now show the correct icon for inserted items
fix: Items with different names & custom prices now show up in unique
rows in custom vendors
refactor: separated custom & normal vending machine code. Reduced UI
code & improved attack chain
/🆑

---------

Co-authored-by: MrMelbert <51863163+MrMelbert@users.noreply.github.com>
2025-08-11 14:37:13 +02:00

117 lines
4.2 KiB
Plaintext

/datum/wires/vending
holder_type = /obj/machinery/vending
proper_name = "Vending Unit"
/// Keeps track of which language is selected
var/language_iterator = 1
/datum/wires/vending/New(atom/holder)
wires = list(
WIRE_THROW, WIRE_SHOCK, WIRE_SPEAKER,
WIRE_CONTRABAND, WIRE_IDSCAN
)
add_duds(1)
var/obj/machinery/vending/vending_machine = holder
var/datum/language_holder/vending_languages = vending_machine.get_language_holder()
if(!length(vending_languages.spoken_languages))
CRASH("Vending machine [vending_machine] does not have any spoken languages in its language holder.")
// synch the current language to the language_iterator
for(var/i in vending_languages.spoken_languages)
if(vending_languages.selected_language == vending_languages.spoken_languages[i])
language_iterator = i
break
..()
/datum/wires/vending/interact(mob/user)
var/obj/machinery/vending/vending_machine = holder
if (!HAS_SILICON_ACCESS(user) && vending_machine.seconds_electrified && vending_machine.shock(user, 100))
return
return ..()
/datum/wires/vending/interactable(mob/user)
if(!..())
return FALSE
var/obj/machinery/vending/vending_machine = holder
if(!HAS_SILICON_ACCESS(user) && vending_machine.seconds_electrified)
var/mob/living/carbon/carbon_user = user
if (!istype(carbon_user) || carbon_user.should_electrocute(get_area(vending_machine)))
return FALSE
if(vending_machine.panel_open)
return TRUE
/datum/wires/vending/get_status()
var/obj/machinery/vending/vending_machine = holder
var/datum/language_holder/vending_languages = vending_machine.get_language_holder()
var/datum/language/current_language = GLOB.language_datum_instances[vending_languages.get_selected_language()]
var/list/status = list()
status += "The orange light is [vending_machine.seconds_electrified ? "on" : "off"]."
status += "The red light is [vending_machine.shoot_inventory ? "off" : "blinking"]."
status += "The green light is [vending_machine.extended_inventory ? "on" : "off"]."
status += "A [vending_machine.scan_id ? "purple" : "yellow"] light is on."
status += "A white light is [vending_machine.age_restrictions ? "on" : "off"]."
status += "The speaker light is [vending_machine.shut_up ? "off" : "on"]. The language is set to [current_language.name]."
return status
/datum/wires/vending/on_pulse(wire)
var/obj/machinery/vending/vending_machine = holder
var/datum/language_holder/vending_languages = vending_machine.get_language_holder()
switch(wire)
if(WIRE_THROW)
vending_machine.shoot_inventory = !vending_machine.shoot_inventory
if(WIRE_CONTRABAND)
vending_machine.extended_inventory = !vending_machine.extended_inventory
if(WIRE_SHOCK)
vending_machine.seconds_electrified = MACHINE_DEFAULT_ELECTRIFY_TIME
vending_machine.shock(usr, 100)
if(WIRE_IDSCAN)
vending_machine.scan_id = !vending_machine.scan_id
if(WIRE_SPEAKER)
language_iterator %= length(vending_languages.spoken_languages)
language_iterator += 1
vending_languages.selected_language = vending_languages.spoken_languages[language_iterator]
if(WIRE_AGELIMIT)
vending_machine.age_restrictions = !vending_machine.age_restrictions
/datum/wires/vending/on_cut(wire, mend, source)
var/obj/machinery/vending/vending_machine = holder
switch(wire)
if(WIRE_THROW)
vending_machine.shoot_inventory = !mend
if(WIRE_CONTRABAND)
vending_machine.extended_inventory = FALSE
if(WIRE_SHOCK)
if (mend)
vending_machine.seconds_electrified = MACHINE_NOT_ELECTRIFIED
else
vending_machine.seconds_electrified = MACHINE_ELECTRIFIED_PERMANENT
vending_machine.shock(usr, 100)
if(WIRE_IDSCAN)
vending_machine.scan_id = mend
if(WIRE_SPEAKER)
vending_machine.shut_up = mend
/**
* Shock the passed in user
*
* This checks we have power and that the passed in prob is passed, then generates some sparks
* and calls electrocute_mob on the user
*
* Arguments:
* * user - the user to shock
* * shock_chance - probability the shock happens
*/
/obj/machinery/vending/proc/shock(mob/living/user, shock_chance)
if(!istype(user) || machine_stat & (BROKEN|NOPOWER)) // unpowered, no shock
return FALSE
if(!prob(shock_chance))
return FALSE
do_sparks(5, TRUE, src)
if(electrocute_mob(user, get_area(src), src, 0.7, dist_check = TRUE))
return TRUE
return FALSE