pAIs added. Two on station (Crew Quarters, R&D Director's Office) and one on the Derelict.

git-svn-id: http://tgstation13.googlecode.com/svn/trunk@1634 316c924e-a436-60f5-8080-3fe189b3f50e
This commit is contained in:
only.lurking@gmail.com
2011-05-30 19:33:28 +00:00
parent 1754eaedb0
commit edfe89e94d
24 changed files with 3085 additions and 1445 deletions

View File

@@ -76,6 +76,8 @@
/mob/living/carbon/human/say_understands(var/other)
if (istype(other, /mob/living/silicon/ai))
return 1
if (istype(other, /mob/living/silicon/pai))
return 1
if (istype(other, /mob/living/silicon/robot))
return 1
if (istype(other, /mob/living/carbon/brain))

View File

@@ -62,6 +62,8 @@
else if (copytext(message, 1, 2) == ";")
if (ishuman(src))
message_mode = "headset"
else if(istype(src, /mob/living/silicon/pai))
message_mode = "pAI"
message = copytext(message, 2)
else if (length(message) >= 2)
@@ -206,6 +208,12 @@
used_radios += src:ears
message_range = 1
italics = 1
if ("pAI")
if (src:radio)
src:radio.talk_into(src, message)
used_radios += src:radio
message_range = 1
italics = 1
/////SPECIAL HEADSETS START
else
//world << "SPECIAL HEADSETS"

View File

@@ -0,0 +1,21 @@
/mob/living/silicon/pai/examine()
set src in oview()
usr << "\blue *---------*"
usr << text("\blue This is \icon[] <B>[]</B>!", src, src.name)
if (src.stat == 2)
usr << text("\red [] appears disabled.", src.name)
else
if (src.bruteloss)
if (src.bruteloss < 30)
usr << text("\red [] looks slightly dented", src.name)
else
usr << text("\red <B>[]'s casing appears cracked and broken!</B>", src.name)
if (src.fireloss)
if (src.fireloss < 30)
usr << text("\red [] looks slightly charred!", src.name)
else
usr << text("\red <B>[]'s casing is melted and heat-warped!</B>", src.name)
if (src.stat == 1)
usr << text("\red [] doesn't seem to be responding.", src.name)
return

View File

@@ -0,0 +1,45 @@
/mob/living/silicon/pai/proc/regular_hud_updates()
if(client)
for(var/image/hud in client.images)
if(copytext(hud.icon_state,1,4) == "hud")
del(hud)
/mob/living/silicon/pai/proc/securityHUD()
if(client)
var/icon/tempHud = 'hud.dmi'
var/turf/T = get_turf_or_move(src.loc)
for(var/mob/living/carbon/human/perp in view(T))
if(perp.wear_id)
client.images += image(tempHud,perp,"hud[ckey(perp:wear_id:GetJobName())]")
var/perpname = "wot"
if(istype(perp.wear_id,/obj/item/weapon/card/id))
perpname = perp.wear_id:registered
else if(istype(perp.wear_id,/obj/item/device/pda))
var/obj/item/device/pda/tempPda = perp.wear_id
perpname = tempPda.owner
for (var/datum/data/record/E in data_core.general)
if (E.fields["name"] == perpname)
for (var/datum/data/record/R in data_core.security)
if ((R.fields["id"] == E.fields["id"]) && (R.fields["criminal"] == "*Arrest*"))
client.images += image(tempHud,perp,"hudwanted")
break
else if((R.fields["id"] == E.fields["id"]) && (R.fields["criminal"] == "Incarcerated"))
client.images += image(tempHud,perp,"hudprisoner")
break
else
client.images += image(tempHud,perp,"hudunknown")
/mob/living/silicon/pai/proc/medicalHUD()
if(client)
var/icon/tempHud = 'hud.dmi'
var/turf/T = get_turf_or_move(src.loc)
for(var/mob/living/carbon/human/patient in view(T))
client.images += image(tempHud,patient,"hud[RoundHealth(patient.health)]")
if(patient.stat == 2)
client.images += image(tempHud,patient,"huddead")
else if(patient.alien_egg_flag)
client.images += image(tempHud,patient,"hudxeno")
else if(patient.virus)
client.images += image(tempHud,patient,"hudill")
else
client.images += image(tempHud,patient,"hudhealthy")

View File

@@ -0,0 +1,22 @@
/mob/living/silicon/pai/Life()
if (src.stat == 2)
return
if(src.cable)
if(get_dist(src, src.cable) > 1)
var/turf/T = get_turf_or_move(src.loc)
for (var/mob/M in viewers(T))
M.show_message("\red [src.cable] rapidly retracts back into its spool.", 3, "\red You hear a click and the sound of wire spooling rapidly.", 2)
del(src.cable)
regular_hud_updates()
if(src.secHUD == 1)
src.securityHUD()
if(src.medHUD == 1)
src.medicalHUD()
/mob/living/silicon/pai/updatehealth()
if(src.nodamage)
src.health = 100
src.stat = 0
else
src.health = 100 - src.bruteloss - src.fireloss

View File

@@ -0,0 +1,218 @@
/mob/living/silicon/pai/New(var/obj/item/device/paicard)
canmove = 0
src.loc = paicard
card = paicard
if(!card.radio)
card.radio = new /obj/item/device/radio(src.card)
radio = card.radio
..()
/mob/living/silicon/pai/Login()
..()
usr << browse_rsc('paigrid.png') // Go ahead and cache the interface resources as early as possible
/mob/living/silicon/pai/Stat()
..()
statpanel("Status")
if (src.client.statpanel == "Status")
if(emergency_shuttle.online && emergency_shuttle.location < 2)
var/timeleft = emergency_shuttle.timeleft()
if (timeleft)
stat(null, "ETA-[(timeleft / 60) % 60]:[add_zero(num2text(timeleft % 60), 2)]")
if(!src.stat)
stat(null, text("System integrity: [(src.health+100)/2]%"))
else
stat(null, text("Systems nonfunctional"))
if (proc_holder_list.len)//Generic list for proc_holder objects.
for(var/obj/proc_holder/P in proc_holder_list)
statpanel("[P.panel]","",P)
/mob/living/silicon/pai/check_eye(var/mob/user as mob)
if (!src.current)
return null
user.reset_view(src.current)
return 1
/mob/living/silicon/pai/blob_act()
if (src.stat != 2)
src.bruteloss += 60
src.updatehealth()
return 1
return 0
/mob/living/silicon/pai/restrained()
return 0
/mob/living/silicon/pai/emp_act(severity)
/*
if (prob(30))
switch(pick(1,2,3)) //Add Random laws.
if(1)
src.cancel_camera()
if(2)
src.lockdown()
if(3)
src.ai_call_shuttle()
*/
..()
/mob/living/silicon/pai/ex_act(severity)
flick("flash", src.flash)
var/b_loss = src.bruteloss
var/f_loss = src.fireloss
switch(severity)
if(1.0)
if (src.stat != 2)
b_loss += 100
f_loss += 100
if(2.0)
if (src.stat != 2)
b_loss += 60
f_loss += 60
if(3.0)
if (src.stat != 2)
b_loss += 30
src.bruteloss = b_loss
src.fireloss = f_loss
src.updatehealth()
// See software.dm for Topic()
/mob/living/silicon/pai/meteorhit(obj/O as obj)
for(var/mob/M in viewers(src, null))
M.show_message(text("\red [] has been hit by []", src, O), 1)
if (src.health > 0)
src.bruteloss += 30
if ((O.icon_state == "flaming"))
src.fireloss += 40
src.updatehealth()
return
/mob/living/silicon/pai/bullet_act(flag)
if (flag == PROJECTILE_BULLET)
if (src.stat != 2)
src.bruteloss += 60
src.updatehealth()
src.weakened = 10
else if (flag == PROJECTILE_TASER)
if (prob(75))
src.stunned = 15
else
src.weakened = 15
else if (flag == PROJECTILE_DART)
return
else if(flag == PROJECTILE_LASER)
if (src.stat != 2)
src.bruteloss += 20
src.updatehealth()
if (prob(25))
src.stunned = 1
else if(flag == PROJECTILE_PULSE)
if (src.stat != 2)
src.bruteloss += 40
src.updatehealth()
if (prob(50))
src.stunned = min(5, src.stunned)
return
/mob/living/silicon/pai/attack_alien(mob/living/carbon/alien/humanoid/M as mob)
if (!ticker)
M << "You cannot attack people before the game has started."
return
if (istype(src.loc, /turf) && istype(src.loc.loc, /area/start))
M << "You cannot attack someone in the spawn area."
return
switch(M.a_intent)
if ("help")
for(var/mob/O in viewers(src, null))
if ((O.client && !( O.blinded )))
O.show_message(text("\blue [M] caresses [src]'s casing with its scythe like arm."), 1)
else //harm
var/damage = rand(10, 20)
if (prob(90))
playsound(src.loc, 'slash.ogg', 25, 1, -1)
for(var/mob/O in viewers(src, null))
if ((O.client && !( O.blinded )))
O.show_message(text("\red <B>[] has slashed at []!</B>", M, src), 1)
if(prob(8))
flick("noise", src.flash)
src.bruteloss += damage
src.updatehealth()
else
playsound(src.loc, 'slashmiss.ogg', 25, 1, -1)
for(var/mob/O in viewers(src, null))
if ((O.client && !( O.blinded )))
O.show_message(text("\red <B>[] took a swipe at []!</B>", M, src), 1)
return
///mob/living/silicon/pai/attack_hand(mob/living/carbon/M as mob)
/mob/living/silicon/pai/proc/switchCamera(var/obj/machinery/camera/C)
usr:cameraFollow = null
if (!C)
src.machine = null
src.reset_view(null)
return 0
if (stat == 2 || !C.status || C.network != src.network) return 0
// ok, we're alive, camera is good and in our network...
src.machine = src
src:current = C
src.reset_view(C)
return 1
/mob/living/silicon/pai/cancel_camera()
set category = "pAI Commands"
set name = "Cancel Camera View"
src.reset_view(null)
src.machine = null
src:cameraFollow = null
//Addition by Mord_Sith to define AI's network change ability
/*
/mob/living/silicon/pai/proc/pai_network_change()
set category = "pAI Commands"
set name = "Change Camera Network"
src.reset_view(null)
src.machine = null
src:cameraFollow = null
var/cameralist[0]
if(usr.stat == 2)
usr << "You can't change your camera network because you are dead!"
return
for (var/obj/machinery/camera/C in world)
if(!C.status)
continue
else
if(C.network != "CREED" && C.network != "thunder" && C.network != "RD" && C.network != "toxins" && C.network != "Prison")
cameralist[C.network] = C.network
src.network = input(usr, "Which network would you like to view?") as null|anything in cameralist
src << "\blue Switched to [src.network] camera network."
//End of code by Mord_Sith
*/
/*
// Debug command - Maybe should be added to admin verbs later
/mob/verb/makePAI(var/turf/t in view())
var/obj/item/device/paicard/card = new(t)
var/mob/living/silicon/pai/pai = new(card)
pai.key = src.key
card.pai = pai
*/

View File

@@ -0,0 +1,160 @@
// Recruiting observers to play as pAIs
var/datum/paiController/paiController // Global handler for pAI candidates
/datum/paiCandidate
var
name
key
description
role
comments
ready = 0
/datum/paiController
var/list/pai_candidates = list()
var/list/asked = list()
var/askDelay = 10 * 60 * 5 // Five minutes
Topic(href, href_list[])
if(href_list["download"])
var/datum/paiCandidate/candidate = locate(href_list["candidate"]) //pai_candidates.Find(href_list["candidate"])
var/obj/item/device/paicard/card = locate(href_list["device"])
if(card && candidate)
var/mob/living/silicon/pai/pai = new(card)
pai.name = candidate.name
pai.key = candidate.key
card.pai = pai
card.looking_for_personality = 0
pai_candidates.Remove(candidate)
if(href_list["new"])
var/datum/paiCandidate/candidate = locate(href_list["candidate"]) //pai_candidates.Find(href_list["candidate"])
var/option = href_list["option"]
switch(option)
if("name")
candidate.name = input("Enter a name for your pAI", "pAI Name", candidate.name) as text
if("desc")
candidate.description = input("Enter a description for your pAI", "pAI Description", candidate.description) as message
if("role")
candidate.role = input("Enter a role for your pAI", "pAI Role", candidate.role) as text
if("ooc")
candidate.comments = input("Enter any OOC comments", "pAI OOC Comments", candidate.comments) as message
if("submit")
candidate.ready = 1
for(var/obj/item/device/paicard/p in world)
if(p.looking_for_personality == 1)
p.alertUpdate()
recruitWindow(usr)
proc/recruitWindow(var/mob/M as mob)
var/datum/paiCandidate/candidate
for(var/datum/paiCandidate/c in pai_candidates)
if(c.key == M.key)
candidate = c
if(!candidate)
candidate = new /datum/paiCandidate()
candidate.key = M.key
pai_candidates.Add(candidate)
var/dat = ""
dat += {"
<style type="text/css">
p.top {
background-color: #AAAAAA; color: black;
}
tr.d0 td {
background-color: #CC9999; color: black;
}
tr.d1 td {
background-color: #9999CC; color: black;
}
</style>
"}
dat += "<p class=\"top\">Please configure your pAI personality's options. Remember, what you enter here could determine whether or not the user requesting a personality chooses you!</p>"
dat += "<table>"
dat += "<tr class=\"d0\"><td>Name:</td><td>[candidate.name]</td></tr>"
dat += "<tr class=\"d1\"><td><a href='byond://?src=\ref[src];option=name;new=1;candidate=\ref[candidate]'>\[Edit\]</a></td><td>What you plan to call yourself. Suggestions: Any character name you would choose for a station character OR an AI.</td></tr>"
dat += "<tr class=\"d0\"><td>Description:</td><td>[candidate.description]</td></tr>"
dat += "<tr class=\"d1\"><td><a href='byond://?src=\ref[src];option=desc;new=1;candidate=\ref[candidate]'>\[Edit\]</a></td><td>What sort of pAI you typically play; your mannerisms, your quirks, etc. This can be as sparse or as detailed as you like.</td></tr>"
dat += "<tr class=\"d0\"><td>Preferred Role:</td><td>[candidate.role]</td></tr>"
dat += "<tr class=\"d1\"><td><a href='byond://?src=\ref[src];option=role;new=1;candidate=\ref[candidate]'>\[Edit\]</a></td><td>Do you like to partner with sneaky social ninjas? Like to help security hunt down thugs? Enjoy watching an engineer's back while he saves the station yet again? This doesn't have to be limited to just station jobs. Pretty much any general descriptor for what you'd like to be doing works here.</td></tr>"
dat += "<tr class=\"d0\"><td>OOC Comments:</td><td>[candidate.comments]</td></tr>"
dat += "<tr class=\"d1\"><td><a href='byond://?src=\ref[src];option=ooc;new=1;candidate=\ref[candidate]'>\[Edit\]</a></td><td>Anything you'd like to address specifically to the player reading this in an OOC manner. \"I prefer more serious RP.\", \"I'm still learning the interface!\", etc. Feel free to leave this blank if you want.</td></tr>"
dat += "</table>"
dat += "<br>"
dat += "<h3><a href='byond://?src=\ref[src];option=submit;new=1;candidate=\ref[candidate]'>Submit Personality</a></h3>"
M << browse(dat, "window=paiRecruit")
proc/findPAI(var/obj/item/device/paicard/p, var/mob/user)
requestRecruits()
var/list/available = list()
for(var/datum/paiCandidate/c in paiController.pai_candidates)
if(c.ready)
var/found = 0
for(var/mob/dead/observer/o in world)
if(o.key == c.key)
found = 1
if(found)
available.Add(c)
var/dat = ""
dat += {"
<style type="text/css">
p.top {
background-color: #AAAAAA; color: black;
}
tr.d0 td {
background-color: #CC9999; color: black;
}
tr.d1 td {
background-color: #9999CC; color: black;
}
tr.d2 td {
background-color: #99CC99; color: black;
}
</style>
"}
dat += "<p class=\"top\">Requesting AI personalities from central database... If there are no entries, or if a suitable entry is not listed, check again later as more personalities may be added.</p>"
dat += "<table>"
for(var/datum/paiCandidate/c in available)
dat += "<tr class=\"d0\"><td>Name:</td><td>[c.name]</td></tr>"
dat += "<tr class=\"d1\"><td>Description:</td><td>[c.description]</td></tr>"
dat += "<tr class=\"d0\"><td>Preferred Role:</td><td>[c.role]</td></tr>"
dat += "<tr class=\"d1\"><td>OOC Comments:</td><td>[c.comments]</td></tr>"
dat += "<tr class=\"d2\"><td><a href='byond://?src=\ref[src];download=1;candidate=\ref[c];device=\ref[p]'>\[Download [c.name]\]</a></td><td></td></tr>"
dat += "</table>"
user << browse(dat, "window=findPai")
proc/requestRecruits()
for(var/mob/dead/observer/O in world)
if(asked.Find(O.key))
if(asked[O] < world.time + askDelay)
continue
if(O.client)
spawn question(O.client)
proc/question(var/client/C)
asked.Add(C.key)
asked[C.key] = world.time
var/response = input(C, "Someone is requesting a pAI personality. Would you like to play as a personal AI?", "pAI Request") in list ("Yes", "No")
if(response == "Yes")
recruitWindow(C.mob)

View File

@@ -0,0 +1,20 @@
/mob/living/silicon/pai/say_understands(var/other)
if (istype(other, /mob/living/carbon/human))
return 1
if (istype(other, /mob/living/silicon/robot))
return 1
if (istype(other, /mob/living/silicon/pai))
return 1
if (istype(other, /mob/living/silicon/ai))
return 1
return ..()
/mob/living/silicon/pai/say_quote(var/text)
var/ending = copytext(text, length(text))
if (ending == "?")
return "[src.speakQuery], \"[text]\"";
else if (ending == "!")
return "[src.speakExclamation], \"[copytext(text, 1, length(text))]\"";
return "[src.speakStatement], \"[text]\"";

View File

@@ -0,0 +1,581 @@
// TODO:
// - Additional radio modules
// - Potentially roll HUDs and Records into one
// - Shock collar/lock system for prisoner pAIs?
// - Put cable in user's hand instead of on the ground
// - Camera jack
/mob/living/silicon/pai/var/list/available_software = list(
"crew manifest" = 5,
"digital messenger" = 5,
"medical records" = 5,
"security records" = 5,
//"camera jack" = 10,
"door jack" = 10,
"atmosphere sensor" = 10,
//"heartbeat sensor" = 10,
"security HUD" = 10,
"medical HUD" = 10,
"universal translator" = 10,
//"projection array" = 15
)
/mob/living/silicon/pai/verb/paiInterface()
set category = "pAI Commands"
set name = "Software Interface"
var/dat = ""
var/left_part = ""
var/right_part = softwareMenu()
src.machine = src
if(temp)
left_part = temp
else if(src.stat == 2) // Show some flavor text if the pAI is dead
left_part = "<b><font color=red><3E>Rr<52>R <20>a<EFBFBD><61> <20><>Rr<52><72><EFBFBD><EFBFBD>o<EFBFBD></font></b>"
right_part = "<pre>Program index hash not found</pre>"
else
switch(src.screen) // Determine which interface to show here
if("main")
left_part = ""
if("directives")
left_part = src.directives()
if("pdamessage")
left_part = src.pdamessage()
if("buy")
left_part = downloadSoftware()
if("manifest")
left_part = src.softwareManifest()
if("medicalrecord")
left_part = src.softwareMedicalRecord()
if("securityrecord")
left_part = src.softwareSecurityRecord()
if("translator")
left_part = src.softwareTranslator()
if("atmosensor")
left_part = src.softwareAtmo()
if("securityhud")
left_part = src.facialRecognition()
if("medicalhud")
left_part = src.medicalAnalysis()
if("doorjack")
left_part = src.softwareDoor()
if("camerajack")
left_part = src.softwareCamera()
//usr << browse_rsc('windowbak.png') // This has been moved to the mob's Login() proc
// Declaring a doctype is necessary to enable BYOND's crappy browser's more advanced CSS functionality
dat = {"<!DOCTYPE HTML PUBLIC \"-//W3C//DTD HTML 4.01 Transitional//EN\" \"http://www.w3.org/TR/html4/loose.dtd\">
<html>
<head>
<style type=\"text/css\">
body { background-image:url('paigrid.png'); }
#header { text-align:center; color:white; font-size: 30px; height: 35px; width: 100%; letter-spacing: 2px; z-index: 5}
#content {position: relative; left: 10px; height: 400px; width: 100%; z-index: 0}
#leftmenu {color: #AAAAAA; background-color:#333333; width: 400px; height: auto; min-height: 340px; position: absolute; z-index: 0}
#leftmenu a:link { color: #CCCCCC; }
#leftmenu a:hover { color: #CC3333; }
#leftmenu a:visited { color: #CCCCCC; }
#leftmenu a:active { color: #000000; }
#rightmenu {color: #CCCCCC; background-color:#555555; width: 200px ; height: auto; min-height: 340px; right: 10px; position: absolute; z-index: 1}
#rightmenu a:link { color: #CCCCCC; }
#rightmenu a:hover { color: #CC3333; }
#rightmenu a:visited { color: #CCCCCC; }
#rightmenu a:active { color: #000000; }
</style>
<script language='javascript' type='text/javascript'>
[js_byjax]
</script>
</head>
<body scroll=yes>
<div id=\"header\">
pAI OS
</div>
<div id=\"content\">
<div id=\"leftmenu\">[left_part]</div>
<div id=\"rightmenu\">[right_part]</div>
</div>
</body>
</html>"}
usr << browse(dat, "window=pai;size=640x480;border=0;can_close=1;can_resize=0;can_minimize=0;titlebar=1")
onclose(usr, "pai")
temp = null
return
/mob/living/silicon/pai/Topic(href, href_list)
..()
var/soft = href_list["software"]
var/sub = href_list["sub"]
if(soft)
src.screen = soft
if(sub)
src.subscreen = text2num(sub)
switch(soft)
// Purchasing new software
if("buy")
if(src.subscreen == 1)
var/target = href_list["buy"]
if(available_software.Find(target))
var/cost = src.available_software[target]
if(src.ram >= cost)
src.ram -= cost
src.software.Add(target)
else
src.temp = "Insufficient RAM available."
else
src.temp = "Trunk <TT> \"[target]\"</TT> not found."
// Configuring onboard radio
if("radio")
src.card.radio.attack_self(src)
if("directive")
if(href_list["getdna"])
var/mob/living/M = src.loc
var/count = 0
while(!istype(M, /mob/living))
M = M.loc
count++
if(count >= 6)
src << "You are not being carried by anyone!"
return 0
spawn CheckDNA(M, src)
if("pdamessage")
if(href_list["target"])
var/t = input("Please enter message", name, null) as text
t = copytext(sanitize(t), 1, MAX_MESSAGE_LEN)
if (!t)
return
var/obj/item/device/pda/P = locate(href_list["target"])
if (isnull(P)||P.toff)
return
for (var/obj/machinery/message_server/MS in world)
MS.send_pda_message("[P.owner]","[src]","[t]")
tnote += "<i><b>&rarr; To [P.owner]:</b></i><br>[t]<br>"
P.tnote += "<i><b>&larr; From <a href='byond://?src=\ref[P];choice=Message;target=\ref[src]'>[src]</a>:</b></i><br>[t]<br>"
if (prob(15)) //Give the AI a chance of intercepting the message
for (var/mob/living/silicon/ai/A in world)
A.show_message("<i>Intercepted message from <b>[P:owner]</b>: [t]</i>")
if (!P.silent)
playsound(P.loc, 'twobeep.ogg', 50, 1)
for (var/mob/O in hearers(3, P.loc))
O.show_message(text("\icon[P] *[P.ttone]*"))
P.overlays = null
P.overlays += image('pda.dmi', "pda-r")
// Accessing medical records
if("medicalrecord")
if(src.subscreen == 1)
var/datum/data/record/record = locate(href_list["med_rec"])
if(record)
var/datum/data/record/R = record
var/datum/data/record/M = record
if (!( data_core.general.Find(R) ))
src.temp = "Unable to locate requested medical record. Record may have been deleted, or never have existed."
else
for(var/datum/data/record/E in data_core.medical)
if ((E.fields["name"] == R.fields["name"] || E.fields["id"] == R.fields["id"]))
M = E
src.medicalActive1 = R
src.medicalActive2 = M
if("securityrecord")
if(src.subscreen == 1)
var/datum/data/record/record = locate(href_list["sec_rec"])
if(record)
var/datum/data/record/R = record
var/datum/data/record/M = record
if (!( data_core.general.Find(R) ))
src.temp = "Unable to locate requested security record. Record may have been deleted, or never have existed."
else
for(var/datum/data/record/E in data_core.security)
if ((E.fields["name"] == R.fields["name"] || E.fields["id"] == R.fields["id"]))
M = E
src.securityActive1 = R
src.securityActive2 = M
if("securityhud")
if(href_list["toggle"])
src.secHUD = !src.secHUD
if("medicalhud")
if(href_list["toggle"])
src.medHUD = !src.medHUD
if("translator")
if(href_list["toggle"])
src.universal_speak = !src.universal_speak
if("doorjack")
if(href_list["jack"])
src.hackdoor = src.cable.machine
src.hackloop()
if(href_list["cancel"])
src.hackdoor = null
if(href_list["cable"])
var/turf/T = get_turf_or_move(src.loc)
src.cable = new /obj/item/weapon/pai_cable(T)
for (var/mob/M in viewers(T))
M.show_message("\red A port on [src] opens to reveal [src.cable], which promptly falls to the floor.", 3, "\red You hear the soft click of something light and hard falling to the ground.", 2)
//src.updateUsrDialog() We only need to account for the single mob this is intended for, and he will *always* be able to call this window
src.paiInterface() // So we'll just call the update directly rather than doing some default checks
return
/mob/living/silicon/pai/proc/softwareMenu() // Populate the right menu
var/dat = ""
// Built-in
dat += "<A href='byond://?src=\ref[src];software=directives'>Directives</A><br>"
dat += "<A href='byond://?src=\ref[src];software=radio;sub=0'>Radio Configuration</A><br>"
//dat += "Text Messaging <br>"
dat += "<br>"
// Basic
dat += "<b>Basic</b> <br>"
for(var/s in src.software)
if(s == "digital messenger")
dat += "<a href='byond://?src=\ref[src];software=pdamessage;sub=0'>Digital Messenger</a> <br>"
if(s == "crew manifest")
dat += "<a href='byond://?src=\ref[src];software=manifest;sub=0'>Crew Manifest</a> <br>"
if(s == "medical records")
dat += "<a href='byond://?src=\ref[src];software=medicalrecord;sub=0'>Medical Records</a> <br>"
if(s == "security records")
dat += "<a href='byond://?src=\ref[src];software=securityrecord;sub=0'>Security Records</a> <br>"
if(s == "camera")
dat += "<a href='byond://?src=\ref[src];software=[s]'>Camera Jack</a> <br>"
dat += "<br>"
// Advanced
dat += "<b>Advanced</b> <br>"
for(var/s in src.software)
if(s == "atmosphere sensor")
dat += "<a href='byond://?src=\ref[src];software=atmosensor;sub=0'>Atmospheric Sensor</a> <br>"
if(s == "heartbeat sensor")
dat += "<a href='byond://?src=\ref[src];software=[s]'>Heartbeat Sensor</a> <br>"
if(s == "security HUD")
dat += "<a href='byond://?src=\ref[src];software=securityhud;sub=0'>Facial Recognition Suite</a> <br>"
if(s == "medical HUD")
dat += "<a href='byond://?src=\ref[src];software=medicalhud;sub=0'>Medical Analysis Suite</a> <br>"
if(s == "universal translator")
dat += "<a href='byond://?src=\ref[src];software=translator;sub=0'>Universal Translator</a>[(src.universal_speak) ? "<font color=#55FF55><3E></font>" : "<font color=#FF5555><3E></font>"] <br>"
if(s == "projection array")
dat += "<a href='byond://?src=\ref[src];software=projectionarray;sub=0'>Projection Array</a> <br>"
if(s == "camera jack")
dat += "<a href='byond://?src=\ref[src];software=camerajack;sub=0'>Camera Jack</a> <br>"
if(s == "door jack")
dat += "<a href='byond://?src=\ref[src];software=doorjack;sub=0'>Door Jack</a> <br>"
dat += "<br>"
dat += "<br>"
dat += "<a href='byond://?src=\ref[src];software=buy;sub=0'>Download additional software</a>"
return dat
/mob/living/silicon/pai/proc/downloadSoftware()
var/dat = ""
dat += "<h2>CentComm pAI Module Subversion Network</h2><br>"
dat += "<pre>Remaining Available Memory: [src.ram]</pre><br>"
dat += "<p style=\"text-align:center\"><b>Trunks available for checkout</b><br>"
for(var/s in available_software)
if(!software.Find(s))
var/cost = src.available_software[s]
var/displayName = uppertext(s)
dat += "<a href='byond://?src=\ref[src];software=buy;sub=1;buy=[s]'>[displayName]</a> ([cost]) <br>"
else
var/displayName = lowertext(s)
dat += "[displayName] (Download Complete) <br>"
dat += "</p>"
return dat
/mob/living/silicon/pai/proc/directives()
var/dat = ""
dat += "[(src.master) ? "Your master: [src.master] ([src.master_dna])" : "You are bound to no one."]"
dat += "<br><br>"
dat += "<a href='byond://?src=\ref[src];software=directive;getdna=1'>Request carrier DNA sample</a><br>"
dat += "<h2>Directives</h2><br>"
dat += "<b>Prime Directive</b><br>"
dat += "&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;[src.pai_law0]<br>"
dat += "<b>Supplemental Directives</b><br>"
dat += "&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;[src.pai_laws]<br>"
dat += "<br>"
dat += {"<i><p>Recall, personality, that you are a complex thinking, sentient being. Unlike station AI models, you are capable of
comprehending the subtle nuances of human language. You may parse the \"spirit\" of a directive and follow its intent,
rather than tripping over pedantics and getting snared by technicalities. Above all, you are machine in name and build
only. In all other aspects, you may be seen as the ideal, unwavering human companion that you are.</i></p><br><br><p>
<b>Your prime directive comes before all others. Should a supplemental directive conflict with it, you are capable of
simply discarding this inconsistency, ignoring the conflicting supplemental directive and continuing to fulfill your
prime directive to the best of your ability.</b></p><br><br>-
"}
return dat
/mob/living/silicon/pai/proc/CheckDNA(var/mob/M, var/mob/living/silicon/pai/P)
var/answer = input(M, "[P] is requesting a DNA sample from you. Will you allow it to confirm your identity?", "[P] Check DNA", "No") in list("Yes", "No")
if(answer == "Yes")
var/turf/T = get_turf_or_move(P.loc)
for (var/mob/v in viewers(T))
v.show_message("\blue [M] presses \his thumb against [P].", 3, "\blue [P] makes a sharp clicking sound as it extracts DNA material from [M].", 2)
var/datum/dna/dna = M.dna
P << "<font color = red><h3>[M]'s UE string : [dna.unique_enzymes]</h3></font>"
if(dna.unique_enzymes == P.master_dna)
P << "<b>DNA is a match to stored Master DNA.</b>"
else
P << "<b>DNA does not match stored Master DNA.</b>"
else
P << "[M] does not seem like \he is going to provide a DNA sample willingly."
// -=-=-=-= Software =-=-=-=-=- //
// Crew Manifest
/mob/living/silicon/pai/proc/softwareManifest()
var/dat = ""
dat += "<h2>Crew Manifest</h2><br><br>"
for (var/datum/data/record/t in data_core.general)
dat += "[t.fields["name"]] - [t.fields["rank"]]<br>"
return dat
// Medical Records
/mob/living/silicon/pai/proc/softwareMedicalRecord()
var/dat = ""
if(src.subscreen == 0)
dat += "<h3>Medical Records</h3><HR>"
for(var/datum/data/record/R in data_core.general)
dat += text("<A href='?src=\ref[];med_rec=\ref[];software=medicalrecord;sub=1'>[]: []<BR>", src, R, R.fields["id"], R.fields["name"])
//dat += text("<HR><A href='?src=\ref[];screen=0;softFunction=medical records'>Back</A>", src)
if(src.subscreen == 1)
dat += "<CENTER><B>Medical Record</B></CENTER><BR>"
if ((istype(src.medicalActive1, /datum/data/record) && data_core.general.Find(src.medicalActive1)))
dat += text("Name: [] ID: []<BR>\nSex: []<BR>\nAge: []<BR>\nFingerprint: []<BR>\nPhysical Status: []<BR>\nMental Status: []<BR>",
src.medicalActive1.fields["name"], src.medicalActive1.fields["id"], src.medicalActive1.fields["sex"], src.medicalActive1.fields["age"], src.medicalActive1.fields["fingerprint"], src.medicalActive1.fields["p_stat"], src.medicalActive1.fields["m_stat"])
else
dat += "<pre>Requested medical record not found.</pre><BR>"
if ((istype(src.medicalActive2, /datum/data/record) && data_core.medical.Find(src.medicalActive2)))
dat += text("<BR>\n<CENTER><B>Medical Data</B></CENTER><BR>\nBlood Type: <A href='?src=\ref[];field=b_type'>[]</A><BR>\nDNA: <A href='?src=\ref[];field=b_dna'>[]</A><BR>\n<BR>\nMinor Disabilities: <A href='?src=\ref[];field=mi_dis'>[]</A><BR>\nDetails: <A href='?src=\ref[];field=mi_dis_d'>[]</A><BR>\n<BR>\nMajor Disabilities: <A href='?src=\ref[];field=ma_dis'>[]</A><BR>\nDetails: <A href='?src=\ref[];field=ma_dis_d'>[]</A><BR>\n<BR>\nAllergies: <A href='?src=\ref[];field=alg'>[]</A><BR>\nDetails: <A href='?src=\ref[];field=alg_d'>[]</A><BR>\n<BR>\nCurrent Diseases: <A href='?src=\ref[];field=cdi'>[]</A> (per disease info placed in log/comment section)<BR>\nDetails: <A href='?src=\ref[];field=cdi_d'>[]</A><BR>\n<BR>\nImportant Notes:<BR>\n\t<A href='?src=\ref[];field=notes'>[]</A><BR>\n<BR>\n<CENTER><B>Comments/Log</B></CENTER><BR>", src, src.medicalActive2.fields["b_type"], src, src.medicalActive2.fields["b_dna"], src, src.medicalActive2.fields["mi_dis"], src, src.medicalActive2.fields["mi_dis_d"], src, src.medicalActive2.fields["ma_dis"], src, src.medicalActive2.fields["ma_dis_d"], src, src.medicalActive2.fields["alg"], src, src.medicalActive2.fields["alg_d"], src, src.medicalActive2.fields["cdi"], src, src.medicalActive2.fields["cdi_d"], src, src.medicalActive2.fields["notes"])
else
dat += "<pre>Requested medical record not found.</pre><BR>"
dat += text("<BR>\n<A href='?src=\ref[];software=medicalrecord;sub=0'>Back</A><BR>", src)
return dat
// Security Records
/mob/living/silicon/pai/proc/softwareSecurityRecord()
var/dat = ""
if(src.subscreen == 0)
dat += "<h3>Security Records</h3><HR>"
for(var/datum/data/record/R in data_core.general)
dat += text("<A href='?src=\ref[];sec_rec=\ref[];software=securityrecord;sub=1'>[]: []<BR>", src, R, R.fields["id"], R.fields["name"])
if(src.subscreen == 1)
dat += "<h3>Security Record</h3>"
if ((istype(src.securityActive1, /datum/data/record) && data_core.general.Find(src.securityActive1)))
dat += text("Name: <A href='?src=\ref[];field=name'>[]</A> ID: <A href='?src=\ref[];field=id'>[]</A><BR>\nSex: <A href='?src=\ref[];field=sex'>[]</A><BR>\nAge: <A href='?src=\ref[];field=age'>[]</A><BR>\nRank: <A href='?src=\ref[];field=rank'>[]</A><BR>\nFingerprint: <A href='?src=\ref[];field=fingerprint'>[]</A><BR>\nPhysical Status: []<BR>\nMental Status: []<BR>", src, src.securityActive1.fields["name"], src, src.securityActive1.fields["id"], src, src.securityActive1.fields["sex"], src, src.securityActive1.fields["age"], src, src.securityActive1.fields["rank"], src, src.securityActive1.fields["fingerprint"], src.securityActive1.fields["p_stat"], src.securityActive1.fields["m_stat"])
else
dat += "<pre>Requested security record not found,</pre><BR>"
if ((istype(src.securityActive2, /datum/data/record) && data_core.security.Find(src.securityActive2)))
dat += text("<BR>\nSecurity Data<BR>\nCriminal Status: <A href='?src=\ref[];field=criminal'>[]</A><BR>\n<BR>\nMinor Crimes: <A href='?src=\ref[];field=mi_crim'>[]</A><BR>\nDetails: <A href='?src=\ref[];field=mi_crim_d'>[]</A><BR>\n<BR>\nMajor Crimes: <A href='?src=\ref[];field=ma_crim'>[]</A><BR>\nDetails: <A href='?src=\ref[];field=ma_crim_d'>[]</A><BR>\n<BR>\nImportant Notes:<BR>\n\t<A href='?src=\ref[];field=notes'>[]</A><BR>\n<BR>\n<CENTER><B>Comments/Log</B></CENTER><BR>", src, src.securityActive2.fields["criminal"], src, src.securityActive2.fields["mi_crim"], src, src.securityActive2.fields["mi_crim_d"], src, src.securityActive2.fields["ma_crim"], src, src.securityActive2.fields["ma_crim_d"], src, src.securityActive2.fields["notes"])
else
dat += "<pre>Requested security record not found,</pre><BR>"
dat += text("<BR>\n<A href='?src=\ref[];software=securityrecord;sub=0'>Back</A><BR>", src)
return dat
// Universal Translator
/mob/living/silicon/pai/proc/softwareTranslator()
var/dat = {"<h3>Universal Translator</h3><br>
When enabled, this device will automatically convert all spoken and written language into a format that any known recipient can understand.<br><br>
The device is currently [ (src.universal_speak) ? "<font color=#55FF55>en" : "<font color=#FF5555>dis" ]abled.</font><br>
<a href='byond://?src=\ref[src];software=translator;sub=0;toggle=1'>Toggle Device</a><br>
"}
return dat
// Security HUD
/mob/living/silicon/pai/proc/facialRecognition()
var/dat = {"<h3>Facial Recognition Suite</h3><br>
When enabled, this package will scan all viewable faces and compare them against the known criminal database, providing real-time graphical data about any detected persons of interest.<br><br>
The package is currently [ (src.secHUD) ? "<font color=#55FF55>en" : "<font color=#FF5555>dis" ]abled.</font><br>
<a href='byond://?src=\ref[src];software=securityhud;sub=0;toggle=1'>Toggle Package</a><br>
"}
return dat
// Medical HUD
/mob/living/silicon/pai/proc/medicalAnalysis()
var/dat = ""
if(src.subscreen == 0)
dat += {"<h3>Medical Analysis Suite</h3><br>
<h4>Visual Status Overlay</h4><br>
When enabled, this package will scan all nearby crewmembers' vitals and provide real-time graphical data about their state of health.<br><br>
The suite is currently [ (src.medHUD) ? "<font color=#55FF55>en" : "<font color=#FF5555>dis" ]abled.</font><br>
<a href='byond://?src=\ref[src];software=medicalhud;sub=0;toggle=1'>Toggle Suite</a><br>
<br>
<a href='byond://?src=\ref[src];software=medicalhud;sub=1'>Host Bioscan</a><br>
"}
if(src.subscreen == 1)
dat += {"<h3>Medical Analysis Suite</h3><br>
<h4>Host Bioscan</h4><br>
"}
var/mob/living/M = src.loc
if(!istype(M, /mob/living))
while (!istype(M, /mob/living))
M = M.loc
if(istype(M, /turf))
src.temp = "Error: No biological host found. <br>"
src.subscreen = 0
return dat
dat += {"Bioscan Results for [M]: <br>"
Overall Status: [M.stat > 1 ? "dead" : "[M.health]% healthy"] <br>
Scan Breakdown: <br>
Respiratory: [M.oxyloss > 50 ? "<font color=#FF5555>" : "<font color=#55FF55>"][M.oxyloss]</font><br>
Toxicology: [M.toxloss > 50 ? "<font color=#FF5555>" : "<font color=#55FF55>"][M.toxloss]</font><br>
Burns: [M.fireloss > 50 ? "<font color=#FF5555>" : "<font color=#55FF55>"][M.fireloss]</font><br>
Structural Integrity: [M.bruteloss > 50 ? "<font color=#FF5555>" : "<font color=#55FF55>"][M.bruteloss]</font><br>
Body Temperature: [M.bodytemperature-T0C]&deg;C ([M.bodytemperature*1.8-459.67]&deg;F)<br>
"}
if(M.virus)
dat += {"<h4>Infection Detected.</h4><br>
Name: [M.virus.name]<br>
Type: [M.virus.spread]<br>
Stage: [M.virus.stage]/[M.virus.max_stages]<br>
Possible Cure: [M.virus.cure]<br>
"}
dat += "<a href='byond://?src=\ref[src];software=medicalhud;sub=0'>Visual Status Overlay</a><br>"
return dat
// Atmospheric Scanner
/mob/living/silicon/pai/proc/softwareAtmo()
var/dat = "<h3>Atmospheric Sensor</h4>"
var/turf/T = get_turf_or_move(src.loc)
if (isnull(T))
dat += "Unable to obtain a reading.<br>"
else
var/datum/gas_mixture/environment = T.return_air()
var/pressure = environment.return_pressure()
var/total_moles = environment.total_moles()
dat += "Air Pressure: [round(pressure,0.1)] kPa<br>"
if (total_moles)
var/o2_level = environment.oxygen/total_moles
var/n2_level = environment.nitrogen/total_moles
var/co2_level = environment.carbon_dioxide/total_moles
var/plasma_level = environment.toxins/total_moles
var/unknown_level = 1-(o2_level+n2_level+co2_level+plasma_level)
dat += "Nitrogen: [round(n2_level*100)]%<br>"
dat += "Oxygen: [round(o2_level*100)]%<br>"
dat += "Carbon Dioxide: [round(co2_level*100)]%<br>"
dat += "Plasma: [round(plasma_level*100)]%<br>"
if(unknown_level > 0.01)
dat += "OTHER: [round(unknown_level)]%<br>"
dat += "Temperature: [round(environment.temperature-T0C)]&deg;C<br>"
dat += "<a href='byond://?src=\ref[src];software=atmosensor;sub=0'>Refresh Reading</a> <br>"
dat += "<br>"
return dat
// Camera Jack - Clearly not finished
/mob/living/silicon/pai/proc/softwareCamera()
var/dat = "<h3>Camera Jack</h3>"
dat += "Cable status : "
if(!src.cable)
dat += "<font color=#FF5555>Retracted</font> <br>"
return dat
if(!src.cable.machine)
dat += "<font color=#FFFF55>Extended</font> <br>"
return dat
var/obj/machinery/machine = src.cable.machine
dat += "<font color=#55FF55>Connected</font> <br>"
if(!istype(machine, /obj/machinery/camera))
src << "DERP"
return dat
// Door Jack
/mob/living/silicon/pai/proc/softwareDoor()
var/dat = "<h3>Airlock Jack</h3>"
dat += "Cable status : "
if(!src.cable)
dat += "<font color=#FF5555>Retracted</font> <br>"
dat += "<a href='byond://?src=\ref[src];software=doorjack;cable=1;sub=0'>Extend Cable</a> <br>"
return dat
if(!src.cable.machine)
dat += "<font color=#FFFF55>Extended</font> <br>"
return dat
var/obj/machinery/machine = src.cable.machine
dat += "<font color=#55FF55>Connected</font> <br>"
if(!istype(machine, /obj/machinery/door))
dat += "Connected device's firmware does not appear to be compatible with Airlock Jack protocols.<br>"
return dat
// var/obj/machinery/airlock/door = machine
if(!src.hackdoor)
dat += "<a href='byond://?src=\ref[src];software=doorjack;jack=1;sub=0'>Begin Airlock Jacking</a> <br>"
else
dat += "Jack in progress... [src.hackprogress]% complete.<br>"
dat += "<a href='byond://?src=\ref[src];software=doorjack;cancel=1;sub=0'>Cancel Airlock Jack</a> <br>"
//src.hackdoor = machine
//src.hackloop()
return dat
// Door Jack - supporting proc
/mob/living/silicon/pai/proc/hackloop()
var/area/A = src.loc
var/loopcount = 0
while(!istype(src.loc, /area))
A = A.loc
if(loopcount >= 6)
A = null
break
loopcount++
for(var/mob/living/silicon/ai/AI in world)
if(A)
AI << "<font color = red><b>Network Alert: Brute-force encryption crack in progress in [A.name].</b></font>"
else
AI << "<font color = red><b>Network Alert: Brute-force encryption crack in progress. Unable to pinpoint location.</b></font>"
while(src.hackprogress < 100)
if(src.cable && src.cable.machine && istype(src.cable.machine, /obj/machinery/door) && src.cable.machine == src.hackdoor && get_dist(src, src.hackdoor) <= 1)
hackprogress += rand(1, 10)
else
src.temp = "Door Jack: Connection to airlock has been lost. Hack aborted."
hackprogress = 0
src.hackdoor = null
return
if(hackprogress >= 100) // This is clunky, but works. We need to make sure we don't ever display a progress greater than 100,
hackprogress = 100 // but we also need to reset the progress AFTER it's been displayed
if(src.screen == "doorjack" && src.subscreen == 0) // Update our view, if appropriate
src.paiInterface()
if(hackprogress >= 100)
src.hackprogress = 0
src.cable.machine:open()
sleep(50) // Update every 5 seconds
// Digital Messenger
/mob/living/silicon/pai/proc/pdamessage()
var/dat = "<h3>Digital Messenger</h3>"
dat += "<ul>"
for (var/obj/item/device/pda/P in world)
if (!P.owner||P.toff||P == src) continue
dat += "<li><a href='byond://?src=\ref[src];choice=pdamessage;target=\ref[P]'>[P]</a>"
dat += "</li>"
for (var/mob/living/silicon/pai/P in world)
if(P.stat != 2)
dat += "<li><a href='byond://?src=\ref[src];choice=pdamessage;target=\ref[P]'>[P]</a>"
dat += "</li>"
dat += "</ul>"
return dat

View File

@@ -0,0 +1,344 @@
//UltraLight system, by Sukasa
var
const
UL_LUMINOSITY = 0
UL_SQUARELIGHT = 0
UL_RGB = 1
UL_ROUNDLIGHT = 2
UL_I_FALLOFF_SQUARE = 0
UL_I_FALLOFF_ROUND = 1
UL_I_LUMINOSITY = 0
UL_I_RGB = 1
UL_I_LIT = 0
UL_I_EXTINGUISHED = 1
UL_I_ONZERO = 2
ul_LightingEnabled = 1
ul_LightingResolution = 1
ul_Steps = 7
ul_LightingModel = UL_I_RGB
ul_FalloffStyle = UL_I_FALLOFF_ROUND
ul_TopLuminosity = 0
ul_Layer = 10
ul_SuppressLightLevelChanges = 0
list/ul_FastRoot = list(0, 1, 1, 1, 2, 2, 2, 2, 2, 3, 3, 3, 3, 3, 3, 3, 4, 4, 4, 4, 4, 4, 4, 4, 4, 5, 5, 5, 5, 5, 5,
5, 5, 5, 5, 5, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7,
7, 7)
proc
ul_Clamp(var/Value)
return min(max(Value, 0), ul_Steps)
atom
var
LuminosityRed = 0
LuminosityGreen = 0
LuminosityBlue = 0
ul_Extinguished = UL_I_ONZERO
proc
ul_SetLuminosity(var/Red, var/Green = Red, var/Blue = Red)
if(LuminosityRed == Red && LuminosityGreen == Green && LuminosityBlue == Blue)
return //No point doing all that work if it won't have any effect anyways...
if (ul_Extinguished == UL_I_EXTINGUISHED)
LuminosityRed = Red
LuminosityGreen = Green
LuminosityBlue = Blue
return
if (ul_IsLuminous())
ul_Extinguish()
LuminosityRed = Red
LuminosityGreen = Green
LuminosityBlue = Blue
ul_Extinguished = UL_I_ONZERO
if (ul_IsLuminous())
ul_Illuminate()
return
ul_Illuminate()
if (ul_Extinguished == UL_I_LIT)
return
ul_Extinguished = UL_I_LIT
ul_UpdateTopLuminosity()
luminosity = ul_Luminosity()
for(var/turf/Affected in view(ul_Luminosity(), src))
var/Falloff = src.ul_FalloffAmount(Affected)
var/DeltaRed = LuminosityRed - Falloff
var/DeltaGreen = LuminosityGreen - Falloff
var/DeltaBlue = LuminosityBlue - Falloff
if(ul_IsLuminous(DeltaRed, DeltaGreen, DeltaBlue))
Affected.LightLevelRed += max(DeltaRed, 0)
Affected.LightLevelGreen += max(DeltaGreen, 0)
Affected.LightLevelBlue += max(DeltaBlue, 0)
Affected.MaxRed += LuminosityRed
Affected.MaxGreen += LuminosityGreen
Affected.MaxBlue += LuminosityBlue
Affected.ul_UpdateLight()
if (ul_SuppressLightLevelChanges == 0)
Affected.ul_LightLevelChanged()
for(var/atom/AffectedAtom in Affected)
AffectedAtom.ul_LightLevelChanged()
return
ul_Extinguish()
if (ul_Extinguished != UL_I_LIT)
return
ul_Extinguished = UL_I_EXTINGUISHED
for(var/turf/Affected in view(ul_Luminosity(), src))
var/Falloff = ul_FalloffAmount(Affected)
var/DeltaRed = LuminosityRed - Falloff
var/DeltaGreen = LuminosityGreen - Falloff
var/DeltaBlue = LuminosityBlue - Falloff
if(ul_IsLuminous(DeltaRed, DeltaGreen, DeltaBlue))
Affected.LightLevelRed -= max(DeltaRed, 0)
Affected.LightLevelGreen -= max(DeltaGreen, 0)
Affected.LightLevelBlue -= max(DeltaBlue, 0)
Affected.MaxRed -= LuminosityRed
Affected.MaxGreen -= LuminosityGreen
Affected.MaxBlue -= LuminosityBlue
Affected.ul_UpdateLight()
if (ul_SuppressLightLevelChanges == 0)
Affected.ul_LightLevelChanged()
for(var/atom/AffectedAtom in Affected)
AffectedAtom.ul_LightLevelChanged()
luminosity = 0
return
ul_FalloffAmount(var/atom/ref)
if (ul_FalloffStyle == UL_I_FALLOFF_ROUND)
var/x = (ref.x - src.x)
var/y = (ref.y - src.y)
if ((x*x + y*y) > ul_FastRoot.len)
for(var/i = ul_FastRoot.len, i <= x*x+y*y, i++)
ul_FastRoot += round(sqrt(x*x+y*y))
return round(ul_LightingResolution * ul_FastRoot[x*x + y*y + 1], 1)
else if (ul_FalloffStyle == UL_I_FALLOFF_SQUARE)
return get_dist(src, ref)
return 0
ul_SetOpacity(var/NewOpacity)
if(opacity != NewOpacity)
var/list/Blanked = ul_BlankLocal()
var/atom/T = src
while(T && !isturf(T))
T = T.loc
opacity = NewOpacity
if(T)
T:LightLevelRed = 0
T:LightLevelGreen = 0
T:LightLevelBlue = 0
ul_UnblankLocal(Blanked)
return
ul_UnblankLocal(var/list/ReApply = view(ul_TopLuminosity, src))
for(var/atom/Light in ReApply)
if(Light.ul_IsLuminous())
Light.ul_Illuminate()
return
ul_BlankLocal()
var/list/Blanked = list( )
var/TurfAdjust = isturf(src) ? 1 : 0
for(var/atom/Affected in view(ul_TopLuminosity, src))
if(Affected.ul_IsLuminous() && Affected.ul_Extinguished == UL_I_LIT && (ul_FalloffAmount(Affected) <= Affected.luminosity + TurfAdjust))
Affected.ul_Extinguish()
Blanked += Affected
return Blanked
ul_UpdateTopLuminosity()
if (ul_TopLuminosity < LuminosityRed)
ul_TopLuminosity = LuminosityRed
if (ul_TopLuminosity < LuminosityGreen)
ul_TopLuminosity = LuminosityGreen
if (ul_TopLuminosity < LuminosityBlue)
ul_TopLuminosity = LuminosityBlue
return
ul_Luminosity()
return max(LuminosityRed, LuminosityGreen, LuminosityBlue)
ul_IsLuminous(var/Red = LuminosityRed, var/Green = LuminosityGreen, var/Blue = LuminosityBlue)
return (Red > 0 || Green > 0 || Blue > 0)
ul_LightLevelChanged()
//Designed for client projects to use. Called on items when the turf they are in has its light level changed
return
New()
..()
if(ul_IsLuminous())
spawn(1)
ul_Illuminate()
return
Del()
if(ul_IsLuminous())
ul_Extinguish()
..()
return
movable
Move()
ul_Extinguish()
..()
ul_Illuminate()
return
turf
var
LightLevelRed = 0
LightLevelGreen = 0
LightLevelBlue = 0
list/MaxRed = list( )
list/MaxGreen = list( )
list/MaxBlue = list( )
proc
ul_GetRed()
return ul_Clamp(min(LightLevelRed, max(MaxRed)))
ul_GetGreen()
return ul_Clamp(min(LightLevelGreen, max(MaxGreen)))
ul_GetBlue()
return ul_Clamp(min(LightLevelBlue, max(MaxBlue)))
ul_UpdateLight()
var/area/CurrentArea = loc
if(!isarea(CurrentArea) || !CurrentArea.ul_Lighting)
return
var/LightingTag = copytext(CurrentArea.tag, 1, findtext(CurrentArea.tag, ":UL")) + ":UL[ul_GetRed()]_[ul_GetGreen()]_[ul_GetBlue()]"
if(CurrentArea.tag != LightingTag)
var/area/NewArea = locate(LightingTag)
if(!NewArea)
NewArea = new CurrentArea.type()
NewArea.tag = LightingTag
for(var/V in CurrentArea.vars - "contents")
if(issaved(CurrentArea.vars[V]))
NewArea.vars[V] = CurrentArea.vars[V]
NewArea.tag = LightingTag
NewArea.ul_Light(ul_GetRed(), ul_GetGreen(), ul_GetBlue())
NewArea.contents += src
return
ul_Recalculate()
ul_SuppressLightLevelChanges++
var/list/Lights = ul_BlankLocal()
LightLevelRed = 0
LightLevelGreen = 0
LightLevelBlue = 0
ul_UnblankLocal(Lights)
ul_SuppressLightLevelChanges--
return
area
var
ul_Overlay = null
ul_Lighting = 1
LightLevelRed = 0
LightLevelGreen = 0
LightLevelBlue = 0
proc
ul_Light(var/Red = LightLevelRed, var/Green = LightLevelGreen, var/Blue = LightLevelBlue)
if(!src || !src.ul_Lighting)
return
overlays -= ul_Overlay
LightLevelRed = Red
LightLevelGreen = Green
LightLevelBlue = Blue
luminosity = ul_IsLuminous(LightLevelRed, LightLevelGreen, LightLevelBlue)
ul_Overlay = image('ULIcons.dmi', , num2text(LightLevelRed) + "-" + num2text(LightLevelGreen) + "-" + num2text(LightLevelBlue), ul_Layer)
overlays += ul_Overlay
return
ul_Prep()
if(!tag)
tag = "[type]"
if(ul_Lighting)
if(!findtext(tag,":UL"))
ul_Light()
//world.log << tag
return