Robot_module and cyborg stack refactor (#13527)

* robot_module refactor

* some fixes

1. adds medical stacks of 25 for the syndi medical borg
2. fixes various construction steps that weren't using `use()` or `get_amount()`

* review tweaks + other stuff

1. Makes a bunch of for loops into istypeless loops
2. Adds a readout of the current out of stacks a borg has, in the status panel
3. Slightly reorganizes the medical, syndi medical, engineering and syndi engineering cyborgs items

* fixes after upstream merge

* blank line for travis

* fixes and improvements

1. Fixed welder icon's not updating periodically if you were charging in a borg recharger
2. Fixes solar panels dropping /cyborg type glass when they were deconstructed.
3. Band-aid fix (incase #2 doesn't fix this) for cyborg stack's `source` var being null which resulted in tons of "cannot read null.energy" runtimes

* more fixes + constructable frame runtime fix

* removes toy sword placeholder

remove comment

* remove these as well

* .amount to .get_amount(), really should have done this before

* refactors robot_upgrades to work with the new system

- more cleanup
- adds documentation
- fixed a bug I made where you could delete your robot stack via crafting

* moves some unemag logic to the module file, makes more loops typless

* farie review

* fox review

* affected review and more TM bugfixes

* fixes comment

Co-authored-by: SteelSlayer <SteelSlayer@users.noreply.github.com>
This commit is contained in:
SteelSlayer
2021-05-24 16:24:25 +01:00
committed by GitHub
co-authored by SteelSlayer
parent 663eff7b5e
commit e4bbd94d6a
46 changed files with 1057 additions and 914 deletions
+1 -1
View File
@@ -2810,7 +2810,7 @@
if(R.module)
R.module.modules += I
I.loc = R.module
R.module.rebuild()
R.module.rebuild_modules()
R.activate_module(I)
R.module.fix_modules()
@@ -961,15 +961,13 @@
if(1)
if(iscoil(I))
var/obj/item/stack/cable_coil/coil = I
if(coil.amount < 5)
if(coil.get_amount() < 5)
to_chat(user, "You need more cable for this!")
return
to_chat(user, "You wire \the [src]!")
playsound(get_turf(src), coil.usesound, 50, 1)
coil.amount -= 5
if(!coil.amount)
qdel(coil)
coil.use(5)
buildstage = 2
update_icon()
+1 -1
View File
@@ -245,7 +245,7 @@
var/obj/item/stack/SD
while(amt > 0)
S = locate(A) in surroundings
if(S.amount >= amt)
if(S.get_amount() >= amt)
if(!locate(S.type) in Deletion)
SD = new S.type()
Deletion += SD
@@ -114,6 +114,9 @@
icon_state = "enzyme"
list_reagents = list("enzyme" = 50)
/obj/item/reagent_containers/food/condiment/enzyme/cyborg_recharge(coeff, emagged)
reagents.check_and_add("enzyme", volume, 2 * coeff) // Only recharge if the current amount of enzyme is under `volume`.
/obj/item/reagent_containers/food/condiment/sugar
name = "sugar bottle"
desc = "Tasty spacey sugar!"
@@ -115,7 +115,7 @@
return 1
if(istype(O,/obj/item/stack))
var/obj/item/stack/S = O
if(S.amount > 1)
if(S.get_amount() > 1)
var/obj/item/stack/to_add = S.split(user, 1)
to_add.forceMove(src)
user.visible_message("<span class='notice'>[user] adds one of [S] to [src].</span>", "<span class='notice'>You add one of [S] to [src].</span>")
@@ -307,7 +307,7 @@
return FALSE
if(istype(I, /obj/item/stack))
var/obj/item/stack/S = I
if(S.amount == 0)
if(!S.get_amount())
qdel(I)
return FALSE
if(put_in_active_hand(I))
@@ -179,62 +179,6 @@
to_chat(user, "<span class='warning'>Nothing on \the [T] is useful to you.</span>")
return
//PRETTIER TOOL LIST.
/mob/living/silicon/robot/drone/installed_modules()
if(weapon_lock)
to_chat(src, "<span class='warning'>Weapon lock active, unable to use modules! Count:[weaponlock_time]</span>")
return
if(!module)
module = new /obj/item/robot_module/drone(src)
var/dat = "<HEAD><TITLE>Drone modules</TITLE><META HTTP-EQUIV='Refresh' CONTENT='10'></HEAD><BODY>\n"
dat += {"<A HREF='?src=[UID()];mach_close=robotmod'>Close</A>
<BR>
<BR>
<B>Activated Modules</B>
<BR>
Module 1: [module_state_1 ? "<A HREF=?src=[UID()];mod=\ref[module_state_1]>[module_state_1]<A>" : "No Module"]<BR>
Module 2: [module_state_2 ? "<A HREF=?src=[UID()];mod=\ref[module_state_2]>[module_state_2]<A>" : "No Module"]<BR>
Module 3: [module_state_3 ? "<A HREF=?src=[UID()];mod=\ref[module_state_3]>[module_state_3]<A>" : "No Module"]<BR>
<BR>
<B>Installed Modules</B><BR><BR>"}
var/tools = "<B>Tools and devices</B><BR>"
var/resources = "<BR><B>Resources</B><BR>"
for(var/O in module.modules)
var/module_string = ""
if(!O)
module_string += text("<B>Resource depleted</B><BR>")
else if(activated(O))
module_string += text("[O]: <B>Activated</B><BR>")
else
module_string += text("[O]: <A HREF=?src=[UID()];act=\ref[O]>Activate</A><BR>")
if((istype(O,/obj/item) || istype(O,/obj/item)) && !(istype(O,/obj/item/stack/cable_coil)))
tools += module_string
else
resources += module_string
dat += tools
if(emagged)
if(!module.emag)
dat += text("<B>Resource depleted</B><BR>")
else if(activated(module.emag))
dat += text("[module.emag]: <B>Activated</B><BR>")
else
dat += text("[module.emag]: <A HREF=?src=[UID()];act=\ref[module.emag]>Activate</A><BR>")
dat += resources
src << browse(dat, "window=robotmod&can_close=0")
//Putting the decompiler here to avoid doing list checks every tick.
/mob/living/silicon/robot/drone/use_power()
@@ -40,7 +40,7 @@
return 1
/mob/living/silicon/robot/proc/activate_module(obj/item/O)
if(!(locate(O) in src.module.modules) && O != src.module.emag)
if(!(locate(O) in module.modules) && !(O in module.emag_modules))
return
if(activated(O))
to_chat(src, "Already activated")
+38 -72
View File
@@ -482,6 +482,7 @@ GLOBAL_LIST_INIT(robot_verbs_default, list(
speed = 0 // Remove upgrades.
ionpulse = FALSE
magpulse = FALSE
weapons_unlock = FALSE
add_language("Robot Talk", TRUE)
if("lava" in weather_immunities) // Remove the lava-immunity effect given by a printable upgrade
weather_immunities -= "lava"
@@ -635,17 +636,27 @@ GLOBAL_LIST_INIT(robot_verbs_default, list(
else
stat(null, text("No Cell Inserted!"))
/mob/living/silicon/robot/proc/show_gps_coords()
if(locate(/obj/item/gps/cyborg) in module.modules)
var/turf/T = get_turf(src)
stat(null, "GPS: [COORD(T)]")
/mob/living/silicon/robot/proc/show_stack_energy()
for(var/storage in module.storages) // Storages should only contain `/datum/robot_energy_storage`
var/datum/robot_energy_storage/R = storage
stat(null, "[R.statpanel_name]: [R.energy] / [R.max_energy]")
// update the status screen display
/mob/living/silicon/robot/Stat()
..()
statpanel("Status")
if(client.statpanel == "Status")
show_cell_power()
var/total_user_contents = GetAllContents()
if(locate(/obj/item/gps/cyborg) in total_user_contents)
var/turf/T = get_turf(src)
stat(null, "GPS: [COORD(T)]")
if(!statpanel("Status"))
return // They aren't looking at the status panel.
show_cell_power()
if(module)
show_gps_coords()
show_stack_energy()
/mob/living/silicon/robot/restrained()
return 0
@@ -774,16 +785,12 @@ GLOBAL_LIST_INIT(robot_verbs_default, list(
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.drop_item())
return
if(U.action(src))
user.visible_message("<span class = 'notice'>[user] applied [U] to [src].</span>", "<span class='notice'>You apply [U] to [src].</span>")
user.visible_message("<span class='notice'>[user] applied [U] to [src].</span>", "<span class='notice'>You apply [U] to [src].</span>")
U.forceMove(src)
else
to_chat(user, "<span class='danger'>Upgrade error.</span>")
else if(istype(W, /obj/item/mmi_radio_upgrade))
if(!opened)
@@ -910,7 +917,19 @@ GLOBAL_LIST_INIT(robot_verbs_default, list(
spark_system.start()
..()
/mob/living/silicon/robot/emag_act(user as mob)
// Here so admins can unemag borgs.
/mob/living/silicon/robot/unemag()
SetEmagged(FALSE)
if(!module)
return
uneq_all()
module.module_type = initial(module.module_type)
update_module_icon()
module.unemag()
clear_supplied_laws()
laws = new /datum/ai_laws/crewsimov
/mob/living/silicon/robot/emag_act(mob/user)
if(!ishuman(user) && !issilicon(user))
return
var/mob/living/M = user
@@ -925,7 +944,8 @@ GLOBAL_LIST_INIT(robot_verbs_default, list(
return
if(opened)//Cover is open
if(emagged) return//Prevents the X has hit Y with Z message also you cant emag them twice
if(emagged)
return //Prevents the X has hit Y with Z message also you cant emag them twice
if(wiresexposed)
to_chat(user, "You must close the panel first")
return
@@ -933,11 +953,10 @@ GLOBAL_LIST_INIT(robot_verbs_default, list(
sleep(6)
SetEmagged(TRUE)
SetLockdown(1) //Borgs were getting into trouble because they would attack the emagger before the new laws were shown
if(src.hud_used)
src.hud_used.update_robot_modules_display() //Shows/hides the emag item if the inventory screen is already open.
if(hud_used)
hud_used.update_robot_modules_display() //Shows/hides the emag item if the inventory screen is already open.
disconnect_from_ai()
to_chat(user, "You emag [src]'s interface.")
// message_admins("[key_name_admin(user)] emagged cyborg [key_name_admin(src)]. Laws overridden.")
log_game("[key_name(user)] emagged cyborg [key_name(src)]. Laws overridden.")
clear_supplied_laws()
clear_inherent_laws()
@@ -963,17 +982,11 @@ GLOBAL_LIST_INIT(robot_verbs_default, list(
laws.show_laws(src)
to_chat(src, "<span class='boldwarning'>ALERT: [M.real_name] is your new master. Obey your new laws and [M.p_their()] commands.</span>")
SetLockdown(0)
if(src.module && istype(src.module, /obj/item/robot_module/miner))
for(var/obj/item/pickaxe/drill/cyborg/D in src.module.modules)
qdel(D)
src.module.modules += new /obj/item/pickaxe/drill/cyborg/diamond(src.module)
src.module.rebuild()
if(src.module && istype(src.module, /obj/item/robot_module/medical))
for(var/obj/item/borg_defib/F in src.module.modules)
F.safety = 0
if(module)
module.emag_act()
module.module_type = "Malf" // For the cool factor
update_module_icon()
module.rebuild_modules() // This will add the emagged items to the borgs inventory.
update_icons()
return
@@ -1041,51 +1054,6 @@ GLOBAL_LIST_INIT(robot_verbs_default, list(
/mob/living/silicon/robot/proc/borg_icons() // Exists so that robot/destroyer can override it
return
/mob/living/silicon/robot/proc/installed_modules()
if(weapon_lock)
to_chat(src, "<span class='warning'>Weapon lock active, unable to use modules! Count:[weaponlock_time]</span>")
return
if(!module)
pick_module()
return
var/dat = {"<A HREF='?src=[UID()];mach_close=robotmod'>Close</A>
<BR>
<BR>
<B>Activated Modules</B>
<BR>
<table border='0'>
<tr><td>Module 1:</td><td>[module_state_1 ? "<A HREF=?src=[UID()];mod=\ref[module_state_1]>[module_state_1]<A>" : "No Module"]</td></tr>
<tr><td>Module 2:</td><td>[module_state_2 ? "<A HREF=?src=[UID()];mod=\ref[module_state_2]>[module_state_2]<A>" : "No Module"]</td></tr>
<tr><td>Module 3:</td><td>[module_state_3 ? "<A HREF=?src=[UID()];mod=\ref[module_state_3]>[module_state_3]<A>" : "No Module"]</td></tr>
</table><BR>
<B>Installed Modules</B><BR><BR>
<table border='0'>"}
for(var/obj in module.modules)
if(!obj)
dat += text("<tr><td><B>Resource depleted</B></td></tr>")
else if(activated(obj))
dat += text("<tr><td>[obj]</td><td><B>Activated</B></td></tr>")
else
dat += text("<tr><td>[obj]</td><td><A HREF=?src=[UID()];act=\ref[obj]>Activate</A></td></tr>")
if(emagged || weapons_unlock)
if(activated(module.emag))
dat += text("<tr><td>[module.emag]</td><td><B>Activated</B></td></tr>")
else
dat += text("<tr><td>[module.emag]</td><td><A HREF=?src=[UID()];act=\ref[module.emag]>Activate</A></td></tr>")
dat += "</table>"
/*
if(activated(obj))
dat += text("[obj]: \[<B>Activated</B> | <A HREF=?src=[UID()];deact=\ref[obj]>Deactivate</A>\]<BR>")
else
dat += text("[obj]: \[<A HREF=?src=[UID()];act=\ref[obj]>Activate</A> | <B>Deactivated</B>\]<BR>")
*/
var/datum/browser/popup = new(src, "robotmod", "Modules")
popup.set_content(dat)
popup.open()
/mob/living/silicon/robot/Topic(href, href_list)
if(..())
return 1
@@ -1111,7 +1079,6 @@ GLOBAL_LIST_INIT(robot_verbs_default, list(
return 1
activate_module(O)
installed_modules()
//Show alerts window if user clicked on "Show alerts" in chat
if(href_list["showalerts"])
@@ -1134,7 +1101,6 @@ GLOBAL_LIST_INIT(robot_verbs_default, list(
to_chat(src, "Module isn't activated.")
else
to_chat(src, "Module isn't activated")
installed_modules()
return 1
return 1
File diff suppressed because it is too large Load Diff
+8 -4
View File
@@ -596,7 +596,7 @@ GLOBAL_LIST_INIT(cable_coil_recipes, list (new/datum/stack_recipe("cable restrai
/obj/item/stack/cable_coil/examine(mob/user)
. = ..()
if(in_range(user, src))
if(in_range(user, src) && !is_cyborg)
if(get_amount() == 1)
. += "A short piece of power cable."
else if(get_amount() == 2)
@@ -612,10 +612,10 @@ GLOBAL_LIST_INIT(cable_coil_recipes, list (new/datum/stack_recipe("cable restrai
if(istype(W, /obj/item/stack/cable_coil))
var/obj/item/stack/cable_coil/C = W
// Cable merging is handled by parent proc
if(C.amount >= MAXCOIL)
if(C.get_amount() >= MAXCOIL)
to_chat(user, "The coil is as long as it will get.")
return
if( (C.amount + src.amount <= MAXCOIL) )
if((C.get_amount() + get_amount() <= MAXCOIL))
to_chat(user, "You join the cable coils together.")
return
else
@@ -861,7 +861,11 @@ GLOBAL_LIST_INIT(cable_coil_recipes, list (new/datum/stack_recipe("cable restrai
return color
/obj/item/stack/cable_coil/cyborg
name = "cyborg cable coil"
energy_type = /datum/robot_energy_storage/cable
is_cyborg = TRUE
/obj/item/stack/cable_coil/cyborg/update_icon()
return // icon_state should always be a full cable
/obj/item/stack/cable_coil/cyborg/attack_self(mob/user)
var/cablecolor = input(user,"Pick a cable color.","Cable Color") in list("red","yellow","green","blue","pink","orange","cyan","white")
+1 -1
View File
@@ -149,7 +149,7 @@
return
var/obj/item/stack/cable_coil/C = I
if(C.amount < 10)
if(C.get_amount() < 10)
to_chat(user, "<span class='alert'>You need more wires.</span>")
return
+1 -1
View File
@@ -220,7 +220,7 @@
if(istype(W, /obj/item/stack/sheet/glass) || istype(W, /obj/item/stack/sheet/rglass))
var/obj/item/stack/sheet/S = W
if(S.use(2))
glass_type = W.type
glass_type = S.merge_type
playsound(loc, S.usesound, 50, 1)
user.visible_message("[user] places the glass on the solar assembly.", "<span class='notice'>You place the glass on the solar assembly.</span>")
if(tracker)
@@ -55,3 +55,12 @@
/obj/item/gun/energy/disabler/cyborg/newshot()
..()
robocharge()
/obj/item/gun/energy/disabler/cyborg/cyborg_recharge(coeff, emagged)
if(cell.charge < cell.maxcharge)
var/obj/item/ammo_casing/energy/E = ammo_type[select]
cell.give(E.e_cost * coeff)
on_recharge()
update_icon()
else
charge_tick = 0
@@ -131,6 +131,9 @@
volume = 50
list_reagents = list("cleaner" = 50)
/obj/item/reagent_containers/spray/cleaner/drone/cyborg_recharge(coeff, emagged)
reagents.check_and_add("cleaner", volume, 3 * coeff)
//spray tan
/obj/item/reagent_containers/spray/spraytan
name = "spray tan"