Merge pull request #16038 from SandPoot/fix-lava+borgs

Deals with lava plus a lot of borg stuff
This commit is contained in:
deathride58
2023-12-12 19:25:13 -05:00
committed by GitHub
12 changed files with 417 additions and 285 deletions

View File

@@ -133,24 +133,27 @@
#define ui_construct_pull "EAST,CENTER-2:15"
#define ui_construct_health "EAST,CENTER:15"
// AI
#define ui_ai_core "SOUTH:6,WEST"
#define ui_ai_camera_list "SOUTH:6,WEST+1"
#define ui_ai_track_with_camera "SOUTH:6,WEST+2"
#define ui_ai_camera_light "SOUTH:6,WEST+3"
#define ui_ai_crew_monitor "SOUTH:6,WEST+4"
#define ui_ai_crew_manifest "SOUTH:6,WEST+5"
#define ui_ai_alerts "SOUTH:6,WEST+6"
#define ui_ai_announcement "SOUTH:6,WEST+7"
#define ui_ai_shuttle "SOUTH:6,WEST+8"
#define ui_ai_state_laws "SOUTH:6,WEST+9"
#define ui_ai_pda_send "SOUTH:6,WEST+10"
#define ui_ai_pda_log "SOUTH:6,WEST+11"
#define ui_ai_take_picture "SOUTH:6,WEST+12"
#define ui_ai_view_images "SOUTH:6,WEST+13"
#define ui_ai_sensor "SOUTH:6,WEST+14"
#define ui_ai_multicam "SOUTH+1:6,WEST+13"
#define ui_ai_add_multicam "SOUTH+1:6,WEST+14"
//AI
#define ui_ai_core "BOTTOM:6,RIGHT-4"
#define ui_ai_shuttle "BOTTOM:6,RIGHT-3"
#define ui_ai_announcement "BOTTOM:6,RIGHT-2"
#define ui_ai_state_laws "BOTTOM:6,RIGHT-1"
#define ui_ai_pda_log "BOTTOM:6,RIGHT"
#define ui_ai_pda_send "BOTTOM+1:6,RIGHT"
#define ui_ai_language_menu "BOTTOM+1:8,RIGHT-2:30"
#define ui_ai_crew_monitor "BOTTOM:6,CENTER-1"
#define ui_ai_crew_manifest "BOTTOM:6,CENTER"
#define ui_ai_alerts "BOTTOM:6,CENTER+1"
#define ui_ai_view_images "BOTTOM:6,LEFT+4"
#define ui_ai_camera_list "BOTTOM:6,LEFT+3"
#define ui_ai_track_with_camera "BOTTOM:6,LEFT+2"
#define ui_ai_camera_light "BOTTOM:6,LEFT+1"
#define ui_ai_sensor "BOTTOM:6,LEFT"
#define ui_ai_multicam "BOTTOM+1:6,LEFT+1"
#define ui_ai_add_multicam "BOTTOM+1:6,LEFT"
#define ui_ai_take_picture "BOTTOM+2:6,LEFT"
// pAI

View File

@@ -194,7 +194,7 @@
// Language menu
using = new /atom/movable/screen/language_menu
using.screen_loc = ui_borg_language_menu
using.screen_loc = ui_ai_language_menu
using.hud = src
static_inventory += using

View File

@@ -312,6 +312,7 @@
qdel(O.mmi)
O.mmi = W //and give the real mmi to the borg.
O.updatename()
playsound(O.loc, 'sound/voice/liveagain.ogg', 75, TRUE)
SSblackbox.record_feedback("amount", "cyborg_birth", 1)
forceMove(O)
O.robot_suit = src

View File

@@ -8,32 +8,29 @@
icon_state = "cyborg_upgrade"
w_class = WEIGHT_CLASS_SMALL
var/locked = FALSE
var/installed = 0
var/require_module = 0
var/list/module_type
var/installed = FALSE
var/require_module = FALSE
var/list/module_type = null
/// Bitflags listing module compatibility. Used in the exosuit fabricator for creating sub-categories.
var/module_flags = NONE
// if true, is not stored in the robot to be ejected
// if module is reset
var/one_use = FALSE
/// Means this is a basetype and should not be used
var/abstract_type = /obj/item/borg/upgrade
/// Show the amount of this module that is installed
var/show_amount = FALSE
/obj/item/borg/upgrade/proc/action(mob/living/silicon/robot/R, user = usr)
if(R.stat == DEAD)
to_chat(user, "<span class='warning'>[src] will not function on a deceased cyborg.</span>")
to_chat(user, span_warning("[src] will not function on a deceased cyborg!"))
return FALSE
if(module_type && !is_type_in_list(R.module, module_type))
to_chat(R, "<span class='alert'>Upgrade mounting error! No suitable hardpoint detected.</span>")
to_chat(user, "<span class='warning'>There's no mounting point for the module!</span>")
to_chat(R, span_alert("Upgrade mounting error! No suitable hardpoint detected."))
to_chat(user, span_warning("There's no mounting point for the module!"))
return FALSE
return TRUE
/*
This proc gets called by upgrades after installing them. Use this for things that for example need to be moved into a specific borg item,
as performing this in action() will cause the upgrade to end up in the borg instead of its intended location due to forceMove() being called afterwards..
*/
/obj/item/borg/upgrade/proc/afterInstall(mob/living/silicon/robot/R, user = usr)
return
/obj/item/borg/upgrade/proc/deactivate(mob/living/silicon/robot/R, user = usr)
if (!(src in R.upgrades))
return FALSE
@@ -324,12 +321,12 @@ as performing this in action() will cause the upgrade to end up in the borg inst
/obj/item/borg/upgrade/lavaproof/action(mob/living/silicon/robot/R, user = usr)
. = ..()
if(.)
ADD_TRAIT(src, TRAIT_LAVA_IMMUNE, type)
ADD_TRAIT(R, TRAIT_LAVA_IMMUNE, type)
/obj/item/borg/upgrade/lavaproof/deactivate(mob/living/silicon/robot/R, user = usr)
. = ..()
if (.)
REMOVE_TRAIT(src, TRAIT_LAVA_IMMUNE, type)
REMOVE_TRAIT(R, TRAIT_LAVA_IMMUNE, type)
/obj/item/borg/upgrade/selfrepair
name = "self-repair module"
@@ -440,6 +437,7 @@ as performing this in action() will cause the upgrade to end up in the borg inst
/obj/item/robot_module/syndicate_medical)
var/list/additional_reagents = list()
module_flags = BORG_MODULE_MEDICAL
abstract_type = /obj/item/borg/upgrade/hypospray
/obj/item/borg/upgrade/hypospray/action(mob/living/silicon/robot/R, user = usr)
. = ..()

