Skip to content

Commit

Permalink
Chisel and Statue Improvements (tgstation#72638)
Browse files Browse the repository at this point in the history
## About The Pull Request
Resolves tgstation#72607
Resolves tgstation#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
:cl:
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
/:cl:

Co-authored-by: Time-Green <timkoster1@hotmail.com>
  • Loading branch information
timothymtorres and Time-Green committed Jan 23, 2023
1 parent 4c50e64 commit bedf896
Show file tree
Hide file tree
Showing 2 changed files with 66 additions and 44 deletions.
7 changes: 3 additions & 4 deletions code/game/atoms.dm
Expand Up @@ -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
Expand All @@ -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])

Expand Down
103 changes: 63 additions & 40 deletions code/modules/art/statues.dm
@@ -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."
Expand Down Expand Up @@ -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 ..()
Expand All @@ -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/////////////////////////////////////////////////////////////
Expand Down Expand Up @@ -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
Expand Down Expand Up @@ -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
Expand All @@ -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)
Expand All @@ -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"
Expand Down Expand Up @@ -423,17 +443,16 @@ 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
current_target = original.content_ma
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
Expand All @@ -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

Expand Down Expand Up @@ -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)
Expand Down Expand Up @@ -588,3 +609,5 @@ Moving interrupts
. = ..()
if(content_ma)
. += content_ma

#undef SCULPT_SOUND_INCREMENT

0 comments on commit bedf896

Please sign in to comment.