Merge remote-tracking branch 'upstream/dev-freeze' into dev

Conflicts:
	code/modules/admin/admin.dm
	code/modules/admin/topic.dm
This commit is contained in:
PsiOmegaDelta
2015-10-16 13:02:59 +02:00
20 changed files with 207 additions and 165 deletions

View File

@@ -71,11 +71,17 @@ proc/isemptylist(list/list)
return 1 return 1
return 0 return 0
//Empties the list by setting the length to 0. Hopefully the elements get garbage collected /proc/instances_of_type_in_list(var/atom/A, var/list/L)
proc/clearlist(list/list) var/instances = 0
if(istype(list)) for(var/type in L)
list.len = 0 if(istype(A, type))
return instances++
return instances
//Empties the list by .Cut(). Setting lenght = 0 has been confirmed to leak references.
proc/clearlist(var/list/L)
if(islist(L))
L.Cut()
//Removes any null entries from the list //Removes any null entries from the list
proc/listclearnulls(list/list) proc/listclearnulls(list/list)

View File

@@ -86,7 +86,8 @@
/datum/antagonist/proc/tick() /datum/antagonist/proc/tick()
return 1 return 1
/datum/antagonist/proc/get_candidates(var/ghosts_only) // Get the raw list of potential players.
/datum/antagonist/proc/build_candidate_list(var/ghosts_only)
candidates = list() // Clear. candidates = list() // Clear.
// Prune restricted status. Broke it up for readability. // Prune restricted status. Broke it up for readability.
@@ -108,46 +109,57 @@
return candidates return candidates
/datum/antagonist/proc/attempt_random_spawn() /datum/antagonist/proc/attempt_random_spawn()
update_current_antag_max()
build_candidate_list(flags & (ANTAG_OVERRIDE_MOB|ANTAG_OVERRIDE_JOB)) build_candidate_list(flags & (ANTAG_OVERRIDE_MOB|ANTAG_OVERRIDE_JOB))
attempt_spawn() attempt_spawn()
finalize_spawn() finalize_spawn()
/datum/antagonist/proc/attempt_late_spawn(var/datum/mind/player) /datum/antagonist/proc/attempt_auto_spawn()
if(!can_late_spawn()) if(!can_late_spawn())
return 0 return 0
if(!istype(player))
var/list/players = get_candidates(is_latejoin_template())
if(players && players.len)
player = pick(players)
if(!istype(player))
message_admins("AUTO[uppertext(ticker.mode.name)]: Failed to find a candidate for [role_text].")
return 0
player.current << "<span class='danger'><i>You have been selected this round as an antagonist!</i></span>"
message_admins("AUTO[uppertext(ticker.mode.name)]: Selected [player] as a [role_text].")
if(istype(player.current, /mob/dead))
create_default(player.current)
else
add_antagonist(player,0,0,0,1,1)
return 1
/datum/antagonist/proc/build_candidate_list(var/ghosts_only)
// Get the raw list of potential players.
update_current_antag_max() update_current_antag_max()
candidates = get_candidates(ghosts_only) var/active_antags = get_active_antag_count()
log_debug("[uppertext(id)]: Found [active_antags]/[cur_max] active [role_text_plural].")
if(active_antags >= cur_max)
log_debug("Could not auto-spawn a [role_text], active antag limit reached.")
return 0
build_candidate_list(flags & (ANTAG_OVERRIDE_MOB|ANTAG_OVERRIDE_JOB))
if(!candidates.len)
log_debug("Could not auto-spawn a [role_text], no candidates found.")
return 0
attempt_spawn(1) //auto-spawn antags one at a time
if(!pending_antagonists.len)
log_debug("Could not auto-spawn a [role_text], none of the available candidates could be selected.")
return 0
var/datum/mind/player = pending_antagonists[1]
if(!add_antagonist(player,0,0,0,1,1))
log_debug("Could not auto-spawn a [role_text], failed to add antagonist.")
return 0
reset_antag_selection()
return 1
//Selects players that will be spawned in the antagonist role from the potential candidates //Selects players that will be spawned in the antagonist role from the potential candidates
//Selected players are added to the pending_antagonists lists. //Selected players are added to the pending_antagonists lists.
//Attempting to spawn an antag role with ANTAG_OVERRIDE_JOB should be done before jobs are assigned, //Attempting to spawn an antag role with ANTAG_OVERRIDE_JOB should be done before jobs are assigned,
//so that they do not occupy regular job slots. All other antag roles should be spawned after jobs are //so that they do not occupy regular job slots. All other antag roles should be spawned after jobs are
//assigned, so that job restrictions can be respected. //assigned, so that job restrictions can be respected.
/datum/antagonist/proc/attempt_spawn(var/rebuild_candidates = 1) /datum/antagonist/proc/attempt_spawn(var/spawn_target = null)
if(spawn_target == null)
spawn_target = initial_spawn_target
// Update our boundaries. // Update our boundaries.
if(!candidates.len) if(!candidates.len)
return 0 return 0
//Grab candidates randomly until we have enough. //Grab candidates randomly until we have enough.
while(candidates.len && pending_antagonists.len < initial_spawn_target) while(candidates.len && pending_antagonists.len < spawn_target)
var/datum/mind/player = pick(candidates) var/datum/mind/player = pick(candidates)
candidates -= player candidates -= player
draft_antagonist(player) draft_antagonist(player)
@@ -186,11 +198,16 @@
for(var/datum/mind/player in pending_antagonists) for(var/datum/mind/player in pending_antagonists)
pending_antagonists -= player pending_antagonists -= player
add_antagonist(player,0,0,1) add_antagonist(player,0,0,1)
reset_antag_selection()
//Resets all pending_antagonists, clearing their special_role (and assigned_role if ANTAG_OVERRIDE_JOB is set) //Resets the antag selection, clearing all pending_antagonists and their special_role
/datum/antagonist/proc/reset() //(and assigned_role if ANTAG_OVERRIDE_JOB is set) as well as clearing the candidate list.
//Existing antagonists are left untouched.
/datum/antagonist/proc/reset_antag_selection()
for(var/datum/mind/player in pending_antagonists) for(var/datum/mind/player in pending_antagonists)
if(flags & ANTAG_OVERRIDE_JOB) if(flags & ANTAG_OVERRIDE_JOB)
player.assigned_role = null player.assigned_role = null
player.special_role = null player.special_role = null
pending_antagonists.Cut() pending_antagonists.Cut()
candidates.Cut()

