Skip to content

Commit

Permalink
Memory Reduction - Lists + Murder Virus2 (sojourn-13#5527)
Browse files Browse the repository at this point in the history
* Move stats to /atom/movable

* Make allowed_stat_modifiers a lazylist

* Suppress warning from init_openspace

* Make current_stat_modifiers a lazylist

* Rename prefixes to name_prefixes and make it a lazylist

* Easy nulls in items

* Make item_upgrades a lazylist

* Make transform_types a lazylist

* Make attack_verb a lazylist

* Make effective_faction a lazylist

* Make random_icon_states a lazylist

* Make req_access and req_one_access lazylists

* Make obfuscations and statverbs lazy lists

* Make climbers a lazylist

* Remove old unused vars on openspace

* Make a bunch of flooring lists lazy

* Convert antibodies to lazylist

* Make virus2 a lazylist

* Straight up merk virus2

* remove leftover debug verbs whoopsie
  • Loading branch information
ShadowLarkens authored Jul 10, 2024
1 parent 8034ded commit 4f6f1e1
Show file tree
Hide file tree
Showing 135 changed files with 348 additions and 3,669 deletions.
6 changes: 6 additions & 0 deletions code/__HELPERS/_lists.dm
Original file line number Diff line number Diff line change
Expand Up @@ -45,11 +45,17 @@
#define LAZYACCESSASSOC(L, I, K) L ? L[I] ? L[I][K] ? L[I][K] : null : null : null
///Qdel every item in the list before setting the list to null
#define QDEL_LAZYLIST(L) for(var/I in L) qdel(I); L = null;
///Qdel every key and item in the list before setting the list to null
#define QDEL_LAZYLIST_ASSOC(L) for(var/I in L) { qdel(L[I]); qdel(I); }; L = null;
///Qdel every value but not key in the list before setting the list to null
#define QDEL_LAZYLIST_ASSOC_VAL(L) for(var/I in L) qdel(L[I]); L = null;
//These methods don't null the list
///Use LAZYLISTDUPLICATE instead if you want it to null with no entries
#define LAZYCOPY(L) (L ? L.Copy() : list() )
/// Consider LAZYNULL instead
#define LAZYCLEARLIST(L) if(L) L.Cut()
/// Pick a value from a lazylist, or null if the list is empty
#define LAZYPICK(L) ( L ? pick(L) : null )
///Returns the list if it's actually a valid list, otherwise will initialize it
#define SANITIZE_LIST(L) ( islist(L) ? L : list() )
#define reverseList(L) reverse_range(L.Copy())
Expand Down
2 changes: 1 addition & 1 deletion code/_onclick/item_attack.dm
Original file line number Diff line number Diff line change
Expand Up @@ -130,7 +130,7 @@ avoid code duplication. This includes items that may sometimes act as a standard
power *= H.damage_multiplier
if(HULK in user.mutations)
power *= 2
if(effective_faction.Find(target.faction)) // Is the mob's in our list of factions we're effective against?
if(target.faction in effective_faction) // Is the mob's in our list of factions we're effective against?
power *= damage_mult // Increase the damage
target.hit_with_weapon(src, user, power, hit_zone)
return
22 changes: 7 additions & 15 deletions code/controllers/subsystems/staverbs.dm
Original file line number Diff line number Diff line change
Expand Up @@ -69,36 +69,28 @@ SUBSYSTEM_DEF(statverbs)

// Atom part //
/atom
var/list/statverbs
var/list/statverbs = null

/atom/Initialize()
. = ..()
initalize_statverbs()

/atom/Destroy()
. = ..()
if(statverbs)
statverbs.Cut()
LAZYNULL(statverbs)

/atom/proc/initalize_statverbs()
var/list/paths = statverbs
statverbs = new
for(var/path in paths)
add_statverb(path)
return

/atom/proc/add_statverb(path)
if(!statverbs)
statverbs = new
var/datum/statverb/SV = path
statverbs[initial(SV.required_stat)] = path
LAZYSET(statverbs, initial(SV.required_stat), path)

/atom/proc/remove_statverb(path)
statverbs -= path


LAZYREMOVE(statverbs, path)

/atom/proc/show_stat_verbs()
if(statverbs && statverbs.len)
if(LAZYLEN(statverbs))
. = "Apply: "
for(var/stat in statverbs)
. += " <a href='?src=\ref[src];statverb=[stat];obj_name=[src]'>[stat]</a>"
Expand Down Expand Up @@ -206,7 +198,7 @@ SUBSYSTEM_DEF(statverbs)
if(do_mob(user, target, timer))
keyboardsound.stop()
keyboardsound = null
target.req_access.Cut()
LAZYNULL(target.req_access)
target.hacked = 1
user.visible_message(
SPAN_DANGER("[user] breaks the access encryption on [target]!"),
Expand Down
21 changes: 10 additions & 11 deletions code/controllers/subsystems/trade.dm
Original file line number Diff line number Diff line change
Expand Up @@ -281,17 +281,16 @@ SUBSYSTEM_DEF(trade)
/datum/controller/subsystem/trade/proc/check_attachments(item, offer_path, list/attachments, attach_count)
if(attachments && attach_count)
var/obj/item/I = item
if(I.item_upgrades && I.item_upgrades.len)
var/success_count = 0
for(var/mod in I.item_upgrades)
var/list/attachments_to_compare = attachments.Copy()
for(var/path in attachments_to_compare)
if(istype(mod, path))
++success_count
if(attachments_to_compare.len == attach_count)
attachments_to_compare.Remove(path)
if(success_count >= attach_count)
return TRUE
var/success_count = 0
for(var/mod in I.item_upgrades)
var/list/attachments_to_compare = attachments.Copy()
for(var/path in attachments_to_compare)
if(istype(mod, path))
++success_count
if(attachments_to_compare.len == attach_count)
attachments_to_compare.Remove(path)
if(success_count >= attach_count)
return TRUE
return FALSE // If we're looking for attachments and the item has no upgrades, fail
return TRUE // If attachments and attach_count are null, we're not looking for an item with attactments

Expand Down
4 changes: 0 additions & 4 deletions code/datums/autolathe/devices.dm
Original file line number Diff line number Diff line change
Expand Up @@ -14,10 +14,6 @@
name = "slime scanner"
build_path = /obj/item/device/scanner/xenobio

/datum/design/autolathe/device/antibody_scanner
name = "antibody scanner"
build_path = /obj/item/device/antibody_scanner

/datum/design/autolathe/device/megaphone
name = "megaphone"
build_path = /obj/item/device/megaphone
Expand Down
46 changes: 23 additions & 23 deletions code/datums/stat_modifiers/stat_modifier.dm
Original file line number Diff line number Diff line change
Expand Up @@ -21,7 +21,7 @@
var/holder_original_prob

/// The atom we have applied our changes to
var/atom/holder
var/atom/movable/holder

/// The prefix that will be applied to the name of target
var/prefix = null
Expand Down Expand Up @@ -69,17 +69,18 @@
holder.health = ZERO_OR_MORE((holder.health / maxHealth_mult))

// Remove our prefix, and then regenerate prefixes
holder.prefixes -= prefix
LAZYREMOVE(holder.name_prefixes, prefix)
holder.update_prefixes()

holder.current_stat_modifiers -= src
LAZYREMOVE(holder.current_stat_modifiers, src)

// First, we check how many of us are in our holder...
var/instances_in_target = instances_of_type_in_list(src, holder.current_stat_modifiers)

// ...and if it's less than our max, and we are disabled, let's restore our probability
if (instances_in_target < maximum_instances && (holder.allowed_stat_modifiers[type] == 0))
holder.allowed_stat_modifiers[type] = holder_original_prob
// in case of not existing, lazyaccess will return null, which != 0
if (instances_in_target < maximum_instances && (LAZYACCESS(holder.allowed_stat_modifiers, type) == 0))
LAZYSET(holder.allowed_stat_modifiers, type, holder_original_prob)
holder_original_prob = null // dont need to hold onto this anymore

// if we arent in the target anymore...
Expand All @@ -93,7 +94,7 @@
do_we_readd = FALSE // ..and if one is, theyre still mutually exclusive, so lets break and say "we're not re-adding them"
break
if (do_we_readd) // ...if nothing is mutually exclusive...
holder.allowed_stat_modifiers[typepath] = mutually_exclusive_with[typepath] // ...we use our stored value to restore it!
LAZYSET(holder.allowed_stat_modifiers, typepath, mutually_exclusive_with[typepath]) // ...we use our stored value to restore it!

holder = null //we no longer have a holder

Expand All @@ -105,7 +106,7 @@
/datum/stat_modifier/Destroy()

if (holder)
holder.current_stat_modifiers -= src
LAZYREMOVE(holder.current_stat_modifiers, src)
holder = null

return ..()
Expand All @@ -118,12 +119,12 @@
* from the latter list.
*
**/
/datum/stat_modifier/proc/valid_check(var/atom/target, var/list/arguments)
/datum/stat_modifier/proc/valid_check(var/atom/movable/target, var/list/arguments)

var/instances_in_target = instances_of_type_in_list(src, target.current_stat_modifiers) // how many of us are in our target?

if (instances_in_target >= maximum_instances) // this shouldnt ever be true, but if it is, lets make sure it doesnt happen again
target.allowed_stat_modifiers[type] = 0 // by disabling ourselves
LAZYSET(target.allowed_stat_modifiers, type, 0) // by disabling ourselves
return FALSE // and returning

for (var/entry in target.current_stat_modifiers) // if we're allowed in...
Expand All @@ -132,17 +133,17 @@

holder = target // they are now our holder!

holder_original_prob = holder.allowed_stat_modifiers[type] // we need this in case we disable ourselves and remove ourselves later
holder_original_prob = LAZYACCESS(holder.allowed_stat_modifiers, type) // we need this in case we disable ourselves and remove ourselves later

target.current_stat_modifiers += src // add ourselves to their currently held modifiers
LAZYADD(target.current_stat_modifiers, src) // add ourselves to their currently held modifiers

for (var/typepath in mutually_exclusive_with)
mutually_exclusive_with[typepath] = holder.allowed_stat_modifiers[typepath] //store the value for if we get removed
holder.allowed_stat_modifiers[typepath] = 0 // you are now forbidden from having these
mutually_exclusive_with[typepath] = LAZYACCESS(holder.allowed_stat_modifiers, typepath) //store the value for if we get removed
LAZYSET(holder.allowed_stat_modifiers, typepath, 0) // you are now forbidden from having these

instances_in_target = instances_of_type_in_list(src, target.current_stat_modifiers) //refresh the var
if (instances_in_target >= maximum_instances) // if we are now at the maximum of our own instances...
target.allowed_stat_modifiers[type] = 0 // ...disable ourselves
LAZYSET(target.allowed_stat_modifiers, type, 0) // ...disable ourselves
//we dont return here, since we already added ourselves to the list

var/arguments_to_pass = consider_custom_effect(target, arguments, status = PRIOR_TO_APPLY) // lets see if we have any pre_apply effects
Expand All @@ -158,9 +159,9 @@
* general effects.
*
* Args:
* atom/target: The target the effects will be applied to.
* atom/movable/target: The target the effects will be applied to.
**/
/datum/stat_modifier/proc/apply_to(var/atom/target, var/list/arguments, arguments_to_pass)
/datum/stat_modifier/proc/apply_to(var/atom/movable/target, var/list/arguments, arguments_to_pass)

if (maxHealth_mult)
target.maxHealth = ZERO_OR_MORE(SAFEMULT(target.maxHealth, maxHealth_mult, maxHealth_zeroth))
Expand All @@ -175,13 +176,12 @@
determine_description_and_prefixes(target, ratio)

if (prefix && target.get_prefix) // do we have a prefix, and does our target want a prefix?
target.prefixes += prefix // if so, lets add ours to their prefix list...

LAZYADD(target.name_prefixes, prefix) // if so, lets add ours to their prefix list...
target.update_prefixes() // ...and regenerate their prefixes

return TRUE

/datum/stat_modifier/proc/consider_custom_effect(atom/target, list/arguments, arguments_to_pass, status)
/datum/stat_modifier/proc/consider_custom_effect(atom/movable/target, list/arguments, arguments_to_pass, status)

var/list_length

Expand All @@ -197,15 +197,15 @@
return // only happens if no custom effect is present

/// Holder proc for any logic that has to be run before apply_to()
/datum/stat_modifier/proc/before_apply(atom/target, list/arguments, arg_length)
/datum/stat_modifier/proc/before_apply(atom/movable/target, list/arguments, arg_length)
return

/// Holder proc for any logic that has to be run after apply_to(), but before prefixes and descriptions are determined
/datum/stat_modifier/proc/after_apply(atom/target, list/arguments, arg_length, arguments_to_pass)
/datum/stat_modifier/proc/after_apply(atom/movable/target, list/arguments, arg_length, arguments_to_pass)
return

/// Uses a ratio to determine which prefix and description will be gained. If arguments_to_pass is null, uses ratio1 and ratio2 instead. Returns if force_default_prefix is true.
/datum/stat_modifier/proc/determine_description_and_prefixes(atom/target, arguments_to_pass, ratio1, ratio2)
/datum/stat_modifier/proc/determine_description_and_prefixes(atom/movable/target, arguments_to_pass, ratio1, ratio2)

if (force_default_prefix || (!(target.get_prefix)))
return FALSE
Expand Down Expand Up @@ -261,5 +261,5 @@

stattags = NOTHING_STATTAG

/datum/stat_modifier/none/apply_to(var/atom/target)
/datum/stat_modifier/none/apply_to(var/atom/movable/target)
return FALSE
34 changes: 14 additions & 20 deletions code/datums/transformation_types/transform_types.dm
Original file line number Diff line number Diff line change
Expand Up @@ -30,9 +30,9 @@

/datum/transform_type/Destroy()

if (holder)
if (holder.transform_types && holder.transform_types[flag] == src) //we can be deleted by an overridding thing so we must check
holder.transform_types -= flag //for sanity
if(holder)
if(LAZYACCESS(holder.transform_types, flag) == src) //we can be deleted by an overridding thing so we must check
LAZYREMOVE(holder.transform_types, flag) //for sanity
update_holder_status(null, null)
value_target = null

Expand All @@ -50,7 +50,7 @@

/// Updates the transform with the given flag in the transform_types list.
/atom/proc/update_transform(transform_flag)
if (!(transform_types[transform_flag]))
if (!(LAZYACCESS(transform_types, transform_flag)))
return
var/datum/transform_type/transform_datum = transform_types[transform_flag]

Expand Down Expand Up @@ -146,9 +146,6 @@
* valuetarget = src: The atom to be used for update_values() and such, weakreffed. Needed for things that use the values of others, like shadows.
**/
/atom/proc/add_transformation(var/datum/transform_type/transform_datum, list/params, rebuild = TRUE, valuetarget = src)
if (!transform_types)
transform_types = list()

var/result = transform_datum.apply_custom_values(arglist(params)) //dont worry this still works even if params is null or empty
if (result != TRUE) //result can return a string in an error state, so we explicitely check for true
qdel(transform_datum)
Expand All @@ -161,7 +158,7 @@
qdel(transform_datum)
return

transform_types[transform_datum.flag] = transform_datum
LAZYSET(transform_types, transform_datum.flag, transform_datum)
transform_datum.update_holder_status(src, valuetarget)

if (rebuild)
Expand Down Expand Up @@ -199,14 +196,10 @@

/// Remove this flag's associated datum from ourselves, and remove its effects, then remove the flag.
/atom/proc/remove_transformation(flag, rebuild = TRUE)
if (!transform_types)
transform_types = list()
return //theres literally nothing in here

if (!(flag in transform_types))
if(!(flag in transform_types))
return
qdel(transform_types[flag]) //since its no longer needed we can delete it and unassign the flag
transform_types -= flag
LAZYREMOVE(transform_types, flag)

if (rebuild)
rebuild_transform()
Expand All @@ -230,7 +223,7 @@
else
transform = matrix() //reset the transform

QDEL_LIST_ASSOC_VAL(transform_types) //and then destroy everything in the list
QDEL_LAZYLIST_ASSOC_VAL(transform_types) //and then destroy everything in the list

/**
* This is where we rebuild transforms post-modification. Any removal, addition, or modification of a existing transform type will cause this proc to be called
Expand All @@ -245,26 +238,27 @@
**/
/atom/proc/rebuild_transform(update = TRUE, update_values = TRUE, rebuild = FALSE)

var/list/cached_transforms = transform_types.Copy()
var/list/cached_transforms = LAZYCOPY(transform_types)

var/datum/transform_type/transform_datum
var/key
for (key as anything in transform_types) //unhappy with the amount of loops in this proc
for(key as anything in transform_types) //unhappy with the amount of loops in this proc
transform_datum = transform_types[key]
transform_types[key] = transform_datum.priority //temporarily replace it with the priority, for sorting

// note: timsort is a stable algorithm, meaning 2 adjacent values with the same value will be kept in order
// ex: a list of (a = 200, b = 250, c = 250, d = 150). this will be sorted into (d, a, b, c). note that b and c's position doesnt actually really change,
// and their order relative to eachother is preserved
sortTim(transform_types, GLOBAL_PROC_REF(cmp_numeric_asc), TRUE) //sort from least to greatest
if(transform_types)
sortTim(transform_types, GLOBAL_PROC_REF(cmp_numeric_asc), TRUE) //sort from least to greatest

for (key as anything in transform_types)
for(key as anything in transform_types)
transform_types[key] = cached_transforms[key] //now that it's sorted, we can reapply our original values

var/matrix/new_transform = matrix() //destroy the current matrix and reassign a new one
transform = new_transform

for (var/i = 1, i <= transform_types.len, i++) //reapply all our transforms, in the order of their priority
for(var/i in 1 to LAZYLEN(transform_types)) //reapply all our transforms, in the order of their priority
key = transform_types[i]
transform_datum = transform_types[key]
apply_transformation(transform_datum, update, update_values, rebuild)
Expand Down
Loading

0 comments on commit 4f6f1e1

Please sign in to comment.