diff --git a/code/defines/mob/living/silicon/hologram.dm b/code/defines/mob/living/silicon/hologram.dm new file mode 100644 index 00000000000..4bf5dd555cd --- /dev/null +++ b/code/defines/mob/living/silicon/hologram.dm @@ -0,0 +1,7 @@ +/mob/living/silicon/aihologram + name = "AI hologram projection" + voice_name = "synthesized voice" + icon = 'mob.dmi'// + icon_state = "ai-holo" + density = 0 + var/parent_ai = null \ No newline at end of file diff --git a/code/defines/obj/machinery.dm b/code/defines/obj/machinery.dm index 741bfc5e4fa..433a9ac3b77 100644 --- a/code/defines/obj/machinery.dm +++ b/code/defines/obj/machinery.dm @@ -576,32 +576,13 @@ var/gibtime = 40 // Time from starting until meat appears var/mob/occupant // Mob who has been put inside -/obj/machinery/travel - name = "travel thingie" - desc = "it is used for travel idunno" - icon = 'travel.dmi' - density = 1 +/obj/machinery/holopad + name = "holopad" + desc = "A floor-mounted device for projecting AI holograms." + icon_state = "holopad0" anchored = 1 - - //note - didn't use a single loc list just because it's easier to edit via adminmagics if this is done this way - var/z_connect[world.maxz] //the z position of the tiles it connects to - var/x_connect[world.maxx] //the x position of the tiles it connects to - var/y_connect[world.maxy] //the y position of the tiles it connects to - -/obj/machinery/travel/ladder - icon_state = "ladder_up" - name = "ladder" - desc = "It is a ladder." - var/connected = 0 - -/obj/machinery/travel/elevator - icon_state = "elevator_closed" - name = "elevator" - desc = "It is an elevator. The display shows \"1\"." - - var/current_floor = 1 //current floor the elevator is on. do NOT confuse with current z-level of the elevator - var/list/elevators_connected = list() //list of elevators it is connected to - var/list/floors = list() //dependant on the number of elevators, converts z-levels to floors, basically + var/state = "off" + var/slave_holo = null /* //By Darem, will implement.... eventually... /obj/machinery/circuitprinter diff --git a/code/game/machinery/hologram.dm b/code/game/machinery/hologram.dm index 534abd77eb7..0330d6f3a8b 100644 --- a/code/game/machinery/hologram.dm +++ b/code/game/machinery/hologram.dm @@ -1,3 +1,74 @@ +/obj/machinery/holopad/attack_ai(user as mob) + //branches depending on four things - is the user currently a hologram? does it have power? + //is the holopad on? (moot if q2 = 0) is the user the one who is using this holopad? (moot if q3 = 0) + if(!istype(user,/mob/living/silicon/aihologram/)) //question number one + if(!(stat & NOPOWER)) //question number two + if(src.state == "off") //question number three + var/mob/living/silicon/aihologram/holo = new /mob/living/silicon/aihologram(src.loc) + holo.parent_ai = user + holo.client = usr.client //should move the client there + src.state = "on" + src.icon_state = "holopad1" + src.slave_holo = holo + return + else + if(user != src.slave_holo:parent_ai) //question number four //there is always a slave_holo if it's on + user << "\red You're not the one AI who is currently using this holopad!" + return + else + user << "\red \b Something is very wrong, you should be in a hologram by now" + return + else + user << "\red This holopad has no power." + return + else + if(!(stat & NOPOWER)) //question number two + if(src.state == "off") //question number three + user << "\red This holopad is off, you should find your original holopad." + return + else + if(user == src.slave_holo) //question number four + del(user) //code for returning the control back to the AI is in the mob's del() code + src.state = "off" + src.icon_state = "holopad0" + src.slave_holo = null + return + else + user << "\red You're not the one AI who is currently using this holopad!" + return + else + user << "\red This holopad is off, you should find your original holopad." + return + +/obj/machinery/holopad/process() + if((stat & NOPOWER) && src.state == "on") + src.state = "off" + if(src.state == "on") + if(!(src.slave_holo in view(src,5))) //if the hologram strayed too far, destroy it + if(src.slave_holo) + del(src.slave_holo) //code for returning the control back to the AI is in the mob's del() code + src.state = "off" + src.icon_state = "holopad0" + src.slave_holo = null + else + use_power(300) + if(src.state == "off" && src.slave_holo) //usually happens if the power ran out + del(src.slave_holo) //code for returning the control back to the AI is in the mob's del() code + src.slave_holo = null + return 1 + +/obj/machinery/holopad/power_change() + if (powered()) + stat &= ~NOPOWER + else + stat |= ~NOPOWER + +/obj/machinery/holopad/Del() + if(src.slave_holo) + del(src.slave_holo) //code for returning the control back to the AI is in the mob's del() code + ..() + +/* Old code which didn't work, I believe /obj/machinery/hologram_ai/New() ..() @@ -76,4 +147,5 @@ render() else if (href_list["temp"]) src.temp = null - src.show_console(usr) \ No newline at end of file + src.show_console(usr) +*/ \ No newline at end of file diff --git a/code/modules/mob/living/silicon/aihologram/aihologram.dm b/code/modules/mob/living/silicon/aihologram/aihologram.dm new file mode 100644 index 00000000000..92e932a833f --- /dev/null +++ b/code/modules/mob/living/silicon/aihologram/aihologram.dm @@ -0,0 +1,42 @@ +/mob/living/silicon/aihologram/New() + ..() + if(parent_ai) + src.name = parent_ai:name + src.real_name = parent_ai:real_name + +/mob/living/silicon/aihologram/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)]") + +/mob/living/silicon/aihologram/proc/ai_roster() + set category = "AI Commands" + set name = "Show Crew Manifest" + + var/dat = "Crew RosterCrew Roster:

