Adds radial support + balloon alerts to stack crafting, cult metal now uses a radial when making buildings (#66938)

* Adds radial support to stack crafting
- uses it for runed metal

* Unit tests

* Balloon alerts and toilet lives
This commit is contained in:
MrMelbert
2022-05-16 09:34:52 -04:00
committed by GitHub
parent 35f17d5745
commit 4fa6e49c61
6 changed files with 450 additions and 206 deletions
@@ -0,0 +1,114 @@
// Note, the order these in are deliberate, as it affects
// the order they are shown via radial.
GLOBAL_LIST_INIT(runed_metal_recipes, list( \
new /datum/stack_recipe/radial( \
title = "pylon", \
result_type = /obj/structure/destructible/cult/pylon, \
req_amount = 4, \
time = 4 SECONDS, \
one_per_turf = TRUE, \
on_floor = TRUE, \
desc = span_cultbold("Pylon: Heals and regenerates the blood of nearby blood cultists and constructs, and also \
converts nearby floor tiles into engraved flooring, which allows blood cultists to scribe runes faster."), \
required_noun = "runed metal sheet", \
), \
new /datum/stack_recipe/radial( \
title = "altar", \
result_type = /obj/structure/destructible/cult/item_dispenser/altar, \
req_amount = 3, \
time = 4 SECONDS, \
one_per_turf = TRUE, \
on_floor = TRUE, \
desc = span_cultbold("Altar: Can make Eldritch Whetstones, Construct Shells, and Flasks of Unholy Water."), \
required_noun = "runed metal sheet", \
), \
new /datum/stack_recipe/radial( \
title = "archives", \
result_type = /obj/structure/destructible/cult/item_dispenser/archives, \
req_amount = 3, \
time = 4 SECONDS, \
one_per_turf = TRUE, \
on_floor = TRUE, \
desc = span_cultbold("Archives: Can make Zealot's Blindfolds, Shuttle Curse Orbs, \
and Veil Walker equipment. Emits Light."), \
required_noun = "runed metal sheet", \
), \
new /datum/stack_recipe/radial( \
title = "daemon forge", \
result_type = /obj/structure/destructible/cult/item_dispenser/forge, \
req_amount = 3, \
time = 4 SECONDS, \
one_per_turf = TRUE, \
on_floor = TRUE, \
desc = span_cultbold("Daemon Forge: Can make Nar'Sien Hardened Armor, Flagellant's Robes, \
and Eldritch Longswords. Emits Light."), \
required_noun = "runed metal sheet", \
), \
new /datum/stack_recipe/radial( \
title = "runed door", \
result_type = /obj/machinery/door/airlock/cult, \
time = 5 SECONDS, \
one_per_turf = TRUE, \
on_floor = TRUE, \
desc = span_cultbold("Runed Door: A weak door which stuns non-blood cultists who touch it."), \
required_noun = "runed metal sheet", \
), \
new /datum/stack_recipe/radial( \
title = "runed girder", \
result_type = /obj/structure/girder/cult, \
time = 5 SECONDS, \
one_per_turf = TRUE, \
on_floor = TRUE, \
desc = span_cultbold("Runed Girder: A weak girder that can be instantly destroyed by ritual daggers. Not a recommended usage of runed metal."), \
required_noun = "runed metal sheet", \
), \
))
/obj/item/stack/sheet/runed_metal
name = "runed metal"
desc = "Sheets of cold metal with shifting inscriptions writ upon them."
singular_name = "runed metal sheet"
icon_state = "sheet-runed"
inhand_icon_state = "sheet-runed"
icon = 'icons/obj/stack_objects.dmi'
mats_per_unit = list(/datum/material/runedmetal = MINERAL_MATERIAL_AMOUNT)
sheettype = "runed"
merge_type = /obj/item/stack/sheet/runed_metal
novariants = TRUE
grind_results = list(/datum/reagent/iron = 5, /datum/reagent/blood = 15)
material_type = /datum/material/runedmetal
has_unique_girder = TRUE
use_radial = TRUE
/obj/item/stack/sheet/runed_metal/interact(mob/user)
if(!IS_CULTIST(user))
to_chat(user, span_warning("Only one with forbidden knowledge could hope to work this metal..."))
return FALSE
var/turf/user_turf = get_turf(user)
var/area/user_area = get_area(user)
var/is_valid_turf = user_turf && (is_station_level(user_turf.z) || is_mining_level(user_turf.z))
var/is_valid_area = user_area && (user_area.area_flags & CULT_PERMITTED)
if(!is_valid_turf || !is_valid_area)
to_chat(user, span_warning("The veil is not weak enough here."))
return FALSE
return ..()
/obj/item/stack/sheet/runed_metal/radial_check(mob/builder)
return ..() && IS_CULTIST(builder)
/obj/item/stack/sheet/runed_metal/get_main_recipes()
. = ..()
. += GLOB.runed_metal_recipes
/obj/item/stack/sheet/runed_metal/fifty
amount = 50
/obj/item/stack/sheet/runed_metal/ten
amount = 10
/obj/item/stack/sheet/runed_metal/five
amount = 5
@@ -564,59 +564,6 @@ GLOBAL_LIST_INIT(cardboard_recipes, list ( \
else
. = ..()
/*
* Runed Metal
*/
GLOBAL_LIST_INIT(runed_metal_recipes, list ( \
new /datum/stack_recipe("runed door (a weak door that stuns non-cultists who touch it)", /obj/machinery/door/airlock/cult, 1, time = 5 SECONDS, one_per_turf = TRUE, on_floor = TRUE), \
new /datum/stack_recipe("runed girder (not a recommended usage of runed metal)", /obj/structure/girder/cult, 1, time = 5 SECONDS, one_per_turf = TRUE, on_floor = TRUE), \
new /datum/stack_recipe("pylon (heals (and regenerates the blood of) nearby blood cultists and constructs, but also turns nearby floor tiles into engraved flooring)", /obj/structure/destructible/cult/pylon, 4, time = 4 SECONDS, one_per_turf = TRUE, on_floor = TRUE), \
new /datum/stack_recipe("daemon forge (can make Nar'Sien hardened armor, flagellant's robes, and eldritch longswords)", /obj/structure/destructible/cult/item_dispenser/forge, 3, time = 4 SECONDS, one_per_turf = TRUE, on_floor = TRUE), \
new /datum/stack_recipe("archives (can make zealot's blindfolds, shuttle curse orbs, and veil walker equipment)", /obj/structure/destructible/cult/item_dispenser/archives, 3, time = 4 SECONDS, one_per_turf = TRUE, on_floor = TRUE), \
new /datum/stack_recipe("altar (can make eldritch whetstones, construct shells, and flasks of unholy water)", /obj/structure/destructible/cult/item_dispenser/altar, 3, time = 4 SECONDS, one_per_turf = TRUE, on_floor = TRUE), \
))
/obj/item/stack/sheet/runed_metal
name = "runed metal"
desc = "Sheets of cold metal with shifting inscriptions writ upon them."
singular_name = "runed metal sheet"
icon_state = "sheet-runed"
inhand_icon_state = "sheet-runed"
icon = 'icons/obj/stack_objects.dmi'
mats_per_unit = list(/datum/material/runedmetal = MINERAL_MATERIAL_AMOUNT)
sheettype = "runed"
merge_type = /obj/item/stack/sheet/runed_metal
novariants = TRUE
grind_results = list(/datum/reagent/iron = 5, /datum/reagent/blood = 15)
material_type = /datum/material/runedmetal
has_unique_girder = TRUE
/obj/item/stack/sheet/runed_metal/attack_self(mob/living/user)
if(!IS_CULTIST(user))
to_chat(user, span_warning("Only one with forbidden knowledge could hope to work this metal..."))
return
var/turf/T = get_turf(user) //we may have moved. adjust as needed...
var/area/A = get_area(user)
if((!is_station_level(T.z) && !is_mining_level(T.z)) || (A && !(A.area_flags & CULT_PERMITTED)))
to_chat(user, span_warning("The veil is not weak enough here."))
return FALSE
return ..()
/obj/item/stack/sheet/runed_metal/get_main_recipes()
. = ..()
. += GLOB.runed_metal_recipes
/obj/item/stack/sheet/runed_metal/fifty
amount = 50
/obj/item/stack/sheet/runed_metal/ten
amount = 10
/obj/item/stack/sheet/runed_metal/five
amount = 5
/*
* Bronze
*/
+230 -153
View File
@@ -1,8 +1,8 @@
//stack recipe placement check types
/// Checks if there is an object of the result type in any of the cardinal directions
#define STACK_CHECK_CARDINALS "cardinals"
#define STACK_CHECK_CARDINALS (1<<0)
/// Checks if there is an object of the result type within one tile
#define STACK_CHECK_ADJACENT "adjacent"
#define STACK_CHECK_ADJACENT (1<<1)
/* Stack type objects!
* Contains:
@@ -20,35 +20,60 @@
gender = PLURAL
material_modifier = 0.05 //5%, so that a 50 sheet stack has the effect of 5k materials instead of 100k.
max_integrity = 100
/// A list to all recipies this stack item can create.
var/list/datum/stack_recipe/recipes
/// What's the name of just 1 of this stack. You have a stack of leather, but one piece of leather
var/singular_name
/// How much is in this stack?
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 = FALSE // It's TRUE if module is used by a cyborg, and uses its storage
/// How much is allowed in this stack?
// Also see stack recipes initialisation. "max_res_amount" must be equal to this max_amount
var/max_amount = 50
/// If TRUE, this stack is a module used by a cyborg (doesn't run out like normal / etc)
var/is_cyborg = FALSE
/// Related to above. If present, the energy we draw from when using stack items, for cyborgs
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
var/full_w_class = WEIGHT_CLASS_NORMAL //The weight class the stack should have at amount > 2/3rds max_amount
var/novariants = TRUE //Determines whether the item should update it's sprites based on amount.
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
/// Related to above. How much energy it costs from storage to use stack items
var/cost = 1
/// This path and its children should merge with this stack, defaults to src.type
var/merge_type = null
/// The weight class the stack has at amount > 2/3rds max_amount
var/full_w_class = WEIGHT_CLASS_NORMAL
/// Determines whether the item should update it's sprites based on amount.
var/novariants = TRUE
/// List that tells you how much is in a single unit.
var/list/mats_per_unit
/// Datum material type that this stack is made of
var/material_type
//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)
// The following are all for medical treatment, they're here instead of /stack/medical because sticky tape can be used as a makeshift bandage or splint
/// If set and this used as a splint for a broken bone wound, this is used as a multiplier for applicable slowdowns (lower = better) (also for speeding up burn recoveries)
var/splint_factor
/// Like splint_factor but for burns instead of bone wounds. This is a multiplier used to speed up burn recoveries
var/burn_cleanliness_bonus
/// How much blood flow this stack can absorb if used as a bandage on a cut wound, note that absorption is how much we lower the flow rate, not the raw amount of blood we suck up
var/absorption_capacity
/// How quickly we lower the blood flow on a cut wound we're bandaging. Expected lifetime of this bandage in seconds is thus absorption_capacity/absorption_rate, or until the cut heals, whichever comes first
var/absorption_rate
/// Amount of matter for RCD
// 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()
/// Amount of matter given back to RCDs
var/matter_amount = 0
/// Does this stack require a unique girder in order to make a wall?
var/has_unique_girder = FALSE
/// What typepath table we create from this stack
var/obj/structure/table/tableVariant
/// If TRUE, we'll use a radial instead when displaying recipes
var/use_radial = FALSE
/// If use_radial is TRUE, this is the radius of the radial
var/radial_radius = 52
// The following are all for medical treatment
// They're here instead of /stack/medical
// because sticky tape can be used as a makeshift bandage or splint
/// If set and this used as a splint for a broken bone wound,
/// This is used as a multiplier for applicable slowdowns (lower = better) (also for speeding up burn recoveries)
var/splint_factor
/// Like splint_factor but for burns instead of bone wounds. This is a multiplier used to speed up burn recoveries
var/burn_cleanliness_bonus
/// How much blood flow this stack can absorb if used as a bandage on a cut wound.
/// note that absorption is how much we lower the flow rate, not the raw amount of blood we suck up
var/absorption_capacity
/// How quickly we lower the blood flow on a cut wound we're bandaging.
/// Expected lifetime of this bandage in seconds is thus absorption_capacity/absorption_rate,
/// or until the cut heals, whichever comes first
var/absorption_rate
/obj/item/stack/Initialize(mapload, new_amount, merge = TRUE, list/mat_override=null, mat_amt=1)
if(new_amount != null)
@@ -75,18 +100,17 @@
INVOKE_ASYNC(src, .proc/merge_without_del, item_stack)
if(is_zero_amount(delete_if_zero = FALSE))
return INITIALIZE_HINT_QDEL
var/list/temp_recipes = get_main_recipes()
recipes = temp_recipes.Copy()
recipes = get_main_recipes().Copy()
if(material_type)
var/datum/material/M = GET_MATERIAL_REF(material_type) //First/main material
for(var/i in M.categories)
switch(i)
var/datum/material/what_are_we_made_of = GET_MATERIAL_REF(material_type) //First/main material
for(var/category in what_are_we_made_of.categories)
switch(category)
if(MAT_CATEGORY_BASE_RECIPES)
var/list/temp = SSmaterials.base_stack_recipes.Copy()
recipes += temp
recipes |= SSmaterials.base_stack_recipes.Copy()
if(MAT_CATEGORY_RIGID)
var/list/temp = SSmaterials.rigid_stack_recipes.Copy()
recipes += temp
recipes |= SSmaterials.rigid_stack_recipes.Copy()
update_weight()
update_appearance()
var/static/list/loc_connections = list(
@@ -128,8 +152,10 @@
return TRUE
/obj/item/stack/proc/get_main_recipes()
RETURN_TYPE(/list)
SHOULD_CALL_PARENT(TRUE)
return list()//empty list
return list() //empty list
/obj/item/stack/proc/update_weight()
if(amount <= (max_amount * (1/3)))
@@ -224,6 +250,12 @@
return TRUE
return FALSE
/obj/item/stack/interact(mob/user)
if(use_radial)
show_construction_radial(user)
else
ui_interact(user)
/obj/item/stack/ui_state(mob/user)
return GLOB.hands_state
@@ -250,64 +282,149 @@
switch(action)
if("make")
if(get_amount() < 1 && !is_cyborg)
qdel(src)
return
var/datum/stack_recipe/recipe = locate(params["ref"])
if(!is_valid_recipe(recipe, recipes)) //href exploit protection
return
var/multiplier = text2num(params["multiplier"])
if(!multiplier || (multiplier <= 0)) //href exploit protection
return
if(!building_checks(recipe, multiplier))
return
if(recipe.time)
var/adjusted_time = 0
usr.visible_message(span_notice("[usr] starts building \a [recipe.title]."), span_notice("You start building \a [recipe.title]..."))
if(HAS_TRAIT(usr, recipe.trait_booster))
adjusted_time = (recipe.time * recipe.trait_modifier)
else
adjusted_time = recipe.time
if(!do_after(usr, adjusted_time, target = usr))
return
if(!building_checks(recipe, multiplier))
return
var/obj/O
if(recipe.max_res_amount > 1) //Is it a stack?
O = new recipe.result_type(usr.drop_location(), recipe.res_amount * multiplier)
else if(ispath(recipe.result_type, /turf))
var/turf/T = usr.drop_location()
if(!isturf(T))
return
T.PlaceOnTop(recipe.result_type, flags = CHANGETURF_INHERIT_AIR)
else
O = new recipe.result_type(usr.drop_location())
if(O)
O.setDir(usr.dir)
use(recipe.req_amount * multiplier)
usr.investigate_log("[key_name(usr)] crafted [recipe.title]", INVESTIGATE_CRAFTING)
return make_item(usr, recipe, multiplier)
if(recipe.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, recipe.req_amount / recipe.res_amount)
else
O.set_custom_materials(mats_per_unit, recipe.req_amount / recipe.res_amount)
/// The key / title for a radial option that shows the entire list of buildables (uses the old menu)
#define FULL_LIST "view full list"
if(QDELETED(O))
return //It's a stack and has already been merged
/// Shows a radial consisting of every radial recipe we have in our list.
/obj/item/stack/proc/show_construction_radial(mob/builder)
var/list/options = list()
var/list/titles_to_recipes = list()
O.add_fingerprint(usr) //Add fingerprints first, otherwise O might already be deleted because of stack merging
if(isitem(O))
usr.put_in_hands(O)
for(var/datum/stack_recipe/radial/recipe in recipes)
var/datum/radial_menu_choice/option = new()
option.image = image(
icon = initial(recipe.result_type.icon),
icon_state = initial(recipe.result_type.icon_state),
)
//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(recipe.desc)
option.info = recipe.desc
options[recipe.title] = option
titles_to_recipes[recipe.title] = recipe
// After everything's been added to the radial, add an option
// that lets the user see the whole list of buildables
options[FULL_LIST] = image(
icon = 'icons/hud/radial.dmi',
icon_state = "radial_full_list",
)
var/selection = show_radial_menu(
user = builder,
anchor = builder,
choices = options,
custom_check = CALLBACK(src, .proc/radial_check, builder),
radius = radial_radius,
tooltips = TRUE,
)
if(!selection)
return
// Run normal UI interact if we wanna see the full list
if(selection == FULL_LIST)
ui_interact(builder)
return
// Otherwise go straight to building
var/datum/stack_recipe/picked_recipe = titles_to_recipes[selection]
if(!istype(picked_recipe))
return
make_item(builder, picked_recipe, 1)
/// Used as a callback for radial building.
/obj/item/stack/proc/radial_check(mob/builder)
if(QDELETED(builder) || QDELETED(src))
return FALSE
if(builder.incapacitated())
return FALSE
if(!builder.is_holding(src))
return FALSE
return TRUE
#undef FULL_LIST
/// Makes the item with the given recipe.
/obj/item/stack/proc/make_item(mob/builder, datum/stack_recipe/recipe, multiplier)
if(get_amount() < 1 && !is_cyborg) //sanity check as this shouldn't happen
qdel(src)
return
if(!is_valid_recipe(recipe, recipes)) //href exploit protection
return
if(!multiplier || (multiplier <= 0)) //href exploit protection
return
if(!building_checks(builder, recipe, multiplier))
return
if(recipe.time)
var/adjusted_time = 0
builder.balloon_alert(builder, "building...")
builder.visible_message(
span_notice("[builder] starts building \a [recipe.title]."),
span_notice("You start building \a [recipe.title]..."),
)
if(HAS_TRAIT(builder, recipe.trait_booster))
adjusted_time = (recipe.time * recipe.trait_modifier)
else
adjusted_time = recipe.time
if(!do_after(builder, adjusted_time, target = builder))
builder.balloon_alert(builder, "interrupted!")
return
if(!building_checks(builder, recipe, multiplier))
return
var/atom/created
if(recipe.max_res_amount > 1) // Is it a stack?
created = new recipe.result_type(builder.drop_location(), recipe.res_amount * multiplier)
builder.balloon_alert(builder, "built items")
else if(ispath(recipe.result_type, /turf))
var/turf/covered_turf = builder.drop_location()
if(!isturf(covered_turf))
return
covered_turf.PlaceOnTop(recipe.result_type, flags = CHANGETURF_INHERIT_AIR)
builder.balloon_alert(builder, "placed [ispath(recipe.result_type, /turf/open) ? "floor" : "wall"]")
else
created = new recipe.result_type(builder.drop_location())
builder.balloon_alert(builder, "built item")
if(created)
created.setDir(builder.dir)
// Use up the material
use(recipe.req_amount * multiplier)
builder.investigate_log("[key_name(builder)] crafted [recipe.title]", INVESTIGATE_CRAFTING)
// Apply mat datums
if(recipe.applies_mats && LAZYLEN(mats_per_unit))
if(isstack(created))
var/obj/item/stack/crafted_stack = created
crafted_stack.set_mats_per_unit(mats_per_unit, recipe.req_amount / recipe.res_amount)
else
created.set_custom_materials(mats_per_unit, recipe.req_amount / recipe.res_amount)
// We could be qdeleted - like if it's a stack and has already been merged
if(QDELETED(created))
return TRUE
// Add fingerprints first, otherwise created might already be deleted because of stack merging
created.add_fingerprint(builder)
if(isitem(created))
builder.put_in_hands(created)
//BubbleWrap - so newly formed boxes are empty
if(istype(created, /obj/item/storage))
for (var/obj/item/thing in created)
qdel(thing)
//BubbleWrap END
return TRUE
/obj/item/stack/vv_edit_var(vname, vval)
if(vname == NAMEOF(src, amount))
@@ -319,34 +436,32 @@
return TRUE
return ..()
/obj/item/stack/proc/building_checks(datum/stack_recipe/recipe, multiplier)
if (get_amount() < recipe.req_amount*multiplier)
if (recipe.req_amount*multiplier>1)
to_chat(usr, span_warning("You haven't got enough [src] to build \the [recipe.req_amount*multiplier] [recipe.title]\s!"))
else
to_chat(usr, span_warning("You haven't got enough [src] to build \the [recipe.title]!"))
/// Checks if we can build here, validly.
/obj/item/stack/proc/building_checks(mob/builder, datum/stack_recipe/recipe, multiplier)
if (get_amount() < recipe.req_amount * multiplier)
builder.balloon_alert(builder, "not enough material!")
return FALSE
var/turf/dest_turf = get_turf(usr)
var/turf/dest_turf = get_turf(builder)
// If we're making a window, we have some special snowflake window checks to do.
if(ispath(recipe.result_type, /obj/structure/window))
var/obj/structure/window/result_path = recipe.result_type
if(!valid_window_location(dest_turf, usr.dir, is_fulltile = initial(result_path.fulltile)))
to_chat(usr, span_warning("The [recipe.title] won't fit here!"))
if(!valid_window_location(dest_turf, builder.dir, is_fulltile = initial(result_path.fulltile)))
builder.balloon_alert(builder, "won't fit here!")
return FALSE
if(recipe.one_per_turf && (locate(recipe.result_type) in dest_turf))
to_chat(usr, span_warning("There is another [recipe.title] here!"))
builder.balloon_alert(builder, "already one here!")
return FALSE
if(recipe.on_tram)
if(!locate(/obj/structure/industrial_lift/tram) in dest_turf)
to_chat(usr, span_warning("\The [recipe.title] must be constructed on a tram floor!"))
builder.balloon_alert(builder, "must be made on a tram!")
return FALSE
if(recipe.on_floor)
if(!isfloorturf(dest_turf))
to_chat(usr, span_warning("\The [recipe.title] must be constructed on the floor!"))
builder.balloon_alert(builder, "must be made on a floor!")
return FALSE
for(var/obj/object in dest_turf)
@@ -359,21 +474,23 @@
if(!window_structure.fulltile)
continue
if(object.density || NO_BUILD & object.obj_flags)
to_chat(usr, span_warning("There is \a [object.name] here. You can\'t make \a [recipe.title] here!"))
builder.balloon_alert(builder, "something is in the way!")
return FALSE
if(recipe.placement_checks)
switch(recipe.placement_checks)
if(STACK_CHECK_CARDINALS)
var/turf/step
for(var/direction in GLOB.cardinals)
step = get_step(dest_turf, direction)
if(locate(recipe.result_type) in step)
to_chat(usr, span_warning("\The [recipe.title] must not be built directly adjacent to another!"))
return FALSE
if(STACK_CHECK_ADJACENT)
if(locate(recipe.result_type) in range(1, dest_turf))
to_chat(usr, span_warning("\The [recipe.title] must be constructed at least one tile away from others of its type!"))
return FALSE
if(recipe.placement_checks & STACK_CHECK_CARDINALS)
var/turf/nearby_turf
for(var/direction in GLOB.cardinals)
nearby_turf = get_step(dest_turf, direction)
if(locate(recipe.result_type) in nearby_turf)
to_chat(builder, span_warning("\The [recipe.title] must not be built directly adjacent to another!"))
builder.balloon_alert(builder, "can't be adjacent to another!")
return FALSE
if(recipe.placement_checks & STACK_CHECK_ADJACENT)
if(locate(recipe.result_type) in range(1, dest_turf))
builder.balloon_alert(builder, "can't be near another!")
return FALSE
return TRUE
/obj/item/stack/use(used, transfer = FALSE, check = TRUE) // return 0 = borked; return 1 = had enough
@@ -394,6 +511,9 @@
/obj/item/stack/tool_use_check(mob/living/user, amount)
if(get_amount() < amount)
// general balloon alert that says they don't have enough
user.balloon_alert(user, "not enough material!")
// then a more specific message about how much they need and what they need specifically
if(singular_name)
if(amount > 1)
to_chat(user, span_warning("You need at least [amount] [singular_name]\s to do this!"))
@@ -577,48 +697,5 @@
if(istype(M) && M.dirty < 100)
M.dirty += amount
/*
* Recipe datum
*/
/datum/stack_recipe
var/title = "ERROR"
var/result_type
var/req_amount = 1
var/res_amount = 1
var/max_res_amount = 1
var/time = 0
var/one_per_turf = FALSE
var/on_floor = FALSE
var/on_tram = FALSE
var/placement_checks = FALSE
var/applies_mats = FALSE
var/trait_booster = null
var/trait_modifier = 1
/datum/stack_recipe/New(title, result_type, req_amount = 1, res_amount = 1, max_res_amount = 1,time = 0, one_per_turf = FALSE, on_floor = FALSE, on_tram = FALSE, window_checks = FALSE, placement_checks = FALSE, applies_mats = FALSE, trait_booster = null, trait_modifier = 1)
src.title = title
src.result_type = result_type
src.req_amount = req_amount
src.res_amount = res_amount
src.max_res_amount = max_res_amount
src.time = time
src.one_per_turf = one_per_turf
src.on_floor = on_floor
src.on_tram = on_tram
src.placement_checks = placement_checks
src.applies_mats = applies_mats
src.trait_booster = trait_booster
src.trait_modifier = trait_modifier
/*
* Recipe list datum
*/
/datum/stack_recipe_list
var/title = "ERROR"
var/list/recipes
/datum/stack_recipe_list/New(title, recipes)
src.title = title
src.recipes = recipes
#undef STACK_CHECK_CARDINALS
#undef STACK_CHECK_ADJACENT
@@ -0,0 +1,104 @@
/*
* Recipe datum
*/
/datum/stack_recipe
/// The title of the recipe
var/title = "ERROR"
/// What atom the recipe makes, typepath
var/atom/result_type
/// Amount of stack required to make
var/req_amount = 1
/// Amount of resulting atoms made
var/res_amount = 1
/// Max amount of resulting atoms made
var/max_res_amount = 1
/// How long it takes to make
var/time = 0
/// If only one of the resulting atom is allowed per turf
var/one_per_turf = FALSE
/// If the atom requires a floor below
var/on_floor = FALSE
/// If the atom requires a tram floor below
var/on_tram = FALSE
/// Bitflag of additional placement checks required to place. (STACK_CHECK_CARDINALS|STACK_CHECK_ADJACENT)
var/placement_checks = NONE
/// If TRUE, the created atom will gain custom mat datums
var/applies_mats = FALSE
/// What trait, if any, boosts the construction speed of this item
var/trait_booster
/// How much the trait above, if supplied, boosts the construct speed of this item
var/trait_modifier = 1
/datum/stack_recipe/New(
title,
result_type,
req_amount = 1,
res_amount = 1,
max_res_amount = 1,
time = 0,
one_per_turf = FALSE,
on_floor = FALSE,
on_tram = FALSE,
window_checks = FALSE,
placement_checks = NONE,
applies_mats = FALSE,
trait_booster,
trait_modifier = 1,
)
src.title = title
src.result_type = result_type
src.req_amount = req_amount
src.res_amount = res_amount
src.max_res_amount = max_res_amount
src.time = time
src.one_per_turf = one_per_turf
src.on_floor = on_floor
src.on_tram = on_tram
src.placement_checks = placement_checks
src.applies_mats = applies_mats
src.trait_booster = trait_booster
src.trait_modifier = trait_modifier
/datum/stack_recipe/radial
/// Optional info to be shown on the radial option for this item
var/desc
/datum/stack_recipe/radial/New(
title,
result_type,
req_amount = 1,
res_amount = 1,
max_res_amount = 1,
time = 0,
one_per_turf = FALSE,
on_floor = FALSE,
on_tram = FALSE,
window_checks = FALSE,
placement_checks = NONE,
applies_mats = FALSE,
trait_booster,
trait_modifier = 1,
desc,
required_noun,
)
if(desc)
src.desc = desc
if(required_noun)
src.desc += span_boldnotice("[desc ? " - ":""]Requires: [req_amount] [required_noun]\s.")
return ..()
/*
* Recipe list datum
*/
/datum/stack_recipe_list
var/title = "ERROR"
var/list/recipes
/datum/stack_recipe_list/New(title, recipes)
src.title = title
src.recipes = recipes
Binary file not shown.

Before

Width:  |  Height:  |  Size: 26 KiB

After

Width:  |  Height:  |  Size: 27 KiB

+2
View File
@@ -1655,6 +1655,7 @@
#include "code\game\objects\items\stacks\medical.dm"
#include "code\game\objects\items\stacks\rods.dm"
#include "code\game\objects\items\stacks\stack.dm"
#include "code\game\objects\items\stacks\stack_recipe.dm"
#include "code\game\objects\items\stacks\tape.dm"
#include "code\game\objects\items\stacks\telecrystal.dm"
#include "code\game\objects\items\stacks\tickets.dm"
@@ -1664,6 +1665,7 @@
#include "code\game\objects\items\stacks\sheets\leather.dm"
#include "code\game\objects\items\stacks\sheets\light.dm"
#include "code\game\objects\items\stacks\sheets\mineral.dm"
#include "code\game\objects\items\stacks\sheets\runed_metal.dm"
#include "code\game\objects\items\stacks\sheets\sheet_types.dm"
#include "code\game\objects\items\stacks\sheets\sheets.dm"
#include "code\game\objects\items\stacks\tiles\light.dm"