Merge pull request #3902 from Neerti/9/19/2017_lost_drone

Adds the Lost Drone
This commit is contained in:
Anewbe
2017-09-22 15:24:05 -05:00
committed by GitHub
28 changed files with 812 additions and 196 deletions

View File

@@ -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)

View File

@@ -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
View 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

View File

@@ -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()

View File

@@ -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
..()

View File

@@ -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

View File

@@ -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

View File

@@ -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)

View 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.")
..()

View File

@@ -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)

View File

@@ -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)

View File

@@ -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)

View File

@@ -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.

View File

@@ -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")

View File

@@ -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)

View File

@@ -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"

View File

@@ -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

View 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

View File

@@ -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)
..()

View File

@@ -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"

View File

@@ -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()
..()

View File

@@ -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)

View 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."

Binary file not shown.

Before

Width:  |  Height:  |  Size: 375 KiB

After

Width:  |  Height:  |  Size: 378 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 133 KiB

After

Width:  |  Height:  |  Size: 133 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 92 KiB

After

Width:  |  Height:  |  Size: 94 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 34 KiB

After

Width:  |  Height:  |  Size: 35 KiB

View File

@@ -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"