Merge pull request #1625 from CHOMPStationBot/upstream-merge-9955

[MIRROR] [MIRROR] Added think-tanks.
This commit is contained in:
Nadyr
2021-03-26 03:50:02 -04:00
committed by GitHub
34 changed files with 823 additions and 76 deletions

View File

@@ -77,6 +77,10 @@
external_type = /obj/item/robot_parts/robot_component/armour
max_damage = 90
/datum/robot_component/armour/platform
name = "platform armour plating"
external_type = /obj/item/robot_parts/robot_component/armour_platform
max_damage = 180
// ACTUATOR
// Enables movement.
@@ -243,6 +247,12 @@
icon_state = "armor"
icon_state_broken = "armor_broken"
/obj/item/robot_parts/robot_component/armour_platform
name = "platform armour plating"
icon_state = "armor"
icon_state_broken = "armor_broken"
color = COLOR_GRAY80
/obj/item/robot_parts/robot_component/camera
name = "camera"
icon_state = "camera"

View File

@@ -158,7 +158,6 @@
if(A?.no_spoilers)
disable_spoiler_vision()
if (src.stat == DEAD || (XRAY in mutations) || (src.sight_mode & BORGXRAY))
src.sight |= SEE_TURFS
src.sight |= SEE_MOBS
@@ -201,8 +200,10 @@
src.see_invisible = SEE_INVISIBLE_LIVING // This is normal vision (25), setting it lower for normal vision means you don't "see" things like darkness since darkness
// has a "invisible" value of 15
plane_holder.set_vis(VIS_FULLBRIGHT,fullbright)
plane_holder.set_vis(VIS_MESONS,seemeson)
if(plane_holder)
plane_holder.set_vis(VIS_FULLBRIGHT,fullbright)
plane_holder.set_vis(VIS_MESONS,seemeson)
..()
if (src.healths)

View File

@@ -98,7 +98,7 @@
/mob/living/silicon/robot/proc/robot_checklaws
)
/mob/living/silicon/robot/New(loc,var/unfinished = 0)
/mob/living/silicon/robot/New(loc, var/unfinished = 0)
spark_system = new /datum/effect/effect/system/spark_spread()
spark_system.set_up(5, 0, src)
spark_system.attach(src)
@@ -114,7 +114,7 @@
ident = rand(1, 999)
module_sprites["Basic"] = "robot"
icontype = "Basic"
updatename("Default")
updatename(modtype)
updateicon()
radio = new /obj/item/device/radio/borg(src)
@@ -142,6 +142,8 @@
cell = new /obj/item/weapon/cell(src)
cell.maxcharge = 7500
cell.charge = 7500
else if(ispath(cell))
cell = new cell(src)
..()
@@ -287,10 +289,7 @@
updatename()
notify_ai(ROBOT_NOTIFICATION_NEW_MODULE, module.name)
/mob/living/silicon/robot/proc/updatename(var/prefix as text)
if(prefix)
modtype = prefix
/mob/living/silicon/robot/proc/update_braintype()
if(istype(mmi, /obj/item/device/mmi/digital/posibrain))
braintype = BORG_BRAINTYPE_POSI
else if(istype(mmi, /obj/item/device/mmi/digital/robot))
@@ -300,6 +299,11 @@
else
braintype = BORG_BRAINTYPE_CYBORG
/mob/living/silicon/robot/proc/updatename(var/prefix as text)
if(prefix)
modtype = prefix
update_braintype()
var/changed_name = ""
if(custom_name)
@@ -1215,3 +1219,6 @@
if(current_selection_index) // Select what the player had before if possible.
select_module(current_selection_index)
/mob/living/silicon/robot/get_cell()
return cell

View File

