diff --git a/code/__defines/_macros.dm b/code/__defines/_macros.dm index 83fa1dd8260..b40d982437f 100644 --- a/code/__defines/_macros.dm +++ b/code/__defines/_macros.dm @@ -52,6 +52,8 @@ #define isbrain(A) istype(A, /mob/living/carbon/brain) +#define isvirtualmob(A) istype(A, /mob/abstract/observer/virtual) + #define iscarbon(A) istype(A, /mob/living/carbon) #define iscorgi(A) istype(A, /mob/living/simple_animal/corgi) diff --git a/code/__defines/dview.dm b/code/__defines/dview.dm index 55764fb9a37..88116e9492b 100644 --- a/code/__defines/dview.dm +++ b/code/__defines/dview.dm @@ -11,4 +11,4 @@ dview_mob.loc = center; \ dview_mob.see_invisible = invis_flags; \ output = view(range, dview_mob); \ - dview_mob.loc = null; + dview_mob.loc = null; \ No newline at end of file diff --git a/code/controllers/subsystems/garbage-debug.dm b/code/controllers/subsystems/garbage-debug.dm index c2c10530218..9a158d64480 100644 --- a/code/controllers/subsystems/garbage-debug.dm +++ b/code/controllers/subsystems/garbage-debug.dm @@ -150,15 +150,11 @@ SearchVar(round_progressing) SearchVar(master_mode) SearchVar(secret_force_mode) - SearchVar(host) - SearchVar(jobMax) SearchVar(bombers) SearchVar(admin_log) SearchVar(lastsignalers) SearchVar(lawchanges) SearchVar(reg_dna) - SearchVar(monkeystart) - SearchVar(wizardstart) SearchVar(newplayer_start) SearchVar(latejoin) SearchVar(latejoin_gateway) @@ -167,15 +163,10 @@ SearchVar(latejoin_merchant) SearchVar(latejoin_living_quarters_lift) SearchVar(kickoffsloc) - SearchVar(prisonwarp) - SearchVar(holdingfacility) - SearchVar(xeno_spawn) SearchVar(tdome1) SearchVar(tdome2) SearchVar(tdomeobserve) SearchVar(tdomeadmin) - SearchVar(prisonsecuritywarp) - SearchVar(prisonwarped) SearchVar(ninjastart) SearchVar(cardinal) SearchVar(cornerdirs) diff --git a/code/game/atoms_movable.dm b/code/game/atoms_movable.dm index 0f15c075a46..dab523f51e9 100644 --- a/code/game/atoms_movable.dm +++ b/code/game/atoms_movable.dm @@ -48,6 +48,10 @@ if (bound_overlay) QDEL_NULL(bound_overlay) + if(virtual_mob && !ispath(virtual_mob)) + qdel(virtual_mob) + virtual_mob = null + // This is called when this atom is prevented from moving by atom/A. /atom/movable/proc/Collide(atom/A) if(airflow_speed > 0 && airflow_dest) diff --git a/code/game/objects/effects/landmarks.dm b/code/game/objects/effects/landmarks.dm index 49baba6ba53..739b84f9eb1 100644 --- a/code/game/objects/effects/landmarks.dm +++ b/code/game/objects/effects/landmarks.dm @@ -16,10 +16,6 @@ /obj/effect/landmark/proc/do_landmark_effect() switch(name) //some of these are probably obsolete - if("monkey") - monkeystart += loc - delete_me = 1 - return if("start") newplayer_start = get_turf(loc) delete_me = 1 @@ -55,12 +51,6 @@ latejoin_merchant += loc delete_me = 1 return - if("prisonwarp") - prisonwarp += loc - delete_me = 1 - return - if("Holding Facility") - holdingfacility += loc if("tdome1") tdome1 += loc if("tdome2") @@ -69,14 +59,6 @@ tdomeadmin += loc if("tdomeobserve") tdomeobserve += loc - if("prisonsecuritywarp") - prisonsecuritywarp += loc - delete_me = 1 - return - if("xeno_spawn") - xeno_spawn += loc - delete_me = 1 - return if("endgame_exit") endgame_safespawns += loc delete_me = 1 diff --git a/code/global.dm b/code/global.dm index 7e4cfaf7672..1f1d52adc5d 100644 --- a/code/global.dm +++ b/code/global.dm @@ -34,9 +34,6 @@ var/round_progressing = 1 var/master_mode = "extended" // "extended" var/secret_force_mode = "secret" // if this is anything but "secret", the secret rotation will forceably choose this mode. -var/host = null //only here until check @ code\modules\ghosttrap\trap.dm:112 is fixed - -var/list/jobMax = list() var/list/bombers = list() var/list/admin_log = list() var/list/signal_log = list() @@ -44,8 +41,6 @@ var/list/lastsignalers = list() // Keeps last 100 signals here in format: "[src] var/list/lawchanges = list() // Stores who uploaded laws to which silicon-based lifeform, and what the law was. var/list/reg_dna = list() -var/list/monkeystart = list() -var/list/wizardstart = list() var/turf/newplayer_start = null //Spawnpoints. @@ -59,16 +54,11 @@ var/list/latejoin_living_quarters_lift = list() var/list/kickoffsloc = list() var/list/virtual_reality_spawn = list() -var/list/prisonwarp = list() // Prisoners go to these -var/list/holdingfacility = list() // Captured people go here -var/list/xeno_spawn = list() // Aliens spawn at at these. var/list/asteroid_spawn = list() // Asteroid "Dungeons" spawn at these. var/list/tdome1 = list() var/list/tdome2 = list() var/list/tdomeobserve = list() var/list/tdomeadmin = list() -var/list/prisonsecuritywarp = list() // Prison security goes to these. -var/list/prisonwarped = list() // List of players already warped. var/list/ninjastart = list() var/list/cardinal = list(NORTH, SOUTH, EAST, WEST) diff --git a/code/modules/admin/admin.dm b/code/modules/admin/admin.dm index ebf044ea549..06ea1c12d3c 100644 --- a/code/modules/admin/admin.dm +++ b/code/modules/admin/admin.dm @@ -77,8 +77,7 @@ proc/admin_notice(var/message, var/rights) "} if(M.client) - body += "| Prison | " - body += "Wind | " + body += "| Wind | " body += "\ Send back to Lobby" var/muted = M.client.prefs.muted body += {"
Mute: diff --git a/code/modules/admin/topic.dm b/code/modules/admin/topic.dm index 010c5d4015b..190b9981f55 100644 --- a/code/modules/admin/topic.dm +++ b/code/modules/admin/topic.dm @@ -493,47 +493,6 @@ log_admin("[key_name(usr)] forced [key_name(M)] to say: [speech]",admin_key=key_name(usr)) message_admins("[key_name_admin(usr)] forced [key_name_admin(M)] to say: [speech]") - else if(href_list["sendtoprison"]) - if(!check_rights(R_ADMIN)) return - - if(alert(usr, "Send to admin prison for the round?", "Message", "Yes", "No") != "Yes") - return - - var/mob/M = locate(href_list["sendtoprison"]) - if(!ismob(M)) - to_chat(usr, "This can only be used on instances of type /mob") - return - if(istype(M, /mob/living/silicon/ai)) - to_chat(usr, "This cannot be used on instances of type /mob/living/silicon/ai") - return - - var/turf/prison_cell = pick(prisonwarp) - if(!prison_cell) return - - var/obj/structure/closet/secure_closet/brig/locker = new /obj/structure/closet/secure_closet/brig(prison_cell) - locker.opened = 0 - locker.locked = 1 - - //strip their stuff and stick it in the crate - for(var/obj/item/I in M) - M.drop_from_inventory(I, locker) - M.update_icon() - - //so they black out before warping - M.Paralyse(5) - sleep(5) - if(!M) return - - M.forceMove(prison_cell) - if(istype(M, /mob/living/carbon/human)) - var/mob/living/carbon/human/prisoner = M - prisoner.equip_to_slot_or_del(new /obj/item/clothing/under/color/orange(prisoner), slot_w_uniform) - prisoner.equip_to_slot_or_del(new /obj/item/clothing/shoes/orange(prisoner), slot_shoes) - - to_chat(M, "You have been sent to the prison station!") - log_admin("[key_name(usr)] sent [key_name(M)] to the prison station.",,admin_key=key_name(usr),ckey=key_name(M)) - message_admins("[key_name_admin(usr)] sent [key_name_admin(M)] to the prison station.", 1) - else if(href_list["sendbacktolobby"]) if(!check_rights(R_ADMIN)) return diff --git a/code/modules/admin/verbs/randomverbs.dm b/code/modules/admin/verbs/randomverbs.dm index 310bad78b86..20575e41752 100644 --- a/code/modules/admin/verbs/randomverbs.dm +++ b/code/modules/admin/verbs/randomverbs.dm @@ -16,32 +16,6 @@ message_admins("[key_name_admin(usr)] made [key_name_admin(M)] drop everything!", 1) feedback_add_details("admin_verb","DEVR") //If you are copy-pasting this, ensure the 2nd parameter is unique to the new proc! -/client/proc/cmd_admin_prison(mob/M as mob in mob_list) - set category = "Admin" - set name = "Prison" - if(!holder) - to_chat(src, "Only administrators may use this command.") - return - if (ismob(M)) - if(istype(M, /mob/living/silicon/ai)) - alert("The AI can't be sent to prison you jerk!", null, null, null, null, null) - return - //strip their stuff before they teleport into a cell :downs: - for(var/obj/item/W in M) - M.drop_from_inventory(W) - //teleport person to cell - M.Paralyse(5) - sleep(5) //so they black out before warping - M.forceMove(pick(prisonwarp)) - if(istype(M, /mob/living/carbon/human)) - var/mob/living/carbon/human/prisoner = M - prisoner.equip_to_slot_or_del(new /obj/item/clothing/under/color/orange(prisoner), slot_w_uniform) - prisoner.equip_to_slot_or_del(new /obj/item/clothing/shoes/orange(prisoner), slot_shoes) - spawn(50) - to_chat(M, "You have been sent to the prison station!") - log_admin("[key_name(usr)] sent [key_name(M)] to the prison station.",admin_key=key_name(usr),ckey=key_name(M)) - message_admins("[key_name_admin(usr)] sent [key_name_admin(M)] to the prison station.", 1) - feedback_add_details("admin_verb","PRISON") //If you are copy-pasting this, ensure the 2nd parameter is unique to the new proc! /client/proc/cmd_admin_subtle_message(mob/M as mob in mob_list) set category = "Special Verbs" diff --git a/code/modules/mob/abstract/new_player/new_player.dm b/code/modules/mob/abstract/new_player/new_player.dm index 4e773ab2d18..4eb75a680b1 100644 --- a/code/modules/mob/abstract/new_player/new_player.dm +++ b/code/modules/mob/abstract/new_player/new_player.dm @@ -14,6 +14,7 @@ anchored = 1 // don't get pushed around simulated = FALSE + virtual_mob = null // Hear no evil, speak no evil var/last_ready_name // This has to be saved because the client is nulled prior to Logout() diff --git a/code/modules/mob/abstract/virtual/helpers.dm b/code/modules/mob/abstract/virtual/helpers.dm index a0c1bea0858..8503a23b9f6 100644 --- a/code/modules/mob/abstract/virtual/helpers.dm +++ b/code/modules/mob/abstract/virtual/helpers.dm @@ -1,13 +1,103 @@ -/proc/mobs_in_range(var/atom/movable/AM) - . = list() - for(var/mob/abstract/observer/virtual/v_mob in range(world.view, get_turf(AM))) - if(ismob(v_mob.host)) - . += v_mob.host +/* +* These calls could easily be setup to be a bunch of call()() with relevant procs and predicates but performance is a concern. +* BYOND is also a bit inflexible, as some predicates are of the sort /proc/name(host), others host.proc_name(), and some even do host.proc_name(parameter). +* Nothing that cannot be worked around, but it'd be a little messy. I miss C# lambdas... +*/ -/proc/clients_in_range(var/atom/movable/AM) +// Procs are arranged by "in range/hearers/viewers()" usage, as opposed to virtual mob hear/see abilities. +// Most of these procs can technically take any movable atom but unless they have a virtual mob the returned objects may not be the expected ones + +#define ACQUIRE_VIRTUAL_OR_TURF(A) A = (isvirtualmob(A) ? A : (((istype(A) && A.virtual_mob) ? A.virtual_mob : get_turf(A)))) ; if(!A) return +#define ACQUIRE_VIRTUAL_OR_RETURN(A) A = (isvirtualmob(A) ? A : (((istype(A) && A.virtual_mob) ? A.virtual_mob : null))) ; if(!A) return + +/**************** +* Range Helpers * +****************/ +/proc/clients_in_range(var/atom/movable/center_vmob) . = list() - for(var/mob/abstract/observer/virtual/v_mob in range(world.view, get_turf(AM))) - if(ismob(v_mob.host)) - var/mob/M = v_mob.host - if(M.client) - . |= M.client \ No newline at end of file + + ACQUIRE_VIRTUAL_OR_TURF(center_vmob) + for(var/mob/abstract/observer/virtual/v_mob in range(world.view, center_vmob)) + var/client/C = v_mob.get_client() + if(C) + . |= C + +/proc/hearers_in_range(var/atom/movable/center_vmob, var/hearing_range = world.view) + . = list() + + ACQUIRE_VIRTUAL_OR_TURF(center_vmob) + for(var/mob/abstract/observer/virtual/v_mob in range(hearing_range, center_vmob)) + if(v_mob.abilities & VIRTUAL_ABILITY_HEAR) + . |= v_mob.host + +/proc/viewers_in_range(var/atom/movable/center_vmob) + . = list() + + ACQUIRE_VIRTUAL_OR_TURF(center_vmob) + for(var/mob/abstract/observer/virtual/v_mob in range(world.view, center_vmob)) + if(v_mob.abilities & VIRTUAL_ABILITY_SEE) + . |= v_mob.host + +/*************** +* Hear Helpers * +***************/ +// A mob hears another mob if they have direct line of sight, ignoring turf luminosity. +// If there is an opaque object beteween the mobs then they cannot hear each other, even if their respective turfs can be seen. +// Thus, unlike viewing hearing is communicative. I.e. if Mob A can hear Mob B then Mob B can also hear Mob A. + +// Gets the hosts of all the virtual mobs that can hear the given movable atom (or rather, it's virtual mob or turf in that existence order) +/proc/all_hearers(var/atom/movable/heard_vmob, var/range = world.view) + . = list() + + ACQUIRE_VIRTUAL_OR_TURF(heard_vmob) + for(var/mob/abstract/observer/virtual/v_mob in hearers(range, heard_vmob)) + if(v_mob.abilities & VIRTUAL_ABILITY_HEAR) + . |= v_mob.host + +/*************** +* View Helpers * +***************/ +// A mob can see another mob if: +// * Within visual range, with the following differences for (N)PCs. +// * PCs: Target is within client.view range, with center originating from either the mob or client.eye depending on client.eye_perspective. +// * NPCs: Target is within world.view range, with center always originating from the mob. +// * Either of the following is true: +// * The target mob is in direct line of sight and not standing on a turf with luminosity = 0 unless the viewing mob is close enough for see_in_dark to also be in range +// * The viewing mob has the SEE_MOBS sight flag. + +// Gets the hosts of all virtual mobs that can see the given atom movable as well as its turf +/proc/all_viewers(var/mob/abstract/observer/virtual/viewed_atom) + . = list() + + viewed_atom = istype(viewed_atom) ? viewed_atom.host : viewed_atom + var/turf/T = get_turf(viewed_atom) + if(!T) + return + + for(var/mob/abstract/observer/virtual/seeing_v_mob in viewers(world.view, viewed_atom)) + if(!(seeing_v_mob.abilities & VIRTUAL_ABILITY_SEE)) + continue + var/atom/movable/host = seeing_v_mob.host + if(host.virtual_can_see_turf(T)) + . |= host + +// This proc returns all hosts of virtual mobs in the given atom's view range (using its turf), ignoring invisibility, VIRUAL_ABILITY_SEE, and most other restrictions. +// In most cases you actually want the all_* procs above. This helper was designed with LOOC in mind. +/proc/hosts_in_view_range(var/atom/movable/viewing_atom, var/range = world.view) + . = list() + + ACQUIRE_VIRTUAL_OR_TURF(viewing_atom) + // As per http://www.byond.com/docs/ref/info.html#/proc/view by using a non-mob/client this automatically skips the vast majority of sight checks + for(var/mob/abstract/observer/virtual/v_mob in viewers(range, get_turf(viewing_atom.loc))) + . |= v_mob.host + +/* + Misc. helper +*/ + +// Eye mobs technically see everything always, the owner just has an overlay applied, thus this helper +/atom/movable/proc/virtual_can_see_turf(var/turf/T) + return TRUE // We assume objects have already been filtered using viewers() or similar proc + +#undef ACQUIRE_VIRTUAL_OR_TURF +#undef ACQUIRE_VIRTUAL_OR_RETURN diff --git a/code/modules/mob/living/carbon/human/human_species.dm b/code/modules/mob/living/carbon/human/human_species.dm index 25107161283..deaf8431755 100644 --- a/code/modules/mob/living/carbon/human/human_species.dm +++ b/code/modules/mob/living/carbon/human/human_species.dm @@ -1,6 +1,7 @@ /mob/living/carbon/human/dummy real_name = "Test Dummy" status_flags = GODMODE|CANPUSH + virtual_mob = null /mob/living/carbon/human/dummy/mannequin mob_thinks = FALSE diff --git a/code/modules/mob/mob_defines.dm b/code/modules/mob/mob_defines.dm index a0e2126b9a2..167f1ec8245 100644 --- a/code/modules/mob/mob_defines.dm +++ b/code/modules/mob/mob_defines.dm @@ -4,6 +4,7 @@ animate_movement = 2 flags = PROXMOVE sight = DEFAULT_SIGHT + virtual_mob = /mob/abstract/observer/virtual/mob var/datum/mind/mind var/stat = 0 //Whether a mob is alive or dead. TODO: Move this to living - Nodrak diff --git a/code/modules/mob/mob_helpers.dm b/code/modules/mob/mob_helpers.dm index 987e4d360b6..1b4af238663 100644 --- a/code/modules/mob/mob_helpers.dm +++ b/code/modules/mob/mob_helpers.dm @@ -1290,3 +1290,15 @@ proc/is_blind(A) /mob/proc/get_talk_bubble() return 'icons/mob/talk.dmi' + +/datum/proc/get_client() + return null + +/client/get_client() + return src + +/mob/get_client() + return client + +/mob/abstract/observer/virtual/get_client() + return host.get_client() diff --git a/code/modules/modular_computers/file_system/programs/generic/signaler.dm b/code/modules/modular_computers/file_system/programs/generic/signaler.dm index a9f689c463f..28e3d44cf11 100644 --- a/code/modules/modular_computers/file_system/programs/generic/signaler.dm +++ b/code/modules/modular_computers/file_system/programs/generic/signaler.dm @@ -77,7 +77,7 @@ if(href_list["send"]) radio.send_signal("ACTIVATE") - computer.output_message("[icon2html(host, viewers(get_turf(src)))] *beep* *beep*", 1) + computer.output_message("[icon2html(computer, viewers(get_turf(src)))] *beep* *beep*", 1) return TRUE else if(href_list["freq"]) diff --git a/code/modules/world_api/commands/server_query.dm b/code/modules/world_api/commands/server_query.dm index b1e168e7bca..936cb87d300 100644 --- a/code/modules/world_api/commands/server_query.dm +++ b/code/modules/world_api/commands/server_query.dm @@ -12,7 +12,6 @@ s["enter"] = config.enter_allowed s["vote"] = config.allow_vote_mode s["ai"] = config.allow_ai - s["host"] = host ? host : null s["stationtime"] = worldtime2text() s["roundduration"] = get_round_duration_formatted() s["gameid"] = game_id diff --git a/code/unit_tests/observation_tests.dm b/code/unit_tests/observation_tests.dm index 029344617e8..cf37770e3de 100644 --- a/code/unit_tests/observation_tests.dm +++ b/code/unit_tests/observation_tests.dm @@ -49,6 +49,8 @@ datum/unit_test/observation/moved_shall_not_register_on_enter_without_listeners/ var/turf/T = locate(20,20,1) var/mob/living/carbon/human/H = new(T) var/obj/structure/closet/C = new(T) + qdel(H.virtual_mob) + H.virtual_mob = null H.forceMove(C) if(!is_listening_to_movement(C, H)) diff --git a/html/changelogs/mattatlas-repent.yml b/html/changelogs/mattatlas-repent.yml new file mode 100644 index 00000000000..36d330f527a --- /dev/null +++ b/html/changelogs/mattatlas-repent.yml @@ -0,0 +1,41 @@ +################################ +# Example Changelog File +# +# Note: This file, and files beginning with ".", and files that don't end in ".yml" will not be read. If you change this file, you will look really dumb. +# +# Your changelog will be merged with a master changelog. (New stuff added only, and only on the date entry for the day it was merged.) +# When it is, any changes listed below will disappear. +# +# Valid Prefixes: +# bugfix +# wip (For works in progress) +# tweak +# soundadd +# sounddel +# rscadd (general adding of nice things) +# rscdel (general deleting of nice things) +# imageadd +# imagedel +# maptweak +# spellcheck (typo fixes) +# experiment +# balance +# admin +# backend +# security +# refactor +################################# + +# Your name. +author: MattAtlas + +# Optional: Remove this file after generating master changelog. Useful for PR changelogs that won't get used again. +delete-after: True + +# Any changes you've made. See valid prefix list above. +# INDENT WITH TWO SPACES. NOT TABS. SPACES. +# SCREW THIS UP AND IT WON'T WORK. +# Also, all entries are changed into a single [] after a master changelog generation. Just remove the brackets when you add new entries. +# Please surround your changes in double quotes ("), as certain characters otherwise screws up compiling. The quotes will not show up in the changelog. +changes: + - bugfix: "Fixed mobs being unable to hear from inside machines or objects."