mirror of
https://github.com/CHOMPStation2/CHOMPStation2.git
synced 2025-12-11 18:53:06 +00:00
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:
@@ -71,11 +71,17 @@ proc/isemptylist(list/list)
|
||||
return 1
|
||||
return 0
|
||||
|
||||
//Empties the list by setting the length to 0. Hopefully the elements get garbage collected
|
||||
proc/clearlist(list/list)
|
||||
if(istype(list))
|
||||
list.len = 0
|
||||
return
|
||||
/proc/instances_of_type_in_list(var/atom/A, var/list/L)
|
||||
var/instances = 0
|
||||
for(var/type in L)
|
||||
if(istype(A, type))
|
||||
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
|
||||
proc/listclearnulls(list/list)
|
||||
|
||||
@@ -86,7 +86,8 @@
|
||||
/datum/antagonist/proc/tick()
|
||||
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.
|
||||
|
||||
// Prune restricted status. Broke it up for readability.
|
||||
@@ -108,46 +109,57 @@
|
||||
return candidates
|
||||
|
||||
/datum/antagonist/proc/attempt_random_spawn()
|
||||
update_current_antag_max()
|
||||
build_candidate_list(flags & (ANTAG_OVERRIDE_MOB|ANTAG_OVERRIDE_JOB))
|
||||
attempt_spawn()
|
||||
finalize_spawn()
|
||||
|
||||
/datum/antagonist/proc/attempt_late_spawn(var/datum/mind/player)
|
||||
/datum/antagonist/proc/attempt_auto_spawn()
|
||||
if(!can_late_spawn())
|
||||
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()
|
||||
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
|
||||
//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,
|
||||
//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.
|
||||
/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.
|
||||
if(!candidates.len)
|
||||
return 0
|
||||
|
||||
//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)
|
||||
candidates -= player
|
||||
draft_antagonist(player)
|
||||
@@ -187,10 +199,15 @@
|
||||
pending_antagonists -= player
|
||||
add_antagonist(player,0,0,1)
|
||||
|
||||
//Resets all pending_antagonists, clearing their special_role (and assigned_role if ANTAG_OVERRIDE_JOB is set)
|
||||
/datum/antagonist/proc/reset()
|
||||
reset_antag_selection()
|
||||
|
||||
//Resets the antag selection, clearing all pending_antagonists and their special_role
|
||||
//(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)
|
||||
if(flags & ANTAG_OVERRIDE_JOB)
|
||||
player.assigned_role = null
|
||||
player.special_role = null
|
||||
pending_antagonists.Cut()
|
||||
candidates.Cut()
|
||||
|
||||
@@ -16,6 +16,7 @@
|
||||
create_objectives(target)
|
||||
update_icons_added(target)
|
||||
greet(target)
|
||||
if(!gag_announcement)
|
||||
announce_antagonist_spawn()
|
||||
|
||||
/datum/antagonist/proc/create_default(var/mob/source)
|
||||
|
||||
@@ -20,6 +20,17 @@
|
||||
/datum/antagonist/proc/get_antag_count()
|
||||
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)
|
||||
if(player in current_antagonists)
|
||||
return 1
|
||||
@@ -33,9 +44,6 @@
|
||||
return (flags & ANTAG_VOTABLE)
|
||||
|
||||
/datum/antagonist/proc/can_late_spawn()
|
||||
update_current_antag_max()
|
||||
if(get_antag_count() >= cur_max)
|
||||
return 0
|
||||
return 1
|
||||
|
||||
/datum/antagonist/proc/is_latejoin_template()
|
||||
|
||||
@@ -22,13 +22,11 @@ var/datum/antagonist/rogue_ai/malf
|
||||
malf = src
|
||||
|
||||
|
||||
/datum/antagonist/rogue_ai/get_candidates()
|
||||
/datum/antagonist/rogue_ai/build_candidate_list()
|
||||
..()
|
||||
for(var/datum/mind/player in candidates)
|
||||
if(player.assigned_role && player.assigned_role != "AI")
|
||||
candidates -= player
|
||||
if(!candidates.len)
|
||||
return list()
|
||||
return candidates
|
||||
|
||||
|
||||
|
||||
@@ -12,14 +12,15 @@
|
||||
|
||||
/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.
|
||||
var/i = 1
|
||||
//Let's not modify global lists for trivial reasons, even if it seems harmless right now.
|
||||
var/list/antag_candidates = all_antag_types.Copy()
|
||||
|
||||
var/grab_antags = round(num_players()/ANTAG_TYPE_RATIO)+1
|
||||
for(var/antag_id in all_antag_types)
|
||||
if(i > grab_antags)
|
||||
break
|
||||
while(antag_candidates.len && antag_tags.len < grab_antags)
|
||||
var/antag_id = pick(antag_candidates)
|
||||
antag_candidates -= antag_id
|
||||
antag_tags |= antag_id
|
||||
i++
|
||||
|
||||
..()
|
||||
|
||||
/datum/game_mode/calamity/check_victory()
|
||||
|
||||
@@ -21,7 +21,6 @@ var/global/list/additional_antag_types = list()
|
||||
|
||||
var/list/antag_tags = list() // Core antag templates to spawn.
|
||||
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/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.
|
||||
@@ -183,6 +182,7 @@ var/global/list/additional_antag_types = list()
|
||||
|
||||
/datum/game_mode/proc/pre_setup()
|
||||
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 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))
|
||||
antag.attempt_spawn() //select antags to be spawned
|
||||
antag.finalize_spawn() //actually spawn antags
|
||||
if(antag.is_latejoin_template())
|
||||
latejoin_templates |= antag
|
||||
|
||||
if(emergency_shuttle && auto_recall_shuttle)
|
||||
emergency_shuttle.auto_recall = 1
|
||||
@@ -221,7 +219,7 @@ var/global/list/additional_antag_types = list()
|
||||
|
||||
/datum/game_mode/proc/fail_setup()
|
||||
for(var/datum/antagonist/antag in antag_templates)
|
||||
antag.reset()
|
||||
antag.reset_antag_selection()
|
||||
|
||||
/datum/game_mode/proc/announce_ert_disabled()
|
||||
if(!ert_disabled)
|
||||
@@ -493,6 +491,7 @@ var/global/list/additional_antag_types = list()
|
||||
if(antag)
|
||||
antag_templates |= antag
|
||||
|
||||
shuffle(antag_templates) //In the case of multiple antag types
|
||||
newscaster_announcements = pick(newscaster_standard_feeds)
|
||||
|
||||
/datum/game_mode/proc/check_victory()
|
||||
|
||||
@@ -3,55 +3,39 @@
|
||||
/datum/game_mode/var/max_autotraitor_delay = 12000 // Approx 20 minutes.
|
||||
/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()
|
||||
///Called by the gameticker
|
||||
/datum/game_mode/proc/process()
|
||||
// Slow this down a bit so latejoiners have a chance of being antags.
|
||||
process_count++
|
||||
if(process_count >= 10)
|
||||
process_count = 0
|
||||
try_latespawn()
|
||||
if(round_autoantag && world.time < next_spawn && !emergency_shuttle.departed)
|
||||
process_autoantag()
|
||||
|
||||
/datum/game_mode/proc/latespawn(var/mob/living/carbon/human/character)
|
||||
if(!character.mind)
|
||||
return
|
||||
try_latespawn(character.mind)
|
||||
//This can be overriden in case a game mode needs to do stuff when a player latejoins
|
||||
/datum/game_mode/proc/handle_latejoin(var/mob/living/carbon/human/character)
|
||||
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)
|
||||
return
|
||||
var/list/usable_templates = list()
|
||||
for(var/datum/antagonist/A in antag_templates)
|
||||
if(A.can_late_spawn())
|
||||
message_admins("[uppertext(name)]: [A.id] selected for spawn attempt.")
|
||||
usable_templates |= A
|
||||
|
||||
if(world.time < next_spawn)
|
||||
return
|
||||
|
||||
message_admins("AUTO[uppertext(name)]: Attempting spawn.")
|
||||
|
||||
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.")
|
||||
if(!usable_templates.len)
|
||||
message_admins("[uppertext(name)]: Failed to find configured mode spawn templates, please re-enable auto-antagonists after one is added.")
|
||||
round_autoantag = 0
|
||||
return
|
||||
|
||||
while(usable_templates.len)
|
||||
var/datum/antagonist/spawn_antag = pick(usable_templates)
|
||||
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)
|
||||
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
|
||||
|
||||
@@ -191,7 +191,10 @@ Class Procs:
|
||||
return (stat & (NOPOWER|BROKEN|additional_flags))
|
||||
|
||||
/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 ..()
|
||||
|
||||
@@ -722,7 +722,8 @@ var/global/list/obj/item/device/pda/PDAs = list()
|
||||
if("Message")
|
||||
|
||||
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(href_list["target"] in conversations) // Need to make sure the message went through, if not welp.
|
||||
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)
|
||||
|
||||
/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)
|
||||
|
||||
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))
|
||||
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)
|
||||
|
||||
log_pda("[usr] (PDA: [sending_unit]) sent \"[message]\" to [name]")
|
||||
|
||||
@@ -623,35 +623,36 @@
|
||||
icon_state = "light"
|
||||
desc = "This box is shaped on the inside so that only light tubes and bulbs fit."
|
||||
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
|
||||
|
||||
/obj/item/weapon/storage/box/lights/bulbs/New()
|
||||
/obj/item/weapon/storage/box/lights/New()
|
||||
..()
|
||||
make_exact_fit()
|
||||
|
||||
/obj/item/weapon/storage/box/lights/bulbs/New()
|
||||
for(var/i = 0; i < 21; i++)
|
||||
new /obj/item/weapon/light/bulb(src)
|
||||
..()
|
||||
|
||||
/obj/item/weapon/storage/box/lights/tubes
|
||||
name = "box of replacement tubes"
|
||||
icon_state = "lighttube"
|
||||
|
||||
/obj/item/weapon/storage/box/lights/tubes/New()
|
||||
..()
|
||||
for(var/i = 0; i < 21; i++)
|
||||
new /obj/item/weapon/light/tube(src)
|
||||
..()
|
||||
|
||||
/obj/item/weapon/storage/box/lights/mixed
|
||||
name = "box of replacement lights"
|
||||
icon_state = "lightmixed"
|
||||
|
||||
/obj/item/weapon/storage/box/lights/mixed/New()
|
||||
..()
|
||||
for(var/i = 0; i < 14; i++)
|
||||
new /obj/item/weapon/light/tube(src)
|
||||
for(var/i = 0; i < 7; i++)
|
||||
new /obj/item/weapon/light/bulb(src)
|
||||
..()
|
||||
|
||||
/obj/item/weapon/storage/box/freezer
|
||||
name = "portable freezer"
|
||||
|
||||
@@ -130,8 +130,7 @@
|
||||
|
||||
/obj/item/weapon/storage/firstaid/surgery
|
||||
name = "surgery kit"
|
||||
desc = "Contains tools for surgery."
|
||||
storage_slots = 10
|
||||
desc = "Contains tools for surgery. Has precise foam fitting for safe transport."
|
||||
|
||||
/obj/item/weapon/storage/firstaid/surgery/New()
|
||||
..()
|
||||
@@ -146,7 +145,8 @@
|
||||
new /obj/item/weapon/bonegel(src)
|
||||
new /obj/item/weapon/FixOVein(src)
|
||||
new /obj/item/stack/medical/advanced/bruise_pack(src)
|
||||
return
|
||||
|
||||
make_exact_fit()
|
||||
|
||||
/*
|
||||
* Pill Bottles
|
||||
|
||||
@@ -235,11 +235,15 @@
|
||||
usr << "<span class='notice'>[src] is full, make some space.</span>"
|
||||
return 0 //Storage item is full
|
||||
|
||||
if(can_hold.len && !is_type_in_list(W, can_hold))
|
||||
if(!stop_messages)
|
||||
if (istype(W, /obj/item/weapon/hand_labeler))
|
||||
if(can_hold.len)
|
||||
if(!is_type_in_list(W, can_hold))
|
||||
if(!stop_messages && ! istype(W, /obj/item/weapon/hand_labeler))
|
||||
usr << "<span class='notice'>[src] cannot hold \the [W].</span>"
|
||||
return 0
|
||||
usr << "<span class='notice'>[src] cannot hold [W].</span>"
|
||||
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))
|
||||
@@ -461,6 +465,17 @@
|
||||
src.quick_empty()
|
||||
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 -1 if the atom was not found on container.
|
||||
/atom/proc/storage_depth(atom/container)
|
||||
|
||||
@@ -1293,7 +1293,7 @@ proc/admin_notice(var/message, var/rights)
|
||||
|
||||
var/datum/antagonist/antag = all_antag_types[antag_type]
|
||||
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()
|
||||
set category = "Admin"
|
||||
@@ -1310,6 +1310,5 @@ proc/admin_notice(var/message, var/rights)
|
||||
usr << "Mode has not started."
|
||||
return
|
||||
|
||||
message_admins("[key_name(usr)] attempting to force mode latespawn.")
|
||||
ticker.mode.next_spawn = 0
|
||||
ticker.mode.try_latespawn()
|
||||
message_admins("[key_name(usr)] attempting to force mode autospawn.")
|
||||
ticker.mode.process_autoantag()
|
||||
|
||||
@@ -311,17 +311,18 @@ var/global/list/gear_datums = list()
|
||||
allowed_roles = list("Security Officer","Head of Security","Warden")
|
||||
|
||||
/datum/gear/thugshades
|
||||
display_name = "Sunglasses, Fat (Security)"
|
||||
display_name = "Sunglasses, Fat"
|
||||
path = /obj/item/clothing/glasses/sunglasses/big
|
||||
cost = 1
|
||||
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
|
||||
display_name = "sunglasses, presciption"
|
||||
path = /obj/item/clothing/glasses/sunglasses/prescription
|
||||
cost = 2
|
||||
slot = slot_glasses
|
||||
allowed_roles = list("Security Officer","Head of Security","Warden","Detective","Internal Affairs Agent","Quartermaster","Head of Personnel","Captain")
|
||||
|
||||
// Mask
|
||||
|
||||
|
||||
@@ -12,7 +12,7 @@
|
||||
/mob/living/silicon/proc/set_zeroth_law(var/law, var/law_borg)
|
||||
laws_sanity_check()
|
||||
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)
|
||||
..()
|
||||
@@ -22,40 +22,40 @@
|
||||
/mob/living/silicon/proc/add_ion_law(var/law)
|
||||
laws_sanity_check()
|
||||
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)
|
||||
laws_sanity_check()
|
||||
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)
|
||||
laws_sanity_check()
|
||||
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)
|
||||
laws_sanity_check()
|
||||
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)
|
||||
laws_sanity_check()
|
||||
laws.clear_inherent_laws()
|
||||
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)
|
||||
laws_sanity_check()
|
||||
laws.clear_ion_laws()
|
||||
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)
|
||||
laws_sanity_check()
|
||||
laws.clear_supplied_laws()
|
||||
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)
|
||||
var/prefix = ""
|
||||
@@ -103,3 +103,7 @@
|
||||
/mob/living/silicon/proc/lawsync()
|
||||
laws_sanity_check()
|
||||
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]"
|
||||
|
||||
@@ -68,31 +68,46 @@
|
||||
if (!message)
|
||||
return
|
||||
|
||||
var/obj/machinery/hologram/holopad/T = src.holo
|
||||
if(T && T.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
|
||||
var/obj/machinery/hologram/holopad/H = src.holo
|
||||
if(H && H.masters[src])//If there is a hologram and its master is the user.
|
||||
|
||||
// AI can hear their own message, this formats it for them.
|
||||
if(speaking)
|
||||
rendered_a = "<span class='game say'><span class='name'>[name]</span> [speaking.format_message(message, verb)]</span>"
|
||||
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.
|
||||
src << "<i><span class='game say'>Holopad transmitted, <span class='name'>[real_name]</span> [speaking.format_message(message, verb)]</span></i>"
|
||||
else
|
||||
rendered_a = "<span class='game say'><span class='name'>[name]</span> [verb], <span class='message'>\"[message]\"</span></span>"
|
||||
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.
|
||||
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>"
|
||||
|
||||
//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
|
||||
src << "No holopad connected."
|
||||
return 0
|
||||
|
||||
@@ -289,7 +289,7 @@
|
||||
|
||||
|
||||
proc/AttemptLateSpawn(rank,var/spawning_at)
|
||||
if (src != usr)
|
||||
if(src != usr)
|
||||
return 0
|
||||
if(!ticker || ticker.current_state != GAME_STATE_PLAYING)
|
||||
usr << "\red The round is either not ready, or has already finished..."
|
||||
@@ -323,7 +323,7 @@
|
||||
character.loc = C.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(src)
|
||||
@@ -338,7 +338,7 @@
|
||||
character.buckled.loc = character.loc
|
||||
character.buckled.set_dir(character.dir)
|
||||
|
||||
ticker.mode.latespawn(character)
|
||||
ticker.mode.handle_latejoin(character)
|
||||
|
||||
if(character.mind.assigned_role != "Cyborg")
|
||||
data_core.manifest_inject(character)
|
||||
|
||||
@@ -72,13 +72,8 @@
|
||||
return
|
||||
|
||||
/obj/machinery/chem_master/Topic(href, href_list)
|
||||
if(stat & (BROKEN|NOPOWER)) return
|
||||
if(usr.stat || usr.restrained()) return
|
||||
if(!in_range(src, usr)) return
|
||||
|
||||
src.add_fingerprint(usr)
|
||||
usr.set_machine(src)
|
||||
|
||||
if(..())
|
||||
return 1
|
||||
|
||||
if (href_list["ejectp"])
|
||||
if(loaded_pill_bottle)
|
||||
@@ -228,7 +223,7 @@
|
||||
return src.attack_hand(user)
|
||||
|
||||
/obj/machinery/chem_master/attack_hand(mob/user as mob)
|
||||
if(stat & BROKEN)
|
||||
if(inoperable())
|
||||
return
|
||||
user.set_machine(src)
|
||||
if(!(user.client in has_sprites))
|
||||
@@ -337,11 +332,8 @@
|
||||
|
||||
|
||||
/obj/machinery/computer/pandemic/Topic(href, href_list)
|
||||
if(stat & (NOPOWER|BROKEN)) return
|
||||
if(usr.stat || usr.restrained()) return
|
||||
if(!in_range(src, usr)) return
|
||||
|
||||
usr.set_machine(src)
|
||||
if(..())
|
||||
return 1
|
||||
if(!beaker) return
|
||||
|
||||
if (href_list["create_vaccine"])
|
||||
@@ -649,10 +641,12 @@
|
||||
return 0
|
||||
|
||||
/obj/machinery/reagentgrinder/attack_hand(mob/user as mob)
|
||||
user.set_machine(src)
|
||||
interact(user)
|
||||
|
||||
/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_beaker_ready = 0
|
||||
var/processing_chamber = ""
|
||||
@@ -699,8 +693,8 @@
|
||||
|
||||
/obj/machinery/reagentgrinder/Topic(href, href_list)
|
||||
if(..())
|
||||
return
|
||||
usr.set_machine(src)
|
||||
return 1
|
||||
|
||||
switch(href_list["action"])
|
||||
if ("grind")
|
||||
grind()
|
||||
@@ -709,7 +703,7 @@
|
||||
if ("detach")
|
||||
detach()
|
||||
src.updateUsrDialog()
|
||||
return
|
||||
return 1
|
||||
|
||||
/obj/machinery/reagentgrinder/proc/detach()
|
||||
|
||||
|
||||
@@ -113,9 +113,6 @@
|
||||
return ..()
|
||||
|
||||
/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
|
||||
var/data[0]
|
||||
data["amount"] = amount
|
||||
@@ -148,8 +145,8 @@
|
||||
ui.open()
|
||||
|
||||
/obj/machinery/chemical_dispenser/Topic(href, href_list)
|
||||
if(stat & (NOPOWER|BROKEN))
|
||||
return 0 // don't update UIs attached to this object
|
||||
if(..())
|
||||
return 1
|
||||
|
||||
if(href_list["amount"])
|
||||
amount = round(text2num(href_list["amount"]), 1) // round to nearest 1
|
||||
@@ -171,9 +168,7 @@
|
||||
return 1 // update UIs attached to this object
|
||||
|
||||
/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)
|
||||
if(stat & BROKEN)
|
||||
return
|
||||
ui_interact(user)
|
||||
|
||||
Reference in New Issue
Block a user