View File

@@ -16,7 +16,8 @@
create_objectives(target) create_objectives(target)
update_icons_added(target) update_icons_added(target)
greet(target) greet(target)
announce_antagonist_spawn() if(!gag_announcement)
announce_antagonist_spawn()
/datum/antagonist/proc/create_default(var/mob/source) /datum/antagonist/proc/create_default(var/mob/source)
var/mob/living/M var/mob/living/M

View File

@@ -20,6 +20,17 @@
/datum/antagonist/proc/get_antag_count() /datum/antagonist/proc/get_antag_count()
return current_antagonists ? current_antagonists.len : 0 return current_antagonists ? current_antagonists.len : 0
/datum/antagonist/proc/get_active_antag_count()
var/active_antags = 0
for(var/datum/mind/player in current_antagonists)
var/mob/living/L = player.current
if(!L || L.stat == DEAD)
continue //no mob or dead
if(!L.client && !L.teleop)
continue //SSD
active_antags++
return active_antags
/datum/antagonist/proc/is_antagonist(var/datum/mind/player) /datum/antagonist/proc/is_antagonist(var/datum/mind/player)
if(player in current_antagonists) if(player in current_antagonists)
return 1 return 1
@@ -33,9 +44,6 @@
return (flags & ANTAG_VOTABLE) return (flags & ANTAG_VOTABLE)
/datum/antagonist/proc/can_late_spawn() /datum/antagonist/proc/can_late_spawn()
update_current_antag_max()
if(get_antag_count() >= cur_max)
return 0
return 1 return 1
/datum/antagonist/proc/is_latejoin_template() /datum/antagonist/proc/is_latejoin_template()

View File

@@ -22,13 +22,11 @@ var/datum/antagonist/rogue_ai/malf
malf = src malf = src
/datum/antagonist/rogue_ai/get_candidates() /datum/antagonist/rogue_ai/build_candidate_list()
..() ..()
for(var/datum/mind/player in candidates) for(var/datum/mind/player in candidates)
if(player.assigned_role && player.assigned_role != "AI") if(player.assigned_role && player.assigned_role != "AI")
candidates -= player candidates -= player
if(!candidates.len)
return list()
return candidates return candidates

View File

@@ -12,14 +12,15 @@
/datum/game_mode/calamity/create_antagonists() /datum/game_mode/calamity/create_antagonists()
shuffle(all_antag_types) // This is probably the only instance in the game where the order will be important. //Let's not modify global lists for trivial reasons, even if it seems harmless right now.
var/i = 1 var/list/antag_candidates = all_antag_types.Copy()
var/grab_antags = round(num_players()/ANTAG_TYPE_RATIO)+1 var/grab_antags = round(num_players()/ANTAG_TYPE_RATIO)+1
for(var/antag_id in all_antag_types) while(antag_candidates.len && antag_tags.len < grab_antags)
if(i > grab_antags) var/antag_id = pick(antag_candidates)
break antag_candidates -= antag_id
antag_tags |= antag_id antag_tags |= antag_id
i++
..() ..()
/datum/game_mode/calamity/check_victory() /datum/game_mode/calamity/check_victory()

View File

