Merge pull request #3889 from VOREStation/upstream-merge-5282

[MIRROR] Allows AIs to produce and control maint/construction/mining drones.
This commit is contained in:
Aronai Sieyes
2018-06-16 10:51:20 -04:00
committed by GitHub
12 changed files with 217 additions and 42 deletions

View File

@@ -60,6 +60,7 @@ var/list/gamemode_cache = list()
var/humans_need_surnames = 0
var/allow_random_events = 0 // enables random events mid-round when set to 1
var/allow_ai = 1 // allow ai job
var/allow_ai_drones = 0 // allow ai controlled drones
var/hostedby = null
var/respawn = 1
var/guest_jobban = 1
@@ -400,6 +401,9 @@ var/list/gamemode_cache = list()
if ("allow_ai")
config.allow_ai = 1
if ("allow_ai_drones")
config.allow_ai_drones = 1
// if ("authentication")
// config.enable_authentication = 1

View File

@@ -200,14 +200,16 @@ GLOBAL_LIST_BOILERPLATE(all_deactivated_AI_cores, /obj/structure/AIcore/deactiva
if(!istype(transfer) || locate(/mob/living/silicon/ai) in src)
return
if(transfer.controlling_drone)
transfer.controlling_drone.release_ai_control("Unit control lost. Core transfer completed.")
transfer.aiRestorePowerRoutine = 0
transfer.control_disabled = 0
transfer.aiRadio.disabledAi = 0
transfer.loc = get_turf(src)
transfer.create_eyeobj()
transfer.cancel_camera()
user << "<span class='notice'>Transfer successful:</span> [transfer.name] placed within stationary core."
transfer << "You have been transferred into a stationary core. Remote device connection restored."
to_chat(user, "<span class='notice'>Transfer successful:</span> [transfer.name] placed within stationary core.")
to_chat(transfer, "You have been transferred into a stationary core. Remote device connection restored.")
if(card)
card.clear()

View File

@@ -64,20 +64,24 @@
add_attack_logs(user,carded_ai,"Purged from AI Card")
flush = 1
carded_ai.suiciding = 1
carded_ai << "Your power has been disabled!"
to_chat(carded_ai, "Your power has been disabled!")
while (carded_ai && carded_ai.stat != 2)
if(carded_ai.controlling_drone && prob(carded_ai.oxyloss)) //You feel it creeping? Eventually will reach 100, resulting in the second half of the AI's remaining life being lonely.
carded_ai.controlling_drone.release_ai_control("Unit lost. Integrity too low to maintain connection.")
carded_ai.adjustOxyLoss(2)
carded_ai.updatehealth()
sleep(10)
flush = 0
if (href_list["radio"])
carded_ai.aiRadio.disabledAi = text2num(href_list["radio"])
carded_ai << "<span class='warning'>Your Subspace Transceiver has been [carded_ai.aiRadio.disabledAi ? "disabled" : "enabled"]!</span>"
user << "<span class='notice'>You [carded_ai.aiRadio.disabledAi ? "disable" : "enable"] the AI's Subspace Transceiver.</span>"
to_chat(carded_ai, "<span class='warning'>Your Subspace Transceiver has been [carded_ai.aiRadio.disabledAi ? "disabled" : "enabled"]!</span>")
to_chat(user, "<span class='notice'>You [carded_ai.aiRadio.disabledAi ? "disable" : "enable"] the AI's Subspace Transceiver.</span>")
if (href_list["wireless"])
carded_ai.control_disabled = text2num(href_list["wireless"])
carded_ai << "<span class='warning'>Your wireless interface has been [carded_ai.control_disabled ? "disabled" : "enabled"]!</span>"
user << "<span class='notice'>You [carded_ai.control_disabled ? "disable" : "enable"] the AI's wireless interface.</span>"
to_chat(carded_ai, "<span class='warning'>Your wireless interface has been [carded_ai.control_disabled ? "disabled" : "enabled"]!</span>")
to_chat(user, "<span class='notice'>You [carded_ai.control_disabled ? "disable" : "enable"] the AI's wireless interface.</span>")
if(carded_ai.control_disabled && carded_ai.controlling_drone)
carded_ai.controlling_drone.release_ai_control("Unit control terminated at intellicore port.")
update_icon()
return 1
@@ -94,12 +98,12 @@
icon_state = "aicard"
/obj/item/device/aicard/proc/grab_ai(var/mob/living/silicon/ai/ai, var/mob/living/user)
if(!ai.client)
user << "<span class='danger'>ERROR:</span> AI [ai.name] is offline. Unable to transfer."
if(!ai.client && !ai.controlling_drone)
to_chat(user, "<span class='danger'>ERROR:</span> AI [ai.name] is offline. Unable to transfer.")
return 0
if(carded_ai)
user << "<span class='danger'>Transfer failed:</span> Existing AI found on remote device. Remove existing AI to install a new one."
to_chat(user, "<span class='danger'>Transfer failed:</span> Existing AI found on remote device. Remove existing AI to install a new one.")
return 0
if(!user.IsAdvancedToolUser() && isanimal(user))
@@ -108,7 +112,9 @@
return 0
user.visible_message("\The [user] starts transferring \the [ai] into \the [src]...", "You start transferring \the [ai] into \the [src]...")
ai << "<span class='danger'>\The [user] is transferring you into \the [src]!</span>"
to_chat(ai, "<span class='danger'>\The [user] is transferring you into \the [src]!</span>")
if(ai.controlling_drone)
to_chat(ai.controlling_drone, "<span class='danger'>\The [user] is transferring you into \the [src]!</span>")
if(do_after(user, 100))
if(istype(ai.loc, /turf/))
@@ -124,11 +130,13 @@
ai.control_disabled = 1
ai.aiRestorePowerRoutine = 0
carded_ai = ai
if(ai.controlling_drone)
ai.controlling_drone.release_ai_control("Unit control lost.")
if(ai.client)
ai << "You have been transferred into a mobile core. Remote access lost."
to_chat(ai, "You have been transferred into a mobile core. Remote access lost.")
if(user.client)
user << "<span class='notice'><b>Transfer successful:</b></span> [ai.name] extracted from current device and placed within mobile core."
to_chat(ai, "<span class='notice'><b>Transfer successful:</b></span> [ai.name] extracted from current device and placed within mobile core.")
ai.canmove = 1
update_icon()

View File

@@ -693,6 +693,9 @@ var/list/ai_verbs_default = list(
card.grab_ai(src, user)
else if(istype(W, /obj/item/weapon/wrench))
if(user == controlling_drone)
to_chat(user, "<span class='notice'>The drone's subsystems resist your efforts to tamper with your bolts.</span>")
return
if(anchored)
playsound(src, W.usesound, 50, 1)
user.visible_message("<font color='blue'>\The [user] starts to unbolt \the [src] from the plating...</font>")

View File

@@ -3,6 +3,10 @@
if(stat == DEAD)
return
if(controlling_drone)
controlling_drone.release_ai_control("<b>WARNING: Primary control loop failure.</b> Session terminated.")
. = ..(gibbed)
if(src.eyeobj)
src.eyeobj.setLoc(get_turf(src))

View File

@@ -8,6 +8,8 @@
if (src.stat!=CONSCIOUS)
src.cameraFollow = null
src.reset_view(null)
if(controlling_drone)
controlling_drone.release_ai_control("<b>WARNING: Primary control loop failure.</b> Session terminated.")
src.updatehealth()

View File

@@ -19,7 +19,7 @@ var/list/mob_hat_cache = list()
return mob_hat_cache[key]
/mob/living/silicon/robot/drone
name = "drone"
name = "maintenance drone"
real_name = "drone"
icon = 'icons/mob/robots.dmi'
icon_state = "repairbot"
@@ -57,6 +57,8 @@ var/list/mob_hat_cache = list()
var/obj/item/hat
var/hat_x_offset = 0
var/hat_y_offset = -13
var/serial_number = 0
var/name_override = 0
holder_type = /obj/item/weapon/holder/drone
@@ -71,6 +73,7 @@ var/list/mob_hat_cache = list()
return FALSE
/mob/living/silicon/robot/drone/construction
name = "construction drone"
icon_state = "constructiondrone"
law_type = /datum/ai_laws/construction_drone
module_type = /obj/item/weapon/robot_module/drone/construction
@@ -95,6 +98,7 @@ var/list/mob_hat_cache = list()
remove_language("Robot Talk")
add_language("Robot Talk", 0)
add_language("Drone Talk", 1)
serial_number = rand(0,999)
//They are unable to be upgraded, so let's give them a bit of a better battery.
cell.maxcharge = 10000
@@ -127,14 +131,22 @@ var/list/mob_hat_cache = list()
name = real_name
/mob/living/silicon/robot/drone/updatename()
real_name = "maintenance drone ([rand(100,999)])"
if(name_override)
return
if(controlling_ai)
real_name = "remote drone ([controlling_ai])"
else
real_name = "[initial(name)] ([serial_number])"
name = real_name
/mob/living/silicon/robot/drone/updateicon()
overlays.Cut()
if(stat == 0)
overlays += "eyes-[icon_state]"
if(controlling_ai)
overlays += "eyes-[icon_state]-ai"
else
overlays += "eyes-[icon_state]"
else
overlays -= "eyes"
if(hat) // Let the drones wear hats.
@@ -213,15 +225,18 @@ var/list/mob_hat_cache = list()
return
if(emagged)
to_chat(user, "<span class='danger'>\The [user] attempts to load subversive software into you, but your hacked subroutines ignore the attempt.</span>")
to_chat(src, "<span class='danger'>\The [user] attempts to load subversive software into you, but your hacked subroutines ignore the attempt.</span>")
to_chat(user, "<span class='danger'>You attempt to subvert [src], but the sequencer has no effect.</span>")
return
to_chat(user, "<span class='danger'>You swipe the sequencer across [src]'s interface and watch its eyes flicker.</span>")
to_chat(user, "<span class='danger'>You feel a sudden burst of malware loaded into your execute-as-root buffer. Your tiny brain methodically parses, loads and executes the script.</span>")
message_admins("[key_name_admin(user)] emagged drone [key_name_admin(src)]. Laws overridden.")
log_game("[key_name(user)] emagged drone [key_name(src)]. Laws overridden.")
if(controlling_ai)
to_chat(src, "<span class='danger'>\The [user] loads some kind of subversive software into the remote drone, corrupting its lawset but luckily sparing yours.</span>")
else
to_chat(src, "<span class='danger'>You feel a sudden burst of malware loaded into your execute-as-root buffer. Your tiny brain methodically parses, loads and executes the script.</span>")
log_game("[key_name(user)] emagged drone [key_name(src)][controlling_ai ? " but AI [key_name(controlling_ai)] is in remote control" : " Laws overridden"].")
var/time = time2text(world.realtime,"hh:mm:ss")
lawchanges.Add("[time] <B>:</B> [user.name]([user.key]) emagged [name]([key])")
@@ -234,9 +249,10 @@ var/list/mob_hat_cache = list()
var/datum/gender/TU = gender_datums[user.get_visible_gender()]
set_zeroth_law("Only [user.real_name] and people [TU.he] designate[TU.s] as being such are operatives.")
src << "<b>Obey these laws:</b>"
laws.show_laws(src)
src << "<span class='danger'>ALERT: [user.real_name] [TU.is] your new master. Obey your new laws and [TU.his] commands.</span>"
if(!controlling_ai)
to_chat(src, "<b>Obey these laws:</b>")
laws.show_laws(src)
to_chat(src, "<span class='danger'>ALERT: [user.real_name] is your new master. Obey your new laws and \his commands.</span>")
return 1
//DRONE LIFE/DEATH
@@ -262,26 +278,41 @@ var/list/mob_hat_cache = list()
return
..()
/mob/living/silicon/robot/drone/death(gibbed)
if(controlling_ai)
release_ai_control("<b>WARNING: remote system failure.</b> Connection timed out.")
. = ..(gibbed)
//DRONE MOVEMENT.
/mob/living/silicon/robot/drone/Process_Spaceslipping(var/prob_slip)
return 0
//CONSOLE PROCS
/mob/living/silicon/robot/drone/proc/law_resync()
if(controlling_ai)
to_chat(src, "<span class='warning'>Someone issues a remote law reset order for this unit, but you disregard it.</span>")
return
if(stat != 2)
if(emagged)
src << "<span class='danger'>You feel something attempting to modify your programming, but your hacked subroutines are unaffected.</span>"
to_chat(src, "<span class='danger'>You feel something attempting to modify your programming, but your hacked subroutines are unaffected.</span>")
else
src << "<span class='danger'>A reset-to-factory directive packet filters through your data connection, and you obediently modify your programming to suit it.</span>"
to_chat(src, "<span class='danger'>A reset-to-factory directive packet filters through your data connection, and you obediently modify your programming to suit it.</span>")
full_law_reset()
show_laws()
/mob/living/silicon/robot/drone/proc/shut_down()
if(controlling_ai && mind.special_role)
to_chat(src, "<span class='warning'>Someone issued a remote kill order for this unit, but you disregard it.</span>")
return
if(stat != 2)
if(emagged)
src << "<span class='danger'>You feel a system kill order percolate through your tiny brain, but it doesn't seem like a good idea to you.</span>"
to_chat(src, "<span class='danger'>You feel a system kill order percolate through [controlling_ai ? "the drones" : "your"] tiny brain, but it doesn't seem like a good idea to [controlling_ai ? "it" : "you"].</span>")
else
src << "<span class='danger'>You feel a system kill order percolate through your tiny brain, and you obediently destroy yourself.</span>"
to_chat(src, "<span class='danger'>You feel a system kill order percolate through [controlling_ai ? "the drones" : "your"] tiny brain, and [controlling_ai ? "it" : "you"] obediently destroy[controlling_ai ? "s itself" : " yourself"].</span>")
death()
/mob/living/silicon/robot/drone/proc/full_law_reset()
@@ -290,6 +321,21 @@ var/list/mob_hat_cache = list()
clear_ion_laws(1)
laws = new law_type
/mob/living/silicon/robot/drone/show_laws(var/everyone = 0)
if(!controlling_ai)
return..()
to_chat(src, "<b>Obey these laws:</b>")
controlling_ai.laws_sanity_check()
controlling_ai.laws.show_laws(src)
/mob/living/silicon/robot/drone/robot_checklaws()
set category = "Silicon Commands"
set name = "State Laws"
if(!controlling_ai)
return ..()
controlling_ai.subsystem_law_manager()
//Reboot procs.
/mob/living/silicon/robot/drone/proc/request_player()
@@ -347,14 +393,6 @@ var/list/mob_hat_cache = list()
..()
flavor_text = "It's a bulky construction drone stamped with a Sol Central glyph."
/mob/living/silicon/robot/drone/construction/updatename()
real_name = "construction drone ([rand(100,999)])"
name = real_name
/mob/living/silicon/robot/drone/mining/init()
..()
flavor_text = "It's a bulky mining drone stamped with a Grayson logo."
/mob/living/silicon/robot/drone/mining/updatename()
real_name = "mining drone ([rand(100,999)])"
name = real_name

View File

@@ -75,20 +75,22 @@
if(!produce_drones || !config.allow_drone_spawn || count_drones() >= config.max_maint_drones)
return
if(!player || !istype(player.mob,/mob/observer/dead))
if(player && !istype(player.mob,/mob/observer/dead))
return
announce_ghost_joinleave(player, 0, "They have taken control over a maintenance drone.")
visible_message("\The [src] churns and grinds as it lurches into motion, disgorging a shiny new drone after a few moments.")
flick("h_lathe_leave",src)
drone_progress = 0
time_last_drone = world.time
if(player.mob && player.mob.mind) player.mob.mind.reset()
var/mob/living/silicon/robot/drone/new_drone = new drone_type(get_turf(src))
new_drone.transfer_personality(player)
new_drone.master_fabricator = src
drone_progress = 0
var/mob/living/silicon/robot/drone/new_drone = new drone_type(get_turf(src))
if(player)
announce_ghost_joinleave(player, 0, "They have taken control over a maintenance drone.")
if(player.mob && player.mob.mind) player.mob.mind.reset()
new_drone.transfer_personality(player)
return new_drone
/mob/observer/dead/verb/join_as_drone()

View File

@@ -0,0 +1,104 @@
/mob/living/silicon/ai
var/mob/living/silicon/robot/drone/controlling_drone
/mob/living/silicon/robot/drone
var/mob/living/silicon/ai/controlling_ai
/mob/living/silicon/robot/drone/attack_ai(var/mob/living/silicon/ai/user)
if(!istype(user) || controlling_ai || !config.allow_drone_spawn || !config.allow_ai_drones)
return
if(client || key)
to_chat(user, "<span class='warning'>You cannot take control of an autonomous, active drone.</span>")
return
if(health < -35 || emagged)
to_chat(user, "<span class='notice'><b>WARNING:</b> connection timed out.</span>")
return
user.controlling_drone = src
user.teleop = src
radio.channels = user.aiRadio.keyslot2.channels
controlling_ai = user
verbs += /mob/living/silicon/robot/drone/proc/release_ai_control_verb
local_transmit = FALSE
languages = controlling_ai.languages.Copy()
speech_synthesizer_langs = controlling_ai.speech_synthesizer_langs.Copy()
stat = CONSCIOUS
if(user.mind)
user.mind.transfer_to(src)
else
key = user.key
updatename()
to_chat(src, "<span class='notice'><b>You have shunted your primary control loop into \a [initial(name)].</b> Use the <b>Release Control</b> verb to return to your core.</span>")
/obj/machinery/drone_fabricator/attack_ai(var/mob/living/silicon/ai/user as mob)
if(!istype(user) || user.controlling_drone || !config.allow_drone_spawn || !config.allow_ai_drones)
return
if(stat & NOPOWER)
to_chat(user, "<span class='warning'>\The [src] is unpowered.</span>")
return
if(!produce_drones)
to_chat(user, "<span class='warning'>\The [src] is disabled.</span>")
return
if(drone_progress < 100)
to_chat(user, "<span class='warning'>\The [src] is not ready to produce a new drone.</span>")
return
if(count_drones() >= config.max_maint_drones)
to_chat(user, "<span class='warning'>The drone control subsystems are tasked to capacity; they cannot support any more drones.</span>")
return
var/mob/living/silicon/robot/drone/new_drone = create_drone()
user.controlling_drone = new_drone
user.teleop = new_drone
new_drone.radio.channels = user.aiRadio.keyslot2.channels
new_drone.controlling_ai = user
new_drone.verbs += /mob/living/silicon/robot/drone/proc/release_ai_control_verb
new_drone.local_transmit = FALSE
new_drone.languages = new_drone.controlling_ai.languages.Copy()
new_drone.speech_synthesizer_langs = new_drone.controlling_ai.speech_synthesizer_langs.Copy()
if(user.mind)
user.mind.transfer_to(new_drone)
else
new_drone.key = user.key
new_drone.updatename()
to_chat(new_drone, "<span class='notice'><b>You have shunted your primary control loop into \a [initial(new_drone.name)].</b> Use the <b>Release Control</b> verb to return to your core.</span>")
/mob/living/silicon/robot/drone/proc/release_ai_control_verb()
set name = "Release Control"
set desc = "Release control of a remote drone."
set category = "Silicon Commands"
release_ai_control("Remote session terminated.")
/mob/living/silicon/robot/drone/proc/release_ai_control(var/message = "Connection terminated.")
if(controlling_ai)
if(mind)
mind.transfer_to(controlling_ai)
else
controlling_ai.key = key
to_chat(controlling_ai, "<span class='notice'>[message]</span>")
controlling_ai.controlling_drone = null
controlling_ai.teleop = null
controlling_ai = null
radio.channels = module.channels
verbs -= /mob/living/silicon/robot/drone/proc/release_ai_control_verb
languages = initial(languages)
speech_synthesizer_langs = initial(speech_synthesizer_langs)
remove_language("Robot Talk")
add_language("Robot Talk", 0)
add_language("Drone Talk", 1)
local_transmit = TRUE
full_law_reset()
updatename()
death()

View File

@@ -0,0 +1,7 @@
author: Mechoid
delete-after: True
changes:
- rscadd: "Allow AIs to create and take control of mindless drones from fabricators."

Binary file not shown.

Before

Width:  |  Height:  |  Size: 388 KiB

After

Width:  |  Height:  |  Size: 388 KiB

View File

@@ -2144,6 +2144,7 @@
#include "code\modules\mob\living\silicon\robot\drone\drone_damage.dm"
#include "code\modules\mob\living\silicon\robot\drone\drone_items.dm"
#include "code\modules\mob\living\silicon\robot\drone\drone_manufacturer.dm"
#include "code\modules\mob\living\silicon\robot\drone\drone_remote_control.dm"
#include "code\modules\mob\living\silicon\robot\drone\drone_say.dm"
#include "code\modules\mob\living\silicon\robot\robot_modules\event.dm"
#include "code\modules\mob\living\silicon\robot\robot_modules\station.dm"