mirror of
https://github.com/Bubberstation/Bubberstation.git
synced 2026-08-24 13:38:41 +01:00
[MODULAR] Refactors glassblowing + gives it a new UI (#20495)
* Refactors glassblowing, adds a new tgui for it * quality pass 1 * quality pass 2 * Final passes * Final touches * this was a bit too horizontal * ewps * just some last minute tidying of unneeded bits * no touch hot glass * Merge branch 'glass-fix' of https://github.com/vinylspiders/Skyrat-customization-expansion into glass-fix
This commit is contained in:
@@ -1,4 +1,9 @@
|
||||
#define DEFAULT_TIMED (4 SECONDS)
|
||||
#define STEP_BLOW "blow"
|
||||
#define STEP_SPIN "spin"
|
||||
#define STEP_PADDLE "paddle"
|
||||
#define STEP_SHEAR "shear"
|
||||
#define STEP_JACKS "jacks"
|
||||
|
||||
/obj/item/glassblowing
|
||||
icon = 'modular_skyrat/modules/primitive_production/icons/prim_fun.dmi'
|
||||
@@ -13,14 +18,16 @@
|
||||
/datum/export/glassblowing
|
||||
cost = CARGO_CRATE_VALUE * 5
|
||||
unit_name = "glassblowing product"
|
||||
export_types = list(/obj/item/glassblowing/glass_lens,
|
||||
/obj/item/glassblowing/glass_globe,
|
||||
/obj/item/reagent_containers/cup/bowl/blowing_glass,
|
||||
/obj/item/reagent_containers/cup/beaker/large/blowing_glass,
|
||||
/obj/item/plate/blowing_glass)
|
||||
export_types = list(
|
||||
/obj/item/glassblowing/glass_lens,
|
||||
/obj/item/glassblowing/glass_globe,
|
||||
/obj/item/reagent_containers/cup/bowl/blowing_glass,
|
||||
/obj/item/reagent_containers/cup/beaker/large/blowing_glass,
|
||||
/obj/item/plate/blowing_glass
|
||||
)
|
||||
|
||||
/datum/export/glassblowing/sell_object(obj/O, datum/export_report/report, dry_run, apply_elastic = FALSE) //I really dont want them to feel gimped
|
||||
. = ..()
|
||||
return ..()
|
||||
|
||||
/obj/item/glassblowing/glass_lens
|
||||
name = "glass lens"
|
||||
@@ -55,87 +62,98 @@
|
||||
name = "molten glass"
|
||||
desc = "A glob of molten glass, ready to be shaped into art."
|
||||
icon_state = "molten_glass"
|
||||
//the cooldown if its still molten / requires heating up
|
||||
///the cooldown if its still molten / requires heating up
|
||||
COOLDOWN_DECLARE(remaining_heat)
|
||||
///the list of required steps to produce the chosen_item: blowing, spinning, paddles, shears, jacks
|
||||
var/list/required_actions = list(0,0,0,0,0)
|
||||
///the list of current steps: blowing, spinning, paddles, shears, jacks
|
||||
var/list/current_actions = list(0,0,0,0,0)
|
||||
///the typepath of the item that will be produced when the required actions are met
|
||||
var/chosen_item
|
||||
///the list of steps remaining
|
||||
var/list/steps_remaining
|
||||
///the amount of time this glass will stay heated, updated each time it gets put in the forge based on the user's skill
|
||||
var/total_time
|
||||
///whether this glass's chosen item has completed all its steps. So we don't have to keep checking this a million times once it's done.
|
||||
var/is_finished = FALSE
|
||||
|
||||
/obj/item/glassblowing/molten_glass/examine(mob/user)
|
||||
. = ..()
|
||||
if(COOLDOWN_FINISHED(src, remaining_heat))
|
||||
. += span_warning("[src] has cooled down and will require reheating to modify!")
|
||||
if(required_actions[1])
|
||||
. += "You require [required_actions[1]] blowing actions!"
|
||||
. += "You currently have [current_actions[1]] blowing actions!"
|
||||
if(required_actions[2])
|
||||
. += "You require [required_actions[2]] spinning actions!"
|
||||
. += "You currently have [current_actions[2]] spinning actions!"
|
||||
if(required_actions[3])
|
||||
. += "You require [required_actions[3]] paddling actions!"
|
||||
. += "You currently have [current_actions[3]] paddling actions!"
|
||||
if(required_actions[4])
|
||||
. += "You require [required_actions[4]] shearing actions!"
|
||||
. += "You currently have [current_actions[4]] shearing actions!"
|
||||
if(required_actions[5])
|
||||
. += "You require [required_actions[5]] jacking actions!"
|
||||
. += "You currently have [current_actions[5]] jacking actions!"
|
||||
. += get_examine_message(src)
|
||||
|
||||
/obj/item/glassblowing/molten_glass/pickup(mob/user)
|
||||
if(!isliving(user))
|
||||
/obj/item/glassblowing/molten_glass/pickup(mob/living/user)
|
||||
if(!istype(user))
|
||||
return ..()
|
||||
|
||||
. = ..()
|
||||
var/mob/living/living_user = user
|
||||
|
||||
try_burn_user(user)
|
||||
|
||||
/**
|
||||
* Tries to burn the user if the glass is still molten hot.
|
||||
*
|
||||
* Arguments:
|
||||
* * mob/living/user - user to burn
|
||||
*/
|
||||
/obj/item/glassblowing/molten_glass/proc/try_burn_user(mob/living/user)
|
||||
if(!COOLDOWN_FINISHED(src, remaining_heat))
|
||||
to_chat(living_user, span_warning("You burn your hands trying to pick up [src]!"))
|
||||
living_user.adjustFireLoss(15)
|
||||
to_chat(user, span_warning("You burn your hands trying to pick up [src]!"))
|
||||
user.emote("scream")
|
||||
user.dropItemToGround(src)
|
||||
var/obj/item/bodypart/affecting = user.get_active_hand()
|
||||
return affecting?.receive_damage(0, 15, wound_bonus = CANT_WOUND)
|
||||
user.investigate_log("was burned their hand on [src] for [15] at [AREACOORD(user)]", INVESTIGATE_CRAFTING)
|
||||
|
||||
/obj/item/glassblowing/blowing_rod
|
||||
name = "blowing rod"
|
||||
desc = "A tool that is used to hold the molten glass as well as help shape it."
|
||||
icon_state = "blow_pipe_empty"
|
||||
tool_behaviour = TOOL_BLOWROD
|
||||
/// Whether the rod is in use currently; will try to prevent many other actions on it
|
||||
var/in_use = FALSE
|
||||
/// A ref to the glass item being blown
|
||||
var/datum/weakref/glass_ref
|
||||
|
||||
/obj/item/glassblowing/blowing_rod/examine(mob/user)
|
||||
. = ..()
|
||||
var/obj/item/glassblowing/molten_glass/find_glass = locate() in contents
|
||||
if(!find_glass)
|
||||
var/obj/item/glassblowing/molten_glass/glass = glass_ref.resolve()
|
||||
if(!glass)
|
||||
return
|
||||
if(COOLDOWN_FINISHED(find_glass, remaining_heat))
|
||||
. += span_warning("[src] has cooled down and will require reheating to modify!")
|
||||
if(find_glass.required_actions[1])
|
||||
. += "You require [find_glass.required_actions[1]] blowing actions!"
|
||||
. += "You currently have [find_glass.current_actions[1]] blowing actions!"
|
||||
if(find_glass.required_actions[2])
|
||||
. += "You require [find_glass.required_actions[2]] spinning actions!"
|
||||
. += "You currently have [find_glass.current_actions[2]] spinning actions!"
|
||||
if(find_glass.required_actions[3])
|
||||
. += "You require [find_glass.required_actions[3]] paddling actions!"
|
||||
. += "You currently have [find_glass.current_actions[3]] paddling actions!"
|
||||
if(find_glass.required_actions[4])
|
||||
. += "You require [find_glass.required_actions[4]] shearing actions!"
|
||||
. += "You currently have [find_glass.current_actions[4]] shearing actions!"
|
||||
if(find_glass.required_actions[5])
|
||||
. += "You require [find_glass.required_actions[5]] jacking actions!"
|
||||
. += "You currently have [find_glass.current_actions[5]] jacking actions!"
|
||||
. += get_examine_message(glass)
|
||||
|
||||
/obj/item/glassblowing/blowing_rod/proc/check_valid_table(mob/living/user)
|
||||
var/skill_level = user.mind.get_skill_level(/datum/skill/production)
|
||||
if(skill_level >= SKILL_LEVEL_MASTER) //as a master, you can skip tables
|
||||
return TRUE
|
||||
for(var/obj/structure/table/check_table in range(1, get_turf(src)))
|
||||
if(!(check_table.resistance_flags & FLAMMABLE))
|
||||
return TRUE //if you can find a table that is not flammable, good
|
||||
return FALSE
|
||||
|
||||
/**
|
||||
* Create the examine message and return it.
|
||||
*
|
||||
* This will include all the remaining steps and whether the glass has cooled down or not.
|
||||
*
|
||||
* Arguments:
|
||||
* * obj/item/glassblowing/molten_glass/glass - the glass object being examined
|
||||
*
|
||||
* Returns the examine message.
|
||||
*/
|
||||
/obj/item/glassblowing/proc/get_examine_message(obj/item/glassblowing/molten_glass/glass)
|
||||
if(COOLDOWN_FINISHED(glass, remaining_heat))
|
||||
. += span_warning("The glass has cooled down and will require reheating to modify! ")
|
||||
if(glass.steps_remaining[STEP_BLOW])
|
||||
. += "The glass requires [glass.steps_remaining[STEP_BLOW]] more blowing actions! "
|
||||
if(glass.steps_remaining[STEP_SPIN])
|
||||
. += "The glass requires [glass.steps_remaining[STEP_SPIN]] more spinning actions! "
|
||||
if(glass.steps_remaining[STEP_PADDLE])
|
||||
. += "The glass requires [glass.steps_remaining[STEP_PADDLE]] more paddling actions! "
|
||||
if(glass.steps_remaining[STEP_SHEAR])
|
||||
. += "The glass requires [glass.steps_remaining[STEP_SHEAR]] more shearing actions! "
|
||||
if(glass.steps_remaining[STEP_JACKS])
|
||||
. += "The glass requires [glass.steps_remaining[STEP_JACKS]] more jacking actions!"
|
||||
|
||||
/obj/item/glassblowing/blowing_rod/afterattack(atom/target, mob/user, proximity_flag, click_parameters)
|
||||
if(!proximity_flag)
|
||||
return ..()
|
||||
if(istype(target, /obj/item/glassblowing/molten_glass))
|
||||
var/obj/item/glassblowing/molten_glass/attacking_glass = target
|
||||
var/obj/item/glassblowing/molten_glass/find_glass = locate() in contents
|
||||
if(find_glass)
|
||||
var/obj/item/glassblowing/molten_glass/glass = glass_ref?.resolve()
|
||||
if(glass)
|
||||
to_chat(user, span_warning("[src] already has some glass on it!"))
|
||||
return
|
||||
attacking_glass.forceMove(src)
|
||||
if(!user.transferItemToLoc(attacking_glass, src))
|
||||
return
|
||||
glass_ref = WEAKREF(attacking_glass)
|
||||
to_chat(user, span_notice("[src] picks up [target]."))
|
||||
icon_state = "blow_pipe_full"
|
||||
return
|
||||
@@ -143,138 +161,303 @@
|
||||
|
||||
/obj/item/glassblowing/blowing_rod/attackby(obj/item/attacking_item, mob/living/user, params)
|
||||
var/actioning_speed = user.mind.get_skill_modifier(/datum/skill/production, SKILL_SPEED_MODIFIER) * DEFAULT_TIMED
|
||||
var/obj/item/glassblowing/molten_glass/find_glass = locate() in contents
|
||||
var/obj/item/glassblowing/molten_glass/glass = glass_ref?.resolve()
|
||||
|
||||
if(istype(attacking_item, /obj/item/glassblowing/molten_glass))
|
||||
if(find_glass)
|
||||
if(glass)
|
||||
to_chat(user, span_warning("[src] already has some glass on it still!"))
|
||||
return
|
||||
attacking_item.forceMove(src)
|
||||
if(!user.transferItemToLoc(attacking_item, src))
|
||||
return
|
||||
glass_ref = WEAKREF(attacking_item)
|
||||
to_chat(user, span_notice("[src] picks up [attacking_item]."))
|
||||
icon_state = "blow_pipe_full"
|
||||
return
|
||||
|
||||
if(istype(attacking_item, /obj/item/glassblowing/paddle))
|
||||
do_glass_step(3, user, "paddle", actioning_speed)
|
||||
do_glass_step(STEP_PADDLE, user, actioning_speed, glass)
|
||||
return
|
||||
|
||||
if(istype(attacking_item, /obj/item/glassblowing/shears))
|
||||
do_glass_step(4, user, "shear", actioning_speed)
|
||||
do_glass_step(STEP_SHEAR, user, actioning_speed, glass)
|
||||
return
|
||||
|
||||
if(istype(attacking_item, /obj/item/glassblowing/jacks))
|
||||
do_glass_step(5, user, "jack", actioning_speed)
|
||||
do_glass_step(STEP_JACKS, user, actioning_speed, glass)
|
||||
return
|
||||
|
||||
return ..()
|
||||
|
||||
/obj/item/glassblowing/blowing_rod/attack_self(mob/user, modifiers)
|
||||
var/obj/item/glassblowing/molten_glass/find_glass = locate() in contents
|
||||
var/actioning_speed = user.mind.get_skill_modifier(/datum/skill/production, SKILL_SPEED_MODIFIER) * DEFAULT_TIMED
|
||||
|
||||
if(find_glass)
|
||||
if(COOLDOWN_FINISHED(find_glass, remaining_heat))
|
||||
to_chat(user, span_warning("The glass has cooled down far too much to be handled..."))
|
||||
return
|
||||
if(in_use)
|
||||
to_chat(user, span_warning("[src] is busy being used!"))
|
||||
return
|
||||
in_use = TRUE
|
||||
if(!find_glass.chosen_item)
|
||||
var/choice = tgui_input_list(user, "What would you like to make?", "Choice Selection", list("Plate", "Bowl", "Globe", "Cup", "Lens", "Bottle"))
|
||||
if(!choice)
|
||||
in_use = FALSE
|
||||
return
|
||||
switch(choice)
|
||||
if("Plate")
|
||||
find_glass.chosen_item = /obj/item/plate/blowing_glass
|
||||
find_glass.required_actions = list(3,3,3,0,0) //blowing, spinning, paddling
|
||||
if("Bowl")
|
||||
find_glass.chosen_item = /obj/item/reagent_containers/cup/bowl/blowing_glass
|
||||
find_glass.required_actions = list(2,2,2,0,3) //blowing, spinning, paddling
|
||||
if("Globe")
|
||||
find_glass.chosen_item = /obj/item/glassblowing/glass_globe
|
||||
find_glass.required_actions = list(6,3,0,0,0) //blowing, spinning
|
||||
if("Cup")
|
||||
find_glass.chosen_item = /obj/item/reagent_containers/cup/beaker/large/blowing_glass
|
||||
find_glass.required_actions = list(3,3,3,0,0) //blowing, spinning, paddling
|
||||
if("Lens")
|
||||
find_glass.chosen_item = /obj/item/glassblowing/glass_lens
|
||||
find_glass.required_actions = list(0,0,3,3,3) //paddling, shearing, jacking
|
||||
if("Bottle")
|
||||
find_glass.chosen_item = /obj/item/reagent_containers/cup/glass/bottle/small
|
||||
find_glass.required_actions = list(3,2,3,0,0) //blowing, spinning, paddling
|
||||
in_use = FALSE
|
||||
return
|
||||
else
|
||||
in_use = FALSE
|
||||
var/action_choice = tgui_alert(user, "What would you like to do?", "Action Selection", list("Blow", "Spin", "Remove"))
|
||||
if(!action_choice)
|
||||
return
|
||||
switch(action_choice)
|
||||
if("Blow")
|
||||
do_glass_step(1, user, "blow", actioning_speed)
|
||||
if("Spin")
|
||||
do_glass_step(2, user, "spin", actioning_speed)
|
||||
if("Remove")
|
||||
for(var/iterate in 1 to 5)
|
||||
if(find_glass.current_actions[iterate] < find_glass.required_actions[iterate])
|
||||
remove_glass()
|
||||
return
|
||||
new find_glass.chosen_item(get_turf(src))
|
||||
user.mind.adjust_experience(/datum/skill/production, 30)
|
||||
qdel(find_glass)
|
||||
icon_state = "blow_pipe_empty"
|
||||
return
|
||||
return
|
||||
return ..()
|
||||
|
||||
/obj/item/glassblowing/blowing_rod/ui_interact(mob/user, datum/tgui/ui)
|
||||
ui = SStgui.try_update_ui(user, src, ui)
|
||||
if(!ui)
|
||||
ui = new(user, src, "GlassBlowing", name)
|
||||
ui.open()
|
||||
|
||||
/obj/item/glassblowing/blowing_rod/ui_data()
|
||||
var/obj/item/glassblowing/molten_glass/glass = glass_ref?.resolve()
|
||||
|
||||
var/data = list()
|
||||
data["inUse"] = in_use
|
||||
|
||||
if(glass)
|
||||
data["glass"] = list(
|
||||
timeLeft = COOLDOWN_TIMELEFT(glass, remaining_heat),
|
||||
totalTime = glass.total_time,
|
||||
chosenItem = null,
|
||||
stepsRemaining = glass.steps_remaining,
|
||||
isFinished = glass.is_finished
|
||||
)
|
||||
|
||||
var/obj/item_path = glass.chosen_item
|
||||
data["glass"]["chosenItem"] = item_path ? list(name = initial(item_path.name), type = item_path) : null
|
||||
else
|
||||
data["glass"] = null
|
||||
|
||||
return data
|
||||
|
||||
/obj/item/glassblowing/blowing_rod/ui_act(action, params)
|
||||
. = ..()
|
||||
if(.)
|
||||
return
|
||||
if(!Adjacent(usr))
|
||||
return
|
||||
add_fingerprint(usr)
|
||||
usr.set_machine(src)
|
||||
|
||||
var/obj/item/glassblowing/molten_glass/glass = glass_ref?.resolve()
|
||||
var/actioning_speed = usr.mind.get_skill_modifier(/datum/skill/production, SKILL_SPEED_MODIFIER) * DEFAULT_TIMED
|
||||
|
||||
if(!glass)
|
||||
return
|
||||
|
||||
if(action == "Remove")
|
||||
if(!glass.chosen_item)
|
||||
remove_glass(usr, glass)
|
||||
in_use = FALSE
|
||||
return
|
||||
|
||||
if(glass.is_finished)
|
||||
create_item(usr, glass)
|
||||
in_use = FALSE
|
||||
else
|
||||
remove_glass(usr, glass)
|
||||
return
|
||||
|
||||
if(!glass.chosen_item)
|
||||
switch(action)
|
||||
if("Plate")
|
||||
glass.chosen_item = /obj/item/plate/blowing_glass
|
||||
glass.steps_remaining = list(blow=3,spin=3,paddle=3,shear=0,jacks=0) //blowing, spinning, paddling
|
||||
if("Bowl")
|
||||
glass.chosen_item = /obj/item/reagent_containers/cup/bowl/blowing_glass
|
||||
glass.steps_remaining = list(blow=2,spin=2,paddle=2,shear=0,jacks=3) //blowing, spinning, paddling
|
||||
if("Globe")
|
||||
glass.chosen_item = /obj/item/glassblowing/glass_globe
|
||||
glass.steps_remaining = list(blow=6,spin=3,paddle=0,shear=0,jacks=0) //blowing, spinning
|
||||
if("Cup")
|
||||
glass.chosen_item = /obj/item/reagent_containers/cup/beaker/large/blowing_glass
|
||||
glass.steps_remaining = list(blow=3,spin=3,paddle=3,shear=0,jacks=0) //blowing, spinning, paddling
|
||||
if("Lens")
|
||||
glass.chosen_item = /obj/item/glassblowing/glass_lens
|
||||
glass.steps_remaining = list(blow=0,spin=0,paddle=3,shear=3,jacks=3) //paddling, shearing, jacking
|
||||
if("Bottle")
|
||||
glass.chosen_item = /obj/item/reagent_containers/cup/glass/bottle/small
|
||||
glass.steps_remaining = list(blow=3,spin=2,paddle=3,shear=0,jacks=0) //blowing, spinning, paddling
|
||||
else
|
||||
switch(action)
|
||||
if("Blow")
|
||||
do_glass_step(STEP_BLOW, usr, actioning_speed, glass)
|
||||
if("Spin")
|
||||
do_glass_step(STEP_SPIN, usr, actioning_speed, glass)
|
||||
if("Paddle")
|
||||
do_glass_step(STEP_PADDLE, usr, actioning_speed, glass)
|
||||
if("Shear")
|
||||
do_glass_step(STEP_SHEAR, usr, actioning_speed, glass)
|
||||
if("Jacks")
|
||||
do_glass_step(STEP_JACKS, usr, actioning_speed, glass)
|
||||
if("Cancel")
|
||||
glass.chosen_item = null
|
||||
glass.steps_remaining = null
|
||||
glass.is_finished = FALSE
|
||||
to_chat(usr, span_notice("You start over with the [src]."))
|
||||
|
||||
|
||||
/**
|
||||
* Removes the glass object from the rod.
|
||||
*
|
||||
* Try to put the glass into the user's hands, or on the floor if that fails.
|
||||
*
|
||||
* Arguments:
|
||||
* * mob/user - the mob doing the removing
|
||||
* * obj/item/glassblowing/molten_glass/glass - the glass object
|
||||
*
|
||||
* Returns TRUE or FALSE.
|
||||
*/
|
||||
/obj/item/glassblowing/blowing_rod/proc/remove_glass(mob/user, obj/item/glassblowing/molten_glass/glass)
|
||||
if(!glass)
|
||||
return
|
||||
|
||||
in_use = FALSE
|
||||
user.put_in_hands(glass)
|
||||
glass.try_burn_user(user)
|
||||
glass_ref = null
|
||||
icon_state = "blow_pipe_empty"
|
||||
|
||||
/**
|
||||
* Creates the finished product and delete the glass object used to make it.
|
||||
*
|
||||
* Try to put the finished product into the user's hands
|
||||
*
|
||||
* Arguments:
|
||||
* * mob/user - the user doing the creating
|
||||
* * obj/item/glassblowing/molten_glass/glass - the glass object
|
||||
*
|
||||
* Returns TRUE or FALSE.
|
||||
*/
|
||||
/obj/item/glassblowing/blowing_rod/proc/create_item(mob/user, obj/item/glassblowing/molten_glass/glass)
|
||||
if(!glass)
|
||||
return
|
||||
if(in_use)
|
||||
return
|
||||
|
||||
in_use = TRUE
|
||||
user.put_in_hands(new glass.chosen_item)
|
||||
user.mind.adjust_experience(/datum/skill/production, 30)
|
||||
glass_ref = null
|
||||
qdel(glass)
|
||||
icon_state = "blow_pipe_empty"
|
||||
return
|
||||
|
||||
/**
|
||||
* Display fail message and reset in_use.
|
||||
*
|
||||
* Craft is finished when all steps in steps_remaining are 0.
|
||||
*
|
||||
* Arguments:
|
||||
* * mob/user - mob to display to
|
||||
* * message - to display
|
||||
*/
|
||||
/obj/item/glassblowing/blowing_rod/proc/fail_message(message, mob/user)
|
||||
to_chat(user, span_warning(message))
|
||||
in_use = FALSE
|
||||
|
||||
/obj/item/glassblowing/blowing_rod/proc/do_glass_step(number, mob/user, message, actioning_speed)
|
||||
var/obj/item/glassblowing/molten_glass/find_glass = locate() in contents
|
||||
if(!find_glass)
|
||||
/**
|
||||
* Try to do a glassblowing action.
|
||||
*
|
||||
* Checks for a table and valid tool if applicable, and updates the steps_remaining on the glass object.
|
||||
*
|
||||
* Arguments:
|
||||
* * step_id - the step id e.g. STEP_BLOW
|
||||
* * actioning_speed - the speed based on the user's production skill
|
||||
* * obj/item/glassblowing/molten_glass/glass - the glass object
|
||||
*/
|
||||
/obj/item/glassblowing/blowing_rod/proc/do_glass_step(step_id, mob/user, actioning_speed, obj/item/glassblowing/molten_glass/glass)
|
||||
if(!glass)
|
||||
return
|
||||
if(in_use)
|
||||
return
|
||||
|
||||
in_use = TRUE
|
||||
|
||||
if(!check_valid_table(user))
|
||||
fail_message("You must be near a non-flammable table!", user)
|
||||
return
|
||||
to_chat(user, span_notice("You begin to [message] [src]."))
|
||||
if(!check_valid_tool(user, step_id))
|
||||
return
|
||||
to_chat(user, span_notice("You begin to [step_id] [src]."))
|
||||
if(!do_after(user, actioning_speed, target = src))
|
||||
fail_message("You interrupt an action!", user)
|
||||
return
|
||||
if(!check_valid_table(user))
|
||||
fail_message("You must be near a non-flammable table!", user)
|
||||
return
|
||||
find_glass.current_actions[number]++
|
||||
to_chat(user, span_notice("You finish trying to [message] [src]."))
|
||||
|
||||
if(glass.steps_remaining)
|
||||
// We do not want to have negative values here
|
||||
if(glass.steps_remaining[step_id] > 0)
|
||||
glass.steps_remaining[step_id]--
|
||||
if(check_finished(glass))
|
||||
glass.is_finished = TRUE
|
||||
|
||||
in_use = FALSE
|
||||
|
||||
to_chat(user, span_notice("You finish trying to [step_id] [src]."))
|
||||
user.mind.adjust_experience(/datum/skill/production, 10)
|
||||
|
||||
/obj/item/glassblowing/blowing_rod/proc/remove_glass()
|
||||
var/obj/item/glassblowing/molten_glass/find_glass = locate() in contents
|
||||
if(!find_glass)
|
||||
return
|
||||
|
||||
/**
|
||||
* Check if there is a non-flammable table nearby to do the crafting on.
|
||||
*
|
||||
* If the user is a master in the production skill, they can skip tables.
|
||||
*
|
||||
* Arguments:
|
||||
* * mob/living/user - the mob doing the action
|
||||
*
|
||||
* Returns TRUE or FALSE.
|
||||
*/
|
||||
/obj/item/glassblowing/blowing_rod/proc/check_valid_table(mob/living/user)
|
||||
var/skill_level = user.mind.get_skill_level(/datum/skill/production)
|
||||
if(skill_level >= SKILL_LEVEL_MASTER) //
|
||||
return TRUE
|
||||
for(var/obj/structure/table/check_table in range(1, get_turf(src)))
|
||||
if(!(check_table.resistance_flags & FLAMMABLE))
|
||||
return TRUE
|
||||
return FALSE
|
||||
|
||||
/**
|
||||
* Check if user is carrying the proper tool for the step.
|
||||
*
|
||||
* Arguments:
|
||||
* * mob/living/carbon/human/user - the mob doing the action
|
||||
* * step_id - the step id of the action being done
|
||||
*
|
||||
* Returns TRUE or FALSE.
|
||||
*/
|
||||
/obj/item/glassblowing/blowing_rod/proc/check_valid_tool(mob/living/carbon/human/user, step_id)
|
||||
if(!istype(user))
|
||||
return FALSE
|
||||
|
||||
var/obj/item/glassblowing/tool_path
|
||||
switch(step_id)
|
||||
if(STEP_BLOW)
|
||||
return TRUE
|
||||
if(STEP_SPIN)
|
||||
return TRUE
|
||||
if(STEP_PADDLE)
|
||||
tool_path = /obj/item/glassblowing/paddle
|
||||
if(STEP_SHEAR)
|
||||
tool_path = /obj/item/glassblowing/shears
|
||||
if(STEP_JACKS)
|
||||
tool_path = /obj/item/glassblowing/jacks
|
||||
|
||||
if(user.is_holding_item_of_type(tool_path))
|
||||
return TRUE
|
||||
|
||||
balloon_alert(user, "need to be holding [initial(tool_path.name)]!")
|
||||
in_use = FALSE
|
||||
find_glass.forceMove(get_turf(src))
|
||||
icon_state = "blow_pipe_empty"
|
||||
return FALSE
|
||||
|
||||
/**
|
||||
* Checks if the glass is ready to craft into its chosen item.
|
||||
*
|
||||
* Craft is finished when all steps in steps_remaining are 0.
|
||||
*
|
||||
* Arguments:
|
||||
* * obj/item/glassblowing/molten_glass/glass - the glass object
|
||||
*
|
||||
* Returns TRUE or FALSE.
|
||||
*/
|
||||
/obj/item/glassblowing/blowing_rod/proc/check_finished(obj/item/glassblowing/molten_glass/glass)
|
||||
for(var/step_id in glass.steps_remaining)
|
||||
if(glass.steps_remaining[step_id] != 0)
|
||||
return FALSE
|
||||
return TRUE
|
||||
|
||||
/datum/crafting_recipe/glassblowing_recipe
|
||||
reqs = list(/obj/item/stack/sheet/iron = 5)
|
||||
category = CAT_MISC
|
||||
|
||||
/obj/item/glassblowing/blowing_rod
|
||||
name = "blowing rod"
|
||||
desc = "A tool that is used to hold the molten glass as well as help shape it."
|
||||
icon_state = "blow_pipe_empty"
|
||||
///whether the item is in use currently; will try to prevent many other actions on it
|
||||
var/in_use = FALSE
|
||||
tool_behaviour = TOOL_BLOWROD
|
||||
|
||||
/datum/crafting_recipe/glassblowing_recipe/glass_blowing_rod
|
||||
name = "Glass-blowing Blowing Rod"
|
||||
result = /obj/item/glassblowing/blowing_rod
|
||||
@@ -326,3 +509,8 @@
|
||||
return ..()
|
||||
|
||||
#undef DEFAULT_TIMED
|
||||
#undef STEP_BLOW
|
||||
#undef STEP_SPIN
|
||||
#undef STEP_PADDLE
|
||||
#undef STEP_SHEAR
|
||||
#undef STEP_JACKS
|
||||
|
||||
@@ -861,6 +861,7 @@
|
||||
return TOOL_ACT_TOOLTYPE_SUCCESS
|
||||
|
||||
COOLDOWN_START(find_glass, remaining_heat, glassblowing_amount)
|
||||
find_glass.total_time = glassblowing_amount
|
||||
to_chat(user, span_notice("You finish heating up [blowing_item]."))
|
||||
user.mind.adjust_experience(/datum/skill/smithing, 5)
|
||||
user.mind.adjust_experience(/datum/skill/production, 10)
|
||||
|
||||
@@ -0,0 +1,257 @@
|
||||
import { Box, Button, Flex, Stack, Section, ProgressBar, AnimatedNumber, Table } from '../components';
|
||||
import { toFixed } from 'common/math';
|
||||
import { BooleanLike } from 'common/react';
|
||||
import { useBackend } from '../backend';
|
||||
import { Window } from '../layouts';
|
||||
|
||||
type GlassData = {
|
||||
hasGlass: BooleanLike;
|
||||
inUse: BooleanLike;
|
||||
glass: Glass;
|
||||
};
|
||||
|
||||
type Glass = {
|
||||
chosenItem: CraftItem;
|
||||
stepsRemaining: RemainingSteps;
|
||||
timeLeft: number;
|
||||
totalTime: number;
|
||||
isFinished: BooleanLike;
|
||||
};
|
||||
|
||||
type CraftItem = {
|
||||
name: string;
|
||||
type: string;
|
||||
};
|
||||
|
||||
type RemainingSteps = {
|
||||
blow: number;
|
||||
spin: number;
|
||||
paddle: number;
|
||||
shear: number;
|
||||
jacks: number;
|
||||
};
|
||||
|
||||
export const GlassBlowing = (props, context) => {
|
||||
const { act, data } = useBackend<GlassData>(context);
|
||||
const { glass, inUse } = data;
|
||||
|
||||
return (
|
||||
<Window width={335} height={325}>
|
||||
<Window.Content scrollable>
|
||||
<Section
|
||||
title={glass && glass.timeLeft ? 'Molten Glass' : 'Cooled Glass'}
|
||||
buttons={
|
||||
<Button
|
||||
icon={
|
||||
glass && glass.isFinished
|
||||
? 'check'
|
||||
: glass && glass.timeLeft
|
||||
? 'triangle-exclamation'
|
||||
: 'arrow-right'
|
||||
}
|
||||
color={
|
||||
glass && glass.isFinished
|
||||
? 'good'
|
||||
: glass && glass.timeLeft
|
||||
? 'red'
|
||||
: 'default'
|
||||
}
|
||||
tooltipPosition="bottom"
|
||||
tooltip={
|
||||
glass && glass.timeLeft
|
||||
? 'You may want to think twice about touching this right now...'
|
||||
: 'It has cooled and is safe to handle.'
|
||||
}
|
||||
content={glass && glass.isFinished ? 'Complete Craft' : 'Remove'}
|
||||
disabled={!glass || inUse}
|
||||
onClick={() => act('Remove')}
|
||||
/>
|
||||
}
|
||||
/>
|
||||
{glass && !glass.chosenItem && (
|
||||
<Section title="Pick a craft">
|
||||
<Stack fill vertical>
|
||||
<Stack.Item>
|
||||
<Box>What will you craft?</Box>
|
||||
</Stack.Item>
|
||||
|
||||
<Stack.Item>
|
||||
<Button
|
||||
content="Plate"
|
||||
disabled={inUse}
|
||||
onClick={() => act('Plate')}
|
||||
/>
|
||||
<Button
|
||||
content="Bowl"
|
||||
tooltipPosition="bottom"
|
||||
disabled={inUse}
|
||||
onClick={() => act('Bowl')}
|
||||
/>
|
||||
<Button
|
||||
content="Globe"
|
||||
disabled={inUse}
|
||||
onClick={() => act('Globe')}
|
||||
/>
|
||||
<Button
|
||||
content="Cup"
|
||||
disabled={inUse}
|
||||
onClick={() => act('Cup')}
|
||||
/>
|
||||
<Button
|
||||
content="Lens"
|
||||
tooltipPosition="bottom"
|
||||
disabled={inUse}
|
||||
onClick={() => act('Lens')}
|
||||
/>
|
||||
<Button
|
||||
content="Bottle"
|
||||
disabled={inUse}
|
||||
onClick={() => act('Bottle')}
|
||||
/>
|
||||
</Stack.Item>
|
||||
</Stack>
|
||||
</Section>
|
||||
)}
|
||||
{glass && glass.chosenItem && (
|
||||
<>
|
||||
<Section title="Steps Remaining:">
|
||||
<Stack fill vertical>
|
||||
<Stack.Item>
|
||||
<Box>
|
||||
You are crafting a {glass.chosenItem.name}.
|
||||
<br />
|
||||
<br />
|
||||
</Box>
|
||||
</Stack.Item>
|
||||
<Table>
|
||||
<Stack.Item>
|
||||
{glass.stepsRemaining.blow !== 0 && (
|
||||
<Table.Cell>
|
||||
<Button
|
||||
content="Blow"
|
||||
icon="fire"
|
||||
color="orange"
|
||||
disabled={inUse || !glass.timeLeft}
|
||||
tooltipPosition="bottom"
|
||||
tooltip={
|
||||
glass.timeLeft === 0
|
||||
? 'Needs to be glowing hot.'
|
||||
: ''
|
||||
}
|
||||
onClick={() => act('Blow')}
|
||||
/>
|
||||
x{glass.stepsRemaining.blow}
|
||||
</Table.Cell>
|
||||
)}
|
||||
{glass.stepsRemaining.spin !== 0 && (
|
||||
<Table.Cell>
|
||||
<Button
|
||||
content="Spin"
|
||||
icon="fire"
|
||||
color="orange"
|
||||
disabled={inUse || !glass.timeLeft}
|
||||
tooltipPosition="bottom"
|
||||
tooltip={
|
||||
glass.timeLeft === 0
|
||||
? 'Needs to be glowing hot.'
|
||||
: ''
|
||||
}
|
||||
onClick={() => act('Spin')}
|
||||
/>
|
||||
x{glass.stepsRemaining.spin}
|
||||
</Table.Cell>
|
||||
)}
|
||||
{glass.stepsRemaining.paddle !== 0 && (
|
||||
<Table.Cell>
|
||||
<Button
|
||||
content="Paddle"
|
||||
disabled={inUse}
|
||||
tooltipPosition="bottom"
|
||||
tooltip={'You need to use a paddle.'}
|
||||
onClick={() => act('Paddle')}
|
||||
/>
|
||||
x{glass.stepsRemaining.paddle}
|
||||
</Table.Cell>
|
||||
)}
|
||||
{glass.stepsRemaining.shear !== 0 && (
|
||||
<Table.Cell>
|
||||
<Button
|
||||
content="Shears"
|
||||
disabled={inUse}
|
||||
tooltipPosition="bottom"
|
||||
tooltip={'You need to use shears.'}
|
||||
onClick={() => act('Shear')}
|
||||
/>
|
||||
x{glass.stepsRemaining.shear}
|
||||
</Table.Cell>
|
||||
)}
|
||||
{glass.stepsRemaining.jacks !== 0 && (
|
||||
<Table.Cell>
|
||||
<Button
|
||||
content="Jacks"
|
||||
disabled={inUse}
|
||||
tooltipPosition="bottom"
|
||||
tooltip={'You need to use jacks.'}
|
||||
onClick={() => act('Jacks')}
|
||||
/>
|
||||
x{glass.stepsRemaining.jacks}
|
||||
</Table.Cell>
|
||||
)}
|
||||
</Stack.Item>
|
||||
</Table>
|
||||
</Stack>
|
||||
</Section>
|
||||
<Section title>
|
||||
<Flex direction="row-reverse">
|
||||
<Flex.Item>
|
||||
<Button
|
||||
icon="times"
|
||||
color={glass.timeLeft ? 'orange' : 'default'}
|
||||
content="Cancel craft"
|
||||
disabled={inUse}
|
||||
onClick={() => act('Cancel')}
|
||||
/>
|
||||
</Flex.Item>
|
||||
</Flex>
|
||||
</Section>
|
||||
</>
|
||||
)}
|
||||
{glass && glass.timeLeft !== 0 && (
|
||||
<Section title="Heat level">
|
||||
<ProgressBar
|
||||
value={glass.timeLeft / glass.totalTime}
|
||||
ranges={{
|
||||
red: [0.8, Infinity],
|
||||
orange: [0.65, 0.8],
|
||||
yellow: [0.3, 0.65],
|
||||
blue: [0.05, 0.3],
|
||||
black: [-Infinity, 0.05],
|
||||
}}
|
||||
style={{
|
||||
'background-image':
|
||||
'linear-gradient(to right, blue, yellow, red)',
|
||||
}}>
|
||||
<AnimatedNumber
|
||||
value={glass.timeLeft}
|
||||
format={(value) => toFixed(value, 1)}
|
||||
/>
|
||||
{'/' + glass.totalTime.toFixed(1)}
|
||||
</ProgressBar>
|
||||
</Section>
|
||||
)}
|
||||
{glass && glass.timeLeft === 0 && (
|
||||
<Section title="Heat level">
|
||||
<ProgressBar
|
||||
value={0 / 0}
|
||||
ranges={{}}
|
||||
style={{
|
||||
'background-image': 'grey',
|
||||
}}>
|
||||
<AnimatedNumber value={0} />
|
||||
</ProgressBar>
|
||||
</Section>
|
||||
)}
|
||||
</Window.Content>
|
||||
</Window>
|
||||
);
|
||||
};
|
||||
Reference in New Issue
Block a user