@@ -21,7 +21,6 @@ var/global/list/additional_antag_types = list()
var/list/antag_tags = list() // Core antag templates to spawn. var/list/antag_tags = list() // Core antag templates to spawn.
var/list/antag_templates // Extra antagonist types to include. var/list/antag_templates // Extra antagonist types to include.
var/list/latejoin_templates = list()
var/round_autoantag = 0 // Will this round attempt to periodically spawn more antagonists? var/round_autoantag = 0 // Will this round attempt to periodically spawn more antagonists?
var/antag_scaling_coeff = 5 // Coefficient for scaling max antagonists to player count. var/antag_scaling_coeff = 5 // Coefficient for scaling max antagonists to player count.
var/require_all_templates = 0 // Will only start if all templates are checked and can spawn. var/require_all_templates = 0 // Will only start if all templates are checked and can spawn.
@@ -183,6 +182,7 @@ var/global/list/additional_antag_types = list()
/datum/game_mode/proc/pre_setup() /datum/game_mode/proc/pre_setup()
for(var/datum/antagonist/antag in antag_templates) for(var/datum/antagonist/antag in antag_templates)
antag.update_current_antag_max()
antag.build_candidate_list() //compile a list of all eligible candidates antag.build_candidate_list() //compile a list of all eligible candidates
//antag roles that replace jobs need to be assigned before the job controller hands out jobs. //antag roles that replace jobs need to be assigned before the job controller hands out jobs.
@@ -207,8 +207,6 @@ var/global/list/additional_antag_types = list()
if(!(antag.flags & ANTAG_OVERRIDE_JOB)) if(!(antag.flags & ANTAG_OVERRIDE_JOB))
antag.attempt_spawn() //select antags to be spawned antag.attempt_spawn() //select antags to be spawned
antag.finalize_spawn() //actually spawn antags antag.finalize_spawn() //actually spawn antags
if(antag.is_latejoin_template())
latejoin_templates |= antag
if(emergency_shuttle && auto_recall_shuttle) if(emergency_shuttle && auto_recall_shuttle)
emergency_shuttle.auto_recall = 1 emergency_shuttle.auto_recall = 1
@@ -221,7 +219,7 @@ var/global/list/additional_antag_types = list()
/datum/game_mode/proc/fail_setup() /datum/game_mode/proc/fail_setup()
for(var/datum/antagonist/antag in antag_templates) for(var/datum/antagonist/antag in antag_templates)
antag.reset() antag.reset_antag_selection()
/datum/game_mode/proc/announce_ert_disabled() /datum/game_mode/proc/announce_ert_disabled()
if(!ert_disabled) if(!ert_disabled)
@@ -493,6 +491,7 @@ var/global/list/additional_antag_types = list()
if(antag) if(antag)
antag_templates |= antag antag_templates |= antag
shuffle(antag_templates) //In the case of multiple antag types
newscaster_announcements = pick(newscaster_standard_feeds) newscaster_announcements = pick(newscaster_standard_feeds)
/datum/game_mode/proc/check_victory() /datum/game_mode/proc/check_victory()

View File

@@ -3,55 +3,39 @@
/datum/game_mode/var/max_autotraitor_delay = 12000 // Approx 20 minutes. /datum/game_mode/var/max_autotraitor_delay = 12000 // Approx 20 minutes.
/datum/game_mode/var/process_count = 0 /datum/game_mode/var/process_count = 0
/datum/game_mode/proc/get_usable_templates(var/list/supplied_templates)
var/list/usable_templates = list()
for(var/datum/antagonist/A in supplied_templates)
if(A.can_late_spawn())
message_admins("AUTO[uppertext(name)]: [A.id] selected for spawn attempt.")
usable_templates |= A
return usable_templates
///process() ///process()
///Called by the gameticker ///Called by the gameticker
/datum/game_mode/proc/process() /datum/game_mode/proc/process()
// Slow this down a bit so latejoiners have a chance of being antags. if(round_autoantag && world.time < next_spawn && !emergency_shuttle.departed)
process_count++ process_autoantag()
if(process_count >= 10)
process_count = 0
try_latespawn()
/datum/game_mode/proc/latespawn(var/mob/living/carbon/human/character) //This can be overriden in case a game mode needs to do stuff when a player latejoins
if(!character.mind) /datum/game_mode/proc/handle_latejoin(var/mob/living/carbon/human/character)
return
try_latespawn(character.mind)
return 0 return 0
/datum/game_mode/proc/try_latespawn(var/datum/mind/player, var/latejoin_only) /datum/game_mode/proc/process_autoantag()
message_admins("[uppertext(name)]: Attempting autospawn.")
if(emergency_shuttle.departed || !round_autoantag) var/list/usable_templates = list()
return for(var/datum/antagonist/A in antag_templates)
if(A.can_late_spawn())
if(world.time < next_spawn) message_admins("[uppertext(name)]: [A.id] selected for spawn attempt.")
return usable_templates |= A
message_admins("AUTO[uppertext(name)]: Attempting spawn.") if(!usable_templates.len)
message_admins("[uppertext(name)]: Failed to find configured mode spawn templates, please re-enable auto-antagonists after one is added.")
var/list/usable_templates
if(latejoin_only && latejoin_templates.len)
usable_templates = get_usable_templates(latejoin_templates)
else if (antag_templates && antag_templates.len)
usable_templates = get_usable_templates(antag_templates)
else
message_admins("AUTO[uppertext(name)]: Failed to find configured mode spawn templates, please disable auto-antagonists until one is added.")
round_autoantag = 0 round_autoantag = 0
return return
while(usable_templates.len) while(usable_templates.len)
var/datum/antagonist/spawn_antag = pick(usable_templates) var/datum/antagonist/spawn_antag = pick(usable_templates)
usable_templates -= spawn_antag usable_templates -= spawn_antag
if(spawn_antag.attempt_late_spawn(player))
message_admins("AUTO[uppertext(name)]: Attempting to latespawn [spawn_antag.id]. ([spawn_antag.get_antag_count()]/[spawn_antag.cur_max])") if(spawn_antag.attempt_auto_spawn())
message_admins("[uppertext(name)]: Auto-added a new [spawn_antag.role_text].")
message_admins("There are now [spawn_antag.get_active_antag_count()]/[spawn_antag.cur_max] active [spawn_antag.role_text_plural].")
next_spawn = world.time + rand(min_autotraitor_delay, max_autotraitor_delay) next_spawn = world.time + rand(min_autotraitor_delay, max_autotraitor_delay)
return return
message_admins("AUTO[uppertext(name)]: Failed to proc a viable spawn template.")
next_spawn = world.time + rand(min_autotraitor_delay, max_autotraitor_delay) message_admins("[uppertext(name)]: Failed to proc a viable spawn template.")
next_spawn = world.time + min_autotraitor_delay //recheck again in the miniumum time

