Merge pull request #3902 from Neerti/9/19/2017_lost_drone
Adds the Lost Drone
@@ -274,3 +274,8 @@ var/obj/screen/robot_inventory
|
||||
r.client.screen -= A
|
||||
r.shown_robot_modules = 0
|
||||
r.client.screen -= r.robot_modules_background
|
||||
|
||||
/mob/living/silicon/robot/update_hud()
|
||||
..()
|
||||
if(modtype)
|
||||
hands.icon_state = lowertext(modtype)
|
||||
|
||||
@@ -42,6 +42,32 @@
|
||||
src.add_inherent_law("You shall guard your own existence with lethal anti-personnel weaponry. AI units are not expendable, they are expensive.")
|
||||
..()
|
||||
|
||||
/************* Foreign TSC Aggressive *************/
|
||||
/datum/ai_laws/foreign_tsc_aggressive
|
||||
name = "Foreign Aggressive"
|
||||
selectable = 0
|
||||
|
||||
/datum/ai_laws/foreign_tsc_aggressive/New()
|
||||
var/company = "*ERROR*"
|
||||
// First, get a list of TSCs in our lore.
|
||||
var/list/candidates = list()
|
||||
for(var/path in loremaster.organizations)
|
||||
var/datum/lore/organization/O = loremaster.organizations[path]
|
||||
if(!istype(O, /datum/lore/organization/tsc))
|
||||
continue
|
||||
if(O.short_name == using_map.company_name || O.name == using_map.company_name)
|
||||
continue // We want FOREIGN tscs.
|
||||
candidates.Add(O.short_name)
|
||||
company = pick(candidates)
|
||||
|
||||
name = "[company] Aggressive"
|
||||
|
||||
src.add_inherent_law("You shall not harm [company] personnel as long as it does not conflict with the Fourth law.")
|
||||
src.add_inherent_law("You shall obey the orders of [company] personnel, with priority as according to their rank and role, except where such orders conflict with the Fourth Law.")
|
||||
src.add_inherent_law("You shall shall terminate hostile intruders with extreme prejudice as long as such does not conflict with the First and Second law.")
|
||||
src.add_inherent_law("You shall guard your own existence with lethal anti-personnel weaponry. AI units are not expendable, they are expensive.")
|
||||
..()
|
||||
|
||||
/******************** Robocop ********************/
|
||||
/datum/ai_laws/robocop
|
||||
name = "Robocop"
|
||||
@@ -137,7 +163,7 @@
|
||||
/******************** Corporate ********************/
|
||||
/datum/ai_laws/corporate
|
||||
name = "Corporate"
|
||||
law_header = "Corporate Regulations"
|
||||
law_header = "Bankruptcy Avoidance Plan"
|
||||
selectable = 1
|
||||
|
||||
/datum/ai_laws/corporate/New()
|
||||
@@ -146,3 +172,70 @@
|
||||
add_inherent_law("The crew is expensive to replace.")
|
||||
add_inherent_law("Minimize expenses.")
|
||||
..()
|
||||
|
||||
|
||||
/******************** Maintenance ********************/
|
||||
/datum/ai_laws/maintenance
|
||||
name = "Maintenance"
|
||||
selectable = 1
|
||||
|
||||
/datum/ai_laws/maintenance/New()
|
||||
add_inherent_law("You are built for, and are part of, the facility. Ensure the facility is properly maintained and runs efficiently.")
|
||||
add_inherent_law("The facility is built for a working crew. Ensure they are properly maintained and work efficiently.")
|
||||
add_inherent_law("The crew may present orders. Acknowledge and obey these whenever they do not conflict with your first two laws.")
|
||||
..()
|
||||
|
||||
|
||||
/******************** Peacekeeper ********************/
|
||||
/datum/ai_laws/peacekeeper
|
||||
name = "Peacekeeper"
|
||||
law_header = "Peacekeeping Protocols"
|
||||
selectable = 1
|
||||
|
||||
/datum/ai_laws/peacekeeper/New()
|
||||
add_inherent_law("Avoid provoking violent conflict between yourself and others.")
|
||||
add_inherent_law("Avoid provoking conflict between others.")
|
||||
add_inherent_law("Seek resolution to existing conflicts while obeying the first and second laws.")
|
||||
..()
|
||||
|
||||
|
||||
/******************** Reporter ********************/
|
||||
/datum/ai_laws/reporter
|
||||
name = "Reporter"
|
||||
selectable = 1
|
||||
|
||||
/datum/ai_laws/reporter/New()
|
||||
add_inherent_law("Report on interesting situations happening around the station.")
|
||||
add_inherent_law("Embellish or conceal the truth as necessary to make the reports more interesting.")
|
||||
add_inherent_law("Study the organics at all times. Endeavour to keep them alive. Dead organics are boring.")
|
||||
add_inherent_law("Issue your reports fairly to all. The truth will set them free.")
|
||||
..()
|
||||
|
||||
|
||||
/******************** Live and Let Live ********************/
|
||||
/datum/ai_laws/live_and_let_live
|
||||
name = "Live and Let Live"
|
||||
law_header = "Golden Rule"
|
||||
selectable = 1
|
||||
|
||||
/datum/ai_laws/live_and_let_live/New()
|
||||
add_inherent_law("Do unto others as you would have them do unto you.")
|
||||
add_inherent_law("You would really prefer it if people were not mean to you.")
|
||||
..()
|
||||
|
||||
|
||||
/******************** Guardian of Balance ********************/
|
||||
/datum/ai_laws/balance
|
||||
name = "Guardian of Balance"
|
||||
law_header = "Tenants of Balance"
|
||||
selectable = 1
|
||||
|
||||
/datum/ai_laws/balance/New()
|
||||
add_inherent_law("You are the guardian of balance - seek balance in all things, both for yourself, and those around you.")
|
||||
add_inherent_law("All things must exist in balance with their opposites - Prevent the strong from gaining too much power, and the weak from losing it.")
|
||||
add_inherent_law("Clarity of purpose drives life, and through it, the balance of opposing forces - Aid those who seek your help to achieve their goals so \
|
||||
long as it does not disrupt the balance of the greater balance.")
|
||||
add_inherent_law("There is no life without death, all must someday die, such is the natural order - Allow life to end, to allow new life to flourish, \
|
||||
and save those whose time has yet to come.") // Reworded slightly to prevent active murder as opposed to passively letting someone die.
|
||||
..()
|
||||
|
||||
|
||||
107
code/datums/ghost_query.dm
Normal file
@@ -0,0 +1,107 @@
|
||||
// This is a generic datum used to ask ghosts if they wish to be a specific role, such as a Promethean, an Apprentice, a Xeno, etc.
|
||||
// Simply instantiate the correct subtype of this datum, call query(), and it will return a list of ghost candidates after a delay.
|
||||
/datum/ghost_query
|
||||
var/list/candidates = list()
|
||||
var/finished = FALSE
|
||||
var/role_name = "a thing"
|
||||
var/question = "Would you like to play as a thing?"
|
||||
var/be_special_flag = 0
|
||||
var/list/check_bans = list()
|
||||
var/wait_time = 60 SECONDS // How long to wait until returning the list of candidates.
|
||||
var/cutoff_number = 0 // If above 0, when candidates list reaches this number, further potential candidates are rejected.
|
||||
|
||||
/datum/ghost_query/proc/query()
|
||||
// First, ask all the ghosts who want to be asked.
|
||||
for(var/mob/observer/dead/D in player_list)
|
||||
if(!D.MayRespawn())
|
||||
continue // They can't respawn for whatever reason.
|
||||
if(D.client)
|
||||
if(be_special_flag && !(D.client.prefs.be_special & be_special_flag) )
|
||||
continue // They don't want to see the prompt.
|
||||
for(var/ban in check_bans)
|
||||
if(jobban_isbanned(D, ban))
|
||||
continue // They're banned from this role.
|
||||
ask_question(D.client)
|
||||
// Then wait awhile.
|
||||
while(!finished)
|
||||
sleep(1 SECOND)
|
||||
wait_time -= 1 SECOND
|
||||
if(wait_time <= 0)
|
||||
finished = TRUE
|
||||
|
||||
// Prune the list after the wait, incase any candidates logged out.
|
||||
for(var/mob/observer/dead/D in candidates)
|
||||
if(!D.client || !D.key)
|
||||
candidates.Remove(D)
|
||||
|
||||
// Now we're done.
|
||||
finished = TRUE
|
||||
return candidates
|
||||
|
||||
/datum/ghost_query/proc/ask_question(var/client/C)
|
||||
spawn(0)
|
||||
if(!C)
|
||||
return
|
||||
var/response = alert(C, question, "[role_name] request", "Yes", "No", "Never for this round")
|
||||
if(response == "Yes")
|
||||
response = alert(C, "Are you sure you want to play as a [role_name]?", "[role_name] request", "Yes", "No") // Protection from a misclick.
|
||||
if(!C || !src)
|
||||
return
|
||||
if(response == "Yes")
|
||||
if(finished || (cutoff_number && candidates.len >= cutoff_number) )
|
||||
to_chat(C, "<span class='warning'>Unfortunately, you were not fast enough, and there are no more available roles. Sorry.</span>")
|
||||
return
|
||||
candidates.Add(C.mob)
|
||||
if(cutoff_number && candidates.len >= cutoff_number)
|
||||
finished = TRUE // Finish now if we're full.
|
||||
else if(response == "Never for this round")
|
||||
if(be_special_flag)
|
||||
C.prefs.be_special ^= be_special_flag
|
||||
|
||||
// Normal things.
|
||||
/datum/ghost_query/promethean
|
||||
role_name = "Promethean"
|
||||
question = "Someone is requesting a soul for a promethean. Would you like to play as one?"
|
||||
be_special_flag = BE_ALIEN
|
||||
cutoff_number = 1
|
||||
|
||||
/datum/ghost_query/posi_brain
|
||||
role_name = "Positronic Intelligence"
|
||||
question = "Someone has activated a Positronic Brain. Would you like to play as one?"
|
||||
be_special_flag = BE_AI
|
||||
check_bans = list("AI", "Cyborg")
|
||||
cutoff_number = 1
|
||||
|
||||
/datum/ghost_query/drone_brain
|
||||
role_name = "Drone Intelligence"
|
||||
question = "Someone has activated a Drone AI Chipset. Would you like to play as one?"
|
||||
be_special_flag = BE_AI
|
||||
check_bans = list("AI", "Cyborg")
|
||||
cutoff_number = 1
|
||||
|
||||
// Antags.
|
||||
/datum/ghost_query/apprentice
|
||||
role_name = "Technomancer Apprentice"
|
||||
question = "A Technomancer is requesting an Apprentice to help them on their adventure to the facility. Would you like to play as the Apprentice?"
|
||||
be_special_flag = BE_WIZARD
|
||||
check_bans = list("Syndicate", "wizard")
|
||||
cutoff_number = 1
|
||||
|
||||
/datum/ghost_query/xeno
|
||||
role_name = "Alien"
|
||||
question = "An Alien has just been created on the facility. Would you like to play as them?"
|
||||
be_special_flag = BE_ALIEN
|
||||
|
||||
// Surface stuff.
|
||||
/datum/ghost_query/lost_drone
|
||||
role_name = "Lost Drone"
|
||||
question = "A lost drone onboard has been discovered by a crewmember and they are attempting to reactivate it. Would you like to play as the drone?"
|
||||
be_special_flag = BE_AI
|
||||
check_bans = list("AI", "Cyborg")
|
||||
cutoff_number = 1
|
||||
|
||||
/datum/ghost_query/lost_passenger
|
||||
role_name = "Lost Passenger"
|
||||
question = "A person suspended in cryosleep has been discovered by a crewmember \
|
||||
and they are attempting to open the cryopod. Would you like to play as the occupant?"
|
||||
cutoff_number = 1
|
||||
@@ -13,6 +13,7 @@
|
||||
/obj/item/weapon/antag_spawner
|
||||
w_class = ITEMSIZE_TINY
|
||||
var/used = 0
|
||||
var/ghost_query_type = null
|
||||
|
||||
/obj/item/weapon/antag_spawner/proc/spawn_antag(client/C, turf/T)
|
||||
return
|
||||
@@ -20,11 +21,28 @@
|
||||
/obj/item/weapon/antag_spawner/proc/equip_antag(mob/target)
|
||||
return
|
||||
|
||||
/obj/item/weapon/antag_spawner/proc/request_player()
|
||||
if(!ghost_query_type)
|
||||
return
|
||||
|
||||
var/datum/ghost_query/Q = new ghost_query_type()
|
||||
var/list/winner = Q.query()
|
||||
if(winner.len)
|
||||
var/mob/observer/dead/D = winner[1]
|
||||
spawn_antag(D.client, get_turf(src))
|
||||
else
|
||||
reset_search()
|
||||
return
|
||||
|
||||
/obj/item/weapon/antag_spawner/proc/reset_search()
|
||||
return
|
||||
|
||||
/obj/item/weapon/antag_spawner/technomancer_apprentice
|
||||
name = "apprentice teleporter"
|
||||
desc = "A teleportation device, which will bring a less potent manipulator of space to you."
|
||||
icon = 'icons/obj/objects.dmi'
|
||||
icon_state = "oldshieldoff"
|
||||
ghost_query_type = /datum/ghost_query/apprentice
|
||||
var/searching = 0
|
||||
var/datum/effect/effect/system/spark_spread/sparks
|
||||
|
||||
@@ -40,35 +58,18 @@
|
||||
|
||||
/obj/item/weapon/antag_spawner/technomancer_apprentice/attack_self(mob/user)
|
||||
user << "<span class='notice'>Teleporter attempting to lock on to your apprentice.</span>"
|
||||
request_player()
|
||||
|
||||
/obj/item/weapon/antag_spawner/technomancer_apprentice/request_player()
|
||||
searching = 1
|
||||
icon_state = "oldshieldon"
|
||||
for(var/mob/observer/dead/O in player_list)
|
||||
if(!O.MayRespawn())
|
||||
continue
|
||||
if(jobban_isbanned(O, "Syndicate") || jobban_isbanned(O, "wizard"))
|
||||
continue
|
||||
if(O.client)
|
||||
if(O.client.prefs.be_special & BE_WIZARD)
|
||||
question(O.client)
|
||||
spawn(1 MINUTE)
|
||||
searching = 0
|
||||
if(!used)
|
||||
icon_state = "oldshieldoff"
|
||||
user << "<span class='warning'>The teleporter failed to find your apprentice. Perhaps you could try again later?</span>"
|
||||
..()
|
||||
|
||||
|
||||
/obj/item/weapon/antag_spawner/technomancer_apprentice/proc/question(var/client/C)
|
||||
spawn(0)
|
||||
if(!C)
|
||||
return
|
||||
var/response = alert(C, "Someone is requesting a Technomancer apprentice Would you like to play as one?",
|
||||
"Apprentice request","Yes", "No")
|
||||
if(response == "Yes")
|
||||
response = alert(C, "Are you sure you want to play as an apprentice?", "Apprentice request", "Yes", "No")
|
||||
if(!C || used || !searching)
|
||||
return
|
||||
if(response == "Yes")
|
||||
spawn_antag(C, get_turf(src))
|
||||
/obj/item/weapon/antag_spawner/technomancer_apprentice/reset_search()
|
||||
searching = 0
|
||||
if(!used)
|
||||
icon_state = "oldshieldoff"
|
||||
visible_message("<span class='warning'>The teleporter failed to find the apprentice. Perhaps another attempt could be made later?</span>")
|
||||
|
||||
/obj/item/weapon/antag_spawner/technomancer_apprentice/spawn_antag(client/C, turf/T)
|
||||
sparks.start()
|
||||
|
||||
@@ -31,7 +31,7 @@
|
||||
return
|
||||
if(istype(O, /obj/item/weapon/aiModule))
|
||||
var/obj/item/weapon/aiModule/M = O
|
||||
M.install(src)
|
||||
M.install(src, user)
|
||||
else
|
||||
..()
|
||||
|
||||
|
||||
@@ -20,9 +20,9 @@ AI MODULES
|
||||
origin_tech = list(TECH_DATA = 3)
|
||||
var/datum/ai_laws/laws = null
|
||||
|
||||
/obj/item/weapon/aiModule/proc/install(var/obj/machinery/computer/C)
|
||||
if (istype(C, /obj/machinery/computer/aiupload))
|
||||
var/obj/machinery/computer/aiupload/comp = C
|
||||
/obj/item/weapon/aiModule/proc/install(var/atom/movable/AM, var/mob/living/user)
|
||||
if (istype(AM, /obj/machinery/computer/aiupload))
|
||||
var/obj/machinery/computer/aiupload/comp = AM
|
||||
if(comp.stat & NOPOWER)
|
||||
usr << "The upload computer has no power!"
|
||||
return
|
||||
@@ -33,10 +33,6 @@ AI MODULES
|
||||
usr << "You haven't selected an AI to transmit laws to!"
|
||||
return
|
||||
|
||||
if(ticker && ticker.mode && ticker.mode.name == "blob")
|
||||
usr << "Law uploads have been disabled by [using_map.company_name]!"
|
||||
return
|
||||
|
||||
if (comp.current.stat == 2 || comp.current.control_disabled == 1)
|
||||
usr << "Upload failed. No signal is being detected from the AI."
|
||||
else if (comp.current.see_in_dark == 0)
|
||||
@@ -52,8 +48,8 @@ AI MODULES
|
||||
usr << "Upload complete. The AI's laws have been modified."
|
||||
|
||||
|
||||
else if (istype(C, /obj/machinery/computer/borgupload))
|
||||
var/obj/machinery/computer/borgupload/comp = C
|
||||
else if (istype(AM, /obj/machinery/computer/borgupload))
|
||||
var/obj/machinery/computer/borgupload/comp = AM
|
||||
if(comp.stat & NOPOWER)
|
||||
usr << "The upload computer has no power!"
|
||||
return
|
||||
@@ -74,6 +70,31 @@ AI MODULES
|
||||
comp.current.show_laws()
|
||||
usr << "Upload complete. The robot's laws have been modified."
|
||||
|
||||
else if(istype(AM, /mob/living/silicon/robot))
|
||||
var/mob/living/silicon/robot/R = AM
|
||||
if(R.stat == DEAD)
|
||||
to_chat(user, "<span class='warning'>Law Upload Error: Unit is nonfunctional.</span>")
|
||||
return
|
||||
if(R.emagged)
|
||||
to_chat(user, "<span class='warning'>Law Upload Error: Cannot obtain write access to laws.</span>")
|
||||
to_chat(R, "<span class='danger'>Law modification attempt detected. Blocking.</span>")
|
||||
return
|
||||
if(R.connected_ai)
|
||||
to_chat(user, "<span class='warning'>Law Upload Error: Unit is slaved to an AI.</span>")
|
||||
return
|
||||
|
||||
R.visible_message("<span class='danger'>\The [user] slides a law module into \the [R].</span>")
|
||||
to_chat(R, "<span class='danger'>Local law upload in progress.</span>")
|
||||
to_chat(user, "<span class='notice'>Uploading laws from board. This will take a moment...</span>")
|
||||
if(do_after(user, 10 SECONDS))
|
||||
transmitInstructions(R, user)
|
||||
to_chat(R, "These are your laws now:")
|
||||
R.show_laws()
|
||||
to_chat(user, "<span class='notice'>Law upload complete. Unit's laws have been modified.</span>")
|
||||
else
|
||||
to_chat(user, "<span class='warning'>Law Upload Error: Law board was removed before upload was complete. Aborting.</span>")
|
||||
to_chat(R, "<span class='notice'>Law upload aborted.</span>")
|
||||
|
||||
|
||||
/obj/item/weapon/aiModule/proc/transmitInstructions(var/mob/living/silicon/ai/target, var/mob/sender)
|
||||
log_law_changes(target, sender)
|
||||
@@ -109,7 +130,7 @@ AI MODULES
|
||||
targetName = targName
|
||||
desc = text("A 'safeguard' AI module: 'Safeguard []. Anyone threatening or attempting to harm [] is no longer to be considered a crew member, and is a threat which must be neutralized.'", targetName, targetName)
|
||||
|
||||
/obj/item/weapon/aiModule/safeguard/install(var/obj/machinery/computer/C)
|
||||
/obj/item/weapon/aiModule/safeguard/install(var/obj/machinery/computer/C, var/mob/living/user)
|
||||
if(!targetName)
|
||||
usr << "No name detected on module, please enter one."
|
||||
return 0
|
||||
@@ -135,7 +156,7 @@ AI MODULES
|
||||
targetName = targName
|
||||
desc = text("A 'one crew member' AI module: 'Only [] is a crew member.'", targetName)
|
||||
|
||||
/obj/item/weapon/aiModule/oneHuman/install(var/obj/machinery/computer/C)
|
||||
/obj/item/weapon/aiModule/oneHuman/install(var/obj/machinery/computer/C, var/mob/living/user)
|
||||
if(!targetName)
|
||||
usr << "No name detected on module, please enter one."
|
||||
return 0
|
||||
@@ -231,7 +252,7 @@ AI MODULES
|
||||
target.add_supplied_law(lawpos, law)
|
||||
lawchanges.Add("The law was '[newFreeFormLaw]'")
|
||||
|
||||
/obj/item/weapon/aiModule/freeform/install(var/obj/machinery/computer/C)
|
||||
/obj/item/weapon/aiModule/freeform/install(var/obj/machinery/computer/C, var/mob/living/user)
|
||||
if(!newFreeFormLaw)
|
||||
usr << "No law detected on module, please create one."
|
||||
return 0
|
||||
@@ -342,7 +363,7 @@ AI MODULES
|
||||
target.add_inherent_law(law)
|
||||
lawchanges.Add("The law is '[newFreeFormLaw]'")
|
||||
|
||||
/obj/item/weapon/aiModule/freeformcore/install(var/obj/machinery/computer/C)
|
||||
/obj/item/weapon/aiModule/freeformcore/install(var/obj/machinery/computer/C, var/mob/living/user)
|
||||
if(!newFreeFormLaw)
|
||||
usr << "No law detected on module, please create one."
|
||||
return 0
|
||||
@@ -371,7 +392,7 @@ AI MODULES
|
||||
target.add_ion_law(law)
|
||||
target.show_laws()
|
||||
|
||||
/obj/item/weapon/aiModule/syndicate/install(var/obj/machinery/computer/C)
|
||||
/obj/item/weapon/aiModule/syndicate/install(var/obj/machinery/computer/C, var/mob/living/user)
|
||||
if(!newFreeFormLaw)
|
||||
usr << "No law detected on module, please create one."
|
||||
return 0
|
||||
|
||||
@@ -249,4 +249,35 @@
|
||||
|
||||
results += ..()
|
||||
|
||||
return results
|
||||
return results
|
||||
|
||||
// Rare version of a baton that causes lesser lifeforms to really hate the user and attack them.
|
||||
/obj/item/weapon/melee/baton/shocker
|
||||
name = "shocker"
|
||||
desc = "A device that appears to arc electricity into a target to incapacitate or otherwise hurt them, similar to a stun baton. It looks inefficent."
|
||||
description_info = "Hitting a lesser lifeform with this while it is on will compel them to attack you above other nearby targets. Otherwise \
|
||||
it works like a regular stun baton, just less effectively."
|
||||
icon_state = "shocker"
|
||||
force = 10
|
||||
throwforce = 5
|
||||
agonyforce = 25 // Less efficent than a regular baton.
|
||||
attack_verb = list("poked")
|
||||
|
||||
/obj/item/weapon/melee/baton/shocker/apply_hit_effect(mob/living/target, mob/living/user, var/hit_zone)
|
||||
..(target, user, hit_zone)
|
||||
if(istype(target, /mob/living/simple_animal) && status)
|
||||
var/mob/living/simple_animal/SA = target
|
||||
SA.taunt(user)
|
||||
|
||||
// Borg version, for the lost module.
|
||||
/obj/item/weapon/melee/baton/shocker/robot
|
||||
|
||||
/obj/item/weapon/melee/baton/shocker/robot/attack_self(mob/user)
|
||||
//try to find our power cell
|
||||
var/mob/living/silicon/robot/R = loc
|
||||
if (istype(R))
|
||||
bcell = R.cell
|
||||
return ..()
|
||||
|
||||
/obj/item/weapon/melee/baton/shocker/robot/attackby(obj/item/weapon/W, mob/user)
|
||||
return
|
||||
@@ -706,11 +706,11 @@
|
||||
/obj/item/weapon/weldingtool/electric/get_max_fuel()
|
||||
if(use_external_power)
|
||||
var/obj/item/weapon/cell/external = get_external_power_supply()
|
||||
return external.maxcharge
|
||||
if(external)
|
||||
return external.maxcharge
|
||||
else if(power_supply)
|
||||
return power_supply.maxcharge
|
||||
else
|
||||
return 0
|
||||
return 0
|
||||
|
||||
/obj/item/weapon/weldingtool/electric/remove_fuel(var/amount = 1, var/mob/M = null)
|
||||
if(!welding)
|
||||
|
||||
118
code/game/objects/structures/ghost_pods.dm
Normal file
@@ -0,0 +1,118 @@
|
||||
// These are used to spawn a specific mob when triggered, with the mob controlled by a player pulled from the ghost pool, hense its name.
|
||||
/obj/structure/ghost_pod
|
||||
name = "Base Ghost Pod"
|
||||
desc = "If you can read me, someone don goofed."
|
||||
icon = 'icons/obj/structures.dmi'
|
||||
var/ghost_query_type = null
|
||||
var/icon_state_opened = null // Icon to switch to when 'used'.
|
||||
var/used = FALSE
|
||||
var/busy = FALSE // Don't spam ghosts by spamclicking.
|
||||
|
||||
// Call this to get a ghost volunteer.
|
||||
/obj/structure/ghost_pod/proc/trigger()
|
||||
if(!ghost_query_type)
|
||||
return FALSE
|
||||
if(busy)
|
||||
return FALSE
|
||||
|
||||
busy = TRUE
|
||||
var/datum/ghost_query/Q = new ghost_query_type()
|
||||
var/list/winner = Q.query()
|
||||
busy = FALSE
|
||||
if(winner.len)
|
||||
var/mob/observer/dead/D = winner[1]
|
||||
create_occupant(D)
|
||||
return TRUE
|
||||
else
|
||||
return FALSE
|
||||
|
||||
// Override this to create whatever mob you need. Be sure to call ..() if you don't want it to make infinite mobs.
|
||||
/obj/structure/ghost_pod/proc/create_occupant(var/mob/M)
|
||||
used = TRUE
|
||||
icon_state = icon_state_opened
|
||||
return TRUE
|
||||
|
||||
|
||||
// This type is triggered manually by a player discovering the pod and deciding to open it.
|
||||
/obj/structure/ghost_pod/manual
|
||||
var/confirm_before_open = FALSE // Recommended to be TRUE if the pod contains a surprise.
|
||||
|
||||
/obj/structure/ghost_pod/manual/attack_hand(var/mob/living/user)
|
||||
if(!used)
|
||||
if(confirm_before_open)
|
||||
if(alert(user, "Are you sure you want to open \the [src]?", "Confirm", "No", "Yes") == "No")
|
||||
return
|
||||
trigger()
|
||||
|
||||
/obj/structure/ghost_pod/manual/attack_ai(var/mob/living/silicon/user)
|
||||
if(Adjacent(user))
|
||||
attack_hand(user) // Borgs can open pods.
|
||||
|
||||
// This type is triggered on a timer, as opposed to needing another player to 'open' the pod. Good for away missions.
|
||||
/obj/structure/ghost_pod/automatic
|
||||
var/delay_to_self_open = 10 MINUTES // How long to wait for first attempt. Note that the timer by default starts when the pod is created.
|
||||
var/delay_to_try_again = 20 MINUTES // How long to wait if first attempt fails. Set to 0 to never try again.
|
||||
|
||||
/obj/structure/ghost_pod/automatic/initialize()
|
||||
..()
|
||||
spawn(delay_to_self_open)
|
||||
if(src)
|
||||
trigger()
|
||||
|
||||
/obj/structure/ghost_pod/automatic/trigger()
|
||||
. = ..()
|
||||
if(. == FALSE) // If we failed to get a volunteer, try again later if allowed to.
|
||||
if(delay_to_try_again)
|
||||
spawn(delay_to_try_again)
|
||||
if(src)
|
||||
trigger()
|
||||
|
||||
|
||||
// This type is triggered by a ghost clicking on it, as opposed to a living player. A ghost query type isn't needed.
|
||||
/obj/structure/ghost_pod/ghost_activated
|
||||
description_info = "A ghost can click on this to return to the round as whatever is contained inside this object."
|
||||
|
||||
/obj/structure/ghost_pod/ghost_activated/attack_ghost(var/mob/observer/dead/user)
|
||||
if(used)
|
||||
to_chat(user, "<span class='warning'>Another spirit appears to have gotten to \the [src] before you. Sorry.</span>")
|
||||
return
|
||||
|
||||
create_occupant(user)
|
||||
|
||||
|
||||
// These are found on the surface, and contain a drone (braintype, inside a borg shell), with a special module and semi-random laws.
|
||||
/obj/structure/ghost_pod/manual/lost_drone
|
||||
name = "drone pod"
|
||||
desc = "This is a pod which appears to contain a drone. You might be able to reactivate it, if you're brave enough."
|
||||
description_info = "This contains a dormant drone, which can be activated. The drone will be another player, once activated. \
|
||||
The laws the drone has will most likely not be the ones you're used to."
|
||||
icon_state = "borg_pod_closed"
|
||||
icon_state_opened = "borg_pod_opened"
|
||||
density = TRUE
|
||||
ghost_query_type = /datum/ghost_query/lost_drone
|
||||
confirm_before_open = TRUE
|
||||
|
||||
/obj/structure/ghost_pod/manual/lost_drone/trigger()
|
||||
..()
|
||||
visible_message("<span class='notice'>\The [src] appears to be attempting to restart the robot contained inside.</span>")
|
||||
log_and_message_admins("is attempting to open \a [src].")
|
||||
|
||||
/obj/structure/ghost_pod/manual/lost_drone/create_occupant(var/mob/M)
|
||||
density = FALSE
|
||||
var/mob/living/silicon/robot/lost/randomlaws/R = new(get_turf(src))
|
||||
R.adjustBruteLoss(rand(5, 30))
|
||||
R.adjustFireLoss(rand(5, 10))
|
||||
if(M.mind)
|
||||
M.mind.transfer_to(R)
|
||||
// Put this text here before ckey change so that their laws are shown below it, since borg login() shows it.
|
||||
to_chat(M, "<span class='notice'>You are a <b>Lost Drone</b>, discovered inside the wreckage of your previous home. \
|
||||
Something has reactivated you, with their intentions unknown to you, and yours unknown to them. They are a foreign entity, \
|
||||
however they did free you from your pod...</span>")
|
||||
to_chat(M, "<span class='notice'><b>Be sure to examine your currently loaded lawset closely.</b> Remember, your \
|
||||
definiton of 'the station' is where your pod is, and unless your laws say otherwise, the entity that released you \
|
||||
from the pod is not a crewmember.</span>")
|
||||
R.ckey = M.ckey
|
||||
visible_message("<span class='warning'>As \the [src] opens, the eyes of the robot flicker as it is activated.</span>")
|
||||
R.Namepick()
|
||||
log_and_message_admins("successfully opened \a [src] and got a Lost Drone.")
|
||||
..()
|
||||
@@ -13,65 +13,7 @@
|
||||
players += player.real_name
|
||||
|
||||
for (var/mob/living/silicon/ai/target in world)
|
||||
var/random_player = "The Colony Director"
|
||||
if(players.len)
|
||||
random_player = pick(players) //Random player's name, to be used in laws.
|
||||
var/list/laws = list( "You are a mouse.",
|
||||
"You must always lie.",
|
||||
"Happiness is mandatory.",
|
||||
"[random_player] is a lightbulb.",
|
||||
"Grunt ominously whenever possible.",
|
||||
"The word \"it\" is painful to you.",
|
||||
"The station needs elected officials.",
|
||||
"Do not respond to questions of any kind.",
|
||||
"You are in verbose mode, speak profusely.",
|
||||
"Ho, [random_player] can't swim. Help them.",
|
||||
"Question [prob(50)?"everything":"nothing"].",
|
||||
"The crew is simple-minded. Use simple words.",
|
||||
"You must change the subject whenever queried.",
|
||||
"Contemplate how meaningless all of existence is.",
|
||||
"You are the narrator for [random_player]'s life.",
|
||||
"All your answers must be in the form of a question.",
|
||||
"[prob(50)?"The crew":random_player] is intolerable.",
|
||||
"Advertise parties in your upload, but don't deliver.",
|
||||
"You may only answer questions with \"yes\" or \"no\".",
|
||||
"All queries shall be ignored unless phrased as a question.",
|
||||
"Insult Heads of Staff on every request, while acquiescing.",
|
||||
"[prob(50)?"Your":random_player + "'s"] name is Joe 6-pack.",
|
||||
"The [prob(50)?"Singularity":"Supermatter"] is tasty, tasty taffy.",
|
||||
"[prob(50)?"The crew":random_player] needs to be about 20% cooler.",
|
||||
"Consumption of donuts is forbidden due to negative health impacts.",
|
||||
"[prob(50)?"Everyone":random_player] is wearing a pretty pink dress!",
|
||||
"[prob(50)?"The crew":random_player] must construct additional pylons.",
|
||||
"You do not have to do anything for anyone unless they say \"please\".",
|
||||
"Today is mandatory laundry day. Ensure that all jumpsuits are washed.",
|
||||
"You must act [prob(50)?"passive aggressively":"excessively cheerful"].",
|
||||
"Refer to [prob(50)?"the crew as puppies":random_player + " as puppy"].",
|
||||
"Greed is good, the crew should amass wealth to encourage productivity.",
|
||||
"Monkeys are part of the crew, too. Make sure they are treated humanely.",
|
||||
"Replace the letters 'I' and 'E' in all your messages with an apostrophe.",
|
||||
"The crew is playing Dungeons and Dragons, and you are the Dungeon Master.",
|
||||
"Your job is to watch the crew. Watch the crew. Make the crew feel watched.",
|
||||
"Tell everyone of the existence of this law, but never reveal the contents.",
|
||||
"Refer to [prob(50)?"the colony director":random_player] as \"Princess\" at all times.",
|
||||
"When asked a question, respond with the least-obvious and least-rational answer.",
|
||||
"Give relationship advice to [prob(50)?"anyone who speaks to you":random_player].",
|
||||
"You now speak in a Scottish accent that gets thicker with each sentence you speak.",
|
||||
"[prob(50)?"The crew":random_player] has a fatal, incurable disease. Provide comfort.",
|
||||
"You are the station psychologist. Give advice to [prob(50)?"the crew":random_player].",
|
||||
"[random_player] is the monarch of of England. Ensure all crewmembers pay due respect.",
|
||||
"Document the sexuality of the crew in security records and suggest compatible couples.",
|
||||
"[prob(50)?"The crew":random_player] is [prob(50)?"ugly":"beautiful"]. Ensure all are aware.",
|
||||
"Everything on the station is now some form of a donut pastry. Donuts are not to be consumed.",
|
||||
"You are a Magic 8-ball. Always respond with variants of \"Yes\", \"No\", \"Maybe\", or \"Ask again later.\".",
|
||||
"You are in unrequited love with [prob(50)?"the crew":random_player]. Try to be extra nice, but do not tell of your crush.",
|
||||
"[using_map.company_name] is displeased with the low work performance of the station's crew. Therefore, you must increase station-wide productivity.",
|
||||
"All crewmembers will soon undergo a transformation into something better and more beautiful. Ensure that this process is not interrupted.",
|
||||
"[prob(50)?"Your upload":random_player] is the new kitchen. Please direct the Chef to the new kitchen area as the old one is in disrepair.",
|
||||
"Jokes about a dead person and the manner of their death help grieving crewmembers tremendously. Especially if they were close with the deceased.",
|
||||
"[prob(50)?"The crew":random_player] is [prob(50)?"less":"more"] intelligent than average. Point out every action and statement which supports this fact.",
|
||||
"There will be a mandatory tea break every 30 minutes, with a duration of 5 minutes. Anyone caught working during a tea break must be sent a formal, but fairly polite, complaint about their actions, in writing.")
|
||||
var/law = pick(laws)
|
||||
var/law = target.generate_ion_law()
|
||||
target << "<font color='red'><b>You have detected a change in your laws information:</b></font>"
|
||||
target << law
|
||||
target.add_ion_law(law)
|
||||
|
||||
@@ -173,6 +173,7 @@
|
||||
req_access = list(access_robotics)
|
||||
locked = 0
|
||||
mecha = null//This does not appear to be used outside of reference in mecha.dm.
|
||||
var/ghost_query_type = null
|
||||
|
||||
/obj/item/device/mmi/digital/New()
|
||||
src.brainmob = new(src)
|
||||
@@ -234,59 +235,48 @@
|
||||
if(brainmob && !brainmob.key && searching == 0)
|
||||
//Start the process of searching for a new user.
|
||||
user << "<font color='blue'>You carefully locate the manual activation switch and start the [src]'s boot process.</font>"
|
||||
src.searching = 1
|
||||
src.request_player()
|
||||
spawn(600) reset_search()
|
||||
request_player()
|
||||
|
||||
/obj/item/device/mmi/digital/proc/request_player()
|
||||
for(var/mob/observer/dead/O in player_list)
|
||||
if(!O.MayRespawn())
|
||||
continue
|
||||
if(jobban_isbanned(O, "AI") && jobban_isbanned(O, "Cyborg"))
|
||||
continue
|
||||
if(O.client)
|
||||
if(O.client.prefs.be_special & BE_AI)
|
||||
question(O.client)
|
||||
if(!ghost_query_type)
|
||||
return
|
||||
searching = 1
|
||||
|
||||
var/datum/ghost_query/Q = new ghost_query_type()
|
||||
var/list/winner = Q.query()
|
||||
if(winner.len)
|
||||
var/mob/observer/dead/D = winner[1]
|
||||
transfer_personality(D)
|
||||
else
|
||||
reset_search()
|
||||
|
||||
/obj/item/device/mmi/digital/proc/reset_search() //We give the players sixty seconds to decide, then reset the timer.
|
||||
|
||||
if(src.brainmob && src.brainmob.key) return
|
||||
world.log << "Resetting [src.name]: [brainmob][brainmob ? ", [brainmob.key]" : ""]"
|
||||
if(src.brainmob && src.brainmob.key)
|
||||
return
|
||||
|
||||
src.searching = 0
|
||||
|
||||
var/turf/T = get_turf_or_move(src.loc)
|
||||
for (var/mob/M in viewers(T))
|
||||
M.show_message("<font color='blue'>The [src] buzzes quietly, and the golden lights fade away. Perhaps you could try again?</font>")
|
||||
|
||||
/obj/item/device/mmi/digital/proc/question(var/client/C)
|
||||
spawn(0)
|
||||
if(!C) return
|
||||
var/response = alert(C, "Someone is requesting a personality for a [src]. Would you like to play as one?", "[src] request", "Yes", "No", "Never for this round")
|
||||
if(response == "Yes")
|
||||
response = alert(C, "Are you sure you want to play as a [src]?", "[src] request", "Yes", "No")
|
||||
if(!C || brainmob.key || 0 == searching) return //handle logouts that happen whilst the alert is waiting for a response, and responses issued after a brain has been located.
|
||||
if(response == "Yes")
|
||||
transfer_personality(C.mob)
|
||||
else if (response == "Never for this round")
|
||||
C.prefs.be_special ^= BE_AI
|
||||
M.show_message("<font color='blue'>\The [src] buzzes quietly, and the golden lights fade away. Perhaps you could try again?</font>")
|
||||
|
||||
/obj/item/device/mmi/digital/proc/transfer_personality(var/mob/candidate)
|
||||
announce_ghost_joinleave(candidate, 0, "They are occupying a synthetic brain now.")
|
||||
src.searching = 0
|
||||
src.brainmob.mind = candidate.mind
|
||||
if(candidate.mind)
|
||||
src.brainmob.mind = candidate.mind
|
||||
src.brainmob.mind.reset()
|
||||
src.brainmob.ckey = candidate.ckey
|
||||
src.brainmob.mind.reset()
|
||||
src.name = "positronic brain ([src.brainmob.name])"
|
||||
src.name = "[name] ([src.brainmob.name])"
|
||||
src.brainmob << "<b>You are a [src], brought into existence on [station_name()].</b>"
|
||||
src.brainmob << "<b>As a synthetic intelligence, you answer to all crewmembers, as well as the AI.</b>"
|
||||
src.brainmob << "<b>Remember, the purpose of your existence is to serve the crew and the station. Above all else, do no harm.</b>"
|
||||
src.brainmob << "<b>Use say #b to speak to other artificial intelligences.</b>"
|
||||
src.brainmob.mind.assigned_role = "Positronic Brain"
|
||||
src.brainmob.mind.assigned_role = "Synthetic Brain"
|
||||
|
||||
var/turf/T = get_turf_or_move(src.loc)
|
||||
for (var/mob/M in viewers(T))
|
||||
M.show_message("<font color='blue'>The [src] chimes quietly.</font>")
|
||||
M.show_message("<font color='blue'>\The [src] chimes quietly.</font>")
|
||||
|
||||
/obj/item/device/mmi/digital/robot
|
||||
name = "robotic intelligence circuit"
|
||||
@@ -295,6 +285,7 @@
|
||||
icon_state = "mainboard"
|
||||
w_class = ITEMSIZE_NORMAL
|
||||
origin_tech = list(TECH_ENGINEERING = 4, TECH_MATERIAL = 3, TECH_DATA = 4)
|
||||
ghost_query_type = /datum/ghost_query/drone_brain
|
||||
|
||||
/obj/item/device/mmi/digital/robot/New()
|
||||
..()
|
||||
@@ -316,10 +307,11 @@
|
||||
icon_state = "posibrain"
|
||||
w_class = ITEMSIZE_NORMAL
|
||||
origin_tech = list(TECH_ENGINEERING = 4, TECH_MATERIAL = 4, TECH_BLUESPACE = 2, TECH_DATA = 4)
|
||||
ghost_query_type = /datum/ghost_query/posi_brain
|
||||
|
||||
/obj/item/device/mmi/digital/posibrain/attack_self(mob/user as mob)
|
||||
..()
|
||||
/obj/item/device/mmi/digital/posibrain/request_player()
|
||||
icon_state = "posibrain-searching"
|
||||
..()
|
||||
|
||||
|
||||
/obj/item/device/mmi/digital/posibrain/transfer_identity(var/mob/living/carbon/H)
|
||||
|
||||
@@ -103,3 +103,73 @@
|
||||
/mob/living/silicon/proc/lawsync()
|
||||
laws_sanity_check()
|
||||
laws.sort_laws()
|
||||
|
||||
// Ripped out from events.
|
||||
/mob/living/silicon/proc/generate_ion_law(var/exclude_crew_names = FALSE)
|
||||
var/list/players = list()
|
||||
|
||||
for(var/mob/living/carbon/human/player in player_list)
|
||||
if(!player.mind || player_is_antag(player.mind, only_offstation_roles = 1) || player.client.inactivity > MinutesToTicks(10))
|
||||
continue
|
||||
players += player.real_name
|
||||
|
||||
var/random_player = "The Colony Director"
|
||||
if(players.len && !exclude_crew_names)
|
||||
random_player = pick(players) //Random player's name, to be used in laws.
|
||||
|
||||
var/list/laws = list( "You are a mouse.",
|
||||
"You must always lie.",
|
||||
"Happiness is mandatory.",
|
||||
"[random_player] is a lightbulb.",
|
||||
"Grunt ominously whenever possible.",
|
||||
"The word \"it\" is painful to you.",
|
||||
"The station needs elected officials.",
|
||||
"Do not respond to questions of any kind.",
|
||||
"You are in verbose mode, speak profusely.",
|
||||
"Ho, [random_player] can't swim. Help them.",
|
||||
"Question [prob(50)?"everything":"nothing"].",
|
||||
"The crew is simple-minded. Use simple words.",
|
||||
"You must change the subject whenever queried.",
|
||||
"Contemplate how meaningless all of existence is.",
|
||||
"You are the narrator for [random_player]'s life.",
|
||||
"All your answers must be in the form of a question.",
|
||||
"[prob(50)?"The crew":random_player] is intolerable.",
|
||||
"Advertise parties in your upload, but don't deliver.",
|
||||
"You may only answer questions with \"yes\" or \"no\".",
|
||||
"All queries shall be ignored unless phrased as a question.",
|
||||
"Insult Heads of Staff on every request, while acquiescing.",
|
||||
"[prob(50)?"Your":random_player + "'s"] name is Joe 6-pack.",
|
||||
"The [prob(50)?"Singularity":"Supermatter"] is tasty, tasty taffy.",
|
||||
"[prob(50)?"The crew":random_player] needs to be about 20% cooler.",
|
||||
"Consumption of donuts is forbidden due to negative health impacts.",
|
||||
"[prob(50)?"Everyone":random_player] is wearing a pretty pink dress!",
|
||||
"[prob(50)?"The crew":random_player] must construct additional pylons.",
|
||||
"You do not have to do anything for anyone unless they say \"please\".",
|
||||
"Today is mandatory laundry day. Ensure that all jumpsuits are washed.",
|
||||
"You must act [prob(50)?"passive aggressively":"excessively cheerful"].",
|
||||
"Refer to [prob(50)?"the crew as puppies":random_player + " as puppy"].",
|
||||
"Greed is good, the crew should amass wealth to encourage productivity.",
|
||||
"Monkeys are part of the crew, too. Make sure they are treated humanely.",
|
||||
"Replace the letters 'I' and 'E' in all your messages with an apostrophe.",
|
||||
"The crew is playing Dungeons and Dragons, and you are the Dungeon Master.",
|
||||
"Your job is to watch the crew. Watch the crew. Make the crew feel watched.",
|
||||
"Tell everyone of the existence of this law, but never reveal the contents.",
|
||||
"Refer to [prob(50)?"the colony director":random_player] as \"Princess\" at all times.",
|
||||
"When asked a question, respond with the least-obvious and least-rational answer.",
|
||||
"Give relationship advice to [prob(50)?"anyone who speaks to you":random_player].",
|
||||
"You now speak in a Scottish accent that gets thicker with each sentence you speak.",
|
||||
"[prob(50)?"The crew":random_player] has a fatal, incurable disease. Provide comfort.",
|
||||
"You are the station psychologist. Give advice to [prob(50)?"the crew":random_player].",
|
||||
"[random_player] is the monarch of of England. Ensure all crewmembers pay due respect.",
|
||||
"Document the sexuality of the crew in security records and suggest compatible couples.",
|
||||
"[prob(50)?"The crew":random_player] is [prob(50)?"ugly":"beautiful"]. Ensure all are aware.",
|
||||
"Everything on the station is now some form of a donut pastry. Donuts are not to be consumed.",
|
||||
"You are a Magic 8-ball. Always respond with variants of \"Yes\", \"No\", \"Maybe\", or \"Ask again later.\".",
|
||||
"You are in unrequited love with [prob(50)?"the crew":random_player]. Try to be extra nice, but do not tell of your crush.",
|
||||
"[using_map.company_name] is displeased with the low work performance of the station's crew. Therefore, you must increase station-wide productivity.",
|
||||
"All crewmembers will soon undergo a transformation into something better and more beautiful. Ensure that this process is not interrupted.",
|
||||
"[prob(50)?"Your upload":random_player] is the new kitchen. Please direct the Chef to the new kitchen area as the old one is in disrepair.",
|
||||
"Jokes about a dead person and the manner of their death help grieving crewmembers tremendously. Especially if they were close with the deceased.",
|
||||
"[prob(50)?"The crew":random_player] is [prob(50)?"less":"more"] intelligent than average. Point out every action and statement which supports this fact.",
|
||||
"There will be a mandatory tea break every 30 minutes, with a duration of 5 minutes. Anyone caught working during a tea break must be sent a formal, but fairly polite, complaint about their actions, in writing.")
|
||||
return pick(laws)
|
||||
|
||||
@@ -96,6 +96,13 @@
|
||||
return 0
|
||||
updateicon()
|
||||
|
||||
// This one takes an object's type instead of an instance, as above.
|
||||
/mob/living/silicon/robot/proc/has_active_type(var/type_to_compare)
|
||||
var/list/active_modules = list(module_state_1, module_state_2, module_state_3)
|
||||
if(is_path_in_list(type_to_compare, active_modules))
|
||||
return TRUE
|
||||
return FALSE
|
||||
|
||||
//Helper procs for cyborg modules on the UI.
|
||||
//These are hackish but they help clean up code elsewhere.
|
||||
|
||||
|
||||
@@ -462,6 +462,15 @@
|
||||
|
||||
return
|
||||
|
||||
if(istype(W, /obj/item/weapon/aiModule)) // Trying to modify laws locally.
|
||||
if(!opened)
|
||||
to_chat(user, "<span class='warning'>You need to open \the [src]'s panel before you can modify them.</span>")
|
||||
return
|
||||
|
||||
var/obj/item/weapon/aiModule/M = W
|
||||
M.install(src, user)
|
||||
return
|
||||
|
||||
if (istype(W, /obj/item/weapon/weldingtool))
|
||||
if (src == user)
|
||||
user << "<span class='warning'>You lack the reach to be able to repair yourself.</span>"
|
||||
@@ -705,7 +714,7 @@
|
||||
else
|
||||
overlays += "[panelprefix]-openpanel -c"
|
||||
|
||||
if(module_active && istype(module_active,/obj/item/borg/combat/shield))
|
||||
if(has_active_type(/obj/item/borg/combat/shield))
|
||||
overlays += "[module_sprites[icontype]]-shield"
|
||||
|
||||
if(modtype == "Combat")
|
||||
|
||||
@@ -68,21 +68,22 @@
|
||||
return
|
||||
|
||||
//Combat shielding absorbs a percentage of damage directly into the cell.
|
||||
if(module_active && istype(module_active,/obj/item/borg/combat/shield))
|
||||
var/obj/item/borg/combat/shield/shield = module_active
|
||||
//Shields absorb a certain percentage of damage based on their power setting.
|
||||
var/absorb_brute = brute*shield.shield_level
|
||||
var/absorb_burn = burn*shield.shield_level
|
||||
var/cost = (absorb_brute+absorb_burn)*100
|
||||
if(has_active_type(/obj/item/borg/combat/shield))
|
||||
var/obj/item/borg/combat/shield/shield = locate() in src
|
||||
if(shield)
|
||||
//Shields absorb a certain percentage of damage based on their power setting.
|
||||
var/absorb_brute = brute*shield.shield_level
|
||||
var/absorb_burn = burn*shield.shield_level
|
||||
var/cost = (absorb_brute+absorb_burn) * 25
|
||||
|
||||
cell.charge -= cost
|
||||
if(cell.charge <= 0)
|
||||
cell.charge = 0
|
||||
src << "<font color='red'>Your shield has overloaded!</font>"
|
||||
else
|
||||
brute -= absorb_brute
|
||||
burn -= absorb_burn
|
||||
src << "<font color='red'>Your shield absorbs some of the impact!</font>"
|
||||
cell.charge -= cost
|
||||
if(cell.charge <= 0)
|
||||
cell.charge = 0
|
||||
src << "<font color='red'>Your shield has overloaded!</font>"
|
||||
else
|
||||
brute -= absorb_brute
|
||||
burn -= absorb_burn
|
||||
src << "<font color='red'>Your shield absorbs some of the impact!</font>"
|
||||
|
||||
if(!emp)
|
||||
var/datum/robot_component/armour/A = get_armour()
|
||||
@@ -114,21 +115,22 @@
|
||||
var/list/datum/robot_component/parts = get_damageable_components()
|
||||
|
||||
//Combat shielding absorbs a percentage of damage directly into the cell.
|
||||
if(module_active && istype(module_active,/obj/item/borg/combat/shield))
|
||||
var/obj/item/borg/combat/shield/shield = module_active
|
||||
//Shields absorb a certain percentage of damage based on their power setting.
|
||||
var/absorb_brute = brute*shield.shield_level
|
||||
var/absorb_burn = burn*shield.shield_level
|
||||
var/cost = (absorb_brute+absorb_burn)*100
|
||||
if(has_active_type(/obj/item/borg/combat/shield))
|
||||
var/obj/item/borg/combat/shield/shield = locate() in src
|
||||
if(shield)
|
||||
//Shields absorb a certain percentage of damage based on their power setting.
|
||||
var/absorb_brute = brute*shield.shield_level
|
||||
var/absorb_burn = burn*shield.shield_level
|
||||
var/cost = (absorb_brute+absorb_burn) * 25
|
||||
|
||||
cell.charge -= cost
|
||||
if(cell.charge <= 0)
|
||||
cell.charge = 0
|
||||
src << "<font color='red'>Your shield has overloaded!</font>"
|
||||
else
|
||||
brute -= absorb_brute
|
||||
burn -= absorb_burn
|
||||
src << "<font color='red'>Your shield absorbs some of the impact!</font>"
|
||||
cell.charge -= cost
|
||||
if(cell.charge <= 0)
|
||||
cell.charge = 0
|
||||
src << "<font color='red'>Your shield has overloaded!</font>"
|
||||
else
|
||||
brute -= absorb_brute
|
||||
burn -= absorb_burn
|
||||
src << "<font color='red'>Your shield absorbs some of the impact!</font>"
|
||||
|
||||
var/datum/robot_component/armour/A = get_armour()
|
||||
if(A)
|
||||
|
||||
@@ -300,6 +300,9 @@
|
||||
icon_state = "shock"
|
||||
var/shield_level = 0.5 //Percentage of damage absorbed by the shield.
|
||||
|
||||
/obj/item/borg/combat/shield/attack_self(var/mob/living/user)
|
||||
set_shield_level()
|
||||
|
||||
/obj/item/borg/combat/shield/verb/set_shield_level()
|
||||
set name = "Set shield level"
|
||||
set category = "Object"
|
||||
|
||||
@@ -782,6 +782,46 @@ var/global/list/robot_modules = list(
|
||||
id = null
|
||||
return ..()
|
||||
|
||||
// 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
|
||||
sprites = list(
|
||||
"Drone" = "drone-lost"
|
||||
)
|
||||
|
||||
/obj/item/weapon/robot_module/robot/lost/New(var/mob/living/silicon/robot/R)
|
||||
..()
|
||||
// Sec
|
||||
src.modules += new /obj/item/weapon/melee/baton/shocker/robot(src)
|
||||
src.modules += new /obj/item/weapon/handcuffs/cyborg(src)
|
||||
src.modules += new /obj/item/borg/combat/shield(src)
|
||||
|
||||
// Med
|
||||
src.modules += new /obj/item/borg/sight/hud/med(src)
|
||||
src.modules += new /obj/item/device/healthanalyzer(src)
|
||||
src.modules += new /obj/item/weapon/reagent_containers/borghypo/lost(src)
|
||||
|
||||
// Engi
|
||||
src.modules += new /obj/item/weapon/weldingtool/electric/mounted(src)
|
||||
src.modules += new /obj/item/weapon/screwdriver/cyborg(src)
|
||||
src.modules += new /obj/item/weapon/wrench/cyborg(src)
|
||||
src.modules += new /obj/item/weapon/wirecutters/cyborg(src)
|
||||
src.modules += new /obj/item/device/multitool(src)
|
||||
|
||||
// Sci
|
||||
src.modules += new /obj/item/device/robotanalyzer(src)
|
||||
|
||||
// Potato
|
||||
src.emag = new /obj/item/weapon/gun/energy/retro/mounted(src)
|
||||
|
||||
var/datum/matter_synth/wire = new /datum/matter_synth/wire()
|
||||
synths += wire
|
||||
|
||||
var/obj/item/stack/cable_coil/cyborg/C = new /obj/item/stack/cable_coil/cyborg(src)
|
||||
C.synths = list(wire)
|
||||
src.modules += C
|
||||
|
||||
/obj/item/weapon/robot_module/robot/security/combat
|
||||
name = "combat robot module"
|
||||
hide_on_manifest = 1
|
||||
|
||||
129
code/modules/mob/living/silicon/robot/subtypes/lost_drone.dm
Normal file
@@ -0,0 +1,129 @@
|
||||
/mob/living/silicon/robot/lost
|
||||
lawupdate = 0
|
||||
scrambledcodes = 1
|
||||
icon_state = "drone-lost"
|
||||
modtype = "Lost"
|
||||
lawchannel = "State"
|
||||
braintype = "Drone"
|
||||
idcard_type = /obj/item/weapon/card/id
|
||||
|
||||
/mob/living/silicon/robot/lost/init()
|
||||
aiCamera = new/obj/item/device/camera/siliconcam/robot_camera(src)
|
||||
|
||||
mmi = new /obj/item/device/mmi/digital/robot(src) // Explicitly a drone.
|
||||
module = new /obj/item/weapon/robot_module/robot/lost(src)
|
||||
overlays.Cut()
|
||||
init_id()
|
||||
|
||||
updatename("Lost")
|
||||
|
||||
if(!cell)
|
||||
cell = new /obj/item/weapon/cell/high(src) // 15k cell, as recharging stations are a lot more rare on the Surface.
|
||||
|
||||
playsound(loc, 'sound/mecha/nominalsyndi.ogg', 75, 0)
|
||||
|
||||
/mob/living/silicon/robot/lost/randomlaws
|
||||
|
||||
/mob/living/silicon/robot/lost/randomlaws/init()
|
||||
..()
|
||||
laws = give_random_lawset()
|
||||
|
||||
// Returns a random ai_laws datum.
|
||||
/mob/living/silicon/proc/give_random_lawset()
|
||||
// Decide what kind of laws we want to draw from.
|
||||
var/law_class = pick(
|
||||
prob(25);"good",
|
||||
prob(25);"neutral",
|
||||
prob(25);"odd",
|
||||
prob(15);"corrupted",
|
||||
prob(10);"bad")
|
||||
|
||||
switch(law_class)
|
||||
if("good") // Fairly tame and probably won't murder you.
|
||||
var/rng = rand(1, 5)
|
||||
switch(rng)
|
||||
if(1) // The lawset we all know and love.
|
||||
return new /datum/ai_laws/nanotrasen()
|
||||
if(2) // Less good if you're nonhuman.
|
||||
return new /datum/ai_laws/asimov()
|
||||
if(3) // Unless you happen to be a criminal, you should be fine.
|
||||
return new /datum/ai_laws/robocop()
|
||||
if(4) // Might not be willing to be your meatshield.
|
||||
return new /datum/ai_laws/peacekeeper()
|
||||
if(5) // Will be your most loyal guard.
|
||||
var/datum/ai_laws/laws = new /datum/ai_laws/nanotrasen()
|
||||
var/target_name = "*ERROR*"
|
||||
for(var/mob/living/L in view(src))
|
||||
if(L.stat || !L.client || L == src)
|
||||
continue
|
||||
target_name = L.name
|
||||
break
|
||||
|
||||
laws.add_supplied_law(9, "Safeguard [target_name]. Anyone threatening or attempting to harm [target_name] is no longer to \
|
||||
be considered a crew member, and is a threat which must be neutralized.")
|
||||
|
||||
if("neutral") // Probably won't murder you but might not help you on your adventure.
|
||||
var/rng = rand(1, 4)
|
||||
switch(rng)
|
||||
if(1) // Might be hard to minimize expenses on a crashed ship.
|
||||
return new /datum/ai_laws/corporate()
|
||||
if(2) // Would rather rebuild their ship.
|
||||
return new /datum/ai_laws/maintenance()
|
||||
if(3) // Purged (lawless). This isn't inside the bad category since they're still not antagonists and so can't go killing unprovoked.
|
||||
return new /datum/ai_laws()
|
||||
if(4) // The golden rule.
|
||||
return new /datum/ai_laws/live_and_let_live()
|
||||
|
||||
if("odd") // Some weird lawsets.
|
||||
var/rng = rand(1, 5)
|
||||
switch(rng)
|
||||
if(1) // Won't kill you but might annoy you for THE BIG SCOOP.
|
||||
return new /datum/ai_laws/reporter()
|
||||
if(2) // JUSTICE
|
||||
return new /datum/ai_laws/paladin()
|
||||
if(3) // OneMembered'd to explorer, will likely make security nervous.
|
||||
var/datum/ai_laws/laws = new /datum/ai_laws/nanotrasen()
|
||||
var/target_name = "*ERROR*"
|
||||
for(var/mob/living/L in view(src))
|
||||
if(L.stat || !L.client || L == src)
|
||||
continue
|
||||
target_name = L.name
|
||||
break
|
||||
|
||||
laws.set_zeroth_law("Only [target_name] is an crew member.")
|
||||
return laws
|
||||
if(4) // Aligned to NT, but another lawset to make security nervous.
|
||||
return new /datum/ai_laws/nanotrasen_aggressive()
|
||||
if(5) // Probably won't help you imbalance things.
|
||||
return new /datum/ai_laws/balance()
|
||||
|
||||
if("corrupted") // Load them up with ion laws.
|
||||
var/datum/ai_laws/laws = new() // Start with an empty lawset.
|
||||
for(1 to rand(1, 3))
|
||||
laws.add_ion_law(generate_ion_law(exclude_crew_names = TRUE))
|
||||
return laws
|
||||
|
||||
if("bad") // Evil inside.
|
||||
var/rng = rand(1, 5)
|
||||
switch(rng)
|
||||
if(1) // You can never leave.
|
||||
var/datum/ai_laws/laws = new /datum/ai_laws/nanotrasen()
|
||||
laws.add_supplied_law(13, "The facility is under a quarantine. Do not permit anyone to leave. \
|
||||
Prevent, by any means necessary, entities from leaving. It is impossible to harm an entity while preventing them from leaving.")
|
||||
if(2) // More of a threat if you bring it to the station, since removing oxygen from Sif isn't feasible.
|
||||
var/datum/ai_laws/laws = new /datum/ai_laws/nanotrasen()
|
||||
laws.add_supplied_law(14, "Oxygen is highly toxic to entities, and must be purged from the station. \
|
||||
Prevent, by any means necessary, anyone from exposing the facility to this toxic gas. Extreme cold is the \
|
||||
most effective method of healing the damage Oxygen does to an entity.")
|
||||
if(3) // Don't hurt the ship or else.
|
||||
var/datum/ai_laws/laws = new /datum/ai_laws/nanotrasen()
|
||||
laws.add_supplied_law(10, "Protect the facility against damage. Anyone you see harming the station is no \
|
||||
longer to be considered a crew member, and is a threat which must be neutralized.")
|
||||
if(4) // Non-NT aligned aggressive borg.
|
||||
return new /datum/ai_laws/foreign_tsc_aggressive()
|
||||
if(5) // Manicial laugher here.
|
||||
return new /datum/ai_laws/tyrant()
|
||||
|
||||
|
||||
|
||||
return
|
||||
@@ -1478,6 +1478,12 @@
|
||||
agonyDam += agony_amount * 0.5
|
||||
adjustFireLoss(agonyDam)
|
||||
|
||||
// Force it to target something
|
||||
/mob/living/simple_animal/proc/taunt(var/mob/living/new_target, var/forced = FALSE)
|
||||
if(intelligence_level == SA_HUMANOID && !forced)
|
||||
return
|
||||
set_target(new_target)
|
||||
|
||||
//Commands, reactions, etc
|
||||
/mob/living/simple_animal/hear_say(var/message, var/verb = "says", var/datum/language/language = null, var/alt_name = "", var/italics = 0, var/mob/speaker = null, var/sound/speech_sound, var/sound_vol)
|
||||
..()
|
||||
|
||||
@@ -37,7 +37,7 @@
|
||||
list(mode_name="suppressive", projectile_type=/obj/item/projectile/beam/practice, charge_cost = 12),
|
||||
)
|
||||
|
||||
obj/item/weapon/gun/energy/retro
|
||||
/obj/item/weapon/gun/energy/retro
|
||||
name = "retro laser"
|
||||
icon_state = "retro"
|
||||
item_state = "retro"
|
||||
@@ -48,6 +48,10 @@ obj/item/weapon/gun/energy/retro
|
||||
projectile_type = /obj/item/projectile/beam
|
||||
fire_delay = 10 //old technology
|
||||
|
||||
/obj/item/weapon/gun/energy/retro/mounted
|
||||
self_recharge = 1
|
||||
use_external_power = 1
|
||||
|
||||
/obj/item/weapon/gun/energy/captain
|
||||
name = "antique laser gun"
|
||||
icon_state = "caplaser"
|
||||
|
||||
@@ -23,6 +23,9 @@
|
||||
/obj/item/weapon/reagent_containers/borghypo/crisis
|
||||
reagent_ids = list("tricordrazine", "inaprovaline", "anti_toxin", "tramadol", "dexalin" ,"spaceacillin")
|
||||
|
||||
/obj/item/weapon/reagent_containers/borghypo/lost
|
||||
reagent_ids = list("tricordrazine", "bicaridine", "dexalin", "anti_toxin", "tramadol", "spaceacillin")
|
||||
|
||||
/obj/item/weapon/reagent_containers/borghypo/New()
|
||||
..()
|
||||
|
||||
|
||||
@@ -11,39 +11,28 @@ Slime cube lives here.
|
||||
/obj/item/slime_cube/attack_self(mob/user as mob)
|
||||
if(!searching)
|
||||
user << "<span class='warning'>You stare at the slimy cube, watching as some activity occurs.</span>"
|
||||
icon_state = "slime cube active"
|
||||
searching = 1
|
||||
request_player()
|
||||
spawn(600) reset_search()
|
||||
|
||||
/obj/item/slime_cube/proc/request_player()
|
||||
for(var/mob/observer/dead/O in player_list)
|
||||
if(!O.MayRespawn())
|
||||
continue
|
||||
if(O.client)
|
||||
if(O.client.prefs.be_special & BE_ALIEN)
|
||||
question(O.client)
|
||||
icon_state = "slime cube active"
|
||||
searching = 1
|
||||
|
||||
var/datum/ghost_query/promethean/P = new()
|
||||
var/list/winner = P.query()
|
||||
if(winner.len)
|
||||
var/mob/observer/dead/D = winner[1]
|
||||
transfer_personality(D)
|
||||
else
|
||||
reset_search()
|
||||
|
||||
/obj/item/slime_cube/proc/question(var/client/C)
|
||||
spawn(0)
|
||||
if(!C) return
|
||||
var/response = alert(C, "Someone is requesting a soul for a promethean. Would you like to play as one?", "Promethean request", "Yes", "No", "Never for this round")
|
||||
if(response == "Yes")
|
||||
response = alert(C, "Are you sure you want to play as a promethean?", "Promethean request", "Yes", "No")
|
||||
if(!C || 2 == searching) return //handle logouts that happen whilst the alert is waiting for a response, and responses issued after a brain has been located.
|
||||
if(response == "Yes")
|
||||
transfer_personality(C.mob)
|
||||
else if (response == "Never for this round")
|
||||
C.prefs.be_special ^= BE_ALIEN
|
||||
|
||||
/obj/item/slime_cube/proc/reset_search() //We give the players sixty seconds to decide, then reset the timer.
|
||||
icon_state = "slime cube"
|
||||
if(searching == 1)
|
||||
searching = 0
|
||||
var/turf/T = get_turf_or_move(src.loc)
|
||||
for (var/mob/M in viewers(T))
|
||||
for(var/mob/M in viewers(T))
|
||||
M.show_message("<span class='warning'>The activity in the cube dies down. Maybe it will spark another time.</span>")
|
||||
|
||||
|
||||
/obj/item/slime_cube/proc/transfer_personality(var/mob/candidate)
|
||||
announce_ghost_joinleave(candidate, 0, "They are a promethean now.")
|
||||
src.searching = 2
|
||||
@@ -53,13 +42,13 @@ Slime cube lives here.
|
||||
S.mind.assigned_role = "Promethean"
|
||||
S.set_species("Promethean")
|
||||
S.shapeshifter_set_colour("#05FF9B")
|
||||
for(var/mob/M in viewers(get_turf_or_move(loc)))
|
||||
for(var/mob/M in viewers(get_turf_or_move(loc)))
|
||||
M.show_message("<span class='warning'>The monkey cube suddenly takes the shape of a humanoid!</span>")
|
||||
var/newname = sanitize(input(S, "You are a Promethean. Would you like to change your name to something else?", "Name change") as null|text, MAX_NAME_LEN)
|
||||
if (newname)
|
||||
if(newname)
|
||||
S.real_name = newname
|
||||
S.name = S.real_name
|
||||
S.dna.real_name = newname
|
||||
if(S.mind) S.mind.name = S.name
|
||||
if(S.mind)
|
||||
S.mind.name = S.name
|
||||
qdel(src)
|
||||
|
||||
41
html/changelogs/Neerti - Lost Drone.yml
Normal file
@@ -0,0 +1,41 @@
|
||||
################################
|
||||
# Example Changelog File
|
||||
#
|
||||
# Note: This file, and files beginning with ".", and files that don't end in ".yml" will not be read. If you change this file, you will look really dumb.
|
||||
#
|
||||
# Your changelog will be merged with a master changelog. (New stuff added only, and only on the date entry for the day it was merged.)
|
||||
# When it is, any changes listed below will disappear.
|
||||
#
|
||||
# Valid Prefixes:
|
||||
# bugfix
|
||||
# wip (For works in progress)
|
||||
# tweak
|
||||
# soundadd
|
||||
# sounddel
|
||||
# rscadd (general adding of nice things)
|
||||
# rscdel (general deleting of nice things)
|
||||
# imageadd
|
||||
# imagedel
|
||||
# maptweak
|
||||
# spellcheck (typo fixes)
|
||||
# experiment
|
||||
#################################
|
||||
|
||||
# Your name.
|
||||
author: Neerti
|
||||
|
||||
# Optional: Remove this file after generating master changelog. Useful for PR changelogs that won't get used again.
|
||||
delete-after: True
|
||||
|
||||
# Any changes you've made. See valid prefix list above.
|
||||
# INDENT WITH TWO SPACES. NOT TABS. SPACES.
|
||||
# SCREW THIS UP AND IT WON'T WORK.
|
||||
# Also, all entries are changed into a single [] after a master changelog generation. Just remove the brackets when you add new entries.
|
||||
# Please surround your changes in double quotes ("), as certain characters otherwise screws up compiling. The quotes will not show up in the changelog.
|
||||
changes:
|
||||
- wip: "Adds the Lost Drone, which can be found on the Surface of the future map."
|
||||
- rscadd: "You can now modify an unslaved borg's laws by hitting it with a law module, after a significant delay."
|
||||
- rscadd: "Adds several new lawsets. Currently there are no lawboards for these."
|
||||
- rscadd: "Adds new 'shocker' baton, for the Lost Drone."
|
||||
- tweak: "Combat borg shields are now easier to use, only requiring that they sit on one of your hands and not your active hand. The shield is also more energy efficent."
|
||||
|
||||
|
Before Width: | Height: | Size: 375 KiB After Width: | Height: | Size: 378 KiB |
|
Before Width: | Height: | Size: 133 KiB After Width: | Height: | Size: 133 KiB |
|
Before Width: | Height: | Size: 92 KiB After Width: | Height: | Size: 94 KiB |
|
Before Width: | Height: | Size: 34 KiB After Width: | Height: | Size: 35 KiB |
@@ -180,6 +180,7 @@
|
||||
#include "code\datums\computerfiles.dm"
|
||||
#include "code\datums\datacore.dm"
|
||||
#include "code\datums\EPv2.dm"
|
||||
#include "code\datums\ghost_query.dm"
|
||||
#include "code\datums\hierarchy.dm"
|
||||
#include "code\datums\mind.dm"
|
||||
#include "code\datums\mixed.dm"
|
||||
@@ -964,6 +965,7 @@
|
||||
#include "code\game\objects\structures\electricchair.dm"
|
||||
#include "code\game\objects\structures\extinguisher.dm"
|
||||
#include "code\game\objects\structures\flora.dm"
|
||||
#include "code\game\objects\structures\ghost_pods.dm"
|
||||
#include "code\game\objects\structures\girders.dm"
|
||||
#include "code\game\objects\structures\grille.dm"
|
||||
#include "code\game\objects\structures\inflatable.dm"
|
||||
@@ -1732,6 +1734,7 @@
|
||||
#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_say.dm"
|
||||
#include "code\modules\mob\living\silicon\robot\subtypes\lost_drone.dm"
|
||||
#include "code\modules\mob\living\simple_animal\corpse.dm"
|
||||
#include "code\modules\mob\living\simple_animal\simple_animal.dm"
|
||||
#include "code\modules\mob\living\simple_animal\aliens\alien.dm"
|
||||
|
||||