@@ -3,7 +3,7 @@
// The module that borgs on the surface have. Generally has a lot of useful tools in exchange for questionable loyalty to the crew.
/obj/item/weapon/robot_module/robot/lost
name = "lost robot module"
hide_on_manifest = 1
hide_on_manifest = TRUE
sprites = list(
"Drone" = "drone-lost"
)
@@ -41,7 +41,7 @@
/obj/item/weapon/robot_module/robot/gravekeeper
name = "gravekeeper robot module"
hide_on_manifest = 1
hide_on_manifest = TRUE
sprites = list(
"Drone" = "drone-gravekeeper",
"Sleek" = "sleek-gravekeeper"

View File

@@ -18,7 +18,7 @@ var/global/list/robot_modules = list(
icon_state = "std_module"
w_class = ITEMSIZE_NO_CONTAINER
item_state = "std_mod"
var/hide_on_manifest = 0
var/hide_on_manifest = FALSE
var/channels = list()
var/networks = list()
var/languages = list(LANGUAGE_SOL_COMMON = 1, LANGUAGE_TRADEBAND = 1, LANGUAGE_UNATHI = 0, LANGUAGE_SIIK = 0, LANGUAGE_AKHANI = 0, LANGUAGE_SKRELLIAN = 0, LANGUAGE_GUTTER = 0, LANGUAGE_SCHECHI = 0, LANGUAGE_SIGN = 0, LANGUAGE_TERMINUS = 1, LANGUAGE_ZADDAT = 0)
@@ -37,6 +37,9 @@ var/global/list/robot_modules = list(
var/list/original_languages = list()
var/list/added_networks = list()
/obj/item/weapon/robot_module/proc/hide_on_manifest()
. = hide_on_manifest
/obj/item/weapon/robot_module/New(var/mob/living/silicon/robot/R)
..()
R.module = src
@@ -805,7 +808,7 @@ var/global/list/robot_modules = list(
/obj/item/weapon/robot_module/robot/security/combat
name = "combat robot module"
hide_on_manifest = 1
hide_on_manifest = TRUE
sprites = list(
"Haruka" = "marinaCB",
"Combat Android" = "droid-combat",
@@ -828,7 +831,7 @@ var/global/list/robot_modules = list(
/obj/item/weapon/robot_module/drone
name = "drone module"
hide_on_manifest = 1
hide_on_manifest = TRUE
no_slip = 1
networks = list(NETWORK_ENGINEERING)
@@ -912,7 +915,7 @@ var/global/list/robot_modules = list(
/obj/item/weapon/robot_module/drone/construction
name = "construction drone module"
hide_on_manifest = 1
hide_on_manifest = TRUE
channels = list("Engineering" = 1)
languages = list()

View File

@@ -2,7 +2,7 @@
/obj/item/weapon/robot_module/robot/syndicate
name = "illegal robot module"
hide_on_manifest = 1
hide_on_manifest = TRUE
languages = list(
LANGUAGE_SOL_COMMON = 1,
LANGUAGE_TRADEBAND = 1,

View File

@@ -0,0 +1,164 @@
// Spawner landmarks are used because platforms that are mapped during
// SSatoms init try to Initialize() twice. I have no idea why and I am
// not paid enough to spend more time trying to debug it.
/obj/effect/landmark/robot_platform
name = "recon platform spawner"
icon = 'icons/mob/screen1.dmi'
icon_state = "x3"
delete_me = TRUE
var/platform_type
/obj/effect/landmark/robot_platform/Initialize()
if(platform_type)
new platform_type(get_turf(src))
return ..()
/mob/living/silicon/robot/platform
name = "support platform"
desc = "A large quadrupedal AI platform, colloquially known as a 'think-tank' due to the flexible onboard intelligence."
icon = 'icons/mob/robots_thinktank.dmi'
icon_state = "tachi"
color = "#68a2f2"
speed = -1 // They're meant to be viable for transport, so can't be slower than a human.
cell = /obj/item/weapon/cell/mech
idcard_type = /obj/item/weapon/card/id/platform
module = /obj/item/weapon/robot_module/robot/platform
lawupdate = FALSE
modtype = "Standard"
speak_statement = "chirps"
mob_bump_flag = HEAVY
mob_swap_flags = ~HEAVY
mob_push_flags = HEAVY
mob_size = MOB_LARGE
var/const/platform_respawn_time = 3 MINUTES
var/tmp/last_recharge_state = FALSE
var/tmp/recharge_complete = FALSE
var/tmp/recharger_charge_amount = 10 KILOWATTS
var/tmp/recharger_tick_cost = 80 KILOWATTS
var/weakref/recharging
var/list/stored_atoms
var/max_stored_atoms = 1
var/static/list/can_store_types = list(
/mob/living,
/obj/item,
/obj/structure,
/obj/machinery
)
// Currently set to prevent tonks hauling a deliaminating SM into the middle of the station.
var/static/list/cannot_store_types = list(
/obj/machinery/power/supermatter
)
/mob/living/silicon/robot/platform/SetName(pickedName)
. = ..()
if(mind)
mind.name = real_name
/mob/living/silicon/robot/platform/Initialize(var/mapload)
. = ..()
if(!mmi)
mmi = new /obj/item/device/mmi/digital/robot(src)
SetName("inactive [initial(name)]")
updateicon()
// Copypasting from root proc to avoid calling ..() and accidentally creating duplicate armour etc.
/mob/living/silicon/robot/platform/initialize_components()
components["actuator"] = new /datum/robot_component/actuator(src)
components["radio"] = new /datum/robot_component/radio(src)
components["power cell"] = new /datum/robot_component/cell(src)
components["diagnosis unit"] = new /datum/robot_component/diagnosis_unit(src)
components["camera"] = new /datum/robot_component/camera(src)
components["comms"] = new /datum/robot_component/binary_communication(src)
components["armour"] = new /datum/robot_component/armour/platform(src)
/mob/living/silicon/robot/platform/Destroy()
for(var/weakref/drop_ref in stored_atoms)
var/atom/movable/drop_atom = drop_ref.resolve()
if(istype(drop_atom) && !QDELETED(drop_atom) && drop_atom.loc == src)
drop_atom.dropInto(loc)
stored_atoms = null
if(recharging)
var/obj/item/recharging_atom = recharging.resolve()
if(istype(recharging_atom) && recharging_atom.loc == src)
recharging_atom.dropInto(loc)
recharging = null
. = ..()
/mob/living/silicon/robot/platform/examine(mob/user, distance)
. = ..()
if(distance <= 3)
if(recharging)
var/obj/item/weapon/cell/recharging_atom = recharging.resolve()
if(istype(recharging_atom) && !QDELETED(recharging_atom))
. += "It has \a [recharging_atom] slotted into its recharging port."
. += "The cell readout shows [round(recharging_atom.percent(),1)]% charge."
else
. += "Its recharging port is empty."
else
. += "Its recharging port is empty."
if(length(stored_atoms))
var/list/atom_names = list()
for(var/weakref/stored_ref in stored_atoms)
var/atom/movable/AM = stored_ref.resolve()
if(istype(AM))
atom_names += "\a [AM]"
if(length(atom_names))
. += "It has [english_list(atom_names)] loaded into its transport bay."
else
. += "Its cargo bay is empty."
/mob/living/silicon/robot/platform/update_braintype()
braintype = BORG_BRAINTYPE_PLATFORM
/mob/living/silicon/robot/platform/init()
. = ..()
if(ispath(module, /obj/item/weapon/robot_module))
module = new module(src)
/mob/living/silicon/robot/platform/module_reset()
return FALSE
/mob/living/silicon/robot/platform/use_power()
. = ..()
if(stat != DEAD && cell)
// TODO generalize solar occlusion to charge from the actual sun.
var/new_recharge_state = istype(loc, /turf/simulated/floor/outdoors) || /*, /turf/exterior) */ istype(loc, /turf/space)
if(new_recharge_state != last_recharge_state)
last_recharge_state = new_recharge_state
if(last_recharge_state)
to_chat(src, SPAN_NOTICE("<b>Your integrated solar panels begin recharging your battery.</b>"))
else
to_chat(src, SPAN_DANGER("Your integrated solar panels cease recharging your battery."))
if(last_recharge_state)
var/charge_amt = recharger_charge_amount * CELLRATE
cell.give(charge_amt)
used_power_this_tick -= (charge_amt)
module.respawn_consumable(src, (charge_amt / 250)) // magic number copied from borg charger.
if(recharging)
var/obj/item/weapon/cell/recharging_atom = recharging.resolve()
if(!istype(recharging_atom) || QDELETED(recharging_atom) || recharging_atom.loc != src)
recharging = null
return
if(recharging_atom.percent() < 100)
var/charge_amount = recharger_tick_cost * CELLRATE
if(cell.check_charge(charge_amount * 1.5) && cell.checked_use(charge_amount)) // Don't kill ourselves recharging the battery.
recharging_atom.give(charge_amount)
used_power_this_tick += charge_amount
if(!recharge_complete && recharging_atom.percent() >= 100)
recharge_complete = TRUE
visible_message(SPAN_NOTICE("\The [src] beeps and flashes a green light above \his recharging port."))

View File

@@ -0,0 +1,109 @@
/mob/living/silicon/robot/platform/update_icon()
updateicon()
/mob/living/silicon/robot/platform/updateicon()
cut_overlays()
underlays.Cut()
var/obj/item/weapon/robot_module/robot/platform/tank_module = module
if(!istype(tank_module))
icon = initial(icon)
icon_state = initial(icon_state)
color = initial(color)
return
// This is necessary due to Polaris' liberal use of KEEP_TOGETHER and propensity for scaling transforms.
// If we just apply state/colour to the base icon, RESET_COLOR on the additional overlays is ignored.
icon = tank_module.user_icon
icon_state = "blank"
color = null
var/image/I = image(tank_module.user_icon, tank_module.user_icon_state)
I.color = tank_module.base_color
I.appearance_flags |= (RESET_COLOR|PIXEL_SCALE)
underlays += I
if(tank_module.armor_color)
I = image(icon, "[tank_module.user_icon_state]_armour")
I.color = tank_module.armor_color
I.appearance_flags |= (RESET_COLOR|PIXEL_SCALE)
add_overlay(I)
for(var/decal in tank_module.decals)
I = image(icon, "[tank_module.user_icon_state]_[decal]")
I.color = tank_module.decals[decal]
I.appearance_flags |= (RESET_COLOR|PIXEL_SCALE)
add_overlay(I)
if(tank_module.eye_color)
I = image(icon, "[tank_module.user_icon_state]_eyes")
I.color = tank_module.eye_color
I.appearance_flags |= (RESET_COLOR|PIXEL_SCALE)
add_overlay(I)
if(client && key && stat == CONSCIOUS && tank_module.pupil_color)
I = image(icon, "[tank_module.user_icon_state]_pupils")
I.color = tank_module.pupil_color
I.plane = PLANE_LIGHTING_ABOVE
I.appearance_flags |= (RESET_COLOR|PIXEL_SCALE)
add_overlay(I)
if(opened)
add_overlay("[tank_module.user_icon_state]-open")
if(wiresexposed)
I = image(icon, "[tank_module.user_icon_state]-wires")
else if(cell)
I = image(icon, "[tank_module.user_icon_state]-cell")
else
I = image(icon, "[tank_module.user_icon_state]-nowires")
I.appearance_flags |= (RESET_COLOR|PIXEL_SCALE)
add_overlay(I)
/mob/living/silicon/robot/platform/proc/try_paint(var/obj/item/device/floor_painter/painting, var/mob/user)
var/obj/item/weapon/robot_module/robot/platform/tank_module = module
if(!istype(tank_module))
to_chat(user, SPAN_WARNING("\The [src] is not paintable."))
return FALSE
var/list/options = list("Eyes", "Armour", "Body", "Clear Colors")
if(length(tank_module.available_decals))
options += "Decal"
if(length(tank_module.decals))
options += "Clear Decals"
for(var/option in options)
LAZYSET(options, option, new /image('icons/effects/thinktank_labels.dmi', option))
var/choice = show_radial_menu(user, painting, options, radius = 42, require_near = TRUE)
if(!choice || QDELETED(src) || QDELETED(painting) || QDELETED(user) || user.incapacitated() || tank_module.loc != src)
return FALSE
if(choice == "Decal")
choice = null
options = list()
for(var/decal_name in tank_module.available_decals)
LAZYSET(options, decal_name, new /image('icons/effects/thinktank_labels.dmi', decal_name))
choice = show_radial_menu(user, painting, options, radius = 42, require_near = TRUE)
if(!choice || QDELETED(src) || QDELETED(painting) || QDELETED(user) || user.incapacitated() || tank_module.loc != src)
return FALSE
. = TRUE
switch(choice)
if("Eyes")
tank_module.eye_color = painting.paint_colour
if("Armour")
tank_module.armor_color = painting.paint_colour
if("Body")
tank_module.base_color = painting.paint_colour
if("Clear Colors")
tank_module.eye_color = initial(tank_module.eye_color)
tank_module.armor_color = initial(tank_module.armor_color)
tank_module.base_color = initial(tank_module.base_color)
if("Clear Decals")
tank_module.decals = null
else
if(choice in tank_module.available_decals)
LAZYSET(tank_module.decals, tank_module.available_decals[choice], painting.paint_colour)
else
. = FALSE
if(.)
updateicon()

View File

@@ -0,0 +1,77 @@
/mob/living/silicon/robot/platform/attack_hand(mob/user)
if(!opened)
if(recharging)
var/obj/item/recharging_atom = recharging.resolve()
if(istype(recharging_atom) && !QDELETED(recharging_atom) && recharging_atom.loc == src)
recharging_atom.dropInto(loc)
user.put_in_hands(recharging_atom)
user.visible_message(SPAN_NOTICE("\The [user] pops \the [recharging_atom] out of \the [src]'s recharging port."))
recharging = null
return TRUE
if(try_remove_cargo(user))
return TRUE
. = ..()
/mob/living/silicon/robot/platform/attackby(obj/item/W, mob/user)
if(istype(W, /obj/item/weapon/cell) && !opened)
if(recharging)
to_chat(user, SPAN_WARNING("\The [src] already has \a [recharging.resolve()] inserted into its recharging port."))
else if(user.unEquip(W))
W.forceMove(src)
recharging = weakref(W)
recharge_complete = FALSE
user.visible_message(SPAN_NOTICE("\The [user] slots \the [W] into \the [src]'s recharging port."))
return TRUE
if(istype(W, /obj/item/device/floor_painter))
return FALSE // Paint sprayer wil call try_paint() in afterattack()
. = ..()
/mob/living/silicon/robot/platform/attack_ghost(mob/observer/ghost/user)
if(client || key || stat == DEAD || !ticker || !ticker.mode)
return ..()
var/confirm = alert("Do you wish to take control of \the [src]?", "Platform Control", "No", "Yes")
if(confirm != "Yes" || QDELETED(src) || client || key || stat == DEAD || !ticker || !ticker.mode)
return ..()
if(jobban_isbanned(user, "Robot"))
to_chat(user, SPAN_WARNING("You are banned from synthetic roles and cannot take control of \the [src]."))
return
// Boilerplate from drone fabs, unsure if there's a shared proc to use instead.
var/deathtime = world.time - user.timeofdeath
var/deathtimeminutes = round(deathtime / (1 MINUTE))
var/pluralcheck = ""
if(deathtimeminutes == 1)
pluralcheck = "minute"
else if(deathtimeminutes > 0)
pluralcheck = " [deathtimeminutes] minute\s and"
var/deathtimeseconds = round((deathtime - deathtimeminutes * 1 MINUTE) / 10,1)
if (deathtime < platform_respawn_time)
to_chat(usr, "You have been dead for[pluralcheck] [deathtimeseconds] seconds.")
to_chat(usr, "You must wait [platform_respawn_time/600] minute\s to respawn as a drone!")
return
// End boilerplate.
if(user.mind)
user.mind.transfer_to(src)
if(key != user.key)
key = user.key
SetName("[modtype] [braintype]-[rand(100,999)]")
addtimer(CALLBACK(src, .proc/welcome_client), 1)
qdel(user)
/mob/living/silicon/robot/platform/proc/welcome_client()
if(client)
to_chat(src, SPAN_NOTICE("<b>You are a think-tank</b>, a kind of flexible and adaptive drone intelligence installed into an armoured platform. Your programming compels you to be friendly and helpful wherever possible."))
SetSleeping(0)
SetWeakened(0)
SetParalysis(0)
resting = FALSE

View File

@@ -0,0 +1,103 @@
/obj/item/weapon/robot_module/robot/platform
hide_on_manifest = TRUE
var/pupil_color = COLOR_CYAN
var/base_color = COLOR_WHITE
var/eye_color = COLOR_BEIGE
var/armor_color = "#68a2f2"
var/user_icon = 'icons/mob/robots_thinktank.dmi'
var/user_icon_state = "tachi"
var/list/decals
var/list/available_decals = list(
"Stripe" = "stripe",
"Vertical Stripe" = "stripe_vertical"
)
// Only show on manifest if they have a player.
/obj/item/weapon/robot_module/robot/platform/hide_on_manifest()
if(isrobot(loc))
var/mob/living/silicon/robot/R = loc
return !R.key
return ..()
/obj/item/weapon/robot_module/robot/platform/verb/set_eye_colour()
set name = "Set Eye Colour"
set desc = "Select an eye colour to use."
set category = "Robot Commands"
set src in usr
var/new_pupil_color = input(usr, "Select a pupil colour.", "Pupil Colour Selection") as color|null
if(usr.incapacitated() || QDELETED(usr) || QDELETED(src) || loc != usr)
return
pupil_color = new_pupil_color || initial(pupil_color)
usr.update_icon()
/obj/item/weapon/robot_module/robot/platform/explorer
armor_color = "#528052"
eye_color = "#7b7b46"
decals = list(
"stripe_vertical" = "#52b8b8",
"stripe" = "#52b8b8"
)
channels = list(
"Science" = 1,
"Explorer" = 1
)
/obj/item/weapon/robot_module/robot/platform/explorer/New()
..()
modules += new /obj/item/weapon/tool/wrench/cyborg(src)
modules += new /obj/item/weapon/tool/screwdriver/cyborg(src)
modules += new /obj/item/weapon/pickaxe/plasmacutter(src)
modules += new /obj/item/weapon/chainsaw(src)
var/datum/matter_synth/medicine = new /datum/matter_synth/medicine(7500)
var/obj/item/stack/medical/bruise_pack/bandaid = new(src)
bandaid.uses_charge = 1
bandaid.charge_costs = list(1000)
bandaid.synths = list(medicine)
modules += bandaid
synths += medicine
var/obj/item/weapon/gun/energy/phasegun/mounted/cyborg/phasegun = new(src)
modules += phasegun
var/obj/item/weapon/gun/energy/laser/mounted/pew = new(src)
pew.name = "overvolted phase carbine"
pew.appearance = phasegun
emag = pew
/obj/item/weapon/robot_module/robot/platform/explorer/respawn_consumable(var/mob/living/silicon/robot/R, rate)
. = ..()
for(var/obj/item/weapon/gun/energy/pew in modules)
if(pew.power_supply && pew.power_supply.charge < pew.power_supply.maxcharge)
pew.power_supply.give(pew.charge_cost * rate)
pew.update_icon()
else
pew.charge_tick = 0
/obj/item/weapon/robot_module/robot/platform/cargo
armor_color = "#d5b222"
eye_color = "#686846"
decals = list(
"stripe_vertical" = "#bfbfa1",
"stripe" = "#bfbfa1"
)
channels = list("Supply" = 1)
networks = list(NETWORK_MINE)
/obj/item/weapon/robot_module/robot/platform/cargo/New()
..()
modules += new /obj/item/weapon/packageWrap(src)
modules += new /obj/item/weapon/pen/multi(src)
modules += new /obj/item/device/destTagger(src)
emag = new /obj/item/weapon/stamp/denied
/obj/item/weapon/robot_module/robot/platform/cargo/respawn_consumable(mob/living/silicon/robot/R, rate)
. = ..()
var/obj/item/weapon/packageWrap/wrapper = locate() in modules
if(wrapper.amount < initial(wrapper.amount))
wrapper.amount++

View File

@@ -0,0 +1,139 @@
/mob/living/silicon/robot/platform/death(gibbed, deathmessage, show_dead_message)
if(gibbed)
if(recharging)
var/obj/item/recharging_atom = recharging.resolve()
if(istype(recharging_atom) && !QDELETED(recharging_atom) && recharging_atom.loc == src)
recharging_atom.dropInto(loc)
recharging_atom.throw_at(get_edge_target_turf(src,pick(GLOB.alldirs)),rand(1,3),30)
recharging = null
if(length(stored_atoms))
for(var/weakref/stored_ref in stored_atoms)
var/atom/movable/dropping = stored_ref.resolve()
if(istype(dropping) && !QDELETED(dropping) && dropping.loc == src)
dropping.dropInto(loc)
dropping.throw_at(get_edge_target_turf(src,pick(GLOB.alldirs)),rand(1,3),30)
stored_atoms = null
. = ..()
/mob/living/silicon/robot/platform/proc/can_store_atom(var/atom/movable/storing, var/mob/user)
if(!istype(storing))
var/storing_target = (user == src) ? "yourself" : "\the [src]"
to_chat(user, SPAN_WARNING("You cannot store that inside [storing_target]."))
return FALSE
if(!isturf(storing.loc))
return FALSE
if(storing.anchored || !storing.simulated)
to_chat(user, SPAN_WARNING("\The [storing] won't budge!"))
return FALSE
if(storing == src)
var/storing_target = (user == src) ? "yourself" : "\the [src]"
to_chat(user, SPAN_WARNING("You cannot store [storing_target] inside [storing_target]!"))
return FALSE
if(length(stored_atoms) >= max_stored_atoms)
var/storing_target = (user == src) ? "Your" : "\The [src]'s"
to_chat(user, SPAN_WARNING("[storing_target] cargo compartment is full."))
return FALSE
if(ismob(storing))
var/mob/M = storing
if(M.mob_size >= mob_size)
var/storing_target = (user == src) ? "your storage compartment" : "\the [src]"
to_chat(user, SPAN_WARNING("\The [storing] is too big for [storing_target]."))
return FALSE
for(var/store_type in can_store_types)
if(istype(storing, store_type))
. = TRUE
break
if(.)
for(var/store_type in cannot_store_types)
if(istype(storing, store_type))
. = FALSE
break
if(!.)
var/storing_target = (user == src) ? "yourself" : "\the [src]"
to_chat(user, SPAN_WARNING("You cannot store \the [storing] inside [storing_target]."))
/mob/living/silicon/robot/platform/proc/store_atom(var/atom/movable/storing, var/mob/user)
if(istype(storing))
storing.forceMove(src)
LAZYDISTINCTADD(stored_atoms, weakref(storing))
/mob/living/silicon/robot/platform/proc/drop_stored_atom(var/atom/movable/ejecting, var/mob/user)
if(!ejecting && length(stored_atoms))
var/weakref/stored_ref = stored_atoms[1]
if(!istype(stored_ref))
LAZYREMOVE(stored_atoms, stored_ref)
else
ejecting = stored_ref?.resolve()
LAZYREMOVE(stored_atoms, weakref(ejecting))
if(istype(ejecting) && !QDELETED(ejecting) && ejecting.loc == src)
ejecting.dropInto(loc)
if(user == src)
visible_message(SPAN_NOTICE("\The [src] ejects \the [ejecting] from its cargo compartment."))
else
user.visible_message(SPAN_NOTICE("\The [user] pulls \the [ejecting] from \the [src]'s cargo compartment."))
/mob/living/silicon/robot/platform/attack_ai(mob/user)
if(isrobot(user) && user.Adjacent(src))
return try_remove_cargo(user)
return ..()
/mob/living/silicon/robot/platform/proc/try_remove_cargo(var/mob/user)
if(!length(stored_atoms) || !istype(user))
return FALSE
var/weakref/remove_ref = stored_atoms[length(stored_atoms)]
var/atom/movable/removing = remove_ref?.resolve()
if(!istype(removing) || QDELETED(removing) || removing.loc != src)
LAZYREMOVE(stored_atoms, remove_ref)
else
user.visible_message(SPAN_NOTICE("\The [user] begins unloading \the [removing] from \the [src]'s cargo compartment."))
if(do_after(user, 3 SECONDS, src) && !QDELETED(removing) && removing.loc == src)
drop_stored_atom(removing, user)
return TRUE
/mob/living/silicon/robot/platform/verb/drop_stored_atom_verb()
set name = "Eject Cargo"
set category = "Robot Commands"
set desc = "Drop something from your internal storage."
if(incapacitated())
to_chat(src, SPAN_WARNING("You are not in any state to do that."))
return
if(length(stored_atoms))
drop_stored_atom(user = src)
else
to_chat(src, SPAN_WARNING("You have nothing in your cargo compartment."))
/mob/living/silicon/robot/platform/MouseDrop_T(atom/movable/dropping, mob/user)
if(!istype(user) || !istype(dropping) || user.incapacitated())
return FALSE
if(!can_mouse_drop(dropping, user) || !can_store_atom(dropping, user))
return FALSE
if(user == src)
visible_message(SPAN_NOTICE("\The [src] begins loading \the [dropping] into its cargo compartment."))
else
user.visible_message(SPAN_NOTICE("\The [user] begins loading \the [dropping] into \the [src]'s cargo compartment."))
if(do_after(user, 3 SECONDS, src) && can_mouse_drop(dropping, user) && can_store_atom(dropping, user))
store_atom(dropping, user)
return FALSE
/mob/living/silicon/robot/platform/proc/can_mouse_drop(var/atom/dropping, var/mob/user)
if(!istype(user) || !istype(dropping) || QDELETED(dropping) || QDELETED(user) || QDELETED(src))
return FALSE
if(user.incapacitated() || !Adjacent(user) || !dropping.Adjacent(user))
return FALSE
return TRUE

View File

@@ -0,0 +1,32 @@
/mob/living/silicon/robot/platform/explorer
name = "recon platform"
desc = "A large quadrupedal AI platform, colloquially known as a 'think-tank' due to the flexible onboard intelligence. This one is lightly armoured and fitted with all-terrain wheels."
modtype = "Recon"
module = /obj/item/weapon/robot_module/robot/platform/explorer
/mob/living/silicon/robot/platform/explorer/Initialize()
. = ..()
laws = new /datum/ai_laws/explorer
/mob/living/silicon/robot/platform/explorer/welcome_client()
..()
if(client) // ganbatte tachikoma-san
to_chat(src, SPAN_NOTICE("You are tasked with supporting the Exploration and Science staff as they unearth the secrets of the planet. Do your best!"))
/obj/effect/landmark/robot_platform/explorer
platform_type = /mob/living/silicon/robot/platform/explorer
/mob/living/silicon/robot/platform/cargo
name = "logistics platform"
desc = "A large quadrupedal AI platform, colloquially known as a 'think-tank' due to the flexible onboard intelligence. This one has an expanded storage compartment."
modtype = "Logistics"
module = /obj/item/weapon/robot_module/robot/platform/cargo
max_stored_atoms = 3
/mob/living/silicon/robot/platform/cargo/welcome_client()
..()
if(client)
to_chat(src, SPAN_NOTICE("You are tasked with supporting the Cargo and Supply staff as they handle operational logistics. Do your best!"))
/obj/effect/landmark/robot_platform/cargo
platform_type = /mob/living/silicon/robot/platform/cargo