View File

@@ -191,7 +191,10 @@ Class Procs:
return (stat & (NOPOWER|BROKEN|additional_flags)) return (stat & (NOPOWER|BROKEN|additional_flags))
/obj/machinery/CanUseTopic(var/mob/user) /obj/machinery/CanUseTopic(var/mob/user)
if(!interact_offline && (stat & (NOPOWER|BROKEN))) if(stat & BROKEN)
return STATUS_CLOSE
if(!interact_offline && (stat & NOPOWER))
return STATUS_CLOSE return STATUS_CLOSE
return ..() return ..()

View File

@@ -722,7 +722,8 @@ var/global/list/obj/item/device/pda/PDAs = list()
if("Message") if("Message")
var/obj/item/device/pda/P = locate(href_list["target"]) var/obj/item/device/pda/P = locate(href_list["target"])
src.create_message(U, P, !href_list["notap"]) var/tap = istype(U, /mob/living/carbon)
src.create_message(U, P, tap)
if(mode == 2) if(mode == 2)
if(href_list["target"] in conversations) // Need to make sure the message went through, if not welp. if(href_list["target"] in conversations) // Need to make sure the message went through, if not welp.
active_conversation = href_list["target"] active_conversation = href_list["target"]
@@ -1041,7 +1042,7 @@ var/global/list/obj/item/device/pda/PDAs = list()
new_message(sending_device, sending_device.owner, sending_device.ownjob, message) new_message(sending_device, sending_device.owner, sending_device.ownjob, message)
/obj/item/device/pda/proc/new_message(var/sending_unit, var/sender, var/sender_job, var/message) /obj/item/device/pda/proc/new_message(var/sending_unit, var/sender, var/sender_job, var/message)
var/reception_message = "\icon[src] <b>Message from [sender] ([sender_job]), </b>\"[message]\" (<a href='byond://?src=\ref[src];choice=Message;notap=[istype(loc, /mob/living/silicon)];skiprefresh=1;target=\ref[sending_unit]'>Reply</a>)" var/reception_message = "\icon[src] <b>Message from [sender] ([sender_job]), </b>\"[message]\" (<a href='byond://?src=\ref[src];choice=Message;skiprefresh=1;target=\ref[sending_unit]'>Reply</a>)"
new_info(message_silent, ttone, reception_message) new_info(message_silent, ttone, reception_message)
log_pda("[usr] (PDA: [sending_unit]) sent \"[message]\" to [name]") log_pda("[usr] (PDA: [sending_unit]) sent \"[message]\" to [name]")
@@ -1053,7 +1054,7 @@ var/global/list/obj/item/device/pda/PDAs = list()
if(ismob(sending_unit.loc) && isAI(loc)) if(ismob(sending_unit.loc) && isAI(loc))
track = "(<a href='byond://?src=\ref[loc];track=\ref[sending_unit.loc];trackname=[html_encode(sender)]'>Follow</a>)" track = "(<a href='byond://?src=\ref[loc];track=\ref[sending_unit.loc];trackname=[html_encode(sender)]'>Follow</a>)"
var/reception_message = "\icon[src] <b>Message from [sender] ([sender_job]), </b>\"[message]\" (<a href='byond://?src=\ref[src];choice=Message;notap=1;skiprefresh=1;target=\ref[sending_unit]'>Reply</a>) [track]" var/reception_message = "\icon[src] <b>Message from [sender] ([sender_job]), </b>\"[message]\" (<a href='byond://?src=\ref[src];choice=Message;skiprefresh=1;target=\ref[sending_unit]'>Reply</a>) [track]"
new_info(message_silent, newstone, reception_message) new_info(message_silent, newstone, reception_message)
log_pda("[usr] (PDA: [sending_unit]) sent \"[message]\" to [name]") log_pda("[usr] (PDA: [sending_unit]) sent \"[message]\" to [name]")

View File