" + + for (var/datum/data/record/t in data_core.general) + dat += "[t.fields["name"]] - [t.fields["rank"]]
" + + dat += "" + + src << browse(dat, "window=airoster") + onclose(src, "airoster") + +/mob/living/silicon/aihologram/ex_act(severity) //something immaterial is immune to bombs and everything else, really + return + +/mob/living/silicon/aihologram/meteorhit(obj/O as obj) + return + +/mob/living/silicon/aihologram/bullet_act(flag) + return + +/mob/living/silicon/aihologram/proc/back_to_ai() + set category = "AI Commands" + set name = "Return To AI" + del(src) diff --git a/code/modules/mob/living/silicon/aihologram/death.dm b/code/modules/mob/living/silicon/aihologram/death.dm new file mode 100644 index 00000000000..cdbab8fdd73 --- /dev/null +++ b/code/modules/mob/living/silicon/aihologram/death.dm @@ -0,0 +1,4 @@ +/mob/living/silicon/aihologram/Del() //can't "die" per se, so it's only Del() + if(parent_ai) + parent_ai:client = src.client //parent_ai is always an ai mob, so : is okay + ..() \ No newline at end of file diff --git a/code/modules/mob/living/silicon/aihologram/emote.dm b/code/modules/mob/living/silicon/aihologram/emote.dm new file mode 100644 index 00000000000..ee321cda0ba --- /dev/null +++ b/code/modules/mob/living/silicon/aihologram/emote.dm @@ -0,0 +1,451 @@ +/mob/living/silicon/aihologram/emote(var/act) + var/param = null + + if (findtext(act, "-", 1, null)) + var/t1 = findtext(act, "-", 1, null) + param = copytext(act, t1 + 1, length(act) + 1) + act = copytext(act, 1, t1) + + var/muzzled = istype(src.wear_mask, /obj/item/clothing/mask/muzzle) + var/m_type = 1 + + for (var/obj/item/weapon/implant/I in src) + if (I.implanted) + I.trigger(act, src) + + var/message + + switch(act) + if ("airguitar") + if (!src.restrained()) + message = "[src] is strumming the air and headbanging like a safari chimp." + m_type = 1 + + if ("blink") + message = "[src] blinks." + m_type = 1 + + if ("blink_r") + message = "[src] blinks rapidly." + m_type = 1 + + if ("bow") + if (!src.buckled) + var/M = null + if (param) + for (var/mob/A in view(null, null)) + if (param == A.name) + M = A + break + if (!M) + param = null + + if (param) + message = "[src] bows to [param]." + else + message = "[src] bows." + m_type = 1 + + if ("custom") + var/input = input("Choose an emote to display.") + var/input2 = input("Is this a visible or hearable emote?") in list("Visible","Hearable") + if (input2 == "Visible") + m_type = 1 + else if (input2 == "Hearable") + if (src.miming) + return + m_type = 2 + else + alert("Unable to use this emote, must be either hearable or visible.") + return + message = "[src] [input]" + + + if ("salute") + if (!src.buckled) + var/M = null + if (param) + for (var/mob/A in view(null, null)) + if (param == A.name) + M = A + break + if (!M) + param = null + + if (param) + message = "[src] salutes to [param]." + else + message = "[src] salutes." + m_type = 1 + + if ("choke") + if (!muzzled) + message = "[src] chokes!" + m_type = 2 + else + message = "[src] makes a strong noise." + m_type = 2 + + if ("clap") + if (!src.restrained()) + message = "[src] claps." + m_type = 2 + if ("flap") + if (!src.restrained()) + message = "[src] flaps his wings." + m_type = 2 + + if ("aflap") + if (!src.restrained()) + message = "[src] flaps his wings ANGRILY!" + m_type = 2 + + if ("drool") + message = "[src] drools." + m_type = 1 + + if ("eyebrow") + message = "[src] raises an eyebrow." + m_type = 1 + + if ("chuckle") + if (!muzzled) + message = "[src] chuckles." + m_type = 2 + else + message = "[src] makes a noise." + m_type = 2 + + if ("twitch") + message = "[src] twitches violently." + m_type = 1 + + if ("twitch_s") + message = "[src] twitches." + m_type = 1 + + if ("faint") + message = "[src] faints." + src.sleeping = 1 + m_type = 1 + + if ("cough") + if (!muzzled) + message = "[src] coughs!" + m_type = 2 + else + message = "[src] makes a strong noise." + m_type = 2 + + if ("frown") + message = "[src] frowns." + m_type = 1 + + if ("nod") + message = "[src] nods." + m_type = 1 + + if ("blush") + message = "[src] blushes." + m_type = 1 + + if ("gasp") + if (!muzzled) + message = "[src] gasps!" + m_type = 2 + else + message = "[src] makes a weak noise." + m_type = 2 + + if ("deathgasp") + message = "[src] seizes up and falls limp, \his eyes dead and lifeless..." + m_type = 1 + + if ("giggle") + if (!muzzled) + message = "[src] giggles." + m_type = 2 + else + message = "[src] makes a noise." + m_type = 2 + + if ("glare") + var/M = null + if (param) + for (var/mob/A in view(null, null)) + if (param == A.name) + M = A + break + if (!M) + param = null + + if (param) + message = "[src] glares at [param]." + else + message = "[src] glares." + + if ("stare") + var/M = null + if (param) + for (var/mob/A in view(null, null)) + if (param == A.name) + M = A + break + if (!M) + param = null + + if (param) + message = "[src] stares at [param]." + else + message = "[src] stares." + + if ("look") + var/M = null + if (param) + for (var/mob/A in view(null, null)) + if (param == A.name) + M = A + break + + if (!M) + param = null + + if (param) + message = "[src] looks at [param]." + else + message = "[src] looks." + m_type = 1 + + if ("grin") + message = "[src] grins." + m_type = 1 + + if ("cry") + if (!muzzled) + message = "[src] cries." + m_type = 2 + else + message = "[src] makes a weak noise. \He frowns." + m_type = 2 + + if ("sigh") + if (!muzzled) + message = "[src] sighs." + m_type = 2 + else + message = "[src] makes a weak noise." + m_type = 2 + + if ("laugh") + if (!muzzled) + message = "[src] laughs." + m_type = 2 + else + message = "[src] makes a noise." + m_type = 2 + + if ("mumble") + message = "[src] mumbles!" + m_type = 2 + + if ("grumble") + if (!muzzled) + message = "[src] grumbles!" + m_type = 2 + else + message = "[src] makes a noise." + m_type = 2 + + if ("groan") + if (!muzzled) + message = "[src] groans!" + m_type = 2 + else + message = "[src] makes a loud noise." + m_type = 2 + + if ("moan") + message = "[src] moans!" + m_type = 2 + + if ("johnny") + var/M + if (param) + M = param + if (!M) + param = null + else + message = "[src] says, \"[M], please. He had a family.\" [src.name] takes a drag from a cigarette and blows his name out in smoke." + m_type = 2 + + if ("point") + if (!src.restrained()) + var/mob/M = null + if (param) + for (var/atom/A as mob|obj|turf|area in view(null, null)) + if (param == A.name) + M = A + break + + if (!M) + message = "[src] points." + else + M.point() + + if (M) + message = "[src] points to [M]." + else + m_type = 1 + + if ("raise") + if (!src.restrained()) + message = "[src] raises a hand." + m_type = 1 + + if("shake") + message = "[src] shakes \his head." + m_type = 1 + + if ("shrug") + message = "[src] shrugs." + m_type = 1 + + if ("signal") + if (!src.restrained()) + var/t1 = round(text2num(param)) + if (isnum(t1)) + if (t1 <= 5 && (!src.r_hand || !src.l_hand)) + message = "[src] raises [t1] finger\s." + else if (t1 <= 10 && (!src.r_hand && !src.l_hand)) + message = "[src] raises [t1] finger\s." + m_type = 1 + + if ("smile") + message = "[src] smiles." + m_type = 1 + + if ("shiver") + message = "[src] shivers." + m_type = 2 + + if ("pale") + message = "[src] goes pale for a second." + m_type = 1 + + if ("tremble") + message = "[src] trembles in fear!" + m_type = 1 + + if ("sneeze") + if (!muzzled) + message = "[src] sneezes." + m_type = 2 + else + message = "[src] makes a strange noise." + m_type = 2 + + if ("sniff") + message = "[src] sniffs." + m_type = 2 + + if ("snore") + if (!muzzled) + message = "[src] snores." + m_type = 2 + else + message = "[src] makes a noise." + m_type = 2 + + if ("whimper") + if (!muzzled) + message = "[src] whimpers." + m_type = 2 + else + message = "[src] makes a weak noise." + m_type = 2 + + if ("wink") + message = "[src] winks." + m_type = 1 + + if ("yawn") + if (!muzzled) + message = "[src] yawns." + m_type = 2 + + if ("collapse") + if (!src.paralysis) + src.paralysis += 2 + message = "[src] collapses!" + m_type = 2 + + if("hug") + m_type = 1 + if (!src.restrained()) + var/M = null + if (param) + for (var/mob/A in view(1, null)) + if (param == A.name) + M = A + break + if (M == src) + M = null + + if (M) + message = "[src] hugs [M]." + else + message = "[src] hugs \himself." + + if ("handshake") + m_type = 1 + if (!src.restrained() && !src.r_hand) + var/mob/M = null + if (param) + for (var/mob/A in view(1, null)) + if (param == A.name) + M = A + break + if (M == src) + M = null + + if (M) + if (M.canmove && !M.r_hand && !M.restrained()) + message = "[src] shakes hands with [M]." + else + message = "[src] holds out \his hand to [M]." + + if("daps") + m_type = 1 + if (!src.restrained()) + var/M = null + if (param) + for (var/mob/A in view(1, null)) + if (param == A.name) + M = A + break + if (M) + message = "[src] gives daps to [M]." + else + message = "[src] sadly can't find anybody to give daps to, and daps \himself. Shameful." + + if ("scream") + if (!muzzled) + message = "[src] screams!" + m_type = 2 + else + message = "[src] makes a very loud noise." + m_type = 2 + + if ("help") + src << "blink, blink_r, blush, bow-(none)/mob, burp, choke, chuckle, clap, collapse, cough,\ncry, custom, deathgasp, drool, eyebrow, frown, gasp, giggle, groan, grumble, handshake, hug-(none)/mob, glare-(none)/mob,\ngrin, laugh, look-(none)/mob, moan, mumble, nod, pale, point-atom, raise, salute, shake, shiver, shrug,\nsigh, signal-#1-10, smile, sneeze, sniff, snore, stare-(none)/mob, tremble, twitch, twitch_s, whimper,\nwink, yawn" + + else + src << "\blue Unusable emote '[act]'. Say *help for a list." + + if (message) + if (m_type & 1) + for (var/mob/O in viewers(src, null)) + O.show_message(message, m_type) + else if (m_type & 2) + for (var/mob/O in hearers(src, null)) + O.show_message(message, m_type) diff --git a/code/modules/mob/living/silicon/aihologram/examine.dm b/code/modules/mob/living/silicon/aihologram/examine.dm new file mode 100644 index 00000000000..6345ddf7fc5 --- /dev/null +++ b/code/modules/mob/living/silicon/aihologram/examine.dm @@ -0,0 +1,5 @@ +/mob/living/silicon/aihologram/examine() + set src in oview() + usr << "\blue *---------*" + usr << text("\blue This is \icon[] []!", src, src.name) + return \ No newline at end of file diff --git a/code/modules/mob/living/silicon/aihologram/hud.dm b/code/modules/mob/living/silicon/aihologram/hud.dm new file mode 100644 index 00000000000..3c54d0eac68 --- /dev/null +++ b/code/modules/mob/living/silicon/aihologram/hud.dm @@ -0,0 +1,10 @@ +/obj/hud/proc/aihologram_hud() + + src.station_explosion = new src.h_type( src ) + src.station_explosion.icon = 'station_explosion.dmi' + src.station_explosion.icon_state = "start" + src.station_explosion.layer = 20 + src.station_explosion.mouse_opacity = 0 + src.station_explosion.screen_loc = "1,3" + + return \ No newline at end of file diff --git a/code/modules/mob/living/silicon/aihologram/laws.dm b/code/modules/mob/living/silicon/aihologram/laws.dm new file mode 100644 index 00000000000..77c2cf9f946 --- /dev/null +++ b/code/modules/mob/living/silicon/aihologram/laws.dm @@ -0,0 +1 @@ +//I don't even know -- Urist \ No newline at end of file diff --git a/code/modules/mob/living/silicon/aihologram/login.dm b/code/modules/mob/living/silicon/aihologram/login.dm new file mode 100644 index 00000000000..dc48c6628f5 --- /dev/null +++ b/code/modules/mob/living/silicon/aihologram/login.dm @@ -0,0 +1,10 @@ +/mob/dead/aihologram/Login() + ..() + + src.client.screen = null + + if (!isturf(src.loc)) + src.client.eye = src.loc + src.client.perspective = EYE_PERSPECTIVE + + return \ No newline at end of file diff --git a/code/modules/mob/living/silicon/aihologram/say.dm b/code/modules/mob/living/silicon/aihologram/say.dm new file mode 100644 index 00000000000..a37d07f7474 --- /dev/null +++ b/code/modules/mob/living/silicon/aihologram/say.dm @@ -0,0 +1,16 @@ +/mob/living/silicon/aihologram/say_understands(var/other) + if (istype(other, /mob/living/carbon/human)) + return 1 + if (istype(other, /mob/living/silicon)) + return 1 + return ..() + +/mob/living/silicon/aihologram/say_quote(var/text) + var/ending = copytext(text, length(text)) + + if (ending == "?") + return "queries, \"[text]\""; + else if (ending == "!") + return "declares, \"[copytext(text, 1, length(text))]\""; + + return "states, \"[text]\""; \ No newline at end of file diff --git a/config/admins.txt b/config/admins.txt index 73d716133d8..75836e84875 100644 --- a/config/admins.txt +++ b/config/admins.txt @@ -1,5 +1,6 @@ deuryn - Host tle - Host +uristmcdorf - Host mport2004 - Coder \ No newline at end of file diff --git a/tgstation.dme b/tgstation.dme index 9523c649d26..090472489c6 100644 --- a/tgstation.dme +++ b/tgstation.dme @@ -336,6 +336,7 @@ #include "code\game\machinery\flasher.dm" #include "code\game\machinery\Freezer.dm" #include "code\game\machinery\gibber.dm" +#include "code\game\machinery\hologram.dm" #include "code\game\machinery\hydroponics.dm" #include "code\game\machinery\igniter.dm" #include "code\game\machinery\lightswitch.dm" @@ -644,6 +645,14 @@ #include "code\modules\mob\living\silicon\ai\logout.dm" #include "code\modules\mob\living\silicon\ai\move.dm" #include "code\modules\mob\living\silicon\ai\say.dm" +#include "code\modules\mob\living\silicon\aihologram\aihologram.dm" +#include "code\modules\mob\living\silicon\aihologram\death.dm" +#include "code\modules\mob\living\silicon\aihologram\emote.dm" +#include "code\modules\mob\living\silicon\aihologram\examine.dm" +#include "code\modules\mob\living\silicon\aihologram\hud.dm" +#include "code\modules\mob\living\silicon\aihologram\laws.dm" +#include "code\modules\mob\living\silicon\aihologram\login.dm" +#include "code\modules\mob\living\silicon\aihologram\say.dm" #include "code\modules\mob\living\silicon\decoy\death.dm" #include "code\modules\mob\living\silicon\decoy\decoy.dm" #include "code\modules\mob\living\silicon\decoy\life.dm"