Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

[EARLY MIRROR] Empty & Universal Medipens in Medical Lathe #3577 #5257

Open
wants to merge 48 commits into
base: master
Choose a base branch
from
Open
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
48 commits
Select commit Hold shift + click to select a range
ee9efe6
Add lathe_medipens module for bounty
Floofies Jul 6, 2024
6086076
Add whitelist to medipen refiller
Floofies Jul 7, 2024
212ca29
Add low pressure medipen design
Floofies Jul 7, 2024
5b2a18b
Fix typo in medbay medipen node
Floofies Jul 7, 2024
88c9740
Update sprites for lathe medipens
Floofies Jul 7, 2024
66a36c7
Add low pressure universal medipen, update icons
Floofies Jul 7, 2024
f6b8928
Add readme for lathe_medipens module
Floofies Jul 8, 2024
1bb4d06
Cleanup edits to medipen refiller
Floofies Jul 8, 2024
09eb264
Finish icons for universal medipens
Floofies Jul 8, 2024
2919c4a
Macro-ize empty medipen subtypes, add overrides to allow medipens to …
Floofies Jul 8, 2024
e5929b0
Fix typos in typepaths, update buildpaths
Floofies Jul 8, 2024
4d6c142
Add missing nova edit comments, change comment names
Floofies Jul 8, 2024
5c3c340
Fix icon for low pressure universal medipen
Floofies Jul 8, 2024
05731f4
Refine init_reagents into init_empty, fix icon states
Floofies Jul 8, 2024
e59b106
Remove extra slash in typepath
Floofies Jul 8, 2024
c5f1ec3
Swap init_reagents for init_empty, set label text correctly for empty…
Floofies Jul 8, 2024
810ce22
Create new master file hypospray.dm to implement var init_empty, whic…
Floofies Jul 8, 2024
a0526d5
Reflect new master file creation in readme
Floofies Jul 8, 2024
9d59101
Remove overrides
Floofies Jul 8, 2024
0d615c7
Add empty variants of medipens to medipen refiller whitelist
Floofies Jul 9, 2024
0693830
Remove macros, add medipen/inject() override, add medipen/var/unused
Floofies Jul 9, 2024
ab88c96
Update readme
Floofies Jul 9, 2024
d428987
Add init_empty to universal medipen
Floofies Jul 9, 2024
07e45aa
Make balloon message more concise
Floofies Jul 9, 2024
54045df
Add missing info to readme
Floofies Jul 9, 2024
3aba555
Remove worn icon var
Floofies Jul 9, 2024
bc65595
Add missing TG proc changes to readme
Floofies Jul 9, 2024
e80c584
Refactor volume calc code into trans_to_equal
Floofies Aug 4, 2024
997ae32
Refactored naive solution again for trans_to_equal
Floofies Aug 8, 2024
e108333
Cleaning up
Floofies Aug 13, 2024
4b6464c
Cleaning up comments and refining
Floofies Aug 13, 2024
970e23b
Improve type safety
Floofies Sep 1, 2024
d3e9d20
Improve type safety
Floofies Sep 1, 2024
691b1fb
Improve type safety
Floofies Sep 1, 2024
afcc3fa
Cleanup list accesses
Floofies Sep 1, 2024
a1877c2
Add workaround for reagent flags reset on injection, fix overlay and …
Floofies Oct 7, 2024
94ca574
Fix alert bug
Floofies Oct 7, 2024
bfadac8
Change universal medipens to require TECHWEB_NODE_CHEM_SYNTHESIS and …
Floofies Oct 7, 2024
a43b318
Refactor naive solution
Floofies Oct 7, 2024
84f58c9
Cleaning up unused vars and a oversight
Floofies Oct 11, 2024
efc7837
Fixing refiller logic to make more sense to the user
Floofies Oct 11, 2024
e635d3f
Add inhand sprites for universal medipens
Floofies Oct 11, 2024
eadc4eb
Shorten description for medbay_medipens
Floofies Oct 11, 2024
5cff671
Update readme
Floofies Oct 11, 2024
0948289
Update modular_nova/master_files/code/modules/reagents/chemistry/hold…
Floofies Nov 4, 2024
efc1650
Apply suggestions from code review
Floofies Nov 4, 2024
46f4e2a
Update code/game/machinery/medipen_refiller.dm
vinylspiders Dec 20, 2024
abb6a0e
Update code/game/machinery/medipen_refiller.dm
vinylspiders Dec 20, 2024
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
1 change: 1 addition & 0 deletions code/__DEFINES/~nova_defines/techweb_nodes.dm
Original file line number Diff line number Diff line change
Expand Up @@ -15,6 +15,7 @@
#define TECHWEB_NODE_CYBERNETICS_DIGITIGRADE_ADVANCED "adv_digitigrade_cyber"
#define TECHWEB_NODE_CYBERNETICS_TESHARI "teshari_cyber"
#define TECHWEB_NODE_CYBERNETICS_TESHARI_ADVANCED "adv_teshari_cyber"
#define TECHWEB_NODE_MEDBAY_MEDIPENS "medbay_medipens"
#define TECHWEB_NODE_MUTANT_TECH "mutant_tech"
#define TECHWEB_NODE_NIGHT_VISION_IMPLANTS "nv_implants"
#define TECHWEB_NODE_ROBOTIC_SURGERY "improved_robotic_surgery"
Expand Down
57 changes: 53 additions & 4 deletions code/game/machinery/medipen_refiller.dm
Original file line number Diff line number Diff line change
Expand Up @@ -19,7 +19,28 @@
/obj/item/reagent_containers/hypospray/medipen/survival = /datum/reagent/medicine/c2/libital,
/obj/item/reagent_containers/hypospray/medipen/survival/luxury = /datum/reagent/medicine/c2/penthrite,
/obj/item/reagent_containers/hypospray/medipen/invisibility = /datum/reagent/drug/saturnx,
// NOVA EDIT ADDITION BEGIN - Universal medipens and lathe medipens
/obj/item/reagent_containers/hypospray/medipen/universal = null,
/obj/item/reagent_containers/hypospray/medipen/universal/lowpressure = null,
/obj/item/reagent_containers/hypospray/medipen/empty = /datum/reagent/medicine/epinephrine,
/obj/item/reagent_containers/hypospray/medipen/atropine/empty = /datum/reagent/medicine/atropine,
/obj/item/reagent_containers/hypospray/medipen/salbutamol/empty = /datum/reagent/medicine/salbutamol,
/obj/item/reagent_containers/hypospray/medipen/oxandrolone/empty = /datum/reagent/medicine/oxandrolone,
/obj/item/reagent_containers/hypospray/medipen/salacid/empty = /datum/reagent/medicine/sal_acid,
/obj/item/reagent_containers/hypospray/medipen/penacid/empty = /datum/reagent/medicine/pen_acid,
// NOVA EDIT ADDITION END
)
// NOVA EDIT ADDITION BEGIN - Universal medipens
///Whitelist typecache of reagent types which are allowed to refill universal medipens.
var/static/list/medipen_reagent_whitelist = typecacheof(list(
/datum/reagent/medicine,
/datum/reagent/vaccine,
))
///Blacklist typecache of reagent types which are disallowed to refill universal medipens.
var/static/list/medipen_reagent_blacklist = typecacheof(list(
/datum/reagent/medicine/morphine,
))
// NOVA EDIT ADDITION END