View File

@@ -201,6 +201,7 @@
var/obj/structure/closet/burn_closet = burn_obj
for(var/burn_content in burn_closet.contents)
burn_stuff(burn_content)
return
var/mob/living/burn_living = burn_target
burn_living.update_fire()

View File

@@ -50,15 +50,12 @@
"lockdown" = borg.locked_down,
"scrambledcodes" = borg.scrambledcodes
)
.["upgrades"] = list()
for (var/upgradetype in subtypesof(/obj/item/borg/upgrade)-/obj/item/borg/upgrade/hypospray) //hypospray is a dummy parent for hypospray upgrades
var/obj/item/borg/upgrade/upgrade = upgradetype
if (initial(upgrade.module_type) && !is_type_in_list(borg.module, initial(upgrade.module_type))) // Upgrade requires a different module
continue
var/installed = FALSE
if (locate(upgradetype) in borg)
installed = TRUE
.["upgrades"] += list(list("name" = initial(upgrade.name), "installed" = installed, "type" = upgradetype))
var/obj/item/gun/energy/kinetic_accelerator/kinetic_accelerator = locate(/obj/item/gun/energy/kinetic_accelerator) in borg.module
if(kinetic_accelerator)
.["ka_remaining_capacity"] = kinetic_accelerator.get_remaining_mod_capacity()
.["active_upgrades"] = list()
for (var/obj/item/borg/upgrade/upgrade as anything in borg.upgrades) // put a non-upgrade here, i dare you.
.["active_upgrades"] += list(list("type" = upgrade.type))
.["laws"] = borg.laws ? borg.laws.get_law_list(include_zeroth = TRUE, render_html = FALSE) : list()
.["channels"] = list()
for (var/k in GLOB.radiochannels)
@@ -77,6 +74,28 @@
for(var/mob/living/silicon/ai/ai in GLOB.ai_list)
.["ais"] += list(list("name" = ai.name, "ref" = REF(ai), "connected" = (borg.connected_ai == ai)))
/datum/borgpanel/ui_static_data(mob/user)
. = ..()
.["upgrades"] = list()
for(var/obj/item/borg/upgrade/upgrade as anything in GLOB.borg_upgrades)
if(upgrade.type == upgrade.abstract_type)
continue
var/obj/item/borg/upgrade/modkit/modkit
if(istype(upgrade, /obj/item/borg/upgrade/modkit))
modkit = upgrade
if(modkit.minebot_exclusive)
continue
modkit = upgrade
.["upgrades"] += list(
list(
"name" = upgrade.name,
"type" = upgrade.type,
"module_type" = upgrade.module_type,
"maximum_of_type" = modkit ? modkit.maximum_of_type : null,
"denied_type" = modkit ? modkit.denied_type : null,
"cost" = modkit ? modkit.cost : null
)
)
/datum/borgpanel/ui_act(action, params)
if(..())
@@ -148,17 +167,31 @@
var/upgradepath = text2path(params["upgrade"])
var/obj/item/borg/upgrade/installedupgrade = locate(upgradepath) in borg
if (installedupgrade)
installedupgrade.deactivate(borg, user)
borg.upgrades -= installedupgrade
qdel(installedupgrade)
message_admins("[key_name_admin(user)] removed the [installedupgrade] upgrade from [ADMIN_LOOKUPFLW(borg)].")
log_admin("[key_name(user)] removed the [installedupgrade] upgrade from [key_name(borg)].")
qdel(installedupgrade)
else
var/obj/item/borg/upgrade/upgrade = new upgradepath(borg)
upgrade.action(borg, user)
borg.upgrades += upgrade
var/obj/item/borg/upgrade/upgrade = new upgradepath()
if(!borg.apply_upgrade(upgrade, user, TRUE))
to_chat(user, span_danger("Upgrade error."))
return
message_admins("[key_name_admin(user)] added the [upgrade] borg upgrade to [ADMIN_LOOKUPFLW(borg)].")
log_admin("[key_name(user)] added the [upgrade] borg upgrade to [key_name(borg)].")
if ("add_upgrade")
var/upgradepath = text2path(params["upgrade"])
var/obj/item/borg/upgrade/upgrade = new upgradepath()
if(!borg.apply_upgrade(upgrade, user, TRUE))
to_chat(user, span_danger("Upgrade error."))
return
message_admins("[key_name_admin(user)] added the [upgrade] borg upgrade to [ADMIN_LOOKUPFLW(borg)].")
log_admin("[key_name(user)] added the [upgrade] borg upgrade to [key_name(borg)].")
if ("remove_upgrade")
var/upgradepath = text2path(params["upgrade"])
var/obj/item/borg/upgrade/installedupgrade = locate(upgradepath) in borg
if (installedupgrade)
qdel(installedupgrade)
message_admins("[key_name_admin(user)] removed the [installedupgrade] upgrade from [ADMIN_LOOKUPFLW(borg)].")
log_admin("[key_name(user)] removed the [installedupgrade] upgrade from [key_name(borg)].")
if ("toggle_radio")
var/channel = params["channel"]
if (channel in borg.radio.channels) // We're removing a channel
@@ -236,3 +269,10 @@
message_admins("[key_name_admin(usr)] added [chosenboard] to [ADMIN_LOOKUPFLW(beepboop)].")
log_admin("[key_name(usr)] added [chosenboard] to [key_name(beepboop)].")
qdel(new_board)
GLOBAL_LIST_INIT(borg_upgrades, populate_borg_upgrades())
/proc/populate_borg_upgrades()
. = list()
for(var/type in typesof(/obj/item/borg/upgrade))
. += new type

