mirror of
https://github.com/Bubberstation/Bubberstation.git
synced 2025-12-11 10:11:09 +00:00
No roundstart playable MULEs / Trampling requires hacking (#76837)
## About The Pull Request Prevailing feedback has been: - The player base cannot be trusted to control MULEbots. - It should be clearer what bots can and can't do. The former is easy to fix. The latter is sort of a matter for policy but I'm going to investigate giving bots a rudimentary laws system. Plus that sounds much more controversial than this so I am going to atomise this outside of that PR. MULEbots can still be set to allow sentience by cargo technicians, but don't start that way. ADDITIONALLY this PR just changes it so that MULEbots do not crush people unless: - They have been emagged. - Their safety wire has been cut. Either means works, so it's not too hard to access for nefarious purposes, but hard to do to yourself. Otherwise they just slow down for a few seconds instead. Also fixed an unrelated name bug while I was there. Closes #76926 ## Why It's Good For The Game Players would take them, not deliver any cargo, and repeatedly ask people to lie down in front of them. Plus Tram has 5 of the things which is frankly too many to be wandering around the bar. ## Changelog 🆑 balance: You can't possess a MULE as soon as the round starts, someone will have to give you permission. balance: MULEbots no longer crush prone characters unless they have been hacked (or emagged). fix: Bots can put numbers in their names, what with being robots. admin: Adds attack logging when certain wires are cut (for instance: MULEbot safeties) /🆑
This commit is contained in:
@@ -88,6 +88,8 @@
|
||||
#define BOT_MODE_REMOTE_ENABLED (1<<2)
|
||||
///The Bot is allowed to have a ghost placed in control of it.
|
||||
#define BOT_MODE_CAN_BE_SAPIENT (1<<3)
|
||||
///The Bot is allowed to be possessed if it is present on mapload.
|
||||
#define BOT_MODE_ROUNDSTART_POSSESSION (1<<4)
|
||||
|
||||
//Bot cover defines indicating the Bot's status
|
||||
///The Bot's cover is open and can be modified/emagged by anyone.
|
||||
|
||||
@@ -933,5 +933,27 @@
|
||||
/datum/status_effect/teleport_madness/tick()
|
||||
dump_in_space(owner)
|
||||
|
||||
/datum/status_effect/careful_driving
|
||||
id = "careful_driving"
|
||||
alert_type = /atom/movable/screen/alert/status_effect/careful_driving
|
||||
duration = 5 SECONDS
|
||||
status_type = STATUS_EFFECT_REPLACE
|
||||
|
||||
/datum/status_effect/careful_driving/on_apply()
|
||||
. = ..()
|
||||
owner.add_movespeed_modifier(/datum/movespeed_modifier/careful_driving, update = TRUE)
|
||||
|
||||
/datum/status_effect/careful_driving/on_remove()
|
||||
. = ..()
|
||||
owner.remove_movespeed_modifier(/datum/movespeed_modifier/careful_driving, update = TRUE)
|
||||
|
||||
/atom/movable/screen/alert/status_effect/careful_driving
|
||||
name = "Careful Driving"
|
||||
desc = "That was close! You almost ran that one over!"
|
||||
icon_state = "paralysis"
|
||||
|
||||
/datum/movespeed_modifier/careful_driving
|
||||
multiplicative_slowdown = 3
|
||||
|
||||
#undef HEALING_SLEEP_DEFAULT
|
||||
#undef HEALING_SLEEP_ORGAN_MULTIPLIER
|
||||
|
||||
@@ -153,25 +153,25 @@
|
||||
/datum/wires/proc/is_dud_color(color)
|
||||
return is_dud(get_wire(color))
|
||||
|
||||
/datum/wires/proc/cut(wire)
|
||||
/datum/wires/proc/cut(wire, source)
|
||||
if(is_cut(wire))
|
||||
cut_wires -= wire
|
||||
SEND_SIGNAL(src, COMSIG_MEND_WIRE(wire), wire)
|
||||
on_cut(wire, mend = TRUE)
|
||||
on_cut(wire, mend = TRUE, source = source)
|
||||
else
|
||||
cut_wires += wire
|
||||
SEND_SIGNAL(src, COMSIG_CUT_WIRE(wire), wire)
|
||||
on_cut(wire, mend = FALSE)
|
||||
on_cut(wire, mend = FALSE, source = source)
|
||||
|
||||
/datum/wires/proc/cut_color(color)
|
||||
cut(get_wire(color))
|
||||
/datum/wires/proc/cut_color(color, source)
|
||||
cut(get_wire(color), source)
|
||||
|
||||
/datum/wires/proc/cut_random()
|
||||
cut(wires[rand(1, wires.len)])
|
||||
/datum/wires/proc/cut_random(source)
|
||||
cut(wires[rand(1, wires.len)], source)
|
||||
|
||||
/datum/wires/proc/cut_all()
|
||||
/datum/wires/proc/cut_all(source)
|
||||
for(var/wire in wires)
|
||||
cut(wire)
|
||||
cut(wire, source)
|
||||
|
||||
/datum/wires/proc/pulse(wire, user, force=FALSE)
|
||||
if(!force && is_cut(wire))
|
||||
@@ -232,7 +232,7 @@
|
||||
/datum/wires/proc/get_status()
|
||||
return list()
|
||||
|
||||
/datum/wires/proc/on_cut(wire, mend = FALSE)
|
||||
/datum/wires/proc/on_cut(wire, mend = FALSE, source = null)
|
||||
return
|
||||
|
||||
/datum/wires/proc/on_pulse(wire, user)
|
||||
@@ -329,7 +329,7 @@
|
||||
if(I || isAdminGhostAI(usr))
|
||||
if(I && holder)
|
||||
I.play_tool_sound(holder, 20)
|
||||
cut_color(target_wire)
|
||||
cut_color(target_wire, source = L)
|
||||
. = TRUE
|
||||
else
|
||||
to_chat(L, span_warning("You need wirecutters!"))
|
||||
|
||||
@@ -52,7 +52,7 @@
|
||||
A.danger_level = AIR_ALARM_ALERT_NONE
|
||||
A.update_appearance()
|
||||
|
||||
/datum/wires/airalarm/on_cut(wire, mend)
|
||||
/datum/wires/airalarm/on_cut(wire, mend, source)
|
||||
var/obj/machinery/airalarm/A = holder
|
||||
switch(wire)
|
||||
if(WIRE_POWER) // Short out forever.
|
||||
|
||||
@@ -157,7 +157,7 @@
|
||||
else if(aiControlDisabled == AI_WIRE_HACKED)
|
||||
aiControlDisabled = AI_WIRE_DISABLED_HACKED
|
||||
|
||||
/datum/wires/airlock/on_cut(wire, mend)
|
||||
/datum/wires/airlock/on_cut(wire, mend, source)
|
||||
var/obj/machinery/door/airlock/A = holder
|
||||
switch(wire)
|
||||
if(WIRE_POWER1, WIRE_POWER2) // Cut to lose power, repair all to gain power.
|
||||
@@ -189,6 +189,8 @@
|
||||
else if(A.aiControlDisabled == AI_WIRE_DISABLED_HACKED)
|
||||
A.aiControlDisabled = AI_WIRE_HACKED
|
||||
if(WIRE_SHOCK) // Cut to shock the door, mend to unshock.
|
||||
if (!isnull(source))
|
||||
log_combat(source, A, "[mend ? "disabled" : "enabled"] shocking for")
|
||||
if(mend)
|
||||
if(A.secondsElectrified)
|
||||
A.set_electrified(MACHINE_NOT_ELECTRIFIED, usr)
|
||||
@@ -198,6 +200,8 @@
|
||||
A.shock(usr, 100)
|
||||
if(WIRE_SAFETY) // Cut to disable safeties, mend to re-enable.
|
||||
A.safe = mend
|
||||
if (!isnull(source))
|
||||
log_combat(source, A, "[mend ? "enabled" : "disabled"] door safeties for")
|
||||
if(WIRE_TIMING) // Cut to disable auto-close, mend to re-enable.
|
||||
A.autoclose = mend
|
||||
if(A.autoclose && !A.density)
|
||||
|
||||
@@ -40,7 +40,7 @@
|
||||
A.aidisabled = TRUE
|
||||
addtimer(CALLBACK(A, TYPE_PROC_REF(/obj/machinery/power/apc, reset), wire), 1 SECONDS)
|
||||
|
||||
/datum/wires/apc/on_cut(wire, mend)
|
||||
/datum/wires/apc/on_cut(wire, mend, source)
|
||||
var/obj/machinery/power/apc/A = holder
|
||||
switch(wire)
|
||||
if(WIRE_POWER1, WIRE_POWER2) // Short out.
|
||||
|
||||
@@ -37,7 +37,7 @@
|
||||
A.disabled = !A.disabled
|
||||
addtimer(CALLBACK(A, TYPE_PROC_REF(/obj/machinery/autolathe, reset), wire), 60)
|
||||
|
||||
/datum/wires/autolathe/on_cut(wire, mend)
|
||||
/datum/wires/autolathe/on_cut(wire, mend, source)
|
||||
var/obj/machinery/autolathe/A = holder
|
||||
switch(wire)
|
||||
if(WIRE_HACK)
|
||||
|
||||
@@ -12,6 +12,6 @@
|
||||
our_sniffer.activate()
|
||||
..()
|
||||
|
||||
/datum/wires/ecto_sniffer/on_cut(wire, mend)
|
||||
/datum/wires/ecto_sniffer/on_cut(wire, mend, source)
|
||||
var/obj/machinery/ecto_sniffer/our_sniffer = holder
|
||||
our_sniffer.sensor_enabled = mend
|
||||
|
||||
@@ -10,7 +10,9 @@
|
||||
/datum/wires/explosive/on_pulse(index)
|
||||
explode()
|
||||
|
||||
/datum/wires/explosive/on_cut(index, mend)
|
||||
/datum/wires/explosive/on_cut(index, mend, source)
|
||||
if (!isnull(source))
|
||||
log_combat(source, holder, "cut the detonation wire for")
|
||||
explode()
|
||||
|
||||
/datum/wires/explosive/proc/explode()
|
||||
@@ -34,7 +36,7 @@
|
||||
return
|
||||
. = ..()
|
||||
|
||||
/datum/wires/explosive/chem_grenade/on_cut(index, mend)
|
||||
/datum/wires/explosive/chem_grenade/on_cut(index, mend, source)
|
||||
var/obj/item/grenade/chem_grenade/grenade = holder
|
||||
if(grenade.stage != GRENADE_READY)
|
||||
return
|
||||
@@ -127,7 +129,7 @@
|
||||
else // Boom
|
||||
explode()
|
||||
|
||||
/datum/wires/explosive/pizza/on_cut(wire, mend)
|
||||
/datum/wires/explosive/pizza/on_cut(wire, mend, source)
|
||||
var/obj/item/pizzabox/P = holder
|
||||
switch(wire)
|
||||
if(WIRE_DISARM) // Disarm and untrap the box.
|
||||
@@ -135,6 +137,8 @@
|
||||
P.bomb_defused = TRUE
|
||||
else
|
||||
if(!mend && !P.bomb_defused)
|
||||
if (!isnull(source))
|
||||
log_combat(source, holder, "cut the detonation wire for")
|
||||
explode()
|
||||
|
||||
/datum/wires/explosive/pizza/explode()
|
||||
|
||||
@@ -38,7 +38,7 @@
|
||||
if(WIRE_LOADCHECK)
|
||||
machine.allow_exotic_faxes = !machine.allow_exotic_faxes
|
||||
|
||||
/datum/wires/fax/on_cut(wire, mend)
|
||||
/datum/wires/fax/on_cut(wire, mend, source)
|
||||
var/obj/machinery/fax/machine = holder
|
||||
switch(wire)
|
||||
if(WIRE_SHOCK)
|
||||
|
||||
@@ -22,7 +22,7 @@
|
||||
if(WIRE_ACTIVATE)
|
||||
M.cook()
|
||||
|
||||
/datum/wires/microwave/on_cut(wire, mend)
|
||||
/datum/wires/microwave/on_cut(wire, mend, source)
|
||||
var/obj/machinery/microwave/M = holder
|
||||
switch(wire)
|
||||
if(WIRE_ACTIVATE)
|
||||
|
||||
@@ -34,7 +34,7 @@
|
||||
if(WIRE_INTERFACE)
|
||||
mod.interface_break = !mod.interface_break
|
||||
|
||||
/datum/wires/mod/on_cut(wire, mend)
|
||||
/datum/wires/mod/on_cut(wire, mend, source)
|
||||
var/obj/item/mod/control/mod = holder
|
||||
switch(wire)
|
||||
if(WIRE_HACK)
|
||||
|
||||
@@ -23,7 +23,7 @@
|
||||
if(mule.bot_cover_flags & BOT_COVER_OPEN)
|
||||
return TRUE
|
||||
|
||||
/datum/wires/mulebot/on_cut(wire, mend)
|
||||
/datum/wires/mulebot/on_cut(wire, mend, source)
|
||||
var/mob/living/simple_animal/bot/mulebot/mule = holder
|
||||
switch(wire)
|
||||
if(WIRE_MOTOR1, WIRE_MOTOR2)
|
||||
@@ -38,6 +38,9 @@
|
||||
mule.set_varspeed(AVERAGE_MOTOR_SPEED)
|
||||
else
|
||||
mule.set_varspeed(SLOW_MOTOR_SPEED)
|
||||
if(WIRE_AVOIDANCE)
|
||||
if (!isnull(source))
|
||||
log_combat(source, mule, "[is_cut(WIRE_AVOIDANCE) ? "cut" : "mended"] the MULE safety wire of")
|
||||
|
||||
/datum/wires/mulebot/on_pulse(wire)
|
||||
var/mob/living/simple_animal/bot/mulebot/mule = holder
|
||||
|
||||
@@ -33,7 +33,7 @@
|
||||
R.hacked = !R.hacked
|
||||
if(WIRE_DISABLE)
|
||||
R.disabled = !R.disabled
|
||||
/datum/wires/rnd/on_cut(wire, mend)
|
||||
/datum/wires/rnd/on_cut(wire, mend, source)
|
||||
var/obj/machinery/rnd/R = holder
|
||||
switch(wire)
|
||||
if(WIRE_HACK)
|
||||
|
||||
@@ -68,7 +68,7 @@
|
||||
if(R.has_model())
|
||||
R.visible_message(span_notice("[R]'s model servos twitch."), span_notice("Your model display flickers."))
|
||||
|
||||
/datum/wires/robot/on_cut(wire, mend)
|
||||
/datum/wires/robot/on_cut(wire, mend, source)
|
||||
var/mob/living/silicon/robot/R = holder
|
||||
switch(wire)
|
||||
if(WIRE_AI) // Cut the AI wire to reset AI control.
|
||||
|
||||
@@ -51,7 +51,7 @@
|
||||
R.audible_message(span_warning("Unauthorized prize vend detected! Locking down machine!"))
|
||||
R.prize_theft(0.20)
|
||||
|
||||
/datum/wires/roulette/on_cut(wire, mend)
|
||||
/datum/wires/roulette/on_cut(wire, mend, source)
|
||||
var/obj/machinery/roulette/R = holder
|
||||
switch(wire)
|
||||
if(WIRE_SHOCK)
|
||||
|
||||
@@ -35,7 +35,7 @@
|
||||
if(usr)
|
||||
SSU.shock(usr)
|
||||
|
||||
/datum/wires/suit_storage_unit/on_cut(wire, mend)
|
||||
/datum/wires/suit_storage_unit/on_cut(wire, mend, source)
|
||||
var/obj/machinery/suit_storage_unit/SSU = holder
|
||||
switch(wire)
|
||||
if(WIRE_HACK)
|
||||
|
||||
@@ -69,7 +69,7 @@
|
||||
B.detonation_timer += 100
|
||||
B.delayedlittle = TRUE
|
||||
|
||||
/datum/wires/syndicatebomb/on_cut(wire, mend)
|
||||
/datum/wires/syndicatebomb/on_cut(wire, mend, source)
|
||||
var/obj/machinery/syndicatebomb/B = holder
|
||||
switch(wire)
|
||||
if(WIRE_BOOM,WIRE_BOOM2)
|
||||
@@ -78,9 +78,9 @@
|
||||
B.explode_now = TRUE
|
||||
if(!istype(B.payload, /obj/machinery/syndicatebomb/training))
|
||||
tell_admins(B)
|
||||
// Cursed usr use but no easy way to get the cutter
|
||||
if(isliving(usr))
|
||||
add_memory_in_range(B, 7, /datum/memory/bomb_defuse_failure, protagonist = usr, antagonist = B)
|
||||
if(isliving(source))
|
||||
log_combat(source, holder, "cut the detonation wire for")
|
||||
add_memory_in_range(B, 7, /datum/memory/bomb_defuse_failure, protagonist = source, antagonist = B)
|
||||
|
||||
if(WIRE_UNBOLT)
|
||||
if(!mend && B.anchored)
|
||||
|
||||
@@ -66,7 +66,7 @@
|
||||
if(WIRE_AGELIMIT)
|
||||
vending_machine.age_restrictions = !vending_machine.age_restrictions
|
||||
|
||||
/datum/wires/vending/on_cut(wire, mend)
|
||||
/datum/wires/vending/on_cut(wire, mend, source)
|
||||
var/obj/machinery/vending/vending_machine = holder
|
||||
switch(wire)
|
||||
if(WIRE_THROW)
|
||||
|
||||
@@ -47,8 +47,8 @@
|
||||
///All initial access this bot started with.
|
||||
var/list/prev_access = list()
|
||||
|
||||
///Bot-related mode flags on the Bot indicating how they will act. BOT_MODE_ON | BOT_MODE_AUTOPATROL | BOT_MODE_REMOTE_ENABLED | BOT_MODE_CAN_BE_SAPIENT
|
||||
var/bot_mode_flags = BOT_MODE_ON | BOT_MODE_REMOTE_ENABLED | BOT_MODE_CAN_BE_SAPIENT
|
||||
///Bot-related mode flags on the Bot indicating how they will act. BOT_MODE_ON | BOT_MODE_AUTOPATROL | BOT_MODE_REMOTE_ENABLED | BOT_MODE_CAN_BE_SAPIENT | BOT_MODE_ROUNDSTART_POSSESSION
|
||||
var/bot_mode_flags = BOT_MODE_ON | BOT_MODE_REMOTE_ENABLED | BOT_MODE_CAN_BE_SAPIENT | BOT_MODE_ROUNDSTART_POSSESSION
|
||||
|
||||
///Bot-related cover flags on the Bot to deal with what has been done to their cover, including emagging. BOT_COVER_OPEN | BOT_COVER_LOCKED | BOT_COVER_EMAGGED | BOT_COVER_HACKED
|
||||
var/bot_cover_flags = BOT_COVER_LOCKED
|
||||
@@ -192,7 +192,7 @@
|
||||
if(HAS_TRAIT(SSstation, STATION_TRAIT_BOTS_GLITCHED))
|
||||
randomize_language_if_on_station()
|
||||
|
||||
if(mapload && is_station_level(z) && (bot_mode_flags & BOT_MODE_CAN_BE_SAPIENT))
|
||||
if(mapload && is_station_level(z) && bot_mode_flags & BOT_MODE_CAN_BE_SAPIENT && bot_mode_flags & BOT_MODE_ROUNDSTART_POSSESSION)
|
||||
enable_possession(mapload = mapload)
|
||||
|
||||
/mob/living/simple_animal/bot/Destroy()
|
||||
@@ -252,13 +252,16 @@
|
||||
|
||||
/// Allows renaming the bot to something else
|
||||
/mob/living/simple_animal/bot/proc/rename(mob/user)
|
||||
var/new_name = sanitize_name(reject_bad_text(tgui_input_text(
|
||||
user = user,
|
||||
message = "This machine is designated [real_name]. Would you like to update its registration?",
|
||||
title = "Name change",
|
||||
default = real_name,
|
||||
max_length = MAX_NAME_LEN,
|
||||
)))
|
||||
var/new_name = sanitize_name(
|
||||
reject_bad_text(tgui_input_text(
|
||||
user = user,
|
||||
message = "This machine is designated [real_name]. Would you like to update its registration?",
|
||||
title = "Name change",
|
||||
default = real_name,
|
||||
max_length = MAX_NAME_LEN,
|
||||
)),
|
||||
allow_numbers = TRUE
|
||||
)
|
||||
if (isnull(new_name) || QDELETED(src))
|
||||
return
|
||||
if (key && user != src)
|
||||
|
||||
@@ -24,6 +24,7 @@
|
||||
buckle_lying = 0
|
||||
mob_size = MOB_SIZE_LARGE
|
||||
buckle_prevents_pull = TRUE // No pulling loaded shit
|
||||
bot_mode_flags = ~BOT_MODE_ROUNDSTART_POSSESSION
|
||||
|
||||
maints_access_required = list(ACCESS_ROBOTICS, ACCESS_CARGO)
|
||||
radio_key = /obj/item/encryptionkey/headset_cargo
|
||||
@@ -232,7 +233,7 @@
|
||||
unload(0)
|
||||
if(prob(25))
|
||||
visible_message(span_danger("Something shorts out inside [src]!"))
|
||||
wires.cut_random()
|
||||
wires.cut_random(source = Proj.firer)
|
||||
|
||||
/mob/living/simple_animal/bot/mulebot/ui_interact(mob/user, datum/tgui/ui)
|
||||
ui = SStgui.try_update_ui(user, src, ui)
|
||||
@@ -671,6 +672,12 @@
|
||||
|
||||
// when mulebot is in the same loc
|
||||
/mob/living/simple_animal/bot/mulebot/proc/run_over(mob/living/carbon/human/crushed)
|
||||
if (!(bot_cover_flags & BOT_COVER_EMAGGED) && !wires.is_cut(WIRE_AVOIDANCE))
|
||||
if (!has_status_effect(/datum/status_effect/careful_driving))
|
||||
crushed.visible_message(span_notice("[src] slows down to avoid crushing [crushed]."))
|
||||
apply_status_effect(/datum/status_effect/careful_driving)
|
||||
return // Player mules must be emagged before they can trample
|
||||
|
||||
log_combat(src, crushed, "run over", addition = "(DAMTYPE: [uppertext(BRUTE)])")
|
||||
crushed.visible_message(
|
||||
span_danger("[src] drives over [crushed]!"),
|
||||
|
||||
@@ -2,7 +2,7 @@
|
||||
holder_type = /obj/machinery/door/airlock/shell
|
||||
proper_name = "Circuit Airlock"
|
||||
|
||||
/datum/wires/airlock/shell/on_cut(wire, mend)
|
||||
/datum/wires/airlock/shell/on_cut(wire, mend, source)
|
||||
// Don't allow them to re-enable autoclose.
|
||||
if(wire == WIRE_TIMING)
|
||||
return
|
||||
|
||||
Reference in New Issue
Block a user