mirror of
https://github.com/Bubberstation/Bubberstation.git
synced 2026-08-27 15:17:01 +01:00
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:
@@ -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
|
||||
*/
|
||||
|
||||
@@ -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 |
@@ -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"
|
||||
|
||||
Reference in New Issue
Block a user