refactors clickcatchers/parallax/fullsceren (#15460)
* :) * that * move those there * refactor that too * wew * stuff * almost. * sigh * just need speed * stuf * pain * hm * tweaks * that * eh * wack * a * done * that's important * wacky * all that * fixes * typo * that * a * funny * that * that * woo * help im losing my fucking mind * okay * fix
This commit is contained in:
@@ -0,0 +1,182 @@
|
||||
GLOBAL_LIST_EMPTY(active_alternate_appearances)
|
||||
|
||||
|
||||
/atom
|
||||
var/list/alternate_appearances
|
||||
|
||||
/atom/proc/remove_alt_appearance(key)
|
||||
if(alternate_appearances)
|
||||
for(var/K in alternate_appearances)
|
||||
var/datum/atom_hud/alternate_appearance/AA = alternate_appearances[K]
|
||||
if(AA.appearance_key == key)
|
||||
AA.remove_from_hud(src)
|
||||
break
|
||||
|
||||
/atom/proc/add_alt_appearance(type, key, ...)
|
||||
if(!type || !key)
|
||||
return
|
||||
if(alternate_appearances && alternate_appearances[key])
|
||||
return
|
||||
var/list/arguments = args.Copy(2)
|
||||
new type(arglist(arguments))
|
||||
|
||||
/datum/atom_hud/alternate_appearance
|
||||
var/appearance_key
|
||||
|
||||
/datum/atom_hud/alternate_appearance/New(key)
|
||||
..()
|
||||
GLOB.active_alternate_appearances += src
|
||||
appearance_key = key
|
||||
|
||||
/datum/atom_hud/alternate_appearance/Destroy()
|
||||
GLOB.active_alternate_appearances -= src
|
||||
return ..()
|
||||
|
||||
/datum/atom_hud/alternate_appearance/proc/onNewMob(mob/M)
|
||||
if(mobShouldSee(M))
|
||||
add_hud_to(M)
|
||||
|
||||
/datum/atom_hud/alternate_appearance/proc/mobShouldSee(mob/M)
|
||||
return FALSE
|
||||
|
||||
/datum/atom_hud/alternate_appearance/add_to_hud(atom/A, image/I)
|
||||
. = ..()
|
||||
if(.)
|
||||
LAZYINITLIST(A.alternate_appearances)
|
||||
A.alternate_appearances[appearance_key] = src
|
||||
|
||||
/datum/atom_hud/alternate_appearance/remove_from_hud(atom/A)
|
||||
. = ..()
|
||||
if(.)
|
||||
LAZYREMOVE(A.alternate_appearances, appearance_key)
|
||||
|
||||
|
||||
//an alternate appearance that attaches a single image to a single atom
|
||||
/datum/atom_hud/alternate_appearance/basic
|
||||
var/atom/target
|
||||
var/image/theImage
|
||||
var/add_ghost_version = FALSE
|
||||
var/ghost_appearance
|
||||
|
||||
/datum/atom_hud/alternate_appearance/basic/New(key, image/I, target_sees_appearance = TRUE)
|
||||
..()
|
||||
theImage = I
|
||||
target = I.loc
|
||||
hud_icons = list(appearance_key)
|
||||
add_to_hud(target, I)
|
||||
if(target_sees_appearance && ismob(target))
|
||||
add_hud_to(target)
|
||||
if(add_ghost_version)
|
||||
var/image/ghost_image = image(icon = I.icon , icon_state = I.icon_state, loc = I.loc)
|
||||
ghost_image.override = FALSE
|
||||
ghost_image.alpha = 128
|
||||
ghost_appearance = new /datum/atom_hud/alternate_appearance/basic/observers(key + "_observer", ghost_image, FALSE)
|
||||
|
||||
/datum/atom_hud/alternate_appearance/basic/Destroy()
|
||||
. = ..()
|
||||
if(ghost_appearance)
|
||||
QDEL_NULL(ghost_appearance)
|
||||
|
||||
/datum/atom_hud/alternate_appearance/basic/add_to_hud(atom/A)
|
||||
LAZYINITLIST(A.hud_list)
|
||||
A.hud_list[appearance_key] = theImage
|
||||
. = ..()
|
||||
|
||||
/datum/atom_hud/alternate_appearance/basic/remove_from_hud(atom/A)
|
||||
. = ..()
|
||||
A.hud_list -= appearance_key
|
||||
if(. && !QDELETED(src))
|
||||
qdel(src)
|
||||
|
||||
/datum/atom_hud/alternate_appearance/basic/everyone
|
||||
add_ghost_version = TRUE
|
||||
|
||||
/datum/atom_hud/alternate_appearance/basic/everyone/New()
|
||||
..()
|
||||
for(var/mob in GLOB.mob_list)
|
||||
if(mobShouldSee(mob))
|
||||
add_hud_to(mob)
|
||||
|
||||
/datum/atom_hud/alternate_appearance/basic/everyone/mobShouldSee(mob/M)
|
||||
return !isobserver(M)
|
||||
|
||||
/datum/atom_hud/alternate_appearance/basic/silicons
|
||||
|
||||
/datum/atom_hud/alternate_appearance/basic/silicons/New()
|
||||
..()
|
||||
for(var/mob in GLOB.silicon_mobs)
|
||||
if(mobShouldSee(mob))
|
||||
add_hud_to(mob)
|
||||
|
||||
/datum/atom_hud/alternate_appearance/basic/silicons/mobShouldSee(mob/M)
|
||||
if(issilicon(M))
|
||||
return TRUE
|
||||
return FALSE
|
||||
|
||||
/datum/atom_hud/alternate_appearance/basic/observers
|
||||
add_ghost_version = FALSE //just in case, to prevent infinite loops
|
||||
|
||||
/datum/atom_hud/alternate_appearance/basic/observers/New()
|
||||
..()
|
||||
for(var/mob in GLOB.dead_mob_list)
|
||||
if(mobShouldSee(mob))
|
||||
add_hud_to(mob)
|
||||
|
||||
/datum/atom_hud/alternate_appearance/basic/observers/mobShouldSee(mob/M)
|
||||
return isobserver(M)
|
||||
|
||||
/datum/atom_hud/alternate_appearance/basic/noncult
|
||||
|
||||
/datum/atom_hud/alternate_appearance/basic/noncult/New()
|
||||
..()
|
||||
for(var/mob in GLOB.player_list)
|
||||
if(mobShouldSee(mob))
|
||||
add_hud_to(mob)
|
||||
|
||||
/datum/atom_hud/alternate_appearance/basic/noncult/mobShouldSee(mob/M)
|
||||
if(!iscultist(M))
|
||||
return TRUE
|
||||
return FALSE
|
||||
|
||||
/datum/atom_hud/alternate_appearance/basic/cult
|
||||
|
||||
/datum/atom_hud/alternate_appearance/basic/cult/New()
|
||||
..()
|
||||
for(var/mob in GLOB.player_list)
|
||||
if(mobShouldSee(mob))
|
||||
add_hud_to(mob)
|
||||
|
||||
/datum/atom_hud/alternate_appearance/basic/cult/mobShouldSee(mob/M)
|
||||
if(iscultist(M))
|
||||
return TRUE
|
||||
return FALSE
|
||||
|
||||
/datum/atom_hud/alternate_appearance/basic/blessedAware
|
||||
|
||||
/datum/atom_hud/alternate_appearance/basic/blessedAware/New()
|
||||
..()
|
||||
for(var/mob in GLOB.mob_list)
|
||||
if(mobShouldSee(mob))
|
||||
add_hud_to(mob)
|
||||
|
||||
/datum/atom_hud/alternate_appearance/basic/blessedAware/mobShouldSee(mob/M)
|
||||
if(M.mind && (M.mind.assigned_role == "Chaplain"))
|
||||
return TRUE
|
||||
if (istype(M, /mob/living/simple_animal/hostile/construct/wraith))
|
||||
return TRUE
|
||||
if(isrevenant(M) || iseminence(M) || iswizard(M))
|
||||
return TRUE
|
||||
return FALSE
|
||||
|
||||
/datum/atom_hud/alternate_appearance/basic/onePerson
|
||||
var/mob/seer
|
||||
|
||||
/datum/atom_hud/alternate_appearance/basic/onePerson/mobShouldSee(mob/M)
|
||||
if(M == seer)
|
||||
return TRUE
|
||||
return FALSE
|
||||
|
||||
/datum/atom_hud/alternate_appearance/basic/onePerson/New(key, image/I, mob/living/M)
|
||||
..(key, I, FALSE)
|
||||
seer = M
|
||||
add_hud_to(seer)
|
||||
@@ -0,0 +1,126 @@
|
||||
/* HUD DATUMS */
|
||||
|
||||
GLOBAL_LIST_EMPTY(all_huds)
|
||||
|
||||
//GLOBAL HUD LIST
|
||||
GLOBAL_LIST_INIT(huds, list(
|
||||
DATA_HUD_SECURITY_BASIC = new/datum/atom_hud/data/human/security/basic(),
|
||||
DATA_HUD_SECURITY_ADVANCED = new/datum/atom_hud/data/human/security/advanced(),
|
||||
DATA_HUD_MEDICAL_BASIC = new/datum/atom_hud/data/human/medical/basic(),
|
||||
DATA_HUD_MEDICAL_ADVANCED = new/datum/atom_hud/data/human/medical/advanced(),
|
||||
DATA_HUD_DIAGNOSTIC_BASIC = new/datum/atom_hud/data/diagnostic/basic(),
|
||||
DATA_HUD_DIAGNOSTIC_ADVANCED = new/datum/atom_hud/data/diagnostic/advanced(),
|
||||
DATA_HUD_ABDUCTOR = new/datum/atom_hud/abductor(),
|
||||
DATA_HUD_SENTIENT_DISEASE = new/datum/atom_hud/sentient_disease(),
|
||||
DATA_HUD_AI_DETECT = new/datum/atom_hud/ai_detector(),
|
||||
ANTAG_HUD_CULT = new/datum/atom_hud/antag(),
|
||||
ANTAG_HUD_REV = new/datum/atom_hud/antag(),
|
||||
ANTAG_HUD_OPS = new/datum/atom_hud/antag(),
|
||||
ANTAG_HUD_WIZ = new/datum/atom_hud/antag(),
|
||||
ANTAG_HUD_SHADOW = new/datum/atom_hud/antag(),
|
||||
ANTAG_HUD_TRAITOR = new/datum/atom_hud/antag/hidden(),
|
||||
ANTAG_HUD_NINJA = new/datum/atom_hud/antag/hidden(),
|
||||
ANTAG_HUD_CHANGELING = new/datum/atom_hud/antag/hidden(),
|
||||
ANTAG_HUD_ABDUCTOR = new/datum/atom_hud/antag/hidden(),
|
||||
ANTAG_HUD_DEVIL = new/datum/atom_hud/antag(),
|
||||
ANTAG_HUD_SINTOUCHED = new/datum/atom_hud/antag/hidden(),
|
||||
ANTAG_HUD_SOULLESS = new/datum/atom_hud/antag/hidden(),
|
||||
ANTAG_HUD_CLOCKWORK = new/datum/atom_hud/antag(),
|
||||
ANTAG_HUD_BROTHER = new/datum/atom_hud/antag/hidden(),
|
||||
ANTAG_HUD_BLOODSUCKER = new/datum/atom_hud/antag/bloodsucker(),
|
||||
ANTAG_HUD_FUGITIVE = new/datum/atom_hud/antag(),
|
||||
ANTAG_HUD_HERETIC = new/datum/atom_hud/antag/hidden()
|
||||
))
|
||||
|
||||
/datum/atom_hud
|
||||
var/list/atom/hudatoms = list() //list of all atoms which display this hud
|
||||
var/list/hudusers = list() //list with all mobs who can see the hud
|
||||
var/list/hud_icons = list() //these will be the indexes for the atom's hud_list
|
||||
|
||||
var/list/next_time_allowed = list() //mobs associated with the next time this hud can be added to them
|
||||
var/list/queued_to_see = list() //mobs that have triggered the cooldown and are queued to see the hud, but do not yet
|
||||
|
||||
/datum/atom_hud/New()
|
||||
GLOB.all_huds += src
|
||||
|
||||
/datum/atom_hud/Destroy()
|
||||
for(var/v in hudusers)
|
||||
remove_hud_from(v)
|
||||
for(var/v in hudatoms)
|
||||
remove_from_hud(v)
|
||||
GLOB.all_huds -= src
|
||||
return ..()
|
||||
|
||||
/datum/atom_hud/proc/remove_hud_from(mob/M)
|
||||
if(!M || !hudusers[M])
|
||||
return
|
||||
if (!--hudusers[M])
|
||||
hudusers -= M
|
||||
if(queued_to_see[M])
|
||||
queued_to_see -= M
|
||||
else
|
||||
for(var/atom/A in hudatoms)
|
||||
remove_from_single_hud(M, A)
|
||||
|
||||
/datum/atom_hud/proc/remove_from_hud(atom/A)
|
||||
if(!A)
|
||||
return FALSE
|
||||
for(var/mob/M in hudusers)
|
||||
remove_from_single_hud(M, A)
|
||||
hudatoms -= A
|
||||
return TRUE
|
||||
|
||||
/datum/atom_hud/proc/remove_from_single_hud(mob/M, atom/A) //unsafe, no sanity apart from client
|
||||
if(!M || !M.client || !A)
|
||||
return
|
||||
for(var/i in hud_icons)
|
||||
M.client.images -= A.hud_list[i]
|
||||
|
||||
/datum/atom_hud/proc/add_hud_to(mob/M)
|
||||
if(!M)
|
||||
return
|
||||
if(!hudusers[M])
|
||||
hudusers[M] = 1
|
||||
if(next_time_allowed[M] > world.time)
|
||||
if(!queued_to_see[M])
|
||||
addtimer(CALLBACK(src, .proc/show_hud_images_after_cooldown, M), next_time_allowed[M] - world.time)
|
||||
queued_to_see[M] = TRUE
|
||||
else
|
||||
next_time_allowed[M] = world.time + ADD_HUD_TO_COOLDOWN
|
||||
for(var/atom/A in hudatoms)
|
||||
add_to_single_hud(M, A)
|
||||
else
|
||||
hudusers[M]++
|
||||
|
||||
/datum/atom_hud/proc/show_hud_images_after_cooldown(M)
|
||||
if(queued_to_see[M])
|
||||
queued_to_see -= M
|
||||
next_time_allowed[M] = world.time + ADD_HUD_TO_COOLDOWN
|
||||
for(var/atom/A in hudatoms)
|
||||
add_to_single_hud(M, A)
|
||||
|
||||
/datum/atom_hud/proc/add_to_hud(atom/A)
|
||||
if(!A)
|
||||
return FALSE
|
||||
hudatoms |= A
|
||||
for(var/mob/M in hudusers)
|
||||
if(!queued_to_see[M])
|
||||
add_to_single_hud(M, A)
|
||||
return TRUE
|
||||
|
||||
/datum/atom_hud/proc/add_to_single_hud(mob/M, atom/A) //unsafe, no sanity apart from client
|
||||
if(!M || !M.client || !A)
|
||||
return
|
||||
for(var/i in hud_icons)
|
||||
if(A.hud_list[i])
|
||||
M.client.images |= A.hud_list[i]
|
||||
|
||||
//MOB PROCS
|
||||
/mob/proc/reload_huds()
|
||||
for(var/datum/atom_hud/hud in GLOB.all_huds)
|
||||
if(hud && hud.hudusers[src])
|
||||
for(var/atom/A in hud.hudatoms)
|
||||
hud.add_to_single_hud(src, A)
|
||||
|
||||
/mob/dead/new_player/reload_huds()
|
||||
return
|
||||
@@ -0,0 +1,523 @@
|
||||
/*
|
||||
* Data HUDs have been rewritten in a more generic way.
|
||||
* In short, they now use an observer-listener pattern.
|
||||
* See code/datum/hud.dm for the generic hud datum.
|
||||
* Update the HUD icons when needed with the appropriate hook. (see below)
|
||||
*/
|
||||
|
||||
/* DATA HUD DATUMS */
|
||||
|
||||
/atom/proc/add_to_all_human_data_huds()
|
||||
for(var/datum/atom_hud/data/human/hud in GLOB.huds)
|
||||
hud.add_to_hud(src)
|
||||
|
||||
/atom/proc/remove_from_all_data_huds()
|
||||
for(var/datum/atom_hud/data/hud in GLOB.huds)
|
||||
hud.remove_from_hud(src)
|
||||
|
||||
/datum/atom_hud/data
|
||||
|
||||
/datum/atom_hud/data/human/medical
|
||||
hud_icons = list(STATUS_HUD, HEALTH_HUD, NANITE_HUD, RAD_HUD)
|
||||
|
||||
/datum/atom_hud/data/human/medical/basic
|
||||
|
||||
/datum/atom_hud/data/human/medical/basic/proc/check_sensors(mob/living/carbon/human/H)
|
||||
if(!istype(H))
|
||||
return 0
|
||||
var/obj/item/clothing/under/U = H.w_uniform
|
||||
if(!istype(U))
|
||||
return 0
|
||||
if(U.sensor_mode <= SENSOR_VITALS)
|
||||
return 0
|
||||
return 1
|
||||
|
||||
/datum/atom_hud/data/human/medical/basic/add_to_single_hud(mob/M, mob/living/carbon/H)
|
||||
if(check_sensors(H))
|
||||
..()
|
||||
|
||||
/datum/atom_hud/data/human/medical/basic/proc/update_suit_sensors(mob/living/carbon/H)
|
||||
check_sensors(H) ? add_to_hud(H) : remove_from_hud(H)
|
||||
|
||||
/datum/atom_hud/data/human/medical/advanced
|
||||
|
||||
/datum/atom_hud/data/human/security
|
||||
|
||||
/datum/atom_hud/data/human/security/basic
|
||||
hud_icons = list(ID_HUD)
|
||||
|
||||
/datum/atom_hud/data/human/security/advanced
|
||||
hud_icons = list(ID_HUD, IMPTRACK_HUD, IMPLOYAL_HUD, IMPCHEM_HUD, WANTED_HUD, NANITE_HUD)
|
||||
|
||||
/datum/atom_hud/data/diagnostic
|
||||
|
||||
/datum/atom_hud/data/diagnostic/basic
|
||||
hud_icons = list(DIAG_HUD, DIAG_STAT_HUD, DIAG_BATT_HUD, DIAG_MECH_HUD, DIAG_BOT_HUD, DIAG_CIRCUIT_HUD, DIAG_TRACK_HUD, DIAG_AIRLOCK_HUD, DIAG_NANITE_FULL_HUD)
|
||||
|
||||
/datum/atom_hud/data/diagnostic/advanced
|
||||
hud_icons = list(DIAG_HUD, DIAG_STAT_HUD, DIAG_BATT_HUD, DIAG_MECH_HUD, DIAG_BOT_HUD, DIAG_CIRCUIT_HUD, DIAG_TRACK_HUD, DIAG_AIRLOCK_HUD, DIAG_NANITE_FULL_HUD, DIAG_PATH_HUD)
|
||||
|
||||
/datum/atom_hud/data/bot_path
|
||||
hud_icons = list(DIAG_PATH_HUD)
|
||||
|
||||
/datum/atom_hud/abductor
|
||||
hud_icons = list(GLAND_HUD)
|
||||
|
||||
/datum/atom_hud/sentient_disease
|
||||
hud_icons = list(SENTIENT_DISEASE_HUD)
|
||||
|
||||
/datum/atom_hud/ai_detector
|
||||
hud_icons = list(AI_DETECT_HUD)
|
||||
|
||||
/datum/atom_hud/ai_detector/add_hud_to(mob/M)
|
||||
..()
|
||||
if(M && (hudusers.len == 1))
|
||||
for(var/V in GLOB.aiEyes)
|
||||
var/mob/camera/aiEye/E = V
|
||||
E.update_ai_detect_hud()
|
||||
|
||||
/* MED/SEC/DIAG HUD HOOKS */
|
||||
|
||||
/*
|
||||
* THESE HOOKS SHOULD BE CALLED BY THE MOB SHOWING THE HUD
|
||||
*/
|
||||
|
||||
/***********************************************
|
||||
Medical HUD! Basic mode needs suit sensors on.
|
||||
************************************************/
|
||||
|
||||
//HELPERS
|
||||
|
||||
//called when a carbon changes virus
|
||||
/mob/living/carbon/proc/check_virus()
|
||||
var/threat
|
||||
for(var/thing in diseases)
|
||||
var/datum/disease/D = thing
|
||||
if(!(D.visibility_flags & HIDDEN_SCANNER))
|
||||
if(!threat || D.severity > threat) //a buffing virus gets an icon
|
||||
threat = D.severity
|
||||
return threat
|
||||
|
||||
//helper for getting the appropriate health status
|
||||
/proc/RoundHealth(mob/living/M)
|
||||
if(M.stat == DEAD || (HAS_TRAIT(M, TRAIT_FAKEDEATH)))
|
||||
return "health-100" //what's our health? it doesn't matter, we're dead, or faking
|
||||
var/maxi_health = M.maxHealth
|
||||
if(iscarbon(M) && M.health < 0)
|
||||
maxi_health = 100 //so crit shows up right for aliens and other high-health carbon mobs; noncarbons don't have crit.
|
||||
var/resulthealth = (M.health / maxi_health) * 100
|
||||
switch(resulthealth)
|
||||
if(100 to INFINITY)
|
||||
return "health100"
|
||||
if(90.625 to 100)
|
||||
return "health93.75"
|
||||
if(84.375 to 90.625)
|
||||
return "health87.5"
|
||||
if(78.125 to 84.375)
|
||||
return "health81.25"
|
||||
if(71.875 to 78.125)
|
||||
return "health75"
|
||||
if(65.625 to 71.875)
|
||||
return "health68.75"
|
||||
if(59.375 to 65.625)
|
||||
return "health62.5"
|
||||
if(53.125 to 59.375)
|
||||
return "health56.25"
|
||||
if(46.875 to 53.125)
|
||||
return "health50"
|
||||
if(40.625 to 46.875)
|
||||
return "health43.75"
|
||||
if(34.375 to 40.625)
|
||||
return "health37.5"
|
||||
if(28.125 to 34.375)
|
||||
return "health31.25"
|
||||
if(21.875 to 28.125)
|
||||
return "health25"
|
||||
if(15.625 to 21.875)
|
||||
return "health18.75"
|
||||
if(9.375 to 15.625)
|
||||
return "health12.5"
|
||||
if(1 to 9.375)
|
||||
return "health6.25"
|
||||
if(-50 to 1)
|
||||
return "health0"
|
||||
if(-85 to -50)
|
||||
return "health-50"
|
||||
if(-99 to -85)
|
||||
return "health-85"
|
||||
else
|
||||
return "health-100"
|
||||
|
||||
//HOOKS
|
||||
|
||||
//called when a human changes suit sensors
|
||||
/mob/living/carbon/proc/update_suit_sensors()
|
||||
var/datum/atom_hud/data/human/medical/basic/B = GLOB.huds[DATA_HUD_MEDICAL_BASIC]
|
||||
B.update_suit_sensors(src)
|
||||
|
||||
//called when a living mob changes health
|
||||
/mob/living/proc/med_hud_set_health()
|
||||
var/image/holder = hud_list[HEALTH_HUD]
|
||||
holder.icon_state = "hud[RoundHealth(src)]"
|
||||
var/icon/I = icon(icon, icon_state, dir)
|
||||
holder.pixel_y = I.Height() - world.icon_size
|
||||
med_hud_set_radstatus()
|
||||
|
||||
//for carbon suit sensors
|
||||
/mob/living/carbon/med_hud_set_health()
|
||||
..()
|
||||
|
||||
//called when a carbon changes stat, virus or XENO_HOST
|
||||
/mob/living/proc/med_hud_set_status()
|
||||
var/image/holder = hud_list[STATUS_HUD]
|
||||
var/icon/I = icon(icon, icon_state, dir)
|
||||
holder.pixel_y = I.Height() - world.icon_size
|
||||
if(stat == DEAD || (HAS_TRAIT(src, TRAIT_FAKEDEATH)))
|
||||
holder.icon_state = "huddead"
|
||||
else
|
||||
holder.icon_state = "hudhealthy"
|
||||
|
||||
/mob/living/carbon/med_hud_set_status()
|
||||
var/image/holder = hud_list[STATUS_HUD]
|
||||
var/icon/I = icon(icon, icon_state, dir)
|
||||
var/virus_threat = check_virus()
|
||||
holder.pixel_y = I.Height() - world.icon_size
|
||||
if(HAS_TRAIT(src, TRAIT_XENO_HOST))
|
||||
holder.icon_state = "hudxeno"
|
||||
else if(stat == DEAD || (HAS_TRAIT(src, TRAIT_FAKEDEATH)))
|
||||
if(tod)
|
||||
var/tdelta = round(world.time - timeofdeath)
|
||||
if(tdelta < (DEFIB_TIME_LIMIT * 10))
|
||||
var/obj/item/organ/heart/He = getorgan(/obj/item/organ/heart)
|
||||
if(He)
|
||||
holder.icon_state = "huddefib"
|
||||
if(He.organ_flags & ORGAN_FAILING)
|
||||
holder.icon_state = "huddefibheart"
|
||||
else
|
||||
holder.icon_state = "huddefibheart"
|
||||
return
|
||||
holder.icon_state = "huddead"
|
||||
else
|
||||
switch(virus_threat)
|
||||
if(DISEASE_SEVERITY_BIOHAZARD)
|
||||
holder.icon_state = "hudill5"
|
||||
if(DISEASE_SEVERITY_DANGEROUS)
|
||||
holder.icon_state = "hudill4"
|
||||
if(DISEASE_SEVERITY_HARMFUL)
|
||||
holder.icon_state = "hudill3"
|
||||
if(DISEASE_SEVERITY_MEDIUM)
|
||||
holder.icon_state = "hudill2"
|
||||
if(DISEASE_SEVERITY_MINOR)
|
||||
holder.icon_state = "hudill1"
|
||||
if(DISEASE_SEVERITY_NONTHREAT)
|
||||
holder.icon_state = "hudill0"
|
||||
if(DISEASE_SEVERITY_POSITIVE)
|
||||
holder.icon_state = "hudbuff"
|
||||
if(null)
|
||||
holder.icon_state = "hudhealthy"
|
||||
|
||||
|
||||
/mob/living/proc/med_hud_set_radstatus()
|
||||
var/image/radholder = hud_list[RAD_HUD]
|
||||
var/icon/I = icon(icon, icon_state, dir)
|
||||
radholder.pixel_y = I.Height() - world.icon_size
|
||||
var/mob/living/M = src
|
||||
var/rads = M.radiation
|
||||
switch(rads)
|
||||
if(-INFINITY to RAD_MOB_SAFE)
|
||||
radholder.icon_state = "hudradsafe"
|
||||
if((RAD_MOB_SAFE+1) to RAD_MOB_MUTATE)
|
||||
radholder.icon_state = "hudraddanger"
|
||||
if((RAD_MOB_MUTATE+1) to RAD_MOB_VOMIT)
|
||||
radholder.icon_state = "hudradlethal"
|
||||
if((RAD_MOB_VOMIT+1) to INFINITY)
|
||||
radholder.icon_state = "hudradnuke"
|
||||
|
||||
/***********************************************
|
||||
Security HUDs! Basic mode shows only the job.
|
||||
************************************************/
|
||||
|
||||
//HOOKS
|
||||
|
||||
/mob/living/carbon/human/proc/sec_hud_set_ID()
|
||||
var/image/holder = hud_list[ID_HUD]
|
||||
var/icon/I = icon(icon, icon_state, dir)
|
||||
holder.pixel_y = I.Height() - world.icon_size
|
||||
holder.icon_state = "hudno_id"
|
||||
if(wear_id?.GetID())
|
||||
holder.icon_state = "hud[ckey(wear_id.GetJobName())]"
|
||||
sec_hud_set_security_status()
|
||||
|
||||
/mob/living/proc/sec_hud_set_implants()
|
||||
var/image/holder
|
||||
for(var/i in list(IMPTRACK_HUD, IMPLOYAL_HUD, IMPCHEM_HUD))
|
||||
holder = hud_list[i]
|
||||
holder.icon_state = null
|
||||
for(var/obj/item/implant/I in implants)
|
||||
if(istype(I, /obj/item/implant/tracking))
|
||||
holder = hud_list[IMPTRACK_HUD]
|
||||
var/icon/IC = icon(icon, icon_state, dir)
|
||||
holder.pixel_y = IC.Height() - world.icon_size
|
||||
holder.icon_state = "hud_imp_tracking"
|
||||
else if(istype(I, /obj/item/implant/chem))
|
||||
holder = hud_list[IMPCHEM_HUD]
|
||||
var/icon/IC = icon(icon, icon_state, dir)
|
||||
holder.pixel_y = IC.Height() - world.icon_size
|
||||
holder.icon_state = "hud_imp_chem"
|
||||
if(HAS_TRAIT(src, TRAIT_MINDSHIELD))
|
||||
holder = hud_list[IMPLOYAL_HUD]
|
||||
var/icon/IC = icon(icon, icon_state, dir)
|
||||
holder.pixel_y = IC.Height() - world.icon_size
|
||||
holder.icon_state = "hud_imp_loyal"
|
||||
|
||||
/mob/living/carbon/human/proc/sec_hud_set_security_status()
|
||||
var/image/holder = hud_list[WANTED_HUD]
|
||||
var/icon/I = icon(icon, icon_state, dir)
|
||||
holder.pixel_y = I.Height() - world.icon_size
|
||||
var/perpname = get_face_name(get_id_name(""))
|
||||
if(perpname && GLOB.data_core)
|
||||
var/datum/data/record/R = find_record("name", perpname, GLOB.data_core.security)
|
||||
if(R)
|
||||
switch(R.fields["criminal"])
|
||||
if("*Arrest*")
|
||||
holder.icon_state = "hudwanted"
|
||||
return
|
||||
if("Incarcerated")
|
||||
holder.icon_state = "hudincarcerated"
|
||||
return
|
||||
if("Paroled")
|
||||
holder.icon_state = "hudparolled"
|
||||
return
|
||||
if("Discharged")
|
||||
holder.icon_state = "huddischarged"
|
||||
return
|
||||
holder.icon_state = null
|
||||
|
||||
/***********************************************
|
||||
Diagnostic HUDs!
|
||||
************************************************/
|
||||
|
||||
/mob/living/proc/hud_set_nanite_indicator()
|
||||
var/image/holder = hud_list[NANITE_HUD]
|
||||
var/icon/I = icon(icon, icon_state, dir)
|
||||
holder.pixel_y = I.Height() - world.icon_size
|
||||
holder.icon_state = null
|
||||
if(src in SSnanites.nanite_monitored_mobs)
|
||||
holder.icon_state = "nanite_ping"
|
||||
|
||||
//For Diag health and cell bars!
|
||||
/proc/RoundDiagBar(value)
|
||||
switch(value * 100)
|
||||
if(95 to INFINITY)
|
||||
return "max"
|
||||
if(80 to 100)
|
||||
return "good"
|
||||
if(60 to 80)
|
||||
return "high"
|
||||
if(40 to 60)
|
||||
return "med"
|
||||
if(20 to 40)
|
||||
return "low"
|
||||
if(1 to 20)
|
||||
return "crit"
|
||||
else
|
||||
return "dead"
|
||||
|
||||
//Sillycone hooks
|
||||
/mob/living/silicon/proc/diag_hud_set_health()
|
||||
var/image/holder = hud_list[DIAG_HUD]
|
||||
var/icon/I = icon(icon, icon_state, dir)
|
||||
holder.pixel_y = I.Height() - world.icon_size
|
||||
if(stat == DEAD)
|
||||
holder.icon_state = "huddiagdead"
|
||||
else
|
||||
holder.icon_state = "huddiag[RoundDiagBar(health/maxHealth)]"
|
||||
|
||||
/mob/living/silicon/proc/diag_hud_set_status()
|
||||
var/image/holder = hud_list[DIAG_STAT_HUD]
|
||||
var/icon/I = icon(icon, icon_state, dir)
|
||||
holder.pixel_y = I.Height() - world.icon_size
|
||||
switch(stat)
|
||||
if(CONSCIOUS)
|
||||
holder.icon_state = "hudstat"
|
||||
if(UNCONSCIOUS)
|
||||
holder.icon_state = "hudoffline"
|
||||
else
|
||||
holder.icon_state = "huddead2"
|
||||
|
||||
//Borgie battery tracking!
|
||||
/mob/living/silicon/robot/proc/diag_hud_set_borgcell()
|
||||
var/image/holder = hud_list[DIAG_BATT_HUD]
|
||||
var/icon/I = icon(icon, icon_state, dir)
|
||||
holder.pixel_y = I.Height() - world.icon_size
|
||||
if(cell)
|
||||
var/chargelvl = (cell.charge/cell.maxcharge)
|
||||
holder.icon_state = "hudbatt[RoundDiagBar(chargelvl)]"
|
||||
else
|
||||
holder.icon_state = "hudnobatt"
|
||||
|
||||
//borg-AI shell tracking
|
||||
/mob/living/silicon/robot/proc/diag_hud_set_aishell() //Shows tracking beacons on the mech
|
||||
var/image/holder = hud_list[DIAG_TRACK_HUD]
|
||||
var/icon/I = icon(icon, icon_state, dir)
|
||||
holder.pixel_y = I.Height() - world.icon_size
|
||||
if(!shell) //Not an AI shell
|
||||
holder.icon_state = null
|
||||
else if(deployed) //AI shell in use by an AI
|
||||
holder.icon_state = "hudtrackingai"
|
||||
else //Empty AI shell
|
||||
holder.icon_state = "hudtracking"
|
||||
|
||||
//AI side tracking of AI shell control
|
||||
/mob/living/silicon/ai/proc/diag_hud_set_deployed() //Shows tracking beacons on the mech
|
||||
var/image/holder = hud_list[DIAG_TRACK_HUD]
|
||||
var/icon/I = icon(icon, icon_state, dir)
|
||||
holder.pixel_y = I.Height() - world.icon_size
|
||||
if(!deployed_shell)
|
||||
holder.icon_state = null
|
||||
else //AI is currently controlling a shell
|
||||
holder.icon_state = "hudtrackingai"
|
||||
|
||||
/*~~~~~~~~~~~~~~~~~~~~
|
||||
BIG STOMPY MECHS
|
||||
~~~~~~~~~~~~~~~~~~~~~*/
|
||||
/obj/mecha/proc/diag_hud_set_mechhealth()
|
||||
var/image/holder = hud_list[DIAG_MECH_HUD]
|
||||
var/icon/I = icon(icon, icon_state, dir)
|
||||
holder.pixel_y = I.Height() - world.icon_size
|
||||
holder.icon_state = "huddiag[RoundDiagBar(obj_integrity/max_integrity)]"
|
||||
|
||||
|
||||
/obj/mecha/proc/diag_hud_set_mechcell()
|
||||
var/image/holder = hud_list[DIAG_BATT_HUD]
|
||||
var/icon/I = icon(icon, icon_state, dir)
|
||||
holder.pixel_y = I.Height() - world.icon_size
|
||||
if(cell)
|
||||
var/chargelvl = cell.charge/cell.maxcharge
|
||||
holder.icon_state = "hudbatt[RoundDiagBar(chargelvl)]"
|
||||
else
|
||||
holder.icon_state = "hudnobatt"
|
||||
|
||||
|
||||
/obj/mecha/proc/diag_hud_set_mechstat()
|
||||
var/image/holder = hud_list[DIAG_STAT_HUD]
|
||||
var/icon/I = icon(icon, icon_state, dir)
|
||||
holder.pixel_y = I.Height() - world.icon_size
|
||||
holder.icon_state = null
|
||||
if(internal_damage)
|
||||
holder.icon_state = "hudwarn"
|
||||
|
||||
/obj/mecha/proc/diag_hud_set_mechtracking() //Shows tracking beacons on the mech
|
||||
var/image/holder = hud_list[DIAG_TRACK_HUD]
|
||||
var/icon/I = icon(icon, icon_state, dir)
|
||||
holder.pixel_y = I.Height() - world.icon_size
|
||||
var/new_icon_state //This var exists so that the holder's icon state is set only once in the event of multiple mech beacons.
|
||||
for(var/obj/item/mecha_parts/mecha_tracking/T in trackers)
|
||||
if(T.ai_beacon) //Beacon with AI uplink
|
||||
new_icon_state = "hudtrackingai"
|
||||
break //Immediately terminate upon finding an AI beacon to ensure it is always shown over the normal one, as mechs can have several trackers.
|
||||
else
|
||||
new_icon_state = "hudtracking"
|
||||
holder.icon_state = new_icon_state
|
||||
|
||||
/*~~~~~~~~~
|
||||
Bots!
|
||||
~~~~~~~~~~*/
|
||||
/mob/living/simple_animal/bot/proc/diag_hud_set_bothealth()
|
||||
var/image/holder = hud_list[DIAG_HUD]
|
||||
var/icon/I = icon(icon, icon_state, dir)
|
||||
holder.pixel_y = I.Height() - world.icon_size
|
||||
holder.icon_state = "huddiag[RoundDiagBar(health/maxHealth)]"
|
||||
|
||||
/mob/living/simple_animal/bot/proc/diag_hud_set_botstat() //On (With wireless on or off), Off, EMP'ed
|
||||
var/image/holder = hud_list[DIAG_STAT_HUD]
|
||||
var/icon/I = icon(icon, icon_state, dir)
|
||||
holder.pixel_y = I.Height() - world.icon_size
|
||||
if(on)
|
||||
holder.icon_state = "hudstat"
|
||||
else if(stat) //Generally EMP causes this
|
||||
holder.icon_state = "hudoffline"
|
||||
else //Bot is off
|
||||
holder.icon_state = "huddead2"
|
||||
|
||||
/mob/living/simple_animal/bot/proc/diag_hud_set_botmode() //Shows a bot's current operation
|
||||
var/image/holder = hud_list[DIAG_BOT_HUD]
|
||||
var/icon/I = icon(icon, icon_state, dir)
|
||||
holder.pixel_y = I.Height() - world.icon_size
|
||||
if(client) //If the bot is player controlled, it will not be following mode logic!
|
||||
holder.icon_state = "hudsentient"
|
||||
return
|
||||
|
||||
switch(mode)
|
||||
if(BOT_SUMMON, BOT_RESPONDING) //Responding to PDA or AI summons
|
||||
holder.icon_state = "hudcalled"
|
||||
if(BOT_CLEANING, BOT_REPAIRING, BOT_HEALING) //Cleanbot cleaning, Floorbot fixing, or Medibot Healing
|
||||
holder.icon_state = "hudworking"
|
||||
if(BOT_PATROL, BOT_START_PATROL) //Patrol mode
|
||||
holder.icon_state = "hudpatrol"
|
||||
if(BOT_PREP_ARREST, BOT_ARREST, BOT_HUNT) //STOP RIGHT THERE, CRIMINAL SCUM!
|
||||
holder.icon_state = "hudalert"
|
||||
if(BOT_MOVING, BOT_DELIVER, BOT_GO_HOME, BOT_NAV) //Moving to target for normal bots, moving to deliver or go home for MULES.
|
||||
holder.icon_state = "hudmove"
|
||||
else
|
||||
holder.icon_state = ""
|
||||
|
||||
/*~~~~~~~~~~~~
|
||||
Circutry!
|
||||
~~~~~~~~~~~~~*/
|
||||
/obj/item/electronic_assembly/proc/diag_hud_set_circuithealth(hide = FALSE)
|
||||
var/image/holder = hud_list[DIAG_CIRCUIT_HUD]
|
||||
var/icon/I = icon(icon, icon_state, dir)
|
||||
holder.pixel_y = I.Height() - world.icon_size
|
||||
if((!isturf(loc))||hide) //if not on the ground dont show overlay
|
||||
holder.icon_state = null
|
||||
else
|
||||
holder.icon_state = "huddiag[RoundDiagBar(obj_integrity/max_integrity)]"
|
||||
|
||||
/obj/item/electronic_assembly/proc/diag_hud_set_circuitcell(hide = FALSE)
|
||||
var/image/holder = hud_list[DIAG_BATT_HUD]
|
||||
var/icon/I = icon(icon, icon_state, dir)
|
||||
holder.pixel_y = I.Height() - world.icon_size
|
||||
if((!isturf(loc))||hide) //if not on the ground dont show overlay
|
||||
holder.icon_state = null
|
||||
else if(battery)
|
||||
var/chargelvl = battery.charge/battery.maxcharge
|
||||
holder.icon_state = "hudbatt[RoundDiagBar(chargelvl)]"
|
||||
else
|
||||
holder.icon_state = "hudnobatt"
|
||||
|
||||
/obj/item/electronic_assembly/proc/diag_hud_set_circuitstat(hide = FALSE) //On, On and dangerous, or Off
|
||||
var/image/holder = hud_list[DIAG_STAT_HUD]
|
||||
var/icon/I = icon(icon, icon_state, dir)
|
||||
holder.pixel_y = I.Height() - world.icon_size
|
||||
if((!isturf(loc))||hide) //if not on the ground don't show overlay
|
||||
holder.icon_state = null
|
||||
else if(!battery)
|
||||
holder.icon_state = "hudoffline"
|
||||
else if(battery.charge == 0)
|
||||
holder.icon_state = "hudoffline"
|
||||
else if(combat_circuits) //has a circuit that can harm people
|
||||
holder.icon_state = prefered_hud_icon + "-red"
|
||||
else //Bot is on and not dangerous
|
||||
holder.icon_state = prefered_hud_icon
|
||||
|
||||
/obj/item/electronic_assembly/proc/diag_hud_set_circuittracking(hide = FALSE)
|
||||
var/image/holder = hud_list[DIAG_TRACK_HUD]
|
||||
var/icon/I = icon(icon, icon_state, dir)
|
||||
holder.pixel_y = I.Height() - world.icon_size
|
||||
if((!isturf(loc))||hide) //if not on the ground dont show overlay
|
||||
holder.icon_state = null
|
||||
else if(long_range_circuits)
|
||||
holder.icon_state = "hudtracking"
|
||||
else
|
||||
holder.icon_state = null
|
||||
|
||||
/*~~~~~~~~~~~~
|
||||
Airlocks!
|
||||
~~~~~~~~~~~~~*/
|
||||
/obj/machinery/door/airlock/proc/diag_hud_set_electrified()
|
||||
var/image/holder = hud_list[DIAG_AIRLOCK_HUD]
|
||||
if(secondsElectrified != 0)
|
||||
holder.icon_state = "electrified"
|
||||
else
|
||||
holder.icon_state = ""
|
||||
@@ -0,0 +1,74 @@
|
||||
/atom/movable/screen/click_catcher
|
||||
icon = 'icons/screen/clickcatcher.dmi'
|
||||
icon_state = "catcher"
|
||||
appearance_flags = TILE_BOUND | NO_CLIENT_COLOR | RESET_TRANSFORM | RESET_COLOR | RESET_ALPHA
|
||||
plane = CLICKCATCHER_PLANE
|
||||
plane = CLICKCATCHER_PLANE
|
||||
mouse_opacity = MOUSE_OPACITY_OPAQUE
|
||||
screen_loc = "CENTER"
|
||||
|
||||
/*
|
||||
#define MAX_SAFE_BYOND_ICON_SCALE_TILES (MAX_SAFE_BYOND_ICON_SCALE_PX / world.icon_size)
|
||||
#define MAX_SAFE_BYOND_ICON_SCALE_PX (33 * 32) //Not using world.icon_size on purpose.
|
||||
|
||||
/atom/movable/screen/click_catcher/proc/UpdateFill(view_size_x = 15, view_size_y = 15)
|
||||
var/icon/newicon = icon('icons/mob/screen_gen.dmi', "catcher")
|
||||
var/ox = min(MAX_SAFE_BYOND_ICON_SCALE_TILES, view_size_x)
|
||||
var/oy = min(MAX_SAFE_BYOND_ICON_SCALE_TILES, view_size_y)
|
||||
var/px = view_size_x * world.icon_size
|
||||
var/py = view_size_y * world.icon_size
|
||||
var/sx = min(MAX_SAFE_BYOND_ICON_SCALE_PX, px)
|
||||
var/sy = min(MAX_SAFE_BYOND_ICON_SCALE_PX, py)
|
||||
newicon.Scale(sx, sy)
|
||||
icon = newicon
|
||||
screen_loc = "CENTER-[(ox-1)*0.5],CENTER-[(oy-1)*0.5]"
|
||||
var/matrix/M = new
|
||||
M.Scale(px/sx, py/sy)
|
||||
transform = M
|
||||
|
||||
#undef MAX_SAFE_BYOND_ICON_SCALE_TILES
|
||||
#undef MAX_SAFE_BYOND_ICON_SCALE_PX
|
||||
*/
|
||||
|
||||
/atom/movable/screen/click_catcher/proc/UpdateFill(view_size_x, view_size_y)
|
||||
screen_loc = "1,1 to [view_size_x],[view_size_y]"
|
||||
|
||||
/atom/movable/screen/click_catcher/Click(location, control, params)
|
||||
var/list/modifiers = params2list(params)
|
||||
if(modifiers["middle"] && iscarbon(usr))
|
||||
var/mob/living/carbon/C = usr
|
||||
C.swap_hand()
|
||||
else
|
||||
var/turf/T = Parse(modifiers["screen-loc"], get_turf(usr.client?.eye || usr), usr.client)
|
||||
params += "&catcher=1"
|
||||
if(T)
|
||||
T.Click(location, control, params)
|
||||
return TRUE
|
||||
|
||||
/atom/movable/screen/click_catcher/proc/Parse(scr_loc, turf/origin, client/C)
|
||||
// screen-loc: Pixel coordinates in screen_loc format ("[tile_x]:[pixel_x],[tile_y]:[pixel_y]")
|
||||
if(!scr_loc)
|
||||
return null
|
||||
var/tX = splittext(scr_loc, ",")
|
||||
var/tY = splittext(tX[2], ":")
|
||||
var/tZ = origin.z
|
||||
tY = tY[1]
|
||||
tX = splittext(tX[1], ":")
|
||||
tX = tX[1]
|
||||
var/list/actual_view = getviewsize(C ? C.view : world.view)
|
||||
tX = clamp(origin.x + text2num(tX) - round(actual_view[1] / 2) - 1, 1, world.maxx)
|
||||
tY = clamp(origin.y + text2num(tY) - round(actual_view[2] / 2) - 1, 1, world.maxy)
|
||||
return locate(tX, tY, tZ)
|
||||
|
||||
/**
|
||||
* Makes a clickcatcher if necessary, and ensures it's fit to our size.
|
||||
*/
|
||||
/client/proc/update_clickcatcher(list/view_override)
|
||||
if(!click_catcher)
|
||||
click_catcher = new
|
||||
screen |= click_catcher
|
||||
if(view_override)
|
||||
click_catcher.UpdateFill(view_override[1], view_override[2])
|
||||
else
|
||||
var/list/view_list = getviewsize(view)
|
||||
click_catcher.UpdateFill(view_list[1], view_list[2])
|
||||
@@ -0,0 +1,234 @@
|
||||
/**
|
||||
* Adds a fullscreen overlay
|
||||
*
|
||||
* @params
|
||||
* - category - string - must exist. will overwrite any other screen in this category. defaults to type.
|
||||
* - type - the typepath of the screen
|
||||
* - severity - severity - different screen objects have differing severities
|
||||
*/
|
||||
/mob/proc/overlay_fullscreen(category, type, severity)
|
||||
ASSERT(type)
|
||||
if(!category)
|
||||
category = type
|
||||
var/atom/movable/screen/fullscreen/screen = fullscreens[category]
|
||||
if (!screen || screen.type != type)
|
||||
// needs to be recreated
|
||||
clear_fullscreen(category, 0)
|
||||
fullscreens[category] = screen = new type
|
||||
screen.SetSeverity(severity)
|
||||
if(client && screen.ShouldShow(src))
|
||||
screen.SetView(client.view)
|
||||
client.screen += screen
|
||||
return screen
|
||||
|
||||
/**
|
||||
* Wipes a fullscreen of a certain category
|
||||
*
|
||||
* Second argument is for animation delay.
|
||||
*/
|
||||
/mob/proc/clear_fullscreen(category, animated = 10)
|
||||
if(!fullscreens)
|
||||
return
|
||||
var/atom/movable/screen/fullscreen/screen = fullscreens[category]
|
||||
fullscreens -= category
|
||||
if(!screen)
|
||||
return
|
||||
if(animated > 0)
|
||||
animate(screen, alpha = 0, time = animated)
|
||||
addtimer(CALLBACK(src, .proc/_remove_fullscreen_direct, screen), animated, TIMER_CLIENT_TIME)
|
||||
else
|
||||
if(client)
|
||||
client.screen -= screen
|
||||
qdel(screen)
|
||||
|
||||
/mob/proc/_remove_fullscreen_direct(atom/movable/screen/fullscreen/screen)
|
||||
if(client)
|
||||
client.screen -= screen
|
||||
qdel(screen)
|
||||
|
||||
/**
|
||||
* Wipes all fullscreens
|
||||
*/
|
||||
/mob/proc/wipe_fullscreens()
|
||||
for(var/category in fullscreens)
|
||||
clear_fullscreen(category)
|
||||
|
||||
/**
|
||||
* Removes fullscreens from client but not the mob
|
||||
*/
|
||||
/mob/proc/hide_fullscreens()
|
||||
if(client)
|
||||
for(var/category in fullscreens)
|
||||
client.screen -= fullscreens[category]
|
||||
|
||||
/**
|
||||
* Ensures all fullscreens are on client.
|
||||
*/
|
||||
/mob/proc/reload_fullscreen()
|
||||
if(client)
|
||||
var/atom/movable/screen/fullscreen/screen
|
||||
for(var/category in fullscreens)
|
||||
screen = fullscreens[category]
|
||||
if(screen.ShouldShow(src))
|
||||
screen.SetView(client.view)
|
||||
client.screen |= screen
|
||||
else
|
||||
client.screen -= screen
|
||||
|
||||
/atom/movable/screen/fullscreen
|
||||
icon = 'icons/screen/fullscreen_15x15.dmi'
|
||||
icon_state = "default"
|
||||
screen_loc = "CENTER-7,CENTER-7"
|
||||
layer = FULLSCREEN_LAYER
|
||||
plane = FULLSCREEN_PLANE
|
||||
mouse_opacity = MOUSE_OPACITY_TRANSPARENT
|
||||
/// current view we're adapted to
|
||||
var/view_current
|
||||
/// min severity
|
||||
var/severity_min = 0
|
||||
/// max severity
|
||||
var/severity_max = INFINITY
|
||||
/// current severity
|
||||
var/severity = 0
|
||||
/// show this while dead
|
||||
var/show_when_dead = FALSE
|
||||
|
||||
/atom/movable/screen/fullscreen/proc/SetSeverity(severity)
|
||||
src.severity = clamp(severity, severity_min, severity_max)
|
||||
icon_state = "[initial(icon_state)][severity]"
|
||||
|
||||
/atom/movable/screen/fullscreen/proc/SetView(client_view)
|
||||
view_current = client_view
|
||||
|
||||
/atom/movable/screen/fullscreen/proc/ShouldShow(mob/M)
|
||||
if(!show_when_dead && M.stat == DEAD)
|
||||
return FALSE
|
||||
return TRUE
|
||||
|
||||
/atom/movable/screen/fullscreen/Destroy()
|
||||
SetSeverity(0)
|
||||
return ..()
|
||||
|
||||
/atom/movable/screen/fullscreen/scaled
|
||||
icon = 'icons/screen/fullscreen_15x15.dmi'
|
||||
screen_loc = "CENTER-7,CENTER-7"
|
||||
/// size of sprite in tiles
|
||||
var/size_x = 15
|
||||
/// size of sprite in tiles
|
||||
var/size_y = 15
|
||||
|
||||
/atom/movable/screen/fullscreen/scaled/SetView(client_view)
|
||||
if(view_current != client_view)
|
||||
var/list/actualview = getviewsize(client_view)
|
||||
view_current = client_view
|
||||
transform = matrix(actualview[1] / size_x, 0, 0, 0, actualview[2] / size_y, 0)
|
||||
return ..()
|
||||
|
||||
/atom/movable/screen/fullscreen/scaled/brute
|
||||
icon_state = "brutedamageoverlay"
|
||||
layer = UI_DAMAGE_LAYER
|
||||
plane = FULLSCREEN_PLANE
|
||||
|
||||
/atom/movable/screen/fullscreen/scaled/oxy
|
||||
icon_state = "oxydamageoverlay"
|
||||
layer = UI_DAMAGE_LAYER
|
||||
plane = FULLSCREEN_PLANE
|
||||
|
||||
/atom/movable/screen/fullscreen/scaled/crit
|
||||
icon_state = "passage"
|
||||
layer = CRIT_LAYER
|
||||
plane = FULLSCREEN_PLANE
|
||||
|
||||
/atom/movable/screen/fullscreen/scaled/crit/vision
|
||||
icon_state = "oxydamageoverlay"
|
||||
layer = BLIND_LAYER
|
||||
|
||||
/atom/movable/screen/fullscreen/scaled/blind
|
||||
icon_state = "blackimageoverlay"
|
||||
layer = BLIND_LAYER
|
||||
plane = FULLSCREEN_PLANE
|
||||
|
||||
/atom/movable/screen/fullscreen/scaled/curse
|
||||
icon_state = "curse"
|
||||
layer = CURSE_LAYER
|
||||
plane = FULLSCREEN_PLANE
|
||||
|
||||
/atom/movable/screen/fullscreen/scaled/impaired
|
||||
icon_state = "impairedoverlay"
|
||||
|
||||
/atom/movable/screen/fullscreen/scaled/emergency_meeting
|
||||
icon_state = "emergency_meeting"
|
||||
show_when_dead = TRUE
|
||||
layer = CURSE_LAYER
|
||||
plane = SPLASHSCREEN_PLANE
|
||||
|
||||
/atom/movable/screen/fullscreen/tiled/blurry
|
||||
icon = 'icons/mob/screen_gen.dmi'
|
||||
screen_loc = "WEST,SOUTH to EAST,NORTH"
|
||||
icon_state = "cloudy"
|
||||
|
||||
/atom/movable/screen/fullscreen/tiled/flash
|
||||
icon = 'icons/mob/screen_gen.dmi'
|
||||
screen_loc = "WEST,SOUTH to EAST,NORTH"
|
||||
icon_state = "flash"
|
||||
|
||||
/atom/movable/screen/fullscreen/tiled/flash/static
|
||||
icon = 'icons/mob/screen_gen.dmi'
|
||||
screen_loc = "WEST,SOUTH to EAST,NORTH"
|
||||
icon_state = "noise"
|
||||
|
||||
/atom/movable/screen/fullscreen/tiled/high
|
||||
icon = 'icons/mob/screen_gen.dmi'
|
||||
screen_loc = "WEST,SOUTH to EAST,NORTH"
|
||||
icon_state = "druggy"
|
||||
|
||||
/atom/movable/screen/fullscreen/tiled/color_vision
|
||||
icon = 'icons/mob/screen_gen.dmi'
|
||||
screen_loc = "WEST,SOUTH to EAST,NORTH"
|
||||
icon_state = "flash"
|
||||
alpha = 80
|
||||
|
||||
/atom/movable/screen/fullscreen/tiled/color_vision/green
|
||||
color = "#00ff00"
|
||||
|
||||
/atom/movable/screen/fullscreen/tiled/color_vision/red
|
||||
color = "#ff0000"
|
||||
|
||||
/atom/movable/screen/fullscreen/tiled/color_vision/blue
|
||||
color = "#0000ff"
|
||||
|
||||
/atom/movable/screen/fullscreen/tiled/cinematic_backdrop
|
||||
icon = 'icons/mob/screen_gen.dmi'
|
||||
screen_loc = "WEST,SOUTH to EAST,NORTH"
|
||||
icon_state = "flash"
|
||||
plane = SPLASHSCREEN_PLANE
|
||||
layer = SPLASHSCREEN_LAYER - 1
|
||||
color = "#000000"
|
||||
show_when_dead = TRUE
|
||||
|
||||
/atom/movable/screen/fullscreen/special/lighting_backdrop
|
||||
icon = 'icons/mob/screen_gen.dmi'
|
||||
icon_state = "flash"
|
||||
transform = matrix(200, 0, 0, 0, 200, 0)
|
||||
plane = LIGHTING_PLANE
|
||||
blend_mode = BLEND_OVERLAY
|
||||
show_when_dead = TRUE
|
||||
|
||||
//Provides darkness to the back of the lighting plane
|
||||
/atom/movable/screen/fullscreen/special/lighting_backdrop/lit
|
||||
invisibility = INVISIBILITY_LIGHTING
|
||||
layer = BACKGROUND_LAYER+21
|
||||
color = "#000"
|
||||
show_when_dead = TRUE
|
||||
|
||||
//Provides whiteness in case you don't see lights so everything is still visible
|
||||
/atom/movable/screen/fullscreen/special/lighting_backdrop/unlit
|
||||
layer = BACKGROUND_LAYER+20
|
||||
show_when_dead = TRUE
|
||||
|
||||
/atom/movable/screen/fullscreen/special/see_through_darkness
|
||||
icon_state = "nightvision"
|
||||
plane = LIGHTING_PLANE
|
||||
layer = LIGHTING_LAYER
|
||||
blend_mode = BLEND_ADD
|
||||
show_when_dead = TRUE
|
||||
@@ -0,0 +1,21 @@
|
||||
/**
|
||||
* initializes screen rendering. call on mob new
|
||||
*/
|
||||
/mob/proc/init_rendering()
|
||||
|
||||
/**
|
||||
* loads screen rendering. call on mob login
|
||||
*/
|
||||
/mob/proc/reload_rendering()
|
||||
if(!client.parallax_holder)
|
||||
client.CreateParallax()
|
||||
else
|
||||
client.parallax_holder.Reset(force = TRUE)
|
||||
client.update_clickcatcher()
|
||||
reload_fullscreen()
|
||||
|
||||
/**
|
||||
* destroys screen rendering. call on mob del
|
||||
*/
|
||||
/mob/proc/dispose_rendering()
|
||||
wipe_fullscreens()
|
||||
@@ -0,0 +1,28 @@
|
||||
/**
|
||||
* Holds parallax information.
|
||||
*/
|
||||
/datum/parallax
|
||||
/// List of parallax objects - these are cloned to a parallax holder using Clone on each.
|
||||
var/list/atom/movable/screen/parallax_layer/objects
|
||||
/// Parallax layers
|
||||
var/layers = 0
|
||||
|
||||
/datum/parallax/New(create_objects = TRUE)
|
||||
if(create_objects)
|
||||
objects = CreateObjects()
|
||||
layers = objects.len
|
||||
|
||||
/datum/parallax/Destroy()
|
||||
QDEL_LIST(objects)
|
||||
return ..()
|
||||
|
||||
/**
|
||||
* Gets a new version of the objects inside - used when applying to a holder.
|
||||
*/
|
||||
/datum/parallax/proc/GetObjects()
|
||||
. = list()
|
||||
for(var/atom/movable/screen/parallax_layer/layer in objects)
|
||||
. += layer.Clone()
|
||||
|
||||
/datum/parallax/proc/CreateObjects()
|
||||
. = objects = list()
|
||||
@@ -0,0 +1,311 @@
|
||||
/**
|
||||
* # Parallax holders
|
||||
*
|
||||
* Holds all the information about a client's parallax
|
||||
*
|
||||
* Not on mob because parallax is area based, not mob based.
|
||||
*
|
||||
* How parallax works:
|
||||
* - Layers - normal layers, scroll with movement to relative position, can scroll
|
||||
* - Absolute - absolute layers, scroll with movement to absolute position, cannot scroll
|
||||
* - Vis - vis_contents-like model - things in this are directly applied and get no processing whatsoever. Things like overmap ships can use this.
|
||||
*/
|
||||
/datum/parallax_holder
|
||||
/// Client that owns us
|
||||
var/client/owner
|
||||
/// The parallax object we're currently rendering
|
||||
var/datum/parallax/parallax
|
||||
/// Eye we were last anchored to - used to detect eye changes
|
||||
var/atom/cached_eye
|
||||
/// force this eye as the "real" eye - useful for secondary maps
|
||||
var/atom/forced_eye
|
||||
/// last turf loc
|
||||
var/turf/last
|
||||
/// last area - for parallax scrolling/loop animations
|
||||
var/area/last_area
|
||||
/// Holder object for vis
|
||||
var/atom/movable/screen/parallax_vis/vis_holder
|
||||
/// are we not on the main map? if so, put map id here
|
||||
var/secondary_map
|
||||
/// all layers
|
||||
var/list/atom/movable/screen/parallax_layer/layers
|
||||
/// vis contents
|
||||
var/list/atom/movable/vis
|
||||
/// currently scrolling?
|
||||
var/scrolling = FALSE
|
||||
/// current scroll speed in DS per scroll
|
||||
var/scroll_speed
|
||||
/// current scroll turn - applied after angle. if angle is 0 (picture moving north) and turn is 90, it would be like if you turned your viewport 90 deg clockwise.
|
||||
var/scroll_turn
|
||||
/// override planemaster we manipulate for turning and other effects
|
||||
var/atom/movable/screen/plane_master/parallax/planemaster_override
|
||||
|
||||
/datum/parallax_holder/New(client/C, secondary_map, forced_eye, planemaster_override)
|
||||
owner = C
|
||||
if(!owner)
|
||||
CRASH("No client")
|
||||
src.secondary_map = secondary_map
|
||||
src.forced_eye = forced_eye
|
||||
src.planemaster_override = planemaster_override
|
||||
Reset()
|
||||
|
||||
/datum/parallax_holder/Destroy()
|
||||
if(owner)
|
||||
if(owner.parallax_holder == src)
|
||||
owner.parallax_holder = null
|
||||
Remove()
|
||||
HardResetAnimations()
|
||||
QDEL_NULL(vis_holder)
|
||||
QDEL_NULL(parallax)
|
||||
layers = null
|
||||
vis = null
|
||||
last = null
|
||||
forced_eye = cached_eye = null
|
||||
owner = null
|
||||
return ..()
|
||||
|
||||
/datum/parallax_holder/proc/Reset(auto_z_change, force)
|
||||
if(!(cached_eye = Eye()))
|
||||
// if no eye, tear down
|
||||
last = cached_eye = last_area = null
|
||||
SetParallax(null, null, auto_z_change)
|
||||
return
|
||||
// first, check loc
|
||||
var/turf/T = get_turf(cached_eye)
|
||||
if(!T)
|
||||
// if in nullspace, tear down
|
||||
last = cached_eye = last_area = null
|
||||
SetParallax(null, null, auto_z_change)
|
||||
return
|
||||
// set last loc and eye
|
||||
last = T
|
||||
last_area = T.loc
|
||||
// rebuild parallax
|
||||
SetParallax(SSparallax.get_parallax_datum(T.z), null, auto_z_change, force)
|
||||
// hard reset positions to correct positions
|
||||
for(var/atom/movable/screen/parallax_layer/L in layers)
|
||||
L.ResetPosition(T.x, T.y)
|
||||
|
||||
// better updates via client_mobs_in_contents can be created again when important recursive contents is ported!
|
||||
/datum/parallax_holder/proc/Update(full)
|
||||
if(!full && !cached_eye || (get_turf(cached_eye) == last))
|
||||
return
|
||||
if(!owner) // why are we here
|
||||
if(!QDELETED(src))
|
||||
qdel(src)
|
||||
return
|
||||
if(cached_eye != Eye())
|
||||
// eye mismatch, reset
|
||||
Reset()
|
||||
return
|
||||
var/turf/T = get_turf(cached_eye)
|
||||
if(!last || T.z != last.z)
|
||||
// z mismatch, reset
|
||||
Reset()
|
||||
return
|
||||
// get rel offsets
|
||||
var/rel_x = T.x - last.x
|
||||
var/rel_y = T.y - last.y
|
||||
// set last
|
||||
last = T
|
||||
// move
|
||||
for(var/atom/movable/screen/parallax_layer/L in layers)
|
||||
L.RelativePosition(T.x, T.y, rel_x, rel_y)
|
||||
// process scrolling/movedir
|
||||
if(last_area != T.loc)
|
||||
last_area = T.loc
|
||||
UpdateMotion()
|
||||
|
||||
/**
|
||||
* Gets the eye we should be centered on
|
||||
*/
|
||||
/datum/parallax_holder/proc/Eye()
|
||||
return forced_eye || owner?.eye
|
||||
|
||||
/**
|
||||
* Gets the base parallax planemaster for things like turning
|
||||
*/
|
||||
/datum/parallax_holder/proc/GetPlaneMaster()
|
||||
return planemaster_override || (owner && (locate(/atom/movable/screen/plane_master/parallax) in owner?.screen))
|
||||
|
||||
/**
|
||||
* Syncs us to our parallax objects. Does NOT check if we should have those objects, that's Reset()'s job.
|
||||
*
|
||||
* Doesn't move/update positions/screen locs either.
|
||||
*
|
||||
* Also ensures movedirs are correct for the eye's pos.
|
||||
*/
|
||||
/datum/parallax_holder/proc/Sync(auto_z_change, force)
|
||||
layers = list()
|
||||
for(var/atom/movable/screen/parallax_layer/L in parallax.objects)
|
||||
layers += L
|
||||
L.map_id = secondary_map
|
||||
if(!istype(vis_holder))
|
||||
vis_holder = new /atom/movable/screen/parallax_vis
|
||||
var/turf/T = get_turf(cached_eye)
|
||||
vis_holder.vis_contents = vis = T? SSparallax.get_parallax_vis_contents(T.z) : list()
|
||||
UpdateMotion(auto_z_change, force)
|
||||
|
||||
/**
|
||||
* Updates motion if needed
|
||||
*/
|
||||
/datum/parallax_holder/proc/UpdateMotion(auto_z_change, force)
|
||||
var/turf/T = get_turf(cached_eye)
|
||||
if(!T)
|
||||
if(scroll_speed || scroll_turn)
|
||||
HardResetAnimations()
|
||||
return
|
||||
var/list/ret = SSparallax.get_parallax_motion(T.z)
|
||||
if(ret)
|
||||
Animation(ret[1], ret[2], auto_z_change? 0 : ret[3], auto_z_change? 0 : ret[4], force)
|
||||
else
|
||||
var/area/A = T.loc
|
||||
Animation(A.parallax_move_speed, A.parallax_move_angle, auto_z_change? 0 : null, auto_z_change? 0 : null, force)
|
||||
|
||||
/datum/parallax_holder/proc/Apply(client/C = owner)
|
||||
if(QDELETED(C))
|
||||
return
|
||||
. = list()
|
||||
for(var/atom/movable/screen/parallax_layer/L in layers)
|
||||
if(L.parallax_intensity > owner.prefs.parallax)
|
||||
continue
|
||||
if(!L.ShouldSee(C, last))
|
||||
continue
|
||||
L.SetView(C.view, TRUE)
|
||||
. |= L
|
||||
C.screen |= .
|
||||
if(!secondary_map)
|
||||
var/atom/movable/screen/plane_master/parallax_white/PM = locate() in C.screen
|
||||
if(PM)
|
||||
PM.color = list(
|
||||
0, 0, 0, 0,
|
||||
0, 0, 0, 0,
|
||||
0, 0, 0, 0,
|
||||
1, 1, 1, 1,
|
||||
0, 0, 0, 0
|
||||
)
|
||||
|
||||
/datum/parallax_holder/proc/Remove(client/C = owner)
|
||||
if(QDELETED(C))
|
||||
return
|
||||
C.screen -= layers
|
||||
if(!secondary_map)
|
||||
var/atom/movable/screen/plane_master/parallax_white/PM = locate() in C.screen
|
||||
if(PM)
|
||||
PM.color = initial(PM.color)
|
||||
|
||||
/datum/parallax_holder/proc/SetParallaxType(path)
|
||||
if(!ispath(path, /datum/parallax))
|
||||
CRASH("Invalid path")
|
||||
SetParallax(new path)
|
||||
|
||||
/datum/parallax_holder/proc/SetParallax(datum/parallax/P, delete_old = TRUE, auto_z_change, force)
|
||||
if(P == parallax)
|
||||
return
|
||||
Remove()
|
||||
if(delete_old && istype(parallax) && !QDELETED(parallax))
|
||||
qdel(parallax)
|
||||
HardResetAnimations()
|
||||
parallax = P
|
||||
if(!parallax)
|
||||
return
|
||||
Sync(auto_z_change, force)
|
||||
Apply()
|
||||
|
||||
/**
|
||||
* Runs a modifier to parallax as an animation.
|
||||
*
|
||||
* @params
|
||||
* speed - ds per loop
|
||||
* turn - angle clockwise from north to turn the motion to
|
||||
* windup - ds to spend on windups. 0 for immediate.
|
||||
* turn_speed - ds to spend on turning. 0 for immediate.
|
||||
*/
|
||||
/datum/parallax_holder/proc/Animation(speed = 25, turn = 0, windup = speed, turn_speed = speed, force)
|
||||
// Parallax doesn't currently use this method of rotating.
|
||||
|
||||
// #if !PARALLAX_ROTATION_ANIMATIONS
|
||||
// turn_speed = 0
|
||||
// #endif
|
||||
|
||||
if(speed == 0)
|
||||
StopScrolling(turn = turn, time = windup)
|
||||
return
|
||||
// if(turn != scroll_turn && GetPlaneMaster())
|
||||
// // first handle turn. we turn the planemaster
|
||||
// var/matrix/turn_transform = matrix()
|
||||
// turn_transform.Turn(turn)
|
||||
// scroll_turn = turn
|
||||
// animate(GetPlaneMaster(), transform = turn_transform, time = turn_speed, easing = QUAD_EASING | EASE_IN, flags = ANIMATION_END_NOW | ANIMATION_LINEAR_TRANSFORM)
|
||||
if(scroll_speed == speed && !force)
|
||||
// we're done
|
||||
return
|
||||
// speed diff?
|
||||
scroll_speed = speed
|
||||
scrolling = TRUE
|
||||
// always scroll from north; turn handles everything
|
||||
for(var/atom/movable/screen/parallax_layer/P in layers)
|
||||
if(P.absolute)
|
||||
continue
|
||||
var/matrix/translate_matrix = matrix()
|
||||
translate_matrix.Translate(cos(turn) * 480, sin(turn) * 480)
|
||||
var/matrix/target_matrix = matrix()
|
||||
var/move_speed = speed * P.speed
|
||||
// do the first segment by shifting down one screen
|
||||
P.transform = translate_matrix
|
||||
animate(P, transform = target_matrix, time = move_speed, easing = QUAD_EASING|EASE_IN, flags = ANIMATION_END_NOW)
|
||||
// queue up another incase lag makes QueueLoop not fire on time, this time by shifting up
|
||||
animate(transform = translate_matrix, time = 0)
|
||||
animate(transform = target_matrix, time = move_speed)
|
||||
P.QueueLoop(move_speed, speed * P.speed, translate_matrix, target_matrix)
|
||||
|
||||
/**
|
||||
* Smoothly stops the animation, turning to a certain angle as needed.
|
||||
*/
|
||||
/datum/parallax_holder/proc/StopScrolling(turn = 0, time = 30)
|
||||
// reset turn
|
||||
if(turn != scroll_turn && GetPlaneMaster())
|
||||
var/matrix/turn_transform = matrix()
|
||||
turn_transform.Turn(turn)
|
||||
scroll_turn = turn
|
||||
animate(GetPlaneMaster(), transform = turn_transform, time = time, easing = QUAD_EASING | EASE_OUT, flags = ANIMATION_END_NOW | ANIMATION_LINEAR_TRANSFORM)
|
||||
if(scroll_speed == 0)
|
||||
// we're done
|
||||
scrolling = FALSE
|
||||
scroll_speed = 0
|
||||
return
|
||||
scrolling = FALSE
|
||||
scroll_speed = 0
|
||||
// someone can do the math for "stop after a smooth iteration" later.
|
||||
for(var/atom/movable/screen/parallax_layer/P in layers)
|
||||
if(P.absolute)
|
||||
continue
|
||||
P.CancelAnimation()
|
||||
var/matrix/translate_matrix = matrix()
|
||||
translate_matrix.Translate(cos(turn) * 480, sin(turn) * 480)
|
||||
P.transform = translate_matrix
|
||||
animate(P, transform = matrix(), time = time, easing = QUAD_EASING | EASE_OUT)
|
||||
|
||||
/**
|
||||
* fully resets animation state
|
||||
*/
|
||||
/datum/parallax_holder/proc/HardResetAnimations()
|
||||
// reset vars
|
||||
scroll_turn = 0
|
||||
scroll_speed = 0
|
||||
scrolling = FALSE
|
||||
// reset turn
|
||||
if(GetPlaneMaster())
|
||||
animate(GetPlaneMaster(), transform = matrix(), time = 0, flags = ANIMATION_END_NOW)
|
||||
// reset objects
|
||||
for(var/atom/movable/screen/parallax_layer/P in layers)
|
||||
if(P.absolute)
|
||||
continue
|
||||
P.CancelAnimation()
|
||||
animate(P, transform = matrix(), time = 0, flags = ANIMATION_END_NOW)
|
||||
|
||||
/client/proc/CreateParallax()
|
||||
if(!parallax_holder)
|
||||
parallax_holder = new(src)
|
||||
/atom/movable/screen/parallax_vis
|
||||
screen_loc = "CENTER,CENTER"
|
||||
@@ -0,0 +1,137 @@
|
||||
|
||||
/atom/movable/screen/parallax_layer
|
||||
icon = 'icons/screen/parallax.dmi'
|
||||
blend_mode = BLEND_ADD
|
||||
plane = PLANE_SPACE_PARALLAX
|
||||
screen_loc = "CENTER-7,CENTER-7"
|
||||
mouse_opacity = MOUSE_OPACITY_TRANSPARENT
|
||||
appearance_flags = PIXEL_SCALE | KEEP_TOGETHER
|
||||
|
||||
// notice - all parallax layers are 15x15 tiles. They roll over every 240 pixels.
|
||||
/// pixel x/y shift per real x/y
|
||||
var/speed = 1
|
||||
/// current cached offset x
|
||||
var/offset_x = 0
|
||||
/// current cached offset y
|
||||
var/offset_y = 0
|
||||
/// normal centered x
|
||||
var/center_x = 0
|
||||
/// normal centered y
|
||||
var/center_y = 0
|
||||
/// absolute - always determine shift x/y as a function of real x/y instead of allowing for relative scroll.
|
||||
var/absolute = FALSE
|
||||
/// parallax level required to see this
|
||||
var/parallax_intensity = PARALLAX_INSANE
|
||||
/// current view we're adapted to
|
||||
var/view_current
|
||||
/// dynamic self tile - tile to our view size. set this to false for static parallax layers.
|
||||
var/dynamic_self_tile = TRUE
|
||||
/// map id
|
||||
var/map_id
|
||||
/// queued animation timerid
|
||||
var/queued_animation
|
||||
|
||||
/atom/movable/screen/parallax_layer/proc/ResetPosition(x, y)
|
||||
// remember that our offsets/directiosn are relative to the player's viewport
|
||||
// this means we need to scroll reverse to them.
|
||||
offset_x = -(center_x + speed * x)
|
||||
offset_y = -(center_y + speed * y)
|
||||
if(!absolute)
|
||||
if(offset_x > 240)
|
||||
offset_x -= 480
|
||||
if(offset_x < -240)
|
||||
offset_x += 480
|
||||
if(offset_y > 240)
|
||||
offset_y -= 480
|
||||
if(offset_y < -240)
|
||||
offset_y += 480
|
||||
screen_loc = "[map_id && "[map_id]:"]CENTER-7:[round(offset_x,1)],CENTER-7:[round(offset_y,1)]"
|
||||
|
||||
/atom/movable/screen/parallax_layer/proc/RelativePosition(x, y, rel_x, rel_y)
|
||||
if(absolute)
|
||||
return ResetPosition(x, y)
|
||||
offset_x -= rel_x * speed
|
||||
offset_y -= rel_y * speed
|
||||
if(offset_x > 240)
|
||||
offset_x -= 480
|
||||
if(offset_x < -240)
|
||||
offset_x += 480
|
||||
if(offset_y > 240)
|
||||
offset_y -= 480
|
||||
if(offset_y < -240)
|
||||
offset_y += 480
|
||||
screen_loc = "[map_id && "[map_id]:"]CENTER-7:[round(offset_x,1)],CENTER-7:[round(offset_y,1)]"
|
||||
|
||||
/atom/movable/screen/parallax_layer/proc/SetView(client_view = world.view, force_update = FALSE)
|
||||
if(view_current == client_view && !force_update)
|
||||
return
|
||||
view_current = client_view
|
||||
if(!dynamic_self_tile)
|
||||
return
|
||||
var/list/real_view = getviewsize(client_view)
|
||||
var/count_x = CEILING((real_view[1] / 2) / 15, 1) + 1
|
||||
var/count_y = CEILING((real_view[2] / 2) / 15, 1) + 1
|
||||
var/list/new_overlays = GetOverlays()
|
||||
for(var/x in -count_x to count_x)
|
||||
for(var/y in -count_y to count_y)
|
||||
if(!x && !y)
|
||||
continue
|
||||
var/mutable_appearance/clone = new
|
||||
// appearance clone
|
||||
clone.icon = icon
|
||||
clone.icon_state = icon_state
|
||||
clone.overlays = GetOverlays()
|
||||
// do NOT inherit our overlays! parallax layers should never have overlays,
|
||||
// because if it inherited us it'll result in exponentially increasing overlays
|
||||
// due to cut_overlays() above over there being a queue operation and not instant!
|
||||
// clone.overlays = list()
|
||||
// currently instantly using overlays =.
|
||||
// clone.blend_mode = blend_mode
|
||||
// clone.mouse_opacity = mouse_opacity
|
||||
// clone.plane = plane
|
||||
// clone.layer = layer
|
||||
// shift to position
|
||||
clone.transform = matrix(1, 0, x * 480, 0, 1, y * 480)
|
||||
new_overlays += clone
|
||||
overlays = new_overlays
|
||||
|
||||
/atom/movable/screen/parallax_layer/proc/ShouldSee(client/C, atom/location)
|
||||
return TRUE
|
||||
|
||||
/**
|
||||
* Return "natural" overlays, as we're goin to do some fuckery to overlays above.
|
||||
*/
|
||||
/atom/movable/screen/parallax_layer/proc/GetOverlays()
|
||||
return list()
|
||||
|
||||
/atom/movable/screen/parallax_layer/proc/Clone()
|
||||
var/atom/movable/screen/parallax_layer/layer = new type
|
||||
layer.speed = speed
|
||||
layer.offset_x = offset_x
|
||||
layer.offset_y = offset_y
|
||||
layer.absolute = absolute
|
||||
layer.parallax_intensity = parallax_intensity
|
||||
layer.view_current = view_current
|
||||
layer.appearance = appearance
|
||||
|
||||
/atom/movable/screen/parallax_layer/proc/default_x()
|
||||
return center_x
|
||||
|
||||
/atom/movable/screen/parallax_layer/proc/default_y()
|
||||
return center_y
|
||||
|
||||
/atom/movable/screen/parallax_layer/proc/QueueLoop(delay, speed, matrix/translate_matrix, matrix/target_matrix)
|
||||
if(queued_animation)
|
||||
CancelAnimation()
|
||||
queued_animation = addtimer(CALLBACK(src, .proc/_loop, speed, translate_matrix, target_matrix), delay, TIMER_STOPPABLE)
|
||||
|
||||
/atom/movable/screen/parallax_layer/proc/_loop(speed, matrix/translate_matrix = matrix(1, 0, 0, 0, 1, 480), matrix/target_matrix = matrix())
|
||||
transform = translate_matrix
|
||||
animate(src, transform = target_matrix, time = speed, loop = -1)
|
||||
animate(transform = translate_matrix, time = 0)
|
||||
queued_animation = null
|
||||
|
||||
/atom/movable/screen/parallax_layer/proc/CancelAnimation()
|
||||
if(queued_animation)
|
||||
deltimer(queued_animation)
|
||||
queued_animation = null
|
||||
@@ -0,0 +1,66 @@
|
||||
/datum/parallax/space
|
||||
var/static/planet_offset_x = rand(100, 160)
|
||||
var/static/planet_offset_y = rand(100, 160)
|
||||
var/static/random_layer = pickweightAllowZero(list(
|
||||
/atom/movable/screen/parallax_layer/space/random/asteroids = 35,
|
||||
/atom/movable/screen/parallax_layer/space/random/space_gas = 35,
|
||||
null = 30
|
||||
))
|
||||
var/static/random_gas_color = pick(COLOR_TEAL, COLOR_GREEN, COLOR_YELLOW, COLOR_CYAN, COLOR_ORANGE, COLOR_PURPLE)
|
||||
|
||||
/datum/parallax/space/CreateObjects()
|
||||
. = ..()
|
||||
. += new /atom/movable/screen/parallax_layer/space/layer_1
|
||||
. += new /atom/movable/screen/parallax_layer/space/layer_2
|
||||
. += new /atom/movable/screen/parallax_layer/space/layer_3
|
||||
var/atom/movable/screen/parallax_layer/space/planet/P = new
|
||||
P.pixel_x = planet_offset_x
|
||||
P.pixel_y = planet_offset_y
|
||||
. += P
|
||||
if(random_layer)
|
||||
. += new random_layer
|
||||
if(ispath(random_layer, /atom/movable/screen/parallax_layer/space/random/space_gas))
|
||||
var/atom/movable/screen/parallax_layer/space/random/space_gas/SG = locate(random_layer) in objects
|
||||
SG.add_atom_colour(random_gas_color, ADMIN_COLOUR_PRIORITY)
|
||||
|
||||
/atom/movable/screen/parallax_layer/space/layer_1
|
||||
icon_state = "layer1"
|
||||
speed = 0.6
|
||||
layer = 1
|
||||
parallax_intensity = PARALLAX_LOW
|
||||
|
||||
/atom/movable/screen/parallax_layer/space/layer_2
|
||||
icon_state = "layer2"
|
||||
speed = 1
|
||||
layer = 2
|
||||
parallax_intensity = PARALLAX_MED
|
||||
|
||||
/atom/movable/screen/parallax_layer/space/layer_3
|
||||
icon_state = "layer3"
|
||||
speed = 1.4
|
||||
layer = 3
|
||||
parallax_intensity = PARALLAX_HIGH
|
||||
|
||||
/atom/movable/screen/parallax_layer/space/random
|
||||
blend_mode = BLEND_OVERLAY
|
||||
speed = 3
|
||||
layer = 3
|
||||
parallax_intensity = PARALLAX_INSANE
|
||||
|
||||
/atom/movable/screen/parallax_layer/space/random/space_gas
|
||||
icon_state = "space_gas"
|
||||
|
||||
/atom/movable/screen/parallax_layer/space/random/asteroids
|
||||
icon_state = "asteroids"
|
||||
|
||||
/atom/movable/screen/parallax_layer/space/planet
|
||||
icon_state = "planet"
|
||||
blend_mode = BLEND_OVERLAY
|
||||
absolute = TRUE //Status of seperation
|
||||
speed = 3
|
||||
layer = 30
|
||||
dynamic_self_tile = FALSE
|
||||
|
||||
/atom/movable/screen/parallax_layer/space/planet/ShouldSee(client/C, atom/location)
|
||||
var/turf/T = get_turf(location)
|
||||
return ..() && T && is_station_level(T.z)
|
||||
Reference in New Issue
Block a user