Files
Bubberstation/code/modules/mining/boulder_processing/boulder.dm
Jacquerel 98153ad983 Adds an achievement for pushing a boulder up a hill (#82813)
## About The Pull Request

Credit to Melbert for this idea.
Adds a new achievement awarded for carrying a boulder from Lavaland to
the Centcom Rescue Wing (via the Escape Shuttle).
If the boulder ever leaves your hands you will not gain the achievement.
If the boulder is not outside on Lavaland when you pick it up you will
not gain the achievement.
If you arrive at the Rescue Ship (via pod) you will not gain the
achievement.
If you drop the boulder 
If the shuttle is hijacked and you do not arrive at Centcom you will not
gain the achievement (perhaps try hitting the hijacker with the boulder
you are not allowed to drop?).
If you arrive at Centcom via the Escape Shuttle but fail to exit the
shuttle holding the boulder (for instance, because a max cap bomb is
detonated next to you one second after the shuttle arrives) you will not
gain the achievement.

As the achievement is rewarded after the round-end report is generated,
you also will not be represented on the round-end report. This is a
personal struggle.

Also carrying a boulder slows you down. Dragging it already did, so I'm
not sure why carrying one did not. It feels like an oversight, and just
makes sense.
People rarely have any particular need to manually carry them anywhere
so this should be fine, right? 🙂

## Why It's Good For The Game

Making players do pointless and weird bullshit is the reason to have an
achievement system.
It's a social experiment.
I think that it is funny.

## Changelog

🆑 Jacquerel and Melbert
add: A new achievement for moving a boulder from one place to another,
at great effort.
balance: Hauling a boulder around makes you move slower, as it does when
dragging it.
/🆑
2024-04-22 21:24:14 -06:00

178 lines
7.5 KiB
Plaintext

/**
* The objects that ore vents produce, which is refined into minerals.
*/
/obj/item/boulder
name = "boulder"
desc = "This rocks."
icon_state = "ore"
icon = 'icons/obj/ore.dmi'
item_flags = NO_MAT_REDEMPTION | SLOWS_WHILE_IN_HAND
throw_range = 2
throw_speed = 0.5
slowdown = 1.5
drag_slowdown = 1.5 // It's still a big rock.
///When a refinery machine is working on this boulder, we'll set this. Re reset when the process is finished, but the boulder may still be refined/operated on further.
var/obj/machinery/processed_by = null
/// How many steps of refinement this boulder has gone through. Starts at 5-8, goes down one each machine process.
var/durability = 5
/// What was the size of the boulder when it was spawned? This is used for inheiriting the icon_state.
var/boulder_size = BOULDER_SIZE_SMALL
/// Used in inheriting the icon_state from our parent vent in update_icon.
var/boulder_string = "boulder"
/obj/item/boulder/Initialize(mapload)
. = ..()
register_context()
AddComponent(/datum/component/two_handed, require_twohands = TRUE, force_unwielded = 0, force_wielded = 5) //Heavy as all hell, it's a boulder, dude.
AddComponent(/datum/component/sisyphus_awarder)
/obj/item/boulder/Destroy(force)
SSore_generation.available_boulders -= src
processed_by = null
return ..()
/obj/item/boulder/add_context(atom/source, list/context, obj/item/held_item, mob/living/user)
if(held_item?.tool_behaviour == TOOL_MINING || HAS_TRAIT(user, TRAIT_BOULDER_BREAKER))
context[SCREENTIP_CONTEXT_RMB] = "Crush boulder into ore"
return CONTEXTUAL_SCREENTIP_SET
/obj/item/boulder/examine(mob/user)
. = ..()
. += span_notice("This boulder would take [durability] more steps to refine or break.")
if(HAS_TRAIT(user, TRAIT_BOULDER_BREAKER))
. += span_notice("You can crush this boulder with your bare hands.")
/obj/item/boulder/examine_more(mob/user)
. = ..()
. += span_notice("[span_bold("Boulders")] can either be cracked open by [span_bold("mining tools")], or processed into sheets with [span_bold("refineries or smelters")]. Undisturbed boulders can be collected by the [span_bold("BRM")].")
/obj/item/boulder/update_icon_state()
. = ..()
switch(boulder_size)
if(BOULDER_SIZE_SMALL)
icon_state = "[boulder_string]_small"
if(BOULDER_SIZE_MEDIUM)
icon_state = "[boulder_string]_medium"
if(BOULDER_SIZE_LARGE)
icon_state = "[boulder_string]_large"
else
icon_state = "[boulder_string]_small"
/obj/item/boulder/CanAllowThrough(atom/movable/mover, border_dir)
. = ..()
if(istype(mover, /obj/item/boulder)) //This way, boulders can only go one at a time on conveyor belts, but everyone else can go through.
return FALSE
/obj/item/boulder/attack_self(mob/user, list/modifiers)
. = ..()
if(.)
return
if(HAS_TRAIT(user, TRAIT_BOULDER_BREAKER))
manual_process(null, user, INATE_BOULDER_SPEED_MULTIPLIER)
return
/obj/item/boulder/attack_hand_secondary(mob/user, list/modifiers)
. = ..()
if(. == SECONDARY_ATTACK_CANCEL_ATTACK_CHAIN)
return
if(HAS_TRAIT(user, TRAIT_BOULDER_BREAKER))
manual_process(null, user, INATE_BOULDER_SPEED_MULTIPLIER)
return SECONDARY_ATTACK_CANCEL_ATTACK_CHAIN
/obj/item/boulder/attackby_secondary(obj/item/weapon, mob/user, params)
. = ..()
if(HAS_TRAIT(user, TRAIT_BOULDER_BREAKER) || HAS_TRAIT(weapon, TRAIT_BOULDER_BREAKER))
manual_process(weapon, user, INATE_BOULDER_SPEED_MULTIPLIER)
return SECONDARY_ATTACK_CANCEL_ATTACK_CHAIN
if(weapon.tool_behaviour == TOOL_MINING)
manual_process(weapon, user)
return SECONDARY_ATTACK_CANCEL_ATTACK_CHAIN
return ..()
/obj/item/boulder/attack_basic_mob(mob/user, list/modifiers)
. = ..()
if(.)
return
if(HAS_TRAIT(user, TRAIT_BOULDER_BREAKER))
manual_process(null, user, INATE_BOULDER_SPEED_MULTIPLIER) //A little hacky but it works around the speed of the blackboard task selection process for now.
return SECONDARY_ATTACK_CANCEL_ATTACK_CHAIN
/**
* This is called when a boulder is processed by a mob or tool, and reduces the durability of the boulder.
* @param obj/item/weapon The weapon that is being used to process the boulder, that we pull toolspeed from. If null, we use the override_speed_multiplier instead.
* @param mob/living/user The mob that is processing the boulder.
* @param override_speed_multiplier The speed multiplier to use if weapon is null. The do_after will take 2 * this value seconds to complete.
* @param continued Whether or not this is a continued process, or the first one. If true, we don't play the "You swing at the boulder" message.
*/
/obj/item/boulder/proc/manual_process(obj/item/weapon, mob/living/user, override_speed_multiplier, continued = FALSE)
var/process_speed = 0
//Handle weapon conditions.
var/skill_modifier = user.mind?.get_skill_modifier(/datum/skill/mining, SKILL_SPEED_MODIFIER) || 1
if(weapon)
if(HAS_TRAIT(weapon, TRAIT_INSTANTLY_PROCESSES_BOULDERS))
durability = 0
process_speed = weapon.toolspeed
weapon.play_tool_sound(src, 50)
if(!continued)
to_chat(user, span_notice("You swing at \the [src]..."))
// Handle user conditions/override conditions.
else if (override_speed_multiplier || HAS_TRAIT(user, TRAIT_BOULDER_BREAKER))
if(HAS_TRAIT(user, TRAIT_INSTANTLY_PROCESSES_BOULDERS))
durability = 0
else if(override_speed_multiplier)
process_speed = override_speed_multiplier
else
process_speed = INATE_BOULDER_SPEED_MULTIPLIER
playsound(src, 'sound/effects/rocktap1.ogg', 50)
if(!continued)
to_chat(user, span_notice("You scrape away at \the [src]..."))
else
CRASH("No weapon, acceptable user, or override speed multiplier passed to manual_process()")
if(durability > 0)
if(!do_after(user, (2 * process_speed * skill_modifier SECONDS), target = src))
return
if(!user.Adjacent(src))
return
durability--
user.apply_damage(4 * skill_modifier, STAMINA)
if(durability <= 0)
convert_to_ore()
to_chat(user, span_notice("You finish working on \the [src], and it crumbles into ore."))
playsound(src, 'sound/effects/rock_break.ogg', 50)
user.mind?.adjust_experience(/datum/skill/mining, MINING_SKILL_BOULDER_SIZE_XP * 0.2)
qdel(src)
return
var/msg = (durability == 1 ? "is crumbling!" : "looks weaker!")
to_chat(user, span_notice("\The [src] [msg]"))
manual_process(weapon, user, override_speed_multiplier, continued = TRUE)
/**
* This function is called while breaking boulders manually, and drops ore based on the boulder's mineral content.
* Quantity of ore spawned here is 1 less than if the boulder was processed by a machine, but clamped at 10 maximum, 1 minimum.
*/
/obj/item/boulder/proc/convert_to_ore()
for(var/datum/material/picked in custom_materials)
var/obj/item/stack/ore/cracked_ore // Take the associated value and convert it into ore stacks...
var/quantity = clamp(round((custom_materials[picked] - SHEET_MATERIAL_AMOUNT)/SHEET_MATERIAL_AMOUNT), 1, 10) //but less resources than if they processed it by hand.
var/cracked_ore_type = picked.ore_type
if(isnull(cracked_ore_type))
stack_trace("boulder found containing material type [picked.type] with no set ore_type")
continue
cracked_ore = new cracked_ore_type (drop_location(), quantity)
SSblackbox.record_feedback("tally", "ore_mined", quantity, cracked_ore.type)
///Moves boulder contents to the drop location, and then deletes the boulder.
/obj/item/boulder/proc/break_apart()
if(length(contents))
var/list/quips = list("Clang!", "Crack!", "Bang!", "Clunk!", "Clank!")
visible_message(span_notice("[pick(quips)] Something falls out of \the [src]!"))
playsound(loc, 'sound/effects/picaxe1.ogg', 60, FALSE)
for(var/obj/item/content as anything in contents)
content.forceMove(get_turf(src))
qdel(src)