mirror of
https://github.com/Bubberstation/Bubberstation.git
synced 2026-08-23 13:10:02 +01:00
Merge branch 'master' of github.com:tgstation/tgstation into upstream-2026-06-23
This commit is contained in:
@@ -7,7 +7,7 @@
|
||||
///what blackboard key are we setting
|
||||
var/weather_key
|
||||
|
||||
/datum/component/ai_listen_to_weather/Initialize(weather_type = /datum/weather/ash_storm, weather_key = BB_STORM_APPROACHING)
|
||||
/datum/component/ai_listen_to_weather/Initialize(weather_type = /datum/weather/particle/ash_storm, weather_key = BB_STORM_APPROACHING)
|
||||
if(!isliving(parent))
|
||||
return COMPONENT_INCOMPATIBLE
|
||||
src.weather_type = weather_type
|
||||
|
||||
@@ -98,7 +98,7 @@
|
||||
baked_result.reagents.add_reagent_list(added_reagents)
|
||||
|
||||
if(who_baked_us)
|
||||
ADD_TRAIT(baked_result, TRAIT_FOOD_CHEF_MADE, who_baked_us)
|
||||
ADD_TRAIT(baked_result, TRAIT_HANDMADE, who_baked_us)
|
||||
|
||||
if(original_object.custom_materials)
|
||||
baked_result.set_custom_materials(original_object.custom_materials, 1)
|
||||
|
||||
@@ -97,6 +97,7 @@
|
||||
|
||||
casting_spell = FALSE
|
||||
if(!COOLDOWN_FINISHED(src, heal_cooldown))
|
||||
to_chat(source, span_danger("Your chuuni powers are on cooldown! You fail to heal!"))
|
||||
return
|
||||
COOLDOWN_START(src, heal_cooldown, CHUUNIBYOU_COOLDOWN_TIME)
|
||||
|
||||
|
||||
@@ -120,7 +120,7 @@
|
||||
|
||||
/datum/crafting_recipe/vim
|
||||
name = "Vim"
|
||||
result = /obj/vehicle/sealed/car/vim
|
||||
result = /obj/vehicle/sealed/mecha/vim
|
||||
reqs = list(
|
||||
/obj/item/clothing/head/helmet/space/eva = 1,
|
||||
/obj/item/bodypart/leg/left/robot = 1,
|
||||
|
||||
@@ -24,6 +24,8 @@ Behavior that's still missing from this component that original food items had t
|
||||
var/food_flags = NONE
|
||||
///Bitfield of the types of this food
|
||||
var/foodtypes = NONE
|
||||
///The main food complexity (read: quality) when handmade. It dictates the strength of the effect that this edible gives when eaten.
|
||||
var/handmade_complexity = FOOD_COMPLEXITY_0
|
||||
///Amount of seconds it takes to eat this food
|
||||
var/eat_time = 3 SECONDS
|
||||
///Defines how much it lowers someones satiety (Need to eat, essentialy)
|
||||
@@ -59,6 +61,7 @@ Behavior that's still missing from this component that original food items had t
|
||||
datum/callback/on_consume,
|
||||
datum/callback/check_liked,
|
||||
reagent_purity = 0.5,
|
||||
handmade_complexity = FOOD_COMPLEXITY_0
|
||||
)
|
||||
if(!isatom(parent))
|
||||
return COMPONENT_INCOMPATIBLE
|
||||
@@ -72,6 +75,7 @@ Behavior that's still missing from this component that original food items had t
|
||||
src.foodtypes = foodtypes
|
||||
src.eat_time = eat_time
|
||||
src.eatverbs = string_list(eatverbs)
|
||||
src.handmade_complexity = handmade_complexity
|
||||
|
||||
/datum/component/edible/RegisterWithParent()
|
||||
RegisterSignal(parent, COMSIG_ATOM_EXAMINE, PROC_REF(examine))
|
||||
@@ -136,6 +140,7 @@ Behavior that's still missing from this component that original food items had t
|
||||
datum/callback/on_consume,
|
||||
datum/callback/check_liked,
|
||||
reagent_purity = 0.5,
|
||||
handmade_complexity,
|
||||
)
|
||||
. = ..()
|
||||
|
||||
@@ -269,7 +274,7 @@ Behavior that's still missing from this component that original food items had t
|
||||
examine_list += span_green("It is made of finest ingredients prolonging the effect!")
|
||||
|
||||
var/datum/mind/mind = user.mind
|
||||
if(mind && HAS_TRAIT_FROM(owner, TRAIT_FOOD_CHEF_MADE, REF(mind)))
|
||||
if(mind && HAS_TRAIT_FROM(owner, TRAIT_HANDMADE, REF(mind)))
|
||||
examine_list += span_green("[owner] was made by you!")
|
||||
|
||||
if(!(food_flags & FOOD_IN_CONTAINER))
|
||||
@@ -638,15 +643,14 @@ Behavior that's still missing from this component that original food items had t
|
||||
var/quality_label = GLOB.food_quality_description[food_quality]
|
||||
to_chat(gourmand, span_notice("That's \an [quality_label] meal."))
|
||||
|
||||
/// Get the complexity of the crafted food
|
||||
/// Get the complexity of the crafted food. Some ingredients may influence this value.
|
||||
/datum/component/edible/proc/get_recipe_complexity()
|
||||
var/list/extra_complexity = list(0)
|
||||
SEND_SIGNAL(parent, COMSIG_FOOD_GET_EXTRA_COMPLEXITY, extra_complexity)
|
||||
var/complexity_to_add = extra_complexity[1]
|
||||
if(!HAS_TRAIT(parent, TRAIT_FOOD_CHEF_MADE) || !istype(parent, /obj/item/food))
|
||||
return complexity_to_add // It is factory made. Soulless.
|
||||
var/obj/item/food/food = parent
|
||||
return food.crafting_complexity + complexity_to_add
|
||||
var/complexity = FOOD_COMPLEXITY_0
|
||||
if(HAS_TRAIT(parent, TRAIT_HANDMADE))
|
||||
complexity += handmade_complexity
|
||||
var/list/complexity_holder = list(complexity)
|
||||
SEND_SIGNAL(parent, COMSIG_FOOD_GET_EXTRA_COMPLEXITY, complexity_holder)
|
||||
return complexity_holder[1]
|
||||
|
||||
/// Get food quality adjusted according to eater's preferences
|
||||
/datum/component/edible/proc/get_perceived_food_quality(mob/living/eater)
|
||||
|
||||
@@ -167,7 +167,7 @@
|
||||
SEND_SIGNAL(parent, COMSIG_ITEM_GRILLED, grilled_result)
|
||||
SEND_SIGNAL(grilled_result, COMSIG_ITEM_GRILLED_RESULT, parent)
|
||||
if(who_placed_us)
|
||||
ADD_TRAIT(grilled_result, TRAIT_FOOD_CHEF_MADE, who_placed_us)
|
||||
ADD_TRAIT(grilled_result, TRAIT_HANDMADE, who_placed_us)
|
||||
|
||||
grill_source.visible_message("<span class='[positive_result ? "notice" : "warning"]'>[parent] turns into \a [grilled_result]!</span>")
|
||||
grilled_result.pixel_x = original_object.pixel_x
|
||||
|
||||
@@ -18,7 +18,7 @@
|
||||
|
||||
var/list/starting_signals = list()
|
||||
var/list/ending_signals = list()
|
||||
for(var/datum/weather/weather_type as anything in typesof(/datum/weather))
|
||||
for(var/datum/weather/weather_type as anything in valid_subtypesof(/datum/weather))
|
||||
starting_signals += COMSIG_WEATHER_TELEGRAPH(weather_type)
|
||||
ending_signals += COMSIG_WEATHER_END(weather_type)
|
||||
|
||||
|
||||
@@ -136,13 +136,22 @@
|
||||
if(source.client.intended_direction && check_on_move.Invoke(TRUE)) //You use jet when press keys. yes.
|
||||
trail?.generate_effect()
|
||||
|
||||
/// Handles all active 0g movement, including both manual (trying to move a direction in 0g) and automatic (drifting idly in 0g)
|
||||
/datum/component/jetpack/proc/stabilize(mob/source, movement_dir, continuous_move, backup)
|
||||
SIGNAL_HANDLER
|
||||
if(!continuous_move && movement_dir)
|
||||
return COMSIG_MOVABLE_STOP_SPACEMOVE
|
||||
// Check if we have the fuel to stop this. Do NOT consume any fuel, just check
|
||||
// This is done because things other then us can use our fuel
|
||||
if(stabilize && check_on_move.Invoke(FALSE))
|
||||
/*
|
||||
* Checks if we should stop any active movement
|
||||
*
|
||||
* Obviously we stop all forms of drifting if we have stabilizers active (allowing free space movement)
|
||||
* Less obviously, we stop need to stop drift if we are trying to move *while passively drifting*
|
||||
* (Without checking the latter, jetpacks will act very weird and jank. As you move in one direction,
|
||||
* you will simultaneously drift in that direction, causing you to jump/skip a tile every so often.)
|
||||
*
|
||||
* Either way, we need to check that we have the "fuel" to stop this
|
||||
* DO NOT CONSUME FUEL HERE, just check if we have it
|
||||
* This is done because things other then us can use our fuel
|
||||
*/
|
||||
if((stabilize || (!continuous_move && movement_dir)) && check_on_move.Invoke(FALSE))
|
||||
return COMSIG_MOVABLE_STOP_SPACEMOVE
|
||||
return NONE
|
||||
|
||||
|
||||
@@ -8,6 +8,10 @@
|
||||
#define MESSAGE_VOICE "voice"
|
||||
/// the tone it should be said in
|
||||
#define MESSAGE_PITCH "pitch"
|
||||
/// the blip base it should be said in
|
||||
#define MESSAGE_BLIP_BASE "blip_base"
|
||||
/// the blip base it should be said in
|
||||
#define MESSAGE_BLIP_NUMBER "blip_number"
|
||||
|
||||
/// Simple element that will deterministically set a value based on stuff that the source has heard and will then compel the source to repeat it.
|
||||
/// Requires a valid AI Blackboard.
|
||||
@@ -24,6 +28,8 @@
|
||||
var/static/list/invalid_voice = list(
|
||||
MESSAGE_VOICE = "invalid",
|
||||
MESSAGE_PITCH = 0,
|
||||
MESSAGE_BLIP_BASE = "male",
|
||||
MESSAGE_BLIP_NUMBER = 1,
|
||||
)
|
||||
|
||||
/datum/component/listen_and_repeat/Initialize(list/desired_phrases, blackboard_key)
|
||||
@@ -68,6 +74,8 @@
|
||||
var/atom/movable/movable_speaker = speaker
|
||||
speaker_sound[MESSAGE_VOICE] = movable_speaker.voice || "invalid"
|
||||
speaker_sound[MESSAGE_PITCH] = (movable_speaker.pitch && SStts.pitch_enabled ? movable_speaker.pitch : 0)
|
||||
speaker_sound[MESSAGE_BLIP_BASE] = movable_speaker.blip_base || "male"
|
||||
speaker_sound[MESSAGE_BLIP_NUMBER] = movable_speaker.blip_number || 1
|
||||
|
||||
if(over_radio && prob(RADIO_IGNORE_CHANCE))
|
||||
return
|
||||
@@ -99,6 +107,9 @@
|
||||
if(islist(speech_buffer[selected_phrase]))
|
||||
to_return[MESSAGE_VOICE] = speech_buffer[selected_phrase][MESSAGE_VOICE]
|
||||
to_return[MESSAGE_PITCH] = speech_buffer[selected_phrase][MESSAGE_PITCH]
|
||||
to_return[MESSAGE_BLIP_BASE] = speech_buffer[selected_phrase][MESSAGE_BLIP_BASE]
|
||||
to_return[MESSAGE_BLIP_NUMBER] = speech_buffer[selected_phrase][MESSAGE_BLIP_NUMBER]
|
||||
|
||||
|
||||
controller.override_blackboard_key(blackboard_key, to_return)
|
||||
|
||||
@@ -117,3 +128,5 @@
|
||||
#undef MESSAGE_VOICE
|
||||
#undef MESSAGE_PITCH
|
||||
#undef MESSAGE_LINE
|
||||
#undef MESSAGE_BLIP_BASE
|
||||
#undef MESSAGE_BLIP_NUMBER
|
||||
|
||||
@@ -0,0 +1,89 @@
|
||||
/**
|
||||
* A component that allows the attached mind to listen prayers from other mobs.
|
||||
* Unlike admins, they cannot smite the person for it, also the prayers are anonymous unless the person says who he's in the message.
|
||||
*/
|
||||
/datum/component/listen_prayers
|
||||
///A callback called before the prayer is heard. May alter the message or prevent it from being heard if it returns FALSE
|
||||
var/datum/callback/pre_prayer_callback
|
||||
///This will be affixed to the "deities" that have heard this message.
|
||||
var/deity_name
|
||||
///The action that the owner can use to ignore the prayers
|
||||
var/datum/action/innate/listen_prayers/toggle
|
||||
///The description we give to the instance of the listen_prayers toggle.
|
||||
var/toggle_desc
|
||||
|
||||
/datum/component/listen_prayers/Initialize(datum/callback/pre_prayer_callback, deity_name, toggle_desc)
|
||||
if (!istype(parent, /datum/mind))
|
||||
return COMPONENT_INCOMPATIBLE
|
||||
src.pre_prayer_callback = pre_prayer_callback
|
||||
src.deity_name = deity_name
|
||||
src.toggle_desc = toggle_desc
|
||||
|
||||
/datum/component/listen_prayers/Destroy()
|
||||
pre_prayer_callback = null
|
||||
return ..()
|
||||
|
||||
/datum/component/listen_prayers/RegisterWithParent()
|
||||
RegisterSignal(SSdcs, COMSIG_GLOB_SEND_PRAYER, PROC_REF(on_sent_prayer))
|
||||
var/datum/mind/mind = parent
|
||||
|
||||
var/datum/action/innate/listen_prayers/toggle = new(mind)
|
||||
if(toggle_desc)
|
||||
toggle.desc = toggle_desc
|
||||
if(mind.current)
|
||||
toggle.Grant(mind.current)
|
||||
|
||||
/datum/component/listen_prayers/UnregisterFromParent()
|
||||
UnregisterSignal(SSdcs, COMSIG_GLOB_SEND_PRAYER)
|
||||
QDEL_NULL(toggle)
|
||||
|
||||
/datum/component/listen_prayers/proc/on_sent_prayer(source, mob/praying, message, prayer_type, symbol, list/deities_that_listened)
|
||||
SIGNAL_HANDLER
|
||||
var/datum/mind/mind = parent
|
||||
if(!mind.current || mind.current.stat >= UNCONSCIOUS || !mind.current.client) //You can't hear prayers if unconscious or disconnected
|
||||
return
|
||||
if(!isliving(praying) || praying.stat == DEAD)
|
||||
return FALSE //I don't see any reason in hell to why dead people should be allowed into this. This isn't a knockoff TRAIT_SIXTHSENSE.
|
||||
if(praying == mind.current) //Ignore prayers coming from ourselves.
|
||||
return
|
||||
if(mind.current.client in GLOB.admins) //This is redundant if we're adminning
|
||||
return
|
||||
if(HAS_MIND_TRAIT(mind.current, TRAIT_DONT_HEAR_PRAYERS))
|
||||
return
|
||||
var/list/arguments = args.Copy(2)
|
||||
if(pre_prayer_callback && !pre_prayer_callback.Invoke(arguments))
|
||||
return
|
||||
prayer_type = arguments[ARG_PRAYER_TYPE]
|
||||
symbol = arguments[ARG_PRAYER_SYMBOL]
|
||||
message = "[icon2html(arguments[ARG_PRAYER_SYMBOL], mind.current.client)]<b><font color=[GLOB.prayer_type_to_font_color[prayer_type]]>[prayer_type]: </font></b> [span_notice(arguments[ARG_PRAYER_MSG])]"
|
||||
to_chat(mind.current, custom_boxed_message(GLOB.prayer_type_to_message_box[prayer_type], message))
|
||||
SEND_SOUND(mind.current, sound('sound/effects/pray.ogg'))
|
||||
if(deity_name)
|
||||
deities_that_listened += deity_name
|
||||
|
||||
///An action to stop hearing prayers on command. Doesn't do a whole lot without the associated component
|
||||
/datum/action/innate/listen_prayers
|
||||
name = "Listen Prayers"
|
||||
button_icon = 'icons/hud/actions.dmi'
|
||||
button_icon_state = "pray"
|
||||
desc = "Allows you to eavesdrop on prayers from the world around you."
|
||||
active = TRUE
|
||||
|
||||
/datum/action/innate/listen_prayers/Destroy()
|
||||
REMOVE_TRAIT(owner, TRAIT_DONT_HEAR_PRAYERS, ACTION_TRAIT)
|
||||
return ..()
|
||||
|
||||
/datum/action/innate/listen_prayers/is_action_active(atom/movable/screen/movable/action_button/current_button)
|
||||
return !HAS_TRAIT_FROM(owner, TRAIT_DONT_HEAR_PRAYERS, ACTION_TRAIT)
|
||||
|
||||
/datum/action/innate/listen_prayers/Activate()
|
||||
active = TRUE
|
||||
REMOVE_TRAIT(owner, TRAIT_DONT_HEAR_PRAYERS, ACTION_TRAIT)
|
||||
to_chat(owner, span_green("You are ready to listen to prayers once again."))
|
||||
build_all_button_icons(UPDATE_BUTTON_BACKGROUND)
|
||||
|
||||
/datum/action/innate/listen_prayers/Deactivate()
|
||||
active = FALSE
|
||||
ADD_TRAIT(owner, TRAIT_DONT_HEAR_PRAYERS, ACTION_TRAIT)
|
||||
to_chat(owner, span_green("You stop listening to prayers."))
|
||||
build_all_button_icons(UPDATE_BUTTON_BACKGROUND)
|
||||
@@ -226,11 +226,14 @@
|
||||
. = ..()
|
||||
if(action != "keypad")
|
||||
return TRUE
|
||||
|
||||
var/atom/source = parent
|
||||
playsound(source, SFX_TERMINAL_TYPE, 50, FALSE)
|
||||
|
||||
var/digit = params["digit"]
|
||||
switch(digit)
|
||||
//locking it back up
|
||||
if("C")
|
||||
var/atom/source = parent
|
||||
numeric_input = ""
|
||||
//you can't lock it if it's already locked or lacks a lock code.
|
||||
if(source.atom_storage.locked || isnull(lock_code))
|
||||
@@ -249,7 +252,6 @@
|
||||
//unlocking the current code.
|
||||
if(numeric_input != lock_code)
|
||||
return TRUE
|
||||
var/atom/source = parent
|
||||
source.atom_storage.set_locked(STORAGE_NOT_LOCKED)
|
||||
numeric_input = ""
|
||||
return TRUE
|
||||
|
||||
@@ -69,9 +69,9 @@
|
||||
user.name = target.name
|
||||
user.reset_perspective(target)
|
||||
|
||||
target.AddElement(/datum/element/weather_listener, /datum/weather/ash_storm, ZTRAIT_ASHSTORM, GLOB.ash_storm_sounds)
|
||||
target.AddElement(/datum/element/weather_listener, /datum/weather/particle/ash_storm, ZTRAIT_ASHSTORM, GLOB.ash_storm_sounds)
|
||||
target.AddElement(/datum/element/weather_listener, /datum/weather/snow_storm, ZTRAIT_SNOWSTORM, GLOB.snowstorm_sounds)
|
||||
target.AddElement(/datum/element/weather_listener, /datum/weather/rain_storm, ZTRAIT_RAINSTORM, GLOB.rain_storm_sounds)
|
||||
target.AddElement(/datum/element/weather_listener, /datum/weather/particle/rain_storm, ZTRAIT_RAINSTORM, GLOB.rain_storm_sounds)
|
||||
target.AddElement(/datum/element/weather_listener, /datum/weather/sand_storm, ZTRAIT_SANDSTORM, GLOB.sand_storm_sounds)
|
||||
|
||||
RegisterSignal(target, COMSIG_QDELETING, PROC_REF(end_possession))
|
||||
@@ -84,8 +84,8 @@
|
||||
|
||||
var/mob/poltergeist = parent
|
||||
|
||||
possessed.RemoveElement(/datum/element/weather_listener, /datum/weather/ash_storm, ZTRAIT_ASHSTORM, GLOB.ash_storm_sounds)
|
||||
possessed.RemoveElement(/datum/element/weather_listener, /datum/weather/rain_storm, ZTRAIT_RAINSTORM, GLOB.rain_storm_sounds)
|
||||
possessed.RemoveElement(/datum/element/weather_listener, /datum/weather/particle/ash_storm, ZTRAIT_ASHSTORM, GLOB.ash_storm_sounds)
|
||||
possessed.RemoveElement(/datum/element/weather_listener, /datum/weather/particle/rain_storm, ZTRAIT_RAINSTORM, GLOB.rain_storm_sounds)
|
||||
possessed.RemoveElement(/datum/element/weather_listener, /datum/weather/sand_storm, ZTRAIT_SANDSTORM, GLOB.sand_storm_sounds)
|
||||
possessed.RemoveElement(/datum/element/weather_listener, /datum/weather/snow_storm, ZTRAIT_SNOWSTORM, GLOB.snowstorm_sounds)
|
||||
UnregisterSignal(possessed, COMSIG_QDELETING)
|
||||
|
||||
@@ -41,7 +41,12 @@
|
||||
INVOKE_ASYNC(src, PROC_REF(slow_mine), user, target)
|
||||
return
|
||||
|
||||
var/mob/living/driver = null
|
||||
if (pass_driver && length(user.buckled_mobs))
|
||||
driver = user.buckled_mobs[1]
|
||||
|
||||
last_bumpmine_tick = world.time
|
||||
SEND_SIGNAL(parent, COMSIG_PROFICIENT_MINER_MINED, mineral_wall, driver || user)
|
||||
mineral_wall.gets_drilled(source)
|
||||
|
||||
/datum/component/proficient_miner/proc/slow_mine(mob/living/user, turf/closed/mineral/mineral_wall)
|
||||
@@ -65,4 +70,5 @@
|
||||
playsound(user, pick(mine_sounds), 50)
|
||||
|
||||
if(istype(mineral_wall))
|
||||
SEND_SIGNAL(parent, COMSIG_PROFICIENT_MINER_MINED, mineral_wall, driver || user)
|
||||
mineral_wall.gets_drilled(driver || user)
|
||||
|
||||
@@ -119,24 +119,35 @@
|
||||
return COMPONENT_DRIVER_BLOCK_MOVE
|
||||
var/mob/living/living_parent = parent
|
||||
step(living_parent, direction)
|
||||
var/modified_move_delay = uses_native_speed ? living_parent.cached_multiplicative_slowdown : vehicle_move_delay
|
||||
if(HAS_TRAIT(user, TRAIT_ROUGHRIDER)) // YEEHAW!
|
||||
switch(HAS_TRAIT(user, TRAIT_PRIMITIVE) ? SANITY_LEVEL_GREAT : user.mob_mood?.sanity_level)
|
||||
if(SANITY_LEVEL_GREAT)
|
||||
modified_move_delay *= 0.8
|
||||
if(SANITY_LEVEL_NEUTRAL)
|
||||
modified_move_delay *= 0.9
|
||||
if(SANITY_LEVEL_DISTURBED)
|
||||
modified_move_delay *= 1
|
||||
if(SANITY_LEVEL_CRAZY)
|
||||
modified_move_delay *= 1.1
|
||||
if(SANITY_LEVEL_INSANE)
|
||||
modified_move_delay *= 1.2
|
||||
var/modified_move_delay = get_move_delay(living_parent, user, direction)
|
||||
if(NSCOMPONENT(direction) && EWCOMPONENT(direction))
|
||||
modified_move_delay = FLOOR(modified_move_delay * sqrt(2), world.tick_lag)
|
||||
COOLDOWN_START(src, vehicle_move_cooldown, modified_move_delay)
|
||||
return ..()
|
||||
|
||||
/// Calculates and returns movement delay for a certain direction
|
||||
/datum/component/riding/creature/proc/get_move_delay(mob/living/living_parent, mob/living/user, direction)
|
||||
var/modified_move_delay = uses_native_speed ? living_parent.cached_multiplicative_slowdown : vehicle_move_delay
|
||||
if(HAS_TRAIT(user, TRAIT_ROUGHRIDER)) // YEEHAW!
|
||||
modified_move_delay *= get_roughrider_mult(user)
|
||||
return modified_move_delay
|
||||
|
||||
/datum/component/riding/creature/proc/get_roughrider_mult(mob/living/user)
|
||||
if (HAS_TRAIT(user, TRAIT_PRIMITIVE))
|
||||
return 0.8
|
||||
switch(user.mob_mood?.sanity_level)
|
||||
if(SANITY_LEVEL_GREAT)
|
||||
return 0.8
|
||||
if(SANITY_LEVEL_NEUTRAL)
|
||||
return 0.9
|
||||
if(SANITY_LEVEL_DISTURBED)
|
||||
return 1
|
||||
if(SANITY_LEVEL_CRAZY)
|
||||
return 1.1
|
||||
if(SANITY_LEVEL_INSANE)
|
||||
return 1.2
|
||||
return 1
|
||||
|
||||
/// Yeets the rider off, used for animals and cyborgs, redefined for humans who shove their piggyback rider off
|
||||
/datum/component/riding/creature/proc/force_dismount(mob/living/rider, throw_range = 8, throw_speed = 3, gentle = FALSE)
|
||||
var/atom/movable/movable_parent = parent
|
||||
@@ -566,19 +577,53 @@
|
||||
keytype = /obj/item/key/lasso
|
||||
uses_native_speed = TRUE
|
||||
rider_traits = list(TRAIT_NO_FLOATING_ANIM, TRAIT_TENTACLE_IMMUNE)
|
||||
/// Flat speed boost to ourselves
|
||||
var/flat_speed_mod = -9.5
|
||||
/// Last direction we've moved in
|
||||
var/last_move_dir = null
|
||||
/// Current speed boost
|
||||
var/speed_boost = 0
|
||||
/// Speed boost per time equivalent tile of movement in the same direction
|
||||
/// Not directly per tile as we move faster and thus would accelerate faster
|
||||
var/rush_speed_boost = -0.3
|
||||
/// Maximum speed boost we can have
|
||||
var/maximum_boost = -3
|
||||
/// Have we spawned an afterimage last move?
|
||||
var/spawned_last_move = FALSE
|
||||
|
||||
/datum/component/riding/creature/goliath/deathmatch
|
||||
keytype = null
|
||||
|
||||
/datum/component/riding/creature/goliath/Initialize(mob/living/riding_mob, force, ride_check_flags)
|
||||
/datum/component/riding/creature/goliath/driver_move(atom/movable/movable_parent, mob/living/user, direction)
|
||||
if (speed_boost != maximum_boost)
|
||||
return ..()
|
||||
// At maximum acceleration, start spawning afterimages
|
||||
var/turf/old_loc = movable_parent.loc
|
||||
. = ..()
|
||||
var/mob/living/basic/mining/goliath/goliath = parent
|
||||
goliath.add_movespeed_modifier(/datum/movespeed_modifier/goliath_mount)
|
||||
if (. & COMPONENT_DRIVER_BLOCK_MOVE)
|
||||
return
|
||||
if (!spawned_last_move && istype(old_loc))
|
||||
new /obj/effect/temp_visual/decoy/fading(old_loc, movable_parent, 150)
|
||||
spawned_last_move = !spawned_last_move
|
||||
|
||||
/datum/component/riding/creature/goliath/Destroy(force)
|
||||
var/mob/living/basic/mining/goliath/goliath = parent
|
||||
goliath.remove_movespeed_modifier(/datum/movespeed_modifier/goliath_mount)
|
||||
return ..()
|
||||
/datum/component/riding/creature/goliath/get_move_delay(mob/living/living_parent, mob/living/user, direction)
|
||||
var/move_delay = living_parent.cached_multiplicative_slowdown + flat_speed_mod
|
||||
// We give grace of 2 ticks of stopped movement, or 0.1 seconds, in case of SSinput not being able to process all inputs in a single tick
|
||||
if (last_move_dir != direction || vehicle_move_cooldown + 0.1 SECONDS < world.time)
|
||||
last_move_dir = direction
|
||||
// If we're "drifting" only halve our speed instead
|
||||
if (last_move_dir & direction)
|
||||
speed_boost /= 2
|
||||
else
|
||||
speed_boost = 0
|
||||
|
||||
var/modified_move_delay = move_delay + max(maximum_boost, speed_boost)
|
||||
speed_boost += rush_speed_boost * (modified_move_delay / move_delay)
|
||||
|
||||
// Apply roughrider boost last
|
||||
if(HAS_TRAIT(user, TRAIT_ROUGHRIDER))
|
||||
modified_move_delay *= get_roughrider_mult(user)
|
||||
return modified_move_delay
|
||||
|
||||
/datum/component/riding/creature/goliath/get_rider_offsets_and_layers(pass_index, mob/offsetter)
|
||||
return list(
|
||||
@@ -646,12 +691,18 @@
|
||||
. = ..()
|
||||
var/mob/living/basic/mining/goldgrub/goldgrub = parent
|
||||
goldgrub.add_movespeed_modifier(/datum/movespeed_modifier/goldgrub_mount)
|
||||
RegisterSignal(goldgrub, COMSIG_PROFICIENT_MINER_MINED, PROC_REF(on_mined))
|
||||
|
||||
/datum/component/riding/creature/goldgrub/Destroy(force)
|
||||
var/mob/living/basic/mining/goldgrub/goldgrub = parent
|
||||
goldgrub.remove_movespeed_modifier(/datum/movespeed_modifier/goldgrub_mount)
|
||||
return ..()
|
||||
|
||||
/datum/component/riding/creature/goldgrub/proc/on_mined(datum/source, turf/closed/wall/mineral/rock, mob/living/user)
|
||||
SIGNAL_HANDLER
|
||||
// Reset movement cooldown once you've dug a tile
|
||||
COOLDOWN_RESET(src, vehicle_move_cooldown)
|
||||
|
||||
/datum/component/riding/creature/goldgrub/get_rider_offsets_and_layers(pass_index, mob/offsetter)
|
||||
return list(
|
||||
TEXT_NORTH = list(0, 3),
|
||||
|
||||
@@ -4,7 +4,7 @@
|
||||
/datum/component/storm_hating
|
||||
/// Types of weather which trigger the effect
|
||||
var/static/list/stormy_weather = list(
|
||||
/datum/weather/ash_storm,
|
||||
/datum/weather/particle/ash_storm,
|
||||
/datum/weather/snow_storm,
|
||||
/datum/weather/void_storm,
|
||||
)
|
||||
|
||||
@@ -284,7 +284,7 @@
|
||||
if(!isnull(throwforce_on))
|
||||
source.throwforce = throwforce_off
|
||||
if(!isnull(throw_speed_on))
|
||||
source.throw_speed = throwforce_off
|
||||
source.throw_speed = throw_speed_off
|
||||
|
||||
if(LAZYLEN(attack_verb_continuous_on))
|
||||
source.attack_verb_continuous = attack_verb_continuous_off
|
||||
|
||||
@@ -119,7 +119,7 @@
|
||||
src.force_multiplier = force_multiplier
|
||||
if(!isnull(force_wielded))
|
||||
src.force_wielded = force_wielded
|
||||
if(isnull(force_unwielded))
|
||||
if(!isnull(force_unwielded))
|
||||
src.force_unwielded = force_unwielded
|
||||
if(icon_wielded)
|
||||
src.icon_wielded = icon_wielded
|
||||
|
||||
@@ -0,0 +1,161 @@
|
||||
/**
|
||||
* Walking Aid Component
|
||||
*
|
||||
* Add this to an item to allow it to act as a cane (or crutch) while held.
|
||||
* Items with this component will help mobs avoid limping from broken
|
||||
* leg bones, and lessen the slowdown caused by missing legs.
|
||||
*
|
||||
* Used by canes, crutches, and pole-like items such as spears and staffs.
|
||||
*/
|
||||
/datum/component/walking_aid
|
||||
dupe_mode = COMPONENT_DUPE_UNIQUE
|
||||
/// Causes a mob to waddle (wiggle) while walking when holding this object
|
||||
var/waddling = FALSE
|
||||
/// If set, the parent item must have this trait for the support to function
|
||||
var/required_trait
|
||||
/// Weakref to the mob currently being supported
|
||||
var/datum/weakref/current_user_ref
|
||||
/// The amount of slowdown to reduce for a limbless leg
|
||||
var/limbless_slowdown_modifier = 0.6 // reduces slowdown by 40%
|
||||
|
||||
/datum/component/walking_aid/Initialize(limbless_slowdown_modifier = 0.6, required_trait = null, waddling = FALSE)
|
||||
if(!isitem(parent))
|
||||
return COMPONENT_INCOMPATIBLE
|
||||
|
||||
src.waddling = waddling
|
||||
src.required_trait = required_trait
|
||||
src.limbless_slowdown_modifier = limbless_slowdown_modifier
|
||||
|
||||
/datum/component/walking_aid/Destroy(force)
|
||||
remove_support()
|
||||
return ..()
|
||||
|
||||
/datum/component/walking_aid/RegisterWithParent()
|
||||
RegisterSignal(parent, COMSIG_ITEM_EQUIPPED, PROC_REF(on_equip))
|
||||
RegisterSignal(parent, COMSIG_ITEM_DROPPED, PROC_REF(on_drop))
|
||||
RegisterSignal(parent, COMSIG_ATOM_EXAMINE_TAGS, PROC_REF(get_examine_tags))
|
||||
RegisterSignal(parent, SIGNAL_ADDTRAIT(TRAIT_WIELDED), PROC_REF(update_legs))
|
||||
RegisterSignal(parent, SIGNAL_REMOVETRAIT(TRAIT_WIELDED), PROC_REF(update_legs))
|
||||
RegisterSignal(parent, SIGNAL_ADDTRAIT(required_trait), PROC_REF(update_legs))
|
||||
RegisterSignal(parent, SIGNAL_REMOVETRAIT(required_trait), PROC_REF(update_legs))
|
||||
|
||||
/datum/component/walking_aid/UnregisterFromParent()
|
||||
UnregisterSignal(parent, list(
|
||||
COMSIG_ITEM_EQUIPPED,
|
||||
COMSIG_ITEM_DROPPED,
|
||||
COMSIG_ATOM_EXAMINE_TAGS,
|
||||
SIGNAL_ADDTRAIT(TRAIT_WIELDED),
|
||||
SIGNAL_REMOVETRAIT(TRAIT_WIELDED),
|
||||
SIGNAL_ADDTRAIT(required_trait),
|
||||
SIGNAL_REMOVETRAIT(required_trait),
|
||||
))
|
||||
remove_support()
|
||||
|
||||
/datum/component/walking_aid/proc/on_equip(datum/source, mob/equipper, slot)
|
||||
SIGNAL_HANDLER
|
||||
|
||||
remove_support()
|
||||
if(!(slot & ITEM_SLOT_HANDS))
|
||||
return
|
||||
if(!isliving(equipper))
|
||||
return
|
||||
|
||||
apply_support(equipper)
|
||||
|
||||
/datum/component/walking_aid/proc/on_drop(datum/source, mob/user)
|
||||
SIGNAL_HANDLER
|
||||
remove_support()
|
||||
|
||||
/datum/component/walking_aid/proc/get_examine_tags(atom/source, mob/user, list/examine_list)
|
||||
SIGNAL_HANDLER
|
||||
|
||||
examine_list["walking-aid"] = "It can help lessen the slowdown caused from a missing or injured leg, when held on the same side as the injury."
|
||||
|
||||
// Updates our leg status when wielded/unwielded a two handed walking aid like a spear
|
||||
/datum/component/walking_aid/proc/update_legs(atom/source)
|
||||
SIGNAL_HANDLER
|
||||
|
||||
var/mob/living/user = current_user_ref?.resolve()
|
||||
user?.update_usable_leg_status()
|
||||
|
||||
/datum/component/walking_aid/proc/apply_support(mob/living/user)
|
||||
if(current_user_ref)
|
||||
remove_support()
|
||||
|
||||
current_user_ref = WEAKREF(user)
|
||||
RegisterSignal(user, COMSIG_CARBON_LIMPING, PROC_REF(handle_limping))
|
||||
RegisterSignal(user, COMSIG_LIVING_LIMBLESS_SLOWDOWN, PROC_REF(handle_slowdown))
|
||||
user.update_usable_leg_status()
|
||||
|
||||
if(waddling)
|
||||
user.AddElementTrait(TRAIT_WADDLING, REF(src), /datum/element/waddling)
|
||||
|
||||
/datum/component/walking_aid/proc/remove_support()
|
||||
var/mob/living/user = current_user_ref?.resolve()
|
||||
current_user_ref = null
|
||||
if(isnull(user))
|
||||
return
|
||||
UnregisterSignal(user, list(COMSIG_CARBON_LIMPING, COMSIG_LIVING_LIMBLESS_SLOWDOWN))
|
||||
user.update_usable_leg_status()
|
||||
|
||||
if(waddling)
|
||||
REMOVE_TRAIT(user, TRAIT_WADDLING, REF(src))
|
||||
|
||||
/datum/component/walking_aid/proc/is_active()
|
||||
// if both hands are holding it, then it is not being used for support
|
||||
if(HAS_TRAIT(parent, TRAIT_WIELDED))
|
||||
return FALSE
|
||||
|
||||
if(isnull(required_trait))
|
||||
return TRUE
|
||||
|
||||
return HAS_TRAIT(parent, required_trait)
|
||||
|
||||
/datum/component/walking_aid/proc/handle_limping(mob/living/user, obj/item/bodypart/limping_leg)
|
||||
SIGNAL_HANDLER
|
||||
|
||||
if(!is_active())
|
||||
return NONE
|
||||
if(isnull(limping_leg))
|
||||
return NONE
|
||||
|
||||
var/supported_zone = get_supported_leg_zone(user)
|
||||
if(isnull(supported_zone))
|
||||
return NONE
|
||||
if(limping_leg.body_zone != supported_zone)
|
||||
return NONE
|
||||
|
||||
return COMPONENT_CANCEL_LIMP
|
||||
|
||||
/datum/component/walking_aid/proc/handle_slowdown(mob/living/user, limbless_slowdown, list/slowdown_mods)
|
||||
SIGNAL_HANDLER
|
||||
|
||||
if(!is_active())
|
||||
return
|
||||
if(!iscarbon(user))
|
||||
return
|
||||
var/mob/living/carbon/carbon_user = user
|
||||
var/leg_amount = carbon_user.usable_legs
|
||||
if(leg_amount >= carbon_user.default_num_legs)
|
||||
return
|
||||
if(!leg_amount) // someday support dual-wielding crutches but for now they are destined to waddle
|
||||
return
|
||||
|
||||
var/supported_zone = get_supported_leg_zone(user)
|
||||
if(isnull(supported_zone))
|
||||
return
|
||||
if(carbon_user.get_bodypart(supported_zone)) // make sure their leg is actually missing
|
||||
return
|
||||
|
||||
slowdown_mods += limbless_slowdown_modifier
|
||||
|
||||
/datum/component/walking_aid/proc/get_supported_leg_zone(mob/living/user)
|
||||
var/held_hand_zone = user.get_hand_zone_of_item(parent)
|
||||
|
||||
switch(held_hand_zone)
|
||||
if(BODY_ZONE_R_ARM)
|
||||
return BODY_ZONE_R_LEG
|
||||
if(BODY_ZONE_L_ARM)
|
||||
return BODY_ZONE_L_LEG
|
||||
else
|
||||
return null
|
||||
Reference in New Issue
Block a user