Holocalls

This commit is contained in:
CitadelStationBot
2017-05-01 12:53:40 -05:00
parent 1842665af6
commit 36dfc5a4db
6 changed files with 514 additions and 35 deletions
+115 -34
View File
@@ -57,8 +57,16 @@ Possible to do for anyone motivated enough:
holopads += src
/obj/machinery/holopad/Destroy()
for (var/mob/living/silicon/ai/master in masters)
clear_holo(master)
if(outgoing_call)
LAZYADD(holo_calls, outgoing_call)
for(var/I in holo_calls)
var/datum/holocall/HC = I
HC.ConnectionFailure(src)
LAZYCLEARLIST(holo_calls)
for (var/I in masters)
clear_holo(I)
holopads -= src
return ..()
@@ -128,12 +136,49 @@ Possible to do for anyone motivated enough:
temp = "A request for AI presence was already sent recently.<BR>"
temp += "<A href='?src=\ref[src];mainmenu=1'>Main Menu</A>"
else if(href_list["Holocall"])
if(outgoing_call)
return
temp = "You must stand on the holopad to make a call!<br>"
temp += "<A href='?src=\ref[src];mainmenu=1'>Main Menu</A>"
if(usr.loc == loc)
var/list/callnames = list()
for(var/I in holopads)
var/area/A = get_area(I)
if(A)
LAZYADD(callnames[A], I)
callnames -= get_area(src)
var/result = input(usr, "Choose an area to call", "Holocall") as null|anything in callnames
if(QDELETED(usr) || !result || outgoing_call)
return
if(usr.loc == loc)
temp = "Dialing...<br>"
temp += "<A href='?src=\ref[src];mainmenu=1'>Main Menu</A>"
new /datum/holocall(usr, src, callnames[result])
else if(href_list["connectcall"])
var/datum/holocall/call_to_connect = locate(href_list["connectcall"])
if(!QDELETED(call_to_connect))
call_to_connect.Answer(src)
temp = ""
else if(href_list["disconnectcall"])
var/datum/holocall/call_to_disconnect = locate(href_list["disconnectcall"])
if(!QDELETED(call_to_disconnect))
call_to_disconnect.Disconnect(src)
temp = ""
else if(href_list["mainmenu"])
temp = ""
if(outgoing_call)
outgoing_call.Disconnect()
updateDialog()
add_fingerprint(usr)
//do not allow AIs to answer calls or people will use it to meta the AI sattelite
/obj/machinery/holopad/attack_ai(mob/living/silicon/ai/user)
if (!istype(user))
return
@@ -148,39 +193,75 @@ Possible to do for anyone motivated enough:
clear_holo(user)
/obj/machinery/holopad/process()
if(masters.len)//If there is a hologram.
for (var/mob/living/silicon/ai/master in masters)
if(master && !master.stat && master.client && master.eyeobj)//If there is an AI attached, it's not incapacitated, it has a client, and the client eye is centered on the projector.
if(!(stat & NOPOWER))//If the machine has power.
if(HOLOPAD_MODE == RANGE_BASED)
if(get_dist(master.eyeobj, src) <= holo_range)
return TRUE
else
var/obj/machinery/holopad/pad_close = get_closest_atom(/obj/machinery/holopad, holopads, master.eyeobj)
if(get_dist(pad_close, master.eyeobj) <= holo_range)
var/obj/effect/overlay/holo_pad_hologram/h = masters[master]
unset_holo(master)
pad_close.set_holo(master, h)
return TRUE
else if (HOLOPAD_MODE == AREA_BASED)
var/area/holo_area = get_area(src)
var/area/eye_area = get_area(master.eyeobj)
if(eye_area in holo_area.related)
return TRUE
clear_holo(master)//If not, we want to get rid of the hologram.
return TRUE
/obj/machinery/holopad/proc/activate_holo(mob/living/silicon/ai/user)
if(!(stat & NOPOWER) && user.eyeobj.loc == src.loc)//If the projector has power and client eye is on it
if (istype(user.current, /obj/machinery/holopad))
for(var/I in masters)
var/mob/living/master = I
var/mob/living/silicon/ai/AI = master
if(!istype(AI))
AI = null
if(!QDELETED(master) && !master.incapacitated() && master.client && (!AI || AI.eyeobj))//If there is an AI attached, it's not incapacitated, it has a client, and the client eye is centered on the projector.
if(is_operational())//If the machine has power.
if(AI) //ais are range based
if(get_dist(AI.eyeobj, src) <= holo_range)
continue
else
var/obj/machinery/holopad/pad_close = get_closest_atom(/obj/machinery/holopad, holopads, AI.eyeobj)
if(get_dist(pad_close, AI.eyeobj) <= holo_range)
var/obj/effect/overlay/holo_pad_hologram/h = masters[master]
unset_holo(master)
pad_close.set_holo(master, h)
continue
else
continue
clear_holo(master)//If not, we want to get rid of the hologram.
if(outgoing_call)
outgoing_call.Check()
for(var/I in holo_calls)
var/datum/holocall/HC = I
if(HC.connected_holopad != src)
if(force_answer_call && world.time > (HC.call_start_time + (HOLOPAD_MAX_DIAL_TIME / 2)))
HC.Answer(src)
break
if(outgoing_call)
HC.Disconnect(src)//can't answer calls while calling
else
playsound(src, 'sound/machines/twobeep.ogg', 100) //bring, bring!
/obj/machinery/holopad/proc/activate_holo(mob/living/user)
var/mob/living/silicon/ai/AI = user
if(!istype(AI))
AI = null
if(is_operational() && (!AI || AI.eyeobj.loc == loc))//If the projector has power and client eye is on it
if (AI && istype(AI.current, /obj/machinery/holopad))
to_chat(user, "<span class='danger'>ERROR:</span> \black Image feed in progress.")
return
create_holo(user)//Create one.
src.visible_message("A holographic image of [user] flicks to life right before your eyes!")
var/obj/effect/overlay/holo_pad_hologram/Hologram = new(loc)//Spawn a blank effect at the location.
if(AI)
Hologram.icon = AI.holo_icon
else //make it like real life
Hologram.icon = user.icon
Hologram.icon_state = user.icon_state
Hologram.copy_overlays(user, TRUE)
//codersprite some holo effects here
Hologram.alpha = 100
Hologram.add_atom_colour("#77abff", FIXED_COLOUR_PRIORITY)
Hologram.Impersonation = user
Hologram.languages_spoken = user.languages_spoken
Hologram.mouse_opacity = 0//So you can't click on it.
Hologram.layer = FLY_LAYER//Above all the other objects/mobs. Or the vast majority of them.
Hologram.anchored = 1//So space wind cannot drag it.
Hologram.name = "[user.name] (Hologram)"//If someone decides to right click.
Hologram.set_light(2) //hologram lighting
set_holo(user, Hologram)
visible_message("A holographic image of [user] flicks to life right before your eyes!")
return Hologram
else
to_chat(user, "<span class='danger'>ERROR:</span> \black Unable to project hologram.")
+226
View File
@@ -0,0 +1,226 @@
diff a/code/game/machinery/hologram.dm b/code/game/machinery/hologram.dm (rejected hunks)
@@ -26,16 +26,12 @@ Possible to do for anyone motivated enough:
#define HOLOPAD_PASSIVE_POWER_USAGE 1
#define HOLOGRAM_POWER_USAGE 2
-#define RANGE_BASED 4
-#define AREA_BASED 6
-
-var/const/HOLOPAD_MODE = RANGE_BASED
var/list/holopads = list()
/obj/machinery/holopad
- name = "\improper AI holopad"
- desc = "It's a floor-mounted device for projecting holographic images. It is activated remotely."
+ name = "Holopad"
+ desc = "It's a floor-mounted device for projecting holographic images."
icon_state = "holopad0"
layer = LOW_OBJ_LAYER
flags = HEAR
@@ -48,10 +44,13 @@ var/list/holopads = list()
obj_integrity = 300
max_integrity = 300
armor = list(melee = 50, bullet = 20, laser = 20, energy = 20, bomb = 0, bio = 0, rad = 0, fire = 50, acid = 0)
- var/list/masters = list()//List of AIs that use the holopad
+ var/list/masters = list()//List of living mobs that use the holopad
var/last_request = 0 //to prevent request spam. ~Carn
var/holo_range = 5 // Change to change how far the AI can move away from the holopad before deactivating.
var/temp = ""
+ var/list/holo_calls //array of /datum/holocalls
+ var/datum/holocall/outgoing_call //do not modify the datums only check and call the public procs
+ var/static/force_answer_call = FALSE //Calls will be automatically answered after a couple rings, here for debugging
/obj/machinery/holopad/Initialize()
..()
@@ -94,20 +101,60 @@ var/list/holopads = list()
return
return ..()
+/obj/machinery/holopad/proc/CheckCallClose()
+ for(var/I in holo_calls)
+ var/datum/holocall/HC = I
+ if(usr == HC.eye)
+ HC.Disconnect(HC.calling_holopad) //disconnect via clicking the called holopad
+ return TRUE
+ return FALSE
+
+/obj/machinery/holopad/Click(location,control,params)
+ if(!CheckCallClose())
+ return ..()
+
/obj/machinery/holopad/AltClick(mob/living/carbon/human/user)
- interact(user)
+ if(!CheckCallClose())
+ interact(user)
/obj/machinery/holopad/interact(mob/living/carbon/human/user) //Carn: Hologram requests.
if(!istype(user))
return
- if(user.stat || stat & (NOPOWER|BROKEN))
+ if(user.incapacitated() || !is_operational())
+ return
+
+ if(outgoing_call) //someone is making a call, leave them be
return
+
user.set_machine(src)
var/dat
if(temp)
dat = temp
else
- dat = "<A href='?src=\ref[src];AIrequest=1'>request an AI's presence.</A>"
+ dat = "<a href='?src=\ref[src];AIrequest=1'>Request an AI's presence.</a><br>"
+ dat += "<a href='?src=\ref[src];Holocall=1'>Call another holopad.</a><br>"
+
+ if(LAZYLEN(holo_calls))
+ dat += "=====================================================<br>"
+
+ var/one_answered_call = FALSE
+ var/one_unanswered_call = FALSE
+ for(var/I in holo_calls)
+ var/datum/holocall/HC = I
+ if(HC.connected_holopad != src)
+ dat += "<a href='?src=\ref[src];connectcall=\ref[HC]'>Answer call from [get_area(HC.calling_holopad)].</a><br>"
+ one_unanswered_call = TRUE
+ else
+ one_answered_call = TRUE
+
+ if(one_answered_call && one_unanswered_call)
+ dat += "=====================================================<br>"
+ //we loop twice for formatting
+ for(var/I in holo_calls)
+ var/datum/holocall/HC = I
+ if(HC.connected_holopad == src)
+ dat += "<a href='?src=\ref[src];disconnectcall=\ref[HC]'>Disconnect call from [HC.user].</a><br>"
+
var/datum/browser/popup = new(user, "holopad", name, 300, 130)
popup.set_content(dat)
@@ -115,7 +162,10 @@ var/list/holopads = list()
popup.open()
/obj/machinery/holopad/Topic(href, href_list)
- if(..())
+ if(..() || isAI(usr))
+ return
+ add_fingerprint(usr)
+ if(!is_operational())
return
if (href_list["AIrequest"])
if(last_request + 200 < world.time)
@@ -194,59 +317,81 @@ For the other part of the code, check silicon say.dm. Particularly robot talk.*/
for(var/mob/living/silicon/ai/master in masters)
if(masters[master] && speaker != master)
master.relay_speech(message, speaker, message_langs, raw_message, radio_freq, spans)
+
+ for(var/I in holo_calls)
+ var/datum/holocall/HC = I
+ if(HC.connected_holopad == src && speaker != HC.hologram)
+ HC.user.Hear(message, speaker, message_langs, raw_message, radio_freq, spans)
+
+ if(outgoing_call && speaker == outgoing_call.user)
+ outgoing_call.hologram.say(raw_message)
+
+/obj/machinery/holopad/proc/SetLightsAndPower()
+ var/total_users = masters.len + LAZYLEN(holo_calls)
+ use_power = HOLOPAD_PASSIVE_POWER_USAGE + HOLOGRAM_POWER_USAGE * total_users
+ if(total_users)
+ set_light(2)
+ icon_state = "holopad1"
+ else
+ set_light(0)
+ icon_state = "holopad0"
-/obj/machinery/holopad/proc/create_holo(mob/living/silicon/ai/A, turf/T = loc)
- var/obj/effect/overlay/holo_pad_hologram/h = new(T)//Spawn a blank effect at the location.
- h.icon = A.holo_icon
- h.mouse_opacity = 0//So you can't click on it.
- h.layer = FLY_LAYER//Above all the other objects/mobs. Or the vast majority of them.
- h.anchored = 1//So space wind cannot drag it.
- h.name = "[A.name] (Hologram)"//If someone decides to right click.
- h.set_light(2) //hologram lighting
- set_holo(A, h)
- return TRUE
-
-/obj/machinery/holopad/proc/set_holo(mob/living/silicon/ai/A, var/obj/effect/overlay/holo_pad_hologram/h)
- masters[A] = h
- set_light(2) // pad lighting
- icon_state = "holopad1"
- A.current = src
- use_power += HOLOGRAM_POWER_USAGE
+/obj/machinery/holopad/proc/set_holo(mob/living/user, var/obj/effect/overlay/holo_pad_hologram/h)
+ masters[user] = h
+ var/mob/living/silicon/ai/AI = user
+ if(istype(AI))
+ AI.current = src
+ SetLightsAndPower()
return TRUE
-/obj/machinery/holopad/proc/clear_holo(mob/living/silicon/ai/user)
+/obj/machinery/holopad/proc/clear_holo(mob/living/user)
qdel(masters[user]) // Get rid of user's hologram
unset_holo(user)
return TRUE
-/obj/machinery/holopad/proc/unset_holo(mob/living/silicon/ai/user)
- if(user.current == src)
- user.current = null
+/obj/machinery/holopad/proc/unset_holo(mob/living/user)
+ var/mob/living/silicon/ai/AI = user
+ if(istype(AI) && AI.current == src)
+ AI.current = null
masters -= user // Discard AI from the list of those who use holopad
- use_power = max(HOLOPAD_PASSIVE_POWER_USAGE, use_power - HOLOGRAM_POWER_USAGE)//Reduce power usage
- if (!masters.len) // If no users left
- set_light(0) // pad lighting (hologram lighting will be handled automatically since its owner was deleted)
- icon_state = "holopad0"
- use_power = HOLOPAD_PASSIVE_POWER_USAGE
+ SetLightsAndPower()
return TRUE
-/obj/machinery/holopad/proc/move_hologram(mob/living/silicon/ai/user)
+/obj/machinery/holopad/proc/move_hologram(mob/living/user, turf/new_turf)
if(masters[user])
- step_to(masters[user], user.eyeobj)
var/obj/effect/overlay/holo_pad_hologram/H = masters[user]
- H.loc = get_turf(user.eyeobj)
+ step_to(H, new_turf)
+ H.loc = new_turf
+ var/area/holo_area = get_area(src)
+ var/area/eye_area = new_turf.loc
+
+ if(!(eye_area in holo_area.related))
+ clear_holo(user)
return TRUE
+/obj/effect/overlay/holo_pad_hologram
+ var/mob/living/Impersonation
+ var/datum/holocall/HC
+
+/obj/effect/overlay/holo_pad_hologram/Destroy()
+ Impersonation = null
+ if(HC)
+ HC.Disconnect(HC.calling_holopad)
+ return ..()
+
/obj/effect/overlay/holo_pad_hologram/Process_Spacemove(movement_dir = 0)
return 1
+/obj/effect/overlay/holo_pad_hologram/examine(mob/user)
+ if(Impersonation)
+ return Impersonation.examine(user)
+ return ..()
+
/obj/item/weapon/circuitboard/machine/holopad
name = "AI Holopad (Machine Board)"
build_path = /obj/machinery/holopad
origin_tech = "programming=1"
req_components = list(/obj/item/weapon/stock_parts/capacitor = 1)
-#undef RANGE_BASED
-#undef AREA_BASED
#undef HOLOPAD_PASSIVE_POWER_USAGE
-#undef HOLOGRAM_POWER_USAGE
+#undef HOLOGRAM_POWER_USAGE
\ No newline at end of file