diff --git a/code/__HELPERS/duplicating.dm b/code/__HELPERS/duplicating.dm new file mode 100644 index 00000000000..e15f375d20a --- /dev/null +++ b/code/__HELPERS/duplicating.dm @@ -0,0 +1,93 @@ +///List of all vars that will not be copied over when using duplicate_object() +GLOBAL_LIST_INIT(duplicate_forbidden_vars, list( + "actions", + "active_hud_list", + "active_timers", + "AIStatus", + "appearance", + "area", + "atmos_adjacent_turfs", + "bodyparts", + "ckey", + "comp_lookup", + "computer_id", + "contents", + "cooldowns", + "datum_components", + "external_organs", + "external_organs_slot", + "group", + "hand_bodyparts", + "held_items", + "hud_list", + "implants", + "important_recursive_contents", + "internal_organs", + "internal_organs_slot", + "key", + "lastKnownIP", + "loc", + "locs", + "managed_overlays", + "managed_vis_overlays", + "overlays", + "overlays_standing", + "parent", + "parent_type", + "power_supply", + "quirks", + "reagents", + "signal_procs", + "status_traits", + "stat", + "tag", + "tgui_shared_states", + "type", + "vars", + "verbs", + "x", "y", "z", +)) +GLOBAL_PROTECT(duplicate_forbidden_vars) + +/** + * # duplicate_object + * + * Makes a copy of an item and transfers most vars over, barring GLOB.duplicate_forbidden_vars + * Args: + * original - Atom being duplicated + * spawning_location - Turf where the duplicated atom will be spawned at. + */ +/proc/duplicate_object(atom/original, turf/spawning_location) + RETURN_TYPE(original.type) + if(!original) + return + + var/atom/made_copy = new original.type(spawning_location) + + for(var/atom_vars in original.vars - GLOB.duplicate_forbidden_vars) + if(islist(original.vars[atom_vars])) + var/list/var_list = original.vars[atom_vars] + made_copy.vars[atom_vars] = var_list.Copy() + continue + else if(istype(original.vars[atom_vars], /datum) || ismob(original.vars[atom_vars])) + continue // this would reference the original's object, that will break when it is used or deleted. + made_copy.vars[atom_vars] = original.vars[atom_vars] + + if(isliving(made_copy)) + if(iscarbon(made_copy)) + var/mob/living/carbon/original_carbon = original + var/mob/living/carbon/copied_carbon = made_copy + //transfer DNA over (also body features), then update skin color. + original_carbon.dna.transfer_identity(copied_carbon, transfer_SE = TRUE) + copied_carbon.updateappearance(mutcolor_update = TRUE) + + var/mob/living/original_living = original + //transfer implants, we do this so the original's implants being removed won't destroy ours. + for(var/obj/item/implant/original_implants as anything in original_living.implants) + var/obj/item/implant/copied_implant = new original_implants.type + copied_implant.implant(made_copy, silent = TRUE, force = TRUE) + //transfer quirks, we do this because transfering the original's quirks keeps the 'owner' as the original. + for(var/datum/quirk/original_quirks as anything in original_living.quirks) + original_living.add_quirk(original_quirks.type) + + return made_copy diff --git a/code/modules/admin/topic.dm b/code/modules/admin/topic.dm index 7dfc03e22c7..c5a77df1b46 100644 --- a/code/modules/admin/topic.dm +++ b/code/modules/admin/topic.dm @@ -1212,7 +1212,7 @@ else if(href_list["dupe_marked_datum"]) if(!check_rights(R_SPAWN)) return - return DuplicateObject(marked_datum, perfectcopy=1, newloc=get_turf(usr)) + return duplicate_object(marked_datum, spawning_location = get_turf(usr)) else if(href_list["object_list"]) //this is the laggiest thing ever if(!check_rights(R_SPAWN)) diff --git a/code/modules/buildmode/submodes/copy.dm b/code/modules/buildmode/submodes/copy.dm index 739f53e9bc8..9effd1d9c30 100644 --- a/code/modules/buildmode/submodes/copy.dm +++ b/code/modules/buildmode/submodes/copy.dm @@ -18,7 +18,7 @@ if(LAZYACCESS(modifiers, LEFT_CLICK)) var/turf/T = get_turf(object) if(stored) - DuplicateObject(stored, perfectcopy=1, sameloc=0,newloc=T) + duplicate_object(stored, spawning_location = T) log_admin("Build Mode: [key_name(c)] copied [stored] to [AREACOORD(object)]") else if(LAZYACCESS(modifiers, RIGHT_CLICK)) if(ismovable(object)) // No copying turfs for now. diff --git a/code/modules/cargo/centcom_podlauncher.dm b/code/modules/cargo/centcom_podlauncher.dm index baec0b57829..8c25da21cf2 100644 --- a/code/modules/cargo/centcom_podlauncher.dm +++ b/code/modules/cargo/centcom_podlauncher.dm @@ -42,7 +42,7 @@ var/bayNumber //Quick reference to what bay we're in. Usually set to the loading_id variable for the related area type var/customDropoff = FALSE var/picking_dropoff_turf = FALSE - var/launchClone = FALSE //If true, then we don't actually launch the thing in the bay. Instead we call duplicateObject() and send the result + var/launchClone = FALSE //If true, then we don't actually launch the thing in the bay. Instead we call duplicate_object() and send the result var/launchRandomItem = FALSE //If true, lauches a single random item instead of everything on a turf. var/launchChoice = LAUNCH_RANDOM //Determines if we launch all at once (0) , in order (1), or at random(2) var/explosionChoice = 0 //Determines if there is no explosion (0), custom explosion (1), or just do a maxcap (2) @@ -721,7 +721,7 @@ /datum/centcom_podlauncher/proc/launch(turf/target_turf) //Game time started if (isnull(target_turf)) return - var/obj/structure/closet/supplypod/centcompod/toLaunch = DuplicateObject(temp_pod) //Duplicate the temp_pod (which we have been varediting or configuring with the UI) and store the result + var/obj/structure/closet/supplypod/centcompod/toLaunch = duplicate_object(temp_pod) //Duplicate the temp_pod (which we have been varediting or configuring with the UI) and store the result toLaunch.update_appearance()//we update_appearance() here so that the door doesnt "flicker on" right after it lands var/shippingLane = GLOB.areas_by_type[/area/centcom/central_command_areas/supplypod/supplypod_temp_holding] toLaunch.forceMove(shippingLane) @@ -734,7 +734,7 @@ toLaunch.turfs_in_cargo += atom_to_launch.type else var/atom/movable/movable_to_launch = launch_candidate - DuplicateObject(movable_to_launch).forceMove(toLaunch) //Duplicate a single atom/movable from launchList and forceMove it into the supplypod + duplicate_object(movable_to_launch).forceMove(toLaunch) //Duplicate a single atom/movable from launchList and forceMove it into the supplypod else for (var/launch_candidate in launchList) if (isnull(launch_candidate)) @@ -744,7 +744,7 @@ toLaunch.turfs_in_cargo += turf_to_launch.type else var/atom/movable/movable_to_launch = launch_candidate - DuplicateObject(movable_to_launch).forceMove(toLaunch) //Duplicate each atom/movable in launchList and forceMove them into the supplypod + duplicate_object(movable_to_launch).forceMove(toLaunch) //Duplicate each atom/movable in launchList and forceMove them into the supplypod else if(launchRandomItem) var/atom/random_item = pick_n_take(launchList) diff --git a/code/modules/holodeck/area_copy.dm b/code/modules/holodeck/area_copy.dm deleted file mode 100644 index 054f5d59abc..00000000000 --- a/code/modules/holodeck/area_copy.dm +++ /dev/null @@ -1,147 +0,0 @@ -//Vars that will not be copied when using /DuplicateObject -GLOBAL_LIST_INIT(duplicate_forbidden_vars,list( - "tag", "datum_components", "area", "type", "loc", "locs", "vars", "parent", "parent_type", "verbs", "ckey", "key", - "power_supply", "contents", "reagents", "stat", "x", "y", "z", "group", "atmos_adjacent_turfs", "comp_lookup", - "important_recursive_contents", "bodyparts", "internal_organs", "hand_bodyparts", "overlays_standing", "hud_list", - "actions", "AIStatus", "appearance", "managed_overlays", "managed_vis_overlays", "computer_id", "lastKnownIP", "implants", - "tgui_shared_states" - )) - -/proc/DuplicateObject(atom/original, perfectcopy = TRUE, sameloc, atom/newloc = null, nerf, holoitem) - RETURN_TYPE(original.type) - if(!original) - return - var/atom/O - - if(sameloc) - O = new original.type(original.loc) - else - O = new original.type(newloc) - - if(perfectcopy && O && original) - for(var/V in original.vars - GLOB.duplicate_forbidden_vars) - if(islist(original.vars[V])) - var/list/L = original.vars[V] - O.vars[V] = L.Copy() - else if(istype(original.vars[V], /datum) || ismob(original.vars[V])) - continue // this would reference the original's object, that will break when it is used or deleted. - else - O.vars[V] = original.vars[V] - - if(isobj(O)) - var/obj/N = O - if(holoitem) - N.resistance_flags = LAVA_PROOF | FIRE_PROOF | UNACIDABLE | ACID_PROOF // holoitems do not burn - - if(nerf && isitem(O)) - var/obj/item/I = O - I.damtype = STAMINA // thou shalt not - - N.update_appearance() - if(ismachinery(O)) - var/obj/machinery/M = O - M.power_change() - if(istype(O, /obj/machinery/button)) - var/obj/machinery/button/B = O - B.setup_device() - - if(holoitem) - O.flags_1 |= HOLOGRAM_1 - for(var/atom/thing in O) - thing.flags_1 |= HOLOGRAM_1 - if(ismachinery(O)) - var/obj/machinery/M = O - for(var/atom/contained_atom in M.component_parts) - contained_atom.flags_1 |= HOLOGRAM_1 - if(M.circuit) - M.circuit.flags_1 |= HOLOGRAM_1 - - if(ismob(O)) //Overlays are carried over despite disallowing them, if a fix is found remove this. - var/mob/M = O - M.cut_overlays() - M.regenerate_icons() - return O - - -/area/proc/copy_contents_to(area/A , platingRequired = 0, nerf_weapons = 0 ) - //Takes: Area. Optional: If it should copy to areas that don't have plating - //Returns: Nothing. - //Notes: Attempts to move the contents of one area to another area. - // Movement based on lower left corner. Tiles that do not fit - // into the new area will not be moved. - - if(!A || !src) - return 0 - - var/list/turfs_src = get_area_turfs(src.type) - var/list/turfs_trg = get_area_turfs(A.type) - - var/src_min_x = 99999 - var/src_min_y = 99999 - var/list/refined_src = new/list() - - for (var/turf/T in turfs_src) - src_min_x = min(src_min_x,T.x) - src_min_y = min(src_min_y,T.y) - for (var/turf/T in turfs_src) - refined_src[T] = "[T.x - src_min_x].[T.y - src_min_y]" - - var/trg_min_x = 99999 - var/trg_min_y = 99999 - var/list/refined_trg = new/list() - - for (var/turf/T in turfs_trg) - trg_min_x = min(trg_min_x,T.x) - trg_min_y = min(trg_min_y,T.y) - for (var/turf/T in turfs_trg) - refined_trg["[T.x - trg_min_x].[T.y - trg_min_y]"] = T - - var/list/toupdate = new/list() - - var/copiedobjs = list() - - for (var/turf/T in refined_src) - var/coordstring = refined_src[T] - var/turf/B = refined_trg[coordstring] - if(!istype(B)) - continue - - if(platingRequired) - if(isspaceturf(B)) - continue - - var/old_dir1 = T.dir - var/old_icon_state1 = T.icon_state - var/old_icon1 = T.icon - - B = B.ChangeTurf(T.type) - B.setDir(old_dir1) - B.icon = old_icon1 - B.icon_state = old_icon_state1 - - for(var/obj/O in T) - var/obj/O2 = DuplicateObject(O , perfectcopy=TRUE, newloc = B, nerf=nerf_weapons, holoitem=TRUE) - if(!O2) - continue - copiedobjs += O2.get_all_contents() - - for(var/mob/M in T) - if(iscameramob(M)) - continue // If we need to check for more mobs, I'll add a variable - var/mob/SM = DuplicateObject(M , perfectcopy=TRUE, newloc = B, holoitem=TRUE) - copiedobjs += SM.get_all_contents() - - for(var/V in T.vars - GLOB.duplicate_forbidden_vars) - if(V == "air") - var/turf/open/O1 = B - var/turf/open/O2 = T - O1.air.copy_from(O2.return_air()) - continue - B.vars[V] = T.vars[V] - toupdate += B - - if(toupdate.len) - for(var/turf/T1 in toupdate) - CALCULATE_ADJACENT_TURFS(T1, KILL_EXCITED) - - return copiedobjs diff --git a/tgstation.dme b/tgstation.dme index 8c44ed2787f..89722ebfabf 100644 --- a/tgstation.dme +++ b/tgstation.dme @@ -406,6 +406,7 @@ #include "code\__HELPERS\dates.dm" #include "code\__HELPERS\datums.dm" #include "code\__HELPERS\dna.dm" +#include "code\__HELPERS\duplicating.dm" #include "code\__HELPERS\files.dm" #include "code\__HELPERS\filters.dm" #include "code\__HELPERS\forensics.dm" @@ -3343,7 +3344,6 @@ #include "code\modules\holiday\foreign_calendar.dm" #include "code\modules\holiday\holidays.dm" #include "code\modules\holiday\nth_week.dm" -#include "code\modules\holodeck\area_copy.dm" #include "code\modules\holodeck\computer.dm" #include "code\modules\holodeck\holo_effect.dm" #include "code\modules\holodeck\holodeck_map_templates.dm"