/obj/machinery/medipen_refiller/Initialize(mapload)
. = ..()
Expand All @@ -37,7 +58,9 @@
context[SCREENTIP_CONTEXT_LMB] = panel_open ? "Close panel" : "Open panel"
else if(is_reagent_container(held_item) && held_item.is_open_container())
context[SCREENTIP_CONTEXT_LMB] = "Refill machine"
else if(istype(held_item, /obj/item/reagent_containers/hypospray/medipen) && reagents.has_reagent(allowed_pens[held_item.type]))
// NOVA EDIT CHANGE - ORIGINAL: else if(istype(held_item, /obj/item/reagent_containers/hypospray/medipen) && reagents.has_reagent(allowed_pens[held_item.type]))
else if(istype(held_item, /obj/item/reagent_containers/hypospray/medipen/universal) || istype(held_item, /obj/item/reagent_containers/hypospray/medipen) && reagents.has_reagent(allowed_pens[held_item.type]))
// NOVA EDIT CHANGE END
context[SCREENTIP_CONTEXT_LMB] = "Refill medipen"
else if(istype(held_item, /obj/item/plunger))
context[SCREENTIP_CONTEXT_LMB] = "Plunge machine"
Expand Down Expand Up @@ -76,14 +99,40 @@
if(medipen.reagents?.reagent_list.len)
balloon_alert(user, "medipen full!")
return
if(!reagents.has_reagent(allowed_pens[medipen.type], 10))
//if(!reagents.has_reagent(allowed_pens[medipen.type], 10)) // NOVA EDIT REMOVAL
// NOVA EDIT ADDITION BEGIN - Universal medipen and lathe medipens
var/list/datum/reagent/compatible_universal_reagents
if(istype(medipen, /obj/item/reagent_containers/hypospray/medipen/universal))
if(!reagents.total_volume)
balloon_alert(user, "not enough reagents!")
return
// Ignore reagents which aren't the blacklist or whitelist
compatible_universal_reagents = typecache_filter_multi_list_exclusion(reagents.reagent_list, medipen_reagent_whitelist, medipen_reagent_blacklist)
// Ensure there is enough of the whitelisted reagents
if(!length(compatible_universal_reagents))
balloon_alert(user, "reagents incompatible!")
return
else if(!reagents.has_reagent(allowed_pens[medipen.type], medipen.volume))
// NOVA EDIT ADDITION END
balloon_alert(user, "not enough reagents!")
return
add_overlay("active")
if(do_after(user, 2 SECONDS, src))
// NOVA EDIT ADDITION BEGIN - Universal medipen and lathe medipens
if(istype(medipen, /obj/item/reagent_containers/hypospray/medipen/universal))
// Create list of transferable reagent typepaths
var/list/target_reagent_types = list()
for(var/datum/reagent/target_reagent as anything in compatible_universal_reagents)
target_reagent_types += target_reagent.type
// Transfer proportionally distributed amounts of each reagent
reagents.trans_to_multiple(target_atom = medipen, amount = medipen.volume, target_ids = target_reagent_types)
else
medipen.add_initial_reagents()
reagents.remove_reagent(allowed_pens[medipen.type], medipen.volume)
// NOVA EDIT ADDITION END
medipen.used_up = FALSE
medipen.add_initial_reagents()
reagents.remove_reagent(allowed_pens[medipen.type], 10)
//medipen.add_initial_reagents() // NOVA EDIT REMOVAL - Handled above
//reagents.remove_reagent(allowed_pens[medipen.type], 10) // NOVA EDIT REMOVAL - Handled above
balloon_alert(user, "refilled")
use_energy(active_power_usage)
cut_overlays()
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -15,3 +15,101 @@
return TRUE