View File

@@ -82,8 +82,7 @@
Field repairs can be done with a welder."
if(stored_gun && stored_gun.max_mod_capacity)
. += "<b>[stored_gun.get_remaining_mod_capacity()]%</b> mod capacity remaining."
for(var/A in stored_gun.get_modkits())
var/obj/item/borg/upgrade/modkit/M = A
for(var/obj/item/borg/upgrade/modkit/M in stored_gun.modkits)
. += "<span class='notice'>There is \a [M] installed, using <b>[M.cost]%</b> capacity.</span>"
/mob/living/simple_animal/hostile/mining_drone/welder_act(mob/living/user, obj/item/I)
@@ -136,8 +135,7 @@
if(istype(O, /obj/item/projectile/kinetic))
var/obj/item/projectile/kinetic/K = O
if(K.kinetic_gun)
for(var/A in K.kinetic_gun.get_modkits())
var/obj/item/borg/upgrade/modkit/M = A
for(var/obj/item/borg/upgrade/modkit/M in K.kinetic_gun.modkits)
if(istype(M, /obj/item/borg/upgrade/modkit/minebot_passthrough))
return TRUE
if(istype(O, /obj/item/projectile/destabilizer))

View File

@@ -28,11 +28,13 @@
inv2 = new /atom/movable/screen/robot/module2()
inv3 = new /atom/movable/screen/robot/module3()
ident = rand(1, 999)
if(!shell)
aiPDA = new/obj/item/pda/ai(src)
aiPDA.owner = real_name
aiPDA.ownjob = "Cyborg"
aiPDA.name = real_name + " (" + aiPDA.ownjob + ")"
aiPDA.name = real_name + " ([aiPDA.ownjob])"
previous_health = health
@@ -59,26 +61,29 @@
update_icons()
. = ..()
//If this body is meant to be a borg controlled by the AI player
//If this body is meant to be a borg controlled by the AI player
if(shell)
make_shell()
var/obj/item/borg/upgrade/ai/board = new(src)
make_shell(board)
add_to_upgrades(board)
else
//MMI stuff. Held togheter by magic. ~Miauw
else if(!mmi || !mmi.brainmob)
if(!mmi?.brainmob)
mmi = new (src)
mmi.brain = new /obj/item/organ/brain(mmi)
mmi.brain.organ_flags |= ORGAN_FROZEN
mmi.brain.name = "[real_name]'s brain"
mmi.icon_state = "mmi_full"
mmi.name = "Man-Machine Interface: [real_name]"
mmi.name = "[initial(mmi.name)]: [real_name]"
mmi.brainmob = new(mmi)
mmi.brainmob.name = src.real_name
mmi.brainmob.real_name = src.real_name
mmi.brainmob.container = mmi
mmi.update_appearance()
INVOKE_ASYNC(src, .proc/updatename)
playsound(loc, 'sound/voice/liveagain.ogg', 75, TRUE)
aicamera = new/obj/item/camera/siliconcam/robot_camera(src)
toner = tonermax
diag_hud_set_borgcell()
@@ -330,193 +335,144 @@
return FALSE
return ISINRANGE(T1.x, T0.x - interaction_range, T0.x + interaction_range) && ISINRANGE(T1.y, T0.y - interaction_range, T0.y + interaction_range)
/mob/living/silicon/robot/proc/attempt_welder_repair(obj/item/W, mob/user)
if(!W.tool_behaviour == TOOL_WELDER)
return
if(!getBruteLoss())
to_chat(user, "<span class='warning'>[src] is already in good condition!</span>")
return
if(!W.tool_start_check(user, amount=0)) //The welder has 1u of fuel consumed by it's afterattack, so we don't need to worry about taking any away.
return
/mob/living/silicon/robot/attackby(obj/item/W, mob/user, params)
if(istype(W, /obj/item/stack/cable_coil) && wiresexposed)
user.DelayNextAction(CLICK_CD_MELEE)
if(src == user)
to_chat(user, "<span class='notice'>You start fixing yourself...</span>")
if(!W.use_tool(src, user, 50))
return
adjustBruteLoss(-10)
else
to_chat(user, "<span class='notice'>You start fixing [src]...</span>")
if(!do_after(user, 30, target = src))
return
adjustBruteLoss(-30)
updatehealth()
add_fingerprint(user)
visible_message("<span class='notice'>[user] has fixed some of the dents on [src].</span>")
/mob/living/silicon/robot/proc/attempt_cable_repair(obj/item/stack/cable_coil/W, mob/user)
if (getFireLoss() > 0 || getToxLoss() > 0)
user.DelayNextAction(CLICK_CD_MELEE)
if(src == user)
to_chat(user, "<span class='notice'>You start fixing yourself...</span>")
if(!W.use_tool(src, user, 50, 1, skill_gain_mult = TRIVIAL_USE_TOOL_MULT))
to_chat(user, "<span class='warning'>You need more cable to repair [src]!</span>")
to_chat(user, span_notice("You start fixing yourself..."))
if(!W.use_tool(src, user, 5 SECONDS, 1, skill_gain_mult = TRIVIAL_USE_TOOL_MULT))
to_chat(user, span_warning("You need more cable to repair [src]!"))
return
adjustFireLoss(-10)
adjustToxLoss(-10)
else
to_chat(user, "<span class='notice'>You start fixing [src]...</span>")
if(!W.use_tool(src, user, 30, 1))
to_chat(user, "<span class='warning'>You need more cable to repair [src]!</span>")
return
to_chat(user, span_notice("You start fixing [src]..."))
if(!W.use_tool(src, user, 3 SECONDS, 1))
to_chat(user, span_warning("You need more cable to repair [src]!"))
adjustFireLoss(-30)
adjustToxLoss(-30)
updatehealth()
user.visible_message("[user] has fixed some of the burnt wires on [src].", "<span class='notice'>You fix some of the burnt wires on [src].</span>")
user.visible_message(span_notice("[user] has fixed some of the burnt wires on [src]."), span_notice("You fix some of the burnt wires on [src]."))
else
to_chat(user, "The wires seem fine, there's no need to fix them.")
/mob/living/silicon/robot/attackby(obj/item/W, mob/user, params)
if(W.tool_behaviour == TOOL_WELDER && (user.a_intent != INTENT_HARM || user == src))
INVOKE_ASYNC(src, .proc/attempt_welder_repair, W, user)
to_chat(user, span_warning("The wires seem fine, there's no need to fix them."))
return
else if(istype(W, /obj/item/stack/cable_coil) && wiresexposed)
INVOKE_ASYNC(src, .proc/attempt_cable_repair, W, user)
return
else if(W.tool_behaviour == TOOL_CROWBAR) // crowbar means open or close the cover
if(opened)
to_chat(user, "<span class='notice'>You close the cover.</span>")
opened = 0
update_icons()
else
if(locked)
to_chat(user, "<span class='warning'>The cover is locked and cannot be opened!</span>")
else
to_chat(user, "<span class='notice'>You open the cover.</span>")
opened = 1
update_icons()
else if(istype(W, /obj/item/stock_parts/cell) && opened) // trying to put a cell inside
if(istype(W, /obj/item/stock_parts/cell) && opened) // trying to put a cell inside
if(wiresexposed)
to_chat(user, "<span class='warning'>Close the cover first!</span>")
to_chat(user, span_warning("Close the cover first!"))
else if(cell)
to_chat(user, "<span class='warning'>There is a power cell already installed!</span>")
to_chat(user, span_warning("There is a power cell already installed!"))
else
if(!user.transferItemToLoc(W, src))
return
cell = W
to_chat(user, "<span class='notice'>You insert the power cell.</span>")
to_chat(user, span_notice("You insert the power cell."))
update_icons()
diag_hud_set_borgcell()
return
else if(is_wire_tool(W))
if(is_wire_tool(W))
if (wiresexposed)
wires.interact(user)
else
to_chat(user, "<span class='warning'>You can't reach the wiring!</span>")
else if(W.tool_behaviour == TOOL_SCREWDRIVER && opened && !cell) // haxing
wiresexposed = !wiresexposed
to_chat(user, "The wires have been [wiresexposed ? "exposed" : "unexposed"]")
update_icons()
else if((W.tool_behaviour == TOOL_SCREWDRIVER) && opened && cell) // radio
if(shell)
to_chat(user, "You cannot seem to open the radio compartment") //Prevent AI radio key theft
else if(radio)
radio.attackby(W,user)//Push it to the radio to let it handle everything
else
to_chat(user, "<span class='warning'>Unable to locate a radio!</span>")
update_icons()
else if(W.tool_behaviour == TOOL_WRENCH && opened && !cell) //Deconstruction. The flashes break from the fall, to prevent this from being a ghetto reset module.
if(!locked_down)
to_chat(user, "<span class='boldannounce'>[src]'s bolts spark! Maybe you should lock them down first!</span>")
spark_system.start()
to_chat(user, span_warning("You can't reach the wiring!"))
return
else
to_chat(user, "<span class='notice'>You start to unfasten [src]'s securing bolts...</span>")
if(W.use_tool(src, user, 50, volume=50) && !cell)
user.visible_message("[user] deconstructs [src]!", "<span class='notice'>You unfasten the securing bolts, and [src] falls to pieces!</span>")
deconstruct()
else if(istype(W, /obj/item/aiModule))
if(istype(W, /obj/item/aiModule))
var/obj/item/aiModule/MOD = W
if(!opened)
to_chat(user, "<span class='warning'>You need access to the robot's insides to do that!</span>")
to_chat(user, span_warning("You need access to the robot's insides to do that!"))
return
if(wiresexposed)
to_chat(user, "<span class='warning'>You need to close the wire panel to do that!</span>")
to_chat(user, span_warning("You need to close the wire panel to do that!"))
return
if(!cell)
to_chat(user, "<span class='warning'>You need to install a power cell to do that!</span>")
to_chat(user, span_warning("You need to install a power cell to do that!"))
return
if(shell) //AI shells always have the laws of the AI
to_chat(user, "<span class='warning'>[src] is controlled remotely! You cannot upload new laws this way!</span>")
to_chat(user, span_warning("[src] is controlled remotely! You cannot upload new laws this way!"))
return
if(emagged || (connected_ai && lawupdate)) //Can't be sure which, metagamers
emote("buzz-[user.name]")
if(connected_ai && lawupdate)
to_chat(user, span_warning("[src] is receiving laws remotely from a synced AI!"))
return
if(emagged)
to_chat(user, span_warning("The law interface glitches out!"))
emote("buzz")
return
if(!mind) //A player mind is required for law procs to run antag checks.
to_chat(user, "<span class='warning'>[src] is entirely unresponsive!</span>")
to_chat(user, span_warning("[src] is entirely unresponsive!"))
return
MOD.install(laws, user) //Proc includes a success mesage so we don't need another one
return
else if(istype(W, /obj/item/encryptionkey/) && opened)
if(istype(W, /obj/item/encryptionkey) && opened)
if(radio)//sanityyyyyy
radio.attackby(W,user)//GTFO, you have your own procs
else
to_chat(user, "<span class='warning'>Unable to locate a radio!</span>")
to_chat(user, span_warning("Unable to locate a radio!"))
return
else if (istype(W, /obj/item/card/id)||istype(W, /obj/item/pda)) // trying to unlock the interface with an ID card
if(emagged)//still allow them to open the cover
to_chat(user, "<span class='notice'>The interface seems slightly damaged.</span>")
if (W.GetID()) // trying to unlock the interface with an ID card
if(opened)
to_chat(user, "<span class='warning'>You must close the cover to swipe an ID card!</span>")
to_chat(user, span_warning("You must close the cover to swipe an ID card!"))
else
if(allowed(usr))
locked = !locked
to_chat(user, "<span class='notice'>You [ locked ? "lock" : "unlock"] [src]'s cover.</span>")
to_chat(user, span_notice("You [ locked ? "lock" : "unlock"] [src]'s cover."))
update_icons()
if(emagged)
to_chat(user, span_notice("The cover interface glitches out for a split second."))
logevent("ChÃ¥vÃis cover lock has been [locked ? "engaged" : "released"]") //ChÃ¥vÃis: see above line
else
to_chat(user, "<span class='danger'>Access denied.</span>")
logevent("Chassis cover lock has been [locked ? "engaged" : "released"]")
else
to_chat(user, span_danger("Access denied."))
return
else if(istype(W, /obj/item/borg/upgrade/))
if(istype(W, /obj/item/borg/upgrade))
var/obj/item/borg/upgrade/U = W
if(!opened)
to_chat(user, "<span class='warning'>You must access the borg's internals!</span>")
else if(!src.module && U.require_module)
to_chat(user, "<span class='warning'>The borg must choose a module before it can be upgraded!</span>")
else if(U.locked)
to_chat(user, "<span class='warning'>The upgrade is locked and cannot be used yet!</span>")
else
if(!user.temporarilyRemoveItemFromInventory(U))
to_chat(user, span_warning("You must access the cyborg's internals!"))
return
if(!module && U.require_module)
to_chat(user, span_warning("The cyborg must choose a model before it can be upgraded!"))
return
if(U.locked)
to_chat(user, span_warning("The upgrade is locked and cannot be used yet!"))
return
if(!user.canUnEquip(U))
to_chat(user, span_warning("The upgrade is stuck to you and you can't seem to let go of it!"))
return
apply_upgrade(U, user)
return
if(U.action(src))
to_chat(user, "<span class='notice'>You apply the upgrade to [src].</span>")
if(U.one_use)
U.afterInstall(src)
qdel(U)
else
U.forceMove(src)
upgrades += U
U.afterInstall(src)
else
to_chat(user, "<span class='danger'>Upgrade error.</span>")
U.forceMove(drop_location())
else if(istype(W, /obj/item/toner))
if(istype(W, /obj/item/toner))
if(toner >= tonermax)
to_chat(user, "<span class='warning'>The toner level of [src] is at its highest level possible!</span>")
else
to_chat(user, span_warning("The toner level of [src] is at its highest level possible!"))
return
if(!user.temporarilyRemoveItemFromInventory(W))
return
toner = tonermax
qdel(W)
to_chat(user, "<span class='notice'>You fill the toner level of [src] to its max capacity.</span>")
else
to_chat(user, span_notice("You fill the toner level of [src] to its max capacity."))
return
if(istype(W, /obj/item/flashlight))
if(!opened)
to_chat(user, span_warning("You need to open the panel to repair the headlamp!"))
return
if(lamp_functional)
to_chat(user, span_warning("The headlamp is already functional!"))
return
if(!user.temporarilyRemoveItemFromInventory(W))
to_chat(user, span_warning("[W] seems to be stuck to your hand. You'll have to find a different light."))
return
lamp_functional = TRUE
qdel(W)
to_chat(user, span_notice("You replace the headlamp bulbs."))
return
return ..()
/mob/living/silicon/robot/crowbar_act(mob/living/user, obj/item/I) //TODO: make fucking everything up there in that attackby() proc use the proper tool_act() procs. But honestly, who has time for that? 'cause I know for sure that you, the person reading this, sure as hell doesn't.
@@ -1064,33 +1020,49 @@
*Checking Exited() to detect if a hat gets up and walks off.
*Drones and pAIs might do this, after all.
*/
/mob/living/silicon/robot/Exited(atom/A)
if(hat && hat == A)
/mob/living/silicon/robot/Exited(atom/movable/gone)
. = ..()
if(hat == gone)
hat = null
if(!QDELETED(src)) //Don't update icons if we are deleted.
update_icons()
return ..()
///Use this to add upgrades to robots. It'll register signals for when the upgrade is moved or deleted, if not single use.
/mob/living/silicon/robot/proc/add_to_upgrades(obj/item/borg/upgrade/new_upgrade, mob/user)
if(gone == cell)
cell = null
if(gone == mmi)
mmi = null
///Called when a mob uses an upgrade on an open borg. Checks to make sure the upgrade can be applied
/mob/living/silicon/robot/proc/apply_upgrade(obj/item/borg/upgrade/new_upgrade, mob/user, admin_added)
if(!admin_added && isnull(user))
return FALSE
if(new_upgrade in upgrades)
return FALSE
if(!user.temporarilyRemoveItemFromInventory(new_upgrade)) //calling the upgrade's dropped() proc /before/ we add action buttons
if(!admin_added && !user.temporarilyRemoveItemFromInventory(new_upgrade)) //calling the upgrade's dropped() proc /before/ we add action buttons
return FALSE
if(!new_upgrade.action(src, user))
to_chat(user, "<span class='danger'>Upgrade error.</span>")
to_chat(user, span_danger("Upgrade error."))
if(admin_added)
qdel(new_upgrade)
else
new_upgrade.forceMove(loc) //gets lost otherwise
return FALSE
to_chat(user, "<span class='notice'>You apply the upgrade to [src].</span>")
to_chat(user, span_notice("You apply the upgrade to [src]."))
add_to_upgrades(new_upgrade)
return TRUE
///Moves the upgrade inside the robot and registers relevant signals.
/mob/living/silicon/robot/proc/add_to_upgrades(obj/item/borg/upgrade/new_upgrade)
to_chat(src, "----------------\nNew hardware detected...Identified as \"<b>[new_upgrade]</b>\"...Setup complete.\n----------------")
if(new_upgrade.one_use)
logevent("Firmware [new_upgrade] run successfully.")
qdel(new_upgrade)
return FALSE
return
upgrades += new_upgrade
new_upgrade.forceMove(src)
RegisterSignal(new_upgrade, COMSIG_MOVABLE_MOVED, .proc/remove_from_upgrades)
RegisterSignal(new_upgrade, COMSIG_PARENT_QDELETING, .proc/on_upgrade_deleted)
RegisterSignal(new_upgrade, COMSIG_MOVABLE_MOVED, PROC_REF(remove_from_upgrades))
RegisterSignal(new_upgrade, COMSIG_PARENT_QDELETING, PROC_REF(on_upgrade_deleted))
logevent("Hardware [new_upgrade] installed successfully.")
///Called when an upgrade is moved outside the robot. So don't call this directly, use forceMove etc.
@@ -1117,8 +1089,10 @@
* * board - B.O.R.I.S. module board used for transforming the cyborg into AI shell
*/
/mob/living/silicon/robot/proc/make_shell(obj/item/borg/upgrade/ai/board)
if(!board)
upgrades |= new /obj/item/borg/upgrade/ai(src)
if(isnull(board))
stack_trace("make_shell was called without a board argument! This is never supposed to happen!")
return FALSE
shell = TRUE
braintype = "AI Shell"
name = "Empty AI Shell-[ident]"

