Files
drsingh dc4217b498 modified process scheduler, 510 compatibility, explosions moved to process
this is all very alpha please don't hate me too much if i fucked it up
2016-03-12 16:36:00 -08:00

438 lines
18 KiB
Plaintext

var/global/list/material_cache = list()
/atom/var/datum/material/material = null
//This contains the names of the trigger lists on materials. Required for copying materials. Remember to keep this updated if you add new triggers.
var/global/list/triggerVars = list("triggersFail", "triggersTemp", "triggersChem", "triggersPickup", "triggersDrop", "triggersExp", "triggersOnAdd", "triggersOnLife", "triggersOnAttack", "triggersOnAttacked", "triggersOnEntered")
//Returns one of the base materials by id.
/proc/getCachedMaterial(var/mat)
if(!istext(mat) || !length(mat)) return null
if(!material_cache.len) buildMaterialCache()
if(material_cache.Find(mat)) return copyMaterial(material_cache[mat])
return null
/proc/mergeProperties(var/list/l1, var/list/l2, var/bias=0.5)
if(!l1) CRASH("SOME IDIOT TRIED TO MERGE LISTS WITHOUT PASSING LISTS TO MERGEPROPERTIES")
var/oBias = 1 - bias
var/list/merged = list()
for(var/o in l1)
merged.Add(o)
var/datum/material_property/Base = l1[o]
var/datum/material_property/newProp = new/datum/material_property()
merged[o] = newProp
newProp.name = o
newProp.value_max = Base.value_max
newProp.value_min = Base.value_min
newProp.value = Base.value
if(l2)
for(var/x in l2)
if(merged.Find(x))
var/datum/material_property/Base = l2[x]
var/datum/material_property/Modded = merged[x]
Modded.value_min = round(Modded.value_min * oBias + Base.value_min * bias)
Modded.value_max = round(Modded.value_max * oBias + Base.value_max * bias)
Modded.value = round(Modded.value * oBias + Base.value * bias)
else
var/datum/material_property/Base = l2[x]
var/datum/material_property/newProp = new/datum/material_property()
merged[x] = newProp
newProp.name = x
newProp.value_max = Base.value_max
newProp.value_min = Base.value_min
newProp.value = Base.value
return merged
//Returns a copy of a given material.
/proc/copyMaterial(var/datum/material/base)
if(!base || !istype(base, /datum/material))
var/datum/material/M = new/datum/material()
return M
else
var/datum/material/M = new base.type ()
var/list/copyProps = mergeProperties(base.properties)
M.properties = copyProps
for(var/X in base.vars)
if(X == "type" || X == "parent_type" || X == "tag" || X == "vars" || X == "properties") continue
if(X in triggerVars)
M.vars[X] = getFusedTriggers(base.vars[X], list()) //Pass in an empty list to basically copy the first one.
else
if(M.vars.Find(X))
if(istype(base.vars[X],/list))
var/list/oldList = base.vars[X]
M.vars[X] = oldList.Copy()
else
M.vars[X] = base.vars[X]
return M
return null
//Simply removes a material from an object.
/atom/proc/removeMaterial()
if(src.mat_changename)
src.remove_prefixes(99)
src.remove_suffixes(99)
src.UpdateName()
//src.name = initial(src.name)
if(src.mat_changedesc)
src.desc = initial(src.desc)
src.alpha = initial(src.alpha)
src.color = initial(src.color)
src.UpdateOverlays(null, "material")
src.material = null
return
//Time for some super verbose proc names.
/proc/get_material_trait_desc(var/datum/material/mat1)
var/string = ""
var/list/allTriggers = (mat1.triggersFail + mat1.triggersTemp + mat1.triggersChem + mat1.triggersPickup + mat1.triggersDrop + mat1.triggersExp + mat1.triggersOnAdd + mat1.triggersOnLife + mat1.triggersOnAttack + mat1.triggersOnAttacked + mat1.triggersOnEntered)
for(var/datum/materialProc/P in allTriggers)
if(length(P.desc))
if(length(string))
if(!findtext(string,P.desc))
string += " " + P.desc
else
string = P.desc
return string
//Sets the material of an object. PLEASE USE THIS TO SET MATERIALS UNLESS YOU KNOW WHAT YOU'RE DOING.
/atom/proc/setMaterial(var/datum/material/mat1)
if(!mat1 ||!istype(mat1, /datum/material)) return
var/traitDesc = get_material_trait_desc(mat1)
var/strPrefix = jointext(mat1.prefixes, " ")
var/strSuffix = jointext(mat1.suffixes, " ")
// Setting mat_changename/desc == 0 is almost as conspicuous as having "good gold chameleon bombs".
// Real_desc/name is a substandard implementation, but it will prevent some midas touch exploits (Convair880).
if (src.mat_changename) // now that I've cleaned up the name prefix/suffix stuff, let's try this, in the hopes that eveything that SHOULD override UpdateName() actually DOES - Haine
src.remove_prefixes(99) // janky but better than ending up with uhh
src.remove_suffixes(99) // "This is a good gold good gold good gold good gold good gold good gold good gold good gold good gold good gold bedsheet."
src.name_prefix(strPrefix ? strPrefix : "")
src.name_prefix(length(getQualityName(mat1.quality)) ? getQualityName(mat1.quality) : "")
src.name_prefix(mat1.name ? mat1.name : "")
src.name_suffix(strSuffix ? "of [strSuffix]" : "")
src.UpdateName()
/* if (istype(src, /obj))
var/obj/O = src
O.name = "[strPrefix ? strPrefix + " ":""][length(getQualityName(mat1.quality)) ? getQualityName(mat1.quality) + " ":""][mat1.name ? mat1.name + " ":""][!isnull(O.real_name) ? "[O.real_name]" : "[initial(O.name)]"][strSuffix ? (" of " + strSuffix) : ""]"
else
src.name = "[strPrefix ? strPrefix + " ":""][length(getQualityName(mat1.quality)) ? getQualityName(mat1.quality) + " ":""][mat1.name ? mat1.name + " ":""][initial(src.name)][strSuffix ? (" of " + strSuffix) : ""]"
*/
if (src.mat_changedesc)
if (istype(src, /obj))
var/obj/O2 = src
O2.desc = "[!isnull(O2.real_desc) ? "[O2.real_desc]" : "[initial(O2.desc)]"] It is made of [mat1.name].[length(traitDesc) ? " " + traitDesc : ""]"
else
src.desc = "[initial(src.desc)] It is made of [mat1.name].[length(traitDesc) ? " " + traitDesc : ""]"
if(mat1.texture)
src.setTexture(mat1.texture, mat1.texture_blend, "material")
src.alpha = mat1.alpha
src.color = mat1.color
src.material = mat1
mat1.owner = src
mat1.triggerOnAdd(src)
src.onMaterialChanged()
return
/proc/getProcessedMaterialForm(var/datum/material/MAT)
if (!istype(MAT))
return /obj/item/material_piece // just in case
// higher on this list means higher priority, be careful with it!
if (MAT.material_flags & MATERIAL_CRYSTAL)
return /obj/item/material_piece/block
if (MAT.material_flags & MATERIAL_METAL)
return /obj/item/material_piece
if (MAT.material_flags & MATERIAL_ORGANIC)
return /obj/item/material_piece/wad
if (MAT.material_flags & MATERIAL_CLOTH)
return /obj/item/material_piece/cloth
if (MAT.material_flags & MATERIAL_RUBBER)
return /obj/item/material_piece/block
if (MAT.material_flags & MATERIAL_ENERGY)
return /obj/item/material_piece/sphere
return /obj/item/material_piece
//Increases generations on material triggers and handles removal if over the generation cap.
/proc/handleTriggerGenerations(var/list/toDo)
for(var/datum/materialProc/current in toDo)
if(current.max_generations != -1 && (toDo[current] + 1) > current.max_generations) toDo.Remove(current)
else toDo[current] = (toDo[current] + 1)
return toDo
//Fuses two material trigger lists.
/proc/getFusedTriggers(var/list/L1 , var/list/L2)
var/list/newList = list()
for(var/datum/materialProc/toCopy in L1) //Copy list 1 with new instances of trigger datum.
var/datum/materialProc/P = new toCopy.type()
newList.Add(P) //Add new instance of datum
newList[P] = L1[toCopy] //Set generation
for(var/varCopy in toCopy.vars)
if(varCopy == "type" || varCopy == "id" || varCopy == "parent_type" || varCopy == "tag" || varCopy == "vars") continue
if(!issaved(toCopy.vars[varCopy])) continue
P.vars[varCopy] = toCopy.vars[varCopy]
for(var/datum/materialProc/A in L2) //Go through second list
if((locate(A.type) in newList)) //We already have that trigger type from the other list
var/datum/materialProc/existing = (locate(A.type) in newList) //Get the trigger datum from the other list
if(newList[existing] <= L2[A]) continue //If the generation of the datum that already exists is lower or equal to the new one, leave it alone.
else newList[existing] = L2[A] //Otherwise set the generation to the generation of the second copy because it is lower.
else //Trigger type isnt in the list yet.
var/datum/materialProc/newProc = new A.type() //Create a new instance
newList.Add(newProc) //Add to list
newList[newProc] = L2[A] //Set generation
for(var/varCopy in A.vars)
if(varCopy == "type" || varCopy == "id" || varCopy == "parent_type" || varCopy == "tag" || varCopy == "vars") continue
if(!issaved(A.vars[varCopy])) continue
newProc.vars[varCopy] = A.vars[varCopy]
return newList
/proc/getFusedMaterial(var/datum/material/mat1,var/datum/material/mat2)
//Merges two materials and returns result as new material.
return getInterpolatedMaterial(mat1, mat2, 0.5)
/proc/getInterpolatedMaterial(var/datum/material/mat1,var/datum/material/mat2,var/t)
var/ot = 1 - t
var/datum/material/newMat = new()
newMat.quality = round(mat1.quality * ot + mat2.quality * t)
newMat.prefixes = (mat1.prefixes | mat2.prefixes)
newMat.suffixes = (mat1.suffixes | mat2.suffixes)
//newMat.name = getInterpolatedName(mat1.name, mat2.name, t)
newMat.name = getInterpolatedName(mat1.name, mat2.name, 0.5)
newMat.mat_id = "([mat1.mat_id]+[mat2.mat_id])"
newMat.alpha = round(mat1.alpha * ot + mat2.alpha * t)
newMat.color = rgb(round(GetRedPart(mat1.color) * ot + GetRedPart(mat2.color) * t), round(GetGreenPart(mat1.color) * ot + GetGreenPart(mat2.color) * t), round(GetBluePart(mat1.color) * ot + GetBluePart(mat2.color) * t))
newMat.properties = mergeProperties(mat1.properties, mat2.properties, t)
//--
newMat.triggersFail = getFusedTriggers(mat1.triggersFail, mat2.triggersFail)
newMat.triggersTemp = getFusedTriggers(mat1.triggersTemp, mat2.triggersTemp)
newMat.triggersChem = getFusedTriggers(mat1.triggersChem, mat2.triggersChem)
newMat.triggersPickup = getFusedTriggers(mat1.triggersPickup, mat2.triggersPickup)
newMat.triggersDrop = getFusedTriggers(mat1.triggersDrop, mat2.triggersDrop)
newMat.triggersExp = getFusedTriggers(mat1.triggersExp, mat2.triggersExp)
newMat.triggersOnAdd = getFusedTriggers(mat1.triggersOnAdd, mat2.triggersOnAdd)
newMat.triggersOnLife = getFusedTriggers(mat1.triggersOnLife, mat2.triggersOnLife)
newMat.triggersOnAttack = getFusedTriggers(mat1.triggersOnAttack, mat2.triggersOnAttack)
newMat.triggersOnAttacked = getFusedTriggers(mat1.triggersOnAttacked, mat2.triggersOnAttacked)
newMat.triggersOnEntered = getFusedTriggers(mat1.triggersOnEntered, mat2.triggersOnEntered)
handleTriggerGenerations(newMat.triggersFail)
handleTriggerGenerations(newMat.triggersTemp)
handleTriggerGenerations(newMat.triggersChem)
handleTriggerGenerations(newMat.triggersPickup)
handleTriggerGenerations(newMat.triggersDrop)
handleTriggerGenerations(newMat.triggersExp)
handleTriggerGenerations(newMat.triggersOnAdd)
handleTriggerGenerations(newMat.triggersOnLife)
handleTriggerGenerations(newMat.triggersOnAttack)
handleTriggerGenerations(newMat.triggersOnAttacked)
handleTriggerGenerations(newMat.triggersOnEntered)
//--
//Texture merging. SUPER DUPER UGLY AAAAH
if(mat2.texture && !mat1.texture)
newMat.texture = mat2.texture
newMat.texture_blend = mat2.texture_blend
else if (mat1.texture && !mat2.texture)
newMat.texture = mat2.texture
newMat.texture_blend = mat1.texture_blend
else if (mat1.texture && mat2.texture)
if(mat1.generation == mat2.generation)
//Mat1 has higher priority in this case. Optional: implement some shitty blended texture thing. probably a bad idea.
newMat.texture = mat1.texture
newMat.texture_blend = mat1.texture_blend
else
if(mat1.generation < mat2.generation)
newMat.texture = mat1.texture
newMat.texture_blend = mat1.texture_blend
else
newMat.texture = mat2.texture
newMat.texture_blend = mat2.texture_blend
//
//This is sub-optimal and only used because im dumb
if(mat1.material_flags & MATERIAL_CRYSTAL || mat2.material_flags & MATERIAL_CRYSTAL) newMat.material_flags |= MATERIAL_CRYSTAL
if(mat1.material_flags & MATERIAL_METAL || mat2.material_flags & MATERIAL_METAL) newMat.material_flags |= MATERIAL_METAL
if(mat1.material_flags & MATERIAL_CLOTH || mat2.material_flags & MATERIAL_CLOTH) newMat.material_flags |= MATERIAL_CLOTH
if(mat1.material_flags & MATERIAL_ORGANIC || mat2.material_flags & MATERIAL_ORGANIC) newMat.material_flags |= MATERIAL_ORGANIC
if(mat1.material_flags & MATERIAL_ENERGY || mat2.material_flags & MATERIAL_ENERGY) newMat.material_flags |= MATERIAL_ENERGY
if(mat1.material_flags & MATERIAL_RUBBER || mat2.material_flags & MATERIAL_RUBBER) newMat.material_flags |= MATERIAL_RUBBER
newMat.parent_materials.Add(mat1)
newMat.parent_materials.Add(mat2)
return newMat
//Merges two material names into one.
/proc/getInterpolatedName(var/mat1, var/mat2, var/t)
var/ot = 1 - t
var/part1 = copytext(mat1, 1, round((length(mat1) * ot) + 0.5))
var/part2 = copytext(mat2, round((length(mat2) * ot) + 0.5), 0)
return capitalize(ckey("[part1][part2]"))
//Returns a string for when a material fail or breaks depending on its material flags.
/proc/getMatFailString(var/flag)
if(flag & MATERIAL_METAL && flag & MATERIAL_CRYSTAL && flag & MATERIAL_CLOTH)
return "frays apart into worthless dusty fibers"
if(flag & MATERIAL_METAL && flag & MATERIAL_CRYSTAL)
return "cracks and shatters into unworkable dust"
if(flag & MATERIAL_CLOTH && flag & MATERIAL_CRYSTAL)
return "shatters into useless brittle fibers"
if(flag & MATERIAL_ENERGY && flag & MATERIAL_CRYSTAL)
return "violently disintegrates into vapor"
if(flag & MATERIAL_ENERGY && flag & MATERIAL_METAL)
return "shines brightly before self-vaporizing"
if(flag & MATERIAL_ENERGY && flag & MATERIAL_CLOTH)
return "bursts into flames and is gone almost instantly"
if(flag & MATERIAL_ENERGY && flag & MATERIAL_ORGANIC)
return "catches on fire and rapidly burns to ash"
if(flag & MATERIAL_ORGANIC)
return "crumbles into worthless slime"
if(flag & MATERIAL_CRYSTAL)
return "shatters to dust and blows away"
if(flag & MATERIAL_METAL)
return "disintegrates into useless flakes"
if(flag & MATERIAL_CLOTH)
return "frays apart into useless strands"
if(flag & MATERIAL_ENERGY)
return "suddenly vanishes into nothingness"
if(flag & MATERIAL_RUBBER)
return "melts into an unworkable pile of slop"
return "comes apart"
//Translates a material flag into a string.
/proc/getMatFlagString(var/flag)
switch(flag)
if(MATERIAL_CRYSTAL)
return "Crystal"
if(MATERIAL_METAL)
return "Metal"
if(MATERIAL_CLOTH)
return "Fabric"
if(MATERIAL_ORGANIC)
return "Organic Matter"
if(MATERIAL_ENERGY)
return "Energy Source"
if(MATERIAL_RUBBER)
return "Rubber"
else
return "Unknown"
return
//Simply returns a string for a given quality. Used as prefix for objects.
/proc/getQualityName(var/quality)
switch(quality)
if(-INFINITY to -101)
return "useless"
if(-100 to -91)
return "atrocious"
if(-90 to -81)
return "wretched"
if(-80 to -71)
return "crap"
if(-70 to -61)
return "awful"
if(-60 to -51)
return "terrible"
if(-50 to -41)
return "bad"
if(-40 to -31)
return "shabby"
if(-30 to -21)
return "mediocre"
if(-20 to -11)
return "low-quality"
if(-10 to -1)
return "poor"
if(0)
return ""
if(1 to 10)
return "decent"
if(11 to 20)
return "fine"
if(21 to 30)
return "good"
if(31 to 40)
return "great"
if(41 to 50)
return "high-quality"
if(51 to 60)
return "excellent"
if(61 to 70)
return "superb"
if(71 to 80)
return "incredible"
if(81 to 90)
return "amazing"
if(91 to 100)
return "supreme"
if(101 to INFINITY)
return "perfect"
else
return "odd"
return
//Checks if a material matches a recipe and returns the recipe if a match is found. returns null if nothing matches it.
/proc/matchesMaterialRecipe(var/datum/material/M)
for(var/datum/material_recipe/R in materialRecipes)
if(R.validate(M)) return R
return null
//Searches the parent materials of the given material, up to a given generation, for an id.
//Useful if you want to figure out if a given material was used in the making of another material.
//Keep in mind that this can be expensive so use it only when you have to.
/proc/hasParentMaterial(var/datum/material/M, var/search_id, var/max_generations = 3)
return searchMatTree(M, search_id, 0, max_generations)
/proc/searchMatTree(var/datum/material/M, var/id, var/current_depth, var/max_depth = 3)
if(!M || !id) return null
if(!M.parent_materials.len) return null
for(var/datum/material/CM in M.parent_materials)
if(CM.mat_id == id) return CM
if(current_depth + 1 <= max_depth)
var/temp = searchMatTree(CM, id, current_depth + 1, max_depth)
if(temp) return temp
return null
//Yes hello apparently we need a proc for this because theres a million types of different wires and cables.
/proc/applyCableMaterials(var/atom/C, var/datum/material/insulator, var/datum/material/conductor)
if(!conductor) return // silly
if(istype(C, /obj/cable))
var/obj/cable/cable = C
cable.insulator = insulator
cable.conductor = conductor
if (cable.insulator)
cable.setMaterial(copyMaterial(cable.insulator))
cable.name = "[cable.insulator.name]-insulated [cable.conductor.name]-cable"
cable.color = cable.insulator.color
else
cable.setMaterial(copyMaterial(cable.conductor))
cable.name = "uninsulated [cable.conductor.name]-cable"
cable.color = cable.conductor.color
if(istype(C, /obj/item/cable_coil))
var/obj/item/cable_coil/coil = C
coil.insulator = insulator
coil.conductor = conductor
if (coil.insulator)
coil.setMaterial(copyMaterial(coil.insulator))
coil.color = coil.insulator.color
else
coil.setMaterial(copyMaterial(coil.conductor))
coil.color = coil.conductor.color
coil.updateName()