return FALSE

/**
* Proportionally transfers each reagent to the target atom. Calls trans_to() to do the actual transfer.
* Unlike trans_to(), target_id is replaced with list target_ids.
*
* Arguments:
* * obj/target - Target atom to attempt transfers to
* * amount - Maximum total reagent volume to transfer
* * multiplier - multiplies each reagent amount by this number well byond their available volume before transfering. used to create reagents from thin air if you ever need to
* * list/datum/reagent/target_ids - transfers only the listed reagent types in this holder leaving others untouched
* * preserve_data - if preserve_data=FALSE, the reagents data will be lost. Usefull if you use data for some strange stuff and don't want it to be transferred.
* * no_react - passed through to [/datum/reagents/proc/add_reagent]
* * mob/transferred_by - used for logging
* * remove_blacklisted - skips transferring of reagents without REAGENT_CAN_BE_SYNTHESIZED in chemical_flags
* * methods - passed through to [/datum/reagents/proc/expose] and [/datum/reagent/proc/on_transfer]
* * show_message - passed through to [/datum/reagents/proc/expose]
* * ignore_stomach - when using methods INGEST will not use the stomach as the target
*/
/datum/reagents/proc/trans_to_multiple(
atom/target_atom,
amount = 1,
multiplier = 1,
list/datum/reagent/target_ids,
preserve_data = TRUE,
no_react = FALSE,
mob/transferred_by,
remove_blacklisted = FALSE,
methods = NONE,
show_message = TRUE,
ignore_stomach = FALSE,
)
// Nothing to transfer, or the targeted atom can't hold reagents
if(!total_volume || QDELETED(target_atom) || isnull(target_atom.reagents))
return FALSE

if(!IS_FINITE(amount))
stack_trace("non-number or infinite number passed to trans_to_equal: amount = [amount]")
return FALSE