View File

@@ -94,6 +94,76 @@ GLOBAL_LIST_INIT(blacklisted_borg_hats, typecacheof(list( //Hats that don't real
apply_status_effect(/datum/status_effect/vtec_disabled, time)
update_movespeed()
/mob/living/silicon/robot/welder_act(mob/living/user, obj/item/tool)
if(user.a_intent == INTENT_HARM)
return FALSE
. = TRUE
if (!getBruteLoss())
to_chat(user, span_warning("[src] is already in good condition!"))
return
if (!tool.tool_start_check(user, amount=0)) //The welder has 1u of fuel consumed by it's afterattack, so we don't need to worry about taking any away.
return
user.DelayNextAction(CLICK_CD_MELEE)
if(src == user)
to_chat(user, span_notice("You start fixing yourself..."))
if(!tool.use_tool(src, user, 50))
return
adjustBruteLoss(-10)
else
to_chat(user, span_notice("You start fixing [src]..."))
if(!do_after(user, 3 SECONDS, target = src))
return
adjustBruteLoss(-30)
updatehealth()
add_fingerprint(user)
visible_message(span_notice("[user] has fixed some of the dents on [src]."))
/mob/living/silicon/robot/crowbar_act(mob/living/user, obj/item/tool)
. = TRUE
if(opened)
to_chat(user, span_notice("You close the cover."))
opened = FALSE
update_icons()
else
if(locked)
to_chat(user, span_warning("The cover is locked and cannot be opened!"))
else
to_chat(user, span_notice("You open the cover."))
opened = TRUE
update_icons()
return TRUE
/mob/living/silicon/robot/screwdriver_act(mob/living/user, obj/item/tool)
if(!opened)
return FALSE
. = TRUE
if(!cell) // haxing
wiresexposed = !wiresexposed
to_chat(user, span_notice("The wires have been [wiresexposed ? "exposed" : "unexposed"]."))
else // radio
if(shell)
to_chat(user, span_warning("You cannot seem to open the radio compartment!")) //Prevent AI radio key theft
else if(radio)
radio.screwdriver_act(user, tool) // Push it to the radio to let it handle everything
else
to_chat(user, span_warning("Unable to locate a radio!"))
update_icons()
/mob/living/silicon/robot/wrench_act(mob/living/user, obj/item/tool)
if(!(opened && !cell)) // Deconstruction. The flashes break from the fall, to prevent this from being a ghetto reset module.
return FALSE
. = TRUE
if(!locked_down)
to_chat(user, span_boldannounce("[src]'s bolts spark! Maybe you should lock them down first!"))
spark_system.start()
return
to_chat(user, span_notice("You start to unfasten [src]'s securing bolts..."))
if(tool.use_tool(src, user, 5 SECONDS, volume = 50) && !cell)
user.visible_message(span_notice("[user] deconstructs [src]!"), span_notice("You unfasten the securing bolts, and [src] falls to pieces!"))
deconstruct()
return
/mob/living/silicon/robot/fire_act()
if(!on_fire) //Silicons don't gain stacks from hotspots, but hotspots can ignite them
IgniteMob()

View File

@@ -57,25 +57,24 @@
. = ..()
if(max_mod_capacity)
. += "<b>[get_remaining_mod_capacity()]%</b> mod capacity remaining."
for(var/A in get_modkits())
var/obj/item/borg/upgrade/modkit/M = A
for(var/obj/item/borg/upgrade/modkit/M in modkits)
. += "<span class='notice'>There is \a [M] installed, using <b>[M.cost]%</b> capacity.</span>"
/obj/item/gun/energy/kinetic_accelerator/crowbar_act(mob/living/user, obj/item/I)
. = TRUE
if(modkits.len)
to_chat(user, "<span class='notice'>You pry the modifications out.</span>")
to_chat(user, span_notice("You pry all the modifications out."))
I.play_tool_sound(src, 100)
for(var/obj/item/borg/upgrade/modkit/M in modkits)
M.uninstall(src)
M.forceMove(drop_location()) //uninstallation handled in Exited(), or /mob/living/silicon/robot/remove_from_upgrades() for borgs
else
to_chat(user, "<span class='notice'>There are no modifications currently installed.</span>")
to_chat(user, span_notice("There are no modifications currently installed."))
/obj/item/gun/energy/kinetic_accelerator/Exited(atom/movable/AM)
. = ..()
if((AM in modkits) && istype(AM, /obj/item/borg/upgrade/modkit))
var/obj/item/borg/upgrade/modkit/M = AM
M.uninstall(src, FALSE)
/obj/item/gun/energy/kinetic_accelerator/Exited(atom/movable/gone)
if(gone in modkits)
var/obj/item/borg/upgrade/modkit/MK = gone
MK.uninstall(src)
return ..()
/obj/item/gun/energy/kinetic_accelerator/attackby(obj/item/I, mob/user)
if(istype(I, /obj/item/borg/upgrade/modkit))
@@ -86,20 +85,13 @@
/obj/item/gun/energy/kinetic_accelerator/proc/get_remaining_mod_capacity()
var/current_capacity_used = 0
for(var/A in get_modkits())
var/obj/item/borg/upgrade/modkit/M = A
for(var/obj/item/borg/upgrade/modkit/M in modkits)
current_capacity_used += M.cost
return max_mod_capacity - current_capacity_used
/obj/item/gun/energy/kinetic_accelerator/proc/get_modkits()
. = list()
for(var/A in modkits)
. += A
/obj/item/gun/energy/kinetic_accelerator/proc/modify_projectile(obj/item/projectile/kinetic/K)
K.kinetic_gun = src //do something special on-hit, easy!
for(var/A in get_modkits())
var/obj/item/borg/upgrade/modkit/M = A
for(var/obj/item/borg/upgrade/modkit/M in modkits)
M.modify_projectile(K)
/obj/item/gun/energy/kinetic_accelerator/cyborg
@@ -259,7 +251,7 @@
if(!target_turf)
target_turf = get_turf(src)
if(kinetic_gun) //hopefully whoever shot this was not very, very unfortunate.
var/list/mods = kinetic_gun.get_modkits()
var/list/mods = kinetic_gun.modkits
for(var/obj/item/borg/upgrade/modkit/M in mods)
M.projectile_strike_predamage(src, target_turf, target, kinetic_gun)
for(var/obj/item/borg/upgrade/modkit/M in mods)
@@ -278,7 +270,7 @@
icon = 'icons/obj/objects.dmi'
icon_state = "modkit"
w_class = WEIGHT_CLASS_SMALL
require_module = 1
require_module = TRUE
module_type = list(/obj/item/robot_module/miner)
module_flags = BORG_MODULE_MINER
var/denied_type = null
@@ -298,26 +290,24 @@
else
..()
/obj/item/borg/upgrade/modkit/afterInstall(mob/living/silicon/robot/R)
/obj/item/borg/upgrade/modkit/action(mob/living/silicon/robot/R)
. = ..()
if (.)
for(var/obj/item/gun/energy/kinetic_accelerator/H in R.module.modules)
if(install(H, R)) //It worked
return
to_chat(R, "<span class='alert'>Upgrade error - Aborting Kinetic Accelerator linking.</span>") //No applicable KA found, insufficient capacity, or some other problem.
return install(H, usr, FALSE)
/obj/item/borg/upgrade/modkit/proc/install(obj/item/gun/energy/kinetic_accelerator/KA, mob/user)
/obj/item/borg/upgrade/modkit/proc/install(obj/item/gun/energy/kinetic_accelerator/KA, mob/user, transfer_to_loc = TRUE)
. = TRUE
if(src in KA.modkits) // Sanity check to prevent installing the same modkit twice thanks to occasional click/lag delays.
return FALSE
if(minebot_upgrade)
if(minebot_exclusive && !istype(KA.loc, /mob/living/simple_animal/hostile/mining_drone))
to_chat(user, "<span class='notice'>The modkit you're trying to install is only rated for minebot use.</span>")
to_chat(user, span_notice("The modkit you're trying to install is only rated for minebot use."))
return FALSE
else if(istype(KA.loc, /mob/living/simple_animal/hostile/mining_drone))
to_chat(user, "<span class='notice'>The modkit you're trying to install is not rated for minebot use.</span>")
to_chat(user, span_notice("The modkit you're trying to install is not rated for minebot use."))
return FALSE
if(denied_type)
var/number_of_denied = 0
for(var/A in KA.get_modkits())
for(var/A in KA.modkits)
var/obj/item/borg/upgrade/modkit/M = A
if(istype(M, denied_type))
number_of_denied++
@@ -326,21 +316,25 @@
break
if(KA.get_remaining_mod_capacity() >= cost)
if(.)
if(!user.transferItemToLoc(src, KA))
return FALSE
to_chat(user, "<span class='notice'>You install the modkit.</span>")
playsound(loc, 'sound/items/screwdriver.ogg', 100, 1)
if(transfer_to_loc && !user.transferItemToLoc(src, KA))
return
to_chat(user, span_notice("You install the modkit."))
playsound(loc, 'sound/items/screwdriver.ogg', 100, TRUE)
KA.modkits += src
else
to_chat(user, "<span class='notice'>The modkit you're trying to install would conflict with an already installed modkit. Use a crowbar to remove existing modkits.</span>")
to_chat(user, span_notice("The modkit you're trying to install would conflict with an already installed modkit. Use a crowbar to remove existing modkits."))
else
to_chat(user, "<span class='notice'>You don't have room(<b>[KA.get_remaining_mod_capacity()]%</b> remaining, [cost]% needed) to install this modkit. Use a crowbar to remove existing modkits.</span>")
to_chat(user, span_notice("You don't have room(<b>[KA.get_remaining_mod_capacity()]%</b> remaining, [cost]% needed) to install this modkit. Use a crowbar to remove existing modkits."))
. = FALSE
/obj/item/borg/upgrade/modkit/proc/uninstall(obj/item/gun/energy/kinetic_accelerator/KA, forcemove = TRUE)
/obj/item/borg/upgrade/modkit/deactivate(mob/living/silicon/robot/R, user = usr)
. = ..()
if (.)
for(var/obj/item/gun/energy/kinetic_accelerator/KA in R.module.modules)
uninstall(KA)
/obj/item/borg/upgrade/modkit/proc/uninstall(obj/item/gun/energy/kinetic_accelerator/KA)
KA.modkits -= src
if(forcemove)
forceMove(get_turf(KA))
/obj/item/borg/upgrade/modkit/proc/modify_projectile(obj/item/projectile/kinetic/K)
@@ -467,6 +461,7 @@
/obj/item/borg/upgrade/modkit/minebot_passthrough
name = "minebot passthrough"
desc = "Causes kinetic accelerator shots to pass through minebots."
denied_type = /obj/item/borg/upgrade/modkit/minebot_passthrough // If you have something cost zero, you can keep adding forever, why
cost = 0
//Tendril-unique modules

View File

@@ -1,5 +1,5 @@
import { useBackend } from '../backend';
import { Box, Button, LabeledList, ProgressBar, Section } from '../components';
import { Box, Button, Icon, LabeledList, ProgressBar, Section } from '../components';
import { Window } from '../layouts';
export const BorgPanel = (props, context) => {
@@ -12,6 +12,9 @@ export const BorgPanel = (props, context) => {
const upgrades = data.upgrades || [];
const ais = data.ais || [];
const laws = data.laws || [];
const active_upgrades = data.active_upgrades || [];
const ka_remaining_capacity = data.ka_remaining_capacity || 0;
return (
<Window
title="Borg Panel"
@@ -97,17 +100,63 @@ export const BorgPanel = (props, context) => {
))}
</LabeledList.Item>
<LabeledList.Item label="Upgrades">
{upgrades.map(upgrade => (
{upgrades.map(upgrade => {
if (!upgrade.module_type
|| (upgrade.module_type.includes(borg.active_module))) {
const installedCount
= active_upgrades.filter(installed_upgrade =>
installed_upgrade.type === upgrade.type).length;
const isInstalled = installedCount > 0;
return (
<>
<Button
key={upgrade.type}
icon={upgrade.installed ? 'check-square-o' : 'square-o'}
content={upgrade.name}
selected={upgrade.installed}
icon={isInstalled ? 'check-square-o' : 'square-o'}
content={isInstalled ? `${upgrade.name} ${installedCount
&& (!upgrade.denied_type || upgrade.maximum_of_type > 1)
&& upgrade.cost
!== null ? `(${installedCount} installed)` : ''}`
: upgrade.name}
selected={isInstalled}
onClick={() => act('toggle_upgrade', {
upgrade: upgrade.type,
})} />
))}
{
(!upgrade.denied_type || upgrade.maximum_of_type > 1)
&& upgrade.cost !== null
? (
<>
<Button
content={<Icon name="plus" />}
disabled={ka_remaining_capacity < upgrade.cost
|| (upgrade.denied_type
&& (installedCount === upgrade.maximum_of_type))}
onClick={() => act('add_upgrade', {
upgrade: upgrade.type,
})}
/>
<Button
content={<Icon name="minus" />}
disabled={!isInstalled}
onClick={() => act('remove_upgrade', {
upgrade: upgrade.type,
})}
/>
</>
) : ""
}
</>
);
} })}
</LabeledList.Item>
{
ka_remaining_capacity !== null
&& (
<LabeledList.Item label="Remaining ka capacity">
{ka_remaining_capacity}
</LabeledList.Item>
)
}
<LabeledList.Item label="Master AI">
{ais.map(ai => (
<Button

View File

@@ -213,13 +213,16 @@ export const NtosRobotactContent = (props, context) => {
)}
{tab_sub === 2 && (
<Section>
{borgUpgrades.map(upgrade => (
<Box
mb={1}
key={upgrade}>
{upgrade}
{borgUpgrades.filter((upgrade, index, arr) =>
arr.indexOf(upgrade) === index).map(upgrade => {
const upgradeCount = borgUpgrades.filter(u =>
u === upgrade).length;
return (
<Box mb={1} key={upgrade}>
{upgrade} {upgradeCount > 1 ? `x${upgradeCount}` : ''}
</Box>
))}
);
})}
</Section>
)}
{tab_sub === 3 && (