@@ -623,35 +623,36 @@
icon_state = "light" icon_state = "light"
desc = "This box is shaped on the inside so that only light tubes and bulbs fit." desc = "This box is shaped on the inside so that only light tubes and bulbs fit."
item_state = "syringe_kit" item_state = "syringe_kit"
storage_slots=21
can_hold = list(/obj/item/weapon/light/tube, /obj/item/weapon/light/bulb)
max_storage_space = 42 //holds 21 items of w_class 2
use_to_pickup = 1 // for picking up broken bulbs, not that most people will try use_to_pickup = 1 // for picking up broken bulbs, not that most people will try
/obj/item/weapon/storage/box/lights/New()
..()
make_exact_fit()
/obj/item/weapon/storage/box/lights/bulbs/New() /obj/item/weapon/storage/box/lights/bulbs/New()
..()
for(var/i = 0; i < 21; i++) for(var/i = 0; i < 21; i++)
new /obj/item/weapon/light/bulb(src) new /obj/item/weapon/light/bulb(src)
..()
/obj/item/weapon/storage/box/lights/tubes /obj/item/weapon/storage/box/lights/tubes
name = "box of replacement tubes" name = "box of replacement tubes"
icon_state = "lighttube" icon_state = "lighttube"
/obj/item/weapon/storage/box/lights/tubes/New() /obj/item/weapon/storage/box/lights/tubes/New()
..()
for(var/i = 0; i < 21; i++) for(var/i = 0; i < 21; i++)
new /obj/item/weapon/light/tube(src) new /obj/item/weapon/light/tube(src)
..()
/obj/item/weapon/storage/box/lights/mixed /obj/item/weapon/storage/box/lights/mixed
name = "box of replacement lights" name = "box of replacement lights"
icon_state = "lightmixed" icon_state = "lightmixed"
/obj/item/weapon/storage/box/lights/mixed/New() /obj/item/weapon/storage/box/lights/mixed/New()
..()
for(var/i = 0; i < 14; i++) for(var/i = 0; i < 14; i++)
new /obj/item/weapon/light/tube(src) new /obj/item/weapon/light/tube(src)
for(var/i = 0; i < 7; i++) for(var/i = 0; i < 7; i++)
new /obj/item/weapon/light/bulb(src) new /obj/item/weapon/light/bulb(src)
..()
/obj/item/weapon/storage/box/freezer /obj/item/weapon/storage/box/freezer
name = "portable freezer" name = "portable freezer"

View File

