Files
Y0SH1M4S73RandGitHub 6f37db300b Gives non-standard nullrods the rest of the features common to regular null rods (#94980)
## About The Pull Request

Non-standard null-rods (the skateboard, bow, revolver, carpsie plush,
and eswords) did not receive all the common characteristics of regular
null rods in #93394. In particular, they were not given the
`UNIQUE_RENAME` obj flag, and they did not receive the ability to track
how many cultists they've crit/killed and be turned into cult weapons
when sacrificed. This PR corrects that by extracting the cult kill
tracking behavior to a component, while doing the following refactors to
ensure complete compatibility:

- Skateboard items now move themselves into the skateboard vehicle they
spawn on use, instead of deleting themselves. This was necessary for the
holy board to keep its custom name/desc and cultist kill count.
- Guns (which the bow technically is) will track cultists killed/crit
with bullets fired from them by a mob with a holy role.
- A signal can now be used for an item to provide an arbitrary response
when an offer rune underneath it is activated.

## Why It's Good For The Game

I just wanted the holy eswords to be renameable for chaplains to provide
plausible deniability for the possession of actual eswords, but after I
discovered this consistency issue, and felt the need to fix it.

## Changelog

🆑
fix: The holy energy swords and the carp-sie plushie can once again be
renamed
fix: The holy energy swords and the carp-sie plushie can once again be
sacrificed by cultists to spawn different weapons based on how many
unique cultists the chaplain has crit or killed with them
qol: The holy skateboard can be renamed like other null rod variants can
fix: Unusual null rod variants like the holy skateboard and bow can now
be sacrificed by cultists to spawn different weapons based on how many
unique cultists the chaplain has crit or killed with them. The bow and
the burdened chaplain's revolver, in particular, also count cultists
crit or killed by arrows/bullets fired from them by the chaplain.
/🆑
2026-02-03 22:23:20 -05:00

354 lines
14 KiB
Plaintext

/obj/vehicle/ridden/scooter
name = "scooter"
desc = "A fun way to get around."
icon_state = "scooter"
are_legs_exposed = TRUE
custom_materials = list(/datum/material/iron = SHEET_MATERIAL_AMOUNT * 11)
/obj/vehicle/ridden/scooter/Initialize(mapload)
. = ..()
make_ridable()
/obj/vehicle/ridden/scooter/proc/make_ridable()
AddElement(/datum/element/ridable, /datum/component/riding/vehicle/scooter)
/obj/vehicle/ridden/scooter/wrench_act(mob/living/user, obj/item/I)
..()
to_chat(user, span_notice("You begin to remove the handlebars..."))
if(!I.use_tool(src, user, 40, volume=50))
return TRUE
var/obj/vehicle/ridden/scooter/skateboard/improvised/skater = new(drop_location())
new /obj/item/stack/rods(drop_location(), 2)
to_chat(user, span_notice("You remove the handlebars from [src]."))
if(has_buckled_mobs())
var/mob/living/carbon/carbons = buckled_mobs[1]
unbuckle_mob(carbons)
skater.buckle_mob(carbons)
qdel(src)
return TRUE
/obj/vehicle/ridden/scooter/Moved(atom/old_loc, movement_dir, forced, list/old_locs, momentum_change = TRUE)
. = ..()
for(var/mob/living/buckled_mob as anything in buckled_mobs)
if(buckled_mob.num_legs > 0)
buckled_mob.pixel_y = 5
else
buckled_mob.pixel_y = -4
/obj/vehicle/ridden/scooter/skateboard
name = "skateboard"
desc = "An old, battered skateboard. It's still rideable, but probably unsafe."
icon_state = "skateboard"
density = FALSE
custom_materials = list(/datum/material/iron = SHEET_MATERIAL_AMOUNT * 10)
///Sparks datum for when we grind on tables
var/datum/effect_system/basic/spark_spread/sparks
///Whether the board is currently grinding
var/grinding = FALSE
///Stores the time of the last crash plus a short cooldown, affects availability and outcome of certain actions
var/next_crash
///The handheld item counterpart for the board
var/board_item_type = /obj/item/melee/skateboard
///Stamina drain multiplier
var/instability = 10
///If true, riding the skateboard with walk intent on will prevent crashing.
var/can_slow_down = TRUE
///The actual item for the skateboard
var/obj/item/melee/skateboard/board_item
/obj/vehicle/ridden/scooter/skateboard/Initialize(mapload, obj/item/melee/skateboard/board_item)
. = ..()
sparks = new(src, 1, FALSE)
sparks.attach(src)
if(!istype(board_item))
src.board_item = new board_item_type(src)
else
src.board_item = board_item
/obj/vehicle/ridden/scooter/skateboard/make_ridable()
AddElement(/datum/element/ridable, /datum/component/riding/vehicle/scooter/skateboard)
/obj/vehicle/ridden/scooter/skateboard/Destroy()
QDEL_NULL(sparks)
return ..()
/obj/vehicle/ridden/scooter/skateboard/relaymove(mob/living/user, direction)
if (grinding || world.time < next_crash)
return FALSE
return ..()
/obj/vehicle/ridden/scooter/skateboard/generate_actions()
. = ..()
initialize_controller_action_type(/datum/action/vehicle/ridden/scooter/skateboard/ollie, VEHICLE_CONTROL_DRIVE)
initialize_controller_action_type(/datum/action/vehicle/ridden/scooter/skateboard/kickflip, VEHICLE_CONTROL_DRIVE)
/obj/vehicle/ridden/scooter/skateboard/post_buckle_mob(mob/living/M)//allows skateboards to be non-dense but still allows 2 skateboarders to collide with each other
set_density(TRUE)
return ..()
/obj/vehicle/ridden/scooter/skateboard/post_unbuckle_mob(mob/living/M)
if(!has_buckled_mobs())
set_density(FALSE)
return ..()
/obj/vehicle/ridden/scooter/skateboard/Bump(atom/bumped_thing)
. = ..()
if(!bumped_thing.density || !has_buckled_mobs() || world.time < next_crash)
return
var/mob/living/rider = buckled_mobs[1]
if(rider.move_intent == MOVE_INTENT_WALK && can_slow_down) //Going slow prevents you from crashing.
return
next_crash = world.time + 10
rider.adjust_stamina_loss(instability*6)
playsound(src, 'sound/effects/bang.ogg', 40, TRUE)
if(!iscarbon(rider) || rider.get_stamina_loss() >= 100 || grinding || iscarbon(bumped_thing))
var/atom/throw_target = get_edge_target_turf(rider, pick(GLOB.cardinals))
unbuckle_mob(rider)
if((istype(bumped_thing, /obj/machinery/disposal/bin)))
rider.Paralyze(8 SECONDS)
rider.forceMove(bumped_thing)
forceMove(bumped_thing)
visible_message(span_danger("[src] crashes into [bumped_thing], and gets dumped straight into it!"))
return
rider.throw_at(throw_target, 3, 2)
var/head_slot = rider.get_item_by_slot(ITEM_SLOT_HEAD)
if(!head_slot || !(istype(head_slot,/obj/item/clothing/head/helmet) || istype(head_slot,/obj/item/clothing/head/utility/hardhat)))
rider.adjust_organ_loss(ORGAN_SLOT_BRAIN, 5)
rider.updatehealth()
visible_message(span_danger("[src] crashes into [bumped_thing], sending [rider] flying!"))
rider.Paralyze(8 SECONDS)
if(iscarbon(bumped_thing))
var/mob/living/carbon/victim = bumped_thing
var/grinding_mulitipler = 1
if(grinding)
grinding_mulitipler = 2
victim.Knockdown(4 * grinding_mulitipler SECONDS)
else
var/backdir = REVERSE_DIR(dir)
step(src, backdir)
rider.spin(4, 1)
///Moves the vehicle forward and if it lands on a table, repeats
/obj/vehicle/ridden/scooter/skateboard/proc/grind()
step(src, dir)
if(!has_buckled_mobs() || !(locate(/obj/structure/table) in loc.contents) && !(locate(/obj/structure/fluff/tram_rail) in loc.contents))
obj_flags = CAN_BE_HIT
grinding = FALSE
icon_state = "[initial(icon_state)]"
return
var/mob/living/skater = buckled_mobs[1]
skater.adjust_stamina_loss(instability*0.3)
if(skater.get_stamina_loss() >= 100)
obj_flags = CAN_BE_HIT
playsound(src, 'sound/effects/bang.ogg', 20, TRUE)
unbuckle_mob(skater)
var/atom/throw_target = get_edge_target_turf(src, pick(GLOB.cardinals))
skater.throw_at(throw_target, 2, 2)
visible_message(span_danger("[skater] loses [skater.p_their()] footing and slams on the ground!"))
skater.Paralyze(4 SECONDS)
grinding = FALSE
icon_state = "[initial(icon_state)]"
return
playsound(src, 'sound/vehicles/skateboard_roll.ogg', 50, TRUE)
var/turf/location = get_turf(src)
if(location)
if(prob(25))
location.hotspot_expose(1000,1000)
sparks.start() //the most radical way to start plasma fires
for(var/mob/living/carbon/victim in location)
if(victim.body_position == LYING_DOWN)
playsound(location, 'sound/items/trayhit/trayhit2.ogg', 40)
victim.apply_damage(damage = 25, damagetype = BRUTE, def_zone = victim.get_random_valid_zone(even_weights = TRUE), wound_bonus = 20)
victim.Paralyze(1.5 SECONDS)
skater.adjust_stamina_loss(instability)
victim.visible_message(span_danger("[victim] straight up gets grinded into the ground by [skater]'s [src]! Radical!"))
addtimer(CALLBACK(src, PROC_REF(grind)), 0.1 SECONDS)
/obj/vehicle/ridden/scooter/skateboard/mouse_drop_dragged(atom/over_object, mob/user)
var/mob/living/carbon/skater = user
if(!istype(skater))
return
if (over_object == skater)
pick_up_board(skater)
/obj/vehicle/ridden/scooter/skateboard/proc/pick_up_board(mob/living/carbon/skater, forced = FALSE)
if ((skater.incapacitated || !Adjacent(skater)) && !forced)
return
if(has_buckled_mobs())
to_chat(skater, span_warning("You can't lift this up when somebody's on it."))
return
skater.put_in_hands(board_item)
qdel(src)
/obj/vehicle/ridden/scooter/skateboard/pro
name = "skateboard"
desc = "An EightO brand professional skateboard. Looks a lot more stable than the average board."
icon_state = "skateboard2"
board_item_type = /obj/item/melee/skateboard/pro
instability = 6
/obj/vehicle/ridden/scooter/skateboard/pro/make_ridable()
AddElement(/datum/element/ridable, /datum/component/riding/vehicle/scooter/skateboard/pro)
/obj/vehicle/ridden/scooter/skateboard/hoverboard
name = "hoverboard"
desc = "A blast from the past, so retro!"
board_item_type = /obj/item/melee/skateboard/hoverboard
instability = 3
icon_state = "hoverboard_red"
/obj/vehicle/ridden/scooter/skateboard/hoverboard/make_ridable()
AddElement(/datum/element/ridable, /datum/component/riding/vehicle/scooter/skateboard/hover)
/obj/vehicle/ridden/scooter/skateboard/hoverboard/can_z_move(direction, turf/start, turf/destination, z_move_flags = ZMOVE_FLIGHT_FLAGS, mob/living/rider)
. = ..()
if(!.)
return
if(rider && (z_move_flags & ZMOVE_CAN_FLY_CHECKS) && direction == UP)
if(z_move_flags & ZMOVE_FEEDBACK)
to_chat(rider, span_warning("[src] [p_are()] not powerful enough to fly upwards."))
return FALSE
/obj/vehicle/ridden/scooter/skateboard/hoverboard/holyboarded
name = "holy skateboard"
desc = "A board blessed by the gods with the power to grind for our sins. Has the initials 'J.C.' on the underside."
board_item_type = /obj/item/melee/skateboard/holyboard
instability = 3
icon_state = "hoverboard_holy"
/obj/vehicle/ridden/scooter/skateboard/hoverboard/holyboarded/make_ridable()
AddElement(/datum/element/ridable, /datum/component/riding/vehicle/scooter/skateboard/hover/holy)
/obj/vehicle/ridden/scooter/skateboard/hoverboard/holyboarded/Initialize(mapload)
. = ..()
AddComponent(/datum/component/anti_magic, MAGIC_RESISTANCE|MAGIC_RESISTANCE_HOLY)
/obj/vehicle/ridden/scooter/skateboard/hoverboard/admin
name = "\improper Board Of Directors"
desc = "The engineering complexity of a spaceship concentrated inside of a board. Just as expensive, too."
board_item_type = /obj/item/melee/skateboard/hoverboard/admin
instability = 0
icon_state = "hoverboard_nt"
/obj/vehicle/ridden/scooter/skateboard/improvised
name = "improvised skateboard"
desc = "An unfinished scooter which can only barely be called a skateboard. It's still rideable, but probably unsafe. Looks like you'll need to add a few rods to make handlebars."
board_item_type = /obj/item/melee/skateboard/improvised
instability = 12
//CONSTRUCTION
/obj/item/scooter_frame
name = "scooter frame"
desc = "A metal frame for building a scooter. Looks like you'll need to add some iron to make wheels."
icon = 'icons/mob/rideables/vehicles.dmi'
icon_state = "scooter_frame"
w_class = WEIGHT_CLASS_NORMAL
custom_materials = list(/datum/material/iron = SHEET_MATERIAL_AMOUNT * 5)
/obj/item/scooter_frame/attackby(obj/item/I, mob/user, list/modifiers, list/attack_modifiers)
if(!istype(I, /obj/item/stack/sheet/iron))
return ..()
if(!I.tool_start_check(user, amount=5))
return
to_chat(user, span_notice("You begin to add wheels to [src]."))
if(!I.use_tool(src, user, 80, volume=50, amount=5))
return
to_chat(user, span_notice("You finish making wheels for [src]."))
new /obj/vehicle/ridden/scooter/skateboard/improvised(user.loc)
qdel(src)
/obj/item/scooter_frame/wrench_act(mob/living/user, obj/item/I)
..()
to_chat(user, span_notice("You deconstruct [src]."))
new /obj/item/stack/rods(drop_location(), 10)
I.play_tool_sound(src)
qdel(src)
return TRUE
/obj/vehicle/ridden/scooter/skateboard/wrench_act(mob/living/user, obj/item/I)
return
/obj/vehicle/ridden/scooter/skateboard/improvised/attackby(obj/item/I, mob/user, list/modifiers, list/attack_modifiers)
if(!istype(I, /obj/item/stack/rods))
return ..()
if(!I.tool_start_check(user, amount=2))
return
to_chat(user, span_notice("You begin making handlebars for [src]."))
if(!I.use_tool(src, user, 25, volume=50, amount=2))
return
to_chat(user, span_notice("You add the rods to [src], creating handlebars."))
var/obj/vehicle/ridden/scooter/skaterskoot = new(loc)
if(has_buckled_mobs())
var/mob/living/carbon/skaterboy = buckled_mobs[1]
unbuckle_mob(skaterboy)
skaterskoot.buckle_mob(skaterboy)
qdel(src)
/obj/vehicle/ridden/scooter/skateboard/improvised/screwdriver_act(mob/living/user, obj/item/I)
. = ..()
if(.)
return
to_chat(user, span_notice("You begin to deconstruct and remove the wheels on [src]..."))
if(!I.use_tool(src, user, 20, volume=50))
return
to_chat(user, span_notice("You deconstruct the wheels on [src]."))
new /obj/item/stack/sheet/iron(drop_location(), 5)
new /obj/item/scooter_frame(drop_location())
if(has_buckled_mobs())
var/mob/living/carbon/skatergirl = buckled_mobs[1]
unbuckle_mob(skatergirl)
qdel(src)
return TRUE
//Wheelys
/obj/vehicle/ridden/scooter/skateboard/wheelys
name = "Wheely-Heels"
desc = "Uses patented retractable wheel technology. Never sacrifice speed for style - not that this provides much of either."
icon_state = null
density = FALSE
instability = 12
///Stores the shoes associated with the vehicle
var/obj/item/clothing/shoes/wheelys/shoes = null
///Name of the wheels, for visible messages
var/wheel_name = "wheels"
///Component typepath to attach in [/obj/vehicle/ridden/scooter/skateboard/wheelys/proc/make_ridable()]
var/component_type = /datum/component/riding/vehicle/scooter/skateboard/wheelys
/obj/vehicle/ridden/scooter/skateboard/wheelys/make_ridable()
AddElement(/datum/element/ridable, component_type)
/obj/vehicle/ridden/scooter/skateboard/wheelys/post_unbuckle_mob(mob/living/M)
if(!has_buckled_mobs())
to_chat(M, span_notice("You pop the [wheel_name] back into place."))
moveToNullspace()
shoes.toggle_wheels(FALSE)
return ..()
/obj/vehicle/ridden/scooter/skateboard/wheelys/pick_up_board(mob/living/carbon/Skater)
return
/obj/vehicle/ridden/scooter/skateboard/wheelys/post_buckle_mob(mob/living/M)
to_chat(M, span_notice("You pop out the [wheel_name]."))
shoes.toggle_wheels(TRUE)
return ..()
///Sets the shoes that the vehicle is associated with, called when the shoes are initialized
/obj/vehicle/ridden/scooter/skateboard/wheelys/proc/link_shoes(newshoes)
shoes = newshoes
/obj/vehicle/ridden/scooter/skateboard/wheelys/rollerskates
name = "roller skates"
desc = "An EightO brand pair of roller skates. Vintage, yet functional!"
instability = 8
component_type = /datum/component/riding/vehicle/scooter/skateboard/wheelys/rollerskates
/obj/vehicle/ridden/scooter/skateboard/wheelys/skishoes
name = "ski shoes"
desc = "A pair of shoes equipped with foldable skis! Very handy to move in snowy environments unimpeded."
instability = 8
wheel_name = "skis"
component_type = /datum/component/riding/vehicle/scooter/skateboard/wheelys/skishoes