// Ensure given amount is in a safe range
amount = round(amount, CHEMICAL_QUANTISATION_LEVEL)
if(amount <= 0)
return FALSE

// Maximum amount of reagents which can fit inside the target
var/max_volume = min(amount, target_atom.reagents.maximum_volume)
// Total volume of fillable empty space inside the target, accounting for given maximum
var/empty_volume = max(0, max_volume - target_atom.reagents.total_volume)

// Targeted atom is already full of reagents
if(max_volume == 0 || empty_volume == 0)
return FALSE

// Total volume of transferable reagents after whitelisting and rounding
var/possible_transfer_volume = 0
// Only FALSE if a reagent whitelist was given
var/ignore_whitelist = isnull(target_ids)
// Associative list of reagent typepaths to datums
var/list/datum/reagent/target_reagents = list()
var/list/cached_reagents = reagent_list
// Perform whitelisting, then calculate total possible transfer volume
for(var/datum/reagent/reagent as anything in cached_reagents)
if(remove_blacklisted && !(reagent.chemical_flags & REAGENT_CAN_BE_SYNTHESIZED))
continue
if(ignore_whitelist || is_type_in_list(reagent, target_ids) && reagent.volume)
target_reagents[reagent.type] = reagent
possible_transfer_volume += reagent.volume

// There are no transferable reagents
if(!length(target_reagents) || !possible_transfer_volume)
return FALSE

// Associative list of reagent typepaths to transfer volumes
// Used to provide reagent transfer amounts to trans_to()
var/list/transfer_volumes = list()
// Calculate proportional transfer volumes per reagent
// Account for reagents with insufficient and excess volumes
for(var/reagent_type as anything in target_reagents)
var/datum/reagent/reagent = target_reagents[reagent_type]
var/distributed_volume = round(reagent.volume / possible_transfer_volume, CHEMICAL_QUANTISATION_LEVEL)
transfer_volumes[reagent.type] = empty_volume * distributed_volume

// Actually perform the reagent transfers and return total volume transferred
var/transfer_total = 0
for(var/datum/reagent/reagent as anything in target_reagents)
transfer_total += trans_to(
target = target_atom,
amount = transfer_volumes[reagent],
target_id = reagent.type,
preserve_data = preserve_data,
no_react = no_react,
transferred_by = transferred_by,
remove_blacklisted = remove_blacklisted,
methods = methods,
show_message = show_message,
ignore_stomach = ignore_stomach,
)
return transfer_total
Original file line number Diff line number Diff line change
@@ -0,0 +1,58 @@
/obj/item/reagent_containers/hypospray/medipen
/// If TRUE, the medipen will initialize without reagents
var/init_empty = FALSE
/// If TRUE, indicates that the medipen hasn't been injected by a mob yet
var/unused = TRUE

// Allows medipens to initialize without reagents if init_empty is TRUE
/obj/item/reagent_containers/hypospray/medipen/Initialize(mapload)
if(init_empty != TRUE)
return ..()

// Temporarily sets list_reagents to null to avoid filling the medipen
var/initial_reagents = list_reagents
list_reagents = null
. = ..()
list_reagents = initial_reagents

if(label_examine)
var/reagent_types = assoc_to_keys(list_reagents)
// Set label text via list_reagents, due to actual reagents being empty
label_text = span_notice("There is a sticker pasted onto the side which reads, 'WARNING: This medipen contains [pretty_string_from_reagent_list(reagent_types, names_only = TRUE, join_text = ", ", final_and = TRUE, capitalize_names = TRUE)], do not use if allergic to any listed chemicals.")

// Sends a more generic chat message when an unused medipen is empty
/obj/item/reagent_containers/hypospray/medipen/inject(mob/living/affected_mob, mob/user)
if(!reagents?.total_volume || (init_empty && used_up && unused))
to_chat(user, span_warning("You push [src]'s button, but nothing happens. It's empty!"))
return FALSE

// Attempt the injection
. = ..()

// If the injection succeeded, then the medipen is not unused anymore
if(unused && .)
unused = FALSE

/obj/item/reagent_containers/hypospray/medipen/empty
init_empty = TRUE
used_up = TRUE

/obj/item/reagent_containers/hypospray/medipen/atropine/empty
init_empty = TRUE
used_up = TRUE

/obj/item/reagent_containers/hypospray/medipen/salbutamol/empty
init_empty = TRUE
used_up = TRUE

