Files
Bubberstation/code/game/atom/atom_vv.dm
Ghom 2531d69ff4 refactoring how materials effects are added to atoms (#86901)
## About The Pull Request
I'm "cooking" the materials system a bit, specifically the code
responsible for applying and removing effects. My goal is to move most
of the code to the objects-side, split it in smaller procs that can be
more easily overriden or called for object-specific modifiers and
effects, while also revamping things all around to better support items
made from multiple materials (the cleric mace will most likely be one in
this PR, with the handle and tip made of different materials).

PR NO LONGER WIP, TESTED AND ALL, CLERIC MACES CAN NOW BE MADE OF TWO
MATERIALS.

## Why It's Good For The Game
One of the nastiest flaws with the materials system is that it's just
unfeasable to have items made of multiple mats (with effects enabled)
right now, as they easily tend to override each other, where some of the
modifiers and effects should only be applied the main material.

Beside, the system's starting to show signs of its time, from the
several type checks used to apply different effects, the one letter
variables to the the material flags that are still being passed down as
arguments when you can access them from the atom/source arg anyway. It
would be disonhest of me if I went ahead and coded material fishing rods
or whatever fish fuckery with materials without ensuring it won't
further the technical debt the feature currently has.

## Changelog
🆑
refactor: Refactored materials code. report any issue.
add: Cleric maces (The autolathe-printable weapon design from outer
space) can now be made of two different materials.
balance: Buffed cleric maces a little.
fix: toolboxes' stats are now affected by materials again.
/🆑

---------

Co-authored-by: _0Steven <42909981+00-Steven@users.noreply.github.com>
2024-11-11 00:43:40 -08:00

297 lines
10 KiB
Plaintext

/**
* Return the markup to for the dropdown list for the VV panel for this atom
*
* Override in subtypes to add custom VV handling in the VV panel
*/
/atom/vv_get_dropdown()
. = ..()
VV_DROPDOWN_OPTION("", "---------")
if(!ismovable(src))
var/turf/curturf = get_turf(src)
if(curturf)
. += "<option value='?_src_=holder;[HrefToken()];adminplayerobservecoodjump=1;X=[curturf.x];Y=[curturf.y];Z=[curturf.z]'>Jump To</option>"
VV_DROPDOWN_OPTION(VV_HK_MODIFY_TRANSFORM, "Modify Transform")
VV_DROPDOWN_OPTION(VV_HK_SPIN_ANIMATION, "SpinAnimation")
VV_DROPDOWN_OPTION(VV_HK_STOP_ALL_ANIMATIONS, "Stop All Animations")
VV_DROPDOWN_OPTION(VV_HK_SHOW_HIDDENPRINTS, "Show Hiddenprint log")
VV_DROPDOWN_OPTION(VV_HK_ADD_REAGENT, "Add Reagent")
VV_DROPDOWN_OPTION(VV_HK_TRIGGER_EMP, "EMP Pulse")
VV_DROPDOWN_OPTION(VV_HK_TRIGGER_EXPLOSION, "Explosion")
VV_DROPDOWN_OPTION(VV_HK_EDIT_FILTERS, "Edit Filters")
VV_DROPDOWN_OPTION(VV_HK_EDIT_COLOR_MATRIX, "Edit Color as Matrix")
VV_DROPDOWN_OPTION(VV_HK_TEST_MATRIXES, "Test Matrices")
VV_DROPDOWN_OPTION(VV_HK_ADD_AI, "Add AI controller")
VV_DROPDOWN_OPTION(VV_HK_ARMOR_MOD, "Modify Armor")
if(greyscale_colors)
VV_DROPDOWN_OPTION(VV_HK_MODIFY_GREYSCALE, "Modify greyscale colors")
/atom/vv_do_topic(list/href_list)
. = ..()
if(!.)
return
if(href_list[VV_HK_ADD_REAGENT])
if(!check_rights(R_VAREDIT))
return
if(!reagents)
var/amount = input(usr, "Specify the reagent size of [src]", "Set Reagent Size", 50) as num|null
if(amount)
create_reagents(amount)
if(reagents)
var/chosen_id
switch(tgui_alert(usr, "Choose a method.", "Add Reagents", list("Search", "Choose from a list", "I'm feeling lucky")))
if("Search")
var/valid_id
while(!valid_id)
chosen_id = input(usr, "Enter the ID of the reagent you want to add.", "Search reagents") as null|text
if(isnull(chosen_id)) //Get me out of here!
break
if (!ispath(text2path(chosen_id)))
chosen_id = pick_closest_path(chosen_id, make_types_fancy(subtypesof(/datum/reagent)))
if (ispath(chosen_id))
valid_id = TRUE
else
valid_id = TRUE
if(!valid_id)
to_chat(usr, span_warning("A reagent with that ID doesn't exist!"))
if("Choose from a list")
chosen_id = input(usr, "Choose a reagent to add.", "Choose a reagent.") as null|anything in sort_list(subtypesof(/datum/reagent), GLOBAL_PROC_REF(cmp_typepaths_asc))
if("I'm feeling lucky")
chosen_id = pick(subtypesof(/datum/reagent))
if(chosen_id)
var/amount = input(usr, "Choose the amount to add.", "Choose the amount.", reagents.maximum_volume) as num|null
if(amount)
reagents.add_reagent(chosen_id, amount)
log_admin("[key_name(usr)] has added [amount] units of [chosen_id] to [src]")
message_admins(span_notice("[key_name(usr)] has added [amount] units of [chosen_id] to [src]"))
if(href_list[VV_HK_TRIGGER_EXPLOSION])
return SSadmin_verbs.dynamic_invoke_verb(usr, /datum/admin_verb/admin_explosion, src)
if(href_list[VV_HK_TRIGGER_EMP])
return SSadmin_verbs.dynamic_invoke_verb(usr, /datum/admin_verb/admin_emp, src)
if(href_list[VV_HK_SHOW_HIDDENPRINTS])
if(!check_rights(R_ADMIN))
return
usr.client.cmd_show_hiddenprints(src)
if(href_list[VV_HK_ARMOR_MOD])
if(!check_rights(NONE))
return
var/list/pickerlist = list()
var/list/armorlist = get_armor().get_rating_list()
for (var/i in armorlist)
pickerlist += list(list("value" = armorlist[i], "name" = i))
var/list/result = presentpicker(usr, "Modify armor", "Modify armor: [src]", Button1="Save", Button2 = "Cancel", Timeout=FALSE, inputtype = "text", values = pickerlist)
var/list/armor_all = ARMOR_LIST_ALL()
if(islist(result))
if(result["button"] != 2) // If the user pressed the cancel button
// text2num conveniently returns a null on invalid values
var/list/converted = list()
for(var/armor_key in armor_all)
converted[armor_key] = text2num(result["values"][armor_key])
set_armor(get_armor().generate_new_with_specific(converted))
var/message = "[key_name(usr)] modified the armor on [src] ([type]) to: "
for(var/armor_key in armor_all)
message += "[armor_key]=[get_armor_rating(armor_key)],"
message = copytext(message, 1, -1)
log_admin(span_notice(message))
message_admins(span_notice(message))
if(href_list[VV_HK_ADD_AI])
if(!check_rights(R_VAREDIT))
return
var/result = input(usr, "Choose the AI controller to apply to this atom WARNING: Not all AI works on all atoms.", "AI controller") as null|anything in subtypesof(/datum/ai_controller)
if(!result)
return
ai_controller = new result(src)
if(href_list[VV_HK_MODIFY_TRANSFORM])
if(!check_rights(R_VAREDIT))
return
var/result = input(usr, "Choose the transformation to apply","Transform Mod") as null|anything in list("Scale","Translate","Rotate","Shear")
var/matrix/M = transform
if(!result)
return
switch(result)
if("Scale")
var/x = input(usr, "Choose x mod","Transform Mod") as null|num
var/y = input(usr, "Choose y mod","Transform Mod") as null|num
if(isnull(x) || isnull(y))
return
transform = M.Scale(x,y)
if("Translate")
var/x = input(usr, "Choose x mod (negative = left, positive = right)","Transform Mod") as null|num
var/y = input(usr, "Choose y mod (negative = down, positive = up)","Transform Mod") as null|num
if(isnull(x) || isnull(y))
return
transform = M.Translate(x,y)
if("Shear")
var/x = input(usr, "Choose x mod","Transform Mod") as null|num
var/y = input(usr, "Choose y mod","Transform Mod") as null|num
if(isnull(x) || isnull(y))
return
transform = M.Shear(x,y)
if("Rotate")
var/angle = input(usr, "Choose angle to rotate","Transform Mod") as null|num
if(isnull(angle))
return
transform = M.Turn(angle)
SEND_SIGNAL(src, COMSIG_ATOM_VV_MODIFY_TRANSFORM)
if(href_list[VV_HK_SPIN_ANIMATION])
if(!check_rights(R_VAREDIT))
return
var/num_spins = input(usr, "Do you want infinite spins?", "Spin Animation") in list("Yes", "No")
if(num_spins == "No")
num_spins = input(usr, "How many spins?", "Spin Animation") as null|num
else
num_spins = -1
if(!num_spins)
return
var/spin_speed = input(usr, "How fast?", "Spin Animation") as null|num
if(!spin_speed)
return
var/direction = input(usr, "Which direction?", "Spin Animation") in list("Clockwise", "Counter-clockwise")
switch(direction)
if("Clockwise")
direction = 1
if("Counter-clockwise")
direction = 0
else
return
SpinAnimation(spin_speed, num_spins, direction)
if(href_list[VV_HK_STOP_ALL_ANIMATIONS])
if(!check_rights(R_VAREDIT))
return
var/result = input(usr, "Are you sure?", "Stop Animating") in list("Yes", "No")
if(result == "Yes")
animate(src, transform = null, flags = ANIMATION_END_NOW) // Literally just fucking stop animating entirely because admin said so
return
if(href_list[VV_HK_AUTO_RENAME])
if(!check_rights(R_VAREDIT))
return
var/newname = input(usr, "What do you want to rename this to?", "Automatic Rename") as null|text
// Check the new name against the chat filter. If it triggers the IC chat filter, give an option to confirm.
if(newname && !(is_ic_filtered(newname) || is_soft_ic_filtered(newname) && tgui_alert(usr, "Your selected name contains words restricted by IC chat filters. Confirm this new name?", "IC Chat Filter Conflict", list("Confirm", "Cancel")) != "Confirm"))
vv_auto_rename(newname)
if(href_list[VV_HK_EDIT_FILTERS])
if(!check_rights(R_VAREDIT))
return
usr.client?.open_filter_editor(src)
if(href_list[VV_HK_EDIT_COLOR_MATRIX])
if(!check_rights(R_VAREDIT))
return
usr.client?.open_color_matrix_editor(src)
if(href_list[VV_HK_TEST_MATRIXES])
if(!check_rights(R_VAREDIT))
return
usr.client?.open_matrix_tester(src)
/atom/vv_get_header()
. = ..()
var/refid = REF(src)
. += "[VV_HREF_TARGETREF(refid, VV_HK_AUTO_RENAME, "<b id='name'>[src]</b>")]"
. += "<br><font size='1'><a href='?_src_=vars;[HrefToken()];rotatedatum=[refid];rotatedir=left'><<</a> <a href='?_src_=vars;[HrefToken()];datumedit=[refid];varnameedit=dir' id='dir'>[dir2text(dir) || dir]</a> <a href='?_src_=vars;[HrefToken()];rotatedatum=[refid];rotatedir=right'>>></a></font>"
/**
* call back when a var is edited on this atom
*
* Can be used to implement special handling of vars
*
* At the atom level, if you edit a var named "color" it will add the atom colour with
* admin level priority to the atom colours list
*
* Also, if GLOB.Debug2 is FALSE, it sets the [ADMIN_SPAWNED_1] flag on [flags_1][/atom/var/flags_1], which signifies
* the object has been admin edited
*/
/atom/vv_edit_var(var_name, var_value)
var/old_light_flags = light_flags
// Disable frozen lights for now, so we can actually modify it
light_flags &= ~LIGHT_FROZEN
switch(var_name)
if(NAMEOF(src, light_range))
if(light_system == COMPLEX_LIGHT)
set_light(l_range = var_value)
else
set_light_range(var_value)
. = TRUE
if(NAMEOF(src, light_power))
if(light_system == COMPLEX_LIGHT)
set_light(l_power = var_value)
else
set_light_power(var_value)
. = TRUE
if(NAMEOF(src, light_color))
if(light_system == COMPLEX_LIGHT)
set_light(l_color = var_value)
else
set_light_color(var_value)
. = TRUE
if(NAMEOF(src, light_angle))
if(light_system == COMPLEX_LIGHT)
set_light(l_angle = var_value)
. = TRUE
if(NAMEOF(src, light_dir))
if(light_system == COMPLEX_LIGHT)
set_light(l_dir = var_value)
. = TRUE
if(NAMEOF(src, light_height))
if(light_system == COMPLEX_LIGHT)
set_light(l_height = var_value)
. = TRUE
if(NAMEOF(src, light_on))
if(light_system == COMPLEX_LIGHT)
set_light(l_on = var_value)
else
set_light_on(var_value)
. = TRUE
if(NAMEOF(src, light_flags))
set_light_flags(var_value)
// I'm sorry
old_light_flags = var_value
. = TRUE
if(NAMEOF(src, smoothing_junction))
set_smoothed_icon_state(var_value)
. = TRUE
if(NAMEOF(src, opacity))
set_opacity(var_value)
. = TRUE
if(NAMEOF(src, base_pixel_x))
set_base_pixel_x(var_value)
. = TRUE
if(NAMEOF(src, base_pixel_y))
set_base_pixel_y(var_value)
. = TRUE
if(NAMEOF(src, material_flags))
toggle_material_flags(var_value)
. = TRUE
if(NAMEOF(src, material_modifier))
change_material_modifier(var_value)
. = TRUE
light_flags = old_light_flags
if(!isnull(.))
datum_flags |= DF_VAR_EDITED
return
if(!GLOB.Debug2)
flags_1 |= ADMIN_SPAWNED_1
. = ..()
switch(var_name)
if(NAMEOF(src, color))
add_atom_colour(color, ADMIN_COLOUR_PRIORITY)
update_appearance()
/atom/proc/vv_auto_rename(newname)
name = newname