@@ -130,8 +130,7 @@
/obj/item/weapon/storage/firstaid/surgery /obj/item/weapon/storage/firstaid/surgery
name = "surgery kit" name = "surgery kit"
desc = "Contains tools for surgery." desc = "Contains tools for surgery. Has precise foam fitting for safe transport."
storage_slots = 10
/obj/item/weapon/storage/firstaid/surgery/New() /obj/item/weapon/storage/firstaid/surgery/New()
..() ..()
@@ -146,7 +145,8 @@
new /obj/item/weapon/bonegel(src) new /obj/item/weapon/bonegel(src)
new /obj/item/weapon/FixOVein(src) new /obj/item/weapon/FixOVein(src)
new /obj/item/stack/medical/advanced/bruise_pack(src) new /obj/item/stack/medical/advanced/bruise_pack(src)
return
make_exact_fit()
/* /*
* Pill Bottles * Pill Bottles

View File

@@ -235,12 +235,16 @@
usr << "<span class='notice'>[src] is full, make some space.</span>" usr << "<span class='notice'>[src] is full, make some space.</span>"
return 0 //Storage item is full return 0 //Storage item is full
if(can_hold.len && !is_type_in_list(W, can_hold)) if(can_hold.len)
if(!stop_messages) if(!is_type_in_list(W, can_hold))
if (istype(W, /obj/item/weapon/hand_labeler)) if(!stop_messages && ! istype(W, /obj/item/weapon/hand_labeler))
return 0 usr << "<span class='notice'>[src] cannot hold \the [W].</span>"
usr << "<span class='notice'>[src] cannot hold [W].</span>" return 0
return 0 var/max_instances = can_hold[W.type]
if(max_instances && instances_of_type_in_list(W, contents) >= max_instances)
if(!stop_messages && !istype(W, /obj/item/weapon/hand_labeler))
usr << "<span class='notice'>[src] has no more space specifically for \the [W].</span>"
return 0
if(cant_hold.len && is_type_in_list(W, cant_hold)) if(cant_hold.len && is_type_in_list(W, cant_hold))
if(!stop_messages) if(!stop_messages)
@@ -461,6 +465,17 @@
src.quick_empty() src.quick_empty()
return 1 return 1
/obj/item/weapon/storage/proc/make_exact_fit()
storage_slots = contents.len
can_hold.Cut()
max_w_class = 0
max_storage_space = 0
for(var/obj/item/I in src)
can_hold[I.type]++
max_w_class = max(I.w_class, max_w_class)
max_storage_space += I.get_storage_cost()
//Returns the storage depth of an atom. This is the number of storage items the atom is contained in before reaching toplevel (the area). //Returns the storage depth of an atom. This is the number of storage items the atom is contained in before reaching toplevel (the area).
//Returns -1 if the atom was not found on container. //Returns -1 if the atom was not found on container.
/atom/proc/storage_depth(atom/container) /atom/proc/storage_depth(atom/container)

View File

@@ -1293,7 +1293,7 @@ proc/admin_notice(var/message, var/rights)
var/datum/antagonist/antag = all_antag_types[antag_type] var/datum/antagonist/antag = all_antag_types[antag_type]
message_admins("[key_name(usr)] attempting to force latespawn with template [antag.id].") message_admins("[key_name(usr)] attempting to force latespawn with template [antag.id].")
antag.attempt_late_spawn() antag.attempt_auto_spawn()
/datum/admins/proc/force_mode_latespawn() /datum/admins/proc/force_mode_latespawn()
set category = "Admin" set category = "Admin"
@@ -1310,6 +1310,5 @@ proc/admin_notice(var/message, var/rights)
usr << "Mode has not started." usr << "Mode has not started."
return return
message_admins("[key_name(usr)] attempting to force mode latespawn.") message_admins("[key_name(usr)] attempting to force mode autospawn.")
ticker.mode.next_spawn = 0 ticker.mode.process_autoantag()
ticker.mode.try_latespawn()

View File

@@ -311,17 +311,18 @@ var/global/list/gear_datums = list()
allowed_roles = list("Security Officer","Head of Security","Warden") allowed_roles = list("Security Officer","Head of Security","Warden")
/datum/gear/thugshades /datum/gear/thugshades
display_name = "Sunglasses, Fat (Security)" display_name = "Sunglasses, Fat"
path = /obj/item/clothing/glasses/sunglasses/big path = /obj/item/clothing/glasses/sunglasses/big
cost = 1 cost = 1
slot = slot_glasses slot = slot_glasses
allowed_roles = list("Security Officer","Head of Security","Warden") allowed_roles = list("Security Officer","Head of Security","Warden","Detective","Internal Affairs Agent","Quartermaster","Head of Personnel","Captain")
/datum/gear/prescriptionsun /datum/gear/prescriptionsun
display_name = "sunglasses, presciption" display_name = "sunglasses, presciption"
path = /obj/item/clothing/glasses/sunglasses/prescription path = /obj/item/clothing/glasses/sunglasses/prescription
cost = 2 cost = 2
slot = slot_glasses slot = slot_glasses
allowed_roles = list("Security Officer","Head of Security","Warden","Detective","Internal Affairs Agent","Quartermaster","Head of Personnel","Captain")
// Mask // Mask

View File

@@ -12,7 +12,7 @@
/mob/living/silicon/proc/set_zeroth_law(var/law, var/law_borg) /mob/living/silicon/proc/set_zeroth_law(var/law, var/law_borg)
laws_sanity_check() laws_sanity_check()
laws.set_zeroth_law(law, law_borg) laws.set_zeroth_law(law, law_borg)
log_and_message_admins("has given [src] the zeroth laws: [law]/[law_borg ? law_borg : "N/A"]") log_law("has given [src] the zeroth law: '[law]'[law_borg ? " / '[law_borg]'" : ""]")
/mob/living/silicon/robot/set_zeroth_law(var/law, var/law_borg) /mob/living/silicon/robot/set_zeroth_law(var/law, var/law_borg)
..() ..()
@@ -22,40 +22,40 @@
/mob/living/silicon/proc/add_ion_law(var/law) /mob/living/silicon/proc/add_ion_law(var/law)
laws_sanity_check() laws_sanity_check()
laws.add_ion_law(law) laws.add_ion_law(law)
log_and_message_admins("has given [src] the ion law: [law]") log_law("has given [src] the ion law: [law]")
/mob/living/silicon/proc/add_inherent_law(var/law) /mob/living/silicon/proc/add_inherent_law(var/law)
laws_sanity_check() laws_sanity_check()
laws.add_inherent_law(law) laws.add_inherent_law(law)
log_and_message_admins("has given [src] the inherent law: [law]") log_law("has given [src] the inherent law: [law]")
/mob/living/silicon/proc/add_supplied_law(var/number, var/law) /mob/living/silicon/proc/add_supplied_law(var/number, var/law)
laws_sanity_check() laws_sanity_check()
laws.add_supplied_law(number, law) laws.add_supplied_law(number, law)
log_and_message_admins("has given [src] the supplied law: [law]") log_law("has given [src] the supplied law: [law]")
/mob/living/silicon/proc/delete_law(var/datum/ai_law/law) /mob/living/silicon/proc/delete_law(var/datum/ai_law/law)
laws_sanity_check() laws_sanity_check()
laws.delete_law(law) laws.delete_law(law)
log_and_message_admins("has deleted a law belonging to [src]: [law.law]") log_law("has deleted a law belonging to [src]: [law.law]")
/mob/living/silicon/proc/clear_inherent_laws(var/silent = 0) /mob/living/silicon/proc/clear_inherent_laws(var/silent = 0)
laws_sanity_check() laws_sanity_check()
laws.clear_inherent_laws() laws.clear_inherent_laws()
if(!silent) if(!silent)
log_and_message_admins("cleared the inherent laws of [src]") log_law("cleared the inherent laws of [src]")
/mob/living/silicon/proc/clear_ion_laws(var/silent = 0) /mob/living/silicon/proc/clear_ion_laws(var/silent = 0)
laws_sanity_check() laws_sanity_check()
laws.clear_ion_laws() laws.clear_ion_laws()
if(!silent) if(!silent)
log_and_message_admins("cleared the ion laws of [src]") log_law("cleared the ion laws of [src]")
/mob/living/silicon/proc/clear_supplied_laws(var/silent = 0) /mob/living/silicon/proc/clear_supplied_laws(var/silent = 0)
laws_sanity_check() laws_sanity_check()
laws.clear_supplied_laws() laws.clear_supplied_laws()
if(!silent) if(!silent)
log_and_message_admins("cleared the supplied laws of [src]") log_law("cleared the supplied laws of [src]")
/mob/living/silicon/proc/statelaws(var/datum/ai_laws/laws) /mob/living/silicon/proc/statelaws(var/datum/ai_laws/laws)
var/prefix = "" var/prefix = ""
@@ -103,3 +103,7 @@
/mob/living/silicon/proc/lawsync() /mob/living/silicon/proc/lawsync()
laws_sanity_check() laws_sanity_check()
laws.sort_laws() laws.sort_laws()
/mob/living/silicon/proc/log_law(var/law_message)
log_and_message_admins(law_message)
lawchanges += "[worldtime2text()] - [usr ? "[key_name(usr)]" : "EVENT"] [law_message]"

View File

@@ -68,31 +68,46 @@
if (!message) if (!message)
return return
var/obj/machinery/hologram/holopad/T = src.holo var/obj/machinery/hologram/holopad/H = src.holo
if(T && T.masters[src])//If there is a hologram and its master is the user. if(H && H.masters[src])//If there is a hologram and its master is the user.
//Human-like, sorta, heard by those who understand humans.
var/rendered_a
//Speach distorted, heard by those who do not understand AIs.
var/message_stars = stars(message)
var/rendered_b
// AI can hear their own message, this formats it for them.
if(speaking) if(speaking)
rendered_a = "<span class='game say'><span class='name'>[name]</span> [speaking.format_message(message, verb)]</span>" src << "<i><span class='game say'>Holopad transmitted, <span class='name'>[real_name]</span> [speaking.format_message(message, verb)]</span></i>"
rendered_b = "<span class='game say'><span class='name'>[voice_name]</span> [speaking.format_message(message_stars, verb)]</span>"
src << "<i><span class='game say'>Holopad transmitted, <span class='name'>[real_name]</span> [speaking.format_message(message, verb)]</span></i>"//The AI can "hear" its own message.
else else
rendered_a = "<span class='game say'><span class='name'>[name]</span> [verb], <span class='message'>\"[message]\"</span></span>" src << "<i><span class='game say'>Holopad transmitted, <span class='name'>[real_name]</span> [verb], <span class='message'><span class='body'>\"[message]\"</span></span></span></i>"
rendered_b = "<span class='game say'><span class='name'>[voice_name]</span> [verb], <span class='message'>\"[message_stars]\"</span></span>"
src << "<i><span class='game say'>Holopad transmitted, <span class='name'>[real_name]</span> [verb], <span class='message'><span class='body'>\"[message]\"</span></span></span></i>"//The AI can "hear" its own message. //This is so pAI's and people inside lockers/boxes,etc can hear the AI Holopad, the alternative being recursion through contents.
//This is much faster.
var/list/listening = list()
var/list/listening_obj = list()
var/turf/T = get_turf(H)
if(T)
var/list/hear = hear(7, T)
var/list/hearturfs = list()
for(var/I in hear)
if(istype(I, /mob/))
var/mob/M = I
listening += M
hearturfs += M.locs[1]
for(var/obj/O in M.contents)
listening_obj |= O
else if(istype(I, /obj/))
var/obj/O = I
hearturfs += O.locs[1]
listening_obj |= O
for(var/mob/M in player_list)
if(M.stat == DEAD && M.client && (M.client.prefs.toggles & CHAT_GHOSTEARS))
M.hear_say(message,verb,speaking,null,null, src)
continue
if(M.loc && M.locs[1] in hearturfs)
M.hear_say(message,verb,speaking,null,null, src)
for(var/mob/M in hearers(T.loc))//The location is the object, default distance.
if(M.say_understands(src))//If they understand AI speak. Humans and the like will be able to.
M.show_message(rendered_a, 2)
else//If they do not.
M.show_message(rendered_b, 2)
/*Radios "filter out" this conversation channel so we don't need to account for them.
This is another way of saying that we won't bother dealing with them.*/
else else
src << "No holopad connected." src << "No holopad connected."
return 0 return 0