/obj/item/reagent_containers/hypospray/medipen/oxandrolone/empty
init_empty = TRUE
used_up = TRUE

/obj/item/reagent_containers/hypospray/medipen/salacid/empty
init_empty = TRUE
used_up = TRUE

/obj/item/reagent_containers/hypospray/medipen/penacid/empty
init_empty = TRUE
used_up = TRUE
37 changes: 37 additions & 0 deletions modular_nova/modules/lathe_medipens/README.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,37 @@
https://github.com/NovaSector/NovaSector/pull/3577

## Title: Lathe Medipens

MODULE ID: lathe_medipens

### Description:

Contains empty subtypes of several medipens, custom/universal medipen subtypes with new icons, and techweb nodes/designs for them.

### TG Proc Changes:

- `/obj/item/reagent_containers/hypospray/medipen/Initialize()`
- `/obj/item/reagent_containers/hypospray/medipen/inject()`
- `/obj/machinery/medipen_refiller/add_context()`
- `/obj/machinery/medipen_refiller/attackby()`

### Defines:

- N/A

### Master file additions

- `modular_nova/master_files/code/modules/reagents/reagent_containers/hypospray.dm`
- Overrides `Initialize()` and `inject()`.
- Adds new variables `medipen/var/init_empty` and `medipen/var/unused`.
- `modular_nova/master_files/code/modules/reagents/chemistry/holder.dm`
- Adds new proc `/datum/reagents/proc/trans_to_multiple()`

### Included files that are not contained in this module:

Dependent to avoid runtime errors:

- `modular_nova/master_files/code/modules/reagents/reagent_containers/hypospray.dm`

### Credits:
- [@Floofies](https://github.com/Floofies)
57 changes: 57 additions & 0 deletions modular_nova/modules/lathe_medipens/code/autolathe_designs.dm
Original file line number Diff line number Diff line change
@@ -0,0 +1,57 @@
// Basetype for developer usage only. Shouldn't be visible ingame.
/datum/design/medipen
name = "Medipen Basetype"
id = DESIGN_ID_IGNORE
build_type = PROTOLATHE | AWAY_LATHE
materials = list(
/datum/material/plastic = SHEET_MATERIAL_AMOUNT * 3,
/datum/material/glass = SHEET_MATERIAL_AMOUNT * 2,
/datum/material/iron = SMALL_MATERIAL_AMOUNT * 0.1,
/datum/material/silver = SHEET_MATERIAL_AMOUNT,
)
build_path = /obj/item/reagent_containers/hypospray/medipen
category = list(
RND_CATEGORY_INITIAL,
RND_CATEGORY_EQUIPMENT + RND_SUBCATEGORY_EQUIPMENT_CHEMISTRY,
)
departmental_flags = DEPARTMENT_BITFLAG_MEDICAL

/datum/design/medipen/universal
name = "Universal Medipen"
id = "medipen_universal"
build_path = /obj/item/reagent_containers/hypospray/medipen/universal

/datum/design/medipen/universal_lowpressure
name = "Universal Low-Pressure Medipen"
id = "medipen_universal_lowpressure"
build_path = /obj/item/reagent_containers/hypospray/medipen/universal/lowpressure

/datum/design/medipen/epinephrine
name = "Epinephrine Medipen"
id = "medipen_epinephrine"
build_path = /obj/item/reagent_containers/hypospray/medipen/empty

/datum/design/medipen/atropine
name = "Atropine Medipen"
id = "medipen_atropine"
build_path = /obj/item/reagent_containers/hypospray/medipen/atropine/empty

/datum/design/medipen/salbutamol
name = "Salbutamol Medipen"
id = "medipen_salbutamol"
build_path = /obj/item/reagent_containers/hypospray/medipen/salbutamol/empty

/datum/design/medipen/oxandrolone
name = "Oxandrolone Medipen"
id = "medipen_oxandrolone"
build_path = /obj/item/reagent_containers/hypospray/medipen/oxandrolone/empty

/datum/design/medipen/salacid
name = "Salicylic Acid Medipen"
id = "medipen_salacid"
build_path = /obj/item/reagent_containers/hypospray/medipen/salacid/empty

/datum/design/medipen/penacid
name = "Pentetic Acid Medipen"
id = "medipen_penacid"
build_path = /obj/item/reagent_containers/hypospray/medipen/penacid/empty
Loading
Loading