mirror of
https://github.com/SPLURT-Station/S.P.L.U.R.T-Station-13.git
synced 2025-12-09 16:07:40 +00:00
more updates!
This commit is contained in:
@@ -158,6 +158,10 @@ GLOBAL_LIST_INIT(ai_core_display_screens, list(
|
||||
else
|
||||
if(input == "Random")
|
||||
input = pick(GLOB.ai_core_display_screens - "Random")
|
||||
if(input == "Portrait")
|
||||
var/datum/portrait_picker/tgui = new(usr)//create the datum
|
||||
tgui.ui_interact(usr)//datum has a tgui component, here we open the window
|
||||
return "ai-portrait" //just take this until they decide
|
||||
return "ai-[lowertext(input)]"
|
||||
|
||||
GLOBAL_LIST_INIT(security_depts_prefs, list(SEC_DEPT_RANDOM, SEC_DEPT_NONE, SEC_DEPT_ENGINEERING, SEC_DEPT_MEDICAL, SEC_DEPT_SCIENCE, SEC_DEPT_SUPPLY))
|
||||
|
||||
@@ -1,6 +1,8 @@
|
||||
/*! How material datums work
|
||||
Materials are now instanced datums, with an associative list of them being kept in SSmaterials. We only instance the materials once and then re-use these instances for everything.
|
||||
|
||||
These materials call on_applied() on whatever item they are applied to, common effects are adding components, changing color and changing description. This allows us to differentiate items based on the material they are made out of.area
|
||||
|
||||
*/
|
||||
|
||||
SUBSYSTEM_DEF(materials)
|
||||
@@ -14,12 +16,16 @@ SUBSYSTEM_DEF(materials)
|
||||
var/list/materialtypes_by_category
|
||||
///A cache of all material combinations that have been used
|
||||
var/list/list/material_combos
|
||||
///List of stackcrafting recipes for materials using rigid materials
|
||||
///List of stackcrafting recipes for materials using base recipes
|
||||
var/list/base_stack_recipes = list(
|
||||
new /datum/stack_recipe("Chair", /obj/structure/chair/greyscale, one_per_turf = TRUE, on_floor = TRUE, applies_mats = TRUE),
|
||||
new /datum/stack_recipe("Toilet", /obj/structure/toilet/greyscale, one_per_turf = TRUE, on_floor = TRUE, applies_mats = TRUE),
|
||||
new /datum/stack_recipe("Sink Frame", /obj/structure/sink/greyscale, one_per_turf = TRUE, on_floor = TRUE, applies_mats = TRUE),
|
||||
new /datum/stack_recipe("Floor tile", /obj/item/stack/tile/material, 1, 4, 20, applies_mats = TRUE),
|
||||
)
|
||||
///List of stackcrafting recipes for materials using rigid recipes
|
||||
var/list/rigid_stack_recipes = list(
|
||||
new /datum/stack_recipe("chair", /obj/structure/chair/greyscale, one_per_turf = TRUE, on_floor = TRUE, applies_mats = TRUE),
|
||||
new /datum/stack_recipe("toilet", /obj/structure/toilet/greyscale, one_per_turf = TRUE, on_floor = TRUE, applies_mats = TRUE),
|
||||
new /datum/stack_recipe("sink", /obj/structure/sink/greyscale, one_per_turf = TRUE, on_floor = TRUE, applies_mats = TRUE),
|
||||
new /datum/stack_recipe("Floor tile", /obj/item/stack/tile/material, 1, 4, 20, applies_mats = TRUE)
|
||||
// new /datum/stack_recipe("Carving block", /obj/structure/carving_block, 5, one_per_turf = TRUE, on_floor = TRUE, applies_mats = TRUE),
|
||||
)
|
||||
|
||||
///Ran on initialize, populated the materials and materials_by_category dictionaries with their appropiate vars (See these variables for more info)
|
||||
@@ -29,7 +35,11 @@ SUBSYSTEM_DEF(materials)
|
||||
materialtypes_by_category = list()
|
||||
material_combos = list()
|
||||
for(var/type in subtypesof(/datum/material))
|
||||
var/datum/material/ref = new type
|
||||
var/datum/material/ref = type
|
||||
// if(!(initial(ref.init_flags) & MATERIAL_INIT_MAPLOAD))
|
||||
// continue // Do not initialize
|
||||
|
||||
ref = new ref
|
||||
materials[type] = ref
|
||||
for(var/c in ref.categories)
|
||||
materials_by_category[c] += list(ref)
|
||||
@@ -40,7 +50,6 @@ SUBSYSTEM_DEF(materials)
|
||||
InitializeMaterials()
|
||||
return materials[fakemat] || fakemat
|
||||
|
||||
|
||||
///Returns a list to be used as an object's custom_materials. Lists will be cached and re-used based on the parameters.
|
||||
/datum/controller/subsystem/materials/proc/FindOrCreateMaterialCombo(list/materials_declaration, multiplier)
|
||||
if(!material_combos)
|
||||
|
||||
@@ -8,15 +8,17 @@
|
||||
/*
|
||||
* Stacks
|
||||
*/
|
||||
|
||||
/obj/item/stack
|
||||
icon = 'icons/obj/stack_objects.dmi'
|
||||
gender = PLURAL
|
||||
material_modifier = 0.01
|
||||
material_modifier = 0.05 //5%, so that a 50 sheet stack has the effect of 5k materials instead of 100k.
|
||||
max_integrity = 100
|
||||
var/list/datum/stack_recipe/recipes
|
||||
var/singular_name
|
||||
var/amount = 1
|
||||
var/max_amount = 50 //also see stack recipes initialisation, param "max_res_amount" must be equal to this max_amount
|
||||
var/is_cyborg = 0 // It's 1 if module is used by a cyborg, and uses its storage
|
||||
var/is_cyborg = FALSE // It's TRUE if module is used by a cyborg, and uses its storage
|
||||
var/datum/robot_energy_storage/source
|
||||
var/cost = 1 // How much energy from storage it costs
|
||||
var/merge_type = null // This path and its children should merge with this stack, defaults to src.type
|
||||
@@ -25,7 +27,6 @@
|
||||
var/list/mats_per_unit //list that tells you how much is in a single unit.
|
||||
///Datum material type that this stack is made of
|
||||
var/material_type
|
||||
max_integrity = 100
|
||||
//NOTE: When adding grind_results, the amounts should be for an INDIVIDUAL ITEM - these amounts will be multiplied by the stack size in on_grind()
|
||||
var/obj/structure/table/tableVariant // we tables now (stores table variant to be built from this stack)
|
||||
|
||||
@@ -36,16 +37,8 @@
|
||||
var/absorption_capacity
|
||||
/// How quickly we lower the blood flow on a cut wound we're bandaging. Expected lifetime of this bandage in ticks is thus absorption_capacity/absorption_rate, or until the cut heals, whichever comes first
|
||||
var/absorption_rate
|
||||
|
||||
/obj/item/stack/on_grind()
|
||||
for(var/i in 1 to grind_results.len) //This should only call if it's ground, so no need to check if grind_results exists
|
||||
grind_results[grind_results[i]] *= get_amount() //Gets the key at position i, then the reagent amount of that key, then multiplies it by stack size
|
||||
|
||||
/obj/item/stack/grind_requirements()
|
||||
if(is_cyborg)
|
||||
to_chat(usr, "<span class='danger'>[src] is electronically synthesized in your chassis and can't be ground up!</span>")
|
||||
return
|
||||
return TRUE
|
||||
/// Amount of matter for RCD
|
||||
var/matter_amount = 0
|
||||
|
||||
/obj/item/stack/Initialize(mapload, new_amount, merge = TRUE)
|
||||
if(new_amount != null)
|
||||
@@ -55,16 +48,16 @@
|
||||
new type(loc, max_amount, FALSE)
|
||||
if(!merge_type)
|
||||
merge_type = type
|
||||
if(custom_materials && custom_materials.len)
|
||||
mats_per_unit = list()
|
||||
var/in_process_mat_list = custom_materials.Copy()
|
||||
for(var/i in custom_materials)
|
||||
mats_per_unit[SSmaterials.GetMaterialRef(i)] = in_process_mat_list[i]
|
||||
custom_materials[i] *= amount
|
||||
|
||||
if(LAZYLEN(mats_per_unit))
|
||||
set_mats_per_unit(mats_per_unit, 1)
|
||||
else if(LAZYLEN(custom_materials))
|
||||
set_mats_per_unit(custom_materials, amount ? 1/amount : 1)
|
||||
|
||||
. = ..()
|
||||
if(merge)
|
||||
for(var/obj/item/stack/S in loc)
|
||||
if(S.merge_type == merge_type)
|
||||
if(can_merge(S))
|
||||
INVOKE_ASYNC(src, .proc/merge, S)
|
||||
var/list/temp_recipes = get_main_recipes()
|
||||
recipes = temp_recipes.Copy()
|
||||
@@ -73,12 +66,42 @@
|
||||
for(var/i in M.categories)
|
||||
switch(i)
|
||||
if(MAT_CATEGORY_BASE_RECIPES)
|
||||
var/list/temp = SSmaterials.base_stack_recipes.Copy()
|
||||
recipes += temp
|
||||
if(MAT_CATEGORY_RIGID)
|
||||
var/list/temp = SSmaterials.rigid_stack_recipes.Copy()
|
||||
recipes += temp
|
||||
update_weight()
|
||||
update_icon()
|
||||
|
||||
/** Sets the amount of materials per unit for this stack.
|
||||
*
|
||||
* Arguments:
|
||||
* - [mats][/list]: The value to set the mats per unit to.
|
||||
* - multiplier: The amount to multiply the mats per unit by. Defaults to 1.
|
||||
*/
|
||||
/obj/item/stack/proc/set_mats_per_unit(list/mats, multiplier=1)
|
||||
mats_per_unit = SSmaterials.FindOrCreateMaterialCombo(mats, multiplier)
|
||||
update_custom_materials()
|
||||
|
||||
/** Updates the custom materials list of this stack.
|
||||
*/
|
||||
/obj/item/stack/proc/update_custom_materials()
|
||||
set_custom_materials(mats_per_unit, amount)
|
||||
|
||||
/obj/item/stack/on_grind()
|
||||
. = ..()
|
||||
for(var/i in 1 to length(grind_results)) //This should only call if it's ground, so no need to check if grind_results exists
|
||||
grind_results[grind_results[i]] *= get_amount() //Gets the key at position i, then the reagent amount of that key, then multiplies it by stack size
|
||||
|
||||
/obj/item/stack/grind_requirements()
|
||||
if(is_cyborg)
|
||||
to_chat(usr, "<span class='warning'>[src] is electronically synthesized in your chassis and can't be ground up!</span>")
|
||||
return
|
||||
return TRUE
|
||||
|
||||
/obj/item/stack/proc/get_main_recipes()
|
||||
SHOULD_CALL_PARENT(TRUE)
|
||||
return list()//empty list
|
||||
|
||||
/obj/item/stack/proc/update_weight()
|
||||
@@ -99,12 +122,6 @@
|
||||
else
|
||||
icon_state = "[initial(icon_state)]_3"
|
||||
|
||||
|
||||
/obj/item/stack/Destroy()
|
||||
if (usr && usr.machine==src)
|
||||
usr << browse(null, "window=stack")
|
||||
. = ..()
|
||||
|
||||
/obj/item/stack/examine(mob/user)
|
||||
. = ..()
|
||||
if (is_cyborg)
|
||||
@@ -126,151 +143,158 @@
|
||||
|
||||
/obj/item/stack/proc/get_amount()
|
||||
if(is_cyborg)
|
||||
. = round(source.energy / cost)
|
||||
. = round(source?.energy / cost)
|
||||
else
|
||||
. = (amount)
|
||||
|
||||
/obj/item/stack/attack_self(mob/user)
|
||||
interact(user)
|
||||
/**
|
||||
* Builds all recipes in a given recipe list and returns an association list containing them
|
||||
*
|
||||
* Arguments:
|
||||
* * recipe_to_iterate - The list of recipes we are using to build recipes
|
||||
*/
|
||||
/obj/item/stack/proc/recursively_build_recipes(list/recipe_to_iterate)
|
||||
var/list/L = list()
|
||||
for(var/recipe in recipe_to_iterate)
|
||||
if(istype(recipe, /datum/stack_recipe_list))
|
||||
var/datum/stack_recipe_list/R = recipe
|
||||
L["[R.title]"] = recursively_build_recipes(R.recipes)
|
||||
if(istype(recipe, /datum/stack_recipe))
|
||||
var/datum/stack_recipe/R = recipe
|
||||
L["[R.title]"] = build_recipe(R)
|
||||
return L
|
||||
|
||||
/obj/item/stack/interact(mob/user, sublist)
|
||||
ui_interact(user, sublist)
|
||||
/**
|
||||
* Returns a list of properties of a given recipe
|
||||
*
|
||||
* Arguments:
|
||||
* * R - The stack recipe we are using to get a list of properties
|
||||
*/
|
||||
/obj/item/stack/proc/build_recipe(datum/stack_recipe/R)
|
||||
return list(
|
||||
"res_amount" = R.res_amount,
|
||||
"max_res_amount" = R.max_res_amount,
|
||||
"req_amount" = R.req_amount,
|
||||
"ref" = "\ref[R]",
|
||||
)
|
||||
|
||||
/obj/item/stack/ui_interact(mob/user, recipes_sublist)
|
||||
/**
|
||||
* Checks if the recipe is valid to be used
|
||||
*
|
||||
* Arguments:
|
||||
* * R - The stack recipe we are checking if it is valid
|
||||
* * recipe_list - The list of recipes we are using to check the given recipe
|
||||
*/
|
||||
/obj/item/stack/proc/is_valid_recipe(datum/stack_recipe/R, list/recipe_list)
|
||||
for(var/S in recipe_list)
|
||||
if(S == R)
|
||||
return TRUE
|
||||
if(istype(S, /datum/stack_recipe_list))
|
||||
var/datum/stack_recipe_list/L = S
|
||||
if(is_valid_recipe(R, L.recipes))
|
||||
return TRUE
|
||||
return FALSE
|
||||
|
||||
/obj/item/stack/ui_state(mob/user)
|
||||
return GLOB.hands_state
|
||||
|
||||
/obj/item/stack/ui_interact(mob/user, datum/tgui/ui)
|
||||
ui = SStgui.try_update_ui(user, src, ui)
|
||||
if(!ui)
|
||||
ui = new(user, src, "Stack", name)
|
||||
ui.open()
|
||||
|
||||
/obj/item/stack/ui_data(mob/user)
|
||||
var/list/data = list()
|
||||
data["amount"] = get_amount()
|
||||
return data
|
||||
|
||||
/obj/item/stack/ui_static_data(mob/user)
|
||||
var/list/data = list()
|
||||
data["recipes"] = recursively_build_recipes(recipes)
|
||||
return data
|
||||
|
||||
/obj/item/stack/ui_act(action, params)
|
||||
. = ..()
|
||||
if (!recipes)
|
||||
if(.)
|
||||
return
|
||||
if (!src || get_amount() <= 0)
|
||||
user << browse(null, "window=stack")
|
||||
user.set_machine(src) //for correct work of onclose
|
||||
var/list/recipe_list = recipes
|
||||
if (recipes_sublist && recipe_list[recipes_sublist] && istype(recipe_list[recipes_sublist], /datum/stack_recipe_list))
|
||||
var/datum/stack_recipe_list/srl = recipe_list[recipes_sublist]
|
||||
recipe_list = srl.recipes
|
||||
var/t1 = "Amount Left: [get_amount()]<br>"
|
||||
for(var/i in 1 to length(recipe_list))
|
||||
var/E = recipe_list[i]
|
||||
if (isnull(E))
|
||||
t1 += "<hr>"
|
||||
continue
|
||||
if (i>1 && !isnull(recipe_list[i-1]))
|
||||
t1+="<br>"
|
||||
|
||||
if (istype(E, /datum/stack_recipe_list))
|
||||
var/datum/stack_recipe_list/srl = E
|
||||
t1 += "<a href='?src=[REF(src)];sublist=[i]'>[srl.title]</a>"
|
||||
|
||||
if (istype(E, /datum/stack_recipe))
|
||||
var/datum/stack_recipe/R = E
|
||||
var/max_multiplier = round(get_amount() / R.req_amount)
|
||||
var/title
|
||||
var/can_build = 1
|
||||
can_build = can_build && (max_multiplier>0)
|
||||
|
||||
if (R.res_amount>1)
|
||||
title+= "[R.res_amount]x [R.title]\s"
|
||||
else
|
||||
title+= "[R.title]"
|
||||
title+= " ([R.req_amount] [singular_name]\s)"
|
||||
if (can_build)
|
||||
t1 += text("<A href='?src=[REF(src)];sublist=[recipes_sublist];make=[i];multiplier=1'>[title]</A> ")
|
||||
else
|
||||
t1 += text("[]", title)
|
||||
continue
|
||||
if (R.max_res_amount>1 && max_multiplier>1)
|
||||
max_multiplier = min(max_multiplier, round(R.max_res_amount/R.res_amount))
|
||||
t1 += " |"
|
||||
var/list/multipliers = list(5,10,25)
|
||||
for (var/n in multipliers)
|
||||
if (max_multiplier>=n)
|
||||
t1 += " <A href='?src=[REF(src)];make=[i];multiplier=[n]'>[n*R.res_amount]x</A>"
|
||||
if (!(max_multiplier in multipliers))
|
||||
t1 += " <A href='?src=[REF(src)];make=[i];multiplier=[max_multiplier]'>[max_multiplier*R.res_amount]x</A>"
|
||||
|
||||
var/datum/browser/popup = new(user, "stack", name, 400, 400)
|
||||
popup.set_content(t1)
|
||||
popup.open(0)
|
||||
onclose(user, "stack")
|
||||
|
||||
/obj/item/stack/Topic(href, href_list)
|
||||
..()
|
||||
if (usr.restrained() || usr.stat || usr.get_active_held_item() != src)
|
||||
return
|
||||
if (href_list["sublist"] && !href_list["make"])
|
||||
interact(usr, text2num(href_list["sublist"]))
|
||||
if (href_list["make"])
|
||||
if (get_amount() < 1 && !is_cyborg)
|
||||
qdel(src)
|
||||
|
||||
var/list/recipes_list = recipes
|
||||
if (href_list["sublist"])
|
||||
var/datum/stack_recipe_list/srl = recipes_list[text2num(href_list["sublist"])]
|
||||
recipes_list = srl.recipes
|
||||
var/datum/stack_recipe/R = recipes_list[text2num(href_list["make"])]
|
||||
var/multiplier = text2num(href_list["multiplier"])
|
||||
if (!multiplier ||(multiplier <= 0)) //href protection
|
||||
return
|
||||
if(!building_checks(R, multiplier))
|
||||
return
|
||||
if (R.time)
|
||||
var/adjusted_time = 0
|
||||
usr.visible_message("<span class='notice'>[usr] starts building [R.title].</span>", "<span class='notice'>You start building [R.title]...</span>")
|
||||
if(HAS_TRAIT(usr, R.trait_booster))
|
||||
adjusted_time = (R.time * R.trait_modifier)
|
||||
else
|
||||
adjusted_time = R.time
|
||||
if (!do_after(usr, adjusted_time, target = usr))
|
||||
switch(action)
|
||||
if("make")
|
||||
if(get_amount() < 1 && !is_cyborg)
|
||||
qdel(src)
|
||||
return
|
||||
var/datum/stack_recipe/R = locate(params["ref"])
|
||||
if(!is_valid_recipe(R, recipes)) //href exploit protection
|
||||
return
|
||||
var/multiplier = text2num(params["multiplier"])
|
||||
if(!multiplier || (multiplier <= 0)) //href exploit protection
|
||||
return
|
||||
if(!building_checks(R, multiplier))
|
||||
return
|
||||
if(R.time)
|
||||
var/adjusted_time = 0
|
||||
usr.visible_message("<span class='notice'>[usr] starts building \a [R.title].</span>", "<span class='notice'>You start building \a [R.title]...</span>")
|
||||
if(HAS_TRAIT(usr, R.trait_booster))
|
||||
adjusted_time = (R.time * R.trait_modifier)
|
||||
else
|
||||
adjusted_time = R.time
|
||||
if(!do_after(usr, adjusted_time, target = usr))
|
||||
return
|
||||
if(!building_checks(R, multiplier))
|
||||
return
|
||||
|
||||
var/obj/O
|
||||
if(R.max_res_amount > 1) //Is it a stack?
|
||||
O = new R.result_type(usr.drop_location(), R.res_amount * multiplier)
|
||||
else if(ispath(R.result_type, /turf))
|
||||
var/turf/T = usr.drop_location()
|
||||
if(!isturf(T))
|
||||
return
|
||||
T.PlaceOnTop(R.result_type, flags = CHANGETURF_INHERIT_AIR)
|
||||
else
|
||||
O = new R.result_type(get_turf(usr))
|
||||
if(O)
|
||||
O.setDir(usr.dir)
|
||||
log_craft("[O] crafted by [usr] at [loc_name(O.loc)]")
|
||||
var/obj/O
|
||||
if(R.max_res_amount > 1) //Is it a stack?
|
||||
O = new R.result_type(usr.drop_location(), R.res_amount * multiplier)
|
||||
else if(ispath(R.result_type, /turf))
|
||||
var/turf/T = usr.drop_location()
|
||||
if(!isturf(T))
|
||||
return
|
||||
T.PlaceOnTop(R.result_type, flags = CHANGETURF_INHERIT_AIR)
|
||||
else
|
||||
O = new R.result_type(usr.drop_location())
|
||||
if(O)
|
||||
O.setDir(usr.dir)
|
||||
use(R.req_amount * multiplier)
|
||||
|
||||
use(R.req_amount * multiplier)
|
||||
if(R.applies_mats && LAZYLEN(mats_per_unit))
|
||||
if(isstack(O))
|
||||
var/obj/item/stack/crafted_stack = O
|
||||
crafted_stack.set_mats_per_unit(mats_per_unit, R.req_amount / R.res_amount)
|
||||
else
|
||||
O.set_custom_materials(mats_per_unit, R.req_amount / R.res_amount)
|
||||
|
||||
if(R.applies_mats && custom_materials && custom_materials.len)
|
||||
var/list/used_materials = list()
|
||||
for(var/i in custom_materials)
|
||||
used_materials[SSmaterials.GetMaterialRef(i)] = R.req_amount / R.res_amount * (MINERAL_MATERIAL_AMOUNT / custom_materials.len)
|
||||
O.set_custom_materials(used_materials)
|
||||
if(istype(O, /obj/structure/windoor_assembly))
|
||||
var/obj/structure/windoor_assembly/W = O
|
||||
W.ini_dir = W.dir
|
||||
else if(istype(O, /obj/structure/window))
|
||||
var/obj/structure/window/W = O
|
||||
W.ini_dir = W.dir
|
||||
|
||||
//START: oh fuck i'm so sorry
|
||||
if(istype(O, /obj/structure/windoor_assembly))
|
||||
var/obj/structure/windoor_assembly/W = O
|
||||
W.ini_dir = W.dir
|
||||
else if(istype(O, /obj/structure/window))
|
||||
var/obj/structure/window/W = O
|
||||
W.ini_dir = W.dir
|
||||
//END: oh fuck i'm so sorry
|
||||
if(QDELETED(O))
|
||||
return //It's a stack and has already been merged
|
||||
|
||||
else if(istype(O, /obj/item/restraints/handcuffs/cable))
|
||||
var/obj/item/cuffs = O
|
||||
cuffs.color = color
|
||||
if(isitem(O))
|
||||
usr.put_in_hands(O)
|
||||
O.add_fingerprint(usr)
|
||||
|
||||
if (QDELETED(O))
|
||||
return //It's a stack and has already been merged
|
||||
//BubbleWrap - so newly formed boxes are empty
|
||||
if(istype(O, /obj/item/storage))
|
||||
for (var/obj/item/I in O)
|
||||
qdel(I)
|
||||
//BubbleWrap END
|
||||
return TRUE
|
||||
|
||||
if (isitem(O))
|
||||
usr.put_in_hands(O)
|
||||
O.add_fingerprint(usr)
|
||||
|
||||
//BubbleWrap - so newly formed boxes are empty
|
||||
if ( istype(O, /obj/item/storage) )
|
||||
for (var/obj/item/I in O)
|
||||
qdel(I)
|
||||
//BubbleWrap END
|
||||
/obj/item/stack/vv_edit_var(vname, vval)
|
||||
if(vname == NAMEOF(src, amount))
|
||||
add(clamp(vval, 1-amount, max_amount - amount)) //there must always be one.
|
||||
return TRUE
|
||||
else if(vname == NAMEOF(src, max_amount))
|
||||
max_amount = max(vval, 1)
|
||||
add((max_amount < amount) ? (max_amount - amount) : 0) //update icon, weight, ect
|
||||
return TRUE
|
||||
return ..()
|
||||
|
||||
/obj/item/stack/proc/building_checks(datum/stack_recipe/R, multiplier)
|
||||
if (get_amount() < R.req_amount*multiplier)
|
||||
@@ -330,10 +354,7 @@
|
||||
if(check && zero_amount())
|
||||
return TRUE
|
||||
if(length(mats_per_unit))
|
||||
var/temp_materials = custom_materials.Copy()
|
||||
for(var/i in mats_per_unit)
|
||||
temp_materials[i] = mats_per_unit[i] * src.amount
|
||||
set_custom_materials(temp_materials)
|
||||
update_custom_materials()
|
||||
update_icon()
|
||||
update_weight()
|
||||
return TRUE
|
||||
@@ -357,22 +378,36 @@
|
||||
return source.energy < cost
|
||||
if(amount < 1)
|
||||
qdel(src)
|
||||
return 1
|
||||
return 0
|
||||
return TRUE
|
||||
return FALSE
|
||||
|
||||
/obj/item/stack/proc/add(amount)
|
||||
/** Adds some number of units to this stack.
|
||||
*
|
||||
* Arguments:
|
||||
* - _amount: The number of units to add to this stack.
|
||||
*/
|
||||
/obj/item/stack/proc/add(_amount)
|
||||
if (is_cyborg)
|
||||
source.add_charge(amount * cost)
|
||||
source.add_charge(_amount * cost)
|
||||
else
|
||||
src.amount += amount
|
||||
amount += _amount
|
||||
if(length(mats_per_unit))
|
||||
var/temp_materials = custom_materials.Copy()
|
||||
for(var/i in mats_per_unit)
|
||||
temp_materials[i] = mats_per_unit[i] * src.amount
|
||||
set_custom_materials(temp_materials)
|
||||
update_custom_materials()
|
||||
update_icon()
|
||||
update_weight()
|
||||
|
||||
/** Checks whether this stack can merge itself into another stack.
|
||||
*
|
||||
* Arguments:
|
||||
* - [check][/obj/item/stack]: The stack to check for mergeability.
|
||||
*/
|
||||
/obj/item/stack/proc/can_merge(obj/item/stack/check)
|
||||
if(!istype(check, merge_type))
|
||||
return FALSE
|
||||
if(!check.is_cyborg && (mats_per_unit != check.mats_per_unit)) // Cyborg stacks don't have materials. This lets them recycle sheets and floor tiles.
|
||||
return FALSE
|
||||
return TRUE
|
||||
|
||||
/obj/item/stack/proc/merge(obj/item/stack/S) //Merge src into S, as much as possible
|
||||
if(QDELETED(S) || QDELETED(src) || S == src) //amusingly this can cause a stack to consume itself, let's not allow that.
|
||||
return
|
||||
@@ -388,50 +423,51 @@
|
||||
S.add(transfer)
|
||||
return transfer
|
||||
|
||||
/obj/item/stack/Crossed(obj/o)
|
||||
if(istype(o, merge_type) && !o.throwing)
|
||||
merge(o)
|
||||
/obj/item/stack/Crossed(atom/movable/crossing)
|
||||
if(!crossing.throwing && can_merge(crossing))
|
||||
merge(crossing)
|
||||
. = ..()
|
||||
|
||||
/obj/item/stack/hitby(atom/movable/AM, skipcatch, hitpush, blocked, datum/thrownthing/throwingdatum)
|
||||
if(istype(AM, merge_type))
|
||||
merge(AM)
|
||||
/obj/item/stack/hitby(atom/movable/hitting, skipcatch, hitpush, blocked, datum/thrownthing/throwingdatum)
|
||||
if(can_merge(hitting))
|
||||
merge(hitting)
|
||||
. = ..()
|
||||
|
||||
/obj/item/stack/on_attack_hand(mob/user, act_intent = user.a_intent, unarmed_attack_flags)
|
||||
//ATTACK HAND IGNORING PARENT RETURN VALUE
|
||||
/obj/item/stack/on_attack_hand(mob/user)
|
||||
if(user.get_inactive_held_item() == src)
|
||||
if(zero_amount())
|
||||
return
|
||||
return change_stack(user,1)
|
||||
else
|
||||
. = ..()
|
||||
return split_stack(user, 1)
|
||||
|
||||
/obj/item/stack/AltClick(mob/living/user)
|
||||
. = ..()
|
||||
if(!istype(user) || !user.canUseTopic(src, BE_CLOSE, ismonkey(user)))
|
||||
if(isturf(loc)) // to prevent people that are alt clicking a tile to see its content from getting undesidered pop ups
|
||||
return
|
||||
if(is_cyborg)
|
||||
if(is_cyborg || !user.canUseTopic(src, BE_CLOSE, NO_DEXTERITY, FALSE) || zero_amount()) //, !iscyborg(user)
|
||||
return
|
||||
else
|
||||
if(zero_amount())
|
||||
return
|
||||
//get amount from user
|
||||
var/max = get_amount()
|
||||
var/stackmaterial = round(input(user,"How many sheets do you wish to take out of this stack? (Maximum [max])") as null|num)
|
||||
max = get_amount()
|
||||
stackmaterial = min(max, stackmaterial)
|
||||
if(stackmaterial == null || stackmaterial <= 0 || !user.canUseTopic(src, BE_CLOSE, ismonkey(user)))
|
||||
return TRUE
|
||||
else
|
||||
change_stack(user, stackmaterial)
|
||||
to_chat(user, "<span class='notice'>You take [stackmaterial] sheets out of the stack</span>")
|
||||
return TRUE
|
||||
//get amount from user
|
||||
var/max = get_amount()
|
||||
var/stackmaterial = round(input(user,"How many sheets do you wish to take out of this stack? (Maximum [max])") as null|num)
|
||||
max = get_amount()
|
||||
stackmaterial = min(max, stackmaterial)
|
||||
if(stackmaterial == null || stackmaterial <= 0 || !user.canUseTopic(src, BE_CLOSE, NO_DEXTERITY, FALSE)) //, !iscyborg(user)
|
||||
return
|
||||
split_stack(user, stackmaterial)
|
||||
to_chat(user, "<span class='notice'>You take [stackmaterial] sheets out of the stack.</span>")
|
||||
|
||||
/obj/item/stack/proc/change_stack(mob/user, amount)
|
||||
/** Splits the stack into two stacks.
|
||||
*
|
||||
* Arguments:
|
||||
* - [user][/mob]: The mob splitting the stack.
|
||||
* - amount: The number of units to split from this stack.
|
||||
*/
|
||||
/obj/item/stack/proc/split_stack(mob/user, amount)
|
||||
if(!use(amount, TRUE, FALSE))
|
||||
return FALSE
|
||||
return null
|
||||
var/obj/item/stack/F = new type(user? user : drop_location(), amount, FALSE)
|
||||
. = F
|
||||
F.set_mats_per_unit(mats_per_unit, 1) // Required for greyscale sheets and tiles.
|
||||
F.copy_evidences(src)
|
||||
if(user)
|
||||
if(!user.put_in_hands(F, merge_stacks = FALSE))
|
||||
@@ -441,7 +477,7 @@
|
||||
zero_amount()
|
||||
|
||||
/obj/item/stack/attackby(obj/item/W, mob/user, params)
|
||||
if(istype(W, merge_type))
|
||||
if(can_merge(W))
|
||||
var/obj/item/stack/S = W
|
||||
if(merge(S))
|
||||
to_chat(user, "<span class='notice'>Your [S.name] stack now contains [S.get_amount()] [S.singular_name]\s.</span>")
|
||||
@@ -449,14 +485,11 @@
|
||||
. = ..()
|
||||
|
||||
/obj/item/stack/proc/copy_evidences(obj/item/stack/from)
|
||||
if(from.blood_DNA)
|
||||
blood_DNA = from.blood_DNA.Copy()
|
||||
if(from.fingerprints)
|
||||
fingerprints = from.fingerprints.Copy()
|
||||
if(from.fingerprintshidden)
|
||||
fingerprintshidden = from.fingerprintshidden.Copy()
|
||||
if(from.fingerprintslast)
|
||||
fingerprintslast = from.fingerprintslast
|
||||
add_blood_DNA(from.return_blood_DNA())
|
||||
add_fingerprint_list(from.return_fingerprints())
|
||||
add_hiddenprint_list(from.return_hiddenprints())
|
||||
fingerprintslast = from.fingerprintslast
|
||||
//TODO bloody overlay
|
||||
|
||||
/obj/item/stack/microwave_act(obj/machinery/microwave/M)
|
||||
if(istype(M) && M.dirty < 100)
|
||||
|
||||
@@ -7,7 +7,9 @@
|
||||
desc = "Controls a stacking machine... in theory."
|
||||
density = FALSE
|
||||
circuit = /obj/item/circuitboard/machine/stacking_unit_console
|
||||
/// Connected stacking machine
|
||||
var/obj/machinery/mineral/stacking_machine/machine
|
||||
/// Direction for which console looks for stacking machine to connect to
|
||||
var/machinedir = SOUTHEAST
|
||||
|
||||
/obj/machinery/mineral/stacking_unit_console/Initialize()
|
||||
@@ -16,50 +18,53 @@
|
||||
if (machine)
|
||||
machine.CONSOLE = src
|
||||
|
||||
/obj/machinery/mineral/stacking_unit_console/ui_interact(mob/user)
|
||||
. = ..()
|
||||
|
||||
if(!machine)
|
||||
to_chat(user, "<span class='notice'>[src] is not linked to a machine!</span>")
|
||||
return
|
||||
|
||||
var/obj/item/stack/sheet/s
|
||||
var/dat
|
||||
|
||||
dat += text("<b>Stacking unit console</b><br><br>")
|
||||
|
||||
for(var/O in machine.stack_list)
|
||||
s = machine.stack_list[O]
|
||||
if(s.amount > 0)
|
||||
dat += text("[capitalize(s.name)]: [s.amount] <A href='?src=[REF(src)];release=[s.type]'>Release</A><br>")
|
||||
|
||||
dat += text("<br>Stacking: [machine.stack_amt]<br><br>")
|
||||
|
||||
user << browse(dat, "window=console_stacking_machine")
|
||||
|
||||
/obj/machinery/mineral/stacking_unit_console/multitool_act(mob/living/user, obj/item/I)
|
||||
if(istype(I, /obj/item/multitool))
|
||||
var/obj/item/multitool/M = I
|
||||
M.buffer = src
|
||||
to_chat(user, "<span class='notice'>You store linkage information in [I]'s buffer.</span>")
|
||||
return TRUE
|
||||
|
||||
/obj/machinery/mineral/stacking_unit_console/Topic(href, href_list)
|
||||
if(..())
|
||||
if(!multitool_check_buffer(user, I))
|
||||
return
|
||||
usr.set_machine(src)
|
||||
src.add_fingerprint(usr)
|
||||
if(href_list["release"])
|
||||
if(!(text2path(href_list["release"]) in machine.stack_list))
|
||||
return //someone tried to spawn materials by spoofing hrefs
|
||||
var/obj/item/stack/sheet/inp = machine.stack_list[text2path(href_list["release"])]
|
||||
var/obj/item/stack/sheet/out = new inp.type(null, inp.amount)
|
||||
inp.amount = 0
|
||||
machine.unload_mineral(out)
|
||||
var/obj/item/multitool/M = I
|
||||
M.buffer = src
|
||||
to_chat(user, "<span class='notice'>You store linkage information in [I]'s buffer.</span>")
|
||||
return TRUE
|
||||
|
||||
src.updateUsrDialog()
|
||||
return
|
||||
/obj/machinery/mineral/stacking_unit_console/ui_interact(mob/user, datum/tgui/ui)
|
||||
ui = SStgui.try_update_ui(user, src, ui)
|
||||
if(!ui)
|
||||
ui = new(user, src, "StackingConsole", name)
|
||||
ui.open()
|
||||
|
||||
/obj/machinery/mineral/stacking_unit_console/ui_data(mob/user)
|
||||
var/list/data = list()
|
||||
data["machine"] = machine ? TRUE : FALSE
|
||||
data["stacking_amount"] = null
|
||||
data["contents"] = list()
|
||||
if(machine)
|
||||
data["stacking_amount"] = machine.stack_amt
|
||||
for(var/stack_type in machine.stack_list)
|
||||
var/obj/item/stack/sheet/stored_sheet = machine.stack_list[stack_type]
|
||||
if(stored_sheet.amount <= 0)
|
||||
continue
|
||||
data["contents"] += list(list(
|
||||
"type" = stored_sheet.type,
|
||||
"name" = capitalize(stored_sheet.name),
|
||||
"amount" = stored_sheet.amount,
|
||||
))
|
||||
return data
|
||||
|
||||
/obj/machinery/mineral/stacking_unit_console/ui_act(action, list/params)
|
||||
. = ..()
|
||||
if(.)
|
||||
return
|
||||
|
||||
switch(action)
|
||||
if("release")
|
||||
var/obj/item/stack/sheet/released_type = text2path(params["type"])
|
||||
if(!released_type || !(initial(released_type.merge_type) in machine.stack_list))
|
||||
return //someone tried to spawn materials by spoofing hrefs
|
||||
var/obj/item/stack/sheet/inp = machine.stack_list[initial(released_type.merge_type)]
|
||||
var/obj/item/stack/sheet/out = new inp.type(null, inp.amount)
|
||||
inp.amount = 0
|
||||
machine.unload_mineral(out)
|
||||
return TRUE
|
||||
|
||||
/**********************Mineral stacking unit**************************/
|
||||
|
||||
@@ -108,6 +113,17 @@
|
||||
/obj/machinery/mineral/stacking_machine/proc/process_sheet(obj/item/stack/sheet/inp)
|
||||
if(QDELETED(inp))
|
||||
return
|
||||
|
||||
// Dump the sheets to the silo if attached
|
||||
if(materials.silo && !materials.on_hold())
|
||||
var/matlist = inp.custom_materials & materials.mat_container.materials
|
||||
if (length(matlist))
|
||||
var/inserted = materials.mat_container.insert_item(inp)
|
||||
materials.silo_log(src, "collected", inserted, "sheets", matlist)
|
||||
qdel(inp)
|
||||
return
|
||||
|
||||
// No silo attached process to internal storage
|
||||
var/key = inp.merge_type
|
||||
var/obj/item/stack/sheet/storage = stack_list[key]
|
||||
if(!storage) //It's the first of this sheet added
|
||||
@@ -115,15 +131,6 @@
|
||||
storage.amount += inp.amount //Stack the sheets
|
||||
qdel(inp)
|
||||
|
||||
if(materials.silo && !materials.on_hold()) //Dump the sheets to the silo
|
||||
var/matlist = storage.custom_materials & materials.mat_container.materials
|
||||
if (length(matlist))
|
||||
var/inserted = materials.mat_container.insert_item(storage)
|
||||
materials.silo_log(src, "collected", inserted, "sheets", matlist)
|
||||
if (QDELETED(storage))
|
||||
stack_list -= key
|
||||
return
|
||||
|
||||
while(storage.amount >= stack_amt) //Get rid of excessive stackage
|
||||
var/obj/item/stack/sheet/out = new inp.type(null, stack_amt)
|
||||
unload_mineral(out)
|
||||
|
||||
78
code/modules/mob/living/silicon/ai/ai_portrait_picker.dm
Normal file
78
code/modules/mob/living/silicon/ai/ai_portrait_picker.dm
Normal file
@@ -0,0 +1,78 @@
|
||||
|
||||
//Portrait picker! It's a tgui window that lets you look through all the portraits, and choose one as your AI.
|
||||
|
||||
//very similar to centcom_podlauncher in terms of how this is coded, so i kept a lot of comments from it
|
||||
//^ wow! it's the second time i've said this! i'm a real coder now, copying my statement of copying other people's stuff.
|
||||
|
||||
|
||||
#define TAB_LIBRARY 1
|
||||
#define TAB_SECURE 2
|
||||
#define TAB_PRIVATE 3
|
||||
|
||||
/datum/portrait_picker
|
||||
var/client/holder //client of whoever is using this datum
|
||||
|
||||
/datum/portrait_picker/New(user)//user can either be a client or a mob due to byondcode(tm)
|
||||
if (istype(user, /client))
|
||||
var/client/user_client = user
|
||||
holder = user_client //if its a client, assign it to holder
|
||||
else
|
||||
var/mob/user_mob = user
|
||||
holder = user_mob.client //if its a mob, assign the mob's client to holder
|
||||
|
||||
/datum/portrait_picker/ui_interact(mob/user, datum/tgui/ui)
|
||||
ui = SStgui.try_update_ui(user, src, ui)
|
||||
if(!ui)
|
||||
ui = new(user, src, "PortraitPicker")
|
||||
ui.open()
|
||||
|
||||
/datum/portrait_picker/ui_close()
|
||||
qdel(src)
|
||||
|
||||
/datum/portrait_picker/ui_state(mob/user)
|
||||
return GLOB.conscious_state
|
||||
|
||||
/datum/portrait_picker/ui_assets(mob/user)
|
||||
return list(
|
||||
get_asset_datum(/datum/asset/simple/portraits/library),
|
||||
get_asset_datum(/datum/asset/simple/portraits/library_secure),
|
||||
get_asset_datum(/datum/asset/simple/portraits/library_private)
|
||||
)
|
||||
|
||||
/datum/portrait_picker/ui_data(mob/user)
|
||||
var/list/data = list()
|
||||
data["library"] = SSpersistence.paintings["library"] ? SSpersistence.paintings["library"] : 0
|
||||
data["library_secure"] = SSpersistence.paintings["library_secure"] ? SSpersistence.paintings["library_secure"] : 0
|
||||
data["library_private"] = SSpersistence.paintings["library_private"] ? SSpersistence.paintings["library_private"] : 0 //i'm gonna regret this, won't i?
|
||||
return data
|
||||
|
||||
/datum/portrait_picker/ui_act(action, params)
|
||||
. = ..()
|
||||
if(.)
|
||||
return
|
||||
switch(action)
|
||||
if("select")
|
||||
var/list/tab2key = list(TAB_LIBRARY = "library", TAB_SECURE = "library_secure", TAB_PRIVATE = "library_private")
|
||||
var/folder = tab2key[params["tab"]]
|
||||
var/list/current_list = SSpersistence.paintings[folder]
|
||||
var/list/chosen_portrait = current_list[params["selected"]]
|
||||
var/png = "data/paintings/[folder]/[chosen_portrait["md5"]].png"
|
||||
var/icon/portrait_icon = new(png)
|
||||
var/mob/living/ai = holder.mob
|
||||
var/w = portrait_icon.Width()
|
||||
var/h = portrait_icon.Height()
|
||||
var/mutable_appearance/MA = mutable_appearance(portrait_icon)
|
||||
if(w == 23 || h == 23)
|
||||
to_chat(ai, "<span class='notice'>Small note: 23x23 Portraits are accepted, but they do not fit perfectly inside the display frame.</span>")
|
||||
MA.pixel_x = 5
|
||||
MA.pixel_y = 5
|
||||
else if(w == 24 || h == 24)
|
||||
to_chat(ai, "<span class='notice'>Portrait Accepted. Enjoy!</span>")
|
||||
MA.pixel_x = 4
|
||||
MA.pixel_y = 4
|
||||
else
|
||||
to_chat(ai, "<span class='warning'>Sorry, only 23x23 and 24x24 Portraits are accepted.</span>")
|
||||
return
|
||||
ai.cut_overlays() //so people can't keep repeatedly select portraits to add stacking overlays
|
||||
ai.icon_state = "ai-portrait-active"//background
|
||||
ai.add_overlay(MA)
|
||||
@@ -11,7 +11,6 @@
|
||||
#define MODE_WRITING 1
|
||||
#define MODE_STAMPING 2
|
||||
|
||||
|
||||
/**
|
||||
* Paper is now using markdown (like in github pull notes) for ALL rendering
|
||||
* so we do loose a bit of functionality but we gain in easy of use of
|
||||
@@ -23,9 +22,6 @@
|
||||
icon = 'icons/obj/bureaucracy.dmi'
|
||||
icon_state = "paper"
|
||||
item_state = "paper"
|
||||
// inhand_icon_state = "paper"
|
||||
// worn_icon_state = "paper"
|
||||
// custom_fire_overlay = "paper_onfire_overlay"
|
||||
throwforce = 0
|
||||
w_class = WEIGHT_CLASS_TINY
|
||||
throw_range = 1
|
||||
@@ -102,8 +98,8 @@
|
||||
|
||||
/obj/item/paper/Initialize()
|
||||
. = ..()
|
||||
pixel_y = rand(-8, 8)
|
||||
pixel_x = rand(-9, 9)
|
||||
pixel_x = base_pixel_x + rand(-9, 9)
|
||||
pixel_y = base_pixel_y + rand(-8, 8)
|
||||
update_icon()
|
||||
|
||||
/obj/item/paper/update_icon_state()
|
||||
@@ -193,13 +189,6 @@
|
||||
user.visible_message(ignition_message)
|
||||
add_fingerprint(user)
|
||||
fire_act(I.get_temperature())
|
||||
//I would have it become a paper plane before the throw, but that would risk runtimes
|
||||
/obj/item/paper/DoRevenantThrowEffects(atom/target)
|
||||
sleep(10)
|
||||
if(HAS_TRAIT(src, TRAIT_SPOOKY_THROW))
|
||||
return
|
||||
new /obj/item/paperplane(get_turf(src))
|
||||
qdel(src)
|
||||
|
||||
/obj/item/paper/attackby(obj/item/P, mob/living/user, params)
|
||||
if(burn_paper_product_attackby_check(P, user))
|
||||
@@ -253,6 +242,8 @@
|
||||
|
||||
/obj/item/paper/ui_data(mob/user)
|
||||
var/list/data = list()
|
||||
data["edit_usr"] = "[user]"
|
||||
|
||||
var/obj/O = user.get_active_held_item()
|
||||
if(istype(O, /obj/item/toy/crayon))
|
||||
var/obj/item/toy/crayon/PEN = O
|
||||
@@ -291,7 +282,8 @@
|
||||
return data
|
||||
|
||||
/obj/item/paper/ui_act(action, params,datum/tgui/ui)
|
||||
if(..())
|
||||
. = ..()
|
||||
if(.)
|
||||
return
|
||||
switch(action)
|
||||
if("stamp")
|
||||
@@ -317,7 +309,8 @@
|
||||
LAZYADD(stamped, stamp_icon_state)
|
||||
|
||||
update_static_data(usr,ui)
|
||||
ui.user.visible_message("<span class='notice'>[ui.user] stamps [src] with [stamp_class]!</span>", "<span class='notice'>You stamp [src] with [stamp_class]!</span>")
|
||||
var/obj/O = ui.user.get_active_held_item()
|
||||
ui.user.visible_message("<span class='notice'>[ui.user] stamps [src] with \the [O.name]!</span>", "<span class='notice'>You stamp [src] with \the [O.name]!</span>")
|
||||
else
|
||||
to_chat(usr, pick("You try to stamp but you miss!", "There is no where else you can stamp!"))
|
||||
. = TRUE
|
||||
|
||||
@@ -2635,6 +2635,7 @@
|
||||
#include "code\modules\mob\living\silicon\silicon_movement.dm"
|
||||
#include "code\modules\mob\living\silicon\ai\ai.dm"
|
||||
#include "code\modules\mob\living\silicon\ai\ai_defense.dm"
|
||||
#include "code\modules\mob\living\silicon\ai\ai_portrait_picker.dm"
|
||||
#include "code\modules\mob\living\silicon\ai\death.dm"
|
||||
#include "code\modules\mob\living\silicon\ai\examine.dm"
|
||||
#include "code\modules\mob\living\silicon\ai\laws.dm"
|
||||
|
||||
@@ -36,13 +36,13 @@ export const ThermoMachine = (props, context) => {
|
||||
onClick={() => act('power')} />
|
||||
)}>
|
||||
<LabeledList>
|
||||
<LabeledList.Item label="Setting">
|
||||
{/* <LabeledList.Item label="Setting">
|
||||
<Button
|
||||
icon={data.cooling ? 'cooling' : 'heating'}
|
||||
content={data.cooling ? 'Cooling' : 'Heating'}
|
||||
selected={data.cooling}
|
||||
onClick={() => act('cooling')} />
|
||||
</LabeledList.Item>
|
||||
</LabeledList.Item> */}
|
||||
<LabeledList.Item label="Target Temperature">
|
||||
<NumberInput
|
||||
animated
|
||||
|
||||
File diff suppressed because one or more lines are too long
Reference in New Issue
Block a user