View File

@@ -289,7 +289,7 @@
proc/AttemptLateSpawn(rank,var/spawning_at) proc/AttemptLateSpawn(rank,var/spawning_at)
if (src != usr) if(src != usr)
return 0 return 0
if(!ticker || ticker.current_state != GAME_STATE_PLAYING) if(!ticker || ticker.current_state != GAME_STATE_PLAYING)
usr << "\red The round is either not ready, or has already finished..." usr << "\red The round is either not ready, or has already finished..."
@@ -323,7 +323,7 @@
character.loc = C.loc character.loc = C.loc
AnnounceCyborg(character, rank, "has been downloaded to the empty core in \the [character.loc.loc]") AnnounceCyborg(character, rank, "has been downloaded to the empty core in \the [character.loc.loc]")
ticker.mode.latespawn(character) ticker.mode.handle_latejoin(character)
qdel(C) qdel(C)
qdel(src) qdel(src)
@@ -338,7 +338,7 @@
character.buckled.loc = character.loc character.buckled.loc = character.loc
character.buckled.set_dir(character.dir) character.buckled.set_dir(character.dir)
ticker.mode.latespawn(character) ticker.mode.handle_latejoin(character)
if(character.mind.assigned_role != "Cyborg") if(character.mind.assigned_role != "Cyborg")
data_core.manifest_inject(character) data_core.manifest_inject(character)

