Chisel and Statue Improvements (#72638)

## About The Pull Request
Resolves #72607
Resolves #65701

Chisels and statues had quite a few bugs and they lacked any kind of
feedback system to inform the user on it's proper usage. My improvements
do the following:

- Chisels now give balloon alerts when selecting a target, cancelling,
or sculpting
- Chisels used on carving blocks that were interrupted will now continue
- Fixed abstract statues not letting people use the radial menu
- Fixed chisel targets to have no range requirement (so you can use
binoculars, cameras, etc.)
- Refactor a lot of the chisel and statue code to be more robust
- Add sculpting sounds when chisels are used on carving blocks

## Why It's Good For The Game
Less bugs and now people can now sculpt easier.

## Changelog
🆑
soundadd: Chisels now make sculpting sounds when used on carving blocks
qol: Chisels now give balloon alerts when selecting a target,
cancelling, or sculpting
qol: Chisels used on carving blocks that were interrupted will now
continue
fix: Fix chisel targets to have no range requirement (so you can use
binoculars, cameras, etc.)
fix: Fix standard mineral blocks (uranium, diamond, plasma, etc.) not
letting people use the radial menu to craft abstract statues properly.
This does not work with custom mineral blocks. (pizza, glass, etc.)
code: Change chisel and statue code to be more readable
/🆑

Co-authored-by: Time-Green <timkoster1@hotmail.com>
This commit is contained in:
Tim
2023-01-23 14:09:34 +00:00
committed by GitHub
co-authored by Time-Green
parent 4c50e64fb8
commit bedf896c3c
2 changed files with 66 additions and 44 deletions
+3 -4
View File
@@ -1648,11 +1648,10 @@
* Fetches a list of all of the materials this object has of the desired type. Returns null if there is no valid materials of the type
*
* Arguments:
* - [mat_type][/datum/material]: The type of material we are checking for
* - exact: Whether to search for the _exact_ material type
* - [required_material][/datum/material]: The type of material we are checking for
* - mat_amount: The minimum required amount of material
*/
/atom/proc/has_material_type(datum/material/mat_type, exact=FALSE, mat_amount=0)
/atom/proc/has_material_type(datum/material/required_material, mat_amount = 0)
var/list/cached_materials = custom_materials
if(!length(cached_materials))
return null
@@ -1662,7 +1661,7 @@
if(cached_materials[current_material] < mat_amount)
continue
var/datum/material/material = GET_MATERIAL_REF(current_material)
if(exact ? material.type != current_material : !istype(material, mat_type))
if(!istype(material, required_material))
continue
LAZYSET(materials_of_type, material, cached_materials[current_material])
+63 -40
View File
@@ -1,3 +1,7 @@
/// This controls the delay for the sculpt rock breaking sound
/// Every 4th iterator while sculpting will emit a sound (rougly every couple of seconds)
#define SCULPT_SOUND_INCREMENT 4
/obj/structure/statue
name = "statue"
desc = "Placeholder. Yell at Firecage if you SOMEHOW see this."
@@ -36,12 +40,8 @@
if(W.tool_behaviour == TOOL_WELDER)
if(!W.tool_start_check(user, amount=0))
return FALSE
user.visible_message(span_notice("[user] is slicing apart the [name]."), \
span_notice("You are slicing apart the [name]..."))
user.balloon_alert(user, "slicing apart...")
if(W.use_tool(src, user, 40, volume=50))
user.visible_message(span_notice("[user] slices apart the [name]."), \
span_notice("You slice apart the [name]!"))
deconstruct(TRUE)
return
return ..()
@@ -56,7 +56,7 @@
var/datum/material/custom_material = GET_MATERIAL_REF(mat)
var/amount = max(0,round(custom_materials[mat]/MINERAL_MATERIAL_AMOUNT) + amount_mod)
if(amount > 0)
new custom_material.sheet_type(drop_location(),amount)
new custom_material.sheet_type(drop_location(), amount)
qdel(src)
//////////////////////////////////////STATUES/////////////////////////////////////////////////////////////
@@ -279,7 +279,7 @@
attack_verb_continuous = list("stabs")
attack_verb_simple = list("stab")
hitsound = 'sound/weapons/bladeslice.ogg'
usesound = list('sound/items/screwdriver.ogg', 'sound/items/screwdriver2.ogg')
usesound = list('sound/effects/picaxe1.ogg', 'sound/effects/picaxe2.ogg', 'sound/effects/picaxe3.ogg')
drop_sound = 'sound/items/handling/screwdriver_drop.ogg'
pickup_sound = 'sound/items/handling/screwdriver_pickup.ogg'
sharpness = SHARP_POINTY
@@ -311,35 +311,40 @@ Point with the chisel at the target to choose what to sculpt or hit block to cho
Hit block again to start sculpting.
Moving interrupts
*/
/obj/item/chisel/pre_attack(atom/A, mob/living/user, params)
/obj/item/chisel/pre_attack(atom/target, mob/living/user, params)
. = ..()
if(sculpting)
return
if(istype(A,/obj/structure/carving_block))
if(A == prepared_block && (prepared_block.current_target || prepared_block.current_preset_type))
return TRUE
if(istype(target, /obj/structure/carving_block))
var/obj/structure/carving_block/sculpt_block = target
if(sculpt_block.completion) // someone already started sculpting this so just finish
set_block(sculpt_block, user, silent = TRUE)
start_sculpting(user)
else if(sculpt_block == prepared_block && (prepared_block.current_target || prepared_block.current_preset_type))
start_sculpting(user)
else if(!prepared_block)
set_block(A,user)
else if(A == prepared_block)
set_block(sculpt_block, user)
else if(sculpt_block == prepared_block)
show_generic_statues_prompt(user)
return TRUE
else if(prepared_block) //We're aiming at something next to us with block prepared
prepared_block.set_target(A,user)
prepared_block.set_target(target, user)
return TRUE
// We aim at something distant.
/obj/item/chisel/afterattack(atom/target, mob/user, proximity_flag, click_parameters)
. = ..()
if(proximity_flag)
return .
if (!sculpting && prepared_block && ismovable(target) && prepared_block.completion == 0)
prepared_block.set_target(target,user)
return . | AFTERATTACK_PROCESSED_ITEM
/// Starts or continues the sculpting action on the carving block material
/obj/item/chisel/proc/start_sculpting(mob/living/user)
to_chat(user,span_notice("You start sculpting [prepared_block]."),type=MESSAGE_TYPE_INFO)
user.balloon_alert(user, "sculpting block...")
playsound(src, pick(usesound), 75, TRUE)
sculpting = TRUE
//How long whole process takes
var/sculpting_time = 30 SECONDS
@@ -348,9 +353,12 @@ Moving interrupts
var/interrupted = FALSE
var/remaining_time = sculpting_time - (prepared_block.completion * sculpting_time)
var/datum/progressbar/total_progress_bar = new(user, sculpting_time, prepared_block )
var/datum/progressbar/total_progress_bar = new(user, sculpting_time, prepared_block)
while(remaining_time > 0 && !interrupted)
if(do_after(user,sculpting_period, target = prepared_block, progress = FALSE))
if(do_after(user, sculpting_period, target = prepared_block, progress = FALSE))
var/time_delay = !(remaining_time % SCULPT_SOUND_INCREMENT)
if(time_delay)
playsound(src, 'sound/effects/break_stone.ogg', 50, TRUE)
remaining_time -= sculpting_period
prepared_block.set_completion((sculpting_time - remaining_time)/sculpting_time)
total_progress_bar.update(sculpting_time - remaining_time)
@@ -359,42 +367,54 @@ Moving interrupts
total_progress_bar.end_progress()
if(!interrupted && !QDELETED(prepared_block))
prepared_block.create_statue()
to_chat(user,span_notice("The statue is finished!"),type=MESSAGE_TYPE_INFO)
break_sculpting()
user.balloon_alert(user, "statue finished")
stop_sculpting(silent = !interrupted)
/obj/item/chisel/proc/set_block(obj/structure/carving_block/B,mob/living/user)
/// To setup the sculpting target for the carving block
/obj/item/chisel/proc/set_block(obj/structure/carving_block/B, mob/living/user, silent = FALSE)
prepared_block = B
tracked_user = user
RegisterSignal(tracked_user,COMSIG_MOVABLE_MOVED, PROC_REF(break_sculpting))
to_chat(user,span_notice("You prepare to work on [B]."),type=MESSAGE_TYPE_INFO)
RegisterSignal(tracked_user, COMSIG_MOVABLE_MOVED, PROC_REF(on_moved))
if(!silent)
user.balloon_alert(user, "select sculpt target")
/obj/item/chisel/dropped(mob/user, silent)
. = ..()
break_sculpting()
stop_sculpting()
/obj/item/chisel/proc/break_sculpting()
SIGNAL_HANDLER
/// Cancel the sculpting action
/obj/item/chisel/proc/stop_sculpting(silent = FALSE)
sculpting = FALSE
if(prepared_block && prepared_block.completion == 0)
prepared_block.reset_target()
prepared_block = null
if(!silent && tracked_user)
tracked_user.balloon_alert(tracked_user, "sculpting cancelled!")
if(tracked_user)
UnregisterSignal(tracked_user,COMSIG_MOVABLE_MOVED)
UnregisterSignal(tracked_user, COMSIG_MOVABLE_MOVED)
tracked_user = null
/obj/item/chisel/proc/on_moved()
SIGNAL_HANDLER
stop_sculpting()
/obj/item/chisel/proc/show_generic_statues_prompt(mob/living/user)
var/list/choices = list()
for(var/statue_path in prepared_block.get_possible_statues())
var/obj/structure/statue/S = statue_path
choices[statue_path] = image(icon=initial(S.icon),icon_state=initial(S.icon_state))
var/choice = show_radial_menu(user, prepared_block , choices, require_near = TRUE)
var/obj/structure/statue/abstract_statue = statue_path
choices[statue_path] = image(icon = initial(abstract_statue.icon), icon_state = initial(abstract_statue.icon_state))
if(!choices.len)
user.balloon_alert(user, "no abstract statues for material!")
var/choice = show_radial_menu(user, prepared_block, choices, require_near = TRUE)
if(choice)
prepared_block.current_preset_type = choice
var/image/chosen_looks = choices[choice]
prepared_block.current_target = chosen_looks.appearance
var/obj/structure/statue/S = choice
to_chat(user,span_notice("You decide to sculpt [prepared_block] into [initial(S.name)]."),type=MESSAGE_TYPE_INFO)
user.balloon_alert(user, "abstract statue selected")
/obj/structure/carving_block
name = "block"
@@ -423,9 +443,8 @@ Moving interrupts
target_appearance_with_filters = null
return ..()
/obj/structure/carving_block/proc/set_target(atom/movable/target,mob/living/user)
if(!is_viable_target(target))
to_chat(user,"You won't be able to carve that.")
/obj/structure/carving_block/proc/set_target(atom/movable/target, mob/living/user)
if(!is_viable_target(user, target))
return
if(istype(target,/obj/structure/statue/custom))
var/obj/structure/statue/custom/original = target
@@ -433,7 +452,7 @@ Moving interrupts
else
current_target = target.appearance
var/mutable_appearance/ma = current_target
to_chat(user,span_notice("You decide to sculpt [src] into [ma.name]."),type=MESSAGE_TYPE_INFO)
user.balloon_alert(user, "sculpt target is [ma.name]")
/obj/structure/carving_block/proc/reset_target()
current_target = null
@@ -448,13 +467,15 @@ Moving interrupts
var/mutable_appearance/clone = new(target_appearance_with_filters)
. += clone
/obj/structure/carving_block/proc/is_viable_target(atom/movable/target)
/obj/structure/carving_block/proc/is_viable_target(mob/living/user, atom/movable/target)
//Only things on turfs
if(!isturf(target.loc))
user.balloon_alert(user, "no sculpt target!")
return FALSE
//No big icon things
var/icon/thing_icon = icon(target.icon, target.icon_state)
if(thing_icon.Height() != world.icon_size || thing_icon.Width() != world.icon_size)
user.balloon_alert(user, "sculpt target is too big!")
return FALSE
return TRUE
@@ -505,7 +526,7 @@ Moving interrupts
var/list/carving_cost = statue_costs[statue_path]
var/enough_materials = TRUE
for(var/required_material in carving_cost)
if(!has_material_type(required_material, TRUE, carving_cost[required_material]))
if(!has_material_type(required_material, carving_cost[required_material]))
enough_materials = FALSE
break
if(enough_materials)
@@ -588,3 +609,5 @@ Moving interrupts
. = ..()
if(content_ma)
. += content_ma
#undef SCULPT_SOUND_INCREMENT