View File

@@ -72,13 +72,8 @@
return return
/obj/machinery/chem_master/Topic(href, href_list) /obj/machinery/chem_master/Topic(href, href_list)
if(stat & (BROKEN|NOPOWER)) return if(..())
if(usr.stat || usr.restrained()) return return 1
if(!in_range(src, usr)) return
src.add_fingerprint(usr)
usr.set_machine(src)
if (href_list["ejectp"]) if (href_list["ejectp"])
if(loaded_pill_bottle) if(loaded_pill_bottle)
@@ -228,7 +223,7 @@
return src.attack_hand(user) return src.attack_hand(user)
/obj/machinery/chem_master/attack_hand(mob/user as mob) /obj/machinery/chem_master/attack_hand(mob/user as mob)
if(stat & BROKEN) if(inoperable())
return return
user.set_machine(src) user.set_machine(src)
if(!(user.client in has_sprites)) if(!(user.client in has_sprites))
@@ -337,11 +332,8 @@
/obj/machinery/computer/pandemic/Topic(href, href_list) /obj/machinery/computer/pandemic/Topic(href, href_list)
if(stat & (NOPOWER|BROKEN)) return if(..())
if(usr.stat || usr.restrained()) return return 1
if(!in_range(src, usr)) return
usr.set_machine(src)
if(!beaker) return if(!beaker) return
if (href_list["create_vaccine"]) if (href_list["create_vaccine"])
@@ -649,10 +641,12 @@
return 0 return 0
/obj/machinery/reagentgrinder/attack_hand(mob/user as mob) /obj/machinery/reagentgrinder/attack_hand(mob/user as mob)
user.set_machine(src)
interact(user) interact(user)
/obj/machinery/reagentgrinder/interact(mob/user as mob) // The microwave Menu /obj/machinery/reagentgrinder/interact(mob/user as mob) // The microwave Menu
if(inoperable())
return
user.set_machine(src)
var/is_chamber_empty = 0 var/is_chamber_empty = 0
var/is_beaker_ready = 0 var/is_beaker_ready = 0
var/processing_chamber = "" var/processing_chamber = ""
@@ -699,8 +693,8 @@
/obj/machinery/reagentgrinder/Topic(href, href_list) /obj/machinery/reagentgrinder/Topic(href, href_list)
if(..()) if(..())
return return 1
usr.set_machine(src)
switch(href_list["action"]) switch(href_list["action"])
if ("grind") if ("grind")
grind() grind()
@@ -709,7 +703,7 @@
if ("detach") if ("detach")
detach() detach()
src.updateUsrDialog() src.updateUsrDialog()
return return 1
/obj/machinery/reagentgrinder/proc/detach() /obj/machinery/reagentgrinder/proc/detach()

View File

@@ -113,9 +113,6 @@
return ..() return ..()
/obj/machinery/chemical_dispenser/ui_interact(mob/user, ui_key = "main",var/datum/nanoui/ui = null, var/force_open = 1) /obj/machinery/chemical_dispenser/ui_interact(mob/user, ui_key = "main",var/datum/nanoui/ui = null, var/force_open = 1)
if(stat & (BROKEN|NOPOWER)) return
if(user.stat || user.restrained()) return
// this is the data which will be sent to the ui // this is the data which will be sent to the ui
var/data[0] var/data[0]
data["amount"] = amount data["amount"] = amount
@@ -148,8 +145,8 @@
ui.open() ui.open()
/obj/machinery/chemical_dispenser/Topic(href, href_list) /obj/machinery/chemical_dispenser/Topic(href, href_list)
if(stat & (NOPOWER|BROKEN)) if(..())
return 0 // don't update UIs attached to this object return 1
if(href_list["amount"]) if(href_list["amount"])
amount = round(text2num(href_list["amount"]), 1) // round to nearest 1 amount = round(text2num(href_list["amount"]), 1) // round to nearest 1
@@ -171,9 +168,7 @@
return 1 // update UIs attached to this object return 1 // update UIs attached to this object
/obj/machinery/chemical_dispenser/attack_ai(mob/user as mob) /obj/machinery/chemical_dispenser/attack_ai(mob/user as mob)
src.attack_hand(user) ui_interact(user)
/obj/machinery/chemical_dispenser/attack_hand(mob/user as mob) /obj/machinery/chemical_dispenser/attack_hand(mob/user as mob)
if(stat & BROKEN)
return
ui_interact(user) ui_interact(user)